fix: les
This commit is contained in:
@@ -1,260 +0,0 @@
|
||||
# DevDash Debug Challenge Series - START HERE
|
||||
|
||||
Welcome to the **DevDash Debug Challenge Series** - a comprehensive three-tier debugging curriculum for Next.js developers.
|
||||
|
||||
## Quick Links
|
||||
|
||||
### Debug Challenge Tiers
|
||||
|
||||
1. **Easy Tier** (5 errors - 30-45 min)
|
||||
- File: `les3-debug-challenge.zip`
|
||||
- Answer Key: `Les03-Debug-Challenge-ANTWOORDEN.md`
|
||||
- Topics: Basic syntax, typos, simple logic
|
||||
- **Start here if:** You're new to debugging or Next.js
|
||||
|
||||
2. **Hard Tier** (12 errors - 60-90 min)
|
||||
- File: `les3-debug-challenge-hard.zip`
|
||||
- Answer Key: `Les03-Debug-Challenge-Hard-ANTWOORDEN.md`
|
||||
- Topics: Next.js patterns, React hooks, TypeScript
|
||||
- **Start here if:** You're comfortable with React basics
|
||||
|
||||
3. **Super Hard Tier** (16-18 errors - 2-3 hours) ← YOU ARE HERE
|
||||
- File: `les3-debug-challenge-super-hard.zip`
|
||||
- Answer Key: `Les03-Debug-Challenge-SuperHard-ANTWOORDEN.md`
|
||||
- Topics: Advanced patterns, circular deps, complex interactions
|
||||
- **Start here if:** You're ready to master advanced concepts
|
||||
|
||||
## What is DevDash?
|
||||
|
||||
DevDash is a fully-featured developer portfolio and dashboard application built with:
|
||||
- **Next.js 14** (App Router)
|
||||
- **React 18** (with hooks)
|
||||
- **TypeScript 5**
|
||||
- **Tailwind CSS 3**
|
||||
|
||||
The application includes:
|
||||
- Homepage with Hero section, Features grid, Testimonials carousel
|
||||
- Blog system with dynamic routes
|
||||
- Dashboard with analytics and user profile
|
||||
- API routes for data
|
||||
- Middleware for authentication
|
||||
- Theme context for dark/light mode
|
||||
|
||||
## Getting Started (5 minutes)
|
||||
|
||||
### Option 1: Start the Super Hard Challenge
|
||||
|
||||
```bash
|
||||
# 1. Extract the project
|
||||
unzip les3-debug-challenge-super-hard.zip
|
||||
cd les3-debug-challenge-super-hard
|
||||
|
||||
# 2. Install dependencies
|
||||
npm install
|
||||
|
||||
# 3. Run the development server
|
||||
npm run dev
|
||||
|
||||
# 4. Open browser to http://localhost:3000
|
||||
# (You'll see errors - that's the point!)
|
||||
|
||||
# 5. Read the errors and start debugging
|
||||
# Open Les03-Debug-Challenge-SuperHard-ANTWOORDEN.md for help
|
||||
```
|
||||
|
||||
### Option 2: Read First, Debug Later
|
||||
|
||||
1. Start with `DEBUG-CHALLENGES-OVERVIEW.md` for context
|
||||
2. Read `Les03-Debug-Challenge-SuperHard-ANTWOORDEN.md` to understand all errors
|
||||
3. Then extract and debug the project yourself
|
||||
|
||||
## What Will You Learn?
|
||||
|
||||
By fixing all 16-18 errors, you'll master:
|
||||
|
||||
### Advanced React Concepts
|
||||
- Advanced hook patterns (useState, useEffect, useContext)
|
||||
- Closure patterns and stale closures
|
||||
- Key prop best practices
|
||||
- Memory leak prevention
|
||||
- Context API provider patterns
|
||||
|
||||
### Next.js 14 Deep Dive
|
||||
- Client vs Server components
|
||||
- Middleware patterns
|
||||
- Dynamic routes with metadata
|
||||
- API routes and type safety
|
||||
- App Router structure
|
||||
|
||||
### TypeScript Mastery
|
||||
- Type safety in React
|
||||
- Optional chaining
|
||||
- API contracts
|
||||
- Type narrowing
|
||||
|
||||
### Advanced Debugging Skills
|
||||
- Circular dependency detection
|
||||
- Performance issue identification
|
||||
- Memory leak detection
|
||||
- State management debugging
|
||||
|
||||
## The 6 Error Categories
|
||||
|
||||
| Category | Count | Examples |
|
||||
|----------|-------|----------|
|
||||
| **Blocking Errors** | 3 | Missing deps, wrong imports, circular refs |
|
||||
| **Next.js Specific** | 4 | Client/Server components, metadata, middleware |
|
||||
| **Logic Errors** | 3 | Filter bugs, stale closures, key issues |
|
||||
| **TypeScript Errors** | 2 | Type mismatches, optional chaining |
|
||||
| **React Patterns** | 3 | Cleanup, context, prop drilling |
|
||||
| **Styling Errors** | 2-3 | Custom CSS, inline styles |
|
||||
|
||||
## How to Use the Answer Key
|
||||
|
||||
The answer key (`Les03-Debug-Challenge-SuperHard-ANTWOORDEN.md`) provides:
|
||||
|
||||
1. **Error Location** - Exact file and line
|
||||
2. **Issue Description** - What's wrong and why
|
||||
3. **Symptom** - What breaks or misbehaves
|
||||
4. **Multiple Solutions** - Usually 2-3 ways to fix
|
||||
5. **Severity Level** - CRITICAL, HIGH, MEDIUM, LOW
|
||||
6. **Code Examples** - Before/after comparisons
|
||||
|
||||
**Pro Tip:** Try to fix each error without looking at the answer first. Use the answer key to verify your fix or for hints.
|
||||
|
||||
## Debugging Strategy
|
||||
|
||||
**Recommended approach:**
|
||||
|
||||
1. Start the dev server: `npm run dev`
|
||||
2. Read the console errors
|
||||
3. Fix blocking errors first (they prevent the app from running)
|
||||
4. Then tackle Next.js errors (build-time failures)
|
||||
5. Next, logic errors (functionality breaks)
|
||||
6. Then TypeScript errors (feature-specific)
|
||||
7. Finally, React patterns and styling
|
||||
|
||||
## Testing Your Fixes
|
||||
|
||||
After each fix, verify:
|
||||
|
||||
```bash
|
||||
# Check for build errors
|
||||
npm run build
|
||||
|
||||
# Check for runtime errors
|
||||
npm run dev
|
||||
|
||||
# Run in your browser
|
||||
# Click around and check if features work
|
||||
```
|
||||
|
||||
## Validation Checklist
|
||||
|
||||
Your fixes are complete when:
|
||||
- [ ] `npm install` succeeds
|
||||
- [ ] `npm run build` succeeds (no errors)
|
||||
- [ ] `npm run dev` starts without errors
|
||||
- [ ] Homepage loads with all sections
|
||||
- [ ] Blog shows 2 published posts
|
||||
- [ ] Blog post detail pages work
|
||||
- [ ] Dashboard page loads
|
||||
- [ ] Stats load from API
|
||||
- [ ] No console errors or warnings
|
||||
- [ ] No TypeScript errors
|
||||
|
||||
## Need Help?
|
||||
|
||||
### If you're stuck on an error:
|
||||
1. Read the error message carefully
|
||||
2. Check `Les03-Debug-Challenge-SuperHard-ANTWOORDEN.md` for that error number
|
||||
3. Try the "Symptom" section to understand what's broken
|
||||
4. Look at the code example to see the fix
|
||||
|
||||
### If something doesn't make sense:
|
||||
- Refer to the "Key Concepts Covered" section in the answer key
|
||||
- Research the specific Next.js/React feature being tested
|
||||
- Try different solutions to understand the principle
|
||||
|
||||
### If you need a broader context:
|
||||
- Read `DEBUG-CHALLENGES-OVERVIEW.md` for the big picture
|
||||
- Review the "Learning Outcomes" section
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
les3-debug-challenge-super-hard/
|
||||
├── src/
|
||||
│ ├── app/ # Next.js pages and API routes
|
||||
│ ├── components/ # React components (many with errors)
|
||||
│ ├── context/ # Theme context
|
||||
│ ├── lib/ # Utilities and types
|
||||
│ └── data/ # Static blog data
|
||||
├── package.json # Dependencies (some missing!)
|
||||
├── tsconfig.json # TypeScript config
|
||||
├── tailwind.config.ts # Tailwind setup
|
||||
├── middleware.ts # Auth simulation (has error)
|
||||
└── README.md # Project overview
|
||||
```
|
||||
|
||||
## Time Estimate
|
||||
|
||||
- **Easy errors (1-3):** 20-30 min
|
||||
- **Next.js errors (4-7):** 30-40 min
|
||||
- **Logic errors (8-10):** 25-35 min
|
||||
- **TypeScript errors (11-12):** 20-30 min
|
||||
- **React patterns (13-15):** 30-45 min
|
||||
- **Styling (16-18):** 20-30 min
|
||||
- **Testing:** 15-20 min
|
||||
|
||||
**Total:** 2-3 hours for the complete challenge
|
||||
|
||||
## Progression Path
|
||||
|
||||
After this challenge, you'll be ready for:
|
||||
- Building production Next.js applications
|
||||
- Advanced React patterns
|
||||
- Complex state management
|
||||
- Performance optimization
|
||||
- Team code reviews
|
||||
|
||||
## Questions About Specific Errors?
|
||||
|
||||
Each error is thoroughly explained in `Les03-Debug-Challenge-SuperHard-ANTWOORDEN.md`. The document includes:
|
||||
- Exact error location
|
||||
- Root cause explanation
|
||||
- Visual code examples
|
||||
- Multiple solution options
|
||||
- Why the error matters
|
||||
- Best practices to avoid it
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Now:** Extract the zip and run `npm install`
|
||||
2. **Then:** Start the dev server with `npm run dev`
|
||||
3. **When stuck:** Check the answer key
|
||||
4. **After fixing all:** Review your solutions and make sure you understand each error
|
||||
5. **Finally:** Try building a similar project from scratch using these patterns
|
||||
|
||||
---
|
||||
|
||||
## Document Reference
|
||||
|
||||
| Document | Purpose |
|
||||
|----------|---------|
|
||||
| **00-START-HERE.md** | This file - quick start guide |
|
||||
| **DEBUG-CHALLENGES-OVERVIEW.md** | Big picture overview of all 3 tiers |
|
||||
| **Les03-Debug-Challenge-SuperHard-ANTWOORDEN.md** | Complete answer key with explanations |
|
||||
| **les3-debug-challenge-super-hard.zip** | The actual buggy project |
|
||||
|
||||
---
|
||||
|
||||
**Good luck debugging! You've got this.**
|
||||
|
||||
Remember: The goal isn't just to fix errors, but to understand *why* they happened and how to prevent them in the future.
|
||||
|
||||
---
|
||||
|
||||
Created: February 2026
|
||||
Level: Super Hard (16-18 errors)
|
||||
Time: 2-3 hours
|
||||
@@ -1,222 +0,0 @@
|
||||
# DevDash Debug Challenge Series - Complete Overview
|
||||
|
||||
This folder contains a complete series of 3 debug challenges of increasing difficulty, all featuring the "DevDash" developer portfolio and dashboard application.
|
||||
|
||||
## Challenge Tiers
|
||||
|
||||
### 1. Easy Tier (5 Errors)
|
||||
- **File:** `les3-debug-challenge.zip`
|
||||
- **Answer Key:** `Les03-Debug-Challenge-ANTWOORDEN.md`
|
||||
- **Target:** Beginners, first-time debuggers
|
||||
- **Topics:** Basic syntax errors, typos, simple logic mistakes
|
||||
|
||||
### 2. Hard Tier (12 Errors)
|
||||
- **File:** `les3-debug-challenge-hard.zip`
|
||||
- **Answer Key:** `Les03-Debug-Challenge-Hard-ANTWOORDEN.md`
|
||||
- **Target:** Intermediate developers
|
||||
- **Topics:** Next.js patterns, React hooks, TypeScript basics, state management
|
||||
|
||||
### 3. Super Hard Tier (16-18 Errors)
|
||||
- **File:** `les3-debug-challenge-super-hard.zip`
|
||||
- **Answer Key:** `Les03-Debug-Challenge-SuperHard-ANTWOORDEN.md`
|
||||
- **Target:** Advanced developers, mastery level
|
||||
- **Topics:** Circular dependencies, advanced React patterns, middleware, complex type issues
|
||||
|
||||
## Challenge Structure
|
||||
|
||||
All challenges are based on the same application concept: **DevDash** - a developer portfolio and dashboard application built with Next.js 14, React 18, TypeScript, and Tailwind CSS.
|
||||
|
||||
### Features Included
|
||||
- **Homepage:** Hero section, features showcase, testimonials carousel
|
||||
- **Blog:** Dynamic routes with MDX-style content
|
||||
- **Dashboard:** Analytics, stats grid, user profile, charts placeholder
|
||||
- **API Routes:** `/api/stats`, `/api/posts`
|
||||
- **Middleware:** Authentication simulation
|
||||
- **Context:** Theme management (dark/light mode)
|
||||
|
||||
### Tech Stack
|
||||
- Next.js 14 (App Router)
|
||||
- React 18
|
||||
- TypeScript 5
|
||||
- Tailwind CSS 3
|
||||
- PostCSS
|
||||
|
||||
## Error Categories by Tier
|
||||
|
||||
### Easy (5 errors)
|
||||
1. Wrong variable name
|
||||
2. Missing closing tag
|
||||
3. Typo in function name
|
||||
4. Array method confusion
|
||||
5. Logic error in condition
|
||||
|
||||
### Hard (12 errors)
|
||||
- 3 Blocking errors (missing deps, wrong imports)
|
||||
- 3 Next.js specific errors (layout, metadata, routing)
|
||||
- 2 Logic errors
|
||||
- 2 TypeScript errors
|
||||
- 2 React pattern errors
|
||||
|
||||
### Super Hard (16-18 errors)
|
||||
- 3 Blocking errors (circular dependencies, missing deps)
|
||||
- 4 Next.js specific errors (client/server components, middleware)
|
||||
- 3 Logic errors (filters, closures, keys)
|
||||
- 2 TypeScript errors (type mismatches, optional chaining)
|
||||
- 3 React pattern errors (cleanup, context, props)
|
||||
- 2-3 Styling errors (CSS and inline styles)
|
||||
|
||||
## Getting Started
|
||||
|
||||
Each zip file contains a complete Next.js project. To work on a challenge:
|
||||
|
||||
```bash
|
||||
# Extract the zip
|
||||
unzip les3-debug-challenge-super-hard.zip
|
||||
|
||||
# Navigate to project
|
||||
cd les3-debug-challenge-super-hard
|
||||
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Run development server
|
||||
npm run dev
|
||||
|
||||
# Open browser to http://localhost:3000
|
||||
```
|
||||
|
||||
## Using Answer Keys
|
||||
|
||||
Each answer key document provides:
|
||||
- Exact location of each error
|
||||
- Code snippet showing the problem
|
||||
- Explanation of why it's an error
|
||||
- The symptom (what breaks)
|
||||
- One or more solutions
|
||||
- Difficulty level (CRITICAL, HIGH, MEDIUM, LOW)
|
||||
|
||||
## Progression Path
|
||||
|
||||
**Suggested learning path:**
|
||||
|
||||
1. Start with **Easy Tier** to get familiar with the codebase and debugging process
|
||||
2. Move to **Hard Tier** to tackle more complex Next.js and React patterns
|
||||
3. Finish with **Super Hard Tier** for mastery of advanced debugging concepts
|
||||
|
||||
## Timeline Recommendations
|
||||
|
||||
| Tier | Recommended Time | Notes |
|
||||
|------|-----------------|-------|
|
||||
| Easy | 30-45 minutes | Quick confidence builder |
|
||||
| Hard | 60-90 minutes | Requires research and testing |
|
||||
| Super Hard | 120-180 minutes | Deep analysis and multiple fixes needed |
|
||||
|
||||
## Learning Outcomes
|
||||
|
||||
After completing all three tiers, students will have mastered:
|
||||
|
||||
### Easy Tier
|
||||
- Basic syntax debugging
|
||||
- Reading error messages
|
||||
- Variable naming conventions
|
||||
- Simple conditional logic
|
||||
|
||||
### Hard Tier
|
||||
- Next.js App Router concepts
|
||||
- React hooks and their rules
|
||||
- TypeScript type safety basics
|
||||
- Component composition
|
||||
- Data flow and props
|
||||
|
||||
### Super Hard Tier
|
||||
- Circular dependencies and module loading
|
||||
- Advanced React patterns (closures, cleanup, context)
|
||||
- Client vs Server components
|
||||
- Middleware patterns
|
||||
- Type-safe API contracts
|
||||
- Performance patterns (keys, memoization)
|
||||
- Styling best practices with Tailwind
|
||||
|
||||
## Key Concepts Covered
|
||||
|
||||
### JavaScript/TypeScript
|
||||
- Module imports and circular dependencies
|
||||
- Type safety and optional chaining
|
||||
- Closures and their pitfalls
|
||||
- Array methods and filtering
|
||||
- Object destructuring
|
||||
|
||||
### React
|
||||
- Hooks (useState, useEffect, useContext)
|
||||
- Rules of hooks and dependencies
|
||||
- Client vs Server components
|
||||
- Context API and providers
|
||||
- Key props and list rendering
|
||||
- Memory leaks and cleanup
|
||||
|
||||
### Next.js
|
||||
- App Router structure
|
||||
- API routes
|
||||
- Middleware
|
||||
- Metadata and SEO
|
||||
- Dynamic routes
|
||||
- Image optimization
|
||||
|
||||
### CSS/Styling
|
||||
- Tailwind CSS utilities
|
||||
- Inline styles vs. classes
|
||||
- CSS custom properties
|
||||
- Responsive design
|
||||
|
||||
## Files Included
|
||||
|
||||
Each zip contains:
|
||||
```
|
||||
les3-debug-challenge-super-hard/
|
||||
├── src/
|
||||
│ ├── app/ # Next.js pages and layouts
|
||||
│ ├── components/ # React components
|
||||
│ ├── context/ # React Context
|
||||
│ ├── lib/ # Utilities and types
|
||||
│ └── data/ # Static data
|
||||
├── package.json
|
||||
├── tsconfig.json
|
||||
├── tailwind.config.ts
|
||||
├── next.config.js
|
||||
├── postcss.config.js
|
||||
├── middleware.ts
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## Grading Rubric
|
||||
|
||||
Students can self-assess:
|
||||
- All 5/12/16-18 errors identified and documented
|
||||
- Code builds successfully (`npm run build`)
|
||||
- No runtime errors or warnings
|
||||
- Application functionality works as intended
|
||||
- Code follows best practices (Tailwind usage, React patterns, etc.)
|
||||
- Understanding demonstrated in commit messages or documentation
|
||||
|
||||
## Support for Instructors
|
||||
|
||||
Each answer key provides:
|
||||
- Clear explanation of each error
|
||||
- Multiple solution options where applicable
|
||||
- Severity levels to help prioritize feedback
|
||||
- Testing checklist to verify all fixes
|
||||
- Common student mistakes and misconceptions
|
||||
|
||||
## File Sizes
|
||||
|
||||
| File | Size | Components |
|
||||
|------|------|-----------|
|
||||
| les3-debug-challenge.zip | 12 KB | 10 files |
|
||||
| les3-debug-challenge-hard.zip | 19 KB | 32 files |
|
||||
| les3-debug-challenge-super-hard.zip | 26 KB | 38 files |
|
||||
|
||||
---
|
||||
|
||||
**Created:** February 2026
|
||||
**Updated:** February 25, 2026
|
||||
**Version:** 3.0 (Complete Series)
|
||||
@@ -1,175 +0,0 @@
|
||||
# Debug Challenge - Antwoordenblad (ALLEEN VOOR TIM)
|
||||
|
||||
**⚠️ NIET DELEN MET STUDENTEN**
|
||||
|
||||
---
|
||||
|
||||
## Overzicht Fouten
|
||||
|
||||
Het project bevat **4 typen fouten**, verspreid over **8 bestanden**.
|
||||
|
||||
---
|
||||
|
||||
## FOUT 1: Missing Dependency — `lucide-react`
|
||||
|
||||
**Bestanden:** `components/Hero.tsx`, `components/FeatureCards.tsx`
|
||||
**Symptoom:** `npm install` werkt, maar `npm run dev` geeft:
|
||||
```
|
||||
Module not found: Can't resolve 'lucide-react'
|
||||
```
|
||||
|
||||
**Oorzaak:** `lucide-react` wordt geïmporteerd in Hero.tsx en FeatureCards.tsx, maar staat NIET in package.json.
|
||||
|
||||
**Fix:**
|
||||
```bash
|
||||
npm install lucide-react
|
||||
```
|
||||
|
||||
**Leerdoel:** Studenten leren dat je imports moet matchen met dependencies in package.json.
|
||||
|
||||
---
|
||||
|
||||
## FOUT 2: Typo in Import Path
|
||||
|
||||
**Bestand:** `app/page.tsx` (regel 1)
|
||||
**Symptoom:**
|
||||
```
|
||||
Module not found: Can't resolve '@/componenst/Hero'
|
||||
```
|
||||
|
||||
**Oorzaak:** Typo: `@/componenst/Hero` i.p.v. `@/components/Hero`
|
||||
|
||||
**Fix:**
|
||||
```tsx
|
||||
// FOUT:
|
||||
import Hero from "@/componenst/Hero";
|
||||
|
||||
// CORRECT:
|
||||
import Hero from "@/components/Hero";
|
||||
```
|
||||
|
||||
**Leerdoel:** Lezen van error messages, herkennen van typos in import paden.
|
||||
|
||||
---
|
||||
|
||||
## FOUT 3: Missing Import — `TestimonialSection`
|
||||
|
||||
**Bestand:** `app/page.tsx` (regel 9)
|
||||
**Symptoom:**
|
||||
```
|
||||
ReferenceError: TestimonialSection is not defined
|
||||
```
|
||||
|
||||
**Oorzaak:** `<TestimonialSection />` wordt gebruikt in page.tsx maar is niet geïmporteerd.
|
||||
|
||||
**Fix:** Voeg import toe bovenaan page.tsx:
|
||||
```tsx
|
||||
import TestimonialSection from "@/components/TestimonialSection";
|
||||
```
|
||||
|
||||
**Leerdoel:** Begrijpen dat elk component geïmporteerd moet worden.
|
||||
|
||||
---
|
||||
|
||||
## FOUT 4: Missing Imports in layout.tsx — `Navbar` en `Footer`
|
||||
|
||||
**Bestand:** `app/layout.tsx` (regels 17-18)
|
||||
**Symptoom:**
|
||||
```
|
||||
ReferenceError: Navbar is not defined
|
||||
ReferenceError: Footer is not defined
|
||||
```
|
||||
|
||||
**Oorzaak:** `<Navbar />` en `<Footer />` worden gebruikt maar niet geïmporteerd.
|
||||
|
||||
**Fix:** Voeg imports toe bovenaan layout.tsx:
|
||||
```tsx
|
||||
import Navbar from "@/components/Navbar";
|
||||
import Footer from "@/components/Footer";
|
||||
```
|
||||
|
||||
**Leerdoel:** Zelfs in layout.tsx moeten componenten geïmporteerd worden.
|
||||
|
||||
---
|
||||
|
||||
## FOUT 5: Inline Styles → Tailwind (6 bestanden!)
|
||||
|
||||
**Bestanden met inline styles:**
|
||||
1. `components/Hero.tsx` — hele component
|
||||
2. `components/FeatureCards.tsx` — hele component
|
||||
3. `components/TestimonialSection.tsx` — hele component
|
||||
4. `components/Navbar.tsx` — hele component
|
||||
5. `components/Footer.tsx` — hele component
|
||||
6. `app/about/page.tsx` — hele pagina
|
||||
7. `app/contact/page.tsx` — hele pagina (formulier)
|
||||
|
||||
**Symptoom:** Geen error, maar code gebruikt `style={{...}}` i.p.v. Tailwind classes.
|
||||
|
||||
**Voorbeeld fix (Hero.tsx):**
|
||||
```tsx
|
||||
// FOUT (inline styles):
|
||||
<section style={{
|
||||
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
||||
padding: '80px 20px',
|
||||
textAlign: 'center',
|
||||
color: 'white',
|
||||
minHeight: '500px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}}>
|
||||
|
||||
// CORRECT (Tailwind):
|
||||
<section className="bg-gradient-to-br from-indigo-500 to-purple-700 py-20 px-5 text-center text-white min-h-[500px] flex items-center justify-center">
|
||||
```
|
||||
|
||||
**Aanpak voor studenten:**
|
||||
1. Selecteer de `style={{...}}` code
|
||||
2. Druk `Ctrl+K` (Inline Edit)
|
||||
3. Typ: "Converteer alle inline styles naar Tailwind CSS classes"
|
||||
4. Accept
|
||||
|
||||
**Leerdoel:** Leren werken met Tailwind, Inline Edit gebruiken voor refactoring.
|
||||
|
||||
---
|
||||
|
||||
## Samenvatting: Alle Fouten
|
||||
|
||||
| # | Type | Bestand | Ernst |
|
||||
|---|------|---------|-------|
|
||||
| 1 | Missing dependency | package.json (lucide-react) | 🔴 Blokkerend |
|
||||
| 2 | Typo in import | app/page.tsx (`componenst`) | 🔴 Blokkerend |
|
||||
| 3 | Missing import | app/page.tsx (TestimonialSection) | 🔴 Blokkerend |
|
||||
| 4 | Missing imports | app/layout.tsx (Navbar, Footer) | 🔴 Blokkerend |
|
||||
| 5 | Inline styles | 7 bestanden | 🟡 Niet blokkerend, maar opdracht |
|
||||
|
||||
**Verwachte volgorde van oplossen:**
|
||||
1. `npm install` → werkt (geen errors hier)
|
||||
2. `npm run dev` → Module not found: lucide-react → `npm install lucide-react`
|
||||
3. `npm run dev` → Can't resolve '@/componenst/Hero' → fix typo
|
||||
4. `npm run dev` → TestimonialSection not defined → add import
|
||||
5. `npm run dev` → Navbar/Footer not defined → add imports
|
||||
6. `npm run dev` → ✅ WERKT! Site is zichtbaar
|
||||
7. Inline styles → Tailwind conversie (Inline Edit)
|
||||
|
||||
---
|
||||
|
||||
## Verwachte Requests Gebruik
|
||||
|
||||
| Actie | Requests |
|
||||
|-------|----------|
|
||||
| "Welke deps missen?" (Chat) | 1 |
|
||||
| Fix typos/imports (handmatig of Chat) | 0-1 |
|
||||
| Inline styles conversie (Inline Edit × 3-5) | 3-5 |
|
||||
| **Totaal** | **4-7 requests** |
|
||||
|
||||
Studenten op Hobby plan moeten dit kunnen doen. Tab Completion helpt bij imports.
|
||||
|
||||
---
|
||||
|
||||
## Tips voor Tim
|
||||
|
||||
- **Moeilijkheidsgraad:** Gemiddeld. Fouten 1-4 zijn "lees de error message" niveau. Fout 5 (Tailwind) is de echte oefening.
|
||||
- **Als studenten vastlopen:** Wijs ze op de terminal error messages. Zeg: "Lees de eerste regel van de error."
|
||||
- **Grid responsiveness:** De FeatureCards en TestimonialSection grids zijn `repeat(3, 1fr)` — op mobiel breken ze. Bonuspunt als studenten dit ook fixen naar responsive grid.
|
||||
- **Contact form:** Werkt functioneel (alert), maar alle styling is inline. Goed voorbeeld van een formulier omzetten naar Tailwind.
|
||||
@@ -1,322 +0,0 @@
|
||||
# Debug Challenge HARD - Antwoordenblad (ALLEEN VOOR TIM)
|
||||
|
||||
**⚠️ NIET DELEN MET STUDENTEN**
|
||||
|
||||
---
|
||||
|
||||
## Overzicht
|
||||
|
||||
Dit project is aanzienlijk complexer dan de easy versie. Het bevat:
|
||||
- Blog met dynamische routes
|
||||
- Dashboard met statistieken
|
||||
- API route voor quotes
|
||||
- Utility functions
|
||||
- TypeScript types
|
||||
|
||||
**12 fouten verspreid over 4 categorieën:**
|
||||
- Blokkerende fouten (compile/runtime)
|
||||
- Logische fouten (code draait maar werkt verkeerd)
|
||||
- Pattern fouten (React anti-patterns)
|
||||
- Styling fouten (inline styles + custom CSS → Tailwind)
|
||||
|
||||
**Geschatte tijd: 2-3 uur met AI**
|
||||
|
||||
---
|
||||
|
||||
## CATEGORIE 1: BLOKKERENDE FOUTEN
|
||||
|
||||
### Fout 1: Missing dependency — `clsx`
|
||||
|
||||
**Bestand:** `lib/utils.ts` (regel 2)
|
||||
**Symptoom:**
|
||||
```
|
||||
Module not found: Can't resolve 'clsx'
|
||||
```
|
||||
|
||||
**Oorzaak:** `clsx` wordt geïmporteerd maar staat niet in package.json.
|
||||
`formatDate()` wordt overal gebruikt, dus dit blokkeert ALLES.
|
||||
|
||||
**Fix:**
|
||||
```bash
|
||||
npm install clsx
|
||||
```
|
||||
|
||||
**Moeilijkheid:** ⭐ (makkelijk, zelfde als easy versie)
|
||||
|
||||
---
|
||||
|
||||
### Fout 2: Verkeerde import path — NextResponse
|
||||
|
||||
**Bestand:** `app/api/quotes/route.ts` (regel 2)
|
||||
**Symptoom:**
|
||||
```
|
||||
Module not found: Can't resolve 'next/servers'
|
||||
```
|
||||
|
||||
**Oorzaak:** `"next/servers"` moet `"next/server"` zijn (zonder s).
|
||||
|
||||
**Fix:**
|
||||
```ts
|
||||
// FOUT:
|
||||
import { NextResponse } from "next/servers";
|
||||
|
||||
// CORRECT:
|
||||
import { NextResponse } from "next/server";
|
||||
```
|
||||
|
||||
**Moeilijkheid:** ⭐⭐ (subtiel — 1 letter verschil)
|
||||
|
||||
---
|
||||
|
||||
## CATEGORIE 2: LOGISCHE FOUTEN
|
||||
|
||||
### Fout 3: Array.slice() met verkeerde parameters
|
||||
|
||||
**Bestand:** `components/BlogPreview.tsx` (regel 7)
|
||||
**Symptoom:** BlogPreview sectie op homepage toont GEEN posts (lege grid)
|
||||
|
||||
**Oorzaak:** `blogPosts.slice(-2, 0)` retourneert een lege array.
|
||||
`slice(-2, 0)` betekent: start bij index -2 (2e van achteren), stop bij index 0 — dat is leeg!
|
||||
|
||||
**Fix:**
|
||||
```ts
|
||||
// FOUT:
|
||||
const recentPosts = blogPosts.slice(-2, 0);
|
||||
|
||||
// CORRECT:
|
||||
const recentPosts = blogPosts.slice(0, 2);
|
||||
```
|
||||
|
||||
**Moeilijkheid:** ⭐⭐⭐ (geen error, gewoon lege output — student moet debuggen WAAROM)
|
||||
|
||||
---
|
||||
|
||||
### Fout 4: Icon mapping mist "star" entry
|
||||
|
||||
**Bestand:** `app/dashboard/page.tsx` (regel 25-30)
|
||||
**Symptoom:** De "Rating" stat card toont geen icon (undefined rendered als leeg)
|
||||
|
||||
**Oorzaak:** `getIcon()` functie heeft entries voor "users", "eye", "clock" maar NIET voor "star". De stats array bevat wel `icon: "star"`.
|
||||
|
||||
**Fix:**
|
||||
```ts
|
||||
function getIcon(iconName: string) {
|
||||
const icons: Record<string, React.ReactNode> = {
|
||||
users: <Users size={24} />,
|
||||
eye: <Eye size={24} />,
|
||||
clock: <Clock size={24} />,
|
||||
star: <Star size={24} />, // ← TOEVOEGEN
|
||||
};
|
||||
return icons[iconName];
|
||||
}
|
||||
```
|
||||
|
||||
**Moeilijkheid:** ⭐⭐⭐ (geen crash, subtiel visueel verschil)
|
||||
|
||||
---
|
||||
|
||||
### Fout 5: Mobile menu altijd verborgen
|
||||
|
||||
**Bestand:** `components/Header.tsx` (regel 62 + 73)
|
||||
**Symptoom:** Hamburger menu knop is onzichtbaar, en zelfs als je `display: none` verwijdert van de button, is het dropdown menu ALSOOK `display: none`.
|
||||
|
||||
**Oorzaak:** Twee problemen:
|
||||
1. De hamburger button heeft `display: 'none'` → onzichtbaar
|
||||
2. Het mobile menu div heeft `display: 'none'` → zelfs als `menuOpen` true is
|
||||
|
||||
**Fix:** Dit moet volledig naar responsive Tailwind met `md:hidden`/`md:flex`:
|
||||
```tsx
|
||||
// Button: verberg op desktop, toon op mobiel
|
||||
<button className="md:hidden" ...>
|
||||
|
||||
// Desktop nav: verberg op mobiel
|
||||
<nav className="hidden md:flex gap-6" ...>
|
||||
|
||||
// Mobile menu: toon als flex wanneer open
|
||||
{menuOpen && (
|
||||
<div className="flex flex-col md:hidden p-3 border-t bg-white">
|
||||
```
|
||||
|
||||
**Moeilijkheid:** ⭐⭐⭐⭐ (vereist begrijpen van responsive design patterns)
|
||||
|
||||
---
|
||||
|
||||
## CATEGORIE 3: REACT PATTERN FOUTEN
|
||||
|
||||
### Fout 6: async functie in useEffect
|
||||
|
||||
**Bestand:** `app/dashboard/page.tsx` (regel 35-39)
|
||||
**Symptoom:** React warning in console:
|
||||
```
|
||||
Warning: useEffect must not return anything besides a function
|
||||
```
|
||||
En mogelijke infinite loop.
|
||||
|
||||
**Oorzaak:** `useEffect(async () => {...})` is een React anti-pattern. async functie retourneert een Promise, maar useEffect verwacht `void` of een cleanup functie.
|
||||
|
||||
**Fix:**
|
||||
```tsx
|
||||
// FOUT:
|
||||
useEffect(async () => {
|
||||
const res = await fetch("/api/quotes");
|
||||
...
|
||||
}, [quote]);
|
||||
|
||||
// CORRECT:
|
||||
useEffect(() => {
|
||||
async function fetchQuote() {
|
||||
const res = await fetch("/api/quotes");
|
||||
const data = await res.json();
|
||||
setQuote(data.text);
|
||||
setLoading(false);
|
||||
}
|
||||
fetchQuote();
|
||||
}, []); // ← ook dependency array gefixed (zie Fout 7)
|
||||
```
|
||||
|
||||
**Moeilijkheid:** ⭐⭐⭐⭐ (vereist kennis van React hooks patterns)
|
||||
|
||||
---
|
||||
|
||||
### Fout 7: Verkeerde dependency array → infinite loop
|
||||
|
||||
**Bestand:** `app/dashboard/page.tsx` (regel 39)
|
||||
**Symptoom:** Dashboard pagina loopt vast, continue fetch requests in Network tab
|
||||
|
||||
**Oorzaak:** `[quote]` als dependency betekent: "run opnieuw als `quote` verandert". Maar de effect ZET quote, wat de effect OPNIEUW triggert → infinite loop.
|
||||
|
||||
**Fix:**
|
||||
```tsx
|
||||
// FOUT:
|
||||
}, [quote]);
|
||||
|
||||
// CORRECT:
|
||||
}, []); // Lege array = run 1x bij mount
|
||||
```
|
||||
|
||||
**Moeilijkheid:** ⭐⭐⭐⭐ (vereist begrip van useEffect dependency arrays)
|
||||
|
||||
---
|
||||
|
||||
### Fout 8: Null check mist op quote state
|
||||
|
||||
**Bestand:** `components/QuoteOfTheDay.tsx` (regel 22)
|
||||
**Symptoom:** `TypeError: Cannot read properties of null (reading 'text')`
|
||||
|
||||
**Oorzaak:** `quote` begint als `null`, maar zodra loading false is, probeert de component `quote.text` te lezen. Als de API fails of traag is, kan dit crashen.
|
||||
|
||||
**Fix:** Voeg TypeScript type toe en null check:
|
||||
```tsx
|
||||
// Verbeterde state typing:
|
||||
const [quote, setQuote] = useState<{ text: string; author: string } | null>(null);
|
||||
|
||||
// In de render:
|
||||
{!loading && quote && (
|
||||
<>
|
||||
<blockquote>"{quote.text}"</blockquote>
|
||||
<cite>— {quote.author}</cite>
|
||||
</>
|
||||
)}
|
||||
```
|
||||
|
||||
**Moeilijkheid:** ⭐⭐⭐ (runtime error, maar duidelijke error message)
|
||||
|
||||
---
|
||||
|
||||
## CATEGORIE 4: STYLING FOUTEN (Inline Styles → Tailwind)
|
||||
|
||||
### Fout 9: Custom CSS classes in globals.css
|
||||
|
||||
**Bestand:** `app/globals.css`
|
||||
**Probleem:** `.card`, `.page-container`, `.section-title` zijn custom CSS classes. Deze horen Tailwind utility classes te zijn.
|
||||
|
||||
**Fix:** Verwijder custom CSS uit globals.css. Vervang in alle componenten:
|
||||
- `.card` → `className="p-6 bg-white rounded-xl border border-gray-200 hover:shadow-lg hover:-translate-y-0.5 transition-all"`
|
||||
- `.page-container` → `className="max-w-[1200px] mx-auto px-5"`
|
||||
- `.section-title` → `className="text-3xl font-bold text-center mb-10 text-gray-900"`
|
||||
|
||||
**Moeilijkheid:** ⭐⭐⭐ (moet begrijpen waarom Tailwind beter is dan custom CSS)
|
||||
|
||||
---
|
||||
|
||||
### Fout 10-12: Inline styles in alle componenten
|
||||
|
||||
**Bestanden met inline styles:**
|
||||
|
||||
| # | Bestand | Complexiteit |
|
||||
|---|---------|-------------|
|
||||
| 10 | `components/Hero.tsx` | Hoog (gradient, positioning) |
|
||||
| 11 | `components/Header.tsx` | Hoog (responsive, sticky) |
|
||||
| 12 | `components/Footer.tsx` | Medium (grid, links) |
|
||||
| - | `components/StatsSection.tsx` | Medium (grid) |
|
||||
| - | `components/BlogPreview.tsx` | Medium (grid, cards) |
|
||||
| - | `components/QuoteOfTheDay.tsx` | Laag |
|
||||
| - | `app/blog/page.tsx` | Medium (grid, tags) |
|
||||
| - | `app/blog/[slug]/page.tsx` | Medium (article layout) |
|
||||
| - | `app/dashboard/page.tsx` | Hoog (stats grid, cards) |
|
||||
|
||||
**Studenten moeten minimaal 3-4 bestanden omzetten.**
|
||||
|
||||
**Aanpak:**
|
||||
1. Selecteer inline style code
|
||||
2. `Ctrl+K` → "Converteer inline styles naar Tailwind CSS. Gebruik de brand- kleuren uit tailwind.config.ts waar mogelijk."
|
||||
3. Review + Accept
|
||||
|
||||
**Moeilijkheid:** ⭐⭐ per bestand (maar het zijn er VEEL)
|
||||
|
||||
---
|
||||
|
||||
## Samenvatting Alle Fouten
|
||||
|
||||
| # | Type | Bestand | Ernst | Moeilijkheid |
|
||||
|---|------|---------|-------|-------------|
|
||||
| 1 | Missing dependency (clsx) | lib/utils.ts | 🔴 Blokkerend | ⭐ |
|
||||
| 2 | Verkeerde import (next/servers) | api/quotes/route.ts | 🔴 Blokkerend | ⭐⭐ |
|
||||
| 3 | Verkeerde slice() params | BlogPreview.tsx | 🟡 Logisch | ⭐⭐⭐ |
|
||||
| 4 | Missende icon mapping | dashboard/page.tsx | 🟡 Logisch | ⭐⭐⭐ |
|
||||
| 5 | Mobile menu altijd hidden | Header.tsx | 🟡 Logisch | ⭐⭐⭐⭐ |
|
||||
| 6 | async in useEffect | dashboard/page.tsx | 🟠 Anti-pattern | ⭐⭐⭐⭐ |
|
||||
| 7 | Infinite loop dep array | dashboard/page.tsx | 🔴 Runtime crash | ⭐⭐⭐⭐ |
|
||||
| 8 | Null check quote state | QuoteOfTheDay.tsx | 🔴 Runtime crash | ⭐⭐⭐ |
|
||||
| 9 | Custom CSS → Tailwind | globals.css | 🟡 Styling | ⭐⭐⭐ |
|
||||
| 10-12 | Inline styles (9+ bestanden) | Overal | 🟡 Styling | ⭐⭐ elk |
|
||||
|
||||
---
|
||||
|
||||
## Verwachte Oplos-Volgorde
|
||||
|
||||
1. `npm install` → werkt
|
||||
2. `npm run dev` → `Can't resolve 'clsx'` → `npm install clsx`
|
||||
3. `npm run dev` → `Can't resolve 'next/servers'` → fix import
|
||||
4. Site laadt! Maar:
|
||||
- BlogPreview is leeg → fix slice()
|
||||
- Dashboard crasht/loopt vast → fix useEffect + dep array
|
||||
- Quote component crasht → fix null check
|
||||
- Rating icon mist → fix icon mapping
|
||||
- Mobile menu werkt niet → fix responsive
|
||||
5. Inline styles → Tailwind conversie
|
||||
6. Custom CSS → Tailwind refactor
|
||||
|
||||
---
|
||||
|
||||
## Verwacht Request Gebruik
|
||||
|
||||
| Actie | Requests |
|
||||
|-------|----------|
|
||||
| Debug blokkerende errors (Chat) | 2-3 |
|
||||
| Fix logische fouten (Chat + Edit) | 3-4 |
|
||||
| Fix React patterns (Chat) | 2-3 |
|
||||
| Inline styles → Tailwind (Inline Edit × 4-5) | 4-5 |
|
||||
| **Totaal** | **11-15 requests** |
|
||||
|
||||
⚠️ Dit is meer dan de easy versie. Studenten op Hobby plan moeten efficiënt werken. Student plan (500/maand) is ruim voldoende.
|
||||
|
||||
---
|
||||
|
||||
## Tips voor Tim
|
||||
|
||||
- **Dit is echt moeilijk.** Fout 5, 6, 7 zijn lastig voor beginners. Verwacht dat studenten hier hulp bij nodig hebben.
|
||||
- **De useEffect fouten** zijn een goed leermoment — dit is een HEEL veelvoorkomende bug in React.
|
||||
- **De slice() bug** is een subtiele logische fout. Studenten moeten leren: "het werkt zonder errors, maar het resultaat klopt niet" → debuggen.
|
||||
- **Mobile menu** is bewust moeilijk. Dit vereist dat ze responsive design begrijpen. Goede Cursor prompt: "Maak deze header responsive met een hamburger menu dat werkt op mobiel met Tailwind."
|
||||
- **Geef de easy zip als standaard.** Hard is voor studenten die de easy versie snel af hebben of die extra uitdaging willen.
|
||||
@@ -1,212 +0,0 @@
|
||||
%PDF-1.4
|
||||
%<25><><EFBFBD><EFBFBD> ReportLab Generated PDF document (opensource)
|
||||
1 0 obj
|
||||
<<
|
||||
/F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 5 0 R /F5 6 0 R /F6 10 0 R
|
||||
>>
|
||||
endobj
|
||||
2 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
3 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
4 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica-Oblique /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
5 0 obj
|
||||
<<
|
||||
/BaseFont /ZapfDingbats /Name /F4 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F5 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<<
|
||||
/Contents 18 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 17 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
8 0 obj
|
||||
<<
|
||||
/Contents 19 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 17 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
9 0 obj
|
||||
<<
|
||||
/Contents 20 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 17 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
10 0 obj
|
||||
<<
|
||||
/BaseFont /Symbol /Name /F6 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
11 0 obj
|
||||
<<
|
||||
/Contents 21 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 17 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
12 0 obj
|
||||
<<
|
||||
/Contents 22 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 17 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
13 0 obj
|
||||
<<
|
||||
/Contents 23 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 17 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
14 0 obj
|
||||
<<
|
||||
/Contents 24 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 17 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
15 0 obj
|
||||
<<
|
||||
/PageMode /UseNone /Pages 17 0 R /Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
16 0 obj
|
||||
<<
|
||||
/Author (\(anonymous\)) /CreationDate (D:20260224202513+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260224202513+00'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
17 0 obj
|
||||
<<
|
||||
/Count 7 /Kids [ 7 0 R 8 0 R 9 0 R 11 0 R 12 0 R 13 0 R 14 0 R ] /Type /Pages
|
||||
>>
|
||||
endobj
|
||||
18 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1125
|
||||
>>
|
||||
stream
|
||||
GauHJbAu>s&A7<Z-DsjA&V@iWKPu^L<1G@cCq+i_Ke("q>nX,uP2k9MO3[e?.I1PVX-/]HU]b(Umch^k#b4'qT&U^(]*.!'7mI*s/YHP[OqA+dhU`gO7[f]9,6UD4Z<.E-@D1uTrJ4bZf,dkq&Wm8E7&2X@Zbe1qV4.$i8aK7^$m[W\+@*jd!_l&_KP&@tD.u7u6%@s1O=,#0r`N"SoIc\0>qp><e,PM1g!.^,OPE4o$3lu.`8Z(r;A0ER94\Sf0bNmNrs'4f0Tgl4,Vq-Z1#pi.9W7Ki>V97^%sa;bMnZ[r,<][W!N4,@/ut#XB'_fEg1hBJDR1K@0p4kTQF?0.2HG2"`.Ha2.iLo?$4>.7^;c@((snnt_<i`sO4Ne;(cJ1Xd;^_eML9@Q?^'=8%4^6R(>[&q=*PL$1^^fQ'CbLj-I=t-h=MuR?p/qQd=1*HQ;Z/p4YCC=WI':+pUFW*29`,lhMi<pct@8[F[%=uBtZT>PO6t`\8%<Gl1?jGX3,@gX5H3E%IU)1OZMTO&$1-ZGn$0oc^2Q@dJ:gY6[3QMS\#]?N1Fk<#P:q,Z7*!`2jUh&.;kF>J&[F9#jX=+/<^Ynko(_m/(2Nd]K0@W_r?r#:GegA%'H<rWrA@Gm1o+(\GGgfj7"mVbH'U@n7%%-*n6X-=;`,iV0LV,i=NgK/;nN.&DVHMS+iq*>o;!C[U`Mu_ccf;R$MHpUZU(VEfbQ:%E<6B);J(@@K5K]*K@bm&spo/*CY03Tm4GR"h]oO2V9,6oN+<iIFTb/oZ2rmRW/n-+?r8-%[p(Qibe^EkT+]K$)u`EIRh]3+tN[qmBpTc8Gcr.F]$R62Nlod7GK`&(-YX<Qt_Pr[uI)bIjbe:]+3ND5mNUQ-Mn^_VaP)+[B]?^4Gjkj1\<JY]!Mm65Am$)Bk-d^BPV/<B+Z4uLKP^1N-%&X%`V-?7)EA*!BX'%BZ=U^RJ6EUW9aIP2=A,U(L@Y6[5(5uJaO64gsmchc-pMI/*8W;(LcfQ?>+gGmOsL*=qKa"TECNUbl*'mA`:[G!FFSEJr[pa'<JgH..RSuR[E6eJ6QU/M"^aT*-Dt.EU88`2g!il`T?"?n=cA^H@/4AMPfnnSP\hYHian+hZ<XDS/V~>endstream
|
||||
endobj
|
||||
19 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 951
|
||||
>>
|
||||
stream
|
||||
Gaua;_,B#A&;KY!MWJH;W@H#qCi_,G)/(0YEL@kgEK\9qEU4f0D9:7NjZ"Ru1A'"/1)%Wi<rW,;="AgM=#@\P3P\2p+8Z+mK_QUA@LD*&LuR9$:UE3+^g&H;po_dA,s;V$h/'2lORQQ?Je"D34SDkoC@2<l;m((f@+p'W0PR_`35r__RY<L2n:;Vh_Ym>mH+roM#Y]P,Uf^A&>hYR):>Y3!4">riZd"tb1UW5TSQu]pS;r]#,IBVNq1>hSju$C5E>/i^N@@R*Wsf@Q9'O5=W?J<MJhY&5M0W-t#DWjT5^[,"J('LhBueiD[.IHC`+rbMAP[$;'G'Rl;h:7K8&hC/4964V&op?T$^MkifB580M$`L]"!fIR`Z5Fj6sC5d4>#9#K&PM)T<:I"_o]mJf<<T2BQ+kUs6=r)+St7cU;754Ds/"#;7bjQIk"FRqS'$6l`>2bD,`Tp\0?"UZDKI[8s@\2'1#d"Z5TFXYQi%?JuVR>c(L^-#)YZ&<P=ln*F3!eW&"=b\u"cE+1L?(%^IOY[EN::)fIR0?90MR2*2#9S_d>@djMKoL8O)cZ`9`\,J+=7-<Q5!NaJ@:5X\-Ya`s,I#ertfW?K6C=_=uYk"0#5(]r9=b.=/1TdgGYiT"/c2O3)44j:12B[?SN>[RLQ4E?GE%aBqf9u=74U,4a<X/BkLC,\fun!eo[C,r:MbRs-<70u=O5`TuH#(BJ7N2KfB4Cmr,MW7i0W<8BN3;EqC/esFjpGPS\G3dX&mA3m+lbaj,XrY&Cs5*"&h!T<9H!H#k>(q&c8aYm%29B'Ll'eXWjl-7mD1N;*<VB6S;5R;RoX$=6.*"=`N3PMdZBZ4a8+WlN0h":),uHJj\JKG/?Ad4;"frOW*jnVp_(M[<h.&F`d5%Q2-$bLSh2%bGQC,e`E*Y/MX1NF4.oW5PQY!n&]M?nV83h&aL#*nW_R)u~>endstream
|
||||
endobj
|
||||
20 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1197
|
||||
>>
|
||||
stream
|
||||
Gaua=?#T!f&;KZL'si,VS38m;P;o7[/58@)MY<9N='BTR_>o-pViCec^O@QhX"C0M<n_DQ+;r5nqp%1IP^uIL<e%#gJ3O\AH-Uq[84LCBa+r^oihZ+k@%/N4jEQ8tqMcIZME"=Gd"UCd!"S1c+#%Y;]]IT\B&$5UZp9Es`ZT(X?Kes4(kg9q>.".QA+dR+G-(EQ::/]@inKH,4i'%_P;tIH8c':u.9tb8>kL.E0q@/!RD`C@^ZqE0h%N>VOF4+[q"9sLJ@pTkYLL<ImYTcp6c6#rf.u#3A$q7V>AgRSf%`C*-aKTc();dJ8`(==WBt+%q&STq)AjZ_R715OR9<?(=r;#p3\N>)WQK?(`l0[[6,^7M&'q*CNRkMS^#H.G$Mc>LW*7>p2qWfZ-JU^2TAW#-l4,OO/MXXNK%4%e-_s:*=%G:KAr^AS4I_YFIrbC#r?cV5R*M_U[#L3/0Ln4P6W>/j,bRbYJSBUP3[9\>cUnSVJ-cs3.*K^t9/A];H&lQrP_@cU:g.!^Xfg96aJ-c*p_0O8p^5Kdg@Q[_T'J\.,H4b&BBT&\\f*+-XibI:d-:4P-8NbGRJOjqpT%6;>lOTL':i7hE=[GHs1h">BsiU57c6\Ka1Ms';>l2Q(AZ9aoRh&4*--Xm#C_R2(:YrbldCd9G@9,NLEGH9LrK-T*F'.u)8s)pr1,U!(M2MX_iSEJ@88Ip?l%E(3X\l$6Re>Oqphqus%^0lB0Q6Bh*1p$RKG+iM92V>=OAp'KYO^"=I.8+p--4fX51<[%]f*b82\',G::/`0a86bS^:Z'IpH:J:>mgCG7qE&-V8^;h=QF4RK=;.,=p-XDfj@7j8ZhB4CqFp;VCD,+g"2.8f/0s#E*R.9/KhA-TV&4q7%ppcPODP\VrTAG5VB9K\3&>;.;X+;,\SiilFI:&S1^9;CIJFjG<DOLd=E[2)/\hN?Tj<^O;I]7Kkj8R#D!kEk&S@_u^ZrY4N<:h9*/`Q*[mu9T:f-[JsLt2dYpCr@Zfh2D_RX5]aBjkpS+sXn2,Do>-6E?W$i:T8Zaq$2R[%:CT2#\jNJdSjR4g`HTNRNs55TP8+ia>opN3@(B9qEHbZ,Hq*`UJGXfZ#/p,KV#Yl8Q3t?7)52um"K71sf2u)+3(&!(/#;;f.f+pshn5aS:,K(9F`6]Oi)5UdXATY]_-8qFPQ^HC6tlK#OQ!qg~>endstream
|
||||
endobj
|
||||
21 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1262
|
||||
>>
|
||||
stream
|
||||
Gau0B;0/3d&:XAWfR'XI>SKa8!IhZUOs\X_g5K`Y3o_"oX-bE1"QZr#?[iFfN,]j#*mU@^$sKcV^]!ki(f:.9qDZOs/j_P4@_asVhgl(X+M<EOE:c,!NMZ9(,<6"TEJQ9XMp"Ta]m3l$4GQ!@K<;uML]i:)Se&d6-2624/E0NelN@Am8eUWD_&5EN)SWs.&IF+ffCsPLU4!t*X^gF=&Md4sX`pW7X3DR6V(*Y4cin>naNDKtQ.U@'kP5F;J+)'MiQA5RaAWUAQ0B9[FC@l5O8=G-Qcd0;>9(i:_PgoM:TCe$0b9ScKoV?:<f&FOX).E;*QL5@XkkCP?R9]!6[@RJ6c^QtM9jfcnTNV$OpF@+C7^4cB$NQu18p9LN43d#d.RP#Ga/%6jK&Ee6^_"`eu9=t_7>=HqNJ!`NJNU-i?+[X9OJWb]=kcP!*>f,KU6m:+5c-nP&$H<k>[ep^a]T'a)g[k/`aNb&?7#SRH2QeaUVQ/TYNNQf'u*UM*Q1SLBumX#h!^/'>kh+9r0-O%^[^XX2:3[Sj9U'Y2!QS)/YKB\Pbj41taDL?<"('YW]XO;01U=5PB`k'R7mc9p",&gW]N4hW3)THB90VkWZ.p*l&aE"EA/lQog/I&f1<MBcaBLCGM:&Ae:f=/2?hnQpf$khgmng=J&#/[gJ6HjsQA/Q=K]iM^Oe1Yf,C4d2BE<_:g5M@\6lNa745TWe^*6s$q;N4i8nN+UUsVRF8*_M</+/`<(f8C@$R,2*$i@l:MYO4NWg[6#=6I+`3PY.\221m'(BA0>YM6NX%sQ+7G!g],l/bJ3r8D!7t+rT`8#HpXQb'>lI>UjA%^i.NBcGqga.BMdi7TJ4=K1Q\e.3:2Q,bIY;d0B$8Yaa@7S#WhUL,aC%)J'rer::QO.9o67mjmC*$ihcJY(m`k=JV'$gBX8s=6]q%B^>^VmM(EG06A$*bH2piF&T,cr07hMU.4+,C2.QW4&@j_f)^K[/s]jmtGn\n-J,k.W!.Yeas`R`h07m5kdf1ao)DO8L/@!r;KIDe!6p-@qH3Pm/f`S;EmWQ?2Zr@>-6Z+UnNb#Qpu%e#;2=ZMAdOi_``bO]M^D%KqN3YF`bnCj9)AP4*kF5OH1lJ`90S#*<6a(ri5qiro0:#;A9J*COMc?cp9kNouR]8Ht-%%2YZ-%nco<%OBq$T;Z1aW'>0cITU->MWcK3YV:p\rjgNV:&?+Yt!ib`oClaZI/EY:LA%ug;LR]<lUr)Q_,#LknJq[Qn\@Q+q_5s~>endstream
|
||||
endobj
|
||||
22 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 504
|
||||
>>
|
||||
stream
|
||||
Gat%^hbV*C&BE]&=55$`=OsYB=s"=c-7BcK?c7^$V9Ea+Yi1ZChE%\<JhV5eZ<Y0=rNpd(+`r;$mj&/%-IB<CJ-dJW^_BX:#&oh1b5cmc9B%oT&MPYr?m9W6p$m7-9Mg,;\,aN/P!ib=-N[<eB'fT?R*ulSP!"[,h9aViT75PDh<>VLpOCDMnWOs7hFE9B?_#'D:=bs\^2GY"gGf5$@7YEP9l.PJKeBC2o2qulI+4?0[0<SQO#'=5+_gD07T:MS@eSu(X/G2Ch_0-m2k:sa2m_XqV;G2Lh?;jJ%V$d=V*(hrV2)BfY']H?!QR81PVW8)G[*nk@aQ(*2fohXkQ]>Hm-k*$\aB?#Ao%"d']H*RMus#&VQ-/IX]eGg!dnkBg<K%:K82Lreh';,0-$_=mB$@VBcJl7LkRI4rIY#(3'e-(`3E-@Zg':/&u#ctl1*KCj]lAb/rYN^X7%Z(3eJ"f1#*51DP1p-/gk^UZ_-<l123G4D-Ra+0>MuDPQ~>endstream
|
||||
endobj
|
||||
23 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 950
|
||||
>>
|
||||
stream
|
||||
Gau`R9lo#B&A@ZcG&kZcFQ,p`2n+H:aHV'/\2eO`=;V3G,.=!us1W8Y'#MGodjaO;6*ONamn(-07=ejAeb:m(\-V$Y2[Yd80EZ&-('I"g"g+[<XZ[]N0HJ0;pC,7:(f"l*%u7\R(lZ"k9u6=eDrDU;glg2EgMoh)"kP\,QOjZ_%^T)=Zu"r,mE9IhC1#$Nl@%'ohAFjcBK\FJTfib.n%e?Vs!iQemI`>[a)H/Wlok"/HT*;`4@4!jY46!<H5jE*bUV$/*2hZJpsUPs7Y!M\rj78Z*>U(iPH&1KR]P5MEbW](bI_D(L'P[R."q"Rm9nNUm9"$-UBh8fY(kZN:n"729sHcQiFjQeFWf\-,).dCb-U&0VQq1.)53[Mk*]Nt6!GiF6BSnd)'+,bQX.gPTBp.Wr>Xb.kUqd@^?+4+EEg[1%Dr??_2B*>IA$nb"G:?d`[B#1*4A.ENH5o6D2`s<j\FnUKS4l2C#3"Q98$Qc(W`Klk;&Y[NIN9;T?]7_paft2LtqPT4>#R]$Vu]5#'!`)s!@InHP\pDclMbihhP:.THW&`QQ!e3CjYB5[eVh1TSkj,&e:*n/J^J/1;X,iL#s"8N/^Uu/RtC1<An0Bam;ehR]'=r]PPA?&SB7Z'k3M[T9uAX1]q@(HYC4h4Ii-P8M/5RU"2>iH&[$nZNVCn#o<bZ_Jq,A7dTo*7bfS9X]"AC7VaSr5'i0UmHg7Q<`1?Q8;)GGBbKPgc^T2_o[(7RKbPr%$!=%ZkcfpZ+]47ZjSCamq;:d\k!qW^M0!pXW7%'=QmC-7R:Fro9L;8p5jB@PGPgi/3p(#4C/.T?+$;jd==uPTe/"kValc_]aIDrD(A/\IH`TReZ$e<BJd/f?%4gd;(G17^'>#_(6bF\N"..R0UcZU%$C<J;9c/OdKX*;O8d./_%p(G]EEO'B8lisD0GZDHB*0?bIKOE)IM;~>endstream
|
||||
endobj
|
||||
24 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1110
|
||||
>>
|
||||
stream
|
||||
Gaua=D/\/e&BE]*;r%5lm4ajPPk$0Bj5SX*RT*KG/-Dd%[&mH-*(i[B55e6`jLDVI@'9b8#t"X[m`.EG0aoIZ/Gu$>!)=2PIE@"Z87oX_OcYO\+rNKQ=JO@X&XmdfED.RZ,;^@pFR=-AUsc-s-Sj-*-m5$!W>L_a`tDnWq7m.iV00Jk^r/VX8gEg@B!9QqrLkc]E?klrRR@T$Y.&u0T4X(*Z@_&c`V;U/]07>8HMeD=#=r1O#$n/WdR6\GpDl]B:]$4M+XogdNl;&p!2MIp%A091nD)l=k"o)BXmA0V7tDpr3!b:YMTZK)`l[Gh3S\6X0XY;j0.Zt^IGk3NEN-6mQ+8^^p@V:SJdp$5<u/?#:T8Q+S!Smr/ho<0U2CaUaMU*BoQTk<#?nT:H;EJMVNYa2!>[S#>PD&4c,e-bQQ^fa'^OdHQEu:9/7DK2MqQ=Kc`'?/;sPc;+S@qs;Ka.%[4[tl'hj!Y/ui6m`=.ri\H]ObF',:L^1Im.,hCRUI&H^u0/:pgMmS)Da&(<[q\Q"R/:I4G8)URFD3!PXFe14pJ,E%!,MM&0at@JVKrpABHung=Y?'I*1mWPk:ImsRf^Abm?1djMcdV3DgN3./Fa]aLrLSC]VO7QEKQ<d$57nA=Acrpc7(a0q5'JE0"(lbY?hhHoJk"0@%>g(1VY6sfM<(6Lh*:'9p&E"-da*7#5<_VBRV`H'_nm6c+sr!EVS^OpSkQ0.mM05-b698^1U5DXbhTT#<5'DdDY(En7OgdbR&QY$Ds:e.foEF*o0UC/S;J_gC/1jQmAFj&*_[!a["t<LQ-Xq$p[JPVUHQ)eBqJ?t_P8"m<a09$4j'Yr4")9sR>c=S)Ih2$+c-b+;InugC.5XhOV_B?=up\Ljt'b2Zef5+U9t];6,7a"LV\h)Y\RDoEqDo1_/_rb+lXV=p)fIC>VL"_Wt#^@o]LhG<:.$ud3HVWcQc@)Ns4dm-Gru7RIsh(>t#ZWTHHJ%81R,bIH=t+]/SX(>.PZ#(^=2)!dri6<A>%REM76j*BnCs0qh:/D=,BP"E=S!#9N>YSm+._E&YF%rUfM(gu1N9Im<oL_,W5!j^_4&q0):VMGJ[.Ae,OZrrQpK4+d~>endstream
|
||||
endobj
|
||||
xref
|
||||
0 25
|
||||
0000000000 65535 f
|
||||
0000000061 00000 n
|
||||
0000000143 00000 n
|
||||
0000000250 00000 n
|
||||
0000000362 00000 n
|
||||
0000000477 00000 n
|
||||
0000000560 00000 n
|
||||
0000000665 00000 n
|
||||
0000000870 00000 n
|
||||
0000001075 00000 n
|
||||
0000001280 00000 n
|
||||
0000001358 00000 n
|
||||
0000001564 00000 n
|
||||
0000001770 00000 n
|
||||
0000001976 00000 n
|
||||
0000002182 00000 n
|
||||
0000002252 00000 n
|
||||
0000002533 00000 n
|
||||
0000002633 00000 n
|
||||
0000003850 00000 n
|
||||
0000004892 00000 n
|
||||
0000006181 00000 n
|
||||
0000007535 00000 n
|
||||
0000008130 00000 n
|
||||
0000009171 00000 n
|
||||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<ae7522970d3e617d2353a6d07b4c4975><ae7522970d3e617d2353a6d07b4c4975>]
|
||||
% ReportLab generated PDF document -- digest (opensource)
|
||||
|
||||
/Info 16 0 R
|
||||
/Root 15 0 R
|
||||
/Size 25
|
||||
>>
|
||||
startxref
|
||||
10373
|
||||
%%EOF
|
||||
@@ -1,638 +0,0 @@
|
||||
# DevDash - Super Hard Debug Challenge (16-18 Errors)
|
||||
|
||||
## Challenge Overview
|
||||
|
||||
This is the **super hard tier** debug challenge with 16-18 intentional errors distributed across 6 categories. Students must identify and fix all errors to make the project run successfully.
|
||||
|
||||
---
|
||||
|
||||
## CATEGORY 1: BLOCKING ERRORS (3 Errors)
|
||||
|
||||
### Error 1: Missing Dependency - `date-fns`
|
||||
|
||||
**File:** `src/lib/utils.ts`
|
||||
|
||||
**Issue:** The code imports `format` from `date-fns`:
|
||||
```typescript
|
||||
import { format } from "date-fns";
|
||||
```
|
||||
|
||||
But `date-fns` is **NOT** listed in `package.json`.
|
||||
|
||||
**Symptom:** Runtime error: "Cannot find module 'date-fns'"
|
||||
|
||||
**Fix:** Add to `package.json` dependencies:
|
||||
```json
|
||||
"dependencies": {
|
||||
"date-fns": "^2.30.0"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Error 2: Wrong Import Path - `next/navigations` (with 's')
|
||||
|
||||
**File:** `src/components/Header.tsx`
|
||||
|
||||
**Issue:**
|
||||
```typescript
|
||||
import { usePathname } from "next/navigations"; // WRONG - has 's'
|
||||
```
|
||||
|
||||
Should be:
|
||||
```typescript
|
||||
import { usePathname } from "next/navigation"; // CORRECT
|
||||
```
|
||||
|
||||
**Symptom:** Module not found error at build time
|
||||
|
||||
**Fix:** Remove the 's' from the import path.
|
||||
|
||||
---
|
||||
|
||||
### Error 3: Circular Dependency Crash
|
||||
|
||||
**Files:** `src/lib/types.ts` and `src/lib/utils.ts`
|
||||
|
||||
**Issue:**
|
||||
|
||||
In `src/lib/utils.ts`:
|
||||
```typescript
|
||||
import { formatDate } from "./utils"; // Value import, not type
|
||||
```
|
||||
|
||||
In `src/lib/types.ts`:
|
||||
```typescript
|
||||
import { formatDate } from "./utils";
|
||||
|
||||
export function createPost(data: Omit<Post, "formattedDate">): Post {
|
||||
return { ...data, formattedDate: formatDate(data.date) }; // formatDate is undefined!
|
||||
}
|
||||
```
|
||||
|
||||
**Symptom:** `TypeError: formatDate is not a function` at runtime
|
||||
|
||||
**Fix:** Use `import type` for types to avoid the circular dependency:
|
||||
|
||||
In `src/lib/utils.ts`:
|
||||
```typescript
|
||||
import type { Post } from "./types"; // Change to type import
|
||||
```
|
||||
|
||||
Alternatively, restructure to avoid circular imports altogether.
|
||||
|
||||
---
|
||||
|
||||
## CATEGORY 2: NEXT.JS SPECIFIC ERRORS (4 Errors)
|
||||
|
||||
### Error 4: Missing "use client" Directive
|
||||
|
||||
**File:** `src/components/ThemeToggle.tsx`
|
||||
|
||||
**Issue:** The component uses `useState` (a client-side hook) but **lacks** `"use client"` at the top.
|
||||
|
||||
```typescript
|
||||
// MISSING "use client" at the top!
|
||||
import { useState } from 'react';
|
||||
export function ThemeToggle() {
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
**Symptom:** Next.js error: "You're importing a component that needs useState. It only works in Client Components."
|
||||
|
||||
**Fix:** Add at the very top of the file:
|
||||
```typescript
|
||||
"use client";
|
||||
|
||||
import { useState } from 'react';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Error 5: Hooks in Server Component
|
||||
|
||||
**File:** `src/app/dashboard/page.tsx`
|
||||
|
||||
**Issue:** The page uses `useState` and `useEffect` directly:
|
||||
```typescript
|
||||
// MISSING "use client" at the top!
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
export default function DashboardPage() {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
**Symptom:** Hydration error or "You're importing a component that needs useState"
|
||||
|
||||
**Fix:** Add `"use client"` directive at the top:
|
||||
```typescript
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Error 6: Wrong Middleware Matcher Pattern
|
||||
|
||||
**File:** `middleware.ts`
|
||||
|
||||
**Issue:**
|
||||
```typescript
|
||||
export const config = {
|
||||
matcher: ['/dashboard/:path'], // WRONG - missing asterisk
|
||||
};
|
||||
```
|
||||
|
||||
This matches `/dashboard/:path` but NOT `/dashboard/page/subpage`. The sub-routes won't be protected.
|
||||
|
||||
Also, the middleware looks for `'auth-token'` cookie but the app doesn't set one:
|
||||
```typescript
|
||||
const authToken = request.cookies.get('auth-token')?.value;
|
||||
```
|
||||
|
||||
**Symptom:** Sub-routes of dashboard bypass middleware; authentication doesn't work
|
||||
|
||||
**Fix:**
|
||||
```typescript
|
||||
export const config = {
|
||||
matcher: ['/dashboard/:path*'], // Add asterisk for all sub-routes
|
||||
};
|
||||
```
|
||||
|
||||
And update cookie name to match what's actually used or create a mock auth mechanism.
|
||||
|
||||
---
|
||||
|
||||
### Error 7: `metadata` Export in Client Component
|
||||
|
||||
**File:** `src/app/blog/[slug]/page.tsx`
|
||||
|
||||
**Issue:**
|
||||
```typescript
|
||||
'use client'; // This is a CLIENT component
|
||||
|
||||
export const metadata = { // Can't export metadata from client!
|
||||
title: 'Blog Post',
|
||||
description: 'Read the full article',
|
||||
};
|
||||
|
||||
import { useParams } from 'next/navigation';
|
||||
```
|
||||
|
||||
**Symptom:** Build error: "Metadata exports must be in a Server Component"
|
||||
|
||||
**Fix (Option 1):** Remove `'use client'` and use function parameters instead of `useParams()`:
|
||||
```typescript
|
||||
// Remove "use client"
|
||||
import { generateMetadata } from 'next';
|
||||
import type { Metadata } from 'next';
|
||||
|
||||
export async function generateMetadata({ params }): Promise<Metadata> {
|
||||
const post = getPostBySlug(params.slug);
|
||||
return {
|
||||
title: post?.title || 'Blog Post',
|
||||
description: post?.content.substring(0, 100) || '',
|
||||
};
|
||||
}
|
||||
|
||||
export default function BlogPostPage({ params }: { params: { slug: string } }) {
|
||||
const post = getPostBySlug(params.slug);
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
**Fix (Option 2):** Keep as client component and remove metadata export:
|
||||
```typescript
|
||||
'use client';
|
||||
|
||||
// Remove metadata export
|
||||
|
||||
import { useParams } from 'next/navigation';
|
||||
// ... rest of component
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CATEGORY 3: LOGIC ERRORS (3 Errors)
|
||||
|
||||
### Error 8: Wrong Filter Condition
|
||||
|
||||
**File:** `src/data/posts.ts`
|
||||
|
||||
**Issue:**
|
||||
```typescript
|
||||
export function getPublishedPosts(): Post[] {
|
||||
return posts.filter(p => p.draft); // WRONG - returns DRAFTS!
|
||||
}
|
||||
```
|
||||
|
||||
Should check for `!p.draft` (NOT drafted):
|
||||
```typescript
|
||||
export function getPublishedPosts(): Post[] {
|
||||
return posts.filter(p => !p.draft); // CORRECT
|
||||
}
|
||||
```
|
||||
|
||||
**Symptom:** Blog page shows only draft posts (only 1 post visible instead of 2 published ones)
|
||||
|
||||
**Fix:** Change condition to `!p.draft`.
|
||||
|
||||
---
|
||||
|
||||
### Error 9: Stale Closure in Event Handler
|
||||
|
||||
**File:** `src/components/Testimonials.tsx`
|
||||
|
||||
**Issue:**
|
||||
```typescript
|
||||
useEffect(() => {
|
||||
const timer = setInterval(() => {
|
||||
setCurrentIndex(currentIndex + 1); // STALE CLOSURE!
|
||||
}, 4000);
|
||||
return () => clearInterval(timer);
|
||||
}, []); // Empty dependency array captures initial value
|
||||
```
|
||||
|
||||
The `currentIndex` is captured from the initial render (0). The interval always increments from 0 to 1, causing the carousel to jump back repeatedly.
|
||||
|
||||
**Symptom:** Testimonial carousel doesn't advance smoothly; always jumps to position 1
|
||||
|
||||
**Fix:** Use the functional update form of `setState`:
|
||||
```typescript
|
||||
useEffect(() => {
|
||||
const timer = setInterval(() => {
|
||||
setCurrentIndex(prev => (prev + 1) % testimonials.length); // Use prev!
|
||||
}, 4000);
|
||||
return () => clearInterval(timer);
|
||||
}, []);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Error 10: Using Index as Key
|
||||
|
||||
**File:** `src/components/Features.tsx`
|
||||
|
||||
**Issue:**
|
||||
```typescript
|
||||
{displayedFeatures.map((feature, index) => (
|
||||
<div key={index}> // WRONG - using index as key
|
||||
{/* ... */}
|
||||
</div>
|
||||
))}
|
||||
```
|
||||
|
||||
Using index as key is problematic if the list reorders or filters.
|
||||
|
||||
**Symptom:** Visual glitches when filtering features; component state gets mixed up
|
||||
|
||||
**Fix:** Use unique identifier:
|
||||
```typescript
|
||||
{displayedFeatures.map((feature) => (
|
||||
<div key={feature.id}> // Use feature.id
|
||||
{/* ... */}
|
||||
</div>
|
||||
))}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CATEGORY 4: TYPESCRIPT ERRORS (2 Errors)
|
||||
|
||||
### Error 11: Wrong API Response Type
|
||||
|
||||
**File:** `src/app/api/stats/route.ts` and `src/components/StatsGrid.tsx`
|
||||
|
||||
**Issue:**
|
||||
|
||||
API returns wrapped response:
|
||||
```typescript
|
||||
// src/app/api/stats/route.ts
|
||||
return NextResponse.json({ data: stats }); // Wrapped in { data: ... }
|
||||
```
|
||||
|
||||
But component expects unwrapped array:
|
||||
```typescript
|
||||
// src/components/StatsGrid.tsx
|
||||
const data = await response.json();
|
||||
setStats(data); // Expects data to be array, but gets { data: [...] }
|
||||
```
|
||||
|
||||
Later:
|
||||
```typescript
|
||||
{stats.map((stat, index) => ( // stats is an object, not array!
|
||||
```
|
||||
|
||||
**Symptom:** TypeError: `stats.map is not a function`
|
||||
|
||||
**Fix - Option 1:** Unwrap in component:
|
||||
```typescript
|
||||
const data = await response.json();
|
||||
setStats(data.data); // Extract the array
|
||||
```
|
||||
|
||||
**Fix - Option 2:** Change API response:
|
||||
```typescript
|
||||
return NextResponse.json(stats); // Return array directly
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Error 12: Missing Optional Chaining
|
||||
|
||||
**File:** `src/components/UserProfile.tsx`
|
||||
|
||||
**Issue:**
|
||||
```typescript
|
||||
{user.profile.avatar} // profile could be undefined!
|
||||
```
|
||||
|
||||
The API might return a user without a `profile` object:
|
||||
```typescript
|
||||
const user: User = {
|
||||
id: '1',
|
||||
name: 'John',
|
||||
email: 'john@example.com',
|
||||
// profile is undefined!
|
||||
};
|
||||
```
|
||||
|
||||
**Symptom:** TypeError: `Cannot read property 'avatar' of undefined`
|
||||
|
||||
**Fix:** Use optional chaining:
|
||||
```typescript
|
||||
{user.profile?.avatar} // Safe access
|
||||
```
|
||||
|
||||
Or add a null check:
|
||||
```typescript
|
||||
{user.profile && user.profile.avatar}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CATEGORY 5: REACT PATTERN ERRORS (3 Errors)
|
||||
|
||||
### Error 13: Missing useEffect Cleanup
|
||||
|
||||
**File:** `src/app/dashboard/page.tsx`
|
||||
|
||||
**Issue:**
|
||||
```typescript
|
||||
useEffect(() => {
|
||||
window.addEventListener('resize', handleResize);
|
||||
// Missing cleanup!
|
||||
// Should have: return () => window.removeEventListener('resize', handleResize);
|
||||
}, []);
|
||||
```
|
||||
|
||||
**Symptom:** Memory leak; listeners accumulate when component remounts; "Can't perform a React state update on an unmounted component" warnings
|
||||
|
||||
**Fix:** Add cleanup function:
|
||||
```typescript
|
||||
useEffect(() => {
|
||||
function handleResize() {
|
||||
setIsLoading(window.innerWidth < 768);
|
||||
}
|
||||
|
||||
window.addEventListener('resize', handleResize);
|
||||
|
||||
// Add cleanup
|
||||
return () => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
};
|
||||
}, []);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Error 14: Incorrect Context Provider Wrapping
|
||||
|
||||
**File:** `src/app/layout.tsx`
|
||||
|
||||
**Issue:**
|
||||
```typescript
|
||||
<body>
|
||||
<Header /> {/* Header tries to use theme context but provider hasn't wrapped it yet! */}
|
||||
<ThemeProvider>
|
||||
<main>
|
||||
{children}
|
||||
</main>
|
||||
<Footer />
|
||||
</ThemeProvider>
|
||||
</body>
|
||||
```
|
||||
|
||||
The `Header` component is rendered BEFORE the `ThemeProvider`, so it can't access the theme context.
|
||||
|
||||
**Symptom:** Error in Header when trying to use `useTheme()`: "useTheme must be used within ThemeProvider"
|
||||
|
||||
**Fix:** Move provider to wrap everything:
|
||||
```typescript
|
||||
<body>
|
||||
<ThemeProvider>
|
||||
<Header />
|
||||
<main>
|
||||
{children}
|
||||
</main>
|
||||
<Footer />
|
||||
</ThemeProvider>
|
||||
</body>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Error 15: Prop Drilling Mistake - Wrong Prop Name
|
||||
|
||||
**File:** `src/app/blog/page.tsx` and `src/components/BlogCard.tsx`
|
||||
|
||||
**Issue:**
|
||||
|
||||
BlogCard expects `post`:
|
||||
```typescript
|
||||
// src/components/BlogCard.tsx
|
||||
export function BlogCard({ post }: { post: Post }) {
|
||||
return (
|
||||
<article>
|
||||
<h3>{post?.title || 'Untitled'}</h3>
|
||||
{/* ... */}
|
||||
</article>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
But blog page passes `blogPost`:
|
||||
```typescript
|
||||
// src/app/blog/page.tsx
|
||||
{posts.map((post) => (
|
||||
<BlogCard key={post.slug} blogPost={post} /> // WRONG prop name!
|
||||
))}
|
||||
```
|
||||
|
||||
**Symptom:** BlogCard displays "Untitled" and "Date unknown"; content is empty
|
||||
|
||||
**Fix:** Use correct prop name:
|
||||
```typescript
|
||||
{posts.map((post) => (
|
||||
<BlogCard key={post.slug} post={post} /> // Correct
|
||||
))}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CATEGORY 6: STYLING ERRORS (3 Errors)
|
||||
|
||||
### Error 16: Custom CSS Classes Instead of Tailwind
|
||||
|
||||
**File:** `src/app/globals.css`
|
||||
|
||||
**Issue:** The stylesheet defines custom classes:
|
||||
```css
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: white;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: #3b82f6;
|
||||
color: white;
|
||||
/* ... more styles ... */
|
||||
}
|
||||
```
|
||||
|
||||
In a Tailwind project, these should be Tailwind classes, not custom CSS.
|
||||
|
||||
**Symptom:** Custom classes work but don't align with Tailwind approach; styling is scattered between CSS and inline styles
|
||||
|
||||
**Fix:** Replace with Tailwind classes or @apply directives:
|
||||
```css
|
||||
@layer components {
|
||||
.container {
|
||||
@apply max-w-5xl mx-auto px-4;
|
||||
}
|
||||
|
||||
.card {
|
||||
@apply bg-white rounded-lg shadow p-6;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
@apply bg-blue-500 text-white px-6 py-3 rounded transition-colors hover:bg-blue-600;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Error 17-18: Inline Styles Instead of Tailwind Classes
|
||||
|
||||
**Files:** Multiple components use inline `style={{}}` instead of Tailwind:
|
||||
|
||||
- `src/components/Header.tsx` - All styling is inline
|
||||
- `src/components/Hero.tsx` - All styling is inline
|
||||
- `src/components/Features.tsx` - All styling is inline
|
||||
- `src/components/Testimonials.tsx` - All styling is inline
|
||||
- `src/components/StatsGrid.tsx` - All styling is inline
|
||||
- `src/components/BlogCard.tsx` - All styling is inline
|
||||
- `src/components/UserProfile.tsx` - All styling is inline
|
||||
- And more...
|
||||
|
||||
**Example Issue:**
|
||||
```typescript
|
||||
<header style={{
|
||||
backgroundColor: '#ffffff',
|
||||
borderBottom: '1px solid #e5e7eb',
|
||||
padding: '1rem 0'
|
||||
}}>
|
||||
{/* ... */}
|
||||
</header>
|
||||
```
|
||||
|
||||
Should be:
|
||||
```typescript
|
||||
<header className="bg-white border-b border-gray-200 py-4">
|
||||
{/* ... */}
|
||||
</header>
|
||||
```
|
||||
|
||||
**Symptom:** Project uses Tailwind but styling isn't using Tailwind; inconsistent; not maintainable
|
||||
|
||||
**Fix:** Convert all inline styles to Tailwind classes. Example conversions:
|
||||
|
||||
```
|
||||
backgroundColor: '#ffffff' → bg-white
|
||||
borderBottom: '1px solid #e5e7eb' → border-b border-gray-200
|
||||
padding: '1rem 0' → py-4
|
||||
fontSize: '1.5rem' → text-2xl
|
||||
fontWeight: 'bold' → font-bold
|
||||
display: 'flex' → flex
|
||||
gap: '1rem' → gap-4
|
||||
justifyContent: 'center' → justify-center
|
||||
alignItems: 'center' → items-center
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Summary Table
|
||||
|
||||
| # | Category | Error | File | Severity |
|
||||
|---|----------|-------|------|----------|
|
||||
| 1 | Blocking | Missing `date-fns` | `lib/utils.ts` | CRITICAL |
|
||||
| 2 | Blocking | Wrong import `next/navigations` | `components/Header.tsx` | CRITICAL |
|
||||
| 3 | Blocking | Circular dependency | `lib/types.ts`, `lib/utils.ts` | CRITICAL |
|
||||
| 4 | Next.js | Missing "use client" | `components/ThemeToggle.tsx` | CRITICAL |
|
||||
| 5 | Next.js | Hooks in server component | `app/dashboard/page.tsx` | CRITICAL |
|
||||
| 6 | Next.js | Wrong matcher pattern | `middleware.ts` | HIGH |
|
||||
| 7 | Next.js | Metadata in client component | `app/blog/[slug]/page.tsx` | CRITICAL |
|
||||
| 8 | Logic | Wrong filter condition | `data/posts.ts` | MEDIUM |
|
||||
| 9 | Logic | Stale closure | `components/Testimonials.tsx` | MEDIUM |
|
||||
| 10 | Logic | Index as key | `components/Features.tsx` | MEDIUM |
|
||||
| 11 | TypeScript | API response type mismatch | `api/stats/route.ts`, `components/StatsGrid.tsx` | HIGH |
|
||||
| 12 | TypeScript | Missing optional chaining | `components/UserProfile.tsx` | MEDIUM |
|
||||
| 13 | React | Missing useEffect cleanup | `app/dashboard/page.tsx` | HIGH |
|
||||
| 14 | React | Wrong provider wrapping | `app/layout.tsx` | CRITICAL |
|
||||
| 15 | React | Wrong prop name | `app/blog/page.tsx`, `components/BlogCard.tsx` | MEDIUM |
|
||||
| 16 | Styling | Custom CSS classes | `app/globals.css` | LOW |
|
||||
| 17-18 | Styling | Inline styles (8+ components) | Multiple components | LOW |
|
||||
|
||||
---
|
||||
|
||||
## Debugging Strategy
|
||||
|
||||
1. **Start with blocking errors** (1-3) - These prevent the app from running at all
|
||||
2. **Fix Next.js errors** (4-7) - These cause build-time failures
|
||||
3. **Address logic errors** (8-10) - These cause runtime misbehavior
|
||||
4. **Resolve TypeScript errors** (11-12) - These break specific features
|
||||
5. **Fix React patterns** (13-15) - These cause memory leaks and state issues
|
||||
6. **Clean up styling** (16-18) - These improve code quality and maintainability
|
||||
|
||||
---
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
After fixing all errors:
|
||||
|
||||
- [ ] App builds without errors: `npm run build`
|
||||
- [ ] Dev server runs: `npm run dev`
|
||||
- [ ] Homepage loads with Hero, Features, Testimonials
|
||||
- [ ] All navigation links work
|
||||
- [ ] Blog page shows published posts (2 posts, not drafts)
|
||||
- [ ] Blog post pages load correctly
|
||||
- [ ] Dashboard page loads with stats and user profile
|
||||
- [ ] Theme toggle works (if fixed)
|
||||
- [ ] Carousel auto-advances smoothly
|
||||
- [ ] No console errors
|
||||
- [ ] No memory leaks in browser dev tools
|
||||
|
||||
@@ -1,269 +0,0 @@
|
||||
%PDF-1.4
|
||||
%<25><><EFBFBD><EFBFBD> ReportLab Generated PDF document (opensource)
|
||||
1 0 obj
|
||||
<<
|
||||
/F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 5 0 R /F5 6 0 R /F6 11 0 R
|
||||
>>
|
||||
endobj
|
||||
2 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
3 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
4 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica-Oblique /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
5 0 obj
|
||||
<<
|
||||
/BaseFont /ZapfDingbats /Name /F4 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F5 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<<
|
||||
/Contents 21 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
8 0 obj
|
||||
<<
|
||||
/Contents 22 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
9 0 obj
|
||||
<<
|
||||
/Contents 23 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
10 0 obj
|
||||
<<
|
||||
/Contents 24 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
11 0 obj
|
||||
<<
|
||||
/BaseFont /Symbol /Name /F6 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
12 0 obj
|
||||
<<
|
||||
/Contents 25 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
13 0 obj
|
||||
<<
|
||||
/Contents 26 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
14 0 obj
|
||||
<<
|
||||
/Contents 27 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
15 0 obj
|
||||
<<
|
||||
/Contents 28 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
16 0 obj
|
||||
<<
|
||||
/Contents 29 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
17 0 obj
|
||||
<<
|
||||
/Contents 30 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
18 0 obj
|
||||
<<
|
||||
/PageMode /UseNone /Pages 20 0 R /Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
19 0 obj
|
||||
<<
|
||||
/Author (\(anonymous\)) /CreationDate (D:20260225061542+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260225061542+00'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
20 0 obj
|
||||
<<
|
||||
/Count 10 /Kids [ 7 0 R 8 0 R 9 0 R 10 0 R 12 0 R 13 0 R 14 0 R 15 0 R 16 0 R 17 0 R ] /Type /Pages
|
||||
>>
|
||||
endobj
|
||||
21 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 897
|
||||
>>
|
||||
stream
|
||||
Gau1,9iKe#&;KZQ'mgA57-NA<[fW81_h8`ZT"):j'#Go;YS1F>oj,\Z,p=.M3\\k#YuVt85.`="T_Pb<Ada-Q"HLbF0Fl2-Qm<<-9,Jr%6c>FUg(9r<LR8HYPS#kaX[F)P@g.PW==ONnE[u-pEZ3o"XPJSE8/A]=#B'GT\.EPn3>%E'MZ]+soIaDQiY]trn+@Ain'_$ej\lDn]pn]CPm<E+6ZNG`VF6e`b!fKoD\$/KI:bKr3GoV6W;d)dmsWR6reD#4=o0=n2j47-'!*8+g=?L@?rF(-/r.JM5/nE<-F7?$(N'DSl`r!D:\pQ%pWMZ](a6;R]?;gd+H1@*mDLKX*hAtT:l1so%:WjAE>sM30cZ0Re(DJ/f8.=CP_\prf%tIA!m*ta\:E#DaW]YP38+@@2&;qb)R@0mZA/@tJPNk/L4+lH1EOEj4"K+!M=8q-8eDTJZXU20]4Vtlk7tP2?s+9>/mAKg;jZLJbdhc\)R?RA!j<V$Qm+AaFrr:Z'QQHo4K\RUhguJF,/Pma1-*9A=cG<^i5dGld)>:(TNO)*;n,E5N.;tekkaTAi&$"cd9npNG'G<H9SAR<T3'h#f)?6.@,4La:;PEdgdWiN4Z\oKhn9rtp95U.'i4Y<8B3E.Q0=9W'`6R!Q1c_8U]!9U8+JE>L=dh*>uVblm8WN4I'3%4\X.u;<\1MDj]cl;?^cf.8AbL:8n/Sj?T\sb#!\)r036V4("i@>%3j@h_`sg[<eUkZ;6$qIBQhO,<d^F-&/QJFS,,?IX*s*F'Q*60PZ7I!JZ2VN&6ZKtE796HS8t1<fKF,oBhmo]1Mopdp0<s/je+#FYUs.L2s65IPc6W1XlH.1qGN&P4B,a6p$3Q%'N8(EG==6i4%JOWQD_OT#_hIQ\)dHm~>endstream
|
||||
endobj
|
||||
22 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1081
|
||||
>>
|
||||
stream
|
||||
GauI49lo#Z&;KZOMTu\.0[Y8],l&4r,4PllfiW7]JW#%JN"H[?8Toep^HEg7li\,/]2]5=P%m0arOb;lMF0XYm]WrS^h!`=7i]$hC]Rcq"kaa@D"(rMG:Rg[U_X"U.9W`?8D=>u*gmNP_)MsYRqG<eK.$rX+M!G]C%mP$(2cb6OG4sA.!dIDTh9"M[nd),c\'A1%CKf)816.1=X8\(Mf<r*?st<o3A;$L$&&od]bGY9&U4ejUS-"_RP^<U9Q6[K>Joq@KPaf!E0FmJH4+D'D&_+GXC*5?"Aah"X:[&.o*VAW&`s@kF$$9;gDG<^#2(53kO'oleY'j5=R3HG;OYD2p1c>tCCu7g,pF(EE9L%8_YQ]]-t+k<K%S2M32`G;^S_mDQD`=c50?[)lutMlm^!F2JR?4Sq!Q=loNQWgQ,;bQHU_J'Y5b6^A14-c]2^XI42Ir\A5H\5-7]T;o03G1TC%j)LXYINH;Qt(0YG7SJ_"+"A_GYCT\DSI>q$]@,#ebN5cbkr1q,&h9.Wa?97uq\I?%kbA&U:(qGu117,Q<4cW[uDpA9tuND]L^I\VN-O\m*Ji,26;R&V:;%9@POAj7pk-/M?[>NH%*F)C(l'KELk=gbKZF6fbr%Bk@DXCRAd?*VlR1B(YM7$%(mG"(4TPr%`#D-P/k?1rr`JL0<m<th$?g);LSg7Ok'c67rUgQl$j[GG_6b/r=N5!a@6P-6fsrrslu^lQL\\rqsAZ@LUa,#"-aj@4<gB^,&D>Qr<9X5Yp@k&kN(qkC-'"M_trG-l6t.\)-*(gIrYF9CP6pY#5;rk0"i"]Z$iM6iQ>W@eQ>/pOr6KVDBV7H1ErhuPj!;I2fS>Y:,Q-#kK3]*BKBGuG6#>>?I>1X0V%A,jd$!uFW4$Nlu61-ZrH"/5aKVnXXL?TXLeQE;6`HflF+0qdC9K,[kp&oVP,/#__7*n#/cHiM+:dh:871%tI^m8?T)f\k\s9G%@E/5n#*_W1^iqVZ(mCI,o@q@n\@O2on']RVN&Fp37uk%0Aa[JaW\heabTpZ\*9od.AdHangVFb/$NF^=]n?ZWNe*5mal@IQ4m_t%U~>endstream
|
||||
endobj
|
||||
23 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 984
|
||||
>>
|
||||
stream
|
||||
GauI4a\q.Q&;KY!MWP\Q)Bm5.'QY/u$-Q.r+eGYnjPi->UF`jYSNu`;dp<Zq:iIV]9%i$(qWn.2'#<`DeUP(33:Yt300i(tV]Z[Pi*SdrDr%lj1K&FaUSS)<2![+ne$R]p*IdAmVKD3<WhZD1JOsR?.tDon;m]%1[GkqiX*&+i?p*Qgc9%+29FkgantBJl>`p;2ihE!5\B)D;R+B`\RI)Z$4nOeR5T[b7pWmK=6Q"\P\ek='hQJ!mYQ+C2!K>_>nmXK&8,N2AcbManQeVnb4XNQeHj&aRBC!<Nn]G'+/[btO\dYX^0!?ZQLA!&[&SeU$0SUr:M]kkNZr;m(==6ZE"+2ZP/;N7BL"gWM`o%J<R:$&*N&!IfC$&]Q0Z7de):2H/@50Am9^Q`'9Tthp3BU\-a-aQWh$Kl&;i5oD!_]romfo't3kKnQqs&;*i[U=>H%A/qJq=SK#'pCeDC?XEEON1EJuFlY%a-!9?to36OG8a7&]A6ajp2Wi@9D/>_Dk\.*!BUk=.]C,1A@1f%3c_rcWI4fLIG%t+hdNF;aRE#D-df4Fl$0l$V^3`*DF%V3[K(*a^fr5!?L2SM5N6UJg.kFVGJ%$/J?O.P^'n\s2[fHk7Ej?b9A7.Do"3t8qi=?Oqicj<<e@h&ek@C6YQm,+28TqK%$BCGnASP_.%t*[!SG93MdFd.mH(JdT&t>gT4S[k@nfp^cKUMNWH$#T.0@t/h($\RC_]>jXQ<a\34V!G^.toKbDThdO@9Ia[(iqL:6WNFh?G(j`s"5duq39OujVgk:nDDNDI5+q`a,L)17np_%i+M-FiGlP9e?q.:qD8J"=>IF3`^F5!nbF)S_\VW?eMq-`(tSJn"24?8!U;g6a5Q%Ad,paLCmR;hFR7q,#4QQdXo715Im[e$:Eu@[nq+<qk#WOZ>pR8B.^/%#ECE7nAuoE0V'g3?=")I]^,rp"p-::En"MC3>HgGZ.8^H%?!us40R0$i~>endstream
|
||||
endobj
|
||||
24 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1117
|
||||
>>
|
||||
stream
|
||||
GauHIh/hR6&:`lHfR"j2)qC,5YIl^qP+-'HCZG,F(L\((0GZ%XiL7NqCE$q>#t&@Z.El13[?C:YTj8-/I<kQkC]LVZph@Tr$cj."-'OGJ_`/`c)t88fS?aga!b)`t/n3Nl?s+6M8I@"CA!'1"V_)U39gqUH==-=u*M:+&%Ku,&Fa%L5a".lA]iK0>KH^PWE.'`S0eaY:FMdQ>7ik82\e;ur5`-U4Uf`p;d2&'e-s-D0407`UaB.iU(rF3J*YN]eMqWGAXC7+5$XSBe^_9mTJ<AN$9oZQ9NETij\R!p^=**J']5slOF4stW\A<J#[JJCd/AH":r:L.1UEh%"6FK"*ZnA\`VkiEWmeISAOV*A71s%gWh@Q)c/51X<D2DM&d\6(&^muU>45;P`5@cG0qqXZtn1"D5.tguCs*4G&Bll:galDjcp]780&=d[iDL-:,U5Ta$VGVXPU<JY`hZcBUg=OK.mS%sVO-4X>%r^rkn<%N4<Jf&oHTS+QcrspN(?\YRXV0R!8!mMW[/WhB.185ECYpVM7^R71",%2Cj=*`R1cYjd#`e3mK+KD,]J=/]lCC/g=8km%9'WmQAsFg])cQbG"(>u8GGG[V?-j\<[d9Co2qqqFl(ZFj?8*3JYuh+)06H<teV1!cg2$V.QA.)Vk@#DahS6mp*H?CI?>iN><<\)^VK#^hgKImLSfEPGGEcU,P&;3F9+81(J<TKVK6H'>G$\/S7:f_6nUPYi[:WG_DEufZ(*,PE/?nX,r=Dm(q`j_M:e/G,Q)E%N<-h!XWPk3A1c\[iF8QNJEn%/hA8nYPHVoWkeec?Y(SrOB"GURV)C-BH9)E(SmQ=1*$5QQ53G!Oi"%LQ8bnuNc%hn7$m3h/=5UL_DTqq-Z9L^cF`'54D;'IEZg0PJ(FF;I(r@^XVM+Nfpm1ha$aUrVb7](?`8=L):>YHf$U(?I3`id.Y)1u;gC(36n"2i!#FI0Jj?t61`e/EbEZGLK;W+,SB=mlYk1R:o0jZVRLJ6>rYE,=-"Eh]#$OSc!q"Vfm5$lFo9<@&$/r2=DopLGH4ju58p$SttdWku>`_*'Y[!cY'k%aeMKiUMs^E+_db`R:-R%t7NTXqf#Z0OXAdj-'uI~>endstream
|
||||
endobj
|
||||
25 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1037
|
||||
>>
|
||||
stream
|
||||
Gau`R;/b/B&:WeDh"EGLC@boT8P%`@8(C43bM$d\,[O_0_'Q?Ba.]9CIMY@c]7FXlBi?8_5!*uGh=l>K6@]mFTApRB;[+=>-r:-$'IY=KZ?$jnSKAl`hAQ&Y(c-p(4i2P/L;u?"'=/qc_H=Z"$7'13a(O&;U]%GGNnZDu8P6iF#^Tl)9FpZem=j;B?A9>GhO*rdH#`d+0g77fldJuCh<V.,"F^L,pYk',q!)[__)pikcf!mTCGr\Q;3sT9RX%%W3.U?2ZGZBe?a`7W"%#"B=t!V8S8I7M3e<?pC8RKoq3l]s!Y<*Lk[r"16E06J\FE8DY`REQHS=MZK5ItoV1c)g29*_D,.Ek(.H*"BGEj$ld3cT@9GRVd[h\c0KKh+pqeH,G""0sc5UhY2ddUE9IcjU(*DD,"i1t41:`:S\]X+?4U]kg\/'%'@PX8K>+CJ,K7SE.&G2.rEbdH1Ii-0m_@S)*7U)J/E#;?meE,YGn-Xu=)6I/]r#70i38nH8,Ph&39Iir^>`-srpmr;n^<]qm+/dle`LIP)#<,"?q[q@MrmUbLEd@u0]9IR#bh@dosV[(6]c@^3T4i1MtJn,VrItEZ?i+gV'c=#;NZGG)1UKYPOW\m2P-B.Pe3)Qdgn^jbJO+R:+$&:(_2,"]V=-giYEJ@q/"-0R.!_7RcjNjX7Il8H],iB!`<ASfJ'AlC<X[U!f]AXuYRp$<!;ktHcN6GAAQ&CsO"nGB&<3A#tV-;WPdXbHIJZ3%J+b$"k`1hKHmO)l,h^c]nqg7j7KZlA5QH`qhLXn$+"C\dZ<Njc,U3L-L3,1F<U>=j8)nStAms1qg1^`:,D]9j\%A*@Zi*O)^]o3-pL&o[[pR5</S$+u&TnMS1&q#_"L5+O<)/(0c!e'E*NP%MinFeBt`>*FaG!A*X`$>UC\JN'X?Uj=]$T?j-3)*m>$ad/aLf,?mJ.)"Y5/ceRk9Q_qcL]n5N`Cd'3(h[I*7*?Dl!0s`>W;%#kZ$1@^.LNYMp$$OE/HhaO(ZHHX2UdRPnjoo!<Sg!b6LM(~>endstream
|
||||
endobj
|
||||
26 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1231
|
||||
>>
|
||||
stream
|
||||
GauHJ;/b2I&:W67\38A6:kkboMTT/`V+DFICM0?V!5HT5X!j7S<0EI=hsVu8ZL$4d"q6D$$RCeR]C51b-jCA-f).--JBJeT5;HUdiig-#&J.ar.e^T'XL".Kpl]][>S>%&md`m_8K''$8kC'.rOYaC8La)fPS>8MUAk,C[E%7F1QBjK8eUY"NtmV,551c#E-^^\$&$\+4nNZ7\IO`[+n@6NS6\X@F&>?8$SF'Y<c$HLN&cIanWf.II'fpm6\)7iC,N1NS\pEX&=+6+9)G,1FU;'=,W0*:o&M0ePIgSk7?Wo);C50sQqZ-$@5>B^'"H++^HlW-&r\V30@)OPD7S022$(Xn0(.&4TFJa<oB!ht]5LtC5mrmo??DQEU`s4)J/#'cC'WNJ,(<(^Eo;C07AoQVj2kTd%LYkX?:6+*FsEfXC&Hp'a:"BTInstNY@0?#20idj9^A=]Y+Pl!mPl63GTaW+h#g.Y-X$G3RH<er#WtG.`)hLN#`jf<p$Wr=<nf`>hsIF\NP5SM)"+YT8RAr2,mMPP-.?Fjl08>JF,b<\ZE2b2$`e&[g?Phn-X3kENK,G#;AC73T$i(9J+WY(pk)=[ds9L-C=qaUmHug?F3L%'WX@nb)7t7#WbPbRGWLOISlCuX#^k%]F(/$L>5N6$ogA`Y,SRo4EKcGE__dIP=?cluH9TC$<o"%?XhhU")YmWK-:@dp&8ZO'+YBjQ6rG&*+]HHB8U&*Mprj7G!Sq,8MIXS-J5]n"=X!nZ;>s%)$pp!:8Gn!-kao50rsOB?TT@]N?EUSPcuK#!RFTCVEF%^>GAn&P@X3,U41Tl6kBbOK]<KAPN>N);%A[D+S9KV^CboseC9Bk[*K^[EE"\iclkTqH2V)98,.F^9XZ.N%dbe$a4gs()O?+%^%SUh\b_3+[Qp`*(NUB?h/Ri4M(4484WV=5<j(Yk4mE;rQ#D`h'Ld24pHK27^SoXcSX*%GRFpo8dlQ27?kW2KIoONq>F`i/.9C$K>,9_.JDlc\->@Ni#>plT&Df?caoBdIV&,^qLOJV>g9%\Q9FR2FgZAt+#"i[>a36G[`EOBJHgPOd?rka+l[%>;:(sM#R]n"'D/E!I4i6#t:F8l#%GL#C6l)GIU`M3;?:B\T%:ch(3F?jhtm3o@&S`gAH;6="%-cedW!e/bm<=7akG<;6mUDus/:Is60Ur7Vm($,6V^YH\c9m*jgYdXG+qNReD8O*cC!8]r3_gaQ~>endstream
|
||||
endobj
|
||||
27 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 630
|
||||
>>
|
||||
stream
|
||||
Gat$u9lldX&A@Zcp6]BfMBmj=E_P3*mA+Sse!tfZN_ILo8c_`bo=JC]0m+IK(c/Mqp?fan]4+%q@GQ95!*mN_Ia*C_Lf_@p&J3j:V`=Gl0OKZ.VEu>UN""*r%[#AZm8KiIfiCrZOd*e'_r*m$<>JVJ#E/Es@[%Ra!AT`e/[k>,mOR1/WVF(d7cM[QTmTp3[eDH&c8mN@h5-[Sgj=t4hHU@6K"->pV(5kWC!3A;^U?_?Y&$h$qX5lOcOc^C=BldhU_q0/kL0<o&sSjYO)<]`Ke'JT5=WOLphCnWFn(nmA>UjJ->Db7.XO9E_QsbG#W@sXb[#O[<6$D3nmM]lnVP-/g/`E_>@k?.6H&KQE9b3uG-8+#0eRUmgE[Z/Fh<H:nFmn6/JLW$$,3h0331l>_N,Xhs)c^^U%!Dr_]1JMkdJ8<CiR#oclq52]YZ?a'XQoZY)WL@H2tEp"CT^]\;MR3UHs?1]bfimgc3i5_@Z>]GMbR<HVJ5f8ra^D@7519gM?2jhcS>Z/1'#R/.i<He3J[G3MMmKI`I50I+'hbKX+/E"1'k<(\#iO>,Q?4PiTA,;[\MIq>/'20Z*otSAKl!"lI$YI"n%^D7t=;0&IrCOu+[&:npC5i#d<_=A]~>endstream
|
||||
endobj
|
||||
28 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 955
|
||||
>>
|
||||
stream
|
||||
Gaua=92jS!&:j6F'g"Q4JIY#0j[ZgH80QFn-uh9/i]+deZ"5.A4SnBU2?lJpN8`]<4;0fWQ1XIHG-q`,5-4Si'7aR7%Xp*>*;ga`JdCj90^q/J*EHr:*jH^1na-qIGoW`)nAF4f%>8e(fF1<3pB7X-U5lCRfoB"R(q;_<\WhDJ,i%bFU?.#Be\3#IXS-dm=7;(<Q]5uJLXia0"M,9HkRuZ<3$%kB^GnHuf+&50UVZW]C,"KJrtbOGEfFG\kT*9_?uAQNF^4Ffn[ioN:8-C5<J6X@BZWrKa$_<g[HLbiX"0DnbutO<.Nk,)J\Y$WdG:ci@@AJ:g/$Y]NI!^?\X]cG#i`@a.#gem%SB+&b+sSW@-/"QE)c*nIX>`"<jOKUDe?[:DmOAGpIf+0X*i=9@XCl)/=1'WPg8i2OQ:Xa<,o@86*0\k^-`q[.<W?q$iDfEH+5Qnp0R!^R@JSV1!2^A4G%pu(%hO&`l[06pF5a\#5t0hiP]ZU"[OTBHIdk^@!VZm]VRk6i;n[9S1^/V83KHJUoQgsR!,Ur/u2Vq@glpY?n>Nh9feT$"hDl$cX`tlP[(Ar$=o,AB'gs:\arUE)Q/_7PJ,r%8D^9.A_i0aHX>Hor_k-kTi"s4E-+*fj5aPR4EkMoS6%HOZ!clam:S^^8>Ge1S+k@T,RW\YR%j7IlEBb&9qX_=5cs"Xf9gU5q'Zr.MBA)^KH7/e4?HVJ,s`)p?.S-^.$#mEEie(0o&;*aH&MANYP%83=TW33@CB)(*$1nY(@\4q8lK*fc&d,7\QP5[]S9'8/1+d:0/+IY/P9_5T[e?dT"['UOi6:cCb?HIDmrIfZh;=J"0$1CHdrQ$HCY_cH4Jfh6jT.54WlXO!S_"'G^Y&I6CEg]7=!^M0M'b<S5c%gs.p[Ql85K/`%u3BYtRls"+g!]oaoEsW,-\+1k$3H#*I=7G\`u!q$S^fd.d~>endstream
|
||||
endobj
|
||||
29 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1316
|
||||
>>
|
||||
stream
|
||||
Gau`RgN)"=&:N^lHMt)0,aCY6NGcD=CqtdmX:qAqf%,/J/AqMih)pjjEk[!,G@<j<iFPXcdS+#nl'^f(O[6iScMnn,i6$ZN[1"eoCBZI<%'1>*XkluP/i>M=-lSqTR3jYeAtW;qlQJ9R#ZETDP7qPA<*+WIW\[WZ@T&C5L042%ge?8*Ceb2j,`43G"pb^>pZOG\:bCj!O\sCs,=]c_k:9s4VobdCjhpn)4So20gl80i([o/nK(V;`3(-b(.?S1u*XbEe=Y5-g8\)4d<,#5:EmT4$Umtr?n9i.jko/PLfEkosHiR7C$K,r:9g=VFiGN)GJTDDNp_"bbJ5Vn0\FA=ip@ajqjMnQ*\XfQO#KLn2OIST^_M-$Y*XlH%`A8;a%/hR_:`+g,Y'C"_NdmNPgr9'!&?3;%5rV$]30iCJ'i+&I!nS[V_3,&Kb5cDeA9`3YSOalKM>/=*,U1R1RXFI4`D#N,<acPp*f'3m#i&f.&)\@%?B3[Qf(O5.W2c,G='hP?PLp6EpY9qTg*:FDLB7G+*JHsYNFEg-gq^lrkCm>d0nA5;4$14[0j^tAEbUgZCa&/3\=8FtEg"p"%3/fsS##0[XtXuPF8C,BUDSU4oD0oa6LK4-4$.s7m^E!$1?mj>)5\UtU`=:=,YJ_68d95mh8)jrgGQ.^O"tPWn5&,u]417_J\P$2_%XQ+U>#+tiiJ??64G.'L4632;.^AF1B,%?H9;-'lL+4l"S9ak]f#_"brb2?`>4Pb]S[!lMQA=-!CO!N:L,]sMV:JkOm9+Pb&re[UEdO5qLDJ?6VLcqH3UG/0!Ih&PRa\]\^]jsGuRqE7n*;$O7L,KhJ@@TZK^,G`k$lYODXQ9K*BarPLe<no>E<hdo`Aokp10!cG4UH[Bf$>VQ&]AL5GC`gd3*;rpmsD#B4B5%6U]m0OD=\Qti;[NV?T?IFdAj[$btg.tTR139FL()t3BX]1QgsEn#Y>g4)l2`;Sm6<Mk:0L</E[EDg7?3`&G<CH#A4n(;6V7QEt+_M"ukqB\DA"/*$+_Y"h:)&@8*5oblWfK*i8?#,Yih-gP?&V%7+ctg+_XH%\FhmQ#`VG"F\=;FoSTU6L??GQLKMSIbC_f'Q?)gX1kMkj]0'Jm.[oJ;Dk<]-E_PdU`*/!7AT@Q$,H0j4Vu<<B62/HLk]!EOl>!(SpE5'dB-%Ad1ON']\+_YKWbAWE4)MFr"%+ABe/1k;fNI8pS$jB"JX0-<X?@RQAZ^"B\0O$OXKEUC`Jl$5BnF*K[:V\.c7-am,@]RpG?nTZqkEs`Sn=iLqX._T<^MiH=u)pHl^6gm78U\R.~>endstream
|
||||
endobj
|
||||
30 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 410
|
||||
>>
|
||||
stream
|
||||
Gasaia\K`-'YNTZk1E,4[c8Vk8&A0(M?:1Fob(FeD3Y:Q<r>.AZ`"uVkUDhS]GY9m(oSJ;hK9=`BM@h3(l-t"#pQ&*\C9<4a',>D=laWGO\eFMd^M8]Y,=n*U1Qt"@7V)6$s.VO%(;r2:oO8JV0"o"o>+WI(@>pk#bZ5Ii_u,%Qb34i1nJ--38\i4&GcAiqPE4M&J9mqY0/ZH%-"QPQC5:Fe;7f24*X/NL^"4)^/At_V*Z(l]KY!>QO?0C2j#jH/^Oa'nUB`KoI!C\fJ<HcF6PWLCK\EZk8-'o?-9QDM/<&5Jm#8i7'mO-C&um$gfMUS+*%iu&B]U'.;!IXn?6hIhTmY1?'8cr8.AUPjnZenQmU?q28kCD#Z$Af7nh+U*7qg.bSot28bYY_c!5>tmi1FNN*-~>endstream
|
||||
endobj
|
||||
xref
|
||||
0 31
|
||||
0000000000 65535 f
|
||||
0000000061 00000 n
|
||||
0000000143 00000 n
|
||||
0000000250 00000 n
|
||||
0000000362 00000 n
|
||||
0000000477 00000 n
|
||||
0000000560 00000 n
|
||||
0000000665 00000 n
|
||||
0000000870 00000 n
|
||||
0000001075 00000 n
|
||||
0000001280 00000 n
|
||||
0000001486 00000 n
|
||||
0000001564 00000 n
|
||||
0000001770 00000 n
|
||||
0000001976 00000 n
|
||||
0000002182 00000 n
|
||||
0000002388 00000 n
|
||||
0000002594 00000 n
|
||||
0000002800 00000 n
|
||||
0000002870 00000 n
|
||||
0000003151 00000 n
|
||||
0000003273 00000 n
|
||||
0000004261 00000 n
|
||||
0000005434 00000 n
|
||||
0000006509 00000 n
|
||||
0000007718 00000 n
|
||||
0000008847 00000 n
|
||||
0000010170 00000 n
|
||||
0000010891 00000 n
|
||||
0000011937 00000 n
|
||||
0000013345 00000 n
|
||||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<7a0979c2f1194bbadc3bbce6ebad8598><7a0979c2f1194bbadc3bbce6ebad8598>]
|
||||
% ReportLab generated PDF document -- digest (opensource)
|
||||
|
||||
/Info 19 0 R
|
||||
/Root 18 0 R
|
||||
/Size 31
|
||||
>>
|
||||
startxref
|
||||
13846
|
||||
%%EOF
|
||||
232
Les03-Cursor-Basics/Les03-Docenttekst-Autocue.md
Normal file
232
Les03-Cursor-Basics/Les03-Docenttekst-Autocue.md
Normal file
@@ -0,0 +1,232 @@
|
||||
# Les 3 — Docenttekst (Autocue)
|
||||
|
||||
**Fysieke les — letterlijk voorleesbaar. Slide-nummers tussen `[SLIDE N]`.**
|
||||
|
||||
> **Structuur:** ±1,5 uur theorie/demo → kwartier pauze → ±1,25 uur hands-on
|
||||
>
|
||||
> **Voorbereiding — accounts en tools:**
|
||||
> - Cursor zelf geïnstalleerd en met Pro Student account ingelogd
|
||||
> - Twee test-projecten klaar (één leeg, één met Hero al gebouwd als backup)
|
||||
> - Browser tabs: cursor.com/students, cursor.com/download, Next.js docs
|
||||
> - Terminal open in `~/web` voor de live demo
|
||||
>
|
||||
> **Voorbereiding — content:**
|
||||
> - `.cursorrules` snippet copy-paste klaar
|
||||
> - Hero-prompt copy-paste klaar
|
||||
> - Cmd+K tweak-prompt copy-paste klaar
|
||||
>
|
||||
> **Voorbereiding — backup:**
|
||||
> - Cursor Pro Student verificatie kan haperen — heb een tweede gedragslijn klaar als studenten niet kunnen activeren
|
||||
> - Screenshots van Hero-resultaat als live demo niet werkt
|
||||
>
|
||||
> **Voor uitgebreide handleiding zie `Les03-Docenttekst.md` (normale versie).**
|
||||
|
||||
---
|
||||
|
||||
## BLOK 1 — Welkom + Wat is Cursor
|
||||
|
||||
`[SLIDE 1]`
|
||||
|
||||
Welkom bij Les 3. Vandaag installeren we Cursor — de AI-powered editor die we vanaf nu de hele opleiding gaan gebruiken. Aan het eind van vandaag heeft iedereen Cursor draaien, het Student Plan actief, en jullie eigen Next.js project waarin je drie kleine componenten hebt gebouwd.
|
||||
|
||||
`[SLIDE 2]`
|
||||
|
||||
Drie dingen die je vandaag leert: Cursor installeren plus activeren met het Student Plan. De drie hoofdsneltoetsen — Tab, Cmd+K, Cmd+L. En een werkend Next.js-project waarin je een Hero-component hebt gebouwd.
|
||||
|
||||
De werkwijze: ik demonstreer eerst. Jullie kijken mee. Na de pauze gaan jullie zelf bouwen in je eigen project, en ik loop rond om vragen te beantwoorden.
|
||||
|
||||
`[SLIDE 3]`
|
||||
|
||||
Wat is Cursor eigenlijk? Het is een fork van Visual Studio Code. Dat betekent: alles wat je in VS Code kent — file explorer, terminal, debugger, extensies — werkt hier ook. Het belangrijke verschil: AI zit ingebouwd, niet als plug-in.
|
||||
|
||||
Dat is een groot verschil met bijvoorbeeld GitHub Copilot, waarbij je een extensie installeert. In Cursor is de AI overal: in de file-completion, in inline edits, in de chat, in code-review. En je kunt kiezen welk model je gebruikt — Claude, GPT, Gemini, of zelfs een lokaal model.
|
||||
|
||||
Waarom relevant voor jullie? Cursor is industry-standard aan het worden. Vacatures noemen het. En het is gratis Pro voor studenten via NOVI e-mail. Dat is de eerste reden waarom we hiermee starten.
|
||||
|
||||
## BLOK 2 — Student Plan + Installatie
|
||||
|
||||
`[SLIDE 4]`
|
||||
|
||||
Het Student Plan. Wat krijg je: 500 fast requests per maand. De gratis tier krijgt er 50, dus dat is tien keer zoveel. Plus toegang tot premium modellen — Claude Opus, GPT-5, Gemini Pro. En tab-completion is altijd gratis, dus die telt niet mee.
|
||||
|
||||
Activeren: ga naar cursor.com slash students. Log in met je NOVI e-mailadres. Cursor stuurt je naar SheerID — dat is een externe verificatieservice — die bevestigt binnen één tot twee minuten dat je echt een NOVI-student bent. Daarna is je account upgraded.
|
||||
|
||||
*(Ik laat de pagina cursor.com/students zien.)*
|
||||
|
||||
`[SLIDE 5]`
|
||||
|
||||
Installeren. Vier stappen. Download van cursor.com — dat herkent je OS automatisch. Installeer als gewone app — sleep naar Applications of next-next-finish op Windows. Open Cursor, kies "Sign in" bovenaan rechts. En optioneel: importeer je VS Code-instellingen. Cursor vraagt dit bij de eerste start. Klik "ja" — dan blijven al je keybindings, je extensies, en je theme behouden.
|
||||
|
||||
`[SLIDE 6]`
|
||||
|
||||
Eerste login en check of het Student Plan actief is. Settings — Cmd-comma. Tab "General". Daar staat "Account". Status moet zijn: "Pro Student".
|
||||
|
||||
*(Ik laat dit zien in Cursor.)*
|
||||
|
||||
Als het "Free" zegt — geen paniek. Log opnieuw in via cursor.com slash students. Soms moet je Cursor één keer herstarten zodat de upgrade in de IDE wordt doorgegeven. Als het na drie pogingen nog niet werkt: er is een handmatige route via support, maar die hebben we vandaag niet nodig.
|
||||
|
||||
## BLOK 3 — Skills/Docs + Eerste project
|
||||
|
||||
`[SLIDE 7]`
|
||||
|
||||
Skills en Docs. Dit is een feature die Cursor onderscheidt van andere AI-editors. Je kunt Cursor framework-documentatie laten indexeren. Vervolgens kun je in chat zeggen "at-docs Next.js" en de AI weet exact wat de huidige Next.js docs zeggen — niet wat hij heeft geleerd in zijn training.
|
||||
|
||||
Setup: Settings, Features, Docs. Klik plus add new doc. Voeg toe: Next dot js, React, en Tailwind CSS. Cursor indexeert ze in één tot twee minuten.
|
||||
|
||||
Vanaf nu kun je dingen vragen als: "at-docs Tailwind hoe centreer ik een div?" en je krijgt het antwoord uit de officiële docs.
|
||||
|
||||
*(Ik open Settings en demonstreer Docs.)*
|
||||
|
||||
`[SLIDE 8]`
|
||||
|
||||
Eerste Next.js project aanmaken. Open een terminal in je web-folder. Type: npx create-next-app at latest mijn-eerste-cursor-app.
|
||||
|
||||
Beantwoord de prompts. TypeScript ja. ESLint ja. Tailwind ja. src dir ja. App Router ja. Import alias at-slash-asterisk — ja.
|
||||
|
||||
*(Ik draai dit live in de terminal.)*
|
||||
|
||||
Daarna cd in de folder, npm run dev, en je hebt localhost drie duizend draaiend. Dat is de Next.js startpagina. Standaard, maar werkend.
|
||||
|
||||
`[SLIDE 9]`
|
||||
|
||||
Open dit project in Cursor. File, Open Folder — kies mijn-eerste-cursor-app.
|
||||
|
||||
Wat je nu ziet: linker zijbalk is de file explorer, midden is de editor, onder is de terminal. Tot zover hetzelfde als VS Code.
|
||||
|
||||
Wat anders is: rechts is een AI-paneel. Je opent het met Cmd-L. Tab-completion is in Cursor slimmer dan in VS Code — hij kijkt mee met je hele bestand, niet alleen je laatste regel. En Cmd-K geeft je een AI-prompt direct in de editor.
|
||||
|
||||
Die drie verschillen zijn waar we het in de rest van de les over gaan hebben.
|
||||
|
||||
## BLOK 4 — De drie sneltoetsen + request-management
|
||||
|
||||
`[SLIDE 10]`
|
||||
|
||||
De drie sneltoetsen die je vandaag leert. Tab voor auto-completion. Cmd-K voor inline edit. Cmd-L voor chat. Onthoud deze drie — dat is 80 procent van wat je nodig hebt om Cursor productief te gebruiken.
|
||||
|
||||
Tab is gratis — kost geen requests. Cmd-K en Cmd-L kosten elk één request, dus daar moet je iets meer mee opletten.
|
||||
|
||||
`[SLIDE 11]`
|
||||
|
||||
Tab. Het simpelste, maar onderschat. Cursor analyseert je hele bestand plus je recente edits. Hij suggereert hele blokken code, niet alleen één woord.
|
||||
|
||||
Een mooi voorbeeld: typ een commentaar zoals "slash slash render team list". Cursor begrijpt: aha, je wilt een lijst van team-leden. Hij genereert de hele component eronder. Druk Tab om te accepteren. Esc om te negeren.
|
||||
|
||||
Wanneer gebruik je Tab actief? Voor boilerplate — imports, types, props. Voor herhalende patronen — als je tien velden definieert in een form, voorspelt Cursor het patroon. Voor voorspelbare code — CRUD operations, lijsten renderen.
|
||||
|
||||
*(Ik demonstreer Tab live: typ commentaar, krijg suggestie, druk Tab.)*
|
||||
|
||||
`[SLIDE 12]`
|
||||
|
||||
Cmd-K. Inline edit. Dit is je gerichte AI-actie op een specifiek stuk code.
|
||||
|
||||
Selecteer code — of zet je cursor op een regel. Druk Cmd-K. Er opent een input-balkje boven je code. Typ wat je wilt — bijvoorbeeld "converteer naar TypeScript". Cursor toont een diff direct in de editor. Tab om te accepteren, Esc om te rejecten.
|
||||
|
||||
Wanneer Cmd-K? Eén variabele hernoemen. Eén functie refactoren. TypeScript-types toevoegen. Een comment toevoegen. Korte, gerichte wijzigingen waar je precies wilt zien wat er verandert.
|
||||
|
||||
Kosten: één request per Cmd-K aanroep.
|
||||
|
||||
*(Ik demonstreer Cmd-K live op een kleine wijziging.)*
|
||||
|
||||
`[SLIDE 13]`
|
||||
|
||||
Cmd-L. Chat. Voor grotere taken en vragen.
|
||||
|
||||
Cmd-L opent het chat-paneel rechts. Typ je vraag of taak. Je kunt context geven met at-symbolen: at-file foo punt tsx voor één bestand, at-docs Next dot js voor framework-docs, at-web voor live web search.
|
||||
|
||||
Cursor antwoordt en kan voorstellen om code te wijzigen. Je krijgt diffs te zien voordat ze worden toegepast.
|
||||
|
||||
Wanneer Cmd-L? Vragen — "hoe werkt useEffect?". Grote taken — "bouw een hele Hero-component". Code-review op een functie. Een soort senior collega in een chat-venster.
|
||||
|
||||
Kosten: één request per nieuwe chat-conversatie. Vervolg-berichten in dezelfde context zijn gratis tot je een nieuwe chat start.
|
||||
|
||||
*(Ik demonstreer Cmd-L live met een vraag aan Cursor.)*
|
||||
|
||||
`[SLIDE 14]`
|
||||
|
||||
Request management. Vijfhonderd requests per maand klinkt veel, maar als je niet oplet zijn ze in een week op.
|
||||
|
||||
Tips. Combineer taken in één Cmd-L. In plaats van vijf losse vragen, vraag in één prompt: "maak een Hero met titel, ondertitel, twee CTA-knoppen, en responsive design". Eén request, één goede output.
|
||||
|
||||
Gebruik Tab voor alles wat eenvoudig is — kost niets en is vaak even snel als typen.
|
||||
|
||||
Cmd-K alleen voor gerichte, specifieke één-bestand-edits. Niet voor "maak iets nieuws" — dat is Cmd-L territory.
|
||||
|
||||
Anti-pattern: tien losse Cmd-K's voor één feature. Dat zijn tien requests voor wat één Cmd-L had moeten zijn.
|
||||
|
||||
## BLOK 5 — `.cursorrules`
|
||||
|
||||
`[SLIDE 15]`
|
||||
|
||||
Even kort over dot-cursorrules — kleine letter. Dit is een bestand in de root van je project. Cursor leest het bij elke AI-prompt. Het vertelt: "in dit project doen we het zo".
|
||||
|
||||
Bijvoorbeeld: "gebruik TypeScript strict mode". "Tailwind voor styling, geen CSS modules". "Server components by default, use-client alleen waar nodig". Imports met at-slash alias.
|
||||
|
||||
Het effect: je hoeft niet elke keer "vergeet niet TypeScript te gebruiken" in je chat te typen. Cursor weet het al.
|
||||
|
||||
Hoe maak je het? Vraag het Cursor zelf. Open een chat met Cmd-L: "Maak een dot-cursorrules voor dit Next dot js project". Kost één request, en je hebt een degelijke basis. Daarna pas je het naar smaak aan.
|
||||
|
||||
*(Ik laat een voorbeeld zien.)*
|
||||
|
||||
Belangrijk om te weten: in Les 14 — veel later — gaan we naar de nieuwere variant: een map dot-cursor-slash-rules met meerdere md-bestanden. Dat is hetzelfde idee maar uitgebreider. Voor nu is dot-cursorrules in de root prima.
|
||||
|
||||
## BLOK 6 — Hands-on
|
||||
|
||||
`[SLIDE 16]`
|
||||
|
||||
Goed. Tot zover de theorie. Drie taken die jullie na de pauze gaan doen.
|
||||
|
||||
Taak één: bouw een Hero-component via Cmd-L. Titel, ondertitel, twee CTA-knoppen, gradient achtergrond, responsive.
|
||||
|
||||
Taak twee: tweak de styling via Cmd-K. Pak de twee knoppen, en verander kleur of spacing met een Cmd-K prompt.
|
||||
|
||||
Taak drie: kies één extra feature. Een FeatureCards-sectie, een ContactForm, of een Footer. Vrije keuze.
|
||||
|
||||
Daarna: git init, git add, git commit. Je eerste commit met Cursor-code.
|
||||
|
||||
Ik demonstreer nu taak één en taak twee, dan gaan we pauze houden, dan jullie aan de slag.
|
||||
|
||||
`[SLIDE 17]`
|
||||
|
||||
Taak één live. Ik open mijn Hero-component prompt en plak hem in Cmd-L.
|
||||
|
||||
*(Ik plak en lees voor:)*
|
||||
|
||||
"Bouw een Hero-component in app slash page punt tsx. Specs: gradient achtergrond in blauw, grote titel plus ondertitel, twee CTA-knoppen met de tekst 'Aan de slag' en 'Meer info', responsive met Tailwind, geen custom CSS."
|
||||
|
||||
Cursor genereert een diff. Ik bekijk hem — controleer of het responsive is, of de Tailwind klassen kloppen, of de structuur logisch is. Accept. Save. Naar browser, refresh.
|
||||
|
||||
*(Ik refresh de browser en toon de Hero.)*
|
||||
|
||||
Daar staat hij. Eén prompt, één goede Hero. Eén request gebruikt.
|
||||
|
||||
`[SLIDE 18]`
|
||||
|
||||
Taak twee live. Ik selecteer de twee knoppen in mijn code. Cmd-K. Input-balkje opent boven mijn selectie.
|
||||
|
||||
Ik typ: "verander primaire knop naar paars gradient, secundaire naar transparant met paarse rand".
|
||||
|
||||
Cursor toont een diff direct in de editor. Tab om te accepteren. Save. Naar browser, refresh.
|
||||
|
||||
*(Ik toon het resultaat.)*
|
||||
|
||||
Zelfde Hero, andere kleuren. Tweede request gebruikt.
|
||||
|
||||
`[SLIDE 19]`
|
||||
|
||||
Nu jullie. Open je eigen Next.js project in Cursor. Volg de stappen op de Lesopdracht-PDF. Drie taken: Hero, Cmd-K tweak, en een extra feature naar keuze.
|
||||
|
||||
Vijfenzeventig minuten. Vragen — gewoon stellen. Ik loop rond.
|
||||
|
||||
## BLOK 7 — Afronding
|
||||
|
||||
`[SLIDE 20]`
|
||||
|
||||
Voor we afsluiten. Wat heb je vandaag geleerd?
|
||||
|
||||
Cursor is een VS Code-fork met AI ingebouwd. Je hebt Pro Student actief. Drie sneltoetsen — Tab gratis, Cmd-K één request, Cmd-L één request. En je hebt drie kleine componenten gebouwd met requests onder de tien.
|
||||
|
||||
Volgende les is Les 4 — TypeScript Fundamentals. Strict types, generics, utility types. We gaan ze toepassen in je Next.js project.
|
||||
|
||||
En veel later — Les 14 — duiken we diep in Cursor 3. De Editor Window versus de Agents Window. Agent mode en background agents. Vercel deployment met preview URLs.
|
||||
|
||||
Vandaag was de basis. Vanaf nu zie je deze sneltoetsen elke les terug. Tot volgende week.
|
||||
187
Les03-Cursor-Basics/Les03-Docenttekst-Autocue.pdf
Normal file
187
Les03-Cursor-Basics/Les03-Docenttekst-Autocue.pdf
Normal file
@@ -0,0 +1,187 @@
|
||||
%PDF-1.4
|
||||
%<25><><EFBFBD><EFBFBD> ReportLab Generated PDF document (opensource)
|
||||
1 0 obj
|
||||
<<
|
||||
/F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 5 0 R /F5 7 0 R
|
||||
>>
|
||||
endobj
|
||||
2 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
3 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
4 0 obj
|
||||
<<
|
||||
/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
5 0 obj
|
||||
<<
|
||||
/BaseFont /Symbol /Name /F4 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/Contents 16 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica-Oblique /Encoding /WinAnsiEncoding /Name /F5 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
8 0 obj
|
||||
<<
|
||||
/Contents 17 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
9 0 obj
|
||||
<<
|
||||
/Contents 18 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
10 0 obj
|
||||
<<
|
||||
/Contents 19 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
11 0 obj
|
||||
<<
|
||||
/Contents 20 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
12 0 obj
|
||||
<<
|
||||
/Contents 21 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
13 0 obj
|
||||
<<
|
||||
/PageMode /UseNone /Pages 15 0 R /Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
14 0 obj
|
||||
<<
|
||||
/Author (NOVI Hogeschool Utrecht) /CreationDate (D:20260615075148+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260615075148+00'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Subject (\(unspecified\)) /Title (Les 3 Autocue) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
15 0 obj
|
||||
<<
|
||||
/Count 6 /Kids [ 6 0 R 8 0 R 9 0 R 10 0 R 11 0 R 12 0 R ] /Type /Pages
|
||||
>>
|
||||
endobj
|
||||
16 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2079
|
||||
>>
|
||||
stream
|
||||
Gb"/'968QQ&AI=/oOY'3fS\Oo3U@LmW+AQ*:iX<[6WIZrD9J)"g<h;Q%f>#TRuub::;B!/M)^>KekC9`pX`dHa<;KEa8D!"7#r^;qTL,'V9+Z9hstK%:/<5bs.24;bg<c7Yrd,Bk_@Y:Y^NUjA'5>;Tc]BXNGNP"Ou;t*&'=VRA3(Ye+\c!6iK?"F.U8aAGKpqKFQpA(3YO4a8o[l\]'MS[Q&'4i]Q]D`9:FYf[_0WC-@9QYa.>Gj^/jM9<CXBu<EjA</*GE/p7Y)=A'/590dC>`+S0]CdBsN@B<J+/,V?UKdt@rp]iq\B8C^_Z"W?W$T6[R&hEMh>cd/32bBN?+:1qnaFWWp%mN]Z1[eoi:b4Dt_'hr`rag%R":WnrR!j#Rf5=?&Pit2JU#%K.l4?`1(:@l/7\R)cd"r(t\#Z&/j$ER\"Dh[+n,9?M5f&Dk%&ri3#M6/)C\-.%m[hG51[]qWc"hhTF`Q<%',R8\$`qFY1rE<^_$,SF"%>4_P6H^EeD&cq+R:c1hCu_r.>m@RR^DaSRi"]\@\)2do$RP+@e[9eW7^:Fj"%5Jrkm)lsU_YLlb,5QL6jEk0Z_rBKV&P)[aCq2B[Z7.U=]--f+8P6S2jUt5.>t,qWduQ.5kb&_U^;I!08VXB^VO%Xb('FHR"M+4PJA/!]3l,^I5$H8<]]Y+QuVB+*,;.T95H3EcG1FfQp8CE#D(QL^PM#2@'M.R:6W&P2]NXQZ)A%1&K"1JO]R<'+4-3T<^P5)c=\us9.q+tQ&9SnU.k3r'e=SV"^S&f!HE<M4)"8ZNH6gM+DS2o-H25gPYs'k1+^alYUYGMJfXekJ9cFsVsRS:plhBpb$i(beE[7H'htG_X38\5&H#XfFbLf%0\S['c*=P/MT+kfC5f4i[.@iQejV3cUe`Z>]s<q=,pKM!SLdiV!Hk,iK`LJiJ#@(R?C=DN$*$C>c(st0pd>LAn88oa[XV2Lq8;#Vo>g`b(:[T5\CZRl9:'>%[C[`nQ?6brVX<"])?rDSd<+"2onaHB!a&M_V:V!_+B$d(4g(_5d]s#6@o7[lPYn9ec&dLu!M)3NntsGHe3@(^%pk?$F-PK=qfpWe,POr1lT7>3fD/Df^)FBg_1&7.m*bkjbB0&i&UG>;U&qGf$#)gQBu*_W?"?b3'&GlrcA@MB'q4Kl%VT0e\JiqT'Ub'57=k=a<Zk["EBk>FKX>J;:qEg'b@H@gWm4TY.3mo(TmK8]RUr@VLVGd^g[<,jI^T#re*;E3<pkF<2#=1H(&A</!c0p^]M4-AJFjROW4"Y;3Lj9Rj9g<.+lk,i*e@%U+><1(*q4&;(OC#G%g-\=bnKHkB#=;6YTKM;r;r$S3kj]<'.\AoDilVceY_r):Y>(`gp?280)#!Eg`D<CG=Ulem:5cFXEK\LmI$k9P0@\FMr#SD;)Ccjf6"0a7Fp8!QuNF!roj0N'HdZN>FVE\GBsNWk(.!9)&9QN[,?>T?_Zm0164[f)E`/2EFI6>c%+^k:6>[JU97]6(<eT0*%\$;X>9l6(o:L0c'jYi?ff\t+P5*7a0WKt\<h?0__=jK(j)<agJH?;/.)kiK)DEV@Mi3$)Ltg:MM>*H`N&7!Dgr_2NJ6\IGKekf@dXYc_U^:n5LZ+POh_0De<[c;\3?jiLRk>e+].<D[8U0!3TF'<>BJG@ZJ311[VRl>"We.0e6<259<*Sb-!4/Q[@9S55++=1\XZmrZnV/KQQJq[D:AcF;:DjF3ST4gdqgr]^FjiX%`Nh8X%cZBkZ'MVYLDT'IRn0b$7[#$kXnr,6%\`1K>oHJB#]UBdE>'n9(P6a,Y!\oF+i&/2i"DEMr>,b>Ak@?6Wl$08Q*?0aQ@7p$G(drRW;B+2>A(U3lV9ipN)XE"F`jqZMa3]n>fDDFDP72&E>oSDLA8;6iI*oQj4NS1EePA/8rt:`^s0_2APjP,RD1'"AB\58tS+7_n?,iPkI*7roV'kU[.tc#/.>WeVrCP\WAB>n9B!imN\UXH9Ts<!PN0]ddC,7BrYj??Xa>(=iSZ7,CAQNUV`88G`h,!6*Vi8fL+%1\A-pll,F0(3?P%%Oen9A!=#=BEW~>endstream
|
||||
endobj
|
||||
17 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2260
|
||||
>>
|
||||
stream
|
||||
Gatm;?$G&5&Ui!/R%l$I.l$n/m$Blg36Ab$ZVE$AjItf?6pN"C&E&/5PkD6K*KZHNe4uF/EGWf23#LG]F6@"#6[XmQca4hkAOS90NbC8HeV6QBA4iosoOddUNu+R7ja<TBYJsWg\f<>c`G@NQF8.^4;tJmZ0+_Z9ME=,&U'WksJo\qj)\GVBUm._"3u;S6I$NjJ:n[rmolfeo?Ro\5^!krlH;1SKWJq:63XF]LJ@6pkY.b$M/$2@s.L9OKnfa]29<W,<3KIHpU=GQ1J"[7Lkg_7FCaI:_ee?omBVPd2.nZRgG.,_8CMU:GFK%XXDqChr#k<'&U`+KcfBSIE)p;s^C)^iaeNM>@.'oZMCWpKsXN8oFf6S7so6>XSYDoKWlI3?U/,W4t[^o7P6he`>)GH+E$"98^aY=@ln997C;2b83]LshGMl1;E(ac$"BJR8qeU]>:!F8cg=%;Q\Nl?.6D/G545G')&&@/Hjs)S1aXV>*)&=.@dmbk`W2PH0U'qt?$,3r4%ieJ+"??@gB0^bBT&J4VfGKkkB!'h<RV7dZ:qq]:s;M.;LP>KFBajp,c:e4SAmS2OC7CcI5:^Sq17t`Mac)8Zo3hJ-S:G3P<:(%orq=ntkUL^YI:9K->eV*u$#MenTm;^'m6fWps^V%>YNQ)D>QH_/KK)p4H"_f36!JTg#oPjdXVe9a.D3C8KDSLZRhr!;'U$9>kq`_@^Yff5Vo_G[=p;9fUoEk3FH+hJL3S-),%V[/fJ1COqX"%(J.Sg5h,Z/;5:.#F4igZhIiRMbs-h*1-_ZbF&Ba6\h>4*G+Nm>J,=;@@KK['!J;!HAFFjY;s_.*uoP4$K(MHr60*W)!K)-IosqLM=&<#&hnhT@b*2D<-K:aV:S3'YL:JV:AWoET>aPm.\';tcY85o.^1Bl)?'8Q01gPolKq9'Et3=NX`\+\iR%91UmUEpRj0;#@bU".g"8bQ7D(9`pqK$TT`BLMe:H^!S:X\5IdZ;q3K(.VlF^Q$((bD_:!6R>q!r`q"cb)Afp8h"i"Z76\u6BlDj`o,Y2n5sQAk'SNrI'>Xbp9cYa)?(rZDaU[6)YJ-p&Arj4sHuZbC,EOK:</O?oP;DteO0I(rBUX>JWC&S1M]Zj(=bkS"Nk4U6J!+iS=u#97p=u>9].Ec])gAO+#tYsW%s`D/9Wn;RX+tHG/P4I.(#1rdSfC01'I.&3?'_IB"1PL#';`R'Z6B(FZ8@\]c;m%s/VlBB5;q_5&DrcF#m8?k5j^WYf^cZ#1V9C<;J/,`HcNfR&;T<)HngYVBalMr4PW%4Z&3#K9&9s`!uFh!%V#^ri[c1<YUQd]CdfI"g1H:5gJ*#J"F(GU_>`T5!/lIZU#1gc4e@PEXlpc[Za;W077\K6J3A\a'-/@'"Z2"HUpWM`91;blE_KcG8+)an?$]o28a*q2\p4P3:$/!KpU")6Ggg&4*86?IRcZ*UERjZa-4OJc!jmM*,d^Mo0N,%,(QtW-&.,JWRX4FeAOkBgA;&,Lc@XMleYid<>m;.7$DR\bh<QYg[`=-!h6bc7ilUP6+F[X/FGODC)W$RVPH7H45;ZeB'f#-ioh+o8<O:9$Aus+N^o6!FPJrf3>ou$fG&Q9*6VCLfG_30E8P['n#6RbF<fGVVdCka'f!YY;3csL+RnnD7$^mt&UB]OubT!9-4XO"IbX#UQQ=b,#T6<=^Peo<TMftcTE$;;U),-pF8;bHelB46CcR-WOR?joH3]_bV4,G;&`kHRnB,sNompn-n5OUeVZe9'/s2BC]>5,SV``+U0>["sk[Z+:5[oI/+OS35U.'*A:/hT6,`Fs8EAY3U;gROC[Jrb`uf-e29;=T)J9@ukDZSGiSPm3.kFpWVMDiFk5$p'FTIr"M"?dX#V7=c'4G6@*X)Y]f<rWiB?@\69cV&be>7*^=4'o-5So:6M\9C=4*APWF=;:4iooOM2!3;If?I6^cY97;B,iS"r,+g8:aR^UO=%+#3;[>p4,`ApBur7`QkDgBDrhOi>WJeo8j[L6Y:?SV-K,TLQ(Qe*T^maKpf&pVq@M'jI3Cu'f0)!;,f&"nQ9B/>#XO,<TR)gLKe$:)P/[t95q!,Hno>b4]1EP/Zu)CWoso9l40Sm;=5G9[&C!.5J]^o#UO#098q?kBV'hlH'!$Vk?WSY?h*nuRS]LFFeIro[TLn(ZS/9-*Hf#=tM`>+a=S/9)W]EfEF^N/A>6EmeBo;L`1e3HeZ*#oq&l^o90rM$<?']NQ$es+oG]^6T^anSb^c>6Y~>endstream
|
||||
endobj
|
||||
18 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2164
|
||||
>>
|
||||
stream
|
||||
Gatm<d<=8&&q/)-bfNep/$U9EbE?4Yg/p@0j3sO#[I(kD+!>SL5p?=FK^;*6h`Cg,`Jr@.g5R=],!c5'cCI$!V)6%b)Lgiad18nHp.\.n7a!ZcP@R#')d4e"r;ImW7o$C$3mZq;?"R4p],493*,[,A`W'iI!gBG9]]kB@<Le.F-^?,f/_DqPl"C"ZP?gP`ZTHGq.:k!:B9U^>RLLuXSmA1P.S1T51#;G9\@,tb/tqC)R]jf^+";E84:_mu)lgIrjf-1P`d^A!*A.:WY:@4A6Op.,o7Lh[PC^j?4tusD5EF`mc:?3rq#`/-n#^^9'eD&>g,F$7\%0tqVk$FnEI4HTI(N@h][s"d*u^JETj;pC4^e4t&"k.pHs>.PJZr%QV?<gqYUNSY*@ejH]%PPf/A%/:4`Fa$MWZ8%]Qa_R_lL7n.\'BTqZZ`jN[8"^HjX6OiL:m8Qop/iCSdOuPS``8;'lANU`t#E96UKtTV=$AYY1IdEbcVTSSP+^TT9N@!t;h6kSc5)ND.mfZm30Pb5#4XJ1RBuY=sMTMZHiQ",XV&4Pp6Z^DpuK+$YGUTA,jEf*e&I\&UP)aoAWkT4e\%-rE,R.G0%h1+8hT]&Z0$eMi'H.(HtQL7XoT(]BTn'c$Y$THV275Y')u$<f95m-CTo.ol#lGcn;iifA4rSLC;^70*\a*WrI^7;E$%][j'LQIaO4hQcCRY[r=FEfEqrD!9JTH>O&X"#HG?JN;#i$<,%V)f5&%*9UNZDhD\Os)qKp_i4Qn`+0H$&'90un9S@T_]/-6eM)atQ0bmfd(?M[;sL@ap-P/W-184g@YhL>LG82j1+A!86X#&l'l4[J6f*BDE)L`#\Pak0T'pnK)dA]6Q$9TD?AGF5Y$4X4"LAgBCIQjoV@U54g!^[c/T)\sJ1rqX<Wdpc!?&J0q&RP84*!SZG:L6YTmDh*D,A9k@ofO=s*Lr5q(rsbVAHPi`s5:.h#II3bq:@[P`07MnJndqA,5j&[V<[GKg]'BeeY'Np[8)D`:1?lfbc?TA`!LM5Cr%m"$d;GA^lGbBVu)gna+(%T42?qW/$R27ajO/IB>gu!k?$YM!ls@p]`H`k<jRB*Qg:>K=@I!9%&STgsZJi&k*\Ahh:<dM"@acNVCG2m6U%;Z!BPT?c:qZ)i:c\P+eVEqprGsTf95Kg$4ff(fq\tYB^RA6JANr619.LCj\6g#&D'ZG.M\9j%hLVWL=btlrG^_M&8-&'/DsZ3-akHnO4q2DY*qJ(;;9?<7tq*n;9]:jNO4jMA=in5E$DlPk!?<9RB<LS3<([KRO'd7TVI6i2H#]6Fgg)AD2PY!R"8u#kH=(8p(FAG@Ec\SZ"imi((IBpF(gAL0]$b5$HZ'j?bjhr1Q-CitFK(*b8oM^%2+P[;1=N.r0:KQ5.PAECKk**D.,G9e8dO3Edl101/6&n[IOTPWc&SKt["040DVsEI(]]i2`suKTh!?46INBP#490NA#!k:Tn<";X[fLQH=k-(NSd@Iuq'PBe*B8-2js.'P/)tK\"Kjp;	StKHP3S.pWA<'*Ba/c,W7q#94RrH+I\`<&@j9j<d*Dbg+dGL0S)rOJ'+gf=f<H+)hkZ;c/PsmLiC,mrdjOW:'d0q9IN'Hg&)VPON\*UQ'PUKA1]G"?*6O;40]N>N!(t?o1HE2YL)O_=CFZe<YXfDXl!Y#dYT)pI<2,#T6)qI+\=XhBW]lD$C^\mu?'0CL[YpX=kh[nLL9bOLUPc)38qQCAn>[_V*_?gq"&La[UXQT]PU!X='b\Y')I'D-uYN&J@ru3LAlX=dI^[uufHO=lq#Lq(Xj0]B9DC9#=Bsalk4_g'%4?gge&^L&Qo:?j2:@`j.FSactR7tZS/-tqbWLeHnhcXH49ugA.iX+bSfsZYF0$rT`\@0eNqqBO)5El6T*aPHe$ls<&,\R.4RF9Z6nZ01b9(+fRUmJVLkUFEhN7d.c]7[HeH"9QQ\^9[8UHS5%Xj18iFKRJ\],%Wm.Bch,Unc<n9&[m^!eK7V,*nl`jg83JmD<XtPm0'*h-1spOGr3WZt"aET'7'r^B,4!B+Z52m'@?oRtdQmIKu?0%X+#Jf=RftR3":sVn\G!C`lBp)PV<&**Y8d)DMQ]0AhD[=V0h.qP8Lb(E09R0=rX4:ZTXlB$Tr`LMM5+#Jj5m_Z~>endstream
|
||||
endobj
|
||||
19 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2097
|
||||
>>
|
||||
stream
|
||||
Gatm<>uM]_&q0MXkgIX#.C@L*4oi?nCeS;IP171DHlq?IAYa07,HYS/1F"@<lZ7Aa,sGe$,m47&[.D[nqXj#iEpDVKa5>?'dG$C(o3G+:6/rjEK5<g5/%QS4qYVg]<fW&RFB4pnFOD7BVo.?kqsZQq."/`'.ia]ocG^**S2mCXQd1g/O$4RiY,LEh2*O!38*B3Dqgg61A[40J)d67C%F\'*DtRA)H1pL'Y@tSEn^h6sJ+<Au;>KH4N9WValBgh;bBFbepO@%";6T_QMt2W>M6g8$SM*s`kbGPGk0=0S9L5f=3ki'uc.QWWDocVAb2`ElBhNt9Rm7>k1keNW=rHI[*)@BeB/I?%BushHRZj;Y7^^D&#H$#U];F-^r]SVu[kN/g1N7r\=\ikQk-_jil&,4a*6kR]>4r."4)Mt0:]4]S5DCNOK/2PnCb"i%dnb"'B`fr8>!$e?brb5lnTeBLj%4P4\KgQ*.lUb@JZ^#GT7Ut@4K_[2lu7@j,\ei@U+niN"o$-AJPV-,mWjbQ7c^(GcJb4`c+H0OeXSO`.aTa_j"E:qd":@>f?/k,:A"fEE9dJGR!h#%I7kY,$gCSeS5<j,"^e_G[./MuS+/=_gWAZ+Tl*6QZuBJ5]9pGCY*e(PZe_Tdf@GI`SV%;?k<Pp1GcQ,!chZ869S;Jd0(?j_O+:m^%@F%/JBemD',O-0JoC_D[/ac_;S3!o%i3cIbBHX&r-8CM;@TR`k08pM77`.b40P@h+5(LJ2=F;mBk.jXL@HSIE]!qFp3C_[QNl]8/RX0,r@V0id<hc)ZGX)D^i7q`!ma^*X-?nQh42Ci;P6;KPQ\+aH2+IenUr_0>"J8S72bU0-F@Q"_#6,=Mb*-pCgg&[Y2"fha4RSH6&A41%C0FNd6*_U+:=AMa[GV"W*OBVAn6)EmifV2jqUq(#jU=o'^k\#]Z<Tf[\KV&Y+b.DG!45-f2LtOYWI:m"mXN4>q#qi[j#WRJL]tK2q@0&+i8l6[6psLf@0g4X2l%gJA$HGBS#Y$kTFh5<1CW)d%L"#S*nGO\sDqj;U%Qh][3imYNH+QF7C@\O71mg[uB+JRo"%WABNh5RIZ._ht+d'oSUYgWB^e'j_:W%P&0N_eA0'O;-ZCS+s4HWV$0_I7r"n[.(7![E)X4qq1IZQC6gn4Z*gPk.,@IfNlfm8eMGH#^;I>4PiXNa>2"P"K[b!K$?>\eb*;???_rRp_apN6)TL(e@,4Nb#Q&/9R]@eUHt.at%hin,6p!qR9rs>Gs2R?A4(bS2`^-idW?tF$SjT6mjV$*6q*>Bgdb8`OQd;tNNIrUV=ar+DMM#8B0IRD="G'Ei1)Np?5OJ-iJAkYu^A\8V.,e#kA7edd4PjECr.0SO1r!VNW7YtiWrCSdd%^9MNdi>._\StPS=[1"k_YC.804n/?*L9BdP?"7q:T:dRO95tdPK63*D%_Pck&=)B6"bf=S*()%P_1^c,lD8LWr^8cmTt;51*$_$Mj8TZC@XCKA]<UE6pGh5rf[(2+PJ@gk^h?h=du<Zli!r*5)?@[sBJ+StJ'.Y\(Tc/SNE%eEL/j$D]ln*ni>^CM0_j[F9XNo%o-@<4DZX6iqP(?XLu;!EGFlUVgMa^uE`%H(*Lgb*gs_:hOm.h.`]s`+W+_-T0=SkT`j5`$U6kqpD*8IY!2Vq)6k>K7AmjWaZK[S.*"X8eO"A?0uD64hBHP;X>+TQ'BE$g]\86kP$Yu#M^HFVB\K42EdP:`_k=]'\^\&HONL];,o3<c-M7`&E,e+pF+\;8A<a3UNd.W)q1T=c04>Zms==;Q)JlacB%j[r]%Y:;aBmU'CHBK%Ik$El(e:67)pc!D479gZG`tGkp8$U.'L>JZ>rDH#,&tZ1.!**]g2nS#.g"!4Sao$=Sa/oQctgkEGB:>qW:3sEU+EJc=!f>R:B]2aZM#I,fam-/@tuY=;CL'g.tfWED,c`d[rm?,$$!KPCu<pVOYZUqDrr/<qRVNG@=3KfM0a.$EV)C;Ds.7NEcgghk`r+O>Kmq/t#WG][9##K(4\5rlJS,=T!m-dP^dK[s!)"g-de?AuC:@kq[R*(7uEC=rA>,Cu<-[hmMU/M=g'Dnlnn=~>endstream
|
||||
endobj
|
||||
20 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1919
|
||||
>>
|
||||
stream
|
||||
Gatm<?!#cM&:Mm.R)9;'O&7M)"65^h!hlHa8UB_jcY;X]>$B*bb?AJ$"bC%<4"JuD`$@)j"sJ=p]/-efhO/@SD7i2bNL*%Oa7Ssl87=pH.>?TN9B.OK2h(Gq<ERT67m[/#3XP&\dglYrFr/J53/FO02<cVB'!Bj*$;7JRTs.h)aXb+)B689Arf4kp^MddJVt!Qqae*fpgF+'.YYk2g7_`]+">n\i*qZQkPXogNWK!&AS`<=;/7_K^mcJ)HiEn3^;Ba0f8Z<7<dkVG_ChA1D-m%>TX.<`D(3J$iL&@8JBqid4P-F:3C%P9(Q\E^rmc[[X3a3q$=)^blRC,TKM);BHGBZs5g%b2QOmAa'H&GQFi*5VMp:hC5bXn!:4Ot]$/_7>p<]4s%fA5%E[Vs5gg`snkh.J35f1s!ikYj@u*EbIT0];:#4%bE)QA5$rCa!8:GUXX<C@.[$L^Jcr\L(YM"QO>o-%OC)(/!<$"!m]])*q1M>\O2GGAuN8H?1E,@ZRULSWYRS`+M,T,'FdV/6hHYIs.MCN[^W:UZRAc"<*ahZO^']KeU%S;Q:_9>e-08'1l*X!/!r+!r?3>5\$@d5Oett<Z8"JE1/U=Ze^)@R?n>D,uEn9m%CuoKf?Q[BQ5Q,[3u'.4cSo2Un6g+@8ubfc$<*+i%YmZ"7pklBRf,*DP2BjINuj\#FgcOadD.Bi+Z#FQ>6DYZrE:Kn.cf^S]N0c:lA$M>J%N:W;!^%2ghWS=6uMM0^2VR1VA"^@,GQul9nj/FR\uASV?7$-l<P>#2H!S:Pk.'r=[JUOKfh/V3NqaQ(OOVU:b!t"bXo)o3.W@XL-k"CelD/5In"Y%Sn0dH,u[>r.?/rnu4h.'Q=$$=K(R]6.OT!V<h8g>,R^/2Au`(5E9?bhag#(dJ-<;.$_>RDL,SXC7S*_n0W1LjqY%:U?EHbOZT<op'@BOK*rV>.I3fAcEI.tndB6<i$,5M_V3=N*qZ+a?&@X(ku?>\L,B#nNFRf-5U4,7rr@nNM:$NJ)@k[>43eap]A)(/YdT+phMViFp\-_F[6J%'?dJrCh9IY$ZUNda-6XARe/V&Z;ML)'XUVC';)HfmXX4q]\WhVT.OV)mM^Fk")t'G,ccG1?JP:5^p.aM;L22LM1.-5NFg\_VM(lQTEr%o-.TnCqU3&m=OY)Zo=^<&J\(d1h<f<q(BsD`l8+q\nm_0Od_7EMoN*6R".dKs_ip[=\lrpo&0J5!L`)#saW*+/j<Oc(Dh9VG+$Q_-ETYF!'YJl,CnL,Be(kdqPO0aq)EZ.Bo=A0!h#'grThGB\h?]''=].e">`BBW))(RM?=X-O_U-4\;h_L\P<,Ia^G$.hd*0;nJMnp3+\'t<uHFo@Fe;]L_kp\f\FTE<*8#@[/-P`otI6dTKbUlKB]S92c0,2ns9<3.X4Jb=Q]Xs>-(Q%*EIe;n&@^A!5Y4G=%jf6)b4cJi'(ogqCq\>BbQL%Ie&+R53o;TqU,h0g_ZpH5q*M<8;&KD"IAlEuq^dQ#1ANU0mAf=us\^JF1DE$d$q`VB+qh4ZN4b4X;j%Oe6F9_-X$!]LTnBX&moIGD8J$`/@ir+.Lp$k0c=*C32fg9e*5IN:7lb.#L9Ag_r)o+>t%sHUhl!^9]jXrqpD,r-9:4I75Q4jJj/_DRAMW<]R./B]j0i?H=QtIo+>&KVu!59MJ$Vf^0<1ASCrmON%#)\!&3:T-Rb]NL!BGrmKT=F/T<h%Z6Z+8)KQHlX0`tF@oj&!cZl-(6mN*;Su8mQj,JE"Ifg2G5A2G9O^IH+Iql.E,Hd2Q@UB-/WkT*RH8X%)"*S?t;Nh>YUYLo!OL7s$GN!t.s,'WQ--(NL3/L&U@h1[YmqM[]:Ca;G/46L'l8G^\\T@bd5DA]ih1!rtsl?.=L3qhB&+<C*^6Pb)RF;fCpNJ$`3MYl~>endstream
|
||||
endobj
|
||||
21 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 387
|
||||
>>
|
||||
stream
|
||||
GasbT4]B6P%#4NUMK^W,@:D1fA)sCY?/SCZ=PR*)V+L#_-dC%GO-11]Xog&Dc]Y+pdOUHaao:-t^k9YoZ\2<)431Bscmp[?k]8#qR8YE/$al(`.4+,#8]l2R/JNpQZ4TIb03?GmWr\Xtcjk>bLa8N:?(VnmV8JFo6tpBCpeY^['u_f5J(l;'aIsp4S.<U\*h*^h^dR+;YdA]#c?nu\D]'6u'4D4A)7_f"j'lu2T_Hgb4BL.Dnsm_\NS,(Mn;Xb.I?D=6_NlRTF=@)h`A(=kit1FA;iA-:<>7YKQKNthP!hn<+,SE=$B<ZW=^s4oVVbuq@c#@@SCt_939>fV.mbUMFB$h_lH$S6=V+2+O/6YJ!UXYBIE?7ZUa7MicAg41ajH,$~>endstream
|
||||
endobj
|
||||
xref
|
||||
0 22
|
||||
0000000000 65535 f
|
||||
0000000061 00000 n
|
||||
0000000132 00000 n
|
||||
0000000239 00000 n
|
||||
0000000351 00000 n
|
||||
0000000456 00000 n
|
||||
0000000533 00000 n
|
||||
0000000738 00000 n
|
||||
0000000853 00000 n
|
||||
0000001058 00000 n
|
||||
0000001263 00000 n
|
||||
0000001469 00000 n
|
||||
0000001675 00000 n
|
||||
0000001881 00000 n
|
||||
0000001951 00000 n
|
||||
0000002242 00000 n
|
||||
0000002335 00000 n
|
||||
0000004506 00000 n
|
||||
0000006858 00000 n
|
||||
0000009114 00000 n
|
||||
0000011303 00000 n
|
||||
0000013314 00000 n
|
||||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<15bd1c06a323579dbb461de4ce8768e8><15bd1c06a323579dbb461de4ce8768e8>]
|
||||
% ReportLab generated PDF document -- digest (opensource)
|
||||
|
||||
/Info 14 0 R
|
||||
/Root 13 0 R
|
||||
/Size 22
|
||||
>>
|
||||
startxref
|
||||
13792
|
||||
%%EOF
|
||||
@@ -1,231 +0,0 @@
|
||||
# Les 3 - Keynote Notes
|
||||
|
||||
**Spreektijd:** ~55 min | **Hands-on:** ~75 min | **Pauze:** 15 min (10:15-10:30)
|
||||
|
||||
---
|
||||
|
||||
## BLOK 1: WELKOM & MEDEDELING (10 min)
|
||||
|
||||
---
|
||||
|
||||
### Slide 1: Titelslide
|
||||
- Welkom Les 3, vandaag: Cursor
|
||||
- "Dit wordt je nieuwe favoriete tool!"
|
||||
|
||||
---
|
||||
|
||||
### Slide 2: Planning
|
||||
- 09:00-09:30: Setup + Installatie
|
||||
- 09:30-09:58: Features + Skills + Request tips
|
||||
- 09:58-10:13: Live Demo nieuw project
|
||||
- 10:13-10:15: Start Hands-on
|
||||
- 10:15-10:30: PAUZE
|
||||
- 10:30-11:45: Hands-on vervolg
|
||||
- 11:45-12:00: Afsluiting
|
||||
|
||||
---
|
||||
|
||||
### Slide 3: Terugblik Les 2
|
||||
- **OpenCode problemen:** token limits, EACCES, permission denied
|
||||
- "Niet jullie schuld, beperking platform"
|
||||
- **Waarom Cursor:** voor developers, meer requests, ingebouwde terminal, Skills
|
||||
|
||||
---
|
||||
|
||||
### Slide 4: Wat is Cursor?
|
||||
- VS Code + AI ingebouwd
|
||||
- **Gratis Student plan:** 500 fast requests/maand
|
||||
- **5 features:** Chat, Inline Edit, Composer, Tab Completion, @mentions
|
||||
- Hobby EERST → Student upgrade later
|
||||
|
||||
---
|
||||
|
||||
## BLOK 2: INSTALLATIE & SETUP (20 min)
|
||||
|
||||
---
|
||||
|
||||
### Slide 5: Download Cursor
|
||||
- cursor.com → juiste OS versie
|
||||
- macOS: Intel of Apple Silicon (let op!)
|
||||
- Windows: Installer
|
||||
- "Allemaal gedownload?"
|
||||
|
||||
---
|
||||
|
||||
### Slide 6: Account Aanmaken
|
||||
- Sign Up → **Hobby account EERST**
|
||||
- Email + wachtwoord verifiëren
|
||||
- Student upgrade: cursor.com/students (later)
|
||||
- ✓ CHECKPOINT: Cursor geopend, account gemaakt
|
||||
|
||||
---
|
||||
|
||||
### Slide 7: Interface Tour
|
||||
- Activity Bar (links), Sidebar (files), Editor (midden)
|
||||
- **Chat Panel:** Ctrl+L (rechts)
|
||||
- **Terminal:** Ctrl+` (onderin) → alles in 1 window!
|
||||
|
||||
---
|
||||
|
||||
### Slide 8: Terminal Setup Check
|
||||
- **SAMEN DOEN** - iedereen tegelijk
|
||||
- `node -v` (v20+)
|
||||
- `git --version` (2.x+)
|
||||
- `npm -v` (10.x+)
|
||||
- `npx -v` (10.x+) → **nodig voor create-next-app!**
|
||||
- Help bij errors, CHECKPOINT
|
||||
|
||||
---
|
||||
|
||||
## BLOK 3: CURSOR FEATURES (15 min)
|
||||
|
||||
---
|
||||
|
||||
### Slide 9: Chat Panel (Ctrl+L)
|
||||
- Vragen over code, AI ziet hele codebase
|
||||
- Wees specifiek → bespaart requests
|
||||
- "Analyseer dit project" → AI leest alles
|
||||
|
||||
---
|
||||
|
||||
### Slide 10: Inline Edit (Ctrl+K)
|
||||
- Select code → Ctrl+K → instructie → Accept/Reject
|
||||
- Voorbeeld: inline styles → Tailwind
|
||||
- Voor: kleine aanpassingen, styling fixes
|
||||
|
||||
---
|
||||
|
||||
### Slide 11: Composer (Ctrl+I)
|
||||
- Multi-file, grote taken
|
||||
- "Voeg pagina toe" → AI maakt alles
|
||||
- Preview → Accept → instant
|
||||
|
||||
---
|
||||
|
||||
### Slide 12: Tab Completion
|
||||
- AI voorspelt code, druk Tab
|
||||
- **GRATIS - kost geen premium request!**
|
||||
- Benadrukken: gebruik dit voor kleine dingen
|
||||
|
||||
---
|
||||
|
||||
### Slide 13: @ Mentions
|
||||
- @file, @folder, @web, @docs
|
||||
- **@docs belangrijk:** verwijst naar geïnstalleerde docs
|
||||
- "Hoe werkt App Router? @docs Next.js"
|
||||
|
||||
---
|
||||
|
||||
## BLOK 4: SKILLS, RULES & REQUESTS (15 min)
|
||||
|
||||
---
|
||||
|
||||
### Slide 14: Cursor Skills Installeren
|
||||
- **SAMEN DOEN!**
|
||||
- Settings → Features → Docs → Add
|
||||
- Toevoegen: nextjs.org/docs, react.dev, tailwindcss.com/docs
|
||||
- Test: Chat + @docs Next.js
|
||||
- ✓ CHECKPOINT: Docs toegevoegd
|
||||
|
||||
---
|
||||
|
||||
### Slide 15: .cursorrules via Chat
|
||||
- NIET handmatig schrijven
|
||||
- Chat (Ctrl+L): "Genereer .cursorrules voor Next.js + Tailwind + TypeScript"
|
||||
- Kopieer → maak bestand → save
|
||||
- **1 request = goed besteed**
|
||||
|
||||
---
|
||||
|
||||
### Slide 16: Request Management
|
||||
- Hobby = beperkte requests
|
||||
- **Tab Completion = GRATIS**
|
||||
- Chat/Composer/Inline Edit = 1 request
|
||||
- Tips: denk eerst, combineer taken, gebruik Tab Completion
|
||||
- "3 kleine prompts = 3 requests. 1 grote prompt = 1 request!"
|
||||
|
||||
---
|
||||
|
||||
## BLOK 5: LIVE DEMO (15 min)
|
||||
|
||||
---
|
||||
|
||||
### Slide 17: Demo Nieuw Project (blijft op scherm)
|
||||
1. mkdir + git init (1 min)
|
||||
2. npx create-next-app@latest . (2 min)
|
||||
- TypeScript, Tailwind, App Router: allemaal Yes
|
||||
3. npm run dev → localhost:3000 (1 min)
|
||||
4. Chat: genereer .cursorrules (3 min, 1 request)
|
||||
5. Composer: HeroSection component (4 min, 1 request)
|
||||
6. Refresh browser → toon resultaat (1 min)
|
||||
7. git add + commit (1 min)
|
||||
- **"Van niks naar werkende site in 15 min!"**
|
||||
|
||||
---
|
||||
|
||||
## BLOK 6: HANDS-ON (75 min + 15 min pauze)
|
||||
|
||||
---
|
||||
|
||||
### Slide 18: Opdracht (blijft op scherm)
|
||||
- STAP 1: mkdir + git init + npx create-next-app + npm run dev
|
||||
- STAP 2: Check Skills/Docs, genereer .cursorrules via Chat
|
||||
- STAP 3: Bouw componenten (Hero, Features, Form, Footer)
|
||||
- STAP 4: git commit
|
||||
- **Let op requests! Max ~6-7 in de les**
|
||||
- ☕ Pauze 10:15-10:30
|
||||
|
||||
**Checks:**
|
||||
- 10:45: "Wie heeft npx gedaan? .cursorrules? Component?"
|
||||
- 11:00: "Wie heeft 2 componenten? Requests over?"
|
||||
- 11:30: "Wie heeft gecommit?"
|
||||
|
||||
---
|
||||
|
||||
## BLOK 7: AFSLUITING (15 min)
|
||||
|
||||
---
|
||||
|
||||
### Slide 19: Resultaten
|
||||
- 3-4 studenten tonen werk
|
||||
- "Welke componenten? Hoeveel requests?"
|
||||
|
||||
---
|
||||
|
||||
### Slide 20: Samenvatting
|
||||
- ✅ Cursor setup + Skills/Docs
|
||||
- ✅ .cursorrules via AI Chat
|
||||
- ✅ npx create-next-app workflow
|
||||
- ✅ Chat, Composer, Inline Edit, Tab Completion
|
||||
- ✅ Request management (Tab = gratis!)
|
||||
|
||||
---
|
||||
|
||||
### Slide 21: Huiswerk - Debug Challenge
|
||||
- Download zip van Teams
|
||||
- **Fouten:** missende deps, syntax errors, inline styles
|
||||
- Fix met Cursor terminal + AI
|
||||
- Push naar GitHub
|
||||
- Post op Teams: link + screenshot + beschrijving
|
||||
|
||||
---
|
||||
|
||||
### Slide 22: Volgende Les
|
||||
- Les 4: Effectief Prompting & Iteratief Werken
|
||||
- Huiswerk MOET af zijn!
|
||||
|
||||
---
|
||||
|
||||
## TIMING SUMMARY
|
||||
|
||||
| Blok | Onderdeel | Duur |
|
||||
|------|-----------|------|
|
||||
| 1 | Welkom & Mededeling | 10 min |
|
||||
| 2 | Installatie & Setup | 20 min |
|
||||
| 3 | Cursor Features | 15 min |
|
||||
| 4 | Skills, Rules & Requests | 15 min |
|
||||
| 5 | Live Demo | 15 min |
|
||||
| **PAUZE** | | **15 min** |
|
||||
| 6 | Hands-On | 75 min |
|
||||
| 7 | Afsluiting | 15 min |
|
||||
| **TOTAAL** | | **180 min** |
|
||||
@@ -1,561 +1,155 @@
|
||||
# Les 3: Cursor - AI-Powered Code Editor
|
||||
## Docenttekst (Spreektekst voor Tim)
|
||||
# Les 3 — Docenttekst (normaal)
|
||||
|
||||
> **Totale lesduur:** 3 uur (180 minuten)
|
||||
> **Totale spreektijd:** ~90 minuten (verdeeld over blokken)
|
||||
> **Hands-on praktijk:** ~75 minuten
|
||||
> **Pauze:** 15 minuten (10:15-10:30)
|
||||
**Fysieke les. Voor uitgebreide voorbereiding + context per blok.**
|
||||
**Voor letterlijk voorleesbaar script: zie `Les03-Docenttekst-Autocue.md`.**
|
||||
|
||||
---
|
||||
|
||||
## BLOK 1: WELKOM & MEDEDELING (10 min)
|
||||
## Lesvorm en flow
|
||||
|
||||
### Slide 1: Titelslide - Welkom Les 3, Cursor!
|
||||
**[09:00 - 09:02]**
|
||||
|
||||
"Goedemorgen iedereen, welkom bij Les 3! Vandaag gaan we kennismaken met Cursor, een code editor die echt gemaakt is voor developers. Dit is geen random AI tool – het is gebouwd VOOR programmeurs. In de vorige les hebben jullie gemerkt dat OpenCode wat problemen had: token limits, EACCES errors, en niet echt ontworpen voor professionele development. Cursor lost dat allemaal op. We gaan hem vandaag installeren, je eerste project bouwen, en je zult zien hoe snel je daarmee dingen kunt maken."
|
||||
|
||||
_[Glimlach, maak oogcontact. Stel de energie in voor een praktische, hands-on les.]_
|
||||
| Onderdeel | Indeling |
|
||||
|-----------|----------|
|
||||
| Theorie + demo | ±1,5 uur klassikaal |
|
||||
| Pauze | 15 minuten |
|
||||
| Hands-on | ±1,25 uur zelf bouwen met begeleiding |
|
||||
|
||||
---
|
||||
|
||||
### Slide 2: Planning vandaag
|
||||
**[09:02 - 09:05]**
|
||||
## Voorbereiding — een week vooraf
|
||||
|
||||
"Dit is de planning voor vandaag. We starten met een korte terugblik op waarom Cursor beter is dan OpenCode. Dan gaan we Cursor installeren en je account opzetten – dat gaat snel. Daarna laat ik alle features zien: Chat, Inline Edit, Composer, Tab Completion, en @mentions. We doen een interfacetour zodat je precies weet waar alles zit.
|
||||
**Studenten checklist (stuur via Slack):**
|
||||
- Laptop met admin-rechten (Cursor installatie vereist admin op Windows)
|
||||
- NOVI e-mailadres werkend
|
||||
- `node -v` werkt (versie 18 of hoger)
|
||||
- `git --version` werkt
|
||||
- Browser-bookmark voor `cursor.com/students` ergens klaarzetten
|
||||
|
||||
Vervolgens duiken we in het inrichten van Cursor Skills – dat is belangrijk, je gaat framework documentatie inladen zodat de AI beter kan helpen. We maken je eerste .cursorrules file, en ik leg uit hoe je request limit management moet denken.
|
||||
|
||||
Om 09:40 doen we een live demo: ik bouw in real-time een Next.js project van nul tot werkend. Dan krijgen jullie rond 10:00 een praktische opdracht. Jullie bouwen zelf een project, en we hebben een pauze van 10:15 tot 10:30. Na de pauze werken jullie verder, en we afsluiten met het delen van jullie resultaten, een samenvatting, en huiswerk."
|
||||
|
||||
_[Wijs naar timeline op slide. Ga niet te snel. Geef studenten een gevoel van progressie.]_
|
||||
**Jouw eigen voorbereiding:**
|
||||
- Test je eigen Cursor Pro Student status (om geen "ik vergat hem te activeren" te krijgen tijdens demo)
|
||||
- Test `npx create-next-app@latest` (cache kan blokkeren — `npm cache clean --force` als nodig)
|
||||
- Backup-project klaar met Hero al gebouwd voor het geval live demo vastloopt
|
||||
- `.cursorrules` snippet copy-paste klaar
|
||||
|
||||
---
|
||||
|
||||
### Slide 3: Terugblik Les 2 - Waarom Cursor beter is
|
||||
**[09:05 - 09:08]**
|
||||
## Voorbereiding — dag van de les
|
||||
|
||||
"Laten we even teruggaan naar Les 2 met OpenCode. Veel van jullie hebben vast gelopen tegen problemen, toch? Token limits die onverwacht opraken, EACCES permission errors als je externe packages wilde installeren, en eigenlijk voelde het meer als een AI chatbot dan als een echte code editor.
|
||||
**30 minuten vooraf:**
|
||||
- Cursor open in een lege folder voor de demo
|
||||
- Twee terminals klaar (één in `~/web`, één leeg)
|
||||
- Browser tabs: cursor.com/students, cursor.com/download, github.com (logged in)
|
||||
- Slides in fullscreen op presentatiescherm
|
||||
|
||||
Cursor is fundamenteel anders. Het is GEBOUWD voor developers. Cursor ziet je hele codebase tegelijk – Chat werkt niet op fragmenten, maar snapt je hele project. De AI completion (Tab completion) is ingebouwd en super snel. Bovendien: het Hobby plan is helemaal gratis, en studenten kunnen upgraden naar het Student plan, ook gratis, via cursor.com/students. Geen creditcard nodig.
|
||||
|
||||
En het allerbelangrijkste: Cursor heeft een INGEBOUWDE terminal. Je kunt node -v, npm install, en git commands rechtstreeks uitvoeren zonder naar een ander venster te hoppen. Alles gebeurt in één editor."
|
||||
|
||||
_[Maak oogcontact. Zeg duidelijk "gratis" – dat is een belangrijk voordeel.]_
|
||||
**Backup scenario:**
|
||||
- SheerID verificatie geeft soms 5–10 minuten vertraging → vertel studenten dit vooraf
|
||||
- `npx create-next-app` kan hangen → check cache of gebruik `bun create next-app` als alternatief
|
||||
- Internet traag in zaal → backup-project op standby
|
||||
|
||||
---
|
||||
|
||||
### Slide 4: Wat is Cursor? Features en pricing
|
||||
**[09:08 - 09:10]**
|
||||
## Per blok — wat je extra wilt zeggen
|
||||
|
||||
"Oké, wat IS Cursor precies? Het is eigenlijk VS Code – dezelfde editor die de helft van de wereld gebruikt – maar dan met krachtige AI features ingebouwd. Je krijgt vijf hoofdfeatures:
|
||||
### Blok 1 — Welkom + Wat is Cursor (slides 1–3)
|
||||
**Doel:** verwachtingen zetten, energie inschakelen.
|
||||
|
||||
**Eerste: Chat (Ctrl+L).** Je kunt vragen stellen over je code. De AI ziet je hele codebase en kan context begrijpen. Je kunt vragen 'Hoe werkt deze functie?' of 'Wat doet dit component?'. Wees specifiek in je vragen, dan krijg je betere antwoorden.
|
||||
Vraag vooraf: wie heeft GitHub Copilot wel eens gebruikt? Wie ChatGPT voor code? Dat is je startpunt — Cursor is dat, maar nauwer geïntegreerd in de editor zelf.
|
||||
|
||||
**Tweede: Inline Edit (Ctrl+K).** Je selecteert code, geeft een instructie zoals 'Zet dit om naar Tailwind classes', en de AI edit precies dat stukje. Super handig voor kleine aanpassingen.
|
||||
### Blok 2 — Student Plan + Installatie (slides 4–6)
|
||||
**Doel:** iedereen heeft Pro Student actief aan het eind van dit blok.
|
||||
|
||||
**Derde: Composer (Ctrl+I).** Dit is voor grotere taken. Je kunt zeggen 'Voeg een product pagina toe met filtering en cart functionaliteit', en de AI genereert meerdere files tegelijk. Echt krachtig.
|
||||
**Vooraf melden:** SheerID-verificatie kan 1–10 minuten duren. Geen reden om paniek te krijgen.
|
||||
|
||||
**Vierde: Tab Completion.** De AI voorspelt je code. Je begint te typen, en het suggereert wat je waarschijnlijk wilt. Je drukt Tab en klaar. Dit kost GEEN requests – het is gratis!
|
||||
**Common issue:** studenten met persoonlijk Gmail-adres in plaats van NOVI. Verificatie faalt → "log in met je NOVI-mail" — dat is non-negotiable.
|
||||
|
||||
**Vijfde: @mentions.** Je kunt context geven door @file, @folder, @web, en @docs te gebruiken. @docs is echt belangrijk: je kunt framework documentatie inladen, zodat de AI tegen de juiste versie van React of Next.js praat.
|
||||
**Voor wie technisch slim is:** Cursor heeft een settings.json zoals VS Code. Importeer de jouwe als je hem hebt. Maakt de transitie soepel.
|
||||
|
||||
Nu: pricing. Het Hobby plan is gratis en volstaat voor het meeste. Je krijgt beperkte requests – precies genoeg om te oefenen. Als je Student ben, kun je naar cursor.com/students gaan en upgraden naar Student, ook gratis, met veel meer requests."
|
||||
### Blok 3 — Skills/Docs + Eerste project (slides 7–9)
|
||||
**Doel:** student heeft `mijn-eerste-cursor-app` draaiend op localhost en open in Cursor.
|
||||
|
||||
_[Toon de vijf features op je vingers. Zeg "GRATIS" luidop voor Tab Completion – veel studenten snappen niet dat dit geen request kost.]_
|
||||
**Verwacht problemen:**
|
||||
- "I get a permission error" → npm prefix issue, gebruik nvm of corepack
|
||||
- "create-next-app duurt eeuwig" → cache + slecht internet, even geduld
|
||||
- "ik krijg geen Tailwind" → student kiest "no" bij Tailwind-prompt, opnieuw beginnen
|
||||
|
||||
Loop rond in dit blok — dit is waar studenten het meest vastlopen.
|
||||
|
||||
### Blok 4 — Drie sneltoetsen (slides 10–14)
|
||||
**Doel:** student kan Tab, Cmd+K en Cmd+L actief gebruiken.
|
||||
|
||||
**Voor elke sneltoets: doe een mini-live-demo.** Niet alleen praten — laat letterlijk zien wat er gebeurt. Studenten leren dit door te zien.
|
||||
|
||||
**Bij Tab:** typ een commentaar en wacht 2 seconden — Cursor stelt de hele functie voor. Dat is een wow-moment.
|
||||
|
||||
**Bij Cmd+K:** kies bewust iets simpels (zoals een variabele hernoemen) — niet iets complex dat 10 seconden duurt.
|
||||
|
||||
**Bij Cmd+L:** stel een vraag, niet meteen een grote taak. *"Hoe werkt useEffect?"* — laat Cursor antwoorden zien.
|
||||
|
||||
### Blok 5 — `.cursorrules` (slide 15)
|
||||
**Doel:** student weet wat het is + heeft één in zijn project.
|
||||
|
||||
**Vertel ook:** in Les 14 (veel later) gaan we naar `.cursor/rules/` (folder met meerdere bestanden). Voor nu is het oude format prima en simpeler om uit te leggen.
|
||||
|
||||
**Demo:** ik vraag Cursor in Cmd+L *"Maak een .cursorrules voor dit Next.js project"*. Laat de output zien, plak in `.cursorrules`-bestand, save.
|
||||
|
||||
### Blok 6 — Hands-on (slides 16–19)
|
||||
**Doel:** elke student heeft een werkende Hero gebouwd en één commit gedaan.
|
||||
|
||||
**Voor de pauze:** demonstreer taak 1 + 2. Niet meer.
|
||||
|
||||
**Na de pauze:** loop rond. Voor elke vraag, beantwoord met "wat zou je in Cursor zelf vragen?" — leer ze om de IDE te benutten.
|
||||
|
||||
**Verwacht vragen:**
|
||||
- "Mijn Hero ziet er saai uit" → vraag Cursor om een tweede iteratie via Cmd+K
|
||||
- "Tailwind classes werken niet" → check of `globals.css` `@tailwind base/components/utilities` heeft
|
||||
- "Git werkt niet" → check `gh auth login` of `git config user.email`
|
||||
|
||||
### Blok 7 — Afronding (slide 20)
|
||||
**Doel:** koppel vandaag aan de rest van de opleiding.
|
||||
|
||||
Maak expliciet: vandaag was de basis. Tab + Cmd+K + Cmd+L gaan jullie elke les terugzien. Les 4 gaat over TypeScript. Les 14 (veel later) gaat dieper op Cursor 3 features.
|
||||
|
||||
---
|
||||
|
||||
## BLOK 2: INSTALLATIE & SETUP (20 min)
|
||||
## Veelvoorkomende vragen + antwoorden
|
||||
|
||||
### Slide 5: Download en installatie
|
||||
**[09:10 - 09:14]**
|
||||
**"Werkt Cursor op Linux?"**
|
||||
Ja — AppImage download via cursor.com.
|
||||
|
||||
"Goed, laten we beginnen met installatie. Je gaat naar cursor.com en klikt op Download. Cursor draait op Mac, Windows, en Linux – dus voor iedereen. De installer is heel eenvoudig: je downloadt het, opent het, sleep je Cursor naar je Applications folder, en klaar. Als je op Windows bent, run je de .exe en volg je de stappen.
|
||||
**"Wat als ik geen Pro Student krijg?"**
|
||||
Stuur student naar support@cursor.com met NOVI mail + bewijs van inschrijving. Werkt meestal binnen 24 uur.
|
||||
|
||||
Dit kost ongeveer twee minuten. Als je al VS Code hebt, hoef je niks te desinstalleren – Cursor en VS Code kunnen naast elkaar bestaan zonder problemen."
|
||||
**"Mag ik mijn eigen OpenAI/Anthropic key gebruiken?"**
|
||||
Ja — Settings → Models → eigen key plakken. Soms goedkoper bij weinig gebruik, niet nodig met Pro Student.
|
||||
|
||||
_[Navigeer naar cursor.com en wijs de download knop aan. Laat zien hoe het eruit ziet op Mac en Windows (screenshot).]_
|
||||
**"Wat is het verschil tussen Cmd+K en Cmd+L?"**
|
||||
Cmd+K = inline edit op selectie (één bestand, één gericht ding). Cmd+L = chat (uitleg vragen of grotere taak met meerdere bestanden).
|
||||
|
||||
**"Wordt mijn code naar OpenAI/Anthropic gestuurd?"**
|
||||
Standaard: ja, voor inference. Cursor heeft een Privacy Mode in Settings — als die aan staat, wordt code niet bewaard. Geen training op je code.
|
||||
|
||||
**"Wat als ik door 500 requests heen ben?"**
|
||||
Wacht op nieuwe maand (reset op de 1e), of upgrade naar betaalde tier ($20/maand), of plug je eigen API-key in.
|
||||
|
||||
**"Kan ik blijven coden zonder internet?"**
|
||||
Tab + lokale modellen via Settings, ja. Cmd+K en Cmd+L vereisen internet.
|
||||
|
||||
---
|
||||
|
||||
### Slide 6: Account aanmaken en upgraden
|
||||
**[09:14 - 09:18]**
|
||||
## Foutmodi tijdens de les
|
||||
|
||||
"Zodra Cursor open is, maak je een account aan. Je hoeft NIET direct Student plan te nemen – begin met Hobby. Je geeft je emailadres en een wachtwoord in. Cursor stuurt je een bevestigingsmail.
|
||||
|
||||
BELANGRIJK: als je Student bent, upgrade je NA deze eerste setup. Je gaat naar cursor.com/students, logt in met diezelfde email, en kiest Student plan. Geen creditcard, geen gedoe – je werkt gewoon mee met onze les en je bent gedekt.
|
||||
|
||||
Na login zie je je Hobby account. Dan gaan we gelijk verder met setup."
|
||||
|
||||
_[Toon account maken op je eigen machine. Zeg duidelijk: "Hobby EERST, Student plan LATER". CHECKPOINT: check rond of iedereen ingelogd is.]_
|
||||
| Probleem | Snelle fix |
|
||||
|----------|-----------|
|
||||
| SheerID hangt | Volgende student helpen, terugkomen na 10 min |
|
||||
| `npx create-next-app` hangt | `npm cache clean --force` of `bun create next-app` |
|
||||
| Cursor niet ingelogd na herstart | Settings → Account → opnieuw inloggen |
|
||||
| Tab-completion verschijnt niet | Settings → Features → Cursor Tab → check enabled |
|
||||
| Cmd+L opent niet | Mogelijk Notion of andere app vangt sneltoets — check System Preferences |
|
||||
| `.cursorrules` lijkt genegeerd | File moet in project-root staan, niet in src/ — herstart Cursor |
|
||||
|
||||
---
|
||||
|
||||
### Slide 7: Interface tour
|
||||
**[09:18 - 09:22]**
|
||||
## Vooruitblik Les 4
|
||||
|
||||
"Oké, je bent ingelogd. Laten we de interface doornemen zodat je weet waar alles zit.
|
||||
Volgende les: TypeScript Fundamentals. Strict types, generics, utility types. Studenten gaan ze toepassen in hun Next.js project. Geen extra installatie nodig — Next.js scaffold zit al met TS.
|
||||
|
||||
Links zie je de **Activity Bar** – kleine iconen voor Files, Search, Source Control, en Run & Debug. Dit is hetzelfde als VS Code.
|
||||
|
||||
Daaronder zie je de **Sidebar** – dit is waar je bestanden staan als je Files opent.
|
||||
|
||||
In het midden: de **Editor**. Dit is waar je code schrijft en bewerkt.
|
||||
|
||||
Aan de rechterkant – en dit is NIEUW vergeleken met normale VS Code – de **Chat Panel**. Dit open je met Ctrl+L. Hier stel je vragen over je code.
|
||||
|
||||
Onder de editor zie je de **Terminal** – Ctrl+backtick, dus Ctrl+` – hier voer je commands uit.
|
||||
|
||||
Het mooie is: ALLES zit in één window. Je hoeft niet tussen VS Code en ChatGPT heen en weer te springen."
|
||||
|
||||
_[Beweeg je cursor rond op de interface. Duid elke component aan. Open de Chat Panel met Ctrl+L, sluit het weer met Escape.]_
|
||||
|
||||
---
|
||||
|
||||
### Slide 8: Terminal setup check SAMEN
|
||||
**[09:22 - 09:30]**
|
||||
|
||||
"Nu gaan we even checken of je setup klaar is. Dit doen we via de Terminal. Open Terminal met Ctrl+backtick – dus Ctrl+`.
|
||||
|
||||
Je ziet prompt. We gaan drie commands checken:
|
||||
|
||||
**Eerste: node -v** – dit geeft je Node.js versie. Je wilt versie 18 of hoger. Als je error ziet 'command not found', moet je Node.js installeren via nodejs.org.
|
||||
|
||||
**Tweede: git --version** – dit geeft je Git versie. Versie 2.20 of hoger is prima.
|
||||
|
||||
**Derde: npm -v** – dit is de Package Manager die met Node.js komt. Ook 7.0 of hoger.
|
||||
|
||||
**Vierde: npx -v** – dit is ESSENTIEEL. npx gebruiken we straks om create-next-app te draaien. Als npx niet werkt, kun je geen nieuw project aanmaken. npx komt normaal mee met npm, dus als npm werkt, werkt npx ook. Maar even checken!
|
||||
|
||||
Wie errors ziet, geen paniek. Steek je hand op, ik help je. Dit duurt twee minuten per persoon."
|
||||
|
||||
_[Open je eigen Terminal. Typ de vier commands. Laat zien wat output eruitziet. Sta twee minuten stil en help studenten die problemen hebben.]_
|
||||
|
||||
_[CHECKPOINT: zorg dat iedereen node, git, npm EN npx werkend heeft. Dit is essentieel voor de rest van de les.]_
|
||||
|
||||
---
|
||||
|
||||
## BLOK 3: CURSOR FEATURES (15 min)
|
||||
|
||||
### Slide 9: Chat Panel - Vragen over je code
|
||||
**[09:30 - 09:36]**
|
||||
|
||||
"Nu duiken we in de échte kracht van Cursor: de Features. Laten we beginnen met **Chat Panel**.
|
||||
|
||||
Je opent Chat met Ctrl+L. Ik open het nu even op mijn scherm. Je ziet een textbox waar je kunt typen. Het bijzondere: Cursor ziet je HELE project, niet gewoon het stukje code dat je hebt geselect.
|
||||
|
||||
Stel je voor: je hebt een Next.js project met 15 componenten. Je kunt in Chat vragen: 'Hoe werkt de authentication flow in dit project?' en de AI snapt je hele setup en geeft een ingewikkeld antwoord.
|
||||
|
||||
**Tips voor goede Chat vragen:**
|
||||
- Wees specifiek. Zeg niet 'Fix dit' maar 'Zet alle inline styles om naar Tailwind classes en zorg dat de layout hetzelfde blijft.'
|
||||
- Geef context. 'In de ProductCard component, de border is nu blauw, kan hij rood zijn en dikker?'
|
||||
- Stel vervolgvragen. De AI onthoudt wat je eerder vroeg.
|
||||
|
||||
Chat kost één request per bericht. Hop voorzichtig – je hebt beperkte requests op Hobby."
|
||||
|
||||
_[Open Chat (Ctrl+L). Typ een voorbeeld vraag. Laat zien hoe antwoord zich opent.]_
|
||||
|
||||
---
|
||||
|
||||
### Slide 10: Inline Edit - Snelle code changes
|
||||
**[09:36 - 09:41]**
|
||||
|
||||
"Volgende feature: **Inline Edit (Ctrl+K)**. Dit is voor als je kleine stukken wilt aanpassen.
|
||||
|
||||
Stel je voor: je hebt een component met inline styles – die lelijke style={{color: 'red', marginTop: '10px'}}. Je wilt dit naar Tailwind. Je selecteert die hele component code, drukt Ctrl+K, en je typt: 'Zet alle inline styles om naar Tailwind classes, keep the same styling.'
|
||||
|
||||
Cursor selecteert precies dat stukje, geeft een preview, en je ziet de diff. Je kunt dan een diff accepteren of afwijzen. Super handig voor refactoring.
|
||||
|
||||
**Voorbeeld in mijn hoofd:**
|
||||
Input: Component met inline styles
|
||||
Instructie: 'Convert to Tailwind'
|
||||
Output: Dezelfde component, maar nu className='text-red-600 mt-2.5'
|
||||
|
||||
Dit kost ook één request. Gebruik het voor kleine, chirurgische aanpassingen."
|
||||
|
||||
_[Maak een voorbeeld component met inline styles. Demonstreer Ctrl+K en de AI vervanging.]_
|
||||
|
||||
---
|
||||
|
||||
### Slide 11: Composer - Multi-file grote taken
|
||||
**[09:41 - 09:46]**
|
||||
|
||||
"Nu het heavyweight: **Composer (Ctrl+I)**. Dit is voor als je GROTE dingen wilt doen – dingen die meerdere files raken.
|
||||
|
||||
Stel je voor: je hebt een Next.js app met één pagina. Je wilt een heel nieuwe feature: een Admin Dashboard met login, user list, en stats panel. Dit raakt misschien 5 bestanden: nieuwe route, nieuwe component, styles, database queries, alles.
|
||||
|
||||
In plaats van dit in stukken te vragen in Chat, openen je Composer met Ctrl+I. Je zegt: 'Voeg een Admin Dashboard toe met login, user management, en stats. Zet het op /admin route.'
|
||||
|
||||
Composer genereert ALLES tegelijk – alle files, alle imports, alle routing. Je ziet een preview, klikt 'Accept', en BOEM – je project heeft een werkende admin dashboard.
|
||||
|
||||
Dit is échte time-saver. En ja, dit kost ook één request – niet meer, niet minder, want Cursor snapt dat je één logische taak doet."
|
||||
|
||||
_[Open je eigen project. Open Composer (Ctrl+I). Laat zien hoe je een multi-file taak kunt beschrijven.]_
|
||||
|
||||
---
|
||||
|
||||
### Slide 12: Tab Completion - AI code voorspelling
|
||||
**[09:46 - 09:50]**
|
||||
|
||||
"Feature vier: **Tab Completion**. Dit is mijn favoriet. En het BELANGRIJKSTE: dit kost GEEN requests. Nul. Gratis.
|
||||
|
||||
Je begint gewoon code te typen. Terwijl je typt, ziet Cursor wat je waarschijnlijk wilt doen. Je typt:
|
||||
|
||||
```javascript
|
||||
const handleClick = () => {
|
||||
```
|
||||
|
||||
En Cursor suggereert al wat je waarschijnlijk volgende doet. Je drukt Tab en het wordt aanvaard. Je typt verder, Tab, verder, Tab. Dit gaat super snel.
|
||||
|
||||
**Waarom is dit gratis?** Omdat Tab Completion niet intensief is voor Cursor – het is lokale voorspelling, niet een volledige AI analyse. Dus gebruik dit VEEL! Dit moet je reflexmatig doen.
|
||||
|
||||
**Tip:** als je een suggestion ziet die je niet wilt, druk je gewoon Escape of tik je wat anders. Geen probleem.
|
||||
|
||||
Dit is echt de feature waar je sneller in je code wordt als je het goed gebruikt."
|
||||
|
||||
_[Demonstreer Tab Completion in je editor. Typ langzaam zodat Cursor suggestions toont. Druk Tab en laat zien hoe snel dit gaat.]_
|
||||
|
||||
---
|
||||
|
||||
### Slide 13: @mentions - Context voor je vragen
|
||||
**[09:50 - 09:55]**
|
||||
|
||||
"Laatste feature: **@mentions**. Dit is hoe je de AI context geeft.
|
||||
|
||||
Je kent het van Slack en Discord: als je @iemand typt, tag je ze. In Cursor Chat doe je iets soortgelijks.
|
||||
|
||||
Je kunt typen:
|
||||
- **@file** – je verwijst naar een specifiek bestand. Voorbeeld: '@pages/api/auth.js write a logout endpoint'
|
||||
- **@folder** – je verwijst naar een hele folder. Voorbeeld: '@components analyze this folder and tell me architecture'
|
||||
- **@web** – de AI zoekt het web op. Voorbeeld: 'how do I connect to @web stripe payment gateway?'
|
||||
- **@docs** – DIT IS HEEL BELANGRIJK – je verwijst naar framework documentatie. Voorbeeld: '@docs latest react patterns for state management'
|
||||
|
||||
@docs is een game changer. Als je @docs docs react typen, zal de AI antwoorden tegen de officieële React documentatie, niet tegen oude tutorials. Dit voorkomt dat je advice krijgt van 2019.
|
||||
|
||||
We gaan straks je Skills opzetten, en daar laad je @docs in. Ongelofelijk powerful."
|
||||
|
||||
_[Typ in Chat: '@docs how do I use hooks?' Laat zien dat niks gebeurt totdat Skills ingesteld zijn – dat doen we volgende slide.]_
|
||||
|
||||
---
|
||||
|
||||
## BLOK 4: SKILLS, RULES & REQUESTS (15 min)
|
||||
|
||||
### Slide 14: Cursor Skills - Framework documentatie inladen
|
||||
**[09:55 - 10:05]**
|
||||
|
||||
"Oké, volgende stap. Ik zei net dat @docs belangrijk is. Daarvoor moeten we eerst je **Cursor Skills** instellen. Dit is hoe je documentatie inlaadt zodat de AI weet tegen welke versies het praat.
|
||||
|
||||
We doen dit SAMEN, dus volg mee op je eigen machine.
|
||||
|
||||
**Stap 1:** Ga naar Settings. Op Mac: Cmd+, (command komma). Op Windows: Ctrl+, (control komma). De Settings paneel opent.
|
||||
|
||||
**Stap 2:** Je zoekt naar 'Features' en je klikt op Features.
|
||||
|
||||
**Stap 3:** Je zoekt naar 'Docs' – je ziet 'Cursor Docs' instelling. Daar klikt je op.
|
||||
|
||||
**Stap 4:** Je ziet een + knop. Je klikt erop. Nu kun je documentatie toevoegen. Dit zijn de drie die ik aanraad:
|
||||
|
||||
- **Next.js:** je gaat naar nextjs.org/docs en je pakt die URL. Voeg toe.
|
||||
- **React:** react.dev is de officieële React docs. Voeg toe.
|
||||
- **Tailwind CSS:** tailwindcss.com/docs. Voeg toe.
|
||||
|
||||
Na toevoegen kun je in Chat @docs gebruiken en de AI leest tegen jouw documentatie. Test het: type in Chat '@docs what is the latest way to do routing in next.js?' en je krijgt antwoord uit de officieële Next.js documentatie, niet uit random StackOverflow.
|
||||
|
||||
Dit is echt belangrijk voor professioneel werken."
|
||||
|
||||
_[DOEN, niet demo. Zorg dat iedereen dit meegedaan heeft. Help met technische vragen. CHECKPOINT: vraag "Iedereen Skills ingesteld?" en wacht op bevestiging.]_
|
||||
|
||||
---
|
||||
|
||||
### Slide 15: .cursorrules - Jouw AI richtlijnen
|
||||
**[10:05 - 10:12]**
|
||||
|
||||
"Nu gaan we een .cursorrules bestand maken. Dit is NIET handmatig geschreven – Cursor genereert dit voor je.
|
||||
|
||||
Een .cursorrules file is een bestand in de root van je project waarin je aan Cursor zegt: 'Hey, als je met mijn code werkt, volg deze richtlijnen.'
|
||||
|
||||
Voorbeeld richtlijnen:
|
||||
- 'Alle componenten moeten TypeScript hebben type annotations'
|
||||
- 'Gebruik Tailwind, geen CSS modules'
|
||||
- 'Nederlandse comments in de code'
|
||||
- 'Altijd error handling toevoegen'
|
||||
|
||||
Dit is SUPER handig omdat je je preferences maar één keer ingesteld hebt, en dan volgt de AI altijd.
|
||||
|
||||
**Hoe maak je het?** Heel makkelijk:
|
||||
|
||||
**Stap 1:** Je opent Chat (Ctrl+L).
|
||||
|
||||
**Stap 2:** Je plakt deze prompt:
|
||||
|
||||
'Genereer een .cursorrules bestand voor een Next.js + Tailwind CSS + TypeScript project. Include richtlijnen voor: code style, components best practices, error handling, en Nederlandse comments. Output het volledige bestand klaar om te kopieën.'
|
||||
|
||||
**Stap 3:** Cursor genereert een complete .cursorrules file. Je kopieert dit.
|
||||
|
||||
**Stap 4:** In je project maak je een nieuw bestand genaamd `.cursorrules` in de root folder. Je plakt de content en je saved.
|
||||
|
||||
**Klaar!** Dát is één request, en nu volgt Cursor altijd jouw rules.
|
||||
|
||||
Dit is echt tijd besparen. Je zegt nooit meer 'gebruik TypeScript' – dat weet Cursor al."
|
||||
|
||||
_[Open Chat. Paste je eigen .cursorrules prompt (aanwezig op je machine). Laat zien hoe output eruitziet. Demonstreer kopieën naar nieuw bestand.]_
|
||||
|
||||
---
|
||||
|
||||
### Slide 16: Request management - Budget uitzetten
|
||||
**[10:12 - 10:20]**
|
||||
|
||||
"Oké, de grote vraag: requests. Op Hobby heb je BEPERKT aantal requests. Je wilt ze slim gebruiken.
|
||||
|
||||
**Hier is de breakdown:**
|
||||
- **Tab Completion:** GRATIS. Ongelimiteerd. Gebruik dit voor kleine dingen.
|
||||
- **Chat:** 1 request per bericht. Wees voorzichtig.
|
||||
- **Inline Edit:** 1 request. Snel maar denk je in voor je tikt.
|
||||
- **Composer:** 1 request, ongeacht hoe groot. Dit is eigenlijk heel voordelig voor grote dingen.
|
||||
|
||||
**Budget tips:**
|
||||
|
||||
**Eén: Denk eerst, prompt daarna.** Voordat je iets vraagt, bepaal je wat je PRECIES wilt. Maak een kopje koffie, bedenk je vraag, tik dan. Dit voorkomt vijf mislukte requests.
|
||||
|
||||
**Twee: Combineer taken.** In plaats van drie aparte Chat vragen, maak je één grote vraag. Zeg alles in één bericht.
|
||||
|
||||
**Drie: Gebruik Tab Completion voor kleine dingen.** Import statements, losse variabelen, functies. Dit bespaart requests.
|
||||
|
||||
**Vier: Composer voor grote refactors.** Als je iets aan meerdere files moet doen, doe je het in Composer, niet in aparte Chat vragen.
|
||||
|
||||
**Vijf: @mentions voor efficiency.** @docs helpt je beter vragen stellen, minder 'wat is het beste patroon' vragen.
|
||||
|
||||
Op Hobby krijg je genoeg om deze hele les te doen en meer. Maar als je gaat echt projecten bouwen, upgrade je naar Student. Dan heb je veel meer."
|
||||
|
||||
_[Toon scherm met request counter. Leg uit waar je request status ziet (rechtsboven in Cursor).]_
|
||||
|
||||
---
|
||||
|
||||
## BLOK 5: LIVE DEMO (15 min)
|
||||
|
||||
### Slide 17: Live Demo - Van nul naar werkende website
|
||||
**[10:20 - 10:35]**
|
||||
|
||||
"Oké, genoeg theorie. Ik bouw nu in real-time een werkende Next.js website. Dit doet twee dingen: één, je ziet hoe snel dit echt gaat, en twee, je ziet de volledige workflow die je straks zelf doet.
|
||||
|
||||
**Stap 1: Project setup**
|
||||
```bash
|
||||
mkdir my-demo-site
|
||||
cd my-demo-site
|
||||
git init
|
||||
```
|
||||
|
||||
Ik heb een folder, git aan. Cursor openen.
|
||||
|
||||
**Stap 2: Next.js project**
|
||||
```bash
|
||||
npx create-next-app@latest . --typescript --tailwind --app
|
||||
```
|
||||
|
||||
Ik zeg Yes op TypeScript, Yes op Tailwind, Yes op App Router. Dit duurt ongeveer een minuut.
|
||||
|
||||
**Stap 3: Dev server**
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Nu draait http://localhost:3000 met de default Next.js pagina.
|
||||
|
||||
**Stap 4: .cursorrules via Chat**
|
||||
Ctrl+L. Ik paste mijn prompt. Één request. Copy. Make file `.cursorrules`. Done.
|
||||
|
||||
**Stap 5: HeroSection via Composer**
|
||||
Ctrl+I. 'Create a Hero section component in app/components/HeroSection.tsx with a headline, subheading, and a Call-to-Action button. Use Tailwind classes. Make it look modern.'
|
||||
|
||||
Cursor genereert de hele component. Één request. Ik accepteer.
|
||||
|
||||
**Stap 6: Integrate in page**
|
||||
Ik open app/page.tsx. Voeg import HeroSection. Zet het in HTML. Refresh browser. BOOM. Werkende website, mooi design.
|
||||
|
||||
**Stap 7: Git commit**
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "Initial setup with HeroSection"
|
||||
```
|
||||
|
||||
**Totaal:** Ik gebruikte 2 requests (één voor .cursorrules, één voor HeroSection). Tab Completion hielp met imports en minor edits. Van nul naar werkende website in 15 minuten. Dat kan jij straks ook."
|
||||
|
||||
_[ECHTE DEMO, niet gerendeert. Wys elke stap live. Stop niet totdat npm run dev werkt en browser toont mooi design. Timing is belangrijk – studenten moeten zien dat dit ECHT snel gaat.]_
|
||||
|
||||
---
|
||||
|
||||
## BLOK 6: HANDS-ON PRAKTIJK (75 min + 15 min pauze)
|
||||
|
||||
### Slide 18: Hands-on opdracht - Studenten bouwen eigen project
|
||||
**[10:35 - 10:50] (+ pauze 10:15-10:30, dan verder tot 11:30]**
|
||||
|
||||
"Jullie beurt. Hier is wat je gaat doen. Dit is dezelfde workflow als mijn demo, maar je doet het zelf.
|
||||
|
||||
**Opdracht:** Bouw een NIEUW project. Mag elk onderwerp zijn – portfolio site, blog, product showcase, whatever. Belangrijkste: je volgt deze stappen:
|
||||
|
||||
**Stap 1: Project initialize**
|
||||
```bash
|
||||
mkdir my-awesome-project
|
||||
cd my-awesome-project
|
||||
git init
|
||||
```
|
||||
|
||||
**Stap 2: Next.js setup**
|
||||
```bash
|
||||
npx create-next-app@latest . --typescript --tailwind --app
|
||||
```
|
||||
TypeScript = Yes, Tailwind = Yes, App Router = Yes.
|
||||
|
||||
**Stap 3: Cursor Skills check**
|
||||
Zorg dat je Next.js, React, en Tailwind documentatie ingeladen hebt. Test @docs.
|
||||
|
||||
**Stap 4: .cursorrules genereren**
|
||||
Chat, één prompt, één request. Kopieën naar bestand.
|
||||
|
||||
**Stap 5: Componenten bouwen**
|
||||
Gebruik Composer (Ctrl+I) om componenten te genereren:
|
||||
- HeroSection (headline, subheading, CTA)
|
||||
- FeatureCards (3-4 feature cards met iconen en beschrijvingen)
|
||||
- TestimonialSection (3 testimonials)
|
||||
- Footer
|
||||
|
||||
Elke Composer request = één component.
|
||||
|
||||
**Stap 6: Integreren in main page**
|
||||
Import alle componenten in app/page.tsx. npm run dev. Check dat alles looks good.
|
||||
|
||||
**Stap 7: Git commit**
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "Complete project setup with all components"
|
||||
```
|
||||
|
||||
**Timing:**
|
||||
- Nu tot 10:15: je begint. Ik loop rond, ik help met problemen.
|
||||
- 10:15-10:30: PAUZE. Stretch, koffie, toilet.
|
||||
- 10:30-11:15: jullie bouwen verder. Meer componenten, refinement, styling tweaks. Ik help.
|
||||
|
||||
**Checks tussendoor:**
|
||||
- Is npm run dev werkend?
|
||||
- Hoe veel requests heb je gebruikt?
|
||||
- Zit je stuck? Vraag me.
|
||||
|
||||
**Let op:** dit is HANDS-ON. Je moet dit zelf doen, niet copy-paste van mij. De waarde zit in het leren van de workflow."
|
||||
|
||||
_[Zet timer op. Check na 10 minuten wie klaar is met setup. Help trackers. Zorg dat iedereen minstens HeroSection werkend heeft voor de pauze.]_
|
||||
|
||||
_[Na pauze: motiveer studenten, help met volgende componenten, praise progress.]_
|
||||
|
||||
---
|
||||
|
||||
## BLOK 7: AFSLUITING (15 min)
|
||||
|
||||
### Slide 19: Resultaten delen
|
||||
**[11:15 - 11:25]**
|
||||
|
||||
"Goed werk iedereen! Nu gaan we een paar resultaten delen. Ik wil 3-4 van jullie zien wat je hebt gebouwd.
|
||||
|
||||
[Roep studenten op om hun project op scherm te delen. Laat hun website zien. Zeg wat je goed vindt – 'Leuke kleuren!' of 'Mooie layout, hoe heb je die FeatureCards gedaan?' Geef high-fives digitaal of letterlijk.]
|
||||
|
||||
Dit is echt professioneel werk. En je hebt dit in anderhalf uur gebouwd. Besef je dat? Met OpenCode zou dit twee keer zo lang geduurd hebben."
|
||||
|
||||
_[Echt naar mensen luisteren. 3-4 korte demo's, niet lang. Maak het positief.]_
|
||||
|
||||
---
|
||||
|
||||
### Slide 20: Samenvatting - De les in vijf punten
|
||||
**[11:25 - 11:35]**
|
||||
|
||||
"Laten we samenvatten wat je vandaag geleerd hebt.
|
||||
|
||||
**Eén: Setup.** Je kunt Cursor installeren, een account maken, Skills configureren. Dit is standaard, je doet dit nu automatisch.
|
||||
|
||||
**Twee: AI Features.** Je kent Chat, Inline Edit, Composer, Tab Completion, @mentions. Elke feature heeft een use case. Chat voor vragen, Composer voor grote dingen, Tab Completion voor snelheid.
|
||||
|
||||
**Drie: Workflow.** Initialize project, create Next.js app, .cursorrules, build components, integrate, commit. Dit is de bouwsteen voor alle projecten voortaan.
|
||||
|
||||
**Vier: Request Management.** Je weet dat je beperkt hebt, je plant je requests, je combineert taken. Je denkt, daarna prompt.
|
||||
|
||||
**Vijf: Speed.** Je bouwde een website in anderhalf uur. Dat gaat niet slimmer worden – dat is de norm voortaan.
|
||||
|
||||
Dit zijn de fundamentals. Volgende les gaan we dieper: effectief prompting, hoe je betere vragen stelt, hoe je iteratief werkt met de AI. Dat is waar de echte magie gebeurt."
|
||||
|
||||
_[Zeg duidelijk, maak oogcontact. Dit is de afsluiting.]_
|
||||
|
||||
---
|
||||
|
||||
### Slide 21: Huiswerk - DEBUG CHALLENGE
|
||||
**[11:35 - 11:40]**
|
||||
|
||||
"Huiswerk. Dit is een DEBUG CHALLENGE. Je gaat een zip bestand krijgen via Teams. Die zip bevat een half-gebouwde Next.js project – EXPRES met fouten.
|
||||
|
||||
**Wat zit erin:**
|
||||
- Missende dependencies (package.json incomplete)
|
||||
- Syntax errors (typos in components)
|
||||
- Inline styles die naar Tailwind moeten
|
||||
- Import statements die broken zijn
|
||||
- Misschien een API route die niet werkt
|
||||
|
||||
**Je taak:**
|
||||
1. Download de zip
|
||||
2. Extract em
|
||||
3. Open in Cursor
|
||||
4. USE Cursor om ALLE fouten te fixen. Niet handmatig repareren – dat is het punt niet. Gebruik Chat, Inline Edit, Composer. Leer hoe je de AI gebruikt om bugs op te spotten en te fixen.
|
||||
5. Als alles werkend is: npm run dev moet geen errors geven
|
||||
6. Push naar je GitHub
|
||||
|
||||
**Due:** volgende les. Zorg dat je een werkend project hebt en een GitHub link.
|
||||
|
||||
Dit is echt oefenen. Debugging met AI is een skill. Je leert het nu."
|
||||
|
||||
_[Upload de zip naar Teams. Zeg de naam van het bestand luid.]_
|
||||
|
||||
---
|
||||
|
||||
### Slide 22: Volgende les preview
|
||||
**[11:40 - 11:45]**
|
||||
|
||||
"Volgende les: **Effectief Prompting & Iteratief Werken**. We gaan dieper.
|
||||
|
||||
Vandaag maakte je basale prompts. Volgende keer leren we:
|
||||
- Prompt engineering: hoe je vragen stelt zodat de AI beter begrijpt wat je wilt
|
||||
- Iteratie: hoe je feedback geeft en verbeteringen doet, stap voor stap
|
||||
- Context building: hoe je de AI steeds meer context geeft voor betere resultaten
|
||||
- Real-world scenarios: fixing bugs, refactoring code, building complex features
|
||||
|
||||
Dit is waar development met AI echt wordt. Prompting is een skill, net als typen of debuggen. We gaan het trainen.
|
||||
|
||||
Tot volgende week!"
|
||||
|
||||
_[Smile. Dit is motiverend. Zeg "Goed gedaan vandaag" en bedank iedereen voor de aandacht.]_
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
## TIMING OVERVIEW
|
||||
|
||||
| Blok | Slides | Duratie | Totaal (min) |
|
||||
|------|--------|---------|------|
|
||||
| **BLOK 1: Welkom & Mededeling** | 1-4 | 10 min | 0-10 |
|
||||
| **BLOK 2: Installatie & Setup** | 5-8 | 20 min | 10-30 |
|
||||
| **BLOK 3: Cursor Features** | 9-13 | 15 min | 30-45 |
|
||||
| **BLOK 4: Skills, Rules & Requests** | 14-16 | 15 min | 45-60 |
|
||||
| **BLOK 5: Live Demo** | 17 | 15 min | 60-75 |
|
||||
| **BLOK 6: Hands-on (incl. pauze)** | 18 | 75 min + 15 min pauze | 75-165 |
|
||||
| | | Pauze: 10:15-10:30 | |
|
||||
| **BLOK 7: Afsluiting** | 19-22 | 10 min | 165-175 |
|
||||
| **TOTAAL** | 22 | **175 minuten (2h 55min)** | |
|
||||
|
||||
---
|
||||
|
||||
## EXTRA NOTES VOOR TIM
|
||||
|
||||
- **Checkpoints:** Slide 6, 8, 14 – zorg dat iedereen op dezelfde plek is voor je verdergaat
|
||||
- **Problemen:** Bij terminal setup kan het 5 minuten extra kosten. Plan dit in.
|
||||
- **Live demo timing:** dit duurt 15 minuten ECHT. Niet sneller – studenten moeten het zien gebeuren.
|
||||
- **Hands-on pauze:** 10:15-10:30 is VAST. Studenten hebben dit nodig.
|
||||
- **Request usage:** controleer rond 10:45 dat niemand meer dan 5 requests gebruikt heeft. Anders raken ze op.
|
||||
- **Debugging hw:** zip bestand moet express simple bugs hebben (missing import, extra comma, inline style). Niet complex.
|
||||
- **Energy:** rond minuut 120 zakt energie. Zet muziek op pauze, trek grappen, keep it real.
|
||||
Stuur de avond ervoor een Slack-bericht: "voor les 4: zorg dat je Cursor Pro Student actief hebt, anders sta je achter".
|
||||
|
||||
149
Les03-Cursor-Basics/Les03-Docenttekst.pdf
Normal file
149
Les03-Cursor-Basics/Les03-Docenttekst.pdf
Normal file
@@ -0,0 +1,149 @@
|
||||
%PDF-1.4
|
||||
%<25><><EFBFBD><EFBFBD> ReportLab Generated PDF document (opensource)
|
||||
1 0 obj
|
||||
<<
|
||||
/F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 6 0 R /F5 7 0 R
|
||||
>>
|
||||
endobj
|
||||
2 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
3 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
4 0 obj
|
||||
<<
|
||||
/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
5 0 obj
|
||||
<<
|
||||
/Contents 14 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 13 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/BaseFont /Symbol /Name /F4 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica-Oblique /Encoding /WinAnsiEncoding /Name /F5 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
8 0 obj
|
||||
<<
|
||||
/Contents 15 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 13 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
9 0 obj
|
||||
<<
|
||||
/Contents 16 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 13 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
10 0 obj
|
||||
<<
|
||||
/Contents 17 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 13 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
11 0 obj
|
||||
<<
|
||||
/PageMode /UseNone /Pages 13 0 R /Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
12 0 obj
|
||||
<<
|
||||
/Author (NOVI Hogeschool Utrecht) /CreationDate (D:20260615075148+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260615075148+00'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Subject (\(unspecified\)) /Title (Les 3 Docenttekst) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
13 0 obj
|
||||
<<
|
||||
/Count 4 /Kids [ 5 0 R 8 0 R 9 0 R 10 0 R ] /Type /Pages
|
||||
>>
|
||||
endobj
|
||||
14 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1720
|
||||
>>
|
||||
stream
|
||||
Gb!;c99[go&AIV:ki-,\,s6L3;aM)u'GX0i74u<5V7%pjUesUE%=?07:QHcJrUu[*/m.S[/,/\rS*mJl)%>cKg>>a;n7i(Z?8Gt)N2FB1dt,nnpgnR=f+%$l4j3Ia.qIRBSf,%*LX+;fVWCspj+:tM6T_Zj$uPqH._-^nCi.1E;,/Gh@"C4E[0?j(YlYlaQK?$11;]cg0ro%+%go:VcGfSC;]*bfoM#/Q41u.!j+YA[J$t;N><.D4D7-g-g9t_gh^X2nlRu7q)1oZHKMPJqB[SrXM8D)==O;[,lM#"T^iP<B;<-gX8lRJV1,E//>3&l;"6^i.C^jR5!\#fLdWsDY'St:mEs5R>d^">4MK*U-i_"d8;Etd&D.<Ygj2\$_;1iI%mi!u(JX.CF[c=n:Xht4#[2/NJY'3/J$!=uBaQ6:f>d$*Sg;2g.(N_;%^^6AG"CV97=]>[UB;AJ@H4f$q,[uM2(O.k)rp:4V_-+JDoTVmN9rhLG2:^:+#%/JT6]KaV6P6)N&]Fr4)fh8)RA&Yo/+L(o/gqGnUkc)9as_o3\4tRnQ&K<''kQ*?LbY6/%/4DSQH.X[$VdB='>1?nN6:b]=V'_VoV%>Y\]6N&HVrolSeb%[`A*ol/,+c7EFm39;JWDnL=92dof\0]9OtK*AB_<5#pq(3_VS+dF7L@Mb\p/j"I;d(BDI*g1GF7"&`TcSI_@IA=K^(&In0_=:V^8*g'9.O[HX5X;TDDU[2bD+p2L*\#hB(W[Pg?e;-Q]08C/n"4-JUPo46j*hNgBA?JTe?=ZatF7-D?kh8I6GA2BZ_P_lanri4P9[7E=5#p*[<V_?B&L@&1aDX8.W:),s_V]37PM&d(:b^BGhP;Y4&`WESWlSM4M>PWVPf!9*JQH)rKL;IW$5oU>`C/dXH,qZ-c$c-U.l%QjuWYYh"pLd[JE`nssUB0=u4VSrR?%g(5+$R@A1if/p*\/-IQDcPiiY,2B_=aO+g"KN;RQ^")ZUZ0Q`%VsR1P?65f)jbT%4A`'jV2;^6$;`>Xl8ps?J2nDiZtYB0\X$_%c<3A<.J&/mp(,(:jB/XeJ]oI,%[']eIh'&6l37RCIU(/;0<j\m6Q:Q_4oA[QE,?q4ViB.+71kml[1iG^S;8FR$..0iV*p@Cq7HeUZ(."1d!l&9=H_D1!g2_<p/+&do5^*-)#6e5U9Sn'ihB[+jlkQ8Xa?W:3[4(bb7Ma;4VHV/tV;,16p.mXu`,;Jnht%kb7?"?XL&J%Plf4>'7%^>.A_h^F2<6Ula2A'XU:H]I\Q*^."cCq*,ogSAkWOGgS-IR>.i5;YIN\cj<2D8_c"s;FS*nP)BR(M0[S2Rj6AiS)PreO.+KFQ(2>`G?iN*$?)$sOpalL4n$B2$dImf";g]4:_L435:h%Z$Rs9fKldk!'XQgue^+Z<GNi+iQ6es@amt?e;RkB<oQW:%*+jM'BHJ8;XeE?Bp`G7]QmZuO"^MtH!^&K,ZbYF<k9BW/LT<;6hZ4caqeYJ7(qbCm^Os)'kBU2C+>co1=r4P)_GglrgUk=[EHdKC[R\`_Hqer02'k]#:H[<Oa`oMJ?)E,*k]_mXmh\WelrMmn4Id">h`o5+,9>9];S@_cUYG1u6e\pT+aJGC2!N;SM1.uL$CN.V'8EF4\2r)FLrGoUA(nUE'rHs%'t&'uQctUN14hi2TG@-.Ps:jGK2?WE'n-m%FU\n^#Rde5\][ulo+)Z?B(u~>endstream
|
||||
endobj
|
||||
15 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2126
|
||||
>>
|
||||
stream
|
||||
Gb!;dgJZcs&:N^l]):W*Yco`<G$\&]8-lV>Q4ttB_F)=@gE(\uUE,>1_Ui_P8@$(O=`Gmj(3;"-l06CUe#2`09/#1NO&LR),<5PZK-.mB!e03!0Y2e\UP"%+r9DC1hs1f*Tb%)fi!k"gLsFE&?2(e!*n1t:c9eaVIK7'S4Q6PCi&L"Q(Cn%80E?#.g5jC4^\3V68BGI?gN5WeDuAYUG;,K'kRW$VGC"*Y$%9#?qZHlT>u6"<1%%7_IPjLBkGPOPbpPVcL*KA(-O+UVk0U^HJj(2G\L\.]qj>cIb2j>-91N?`/SB]B^NsPY-?g4/jJGIE>%7jtYZ+6$aklLk&4UT)_k:5jot[4bYSKkn7pj-Um_(GE>@t>UCLdW2&oUL"A_C)og9=rtAkYrKmO)X"Smf9^R*e]+'<9A\(OT*7WEj8"$X("@Hei'RYOg+Q_P!4'jM*4\)e/Sf&3cF=$oC5jA5hD!mMHU5cgmIBM^%It>0Sc[TJD*KPKEUONoT$+!pBkH;]J;6)"i56NlN4I#O;V`kHr"Ll+f>"PR_&pL9XP_TH67N'f.O6TXnnC.kV7ciKV]t2sVETr9f!*r6gAfTDRpo\KhZT:S4^QId,5j'FU2CHh]n0nJk:2SLY..m9K,`F7:cjKK&B!gV_n;^5'=<eBJjnesrWF`J:!J+>R+t58ilMndZ*@dNP8O4XC<n166'aJHD\"^qJUBU@(<c8L-C-]6:,)H11o9%UnMppPbTF`>D?L`e?1P,3hR\H/8G],Q+3I:M.h@?&m]cLfK$KiNu9;JV!<k9iagF$F9*sWY"er_TX1!N+nBT=:q.%GSBe2WM-2Xk!EOH.3VM";q$:Z'U'm.#[\HF6&DM?EcAgj+=_dMkE<[q_G.*hVBUqtINqP^YDt&l#u]Jf<PV80eipFmZ7I[k"Gj%=b64-4*.bPR)l,>0#1%Mgg;+.p']dQBkEQD<gfFN"@/4$e5:JF3"J"-f2+9$H)E_MmirWoZ/2Wtp)mrAhhjaS"oCgRF:/mZ38H@$Dg^Rj?0N(McL'2ZG"eRI+/7i(.=J?*NK^;AdAo^t.Dgu,dHZ4Bdr!CUZoCO3S'$?1V\pE1Ne;;b*a55Z&Z(.%A.[;9u0NEk6Z+q]3$O/9*Rmhm<(k_?PEoK'O^.HG1h(2SP;*rse4"$%6[`lF1::\,<Ua4mpMYJVd&'iWtOh)bA+hF$kiY&:KLkF8MQsiV,`l<YG(g@jS*).oNF.;N$@>:LJr7tH:QE]A7"W&@I3`U/peFK"]6ZB2n^m\PhD*&/qYR:p4f4L?Vel>/I[9q)>Z@gHk:@(UIW;K;%fPi,,+a##/bf!3:<*nkMN4omAbHa(*7+`$=%)'^Ci,po*D2JYpC!B51h7-e/_JXJa`[@iriSa)Km,kGuC"UusNF!M:QEF-F2,5`X=tAET3X*Wa3*G9phj+[r\6^$51:@!HX>FN7G(1n9]5PH,4Z-eT)]&s]6<gH><dab&[$Bt-HX]CMaQ1lP6)&<iXYIej&BXrt9kk7?gjlj1]n?t,UD:n4B4S#SU'4%2O-W`s)"[RWU>;KjN"W$D&dH;^`]3'X5-g(4h4oQfrs@bljkkb9EmmXHlEq7,e_&u$m&mGLh8f`"aATCM/6QkDV8<E>(d(dr0-<V[l/SbO"&YdH$;F:`D&0"OP@IIR!>L36Ku-IfO;3Kp2EleX1jT,!*?Op@Md#.AACE)bh>U(/$n[nAde*VRKhee4AE=iJQe4k`<SgJ-hmhcP+mcP'AekV(rDjS`Ykt):RdlEXV-C+YFu2\JQuug(X#5V7.K:#tM=lbUK0@j0"o`N6JeWTQI5g"7QMHfV1rLZ)a[6G\(PeiqJ@&QTrDA>T8Ni4H_We?DmCb2&UogP!/A6A-`(^oS=)-8WPr7DDb%U87dP+8u[bWnp#8+eR$L1rtBF[$u8P8-p25N^K8Q[`B!o$1%,>M<@DqquUA![r8mN?'j'6ri=\_g\J\PAD/024dh^K?eqG.M!=(ktBpXdXrlnQ7H1rsjRUrU7R2)$]IJp.tBtWYIg]b.d@[IdbgB>@4?uB\=aF?KCm,1*MYSZ*eYlVAh"40POPjL1GpfXpq)\&Ej4OJ>iK_I+^#Ur99Jm<u1r0T/Bi)hqOhr3;=;'CDn#~>endstream
|
||||
endobj
|
||||
16 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2205
|
||||
>>
|
||||
stream
|
||||
GauHL?$"c/&q/*0f[8IZq:;62MY_:(3c4_Ueub.5'2A%l(Pm`X80l!6TU#<(hm4FS/!f6MnX[\)V',kKEVAbP!s[iH-ZFRqSEQk2?+^Lm#\h#I+S$_F?dl4MBE((%g6%TGRp:]7!DQ&tD`7;6ben9k%!Kt6X;nQlm_u5g!hZ+IL$emqV;X'sAhVGC^2B6X",9e.3g&.E<_E9%Q>Z2k.f'W^jN>n[1_0:^PL=QNes_KEXCZ32pSdn;3Rkh6F"CQ\3YcNdj*73nSj*N/1MhL:Gjt05Bk9cRC_!q)^oh7fo,#;KM,B\FZ<Wns.YPg]8./9m4)NJAoA[?_9R0LdRB/"N*kE2k9U<b_Eo<'Q=lR&hV6$cF!,QZ;d<fBG%KrDJ0[qsI`s<TV8h3j&5dVq>/kB`W<*mWScSRZ4b*&$SaY]9o#F:Qfpc+S#k?d<5#]L`o/VQa[B*SSBq/`-TGMQ[bmR@[m$aCk3/[VH:d-)5F:kF\>OWU^7Xu^;+*j4SO[/^bg`725o/Vk\FH+3$HOl>P,r'ZFt@LjRV]M6@*<T7'Q!AN4TUDJma+$KNQdj&Gc5`K#oc5>X$:RTn_KGIuUV;DkQp"X47VTMlT7%E2T,e.*LonY([=X)a,d5'It?!0*TbaI5.E[*kUqH]DA;RnXW2ITYC=*SQP*8+"sK#6aSWW*)]HLJp"W=\`n4PW@,`p1^4W'%B0^&X<1HLs\7p"1M'nam4co4WYm`$=5P`Y;AjSMW+KJF8<Z*$QQ5h;W2/`+-T_H=ptr935OrXkh*8`=l)H57AGWA\?VV\LS&d"9Q+0j]<4TV:;o\]qf+"hG;>OSk`/;D`WrS2M?6(iZ$Xlp>Y.R=JT(PRdHm:]A(S6pOI7)HdL8S1_.,'-fHm#P;es+UJ&OOq5%9M%sS[[V^I*:"l;3EB#3>-O/!;7rp[a>mWbmDm[/5i:aLd(ocA3q'g7@#*)@X&V7lK2fHRq4Q55Gr=]X`g_CBLq#q*T>T%qeR7a\sU>j-[BH@fYW1RJQ8D3[jEc9tYu()m8u%33+`]D+k8)`"IH-BVnP.C.*SX+MI50_S#k#.:M:V5WGYFK[A:E`l\t<b2V`3..#jdRTJk09S?nP2ID-aD]54,hT$Vi#i%Z,\hZ.8PGC5JF-IY&4^R/8u5Kg&9=0`.gN]cqin`^T?H!<)u6k'hj5kEF/@?gPCra\>'T]>2rtuW^aRV_X9C*YgK9,-_X[+QkG*o..LrmW5DVM0i?oAE.I)Pe2qIG-Of92!H*I`l.k2#3"f*W/k$j2Hm"DG<]Pd*1]$<(PRd6%$)52+ob4a/&VENp9p:fYE6=K&L$Mc;,<FNSi`ZB"qab%3Jd4+@:<`7Qg0_GDL[HW[Fad>@S4odG*#4sS7ac9sh`\?bJWm'*HDbTRM=OUIT<+co@mLet;g'd*pGrGHU$GYmi"^NWaJ,J9@WRDr`XbNR[aq5pGAud^4'%`Ni6gd5oq`sM'VZQ9p^BPdA@gG/g;GuqIDpa6q[C16WWc`V5HJG^ISb[Ek^8`dm;q`>^6[,^"c!TqCLkQ(:=N[aL=$%%8M()`L2d#.,98jeYi&Yl=aCqP0RK_jiMtOk/SGH$tiAHK%)!($OUgi3Y<Cm)ZlJeYK2l.s&9H3ea*IV(k%GT!g8UVtg`J1CrQi>S`OkD\;CBEYnplMu<o<6&U-EegT14e/QNgFL?m\D\N6G&M(f;D0/"P5VGHOT*?qe5\&qR)*(L_A>?Wn84b7^k/)I^qXoG;J0(YUEEgil>\Be6I^FJ'96X0t]_mmEVuK907f)=Xpl>XRlA,Tommod>&=g@L*X9ag;]p1to;nQJYTMo?tbT(-RcN-Vm&=Jn>t9`h6%)L'O5C&JF@V3EjD)a-=[R>)W"721s=-Cdc=llU5Q5[,'^6[T'^[roD/C8$*ff*Vii2cneoc"WG7Le(-tA"NaVq&FctHrT:2,.6pDu!Mg3<2]gNP]O6%`VS?%%'&NB8a(\0F;ZeTuUL_4]/+F/<d"Y)rOa8N$D86].5rY%r3qaE3`S!6bV(U1o[$eJ6_@iMP\-dtVR/*B$^Mlt_-P]dT1(I#M^O1D$SBG+/3KXNnP<-OP/BAc6B$b&@O@nP$XnhX[d\+7=p';q'-\9/K)=V#7b:o"3=@\<knB6/TcM)/UHrF;<h%G,o)I@`r-p6lH/k>@/<ur-;]8B[e[b-m4_U^ujfs0s>fmT+Wm!mf#eNE~>endstream
|
||||
endobj
|
||||
17 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1134
|
||||
>>
|
||||
stream
|
||||
GatU1a`?,q&A@B[\oL\((+hjXIEO06c'0T@7'&E1!eDq\&dWGAd'<QBe)2E#/h+(^U,EXt^@$I;_ji?oq\Bp^Y8LRuIIJ+b)t3q_JF"'Na<pp^r'<)s]I7>?rCNBCK_'`dkh'AWMh;SR75A5G%(p]@?=8YIEdCRa6/m5_OsVkm!>pL74#6*(;'lQDa`qM:-.)dcs,L9!IaN0SrIj-s?*kQ@9^748Fu%6nh6$efr-;?E2W.A,`r\ZeL\/*.kpN7X'!Z`jfab<3cfA1>H"dhc#P"'G.EP_<J#"deUdr0`Ud&hAdb`7bdJWf%Cq2%^-/X@#5?\i$EeMH@3@YD@PVoHkY\;a"Y:ESF\BDH5eS1Ke^c^tBWVRZh6#L\>nD;H8?,%qXK73uUM_0OBa;)p2)f5_0hS?^&K4u/sT8P&d4(H%5VU5TIM&&]`T[ZEu;V@dY/2ro))Q^$e>1.;]'>IiXa+]n0ARRD8Hrm!j]GEoD"Qq;cFA;;6h^Dk>QO7dda"ZqUbP6B1FB(u@V,hP*WJPK&,JPku$Q0F4IQ#(i'r*Y]C;$;n'`)T&WA2=4:iRDVr#@I[D-ch8r0LW>'46L5T_5dk4t1]&po$8>WUVqW#;LdFjZD):d*T.'NOFDAN5\.\X,"]("eQ3@86Q=9cGeCrSL6H49IgE7kKs?2)[dSB1RT7Mm0tU>@Z3p']a_Bs3tujM[&3ULk;9q@ha:nlFW]l#pd54Fgpe[$(O^H?cVG1^TP_O),Zsj"`Pdk6qrP`6$fTiK*E5g6l#%fK-D.p9Bcfc[gdc?XAprS(UXK9Ai^GTLqH8@Q3sbb'UE/;N-`dWQNj9>M7BB^]7!RFmV-V8b&%;[jE.l,s"G/K,c9:ggkPh!@Wo)8'NYicH$qmG2JaB)MPqZcd@G.ZN'>I^')\6!#Per$KoB*&g#.g^^XY"*u+8Q'ef$Q=ZE^=8k7g/+rRQ&J)=%oUY>GB<%`09&\)8!e=%nLI-cu<_.C'?&s/W!8G?5@sIN%0hFRuN^o4I-bmKSk()>BqlP.LQ.[<0UX'J=tnG>31:sNf!umlBUF>5?g3C[e9p^F9c],JfAsaVLY1@f\o@R["(ZBJ."ti6f#Mc=8artAogQe3%\;o[-ld5cOVB&!>N"bR/~>endstream
|
||||
endobj
|
||||
xref
|
||||
0 18
|
||||
0000000000 65535 f
|
||||
0000000061 00000 n
|
||||
0000000132 00000 n
|
||||
0000000239 00000 n
|
||||
0000000351 00000 n
|
||||
0000000456 00000 n
|
||||
0000000661 00000 n
|
||||
0000000738 00000 n
|
||||
0000000853 00000 n
|
||||
0000001058 00000 n
|
||||
0000001263 00000 n
|
||||
0000001469 00000 n
|
||||
0000001539 00000 n
|
||||
0000001834 00000 n
|
||||
0000001913 00000 n
|
||||
0000003725 00000 n
|
||||
0000005943 00000 n
|
||||
0000008240 00000 n
|
||||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<c26c46b5aaf48c9074c79fbcb3fd71b3><c26c46b5aaf48c9074c79fbcb3fd71b3>]
|
||||
% ReportLab generated PDF document -- digest (opensource)
|
||||
|
||||
/Info 12 0 R
|
||||
/Root 11 0 R
|
||||
/Size 18
|
||||
>>
|
||||
startxref
|
||||
9466
|
||||
%%EOF
|
||||
@@ -1,231 +0,0 @@
|
||||
%PDF-1.4
|
||||
%<25><><EFBFBD><EFBFBD> ReportLab Generated PDF document (opensource)
|
||||
1 0 obj
|
||||
<<
|
||||
/F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 5 0 R /F5 6 0 R /F6 9 0 R
|
||||
>>
|
||||
endobj
|
||||
2 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
3 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
4 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica-Oblique /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
5 0 obj
|
||||
<<
|
||||
/BaseFont /ZapfDingbats /Name /F4 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F5 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<<
|
||||
/Contents 19 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 18 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
8 0 obj
|
||||
<<
|
||||
/Contents 20 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 18 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
9 0 obj
|
||||
<<
|
||||
/BaseFont /Symbol /Name /F6 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
10 0 obj
|
||||
<<
|
||||
/Contents 21 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 18 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
11 0 obj
|
||||
<<
|
||||
/Contents 22 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 18 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
12 0 obj
|
||||
<<
|
||||
/Contents 23 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 18 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
13 0 obj
|
||||
<<
|
||||
/Contents 24 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 18 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
14 0 obj
|
||||
<<
|
||||
/Contents 25 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 18 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
15 0 obj
|
||||
<<
|
||||
/Contents 26 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 18 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
16 0 obj
|
||||
<<
|
||||
/PageMode /UseNone /Pages 18 0 R /Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
17 0 obj
|
||||
<<
|
||||
/Author (\(anonymous\)) /CreationDate (D:20260224202513+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260224202513+00'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
18 0 obj
|
||||
<<
|
||||
/Count 8 /Kids [ 7 0 R 8 0 R 10 0 R 11 0 R 12 0 R 13 0 R 14 0 R 15 0 R ] /Type /Pages
|
||||
>>
|
||||
endobj
|
||||
19 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1236
|
||||
>>
|
||||
stream
|
||||
Gau0Bd;mr#'Rf-pm_7(d&X"]e&oU?"h53h9d^n0L5HGZ#@KJHm@FFE,o\4_(C^1'>Ubb)CK!Fa/mQ'Iq8.6nq=RgmR!&tL^s-<]G&:=L*Lk&k=QU0f>_obNHM5N<<ht)X>>[gn"ma*q'p%W$P#d(TiJT1#baab4G"Kmn^41HQ:X6:u<(0CVCY$D>n&JcK,1"8aH!PnoM6^r]eJ9OjGaa5rQgajgU1qm>1Jm\f!CZmY9Z2D4d,q@/rp4R15TR9q(^Arl<5k'<'K#IcmURLu3=!`OkFSu=u$T=U1"I<1OZf;cOlj>Ar=e96?eQA8sX]VB]6o27Z"XR]na$#NUWQ#O-OfikH/86Rf%RDA-+;Ol)LQ!C7$8Mur?6aK&'\,J$"u/tQCG&6?7DI2^UlB8#_S%N:D33h#>ndDN$aho,d,L6`U&.>pkC\A=kNTT4MCm77Z<p[DQ60KDcE<$E8)3^;h&oGTq>P3"S2V#3C_8&Br!f0/ku2IUp^bO*HAWlKOY6Ckpg>2q2IGS8/Y49XY?flK@0Ig_#Wu7+dr4P3M5RbM[=!0M1('Wch`%[LatoOnC4mNjdZ@%_<_MZriqX9'guukM0XZ5^M<*/b7$mae8VQab<bA+9h2fD*/[,87XtDqeL>*4tmk6<q3'/'bTD`mmC>_3N]u109q5ri`XiD@i_^Q;C1VIK>[bEM7\"[WS,,C^p86*AnYJC*;G"X,DK\]qI036d(pO@AJ%U\T0\Hd]^`+Q)M5d!gErn+485D40gp6-Y+8'qE@KUK@;@UTj#!ImfgYZ[J)IL:WV:40)9<K[K55YLG[=pL^gB_2k^3&>Q_i7a8aAZ@Y!Y,dg1=u-7D:K3opI"fh*d4X*`C#LdDASJiCUoVMkVX(bZ:b\o?igO<4V!^8^6Q_&&ZMrS#&f8%[E=;co!h\L`JeitJGFLeLm,PdMc]9mtF7\`X[T$FUpl4W;<KjKb3@Ds4<;[e/W+5(K#t6kQ\p06Rg:=u34!g8kRkGg0E<b=tV.8]e"hJ9Kr)Gh%G<@l(F&\.JG`oq/H7EN&!GA<Nl68Ca!_/_mGe\KS!f^Y-r+#@pq6)dE?4=^?'-;4?(s_UhdS$<J&V_%h@FupPY>9,[ai>7U4L>s'&bYYnjI94B]S`J0S6NW-r#)\]S[()CK%iW&NU,*',CsUgSWcU%0A'$BMH<:fThOIFm1.URMsTR-0tR2X$JqUXRud%.#.&T#)bokD!k))JFFF4ST=9C~>endstream
|
||||
endobj
|
||||
20 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1186
|
||||
>>
|
||||
stream
|
||||
Gau0BgMYb*&:O:SbQ<33".84VP[Ck)_qAQZYS14mYWuO%17bA*,t1k'G/&K]ZL%?ib=.$`O\$%<kF<D"LB5@Y<rJ*A!.P-u]k"o<">aGK8-j*@&@A$4XL?W5#gGAS8e@bV^hpSRI)UNU!5I6$JR9ulWhFZNV81n^.1B&\*A\"UL"So\Y0fEZ?[!X('b">G&BrrK,4&Vcn/Z&V3)ePOYGRnR5hs^GJ'`WL%rhnq)OKn9p]A9c,Bd/)fH\E?@>6L,mbg-+lh..kX]?&)2Ep0j<GKrS9s[5;\&RgB!jc[nL.N*)Am$mC\LeuL^\(?ReqS$lHFntec$s"iO;UH?%85GImC0A7k4sc87uJ#$BuZ#C7>8Jq-H82Zjti+AX:6.,&%OZ7#3WMn9&Z-sC:FePKVX8M:I3$\Q5#bYGh>QgCgLC#8\WnoHH:Qi-T>]6o^teB>+XhQ*$hq[f,G%=pM'bN4MBdAiQ,;<#N'SaM2F8GIm4ie:(<=jnV/F\m1]K(MkcjaC8&pC4db$CBd:QU]Ut%JMP&6UN0BSfSO.f]BnEtE)<]uPIS_PU_-RgQ(T)1\UG=@62ZV^uORmFpC<&?E5NXtbZffaP%59_%i(U9!LO;82Z_E+,M8KLEk[$(XqknDNI=%'M1AC83::NA`je\n+duh[Q1;7(EX2h^Y;4X]b$4C'c[DhCN=;\@FlKoX&O-3lH)UG+%:*%g4%$a>Y=dFqtlb[#4595X$.L%E.=-78>Q;MNupp\=N0If5aNE/'kIOr[TfBjnf'IJmoU?i1Yl"O>(lWqCTP2TVZJ4S0qTkoVG"P_+D]h5J#A>Ui(Ip)P"[OuK+LqO8nZ@Ea\7+p?^*^7MVptJ@sguCe;WV8Fn8XLm8!%qRe&?aF9PKJ#+L(!aP$@f1LH&4PT2=W]87NEJu>lf)V@a0mOClXm#o^GL4qh$r&GNs_8\TZN5/TsH^:IG.sd/WudF?N$Y4kL5iPZa<<CLO,a(-X*W/SsJ$_DF_dLnfsD;1r]P=#CoF!nB_:\^T2:8p<5GibiGqq*]HAdq5L6X5p@bCIODR>0m`#d%=qCDNq:e#sR2Imm7!&GVU1)Il+gNrq"T`0HLY38Cio,VB9)jDO/&+f=<O@XbrE+q$)bbkeU8d:)BHuMO/0`K[F99pW+G2UX.P2Ps*bgoU'43Eq6XO+8?$qB`/Gq*$eP~>endstream
|
||||
endobj
|
||||
21 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1317
|
||||
>>
|
||||
stream
|
||||
GauHJ?!$#V&:N_Ce@snC[f)c8[i&5u3NJf?G(&<qL'AkGM+OK&^Ye;V0bHG2Shl;f+JGg6>ISKM2ZnqeXF?4s!8g+&5%DAfKJR#!8-gm,2!dBtfZ$ke6tjl^'8$"B.h(`L^L_&XYs7koD(Xp69X+3N'RU1Ql\)W?kdtrWB<q-acOM)1hf7u"i6K7KQpqkZ%K)@/ea[mHUhL!Vk17DF5>IEA_($c:-hT-G?X,&3Do1$*D8@N]"e,9QV"CSmJ1-:^YZD!)cs-E6ND%g3`l?^XRochFXZP)?=1YB/D1FDUfi;`M*TnpPCs:9([,eq^KHDOum3.-[P!12F'UH;7-3I0n),rMOZM0bc-kf+r*[,3j)uD9$_Oi/2V(j9XGZ@di=ftYunM,ks,*Dgho;UW!f]d>aC^XmFG?Y4B7g5(;P/,MuD%l]aXZs%$qYS5^d!\mU%8r`]<Q>nI[e`!EJ:+dE]:?SQH5X[=J6D8\nU>&lo8(`ji,s*'9pAIPJFm1g;"oP#JRh"I)Yb$"GFcl1,+p&)-_*d>Npr`!0`0:4AudG0B5+T]Oh9s(jc3ZXVH9lW8f225j3TMT4^S81O1qdmDE;WrJPN[m%E]Chr0ZXn9G7e&RGXLdP+!Uc;ZFbPgt\3rA:_Rd$%T3J!C-.?2.^P1#357493h6sQuQ@X"V(l/c;n(aP<=b$M">2?B-srbh>b)L?W=.\6SgT2MPr#b>aN`uTN]SK$(Msi<"A;Rs"$_N:0kDfh'+h3/6_$WWKUBV3Q9<TVrQBU3\OJuUrVT2Z':D/p0TYBQVk,7ZUsWO<\i&hpR-k#Eu[*mYQLi1%_GPmjpD#kA/7VWPF^rT=1pE.T?^<080hrW=P;"*O/#3tH_]Fd@lO\%=N6PWG?Z1P'St2oCB<CrJ9c_S&E:[FXcC2V/)Vj+R.,W>p[Ya#6rHibPCNlHNoYA7&ERmXER_P9K`d"f"6CW\."&dQS"k8`&Z/o,=*LIpFi-!M(W[f(X>Ol#RYMUb(FGZ!0[J"Nf!-sYh`a/^JdT@3ja5,1qS`KWoJQB=_EI8_>e'f5iMUn@Us<$uQPIA+^mY0DfbAec*1WW2rjj"r+,7R,\f8KA0eD6oA$`>3b]EYi>$7L(MJbqZN?'[G*aRNWFJL+IgemC_3-Wk0S@0j=![9aaf=s2HbRr@/aQqm/eOKHGO"I6upGCVm,@g[lq"5!4$%*]jI05,Ljje$h3Xef>SI0R\qi'_W8mU&GHg;%ZD:3n"P,e=IJW`j,Y^QiC!guPXkO*"E)J(TPVI^J!D'V:brUV&To=:i04OMUMQWMQsaW_9JjO!c?UaG2e~>endstream
|
||||
endobj
|
||||
22 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1397
|
||||
>>
|
||||
stream
|
||||
GauHKhbW8l&:WfGR+nOE$Z>>+7oJRm30q6H$d3QYHd\lH+`Z7%)i#[Bp:n@^P(kl3<C#iX;O_nncM*;]hb5FXpncMZ1^!M'JGp>lPX-u)apEj]!mZCMLBH8S`'LD.k(7'"Gf"OL&'`&eV5$-q*d=TaJ4TQ7OH0oMo]$De.>cAu$HICTCD_I^+@7g!I3;3C55I<bj"Tf*^u86PfEN%5[!K#V%FmYLV'@.Ni=]t3KX=DE^[RNc?CDp%E47a/#8_"R>l>MTWL;QhWRa(oiOqu08TFDS2m]Rg1IE&kF'Y"6PT#E1b]WbP[:&LO_S*tX6hPf>"C6>lQ&L:d>mqJ^QGl>*'!;+@Q(2L/;6Qk(JA-gAoR`9jDa4Qs<Th@Wa@rV_&r+*b\j/#<`Y>T*^`OW#JR/Gr"eei`X^LZQ/F4lp=U-PGU0ZIdYMPIT9BbXpI*UpLd+PSYBpha]STd2B8G1jcm9_.'r-<MmB!gtbM`84QL(QI'#.]V!aFr?#XUVAR0[`%X.=?Uo>+6#k,&H(*]fK?5Y70EdCsM<R2^H?J'l*+m.S5:D\-q)=R:+KL0V;:ZJ*BN@s!:a,>bnum):'1/%TdW90@G9:kg&O<2Oo+cX/!W!8-n^e5G=#CM'>9g!-&\dC,&_VE#FE)TJ:A%.bs6d9M>djRh;%473;-VJYKn9O-IU>WT%Llf=TNYN,sW.?7)M?*^MNqD6Cm((ajL?0Ue4ea'!,(o\t-7SA=O)/5:GDJLL"b7ImB##a=LOP/^=_^SXR`?@(0uUW3r3("B)-&;E(#0[';q37\l)Mq>3-W:S%`X^#@!$KokN^?asFg_E@@/J7"3OM"bi\3PV>FBcn/="MRBb4pJYA"oSHRk1`rhk$4a,[+9/P:4l4mPO$cg,m1aSqm\H9b^>MVC2\Pj#CtTfd6E#U>`7=5O/KP9@NPZiJML&G#p]+*Aa=7./!_kN%$B\!a$UR*W<j+V?4B#$7o7/m1LkW;hI;ASQuYCX]A\r])*j;ko>V$r0#1*+NZa_"Z@X\85c@n^SBMg!Sl1=%)J.1>(pDR4N.=1B3'fF>]H2&M,O?(p4,`gg@nQ6Y-=;\&BNZa>^,'ZDtF_EfcCTf@Y-O3$6P[<n&FRI-&fULH270Jk%0b24.DS5A%FHq<2k:a-[%*Epe[6kM8>&R@@GEW&f#7\!ca^qH:jh[n88,p)3a9S^u%W%<C7h\KJXPbDA,/Z+*R89rkA3Y`<Wm<$nHAtSden'NSE5NTe>a[A[RR\r\c4!PdU5B0C[S7>G@T6#Y)olbcoW4V6\"ABcX8"%jftGH:Ph$^45,m,f_fB?o'2N*2">!Ou6^pM,X)Q8>(1#$ZPWI.88d]paS__Mf[XoeWTn0lK:0T2.Ko['4[p4i/_iIU`o4RCiJl.B4%\"~>endstream
|
||||
endobj
|
||||
23 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1209
|
||||
>>
|
||||
stream
|
||||
Gau0B9lo;R&A@ZcHKR\.M6LMn[SsSh$k&>"11;s"RM-LV.)`s1Lb4e3r;(8]0d"4s%U5r"\@^;VpXJID"U>9<r5KVi[g9PI$C!jK#a>u4d4P!cek:p%Q6IHS?jqG7,lqX"/o0;3do3I$^U2?@Xg\W[b(']IFa(WO3d*;l0o?:EUW^h"E%dmagCt8)8t(%!@+=W/Co0j*^ka]e*>RjNY"CK24+l`7U9?K#qn97j^`ug']I?l)r*$iM/)(ArmKVDdn4L&EC$1C^es;R<r[m82W,sQ2m@GcT^TVi^[%[BE0H9JcWrumYWtFqk6P(aPNt^Z1)hb<>mUKjQPEQ<`8Q6#prZ/Yo*6.9)!^/=f]/Uk%,7"e][c]IfQ[6G1Vq/Vi8Ed=?;nuN=_SoYsh[pW!DO5VM(PIH=-K*[.@BMbB7Ak=q2=aj\6UDlC=kCO\"2844n9t"75#Jo3A<Z9fcIdnfL^HaWoD-nV_mXj*4E+Rc-P#fsn!IaHGgFL@^O2Ag$;0E\455t<\:iK]?*82MR53\eCo%:2ku986?U,7i*:LAZoQ)cKl[VQc8o[bXdZ@J9m@UCH5@sDc?rA8[N5APl3eL*j,hChk1b,CmcNloo8`,\Y9]27<'/1?2.j&9c\5J%#7"^nt-t:?Vj@^^:LeTk$-huFF"<Vf7Pi&(XNJu+I(YK;3\Wg5%</100n=YXaIPUDmd]psHX?^LVdj1P:fr59aYV^tp;=c^Mh0?JeV(0UK@A8A"o@,jUVh9GZVkMZGc[;3*"?nD!.%IsealLQcT[[s*;cJbj\]Da1SW"Ko,\::\Q-+;62[p(8hb^dA@t\mf2g$;3n65iV(#@%m<\s@C`pltj(92b6LI/bHdQcN;OT:;Z'3&%h>)stu#D1oK'C>&?Zh;gKCpjEe"kA19X6@J7]\*);`3F09?$P#:]`=ofEajWe78=<i"1(<Y.no_0TiGS$3Y%<miWoI<<s:dWW:)JX=Kj\KPSPN7PTf`If?TCh]2[;k348s#"eejSa,d7>37\kWQKQUk+>q@P)&4NA#S)X5\Ce?Y@OIG,S@L_"OVO.pX+'O"a7/pXZ>[/>8Y.&c.Bk\;GQZi&0uXI"b-Q[4bBh';WN_&6%3-![?jK9L:&orWbP&fAKl&)e<TgWe)@3BlMm!MIlUp="npHhBE&K>E/V]2(j5'4V2-fC&.cVnYe"uQSU<nJ#&L4[^"7biV1&~>endstream
|
||||
endobj
|
||||
24 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1234
|
||||
>>
|
||||
stream
|
||||
Gau`RD/\-!&H9tYQrO%BZsr'D[2nLRV3E7(8P#d5pOs+]ZN2H3-%<D:rqi1m_$(_[-^C9b=F4[npN`?uSM:9aJ$f-7jo?Jj34khK)2+&9"VD;P6RQ]_2!AtVnd/BViTLs6q[D:!pn4!%JM?3m8V%!q&@b4kBdBOE<6EK`n,gHifC^<;nG!JP[6InsT$-WAnm"W]jgd@c3Z.TiFQjgk_>+_PmQd;[AN,9cn)gJdSjN2TiB-@Lru,@'Hor`,i`GMPeb5>a>?WOjX-Ln_o'B6u[tIod4hD7EmnQbIfj<f+W7-$^$th85g3G`+rtWhP4WhH=3]MgQJTd/f-9^8EnL@Ed$0=;%ai($`rM;d]Bu>L!Oig`F7jU9!<RG7+;fJ@"8PB#_^t^$m-Nd&(g1O>4Bn`:UP".iHAK[47W<+')lhLVRL"`YK7r[>%,gKgX*Wt*=?XarP$@YYTU4+`2aNWg,2!=A*Kj:N:2)%_Dn>M+fJ]FF3@1o-lfphpqE0!i\dp6Z1Bi*QFPgBN1\&`%^XCmp;2oFT1>fQS>0g`tt#'9p),+J#HBG#L-o)cI\MXYn.5A%jEbC41u:FdH['Z6t[*^:sq7;AE9KIP8Q'VeeNiBq471t'.$E\<jL=%g*iC'Y_+/;ch<)2V1cM\C1_e1R\"UeBWFQ4`IhSD1]H(*eF1#Kng%NAUeb<?;*^"5N1VToT>_3&g*2s6BQLR8'pPAU.HIH*"@N]W"[h`Vo0T_+$jVc8]e3qZ7JOFsV]V.DS-dmH@0sZ'K5uXS&D:^/Q7'Y$K4d'a`n$UT/30oaP:nZpm^ub'%.#3Wa-*L"a+Rjh&EsC2GSETRG@)J%k5kDaW:Qg1IEpU8rT\nq2&Y4!`l$;o_M<j.\8'X,$_UXae'&[JIYU6`9s`dta!t5Q:$)T'Y_.'WVHTC1m44(>mPhUdFiaoE5d_!SV)AM`B;&gu,lt3Q;Hi17_mrSDgMO^lq6u?4*7bfu`/oDt6guf1<Q+I>)nLD8l*c&smp/(@a1s-(kn]7jWTeNjX>Zg"p5&_XgIAM="Z;Q31cHLWb,sm!^tJG!1L:j2[29MKUqH=UL]S2X$<&Q@Hf?#s?6-kR:VA<PW!nJ]-4Dn-@CY([?hOmntsi#jB1Y6lG'o/<kg0ZJBbl's+FPDLEN9lQD':98F]CQ!W,QSSJpoT>MCm_dq"u!klQ4*CeKt#$<_?[eJ.&.l5RU1c8lG:#6=,p^IXH%3%/'"Z1_aXT~>endstream
|
||||
endobj
|
||||
25 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 941
|
||||
>>
|
||||
stream
|
||||
Gaua=?#u_o'Sc)T'k_l)GK6'R&qW(@['d6C[U!OL]V-/W"_%Merqnn[ldW'I]lA4_JI*LAo=g!$&dB%'<o1^si,Stf)[;8=BF;s0/r]YR*AsE-D"FK&`0$RB-R9;JpMa6p@:-dm\,FV^iX>1d%.G^2FRU_bO%RK*N>/lCkrO\-JI=7M1(D_$jfF,T-DV0*8a7`@Li'/4*2:0NM%^.3-&=1hYK/;>o4f<\*B<:$%Bhfs(,4-TZ!+u==Vj+\KCap+Eu=,MJh6JV;]%)oo\IZ<fIKNc8R/+e+j!&rKJCG^5CP#k-P2YlY->dFIU3>h_ZW_hmhg:5EBHkD7Q$Wq=/E*K;qbX`8YS,:pn/ShPAE#njYsAuh0sPJQef^Mh9XL%NhAPF_BFkYpRiKrD#9hD[-[b3G?+I!/@=Ih.GHfL::obT.%`_>_B@:m='0$GTu-qD3Y-l-eAN"kF91XkXYqGVHH0X1>%bCfi:f!aj1KeWs-T2q42OY^,)Ba2ZUlaGMa9N^-4*>jC`R:!37FkP/6chb9n[g`_2]!#.nZQ^#\(Rh1<I\73\>H2\5-`8q?7hKF)8^Of_SZL$aYH;KL%^ZH-pU[V6ti6J+Su9N=+uW&f!=KB]cTaZAq%nQ9=Hq[Eam`O/'Vt1g<Jni`duQ=$E<!oa_c\:46$k\,TH,HenZa%#3AX[rqA.H%JR5%Oki'Hgff5K5CnhY.%L<+j>%)kZ3RF<@bj*Cl1e`FDBWC%f>7ST>N:*)9,q&6hPH%_^,^"m]A-'b9Phoe2CJ`0Q&3AX3V/P5K9T(mPFHf-)gun'V3:sapUb77G?I3#ds4WgDi]i<E[$r]2T"8\rA:]R4g:^`5NCF^nZRUpk!oL6LmjN\:e=eb2YmrO/9YV5VGYUH#&eaE&GahE*g<ss$6K2rnKfcfNi919O,9D%q\ZWJG4U8)Lhe(j!u\~>endstream
|
||||
endobj
|
||||
26 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1266
|
||||
>>
|
||||
stream
|
||||
Gb!#[D/\/e&H88.E@?RYCD!#28;bR!2G9C0=hU]dL&hH9<MCLFQK7>-)>`ZCP[r*YR\U@E#6?`Yj4ukBcU76@JE"Q5h_5(UmDJQ*"3/0L!u"(QIg]?Wg#k0BY#LiLMK<`j8$pbU\tPD?epMIl!SA`r#!]qK*#Pg<BcCoPXqJgV'I*,Pk!?4&0>7Vi!W3`ld<iNd,id1sA8EXHoSqR!rfKiRVqYQ=J]iBRrW1[l*Xot&*^!DA;&VuW'bk3jPQZF@_Wbp-<e"Gkl7mmOS@e8`S4;1AE<0JN?aDRE3<]/P8k`F^(8eH3,XV]:fMT9O2YN8=c6DjaP"!pL'X5`d:J6=rqHL(TZ^(&7dCQOIm]A4'C@tUHo*!A13UFP0?Frq'K9]'!@dfZ,]jBkn'^%/%qAoG`VCl:LMCoC7p,;Va**cNiOl\!mTU]>#aXSf;)n?7j`oJGAYo+[4WLT[8s/kqRZo!&C8pH185?F^1$cl?[el@ec9;XulAlX`ci!t_If$IAeqQ&P3BVrJg*`KbWO6c?1EB-MF6M%<Is,jt/JH_db%[C#pm@*"j@84aO:]dXCM$o+IdY81)#ftmQ[uZW:"TQa\Ga=_k5]&[MDh:eR\@bc1JoN!1EkC[uit/5UZ?@G!iiWE9gJ^WI`8_p8>P?M!9e'_H0lT;8\<L_B(X-5o:jY&Ff;sk@$)j']bh40Fj!iQ*,>"*.=22J@]t4(N5$ZG%r6(`1%m)Wj,3GIeW(RZo-OKC/QJb>Mf5@@ASt\1Z+I"!P1CqbOd8iXt<sdK]f$s6"r>,s0eTrs:DL'pI]g`to3YE@g<a'=AGLWnj].k`V'iXARONu5X*)PAQRNDqMbSL&.6g[lU`hl\kbf,-eHK&YDgS4qL:nLFP=WB&M'%223(-MEd,&_gH]aTo[9oM:A-MI5NpUEdh3hUW]%)e?1o;E.uZuW6?KM,;i!+($2I)p;Ofq$meD^,n7R8b6cTiJ.NfNYKOY[RUcJAnYBbaK!l11.c.*ROZs_b?eS5\Z'aoEdpf7te]hXg=OZXIB6$SJW]:eVt3H\S=6.2sE(m%9u>ApQ3/KBq=181qi:Sl,5!4V/DCIHbmb/jI88gdpP1\8$.uFOK%.7R6!&pA?$RoZWrG:.ej/?osZbhS.4CJT<\J'[\'>p*Q%RDeIEJA@_.u8M81h_LMJ(FS]%muiWHWU:@WN,(PFR.eu:%+ptb=B^ib`.`VD'=fdb-sn@i^&f\ar&^4GTd@>aP<bM'/p++jab9$gcZiTr4cO!+&~>endstream
|
||||
endobj
|
||||
xref
|
||||
0 27
|
||||
0000000000 65535 f
|
||||
0000000061 00000 n
|
||||
0000000142 00000 n
|
||||
0000000249 00000 n
|
||||
0000000361 00000 n
|
||||
0000000476 00000 n
|
||||
0000000559 00000 n
|
||||
0000000664 00000 n
|
||||
0000000869 00000 n
|
||||
0000001074 00000 n
|
||||
0000001151 00000 n
|
||||
0000001357 00000 n
|
||||
0000001563 00000 n
|
||||
0000001769 00000 n
|
||||
0000001975 00000 n
|
||||
0000002181 00000 n
|
||||
0000002387 00000 n
|
||||
0000002457 00000 n
|
||||
0000002738 00000 n
|
||||
0000002846 00000 n
|
||||
0000004174 00000 n
|
||||
0000005452 00000 n
|
||||
0000006861 00000 n
|
||||
0000008350 00000 n
|
||||
0000009651 00000 n
|
||||
0000010977 00000 n
|
||||
0000012009 00000 n
|
||||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<d99cd050eea65d365d48b1f6682b5622><d99cd050eea65d365d48b1f6682b5622>]
|
||||
% ReportLab generated PDF document -- digest (opensource)
|
||||
|
||||
/Info 17 0 R
|
||||
/Root 16 0 R
|
||||
/Size 27
|
||||
>>
|
||||
startxref
|
||||
13367
|
||||
%%EOF
|
||||
@@ -1,375 +0,0 @@
|
||||
# Les 3: Cursor Basics - Huiswerkopdracht (Homework - DEBUG CHALLENGE)
|
||||
|
||||
**Deadline:** Vóór Les 4
|
||||
|
||||
**Type:** Debug Challenge - Je krijgt een kapot Next.js project en moet het repareren met Cursor.
|
||||
|
||||
---
|
||||
|
||||
## Introductie
|
||||
|
||||
Dit huiswerk is anders dan gewoon code schrijven. Je krijgt een **intentioneel kapot** Next.js project dat je met Cursor moet debuggen.
|
||||
|
||||
Je leert:
|
||||
- Errors opsporen met Cursor
|
||||
- De Terminal gebruiken voor error messages
|
||||
- Inline styles naar Tailwind CSS converteren
|
||||
- Missing imports en dependencies vinden
|
||||
- ESLint warnings beheren
|
||||
|
||||
**Geschatte tijd:** 1.5-2 uur
|
||||
|
||||
---
|
||||
|
||||
## Stap 0: Download het Zip-bestand
|
||||
|
||||
Download `les3-debug-challenge.zip` van Teams.
|
||||
|
||||
Unzip het bestand:
|
||||
```bash
|
||||
unzip les3-debug-challenge.zip
|
||||
cd les3-debug-challenge
|
||||
```
|
||||
|
||||
Open het in Cursor:
|
||||
```bash
|
||||
cursor .
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Wat je tegenkomt
|
||||
|
||||
Het project `les3-debug-challenge` bevat deze INTENTIONELE ERRORS:
|
||||
|
||||
### Error Type 1: Missing Dependencies
|
||||
|
||||
**Wat:** `lucide-react` wordt gebruikt in `components/HeroIcon.tsx`, maar staat niet in `package.json`.
|
||||
|
||||
**Hoe te vinden:**
|
||||
- Open Terminal in Cursor (Ctrl+`)
|
||||
- Run: `npm run dev`
|
||||
- Je ziet: `Error: Module not found: lucide-react`
|
||||
|
||||
**Hoe te fixen:**
|
||||
```bash
|
||||
npm install lucide-react
|
||||
```
|
||||
|
||||
### Error Type 2: Syntax Errors (typos, missing closing tags)
|
||||
|
||||
**Wat:** Een component heeft een vergeten closing JSX tag of import typo.
|
||||
|
||||
**Bijv. in `app/page.tsx`:**
|
||||
```tsx
|
||||
<Hero // Missing closing >
|
||||
```
|
||||
|
||||
Of in imports:
|
||||
```tsx
|
||||
import { Button } from '@/componenst/Button' // typo: componenst
|
||||
```
|
||||
|
||||
**Hoe te vinden:**
|
||||
- Terminal errors: `SyntaxError` of `Cannot find module`
|
||||
- Cursor geeft rode underlines in editor
|
||||
- Gebruik Cursor Chat (Ctrl+L) om de error uit te leggen
|
||||
|
||||
**Hoe te fixen:**
|
||||
1. Kijk naar de regel number in error
|
||||
2. Open dat bestand
|
||||
3. Controleer imports en JSX syntax
|
||||
4. Fix typos
|
||||
5. Save en test: `npm run dev`
|
||||
|
||||
### Error Type 3: Inline Styles (moeten naar Tailwind)
|
||||
|
||||
**Wat:** Een component gebruikt `style={{...}}` ipv Tailwind classes.
|
||||
|
||||
**Bijv. in `components/Card.tsx`:**
|
||||
```tsx
|
||||
<div style={{
|
||||
padding: '20px',
|
||||
backgroundColor: '#f0f0f0',
|
||||
borderRadius: '8px',
|
||||
border: '1px solid #ccc'
|
||||
}}>
|
||||
Content
|
||||
</div>
|
||||
```
|
||||
|
||||
**Hoe te fixen:** Gebruik Cursor **Inline Edit (Ctrl+K)**
|
||||
|
||||
1. Open het bestand
|
||||
2. Selecteer de `style={{...}}` block
|
||||
3. Druk **Ctrl+K**
|
||||
4. Type:
|
||||
|
||||
```
|
||||
Converteer deze inline styles naar Tailwind CSS classes.
|
||||
Verwijder de style prop en voeg className toe.
|
||||
```
|
||||
|
||||
5. Cursor converteerd het naar:
|
||||
|
||||
```tsx
|
||||
<div className="p-5 bg-gray-100 rounded-lg border border-gray-300">
|
||||
Content
|
||||
</div>
|
||||
```
|
||||
|
||||
6. Accept en verify
|
||||
|
||||
**Tabel: Inline Styles → Tailwind Mapping**
|
||||
| Inline Style | Tailwind Class |
|
||||
|--------------|----------------|
|
||||
| `padding: '20px'` | `p-5` (4px × 5) |
|
||||
| `backgroundColor: '#f0f0f0'` | `bg-gray-100` |
|
||||
| `borderRadius: '8px'` | `rounded-lg` |
|
||||
| `border: '1px solid #ccc'` | `border border-gray-300` |
|
||||
| `marginBottom: '16px'` | `mb-4` |
|
||||
| `display: 'flex'` | `flex` |
|
||||
| `justifyContent: 'center'` | `justify-center` |
|
||||
|
||||
### Error Type 4: Missing Imports
|
||||
|
||||
**Wat:** Een component wordt gebruikt maar niet geïmporteerd.
|
||||
|
||||
**Bijv. in `app/page.tsx`:**
|
||||
```tsx
|
||||
export default function Home() {
|
||||
return <FeatureCards /> // FeatureCards is niet geïmporteerd!
|
||||
}
|
||||
```
|
||||
|
||||
**Hoe te vinden:**
|
||||
- Cursor geeft rode underline: "Cannot find name 'FeatureCards'"
|
||||
- Terminal error bij `npm run dev`
|
||||
|
||||
**Hoe te fixen:**
|
||||
- Voeg import bovenaan toe:
|
||||
|
||||
```tsx
|
||||
import FeatureCards from '@/components/FeatureCards';
|
||||
```
|
||||
|
||||
Of gebruik Cursor's **Quick Fix** (Ctrl+. op de fout).
|
||||
|
||||
---
|
||||
|
||||
## Debug-aanpak stap-voor-stap
|
||||
|
||||
### Stap 1: Installeer eerst alles
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
### Stap 2: Start dev server
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Lees ALLE errors van boven naar beneden.
|
||||
|
||||
### Stap 3: Fix errors één voor één
|
||||
|
||||
**Beginnen bij:**
|
||||
1. **npm install errors** (missing packages)
|
||||
2. **Syntax errors** (ESLint, typos)
|
||||
3. **Runtime errors** (module not found, missing imports)
|
||||
4. **Styling issues** (inline styles)
|
||||
|
||||
### Stap 4: Use Cursor Chat voor moeilijke errors
|
||||
|
||||
Druk **Ctrl+L** en beschrijf de error:
|
||||
|
||||
```
|
||||
Ik krijg deze error:
|
||||
Error: Cannot find module 'lucide-react'
|
||||
|
||||
Hoe fix ik dit?
|
||||
```
|
||||
|
||||
Cursor helpt je.
|
||||
|
||||
### Stap 5: Verify in browser
|
||||
|
||||
Na elke fix:
|
||||
1. Zorg dat `npm run dev` draait zonder errors
|
||||
2. Open http://localhost:3000
|
||||
3. Check visueel dat alles werkt
|
||||
4. Geen rode errors in console (F12 → Console tab)
|
||||
|
||||
---
|
||||
|
||||
## Checklist van errors om op te lossen
|
||||
|
||||
Zorg dat je ALLE deze punten fixt:
|
||||
|
||||
- [ ] **npm install errors** - Alle missing dependencies geïnstalleerd
|
||||
- [ ] **Syntax errors** - Alle closing tags toegevoegd, imports gecorrigeerd
|
||||
- [ ] **Missing imports** - Alle componenten die gebruikt worden zijn geïmporteerd
|
||||
- [ ] **Inline styles** - Minimaal 3 inline styles → Tailwind conversions
|
||||
- [ ] **ESLint warnings** - Geen rode/oranje squiggly lines meer
|
||||
- [ ] **Browser console** - Geen rood errors (F12)
|
||||
- [ ] **Visual check** - Website ziet er correct uit
|
||||
|
||||
---
|
||||
|
||||
## Tips per error-type
|
||||
|
||||
### Voor Missing Dependencies
|
||||
|
||||
```bash
|
||||
# Check welke packages ontbreken
|
||||
npm install
|
||||
|
||||
# Of installeer handmatig
|
||||
npm install [package-name]
|
||||
```
|
||||
|
||||
### Voor Syntax Errors
|
||||
|
||||
- **Controleer imports:** `import X from '@/components/X'` (check spelling)
|
||||
- **Controleer JSX closing:** Elke `<div>` moet `</div>` hebben
|
||||
- **Controleer quotes:** Tailwind classes moeten in dubbele quotes: `className="..."`
|
||||
|
||||
### Voor Inline Styles → Tailwind
|
||||
|
||||
Gebruik altijd Inline Edit (Ctrl+K):
|
||||
1. Select de `style={{...}}` code
|
||||
2. Ctrl+K
|
||||
3. Type: "Convert to Tailwind classes"
|
||||
4. Accept
|
||||
|
||||
Tailwind Cheat Sheet:
|
||||
- Padding: `p-2`, `p-4`, `p-8` (2, 4, 8 × 4px)
|
||||
- Margin: `m-2`, `mb-4`, `mt-2`
|
||||
- Background: `bg-white`, `bg-gray-100`, `bg-blue-500`
|
||||
- Border: `border`, `border-2`, `border-gray-300`
|
||||
- Radius: `rounded`, `rounded-lg`, `rounded-full`
|
||||
- Display: `flex`, `grid`, `block`
|
||||
- Colors: `text-white`, `bg-red-500`, `border-blue-300`
|
||||
|
||||
### Voor Missing Imports
|
||||
|
||||
Cursor's Quick Fix (Ctrl+.) werkt vaak:
|
||||
1. Klik op de rode error
|
||||
2. Druk Ctrl+.
|
||||
3. "Add import"
|
||||
|
||||
Of manual:
|
||||
```tsx
|
||||
import ComponentNaam from '@/components/ComponentNaam';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Submitting Your Work
|
||||
|
||||
### Voor Les 4:
|
||||
|
||||
Maak een **GitHub commit** en **push** het:
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "fix: debug all errors and convert styles to Tailwind"
|
||||
git push
|
||||
```
|
||||
|
||||
Post in Teams:
|
||||
1. **GitHub link** naar je debugged project
|
||||
2. **Screenshot** van je werkende website (http://localhost:3000)
|
||||
3. **Korte beschrijving:** Welke errors heb je gerepareerd?
|
||||
```
|
||||
- Fixed missing lucide-react dependency
|
||||
- Fixed typo in import statement (componenst → components)
|
||||
- Converted 5 inline styles to Tailwind classes
|
||||
- Added missing Hero import to page.tsx
|
||||
- Verified no ESLint errors
|
||||
```
|
||||
|
||||
### Checklist voor inlevering
|
||||
|
||||
- [ ] Alle npm/syntax/import errors zijn fixed
|
||||
- [ ] `npm run dev` draait zonder errors
|
||||
- [ ] http://localhost:3000 toont de website correct
|
||||
- [ ] Browser console (F12) toont geen errors
|
||||
- [ ] Minimaal 3 inline styles zijn converted naar Tailwind
|
||||
- [ ] Git commit is gemaakt
|
||||
- [ ] GitHub link gepost in Teams
|
||||
|
||||
---
|
||||
|
||||
## Bonus: Maak je eigen component (optioneel)
|
||||
|
||||
Na alle errors te hebben opgelost, voeg je **een eigen component** toe:
|
||||
|
||||
Ideeën:
|
||||
- Een "Newsletter Signup" sectie
|
||||
- Een "Call to Action" button bar
|
||||
- Een "Stats" sectiie met cijfers
|
||||
- Een "Testimonials" carousel
|
||||
- Een "FAQ" sectie met accordions
|
||||
|
||||
**Hoe:**
|
||||
1. Open Composer (Ctrl+Shift+I)
|
||||
2. Prompt:
|
||||
|
||||
```
|
||||
Maak een [ComponentNaam] component met:
|
||||
- [beschrijving]
|
||||
- Tailwind CSS styling
|
||||
- Responsive design
|
||||
- TypeScript types
|
||||
|
||||
Voeg het toe aan /components en importeer het in /app/page.tsx
|
||||
```
|
||||
|
||||
3. Accept en test
|
||||
|
||||
**Bonus punten!**
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting Debug Errors
|
||||
|
||||
### Error: "SyntaxError: Unexpected token"
|
||||
**Oorzaak:** Ontbrekende haakje, quote, of JSX closing tag
|
||||
**Fix:** Kijk naar de regel in de editor, controleer haakjes
|
||||
|
||||
### Error: "Cannot find module 'X'"
|
||||
**Oorzaak:** Package niet geïnstalleerd OF typo in import
|
||||
**Fix:**
|
||||
- Check spelling in import statement
|
||||
- Of: `npm install X`
|
||||
|
||||
### Error: "Cannot find name 'Component'"
|
||||
**Oorzaak:** Component niet geïmporteerd
|
||||
**Fix:** Voeg import toe boven het bestand
|
||||
|
||||
### Error in Browser Console (F12)
|
||||
**Oplossing:** Zeg dit tegen Cursor Chat:
|
||||
```
|
||||
Ik zie deze error in de browser console:
|
||||
[paste de error]
|
||||
|
||||
Wat betekent het en hoe fix ik het?
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Veel Succes!
|
||||
|
||||
Je gaat leren:
|
||||
- ✅ Debuggen met Cursor
|
||||
- ✅ Terminal errors lezen
|
||||
- ✅ Inline styles naar Tailwind converteren
|
||||
- ✅ Imports en dependencies beheren
|
||||
- ✅ Website testen in browser
|
||||
|
||||
Dit zijn essentiële vaardigheden als je echt met code werkt!
|
||||
|
||||
**Deadline:** Vóór Les 4 🚀
|
||||
@@ -1,225 +0,0 @@
|
||||
%PDF-1.4
|
||||
%<25><><EFBFBD><EFBFBD> ReportLab Generated PDF document (opensource)
|
||||
1 0 obj
|
||||
<<
|
||||
/F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 7 0 R /F5 13 0 R
|
||||
>>
|
||||
endobj
|
||||
2 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
3 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
4 0 obj
|
||||
<<
|
||||
/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
5 0 obj
|
||||
<<
|
||||
/Contents 18 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 17 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/Contents 19 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 17 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<<
|
||||
/BaseFont /Symbol /Name /F4 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
8 0 obj
|
||||
<<
|
||||
/Contents 20 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 17 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
9 0 obj
|
||||
<<
|
||||
/Contents 21 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 17 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
10 0 obj
|
||||
<<
|
||||
/Contents 22 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 17 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
11 0 obj
|
||||
<<
|
||||
/Contents 23 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 17 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
12 0 obj
|
||||
<<
|
||||
/Contents 24 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 17 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
13 0 obj
|
||||
<<
|
||||
/BaseFont /ZapfDingbats /Name /F5 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
14 0 obj
|
||||
<<
|
||||
/Contents 25 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 17 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
15 0 obj
|
||||
<<
|
||||
/PageMode /UseNone /Pages 17 0 R /Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
16 0 obj
|
||||
<<
|
||||
/Author (NOVI Hogeschool Utrecht) /CreationDate (D:20260607080655+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260607080655+00'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Subject (\(unspecified\)) /Title (Huiswerk) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
17 0 obj
|
||||
<<
|
||||
/Count 8 /Kids [ 5 0 R 6 0 R 8 0 R 9 0 R 10 0 R 11 0 R 12 0 R 14 0 R ] /Type /Pages
|
||||
>>
|
||||
endobj
|
||||
18 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1821
|
||||
>>
|
||||
stream
|
||||
Gau`T8TWWE'Ya0?]VCr6,?RJ:bcQlb`0iGrC*eX1/i8:'Zmefu.D+iJmfPLFX(A,!/ScL8]_-Uj),P^cjtiP1r&0,hk6r2_a]Djn$"<B7?;6$`J8iV1(]b5;MO4L&L&6LC(0HA<OYMn7BW?kh+bZ9rX^_e[cRHgIPQnic$Q'F$WR;q$bp'.K`d'iqkK#\0Od,D4q+a-@`/BK=UdHlkIjBb1=JsY6<J6%284>5#_o_cdT.f+s0f)gU>nf;HW_8O^fC4K8"i"BZRCP8%YqY8m0Y)bV1WNlk1mEqi7F`m82p8:K0]d.Ejc<r<f`]r`_FHFk:I=VI/h%W7E?rp'HgMbC4?!d;'t$N-OQ/c'30ipWaOjAum]Rq4_/R5X+>etC46tKD&W4O]:h)%oG7DcNPr'?6c@_/1YX1K1lC"IL758i\m.PX1DA=<2>R0Im_R/G,Fm"Phd9oA;2?#\n\Nl<El*9Y]&ZTQ@^$\#NFq)ZM'rUqJ1$Cg&:f!'sB&B`&,8QDt1!R@?+lO#k0f8`_Ej$8Rcd.`/FKpD4ia$M^Y_rP,Pi)TWMFa_()sk9p'o3X84cEI9hdcl@A-B0(CeS<`S,c+Qjg(tF'(1mNZ.@Pt@f`PWQT?f9`Z'XTN[,W'g]b'qh5cMjcpg2_jK&8B"ejZq.!kd*RO&M4:1._HN_#B+:-L&7033`I9,/[^S>M(iAui9nc($HS1mo:e-[E+`%Jl\<-+pS`Z?fdT6cj8h^F`/t#_/B'MgT.'e3Im]dGQDV*9P-So94)#F.&?IU>Fi$EK0,]egSDHUbQW9_!3k3@b@nfoDX,sM[rO0CRAU'M;-Cse,ksu#\#"A$/TOHYgpqOEb#\?3A\c6c`Ci_l&BZaT>(X\gq/6Z,Wj9<"i1OqZlmZFRmNX5X5sar?71#9m**6o]JXY4AiI%7N3R>k/;bA&S%i`Z;o,1ZDG5q3/BeK#__o/$ZUd\e\g>"(;\+.YQS?FLK*?Lt)oG2W)tp^*.s@!VXIDD-[ue5+F]hD)Bq:Xo,ia9jG_N^RlHRP]qE%'NoGpM(6%[K`<\R6!bfiFO=@`gY05Q0caS3];21p)ol<SXtfbtN(<`il&ef,Pl>kcN#WSqGcoYeA<FkY?U*2EEC-dcnP#>^6K[k<T+ZJM-BI$;Y8LsNp1771FF%Y_ssXS7Dt[8TUIkA;$nGs07XYKF.9!#1?+;637/:6leMoCMVF]UkqNR=U2DkLaV6M!V0_R:3E&pBAFX30d@gW_0MGhkR&%iBLYn,MRn[l`rHKof"FY@$@C>8Wr0GR@V4<b=de+Mg\Xn'&Xg"IBEP>MB:GPr16ngAnR4M&Z9d5Er=E<>Vfd:$rt'ggs:C0r^7K^Mo<e_QqcN_.4m#Q_3MRflF*7c#EO(0L<&WKCH(l4F`!esDPing(j.q%Y[$Tk$XO<;EF`eDG5DI`iVO)A><=M(A-)<+S.uPm09U$Jo`*&LVcTaqZ+:qu/f%D>c#0k)YGXP<c=!A*(l"eFD/.a<g:&`rT5:c@fR#0_'9gY@!t$*IX+ks6^-5\1hjC;tc0i_50P$k(%A_fi#Y&gD`0PQ@DZ/+Eih7GXh*eEs##[Bb;g6SAq/MqOOK.i.me;\&FR5IVok+u47,aq^'6$HHFdp#HrCZ?C<!*Sa"/?pnVOeXt]\JmW]aiQ8g7KIonNXYMI<GD+$+OsY-$jW)mY>;4HF[Zlc'5kWgpIqf)c*,Q6K;cASSfbEf[.kG*Ba@4W-uJ"g`S2T>r-I#eoX<e`**-?a-tprPR/VQ(`u!iUkb:MSgCqN!E-ct_<K9B8*_OtBZ9da@ne$92X2OB_pp)D6guc!'C1M~>endstream
|
||||
endobj
|
||||
19 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1764
|
||||
>>
|
||||
stream
|
||||
Gb"/'>Bedj&:WeDbZgXF=gY6[NRRU.EH1A&[2YTA*rJi;/@')sU8s"#aiT&$lll`E"p6#/H&1E%H*oa.q.<)1*;iY1Rg]=(p7Qh%JMQEuJ9&N#pDUWVepf9gHkpZ3L`8Bm`.17Yq#cnj,^;NC,8O,^SUc@o#9HbUL/A3bcNO=Y5RA8iDc%X.mfXd=&lR$drMB*<nJO^FS9Vai/Y90,$]TBCnLNj#bioq#i=9$?ePLBKEMs[ucl9j<l.KDkE*T359Wj9tLHi0ZagHjr`WGr2"F^prOV]79SjDfLHI!%Q3MP<,`"/Br+jo=i<k]=6G"UkW36btBClZ@O1gs+qB9c^&o1A.+*)43)_K5Vqn.!G3&K8c[JQX'8r#KR_&YMQBjD?X$%sU=ah;NG1+0a[X"gs##3&lX)@F\GUW3FW&;T4Vd1g!fG,IcBNOGhP8d2,mEoL3d@kIH\RW:n`J%cBrQ:u]36-fF'mf0/MlS=Oh1GG0A4IWg1fH!5S[G[NWp2:gc0d<N;Y*k*:6>2saj.MVOC7fm?/Ia?.lP:8u<8BAN,8LDRhjPap?3=V=C4kX?=7/(hiCp[a*EK^"6$ROe#05Z/BW4n!c>cD^dX!*["a-0sl.\r0;C`a$bS0We6]"D7CoGnA#=@&orFHF_"TiJ-X7r8qf[rEn=9j,P+&nD)c1&`<h)dBE7QSX=@l`]?c6on!sj.=f+dJs86aW*+W5+Ze`$#MB"_RfSk#]@.XDE]]@,n5Hk6FrD+P_O:?f6UZJLW%Lm8>.E\&0WD[DEf,A&u59ni)$KPgOClKX^mF\m!M"qC0k*gc1tIbQ9n`7L7lO!nRJk"]?dG2::e+On.$+J=[*9bLdX[]S-tF4L-[P[r=1AE^q<Wb<[F6U_iIR$6$B^if4M\"XE[TUGnK>gaN(%4>c/Vs7DFO^!b!.Q7kecL+IG%qc!&u`TjnSXQC=tn-Ot?Pq3A2@PI-c9QWYO*In5<'P1NZ=*u_#$O6=_5Dc%.#Tj;]-1QJ/o+E2uil(".UeWH8iZeM9uh6MHiq:(Md6=fKLOKcTl3B'>O@[-]5e[-,>gbXeCSEHpti"9=8XHBnDp/iPB#;5G@Npjb9QA@EpIT2P63NCMqjFt;43%`_^cqI8S?I75*[!D'*+t>JS&$CU'BFq[3&LnOL4KLquFn(M)'8cg$\6Wf&\nk3Z\/Xigo?6K4667Z*nS$DnRCYG[bVas(%C4<>3,uLtIEfM)A`*6Z>Cq%1Baj=Sq=1H^F#!]0Dere5#:;X30j/DRHC#3kia6!+8(Ugun/bnr[4W_PJ:T2)nBFbr)I#hiSj*%k7#6DS%a:M-)'CnKf09)m>qj1.)7)!/$f81QC)UJg/(/H.2(_q=?7j\7K`8sXLU"3l(YTXZ[L;uL]'(`^U`'S<>6e0U(P(nK:jFBVBjaF&1L6q4WgDR?_dB=*Da"(>?K:Z]bs8HcT)iOU.W(p_`gJ`APD_74Eq:oP@DVurA::21DK;#RI(*>ih0h8?Y3peL;n_poESAQ2^L]@5+O(i0oS4'Ya?biA=$kRoD"@2f..m8.*SWh@IlHc]1u?:"]+Wc!bPiDcpg/&^2pd9IVTWBk[463*>Vkb6!0oA=EbW@3*Eqeu2nji\CcC11Z9)9l=23D*ZF:>b]FAt%G:IkSnO+4LBT0=chN4g,39n_3#^`$Wh%#rG;ek5Whrhl#Mo3CA@29)oEL+AY6G(@4(g6rcoVi&6k5FP=4\I$q&+ABh69]d!,*Ip4N>abt`+:C?7E7d]J)=\WL&~>endstream
|
||||
endobj
|
||||
20 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1892
|
||||
>>
|
||||
stream
|
||||
Gb!SlD0+/q&H;*)Ylc(%[(4t]FJhf@#"!jI"U]86Q[DZ+Mk`\+<(V?cPQ0LigW=Ui4392'Bq-;fhL0SADP,as@mKS%l@4F(^oIcX^L=o;9TFZq,%:%(lqKs!NsKs?Oq&%sWUMkY:K0Q?:Ib^N/oa&B1!il3XX$H^Lt8.%Nd=;P"hB3EB-RUK\Q!8L6o2m6mO`iQ>gCa(,`_2:bPJ>j\oQ+ADX/=Sg&*$29!C3%M^g!GbY\jDAha5Rn]O,/9;eWm:=:tR5Khgb-RBaQY2JD*]J^QQ:,A(uKukc;SlH!W5c)Y[X/K2)I<Q_IQR4q4;#]s^;<!4q6hl=5fKm$[oh,UXBST3MHMi*7#R+AIZ?lAVhr&n/.Up9Lhg>dk=4-79JLH*'b4Ze%$B9[[QDKF0b$o_LcU1SG=05#K1Yu:(Co)&&oa#b\"jo9G..^\K48Wi7TN\r>/iF'r\-K@&<2s)F3u3mQVNkUTA<XnW<)PS<U-"cNAB,O.L_,q'nbeauNi_TSi/Dr@OS-DL+B8@RNu1_tc[AN70\Y7g7^R@d`Y[rVX5?Frs#1dcN9V[l5#!Y1lf-H*U-uKT3k*HWnMoP]GbUerHI^'NK[Br;j`PC2J,Qr>$TgMA&)g'T@AO3jq-b*ddiE\MBm011kOm!#8#4Y'\&q3iE&Ptio-E*cj"s8fa2bR`Cr11lknAYk3,'G&r3IJ7k66J$c&P>M\3fE`IFMf\'bk@%L%%&-Jg]k=KHNm+hLOD:]N?i30or?Od[JrcP7e2.?Di/$9=0[ooO8KK*KO>5h4*<j;?J3\^$*Ta4"Z"d7ppRWNq2f*%!Ktg,0aPai;6(c,mO([#RfC3\'3m)IQMp<aEh&>*N\/3a0biW9B=BCeK!;?d-2d?7AI/c:#(cDGIX&t0dD<'9%oTchNFG2Q-a=ZqI=+M3&)^!RA0>;E6o.oqjYO@mgr-)BfJ!&Wmj!^YmF$4EX9plo%t/l6HIErXh6ZOe)5%:m/3?k0('94Iou'@oCK:ml/!]\R]sLt<:UMr4Y/T@f9s2*P<TNLB'D;-oXOhh]ib^%;9*,:]ihq"0ip*aS#'kRH4RTLW]/ZKgRIR9mD3ISlT=k'KjK>$ikjb.p\lnWs/HHD9tCB=hp5`j8+C/TKWofB!(#rfKdk+!>K[hH?Ugr%6gbj/Z96A3bL]0tV@DMiItlc&2.W?`fn(hFT.9RbkhiM65E%=6h[AdkKQV:<(>p6%&rI80lT[W[A@,sY;"I(q1nbn=/<LpU's\n5Obu^'`=g:QclS/>[_=P[(:IoL-J.DNo1.K""%UhBC$o>H0oAP+D+%+.'i3Qn@Ja^`"Jq0.j;+p`=uq'9rL`lX1'gQSej[X?dIHlm3/,Q2cc@H>9*%cb,89N2]6uhUWbU;UjeCr^GMK$C5l48_J`$?-L?G8Tqd(W!K%"N'3`+/_4did`[WZj6/L,!J=0Ic1??PKU@/8Ji8\#_,dg%"BmRCTl19(enEb1UG\9r]u2-'E,<T\>@"f<21cDSWr,'2NmGZ&igV/O@RWL6[gVQ.,F][NCSQVQ/%4Qs/VYT8`MSn/E9=5YVL_\VWYYLXOSLi5'%!VCMVck^INY#ZOn2]6<eqZ8ok6aJcdG<O8V3t'cc`IGt)e!0`tT226C<Eb^QX>9-[%]e&@g6+h]m57NR'j9m1,OTPf2WD/;Q08csZY69"7>Z`,m8Jf^i5=WFn/%=u)P&mRWn.-+J#Bfkd@(FoC0YI%lAJc(AI^o=*>&N/D:P*JCoq#R3#Jgk9J@Y)mS'j$Xqm\I$=I.N9c[Mg%eg01Za/FdN;)l_GC7q<$02T/O,="\#lCqZc-'S#`*6;bm0S3nA^"M1H2A(`&%eUMCkYO+ck<5#]hAa=l6q`^VA_K0NiLp:p8Q4e)b0i/$W'G\~>endstream
|
||||
endobj
|
||||
21 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1651
|
||||
>>
|
||||
stream
|
||||
Gb"/'968iG&AIa;CickO-4g0?!9nYf9q6Hk),F2_8kutE1*k>C5QrE5HTM,o?19/_Q7U/*A9s&<,XGo0mI%FoL]PIR.t:&FJ@>XET.s^n#%M$^nR-;Gmg%->LN()+k6#]+l@p9Lkh6i?M5.m'7"d[5&5Yq"l%'X)&d2VC*9To8,T$^FQOX*A"dOWD,[e=l`2!,\&Y.n0*q=pi+3q(["VtE87#_[b<Z`$1:U"$%<iYHtb'`Hk?j=;/5(354+4?"g7Q5%M^usLOd7k*<c6^.!#k-80-0\[&@i4"<i2'_P,LdBc#YF-XcjrR8rN4;NP4E6BM0/r-8&>FuYRr%'ND$j7"?uM*oQ\!S#R/P3AYo5"B4qfj2($!8QjNEA`jZ<WZ%d:arg?tTe;NJ\r]HVtP%T"3]gb9UA-LCb:dP:Q=s"q:_C,cq3itPGcF6Pid*%+>3$,r\nYE6+hMrnB(Jm253Rk?$&F*-G*=80I7SZ&-qa_>hGq#a2$OGkhJk!6ledo.og(>%,]LX#sC'C0_F=E/$f,?Yk#q!KH(2H'_WQk!UjP2^@]C!3STlin.7M-q4c-q].6P=FZ"h61I0'>OB,'>h?9b,ci*#2$Tj$Jgt37Z+$R2YdRa7.E$:,]sK)Td_,.1@n@o"o)8oh7f!U.uqSSO*97kkALs.*b)u.Yij!]"X\;$qcrRT:TAj3SLn?h8XQqe!<rkQaAk]_tkZb/,o9,U^D,GMca=:]pZ]R\-pknN0^plVm&WID_kTR+-RFVn86Bl42;jl.5uj#)=\RP=D+b6D8B8,T,&bH%D#/kF"ljdJc`&`P$"auG]=X9SK`(#;P9eQJtoKDO'ZXUKt;b(e[OX%[P$GHPaPr\9gBSK(:]6?+([W!T7JFJ#12?AMMk4)c4B_0;f`r9mDM\*5*q\ph)fuSnk5u0&=9p0Y0r$P;5>@2eRP@jG(`MFn,!':_W.e`*%^`PZ":mo`Nn(Q\ZIW3B^6%tdrl5/ZG(BOkpGQH,:i#-Csj1@rSAWmGZ-,`BDn)Hn]S@OmPE]\C@<kU1reU!AVt^><A$AUi*hsm;8f4YSAe5"dKo-SY]lP*jC\PY*2=LnBorpeanDUOVj(#Eq%iPT#<^tQ&*t?MU5cLb,NVoV]MhnNj>@.W4ISU&8+Y>j1c;K(flj/4p4OG/XBPDXEHApB,sb.LoIb,P?mkG@j4[(V731lej^9aIm9&-d,Z9BrO,,o'7+rOo=8phfB.e'Z)Y5&($N(%r=E^&>aHTi/CiVFrJGI.H;Z%ZR@7d]+;-@CX*m3(3HWT<MV)!::If@&rRPIuQ<A)HN[YGGQ;+`A*WHUn+>_HB"hp+[b`$Y6`(N)@&rG&R9Ed>1t0JD5!4qB]K[gG(Z=9<=u\O686K\opJO7l;XLZmXJAj:RJr\L9OC!T!W3a&G*adUX>MmFtc':;:bBf&]?nG%k=KQdumq$nm$cVsZ1?K]_lAo6F4T#WmA"o8*ZI9KX"&67O,<9;G)org^F1%#6)HT&Pi&d@CR0uXU`.qj<923:W"Ih;:d*RoS9U\"AY<$f]p[8-U$g[-e?CA5hR;K(?q0NT;R.=*B23E('1%&Z$]?KK(-Wo>;<SZ]KlagB,k(YYHDqE%VL+#W.kj*gpJHo?9(^J[dR416_d$1M@U"m8*q*X?W~>endstream
|
||||
endobj
|
||||
22 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1859
|
||||
>>
|
||||
stream
|
||||
Gb!;d=``=U&:W67fU4p*aj_"*hL9/Pa(a=KP%Lf,R7;Ip8Q^R5!=T7eZ%%1gVeA`Q&Sp0&dYJNr4[/4d-",`%']7:Hi:RWcD[?s^_^ck<@DhRC:56H#4bL>qZQ1_Nhm<Fl7UY=2:ue,Ia#2Y&"pB>&1ORLQgF%aE#<ku>kBXuJ`Sg#mO+?3"VWZ]Apr%0#GA4g'\<J1QgMgCVGeCeScd0Q<%(DB0`@O5E$s/N_WJ7Ea)^]Pe#DP%uJ,"8.$Ld&CA^Nog"THo.72$+T8j.EA$?+Q+94Z2p$Q*3fn7Bn<7FZL;iHhBqOQa;:cYf/>Q;mhha'=;UZm^;g#\t&*XlOLc)c7d[6JjST8HK^uBq?Wr3BfS/e=[;3#;GJsSl]CUN$UXA2tN#eU#l>[_mE.A4lY(/U>B@EB6_@;m"/2"()R)FMSh!%H_aip8C3;<WPtL*LVJ5O2/Ot%R1!=ucWga>i1EKiCB$Vi`QtJAknSr;^WZ3i]X8k1%+[95as:.<Q?+D&"ktb:bO^Y`3h=,en`qpJm%+5V8ueZ:k?[Pb/AneB/[q>d)rN[i6>F$i,)2MEk6ZcnA019.*@_goqHuHXMEp@USWiDH<BgjIPNW2J47F];>lV+W^<cssqoV&=b0NF.0bI]e?+@RN\p]TIs*1\%WF3T+<5URL*\^gCNr!U9U^RfqT,l^$_&'Wu-eLZ8@1(9l>VO.#mXP\T<:Vqoi0@SWR/W.^r?2<09FI)G3a"=k`M%I5Q!$f42VAY=9an/uUMj;CFIc::"/NB0V#*u)Z\hL8Ve'lpObKG[UnIas`:#\8:iOK=XBa6kkmZ'HT]=g,;t^,R`$u2+L3k@YVFn&73[I2gh?sU2$P4)DFu"f5.2+D_3^"Ai&fHDF6tZ;:1/2hL<cfuu=^,Q.InZp'$&b["_m;@58TDaYP->Acr2&!n[MQXD/bJlo[=2V1=A$S537%/_&P8*VN67pp>BId*?L<OF7auE"=`QA%a45>R?B/>Cao/1h!'.tTnjJ+6XIRW.Bf3XgS8JFA;>eel=XH8[E"e+4EB+,hJnC+c/7W.1`3^Q"/^R7s2hBtW_5joKP;8o1F.r+`0T,-I_Pfn-r-*skKUDY@aV"'U:*D2u3/%';_/.._q?=UaQ:K[qP`&51j0cd84-gr)/+cH$nLW]EY>[+j`CrZ>4a"t<QK+8-),p&DVaW;2%AB6B*WS79'0?'*!LjA^43'gGis`;*@s3K3n^#!`WDkq!.?[<nnHOrV.Xa46C0l8&k^@"\Q+!538XpTunAgnP"Q`P+q,G86<+o*Ic`]cK;$EX&?odZHJQ;<q"'DHFiIX@mmkE:oJEf96HkqGC-6M)N\pMjBL-3#kDZlGTDOAR+-BWFRFiQW6'Kg/;Hbf76r/;#jThl'&_,Z:Lq04#^-nm_nhr];K:@96[2hMuP;p8_hoo,T8mOtl\/oN1]jjB'GN9bRk'IPErM\[)S#fYY^\A/.Zr@,l>PSGnM`@`s,29J'p)@F9E@ZcC*?`l[V.kQY^7D#P"d\=HUcTehc)Y,_;[(b*2lFW9t0!)#3[.llM6@9sH11#b62m$h&ZP:?Ss*faF$hD</l*NNGq9uXJdr^t)X'4"Dd#@$+VWL\'@;89U"Yk)7l^9h.Nb:>[AW`]go+R?)XkTSBOG;.>*+RWb6=23#I8H5JBNDO@`U/"OgU3SKb)]U]E=BoB#t6ra2'9$be8@mdMqKbKSqeM[Z*0Yn;oIC^CK)&/anhl%F60?9eK&NHs/h5J=2eU\Y\GJBK<2)iUSZ?7\=lhRK[4V6nD\]^l_#[DZbbgWV<t%,&^_ap=b;KXr4bg.RfN?ar,[:]=9e.<pYhOY<&J*NQRhLRAVu)r5Nff*cN~>endstream
|
||||
endobj
|
||||
23 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1789
|
||||
>>
|
||||
stream
|
||||
Gb!#]=`<%S&:XAW(uuu<RkQ*V8Q6H/[S<rupVtt,!e-7Xg/b>nV5-"8dJpr1D+ClV]34UV6'T`;IWLT<'>Wm-o&!1Bn8&6j0*r0sUF?b/(l[=gMp^JK!)\B;9F%A5XB?7!V.D<AZU"l.JIIH?"?8:O2]4;E&Eaf6Wq]8OQllQ+*t8Jue%d;CJ2kpcDRB0rA5K:*1SbtEFdKkMO([TXa=+/hAemU'R%b_";mfSa+\ZuVLJ\&hpE)S+_<Yb]@V6`N55^g>iQMrP;ej1u.sN\\#sVT#Glj`o0RAs4=:r[aJd`<^lU"sV?Mn*M73Ucf4nCuZN"lYk'SJ'M9T:7!A#>o#+63:Z_M()X3"H(m6W!;'<""^<0j1au"3YLCIn;/QGuTQ/@[_'JY1ffdU_CU:V5c,NOO?Zg[/?%B(g][?+sUG#$").0&b/;mWGu\Z,MVh)H_Ch-Do],=+c&N16L[<\e&b#QU1/h>=0$ReNq[]>SfAo,N`o2*]&S`8/&3lD!?@4'Y.N$)n?ErsT#::_MBlG\^)%-d:2YLA6"q]N-QH(@-pP6eU;gSN(i%5'^1MYCFf23L4jpOP7&JfBCd7I(\<YGp>Yer0n1p.*j#?"^MiC3Uq.a<M?bRH46R43K)bjkQ/B1<2k'SI\q0K0kbt5\cX^$djcp%9q6RCI4T<0A^,$/S;M?A2:^M+4n)biD*7M5PM*mb/^5jRA0h9U`$m8@3)O_Ql5KM3MF>)fB7*uakp`&lPf]D\7Hl8W7@o^?]ZVu([p)Rmo#YS4O<$^('p$;B>u'-dW%DB#XAmFW7>g90aqZh>HI4JR,4_.a,dlU/TpI:YO:Vnc%B8n1R9.+n*&I'P&XXTKUMXF!_GSNsoqV)f<uE=D^%(ejc+)'l&[DNIP8305Uq4+d+KFqukOV4lWJC,.mJ55,\057WQk-LKPDJoNI'M4]Y]]d3$c:,`Z<?);=<llt[$fn!AAh?/S(Y"psAPW?b;<nK6X37o]d42U]Hm<WKe)*?/2iSKVb8U0CDqU82<hqrV@38heApY-LUHh#OnDqhcrI;s<m&2WSDJ9KpBc=._fs._<Q';`mnO(:b$-/p9)TpnW=14$-9<`E\fd(1]Jj2$T"#9F<2H#]q2%<*%5,FQLE%sSN__LQiuauGR)0mlSVB)s[!Rqf/pitKKd-5-)cgP[,n3K<Ddj#tVfdq?\TF4PWsWt@<pAj`.h@iG\&,Isqf%Q:ue3Vkk)klQ_js4\bnT)igo-]Xe0/pMZ,lu8)^d9d`45"m-(_pnB=QU@m2RN1Q-cP7UTM.I63SctA3($:#I6W@.Q('F_OR`4r4^#fhB`u/Bn<8WfV#W$;"Y4.=g):WF?c%T-s.5=6@@3no0TN8)l<d`T<*tVt'ShK&k#A:=^<SP0k%Q@FQ/<-4FT?^h.aDZ()GL[EbY]=\_h^I6r8dm7];*p9=R9c*od>#h84[Tf.mqk.:WJgm<rr(WO<o`d/K&b`Hgnq6-8nF`n;I"pURio>K/ID7iKM`ORId9[c*4elmJX7WbMuPk2-2\M"br^&X!B*t1q"8LdXb_Q$87TM<(%48rfaA?8XL?l`2[j&=am4$M.V&mEedU<LYY=)&Mf-8rR\B8%E.g*Cs7_5Gl\H4+f?-rl`_lE/lVY,`U=t3F-*,;eT=RAT(#0)4NNNAMX/7%=oiRg;lc`#;<aC#o&*VrF$B+8oR[U.q$TJOPB^4DYW/Z"acG9/P@dB#ic7\A(Mn?L/6=7:<45-iT[A.9dlJ1+A,1K"c-dg5o`lBK&Z>V*[_@GS;)%2(H!,=D"-i~>endstream
|
||||
endobj
|
||||
24 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1994
|
||||
>>
|
||||
stream
|
||||
Gb!;d>?BQ=&:Vs/R+%t?]-rsr>;e-]-sIJ4[^7U=mR,G.j+p+]=C0[3dU0a6a1%.'$-R?)P(OE:)U149q.;Gt*.60)IlmgX4+tE^"j14t$'Z)5_tWY<f_`9NR*Pp0J@L0jL($W:g-79T?4*9"r/cUH!_8>;E8UaC5nF79E1IP>J<=gHVFQ1Ch[oko&l?mbr0?q-nJT6H3UqJ]]YD2/0<j_q`36O82&C0FL,3KHWfcRei_WEq0UtH/o],*J37\b2a&B)Rpp2Y0Sea"h9YeINr$lVqU,-Li_se"fDsRZKU"lQa(QMT5H9>:)XYeW;.A*>k8g=lf$"mqg'tsOl+bAfq1d1j)PWpfDPYQ0i-a:Sop%eZu]3)AX.34Zoi)[t9&Z]K/DXCB.UgR7mmSr-0SQ<]]KX=&PX57FirSLRo4MQD7V:XfM/Y5/%;.STW_H:-g-PJLpbigPp(E8XU;tM>[f`U`La5K1BNKe-@e\qmNRjb[XmHK_sfRC?O<?Yf#T,'l(58YY,NfpBeMga2sSC-XSG'FWU\.::2j/ha^2@/Zd7[?nQ2_(BbYF+?'R9WCH`b:RR<*i\]9VdeRKGHE)?WM81];MFMlKE4)$&)_U&"sIBI:S],\Zh$(QQFQe@31Ga0^E^%(<k9e,s<;/G%!J^d$INJmYL:%:sXuFc'SbgBfTKKWh+uAf4>dbQ12Sk-8c\u,:KSjP4U.76.#G\Bn\S7?83'^csgrt?*!WMReC7HS+]Gm[]c-7>R8O5JRh`"9ul]G#oR;<G_11qF_OEk!3c\ul5Krr9]\8q)NoBI`cBDH-n[3\1OI^%phi6Oej?o;HrgIFAJTKX#*je/AU'pl0;:eYA;VA_O#;ro(hs4R7uK$9h]FT!YC=%fX:P!h,$t\`24D'.&M@Q6eIH_J,Op/B_*d%?fd&%jQcL-R%Dt^_[jiCcS4%WToBjC4]$mOa<qsLUgp,tG1qEmP_R!o"8WeMW0!p'c1-\F,/es7<27u##YL%`VYhP8*R_\IsDZU<gL+^R/rc9mKnC$M.P93P2I%;[-f8\A$)@k5s6'*$GW6('iZ]5qcA4K7_Vr5Z/'k3r(/gVR8!UXdU0]?4"FBSGVp^.6t+sG3CKD[>RU2P\,jV9e)='$hUg47h=&J3L!6*9n8S/(8!XC./K!El6"":\t7,#R-sA;ILI,#uF&N=9:I*SG!3#l]2eB_U66f5$R57^l,E>rG\KXGtn>$[MaCiGJ>C)=Le)DfbPXXOCE%[bNm;D"P;*4Mbdsa0'Q;kC_LV[56;C.TNf'9!E&6:(1\:a%bD=$f=!DCo_`OOhTK.faDSCRo!bm:cWh99lReRLjqlnrruGNEC!,5#-'7CL,,4"*n617.EB%D(T\m?[1h=LBI5js,(=$ao)?fJ>//VP4Pto)BRO)X9/ViG>NfJMl)[_V=XI@U(9M2cmqB-Se"9)@fp#M`0VgKUn1RTYSPATKSJOM#'d+l)c&210n+KC<=B9hr0bdgZ56-8DCtkM@^r]^$OmBRBk)Gi+K_`9ed15ik$clH=ck3HVj_^U1U-KJY=-I`t]n.5FPEIR\4-eG.nY"UiqB35_nHpo27A3YiLs4&f7jYZd]J/H4Z]p-27&!^`QZ?lII0!KK"?2QjTk6>c;1]YFaQRn%PF%e`8m"RgB6AHa%Z=dI"ikjGGK;k)q`@X34bUl1fX3"gLHU[iSu.59OHsIidnX6ER%YH/D=XrCl_o;8R,k1:WOaX03r/66EY%D/4q?0lK:%Nrf5<]>TgM3jrWd9tlF<X+3@3K9O8,6W9j<T<@POk0TGb"O[H:-2<bk0p<g_A(ouq81`9#^e>1p>5CH,N)I6"BeT[P<XII38?8.Aj+Y*%q'K_$<oV8POldV[$Rh7e!1a1'YY[1:O/b:ChXgZAb>]KQ$Wk,<F*DJZL@`sQ:2Q5f7@Qc\jOW3!6%^g1,Y&*o@+[[$&Ug('U*-q[ppFpC=abt!Uq?mjnZ?k?o&?qi<BX9ZFg!'$N7gA~>endstream
|
||||
endobj
|
||||
25 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1676
|
||||
>>
|
||||
stream
|
||||
Gb!#\a`?,q&A@B[H?+k*8hgGS!h_2FYoQo9UrGtp=_brtTI?2%7=bdP3KCk')Vi$IVUl_Z1*mLqj`R?qJHT5*On+"/"PB<]lTG<&_W1t.Eu7S7_V<2rkK'?e$Kd!$8_4=u3.Y`B+HK#2I.$KS"pC_P*%;^Y8K9/]#o(tt5m66UNa@_O3.eb/12nN/\`B+.HOcqf<AV\Y4Lho8[SL)u!f,CYTpaFML#EG<44QsrR,\fdpb5jfpof<gqsZ4r<>!K^/;:8S=4,g=+f,7sm),te;/*I:q$WQ0_rRXockFP]EO]u,H(j]X8b#I8Mb;-i0MZ]qZ7"Te6?pU)iOP!@?&$_dD7@/`\PNLH/V?=C&2`]!Gh%[e@a_U8"_MV!]gj$(AQ6^g3G2^V6KZk5[>LW'DidZ<97@OCC1TYE0WHgn[!]T\NRJ(B6@3t4V"B7#gR2@aYZbh;oH,#8lZB\?j"]t+>useZS@'#b6d8iiarI7CD3I(d:K(8$_O3g4Qt+Tf$ub`"bDViajW<kp67U4rYFABu,tbJMUsupYcbB>.-9SD[IF[V)V';[H@'YL7cN`%_d[j1r'O+;T3\"F"HI7E96'e-siF8k;e"tA-%^_Yd$;Hm:R,a-8oa6/N1P;%\#i:(,!E#:#(.&\S:bQ`dN;&Lab9B.r`s^7&QikLT<NK(h[/I.>M95<i&7sSV=fT%R5H[rr#`ULiK84%de2fC)Piru9Ze7B>nGL>u!AX+m[OEQimNMB?7Z/s$TG(lZ<em8"FCE&9!]G[`4YXWPR>!J#Y-Qi!%a%e[\#%G!IG8[;$E<n6[IB7`Z-c+'3'JLKoQ8oh*:D$N[")V^daVlH#8P*he5GPS-*l^k'=rBdifGZ(k@goQ\_"c)YEnBaR3h?4Gl;:Gi<rq@2sG:<HYFipoJN@,A5=r*+(7sQ-M2L^R1n\Z)H>>&AL_R1a^baUfa0Rl3Js;8dgbtdJ9.<0=M/KgDs,fW6KRF+0!M@miHUF1_\WEV+n?[NYHT\4`c)fo^C_hEouKR2"DDG=(MN$X4>`PN;JVJ/&JEN\j:IX\*!pG.X`gEbYTm\k%eXg(JE;Rn;3BaZ/0-J0g4e?ZbE09p10=*<A2>SOFgH`G#kqINWYl27J;TM,=2G-?-aa_s,:KShOcJq#PeGgh-d:t"79G@WkC_OB>-ID-l+TW^q5@j#p=5CH%tZQ<ORLaX]GFqUR8=C;GIRh2''fE!S0\NsoGKRP-FL'l:[@A)WpJHNR\VkT4jO]]V3T,O<afE9g%hbcJ$33O&S-7\YY-q$C9CV:pX!e@A(cbhpS$E'\1s&-;b.[IjNe8?JhGkm:`c5eEDd^"c2IN;dVfJLd$HUFojRo*VO/eq`OBT3mhNba@[!fsklFb6#gqnJ"V\Bt0)'(FGD"oJSpt(7^/1oriTbeuX47j3W2`tO:^!CTS`?9D7r`pNng,?JdqXdVQnrAI?fS^FT?d+)f;#jiYE9hTjFk;<TNE4:-=N):ZGZpIh2+I=OC&C8s.9W/#G^?;Ke8uS[Bdh=*@2!7<6]=_iQ:od,=1g)9oB/OQ$n=;0OXdYHf&d+:&Nqp<I5N"dog^m5nsP]Zih8HLMZA]o5^/8F+k3W0J23"gSoUKAh-lG@<8i;_9@Fq6<LFfglh'lWc2Qob8%,Rd,U_rjR<cQKf*+]&Eo[u0_u=[OkO%~>endstream
|
||||
endobj
|
||||
xref
|
||||
0 26
|
||||
0000000000 65535 f
|
||||
0000000061 00000 n
|
||||
0000000133 00000 n
|
||||
0000000240 00000 n
|
||||
0000000352 00000 n
|
||||
0000000457 00000 n
|
||||
0000000662 00000 n
|
||||
0000000867 00000 n
|
||||
0000000944 00000 n
|
||||
0000001149 00000 n
|
||||
0000001354 00000 n
|
||||
0000001560 00000 n
|
||||
0000001766 00000 n
|
||||
0000001972 00000 n
|
||||
0000002056 00000 n
|
||||
0000002262 00000 n
|
||||
0000002332 00000 n
|
||||
0000002618 00000 n
|
||||
0000002724 00000 n
|
||||
0000004637 00000 n
|
||||
0000006493 00000 n
|
||||
0000008477 00000 n
|
||||
0000010220 00000 n
|
||||
0000012171 00000 n
|
||||
0000014052 00000 n
|
||||
0000016138 00000 n
|
||||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<523578e4abc2fdb4125b5ff1e456104b><523578e4abc2fdb4125b5ff1e456104b>]
|
||||
% ReportLab generated PDF document -- digest (opensource)
|
||||
|
||||
/Info 16 0 R
|
||||
/Root 15 0 R
|
||||
/Size 26
|
||||
>>
|
||||
startxref
|
||||
17906
|
||||
%%EOF
|
||||
@@ -1,231 +0,0 @@
|
||||
%PDF-1.4
|
||||
%<25><><EFBFBD><EFBFBD> ReportLab Generated PDF document (opensource)
|
||||
1 0 obj
|
||||
<<
|
||||
/F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 5 0 R /F5 6 0 R /F6 9 0 R
|
||||
>>
|
||||
endobj
|
||||
2 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
3 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
4 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica-Oblique /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
5 0 obj
|
||||
<<
|
||||
/BaseFont /ZapfDingbats /Name /F4 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F5 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<<
|
||||
/Contents 19 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 18 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
8 0 obj
|
||||
<<
|
||||
/Contents 20 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 18 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
9 0 obj
|
||||
<<
|
||||
/BaseFont /Symbol /Name /F6 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
10 0 obj
|
||||
<<
|
||||
/Contents 21 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 18 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
11 0 obj
|
||||
<<
|
||||
/Contents 22 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 18 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
12 0 obj
|
||||
<<
|
||||
/Contents 23 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 18 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
13 0 obj
|
||||
<<
|
||||
/Contents 24 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 18 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
14 0 obj
|
||||
<<
|
||||
/Contents 25 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 18 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
15 0 obj
|
||||
<<
|
||||
/Contents 26 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 18 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
16 0 obj
|
||||
<<
|
||||
/PageMode /UseNone /Pages 18 0 R /Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
17 0 obj
|
||||
<<
|
||||
/Author (\(anonymous\)) /CreationDate (D:20260224202513+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260224202513+00'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
18 0 obj
|
||||
<<
|
||||
/Count 8 /Kids [ 7 0 R 8 0 R 10 0 R 11 0 R 12 0 R 13 0 R 14 0 R 15 0 R ] /Type /Pages
|
||||
>>
|
||||
endobj
|
||||
19 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1071
|
||||
>>
|
||||
stream
|
||||
Gau`Qa`?,q&A@B[H>]19N;t(,'#(0SaHLU(ZCS4_9.l//;iiG)#3dG5q=nZCZR)*)aXKZ9"egM8If1<+$n+<@q(C4u7gZgkA\^8Nf>%M$OIX3>RG:P>[o13kOISZP"=+aF`,1^=fBeG*p=flcZ/eafK_%`f%#En8?ker'0I.UCfU%]$0a/%Lp*lXZ9L*V2`DNRQ6'B(V>ZVIV_#$2l4_T%<DDIP2QM$l3X<;e@5.6bep/eG0-t?$35fbY_189F"(D)B<5laS:7;NN'Jl'Dj"=O'#>n4ouZm`<+21.ijE,$G&WGB"82e?91fXPsu(\JjPY&,P]\3^pnR'Bq!a<lfH*^CR@hN"g>k]%^bWa[Gs*<NOV+dDaoO-7=Crc&jZhd@1dOu*B[>4b4;EQgjQKgn,q$2'U'R..FVd&hnFMUtS-c5YbI#IJb]mVA)"KsCKIWP_Yj.=D+5aM@fqGY&29#J)e+QYH#=o?,)/nuo=`a*4[9?*i#sqjEKiD9L/afhuJ:^3%qDgk/#,[BXGN#=kqEW3kl9)i2'D+\Y:_7$/BN8qGti:aNdQ5@eGsD$+L7,!eVZX-Pd..2[<hSds)1,]UlS1K)SlADM.aB):UCJ\M]RC^)7'Zh_3b@'?@Fi]m[p-lbMXqsC1,H<V)'H\_kd2+^Qh1u('sb%oAXK!D_l[4/6/7=/]UXrhGbWqrJXi5<>]j=./eGfo!V]YgjJDQ6FqE.IDbH.8.mTPQQ2Y2iB"kAi-L6>KXEJ9J);eI[0?l:sCB"m&idBo\''oFGjuf'=EXqKmdW2GG2;W@8mIc!XE&HZZ:$T0E/:g/O?B3LDZ.W%3o^di3.$^C,ZHmYr=f&%%k8K+TFJ18tt#^J1)fP/Bqc#B9M/ibWe.TKL!5cS#c(B(MX.PYk+$P%"i&*.)`<^Z\b3dq28<'?NVVH@%-MH+,jUURR"%o"c)QRe8foloPQ;*:.=P7I;c)(.E\>c&9kgT3CSBl+5RlZKoH/M+37]%_Z)&LuL!Q6AcFm8&':oG,LR$(*]Hdc6G8cHZ..^55u)\9,-`%=dDK<H(!fnBOK.aK?:l-aTj-~>endstream
|
||||
endobj
|
||||
20 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 855
|
||||
>>
|
||||
stream
|
||||
Gau`Q?#SFN'Rf.Ggq?C_;I*XZLUV+%[1f8V9;ar>,pb1J5sc7;V#L3r-T%SM;>/@S=Mh>Hm@87cnI5PtL=Q<G"n3[iP7[j'Li3;/;\5!u)#*HE\6EYeP=>h^.Ul.78_YZ9X(X6Rd/ab."U>;&W]lMG#J+m0a[eQ5pTo&TIt+o.&(fM5@L[CnJK%s6Ot7VQ$fe"4k`XX#<+m.1`.7,\SBE7.f40pYO[>_t3$YC]b&S/?A-"m]1kK7g_Sbcg'5fjM6WGqj&-_,'"_n]JDn'os=;\Vg+S<,XS#%e"EU%JNZfC:4=Y>+\o8EaAb`$ZQXV>WrN)<=IYF#X8?B!Vq4\2ZDPa"j1VDVW`FVB6NPF\n*#)`mRDMp8'\fIXmgk4+YZ]ZsiF+k3.2oqY];5R&h,n8msdNQo#1W!mQOg%F_.Y3_\.>2QlQnX;',:5#*DT@HqUfODRA5n["\f0^S7:VB0L0X.i'BfAXq#(BS!6uq`1`d12L(ee>oR%Aa-]dI3!7(fnBl"_Kku8=G-.?Dj'mYOKdW4$/$`VCcJ5^8?8H$kP3)h'#9ZX-s@9l&B#lA7#0R+:Z#g=`SdK25`B-5p&p?ZcmKA%2:>G2dW=D/c'?;:ST)QP^a`Nu`UGmHjN;B3moThM;u-P,qZqG-g[aGU\FOd.(a2R"SQbDTA`/Dn7qqiVYnf>,OqAMU$K=mjc%([A:p4i&@DRCL4_-omKSg])W*_uN9if6!3aFS<-65"12tUlnc"g1@4_7ECs"1506Ab,(j/VCApAA#P!?o4,_aA97oNgT&!\a/$!\_!-#>rpn$hI%;%pFM=`\1cbSV#,aIm@QMj,ANb=$bSF=_@LkHjIKP4>l1Y~>endstream
|
||||
endobj
|
||||
21 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1260
|
||||
>>
|
||||
stream
|
||||
Gau0C?#SIU'Re<2\F@CtX;rN`+-m?%@<3G7=L,*9cjcB>TLcH-7Nu,qG+9?Hn%4hGO#SlX,T?m]K3'8C4nm`!MLpU"D*IOui7AZ<cR;Toknn)!!_=tQO</g1U@"LK9`0]$kQV?M_q<#M0^:Mm4ZU@ck^(MkdV:e7f?>&cfoFCs!X]EI2)AKhOSIuhLUel^8f,-a!pO>gJ$c8*_!?iBWD>j<PMsY[`M4\``uW7R6Y$;$Q%np[b(99E9%:81'6qQq>S^T,K%Eb:;3W'3p^SkX,\*;)\(QGP*AV&2_FK(-Xen]0c?0.fQ>*9lQ5Pd9)bXK6!;TkM8_i5*Igb%A9M6WM>#t.Opfqem=<q=3=I*Wa^bN1uiG(VQ/'p(Vg%i@/UPIN`=;^G\g.%`VV2AEt5q6A5,E!W@e)pV.j3F'9?^L@d/.PBW8?>QhY2T=)Z`O#aKG_^ncmT=r#s+%CFo6M6C^HR'm'j"R#8l;jP:`F6\eQ7^h6#5"UZdV*\u8KU%&boA$3qiC7V3Bq>k<5QX9BH!bH5*PiX9I>W&NhL&i(tg2fr'4Y-E6E>L3_*$3eIm.3u*6_t@ZR<n`BfLr7hQh4qQqP")Jbm/ZE#02(V,Le9Kt,NAWUkI8M`l;/7=_m::t&<iL$aZfM(^:0-;fMDI*T.X^6(1,o<\66]`(N:-n];3pbh$^H7!OSdR5&Ogp'qi!<$fJ"mA/b@-:<Ljr/F\hD!N5^HpA/h\CNtat#N]I3,E9NAb=N6b>j?*u1ETJcgXL?E6(VT9F5HS@6ReC[nit[k.\(AcefC2uh9FhrsV?JQ(c6`>^QnE@4*u&p2f5Me#DlNk\\k5n>TDjVEU5^;PJEDH/c>6(3Z$%ZB\tLNV8chYkEeO,C9Gm?V2Y[C[C.2M%L8I3XDms8JsMJkX:VXO0@@Ap)?/Y[A570;Nkt;s:GtV2CT.5p;3ajN!Y^1i(<(gZ_l1&<GUffGO1BkLL11&bUFNk1H<O'PP?'%'i%!G&RfWoF.57G1^`cC4?P8H7@ok0flR6BcG>-?Y0$6D+CAZs$hp;f7OS$CNJA-0Q(N_,3i_I8o*$oU%X8ZPuuii5O,l!qJ,N7j>ihN5Y32H0tqj@6CX]#9_Q34`82j?]E[,0e509U-"4%!W[Y6`gKEoJ?ICrrRsY$q7fo,I?48(b\mCa(#sB9$3rgJU>&lkj)KnK+k4fQ^Kj4KN9[n8khl:CaZi%hYLp8T1rr1p]S1?^"jYoesbJ?EK$(e]Chgu&&rrOo$REG~>endstream
|
||||
endobj
|
||||
22 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 696
|
||||
>>
|
||||
stream
|
||||
Gat=*>>O!-'RnB33"c`UU_quu4$8+^5XO5:7=3`]8DFbIj5Qkdrqe\^TXL(A=I'lioUPBuc]1Wu]1)SBC]SL;^tEo5KL.F!_@_Ra(9WhY.3Pgb66R[("j%uW'Hq?FQu.6>L59B)!LN/di@.#s#q@/bPe'Ef.&J_C1q![)2b,0J8;OE@+ClInLA@eNmFGJP;u:l;/-V@\U;0[sNIK(^@M4O4KLqOjN/@:Tq%Qco[C$1[`gub$;2G+rk_I4n:bIJ>E*jMQaF!UfP!tEsE"AX'Lm+=>.VfKCg3'7,61P#tBnne)MOSU>8E>BqU.E_<H7nN2#C[>\gQ!Mu>kKdd[*?0Uo=V/_F#^%Aq/SU6Rhn^7I>Y,]``$6"]M#TO_O=Jq?^f,>BAdH`]/@EW+(5`s2I2(@j"W3WHU&O>C\p3<b>mS]W(B:"1%dbucGQY!o0BO`#H+.E?_B,RRDVmfAQ+Q_e%tMjJmkFja=0W"LLcP$U9$"AgR:Ro9M>f5Ms2kT,N?8SRENcc=f#o3HX>qc\p[+1kRlVla6[6b[,l[`C$JaNX](k&LUIlgqic^9`s7LT%b9<^c`t+NGq=^IId=t3Oa;F5,>R%]V>tTgE>/M4YUbeUAV(DRN$I,iE&(4,FT^tMY#f3+XR2ccju1KP>PRC\0YiaAIrF9!'Y;ESNN%ZlYLIF='K5[s"TJKS<V-b~>endstream
|
||||
endobj
|
||||
23 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1075
|
||||
>>
|
||||
stream
|
||||
Gau`R>u03/'RfGR\D%*9P@eXOG*9R50U3.T(u(cVPB]Y<dtT/gEDkH_lZ\ns=UU3m,g[7):9QnM3QKal@6j?kp$XjF3/ZYPQiZ4Yh#J*V5]dLRW-?j'bt&Q\:N;D35XZ0&SCYRo`I/&GF'hHB,ikZ72=.,?eC13k0#k[;M<@eUJCSW1*Z&r0%]f2AbZO%.,\ZaXI$ki';llB-jj=#C*F=:UJFCCZB?*5E&#/$lBHNsQLu,bC?T*J$8BL&3J_o&JWODhE2*%R2B4Ws)=sE7)de^3^%#H=<(t('P./uap@;*N`$29?\%X)/DU@02KkX/h>33D,".2$J`>AJ&c`c*.-)Q[m[!o-3+0t<c79WMnd3&o"'36nCuX9K`B'ImUM$@0F>*gLH9@;N$qj(^)R):6u)Ht:JhM&MCK;4:1rFoRj!lhq%Z7-aoU60LCF/1#d_`#!-Mk&HoB#AK<sKnco0S`t/t5\b`F24(=QV'o*FLU9U6-ITZ\[aNkVgH"9`B3[S`.PC"5g]QNErHCEa$p^HfKP1[`CT2F<co?PXZ%*A[B6!bSF^mQWP-RoXD/_/h9XT>r'&cVk#`XH+DY5HW8)gRQMo3afpn7$#l6Df9S\Rer8LJGJM".</'L<J-+VO/r&<A>nFWpaf.uF@tS42r3o>LkkHZ4.R5"(k[?>d#<*cg8h_!b`f4PKceiL?k1lU;Y)S#6Ejo@W,L>U8H;3S7Md>k4/%,a;%gPYnGG@F^$'pf&j+jDLh#LiQrV<*VYHZ?C/k3._c0LCMFn8JP^8W#l<#.-?h=G2Ajan&@p#A33EOP?Rr<d?rPZn%uq?52e.d_b#m5LE,1-Uq[,td%gC>i[em#%WFY*EJC=3<2R'_[p'STpaMl?OLl37=>nA%SbCHX=TN.+Ek7fpLG(u:SnuD\g]+q?^VUp&4WGXdk;uXk-sRgeSq"6A)1e!Y3h;<308uN"`3G##%5Vd;TAIJF`RYAOg3O,=kf$Z+7,Y5hYVkTd#`:Qi-O=;3YBQgmNeN*-A>f%+F;AY(q#)t><cF$g">2og5D)ljdH,Uf9XY45`=m=sO=S\NpD7IeB@d~>endstream
|
||||
endobj
|
||||
24 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 965
|
||||
>>
|
||||
stream
|
||||
Gau`Rhf%4&&:WfG\@p9j1:EB+#qshd?q"YRNN>pgK]!'DM9VPegAU]Vn=s_[:qB88Z4rDH^AI?d]/qgA\CgYIj8]u.[!E,tLZfM@93d8Wd#Ar.)f0k!"N1nBKC=O?n,`iuTp2^V2Jo+=h+:?bJ10;'UhbZMV67oHN"[_<0'9$aLKMGdg3]f3')tW5<QYu2mN=Qm/:YRFa#[iT[I+U91:EE$PsmI;lL$t&[#LBXHO8,(@ge[I.GRKcV3QrUOkSK6/L9:9,iBlF+RPA>!lO7/^QK6h&D[#1E:1=Z!tt1O`Lrt6H@=$OU=s,8LW&^3%DYTG4[l3tg3D?:ED4d61I6V0U0^4foa/(?NIbd:LP,"hpH*IL]:GugIiQ.BBb+U,'%`u=6&-;,QN(5#>!;V&:@oII+/sk<=XHEfnlG:VbP8?=ncbn.Q_d[<WlMD'0lGp`^ps^,%b/f#cB\.aghqJnm3Y.(]@8Nu%rZ>B@:nP%Q12s>hsK![H657hlr[mIM6j`Ab-jYdL!gfDmckAsA$&G]&SiF-)s;o4WraN4(gRuSa/%BuHuagTOS[elV"E:n^FHAV36o;?V)+qo']i7?M]Gm;lgkeXM$'3@=Cj"ZB=2&+rm;,E$SjXqH&b+g7/--8.H.f)5<sA%S,u1U*apX^_\dHNA=V7MJRbTHFRGhT`r_l0B-[F0D>Rd!r%U[,O058WB\;\^-7:[1Rs>L;g^scsEkH&\reqhcSQAr6A'`#CXg2\,ju=:*iPrqQf%$Zrr$"?@7SE(hV3.Bb'>S;V5r>>?>3f/=WdZX9G"S6poq;P[I!4)]Q@RtPUG0Y1:YN3IJkanm&Xb\EX!3a=M0R&je]S+1fN-PW#LE)](9XjhB9j*qK`Yt>p#K%)"QE;6?uJ:;^+2<4R>5md=>[h=j0[ccWJ]uGAJR7[P'I?IUbW?K2gr1mC%WT(-JN?Ca/RKAL_nF2nJh41@lO~>endstream
|
||||
endobj
|
||||
25 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1016
|
||||
>>
|
||||
stream
|
||||
Gaua<D/[lW&BE]&;]L-=_U)QBZ(5ED?n30`%/(C,Ue)t-gb(._4"#`ccQu:U\$hNp+W@=Pm.:%%s#Zhj:jcCBT9]J(1%Ytn0FmUaQllIi,M8'(2a,_pWf["5EsP0%65fX0$tj99lUF$Z0XKgS6AWga6eXR0)gD5_ETc(4cQN4q@-59J.13"*m&"oC%9t6_22o#5LedJC&f#'Z3i_d4W@Oo(#,TqkUE]_Fa)eJ3$DjmK8Q4q1'WP=YQ'=ZlFF[65cXXgpi,]tSqdj`q,>k7M&-</lchmd!C48GN@W7m2+I+,_Nu2]nLXRs4l4FnQ.3]m>dKnH&r1L]TT;1<P'uiWt\l(3hlCM=^'k5LX8N!*,=rU"i$GL5qnes9alR*'tS?>[XML^MEqY-8CbmSo-N4.]=U#LVk666ESTM[s.5*KPQPoq9"5\\kB_]$U#-$TOI@Z[hC@ZD6&.FtUjC@?-AkQK`a^O#MJ`>tm'U&'Af8B@&E\D_9'k,uMe<jOQGS]nEFJ@G'oAs5Q6Yr)sW`+1t!H/i4RHI*,"]B+@TV-6a;h=,5Fc\tN<9iX,Xi:GZkp*9FC3.o/V.(RHmS>&/pfhZHF[ROa,I6u$(7fXN6l1>moYqCphN0"KhgqqV-fp)89[PL(r:7G5O4(fQ\$M(2k>c*WbB9.T9dHXS!K&'VJV>[PkP$l2YQopS7a7I2/]]EdTBoho[SGc<!#:XgZMeUWLjMM:!MWD??a'dmV>X,_jC:Na;[4@iDX=u'/k=6?7eoK^=?^2t@I\.ut1];H"HdtGP`m.m+]#;>V@'XuJ]!H@[>RB/&#kND[Ao$IE_VD+p#c&!'n;O%$bC!ptmIfi=X$?7U><*ReKj*/e)-2a6pA3ZMn_=!qHcNa2YMf?JpadJ6LsO[pA4?`"6,9Bdh)-%W)q*IMM-tS_ie8gL5UG9ZP2ZJRG9@UgNXf)0P=XO5FG*9`4)d1$Wup&$gMuA=oEn5/<P^cWiu9tb,@.-IeeZ`NP@ToI"G42"U%]5uX]SF~>endstream
|
||||
endobj
|
||||
26 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 612
|
||||
>>
|
||||
stream
|
||||
Gat=j95g:b&:j6K'm!&HFgLNWE_EE#Z0FM(U%Zo%&LKDqJJ;ps5JI</,!mERd7PC5SSr[8<m(j.1dpqo1Otr+0(/oK$/kslbqt(]\.*)#BAtn7K#/t9^f\S&TV=PpbqrVg$ns-$2?Hu'"&5/'4j,9ME_QkKNXGQ[1mA;/>S+7`a#V$,^,[``<kFf6\O52AYO"64bEJ;/8!3*8:)\bJ$9&1N)h1D,ikZLN6AHQNnf\R]XGt"6EHWAkdc;Cb57h/N^a4uk7rcVK&N>^J1X0"?F*5#aoDQG?)Tl2p\-f+`p_(OdE]^niF2>(7XZ[#Kf*+BUU7I&m0=9u:GNJP9_F)fuGd_pR9eljD+J[#LMCL&<KQuJQKZlT49S/Ii@5`_DVu)kEgGD^aG*RC?&[)7a7QukPRD^Eq_e90):DXWjAX;K+G2.fg^!F^eE>t+oA7HI9i,_qAA1[Ihr!7N2n6,Nq_h[(rK8n'AJgM:PaidE_MbI8&5mN.<Zq[+QlVj0,4J'Ga$i3@;0Wc?S!RTOK+?Bn9npj].EFJ&L5cZtN,Sd7.\DO47F&G1;:TH7.2`pe'<s8<pmDg47Mfhq:S"eOVK&<=\D*l$=$S_GgCn]OE~>endstream
|
||||
endobj
|
||||
xref
|
||||
0 27
|
||||
0000000000 65535 f
|
||||
0000000061 00000 n
|
||||
0000000142 00000 n
|
||||
0000000249 00000 n
|
||||
0000000361 00000 n
|
||||
0000000476 00000 n
|
||||
0000000559 00000 n
|
||||
0000000664 00000 n
|
||||
0000000869 00000 n
|
||||
0000001074 00000 n
|
||||
0000001151 00000 n
|
||||
0000001357 00000 n
|
||||
0000001563 00000 n
|
||||
0000001769 00000 n
|
||||
0000001975 00000 n
|
||||
0000002181 00000 n
|
||||
0000002387 00000 n
|
||||
0000002457 00000 n
|
||||
0000002738 00000 n
|
||||
0000002846 00000 n
|
||||
0000004009 00000 n
|
||||
0000004955 00000 n
|
||||
0000006307 00000 n
|
||||
0000007094 00000 n
|
||||
0000008261 00000 n
|
||||
0000009317 00000 n
|
||||
0000010425 00000 n
|
||||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<e1d0fc053ad55e2642c670c80d245c9d><e1d0fc053ad55e2642c670c80d245c9d>]
|
||||
% ReportLab generated PDF document -- digest (opensource)
|
||||
|
||||
/Info 17 0 R
|
||||
/Root 16 0 R
|
||||
/Size 27
|
||||
>>
|
||||
startxref
|
||||
11128
|
||||
%%EOF
|
||||
@@ -1,493 +1,178 @@
|
||||
# Les 3: Cursor Basics - Lesopdracht (In-Class Assignment)
|
||||
# Les 3 — Lesopdracht
|
||||
## Bouw je eerste Cursor-componenten
|
||||
|
||||
## Doelstelling
|
||||
|
||||
In deze les leer je hoe je **Cursor** effectief gebruikt om snel professionele componenten te bouwen. Je maakt een **NIEUW** Next.js project met Cursor Composer, genereert AI-gegenereerde cursorrules, en oefent met Tab Completion, Chat, Inline Edit en Composer.
|
||||
|
||||
**Eindresultaat:** Een werkende Next.js applicatie met Hero component en Feature Cards, volledig gebouwd met Cursor.
|
||||
**Vak:** AI-Assisted Development
|
||||
**Opleiding:** NOVI Hogeschool Utrecht
|
||||
**Werkvorm:** in-class, na de pauze (±75 minuten)
|
||||
**Status:** klaar = drie components live op `localhost:3000` + eerste git commit
|
||||
|
||||
---
|
||||
|
||||
## Timing
|
||||
## Doel
|
||||
|
||||
**Totaal: 85 minuten**
|
||||
- Setup & Git: 10 min
|
||||
- Skills & cursorrules: 10 min
|
||||
- Hero Component (Composer): 20 min
|
||||
- Feature Cards (Composer): 20 min
|
||||
- Inline Edit styling: 15 min
|
||||
- Git commit: 5 min
|
||||
- Buffer: 5 min
|
||||
Je gebruikt vandaag voor het eerst Cursor's drie hoofdsneltoetsen — Tab, Cmd+K en Cmd+L — om een werkende Next.js homepage te bouwen. Aan het eind heb je een Hero, een styling-tweak en één extra feature in je code, plus een eerste git commit.
|
||||
|
||||
---
|
||||
|
||||
## Voorbereiding
|
||||
## Wat je nodig hebt (klaar uit de demo)
|
||||
|
||||
### Benodigde software
|
||||
- **Cursor** (gedownload en geïnstalleerd van cursor.com)
|
||||
- **Node.js** 18+ en npm
|
||||
- **Git** (voor versiecontrole)
|
||||
- **Terminal/Command Prompt**
|
||||
- Cursor geïnstalleerd + Pro Student actief
|
||||
- Skills/Docs voor Next.js, React, Tailwind toegevoegd
|
||||
- Vers Next.js-project: `mijn-eerste-cursor-app`
|
||||
- `npm run dev` draait op `localhost:3000`
|
||||
|
||||
---
|
||||
|
||||
## Stap 1: Project aanmaken met Git (10 minuten)
|
||||
## Stappenplan
|
||||
|
||||
### Stap 1.1: Nieuwe folder en Git init
|
||||
### Stap 1 — `.cursorrules` genereren
|
||||
|
||||
Open Terminal/Command Prompt op je computer (niet in Cursor nog):
|
||||
Open Cursor in je project. Druk **Cmd+L** voor de chat. Plak deze prompt:
|
||||
|
||||
```
|
||||
Maak een .cursorrules voor dit Next.js 16 project. Focus op:
|
||||
- TypeScript strict mode
|
||||
- Tailwind CSS voor styling, geen CSS modules
|
||||
- Server components by default; "use client" alleen waar nodig
|
||||
- @/ import alias
|
||||
- Functional components
|
||||
|
||||
Geef alleen het bestand terug, geen extra uitleg.
|
||||
```
|
||||
|
||||
Cursor geeft een bestand. Kopieer de inhoud naar een nieuw bestand `.cursorrules` in de root van je project. Save.
|
||||
|
||||
### Stap 2 — Taak 1: Hero-component (via Cmd+L)
|
||||
|
||||
Open `src/app/page.tsx`. Druk **Cmd+L** voor de chat (nieuwe chat). Plak deze prompt:
|
||||
|
||||
```
|
||||
@file:src/app/page.tsx
|
||||
|
||||
Vervang de huidige inhoud met een Hero-component. Specs:
|
||||
- Gradient achtergrond (subtiele blauwe verloop)
|
||||
- Grote titel: "Mijn Eerste Cursor App"
|
||||
- Ondertitel: "Gebouwd in les 3 met Cursor"
|
||||
- Twee CTA-knoppen: "Aan de slag" (primair) en "Meer info" (secundair)
|
||||
- Responsive: stack op mobiel, naast elkaar op desktop
|
||||
- Tailwind only, geen custom CSS
|
||||
- Inline in app/page.tsx houden (geen aparte component file)
|
||||
```
|
||||
|
||||
Cursor toont een diff. Bekijk de code, klik **Accept all**. Save. Open `http://localhost:3000` in je browser.
|
||||
|
||||
✅ **Check:** je ziet je Hero. Responsive: maak browser smaller, knoppen moeten onder elkaar staan.
|
||||
|
||||
### Stap 3 — Taak 2: Styling-tweak (via Cmd+K)
|
||||
|
||||
Selecteer in `src/app/page.tsx` de twee knoppen (de hele button- of link-blokken). Druk **Cmd+K**. Plak deze prompt in het balkje:
|
||||
|
||||
```
|
||||
Verander de primaire knop naar een paars gradient (purple-600 naar pink-600). Maak de secundaire knop transparant met een paarse border en paarse tekst. Voeg een hover-effect toe aan beide.
|
||||
```
|
||||
|
||||
Cursor toont een inline diff. Druk **Tab** om te accepteren. Save. Refresh browser.
|
||||
|
||||
✅ **Check:** knoppen zijn paars, hover werkt.
|
||||
|
||||
### Stap 4 — Taak 3: Extra feature (vrije keuze)
|
||||
|
||||
Kies één van de drie. Gebruik Cmd+L of Cmd+K naar wat het beste past.
|
||||
|
||||
**Optie A — FeatureCards (3 cards onder de Hero)**
|
||||
|
||||
```
|
||||
Voeg onder de Hero in @file:src/app/page.tsx een sectie toe met 3 feature-cards.
|
||||
Per card: een emoji-icoon, een titel, een korte beschrijving.
|
||||
Drie features: "Snel", "AI-powered", "Open Source".
|
||||
Grid layout: 1 kolom mobiel, 3 kolommen desktop.
|
||||
Tailwind styling, matched de Hero.
|
||||
```
|
||||
|
||||
**Optie B — ContactForm (form onderaan)**
|
||||
|
||||
```
|
||||
Voeg onder de Hero in @file:src/app/page.tsx een contact-form toe.
|
||||
Velden: naam, e-mail, bericht (textarea).
|
||||
Een submit-knop in dezelfde paarse stijl als de Hero CTAs.
|
||||
Form moet er goed uitzien — max-width, padding, ronde hoeken.
|
||||
"use client" gebruiken, met useState voor de velden (nog geen echte submit-logica).
|
||||
```
|
||||
|
||||
**Optie C — Footer (footer met links + copyright)**
|
||||
|
||||
```
|
||||
Voeg een Footer toe onder de hele page-inhoud in @file:src/app/page.tsx.
|
||||
Drie kolommen: "Product" (3 links), "Resources" (3 links), "Contact" (e-mail + locatie).
|
||||
Copyright-regel onderaan: "© 2026 Mijn Eerste Cursor App".
|
||||
Matched de Hero-stijl, donkere achtergrond voor contrast.
|
||||
```
|
||||
|
||||
Cursor toont diff → Accept → save → refresh.
|
||||
|
||||
✅ **Check:** je extra feature staat in de pagina, matched de Hero-stijl.
|
||||
|
||||
### Stap 5 — Git commit
|
||||
|
||||
Open een terminal in Cursor (Ctrl+ ` of Terminal → New Terminal).
|
||||
|
||||
```bash
|
||||
mkdir les3-cursor-project
|
||||
cd les3-cursor-project
|
||||
git init
|
||||
git add .
|
||||
git commit -m "first cursor build: hero + tweaks + extra feature"
|
||||
```
|
||||
|
||||
### Stap 1.2: Open in Cursor
|
||||
Optioneel: push naar GitHub.
|
||||
|
||||
```bash
|
||||
cursor .
|
||||
gh repo create mijn-eerste-cursor-app --public --source=. --push
|
||||
```
|
||||
|
||||
Dit opent je lege project in Cursor.
|
||||
|
||||
**Checkpoint 1:** Project is open in Cursor met lege folder.
|
||||
|
||||
### Stap 1.3: Create Next.js app in Cursor Terminal
|
||||
|
||||
Open de Terminal in Cursor met **Ctrl+`** (backtick):
|
||||
|
||||
```bash
|
||||
npx create-next-app@latest . --typescript --tailwind --app
|
||||
```
|
||||
|
||||
Beantwoord alle vragen met **Yes (y)**:
|
||||
- TypeScript? → **Yes**
|
||||
- ESLint? → **Yes**
|
||||
- Tailwind CSS? → **Yes**
|
||||
- `src/` directory? → **No**
|
||||
- App Router? → **Yes**
|
||||
- Default import alias? → **Yes**
|
||||
|
||||
Dit duurt ~2-3 minuten. Wacht tot het klaar is.
|
||||
|
||||
**Checkpoint 2:** Next.js project is aangemaakt. Je ziet `app/`, `components/`, `package.json`, etc. in de file tree.
|
||||
(Vereist `gh auth login`.)
|
||||
|
||||
---
|
||||
|
||||
## Stap 2: Cursor Skills & Docs (10 minuten)
|
||||
## Op te leveren
|
||||
|
||||
### Stap 2.1: Open Settings
|
||||
In de chat (Teams):
|
||||
|
||||
Klik op het **⚙️ Settings icoon** linksonder in Cursor.
|
||||
|
||||
### Stap 2.2: Activeer Docs
|
||||
|
||||
Ga naar **Features** → **Docs**
|
||||
|
||||
Voeg deze drie documenten toe (zoek en click Add):
|
||||
1. **Next.js** (officiële docs)
|
||||
2. **React** (officiële docs)
|
||||
3. **Tailwind CSS** (officiële docs)
|
||||
|
||||
Dit helpt Cursor veel beter code te genereren omdat het toegang heeft tot de juiste documentatie.
|
||||
|
||||
### Stap 2.3: Controleer Tab Completion
|
||||
|
||||
Ga naar **Features** → **Completion**
|
||||
- Zorg dat **Tab Completion** is ingeschakeld (dit is gratis!)
|
||||
|
||||
**Checkpoint 3:** Alle drie docs zijn zichtbaar in je Docs sidebar rechts. Tab Completion is enabled.
|
||||
1. Screenshot van je `localhost:3000` met Hero + extra feature zichtbaar
|
||||
2. Korte tekst: welke optie (A/B/C) heb je gekozen voor taak 3?
|
||||
3. Optioneel: GitHub-URL als je hebt gepushed
|
||||
|
||||
---
|
||||
|
||||
## Stap 3: Generate cursorrules met Chat (1 request)
|
||||
## Bonus — als je tijd over hebt
|
||||
|
||||
### Stap 3.1: Open Cursor Chat
|
||||
|
||||
Druk **Ctrl+L** (Windows/Linux) of **Cmd+L** (Mac).
|
||||
|
||||
Een chat panel opent aan de zijkant.
|
||||
|
||||
### Stap 3.2: Prompt voor .cursorrules
|
||||
|
||||
Typ deze prompt en druk Enter:
|
||||
|
||||
```
|
||||
Je bent een expert Next.js developer. Genereer een .cursorrules bestand
|
||||
voor een Next.js project met TypeScript, Tailwind CSS, en App Router.
|
||||
|
||||
Het bestand moet guidelines bevatten voor:
|
||||
- Functional components en React hooks
|
||||
- TypeScript best practices
|
||||
- Tailwind CSS utilities (nooit inline styles)
|
||||
- Bestandsnaamgeving (PascalCase voor components, camelCase voor utils)
|
||||
- Folder structuur (/app, /components, /lib)
|
||||
- Comments in het Nederlands
|
||||
- Keine `any` types
|
||||
|
||||
Output het volledige .cursorrules bestand klaar om te copy-pasten.
|
||||
```
|
||||
|
||||
Wacht op Cursor's antwoord.
|
||||
|
||||
### Stap 3.3: Copy de output
|
||||
|
||||
Cursor geeft je het complete .cursorrules bestand.
|
||||
|
||||
Selecteer alle code (Ctrl+A in de chat output) en kopieer het.
|
||||
|
||||
### Stap 3.4: Maak .cursorrules bestand
|
||||
|
||||
1. Rechtsklik op de root folder in de left sidebar
|
||||
2. Klik "New File"
|
||||
3. Noem het `.cursorrules` (met punt aan het begin!)
|
||||
4. Plak de content
|
||||
|
||||
Save het bestand (Ctrl+S).
|
||||
|
||||
**Checkpoint 4:** `.cursorrules` bestand bestaat in je project root met goede guidelines.
|
||||
|
||||
**Request Budget: 1 van ~7 used**
|
||||
- Vraag Cursor om een dark/light mode toggle toe te voegen
|
||||
- Probeer `@docs:Tailwind` om een geavanceerde animatie te toevoegen
|
||||
- Voeg een tweede pagina toe (`src/app/about/page.tsx`) en link ernaar vanuit de Hero
|
||||
- Genereer favicon + metadata via Cursor
|
||||
|
||||
---
|
||||
|
||||
## Stap 4: Hero Component met Composer (20 minuten)
|
||||
## Vastgelopen?
|
||||
|
||||
### Stap 4.1: Maak component file
|
||||
| Probleem | Snelle fix |
|
||||
|----------|-----------|
|
||||
| Cursor reageert niet bij Cmd+L | Settings → Account: nog Pro Student? Anders opnieuw activeren |
|
||||
| Tab-completion komt niet | Settings → Features → Cursor Tab → check enabled |
|
||||
| Tailwind classes worden niet toegepast | Check `globals.css` op `@tailwind base/components/utilities` |
|
||||
| Diff is verkeerd | Esc om te rejecten, herformuleer prompt specifieker |
|
||||
| `@file` werkt niet | Wacht 5 sec na file aanmaken (Cursor moet indexeren) |
|
||||
| Geen requests meer | Wacht op nieuwe maand, of plug je eigen OpenAI/Claude key in via Settings |
|
||||
|
||||
1. Rechtsklik op de `app` folder
|
||||
2. "New File"
|
||||
3. Noem het `app/components/Hero.tsx`
|
||||
|
||||
(Dit maakt automatisch de `components` subfolder)
|
||||
|
||||
### Stap 4.2: Open Composer
|
||||
|
||||
Met het Hero.tsx file open, druk **Ctrl+Shift+I** (Windows/Linux) of **Cmd+Shift+I** (Mac).
|
||||
|
||||
De Composer panel opent.
|
||||
|
||||
### Stap 4.3: Geef instructie aan Composer
|
||||
|
||||
In Composer, typ:
|
||||
|
||||
```
|
||||
Maak een Hero component (TypeScript, React functional component) met:
|
||||
- Grote h1 heading: "Welkom bij Cursor"
|
||||
- Subheading met beschrijvende tekst: "Bouw websites snel met AI"
|
||||
- Een CTA button: "Aan de slag" (link naar #features)
|
||||
- Responsive design: Tailwind CSS (md: breakpoint)
|
||||
- Flexbox voor verticale centrering
|
||||
- Dark mode compatible (dark: classes)
|
||||
- Gradient background (blauw naar paars)
|
||||
- Geen external dependencies
|
||||
|
||||
Geef alleen de component code, geen imports of exports statements voor buiten.
|
||||
```
|
||||
|
||||
Cursor genereert het component.
|
||||
|
||||
### Stap 4.4: Accept of refine
|
||||
|
||||
Review de getoonde code. Klik **Accept All** (groene knop) om het in je bestand in te voegen.
|
||||
|
||||
**Checkpoint 5:** Hero.tsx file bevat een werkend Hero component met juiste structuur.
|
||||
|
||||
**Request Budget: 2 van ~7 used**
|
||||
Tim loopt rond — vragen gewoon stellen.
|
||||
|
||||
---
|
||||
|
||||
## Stap 5: Feature Cards Component met Composer (20 minuten)
|
||||
## Reflectie (na afloop)
|
||||
|
||||
### Stap 5.1: Maak component file
|
||||
Denk na voor jezelf:
|
||||
- Hoeveel requests heb je gebruikt? (Settings → Account toont saldo)
|
||||
- Welke sneltoets voelde het meest natuurlijk?
|
||||
- Wanneer zou je liever zelf typen dan Cursor laten genereren?
|
||||
|
||||
1. Rechtsklik op `app` folder
|
||||
2. "New File"
|
||||
3. Noem het `app/components/FeatureCards.tsx`
|
||||
Dat zijn de gewoontes die je deze opleiding gaat ontwikkelen.
|
||||
|
||||
### Stap 5.2: Open Composer
|
||||
|
||||
Druk **Ctrl+Shift+I** in dit nieuwe bestand.
|
||||
|
||||
### Stap 5.3: Composer prompt
|
||||
|
||||
```
|
||||
Maak een FeatureCards component (TypeScript, React) dat:
|
||||
- Een grid van 3 feature cards toont
|
||||
- Responsive: 1 kolom op mobile, 3 kolommen op desktop (Tailwind grid)
|
||||
- Elke card heeft:
|
||||
* Een icon uit lucide-react (Package, Zap, Layers)
|
||||
* Een h3 title
|
||||
* Een description text
|
||||
- Hover effect: transform scale-105 en shadow toename
|
||||
- Cards hebben border en padding (Tailwind)
|
||||
- Dark mode ready
|
||||
- lucide-react is geïmporteerd bovenaan
|
||||
|
||||
Geef alleen de component code.
|
||||
```
|
||||
|
||||
Composer genereert het component.
|
||||
|
||||
### Stap 5.4: Accept
|
||||
|
||||
Klik **Accept All**.
|
||||
|
||||
### Stap 5.5: Install lucide-react
|
||||
|
||||
In je Cursor Terminal (Ctrl+`):
|
||||
|
||||
```bash
|
||||
npm install lucide-react
|
||||
```
|
||||
|
||||
Wacht tot npm klaar is.
|
||||
|
||||
**Checkpoint 6:** FeatureCards.tsx werkt, lucide-react is geïnstalleerd.
|
||||
|
||||
**Request Budget: 3 van ~7 used**
|
||||
|
||||
---
|
||||
|
||||
## Stap 6: Integreer in Homepage (5 minuten)
|
||||
|
||||
### Stap 6.1: Open `app/page.tsx`
|
||||
|
||||
Dit is je homepage.
|
||||
|
||||
### Stap 6.2: Update de content
|
||||
|
||||
Vervang de bestaande content (of voeg toe aan het bestand) met:
|
||||
|
||||
```typescript
|
||||
import Hero from './components/Hero';
|
||||
import FeatureCards from './components/FeatureCards';
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<main className="min-h-screen">
|
||||
<Hero />
|
||||
<section className="py-20 bg-gray-50 dark:bg-gray-900">
|
||||
<div className="container mx-auto px-4">
|
||||
<h2 className="text-4xl font-bold mb-12 text-center">Features</h2>
|
||||
<FeatureCards />
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
Save (Ctrl+S).
|
||||
|
||||
### Stap 6.3: Test in browser
|
||||
|
||||
In Cursor Terminal:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Open `http://localhost:3000` in je browser.
|
||||
|
||||
Je ziet nu: Hero → Features section met 3 cards.
|
||||
|
||||
**Checkpoint 7:** Website draait lokaal en ziet er netjes uit.
|
||||
|
||||
---
|
||||
|
||||
## Stap 7: Styling Refinement met Inline Edit (15 minuten)
|
||||
|
||||
Nu gebruiken we **Inline Edit** (Ctrl+K) voor kleine styling tweaks.
|
||||
|
||||
### Stap 7.1: Hero button styling
|
||||
|
||||
1. Open `app/components/Hero.tsx`
|
||||
2. Klik ergens in de button JSX
|
||||
3. Druk **Ctrl+K**
|
||||
4. Type:
|
||||
|
||||
```
|
||||
Voeg een hover effect toe aan de button:
|
||||
- Scale slightly bigger on hover
|
||||
- Change background color smoothly
|
||||
- Add smooth transition
|
||||
```
|
||||
|
||||
5. Review de suggestie, klik Accept
|
||||
|
||||
### Stap 7.2: Card shadows verbeteren
|
||||
|
||||
1. Open `app/components/FeatureCards.tsx`
|
||||
2. Selecteer een card div
|
||||
3. Druk **Ctrl+K**
|
||||
4. Type:
|
||||
|
||||
```
|
||||
Voeg een mooier shadow effect toe aan de cards:
|
||||
- Larger shadow on hover
|
||||
- Smooth transition
|
||||
- Better depth perception
|
||||
```
|
||||
|
||||
5. Accept
|
||||
|
||||
### Stap 7.3: Typography verbeteren
|
||||
|
||||
1. Open `app/page.tsx`
|
||||
2. Druk **Ctrl+K**
|
||||
3. Type:
|
||||
|
||||
```
|
||||
Maak de "Features" heading groter en mooier:
|
||||
- Groter font size
|
||||
- Betere kleur gradient
|
||||
```
|
||||
|
||||
5. Accept
|
||||
|
||||
Refresh je browser (F5) om de changes te zien.
|
||||
|
||||
**Checkpoint 8:** Styling ziet er gepolijst uit, hover effects werken.
|
||||
|
||||
**Request Budget: 4-5 van ~7 used**
|
||||
|
||||
---
|
||||
|
||||
## Stap 8: Git Commit (5 minuten)
|
||||
|
||||
### Stap 8.1: Open Source Control
|
||||
|
||||
Druk **Ctrl+Shift+G** in Cursor.
|
||||
|
||||
Source Control panel opent links.
|
||||
|
||||
### Stap 8.2: Stage alle bestanden
|
||||
|
||||
Klik op het **+** icoon bij "Changes" of druk **Ctrl+Shift+A**.
|
||||
|
||||
Alle bestanden worden staged (groen).
|
||||
|
||||
### Stap 8.3: Write commit message
|
||||
|
||||
In het message veld, typ:
|
||||
|
||||
```
|
||||
feat: Build Hero and FeatureCards components with Cursor Composer
|
||||
```
|
||||
|
||||
### Stap 8.4: Commit
|
||||
|
||||
Druk **Ctrl+Enter** of klik de ✓ button.
|
||||
|
||||
Je commit is gemaakt!
|
||||
|
||||
**Checkpoint 9:** Git commit is succesvol (geen errors).
|
||||
|
||||
---
|
||||
|
||||
## Keyboard Shortcuts Reference
|
||||
|
||||
| Actie | Windows | Mac |
|
||||
|-------|---------|-----|
|
||||
| **Cursor Chat** | Ctrl+L | Cmd+L |
|
||||
| **Composer** | Ctrl+Shift+I | Cmd+Shift+I |
|
||||
| **Inline Edit (quick fix)** | Ctrl+K | Cmd+K |
|
||||
| **Terminal** | Ctrl+` | Cmd+` |
|
||||
| **Command Palette** | Ctrl+Shift+P | Cmd+Shift+P |
|
||||
| **Source Control** | Ctrl+Shift+G | Cmd+Shift+G |
|
||||
| **Save** | Ctrl+S | Cmd+S |
|
||||
| **Tab Completion** | Tab | Tab |
|
||||
|
||||
---
|
||||
|
||||
## Request Budget Tracking
|
||||
|
||||
Je hebt **~7 requests** beschikbaar in deze les:
|
||||
|
||||
| Fase | Type | Requests |
|
||||
|------|------|----------|
|
||||
| cursorrules generatie | Chat | 1 |
|
||||
| Hero Component | Composer | 1 |
|
||||
| FeatureCards Component | Composer | 1 |
|
||||
| Button styling tweak | Inline Edit | 0.5 |
|
||||
| Card styling tweak | Inline Edit | 0.5 |
|
||||
| Typography tweak | Inline Edit | 0.5 |
|
||||
| Buffer/extra | - | 2.5 |
|
||||
|
||||
**💡 Pro tip:** Gebruik **Tab Completion** (gratis!) voor:
|
||||
- Imports toevoegen
|
||||
- Props schrijven
|
||||
- Repetitieve code (zelfde classNames herhalen)
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Probleem: "Module not found: lucide-react"
|
||||
**Oplossing:**
|
||||
```bash
|
||||
npm install lucide-react
|
||||
npm run dev
|
||||
```
|
||||
(Herstart je dev server na npm install)
|
||||
|
||||
### Probleem: Composer stelt rare dingen voor
|
||||
**Oplossing:** Wees specifieker in je prompt. Verwijs naar bestaande code:
|
||||
- "Voeg lucide-react icons toe" (voldoende duidelijk)
|
||||
- "Zorg dat het met TypeScript werkt" (specifieer)
|
||||
|
||||
### Probleem: Inline Edit accepteert niet
|
||||
**Oplossing:** Klik de groene ✓ knop of druk Ctrl+Enter
|
||||
|
||||
### Probleem: `npm run dev` geeft error
|
||||
**Stappen:**
|
||||
1. Controleer dat je in de juiste folder bent: `pwd`
|
||||
2. Controleer node versie: `node --version` (moet 18+ zijn)
|
||||
3. Verwijder en herinstalleer dependencies:
|
||||
```bash
|
||||
rm -rf node_modules package-lock.json
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Probleem: Port 3000 al in gebruik
|
||||
```bash
|
||||
npm run dev -- -p 3001
|
||||
# Openen: http://localhost:3001
|
||||
```
|
||||
|
||||
### Probleem: Git werkt niet
|
||||
**Controleer:**
|
||||
- Ben je in de juiste folder? `pwd` moet je project folder zijn
|
||||
- Bestaat `.git` folder? `ls -la .git`
|
||||
- Zijn je bestanden getracked? `git status`
|
||||
|
||||
---
|
||||
|
||||
## Checklist - Vinkje alles af voor je klaar bent
|
||||
|
||||
- [ ] Git init en create-next-app uitgevoerd
|
||||
- [ ] Cursor Skills (Next.js, React, Tailwind) geactiveerd
|
||||
- [ ] `.cursorrules` bestand gegenereerd en in root geplaatst
|
||||
- [ ] `app/components/Hero.tsx` aangemaakt met Composer
|
||||
- [ ] `app/components/FeatureCards.tsx` aangemaakt met Composer
|
||||
- [ ] lucide-react geïnstalleerd via npm
|
||||
- [ ] Componenten geïmporteerd in `app/page.tsx`
|
||||
- [ ] `npm run dev` draait zonder errors
|
||||
- [ ] Website ziet er goed uit op http://localhost:3000
|
||||
- [ ] Styling verfijnd met Inline Edit (minimaal 2 aanpassingen)
|
||||
- [ ] Git commit gemaakt met duidelijke message
|
||||
- [ ] Alle bestanden zijn saved (geen rode stippen in sidebar)
|
||||
|
||||
---
|
||||
|
||||
## Volgende stappen
|
||||
|
||||
**Voor volgende les:**
|
||||
- Zorg dat `npm run dev` nog werkt
|
||||
- Download het huiswerk zip bestand van Teams (les3-debug-challenge.zip)
|
||||
- Voorkom dat je project files verwijdert/opslaanslecht
|
||||
|
||||
**Veel succes! 🚀**
|
||||
Veel succes!
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
%<25><><EFBFBD><EFBFBD> ReportLab Generated PDF document (opensource)
|
||||
1 0 obj
|
||||
<<
|
||||
/F1 2 0 R /F2 3 0 R /F3 5 0 R /F4 6 0 R /F5 7 0 R
|
||||
/F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 6 0 R /F5 8 0 R
|
||||
>>
|
||||
endobj
|
||||
2 0 obj
|
||||
@@ -17,32 +17,12 @@ endobj
|
||||
endobj
|
||||
4 0 obj
|
||||
<<
|
||||
/Contents 20 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
5 0 obj
|
||||
<<
|
||||
/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/BaseFont /Symbol /Name /F4 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<<
|
||||
/BaseFont /ZapfDingbats /Name /F5 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
8 0 obj
|
||||
<<
|
||||
/Contents 21 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||
/Contents 14 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 13 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
@@ -50,9 +30,29 @@ endobj
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/BaseFont /ZapfDingbats /Name /F4 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<<
|
||||
/Contents 15 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 13 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
8 0 obj
|
||||
<<
|
||||
/BaseFont /Symbol /Name /F5 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
9 0 obj
|
||||
<<
|
||||
/Contents 22 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||
/Contents 16 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 13 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
@@ -62,7 +62,7 @@ endobj
|
||||
endobj
|
||||
10 0 obj
|
||||
<<
|
||||
/Contents 23 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||
/Contents 17 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 13 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
@@ -72,192 +72,78 @@ endobj
|
||||
endobj
|
||||
11 0 obj
|
||||
<<
|
||||
/Contents 24 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
/PageMode /UseNone /Pages 13 0 R /Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
12 0 obj
|
||||
<<
|
||||
/Contents 25 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
/Author (NOVI Hogeschool Utrecht) /CreationDate (D:20260615075148+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260615075148+00'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Subject (\(unspecified\)) /Title (Les 3 Lesopdracht) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
13 0 obj
|
||||
<<
|
||||
/Contents 26 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
/Count 4 /Kids [ 5 0 R 7 0 R 9 0 R 10 0 R ] /Type /Pages
|
||||
>>
|
||||
endobj
|
||||
14 0 obj
|
||||
<<
|
||||
/Contents 27 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1797
|
||||
>>
|
||||
stream
|
||||
GauHKgN)%,&:N/3m,Y!`,/FD,GGd5kihf;2k#/2#M]Mq`O@5!0=HJc2I!lg,8C?#-9&5><>8.@7Zb&2T>u7cpU@nO7"*c_Xo+r)hKBXAS6QDK-J`!>WIg1!Ndpp<(=\-AA*XQ)p_>!FR@35"\(Pj)6G0#2e[eTs;(a(0mBKVYo8ATf\L4[qY_`+:i)eP')J@@"h234'b),.5BqUk:e^h]POe0;?]\]0B;'0P1:-9Tf!B<&OoCB6ccU(m+0dY6-087f>p6C'spDm*dY4`bL\)QF35DQ%;bb>8k\q:,iiIcRPfR\O2`qY:\o^)B3fM?GMgiDQaGWq$S#J^)+KB_X2U71ptgYm^*qh8`Ud;Ct9K/X8remnsN%rslspTiZ$+ZX&5PNh_gT`<[`E=?t04Dk[]]E&O4@O8:J>M6&C+Za1\98]f/UfEGTXS87m'@\!eg6<ujFX9GQ8`Ne/6;AJ_DWJ^8`[Oc2!mRb$8Mki1K=`T,84Q_gB@>@;6#%9ILTd%*J,/)kZf=oM^M<$RKbo2U#!0+REJ"Zi$8ls-7KJf)Nk6kBBV-tgq-9rMis&:h+7oddn6Ai-LU+Ct613LaC7drNuT=b@J1,j-?#:`**/fTO(-lX=,'lV'XP$Ae/Q\h4c"Q2UO@8[D'i$k!%I3N16\S;aO_FpTQW4je)Y:7V<>i#b#15n$DV<1PTibI??blqiR$P]E<M,Z#qOJc)UU[5'H3?d,#-ak%?#6j%=[%$P]!IWn'0jCY;=dVI=0H2oQ:nc,N`E6YcG';5If5$A?IA<n?EFV=2&8Z!/%hR^sr,=\]qBDD+h`keM9o2MW5^Q`@,jaktE$J.X0s88EMiste/o6LBrE_"APZ;P.5TZ2IQle./!'BsqSo2*QbL=Q_8^l\s;FO$<URNMI_-[9B)dsL/l&A7QbftiDj1kAFa3=C"*k,CdJ8LRHH`J,uB^=b>fBQO-ji,M7T-`*0ga)JNC+:sao4+Bl5f`?bgYV,&bVRV2`;Es1e1L$B3+i2)"g;k!LI6EW@keU(.roT)ZTYL]nBa<-X*^EGRA]t9*XVSB4u$o1mX?3`0;i-[THhIsF]J93)P-(A'uah@4/C5JSRN2u>P+J,I[?P`f^)[67G;FD^nn274.T2R7s>)4V`o"td?<OJmo-<<Z1q@0AU/Q@^CM#O'QY7/Hm$q5TgrPgfdnVm<"9me#]juJKP]TA4pcfpfT)d1-a:gQgE@r;bp8?PNog"*Jp'mGkf,#nS%=jXa*cl-L1^T`C"Q,E/EfP7CAT:t:uV^Gn$08(ZaO*N(;O>DK=/+0oD[=1m;4[^%d&g,QKDpTV[[&d0T-('g=[--84#e6#GI+o@8O"7pa8$!$EBaP^s.aG;R]pDosW"fTd&i)<8M!74Z"!>gN>1h%*]Wd?ZRrYFHW!C/EnE0+iEI*3.r(\`sDgu6F>;(q..p@\7rQEQnV"N3/jNMKB'JE=TdEU)r-:sCSCVGr7+kJn=3Qoq(k.5$C#_&i.FNrf5_0VVWFehT]8G#90Cr>2E\aG6\6!jMgq2bHYg'+inKF"n%P_G2@N4KZtJQA"GZbaT'mVO_mA&m6h@o$o@?@Zmp6=e?;1#-\nZk&\$Msf9?#n6Hb(l8h69Q=UIWJ?]2R<PM0W6>FCPi4f.'S#^7%bDO\8]nGdP@'0lpkLn0HdmI^^No<PIXhBE5G<ouR;[_ldeDZp3MbEC*T!D;+UYIjbu34k3rKdYmt[Ys$lP'>@4dF3$AiHuH-^o['V.=>K<![F!;]<mbu0E$Al`j_ec3F#cP<l32%=c-G`10/3/;nc!jm~>endstream
|
||||
endobj
|
||||
15 0 obj
|
||||
<<
|
||||
/Contents 28 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2152
|
||||
>>
|
||||
stream
|
||||
Gb"/'?$Dbt&:O;VR$/nq)\YL3"$^Xk-Jb9%Vqo@j:O\F7Cb'mh$=UF>ofEcjgPHjsh4Ad3[V5dK(lb\1mbGV\Q[V'o2p),,:>l'("4)bE*5'&n@.Ff1-Cle1DtE&*G6X`_dYZ/;+;g+%]oM-`?9%F^HQ9RIoKb&iGpe-XnbY-a6IlHt6YA4_8)(;U'9$2ficZ^eH1aN,`sph_m`;>P-L.sJ*X`uA#RAp[1DY3F)n7`N`jchhqOuJmG(`P+0@GmD$qI(`g[<X[]:CJ;\6ETD\nHNJ]Y@asp,)%c47a8AV>29R/DLY#Mmhr12JCQY"*`s^^?6$Bo7i8eFQpmU\pr!oMW7T'kI`4g$bekrQX<NsEXS'Ih_X3a*H0:8N.LF^'f'ee*8.7$T2D_8^47&/=c$63&4F6s<=Ba[5g81?<3d=^XH5I)g4>^pUN6:B,IBh>+#%<)keV&R@mMaMO-U^76HM?EBt(0U>%!4A96mp7=J8?`/>f>+)]s_k-N2N*e-K5k9ZM,C?JO[^KrUrRb=\$t_*q4k4DqDgFH!]c`o;b97b&?'NAF_>@mU>s/:gr/C<K,K#(:."L80aUaVr9ra[Il)APli1VD!13E%b/(3$C6g,r.+&oFqT(PP9lj-CmeNX2LsZ@sdh;3>lmmbkISu5@I.<<f.WPU!u1s5SfI')52K`3Th]*ELLjLb]o(XU1Nli"?tq=58Xm"<H4/("mr22dr/m'0EDheV3W!(hV:52W]AXrhW1ZW:%5u:]RpMZZ8q;Ue%FUr2R\T70M/R*akqkeX?Z>\)Z-i+$N4/,4Ni;A'j[$$NkbCn(=:ljOd7c+1EmV+\H=K>&\!VM^duIi#"^9WYb%@lq\qWQM^ZGoi]^'qGFBD\PXp1U%XapOBO52nc)'"1q#!7>&Pnb!e77XPmX5HIX'9DkhOQ++/l=WU?lXorcb9WSE"%`tlX2MP5Ln$I\[<<(JAgO^ULa:1%CZUeJhi4DL1m*jONfa\@'_I61I;Zg!F7&a`A)*g8<^/M(fQOfr$`3Pr>c.`O-tK:s&cW%4`p%Z!kVFTjkUm#$fZl>mo*7(O8Ufgk\h0\Mk46"%8=Aa_;R/-s*/lD=:[G/K`<B(Dhq78?*hS(^cGRnG5$X+=W=5Q5b<-nA[!FcBeAota>qVqP27aT8V6d1e:C]$H5QL%\IYJ7A'0unAn/J@-krMa2Vp&8&8"%!DK5RWP_,T-(YmoM9pi\r8f3ud86e#Qfo@%\[1Hb.&qh.mdCeKX>JF9_m*[Se!H-@82VV]a;&p"@==?gk"eCm^BIZ'.X\'<Wp'.[(5?+$.TIUZmmnGj1&kDW\(eFs]f^@pD=m7)"Mn5G.<.-Ga-[bV1qPe:.H/Y'r;.8=CoI$.Z/=5jJNX\,>LKF)R3O[&k4/7f%rgcnl-+*nl</H(@C=n@0XQCnWA["OgC^aBP[Gil1Xt'i=U.Zf2+=((Fh667%h&G^k[tXCG5PJ!%.nJ5c=l2$M3NQsm(+V]J:?#&L<7VMF]edlF8Ze$E2:j]oU!];4BrS!18YY_=T)/>UIOI`>_aP$jFUcnJ=#%8CAJ!NNfqbgNVGG%R-S]!Dj):jC@H\,IhsKlqWAu`rpKKPP5cc&B4_R=oZaLZ%^U>BTesO(?lPGcP?Dm<riaRDT9G'DBpfUK>)Dr,"-/'u)2&XlLHga'L[s-ShO#3\YB5Gh%->u=K6q!VZG/3f8ok>V0i2.?PQB[R`dPOIkg$:n0;&2#aQIPH[jHuO/;<RPJ=%FMWN6RWQ^c/Ps&Y9uI^=RhH<[*9_J!6-=dkchSM8,PJL=OnDdHbpbF2[]g*GjK!ZIX#.,Xlj_`44JKk?'V5=hd\3+&)<nFeW5@8`PrIQ7AXlT::Im)%sMVa`$d-j1k*jkPtHDQJYQQeNLOdPi^64kg,X9k+`!CVMm:>8(*B[@"q9A9;BolIaq[H-WTl!r4Ok];p@(km:Qge^6.dHguq*M,Y6X'ELTjY>IJ=[S6R&oU:iClO_pOI+J9L5P,o:bR_l^ts,;HpX[T=XB/F0>gMA\gOJjan8.EWrde]a`LSN?)f+V99[2k+q%%5Nq;C9>).k0k7XXp1L>qQrdLCH(IY8TN$\Id.O3"ICpI]N8h9Q7Nkq,3A*[3T-UN8(3E/)_!GS`6+OMktm<$./JQJcpLP~>endstream
|
||||
endobj
|
||||
16 0 obj
|
||||
<<
|
||||
/Contents 29 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2071
|
||||
>>
|
||||
stream
|
||||
Gb!#\=``=U&:WfGf^Y/q6o55,Rd&mPS"soL-F)h`4VT(`&f+%e,\X+Ooj.'QCdjYRn\gG4#hSKnq"=\]0_!\qrspo9=*$?JD1Y>e^&ld7D4&(jhr`X*c"q%(7!A_G@)K<nh_tXBVs1'e#-J9MVf,Z<JKiZcbm%B"%e^-hBt!3`Wk]_Q;U+nE[;b?8IC#@&l@s/#iuYt)'5GE9:\RQ7Z0SO'^-E3bkFq6cF3eYMoc!Hc\CL'peZe04UL@ZbbSXlERP?4Sig4!'G5Ygncj[<M><P8'eLuMQ_eh\9UM]4DM`,a&E%B$WEPZg?fCElI#*V]r@ULaBf0W#/J.rD[*apR.OKatcL;n&Po0cOin/Pc9GfjW0&Y@Cpk"H6LZM^Gh_Yac':\I>d/D[W<Bghr(E!C*?MC`95$r/u#,-!tT!fMm=.F6W-iq++YHt&qNMNF+8"6Ukp[$f7;)<E;0KiE_)EjdqjTEr@Y-*HF]MO]ULIg(lH3A"@Wd`-/sPth\i)2NhohXdcfIUbeq)4Xbs.11=1fpj%DdsW]#n#6^/(+DN+Z9h5Xafj-*&;beZ$3i=\&GWb#l#84nq[i-FBIUtG52PN]Nn\p*B2'c#r+ifMp>0I5/S\'<)Ga>VR'a:mJ^P\#Wtj.Dc<`Teo+25;*SK*H?A9WXaQ(m;oU6f8WaMlZQ,tp6GN30.,@#+rdHih`(a4[Jp9rb(O#h,:BtGbU#n,@kS]MPT@_f_9EPdT1=lF@eP#A8!.B6[3kO]X&G;8/BL+5D0#[gj$#Bi?+n:B)dTL!^rQs<1n!='BnGjpG\A7:dDGut;!0HO!+^Gd!T<:iHea:O5.!RifF0fbRhq@ro4Z%@6[IPbp@@Q48NmI7@++@:2-oRDHtj>a)oBom<eEdZ[cps\CM-YOn#)Y?0B(\M/3>h&Kb_e-n2l]H89<b@/unr,0O*K&fj$&p,g+s+cf]4%/EabjSELThrXZJoRT_o,U^bUW1<d<1;*/JgT2'UKiXmMYWsQ]PJ5N28>_<+Q+kV1is2\(1$jjL&8\G?jki+Kr1A>77npc%39g47F!>MQ-BuEtm@u^W')s4YeUupl]%Qfa%ik4F[PQ('IQ:(Bi3A2,gT0?om+CbERe7B^1mjoX_5"%ai8(8Uk?mVQ7gJEf!3f0DdSBFf>VrVNjiZ1r:NES!Wcdkrm*u)7nd19!:=sXhaAE(!U%Dfad4H__OBb48ZO9p@4CpUglQb!(bd#)Nu8objrhWnkfnjH_#K#"LIT,11rG]WcGOL,aMQ78AcN;)YIdaW*TJ7Fi-LO*f84)S]=?lqgIAA6S]\.kp7@lTF9g<bKE:E\>Hed=E^+.MX*)2V4:\C@GE>P1+)=mAN*B$=,s-E''%SMh0gD1"<MRoGf[ednu!mtR?F]"I(3VL)Xg05U)B-Wjk6]@o>N.jMku"WAo$oOCRMbia!u!:f(3f^r^.+'mU>n.llP8^-MpL:q=G/1=t3Iu@YsfYkf0?$)LU?'[Nl-#a2,d0LdG@ITCBN;jd!ofZDhJ@Xg+md5[]DIofqg6VE`Yo#bQ=r+*"^se+<8_BplPBR_CeFFk#qfi^Gfo8o9^@7<h4Yoi\:I`/k:aO]',;b3C>TFFe4YQfS+M)%#[pT%0C5,@fPb67aj6hhlA++q^-I3T]K7c_F\VY/Mc#'I..E)^%*skF$X::s^=O#LO^7j.XrD3YJ"_/I:ZKemD5=o3Y17+mWHbkYbBcIg=\]%\k9:Vqu<A'm1s`#Zb&Q[o_C(!VV=o4ii?6YT0\YACHEBo2+M8s"G29Le8$+S@6^cs6+-BNc$i%roe$!5sO=TUZ3XPA^"&'(\%ApWfMfM#aO>c8!5C0r8D6A7<)E9N/MX4L"P:Q;Faip)du6;\`ue[C3/L`.:_&e[m+?6H=5Jn2u=e3.0d-os"^%X)qT`@6A+FRYR-bC)i4%V-0-$RTI%@)o.54amXQY/()KY:T#]s^S2$2<rL,G^:bQ^\b-;N"71<ik>f\C(\U4l?e_=YlV$Um8h#Im1hlWa*\c./0=*QOnI:D.9'$n$=]GZ$uO%0PLhIsJ&2r,'W_]e!J'J<SWK(_D6^m/7~>endstream
|
||||
endobj
|
||||
17 0 obj
|
||||
<<
|
||||
/PageMode /UseNone /Pages 19 0 R /Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
18 0 obj
|
||||
<<
|
||||
/Author (NOVI Hogeschool Utrecht) /CreationDate (D:20260607080655+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260607080655+00'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Subject (\(unspecified\)) /Title (Lesopdracht) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
19 0 obj
|
||||
<<
|
||||
/Count 10 /Kids [ 4 0 R 8 0 R 9 0 R 10 0 R 11 0 R 12 0 R 13 0 R 14 0 R 15 0 R 16 0 R ] /Type /Pages
|
||||
>>
|
||||
endobj
|
||||
20 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1720
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1205
|
||||
>>
|
||||
stream
|
||||
Gb!#\?!H&A'Ya=F3*1ITNiJ7Y=Yb1OK9eZK=M(Hd9l<Y+"G:3\[KGiErJpe!4!]B1DQG*/8=%SKhXbS$:jfPEF1M?r1PXLo$lFci$s5ar(r(jTZ1lcn4QJ7/5^Z$!L]`K]qZFgmb<^e,N-N9+;+Zu\+Ae"F'e/'cT9N#9TjdZC@mFQqV$_`$-:/Gbh!^GgF+b$Z#fGm*rN1OkWY^f%eIL,GhC&e.Ya1N;l3Dtt+U*f@0Y7&Xb;m3kF'VPEN61"!<Tr[I"V]0-r,N:^l<BgIV(Q)ip_q.*/\jVb+=IhN+P2=]f;2Us7I1/*M!&In!uhOALfWl<KY1;:oGNdRnBq(CRb/#<^4d@odFa^NL5Uk,)VQ\DH\]c,rAoV2k8'$PKF5Q^^&;8.I*!ROdMRn2;\%%=9YJ:(b\P&M%dg+?*c1+=<$T<,p3caKG;8Bq.h<XnQr;^0mMpksYJWc%2?#c,gddL@<($(Y&uqm,4a.sTV];)YZ/"0PEHaLOQUZ>+n)eMA#pL3bX="bp/m*e[d3Y'+26m2X$o()<*Z/"lc&Y0c@SS`DEuu[-8?%QZn--Q5gd*3h-U:rR=Bua@#:2kcilp\<JkoE9BaRCP82MlUpngZeD][.0'I@T2_42>`E;;%Ol4/47BRRFdO,D:f8a]2PG<Z7<27K7Xc$R-3?n>H_XUSJXFo<8-M/SF+PTFQS@H^h)qoWO:ZE`DZXn!`Dke)eZE[M:8!I^.%eci,FEW,VH^T%7AMRfGYdgU0#\]upO1;+3N-P<Sf+#L5erjL=KVFA(t2R#C%_fW^E"L]_4fm>ASqZDE<%W&Sg5MkD^?(L-c((c-rPN#\Ri6uk#5pW#:YNlV%Z67,@=AO$H&/^tm<;aA:./rK5Xu0H%D80i6]ariXD0J'M,LEcbSlVh^_-C=_X7W7jZ[ag_).pCHl*<tl/i68H@YoTrQ-Q)OE+r?s3[aEdm]8KR`)mU:j7W<%([%]gs4i.=d!o'V]!OHKVunSm"`9)VZ!aC\N_lc](W`\pDZ4CR]-TqoZp%ZpOS]XRgo4`S%(315NT82c<2M0VE<IXjEHMEIH'[S2:6QC"boISQ)3V\>6F"^:9Nc#AU4b6McuF9TEI=89:=D<SFLfPo33J9#9QQ);h<Epr:7'7$nT(%odhnWUPC'28dsK%h3R_uU_CfjA(CAgVemt1Dd^f$%H7S7T;6/NO\+W#(0eXeI2EULS^epdenDJQ%B!fq8M0]Be9b*657@MOE=3?SU29^]1dFb,RZXZf5&8bG?!OMmk3Y`0\J9uJi4*&`d%'s7&$'TD-Q8g$EK7sE^Pk\W<q4t(A&q5GABm"6qUKMbl.>[cj1$YtQ-$5>_=c&(AQ!t89h'DP2b^-@C\m1g&-SG'>UTT>G?6%_Ns"H_N4s.T^lQCdpQ0_=rrTs78o6]Je3,ClloaM^YN(iaI1&d,3jG<sa((]/`(:Jr[9'7)F4Gh:O'b3aQ/g<B48<+.3b9leh+5kWhptfWY`L,Wt8"qinX(S_o&#!,.FoQftl%@\PW\KR[%?;5aTp0.ih8P(s]S/+g)XQu)BVGGrdG!Dp[a&tV-LAifXqPlCB-pC?PW%,,?c]mu#=LYZ-ZC$fD2TU*3g1@E=D9kD$5Y&:33@(cJZ57nqg>sL_(+5kr34%TEUbWX+l)@W9_Hor<FIZ]THes!g38$1ecci&3.$XeG7j!EHml3(+7L]'W$(d5HL!$dhEPaM)PR~>endstream
|
||||
endobj
|
||||
21 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1731
|
||||
>>
|
||||
stream
|
||||
Gb"/'968iG&AIa;m&?bU'b#U'JA/CI*N*U-:/\(YFN0*1'J._-8;;fgkb5c)$bi`5/31/:LIrVOKRh%^DnfR/^jtF2<WAg?_"/upSM=LlVO,(\ikb7E]U1bK*Pqn24<KA0W>fk#TkckhbafIGJ-7#+)+Z65'HVL^&Lg'R*6/B%";Db,T/mC:#cNh+&BXi8"rlT.&o`k0Hc-GHE.*+d:Khud#o[mkZi3=%fRl%7eQI#X6CBKSQnDfhroU[kn7+B.ATX2K$2eNF*F0Pmi*=((=)b0(kTn>onH>`@0R[[`(`;pn8po5(2iYQ&AX:XLeJW\6k&IDO%ue.g(0`9iDkICX&F!+(g&EhL!sfSB46b-1nl.?[.lWG77chFGiGF]_lc=TSku'*T$;56oAW4]"N5@>F=%9)(:MrGP$8)VG&0.aeXC'SqGo\lJ;NVrL,7*a#euOkqbq,:I!YCrW(8nFj"-C"n#RRO1Fs'$jdosd,Ji>^82:VjCTTZ(6Cq3O0b`]BX%:hJ(CP_I$aXN=N1tEEWS?.T'.j3+!(Jg(c5fb>c2?FF5@?cHH9"qpg?F>r?0Lc?BYs!c:isAS<9@oIhStpO;hpfVE5c@2lYXQ!K,,]5JI1.i"H"F!mPD!uS5\o-cRnauUXp%Pm%uJ3n[H-7Yg)Hgc>`hC#0F9pb=I\jZg[qt;F6-B3_1$0,*hBhQ<kb=s2GlYWEC`FAGQ=m>KZgp-@W8lF`<@NuFN78?ZuKCW_Y-64D/eRUk*X:\1csJXHaVnsgSDJN-GJQ39^X@8pb>_TmkfC'=FE-D>iu%k`9Q3@.Ag.k=KbU]kk0f,<ge3s1l:t6)aga08!`+1!OZrugo:?$473VSAZ)fX=?8;tBdJ).Ti#RnIBnY*.31\+S@5#jdT\U)!$mLuY&q%lZPYF$3\U1T8)4dlQPIe3,.22`Kt,G.Hbf7V+#7s\Z/QhB8YMEsE3;DCEa=:>o)ZpUQ.Q2/chHF\D<%jXf9u'(>GJ0+[AA@p@Z'7$5<$*d)#^;*Ko)SD?7V710f#Qjru^n-(\DG@$)1$gitMYS7Q(.+i)=??^j'ZZk?)R:1"I6;T]5$BN0VH9G.T>#\0:7PFg/TOCR(?L=]Wa3-&I?eKpjs^i4?Arcm9%`F&Ne`jL&2h?$X\K*+5SmcRkDfio8chU)blfQ$-!WgW/q?).#!?G(OfRnJROlS*N<HVs(]`jgsnbcFgRL\K@o8f)2h5jIJO^L]]R:?c.W.>Jb\@H&W.1_3seFa((j7lVLlo;1(-e4?+FcHosUH\T[T'DW@KCU8*^5$0uR^!j^hW4YUuLI=WM9+-3(<Xoek!$k&#$1:t)EE4J)?<kV^84k5m6Q!eaEbd51Eg(^UYJQR3,Wsn"(E+-FIrB4Ae&Gn\>m']D6"FdNaJ4sS5$J3p!U/Z[in/aG>mU:;ko1U3'Mt>1s]Ie-p^*Zo2Sa3+M$U`i"%=cEH7F4Nu#`Fn+M#M:eQT[(F;V[+nHZ[Q<:;mPC_.;eBDf$\-/)Zh5q&3PY=LFM_l[:0l4qT!?.,<O-M6Q=8I`m!TmjXP[`Ok--fgjt\];a@/M`=:#p]aL"W''jBNVRAjllJ&Eg`Ee%Ru<+]-;Na9ZUGDAA\6U*4eR:"ie9N^]@s>;O3[ZmZ'2kajmYsKFAS,.X\:)BiJHY.ND-C7U(^<&gY5Dr555pI*0nCp7M)M<AaEaL:eD'E+YGA"GC=;=QU)`%*:M0-p6Jb(PL]R-j~>endstream
|
||||
endobj
|
||||
22 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2057
|
||||
>>
|
||||
stream
|
||||
GauHL>BcPr&:XAWR!m\![oJM$8E;?sYIj$VhY*I&I]*=*6];T\OZ*123s(@\@OI2*ZaLB&6CR`45%=p@^1hYJk5`iJE:B"lAM?:QapEjn$+q+9^5WC+RG\)W?[@1>J4.+u5rftI&;2<f=@>H$Jk3_/91l"=,VV>.";OaJ3<*JVJV_YdOoph'#\A8H]MCl6O>SCO(e-I1GPItd(QkphLG7Hn'#P`s'<7tqF5kS4">HFbhRiNShnX"`eQ%!*9EtOL;TBRh-B&6jH3;LdQ-N'sbC(47_Y=Y^?pKq]*XR3H<f*F3aqRFHH9r_'1sHd1"!SgaM[M!Xl_"PK,VnjKC;3V$[%C>a4Q)5m@i;JXN0AYXZdD]BoM5ofRGu3(oj$Z\k?s:(akfggB7P2GQGt^?8s7<qi<l5$Ug@9!?irr+o=2aq!5Np$=Ib_nrIkq)?"KR'CfMlU2F?J2Vt("hgZ2N^9;2NJU?V=]9.m9"r_f%Fe<DsX:ZHQV#Cb7fZ't#t7"J,3."\`V"D,1OqFRa?rj%oP,,N&.Pe.5^<b_7jbnE'#4l&udO#IXC@2T8spTT%:>.Dp^@H"^K.oX<MeesulX%S7CU;:T3l<K\NcG@^<jn;mpZr<5cn[C]+G8=[-0'fmMbLfiReXJG-`6VK4$>hA<o6[eIGpA>c`&Y6*^c^s*_Qh4"BekZgN7Ag&cAPBNeDsg6nqMZQ>FM_$oIC*U;C-Ec??jBE9<E#9lIu?q/aucP9NVk_f\/L!7<o9gqKs/O^0A<^NtG_4.`=f84s^6+OtKj";"+E&]K5MoWLbuu+0%Q-+O-AWX(FCc0GkH3$!a$ekeGYd%uE^@!k*->[41,16H?FLUq$[/n.s6C/6c0#$@\k=3F8qCT/gOWF1B`hgc_Xb7%`F9djS2VL@[LCFKWnESSSn+!G3+>LOkY%r<=bK%GNs7fK2UP)_o&8>n#Li0&%dJ,B8p/au[udbVA3!?_DNhHPApG<pRob;%Iu'4S"4,Im(:9KHA#-!cqe:0-.&EE/5Zt#J0X#ZC]m4H<Y!2Suen;?a.bAn(#6GRb'bNqd@]fT:I?FO1nWaA:G!%huR%:qh$BD$eOH";\gk';M3dUHG!.d.j4',1R6^3+>EfIL1Q/0Tu9L,E+RD#ADhrAi:6U1.N)S0D/3C`r)#h<ZhY!qO3>dRE6k%O5o>e[CI4siUC_()rjrV/2nP#ffHDf]oa'\)/jqeqoP<-99@"V`0(m+Z83H<siJLn,M+@L_'j+g0A=F%["S%07@6pCjfl$'eoIEIIH'=49&Q0)[HV7i)P#mTr9J0oGQ<:cj950\Vj3biE)=lR0;$)0%)RFZVFu=5H]nf(8Z4JF1^Mnh#)lEV_fIW]uCUBN/JWlITY&d*kG/G23F.-l5gpWndiShqZ4BXn`oc176P`eKFa2U+[SHU*WRS+[U-:adXl-m.9$i:']4m*LA;b'7WT1k5.7IK-T,`+qA89i0-l:g0EW*U_?:)939]U@>QLpAjUA@tgk9mR<GiB=9UJ5GTG)kp-eAY$lEDQ+&Vd<T/@e?u>bcqFn!6h.7hRp^o#*COp6E2fK7/h.CrUp7Xh$Mq%ME6K^NQ%<\D[V;%:X'9!:c&H`!6gb)4b$Lj"=3B#2dU>O'Q]cKeT=%:mY_elGobI0I8G7\9@[.t79"2?FWJ`,8X1996EbOn&)$o5tTaNHA/4&I#Cg"feY"Ri#TSh_8*"3]*AEhcqKR#gL?c\6[p)WbE@+_*]U#DP32OTcsDCW@rKT?GA,P/BfgAIuAl`X^DIeT@ER!7=-0mA!5inL__?e_;mkF*oRNE23;p"D*R=m"Ei1O!>+Cl7PVKu/Zo?S,Aq1,Oub5!qQE4FClBW\HroEr95Ef#[;nltq&..d2uc@hd't\gjjg_)@;8[QkGOh<")dX_BS+@\;uQ'Xo[]H8BE5(A+l&!M/Ka'<]OAb-g?US31LIZ6SPuGh[="X`goR_h9m'7I!Vjpheqt)LQ(rnO%Q%eEjp?ZXIeeXoAS9*ZY3hs4MQOjel]aRUta-"W//\1rdCXRh/e&B$TeTZ"h0-#c%D"@1Rap~>endstream
|
||||
endobj
|
||||
23 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2020
|
||||
>>
|
||||
stream
|
||||
GauHL8QXq3&AI=/e1d69bm5unQ5^:X1iI\obk*1ta&[eKA%?/2d$ORq;j&0U=TF5t2"2-P86):^^=mCTJ\S(2NKsS5`c-6<Jn`&G"stW1`ZO1<Gjo3./D'Hk"2smB40X5<[e^"Z+(X<>`!rf`"Q/^)mnoal8UNbl_8:8bB6k[;bh`b%+J*@n4pBr8NpF;=kAB3^(947MESY%"I#ZHRn,hV#kR_A!LVe"c=^S1kC/\T/Np"3&$,b(rrjdUkI*RW5QLbgiQ@_Q7&giq+_:]Q.YSBfVcGVGrmpQ&_.Hh&6N^4YSHCI5cZ@_8E#TH':_g.E!5W_<HTbVdE\Ud%oa.R*or7]M)=1?P*0XMq'`XD,(5#AjPnq:@2W"#C,kNShNQDm#/[)`He/jsI(pM2WPp%O8UF&V^<BsN8acg2]*PE[(NWWtQT.T`m%>\1$O='R&I]gV%h8/]^=E6BM?%B#P9]kL$3;A<Al11`oQh-.T*-Gq,Naid@E(hWXBPT_Q+RiFY$N*!7fm9tp>H1bqk/g+a;nP$5^m\oriV9ZL"7/*bmd1=`Q'<YGS^d<cYN4(m9,(4eo3I^n'X_NW7<'TetCS1(ADcsHgH%K@uUE(Eu7#3^Fr>nR%1:UhU$\$,?$%d4)MD91td(o6.M-69XXQX^mgHE?^>@b9V5>"<Hn&fn#j9Tt4OKSV0:_kVMU"c<[VQQ\9n(lpsI^>_4Z/#Vb:A.^_"<$@c#Pc(;LNC2RH%mm"B%*@Z-BK14!Qu`=Oe>L'>)U]a](jJVch@7r[\VWCIKprL8+7tG5`$D41X(E26><G#%;6!h0<YTB!S-,D'RHlrCp?eoJ`eM6Ce%6fk;r]#j(Z/'L]=!hdAI7R02%YFlJF6FJ$3,Uct0*a_i%G.P=-/srG)K-g^`-NKJaWR,T-=oAlrD5ad8\pYbg*pXVTt-`JS\>Z)g`uT[\JY9OWq=9?sgiHh@AIq(F\\-Zl,(jk<cs04@8Sli^cp0%Qn(PH-=B\&h=X^"UroHr%&8h\W141#5#eNe,N",qS(("FLQO?8\7A)bKn1.(ir)Fi_IZV>A3;LK`HA?JFN6#l\@NL=O&#U5WX"FF2Z4!4H[Vg_<hlVA#%Uo?m1+bTJ$qOE>P09Z%9DSDp"3.T`SuDEnr/*F'+_3M;sF9n:Jl3hX3\%^o$TR-508)I@X,?gigUc'mma`,H\pMe^gZ9Ur6pCZ2/N<1=d/bmK>C5GSCFGeW)2g1Z0XXf_rqYi"<RBX-.OgY9+87YBHH*d?0'\q8ZJBM[R)=-rE:_ZCHQVWD94pIX;Rg3Z3C6nh:F]&.56M90`71M8Y/89/tWf.=l>EE6[B-D#p*]+H8#>GJ?^pLuHI@X(A82?!W+$8/U:2DJ!\EK\R:E:f]t$bh:.EX1d=^HHm4U>ZXs]C&k^9f]=eksfNi-?#%%X]U=g>-^SJ:$9nc?J`R_Rhgik"V`FWe`O3=B64=@0dlJB]&'Jm3^/11.4*;:mMX"[W[ZA8IY;m^Nd:_/(^g%d`^3f8<bu=G4W9Dr[R2dn.h1+35iWUd:*_PEOuY!0LIlfQR1RY^DUd;TO'jG>=H*d9M0B&RFiCh)nWt\OR.:JaE@tY<KM8*O;fm]L'MP//T9eVa6t%rgBc!IF^ln#7D4+mfS>*+,0ZN2d6toa;cek?U`3hbCTa,mAEGugcMn.cBT#RXAM!i`8c10muRC5gPgTh`kMW=%h183nNZWp?PMirCBH;oiW8O,E\;IZ5j8H#]5l-pZLWDZi&V$a1-NH>5C[@Z<FOG,/rm%O7l#<'\iWe75i1G+`dfk(9<QTC6jldU3!WieYt+_=>$,_@Z(%H&;H94bGip=C^!3-q,a&^."+NaOZ5:OD$(]/U9A***C>ctXb:P4M@//S5.Xo;1hdUBYq.VL*UuA1Q@H()bFuX&:g_eI]G9c1)Go^D1DQD=?o-RHa@TflKq)SD>P#RiU4IX[9!;_*&G>N/m:_TQ9."R1tIkC+IG)oXI0E.K$XK.M!#j_]BfmPW1.t<Y#[Jn/ku"B*J~>endstream
|
||||
endobj
|
||||
24 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1769
|
||||
>>
|
||||
stream
|
||||
Gau`T>BALf'Ro4HSB2GiAZ`X:]AbD^il4nU(PfFT*?MeX(/PR*+t\!/dbioV$^/;5+QI/F@u3X$^@0k'6G^JSXo8PuJ2^st^SF+4N2JoE&MUqRGN6NK!F[%5_?IfA_gMa-kN*fHZU"Yq7m*F>'U0i!Oog<26n)ID_gPE\$+YWOo)T"=4\$t&6rDQ7hLkcsG`3fQ+Kjo'g\Vq=WheekY@32ClSf0g-YT8S/!UM%:fk4^?Gc3La$6`bI6'/Q0Mg.7I^ciojq];&8U,XeDp=i0e'-lc0`DF>k9WAhW,Nd:EZmAq?CN.`_HaR%53Z47BQ/;b5,/kE;EWN,P7Ah[FTbnJE?k3+35D'tp&#F3<LJG=IN![?3WjR/QU]^E)XKfR@0%2/1.r:E=BHJGIk",%P9G"um"W\3=]pq^c8PIcAF)n8B2!)qgXg;^U*V@jcr*$DKT=tLXVVPU9W(a(p/5W'l8bk7`MpSSJZBo:.O<T"n9VhN_,%C]a1djBS"#SS'SY!=`u=39\6;EnPd';@cX:urL1IQFUBRG2<&!L%]QnOrZ`I;5D]ZbPNPgaCh'@ZAp`qo,,BW@8>)d]_VOO<PI5(D7M2m)ZL_`d\"@#50TC^fme1>$gBstojkA>G[k=p\3#tf%(r;iP:qpNejc;UV_)o9S=,].6T>Q\67:Z=b]^!0W:[=-Vd).(rXIdptj:$mk>#I,9q&4RFuaK4e=gmZ+F,i%k+N[AC7D(@g8.VP..SNTZ!$VhtNZ[u#/qB!)]p0%]?f`h]62[OPFh1t)W86NFKFtFa@F?XU/QJ+Og&P"gd^S9<*"G:lWQF5I7fXS[CM'F=%[;[TqrD:\1>sV?DLNl(@<3#]#dg:(VX8jcWl?$u+Y0Hr@S*i0ObQl\2:qkL<SV(9p"G<m,l932``+P<[5[B+RA`^m>eQ**uG!Fr3I:b5Ss2`EN+HJ;T&oNX<m,SRAD+D4MIg^jN67M2$+Ks]D,0]U+KKG`4jd7t)2lP)>RO7`Y32VKb4jf(t0a7+uU,t0JLDFTo0$?/W9Q.0s^-mKdBo/Lm)Ob,DnVX@1.)(b*YbJGNb'-/"dSioA6+j/l@eDM*KBbPNZotn\$h1ea5SU"#X>!H1<=jlH<F/iBBmnFG6I1bf?TNN?fD:9EMaQiYNe-,h9n55/)qg4e@)l<,C[MPRli'pA;WZpE.9c?AJ3,lc#b_rJD"Bj(_e_9\W<qnsCp&t2Rc[6k!Zdb3BF@(Y@]mW@*h@-\]f\R-Q)%q])u4VQcHY`.b.17<YXD,,dpX(>Z^tY;=\ZEEj&.aDhs,T?0bYIqSTX_fnZBGR;/Epi_hCqg1Ge!m`2q(_0c21FBTbdLjDgk%92%@[QU2eaF`T-sJ&1%F*QP&J=YEVSe:S_ZVE&_P6@8:ud?aHn8PG.Jg8^:E'TVB9ba3bUVs$'K"L!Hn*7JMem%^3*P^b8Tc0_B5,K&h,hJUHU(dn'oD%&P\>UA&#j*2e6O5RnQT+?m]"MWkuC6]TL%V(^_=\6Z$Q.<tHpZ-.4(nW;M,W>N!IfeQ0htupPb:&sDel''121<+jgHAls7Z[:=]>l@3rPuUb?Rh4TM1ac<B\;DS:U[ts3>VUq:A?`d@2.Z:Z.:q$a!7m@@Q&>,qid629$W@*#o6Y^@3+u0&#SCSZNT'QI"BbjmM]D9X=WAOYibQ\>A]q:DToR)Np?+G(![4G:0pXbs%$6,-9M@!2DYqSmsIC*np@N73tZf9Il[&Anm]kF/H4b!j*eKq),;fOlRqQ$K`hV[!^`H1JH~>endstream
|
||||
endobj
|
||||
25 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1810
|
||||
>>
|
||||
stream
|
||||
Gau`T=``=U&:W67fZ?eIF9I.;#a23WRF[3B:,5C>.qp*t&;l&b7_D&SZJA:UHPa?VMmDY_7?'lif\LK7Kaj]")9#rI!r-=6j&6$g#1Fk8S8ak0LY("kpAn]Sg"ZX<3n/6h&D,DRaB!p1/4"s4>QYs\'?B7N*J6>3lMs:5gGWlh,V3:2$m<!O[_mYUL*[gZKAIl*0bhlh-%pW9^;B&HGV0RC3eUXbOW!R@.]"&d-7@<IC^[*P$pT.;EX$HFQ-B2LP(`=-A^Xp9Qn`3jcY)`>mUV]\1-:*P2jh>+!]j#c7>YSrH_9PLR4%5Co,:*5HE/1^5]iB@67^Vl"KS3K-6nO>3Efc/fdMi+rP#HO"g3Q>:UQ`#7lf97_fOq9+G_b'O/\)sX-]^De6>M=o#n4`5]2?dlp3oR(Z.;bA!#%m8.+%R!X1k"h^#:e8/>,#,moDl[IS,8T@8Ll,V1598ZZI(%KI^Jj&Q+'Z^ho9[(s5rQ06,gBUB6m-0u8T!gQ<lGHdC5g_VVU7hA6Ll,Uh).tULU,6g#1JVhn3bCnB%1r.<[beeK=U&haj1'sGXE53Ko$/;:';[&kbg>*LAhW#.#Ho<\V*=VGA]>fZoR[UNmcEM='Ri2FS$F4DrKEHkZNmi8J>@t7-jUZ#4-H$u8er%2lVLA(AlTnBfoMp3XHtn7;G`EE7WZ<)b]>R/&![Gi2(>?.:ll\oa9Yh[9-*YUV#bI6bTAX1;m`idurV;M`Q\pNi/VrLL]Z]bCH>8qk'/*SN\+/k"n)]VXX5cV>^LrmeL=N\7UQCfGMM5;]gJG_,)uD*U@]YKMS..2*s6:3<d=RBURL$,W,M3ic]n_J*`3fcPVuVi&08RFT]fc>Q7Im?h;%Sf>UYO1kN1[fMiF^_qg=0uL+htlgj$#eE&OT[59:3oN!$*WTeVI(iY=>S:],Ffd(1+G;eA#9]qZ+2S`a\=ZW'87[@+U[<$O%G7Ae87.]WFdK]c?Q+esLc\`N_CG=X3Mqlge*I;N:H_#YPjeRO@%qUA5(aHh"tn5a0m-QW:!Ga5]&C&M%,'\`9p[@eZV-chs)'1j!6b/7Z%[%jAE<0Q!`R[W1E<*_Om,fP"D\H9Bc@f0dN]^?OmWU7*+qjC*Jgg]-\Wr1*;SUd)BNS9m>Sflj*qn;$Vgd/gB#F@B9d;m]_L!`SGqJ/LJqP)F^+@_)r%/KV+g=UZ\4/5J$cRpi/__?3sh"r`MlVXshs:6Tgi-B=/2^f7DGR\K28poO?<hO4q2ca9C>Rb*&E'YD1%V\*Io(u**60?d/.Cs;qX(+5HOD-bs(#oFFfC`u)s/2n!h8u7aA3)"]Q>UR(NR$?$6;pAmPK+_hE.P;7Q&*@%9S.?%P[hAZKE3+u,PB'Kui:-\^1M2JZ5cZj:306M`LN"jK'7=(^%mc8=F,6+7D,ri'97N-P!D]]hjG"h-Qh*>dj)jF/39,e9`q)M^^D%SrgPVj(L;:9L3WuCcMOpbthS+QOc%^QUSU3tdVG7jR6cRkAAP_5h?%i:hkeG4c2VL]_jk@@[0s4,n]a47tDHME8AW&qQm-"F4n=87MHsg'+fYU8+ZYcp41LA-`>&*4/42>aDUFQ-/E(&G,=:$p[e9gdZ7<Kcebom[/fR%f@p\hnYkKY:Hk?Fc:Jh'B96>93Xc'VHqTuH?/1c9QqRX[`ToN6:]LIFdm^70Jhh:BFd[li[%P+JCsku7Dc",&k2h['>lq31$a%a_PIoUu'T/dsX?$<Aq-FlCjUiA(VoT)Wek?L18U1(V`i4jJP\ZL-dDG*_rJO'5>R'gFsaa#Rp]Q-,S;e#22W_*?Q%S;7~>endstream
|
||||
endobj
|
||||
26 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1595
|
||||
>>
|
||||
stream
|
||||
Gb"/'bBDVu&Dcq.k%(=$?iU=$:qOZFe"!4.;lNoF6W4Q<La!ZKFQtFRm2`q*LMYXDe#/udM@aai@V.;1+9RL>epN6WJ<rng3aof`/D%Z?&[6Wfh^ttV(?$n?KEK/YeFkm6hl^<_6rjMP93e+d$mbM%oE5HALm5UVNoN6_Gu,nk5Hu%:c_[3I5U:DUl!><I':3bs/VrGurmgNZ5?ZJ,M;,:&RdC?rYQsJ@25&ZT;!*!4/@R>1nbpKen@ai])9,jXn;A_p(`PHrgk-D]i0??)WQnN6(m^e%q4oo&!>Q(jN\.oeT^PjZo2QA25X,ELOp0c<5X(hWHPDfje6GeBUR7,![g8bQGL8js[<6WZ+q&fk\:a04Cb=UkXa>i3e.Rqq"378^"tlU$HIEY_pBdt,QUa1#3hh2jgO/"%YDHm"m]iqD^gLhAW:;4Bn<]B'^Zc"n7pDZU7kuOM$s^F7j(u`-TbUd+0%KDKj@:RUpeB%3,.jqD"Kf,V\;S0JY3j=XA084:5cG0$IBEoRla7'/(p+nd10>tbX,PHZr8oj"&T+"^2Wl[QF'+)]Wh<%L-oU;nS0_$cfX`kZ3tt2_f?)l8*QLG]+c@Ju7"qeL'neWu"dE5n9q5PF%b=ukX;@p;2\&LnA7]3_SaAtm@F\b5L=H-;dH9oSgZWq:\=4!4U)u&)DF`J[0d_Q&7M\Q:Sa[]+WAub(0(GDd'XV(iK-=nm4-8-,jIatJU;#+h/h7?+BbL(I2JKIJ(La7_F3X-./,%$&bMA#1#]&UIot#LaU1)U5lYL!]*'D+$E#]Q/XZ0GI0-t#WS113?Q0i\6&24>0o:UWEh^i6MV<`(Pa@LCc<1(AFELf#Oog3RYb^qrA$M?=/REA3KFJ8h8'rpt68PJsG:,5pN%PhD*a*bkD;KSU1/4QWl9/uIG:5DnjI`m]F6"XZr0dH\%#ehdg9cq4.lKm.;l-m,N9^<h-&q=(2=^L0(^43[)Xrop7`W'-AQYATt@"PGZXfaTrI_F7Rqape!TSQ(Y#>+mR(2:K]gKuF_qLIXJKYVG?/Ra")]+AI-rgVF9^)AVk47U3S1u+Z)<X'QZ5osCg9>PI->WaD_LJbF,U*:)Ki->m54665lijOnQs7=0G+3FL/il3;4KcU"K&3%WQOtk+WioWcu3PG];F8W2i^gLiT`GN+&`,01],8_G<I:I9/Ud73J_58!O8)4rjHj$\]<_4&-SfDNc(mOJ!BtL*4YM7H?SJ`i>YNh^bKJa:d<N7O1#1C=nqH]i6h(accbG)q/SG;("kM%lV5Ra8!S/$:'`!Ds[:7TeRTXW/eVg5LCJl2"PK<fjP,9<7Kkj0p^r2/Iu*34%BlND9"cFY:R1S2G">blM:+qk("1fCkZP>A$+.P]7%4e!nZM^gX^&SCq^ro7)YpUO0mi+9<RPaR/Km_Ci#%tF2D.b/8El]`#d\5$o>`XWCf!e#k&PL^c,2NL)5)##"j%^-NJa*PA:bN[6%D3@mgAZ(UXVTWe"b3"cRJ0\QEBEWgY/)610YKR\Ah1H'(;E:*O0B-MZT"_q)Hq=O_<Di$jO-K3HbtPVX43q:)"6;bF;UFVN".9%Vnu@,BIL"?j86u~>endstream
|
||||
endobj
|
||||
27 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1742
|
||||
>>
|
||||
stream
|
||||
Gb!#\?$k9`'Ya=F39q;r2q=(.=jC;FRl5,mAI2RZE\V&,\/:^VVHJ)IhnC?2!s<^?\m?pQK_:jr=%>dL3J)jB05CJVCOk"MG]c<'176::]#9<E-[7_XmOZ47o3Dl_,A\`85QXIUJQc/)Gb"8R"VcXW'B-R]$;,sW">J?sIHlHJ0RmM.+?m8_i;sV@j+8B;4+oDEY$L%,*ZXHHpk4A<&72%tR,o9HT`hJ5eQ?s!@T1VI@'YO70>IL+$1G3SbbJa8-1H8TA@*oGQ8'K,0B%og.[+ZneT7+*J]S;eTOlXGCuRIX^Mib.bd5PfKoMe,E"SukLmF1\0T*7Qc73MA_hdeu(Se0d9Zs(MNr/.J_:;:f?0F89N=n8`URNI_J0=1enCp8rQm<<A1,$Ld-IY+'h,n>0bHXELZGGUWXkaUj^"!0R+-UpQf`mbJ!9;5;1NK7WeO6N!JiLoY'W1C:GW&l_.;m-]aQ>0TgXVG[\5:;jRq4]8?Ci5W,/^J@J_Q4S%Wc8RCWkgC8*>4BK_nI-+kP\D_<kp017?u_56V5Rhg:ud1\e'26:-p=f5Uh,RHKCl"=u2*p4utNArA0PJ7iHe,8:ZXZP38jN-Kn-IL3Dr^l]+qZ(r+/#8Zk8@33]!YdRfo0<(b89.X/s>&cLOn-pbRC]!K:;9M@.1ZpH%UjbWd'Ig5ol>UF,icio$6XipP$Xoq!7`X)g,0SiR8arE>;5ro$m_20AdP?c[?Y/S2>rWC_=PH5Cgt(2BJ-:fdhMdnJjt\L5i:T!'B(0-,$ntQ;![kHLN^G\IF`qT,<2N(opMmHknQ+b>K!CompK4S>dlcN)2XNRPY'[%ZA',:ZN9@U^5EV,coWlTn[&@$^-7'q1Q"I:hXL5_>gij6-WbIi<M]tei?ieU4m9i-FjF(]:HCVl>Y/>3Yr,@6`.S^<olO)Tq.APE?Mph`ZZ_N&a6S(;iq)4+@rY8'U&u.j`PY,L:5D^FE)im[Cm0/+.'QAK4&U:Z#fioS;da3(EX:4/[q(U(_Cr":N;an(4PAr2;;TUc\B@!HC?nOYQ8W%hQnf8DBK`:9qW&jQSL'F_PL'5(P_BX4Xell;e>B\h@Z-;Q#b<b<s"q:C"leJi4FtROF0'cd(5-`\lXZP9)?KJt=gT]pf<5c)Sn"X"#3=CF.p2cbLZMV:=g0m29]^C8"l(>kl-#"=')B5eL^CqOYI:JqIm:BB.!,OJKdsW.Mf*JQmIBn[FF%W.dRaDG7(>gueQU<HA'nl+U#(g97&\Ul%30iuVL?rtC]%b6P$Kgkc\'KiV<VcpUa!"]q0]MA[77;<E$(+8k`hks<!`4^m!.PIZW.bgKO":N%lg7j@np_B$Z7(Iu\5q=#da\>`>,0cG*X.QuK9<gg[ORGBm*e:46XfN_6TjfAn9Fp5SfS%F:75BHiRad%3:539nF*`)[a0#_5*Kr#)D9g33(jK!1b&Uq]B"(IqLG1kfVo1n*%XblDqg;_G7,s%E;e'+*o&]>B>*>#rKtB[.=@[TR(5+pRE'WS1ioV`9q>Sk)L.7WIkB^4nns@E1MhMQ$bVTqnFjPQe&?:46%,X7ie^AUG%"$(4hftUUOT!lJF]I!BrZYuLf`%Z<"Pt[?iDW#Oa6tlWG+6l^ZtJfBf>t*p!kQG.i2VXFT*c3ahsuGEd.@Qam4,sT3P[&,93-2Wj]DdfNG+MKu8=(IJS9unf^fUa#V#lhT#5"m3I^:]H/.+"oW&%^nb\L"?u3D!j$kPQ4KP3~>endstream
|
||||
endobj
|
||||
28 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1847
|
||||
>>
|
||||
stream
|
||||
Gb!;d=``=U&:W67f_W]]`WuSd!<(KY3S^JleT@\KLX7:l;l0g)K]FJp^<<!,W5Ea5'3hnUE-Lj>@e\W2.9Q@>bMV7ui7Ss=^7[_/N$gk2ikY=H4<KWuN!T"lG?c9!Y\]p4na5<DoQ6=LlOhHU4p>A7,.I`8TL9&m!(/op.0hG5np!QRE6mO\!@"K.$#`2g-6?[,[6n3Fo@NYNI%l/S'<al\0WQ!.6O?pXeQT@$@SrK(0V62HS%#"BiK]kS4M4N@J\R/0iJiC=`]3mB$,=TY9N3A3,8ea7r4(CPB@LoQin=lL2>UM=.Z8Dq)L<2nj"pbNBB23FE<DYBGso0.K@/QmA?1MY(YLV,Zp?:X)]<7)P9GAeD&_'`CG"GuCRDGTfQG,=]54rPjb[J6=Cjt-qS[^cio-mc&)fs=bO('S4cD>krDn%<2&d+7)(3Ws/</iuq.1^jPP<"t;RQTr_;BggWY4BH%*V&]Ma0cm>c;qF;ONu%BPZ^-4s.qg%WO'q\''%>B_hSZ_AJP)DS@H;3X'RPKA/O[C<ap92'b;FiW86pQ<F<)AI+7</)N$)7mX-I%Ymq4m!s[&<[WTil6*_7H4Z0AlYmuS_@@];I6NjOe5,2@7L+8o<!m8b2Qik.b.\#qrJj+K&YVNF)bGf.0A@d?$`"s@n8^p%\8,5YhUQ?1B*'0;db_1SR`AT8UM,tAK%@@;\AE+e^@X]9B,##nfm10O-`hd].B^5k+-][$C$A][-E:X%V\PRY40KaTqXH#IPh13nhnki=kr?1*M_gJB<p>@meL@ANM=Y)W*l1`'ID3Sd>P[)dDU6XOi`K]u:*5Zgltm&u;;2Am($0fSUeQ\=&R97X2TT*^doGFpa@b1I@$FnG3L/je:,iJ\5L,g;YG9mhCrp_5WBeM1j_e^[TJ-%[jb(c2K2%<"%"p*nR(;*b1;OK0''/kX?nQN1OnpCqA:!o^"3+_S]+bpJF#I.PNj)]<_^"6M&Lo.i<d?FNC2ofc*60mgh-i!>h<$?UDbd@Xf&)7Da!jA(RV]dQjnp)nr`%8hOcV$p'=CB+F%@'T*6BugK@$,.JBM98[HB*mo&OYRW'!TMLY8Q\aQ=Q+NR*NB#dpW"+e?+2eJT'2f*H"AC^moB_gLNa?I=)2QAg]B7)a&CjaN7mNlClGU6,aPm@%Muhf<"+RVLD96E/#+,Un`E>,Xg8XFpaFhV+WU$dj<;FiLM#Y7M"@F?WeIejdFIVY_3jDFPQIVd7Vj((m$7SPOW&R0O0!.W-VFG>5D(`+a+@,[!^"mB*oRdC_CRoHJu[/dH8'h)W*A4m/T^iTg'#e-K"mR)rer^sR0O2;inZkJ\3?fYh3&I2ibsE6YnNA"cR)kQ%dh&JfmjbH?0l/D>l%gi0N)DuK\8[m\ro1E"2r=Pb7;3%[IaB`r5XI$4=YT&gg05f5J9)1iuj.KVeA;II-JqM7`%-YTV0T5Ztr.1:r!Q'S2_#r\]X8g5R>?ptG;8`JFjNqE2T)Xtj5$?IX'%!GbUF8RJ)S0(*=B*Re"^,:W!9e&__9Fk_Fq[Q'H]>d)IL,(Ojb<Qt=ZbPE8A)F-@r^_!!a/kYCbRW<blYFta]r'@Ss0nuM5YWBLMd*\F3dL9Y2=^bDTYC"<!rTULn"4#<jhu]!q@Gicgc9uSf@'Sl$*m7%#;?^cpLGDeIY`<GA.YJFec0E#FrF+1\h1lR<,/eWF3nJm,%ns83P]GC@unI*/r=+)fr6uMP0@g,0Y<6d1!tW`c44farGU<:i[0285*+g&S)qPoZh!Y;X7'::Mc'!I^;[EqGD=u)ocZY2*tT(^?JJenl/KKuTYO2s4n"WWJbLMX6>7:[I'[317Y]<?)%'=m~>endstream
|
||||
endobj
|
||||
29 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1944
|
||||
>>
|
||||
stream
|
||||
Gb!Sm=``=U&:W67fM5e<:.,,ql'G0)`(ai!3?$G=8_*(@,V2e:!>^@L1r$a48j$W)[N(?kf$[)98F5m*gVkd5J`)GeT5bA1Hj%=p$IjgX2,MnF@Isb1Nd?3L/DIW9f)s2&M%eQM7?70G2<bG:I*7T;LdFW6.h#[%6Y_<`'S;>9Jq+&u3*cL5UL46h#soH0OEuB>Dp<JWhmQCiCO*W9h4DBi0/Vf[QG9j<c!7qZ(d:7;:,Poif-8]P4;d2,J,A[)28#(c?H,nm1\aZp*`"YPD**8\YMfXlnk9g(4b:uh7R%ao*MKY%>9rin9qcKM.>pU!7aQK?8Hf2g3`8-aN3sM[?JC2O=Fl#Sc?g<Q2"D6Rk'Mfi_5N-^>.04H&`c)6#Zg^Y@p.+eM4*!+22cu#]-QU#K_7-@Y8Qpo>SB`r8lRqh>/\EFW.fTGqOto\ActQ1(Klfn>@H\QBn_[M=55%&0c=:S[]\f&hR*=&]kOYoPBj:]I!FU8<0<JKiL1OQ<K!s"VR@"q@g.m0LXi+"JBD;nY!L-^s-:c<Oms%k(=1Ze%l,$KX][*lDBdRSD1p&NZkb*J*)]XKQ=Yh!f&*$DC*=_Yb<%_:8Cj<IaJ>k-]`#M]$j6T!9u@>P>SU'M9`=]X?=fYiBCK4W%1XNa=G@m4KO:]I3o;W'[lK+LcplElVm,Jh&b/!;V(fn>V1(ZK$G4.NU"4gA`)*tSBIMYpOB*34Fe+o:)gpt5"pP/H'P7C1rH\,^]IUMMiXD\f(MCW/P+H5`=mE=tJp+<0(YI!T59:Dd8N#:B2:isKY4(MFkA==PHW0UoYEl85[n?%u'O"(-XNpNSC,Q\`E]]^\Fh:sB>0F=C4gU_%JeQ_TmG15"@I'9b_-S?,C3c%u[*c95E$_A=[0%09T5t#hD?<&]0O(?L`Z8,m$!0>YV:>!U26UBB,jV.-<$-/&[1Q4`3TIANc\4%:9^K/)lN;/g?trt;","^ckq*IJ8ZK6rfS<R0_B<@8bh7Wg$,Lit(8#P'bp$L49LQbB/toQ:RIatDBClr.0tf!Ebk\IrQ<c%s9QEJ[G2N$bIK0:+q$g)!iFoD>J'-esL-14l>c(tjDW.1H"TZ/hV3K-t3R8O@kcNLPC/&`QD8.sqLtlC%PK!U5?^dd[df4h^X1Xr0r4lm)'k`sG"TPP.X=.J=l3UfiY*&nZVVqgfhGJI'VrnFf+osmQdgQ>&gjb6"@O_'dIcW-3:LV2ilm<Ihp^-L58(&]u_fO]uU$&hh,D4`q^6Rd=$4:>oj/lk$c2rg<"H*Os0JM:t/OW10EO`gRdH.'\8)5D"q5]%FPs#1&8GZaGo0QpZUs%^IY,%o;cW_5@-71if%',d92op%rV;,`:[ihqO==c;O*ZpOQbRb0$c^@DJa+B&;0NE:\*M#I$7@Y]PTM0CA3#F_`Y\FKF(g3`[[!N#tND>ihUPG*9<M$9n].*rBQ[#WSjWnGh>m)U\[;OX$g\Kc\\MAEB<-c*,mnu;GN8_eP71)s,F/>\d/rEg8]FuX2<nG_Ms.*M^.CKOiYY@K_?m9l*.KPXMc@1orE;<^[8.T\8U])W6`<;K3?"5IV<13'[^bH<P'6JZXc`osVXHm:ON>\m,AVh)1(dIiAg7S[OJ=,<ee0MF[F!h>hG$-kqF1a%sN:?;9a*E31cS/:ARN0ep6HPNamr<io\LDL%9.k?j'WZh`6j0Z[g9J_G>901;eQMX\<X1ddmsf2TF"&nU?tD&K(>jP;6G9=ur2:j*9@H!TCR&!]hW&.#P)cmKYCi*9&jMR##7-)C$m@"!1U-n&dWcpR6mc%<;bRkR79UV%0V"#tG??U$,L1>YAg(0E!QNMr15Mj*=Mh^biPUFLkP(QD9K:7-?;[AB5*hYD#2D^ddMWf(H74[agEf^/k3&]?Vie4[`Jf$P$WYJ.-l6mIb9(JJHCKtOp$h+fehlUh$QBFubl~>endstream
|
||||
GauHIgQL8M&:N^lHJ_7C0hB#dmn8h7A?snBW_G7uk(OU[g)qq>`0):3YMZcCf8Q+O>8>AYYkrJ;W;AE(+^M2F:()S:`\=o6^c79/@"B-0phtC9mX=K-ehW2s.,bJbBGc#73"3lh*d^$/UEB]cO,&2$_+X_&"m*CpCVM!B+D+q"-S`9p!L*lCEsc)X3u^A2aMpli.#r[7s)#H4kg@0jre.dIr+K>a\Yb*S%W'd:a]g+VmZ,GGm`$q5T`;8R;h\=9KCKSocd1s&&:$hY,^],ENCm&'q<c73fN@V51.X$n*JR:YZ'`7!9sIU[UsY9n_L\$:*eVkOhk>*hcRh!IKA5lTB7Ie9W-rUdV@U-a>ZKe6IQ(8@9aQLL>0h;ABb%'FYrmBC\d2crOs8FGl5?Bi=A(&$VOX>tL]M.-N[nN[USs/pe)[&M1DS&YWO6,7nCm7b9SLGOI/la3G'6\BWMG_k]-)j'-L=s)AKWS+Z-3g'Nf*O<>-E-."]Kq=C=FQ,%eU33@%!FgW2TMa=Hs$.JR)\61Pn,X>rZN%l\M`#8Sts\'L1,,Xk+AO/f]OP0a0/%M'7O)6r#:/qX#^JL?KtIn/I[l-dTAs,YcMW8A6C!XjB*:"a32h@nD]Rd$YIAC4f=oNnFdo)6?dpLF!#E3CWp[L&0&L_2T)X$mE[[KFHF0^hs:8ZIMkK(O_T4O2WjJ8JCnJ%X\K;L]iHni:Hi;(W'c;HGr0>lG!\oHCpYlTXk`mX"L0ON7Fs*TKsFlH\5Lf@JepH_TnV2XffF$qQ2k;6Jim.!gGFh"JqgkS8^g,/k&LN*&iU/_R`os[!,Jg#L[QJoV)q3D^SFIfGe(#+=Ft"/TB.g\-C6f^cu>+W21e<"&VjNXKLQYBt@+rIKJLY]&'1,lP<eGC=jihUWS&S9Y"N#6$QZ/\SRn?Mh?KfIXE/9_4IZ:ckA;UFb97R(G]`tUKgkTnu';]U,n7m!iP].c#Hof13]qcI"#<>Vtc9Pr8\0s8Q/RP>(mE6>G5Zk_AUD0LVJkR6a!Hqqgp:fYdDbk[1H\\K8Lpd6/kBaAk?'<=&u/\bP]ne8q19C:TIE-?14/-;q:i>,kVKBUPT$GS^\Bd6LP]&'!;fd:!-8cs'slUl59<Ds-REWi*J#B$FX^4B`$+H;[DlOVOJ?T691gtKt/=91>'Z1a.LhuJAk=)p2<)n[RsK*^R_3QhLG(bhkg~>endstream
|
||||
endobj
|
||||
xref
|
||||
0 30
|
||||
0 18
|
||||
0000000000 65535 f
|
||||
0000000061 00000 n
|
||||
0000000132 00000 n
|
||||
0000000239 00000 n
|
||||
0000000351 00000 n
|
||||
0000000556 00000 n
|
||||
0000000456 00000 n
|
||||
0000000661 00000 n
|
||||
0000000738 00000 n
|
||||
0000000821 00000 n
|
||||
0000000744 00000 n
|
||||
0000000949 00000 n
|
||||
0000001026 00000 n
|
||||
0000001231 00000 n
|
||||
0000001437 00000 n
|
||||
0000001643 00000 n
|
||||
0000001849 00000 n
|
||||
0000002055 00000 n
|
||||
0000002261 00000 n
|
||||
0000002467 00000 n
|
||||
0000002673 00000 n
|
||||
0000002743 00000 n
|
||||
0000003032 00000 n
|
||||
0000003154 00000 n
|
||||
0000004966 00000 n
|
||||
0000006789 00000 n
|
||||
0000008938 00000 n
|
||||
0000011050 00000 n
|
||||
0000012911 00000 n
|
||||
0000014813 00000 n
|
||||
0000016500 00000 n
|
||||
0000018334 00000 n
|
||||
0000020273 00000 n
|
||||
0000001507 00000 n
|
||||
0000001802 00000 n
|
||||
0000001881 00000 n
|
||||
0000003770 00000 n
|
||||
0000006014 00000 n
|
||||
0000008177 00000 n
|
||||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<459a20e2e948bef44ee56942063a15ff><459a20e2e948bef44ee56942063a15ff>]
|
||||
[<615b7d5ff26d2613909ae4f44e88db16><615b7d5ff26d2613909ae4f44e88db16>]
|
||||
% ReportLab generated PDF document -- digest (opensource)
|
||||
|
||||
/Info 18 0 R
|
||||
/Root 17 0 R
|
||||
/Size 30
|
||||
/Info 12 0 R
|
||||
/Root 11 0 R
|
||||
/Size 18
|
||||
>>
|
||||
startxref
|
||||
22309
|
||||
9474
|
||||
%%EOF
|
||||
|
||||
@@ -1,240 +0,0 @@
|
||||
# Lesplan Les 3: Cursor - AI-Powered Code Editor
|
||||
|
||||
---
|
||||
|
||||
## Lesgegevens
|
||||
|
||||
| Item | Details |
|
||||
|------|---------|
|
||||
| **Les** | 3 van 18 |
|
||||
| **Onderwerp** | Cursor - AI-Powered Code Editor |
|
||||
| **Deel** | 1: AI Foundations (Les 1-4) |
|
||||
| **Duur** | 3 uur (180 minuten) |
|
||||
| **Spreektijd** | ~55 minuten |
|
||||
| **Hands-on** | ~75 minuten |
|
||||
| **Pauze** | 15 minuten (10:15-10:30) |
|
||||
|
||||
---
|
||||
|
||||
## Leerdoelen
|
||||
|
||||
Na deze les kan de student:
|
||||
|
||||
1. Uitleggen wat Cursor is en waarom het beter is dan OpenCode
|
||||
2. Cursor installeren en een Hobby/Student account aanmaken
|
||||
3. Cursor Skills/Docs installeren voor Next.js, React en Tailwind
|
||||
4. Een .cursorrules bestand genereren met AI Chat
|
||||
5. Een nieuw Next.js project opzetten met npx create-next-app
|
||||
6. De vijf AI features gebruiken: Chat, Inline Edit, Composer, Tab Completion, @mentions
|
||||
7. Efficiënt omgaan met requests (Hobby account management)
|
||||
|
||||
---
|
||||
|
||||
## Voorbereiding docent
|
||||
|
||||
### Technische setup
|
||||
- [ ] Cursor geïnstalleerd
|
||||
- [ ] Student account geactiveerd
|
||||
- [ ] npx create-next-app getest
|
||||
- [ ] Cursor Skills/Docs toegevoegd (Next.js, React, Tailwind)
|
||||
- [ ] Demo .cursorrules gegenereerd
|
||||
- [ ] Huiswerk zipbestand gemaakt (les3-debug-challenge.zip) met:
|
||||
- Missende dependencies in package.json
|
||||
- Syntax errors in componenten
|
||||
- Inline styles die naar Tailwind moeten
|
||||
- Missing imports
|
||||
|
||||
### Student voorkennis (uit Les 1-2)
|
||||
- GitHub account, basis git
|
||||
- npm/node.js geïnstalleerd
|
||||
- Terminal basics
|
||||
|
||||
---
|
||||
|
||||
## Lesverloop
|
||||
|
||||
### Blok 1: Welkom & Mededeling (10 minuten)
|
||||
|
||||
| Tijd | Activiteit | Slides |
|
||||
|------|------------|--------|
|
||||
| 09:00-09:02 | Welkom, titelslide | 1 |
|
||||
| 09:02-09:04 | Planning vandaag | 2 |
|
||||
| 09:04-09:07 | Terugblik Les 2, waarom Cursor | 3 |
|
||||
| 09:07-09:10 | Wat is Cursor? Features overzicht | 4 |
|
||||
|
||||
**Kernboodschap:** "Cursor is speciaal gemaakt voor developers. Geen token limits, ingebouwde terminal, gratis Student plan."
|
||||
|
||||
---
|
||||
|
||||
### Blok 2: Installatie & Setup (20 minuten)
|
||||
|
||||
| Tijd | Activiteit | Slides |
|
||||
|------|------------|--------|
|
||||
| 09:10-09:13 | Download Cursor | 5 |
|
||||
| 09:13-09:18 | Account aanmaken (Hobby → Student later) | 6 |
|
||||
| 09:18-09:22 | Interface tour | 7 |
|
||||
| 09:22-09:30 | Terminal Setup Check SAMEN | 8 |
|
||||
|
||||
**Checkpoints:**
|
||||
- ✓ Cursor geïnstalleerd en geopend
|
||||
- ✓ node -v, git --version, npm -v werken
|
||||
|
||||
---
|
||||
|
||||
### Blok 3: Cursor Features (15 minuten)
|
||||
|
||||
| Tijd | Activiteit | Slides |
|
||||
|------|------------|--------|
|
||||
| 09:30-09:33 | Chat Panel (Ctrl+L) | 9 |
|
||||
| 09:33-09:36 | Inline Edit (Ctrl+K) | 10 |
|
||||
| 09:36-09:39 | Composer (Ctrl+I) | 11 |
|
||||
| 09:39-09:41 | Tab Completion (GRATIS!) | 12 |
|
||||
| 09:41-09:43 | @ Mentions + @docs | 13 |
|
||||
|
||||
**Kernboodschap:** "Vijf features, elk voor ander doel. Tab Completion is GRATIS - gebruik dat voor kleine dingen!"
|
||||
|
||||
---
|
||||
|
||||
### Blok 4: Skills, Rules & Requests (15 minuten)
|
||||
|
||||
| Tijd | Activiteit | Slides |
|
||||
|------|------------|--------|
|
||||
| 09:43-09:48 | Cursor Skills installeren (Next.js, React, Tailwind docs) - SAMEN DOEN | 14 |
|
||||
| 09:48-09:53 | .cursorrules genereren met Chat | 15 |
|
||||
| 09:53-09:58 | Request management tips (Hobby account) | 16 |
|
||||
|
||||
**Checkpoints:**
|
||||
- ✓ Docs toegevoegd in Cursor Settings
|
||||
- ✓ Studenten begrijpen request kosten
|
||||
|
||||
**Belangrijk:** Benadruk dat Tab Completion GRATIS is. Chat/Composer/Inline Edit kosten elk 1 request.
|
||||
|
||||
---
|
||||
|
||||
### Blok 5: Live Demo (15 minuten)
|
||||
|
||||
| Tijd | Activiteit | Slides |
|
||||
|------|------------|--------|
|
||||
| 09:58-10:13 | LIVE DEMO: Nieuw project workflow | 17 |
|
||||
|
||||
**Demo flow:**
|
||||
1. mkdir + git init (1 min)
|
||||
2. npx create-next-app@latest . (2 min)
|
||||
3. npm run dev → toon localhost:3000 (1 min)
|
||||
4. Chat: genereer .cursorrules (3 min, 1 request)
|
||||
5. Composer: maak HeroSection component (4 min, 1 request)
|
||||
6. Toon resultaat in browser (1 min)
|
||||
7. git add + commit (1 min)
|
||||
|
||||
**Doel:** Studenten zien de hele workflow in 15 minuten
|
||||
|
||||
---
|
||||
|
||||
### Blok 6: Hands-On Opdracht (75 min + 15 min pauze)
|
||||
|
||||
#### Deel 1 (10:13-10:15, intro + start)
|
||||
|
||||
| Tijd | Activiteit |
|
||||
|------|------------|
|
||||
| 10:13-10:15 | Opdracht uitleggen (Slide 18 op scherm) |
|
||||
|
||||
#### Hands-on Deel 1 (start - 10:15)
|
||||
|
||||
Studenten starten met STAP 1 (npx create-next-app)
|
||||
|
||||
---
|
||||
|
||||
#### ☕ PAUZE (10:15-10:30)
|
||||
|
||||
---
|
||||
|
||||
#### Hands-on Deel 2 (10:30-11:45)
|
||||
|
||||
**Check [10:45]:**
|
||||
"Wie heeft npx gedaan? Wie heeft .cursorrules? Wie heeft een component?"
|
||||
|
||||
**Check [11:00]:**
|
||||
"Wie heeft al 2 componenten? Hoeveel requests heb je nog over?"
|
||||
|
||||
**Check [11:30]:**
|
||||
"Wie heeft git gecommit? Wie wil zijn project laten zien?"
|
||||
|
||||
---
|
||||
|
||||
### Blok 7: Afsluiting (15 minuten)
|
||||
|
||||
| Tijd | Activiteit | Slides |
|
||||
|------|------------|--------|
|
||||
| 11:45-11:50 | Resultaten delen (3-4 studenten) | 19 |
|
||||
| 11:50-11:53 | Samenvatting | 20 |
|
||||
| 11:53-11:58 | Huiswerk uitleggen (DEBUG CHALLENGE!) | 21 |
|
||||
| 11:58-12:00 | Volgende les preview | 22 |
|
||||
|
||||
---
|
||||
|
||||
## Materialen
|
||||
|
||||
- **Slide-Overzicht:** Les03-Slide-Overzicht.md
|
||||
- **Lesopdracht:** Les03-Bijlage-A-Lesopdracht.md
|
||||
- **Huiswerkopdracht:** Les03-Bijlage-B-Huiswerkopdracht.md
|
||||
|
||||
### Huiswerk zipbestand voorbereiden
|
||||
|
||||
**les3-debug-challenge.zip moet bevatten:**
|
||||
- Een Next.js project (App Router, TypeScript, Tailwind)
|
||||
- package.json met 1-2 missende dependencies (bijv. lucide-react gebruikt maar niet in deps)
|
||||
- 1-2 syntax errors (missing closing tag, typo in import)
|
||||
- 3-4 componenten met inline styles (style={{...}}) die naar Tailwind moeten
|
||||
- Een component met een missing import
|
||||
|
||||
---
|
||||
|
||||
## Veelvoorkomende problemen
|
||||
|
||||
| Probleem | Oorzaak | Oplossing |
|
||||
|----------|---------|-----------|
|
||||
| npx create-next-app faalt | Node.js te oud | nvm install 20 && nvm use 20 |
|
||||
| npm run dev werkt niet | Verkeerde folder | cd naar project folder, npm install |
|
||||
| Chat/Composer reageert niet | Requests op of internet | Check cursor.com/account, check internet |
|
||||
| .cursorrules werkt niet | Niet in root of typo | Check bestandsnaam en locatie |
|
||||
| Cursor crash | Memory issue | Restart Cursor |
|
||||
| Terminal commands not found | PATH niet goed | Restart Cursor, check nvm |
|
||||
|
||||
## Request Budget Planning
|
||||
|
||||
| Activiteit | Requests |
|
||||
|------------|----------|
|
||||
| .cursorrules genereren (Chat) | 1 |
|
||||
| Hero component (Composer) | 1 |
|
||||
| Styling tweaken (Inline Edit) | 1 |
|
||||
| Extra component (Composer) | 1 |
|
||||
| Vragen/debugging (Chat) | 2-3 |
|
||||
| **Totaal in de les** | **~6-7** |
|
||||
|
||||
Tab Completion kost GEEN requests - benadruk dit!
|
||||
|
||||
---
|
||||
|
||||
## Voorbereiding Tim
|
||||
|
||||
**1-2 dagen voor les:**
|
||||
- [ ] npx create-next-app testen op eigen machine
|
||||
- [ ] Cursor Skills/Docs toevoegen
|
||||
- [ ] .cursorrules genereren als demo
|
||||
- [ ] Huiswerk zip maken met fouten
|
||||
- [ ] Upload zip naar Teams
|
||||
|
||||
**Dag voor les:**
|
||||
- [ ] Projector test
|
||||
- [ ] Internet snelheid checken
|
||||
- [ ] Cursor fresh install testen (wie upgrade snel?)
|
||||
|
||||
**Tijdens les:**
|
||||
- [ ] Iedereen npx create-next-app laten draaien
|
||||
- [ ] Terminal checks KRITISCH (slide 8)
|
||||
- [ ] Request management benadrukken
|
||||
- [ ] Active walking tijdens hands-on
|
||||
|
||||
---
|
||||
|
||||
**Succes met Les 3!**
|
||||
@@ -1,354 +1,309 @@
|
||||
# Les 3 — Lesstof
|
||||
## Cursor — AI-Powered Code Editor
|
||||
## Cursor Basics
|
||||
|
||||
**Vak:** AI Fundamentals
|
||||
**Vak:** AI-Assisted Development
|
||||
**Opleiding:** NOVI Hogeschool Utrecht
|
||||
**Vorige les:** Les 2 — OpenCode
|
||||
**Volgende les:** Les 4 — TypeScript Fundamentals
|
||||
|
||||
---
|
||||
|
||||
## Inhoud
|
||||
## Doel van deze les
|
||||
|
||||
1. [Wat is Cursor](#1-wat-is-cursor)
|
||||
2. [Setup + eerste keer opstarten](#2-setup--eerste-keer-opstarten)
|
||||
3. [De vier kern-features](#3-de-vier-kern-features)
|
||||
4. [Chat (Cmd+L)](#4-chat-cmdl)
|
||||
5. [Inline Edit (Cmd+K)](#5-inline-edit-cmdk)
|
||||
6. [Composer / Agent (Cmd+I)](#6-composer--agent-cmdi)
|
||||
7. [Tab — predictive completion](#7-tab--predictive-completion)
|
||||
8. [@-mentions — context erbij halen](#8--mentions--context-erbij-halen)
|
||||
9. [.cursorrules — project-context](#9-cursorrules--project-context)
|
||||
10. [Debug-flow met AI](#10-debug-flow-met-ai)
|
||||
11. [Wanneer Cursor vs Console](#11-wanneer-cursor-vs-console)
|
||||
Aan het einde van deze les heb je:
|
||||
|
||||
- Cursor geïnstalleerd en geactiveerd met je Student Plan
|
||||
- Skills/Docs geconfigureerd voor Next.js, React, Tailwind
|
||||
- Een werkend Next.js project opgezet via `npx create-next-app`
|
||||
- De drie hoofdsneltoetsen (Tab / Cmd+K / Cmd+L) actief gebruikt
|
||||
- Een `.cursorrules`-bestand in je project
|
||||
- Een Hero-component, een styling-tweak en één extra feature gebouwd
|
||||
- Je eerste commit naar Git gedaan
|
||||
|
||||
---
|
||||
|
||||
## 1. Wat is Cursor
|
||||
|
||||
**Cursor** is een AI-first code editor — een fork van VS Code met AI-features verweven in elk onderdeel. Geen plugin, geen sidebar — AI is overal: tab-completion, chat, inline edit, agent mode.
|
||||
Cursor is een **fork van Visual Studio Code** met AI als kernfeature ingebouwd. Dat betekent: alles wat je in VS Code kunt — file explorer, terminal, debugger, extensies — werkt hier ook. Het verschil: AI is geen plug-in maar een onderdeel van de editor zelf.
|
||||
|
||||
### Waarom Cursor?
|
||||
### Werkt met meerdere modellen
|
||||
|
||||
- Vertrouwde VS Code interface (alle extensies werken)
|
||||
- AI features die écht in je workflow zitten
|
||||
- Multi-file edits met diff-preview
|
||||
- Background Agents (later in de leerlijn — Les 15)
|
||||
- Werkt met OpenAI, Anthropic, of eigen API keys
|
||||
Cursor laat je per chat kiezen welk AI-model je gebruikt:
|
||||
- **Claude** (Opus, Sonnet, Haiku) — sterk in code-redenering
|
||||
- **GPT** (4, 4o, 5) — solide allround
|
||||
- **Gemini** (Pro, Flash) — snel en goedkoop
|
||||
- **Lokaal** (via Ollama) — privacy en kosten-vriendelijk
|
||||
|
||||
### Cost
|
||||
### Waarom relevant
|
||||
|
||||
- **Hobby (gratis)** — limited, Tab completion, basic chat
|
||||
- **Pro ($20/maand)** — alles, onbeperkt, Background Agents
|
||||
- **Business** — teams, SSO, audit
|
||||
|
||||
Voor deze leerlijn: Pro aanrader. Hobby werkt voor leren maar je raakt rate-limits.
|
||||
- Industry-standard in AI-assisted development
|
||||
- Veel vacatures noemen het expliciet
|
||||
- Gratis Pro Student voor NOVI-studenten
|
||||
|
||||
---
|
||||
|
||||
## 2. Setup + eerste keer opstarten
|
||||
## 2. Student Plan activeren
|
||||
|
||||
### Installatie
|
||||
### Wat krijg je
|
||||
|
||||
Download van cursor.com — installeer net als VS Code.
|
||||
| Tier | Fast requests/maand | Premium models | Tab-completion |
|
||||
|------|--------------------:|----------------|----------------|
|
||||
| Free | 50 | beperkt | onbeperkt |
|
||||
| Pro | 500 | volledig | onbeperkt |
|
||||
| **Pro Student** | **500** | **volledig** | **onbeperkt** |
|
||||
| Business | 1000+ | volledig | onbeperkt |
|
||||
|
||||
### Eerste opstarten
|
||||
Pro Student = gewone Pro, maar gratis voor verified studenten.
|
||||
|
||||
1. Sign in met email of GitHub
|
||||
2. Cursor vraagt: "Import VS Code settings?" — Ja
|
||||
3. Kies thema, snelkoppelingen
|
||||
4. Opt-in op AI training of opt-out (privacy keuze)
|
||||
### Hoe activeer je
|
||||
|
||||
### Model kiezen
|
||||
1. Ga naar `cursor.com/students`
|
||||
2. Log in met je **NOVI e-mailadres** (niet je persoonlijke Gmail)
|
||||
3. SheerID verifieert je via NOVI's inschrijfsysteem (1–10 min)
|
||||
4. Cursor upgrade je account automatisch naar **Pro Student**
|
||||
|
||||
Settings → Models. Defaults:
|
||||
- Cursor Auto (default — Cursor kiest beste model)
|
||||
- Claude Sonnet 4.6 (default voor code)
|
||||
- GPT-5 (alternatief)
|
||||
- o3 (reasoning — trager maar slimmer)
|
||||
### Verifiëren
|
||||
|
||||
Vuistregel: Sonnet voor 90%, o3 voor complex.
|
||||
Open Cursor → Settings (Cmd+,) → Tab **General** → check **Account**. Status moet **"Pro Student"** zijn.
|
||||
|
||||
### Een project openen
|
||||
|
||||
Twee opties:
|
||||
- File → Open Folder (zoals VS Code)
|
||||
- Terminal: `cursor .` in je project-folder
|
||||
Als het "Free" blijft: log opnieuw in via cursor.com/students en herstart Cursor.
|
||||
|
||||
---
|
||||
|
||||
## 3. De vier kern-features
|
||||
## 3. Installeren
|
||||
|
||||
Cursor heeft veel features. Vier die je dagelijks gebruikt:
|
||||
```bash
|
||||
# 1. Download van cursor.com (kies je OS)
|
||||
# 2. Installeer als gewone app (sleep naar Applications op Mac,
|
||||
# next-next-finish op Windows)
|
||||
# 3. Open Cursor → Sign in
|
||||
# 4. Optioneel: importeer VS Code instellingen (klik Ja bij de prompt)
|
||||
```
|
||||
|
||||
| Feature | Shortcut | Wanneer |
|
||||
|---------|----------|---------|
|
||||
| **Tab** | (auto) | Voltooi-suggesties tijdens typen |
|
||||
| **Inline Edit** | `Cmd+K` | Korte edit op selectie of cursor-positie |
|
||||
| **Chat** | `Cmd+L` | Vragen stellen, code uitleggen |
|
||||
| **Composer/Agent** | `Cmd+I` | Multi-file edits, refactors |
|
||||
|
||||
Deze leren = 80% van Cursor's waarde gebruiken.
|
||||
Eerste keer Cursor opent vraagt hij:
|
||||
- VS Code settings importeren? **Ja** (theme, keybindings, extensies blijven)
|
||||
- Welk model kiezen? Voor nu: laat default staan
|
||||
|
||||
---
|
||||
|
||||
## 4. Chat (Cmd+L)
|
||||
## 4. Skills / Docs configureren
|
||||
|
||||
**Wat:** sidebar-chat. Type vraag, krijg antwoord. Net als ChatGPT maar mét je code als context.
|
||||
Cursor kan officiële framework-documentatie indexeren. Vervolgens kun je in chat schrijven `@docs:Next.js` en de AI antwoordt met actuele info uit die docs.
|
||||
|
||||
### Wanneer
|
||||
### Setup
|
||||
|
||||
- Code uitleggen ("wat doet deze functie?")
|
||||
- Algemene vragen tijdens coden ("hoe gebruik je useMemo?")
|
||||
- Debug-hulp ("waarom werkt dit niet?")
|
||||
1. Settings → **Features** → **Docs**
|
||||
2. Klik **+ Add new doc**
|
||||
3. Voeg toe (één voor één):
|
||||
- `Next.js` (URL: `https://nextjs.org/docs`)
|
||||
- `React` (URL: `https://react.dev`)
|
||||
- `Tailwind CSS` (URL: `https://tailwindcss.com/docs`)
|
||||
4. Wacht tot indexering klaar is (1–2 min per doc)
|
||||
|
||||
### Context erbij
|
||||
### Gebruiken
|
||||
|
||||
- `@filename` — voeg specifieke file toe als context
|
||||
- `@Codebase` — hele repo (gebruikt embeddings)
|
||||
- `@Web` — search het web
|
||||
- `@Docs` — geïmporteerde documentatie
|
||||
- Sleep een file naar chat — toegevoegd als context
|
||||
In Cmd+L (chat):
|
||||
|
||||
### Agent-mode binnen Chat
|
||||
```
|
||||
@docs:Tailwind hoe centreer ik verticaal en horizontaal met flex?
|
||||
```
|
||||
|
||||
Switch knop bovenaan: Ask | Agent. Met Agent mode kan Chat ook files bewerken — vergelijkbaar met Composer.
|
||||
Cursor antwoordt met de juiste Tailwind-classes uit de officiële docs.
|
||||
|
||||
---
|
||||
|
||||
## 5. Inline Edit (Cmd+K)
|
||||
## 5. Eerste Next.js project
|
||||
|
||||
**Wat:** edit-popup op je cursor-positie. Beschrijf wat je wilt, AI past selectie of nieuwe code aan.
|
||||
### Scaffolden
|
||||
|
||||
### Voorbeelden
|
||||
```bash
|
||||
cd ~/web # of waar jij je projecten houdt
|
||||
npx create-next-app@latest mijn-eerste-cursor-app
|
||||
```
|
||||
|
||||
Selecteer een functie + `Cmd+K`:
|
||||
> "Voeg error handling toe"
|
||||
Prompts:
|
||||
|
||||
AI past selectie aan, diff zichtbaar, accept/reject.
|
||||
| Vraag | Aanbevolen | Waarom |
|
||||
|-------|-----------|--------|
|
||||
| TypeScript? | **Ja** | strict typing voorkomt bugs |
|
||||
| ESLint? | **Ja** | code-style consistency |
|
||||
| Tailwind CSS? | **Ja** | utility-first styling |
|
||||
| `src/` directory? | **Ja** | houdt project-root schoon |
|
||||
| App Router? | **Ja** | moderne Next.js flow |
|
||||
| Turbopack? | **Ja** | snellere dev-builds |
|
||||
| Import alias `@/*`? | **Ja** | `@/components/x` ipv `../../components/x` |
|
||||
|
||||
Lege regel + `Cmd+K`:
|
||||
> "Genereer een TypeScript interface voor een User met name, email, role"
|
||||
### Starten
|
||||
|
||||
AI inserts code.
|
||||
```bash
|
||||
cd mijn-eerste-cursor-app
|
||||
npm run dev # → http://localhost:3000
|
||||
```
|
||||
|
||||
### Wanneer
|
||||
### Openen in Cursor
|
||||
|
||||
- Snelle wijziging op één plek
|
||||
- Code generaten tussen bestaande regels
|
||||
- Selectie aanpassen
|
||||
```bash
|
||||
cursor . # opent huidige folder in Cursor
|
||||
```
|
||||
|
||||
Voor multi-file edits → Composer.
|
||||
Of: File → Open Folder → kies de map.
|
||||
|
||||
---
|
||||
|
||||
## 6. Composer / Agent (Cmd+I)
|
||||
## 6. De drie hoofdsneltoetsen
|
||||
|
||||
**Wat:** de zwaarste AI-feature. Multi-file edits met preview van alle diffs.
|
||||
| Sneltoets | Functie | Kost |
|
||||
|-----------|---------|------|
|
||||
| **Tab** | Accept AI auto-completion | **Gratis** |
|
||||
| **Cmd+K** | Inline edit op selectie | 1 request |
|
||||
| **Cmd+L** | Chat-paneel openen | 1 request |
|
||||
|
||||
### Tab — autocomplete
|
||||
|
||||
Cursor analyseert je hele bestand én recente edits. Hij suggereert hele blokken code, niet alleen één woord.
|
||||
|
||||
**Voorbeeld:** typ een commentaar `// render team list` op een lege regel. Cursor genereert de hele component eronder. Druk **Tab** om te accepteren, **Esc** om te negeren.
|
||||
|
||||
**Wanneer:** boilerplate, herhalende patronen, voorspelbare code (CRUD, list renders).
|
||||
|
||||
### Cmd+K — inline edit
|
||||
|
||||
Voor gerichte één-bestand-wijzigingen.
|
||||
|
||||
**Stappen:**
|
||||
1. Selecteer code (of zet cursor op een regel)
|
||||
2. Druk **Cmd+K**
|
||||
3. Input-balkje opent boven je code
|
||||
4. Typ je instructie: *"converteer naar TypeScript"*
|
||||
5. Cursor toont een **diff direct in de editor**
|
||||
6. **Tab** = Accept, **Esc** = Reject
|
||||
|
||||
**Wanneer:** variabele hernoemen, één functie refactoren, types toevoegen, commentaar uitleggen.
|
||||
|
||||
### Cmd+L — Chat
|
||||
|
||||
Voor vragen en grotere taken.
|
||||
|
||||
**Stappen:**
|
||||
1. Druk **Cmd+L** — chat-paneel opent rechts
|
||||
2. Optioneel: gebruik `@`-mentions voor context (zie volgende sectie)
|
||||
3. Typ je vraag of taak
|
||||
4. Cursor antwoordt + kan diffs voorstellen
|
||||
5. Apply / Reject per file
|
||||
|
||||
**Wanneer:** uitleg vragen, grote multi-file taken, code-review.
|
||||
|
||||
---
|
||||
|
||||
## 7. Context via `@`-mentions
|
||||
|
||||
In Cmd+L (chat) type je `@` voor een autocomplete-menu:
|
||||
|
||||
| Tag | Wat het doet |
|
||||
|-----|--------------|
|
||||
| `@file:foo.tsx` | inclusief één specifiek bestand |
|
||||
| `@folder:components` | hele map |
|
||||
| `@code:functionName` | losse functie of class |
|
||||
| `@docs:Next.js` | officiële Next.js docs (eerst configureren) |
|
||||
| `@web` | live web-search |
|
||||
| `@git` | git history / blame |
|
||||
|
||||
**Voorbeeld:**
|
||||
|
||||
```
|
||||
@file:page.tsx Refactor deze component zodat hij @docs:React useReducer gebruikt in plaats van useState.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Request management
|
||||
|
||||
500 requests per maand klinkt veel, maar zonder discipline ben je er in een week doorheen.
|
||||
|
||||
### Tips
|
||||
|
||||
- **Combineer in 1 Cmd+L:** *"maak een Hero met titel, ondertitel, twee CTA-knoppen, gradient achtergrond en responsive"* = één request voor een hele feature.
|
||||
- **Tab is gratis** — gebruik het voor alles wat eenvoudig is.
|
||||
- **Cmd+K voor gerichte edits** — niet voor "maak iets nieuws".
|
||||
- **Cmd+L met `@file`** — bespaar Cursor het zoeken naar context.
|
||||
|
||||
### Anti-patterns
|
||||
|
||||
- Tien losse Cmd+K's voor één feature
|
||||
- Cmd+L met te weinig context (*"maak iets cools"*)
|
||||
- Vergeten dat Tab bestaat
|
||||
|
||||
---
|
||||
|
||||
## 9. `.cursorrules`
|
||||
|
||||
Een bestand in de root van je project dat Cursor bij elke prompt meeleest.
|
||||
|
||||
### Voorbeeld
|
||||
|
||||
`Cmd+I` opent Composer panel:
|
||||
```text
|
||||
# .cursorrules
|
||||
|
||||
> "Voeg een /about pagina toe met team-leden in een grid. Match styling van homepage. Gebruik Tailwind. Maak een aparte component voor team-member."
|
||||
|
||||
Composer:
|
||||
1. Leest `app/page.tsx` voor stijl
|
||||
2. Maakt `app/about/page.tsx`
|
||||
3. Maakt `components/TeamMember.tsx`
|
||||
4. Toont alle diffs
|
||||
|
||||
Jij accepteert per file of "Accept All".
|
||||
|
||||
### Wanneer
|
||||
|
||||
- Nieuwe features (multi-file)
|
||||
- Refactors
|
||||
- Bugfixes die meerdere files raken
|
||||
|
||||
### Terminal commands
|
||||
|
||||
Composer kan ook terminal-commands runnen — vraagt approval. "Run pnpm install" → Composer doet het.
|
||||
|
||||
---
|
||||
|
||||
## 7. Tab — predictive completion
|
||||
|
||||
Cursor's Tab-completion ziet **wat je gaat typen voordat je 't typt**. Vergelijkbaar met GitHub Copilot maar slimmer (gebruikt je hele file + recent edits).
|
||||
|
||||
### Hoe gebruiken
|
||||
|
||||
- Type — suggesties verschijnen grijs
|
||||
- `Tab` — accepteer
|
||||
- `Esc` — afwijzen
|
||||
|
||||
### Cursor Tab vs Copilot
|
||||
|
||||
Cursor Tab kan:
|
||||
- Multi-line suggesties (hele functie ineens)
|
||||
- Cursor verplaatsen naar volgende edit-locatie (handig bij refactors)
|
||||
- Suggesties op basis van wat je net hebt geschreven elders
|
||||
|
||||
Verschil voelbaar na een dag gebruik.
|
||||
|
||||
### Wanneer uitzetten
|
||||
|
||||
Soms ga je sneller zonder. Cmd+Shift+P → "Cursor Tab" → toggle.
|
||||
|
||||
---
|
||||
|
||||
## 8. @-mentions — context erbij halen
|
||||
|
||||
`@` in chat of Composer = context kiezen.
|
||||
|
||||
### Soorten
|
||||
|
||||
| Mention | Wat | Voorbeeld |
|
||||
|---------|-----|-----------|
|
||||
| `@File` | Specifieke file | `@app/page.tsx` |
|
||||
| `@Folder` | Hele folder | `@components/` |
|
||||
| `@Codebase` | Repo via embeddings | `@Codebase` |
|
||||
| `@Docs` | Geïmporteerde docs | `@Next.js` |
|
||||
| `@Web` | Web search | `@Web "Next.js 16 caching"` |
|
||||
| `@Git` | Recent commits | `@Git` |
|
||||
| `@Definitions` | Symbols | `@Definitions:UserController` |
|
||||
|
||||
### Goede prompts
|
||||
|
||||
Zonder mentions: AI gokt welke files relevant zijn (langzamer, soms fout).
|
||||
Met mentions: AI heeft exact wat 't nodig heeft.
|
||||
|
||||
```
|
||||
@app/api/auth/route.ts @lib/supabase.ts
|
||||
|
||||
Voeg een endpoint toe /api/user dat de logged-in user returnt.
|
||||
Gebruik supabase auth.getUser().
|
||||
- Gebruik TypeScript strict mode
|
||||
- Tailwind voor styling, geen CSS modules
|
||||
- Server components by default; "use client" alleen waar nodig
|
||||
- Imports met @/ alias voor src/
|
||||
- Functional components, geen classes
|
||||
- Geen any-types; expliciete return types op exports
|
||||
```
|
||||
|
||||
---
|
||||
### Genereren
|
||||
|
||||
## 9. .cursorrules — project-context
|
||||
Vraag Cursor het zelf in Cmd+L:
|
||||
|
||||
**`.cursorrules`** = markdown-file in project-root die Cursor leest bij elke prompt. Net als AGENTS.md in Les 2.
|
||||
|
||||
### Voorbeeld
|
||||
|
||||
```markdown
|
||||
# Cursor Rules — QuickPoll
|
||||
|
||||
## Stack
|
||||
- Next.js 16 App Router
|
||||
- TypeScript strict mode
|
||||
- Tailwind v4
|
||||
- Supabase (DB + Auth)
|
||||
|
||||
## Conventies
|
||||
- Server Components default, "use client" alleen waar nodig
|
||||
- Tailwind classes inline, geen CSS-files
|
||||
- Geen comments tenzij gevraagd
|
||||
- Volg bestaande naming (camelCase functions, PascalCase components)
|
||||
- Throw geen errors uit RSCs — return { error } object
|
||||
|
||||
## Verboden
|
||||
- Gebruik geen Next.js Pages Router (alleen App Router)
|
||||
- Geen any-types in TypeScript
|
||||
- Geen inline styles
|
||||
```
|
||||
Maak een .cursorrules voor dit Next.js project. Focus op TypeScript strict, Tailwind, en App Router conventies.
|
||||
```
|
||||
|
||||
Cursor stelt een goede basis voor. Pas aan naar smaak en commit het in je repo.
|
||||
|
||||
### Effect
|
||||
|
||||
AI checkt deze rules bij elke prompt. "Maak een Server Component" wordt automatisch "use client"-vrij. "Voeg comment toe" wordt overgeslagen.
|
||||
Je hoeft niet elke keer "vergeet niet TypeScript te gebruiken" in je chat te typen. Cursor weet het al.
|
||||
|
||||
### Beperkingen
|
||||
|
||||
- Cursor's parsing is niet 100% strikt — soms vergeet AI rules
|
||||
- Hou 'm tussen 30-200 regels (te lang = vergeten)
|
||||
- Test of rules echt werken — soms moet je expliciet refereren
|
||||
> **Vooruitblik (Les 14):** in nieuwere Cursor-versies is er ook een `.cursor/rules/`-map met meerdere `.mdc`-bestanden + YAML front-matter (`alwaysApply`, `globs`). Voor nu is `.cursorrules` in de root prima en simpeler.
|
||||
|
||||
---
|
||||
|
||||
## 10. Debug-flow met AI
|
||||
## 10. Hands-on — wat je gaat bouwen
|
||||
|
||||
### Pattern 1 — Console error
|
||||
Drie kleine taken in je net gescaffolde project:
|
||||
|
||||
Console error → kopieer → in chat plakken:
|
||||
| Taak | Wat | Sneltoets |
|
||||
|------|-----|-----------|
|
||||
| **1** | Hero-component (titel, subtitel, 2 CTA-knoppen, gradient, responsive) | Cmd+L |
|
||||
| **2** | Styling-tweak: kleuren/spacing van de knoppen | Cmd+K |
|
||||
| **3** | Extra feature naar keuze: FeatureCards / ContactForm / Footer | Cmd+L of Cmd+K |
|
||||
|
||||
```
|
||||
TypeError: Cannot read property 'name' of undefined
|
||||
at UserCard (components/UserCard.tsx:12)
|
||||
```
|
||||
Daarna `git add . && git commit -m "first cursor build"`.
|
||||
|
||||
AI: leest UserCard.tsx, vindt waar `name` undefined kan zijn, suggereert fix.
|
||||
|
||||
### Pattern 2 — Onverwachte output
|
||||
|
||||
```
|
||||
Mijn fetchData() returnt undefined ipv users. Hier is de code:
|
||||
|
||||
@lib/api.ts
|
||||
|
||||
Wat gaat er mis?
|
||||
```
|
||||
|
||||
AI: leest code, identificeert (vaak) async/await issue of missende return.
|
||||
|
||||
### Pattern 3 — Tests falen
|
||||
|
||||
Run test → copy output → chat:
|
||||
|
||||
```
|
||||
Test "should return user list" faalt:
|
||||
Expected: Array(3)
|
||||
Received: undefined
|
||||
|
||||
@__tests__/api.test.ts
|
||||
@lib/api.ts
|
||||
```
|
||||
|
||||
AI: traceert, fixt.
|
||||
|
||||
### Pattern 4 — Refactor
|
||||
|
||||
```
|
||||
Refactor @app/api/users/route.ts naar gebruik van Supabase
|
||||
in plaats van mock-data.
|
||||
|
||||
Gebruik @lib/supabase.ts voor de client.
|
||||
```
|
||||
|
||||
Composer doet multi-file edit.
|
||||
Exacte stappen + voorbeeldprompts: zie `Les03-Lesopdracht.pdf`.
|
||||
|
||||
---
|
||||
|
||||
## 11. Wanneer Cursor vs Console
|
||||
## 11. Verder lezen
|
||||
|
||||
Cursor is geweldig maar niet altijd het antwoord.
|
||||
|
||||
### Cursor wel
|
||||
|
||||
- Code schrijven, refactoren, debuggen
|
||||
- Nieuwe features
|
||||
- Boilerplate
|
||||
- Documentatie
|
||||
|
||||
### Cursor niet
|
||||
|
||||
- Git workflow (gebruik gewoon `git`)
|
||||
- File-management buiten project (Finder/Explorer)
|
||||
- Terminal-heavy taken (gewone shell)
|
||||
- Browser debuggen (DevTools)
|
||||
- Een quick lookup (ChatGPT/browser)
|
||||
|
||||
### Hybride
|
||||
|
||||
Veel pro devs: **Cursor voor IDE-werk, Claude.ai voor brainstormen, Terminal voor git**. Gebruik niet één tool voor alles.
|
||||
- **Cursor docs** — `cursor.com/docs` — features, sneltoetsen, rules-syntax
|
||||
- **Cursor changelog** — `cursor.com/changelog` — wat is nieuw
|
||||
- **Next.js docs** — `nextjs.org/docs`
|
||||
- **Tailwind docs** — `tailwindcss.com/docs`
|
||||
|
||||
---
|
||||
|
||||
## Bronnen
|
||||
## Samenvatting
|
||||
|
||||
- **Cursor docs:** https://docs.cursor.com
|
||||
- **Cursor Tab features:** https://docs.cursor.com/tab
|
||||
- **Cursor Composer:** https://docs.cursor.com/composer
|
||||
- **.cursorrules examples:** https://github.com/PatrickJS/awesome-cursorrules
|
||||
- **Cursor changelog:** https://www.cursor.com/changelog
|
||||
- **Cursor forum (community):** https://forum.cursor.com
|
||||
Vandaag heb je geleerd:
|
||||
|
||||
- Cursor is een VS Code-fork met AI ingebouwd
|
||||
- Student Plan = 500 requests/maand gratis (via cursor.com/students)
|
||||
- Drie sneltoetsen: Tab (gratis), Cmd+K (inline edit), Cmd+L (chat)
|
||||
- Context via `@`-mentions: file, folder, code, docs, web, git
|
||||
- `.cursorrules` per project voor consistente AI-output
|
||||
- Eerste hands-on met Hero / tweak / extra feature
|
||||
|
||||
Volgende les: TypeScript Fundamentals. Veel later (Les 14): Cursor 3 deep dive met Editor / Agents Window en deployment.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
%<25><><EFBFBD><EFBFBD> ReportLab Generated PDF document (opensource)
|
||||
1 0 obj
|
||||
<<
|
||||
/F1 2 0 R /F2 3 0 R /F3 5 0 R /F4 6 0 R
|
||||
/F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 6 0 R
|
||||
>>
|
||||
endobj
|
||||
2 0 obj
|
||||
@@ -17,7 +17,12 @@ endobj
|
||||
endobj
|
||||
4 0 obj
|
||||
<<
|
||||
/Contents 17 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 16 0 R /Resources <<
|
||||
/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
5 0 obj
|
||||
<<
|
||||
/Contents 16 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
@@ -25,19 +30,14 @@ endobj
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
5 0 obj
|
||||
<<
|
||||
/BaseFont /Symbol /Name /F3 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F4 /Subtype /Type1 /Type /Font
|
||||
/BaseFont /Symbol /Name /F4 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<<
|
||||
/Contents 18 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 16 0 R /Resources <<
|
||||
/Contents 17 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
@@ -47,7 +47,7 @@ endobj
|
||||
endobj
|
||||
8 0 obj
|
||||
<<
|
||||
/Contents 19 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 16 0 R /Resources <<
|
||||
/Contents 18 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
@@ -57,7 +57,7 @@ endobj
|
||||
endobj
|
||||
9 0 obj
|
||||
<<
|
||||
/Contents 20 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 16 0 R /Resources <<
|
||||
/Contents 19 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
@@ -67,7 +67,7 @@ endobj
|
||||
endobj
|
||||
10 0 obj
|
||||
<<
|
||||
/Contents 21 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 16 0 R /Resources <<
|
||||
/Contents 20 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
@@ -77,7 +77,7 @@ endobj
|
||||
endobj
|
||||
11 0 obj
|
||||
<<
|
||||
/Contents 22 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 16 0 R /Resources <<
|
||||
/Contents 21 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
@@ -87,7 +87,7 @@ endobj
|
||||
endobj
|
||||
12 0 obj
|
||||
<<
|
||||
/Contents 23 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 16 0 R /Resources <<
|
||||
/Contents 22 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
@@ -97,95 +97,78 @@ endobj
|
||||
endobj
|
||||
13 0 obj
|
||||
<<
|
||||
/Contents 24 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 16 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
/PageMode /UseNone /Pages 15 0 R /Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
14 0 obj
|
||||
<<
|
||||
/PageMode /UseNone /Pages 16 0 R /Type /Catalog
|
||||
/Author (NOVI Hogeschool Utrecht) /CreationDate (D:20260615075148+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260615075148+00'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Subject (\(unspecified\)) /Title (Les 3 Lesstof) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
15 0 obj
|
||||
<<
|
||||
/Author (NOVI Hogeschool Utrecht) /CreationDate (D:20260607080655+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260607080655+00'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Subject (\(unspecified\)) /Title (Lesstof) /Trapped /False
|
||||
/Count 7 /Kids [ 5 0 R 7 0 R 8 0 R 9 0 R 10 0 R 11 0 R 12 0 R ] /Type /Pages
|
||||
>>
|
||||
endobj
|
||||
16 0 obj
|
||||
<<
|
||||
/Count 8 /Kids [ 4 0 R 7 0 R 8 0 R 9 0 R 10 0 R 11 0 R 12 0 R 13 0 R ] /Type /Pages
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1689
|
||||
>>
|
||||
stream
|
||||
Gb!;d>?fiA&:N_Cb[\5R\<6/<%W<&-@EVa+-(DX<,4(.2/6cH6%]-ph7nRT\OotjbBU<ZE[PBXO1iqe]%/TU*p32`%]G\WQG79iHj!c\>nR6eLDoW+_*jFbK^ib6k4(9mc"",)\IJOr>G20kRq?(]LYj[QVE(6Gp!hC<m:"Hl^@%<>e(Kb?U\CNt/$qp*JdWL=1Dp(aI?buLU`d\i_?g+o>5O1D&*t4,.N=1?3h_'.kJB,&MQ%h61'N+[FCk3D*\6cL[b\!)CA(J6U)`Nehr720r-9OGu53u>&q].XWm2_Ig-nC88"Qq15O^VS4Ea`IVF'_BOZ,i.+-9dtr:>pgtY`*0d8bf43(sVK<QmaO!"Gu5g)eQ#'`D2s?Qli@GRrk`7O9t(>%NGDa`q[!XMb&c#Jp2>YEs%9Ba(3gC32,eYhu,i#C)9!VpJ2JqR.D;,r,+5P*8_kUY.8J[GMSn+nCQ`5;&5]IE](`A:m`6*3i:)%E/fWW!uM0a!.8]BJA/_1n@mo-^";*a0\5,7B7?>V<=G4138>FKa.*0?+^9)t=,*%>R,Ff")!3-pN'u/M?r#<u</J0a2kqX),@"2jCjP3LjS@Ao66M4?#5lcu?FVXd+_CKG6q&C&NDr(V8ZaSq\Y=b)_Jb]\?$>1FPD(WJ\WAaL76=<VpLNdVTPf/52qSZcgI-j9Bj5LPVaMsC67B4P`i&r=,h*bJbQVp@b\NRm0>9`JO]U2Yl!lk_'KZp^#[T+qGJ<e)rY're$O!3mBjBdK.tptpft$I.q%^Psj"13$j7;ZljXW$eJ5[q_.p\(?g4A)g?OhMElNq.lita_=AHH-rXLp<%H<3Y]5W'd,_ZJ#=foZC2"e!\b)Y'48HpFf[Oie#r'<?6Vkuq6G8fIQ>l3;NKBTS%4R@bItnhl1O[/i"9.0W`/llq*!AAP1+i*T$:2(9]A,\3X$S9#/.ktQaaha$^=[S:Jn*BB]-#$Y)\2tGZ+cW(S$JZl]f;8Qdg4Y.d>J(=Fb$dX7*?'[:0r8CrAZk@5UFD@Yk7$KQqG")fBXe8l5ChAVISH9*R85\PE.8dc1MTLD_!d984&k,lW@&@oM2r"i!#%`RYE,oCS6X%qm[eanl,]2\Q67Ru+$Phr#jBQk"n6FL8@]iT(@U9BsBKoqf5Qrrp)O*i7C'N[HWeP16jIqE.R)t/$&Te@_-TuLAR3FAR:aE&_N3/lXN($0lqMoU]4CV7A@'q94U',rC]=gjb>KNQjM6@\R8T/3Q3)WX18e@h;]2!&BECXeq4@qe0DDqk/8nTuUpSjg"C8S+,bp/"'`[kdMa<QqIb=4"%m@cXl`;naYJi5f]*D9^WBTPl5m&EX"?)TkU@cS&)Uc"-=>HpRqe7qs6&LFc]OeaC?lCIt"0]&1RpRfJFdbo>c='ZZMfTd0#@71B)eN7@+YF*$#6:N.HYlXN19pjg0?Hua0Us88DLr),OC7":7q/O"olnaoI/iUR(P5AKVT(*#.TuENl[g%,XW:'96SE)0iXVBCOj2WnoZ(FOk7/JG9N=q*9\#[90^6ls47UNp)C%l0:dlaeV9&K?D0':k[A"n8*S1MX'-VM3WYO76hZC(*C<@T<U$452@:kdDRL]m,Kpq'2WpR5//FGP1q_i;Y,s7t`?2V29gTHUafSEi50kAM0R@:8R(PiFUP=Z_as`HdHW(G?d+#?n*4:&~>endstream
|
||||
endobj
|
||||
17 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1919
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2024
|
||||
>>
|
||||
stream
|
||||
GauHL?$E&%&:N_CbW1*nDBfo'OMnl?g[%FO]'\oDDYBdg"2V91N55nShY,QFKJ6dqFpRClcERo.0JdopB/C5)#=#TlNog=+NSqc[$C&A?!n=P>(qk\`,O:8!1X:[:KC):O%2d`KX8a<7=t07%joGi<84V<1Gi2/.9,U9.pmr$r5d"McgnJ0amKi'./ZI&Bhg=7g3FcaVZ[L,Oh=k^bUinDqH0lW`C&UsI9$eJUUXf$RL\elCd2^G\qf$ri5A*np7!De"^`R-jU:V%U(_cE(&mhW(9!X/nT>B_47aJJnN`(p2KYYR8deBaib%tOOHjlom)?T:Spk077B],t8Mn@ISJa[(/O+u9GptjfsKPt>b5_9MtboEm!3jIhqAaM:/aD)bEF`#1nWID;sj0gIO!0&m/"!c>5CITMK1S%XUZ"Cpg[5k@oaE#Xe"M\aJqF?Sjj/b<M(Y,B\1)I2O,_fN#6t.uJLRkuSdM9'GSI+&5N\=W'/?#B`A'KhLhE3XIRh;RKk-W.B)7rr3gHMHs[_P"pq)#n2fHc^\(uE#PM`/(?%3u^iF/)*.b\&D1k(5i7*Cg5Ol@Nf->I/RDpf0JM<BY;^C(9N[;/ID??7b[lb;VFM5%\SqX"dji@g-ejELGpL-3rfN\s-TCF9S,/p:8WXI'K2VH4pPUb,IL8:&WeYmslq5.gX/mDc[AnQ%kra=Y$J/i7W64Hb&6[f;em3Up9[E9t,7Tfm12'a5L:"AXF/:boe1"6-efh=;HtphcKcjrstC>4m.S(5"hb&7H,Sm%t[(IF:rhQY+r`Jl70s:7Cd'sduM\-XM0bmPf,E8+_rUd\W+E(*r,Uo**cPO04BlF9OMl]CCOMh:l(BFU[ZG/#S!ppQCW8BW8,DO%!FT9[D564/jg[U4,_I6=,2j)n9nE;ZqBrgpNMsD=2WkroLk'"-C!0b2q3J\i!J6G*:7FJilN-?<c&'tN4DXNZK:kS;b`ZhT'Y+r?)DT4ESRJfq/H%(qk0"A;g0o9;btQ)5<joL`!)NCs4>NKGEf2HP/IN\WhGnp#E<5++\r0$o`3W!oe_2#Wa%17HVc1F8d.$KKksVN@:#s5"(n@U,(pd>U*W>TE?%2-$%B>oIQe>CCB^aU1!`gjP)0OhAZcB"gEg>uoG#uI3Y'e($"0qI?uI1GM`[a,c.U'`r;HM^B,[a>+rhiTI%20Ha%h63mt6W07!G%GEG@P=)WWOUUefubMC>"C=D,[ZSu+F95$3TkVMf9)a9q"r$[@@EcN`m8!R+,7cP$rVBam*e$MlU@9(]n]Zs&I+>I0#9Yh>&310uEV0G@I+=]MU-.Do@Vg3M,l*sI._=s\NG+'P[n,e?i<*/058Pbk5Q>(Xn8j*S9D'2u+]C#fQ!AOn+7.[d&/3)'D]H:21TrNa\fRkM%ig2J4I=&HNEWacU%Ng+.nQGh/VS>OA)Vb^ALGgEs,:<=d'ehC/Op9dn1io#R!)+Omq,Wq[cVnq&aq\n7:V5\?&lD+%[gG%]1QDb.nDT&RNHE##dd-Iaq++Se/@)L>a-@C9HV.Pb>#^gD\9l8Nt-m.pQ.@2(@>:-`>7ufkU/)?s+g/fcSf+sPeHTE]'G\Bt)V1m#>4ZgdV)6C[hY-6'OL7qf"#f0-pCHN6-&>u1a).\!aai@""%3s0TBgmqj3K;L/R-KGN7ZrMN]npnY6UbGS&p2rIC\9^OVW8`@Y$H<s%b3`IF7eTKle9^.<YcL3RYBJo4\Tq#ihELimW06-ft:Y!+!*W[ai^t44S_\#?E\`L<o-Xr%Q`k&qSmC1<R/"pb<0"3OV/UJ`)p(38Jimm6,Fn`jnajIK-EdNXAqH2AC"tnAH$r"_lnP.hN)0"l2"@dW?_*)'s',iWbVH->U&TG;#a%]K7Ns49Ze3q6=NiqW3Ujl:F<ZJ_UHm.5\1,b?c\/TM#~>endstream
|
||||
Gatm<=]='G&:XAWk[GX",VWn$2cX(ojFAPA9f@of]_H'"a7e.H*$$BJYMUC8FPm8SJ.39[HFglZl1qn0$3n4Yq&)R#Dhi:T8V&W6:4QNdK&J*P0H>H^:bCociqU`qi0oUL[UJ,UHq^K<?EelQVZYF?)`+EH65'cmQR4h+i:n8;@?J_.'^"Bi%-K<lXfQujGAGlTZt79s\sAc%>g!=\HA:Z?+F[f\<pLS@odK>mhh+j>5q6:5)O7>3QLUM_,/gr2cTtX`Y'Q5RHM(Iu'D/$S@sZ<=_XJFSpmBp1:5g3@<^un0-q2jHAk.S2LKH/YY=1*iQD:;FKuiiO/E/c5DdUU;L\R1s2_4o&73mcsU1>glD#5F*EJ[+iZUMn&:4jfqL*DsUgf\0P.r%!lpq+63BSAP`U;ohWBcB2fBt6=1'^6h1ECC6_nY>(RfWG]_dXtF*g.!/X/\"Ei:lOMC#H*mU`JGs3j+No7(lNWoA:mr:kf9_-pVa,/Hh$s/f\7U6Z,h+L?%]NtVM8NlklL)lK%8`b<O(+Fr1,&eH6+l)Ss\hH-3`Dg@:q4jG;UL$gt2H;[>,g<KlBtRhq)_`lPL>$;QAr!X+9T*NI^"YW.&nd0s/!^jSE`q^`P6FpIQn9Dk6s76422+k;%ZiP,,;pWLQL6L9-OS1"f.T/NDMQJpUPOpcB)'K3YR48GB,(QK*1JYER3LVmbnS5^MiK2EUDO@nV$da"iH:D:`YVD5sY$Zp6\l$cc<g@^SFsJ[8!Jb8^aURO'CKZ9?[KPjQD>e`oTYA:(h#4jD5IaV87oOiVOWCM.GSa.L-%?@t4s\.&0m'q'MWCH@3tE@e/eG[Rj'M*j:1#e3b_7^!j>%"",PR!St5[<0d#]p[gs\:.eW8Wf<FXs=5ePi"9U=r,>d`L:=%ZWr:l@mNVD3N+6enY=CEM!rn9^-=1shN]N"`=f^q/<nmO#a,8bM\gXO.D?.$%o,WY0\`X6Kl/:<=r)N@#.lIrCLl.2.cPpJZrkrPJT:Ol'J\fZks/>]pLqK]BC3q,-ZC=$>fP5$e)jpmIWI8jFgqqJqDNNT9#Mq8iPnGP=EuS6_.#e17?n2Fl3Zl>c\i4D<htB@77WoU38-Xk9@!:2F-c?T,('u70LKA@Wk1EG4/AiIIL[O,?a<',/++,[WmeY8hZ:33L@gdQ,_9^FpV:S@#'!lfC3F_7VJS0lqicT[UqN](@l4k8Fc6=*bM"K8RI(Tn;[/F^KDH'9;U)U9TZ3l1c;'&GGi+9i@(C1*;)S*bJ`Rba@=,%h],Y9^L>0E%eM=t6\``h-@EbrK<OEfQ9p9!_e&nrqWe;8nboKd6IL-7D\=V;tCp_?DelI='MV%]4Zrm"teslBZ?n`O9%$%3VW!q[&c;[!t)7IaK1(`1qc"b&i%;ioXj?=%e5)'f54"5qqY`L&-Pl'S)5mc5=eZt$A\t2sFg'kdRNFT]g<g,2'W&DQJbDNVZQHN)/>RcQ.Aj?42K9O>-R3loJ`bJHIMT(YS[/?<4=Cs@ckF7FNaaM_F)]@7;R.jc%B'r\@I1Xs^:T[&*R8cpk4M?e[Xfn!e9,U_1&0a4A)(h%/=(/_SJTj(sX4j/'0LU@ZA@O"\>eii>GB+2gFID-aSZc&gD2/PcE.,e;AulN#E!.^+/013jWFgrdb5!lLR@KoDpZKca69(W&B?!U:-mS#g4$f="fG#4:Z#sIMXZ%c2/#hAq,euW'9$g)BV0C0s+qc7?j.CO_]1U*M?quV>;hn0aM3W=uP<4l=T,"1MV9q46/ujCI!A_hO'q/>aC;pEX5L+>ok6WfY*(NcL2[d[OSrNT*0]1bnh'hDn/b%Q\L<&t!+[b=t1M"cRK-6!uEa#:9'g'Qs%[74lW4-\(]Ki2d-5.8]c"/;2P4Akr2I2i5PG!a$BHj9&l55F$$5Wa079<':'U$;,L_Zn!NtKSikgeauC;G)ubeHt[G5`BNON]Wg0'"6Nq29%HEINrf3R5h$%>XXDKZ_(UJO8A)+r$keO%)S,jGUD&f[Ub\23T`h+$W55)u~>endstream
|
||||
endobj
|
||||
18 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1629
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1752
|
||||
>>
|
||||
stream
|
||||
Gb!;dgJSt\&:N^l\m.fAG/U[BHPJ1_Y`0fG!\Pq_KpRqO&qa4@l^:l]rqc9Tl3?fg8QPWg.X7?:Sj(u.:Nq_J:VX"-gReJ9FQ)_R!TVNI!Xl[Q]'nTpGOOR`a((]o&U6V,#AjrW4",ToN:mrRYnslpRmH<e?CHNYVT_]^Fpabr9+mP@5o@>iA)JZ<T;3WT.?!1B??nd)@a=6'd#6nnrUg&fIqe.RgP_udOdl$!N6r;T$>OH9#X+eK8HdiUm/MKRFUi&1KXQB*FU%k*KDc_of:44-Hk()a%PsZNGmW;2ke8N"=>Cf7.7&cRa%"s][8%6J,F;jbPlSO/hucDe`N=dpS47ruOf)^(3j'&o3Uj'hn9G4Mmo*']qNY]6ZK/8$@Hlh2.A,:pZFYP1P2qa`b>&8cM\o+?dTo\!)N;#C`_T!P4>OKE"#q?qEYbhP1Z?]2<%pSY&5=Ki<?3e$+0au*AYV>?q&;ZW$LtlE`XX?Zi$([6I,9Hbj_g%&A\SC:%?qP335.M10g=5)00VMg-K\6m:m!<6`+([]VuN7VLR!p7jl:,n>pK>/04Q&Aa3,V(G"J.Y[;)p(ZS9"U8(^&T^"rj2EFa`dG07;uXSnTKR@Hg'K,/Pt&,LU8BBZ-l/a*Kkqp<(ic!gN6jgee:/rc_Nr5/EMM%FFK'F0b3BSjF&LNuJ[(9H$Y%oonS7cC/I;NZ!L*kXip+n2&J712L<OK0gKY$!tpY1_'Qj@X2T')?5bP"/@2M\9U>!0%4@M=2t2\LX;td#b\4.Lk/W(a8*n#`]-)Ofd4P^q%K_48+7[N_5?ss$5qs+':b*nN<^LbN:ZKmQh(`Oi)*&#d$IW7-Y1A[n[cqC(5@h^?j*GM;l(?CGT^#'%aX\4h>mEbeDL!.aqi,G="U10NK-Re>9%3XPG9,Tr<g(bed?b?L%WpOhNLYG8?7KF\9B<NQ$:q:7#kUTOGdT/gQ$+#:T5B6e^OsNAB(I,?7JiAR!33OBL8Yhar#moUZZ/E$qmb)R.*G@(i_Q#BusX,Bj8Dc6p.\DT4W>kaYTsqtl;?RX^.V<.63&K/LI8mD/]MBtACFPeIo8L"TSk3G*s5)/@VOZO9ak)Q:(HFcj9<iharDQ,OUa'`ff+WTcYa[*J%$7c'"$")2Q@#sU4M2g2AInTQ<,IhA;.(e\UVCWLf5q:hrcB?FDF[e&G!+MjiJ8Y_oL5ing7B_<=%,'3JAbE>AkfM;"3ptJM3Mn?DpLZ?7:6fOaK9!&6F,Kcp,d)3.b9Zl9V]=NEO[9uqS),5>]*NdK@)g_#en7oi*'?]M4diX&eIs9R/L^9BhBFe2+]JKJr=)K#i)M>ol9)\%Sh1uZ&:t7+5C&FNpfgP^.,dpdIX$U!&E.lolN(Oh1gA\:_6j5@nQ0[L\CCG?UV`Pm`']_a@@c(%@5dcUjF$JJE(>X<gB1O6"3c`C&/LSW3T^5EbL7@q5nk15feJTrd7.O-"Bcm,dMRIfpSmcrPFEc,+U_6WN;rlnRmB/Aln5e+[)K]YpS^R7?=9W:7P%ISG91.RKg+j_n+8FR?2CPI/\<E/b0o>85&;;VC2LeH,nA8h!]\')mh]ND#F-&kofu5";Q-Kd`Q8'A@3+h`)Cghu[;ol4j>+Dhk5E;aoF8~>endstream
|
||||
Gau`S968iG&AII3lqB')14ff$m7ZfC8LCF7do^@*d=hcJR5.48+Cs.goXB$9nRY9K--,%LQ>(sJporChG=fWd%k[eO'u7"O(k88F),03Y/RlQg&jB%qIh-3ABfj9'R8:Zh%H?&qKmNOH-m#G.TX%r>(>,4m#F;o#+j=AtAHOYM_t4fXhopRB,IBpp(fk=6<Ak4Y6V?4NF:$F*\bU1=Bj=aE0rXKn[ASFo>9aSR_TH5nJDin0*@6UP$4l/memm#^Aio)fqY3XY:dH+N&qO@>OmRr8J)9a7P%U<dn:82CN7edtB$ZD*mr<H]\#FRj&VcC'%>9m/Z+Ch*S9`'8C.C/PK9g]klami=cr.Yq3&>E?IhT>U;F,^mHZQXYrS%g>L2!OV4JnP'9*B!!?+2Uh-7(RH*j'j5kCIn,&,m.7ROn1>1)p48Fa7#!8>SA[d5oOt`o@3PQ5Pg"0b,]\[+&`,T&PLpH;UYhSJ[VB&TE/59N8/_6?.3Q1gVmRc\f[uLuM-nK^`D*3Ai(neE'h&\6L&D/)<mpcXl*O[Ck[&X<.JXd9*\2@'IS_:tYd*2@]cl;2.B61PWtZ'd\qKPum,nU?8[8C:<<5U.4?icb%fs(g$r>Y<_qe>cW!h/!A1S1iAjSDGQ23QNTLR_KV?VH%$Fj6hPc_+g[!lH\FgR%I-"hRd9[cd<dXQ^`q"BFWXWdbB8[)q-LBC%kQ&J'q6MmUK\ms(ma-h=1h.[&*c$9'h52b1d`uL/$#NL[8ZuFp$ta<TZ$N9@`bQkN8,2h<;.;Q7Y@F7BlH!1o"iRYrYD8nIk$VKi"n]!dBR4RlR[GC1Wl6aMWZ`WcRF3Af74h,Wa$fQ#u!^V+RXp2&J'I17"PqLoT)[fI_-42k-;FGs6/)F*Lbs:LN[^(Hs!EXgNntF%CZ"-(N)S@bB9%`!>Xr5O+Sts)6BUmZ(0,b*oS5L`Zcd/ekPKLVr_.$n?I-ZcGK^l<sp!TBq1W'?G8)$h3UjoUJUb%b5MgKP"S[GUo/4$7N9?COaY*!q-:qu0l/dSML0IFJ*pGdnI=6MD$F/RU""'r9gQrSKc1*E8l!G'VC#lf@Pl)``n)^sPi9?Dj15C_GmOG12rY_UI_jNg:#7dod1Vb>8t1F&l`cpD4hOS=Hf-m2BJIYB]hslgk:th)aK]EHN'rf",@1p8J(hqa,[6NU-e%uh-!.(k\m%E_+CG^tHg0U!P,nD[aeTM(:C1\V7j6o;LLc4%c-8O8m9D.nbNcQqUZq$/IAb]$HZ3%LG--DOHt8R,]r*'"g$T:"3a;og]?RJH.L6fF;is+cP0EZ9fo$u`(3_N_<.\9\-?G;E#cU_sJ_;\X/`GM7d=24jD&,%,&#kq8'rCbT+3[XCCX<<i'[3qA30&:qBg1P<0;Z-uV;Za6a:;E><6R!p5>Ei+U`WG_h2eKKj>%FE9Kuo8j>+jJ`gQ=O:,%F9%8lGnTGLM*dgrDl>jEeuoYY>`@?H*\)[<>N&\cm3JQ7(+@AL-]8bLF8WDr.O<6>rpZRVgs-#lc-pl1LY8a1c=/^5)G$<M8ML$Ab>.eEclj]6V>.VZnTGq:m[=NiP"fBQP:!Pe#S@NLrcV-K=B3#5U*nBH0!]oM*V1R#9SpLTU^V'1Yi+G9:UgHI_ik4;X?I#RN^WD%8#c,TJhV0>2G(k:;`/PC@"q24&U:+`'X9^EP=odgcS()I?(F5cEUJCq**gVKm=KDB?mPO:@_C,8c[l)p_Bi[[YJnC,jT%[>fheR7kg:_XFG~>endstream
|
||||
endobj
|
||||
19 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1971
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1872
|
||||
>>
|
||||
stream
|
||||
Gb!;dgN)%,&:N/3m!'jU2mEqr]P"+j3mOR>S2@3FkJ])"[A#'HKZ]5'B);%'J<WIEU1HEX['aGlZkgI1KAD/cE\Q^rok-)dGWCH?D`D\:__H+g=YMsnf>GEH""##H=uJ(`1JD-Uo1el[Gs'0`G*q:tT7^ddb]>A?4O-(8pH[(bfB"XG#ihfb%a9&(f<^!QgibgC`d!\-6I=-rZQ7*D*oGoI'Ki!J%6B)D^M,I/i/L\$=\XelgidNOcJe91YErnkZ])/F-;p`1H^SA#.H*l)(J`96'jbB"(RT[__^Q"dWWcRi>)l**3,WrgF"E2HNpB8##'#e0@(%EW6k%q&jd68DCr7IZpCU*ZKX"tY=BK?*eZ5tFSR!Sd=%&O^I;K2!@dgsqpOIOCFmH\d-Y]=b*GM8$aVN86I:m87hdB8]3UY`7mLYr+pXdt4':G1a<UMb(L!,-DOB1M9K.OpcAfKHG"d+GpO3lp5NaWLe!S8/p*<oLmYJ/nHXg,U)BdmV6>Z<FHCRJQ2AMP977b>BjR-gKa!Sc/Bca#CL&71E\*\Q%-RK9>XdBe%DTJ`V8LgpR`WBi/0^_A$1#F#6dPnu2??H==as7AUQ\CN0*Jpl9PQA"XQ&%9LM1(Rj<TI;Nh0fstXNY&4d9Ta#T--`W[O`NjLq=>7Th$;23,<OY4XL<L`V.F[0:=>TAieVVa*(6XIMq3,!'Yi#`FMPEL$'Q&hOC4M\3^(msq!II!fs"_Xr-X]@FI0iJWQh?$i](DD35VOa3EM*EgOSpCAY::Tl??<28J%+NqOje9=!&*2YODodME-h!""F$Z\.18Rea`-7!QuV,Bd7'qo.$/:`]E\#'92B`N7;5,_R46!D/cP-G0i<.H4h<JNeeUe`B],%>h-+18^]eMVUJ`J-:9XD)jtL3WJ%0sTpOF$GR-_n_D'&l,=97T86HGSGn@na0[#Yo$pdoHV9DF<5%"[_>%l,u57V*soYUOK[!;sVXFji-+3CV&5Kg[CD03k[20ms.Skp!Pfs.FHI$^j^g3j0/<dW52l.nB@2WH7>^&)[C#%p#.YINolJi#Ko3FtQnXaB0IBh*CrYRZs5?R&-(2c?V1XtliB59ASmCK*S;hp0Wo>5*(0,`Qf(R>t;/l0=L26)aaRaE?LCi2d95O)qkXnSdXc"8+:Jio<Uq0'^+ZE]Jn$jtk^u3Z,1+bFL9Zb-NCQ8'A]s3q!+@0U_@T6W7(tb<pK'q>+dZZs'M;BrtZ5qia']ZXAePjAqW5f+MRA()S@X"D<sbl@:Ku7m:ht;qq+k"K^1c0*+\%_P$*9?p`roPp-T-@GGBB`Q^N`d4!,rimoCR2e;]thLEOa\)RVrGr-]E91mt.5Gl9kp%"B,MVW0i87d?FKe:jAW+rQ!N%39A1?_d&s#U7q8.cYgFN3O7bu=u`ko*=-9dq'W9((*/RG=j__KR%qNHI=&4BD\PQr%L]_,fmNLI(mh.WBau;60'CB:4tuhm88fZqt(m"pW`g3%8J/2eYSfhG`e,5='pk"Z8&sEi)D[+@L@JWH2=&-0?qZa`J<`H5"moXBVSa<1:Z^(jF7(\mB>kD=FrU^!35##rguE]=X=%g_VOVO&=c7[Z=VP7C>s/ZRXEch(jVLlDYItqI<?u+rMqqZoh6IV%u?oFrG3I0<4-6ck#Qm:3!2Ll;n/]-$:@S@QNdre9q^/et%WX]84,H5*Ks9M-efXn-g4U=(9g.HI64"`W"#8)spp[&n7A-"WN-k9T2T"dU]$m;:6lXZsBTtZjgcW/_=WqD5s*!o1lXb'[DGHF$o#cXZN$KH##2B^"9TkPE*Z2-#I8DX#*0P2,cmZS%^d!KDO'D3$Xg+kGOCNSmXIfi=#5dh_QfU,Je6;Ve_i(c#YtQrNM?#lK<>7XpA_pq8:_[i)1;!R--5[8W\o[B4E7I#BuMNYDtF1@9q*#P#57#;'eFJ_j;X;PY1J++G_4HPg=E@P0nI$_;HEY\8bX~>endstream
|
||||
Gb!#\968iG&AII3lm*Cd[3uT6HR=NtM:4;Ll-rbgM_>bN8X)es+X(E[?f)%EP"CRTeP7DnUqd0'mI%Fo=9jFr^%`'MJ=dW3^X5?FYZQHoC*kLG^k]nilU7p%D5u81p$ftBM`[Ffd<)+0[LV]T-&+o5>>P%4"B2'2NdHj]9ZPOcf5o]OG[e6P9l,SY="f8DNL7ZKNjuJj0PSO#6h?+Fl,?QnR'#VamGO`3i_CfL,,e!5"jq&8co&jd4-)tF(hr^O-DUeYj,XC[4hoCA]aZ<Xam&qEWSV<Y_V>??Kscd"<n>:Lg>&:^;4ZE+;(lZG%P/6["sG8>QHpDkElhq00$?[Ao@*=@/@Mdm(g*QIW[2nY5do\aZ983#L19<C`]V0p]r.0%4Z\0TKoM>]eU/Er^lLDuQWFA7Uk@V"?Ih*3@Ehm7NM0ZtHnA'f2rle1k4oHT8er79"M^dl1Cb"PlbW].HhZu(OjYTP+)of(?+(Z]N/g2*YA2]A:%;O%'JBnQnX_RYLg'+/An.0!-2Tr[iq42mH:>\_(PU8*_+MWhb6E@Dk94:n*^Y<P-pIfe5iAH^<$`\g=)\hlXC_">isqK<-A%s)gltp54o$713<g*AI]At$T]KSh0c[#ts)ZA_T.:#re1iQ%N09_+Uc1R*-9tgiN0_P$%GilHZ\ZFeLfKg`(/)JScM/MWbH>fOQ8&^Oa(_.$Z@.IsBB]+#Z':&3qa<9eZ<\COs6*W\1>S/[ioj;b"fH)%0`%0b2RoR@nQg"%rZnMuBGg#[[J8",#;Tce_?P-:aAhAi_OiPGFsKX&<hn-EM!G4WPo5)102KB`"Q'@`9-q7J"TD/R=WikaAhk"s"OLo[a39mtJ-BaSLF](a,lHou#rn46-QYdJ!=L-/M#hW4ZOp6=-DL[rf,Zq,h#SS#Jb.t+S4[h^b?=+O`o81:Yu=]n#'$Slq%`q<=@ZV_)AjCBED6Q$Lk?,5%buN'BGPurae,ps`Et@T'lhip!DF/*\Z5<i.DhmV&br7m'U].!'_*Ze<-2QHZ^B_*>mNfC>&D]OW68?E554++3Hd+i[[<eN*3_geq`KOY_pUR!4htN)ngE&IQY6d&DS9Xb0rLNQMh_O2hLPsc-1H^^nDfnpLg$NTVUfAU9o(>?OeN<.lmUJ\:oQpR=??;roM=7RM%g?$Np=RtjS'?j!B*MG1#HoLND[mCkGU7>F\"8PJN0ZCf3Lk1X2GDSCkc<%<`N4',H4>rKV^sRh3DaZ=/D<r6EQ<V+ko00qq%8nRH@nl"MoUqU_[4,?TsqO+V+chEMhO1a&q0%LTGBb2#:QCa0<i1RsZZh+ir*aQUm/Hb;OgNbR:C'1M)V?fV?4PPf69;CPSVrgeY+ls*0#r(r,W2IfF#=$H,)3?kunR%*b`qU8K_Bf,YNmr>h-^/s7W@JdqRZM4dudQEtMWp.)KMpj//pWC*6XKcWRkPB`a/r9AC%U75HJ*#I5%dbi>onWE@S2QIq!5&:RiBLK<LX1Qog*-,+[9Or=k9X00kR,b3L]?17F'"EEI#Ql$.ZY2s$BNjj]*5Hl-!;@h8j%eW:/,Ll$)'cMo?fo'u4Pe-4dZ5KS^m-:BV:_Q`[UlIa69"Ke\sXdb1LI$6!fIqr&b0+<44Vke_8WH?n3*'Z79H_8)[`j^+H'.nlJ`+]kuj7Y7OUo:7aJ*K8g..;70al422kQd#UA\<UcRmtA\*?MT+]f=SjR.;K[(rFmObDdS\SGX%iF=fJ@BL@[V1am#R=R@S\"hf&$Yf7aBtrb&K:^&=JEre;qtb\*p#)6Y5A9*VOh7pL51(;&+0V`<ZL>1CqE5IlSYgJlK!>pH?%:\3s'Pf3PDt-mS.'F$LBPjo`Y2o1SK+ZOT*.-`F8<rUEh@q~>endstream
|
||||
endobj
|
||||
20 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1727
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1894
|
||||
>>
|
||||
stream
|
||||
Gb!;d>B?8n'RnB330TcUUmDW(69sGVm^AV@[_$Bjnrae,+$1b'(1a?1YMURU0m;mlp:?f/@N,]NF2*+C%bUFBR*R_oGSS'J)[@>ed0(G,EJWJfn'TOt7huc^k8m`C@(RQa.s1G+<7@T^4CO).Kan6oDZr<0*]R13KE3bfkPL8M'uK%bOTUn&Cd6ic"car3n_h&q$-%cY[lbhNp%,;5JJKoG6n9:7ft<+Xm;Q7*3iXgACrc-1Lb^scnFu#Jr)$.mNc0e!KeKICpdW(W@m6Di^i)3QZm`2*$ILFncSU7q;(_oJ627KKhdKfk@aYh`7o#7Q!q-`r8/>H,&?HViGD-cV2CH\siuS^M\>JO.lPk?+>%*>sYA1't:6CJj`>"nriH4dJ[i8+LBB/0)[5So":L:3Fe!I!hPR)P1U*h0276nslW`d:Ji\W*l]BE2ug_Ys2D+JA,mdOJpkkj3ObG>I6E^>hOp/W6fPV7m?X.rGI@ld8L[&%HGZq"q,.Ai"nO6q*Xo4].(A%7)jB942u_0l/G(Ful1JFp697c>34[>Ac7Q*ufb+lb"'RNStsfpZ#Ig/mH2Rk"lYOossOZ";7*)a)rO@XNWFr"a@T&1^#i+o57!kI=,V"\Gl$R`H=S?51Z50/[Ui:dH]iHi]VV,^f\nOlGm5O+1F+Hl%^Xn&OFJdSeXA3D#oZLl3uk>6A`aNX'uU:/ag:Y?SLm_j@k<LAR7[F'M;g/^`qhIAVY1fS!Z+GR`FPBAZ>5Npgm$dWI+eE<<&YCF9pGc7u0:^/&X]-^:u:-q_!m4\*8.-r[e5b*isnrd">lH0qEbCPjX0lD0N!@U@=ERP#hdQ'D*SXb?@W3rVM^p[]N)<0e.";Q,g`^#@Z1q=ag@H`7BE2G7%j3_:`SE1B`K\)"r-1B@$b>$l!9_!<0p$Ru2[ZJY6TbN6UiibmVg=LV_KcU?qPK+D'/R'8X!i!dm[L8`^n%XE'mFF^I$h%O@HP@g;QoT`B/f@quU[!ocVZDnWPhDh(!<3lo`Ge`YJ?.6t(k6^"_>im/OL6%P?U`NoRm]W#IIoTSk+X=pI4FjQS#+:Bf17*"'"+(Uq,F<O:/1$Rm!Ed>N78K'gM.O3Sa"fb^`A/K=;Q&t%bKsgOAa$2.3+?Yq57G_K3BA]YM][I\FLZ,g1RA8?%9,?OULH\Yh#LtcTS[ZB1-83M9H2&AHJc)%`fq$4`A^VoDlIVf3Wj8W%-]Glb?GrdZ_VAO-P:p$q]n+ujIIG<93G,L`B%sY*C9rb).jau,H=^)i$6ha<[uOXc)Z]W!E%#GJM6icJ5LuHL^*$YY:SIHkFDdSSHfpFedj)B=dE^?UT4=i+S1T1C6dSOO#2$/&B3<&`VFt?l[[cl\B0J*os]I<KBVM/d#f>Ha"I&MZ\[&tI?Sf7X*P=Oq#F.F]i$j?$E>Ap:-?1@0OO0R62jPq6,kXFMC'>nT[X2U:adZ0HuAAiH(#cb^]fZ%#K$^t-SHhQp8_rC^uY/3_:_!EdK[_AKIrNmq@S8R92&W`E$Adl<58'5okHCU,[\YLj$_o:XN%3D&%STm9&AqjB0!gm=Rnj^AV>Y5%8\gK@CP!9adrqk+^8>VLS4)A8JT2b6(pc"dtIp$bp]:Wk#]cP-0:@`?!14I>c&8VJ"#Iqk%1E>lqp^`O7s_/@9fJj^tT<u!L:iJ>V"`Kqpaj,k4t#<\Tqr^/VrJdYlr<Zj+KnnGloBl<(X>91iW(/<6n^;~>endstream
|
||||
GauHLgMYb*&:O:S%/T%^[45)K!"60']l2:e;e,]fLXOVlAh6TT7)a#WIYX(;q52fd#*"i!VTH@gc5[moJOpAQrsr025>U7_D[[J<Bai3DCm_ql?`0[&,M(.^\`!`T@,P1jiB*o2lf_i26h=O+7q@9qG0.UYCiWoq@oHSOIo7K:0thr@dp&2GBGVcTdCXDRer=J8/N7;?ET<f(Zn]]6_Xt[R2NbQ*ZQ1_Nhm<HB0sL;rR=R,'0LXYP9]gRpkNU>uA#'WW$RHYi;H-;fXnQ/B=0(Q8qfZqbC(*%kHOqf_RcGY]9HYSL'GMB:<&keg:Z+A@#5el<go"TM:Te6*1V/6"cAG5;Lfg/-hsR6o=]+UoWe@u8.j3&6L#3U"N:/(@:bp'J67=Qf&oV)?J<'RZkZDJjdsHDN9A$E3l1Z08.AoLg3Fjim+dNZ"_k/4sqi#pte+1&LMNW-VUhWUc(FaS499DOdj1*dd;IP_rqEU(eP+m"eMGMFb?(NG$i=0&P/_(s(=?nDN4E1%7cY^_&/s1$IGJi7TO*/oaO]!hIQO!Fc8X84=(D8UGCR>p+6<I6EOqSiW("Q9DLKT:o!q.D;LCrf=27[/KY+n?I3l,glDSl3Rk&stklem$jXCo=KgZWiZ^mDN;3Z9suWFO[eJNT*ir_0"4AKhu9^c*o4IEtdbj[l=a#RW9i;5l+j<dB9(Fl:df-_KMjoAE:73g]WcB85j[5"l6h![59#U\_6`A)#&d(kL`D`8CI<RoS6+BfU.)@+aKemFk'o3an?sc*FZ[.gNel*4CaA"m0c0(?;B]Df*tS'Q1NP@,!t+o<V8t5Qt#>C2:r*>R;J@ab/<q>MYC-EL%KBr-$50]1/Z+;O%l)\?R$Ns&(7d$tUu0#r=,t8>G4RaKb!:NjBuTo$Cr?7rl0c/<5$p(G:ddA0pdi#<lqiCNd7IX#/=3qa%=QK`-("P*I?\@(d'C.2XD+*/MiCa(q26=]f!Z+M'7E:Z]tVal6EWP/+CPSTZ;m1Xu1fWhn-9,F7r$^]Mt*@BgIHojf)Z)J:E;[ke\CLHr0n-&NmO%,#L@@kQ:<Zctn,#7F\7XO-.X/D8!He'27lG<7RImrOD3KmUON0eb`T,uU5a^Q/d.efAb3qPM\Z'DOD3Lfm.DY"/FRF>?t,hbA@fh;M]beJUruBUD/67jd&#\5PIER)oDr1@1SO-IoIX,0hmP6fS3K7^hJ;R<E)^aS&?AYTN/gE"18S^$QD]1FF/b@hu8-Cu19l`\[]S<\5NBNDk-tlh"+2@YX(CooRk/0t"-F\Adp31]&TS-%2<^bAag**DiH[ZBAqsLV+<<!GC3TSpQ478P3ZR,,l66ONItU]LV2<"7EKdPG5^DVAZS"VEn5A2+CS:_Pe4I$=jKh,/i>4k/_H2^sR.(K6>/(TUYG#'o-^(C0rJ8:Em94ZIO9]FN&7CgBlh9o$K2VZtPtq[<Pp_@W#9p1*rIYW9@USTn:(V3t=P/b>@?n.2'h%>*I;U_5Sa$)N">9lBMOd4%%;5EsFeX@($"sgnJt_LYl?AA3MQf3e>3$2H5aIg3_t'g]DA\k7%W00uIGDf?kX:NB5;t>5TjSc(nD#H9YLV+V0;&`=(DFA\DH#@$/9_1k_#amrQ1[m;#.[$!5T"P@^3ImnL0B(QmK&aKZ!e$4Bc*<%hda^lnPuUnd%j"oPa($ek1:V.k@*a!_WBCr9gN*9@,Zco8Z[H2j:i)9>]cUL\ZJ99d]1$sKa_&.#jdQEV^9+u&Gj.["kYnIQ90#?Ka%f->jneb43Nh]*$'9*6l2C&jJtDU<(>OkuCMYZdAH*^num!qBe@hUbJEE*)A.jTfI\?HtFK[bk-L9"E900$'.>iV*/G6X0iWOM<e=T7L/&d@GKE$UqaXE:\e2Ilk@b$N~>endstream
|
||||
endobj
|
||||
21 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1831
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2145
|
||||
>>
|
||||
stream
|
||||
Gb!SlD/[lo&H:Nn1$TPV>dsF\?E]Jdl<St,'6$3'O\Y`33#cL/gDfKR$iT`WlaJ3T>c.b!dksjofX!B[bg+D<[_]hI?%,6l^n2i2IVj^3@5J)@,qb/5_Q2)#f)n>Woj&)a__!7/5Q]"(5oq+Yi%`(M)VDhWT5`ZkQeR2bJ-3c5^2Nn1$^a(=Y^uSno!o-]gE,DAc?b7"9$t"=4N<!?oeepNi!"eakR_A!O31;9Y+9=83\I[RchCh3_VkCM(N85:`M/1N8gWt0k9?@1(fT_;+)g)6\.XX%MYno^(,1&H%'1n#)+PL1^T$k--jm(gQ')Yd/@,o#2$G'VJrKt(CKNcsKR9#COiQ3l2XntN>.Y2m\KR:/R*b[oO(!"=apXJ!.:<ibNZs`@';;8Fi'n%_V<R$lZsG`%%Q,d?`$'Tqmn8eZPu@Fb])&58VX$+!YlTC`OiJZ.Mp"[/k)c=o1TA]%'0&ubR4&Ln?>mIr'T#L^Oi)DTMb1XGQ_j8`89!`;IQYY6N'sO/9VjA]:WZ(RG".8kmTP:"?)??MpZAV_i0r;`cF[X+EtcO/\O-<H?m=nnh<#,eekKB1mE3dmLeO5djjC0mi:%Y%GJSBoX`TkU4rE%gh[.`9M.bSu?F/0/`_PXhVXb=25aA@g.`Og%;A='rEi]PWa=oX6>V:n/o2sPoYOf$(F]W!M*q$3%^oH$^kfW!@MSrDNNV^BLh_0*?;;Su9U(6X(f5bl;,JcTfesOF*>)cNFa`Jf<.[i!;?fiEeJFKdR?F+npAhX!2gS=[r>M8IGM3^Ygbf"gANsAZ$?=a`J#.uHACr$(U!e9">A(t0637\FQ>F?@-="9%q2AP>@3D*6b)P8_e@5aB*9]Q9<cn(-_b'RUebF?9L,;?dd@C:b[=@hf<@0ZD/cZ!4:`C*'bF`O98)2Mg\D1;NIi7Z]A/+]L(-jadJ84j5?X9_`8VIA8=i]Th_bNVf<:g_'JP<Xhfe2K_[H\fJ>Gt&ktJtYdEA6ie/MG,9%R_DXdS2l/LFS^AEQS\U<6UTIqXk]TkgZnA&*B:_!HA<#<X]6>g@\;"o(3*UA);fWGi#/4#fY:Bf]/M$uV\LaXi8c:TJqttdW2<^n1+g3`A'@[#cGO1b%7A<SQl\4h:[X0AR6`[MMF)K9MC_sH\;.i.a=a=)BtHk`*OZQZ+3NRdEqfHO[iKTLA,C+=B%Gq;p=shES'i;0bc?k7I$Y6JbZPG3f_TJd\Sf/o*!6`'*3`bgr_BYCoX[-?gsA^_pSjr%FIQ%,D(YqF0+24XY0-Rrk=r::N!;Qur?]t*,ou7al62TcncI9N,-^14a`#Y!i#[-7;lVj'NMj6LE4,%O.3^d9ij(W:o`8n\KZiKI15lCa`OFZ=&.T.a36DZ75!ZOJGtEDO=`FhHd;R=Y$;Wt!3:=^o<QG*&;`,:LG^I>,bC:-t"]l>7?oenKWQa@r&(Q,p(a+_bj^+sc6YD=S(-N=@a7I^1gmj+\0MOWq[W!-8n$2VL7>E]%c`b:$Le/,C=qV"4&7HX)HN:-]L;Oo5C4dp&VNJiQ?&5"3e';JoosBNia\UHn$;?1RlFsLpC1g?jf1Ri^R4Lj5%utD@n9[2n8Y>snb$TP93H^3H.T_@IXK=Eki\,[4E!UGY*LmAakH7`IRc?@Ni7$?[n_guqpuuXj1HuNiFq[?7=bQT7m:6X66X,*`SV(QI@+m5S/6La,\=ti$E)Jhl]V!;Gcee)oVLM4p"q<kD@@e4Rl;GO-8EtA"i"/E^;K*((Efo=S,71^O-;6l-)\e#6cI>IIT+ZC(gjDK<>_j9gS8WX)Bcj8k*reVqVTcTI'\MOcE:>NN66#I~>endstream
|
||||
Gau`TD,]1Y&H;*)YsTm;6L^[1]r,5+;FoLgSYgYcl&7k%/>%ne0<QQfkcaGrVcOOj+e;1Z[]Is7mbYZ?]5(.W?JKot.FAY>3]ZBA"\k<$*Tk`04e5;:IuehAl$CP]7EERY4VkPnK7.u\RE*9]e8hc%#P$LHJF&rc_Ls:aa!G=&Q5p<ATrn>5-G7e93i([_>+S3]_^Y?YQSc7IacRA.&[,Msc'cb#^^%0DrnkP^D_n$(.\e7B91>cCimf^>Q?8>R"\ij#lZYfk-*'b6G%qSMYeJsKHWeZUVEWa]8l\<FU0A@FnVX&'X44&)VM@YHWKc!KX/a*QSs0IMe!H+9pa_s1MiR[i.TWR$B,@kJM4E%"Q'ITaBC\7CPO"&`k(A3;Not0I%hlII,C$dK]Zq4B<`df9L5]^qg(\+)'UqLUZ^l:(`S8t0ph-#X%$iU`aVGT.8;`9eYNSGfFJWYVjB!h2N9sB";DaH<80umM=h:aI81IJE^n.3t[:L^lgZAEWGK;a5n"=hS133rQMu@**?SLA[6S4UDMh`@Or`VAi6F2eA%MLJG6V9k/n$=,BK75Bi3J""cp.J/rCEegBNo^dQJsI`%F_dMZbdIW"Yj0eejuQ[@_jp>&-L*GO<kt`M8Of6G5qmP"ousLD<Wnd"qD26eY0HtF2#Z$>F?*MG_3XrJ!k_7$nUST1#2ofI$<\den0kZ[,7KO_%_n]G/.Z"Y^d]0ZFr^\c2X[I56KU6n+:S-%]iFZ5'495LDQPOc,"=h`<=pHddsRi1([,U<ff!bN9k9dL`^g16qIOf9`7aFC<XK^bH?#VrmQZBb1=,ZHL?4+=DH$WV:"OZf1-k.&%OniNS##n@%Q:7B;1bfH*KWr-/a-6XK!Kb9Y9'$?gW[-\BEe>;!<q+k<<)q#b[T6>YHisZ*bQc1Lr/c^L=Q)HMlJb_A2;ND0gh0r<6%-KBWnOjYYSkTisHhW^E`DcS\u,_$\1^?QtBkM:qkMAoHCXUqOr"SS1^B4.uLu>R4@^KSq&"o9C+Hm:a+r#7F4[ekoZ0A2;Xd2r-H,"e.UmFWW%AUZc*KhCp;l3pfaio!4M54Yj;Bifc$[?4dP7'[F&\"S0)jJUVh//;0CG@iei1R6c?.M[K\KJc_HI+eBbqm\-%e%!l$\k6J0;eesk"Shs)U>/!X('rDg!s[carTC[E#<L?t8*i0d&udPQ&,Hh0)5\TIVcVRdRYSNifagMke1g]*LWB?MT;q#m,@q/QlAXQVE@bDJ(59\ldT/)]p5NU?sMZTdk&^h?^a&sXIo`ec=EH(a+F@r:YjlL!;W1>-NTDH[[un.[P<C'EIZS1!%aW)3QpodD%$]2I^L=6GQ3$#W)l\[K6:E_S6]e#U/N)`>]BXuCKIW",EJ1\&,L42+5;MbDK;oQ3th>:e#J_SsK(X!+E+/YcrHQh9GQAYU%KV=OUg=D3BhVF-nc/eXG'4Z$m0"80^E.23qbT0,QZ]t>3a[\CPqh*CB*I^U'r:#.F>ibG'X=-t&C8"Od7qQ^=^?KRsT4b@0bMji#&I#O^I@r+DR+boR#`f.>t5;B*V1)m-3D9=O.iF8MW+n9NkdR>u32bc3=^7rC!I!AH1!^dd4<>F.]%qdZ.Q$;>ZofBXQ*RehijR[CMIE>%G:>&)eYWWm5)YQq[\qj:aZb;=H2*1?go.\u\k\)X<RW4#RbfTS;nHS2NmpLljS7aYn_FMXFl#^-<,boVpb<M[9F8sE1r#^h6:lo)I7:&V4H^!b5r3fL7,aZ\:=`e0"m^h1b\A/&V%3>6&0^rM.3q0cXV+H()&.&_M0CXLtpTDaf-eQTYX,iC1S.kX<DI?*ok*@H_'9nW74$W/L*$Peqb!3A4lN*\2HnubLKGPM@=K])Y^ADRTmT.Q6HWIjNX+ou3.e7T2dN[_O(a\gAb0@Tp-KoRBApg02CHt'ehEii:F++OeQ.T*V2eqZfOG?T^#W$nb_kakh2`,!)h@8.,4c,,u>:$I[lgW`'@6H'k1;^>be.K!GepFc>=IPkkG%ha2&po[[2:^BXWfZVo@Wf;&XZ$3Xf5t?&S]YD=dKuHGlXWtck699HSQ$*GgS8Q:)j9b<h:GdWj3MsWTd.B9BI!8)+#k,#:ri]K,Q7Ub`*BljZRbG7!-\`T1dFU,IfVEZ&Y/~>endstream
|
||||
endobj
|
||||
22 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1936
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1164
|
||||
>>
|
||||
stream
|
||||
Gau`T>BA7Q'RnB33)aFE^_0Y1jkBknP]E='=eMHaI;p7GF^nWY=_WGXrU5(Yhi_</Z7p+D8K(_mp[aqOAO,e)gj<3+4J0LL.gCsMF9,&H!Rl8^E]X&47!QL7i</TolGX`6m+EK-fr+s:+@44]"q_;9'FGB`,>f.F_!tYHZ4OBr`T%O4&dC1O"H\H85nr*6mu`-A<%WnJ"S)0VXaQ<h0.&u#*Lb[ZU+kB=>,Q\GSfj9nTb#Tb`p`piI1'sm-L:;/W<,7&/^nbCB:O`roG1cS93J3Ye;n!`!Ro(i_1kbu7-HrKD@:k?le8:+,NM4Tj])AuL4G=%_+m>4>I/oX@$"KLOWP0)=WCgoqTgM42EW4C-fI7la&%da(cJ)Tf8>]HW'**kp$iOu'f=]NM7Pk7B\4&_O9N@;U:Rb"`&r.PCkRSFh:,ZUYFqiQ9/4;uU1iRA*JDg+=$!(.0a3$jD/IT0h@+n2U[sVK,Pu6(IJ?E"m-9k!W3(l8KNZQY#9\C,G[][]odj7J%[0nAR&nR.TiPqRM5fH:Oj=O'odZ@U[9^;U!]kn(7m`8X-h6V1*5cJ`f]bP!1'8sUOO\`To#cJ[&tC96>&'EP#3HO*Q"=u"aX_>2>+2k%%,#JmpM'<5Q8?5"QdGO0ek_H#o,6Y\NR&Z.]sS^\`'t,-oCh>gm@NdbL(-L)_:H-6=4lB4J[n.7ED1nYCL&Hmf7g;q*a39#+]C0g<Ft5-ZXrR,#5PM@%,0.P>_\VEAo!)tX.8\Q=(a5DeF-?s&9Rfhn.a#50B_W#ROn"r!iDg#:+M#)b9\.?o2%t\)jo_'+H*)'gWGd)n6R#(MAhL]^O/7/+ls\TF<4TK5a8m9K0r*^iiJ"+p!;q9(Oa5UlO_Yi=GBGoUb([*[<g?3oc*l0(r\p/G`:pFc*`B&N"-]DIG/N&/a-7e7eL,7N9XL.+H-fAIPF<3N^>^BB$,b/W]gl/nSt+tb7CU$G%1Qe&Wca7OGQjZBIk'5&)bAOl#O7<(1E"QkO-ColhZM_(H&DsN`I\*A9%7%Z.VbU"6.@`BI-?eY2i0So9Fm\kWC_!Wk$n0+qUn:3tY%j>ijKU0#aE'50'1ISa)CK)pcMWT#:#9KFiG&BTEEbRu+g7Y`)'t%YHsLa/Z_8Q-&-ZJ\kM[BLk5*:8GTloKPeR;&,\+EAT50F^^lW!R:j>M]>e/&6T?%;Qc0N6`&pj[RU^K[%"h^_Nu$0?"9Ge<KUAR$"R*#n]?Ui]fh\%*nL=Pe^sM.WliamD.N;K&M]K93_?XQDFrL6ShCYs)G-j,aC'aqRNrUX`[WG/.`74A8L]R-S%ZeP8klIgq?c_q3_c'nZk(m)PThmq,)UU]NcV>*)W.CB9%U;m%=C2sDB#gJ`UJ*C'`J+jZ]ee+%R25i-apX'2@0^kc)K2Km"Oa(,fE-c)>qd2Y!%o.@U>Pl`7VKj13Dls&8b:32S2QRF^hS#D7sb-nbjn//#T@)D#UWm7<[uNiYL%u@J$<NnE",aS[UZb+;`n3c@Ik.7PY2%d*Rb,hC$`mR4^(nq^/![3&gWK_&l7SFM.*hcQBrfdW8poRjo)8j.0b^q'VLi^Z`eWpqRKc[du&Zm*7,GMFC?L,ujWs)P$Uf/^VfihPHOj[TfT@Xgl-F0n3+VFcX-@g4u!gQdY;L"Q"?#dD=DYFIfZj][KE4+['3FgX((50o0%LTpb$RCKMmo[P4$!:ut4W)5Y*Yn[E=QTsZ@cE#HQk=@**C^!//T1%a'X5NqqrkMN3q4=n=MEQ1u!.OW;$&54m:[.nHRnBR5*7%Q;Cj2BTeU`9=46?iHn[o7V_:lDd>h7jc/YR/\J+hskjjBbB=?WKUeg,dT$+Z6uOp;t@e)O6/@3;C8ST#MW52uMl.%Cn"%OL''f=VNh@937Y\_'JTA"l@Q*P7NMdJQ:Y=(J&(;[DFG^)ogJ\J^M6Ck_-n~>endstream
|
||||
endobj
|
||||
23 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1809
|
||||
>>
|
||||
stream
|
||||
Gb!#\?$"^Z'Rf.Gh!%IG-P_pu96OXMh6c!]VVA;NgD=HWMClW[f[L\4fjDKq[ZO:Q"Hr._)_tfSFMDqCnWbPJpnIG.]EJ"X%&;Dg."h%(-mp"Sn)2`@n81FX@$1a[r6Y$["sid,+-a)t%Y5`H@M+=@P9cA4GXtCC7NjHj-RG$SC7%1*:`rY\1?:\e)Mh5fYhgaZ0m(Z3+@L<oI2cO,_i'=aUVedTIl)m9BUb6ml>tt45R&oK_XRMZ^Ycnt@]$2N?5+9)0r9on"t#:#GjuPUlAa)HPqJ]Ep`.:LXb33B/j`5taBbS0FB+`<g)0XaAneD5p'c>c$>qF$eqPK!6,LFt=S]PDd/<>Zi;pD/l<WqK?*RNC:Pue71(CfGM\9c+UY#M5S-]Qkqob8TYUEPOf(W:6jq,k(JQ8Q_$_8C.,^F6q,4t.NRjOgMN<GukI5YcE-l=(C#RbT6K&qMUfc\@qAHRsYE+(]d?m^]M4kUn`[r^P[)rj,=]HElTWU6&qPR<7:\&Mu@WJb.G'&*toZU'EV_qr^GB?][h`<3:O-GqJhf'RdM9m7Hck(B*Tp=0.PoU8-Hmt=3J(AL%_6mQ6+$"0-eV+_?An`<BXZ2cn>':%a75oQ^*<i*dE\V/#6>3a.Y^g6,[Su0%nY"/HAqY&AV#=',RWH<E[aoj'/\6,nk>j%t&D+BG^^)p93H*WJ<U:k<?n0@iMoQ=j6OTgImhB#%]Fk&ojr>rd%bnC0q8i`:1G59MII0JQHXp2+,3W,)4k=8@NB/<g;;[c@Kn)OJUUFpYV&DF)De^#0ocK[f;MsCfnIT4>N1'cCob(kA>b6s#5V4h"\e_9@#-fBdr)ZBg!PEAjg0BeVGIel59*;Mq9S`Cu6,F3`FM^+i5nN(/dkNd]@(J#0Xhkr=rr^6b&<1A.3;Ah>0:7`U*bdu"m%r(9C")C;A7GpmtHCS#tBS_R7+5b@3*Y@;Rd!E9KP4'(K1KMg?50qZ`O]nSPNn[;&-0-a/pkhZt;tu(b/CWmnI<5u:F/ZbCSZeg#/^k<-$#33r:#h\=PMo!1"kHjWQ[(\k(Fh:EeS;4gb[GIU`o=HhE<)VV`;?8-'L)C'T?!<d"]L]Nr.$aP^OO?hYB)D+@X#QBa2R>L'q9P$`^\p;#/QXjTFgYn?_\f;![\#sf;Qc2.$VS_<"u^'>Qer_C6\VT1s1f&SM@>>otVIl,/SUBZDKplTQjG\Mfk>mS>bNTZEuBJ&=Y.*H\?'&o3QiPl.G4\(g`H'\ss3-SU:D(3]?o;A"@N(l3#e'^:kVbB>`o1Vj7Y>l"QoHGeI/iqbhXOMI)A0^j!<&Qcb^oeY74tHOk1J=Q/)>n+!<3'lV%UZ_"2L']o<:(q./MoR;@W6V&E##^Due_JZ6PO/S%X'VB!#Mnk<S3kI&*c>LSdN-Utt#H%)FJ!rNPkA%E1+<B"7`Mc0*f*GL"D(e$#BB;0[^]p:`^XaoXVCI!Rc%^HC`3Z(&CY$;,L_nAMlu0tkmOA-K_lO/G[;jnG2?d]+S"qUS)aE#r6=r7*_XS\FCcp0K4\Q3"@(FQVqJ;VS@s=(W6:f=tH&dI$YFRqTE"d,;aKcJ\E/^okKWle*8dTmaA"Gj8T<-3CbI"7AI8I.4<Z:Iu;!qA_`ZMXm1OYt',b;d"Jh9d'DKlgdcP)]#bM6@\rZqg!%Y;ufk<Ff+)]hIlUYkJW<)X"9na"^iD^jqVB(!LfG'sY?]A"r]U$hPO<6?/4oW`,'1o*9AGJl9MVi'YKHG7dO]Id@,Yh+^qZ\RA+HVr#V!>E+IId^4K^<h,i;V9.Ul3B8?l5'm."oGsZ6N~>endstream
|
||||
endobj
|
||||
24 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1122
|
||||
>>
|
||||
stream
|
||||
Gb!;c>B?8n'Roe[30-h4&Vu>VH/%K4lu]i'/DDPe#V9J#5ctZlq=cCW%Sd("4?FUfit.9JF8=+*oGn*fWIJmYN&#oZ!>ma4YQ_iMY_*o$^;+kFq`."ZYrp&1A5gtN/O7$U^HffF**e)ODtt6Kkoo=Pi)#@\odO"scL\7FP/HS&$j6'VktqZs`@dkFKtWJ%Aa.POEXD9.gNWJ@3^"RI/j#V9qps'b%buWhH*nZ'@b5ZEaC,#?YO?])=i@t/ej?2%O-2V/.p,o>#CkOF'n>/@fQ)6A_%-f8e,]bK*C;UdipAi+_M^a;<U8_;`C\@*%NKlF'mu.0V[H1(e'XH4b@\*9,%rqi)\/qi"22B#WnEh7E&,Me"K0Pm\?U@P%BK((p:S'QLIp2:\JS7-L^!0m`&Z[ur^e@aQeR`R4rQcj3?jK9?sJPeb]p:X8m^NPp+-ua3b!5=%u<Za7J$HG3'*tZJ2S9MQEh&7nq=&@OLpNnIIj\'nsn_pdDpRtY]]Q%l@:FQh^/[[+ZHH$<3Vb14HsE_JXBM*jNrQ;DOf!m*[dubWcp@.S5"+"99*)(Vc`EQ`>a6"c81cmR+Enr@@8O8_cDX:4OX)&2rmUaNU's+<(JVhn_3V[Gb8HY$ZEglVKF^Y?ZYr1#`<IUg7%e/j;a%7:X_mkrs+gRU+3[+,nJ0YDW'dL'Bl]#9LCmah7V<@I[3R4JQ.G"\^eJJf1b#W#=d?TIKeW-T"=dIJ#0'8+%)GIa+r)A:l>g8mWks@rC3p'F.UrQ;cEQi>kIU:1XN3!K@#[kX6]A7bKWPe9NepeLaDFT-s;`!CPC9Yr?LsTTj<"6h[nRdRQ)9&o7cSkqDSXZ?[!E(QDV;[Dl<[`aEEADfAP0g%Q/GLhVO<(a%UQ:ZZ_*Ic[#Ne.;'<,&G-uAc9L=!l!o]K3U=)eko+%\U>k/m_6?sT>?i"7]o&Or-]1;M+V^h3f;B/b/;+aNWg*GKa:6,*'-$4lTt_;p<bPK\47]>V33aA$:A>hR=_^)$rek@BFGbOLHL!>&nD?#JomHT,DhD'&&/d\S\2pm!_-oJ=X]Z_2ImrDfH;mnPf+Yj:8R3>H6ba8>bk/;/j3#M,;3-XAnN&LrV\HDL>/9K3G#IMW~>endstream
|
||||
Gb!;chf%L6&:WfG)"#4uhEm#38>+C&\(>K)VlNQo2<qmE@doJ6:$gAQ9"TTO9u;rh9'D"n\2uqu*8<:,bkV(T$s\+bl?es#r#.liM?3;kRK;_9I>G&b128tZfP5$V3PicU0aRXYLCG,rFfh.H'>/9?iLr\%Z]-]n2P]Z_bq!jQC!Q6L+!!`G$g1]63.km>;uG11G+;[m6@].[X%2Q<:_$3"QI/JeK+G:V)]C-3;&UcMP)9dN:"FLA:,NU]<!'\2n_G3+n,)2[T3;A-H(Lda:[k<ISfjmSf.+tG3J[&0^;4uP`q?t9X`C-2o\MX>QlY.40FF<m%)(B5"G+1QnBc3g^nY.dit#FF6m+sJq'%)fE<dfXhN\=^=F/t,&SNu_^`@0@)H-KnZIZ]TYd-G0DHh=ca%KVi0['=IWOj>@d*1JJ`o6$N98CP=$u;F+R5868pPl<Ob^94BJ$COdTr)E\EA7+!n4h2pFm;g%p?EI=OP<*sl%"n`>(tP#m!p]d1gT](/Usch1^&;Q]!/;R*>c0K4dRn#.W-6<G?-?+KuAL8YZMm$PinVj;JTJG,P;:*=_DUj<1'HrF5nYh^Jn;Er"Geh$@KdUFHK,A!52YiR2Y\nODVUR;ob\dcuW=Qf/)[,%lP+#.?iWZ%-8_C2NdP,,X3DkhR:''e(u@Tf1ER6;K*\p4\fCF5UQen_U%-&m_8"(=`(t1UD"Epkd[:e8;MKl8[Rr(iBdk;cBS;4)-Zh5)c1!_U5FXaE/;C1l%$M#C'=1[(':=d5>s2nB,J.C6[U</=OYGQPm50q>Dg>.rKqQVU04g-BuXcj,4KNlFMeB3dF<V^C$@WGHpVe=\Ar5&\B)Udhe=?uBd+-c,^)=u9uEbcp0\I2>GAa=9>+0MOu>Rnj'CC:AX?]7`(`-eP$6I?P%"Z..]&`?6_1]ZIjM4?@"FM:foH)N,hCih(M?n?<Hn+*A9-sVWJR8-e5fj<iKklGQD0""&RADh]JpaYPDa7pZZ1hDImTf_8slcE(&*,FXe5oBJc$Jc;UoHpmRht6:&WH;&]lLkEM$jB1e&pUXr12ld;t>W;k;tbXpPfJZ93DIb.@qVOE+!>)OEB4>!>,3LD@As+:rT*aWjj%0'QWiE">.Q-*OGU[/Zkd5qRV/5[^1`kApIURhrI2#$77Y8c~>endstream
|
||||
endobj
|
||||
xref
|
||||
0 25
|
||||
0 23
|
||||
0000000000 65535 f
|
||||
0000000061 00000 n
|
||||
0000000122 00000 n
|
||||
0000000229 00000 n
|
||||
0000000341 00000 n
|
||||
0000000546 00000 n
|
||||
0000000623 00000 n
|
||||
0000000446 00000 n
|
||||
0000000651 00000 n
|
||||
0000000728 00000 n
|
||||
0000000933 00000 n
|
||||
0000001138 00000 n
|
||||
@@ -193,27 +176,25 @@ xref
|
||||
0000001549 00000 n
|
||||
0000001755 00000 n
|
||||
0000001961 00000 n
|
||||
0000002167 00000 n
|
||||
0000002237 00000 n
|
||||
0000002522 00000 n
|
||||
0000002628 00000 n
|
||||
0000004639 00000 n
|
||||
0000006360 00000 n
|
||||
0000008423 00000 n
|
||||
0000010242 00000 n
|
||||
0000012165 00000 n
|
||||
0000014193 00000 n
|
||||
0000016094 00000 n
|
||||
0000002031 00000 n
|
||||
0000002322 00000 n
|
||||
0000002421 00000 n
|
||||
0000004202 00000 n
|
||||
0000006318 00000 n
|
||||
0000008162 00000 n
|
||||
0000010126 00000 n
|
||||
0000012112 00000 n
|
||||
0000014349 00000 n
|
||||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<3aca6d13cd74b57d5c4397c35a55e608><3aca6d13cd74b57d5c4397c35a55e608>]
|
||||
[<1f4d23edf2b4a956040416fb7e0799ac><1f4d23edf2b4a956040416fb7e0799ac>]
|
||||
% ReportLab generated PDF document -- digest (opensource)
|
||||
|
||||
/Info 15 0 R
|
||||
/Root 14 0 R
|
||||
/Size 25
|
||||
/Info 14 0 R
|
||||
/Root 13 0 R
|
||||
/Size 23
|
||||
>>
|
||||
startxref
|
||||
17308
|
||||
15605
|
||||
%%EOF
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
@@ -1,6 +0,0 @@
|
||||
node_modules
|
||||
.next
|
||||
out
|
||||
.DS_Store
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
@@ -1,103 +0,0 @@
|
||||
export default function AboutPage() {
|
||||
return (
|
||||
<div style={{
|
||||
maxWidth: '800px',
|
||||
margin: '0 auto',
|
||||
padding: '40px 20px'
|
||||
}}>
|
||||
<h1 style={{
|
||||
fontSize: '36px',
|
||||
fontWeight: 'bold',
|
||||
marginBottom: '24px',
|
||||
color: '#1a1a1a'
|
||||
}}>Over Ons</h1>
|
||||
|
||||
<p style={{
|
||||
fontSize: '18px',
|
||||
lineHeight: '1.8',
|
||||
color: '#444',
|
||||
marginBottom: '20px'
|
||||
}}>
|
||||
Wij zijn een team van gepassioneerde developers die geloven in de
|
||||
kracht van AI-assisted development. Onze missie is om het bouwen
|
||||
van websites sneller en toegankelijker te maken voor iedereen.
|
||||
</p>
|
||||
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
gap: '20px',
|
||||
marginTop: '40px',
|
||||
flexWrap: 'wrap'
|
||||
}}>
|
||||
<div style={{
|
||||
flex: '1',
|
||||
minWidth: '250px',
|
||||
padding: '24px',
|
||||
backgroundColor: '#f8f9fa',
|
||||
borderRadius: '12px',
|
||||
border: '1px solid #e0e0e0'
|
||||
}}>
|
||||
<h3 style={{
|
||||
fontSize: '20px',
|
||||
fontWeight: '600',
|
||||
marginBottom: '12px',
|
||||
color: '#333'
|
||||
}}>Onze Visie</h3>
|
||||
<p style={{
|
||||
color: '#666',
|
||||
lineHeight: '1.6'
|
||||
}}>
|
||||
AI maakt development niet makkelijker — het maakt het SNELLER.
|
||||
Je moet nog steeds begrijpen wat je bouwt.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div style={{
|
||||
flex: '1',
|
||||
minWidth: '250px',
|
||||
padding: '24px',
|
||||
backgroundColor: '#f8f9fa',
|
||||
borderRadius: '12px',
|
||||
border: '1px solid #e0e0e0'
|
||||
}}>
|
||||
<h3 style={{
|
||||
fontSize: '20px',
|
||||
fontWeight: '600',
|
||||
marginBottom: '12px',
|
||||
color: '#333'
|
||||
}}>Ons Team</h3>
|
||||
<p style={{
|
||||
color: '#666',
|
||||
lineHeight: '1.6'
|
||||
}}>
|
||||
Vier developers, twee designers, en een AI die nooit slaapt.
|
||||
Samen bouwen we de toekomst.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div style={{
|
||||
flex: '1',
|
||||
minWidth: '250px',
|
||||
padding: '24px',
|
||||
backgroundColor: '#f8f9fa',
|
||||
borderRadius: '12px',
|
||||
border: '1px solid #e0e0e0'
|
||||
}}>
|
||||
<h3 style={{
|
||||
fontSize: '20px',
|
||||
fontWeight: '600',
|
||||
marginBottom: '12px',
|
||||
color: '#333'
|
||||
}}>Contact</h3>
|
||||
<p style={{
|
||||
color: '#666',
|
||||
lineHeight: '1.6'
|
||||
}}>
|
||||
Vragen? Neem contact op via ons contactformulier of stuur
|
||||
een mail naar info@debugchallenge.nl.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
|
||||
export default function ContactPage() {
|
||||
const [naam, setNaam] = useState("");
|
||||
const [email, setEmail] = useState("");
|
||||
const [bericht, setBericht] = useState("");
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
alert(`Bedankt ${naam}! Je bericht is verzonden.`);
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
maxWidth: '600px',
|
||||
margin: '0 auto',
|
||||
padding: '40px 20px'
|
||||
}}>
|
||||
<h1 style={{
|
||||
fontSize: '36px',
|
||||
fontWeight: 'bold',
|
||||
marginBottom: '8px',
|
||||
color: '#1a1a1a'
|
||||
}}>Contact</h1>
|
||||
|
||||
<p style={{
|
||||
color: '#666',
|
||||
marginBottom: '32px',
|
||||
fontSize: '16px'
|
||||
}}>Heb je een vraag? Vul het formulier in!</p>
|
||||
|
||||
<form onSubmit={handleSubmit} style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '16px'
|
||||
}}>
|
||||
<div>
|
||||
<label style={{
|
||||
display: 'block',
|
||||
marginBottom: '6px',
|
||||
fontWeight: '500',
|
||||
color: '#333'
|
||||
}}>Naam</label>
|
||||
<input
|
||||
type="text"
|
||||
value={naam}
|
||||
onChange={(e) => setNaam(e.target.value)}
|
||||
required
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: '10px 14px',
|
||||
border: '1px solid #ccc',
|
||||
borderRadius: '8px',
|
||||
fontSize: '16px',
|
||||
outline: 'none'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label style={{
|
||||
display: 'block',
|
||||
marginBottom: '6px',
|
||||
fontWeight: '500',
|
||||
color: '#333'
|
||||
}}>Email</label>
|
||||
<input
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
required
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: '10px 14px',
|
||||
border: '1px solid #ccc',
|
||||
borderRadius: '8px',
|
||||
fontSize: '16px',
|
||||
outline: 'none'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label style={{
|
||||
display: 'block',
|
||||
marginBottom: '6px',
|
||||
fontWeight: '500',
|
||||
color: '#333'
|
||||
}}>Bericht</label>
|
||||
<textarea
|
||||
value={bericht}
|
||||
onChange={(e) => setBericht(e.target.value)}
|
||||
required
|
||||
rows={5}
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: '10px 14px',
|
||||
border: '1px solid #ccc',
|
||||
borderRadius: '8px',
|
||||
fontSize: '16px',
|
||||
outline: 'none',
|
||||
resize: 'vertical'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button type="submit" style={{
|
||||
backgroundColor: '#3b82f6',
|
||||
color: 'white',
|
||||
padding: '12px 24px',
|
||||
border: 'none',
|
||||
borderRadius: '8px',
|
||||
fontSize: '16px',
|
||||
fontWeight: '600',
|
||||
cursor: 'pointer'
|
||||
}}>
|
||||
Verstuur Bericht
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@@ -1,23 +0,0 @@
|
||||
import type { Metadata } from "next";
|
||||
import "./globals.css";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Debug Challenge - Les 3",
|
||||
description: "Fix alle fouten in dit project!",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang="nl">
|
||||
<body className="min-h-screen bg-white text-gray-900">
|
||||
<Navbar />
|
||||
{children}
|
||||
<Footer />
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
import Hero from "@/componenst/Hero";
|
||||
import FeatureCards from "@/components/FeatureCards";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<main>
|
||||
<Hero />
|
||||
<FeatureCards />
|
||||
<TestimonialSection />
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
import { Zap, Shield, Rocket } from "lucide-react"
|
||||
|
||||
interface Feature {
|
||||
icon: React.ReactNode;
|
||||
titel: string;
|
||||
beschrijving: string;
|
||||
}
|
||||
|
||||
const features: Feature[] = [
|
||||
{
|
||||
icon: <Zap size={32} />,
|
||||
titel: "Supersnel",
|
||||
beschrijving: "Bouw componenten in seconden met AI-powered code generation."
|
||||
},
|
||||
{
|
||||
icon: <Shield size={32} />,
|
||||
titel: "Betrouwbaar",
|
||||
beschrijving: "TypeScript en ESLint zorgen voor foutloze, veilige code."
|
||||
},
|
||||
{
|
||||
icon: <Rocket size={32} />,
|
||||
titel: "Deploy Direct",
|
||||
beschrijving: "Push naar GitHub en je site is live op Vercel binnen minuten."
|
||||
}
|
||||
];
|
||||
|
||||
export default function FeatureCards() {
|
||||
return (
|
||||
<section style={{
|
||||
padding: '60px 20px',
|
||||
backgroundColor: '#f9fafb',
|
||||
}}>
|
||||
<div style={{
|
||||
maxWidth: '1000px',
|
||||
margin: '0 auto'
|
||||
}}>
|
||||
<h2 style={{
|
||||
fontSize: '32px',
|
||||
fontWeight: 'bold',
|
||||
textAlign: 'center',
|
||||
marginBottom: '40px',
|
||||
color: '#1a1a1a'
|
||||
}}>Waarom Dit Project?</h2>
|
||||
|
||||
<div style={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(3, 1fr)',
|
||||
gap: '24px'
|
||||
}}>
|
||||
{features.map((feature, index) => (
|
||||
<div key={index} style={{
|
||||
backgroundColor: 'white',
|
||||
padding: '32px',
|
||||
borderRadius: '16px',
|
||||
border: '1px solid #e5e7eb',
|
||||
textAlign: 'center',
|
||||
boxShadow: '0 1px 3px rgba(0,0,0,0.1)'
|
||||
}}>
|
||||
<div style={{
|
||||
display: 'inline-flex',
|
||||
padding: '12px',
|
||||
backgroundColor: '#ede9fe',
|
||||
borderRadius: '12px',
|
||||
marginBottom: '16px',
|
||||
color: '#7c3aed'
|
||||
}}>
|
||||
{feature.icon}
|
||||
</div>
|
||||
<h3 style={{
|
||||
fontSize: '20px',
|
||||
fontWeight: '600',
|
||||
marginBottom: '8px',
|
||||
color: '#1a1a1a'
|
||||
}}>{feature.titel}</h3>
|
||||
<p style={{
|
||||
color: '#6b7280',
|
||||
lineHeight: '1.6'
|
||||
}}>{feature.beschrijving}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
import Link from "next/link"
|
||||
|
||||
export default function Footer() {
|
||||
return (
|
||||
<footer style={{
|
||||
backgroundColor: '#1f2937',
|
||||
color: 'white',
|
||||
padding: '40px 20px',
|
||||
marginTop: '60px'
|
||||
}}>
|
||||
<div style={{
|
||||
maxWidth: '1000px',
|
||||
margin: '0 auto',
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
flexWrap: 'wrap',
|
||||
gap: '32px'
|
||||
}}>
|
||||
<div>
|
||||
<h3 style={{
|
||||
fontSize: '18px',
|
||||
fontWeight: '600',
|
||||
marginBottom: '12px'
|
||||
}}>🚀 Debug Challenge</h3>
|
||||
<p style={{
|
||||
color: '#9ca3af',
|
||||
maxWidth: '300px',
|
||||
lineHeight: '1.6',
|
||||
fontSize: '14px'
|
||||
}}>
|
||||
Een project van NOVI Hogeschool om te leren
|
||||
debuggen met Cursor AI.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 style={{
|
||||
fontSize: '18px',
|
||||
fontWeight: '600',
|
||||
marginBottom: '12px'
|
||||
}}>Links</h3>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '8px'
|
||||
}}>
|
||||
<Link href="/" style={{ color: '#9ca3af', textDecoration: 'none', fontSize: '14px' }}>Home</Link>
|
||||
<Link href="/about" style={{ color: '#9ca3af', textDecoration: 'none', fontSize: '14px' }}>Over Ons</Link>
|
||||
<Link href="/contact" style={{ color: '#9ca3af', textDecoration: 'none', fontSize: '14px' }}>Contact</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 style={{
|
||||
fontSize: '18px',
|
||||
fontWeight: '600',
|
||||
marginBottom: '12px'
|
||||
}}>NOVI Hogeschool</h3>
|
||||
<p style={{
|
||||
color: '#9ca3af',
|
||||
fontSize: '14px',
|
||||
lineHeight: '1.6'
|
||||
}}>
|
||||
AI Development Cursus<br/>
|
||||
Utrecht, Nederland
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{
|
||||
borderTop: '1px solid #374151',
|
||||
marginTop: '32px',
|
||||
paddingTop: '20px',
|
||||
textAlign: 'center',
|
||||
color: '#6b7280',
|
||||
fontSize: '13px'
|
||||
}}>
|
||||
© 2025 Debug Challenge — Les 3 Huiswerk
|
||||
</div>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
import { ArrowRight } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function Hero() {
|
||||
return (
|
||||
<section style={{
|
||||
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
||||
padding: '80px 20px',
|
||||
textAlign: 'center',
|
||||
color: 'white',
|
||||
minHeight: '500px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}}>
|
||||
<div style={{
|
||||
maxWidth: '700px'
|
||||
}}>
|
||||
<h1 style={{
|
||||
fontSize: '48px',
|
||||
fontWeight: 'bold',
|
||||
marginBottom: '16px',
|
||||
lineHeight: '1.2'
|
||||
}}>
|
||||
Bouw Sneller met AI
|
||||
</h1>
|
||||
<p style={{
|
||||
fontSize: '20px',
|
||||
marginBottom: '32px',
|
||||
opacity: '0.9',
|
||||
lineHeight: '1.6'
|
||||
}}>
|
||||
Ontdek hoe je met Cursor en Next.js in minuten een professionele
|
||||
website bouwt. Van idee tot deployment in no-time.
|
||||
</p>
|
||||
<Link href="/about" style={{
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
gap: '8px',
|
||||
backgroundColor: 'white',
|
||||
color: '#764ba2',
|
||||
padding: '14px 28px',
|
||||
borderRadius: '9999px',
|
||||
fontWeight: '600',
|
||||
fontSize: '16px',
|
||||
textDecoration: 'none'
|
||||
}}>
|
||||
Meer Weten <ArrowRight size={18} />
|
||||
</Link>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { useState } from "react";
|
||||
|
||||
export default function Navbar() {
|
||||
const [menuOpen, setMenuOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<nav style={{
|
||||
backgroundColor: 'white',
|
||||
borderBottom: '1px solid #e5e7eb',
|
||||
padding: '0 20px',
|
||||
position: 'sticky',
|
||||
top: '0',
|
||||
zIndex: '50'
|
||||
}}>
|
||||
<div style={{
|
||||
maxWidth: '1200px',
|
||||
margin: '0 auto',
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
height: '64px'
|
||||
}}>
|
||||
<Link href="/" style={{
|
||||
fontSize: '20px',
|
||||
fontWeight: 'bold',
|
||||
color: '#7c3aed',
|
||||
textDecoration: 'none'
|
||||
}}>
|
||||
🚀 Debug Challenge
|
||||
</Link>
|
||||
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
gap: '24px',
|
||||
alignItems: 'center'
|
||||
}}>
|
||||
<Link href="/" style={{
|
||||
color: '#4b5563',
|
||||
textDecoration: 'none',
|
||||
fontWeight: '500'
|
||||
}}>Home</Link>
|
||||
<Link href="/about" style={{
|
||||
color: '#4b5563',
|
||||
textDecoration: 'none',
|
||||
fontWeight: '500'
|
||||
}}>Over Ons</Link>
|
||||
<Link href="/contact" style={{
|
||||
color: '#4b5563',
|
||||
textDecoration: 'none',
|
||||
fontWeight: '500'
|
||||
}}>Contact</Link>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
const testimonials = [
|
||||
{
|
||||
naam: "Lisa de Vries",
|
||||
rol: "Frontend Developer",
|
||||
tekst: "Cursor heeft mijn workflow compleet veranderd. Ik bouw nu in uren wat vroeger dagen kostte.",
|
||||
},
|
||||
{
|
||||
naam: "Mark Jansen",
|
||||
rol: "Student NOVI",
|
||||
tekst: "Eindelijk een tool die écht begrijpt wat ik wil bouwen. De Composer feature is geweldig!",
|
||||
},
|
||||
{
|
||||
naam: "Sophie Bakker",
|
||||
rol: "Full-Stack Developer",
|
||||
tekst: "Van OpenCode naar Cursor was de beste beslissing. Geen token limits meer, gewoon bouwen.",
|
||||
},
|
||||
];
|
||||
|
||||
export default function TestimonialSection() {
|
||||
return (
|
||||
<section style={{
|
||||
padding: '60px 20px',
|
||||
backgroundColor: 'white'
|
||||
}}>
|
||||
<div style={{
|
||||
maxWidth: '1000px',
|
||||
margin: '0 auto'
|
||||
}}>
|
||||
<h2 style={{
|
||||
fontSize: '32px',
|
||||
fontWeight: 'bold',
|
||||
textAlign: 'center',
|
||||
marginBottom: '40px',
|
||||
color: '#1a1a1a'
|
||||
}}>Wat Anderen Zeggen</h2>
|
||||
|
||||
<div style={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(3, 1fr)',
|
||||
gap: '24px'
|
||||
}}>
|
||||
{testimonials.map((t, i) => (
|
||||
<div key={i} style={{
|
||||
padding: '28px',
|
||||
backgroundColor: '#faf5ff',
|
||||
borderRadius: '16px',
|
||||
border: '1px solid #e9d5ff'
|
||||
}}>
|
||||
<p style={{
|
||||
fontStyle: 'italic',
|
||||
color: '#4b5563',
|
||||
marginBottom: '16px',
|
||||
lineHeight: '1.6',
|
||||
fontSize: '15px'
|
||||
}}>"{t.tekst}"</p>
|
||||
<div>
|
||||
<p style={{
|
||||
fontWeight: '600',
|
||||
color: '#1a1a1a',
|
||||
fontSize: '15px'
|
||||
}}>{t.naam}</p>
|
||||
<p style={{
|
||||
color: '#7c3aed',
|
||||
fontSize: '13px'
|
||||
}}>{t.rol}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {};
|
||||
|
||||
export default nextConfig;
|
||||
5671
Les03-Cursor-Basics/les3-debug-challenge/package-lock.json
generated
5671
Les03-Cursor-Basics/les3-debug-challenge/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,27 +0,0 @@
|
||||
{
|
||||
"name": "les3-debug-challenge",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "14.2.5",
|
||||
"react": "^18",
|
||||
"react-dom": "^18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"typescript": "^5",
|
||||
"postcss": "^8",
|
||||
"autoprefixer": "^10",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "14.2.5"
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
/** @type {import('postcss-load-config').Config} */
|
||||
const config = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -1,13 +0,0 @@
|
||||
import type { Config } from "tailwindcss";
|
||||
|
||||
const config: Config = {
|
||||
content: [
|
||||
"./components/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./app/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
export default config;
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"plugins": [{ "name": "next" }],
|
||||
"paths": { "@/*": ["./*"] }
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user