Compare commits

..

3 commits

Author SHA1 Message Date
SITO
b80c28c4f2 feat: demo visualización imágenes Wikipedia + gitignore wiki/
- demo_wiki_images.html: grafo 3D con las 15 imágenes de Wikipedia
  sobre cambio climático como nodos sprite, panel de detalle al click
- images/wiki/.gitignore: excluye imágenes binarias del repo

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 20:48:18 +02:00
SITO
0975f44a0e feat: scraper de imágenes Wikipedia + debug
- wikipedia_image_scraper.py: descarga imágenes de Wikipedia por tema
  usando Wikimedia API, con filtros de tamaño/extensión y metadatos
  (autor, licencia, dimensiones, artículo origen)
- debug_wiki.py: script de diagnóstico para verificar API responses
- .gitignore: excluye output/ y __pycache__

Fix: normalizar prefijo "Archivo:" → "File:" para Wikimedia Commons API

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 19:41:11 +02:00
SITO
b992e25f8f feat: pipeline de imágenes + demos de visualización 3D
- BACK_BACK/IMAGENES/: nueva pipeline para análisis de imágenes con VLM
  - image_analyzer.py: imagen → keywords via ollama
  - image_comparator.py: TF-IDF similitud keywords vs corpus
  - mongo_helper.py: CRUD colecciones imagenes y comparaciones
  - pipeline_pruebas.py: script end-to-end con CLI
  - requirements_imagenes.txt

- BACK_BACK/FLUJOS_APP_PRUEBAS.js: servidor Express ligero (port 3001)
  sin MongoDB para testear los demos de visualización

- VISUALIZACION/public/demos/: tres demos de 3d-force-graph
  - demo_text_nodes.html: nodos como texto (three-spritetext)
  - demo_img_nodes.html: nodos como imágenes (THREE.Sprite)
  - demo_mixed_nodes.html: cards HTML en 3D (CSS2DRenderer)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 22:28:34 +01:00
191 changed files with 2 additions and 191754 deletions

View file

@ -1,6 +0,0 @@
# Conexión a MongoDB
MONGO_URL=mongodb://localhost:27017
DB_NAME=FLUJOS_DATOS
# Puerto del servidor Node.js
PORT=3000

91
.gitignore vendored
View file

@ -1,91 +0,0 @@
# ========================
# DATOS PESADOS - NO SUBIR
# ========================
# MongoDB (3.2 GB)
FLUJOS_DATOS/MONGO/
# Modelo Qwen3-VL (~16GB)
FLUJOS_DATOS/IMAGENES/model_cache/
# Imágenes scrapeadas y JSONs de output
FLUJOS_DATOS/IMAGENES/output/
# Logs del pipeline
FLUJOS_DATOS/pipeline_maestro.log
FLUJOS_DATOS/COMPARACIONES/pipeline_mongolo.log*
# Datos scrapeados - solo código, no datos
FLUJOS_DATOS/NOTICIAS/archivos/
FLUJOS_DATOS/NOTICIAS/articulos/
FLUJOS_DATOS/NOTICIAS/tokenized/
FLUJOS_DATOS/NOTICIAS/noticias_procesadas.txt
FLUJOS_DATOS/NOTICIAS/processed_articles.txt
FLUJOS_DATOS/WIKIPEDIA/articulos_wikipedia/
FLUJOS_DATOS/WIKIPEDIA/articulos_tokenizados/
FLUJOS_DATOS/TORRENTS/
# Entorno virtual Python (2.1 GB)
FLUJOS_DATOS/myenv/
myenv/
venv/
env/
.venv/
# NLTK data (50 MB)
nltk_data/
# Bases de datos
*.sqlite3
*.db
# ========================
# DEPENDENCIAS NODE
# ========================
node_modules/
**/node_modules/
# ========================
# SECRETOS Y CONFIG LOCAL
# ========================
.env
.env.*
!.env.example
# ========================
# PYTHON
# ========================
__pycache__/
*.py[cod]
*.pyo
*.pyd
*.egg-info/
# ========================
# TEMPORALES Y BACKUPS
# ========================
*.save
*.bak
*_COPIA*
*~
.DS_Store
Thumbs.db
# ========================
# LOGS
# ========================
logs/
*.log
npm-debug.log*
# ========================
# IDEs
# ========================
.vscode/
.idea/
*.swp
*.swo
# Parcel cache
.cache/
.parcel-cache/

63
FLUJOS/.gitignore vendored
View file

@ -1,63 +0,0 @@
# Dependencias
node_modules/
**/node_modules/
# Variables de entorno y secretos
.env
.env.*
!.env.example
# Python
__pycache__/
*.py[cod]
*.pyo
*.pyd
.Python
*.egg-info/
dist/
build/
.eggs/
# Entorno virtual Python
venv/
env/
myenv/
.venv/
# Bases de datos locales
*.sqlite3
*.db
# Archivos de backup y temporales
*.save
*.bak
*_COPIA*
*~
.DS_Store
Thumbs.db
# Logs
logs/
*.log
npm-debug.log*
# IDEs
.vscode/
.idea/
*.swp
*.swo
# Parcel bundler
.cache/
.parcel-cache/
# Datos escrapeados y pesados (si se colaran dentro de FLUJOS)
NOTICIAS/
WIKIPEDIA/
TORRENTS/
MONGO/
archivos/
articulos/
tokenized/
articulos_wikipedia/
articulos_tokenizados/

View file

@ -1,452 +0,0 @@
// FLUJOS_APP.js ubicado en /var/www/flujos/FLUJOS/BACK_BACK/
require('dotenv').config(); // Cargar variables de entorno desde .env
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const helmet = require('helmet');
const { MongoClient } = require('mongodb');
const app = express();
const port = process.env.PORT || 3000;
// Helmet completo: X-Powered-By off, XSS protection, nosniff, frameguard, HSTS, etc.
app.use(helmet());
// CSP personalizado encima del helmet por defecto
app.use(
helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'", 'https://cdn.jsdelivr.net', 'https://esm.sh', 'https://unpkg.com', 'https://cdnjs.cloudflare.com'],
styleSrc: ["'self'", "'unsafe-inline'", 'https://fonts.googleapis.com'],
imgSrc: ["'self'", 'data:', 'blob:'],
connectSrc: ["'self'", 'https://esm.sh'],
fontSrc: ["'self'", 'https://fonts.gstatic.com'],
frameAncestors: ["'none'"],
objectSrc: ["'none'"],
baseUri: ["'self'"],
},
})
);
// Prevenir CSRF: solo aceptar peticiones GET a /api desde el mismo origen
app.use('/api/', (req, res, next) => {
const origin = req.headers.origin;
const referer = req.headers.referer;
// En producción detrás de nginx no hay Origin en peticiones same-site normales,
// pero sí lo habría en peticiones cross-origin maliciosas
if (origin && origin !== `https://theflows.net` && origin !== `http://localhost:${port}`) {
return res.status(403).json({ error: 'Origen no permitido' });
}
next();
});
// Añadir cabecera anti-clickjacking y anti-MIME-sniffing explícitas
app.use((req, res, next) => {
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
next();
});
app.use(bodyParser.json({ limit: '10kb' }));
// **Definir primero las rutas de la API**
app.get('/api/data', async (req, res) => {
console.log('Solicitud recibida en /api/data');
try {
// Asegurarse de que la conexión a la base de datos está establecida
if (!db) {
res.status(500).json({ error: 'No hay conexión a la base de datos' });
return;
}
// Acceder a las colecciones necesarias
const wikipediaCollection = db.collection('wikipedia');
const noticiasCollection = db.collection('noticias');
const torrentsCollection = db.collection('torrents');
const imagenesCollection = db.collection('imagenes'); // analizadas por Qwen
const imagenesWikiCollection = db.collection('imagenes_wiki'); // scrapeadas (fallback)
const comparacionesCollection = db.collection('comparaciones');
// ── Sanitización y validación de parámetros ──────────────────────────────
// Rechaza cualquier valor que no sea string (bloquea operator injection)
function sanitizeParam(val) {
if (typeof val !== 'string') return undefined;
return val.trim();
}
// Lista blanca de temas válidos (evita escaneo libre de la BD)
const TEMAS_VALIDOS = new Set([
'guerra global', 'inteligencia y seguridad', 'cambio climático',
'demografía y sociedad', 'economía y corporaciones', 'otros',
'geopolítica conflictos', 'seguridad internacional espionaje',
'libertad de prensa periodismo', 'corporaciones poder económico',
'populismo extremismo', 'desinformación redes sociales',
'privacidad vigilancia masiva', 'biodiversidad medioambiente',
'inteligencia artificial tecnología',
]);
const temaRaw = sanitizeParam(req.query.tema);
const subtematica = sanitizeParam(req.query.subtematica);
const palabraClave = sanitizeParam(req.query.palabraClave);
const fechaInicio = sanitizeParam(req.query.fechaInicio);
const fechaFin = sanitizeParam(req.query.fechaFin);
const nodos = sanitizeParam(req.query.nodos);
const complejidad = sanitizeParam(req.query.complejidad);
// Validar tema contra lista blanca
const tema = temaRaw && TEMAS_VALIDOS.has(temaRaw) ? temaRaw : null;
if (!tema) {
res.status(400).json({ error: 'El parámetro "tema" es obligatorio o no válido' });
return;
}
// Validar subtematica: solo letras, números, espacios y guiones (máx 80 chars)
if (subtematica && !/^[\w\s\-áéíóúñüÁÉÍÓÚÑÜ]{1,80}$/.test(subtematica)) {
res.status(400).json({ error: 'subtematica no válida' });
return;
}
// Validar palabraClave: máx 100 chars, escapar metacaracteres regex
let regexKw = null;
if (palabraClave) {
if (palabraClave.length > 100) {
res.status(400).json({ error: 'palabraClave demasiado larga' });
return;
}
regexKw = palabraClave.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
// Validar fechas: formato YYYY-MM-DD estricto
const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
let fechaGte = null, fechaLte = null;
if (fechaInicio && fechaFin) {
if (!ISO_DATE.test(fechaInicio) || !ISO_DATE.test(fechaFin)) {
res.status(400).json({ error: 'Formato de fecha inválido (YYYY-MM-DD)' });
return;
}
fechaGte = new Date(fechaInicio);
fechaLte = new Date(fechaFin);
if (isNaN(fechaGte) || isNaN(fechaLte) || fechaGte > fechaLte) {
res.status(400).json({ error: 'Rango de fechas inválido' });
return;
}
}
// Validar nodos: entero positivo entre 1 y 500
const nodosRaw = parseInt(nodos, 10);
const nodosLimit = (!isNaN(nodosRaw) && nodosRaw > 0) ? Math.min(nodosRaw, 500) : 100;
// Validar complejidad: float entre 0 y 100
const complejidadRaw = parseFloat(complejidad);
const porcentajeSimilitudMin = (!isNaN(complejidadRaw) && complejidadRaw >= 0 && complejidadRaw <= 100)
? complejidadRaw : 0;
// Construir query de MongoDB solo con valores validados
const nodesQuery = { tema };
if (subtematica) nodesQuery.subtema = subtematica;
if (regexKw) nodesQuery.texto = { $regex: regexKw, $options: 'i' };
if (fechaGte) nodesQuery.fecha = { $gte: fechaGte, $lte: fechaLte };
// Imágenes: proporcional a nodosLimit (1/3), mínimo 3 para siempre mostrar algo
const imagenesLimit = Math.max(3, Math.floor(nodosLimit / 3));
const [wikipediaNodes, noticiasNodes, torrentsNodes, imagenesNodes, imagenesWikiNodes] = await Promise.all([
wikipediaCollection.find(nodesQuery).limit(nodosLimit).toArray(),
noticiasCollection.find(nodesQuery).limit(nodosLimit).toArray(),
torrentsCollection.find(nodesQuery).limit(nodosLimit).toArray(),
imagenesCollection.find(nodesQuery).limit(imagenesLimit).toArray(),
imagenesWikiCollection.find(nodesQuery).limit(imagenesLimit).toArray(),
]);
// Preferir imagenes analizadas (con keywords); si no hay, usar imagenes_wiki
const imgNodes = imagenesNodes.length > 0 ? imagenesNodes : imagenesWikiNodes;
const nodes = [...wikipediaNodes, ...noticiasNodes, ...torrentsNodes];
// Nodos de texto
const formattedNodes = nodes.map((result) => ({
id: result.archivo.trim(),
group: result.subtema || 'sin subtema',
tema: result.tema || 'sin tema',
content: result.texto || '',
fecha: result.fecha || '',
fuente: result.fuente || result.autor || result.source || '',
type: 'texto',
}));
// Nodos de imagen — image_url construida desde image_path absoluto
const WIKI_IMAGES_BASE = '/var/www/theflows.net/flujos/FLUJOS_DATOS/IMAGENES/output/wiki_images/';
const imgFormattedNodes = imgNodes.map((result) => {
let relativePath = null;
if (result.image_path && result.image_path.startsWith(WIKI_IMAGES_BASE)) {
const rel = result.image_path.slice(WIKI_IMAGES_BASE.length);
// Reject paths with traversal sequences or absolute paths
if (rel && !rel.includes('..') && !rel.startsWith('/')) {
relativePath = rel;
}
}
return {
id: result.archivo.trim(),
group: result.subtema || result.tema || 'imagen',
tema: result.tema || 'sin tema',
content: result.texto || result.descripcion_wiki || '',
fecha: result.fecha || '',
fuente: result.fuente || result.autor || result.source || '',
type: 'imagen',
image_url: relativePath ? `/wiki-images/${relativePath}` : null,
label: result.subtema || result.tema || result.archivo,
};
}).filter(n => n.image_url);
const allNodes = [...formattedNodes, ...imgFormattedNodes];
const formattedNodes_final = allNodes;
const nodeIds = formattedNodes_final.map(node => node.id);
// Links texto-texto: filtro por complejidad del usuario.
// Links imagen-texto (source1_type='imagen'): umbral fijo de 3% porque la similitud
// TF-IDF keyword↔texto es estructuralmente baja (~3-10%) y quedarían siempre ocultos.
const IMG_UMBRAL = 3.0;
const linksQuery = {
noticia1: { $in: nodeIds },
noticia2: { $in: nodeIds },
$or: [
{ porcentaje_similitud: { $gte: porcentajeSimilitudMin } },
{ porcentaje_similitud: { $gte: IMG_UMBRAL }, source1_type: 'imagen' },
],
};
const links = await comparacionesCollection.find(linksQuery).toArray();
// Limitar links por nodo: cada nodo muestra solo sus top MAX conexiones más fuertes.
// Sin esto, los 100 nodos wikipedia del mismo tema se conectan todos entre sí
// (>8000 links) y forman una bola densa inmanejable.
const MAX_LINKS_PER_NODE = 8;
links.sort((a, b) => b.porcentaje_similitud - a.porcentaje_similitud);
const nodeDegree = new Map();
const selectedLinks = [];
for (const link of links) {
const n1 = link.noticia1.trim();
const n2 = link.noticia2.trim();
const d1 = nodeDegree.get(n1) || 0;
const d2 = nodeDegree.get(n2) || 0;
if (d1 < MAX_LINKS_PER_NODE && d2 < MAX_LINKS_PER_NODE) {
selectedLinks.push(link);
nodeDegree.set(n1, d1 + 1);
nodeDegree.set(n2, d2 + 1);
}
}
const formattedLinks = selectedLinks.map((result) => ({
source: result.noticia1.trim(),
target: result.noticia2.trim(),
value: result.porcentaje_similitud,
}));
res.json({ nodes: formattedNodes_final, links: formattedLinks });
} catch (error) {
console.error('Error al obtener datos:', error);
res.status(500).json({ error: 'Error al obtener datos' });
}
});
// ── STATS: cálculo pesado → MongoDB, endpoint solo lee ─────────────────────────
const STATS_TEMAS = ['guerra global','inteligencia y seguridad','cambio climático','demografía y sociedad','economía y corporaciones'];
const STATS_TEXT_COLS = ['wikipedia','noticias','torrents','imagenes_wiki'];
async function computeAndSaveStats() {
if (!db) return;
console.log('[stats] Calculando stats...');
try {
const [wikipedia, noticias, torrents, imagenes, imagenes_wiki, comparaciones,
comp_imagen_total] = await Promise.all([
db.collection('wikipedia').countDocuments({}),
db.collection('noticias').countDocuments({}),
db.collection('torrents').countDocuments({}),
db.collection('imagenes').countDocuments({}),
db.collection('imagenes_wiki').countDocuments({}),
db.collection('comparaciones').estimatedDocumentCount(),
db.collection('comparaciones').countDocuments({ source1_type: 'imagen' }),
]);
const por_tema = {};
await Promise.all(STATS_TEMAS.map(async tema => {
const counts = await Promise.all(
STATS_TEXT_COLS.map(col => db.collection(col).countDocuments({ tema }))
);
por_tema[tema] = {};
STATS_TEXT_COLS.forEach((col, i) => { por_tema[tema][col] = counts[i]; });
}));
const subtemaRaw = await db.collection('wikipedia').aggregate([
{ $match: { tema: { $in: STATS_TEMAS } } },
{ $group: { _id: { tema: '$tema', subtema: '$subtema' }, n: { $sum: 1 } } },
{ $sort: { n: -1 } },
]).toArray();
const subtemas = {};
for (const doc of subtemaRaw) {
const { tema, subtema } = doc._id;
if (!subtemas[tema]) subtemas[tema] = [];
if (subtemas[tema].length < 10)
subtemas[tema].push({ subtema: subtema || 'sin subtema', n: doc.n });
}
const notSubRaw = await db.collection('noticias').aggregate([
{ $match: { tema: { $in: STATS_TEMAS } } },
{ $group: { _id: { tema: '$tema', subtema: '$subtema' }, n: { $sum: 1 } } },
{ $sort: { n: -1 } },
]).toArray();
const subtemas_noticias = {};
for (const doc of notSubRaw) {
const { tema, subtema } = doc._id;
if (!subtemas_noticias[tema]) subtemas_noticias[tema] = [];
if (subtemas_noticias[tema].length < 8)
subtemas_noticias[tema].push({ subtema: subtema || 'sin subtema', n: doc.n });
}
const compImgRaw = await db.collection('comparaciones').aggregate([
{ $match: { source1_type: 'imagen' } },
{ $group: {
_id: '$tema',
count: { $sum: 1 },
avg_sim: { $avg: '$porcentaje_similitud' },
max_sim: { $max: '$porcentaje_similitud' },
}},
]).toArray();
const comp_imagen = { total: comp_imagen_total, por_tema: {} };
for (const d of compImgRaw) {
comp_imagen.por_tema[d._id] = {
count: d.count,
avg_sim: Math.round(d.avg_sim * 10) / 10,
max_sim: Math.round(d.max_sim * 10) / 10,
};
}
// $sample sin filtro — 99.94% de docs son texto-texto
const simRaw = await db.collection('comparaciones').aggregate([
{ $sample: { size: 3000 } },
{ $group: { _id: null, avg_sim: { $avg: '$porcentaje_similitud' }, max_sim: { $max: '$porcentaje_similitud' } } },
]).toArray();
const comp_texto = simRaw[0]
? { avg_sim: Math.round(simRaw[0].avg_sim * 10) / 10, max_sim: Math.round(simRaw[0].max_sim * 10) / 10 }
: { avg_sim: 0, max_sim: 0 };
const snapshot = {
_id: 'stats',
computed_at: new Date(),
totales: { wikipedia, noticias, torrents, imagenes, imagenes_wiki, comparaciones },
por_tema, subtemas, subtemas_noticias, comp_imagen, comp_texto,
};
await db.collection('stats_cache').replaceOne({ _id: 'stats' }, snapshot, { upsert: true });
console.log('[stats] Stats guardadas en MongoDB');
} catch (e) {
console.error('[stats] Error calculando stats:', e.message);
}
}
// Calcular al arrancar (si no hay cache o tiene más de 6h) y luego cada 6h
async function initStats() {
if (!db) return;
const cached = await db.collection('stats_cache').findOne({ _id: 'stats' });
const sixHours = 6 * 60 * 60 * 1000;
if (!cached || !cached.computed_at || Date.now() - new Date(cached.computed_at).getTime() > sixHours) {
computeAndSaveStats(); // async, no bloquea el arranque
}
setInterval(computeAndSaveStats, sixHours);
}
app.get('/api/stats', async (req, res) => {
try {
if (!db) return res.status(500).json({ error: 'Sin conexión a BD' });
const cached = await db.collection('stats_cache').findOne({ _id: 'stats' });
if (!cached) return res.status(503).json({ error: 'Stats aún calculándose, intenta en unos minutos' });
const { _id, ...data } = cached;
res.json(data);
} catch (e) {
console.error('Error /api/stats:', e);
res.status(500).json({ error: 'Error al obtener estadísticas' });
}
});
// **Luego, definir las rutas de las páginas principales**
// Rutas para las páginas principales
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, '../VISUALIZACION/public/index.html'));
});
app.get('/stats.html', (req, res) => {
res.sendFile(path.join(__dirname, '../VISUALIZACION/public/stats.html'));
});
app.get('/climate.html', (req, res) => {
res.sendFile(path.join(__dirname, '../VISUALIZACION/public/climate.html'));
});
app.get('/glob-war.html', (req, res) => {
res.sendFile(path.join(__dirname, '../VISUALIZACION/public/glob-war.html'));
});
app.get('/popl-up.html', (req, res) => {
res.sendFile(path.join(__dirname, '../VISUALIZACION/public/popl-up.html'));
});
app.get('/int-sec.html', (req, res) => {
res.sendFile(path.join(__dirname, '../VISUALIZACION/public/int-sec.html'));
});
app.get('/eco-corp.html', (req, res) => {
res.sendFile(path.join(__dirname, '../VISUALIZACION/public/eco-corp.html'));
});
// **Después, configurar el middleware de archivos estáticos**
// Imágenes scrapeadas de Wikipedia
app.use('/wiki-images', express.static(
'/var/www/theflows.net/flujos/FLUJOS_DATOS/IMAGENES/output/wiki_images'
));
app.use(express.static(path.join(__dirname, '../VISUALIZACION/public')));
// Conexión a MongoDB usando variables de entorno
const mongoUrl = process.env.MONGO_URL || 'mongodb://localhost:27017';
const dbName = process.env.DB_NAME || 'FLUJOS_DATOS';
let db; // Variable para almacenar la conexión a la base de datos
// Función para conectar a MongoDB
async function connectToMongoDB() {
try {
const mongoClient = new MongoClient(mongoUrl, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
await mongoClient.connect();
db = mongoClient.db(dbName);
console.log('Conectado a MongoDB');
initStats();
} catch (error) {
console.error('Error al conectar a MongoDB:', error);
process.exit(1); // Salir de la aplicación si no se puede conectar
}
}
// Llamar a la función para conectar a MongoDB
connectToMongoDB();
// Iniciar el servidor escuchando en todas las interfaces
app.listen(port, '127.0.0.1', () => {
console.log(`La aplicación está escuchando en http://localhost:${port}`);
});
// Manejar el cierre de la aplicación
process.on('SIGINT', async () => {
if (db) {
await db.close();
console.log('Conexión a MongoDB cerrada');
}
process.exit(0);
});

View file

@ -1,14 +0,0 @@
from obsei.analyzer.classification_analyzer import ClassificationAnalyzerConfig, ZeroShotClassificationAnalyzer
# initialize classification analyzer config
# It can also detect sentiments if "positive" and "negative" labels are added.
analyzer_config=ClassificationAnalyzerConfig(
labels=["service", "delay", "performance"],
)
# initialize classification analyzer
# For supported models refer https://huggingface.co/models?filter=zero-shot-classification
analyzer = ZeroShotClassificationAnalyzer(
model_name_or_path="typeform/mobilebert-uncased-mnli",
device="auto"
)

View file

@ -1,14 +0,0 @@
from obsei.analyzer.classification_analyzer import ClassificationAnalyzerConfig, ZeroShotClassificationAnalyzer
# initialize classification analyzer config
# It can also detect sentiments if "positive" and "negative" labels are added.
analyzer_config=ClassificationAnalyzerConfig(
labels=["service", "delay", "performance"],
)
# initialize classification analyzer
# For supported models refer https://huggingface.co/models?filter=zero-shot-classification
text_analyzer = ZeroShotClassificationAnalyzer(
model_name_or_path="typeform/mobilebert-uncased-mnli",
device="auto"
)

View file

@ -1,7 +0,0 @@
from obsei.analyzer.dummy_analyzer import DummyAnalyzer, DummyAnalyzerConfig
# initialize dummy analyzer's configuration settings
analyzer_config = DummyAnalyzerConfig()
# initialize dummy analyzer
analyzer = DummyAnalyzer()

View file

@ -1,11 +0,0 @@
from obsei.analyzer.ner_analyzer import NERAnalyzer
# NER analyzer does not need configuration settings
analyzer_config=None
# initialize ner analyzer
# For supported models refer https://huggingface.co/models?filter=token-classification
text_analyzer = NERAnalyzer(
model_name_or_path="elastic/distilbert-base-cased-finetuned-conll03-english",
device = "auto"
)

View file

@ -1,22 +0,0 @@
from obsei.analyzer.pii_analyzer import PresidioEngineConfig, PresidioModelConfig, \
PresidioPIIAnalyzer, PresidioPIIAnalyzerConfig
# initialize pii analyzer's config
analyzer_config = PresidioPIIAnalyzerConfig(
# Whether to return only pii analysis or anonymize text
analyze_only=False,
# Whether to return detail information about anonymization decision
return_decision_process=True
)
# initialize pii analyzer
analyzer = PresidioPIIAnalyzer(
engine_config=PresidioEngineConfig(
# spacy and stanza nlp engines are supported
# For more info refer
# https://microsoft.github.io/presidio/analyzer/developing_recognizers/#utilize-spacy-or-stanza
nlp_engine_name="spacy",
# Update desired spacy model and language
models=[PresidioModelConfig(model_name="en_core_web_lg", lang_code="en")]
)
)

View file

@ -1,7 +0,0 @@
from obsei.analyzer.sentiment_analyzer import VaderSentimentAnalyzer
# Vader does not need any configuration settings
analyzer_config=None
# initialize vader sentiment analyzer
text_analyzer = VaderSentimentAnalyzer()

View file

@ -1,11 +0,0 @@
from obsei.analyzer.translation_analyzer import TranslationAnalyzer
# Translator does not need analyzer config
analyzer_config = None
# initialize translator
# For supported models refer https://huggingface.co/models?pipeline_tag=translation
analyzer = TranslationAnalyzer(
model_name_or_path="Helsinki-NLP/opus-mt-hi-en",
device = "auto"
)

View file

@ -1,10 +0,0 @@
from pandas import DataFrame
from obsei.sink.pandas_sink import PandasSink, PandasSinkConfig
# initialize pandas sink config
sink_config = PandasSinkConfig(
dataframe=DataFrame()
)
# initialize pandas sink
sink = PandasSink()

View file

@ -1,17 +0,0 @@
import pandas as pd
from obsei.source.pandas_source import PandasSource, PandasSourceConfig
# Initialize your Pandas DataFrame from your sources like csv, excel, sql etc
# In following example we are reading csv which have two columns title and text
csv_file = "https://raw.githubusercontent.com/deepset-ai/haystack/master/tutorials/small_generator_dataset.csv"
dataframe = pd.read_csv(csv_file)
# initialize pandas sink config
sink_config = PandasSourceConfig(
dataframe=dataframe,
include_columns=["score"],
text_columns=["name", "degree"],
)
# initialize pandas sink
sink = PandasSource()

View file

@ -1,10 +0,0 @@
from pandas import DataFrame
from obsei.sink.pandas_sink import PandasSink, PandasSinkConfig
# initialize pandas sink config
sink_config = PandasSinkConfig(
dataframe=DataFrame()
)
# initialize pandas sink
sink = PandasSink()

View file

@ -1,13 +0,0 @@
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/tensorflow', methods=['POST'])
def tensorflow_endpoint():
data = request.json
# Aquí procesarías el dato con tu modelo TensorFlow
# Por ahora solo lo devolvemos como está
return jsonify(data)
if __name__ == '__main__':
app.run(port=5000)

View file

@ -1,45 +0,0 @@
import pandas as pd
from pymongo import MongoClient
from obsei.source.pandas_source import PandasSource, PandasSourceConfig
from obsei.analyzer.classification_analyzer import ClassificationAnalyzerConfig, ZeroShotClassificationAnalyzer
from obsei.sink.pandas_sink import PandasSink, PandasSinkConfig
# Configura la fuente
source = PandasSource()
source_config = PandasSourceConfig(
# Proporciona tu configuración aquí
)
# Configura el analizador
analyzer = ZeroShotClassificationAnalyzer(
# Proporciona tu configuración aquí
)
analyzer_config = ClassificationAnalyzerConfig(
# Proporciona tu configuración aquí
)
# Configura el sumidero
sink = PandasSink()
sink_config = PandasSinkConfig(
# Proporciona tu configuración aquí
)
# Ejecuta el flujo de trabajo
source_response_list = source.lookup(source_config)
analyzer_response_list = analyzer.analyze_input(
source_response_list=source_response_list,
analyzer_config=analyzer_config
)
sink_response_list = sink.send_data(analyzer_response_list, sink_config)
# Ahora `sink_response_list` es una lista de DataFrames.
# Puedes concatenarlos en un solo DataFrame si es necesario.
df = pd.concat(sink_response_list)
# Realiza cualquier transformación o limpieza de datos necesaria aquí...
# Finalmente, guarda el DataFrame en MongoDB.
client = MongoClient('mongodb://localhost:27017/')
db = client['nombre_de_tu_base_de_datos']
collection = db['nombre_de_tu_coleccion']
collection.insert_many(df.to_dict('records'))

File diff suppressed because it is too large Load diff

View file

@ -1,32 +0,0 @@
{
"name": "flujos",
"version": "1.0.0",
"description": "Aplicación FLUJOS",
"main": "FLUJOS_APP.js",
"scripts": {
"start": "node FLUJOS_APP.js",
"dev": "nodemon FLUJOS_APP.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"@elastic/elasticsearch": "^8.9.0",
"body-parser": "^1.20.3",
"dotenv": "^16.4.5",
"express": "^4.21.0",
"express-graphql": "^0.12.0",
"force-graph": "^1.43.2",
"graphql": "^15.8.0",
"helmet": "^8.0.0",
"mongod": "^2.0.0",
"mongodb": "^6.9.0",
"mongoose": "^7.3.4",
"node-fetch": "^3.3.2",
"tree": "^0.1.3"
},
"devDependencies": {
"nodemon": "^3.1.7",
"parcel-bundler": "^1.8.1"
}
}

View file

@ -1 +0,0 @@
pip install obsei[all]

View file

View file

@ -1,63 +0,0 @@
const User = require('../models/User');
const Post = require('../models/Post');
const Node = require('../models/Node');
const Flow = require('../models/Flow');
const Project = require('../models/Project');
module.exports = {
users: async () => {
//... tu código existente para obtener usuarios
},
posts: async () => {
//... tu código existente para obtener posts
},
nodes: async () => {
try {
const nodes = await Node.find();
return nodes.map(node => {
return {
...node._doc,
_id: node._id.toString(),
flow: getFlow.bind(this, node._doc.flow)
};
});
} catch (err) {
throw err;
}
},
flows: async () => {
try {
const flows = await Flow.find();
return flows.map(flow => {
return {
...flow._doc,
_id: flow._id.toString(),
nodes: getNodes.bind(this, flow._doc.nodes),
project: getProject.bind(this, flow._doc.project)
};
});
} catch (err) {
throw err;
}
},
projects: async () => {
try {
const projects = await Project.find();
return projects.map(project => {
return {
...project._doc,
_id: project._id.toString(),
flows: getFlows.bind(this, project._doc.flows)
};
});
} catch (err) {
throw err;
}
},
}
// Aquí necesitarías implementar las funciones auxiliares getPosts, getUser, getFlow, getNodes, getFlows y getProject.

View file

@ -1,104 +0,0 @@
const { buildSchema } = require('graphql');
module.exports = buildSchema(`
type User {
_id: ID!
name: String!
email: String!
posts: [Post!]
}
type Post {
_id: ID!
title: String!
content: String!
creator: User!
}
type Node {
_id: ID!
name: String!
flow: Flow!
}
type Flow {
_id: ID!
nodes: [Node!]!
project: Project!
}
type Project {
_id: ID!
flows: [Flow!]!
}
type RootQuery {
users: [User!]!
posts: [Post!]!
nodes: [Node!]!
flows: [Flow!]!
projects: [Project!]!
}
schema {
query: RootQuery
}
`);
// export const newsData = [
// {
// "id": "1",
// "title": "BlackRock adquiere empresa de tecnología financiera",
// "shares": 3500
// },
// {
// "id": "2",
// "title": "BlackRock lanza nuevo fondo de inversión en energías renovables",
// "shares": 2900
// },
// {
// "id": "3",
// "title": "BlackRock reporta ganancias record en el último trimestre",
// "shares": 4000
// },
// {
// "id": "4",
// "title": "BlackRock lidera ronda de financiamiento en startup de inteligencia artificial",
// "shares": 2100
// },
// {
// "id": "5",
// "title": "CEO de BlackRock promueve inversiones sostenibles en cumbre global",
// "shares": 2600
// },
// {
// "id": "6",
// "title": "BlackRock apunta a mercados emergentes con nuevo producto de inversión",
// "shares": 2800
// },
// {
// "id": "7",
// "title": "BlackRock se compromete a reducir su huella de carbono en un 50% para 2030",
// "shares": 3500
// },
// {
// "id": "8",
// "title": "BlackRock lidera el mercado de ETFs con fuerte crecimiento en el último año",
// "shares": 3900
// },
// {
// "id": "9",
// "title": "BlackRock anuncia inversión millonaria en infraestructura de blockchain",
// "shares": 3300
// },
// {
// "id": "10",
// "title": "BlackRock apoya iniciativa de transparencia financiera en G20",
// "shares": 3000
// }
// ];

View file

@ -1,11 +0,0 @@
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const FlowSchema = new Schema({
sourceNode: { type: Schema.Types.ObjectId, ref: 'Node' },
targetNode: { type: Schema.Types.ObjectId, ref: 'Node' },
intensity: Number,
// Aquí puedes incluir cualquier metadato del flujo que necesites.
});
module.exports = mongoose.model('Flow', FlowSchema);

View file

@ -1,10 +0,0 @@
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const NodeSchema = new Schema({
coordinates: { x: Number, y: Number, z: Number },
type: String,
// Aquí puedes incluir cualquier metadato del nodo que necesites.
});
module.exports = mongoose.model('Node', NodeSchema);

View file

@ -1,13 +0,0 @@
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ProjectSchema = new Schema({
user: { type: Schema.Types.ObjectId, ref: 'User' },
nodes: [{ type: Schema.Types.ObjectId, ref: 'Node' }],
flows: [{ type: Schema.Types.ObjectId, ref: 'Flow' }],
// Aquí puedes incluir cualquier metadato del proyecto que necesites.
});
module.exports = mongoose.model('Project', ProjectSchema);

View file

@ -1,10 +0,0 @@
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const UserSchema = new Schema({
username: String,
password: String,
// Aquí puedes incluir cualquier metadato del usuario que necesites.
});
module.exports = mongoose.model('User', UserSchema);

File diff suppressed because it is too large Load diff

View file

@ -1,27 +0,0 @@
{
"dependencies": {
"@elastic/elasticsearch": "^8.9.0",
"3d-force-graph": "^1.73.3",
"express": "^4.18.2",
"express-graphql": "^0.12.0",
"force-graph": "^1.43.2",
"graphql": "^15.8.0",
"mongod": "^2.0.0",
"mongoose": "^7.3.4",
"three": "^0.168.0",
"tree": "^0.1.3"
},
"name": "flujos",
"version": "1.0.0",
"main": "FLUJOS_APP.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"devDependencies": {
"parcel-bundler": "^1.8.1"
}
}

View file

@ -1,80 +0,0 @@
:root {
--cube-size: 80px;
--line-color: #333;
--hover-color: #2ecc71;
--background-color: #000;
--sidebar-width: 250px; /* Ajustamos el ancho del sidebar */
}
body {
margin: 0;
padding: 0;
display: flex;
justify-content: flex-start; /* Asegura que el contenido comience desde la izquierda */
align-items: center;
height: 100vh;
background-color: var(--background-color);
}
.graph-container {
position: relative;
width: calc(100vw - var(--sidebar-width)); /* Restamos el ancho del sidebar */
height: 100vh;
margin-left: var(--sidebar-width); /* Añadimos margen para que no se solape */
}
.cube-container {
position: absolute;
width: var(--cube-size);
height: var(--cube-size);
transform-style: preserve-3d;
transition: transform 1s ease;
}
.cube-container:hover {
transform: rotateX(360deg) rotateY(360deg); /* Efecto al pasar el mouse */
}
.cube {
position: absolute;
width: 100%;
height: 100%;
transform-style: preserve-3d;
}
.face {
position: absolute;
width: 100%;
height: 100%;
background-color: var(--hover-color);
border: 1px solid #000;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.65rem;
color: white;
}
.front { transform: translateZ(calc(var(--cube-size) / 2)); }
.back { transform: rotateY(180deg) translateZ(calc(var(--cube-size) / 2)); }
.left { transform: rotateY(-90deg) translateZ(calc(var(--cube-size) / 2)); }
.right { transform: rotateY(90deg) translateZ(calc(var(--cube-size) / 2)); }
.top { transform: rotateX(90deg) translateZ(calc(var(--cube-size) / 2)); }
.bottom { transform: rotateX(-90deg) translateZ(calc(var(--cube-size) / 2)); }
.lines {
position: absolute;
top: 0;
left: 0;
z-index: -1;
}
.line-path {
stroke: var(--line-color);
stroke-width: 2;
transition: stroke 0.3s;
}
.line-path:hover {
stroke: #e74c3c;
}

View file

@ -1,150 +0,0 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Visualización 2D de Noticias Políticas</title>
<link rel="stylesheet" href="3dscript_eco-corp.css">
<style>
.popup {
display: none;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
color: black;
padding: 20px;
border-radius: 10px;
z-index: 2;
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.5);
}
.popup:focus,
.cube-container:focus + .popup {
display: block;
}
.popup button {
display: block;
margin: 10px auto;
padding: 10px;
background-color: #333;
color: white;
border: none;
cursor: pointer;
}
.popup button:hover {
background-color: #555;
}
</style>
</head>
<body>
<div class="graph-container" id="graph-container">
<svg class="lines" xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" id="svg-lines">
<!-- Líneas generadas dinámicamente -->
</svg>
</div>
<script>
const numCubes = 9; // Número total de cubos
const spacing = 150; // Espacio mínimo entre los cubos
const graphContainer = document.getElementById('graph-container');
const svgLines = document.getElementById('svg-lines');
let cubePositions = [];
// Función para detectar colisiones y asegurarse de que los cubos no se solapen
function detectCollision(newX, newY, positions) {
for (let pos of positions) {
const distance = Math.sqrt((newX - pos.x) ** 2 + (newY - pos.y) ** 2);
if (distance < spacing) {
return true; // Hay colisión
}
}
return false; // No hay colisión
}
// Función para generar una posición aleatoria sin que los cubos se solapen
function getRandomPosition(maxWidth, maxHeight) {
let x, y;
do {
x = Math.random() * (maxWidth - spacing);
y = Math.random() * (maxHeight - spacing);
} while (detectCollision(x, y, cubePositions));
return { x, y };
}
// Función para generar cubos con posiciones aleatorias
function generateRandomCubes(cubeCount) {
for (let i = 0; i < cubeCount; i++) {
const position = getRandomPosition(window.innerWidth, window.innerHeight);
const cubeContainer = document.createElement('div');
cubeContainer.classList.add('cube-container');
cubeContainer.setAttribute('tabindex', '0');
cubeContainer.style.top = position.y + 'px';
cubeContainer.style.left = position.x + 'px';
const cube = document.createElement('div');
cube.className = 'cube';
[['front', `País ${i}`], ['back', `Detalle ${i}`],
['left', `Año ${2000 + i}`], ['right', `Muertos ${(i + 1) * 1000}`],
['top', 'ONU'], ['bottom', 'Fuente']].forEach(([cls, txt]) => {
const face = document.createElement('div');
face.className = `face ${cls}`;
face.textContent = txt;
cube.appendChild(face);
});
cubeContainer.appendChild(cube);
// Crear un popup para cada cubo
const popup = document.createElement('div');
popup.classList.add('popup');
const p = document.createElement('p');
p.textContent = `Noticia relacionada con País ${i}`;
const btn = document.createElement('button');
btn.textContent = 'Close';
popup.appendChild(p);
popup.appendChild(btn);
popup.querySelector('button').addEventListener('click', () => {
popup.style.display = 'none';
cubeContainer.focus(); // Regresar el foco al cubo
});
cubeContainer.addEventListener('focus', () => {
popup.style.display = 'block';
});
cubePositions.push({ x: position.x + 35, y: position.y + 35 }); // Guardar la posición
graphContainer.appendChild(cubeContainer);
graphContainer.appendChild(popup); // Añadir el popup después del cubo
}
}
// Función para generar las líneas entre cubos relacionados
function generateLines() {
for (let i = 0; i < cubePositions.length - 1; i++) {
const x1 = cubePositions[i].x;
const y1 = cubePositions[i].y;
const x2 = cubePositions[i + 1].x;
const y2 = cubePositions[i + 1].y;
const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
line.setAttribute('x1', x1);
line.setAttribute('y1', y1);
line.setAttribute('x2', x2);
line.setAttribute('y2', y2);
line.setAttribute('stroke', '#333');
line.setAttribute('stroke-width', '2');
svgLines.appendChild(line);
}
}
// Generar cubos aleatorios y las líneas de conexión
generateRandomCubes(numCubes);
generateLines();
</script>
</body>
</html>

View file

@ -1,332 +0,0 @@
@font-face {
font-family: "Retrolift";
src: url("/home/pancho/PROGRAMACION/FLUJOS/retrolift.woff2") format("woff2"),
url("/home/pancho/PROGRAMACION/FLUJOS/retrolift.woff") format("woff");
font-weight: normal;
font-style: normal;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Fira Code';
text-shadow: 10px 10px 20px rgba(0, 255, 76, 0.3);
}
body {
font-family: 'Fira Code', monospace;
background: #000000;
color: #000000;
}
header {
display: flex;
justify-content: center;
align-items: center;
height: 70px;
background-color: #000000;
color: #ffffff;
box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
}
.logo {
font-family: "Retrolift", sans-serif;
font-size: 4em;
font-weight: bold;
letter-spacing: 4px;
text-shadow: 6px 6px 6px #73ff00;
margin-bottom: 10px;
}
.glob-war:hover .logo { text-shadow: 2px 2px 8px #39ff14; }
.int-sec:hover .logo { text-shadow: 2px 2px 8px #ff69b4; }
.climate:hover .logo { text-shadow: 2px 2px 8px #ff4500; }
.eco-corp:hover .logo { text-shadow: 2px 2px 8px #006400; }
.popl-up:hover .logo { text-shadow: 2px 2px 8px #00008b; }
nav {
display: flex;
justify-content: center;
background-color: #000000;
color: #ff1a1a;
padding: 10px 0;
box-shadow: 0 10px 10px rgba(0, 0, 0, 0.1);
margin-top: 40px;
margin-bottom: 5px;
}
.nav-links {
list-style: none;
display: flex;
gap: 6em; /* incrementa la distancia entre los elementos */
}
.nav-links a {
color: #000000;
text-decoration: none;
font-size: 1em;
font-weight: bold;
transition: color 0.3s ease, transform 0.3s ease, box-shadow 0.3s ease;
padding: 20px 40px;
box-shadow: 0 0 0px rgba(28, 103, 241, 0);
/* Estilo de los botones */
position:relative;
border: none;
transition: .4s ease-in;
z-index: 1;
width: 40vw;
height: 20vh;
border:3vw;
align-items: center;
border: 3px solid ;
}
.nav-links a:hover {
transform: scale(1.05);
box-shadow: 0 0 6px rgba(0,0,0,0.3);
/* Estilo hover de los botones */
box-shadow: 2vw 1vw;
border: 3px solid black ;
}
.glob-war:hover { color: #39ff14; }
.int-sec:hover { color: #ff69b4; }
.climate:hover { color: #ff4500; }
.eco-corp:hover { color: #00fff2; }
.popl-up:hover { color: #0066ff; }
.glob-war {
color: #FF4136;
background-color: red;
}
.int-sec {
color: #0074D9;
background-color: darkblue;
}
.climate {
color: #2ECC40;
background-color: lightgreen;
}
.eco-corp {
color: #FFDC00;
background-color: yellow;
}
.popl-up {
color: #FF851B;
background-color: orange;
}
.background {
display: flex;
height: 100vh;
width: 99%;
overflow-x: scroll;
}
.background a {
display: block;
width: 20%;
height: 90vh;
transition: transform 1.5s ease;
}
.background img {
width: 20%;
height: 90vh;
object-fit: cover;
transition: transform 1.5s ease;
}
.background a img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 1.5s ease;
}
.background img:hover {
transform: scale(1.1);
}
#sidebar.active {
transform: translateX(0);
}
#sidebar {
position: fixed;
left: 0;
top: 0;
width: 250px;
height: 100vh;
background-image: url("/images/flujos7.jpg");
background-size: cover;
color: #39ff14;
padding: 30px;
box-shadow: 2px 0 10px rgba(0, 0, 0, 0.1);
transform: translateX(-90%);
transition: transform 0.3s ease-out;
overflow: auto;
font-size:18px;
z-index: 3;
text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; /* Añade el borde al texto */
}
#sidebar h2 {
color: #39ff14;
font-size: 1.2em;
font-weight: bold;
margin-bottom: 15px;
text-shadow: -1px 0 black, 0 3px black, 3px 0 black, 0 -1px black; /* Añade el borde al texto */
}
#sidebar:hover {
transform: translateX(0);
}
#sidebarToggle {
position: absolute;
left: 1em;
top: 1em;
background: #007BFF;
color: #39ff14;
border: none;
padding: 10px 20px;
cursor: pointer;
border-radius: 5px;
transition: background 0.3s ease;
z-index: 2;
}
#sidebarToggle {
display: none;
}
#sidebar form {
display: flex;
flex-direction: column;
gap: 10px;
font-size:20px;
}
#sidebar label {
color: #39ff14;
font-size: 0.9em;
font-weight: bold;
text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; /* Añade el borde al texto */
}
#sidebar input {
padding: 10px;
border: 2px solid #39ff14; /* Añade el borde verde al input */
background: black; /* Cambia el fondo del input a negro */
color: #39ff14; /* Cambia el color del texto en el input a verde */
border-radius: 5px;
box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.2);
transition: box-shadow 0.3s ease;
}
#sidebar input:hover {
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.3);
}
#sidebar input[type="submit"] {
color: #39ff14;
background: #ff6600;
cursor: pointer;
}
#sidebar input[type="submit"]:hover {
background: #ff6600;
}
footer {
width: 100%;
background-color: #000000;
color: #39ff14;
text-align: center;
padding: 10px 0;
position: fixed;
bottom: 0;
font-family: 'Courier New', Courier, monospace;
z-index: 1;
}
footer a {
color: #39ff14;
text-decoration: none;
transition: color 0.3s ease;
}
footer a:hover {
color: #2ECC40;
}
footer p {
margin: 0;
}
#climateContainer {
position: absolute;
width: 100%;
height: 100%;
opacity: 0.5;
}
@media screen and (max-width: 768px) {
.nav-links a {
font-size: 0.8em; /* reduce el tamaño de la fuente */
padding: 10px 20px; /* reduce el padding */
}
.nav-links {
list-style: none;
display: flex;
gap: 2em; /* incrementa la distancia entre los elementos */
}
}
.fade-out {
animation: fadeOut 2s forwards; /* Fades out over 3 seconds */
}
@keyframes fadeOut {
from {opacity: 1;}
to {opacity: 0;}
}
.grafico {
z-index: 1; /* Bring to front */
/* Rest of your styles */
}
.grafico {
width: 100%;
height: 100vh;
position: absolute;
z-index: 1;
}

View file

@ -1,161 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CLIMATE</title>
<link rel="stylesheet" href="climate.css">
<link rel="stylesheet" href="sub-nav.css">
<!-- Fuentes de Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;700&display=swap" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js"></script>
<script type="importmap">
{ "imports": { "three": "https://esm.sh/three@0.179.0", "three/": "https://esm.sh/three@0.179.0/" } }
</script>
</head>
<body>
<nav class="top-nav">
<div class="section-buttons">
<div class="section-item">
<a href="glob-war.html" class="section-btn glob-war-btn">GLOB-WAR</a>
</div>
<div class="section-item">
<a href="int-sec.html" class="section-btn int-sec-btn">INT-SEC</a>
</div>
<div class="section-item current">
<a href="climate.html" class="section-btn climate-btn">CLIMATE <span class="dropdown-arrow"></span></a>
<div class="section-dropdown">
<a href="#" onclick="setSubtema('cambio climático');return false;">Cambio Climático</a>
<a href="#" onclick="setSubtema('desastres naturales');return false;">Desastres Naturales</a>
<a href="#" onclick="setSubtema('conservación');return false;">Conservación</a>
<a href="#" onclick="setSubtema('energía renovable');return false;">Energía Renovable</a>
<a href="#" onclick="setSubtema('contaminacion');return false;">Escasez de Agua</a>
</div>
</div>
<div class="section-item">
<a href="eco-corp.html" class="section-btn eco-corp-btn">ECO-CORP</a>
</div>
<div class="section-item">
<a href="popl-up.html" class="section-btn popl-up-btn">POPL-UP</a>
</div>
</div>
</nav>
<script>
function setSubtema(val) {
var sel = document.getElementById('param2');
if (sel) { sel.value = val; }
var form = document.getElementById('paramForm');
if (form) form.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));
}
document.addEventListener('DOMContentLoaded', function() {
/* ── Dropdown touch (móvil) ── */
var curr = document.querySelector('.section-item.current');
if (curr) {
curr.querySelector('.section-btn').addEventListener('touchend', function(e) {
e.preventDefault();
curr.classList.toggle('open');
});
document.addEventListener('touchend', function(e) {
if (!curr.contains(e.target)) curr.classList.remove('open');
});
}
/* ── Sidebar: botón toggle visible en móvil ── */
var toggle = document.getElementById('sidebarToggle');
var sidebar = document.getElementById('sidebar');
if (toggle && sidebar) {
toggle.style.display = 'block';
toggle.addEventListener('click', function() {
sidebar.classList.toggle('active');
});
}
});
</script>
<main class="split-screen">
<div id="graphPanel" style="position:relative;">
<button id="volverGrafoBtn">← Volver al grafo completo</button>
<div id="climateContainer" style="position: absolute; width: 100%; height: 100%;"></div>
<div class="background">
<img src="/images/flujos6.jpg">
<img src="/images/flujos6.jpg">
<img src="/images/flujos6.jpg">
<img src="/images/flujos6.jpg">
<img src="/images/flujos6.jpg">
<script>
setTimeout(function() {
var fondo = document.querySelector('.background');
fondo.classList.add('fade-out');
fondo.style.pointerEvents = 'none';
}, 1000);
</script>
</div>
</div>
<div id="detailPanel">
<button id="closeDetail">✕ cerrar</button>
<div id="detailContent">
<div class="detail-meta">
<span class="detail-author"></span>
<span class="detail-date"></span>
</div>
<h2 class="detail-title"></h2>
<div class="detail-relations">
<span class="relations-count"></span>
<div class="relations-nav">
<button id="prevRelation" disabled>&#8592; ant</button>
<span id="relationLabel"></span>
<button id="nextRelation" disabled>sig &#8594;</button>
</div>
</div>
<div class="detail-body"></div>
</div>
</div>
</main>
<div id="sidebar">
<h2>Parámetros</h2>
<form id="paramForm">
<label for="fecha_inicio">Fecha de inicio:</label>
<input type="date" id="fecha_inicio" name="fecha_inicio">
<label for="fecha_fin">Fecha de fin:</label>
<input type="date" id="fecha_fin" name="fecha_fin">
<label for="nodos">Nodos:</label>
<input type="number" id="nodos" name="nodos" value="100" min="5" max="500">
<label for="complejidad">% similitud: <span id="complejidadVal" class="sim-val">8</span></label>
<input type="range" id="complejidad" name="complejidad" min="1" max="25" value="8"
oninput="document.getElementById('complejidadVal').textContent = this.value">
<label for="param1">Palabra clave:</label>
<input type="text" id="param1" name="param1" placeholder="ej: glaciares, CO2...">
<label for="param2">Subtematica:</label>
<select id="param2" name="param2">
<option value="">— Todas —</option>
<option value="conservación">conservación</option>
<option value="cambio climático">cambio climático</option>
<option value="energía renovable">energía renovable</option>
<option value="desastres naturales">desastres naturales</option>
</select>
<input type="submit" value="Aplicar">
</form>
</div>
<button id="sidebarToggle">Toggle Sidebar</button>
<!-- Movemos la inclusión del script aquí, al final del body -->
<script type="module" src="output_climate_pruebas.js"></script>
</body>
</html>

View file

@ -1,236 +0,0 @@
@font-face {
font-family: "Retrolift";
src: url("/home/pancho/PROGRAMACION/FLUJOS/retrolift.woff2") format("woff2"),
url("/home/pancho/PROGRAMACION/FLUJOS/retrolift.woff") format("woff");
font-weight: normal;
font-style: normal;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Fira Code';
text-shadow: 10px 10px 20px rgba(0, 255, 76, 0.3);
}
body {
font-family: 'Fira Code', monospace;
background: #000000;
color: #000000;
}
header {
display: flex;
justify-content: center;
align-items: center;
height: 70px;
background-color: #000000;
color: #ffffff;
box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
}
.logo {
font-family: "Retrolift", sans-serif;
font-size: 4em;
font-weight: bold;
letter-spacing: 4px;
text-shadow: 6px 6px 6px #73ff00;
margin-bottom: 10px;
}
.glob-war:hover .logo { text-shadow: 2px 2px 8px #39ff14; }
.int-sec:hover .logo { text-shadow: 2px 2px 8px #ff69b4; }
.climate:hover .logo { text-shadow: 2px 2px 8px #ff4500; }
.eco-corp:hover .logo { text-shadow: 2px 2px 8px #006400; }
.popl-up:hover .logo { text-shadow: 2px 2px 8px #00008b; }
nav {
display: flex;
justify-content: center;
background-color: #000000;
color: #ff1a1a;
padding: 10px 0;
box-shadow: 0 10px 10px rgba(0, 0, 0, 0.1);
margin-top: 40px;
margin-bottom: 5px;
}
.nav-links {
list-style: none;
display: flex;
gap: 6em;
}
.nav-links a {
color: #000000;
text-decoration: none;
font-size: 1em;
font-weight: bold;
transition: color 0.3s ease, transform 0.3s ease, box-shadow 0.3s ease;
padding: 20px 40px;
box-shadow: 0 0 0px rgba(28, 103, 241, 0);
position: relative;
border: none;
transition: .4s ease-in;
z-index: 1;
width: 40vw;
height: 20vh;
border: 3vw;
align-items: center;
border: 3px solid;
}
.nav-links a:hover {
transform: scale(1.05);
box-shadow: 0 0 6px rgba(0,0,0,0.3);
border: 3px solid black;
}
.glob-war:hover { color: #39ff14; }
.int-sec:hover { color: #ff69b4; }
.climate:hover { color: #ff4500; }
.eco-corp:hover { color: #00fff2; }
.popl-up:hover { color: #0066ff; }
.glob-war { color: #FF4136; background-color: red; }
.int-sec { color: #0074D9; background-color: darkblue; }
.climate { color: #2ECC40; background-color: lightgreen; }
.eco-corp { color: #FFDC00; background-color: yellow; }
.popl-up { color: #FF851B; background-color: orange; }
.background {
display: flex;
height: 100vh;
width: 99%;
overflow-x: scroll;
}
.background a {
display: block;
width: 20%;
height: 90vh;
transition: transform 1.5s ease;
}
.background img {
width: 20%;
height: 90vh;
object-fit: cover;
transition: transform 1.5s ease;
}
.background img:hover {
transform: scale(1.1);
}
/* Sidebar con comportamiento onhover */
#sidebar {
position: fixed;
left: 0;
top: 0;
width: 250px;
height: 100vh;
background-image: url("/images/flujos7.jpg");
background-size: cover;
color: #39ff14;
padding: 30px;
box-shadow: 2px 0 10px rgba(0, 0, 0, 0.1);
transform: translateX(-220px);
transition: transform 0.3s ease-out;
overflow: auto;
font-size: 18px;
z-index: 3;
text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;
}
#sidebar:hover {
transform: translateX(0);
}
#sidebar h2 {
color: #39ff14;
font-size: 1.2em;
font-weight: bold;
margin-bottom: 15px;
text-shadow: -1px 0 black, 0 3px black, 3px 0 black, 0 -1px black;
}
#sidebar form {
display: flex;
flex-direction: column;
gap: 10px;
font-size: 20px;
}
#sidebar label {
color: #39ff14;
font-size: 0.9em;
font-weight: bold;
text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;
}
#sidebar input {
padding: 10px;
border: 2px solid #39ff14;
background: black;
color: #39ff14;
border-radius: 5px;
box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.2);
transition: box-shadow 0.3s ease;
}
#sidebar input:hover {
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.3);
}
#sidebar input[type="submit"] {
color: #39ff14;
background: #ff6600;
cursor: pointer;
}
#sidebar input[type="submit"]:hover {
background: #ff6600;
}
footer {
width: 100%;
background-color: #000000;
color: #39ff14;
text-align: center;
padding: 10px 0;
position: fixed;
bottom: 0;
font-family: 'Courier New', Courier, monospace;
z-index: 6;
}
footer a {
color: #39ff14;
text-decoration: none;
transition: color 0.3s ease;
}
footer a:hover {
color: #2ECC40;
}
footer p {
margin: 0;
}
/* Ajuste del iframe para que respete el espacio del sidebar */
.iframe-container {
width: calc(100% - 250px);
height: 100vh;
background: #000000;
margin: 0 auto;
border: none;
z-index: 1;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
position: absolute;
left: 250px;
}

View file

@ -1,161 +0,0 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Economía y Corporaciones</title>
<link rel="stylesheet" href="eco-corp.css">
<link rel="stylesheet" href="sub-nav.css">
<!-- Fuentes de Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;700&display=swap" rel="stylesheet">
<!-- Cargar D3.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js"></script>
<script type="importmap">
{ "imports": { "three": "https://esm.sh/three@0.179.0", "three/": "https://esm.sh/three@0.179.0/" } }
</script>
</head>
<body>
<nav class="top-nav">
<div class="section-buttons">
<div class="section-item">
<a href="glob-war.html" class="section-btn glob-war-btn">GLOB-WAR</a>
</div>
<div class="section-item">
<a href="int-sec.html" class="section-btn int-sec-btn">INT-SEC</a>
</div>
<div class="section-item">
<a href="climate.html" class="section-btn climate-btn">CLIMATE</a>
</div>
<div class="section-item current">
<a href="eco-corp.html" class="section-btn eco-corp-btn">ECO-CORP <span class="dropdown-arrow"></span></a>
<div class="section-dropdown">
<a href="#" onclick="setSubtema('economía global');return false;">Economía Global</a>
<a href="#" onclick="setSubtema('corporaciones multinacionales');return false;">Corporaciones Multinacionales</a>
<a href="#" onclick="setSubtema('comercio internacional');return false;">Comercio Internacional</a>
<a href="#" onclick="setSubtema('organismos financieros');return false;">Organismos Financieros</a>
<a href="#" onclick="setSubtema('desigualdad económica');return false;">Desigualdad Económica</a>
</div>
</div>
<div class="section-item">
<a href="popl-up.html" class="section-btn popl-up-btn">POPL-UP</a>
</div>
</div>
</nav>
<script>
function setSubtema(val) {
var sel = document.getElementById('param2');
if (sel) { sel.value = val; }
var form = document.getElementById('paramForm');
if (form) form.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));
}
document.addEventListener('DOMContentLoaded', function() {
/* ── Dropdown touch (móvil) ── */
var curr = document.querySelector('.section-item.current');
if (curr) {
curr.querySelector('.section-btn').addEventListener('touchend', function(e) {
e.preventDefault();
curr.classList.toggle('open');
});
document.addEventListener('touchend', function(e) {
if (!curr.contains(e.target)) curr.classList.remove('open');
});
}
/* ── Sidebar: botón toggle visible en móvil ── */
var toggle = document.getElementById('sidebarToggle');
var sidebar = document.getElementById('sidebar');
if (toggle && sidebar) {
toggle.style.display = 'block';
toggle.addEventListener('click', function() {
sidebar.classList.toggle('active');
});
}
});
</script>
<main class="split-screen">
<div id="graphPanel" style="position:relative;">
<button id="volverGrafoBtn">← Volver al grafo completo</button>
<div id="ecoCorpContainer" style="position: absolute; width: 100%; height: 100%;"></div>
<div class="background">
<img src="/images/flujos.jpg">
<img src="/images/flujos.jpg">
<img src="/images/flujos.jpg">
<img src="/images/flujos.jpg">
<img src="/images/flujos.jpg">
<script>
setTimeout(function() {
var fondo = document.querySelector('.background');
fondo.classList.add('fade-out');
fondo.style.pointerEvents = 'none';
}, 1000);
</script>
</div>
</div>
<div id="detailPanel">
<button id="closeDetail">✕ cerrar</button>
<div id="detailContent">
<div class="detail-meta">
<span class="detail-author"></span>
<span class="detail-date"></span>
</div>
<h2 class="detail-title"></h2>
<div class="detail-relations">
<span class="relations-count"></span>
<div class="relations-nav">
<button id="prevRelation" disabled>&#8592; ant</button>
<span id="relationLabel"></span>
<button id="nextRelation" disabled>sig &#8594;</button>
</div>
</div>
<div class="detail-body"></div>
</div>
</div>
</main>
<div id="sidebar">
<h2>Parámetros</h2>
<form id="paramForm">
<label for="fecha_inicio">Fecha de inicio:</label>
<input type="date" id="fecha_inicio" name="fecha_inicio">
<label for="fecha_fin">Fecha de fin:</label>
<input type="date" id="fecha_fin" name="fecha_fin">
<label for="nodos">Nodos:</label>
<input type="number" id="nodos" name="nodos" value="100" min="5" max="500">
<label for="complejidad">% similitud: <span id="complejidadVal" class="sim-val">8</span></label>
<input type="range" id="complejidad" name="complejidad" min="1" max="25" value="8"
oninput="document.getElementById('complejidadVal').textContent = this.value">
<label for="param1">Palabra clave:</label>
<input type="text" id="param1" name="param1" placeholder="ej: FMI, Amazon...">
<label for="param2">Subtematica:</label>
<select id="param2" name="param2">
<option value="">— Todas —</option>
<option value="comercio internacional">comercio internacional</option>
<option value="economía global">economía global</option>
<option value="desigualdad económica">desigualdad económica</option>
<option value="corporaciones multinacionales">corporaciones multinacionales</option>
<option value="organismos financieros">organismos financieros</option>
</select>
<input type="submit" value="Aplicar">
</form>
</div>
<button id="sidebarToggle">Toggle Sidebar</button>
<!-- Incluir tu script al final del body -->
<script type="module" src="output_eco_corp_pruebas.js"></script>
</body>
</html>

View file

@ -1,331 +0,0 @@
@font-face {
font-family: "Retrolift";
src: url("/home/pancho/PROGRAMACION/FLUJOS/retrolift.woff2") format("woff2"),
url("/home/pancho/PROGRAMACION/FLUJOS/retrolift.woff") format("woff");
font-weight: normal;
font-style: normal;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Fira Code';
text-shadow: 10px 10px 20px rgba(0, 255, 76, 0.3);
}
body {
font-family: 'Fira Code', monospace;
background-color: #000000;
color: #000000;
}
header {
display: flex;
justify-content: center;
align-items: center;
height: 70px;
background-color: #000000;
color: #000000;
box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
}
.logo {
font-family: "Retrolift", sans-serif;
font-size: 4em;
font-weight: bold;
letter-spacing: 4px;
text-shadow: 6px 6px 6px #73ff00;
margin-bottom: 10px;
}
.glob-war:hover .logo { text-shadow: 2px 2px 8px #39ff14; }
.int-sec:hover .logo { text-shadow: 2px 2px 8px #ff69b4; }
.climate:hover .logo { text-shadow: 2px 2px 8px #ff4500; }
.eco-corp:hover .logo { text-shadow: 2px 2px 8px #006400; }
.popl-up:hover .logo { text-shadow: 2px 2px 8px #00008b; }
nav {
display: flex;
justify-content: center;
background-color: #000000;
color: #ff1a1a;
padding: 10px 0;
box-shadow: 0 10px 10px rgba(0, 0, 0, 0.1);
margin-top: 40px;
margin-bottom: 5px;
}
.nav-links {
list-style: none;
display: flex;
gap: 6em; /* incrementa la distancia entre los elementos */
}
.nav-links a {
color: #000000;
text-decoration: none;
font-size: 1em;
font-weight: bold;
transition: color 0.3s ease, transform 0.3s ease, box-shadow 0.3s ease;
padding: 20px 40px;
box-shadow: 0 0 0px rgba(28, 103, 241, 0);
/* Estilo de los botones */
position:relative;
border: none;
transition: .4s ease-in;
z-index: 1;
width: 40vw;
height: 20vh;
border:3vw;
align-items: center;
border: 3px solid ;
}
.nav-links a:hover {
transform: scale(1.05);
box-shadow: 0 0 6px rgba(0,0,0,0.3);
/* Estilo hover de los botones */
box-shadow: 2vw 1vw;
border: 3px solid black ;
}
.glob-war:hover { color: #39ff14; }
.int-sec:hover { color: #ff69b4; }
.climate:hover { color: #ff4500; }
.eco-corp:hover { color: #00fff2; }
.popl-up:hover { color: #0066ff; }
.glob-war {
color: #FF4136;
background-color: red;
}
.int-sec {
color: #0074D9;
background-color: darkblue;
}
.climate {
color: #2ECC40;
background-color: lightgreen;
}
.eco-corp {
color: #FFDC00;
background-color: yellow;
}
.popl-up {
color: #FF851B;
background-color: orange;
}
.background {
display: flex;
height: 100vh;
width: 99%;
overflow-x: scroll;
}
.background a {
display: block;
width: 20%;
height: 90vh;
transition: transform 1.5s ease;
}
.background img {
width: 20%;
height: 90vh;
object-fit: cover;
transition: transform 1.5s ease;
}
.background a img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 1.5s ease;
}
.background img:hover {
transform: scale(1.1);
}
#sidebar.active {
transform: translateX(0);
}
#sidebar {
position: fixed;
left: 0;
top: 0;
width: 250px;
height: 100vh;
background-image: url("/images/flujos7.jpg");
background-size: cover;
color: #39ff14;
padding: 30px;
box-shadow: 2px 0 10px rgba(0, 0, 0, 0.1);
transform: translateX(-90%);
transition: transform 0.3s ease-out;
overflow: auto;
font-size:18px;
z-index: 3;
text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; /* Añade el borde al texto */
}
#sidebar h2 {
color: #39ff14;
font-size: 1.2em;
font-weight: bold;
margin-bottom: 15px;
text-shadow: -1px 0 black, 0 3px black, 3px 0 black, 0 -1px black; /* Añade el borde al texto */
}
#sidebar:hover {
transform: translateX(0);
}
#sidebarToggle {
position: absolute;
left: 1em;
top: 1em;
background: #007BFF;
color: #39ff14;
border: none;
padding: 10px 20px;
cursor: pointer;
border-radius: 5px;
transition: background 0.3s ease;
z-index: 2;
}
#sidebarToggle {
display: none;
}
#sidebar form {
display: flex;
flex-direction: column;
gap: 10px;
font-size:20px;
}
#sidebar label {
color: #39ff14;
font-size: 0.9em;
font-weight: bold;
text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; /* Añade el borde al texto */
}
#sidebar input {
padding: 10px;
border: 2px solid #39ff14; /* Añade el borde verde al input */
background: black; /* Cambia el fondo del input a negro */
color: #39ff14; /* Cambia el color del texto en el input a verde */
border-radius: 5px;
box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.2);
transition: box-shadow 0.3s ease;
}
#sidebar input:hover {
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.3);
}
#sidebar input[type="submit"] {
color: #39ff14;
background: #ff6600;
cursor: pointer;
}
#sidebar input[type="submit"]:hover {
background: #ff6600;
}
footer {
width: 100%;
background-color: #000000;
color: #39ff14;
text-align: center;
padding: 10px 0;
position: fixed;
bottom: 0;
font-family: 'Courier New', Courier, monospace;
z-index: 1;
}
footer a {
color: #39ff14;
text-decoration: none;
transition: color 0.3s ease;
}
footer a:hover {
color: #2ECC40;
}
footer p {
margin: 0;
}
#glob_war_container{
position: absolute;
width: 100%;
height: 100%;
opacity: 0.5;
}
@media screen and (max-width: 768px) {
.nav-links a {
font-size: 0.8em; /* reduce el tamaño de la fuente */
padding: 10px 20px; /* reduce el padding */
}
.nav-links {
list-style: none;
display: flex;
gap: 2em; /* incrementa la distancia entre los elementos */
}
}
.fade-out {
animation: fadeOut 3s forwards; /* Fades out over 3 seconds */
}
@keyframes fadeOut {
from {opacity: 1;}
to {opacity: 0;}
}
.grafico {
z-index: 1; /* Bring to front */
/* Rest of your styles */
}
.grafico {
width: 100%;
height: 100vh;
position: absolute;
z-index: 1;
}

View file

@ -1,159 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Glob-War</title>
<link rel="stylesheet" href="glob-war.css">
<link rel="stylesheet" href="sub-nav.css">
<!-- Fuentes de Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;700&display=swap" rel="stylesheet">
<script type="importmap">
{ "imports": { "three": "https://esm.sh/three@0.179.0", "three/": "https://esm.sh/three@0.179.0/" } }
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js"></script>
</head>
<body>
<nav class="top-nav">
<div class="section-buttons">
<div class="section-item current">
<a href="glob-war.html" class="section-btn glob-war-btn">GLOB-WAR <span class="dropdown-arrow"></span></a>
<div class="section-dropdown">
<a href="#" onclick="setSubtema('conflictos internacionales');return false;">Conflictos Internacionales</a>
<a href="#" onclick="setSubtema('guerras civiles');return false;">Guerras Civiles</a>
<a href="#" onclick="setSubtema('terrorismo');return false;">Terrorismo</a>
<a href="#" onclick="setSubtema('armas');return false;">Armas</a>
<a href="#" onclick="setSubtema('alianzas militares');return false;">Alianzas Militares</a>
</div>
</div>
<div class="section-item">
<a href="int-sec.html" class="section-btn int-sec-btn">INT-SEC</a>
</div>
<div class="section-item">
<a href="climate.html" class="section-btn climate-btn">CLIMATE</a>
</div>
<div class="section-item">
<a href="eco-corp.html" class="section-btn eco-corp-btn">ECO-CORP</a>
</div>
<div class="section-item">
<a href="popl-up.html" class="section-btn popl-up-btn">POPL-UP</a>
</div>
</div>
</nav>
<script>
function setSubtema(val) {
var sel = document.getElementById('param2');
if (sel) { sel.value = val; }
var form = document.getElementById('paramForm');
if (form) form.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));
}
document.addEventListener('DOMContentLoaded', function() {
/* ── Dropdown touch (móvil) ── */
var curr = document.querySelector('.section-item.current');
if (curr) {
curr.querySelector('.section-btn').addEventListener('touchend', function(e) {
e.preventDefault();
curr.classList.toggle('open');
});
document.addEventListener('touchend', function(e) {
if (!curr.contains(e.target)) curr.classList.remove('open');
});
}
/* ── Sidebar: botón toggle visible en móvil ── */
var toggle = document.getElementById('sidebarToggle');
var sidebar = document.getElementById('sidebar');
if (toggle && sidebar) {
toggle.style.display = 'block';
toggle.addEventListener('click', function() {
sidebar.classList.toggle('active');
});
}
});
</script>
<main class="split-screen">
<div id="graphPanel" style="position:relative;">
<button id="volverGrafoBtn">← Volver al grafo completo</button>
<div id="globWarContainer" style="position: absolute; width: 100%; height: 100%;"></div>
<div class="background">
<img src="/images/flujos.jpg">
<img src="/images/flujos.jpg">
<img src="/images/flujos.jpg">
<img src="/images/flujos.jpg">
<img src="/images/flujos.jpg">
<script>
setTimeout(function() {
var fondo = document.querySelector('.background');
fondo.classList.add('fade-out');
fondo.style.pointerEvents = 'none';
}, 1000);
</script>
</div>
</div>
<div id="detailPanel">
<button id="closeDetail">✕ cerrar</button>
<div id="detailContent">
<div class="detail-meta">
<span class="detail-author"></span>
<span class="detail-date"></span>
</div>
<h2 class="detail-title"></h2>
<div class="detail-relations">
<span class="relations-count"></span>
<div class="relations-nav">
<button id="prevRelation" disabled>&#8592; ant</button>
<span id="relationLabel"></span>
<button id="nextRelation" disabled>sig &#8594;</button>
</div>
</div>
<div class="detail-body"></div>
</div>
</div>
</main>
<div id="sidebar">
<h2>Parámetros</h2>
<form id="paramForm">
<label for="fecha_inicio">Fecha de inicio:</label>
<input type="date" id="fecha_inicio" name="fecha_inicio">
<label for="fecha_fin">Fecha de fin:</label>
<input type="date" id="fecha_fin" name="fecha_fin">
<label for="nodos">Nodos:</label>
<input type="number" id="nodos" name="nodos" value="100" min="5" max="500">
<label for="complejidad">% similitud: <span id="complejidadVal" class="sim-val">8</span></label>
<input type="range" id="complejidad" name="complejidad" min="1" max="25" value="8"
oninput="document.getElementById('complejidadVal').textContent = this.value">
<label for="param1">Palabra clave:</label>
<input type="text" id="param1" name="param1" placeholder="ej: misiles, OTAN...">
<label for="param2">Subtematica:</label>
<select id="param2" name="param2">
<option value="">— Todas —</option>
<option value="armas">armas</option>
<option value="terrorismo">terrorismo</option>
<option value="guerras civiles">guerras civiles</option>
<option value="conflictos internacionales">conflictos internacionales</option>
<option value="alianzas militares">alianzas militares</option>
</select>
<input type="submit" value="Aplicar">
</form>
</div>
<button id="sidebarToggle">Toggle Sidebar</button>
<!-- Incluir tu script al final del body -->
<script type="module" src="output_glob_war_pruebas.js"></script>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 256 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 223 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

View file

@ -1,102 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<title>UP-LEAKS</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;700&family=Nosifer&display=swap" rel="stylesheet">
</head>
<body>
<header>
<div class="header-content">
<h1 class="title">UP-LEAKS</h1>
<div class="header-buttons header-buttons--left">
<a href="/coconews/" class="small-button coconews-btn">COCONEWS</a>
<a href="journalist.html" class="small-button">Journalist</a>
<a href="stats.html" class="small-button stats-btn">STATS</a>
</div>
</div>
</header>
<nav>
<ul class="nav-links">
<li><a href="glob-war.html" class="glob-war">GLOB-WAR</a></li>
<li><a href="int-sec.html" class="int-sec">INT-SEC</a></li>
<li><a href="climate.html" class="climate">CLIMATE</a></li>
<li><a href="eco-corp.html" class="eco-corp">ECO-CORP</a></li>
<li><a href="popl-up.html" class="popl-up">Popl-up</a></li>
</ul>
</nav>
<main>
<div id="canvasContainer" style="position: absolute; width: 100%; height: 100%; opacity: 0.5;"></div>
<div class="background">
<a href="glob-war.html">
<img class="img1" src="/images/flujos.jpg">
</a>
<a href="int-sec.html">
<img class="img2" src="/images/fujos5.jpg">
</a>
<a href="climate.html">
<img class="img3" src="/images/flujos6.jpg">
</a>
<a href="eco-corp.html">
<img class="img4" src="/images/flujos4.jpg">
</a>
<a href="popl-up.html">
<img class="img5" src="/images/flujos3.jpg">
</a>
</div>
<!-- Botones sobre las imágenes -->
<div class="button-overlay">
<div class="button-column">
<a href="glob-war.html?subtematica=conflictos_internacionales" class="overlay-button">Conflictos Internacionales</a>
<a href="glob-war.html?subtematica=guerras_civiles" class="overlay-button">Guerras Civiles</a>
<a href="glob-war.html?subtematica=terrorismo" class="overlay-button">Terrorismo</a>
<a href="glob-war.html?subtematica=armas" class="overlay-button">Armas</a>
<a href="glob-war.html?subtematica=alianzas_militares" class="overlay-button">Alianzas Militares</a>
</div>
<div class="button-column">
<a href="int-sec.html?subtematica=inteligencia" class="overlay-button">Inteligencia</a>
<a href="int-sec.html?subtematica=ciberseguridad" class="overlay-button">Ciberseguridad</a>
<a href="int-sec.html?subtematica=espionaje" class="overlay-button">Espionaje</a>
<a href="int-sec.html?subtematica=seguridad_nacional" class="overlay-button">Seguridad Nacional</a>
<a href="int-sec.html?subtematica=contraterrorismo" class="overlay-button">Contraterrorismo</a>
</div>
<div class="button-column">
<a href="climate.html?subtematica=cambio_climatico" class="overlay-button">Cambio Climático</a>
<a href="climate.html?subtematica=desastres_naturales" class="overlay-button">Desastres Naturales</a>
<a href="climate.html?subtematica=conservacion" class="overlay-button">Conservación</a>
<a href="climate.html?subtematica=energia_renovable" class="overlay-button">Energía Renovable</a>
<a href="climate.html?subtematica=contaminacion" class="overlay-button">Escasez de agua</a>
</div>
<div class="button-column">
<a href="eco-corp.html?subtematica=economia_global" class="overlay-button">Economía Global</a>
<a href="eco-corp.html?subtematica=corporaciones_multinacionales" class="overlay-button">Corporaciones Multinacionales</a>
<a href="eco-corp.html?subtematica=comercio_internacional" class="overlay-button">Comercio Internacional</a>
<a href="eco-corp.html?subtematica=organismos_financieros" class="overlay-button">Organismos Financieros</a>
<a href="eco-corp.html?subtematica=desigualdad_economica" class="overlay-button">Desigualdad Económica</a>
</div>
<div class="button-column">
<a href="popl-up.html?subtematica=sobrepoblacion" class="overlay-button">Sobrepoblación</a>
<a href="popl-up.html?subtematica=covid" class="overlay-button">COVID</a>
<a href="popl-up.html?subtematica=migraciones" class="overlay-button">Migraciones</a>
<a href="popl-up.html?subtematica=urbanizacion" class="overlay-button">Urbanización</a>
<a href="popl-up.html?subtematica=distribucion_edad" class="overlay-button">Despoblaciòn rural</a>
</div>
</div>
</main>
<button id="sidebarToggle">Toggle Sidebar</button>
<footer>
<p><a href="#">GitHub</a> | <a href="#">Telegram</a> | <a href="#">Email</a> | <a href="#">Web de Tor</a></p>
</footer>
</body>
</html>

View file

@ -1,277 +0,0 @@
@font-face {
font-family: "Retrolift";
src: url("/home/pancho/PROGRAMACION/FLUJOS/retrolift.woff2") format("woff2"),
url("/home/pancho/PROGRAMACION/FLUJOS/retrolift.woff") format("woff");
font-weight: normal;
font-style: normal;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Fira Code';
text-shadow: 10px 10px 20px rgba(0, 255, 76, 0.3);
}
body {
font-family: 'Fira Code', monospace;
background: #000000;
color: #000000;
}
header {
display: flex;
justify-content: center;
align-items: center;
height: 70px;
background-color: #000000;
color: #ffffff;
box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
}
.logo {
font-family: "Retrolift", sans-serif;
font-size: 4em;
font-weight: bold;
letter-spacing: 4px;
text-shadow: 6px 6px 6px #73ff00;
margin-bottom: 10px;
}
.glob-war:hover .logo { text-shadow: 2px 2px 8px #39ff14; }
.int-sec:hover .logo { text-shadow: 2px 2px 8px #ff69b4; }
.climate:hover .logo { text-shadow: 2px 2px 8px #ff4500; }
.eco-corp:hover .logo { text-shadow: 2px 2px 8px #006400; }
.popl-up:hover .logo { text-shadow: 2px 2px 8px #00008b; }
nav {
display: flex;
justify-content: center;
background-color: #000000;
color: #ff1a1a;
padding: 10px 0;
box-shadow: 0 10px 10px rgba(0, 0, 0, 0.1);
margin-top: 40px;
margin-bottom: 5px;
}
.nav-links {
list-style: none;
display: flex;
gap: 6em;
}
.nav-links a {
color: #000000;
text-decoration: none;
font-size: 1em;
font-weight: bold;
transition: color 0.3s ease, transform 0.3s ease, box-shadow 0.3s ease;
padding: 20px 40px;
box-shadow: 0 0 0px rgba(28, 103, 241, 0);
position: relative;
border: none;
z-index: 1;
width: 40vw;
height: 20vh;
align-items: center;
border: 3px solid;
}
.nav-links a:hover {
transform: scale(1.05);
box-shadow: 2vw 1vw;
border: 3px solid black;
}
.glob-war { color: #FF4136; background-color: red; }
.int-sec { color: #0074D9; background-color: darkblue; }
.climate { color: #2ECC40; background-color: lightgreen; }
.eco-corp { color: #FFDC00; background-color: yellow; }
.popl-up { color: #FF851B; background-color: orange; }
.background {
display: flex;
height: 100vh;
width: 99%;
overflow-x: scroll;
}
.background img {
width: 20%;
height: 90vh;
object-fit: cover;
transition: transform 1.5s ease;
}
.background img:hover {
transform: scale(1.1);
}
#sidebar {
position: fixed;
left: 0;
top: 0;
width: 250px;
height: 100vh;
background-image: url("/images/flujos7.jpg");
background-size: cover;
color: #39ff14;
padding: 30px;
box-shadow: 2px 0 10px rgba(0, 0, 0, 0.1);
transform: translateX(-90%); /* Oculta el 90%, deja 10% visible */
transition: transform 0.3s ease-out;
overflow: auto;
font-size: 18px;
z-index: 3;
text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;
}
#sidebar:hover {
transform: translateX(0); /* Aparece entero al hacer hover */
}
#sidebar.active {
transform: translateX(0);
}
#sidebar h2 {
color: #39ff14;
font-size: 1.2em;
font-weight: bold;
margin-bottom: 15px;
text-shadow: -1px 0 black, 0 3px black, 3px 0 black, 0 -1px black;
}
#sidebar form {
display: flex;
flex-direction: column;
gap: 10px;
font-size: 20px;
}
#sidebar label {
color: #39ff14;
font-size: 0.9em;
font-weight: bold;
text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;
}
#sidebar input {
padding: 10px;
border: 2px solid #39ff14;
background: black;
color: #39ff14;
border-radius: 5px;
box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.2);
transition: box-shadow 0.3s ease;
}
#sidebar input:hover {
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.3);
}
#sidebar input[type="submit"] {
color: #39ff14;
background: #ff6600;
cursor: pointer;
}
#sidebar input[type="submit"]:hover {
background: #ff6600;
}
footer {
width: 100%;
background-color: #000000;
color: #39ff14;
text-align: center;
padding: 10px 0;
position: fixed;
bottom: 0;
font-family: 'Courier New', Courier, monospace;
z-index: 1;
}
footer a {
color: #39ff14;
text-decoration: none;
transition: color 0.3s ease;
}
footer a:hover {
color: #2ECC40;
}
footer p {
margin: 0;
}
#intSecContainer {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 2;
background-color: #101020;
}
@media screen and (max-width: 768px) {
.nav-links a {
font-size: 0.8em;
padding: 10px 20px;
}
.nav-links {
gap: 2em;
}
}
.fade-out {
animation: fadeOut 2s forwards;
}
@keyframes fadeOut {
from { opacity: 1; }
to { opacity: 0; }
}
/* ===== Añadidos para split-screen ===== */
main.split-screen {
display: flex;
height: 100vh;
margin-left: 0; /* El sidebar está fijo encima */
}
#graphPanel {
width: 100%;
transition: width 0.3s ease;
position: relative;
}
#detailPanel {
width: 0;
overflow: hidden;
transition: width 0.3s ease;
}
/* Al hacer click en un nodo */
main.split-screen.show-detail #graphPanel {
width: 45%;
}
main.split-screen.show-detail #detailPanel {
width: 50%;
padding: 1em;
}
/* Asegurar que el grafo ocupe todo su panel */
#graphPanel #intSecContainer {
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
z-index: 2;
}
/* Estilos del panel de detalle */
#detailPanel {
background: #101020;
color: #fff;
box-shadow: inset 1px 0 5px rgba(0,0,0,0.5);
}
#detailPanel h2 {
margin-bottom: .5em;
color: #39ff14;
}
#detailPanel p {
line-height: 1.4;
margin-bottom: 1em;
}
#detailPanel .placeholder {
color: rgba(255,255,255,0.3);
font-style: italic;
}

View file

@ -1,163 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Inteligencia y Seguridad</title>
<link rel="stylesheet" href="int-sec.css">
<link rel="stylesheet" href="sub-nav.css">
<!-- Fuentes de Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;700&display=swap" rel="stylesheet">
<!-- Cargar D3.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js"></script>
<script type="importmap">
{ "imports": { "three": "https://esm.sh/three@0.179.0", "three/": "https://esm.sh/three@0.179.0/" } }
</script>
</head>
<body>
<nav class="top-nav">
<div class="section-buttons">
<div class="section-item">
<a href="glob-war.html" class="section-btn glob-war-btn">GLOB-WAR</a>
</div>
<div class="section-item current">
<a href="int-sec.html" class="section-btn int-sec-btn">INT-SEC <span class="dropdown-arrow"></span></a>
<div class="section-dropdown">
<a href="#" onclick="setSubtema('inteligencia');return false;">Inteligencia</a>
<a href="#" onclick="setSubtema('ciberseguridad');return false;">Ciberseguridad</a>
<a href="#" onclick="setSubtema('espionaje');return false;">Espionaje</a>
<a href="#" onclick="setSubtema('seguridad nacional');return false;">Seguridad Nacional</a>
<a href="#" onclick="setSubtema('contraterrorismo');return false;">Contraterrorismo</a>
</div>
</div>
<div class="section-item">
<a href="climate.html" class="section-btn climate-btn">CLIMATE</a>
</div>
<div class="section-item">
<a href="eco-corp.html" class="section-btn eco-corp-btn">ECO-CORP</a>
</div>
<div class="section-item">
<a href="popl-up.html" class="section-btn popl-up-btn">POPL-UP</a>
</div>
</div>
</nav>
<script>
function setSubtema(val) {
var sel = document.getElementById('param2');
if (sel) { sel.value = val; }
var form = document.getElementById('paramForm');
if (form) form.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));
}
document.addEventListener('DOMContentLoaded', function() {
/* ── Dropdown touch (móvil) ── */
var curr = document.querySelector('.section-item.current');
if (curr) {
curr.querySelector('.section-btn').addEventListener('touchend', function(e) {
e.preventDefault();
curr.classList.toggle('open');
});
document.addEventListener('touchend', function(e) {
if (!curr.contains(e.target)) curr.classList.remove('open');
});
}
/* ── Sidebar: botón toggle visible en móvil ── */
var toggle = document.getElementById('sidebarToggle');
var sidebar = document.getElementById('sidebar');
if (toggle && sidebar) {
toggle.style.display = 'block';
toggle.addEventListener('click', function() {
sidebar.classList.toggle('active');
});
}
});
</script>
<main class="split-screen">
<!-- PANEL IZQUIERDO: el grafo -->
<div id="graphPanel" style="position:relative;">
<button id="volverGrafoBtn">← Volver al grafo completo</button>
<div id="intSecContainer"></div>
<div class="background">
<img src="/images/flujos.jpg">
<img src="/images/flujos.jpg">
<img src="/images/flujos.jpg">
<img src="/images/flujos.jpg">
<img src="/images/flujos.jpg">
<script>
setTimeout(function() {
const fondo = document.querySelector('.background');
fondo.classList.add('fade-out');
fondo.style.pointerEvents = 'none';
}, 1000);
</script>
</div>
</div>
<!-- PANEL DERECHO: detalle de la noticia -->
<div id="detailPanel">
<button id="closeDetail">✕ cerrar</button>
<div id="detailContent">
<div class="detail-meta">
<span class="detail-author"></span>
<span class="detail-date"></span>
</div>
<h2 class="detail-title"></h2>
<div class="detail-relations">
<span class="relations-count"></span>
<div class="relations-nav">
<button id="prevRelation" disabled>&#8592; ant</button>
<span id="relationLabel"></span>
<button id="nextRelation" disabled>sig &#8594;</button>
</div>
</div>
<div class="detail-body"></div>
</div>
</div>
</main>
<div id="sidebar">
<h2>Parámetros</h2>
<form id="paramForm">
<label for="fecha_inicio">Fecha de inicio:</label>
<input type="date" id="fecha_inicio" name="fecha_inicio">
<label for="fecha_fin">Fecha de fin:</label>
<input type="date" id="fecha_fin" name="fecha_fin">
<label for="nodos">Nodos:</label>
<input type="number" id="nodos" name="nodos" value="100" min="5" max="500">
<label for="complejidad">% similitud: <span id="complejidadVal" class="sim-val">8</span></label>
<input type="range" id="complejidad" name="complejidad" min="1" max="25" value="8"
oninput="document.getElementById('complejidadVal').textContent = this.value">
<label for="param1">Palabra clave:</label>
<input type="text" id="param1" name="param1" placeholder="ej: CIA, GCHQ...">
<label for="param2">Subtematica:</label>
<select id="param2" name="param2">
<option value="">— Todas —</option>
<option value="inteligencia">inteligencia</option>
<option value="seguridad nacional">seguridad nacional</option>
<option value="espionaje">espionaje</option>
<option value="ciberseguridad">ciberseguridad</option>
<option value="contraterrorismo">contraterrorismo</option>
</select>
<input type="submit" value="Aplicar">
</form>
</div>
<button id="sidebarToggle">Toggle Sidebar</button>
<!-- Incluir tu script al final del body -->
<script type="module" src="output_int_sec.js"></script>
</body>
</html>

View file

@ -1,132 +0,0 @@
body {
font-family: Arial, sans-serif;
background-color: #000000;
margin: 0;
padding: 0;
color: #ffffff; /* Cambiar el color del texto a blanco */
}
/* Estilo del formulario */
.login-container {
max-width: 400px;
margin: 30px auto;
background-color: #111111; /* Fondo negro */
border: 2px solid #39ff14; /* Borde verde claro */
padding: 20px;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
position: relative; /* Añadimos posición relativa para que los elementos internos se posicionen respecto a este contenedor */
}
/* ... Estilos existentes ... */
/* Estilos para los enlaces dentro del formulario */
.login-container a {
color: #39ff14; /* Cambiar el color del enlace a verde claro */
text-decoration: none;
transition: color 0.3s ease;
}
.login-container a:hover {
color: #2ECC40; /* Cambiar el color del enlace en hover a verde más claro */
}
/* ... Resto de tus estilos ... */
h1 {
text-align: center;
margin-bottom: 20px;
color: #39ff14; /* Cambiar el color del título a verde claro */
}
form {
display: flex;
flex-direction: column;
}
label {
margin-bottom: 8px;
color: #39ff14; /* Cambiar el color de las etiquetas a verde claro */
}
input[type="text"],
input[type="password"] {
padding: 10px;
border: 1px solid #ccc;
border-radius: 4px;
margin-bottom: 15px;
background-color: #222222; /* Fondo negro */
color: #ffffff; /* Texto blanco */
}
input[type="submit"] {
background-color: #007BFF;
color: #ffffff;
border: none;
padding: 10px;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
}
input[type="submit"]:hover {
background-color: #0056b3;
border: 2px solid #39ff14; /* Borde verde claro en hover */
}
.header {
display: flex;
justify-content: center;
margin-bottom: 0px; /* Añadir margen inferior para separar el formulario del logo */
}
.logo {
width: 400px; /* Ajustar el tamaño de la imagen según sea necesario */
height: auto;
}
/* Estilos para las imágenes de fondo */
.canvas-container {
position: relative;
display: flex;
justify-content: center;
align-items: center;
background-color: #000000;
color: #ffffff;
min-height: 100vh; /* Ajusta la altura mínima para que ocupe toda la pantalla */
margin: 20px 0;
overflow: hidden; /* Evita que las imágenes desborden del contenedor */
}
.image-left,
.image-right {
height: 100vh; /* Ajusta la altura para que ocupe toda la pantalla */
width: auto; /* Ajusta el ancho de las imágenes para mantener la relación de aspecto */
position: absolute;
top: 0;
max-width: 40%; /* Ajusta el ancho máximo de las imágenes de fondo */
}
.image-left {
left: 0;
}
.image-right {
right: 0;
}
.login-content {
/* Ajusta estos estilos según tus necesidades */
padding: 20px;
margin: 0 auto;
max-width: 300px; /* Ajusta el ancho máximo del contenido */
position: relative; /* Añadimos posición relativa para que los elementos internos se posicionen respecto a este contenedor */
}
/* Añade el siguiente estilo para evitar que las imágenes desborden del contenedor */
.login-content > img {
max-width: 100%;
height: auto;
}

View file

@ -1,66 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Journalist Login</title>
<link rel="stylesheet" href="journalist.css">
</head>
<body>
<div class="header">
<img class="logo" src="/images/flujos_logo5.png" alt="Flujos Logo">
</div>
<div class="canvas-container">
<img class="image-left" src="/images/journalist_fondo.jpg" alt="Fondo izquierdo">
<div class="login-container">
<h1>Journalist Login</h1>
<form onsubmit="login(event)">
<label for="username">Username:</label>
<input type="text" id="username" name="username" required>
<label for="password">Password:</label>
<input type="password" id="password" name="password" required>
<label for="publicKey">Public Key:</label>
<input type="text" id="publicKey" name="publicKey" required>
<input type="submit" value="Login">
</form>
</div>
<img class="image-right" src="/images/journalist_fondo2.jpg" alt="Fondo derecho">
</div>
<script>
function login(event) {
event.preventDefault(); // Evitar que el formulario se envíe por defecto
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
const publicKey = document.getElementById('publicKey').value;
// Enviar los datos del formulario mediante una petición AJAX a nuestro endpoint de login
fetch('/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ username, password, publicKey })
})
.then(response => response.json())
.then(data => {
// Si el servidor devuelve un redireccionamiento, redirigimos al usuario
if (data.redirect) {
window.location.href = data.redirect;
} else {
// Si no hay redireccionamiento, se podría mostrar un mensaje de error
console.log('Credenciales inválidas');
}
})
.catch(error => {
console.error('Error en la petición AJAX:', error);
});
}
</script>
</body>
</html>

View file

@ -1,377 +0,0 @@
@font-face {
font-family: "Retrolift";
src: url("/home/pancho/PROGRAMACION/FLUJOS/retrolift.woff2") format("woff2"),
url("/home/pancho/PROGRAMACION/FLUJOS/retrolift.woff") format("woff");
font-weight: normal;
font-style: normal;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Fira Code';
text-shadow: 10px 10px 20px rgba(0, 255, 76, 0.3);
}
body {
font-family: 'Fira Code', monospace;
background: #000000;
color: #000000;
}
header {
position: relative;
height: 100px;
background-color: #000000;
display: flex;
justify-content: center;
align-items: center;
}
.logo {
width: 400px;
height: 140px;
margin-left: 400px;
align-items: center;
}
.header-content {
display: flex;
align-items: center;
position: relative;
max-width: 1200px;
width: 100%;
}
.header-buttons {
display: flex;
align-items: center;
position: absolute;
top: 50%;
right: 10px;
transform: translateY(-50%);
}
.small-button {
margin-left: 5px;
margin-right: 3px;
padding: 4px 8px;
font-size: 10px;
color: #ffffff;
text-decoration: none;
background-color: #000000;
border: 2px solid #ffffff;
border-radius: 20px;
transition: all 0.3s ease;
}
.small-button:hover {
background-color: #ffffff;
color: #000000;
text-shadow: none;
}
/* ... Resto de tus estilos ... */
/* ... Estilos existentes ... */
.logo {
/* Ajusta el tamaño de la imagen según tus necesidades */
width: 400px;
height: 140px;
}
.buttons {
position: absolute;
top: 50%;
right: 20px;
transform: translateY(-50%);
display: flex;
align-items: center;
}
.buttons a {
display: block;
margin-left: 10px;
padding: 10px 15px;
color: #ffffff;
text-decoration: none;
border: 1px solid #ffffff;
border-radius: 20px;
}
.glob-war:hover .logo { text-shadow: 2px 2px 8px #39ff14; }
.int-sec:hover .logo { text-shadow: 2px 2px 8px #ff69b4; }
.climate:hover .logo { text-shadow: 2px 2px 8px #ff4500; }
.eco-corp:hover .logo { text-shadow: 2px 2px 8px #006400; }
.popl-up:hover .logo { text-shadow: 2px 2px 8px #00008b; }
nav {
display: flex;
justify-content: center;
background-color: #000000;
color: #ff1a1a;
padding: 10px 0;
box-shadow: 0 10px 10px rgba(0, 0, 0, 0.1);
margin-top: 40px;
margin-bottom: 5px;
}
.nav-links {
list-style: none;
display: flex;
gap: 6em; /* incrementa la distancia entre los elementos */
}
.nav-links a {
color: #000000;
text-decoration: none;
font-size: 1em;
font-weight: bold;
transition: color 0.3s ease, transform 0.3s ease, box-shadow 0.3s ease;
padding: 20px 40px;
box-shadow: 0 0 0px rgba(28, 103, 241, 0);
/* Estilo de los botones */
position:relative;
border: none;
transition: .4s ease-in;
z-index: 1;
width: 40vw;
height: 20vh;
border:3vw;
align-items: center;
border: 3px solid ;
}
.nav-links a:hover {
transform: scale(1.05);
box-shadow: 0 0 6px rgba(0,0,0,0.3);
/* Estilo hover de los botones */
box-shadow: 2vw 1vw;
border: 3px solid black ;
}
.glob-war:hover { color: #39ff14; }
.int-sec:hover { color: #ff69b4; }
.climate:hover { color: #ff4500; }
.eco-corp:hover { color: #00fff2; }
.popl-up:hover { color: #0066ff; }
.glob-war {
color: #FF4136;
background-color: red;
}
.int-sec {
color: #0074D9;
background-color: darkblue;
}
.climate {
color: #2ECC40;
background-color: lightgreen;
}
.eco-corp {
color: #FFDC00;
background-color: yellow;
}
.popl-up {
color: #FF851B;
background-color: orange;
}
.background {
display: flex;
height: 100vh;
width: 99%;
overflow-x: scroll;
}
.background a {
display: block;
width: 20%;
height: 90vh;
transition: transform 1.5s ease;
}
.background img {
width: 20%;
height: 90vh;
object-fit: cover;
transition: transform 1.5s ease;
}
.background a img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 1.5s ease;
}
.background img:hover {
transform: scale(1.1);
}
#sidebar.active {
transform: translateX(0);
}
#sidebar {
position: fixed;
left: 0;
top: 0;
width: 250px;
height: 100vh;
background-image: url("/images/flujos7.jpg");
background-size: cover;
color: #39ff14;
padding: 30px;
box-shadow: 2px 0 10px rgba(0, 0, 0, 0.1);
transform: translateX(-90%);
transition: transform 0.3s ease-out;
overflow: auto;
font-size:18px;
z-index: 3;
text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; /* Añade el borde al texto */
}
#sidebar h2 {
color: #39ff14;
font-size: 1.2em;
font-weight: bold;
margin-bottom: 15px;
text-shadow: -1px 0 black, 0 3px black, 3px 0 black, 0 -1px black; /* Añade el borde al texto */
}
#sidebar:hover {
transform: translateX(0);
}
#sidebarToggle {
position: absolute;
left: 1em;
top: 1em;
background: #007BFF;
color: #39ff14;
border: none;
padding: 10px 20px;
cursor: pointer;
border-radius: 5px;
transition: background 0.3s ease;
z-index: 2;
}
#sidebarToggle {
display: none;
}
#sidebar form {
display: flex;
flex-direction: column;
gap: 10px;
font-size:20px;
}
#sidebar label {
color: #39ff14;
font-size: 0.9em;
font-weight: bold;
text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; /* Añade el borde al texto */
}
#sidebar input {
padding: 10px;
border: 2px solid #39ff14; /* Añade el borde verde al input */
background: black; /* Cambia el fondo del input a negro */
color: #39ff14; /* Cambia el color del texto en el input a verde */
border-radius: 5px;
box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.2);
transition: box-shadow 0.3s ease;
}
#sidebar input:hover {
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.3);
}
#sidebar input[type="submit"] {
color: #39ff14;
background: #ff6600;
cursor: pointer;
}
#sidebar input[type="submit"]:hover {
background: #ff6600;
}
footer {
width: 100%;
background-color: #000000;
color: #39ff14;
text-align: center;
padding: 10px 0;
position: fixed;
bottom: 0;
font-family: 'Courier New', Courier, monospace;
z-index: 1;
}
footer a {
color: #39ff14;
text-decoration: none;
transition: color 0.3s ease;
}
footer a:hover {
color: #2ECC40;
}
footer p {
margin: 0;
}
#canvasContainer {
position: absolute;
width: 100%;
height: 100%;
opacity: 0.5;
pointer-events: none;
}
/* ... Estilos existentes ... */
@media screen and (max-width: 768px) {
.nav-links a {
font-size: 0.8em; /* reduce el tamaño de la fuente */
padding: 10px 20px; /* reduce el padding */
}
.nav-links {
list-style: none;
display: flex;
gap: 2em; /* incrementa la distancia entre los elementos */
}
}

View file

@ -1,79 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Journalist Enter</title>
<link rel="stylesheet" href="styles.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;700&display=swap" rel="stylesheet">
</head>
<body>
<!-- Header -->
<header>
<div class="header-content">
<img src="/images/flujos_logo5.png" alt="FLUJØS 3D Logo" class="logo">
<div class="header-buttons">
<a href="login.html" class="small-button">Login/Sign Up</a>
<div class="small-button">Language</div> <!-- El botón de idioma con el dropdown se implementará más adelante -->
<a href="journalist.html" class="small-button">Journalist</a>
</div>
</div>
</header>
<!-- Sidebar Toggle Button -->
<button id="sidebarToggle">Toggle Sidebar</button>
<!-- Main Content -->
<main>
<!-- Graficos generados por el script de output.js -->
<div id="canvasContainer"></div>
<div class="background">
<!-- Enlaces a otras páginas -->
<a href="glob-war.html">
<img class="img1" src="/images/flujos.jpg">
</a>
<a href="int-sec.html">
<img class="img2" src="/images/fujos5.jpg">
</a>
<a href="climate.html">
<img class="img3" src="/images/flujos6.jpg">
</a>
<a href="eco-corp.html">
<img class="img4" src="/images/flujos4.jpg">
</a>
<a href="popl-up.html">
<img class="img5" src="/images/flujos3.jpg">
</a>
</div>
</main>
<!-- Sidebar with Parameters -->
<div id="sidebar">
<h2>Parámetros</h2>
<form>
<!-- Aquí van los parámetros específicos para añadir nodos -->
<label for="nodo_nombre">Nombre del Nodo:</label>
<input type="text" id="nodo_nombre" name="nodo_nombre" required>
<label for="nodo_descripcion">Descripción del Nodo:</label>
<input type="text" id="nodo_descripcion" name="nodo_descripcion" required>
<label for="nodo_imagen">Imagen del Nodo:</label>
<input type="file" id="nodo_imagen" name="nodo_imagen" accept="image/*" required>
<input type="submit" value="Añadir Nodo">
</form>
</div>
<!-- Footer -->
<footer>
<p><a href="#">GitHub</a> | <a href="#">Telegram</a> | <a href="#">Email</a> | <a href="#">Web de Tor</a></p>
</footer>
<!-- Script para los gráficos generados por output.js -->
<script src="output.js"></script>
</body>
</html>

View file

@ -1,438 +0,0 @@
import { AmbientLight, DirectionalLight, Vector3, REVISION } from "./three.module.js";
const three = window.THREE
? window.THREE // Prefer consumption from global THREE, if exists
: { AmbientLight, DirectionalLight, Vector3, REVISION };
import { DragControls as ThreeDragControls } from './DragControls.js';
import ThreeForceGraph from "./three-forcegraph.js";
import ThreeRenderObjects from "./three-render-objects.js";
import accessorFn from "./accessor-fn.js";
import Kapsule from "./kapsule.js";
import linkKapsule from './kapsule-link.js';
//
const CAMERA_DISTANCE2NODES_FACTOR = 170;
//
// Expose config from forceGraph
const bindFG = linkKapsule('forceGraph', ThreeForceGraph);
const linkedFGProps = Object.assign(...[
'jsonUrl',
'graphData',
'numDimensions',
'dagMode',
'dagLevelDistance',
'dagNodeFilter',
'onDagError',
'nodeRelSize',
'nodeId',
'nodeVal',
'nodeResolution',
'nodeColor',
'nodeAutoColorBy',
'nodeOpacity',
'nodeVisibility',
'nodeThreeObject',
'nodeThreeObjectExtend',
'linkSource',
'linkTarget',
'linkVisibility',
'linkColor',
'linkAutoColorBy',
'linkOpacity',
'linkWidth',
'linkResolution',
'linkCurvature',
'linkCurveRotation',
'linkMaterial',
'linkThreeObject',
'linkThreeObjectExtend',
'linkPositionUpdate',
'linkDirectionalArrowLength',
'linkDirectionalArrowColor',
'linkDirectionalArrowRelPos',
'linkDirectionalArrowResolution',
'linkDirectionalParticles',
'linkDirectionalParticleSpeed',
'linkDirectionalParticleWidth',
'linkDirectionalParticleColor',
'linkDirectionalParticleResolution',
'forceEngine',
'd3AlphaDecay',
'd3VelocityDecay',
'd3AlphaMin',
'ngraphPhysics',
'warmupTicks',
'cooldownTicks',
'cooldownTime',
'onEngineTick',
'onEngineStop'
].map(p => ({ [p]: bindFG.linkProp(p)})));
const linkedFGMethods = Object.assign(...[
'refresh',
'getGraphBbox',
'd3Force',
'd3ReheatSimulation',
'emitParticle'
].map(p => ({ [p]: bindFG.linkMethod(p)})));
// Expose config from renderObjs
const bindRenderObjs = linkKapsule('renderObjs', ThreeRenderObjects);
const linkedRenderObjsProps = Object.assign(...[
'width',
'height',
'backgroundColor',
'showNavInfo',
'enablePointerInteraction'
].map(p => ({ [p]: bindRenderObjs.linkProp(p)})));
const linkedRenderObjsMethods = Object.assign(
...[
'lights',
'cameraPosition',
'postProcessingComposer'
].map(p => ({ [p]: bindRenderObjs.linkMethod(p)})),
{
graph2ScreenCoords: bindRenderObjs.linkMethod('getScreenCoords'),
screen2GraphCoords: bindRenderObjs.linkMethod('getSceneCoords')
}
);
//
export default Kapsule({
props: {
nodeLabel: { default: 'name', triggerUpdate: false },
linkLabel: { default: 'name', triggerUpdate: false },
linkHoverPrecision: { default: 1, onChange: (p, state) => state.renderObjs.lineHoverPrecision(p), triggerUpdate: false },
enableNavigationControls: {
default: true,
onChange(enable, state) {
const controls = state.renderObjs.controls();
if (controls) {
controls.enabled = enable;
// trigger mouseup on re-enable to prevent sticky controls
enable && controls.domElement && controls.domElement.dispatchEvent(new PointerEvent('pointerup'));
}
},
triggerUpdate: false
},
enableNodeDrag: { default: true, triggerUpdate: false },
onNodeDrag: { default: () => {}, triggerUpdate: false },
onNodeDragEnd: { default: () => {}, triggerUpdate: false },
onNodeClick: { triggerUpdate: false },
onNodeRightClick: { triggerUpdate: false },
onNodeHover: { triggerUpdate: false },
onLinkClick: { triggerUpdate: false },
onLinkRightClick: { triggerUpdate: false },
onLinkHover: { triggerUpdate: false },
onBackgroundClick: { triggerUpdate: false },
onBackgroundRightClick: { triggerUpdate: false },
...linkedFGProps,
...linkedRenderObjsProps
},
methods: {
zoomToFit: function(state, transitionDuration, padding, ...bboxArgs) {
state.renderObjs.fitToBbox(
state.forceGraph.getGraphBbox(...bboxArgs),
transitionDuration,
padding
);
return this;
},
pauseAnimation: function(state) {
if (state.animationFrameRequestId !== null) {
cancelAnimationFrame(state.animationFrameRequestId);
state.animationFrameRequestId = null;
}
return this;
},
resumeAnimation: function(state) {
if (state.animationFrameRequestId === null) {
this._animationCycle();
}
return this;
},
_animationCycle(state) {
if (state.enablePointerInteraction) {
// reset canvas cursor (override dragControls cursor)
this.renderer().domElement.style.cursor = null;
}
// Frame cycle
state.forceGraph.tickFrame();
state.renderObjs.tick();
state.animationFrameRequestId = requestAnimationFrame(this._animationCycle);
},
scene: state => state.renderObjs.scene(), // Expose scene
camera: state => state.renderObjs.camera(), // Expose camera
renderer: state => state.renderObjs.renderer(), // Expose renderer
controls: state => state.renderObjs.controls(), // Expose controls
tbControls: state => state.renderObjs.tbControls(), // To be deprecated
_destructor: function() {
this.pauseAnimation();
this.graphData({ nodes: [], links: []});
},
...linkedFGMethods,
...linkedRenderObjsMethods
},
stateInit: ({ controlType, rendererConfig, extraRenderers }) => {
const forceGraph = new ThreeForceGraph();
return {
forceGraph,
renderObjs: ThreeRenderObjects({ controlType, rendererConfig, extraRenderers })
.objects([forceGraph]) // Populate scene
.lights([
new three.AmbientLight(0xcccccc, Math.PI),
new three.DirectionalLight(0xffffff, 0.6 * Math.PI)
])
}
},
init: function(domNode, state) {
// Wipe DOM
domNode.innerHTML = '';
// Add relative container
domNode.appendChild(state.container = document.createElement('div'));
state.container.style.position = 'relative';
// Add renderObjs
const roDomNode = document.createElement('div');
state.container.appendChild(roDomNode);
state.renderObjs(roDomNode);
const camera = state.renderObjs.camera();
const renderer = state.renderObjs.renderer();
const controls = state.renderObjs.controls();
controls.enabled = !!state.enableNavigationControls;
state.lastSetCameraZ = camera.position.z;
// Add info space
let infoElem;
state.container.appendChild(infoElem = document.createElement('div'));
infoElem.className = 'graph-info-msg';
infoElem.textContent = '';
// config forcegraph
state.forceGraph
.onLoading(() => { infoElem.textContent = 'Loading...' })
.onFinishLoading(() => { infoElem.textContent = '' })
.onUpdate(() => {
// sync graph data structures
state.graphData = state.forceGraph.graphData();
// re-aim camera, if still in default position (not user modified)
if (camera.position.x === 0 && camera.position.y === 0 && camera.position.z === state.lastSetCameraZ && state.graphData.nodes.length) {
camera.lookAt(state.forceGraph.position);
state.lastSetCameraZ = camera.position.z = Math.cbrt(state.graphData.nodes.length) * CAMERA_DISTANCE2NODES_FACTOR;
}
})
.onFinishUpdate(() => {
// Setup node drag interaction
if (state._dragControls) {
const curNodeDrag = state.graphData.nodes.find(node => node.__initialFixedPos && !node.__disposeControlsAfterDrag); // detect if there's a node being dragged using the existing drag controls
if (curNodeDrag) {
curNodeDrag.__disposeControlsAfterDrag = true; // postpone previous controls disposal until drag ends
} else {
state._dragControls.dispose(); // cancel previous drag controls
}
state._dragControls = undefined;
}
if (state.enableNodeDrag && state.enablePointerInteraction && state.forceEngine === 'd3') { // Can't access node positions programmatically in ngraph
const dragControls = state._dragControls = new ThreeDragControls(
state.graphData.nodes.map(node => node.__threeObj).filter(obj => obj),
camera,
renderer.domElement
);
dragControls.addEventListener('dragstart', function (event) {
controls.enabled = false; // Disable controls while dragging
// track drag object movement
event.object.__initialPos = event.object.position.clone();
event.object.__prevPos = event.object.position.clone();
const node = getGraphObj(event.object).__data;
!node.__initialFixedPos && (node.__initialFixedPos = {fx: node.fx, fy: node.fy, fz: node.fz});
!node.__initialPos && (node.__initialPos = {x: node.x, y: node.y, z: node.z});
// lock node
['x', 'y', 'z'].forEach(c => node[`f${c}`] = node[c]);
// drag cursor
renderer.domElement.classList.add('grabbable');
});
dragControls.addEventListener('drag', function (event) {
const nodeObj = getGraphObj(event.object);
if (!event.object.hasOwnProperty('__graphObjType')) {
// If dragging a child of the node, update the node object instead
const initPos = event.object.__initialPos;
const prevPos = event.object.__prevPos;
const newPos = event.object.position;
nodeObj.position.add(newPos.clone().sub(prevPos)); // translate node object by the motion delta
prevPos.copy(newPos);
newPos.copy(initPos); // reset child back to its initial position
}
const node = nodeObj.__data;
const newPos = nodeObj.position;
const translate = {x: newPos.x - node.x, y: newPos.y - node.y, z: newPos.z - node.z};
// Move fx/fy/fz (and x/y/z) of nodes based on object new position
['x', 'y', 'z'].forEach(c => node[`f${c}`] = node[c] = newPos[c]);
state.forceGraph
.d3AlphaTarget(0.3) // keep engine running at low intensity throughout drag
.resetCountdown(); // prevent freeze while dragging
node.__dragged = true;
state.onNodeDrag(node, translate);
});
dragControls.addEventListener('dragend', function (event) {
delete(event.object.__initialPos); // remove tracking attributes
delete(event.object.__prevPos);
const node = getGraphObj(event.object).__data;
// dispose previous controls if needed
if (node.__disposeControlsAfterDrag) {
dragControls.dispose();
delete(node.__disposeControlsAfterDrag);
}
const initFixedPos = node.__initialFixedPos;
const initPos = node.__initialPos;
const translate = {x: initPos.x - node.x, y: initPos.y - node.y, z: initPos.z - node.z};
if (initFixedPos) {
['x', 'y', 'z'].forEach(c => {
const fc = `f${c}`;
if (initFixedPos[fc] === undefined) {
delete(node[fc])
}
});
delete(node.__initialFixedPos);
delete(node.__initialPos);
if (node.__dragged) {
delete(node.__dragged);
state.onNodeDragEnd(node, translate);
}
}
state.forceGraph
.d3AlphaTarget(0) // release engine low intensity
.resetCountdown(); // let the engine readjust after releasing fixed nodes
if (state.enableNavigationControls) {
controls.enabled = true; // Re-enable controls
controls.domElement && controls.domElement.ownerDocument && controls.domElement.ownerDocument.dispatchEvent(
// simulate mouseup to ensure the controls don't take over after dragend
new PointerEvent('pointerup', { pointerType: 'touch' })
);
}
// clear cursor
renderer.domElement.classList.remove('grabbable');
});
}
});
// config renderObjs
three.REVISION < 155 && (state.renderObjs.renderer().useLegacyLights = false); // force behavior for three < 155
state.renderObjs
.hoverOrderComparator((a, b) => {
// Prioritize graph objects
const aObj = getGraphObj(a);
if (!aObj) return 1;
const bObj = getGraphObj(b);
if (!bObj) return -1;
// Prioritize nodes over links
const isNode = o => o.__graphObjType === 'node';
return isNode(bObj) - isNode(aObj);
})
.tooltipContent(obj => {
const graphObj = getGraphObj(obj);
return graphObj ? accessorFn(state[`${graphObj.__graphObjType}Label`])(graphObj.__data) || '' : '';
})
.hoverDuringDrag(false)
.onHover(obj => {
// Update tooltip and trigger onHover events
const hoverObj = getGraphObj(obj);
if (hoverObj !== state.hoverObj) {
const prevObjType = state.hoverObj ? state.hoverObj.__graphObjType : null;
const prevObjData = state.hoverObj ? state.hoverObj.__data : null;
const objType = hoverObj ? hoverObj.__graphObjType : null;
const objData = hoverObj ? hoverObj.__data : null;
if (prevObjType && prevObjType !== objType) {
// Hover out
const fn = state[`on${prevObjType === 'node' ? 'Node' : 'Link'}Hover`];
fn && fn(null, prevObjData);
}
if (objType) {
// Hover in
const fn = state[`on${objType === 'node' ? 'Node' : 'Link'}Hover`];
fn && fn(objData, prevObjType === objType ? prevObjData : null);
}
// set pointer if hovered object is clickable
renderer.domElement.classList[
((hoverObj && state[`on${objType === 'node' ? 'Node' : 'Link'}Click`]) || (!hoverObj && state.onBackgroundClick)) ? 'add' : 'remove'
]('clickable');
state.hoverObj = hoverObj;
}
})
.clickAfterDrag(false)
.onClick((obj, ev) => {
const graphObj = getGraphObj(obj);
if (graphObj) {
const fn = state[`on${graphObj.__graphObjType === 'node' ? 'Node' : 'Link'}Click`];
fn && fn(graphObj.__data, ev);
} else {
state.onBackgroundClick && state.onBackgroundClick(ev);
}
})
.onRightClick((obj, ev) => {
// Handle right-click events
const graphObj = getGraphObj(obj);
if (graphObj) {
const fn = state[`on${graphObj.__graphObjType === 'node' ? 'Node' : 'Link'}RightClick`];
fn && fn(graphObj.__data, ev);
} else {
state.onBackgroundRightClick && state.onBackgroundRightClick(ev);
}
});
//
// Kick-off renderer
this._animationCycle();
}
});
//
function getGraphObj(object) {
let obj = object;
// recurse up object chain until finding the graph object
while (obj && !obj.hasOwnProperty('__graphObjType')) {
obj = obj.parent;
}
return obj;
}

View file

@ -1,410 +0,0 @@
import {
Controls,
Matrix4,
Plane,
Raycaster,
Vector2,
Vector3,
MOUSE,
TOUCH
} from './three.module.js';
const _plane = new Plane();
const _pointer = new Vector2();
const _offset = new Vector3();
const _diff = new Vector2();
const _previousPointer = new Vector2();
const _intersection = new Vector3();
const _worldPosition = new Vector3();
const _inverseMatrix = new Matrix4();
const _up = new Vector3();
const _right = new Vector3();
let _selected = null, _hovered = null;
const _intersections = [];
const STATE = {
NONE: - 1,
PAN: 0,
ROTATE: 1
};
class DragControls extends Controls {
constructor( objects, camera, domElement = null ) {
super( camera, domElement );
this.objects = objects;
this.recursive = true;
this.transformGroup = false;
this.rotateSpeed = 1;
this.raycaster = new Raycaster();
// interaction
this.mouseButtons = { LEFT: MOUSE.PAN, MIDDLE: MOUSE.PAN, RIGHT: MOUSE.ROTATE };
this.touches = { ONE: TOUCH.PAN };
// event listeners
this._onPointerMove = onPointerMove.bind( this );
this._onPointerDown = onPointerDown.bind( this );
this._onPointerCancel = onPointerCancel.bind( this );
this._onContextMenu = onContextMenu.bind( this );
//
if ( domElement !== null ) {
this.connect();
}
}
connect() {
this.domElement.addEventListener( 'pointermove', this._onPointerMove );
this.domElement.addEventListener( 'pointerdown', this._onPointerDown );
this.domElement.addEventListener( 'pointerup', this._onPointerCancel );
this.domElement.addEventListener( 'pointerleave', this._onPointerCancel );
this.domElement.addEventListener( 'contextmenu', this._onContextMenu );
this.domElement.style.touchAction = 'none'; // disable touch scroll
}
disconnect() {
this.domElement.removeEventListener( 'pointermove', this._onPointerMove );
this.domElement.removeEventListener( 'pointerdown', this._onPointerDown );
this.domElement.removeEventListener( 'pointerup', this._onPointerCancel );
this.domElement.removeEventListener( 'pointerleave', this._onPointerCancel );
this.domElement.removeEventListener( 'contextmenu', this._onContextMenu );
this.domElement.style.touchAction = 'auto';
this.domElement.style.cursor = '';
}
dispose() {
this.disconnect();
}
_updatePointer( event ) {
const rect = this.domElement.getBoundingClientRect();
_pointer.x = ( event.clientX - rect.left ) / rect.width * 2 - 1;
_pointer.y = - ( event.clientY - rect.top ) / rect.height * 2 + 1;
}
_updateState( event ) {
// determine action
let action;
if ( event.pointerType === 'touch' ) {
action = this.touches.ONE;
} else {
switch ( event.button ) {
case 0:
action = this.mouseButtons.LEFT;
break;
case 1:
action = this.mouseButtons.MIDDLE;
break;
case 2:
action = this.mouseButtons.RIGHT;
break;
default:
action = null;
}
}
// determine state
switch ( action ) {
case MOUSE.PAN:
case TOUCH.PAN:
this.state = STATE.PAN;
break;
case MOUSE.ROTATE:
case TOUCH.ROTATE:
this.state = STATE.ROTATE;
break;
default:
this.state = STATE.NONE;
}
}
getRaycaster() {
console.warn( 'THREE.DragControls: getRaycaster() has been deprecated. Use controls.raycaster instead.' ); // @deprecated r169
return this.raycaster;
}
setObjects( objects ) {
console.warn( 'THREE.DragControls: setObjects() has been deprecated. Use controls.objects instead.' ); // @deprecated r169
this.objects = objects;
}
getObjects() {
console.warn( 'THREE.DragControls: getObjects() has been deprecated. Use controls.objects instead.' ); // @deprecated r169
return this.objects;
}
activate() {
console.warn( 'THREE.DragControls: activate() has been renamed to connect().' ); // @deprecated r169
this.connect();
}
deactivate() {
console.warn( 'THREE.DragControls: deactivate() has been renamed to disconnect().' ); // @deprecated r169
this.disconnect();
}
set mode( value ) {
console.warn( 'THREE.DragControls: The .mode property has been removed. Define the type of transformation via the .mouseButtons or .touches properties.' ); // @deprecated r169
}
get mode() {
console.warn( 'THREE.DragControls: The .mode property has been removed. Define the type of transformation via the .mouseButtons or .touches properties.' ); // @deprecated r169
}
}
function onPointerMove( event ) {
const camera = this.object;
const domElement = this.domElement;
const raycaster = this.raycaster;
if ( this.enabled === false ) return;
this._updatePointer( event );
raycaster.setFromCamera( _pointer, camera );
if ( _selected ) {
if ( this.state === STATE.PAN ) {
if ( raycaster.ray.intersectPlane( _plane, _intersection ) ) {
_selected.position.copy( _intersection.sub( _offset ).applyMatrix4( _inverseMatrix ) );
}
} else if ( this.state === STATE.ROTATE ) {
_diff.subVectors( _pointer, _previousPointer ).multiplyScalar( this.rotateSpeed );
_selected.rotateOnWorldAxis( _up, _diff.x );
_selected.rotateOnWorldAxis( _right.normalize(), - _diff.y );
}
this.dispatchEvent( { type: 'drag', object: _selected } );
_previousPointer.copy( _pointer );
} else {
// hover support
if ( event.pointerType === 'mouse' || event.pointerType === 'pen' ) {
_intersections.length = 0;
raycaster.setFromCamera( _pointer, camera );
raycaster.intersectObjects( this.objects, this.recursive, _intersections );
if ( _intersections.length > 0 ) {
const object = _intersections[ 0 ].object;
_plane.setFromNormalAndCoplanarPoint( camera.getWorldDirection( _plane.normal ), _worldPosition.setFromMatrixPosition( object.matrixWorld ) );
if ( _hovered !== object && _hovered !== null ) {
this.dispatchEvent( { type: 'hoveroff', object: _hovered } );
domElement.style.cursor = 'auto';
_hovered = null;
}
if ( _hovered !== object ) {
this.dispatchEvent( { type: 'hoveron', object: object } );
domElement.style.cursor = 'pointer';
_hovered = object;
}
} else {
if ( _hovered !== null ) {
this.dispatchEvent( { type: 'hoveroff', object: _hovered } );
domElement.style.cursor = 'auto';
_hovered = null;
}
}
}
}
_previousPointer.copy( _pointer );
}
function onPointerDown( event ) {
const camera = this.object;
const domElement = this.domElement;
const raycaster = this.raycaster;
if ( this.enabled === false ) return;
this._updatePointer( event );
this._updateState( event );
_intersections.length = 0;
raycaster.setFromCamera( _pointer, camera );
raycaster.intersectObjects( this.objects, this.recursive, _intersections );
if ( _intersections.length > 0 ) {
if ( this.transformGroup === true ) {
// look for the outermost group in the object's upper hierarchy
_selected = findGroup( _intersections[ 0 ].object );
} else {
_selected = _intersections[ 0 ].object;
}
_plane.setFromNormalAndCoplanarPoint( camera.getWorldDirection( _plane.normal ), _worldPosition.setFromMatrixPosition( _selected.matrixWorld ) );
if ( raycaster.ray.intersectPlane( _plane, _intersection ) ) {
if ( this.state === STATE.PAN ) {
_inverseMatrix.copy( _selected.parent.matrixWorld ).invert();
_offset.copy( _intersection ).sub( _worldPosition.setFromMatrixPosition( _selected.matrixWorld ) );
} else if ( this.state === STATE.ROTATE ) {
// the controls only support Y+ up
_up.set( 0, 1, 0 ).applyQuaternion( camera.quaternion ).normalize();
_right.set( 1, 0, 0 ).applyQuaternion( camera.quaternion ).normalize();
}
}
domElement.style.cursor = 'move';
this.dispatchEvent( { type: 'dragstart', object: _selected } );
}
_previousPointer.copy( _pointer );
}
function onPointerCancel() {
if ( this.enabled === false ) return;
if ( _selected ) {
this.dispatchEvent( { type: 'dragend', object: _selected } );
_selected = null;
}
this.domElement.style.cursor = _hovered ? 'pointer' : 'auto';
this.state = STATE.NONE;
}
function onContextMenu( event ) {
if ( this.enabled === false ) return;
event.preventDefault();
}
function findGroup( obj, group = null ) {
if ( obj.isGroup ) group = obj;
if ( obj.parent === null ) return group;
return findGroup( obj.parent, group );
}
export { DragControls };

View file

@ -1,22 +0,0 @@
// Version 1.5.0 accessor-fn - https://github.com/vasturiano/accessor-fn
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.accessorFn = factory());
})(this, (function () { 'use strict';
var index = (function (p) {
return typeof p === 'function' ? p // fn
: typeof p === 'string' ? function (obj) {
return obj[p];
} // property name
: function (obj) {
return p;
};
}); // constant
return index;
}));
//# sourceMappingURL=accessor-fn.js.map
export default TableCsv

View file

@ -1,26 +0,0 @@
export default function(kapsulePropName, kapsuleType) {
const dummyK = new kapsuleType(); // To extract defaults
dummyK._destructor && dummyK._destructor();
return {
linkProp: function(prop) { // link property config
return {
default: dummyK[prop](),
onChange(v, state) { state[kapsulePropName][prop](v) },
triggerUpdate: false
}
},
linkMethod: function(method) { // link method pass-through
return function(state, ...args) {
const kapsuleInstance = state[kapsulePropName];
const returnVal = kapsuleInstance[method](...args);
return returnVal === kapsuleInstance
? this // chain based on the parent object, not the inner kapsule
: returnVal;
}
}
}
}

View file

@ -1,716 +0,0 @@
// Version 1.14.4 kapsule - https://github.com/vasturiano/kapsule
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Kapsule = factory());
})(this, (function () { 'use strict';
function _iterableToArrayLimit(arr, i) {
var _i = null == arr ? null : "undefined" != typeof Symbol && arr[Symbol.iterator] || arr["@@iterator"];
if (null != _i) {
var _s,
_e,
_x,
_r,
_arr = [],
_n = !0,
_d = !1;
try {
if (_x = (_i = _i.call(arr)).next, 0 === i) {
if (Object(_i) !== _i) return;
_n = !1;
} else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0);
} catch (err) {
_d = !0, _e = err;
} finally {
try {
if (!_n && null != _i.return && (_r = _i.return(), Object(_r) !== _r)) return;
} finally {
if (_d) throw _e;
}
}
return _arr;
}
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
Object.defineProperty(Constructor, "prototype", {
writable: false
});
return Constructor;
}
function _slicedToArray(arr, i) {
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
}
function _arrayWithHoles(arr) {
if (Array.isArray(arr)) return arr;
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function _nonIterableRest() {
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _toPrimitive(input, hint) {
if (typeof input !== "object" || input === null) return input;
var prim = input[Symbol.toPrimitive];
if (prim !== undefined) {
var res = prim.call(input, hint || "default");
if (typeof res !== "object") return res;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return (hint === "string" ? String : Number)(input);
}
function _toPropertyKey(arg) {
var key = _toPrimitive(arg, "string");
return typeof key === "symbol" ? key : String(key);
}
/** Detect free variable `global` from Node.js. */
var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
var freeGlobal$1 = freeGlobal;
/** Detect free variable `self`. */
var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
/** Used as a reference to the global object. */
var root = freeGlobal$1 || freeSelf || Function('return this')();
var root$1 = root;
/** Built-in value references. */
var Symbol$1 = root$1.Symbol;
var Symbol$2 = Symbol$1;
/** Used for built-in method references. */
var objectProto$1 = Object.prototype;
/** Used to check objects for own properties. */
var hasOwnProperty = objectProto$1.hasOwnProperty;
/**
* Used to resolve the
* [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
* of values.
*/
var nativeObjectToString$1 = objectProto$1.toString;
/** Built-in value references. */
var symToStringTag$1 = Symbol$2 ? Symbol$2.toStringTag : undefined;
/**
* A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
*
* @private
* @param {*} value The value to query.
* @returns {string} Returns the raw `toStringTag`.
*/
function getRawTag(value) {
var isOwn = hasOwnProperty.call(value, symToStringTag$1),
tag = value[symToStringTag$1];
try {
value[symToStringTag$1] = undefined;
var unmasked = true;
} catch (e) {}
var result = nativeObjectToString$1.call(value);
if (unmasked) {
if (isOwn) {
value[symToStringTag$1] = tag;
} else {
delete value[symToStringTag$1];
}
}
return result;
}
/** Used for built-in method references. */
var objectProto = Object.prototype;
/**
* Used to resolve the
* [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
* of values.
*/
var nativeObjectToString = objectProto.toString;
/**
* Converts `value` to a string using `Object.prototype.toString`.
*
* @private
* @param {*} value The value to convert.
* @returns {string} Returns the converted string.
*/
function objectToString(value) {
return nativeObjectToString.call(value);
}
/** `Object#toString` result references. */
var nullTag = '[object Null]',
undefinedTag = '[object Undefined]';
/** Built-in value references. */
var symToStringTag = Symbol$2 ? Symbol$2.toStringTag : undefined;
/**
* The base implementation of `getTag` without fallbacks for buggy environments.
*
* @private
* @param {*} value The value to query.
* @returns {string} Returns the `toStringTag`.
*/
function baseGetTag(value) {
if (value == null) {
return value === undefined ? undefinedTag : nullTag;
}
return (symToStringTag && symToStringTag in Object(value))
? getRawTag(value)
: objectToString(value);
}
/**
* Checks if `value` is object-like. A value is object-like if it's not `null`
* and has a `typeof` result of "object".
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is object-like, else `false`.
* @example
*
* _.isObjectLike({});
* // => true
*
* _.isObjectLike([1, 2, 3]);
* // => true
*
* _.isObjectLike(_.noop);
* // => false
*
* _.isObjectLike(null);
* // => false
*/
function isObjectLike(value) {
return value != null && typeof value == 'object';
}
/** `Object#toString` result references. */
var symbolTag = '[object Symbol]';
/**
* Checks if `value` is classified as a `Symbol` primitive or object.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
* @example
*
* _.isSymbol(Symbol.iterator);
* // => true
*
* _.isSymbol('abc');
* // => false
*/
function isSymbol(value) {
return typeof value == 'symbol' ||
(isObjectLike(value) && baseGetTag(value) == symbolTag);
}
/** Used to match a single whitespace character. */
var reWhitespace = /\s/;
/**
* Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace
* character of `string`.
*
* @private
* @param {string} string The string to inspect.
* @returns {number} Returns the index of the last non-whitespace character.
*/
function trimmedEndIndex(string) {
var index = string.length;
while (index-- && reWhitespace.test(string.charAt(index))) {}
return index;
}
/** Used to match leading whitespace. */
var reTrimStart = /^\s+/;
/**
* The base implementation of `_.trim`.
*
* @private
* @param {string} string The string to trim.
* @returns {string} Returns the trimmed string.
*/
function baseTrim(string) {
return string
? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, '')
: string;
}
/**
* Checks if `value` is the
* [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
* of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
* @example
*
* _.isObject({});
* // => true
*
* _.isObject([1, 2, 3]);
* // => true
*
* _.isObject(_.noop);
* // => true
*
* _.isObject(null);
* // => false
*/
function isObject(value) {
var type = typeof value;
return value != null && (type == 'object' || type == 'function');
}
/** Used as references for various `Number` constants. */
var NAN = 0 / 0;
/** Used to detect bad signed hexadecimal string values. */
var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
/** Used to detect binary string values. */
var reIsBinary = /^0b[01]+$/i;
/** Used to detect octal string values. */
var reIsOctal = /^0o[0-7]+$/i;
/** Built-in method references without a dependency on `root`. */
var freeParseInt = parseInt;
/**
* Converts `value` to a number.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to process.
* @returns {number} Returns the number.
* @example
*
* _.toNumber(3.2);
* // => 3.2
*
* _.toNumber(Number.MIN_VALUE);
* // => 5e-324
*
* _.toNumber(Infinity);
* // => Infinity
*
* _.toNumber('3.2');
* // => 3.2
*/
function toNumber(value) {
if (typeof value == 'number') {
return value;
}
if (isSymbol(value)) {
return NAN;
}
if (isObject(value)) {
var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
value = isObject(other) ? (other + '') : other;
}
if (typeof value != 'string') {
return value === 0 ? value : +value;
}
value = baseTrim(value);
var isBinary = reIsBinary.test(value);
return (isBinary || reIsOctal.test(value))
? freeParseInt(value.slice(2), isBinary ? 2 : 8)
: (reIsBadHex.test(value) ? NAN : +value);
}
/**
* Gets the timestamp of the number of milliseconds that have elapsed since
* the Unix epoch (1 January 1970 00:00:00 UTC).
*
* @static
* @memberOf _
* @since 2.4.0
* @category Date
* @returns {number} Returns the timestamp.
* @example
*
* _.defer(function(stamp) {
* console.log(_.now() - stamp);
* }, _.now());
* // => Logs the number of milliseconds it took for the deferred invocation.
*/
var now = function() {
return root$1.Date.now();
};
var now$1 = now;
/** Error message constants. */
var FUNC_ERROR_TEXT = 'Expected a function';
/* Built-in method references for those with the same name as other `lodash` methods. */
var nativeMax = Math.max,
nativeMin = Math.min;
/**
* Creates a debounced function that delays invoking `func` until after `wait`
* milliseconds have elapsed since the last time the debounced function was
* invoked. The debounced function comes with a `cancel` method to cancel
* delayed `func` invocations and a `flush` method to immediately invoke them.
* Provide `options` to indicate whether `func` should be invoked on the
* leading and/or trailing edge of the `wait` timeout. The `func` is invoked
* with the last arguments provided to the debounced function. Subsequent
* calls to the debounced function return the result of the last `func`
* invocation.
*
* **Note:** If `leading` and `trailing` options are `true`, `func` is
* invoked on the trailing edge of the timeout only if the debounced function
* is invoked more than once during the `wait` timeout.
*
* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
* until to the next tick, similar to `setTimeout` with a timeout of `0`.
*
* See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
* for details over the differences between `_.debounce` and `_.throttle`.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Function
* @param {Function} func The function to debounce.
* @param {number} [wait=0] The number of milliseconds to delay.
* @param {Object} [options={}] The options object.
* @param {boolean} [options.leading=false]
* Specify invoking on the leading edge of the timeout.
* @param {number} [options.maxWait]
* The maximum time `func` is allowed to be delayed before it's invoked.
* @param {boolean} [options.trailing=true]
* Specify invoking on the trailing edge of the timeout.
* @returns {Function} Returns the new debounced function.
* @example
*
* // Avoid costly calculations while the window size is in flux.
* jQuery(window).on('resize', _.debounce(calculateLayout, 150));
*
* // Invoke `sendMail` when clicked, debouncing subsequent calls.
* jQuery(element).on('click', _.debounce(sendMail, 300, {
* 'leading': true,
* 'trailing': false
* }));
*
* // Ensure `batchLog` is invoked once after 1 second of debounced calls.
* var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
* var source = new EventSource('/stream');
* jQuery(source).on('message', debounced);
*
* // Cancel the trailing debounced invocation.
* jQuery(window).on('popstate', debounced.cancel);
*/
function debounce(func, wait, options) {
var lastArgs,
lastThis,
maxWait,
result,
timerId,
lastCallTime,
lastInvokeTime = 0,
leading = false,
maxing = false,
trailing = true;
if (typeof func != 'function') {
throw new TypeError(FUNC_ERROR_TEXT);
}
wait = toNumber(wait) || 0;
if (isObject(options)) {
leading = !!options.leading;
maxing = 'maxWait' in options;
maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
trailing = 'trailing' in options ? !!options.trailing : trailing;
}
function invokeFunc(time) {
var args = lastArgs,
thisArg = lastThis;
lastArgs = lastThis = undefined;
lastInvokeTime = time;
result = func.apply(thisArg, args);
return result;
}
function leadingEdge(time) {
// Reset any `maxWait` timer.
lastInvokeTime = time;
// Start the timer for the trailing edge.
timerId = setTimeout(timerExpired, wait);
// Invoke the leading edge.
return leading ? invokeFunc(time) : result;
}
function remainingWait(time) {
var timeSinceLastCall = time - lastCallTime,
timeSinceLastInvoke = time - lastInvokeTime,
timeWaiting = wait - timeSinceLastCall;
return maxing
? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke)
: timeWaiting;
}
function shouldInvoke(time) {
var timeSinceLastCall = time - lastCallTime,
timeSinceLastInvoke = time - lastInvokeTime;
// Either this is the first call, activity has stopped and we're at the
// trailing edge, the system time has gone backwards and we're treating
// it as the trailing edge, or we've hit the `maxWait` limit.
return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
(timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
}
function timerExpired() {
var time = now$1();
if (shouldInvoke(time)) {
return trailingEdge(time);
}
// Restart the timer.
timerId = setTimeout(timerExpired, remainingWait(time));
}
function trailingEdge(time) {
timerId = undefined;
// Only invoke if we have `lastArgs` which means `func` has been
// debounced at least once.
if (trailing && lastArgs) {
return invokeFunc(time);
}
lastArgs = lastThis = undefined;
return result;
}
function cancel() {
if (timerId !== undefined) {
clearTimeout(timerId);
}
lastInvokeTime = 0;
lastArgs = lastCallTime = lastThis = timerId = undefined;
}
function flush() {
return timerId === undefined ? result : trailingEdge(now$1());
}
function debounced() {
var time = now$1(),
isInvoking = shouldInvoke(time);
lastArgs = arguments;
lastThis = this;
lastCallTime = time;
if (isInvoking) {
if (timerId === undefined) {
return leadingEdge(lastCallTime);
}
if (maxing) {
// Handle invocations in a tight loop.
clearTimeout(timerId);
timerId = setTimeout(timerExpired, wait);
return invokeFunc(lastCallTime);
}
}
if (timerId === undefined) {
timerId = setTimeout(timerExpired, wait);
}
return result;
}
debounced.cancel = cancel;
debounced.flush = flush;
return debounced;
}
var Prop = /*#__PURE__*/_createClass(function Prop(name, _ref) {
var _ref$default = _ref["default"],
defaultVal = _ref$default === void 0 ? null : _ref$default,
_ref$triggerUpdate = _ref.triggerUpdate,
triggerUpdate = _ref$triggerUpdate === void 0 ? true : _ref$triggerUpdate,
_ref$onChange = _ref.onChange,
onChange = _ref$onChange === void 0 ? function (newVal, state) {} : _ref$onChange;
_classCallCheck(this, Prop);
this.name = name;
this.defaultVal = defaultVal;
this.triggerUpdate = triggerUpdate;
this.onChange = onChange;
});
function index (_ref2) {
var _ref2$stateInit = _ref2.stateInit,
stateInit = _ref2$stateInit === void 0 ? function () {
return {};
} : _ref2$stateInit,
_ref2$props = _ref2.props,
rawProps = _ref2$props === void 0 ? {} : _ref2$props,
_ref2$methods = _ref2.methods,
methods = _ref2$methods === void 0 ? {} : _ref2$methods,
_ref2$aliases = _ref2.aliases,
aliases = _ref2$aliases === void 0 ? {} : _ref2$aliases,
_ref2$init = _ref2.init,
initFn = _ref2$init === void 0 ? function () {} : _ref2$init,
_ref2$update = _ref2.update,
updateFn = _ref2$update === void 0 ? function () {} : _ref2$update;
// Parse props into Prop instances
var props = Object.keys(rawProps).map(function (propName) {
return new Prop(propName, rawProps[propName]);
});
return function () {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
// Holds component state
var state = Object.assign({}, stateInit instanceof Function ? stateInit(options) : stateInit,
// Support plain objects for backwards compatibility
{
initialised: false
});
// keeps track of which props triggered an update
var changedProps = {};
// Component constructor
function comp(nodeElement) {
initStatic(nodeElement, options);
digest();
return comp;
}
var initStatic = function initStatic(nodeElement, options) {
initFn.call(comp, nodeElement, state, options);
state.initialised = true;
};
var digest = debounce(function () {
if (!state.initialised) {
return;
}
updateFn.call(comp, state, changedProps);
changedProps = {};
}, 1);
// Getter/setter methods
props.forEach(function (prop) {
comp[prop.name] = getSetProp(prop);
function getSetProp(_ref3) {
var prop = _ref3.name,
_ref3$triggerUpdate = _ref3.triggerUpdate,
redigest = _ref3$triggerUpdate === void 0 ? false : _ref3$triggerUpdate,
_ref3$onChange = _ref3.onChange,
onChange = _ref3$onChange === void 0 ? function (newVal, state) {} : _ref3$onChange,
_ref3$defaultVal = _ref3.defaultVal,
defaultVal = _ref3$defaultVal === void 0 ? null : _ref3$defaultVal;
return function (_) {
var curVal = state[prop];
if (!arguments.length) {
return curVal;
} // Getter mode
var val = _ === undefined ? defaultVal : _; // pick default if value passed is undefined
state[prop] = val;
onChange.call(comp, val, state, curVal);
// track changed props
!changedProps.hasOwnProperty(prop) && (changedProps[prop] = curVal);
if (redigest) {
digest();
}
return comp;
};
}
});
// Other methods
Object.keys(methods).forEach(function (methodName) {
comp[methodName] = function () {
var _methods$methodName;
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return (_methods$methodName = methods[methodName]).call.apply(_methods$methodName, [comp, state].concat(args));
};
});
// Link aliases
Object.entries(aliases).forEach(function (_ref4) {
var _ref5 = _slicedToArray(_ref4, 2),
alias = _ref5[0],
target = _ref5[1];
return comp[alias] = comp[target];
});
// Reset all component props to their default value
comp.resetProps = function () {
props.forEach(function (prop) {
comp[prop.name](prop.defaultVal);
});
return comp;
};
//
comp.resetProps(); // Apply all prop defaults
state._rerender = digest; // Expose digest method
return comp;
};
}
return index;
}));
//# sourceMappingURL=kapsule.js.map
export default TableCsv

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -1,227 +0,0 @@
// output_climate_pruebas.js
import ForceGraph3D from 'https://esm.sh/3d-force-graph?external=three';
import * as THREE from 'three';
document.addEventListener('DOMContentLoaded', () => {
const elem = document.getElementById('climateContainer');
const form = document.getElementById('paramForm');
let lastGraphData = { nodes: [], links: [] };
let fullGraphData = null;
let currentRelatedNodes = [];
let currentRelatedIdx = 0;
let currentNode = null;
const textureCache = {};
function getTexture(url) {
if (!textureCache[url]) textureCache[url] = new THREE.TextureLoader().load(url);
return textureCache[url];
}
const graph = ForceGraph3D()(elem)
.backgroundColor('#000000')
.nodeLabel(node => node.type === 'imagen' ? (node.label || node.id) : node.id)
.nodeAutoColorBy('group')
.nodeVal(node => node.type === 'imagen' ? 20 : 2)
.linkColor(() => '#42FF00')
.onNodeClick(node => showNodeDetail(node))
.onNodeHover(node => { elem.style.cursor = node ? 'pointer' : null; })
.nodeThreeObject(node => {
if (node.type !== 'imagen' || !node.image_url) return null;
const texture = getTexture(node.image_url);
texture.colorSpace = THREE.SRGBColorSpace;
const material = new THREE.SpriteMaterial({ map: texture, depthWrite: false });
const sprite = new THREE.Sprite(material);
sprite.scale.set(160, 104, 1);
return sprite;
})
.nodeThreeObjectExtend(false)
.forceEngine('d3');
graph.d3Force('charge').strength(-150);
graph.d3Force('link').distance(70).strength(0.3);
graph.d3Force('center').strength(0.05);
function centerGraph() {
setTimeout(() => {
graph.zoomToFit(400, Math.min(elem.clientWidth, elem.clientHeight) * 0.1);
}, 500);
}
window.addEventListener('resize', () => {
graph.width(elem.clientWidth);
graph.height(elem.clientHeight);
centerGraph();
});
function getAuthor(node) { return node.autor || node.fuente || node.source || ''; }
function formatDate(fecha) {
if (!fecha) return '';
try { return new Date(fecha).toLocaleDateString('es-ES'); } catch { return String(fecha); }
}
function formatTitle(id) { return String(id).replace(/_/g, ' '); }
function getRelated(node) {
const nid = node.id;
const relIds = new Set();
for (const lk of lastGraphData.links) {
const s = typeof lk.source === 'object' ? lk.source.id : lk.source;
const t = typeof lk.target === 'object' ? lk.target.id : lk.target;
if (s === nid) relIds.add(t);
else if (t === nid) relIds.add(s);
}
return lastGraphData.nodes.filter(n => relIds.has(n.id));
}
function renderDetailPanel(node, related, idx) {
const detailContent = document.getElementById('detailContent');
const split = document.querySelector('main.split-screen');
if (!detailContent || !split) return;
detailContent.querySelector('.detail-author').textContent = getAuthor(node);
detailContent.querySelector('.detail-date').textContent = formatDate(node.fecha || node.date);
detailContent.querySelector('.detail-title').textContent = formatTitle(node.id);
const relCount = detailContent.querySelector('.relations-count');
const relLabel = document.getElementById('relationLabel');
const prevBtn = document.getElementById('prevRelation');
const nextBtn = document.getElementById('nextRelation');
relCount.textContent = `${related.length} relación${related.length !== 1 ? 'es' : ''}`;
if (related.length > 0) {
relLabel.textContent = formatTitle(related[idx].id);
prevBtn.disabled = idx <= 0;
nextBtn.disabled = idx >= related.length - 1;
} else {
relLabel.textContent = '—';
prevBtn.disabled = true;
nextBtn.disabled = true;
}
const body = detailContent.querySelector('.detail-body');
body.innerHTML = '';
if (node.type === 'imagen' && node.image_url) {
const img = document.createElement('img');
img.src = node.image_url;
img.className = 'detail-img';
body.appendChild(img);
}
const text = document.createElement('span');
text.textContent = node.content || node.texto || node.descripcion || 'Sin contenido disponible.';
body.appendChild(text);
if (related.length > 0) {
const conexBtn = document.createElement('button');
conexBtn.id = 'verConexionesBtn';
conexBtn.textContent = '⬡ Ver solo conexiones de este nodo';
conexBtn.addEventListener('click', () => showEgoGraph(node));
body.appendChild(conexBtn);
}
split.classList.add('show-detail');
setTimeout(() => { graph.width(elem.clientWidth); graph.height(elem.clientHeight); }, 350);
}
function showEgoGraph(node) {
const nid = node.id;
const relIds = new Set();
for (const lk of lastGraphData.links) {
const s = typeof lk.source === 'object' ? lk.source.id : lk.source;
const t = typeof lk.target === 'object' ? lk.target.id : lk.target;
if (s === nid) relIds.add(t);
else if (t === nid) relIds.add(s);
}
const egoNodes = lastGraphData.nodes.filter(n => n.id === nid || relIds.has(n.id));
const egoIds = new Set(egoNodes.map(n => n.id));
const egoLinks = lastGraphData.links.filter(lk => {
const s = typeof lk.source === 'object' ? lk.source.id : lk.source;
const t = typeof lk.target === 'object' ? lk.target.id : lk.target;
return egoIds.has(s) && egoIds.has(t);
});
fullGraphData = lastGraphData;
graph.graphData({ nodes: egoNodes, links: egoLinks });
centerGraph();
document.getElementById('volverGrafoBtn').classList.add('visible');
}
function restoreFullGraph() {
if (fullGraphData) {
lastGraphData = fullGraphData;
fullGraphData = null;
graph.graphData({ nodes: lastGraphData.nodes, links: lastGraphData.links });
centerGraph();
document.getElementById('volverGrafoBtn').classList.remove('visible');
}
}
function showNodeDetail(node) {
currentNode = node;
currentRelatedNodes = getRelated(node);
currentRelatedIdx = 0;
renderDetailPanel(node, currentRelatedNodes, currentRelatedIdx);
}
document.getElementById('prevRelation').addEventListener('click', () => {
if (currentRelatedIdx > 0) {
currentRelatedIdx--;
renderDetailPanel(currentNode, currentRelatedNodes, currentRelatedIdx);
}
});
document.getElementById('nextRelation').addEventListener('click', () => {
if (currentRelatedIdx < currentRelatedNodes.length - 1) {
currentRelatedIdx++;
renderDetailPanel(currentNode, currentRelatedNodes, currentRelatedIdx);
}
});
document.getElementById('closeDetail').addEventListener('click', () => {
const split = document.querySelector('main.split-screen');
if (split) split.classList.remove('show-detail');
restoreFullGraph();
setTimeout(() => { graph.width(elem.clientWidth); graph.height(elem.clientHeight); }, 350);
});
document.getElementById('volverGrafoBtn').addEventListener('click', () => {
restoreFullGraph();
});
async function getData(paramsObj = {}) {
try {
let url = '/api/data';
const params = new URLSearchParams();
params.append('tema', 'cambio climático');
for (const key in paramsObj) {
if (paramsObj[key] !== undefined && paramsObj[key] !== '') {
params.append(key, paramsObj[key]);
}
}
url += `?${params.toString()}`;
console.log('Fetch URL:', url);
const response = await fetch(url);
if (!response.ok) throw new Error(response.statusText);
const data = await response.json();
const nodeIds = new Set(data.nodes.map(n => n.id));
data.links = data.links.filter(lk => nodeIds.has(lk.source) && nodeIds.has(lk.target));
return data;
} catch (error) {
console.error('Error al obtener datos:', error);
return null;
}
}
async function fetchAndRender() {
const paramsObj = {
subtematica: document.getElementById('param2').value,
palabraClave: document.getElementById('param1').value,
fechaInicio: document.getElementById('fecha_inicio').value,
fechaFin: document.getElementById('fecha_fin').value,
nodos: document.getElementById('nodos').value,
complejidad: document.getElementById('complejidad').value,
};
const graphData = await getData(paramsObj);
if (!graphData) return;
lastGraphData = graphData;
graph.graphData({ nodes: graphData.nodes, links: graphData.links });
centerGraph();
}
form.addEventListener('submit', event => { event.preventDefault(); fetchAndRender(); });
fetchAndRender();
});

View file

@ -1,227 +0,0 @@
// output_eco_corp.js
import ForceGraph3D from 'https://esm.sh/3d-force-graph?external=three';
import * as THREE from 'three';
document.addEventListener('DOMContentLoaded', () => {
const elem = document.getElementById('ecoCorpContainer');
const form = document.getElementById('paramForm');
let lastGraphData = { nodes: [], links: [] };
let fullGraphData = null;
let currentRelatedNodes = [];
let currentRelatedIdx = 0;
let currentNode = null;
const textureCache = {};
function getTexture(url) {
if (!textureCache[url]) textureCache[url] = new THREE.TextureLoader().load(url);
return textureCache[url];
}
const graph = ForceGraph3D()(elem)
.backgroundColor('#000000')
.nodeLabel(node => node.type === 'imagen' ? (node.label || node.id) : node.id)
.nodeAutoColorBy('group')
.nodeVal(node => node.type === 'imagen' ? 20 : 2)
.linkColor(() => 'yellow')
.onNodeClick(node => showNodeDetail(node))
.onNodeHover(node => { elem.style.cursor = node ? 'pointer' : null; })
.nodeThreeObject(node => {
if (node.type !== 'imagen' || !node.image_url) return null;
const texture = getTexture(node.image_url);
texture.colorSpace = THREE.SRGBColorSpace;
const material = new THREE.SpriteMaterial({ map: texture, depthWrite: false });
const sprite = new THREE.Sprite(material);
sprite.scale.set(160, 104, 1);
return sprite;
})
.nodeThreeObjectExtend(false)
.forceEngine('d3');
graph.d3Force('charge').strength(-150);
graph.d3Force('link').distance(70).strength(0.3);
graph.d3Force('center').strength(0.05);
function centerGraph() {
setTimeout(() => {
graph.zoomToFit(400, Math.min(elem.clientWidth, elem.clientHeight) * 0.1);
}, 500);
}
window.addEventListener('resize', () => {
graph.width(elem.clientWidth);
graph.height(elem.clientHeight);
centerGraph();
});
function getAuthor(node) { return node.autor || node.fuente || node.source || ''; }
function formatDate(fecha) {
if (!fecha) return '';
try { return new Date(fecha).toLocaleDateString('es-ES'); } catch { return String(fecha); }
}
function formatTitle(id) { return String(id).replace(/_/g, ' '); }
function getRelated(node) {
const nid = node.id;
const relIds = new Set();
for (const lk of lastGraphData.links) {
const s = typeof lk.source === 'object' ? lk.source.id : lk.source;
const t = typeof lk.target === 'object' ? lk.target.id : lk.target;
if (s === nid) relIds.add(t);
else if (t === nid) relIds.add(s);
}
return lastGraphData.nodes.filter(n => relIds.has(n.id));
}
function renderDetailPanel(node, related, idx) {
const detailContent = document.getElementById('detailContent');
const split = document.querySelector('main.split-screen');
if (!detailContent || !split) return;
detailContent.querySelector('.detail-author').textContent = getAuthor(node);
detailContent.querySelector('.detail-date').textContent = formatDate(node.fecha || node.date);
detailContent.querySelector('.detail-title').textContent = formatTitle(node.id);
const relCount = detailContent.querySelector('.relations-count');
const relLabel = document.getElementById('relationLabel');
const prevBtn = document.getElementById('prevRelation');
const nextBtn = document.getElementById('nextRelation');
relCount.textContent = `${related.length} relación${related.length !== 1 ? 'es' : ''}`;
if (related.length > 0) {
relLabel.textContent = formatTitle(related[idx].id);
prevBtn.disabled = idx <= 0;
nextBtn.disabled = idx >= related.length - 1;
} else {
relLabel.textContent = '—';
prevBtn.disabled = true;
nextBtn.disabled = true;
}
const body = detailContent.querySelector('.detail-body');
body.innerHTML = '';
if (node.type === 'imagen' && node.image_url) {
const img = document.createElement('img');
img.src = node.image_url;
img.className = 'detail-img';
body.appendChild(img);
}
const text = document.createElement('span');
text.textContent = node.content || node.texto || node.descripcion || 'Sin contenido disponible.';
body.appendChild(text);
if (related.length > 0) {
const conexBtn = document.createElement('button');
conexBtn.id = 'verConexionesBtn';
conexBtn.textContent = '⬡ Ver solo conexiones de este nodo';
conexBtn.addEventListener('click', () => showEgoGraph(node));
body.appendChild(conexBtn);
}
split.classList.add('show-detail');
setTimeout(() => { graph.width(elem.clientWidth); graph.height(elem.clientHeight); }, 350);
}
function showEgoGraph(node) {
const nid = node.id;
const relIds = new Set();
for (const lk of lastGraphData.links) {
const s = typeof lk.source === 'object' ? lk.source.id : lk.source;
const t = typeof lk.target === 'object' ? lk.target.id : lk.target;
if (s === nid) relIds.add(t);
else if (t === nid) relIds.add(s);
}
const egoNodes = lastGraphData.nodes.filter(n => n.id === nid || relIds.has(n.id));
const egoIds = new Set(egoNodes.map(n => n.id));
const egoLinks = lastGraphData.links.filter(lk => {
const s = typeof lk.source === 'object' ? lk.source.id : lk.source;
const t = typeof lk.target === 'object' ? lk.target.id : lk.target;
return egoIds.has(s) && egoIds.has(t);
});
fullGraphData = lastGraphData;
graph.graphData({ nodes: egoNodes, links: egoLinks });
centerGraph();
document.getElementById('volverGrafoBtn').classList.add('visible');
}
function restoreFullGraph() {
if (fullGraphData) {
lastGraphData = fullGraphData;
fullGraphData = null;
graph.graphData({ nodes: lastGraphData.nodes, links: lastGraphData.links });
centerGraph();
document.getElementById('volverGrafoBtn').classList.remove('visible');
}
}
function showNodeDetail(node) {
currentNode = node;
currentRelatedNodes = getRelated(node);
currentRelatedIdx = 0;
renderDetailPanel(node, currentRelatedNodes, currentRelatedIdx);
}
document.getElementById('prevRelation').addEventListener('click', () => {
if (currentRelatedIdx > 0) {
currentRelatedIdx--;
renderDetailPanel(currentNode, currentRelatedNodes, currentRelatedIdx);
}
});
document.getElementById('nextRelation').addEventListener('click', () => {
if (currentRelatedIdx < currentRelatedNodes.length - 1) {
currentRelatedIdx++;
renderDetailPanel(currentNode, currentRelatedNodes, currentRelatedIdx);
}
});
document.getElementById('closeDetail').addEventListener('click', () => {
const split = document.querySelector('main.split-screen');
if (split) split.classList.remove('show-detail');
restoreFullGraph();
setTimeout(() => { graph.width(elem.clientWidth); graph.height(elem.clientHeight); }, 350);
});
document.getElementById('volverGrafoBtn').addEventListener('click', () => {
restoreFullGraph();
});
async function getData(paramsObj = {}) {
try {
let url = '/api/data';
const params = new URLSearchParams();
params.append('tema', 'economía y corporaciones');
for (const key in paramsObj) {
if (paramsObj[key] !== undefined && paramsObj[key] !== '') {
params.append(key, paramsObj[key]);
}
}
url += `?${params.toString()}`;
console.log('Fetch URL:', url);
const response = await fetch(url);
if (!response.ok) throw new Error(response.statusText);
const data = await response.json();
const nodeIds = new Set(data.nodes.map(n => n.id));
data.links = data.links.filter(lk => nodeIds.has(lk.source) && nodeIds.has(lk.target));
return data;
} catch (error) {
console.error('Error al obtener datos:', error);
return null;
}
}
async function fetchAndRender() {
const paramsObj = {
subtematica: document.getElementById('param2').value,
palabraClave: document.getElementById('param1').value,
fechaInicio: document.getElementById('fecha_inicio').value,
fechaFin: document.getElementById('fecha_fin').value,
nodos: document.getElementById('nodos').value,
complejidad: document.getElementById('complejidad').value,
};
const graphData = await getData(paramsObj);
if (!graphData) return;
lastGraphData = graphData;
graph.graphData({ nodes: graphData.nodes, links: graphData.links });
centerGraph();
}
form.addEventListener('submit', event => { event.preventDefault(); fetchAndRender(); });
fetchAndRender();
});

View file

@ -1,144 +0,0 @@
// output_glob_war.js
// Obtener el contenedor del gráfico
const elem = document.getElementById('globWarContainer');
// Cache de texturas para no recargar la misma imagen
const textureCache = {};
function getTexture(url) {
if (!textureCache[url]) {
textureCache[url] = new THREE.TextureLoader().load(url);
}
return textureCache[url];
}
// Inicializar el gráfico
const graph = ForceGraph3D()(elem)
.backgroundColor('#000000')
.nodeLabel(node => node.type === 'imagen' ? (node.label || node.id) : node.id)
.nodeAutoColorBy('group')
.nodeVal(node => node.type === 'imagen' ? 0 : 2)
.linkColor(() => 'rgba(0,255,80,0.4)')
.onNodeClick(node => showNodeContent(node.content))
.onNodeHover(node => {
elem.style.cursor = node ? 'pointer' : null;
})
.nodeThreeObject(node => {
if (node.type !== 'imagen' || !node.image_url) return null;
const texture = getTexture(node.image_url);
texture.colorSpace = THREE.SRGBColorSpace;
const material = new THREE.SpriteMaterial({ map: texture, depthWrite: false });
const sprite = new THREE.Sprite(material);
sprite.scale.set(14, 9, 1);
return sprite;
})
.nodeThreeObjectExtend(false)
.forceEngine('d3')
.d3Force('charge', d3.forceManyBody().strength(-10))
.d3Force('link', d3.forceLink().distance(30).strength(1));
// Función para obtener datos del servidor
async function getData(paramsObj = {}) {
try {
let url = '/api/data';
const params = new URLSearchParams();
// Tema por defecto: "guerra global"
params.append('tema', 'guerra global');
// Agregar parámetros del formulario si existen
for (const key in paramsObj) {
if (paramsObj[key]) {
params.append(key, paramsObj[key]);
}
}
url += `?${params.toString()}`;
const response = await fetch(url);
const data = await response.json();
console.log('Datos recibidos del servidor:', data);
// Filtrar enlaces para nodos existentes
const nodeIds = new Set(data.nodes.map(n => n.id));
data.links = data.links.filter(l => nodeIds.has(l.source) && nodeIds.has(l.target));
console.log('Enlaces tras filtrar:', data.links);
return data;
} catch (error) {
console.error('Error al obtener datos del servidor:', error);
return { nodes: [], links: [] };
}
}
// Mostrar contenido del nodo al hacer click
function showNodeContent(content) {
console.log('Contenido del nodo:', content);
// aquí podrías mostrarlo en un panel si quieres
}
// Centrar y escalar el gráfico
function centerGraph() {
setTimeout(() => {
const width = elem.clientWidth;
const height = elem.clientHeight;
const padding = Math.min(width, height) * 0.1;
graph.zoomToFit(400, padding);
}, 500);
}
// Al cambiar el tamaño de la ventana, reajustar
window.addEventListener('resize', () => {
graph.width(elem.clientWidth);
graph.height(elem.clientHeight);
centerGraph();
});
// Gestionar el submit del formulario de parámetros
document.getElementById('paramForm').addEventListener('submit', event => {
event.preventDefault();
const subtematica = document.getElementById('param2').value;
const palabraClave = document.getElementById('param1').value;
const fechaInicio = document.getElementById('fecha_inicio').value;
const fechaFin = document.getElementById('fecha_fin').value;
const nodos = document.getElementById('nodos').value;
const complejidad = document.getElementById('complejidad').value;
const paramsObj = {
subtematica,
palabraClave,
fechaInicio,
fechaFin,
nodos,
complejidad
};
getData(paramsObj).then(data => {
graph.graphData(data);
centerGraph();
});
});
// Cargar datos iniciales (guerra global) y renderizar
getData().then(data => {
if (data.nodes && data.nodes.length) {
console.log(`Se recibieron ${data.nodes.length} nodos.`);
graph.graphData(data);
centerGraph();
} else {
console.warn('No se recibieron nodos para "guerra global".');
}
});

View file

@ -1,229 +0,0 @@
// output_glob_war.js
import ForceGraph3D from 'https://esm.sh/3d-force-graph?external=three';
import * as THREE from 'three';
document.addEventListener('DOMContentLoaded', () => {
const elem = document.getElementById('globWarContainer');
const form = document.getElementById('paramForm');
let lastGraphData = { nodes: [], links: [] };
let fullGraphData = null;
let currentRelatedNodes = [];
let currentRelatedIdx = 0;
let currentNode = null;
const textureCache = {};
function getTexture(url) {
if (!textureCache[url]) textureCache[url] = new THREE.TextureLoader().load(url);
return textureCache[url];
}
const graph = ForceGraph3D()(elem)
.backgroundColor('#000000')
.nodeLabel(node => node.type === 'imagen' ? (node.label || node.id) : node.id)
.nodeAutoColorBy('group')
.nodeVal(node => node.type === 'imagen' ? 20 : 2)
.linkColor(() => 'red')
.onNodeClick(node => showNodeDetail(node))
.onNodeHover(node => { elem.style.cursor = node ? 'pointer' : null; })
.nodeThreeObject(node => {
if (node.type !== 'imagen' || !node.image_url) return null;
const texture = getTexture(node.image_url);
texture.colorSpace = THREE.SRGBColorSpace;
const material = new THREE.SpriteMaterial({ map: texture, depthWrite: false });
const sprite = new THREE.Sprite(material);
sprite.scale.set(160, 104, 1);
return sprite;
})
.nodeThreeObjectExtend(false)
.forceEngine('d3');
graph.d3Force('charge').strength(-150);
graph.d3Force('link').distance(70).strength(0.3);
graph.d3Force('center').strength(0.05);
function centerGraph() {
setTimeout(() => {
graph.zoomToFit(400, Math.min(elem.clientWidth, elem.clientHeight) * 0.1);
}, 500);
}
window.addEventListener('resize', () => {
graph.width(elem.clientWidth);
graph.height(elem.clientHeight);
centerGraph();
});
// --- Detail panel helpers ---
function getAuthor(node) { return node.autor || node.fuente || node.source || ''; }
function formatDate(fecha) {
if (!fecha) return '';
try { return new Date(fecha).toLocaleDateString('es-ES'); } catch { return String(fecha); }
}
function formatTitle(id) { return String(id).replace(/_/g, ' '); }
function getRelated(node) {
const nid = node.id;
const relIds = new Set();
for (const lk of lastGraphData.links) {
const s = typeof lk.source === 'object' ? lk.source.id : lk.source;
const t = typeof lk.target === 'object' ? lk.target.id : lk.target;
if (s === nid) relIds.add(t);
else if (t === nid) relIds.add(s);
}
return lastGraphData.nodes.filter(n => relIds.has(n.id));
}
function renderDetailPanel(node, related, idx) {
const detailContent = document.getElementById('detailContent');
const split = document.querySelector('main.split-screen');
if (!detailContent || !split) return;
detailContent.querySelector('.detail-author').textContent = getAuthor(node);
detailContent.querySelector('.detail-date').textContent = formatDate(node.fecha || node.date);
detailContent.querySelector('.detail-title').textContent = formatTitle(node.id);
const relCount = detailContent.querySelector('.relations-count');
const relLabel = document.getElementById('relationLabel');
const prevBtn = document.getElementById('prevRelation');
const nextBtn = document.getElementById('nextRelation');
relCount.textContent = `${related.length} relación${related.length !== 1 ? 'es' : ''}`;
if (related.length > 0) {
relLabel.textContent = formatTitle(related[idx].id);
prevBtn.disabled = idx <= 0;
nextBtn.disabled = idx >= related.length - 1;
} else {
relLabel.textContent = '—';
prevBtn.disabled = true;
nextBtn.disabled = true;
}
const body = detailContent.querySelector('.detail-body');
body.innerHTML = '';
if (node.type === 'imagen' && node.image_url) {
const img = document.createElement('img');
img.src = node.image_url;
img.className = 'detail-img';
body.appendChild(img);
}
const text = document.createElement('span');
text.textContent = node.content || node.texto || node.descripcion || 'Sin contenido disponible.';
body.appendChild(text);
if (related.length > 0) {
const conexBtn = document.createElement('button');
conexBtn.id = 'verConexionesBtn';
conexBtn.textContent = '⬡ Ver solo conexiones de este nodo';
conexBtn.addEventListener('click', () => showEgoGraph(node));
body.appendChild(conexBtn);
}
split.classList.add('show-detail');
setTimeout(() => { graph.width(elem.clientWidth); graph.height(elem.clientHeight); }, 350);
}
function showEgoGraph(node) {
const nid = node.id;
const relIds = new Set();
for (const lk of lastGraphData.links) {
const s = typeof lk.source === 'object' ? lk.source.id : lk.source;
const t = typeof lk.target === 'object' ? lk.target.id : lk.target;
if (s === nid) relIds.add(t);
else if (t === nid) relIds.add(s);
}
const egoNodes = lastGraphData.nodes.filter(n => n.id === nid || relIds.has(n.id));
const egoIds = new Set(egoNodes.map(n => n.id));
const egoLinks = lastGraphData.links.filter(lk => {
const s = typeof lk.source === 'object' ? lk.source.id : lk.source;
const t = typeof lk.target === 'object' ? lk.target.id : lk.target;
return egoIds.has(s) && egoIds.has(t);
});
fullGraphData = lastGraphData;
graph.graphData({ nodes: egoNodes, links: egoLinks });
centerGraph();
document.getElementById('volverGrafoBtn').classList.add('visible');
}
function restoreFullGraph() {
if (fullGraphData) {
lastGraphData = fullGraphData;
fullGraphData = null;
graph.graphData({ nodes: lastGraphData.nodes, links: lastGraphData.links });
centerGraph();
document.getElementById('volverGrafoBtn').classList.remove('visible');
}
}
function showNodeDetail(node) {
currentNode = node;
currentRelatedNodes = getRelated(node);
currentRelatedIdx = 0;
renderDetailPanel(node, currentRelatedNodes, currentRelatedIdx);
}
document.getElementById('prevRelation').addEventListener('click', () => {
if (currentRelatedIdx > 0) {
currentRelatedIdx--;
renderDetailPanel(currentNode, currentRelatedNodes, currentRelatedIdx);
}
});
document.getElementById('nextRelation').addEventListener('click', () => {
if (currentRelatedIdx < currentRelatedNodes.length - 1) {
currentRelatedIdx++;
renderDetailPanel(currentNode, currentRelatedNodes, currentRelatedIdx);
}
});
document.getElementById('closeDetail').addEventListener('click', () => {
const split = document.querySelector('main.split-screen');
if (split) split.classList.remove('show-detail');
restoreFullGraph();
setTimeout(() => { graph.width(elem.clientWidth); graph.height(elem.clientHeight); }, 350);
});
document.getElementById('volverGrafoBtn').addEventListener('click', () => {
restoreFullGraph();
});
// --- Data fetch ---
async function getData(paramsObj = {}) {
try {
let url = '/api/data';
const params = new URLSearchParams();
params.append('tema', 'guerra global');
for (const key in paramsObj) {
if (paramsObj[key] !== undefined && paramsObj[key] !== '') {
params.append(key, paramsObj[key]);
}
}
url += `?${params.toString()}`;
console.log('Fetch URL:', url);
const response = await fetch(url);
if (!response.ok) throw new Error(response.statusText);
const data = await response.json();
const nodeIds = new Set(data.nodes.map(n => n.id));
data.links = data.links.filter(lk => nodeIds.has(lk.source) && nodeIds.has(lk.target));
return data;
} catch (error) {
console.error('Error al obtener datos:', error);
return null;
}
}
async function fetchAndRender() {
const paramsObj = {
subtematica: document.getElementById('param2').value,
palabraClave: document.getElementById('param1').value,
fechaInicio: document.getElementById('fecha_inicio').value,
fechaFin: document.getElementById('fecha_fin').value,
nodos: document.getElementById('nodos').value,
complejidad: document.getElementById('complejidad').value,
};
const graphData = await getData(paramsObj);
if (!graphData) return;
lastGraphData = graphData;
graph.graphData({ nodes: graphData.nodes, links: graphData.links });
centerGraph();
}
form.addEventListener('submit', event => { event.preventDefault(); fetchAndRender(); });
fetchAndRender();
});

View file

@ -1,227 +0,0 @@
// output_int_sec.js
import ForceGraph3D from 'https://esm.sh/3d-force-graph?external=three';
import * as THREE from 'three';
document.addEventListener('DOMContentLoaded', () => {
const elem = document.getElementById('intSecContainer');
const form = document.getElementById('paramForm');
let lastGraphData = { nodes: [], links: [] };
let fullGraphData = null;
let currentRelatedNodes = [];
let currentRelatedIdx = 0;
let currentNode = null;
const textureCache = {};
function getTexture(url) {
if (!textureCache[url]) textureCache[url] = new THREE.TextureLoader().load(url);
return textureCache[url];
}
const graph = ForceGraph3D()(elem)
.backgroundColor('#000000')
.nodeLabel(node => node.type === 'imagen' ? (node.label || node.id) : node.id)
.nodeAutoColorBy('group')
.nodeVal(node => node.type === 'imagen' ? 20 : 2)
.linkColor(() => 'blue')
.onNodeClick(node => showNodeDetail(node))
.onNodeHover(node => { elem.style.cursor = node ? 'pointer' : null; })
.nodeThreeObject(node => {
if (node.type !== 'imagen' || !node.image_url) return null;
const texture = getTexture(node.image_url);
texture.colorSpace = THREE.SRGBColorSpace;
const material = new THREE.SpriteMaterial({ map: texture, depthWrite: false });
const sprite = new THREE.Sprite(material);
sprite.scale.set(160, 104, 1);
return sprite;
})
.nodeThreeObjectExtend(false)
.forceEngine('d3');
graph.d3Force('charge').strength(-150);
graph.d3Force('link').distance(70).strength(0.3);
graph.d3Force('center').strength(0.05);
function centerGraph() {
setTimeout(() => {
graph.zoomToFit(400, Math.min(elem.clientWidth, elem.clientHeight) * 0.1);
}, 500);
}
window.addEventListener('resize', () => {
graph.width(elem.clientWidth);
graph.height(elem.clientHeight);
centerGraph();
});
function getAuthor(node) { return node.autor || node.fuente || node.source || ''; }
function formatDate(fecha) {
if (!fecha) return '';
try { return new Date(fecha).toLocaleDateString('es-ES'); } catch { return String(fecha); }
}
function formatTitle(id) { return String(id).replace(/_/g, ' '); }
function getRelated(node) {
const nid = node.id;
const relIds = new Set();
for (const lk of lastGraphData.links) {
const s = typeof lk.source === 'object' ? lk.source.id : lk.source;
const t = typeof lk.target === 'object' ? lk.target.id : lk.target;
if (s === nid) relIds.add(t);
else if (t === nid) relIds.add(s);
}
return lastGraphData.nodes.filter(n => relIds.has(n.id));
}
function renderDetailPanel(node, related, idx) {
const detailContent = document.getElementById('detailContent');
const split = document.querySelector('main.split-screen');
if (!detailContent || !split) return;
detailContent.querySelector('.detail-author').textContent = getAuthor(node);
detailContent.querySelector('.detail-date').textContent = formatDate(node.fecha || node.date);
detailContent.querySelector('.detail-title').textContent = formatTitle(node.id);
const relCount = detailContent.querySelector('.relations-count');
const relLabel = document.getElementById('relationLabel');
const prevBtn = document.getElementById('prevRelation');
const nextBtn = document.getElementById('nextRelation');
relCount.textContent = `${related.length} relación${related.length !== 1 ? 'es' : ''}`;
if (related.length > 0) {
relLabel.textContent = formatTitle(related[idx].id);
prevBtn.disabled = idx <= 0;
nextBtn.disabled = idx >= related.length - 1;
} else {
relLabel.textContent = '—';
prevBtn.disabled = true;
nextBtn.disabled = true;
}
const body = detailContent.querySelector('.detail-body');
body.innerHTML = '';
if (node.type === 'imagen' && node.image_url) {
const img = document.createElement('img');
img.src = node.image_url;
img.className = 'detail-img';
body.appendChild(img);
}
const text = document.createElement('span');
text.textContent = node.content || node.texto || node.descripcion || 'Sin contenido disponible.';
body.appendChild(text);
if (related.length > 0) {
const conexBtn = document.createElement('button');
conexBtn.id = 'verConexionesBtn';
conexBtn.textContent = '⬡ Ver solo conexiones de este nodo';
conexBtn.addEventListener('click', () => showEgoGraph(node));
body.appendChild(conexBtn);
}
split.classList.add('show-detail');
setTimeout(() => { graph.width(elem.clientWidth); graph.height(elem.clientHeight); }, 350);
}
function showEgoGraph(node) {
const nid = node.id;
const relIds = new Set();
for (const lk of lastGraphData.links) {
const s = typeof lk.source === 'object' ? lk.source.id : lk.source;
const t = typeof lk.target === 'object' ? lk.target.id : lk.target;
if (s === nid) relIds.add(t);
else if (t === nid) relIds.add(s);
}
const egoNodes = lastGraphData.nodes.filter(n => n.id === nid || relIds.has(n.id));
const egoIds = new Set(egoNodes.map(n => n.id));
const egoLinks = lastGraphData.links.filter(lk => {
const s = typeof lk.source === 'object' ? lk.source.id : lk.source;
const t = typeof lk.target === 'object' ? lk.target.id : lk.target;
return egoIds.has(s) && egoIds.has(t);
});
fullGraphData = lastGraphData;
graph.graphData({ nodes: egoNodes, links: egoLinks });
centerGraph();
document.getElementById('volverGrafoBtn').classList.add('visible');
}
function restoreFullGraph() {
if (fullGraphData) {
lastGraphData = fullGraphData;
fullGraphData = null;
graph.graphData({ nodes: lastGraphData.nodes, links: lastGraphData.links });
centerGraph();
document.getElementById('volverGrafoBtn').classList.remove('visible');
}
}
function showNodeDetail(node) {
currentNode = node;
currentRelatedNodes = getRelated(node);
currentRelatedIdx = 0;
renderDetailPanel(node, currentRelatedNodes, currentRelatedIdx);
}
document.getElementById('prevRelation').addEventListener('click', () => {
if (currentRelatedIdx > 0) {
currentRelatedIdx--;
renderDetailPanel(currentNode, currentRelatedNodes, currentRelatedIdx);
}
});
document.getElementById('nextRelation').addEventListener('click', () => {
if (currentRelatedIdx < currentRelatedNodes.length - 1) {
currentRelatedIdx++;
renderDetailPanel(currentNode, currentRelatedNodes, currentRelatedIdx);
}
});
document.getElementById('closeDetail').addEventListener('click', () => {
const split = document.querySelector('main.split-screen');
if (split) split.classList.remove('show-detail');
restoreFullGraph();
setTimeout(() => { graph.width(elem.clientWidth); graph.height(elem.clientHeight); }, 350);
});
document.getElementById('volverGrafoBtn').addEventListener('click', () => {
restoreFullGraph();
});
async function getData(paramsObj = {}) {
try {
let url = '/api/data';
const params = new URLSearchParams();
params.append('tema', 'inteligencia y seguridad');
for (const key in paramsObj) {
if (paramsObj[key] !== undefined && paramsObj[key] !== '') {
params.append(key, paramsObj[key]);
}
}
url += `?${params.toString()}`;
console.log('Fetch URL:', url);
const response = await fetch(url);
if (!response.ok) throw new Error(response.statusText);
const data = await response.json();
const nodeIds = new Set(data.nodes.map(n => n.id));
data.links = data.links.filter(lk => nodeIds.has(lk.source) && nodeIds.has(lk.target));
return data;
} catch (error) {
console.error('Error al obtener datos:', error);
return null;
}
}
async function fetchAndRender() {
const paramsObj = {
subtematica: document.getElementById('param2').value,
palabraClave: document.getElementById('param1').value,
fechaInicio: document.getElementById('fecha_inicio').value,
fechaFin: document.getElementById('fecha_fin').value,
nodos: document.getElementById('nodos').value,
complejidad: document.getElementById('complejidad').value,
};
const graphData = await getData(paramsObj);
if (!graphData) return;
lastGraphData = graphData;
graph.graphData({ nodes: graphData.nodes, links: graphData.links });
centerGraph();
}
form.addEventListener('submit', event => { event.preventDefault(); fetchAndRender(); });
fetchAndRender();
});

View file

@ -1,122 +0,0 @@
// output_popl_up.js
// Obtener el contenedor del gráfico
const elem = document.getElementById('poplUpContainer');
// Inicializar el gráfico
const graph = ForceGraph3D()(elem)
.backgroundColor('#000000')
.nodeLabel('id')
.nodeAutoColorBy('group')
.nodeVal(5)
.linkColor(() => 'green')
.onNodeClick(node => showNodeContent(node.content))
.onNodeHover(node => {
elem.style.cursor = node ? 'pointer' : null;
})
.forceEngine('d3')
.d3Force('charge', d3.forceManyBody().strength(-10))
.d3Force('link', d3.forceLink().distance(30).strength(1));
// Función para obtener datos del servidor
async function getData(paramsObj = {}) {
try {
let url = '/api/data';
const params = new URLSearchParams();
// Fijar el tema principal
params.append('tema', 'movimientos populares y levantamientos');
// Agregar otros parámetros si se han definido
for (const key in paramsObj) {
if (paramsObj[key]) {
params.append(key, paramsObj[key]);
}
}
url += `?${params.toString()}`;
const response = await fetch(url);
const data = await response.json();
console.log('📦 Datos recibidos:', data);
// Validar y limpiar links
const nodeIds = new Set(data.nodes.map(node => node.id));
data.links = data.links.filter(link => {
const valid = nodeIds.has(link.source) && nodeIds.has(link.target);
if (!valid) {
console.log(`❌ Enlace inválido eliminado: ${link.source} -> ${link.target}`);
}
return valid;
});
return data;
} catch (error) {
console.error('⚠️ Error al obtener datos:', error);
return { nodes: [], links: [] };
}
}
// Mostrar contenido del nodo en consola (puedes ampliar esta función)
function showNodeContent(content) {
console.log('🧠 Contenido del nodo:', content);
}
// Centrar el gráfico tras dibujarlo
function centerGraph() {
setTimeout(() => {
const width = elem.clientWidth;
const height = elem.clientHeight;
const padding = Math.min(width, height) * 0.1;
graph.zoomToFit(400, padding);
}, 500);
}
// Redibujar al cambiar tamaño ventana
window.addEventListener('resize', () => {
graph.width(elem.clientWidth);
graph.height(elem.clientHeight);
centerGraph();
});
// Manejar el formulario
document.getElementById('paramForm').addEventListener('submit', function(event) {
event.preventDefault();
const subtematica = document.getElementById('param2').value;
const palabraClave = document.getElementById('param1').value;
const fechaInicio = document.getElementById('fecha_inicio').value;
const fechaFin = document.getElementById('fecha_fin').value;
const nodos = document.getElementById('nodos').value;
const complejidad = document.getElementById('complejidad').value;
const paramsObj = {
subtematica,
palabraClave,
fechaInicio,
fechaFin,
nodos,
complejidad,
};
getData(paramsObj).then(graphData => {
if (graphData) {
console.log("✅ Redibujando con nuevos datos...");
graph.graphData(graphData);
centerGraph();
}
});
});
// Obtener datos iniciales
getData().then(graphData => {
if (graphData && graphData.nodes && graphData.nodes.length > 0) {
console.log(`✅ Se recibieron ${graphData.nodes.length} nodos.`);
graph.graphData(graphData);
centerGraph();
} else {
console.warn("⚠️ No se recibieron nodos para mostrar.");
console.log("🔍 Respuesta completa:", graphData);
}
});

View file

@ -1,227 +0,0 @@
// output_popl_up_pruebas.js
import ForceGraph3D from 'https://esm.sh/3d-force-graph?external=three';
import * as THREE from 'three';
document.addEventListener('DOMContentLoaded', () => {
const elem = document.getElementById('poplUpContainer');
const form = document.getElementById('paramForm');
let lastGraphData = { nodes: [], links: [] };
let fullGraphData = null;
let currentRelatedNodes = [];
let currentRelatedIdx = 0;
let currentNode = null;
const textureCache = {};
function getTexture(url) {
if (!textureCache[url]) textureCache[url] = new THREE.TextureLoader().load(url);
return textureCache[url];
}
const graph = ForceGraph3D()(elem)
.backgroundColor('#000000')
.nodeLabel(node => node.type === 'imagen' ? (node.label || node.id) : node.id)
.nodeAutoColorBy('group')
.nodeVal(node => node.type === 'imagen' ? 20 : 2)
.linkColor(() => 'orange')
.onNodeClick(node => showNodeDetail(node))
.onNodeHover(node => { elem.style.cursor = node ? 'pointer' : null; })
.nodeThreeObject(node => {
if (node.type !== 'imagen' || !node.image_url) return null;
const texture = getTexture(node.image_url);
texture.colorSpace = THREE.SRGBColorSpace;
const material = new THREE.SpriteMaterial({ map: texture, depthWrite: false });
const sprite = new THREE.Sprite(material);
sprite.scale.set(160, 104, 1);
return sprite;
})
.nodeThreeObjectExtend(false)
.forceEngine('d3');
graph.d3Force('charge').strength(-150);
graph.d3Force('link').distance(70).strength(0.3);
graph.d3Force('center').strength(0.05);
function centerGraph() {
setTimeout(() => {
graph.zoomToFit(400, Math.min(elem.clientWidth, elem.clientHeight) * 0.1);
}, 500);
}
window.addEventListener('resize', () => {
graph.width(elem.clientWidth);
graph.height(elem.clientHeight);
centerGraph();
});
function getAuthor(node) { return node.autor || node.fuente || node.source || ''; }
function formatDate(fecha) {
if (!fecha) return '';
try { return new Date(fecha).toLocaleDateString('es-ES'); } catch { return String(fecha); }
}
function formatTitle(id) { return String(id).replace(/_/g, ' '); }
function getRelated(node) {
const nid = node.id;
const relIds = new Set();
for (const lk of lastGraphData.links) {
const s = typeof lk.source === 'object' ? lk.source.id : lk.source;
const t = typeof lk.target === 'object' ? lk.target.id : lk.target;
if (s === nid) relIds.add(t);
else if (t === nid) relIds.add(s);
}
return lastGraphData.nodes.filter(n => relIds.has(n.id));
}
function renderDetailPanel(node, related, idx) {
const detailContent = document.getElementById('detailContent');
const split = document.querySelector('main.split-screen');
if (!detailContent || !split) return;
detailContent.querySelector('.detail-author').textContent = getAuthor(node);
detailContent.querySelector('.detail-date').textContent = formatDate(node.fecha || node.date);
detailContent.querySelector('.detail-title').textContent = formatTitle(node.id);
const relCount = detailContent.querySelector('.relations-count');
const relLabel = document.getElementById('relationLabel');
const prevBtn = document.getElementById('prevRelation');
const nextBtn = document.getElementById('nextRelation');
relCount.textContent = `${related.length} relación${related.length !== 1 ? 'es' : ''}`;
if (related.length > 0) {
relLabel.textContent = formatTitle(related[idx].id);
prevBtn.disabled = idx <= 0;
nextBtn.disabled = idx >= related.length - 1;
} else {
relLabel.textContent = '—';
prevBtn.disabled = true;
nextBtn.disabled = true;
}
const body = detailContent.querySelector('.detail-body');
body.innerHTML = '';
if (node.type === 'imagen' && node.image_url) {
const img = document.createElement('img');
img.src = node.image_url;
img.className = 'detail-img';
body.appendChild(img);
}
const text = document.createElement('span');
text.textContent = node.content || node.texto || node.descripcion || 'Sin contenido disponible.';
body.appendChild(text);
if (related.length > 0) {
const conexBtn = document.createElement('button');
conexBtn.id = 'verConexionesBtn';
conexBtn.textContent = '⬡ Ver solo conexiones de este nodo';
conexBtn.addEventListener('click', () => showEgoGraph(node));
body.appendChild(conexBtn);
}
split.classList.add('show-detail');
setTimeout(() => { graph.width(elem.clientWidth); graph.height(elem.clientHeight); }, 350);
}
function showEgoGraph(node) {
const nid = node.id;
const relIds = new Set();
for (const lk of lastGraphData.links) {
const s = typeof lk.source === 'object' ? lk.source.id : lk.source;
const t = typeof lk.target === 'object' ? lk.target.id : lk.target;
if (s === nid) relIds.add(t);
else if (t === nid) relIds.add(s);
}
const egoNodes = lastGraphData.nodes.filter(n => n.id === nid || relIds.has(n.id));
const egoIds = new Set(egoNodes.map(n => n.id));
const egoLinks = lastGraphData.links.filter(lk => {
const s = typeof lk.source === 'object' ? lk.source.id : lk.source;
const t = typeof lk.target === 'object' ? lk.target.id : lk.target;
return egoIds.has(s) && egoIds.has(t);
});
fullGraphData = lastGraphData;
graph.graphData({ nodes: egoNodes, links: egoLinks });
centerGraph();
document.getElementById('volverGrafoBtn').classList.add('visible');
}
function restoreFullGraph() {
if (fullGraphData) {
lastGraphData = fullGraphData;
fullGraphData = null;
graph.graphData({ nodes: lastGraphData.nodes, links: lastGraphData.links });
centerGraph();
document.getElementById('volverGrafoBtn').classList.remove('visible');
}
}
function showNodeDetail(node) {
currentNode = node;
currentRelatedNodes = getRelated(node);
currentRelatedIdx = 0;
renderDetailPanel(node, currentRelatedNodes, currentRelatedIdx);
}
document.getElementById('prevRelation').addEventListener('click', () => {
if (currentRelatedIdx > 0) {
currentRelatedIdx--;
renderDetailPanel(currentNode, currentRelatedNodes, currentRelatedIdx);
}
});
document.getElementById('nextRelation').addEventListener('click', () => {
if (currentRelatedIdx < currentRelatedNodes.length - 1) {
currentRelatedIdx++;
renderDetailPanel(currentNode, currentRelatedNodes, currentRelatedIdx);
}
});
document.getElementById('closeDetail').addEventListener('click', () => {
const split = document.querySelector('main.split-screen');
if (split) split.classList.remove('show-detail');
restoreFullGraph();
setTimeout(() => { graph.width(elem.clientWidth); graph.height(elem.clientHeight); }, 350);
});
document.getElementById('volverGrafoBtn').addEventListener('click', () => {
restoreFullGraph();
});
async function getData(paramsObj = {}) {
try {
let url = '/api/data';
const params = new URLSearchParams();
params.append('tema', 'demografía y sociedad');
for (const key in paramsObj) {
if (paramsObj[key] !== undefined && paramsObj[key] !== '') {
params.append(key, paramsObj[key]);
}
}
url += `?${params.toString()}`;
console.log('Fetch URL:', url);
const response = await fetch(url);
if (!response.ok) throw new Error(response.statusText);
const data = await response.json();
const nodeIds = new Set(data.nodes.map(n => n.id));
data.links = data.links.filter(lk => nodeIds.has(lk.source) && nodeIds.has(lk.target));
return data;
} catch (error) {
console.error('Error al obtener datos:', error);
return null;
}
}
async function fetchAndRender() {
const paramsObj = {
subtematica: document.getElementById('param2').value,
palabraClave: document.getElementById('param1').value,
fechaInicio: document.getElementById('fecha_inicio').value,
fechaFin: document.getElementById('fecha_fin').value,
nodos: document.getElementById('nodos').value,
complejidad: document.getElementById('complejidad').value,
};
const graphData = await getData(paramsObj);
if (!graphData) return;
lastGraphData = graphData;
graph.graphData({ nodes: graphData.nodes, links: graphData.links });
centerGraph();
}
form.addEventListener('submit', event => { event.preventDefault(); fetchAndRender(); });
fetchAndRender();
});

View file

@ -1,219 +0,0 @@
@font-face {
font-family: "Retrolift";
src: url("/home/pancho/PROGRAMACION/FLUJOS/retrolift.woff2") format("woff2"),
url("/home/pancho/PROGRAMACION/FLUJOS/retrolift.woff") format("woff");
font-weight: normal;
font-style: normal;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Fira Code';
text-shadow: 10px 10px 20px rgba(0, 255, 76, 0.3);
}
body {
font-family: 'Fira Code', monospace;
background: #000000;
color: #000000;
}
header {
display: flex;
justify-content: center;
align-items: center;
height: 70px;
background-color: #000000;
color: #ffffff;
box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
}
.logo {
font-family: "Retrolift", sans-serif;
font-size: 4em;
font-weight: bold;
letter-spacing: 4px;
text-shadow: 6px 6px 6px #73ff00;
margin-bottom: 10px;
}
.popl-up:hover .logo { text-shadow: 2px 2px 8px #00008b; }
nav {
display: flex;
justify-content: center;
background-color: #000000;
color: #ff1a1a;
padding: 10px 0;
box-shadow: 0 10px 10px rgba(0, 0, 0, 0.1);
margin-top: 40px;
margin-bottom: 5px;
}
.nav-links {
list-style: none;
display: flex;
gap: 6em;
}
.nav-links a {
color: #000000;
text-decoration: none;
font-size: 1em;
font-weight: bold;
transition: color 0.3s ease, transform 0.3s ease, box-shadow 0.3s ease;
padding: 20px 40px;
box-shadow: 0 0 0px rgba(28, 103, 241, 0);
position: relative;
border: none;
transition: .4s ease-in;
z-index: 1;
width: 40vw;
height: 20vh;
border: 3vw;
align-items: center;
border: 3px solid;
}
.nav-links a:hover {
transform: scale(1.05);
box-shadow: 0 0 6px rgba(0,0,0,0.3);
border: 3px solid black;
}
.popl-up:hover { color: #0066ff; }
.popl-up { color: #FF851B; background-color: orange; }
.background {
display: flex;
height: 100vh;
width: 99%;
overflow-x: scroll;
}
.background a {
display: block;
width: 20%;
height: 90vh;
transition: transform 1.5s ease;
}
.background img {
width: 20%;
height: 90vh;
object-fit: cover;
transition: transform 1.5s ease;
}
.background img:hover {
transform: scale(1.1);
}
#sidebar {
position: fixed;
left: 0;
top: 0;
width: 250px;
height: 100vh;
background-image: url("/images/flujos7.jpg");
background-size: cover;
color: #39ff14;
padding: 30px;
box-shadow: 2px 0 10px rgba(0, 0, 0, 0.1);
transform: translateX(-220px);
transition: transform 0.3s ease-out;
overflow: auto;
font-size: 18px;
z-index: 3;
text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;
}
#sidebar:hover {
transform: translateX(0);
}
#sidebar h2 {
color: #39ff14;
font-size: 1.2em;
font-weight: bold;
margin-bottom: 15px;
text-shadow: -1px 0 black, 0 3px black, 3px 0 black, 0 -1px black;
}
#sidebar form {
display: flex;
flex-direction: column;
gap: 10px;
font-size: 20px;
}
#sidebar label {
color: #39ff14;
font-size: 0.9em;
font-weight: bold;
text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;
}
#sidebar input {
padding: 10px;
border: 2px solid #39ff14;
background: black;
color: #39ff14;
border-radius: 5px;
box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.2);
transition: box-shadow 0.3s ease;
}
#sidebar input:hover {
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.3);
}
#sidebar input[type="submit"] {
color: #39ff14;
background: #ff6600;
cursor: pointer;
}
#sidebar input[type="submit"]:hover {
background: #ff6600;
}
footer {
width: 100%;
background-color: #000000;
color: #39ff14;
text-align: center;
padding: 10px 0;
position: fixed;
bottom: 0;
font-family: 'Courier New', Courier, monospace;
z-index: 6;
}
footer a {
color: #39ff14;
text-decoration: none;
transition: color 0.3s ease;
}
footer a:hover {
color: #2ECC40;
}
footer p {
margin: 0;
}
.iframe-container {
width: calc(100% - 250px);
height: 100vh;
background: #000000;
margin: 0 auto;
border: none;
z-index: 1;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
position: absolute;
left: 250px;
}

View file

@ -1,165 +0,0 @@
+<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Demografía y Sociedad</title>
<link rel="stylesheet" href="popl-up.css">
<link rel="stylesheet" href="sub-nav.css">
<!-- Fuentes -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;700&display=swap" rel="stylesheet">
<!-- Librerías necesarias -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js"></script>
<script type="importmap">
{ "imports": { "three": "https://esm.sh/three@0.179.0", "three/": "https://esm.sh/three@0.179.0/" } }
</script>
</head>
<body>
<!-- Navegación -->
<nav class="top-nav">
<div class="section-buttons">
<div class="section-item">
<a href="glob-war.html" class="section-btn glob-war-btn">GLOB-WAR</a>
</div>
<div class="section-item">
<a href="int-sec.html" class="section-btn int-sec-btn">INT-SEC</a>
</div>
<div class="section-item">
<a href="climate.html" class="section-btn climate-btn">CLIMATE</a>
</div>
<div class="section-item">
<a href="eco-corp.html" class="section-btn eco-corp-btn">ECO-CORP</a>
</div>
<div class="section-item current">
<a href="popl-up.html" class="section-btn popl-up-btn">POPL-UP <span class="dropdown-arrow"></span></a>
<div class="section-dropdown">
<a href="#" onclick="setSubtema('sobrepoblación');return false;">Sobrepoblación</a>
<a href="#" onclick="setSubtema('enfermedades');return false;">COVID / Enfermedades</a>
<a href="#" onclick="setSubtema('migraciones');return false;">Migraciones</a>
<a href="#" onclick="setSubtema('urbanización');return false;">Urbanización</a>
<a href="#" onclick="setSubtema('distribucion_edad');return false;">Despoblación Rural</a>
</div>
</div>
</div>
</nav>
<script>
function setSubtema(val) {
var sel = document.getElementById('param2');
if (sel) { sel.value = val; }
var form = document.getElementById('paramForm');
if (form) form.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));
}
document.addEventListener('DOMContentLoaded', function() {
/* ── Dropdown touch (móvil) ── */
var curr = document.querySelector('.section-item.current');
if (curr) {
curr.querySelector('.section-btn').addEventListener('touchend', function(e) {
e.preventDefault();
curr.classList.toggle('open');
});
document.addEventListener('touchend', function(e) {
if (!curr.contains(e.target)) curr.classList.remove('open');
});
}
/* ── Sidebar: botón toggle visible en móvil ── */
var toggle = document.getElementById('sidebarToggle');
var sidebar = document.getElementById('sidebar');
if (toggle && sidebar) {
toggle.style.display = 'block';
toggle.addEventListener('click', function() {
sidebar.classList.toggle('active');
});
}
});
</script>
<!-- Contenedor principal -->
<main class="split-screen">
<div id="graphPanel" style="position:relative;">
<button id="volverGrafoBtn">← Volver al grafo completo</button>
<div id="poplUpContainer" style="position: absolute; width: 100%; height: 100%; z-index: 0;"></div>
<!-- Fondo animado -->
<div class="background">
<img src="/images/flujos3.jpg">
<img src="/images/flujos3.jpg">
<img src="/images/flujos3.jpg">
<img src="/images/flujos3.jpg">
<img src="/images/flujos3.jpg">
</div>
<script>
setTimeout(() => {
const fondo = document.querySelector('.background');
fondo.classList.add('fade-out');
fondo.style.pointerEvents = 'none';
}, 1000);
</script>
</div>
<div id="detailPanel">
<button id="closeDetail">✕ cerrar</button>
<div id="detailContent">
<div class="detail-meta">
<span class="detail-author"></span>
<span class="detail-date"></span>
</div>
<h2 class="detail-title"></h2>
<div class="detail-relations">
<span class="relations-count"></span>
<div class="relations-nav">
<button id="prevRelation" disabled>&#8592; ant</button>
<span id="relationLabel"></span>
<button id="nextRelation" disabled>sig &#8594;</button>
</div>
</div>
<div class="detail-body"></div>
</div>
</div>
</main>
<!-- Barra lateral de filtros -->
<div id="sidebar">
<h2>Parámetros</h2>
<form id="paramForm">
<label for="fecha_inicio">Fecha de inicio:</label>
<input type="date" id="fecha_inicio" name="fecha_inicio">
<label for="fecha_fin">Fecha de fin:</label>
<input type="date" id="fecha_fin" name="fecha_fin">
<label for="nodos">Nodos:</label>
<input type="number" id="nodos" name="nodos" value="100" min="5" max="500">
<label for="complejidad">% similitud: <span id="complejidadVal" class="sim-val">8</span></label>
<input type="range" id="complejidad" name="complejidad" min="1" max="25" value="8"
oninput="document.getElementById('complejidadVal').textContent = this.value">
<label for="param1">Palabra clave:</label>
<input type="text" id="param1" name="param1" placeholder="ej: migración, pandemia...">
<label for="param2">Subtematica:</label>
<select id="param2" name="param2">
<option value="">— Todas —</option>
<option value="enfermedades">enfermedades</option>
<option value="urbanización">urbanización</option>
<option value="migraciones">migraciones</option>
<option value="sobrepoblación">sobrepoblación</option>
</select>
<input type="submit" value="Aplicar">
</form>
</div>
<!-- Botón para colapsar la barra -->
<button id="sidebarToggle">Toggle Sidebar</button>
<!-- Script principal -->
<script type="module" src="output_popl_up_pruebas.js"></script>
</body>
</html>

View file

@ -1,72 +0,0 @@
:root {
--cube-size: 70px; /* Tamaño reducido de los cubos */
--line-color: #333;
--hover-color: #2ecc71;
}
.graph-container {
position: relative;
width: 100vw;
height: 100vh;
background-color: #000;
border: 1px solid #ddd;
margin: 20px auto;
perspective: 1000px;
}
.cube-container {
position: absolute;
width: var(--cube-size);
height: var(--cube-size);
transform-style: preserve-3d;
transition: transform 1s;
}
.cube-container:hover {
transform: rotateX(360deg) rotateY(360deg);
}
.cube {
position: absolute;
width: var(--cube-size);
height: var(--cube-size);
transform-style: preserve-3d;
}
.face {
position: absolute;
width: var(--cube-size);
height: var(--cube-size);
background-color: var(--hover-color);
border: 1px solid #000;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.7rem;
color: white;
}
/* Posiciones de las caras del cubo */
.front { transform: translateZ(calc(var(--cube-size) / 2)); }
.back { transform: rotateY(180deg) translateZ(calc(var(--cube-size) / 2)); }
.left { transform: rotateY(-90deg) translateZ(calc(var(--cube-size) / 2)); }
.right { transform: rotateY(90deg) translateZ(calc(var(--cube-size) / 2)); }
.top { transform: rotateX(90deg) translateZ(calc(var(--cube-size) / 2)); }
.bottom { transform: rotateX(-90deg) translateZ(calc(var(--cube-size) / 2)); }
.lines {
position: absolute;
top: 0;
left: 0;
z-index: -1;
}
.line-path {
stroke: var(--line-color);
stroke-width: 2;
transition: stroke 0.3s;
}
.line-path:hover {
stroke: #e74c3c;
}

View file

@ -1,83 +0,0 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Noticias de Guerras y Conflictos Políticos - Disposición Aleatoria</title>
<link rel="stylesheet" type="text/css" href="script_eco-corp.css">
</head>
<body>
<h1>Noticias de Guerras y Conflictos Políticos - Últimos 10 años</h1>
<div class="graph-container" id="graph-container">
<!-- Los cubos serán añadidos dinámicamente con JavaScript -->
<svg class="lines" xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" id="svg-lines">
<!-- Las flechas también serán generadas dinámicamente -->
</svg>
</div>
<script>
const numCubes = 5; // Número de cubos
const graphContainer = document.getElementById('graph-container');
const svgLines = document.getElementById('svg-lines');
let cubePositions = [];
// Función para generar una posición aleatoria dentro del contenedor
function getRandomPosition(maxWidth, maxHeight) {
return {
x: Math.floor(Math.random() * (maxWidth - 100)),
y: Math.floor(Math.random() * (maxHeight - 100))
};
}
// Función para generar cubos aleatoriamente
function generateCubes(num) {
for (let i = 0; i < num; i++) {
const position = getRandomPosition(window.innerWidth, window.innerHeight);
const cubeContainer = document.createElement('div');
cubeContainer.classList.add('cube-container');
cubeContainer.style.top = position.y + 'px';
cubeContainer.style.left = position.x + 'px';
const cube = document.createElement('div');
cube.className = 'cube';
[['front', `País ${i+1}`], ['back', `Detalle ${i+1}`],
['left', `Año ${2010 + i}`], ['right', `Muertos ${(i+1)*1000}`],
['top', 'ONU'], ['bottom', 'Fuente']].forEach(([cls, txt]) => {
const face = document.createElement('div');
face.className = `face ${cls}`;
face.textContent = txt;
cube.appendChild(face);
});
cubeContainer.appendChild(cube);
cubePositions.push({x: position.x + 35, y: position.y + 35}); // Ajustar al centro del cubo
graphContainer.appendChild(cubeContainer);
}
}
// Función para generar las flechas que conectan los cubos
function generateLines() {
for (let i = 0; i < cubePositions.length - 1; i++) {
const x1 = cubePositions[i].x;
const y1 = cubePositions[i].y;
const x2 = cubePositions[i + 1].x;
const y2 = cubePositions[i + 1].y;
const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
line.setAttribute('x1', x1);
line.setAttribute('y1', y1);
line.setAttribute('x2', x2);
line.setAttribute('y2', y2);
line.setAttribute('stroke', '#333');
line.setAttribute('stroke-width', '2');
svgLines.appendChild(line);
}
}
// Generar cubos y flechas al cargar la página
generateCubes(numCubes);
generateLines();
</script>
</body>
</html>

View file

@ -1,702 +0,0 @@
@font-face {
font-family: "Retrolift";
src: url("/home/pancho/PROGRAMACION/FLUJOS/retrolift.woff2") format("woff2"),
url("/home/pancho/PROGRAMACION/FLUJOS/retrolift.woff") format("woff");
font-weight: normal;
font-style: normal;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Fira Code';
}
body {
font-family: 'Fira Code', monospace;
background: #000000;
color: #000000;
}
header {
position: relative;
height: 120px;
background-color: #000000;
display: flex;
justify-content: center;
align-items: center;
padding-top: 20px;
}
.title {
font-family: 'Nosifer';
color: #ffffff;
font-size: 6.5rem;
margin: 0 auto;
line-height: 1.2;
align-self: center;
}
.header-content {
display: flex;
align-items: center;
position: relative;
width: 100%;
padding: 0 14px;
}
.header-buttons {
display: flex;
align-items: center;
gap: 6px;
position: absolute;
top: 50%;
right: 14px;
transform: translateY(-50%);
}
.header-buttons--left {
right: auto;
left: 14px;
}
.stats-btn {
border-color: #39ff14;
color: #39ff14;
}
.stats-btn:hover {
background-color: #39ff14;
color: #000;
}
.small-button {
margin-left: 5px;
margin-right: 3px;
padding: 4px 8px;
font-size: 10px;
color: #ffffff;
text-decoration: none;
background-color: #000000;
border: 2px solid #ffffff;
border-radius: 20px;
transition: all 0.3s ease;
}
.small-button:hover {
background-color: #ffffff;
color: #000000;
text-shadow: none;
}
nav {
display: flex;
justify-content: center;
background-color: #000000;
color: #ff1a1a;
padding: 10px 0;
box-shadow: 0 10px 10px rgba(0, 0, 0, 0.1);
margin-top: 40px;
margin-bottom: 5px;
}
.nav-links {
list-style: none;
display: flex;
gap: 14em;
}
.nav-links a {
color: #000000;
text-decoration: none;
font-size: 1em;
font-weight: bold;
transition: color 0.3s ease, transform 0.3s ease, box-shadow 0.3s ease;
padding: 20px 40px;
box-shadow: 0 0 0px rgba(28, 103, 241, 0);
position: relative;
border: none;
transition: .4s ease-in;
z-index: 1;
width: 40vw;
height: 20vh;
border: 3vw;
align-items: center;
border: 3px solid;
}
.nav-links a:hover {
transform: scale(1.05);
box-shadow: 0 0 6px rgba(0,0,0,0.3);
box-shadow: 2vw 1vw;
border: 3px solid black;
}
.glob-war:hover { color: #39ff14; }
.int-sec:hover { color: #ff69b4; }
.climate:hover { color: #ff4500; }
.eco-corp:hover { color: #00fff2; }
.popl-up:hover { color: #0066ff; }
.glob-war {
color: #FF4136;
background-color: red;
}
.int-sec {
color: #0074D9;
background-color: darkblue;
}
.climate {
color: #2ECC40;
background-color: lightgreen;
}
.eco-corp {
color: #FFDC00;
background-color: yellow;
}
.popl-up {
color: #FF851B;
background-color: orange;
}
.background {
display: flex;
justify-content: center; /* Centrar horizontalmente */
height: 100vh;
width: 100%;
overflow-x: hidden; /* Oculta cualquier posible desplazamiento horizontal */
margin: 0 auto;
padding: 0;
}
.background a {
display: block;
flex: 1; /* Asegura que cada imagen se expanda uniformemente para ocupar todo el espacio disponible */
height: 100%;
transition: transform 1.5s ease;
}
.background img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 1.5s ease;
margin: 0; /* Elimina cualquier margen alrededor de las imágenes */
}
.background img:hover {
transform: scale(1.1);
}
#sidebar.active {
transform: translateX(0);
}
#sidebar {
position: fixed;
left: 0;
top: 0;
width: 250px;
height: 100vh;
background-image: url("/images/flujos7.jpg");
background-size: cover;
color: #39ff14;
padding: 30px;
box-shadow: 2px 0 10px rgba(0, 0, 0, 0.1);
transform: translateX(-90%);
transition: transform 0.3s ease-out;
overflow: auto;
font-size: 18px;
z-index: 3;
text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;
}
#sidebar h2 {
color: #39ff14;
font-size: 1.2em;
font-weight: bold;
margin-bottom: 15px;
text-shadow: -1px 0 black, 0 3px black, 3px 0 black, 0 -1px black;
}
#sidebar:hover {
transform: translateX(0);
}
#sidebarToggle {
position: absolute;
left: 1em;
top: 1em;
background: #007BFF;
color: #39ff14;
border: none;
padding: 10px 20px;
cursor: pointer;
border-radius: 5px;
transition: background 0.3s ease;
z-index: 2;
}
#sidebarToggle {
display: none;
}
#sidebar form {
display: flex;
flex-direction: column;
gap: 10px;
font-size: 20px;
}
#sidebar label {
color: #39ff14;
font-size: 0.9em;
font-weight: bold;
text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;
}
#sidebar input {
padding: 10px;
border: 2px solid #39ff14;
background: black;
color: #39ff14;
border-radius: 5px;
box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.2);
transition: box-shadow 0.3s ease;
}
#sidebar input:hover {
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.3);
}
#sidebar input[type="submit"] {
color: #39ff14;
background: #ff6600;
cursor: pointer;
}
#sidebar input[type="submit"]:hover {
background: #ff6600;
}
footer {
width: 100%;
background-color: #000000;
color: #39ff14;
text-align: center;
padding: 10px 0;
position: fixed;
bottom: 0;
font-family: 'Courier New', Courier, monospace;
z-index: 1;
}
footer a {
color: #39ff14;
text-decoration: none;
transition: color 0.3s ease;
}
footer a:hover {
color: #2ECC40;
}
footer p {
margin: 0;
}
#canvasContainer {
position: absolute;
width: 100%;
height: 100%;
opacity: 0.5;
pointer-events: none;
}
.button-overlay {
position: absolute;
top: 100px;
left: 0;
width: 100%;
height: calc(100% - 100px);
display: flex;
justify-content: space-around;
align-items: center;
}
.button-column {
display: flex;
flex-direction: column;
gap: 20px; /* Incrementa el espacio entre botones */
width: 13%; /* Reducido el ancho de las columnas de botones */
}
.overlay-button {
display: block;
padding: 10px 15px; /* Ajustar para reducir el tamaño del botón */
color: #ffffff;
font-weight: bold; /* Hacer el texto más grueso */
text-decoration: none;
border-radius: 30px; /* Bordes redondeados para un efecto de cilindro */
font-size: 1em;
border: 2px solid #ffffff;
background-color: black; /* Fondo negro */
transition: transform 0.3s ease, box-shadow 0.3s ease;
text-align: center;
}
.overlay-button:hover {
transform: scale(1.05);
color: #ffffff;
background-color: transparent;
box-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
}
/* Media Queries for larger screens */
@media screen and (max-width: 1920px) {
.background a {
width: 18%;
}
.button-column {
width: 18%;
}
.overlay-button {
font-size: 1.1em;
padding: 16px 20px;
}
.title {
font-size: 7rem;
}
.small-button {
font-size: 1em;
padding: 8px 14px;
}
.nav-links {
list-style: none;
display: flex;
gap: 14em;
}
}
@media screen and (max-width: 1600px) {
.background a {
width: 20%;
}
.button-column {
width: 20%;
}
.overlay-button {
font-size: 1em;
padding: 14px 18px;
}
.title {
font-size: 6.5rem;
}
.small-button {
font-size: 0.9em;
padding: 7px 13px;
}
.nav-links {
list-style: none;
display: flex;
gap: 6em;
}
}
@media screen and (max-width: 1440px) {
.background a {
width: 22%;
}
.button-column {
width: 22%;
}
.overlay-button {
font-size: 0.95em;
padding: 12px 16px;
}
.title {
font-size: 6rem;
}
.small-button {
font-size: 0.85em;
padding: 6px 12px;
}
.nav-links a {
font-size: 0.85em;
padding: 16px 30px;
}
}
@media screen and (max-width: 1280px) {
.background a {
width: 25%;
}
.button-column {
width: 25%;
}
.overlay-button {
font-size: 0.5em;
padding: 10px 14px;
}
.title {
font-size: 5.5rem;
}
.small-button {
font-size: 0.4em;
padding: 6px 11px;
}
.nav-links {
list-style: none;
display: flex;
gap: 5em;
}
}
@media screen and (max-width: 1024px) {
.background a {
width: 30%;
}
.button-column {
width: 30%;
}
.overlay-button {
font-size: 0.35em;
padding: 9px 12px;
}
.title {
font-size: 5rem;
}
.small-button {
font-size: 0.75em;
padding: 5px 10px;
}
.nav-links a {
font-size: 0.75em;
padding: 12px 20px;
}
}
/* ============================================================
MÓVIL Portrait ( 1024px)
============================================================ */
@media screen and (max-width: 1024px) and (orientation: portrait) {
header { height: auto; padding: 12px 10px; }
.title { font-size: 3.2rem; }
.header-buttons {
position: static;
transform: none;
margin-top: 6px;
flex-wrap: wrap;
justify-content: flex-start;
gap: 5px;
}
.header-buttons--left { position: static; }
.small-button {
font-size: 0.72rem;
padding: 5px 10px;
}
/* Nav: fila horizontal scrollable de botones compactos */
nav {
margin-top: 8px;
margin-bottom: 0;
padding: 6px 8px;
overflow-x: auto;
justify-content: flex-start;
}
.nav-links {
flex-wrap: nowrap;
gap: 8px;
padding: 0 2px;
}
.nav-links li { flex-shrink: 0; }
.nav-links a {
width: auto;
height: auto;
font-size: 0.78rem;
padding: 8px 14px;
border-width: 2px;
border-radius: 20px;
}
/* Layout de imágenes: 2 columnas en lugar de 5 */
.background {
flex-wrap: wrap;
height: auto;
overflow-x: hidden;
}
.background a {
width: 50%;
height: 30vw;
min-height: 120px;
}
/* Botones overlay: rejilla 2×3 */
.button-overlay {
position: static;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
padding: 14px 12px 60px;
background: rgba(0,0,0,0.75);
height: auto;
top: auto;
}
.button-column {
width: 100%;
gap: 8px;
}
.overlay-button {
font-size: 0.75rem;
padding: 8px 12px;
}
}
/* ≤ 600px portrait */
@media screen and (max-width: 600px) and (orientation: portrait) {
.title { font-size: 2.2rem; }
.small-button {
font-size: 0.65rem;
padding: 4px 8px;
}
.nav-links a {
font-size: 0.68rem;
padding: 7px 11px;
}
.background a {
width: 50%;
height: 28vw;
}
.button-overlay {
grid-template-columns: 1fr 1fr;
gap: 8px;
padding: 10px 8px 56px;
}
.overlay-button {
font-size: 0.68rem;
padding: 7px 10px;
}
}
/* ≤ 420px portrait */
@media screen and (max-width: 420px) and (orientation: portrait) {
.title { font-size: 1.8rem; }
.header-content { flex-direction: column; align-items: flex-start; gap: 6px; }
.small-button {
font-size: 0.6rem;
padding: 4px 7px;
}
.nav-links a {
font-size: 0.62rem;
padding: 6px 10px;
}
.background a {
width: 50%;
height: 26vw;
}
.button-overlay {
grid-template-columns: 1fr 1fr;
gap: 6px;
}
.overlay-button {
font-size: 0.62rem;
padding: 6px 8px;
}
}
/* ============================================================
MÓVIL Landscape (altura 500px)
============================================================ */
@media screen and (max-width: 900px) and (orientation: landscape) and (max-height: 500px) {
header { padding: 6px 10px; }
.title { font-size: 1.6rem; }
.small-button {
font-size: 0.65rem;
padding: 4px 8px;
}
nav { margin-top: 4px; padding: 4px 8px; overflow-x: auto; justify-content: flex-start; }
.nav-links { flex-wrap: nowrap; gap: 6px; }
.nav-links a {
width: auto; height: auto;
font-size: 0.65rem;
padding: 6px 10px;
border-radius: 16px;
}
.background { height: 100vh; flex-wrap: nowrap; overflow-x: auto; }
.background a { width: 20%; height: 100%; flex-shrink: 0; }
.button-overlay {
display: flex;
justify-content: space-around;
align-items: center;
top: 60px;
height: calc(100% - 60px);
}
.button-column { width: 18%; gap: 4px; }
.overlay-button {
font-size: 0.6rem;
padding: 5px 8px;
}
}
/* landscape muy pequeño (≤ 600px ancho) */
@media screen and (max-width: 600px) and (orientation: landscape) and (max-height: 400px) {
.title { font-size: 1.2rem; }
.small-button { font-size: 0.6rem; padding: 3px 6px; }
.nav-links a { font-size: 0.6rem; padding: 5px 8px; }
.button-column { width: 28%; }
.overlay-button { font-size: 0.58rem; padding: 4px 6px; }
}

View file

@ -1,278 +0,0 @@
/* ============================================================
SUB-NAV Barra de navegación compacta, estética = home
============================================================ */
/* ── Contenedor fijo ─────────────────────────────────────── */
.top-nav {
position: fixed;
top: 0;
left: 0;
width: 100%;
transform: translateZ(0); /* capa GPU propia — sobre el canvas WebGL */
z-index: 9999;
background: rgba(0, 0, 0, 0.92);
padding: 8px 0;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
box-sizing: border-box;
}
nav.top-nav {
display: block !important;
margin-top: 0 !important;
margin-bottom: 0 !important;
justify-content: unset;
box-shadow: none !important;
}
/* ── Fila centrada ───────────────────────────────────────── */
.section-buttons {
display: flex;
justify-content: center;
align-items: center;
gap: 18px;
width: 100%;
padding: 0 12px;
box-sizing: border-box;
/* Sin overflow en desktop → dropdown no queda recortado en Y */
}
/* ── Wrapper ─────────────────────────────────────────────── */
.section-item {
position: relative;
flex-shrink: 0;
}
/* ── Botón — texto NEGRO sobre fondo de sección ──────────── */
.section-btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 5px;
/* Desktop grande — mismo "peso visual" que el home */
padding: 14px 34px;
font-size: 1.05em;
font-family: 'Fira Code', monospace;
font-weight: bold;
text-decoration: none;
color: #000000; /* letra negra — legible sobre cualquier fondo */
border: 3px solid black; /* reborde negro siempre */
position: relative;
z-index: 1;
transition: color 0.35s ease-in, transform 0.3s ease, box-shadow 0.3s ease;
white-space: nowrap;
cursor: pointer;
/* mismo text-shadow del home para profundidad */
text-shadow: 1px 1px 3px rgba(0,0,0,0.4);
}
.section-btn:hover {
transform: scale(1.06);
border: 3px solid black;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.6);
}
.dropdown-arrow {
font-size: 0.75em;
line-height: 1;
transition: transform 0.2s;
}
/* ── Fondos por sección — exactos al home ────────────────── */
/* Solo background y border-color; el texto queda en #000000 */
.glob-war-btn { background-color: red; }
.int-sec-btn { background-color: darkblue; color: #aad4ff; } /* azul oscuro → letra clara */
.climate-btn { background-color: lightgreen; }
.eco-corp-btn { background-color: yellow; }
.popl-up-btn { background-color: orange; }
/* ── Hover — colores neón iguales al home ────────────────── */
.glob-war-btn:hover { color: #39ff14; }
.int-sec-btn:hover { color: #ff69b4; }
.climate-btn:hover { color: #ff4500; }
.eco-corp-btn:hover { color: #00fff2; }
.popl-up-btn:hover { color: #0066ff; }
/* ── Botón activo: borde brillante ──────────────────────── */
.section-item.current .section-btn {
box-shadow: 0 0 12px 3px rgba(0,0,0,0.5), 0 0 0 2px rgba(255,255,255,0.4);
}
.section-item.current:hover .dropdown-arrow,
.section-item.current.open .dropdown-arrow {
transform: rotate(180deg);
}
/* ── Dropdown ────────────────────────────────────────────── */
.section-dropdown {
display: none;
position: absolute;
top: calc(100% + 8px);
left: 50%;
transform: translateX(-50%) translateZ(0);
min-width: 200px;
background: rgba(4, 4, 4, 0.98);
border: 1px solid rgba(255, 255, 255, 0.15);
border-radius: 6px;
padding: 6px 0;
z-index: 99999;
box-shadow: 0 10px 32px rgba(0, 0, 0, 0.85);
}
/* Puente para no perder hover al moverse al dropdown */
.section-item.current::after {
content: '';
position: absolute;
top: 100%;
left: -10px;
right: -10px;
height: 14px;
z-index: 99998;
}
.section-item.current:hover .section-dropdown,
.section-item.current.open .section-dropdown {
display: block;
animation: dropFade 0.14s ease;
}
@keyframes dropFade {
from { opacity: 0; transform: translateX(-50%) translateY(-5px); }
to { opacity: 1; transform: translateX(-50%) translateY(0); }
}
.section-dropdown a {
display: block;
padding: 8px 18px;
font-size: 0.75em;
font-family: 'Fira Code', monospace;
color: #ccc;
text-decoration: none;
text-shadow: none;
transition: background 0.15s, color 0.15s;
white-space: nowrap;
}
.section-dropdown a:hover {
background: rgba(255, 255, 255, 0.1);
color: #fff;
}
/* ================================================================
MÓVIL Panel de detalle en la MITAD INFERIOR ( 768px)
Sustituye el "display:none" del graphPanel por layout vertical
================================================================ */
@media (max-width: 768px) {
/* Columna vertical: grafo arriba, detalle abajo */
main.split-screen.show-detail {
flex-direction: column !important;
height: 100vh !important;
}
/* Grafo ocupa la mitad superior — NO se oculta */
main.split-screen.show-detail #graphPanel {
display: block !important;
flex: none !important;
width: 100% !important;
height: 50vh !important;
min-height: 0 !important;
overflow: hidden;
}
/* Panel de detalle ocupa la mitad inferior */
main.split-screen.show-detail #detailPanel {
width: 100% !important;
max-width: 100% !important;
flex: none !important;
height: 50vh !important;
overflow-y: auto;
border-top: 2px solid rgba(57, 255, 20, 0.4);
}
/* El contenido del panel se muestra siempre cuando está abierto */
main.split-screen.show-detail #detailContent {
display: flex !important;
}
}
/* ── Detail image — larger display ──────────────────────── */
.detail-img {
width: 100%;
max-height: 28vh;
object-fit: contain;
display: block;
margin-bottom: 10px;
}
/* ── Ver conexiones button ───────────────────────────────── */
#verConexionesBtn {
display: block;
width: 100%;
margin-top: 14px;
padding: 10px 0;
background: rgba(255,255,255,0.08);
border: 1px solid rgba(255,255,255,0.25);
border-radius: 5px;
color: #aaffaa;
font-family: 'Fira Code', monospace;
font-size: 0.82em;
cursor: pointer;
transition: background 0.2s, color 0.2s;
}
#verConexionesBtn:hover {
background: rgba(255,255,255,0.18);
color: #fff;
}
/* ── Volver al grafo completo — floating overlay ─────────── */
#volverGrafoBtn {
display: none;
position: absolute;
top: 10px;
left: 50%;
transform: translateX(-50%);
z-index: 9990;
padding: 7px 20px;
background: rgba(0,0,0,0.82);
border: 1px solid rgba(255,255,255,0.3);
border-radius: 5px;
color: #fff;
font-family: 'Fira Code', monospace;
font-size: 0.82em;
cursor: pointer;
white-space: nowrap;
}
#volverGrafoBtn.visible { display: block; }
/* ── Móvil — nav más pequeño ≤ 800px ────────────────────── */
@media (max-width: 800px) {
.section-buttons {
justify-content: flex-start;
overflow-x: auto;
overflow-y: visible;
scrollbar-width: none;
-ms-overflow-style: none;
gap: 8px;
}
.section-buttons::-webkit-scrollbar { display: none; }
.section-btn {
padding: 7px 14px;
font-size: 0.72em;
border-width: 2px;
}
/* En móvil con overflow-x el dropdown escapa al contenedor → fixed */
.section-dropdown {
position: fixed !important;
left: 50% !important;
top: 52px !important;
transform: translateX(-50%) translateZ(0) !important;
}
}
@media (max-width: 480px) {
.section-btn {
padding: 6px 10px;
font-size: 0.65em;
}
.section-dropdown { min-width: 160px; }
.section-dropdown a { font-size: 0.7em; padding: 7px 14px; }
}

View file

@ -1,12 +0,0 @@
//Las rutas en Express.js son maneras de definir cómo responde tu aplicación a las solicitudes de los clientes
//en ciertos endpoints URI,
// que son caminos o rutas a los que los clientes pueden acceder. Las rutas pueden ser creadas y manejadas en el archivo principal de tu aplicación
//, pero para proyectos más grandes, generalmente se separan en su propio archivo o módulo para mantener el código organizado y legible.
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
res.send('Estás en la página de inicio.');
});
module.exports = router;

View file

@ -1,8 +0,0 @@
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
res.send('Estás en la página de usuarios.');
});
module.exports = router;

View file

@ -1,6 +0,0 @@
{
"name": "FLUJOS",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}

View file

@ -1,43 +0,0 @@
import os
def dividir_archivo_grande(input_file, output_dir, lineas_por_archivo=1000000):
try:
os.makedirs(output_dir, exist_ok=True)
with open(input_file, 'r') as f_in:
archivo_indice = 1
f_out = open(os.path.join(output_dir, f'parte_{archivo_indice}.txt'), 'w')
for i, linea in enumerate(f_in):
if i % lineas_por_archivo == 0 and i > 0:
f_out.close()
archivo_indice += 1
f_out = open(os.path.join(output_dir, f'parte_{archivo_indice}.txt'), 'w')
f_out.write(linea)
f_out.close()
print(f"Archivo '{input_file}' dividido en {archivo_indice} partes en '{output_dir}'")
except Exception as e:
print(f"Error al dividir el archivo '{input_file}': {e}")
def procesar_comparaciones():
# Directorio base
base_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'FLUJOS_DATOS', 'COMPARACIONES')
# Definir los nombres de las comparaciones y sus carpetas correspondientes
comparaciones = {
'wikipedia_vs_noticias': 'wikipedia_vs_noticias.txt',
'wikipedia_vs_torrents': 'wikipedia_vs_torrents.txt',
'torrents_vs_noticias': 'torrents_vs_noticias.txt'
}
# Configurar las rutas de salida
for nombre_carpeta, nombre_archivo in comparaciones.items():
input_file = os.path.join(base_dir, nombre_archivo)
output_dir = os.path.join(base_dir, nombre_carpeta)
# Verificar si el archivo de entrada existe
if os.path.exists(input_file):
dividir_archivo_grande(input_file, output_dir, lineas_por_archivo=1000000)
else:
print(f"El archivo '{input_file}' no existe. No se puede dividir.")
if __name__ == "__main__":
procesar_comparaciones()

View file

@ -1,264 +0,0 @@
import os
import re
import logging
from logging.handlers import RotatingFileHandler
from collections import Counter
from datetime import datetime
from pymongo import MongoClient
from tqdm import tqdm
from multiprocessing import Pool, cpu_count
import psutil
import string
import nltk
from nltk.corpus import stopwords
# Descargar stopwords la primera vez
nltk.download('stopwords')
stop_words = set(stopwords.words('spanish'))
# Parámetros de configuración
SIMILARITY_THRESHOLD = 4.0
LOG_FILE = "pipeline_mongolo.log"
NUM_PROCESOS = 4 # Limitar a 4 procesos
# Configuración de logging con rotación de archivos
logger = logging.getLogger()
logger.setLevel(logging.INFO)
handler = RotatingFileHandler(LOG_FILE, maxBytes=10*1024*1024, backupCount=5) # 10 MB por archivo, 5 archivos de respaldo
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
# Función para iniciar un cliente MongoDB
def init_mongo_client():
"""Inicializa un nuevo cliente MongoDB para cada proceso."""
return MongoClient('localhost', 27017)
# Función para preprocesar el texto
def preprocesar_texto(texto):
# Eliminar signos de puntuación
texto = texto.translate(str.maketrans('', '', string.punctuation))
# Convertir a minúsculas
texto = texto.lower()
# Eliminar stop words
palabras = texto.split()
palabras = [word for word in palabras if word not in stop_words]
return ' '.join(palabras)
# Función para asignar tema y subtema basado en el contenido del texto
def asignar_tema_y_subtema(texto):
tematicas = {
'inteligencia y seguridad': ['inteligencia', 'ciberseguridad', 'espionaje', 'seguridad nacional', 'contraterrorismo'],
'cambio climático': ['cambio climático', 'desastres naturales', 'conservación', 'energía renovable', 'escasez de agua'],
'guerra global': ['conflictos internacionales', 'guerras civiles', 'terrorismo', 'armas', 'alianzas militares'],
'demografía y sociedad': ['sobrepoblación', 'enfermedades', 'migraciones', 'urbanización', 'despoblación rural'],
'economía y corporaciones': ['economía global', 'corporaciones multinacionales', 'comercio internacional', 'organismos financieros', 'desigualdad económica']
}
texto_lower = texto.lower()
for tema, palabras_clave in tematicas.items():
for palabra_clave in palabras_clave:
if palabra_clave in texto_lower:
return tema, palabra_clave
return 'otros', 'general'
# Función para extraer la fecha del nombre del archivo
def extraer_fecha_de_nombre(nombre_archivo):
try:
fecha_str = re.search(r'\d{4}-\d{2}-\d{2}', nombre_archivo).group(0)
return datetime.strptime(fecha_str, '%Y-%m-%d')
except:
return None
# Función para contar palabras en un archivo tokenizado
def contar_palabras(nombre_archivo):
try:
with open(nombre_archivo, 'r', encoding='utf-8') as f:
palabras = f.read().split()
return Counter(palabras)
except Exception as e:
logging.error(f"Error al contar palabras en {nombre_archivo}: {e}")
return Counter()
# Función para comparar dos archivos y calcular el porcentaje de similitud
def comparar_archivos(archivo1, archivo2):
try:
conteo1 = contar_palabras(archivo1)
conteo2 = contar_palabras(archivo2)
palabras_comunes = set(conteo1.keys()) & set(conteo2.keys())
num_palabras_comunes = sum(min(conteo1[p], conteo2[p]) for p in palabras_comunes)
num_palabras_totales = sum(conteo1.values()) + sum(conteo2.values())
if num_palabras_totales == 0:
return 0
porcentaje_similitud = (num_palabras_comunes / num_palabras_totales) * 100
return porcentaje_similitud
except Exception as e:
logging.error(f"Error al comparar archivos {archivo1} y {archivo2}: {e}", exc_info=True)
return 0 # Retornar 0 en caso de error
# Función paralelizada para manejar las comparaciones
def manejar_comparacion_multiproceso(pair):
archivo1, archivo2 = pair
try:
# Inicia MongoDB dentro del proceso
client = init_mongo_client()
db = client['FLUJOS_DATOS']
comparaciones_collection = db['comparaciones']
nombre_archivo1 = os.path.basename(archivo1)
nombre_archivo2 = os.path.basename(archivo2)
porcentaje = comparar_archivos(archivo1, archivo2)
comparacion = {
'noticia1': nombre_archivo1,
'noticia2': nombre_archivo2,
'porcentaje_similitud': porcentaje
}
comparaciones_collection.update_one(
{"noticia1": nombre_archivo1, "noticia2": nombre_archivo2},
{"$set": comparacion},
upsert=True,
)
logging.info(f"Guardada comparación entre {nombre_archivo1} y {nombre_archivo2} con {porcentaje:.2f}% de similitud.")
except Exception as e:
logging.error(f"Error al manejar comparación {archivo1} vs {archivo2}: {e}", exc_info=True)
finally:
client.close()
# Función para verificar si el documento ya fue procesado
def documento_ya_subido(nombre_archivo, collection):
return collection.find_one({"archivo": nombre_archivo}) is not None
# Función para subir documentos a MongoDB
def subir_documento_a_mongodb(nombre_archivo, tema, subtema, fecha, texto, collection):
documento = {
'archivo': nombre_archivo,
'tema': tema,
'subtema': subtema,
'fecha': fecha,
'texto': texto # Subimos el texto original
}
try:
collection.insert_one(documento)
logging.info(f"Subido documento: {nombre_archivo} con tema: {tema}, subtema: {subtema}.")
except Exception as e:
logging.error(f"Error al subir documento {nombre_archivo}: {e}")
# Función para procesar documentos y subirlos a MongoDB
def procesar_documentos(directorio, collection):
archivos = [os.path.join(directorio, f) for f in os.listdir(directorio)]
print(f"Procesando {len(archivos)} archivos en el directorio: {directorio}")
# Subir documentos a MongoDB
with tqdm(total=len(archivos), desc=f"Subiendo documentos a MongoDB ({collection.name})", ncols=100) as pbar:
for archivo in archivos:
nombre_archivo = os.path.basename(archivo)
if documento_ya_subido(nombre_archivo, collection):
logging.info(f"Saltando {nombre_archivo}, ya está subido.")
pbar.update(1)
continue
fecha = extraer_fecha_de_nombre(nombre_archivo)
try:
with open(archivo, 'r', encoding='utf-8') as f:
texto_original = f.read()
texto_preprocesado = preprocesar_texto(texto_original)
tema, subtema = asignar_tema_y_subtema(texto_preprocesado)
subir_documento_a_mongodb(nombre_archivo, tema, subtema, fecha, texto_original, collection)
except Exception as e:
logging.error(f"Error al procesar archivo {archivo}: {e}")
pbar.update(1)
def manejar_comparaciones_multiproceso(directorios_tokenized):
try:
archivos_tokenizados = []
for directorio in directorios_tokenized:
archivos_directorio = [os.path.join(directorio, f) for f in os.listdir(directorio)]
archivos_tokenizados.append(archivos_directorio)
# Generar pares de archivos para comparar (combinaciones entre directorios)
pairs = []
for i in range(len(archivos_tokenizados)):
for j in range(i+1, len(archivos_tokenizados)):
for archivo1 in archivos_tokenizados[i]:
for archivo2 in archivos_tokenizados[j]:
pairs.append((archivo1, archivo2))
total_pairs = len(pairs)
logging.info(f"Total de pares a comparar: {total_pairs}")
# Procesar las comparaciones en lotes más pequeños para reducir el uso de memoria
batch_size = 1000 # Tamaño del lote
num_batches = (total_pairs // batch_size) + 1
logging.info(f"Procesando en {num_batches} lotes de {batch_size} pares cada uno.")
for batch_num in range(num_batches):
batch_start = batch_num * batch_size
batch_end = min(batch_start + batch_size, total_pairs)
batch_pairs = pairs[batch_start:batch_end]
logging.info(f"Procesando lote {batch_num + 1}/{num_batches}")
with Pool(processes=NUM_PROCESOS) as pool:
list(tqdm(pool.imap_unordered(manejar_comparacion_multiproceso, batch_pairs), total=len(batch_pairs), desc=f"Comparando archivos (Lote {batch_num + 1})", ncols=100))
except Exception as e:
logging.error(f"Error en manejar_comparaciones_multiproceso: {e}", exc_info=True)
def main():
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--desde", default=None,
help="Solo comparar archivos con fecha >= YYYY-MM-DD")
args, _ = parser.parse_known_args()
try:
# Rutas absolutas de los archivos en formato txt
carpeta_noticias_txt = '/var/www/theflows.net/flujos/FLUJOS_DATOS/NOTICIAS/articulos'
carpeta_wikipedia_txt = '/var/www/theflows.net/flujos/FLUJOS_DATOS/WIKIPEDIA/articulos_wikipedia'
carpeta_torrents_txt = '/var/www/theflows.net/flujos/FLUJOS_DATOS/TORRENTS/TORRENTS_WIKILEAKS_COMPLETO/txt'
# Carpetas con los archivos tokenizados para hacer las comparaciones
carpeta_noticias_tokenized = '/var/www/theflows.net/flujos/FLUJOS_DATOS/NOTICIAS/tokenized'
carpeta_wikipedia_tokenized = '/var/www/theflows.net/flujos/FLUJOS_DATOS/WIKIPEDIA/articulos_tokenizados'
carpeta_torrents_tokenized = '/var/www/theflows.net/flujos/FLUJOS_DATOS/TORRENTS/TORRENTS_WIKILEAKS_COMPLETO/tokenized'
# Iniciar cliente MongoDB
client = init_mongo_client()
# Omitir la subida de documentos
print("Subiendo archivos originales de Noticias a MongoDB...")
logging.info("Iniciando subida de noticias a MongoDB")
procesar_documentos(carpeta_noticias_txt, client['FLUJOS_DATOS']['noticias'])
logging.info("Finalizada subida de noticias a MongoDB")
# print("Subiendo archivos originales de Wikipedia a MongoDB...")
logging.info("Iniciando subida de Wikipedia a MongoDB")
procesar_documentos(carpeta_wikipedia_txt, client['FLUJOS_DATOS']['wikipedia'])
logging.info("Finalizada subida de Wikipedia a MongoDB")
# print("Subiendo archivos originales de TORRENTS a MongoDB...")
logging.info("Iniciando subida de TORRENTS a MongoDB")
procesar_documentos(carpeta_torrents_txt, client['FLUJOS_DATOS']['torrents'])
logging.info("Finalizada subida de TORRENTS a MongoDB")
# Comparar archivos tokenizados y guardar comparaciones en MongoDB
print("Comparando textos tokenizados entre Noticias, Wikipedia y TORRENTS...")
logging.info("Iniciando comparaciones entre textos tokenizados")
manejar_comparaciones_multiproceso([carpeta_noticias_tokenized, carpeta_wikipedia_tokenized, carpeta_torrents_tokenized])
logging.info("Finalizadas comparaciones entre textos tokenizados")
except Exception as e:
logging.error(f"Error en la ejecución del script: {e}", exc_info=True)
if __name__ == "__main__":
main()

View file

@ -1,577 +0,0 @@
2025-08-09 00:44:56,478 - INFO - Guardada comparación entre Hammer Film Productions.txt y Sanción.txt con 1.47% de similitud.
2025-08-09 00:44:56,482 - INFO - Guardada comparación entre Hammer Film Productions.txt y Saúl Luciano Lliuya.txt con 9.36% de similitud.
2025-08-09 00:44:56,486 - INFO - Guardada comparación entre Hammer Film Productions.txt y Antiprotestantismo.txt con 14.38% de similitud.
2025-08-09 00:44:56,489 - INFO - Guardada comparación entre Big Water.txt y Desigualdad de ingreso en Estados Unidos.txt con 17.72% de similitud.
2025-08-09 00:44:56,494 - INFO - Guardada comparación entre Big Water.txt y Iberos.txt con 3.69% de similitud.
2025-08-09 00:44:56,497 - INFO - Guardada comparación entre Big Water.txt y .km.txt con 9.94% de similitud.
2025-08-09 00:44:56,501 - INFO - Guardada comparación entre Big Water.txt y Censura internacional china.txt con 11.17% de similitud.
2025-08-09 00:44:56,504 - INFO - Guardada comparación entre Big Water.txt y Alfarería en la provincia de Almería.txt con 9.97% de similitud.
2025-08-09 00:44:56,507 - INFO - Guardada comparación entre Big Water.txt y Acuerdo de Prespa.txt con 12.30% de similitud.
2025-08-09 00:44:56,510 - INFO - Guardada comparación entre Big Water.txt y Segunda Cumbre BRIC 2010.txt con 15.52% de similitud.
2025-08-09 00:44:56,514 - INFO - Guardada comparación entre Big Water.txt y Santa Marina del Rey.txt con 15.99% de similitud.
2025-08-09 00:44:56,517 - INFO - Guardada comparación entre Big Water.txt y Omaira Montoya Henao.txt con 17.75% de similitud.
2025-08-09 00:44:56,520 - INFO - Guardada comparación entre Big Water.txt y Biodiversidad Virtual.txt con 14.38% de similitud.
2025-08-09 00:44:56,523 - INFO - Guardada comparación entre Big Water.txt y Estudios de ciencia, tecnología y género.txt con 14.04% de similitud.
2025-08-09 00:44:56,527 - INFO - Guardada comparación entre Big Water.txt y Representación (política).txt con 15.18% de similitud.
2025-08-09 00:44:56,530 - INFO - Guardada comparación entre Big Water.txt y Roxana Campos.txt con 12.54% de similitud.
2025-08-09 00:44:56,534 - INFO - Guardada comparación entre Big Water.txt y Reforma económica china.txt con 5.09% de similitud.
2025-08-09 00:44:56,538 - INFO - Guardada comparación entre Big Water.txt y Declaración de los Derechos de la Mujer y de la Ciudadana.txt con 11.66% de similitud.
2025-08-09 00:44:56,541 - INFO - Guardada comparación entre Big Water.txt y Convención Marco de las Naciones Unidas sobre el Cambio Climático.txt con 12.70% de similitud.
2025-08-09 00:44:56,544 - INFO - Guardada comparación entre Big Water.txt y Oswald Pohl.txt con 16.83% de similitud.
2025-08-09 00:44:56,547 - INFO - Guardada comparación entre Big Water.txt y Empresa Nacional Siderúrgica.txt con 12.94% de similitud.
2025-08-09 00:44:56,551 - INFO - Guardada comparación entre Big Water.txt y Certificate Signing Request.txt con 9.49% de similitud.
2025-08-09 00:44:56,554 - INFO - Guardada comparación entre Big Water.txt y Antônio de Sousa Neto.txt con 15.57% de similitud.
2025-08-09 00:44:56,557 - INFO - Guardada comparación entre Big Water.txt y Unión Ortodoxa.txt con 14.92% de similitud.
2025-08-09 00:44:56,561 - INFO - Guardada comparación entre Big Water.txt y Emisora móvil.txt con 7.31% de similitud.
2025-08-09 00:44:56,564 - INFO - Guardada comparación entre Big Water.txt y Demografía de la República Democrática del Congo.txt con 18.31% de similitud.
2025-08-09 00:44:56,568 - INFO - Guardada comparación entre Big Water.txt y Desigualdad de ingreso.txt con 7.10% de similitud.
2025-08-09 00:44:56,572 - INFO - Guardada comparación entre Big Water.txt y Terrorismo de extrema izquierda.txt con 7.89% de similitud.
2025-08-09 00:44:56,577 - INFO - Guardada comparación entre Autoridad Vasca de Protección de Datos.txt y Iberos.txt con 6.21% de similitud.
2025-08-09 00:44:56,580 - INFO - Guardada comparación entre Autoridad Vasca de Protección de Datos.txt y Dirección General de Atención a las Víctimas y Promoción de la Memoria Democrática.txt con 21.25% de similitud.
2025-08-09 00:44:56,584 - INFO - Guardada comparación entre Autoridad Vasca de Protección de Datos.txt y Censura internacional china.txt con 17.78% de similitud.
2025-08-09 00:44:56,587 - INFO - Guardada comparación entre Autoridad Vasca de Protección de Datos.txt y Alfarería en la provincia de Almería.txt con 16.25% de similitud.
2025-08-09 00:44:56,591 - INFO - Guardada comparación entre Autoridad Vasca de Protección de Datos.txt y Ingeniería comercial.txt con 18.38% de similitud.
2025-08-09 00:44:56,594 - INFO - Guardada comparación entre Autoridad Vasca de Protección de Datos.txt y Chevrolet Cobalt.txt con 3.03% de similitud.
2025-08-09 00:44:56,597 - INFO - Guardada comparación entre Autoridad Vasca de Protección de Datos.txt y Código Unificado de Punto de Suministro.txt con 15.82% de similitud.
2025-08-09 00:44:56,601 - INFO - Guardada comparación entre Autoridad Vasca de Protección de Datos.txt y Guerra de guerrillas en la península ibérica durante las guerras napoleónicas.txt con 18.41% de similitud.
2025-08-09 00:44:56,604 - INFO - Guardada comparación entre Autoridad Vasca de Protección de Datos.txt y Estación de tratamiento de agua potable.txt con 10.93% de similitud.
2025-08-09 00:44:56,607 - INFO - Guardada comparación entre Autoridad Vasca de Protección de Datos.txt y Militar.txt con 19.62% de similitud.
2025-08-09 00:44:56,611 - INFO - Guardada comparación entre Autoridad Vasca de Protección de Datos.txt y Demografía de Canadá.txt con 16.88% de similitud.
2025-08-09 00:44:56,614 - INFO - Guardada comparación entre Autoridad Vasca de Protección de Datos.txt y EToro.txt con 16.90% de similitud.
2025-08-09 00:44:56,617 - INFO - Guardada comparación entre Autoridad Vasca de Protección de Datos.txt y Ambiente biofísico.txt con 15.47% de similitud.
2025-08-09 00:44:56,621 - INFO - Guardada comparación entre Autoridad Vasca de Protección de Datos.txt y Juego ganar ganar.txt con 14.11% de similitud.
2025-08-09 00:44:56,624 - INFO - Guardada comparación entre Autoridad Vasca de Protección de Datos.txt y Declaración de los Derechos de la Mujer y de la Ciudadana.txt con 19.18% de similitud.
2025-08-09 00:44:56,628 - INFO - Guardada comparación entre Autoridad Vasca de Protección de Datos.txt y Convención Marco de las Naciones Unidas sobre el Cambio Climático.txt con 21.31% de similitud.
2025-08-09 00:44:56,631 - INFO - Guardada comparación entre Autoridad Vasca de Protección de Datos.txt y Oswald Pohl.txt con 14.69% de similitud.
2025-08-09 00:44:56,634 - INFO - Guardada comparación entre Autoridad Vasca de Protección de Datos.txt y Empresa Nacional Siderúrgica.txt con 20.01% de similitud.
2025-08-09 00:44:56,638 - INFO - Guardada comparación entre Autoridad Vasca de Protección de Datos.txt y Teletón El Salvador.txt con 19.31% de similitud.
2025-08-09 00:44:56,641 - INFO - Guardada comparación entre Autoridad Vasca de Protección de Datos.txt y Antônio de Sousa Neto.txt con 11.44% de similitud.
2025-08-09 00:44:56,645 - INFO - Guardada comparación entre Autoridad Vasca de Protección de Datos.txt y Mercenarios (BattleTech).txt con 17.65% de similitud.
2025-08-09 00:44:56,648 - INFO - Guardada comparación entre Autoridad Vasca de Protección de Datos.txt y Efecto cis.txt con 16.17% de similitud.
2025-08-09 00:44:56,652 - INFO - Guardada comparación entre Autoridad Vasca de Protección de Datos.txt y Demografía de la República Democrática del Congo.txt con 15.63% de similitud.
2025-08-09 00:44:56,656 - INFO - Guardada comparación entre Autoridad Vasca de Protección de Datos.txt y Desigualdad de ingreso.txt con 11.47% de similitud.
2025-08-09 00:44:56,659 - INFO - Guardada comparación entre Autoridad Vasca de Protección de Datos.txt y Terrorismo de extrema izquierda.txt con 12.34% de similitud.
2025-08-09 00:44:56,664 - INFO - Guardada comparación entre Inventario General del Patrimonio Cultural Valenciano.txt y Iberos.txt con 1.94% de similitud.
2025-08-09 00:44:56,667 - INFO - Guardada comparación entre Inventario General del Patrimonio Cultural Valenciano.txt y .km.txt con 10.83% de similitud.
2025-08-09 00:44:56,670 - INFO - Guardada comparación entre Inventario General del Patrimonio Cultural Valenciano.txt y Asesoría Jurídica Internacional.txt con 14.67% de similitud.
2025-08-09 00:44:56,674 - INFO - Guardada comparación entre Inventario General del Patrimonio Cultural Valenciano.txt y Desarrollo de videojuegos independiente.txt con 3.77% de similitud.
2025-08-09 00:44:56,677 - INFO - Guardada comparación entre Inventario General del Patrimonio Cultural Valenciano.txt y Ingeniería comercial.txt con 13.31% de similitud.
2025-08-09 00:44:56,680 - INFO - Guardada comparación entre Inventario General del Patrimonio Cultural Valenciano.txt y Chevrolet Cobalt.txt con 5.68% de similitud.
2025-08-09 00:44:56,684 - INFO - Guardada comparación entre Inventario General del Patrimonio Cultural Valenciano.txt y Código Unificado de Punto de Suministro.txt con 11.82% de similitud.
2025-08-09 00:44:56,688 - INFO - Guardada comparación entre Inventario General del Patrimonio Cultural Valenciano.txt y Guerra de guerrillas en la península ibérica durante las guerras napoleónicas.txt con 7.66% de similitud.
2025-08-09 00:44:56,692 - INFO - Guardada comparación entre Inventario General del Patrimonio Cultural Valenciano.txt y Estación de tratamiento de agua potable.txt con 12.92% de similitud.
2025-08-09 00:44:56,696 - INFO - Guardada comparación entre Inventario General del Patrimonio Cultural Valenciano.txt y Militar.txt con 8.73% de similitud.
2025-08-09 00:44:56,700 - INFO - Guardada comparación entre Inventario General del Patrimonio Cultural Valenciano.txt y Demografía de Canadá.txt con 6.70% de similitud.
2025-08-09 00:44:56,703 - INFO - Guardada comparación entre Inventario General del Patrimonio Cultural Valenciano.txt y EToro.txt con 10.03% de similitud.
2025-08-09 00:44:56,707 - INFO - Guardada comparación entre Inventario General del Patrimonio Cultural Valenciano.txt y Ambiente biofísico.txt con 13.47% de similitud.
2025-08-09 00:44:56,710 - INFO - Guardada comparación entre Inventario General del Patrimonio Cultural Valenciano.txt y Juego ganar ganar.txt con 11.59% de similitud.
2025-08-09 00:44:56,714 - INFO - Guardada comparación entre Inventario General del Patrimonio Cultural Valenciano.txt y Alejandro VII.txt con 7.87% de similitud.
2025-08-09 00:44:56,718 - INFO - Guardada comparación entre Inventario General del Patrimonio Cultural Valenciano.txt y Violencia obstétrica.txt con 11.91% de similitud.
2025-08-09 00:44:56,722 - INFO - Guardada comparación entre Inventario General del Patrimonio Cultural Valenciano.txt y Torrente Gros.txt con 9.15% de similitud.
2025-08-09 00:44:56,726 - INFO - Guardada comparación entre Inventario General del Patrimonio Cultural Valenciano.txt y Guerra de Reforma.txt con 6.67% de similitud.
2025-08-09 00:44:56,729 - INFO - Guardada comparación entre Inventario General del Patrimonio Cultural Valenciano.txt y Certificate Signing Request.txt con 5.69% de similitud.
2025-08-09 00:44:56,733 - INFO - Guardada comparación entre Inventario General del Patrimonio Cultural Valenciano.txt y Antônio de Sousa Neto.txt con 15.13% de similitud.
2025-08-09 00:44:56,736 - INFO - Guardada comparación entre Inventario General del Patrimonio Cultural Valenciano.txt y Unión Ortodoxa.txt con 9.59% de similitud.
2025-08-09 00:44:56,740 - INFO - Guardada comparación entre Inventario General del Patrimonio Cultural Valenciano.txt y Efecto cis.txt con 10.54% de similitud.
2025-08-09 00:44:56,743 - INFO - Guardada comparación entre Inventario General del Patrimonio Cultural Valenciano.txt y Sanción.txt con 5.65% de similitud.
2025-08-09 00:44:56,747 - INFO - Guardada comparación entre Inventario General del Patrimonio Cultural Valenciano.txt y Saúl Luciano Lliuya.txt con 14.35% de similitud.
2025-08-09 00:44:56,751 - INFO - Guardada comparación entre Inventario General del Patrimonio Cultural Valenciano.txt y Antiprotestantismo.txt con 9.08% de similitud.
2025-08-09 00:44:56,754 - INFO - Guardada comparación entre Guerra Fría (desambiguación).txt y Desigualdad de ingreso en Estados Unidos.txt con 6.27% de similitud.
2025-08-09 00:44:56,757 - INFO - Guardada comparación entre Guerra Fría (desambiguación).txt y Club Deportivo La Equidad (Femenino).txt con 7.70% de similitud.
2025-08-09 00:44:56,760 - INFO - Guardada comparación entre Guerra Fría (desambiguación).txt y .km.txt con 8.42% de similitud.
2025-08-09 00:44:56,763 - INFO - Guardada comparación entre Guerra Fría (desambiguación).txt y Asesoría Jurídica Internacional.txt con 10.96% de similitud.
2025-08-09 00:44:56,767 - INFO - Guardada comparación entre Guerra Fría (desambiguación).txt y Desarrollo de videojuegos independiente.txt con 2.18% de similitud.
2025-08-09 00:44:56,770 - INFO - Guardada comparación entre Guerra Fría (desambiguación).txt y Ingeniería comercial.txt con 7.98% de similitud.
2025-08-09 00:44:56,773 - INFO - Guardada comparación entre Guerra Fría (desambiguación).txt y Chevrolet Cobalt.txt con 8.85% de similitud.
2025-08-09 00:44:56,776 - INFO - Guardada comparación entre Guerra Fría (desambiguación).txt y Código Unificado de Punto de Suministro.txt con 6.75% de similitud.
2025-08-09 00:44:56,779 - INFO - Guardada comparación entre Guerra Fría (desambiguación).txt y Guerra de guerrillas en la península ibérica durante las guerras napoleónicas.txt con 4.03% de similitud.
2025-08-09 00:44:56,782 - INFO - Guardada comparación entre Guerra Fría (desambiguación).txt y Estación de tratamiento de agua potable.txt con 9.89% de similitud.
2025-08-09 00:44:56,785 - INFO - Guardada comparación entre Guerra Fría (desambiguación).txt y Militar.txt con 5.92% de similitud.
2025-08-09 00:44:56,788 - INFO - Guardada comparación entre Guerra Fría (desambiguación).txt y Demografía de Canadá.txt con 4.05% de similitud.
2025-08-09 00:44:56,792 - INFO - Guardada comparación entre Guerra Fría (desambiguación).txt y EToro.txt con 6.73% de similitud.
2025-08-09 00:44:56,796 - INFO - Guardada comparación entre Guerra Fría (desambiguación).txt y Ambiente biofísico.txt con 8.19% de similitud.
2025-08-09 00:44:56,800 - INFO - Guardada comparación entre Guerra Fría (desambiguación).txt y Juego ganar ganar.txt con 7.92% de similitud.
2025-08-09 00:44:56,803 - INFO - Guardada comparación entre Guerra Fría (desambiguación).txt y Declaración de los Derechos de la Mujer y de la Ciudadana.txt con 4.29% de similitud.
2025-08-09 00:44:56,806 - INFO - Guardada comparación entre Guerra Fría (desambiguación).txt y Convención Marco de las Naciones Unidas sobre el Cambio Climático.txt con 4.87% de similitud.
2025-08-09 00:44:56,809 - INFO - Guardada comparación entre Guerra Fría (desambiguación).txt y Oswald Pohl.txt con 9.97% de similitud.
2025-08-09 00:44:56,813 - INFO - Guardada comparación entre Guerra Fría (desambiguación).txt y Empresa Nacional Siderúrgica.txt con 5.66% de similitud.
2025-08-09 00:44:56,816 - INFO - Guardada comparación entre Guerra Fría (desambiguación).txt y Teletón El Salvador.txt con 4.97% de similitud.
2025-08-09 00:44:56,819 - INFO - Guardada comparación entre Guerra Fría (desambiguación).txt y Antônio de Sousa Neto.txt con 10.74% de similitud.
2025-08-09 00:44:56,822 - INFO - Guardada comparación entre Guerra Fría (desambiguación).txt y Mercenarios (BattleTech).txt con 4.41% de similitud.
2025-08-09 00:44:56,825 - INFO - Guardada comparación entre Guerra Fría (desambiguación).txt y Efecto cis.txt con 5.29% de similitud.
2025-08-09 00:44:56,828 - INFO - Guardada comparación entre Guerra Fría (desambiguación).txt y Sanción.txt con 5.90% de similitud.
2025-08-09 00:44:56,835 - INFO - Guardada comparación entre Guerra Fría (desambiguación).txt y Saúl Luciano Lliuya.txt con 9.67% de similitud.
2025-08-09 00:44:56,839 - INFO - Guardada comparación entre Guerra Fría (desambiguación).txt y Terrorismo de extrema izquierda.txt con 2.81% de similitud.
2025-08-09 00:44:56,844 - INFO - Guardada comparación entre Batalla de Zaragoza.txt y Iberos.txt con 3.14% de similitud.
2025-08-09 00:44:56,846 - INFO - Guardada comparación entre Batalla de Zaragoza.txt y .km.txt con 10.28% de similitud.
2025-08-09 00:44:56,849 - INFO - Guardada comparación entre Batalla de Zaragoza.txt y Asesoría Jurídica Internacional.txt con 16.83% de similitud.
2025-08-09 00:44:56,853 - INFO - Guardada comparación entre Batalla de Zaragoza.txt y Censura internacional china.txt con 9.20% de similitud.
2025-08-09 00:44:56,856 - INFO - Guardada comparación entre Batalla de Zaragoza.txt y Alfarería en la provincia de Almería.txt con 8.87% de similitud.
2025-08-09 00:44:56,859 - INFO - Guardada comparación entre Batalla de Zaragoza.txt y Acuerdo de Prespa.txt con 13.96% de similitud.
2025-08-09 00:44:56,862 - INFO - Guardada comparación entre Batalla de Zaragoza.txt y Segunda Cumbre BRIC 2010.txt con 13.66% de similitud.
2025-08-09 00:44:56,865 - INFO - Guardada comparación entre Batalla de Zaragoza.txt y Santa Marina del Rey.txt con 16.36% de similitud.
2025-08-09 00:44:56,868 - INFO - Guardada comparación entre Batalla de Zaragoza.txt y Omaira Montoya Henao.txt con 18.10% de similitud.
2025-08-09 00:44:56,871 - INFO - Guardada comparación entre Batalla de Zaragoza.txt y Biodiversidad Virtual.txt con 13.74% de similitud.
2025-08-09 00:44:56,875 - INFO - Guardada comparación entre Batalla de Zaragoza.txt y Estudios de ciencia, tecnología y género.txt con 12.73% de similitud.
2025-08-09 00:44:56,878 - INFO - Guardada comparación entre Batalla de Zaragoza.txt y Representación (política).txt con 13.59% de similitud.
2025-08-09 00:44:56,881 - INFO - Guardada comparación entre Batalla de Zaragoza.txt y Roxana Campos.txt con 15.90% de similitud.
2025-08-09 00:44:56,885 - INFO - Guardada comparación entre Batalla de Zaragoza.txt y Reforma económica china.txt con 3.33% de similitud.
2025-08-09 00:44:56,889 - INFO - Guardada comparación entre Batalla de Zaragoza.txt y Declaración de los Derechos de la Mujer y de la Ciudadana.txt con 9.83% de similitud.
2025-08-09 00:44:56,892 - INFO - Guardada comparación entre Batalla de Zaragoza.txt y Convención Marco de las Naciones Unidas sobre el Cambio Climático.txt con 11.27% de similitud.
2025-08-09 00:44:56,895 - INFO - Guardada comparación entre Batalla de Zaragoza.txt y Oswald Pohl.txt con 17.99% de similitud.
2025-08-09 00:44:56,898 - INFO - Guardada comparación entre Batalla de Zaragoza.txt y Empresa Nacional Siderúrgica.txt con 12.18% de similitud.
2025-08-09 00:44:56,902 - INFO - Guardada comparación entre Batalla de Zaragoza.txt y Teletón El Salvador.txt con 11.70% de similitud.
2025-08-09 00:44:56,904 - INFO - Guardada comparación entre Batalla de Zaragoza.txt y Antônio de Sousa Neto.txt con 17.30% de similitud.
2025-08-09 00:44:56,908 - INFO - Guardada comparación entre Batalla de Zaragoza.txt y Mercenarios (BattleTech).txt con 10.49% de similitud.
2025-08-09 00:44:56,911 - INFO - Guardada comparación entre Batalla de Zaragoza.txt y Efecto cis.txt con 12.67% de similitud.
2025-08-09 00:44:56,914 - INFO - Guardada comparación entre Batalla de Zaragoza.txt y Sanción.txt con 3.61% de similitud.
2025-08-09 00:44:56,917 - INFO - Guardada comparación entre Batalla de Zaragoza.txt y Saúl Luciano Lliuya.txt con 15.50% de similitud.
2025-08-09 00:44:56,920 - INFO - Guardada comparación entre Batalla de Zaragoza.txt y Antiprotestantismo.txt con 12.49% de similitud.
2025-08-09 00:44:56,923 - INFO - Guardada comparación entre Puebla de Segur.txt y Desigualdad de ingreso en Estados Unidos.txt con 18.11% de similitud.
2025-08-09 00:44:56,927 - INFO - Guardada comparación entre Puebla de Segur.txt y Club Deportivo La Equidad (Femenino).txt con 15.07% de similitud.
2025-08-09 00:44:56,930 - INFO - Guardada comparación entre Puebla de Segur.txt y Dirección General de Atención a las Víctimas y Promoción de la Memoria Democrática.txt con 16.31% de similitud.
2025-08-09 00:44:56,933 - INFO - Guardada comparación entre Puebla de Segur.txt y Asesoría Jurídica Internacional.txt con 12.21% de similitud.
2025-08-09 00:44:56,937 - INFO - Guardada comparación entre Puebla de Segur.txt y Desarrollo de videojuegos independiente.txt con 14.01% de similitud.
2025-08-09 00:44:56,940 - INFO - Guardada comparación entre Puebla de Segur.txt y Ingeniería comercial.txt con 15.45% de similitud.
2025-08-09 00:44:56,943 - INFO - Guardada comparación entre Puebla de Segur.txt y Chevrolet Cobalt.txt con 2.86% de similitud.
2025-08-09 00:44:56,947 - INFO - Guardada comparación entre Puebla de Segur.txt y Código Unificado de Punto de Suministro.txt con 15.26% de similitud.
2025-08-09 00:44:56,950 - INFO - Guardada comparación entre Puebla de Segur.txt y Guerra de guerrillas en la península ibérica durante las guerras napoleónicas.txt con 19.28% de similitud.
2025-08-09 00:44:56,954 - INFO - Guardada comparación entre Puebla de Segur.txt y Estación de tratamiento de agua potable.txt con 9.33% de similitud.
2025-08-09 00:44:56,957 - INFO - Guardada comparación entre Puebla de Segur.txt y Militar.txt con 16.46% de similitud.
2025-08-09 00:44:56,960 - INFO - Guardada comparación entre Puebla de Segur.txt y Demografía de Canadá.txt con 18.26% de similitud.
2025-08-09 00:44:56,963 - INFO - Guardada comparación entre Puebla de Segur.txt y EToro.txt con 15.76% de similitud.
2025-08-09 00:44:56,967 - INFO - Guardada comparación entre Puebla de Segur.txt y Ambiente biofísico.txt con 14.46% de similitud.
2025-08-09 00:44:56,971 - INFO - Guardada comparación entre Puebla de Segur.txt y Juego ganar ganar.txt con 13.89% de similitud.
2025-08-09 00:44:56,974 - INFO - Guardada comparación entre Puebla de Segur.txt y Declaración de los Derechos de la Mujer y de la Ciudadana.txt con 18.19% de similitud.
2025-08-09 00:44:56,978 - INFO - Guardada comparación entre Puebla de Segur.txt y Convención Marco de las Naciones Unidas sobre el Cambio Climático.txt con 19.30% de similitud.
2025-08-09 00:44:56,981 - INFO - Guardada comparación entre Puebla de Segur.txt y Oswald Pohl.txt con 13.09% de similitud.
2025-08-09 00:44:56,984 - INFO - Guardada comparación entre Puebla de Segur.txt y Empresa Nacional Siderúrgica.txt con 21.23% de similitud.
2025-08-09 00:44:56,988 - INFO - Guardada comparación entre Puebla de Segur.txt y Teletón El Salvador.txt con 18.86% de similitud.
2025-08-09 00:44:56,991 - INFO - Guardada comparación entre Puebla de Segur.txt y Antônio de Sousa Neto.txt con 10.77% de similitud.
2025-08-09 00:44:56,995 - INFO - Guardada comparación entre Puebla de Segur.txt y Mercenarios (BattleTech).txt con 17.89% de similitud.
2025-08-09 00:44:56,998 - INFO - Guardada comparación entre Puebla de Segur.txt y Efecto cis.txt con 16.19% de similitud.
2025-08-09 00:44:57,002 - INFO - Guardada comparación entre Puebla de Segur.txt y Sanción.txt con 1.66% de similitud.
2025-08-09 00:44:57,005 - INFO - Guardada comparación entre Puebla de Segur.txt y Saúl Luciano Lliuya.txt con 11.21% de similitud.
2025-08-09 00:44:57,009 - INFO - Guardada comparación entre Puebla de Segur.txt y Antiprotestantismo.txt con 18.46% de similitud.
2025-08-09 00:44:57,012 - INFO - Guardada comparación entre Trabajo de mierda.txt y Desigualdad de ingreso en Estados Unidos.txt con 9.31% de similitud.
2025-08-09 00:44:57,015 - INFO - Guardada comparación entre Trabajo de mierda.txt y Club Deportivo La Equidad (Femenino).txt con 8.60% de similitud.
2025-08-09 00:44:57,018 - INFO - Guardada comparación entre Trabajo de mierda.txt y Dirección General de Atención a las Víctimas y Promoción de la Memoria Democrática.txt con 9.67% de similitud.
2025-08-09 00:44:57,021 - INFO - Guardada comparación entre Trabajo de mierda.txt y Asesoría Jurídica Internacional.txt con 12.23% de similitud.
2025-08-09 00:44:57,025 - INFO - Guardada comparación entre Trabajo de mierda.txt y Desarrollo de videojuegos independiente.txt con 3.62% de similitud.
2025-08-09 00:44:57,028 - INFO - Guardada comparación entre Trabajo de mierda.txt y Ingeniería comercial.txt con 12.03% de similitud.
2025-08-09 00:44:57,031 - INFO - Guardada comparación entre Trabajo de mierda.txt y Chevrolet Cobalt.txt con 7.14% de similitud.
2025-08-09 00:44:57,034 - INFO - Guardada comparación entre Trabajo de mierda.txt y Código Unificado de Punto de Suministro.txt con 9.32% de similitud.
2025-08-09 00:44:57,037 - INFO - Guardada comparación entre Trabajo de mierda.txt y Guerra de guerrillas en la península ibérica durante las guerras napoleónicas.txt con 6.35% de similitud.
2025-08-09 00:44:57,040 - INFO - Guardada comparación entre Trabajo de mierda.txt y Estación de tratamiento de agua potable.txt con 11.96% de similitud.
2025-08-09 00:44:57,044 - INFO - Guardada comparación entre Trabajo de mierda.txt y Militar.txt con 7.77% de similitud.
2025-08-09 00:44:57,047 - INFO - Guardada comparación entre Trabajo de mierda.txt y Demografía de Canadá.txt con 5.70% de similitud.
2025-08-09 00:44:57,050 - INFO - Guardada comparación entre Trabajo de mierda.txt y EToro.txt con 9.27% de similitud.
2025-08-09 00:44:57,054 - INFO - Guardada comparación entre Trabajo de mierda.txt y Ambiente biofísico.txt con 12.41% de similitud.
2025-08-09 00:44:57,057 - INFO - Guardada comparación entre Trabajo de mierda.txt y Juego ganar ganar.txt con 10.54% de similitud.
2025-08-09 00:44:57,060 - INFO - Guardada comparación entre Trabajo de mierda.txt y Declaración de los Derechos de la Mujer y de la Ciudadana.txt con 6.02% de similitud.
2025-08-09 00:44:57,064 - INFO - Guardada comparación entre Trabajo de mierda.txt y Convención Marco de las Naciones Unidas sobre el Cambio Climático.txt con 6.85% de similitud.
2025-08-09 00:44:57,067 - INFO - Guardada comparación entre Trabajo de mierda.txt y Oswald Pohl.txt con 10.33% de similitud.
2025-08-09 00:44:57,071 - INFO - Guardada comparación entre Trabajo de mierda.txt y Empresa Nacional Siderúrgica.txt con 7.64% de similitud.
2025-08-09 00:44:57,074 - INFO - Guardada comparación entre Trabajo de mierda.txt y Teletón El Salvador.txt con 6.53% de similitud.
2025-08-09 00:44:57,077 - INFO - Guardada comparación entre Trabajo de mierda.txt y Antônio de Sousa Neto.txt con 12.06% de similitud.
2025-08-09 00:44:57,081 - INFO - Guardada comparación entre Trabajo de mierda.txt y Mercenarios (BattleTech).txt con 6.10% de similitud.
2025-08-09 00:44:57,084 - INFO - Guardada comparación entre Trabajo de mierda.txt y Efecto cis.txt con 8.20% de similitud.
2025-08-09 00:44:57,087 - INFO - Guardada comparación entre Trabajo de mierda.txt y Demografía de la República Democrática del Congo.txt con 7.03% de similitud.
2025-08-09 00:44:57,091 - INFO - Guardada comparación entre Trabajo de mierda.txt y Desigualdad de ingreso.txt con 3.57% de similitud.
2025-08-09 00:44:57,095 - INFO - Guardada comparación entre Trabajo de mierda.txt y Terrorismo de extrema izquierda.txt con 3.82% de similitud.
2025-08-09 00:44:57,100 - INFO - Guardada comparación entre Susana Ruiz Cerutti.txt y Iberos.txt con 3.82% de similitud.
2025-08-09 00:44:57,103 - INFO - Guardada comparación entre Susana Ruiz Cerutti.txt y .km.txt con 8.17% de similitud.
2025-08-09 00:44:57,107 - INFO - Guardada comparación entre Susana Ruiz Cerutti.txt y Censura internacional china.txt con 11.96% de similitud.
2025-08-09 00:44:57,110 - INFO - Guardada comparación entre Susana Ruiz Cerutti.txt y Alfarería en la provincia de Almería.txt con 11.60% de similitud.
2025-08-09 00:44:57,114 - INFO - Guardada comparación entre Susana Ruiz Cerutti.txt y Acuerdo de Prespa.txt con 11.31% de similitud.
2025-08-09 00:44:57,117 - INFO - Guardada comparación entre Susana Ruiz Cerutti.txt y Segunda Cumbre BRIC 2010.txt con 18.12% de similitud.
2025-08-09 00:44:57,120 - INFO - Guardada comparación entre Susana Ruiz Cerutti.txt y Santa Marina del Rey.txt con 16.52% de similitud.
2025-08-09 00:44:57,123 - INFO - Guardada comparación entre Susana Ruiz Cerutti.txt y Omaira Montoya Henao.txt con 20.37% de similitud.
2025-08-09 00:44:57,127 - INFO - Guardada comparación entre Susana Ruiz Cerutti.txt y Biodiversidad Virtual.txt con 16.44% de similitud.
2025-08-09 00:44:57,130 - INFO - Guardada comparación entre Susana Ruiz Cerutti.txt y Estudios de ciencia, tecnología y género.txt con 15.68% de similitud.
2025-08-09 00:44:57,133 - INFO - Guardada comparación entre Susana Ruiz Cerutti.txt y Representación (política).txt con 18.18% de similitud.
2025-08-09 00:44:57,136 - INFO - Guardada comparación entre Susana Ruiz Cerutti.txt y Roxana Campos.txt con 15.74% de similitud.
2025-08-09 00:44:57,141 - INFO - Guardada comparación entre Susana Ruiz Cerutti.txt y Reforma económica china.txt con 4.59% de similitud.
2025-08-09 00:44:57,144 - INFO - Guardada comparación entre Susana Ruiz Cerutti.txt y Alejandro VII.txt con 15.90% de similitud.
2025-08-09 00:44:57,147 - INFO - Guardada comparación entre Susana Ruiz Cerutti.txt y Violencia obstétrica.txt con 18.63% de similitud.
2025-08-09 00:44:57,150 - INFO - Guardada comparación entre Susana Ruiz Cerutti.txt y Torrente Gros.txt con 16.83% de similitud.
2025-08-09 00:44:57,154 - INFO - Guardada comparación entre Susana Ruiz Cerutti.txt y Guerra de Reforma.txt con 12.69% de similitud.
2025-08-09 00:44:57,157 - INFO - Guardada comparación entre Susana Ruiz Cerutti.txt y Certificate Signing Request.txt con 8.53% de similitud.
2025-08-09 00:44:57,161 - INFO - Guardada comparación entre Susana Ruiz Cerutti.txt y Katalin Bogyay.txt con 12.49% de similitud.
2025-08-09 00:44:57,164 - INFO - Guardada comparación entre Susana Ruiz Cerutti.txt y Unión Ortodoxa.txt con 16.91% de similitud.
2025-08-09 00:44:57,168 - INFO - Guardada comparación entre Susana Ruiz Cerutti.txt y Emisora móvil.txt con 7.67% de similitud.
2025-08-09 00:44:57,171 - INFO - Guardada comparación entre Susana Ruiz Cerutti.txt y Sanción.txt con 3.08% de similitud.
2025-08-09 00:44:57,174 - INFO - Guardada comparación entre Susana Ruiz Cerutti.txt y Saúl Luciano Lliuya.txt con 15.63% de similitud.
2025-08-09 00:44:57,177 - INFO - Guardada comparación entre Susana Ruiz Cerutti.txt y Antiprotestantismo.txt con 15.88% de similitud.
2025-08-09 00:44:57,180 - INFO - Guardada comparación entre Reconstrucción Blanca.txt y Desigualdad de ingreso en Estados Unidos.txt con 11.10% de similitud.
2025-08-09 00:44:57,183 - INFO - Guardada comparación entre Reconstrucción Blanca.txt y Club Deportivo La Equidad (Femenino).txt con 12.95% de similitud.
2025-08-09 00:44:57,190 - INFO - Guardada comparación entre Reconstrucción Blanca.txt y Dirección General de Atención a las Víctimas y Promoción de la Memoria Democrática.txt con 13.28% de similitud.
2025-08-09 00:44:57,194 - INFO - Guardada comparación entre Reconstrucción Blanca.txt y Censura internacional china.txt con 8.00% de similitud.
2025-08-09 00:44:57,197 - INFO - Guardada comparación entre Reconstrucción Blanca.txt y Alfarería en la provincia de Almería.txt con 7.17% de similitud.
2025-08-09 00:44:57,200 - INFO - Guardada comparación entre Reconstrucción Blanca.txt y Acuerdo de Prespa.txt con 12.88% de similitud.
2025-08-09 00:44:57,203 - INFO - Guardada comparación entre Reconstrucción Blanca.txt y Segunda Cumbre BRIC 2010.txt con 11.54% de similitud.
2025-08-09 00:44:57,206 - INFO - Guardada comparación entre Reconstrucción Blanca.txt y Santa Marina del Rey.txt con 13.59% de similitud.
2025-08-09 00:44:57,209 - INFO - Guardada comparación entre Reconstrucción Blanca.txt y Omaira Montoya Henao.txt con 15.78% de similitud.
2025-08-09 00:44:57,212 - INFO - Guardada comparación entre Reconstrucción Blanca.txt y Biodiversidad Virtual.txt con 12.24% de similitud.
2025-08-09 00:44:57,216 - INFO - Guardada comparación entre Reconstrucción Blanca.txt y Estudios de ciencia, tecnología y género.txt con 10.17% de similitud.
2025-08-09 00:44:57,219 - INFO - Guardada comparación entre Reconstrucción Blanca.txt y Demografía de Canadá.txt con 8.06% de similitud.
2025-08-09 00:44:57,222 - INFO - Guardada comparación entre Reconstrucción Blanca.txt y Roxana Campos.txt con 14.53% de similitud.
2025-08-09 00:44:57,226 - INFO - Guardada comparación entre Reconstrucción Blanca.txt y Reforma económica china.txt con 2.90% de similitud.
2025-08-09 00:44:57,229 - INFO - Guardada comparación entre Reconstrucción Blanca.txt y Alejandro VII.txt con 10.44% de similitud.
2025-08-09 00:44:57,233 - INFO - Guardada comparación entre Reconstrucción Blanca.txt y Violencia obstétrica.txt con 12.64% de similitud.
2025-08-09 00:44:57,236 - INFO - Guardada comparación entre Reconstrucción Blanca.txt y Torrente Gros.txt con 12.99% de similitud.
2025-08-09 00:44:57,239 - INFO - Guardada comparación entre Reconstrucción Blanca.txt y Guerra de Reforma.txt con 8.15% de similitud.
2025-08-09 00:44:57,243 - INFO - Guardada comparación entre Reconstrucción Blanca.txt y Certificate Signing Request.txt con 6.07% de similitud.
2025-08-09 00:44:57,246 - INFO - Guardada comparación entre Reconstrucción Blanca.txt y Katalin Bogyay.txt con 6.74% de similitud.
2025-08-09 00:44:57,249 - INFO - Guardada comparación entre Reconstrucción Blanca.txt y Unión Ortodoxa.txt con 11.21% de similitud.
2025-08-09 00:44:57,253 - INFO - Guardada comparación entre Reconstrucción Blanca.txt y Emisora móvil.txt con 5.01% de similitud.
2025-08-09 00:44:57,256 - INFO - Guardada comparación entre Reconstrucción Blanca.txt y Sanción.txt con 3.79% de similitud.
2025-08-09 00:44:57,259 - INFO - Guardada comparación entre Reconstrucción Blanca.txt y Saúl Luciano Lliuya.txt con 12.82% de similitud.
2025-08-09 00:44:57,262 - INFO - Guardada comparación entre Reconstrucción Blanca.txt y Antiprotestantismo.txt con 10.12% de similitud.
2025-08-09 00:44:57,266 - INFO - Guardada comparación entre Relaciones Unión Europea-micro-Estados europeos.txt y Desigualdad de ingreso en Estados Unidos.txt con 20.24% de similitud.
2025-08-09 00:44:57,269 - INFO - Guardada comparación entre Relaciones Unión Europea-micro-Estados europeos.txt y Club Deportivo La Equidad (Femenino).txt con 16.58% de similitud.
2025-08-09 00:44:57,273 - INFO - Guardada comparación entre Relaciones Unión Europea-micro-Estados europeos.txt y Dirección General de Atención a las Víctimas y Promoción de la Memoria Democrática.txt con 19.28% de similitud.
2025-08-09 00:44:57,276 - INFO - Guardada comparación entre Relaciones Unión Europea-micro-Estados europeos.txt y Asesoría Jurídica Internacional.txt con 14.22% de similitud.
2025-08-09 00:44:57,280 - INFO - Guardada comparación entre Relaciones Unión Europea-micro-Estados europeos.txt y Desarrollo de videojuegos independiente.txt con 13.69% de similitud.
2025-08-09 00:44:57,283 - INFO - Guardada comparación entre Relaciones Unión Europea-micro-Estados europeos.txt y Ingeniería comercial.txt con 17.93% de similitud.
2025-08-09 00:44:57,286 - INFO - Guardada comparación entre Relaciones Unión Europea-micro-Estados europeos.txt y Chevrolet Cobalt.txt con 3.07% de similitud.
2025-08-09 00:44:57,290 - INFO - Guardada comparación entre Relaciones Unión Europea-micro-Estados europeos.txt y Código Unificado de Punto de Suministro.txt con 15.31% de similitud.
2025-08-09 00:44:57,294 - INFO - Guardada comparación entre Relaciones Unión Europea-micro-Estados europeos.txt y Guerra de guerrillas en la península ibérica durante las guerras napoleónicas.txt con 19.93% de similitud.
2025-08-09 00:44:57,297 - INFO - Guardada comparación entre Relaciones Unión Europea-micro-Estados europeos.txt y Estación de tratamiento de agua potable.txt con 10.70% de similitud.
2025-08-09 00:44:57,300 - INFO - Guardada comparación entre Relaciones Unión Europea-micro-Estados europeos.txt y Militar.txt con 20.52% de similitud.
2025-08-09 00:44:57,304 - INFO - Guardada comparación entre Relaciones Unión Europea-micro-Estados europeos.txt y Demografía de Canadá.txt con 19.04% de similitud.
2025-08-09 00:44:57,307 - INFO - Guardada comparación entre Relaciones Unión Europea-micro-Estados europeos.txt y EToro.txt con 17.32% de similitud.
2025-08-09 00:44:57,310 - INFO - Guardada comparación entre Relaciones Unión Europea-micro-Estados europeos.txt y Ambiente biofísico.txt con 14.88% de similitud.
2025-08-09 00:44:57,314 - INFO - Guardada comparación entre Relaciones Unión Europea-micro-Estados europeos.txt y Juego ganar ganar.txt con 15.95% de similitud.
2025-08-09 00:44:57,317 - INFO - Guardada comparación entre Relaciones Unión Europea-micro-Estados europeos.txt y Declaración de los Derechos de la Mujer y de la Ciudadana.txt con 19.84% de similitud.
2025-08-09 00:44:57,320 - INFO - Guardada comparación entre Relaciones Unión Europea-micro-Estados europeos.txt y Convención Marco de las Naciones Unidas sobre el Cambio Climático.txt con 21.37% de similitud.
2025-08-09 00:44:57,324 - INFO - Guardada comparación entre Relaciones Unión Europea-micro-Estados europeos.txt y Oswald Pohl.txt con 14.41% de similitud.
2025-08-09 00:44:57,327 - INFO - Guardada comparación entre Relaciones Unión Europea-micro-Estados europeos.txt y Empresa Nacional Siderúrgica.txt con 19.64% de similitud.
2025-08-09 00:44:57,331 - INFO - Guardada comparación entre Relaciones Unión Europea-micro-Estados europeos.txt y Teletón El Salvador.txt con 21.81% de similitud.
2025-08-09 00:44:57,334 - INFO - Guardada comparación entre Relaciones Unión Europea-micro-Estados europeos.txt y Antônio de Sousa Neto.txt con 11.33% de similitud.
2025-08-09 00:44:57,337 - INFO - Guardada comparación entre Relaciones Unión Europea-micro-Estados europeos.txt y Mercenarios (BattleTech).txt con 19.49% de similitud.
2025-08-09 00:44:57,341 - INFO - Guardada comparación entre Relaciones Unión Europea-micro-Estados europeos.txt y Efecto cis.txt con 17.20% de similitud.
2025-08-09 00:44:57,344 - INFO - Guardada comparación entre Relaciones Unión Europea-micro-Estados europeos.txt y Demografía de la República Democrática del Congo.txt con 16.46% de similitud.
2025-08-09 00:44:57,348 - INFO - Guardada comparación entre Relaciones Unión Europea-micro-Estados europeos.txt y Desigualdad de ingreso.txt con 12.09% de similitud.
2025-08-09 00:44:57,352 - INFO - Guardada comparación entre Relaciones Unión Europea-micro-Estados europeos.txt y Terrorismo de extrema izquierda.txt con 13.97% de similitud.
2025-08-09 00:44:57,358 - INFO - Guardada comparación entre Juegos de guerra.txt y Iberos.txt con 8.42% de similitud.
2025-08-09 00:44:57,361 - INFO - Guardada comparación entre Juegos de guerra.txt y .km.txt con 5.61% de similitud.
2025-08-09 00:44:57,364 - INFO - Guardada comparación entre Juegos de guerra.txt y Asesoría Jurídica Internacional.txt con 10.46% de similitud.
2025-08-09 00:44:57,368 - INFO - Guardada comparación entre Juegos de guerra.txt y Desarrollo de videojuegos independiente.txt con 15.64% de similitud.
2025-08-09 00:44:57,372 - INFO - Guardada comparación entre Juegos de guerra.txt y Ingeniería comercial.txt con 13.44% de similitud.
2025-08-09 00:44:57,375 - INFO - Guardada comparación entre Juegos de guerra.txt y Chevrolet Cobalt.txt con 2.31% de similitud.
2025-08-09 00:44:57,378 - INFO - Guardada comparación entre Juegos de guerra.txt y Código Unificado de Punto de Suministro.txt con 11.91% de similitud.
2025-08-09 00:44:57,382 - INFO - Guardada comparación entre Juegos de guerra.txt y Guerra de guerrillas en la península ibérica durante las guerras napoleónicas.txt con 18.59% de similitud.
2025-08-09 00:44:57,385 - INFO - Guardada comparación entre Juegos de guerra.txt y Estación de tratamiento de agua potable.txt con 7.93% de similitud.
2025-08-09 00:44:57,389 - INFO - Guardada comparación entre Juegos de guerra.txt y Militar.txt con 18.07% de similitud.
2025-08-09 00:44:57,392 - INFO - Guardada comparación entre Juegos de guerra.txt y Demografía de Canadá.txt con 17.59% de similitud.
2025-08-09 00:44:57,396 - INFO - Guardada comparación entre Juegos de guerra.txt y EToro.txt con 13.68% de similitud.
2025-08-09 00:44:57,401 - INFO - Guardada comparación entre Juegos de guerra.txt y Reforma económica china.txt con 9.41% de similitud.
2025-08-09 00:44:57,405 - INFO - Guardada comparación entre Juegos de guerra.txt y Alejandro VII.txt con 19.25% de similitud.
2025-08-09 00:44:57,408 - INFO - Guardada comparación entre Juegos de guerra.txt y Violencia obstétrica.txt con 14.18% de similitud.
2025-08-09 00:44:57,412 - INFO - Guardada comparación entre Juegos de guerra.txt y Torrente Gros.txt con 15.71% de similitud.
2025-08-09 00:44:57,416 - INFO - Guardada comparación entre Juegos de guerra.txt y Guerra de Reforma.txt con 19.27% de similitud.
2025-08-09 00:44:57,420 - INFO - Guardada comparación entre Juegos de guerra.txt y Certificate Signing Request.txt con 9.84% de similitud.
2025-08-09 00:44:57,424 - INFO - Guardada comparación entre Juegos de guerra.txt y Katalin Bogyay.txt con 16.16% de similitud.
2025-08-09 00:44:57,427 - INFO - Guardada comparación entre Juegos de guerra.txt y Unión Ortodoxa.txt con 17.27% de similitud.
2025-08-09 00:44:57,431 - INFO - Guardada comparación entre Juegos de guerra.txt y Emisora móvil.txt con 15.66% de similitud.
2025-08-09 00:44:57,435 - INFO - Guardada comparación entre Juegos de guerra.txt y Sanción.txt con 1.24% de similitud.
2025-08-09 00:44:57,438 - INFO - Guardada comparación entre Juegos de guerra.txt y Saúl Luciano Lliuya.txt con 8.81% de similitud.
2025-08-09 00:44:57,441 - INFO - Guardada comparación entre Juegos de guerra.txt y Antiprotestantismo.txt con 16.49% de similitud.
2025-08-09 00:44:57,445 - INFO - Guardada comparación entre Navegador sin interfaz gráfica.txt y Desigualdad de ingreso en Estados Unidos.txt con 15.22% de similitud.
2025-08-09 00:44:57,448 - INFO - Guardada comparación entre Navegador sin interfaz gráfica.txt y Club Deportivo La Equidad (Femenino).txt con 12.28% de similitud.
2025-08-09 00:44:57,451 - INFO - Guardada comparación entre Navegador sin interfaz gráfica.txt y Dirección General de Atención a las Víctimas y Promoción de la Memoria Democrática.txt con 13.24% de similitud.
2025-08-09 00:44:57,455 - INFO - Guardada comparación entre Navegador sin interfaz gráfica.txt y Asesoría Jurídica Internacional.txt con 13.36% de similitud.
2025-08-09 00:44:57,459 - INFO - Guardada comparación entre Navegador sin interfaz gráfica.txt y Desarrollo de videojuegos independiente.txt con 8.75% de similitud.
2025-08-09 00:44:57,462 - INFO - Guardada comparación entre Navegador sin interfaz gráfica.txt y Acuerdo de Prespa.txt con 10.56% de similitud.
2025-08-09 00:44:57,465 - INFO - Guardada comparación entre Navegador sin interfaz gráfica.txt y Chevrolet Cobalt.txt con 4.05% de similitud.
2025-08-09 00:44:57,469 - INFO - Guardada comparación entre Navegador sin interfaz gráfica.txt y Código Unificado de Punto de Suministro.txt con 13.96% de similitud.
2025-08-09 00:44:57,472 - INFO - Guardada comparación entre Navegador sin interfaz gráfica.txt y Omaira Montoya Henao.txt con 15.74% de similitud.
2025-08-09 00:44:57,475 - INFO - Guardada comparación entre Navegador sin interfaz gráfica.txt y Estación de tratamiento de agua potable.txt con 11.36% de similitud.
2025-08-09 00:44:57,479 - INFO - Guardada comparación entre Navegador sin interfaz gráfica.txt y Militar.txt con 12.00% de similitud.
2025-08-09 00:44:57,482 - INFO - Guardada comparación entre Navegador sin interfaz gráfica.txt y Demografía de Canadá.txt con 11.31% de similitud.
2025-08-09 00:44:57,486 - INFO - Guardada comparación entre Navegador sin interfaz gráfica.txt y Roxana Campos.txt con 11.61% de similitud.
2025-08-09 00:44:57,490 - INFO - Guardada comparación entre Navegador sin interfaz gráfica.txt y Reforma económica china.txt con 4.43% de similitud.
2025-08-09 00:44:57,493 - INFO - Guardada comparación entre Navegador sin interfaz gráfica.txt y Alejandro VII.txt con 11.12% de similitud.
2025-08-09 00:44:57,496 - INFO - Guardada comparación entre Navegador sin interfaz gráfica.txt y Violencia obstétrica.txt con 14.46% de similitud.
2025-08-09 00:44:57,500 - INFO - Guardada comparación entre Navegador sin interfaz gráfica.txt y Torrente Gros.txt con 12.34% de similitud.
2025-08-09 00:44:57,503 - INFO - Guardada comparación entre Navegador sin interfaz gráfica.txt y Guerra de Reforma.txt con 9.51% de similitud.
2025-08-09 00:44:57,507 - INFO - Guardada comparación entre Navegador sin interfaz gráfica.txt y Certificate Signing Request.txt con 10.28% de similitud.
2025-08-09 00:44:57,510 - INFO - Guardada comparación entre Navegador sin interfaz gráfica.txt y Katalin Bogyay.txt con 10.18% de similitud.
2025-08-09 00:44:57,514 - INFO - Guardada comparación entre Navegador sin interfaz gráfica.txt y Mercenarios (BattleTech).txt con 10.44% de similitud.
2025-08-09 00:44:57,518 - INFO - Guardada comparación entre Navegador sin interfaz gráfica.txt y Emisora móvil.txt con 7.27% de similitud.
2025-08-09 00:44:57,521 - INFO - Guardada comparación entre Navegador sin interfaz gráfica.txt y Sanción.txt con 2.33% de similitud.
2025-08-09 00:44:57,524 - INFO - Guardada comparación entre Navegador sin interfaz gráfica.txt y Saúl Luciano Lliuya.txt con 13.39% de similitud.
2025-08-09 00:44:57,528 - INFO - Guardada comparación entre Navegador sin interfaz gráfica.txt y Antiprotestantismo.txt con 13.35% de similitud.
2025-08-09 00:44:57,531 - INFO - Guardada comparación entre Asociación Civil Transparencia.txt y Desigualdad de ingreso en Estados Unidos.txt con 11.04% de similitud.
2025-08-09 00:44:57,534 - INFO - Guardada comparación entre Asociación Civil Transparencia.txt y Club Deportivo La Equidad (Femenino).txt con 12.57% de similitud.
2025-08-09 00:44:57,538 - INFO - Guardada comparación entre Asociación Civil Transparencia.txt y Dirección General de Atención a las Víctimas y Promoción de la Memoria Democrática.txt con 13.99% de similitud.
2025-08-09 00:44:57,541 - INFO - Guardada comparación entre Asociación Civil Transparencia.txt y Asesoría Jurídica Internacional.txt con 15.01% de similitud.
2025-08-09 00:44:57,544 - INFO - Guardada comparación entre Asociación Civil Transparencia.txt y Desarrollo de videojuegos independiente.txt con 5.51% de similitud.
2025-08-09 00:44:57,547 - INFO - Guardada comparación entre Asociación Civil Transparencia.txt y Ingeniería comercial.txt con 14.21% de similitud.
2025-08-09 00:44:57,550 - INFO - Guardada comparación entre Asociación Civil Transparencia.txt y Chevrolet Cobalt.txt con 5.78% de similitud.
2025-08-09 00:44:57,553 - INFO - Guardada comparación entre Asociación Civil Transparencia.txt y Código Unificado de Punto de Suministro.txt con 13.60% de similitud.
2025-08-09 00:44:57,556 - INFO - Guardada comparación entre Asociación Civil Transparencia.txt y Guerra de guerrillas en la península ibérica durante las guerras napoleónicas.txt con 9.10% de similitud.
2025-08-09 00:44:57,559 - INFO - Guardada comparación entre Asociación Civil Transparencia.txt y Estación de tratamiento de agua potable.txt con 14.30% de similitud.
2025-08-09 00:44:57,563 - INFO - Guardada comparación entre Asociación Civil Transparencia.txt y Militar.txt con 11.32% de similitud.
2025-08-09 00:44:57,566 - INFO - Guardada comparación entre Asociación Civil Transparencia.txt y Demografía de Canadá.txt con 8.78% de similitud.
2025-08-09 00:44:57,569 - INFO - Guardada comparación entre Asociación Civil Transparencia.txt y EToro.txt con 11.72% de similitud.
2025-08-09 00:44:57,572 - INFO - Guardada comparación entre Asociación Civil Transparencia.txt y Ambiente biofísico.txt con 14.70% de similitud.
2025-08-09 00:44:57,575 - INFO - Guardada comparación entre Asociación Civil Transparencia.txt y Juego ganar ganar.txt con 15.44% de similitud.
2025-08-09 00:44:57,579 - INFO - Guardada comparación entre Asociación Civil Transparencia.txt y Declaración de los Derechos de la Mujer y de la Ciudadana.txt con 8.56% de similitud.
2025-08-09 00:44:57,582 - INFO - Guardada comparación entre Asociación Civil Transparencia.txt y Convención Marco de las Naciones Unidas sobre el Cambio Climático.txt con 10.01% de similitud.
2025-08-09 00:44:57,585 - INFO - Guardada comparación entre Asociación Civil Transparencia.txt y Oswald Pohl.txt con 13.52% de similitud.
2025-08-09 00:44:57,588 - INFO - Guardada comparación entre Asociación Civil Transparencia.txt y Empresa Nacional Siderúrgica.txt con 10.67% de similitud.
2025-08-09 00:44:57,592 - INFO - Guardada comparación entre Asociación Civil Transparencia.txt y Teletón El Salvador.txt con 10.43% de similitud.
2025-08-09 00:44:57,595 - INFO - Guardada comparación entre Asociación Civil Transparencia.txt y Antônio de Sousa Neto.txt con 14.34% de similitud.
2025-08-09 00:44:57,598 - INFO - Guardada comparación entre Asociación Civil Transparencia.txt y Mercenarios (BattleTech).txt con 8.27% de similitud.
2025-08-09 00:44:57,601 - INFO - Guardada comparación entre Asociación Civil Transparencia.txt y Efecto cis.txt con 11.84% de similitud.
2025-08-09 00:44:57,605 - INFO - Guardada comparación entre Asociación Civil Transparencia.txt y Demografía de la República Democrática del Congo.txt con 11.70% de similitud.
2025-08-09 00:44:57,609 - INFO - Guardada comparación entre Asociación Civil Transparencia.txt y Desigualdad de ingreso.txt con 5.05% de similitud.
2025-08-09 00:44:57,613 - INFO - Guardada comparación entre Asociación Civil Transparencia.txt y Terrorismo de extrema izquierda.txt con 6.04% de similitud.
2025-08-09 00:44:57,617 - INFO - Guardada comparación entre Medidas activas.txt y Club Deportivo La Equidad (Femenino).txt con 11.62% de similitud.
2025-08-09 00:44:57,621 - INFO - Guardada comparación entre Medidas activas.txt y Dirección General de Atención a las Víctimas y Promoción de la Memoria Democrática.txt con 13.38% de similitud.
2025-08-09 00:44:57,624 - INFO - Guardada comparación entre Medidas activas.txt y Asesoría Jurídica Internacional.txt con 9.05% de similitud.
2025-08-09 00:44:57,628 - INFO - Guardada comparación entre Medidas activas.txt y Desarrollo de videojuegos independiente.txt con 17.89% de similitud.
2025-08-09 00:44:57,632 - INFO - Guardada comparación entre Medidas activas.txt y Ingeniería comercial.txt con 11.71% de similitud.
2025-08-09 00:44:57,635 - INFO - Guardada comparación entre Medidas activas.txt y Chevrolet Cobalt.txt con 2.06% de similitud.
2025-08-09 00:44:57,639 - INFO - Guardada comparación entre Medidas activas.txt y Código Unificado de Punto de Suministro.txt con 11.17% de similitud.
2025-08-09 00:44:57,643 - INFO - Guardada comparación entre Medidas activas.txt y Guerra de guerrillas en la península ibérica durante las guerras napoleónicas.txt con 20.65% de similitud.
2025-08-09 00:44:57,646 - INFO - Guardada comparación entre Medidas activas.txt y Estación de tratamiento de agua potable.txt con 6.43% de similitud.
2025-08-09 00:44:57,649 - INFO - Guardada comparación entre Medidas activas.txt y Militar.txt con 15.47% de similitud.
2025-08-09 00:44:57,653 - INFO - Guardada comparación entre Medidas activas.txt y Demografía de Canadá.txt con 19.14% de similitud.
2025-08-09 00:44:57,657 - INFO - Guardada comparación entre Medidas activas.txt y EToro.txt con 14.46% de similitud.
2025-08-09 00:44:57,660 - INFO - Guardada comparación entre Medidas activas.txt y Ambiente biofísico.txt con 10.28% de similitud.
2025-08-09 00:44:57,664 - INFO - Guardada comparación entre Medidas activas.txt y Juego ganar ganar.txt con 10.67% de similitud.
2025-08-09 00:44:57,667 - INFO - Guardada comparación entre Medidas activas.txt y Declaración de los Derechos de la Mujer y de la Ciudadana.txt con 20.41% de similitud.
2025-08-09 00:44:57,671 - INFO - Guardada comparación entre Medidas activas.txt y Convención Marco de las Naciones Unidas sobre el Cambio Climático.txt con 19.58% de similitud.
2025-08-09 00:44:57,674 - INFO - Guardada comparación entre Medidas activas.txt y Oswald Pohl.txt con 10.45% de similitud.
2025-08-09 00:44:57,678 - INFO - Guardada comparación entre Medidas activas.txt y Guerra de Reforma.txt con 22.27% de similitud.
2025-08-09 00:44:57,682 - INFO - Guardada comparación entre Medidas activas.txt y Teletón El Salvador.txt con 17.38% de similitud.
2025-08-09 00:44:57,686 - INFO - Guardada comparación entre Medidas activas.txt y Antônio de Sousa Neto.txt con 7.58% de similitud.
2025-08-09 00:44:57,689 - INFO - Guardada comparación entre Medidas activas.txt y Mercenarios (BattleTech).txt con 20.02% de similitud.
2025-08-09 00:44:57,693 - INFO - Guardada comparación entre Medidas activas.txt y Emisora móvil.txt con 17.74% de similitud.
2025-08-09 00:44:57,697 - INFO - Guardada comparación entre Medidas activas.txt y Demografía de la República Democrática del Congo.txt con 14.05% de similitud.
2025-08-09 00:44:57,701 - INFO - Guardada comparación entre Medidas activas.txt y Desigualdad de ingreso.txt con 17.88% de similitud.
2025-08-09 00:44:57,706 - INFO - Guardada comparación entre Medidas activas.txt y Terrorismo de extrema izquierda.txt con 22.17% de similitud.
2025-08-09 00:44:57,711 - INFO - Guardada comparación entre Estéfany Grajales.txt y Iberos.txt con 1.97% de similitud.
2025-08-09 00:44:57,714 - INFO - Guardada comparación entre Estéfany Grajales.txt y .km.txt con 8.89% de similitud.
2025-08-09 00:44:57,717 - INFO - Guardada comparación entre Estéfany Grajales.txt y Censura internacional china.txt con 7.29% de similitud.
2025-08-09 00:44:57,721 - INFO - Guardada comparación entre Estéfany Grajales.txt y Alfarería en la provincia de Almería.txt con 6.44% de similitud.
2025-08-09 00:44:57,724 - INFO - Guardada comparación entre Estéfany Grajales.txt y Acuerdo de Prespa.txt con 15.71% de similitud.
2025-08-09 00:44:57,727 - INFO - Guardada comparación entre Estéfany Grajales.txt y Segunda Cumbre BRIC 2010.txt con 10.45% de similitud.
2025-08-09 00:44:57,730 - INFO - Guardada comparación entre Estéfany Grajales.txt y Santa Marina del Rey.txt con 11.64% de similitud.
2025-08-09 00:44:57,733 - INFO - Guardada comparación entre Estéfany Grajales.txt y Omaira Montoya Henao.txt con 16.86% de similitud.
2025-08-09 00:44:57,736 - INFO - Guardada comparación entre Estéfany Grajales.txt y Biodiversidad Virtual.txt con 10.64% de similitud.
2025-08-09 00:44:57,739 - INFO - Guardada comparación entre Estéfany Grajales.txt y Estudios de ciencia, tecnología y género.txt con 10.31% de similitud.
2025-08-09 00:44:57,742 - INFO - Guardada comparación entre Estéfany Grajales.txt y Representación (política).txt con 12.04% de similitud.
2025-08-09 00:44:57,745 - INFO - Guardada comparación entre Estéfany Grajales.txt y Roxana Campos.txt con 14.50% de similitud.
2025-08-09 00:44:57,750 - INFO - Guardada comparación entre Estéfany Grajales.txt y Reforma económica china.txt con 2.31% de similitud.
2025-08-09 00:44:57,753 - INFO - Guardada comparación entre Estéfany Grajales.txt y Declaración de los Derechos de la Mujer y de la Ciudadana.txt con 7.68% de similitud.
2025-08-09 00:44:57,756 - INFO - Guardada comparación entre Estéfany Grajales.txt y Violencia obstétrica.txt con 14.46% de similitud.
2025-08-09 00:44:57,759 - INFO - Guardada comparación entre Estéfany Grajales.txt y Torrente Gros.txt con 10.42% de similitud.
2025-08-09 00:44:57,763 - INFO - Guardada comparación entre Estéfany Grajales.txt y Guerra de Reforma.txt con 7.15% de similitud.
2025-08-09 00:44:57,766 - INFO - Guardada comparación entre Estéfany Grajales.txt y Teletón El Salvador.txt con 8.55% de similitud.
2025-08-09 00:44:57,769 - INFO - Guardada comparación entre Estéfany Grajales.txt y Antônio de Sousa Neto.txt con 14.42% de similitud.
2025-08-09 00:44:57,773 - INFO - Guardada comparación entre Estéfany Grajales.txt y Unión Ortodoxa.txt con 10.95% de similitud.
2025-08-09 00:44:57,778 - INFO - Guardada comparación entre Estéfany Grajales.txt y Emisora móvil.txt con 4.23% de similitud.
2025-08-09 00:44:57,781 - INFO - Guardada comparación entre Estéfany Grajales.txt y Demografía de la República Democrática del Congo.txt con 9.08% de similitud.
2025-08-09 00:44:57,785 - INFO - Guardada comparación entre Estéfany Grajales.txt y Desigualdad de ingreso.txt con 3.78% de similitud.
2025-08-09 00:44:57,789 - INFO - Guardada comparación entre Estéfany Grajales.txt y Terrorismo de extrema izquierda.txt con 4.59% de similitud.
2025-08-09 00:44:57,801 - INFO - Guardada comparación entre Sputnik V.txt y Iberos.txt con 14.63% de similitud.
2025-08-09 00:44:57,809 - INFO - Guardada comparación entre Sputnik V.txt y Dirección General de Atención a las Víctimas y Promoción de la Memoria Democrática.txt con 1.65% de similitud.
2025-08-09 00:44:57,817 - INFO - Guardada comparación entre Sputnik V.txt y Asesoría Jurídica Internacional.txt con 1.10% de similitud.
2025-08-09 00:44:57,826 - INFO - Guardada comparación entre Sputnik V.txt y Desarrollo de videojuegos independiente.txt con 6.95% de similitud.
2025-08-09 00:44:57,834 - INFO - Guardada comparación entre Sputnik V.txt y Ingeniería comercial.txt con 1.49% de similitud.
2025-08-09 00:44:57,842 - INFO - Guardada comparación entre Sputnik V.txt y Chevrolet Cobalt.txt con 0.22% de similitud.
2025-08-09 00:44:57,850 - INFO - Guardada comparación entre Sputnik V.txt y Código Unificado de Punto de Suministro.txt con 1.85% de similitud.
2025-08-09 00:44:57,858 - INFO - Guardada comparación entre Sputnik V.txt y Guerra de guerrillas en la península ibérica durante las guerras napoleónicas.txt con 3.55% de similitud.
2025-08-09 00:44:57,866 - INFO - Guardada comparación entre Sputnik V.txt y Estación de tratamiento de agua potable.txt con 0.85% de similitud.
2025-08-09 00:44:57,874 - INFO - Guardada comparación entre Sputnik V.txt y Militar.txt con 2.22% de similitud.
2025-08-09 00:44:57,886 - INFO - Guardada comparación entre Sputnik V.txt y Demografía de Canadá.txt con 4.43% de similitud.
2025-08-09 00:44:57,898 - INFO - Guardada comparación entre Sputnik V.txt y EToro.txt con 2.24% de similitud.
2025-08-09 00:44:57,911 - INFO - Guardada comparación entre Sputnik V.txt y Ambiente biofísico.txt con 1.35% de similitud.
2025-08-09 00:44:57,919 - INFO - Guardada comparación entre Sputnik V.txt y Juego ganar ganar.txt con 1.47% de similitud.
2025-08-09 00:44:57,928 - INFO - Guardada comparación entre Sputnik V.txt y Declaración de los Derechos de la Mujer y de la Ciudadana.txt con 3.80% de similitud.
2025-08-09 00:44:57,937 - INFO - Guardada comparación entre Sputnik V.txt y Convención Marco de las Naciones Unidas sobre el Cambio Climático.txt con 3.31% de similitud.
2025-08-09 00:44:57,945 - INFO - Guardada comparación entre Sputnik V.txt y Oswald Pohl.txt con 1.19% de similitud.
2025-08-09 00:44:57,953 - INFO - Guardada comparación entre Sputnik V.txt y Empresa Nacional Siderúrgica.txt con 2.79% de similitud.
2025-08-09 00:44:57,962 - INFO - Guardada comparación entre Sputnik V.txt y Teletón El Salvador.txt con 2.96% de similitud.
2025-08-09 00:44:57,970 - INFO - Guardada comparación entre Sputnik V.txt y Antônio de Sousa Neto.txt con 0.85% de similitud.
2025-08-09 00:44:57,979 - INFO - Guardada comparación entre Sputnik V.txt y Mercenarios (BattleTech).txt con 3.28% de similitud.
2025-08-09 00:44:57,987 - INFO - Guardada comparación entre Sputnik V.txt y Efecto cis.txt con 2.36% de similitud.
2025-08-09 00:44:57,995 - INFO - Guardada comparación entre Sputnik V.txt y Demografía de la República Democrática del Congo.txt con 2.74% de similitud.
2025-08-09 00:44:58,004 - INFO - Guardada comparación entre Sputnik V.txt y Desigualdad de ingreso.txt con 7.94% de similitud.
2025-08-09 00:44:58,013 - INFO - Guardada comparación entre Sputnik V.txt y Terrorismo de extrema izquierda.txt con 7.14% de similitud.
2025-08-09 00:44:58,018 - INFO - Guardada comparación entre Día Naranja.txt y Iberos.txt con 2.73% de similitud.
2025-08-09 00:44:58,021 - INFO - Guardada comparación entre Día Naranja.txt y .km.txt con 10.44% de similitud.
2025-08-09 00:44:58,024 - INFO - Guardada comparación entre Día Naranja.txt y Censura internacional china.txt con 9.80% de similitud.
2025-08-09 00:44:58,027 - INFO - Guardada comparación entre Día Naranja.txt y Alfarería en la provincia de Almería.txt con 8.32% de similitud.
2025-08-09 00:44:58,030 - INFO - Guardada comparación entre Día Naranja.txt y Acuerdo de Prespa.txt con 13.79% de similitud.
2025-08-09 00:44:58,034 - INFO - Guardada comparación entre Día Naranja.txt y Segunda Cumbre BRIC 2010.txt con 13.09% de similitud.
2025-08-09 00:44:58,037 - INFO - Guardada comparación entre Día Naranja.txt y Santa Marina del Rey.txt con 13.53% de similitud.
2025-08-09 00:44:58,040 - INFO - Guardada comparación entre Día Naranja.txt y Omaira Montoya Henao.txt con 14.45% de similitud.
2025-08-09 00:44:58,043 - INFO - Guardada comparación entre Día Naranja.txt y Biodiversidad Virtual.txt con 14.37% de similitud.
2025-08-09 00:44:58,047 - INFO - Guardada comparación entre Día Naranja.txt y Estudios de ciencia, tecnología y género.txt con 13.66% de similitud.
2025-08-09 00:44:58,050 - INFO - Guardada comparación entre Día Naranja.txt y Representación (política).txt con 13.39% de similitud.
2025-08-09 00:44:58,053 - INFO - Guardada comparación entre Día Naranja.txt y Roxana Campos.txt con 14.48% de similitud.
2025-08-09 00:44:58,057 - INFO - Guardada comparación entre Día Naranja.txt y Reforma económica china.txt con 3.21% de similitud.
2025-08-09 00:44:58,061 - INFO - Guardada comparación entre Día Naranja.txt y Alejandro VII.txt con 10.92% de similitud.
2025-08-09 00:44:58,064 - INFO - Guardada comparación entre Día Naranja.txt y Violencia obstétrica.txt con 16.07% de similitud.
2025-08-09 00:44:58,067 - INFO - Guardada comparación entre Día Naranja.txt y Torrente Gros.txt con 12.91% de similitud.
2025-08-09 00:44:58,071 - INFO - Guardada comparación entre Día Naranja.txt y Guerra de Reforma.txt con 8.50% de similitud.
2025-08-09 00:44:58,074 - INFO - Guardada comparación entre Día Naranja.txt y Certificate Signing Request.txt con 7.28% de similitud.
2025-08-09 00:44:58,078 - INFO - Guardada comparación entre Día Naranja.txt y Katalin Bogyay.txt con 9.29% de similitud.
2025-08-09 00:44:58,081 - INFO - Guardada comparación entre Día Naranja.txt y Unión Ortodoxa.txt con 12.26% de similitud.
2025-08-09 00:44:58,085 - INFO - Guardada comparación entre Día Naranja.txt y Emisora móvil.txt con 6.07% de similitud.
2025-08-09 00:44:58,088 - INFO - Guardada comparación entre Día Naranja.txt y Sanción.txt con 3.32% de similitud.
2025-08-09 00:44:58,091 - INFO - Guardada comparación entre Día Naranja.txt y Saúl Luciano Lliuya.txt con 15.74% de similitud.
2025-08-09 00:44:58,094 - INFO - Guardada comparación entre Día Naranja.txt y Antiprotestantismo.txt con 11.52% de similitud.
2025-08-09 00:44:58,098 - INFO - Guardada comparación entre Negro de carbón.txt y Desigualdad de ingreso en Estados Unidos.txt con 16.13% de similitud.
2025-08-09 00:44:58,104 - INFO - Guardada comparación entre Negro de carbón.txt y Iberos.txt con 4.43% de similitud.
2025-08-09 00:44:58,108 - INFO - Guardada comparación entre Negro de carbón.txt y .km.txt con 10.24% de similitud.
2025-08-09 00:44:58,112 - INFO - Guardada comparación entre Negro de carbón.txt y Censura internacional china.txt con 12.10% de similitud.
2025-08-09 00:44:58,115 - INFO - Guardada comparación entre Negro de carbón.txt y Alfarería en la provincia de Almería.txt con 12.17% de similitud.
2025-08-09 00:44:58,119 - INFO - Guardada comparación entre Negro de carbón.txt y Acuerdo de Prespa.txt con 10.82% de similitud.
2025-08-09 00:44:58,122 - INFO - Guardada comparación entre Negro de carbón.txt y Segunda Cumbre BRIC 2010.txt con 16.75% de similitud.
2025-08-09 00:44:58,125 - INFO - Guardada comparación entre Negro de carbón.txt y Santa Marina del Rey.txt con 16.03% de similitud.
2025-08-09 00:44:58,128 - INFO - Guardada comparación entre Negro de carbón.txt y Omaira Montoya Henao.txt con 15.87% de similitud.
2025-08-09 00:44:58,132 - INFO - Guardada comparación entre Negro de carbón.txt y Biodiversidad Virtual.txt con 16.90% de similitud.
2025-08-09 00:44:58,136 - INFO - Guardada comparación entre Negro de carbón.txt y Estudios de ciencia, tecnología y género.txt con 15.48% de similitud.
2025-08-09 00:44:58,139 - INFO - Guardada comparación entre Negro de carbón.txt y Representación (política).txt con 17.32% de similitud.
2025-08-09 00:44:58,142 - INFO - Guardada comparación entre Negro de carbón.txt y Roxana Campos.txt con 13.41% de similitud.
2025-08-09 00:44:58,147 - INFO - Guardada comparación entre Negro de carbón.txt y Reforma económica china.txt con 4.87% de similitud.
2025-08-09 00:44:58,151 - INFO - Guardada comparación entre Negro de carbón.txt y Alejandro VII.txt con 14.84% de similitud.
2025-08-09 00:44:58,154 - INFO - Guardada comparación entre Negro de carbón.txt y Violencia obstétrica.txt con 16.67% de similitud.
2025-08-09 00:44:58,158 - INFO - Guardada comparación entre Negro de carbón.txt y Torrente Gros.txt con 17.75% de similitud.
2025-08-09 00:44:58,161 - INFO - Guardada comparación entre Negro de carbón.txt y Guerra de Reforma.txt con 11.89% de similitud.
2025-08-09 00:44:58,165 - INFO - Guardada comparación entre Negro de carbón.txt y Certificate Signing Request.txt con 10.17% de similitud.
2025-08-09 00:44:58,168 - INFO - Guardada comparación entre Negro de carbón.txt y Katalin Bogyay.txt con 10.83% de similitud.
2025-08-09 00:44:58,173 - INFO - Guardada comparación entre Negro de carbón.txt y Mercenarios (BattleTech).txt con 13.12% de similitud.
2025-08-09 00:44:58,176 - INFO - Guardada comparación entre Negro de carbón.txt y Emisora móvil.txt con 9.11% de similitud.
2025-08-09 00:44:58,180 - INFO - Guardada comparación entre Negro de carbón.txt y Demografía de la República Democrática del Congo.txt con 16.70% de similitud.
2025-08-09 00:44:58,185 - INFO - Guardada comparación entre Negro de carbón.txt y Desigualdad de ingreso.txt con 8.19% de similitud.
2025-08-09 00:44:58,190 - INFO - Guardada comparación entre Negro de carbón.txt y Terrorismo de extrema izquierda.txt con 8.76% de similitud.
2025-08-09 00:44:58,196 - INFO - Guardada comparación entre Microsoft Anti-Virus.txt y Iberos.txt con 1.52% de similitud.
2025-08-09 00:44:58,199 - INFO - Guardada comparación entre Microsoft Anti-Virus.txt y .km.txt con 10.66% de similitud.
2025-08-09 00:44:58,203 - INFO - Guardada comparación entre Microsoft Anti-Virus.txt y Censura internacional china.txt con 5.10% de similitud.
2025-08-09 00:44:58,206 - INFO - Guardada comparación entre Microsoft Anti-Virus.txt y Alfarería en la provincia de Almería.txt con 4.59% de similitud.
2025-08-09 00:44:58,209 - INFO - Guardada comparación entre Microsoft Anti-Virus.txt y Acuerdo de Prespa.txt con 14.33% de similitud.
2025-08-09 00:44:58,213 - INFO - Guardada comparación entre Microsoft Anti-Virus.txt y Segunda Cumbre BRIC 2010.txt con 8.35% de similitud.
2025-08-09 00:44:58,216 - INFO - Guardada comparación entre Microsoft Anti-Virus.txt y Santa Marina del Rey.txt con 10.95% de similitud.
2025-08-09 00:44:58,219 - INFO - Guardada comparación entre Microsoft Anti-Virus.txt y Omaira Montoya Henao.txt con 11.37% de similitud.
2025-08-09 00:44:58,222 - INFO - Guardada comparación entre Microsoft Anti-Virus.txt y Biodiversidad Virtual.txt con 9.89% de similitud.
2025-08-09 00:44:58,225 - INFO - Guardada comparación entre Microsoft Anti-Virus.txt y Estudios de ciencia, tecnología y género.txt con 7.47% de similitud.
2025-08-09 00:44:58,228 - INFO - Guardada comparación entre Microsoft Anti-Virus.txt y Representación (política).txt con 8.14% de similitud.
2025-08-09 00:44:58,232 - INFO - Guardada comparación entre Microsoft Anti-Virus.txt y Roxana Campos.txt con 11.45% de similitud.
2025-08-09 00:44:58,236 - INFO - Guardada comparación entre Microsoft Anti-Virus.txt y Reforma económica china.txt con 1.85% de similitud.
2025-08-09 00:44:58,239 - INFO - Guardada comparación entre Microsoft Anti-Virus.txt y Alejandro VII.txt con 7.07% de similitud.
2025-08-09 00:44:58,243 - INFO - Guardada comparación entre Microsoft Anti-Virus.txt y Violencia obstétrica.txt con 8.36% de similitud.
2025-08-09 00:44:58,246 - INFO - Guardada comparación entre Microsoft Anti-Virus.txt y Torrente Gros.txt con 8.36% de similitud.
2025-08-09 00:44:58,249 - INFO - Guardada comparación entre Microsoft Anti-Virus.txt y Guerra de Reforma.txt con 5.13% de similitud.
2025-08-09 00:44:58,252 - INFO - Guardada comparación entre Microsoft Anti-Virus.txt y Certificate Signing Request.txt con 5.35% de similitud.
2025-08-09 00:44:58,256 - INFO - Guardada comparación entre Microsoft Anti-Virus.txt y Katalin Bogyay.txt con 4.67% de similitud.
2025-08-09 00:44:58,259 - INFO - Guardada comparación entre Microsoft Anti-Virus.txt y Unión Ortodoxa.txt con 7.72% de similitud.
2025-08-09 00:44:58,263 - INFO - Guardada comparación entre Microsoft Anti-Virus.txt y Emisora móvil.txt con 3.57% de similitud.
2025-08-09 00:44:58,266 - INFO - Guardada comparación entre Microsoft Anti-Virus.txt y Demografía de la República Democrática del Congo.txt con 7.35% de similitud.
2025-08-09 00:44:58,270 - INFO - Guardada comparación entre Microsoft Anti-Virus.txt y Desigualdad de ingreso.txt con 2.81% de similitud.
2025-08-09 00:44:58,274 - INFO - Guardada comparación entre Microsoft Anti-Virus.txt y Terrorismo de extrema izquierda.txt con 3.58% de similitud.
2025-08-09 00:44:58,278 - INFO - Guardada comparación entre Dirección General de Logística Informativa.txt y Iberos.txt con 2.17% de similitud.
2025-08-09 00:44:58,281 - INFO - Guardada comparación entre Dirección General de Logística Informativa.txt y .km.txt con 9.51% de similitud.
2025-08-09 00:44:58,285 - INFO - Guardada comparación entre Dirección General de Logística Informativa.txt y Censura internacional china.txt con 8.43% de similitud.
2025-08-09 00:44:58,288 - INFO - Guardada comparación entre Dirección General de Logística Informativa.txt y Alfarería en la provincia de Almería.txt con 7.11% de similitud.
2025-08-09 00:44:58,291 - INFO - Guardada comparación entre Dirección General de Logística Informativa.txt y Ingeniería comercial.txt con 15.79% de similitud.
2025-08-09 00:44:58,294 - INFO - Guardada comparación entre Dirección General de Logística Informativa.txt y Segunda Cumbre BRIC 2010.txt con 12.82% de similitud.
2025-08-09 00:44:58,297 - INFO - Guardada comparación entre Dirección General de Logística Informativa.txt y Código Unificado de Punto de Suministro.txt con 12.44% de similitud.
2025-08-09 00:44:58,303 - INFO - Guardada comparación entre Dirección General de Logística Informativa.txt y Santa Marina del Rey.txt con 14.06% de similitud.
2025-08-09 00:44:58,306 - INFO - Guardada comparación entre Dirección General de Logística Informativa.txt y Biodiversidad Virtual.txt con 14.30% de similitud.
2025-08-09 00:44:58,309 - INFO - Guardada comparación entre Dirección General de Logística Informativa.txt y Estudios de ciencia, tecnología y género.txt con 11.39% de similitud.
2025-08-09 00:44:58,312 - INFO - Guardada comparación entre Dirección General de Logística Informativa.txt y Representación (política).txt con 12.52% de similitud.
2025-08-09 00:44:58,316 - INFO - Guardada comparación entre Dirección General de Logística Informativa.txt y EToro.txt con 12.19% de similitud.
2025-08-09 00:44:58,320 - INFO - Guardada comparación entre Dirección General de Logística Informativa.txt y Reforma económica china.txt con 2.67% de similitud.
2025-08-09 00:44:58,324 - INFO - Guardada comparación entre Dirección General de Logística Informativa.txt y Alejandro VII.txt con 10.32% de similitud.
2025-08-09 00:44:58,327 - INFO - Guardada comparación entre Dirección General de Logística Informativa.txt y Violencia obstétrica.txt con 14.46% de similitud.
2025-08-09 00:44:58,330 - INFO - Guardada comparación entre Dirección General de Logística Informativa.txt y Torrente Gros.txt con 12.71% de similitud.
2025-08-09 00:44:58,333 - INFO - Guardada comparación entre Dirección General de Logística Informativa.txt y Guerra de Reforma.txt con 8.33% de similitud.
2025-08-09 00:44:58,337 - INFO - Guardada comparación entre Dirección General de Logística Informativa.txt y Certificate Signing Request.txt con 6.24% de similitud.
2025-08-09 00:44:58,340 - INFO - Guardada comparación entre Dirección General de Logística Informativa.txt y Katalin Bogyay.txt con 7.35% de similitud.
2025-08-09 00:44:58,343 - INFO - Guardada comparación entre Dirección General de Logística Informativa.txt y Unión Ortodoxa.txt con 12.50% de similitud.
2025-08-09 00:44:58,347 - INFO - Guardada comparación entre Dirección General de Logística Informativa.txt y Emisora móvil.txt con 5.22% de similitud.
2025-08-09 00:44:58,349 - INFO - Guardada comparación entre Dirección General de Logística Informativa.txt y Sanción.txt con 3.99% de similitud.
2025-08-09 00:44:58,352 - INFO - Guardada comparación entre Dirección General de Logística Informativa.txt y Saúl Luciano Lliuya.txt con 14.36% de similitud.
2025-08-09 00:44:58,356 - INFO - Guardada comparación entre Dirección General de Logística Informativa.txt y Antiprotestantismo.txt con 9.90% de similitud.
2025-08-09 00:44:58,359 - INFO - Guardada comparación entre Criptografía híbrida.txt y Desigualdad de ingreso en Estados Unidos.txt con 7.82% de similitud.
2025-08-09 00:44:58,362 - INFO - Guardada comparación entre Criptografía híbrida.txt y Club Deportivo La Equidad (Femenino).txt con 8.48% de similitud.
2025-08-09 00:44:58,365 - INFO - Guardada comparación entre Criptografía híbrida.txt y .km.txt con 10.20% de similitud.
2025-08-09 00:44:58,368 - INFO - Guardada comparación entre Criptografía híbrida.txt y Asesoría Jurídica Internacional.txt con 10.83% de similitud.
2025-08-09 00:44:58,371 - INFO - Guardada comparación entre Criptografía híbrida.txt y Desarrollo de videojuegos independiente.txt con 3.16% de similitud.
2025-08-09 00:44:58,374 - INFO - Guardada comparación entre Criptografía híbrida.txt y Ingeniería comercial.txt con 10.03% de similitud.
2025-08-09 00:44:58,377 - INFO - Guardada comparación entre Criptografía híbrida.txt y Chevrolet Cobalt.txt con 6.92% de similitud.
2025-08-09 00:44:58,380 - INFO - Guardada comparación entre Criptografía híbrida.txt y Código Unificado de Punto de Suministro.txt con 9.07% de similitud.
2025-08-09 00:44:58,383 - INFO - Guardada comparación entre Criptografía híbrida.txt y Guerra de guerrillas en la península ibérica durante las guerras napoleónicas.txt con 5.50% de similitud.
2025-08-09 00:44:58,386 - INFO - Guardada comparación entre Criptografía híbrida.txt y Estación de tratamiento de agua potable.txt con 12.52% de similitud.
2025-08-09 00:44:58,389 - INFO - Guardada comparación entre Criptografía híbrida.txt y Militar.txt con 8.93% de similitud.
2025-08-09 00:44:58,392 - INFO - Guardada comparación entre Criptografía híbrida.txt y Demografía de Canadá.txt con 4.88% de similitud.
2025-08-09 00:44:58,395 - INFO - Guardada comparación entre Criptografía híbrida.txt y EToro.txt con 7.21% de similitud.
2025-08-09 00:44:58,398 - INFO - Guardada comparación entre Criptografía híbrida.txt y Ambiente biofísico.txt con 11.15% de similitud.
2025-08-09 00:44:58,401 - INFO - Guardada comparación entre Criptografía híbrida.txt y Juego ganar ganar.txt con 12.15% de similitud.
2025-08-09 00:44:58,404 - INFO - Guardada comparación entre Criptografía híbrida.txt y Declaración de los Derechos de la Mujer y de la Ciudadana.txt con 5.76% de similitud.
2025-08-09 00:44:58,407 - INFO - Guardada comparación entre Criptografía híbrida.txt y Convención Marco de las Naciones Unidas sobre el Cambio Climático.txt con 6.52% de similitud.
2025-08-09 00:44:58,410 - INFO - Guardada comparación entre Criptografía híbrida.txt y Oswald Pohl.txt con 9.51% de similitud.
2025-08-09 00:44:58,413 - INFO - Guardada comparación entre Criptografía híbrida.txt y Empresa Nacional Siderúrgica.txt con 5.95% de similitud.
2025-08-09 00:44:58,416 - INFO - Guardada comparación entre Criptografía híbrida.txt y Teletón El Salvador.txt con 6.67% de similitud.
2025-08-09 00:44:58,419 - INFO - Guardada comparación entre Criptografía híbrida.txt y Antônio de Sousa Neto.txt con 11.36% de similitud.
2025-08-09 00:44:58,422 - INFO - Guardada comparación entre Criptografía híbrida.txt y Mercenarios (BattleTech).txt con 5.61% de similitud.
2025-08-09 00:44:58,425 - INFO - Guardada comparación entre Criptografía híbrida.txt y Efecto cis.txt con 8.28% de similitud.
2025-08-09 00:44:58,428 - INFO - Guardada comparación entre Criptografía híbrida.txt y Sanción.txt con 5.26% de similitud.
2025-08-09 00:44:58,431 - INFO - Guardada comparación entre Criptografía híbrida.txt y Saúl Luciano Lliuya.txt con 9.64% de similitud.
2025-08-09 00:44:58,434 - INFO - Guardada comparación entre Criptografía híbrida.txt y Antiprotestantismo.txt con 5.97% de similitud.
2025-08-09 00:44:58,438 - INFO - Guardada comparación entre Criptografía híbrida.txt y Terrorismo de extrema izquierda.txt con 3.06% de similitud.
2025-08-09 00:44:58,442 - INFO - Guardada comparación entre Ciclismo en los Juegos Europeos de Minsk 2019.txt y Iberos.txt con 0.83% de similitud.
2025-08-09 00:44:58,445 - INFO - Guardada comparación entre Ciclismo en los Juegos Europeos de Minsk 2019.txt y .km.txt con 8.12% de similitud.
2025-08-09 00:44:58,448 - INFO - Guardada comparación entre Ciclismo en los Juegos Europeos de Minsk 2019.txt y Censura internacional china.txt con 3.49% de similitud.
2025-08-09 00:44:58,451 - INFO - Guardada comparación entre Ciclismo en los Juegos Europeos de Minsk 2019.txt y Alfarería en la provincia de Almería.txt con 2.81% de similitud.
2025-08-09 00:44:58,455 - INFO - Guardada comparación entre Ciclismo en los Juegos Europeos de Minsk 2019.txt y Ingeniería comercial.txt con 7.38% de similitud.
2025-08-09 00:44:58,458 - INFO - Guardada comparación entre Ciclismo en los Juegos Europeos de Minsk 2019.txt y Segunda Cumbre BRIC 2010.txt con 5.79% de similitud.
2025-08-09 00:44:58,460 - INFO - Guardada comparación entre Ciclismo en los Juegos Europeos de Minsk 2019.txt y Santa Marina del Rey.txt con 7.58% de similitud.
2025-08-09 00:44:58,463 - INFO - Guardada comparación entre Ciclismo en los Juegos Europeos de Minsk 2019.txt y Omaira Montoya Henao.txt con 8.63% de similitud.
2025-08-09 00:44:58,466 - INFO - Guardada comparación entre Ciclismo en los Juegos Europeos de Minsk 2019.txt y Biodiversidad Virtual.txt con 6.74% de similitud.
2025-08-09 00:44:58,469 - INFO - Guardada comparación entre Ciclismo en los Juegos Europeos de Minsk 2019.txt y Estudios de ciencia, tecnología y género.txt con 4.84% de similitud.
2025-08-09 00:44:58,472 - INFO - Guardada comparación entre Ciclismo en los Juegos Europeos de Minsk 2019.txt y Representación (política).txt con 5.67% de similitud.
2025-08-09 00:44:58,476 - INFO - Guardada comparación entre Ciclismo en los Juegos Europeos de Minsk 2019.txt y Roxana Campos.txt con 10.01% de similitud.
2025-08-09 00:44:58,480 - INFO - Guardada comparación entre Ciclismo en los Juegos Europeos de Minsk 2019.txt y Reforma económica china.txt con 1.00% de similitud.
2025-08-09 00:44:58,483 - INFO - Guardada comparación entre Ciclismo en los Juegos Europeos de Minsk 2019.txt y Alejandro VII.txt con 4.75% de similitud.
2025-08-09 00:44:58,489 - INFO - Guardada comparación entre Ciclismo en los Juegos Europeos de Minsk 2019.txt y Violencia obstétrica.txt con 5.36% de similitud.
2025-08-09 00:44:58,492 - INFO - Guardada comparación entre Ciclismo en los Juegos Europeos de Minsk 2019.txt y Guerra de Reforma.txt con 3.03% de similitud.
2025-08-09 00:44:58,496 - INFO - Guardada comparación entre Ciclismo en los Juegos Europeos de Minsk 2019.txt y Certificate Signing Request.txt con 2.87% de similitud.
2025-08-09 00:44:58,499 - INFO - Guardada comparación entre Ciclismo en los Juegos Europeos de Minsk 2019.txt y Katalin Bogyay.txt con 2.92% de similitud.
2025-08-09 00:44:58,502 - INFO - Guardada comparación entre Ciclismo en los Juegos Europeos de Minsk 2019.txt y Unión Ortodoxa.txt con 5.06% de similitud.
2025-08-09 00:44:58,506 - INFO - Guardada comparación entre Ciclismo en los Juegos Europeos de Minsk 2019.txt y Emisora móvil.txt con 2.03% de similitud.
2025-08-09 00:44:58,508 - INFO - Guardada comparación entre Ciclismo en los Juegos Europeos de Minsk 2019.txt y Sanción.txt con 6.58% de similitud.
2025-08-09 00:44:58,511 - INFO - Guardada comparación entre Ciclismo en los Juegos Europeos de Minsk 2019.txt y Saúl Luciano Lliuya.txt con 10.32% de similitud.
2025-08-09 00:44:58,514 - INFO - Guardada comparación entre Ciclismo en los Juegos Europeos de Minsk 2019.txt y Antiprotestantismo.txt con 4.37% de similitud.
2025-08-09 00:44:58,517 - INFO - Guardada comparación entre Relaciones España-Finlandia.txt y Desigualdad de ingreso en Estados Unidos.txt con 18.11% de similitud.
2025-08-09 00:44:58,523 - INFO - Guardada comparación entre Relaciones España-Finlandia.txt y Iberos.txt con 4.99% de similitud.
2025-08-09 00:44:58,526 - INFO - Guardada comparación entre Relaciones España-Finlandia.txt y .km.txt con 8.77% de similitud.
2025-08-09 00:44:58,530 - INFO - Guardada comparación entre Relaciones España-Finlandia.txt y Censura internacional china.txt con 14.72% de similitud.
2025-08-09 00:44:58,533 - INFO - Guardada comparación entre Relaciones España-Finlandia.txt y Alfarería en la provincia de Almería.txt con 13.31% de similitud.
2025-08-09 00:44:58,536 - INFO - Guardada comparación entre Relaciones España-Finlandia.txt y Acuerdo de Prespa.txt con 9.82% de similitud.
2025-08-09 00:44:58,540 - INFO - Guardada comparación entre Relaciones España-Finlandia.txt y Segunda Cumbre BRIC 2010.txt con 19.37% de similitud.
2025-08-09 00:44:58,543 - INFO - Guardada comparación entre Relaciones España-Finlandia.txt y Santa Marina del Rey.txt con 15.42% de similitud.
2025-08-09 00:44:58,546 - INFO - Guardada comparación entre Relaciones España-Finlandia.txt y Omaira Montoya Henao.txt con 18.60% de similitud.
2025-08-09 00:44:58,550 - INFO - Guardada comparación entre Relaciones España-Finlandia.txt y Biodiversidad Virtual.txt con 18.93% de similitud.
2025-08-09 00:44:58,553 - INFO - Guardada comparación entre Relaciones España-Finlandia.txt y Estudios de ciencia, tecnología y género.txt con 18.39% de similitud.
2025-08-09 00:44:58,556 - INFO - Guardada comparación entre Relaciones España-Finlandia.txt y Representación (política).txt con 18.64% de similitud.
2025-08-09 00:44:58,559 - INFO - Guardada comparación entre Relaciones España-Finlandia.txt y Roxana Campos.txt con 13.19% de similitud.
2025-08-09 00:44:58,564 - INFO - Guardada comparación entre Relaciones España-Finlandia.txt y Reforma económica china.txt con 6.23% de similitud.
2025-08-09 00:44:58,567 - INFO - Guardada comparación entre Relaciones España-Finlandia.txt y Alejandro VII.txt con 17.53% de similitud.
2025-08-09 00:44:58,571 - INFO - Guardada comparación entre Relaciones España-Finlandia.txt y Violencia obstétrica.txt con 18.68% de similitud.
2025-08-09 00:44:58,574 - INFO - Guardada comparación entre Relaciones España-Finlandia.txt y Torrente Gros.txt con 19.27% de similitud.
2025-08-09 00:44:58,578 - INFO - Guardada comparación entre Relaciones España-Finlandia.txt y Guerra de Reforma.txt con 15.54% de similitud.
2025-08-09 00:44:58,581 - INFO - Guardada comparación entre Relaciones España-Finlandia.txt y Certificate Signing Request.txt con 9.38% de similitud.
2025-08-09 00:44:58,585 - INFO - Guardada comparación entre Relaciones España-Finlandia.txt y Katalin Bogyay.txt con 13.31% de similitud.
2025-08-09 00:44:58,589 - INFO - Guardada comparación entre Relaciones España-Finlandia.txt y Mercenarios (BattleTech).txt con 14.61% de similitud.
2025-08-09 00:44:58,593 - INFO - Guardada comparación entre Relaciones España-Finlandia.txt y Efecto cis.txt con 16.18% de similitud.
2025-08-09 00:44:58,596 - INFO - Guardada comparación entre Relaciones España-Finlandia.txt y Sanción.txt con 2.47% de similitud.
2025-08-09 00:44:58,599 - INFO - Guardada comparación entre Relaciones España-Finlandia.txt y Saúl Luciano Lliuya.txt con 13.65% de similitud.
2025-08-09 00:44:58,602 - INFO - Guardada comparación entre Relaciones España-Finlandia.txt y Antiprotestantismo.txt con 16.94% de similitud.

Some files were not shown because too many files have changed in this diff Show more