Fix Boostrap y Try Cache

This commit is contained in:
2025-09-10 14:20:44 -03:00
parent 6309003536
commit 153c0f92da
14 changed files with 276 additions and 142 deletions

View File

@@ -1,24 +1,33 @@
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
# Añadimos una ubicación específica para los archivos .mjs
location ~ \.mjs$ {
# Incluimos los tipos MIME por defecto para que Nginx pueda inferir otros tipos si es necesario
include /etc/nginx/mime.types;
# Forzamos explícitamente el tipo de contenido para esta ubicación
default_type application/javascript;
# --- NUEVO BLOQUE ESPECÍFICO PARA BOOTSTRAP.JS ---
location = /bootstrap.js {
# Esta cabecera le dice a los proxies que deben revalidar el archivo
# con el servidor de origen antes de servirlo desde la caché.
add_header Cache-Control "no-cache, must-revalidate";
# 'expires off' es otra capa de seguridad para evitar que se cachee
expires off;
# Intenta servir el archivo. Si no existe, devuelve 404.
try_files $uri =404;
}
# Bloque para otros activos estáticos (con hash) que SÍ pueden ser cacheados agresivamente
location ~* \.(?:js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
# Estos archivos cambian de nombre en cada build, así que pueden
# ser cacheados por mucho tiempo sin riesgo.
expires 1y;
add_header Cache-Control "public";
try_files $uri =404;
}
# Bloque para la SPA
location / {
try_files $uri $uri/ /index.html;
}
location ~* \.(?:css|js|jpg|jpeg|gif|png|ico|svg|woff|woff2)$ {
expires 1y;
add_header Cache-Control "public";
}
}

View File

@@ -21,7 +21,8 @@
"react-pdf": "^10.1.0",
"react-select": "^5.10.2",
"react-simple-maps": "github:ozimmortal/react-simple-maps#feat/react-19-support",
"react-tooltip": "^5.29.1"
"react-tooltip": "^5.29.1",
"topojson-client": "^3.1.0"
},
"devDependencies": {
"@eslint/js": "^9.33.0",
@@ -29,6 +30,7 @@
"@types/react": "^19.1.10",
"@types/react-dom": "^19.1.7",
"@types/react-select": "^5.0.0",
"@types/topojson-client": "^3.1.5",
"@vitejs/plugin-react": "^5.0.0",
"eslint": "^9.33.0",
"eslint-plugin-react-hooks": "^5.2.0",
@@ -2215,6 +2217,27 @@
"@types/react": "*"
}
},
"node_modules/@types/topojson-client": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/@types/topojson-client/-/topojson-client-3.1.5.tgz",
"integrity": "sha512-C79rySTyPxnQNNguTZNI1Ct4D7IXgvyAs3p9HPecnl6mNrJ5+UhvGNYcZfpROYV2lMHI48kJPxwR+F9C6c7nmw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/geojson": "*",
"@types/topojson-specification": "*"
}
},
"node_modules/@types/topojson-specification": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@types/topojson-specification/-/topojson-specification-1.0.5.tgz",
"integrity": "sha512-C7KvcQh+C2nr6Y2Ub4YfgvWvWCgP2nOQMtfhlnwsRL4pYmmwzBS7HclGiS87eQfDOU/DLQpX6GEscviaz4yLIQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/geojson": "*"
}
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.40.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.40.0.tgz",

View File

@@ -23,7 +23,8 @@
"react-pdf": "^10.1.0",
"react-select": "^5.10.2",
"react-simple-maps": "github:ozimmortal/react-simple-maps#feat/react-19-support",
"react-tooltip": "^5.29.1"
"react-tooltip": "^5.29.1",
"topojson-client": "^3.1.0"
},
"devDependencies": {
"@eslint/js": "^9.33.0",
@@ -31,6 +32,7 @@
"@types/react": "^19.1.10",
"@types/react-dom": "^19.1.7",
"@types/react-select": "^5.0.0",
"@types/topojson-client": "^3.1.5",
"@vitejs/plugin-react": "^5.0.0",
"eslint": "^9.33.0",
"eslint-plugin-react-hooks": "^5.2.0",

View File

@@ -63,12 +63,15 @@
}
// 5. Una vez cargado, llamar a la función de renderizado
// 5. Una vez cargado, llamar a la función de renderizado
console.log('Bootstrap: JS principal cargado. Buscando EleccionesWidgets.render...');
if (window.EleccionesWidgets && typeof window.EleccionesWidgets.render === 'function') {
console.log('Bootstrap: La función render() FUE ENCONTRADA. Se procederá a llamarla.');
window.EleccionesWidgets.render();
console.log('Bootstrap: La función render existe. Llamando ahora.');
// Encontramos los contenedores aquí y pasamos sus props.
const widgetContainers = document.querySelectorAll('[data-elecciones-widget]');
widgetContainers.forEach(container => {
// 'dataset' es un objeto que contiene todos los atributos data-*
// container.dataset = { eleccionesWidget: 'mapa-municipios', focoMunicipio: 'LA PLATA' }
window.EleccionesWidgets.render(container, container.dataset);
});
} else {
console.error('Bootstrap: ERROR CRÍTICO - La función render() NO SE ENCONTRÓ en window.EleccionesWidgets.');
console.log('Bootstrap: Contenido de window.EleccionesWidgets:', window.EleccionesWidgets);

View File

@@ -5,19 +5,6 @@
text-align: center;
}
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.react:hover {
filter: drop-shadow(0 0 2em #61dafbaa);
}
@keyframes logo-spin {
from {
transform: rotate(0deg);

View File

@@ -26,25 +26,61 @@ export const DevApp = () => {
<h1 style={{ textAlign: 'center', fontFamily: 'sans-serif' }}>
Showcase de Widgets - Elecciones 2025
</h1>
<main>
<DipSenTickerWidget />
<ResumenGeneralWidget />
<main>
<DipSenTickerWidget />
<ResumenGeneralWidget />
<SenadoresWidget />
<DiputadosWidget />
<ConcejalesWidget />
<SenadoresTickerWidget />
<DiputadosTickerWidget />
<ConcejalesTickerWidget />
<DiputadosPorSeccionWidget />
<SenadoresPorSeccionWidget />
<ConcejalesPorSeccionWidget />
<CongresoWidget />
<BancasWidget />
<MapaBsAs />
<MapaBsAsSecciones />
<TelegramaWidget />
<ResultadosTablaDetalladaWidget />
<ResultadosRankingMunicipioWidget />
<ConcejalesWidget />
<SenadoresTickerWidget />
<DiputadosTickerWidget />
<ConcejalesTickerWidget />
<DiputadosPorSeccionWidget />
<SenadoresPorSeccionWidget />
<ConcejalesPorSeccionWidget />
<CongresoWidget />
<BancasWidget />
<MapaBsAs />
<MapaBsAsSecciones />
<TelegramaWidget />
<ResultadosTablaDetalladaWidget />
<ResultadosRankingMunicipioWidget />
<hr className="border-gray-300 my-8" />
<h2>Mapa - Vista General (Por Defecto)</h2>
<p>Carga la vista provincial completa para Diputados.</p>
<MapaBsAs />
<hr className="border-gray-300 my-8" />
<h2>Mapa - Foco en La Plata (Diputados por defecto)</h2>
<p>Carga el mapa y automáticamente hace zoom en La Plata.</p>
<MapaBsAs focoMunicipio="LA PLATA" />
<hr className="border-gray-300 my-8" />
<h2>Mapa - Foco en Campana</h2>
<p>Carga el mapa y automáticamente hace zoom en Campana.</p>
<MapaBsAs focoMunicipio="CAMPANA" focoCategoria="senadores" />
<hr className="border-gray-300 my-8" />
<h2>Mapa - Vista General de Senadores</h2>
<p>Carga la vista provincial completa para la categoría Senadores.</p>
<MapaBsAs focoCategoria="senadores" />
<hr className="border-gray-300 my-8" />
<h2>Mapa - Foco en Bahía Blanca para Concejales</h2>
<p>Carga el mapa enfocado en Bahía Blanca y con la categoría Concejales seleccionada.</p>
<MapaBsAs focoMunicipio="BAHIA BLANCA" focoCategoria="concejales" />
<hr className="border-gray-300 my-8" />
<h2>Mapa - Foco Inválido (La Plata para Senadores)</h2>
<p>Debería mostrar la vista provincial de Senadores y un warning en la consola del navegador.</p>
<MapaBsAs focoMunicipio="LA PLATA" focoCategoria="senadores" />
</main>
</>
);

View File

@@ -4,6 +4,7 @@ import { ComposableMap, Geographies, Geography, ZoomableGroup } from 'react-simp
import { Tooltip } from 'react-tooltip';
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';
import { feature } from 'topojson-client';
import type { Feature, Geometry } from 'geojson';
import { geoCentroid } from 'd3-geo';
import { API_BASE_URL, assetBaseUrl } from '../apiService';
@@ -12,6 +13,11 @@ import './MapaBsAs.css';
// --- Interfaces y Tipos ---
type PointTuple = [number, number];
interface MapaBsAsProps {
focoMunicipio?: string;
focoCategoria?: string;
}
interface ResultadoMapa {
ambitoId: number;
departamentoNombre: string;
@@ -33,15 +39,8 @@ interface Agrupacion {
nombre: string;
}
interface Categoria {
id: number;
nombre: string;
}
interface PartidoProperties {
departamento: string;
}
interface Categoria { id: number; nombre: string; }
interface PartidoProperties { departamento: string; }
type PartidoGeography = Feature<Geometry, PartidoProperties> & { rsmKey: string };
// --- Constantes ---
@@ -52,19 +51,43 @@ const INITIAL_POSITION = { center: [-60.5, -37.2] as PointTuple, zoom: MIN_ZOOM
const DEFAULT_MAP_COLOR = '#E0E0E0';
const CATEGORIAS: Categoria[] = [
{ id: 5, nombre: 'Senadores' },
{ id: 6, nombre: 'Diputados' },
{ id: 5, nombre: 'Senadores' },
{ id: 7, nombre: 'Concejales' }
];
// --- Helper de Normalización ---
const normalizarTexto = (texto: string = ''): string => {
return texto
.trim()
.toUpperCase()
.normalize("NFD") // Separa los acentos de las letras
.replace(/[\u0300-\u036f]/g, ""); // Elimina los acentos
};
// --- Componente Principal ---
const MapaBsAs = () => {
const MapaBsAs = ({ focoMunicipio, focoCategoria }: MapaBsAsProps) => {
// --- LÓGICA DE ESTADO SIMPLIFICADA ---
const categoriaInicial = useMemo(() => {
const catNorm = focoCategoria?.toLowerCase();
if (catNorm === 'senadores') return 5;
if (catNorm === 'concejales') return 7;
return 6;
}, [focoCategoria]);
const [position, setPosition] = useState(INITIAL_POSITION);
const [selectedAmbitoId, setSelectedAmbitoId] = useState<number | null>(null);
const [selectedCategoriaId, setSelectedCategoriaId] = useState<number>(6);
const [selectedCategoriaId, setSelectedCategoriaId] = useState<number>(categoriaInicial);
const [tooltipContent, setTooltipContent] = useState('');
const [isPanning, setIsPanning] = useState(false);
// Sincroniza el estado si la prop cambia. Esto es para cuando el widget ya está montado
// y recibe nuevas props (no ocurrirá en tu caso actual, pero es buena práctica).
useEffect(() => {
setSelectedCategoriaId(categoriaInicial);
}, [categoriaInicial]);
// --- QUERIES ---
const { data: resultadosData, isLoading: isLoadingResultados } = useQuery<ResultadoMapa[]>({
queryKey: ['mapaResultadosPorMunicipio', selectedCategoriaId],
queryFn: async () => (await axios.get(`${API_BASE_URL}/Resultados/mapa-por-municipio?categoriaId=${selectedCategoriaId}`)).data,
@@ -80,21 +103,16 @@ const MapaBsAs = () => {
queryFn: async () => (await axios.get(`${API_BASE_URL}/Catalogos/agrupaciones`)).data,
});
const { nombresAgrupaciones, resultadosPorDepartamento } = useMemo<{
nombresAgrupaciones: Map<string, string>;
resultadosPorDepartamento: Map<string, ResultadoMapa>;
}>(() => {
const { nombresAgrupaciones, resultadosPorDepartamento } = useMemo(() => {
const nombresMap = new Map<string, string>();
const resultadosMap = new Map<string, ResultadoMapa>();
if (agrupacionesData) {
agrupacionesData.forEach((agrupacion) => {
nombresMap.set(agrupacion.id, agrupacion.nombre);
});
agrupacionesData.forEach((a) => nombresMap.set(a.id, a.nombre));
}
if (resultadosData) {
resultadosData.forEach(r => {
if (r.departamentoNombre) {
resultadosMap.set(r.departamentoNombre.toUpperCase(), r)
resultadosMap.set(normalizarTexto(r.departamentoNombre), r);
}
});
}
@@ -108,20 +126,105 @@ const MapaBsAs = () => {
setPosition(INITIAL_POSITION);
}, []);
// --- LÓGICA DE CLIC Y FOCO ---
const handleGeographyClick = useCallback((geo: PartidoGeography) => {
const departamentoNombre = geo.properties.departamento.toUpperCase();
const resultado = resultadosPorDepartamento.get(departamentoNombre);
const departamentoNombreNormalizado = normalizarTexto(geo.properties.departamento);
const resultado = resultadosPorDepartamento.get(departamentoNombreNormalizado);
if (!resultado) return;
const ambitoIdParaSeleccionar = resultado.ambitoId;
if (selectedAmbitoId === ambitoIdParaSeleccionar) {
if (selectedAmbitoId === resultado.ambitoId) {
handleReset();
} else {
const centroid = geoCentroid(geo) as PointTuple;
setPosition({ center: centroid, zoom: 5 });
setSelectedAmbitoId(ambitoIdParaSeleccionar);
setSelectedAmbitoId(resultado.ambitoId);
}
}, [selectedAmbitoId, handleReset, resultadosPorDepartamento]);
// --- useEffect DE INICIALIZACIÓN (Ligeramente refinado) ---
useEffect(() => {
if (isLoading || !focoMunicipio || selectedAmbitoId) {
return;
}
const geometries = geoData?.objects?.['departamentos-buenos_aires']?.geometries;
if (!geometries) return;
const nombreFocoNormalizado = normalizarTexto(focoMunicipio);
const geoTargetTopo = geometries.find(
(g: any) => normalizarTexto(g.properties.departamento) === nombreFocoNormalizado
);
if (geoTargetTopo) {
if (resultadosPorDepartamento.has(nombreFocoNormalizado)) {
const geoTargetGeoJSON = feature(geoData, geoTargetTopo);
handleGeographyClick(geoTargetGeoJSON as unknown as PartidoGeography);
}
}
// Deshabilitamos la regla para que solo se ejecute cuando isLoading cambia a false.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isLoading]);
useEffect(() => {
if (categoriaInicial !== selectedCategoriaId) {
setSelectedCategoriaId(categoriaInicial);
handleReset();
}
}, [categoriaInicial, selectedCategoriaId, handleReset]);
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => e.key === 'Escape' && handleReset();
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, [handleReset]);
const renderGeography = useCallback((geo: PartidoGeography, isSelectedGeo: boolean = false) => {
const departamentoNombreNormalizado = normalizarTexto(geo.properties.departamento);
const resultado = resultadosPorDepartamento.get(departamentoNombreNormalizado);
const isClickable = !!resultado;
const isSelected = isSelectedGeo || (selectedAmbitoId !== null && selectedAmbitoId === resultado?.ambitoId);
const isFaded = !isSelectedGeo && selectedAmbitoId !== null && !isSelected;
const nombreAgrupacionGanadora = resultado
? nombresAgrupaciones.get(resultado.agrupacionGanadoraId)
: 'Sin datos';
return (
<Geography
key={geo.rsmKey + (isSelectedGeo ? '-selected' : '')}
geography={geo}
className={`rsm-geography ${isSelected ? 'selected' : ''} ${isFaded ? 'faded' : ''} ${!isClickable ? 'no-results' : ''}`}
fill={resultado?.colorGanador || DEFAULT_MAP_COLOR}
onClick={isClickable ? () => handleGeographyClick(geo) : undefined}
onMouseEnter={() => {
if (isClickable) {
setTooltipContent(`${geo.properties.departamento}: ${nombreAgrupacionGanadora}`);
}
}}
onMouseLeave={() => setTooltipContent("")}
/>
);
}, [resultadosPorDepartamento, selectedAmbitoId, nombresAgrupaciones, handleGeographyClick]);
useEffect(() => {
if (isLoading || !focoMunicipio || selectedAmbitoId) {
return;
}
const geometries = geoData?.objects?.['departamentos-buenos_aires']?.geometries;
if (!geometries) return;
const nombreFocoNormalizado = normalizarTexto(focoMunicipio);
const geoTargetTopo = geometries.find(
(g: any) => normalizarTexto(g.properties.departamento) === nombreFocoNormalizado
);
if (geoTargetTopo && resultadosPorDepartamento.has(nombreFocoNormalizado)) {
const geoTargetGeoJSON = feature(geoData, geoTargetTopo);
handleGeographyClick(geoTargetGeoJSON as unknown as PartidoGeography);
}
}, [isLoading, focoMunicipio, selectedCategoriaId]);
const handleMoveEnd = (newPosition: { coordinates: PointTuple; zoom: number }) => {
if (newPosition.zoom <= MIN_ZOOM) {
if (position.zoom > MIN_ZOOM || selectedAmbitoId !== null) {
@@ -147,35 +250,6 @@ const MapaBsAs = () => {
return () => window.removeEventListener('keydown', handleKeyDown);
}, [handleReset]);
const getPartyFillColor = (departamentoNombre: string) => {
const resultado = resultadosPorDepartamento.get(departamentoNombre.toUpperCase());
return resultado?.colorGanador || DEFAULT_MAP_COLOR;
};
// --- Helper de Renderizado ---
const renderGeography = (geo: PartidoGeography, isSelectedGeo: boolean = false) => {
const departamentoNombre = geo.properties.departamento.toUpperCase();
const resultado = resultadosPorDepartamento.get(departamentoNombre);
const isClickable = !!resultado;
const isSelected = isSelectedGeo || (selectedAmbitoId !== null && selectedAmbitoId === resultado?.ambitoId);
const isFaded = !isSelectedGeo && selectedAmbitoId !== null && !isSelected;
const nombreAgrupacionGanadora = resultado ? nombresAgrupaciones.get(resultado.agrupacionGanadoraId) : 'Sin datos';
return (
<Geography
key={geo.rsmKey + (isSelectedGeo ? '-selected' : '')}
geography={geo}
data-tooltip-id="partido-tooltip"
data-tooltip-content={`${geo.properties.departamento}: ${nombreAgrupacionGanadora}`}
className={`rsm-geography ${isSelected ? 'selected' : ''} ${isFaded ? 'faded' : ''} ${!isClickable ? 'no-results' : ''}`}
fill={getPartyFillColor(geo.properties.departamento)}
onClick={isClickable ? () => handleGeographyClick(geo) : undefined}
onMouseEnter={() => setTooltipContent(`${geo.properties.departamento}: ${nombreAgrupacionGanadora}`)}
onMouseLeave={() => setTooltipContent("")}
/>
);
};
return (
<div className="mapa-wrapper">
<div className="mapa-container">
@@ -213,7 +287,7 @@ const MapaBsAs = () => {
{({ geographies }: { geographies: PartidoGeography[] }) => {
const selectedGeo = selectedAmbitoId
? geographies.find(geo => {
const resultado = resultadosPorDepartamento.get(geo.properties.departamento.toUpperCase());
const resultado = resultadosPorDepartamento.get(normalizarTexto(geo.properties.departamento));
return resultado?.ambitoId === selectedAmbitoId;
})
: null;
@@ -239,14 +313,15 @@ const MapaBsAs = () => {
className="mapa-categoria-combobox"
value={selectedCategoriaId}
onChange={(e) => {
// --- LÓGICA DE CAMBIO DE CATEGORÍA ---
// Limpiamos el foco de municipio al cambiar de categoría
setSelectedAmbitoId(null);
setPosition(INITIAL_POSITION);
setSelectedCategoriaId(Number(e.target.value));
handleReset();
}}
>
{CATEGORIAS.map(cat => (
<option key={cat.id} value={cat.id}>
{cat.nombre}
</option>
<option key={cat.id} value={cat.id}>{cat.nombre}</option>
))}
</select>
</div>
@@ -259,6 +334,7 @@ const MapaBsAs = () => {
// --- Sub-componentes ---
const ControlesMapa = ({ onReset }: { onReset: () => void }) => (
<div className="map-controls">
<button onClick={onReset}> VOLVER</button>
</div>
@@ -299,10 +375,10 @@ const DetalleMunicipio = ({ ambitoId, onReset, categoriaId }: { ambitoId: number
}}
></div>
</div>
</li>
</li >
))}
</ul>
</div>
</ul >
</div >
);
};
@@ -321,6 +397,7 @@ const Legend = ({ resultados, nombresAgrupaciones }: { resultados: Map<string, R
});
return Array.from(ganadoresUnicos.values());
}, [resultados, nombresAgrupaciones]);
return (

View File

@@ -63,33 +63,30 @@ if (import.meta.env.DEV) {
} else {
// --- MODO PRODUCCIÓN ---
// Exponemos la función de renderizado para el bootstrap.js
const renderWidgets = () => {
const widgetContainers = document.querySelectorAll('[data-elecciones-widget]');
if (widgetContainers.length === 0) {
console.warn('React: ADVERTENCIA - No se encontró ningún elemento en el DOM para renderizar un widget. Verifica que el HTML contenga <div data-elecciones-widget="...">.');
}
widgetContainers.forEach(container => {
const widgetName = (container as HTMLElement).dataset.eleccionesWidget;
// La función de renderizado acepta el contenedor y las props
const renderWidgets = (container: HTMLElement, props: DOMStringMap) => {
const widgetName = props.eleccionesWidget;
if (widgetName && WIDGET_MAP[widgetName]) {
const WidgetComponent = WIDGET_MAP[widgetName];
const root = ReactDOM.createRoot(container);
if (widgetName && WIDGET_MAP[widgetName]) {
const WidgetComponent = WIDGET_MAP[widgetName];
const root = ReactDOM.createRoot(container);
root.render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<WidgetComponent />
</QueryClientProvider>
</React.StrictMode>
);
} else {
console.error(`React: ERROR - No se encontró un componente para el nombre de widget: "${widgetName}"`);
}
});
// Pasamos todas las props (ej. { eleccionesWidget: '...', focoMunicipio: '...' })
// al componente que se va a renderizar.
root.render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<WidgetComponent {...props} />
</QueryClientProvider>
</React.StrictMode>
);
} else {
console.error(`React: ERROR - No se encontró un componente para el nombre de widget: "${widgetName}"`);
}
};
// La función expuesta ahora se llamará por cada widget, no una sola vez.
(window as any).EleccionesWidgets = {
render: renderWidgets
render: renderWidgets
};
}

View File

@@ -14,7 +14,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Api")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+d5168e1d175a8b1944d6009066d13f9b99cba1d0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+6309003536b4278315dbe89abb0a8fe79e3320a9")]
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Api")]
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Api")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]

View File

@@ -1 +1 @@
{"GlobalPropertiesHash":"b5T/+ta4fUd8qpIzUTm3KyEwAYYUsU5ASo+CSFM3ByE=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["TyIJk/eQMWjmB5LsDE\u002BZIJC9P9ciVxd7bnzRiTZsGt4=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","E2ODTAlJxzsXY1iP1eB/02NIUK\u002BnQveGlWAOHY1cpgA=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","yVoZ4UnBcSOapsJIi046hnn7ylD3jAcEBUxQ\u002Brkvj/4=","/GfbpJthEWmsuz0uFx1QLHM7gyM1wLLeQgAIl4SzUD4=","i5\u002B5LcfxQD8meRAkQbVf4wMvjxSE4\u002BjCd2/FdPtMpms=","AvSkxVPIg0GjnB1RJ4hDNyo9p9GONrzDs8uVuixH\u002BOE=","IgT9pOgRnK37qfILj2QcjFoBZ180HMt\u002BScgje2iYOo4=","ezUlOMzNZmyKDIe1wwXqvX\u002BvhwfB992xNVts7r2zcTc=","y2BV4WpkQuLfqQhfOQBtmuzh940c3s4LAopGKfztfTE=","lHTUEsMkDu8nqXtfTwl7FRfgocyyc7RI5O/edTHN1\u002B0=","A7nz7qgOtQ1CwZZLvNnr0b5QZB3fTi3y4i6y7rBIcxQ=","znnuRi2tsk7AACuYo4WSgj7NcLriG4PKVaF4L35SvDk=","GelE32odx/vTului267wqi6zL3abBnF9yvwC2Q66LoM=","TEsXImnzxFKTIq2f5fiDu7i6Ar/cbecW5MZ3z8Wb/a4=","5WogJu\u002BUPlF\u002BE5mq/ILtDXpVwqwmhHtsEB13nmT5JJk=","dcHQRkttjMjo2dvhL7hA9t4Pg\u002B7OnjZpkFmakT4QR9U=","Of8nTYw5l\u002BgiAJo7z6XYIntG2tUtCFcILzHbTiiXn\u002Bw=","PDy\u002BTiayvNAoXXBEgwC/kCojpgOOMI6RQOIoSXs3LJc=","ePXrkee3hv3wHUr8S7aYmRVvXUTxQf76zApKGv3/l3o=","DJ3OEGlGm0XqehqAshsJPdHddx35xQrKqTYPlJ\u002BmgK0=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","VC4RrsY3drpYvDr8ENTx68n\u002BklPRBIIs4arkXFsPT3E="],"CachedAssets":{},"CachedCopyCandidates":{}}
{"GlobalPropertiesHash":"b5T/+ta4fUd8qpIzUTm3KyEwAYYUsU5ASo+CSFM3ByE=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["TyIJk/eQMWjmB5LsDE\u002BZIJC9P9ciVxd7bnzRiTZsGt4=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","E2ODTAlJxzsXY1iP1eB/02NIUK\u002BnQveGlWAOHY1cpgA=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","yVoZ4UnBcSOapsJIi046hnn7ylD3jAcEBUxQ\u002Brkvj/4=","/GfbpJthEWmsuz0uFx1QLHM7gyM1wLLeQgAIl4SzUD4=","i5\u002B5LcfxQD8meRAkQbVf4wMvjxSE4\u002BjCd2/FdPtMpms=","AvSkxVPIg0GjnB1RJ4hDNyo9p9GONrzDs8uVuixH\u002BOE=","IgT9pOgRnK37qfILj2QcjFoBZ180HMt\u002BScgje2iYOo4=","ezUlOMzNZmyKDIe1wwXqvX\u002BvhwfB992xNVts7r2zcTc=","y2BV4WpkQuLfqQhfOQBtmuzh940c3s4LAopGKfztfTE=","lHTUEsMkDu8nqXtfTwl7FRfgocyyc7RI5O/edTHN1\u002B0=","A7nz7qgOtQ1CwZZLvNnr0b5QZB3fTi3y4i6y7rBIcxQ=","znnuRi2tsk7AACuYo4WSgj7NcLriG4PKVaF4L35SvDk=","GelE32odx/vTului267wqi6zL3abBnF9yvwC2Q66LoM=","TEsXImnzxFKTIq2f5fiDu7i6Ar/cbecW5MZ3z8Wb/a4=","5WogJu\u002BUPlF\u002BE5mq/ILtDXpVwqwmhHtsEB13nmT5JJk=","dcHQRkttjMjo2dvhL7hA9t4Pg\u002B7OnjZpkFmakT4QR9U=","Of8nTYw5l\u002BgiAJo7z6XYIntG2tUtCFcILzHbTiiXn\u002Bw=","PDy\u002BTiayvNAoXXBEgwC/kCojpgOOMI6RQOIoSXs3LJc=","ePXrkee3hv3wHUr8S7aYmRVvXUTxQf76zApKGv3/l3o=","DXx5dQywLo3UsY2zQaUG\u002BbW4ObiYbybxPBWxeJD2bhk=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","/f\u002B\u002BdIRysg7dipW05N4RtxXuPBXZZIhhi3aMiCZ\u002BB2w="],"CachedAssets":{},"CachedCopyCandidates":{}}

View File

@@ -1 +1 @@
{"GlobalPropertiesHash":"tJTBjV/i0Ihkc6XuOu69wxL8PBac9c9Kak6srMso4pU=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["TyIJk/eQMWjmB5LsDE\u002BZIJC9P9ciVxd7bnzRiTZsGt4=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","E2ODTAlJxzsXY1iP1eB/02NIUK\u002BnQveGlWAOHY1cpgA=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","yVoZ4UnBcSOapsJIi046hnn7ylD3jAcEBUxQ\u002Brkvj/4=","/GfbpJthEWmsuz0uFx1QLHM7gyM1wLLeQgAIl4SzUD4=","i5\u002B5LcfxQD8meRAkQbVf4wMvjxSE4\u002BjCd2/FdPtMpms=","AvSkxVPIg0GjnB1RJ4hDNyo9p9GONrzDs8uVuixH\u002BOE=","IgT9pOgRnK37qfILj2QcjFoBZ180HMt\u002BScgje2iYOo4=","ezUlOMzNZmyKDIe1wwXqvX\u002BvhwfB992xNVts7r2zcTc=","y2BV4WpkQuLfqQhfOQBtmuzh940c3s4LAopGKfztfTE=","lHTUEsMkDu8nqXtfTwl7FRfgocyyc7RI5O/edTHN1\u002B0=","A7nz7qgOtQ1CwZZLvNnr0b5QZB3fTi3y4i6y7rBIcxQ=","znnuRi2tsk7AACuYo4WSgj7NcLriG4PKVaF4L35SvDk=","GelE32odx/vTului267wqi6zL3abBnF9yvwC2Q66LoM=","TEsXImnzxFKTIq2f5fiDu7i6Ar/cbecW5MZ3z8Wb/a4=","5WogJu\u002BUPlF\u002BE5mq/ILtDXpVwqwmhHtsEB13nmT5JJk=","dcHQRkttjMjo2dvhL7hA9t4Pg\u002B7OnjZpkFmakT4QR9U=","Of8nTYw5l\u002BgiAJo7z6XYIntG2tUtCFcILzHbTiiXn\u002Bw=","PDy\u002BTiayvNAoXXBEgwC/kCojpgOOMI6RQOIoSXs3LJc=","ePXrkee3hv3wHUr8S7aYmRVvXUTxQf76zApKGv3/l3o=","DJ3OEGlGm0XqehqAshsJPdHddx35xQrKqTYPlJ\u002BmgK0=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","VC4RrsY3drpYvDr8ENTx68n\u002BklPRBIIs4arkXFsPT3E="],"CachedAssets":{},"CachedCopyCandidates":{}}
{"GlobalPropertiesHash":"tJTBjV/i0Ihkc6XuOu69wxL8PBac9c9Kak6srMso4pU=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["TyIJk/eQMWjmB5LsDE\u002BZIJC9P9ciVxd7bnzRiTZsGt4=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","E2ODTAlJxzsXY1iP1eB/02NIUK\u002BnQveGlWAOHY1cpgA=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","yVoZ4UnBcSOapsJIi046hnn7ylD3jAcEBUxQ\u002Brkvj/4=","/GfbpJthEWmsuz0uFx1QLHM7gyM1wLLeQgAIl4SzUD4=","i5\u002B5LcfxQD8meRAkQbVf4wMvjxSE4\u002BjCd2/FdPtMpms=","AvSkxVPIg0GjnB1RJ4hDNyo9p9GONrzDs8uVuixH\u002BOE=","IgT9pOgRnK37qfILj2QcjFoBZ180HMt\u002BScgje2iYOo4=","ezUlOMzNZmyKDIe1wwXqvX\u002BvhwfB992xNVts7r2zcTc=","y2BV4WpkQuLfqQhfOQBtmuzh940c3s4LAopGKfztfTE=","lHTUEsMkDu8nqXtfTwl7FRfgocyyc7RI5O/edTHN1\u002B0=","A7nz7qgOtQ1CwZZLvNnr0b5QZB3fTi3y4i6y7rBIcxQ=","znnuRi2tsk7AACuYo4WSgj7NcLriG4PKVaF4L35SvDk=","GelE32odx/vTului267wqi6zL3abBnF9yvwC2Q66LoM=","TEsXImnzxFKTIq2f5fiDu7i6Ar/cbecW5MZ3z8Wb/a4=","5WogJu\u002BUPlF\u002BE5mq/ILtDXpVwqwmhHtsEB13nmT5JJk=","dcHQRkttjMjo2dvhL7hA9t4Pg\u002B7OnjZpkFmakT4QR9U=","Of8nTYw5l\u002BgiAJo7z6XYIntG2tUtCFcILzHbTiiXn\u002Bw=","PDy\u002BTiayvNAoXXBEgwC/kCojpgOOMI6RQOIoSXs3LJc=","ePXrkee3hv3wHUr8S7aYmRVvXUTxQf76zApKGv3/l3o=","DXx5dQywLo3UsY2zQaUG\u002BbW4ObiYbybxPBWxeJD2bhk=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","/f\u002B\u002BdIRysg7dipW05N4RtxXuPBXZZIhhi3aMiCZ\u002BB2w="],"CachedAssets":{},"CachedCopyCandidates":{}}

View File

@@ -13,7 +13,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Core")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+d5168e1d175a8b1944d6009066d13f9b99cba1d0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+6309003536b4278315dbe89abb0a8fe79e3320a9")]
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Core")]
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Core")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]

View File

@@ -13,7 +13,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Database")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+d5168e1d175a8b1944d6009066d13f9b99cba1d0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+6309003536b4278315dbe89abb0a8fe79e3320a9")]
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Database")]
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Database")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]

View File

@@ -13,7 +13,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Infrastructure")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+d5168e1d175a8b1944d6009066d13f9b99cba1d0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+6309003536b4278315dbe89abb0a8fe79e3320a9")]
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Infrastructure")]
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Infrastructure")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]