Added new files regarding airflow and fixed the png's not zooming in nested panes
This commit is contained in:
@@ -6,7 +6,11 @@
|
||||
|
||||
* Cheat sheet
|
||||
|
||||
[[./assets/git-cheat-sheet-1.png]]
|
||||
|
||||
[[./assets/git-cheat-sheet-2.png]]
|
||||
|
||||
[[./assets/Screenshot_20251227_153037.png]]
|
||||
|
||||
* Open Source Projects:
|
||||
- [[https://github.com/codecrafters-io/build-your-own-x?tab=readme-ov-file][Build your own `x`]]
|
||||
|
||||
@@ -14,3 +14,5 @@
|
||||
* [[id:dd55d635-59de-4ed9-8ff0-423782c2e0ae][clean-code]]
|
||||
|
||||
* [[id:4426cc9a-1568-4fc8-9242-269654c43a3b][naqshe-hayat]]
|
||||
|
||||
- [[id:dc9ece84-0b14-4afd-b25a-786cf1618996][Head First Design Patterns]]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
:PROPERTIES:
|
||||
:ID: 939e301b-6463-46a8-b57e-0af606e7e7ef
|
||||
:END:
|
||||
#+title: postgres
|
||||
#+title: Postgres
|
||||
#+filetags: :database:index:
|
||||
|
||||
#+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).
|
||||
|
||||
|
||||
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]
|
||||
-> % psql -h zserver.zapto.org -p 5432 -U zaine -d zxq_db
|
||||
Password for user zaine:
|
||||
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.
|
||||
Some psql features might not work.
|
||||
Type "help" for help.
|
||||
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
|
||||
Password for user zaine:
|
||||
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.
|
||||
Some psql features might not work.
|
||||
Type "help" for help.
|
||||
|
||||
zxq_db=# \c nextcloud
|
||||
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.
|
||||
Some psql features might not work.
|
||||
You are now connected to database "nextcloud" as user "zaine".
|
||||
nextcloud=# GRANT ALL PRIVILEGES ON DATABASE nextcloud TO nextcloud;
|
||||
GRANT
|
||||
nextcloud=# GRANT USAGE ON SCHEMA public TO nextcloud;
|
||||
GRANT CREATE ON SCHEMA public TO nextcloud;
|
||||
GRANT
|
||||
GRANT
|
||||
nextcloud=# GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO nextcloud;
|
||||
GRANT
|
||||
nextcloud=# GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO nextcloud;
|
||||
GRANT
|
||||
nextcloud=#
|
||||
|
||||
zaine
|
||||
M22ZN-fmefj-RdF36-3BMfT-LfWo8
|
||||
|
||||
zaine
|
||||
zxh123!
|
||||
zxq_db=# \c nextcloud
|
||||
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.
|
||||
Some psql features might not work.
|
||||
You are now connected to database "nextcloud" as user "zaine".
|
||||
nextcloud=# GRANT ALL PRIVILEGES ON DATABASE nextcloud TO nextcloud;
|
||||
GRANT
|
||||
nextcloud=# GRANT USAGE ON SCHEMA public TO nextcloud;
|
||||
GRANT CREATE ON SCHEMA public TO nextcloud;
|
||||
GRANT
|
||||
GRANT
|
||||
nextcloud=# GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO nextcloud;
|
||||
GRANT
|
||||
nextcloud=# GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO nextcloud;
|
||||
GRANT
|
||||
nextcloud=#
|
||||
|
||||
zaine
|
||||
M22ZN-fmefj-RdF36-3BMfT-LfWo8
|
||||
|
||||
zaine
|
||||
zxh123!
|
||||
|
||||
#+end_src
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
:PROPERTIES:
|
||||
:ID: e448cd99-afee-4702-947f-644bb34dc1aa
|
||||
:END:
|
||||
#+title: database_moc
|
||||
#+title: 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]]
|
||||
|
||||
25
20251229180039-airflow.org
Normal file
25
20251229180039-airflow.org
Normal 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]]
|
||||
5
20251229180039-airflow.org~
Normal file
5
20251229180039-airflow.org~
Normal file
@@ -0,0 +1,5 @@
|
||||
:PROPERTIES:
|
||||
:ID: c6cf8f7a-778f-4e83-b607-753ef8dbb3f1
|
||||
:END:
|
||||
#+title: airflow
|
||||
|
||||
14
20251229180156-airflow_tasks.org
Normal file
14
20251229180156-airflow_tasks.org
Normal 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]]
|
||||
6
20251229180156-airflow_tasks.org~
Normal file
6
20251229180156-airflow_tasks.org~
Normal file
@@ -0,0 +1,6 @@
|
||||
:PROPERTIES:
|
||||
:ID: 1ea42d73-3cd1-4cac-a6ee-028de21d08d5
|
||||
:END:
|
||||
#+title: Airflow Tasks
|
||||
#+filetags: :airflow:database:docs:
|
||||
|
||||
7
20251229180249-airflow_dags.org
Normal file
7
20251229180249-airflow_dags.org
Normal 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]]
|
||||
6
20251229180249-airflow_dags.org~
Normal file
6
20251229180249-airflow_dags.org~
Normal 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]]
|
||||
@@ -12,6 +12,9 @@ A complete alphabetical index of all published pages.
|
||||
- [[id:ed4c372b-0314-4b6e-9119-742f69b5e434][afp_lec_5]]
|
||||
- [[id:4bc71106-1d2b-4c71-836d-54b738fe5ff5][afp_week2]]
|
||||
- [[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]]
|
||||
* B
|
||||
- [[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:dd55d635-59de-4ed9-8ff0-423782c2e0ae][clean-code]]
|
||||
* 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:631b2086-4b8f-4fe3-829d-be1dc014e293][Design patterns]]
|
||||
* E
|
||||
@@ -76,7 +79,7 @@ A complete alphabetical index of all published pages.
|
||||
- [[id:2c2d8df4-ad36-40ab-9f30-8a047b372956][old_nextcloud_server_code]]
|
||||
- [[id:a9829b5d-690d-4a21-ba94-ac8beac4d439][old_nginx_code]]
|
||||
* 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:125c81dc-c14f-4b4d-93c6-0a2b157735ac][python-dictionary]]
|
||||
- [[id:9d534e89-7f0b-494c-bff6-7b3be05b85d1][python-lambda]]
|
||||
@@ -102,6 +105,7 @@ A complete alphabetical index of all published pages.
|
||||
* U
|
||||
- [[id:4a8edaed-9ebd-402b-9c5f-7a0cb4399102][uml_fyp]]
|
||||
- [[id:797d6e3e-98eb-4bc7-88b6-e096ef7306ad][uni_moc]]
|
||||
- [[id:dc9ece84-0b14-4afd-b25a-786cf1618996][Untitled]]
|
||||
- [[id:d939e477-d1e9-43ea-960e-8727246d12a3][useful-c-imports]]
|
||||
* W
|
||||
- [[id:7612a9a6-ae70-4525-93a0-81bac857df39][wacom-notes]]
|
||||
|
||||
BIN
assets/git-cheat-sheet-1.png
Normal file
BIN
assets/git-cheat-sheet-1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 485 KiB |
BIN
assets/git-cheat-sheet-2.png
Normal file
BIN
assets/git-cheat-sheet-2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 347 KiB |
@@ -4,79 +4,66 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
return;
|
||||
}
|
||||
|
||||
// 1) Wrap Org-exported images so they’re clickable
|
||||
const imgs = document.querySelectorAll('.figure img, img.org-svg');
|
||||
imgs.forEach((img) => {
|
||||
if (img.closest('a')) return; // already wrapped
|
||||
const a = document.createElement('a');
|
||||
const href = img.currentSrc || img.src;
|
||||
a.href = href;
|
||||
a.dataset.img = href; // lets BP pre-size/raster slides
|
||||
a.dataset.alt = img.alt || '';
|
||||
const setDims = () => {
|
||||
a.dataset.width = img.naturalWidth || img.width || 1920;
|
||||
a.dataset.height = img.naturalHeight || img.height || 1080;
|
||||
};
|
||||
if (img.complete) setDims(); else img.addEventListener('load', setDims);
|
||||
img.style.cursor = 'zoom-in';
|
||||
img.parentElement.insertBefore(a, img);
|
||||
a.appendChild(img);
|
||||
});
|
||||
function setupGalleries(root = document) {
|
||||
const imgs = root.querySelectorAll('.figure img, img.org-svg');
|
||||
imgs.forEach((img) => {
|
||||
if (img.closest('a')) return;
|
||||
|
||||
const a = document.createElement('a');
|
||||
const href = img.currentSrc || img.src;
|
||||
a.href = href;
|
||||
a.dataset.img = href;
|
||||
a.dataset.alt = img.alt || '';
|
||||
|
||||
const setDims = () => {
|
||||
a.dataset.width = img.naturalWidth || img.width || 1920;
|
||||
a.dataset.height = img.naturalHeight || img.height || 1080;
|
||||
};
|
||||
if (img.complete) setDims(); else img.addEventListener('load', setDims);
|
||||
|
||||
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 });
|
||||
|
||||
// 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 currentRotation = 0;
|
||||
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() {
|
||||
if (rotateControls) return rotateControls;
|
||||
|
||||
@@ -110,11 +97,11 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
return btn;
|
||||
};
|
||||
|
||||
const left = mkBtn('⟲', 'Rotate image 90° left');
|
||||
const left = mkBtn('⟲', 'Rotate image 90° left');
|
||||
const right = mkBtn('⟳', 'Rotate image 90° right');
|
||||
|
||||
left.addEventListener('click', (e) => {
|
||||
e.stopPropagation(); // don’t close the lightbox
|
||||
e.stopPropagation();
|
||||
if (!activeContainer) return;
|
||||
currentRotation = (currentRotation - 90 + 360) % 360;
|
||||
applyRotation();
|
||||
@@ -139,11 +126,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const imgRoot = activeContainer.querySelector('.bp-img');
|
||||
if (!imgRoot) return null;
|
||||
|
||||
let imgEl = imgRoot.querySelector('img');
|
||||
const imgEl = imgRoot.querySelector('img');
|
||||
if (!imgEl) return null;
|
||||
|
||||
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;
|
||||
|
||||
let wrapper = imgRoot.querySelector('.bp-rotate-wrapper');
|
||||
@@ -156,7 +142,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
imgRoot.appendChild(wrapper);
|
||||
wrapper.appendChild(imgEl);
|
||||
} else if (!wrapper.contains(imgEl)) {
|
||||
// Slide changed and BiggerPicture replaced the <img>
|
||||
wrapper.innerHTML = '';
|
||||
wrapper.appendChild(imgEl);
|
||||
}
|
||||
@@ -181,13 +166,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
function teardownRotation() {
|
||||
activeContainer = null;
|
||||
currentRotation = 0;
|
||||
if (rotateControls) {
|
||||
rotateControls.style.display = 'none';
|
||||
}
|
||||
if (rotateControls) rotateControls.style.display = 'none';
|
||||
}
|
||||
|
||||
|
||||
// 4) If current slide is an SVG, swap to inline + enable svg-pan-zoom
|
||||
let activePanZoom = null;
|
||||
const destroyPanZoom = () => { try { activePanZoom?.destroy(); } catch(_){} activePanZoom = null; };
|
||||
|
||||
async function enhanceSVG(containerEl) {
|
||||
try {
|
||||
destroyPanZoom();
|
||||
@@ -199,14 +183,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const isSVG = src.toLowerCase().endsWith('.svg');
|
||||
const htmlLayer = containerEl.querySelector('.bp-html');
|
||||
if (!isSVG || !htmlLayer) {
|
||||
// ensure any previous holder is removed and bitmap is visible
|
||||
const old = htmlLayer?.querySelector('.bp-svg-holder');
|
||||
if (old) old.remove();
|
||||
imgEl.style.visibility = '';
|
||||
return;
|
||||
}
|
||||
|
||||
// Create/clear holder
|
||||
let holder = htmlLayer.querySelector('.bp-svg-holder');
|
||||
if (!holder) {
|
||||
holder = document.createElement('div');
|
||||
@@ -217,10 +199,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
holder.innerHTML = '';
|
||||
|
||||
// Hide the bitmap so only the inline SVG shows
|
||||
imgEl.style.visibility = 'hidden';
|
||||
|
||||
// Inline the SVG
|
||||
const res = await fetch(src, { cache: 'force-cache' });
|
||||
const text = await res.text();
|
||||
holder.innerHTML = text;
|
||||
@@ -228,9 +208,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const svg = holder.querySelector('svg');
|
||||
if (!svg) { imgEl.style.visibility = ''; return; }
|
||||
|
||||
svg.style.maxWidth = '95vw';
|
||||
svg.style.maxWidth = '95vw';
|
||||
svg.style.maxHeight = '95vh';
|
||||
svg.style.display = 'block';
|
||||
svg.style.display = 'block';
|
||||
|
||||
if (typeof window.svgPanZoom === 'function') {
|
||||
activePanZoom = svgPanZoom(svg, {
|
||||
@@ -239,11 +219,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
fit: true,
|
||||
center: true,
|
||||
minZoom: 0.05,
|
||||
maxZoom: 400, // effectively "unlimited"
|
||||
maxZoom: 400,
|
||||
zoomScaleSensitivity: 0.25,
|
||||
dblClickZoomEnabled: true
|
||||
});
|
||||
// Keep wheel inside lightbox
|
||||
holder.addEventListener('wheel', (e) => e.stopPropagation(), { passive: true });
|
||||
} else {
|
||||
console.warn('[gallery-init] svg-pan-zoom not loaded');
|
||||
@@ -252,4 +231,27 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
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 });
|
||||
});
|
||||
|
||||
57
book-notes/Head First Design Patterns.org
Normal file
57
book-notes/Head First Design Patterns.org
Normal 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”).
|
||||
|
||||
Don’t 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.
|
||||
5
book-notes/Head First Design Patterns.org~
Normal file
5
book-notes/Head First Design Patterns.org~
Normal 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:
|
||||
Reference in New Issue
Block a user