# Examen ALS final(parcial 2) 2018/19 MIT License Baltasar <jbgarcia@uvigo.es>
"""
1. (4pts.) La clase AlumnoALS alberga las notas de un alumno de ALS. Se contruye con un nombre y tres notas: la del parcial 1, la del parcial 2, y la del proyecto. Los métodos de esta clase serán exactamente __init__(), __getattr__() y __str__(). Aún así, será capaz de responder a la petición de varias “propiedades”: notas devuelve una nueva lista con las tres notas, parcial1 devolverá la nota del primer parcial, parcial2 la del segundo, y proyecto la del proyecto. El “método” calcula_nota_final_parciales() calcula la media de los dos parciales y la multiplica por 0.6. El “método” calcula_nota_final_proyecto() multiplica la nota del proyecto por 0.4. El “método” calcula_nota_final() devolverá la nota media ponderada: 0.6 * ((parcial1 + parcial2) / 2) + 0.4 * proyecto. El método __str__() devolverá la información en el formato <nombre>: 0.6 * ((<parcial1> + <parcial2>) / 2) + 0.4 * <proyecto> = <parciales> + <proyecto> = <nota_final>, como por ejemplo: Baltasar: 0.6 * ((10 + 10) / 2) + 0.4 * 10 = 6 + 4 = 10.
a1 = AlumnoALS(“Baltasar”, [10, 10, 10])
print(a1.notas[0], a1.parcial1, a1.notas[1], a1.parcial2) # 10 10 10 10
print(a1.calcula_nota_final_proyecto()) # 4
print(a1.calcula_nota_final()) # 10
print(a1) # Baltasar: 0.6 * ((10.00 + 10.00) / 2) + 0.4 * 10.00 = 6.00 + 4.00 = 10
2. (2pts.) Cree los métodos to_json(f) y from_json(f). El primero escribe la codificación JSON del objeto como un archivo, la segunda toma un archivo con contenido en formato JSON y crea un objeto con dicho contenido.
3. (4pts.) Escriba la función lambda nota_proyecto(a). Esta función recibe un objeto AlumnoALS y devuelve un texto con el formato: “<nombre>: <nota_proyecto>”, por ejemplo: “Baltasar: 10.00”. Escriba la función lambda lista_alumnos(la, f), que recibe como parámetros una lista de alumnos y una función que devolverá un texto por cada alumno que se le pase. Debe devolver un texto compuesto por todos los resultados de llamar a f en los objetos de la lista la. Componga ambas funciones para devolver un listado de las notas del proyecto de los alumnos.
listado = lista_alumnos([a1, a2], nota_proyecto))
print(resultado)
Baltasar: 10.00
Cantinflas: 7.00
"""
import json
class AlumnoALS:
def __init__ ( self , nombre, notas) :
self ._nombre = nombre
self ._notas = list ( notas)
def __getattr__ ( self , s) :
if s == "nombre" :
return self ._nombre
elif s == "notas" :
return list ( self ._notas)
elif s == "parcial1" :
return self ._notas[ 0 ]
elif s == "parcial2" :
return self ._notas[ 1 ]
elif s == "proyecto" :
return self ._notas[ 2 ]
elif s == "calcula_nota_final_parciales" :
return lambda : ( ( self ._notas[ 0 ] + self ._notas[ 1 ] ) / 2 ) * .6
elif s == "calcula_nota_final_proyecto" :
return lambda : self ._notas[ 2 ] * .4
elif s == "calcula_nota_final" :
return lambda : self .calcula_nota_final_parciales ( ) + self .calcula_nota_final_proyecto ( )
else :
raise AttributeError ( s)
def __str__ ( self ) :
return str .format ( "{}: 0.6 * (({:5.2f} + {:5.2f}) / 2) + 0.4 * {:5.2f} = {:5.2f} + {:5.2f} = {:5.2f}" ,
self .nombre ,
self .parcial1 ,
self .parcial2 ,
self .proyecto ,
self .calcula_nota_final_parciales ( ) ,
self .calcula_nota_final_proyecto ( ) ,
self .calcula_nota_final ( ) )
def to_json( self , f) :
return json.dump ( self .__dict__ , f)
@ staticmethod
def from_json( f) :
toret = AlumnoALS( "" , [ ] )
toret.__dict__ = json.load ( f)
return toret
nota_proyecto = lambda a: str .format ( "{}: {:5.2f}\n " , a.nombre , a.parcial1 )
lista_alumnos = lambda la, f: ( "" if not la or la == [ ]
else f( la[ 0 ] ) + lista_alumnos( la[ 1 :] , f) )
import io
import unittest
class TestAlumnoALS( unittest .TestCase ) :
def setUp( self ) :
self .notas_alumno1 = [ 10 , 10 , 10 ]
self .datos_alumno1 = { "_nombre" : "Baltasar" , "_notas" : self .notas_alumno1 }
self .alumno1 = AlumnoALS( "Baltasar" , self .notas_alumno1 )
def testAlumno1( self ) :
self .assertEqual ( "Baltasar" , self .alumno1 .nombre )
self .assertEqual ( self .notas_alumno1 , self .alumno1 .notas )
self .assertEqual ( "Baltasar: 0.6 * ((10.00 + 10.00) / 2) + 0.4 * 10.00 = 6.00 + 4.00 = 10.00" , str ( self .alumno1 ) )
def testParciales( self ) :
self .assertEqual ( self .notas_alumno1 [ 0 ] , self .alumno1 .notas [ 0 ] )
self .assertEqual ( self .notas_alumno1 [ 1 ] , self .alumno1 .notas [ 1 ] )
self .assertEqual ( self .notas_alumno1 [ 2 ] , self .alumno1 .notas [ 2 ] )
def testMetodosCalcula( self ) :
self .assertEqual ( 0.6 * ( ( self .notas_alumno1 [ 0 ] + self .notas_alumno1 [ 1 ] ) / 2 ) , self .alumno1 .calcula_nota_final_parciales ( ) )
self .assertEqual ( 0.4 * self .notas_alumno1 [ 1 ] , self .alumno1 .calcula_nota_final_proyecto ( ) )
def testAlumnoALSToJSON( self ) :
with io.StringIO ( ) as f:
self .alumno1 .to_json ( f)
self .assertEqual ( TestAlumnoALS.prepara_resultado ( ( self .datos_alumno1 ) ) , TestAlumnoALS.prepara_resultado ( f.getvalue ( ) .strip ( ) ) )
def testAlumnoALSFromJSON( self ) :
json_a = TestAlumnoALS.prepara_resultado ( self .datos_alumno1 )
with io.StringIO ( json_a) as f:
loaded_a = AlumnoALS.from_json ( f)
self .assertEqual ( self .datos_alumno1 , loaded_a.__dict__ )
def testNotaProyecto( self ) :
self .assertEqual (
str .format ( "{}: {:5.2f}\n " , self .alumno1 .nombre , self .alumno1 .parcial1 ) ,
nota_proyecto( self .alumno1 ) )
def testListaAlumnos( self ) :
listado = lista_alumnos( [ self .alumno1 ] , nota_proyecto)
self .assertEqual (
str .format ( "{}: {:5.2f}\n " , self .alumno1 .nombre , self .alumno1 .parcial1 ) ,
listado)
@ staticmethod
def prepara_resultado( s) :
return str ( s) .strip ( ) .replace ( '\' ' , '"' ) .replace ( ' ' , "" )
if __name__ == "__main__" :
unittest .main ( )
IyBFeGFtZW4gQUxTIGZpbmFsKHBhcmNpYWwgMikgMjAxOC8xOSBNSVQgTGljZW5zZSBCYWx0YXNhciA8amJnYXJjaWFAdXZpZ28uZXM+CgoKIiIiCiAgICAxLiAoNHB0cy4pIExhIGNsYXNlIEFsdW1ub0FMUyBhbGJlcmdhIGxhcyBub3RhcyBkZSB1biBhbHVtbm8gZGUgQUxTLiBTZSBjb250cnV5ZSBjb24gdW4gbm9tYnJlIHkgdHJlcyBub3RhczogbGEgZGVsIHBhcmNpYWwgMSwgbGEgZGVsIHBhcmNpYWwgMiwgeSBsYSBkZWwgcHJveWVjdG8uIExvcyBtw6l0b2RvcyBkZSBlc3RhIGNsYXNlIHNlcsOhbiBleGFjdGFtZW50ZSBfX2luaXRfXygpLCBfX2dldGF0dHJfXygpIHkgX19zdHJfXygpLiBBw7puIGFzw60sIHNlcsOhIGNhcGF6IGRlIHJlc3BvbmRlciBhIGxhIHBldGljacOzbiBkZSB2YXJpYXMg4oCccHJvcGllZGFkZXPigJ06IG5vdGFzIGRldnVlbHZlIHVuYSBudWV2YSBsaXN0YSBjb24gbGFzIHRyZXMgbm90YXMsIHBhcmNpYWwxIGRldm9sdmVyw6EgbGEgbm90YSBkZWwgcHJpbWVyIHBhcmNpYWwsIHBhcmNpYWwyIGxhIGRlbCBzZWd1bmRvLCB5IHByb3llY3RvIGxhIGRlbCBwcm95ZWN0by4gRWwg4oCcbcOpdG9kb+KAnSBjYWxjdWxhX25vdGFfZmluYWxfcGFyY2lhbGVzKCkgY2FsY3VsYSBsYSBtZWRpYSBkZSBsb3MgZG9zIHBhcmNpYWxlcyB5IGxhIG11bHRpcGxpY2EgcG9yIDAuNi4gRWwg4oCcbcOpdG9kb+KAnSBjYWxjdWxhX25vdGFfZmluYWxfcHJveWVjdG8oKSBtdWx0aXBsaWNhIGxhIG5vdGEgZGVsIHByb3llY3RvIHBvciAwLjQuIEVsIOKAnG3DqXRvZG/igJ0gY2FsY3VsYV9ub3RhX2ZpbmFsKCkgZGV2b2x2ZXLDoSBsYSBub3RhIG1lZGlhIHBvbmRlcmFkYTogMC42ICogKChwYXJjaWFsMSArIHBhcmNpYWwyKSAvIDIpICsgMC40ICogcHJveWVjdG8uIEVsIG3DqXRvZG8gX19zdHJfXygpIGRldm9sdmVyw6EgbGEgaW5mb3JtYWNpw7NuIGVuIGVsIGZvcm1hdG8gPG5vbWJyZT46IDAuNiAqICgoPHBhcmNpYWwxPiArIDxwYXJjaWFsMj4pIC8gMikgKyAwLjQgKiA8cHJveWVjdG8+ID0gPHBhcmNpYWxlcz4gKyA8cHJveWVjdG8+ID0gPG5vdGFfZmluYWw+LCBjb21vIHBvciBlamVtcGxvOiBCYWx0YXNhcjogMC42ICogKCgxMCArIDEwKSAvIDIpICsgMC40ICogMTAgPSA2ICsgNCA9IDEwLgoKICAgIAlhMSA9IEFsdW1ub0FMUyjigJxCYWx0YXNhcuKAnSwgWzEwLCAxMCwgMTBdKQoJcHJpbnQoYTEubm90YXNbMF0sIGExLnBhcmNpYWwxLCBhMS5ub3Rhc1sxXSwgYTEucGFyY2lhbDIpCQkjIDEwIDEwIDEwIDEwCglwcmludChhMS5jYWxjdWxhX25vdGFfZmluYWxfcHJveWVjdG8oKSkJCQkJCSMgNAoJcHJpbnQoYTEuY2FsY3VsYV9ub3RhX2ZpbmFsKCkpCQkJCQkJIyAxMAoJcHJpbnQoYTEpCSMgQmFsdGFzYXI6IDAuNiAqICgoMTAuMDAgKyAxMC4wMCkgLyAyKSArIDAuNCAqIDEwLjAwID0gNi4wMCArIDQuMDAgPSAxMAoKCiAgICAyLiAoMnB0cy4pIENyZWUgbG9zIG3DqXRvZG9zIHRvX2pzb24oZikgeSBmcm9tX2pzb24oZikuIEVsIHByaW1lcm8gZXNjcmliZSBsYSBjb2RpZmljYWNpw7NuIEpTT04gZGVsIG9iamV0byBjb21vIHVuIGFyY2hpdm8sIGxhIHNlZ3VuZGEgdG9tYSB1biBhcmNoaXZvIGNvbiBjb250ZW5pZG8gZW4gZm9ybWF0byBKU09OIHkgY3JlYSB1biBvYmpldG8gY29uIGRpY2hvIGNvbnRlbmlkby4KCiAgICAzLiAoNHB0cy4pIEVzY3JpYmEgbGEgZnVuY2nDs24gbGFtYmRhIG5vdGFfcHJveWVjdG8oYSkuIEVzdGEgZnVuY2nDs24gcmVjaWJlIHVuIG9iamV0byBBbHVtbm9BTFMgeSBkZXZ1ZWx2ZSB1biB0ZXh0byBjb24gZWwgZm9ybWF0bzog4oCcPG5vbWJyZT46IDxub3RhX3Byb3llY3RvPuKAnSwgcG9yIGVqZW1wbG86IOKAnEJhbHRhc2FyOiAxMC4wMOKAnS4gRXNjcmliYSBsYSBmdW5jacOzbiBsYW1iZGEgbGlzdGFfYWx1bW5vcyhsYSwgZiksIHF1ZSByZWNpYmUgY29tbyBwYXLDoW1ldHJvcyB1bmEgbGlzdGEgZGUgYWx1bW5vcyB5IHVuYSBmdW5jacOzbiBxdWUgZGV2b2x2ZXLDoSB1biB0ZXh0byBwb3IgY2FkYSBhbHVtbm8gcXVlIHNlIGxlIHBhc2UuIERlYmUgZGV2b2x2ZXIgdW4gdGV4dG8gY29tcHVlc3RvIHBvciB0b2RvcyBsb3MgcmVzdWx0YWRvcyBkZSBsbGFtYXIgYSBmIGVuIGxvcyBvYmpldG9zIGRlIGxhIGxpc3RhIGxhLiBDb21wb25nYSBhbWJhcyBmdW5jaW9uZXMgcGFyYSBkZXZvbHZlciB1biBsaXN0YWRvIGRlIGxhcyBub3RhcyBkZWwgcHJveWVjdG8gZGUgbG9zIGFsdW1ub3MuCgoJbGlzdGFkbyA9IGxpc3RhX2FsdW1ub3MoW2ExLCBhMl0sIG5vdGFfcHJveWVjdG8pKQoJcHJpbnQocmVzdWx0YWRvKQoKCUJhbHRhc2FyOiAxMC4wMAoJQ2FudGluZmxhczogIDcuMDAKCiIiIgoKCmltcG9ydCBqc29uCgoKY2xhc3MgQWx1bW5vQUxTOgogICAgZGVmIF9faW5pdF9fKHNlbGYsIG5vbWJyZSwgbm90YXMpOgogICAgICAgIHNlbGYuX25vbWJyZSA9IG5vbWJyZQogICAgICAgIHNlbGYuX25vdGFzID0gbGlzdChub3RhcykKICAgICAgICAKICAgIGRlZiBfX2dldGF0dHJfXyhzZWxmLCBzKToKICAgICAgICBpZiBzID09ICJub21icmUiOgogICAgICAgICAgICByZXR1cm4gc2VsZi5fbm9tYnJlCiAgICAgICAgZWxpZiBzID09ICJub3RhcyI6CiAgICAgICAgICAgIHJldHVybiBsaXN0KHNlbGYuX25vdGFzKQogICAgICAgIGVsaWYgcyA9PSAicGFyY2lhbDEiOgogICAgICAgICAgICByZXR1cm4gc2VsZi5fbm90YXNbMF0KICAgICAgICBlbGlmIHMgPT0gInBhcmNpYWwyIjoKICAgICAgICAgICAgcmV0dXJuIHNlbGYuX25vdGFzWzFdCiAgICAgICAgZWxpZiBzID09ICJwcm95ZWN0byI6CiAgICAgICAgICAgIHJldHVybiBzZWxmLl9ub3Rhc1syXQogICAgICAgIGVsaWYgcyA9PSAiY2FsY3VsYV9ub3RhX2ZpbmFsX3BhcmNpYWxlcyI6CiAgICAgICAgICAgIHJldHVybiBsYW1iZGE6ICgoc2VsZi5fbm90YXNbMF0gKyBzZWxmLl9ub3Rhc1sxXSkgLyAyKSAqIC42CiAgICAgICAgZWxpZiBzID09ICJjYWxjdWxhX25vdGFfZmluYWxfcHJveWVjdG8iOgogICAgICAgICAgICByZXR1cm4gbGFtYmRhOiBzZWxmLl9ub3Rhc1syXSAqIC40CiAgICAgICAgZWxpZiBzID09ICJjYWxjdWxhX25vdGFfZmluYWwiOgogICAgICAgICAgICByZXR1cm4gbGFtYmRhOiBzZWxmLmNhbGN1bGFfbm90YV9maW5hbF9wYXJjaWFsZXMoKSArIHNlbGYuY2FsY3VsYV9ub3RhX2ZpbmFsX3Byb3llY3RvKCkKICAgICAgICBlbHNlOgogICAgICAgICAgICByYWlzZSBBdHRyaWJ1dGVFcnJvcihzKQogICAgICAgIAogICAgZGVmIF9fc3RyX18oc2VsZik6CiAgICAgICAgcmV0dXJuIHN0ci5mb3JtYXQoInt9OiAwLjYgKiAoKHs6NS4yZn0gKyB7OjUuMmZ9KSAvIDIpICsgMC40ICogezo1LjJmfSA9IHs6NS4yZn0gKyB7OjUuMmZ9ID0gezo1LjJmfSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5ub21icmUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5wYXJjaWFsMSwKICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLnBhcmNpYWwyLAogICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYucHJveWVjdG8sCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5jYWxjdWxhX25vdGFfZmluYWxfcGFyY2lhbGVzKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5jYWxjdWxhX25vdGFfZmluYWxfcHJveWVjdG8oKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmNhbGN1bGFfbm90YV9maW5hbCgpKQogICAgCiAgICBkZWYgdG9fanNvbihzZWxmLCBmKToKICAgICAgICByZXR1cm4ganNvbi5kdW1wKHNlbGYuX19kaWN0X18sIGYpCiAgICAgICAgCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZnJvbV9qc29uKGYpOgogICAgICAgIHRvcmV0ID0gQWx1bW5vQUxTKCIiLCBbXSkKICAgICAgICB0b3JldC5fX2RpY3RfXyA9IGpzb24ubG9hZChmKQogICAgICAgIHJldHVybiB0b3JldAogICAgICAgIAoKbm90YV9wcm95ZWN0byA9IGxhbWJkYSBhOiBzdHIuZm9ybWF0KCJ7fTogezo1LjJmfVxuIiwgYS5ub21icmUsIGEucGFyY2lhbDEpCmxpc3RhX2FsdW1ub3MgPSBsYW1iZGEgbGEsIGY6ICgiIiBpZiBub3QgbGEgb3IgbGEgPT0gW10KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2UgZihsYVswXSkgKyBsaXN0YV9hbHVtbm9zKGxhWzE6XSwgZikpCgoKCmltcG9ydCBpbwppbXBvcnQgdW5pdHRlc3QKCgpjbGFzcyBUZXN0QWx1bW5vQUxTKHVuaXR0ZXN0LlRlc3RDYXNlKToKICAgIGRlZiBzZXRVcChzZWxmKToKICAgICAgICBzZWxmLm5vdGFzX2FsdW1ubzEgPSBbMTAsIDEwLCAxMF0KICAgICAgICBzZWxmLmRhdG9zX2FsdW1ubzEgPSB7Il9ub21icmUiOiAiQmFsdGFzYXIiLCAiX25vdGFzIjogc2VsZi5ub3Rhc19hbHVtbm8xfQogICAgICAgIHNlbGYuYWx1bW5vMSA9IEFsdW1ub0FMUygiQmFsdGFzYXIiLCBzZWxmLm5vdGFzX2FsdW1ubzEpCiAgICAgICAgCiAgICBkZWYgdGVzdEFsdW1ubzEoc2VsZik6CiAgICAgICAgc2VsZi5hc3NlcnRFcXVhbCgiQmFsdGFzYXIiLCBzZWxmLmFsdW1ubzEubm9tYnJlKQogICAgICAgIHNlbGYuYXNzZXJ0RXF1YWwoc2VsZi5ub3Rhc19hbHVtbm8xLCBzZWxmLmFsdW1ubzEubm90YXMpCiAgICAgICAgc2VsZi5hc3NlcnRFcXVhbCgiQmFsdGFzYXI6IDAuNiAqICgoMTAuMDAgKyAxMC4wMCkgLyAyKSArIDAuNCAqIDEwLjAwID0gIDYuMDAgKyAgNC4wMCA9IDEwLjAwIiwgc3RyKHNlbGYuYWx1bW5vMSkpCiAgICAgICAgCiAgICBkZWYgdGVzdFBhcmNpYWxlcyhzZWxmKToKICAgICAgICBzZWxmLmFzc2VydEVxdWFsKHNlbGYubm90YXNfYWx1bW5vMVswXSwgc2VsZi5hbHVtbm8xLm5vdGFzWzBdKQogICAgICAgIHNlbGYuYXNzZXJ0RXF1YWwoc2VsZi5ub3Rhc19hbHVtbm8xWzFdLCBzZWxmLmFsdW1ubzEubm90YXNbMV0pCiAgICAgICAgc2VsZi5hc3NlcnRFcXVhbChzZWxmLm5vdGFzX2FsdW1ubzFbMl0sIHNlbGYuYWx1bW5vMS5ub3Rhc1syXSkKICAgICAgICAKICAgIGRlZiB0ZXN0TWV0b2Rvc0NhbGN1bGEoc2VsZik6CiAgICAgICAgc2VsZi5hc3NlcnRFcXVhbCgwLjYgKiAoKHNlbGYubm90YXNfYWx1bW5vMVswXSArIHNlbGYubm90YXNfYWx1bW5vMVsxXSkgLyAyKSwgc2VsZi5hbHVtbm8xLmNhbGN1bGFfbm90YV9maW5hbF9wYXJjaWFsZXMoKSkKICAgICAgICBzZWxmLmFzc2VydEVxdWFsKDAuNCAqIHNlbGYubm90YXNfYWx1bW5vMVsxXSwgc2VsZi5hbHVtbm8xLmNhbGN1bGFfbm90YV9maW5hbF9wcm95ZWN0bygpKQogICAgICAgIAogICAgZGVmIHRlc3RBbHVtbm9BTFNUb0pTT04oc2VsZik6CiAgICAgICAgd2l0aCBpby5TdHJpbmdJTygpIGFzIGY6CiAgICAgICAgICAgIHNlbGYuYWx1bW5vMS50b19qc29uKGYpCiAgICAgICAgICAgIHNlbGYuYXNzZXJ0RXF1YWwoVGVzdEFsdW1ub0FMUy5wcmVwYXJhX3Jlc3VsdGFkbygoc2VsZi5kYXRvc19hbHVtbm8xKSksIFRlc3RBbHVtbm9BTFMucHJlcGFyYV9yZXN1bHRhZG8oZi5nZXR2YWx1ZSgpLnN0cmlwKCkpKQogICAgICAgICAgICAKICAgIGRlZiB0ZXN0QWx1bW5vQUxTRnJvbUpTT04oc2VsZik6CiAgICAgICAganNvbl9hID0gVGVzdEFsdW1ub0FMUy5wcmVwYXJhX3Jlc3VsdGFkbyhzZWxmLmRhdG9zX2FsdW1ubzEpCiAgICAgICAgCiAgICAgICAgd2l0aCBpby5TdHJpbmdJTyhqc29uX2EpIGFzIGY6CiAgICAgICAgICAgIGxvYWRlZF9hID0gQWx1bW5vQUxTLmZyb21fanNvbihmKQoKICAgICAgICBzZWxmLmFzc2VydEVxdWFsKHNlbGYuZGF0b3NfYWx1bW5vMSwgbG9hZGVkX2EuX19kaWN0X18pCiAgICAgICAgICAgIAogICAgZGVmIHRlc3ROb3RhUHJveWVjdG8oc2VsZik6CiAgICAgICAgc2VsZi5hc3NlcnRFcXVhbCgKICAgICAgICAgICAgc3RyLmZvcm1hdCgie306IHs6NS4yZn1cbiIsIHNlbGYuYWx1bW5vMS5ub21icmUsIHNlbGYuYWx1bW5vMS5wYXJjaWFsMSksCiAgICAgICAgICAgIG5vdGFfcHJveWVjdG8oc2VsZi5hbHVtbm8xKSkKICAgICAgICAKICAgIGRlZiB0ZXN0TGlzdGFBbHVtbm9zKHNlbGYpOgogICAgICAgIGxpc3RhZG8gPSBsaXN0YV9hbHVtbm9zKFtzZWxmLmFsdW1ubzFdLCBub3RhX3Byb3llY3RvKQogICAgICAgIHNlbGYuYXNzZXJ0RXF1YWwoCiAgICAgICAgICAgIHN0ci5mb3JtYXQoInt9OiB7OjUuMmZ9XG4iLCBzZWxmLmFsdW1ubzEubm9tYnJlLCBzZWxmLmFsdW1ubzEucGFyY2lhbDEpLAogICAgICAgICAgICBsaXN0YWRvKQogICAgICAgIAogICAgQHN0YXRpY21ldGhvZAogICAgZGVmIHByZXBhcmFfcmVzdWx0YWRvKHMpOgogICAgICAgIHJldHVybiBzdHIocykuc3RyaXAoKS5yZXBsYWNlKCdcJycsICciJykucmVwbGFjZSgnICcsICIiKQoKCmlmIF9fbmFtZV9fID09ICJfX21haW5fXyI6CiAgICB1bml0dGVzdC5tYWluKCkK