import javax.swing.* ;
import java.awt.* ;
import java.awt.event.* ;
import java.util.HashMap ;
import java.util.LinkedHashMap ;
import java.util.Map ;
import java.util.Random ;
public class Main {
public static void main
( String [ ] args
) { SwingUtilities .
invokeLater ( ( ) -> new Controlador
( ) .
mostrarRegistroCandidato ( ) ) ; }
}
class DatosCompartidos {
java.util .List < String> candidatos = new java.util .ArrayList <> ( ) ;
Map
< String , String
> distritos
= new LinkedHashMap
<> ( ) ; Map
< String , Integer
> preferencias
= new HashMap
<> ( ) ; Map
< String , Integer
> votosTotales
= new LinkedHashMap
<> ( ) ; int totalVotos = 0 ;
}
class Controlador {
DatosCompartidos datos = new DatosCompartidos( ) ;
void mostrarRegistroCandidato( ) {
if ( ventana != null ) ventana.dispose ( ) ;
ventana = new RegistroCandidato( this , datos) ;
ventana.setVisible ( true ) ;
}
void mostrarRegistroDistrito( ) {
if ( ventana != null ) ventana.dispose ( ) ;
ventana = new RegistroDistrito( this , datos) ;
ventana.setVisible ( true ) ;
}
void mostrarIntencionVoto( ) {
if ( ventana != null ) ventana.dispose ( ) ;
ventana = new IntencionVoto( this , datos) ;
ventana.setVisible ( true ) ;
}
void mostrarVotacion( ) {
if ( ventana != null ) ventana.dispose ( ) ;
ventana = new Votacion( this , datos) ;
ventana.setVisible ( true ) ;
}
void mostrarResultados( ) {
if ( ventana != null ) ventana.dispose ( ) ;
ventana = new Resultados( this , datos) ;
ventana.setVisible ( true ) ;
}
}
class RegistroCandidato
extends JFrame { public RegistroCandidato( Controlador c, DatosCompartidos d) {
setTitle( "Registro de Candidatos" ) ;
setSize( 400 , 300 ) ;
setDefaultCloseOperation( EXIT_ON_CLOSE) ;
campo.
setFont ( new Font ( "Arial" ,
Font .
PLAIN ,
14 ) ) ; DefaultListModel< String> modelo = new DefaultListModel<> ( ) ;
JList< String> lista = new JList<> ( modelo) ;
lista.
setFont ( new Font ( "Arial" ,
Font .
PLAIN ,
14 ) ) ;
guardar.
setFont ( new Font ( "Arial" ,
Font .
PLAIN ,
14 ) ) ; guardar.addActionListener ( e -> {
String nombre
= campo.
getText ( ) .
trim ( ) ; if ( ! nombre.isEmpty ( ) && d.candidatos .size ( ) < 80 ) {
d.candidatos .add ( nombre) ;
modelo.addElement ( nombre) ;
campo.setText ( "" ) ;
}
} ) ;
siguiente.
setFont ( new Font ( "Arial" ,
Font .
PLAIN ,
14 ) ) ; siguiente.addActionListener ( e -> c.mostrarRegistroDistrito ( ) ) ;
panelBotones.add ( siguiente) ;
}
}
class RegistroDistrito
extends JFrame { public RegistroDistrito( Controlador c, DatosCompartidos d) {
setTitle( "Registro de Distritos" ) ;
setSize( 450 , 300 ) ;
setDefaultCloseOperation( EXIT_ON_CLOSE) ;
DefaultListModel< String> modelo = new DefaultListModel<> ( ) ;
JList< String> lista = new JList<> ( modelo) ;
lista.
setFont ( new Font ( "Arial" ,
Font .
PLAIN ,
14 ) ) ;
guardar.addActionListener ( e -> {
String numero
= campoNumero.
getText ( ) .
trim ( ) ; String nombre
= campoNombre.
getText ( ) .
trim ( ) ; if ( ! numero.isEmpty ( ) && ! nombre.isEmpty ( ) ) {
String clave
= "Distrito " + numero
; d.distritos .put ( clave, nombre) ;
modelo.addElement ( clave + " - " + nombre) ;
campoNumero.setText ( "" ) ;
campoNombre.setText ( "" ) ;
}
if ( ! d.distritos .containsKey ( "Otro" ) ) {
d.distritos .put ( "Otro" , "No válidos" ) ;
modelo.addElement ( "Otro - No válidos" ) ;
}
} ) ;
regresar.addActionListener ( e -> c.mostrarRegistroCandidato ( ) ) ;
siguiente.addActionListener ( e -> c.mostrarIntencionVoto ( ) ) ;
arriba.
add ( new JLabel ( "Número de Distrito:" ) ) ; arriba.add ( campoNumero) ;
arriba.
add ( new JLabel ( "Nombre del Distrito:" ) ) ; arriba.add ( campoNombre) ;
abajo.add ( regresar) ;
abajo.add ( guardar) ;
abajo.add ( siguiente) ;
}
}
class IntencionVoto
extends JFrame { public IntencionVoto( Controlador c, DatosCompartidos d) {
setTitle( "Intención de Voto" ) ;
setSize( 400 , 400 ) ;
setDefaultCloseOperation( EXIT_ON_CLOSE) ;
Map
< String , JTextField
> campos
= new HashMap
<> ( ) ;
for ( String candidato
: d.
candidatos ) { panel.
add ( new JLabel ( candidato
) ) ; campos.put ( candidato, campo) ;
panel.add ( campo) ;
}
guardar.addActionListener ( e -> {
int total = 0 ;
d.preferencias .clear ( ) ;
for ( Map .
Entry < String , JTextField
> entry
: campos.
entrySet ( ) ) { try {
int val
= Integer .
parseInt ( entry.
getValue ( ) .
getText ( ) ) ; if ( val
< 1 || val
> 80 ) throw new Exception ( ) ; d.preferencias .put ( entry.getKey ( ) , val) ;
total += val;
JOptionPane .
showMessageDialog ( this ,
"Error: Preferencias deben ser entre 1% y 80%" ) ; return ;
}
}
if ( total >= 80 && total < 99 ) {
d.preferencias .put ( "Otro" , 99 - total) ;
c.mostrarVotacion ( ) ;
} else {
JOptionPane .
showMessageDialog ( this ,
"La suma total debe estar entre 80% y 98%" ) ; }
} ) ;
}
}
class Votacion
extends JFrame { public Votacion( Controlador c, DatosCompartidos d) {
setTitle( "Generar Votos" ) ;
setSize( 400 , 200 ) ;
setDefaultCloseOperation( EXIT_ON_CLOSE) ;
JLabel etiqueta
= new JLabel ( "Cantidad de votos a generar:" ) ;
generar.addActionListener ( e -> {
try {
int total
= Integer .
parseInt ( campo.
getText ( ) ) ; d.totalVotos = total;
d.votosTotales .clear ( ) ;
for ( String key
: d.
preferencias .
keySet ( ) ) d.
votosTotales .
put ( key,
0 ) ;
java.util .List < String> lista = new java.util .ArrayList <> ( ) ;
for ( Map .
Entry < String , Integer
> entry
: d.
preferencias .
entrySet ( ) ) { for ( int i = 0 ; i < entry.getValue ( ) ; i++ ) {
lista.add ( entry.getKey ( ) ) ;
}
}
for ( int i = 0 ; i < total; i++ ) {
String elegido
= lista.
get ( rnd.
nextInt ( lista.
size ( ) ) ) ; d.votosTotales .put ( elegido, d.votosTotales .get ( elegido) + 1 ) ;
}
c.mostrarResultados ( ) ;
JOptionPane .
showMessageDialog ( this ,
"Error: Ingresa un número válido." ) ; }
} ) ;
add( etiqueta) ;
add( campo) ;
add( generar) ;
}
}
class Resultados
extends JFrame { public Resultados( Controlador c, DatosCompartidos d) {
setTitle( "Resultados" ) ;
setSize( 500 , 400 ) ;
setDefaultCloseOperation( EXIT_ON_CLOSE) ;
area.
setFont ( new Font ( "Arial" ,
Font .
PLAIN ,
14 ) ) ; area.setEditable ( false ) ;
area.append ( "Candidato - Votos - Porcentaje\n " ) ;
for ( Map .
Entry < String , Integer
> entry
: d.
votosTotales .
entrySet ( ) ) { int votos = entry.getValue ( ) ;
double porcentaje = votos * 100.0 / d.totalVotos ;
area.
append ( entry.
getKey ( ) + " - " + votos
+ " - " + String .
format ( "%.2f" , porcentaje
) + "%\n " ) ; }
}
}
aW1wb3J0IGphdmF4LnN3aW5nLio7CmltcG9ydCBqYXZhLmF3dC4qOwppbXBvcnQgamF2YS5hd3QuZXZlbnQuKjsKaW1wb3J0IGphdmEudXRpbC5IYXNoTWFwOwppbXBvcnQgamF2YS51dGlsLkxpbmtlZEhhc2hNYXA7CmltcG9ydCBqYXZhLnV0aWwuTWFwOwppbXBvcnQgamF2YS51dGlsLlJhbmRvbTsKCnB1YmxpYyBjbGFzcyBNYWluIHsKCiAgICBwdWJsaWMgc3RhdGljIHZvaWQgbWFpbihTdHJpbmdbXSBhcmdzKSB7CiAgICAgICAgU3dpbmdVdGlsaXRpZXMuaW52b2tlTGF0ZXIoKCkgLT4gbmV3IENvbnRyb2xhZG9yKCkubW9zdHJhclJlZ2lzdHJvQ2FuZGlkYXRvKCkpOwogICAgfQp9CgpjbGFzcyBEYXRvc0NvbXBhcnRpZG9zIHsKICAgIGphdmEudXRpbC5MaXN0PFN0cmluZz4gY2FuZGlkYXRvcyA9IG5ldyBqYXZhLnV0aWwuQXJyYXlMaXN0PD4oKTsKICAgIE1hcDxTdHJpbmcsIFN0cmluZz4gZGlzdHJpdG9zID0gbmV3IExpbmtlZEhhc2hNYXA8PigpOwogICAgTWFwPFN0cmluZywgSW50ZWdlcj4gcHJlZmVyZW5jaWFzID0gbmV3IEhhc2hNYXA8PigpOwogICAgTWFwPFN0cmluZywgSW50ZWdlcj4gdm90b3NUb3RhbGVzID0gbmV3IExpbmtlZEhhc2hNYXA8PigpOwogICAgaW50IHRvdGFsVm90b3MgPSAwOwp9CgpjbGFzcyBDb250cm9sYWRvciB7CiAgICBKRnJhbWUgdmVudGFuYTsKICAgIERhdG9zQ29tcGFydGlkb3MgZGF0b3MgPSBuZXcgRGF0b3NDb21wYXJ0aWRvcygpOwoKICAgIHZvaWQgbW9zdHJhclJlZ2lzdHJvQ2FuZGlkYXRvKCkgewogICAgICAgIGlmICh2ZW50YW5hICE9IG51bGwpIHZlbnRhbmEuZGlzcG9zZSgpOwogICAgICAgIHZlbnRhbmEgPSBuZXcgUmVnaXN0cm9DYW5kaWRhdG8odGhpcywgZGF0b3MpOwogICAgICAgIHZlbnRhbmEuc2V0VmlzaWJsZSh0cnVlKTsKICAgIH0KCiAgICB2b2lkIG1vc3RyYXJSZWdpc3Ryb0Rpc3RyaXRvKCkgewogICAgICAgIGlmICh2ZW50YW5hICE9IG51bGwpIHZlbnRhbmEuZGlzcG9zZSgpOwogICAgICAgIHZlbnRhbmEgPSBuZXcgUmVnaXN0cm9EaXN0cml0byh0aGlzLCBkYXRvcyk7CiAgICAgICAgdmVudGFuYS5zZXRWaXNpYmxlKHRydWUpOwogICAgfQoKICAgIHZvaWQgbW9zdHJhckludGVuY2lvblZvdG8oKSB7CiAgICAgICAgaWYgKHZlbnRhbmEgIT0gbnVsbCkgdmVudGFuYS5kaXNwb3NlKCk7CiAgICAgICAgdmVudGFuYSA9IG5ldyBJbnRlbmNpb25Wb3RvKHRoaXMsIGRhdG9zKTsKICAgICAgICB2ZW50YW5hLnNldFZpc2libGUodHJ1ZSk7CiAgICB9CgogICAgdm9pZCBtb3N0cmFyVm90YWNpb24oKSB7CiAgICAgICAgaWYgKHZlbnRhbmEgIT0gbnVsbCkgdmVudGFuYS5kaXNwb3NlKCk7CiAgICAgICAgdmVudGFuYSA9IG5ldyBWb3RhY2lvbih0aGlzLCBkYXRvcyk7CiAgICAgICAgdmVudGFuYS5zZXRWaXNpYmxlKHRydWUpOwogICAgfQoKICAgIHZvaWQgbW9zdHJhclJlc3VsdGFkb3MoKSB7CiAgICAgICAgaWYgKHZlbnRhbmEgIT0gbnVsbCkgdmVudGFuYS5kaXNwb3NlKCk7CiAgICAgICAgdmVudGFuYSA9IG5ldyBSZXN1bHRhZG9zKHRoaXMsIGRhdG9zKTsKICAgICAgICB2ZW50YW5hLnNldFZpc2libGUodHJ1ZSk7CiAgICB9Cn0KCmNsYXNzIFJlZ2lzdHJvQ2FuZGlkYXRvIGV4dGVuZHMgSkZyYW1lIHsKICAgIHB1YmxpYyBSZWdpc3Ryb0NhbmRpZGF0byhDb250cm9sYWRvciBjLCBEYXRvc0NvbXBhcnRpZG9zIGQpIHsKICAgICAgICBzZXRUaXRsZSgiUmVnaXN0cm8gZGUgQ2FuZGlkYXRvcyIpOwogICAgICAgIHNldFNpemUoNDAwLCAzMDApOwogICAgICAgIHNldERlZmF1bHRDbG9zZU9wZXJhdGlvbihFWElUX09OX0NMT1NFKTsKICAgICAgICBzZXRMYXlvdXQobmV3IEJvcmRlckxheW91dCgpKTsKCiAgICAgICAgSlRleHRGaWVsZCBjYW1wbyA9IG5ldyBKVGV4dEZpZWxkKCk7CiAgICAgICAgY2FtcG8uc2V0Rm9udChuZXcgRm9udCgiQXJpYWwiLCBGb250LlBMQUlOLCAxNCkpOwogICAgICAgIERlZmF1bHRMaXN0TW9kZWw8U3RyaW5nPiBtb2RlbG8gPSBuZXcgRGVmYXVsdExpc3RNb2RlbDw+KCk7CiAgICAgICAgSkxpc3Q8U3RyaW5nPiBsaXN0YSA9IG5ldyBKTGlzdDw+KG1vZGVsbyk7CiAgICAgICAgbGlzdGEuc2V0Rm9udChuZXcgRm9udCgiQXJpYWwiLCBGb250LlBMQUlOLCAxNCkpOwoKICAgICAgICBKQnV0dG9uIGd1YXJkYXIgPSBuZXcgSkJ1dHRvbigiR3VhcmRhciIpOwogICAgICAgIGd1YXJkYXIuc2V0Rm9udChuZXcgRm9udCgiQXJpYWwiLCBGb250LlBMQUlOLCAxNCkpOwogICAgICAgIGd1YXJkYXIuYWRkQWN0aW9uTGlzdGVuZXIoZSAtPiB7CiAgICAgICAgICAgIFN0cmluZyBub21icmUgPSBjYW1wby5nZXRUZXh0KCkudHJpbSgpOwogICAgICAgICAgICBpZiAoIW5vbWJyZS5pc0VtcHR5KCkgJiYgZC5jYW5kaWRhdG9zLnNpemUoKSA8IDgwKSB7CiAgICAgICAgICAgICAgICBkLmNhbmRpZGF0b3MuYWRkKG5vbWJyZSk7CiAgICAgICAgICAgICAgICBtb2RlbG8uYWRkRWxlbWVudChub21icmUpOwogICAgICAgICAgICAgICAgY2FtcG8uc2V0VGV4dCgiIik7CiAgICAgICAgICAgIH0KICAgICAgICB9KTsKCiAgICAgICAgSkJ1dHRvbiBzaWd1aWVudGUgPSBuZXcgSkJ1dHRvbigiU2lndWllbnRlIik7CiAgICAgICAgc2lndWllbnRlLnNldEZvbnQobmV3IEZvbnQoIkFyaWFsIiwgRm9udC5QTEFJTiwgMTQpKTsKICAgICAgICBzaWd1aWVudGUuYWRkQWN0aW9uTGlzdGVuZXIoZSAtPiBjLm1vc3RyYXJSZWdpc3Ryb0Rpc3RyaXRvKCkpOwoKICAgICAgICBKUGFuZWwgcGFuZWxFbnRyYWRhID0gbmV3IEpQYW5lbChuZXcgQm9yZGVyTGF5b3V0KCkpOwogICAgICAgIHBhbmVsRW50cmFkYS5hZGQobmV3IEpMYWJlbCgiTm9tYnJlIGRlbCBDYW5kaWRhdG86IiksIEJvcmRlckxheW91dC5OT1JUSCk7CiAgICAgICAgcGFuZWxFbnRyYWRhLmFkZChjYW1wbywgQm9yZGVyTGF5b3V0LkNFTlRFUik7CiAgICAgICAgcGFuZWxFbnRyYWRhLmFkZChndWFyZGFyLCBCb3JkZXJMYXlvdXQuRUFTVCk7CgogICAgICAgIEpQYW5lbCBwYW5lbEJvdG9uZXMgPSBuZXcgSlBhbmVsKCk7CiAgICAgICAgcGFuZWxCb3RvbmVzLmFkZChzaWd1aWVudGUpOwoKICAgICAgICBhZGQocGFuZWxFbnRyYWRhLCBCb3JkZXJMYXlvdXQuTk9SVEgpOwogICAgICAgIGFkZChuZXcgSlNjcm9sbFBhbmUobGlzdGEpLCBCb3JkZXJMYXlvdXQuQ0VOVEVSKTsKICAgICAgICBhZGQocGFuZWxCb3RvbmVzLCBCb3JkZXJMYXlvdXQuU09VVEgpOwogICAgfQp9CgpjbGFzcyBSZWdpc3Ryb0Rpc3RyaXRvIGV4dGVuZHMgSkZyYW1lIHsKICAgIHB1YmxpYyBSZWdpc3Ryb0Rpc3RyaXRvKENvbnRyb2xhZG9yIGMsIERhdG9zQ29tcGFydGlkb3MgZCkgewogICAgICAgIHNldFRpdGxlKCJSZWdpc3RybyBkZSBEaXN0cml0b3MiKTsKICAgICAgICBzZXRTaXplKDQ1MCwgMzAwKTsKICAgICAgICBzZXREZWZhdWx0Q2xvc2VPcGVyYXRpb24oRVhJVF9PTl9DTE9TRSk7CiAgICAgICAgc2V0TGF5b3V0KG5ldyBCb3JkZXJMYXlvdXQoKSk7CgogICAgICAgIEpUZXh0RmllbGQgY2FtcG9OdW1lcm8gPSBuZXcgSlRleHRGaWVsZCgpOwogICAgICAgIEpUZXh0RmllbGQgY2FtcG9Ob21icmUgPSBuZXcgSlRleHRGaWVsZCgpOwogICAgICAgIERlZmF1bHRMaXN0TW9kZWw8U3RyaW5nPiBtb2RlbG8gPSBuZXcgRGVmYXVsdExpc3RNb2RlbDw+KCk7CiAgICAgICAgSkxpc3Q8U3RyaW5nPiBsaXN0YSA9IG5ldyBKTGlzdDw+KG1vZGVsbyk7CiAgICAgICAgbGlzdGEuc2V0Rm9udChuZXcgRm9udCgiQXJpYWwiLCBGb250LlBMQUlOLCAxNCkpOwoKICAgICAgICBKQnV0dG9uIGd1YXJkYXIgPSBuZXcgSkJ1dHRvbigiR3VhcmRhciIpOwogICAgICAgIGd1YXJkYXIuYWRkQWN0aW9uTGlzdGVuZXIoZSAtPiB7CiAgICAgICAgICAgIFN0cmluZyBudW1lcm8gPSBjYW1wb051bWVyby5nZXRUZXh0KCkudHJpbSgpOwogICAgICAgICAgICBTdHJpbmcgbm9tYnJlID0gY2FtcG9Ob21icmUuZ2V0VGV4dCgpLnRyaW0oKTsKICAgICAgICAgICAgaWYgKCFudW1lcm8uaXNFbXB0eSgpICYmICFub21icmUuaXNFbXB0eSgpKSB7CiAgICAgICAgICAgICAgICBTdHJpbmcgY2xhdmUgPSAiRGlzdHJpdG8gIiArIG51bWVybzsKICAgICAgICAgICAgICAgIGQuZGlzdHJpdG9zLnB1dChjbGF2ZSwgbm9tYnJlKTsKICAgICAgICAgICAgICAgIG1vZGVsby5hZGRFbGVtZW50KGNsYXZlICsgIiAtICIgKyBub21icmUpOwogICAgICAgICAgICAgICAgY2FtcG9OdW1lcm8uc2V0VGV4dCgiIik7CiAgICAgICAgICAgICAgICBjYW1wb05vbWJyZS5zZXRUZXh0KCIiKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoIWQuZGlzdHJpdG9zLmNvbnRhaW5zS2V5KCJPdHJvIikpIHsKICAgICAgICAgICAgICAgIGQuZGlzdHJpdG9zLnB1dCgiT3RybyIsICJObyB2w6FsaWRvcyIpOwogICAgICAgICAgICAgICAgbW9kZWxvLmFkZEVsZW1lbnQoIk90cm8gLSBObyB2w6FsaWRvcyIpOwogICAgICAgICAgICB9CiAgICAgICAgfSk7CgogICAgICAgIEpCdXR0b24gcmVncmVzYXIgPSBuZXcgSkJ1dHRvbigiUmVncmVzYXIiKTsKICAgICAgICByZWdyZXNhci5hZGRBY3Rpb25MaXN0ZW5lcihlIC0+IGMubW9zdHJhclJlZ2lzdHJvQ2FuZGlkYXRvKCkpOwoKICAgICAgICBKQnV0dG9uIHNpZ3VpZW50ZSA9IG5ldyBKQnV0dG9uKCJTaWd1aWVudGUiKTsKICAgICAgICBzaWd1aWVudGUuYWRkQWN0aW9uTGlzdGVuZXIoZSAtPiBjLm1vc3RyYXJJbnRlbmNpb25Wb3RvKCkpOwoKICAgICAgICBKUGFuZWwgYXJyaWJhID0gbmV3IEpQYW5lbChuZXcgR3JpZExheW91dCgyLCAyKSk7CiAgICAgICAgYXJyaWJhLmFkZChuZXcgSkxhYmVsKCJOw7ptZXJvIGRlIERpc3RyaXRvOiIpKTsKICAgICAgICBhcnJpYmEuYWRkKGNhbXBvTnVtZXJvKTsKICAgICAgICBhcnJpYmEuYWRkKG5ldyBKTGFiZWwoIk5vbWJyZSBkZWwgRGlzdHJpdG86IikpOwogICAgICAgIGFycmliYS5hZGQoY2FtcG9Ob21icmUpOwoKICAgICAgICBKUGFuZWwgYWJham8gPSBuZXcgSlBhbmVsKCk7CiAgICAgICAgYWJham8uYWRkKHJlZ3Jlc2FyKTsKICAgICAgICBhYmFqby5hZGQoZ3VhcmRhcik7CiAgICAgICAgYWJham8uYWRkKHNpZ3VpZW50ZSk7CgogICAgICAgIGFkZChhcnJpYmEsIEJvcmRlckxheW91dC5OT1JUSCk7CiAgICAgICAgYWRkKG5ldyBKU2Nyb2xsUGFuZShsaXN0YSksIEJvcmRlckxheW91dC5DRU5URVIpOwogICAgICAgIGFkZChhYmFqbywgQm9yZGVyTGF5b3V0LlNPVVRIKTsKICAgIH0KfQoKY2xhc3MgSW50ZW5jaW9uVm90byBleHRlbmRzIEpGcmFtZSB7CiAgICBwdWJsaWMgSW50ZW5jaW9uVm90byhDb250cm9sYWRvciBjLCBEYXRvc0NvbXBhcnRpZG9zIGQpIHsKICAgICAgICBzZXRUaXRsZSgiSW50ZW5jacOzbiBkZSBWb3RvIik7CiAgICAgICAgc2V0U2l6ZSg0MDAsIDQwMCk7CiAgICAgICAgc2V0RGVmYXVsdENsb3NlT3BlcmF0aW9uKEVYSVRfT05fQ0xPU0UpOwogICAgICAgIHNldExheW91dChuZXcgQm9yZGVyTGF5b3V0KCkpOwoKICAgICAgICBKUGFuZWwgcGFuZWwgPSBuZXcgSlBhbmVsKG5ldyBHcmlkTGF5b3V0KGQuY2FuZGlkYXRvcy5zaXplKCksIDIpKTsKICAgICAgICBNYXA8U3RyaW5nLCBKVGV4dEZpZWxkPiBjYW1wb3MgPSBuZXcgSGFzaE1hcDw+KCk7CgogICAgICAgIGZvciAoU3RyaW5nIGNhbmRpZGF0byA6IGQuY2FuZGlkYXRvcykgewogICAgICAgICAgICBwYW5lbC5hZGQobmV3IEpMYWJlbChjYW5kaWRhdG8pKTsKICAgICAgICAgICAgSlRleHRGaWVsZCBjYW1wbyA9IG5ldyBKVGV4dEZpZWxkKCk7CiAgICAgICAgICAgIGNhbXBvcy5wdXQoY2FuZGlkYXRvLCBjYW1wbyk7CiAgICAgICAgICAgIHBhbmVsLmFkZChjYW1wbyk7CiAgICAgICAgfQoKICAgICAgICBKQnV0dG9uIGd1YXJkYXIgPSBuZXcgSkJ1dHRvbigiR3VhcmRhciIpOwogICAgICAgIGd1YXJkYXIuYWRkQWN0aW9uTGlzdGVuZXIoZSAtPiB7CiAgICAgICAgICAgIGludCB0b3RhbCA9IDA7CiAgICAgICAgICAgIGQucHJlZmVyZW5jaWFzLmNsZWFyKCk7CgogICAgICAgICAgICBmb3IgKE1hcC5FbnRyeTxTdHJpbmcsIEpUZXh0RmllbGQ+IGVudHJ5IDogY2FtcG9zLmVudHJ5U2V0KCkpIHsKICAgICAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgICAgICAgaW50IHZhbCA9IEludGVnZXIucGFyc2VJbnQoZW50cnkuZ2V0VmFsdWUoKS5nZXRUZXh0KCkpOwogICAgICAgICAgICAgICAgICAgIGlmICh2YWwgPCAxIHx8IHZhbCA+IDgwKSB0aHJvdyBuZXcgRXhjZXB0aW9uKCk7CiAgICAgICAgICAgICAgICAgICAgZC5wcmVmZXJlbmNpYXMucHV0KGVudHJ5LmdldEtleSgpLCB2YWwpOwogICAgICAgICAgICAgICAgICAgIHRvdGFsICs9IHZhbDsKICAgICAgICAgICAgICAgIH0gY2F0Y2ggKEV4Y2VwdGlvbiBleCkgewogICAgICAgICAgICAgICAgICAgIEpPcHRpb25QYW5lLnNob3dNZXNzYWdlRGlhbG9nKHRoaXMsICJFcnJvcjogUHJlZmVyZW5jaWFzIGRlYmVuIHNlciBlbnRyZSAxJSB5IDgwJSIpOwogICAgICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQoKICAgICAgICAgICAgaWYgKHRvdGFsID49IDgwICYmIHRvdGFsIDwgOTkpIHsKICAgICAgICAgICAgICAgIGQucHJlZmVyZW5jaWFzLnB1dCgiT3RybyIsIDk5IC0gdG90YWwpOwogICAgICAgICAgICAgICAgYy5tb3N0cmFyVm90YWNpb24oKTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIEpPcHRpb25QYW5lLnNob3dNZXNzYWdlRGlhbG9nKHRoaXMsICJMYSBzdW1hIHRvdGFsIGRlYmUgZXN0YXIgZW50cmUgODAlIHkgOTglIik7CiAgICAgICAgICAgIH0KICAgICAgICB9KTsKCiAgICAgICAgYWRkKG5ldyBKU2Nyb2xsUGFuZShwYW5lbCksIEJvcmRlckxheW91dC5DRU5URVIpOwogICAgICAgIGFkZChndWFyZGFyLCBCb3JkZXJMYXlvdXQuU09VVEgpOwogICAgfQp9CgpjbGFzcyBWb3RhY2lvbiBleHRlbmRzIEpGcmFtZSB7CiAgICBwdWJsaWMgVm90YWNpb24oQ29udHJvbGFkb3IgYywgRGF0b3NDb21wYXJ0aWRvcyBkKSB7CiAgICAgICAgc2V0VGl0bGUoIkdlbmVyYXIgVm90b3MiKTsKICAgICAgICBzZXRTaXplKDQwMCwgMjAwKTsKICAgICAgICBzZXREZWZhdWx0Q2xvc2VPcGVyYXRpb24oRVhJVF9PTl9DTE9TRSk7CiAgICAgICAgc2V0TGF5b3V0KG5ldyBHcmlkTGF5b3V0KDMsIDEpKTsKCiAgICAgICAgSkxhYmVsIGV0aXF1ZXRhID0gbmV3IEpMYWJlbCgiQ2FudGlkYWQgZGUgdm90b3MgYSBnZW5lcmFyOiIpOwogICAgICAgIEpUZXh0RmllbGQgY2FtcG8gPSBuZXcgSlRleHRGaWVsZCgpOwoKICAgICAgICBKQnV0dG9uIGdlbmVyYXIgPSBuZXcgSkJ1dHRvbigiR2VuZXJhciIpOwogICAgICAgIGdlbmVyYXIuYWRkQWN0aW9uTGlzdGVuZXIoZSAtPiB7CiAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgICBpbnQgdG90YWwgPSBJbnRlZ2VyLnBhcnNlSW50KGNhbXBvLmdldFRleHQoKSk7CiAgICAgICAgICAgICAgICBkLnRvdGFsVm90b3MgPSB0b3RhbDsKICAgICAgICAgICAgICAgIGQudm90b3NUb3RhbGVzLmNsZWFyKCk7CiAgICAgICAgICAgICAgICBmb3IgKFN0cmluZyBrZXkgOiBkLnByZWZlcmVuY2lhcy5rZXlTZXQoKSkgZC52b3Rvc1RvdGFsZXMucHV0KGtleSwgMCk7CgogICAgICAgICAgICAgICAgamF2YS51dGlsLkxpc3Q8U3RyaW5nPiBsaXN0YSA9IG5ldyBqYXZhLnV0aWwuQXJyYXlMaXN0PD4oKTsKICAgICAgICAgICAgICAgIGZvciAoTWFwLkVudHJ5PFN0cmluZywgSW50ZWdlcj4gZW50cnkgOiBkLnByZWZlcmVuY2lhcy5lbnRyeVNldCgpKSB7CiAgICAgICAgICAgICAgICAgICAgZm9yIChpbnQgaSA9IDA7IGkgPCBlbnRyeS5nZXRWYWx1ZSgpOyBpKyspIHsKICAgICAgICAgICAgICAgICAgICAgICAgbGlzdGEuYWRkKGVudHJ5LmdldEtleSgpKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgUmFuZG9tIHJuZCA9IG5ldyBSYW5kb20oKTsKICAgICAgICAgICAgICAgIGZvciAoaW50IGkgPSAwOyBpIDwgdG90YWw7IGkrKykgewogICAgICAgICAgICAgICAgICAgIFN0cmluZyBlbGVnaWRvID0gbGlzdGEuZ2V0KHJuZC5uZXh0SW50KGxpc3RhLnNpemUoKSkpOwogICAgICAgICAgICAgICAgICAgIGQudm90b3NUb3RhbGVzLnB1dChlbGVnaWRvLCBkLnZvdG9zVG90YWxlcy5nZXQoZWxlZ2lkbykgKyAxKTsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICBjLm1vc3RyYXJSZXN1bHRhZG9zKCk7CiAgICAgICAgICAgIH0gY2F0Y2ggKEV4Y2VwdGlvbiBleCkgewogICAgICAgICAgICAgICAgSk9wdGlvblBhbmUuc2hvd01lc3NhZ2VEaWFsb2codGhpcywgIkVycm9yOiBJbmdyZXNhIHVuIG7Dum1lcm8gdsOhbGlkby4iKTsKICAgICAgICAgICAgfQogICAgICAgIH0pOwoKICAgICAgICBhZGQoZXRpcXVldGEpOwogICAgICAgIGFkZChjYW1wbyk7CiAgICAgICAgYWRkKGdlbmVyYXIpOwogICAgfQp9CgpjbGFzcyBSZXN1bHRhZG9zIGV4dGVuZHMgSkZyYW1lIHsKICAgIHB1YmxpYyBSZXN1bHRhZG9zKENvbnRyb2xhZG9yIGMsIERhdG9zQ29tcGFydGlkb3MgZCkgewogICAgICAgIHNldFRpdGxlKCJSZXN1bHRhZG9zIik7CiAgICAgICAgc2V0U2l6ZSg1MDAsIDQwMCk7CiAgICAgICAgc2V0RGVmYXVsdENsb3NlT3BlcmF0aW9uKEVYSVRfT05fQ0xPU0UpOwogICAgICAgIHNldExheW91dChuZXcgQm9yZGVyTGF5b3V0KCkpOwoKICAgICAgICBKVGV4dEFyZWEgYXJlYSA9IG5ldyBKVGV4dEFyZWEoKTsKICAgICAgICBhcmVhLnNldEZvbnQobmV3IEZvbnQoIkFyaWFsIiwgRm9udC5QTEFJTiwgMTQpKTsKICAgICAgICBhcmVhLnNldEVkaXRhYmxlKGZhbHNlKTsKICAgICAgICBhcmVhLmFwcGVuZCgiQ2FuZGlkYXRvIC0gVm90b3MgLSBQb3JjZW50YWplXG4iKTsKCiAgICAgICAgZm9yIChNYXAuRW50cnk8U3RyaW5nLCBJbnRlZ2VyPiBlbnRyeSA6IGQudm90b3NUb3RhbGVzLmVudHJ5U2V0KCkpIHsKICAgICAgICAgICAgaW50IHZvdG9zID0gZW50cnkuZ2V0VmFsdWUoKTsKICAgICAgICAgICAgZG91YmxlIHBvcmNlbnRhamUgPSB2b3RvcyAqIDEwMC4wIC8gZC50b3RhbFZvdG9zOwogICAgICAgICAgICBhcmVhLmFwcGVuZChlbnRyeS5nZXRLZXkoKSArICIgLSAiICsgdm90b3MgKyAiIC0gIiArIFN0cmluZy5mb3JtYXQoIiUuMmYiLCBwb3JjZW50YWplKSArICIlXG4iKTsKICAgICAgICB9CgogICAgICAgIGFkZChuZXcgSlNjcm9sbFBhbmUoYXJlYSksIEJvcmRlckxheW91dC5DRU5URVIpOwogICAgfQp9Cg==