@jjlmoya/utils-science 1.20.0 → 1.22.0
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/package.json +2 -1
- package/src/category/i18n/de.ts +1 -1
- package/src/category/i18n/fr.ts +6 -6
- package/src/category/i18n/ru.ts +1 -1
- package/src/category/index.ts +4 -1
- package/src/category/seo.astro +2 -2
- package/src/entries.ts +7 -1
- package/src/index.ts +3 -0
- package/src/pages/[locale]/[slug].astro +5 -4
- package/src/tests/locale_completeness.test.ts +2 -2
- package/src/tests/no_en_dash.test.ts +70 -0
- package/src/tests/seo_length.test.ts +5 -3
- package/src/tests/title_quality.test.ts +1 -1
- package/src/tests/tool_validation.test.ts +2 -2
- package/src/tool/asteroid-impact/bibliography.astro +2 -2
- package/src/tool/asteroid-impact/component.astro +16 -9
- package/src/tool/asteroid-impact/i18n/fr.ts +6 -6
- package/src/tool/asteroid-impact/i18n/ru.ts +4 -4
- package/src/tool/asteroid-impact/index.ts +1 -0
- package/src/tool/asteroid-impact/script.ts +13 -7
- package/src/tool/cellular-renewal/bibliography.astro +2 -2
- package/src/tool/cellular-renewal/i18n/fr.ts +13 -13
- package/src/tool/cellular-renewal/i18n/ru.ts +17 -17
- package/src/tool/cellular-renewal/i18n/zh.ts +9 -9
- package/src/tool/cellular-renewal/index.ts +1 -0
- package/src/tool/colony-counter/bibliography.astro +2 -2
- package/src/tool/colony-counter/i18n/ru.ts +5 -5
- package/src/tool/colony-counter/i18n/zh.ts +2 -2
- package/src/tool/colony-counter/index.ts +1 -0
- package/src/tool/cosmic-inflation/bibliography.astro +14 -0
- package/src/tool/cosmic-inflation/bibliography.ts +12 -0
- package/src/tool/cosmic-inflation/component.astro +270 -0
- package/src/tool/cosmic-inflation/cosmic-inflation-calculator.css +277 -0
- package/src/tool/cosmic-inflation/entry.ts +26 -0
- package/src/tool/cosmic-inflation/i18n/de.ts +188 -0
- package/src/tool/cosmic-inflation/i18n/en.ts +188 -0
- package/src/tool/cosmic-inflation/i18n/es.ts +168 -0
- package/src/tool/cosmic-inflation/i18n/fr.ts +188 -0
- package/src/tool/cosmic-inflation/i18n/id.ts +188 -0
- package/src/tool/cosmic-inflation/i18n/it.ts +188 -0
- package/src/tool/cosmic-inflation/i18n/ja.ts +188 -0
- package/src/tool/cosmic-inflation/i18n/ko.ts +188 -0
- package/src/tool/cosmic-inflation/i18n/nl.ts +188 -0
- package/src/tool/cosmic-inflation/i18n/pl.ts +188 -0
- package/src/tool/cosmic-inflation/i18n/pt.ts +188 -0
- package/src/tool/cosmic-inflation/i18n/ru.ts +188 -0
- package/src/tool/cosmic-inflation/i18n/sv.ts +188 -0
- package/src/tool/cosmic-inflation/i18n/tr.ts +188 -0
- package/src/tool/cosmic-inflation/i18n/zh.ts +188 -0
- package/src/tool/cosmic-inflation/index.ts +11 -0
- package/src/tool/cosmic-inflation/logic/CosmicInflationEngine.ts +21 -0
- package/src/tool/cosmic-inflation/seo.astro +15 -0
- package/src/tool/lorenz-attractor/bibliography.astro +14 -0
- package/src/tool/lorenz-attractor/bibliography.ts +12 -0
- package/src/tool/lorenz-attractor/component.astro +146 -0
- package/src/tool/lorenz-attractor/entry.ts +27 -0
- package/src/tool/lorenz-attractor/i18n/de.ts +113 -0
- package/src/tool/lorenz-attractor/i18n/en.ts +185 -0
- package/src/tool/lorenz-attractor/i18n/es.ts +113 -0
- package/src/tool/lorenz-attractor/i18n/fr.ts +113 -0
- package/src/tool/lorenz-attractor/i18n/id.ts +113 -0
- package/src/tool/lorenz-attractor/i18n/it.ts +113 -0
- package/src/tool/lorenz-attractor/i18n/ja.ts +113 -0
- package/src/tool/lorenz-attractor/i18n/ko.ts +113 -0
- package/src/tool/lorenz-attractor/i18n/nl.ts +113 -0
- package/src/tool/lorenz-attractor/i18n/pl.ts +113 -0
- package/src/tool/lorenz-attractor/i18n/pt.ts +113 -0
- package/src/tool/lorenz-attractor/i18n/ru.ts +113 -0
- package/src/tool/lorenz-attractor/i18n/sv.ts +113 -0
- package/src/tool/lorenz-attractor/i18n/tr.ts +113 -0
- package/src/tool/lorenz-attractor/i18n/zh.ts +113 -0
- package/src/tool/lorenz-attractor/index.ts +9 -0
- package/src/tool/lorenz-attractor/logic/LorenzEngine.ts +32 -0
- package/src/tool/lorenz-attractor/lorenz-attractor.css +335 -0
- package/src/tool/lorenz-attractor/renderer.ts +136 -0
- package/src/tool/lorenz-attractor/script.ts +282 -0
- package/src/tool/lorenz-attractor/seo.astro +15 -0
- package/src/tool/microwave-detector/bibliography.astro +2 -2
- package/src/tool/microwave-detector/component.astro +9 -7
- package/src/tool/microwave-detector/i18n/fr.ts +4 -4
- package/src/tool/microwave-detector/i18n/ru.ts +18 -18
- package/src/tool/microwave-detector/i18n/zh.ts +10 -10
- package/src/tool/microwave-detector/index.ts +1 -0
- package/src/tool/microwave-detector/logic/MicrowaveEngine.ts +5 -1
- package/src/tool/simulation-probability/bibliography.astro +2 -2
- package/src/tool/simulation-probability/i18n/fr.ts +5 -5
- package/src/tool/simulation-probability/i18n/ru.ts +7 -7
- package/src/tool/simulation-probability/i18n/zh.ts +4 -4
- package/src/tool/simulation-probability/index.ts +1 -0
- package/src/tool/temperature-timeline/bibliography.astro +14 -0
- package/src/tool/temperature-timeline/bibliography.ts +12 -0
- package/src/tool/temperature-timeline/component.astro +289 -0
- package/src/tool/temperature-timeline/entry.ts +26 -0
- package/src/tool/temperature-timeline/i18n/de.ts +213 -0
- package/src/tool/temperature-timeline/i18n/en.ts +213 -0
- package/src/tool/temperature-timeline/i18n/es.ts +178 -0
- package/src/tool/temperature-timeline/i18n/fr.ts +213 -0
- package/src/tool/temperature-timeline/i18n/id.ts +213 -0
- package/src/tool/temperature-timeline/i18n/it.ts +213 -0
- package/src/tool/temperature-timeline/i18n/ja.ts +213 -0
- package/src/tool/temperature-timeline/i18n/ko.ts +213 -0
- package/src/tool/temperature-timeline/i18n/nl.ts +213 -0
- package/src/tool/temperature-timeline/i18n/pl.ts +213 -0
- package/src/tool/temperature-timeline/i18n/pt.ts +213 -0
- package/src/tool/temperature-timeline/i18n/ru.ts +213 -0
- package/src/tool/temperature-timeline/i18n/sv.ts +213 -0
- package/src/tool/temperature-timeline/i18n/tr.ts +213 -0
- package/src/tool/temperature-timeline/i18n/zh.ts +213 -0
- package/src/tool/temperature-timeline/index.ts +11 -0
- package/src/tool/temperature-timeline/logic/TemperatureTimelineEngine.ts +58 -0
- package/src/tool/temperature-timeline/planet-temperature-timeline.css +158 -0
- package/src/tool/temperature-timeline/seo.astro +15 -0
- package/src/tools.ts +6 -0
- package/src/types.ts +1 -1
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import type { Point3D } from './logic/LorenzEngine';
|
|
2
|
+
|
|
3
|
+
export interface RenderContext {
|
|
4
|
+
ctx: CanvasRenderingContext2D;
|
|
5
|
+
w: number;
|
|
6
|
+
h: number;
|
|
7
|
+
rx: number;
|
|
8
|
+
ry: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function getCssVariable(name: string, fallback: string): string {
|
|
12
|
+
return getComputedStyle(document.documentElement).getPropertyValue(name).trim() || fallback;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function project(p: Point3D, rx: number, ry: number, dims: { w: number; h: number }): { x: number; y: number } {
|
|
16
|
+
const scale = Math.min(dims.w, dims.h) * 0.0135;
|
|
17
|
+
const cx = dims.w / 2;
|
|
18
|
+
const cy = dims.h / 2;
|
|
19
|
+
const cosX = Math.cos(rx);
|
|
20
|
+
const sinX = Math.sin(rx);
|
|
21
|
+
const cosY = Math.cos(ry);
|
|
22
|
+
const sinY = Math.sin(ry);
|
|
23
|
+
const px = p.x;
|
|
24
|
+
const py = p.y;
|
|
25
|
+
const pz = p.z - 25;
|
|
26
|
+
const x1 = px * cosY - pz * sinY;
|
|
27
|
+
const z1 = px * sinY + pz * cosY;
|
|
28
|
+
const y2 = py * cosX - z1 * sinX;
|
|
29
|
+
return {
|
|
30
|
+
x: cx + x1 * scale,
|
|
31
|
+
y: cy - y2 * scale,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function drawGridLine(ctx: CanvasRenderingContext2D, p1: Point3D, p2: Point3D, opts: { rx: number; ry: number; w: number; h: number }) {
|
|
36
|
+
const dist1 = Math.sqrt(p1.x * p1.x + p1.y * p1.y);
|
|
37
|
+
const dist2 = Math.sqrt(p2.x * p2.x + p2.y * p2.y);
|
|
38
|
+
const avgDist = (dist1 + dist2) / 2;
|
|
39
|
+
const alpha = Math.max(0, 0.22 - avgDist / 120);
|
|
40
|
+
if (alpha <= 0) return;
|
|
41
|
+
ctx.strokeStyle = `rgba(100, 116, 139, ${alpha})`;
|
|
42
|
+
ctx.beginPath();
|
|
43
|
+
const pt1 = project(p1, opts.rx, opts.ry, opts);
|
|
44
|
+
const pt2 = project(p2, opts.rx, opts.ry, opts);
|
|
45
|
+
ctx.moveTo(pt1.x, pt1.y);
|
|
46
|
+
ctx.lineTo(pt2.x, pt2.y);
|
|
47
|
+
ctx.stroke();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function drawGrid(config: RenderContext) {
|
|
51
|
+
const step = 8;
|
|
52
|
+
const limit = 40;
|
|
53
|
+
const opts = { rx: config.rx, ry: config.ry, w: config.w, h: config.h };
|
|
54
|
+
config.ctx.lineWidth = 1 * window.devicePixelRatio;
|
|
55
|
+
for (let x = -limit; x <= limit; x += step) {
|
|
56
|
+
for (let y = -limit; y < limit; y += step) {
|
|
57
|
+
drawGridLine(config.ctx, { x, y, z: 0 }, { x, y: y + step, z: 0 }, opts);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
for (let y = -limit; y <= limit; y += step) {
|
|
61
|
+
for (let x = -limit; x < limit; x += step) {
|
|
62
|
+
drawGridLine(config.ctx, { x, y, z: 0 }, { x: x + step, y, z: 0 }, opts);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function drawShadowPath(config: RenderContext, history: Point3D[]) {
|
|
68
|
+
if (history.length < 2) return;
|
|
69
|
+
const { ctx, w, h, rx, ry } = config;
|
|
70
|
+
const dims = { w, h };
|
|
71
|
+
ctx.strokeStyle = getCssVariable('--lorenz-shadow-color', 'rgba(0, 0, 0, 0.05)');
|
|
72
|
+
ctx.lineWidth = 1.5 * window.devicePixelRatio;
|
|
73
|
+
ctx.beginPath();
|
|
74
|
+
const p0 = project({ x: history[0].x, y: history[0].y, z: 0 }, rx, ry, dims);
|
|
75
|
+
ctx.moveTo(p0.x, p0.y);
|
|
76
|
+
for (let i = 1; i < history.length; i++) {
|
|
77
|
+
const p = project({ x: history[i].x, y: history[i].y, z: 0 }, rx, ry, dims);
|
|
78
|
+
ctx.lineTo(p.x, p.y);
|
|
79
|
+
}
|
|
80
|
+
ctx.stroke();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function drawPath(config: RenderContext, history: Point3D[], color: string) {
|
|
84
|
+
if (history.length < 2) return;
|
|
85
|
+
const { ctx, w, h, rx, ry } = config;
|
|
86
|
+
const dims = { w, h };
|
|
87
|
+
ctx.strokeStyle = color;
|
|
88
|
+
ctx.beginPath();
|
|
89
|
+
const p0 = project(history[0], rx, ry, dims);
|
|
90
|
+
ctx.moveTo(p0.x, p0.y);
|
|
91
|
+
for (let i = 1; i < history.length; i++) {
|
|
92
|
+
const p = project(history[i], rx, ry, dims);
|
|
93
|
+
ctx.lineTo(p.x, p.y);
|
|
94
|
+
}
|
|
95
|
+
ctx.stroke();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function drawHead(config: RenderContext, p: Point3D, color: string) {
|
|
99
|
+
const { ctx, w, h, rx, ry } = config;
|
|
100
|
+
const pt = project(p, rx, ry, { w, h });
|
|
101
|
+
ctx.fillStyle = color;
|
|
102
|
+
ctx.beginPath();
|
|
103
|
+
ctx.arc(pt.x, pt.y, 5 * window.devicePixelRatio, 0, Math.PI * 2);
|
|
104
|
+
ctx.fill();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function drawAxes(config: RenderContext) {
|
|
108
|
+
const { ctx, h, rx, ry } = config;
|
|
109
|
+
const ox = 50 * window.devicePixelRatio;
|
|
110
|
+
const oy = h - 50 * window.devicePixelRatio;
|
|
111
|
+
const axisLen = 20 * window.devicePixelRatio;
|
|
112
|
+
const cosX = Math.cos(rx);
|
|
113
|
+
const sinX = Math.sin(rx);
|
|
114
|
+
const cosY = Math.cos(ry);
|
|
115
|
+
const sinY = Math.sin(ry);
|
|
116
|
+
const projectVector = (vx: number, vy: number, vz: number) => {
|
|
117
|
+
const x1 = vx * cosY - vz * sinY;
|
|
118
|
+
const z1 = vx * sinY + vz * cosY;
|
|
119
|
+
const y2 = vy * cosX - z1 * sinX;
|
|
120
|
+
return { dx: x1 * axisLen, dy: -y2 * axisLen };
|
|
121
|
+
};
|
|
122
|
+
ctx.lineWidth = 1 * window.devicePixelRatio;
|
|
123
|
+
ctx.font = `${Math.round(9 * window.devicePixelRatio)}px var(--lorenz-font-mono)`;
|
|
124
|
+
const drawAxisLine = (ax: { dx: number; dy: number }, label: string, color: string) => {
|
|
125
|
+
ctx.strokeStyle = color;
|
|
126
|
+
ctx.fillStyle = color;
|
|
127
|
+
ctx.beginPath();
|
|
128
|
+
ctx.moveTo(ox, oy);
|
|
129
|
+
ctx.lineTo(ox + ax.dx, oy + ax.dy);
|
|
130
|
+
ctx.stroke();
|
|
131
|
+
ctx.fillText(label, ox + ax.dx + 4, oy + ax.dy + 3);
|
|
132
|
+
};
|
|
133
|
+
drawAxisLine(projectVector(1, 0, 0), 'X', 'rgba(239, 68, 68, 0.4)');
|
|
134
|
+
drawAxisLine(projectVector(0, 1, 0), 'Y', 'rgba(34, 197, 94, 0.4)');
|
|
135
|
+
drawAxisLine(projectVector(0, 0, 1), 'Z', 'rgba(59, 130, 246, 0.4)');
|
|
136
|
+
}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { LorenzEngine } from './logic/LorenzEngine';
|
|
2
|
+
import type { Point3D, LorenzParams } from './logic/LorenzEngine';
|
|
3
|
+
import {
|
|
4
|
+
getCssVariable,
|
|
5
|
+
drawGrid,
|
|
6
|
+
drawShadowPath,
|
|
7
|
+
drawPath,
|
|
8
|
+
drawHead,
|
|
9
|
+
drawAxes,
|
|
10
|
+
} from './renderer';
|
|
11
|
+
|
|
12
|
+
const canvas = document.getElementById('lorenzCanvas') as HTMLCanvasElement;
|
|
13
|
+
const ctx = canvas?.getContext('2d');
|
|
14
|
+
const chartCanvas = document.getElementById('chartCanvas') as HTMLCanvasElement;
|
|
15
|
+
const chartCtx = chartCanvas?.getContext('2d');
|
|
16
|
+
|
|
17
|
+
const getEl = <T extends HTMLElement>(id: string) => document.getElementById(id) as T;
|
|
18
|
+
const slideSigma = getEl<HTMLInputElement>('slideSigma');
|
|
19
|
+
const slideRho = getEl<HTMLInputElement>('slideRho');
|
|
20
|
+
const slideBeta = getEl<HTMLInputElement>('slideBeta');
|
|
21
|
+
const slideDt = getEl<HTMLInputElement>('slideDt');
|
|
22
|
+
const slidePerturb = getEl<HTMLInputElement>('slidePerturb');
|
|
23
|
+
|
|
24
|
+
const valSigma = getEl('valSigma');
|
|
25
|
+
const valRho = getEl('valRho');
|
|
26
|
+
const valBeta = getEl('valBeta');
|
|
27
|
+
const valDt = getEl('valDt');
|
|
28
|
+
const valPerturb = getEl('valPerturb');
|
|
29
|
+
|
|
30
|
+
const btnPlayPause = getEl<HTMLButtonElement>('btnPlayPause');
|
|
31
|
+
const btnReset = getEl<HTMLButtonElement>('btnReset');
|
|
32
|
+
const btnClear = getEl<HTMLButtonElement>('btnClear');
|
|
33
|
+
|
|
34
|
+
const statT1 = getEl('statT1');
|
|
35
|
+
const statT2 = getEl('statT2');
|
|
36
|
+
const statDist = getEl('statDist');
|
|
37
|
+
const statDelta = getEl('statDelta');
|
|
38
|
+
|
|
39
|
+
let isRunning = true;
|
|
40
|
+
let t1: Point3D = { x: 10.0, y: 10.0, z: 10.0 };
|
|
41
|
+
let t2: Point3D = { x: 10.0001, y: 10.0, z: 10.0 };
|
|
42
|
+
let t1History: Point3D[] = [];
|
|
43
|
+
let t2History: Point3D[] = [];
|
|
44
|
+
let distanceHistory: number[] = [];
|
|
45
|
+
let lastDistance = 0.0001;
|
|
46
|
+
|
|
47
|
+
const maxHistory = 1000;
|
|
48
|
+
let rx = 0.6;
|
|
49
|
+
let ry = 0.45;
|
|
50
|
+
let isDragging = false;
|
|
51
|
+
let previousMousePosition = { x: 0, y: 0 };
|
|
52
|
+
|
|
53
|
+
function getParams(): LorenzParams {
|
|
54
|
+
return {
|
|
55
|
+
sigma: parseFloat(slideSigma.value),
|
|
56
|
+
rho: parseFloat(slideRho.value),
|
|
57
|
+
beta: parseFloat(slideBeta.value),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function getDt(): number {
|
|
62
|
+
return parseFloat(slideDt.value);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function getPerturbation(): number {
|
|
66
|
+
return parseFloat(slidePerturb.value);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function updateDisplays() {
|
|
70
|
+
if (valSigma) valSigma.textContent = parseFloat(slideSigma.value).toFixed(1);
|
|
71
|
+
if (valRho) valRho.textContent = parseFloat(slideRho.value).toFixed(1);
|
|
72
|
+
if (valBeta) valBeta.textContent = parseFloat(slideBeta.value).toFixed(2);
|
|
73
|
+
if (valDt) valDt.textContent = parseFloat(slideDt.value).toFixed(3);
|
|
74
|
+
if (valPerturb) valPerturb.textContent = parseFloat(slidePerturb.value).toFixed(5);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function resetToDefaults() {
|
|
78
|
+
slideSigma.value = '10.0';
|
|
79
|
+
slideRho.value = '28.0';
|
|
80
|
+
slideBeta.value = '2.67';
|
|
81
|
+
slideDt.value = '0.005';
|
|
82
|
+
slidePerturb.value = '0.00010';
|
|
83
|
+
updateDisplays();
|
|
84
|
+
clearPaths();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function clearPaths() {
|
|
88
|
+
const perturbation = getPerturbation();
|
|
89
|
+
t1 = { x: 10.0, y: 10.0, z: 10.0 };
|
|
90
|
+
t2 = { x: 10.0 + perturbation, y: 10.0, z: 10.0 };
|
|
91
|
+
t1History = [];
|
|
92
|
+
t2History = [];
|
|
93
|
+
distanceHistory = [];
|
|
94
|
+
lastDistance = perturbation;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function resize(c: HTMLCanvasElement | null, h: number) {
|
|
98
|
+
if (!c || !c.parentElement) return;
|
|
99
|
+
const rect = c.parentElement.getBoundingClientRect();
|
|
100
|
+
c.width = rect.width * window.devicePixelRatio;
|
|
101
|
+
c.height = h * window.devicePixelRatio;
|
|
102
|
+
c.style.width = '100%';
|
|
103
|
+
c.style.height = `${h}px`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function resizeAll() {
|
|
107
|
+
if (canvas && canvas.parentElement) {
|
|
108
|
+
resize(canvas, canvas.parentElement.getBoundingClientRect().height);
|
|
109
|
+
}
|
|
110
|
+
resize(chartCanvas, 80);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function drawAttractor() {
|
|
114
|
+
if (!canvas || !ctx) return;
|
|
115
|
+
const config = { ctx, w: canvas.width, h: canvas.height, rx, ry };
|
|
116
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
117
|
+
drawGrid(config);
|
|
118
|
+
drawShadowPath(config, t1History);
|
|
119
|
+
drawShadowPath(config, t2History);
|
|
120
|
+
ctx.lineWidth = 1.8 * window.devicePixelRatio;
|
|
121
|
+
ctx.lineCap = 'round';
|
|
122
|
+
ctx.lineJoin = 'round';
|
|
123
|
+
const t1Color = getCssVariable('--lorenz-t1', '#00f0ff');
|
|
124
|
+
const t2Color = getCssVariable('--lorenz-t2', '#ff007f');
|
|
125
|
+
drawPath(config, t1History, t1Color);
|
|
126
|
+
drawPath(config, t2History, t2Color);
|
|
127
|
+
ctx.shadowBlur = 8 * window.devicePixelRatio;
|
|
128
|
+
ctx.shadowColor = t1Color;
|
|
129
|
+
drawHead(config, t1, t1Color);
|
|
130
|
+
ctx.shadowColor = t2Color;
|
|
131
|
+
drawHead(config, t2, t2Color);
|
|
132
|
+
ctx.shadowBlur = 0;
|
|
133
|
+
drawAxes(config);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function drawChartBaseline(w: number, h: number) {
|
|
137
|
+
if (!chartCtx) return;
|
|
138
|
+
chartCtx.strokeStyle = getCssVariable('--lorenz-border', 'rgba(255,255,255,0.06)');
|
|
139
|
+
chartCtx.lineWidth = 1 * window.devicePixelRatio;
|
|
140
|
+
chartCtx.setLineDash([4 * window.devicePixelRatio, 4 * window.devicePixelRatio]);
|
|
141
|
+
chartCtx.beginPath();
|
|
142
|
+
chartCtx.moveTo(0, h - 4);
|
|
143
|
+
chartCtx.lineTo(w, h - 4);
|
|
144
|
+
chartCtx.stroke();
|
|
145
|
+
chartCtx.setLineDash([]);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function getMaxDistance(): number {
|
|
149
|
+
let maxDist = 0.01;
|
|
150
|
+
for (let i = 0; i < distanceHistory.length; i++) {
|
|
151
|
+
if (distanceHistory[i] > maxDist) {
|
|
152
|
+
maxDist = distanceHistory[i];
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return maxDist;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function drawChartPath(w: number, h: number, maxDist: number, stepX: number) {
|
|
159
|
+
if (!chartCtx) return;
|
|
160
|
+
chartCtx.strokeStyle = getCssVariable('--lorenz-accent', '#a78bfa');
|
|
161
|
+
chartCtx.lineWidth = 1.5 * window.devicePixelRatio;
|
|
162
|
+
chartCtx.beginPath();
|
|
163
|
+
chartCtx.moveTo(0, h - (distanceHistory[0] / maxDist) * (h - 10));
|
|
164
|
+
for (let i = 1; i < distanceHistory.length; i++) {
|
|
165
|
+
chartCtx.lineTo(i * stepX, h - (distanceHistory[i] / maxDist) * (h - 10));
|
|
166
|
+
}
|
|
167
|
+
chartCtx.stroke();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function fillChartArea(w: number, h: number) {
|
|
171
|
+
if (!chartCtx) return;
|
|
172
|
+
chartCtx.lineTo(w, h);
|
|
173
|
+
chartCtx.lineTo(0, h);
|
|
174
|
+
chartCtx.closePath();
|
|
175
|
+
const gradient = chartCtx.createLinearGradient(0, 0, 0, h);
|
|
176
|
+
gradient.addColorStop(0, `rgba(167, 139, 250, 0.12)`);
|
|
177
|
+
gradient.addColorStop(1, `rgba(167, 139, 250, 0.0)`);
|
|
178
|
+
chartCtx.fillStyle = gradient;
|
|
179
|
+
chartCtx.fill();
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function drawChart() {
|
|
183
|
+
if (!chartCanvas || !chartCtx) return;
|
|
184
|
+
const w = chartCanvas.width;
|
|
185
|
+
const h = chartCanvas.height;
|
|
186
|
+
chartCtx.clearRect(0, 0, w, h);
|
|
187
|
+
drawChartBaseline(w, h);
|
|
188
|
+
if (distanceHistory.length < 2) return;
|
|
189
|
+
const maxDist = getMaxDistance();
|
|
190
|
+
const stepX = w / (maxHistory - 1);
|
|
191
|
+
drawChartPath(w, h, maxDist, stepX);
|
|
192
|
+
fillChartArea(w, h);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function updatePhysics(params: LorenzParams, dt: number): number {
|
|
196
|
+
let currentDist = lastDistance;
|
|
197
|
+
for (let steps = 0; steps < 4; steps++) {
|
|
198
|
+
t1 = LorenzEngine.nextPoint(t1, params, dt);
|
|
199
|
+
t2 = LorenzEngine.nextPoint(t2, params, dt);
|
|
200
|
+
t1History.push({ ...t1 });
|
|
201
|
+
t2History.push({ ...t2 });
|
|
202
|
+
currentDist = LorenzEngine.getDistance(t1, t2);
|
|
203
|
+
distanceHistory.push(currentDist);
|
|
204
|
+
if (t1History.length > maxHistory) {
|
|
205
|
+
t1History.shift();
|
|
206
|
+
t2History.shift();
|
|
207
|
+
distanceHistory.shift();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return currentDist;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function updateUIStats(currentDist: number, diff: number) {
|
|
214
|
+
if (statT1) statT1.textContent = `X:${t1.x.toFixed(1)} Y:${t1.y.toFixed(1)} Z:${t1.z.toFixed(1)}`;
|
|
215
|
+
if (statT2) statT2.textContent = `X:${t2.x.toFixed(1)} Y:${t2.y.toFixed(1)} Z:${t2.z.toFixed(1)}`;
|
|
216
|
+
if (statDist) statDist.textContent = currentDist.toFixed(4);
|
|
217
|
+
if (statDelta) {
|
|
218
|
+
if (Math.abs(diff) < 0.0001) {
|
|
219
|
+
statDelta.textContent = '--';
|
|
220
|
+
} else if (diff > 0) {
|
|
221
|
+
statDelta.textContent = `▲ +${diff.toFixed(4)}`;
|
|
222
|
+
} else {
|
|
223
|
+
statDelta.textContent = `▼ ${diff.toFixed(4)}`;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function loop() {
|
|
229
|
+
if (isRunning) {
|
|
230
|
+
const params = getParams();
|
|
231
|
+
const dt = getDt();
|
|
232
|
+
const currentDist = updatePhysics(params, dt);
|
|
233
|
+
const diff = currentDist - lastDistance;
|
|
234
|
+
lastDistance = currentDist;
|
|
235
|
+
updateUIStats(currentDist, diff);
|
|
236
|
+
}
|
|
237
|
+
drawAttractor();
|
|
238
|
+
drawChart();
|
|
239
|
+
requestAnimationFrame(loop);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
canvas.addEventListener('pointerdown', (e) => {
|
|
243
|
+
isDragging = true;
|
|
244
|
+
previousMousePosition = { x: e.clientX, y: e.clientY };
|
|
245
|
+
canvas.setPointerCapture(e.pointerId);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
window.addEventListener('pointerup', () => {
|
|
249
|
+
isDragging = false;
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
window.addEventListener('pointermove', (e) => {
|
|
253
|
+
if (!isDragging) return;
|
|
254
|
+
ry += (e.clientX - previousMousePosition.x) * 0.01;
|
|
255
|
+
rx += (e.clientY - previousMousePosition.y) * 0.01;
|
|
256
|
+
previousMousePosition = { x: e.clientX, y: e.clientY };
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
slideSigma.addEventListener('input', () => { updateDisplays(); clearPaths(); });
|
|
260
|
+
slideRho.addEventListener('input', () => { updateDisplays(); clearPaths(); });
|
|
261
|
+
slideBeta.addEventListener('input', () => { updateDisplays(); clearPaths(); });
|
|
262
|
+
slideDt.addEventListener('input', () => { updateDisplays(); clearPaths(); });
|
|
263
|
+
slidePerturb.addEventListener('input', () => { updateDisplays(); clearPaths(); });
|
|
264
|
+
|
|
265
|
+
btnPlayPause.addEventListener('click', () => {
|
|
266
|
+
isRunning = !isRunning;
|
|
267
|
+
btnPlayPause.textContent = isRunning ? (btnPlayPause.dataset.pause || 'Pause') : (btnPlayPause.dataset.play || 'Resume');
|
|
268
|
+
btnPlayPause.className = isRunning ? 'lorenz-btn lorenz-btn-active-state' : 'lorenz-btn';
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
btnReset.addEventListener('click', resetToDefaults);
|
|
272
|
+
btnClear.addEventListener('click', clearPaths);
|
|
273
|
+
|
|
274
|
+
window.addEventListener('resize', resizeAll);
|
|
275
|
+
|
|
276
|
+
btnPlayPause.dataset.pause = btnPlayPause.textContent || 'Pause';
|
|
277
|
+
btnPlayPause.dataset.play = 'Resume';
|
|
278
|
+
|
|
279
|
+
resizeAll();
|
|
280
|
+
updateDisplays();
|
|
281
|
+
clearPaths();
|
|
282
|
+
loop();
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { SEORenderer } from '@jjlmoya/utils-shared';
|
|
3
|
+
import { lorenzAttractor } from './index';
|
|
4
|
+
import type { KnownLocale } from '../../types';
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
locale?: KnownLocale;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const { locale = 'es' } = Astro.props;
|
|
11
|
+
const content = await lorenzAttractor.i18n[locale]?.();
|
|
12
|
+
if (!content) return null;
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
{content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
import { Bibliography } from '@jjlmoya/utils-shared';
|
|
2
|
+
import { Bibliography as SharedBibliography } from '@jjlmoya/utils-shared';
|
|
3
3
|
import { microwaveDetector } from './index';
|
|
4
4
|
import type { KnownLocale } from '../../types';
|
|
5
5
|
|
|
@@ -11,4 +11,4 @@ const { locale = 'es' } = Astro.props;
|
|
|
11
11
|
const content = await microwaveDetector.i18n[locale]?.();
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
-
{content && <
|
|
14
|
+
{content && <SharedBibliography links={content.bibliography} />}
|
|
@@ -87,7 +87,7 @@ const { ui } = Astro.props;
|
|
|
87
87
|
if (root) {
|
|
88
88
|
const startBtn = document.getElementById("start-btn");
|
|
89
89
|
const modal = document.getElementById("initial-modal");
|
|
90
|
-
const canvas = document.getElementById("interference-canvas");
|
|
90
|
+
const canvas = document.getElementById("interference-canvas") as HTMLCanvasElement | null;
|
|
91
91
|
const ctx = canvas?.getContext("2d");
|
|
92
92
|
|
|
93
93
|
const jitterDisplay = document.getElementById("jitter-value");
|
|
@@ -104,7 +104,7 @@ const { ui } = Astro.props;
|
|
|
104
104
|
const engine = new MicrowaveEngine(currentLang);
|
|
105
105
|
let running = false;
|
|
106
106
|
let audioEnabled = true;
|
|
107
|
-
let audioCtx = null;
|
|
107
|
+
let audioCtx: AudioContext | null = null;
|
|
108
108
|
|
|
109
109
|
const history = new Array(60).fill(0);
|
|
110
110
|
|
|
@@ -143,10 +143,12 @@ const { ui } = Astro.props;
|
|
|
143
143
|
ctx.fill();
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
-
async function playClick(_intensity) {
|
|
146
|
+
async function playClick(_intensity: number) {
|
|
147
147
|
if (!audioEnabled) return;
|
|
148
|
-
if (!audioCtx)
|
|
149
|
-
|
|
148
|
+
if (!audioCtx) {
|
|
149
|
+
const AudioContextClass = window.AudioContext || (window as unknown as { webkitAudioContext: typeof AudioContext }).webkitAudioContext;
|
|
150
|
+
audioCtx = new AudioContextClass();
|
|
151
|
+
}
|
|
150
152
|
|
|
151
153
|
const osc = audioCtx.createOscillator();
|
|
152
154
|
const gain = audioCtx.createGain();
|
|
@@ -176,7 +178,7 @@ const { ui } = Astro.props;
|
|
|
176
178
|
};
|
|
177
179
|
|
|
178
180
|
if (verdictContainer) {
|
|
179
|
-
const colors = colorMap[level.color] || colorMap.emerald;
|
|
181
|
+
const colors = colorMap[level.color as keyof typeof colorMap] || colorMap.emerald;
|
|
180
182
|
verdictContainer.style.backgroundColor = colors.bg;
|
|
181
183
|
verdictContainer.style.borderColor = colors.border;
|
|
182
184
|
verdictContainer.style.color = colors.text;
|
|
@@ -189,7 +191,7 @@ const { ui } = Astro.props;
|
|
|
189
191
|
orange: "#f97316",
|
|
190
192
|
red: "#dc2626",
|
|
191
193
|
};
|
|
192
|
-
statusDot.style.backgroundColor = colorValues[level.color] || colorValues.emerald;
|
|
194
|
+
statusDot.style.backgroundColor = colorValues[level.color as keyof typeof colorValues] || colorValues.emerald;
|
|
193
195
|
}
|
|
194
196
|
}
|
|
195
197
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const description = 'Analysez si votre micro-ondes perd des radiations en mesurant l\'interférence en temps réel sur votre réseau WiFi. Outil de sécurité scientifique.';
|
|
2
|
-
const title = 'Détecteur de Fuites Micro ondes
|
|
2
|
+
const title = 'Détecteur de Fuites Micro ondes: Visualiseur d\'Interférences WiFi';
|
|
3
3
|
const slug = 'detecteur-fuites-micro-ondes';
|
|
4
4
|
const howTo = [
|
|
5
5
|
{
|
|
@@ -79,7 +79,7 @@ export const content: ToolLocaleContent = {
|
|
|
79
79
|
seo: [
|
|
80
80
|
{
|
|
81
81
|
type: 'title',
|
|
82
|
-
text: 'PHYSIQUE DES ONDES
|
|
82
|
+
text: 'PHYSIQUE DES ONDES: Votre micro-ondes fuit-il réellement des radiations ?',
|
|
83
83
|
level: 2,
|
|
84
84
|
},
|
|
85
85
|
{
|
|
@@ -88,7 +88,7 @@ export const content: ToolLocaleContent = {
|
|
|
88
88
|
},
|
|
89
89
|
{
|
|
90
90
|
type: 'paragraph',
|
|
91
|
-
html: 'D\'un point de vue purement physique, un four à micro-ondes est un <strong>résonateur à cavité</strong> conçu pour bombarder les molécules d\'eau de radiations électromagnétiques à une fréquence très spécifique
|
|
91
|
+
html: 'D\'un point de vue purement physique, un four à micro-ondes est un <strong>résonateur à cavité</strong> conçu pour bombarder les molécules d\'eau de radiations électromagnétiques à une fréquence très spécifique: <strong>2,45 GHz</strong>. Cette fréquence n\'est pas arbitraire ; elle est nécessaire pour provoquer l\'oscillation dipolaire des particules d\'eau, générant de la chaleur par friction. Le problème est que c\'est exactement la même fréquence que celle utilisée par la norme WiFi 802.11b/g/n.',
|
|
92
92
|
},
|
|
93
93
|
{
|
|
94
94
|
type: 'title',
|
|
@@ -128,7 +128,7 @@ export const content: ToolLocaleContent = {
|
|
|
128
128
|
type: 'list',
|
|
129
129
|
items: [
|
|
130
130
|
'<strong>"Le micro-ondes altère la structure moléculaire de l\'eau"</strong> - FAUX. Le rayonnement micro-ondes est <em>non ionisant</em>. Il n\'a pas assez d\'énergie pour rompre les liaisons chimiques ou altérer l\'ADN. Il fait simplement vibrer les molécules d\'eau, augmentant leur énergie cinétique (température).',
|
|
131
|
-
'<strong>"Le rayonnement s\'accumule dans les aliments"</strong> - FAUX. Les micro-ondes sont comme la lumière
|
|
131
|
+
'<strong>"Le rayonnement s\'accumule dans les aliments"</strong> - FAUX. Les micro-ondes sont comme la lumière: une fois que vous éteignez l\'interrupteur, elles disparaissent. Un aliment chaud n\'émet pas de rayonnement micro-ondes, seulement un rayonnement infrarouge (chaleur) tout comme un feu ou une poêle.',
|
|
132
132
|
'<strong>"Regarder le plateau tourner endommage les yeux"</strong> - PARTIELLEMENT VRAI. La vitre de la porte est conçue avec une grille qui bloque les longueurs d\'onde de 2,45 GHz. Cependant, si la grille est endommagée, la vitre n\'arrêtera pas les micro-ondes. Le cristallin de l\'œil est très sensible à la chaleur et a une mauvaise circulation sanguine, donc une exposition directe prolongée (près d\'une fuite) pourrait causer des cataractes thermiques.',
|
|
133
133
|
],
|
|
134
134
|
},
|
|
@@ -8,25 +8,25 @@ const howTo = [
|
|
|
8
8
|
},
|
|
9
9
|
{
|
|
10
10
|
name: 'Запустите базовый тест задержки',
|
|
11
|
-
text: 'Нажмите кнопку
|
|
11
|
+
text: 'Нажмите кнопку "Начать" при выключенной микроволновке, чтобы установить стабильный базовый уровень соединения.',
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
14
|
name: 'Включите микроволноку',
|
|
15
|
-
text: 'Разогрейте стакан воды в течение 30
|
|
15
|
+
text: 'Разогрейте стакан воды в течение 30-60 секунд и встаньте рядом с прибором со своим устройством.',
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
18
|
name: 'Проанализируйте график',
|
|
19
|
-
text: 'Наблюдайте, поднимается ли задержка выше 100
|
|
19
|
+
text: 'Наблюдайте, поднимается ли задержка выше 100-200 мс или случаются ли потери пакетов во время работы прибора.',
|
|
20
20
|
},
|
|
21
21
|
];
|
|
22
22
|
const faq = [
|
|
23
23
|
{
|
|
24
24
|
question: 'Как веб-сайт может обнаружить мою микроволновку?',
|
|
25
|
-
answer: 'Мы используем не магические сенсоры, а задержку сети. Как WiFi 2,4 ГГц, так и микроволновые печи работают на одной частоте (около 2450 МГц). Если экранирование микроволновки нарушено, оно создает
|
|
25
|
+
answer: 'Мы используем не магические сенсоры, а задержку сети. Как WiFi 2,4 ГГц, так и микроволновые печи работают на одной частоте (около 2450 МГц). Если экранирование микроволновки нарушено, оно создает "шум", который сталкивается с WiFi, резко увеличивая задержку (пинг).',
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
28
|
question: 'Опасно ли, если моя микроволновка пропускает излучение?',
|
|
29
|
-
answer: 'Небольшие помехи WiFi
|
|
29
|
+
answer: 'Небольшие помехи WiFi - это нормально и не несут немедленного риска для здоровья, так как мощность быстро падает с расстоянием. Однако сильная утечка указывает на плохую герметичность дверцы или сетки, что следует проверить в целях технической безопасности.',
|
|
30
30
|
},
|
|
31
31
|
{
|
|
32
32
|
question: 'Почему тест не работает с WiFi 5 ГГц?',
|
|
@@ -34,7 +34,7 @@ const faq = [
|
|
|
34
34
|
},
|
|
35
35
|
{
|
|
36
36
|
question: 'Что означают скачки задержки на графике?',
|
|
37
|
-
answer: 'Постоянные скачки во время работы микроволновки говорят о том, что электромагнитный сигнал
|
|
37
|
+
answer: 'Постоянные скачки во время работы микроволновки говорят о том, что электромагнитный сигнал "утекает" наружу и насыщает эфир, не давая пакетам данных WiFi приходить вовремя.',
|
|
38
38
|
},
|
|
39
39
|
];
|
|
40
40
|
import { bibliography } from '../bibliography';
|
|
@@ -84,11 +84,11 @@ export const content: ToolLocaleContent = {
|
|
|
84
84
|
},
|
|
85
85
|
{
|
|
86
86
|
type: 'paragraph',
|
|
87
|
-
html: 'Микроволновка
|
|
87
|
+
html: 'Микроволновка - самый недопонятый прибор на современной кухне. Ее ненавидят пуристы и любят прагматики, но за ней скрывается постоянная борьба между замкнутой энергией и внешним миром.',
|
|
88
88
|
},
|
|
89
89
|
{
|
|
90
90
|
type: 'paragraph',
|
|
91
|
-
html: 'С чисто физической точки зрения микроволновая печь
|
|
91
|
+
html: 'С чисто физической точки зрения микроволновая печь - это <strong>объемный резонатор</strong>, предназначенный для бомбардировки молекул воды электромагнитным излучением на строго определенной частоте: <strong>2,45 ГГц</strong>. Эта частота не случайна; она необходима для вызова дипольных колебаний частиц воды, генерирующих тепло за счет трения. Проблема в том, что это именно та частота, которую использует стандарт WiFi 802.11b/g/n.',
|
|
92
92
|
},
|
|
93
93
|
{
|
|
94
94
|
type: 'title',
|
|
@@ -97,11 +97,11 @@ export const content: ToolLocaleContent = {
|
|
|
97
97
|
},
|
|
98
98
|
{
|
|
99
99
|
type: 'paragraph',
|
|
100
|
-
html: 'Любое WiFi-устройство, работающее в диапазоне 2,4 ГГц, конкурирует за тот же
|
|
100
|
+
html: 'Любое WiFi-устройство, работающее в диапазоне 2,4 ГГц, конкурирует за тот же "воздух", что и ваша микроволновка. В идеальной печи <strong>клетка Фарадея</strong> (металлическая сетка, которую вы видите на дверце и внутренних стенках) должна удерживать 100% энергии.',
|
|
101
101
|
},
|
|
102
102
|
{
|
|
103
103
|
type: 'paragraph',
|
|
104
|
-
html: 'Однако ни одна клетка не идеальна в долгосрочной перспективе. Уплотнители дверцы, магнитные защелки и износ металла могут привести к утечке небольшого количества энергии. Хотя эти уровни обычно значительно ниже пределов безопасности для человека, они <strong>огромны</strong> для сетевой карты WiFi, вызывая задержки, потерю пакетов и характерный
|
|
104
|
+
html: 'Однако ни одна клетка не идеальна в долгосрочной перспективе. Уплотнители дверцы, магнитные защелки и износ металла могут привести к утечке небольшого количества энергии. Хотя эти уровни обычно значительно ниже пределов безопасности для человека, они <strong>огромны</strong> для сетевой карты WiFi, вызывая задержки, потерю пакетов и характерный "джиттер", который измеряет наш инструмент.',
|
|
105
105
|
},
|
|
106
106
|
{
|
|
107
107
|
type: 'title',
|
|
@@ -115,8 +115,8 @@ export const content: ToolLocaleContent = {
|
|
|
115
115
|
{
|
|
116
116
|
type: 'list',
|
|
117
117
|
items: [
|
|
118
|
-
'<strong>Шаг 1
|
|
119
|
-
'<strong>Шаг 2
|
|
118
|
+
'<strong>Шаг 1 - Телефон:</strong> Положите мобильный телефон внутрь микроволновки (<strong>НИ ПРИ КАКИХ ОБСТОЯТЕЛЬСТВАХ НЕ ВКЛЮЧАЙТЕ ПЕЧЬ!</strong> Просто закройте дверцу).',
|
|
119
|
+
'<strong>Шаг 2 - Звонок:</strong> Попробуйте позвонить на этот телефон с другого устройства. Если телефон зазвонит, клетка Фарадея неисправна или не настроена на сотовые частоты. Если абонент "вне зоны доступа", экранирование работает правильно.',
|
|
120
120
|
],
|
|
121
121
|
},
|
|
122
122
|
{
|
|
@@ -127,9 +127,9 @@ export const content: ToolLocaleContent = {
|
|
|
127
127
|
{
|
|
128
128
|
type: 'list',
|
|
129
129
|
items: [
|
|
130
|
-
'<strong
|
|
131
|
-
'<strong
|
|
132
|
-
'<strong
|
|
130
|
+
'<strong>"Микроволновки изменяют молекулярную структуру воды"</strong> - ЛОЖЬ. Микроволновое излучение является <em>неионизирующим</em>. У него недостаточно энергии, чтобы разорвать химические связи или изменить ДНК. Оно просто заставляет молекулы воды вибрировать, увеличивая их кинетическую энергию (температуру).',
|
|
131
|
+
'<strong>"Радиация накапливается в еде"</strong> - ЛОЖЬ. Микроволны подобны свету: как только вы выключаете выключатель, они исчезают. Горячая еда не испускает микроволновое излучение, только инфракрасное (тепло), точно так же, как костер или сковорода.',
|
|
132
|
+
'<strong>"Наблюдение за вращающейся тарелкой портит зрение"</strong> - ОТЧАСТИ ПРАВДА. Стекло дверцы снабжено сеткой, блокирующей волны 2,45 ГГц. Однако, если сетка повреждена, стекло не остановит микроволны. Хрусталик глаза очень чувствителен к нагреву и плохо снабжается кровью, поэтому длительное прямое воздействие (рядом с утечкой) может вызвать тепловую катаракту.',
|
|
133
133
|
],
|
|
134
134
|
},
|
|
135
135
|
{
|
|
@@ -139,15 +139,15 @@ export const content: ToolLocaleContent = {
|
|
|
139
139
|
},
|
|
140
140
|
{
|
|
141
141
|
type: 'paragraph',
|
|
142
|
-
html: 'Наш инструмент не измеряет радиацию напрямую (в смартфонах нет таких датчиков), но он измеряет <strong>главный симптом</strong>. Когда частица излучения 2,45 ГГц покидает печь, она
|
|
142
|
+
html: 'Наш инструмент не измеряет радиацию напрямую (в смартфонах нет таких датчиков), но он измеряет <strong>главный симптом</strong>. Когда частица излучения 2,45 ГГц покидает печь, она "сталкивается" с WiFi-сигналом вашего устройства. Это вызывает:',
|
|
143
143
|
},
|
|
144
144
|
{
|
|
145
145
|
type: 'list',
|
|
146
146
|
items: [
|
|
147
147
|
'<strong>Повторную передачу пакетов:</strong> Роутер обнаруживает, что сообщение пришло поврежденным, и вынужден отправить его снова, что увеличивает задержку.',
|
|
148
|
-
'<strong>Вариацию джиттера:</strong> Это показатель нестабильности времени отклика. Высокий джиттер
|
|
148
|
+
'<strong>Вариацию джиттера:</strong> Это показатель нестабильности времени отклика. Высокий джиттер - однозначный признак массовых внешних помех.',
|
|
149
149
|
'<strong>Падение производительности:</strong> Скорость передачи падает из-за насыщения радиочастотного спектра.',
|
|
150
|
-
'<strong>Фоновый шум:</strong> Микроволновка вносит шум, который повышает
|
|
150
|
+
'<strong>Фоновый шум:</strong> Микроволновка вносит шум, который повышает "порог шума", из-за чего устройству становится трудно отличить реальные данные от радиоактивного хаоса.',
|
|
151
151
|
],
|
|
152
152
|
},
|
|
153
153
|
],
|