-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontent.js
More file actions
744 lines (687 loc) · 63.7 KB
/
Copy pathcontent.js
File metadata and controls
744 lines (687 loc) · 63.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
let content = [
{
id: 0,
title: "¿Por qué la vivienda y el alquiler son tan caros en España? Una bomba social en plena cuenta atrás",
preview: "/assets/img/0-0.webp",
content: `En España, encontrar una vivienda digna a un precio razonable se ha convertido en una auténtica odisea.
Comprar un piso o incluso alquilar uno, especialmente en las grandes ciudades, se ha transformado en un lujo que muchos no pueden permitirse. ¿Pero por qué? ¿Qué nos ha llevado hasta aquí?
¿Y, lo más importante, qué demonios se puede hacer al respecto?
<br><br><img src="/assets/img/0-1.webp" alt="Políticos ciegos, pueblo ahogado" class="img-fluid" /><br><br>
<h4>#1. El ladrillo como refugio para el ahorro</h4>
<br>
En un país donde los bancos no ofrecen prácticamente rentabilidad por los ahorros y la cultura del ahorro tradicional sigue muy viva, ¿qué hace la gente cuando tiene dinero? Lo mete en ladrillo. Comprar una vivienda se ha convertido en una de las pocas formas de "guardar" valor, de protegerse del futuro, y de paso, alquilarla o venderla más adelante con beneficios. Y esto no es algo que ocurra solo a nivel nacional.
<br><br>
<h4>#2. España, paraíso del comprador extranjero</h4>
<br>
España se ha convertido en el destino ideal para extranjeros con alto poder adquisitivo. Desde alemanes, británicos o franceses hasta fondos de inversión internacionales que ven en nuestras ciudades y costas una oportunidad dorada. ¿Consecuencia directa? Aumenta la presión sobre los precios, y el español medio, con su sueldo congelado y su bolsillo cada vez más exprimido, simplemente no puede competir. Con esto no pretendo decir que hay que prohibir comprar las viviendas a un inverson extranjero, si no simplemente es un punto más que hay que tener en cuenta. Y el problema principal en esta cuestion esta que en el que el "comprador nacional" no puede competir con el "comprador extranjero" pricisamente por el bajo poder adquisitivo del "comprador nacional".
<br><br>
<h4>#3. La inseguridad jurídica y la plaga de la ocupación</h4>
<br>
Y aquí viene lo más sangrante: la inseguridad. ¿Qué propietario se anima a alquilar si sabe que, si le ocupan el piso, tendrá que armarse de paciencia, dinero y abogados durante meses (o años) para recuperarlo? Es absurdo. El gobierno, en vez de proteger a quien ha trabajado toda su vida para comprarse una casa, parece premiar al ocupa. Sí, has leído bien: más derechos para el que entra a la fuerza que para el legítimo dueño. Resultado: miles y miles de viviendas cerradas a cal y canto. Y eso, evidentemente, reduce la oferta y dispara el precio del alquiler.
<br><br>
<h4>4. El nivel adquisitivo bajo y el infierno fiscal español</h4>
<br>
Sumemos a todo esto unos salarios miserables y una carga fiscal que da miedo. Pagamos impuestos como si viviéramos en Suiza, pero los servicios públicos, en muchos casos, rozan la chapuza. No hay vivienda pública suficiente, ni medidas reales para incentivar el alquiler, ni ayudas que lleguen a quien realmente las necesita. Lo que sí hay es burocracia, papeleo, y pérdida de tiempo.
<br><img src="/assets/img/0-2.webp" alt="¿Propietario o rehén?" class="img-fluid" /><br><br>
<h4>5. Las “ayudas al alquiler”: otra tomadura de pelo</h4>
Se llenan la boca hablando de “ayudas al alquiler”. Pero cuando rascas un poco ves el chiste: limitadas por edad, por mil requisitos, gestionadas por oficinas que cuestan millones en sueldos, electricidad y mantenimiento. Y mientras tanto, para financiar estas ayudas, te crujen a impuestos a ti, que trabajas, que pagas, que cumples. Es decir, primero te dejan sin dinero y luego te venden la limosna como si fuera un favor.
<br><br>
Y aún hay más: la gente tiene que dar vueltas presentando documentos, perdiendo días de trabajo o haciendo colas infinitas. ¿Y al final? Ni siquiera está garantizado que la ayuda llegue. Cuando se hace el cálculo global, lo que se ha gastado para dar esas ayudas supera con creces el beneficio real. Un sinsentido.
<br><br>
<h3>¿Qué se puede hacer?</h3>
Sí, hay soluciones. No son fáciles, no son rápidas, pero son reales.
<br><br>
✅ Desahucio exprés y policía local que sirva para algo
Basta ya de premiar al que ocupa. Si alguien irrumpe en tu propiedad, el proceso debería ser simple: una llamada a la policía local y desalojo inmediato. Punto. Porque esa misma policía, que cuesta un dineral a los contribuyentes, está muchas veces dando vueltas por el pueblo sin más. Que al menos sirva para algo útil: proteger al ciudadano honesto.
<br><br>
✅ Seguridad jurídica para el propietario = más oferta = alquileres más bajos
Si se garantiza que el propietario no va a perder su casa por alquilarla, habrá más viviendas en el mercado. Y como en cualquier mercado, cuando hay más oferta, bajan los precios. Es tan sencillo como eso.
<br><br>
✅ Menos impuestos, más poder adquisitivo
Si bajamos la presión fiscal sobre los trabajadores, si dejamos de asfixiar a la clase media, la gente tendrá más dinero en el bolsillo. Y si hay más dinero, hay más consumo, más movimiento, más economía real. Pero claro, eso requiere trabajo serio, no propaganda de saldo.
<br><br>
✅ Revitalizar la España vaciada
No todo el mundo quiere vivir en Madrid o Barcelona. Pero tampoco se puede vivir en un pueblo donde no hay médicos, ni internet, ni oportunidades. Invertir en la España rural sería una medida de largo plazo, pero real. No fotos para Twitter, sino escuelas, centros de salud, transporte. Vida, en definitiva.
<br><br>
<h3>Conclusión: basta de parches, hace falta visión</h3>
Lo que vemos hoy en el mercado inmobiliario español es el resultado de años de decisiones mal tomadas, de mirar para otro lado, de contentarse con medidas inútiles. Hay que proteger al que cumple, al que trabaja, al que se esfuerza. Hay que dejarse de ideología barata y actuar con sentido común.
<br><br>
Porque si seguimos así, el futuro no traerá ni vivienda, ni alquileres asequibles, ni dignidad para el ciudadano. Solo más frustración, más desigualdad… y más ocupas.
<br><br>
<h3>❌ Y lo peor: una clase política inepta, ciega y completamente desconectada de la realidad</h3>
<br><br>
Pero si hay algo que agrava esta situación todavía más es el nivel lamentable de nuestra clase política. Ineptos, ciegos y, con perdón, gilipollas. En vez de estar centrados en solucionar los problemas reales que afectan a millones de españoles —como el precio de la vivienda, los sueldos ridículos o la falta de oportunidades— están más preocupados por cambiar el lenguaje, inventar géneros nuevos o montar debates estériles sobre “elles”, “ellxs” y demás tonterías de salón.
<br><br>
¿Soluciones reales? Cero. ¿Políticas que de verdad impacten en la vida de la gente? Nada. Solo postureo, propaganda y una desconexión total de lo que pasa en la calle. Mientras tanto, siguen trayendo a España a gente que muchas veces no comparte ni respeta los valores de Europa, ni de nuestra sociedad, ni de nuestra convivencia. Y no contentos con eso, meten ruido con ideologías extremas, con teorías absurdas sobre identidad, mientras la gente aquí no puede ni pagar un alquiler digno.
<br><br>
En resumen: están haciendo cualquier cosa menos lo que tienen que hacer. Son incapaces de gestionar, de priorizar, de tener un mínimo de sentido común. Mientras tanto, tú, yo, y la mayoría, seguimos pagando la fiesta.
<br><br>
<h3>🕰️ Es la hora de cambiar las cosas</h3>
Ya está bien. Ya va siendo hora de despertar. De exigir soluciones reales, no parches. De dejar de votar al que promete humo y empezar a apoyar a quien defienda con hechos la dignidad de vivir en España. Hay que devolver la seguridad al propietario, mejorar el poder adquisitivo del ciudadano, y dejar de lado las ideologías baratas que solo distraen del verdadero desastre que tenemos encima.
<br><br>
Porque si no lo hacemos nosotros, no lo va a hacer nadie.
<br>
Porque merecemos un país donde vivir no sea un lujo.
<br>
Porque ya toca que España funcione para los que trabajan, para los que se esfuerzan, para los que la sostienen cada día.
`,
slug:"Por-qué-la-vivienda-y-el-alquiler-son-tan-caros-en-España",
tags: ["Social", "Alquiler", "Vivienda"],
date: "23/03/2025",
description: "El problema de la vivienda en España no se resolverá con medidas superficiales ni con ideologías vacías. Es necesario un cambio real en la gestión política, con soluciones prácticas que protejan a quienes trabajan y contribuyen al país. Sin acción efectiva, la situación solo empeorará, aumentando la desigualdad y la frustración de los ciudadanos."
},
{
id: 1,
title: "Inteligencia Artificial en JavaScript",
preview: "https://suzdalenko-dev.github.io/ia/img/1-3.png",
content: `<p>
La inteligencia artificial (IA) se ha convertido en una de las tecnologías más innovadoras del desarrollo de software moderno.
Pero, ¿cómo funciona realmente una red neuronal desde adentro? Para comprenderlo paso a paso, vamos a crear una red neuronal muy básica
usando solo JavaScript puro —sin bibliotecas externas.
</p>
<h4>#1. Ejemplo básico: Una neurona artificial en JavaScript</h4>
<p>
Una neurona artificial es la unidad fundamental de una red neuronal. Su comportamiento puede modelarse usando tres componentes esenciales:
</p>
<ul>
<li><strong>📌 Pesos (Weights):</strong>Los pesos determinan la influencia de cada entrada en la neurona. Son valores numéricos que multiplican las entradas. <br>
👉 Ejemplo: <br>
Si tienes una entrada x = 0.3 y un peso w=0.8, el resultado ponderado será: <br>
x × w = 0.3 × 0.8 = 0.24 <br>
Un peso alto significa que la entrada tiene más impacto en la salida de la neurona. <br>
</li>
<li><strong>📌 2. Sesgo (Bias):</strong> El sesgo es un número que se suma al cálculo final de la neurona. Permite desplazar la función de activación para que la neurona pueda responder mejor a diferentes casos. <br>
👉 Ejemplo: <br>
Si la salida ponderada es 0.24 y el sesgo es 0.1, entonces: <br>
0.24 + 0.1 = 0.34 <br>
El sesgo ayuda a la neurona a no depender exclusivamente de las entradas y a tomar decisiones más flexibles. <br>
</li>
<li><strong>📌 3. Función de activación:</strong> Esta función decide si la neurona se "activa" o no. En este caso, usaremos un umbral simple: <br>
Si el valor es menor que 0.5, la neurona devuelve 0; de lo contrario, devuelve 1. <br>
function activation(x) { return x < 0.5 ? 0 : 1; } <br><br>
</li>
</ul>
<img src="https://suzdalenko-dev.github.io/ia/img/0-1.png" alt="Perceptrón" class="img-fluid" /><br><br>
<p><strong>🤖 Código: Perceptrón en JavaScript (con explicación)</strong></p>
<div class="vscode-header">perceptron.js</div>
<div class="vscode-editor">
<code>
<span class="comment">// Clase que representa una neurona artificial tipo Perceptrón</span><br>
<span class="keyword">class</span> <span class="variable">Perceptron</span> {<br><br>
<span class="comment">// Constructor: inicializa el peso, el sesgo y la tasa de aprendizaje</span><br>
<span class="method">constructor</span>() {<br>
<span class="comment">// Peso (Weight): determina cuánta influencia tiene la entrada</span><br>
<span class="keyword">this</span>.<span class="variable">weight</span> = <span class="method">Math</span>.<span class="method">random</span>();<br>
<span class="comment">// Sesgo (Bias): permite desplazar la función de activación</span><br>
<span class="keyword">this</span>.<span class="variable">bias</span> = <span class="method">Math</span>.<span class="method">random</span>();<br>
<span class="comment">// Learning rate: controla la velocidad de aprendizaje</span><br>
<span class="keyword">this</span>.<span class="variable">learningRate</span> = <span class="number">0.1</span>;<br>
}<br><br>
<span class="comment">// Función de activación:</span><br>
<span class="comment">// Devuelve 1 si la suma ponderada supera el umbral (0.5), 0 en caso contrario</span><br>
<span class="method">activation</span>(<span class="variable">x</span>) {<br>
<span class="keyword">return</span> <span class="variable">x</span> > <span class="number">0.5</span> ? <span class="number">1</span> : <span class="number">0</span>;<br>
}<br><br>
<span class="comment">// Predicción: calcula la salida del perceptrón</span><br>
<span class="comment">// Suma ponderada: input * peso + sesgo</span><br>
<span class="method">predict</span>(<span class="variable">input</span>) {<br>
<span class="keyword">let</span> <span class="variable">sum</span> = <span class="variable">input</span> * <span class="keyword">this</span>.<span class="variable">weight</span> + <span class="keyword">this</span>.<span class="variable">bias</span>;<br>
<span class="keyword">return</span> <span class="keyword">this</span>.<span class="method">activation</span>(<span class="variable">sum</span>);<br>
}<br><br>
<span class="comment">// Entrenamiento: ajusta peso y sesgo durante 200 épocas</span><br>
<span class="method">train</span>(<span class="variable">inputs</span>, <span class="variable">labels</span>, <span class="variable">epochs</span> = <span class="number">200</span>) {<br>
<span class="keyword">for</span> (<span class="keyword">let</span> <span class="variable">i</span> = <span class="number">0</span>; <span class="variable">i</span> < <span class="variable">epochs</span>; <span class="variable">i</span>++) {<br>
<span class="keyword">for</span> (<span class="keyword">let</span> <span class="variable">j</span> = <span class="number">0</span>; <span class="variable">j</span> < <span class="variable">inputs</span>.<span class="method">length</span>; <span class="variable">j</span>++) {<br>
<span class="keyword">let</span> <span class="variable">prediction</span> = <span class="keyword">this</span>.<span class="method">predict</span>(<span class="variable">inputs</span>[<span class="variable">j</span>]);<br>
<span class="keyword">let</span> <span class="variable">error</span> = <span class="variable">labels</span>[<span class="variable">j</span>] - <span class="variable">prediction</span>;<br><br>
<span class="comment">// Ajuste del peso y del sesgo basado en el error</span><br>
<span class="keyword">this</span>.<span class="variable">weight</span> += <span class="variable">error</span> * <span class="variable">inputs</span>[<span class="variable">j</span>] * <span class="keyword">this</span>.<span class="variable">learningRate</span>;<br>
<span class="keyword">this</span>.<span class="variable">bias</span> += <span class="variable">error</span> * <span class="keyword">this</span>.<span class="variable">learningRate</span>;<br>
}<br>
}<br>
}<br>
}<br><br>
<span class="comment">// Crear y entrenar el perceptrón</span><br>
<span class="keyword">let</span> <span class="variable">perceptron</span> = <span class="keyword">new</span> <span class="variable">Perceptron</span>();<br><br>
<span class="comment">// Entrenamos con datos: menores a 0.5 = 0, mayores o iguales = 1</span><br>
<span class="keyword">let</span> <span class="variable">trainingInputs</span> = [<span class="number">0.1</span>, <span class="number">0.2</span>, <span class="number">0.333</span>, <span class="number">0.4</span>, <span class="number">0.5</span>, <span class="number">0.8</span>, <span class="number">0.9</span>];<br>
<span class="keyword">let</span> <span class="variable">trainingLabels</span> = [<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>];<br><br>
<span class="variable">perceptron</span>.<span class="method">train</span>(<span class="variable">trainingInputs</span>, <span class="variable">trainingLabels</span>);<br><br>
<span class="comment">// Probamos el perceptrón</span><br>
<span class="variable">console</span>.<span class="method">log</span>(<span class="string">"Predicción para 0.3:"</span>, <span class="variable">perceptron</span>.<span class="method">predict</span>(<span class="number">0.3</span>));<br>
<span class="variable">console</span>.<span class="method">log</span>(<span class="string">"Predicción para 0.7:"</span>, <span class="variable">perceptron</span>.<span class="method">predict</span>(<span class="number">0.7</span>));<br><br>
<span class="comment">// Mostrar los pesos aprendidos</span><br>
<span class="variable">console</span>.<span class="method">log</span>(<span class="string">"Peso:"</span>, <span class="variable">perceptron</span>.<span class="variable">weight</span>);<br>
<span class="variable">console</span>.<span class="method">log</span>(<span class="string">"Sesgo:"</span>, <span class="variable">perceptron</span>.<span class="variable">bias</span>);
</code>
</div>
<br>
<p>
Resultado de la ejecución del código anterior:
</p>
<iframe width="100%" height="111px" src="https://suzdalenko-dev.github.io/ia/0.js/0.html" title="Inteligencia Artificial en JavaScript"></iframe>
<p>
Este código nos muestra cómo funciona la inteligencia artificial utilizando una sola neurona artificial, llamada perceptrón.<br><br>
Primero, se entrena con ejemplos de entrada como 0.1, 0.2, 0.333, 0.4, 0.5, 0.8, y 0.9, junto con sus resultados esperados: [0, 0, 0, 0, 1, 1, 1].
A partir de estos datos, la IA ajusta automáticamente los pesos y el sesgo para aprender a distinguir entre valores bajos (0) y altos (1).<br><br>
Una vez entrenado, podemos darle nuevos valores como 0.3 y 0.7, y el perceptrón nos devolverá predicciones razonables, en este caso 0 para el valor bajo y 1 para el alto.
</p>
<p>
Un lector curioso podría preguntarse:
</p>
<p>
<strong>"¿Y no sería más fácil usar una simple comparación como if (x < 0.5) return 0; else return 1 en lugar de todo este entrenamiento con bucles, ajustes de pesos y demás?"
</strong>
</p>
<p>
Y justamente ahí está lo interesante.
</p>
<p>
El perceptrón no se limita a hacer una comparación estática. Ajusta sus propios parámetros (peso y sesgo) a partir de ejemplos reales. Aunque en el primer caso puede parecer que solo está imitando un if, en realidad está aprendiendo a generalizar una regla a partir de datos. Es decir, no le decimos directamente cómo tomar decisiones, sino que las aprende por sí mismo.
</p>
<p>
<strong>¿ Pero… ¿qué pasa cuando el problema no es tan simple ?</strong>
</p>
<p>
Para entender por qué esto es importante, vamos a construir una red un poco más avanzada. En este nuevo ejemplo usaremos 3 neuronas en la capa oculta (una para cada bit de entrada) y una neurona final que evalúa la salida combinada.
</p>
<p>
Vamos ahora a ver un ejemplo en el que una simple condición if no es suficiente.
</p>
<p>
En lugar de entradas individuales como 0.3 o 0.7, ahora trabajaremos con combinaciones binarias de tres valores. Esto genera una lógica más compleja, donde no basta con comparar un solo número para tomar una decisión. Observa los siguientes ejemplos de entrenamiento: <br>
000 → resultado: 0 <br>
001 → resultado: 0 <br>
010 → resultado: 0 <br>
100 → resultado: 1 <br>
110 → resultado: 1 <br>
111 → resultado: 1 <br>
</p>
<p>
Como puedes ver, no hay un solo valor que puedas comparar con un umbral para decidir entre 0 o 1. No podríamos escribir simplemente if (x < 0.5) porque x ahora es un conjunto de bits, y la respuesta depende de cómo interactúan entre ellos.
</p>
<h6>🧠 ¿Cómo lo resolvemos entonces?</h6>
<p>
Para este caso, vamos a construir una red neuronal multicapa: <br>
🔹 Una primera capa compuesta por 3 neuronas, cada una especializada en uno de los bits de entrada. <br>
🔹 Una segunda capa con una sola neurona de salida, que recibe las salidas de las 3 anteriores y toma la decisión final. <br>
🔹 Y en lugar de una función if, usamos una función de activación sigmoide: <br>
<strong>return 1 / (1 + Math.exp(-x)); </strong><br>
Esta función es más suave, permite valores intermedios entre 0 y 1, y hace que el aprendizaje sea mucho más realista y útil.
</p>
<p>
Con este enfoque, la red aprende a combinar patrones entre los distintos bits de entrada y a sacar conclusiones, incluso sobre datos que no ha visto nunca.
</p>
<p>
Este tipo de arquitectura, aunque sencilla, es mucho más poderosa que un if, porque representa la esencia de cómo una inteligencia artificial aprende a pensar por sí sola a partir de ejemplos.
</p>
<img src="https://suzdalenko-dev.github.io/ia/img/1-1.png" alt="Red neuronal de 3 neuronas" class="img-fluid" /><br><br>
<p><strong>🤖 Código: Red neuronal multicapa en JavaScript (con explicación)</strong></p>
<div class="vscode-header">neurona.js</div>
<div class="vscode-editor">
<code>
<span class="comment">// Datos de entrada y etiquetas</span><br>
<span class="keyword">const</span> <span class="variable">inputs</span> = [<br>
[<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>],<br>
[<span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>],<br>
[<span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>],<br>
[<span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>],<br>
[<span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>],<br>
[<span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>]<br>
];<br>
<span class="keyword">const</span> <span class="variable">labels</span> = [<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>];<br><br>
<span class="comment">// Neurona individual con función sigmoide</span><br>
<span class="keyword">class</span> <span class="variable">Neurona</span> {<br>
<span class="method">constructor</span>(<span class="variable">nombre</span> = <span class="string">""</span>) {<br>
<span class="keyword">this</span>.<span class="variable">weight</span> = <span class="method">Math</span>.<span class="method">random</span>();<br>
<span class="keyword">this</span>.<span class="variable">bias</span> = <span class="method">Math</span>.<span class="method">random</span>();<br>
<span class="keyword">this</span>.<span class="variable">learningRate</span> = <span class="number">0.1</span>;<br>
<span class="keyword">this</span>.<span class="variable">nombre</span> = <span class="variable">nombre</span>;<br>
}<br><br>
<span class="method">activation</span>(<span class="variable">x</span>) {<br>
<span class="keyword">return</span> <span class="number">1</span> / (<span class="number">1</span> + <span class="method">Math</span>.<span class="method">exp</span>(-<span class="variable">x</span>));<br>
}<br><br>
<span class="method">raw</span>(<span class="variable">input</span>) {<br>
<span class="keyword">return</span> <span class="variable">input</span> * <span class="keyword">this</span>.<span class="variable">weight</span> + <span class="keyword">this</span>.<span class="variable">bias</span>;<br>
}<br><br>
<span class="method">predict</span>(<span class="variable">input</span>) {<br>
<span class="keyword">return</span> <span class="keyword">this</span>.<span class="method">activation</span>(<span class="keyword">this</span>.<span class="method">raw</span>(<span class="variable">input</span>));<br>
}<br><br>
<span class="method">train</span>(<span class="variable">inputs</span>, <span class="variable">labels</span>, <span class="variable">epochs</span> = <span class="number">10</span>) {<br>
<span class="keyword">for</span> (<span class="keyword">let</span> <span class="variable">i</span> = <span class="number">0</span>; <span class="variable">i</span> < <span class="variable">epochs</span>; <span class="variable">i</span>++) {<br>
<span class="keyword">for</span> (<span class="keyword">let</span> <span class="variable">j</span> = <span class="number">0</span>; <span class="variable">j</span> < <span class="variable">inputs</span>.<span class="method">length</span>; <span class="variable">j</span>++) {<br>
<span class="keyword">let</span> <span class="variable">output</span> = <span class="keyword">this</span>.<span class="method">predict</span>(<span class="variable">inputs</span>[<span class="variable">j</span>]);<br>
<span class="keyword">let</span> <span class="variable">error</span> = <span class="variable">labels</span>[<span class="variable">j</span>] - <span class="variable">output</span>;<br>
<span class="keyword">let</span> <span class="variable">gradient</span> = <span class="variable">output</span> * (<span class="number">1</span> - <span class="variable">output</span>);<br>
<span class="keyword">this</span>.<span class="variable">weight</span> += <span class="variable">error</span> * <span class="variable">gradient</span> * <span class="variable">inputs</span>[<span class="variable">j</span>] * <span class="keyword">this</span>.<span class="variable">learningRate</span>;<br>
<span class="keyword">this</span>.<span class="variable">bias</span> += <span class="variable">error</span> * <span class="variable">gradient</span> * <span class="keyword">this</span>.<span class="variable">learningRate</span>;<br>
}<br>
}<br>
}<br><br>
<span class="method">info</span>() {<br>
<span class="variable">console</span>.<span class="method">log</span>(<span class="keyword">this</span>.<span class="variable">nombre</span>);<br>
<span class="variable">console</span>.<span class="method">log</span>(<span class="string">" Peso:"</span>, <span class="keyword">this</span>.<span class="variable">weight</span>.<span class="method">toFixed</span>(<span class="number">3</span>));<br>
<span class="variable">console</span>.<span class="method">log</span>(<span class="string">" Bias:"</span>, <span class="keyword">this</span>.<span class="variable">bias</span>.<span class="method">toFixed</span>(<span class="number">3</span>));<br>
}<br>
}<br>
<span class="comment">// Clase que representa la neurona de salida con múltiples entradas</span><br>
<span class="keyword">class</span> <span class="variable">NeuronaSalida</span> {<br>
<span class="method">constructor</span>(<span class="variable">numEntradas</span>) {<br>
<span class="comment">// Inicializa pesos y bias aleatoriamente</span><br>
<span class="keyword">this</span>.<span class="variable">weights</span> = <span class="method">Array</span>.<span class="method">from</span>({ length: <span class="variable">numEntradas</span> }, () => <span class="method">Math</span>.<span class="method">random</span>());<br>
<span class="keyword">this</span>.<span class="variable">bias</span> = <span class="method">Math</span>.<span class="method">random</span>();<br>
<span class="keyword">this</span>.<span class="variable">learningRate</span> = <span class="number">0.1</span>;<br>
}<br><br>
<span class="comment">// Función de activación: sigmoide</span><br>
<span class="method">activation</span>(<span class="variable">x</span>) {<br>
<span class="keyword">return</span> <span class="number">1</span> / (<span class="number">1</span> + <span class="method">Math</span>.<span class="method">exp</span>(-<span class="variable">x</span>));<br>
}<br><br>
<span class="comment">// Predicción a partir de salidas ocultas</span><br>
<span class="method">predict</span>(<span class="variable">hiddenOutputs</span>) {<br>
<span class="keyword">let</span> <span class="variable">sum</span> = <span class="variable">hiddenOutputs</span>.<span class="method">reduce</span>((<span class="variable">acc</span>, <span class="variable">h</span>, <span class="variable">i</span>) => <span class="variable">acc</span> + <span class="variable">h</span> * <span class="keyword">this</span>.<span class="variable">weights</span>[<span class="variable">i</span>], <span class="number">0</span>) + <span class="keyword">this</span>.<span class="variable">bias</span>;<br>
<span class="keyword">return</span> <span class="keyword">this</span>.<span class="method">activation</span>(<span class="variable">sum</span>);<br>
}<br><br>
<span class="comment">// Entrenamiento de la neurona de salida</span><br>
<span class="method">train</span>(<span class="variable">hiddenOutputsList</span>, <span class="variable">labels</span>, <span class="variable">epochs</span> = <span class="number">10</span>) {<br>
<span class="keyword">for</span> (<span class="keyword">let</span> <span class="variable">epoch</span> = <span class="number">0</span>; <span class="variable">epoch</span> < <span class="variable">epochs</span>; <span class="variable">epoch</span>++) {<br>
<span class="keyword">for</span> (<span class="keyword">let</span> <span class="variable">i</span> = <span class="number">0</span>; <span class="variable">i</span> < <span class="variable">hiddenOutputsList</span>.<span class="method">length</span>; <span class="variable">i</span>++) {<br>
<span class="keyword">let</span> <span class="variable">output</span> = <span class="keyword">this</span>.<span class="method">predict</span>(<span class="variable">hiddenOutputsList</span>[<span class="variable">i</span>]);<br>
<span class="keyword">let</span> <span class="variable">error</span> = <span class="variable">labels</span>[<span class="variable">i</span>] - <span class="variable">output</span>;<br>
<span class="keyword">let</span> <span class="variable">gradient</span> = <span class="variable">output</span> * (<span class="number">1</span> - <span class="variable">output</span>);<br><br>
<span class="comment">// Ajustar los pesos</span><br>
<span class="keyword">for</span> (<span class="keyword">let</span> <span class="variable">j</span> = <span class="number">0</span>; <span class="variable">j</span> < <span class="keyword">this</span>.<span class="variable">weights</span>.<span class="property">length</span>; <span class="variable">j</span>++) {<br>
<span class="keyword">this</span>.<span class="variable">weights</span>[<span class="variable">j</span>] += <span class="variable">error</span> * <span class="variable">gradient</span> * <span class="variable">hiddenOutputsList</span>[<span class="variable">i</span>][<span class="variable">j</span>] * <span class="keyword">this</span>.<span class="variable">learningRate</span>;<br>
}<br>
<span class="comment">// Ajustar el sesgo</span><br>
<span class="keyword">this</span>.<span class="variable">bias</span> += <span class="variable">error</span> * <span class="variable">gradient</span> * <span class="keyword">this</span>.<span class="variable">learningRate</span>;<br>
}<br>
}<br>
}<br><br>
<span class="comment">// Mostrar información de la neurona</span><br>
<span class="method">info</span>() {<br>
<span class="method">console</span>.<span class="method">log</span>(<span class="string">"⚙️ Neurona de salida:"</span>);<br>
<span class="method">console</span>.<span class="method">log</span>(<span class="string">" Pesos:"</span>, <span class="keyword">this</span>.<span class="variable">weights</span>.<span class="method">map</span>(<span class="variable">w</span> => <span class="variable">w</span>.<span class="method">toFixed</span>(<span class="number">3</span>)).<span class="method">join</span>(<span class="string">", "</span>));<br>
<span class="method">console</span>.<span class="method">log</span>(<span class="string">" Bias:"</span>, <span class="keyword">this</span>.<span class="variable">bias</span>.<span class="method">toFixed</span>(<span class="number">3</span>));<br>
}<br>
}<br><br>
<span class="method">console</span>.<span class="method">log</span>(<span class="string">"📥 Datos de entrenamiento:"</span>);<br>
<span class="variable">inputs</span>.<span class="method">forEach</span>((<span class="variable">input</span>, <span class="variable">i</span>) => {<br>
<span class="method">console</span>.<span class="method">log</span>(<span class="string"> Input: [input.join(", ")}] → Label: labels[i]}</span>);<br>
});<br><br>
<span class="comment">// Capa oculta con 3 neuronas (una por cada bit de entrada)</span><br>
<span class="keyword">const</span> <span class="variable">oculta1</span> = <span class="keyword">new</span> <span class="class">Neurona</span>(<span class="string">"Oculta 1"</span>);<br>
<span class="keyword">const</span> <span class="variable">oculta2</span> = <span class="keyword">new</span> <span class="class">Neurona</span>(<span class="string">"Oculta 2"</span>);<br>
<span class="keyword">const</span> <span class="variable">oculta3</span> = <span class="keyword">new</span> <span class="class">Neurona</span>(<span class="string">"Oculta 3"</span>);<br><br>
<span class="keyword">const</span> <span class="variable">entradasPorNeurona</span> = [<br>
<span class="variable">inputs</span>.<span class="method">map</span>(<span class="variable">i</span> => <span class="variable">i</span>[<span class="number">0</span>]),<br>
<span class="variable">inputs</span>.<span class="method">map</span>(<span class="variable">i</span> => <span class="variable">i</span>[<span class="number">1</span>]),<br>
<span class="variable">inputs</span>.<span class="method">map</span>(<span class="variable">i</span> => <span class="variable">i</span>[<span class="number">2</span>])<br>
];<br><br>
<span class="variable">oculta1</span>.<span class="method">train</span>(<span class="variable">entradasPorNeurona</span>[<span class="number">0</span>], <span class="variable">labels</span>, <span class="number">1000</span>);<br>
<span class="variable">oculta2</span>.<span class="method">train</span>(<span class="variable">entradasPorNeurona</span>[<span class="number">1</span>], <span class="variable">labels</span>, <span class="number">1000</span>);<br>
<span class="variable">oculta3</span>.<span class="method">train</span>(<span class="variable">entradasPorNeurona</span>[<span class="number">2</span>], <span class="variable">labels</span>, <span class="number">1000</span>);<br><br>
<span class="keyword">const</span> <span class="variable">hiddenOutputs</span> = <span class="variable">inputs</span>.<span class="method">map</span>(<span class="variable">input</span> => [<br>
<span class="variable">oculta1</span>.<span class="method">predict</span>(<span class="variable">input</span>[<span class="number">0</span>]),<br>
<span class="variable">oculta2</span>.<span class="method">predict</span>(<span class="variable">input</span>[<span class="number">1</span>]),<br>
<span class="variable">oculta3</span>.<span class="method">predict</span>(<span class="variable">input</span>[<span class="number">2</span>])<br>
]);<br><br>
<span class="keyword">const</span> <span class="variable">salida</span> = <span class="keyword">new</span> <span class="class">NeuronaSalida</span>(<span class="number">3</span>);<br>
<span class="variable">salida</span>.<span class="method">train</span>(<span class="variable">hiddenOutputs</span>, <span class="variable">labels</span>, <span class="number">1000</span>);<br><br>
<span class="keyword">function</span> <span class="method">predecir</span>(<span class="variable">binArray</span>) {<br>
<span class="keyword">const</span> <span class="variable">h1</span> = <span class="variable">oculta1</span>.<span class="method">predict</span>(<span class="variable">binArray</span>[<span class="number">0</span>]);<br>
<span class="keyword">const</span> <span class="variable">h2</span> = <span class="variable">oculta2</span>.<span class="method">predict</span>(<span class="variable">binArray</span>[<span class="number">1</span>]);<br>
<span class="keyword">const</span> <span class="variable">h3</span> = <span class="variable">oculta3</span>.<span class="method">predict</span>(<span class="variable">binArray</span>[<span class="number">2</span>]);<br>
<span class="keyword">const</span> <span class="variable">output</span> = <span class="variable">salida</span>.<span class="method">predict</span>([<span class="variable">h1</span>, <span class="variable">h2</span>, <span class="variable">h3</span>]);<br>
<span class="keyword">const</span> <span class="variable">clasificacion</span> = <span class="variable">output</span> > <span class="number">0.5</span> ? <span class="number">1</span> : <span class="number">0</span>;<br>
}<br><br>
<span class="comment">// Pruebas con nuevos datos</span><br>
<span class="method">console</span>.<span class="method">log</span>(<span class="string">"\n🧪 Pruebas con datos no vistos:"</span>);<br>
<span class="method">predecir</span>([<span class="number">0</span>, <span class="number">1</span>, <span class="number">1</span>]); <span class="comment">// 011</span><br>
<span class="method">predecir</span>([<span class="number">1</span>, <span class="number">0</span>, <span class="number">1</span>]); <span class="comment">// 101</span><br><br>
<span class="comment">// Info de las neuronas</span><br>
<span class="method">console</span>.<span class="method">log</span>(<span class="string">"\nℹ️ Pesos y sesgos finales:"</span>);<br>
<span class="variable">oculta1</span>.<span class="method">info</span>();<br>
<span class="variable">oculta2</span>.<span class="method">info</span>();<br>
<span class="variable">oculta3</span>.<span class="method">info</span>();<br>
<span class="variable">salida</span>.<span class="method">info</span>();<br>
</code>
</div>
<p>
Resultado de la ejecución del código anterior:
</p>
<iframe width="100%" height="411px" src="https://suzdalenko-dev.github.io/ia/0.js/1.html" title="Inteligencia Artificial en JavaScript"></iframe>
<p>
📊 Resultados del entrenamiento y prueba de la red neuronal:
<br>
Después de entrenar nuestra red neuronal en JavaScript con los siguientes datos:
Input: [0, 0, 0] → resultado: 0 <br>
Input: [0, 0, 1] → resultado: 0 <br>
Input: [0, 1, 0] → resultado: 0 <br>
Input: [1, 0, 0] → resultado: 1 <br>
Input: [1, 1, 0] → resultado: 1 <br>
Input: [1, 1, 1] → resultado: 1 <br><br>
La inteligencia artificial fue capaz de generalizar el patrón correctamente. Al presentarle entradas no vistas previamente, como:<br>
Input: [0, 1, 1] → Oculta: [0.08, 0.67, 0.50] → Salida: 0 (confianza: 0.091) <br>
Input: [1, 0, 1] → Oculta: [0.93, 0.33, 0.50] → Salida: 1 (confianza: 0.922) <br><br>
la IA respondió con precisión y gran confianza.
</p>
<p>
🧠 ¿Qué significa esto?
</p>
<p>
Aunque el problema puede parecer simple para un humano (basta con fijarse en el primer bit de entrada para predecir el resultado), la red no fue programada explícitamente para eso. En su lugar, la IA fue capaz de descubrir esta regla por sí sola, aprendiendo a través del entrenamiento.
</p>
<p>
✅ En resumen, esta demostración muestra cómo una red neuronal sencilla, escrita en JavaScript, puede aprender patrones lógicos sin instrucciones explícitas. Es un claro ejemplo del poder del aprendizaje automático.
</p>`,
slug:"Inteligencia-Artificial-en-JavaScript",
tags: ["Desarrollo", "IA", "JavaScript", "Perceptron"],
date: "06/04/2025",
description: `En este artículo, construimos una neurona artificial básica en JavaScript, entendiendo los conceptos clave de pesos, sesgos y funciones de activación. Hemos visto que el perceptrón puede aprender por sí solo a partir de datos, sin necesidad de que le demos reglas explícitas. La inteligencia artificial, en su núcleo, es una función matemática que transforma entradas en salidas mediante una serie de cálculos. En las redes neuronales, esto implica multiplicar cada entrada por un peso, sumar un sesgo y aplicar una función de activación para obtener una decisión. A través del aprendizaje, estos valores se ajustan automáticamente para mejorar la precisión del modelo.`
},{
id: 3,
title: "IVA – herramienta silenciosa",
preview: "https://suzdalenko-dev.github.io/ia/img/3-0.png",
content: `
<h3>Cómo el PSOE —el partido “pro obrero”— fue el primero en hacer más pobre al obrero con el IVA</h3>
<br>
En 1986, el PSOE, ese mismo partido que se llena la boca con la igualdad y los derechos de los trabajadores, fue el primero en imponer **un nuevo impuesto al consumo: el IVA**. Lo hizo “por Europa”, dicen. Pero el resultado fue que, de un día para otro, **todos los españoles pasaron a ser un 11% más pobres**. Porque eso es lo que implica un 11% de IVA: perder poder adquisitivo sin discusión.
<br><br>
Y desde entonces, lejos de corregirlo o eliminarlo, el PSOE (y también el PP) **han subido ese impuesto una y otra vez**, sin vergüenza alguna. Todo sea —dicen— por la clase trabajadora. Aunque a la vista está quién paga realmente la fiesta.
<br><br>
<h3>Cómo el IVA se convirtió en una herramienta silenciosa para asfixiar la economía española</h3>
<br>
Desde que el IVA se implantó, ha sido una fuente estable de recaudación... pero también una forma silenciosa de apretar el bolsillo del ciudadano común.
<br><br>
<strong>¿Qué ha pasado desde entonces?</strong><br>
El IVA ha pasado del 12% original a un 21% en la actualidad, con subidas aplicadas tanto por el PSOE como por el PP. Y lo peor es que esas subidas afectan igual al que cobra 1.000 € que al que cobra 10.000 €. Porque el IVA lo pagamos todos... y cuanto menos tienes, más te duele.
<br><br>
<img src="https://suzdalenko-dev.github.io/ia/img/3-0.png" alt="Subida del IVA" class="img-fluid" /><br><br>
<h4>#1. Un impuesto regresivo que castiga a los que menos tienen</h4>
Mientras los grandes capitales encuentran formas de evadir o aplazar impuestos, el IVA te lo quitan directamente en la caja del supermercado. ¿Compras leche, luz, transporte o productos básicos? Paga. ¿Te suben el IVA? No puedes esquivarlo. Es automático. Es diario.
<br><br>
<h4>#2. Una herramienta de recaudación fácil para gobiernos sin reformas</h4>
Ningún gobierno ha tenido el valor de revertir una subida de IVA. Es cómodo: recaudas más sin tocar a los ricos ni luchar contra el fraude fiscal. Pero eso sí, aprietas a quien trabaja, consume y cumple.
<br><br>
<h4>#3. ¿Dónde están los servicios a cambio?</h4>
Pagamos como si viviéramos en Suiza, pero tenemos listas de espera eternas, transporte colapsado y educación infrafinanciada. ¿Qué hace el Estado con ese IVA? ¿Se invierte realmente en lo que necesitamos o se pierde entre despachos, cargos públicos y chiringuitos?
<br><br>
<h4>#4. El IVA como síntoma de una clase política mediocre</h4>
Subir el IVA ha sido el recurso fácil de una política sin ideas. Lo han hecho los socialistas, lo han hecho los populares. ¿Y mientras? La economía se enfría, el consumo cae, los autónomos sufren y el pequeño comercio cierra.
<br><br>
<h4>#5. El coste oculto del IVA: una trituradora de tiempo y dinero para las empresas</h4>
Si todo esto fuera poco, está el coste oculto que nadie menciona: el coste de gestionar el IVA. En España, miles de pymes y autónomos pierden horas y recursos cada trimestre preparando declaraciones, controlando facturas, soportando inspecciones y adaptándose a cambios legislativos constantes.
<br><br>
Y cada vez que el gobierno decide cambiar un tipo impositivo, modificar la normativa o lanzar una nueva campaña de “simplificación fiscal”, las empresas deben rehacer programas, pagar asesores, reconfigurar sistemas y volver a empezar. Resultado: decenas de millones de euros y horas de trabajo literalmente tiradas a la basura. No se produce más. No se vende más. Solo se mueve papel y se entierra riqueza nacional en burocracia.
<br><br>
<img src="https://suzdalenko-dev.github.io/ia/img/3-0.png" alt="Factura con IVA" class="img-fluid" /><br><br>
<h3>¿Qué se podría hacer?</h3>
<ul>
<li>✅ Quitar el IVA de los productos esenciales.</li>
<li>✅ Devolver parte del IVA a los salarios bajos vía deducciones o compensaciones.</li>
<li>✅ Combatir el fraude fiscal en serio y no con campañas de marketing.</li>
<li>✅ Hacer una reforma tributaria justa, donde todos paguen lo mismo en proporción, sin castigar a quien más trabaja o emprende. El esfuerzo no debe penalizarse con más impuestos, sino valorarse. En una economía sana, el autónomo y el empresario que tiran del país no deberían pagar por encima de su peso, sino tener estabilidad, reglas claras y un Estado que no los trate como enemigos.</li>
</ul>
<br>
<h3>Conclusión: un país que vive del IVA se está empobreciendo en silencio</h3>
<br>
Porque cada euro que pagas en IVA, es un euro menos que puedes ahorrar, invertir o disfrutar. Y cuando todo sube menos tu sueldo, el IVA no es solo un impuesto... es una forma de hundir la economía de los que mantienen en pie este país.
<br><br>
Ya es hora de exigir una fiscalidad que no castigue al trabajador ni al emprendedor. Porque el verdadero progreso no se mide por cuánto recauda Hacienda, sino por cuánta dignidad y libertad económica tiene su gente.
`,
slug: "IVA-España",
tags: ["Fiscalidad", "IVA", "Política económica"],
date: "06/05/2025",
description: "El PSOE, el supuesto defensor del trabajador, fue quien implantó el IVA en España, empobreciendo al ciudadano común desde el primer día. Este artículo explica cómo este impuesto se ha convertido en una trampa silenciosa contra el consumidor, el autónomo y la economía real."
},{
id: 2,
title: "Autentificación con JWT Token en Python Django (sin librerías externas)",
preview: "https://suzdalenko-dev.github.io/ia/img/2-0.png",
content: `
<p><img src="https://suzdalenko-dev.github.io/ia/img/2-0.png" alt="JWT en Django sin librerías externas" class="img-fluid" loading="lazy" width="1200" height="675"></p>
<p>
Implementamos <strong>JWT puro</strong> en Django, sin instalar dependencias externas. Verás el flujo completo:
1) envío de email y password desde HTML, 2) verificación en el servidor, 3) creación del token JWT (HMAC-SHA256 con <code>SECRET_KEY</code>),
4) dónde guardarlo en el cliente, y 5) cómo se valida en cada <code>GET</code>/<code>POST</code> de tu API.
</p>
<h4>#1. Flujo de alto nivel</h4>
<ol>
<li>El cliente manda <em>email</em> y <em>password</em> por <code>POST</code> a <code>/api/login/</code>.</li>
<li>El servidor valida credenciales con <code>authenticate()</code>. Si son correctas, construye el <strong>JWT</strong> con <code>sub</code> (ID de usuario), <code>iat</code> y <code>exp</code>.</li>
<li>El cliente guarda el <strong>access token</strong>:
<ul>
<li>En memoria JS (variable), o</li>
<li>En <strong>cookie HttpOnly + Secure</strong> (recomendado contra XSS).</li>
</ul>
</li>
<li>En cada petición protegida, se envía <code>Authorization: Bearer <token></code> (o la cookie). El servidor verifica firma y caducidad antes de procesar.</li>
</ol>
<h4>#2. Formulario HTML + envío (email & password)</h4>
<div class="vscode-header">login.html (demo)</div>
<div class="vscode-editor"><pre><code class="language-html"><!doctype html>
<html lang="es">
<head><meta charset="utf-8"><title>Login JWT</title></head>
<body>
<h3>Login</h3>
<form id="loginForm">
<input name="email" type="email" placeholder="email" required>
<input name="password" type="password" placeholder="password" required>
<button>Entrar</button>
</form>
<button id="btnGet" type="button">GET protegido</button>
<button id="btnPost" type="button">POST protegido</button>
<pre id="out"></pre>
<script>
let accessToken = null; // opción: guardarlo en memoria (no persiste entre pestañas)
const out = document.querySelector('#out');
document.querySelector('#loginForm').addEventListener('submit', async (e) => {
e.preventDefault();
const fd = new FormData(e.target);
const body = JSON.stringify({ email: fd.get('email'), password: fd.get('password') });
const r = await fetch('/api/login/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body
});
const j = await r.json();
if (r.ok) {
accessToken = j.access; // si usas cookie HttpOnly, no guardes nada aquí
out.textContent = 'Login OK. Token en memoria.';
} else {
out.textContent = 'Error: ' + (j.detail || r.status);
}
});
document.querySelector('#btnGet').addEventListener('click', async () => {
const r = await fetch('/api/todos/', {
headers: accessToken ? { 'Authorization': 'Bearer ' + accessToken } : {}
});
out.textContent = await r.text();
});
document.querySelector('#btnPost').addEventListener('click', async () => {
const r = await fetch('/api/todos/', {
method: 'POST',
headers: Object.assign({ 'Content-Type': 'application/json' },
accessToken ? { 'Authorization': 'Bearer ' + accessToken } : {}),
body: JSON.stringify({ text: 'Comprar pan' })
});
out.textContent = await r.text();
});
</script>
</body>
</html>
</code></pre></div>
<h4>#3. Utilidades JWT (sin librerías externas)</h4>
<p>Firmamos con <strong>HMAC-SHA256</strong> usando <code>SECRET_KEY</code>. El token es <code>header.payload.signature</code> en base64url.</p>
<div class="vscode-header">jwt_utils.py</div>
<div class="vscode-editor"><pre><code class="language-python"># jwt_utils.py
import json, time, hmac, hashlib, base64
from typing import Optional
from django.conf import settings
def _b64url_encode(b: bytes) -> str:
return base64.urlsafe_b64encode(b).decode().rstrip("=")
def _b64url_decode(s: str) -> bytes:
pad = "=" * (-len(s) % 4)
return base64.urlsafe_b64decode(s + pad)
def jwt_encode(payload: dict, secret: str = None, alg: str = "HS256") -> str:
secret = secret or settings.SECRET_KEY
header = {"alg": alg, "typ": "JWT"}
h = _b64url_encode(json.dumps(header, separators=(",", ":")).encode())
p = _b64url_encode(json.dumps(payload, separators=(",", ":")).encode())
msg = f"{h}.{p}".encode()
sig = hmac.new(secret.encode(), msg, hashlib.sha256).digest()
s = _b64url_encode(sig)
return f"{h}.{p}.{s}"
def jwt_decode(token: str, secret: str = None, verify_exp: bool = True) -> Optional[dict]:
secret = secret or settings.SECRET_KEY
try:
h, p, s = token.split(".")
except ValueError:
return None
msg = f"{h}.{p}".encode()
expected_sig = hmac.new(secret.encode(), msg, hashlib.sha256).digest()
try:
got_sig = _b64url_decode(s)
except Exception:
return None
if not hmac.compare_digest(expected_sig, got_sig):
return None
try:
payload = json.loads(_b64url_decode(p))
except Exception:
return None
if verify_exp and "exp" in payload and int(time.time()) > int(payload["exp"]):
return None
return payload
</code></pre></div>
<h4>#4. Endpoint de login: crea y devuelve el JWT</h4>
<p>Validamos email+password con <code>authenticate()</code>. Si todo OK, emitimos un <strong>access token</strong> de 15 minutos.</p>
<div class="vscode-header">views.py (login)</div>
<div class="vscode-editor"><pre><code class="language-python"># views.py (extracto)
import time, json
from django.http import JsonResponse, HttpResponseNotAllowed
from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth import authenticate, get_user_model
from .jwt_utils import jwt_encode
ACCESS_TTL = 15 * 60 # 15 minutos
@csrf_exempt # si usas cookie, configura CSRF y quita esto
def api_login(request):
if request.method != "POST":
return HttpResponseNotAllowed(["POST"])
try:
body = json.loads(request.body or "{}")
except json.JSONDecodeError:
body = {}
email = body.get("email", "")
password = body.get("password", "")
User = get_user_model()
try:
user_obj = User.objects.get(email=email)
username = user_obj.get_username()
except User.DoesNotExist:
return JsonResponse({"detail": "Credenciales inválidas"}, status=401)
user = authenticate(request, username=username, password=password)
if not user:
return JsonResponse({"detail": "Credenciales inválidas"}, status=401)
now = int(time.time())
payload = {
"sub": user.id,
"email": user.email,
"iat": now,
"exp": now + ACCESS_TTL
}
token = jwt_encode(payload)
# Opción A: devolver token en JSON para header Authorization
return JsonResponse({"access": token, "user": {"id": user.id, "email": user.email, "username": user.username}})
# Opción B: cookie HttpOnly (alternativa más resistente a XSS)
# res = JsonResponse({"ok": True})
# res.set_cookie("access", token, httponly=True, secure=True, samesite="Lax", max_age=ACCESS_TTL)
# return res
</code></pre></div>
<h4>#5. Proteger endpoints: verificar el JWT en cada GET/POST</h4>
<p>Extraemos el token del header (o cookie), lo verificamos con <code>jwt_decode()</code> y, si es válido, procesamos.</p>
<div class="vscode-header">views.py (helpers + endpoints)</div>
<div class="vscode-editor"><pre><code class="language-python"># views.py (continuación)
from django.http import JsonResponse, HttpResponseForbidden, HttpResponseNotAllowed
from .jwt_utils import jwt_decode
# demo en memoria (en producción, BD)
TODOS = []
def _get_token_from_request(request):
auth = request.META.get("HTTP_AUTHORIZATION", "")
if auth.lower().startswith("bearer "):
return auth.split(" ", 1)[1].strip()
# alternativa cookie:
# if "access" in request.COOKIES: return request.COOKIES["access"]
return None
def _require_jwt(request):
token = _get_token_from_request(request)
if not token:
return None
return jwt_decode(token) # None si firma/exp inválidos
def api_todos(request):
payload = _require_jwt(request)
if not payload:
return HttpResponseForbidden("No autenticado o token inválido/caducado")
uid = payload["sub"]
if request.method == "GET":
items = [t for t in TODOS if t["user_id"] == uid]
return JsonResponse(items, safe=False)
if request.method == "POST":
try:
body = json.loads(request.body or "{}")
except json.JSONDecodeError:
body = {}
text = (body.get("text") or "").strip()
if not text:
return JsonResponse({"detail": "Falta 'text'"}, status=400)
item = {"id": len(TODOS) + 1, "text": text, "user_id": uid}
TODOS.append(item)
return JsonResponse(item, status=201)
return HttpResponseNotAllowed(["GET", "POST"])
</code></pre></div>
<h4>#6. Enviar el token en peticiones GET/POST</h4>
<p>Desde el cliente, añade el header <code>Authorization</code> en cada llamada a la API.</p>
<div class="vscode-header">fetch.js (trozo)</div>
<div class="vscode-editor"><pre><code class="language-html"><script>
// GET
fetch('/api/todos/', {
headers: { 'Authorization': 'Bearer ' + accessToken }
});
// POST
fetch('/api/todos/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + accessToken
},
body: JSON.stringify({ text: 'Comprar pan' })
});
</script>
</code></pre></div>
<h4>#7. ¿Dónde guardar el JWT?</h4>
<ul>
<li><strong>Memoria JS</strong>: simple, se borra al cerrar pestaña. Evita persistencia innecesaria.</li>
<li><strong>Cookie HttpOnly + Secure</strong>: el JS no la puede leer (mitiga XSS). Requiere configurar <em>CSRF/CORS</em> si front y back van en dominios distintos.</li>
<li><strong>Evitar</strong> <code>localStorage</code> para tokens sensibles (si hay XSS te lo roban).</li>
</ul>
<h4>#8. Seguridad y expiración</h4>
<ul>
<li>Siempre <strong>HTTPS</strong> en producción.</li>
<li>Access token corto (p. ej. <code>exp = 15 min</code>). Si necesitas, añade un <em>refresh token</em> con TTL mayor y endpoint de renovación.</li>
<li>Protege tu <code>SECRET_KEY</code> y rota si sospechas compromiso.</li>
<li>Para revocación inmediata, guarda un identificador del token (p. ej. <code>jti</code>) en BD y revisa una “denylist”.</li>
</ul>
<h4>#9. Resumen</h4>
<p>
Login con email y password → el servidor genera un JWT firmado con tu <code>SECRET_KEY</code> → el cliente lo envía en
<code>Authorization: Bearer</code> (o cookie) → en cada petición, el servidor verifica firma y caducidad → si es válido, autorizas la acción.
Todo esto sin instalar ninguna librería adicional.
</p>
`,
slug: "Python-Django-JWT-Token",
tags: ["JWT","Python","Django","Autentificación"],
date: "13/09/2025",
description: "Implementa JWT en Django sin dependencias externas: login con email y password, creación del token HMAC-SHA256, almacenamiento en cliente y verificación en peticiones GET/POST protegidas."
}
];
content = content.reverse();
window.content = content;