Added new files regarding airflow and fixed the png's not zooming in nested panes

This commit is contained in:
2025-12-29 18:47:48 +00:00
parent f217e8828f
commit 80101cd34b
16 changed files with 259 additions and 120 deletions

View File

@@ -6,7 +6,11 @@
* Cheat sheet * Cheat sheet
[[./assets/git-cheat-sheet-1.png]]
[[./assets/git-cheat-sheet-2.png]]
[[./assets/Screenshot_20251227_153037.png]]
* Open Source Projects: * Open Source Projects:
- [[https://github.com/codecrafters-io/build-your-own-x?tab=readme-ov-file][Build your own `x`]] - [[https://github.com/codecrafters-io/build-your-own-x?tab=readme-ov-file][Build your own `x`]]

View File

@@ -14,3 +14,5 @@
* [[id:dd55d635-59de-4ed9-8ff0-423782c2e0ae][clean-code]] * [[id:dd55d635-59de-4ed9-8ff0-423782c2e0ae][clean-code]]
* [[id:4426cc9a-1568-4fc8-9242-269654c43a3b][naqshe-hayat]] * [[id:4426cc9a-1568-4fc8-9242-269654c43a3b][naqshe-hayat]]
- [[id:dc9ece84-0b14-4afd-b25a-786cf1618996][Head First Design Patterns]]

View File

@@ -1,7 +1,7 @@
:PROPERTIES: :PROPERTIES:
:ID: 939e301b-6463-46a8-b57e-0af606e7e7ef :ID: 939e301b-6463-46a8-b57e-0af606e7e7ef
:END: :END:
#+title: postgres #+title: Postgres
#+filetags: :database:index: #+filetags: :database:index:
#+begin_src bash #+begin_src bash
@@ -24,41 +24,41 @@ To get your phone logged in, there's two ways:
Im thinking of having this as our shared calendar and file system. The only users are us 2 and its completely off the internet (self-hosted). Im thinking of having this as our shared calendar and file system. The only users are us 2 and its completely off the internet (self-hosted).
network issues resolved by: ** network issues resolved by:
docker network connect postgres_network postgres #+begin_src bash
docker network connect postgres_network postgres
zaine@zaine-HP-ProDesk-400-G1-SFF [21:00:27] [~/docker-services/nextcloud] zaine@zaine-HP-ProDesk-400-G1-SFF [21:00:27] [~/docker-services/nextcloud]
-> % psql -h zserver.zapto.org -p 5432 -U zaine -d zxq_db -> % psql -h zserver.zapto.org -p 5432 -U zaine -d zxq_db
Password for user zaine: Password for user zaine:
psql (14.18 (Ubuntu 14.18-0ubuntu0.22.04.1), server 17.5 (Debian 17.5-1.pgdg120+1)) psql (14.18 (Ubuntu 14.18-0ubuntu0.22.04.1), server 17.5 (Debian 17.5-1.pgdg120+1))
WARNING: psql major version 14, server major version 17. WARNING: psql major version 14, server major version 17.
Some psql features might not work. Some psql features might not work.
Type "help" for help. Type "help" for help.
zxq_db=# \c nextcloud zxq_db=# \c nextcloud
psql (14.18 (Ubuntu 14.18-0ubuntu0.22.04.1), server 17.5 (Debian 17.5-1.pgdg120+1)) psql (14.18 (Ubuntu 14.18-0ubuntu0.22.04.1), server 17.5 (Debian 17.5-1.pgdg120+1))
WARNING: psql major version 14, server major version 17. WARNING: psql major version 14, server major version 17.
Some psql features might not work. Some psql features might not work.
You are now connected to database "nextcloud" as user "zaine". You are now connected to database "nextcloud" as user "zaine".
nextcloud=# GRANT ALL PRIVILEGES ON DATABASE nextcloud TO nextcloud; nextcloud=# GRANT ALL PRIVILEGES ON DATABASE nextcloud TO nextcloud;
GRANT GRANT
nextcloud=# GRANT USAGE ON SCHEMA public TO nextcloud; nextcloud=# GRANT USAGE ON SCHEMA public TO nextcloud;
GRANT CREATE ON SCHEMA public TO nextcloud; GRANT CREATE ON SCHEMA public TO nextcloud;
GRANT GRANT
GRANT GRANT
nextcloud=# GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO nextcloud; nextcloud=# GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO nextcloud;
GRANT GRANT
nextcloud=# GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO nextcloud; nextcloud=# GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO nextcloud;
GRANT GRANT
nextcloud=# nextcloud=#
zaine
M22ZN-fmefj-RdF36-3BMfT-LfWo8
zaine
zxh123!
zaine
M22ZN-fmefj-RdF36-3BMfT-LfWo8
zaine
zxh123!
#+end_src

View File

@@ -1,7 +1,9 @@
:PROPERTIES: :PROPERTIES:
:ID: e448cd99-afee-4702-947f-644bb34dc1aa :ID: e448cd99-afee-4702-947f-644bb34dc1aa
:END: :END:
#+title: database_moc #+title: Database MOC
#+filetags: :database:moc: #+filetags: :database:moc:
[[id:939e301b-6463-46a8-b57e-0af606e7e7ef][postgres]] - [[id:939e301b-6463-46a8-b57e-0af606e7e7ef][Postgres]]
- [[id:c6cf8f7a-778f-4e83-b607-753ef8dbb3f1][Airflow]]

View File

@@ -0,0 +1,25 @@
:PROPERTIES:
:ID: c6cf8f7a-778f-4e83-b607-753ef8dbb3f1
:END:
#+title: Airflow
#+filetags: :database:docs:
* xcom
XComs stands for cross-communications, and as the name suggests, it allows [[id:1ea42d73-3cd1-4cac-a6ee-028de21d08d5][Airflow Tasks]] to talk to each other (because by default, tasks are entirely isolated and can run on seperate machines).
See [[https://airflow.apache.org/docs/apache-airflow/stable/core-concepts/xcoms.html][this]]
* parquets
*Key Takeaways*
- What is Parquet: An open-source columnar storage file format for efficient analytics.
- Core Benefits: Superior compression, faster query performance (via column pruning and predicate pushdown), and schema evolution support.
- Common Alternatives: Compared to row-based (CSV, Avro), columnar (ORC), and table formats (Iceberg, Delta Lake).
- DuckDB & MotherDuck: Parquet integrates seamlessly with DuckDB for high-performance SQL queries directly on Parquet files.
*What is Parquet?*
Parquet is a columnar storage file format. When data engineers ask 'what is a Parquet file?', the simple answer is that it's a file that stores data in columns, not rows. This Parquet data format is designed for efficient data processing, particularly in the context of big data applications. Developed as part of the Apache Hadoop ecosystem, Parquet has gained widespread adoption due to its ability to optimize storage and query performance.
[[https://motherduck.com/learn-more/why-choose-parquet-table-file-format/][See this]]

View File

@@ -0,0 +1,5 @@
:PROPERTIES:
:ID: c6cf8f7a-778f-4e83-b607-753ef8dbb3f1
:END:
#+title: airflow

View File

@@ -0,0 +1,14 @@
:PROPERTIES:
:ID: 1ea42d73-3cd1-4cac-a6ee-028de21d08d5
:END:
#+title: Airflow Tasks
#+filetags: :airflow:database:definitions:
A task in the context of airflow is the basic unit of execution. They are arranged into [[id:3b16e19a-62f0-4705-a451-a8790181941f][Dags]] and then have upstream and downstream dependencies set between them in order to express the order in which they should be run.
There are three kinds of tasks:
1. Operators: they are predefined task templates that you can string together quickly.
2. Sensors: special subclass of operators, which are entirely about waiting for an external event to happen.
3. A Taskflow-decorated @task, which is a custom python function packaged as a task.
[[https://airflow.apache.org/docs/apache-airflow/stable/core-concepts/tasks.html][See this]]

View File

@@ -0,0 +1,6 @@
:PROPERTIES:
:ID: 1ea42d73-3cd1-4cac-a6ee-028de21d08d5
:END:
#+title: Airflow Tasks
#+filetags: :airflow:database:docs:

View File

@@ -0,0 +1,7 @@
:PROPERTIES:
:ID: 3b16e19a-62f0-4705-a451-a8790181941f
:END:
#+title: Airflow Dags
#+filetags: :airflow:database:definitions:
A DAG (short for directed acyclic graphs) is a model that encapsulates everything needed to execute a workflow. [[https://airflow.apache.org/docs/apache-airflow/stable/core-concepts/dags.html][See this]]

View File

@@ -0,0 +1,6 @@
:PROPERTIES:
:ID: 3b16e19a-62f0-4705-a451-a8790181941f
:END:
#+title: Airflow Dags
A DAG (short for directed acyclic graphs) is a model that encapsulates everything needed to execute a workflow. [[https://airflow.apache.org/docs/apache-airflow/stable/core-concepts/dags.html][See this]]

View File

@@ -12,6 +12,9 @@ A complete alphabetical index of all published pages.
- [[id:ed4c372b-0314-4b6e-9119-742f69b5e434][afp_lec_5]] - [[id:ed4c372b-0314-4b6e-9119-742f69b5e434][afp_lec_5]]
- [[id:4bc71106-1d2b-4c71-836d-54b738fe5ff5][afp_week2]] - [[id:4bc71106-1d2b-4c71-836d-54b738fe5ff5][afp_week2]]
- [[id:1f395b8c-cf55-43eb-9430-dd9449f6b575][afp_week5]] - [[id:1f395b8c-cf55-43eb-9430-dd9449f6b575][afp_week5]]
- [[id:c6cf8f7a-778f-4e83-b607-753ef8dbb3f1][Airflow]]
- [[id:3b16e19a-62f0-4705-a451-a8790181941f][Airflow Dags]]
- [[id:1ea42d73-3cd1-4cac-a6ee-028de21d08d5][Airflow Tasks]]
- [[id:e7f2302b-16eb-476d-a7b9-be12f077819d][AOC Notes]] - [[id:e7f2302b-16eb-476d-a7b9-be12f077819d][AOC Notes]]
* B * B
- [[id:580cc3a5-af8e-4cbe-b5ad-5b06680e6c37][Backlog]] - [[id:580cc3a5-af8e-4cbe-b5ad-5b06680e6c37][Backlog]]
@@ -24,7 +27,7 @@ A complete alphabetical index of all published pages.
- [[id:f9838952-9753-471b-a2cc-d72e01a53ef6][career_capital]] - [[id:f9838952-9753-471b-a2cc-d72e01a53ef6][career_capital]]
- [[id:dd55d635-59de-4ed9-8ff0-423782c2e0ae][clean-code]] - [[id:dd55d635-59de-4ed9-8ff0-423782c2e0ae][clean-code]]
* D * D
- [[id:e448cd99-afee-4702-947f-644bb34dc1aa][database_moc]] - [[id:e448cd99-afee-4702-947f-644bb34dc1aa][Database MOC]]
- [[id:d4f96bfb-b83d-449b-9f74-f602a1a3c2d3][deliberate_practice]] - [[id:d4f96bfb-b83d-449b-9f74-f602a1a3c2d3][deliberate_practice]]
- [[id:631b2086-4b8f-4fe3-829d-be1dc014e293][Design patterns]] - [[id:631b2086-4b8f-4fe3-829d-be1dc014e293][Design patterns]]
* E * E
@@ -76,7 +79,7 @@ A complete alphabetical index of all published pages.
- [[id:2c2d8df4-ad36-40ab-9f30-8a047b372956][old_nextcloud_server_code]] - [[id:2c2d8df4-ad36-40ab-9f30-8a047b372956][old_nextcloud_server_code]]
- [[id:a9829b5d-690d-4a21-ba94-ac8beac4d439][old_nginx_code]] - [[id:a9829b5d-690d-4a21-ba94-ac8beac4d439][old_nginx_code]]
* P * P
- [[id:939e301b-6463-46a8-b57e-0af606e7e7ef][postgres]] - [[id:939e301b-6463-46a8-b57e-0af606e7e7ef][Postgres]]
- [[id:2BFB84B2-2129-4AE3-8E69-290CA5BF9747][pre_work_prep_microlise]] - [[id:2BFB84B2-2129-4AE3-8E69-290CA5BF9747][pre_work_prep_microlise]]
- [[id:125c81dc-c14f-4b4d-93c6-0a2b157735ac][python-dictionary]] - [[id:125c81dc-c14f-4b4d-93c6-0a2b157735ac][python-dictionary]]
- [[id:9d534e89-7f0b-494c-bff6-7b3be05b85d1][python-lambda]] - [[id:9d534e89-7f0b-494c-bff6-7b3be05b85d1][python-lambda]]
@@ -102,6 +105,7 @@ A complete alphabetical index of all published pages.
* U * U
- [[id:4a8edaed-9ebd-402b-9c5f-7a0cb4399102][uml_fyp]] - [[id:4a8edaed-9ebd-402b-9c5f-7a0cb4399102][uml_fyp]]
- [[id:797d6e3e-98eb-4bc7-88b6-e096ef7306ad][uni_moc]] - [[id:797d6e3e-98eb-4bc7-88b6-e096ef7306ad][uni_moc]]
- [[id:dc9ece84-0b14-4afd-b25a-786cf1618996][Untitled]]
- [[id:d939e477-d1e9-43ea-960e-8727246d12a3][useful-c-imports]] - [[id:d939e477-d1e9-43ea-960e-8727246d12a3][useful-c-imports]]
* W * W
- [[id:7612a9a6-ae70-4525-93a0-81bac857df39][wacom-notes]] - [[id:7612a9a6-ae70-4525-93a0-81bac857df39][wacom-notes]]

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 347 KiB

View File

@@ -4,79 +4,66 @@ document.addEventListener('DOMContentLoaded', () => {
return; return;
} }
// 1) Wrap Org-exported images so theyre clickable function setupGalleries(root = document) {
const imgs = document.querySelectorAll('.figure img, img.org-svg'); const imgs = root.querySelectorAll('.figure img, img.org-svg');
imgs.forEach((img) => { imgs.forEach((img) => {
if (img.closest('a')) return; // already wrapped if (img.closest('a')) return;
const a = document.createElement('a');
const href = img.currentSrc || img.src; const a = document.createElement('a');
a.href = href; const href = img.currentSrc || img.src;
a.dataset.img = href; // lets BP pre-size/raster slides a.href = href;
a.dataset.alt = img.alt || ''; a.dataset.img = href;
const setDims = () => { a.dataset.alt = img.alt || '';
a.dataset.width = img.naturalWidth || img.width || 1920;
a.dataset.height = img.naturalHeight || img.height || 1080; const setDims = () => {
}; a.dataset.width = img.naturalWidth || img.width || 1920;
if (img.complete) setDims(); else img.addEventListener('load', setDims); a.dataset.height = img.naturalHeight || img.height || 1080;
img.style.cursor = 'zoom-in'; };
img.parentElement.insertBefore(a, img); if (img.complete) setDims(); else img.addEventListener('load', setDims);
a.appendChild(img);
}); img.style.cursor = 'zoom-in';
img.parentElement.insertBefore(a, img);
a.appendChild(img);
});
const containers = root.querySelectorAll('main, article, .content, body');
containers.forEach((container) => {
const links = Array.from(container.querySelectorAll('.figure a, a:has(img.org-svg)'));
if (!links.length) return;
links.forEach((link) => {
if (link.dataset.bpBound) return;
link.dataset.bpBound = 'true';
link.addEventListener('click', (e) => {
e.preventDefault();
document.querySelectorAll(".theme-toggle").forEach(el => el.classList.add("hidden"));
bp.open({
items: links,
el: link,
caption: (el) => el.querySelector('img')?.alt || el.title || '',
maxZoom: 40,
onClose(containerEl) {
destroyPanZoom();
teardownRotation();
if (containerEl) containerEl.classList.add('bp-fadeout');
document.querySelectorAll(".theme-toggle").forEach(el => el.classList.remove("hidden"));
},
onOpen(containerEl) { setupRotation(containerEl); enhanceSVG(containerEl); },
onUpdate(containerEl){ setupRotation(containerEl); enhanceSVG(containerEl); }
});
});
});
});
}
// 2) One global BP instance
const bp = BiggerPicture({ target: document.body }); const bp = BiggerPicture({ target: document.body });
// SVG pan/zoom handle
let activePanZoom = null;
const destroyPanZoom = () => { try { activePanZoom?.destroy(); } catch(_){} activePanZoom = null; };
// Simple rotate state (for non-SVG images)
let activeContainer = null; let activeContainer = null;
let currentRotation = 0; let currentRotation = 0;
let rotateControls = null; let rotateControls = null;
// 3) Build galleries per content container
const containers = document.querySelectorAll('main, article, .content, body');
containers.forEach((container) => {
const links = Array.from(container.querySelectorAll('.figure a, a:has(img.org-svg)'));
if (!links.length) return;
// Start the lightbox on click
links.forEach((link, index) => {
link.addEventListener('click', (e) => {
e.preventDefault();
document.querySelectorAll(".theme-toggle").forEach(el => {
el.classList.add("hidden");
});
bp.open({
// IMPORTANT: pass the anchor ELEMENTS, not custom objects
items: links,
el: link,
caption: (el) => el.querySelector('img')?.alt || el.title || '',
maxZoom: 40, // for raster images (PNG/JPG); SVG handled separately
// Fade-out polish + cleanup
onClose(containerEl) {
destroyPanZoom();
teardownRotation();
if (containerEl) containerEl.classList.add('bp-fadeout');
const themeToggle = document.querySelector(".theme-toggle");
if (themeToggle) {
themeToggle.classList.remove("hidden");
}
},
// Called once after open and on every slide change
onOpen(containerEl) { setupRotation(containerEl); enhanceSVG(containerEl); },
onUpdate(containerEl){ setupRotation(containerEl); enhanceSVG(containerEl); }
});
});
});
});
// 4) Simple rotate buttons for raster images
function ensureRotateControls() { function ensureRotateControls() {
if (rotateControls) return rotateControls; if (rotateControls) return rotateControls;
@@ -110,11 +97,11 @@ document.addEventListener('DOMContentLoaded', () => {
return btn; return btn;
}; };
const left = mkBtn('⟲', 'Rotate image 90° left'); const left = mkBtn('⟲', 'Rotate image 90° left');
const right = mkBtn('⟳', 'Rotate image 90° right'); const right = mkBtn('⟳', 'Rotate image 90° right');
left.addEventListener('click', (e) => { left.addEventListener('click', (e) => {
e.stopPropagation(); // dont close the lightbox e.stopPropagation();
if (!activeContainer) return; if (!activeContainer) return;
currentRotation = (currentRotation - 90 + 360) % 360; currentRotation = (currentRotation - 90 + 360) % 360;
applyRotation(); applyRotation();
@@ -139,11 +126,10 @@ document.addEventListener('DOMContentLoaded', () => {
const imgRoot = activeContainer.querySelector('.bp-img'); const imgRoot = activeContainer.querySelector('.bp-img');
if (!imgRoot) return null; if (!imgRoot) return null;
let imgEl = imgRoot.querySelector('img'); const imgEl = imgRoot.querySelector('img');
if (!imgEl) return null; if (!imgEl) return null;
const src = (imgEl.currentSrc || imgEl.src || '').toLowerCase(); const src = (imgEl.currentSrc || imgEl.src || '').toLowerCase();
// We only rotate raster images; SVGs are handled via svg-pan-zoom
if (src.endsWith('.svg')) return null; if (src.endsWith('.svg')) return null;
let wrapper = imgRoot.querySelector('.bp-rotate-wrapper'); let wrapper = imgRoot.querySelector('.bp-rotate-wrapper');
@@ -156,7 +142,6 @@ document.addEventListener('DOMContentLoaded', () => {
imgRoot.appendChild(wrapper); imgRoot.appendChild(wrapper);
wrapper.appendChild(imgEl); wrapper.appendChild(imgEl);
} else if (!wrapper.contains(imgEl)) { } else if (!wrapper.contains(imgEl)) {
// Slide changed and BiggerPicture replaced the <img>
wrapper.innerHTML = ''; wrapper.innerHTML = '';
wrapper.appendChild(imgEl); wrapper.appendChild(imgEl);
} }
@@ -181,13 +166,12 @@ document.addEventListener('DOMContentLoaded', () => {
function teardownRotation() { function teardownRotation() {
activeContainer = null; activeContainer = null;
currentRotation = 0; currentRotation = 0;
if (rotateControls) { if (rotateControls) rotateControls.style.display = 'none';
rotateControls.style.display = 'none';
}
} }
let activePanZoom = null;
// 4) If current slide is an SVG, swap to inline + enable svg-pan-zoom const destroyPanZoom = () => { try { activePanZoom?.destroy(); } catch(_){} activePanZoom = null; };
async function enhanceSVG(containerEl) { async function enhanceSVG(containerEl) {
try { try {
destroyPanZoom(); destroyPanZoom();
@@ -199,14 +183,12 @@ document.addEventListener('DOMContentLoaded', () => {
const isSVG = src.toLowerCase().endsWith('.svg'); const isSVG = src.toLowerCase().endsWith('.svg');
const htmlLayer = containerEl.querySelector('.bp-html'); const htmlLayer = containerEl.querySelector('.bp-html');
if (!isSVG || !htmlLayer) { if (!isSVG || !htmlLayer) {
// ensure any previous holder is removed and bitmap is visible
const old = htmlLayer?.querySelector('.bp-svg-holder'); const old = htmlLayer?.querySelector('.bp-svg-holder');
if (old) old.remove(); if (old) old.remove();
imgEl.style.visibility = ''; imgEl.style.visibility = '';
return; return;
} }
// Create/clear holder
let holder = htmlLayer.querySelector('.bp-svg-holder'); let holder = htmlLayer.querySelector('.bp-svg-holder');
if (!holder) { if (!holder) {
holder = document.createElement('div'); holder = document.createElement('div');
@@ -217,10 +199,8 @@ document.addEventListener('DOMContentLoaded', () => {
} }
holder.innerHTML = ''; holder.innerHTML = '';
// Hide the bitmap so only the inline SVG shows
imgEl.style.visibility = 'hidden'; imgEl.style.visibility = 'hidden';
// Inline the SVG
const res = await fetch(src, { cache: 'force-cache' }); const res = await fetch(src, { cache: 'force-cache' });
const text = await res.text(); const text = await res.text();
holder.innerHTML = text; holder.innerHTML = text;
@@ -228,9 +208,9 @@ document.addEventListener('DOMContentLoaded', () => {
const svg = holder.querySelector('svg'); const svg = holder.querySelector('svg');
if (!svg) { imgEl.style.visibility = ''; return; } if (!svg) { imgEl.style.visibility = ''; return; }
svg.style.maxWidth = '95vw'; svg.style.maxWidth = '95vw';
svg.style.maxHeight = '95vh'; svg.style.maxHeight = '95vh';
svg.style.display = 'block'; svg.style.display = 'block';
if (typeof window.svgPanZoom === 'function') { if (typeof window.svgPanZoom === 'function') {
activePanZoom = svgPanZoom(svg, { activePanZoom = svgPanZoom(svg, {
@@ -239,11 +219,10 @@ document.addEventListener('DOMContentLoaded', () => {
fit: true, fit: true,
center: true, center: true,
minZoom: 0.05, minZoom: 0.05,
maxZoom: 400, // effectively "unlimited" maxZoom: 400,
zoomScaleSensitivity: 0.25, zoomScaleSensitivity: 0.25,
dblClickZoomEnabled: true dblClickZoomEnabled: true
}); });
// Keep wheel inside lightbox
holder.addEventListener('wheel', (e) => e.stopPropagation(), { passive: true }); holder.addEventListener('wheel', (e) => e.stopPropagation(), { passive: true });
} else { } else {
console.warn('[gallery-init] svg-pan-zoom not loaded'); console.warn('[gallery-init] svg-pan-zoom not loaded');
@@ -252,4 +231,27 @@ document.addEventListener('DOMContentLoaded', () => {
console.error('[gallery-init] SVG enhance failed:', err); console.error('[gallery-init] SVG enhance failed:', err);
} }
} }
setupGalleries(document);
const dynamicObserver = new MutationObserver((mutations) => {
for (const m of mutations) {
for (const node of m.addedNodes) {
if (!(node instanceof HTMLElement)) continue;
if (node.querySelectorAll) setupGalleries(node);
}
}
});
dynamicObserver.observe(document.body, { childList: true, subtree: true });
let lastUrl = location.href;
const urlObserver = new MutationObserver(() => {
const currentUrl = location.href;
if (currentUrl !== lastUrl) {
lastUrl = currentUrl;
console.log('[gallery-init] URL changed → reinitializing galleries');
setupGalleries(document);
}
});
urlObserver.observe(document, { subtree: true, childList: true });
}); });

View File

@@ -0,0 +1,57 @@
* Head First Design Patterns
:PROPERTIES:
:NOTER_DOCUMENT: ../../../pdfs/bootcamp/Head First Design Patterns.pdf
:ID: dc9ece84-0b14-4afd-b25a-786cf1618996
:END:
** Chapter 1
:PROPERTIES:
:NOTER_PAGE: 36
:END:
*** Structural:
The Strategy Pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
- Encapsulate what varies
- Favor composition over inheritance
- Program to interfaces, not implementations
** Chapter 2
:PROPERTIES:
:NOTER_PAGE: 82
:END:
*** Observer:
The Observer Pattern defines a one-to-many dependency between objects so that when
one object changes state, all of its dependents are notified and updated automatically.
Subjects, or as we also know them, Observables, update Observers using a common
interface
Observers are loosely coupled in that the Observable knows nothing about them,
other than that they implement the Observer interface.
You can push or pull data from the Observable when using the pattern (pull is
considered more “correct”).
Dont depend on a specific order of notification for your Observers.
Java has several implementations of the Observer Pattern, including the general
purpose java.util.Observable
- Strive for loosely coupled designs between objects that interact
** Notes for page 137
:PROPERTIES:
:NOTER_PAGE: 137
:END:
- Classes should be open for extension, but closed for modification.
** Notes for page 142
:PROPERTIES:
:NOTER_PAGE: 142
:END:
Notes for the decaroter pattern.
** Notes for page 143
:PROPERTIES:
:NOTER_PAGE: 143
:END:
Decorator pattern: The Decorator Pattern attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

View File

@@ -0,0 +1,5 @@
* Head First Design Patterns
:PROPERTIES:
:NOTER_DOCUMENT: ../../../pdfs/bootcamp/Head First Design Patterns.pdf
:ID: dc9ece84-0b14-4afd-b25a-786cf1618996
:END: