.github/ 0000775 0000000 0000000 00000000000 15172212373 0012421 5 ustar 00root root 0000000 0000000 .github/workflows/ 0000775 0000000 0000000 00000000000 15172212373 0014456 5 ustar 00root root 0000000 0000000 .github/workflows/build.yml 0000664 0000000 0000000 00000001676 15172212373 0016312 0 ustar 00root root 0000000 0000000 # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: build
on:
schedule:
- cron: '0 0 1 * *'
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: ['lts/*']
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- run: npm i -g grunt-cli
- run: npm install
- run: grunt
.gitignore 0000664 0000000 0000000 00000000340 15172212373 0013046 0 ustar 00root root 0000000 0000000 /build
/node_modules
/*.log
.idea/workspace.xml
.idea/tasks.xml
.idea/profiles_settings.xml
.idea/inspectionProfiles/Project_Default.xml
.idea/inspectionProfiles/profiles_settings.xml
node_modules/.yarn-integrity
/release .npmignore 0000664 0000000 0000000 00000000172 15172212373 0013060 0 ustar 00root root 0000000 0000000 /assets
/node_modules
/Gruntfile.js
*.log
/.github
/.vscode
/release
secure/
agents/
.claude/
.codex/
CLAUDE.md
AGENTS.md
Gruntfile.js 0000664 0000000 0000000 00000000423 15172212373 0013355 0 ustar 00root root 0000000 0000000 module.exports = (grunt) => {
const builder = require(`corifeus-builder`);
const loader = new builder.loader(grunt);
loader.js({
replacer: {
type: 'p3x',
},
});
grunt.registerTask('default', builder.config.task.build.js);
}; LICENSE 0000664 0000000 0000000 00000002013 15172212373 0012062 0 ustar 00root root 0000000 0000000 MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. README.md 0000664 0000000 0000000 00000063141 15172212373 0012345 0 ustar 00root root 0000000 0000000 [//]: #@corifeus-header
[](https://www.npmjs.com/package/p3x-html-pdf) [](https://paypal.me/patrikx3) [](https://www.patrikx3.com/en/front/contact) [](https://www.facebook.com/corifeus.software) [](https://network.corifeus.com/status/31ad7a5c194347c33e5445dbaf8)
# 📃 Generates PDF from HTML with custom headers and footers with wkhtmltopdf v2026.4.170
🌌 **Bugs are evident™ - MATRIX️**
🚧 **This project is under active development!**
📢 **We welcome your feedback and contributions.**
### NodeJS LTS is supported
### 🛠️ Built on NodeJs version
```txt
v24.14.1
```
# 📝 Description
[//]: #@corifeus-header:end
**p3x-html-pdf** is a Node.js package that generates PDFs from HTML with custom headers and footers using `wkhtmltopdf`. It is a robust tool for creating professional-grade PDFs with features like:
- 📜 **Dynamic Headers and Footers**: Add placeholders for page numbers, dates, and more.
- 🛠️ **Customizable Layouts**: Configure margins, orientation, and paper size.
- ⚡ **Async/Await Support**: Modern JavaScript compatibility for efficient workflows.
- 🔄 **Dynamic Content**: Render data-driven tables and content dynamically.
---
## 🚀 Installation
Install via Yarn:
```bash
yarn add p3x-html-pdf
```
Or install via npm:
```bash
npm install p3x-html-pdf
```
Import in your project:
```javascript
const { generate } = require('p3x-html-pdf');
```
---
## 📖 Usage Example
```javascript
const { generate } = require('p3x-html-pdf');
const path = require('path');
(async () => {
const outputPath = path.join(process.cwd(), 'p3x-html-pdf-output.pdf');
const options = {
settings: {
save: true,
template: {
format: 'A4',
marginLeft: 10,
marginRight: 10,
fixedWidth: null,
fixedHeight: null,
copies: 1,
orientation: 'portrait',
},
html: `
Invoice Content
This invoice showcases structured content on a single page for detailed clarity.
| Item |
Quantity |
Price |
Total |
${Array.from({ length: 26 }).map((_, i) => {
const price = (i + 1) * 10;
const quantity = (i % 5) + 1;
const total = price * quantity;
return `
| Product ${String.fromCharCode(65 + (i % 26))} |
${quantity} |
$${price}.00 |
$${total}.00 |
`;
}).join('')}
| Subtotal |
$${Array.from({ length: 15 }).reduce((acc, _, i) => acc + ((i + 1) * 10 * ((i % 5) + 1)), 0)}.00 |
| VAT (20%) |
$${(Array.from({ length: 15 }).reduce((acc, _, i) => acc + ((i + 1) * 10 * ((i % 5) + 1)), 0) * 0.2).toFixed(2)} |
| Total |
$${(Array.from({ length: 15 }).reduce((acc, _, i) => acc + ((i + 1) * 10 * ((i % 5) + 1)), 0) * 1.2).toFixed(2)} |
Additional Information
This page provides further details about the invoice, payment methods, and terms. Below is a breakdown of important notes:
- Payments are due within 30 days of receipt.
- Accepted payment methods include credit card, bank transfer, and PayPal.
- Please ensure that all transactions reference the invoice number provided above.
If you have any questions, feel free to contact our support team at support@patrikx3.com.
Thank you for your business! We hope to work with you again in the future. Stay tuned for updates on our services and offerings by visiting our website or subscribing to our newsletter.
`,
},
title: 'P3X-HTML-PDF Detailed Invoice',
debug: false,
saveFile: outputPath,
};
try {
await generate(options);
console.log('✅ PDF generated successfully!');
// or
options.settings.save = false
const buffer = await generate(options);
console.log('--------------------------------------------------------------')
console.log('PDF Buffer:', buffer);
} catch (err) {
console.error('❌ Error generating PDF:', err);
}
})();
```
---
## 🔧 Configuration
### Options
- **Settings**
- `save`: If false, it returns as a buffer.
- `template.format`: Page size, e.g., `A4`, `Letter`.
- `template.orientation`: Page orientation (`portrait` or `landscape`).
- `template.marginLeft`, `template.marginRight`: Margins in mm.
- `template.copies`: Copies to generate.
- `template.fixedWidth` and `template.fixedHeight`: If above zero, generates in millimeters.
- `html`: HTML content with placeholders.
- **title**: PDF document title.
- **saveFile**: Path for saving the PDF.
- **base** The HTML base href is other then current directory, it can be online as well.
- **css**: Customize the CSS for serving, by default it is in `src/html-template.css`
- **jquery**: The latest that works with webkit is jQuery v1.12.4 is required, you can extend with more functions, the default is in `src/jquery-1.12.4.min.js`
- **javascriptDelay**: The delay before the PDF is generated as default is 1000 ms.
For more options, check the official [wkhtmltopdf usage guide](https://wkhtmltopdf.org/usage/wkhtmltopdf.txt).
Unfortunately the version latest HTTPS TLS 1.3 is not working, so it is better to use inline filesystem images or using HTTP as that is dated but still works.
### How to Add a Page Break with `p3x-html-pdf`
To insert a page break, simply use the following snippet:
```html
```
#### ✅ Key Points:
- 🔧 **No additional CSS** is required; the functionality is built-in.
- 📑 The content after this `` will automatically start on a new page.
- 🧹 Ensure your HTML structure is clean for proper rendering.
#### 📝 Example:
```html
📜 This content will be on the first page.
📜 This content will appear on the next page.
```
---
## 🌟 Placeholders
You can use placeholders in your HTML for dynamic data (only these, but it is enough, the rest you can generate in HTML):
- `${page}`: Current page.
- `${pages}`: Total pages.
- `${frompage}`: The starting page of the current section.
- `${topage}`: The ending page of the current section.
- `${webpage}`: The URL of the web page (if applicable).
- `${section}`: The name of the current section.
- `${subsection}`: The name of the current subsection.
- `${date}`: The current date in a localized format.
- `${isodate}`: The current date in ISO 8601 format.
- `${time}`: The current time.
- `${title}`: The document title.
- `${doctitle}`: The title of the document as defined in metadata.
- `${sitepage}`: Current site page number (specific context).
- `${sitepages}`: Total number of site pages (specific context).
### Example
```html
```
The `p3x-footer` and `p3x-header` should not have any styles other than `id` and `data-height`.
---
## 📊 Advanced Features
- **Debugging**: Use `debug: true` to enable detailed logs.
- **Header/Footer Templates**: Create rich HTML templates for headers/footers.
- **Dynamic Content**: Inject dynamic tables, invoices, or other content into the PDF.
---
## 🌟 Headers and Footers in `p3x-html-pdf`
This document provides a detailed explanation of how to work with headers and footers using `p3x-html-pdf`, including first-page-specific headers and indexed headers for subsequent pages. With this approach, you can create professional-grade PDFs with precise control over header and footer content.
---
### 📖 Overview
Headers and footers in `p3x-html-pdf` are managed via HTML templates. You can:
- Define **default headers and footers** for all pages.
- Create **specific headers or footers** for certain pages using indexing (e.g., `p3x-header-1` for the first page).
- Dynamically calculate content for headers and footers, such as page numbers, document titles, or custom logic.
---
### 🚀 How It Works
`p3x-html-pdf` uses the `id` attribute and `data-height` to manage headers and footers. The key attributes and elements are:
- **Header IDs**:
- `p3x-header`: The default header for all pages.
- `p3x-header-
`: A header for a specific page (e.g., `p3x-header-1` for the first page).
- `p3x-header-last`: Last header for last page.
- **Footer IDs**:
- `p3x-footer`: The default footer for all pages.
- `p3x-footer-`: A footer for a specific page.
- `p3x-footer-last`: Last footer for last page.
- **`data-height`**: Specifies the height of the header/footer (in millimeters). Ensure this matches the expected content size to prevent overlap.
---
### 🌟 Example: First Page Header and Default Header
The following example demonstrates a **custom header** for the first page and a **default header** for the rest of the document.
#### HTML Template
```html
```
---
### 🛠️ Dynamic Header and Footer Logic
- Use indexed headers or footers for specific pages.
- Utilize placeholders like `${page}` and `${pages}` to dynamically display the current page and total pages.
#### Example Configuration in JavaScript
```javascript
const options = {
settings: {
save: true,
template: {
format: 'A4',
marginLeft: 10,
marginRight: 10,
orientation: 'portrait',
},
html: `
`,
},
title: 'Dynamic Headers and Footers Example',
saveFile: path.resolve(__dirname, 'output.pdf'),
};
```
---
### 📏 Calculating Headers and Footers per Page
When designing headers and footers:
1. **Estimate Content Size:**
- Use `data-height` to reserve enough space for your header or footer content.
- Example: A header with a logo and text may need `40mm`.
2. **Adjust Margins:**
- Ensure the margins accommodate both the header/footer and the main content.
3. **Testing for Multi-Page Documents:**
- For multi-page documents, validate the alignment of headers and footers across all pages.
---
#### 📄 Headers and Footers with Indexed Customization
`p3x-html-pdf` supports indexed headers and footers, allowing unique designs for specific pages. For example, `p3x-header-1` can define a header for the first page, while `p3x-header` applies to subsequent pages. Similarly, `p3x-footer-1` can be used for a custom first-page footer.
##### Key Points:
1. **Indexed IDs**: Use `p3x-header-1`, `p3x-footer-1`, etc., for specific pages. Default headers (`p3x-header`) and footers (`p3x-footer`) are used when no specific index is found and there is `p3x-header-last` or `p3x-footer-last`.
2. **Consistent Heights**: All headers and footers must share the same `data-height` (e.g., `40mm` for headers, `10mm` for footers) to ensure proper alignment and accurate page calculations.
3. **Dynamic Content**: Use placeholders like `${page}` and `${pages}` to display page-specific data dynamically.
This approach allows tailored styling for specific pages while maintaining consistent layouts throughout the document.
---
### 📊 Advanced Features
- Combine **indexed headers/footers** for specific pages with a **default** fallback.
- Use JavaScript in the `header-footer.html` template to dynamically adjust content.
- Use indexed configurations to simulate "first-page" or "last-page" behavior.
---
### 🖼️ Example Output
You can generate a PDF with the provided configuration to see how headers and footers are applied dynamically. For larger documents, this approach allows consistent styling with room for customization.
## 🌍 Architecture
`p3x-html-pdf` works seamlessly on Linux, Windows and ARM64.
---
## 🖼️ Example Output
Check out an example output PDF:
[Example PDF](https://cdn.corifeus.com/git/html-pdf/assets/p3x-html-pdf-output.pdf).

---
## 🔬 Legacy Rendering with Webkit
This library uses `wkhtmltopdf`, which relies on an older version of Webkit. As such, it does not support modern CSS features like `flexbox`. Instead, older solutions such as `float` and `table`-based layouts must be used for alignment. While these approaches are not modern, they are efficient and compatible with the rendering engine.
For instance, the following layout works seamlessly:
```html
```
## Steps to Clone and Run `test/test.js`
1. **Clone the Repository**:
```bash
git clone https://github.com/patrikx3/html-pdf.git
cd html-pdf
```
2. **Install Dependencies**:
Using Yarn:
```bash
yarn install
```
Or, using NPM:
```bash
npm install
```
3. **Run the Test Script**:
```bash
node ./test/test.js
```
---
## Puppeteer vs. p3x-html-pdf: Resource Usage and Features Comparison
When deciding between **Puppeteer** and **p3x-html-pdf**, it's essential to understand their differences in resource usage and capabilities.
### Technology Difference
- **p3x-html-pdf** is built on **wkhtmltopdf**, which uses the WebKit rendering engine. It's lightweight and optimized for HTML-to-PDF tasks.
- **Puppeteer** launches a full **Chrome/Chromium** instance, consuming more CPU and memory, even in headless mode.
### Resource Usage Comparison
| Feature | p3x-html-pdf (wkhtmltopdf) | Puppeteer (Chrome/Chromium) |
|------------------------|---------------------------------------------|------------------------------------------|
| **Memory Usage** | Low | High |
| **CPU Usage** | Low | High |
| **Startup Time** | Fast | Slower due to browser launch |
| **Dynamic Content** | Limited support for JavaScript | Full support for JavaScript |
| **Rendering Accuracy** | Basic CSS and HTML support | Pixel-perfect rendering with modern web standards |
| **Flexibility** | Headers, footers, scripts (older JS versions) | Highly customizable (headers, footers, scripts) |
| **Scalability** | Suitable for lightweight tasks and servers | Better for advanced use cases and large-scale rendering |
| **File Size** | Smaller binary for wkhtmltopdf dependency | Puppeteer requires downloading Chromium (~100MB) |
### Trade-offs
#### p3x-html-pdf (wkhtmltopdf)
- **Pros:**
- Lightweight and uses fewer resources.
- Faster startup time.
- Ideal for static HTML content with minimal JavaScript or CSS.
- **Cons:**
- Limited support for modern web standards and advanced JavaScript.
- Basic rendering capabilities.
#### Puppeteer
- **Pros:**
- Full support for dynamic content, advanced JavaScript, and modern web standards.
- Highly customizable headers, footers, and PDF options.
- Pixel-perfect rendering accuracy.
- **Cons:**
- Consumes more CPU and memory.
- Slower startup time due to launching a full Chrome/Chromium instance.
### When to Use Each
#### Use p3x-html-pdf (wkhtmltopdf):
- When your content is **static** or doesn’t rely on modern web technologies.
- When resource efficiency is a priority (e.g., on resource-constrained servers).
#### Use Puppeteer:
- When your content is **dynamic** or relies heavily on JavaScript and CSS.
- When rendering accuracy, modern web technology support, or customization is critical.
### Conclusion
- **p3x-html-pdf** (wkhtmltopdf) is a better fit for lightweight tasks with simple requirements.
- **Puppeteer** excels in advanced and dynamic use cases but comes with higher resource costs.
---
**Happy PDF Generating!** 🎉
[//]: #@corifeus-footer
---
# Corifeus Network
AI-powered network & email toolkit — free, no signup.
**Web** · [network.corifeus.com](https://network.corifeus.com) **MCP** · [`npm i -g p3x-network-mcp`](https://www.npmjs.com/package/p3x-network-mcp)
- **AI Network Assistant** — ask in plain language, get a full domain health report
- **Network Audit** — DNS, SSL, security headers, DNSBL, BGP, IPv6, geolocation in one call
- **Diagnostics** — DNS lookup & global propagation, WHOIS, reverse DNS, HTTP check, my-IP
- **Mail Tester** — live SPF/DKIM/DMARC + spam score + AI fix suggestions, results emailed (localized)
- **Monitoring** — TCP / HTTP / Ping with alerts and public status pages
- **MCP server** — 17 tools exposed to Claude Code, Codex, Cursor, any MCP client
- **Install** — `claude mcp add p3x-network -- npx p3x-network-mcp`
- **Try** — *"audit example.com"*, *"why do my emails land in spam? test me@example.com"*
- **Source** — [patrikx3/network](https://github.com/patrikx3/network) · [patrikx3/network-mcp](https://github.com/patrikx3/network-mcp)
- **Contact** — [patrikx3.com](https://www.patrikx3.com/en/front/contact) · [donate](https://paypal.me/patrikx3)
---
## ❤️ Support Our Open-Source Project
If you appreciate our work, consider ⭐ starring this repository or 💰 making a donation to support server maintenance and ongoing development. Your support means the world to us—thank you!
---
### 🌍 About My Domains
All my domains, including [patrikx3.com](https://patrikx3.com), [corifeus.eu](https://corifeus.eu), and [corifeus.com](https://corifeus.com), are developed in my spare time. While you may encounter minor errors, the sites are generally stable and fully functional.
---
### 📈 Versioning Policy
**Version Structure:** We follow a **Major.Minor.Patch** versioning scheme:
- **Major:** 📅 Corresponds to the current year.
- **Minor:** 🌓 Set as 4 for releases from January to June, and 10 for July to December.
- **Patch:** 🔧 Incremental, updated with each build.
**🚨 Important Changes:** Any breaking changes are prominently noted in the readme to keep you informed.
[**P3X-HTML-PDF**](https://corifeus.com/html-pdf) Build v2026.4.170
[](https://www.npmjs.com/package/p3x-html-pdf) [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=QZVM4V6HVZJW6) [](https://www.patrikx3.com/en/front/contact) [](https://www.facebook.com/corifeus.software)
[//]: #@corifeus-footer:end
assets/ 0000775 0000000 0000000 00000000000 15172212373 0012363 5 ustar 00root root 0000000 0000000 assets/p3x-html-pdf-output.pdf 0000664 0000000 0000000 00000072367 15172212373 0016656 0 ustar 00root root 0000000 0000000 %PDF-1.4
1 0 obj
<<
/Title ( P 3 X - H T M L - P D F D e t a i l e d I n v o i c e 1 / 1 9 / 2 0 2 5 , 1 2 : 4 3 : 2 4 A M)
/Creator ( w k h t m l t o p d f 0 . 1 2 . 4)
/Producer ( Q t 4 . 8 . 7)
/CreationDate (D:20250119004325+01'00')
>>
endobj
3 0 obj
<<
/Type /ExtGState
/SA true
/SM 0.02
/ca 1.0
/CA 1.0
/AIS false
/SMask /None>>
endobj
4 0 obj
[/Pattern /DeviceRGB]
endobj
8 0 obj
[0 /XYZ 28.5000000
728.750000 0]
endobj
9 0 obj
<<
/Type /XObject
/Subtype /Image
/Width 256
/Height 256
/BitsPerComponent 8
/ColorSpace /DeviceGray
/Length 10 0 R
/Filter /FlateDecode
>>
stream
xG]sJ&$$I$$L2$$d2GLL2L$I2III$$ɕ\ۗs=_uy+)*ld7a+@l[&l g%`z25:"<;a@1[_2Țc@ցDe>ցÃl3[
/>V?tg[
Yswcl-Tqg3y{;~lD8Ni>V47z&{^]bq'J,(z%m"=;zQ6؊O1lEN<bkrG+59H^}ևA%cr8 [cogmتřg}V!jU`rc/N0GxE=*V%?^leJo\Y6-kg9@݁,lqItBϰ }[puz-O0)uܳ+醜=[`_!ïGs-P(_u3P(eS
r-Q )8Y[@rWy0F<;-RA@ Had|g[0w k{aNse
"Y
[ ObD1.P=V*{Ɔ
E2xYsY-U c@**?N XhɬWhɬWhȬWhGZ2
Z2
`X1*ʇXEtf B*9lŶYCТȱwC#dͬl#U>rMƎ0
-ThYN懟Jf\Jf@;lPˬRhYCB5
Fzf(r[ȬkȬnoL{acK*
-2|[G3
[e3 aNfA6|X/NfSVܳms?-ٗB7'$w~fP'
r^w*)_s2F3Y-st^f R,ӫj0ш<nff)3t9 j\̪Evz]w ȬZlƝ#APf:]x!VΫjQ
riZmqQ0Y!Z-yHI%ن:xqȫEQWrb(42[$KoYASy{"<0Ɗ m1?Omaw6Lbȫd܀ u
?Vk;TJtȐWI3}VvS+ 7pKV:gȸ Dэ`wݖ赉RG[l6{=B_Zl [(B9ox R0݇(;kuք-R ϝRlyɵQ >GJ7q֣c&h9M ߥ,MкَG}->v_6`L$JtP/Rl$9UlV'mT{Bj:ڋƨyLjweGвڎ*[y|aU1aL|I6
RtTY'O_*xԗHQeF:RhWwSŽUW/wG!-h1I|ȫ$~*0uq$:d'Qf">*0q4:*0S/JGF2U`(騂hC^Q5t:(-uTA)|SꨂhQ&Rc0C^%F)X%ƒVGFZU`'QтXGە:X먂sScI
b>*0a:\쨂n Q7Jʂ$;Ŏ*0UPwf; Ѣ >Z
endstream
endobj
10 0 obj
2381
endobj
11 0 obj
<<
/Type /XObject
/Subtype /Image
/Width 256
/Height 256
/BitsPerComponent 8
/ColorSpace /DeviceRGB
/SMask 9 0 R
/Length 12 0 R
/Filter /FlateDecode
>>
stream
xn8s
3,w/q(9MҤAIy@Aʐ (̫ROP f5>0~x>1ZoLؚéJ?vt]絍֝ږ~Gnnp>`76Cy˱Wl1&:u1=1OxR.vyc֥`u>ϴϞpp99k/욓8-3v{;~:m_I6Ɵ~vK{3O~x_V6]lߎ_.)F7Ɵ.< gGYR?1CoK?)8vd#"2{gҏJ)qik;"1<;"Yť;g* Ġ|kS,/پ]#uұ/ݫ?hKuƟ@$=n)&Cϣoy~z>ϥNbv+_GhaJҟ NGM~hq2vɯ |w?qZrUCDy|1?"En1ݞMoN~qhwW5~8^}y~" m@bKV}nj۟|'dҏ<<Mo4@}r:V7'm!ԋ(ً9<AaCȰEKot8/tmBJD/iWbP#C>"jEd!ANs-"$ؽ!u[u
Ǥu`$#K#cpk-.uC=|]y3~TԽrͰeNo@_{1~(?9y%-P29tgGO(mE fS_4<$y|-=(HxN'Ɵv};8&Fݯ
!fB)אe1sӢ,T/aY؟R}ߗ~\oE_ܞD'lx8xS,l->Zf8'G_pHƿԭ8;Kx/!yڬ]5o3M\瀌!lA1ٿX#.>lNS "[Kϛ[w"7Xl2?t8vPM15ǣ
Vr~&
ϑL/oy+v:ϣ
r~HW/@rVQ;`n>ﴉXUސT-kdǠВux>(Pؿ5+[{^F:vo5]ו-*+{ҟV"ҿ.Xwi-ni](4ΩzsBP&krVҹ1L"EԚ^Ť]C@._V!
rmJa@zH EvFX|I7=hu~J)FX|bz|TNΑx܋5Nt+Jd'ILNQvƕ){+*
;UTS&;s1N_8EjMgH=q6rY.m{t?^ ՙjOJrWOJr¤|ad
ARʗBѨi{q=u#-eFl7HrA /60]T(t]'N2i#8m=Omk<sڛ~ۅ-ZWi9)glC4&Qv؇a+UŵW"z6o\m*}6؎CigkH3j
-A.6'P'p<~t(B: ARٮ
(DF
?b.egK;E$J1.#e$DA(G̞Ɩ?5xBY
gSz`.\Z;Xócdbv8!Ԁpn,Nu 7y|)dlߘՐ^/jǏҟ`*?}ނ}%ZlVolG&MӱukEnPZ[ڢF6%=P%2k5<UrܫDW2俗Яr_x8 _.kMr
TLXGvk S76z6{:RU#[T2g%K:
c\QnyXOw-r--ܞS]8!㇠ .8sB+8m|&n<Qp-Kx>F٠)/ᇶxh)^?)~qgxa*r hY6k6_F}.4K0wNl~h)ȼqg}( 0hzqDFR7M
,@>Nc<7z's"1~kOݩK?8՞to`'\/`.- >+x>S=[2qBTok0Fqî9M
tP)r834lC$L`]t3.lK;Q`o}װͭ
+N} {/oqs&'T~ۅ=T:LIxᇝ>f]"z6x
{>S1gS`~a,=kNr
^J?&D}|q>}>%9?Գ3ᔤzk'd&5sa$H^Y Y\5QG|bo1~$.Ta1
endstream
endobj
12 0 obj
3873
endobj
5 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 13 0 R
/Resources 15 0 R
/Annots 16 0 R
/MediaBox [0 0 595 842]
>>
endobj
15 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
/Im11 11 0 R
>>
>>
endobj
16 0 obj
[ ]
endobj
13 0 obj
<<
/Length 14 0 R
/Filter /FlateDecode
>>
stream
xQo6FW@&"EJXq@ }(P$-$>H4;If>#tl>Ǜ_Q=}]l*U7wv_/ÿ/tx?}=z7?tC/C|u+;87U[ﻟ>ntb[MY/m];cj`qSaTAz^+jE)
.K|uJArP{Ä8Ei=5d*1OBz0"ixNj^0F!HZz6y,)p\"Џ!^MYaQ) 4Q Y,r|c3TAO~q!)"` O(]8Y@dg0,(fCSE,IAPڰJ?PYa"bpD4t55h%j'"*P[cCSGW.QS.pAO]DMMa>ut55 (n* ˧08Y@dFg0,b,fH
j[CE&+ LDCW.QS.pA\z"ձuK?P9a>ut55ѕKԄ\SGW.QSIAPFuK?P9Y>1* ˧08Y@dcf0KDR'1lTA\&\0
]DMMa"rꉈ
f c떾,r|rt55%jj.ѕK@DR'UlTAOaq!)"`P9Y>X e
[CE&+ LDCW.QS.pA\z"غ0]DMMa>9rp|rt55 *n* ˧08Y@dFg0,b,fH
j-[CE&+ LDKW.QS.pA\z"غ0]DMMa>9rp|rt55 )n* + + + OβuK?PYa"ZrpDt55h%j'"*P[!ѕKԄ\擣+ 'GW.QSIAPNuK?P9Y>1* ˧08Y@dcf0KDR'lTA\&\0-]DMMa"Zrꉈ
f c떾,r|rt55%jj.ѕK@DR'Tٺ,fCSE,r|H3%")lTA\&\0-]DMMa"Zrꉈ
f T-}X@ӕKԄ\SOW.QS.pAO=]DM
D$m0BZ[TwlPA#CR0C\|䣁IEKgjY_}0Yoc#"=%b}xzݾST3~
[7?JW??T?2hڵUJoU³[?TW}_k퇝;픶uHܢӦiKo1>Viţu'ؽr67aKi=tWoӼ
W̦lj4a6YMnoM#wqͦf?|#o}\_|VlA'
ţ݈G#{ ;*EujVߊG&t˘y}O-ߋm=u-Q"Zr,=tli|4yno.J[x
g
ՈmaL(u([-Dye'Z GZעoʊmk\?+U8^QpQYpY"ԎY= нtݑN&v8cW]Nhqy|iU77*I{]:^{]