from optapy import problem_fact, planning_id, planning_entity, planning_variable, planning_solution, planning_score
from optapy import planning_entity_collection_property, problem_fact_collection_property, value_range_provider
from optapy.score import HardSoftScore
from datetime import datetime
import uuid
@problem_fact
class Seat:
def __init__ (self, seat_id=None, room_id=None, team_id=None, created_on=None, position_x=None, position_y=None, code=None):
self.seat_id=seat_id
self.room_id=room_id
self.team_id=team_id
self.created_on=created_on
self.position_x=position_x
self.position_y=position_y
self.code=code
@planning_id
def get_id (self):
return self.seat_id
def __str__ (self):
return f'Seat {self.seat_id} in room {self.room_id} for team {self.team_id} code: {self.code}'
def to_dict (self):
return {
'seat_id': self.seat_id,
'room_id': self.room_id,
'team_id': self.team_id,
'created_on': self.created_on,
'code': self.code
}
@problem_fact
class DateSlot:
def __init__(self, id, date=None):
self.id=id
self.date=date
@planning_id
def get_id (self):
return self.id
def __str__ (self):
return f'Dateslot {self.id} for {self.date}'
def to_dict(self):
return {
'id': self.id,
'date': self.date
}
@problem_fact
class Employee:
def __init__ (self, uuid, prenom=None, nom=None, photo_principale=None,
lastupd_date=None, pos_city=None, pos_country=None,
date_entre=None, fonction=None, date_fin=None, idc=None,
nouvelle_recrute=None, idequipe=None, date_naissance=None, presentation=None,
video_principale=None, ambassadeur=None, id_emplacement_pref=None):
self.uuid=uuid
self.prenom=prenom
self.nom=nom
self.photo_principale=photo_principale
self.lastupd_date=lastupd_date
self.pos_city=pos_city
self.pos_country=pos_country
self.date_entre=date_entre
self.fonction=fonction
self.date_fin=date_fin
self.idc=idc
self.nouvelle_recrute=nouvelle_recrute
self.idequipe=idequipe
self.date_naissance=date_naissance
self.presentation=presentation
self.video_principale=video_principale
self.ambassadeur=ambassadeur
self.id_emplacement_pref=id_emplacement_pref
@planning_id
def get_id (self):
return self.uuid
def __str__ (self):
return f'Employee(name = {self.prenom} {self.nom} in team {self.idequipe} prefered_seat {self.id_emplacement_pref})'
def to_dict (self):
return {
'uuid': self.uuid,
'prenom': self.prenom,
'nom': self.nom,
'photo_principale': self.photo_principale,
'lastupd_date': self.lastupd_date.isoformat(),
'pos_city': self.pos_city,
'pos_country': self.pos_country,
'date_entre': self.date_entre,
'fonction': self.fonction,
'date_fin': self.date_fin,
'idc': self.idc,
'nouvelle_recrute': self.nouvelle_recrute,
'idequipe': self.idequipe,
'date_naissance': self.date_naissance,
'presentation': self.presentation,
'video_principale': self.video_principale,
'ambassadeur': self.ambassadeur,
'id_emplacement_pref': self.id_emplacement_pref
}
@planning_entity
class Reservation:
def __init__ (self, reservation_id, date: DateSlot=None, employee: Employee=None, seat: Seat=None):
self.reservation_id=reservation_id
self.date=date
self.employee=employee
self.seat=seat
@planning_id
def get_id(self):
return self.reservation_id
@planning_variable(Employee, value_range_provider_refs=['employeeRange'])
def get_employee(self):
return self.employee
def set_employee(self, employee):
self.employee=employee
@planning_variable(Seat, value_range_provider_refs=['seatRange'])
def get_seat(self):
return self.seat
def set_seat(self, seat):
self.seat=seat
@planning_variable(DateSlot, value_range_provider_refs=['dateRange'])
def get_dateslot(self):
return self.date
def set_dateslot(self, date):
self.date=date
def __str__ (self):
return f'Reservation(reservation_id = {self.reservation_id} for employee {self.employee} on {self.date} at {self.seat})'
def to_dict(self):
return {
'reservation_id': self.reservation_id,
'date': self.date,
'employee': self.employee,
'seat': self.seat
}
def format_list(a_list):
return ',\n'.join(map(str, a_list))
@planning_solution
class ReservationSchedule:
def __init__ (self, employee_list, seat_list, reservation_list, dates, score=None):
self.employee_list=employee_list
self.seat_list=seat_list
self.reservation_list=reservation_list
self.dates=dates
self.score=score
@problem_fact_collection_property(Employee)
@value_range_provider('employeeRange')
def get_employee_list (self):
return self.employee_list
@problem_fact_collection_property(Seat)
@value_range_provider('seatRange')
def get_seat_list (self):
return self.seat_list
@problem_fact_collection_property(DateSlot)
@value_range_provider('dateRange')
def get_dateslot_list (self):
return self.dates
@planning_entity_collection_property(Reservation)
def get_reservation_list (self):
return self.reservation_list
@planning_score(HardSoftScore)
def get_score (self):
return self.score
def set_score (self, newScore):
self.score=newScore
def __str__(self):
return f"ReservationSchedule(employee_list = {format_list(self.employee_list)},\n seat_list = {format_list(self.seat_list)}, \n reservation_list = {format_list(self.reservation_list)}, \n dates = {format_list(self.dates)}, \n {str(self.score.toString()) if self.score is not None else 'None'})"
def generate_problem():
seat_list=[
Seat(seat_id=uuid.uuid4(), room_id=uuid.uuid4(), team_id=1, created_on=datetime.now(), position_x=1, position_y=1, code='A1'),
Seat(seat_id=uuid.uuid4(), room_id=uuid.uuid4(), team_id=2, created_on=datetime.now(), position_x=2, position_y=1, code='A2'),
Seat(seat_id=uuid.uuid4(), room_id=uuid.uuid4(), team_id=1, created_on=datetime.now(), position_x=3, position_y=1, code='A3'),
Seat(seat_id=uuid.uuid4(), room_id=uuid.uuid4(), team_id=2, created_on=datetime.now(), position_x=4, position_y=1, code='A4'),
Seat(seat_id=uuid.uuid4(), room_id=uuid.uuid4(), team_id=1, created_on=datetime.now(), position_x=1, position_y=2, code='B1'),
Seat(seat_id=uuid.uuid4(), room_id=uuid.uuid4(), team_id=2, created_on=datetime.now(), position_x=2, position_y=2, code='B2'),
Seat(seat_id=uuid.uuid4(), room_id=uuid.uuid4(), team_id=1, created_on=datetime.now(), position_x=3, position_y=2, code='B3'),
Seat(seat_id=uuid.uuid4(), room_id=uuid.uuid4(), team_id=1, created_on=datetime.now(), position_x=4, position_y=2, code='B4'),
Seat(seat_id=uuid.uuid4(), room_id=uuid.uuid4(), team_id=2, created_on=datetime.now(), position_x=1, position_y=3, code='C1'),
Seat(seat_id=uuid.uuid4(), room_id=uuid.uuid4(), team_id=1, created_on=datetime.now(), position_x=2, position_y=3, code='C2'),
Seat(seat_id=uuid.uuid4(), room_id=uuid.uuid4(), team_id=1, created_on=datetime.now(), position_x=3, position_y=3, code='C3'),
Seat(seat_id=uuid.uuid4(), room_id=uuid.uuid4(), team_id=2, created_on=datetime.now(), position_x=4, position_y=3, code='C4'),
Seat(seat_id=uuid.uuid4(), room_id=uuid.uuid4(), team_id=3, created_on=datetime.now(), position_x=1, position_y=4, code='D1'),
Seat(seat_id=uuid.uuid4(), room_id=uuid.uuid4(), team_id=3, created_on=datetime.now(), position_x=2, position_y=4, code='D2'),
Seat(seat_id=uuid.uuid4(), room_id=uuid.uuid4(), team_id=3, created_on=datetime.now(), position_x=3, position_y=4, code='D3'),
Seat(seat_id=uuid.uuid4(), room_id=uuid.uuid4(), team_id=3, created_on=datetime.now(), position_x=4, position_y=4, code='D4')
]
employee_list=[
Employee(uuid.uuid4(), prenom='Karim', nom='test', idequipe=1, id_emplacement_pref=seat_list[4].seat_id),
Employee(uuid.uuid4(), prenom='Sara', nom='test', idequipe=2, id_emplacement_pref=seat_list[5].seat_id),
Employee(uuid.uuid4(), prenom='John', nom='test', idequipe=1, id_emplacement_pref=seat_list[6].seat_id),
Employee(uuid.uuid4(), prenom='Jane', nom='test', idequipe=1, id_emplacement_pref=seat_list[7].seat_id),
Employee(uuid.uuid4(), prenom='Ons', nom='test', idequipe=1, id_emplacement_pref=seat_list[0].seat_id),
Employee(uuid.uuid4(), prenom='Maha', nom='test', idequipe=1, id_emplacement_pref=seat_list[2].seat_id),
Employee(uuid.uuid4(), prenom='Salma', nom='test', idequipe=2, id_emplacement_pref=seat_list[3].seat_id),
Employee(uuid.uuid4(), prenom='Mahdi', nom='test', idequipe=2, id_emplacement_pref=seat_list[1].seat_id),
Employee(uuid.uuid4(), prenom='Manuel', nom='test', idequipe=2, id_emplacement_pref=seat_list[8].seat_id),
Employee(uuid.uuid4(), prenom='Jack', nom='test', idequipe=3, id_emplacement_pref=seat_list[12].seat_id),
Employee(uuid.uuid4(), prenom='Jill', nom='test', idequipe=3, id_emplacement_pref=seat_list[14].seat_id),
Employee(uuid.uuid4(), prenom='Jana', nom='test', idequipe=1, id_emplacement_pref=seat_list[9].seat_id),
Employee(uuid.uuid4(), prenom='Jasmine', nom='test', idequipe=1, id_emplacement_pref=seat_list[10].seat_id),
Employee(uuid.uuid4(), prenom='Jasmin', nom='test', idequipe=3, id_emplacement_pref=seat_list[15].seat_id),
Employee(uuid.uuid4(), prenom='Joseph', nom='test', idequipe=2, id_emplacement_pref=seat_list[11].seat_id),
Employee(uuid.uuid4(), prenom='José', nom='test', idequipe=3, id_emplacement_pref=seat_list[13].seat_id)
]
dates = []
for i in range (1, 4):
dates.append(DateSlot(i, datetime(2020, 1, i)))
reservation_list = []
for i in range (1, len(seat_list) + 1):
reservation_list.append(Reservation(i))
reservation = reservation_list[0]
reservation.set_dateslot(dates[0])
reservation.set_employee(employee_list[0])
reservation.set_seat(seat_list[4])
return ReservationSchedule(dates=dates, seat_list=seat_list, reservation_list=reservation_list, employee_list=employee_list)
ZnJvbSBvcHRhcHkgaW1wb3J0IHByb2JsZW1fZmFjdCwgcGxhbm5pbmdfaWQsIHBsYW5uaW5nX2VudGl0eSwgcGxhbm5pbmdfdmFyaWFibGUsIHBsYW5uaW5nX3NvbHV0aW9uLCBwbGFubmluZ19zY29yZQpmcm9tIG9wdGFweSBpbXBvcnQgcGxhbm5pbmdfZW50aXR5X2NvbGxlY3Rpb25fcHJvcGVydHksIHByb2JsZW1fZmFjdF9jb2xsZWN0aW9uX3Byb3BlcnR5LCB2YWx1ZV9yYW5nZV9wcm92aWRlcgpmcm9tIG9wdGFweS5zY29yZSBpbXBvcnQgSGFyZFNvZnRTY29yZQpmcm9tIGRhdGV0aW1lIGltcG9ydCBkYXRldGltZQppbXBvcnQgdXVpZAoKQHByb2JsZW1fZmFjdApjbGFzcyBTZWF0OgogICAgZGVmIF9faW5pdF9fIChzZWxmLCBzZWF0X2lkPU5vbmUsIHJvb21faWQ9Tm9uZSwgdGVhbV9pZD1Ob25lLCBjcmVhdGVkX29uPU5vbmUsIHBvc2l0aW9uX3g9Tm9uZSwgcG9zaXRpb25feT1Ob25lLCBjb2RlPU5vbmUpOgogICAgICAgIHNlbGYuc2VhdF9pZD1zZWF0X2lkCiAgICAgICAgc2VsZi5yb29tX2lkPXJvb21faWQKICAgICAgICBzZWxmLnRlYW1faWQ9dGVhbV9pZAogICAgICAgIHNlbGYuY3JlYXRlZF9vbj1jcmVhdGVkX29uCiAgICAgICAgc2VsZi5wb3NpdGlvbl94PXBvc2l0aW9uX3gKICAgICAgICBzZWxmLnBvc2l0aW9uX3k9cG9zaXRpb25feQogICAgICAgIHNlbGYuY29kZT1jb2RlCiAgICBAcGxhbm5pbmdfaWQKICAgIGRlZiBnZXRfaWQgKHNlbGYpOgogICAgICAgIHJldHVybiBzZWxmLnNlYXRfaWQKICAgIGRlZiBfX3N0cl9fIChzZWxmKToKICAgICAgICByZXR1cm4gZidTZWF0IHtzZWxmLnNlYXRfaWR9IGluIHJvb20ge3NlbGYucm9vbV9pZH0gZm9yIHRlYW0ge3NlbGYudGVhbV9pZH0gY29kZToge3NlbGYuY29kZX0nCiAgICBkZWYgdG9fZGljdCAoc2VsZik6CiAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgJ3NlYXRfaWQnOiBzZWxmLnNlYXRfaWQsCiAgICAgICAgICAgICdyb29tX2lkJzogc2VsZi5yb29tX2lkLAogICAgICAgICAgICAndGVhbV9pZCc6IHNlbGYudGVhbV9pZCwKICAgICAgICAgICAgJ2NyZWF0ZWRfb24nOiBzZWxmLmNyZWF0ZWRfb24sCiAgICAgICAgICAgICdjb2RlJzogc2VsZi5jb2RlCiAgICAgICAgfQoKQHByb2JsZW1fZmFjdApjbGFzcyBEYXRlU2xvdDoKICAgIGRlZiBfX2luaXRfXyhzZWxmLCBpZCwgZGF0ZT1Ob25lKToKICAgICAgICBzZWxmLmlkPWlkCiAgICAgICAgc2VsZi5kYXRlPWRhdGUKICAgIEBwbGFubmluZ19pZAogICAgZGVmIGdldF9pZCAoc2VsZik6CiAgICAgICAgcmV0dXJuIHNlbGYuaWQKICAgIGRlZiBfX3N0cl9fIChzZWxmKToKICAgICAgICByZXR1cm4gZidEYXRlc2xvdCB7c2VsZi5pZH0gZm9yIHtzZWxmLmRhdGV9JwogICAgZGVmIHRvX2RpY3Qoc2VsZik6CiAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgJ2lkJzogc2VsZi5pZCwKICAgICAgICAgICAgJ2RhdGUnOiBzZWxmLmRhdGUKICAgICAgICB9CgpAcHJvYmxlbV9mYWN0CmNsYXNzIEVtcGxveWVlOgogICAgZGVmIF9faW5pdF9fIChzZWxmLCB1dWlkLCBwcmVub209Tm9uZSwgbm9tPU5vbmUsIHBob3RvX3ByaW5jaXBhbGU9Tm9uZSwKICAgICAgICAgICAgICAgICAgbGFzdHVwZF9kYXRlPU5vbmUsIHBvc19jaXR5PU5vbmUsIHBvc19jb3VudHJ5PU5vbmUsCiAgICAgICAgICAgICAgICAgIGRhdGVfZW50cmU9Tm9uZSwgZm9uY3Rpb249Tm9uZSwgZGF0ZV9maW49Tm9uZSwgaWRjPU5vbmUsCiAgICAgICAgICAgICAgICAgIG5vdXZlbGxlX3JlY3J1dGU9Tm9uZSwgaWRlcXVpcGU9Tm9uZSwgZGF0ZV9uYWlzc2FuY2U9Tm9uZSwgcHJlc2VudGF0aW9uPU5vbmUsCiAgICAgICAgICAgICAgICAgIHZpZGVvX3ByaW5jaXBhbGU9Tm9uZSwgYW1iYXNzYWRldXI9Tm9uZSwgaWRfZW1wbGFjZW1lbnRfcHJlZj1Ob25lKToKICAgICAgICBzZWxmLnV1aWQ9dXVpZAogICAgICAgIHNlbGYucHJlbm9tPXByZW5vbQogICAgICAgIHNlbGYubm9tPW5vbQogICAgICAgIHNlbGYucGhvdG9fcHJpbmNpcGFsZT1waG90b19wcmluY2lwYWxlCiAgICAgICAgc2VsZi5sYXN0dXBkX2RhdGU9bGFzdHVwZF9kYXRlCiAgICAgICAgc2VsZi5wb3NfY2l0eT1wb3NfY2l0eQogICAgICAgIHNlbGYucG9zX2NvdW50cnk9cG9zX2NvdW50cnkKICAgICAgICBzZWxmLmRhdGVfZW50cmU9ZGF0ZV9lbnRyZQogICAgICAgIHNlbGYuZm9uY3Rpb249Zm9uY3Rpb24KICAgICAgICBzZWxmLmRhdGVfZmluPWRhdGVfZmluCiAgICAgICAgc2VsZi5pZGM9aWRjCiAgICAgICAgc2VsZi5ub3V2ZWxsZV9yZWNydXRlPW5vdXZlbGxlX3JlY3J1dGUKICAgICAgICBzZWxmLmlkZXF1aXBlPWlkZXF1aXBlCiAgICAgICAgc2VsZi5kYXRlX25haXNzYW5jZT1kYXRlX25haXNzYW5jZQogICAgICAgIHNlbGYucHJlc2VudGF0aW9uPXByZXNlbnRhdGlvbgogICAgICAgIHNlbGYudmlkZW9fcHJpbmNpcGFsZT12aWRlb19wcmluY2lwYWxlCiAgICAgICAgc2VsZi5hbWJhc3NhZGV1cj1hbWJhc3NhZGV1cgogICAgICAgIHNlbGYuaWRfZW1wbGFjZW1lbnRfcHJlZj1pZF9lbXBsYWNlbWVudF9wcmVmCiAgICBAcGxhbm5pbmdfaWQKICAgIGRlZiBnZXRfaWQgKHNlbGYpOgogICAgICAgIHJldHVybiBzZWxmLnV1aWQKICAgIGRlZiBfX3N0cl9fIChzZWxmKToKICAgICAgICByZXR1cm4gZidFbXBsb3llZShuYW1lID0ge3NlbGYucHJlbm9tfSB7c2VsZi5ub219IGluIHRlYW0ge3NlbGYuaWRlcXVpcGV9IHByZWZlcmVkX3NlYXQge3NlbGYuaWRfZW1wbGFjZW1lbnRfcHJlZn0pJwogICAgZGVmIHRvX2RpY3QgKHNlbGYpOgogICAgICAgIHJldHVybiB7CiAgICAgICAgICAgICd1dWlkJzogc2VsZi51dWlkLAogICAgICAgICAgICAncHJlbm9tJzogc2VsZi5wcmVub20sCiAgICAgICAgICAgICdub20nOiBzZWxmLm5vbSwKICAgICAgICAgICAgJ3Bob3RvX3ByaW5jaXBhbGUnOiBzZWxmLnBob3RvX3ByaW5jaXBhbGUsCiAgICAgICAgICAgICdsYXN0dXBkX2RhdGUnOiBzZWxmLmxhc3R1cGRfZGF0ZS5pc29mb3JtYXQoKSwKICAgICAgICAgICAgJ3Bvc19jaXR5Jzogc2VsZi5wb3NfY2l0eSwKICAgICAgICAgICAgJ3Bvc19jb3VudHJ5Jzogc2VsZi5wb3NfY291bnRyeSwKICAgICAgICAgICAgJ2RhdGVfZW50cmUnOiBzZWxmLmRhdGVfZW50cmUsCiAgICAgICAgICAgICdmb25jdGlvbic6IHNlbGYuZm9uY3Rpb24sCiAgICAgICAgICAgICdkYXRlX2Zpbic6IHNlbGYuZGF0ZV9maW4sCiAgICAgICAgICAgICdpZGMnOiBzZWxmLmlkYywKICAgICAgICAgICAgJ25vdXZlbGxlX3JlY3J1dGUnOiBzZWxmLm5vdXZlbGxlX3JlY3J1dGUsCiAgICAgICAgICAgICdpZGVxdWlwZSc6IHNlbGYuaWRlcXVpcGUsCiAgICAgICAgICAgICdkYXRlX25haXNzYW5jZSc6IHNlbGYuZGF0ZV9uYWlzc2FuY2UsCiAgICAgICAgICAgICdwcmVzZW50YXRpb24nOiBzZWxmLnByZXNlbnRhdGlvbiwKICAgICAgICAgICAgJ3ZpZGVvX3ByaW5jaXBhbGUnOiBzZWxmLnZpZGVvX3ByaW5jaXBhbGUsCiAgICAgICAgICAgICdhbWJhc3NhZGV1cic6IHNlbGYuYW1iYXNzYWRldXIsCiAgICAgICAgICAgICdpZF9lbXBsYWNlbWVudF9wcmVmJzogc2VsZi5pZF9lbXBsYWNlbWVudF9wcmVmCiAgICAgICAgfQoKQHBsYW5uaW5nX2VudGl0eQpjbGFzcyBSZXNlcnZhdGlvbjoKICAgIGRlZiBfX2luaXRfXyAoc2VsZiwgcmVzZXJ2YXRpb25faWQsIGRhdGU6IERhdGVTbG90PU5vbmUsIGVtcGxveWVlOiBFbXBsb3llZT1Ob25lLCBzZWF0OiBTZWF0PU5vbmUpOgogICAgICAgIHNlbGYucmVzZXJ2YXRpb25faWQ9cmVzZXJ2YXRpb25faWQKICAgICAgICBzZWxmLmRhdGU9ZGF0ZQogICAgICAgIHNlbGYuZW1wbG95ZWU9ZW1wbG95ZWUKICAgICAgICBzZWxmLnNlYXQ9c2VhdAogICAgQHBsYW5uaW5nX2lkCiAgICBkZWYgZ2V0X2lkKHNlbGYpOgogICAgICAgIHJldHVybiBzZWxmLnJlc2VydmF0aW9uX2lkCiAgICBAcGxhbm5pbmdfdmFyaWFibGUoRW1wbG95ZWUsIHZhbHVlX3JhbmdlX3Byb3ZpZGVyX3JlZnM9WydlbXBsb3llZVJhbmdlJ10pCiAgICBkZWYgZ2V0X2VtcGxveWVlKHNlbGYpOgogICAgICAgIHJldHVybiBzZWxmLmVtcGxveWVlCiAgICBkZWYgc2V0X2VtcGxveWVlKHNlbGYsIGVtcGxveWVlKToKICAgICAgICBzZWxmLmVtcGxveWVlPWVtcGxveWVlCiAgICAKICAgIEBwbGFubmluZ192YXJpYWJsZShTZWF0LCB2YWx1ZV9yYW5nZV9wcm92aWRlcl9yZWZzPVsnc2VhdFJhbmdlJ10pCiAgICBkZWYgZ2V0X3NlYXQoc2VsZik6CiAgICAgICAgcmV0dXJuIHNlbGYuc2VhdAogICAgZGVmIHNldF9zZWF0KHNlbGYsIHNlYXQpOgogICAgICAgIHNlbGYuc2VhdD1zZWF0CiAgICAKICAgIEBwbGFubmluZ192YXJpYWJsZShEYXRlU2xvdCwgdmFsdWVfcmFuZ2VfcHJvdmlkZXJfcmVmcz1bJ2RhdGVSYW5nZSddKQogICAgZGVmIGdldF9kYXRlc2xvdChzZWxmKToKICAgICAgICByZXR1cm4gc2VsZi5kYXRlCiAgICBkZWYgc2V0X2RhdGVzbG90KHNlbGYsIGRhdGUpOgogICAgICAgIHNlbGYuZGF0ZT1kYXRlCiAgICAKICAgIGRlZiBfX3N0cl9fIChzZWxmKToKICAgICAgICByZXR1cm4gZidSZXNlcnZhdGlvbihyZXNlcnZhdGlvbl9pZCA9IHtzZWxmLnJlc2VydmF0aW9uX2lkfSBmb3IgZW1wbG95ZWUge3NlbGYuZW1wbG95ZWV9IG9uIHtzZWxmLmRhdGV9IGF0IHtzZWxmLnNlYXR9KScKICAgIAogICAgZGVmIHRvX2RpY3Qoc2VsZik6CiAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgJ3Jlc2VydmF0aW9uX2lkJzogc2VsZi5yZXNlcnZhdGlvbl9pZCwKICAgICAgICAgICAgJ2RhdGUnOiBzZWxmLmRhdGUsCiAgICAgICAgICAgICdlbXBsb3llZSc6IHNlbGYuZW1wbG95ZWUsCiAgICAgICAgICAgICdzZWF0Jzogc2VsZi5zZWF0CiAgICAgICAgfQoKZGVmIGZvcm1hdF9saXN0KGFfbGlzdCk6CiAgICByZXR1cm4gJyxcbicuam9pbihtYXAoc3RyLCBhX2xpc3QpKQoKQHBsYW5uaW5nX3NvbHV0aW9uCmNsYXNzIFJlc2VydmF0aW9uU2NoZWR1bGU6CiAgICBkZWYgX19pbml0X18gKHNlbGYsIGVtcGxveWVlX2xpc3QsIHNlYXRfbGlzdCwgcmVzZXJ2YXRpb25fbGlzdCwgZGF0ZXMsIHNjb3JlPU5vbmUpOgogICAgICAgIHNlbGYuZW1wbG95ZWVfbGlzdD1lbXBsb3llZV9saXN0CiAgICAgICAgc2VsZi5zZWF0X2xpc3Q9c2VhdF9saXN0CiAgICAgICAgc2VsZi5yZXNlcnZhdGlvbl9saXN0PXJlc2VydmF0aW9uX2xpc3QKICAgICAgICBzZWxmLmRhdGVzPWRhdGVzCiAgICAgICAgc2VsZi5zY29yZT1zY29yZQogICAgQHByb2JsZW1fZmFjdF9jb2xsZWN0aW9uX3Byb3BlcnR5KEVtcGxveWVlKQogICAgQHZhbHVlX3JhbmdlX3Byb3ZpZGVyKCdlbXBsb3llZVJhbmdlJykKICAgIGRlZiBnZXRfZW1wbG95ZWVfbGlzdCAoc2VsZik6CiAgICAgICAgcmV0dXJuIHNlbGYuZW1wbG95ZWVfbGlzdAogICAgCiAgICBAcHJvYmxlbV9mYWN0X2NvbGxlY3Rpb25fcHJvcGVydHkoU2VhdCkKICAgIEB2YWx1ZV9yYW5nZV9wcm92aWRlcignc2VhdFJhbmdlJykKICAgIGRlZiBnZXRfc2VhdF9saXN0IChzZWxmKToKICAgICAgICByZXR1cm4gc2VsZi5zZWF0X2xpc3QKICAgIAogICAgQHByb2JsZW1fZmFjdF9jb2xsZWN0aW9uX3Byb3BlcnR5KERhdGVTbG90KQogICAgQHZhbHVlX3JhbmdlX3Byb3ZpZGVyKCdkYXRlUmFuZ2UnKQogICAgZGVmIGdldF9kYXRlc2xvdF9saXN0IChzZWxmKToKICAgICAgICByZXR1cm4gc2VsZi5kYXRlcwogICAgCiAgICBAcGxhbm5pbmdfZW50aXR5X2NvbGxlY3Rpb25fcHJvcGVydHkoUmVzZXJ2YXRpb24pCiAgICBkZWYgZ2V0X3Jlc2VydmF0aW9uX2xpc3QgKHNlbGYpOgogICAgICAgIHJldHVybiBzZWxmLnJlc2VydmF0aW9uX2xpc3QKICAgIAogICAgQHBsYW5uaW5nX3Njb3JlKEhhcmRTb2Z0U2NvcmUpCiAgICBkZWYgZ2V0X3Njb3JlIChzZWxmKToKICAgICAgICByZXR1cm4gc2VsZi5zY29yZQogICAgZGVmIHNldF9zY29yZSAoc2VsZiwgbmV3U2NvcmUpOgogICAgICAgIHNlbGYuc2NvcmU9bmV3U2NvcmUKICAgIGRlZiBfX3N0cl9fKHNlbGYpOgogICAgICAgIHJldHVybiBmIlJlc2VydmF0aW9uU2NoZWR1bGUoZW1wbG95ZWVfbGlzdCA9IHtmb3JtYXRfbGlzdChzZWxmLmVtcGxveWVlX2xpc3QpfSxcbiBzZWF0X2xpc3QgPSB7Zm9ybWF0X2xpc3Qoc2VsZi5zZWF0X2xpc3QpfSwgXG4gcmVzZXJ2YXRpb25fbGlzdCA9IHtmb3JtYXRfbGlzdChzZWxmLnJlc2VydmF0aW9uX2xpc3QpfSwgXG4gZGF0ZXMgPSB7Zm9ybWF0X2xpc3Qoc2VsZi5kYXRlcyl9LCBcbiB7c3RyKHNlbGYuc2NvcmUudG9TdHJpbmcoKSkgaWYgc2VsZi5zY29yZSBpcyBub3QgTm9uZSBlbHNlICdOb25lJ30pIgoKZGVmIGdlbmVyYXRlX3Byb2JsZW0oKToKICAgIAogICAgc2VhdF9saXN0PVsKICAgICAgICBTZWF0KHNlYXRfaWQ9dXVpZC51dWlkNCgpLCByb29tX2lkPXV1aWQudXVpZDQoKSwgdGVhbV9pZD0xLCBjcmVhdGVkX29uPWRhdGV0aW1lLm5vdygpLCBwb3NpdGlvbl94PTEsIHBvc2l0aW9uX3k9MSwgY29kZT0nQTEnKSwKICAgICAgICBTZWF0KHNlYXRfaWQ9dXVpZC51dWlkNCgpLCByb29tX2lkPXV1aWQudXVpZDQoKSwgdGVhbV9pZD0yLCBjcmVhdGVkX29uPWRhdGV0aW1lLm5vdygpLCBwb3NpdGlvbl94PTIsIHBvc2l0aW9uX3k9MSwgY29kZT0nQTInKSwKICAgICAgICBTZWF0KHNlYXRfaWQ9dXVpZC51dWlkNCgpLCByb29tX2lkPXV1aWQudXVpZDQoKSwgdGVhbV9pZD0xLCBjcmVhdGVkX29uPWRhdGV0aW1lLm5vdygpLCBwb3NpdGlvbl94PTMsIHBvc2l0aW9uX3k9MSwgY29kZT0nQTMnKSwKICAgICAgICBTZWF0KHNlYXRfaWQ9dXVpZC51dWlkNCgpLCByb29tX2lkPXV1aWQudXVpZDQoKSwgdGVhbV9pZD0yLCBjcmVhdGVkX29uPWRhdGV0aW1lLm5vdygpLCBwb3NpdGlvbl94PTQsIHBvc2l0aW9uX3k9MSwgY29kZT0nQTQnKSwKICAgICAgICBTZWF0KHNlYXRfaWQ9dXVpZC51dWlkNCgpLCByb29tX2lkPXV1aWQudXVpZDQoKSwgdGVhbV9pZD0xLCBjcmVhdGVkX29uPWRhdGV0aW1lLm5vdygpLCBwb3NpdGlvbl94PTEsIHBvc2l0aW9uX3k9MiwgY29kZT0nQjEnKSwKICAgICAgICBTZWF0KHNlYXRfaWQ9dXVpZC51dWlkNCgpLCByb29tX2lkPXV1aWQudXVpZDQoKSwgdGVhbV9pZD0yLCBjcmVhdGVkX29uPWRhdGV0aW1lLm5vdygpLCBwb3NpdGlvbl94PTIsIHBvc2l0aW9uX3k9MiwgY29kZT0nQjInKSwKICAgICAgICBTZWF0KHNlYXRfaWQ9dXVpZC51dWlkNCgpLCByb29tX2lkPXV1aWQudXVpZDQoKSwgdGVhbV9pZD0xLCBjcmVhdGVkX29uPWRhdGV0aW1lLm5vdygpLCBwb3NpdGlvbl94PTMsIHBvc2l0aW9uX3k9MiwgY29kZT0nQjMnKSwKICAgICAgICBTZWF0KHNlYXRfaWQ9dXVpZC51dWlkNCgpLCByb29tX2lkPXV1aWQudXVpZDQoKSwgdGVhbV9pZD0xLCBjcmVhdGVkX29uPWRhdGV0aW1lLm5vdygpLCBwb3NpdGlvbl94PTQsIHBvc2l0aW9uX3k9MiwgY29kZT0nQjQnKSwKICAgICAgICBTZWF0KHNlYXRfaWQ9dXVpZC51dWlkNCgpLCByb29tX2lkPXV1aWQudXVpZDQoKSwgdGVhbV9pZD0yLCBjcmVhdGVkX29uPWRhdGV0aW1lLm5vdygpLCBwb3NpdGlvbl94PTEsIHBvc2l0aW9uX3k9MywgY29kZT0nQzEnKSwKICAgICAgICBTZWF0KHNlYXRfaWQ9dXVpZC51dWlkNCgpLCByb29tX2lkPXV1aWQudXVpZDQoKSwgdGVhbV9pZD0xLCBjcmVhdGVkX29uPWRhdGV0aW1lLm5vdygpLCBwb3NpdGlvbl94PTIsIHBvc2l0aW9uX3k9MywgY29kZT0nQzInKSwKICAgICAgICBTZWF0KHNlYXRfaWQ9dXVpZC51dWlkNCgpLCByb29tX2lkPXV1aWQudXVpZDQoKSwgdGVhbV9pZD0xLCBjcmVhdGVkX29uPWRhdGV0aW1lLm5vdygpLCBwb3NpdGlvbl94PTMsIHBvc2l0aW9uX3k9MywgY29kZT0nQzMnKSwKICAgICAgICBTZWF0KHNlYXRfaWQ9dXVpZC51dWlkNCgpLCByb29tX2lkPXV1aWQudXVpZDQoKSwgdGVhbV9pZD0yLCBjcmVhdGVkX29uPWRhdGV0aW1lLm5vdygpLCBwb3NpdGlvbl94PTQsIHBvc2l0aW9uX3k9MywgY29kZT0nQzQnKSwKICAgICAgICBTZWF0KHNlYXRfaWQ9dXVpZC51dWlkNCgpLCByb29tX2lkPXV1aWQudXVpZDQoKSwgdGVhbV9pZD0zLCBjcmVhdGVkX29uPWRhdGV0aW1lLm5vdygpLCBwb3NpdGlvbl94PTEsIHBvc2l0aW9uX3k9NCwgY29kZT0nRDEnKSwKICAgICAgICBTZWF0KHNlYXRfaWQ9dXVpZC51dWlkNCgpLCByb29tX2lkPXV1aWQudXVpZDQoKSwgdGVhbV9pZD0zLCBjcmVhdGVkX29uPWRhdGV0aW1lLm5vdygpLCBwb3NpdGlvbl94PTIsIHBvc2l0aW9uX3k9NCwgY29kZT0nRDInKSwKICAgICAgICBTZWF0KHNlYXRfaWQ9dXVpZC51dWlkNCgpLCByb29tX2lkPXV1aWQudXVpZDQoKSwgdGVhbV9pZD0zLCBjcmVhdGVkX29uPWRhdGV0aW1lLm5vdygpLCBwb3NpdGlvbl94PTMsIHBvc2l0aW9uX3k9NCwgY29kZT0nRDMnKSwKICAgICAgICBTZWF0KHNlYXRfaWQ9dXVpZC51dWlkNCgpLCByb29tX2lkPXV1aWQudXVpZDQoKSwgdGVhbV9pZD0zLCBjcmVhdGVkX29uPWRhdGV0aW1lLm5vdygpLCBwb3NpdGlvbl94PTQsIHBvc2l0aW9uX3k9NCwgY29kZT0nRDQnKQogICAgXQogICAgCiAgICBlbXBsb3llZV9saXN0PVsKICAgICAgICBFbXBsb3llZSh1dWlkLnV1aWQ0KCksIHByZW5vbT0nS2FyaW0nLCBub209J3Rlc3QnLCBpZGVxdWlwZT0xLCBpZF9lbXBsYWNlbWVudF9wcmVmPXNlYXRfbGlzdFs0XS5zZWF0X2lkKSwKICAgICAgICBFbXBsb3llZSh1dWlkLnV1aWQ0KCksIHByZW5vbT0nU2FyYScsIG5vbT0ndGVzdCcsIGlkZXF1aXBlPTIsIGlkX2VtcGxhY2VtZW50X3ByZWY9c2VhdF9saXN0WzVdLnNlYXRfaWQpLAogICAgICAgIEVtcGxveWVlKHV1aWQudXVpZDQoKSwgcHJlbm9tPSdKb2huJywgbm9tPSd0ZXN0JywgaWRlcXVpcGU9MSwgaWRfZW1wbGFjZW1lbnRfcHJlZj1zZWF0X2xpc3RbNl0uc2VhdF9pZCksCiAgICAgICAgRW1wbG95ZWUodXVpZC51dWlkNCgpLCBwcmVub209J0phbmUnLCBub209J3Rlc3QnLCBpZGVxdWlwZT0xLCBpZF9lbXBsYWNlbWVudF9wcmVmPXNlYXRfbGlzdFs3XS5zZWF0X2lkKSwKICAgICAgICBFbXBsb3llZSh1dWlkLnV1aWQ0KCksIHByZW5vbT0nT25zJywgbm9tPSd0ZXN0JywgaWRlcXVpcGU9MSwgaWRfZW1wbGFjZW1lbnRfcHJlZj1zZWF0X2xpc3RbMF0uc2VhdF9pZCksCiAgICAgICAgRW1wbG95ZWUodXVpZC51dWlkNCgpLCBwcmVub209J01haGEnLCBub209J3Rlc3QnLCBpZGVxdWlwZT0xLCBpZF9lbXBsYWNlbWVudF9wcmVmPXNlYXRfbGlzdFsyXS5zZWF0X2lkKSwKICAgICAgICBFbXBsb3llZSh1dWlkLnV1aWQ0KCksIHByZW5vbT0nU2FsbWEnLCBub209J3Rlc3QnLCBpZGVxdWlwZT0yLCBpZF9lbXBsYWNlbWVudF9wcmVmPXNlYXRfbGlzdFszXS5zZWF0X2lkKSwKICAgICAgICBFbXBsb3llZSh1dWlkLnV1aWQ0KCksIHByZW5vbT0nTWFoZGknLCBub209J3Rlc3QnLCBpZGVxdWlwZT0yLCBpZF9lbXBsYWNlbWVudF9wcmVmPXNlYXRfbGlzdFsxXS5zZWF0X2lkKSwKICAgICAgICBFbXBsb3llZSh1dWlkLnV1aWQ0KCksIHByZW5vbT0nTWFudWVsJywgbm9tPSd0ZXN0JywgaWRlcXVpcGU9MiwgaWRfZW1wbGFjZW1lbnRfcHJlZj1zZWF0X2xpc3RbOF0uc2VhdF9pZCksCiAgICAgICAgRW1wbG95ZWUodXVpZC51dWlkNCgpLCBwcmVub209J0phY2snLCBub209J3Rlc3QnLCBpZGVxdWlwZT0zLCBpZF9lbXBsYWNlbWVudF9wcmVmPXNlYXRfbGlzdFsxMl0uc2VhdF9pZCksCiAgICAgICAgRW1wbG95ZWUodXVpZC51dWlkNCgpLCBwcmVub209J0ppbGwnLCBub209J3Rlc3QnLCBpZGVxdWlwZT0zLCBpZF9lbXBsYWNlbWVudF9wcmVmPXNlYXRfbGlzdFsxNF0uc2VhdF9pZCksCiAgICAgICAgRW1wbG95ZWUodXVpZC51dWlkNCgpLCBwcmVub209J0phbmEnLCBub209J3Rlc3QnLCBpZGVxdWlwZT0xLCBpZF9lbXBsYWNlbWVudF9wcmVmPXNlYXRfbGlzdFs5XS5zZWF0X2lkKSwKICAgICAgICBFbXBsb3llZSh1dWlkLnV1aWQ0KCksIHByZW5vbT0nSmFzbWluZScsIG5vbT0ndGVzdCcsIGlkZXF1aXBlPTEsIGlkX2VtcGxhY2VtZW50X3ByZWY9c2VhdF9saXN0WzEwXS5zZWF0X2lkKSwKICAgICAgICBFbXBsb3llZSh1dWlkLnV1aWQ0KCksIHByZW5vbT0nSmFzbWluJywgbm9tPSd0ZXN0JywgaWRlcXVpcGU9MywgaWRfZW1wbGFjZW1lbnRfcHJlZj1zZWF0X2xpc3RbMTVdLnNlYXRfaWQpLAogICAgICAgIEVtcGxveWVlKHV1aWQudXVpZDQoKSwgcHJlbm9tPSdKb3NlcGgnLCBub209J3Rlc3QnLCBpZGVxdWlwZT0yLCBpZF9lbXBsYWNlbWVudF9wcmVmPXNlYXRfbGlzdFsxMV0uc2VhdF9pZCksCiAgICAgICAgRW1wbG95ZWUodXVpZC51dWlkNCgpLCBwcmVub209J0pvc8OpJywgbm9tPSd0ZXN0JywgaWRlcXVpcGU9MywgaWRfZW1wbGFjZW1lbnRfcHJlZj1zZWF0X2xpc3RbMTNdLnNlYXRfaWQpCiAgICBdCgogICAgZGF0ZXMgPSBbXQogICAgZm9yIGkgaW4gcmFuZ2UgKDEsIDQpOgogICAgICAgIGRhdGVzLmFwcGVuZChEYXRlU2xvdChpLCBkYXRldGltZSgyMDIwLCAxLCBpKSkpCiAgICAKICAgIHJlc2VydmF0aW9uX2xpc3QgPSBbXQogICAgZm9yIGkgaW4gcmFuZ2UgKDEsIGxlbihzZWF0X2xpc3QpICsgMSk6CiAgICAgICAgcmVzZXJ2YXRpb25fbGlzdC5hcHBlbmQoUmVzZXJ2YXRpb24oaSkpCiAgICByZXNlcnZhdGlvbiA9IHJlc2VydmF0aW9uX2xpc3RbMF0KICAgIHJlc2VydmF0aW9uLnNldF9kYXRlc2xvdChkYXRlc1swXSkKICAgIHJlc2VydmF0aW9uLnNldF9lbXBsb3llZShlbXBsb3llZV9saXN0WzBdKQogICAgcmVzZXJ2YXRpb24uc2V0X3NlYXQoc2VhdF9saXN0WzRdKQogICAgCiAgICByZXR1cm4gUmVzZXJ2YXRpb25TY2hlZHVsZShkYXRlcz1kYXRlcywgc2VhdF9saXN0PXNlYXRfbGlzdCwgcmVzZXJ2YXRpb25fbGlzdD1yZXNlcnZhdGlvbl9saXN0LCBlbXBsb3llZV9saXN0PWVtcGxveWVlX2xpc3QpCg==