@mahe_pkm/buzl-html-editor 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/HANDBOOK.md +37 -3
- package/README.md +6 -5
- package/dist/public/public-live-edit.css +82 -7
- package/dist/public/public-live-edit.js +30 -11
- package/dist/server.js +41 -15
- package/docs/Buzl-HTML-Editor-Handbook-Advanced.pdf +232 -0
- package/package.json +1 -1
package/HANDBOOK.md
CHANGED
|
@@ -121,13 +121,13 @@ Press `Ctrl+C` in the same terminal window to stop the server.
|
|
|
121
121
|
## Edit text from the normal website preview
|
|
122
122
|
|
|
123
123
|
1. Open the normal preview URL, such as `http://localhost:4000/`.
|
|
124
|
-
2.
|
|
125
|
-
3.
|
|
124
|
+
2. Select the small floating pencil button in the lower-right corner.
|
|
125
|
+
3. In the compact Buzl menu, select **Edit Text**.
|
|
126
126
|
4. Click highlighted text, type your change, and inspect the result.
|
|
127
127
|
5. Select **Undo** to reverse the latest edit, or **Cancel** to discard all unsaved edits.
|
|
128
128
|
6. Select **Save** only when the page is correct.
|
|
129
129
|
|
|
130
|
-
The toolbar is available only from `buzl-editor` while it is bound to your local machine. Simply opening the preview or turning on Edit Text does not write the toolbar into your website files. Saving writes only the approved page content and creates a recoverable backup under `.buzl/backups/`.
|
|
130
|
+
The pencil opens a compact vertical menu containing Edit Text, Save, Undo, Cancel, and Advanced Editor. The toolbar is available only from `buzl-editor` while it is bound to your local machine. Simply opening the preview or turning on Edit Text does not write the toolbar into your website files. Saving writes only the approved page content and creates a recoverable backup under `.buzl/backups/`.
|
|
131
131
|
|
|
132
132
|
Use the advanced editor when you need image upload, optimization, page controls, or richer editing tools.
|
|
133
133
|
|
|
@@ -223,6 +223,40 @@ npm update -g @mahe_pkm/buzl-html-editor
|
|
|
223
223
|
|
|
224
224
|
Back up the website, run `doctor`, start the editor, and test the website preview and `/admin/` after every update.
|
|
225
225
|
|
|
226
|
+
## Advanced users: global AI API keys
|
|
227
|
+
|
|
228
|
+
Buzl's normal Live Edit and image optimization do not need an AI key. AI text and AI image actions can use an Anthropic or OpenRouter key.
|
|
229
|
+
|
|
230
|
+
To make a key available to every website you run with the global `buzl-editor` command, store it as an operating-system environment variable. Do not place a key in HTML, browser JavaScript, Git, or a deployed website.
|
|
231
|
+
|
|
232
|
+
### Windows PowerShell
|
|
233
|
+
|
|
234
|
+
```powershell
|
|
235
|
+
setx ANTHROPIC_API_KEY "your_anthropic_key"
|
|
236
|
+
setx OPENROUTER_API_KEY "your_openrouter_key"
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Close PowerShell completely and open a new window before starting Buzl. `setx` stores the value for your Windows user account, so treat the computer account as sensitive.
|
|
240
|
+
|
|
241
|
+
### macOS and Linux
|
|
242
|
+
|
|
243
|
+
Add the required key to your shell profile. Use `~/.zshrc` for the usual macOS shell or `~/.bashrc` for Bash:
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
export ANTHROPIC_API_KEY="your_anthropic_key"
|
|
247
|
+
export OPENROUTER_API_KEY="your_openrouter_key"
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Reload the relevant profile before starting Buzl:
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
source ~/.zshrc
|
|
254
|
+
# or
|
|
255
|
+
source ~/.bashrc
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Global operating-system variables take priority over a website's `.env` file. Use a website-root `.env` only when a specific client requires a separate key. Keep `.env` out of Git and hosting uploads.
|
|
259
|
+
|
|
226
260
|
## Safety checklist before deployment
|
|
227
261
|
|
|
228
262
|
- Confirm every changed page in a browser.
|
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ is started; the editor's own files stay inside the npm package.
|
|
|
10
10
|
## Documentation
|
|
11
11
|
|
|
12
12
|
- Full setup handbook: [HANDBOOK.md](./HANDBOOK.md)
|
|
13
|
-
- Printable handbook: [docs/Buzl-HTML-Editor-Handbook.pdf](./docs/Buzl-HTML-Editor-Handbook.pdf)
|
|
13
|
+
- Printable handbook: [docs/Buzl-HTML-Editor-Handbook-Advanced.pdf](./docs/Buzl-HTML-Editor-Handbook-Advanced.pdf)
|
|
14
14
|
|
|
15
15
|
## Requirements
|
|
16
16
|
|
|
@@ -37,10 +37,11 @@ Default addresses:
|
|
|
37
37
|
- Website with a floating **Edit Text** toolbar: `http://localhost:4000/`
|
|
38
38
|
- Advanced editor: `http://localhost:4000/admin/`
|
|
39
39
|
|
|
40
|
-
`buzl-editor` opens the website preview by default. Select
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
`buzl-editor` opens the website preview by default. Select the small floating
|
|
41
|
+
**pencil** button to open the Buzl menu, then select **Edit Text** to edit
|
|
42
|
+
visible text directly on any page. Use **Save**, **Undo**, or **Cancel** from
|
|
43
|
+
the compact menu. The toolbar is injected only while the local editor server is
|
|
44
|
+
running and is never added to the saved website.
|
|
44
45
|
|
|
45
46
|
Open the advanced editor by default when needed:
|
|
46
47
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
}
|
|
4
4
|
|
|
5
5
|
.buzl-toolbar {
|
|
6
|
-
align-items:
|
|
6
|
+
align-items: flex-end;
|
|
7
7
|
background: #211717;
|
|
8
8
|
border: 1px solid rgba(212, 175, 55, 0.55);
|
|
9
9
|
border-radius: 14px;
|
|
@@ -11,16 +11,71 @@
|
|
|
11
11
|
box-shadow: 0 14px 42px rgba(0, 0, 0, 0.35);
|
|
12
12
|
color: #f8f4eb;
|
|
13
13
|
display: flex;
|
|
14
|
-
flex-
|
|
14
|
+
flex-direction: column-reverse;
|
|
15
15
|
font: 600 13px/1.2 Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
16
|
-
gap:
|
|
16
|
+
gap: 0;
|
|
17
17
|
max-width: calc(100vw - 32px);
|
|
18
|
-
padding:
|
|
18
|
+
padding: 7px;
|
|
19
19
|
position: fixed;
|
|
20
20
|
right: 18px;
|
|
21
|
+
transition: width 210ms ease;
|
|
22
|
+
width: 56px;
|
|
21
23
|
z-index: 2147483647;
|
|
22
24
|
}
|
|
23
25
|
|
|
26
|
+
.buzl-toolbar[data-expanded="true"] {
|
|
27
|
+
width: min(242px, calc(100vw - 32px));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.buzl-toolbar .buzl-launcher {
|
|
31
|
+
align-items: center;
|
|
32
|
+
background: #d4af37;
|
|
33
|
+
border-color: #d4af37;
|
|
34
|
+
color: #211717;
|
|
35
|
+
font-size: 22px;
|
|
36
|
+
font-weight: 700;
|
|
37
|
+
height: 42px;
|
|
38
|
+
justify-content: center;
|
|
39
|
+
min-height: 42px;
|
|
40
|
+
padding: 0;
|
|
41
|
+
transition: background 160ms ease, color 160ms ease, transform 180ms ease;
|
|
42
|
+
width: 42px;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.buzl-toolbar .buzl-launcher:hover {
|
|
46
|
+
background: #ebca5b;
|
|
47
|
+
color: #211717;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.buzl-toolbar[data-expanded="true"] .buzl-launcher {
|
|
51
|
+
transform: rotate(-12deg);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.buzl-toolbar .buzl-menu {
|
|
55
|
+
align-items: stretch;
|
|
56
|
+
box-sizing: border-box;
|
|
57
|
+
display: flex;
|
|
58
|
+
flex-direction: column;
|
|
59
|
+
flex-wrap: nowrap;
|
|
60
|
+
gap: 8px;
|
|
61
|
+
max-height: 0;
|
|
62
|
+
opacity: 0;
|
|
63
|
+
overflow: hidden;
|
|
64
|
+
pointer-events: none;
|
|
65
|
+
transform: translateY(8px) scale(0.98);
|
|
66
|
+
transform-origin: bottom right;
|
|
67
|
+
transition: max-height 210ms ease, opacity 170ms ease, padding-top 210ms ease, transform 210ms ease;
|
|
68
|
+
width: 100%;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.buzl-toolbar[data-expanded="true"] .buzl-menu {
|
|
72
|
+
max-height: 300px;
|
|
73
|
+
opacity: 1;
|
|
74
|
+
padding-top: 8px;
|
|
75
|
+
pointer-events: auto;
|
|
76
|
+
transform: translateY(0) scale(1);
|
|
77
|
+
}
|
|
78
|
+
|
|
24
79
|
.buzl-toolbar button,
|
|
25
80
|
.buzl-toolbar a {
|
|
26
81
|
align-items: center;
|
|
@@ -37,6 +92,12 @@
|
|
|
37
92
|
text-decoration: none;
|
|
38
93
|
}
|
|
39
94
|
|
|
95
|
+
.buzl-toolbar .buzl-menu button,
|
|
96
|
+
.buzl-toolbar .buzl-menu a {
|
|
97
|
+
justify-content: center;
|
|
98
|
+
width: 100%;
|
|
99
|
+
}
|
|
100
|
+
|
|
40
101
|
.buzl-toolbar button:hover,
|
|
41
102
|
.buzl-toolbar a:hover {
|
|
42
103
|
border-color: #d4af37;
|
|
@@ -68,11 +129,14 @@
|
|
|
68
129
|
.buzl-toolbar .buzl-status {
|
|
69
130
|
color: #d9d0c7;
|
|
70
131
|
font-weight: 500;
|
|
71
|
-
|
|
132
|
+
box-sizing: border-box;
|
|
133
|
+
max-width: none;
|
|
72
134
|
overflow: hidden;
|
|
73
135
|
padding: 0 5px;
|
|
74
136
|
text-overflow: ellipsis;
|
|
75
|
-
|
|
137
|
+
text-align: center;
|
|
138
|
+
white-space: normal;
|
|
139
|
+
width: 100%;
|
|
76
140
|
}
|
|
77
141
|
|
|
78
142
|
.buzl-toolbar .buzl-status[data-tone="success"] {
|
|
@@ -90,10 +154,15 @@
|
|
|
90
154
|
@media (max-width: 680px) {
|
|
91
155
|
.buzl-toolbar {
|
|
92
156
|
bottom: 10px;
|
|
93
|
-
left:
|
|
157
|
+
left: auto;
|
|
94
158
|
right: 10px;
|
|
95
159
|
}
|
|
96
160
|
|
|
161
|
+
.buzl-toolbar[data-expanded="true"] {
|
|
162
|
+
left: 10px;
|
|
163
|
+
width: min(242px, calc(100vw - 20px));
|
|
164
|
+
}
|
|
165
|
+
|
|
97
166
|
.buzl-toolbar .buzl-status {
|
|
98
167
|
flex: 1 1 100%;
|
|
99
168
|
max-width: none;
|
|
@@ -112,3 +181,9 @@ body.buzl-public-editing [data-buzl-public-edit="true"]:focus {
|
|
|
112
181
|
outline-style: solid !important;
|
|
113
182
|
}
|
|
114
183
|
|
|
184
|
+
@media (prefers-reduced-motion: reduce) {
|
|
185
|
+
.buzl-toolbar .buzl-launcher,
|
|
186
|
+
.buzl-toolbar .buzl-menu {
|
|
187
|
+
transition: none;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
const histories = new Map();
|
|
13
13
|
const dirtyKeys = new Set();
|
|
14
14
|
let editMode = false;
|
|
15
|
+
let menuOpen = false;
|
|
15
16
|
let activeKey = null;
|
|
16
17
|
let lastChangedKey = null;
|
|
17
18
|
let saving = false;
|
|
@@ -29,17 +30,21 @@
|
|
|
29
30
|
toolbar.setAttribute('role', 'toolbar');
|
|
30
31
|
toolbar.setAttribute('aria-label', 'Buzl page editor');
|
|
31
32
|
toolbar.innerHTML = `
|
|
32
|
-
<
|
|
33
|
-
<
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
<button class="buzl-launcher" type="button" data-menu-toggle aria-label="Open Buzl editor" title="Open Buzl editor" aria-expanded="false" aria-controls="buzl-editor-menu"><span aria-hidden="true">✎</span></button>
|
|
34
|
+
<div class="buzl-menu" id="buzl-editor-menu" data-menu>
|
|
35
|
+
<span class="buzl-status" data-status title="${escapeAttribute(pagePath)}">Ready to edit this page</span>
|
|
36
|
+
<button class="buzl-primary" type="button" data-toggle aria-pressed="false">Edit Text</button>
|
|
37
|
+
<button type="button" data-save disabled>Save</button>
|
|
38
|
+
<button type="button" data-undo disabled>Undo</button>
|
|
39
|
+
<button type="button" data-cancel disabled>Cancel</button>
|
|
40
|
+
<a href="/admin/" data-advanced>Advanced Editor</a>
|
|
41
|
+
</div>
|
|
38
42
|
`;
|
|
39
43
|
shadow.appendChild(toolbar);
|
|
40
44
|
document.documentElement.appendChild(host);
|
|
41
45
|
|
|
42
46
|
const toggleButton = shadow.querySelector('[data-toggle]');
|
|
47
|
+
const menuButton = shadow.querySelector('[data-menu-toggle]');
|
|
43
48
|
const saveButton = shadow.querySelector('[data-save]');
|
|
44
49
|
const undoButton = shadow.querySelector('[data-undo]');
|
|
45
50
|
const cancelButton = shadow.querySelector('[data-cancel]');
|
|
@@ -91,6 +96,11 @@
|
|
|
91
96
|
const changed = changedElements();
|
|
92
97
|
const dirty = changed.length > 0;
|
|
93
98
|
toggleButton.textContent = editMode ? 'Editing On' : 'Edit Text';
|
|
99
|
+
const keepMenuOpen = menuOpen || editMode || dirty;
|
|
100
|
+
toolbar.dataset.expanded = String(keepMenuOpen);
|
|
101
|
+
menuButton.setAttribute('aria-expanded', String(keepMenuOpen));
|
|
102
|
+
menuButton.setAttribute('aria-label', editMode ? 'Buzl editing menu' : 'Open Buzl editor');
|
|
103
|
+
menuButton.title = editMode ? 'Buzl editing menu' : 'Open Buzl editor';
|
|
94
104
|
toggleButton.setAttribute('aria-pressed', String(editMode));
|
|
95
105
|
saveButton.disabled = !dirty || saving;
|
|
96
106
|
cancelButton.disabled = !dirty || saving;
|
|
@@ -100,6 +110,12 @@
|
|
|
100
110
|
if (!dirty && !saving) setStatus(editMode ? 'Click highlighted text to edit' : 'Ready to edit this page');
|
|
101
111
|
}
|
|
102
112
|
|
|
113
|
+
function setMenuOpen(nextOpen) {
|
|
114
|
+
if (!nextOpen && (editMode || changedElements().length)) return;
|
|
115
|
+
menuOpen = Boolean(nextOpen);
|
|
116
|
+
updateControls();
|
|
117
|
+
}
|
|
118
|
+
|
|
103
119
|
function setEditMode(nextMode) {
|
|
104
120
|
editMode = Boolean(nextMode);
|
|
105
121
|
document.body.classList.toggle('buzl-public-editing', editMode);
|
|
@@ -114,7 +130,6 @@
|
|
|
114
130
|
element.removeAttribute('data-buzl-public-edit');
|
|
115
131
|
}
|
|
116
132
|
}
|
|
117
|
-
sessionStorage.setItem('buzl-live-edit-enabled', editMode ? '1' : '0');
|
|
118
133
|
updateControls();
|
|
119
134
|
}
|
|
120
135
|
|
|
@@ -183,7 +198,11 @@
|
|
|
183
198
|
}
|
|
184
199
|
}
|
|
185
200
|
|
|
186
|
-
|
|
201
|
+
menuButton.addEventListener('click', () => setMenuOpen(!menuOpen));
|
|
202
|
+
toggleButton.addEventListener('click', () => {
|
|
203
|
+
menuOpen = true;
|
|
204
|
+
setEditMode(!editMode);
|
|
205
|
+
});
|
|
187
206
|
saveButton.addEventListener('click', saveChanges);
|
|
188
207
|
cancelButton.addEventListener('click', () => {
|
|
189
208
|
if (!changedElements().length || window.confirm('Discard all unsaved text changes on this page?')) {
|
|
@@ -242,7 +261,7 @@
|
|
|
242
261
|
if (!editMode) return;
|
|
243
262
|
const editable = event.target.closest && event.target.closest('[data-buzl-public-edit="true"]');
|
|
244
263
|
if (!editable) return;
|
|
245
|
-
if (
|
|
264
|
+
if (event.target.closest && event.target.closest('a, button, summary')) event.preventDefault();
|
|
246
265
|
event.stopPropagation();
|
|
247
266
|
}, true);
|
|
248
267
|
|
|
@@ -254,6 +273,7 @@
|
|
|
254
273
|
if (editMode && event.key === 'Escape' && document.activeElement) {
|
|
255
274
|
document.activeElement.blur();
|
|
256
275
|
}
|
|
276
|
+
if (!editMode && event.key === 'Escape') setMenuOpen(false);
|
|
257
277
|
}, true);
|
|
258
278
|
|
|
259
279
|
window.addEventListener('beforeunload', (event) => {
|
|
@@ -262,6 +282,5 @@
|
|
|
262
282
|
event.returnValue = '';
|
|
263
283
|
});
|
|
264
284
|
|
|
265
|
-
|
|
266
|
-
else updateControls();
|
|
285
|
+
updateControls();
|
|
267
286
|
})();
|
package/dist/server.js
CHANGED
|
@@ -26,9 +26,12 @@ const SITE_ROOT = path.resolve(process.env.BUZL_SITE_ROOT || process.cwd());
|
|
|
26
26
|
|
|
27
27
|
const PUBLIC_LIVE_EDIT_ENABLED = new Set(['127.0.0.1', 'localhost', '::1'])
|
|
28
28
|
.has(String(HOST).toLowerCase());
|
|
29
|
-
const
|
|
30
|
-
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', '
|
|
31
|
-
'
|
|
29
|
+
const PUBLIC_BLOCK_EDIT_SELECTOR = [
|
|
30
|
+
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'li', 'figcaption', 'blockquote',
|
|
31
|
+
'cite', 'label',
|
|
32
|
+
].join(',');
|
|
33
|
+
const PUBLIC_STANDALONE_EDIT_SELECTOR = [
|
|
34
|
+
'span', 'a', 'small', 'strong', 'em',
|
|
32
35
|
].join(',');
|
|
33
36
|
const PUBLIC_EDIT_SESSION_TTL_MS = 2 * 60 * 60 * 1000;
|
|
34
37
|
const publicEditSessions = new Map();
|
|
@@ -958,20 +961,36 @@ function removePublicEditArtifacts($) {
|
|
|
958
961
|
}
|
|
959
962
|
|
|
960
963
|
function collectPublicEditCandidates($) {
|
|
961
|
-
const
|
|
962
|
-
$(PUBLIC_EDIT_SELECTOR).each((_, element) => {
|
|
964
|
+
const isSafeTextTarget = (element) => {
|
|
963
965
|
const target = $(element);
|
|
964
966
|
const text = target.text();
|
|
965
|
-
if (!text || !text.trim()) return;
|
|
966
|
-
if (target.closest('svg, [aria-hidden="true"], script, style, noscript, input, textarea, select').length) {
|
|
967
|
-
return;
|
|
967
|
+
if (!text || !text.trim()) return false;
|
|
968
|
+
if (target.closest('svg, [aria-hidden="true"], script, style, noscript, input, textarea, select, iframe, canvas').length) {
|
|
969
|
+
return false;
|
|
968
970
|
}
|
|
971
|
+
return !target.find('input, textarea, select, button, summary, iframe, canvas, video, audio, [contenteditable="true"]').length;
|
|
972
|
+
};
|
|
969
973
|
|
|
970
|
-
|
|
974
|
+
const rawBlockCandidates = [];
|
|
975
|
+
$(PUBLIC_BLOCK_EDIT_SELECTOR).each((_, element) => {
|
|
976
|
+
if (isSafeTextTarget(element)) rawBlockCandidates.push(element);
|
|
977
|
+
});
|
|
978
|
+
// Prefer the innermost semantic block. This avoids overlapping edit targets
|
|
979
|
+
// for nested list items or a paragraph inside a blockquote.
|
|
980
|
+
const rawBlockSet = new Set(rawBlockCandidates);
|
|
981
|
+
const blockCandidates = rawBlockCandidates.filter((element) => !$(element).find('*').toArray()
|
|
982
|
+
.some((descendant) => rawBlockSet.has(descendant)));
|
|
983
|
+
const blockSet = new Set(blockCandidates);
|
|
984
|
+
const standaloneCandidates = [];
|
|
985
|
+
$(PUBLIC_STANDALONE_EDIT_SELECTOR).each((_, element) => {
|
|
986
|
+
if (!isSafeTextTarget(element)) return;
|
|
987
|
+
const target = $(element);
|
|
988
|
+
if (target.parents().toArray().some((parent) => blockSet.has(parent))) return;
|
|
989
|
+
standaloneCandidates.push(element);
|
|
971
990
|
});
|
|
972
|
-
const
|
|
973
|
-
return
|
|
974
|
-
.some((descendant) =>
|
|
991
|
+
const standaloneSet = new Set(standaloneCandidates);
|
|
992
|
+
return [...blockCandidates, ...standaloneCandidates.filter((element) => !$(element).find('*').toArray()
|
|
993
|
+
.some((descendant) => standaloneSet.has(descendant)))];
|
|
975
994
|
}
|
|
976
995
|
|
|
977
996
|
function sanitizePublicEditHtml(value) {
|
|
@@ -984,15 +1003,22 @@ function sanitizePublicEditHtml(value) {
|
|
|
984
1003
|
root.find('script, style, iframe, object, embed, form, input, textarea, select, option, button, link, meta')
|
|
985
1004
|
.remove();
|
|
986
1005
|
|
|
987
|
-
const allowedTags = new Set(['br', 'strong', 'b', 'em', 'i', 'u', 's', 'sub', 'sup', 'span']);
|
|
1006
|
+
const allowedTags = new Set(['br', 'strong', 'b', 'em', 'i', 'u', 's', 'sub', 'sup', 'span', 'a']);
|
|
988
1007
|
root.find('*').toArray().reverse().forEach((element) => {
|
|
989
1008
|
const tagName = String(element.tagName || element.name || '').toLowerCase();
|
|
990
1009
|
if (!allowedTags.has(tagName)) {
|
|
991
1010
|
fragment(element).replaceWith(fragment(element).text());
|
|
992
1011
|
return;
|
|
993
1012
|
}
|
|
994
|
-
for (const attribute of Object.
|
|
995
|
-
|
|
1013
|
+
for (const [attribute, rawValue] of Object.entries(element.attribs || {})) {
|
|
1014
|
+
const name = attribute.toLowerCase();
|
|
1015
|
+
if (tagName === 'a' && ['href', 'target', 'rel'].includes(name)) {
|
|
1016
|
+
if (name === 'href' && /^(?:javascript|data|vbscript):/i.test(String(rawValue).trim())) {
|
|
1017
|
+
fragment(element).removeAttr(attribute);
|
|
1018
|
+
}
|
|
1019
|
+
} else {
|
|
1020
|
+
fragment(element).removeAttr(attribute);
|
|
1021
|
+
}
|
|
996
1022
|
}
|
|
997
1023
|
});
|
|
998
1024
|
return root.html() || '';
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
%PDF-1.4
|
|
2
|
+
%���� ReportLab Generated PDF document (opensource)
|
|
3
|
+
1 0 obj
|
|
4
|
+
<<
|
|
5
|
+
/F1 2 0 R /F2 3 0 R /F3 4 0 R
|
|
6
|
+
>>
|
|
7
|
+
endobj
|
|
8
|
+
2 0 obj
|
|
9
|
+
<<
|
|
10
|
+
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
|
11
|
+
>>
|
|
12
|
+
endobj
|
|
13
|
+
3 0 obj
|
|
14
|
+
<<
|
|
15
|
+
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
|
|
16
|
+
>>
|
|
17
|
+
endobj
|
|
18
|
+
4 0 obj
|
|
19
|
+
<<
|
|
20
|
+
/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font
|
|
21
|
+
>>
|
|
22
|
+
endobj
|
|
23
|
+
5 0 obj
|
|
24
|
+
<<
|
|
25
|
+
/Contents 17 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 16 0 R /Resources <<
|
|
26
|
+
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
|
27
|
+
>> /Rotate 0 /Trans <<
|
|
28
|
+
|
|
29
|
+
>>
|
|
30
|
+
/Type /Page
|
|
31
|
+
>>
|
|
32
|
+
endobj
|
|
33
|
+
6 0 obj
|
|
34
|
+
<<
|
|
35
|
+
/Contents 18 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 16 0 R /Resources <<
|
|
36
|
+
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
|
37
|
+
>> /Rotate 0 /Trans <<
|
|
38
|
+
|
|
39
|
+
>>
|
|
40
|
+
/Type /Page
|
|
41
|
+
>>
|
|
42
|
+
endobj
|
|
43
|
+
7 0 obj
|
|
44
|
+
<<
|
|
45
|
+
/Contents 19 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 16 0 R /Resources <<
|
|
46
|
+
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
|
47
|
+
>> /Rotate 0 /Trans <<
|
|
48
|
+
|
|
49
|
+
>>
|
|
50
|
+
/Type /Page
|
|
51
|
+
>>
|
|
52
|
+
endobj
|
|
53
|
+
8 0 obj
|
|
54
|
+
<<
|
|
55
|
+
/Contents 20 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 16 0 R /Resources <<
|
|
56
|
+
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
|
57
|
+
>> /Rotate 0 /Trans <<
|
|
58
|
+
|
|
59
|
+
>>
|
|
60
|
+
/Type /Page
|
|
61
|
+
>>
|
|
62
|
+
endobj
|
|
63
|
+
9 0 obj
|
|
64
|
+
<<
|
|
65
|
+
/Contents 21 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 16 0 R /Resources <<
|
|
66
|
+
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
|
67
|
+
>> /Rotate 0 /Trans <<
|
|
68
|
+
|
|
69
|
+
>>
|
|
70
|
+
/Type /Page
|
|
71
|
+
>>
|
|
72
|
+
endobj
|
|
73
|
+
10 0 obj
|
|
74
|
+
<<
|
|
75
|
+
/Contents 22 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 16 0 R /Resources <<
|
|
76
|
+
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
|
77
|
+
>> /Rotate 0 /Trans <<
|
|
78
|
+
|
|
79
|
+
>>
|
|
80
|
+
/Type /Page
|
|
81
|
+
>>
|
|
82
|
+
endobj
|
|
83
|
+
11 0 obj
|
|
84
|
+
<<
|
|
85
|
+
/Contents 23 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 16 0 R /Resources <<
|
|
86
|
+
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
|
87
|
+
>> /Rotate 0 /Trans <<
|
|
88
|
+
|
|
89
|
+
>>
|
|
90
|
+
/Type /Page
|
|
91
|
+
>>
|
|
92
|
+
endobj
|
|
93
|
+
12 0 obj
|
|
94
|
+
<<
|
|
95
|
+
/Contents 24 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 16 0 R /Resources <<
|
|
96
|
+
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
|
97
|
+
>> /Rotate 0 /Trans <<
|
|
98
|
+
|
|
99
|
+
>>
|
|
100
|
+
/Type /Page
|
|
101
|
+
>>
|
|
102
|
+
endobj
|
|
103
|
+
13 0 obj
|
|
104
|
+
<<
|
|
105
|
+
/Contents 25 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 16 0 R /Resources <<
|
|
106
|
+
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
|
107
|
+
>> /Rotate 0 /Trans <<
|
|
108
|
+
|
|
109
|
+
>>
|
|
110
|
+
/Type /Page
|
|
111
|
+
>>
|
|
112
|
+
endobj
|
|
113
|
+
14 0 obj
|
|
114
|
+
<<
|
|
115
|
+
/PageMode /UseNone /Pages 16 0 R /Type /Catalog
|
|
116
|
+
>>
|
|
117
|
+
endobj
|
|
118
|
+
15 0 obj
|
|
119
|
+
<<
|
|
120
|
+
/Author (anonymous) /CreationDate (D:20260906210347+05'00') /Creator (anonymous) /Keywords () /ModDate (D:20260906210347+05'00') /Producer (ReportLab PDF Library - \(opensource\))
|
|
121
|
+
/Subject (unspecified) /Title (Buzl HTML Editor Handbook) /Trapped /False
|
|
122
|
+
>>
|
|
123
|
+
endobj
|
|
124
|
+
16 0 obj
|
|
125
|
+
<<
|
|
126
|
+
/Count 9 /Kids [ 5 0 R 6 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
|
|
127
|
+
>>
|
|
128
|
+
endobj
|
|
129
|
+
17 0 obj
|
|
130
|
+
<<
|
|
131
|
+
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1029
|
|
132
|
+
>>
|
|
133
|
+
stream
|
|
134
|
+
Gatm9gJ6Kg&:O:Sb[ZRpZEs;m>G+qa"]@3IWVRAM")``iKbT3iO72F]I0g3K67!84=jNZqQfAARV[pfI`@\l6%L4'f:dBI5W0i27'TVdDE?hR5^sFLQ%5?3)X6ZjIQaPF==Dbi&ABoH*WtMT/kb<5q-t"M*.#HBpGVM!,?*Ye_]'[h6;Tqb,_4Y:o:4gM#V.GPK:5V_Z6.j'KB6"AODXeHEG@mph>Zl^ia_^L8T!->;4#:)3g[u:akR!u[2Gt2U9+[Jt67^sc"J#bXRQ;$4_^R&P.N*i0V6;'VSlptT7e[o5ihI/sJu-&geqbI-E<f2-D@kL`d:@&A5;%J3/\Ig:*GXV.a>bY=&91[.B-JdZc7t/KF0O(N%ENJHc/HY9e$kG=J:'"<P2,9M6V/;ke8?DhGRsEq5GO<c[9g"BNCTc2nRhIlEk2*.!+Xl)lU\bpa`9Y!%0B<$V*94U.Q=fDFVe0t"ZiFT1Gkm:cC*cl--*I"fPhXdMjeX$"E[1(UuDJVk7f)#c<FhJ.RIkGUJPQ\($qN7kUd]+V:U<@aU`/=ZC@eMkEeMM]oSn\1q%aL".AM&5KQFkaUq3Ao&Iirs%[WmTK'e8.c7rhcY]],nS4%H`<\*>l`.,2e[qk^<S$c\,@(8Ojs@*q:t9dUfj[h/fDG&Q<Sgg=6aTDt:m/c<+o?8@g(Pen.#+DG<<5sh&*;nY[4Ymm/-u9<%?'8G.Np(N=L8@n?P4/h6up_@QIp#9i6mi8D&6/(\m"@lRA'><5l24k_Lu,pW&We^V#afb8J!JD#jQ*&Jl@=:JjJ!$\7cT+?fhqZ$7YI5%J?]rmuV4_VH(p"qrD,,Tr_pqLH^dFO!,U+:\Q$)NaY!JqK_XCFL33aVqV2O6oN@6UR)R<R\lCHn4LJMg_Old^Rs%Ffr/Up@8Z^BDXiaBXtgfQNe;fV=PR?W9=%"J+_uCn!_:bmc15cN??+7$rZ=W]A2hVHITt>A<%ea5"X;::mT3FG"#r=@0V2#>rW&IJNlI'$H?+K)D86>.?hWjJ!<~>endstream
|
|
135
|
+
endobj
|
|
136
|
+
18 0 obj
|
|
137
|
+
<<
|
|
138
|
+
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1580
|
|
139
|
+
>>
|
|
140
|
+
stream
|
|
141
|
+
Gatn&gMRrh&;KZJ.H[oF)O?0;kq[FHe::a*p'*s4Var=b'59CjjJFC&n=;_(4-Jqg%Vu4_3F32FcLBR+.?O2&qS.pt^f^t.^/:O[PUfQY&B[Y5Q%b;pHaFo[6SBGc4j:CE770^27M.rq@&"Ij>6e$C[Y!%f69'm#C(SeXL^HOHecj[-lo3B)K^EuI6BAb+5L_(i*<bU2kN)o^;Zb6VDm$6UnCuJTR(^3^^PD@^PV9Uj,b0<2ce<K$[286sa56.(n]cNsh8=-EWn(OE9AuY05*0U0l)2k#NAY\RQ4?YR9RmT!$&;I.C^i=W0U`Ih5o<DVU,-9q/?[2-B9!Mfd^iM%p?qZJpo42eZ9RL%28DEVQWN@R0&`[T<F235YHtR)MfK#?hd*mdERE3t9G37nf$Gi*%?GeLqa5A.3XfX=<ChPrpsEk23`^[MQ$k4EoUd,olh^n3mf-V2C>3W6IojJLlM[mB=0QPr4hU,UX*21X[]jG7rOd%5jqd5o=oBZ7p7&HLPX[kYKVVhL-t-l#DqtjSX9Rk-SMu6k1E8.(emrj=7Z(?WjeOq-2jC$q)8$k/=VR&OprQOA73se4K#r9paa'&2/;mhFR]Qr+_?IhNa;cDYE)@aA[-hS%ip7n^M2`=j?.&0[']!_c<t*Lg[3G6qS5M_%ilEK1G'[KsD9e<u[*&e_^AP=kmcq6+8qL#%9i/.c"=;e:B<@1,V"$9--r1M0Gaomu`sGA(+[Kh^&sQ)2*$X-V85PI+,\U/IIH32hnM;L_#F;#YRtpSK`r,H^4F29@j0c:)IQU_u+#CVU/C+h6@i\=Q*+l89$HpL"nK^?MT)rPU&[?]/9[6"GSgB%0Y"iMp"A'1?`@IF>3CL;aT:[ZK4j6C7a[\N.MaPY5j"K/aTL*:^:N>]4`/8Za;H4CQa%l/L9tC]Pns/GfeWQ>jSCVjnQdtgd.D1fNnhQ,e=.<pFRjM(;Dd:Jn0"R5eQW#4-C\C#Yp/JXQ9$XY-rNrkMgi+t1?.`GQ4J1M2MiZ@nr,H(^X%h.2GC6Ik.D=e;$meN.RYNgh7a!IW3YNTY5VK3^$Vg;^C/MZ;].X>`#IK0-o&f/07Cs^o96uUkN2k@XF[X^b),M2*1jFUS[P>_+/X(c5*[6>P:CtFC\hI>N7SMer@M1\1&l0'3-=dUKD:g)!-2!(*`M8LY9IpZ\M&6H7&4<I\#Dcf1)2:8F&BcC%.Bi-Y_(`gS]0jO#-;Rs]4@Ulk3^ma7fD83tTk>K1Yqu8q`%\D>Iblu`H9:b0\KQ<+b0]+ShZ\/ZGO>?TRJK%sjMAK36G(rQ%Es%.C;9WHlHT78U<gf=rXa(&hp<_<`"NKHZ1<RVCh'h`gXP@iHUsWGV]?r'GY/p_^PB1iQ:J;n92Ac`9seIF15Eq/ltOY+HJ5[adDp>U(5K)hc,@\;PQ$@rV'dnDR*h3n*E-Z(NO.6.2JR=DBes1,30,H@ZDlHR1MtA%2pc.\A&:>YD,N+B[aglbS+d)=)RD*dWNDY&k09\k@c7.4Qf/>(?+V-i+2;J$:7M(":<hO>%p]42O8%2)V6BL@ZJKf_^uhk'f2R"lKcE*$rWUG$Mp)~>endstream
|
|
142
|
+
endobj
|
|
143
|
+
19 0 obj
|
|
144
|
+
<<
|
|
145
|
+
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1714
|
|
146
|
+
>>
|
|
147
|
+
stream
|
|
148
|
+
Gatm;gMYe)&:NH>R)_+8).#b;I;,32klM>mfJ3g+V,4O&HWt2q89.T5rV-jKnZl?1NDk0)06o+o*7!Lt7gpepf_E'p!)@T[q3D'AODf\A+sB1+Z[>2T`jJc2==,oMJFI:0?*Et3<(flCYm-FmKPQj(jj7#3IBauaP*U,2<cKW-&AqIZ1:M9t`k`3DAtt%*g$fMg-71N&1n0*[%=H2&]NnlLjsU!$r>Ak3j]B3E&,@</^MjRC3IYFN/mMqi8bQP&Xa,l<hY0B7f5Q'1V+s>iD)81$neQ*FphdN;!\W?gc7t&-ci@s'g,@5k\6KW^EL.Gscr_sVZujhjRH\G7p-E#TO,Qi;IQN=WoCr$uRs"_h!oS!Io+/$3S\o%<.UTrF?dDJ#fD-;s]3;s091`'91m+l0AWq]P/^gASfcR5Pib$ofb^t_)^lP(>3A;CFcI?>Ma1m:j?W:Uk1t@%RD17"@;Ld?-*=OkAP]pD7m0EDkII)/F"arJL6WGs^f2k,Bq[,Me?,(1LjH(bgBHS#8*(0DOFSad<>q$7d2Uc>?8r@>t!NQgULpC-uJ-CY5%*pGi1'3n=O-H]$)')(ibVI%t(<#-3pu%`q8'6siT@GH+87k6kaX!NQ&sb&9:o_RhbW*NHHV2<>l=T/5C)A"9XHteDTSJ@A#=2^JDO%P4nZh,l@k`2&nG]j&_Od:i`M`!3;gj7iRc:4@rV"S"j[W;IjCW)jPA7ECg?pC.139Oja&3@0(8]r*TcocC)G5=WTp/1ZA[^+8,Emk2Q>#J*R08aG_F[*jC!ps4*+FRa-0&XfOIK4e^L3:?;@)sN%8W'Wq88T@UuDCaPmgcn[aO_C-DgBt9IcJV_=U&@AaMg]J;c7;=d1@#1'o@mKVM4l;E`:cJP:&ZanY[B;MI=ee#"]5IPS6+j+W5SK,'h*2%-6H-:3Rb%ZmYdOpI>pLkU.JN@11K">KaU-unT$,r/rc4VE>sl%=<i!@]&20Z,<'=GDM;OA#_u,iL.NTJQuj(saqrSru-ZTcUsBpFGT@'W8Z_j34/@XMVE"0PurWR*U[PaWd5qpQ(Zi"NkC_4,sDi2e.GQ7N$kj<6(pofHMU6OCRA'VHcd'ZXpbek]kr*BYuYbB38l6FCOTND8ENQ9S/?)Gb>_NgCh9hdldZX=(*X8ocFUA4Ih6TT"2Ac@m@6a@GA37fNIu=UMJV8^f=`mo9F)].Vpp/Vs_KG/]E/@`HJ2kcUG>-%sec0*';dB@\YH("c!D69.(2_Br`qW+CMIX[/A9Z_O;^)a`uE*9_!hSUs]X+"_;^WQplc681"@KP&PMFTN"]CIc.H?Vkaf0kqFQl`*j:&Eo8Y9h`fhF?>5`9$P<._XEA$8,n?-o*]d!ckh@eO%L\A.jO^86^WBn^,X1/4kqFP[lEK*K/*bq,m&5hZp"UUP9ZLD@?,/A3^5'"pM?/(tB%QdhrO)CJI_35+l\Y^Ip`BO/h6ct$^)c\Ho!U0n$LZZ\DL;s=:UnXP'usXUin/$G/A4Nt_JAMJ3trPsns[?`qp9,'L_jA*aQU#cMd?dQ9EN?^iT)k^G)(XRNtM)MeDVpkL2XVZf0i(=]dEXb""k2Ujh[E55j5/Ner:D?]I'F8oU6?=_-n=s(*LZ=Y>)QVPLkI]*:^t6gjf'e;"F+93UXlc^WD.I**eXU_.9FGl1$5RL=oo;VVh&XMq8d#(>%b%GBMjRgC:Lb;d7*'+#ENZRf~>endstream
|
|
149
|
+
endobj
|
|
150
|
+
20 0 obj
|
|
151
|
+
<<
|
|
152
|
+
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1651
|
|
153
|
+
>>
|
|
154
|
+
stream
|
|
155
|
+
Gatn&gMRrh&;KZJ.H[oFC79q:Eg]!N;,[Ql%+n/[oM1_(YmMK[8TrOV&)SOS8^;)<joF.d]c;mHTC_Xf7g^O?Wq^eP!]ZafnZN:aL?U9<'F<0/QqT"RC[KK#:c1::K@&G!ql*cJ</4d:NGlUY/$uW?GR`CCDI6D<[cjOliN;gP5W$X79c[ic`ABEg`mpm3rG(tVl@iXUNNBbQdhVdk"MD9iIsUfsneTM(hOL+Re`?;qalUi&r<oL+_JGB2^EpWQ+h`&nIPSTX\tm)g=Ms=qHFMP90O*F"HaD@C[Oet.^6YpqD4%OLqVPsr%:$WB6;TSh^^=bq>nq%[KW@]^9q1i!N2,r@%58KWCNNhkr0%JqNnR5mrco!g:#FD]hO[Fp/cks*<.jGWo^!%b0fcp.Rnhnta0W5g/m;GA8RerK&WJQkE"Csn:K>L$VV=bI6K0-XZcAe9XCC^bIBNA;8hU+nI^\(MB&1=E1S67-f5;\b/_k6PYeOs^^"KP:Rd@TB[Z?@?F0mC/4M,m/XljQl9FPL\NrpQi"=c0&F_<G!hTBT3lX%Q1Z=pi:k1Gi+[BQ7fQXe_,\u*qLPq2s6]!ona&o1`DQ""&+9sUE;pEh1^&lN6]7AeJ<_FE%7@3K.fOY&PrO@`Wq;6MtBaEqCBoBNIclo'_r44VM5dLag#M%A9G6gS:.0"l+LFrFPS)8*]`!nRt_/<@eQIE`qcN#bMFmSJe+6>L`%ON+Om.)uf@*]euITgL9W3L!"WTbKhZ&D;Z+6V12=:p2kAaEqCB0BeL8Sok=!Np\jE,V!H@__%?Q*-9;h;j[r]A%CgSiQs1BgrM'O874/ri0O'8^o\T5DWO`8.u0347(-KF.na&h,943np;EP0c7ReLs)Vsshl`#P2ljodgXYq>`N+p"!H4L:[^XE\1:p6[Boh%%'ZS^+@_(dfk]fbH!f\8UA]A[l;[X[bN1A[48tI<ha?5:&,K_3a=&cmR6C&29K$g_P.GC%%pGpBf=<3Q1cX31-MHUjtAZArS28k3Xe?9/>4=N2eW<qb@j:`4kA$oj@>*c_h3NEZ8AV<u[6(TE/aXT(dH-m<5MUGb4FWP^LfHMa^:Yc]_Q_U^B.]le\VS9573,BmDnjj)Q^-6WtI"/KoA\QSX;(BsN)N'bA]oZd_>S&6$\)6)X5!G"?`nb79IuR@Kj4nPA2Xkn#RI(gV:G<s=@+p(__g\pp?I+@CL0$ZIBQ^;l24u^5-=+]O0Z1MS*eG@^*Mh:S_MiD&KOME99$HQ&_U,jr_K$n7Q:HY5*(#r&fn,?j/8<dsoRO0O-WZ"@,RdDl#Xd=fJ1sZ(42U/6qEr,?LcEOu_m?<[@As-d0[tg2r*0NNTqEgYj][.i0Jn^jrK;i-@JBZ@YXs:H`2H?(-H+pBe:I>'fKBf95u#-FYdRZY5.)!+SbS4<bXaNZ9U[\FdMsGXRfgUY\3i*\*[,-oPo_,=BD2D2*/TL5;*cagO<m<'@#(-/*F`'>Eo]Bg3d`/]oJMpXAnj=obbVEF1rY]_#Dn]c,*;BNn8'sLbb,t#AkW4a58V7Y-n%]/\^hihbTI#(]Hgt+@`eOf([d4k>p3DXc1B+6Al@4lQ9)X3!#-u-e->@?rWO?VD:Z!_SjH'e0=98G5JN,@h:ui$h6%df"kA+mW9C,~>endstream
|
|
156
|
+
endobj
|
|
157
|
+
21 0 obj
|
|
158
|
+
<<
|
|
159
|
+
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1570
|
|
160
|
+
>>
|
|
161
|
+
stream
|
|
162
|
+
Gatn&hf%7-&BE]$=5;h:C^PY38Z?WFl?*+iF@_W3fUJVVYua@L,c+e)rUDsI(.m1.Q53&BKKT(u^-(5,UcC.*jmI&0&+I/\Zem`]!Q>7&V?k-Z<^i0,/IX+"\OOInUgfeeG=bH1#4j[pndJL#;IPfE>X2Z6k!bGJKfKg.k"=^U+jIOFRC8\>R=Hhg/fRI&+WET&#@XPS@sSJggqupT_Om0qpD9k@YeG@sK%6?Kib'\=L>mp[,jFq?@LHm;$^9jG6Q77:kgf'<KX(MhKW^#K>JoY#B%W)c'L"CbAgX9A8@of:T*_JB>e[$i:ct/^4j\MQ)UPR:X!Es^QCL;l%2FpRJ@9R)8i'HiIoN0S:>P7%^Xhn$n]0?8q;!@4^B!SDkHEHU<P0e6cJc\+p!lL9K"'>JDcX,VVFW%j`PXc*aeb-i)fXIPX-"%J[$H=OVA=`tfbB4Wgm+M4Dj?rdq!o5#nP.Jtj0$(JZ0RjJZA3J8YKMBFh=O1*mW74ag@+I<,?.t+eie*opS@3Qqm(M.Pq=fW4:<&$IJmk]Ino#MAX\&VFfTr:<3ogJTr("LP]?Zhr9k:F&#Jg)-;fSu<#UD62hP]nbuc#+%W,Jt_58o>RVeLi\LjuqY4Wc^QJa?[($T?FKmYnckY2lt`$f&Z?mM_>Ad?;1(h$-9*NEY>=N\D7@r4Q>CW*c$G,>E8:9FliPae0W.l0=8(I,&8.pB0uUfm2pA+]'R9UaIM`kf8Y*hps?.e-)CP>sI:``an)ZJusZ1Y:'9CfQ3J0WHt8csckLBK=plUYp=c)!utEp2pau#*+oFcX&tidYUOj3Z_'A+t2@;#.l<FoIAk$n%'+60A!tSn5*tq*+1jgqj1r.md[_)`g=a`4'OD(F">8%!4;:>WL=JpS=e4dgL?U`Rtj=M]qe4+EC,jEm"?]soFXeIj$tqOMkeD?!_qO);*^'Q3h!],8!@":a7*l%lL731P\(M%<7N9hb"1FaIN3%l-=Y!l\hT+V;G&QU;A^8Dj$8ee=[fZ8XS%?^;C^sWnXMEb*?G)[F]2?d\/R\!2h:';8g+_EcC8,4&[le72>.lfDl5*Ug!\g%^36SX>s$X)#S6geEid%=Hm3PX7!W!)Pdbol:l6Pr.'jS]0[hC;@4mRr_V?+CjXlK@579l)'1N!W9'D*%P+$)3(.<j67<Ni!;.t&>'P=j#$FAO^^)mTS]SX/g^34=76knp68JLI*W?2A>]ZDXlI:KBD6kmXB?MU*ZTo&2<QgSC9U"n/BQfl<okM(O3F$8#lh;3=Zl2'Y7,%:bf*H''oXp-YQQYf_]mWmJBnB_[,-_bMT_!n^`8tnGab1e,A]IeL9^hejm$ob>>&/1sDZ0W;X/s!9s1<,3p'<GdZ7KG59kcg6/eqoOK6]A7HW")VA9'.>;MCt,dXI'=p0QhutCpNQS^,5O\*EFpo9<=oqYki@Tb+#KHff.LY6WhG]C4:P*XCR@=5t/I[?\[q3Yj5KXk@\C"c?BA_XD=:Y:i8c!WjQVt4WTaSq\bO)0CS0??GT?=I=0\bDLeaj97*Br[(#\to]G+JF#H0%(,nQNrWB-sRLT~>endstream
|
|
163
|
+
endobj
|
|
164
|
+
22 0 obj
|
|
165
|
+
<<
|
|
166
|
+
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1557
|
|
167
|
+
>>
|
|
168
|
+
stream
|
|
169
|
+
Gatn&>u0K?'Sc)J/'d8E#T8-3nKfm)<m**.%C=L>Kf%.-D,N4l1opHBHgEStqgk&!D5C^6`33MiqlpS4MI5Lpb9arL%]<A:(l/#$Qm<=8)n=**6;t%`!l@j7BaTM(p%;83?rJWdaYK'215^%Q;D9*A'g-q:8?/JZ*/IJI8-U>L.a:lGdWNPQ,Kf[K$/bB0&(nmh9Hg1q+J(7F(Id9IrW_9V3lrb!?:00gHSbU8np_e^@[j*9r!%-nX>\ZU4fGJ?&)-b`"oZ)c@eNt^AMo*T<qkuB;CC1o<+e/r@7Ps"1G4oB]5((Bb)$OmJE%YjJ@,PS'-]CGf`2U&PD:$;2Kc8r4_2>J[)fd6GCKSd%K)Ol0b"$S%c@T-c0`L'%8?B"Hu]7;?(Oh>q'B;':VL/TVPunOBNB$5:^SPVLhFNrIOIXBB>[h0/nhgBr9g<3#W%fqVV]K[54R=@>u_?((:.T.SAO##/)T(tBI]O-F^<:n26;\5$HfgAfBo;bFq+,m7c)kl1Pos[.=O+V3'12$DBgu>_cfd!L6QQ;I$lCf)4lm@&g\h9.[;1>-T#D'ACO!J/r!HM,fDMI;Egt7Ypg%>fdQ8?N02PVb^q!1$q$V684J1dlEErmA81";UZ54hO"&4=REQ=;lMKnC8W_R]ARjS%c/AL=Km46-%E`BF4N8_^>UCmp0rIksV4k"AHhXtG,ghQ+nBGJZ<6'$IpeJkkFYpOd]p<hP]:/ksDHS%5DDZ5tQmJTH\n"%7icfUl8DF\='g_Y)hR9rU'Q.@"^&632JP'GQMkQ9NrQ#*<RcA$XG<PRMPXFUlmWOju>J;Yh`]^AlDH2u#(0$#k1Nj_Xh-1<PF?%r*@M^C6MfA5A:PBEj)^crU*_n36HT3H!G&U>+gVM!%*)=3`E:P.i$-K26LQf3S(i!LfV_Ftr%j/_]BcZ0.1:<+*1=Rt)?Of'k&45F3g9T9A:(#VE(/C6tTUO#/S:&ERUE6=(ob0;6*A)Sd9Uq>*62;-hCFGVhXObp;?+h8F.&F5:go>bAUM0?!"G(<Z]+\k8fD;K1laAfn-C4$d]g1?[4N2VkW#f0U%s@YFoCOhoQ'?<M/g$#8nhCZ3[!/gC/ud>a>u^1>7EmGj9^^?JA5!f'HZY5j)%"Ha6V!KPjQQ/p2]?*u;'%nlQS]n`Mm=A7`]L$Y?n=fiN?QKlfG;Y:e^5\LFIOnN"_N0Cd,dXGhq0j\qC0!d(,6ql8XD9]p$@.8BT(P_jm%kaQ5m(4[\(1+lg_.Pik"HK5\f"Q?SC_pnKNd%e(M4P'cp1JFC!F@Vh:U?!n6/6K'Ba[GXUmZr9%Qmi*.&nfI8.F]#U5"7@a0U\E2JuO#[m44r2d\AreaieIH4iclLDZ`,XpTJMSC2Oe@XoFI\2,-^BhSNCFa`P_Y<?7SUgh`9ZP$B9MjO"R!Ceq2hFeChq5D`10]=c'^8:?=+24q2k3g"(spm1RujK#'j1n(^nL$=4IX!MXpRSF_&_7G\(iLj_M:'DU0Q'b2**?H-tRCE*\`/rJCRi[b0SD`<./k#[l3U`H$[9gLDmk$BkDh[7?0K~>endstream
|
|
170
|
+
endobj
|
|
171
|
+
23 0 obj
|
|
172
|
+
<<
|
|
173
|
+
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1632
|
|
174
|
+
>>
|
|
175
|
+
stream
|
|
176
|
+
Gatn&gMYe)&;KZH'Q_s)0uGfd9?2$N".M9SAH_CkXC^C.[*h9=:.68=6QJ_cY)UGP@j!,=ipc-THl@kC`?.#;?YogM(@^=-#)kq>!LP,FMA;Wt)53K<WIQZS%Fm`=2"*V?%5'NdP!$36.'!V48qZ6P3V`(p,?dZ33=r7$Pmg4/Pg6[D3Guh[-YhFr&jGc=IpfT:W?J0cEaES@(JWidq9/)^ir%m.mHRJlF8>,!="+'&igF/1dd\^]k/+amL?Nti)oJH:X3V6>:t;^b@+VqB)tu5[9T7NOjJZG\KAc3g$RO`r2+@ROM&`sS8"G[$ZPou&+ul1F!YGXsL52*ZC8jHS*T#X'O7Q6$bF?7In43!QT6PKU>[@I/$a@3)4'f[FEEZV;/Ko\s2]$i"+B5%.'J&A=8\p&lC%01!mgG39q/hp*"Z:Xe+0:7N0cM@`e3fA=^P'\coFAUHgO:rgPI@I*_mWi4(g:%RD;4\M<t5_o%L1Mq0\hA;iTk*cK;Jg]h@,n9@j5lA2f8/r>LbW!f@E+<57d`L5Ub23_^r-n>((g3MM%5$K5IK]R,S`p2;0la('>RnTb=_A6t+.MK:F!^Z=l$N\dC>e36Hj:guu`Q,%7`UUW@"IB.-.1+u.3XThIAG17:\5VqIk*p]tM)``72KH+J'O=CAdX:'ECKno56+5Tnm'VAgU=0!ZJ+96/MJ^;94"J*I]>hT+]4ZK(j6[PU4,/V]\9KD\PeS0'ADo7LtHKD]\8R%M>Qj_'u-q,pBHE@@"[Vu/*/VYnYqK9'uKAGh,V@I/RC^ra^$m08ZrLbr3/S?)16M(]r$$s.2hPl[029$H`@Q0([OTsTce&9?ko!O[c8nY9><IE[l&RTTT]MU'K+4@h.LFC(c"Jgdl4@i%foE@@"[a'8d>A$1FC`CDmd&r.c7&&538$p1=aFG\a3b7P)^YWWV2/@s;OanT>rTmS]2B/r[[R`;bq32lR-XB`XkK<S%:kZ%a@_PW75.pCN$=t>*._lh5I=E=/CH[IDR]CA:CP%0Pg4,5b]`46Dj8fI^%:h'*X%6r\/IsO$L+]E;h.-(;47"WYEc8B+\g3&lsE,2E,WiVn0gAu2p<`"5^>R.soJh8P%[F_!$o4%VD$L^^k=F^_24+\p6&t"8&0HiI6LIq(7#UUEn9!m^X!%+,'".4[OKIP+h9YhtfLGIP%KIKHlV]"BE.@quF_[jU0[8(+mfGaKlP/`6^&*!po0Hi2[XWM>L^a,3$LInM%BGa7,K#oNHetuW#$760H/4TW'0M.gWme:qe!1P$IZ+N<3p!WsgV27:ID;dpohJSbucc:qc?52/j[d9k/?5$,l?1cHO=&ts9O8'0iW?"_]l?YC6b&EBeordT8cpNXs.dl&omG43nU5oU(NmJ0B"MJ3$?O-B$*dU-oh[-Pn+/((O*d`DY'o2!MOeP@b&UK@,-4XUmiJ:g%1nkd#cT^?VOuW@^H6VMYHG\*YoRp3FOt_p["VUqQf(sC3'D-rTqre>,JI^^r?8-XnbM#q]:SB.0!f2(noL(=,kA=@-?:3DI@C9f5IsYAk`,]cu51Fs1lcZD_B"&d>oln9Qh/75f_kr"%FU2V_'6r->^5'%gX+*5&T6'tXm\]Z[qr51$2TYk"->Juk~>endstream
|
|
177
|
+
endobj
|
|
178
|
+
24 0 obj
|
|
179
|
+
<<
|
|
180
|
+
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2074
|
|
181
|
+
>>
|
|
182
|
+
stream
|
|
183
|
+
Gatn'gMYe)&;KZJ.H[p1*C`0UJD;u$SA]s,'_)A2H;hnsEi`H"KqqH&U(?-),n3AV%dF1WJX@E1B7:?dOi*FqiK*X2DeafhCO#PVJlJtg#&/aAo`^kf=!EN%@Oqd&Rj<kWW3P6.=uA8r0ptS]/-VMGTb8;3VP#HtqT2@JemsmEO]dqe#pPWm:1H62#?-]kl_?m8:!rG@EY;tn8>CEO^96Fm7)8-[hp*n4_B3D,(I,h6Dcf5D@o,#]"KtEZV^`;K]hXbZ"fL[hh-X/NJ((h.jNSIK`NEtER!4['EKm8t?Fsq0mo4#%iPQV)5J#;me:82Q-]bqJ/lt@iS8/<q-^Zc]\oBaj,*R$3ftA#`o&<u)r::!HY2A1c?Ce:WIfT6[i8X_"M[R%"^K@,#@O>DfT!-Juc,]EWB3]Oh;'q/Xe)D5sFeX0HIJ!D7A5t\9APs,:$ch/[%?k;dZS1^TZB'L/m([?5!NL=,=0V!o>_fnG*&l1jhtP)*Y3o]-.H!kN2P8p=XgUZB!]aNQq`EH<h/EF4(I#Z7/jmW])FF-dpUTL\DRY=%c3sXu+<oU?&m&:tHe.TTPuSBba[a%M7Z[?g>D9LffF/Eg2VJbJQ,7"qRDFh(frTcWM1R7`)50kB"Qr?=4.dhCQAl\@pSntNLf;PlL,h(Ai+?PfUh]7UMTH+JM7#:CS!@JGQ&#\-.n_+HjGVMHBKp0@ge<[ea,W)_MW*4Y1qO\"]59_Gn8"TP'S#LflXs;rJ#]D*6X;i,[cPkZI,34bh)qLCiA7#QCSu;J0N2E9oX(eR?T04:ND6WSqQ89lNA>CmNn5jTNn7!?OZ>>@Gq<UkZNRRMS4Mq=QUkX"o114G*#]U>Y8^'5`nmM9ne($&nh@9%[h":,KkId;Ou[H[MeWicbi41)A<Jsle+UU$eD@99A6VLH'LuR_[`L%KeFb#Ja@O01bbg--;L>a=K9F@BS&TKN)`P+@gH\5WqqZ>0+9Hf+fh@1g-bo,K41m)3F+5EH_=MBt1jI!P3Q%OQaT#KZkX^X;W^Im%LIi=IQUBU=E8@q058_F.'/j\`jCM9L0j6Kiii@#P$$b!Pe("7LA^d"#!qO&YL)uE/D-](!JBac:q>lZ;?2eR3\2ZN*l*S'<*cH63P2J.$3J*<.$pLs/6RL*En<q39_.T#sJe(ZE"8JrU#Omkp_ahB?+.3OYBNRM1+%c%mOlFJQQkRZ\6fF5t_.T$<_Iljg0N%?`Ht78Rc!t$`C(;>O<_N4^J2FYOI'^pDR`BHN56bK5&5eJq+0RJLa'o)?W[mZ-*H#u7lJce$1n!;2[Q@8ln[7]g#9=R=S"fB190(eCl-NGFS3!r6=EX=n*("n&Pe*#ir5d?b^27DT`HPR13fT/E,9,[&CohH\9AXb;O*EHA46"L%Hbc,Ud/e/rn[q^Pn4"bB*#]U>o1"m*DkqXK&a%%&n3Gihar#%d-VN<T;+(Vr")h^:WbAJLX,QR\PZmWiA>#=DJN#?0I>W8Z?@RJaUDOaB0mU[$Z<(&\<`_:^fk''-MotrP=IY3V([318j3,?F1-G(CRQ'm#:n7;.?+VU*cf=rO-pF!:(\mdaiaLH+b2OYIaMtG.>G*C-#?Z]N/_I-f_Fhl>!%T)1#?[,-@n"(]'q#JOBNW%^X&-YOVKhYDk/?i[5ch>t$nH]]0<rrHh2aq%*O$_$_F%g=gK92q`b[31dQ509m=5q>S>(9[fD7j:Bu;jDGtb<H8_@Vs+%@o'HTs,\>/a.1*qTk&EDRf]=</#RNjiZ8G'jKq`H@*"q=,Dh\nHie\]^4:a3`'h%c(qGG*G[dd&BjM"^<13TMnF&!1ca4!H_lBcquG]7jc+n)A^[eVaBW_R,Zd(c&(Q@J^CAu1?]EQV$lL+%,jM>!$.I=/K3s0P!Q"I=[K#[5Zrf--3]r7:=21iC],F?P\"O\a+R4,lq-upDdV/X?#dQ]Wk6:t:Drk;jD!@RQX/u#>5/6$b2sIhQ1`cuR-K.5dH^G*XRJEsn(Ra0*,^[DLX.f4lP?!]J,-o\^:E(gT&]FeIH.`UC#iJ07J$?SDp"Rg`QI^d%+2[BosVBr3P)Hk%i)eCL]~>endstream
|
|
184
|
+
endobj
|
|
185
|
+
25 0 obj
|
|
186
|
+
<<
|
|
187
|
+
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1744
|
|
188
|
+
>>
|
|
189
|
+
stream
|
|
190
|
+
Gatn&9lo&I&;KZO'g"F`R04\Ia[6SrXZC2:b@AZ=[$M1q_)<6i<%7Yoe*1f>JeS5VZDUI;er1"gM;<BBqg]63(dGD)cBeP"kO@n@$C&C)&uZoSk/T0I7jM,/$OMJ9Tjn7Zp%.;qWc4pQ.7o[Z!LZQsZrE,BBFJ.[NeiiBN>[gWZ;aXC$'cu;G%DJK5sf)u/LG9I%56(f0VKVG<UY=LKV(_h^Q2,"`eSLs)kYB(LA>11Ir3f1B`*+YN*E2R'D8;&XdOBZ<7Vjg$)7fc:+,P]4KJY*7&MNc#n#iR"8ncF/ifFB@I!'5-a3`tZ-OA%--RRM)5`f'i>N)Y=USH::nR0^:*3KV=JtK`q4G^s@K$T%31S3jB)qr3*)@)7a"X!Dk*#oB4FTMabf=[E4ujU<U19$8;68D42o-rp4KNiFrNYWYQLq_(<5e$ej!PdSj-Y"DVt-h(it_SN-d\=Z(:%[`X'[Ea.g&r2(3R$>4KICPD;_FD3q^WP=^+j,Dq>Nceh"Gr7,XkYQ?`)4\2Ai]m?f@tI*D,TkQCP+l;_%>Mf5#C$&]_%]#Dtnqkh1&D6M3IKZPSKs"sGTm0Ke2au,AG"d.;?pNLVCOlVuU3a3In+UFE,GaiIf'uqSVe'P=5qE4=,.D2^tVIG_B#N;1'2)l['3(n-X\f#h1[1l2T-4r3O6,5SqJY]TDD%po9pmcpsjO&*\pOK0RZ&3KR:dPS5ZST_-b>O2T'<4u1/9QF[Qah#V=j\c19IfaOm8u@@G/cDe1oB2sEU(4Ij#h?J#Er.EX:;T"2RD4FLW3Wk5I-Dcgto9`,5.Qu^Q5GO4ZRJ!P8D%fq73F>p"^N]lT<S>Y"`&RU&J\C6?f5<R%g%iK<YF9F(BB0g3X[-bWhUl:F?BSE#\cHEVp'SHDkbN0*pjDNk"M[l08!(CjJ8eT0736JV1775=)Ra9S73:B*W^q>a;0Djhi$1D.RpL$8SR(*SbeVf]"le2Keml_H.?<T3tGKV>CB+[ZKF`k!5/1D%eH<gEThcG`Q73eIKDNTfWB=91Q4UH%MSY":dj3YTqdll3MQj#9PRrTFT9n=K4>'(ot5BYghI5k/O!#B0oALg27l8"A?kG$'rHs$Z>;;Fsa8'=;u#R+bHO!3+FU5YZ*o,0=-$el_$6jWgimP`E*Bb]Rq".0__WZC%hZ-AI%/<IJX;*2n&CCptDKs$iKHTnnig2jA7dcj,;,V2YaH&>Adf`=UV:-^+;nJ4YL7qaWAII(1?KFN^gk<2TC=rHPhZ/m9qPD[Y(hUoa]!edUDKS*b/gqJO:"PlnEUGb'q@=0_RL1Fa,7Q6E:)rObdk57?T^igt6-'9F.\'CWBT^(^lUH@k<l%*8K1VlqCI-YVt#-6PtaNr6J^_A"eMr5;g^?Fj]2'o@>`mYqRg=Z5ATc*QW24/o7c$9oXp1@]EXVL<f;E]?9X@D!\DE/ePY*16@iVWEKAPh6ZckeeHe+C"CXC?O\2]e4n=S4RXT="lH*$f`M#?c2W)&aYnS&T0PPR1#&TZ:3PlsI$[%>6i&4gUMhiC^nD#8G4]d($5\9QN=VX[:kr]3a&<c%LBm0_qI8\LM<,e,K?5l,XMqI9g<mqS\P40tSnU.WoJr,c2lmIrrXaK?#oF7-8KU`^p\`F+<VJ;s2Xi:Vs3&j2LLZ7%F^gGO=P^?4^nU+C\A*TQ"qT^<jgXS7S)mALC>Zg(JR=4@"q.aelNaa5cm@%Qmb"Yh=+(B6GXo2ELZh%r+!<'2B)~>endstream
|
|
191
|
+
endobj
|
|
192
|
+
xref
|
|
193
|
+
0 26
|
|
194
|
+
0000000000 65535 f
|
|
195
|
+
0000000061 00000 n
|
|
196
|
+
0000000112 00000 n
|
|
197
|
+
0000000219 00000 n
|
|
198
|
+
0000000331 00000 n
|
|
199
|
+
0000000436 00000 n
|
|
200
|
+
0000000641 00000 n
|
|
201
|
+
0000000846 00000 n
|
|
202
|
+
0000001051 00000 n
|
|
203
|
+
0000001256 00000 n
|
|
204
|
+
0000001461 00000 n
|
|
205
|
+
0000001667 00000 n
|
|
206
|
+
0000001873 00000 n
|
|
207
|
+
0000002079 00000 n
|
|
208
|
+
0000002285 00000 n
|
|
209
|
+
0000002355 00000 n
|
|
210
|
+
0000002634 00000 n
|
|
211
|
+
0000002746 00000 n
|
|
212
|
+
0000003867 00000 n
|
|
213
|
+
0000005539 00000 n
|
|
214
|
+
0000007345 00000 n
|
|
215
|
+
0000009088 00000 n
|
|
216
|
+
0000010750 00000 n
|
|
217
|
+
0000012399 00000 n
|
|
218
|
+
0000014123 00000 n
|
|
219
|
+
0000016289 00000 n
|
|
220
|
+
trailer
|
|
221
|
+
<<
|
|
222
|
+
/ID
|
|
223
|
+
[<54b169742b36aa77d8c31830cc1316cd><54b169742b36aa77d8c31830cc1316cd>]
|
|
224
|
+
% ReportLab generated PDF document -- digest (opensource)
|
|
225
|
+
|
|
226
|
+
/Info 15 0 R
|
|
227
|
+
/Root 14 0 R
|
|
228
|
+
/Size 26
|
|
229
|
+
>>
|
|
230
|
+
startxref
|
|
231
|
+
18125
|
|
232
|
+
%%EOF
|