Contract con_chess_v1


Contract Code


  
1 # con_chess_v1
2
3 NUM_ROWS = NUM_COLS = 8
4 NUM_SQUARES = NUM_ROWS * NUM_COLS
5 INITIAL_BOARD = 'rnbqkbnrpppppppp PPPPPPPPRNBQKBNR'
6
7
8 # Setup vectors
9 white_pawn_attack_vectors = [(-1, 1), (-1, -1)]
10 white_pawn_first_vectors = [(-1, 0), (-2, 0)]
11 white_pawn_default_vectors = [(-1, 0)]
12
13 black_pawn_attack_vectors = [(1, 1), (1, -1)]
14 black_pawn_first_vectors = [(1, 0), (2, 0)]
15 black_pawn_default_vectors = [(1, 0)]
16
17 king_vectors = [(-1, -1), (1, -1), (-1, 0), (0, -1), (1, 0), (0, 1), (-1, 1), (1, 1)]
18 knight_vectors = [(1, 2), (2, 1), (-1, 2), (2, -1), (1, -2), (-2, 1), (-2, -1), (-1, -2)]
19 rook_vectors = [(1, 0), (-1, 0), (0, 1), (0, -1)]
20 bishop_vectors = [(-1, -1), (-1, 1), (1, -1), (1, 1)]
21 queen_vectors = rook_vectors + bishop_vectors
22
23
24 assert len(INITIAL_BOARD) == NUM_SQUARES, 'Invalid initial board.'
25
26
27 INITIAL_STATE = {
28 'current_player': 'w',
29 'board': str(INITIAL_BOARD),
30 'creator_team': 'w',
31 'opponent_team': 'b',
32 }
33
34
35 @export
36 def get_initial_state(x: str = None) -> dict:
37 return INITIAL_STATE
38
39
40 # Utility
41 def is_white_piece(piece: str) -> bool:
42 return piece.isupper()
43
44
45 def is_black_piece(piece: str) -> bool:
46 return piece.islower()
47
48
49 def coords_to_index(x: int, y: int) -> int:
50 assert valid_coords(x, y), 'Invalid (x, y): ({}, {})'.format(x, y)
51 return x * NUM_ROWS + y
52
53
54 def index_to_coords(index: int) -> tuple:
55 assert valid_index(index), 'Invalid index: {}'.format(index)
56 x = index // NUM_ROWS
57 y = index % NUM_ROWS
58 return (x, y)
59
60
61 def valid_index(index: int) -> bool:
62 return index >= 0 and index < NUM_SQUARES
63
64
65 def valid_coords(x: int, y: int) -> bool:
66 return x >= 0 and x < NUM_ROWS and y >= 0 and y < NUM_COLS
67
68
69 def find_coords_for_white_king(board: str) -> tuple:
70 return index_to_coords(board.index('K'))
71
72
73 def find_coords_for_black_king(board: str) -> tuple:
74 return index_to_coords(board.index('k'))
75
76
77 def get_attack_maps(board: str, white_only: bool = False, black_only: bool = False) -> set:
78 white_moves_per_piece = {}
79 black_moves_per_piece = {}
80 white_attack_map = {}
81 black_attack_map = {}
82 white_move_map = {}
83 black_move_map = {}
84 for i in range(len(board)):
85 piece = board[i]
86 if piece == ' ':
87 continue
88 x, y = index_to_coords(i)
89 check_path = False
90 if is_white_piece(piece):
91 if black_only:
92 continue
93 attack_set = white_attack_map
94 move_set = white_move_map
95 moves_per_piece = white_moves_per_piece
96 pawn_attack_vectors = white_pawn_attack_vectors
97 if x == 6:
98 pawn_move_vectors = white_pawn_first_vectors
99 else:
100 pawn_move_vectors = white_pawn_default_vectors
101 else:
102 if white_only:
103 continue
104 attack_set = black_attack_map
105 move_set = black_move_map
106 moves_per_piece = black_moves_per_piece
107 pawn_attack_vectors = black_pawn_attack_vectors
108 if x == 1:
109 pawn_move_vectors = black_pawn_first_vectors
110 else:
111 pawn_move_vectors = black_pawn_default_vectors
112 piece = piece.upper()
113 move_vectors = None
114 if piece == 'P':
115 vectors = pawn_attack_vectors
116 move_vectors = pawn_move_vectors
117 elif piece == 'N':
118 vectors = knight_vectors
119 elif piece == 'B':
120 vectors = bishop_vectors
121 check_path = True
122 elif piece == 'R':
123 vectors = rook_vectors
124 check_path = True
125 elif piece == 'Q':
126 vectors = queen_vectors
127 check_path = True
128 elif piece == 'K':
129 vectors = king_vectors
130 else:
131 assert False, f'Invalid piece: {piece}'
132 valid_moves = []
133 for vector in vectors:
134 pos = (vector[0] + x, vector[1] + y)
135 if valid_coords(pos[0], pos[1]):
136 if pos not in attack_set:
137 attack_set[pos] = []
138 attack_set[pos].append(i)
139 if move_vectors is None:
140 if pos not in move_set:
141 move_set[pos] = []
142 move_set[pos].append(i)
143 valid_moves.append(pos)
144 if check_path: # make sure no pieces blocking
145 valid = True
146 while valid:
147 pos_idx = coords_to_index(pos[0], pos[1])
148 if board[pos_idx] == ' ':
149 pos = (pos[0] + vector[0], pos[1] + vector[1])
150 valid = valid_coords(pos[0], pos[1])
151 if valid:
152 if pos not in attack_set:
153 attack_set[pos] = []
154 attack_set[pos].append(i)
155 if move_vectors is None:
156 if pos not in move_set:
157 move_set[pos] = []
158 move_set[pos].append(i)
159 valid_moves.append(pos)
160 else:
161 valid = False
162 if move_vectors is not None:
163 for vector in vectors:
164 pos = (vector[0] + x, vector[1] + y)
165 if valid_coords(pos[0], pos[1]):
166 if pos not in move_set:
167 move_set[pos] = []
168 move_set[pos].append(i)
169 valid_moves.append(pos)
170 if len(valid_moves) > 0:
171 moves_per_piece[i] = valid_moves
172 return white_attack_map, black_attack_map, white_move_map, black_move_map, white_moves_per_piece, black_moves_per_piece
173
174
175 def get_intermediary_path(x1: int, y1: int, x2: int, y2: int) -> list:
176 vector = (x2 - x1, y2 - y1)
177 if vector[0] > 0 and vector[1] > 0:
178 assert vector[0] == vector[1], 'Invalid vector'
179 return [(x1 + i, y1 + i) for i in range(1, vector[0])]
180 elif vector[0] > 0 and vector[1] == 0:
181 return [(x1 + i, y1) for i in range(1, vector[0])]
182 elif vector[0] == 0 and vector[1] > 0:
183 return [(x1, y1 + i) for i in range(1, vector[1])]
184 elif vector[0] < 0 and vector[1] < 0:
185 assert vector[0] == vector[1], 'Invalid vector'
186 return [(x1 - i, y1 - i) for i in range(1, -vector[0])]
187 elif vector[0] < 0 and vector[1] > 0:
188 assert vector[0] == -vector[1], 'Invalid vector'
189 return [(x1 - i, y1 + i) for i in range(1, vector[1])]
190 elif vector[0] > 0 and vector[1] < 0:
191 assert vector[0] == -vector[1], 'Invalid vector'
192 return [(x1 + i, y1 - i) for i in range(1, vector[0])]
193 elif vector[0] < 0 and vector[1] == 0:
194 return [(x1 - i, y1) for i in range(1, -vector[0])]
195 elif vector[0] == 0 and vector[1] < 0:
196 return [(x1, y1 - i) for i in range(1, -vector[1])]
197 else:
198 assert False, 'Not a valid vector.'
199
200
201 def is_white_king_in_check(board: str, black_attack_map: dict) -> bool:
202 king_x, king_y = find_coords_for_white_king(board)
203 return (king_x, king_y) in black_attack_map
204
205
206 def is_white_king_in_check_mate(board: list,
207 white_move_map: dict,
208 white_attack_map: dict,
209 black_attack_map: dict,
210 ) -> bool:
211 king_x, king_y = find_coords_for_white_king(board)
212 pieces_causing_check = black_attack_map.get((king_x, king_y))
213 # See if we are in check
214 if pieces_causing_check is not None and len(pieces_causing_check) > 0:
215 # Check king's ability to move away
216 for x, y in king_vectors:
217 n_king_x = king_x + x
218 n_king_y = king_y + y
219 if valid_coords(n_king_x, n_king_y):
220 other_piece = board[coords_to_index(n_king_x, n_king_y)]
221 if (other_piece == ' '
222 or is_black_piece(other_piece)) \
223 and (n_king_x, n_king_y) not in black_attack_map:
224 return False # Can move
225 if len(pieces_causing_check) == 1:
226 # Single check
227 checker_index = pieces_causing_check[0]
228 checker_x, checker_y = index_to_coords(checker_index)
229 defenders = white_attack_map.get((checker_x, checker_y))
230 # Can this piece be attacked?
231 if defenders is not None:
232 for defender in defenders:
233 # simulate taking this piece
234 new_board = board.copy()
235 new_board[checker_index] = board[defender]
236 new_board[defender] = ' '
237 n0, new_black_attack_map, n2, n3, n4, n5 \
238 = get_attack_maps(new_board, black_only=True)
239 if not is_white_king_in_check(new_board, new_black_attack_map):
240 return False
241 checker_piece = board[checker_index]
242 if checker_piece.upper() in ('R', 'B', 'Q'):
243 intermediate_path = get_intermediary_path(king_x, king_y, checker_x, checker_y)
244 for pos in intermediate_path:
245 # Can we block this?
246 pos_index = coords_to_index(pos[0], pos[1])
247 defenders = white_move_map.get(pos)
248 if defenders is not None:
249 for defender in defenders:
250 # simulate taking this piece
251 new_board = board.copy()
252 new_board[pos_index] = board[defender]
253 new_board[defender] = ' '
254 n0, new_black_attack_map, n2, n3, n4, n5 \
255 = get_attack_maps(new_board, black_only=True)
256 if not is_white_king_in_check(new_board, new_black_attack_map):
257 return False
258 return True
259 return False
260
261
262 def is_white_king_in_stale_mate(board: list, white_moves_per_piece: dict, black_attack_map: dict) -> bool:
263 king_x, king_y = find_coords_for_white_king(board)
264 if (king_x, king_y) not in black_attack_map: # Not in check
265 return len(white_moves_per_piece) == 0 # No valid moves
266 return False
267
268
269 def is_black_king_in_check(board: list, white_attack_map: dict) -> bool:
270 king_x, king_y = find_coords_for_black_king(board)
271 return (king_x, king_y) in white_attack_map
272
273
274 def is_black_king_in_check_mate(board: list,
275 black_move_map: dict,
276 black_attack_map: dict,
277 white_attack_map: dict,
278 ) -> bool:
279 king_x, king_y = find_coords_for_black_king(board)
280 pieces_causing_check = white_attack_map.get((king_x, king_y))
281 # See if we are in check
282 if pieces_causing_check is not None and len(pieces_causing_check) > 0:
283 # Check king's ability to move away
284 for x, y in king_vectors:
285 n_king_x = king_x + x
286 n_king_y = king_y + y
287 if valid_coords(n_king_x, n_king_y):
288 other_piece = board[coords_to_index(n_king_x, n_king_y)]
289 if (other_piece == ' '
290 or is_white_piece(other_piece)) \
291 and (n_king_x, n_king_y) not in white_attack_map:
292 return False # Can move
293 if len(pieces_causing_check) == 1:
294 # Single check
295 checker_index = pieces_causing_check[0]
296 checker_x, checker_y = index_to_coords(checker_index)
297 defenders = black_attack_map.get((checker_x, checker_y))
298 # Can this piece be attacked?
299 if defenders is not None:
300 for defender in defenders:
301 # simulate taking this piece
302 new_board = board.copy()
303 new_board[checker_index] = board[defender]
304 new_board[defender] = ' '
305 new_white_attack_map, n1, n2, n3, n4, n5 \
306 = get_attack_maps(new_board, white_only=True)
307 if not is_black_king_in_check(new_board, new_white_attack_map):
308 return False
309 checker_piece = board[checker_index]
310 if checker_piece.upper() in ('R', 'B', 'Q'):
311 intermediate_path = get_intermediary_path(king_x, king_y, checker_x, checker_y)
312 for pos in intermediate_path:
313 # Can we block this?
314 pos_index = coords_to_index(pos[0], pos[1])
315 defenders = black_move_map.get(pos)
316 if defenders is not None:
317 for defender in defenders:
318 # simulate taking this piece
319 new_board = board.copy()
320 new_board[pos_index] = board[defender]
321 new_board[defender] = ' '
322 new_white_attack_map, n1, n2, n3, n4, n5 \
323 = get_attack_maps(new_board, white_only=True)
324 if not is_black_king_in_check(new_board, new_white_attack_map):
325 return False
326 return True
327 return False
328
329
330 def is_black_king_in_stale_mate(board: list, black_moves_per_piece: dict, white_attack_map: dict) -> bool:
331 king_x, king_y = find_coords_for_black_king(board)
332 if (king_x, king_y) not in white_attack_map: # Not in check
333 return len(black_moves_per_piece) == 0 # No valid moves
334 return False
335
336
337 def opposing_team(team: str):
338 if team == 'w':
339 return 'b'
340 elif team == 'b':
341 return 'w'
342 else:
343 assert False, f'Invalid team: {team}.'
344
345
346 @export
347 def force_end_round(state: dict, metadata: dict):
348 if state.get('winner') is None:
349 state['stalemate'] = True
350
351
352 @export
353 def move(caller: str, team: str, payload: dict, state: dict, metadata: dict):
354 x1=payload['x1']
355 y1=payload['y1']
356 x2=payload['x2']
357 y2=payload['y2']
358 board = list(state['board'])
359
360 curr_index = coords_to_index(x1, y1)
361 curr_piece = board[curr_index]
362
363 assert state['current_player'] == team, 'It is not your turn to move.'
364 if team == 'w':
365 assert is_white_piece(curr_piece), 'This is not your piece to move.'
366 else:
367 assert team == 'b', f'Invalid team: {team}'
368 assert is_black_piece(curr_piece), 'This is not your piece to move.'
369
370 opponent = opposing_team(team)
371
372 piece_upper = curr_piece.upper()
373 check_path = False
374 attack_vectors = None
375 is_castle_attempt = False
376 if piece_upper == 'P':
377 if team == 'b':
378 if x1 == 1:
379 vectors = black_pawn_first_vectors
380 else:
381 vectors = black_pawn_default_vectors
382 attack_vectors = black_pawn_attack_vectors
383 else:
384 if x1 == 6:
385 vectors = white_pawn_first_vectors
386 else:
387 vectors = white_pawn_default_vectors
388 attack_vectors = white_pawn_attack_vectors
389 elif piece_upper == 'N':
390 vectors = knight_vectors
391 elif piece_upper == 'B':
392 vectors = bishop_vectors
393 check_path = True
394 elif piece_upper == 'R':
395 vectors = rook_vectors
396 check_path = True
397 elif piece_upper == 'Q':
398 vectors = queen_vectors
399 check_path = True
400 elif piece_upper == 'K':
401 # check if castle
402 if is_white_piece(curr_piece):
403 if x1 == 7 and x2 == 7:
404 if y1 == 4 and y2 in (6, 2):
405 is_castle_attempt = True
406 else:
407 if x1 == 0 and x2 == 0:
408 if y1 == 4 and y2 in (6, 2):
409 is_castle_attempt = True
410 vectors = king_vectors
411 else:
412 assert False, f'Invalid piece: {curr_piece}'
413
414 attack_vectors = attack_vectors or vectors
415 next_vector = (x2 - x1, y2 - y1)
416 next_index = coords_to_index(x2, y2)
417 state[f'{team}_en_passant'] = None
418
419 if valid_index(next_index):
420 if check_path:
421 valid = False
422 vector_to_use = None
423 for vector in vectors:
424 if vector[0] == 0:
425 valid = next_vector[0] == 0 and next_vector[1] // vector[1] >= 1
426 elif vector[1] == 0:
427 valid = next_vector[1] == 0 and next_vector[0] // vector[0] >= 1
428 else:
429 valid = next_vector[0] // vector[0] >= 1 and next_vector[1] // vector[1] >= 1
430 if valid:
431 vector_to_use = vector
432 break
433 assert valid, f'Invalid move with {curr_piece}.'
434 intermediate_pos = (x1 + vector_to_use[0], y1 + vector_to_use[1])
435 while True:
436 intermediate_index = coords_to_index(intermediate_pos[0], intermediate_pos[1])
437 if intermediate_index != next_index:
438 assert board[intermediate_index] == ' ', 'Invalid move. Another piece is in the way.'
439 intermediate_pos = (intermediate_pos[0] + vector_to_use[0], intermediate_pos[1] + vector_to_use[1])
440 else:
441 break
442 else:
443 if is_castle_attempt:
444 assert not state.get(f'{team}_moved_king'), 'King has already moved.'
445 if team == 'w':
446 l0, opponent_attack_map, \
447 l0, l0, \
448 l0, l0 \
449 = get_attack_maps(board, black_only=True)
450 else:
451 opponent_attack_map, l0, \
452 l0, l0, \
453 l0, l0 \
454 = get_attack_maps(board, black_only=True)
455 assert (x1, y1) not in opponent_attack_map, 'You cannot castle out of check.'
456 if y2 == 6:
457 assert not state.get(f'{team}_moved_rook7'), 'Rook has already moved.'
458 for ny in [5, 6]:
459 n_index = coords_to_index(x1, ny)
460 assert board[n_index] == ' ', 'Pieces are in the way of castling.'
461 assert (x1, ny) not in opponent_attack_map, 'You cannot castle through check.'
462 rook_idx = coords_to_index(x1, 7)
463 rook_to_idx = coords_to_index(x1, 5)
464 else:
465 # y2 == 2
466 assert not state.get(f'{team}_moved_rook0'), 'Rook has already moved.'
467 for ny in [1, 2, 3]:
468 n_index = coords_to_index(x1, ny)
469 assert board[n_index] == ' ', 'Pieces are in the way of castling.'
470 assert (x1, ny) not in opponent_attack_map, 'You cannot castle through check.'
471 rook_idx = coords_to_index(x1, 0)
472 rook_to_idx = coords_to_index(x1, 3)
473 board[rook_to_idx] = board[rook_idx]
474 board[rook_idx] = ' '
475
476 elif piece_upper != 'P':
477 # Handle pawns separately
478 assert next_vector in vectors, 'Invalid move. Not a valid move for this piece.'
479
480 next_space = board[next_index]
481 if next_space != ' ':
482 if team == 'b':
483 assert is_white_piece(next_space), 'You cannot take your own piece.'
484 else:
485 assert is_black_piece(next_space), 'You cannot take your own piece.'
486
487 # Handle pawns
488 if piece_upper == 'P':
489 assert next_vector in attack_vectors, 'Invalid pawn attack.'
490 else:
491 if piece_upper == 'P':
492 # Check en passant
493 en_passant = state.get(f'{opponent}_en_passant')
494 valid_en_passant = False
495 if en_passant is not None:
496 if en_passant[0] == (x1, y1) or en_passant[1] == (x1, y1):
497 if en_passant[2] == (x2, y2):
498 valid_en_passant = True
499 en_passant_index = coords_to_index(en_passant[3][0], en_passant[3][1])
500 board[en_passant_index] = ' '
501 assert valid_en_passant or next_vector in vectors, 'Invalid pawn move.'
502 if next_vector[0] == 2 or next_vector[0] == -2:
503 # En passant possible next round
504 en_passant = [(x2, y2-1), (x2, y2+1), (x1 + next_vector[0]//2, y2), (x2, y2)]
505 state[f'{team}_en_passant'] = en_passant
506
507 # Just move
508 board[curr_index] = ' '
509 board[next_index] = curr_piece
510 if piece_upper == 'K':
511 state[f'{team}_moved_king'] = True
512 elif piece_upper == 'R':
513 if y1 == 0:
514 state[f'{team}_moved_rook0'] = True
515 elif y1 == 7:
516 state[f'{team}_moved_rook7'] = True
517 else:
518 assert False, 'Invalid move. Piece is not on the board.'
519
520 # Check for pawn promotion and check
521 if team == 'b':
522 if x2 == NUM_ROWS - 1 and curr_piece == 'p':
523 board[next_index] = 'q'
524 else:
525 if x2 == 0 and curr_piece == 'P':
526 board[next_index] = 'Q'
527
528 white_attack_map, black_attack_map, \
529 white_move_map, black_move_map, \
530 white_moves_per_piece, black_moves_per_piece \
531 = get_attack_maps(board)
532
533 checkmate = False
534 stalemate = False
535 if team == 'b':
536 assert not is_black_king_in_check(board, white_attack_map), 'This move puts you in check.'
537 opponent_in_check = is_white_king_in_check(board, black_attack_map)
538 state['w_in_check'] = opponent_in_check
539 if opponent_in_check:
540 checkmate = is_white_king_in_check_mate(
541 board=board,
542 white_attack_map=white_attack_map,
543 white_move_map=white_move_map,
544 black_attack_map=black_attack_map
545 )
546 else:
547 stalemate = is_white_king_in_stale_mate(
548 board=board,
549 white_moves_per_piece=white_moves_per_piece,
550 black_attack_map=black_attack_map)
551 else:
552 assert not is_white_king_in_check(board, black_attack_map), 'This move puts you in check.'
553 opponent_in_check = is_black_king_in_check(board, white_attack_map)
554 state['b_in_check'] = opponent_in_check
555 if opponent_in_check:
556 checkmate = is_black_king_in_check_mate(
557 board=board,
558 black_attack_map=black_attack_map,
559 black_move_map=black_move_map,
560 white_attack_map=white_attack_map
561 )
562 else:
563 stalemate = is_black_king_in_stale_mate(
564 board=board,
565 black_moves_per_piece=black_moves_per_piece,
566 white_attack_map=white_attack_map
567 )
568
569 board = ''.join(board)
570 state['current_player'] = opponent
571 state['board'] = board
572
573 if stalemate:
574 state['stalemate'] = True
575 elif checkmate:
576 state['winner'] = team

Byte Code

e30000000000000000000000000900000040000000733a020000640004005a005a016500650114005a0264015a036445644867025a04644a644c67025a05644e67015a06644f645167025a076452645367025a08645467015a0964576459645b645d645e645f6461646267085a0a6463646464666468646a646c646f647267085a0b647364756476647867045a0c647b647d647f648067045a0d650c650d17005a0e650f6503830165026b029000739e741064058301820164066511650383016406640764089c045a12651364098301648165116514640b9c02640c640d840583015a1565116516640e9c02640f641084045a1765116516640e9c026411641284045a1865196519651964139c036414641584045a1a6519651b64169c026417641884045a1c6519651664169c026419641a84045a1d65196519651664139c03641b641c84045a1e6511651b641d9c02641e641f84045a1f6511651b641d9c026420642184045a206482651165166516652164239c046424642584055a226519651965196519652364269c056427642884045a2465116514651664299c03642a642b84045a2565236514651465146516642c9c05642d642e84045a266523651465146516642f9c046430643184045a2765236514651664329c036433643484045a286523651465146514651664359c056436643784045a29652365146514651664389c046439643a84045a2a6511643b9c01643c643d84045a2b65136409830165146514643e9c02643f6440840483015a2c6513640983016511651165146514651464419c0564426443840483015a2d640a53002983e9080000007a40726e62716b626e72707070707070707020202020202020202020202020202020202020202020202020202020202020205050505050505050524e42514b424e52e901000000e900000000e9020000007a16496e76616c696420696e697469616c20626f6172642eda0177da01622904da0e63757272656e745f706c61796572da05626f617264da0c63726561746f725f7465616dda0d6f70706f6e656e745f7465616dda0c636f6e5f63686573735f76314e2902da0178da0672657475726e63010000000000000001000000010000004300000073040000007400530029014e2901da0d494e495449414c5f53544154452901720c000000a900720f000000da00da116765745f696e697469616c5f7374617465170000007302000000000272110000002902da057069656365720d00000063010000000000000001000000010000004300000073080000007c006a008300530029014e2901da076973757070657229017212000000720f000000720f0000007210000000da105f5f69735f77686974655f70696563651c00000073020000000001721400000063010000000000000001000000010000004300000073080000007c006a008300530029014e2901da0769736c6f77657229017212000000720f000000720f0000007210000000da105f5f69735f626c61636b5f7069656365200000007302000000000172160000002903720c000000da0179720d000000630200000000000000020000000400000043000000732600000074007c007c018302731a740164016a027c007c018302830182017c00740314007c011700530029024e7a18496e76616c69642028782c2079293a20287b7d2c207b7d292904da0e5f5f76616c69645f636f6f726473da0e417373657274696f6e4572726f72da06666f726d6174da084e554d5f524f57532902720c0000007217000000720f000000720f0000007210000000da115f5f636f6f7264735f746f5f696e64657824000000730400000000011a01721c0000002902da05696e646578720d000000630100000000000000030000000300000043000000732e00000074007c0083017316740164016a027c008301830182017c0074031a007d017c00740316007d027c017c026602530029024e7a11496e76616c696420696e6465783a207b7d2904da0d5f5f76616c69645f696e6465787219000000721a000000721b0000002903721d000000720c0000007217000000720f000000720f0000007210000000da115f5f696e6465785f746f5f636f6f7264732900000073080000000001160108010801721f00000063010000000000000001000000020000004300000073100000007c0064016b056f0e7c0074006b00530029024e72030000002901da0b4e554d5f535155415245532901721d000000720f000000720f0000007210000000721e0000003000000073020000000001721e00000063020000000000000002000000020000004300000073200000007c0064016b056f1e7c0074006b006f1e7c0164016b056f1e7c0174016b00530029024e72030000002902721b000000da084e554d5f434f4c532902720c0000007217000000720f000000720f000000721000000072180000003400000073020000000001721800000029027208000000720d000000630100000000000000010000000300000043000000730e00000074007c006a01640183018301530029024eda014b2902721f000000721d00000029017208000000720f000000720f0000007210000000da1c5f5f66696e645f636f6f7264735f666f725f77686974655f6b696e6738000000730200000000017223000000630100000000000000010000000300000043000000730e00000074007c006a01640183018301530029024eda016b2902721f000000721d00000029017208000000720f000000720f0000007210000000da1c5f5f66696e645f636f6f7264735f666f725f626c61636b5f6b696e673c0000007302000000000172250000004629047208000000da0a77686974655f6f6e6c79da0a626c61636b5f6f6e6c79720d0000006303000000000000001a0000000600000043000000732c03000069007d0369007d0469007d0569007d0669007d0769007d0890037800740074017c0083018301440090025dee7d097c007c0919007d0a7c0a64016b027240712874027c0983015c027d0b7d0c64027d0d74037c0a830172827c02725e71287c057d0e7c077d0f7c037d1074047d117c0b64036b02727c74057d1271aa74067d126e287c01728871287c067d0e7c087d0f7c047d1074077d117c0b64046b0272a674087d126e0474097d127c0a6a0a83007d0a64007d137c0a64056b0272c87c117d147c127d136e6a7c0a64066b0272d6740b7d146e5c7c0a64076b0272e8740c7d1464087d0d6e4a7c0a64096b0272fa740d7d1464087d0d6e387c0a640a6b029001720e740e7d1464087d0d6e247c0a640b6b029001721e740f7d146e146402900173327410640c7c0a9b009d028301820167007d159001785a7c14440090015d507d167c16640d19007c0b17007c16640419007c0c170066027d1774117c17640d19007c176404190083029001723e7c177c0e6b079001728267007c0e7c173c007c0e7c1719006a127c09830101007c1364006b08900172ba7c177c0f6b07900172ac67007c0f7c173c007c0f7c1719006a127c09830101007c156a127c17830101007c0d9001723e64087d1878be7c189002728c74137c17640d19007c176404190083027d197c007c19190064016b02900272847c17640d19007c16640d190017007c17640419007c1664041900170066027d1774117c17640d19007c176404190083027d187c18900272887c177c0e6b079002724067007c0e7c173c007c0e7c1719006a127c09830101007c1364006b08900272787c177c0f6b079002726a67007c0f7c173c007c0f7c1719006a127c09830101007c156a127c17830101006e0464027d18900171d057009001713e57007c1364006b099003720478647c1444005d5c7d167c16640d19007c0b17007c16640419007c0c170066027d1774117c17640d19007c17640419008302900272a47c177c0f6b07900272e667007c0f7c173c007c0f7c1719006a127c09830101007c156a127c1783010100900271a4570074017c158301640d6b0472287c157c107c093c00712857007c057c067c077c087c037c0466065300290e4efa012046e9060000007202000000da0150da014eda014254da0152da015172220000007a0f496e76616c69642070696563653a2072030000002914da0572616e6765da036c656e721f0000007214000000da1977686974655f7061776e5f61747461636b5f766563746f7273da1877686974655f7061776e5f66697273745f766563746f7273da1a77686974655f7061776e5f64656661756c745f766563746f7273da19626c61636b5f7061776e5f61747461636b5f766563746f7273da18626c61636b5f7061776e5f66697273745f766563746f7273da1a626c61636b5f7061776e5f64656661756c745f766563746f7273da057570706572da0e6b6e696768745f766563746f7273da0e626973686f705f766563746f7273da0c726f6f6b5f766563746f7273da0d717565656e5f766563746f7273da0c6b696e675f766563746f727372190000007218000000da06617070656e64721c000000291a720800000072260000007227000000da1577686974655f6d6f7665735f7065725f7069656365da15626c61636b5f6d6f7665735f7065725f7069656365da1077686974655f61747461636b5f6d6170da10626c61636b5f61747461636b5f6d6170da0e77686974655f6d6f76655f6d6170da0e626c61636b5f6d6f76655f6d6170da01697212000000720c0000007217000000da0a636865636b5f70617468da0a61747461636b5f736574da086d6f76655f736574da0f6d6f7665735f7065725f7069656365da137061776e5f61747461636b5f766563746f7273da117061776e5f6d6f76655f766563746f7273da0c6d6f76655f766563746f7273da07766563746f7273da0b76616c69645f6d6f766573da06766563746f72da03706f73da0576616c6964da07706f735f696478720f000000720f0000007210000000da115f5f6765745f61747461636b5f6d6170734000000073b6000000000204010401040104010401040116010801080102010c010401080104010201040104010401040108010602060204010201040104010401040108010602040108010401080104010601080106010801040106010801040106010a01040106010a010602140104010e01180114010a0108010e010a010a0108010e010a0106010401080112010e012001120106010a0108010e010a010a0108010e010c0210010a010a01180114010a0108010e0110010c010c01060172520000002905da027831da027931da027832da027932720d00000063040000000000000005000000050000000300000073540200007c02880018007c038801180066027d047c046401190064016b04725e7c046402190064016b04725e7c04640119007c04640219006b0273407400640383018201870087016602640464058408740164027c046401190083024400830153007c046401190064016b0472947c046402190064016b027294870087016602640664058408740164027c046401190083024400830153007c046401190064016b0272ca7c046402190064016b0472ca870087016602640764058408740164027c046402190083024400830153007c046401190064016b006fe07c046402190064016b009001721e7c04640119007c04640219006b02900073fe7400640383018201870087016602640864058408740164027c04640119000b0083024400830153007c046401190064016b00900172747c046402190064016b04900172747c04640119007c04640219000b006b02900173567400640383018201870087016602640964058408740164027c046402190083024400830153007c046401190064016b04900172ca7c046402190064016b00900172ca7c04640119007c04640219000b006b02900173ac7400640383018201870087016602640a64058408740164027c046401190083024400830153007c046401190064016b00900272067c046402190064016b0290027206870087016602640b64058408740164027c04640119000b0083024400830153007c046401190064016b02900272427c046402190064016b0090027242870087016602640c64058408740164027c04640219000b008302440083015300640d900273507400640e8301820164005300290f4e720300000072020000007a0e496e76616c696420766563746f72630100000000000000020000000500000013000000731c00000067007c005d147d0188007c01170088017c0117006602910271045300720f000000720f0000002902da022e307244000000290272530000007254000000720f0000007210000000fa0a3c6c697374636f6d703ea8000000730200000006007a2b5f5f6765745f696e7465726d6564696172795f706174682e3c6c6f63616c733e2e3c6c697374636f6d703e630100000000000000020000000400000013000000731800000067007c005d107d0188007c01170088016602910271045300720f000000720f000000290272570000007244000000290272530000007254000000720f00000072100000007258000000aa00000073020000000600630100000000000000020000000500000013000000731800000067007c005d107d01880088017c0117006602910271045300720f000000720f000000290272570000007244000000290272530000007254000000720f00000072100000007258000000ac00000073020000000600630100000000000000020000000500000013000000731c00000067007c005d147d0188007c01180088017c0118006602910271045300720f000000720f000000290272570000007244000000290272530000007254000000720f00000072100000007258000000af00000073020000000600630100000000000000020000000500000013000000731c00000067007c005d147d0188007c01180088017c0117006602910271045300720f000000720f000000290272570000007244000000290272530000007254000000720f00000072100000007258000000b200000073020000000600630100000000000000020000000500000013000000731c00000067007c005d147d0188007c01170088017c0118006602910271045300720f000000720f000000290272570000007244000000290272530000007254000000720f00000072100000007258000000b500000073020000000600630100000000000000020000000400000013000000731800000067007c005d107d0188007c01180088016602910271045300720f000000720f000000290272570000007244000000290272530000007254000000720f00000072100000007258000000b700000073020000000600630100000000000000020000000500000013000000731800000067007c005d107d01880088017c0118006602910271045300720f000000720f000000290272570000007244000000290272530000007254000000720f00000072100000007258000000b900000073020000000600467a134e6f7420612076616c696420766563746f722e29027219000000722f00000029057253000000725400000072550000007256000000724e000000720f0000002902725300000072540000007210000000da175f5f6765745f696e7465726d6564696172795f70617468a4000000732c00000000011001180118011e0118011e0118011e011a011a0120011c011c011e011c011c011e011c0120011c0120027259000000290372080000007241000000720d000000630200000000000000040000000200000043000000731800000074007c0083015c027d027d037c027c0366027c016b06530029014e29017223000000290472080000007241000000da066b696e675f78da066b696e675f79720f000000720f0000007210000000da185f5f69735f77686974655f6b696e675f696e5f636865636bbe000000730400000000010c01725c00000029057208000000724200000072400000007241000000720d0000006304000000000000001c000000080000004300000073ca01000074007c0083015c027d047d057c036a017c047c05660283017d067c0664006b096f2c74027c06830164016b04900172c67858740344005d505c027d077d087c047c0717007d097c057c0817007d0a74047c097c0a830272367c0074057c097c0a830219007d0b7c0b64026b02737674067c0b830172367c097c0a66027c036b077236640353007136570074027c06830164046b02900172c27c06640119007d0c74077c0c83015c027d0d7d0e7c026a017c0d7c0e660283017d0f7c0f64006b0990017214784e7c0f44005d467d107c006a0883007d117c007c1019007c117c0c3c0064027c117c103c0074097c11640564068d025c067d127d137d147d157d167d17740a7c117c13830273ca6403530071ca57007c007c0c19007d187c186a0b8300640a6b06900172c2740c7c047c057c0d7c0e83047d1978887c1944005d807d1a74057c1a640119007c1a6404190083027d1b7c016a017c1a83017d0f7c0f64006b099001723e78527c0f44005d4a7d107c006a0883007d117c007c1019007c117c1b3c0064027c117c103c0074097c11640564068d025c067d127d137d147d157d167d17740a7c117c1383029001736e640353009001716e57009001713e57006405530064035300290b4e720300000072280000004672020000005429017227000000722d000000722c000000722e0000002903722d000000722c000000722e000000290d7223000000da036765747230000000723c0000007218000000721c0000007216000000721f000000da04636f70797252000000725c00000072370000007259000000291c7208000000724200000072400000007241000000725a000000725b000000da147069656365735f63617573696e675f636865636b720c0000007217000000da086e5f6b696e675f78da086e5f6b696e675f79da0b6f746865725f7069656365da0d636865636b65725f696e646578da09636865636b65725f78da09636865636b65725f79da09646566656e64657273da08646566656e646572da096e65775f626f617264da026e30da146e65775f626c61636b5f61747461636b5f6d6170da026e32da026e33da026e34da026e35da0d636865636b65725f7069656365da11696e7465726d6564696174655f70617468724f000000da09706f735f696e646578720f000000720f0000007210000000da1d5f5f69735f77686974655f6b696e675f696e5f636865636b5f6d617465c3000000735400000000020c010e0116010e01080108010a010e0110010c0108010e0108010c010e010a010a0108010c010802180104010601080108010e01060108010a0112010a010a010a0108010c01080218010401080110010401727200000029047208000000723e0000007241000000720d000000630300000000000000050000000200000043000000732800000074007c0083015c027d037d047c037c0466027c026b07722474017c01830164016b0253006402530029034e72030000004629027223000000723000000029057208000000723e0000007241000000725a000000725b000000720f000000720f0000007210000000da1d5f5f69735f77686974655f6b696e675f696e5f7374616c655f6d617465f3000000730800000000020c010c010c017273000000290372080000007240000000720d000000630200000000000000040000000200000043000000731800000074007c0083015c027d027d037c027c0366027c016b06530029014e29017225000000290472080000007240000000725a000000725b000000720f000000720f0000007210000000da185f5f69735f626c61636b5f6b696e675f696e5f636865636bfb000000730400000000010c01727400000029057208000000724300000072410000007240000000720d0000006304000000000000001c000000080000004300000073ca01000074007c0083015c027d047d057c036a017c047c05660283017d067c0664006b096f2c74027c06830164016b04900172c67858740344005d505c027d077d087c047c0717007d097c057c0817007d0a74047c097c0a830272367c0074057c097c0a830219007d0b7c0b64026b02737674067c0b830172367c097c0a66027c036b077236640353007136570074027c06830164046b02900172c27c06640119007d0c74077c0c83015c027d0d7d0e7c026a017c0d7c0e660283017d0f7c0f64006b0990017214784e7c0f44005d467d107c006a0883007d117c007c1019007c117c0c3c0064027c117c103c0074097c11640564068d025c067d127d137d147d157d167d17740a7c117c12830273ca6403530071ca57007c007c0c19007d187c186a0b8300640a6b06900172c2740c7c047c057c0d7c0e83047d1978887c1944005d807d1a74057c1a640119007c1a6404190083027d1b7c016a017c1a83017d0f7c0f64006b099001723e78527c0f44005d4a7d107c006a0883007d117c007c1019007c117c1b3c0064027c117c103c0074097c11640564068d025c067d127d137d147d157d167d17740a7c117c1283029001736e640353009001716e57009001713e57006405530064035300290b4e720300000072280000004672020000005429017226000000722d000000722c000000722e0000002903722d000000722c000000722e000000290d7225000000725d0000007230000000723c0000007218000000721c0000007214000000721f000000725e0000007252000000727400000072370000007259000000291c7208000000724300000072410000007240000000725a000000725b000000725f000000720c0000007217000000726000000072610000007262000000726300000072640000007265000000726600000072670000007268000000da146e65775f77686974655f61747461636b5f6d6170da026e31726b000000726c000000726d000000726e000000726f0000007270000000724f0000007271000000720f000000720f0000007210000000da1d5f5f69735f626c61636b5f6b696e675f696e5f636865636b5f6d61746500010000735400000000020c010e0116010e01080108010a010e0110010c0108010e0108010c010e010a010a0108010c010802180104010601080108010e01060108010a0112010a010a010a0108010c01080218010401080110010401727700000029047208000000723f0000007240000000720d000000630300000000000000050000000200000043000000732800000074007c0083015c027d037d047c037c0466027c026b07722474017c01830164016b0253006402530029034e72030000004629027225000000723000000029057208000000723f0000007240000000725a000000725b000000720f000000720f0000007210000000da1d5f5f69735f626c61636b5f6b696e675f696e5f7374616c655f6d61746530010000730800000000020c010c010c0172780000002901da047465616d63010000000000000001000000040000004300000073300000007c0064016b02720c640253007c0064026b027218640153006403732c740064047c009b0064059d03830182016400530029064e72050000007206000000467a0e496e76616c6964207465616d3a20da012e2901721900000029017279000000720f000000720f0000007210000000da0f5f5f6f70706f73696e675f7465616d38010000730a00000000010801040108010402727b0000002902da057374617465da086d65746164617461630200000000000000020000000300000043000000731a0000007c006a006401830164006b08721664027c0064033c006400530029044eda0677696e6e657254da097374616c656d6174652901725d0000002902727c000000727d000000720f000000720f0000007210000000da0f666f7263655f656e645f726f756e6441010000730400000000020e0172800000002905da0663616c6c65727279000000da077061796c6f6164727c000000727d0000006305000000000000002c000000060000004300000073f60700007c02640119007d057c02640219007d067c02640319007d077c02640419007d0874007c036405190083017d0974017c057c0683027d0a7c097c0a19007d0b7c03640619007c016b02735274026407830182017c0164086b02726c74037c0b8301739274026409830182016e267c01640a6b0273827402640b7c019b009d028301820174047c0b83017392740264098301820174057c0183017d0c7c0b6a0683007d0d640c7d0e64007d0f640c7d107c0d640d6b0272ee7c01640a6b0272d67c05640e6b0272cc74077d116e0474087d1174097d0f6e167c05640f6b0272e4740a7d116e04740b7d11740c7d0f6ed27c0d64106b0272fc740d7d116ec47c0d64116b0290017210740e7d1164127d0e6eb07c0d64136b0290017224740f7d1164127d0e6e9c7c0d64146b029001723874107d1164127d0e6e887c0d64156b02900172ac74037c0b83019001727a7c0564166b02900172a67c0764166b02900172a67c0664176b02900172a67c08643c6b06900172a664127d106e2c7c0564196b02900172a67c0764196b02900172a67c0664176b02900172a67c08643d6b06900172a664127d1074117d116e14640c900173c07402641a7c0b9b009d02830182017c0f900170c87c117d0f7c077c0518007c087c06180066027d1274017c077c0883027d1364007c037c019b00641b9d023c0074127c138301900672a07c0e90037244640c7d1464007d1578a87c1144005da07d167c166419190064196b02900272467c126419190064196b0290026f427c12640e19007c16640e19001a00640e6b057d146e5c7c16640e190064196b02900272787c12640e190064196b0290026f747c12641919007c16641919001a00640e6b057d146e2a7c12641919007c16641919001a00640e6b0590026fa07c12640e19007c16640e19001a00640e6b057d147c14900272107c167d1550009002711057007c14900273ca7402641c7c0b9b00641d9d03830182017c057c156419190017007c067c15640e1900170066027d17785c74017c17641919007c17640e190083027d187c187c136b03900372387c097c181900641e6b02900373167402641f830182017c17641919007c156419190017007c17640e19007c15640e1900170066027d176e025000900271e4570090016e9e7c10900472c67c036a137c019b0064209d0283010c009003736674026421830182017c0164086b029003728a74147c09641264228d025c067d197d1a7d197d197d197d196e1874147c09641264228d025c067d1a7d197d197d197d197d197c057c0666027c1a6b07900373b874026423830182017c08640f6b029004723a7c036a137c019b0064249d0283010c00900373de74026425830182017844643e44005d3c7d1b74017c057c1b83027d1c7c097c1c1900641e6b029004730874026427830182017c057c1b66027c1a6b07900373e47402642883018201900371e4570074017c05641683027d1d74017c05642683027d1e6e767c036a137c019b0064299d0283010c009004735674026425830182017844643f44005d3c7d1b74017c057c1b83027d1c7c097c1c1900641e6b029004738074026427830182017c057c1b66027c1a6b079004735c74026428830182019004715c570074017c05641983027d1d74017c05642a83027d1e7c097c1d19007c097c1e3c00641e7c097c1d3c006e1c7c0d640d6b03900472e27c127c116b06900473e27402642b830182017c097c1319007d1f7c1f641e6b03900572427c01640a6b029005721274037c1f8301900573247402642c830182016e1274047c1f8301900573247402642c830182017c0d640d6b02900672387c127c0f6b06900673387402642d830182016ef67c0d640d6b02900672387c036a137c0c9b00641b9d0283017d20640c7d217c2064006b09900572c67c20641919007c057c0666026b029005738e7c20640e19007c057c0666026b02900572c67c20641819007c077c0866026b02900572c664127d2174017c20642a1900641919007c20642a1900640e190083027d22641e7c097c223c007c21900573de7c127c116b06900573de7402642e830182017c126419190064186b02900573fa7c126419190064406b02900672387c077c08640e180066027c077c08640e170066027c057c126419190064181a0017007c0866027c077c08660267047d207c207c037c019b00641b9d023c00641e7c097c0a3c007c0b7c097c133c007c0d64156b029006726264127c037c019b0064209d023c006e3c7c0d64136b02900672ae7c0664196b029006728664127c037c019b0064299d023c006e187c0664166b02900672ae64127c037c019b0064249d023c006e0e640c900673ae7402642f830182017c01640a6b02900672da7c077415640e18006b02900672f67c0b64306b02900672f664317c097c133c006e1c7c0764196b02900672f67c0b640d6b02900672f664147c097c133c0074147c0983015c067d237d247d257d267d277d28640c7d29640c7d2a7c01640a6b029007726c74167c097c2383020c0090077332740264328301820174177c097c2483027d2b7c2b7c0364333c007c2b9007725c74187c097c237c257c2464348d047d296e0e74197c097c277c2464358d037d2a6e4e74177c097c2483020c0090077382740264328301820174167c097c2383027d2b7c2b7c0364363c007c2b900772ac741a7c097c247c267c2364378d047d296e0e741b7c097c287c2364388d037d2a64396a1c7c0983017d097c0c7c0364063c007c097c0364053c007c2a900772e464127c03643a3c006e0e7c29900772f27c017c03643b3c006400530029414e7253000000725400000072550000007256000000720800000072070000007a1c4974206973206e6f7420796f7572207475726e20746f206d6f76652e72050000007a1f54686973206973206e6f7420796f757220706965636520746f206d6f76652e72060000007a0e496e76616c6964207465616d3a2046722a00000072020000007229000000722b000000722c00000054722d000000722e0000007222000000e907000000e904000000720400000072030000007a0f496e76616c69642070696563653a20da0b5f656e5f70617373616e747a12496e76616c6964206d6f7665207769746820727a00000072280000007a2a496e76616c6964206d6f76652e20416e6f7468657220706965636520697320696e20746865207761792eda0b5f6d6f7665645f6b696e677a174b696e672068617320616c7265616479206d6f7665642e290172270000007a1f596f752063616e6e6f7420636173746c65206f7574206f6620636865636b2eda0c5f6d6f7665645f726f6f6b377a17526f6f6b2068617320616c7265616479206d6f7665642ee9050000007a225069656365732061726520696e2074686520776179206f6620636173746c696e672e7a20596f752063616e6e6f7420636173746c65207468726f75676820636865636b2eda0c5f6d6f7665645f726f6f6b30e9030000007a2e496e76616c6964206d6f76652e204e6f7420612076616c6964206d6f766520666f7220746869732070696563652e7a1f596f752063616e6e6f742074616b6520796f7572206f776e2070696563652e7a14496e76616c6964207061776e2061747461636b2e7a12496e76616c6964207061776e206d6f76652e7a28496e76616c6964206d6f76652e205069656365206973206e6f74206f6e2074686520626f6172642eda0170da01717a1c54686973206d6f7665207075747320796f7520696e20636865636b2eda0a775f696e5f636865636b2904720800000072400000007242000000724100000029037208000000723e0000007241000000da0a625f696e5f636865636b2904720800000072410000007243000000724000000029037208000000723f00000072400000007210000000727f000000727e000000290272290000007204000000290272290000007204000000290272880000007229000000290372020000007204000000728a000000e9feffffff291dda046c697374721c000000721900000072140000007216000000727b000000723700000072350000007236000000723400000072320000007233000000723100000072380000007239000000723a000000723b000000723c000000721e000000725d0000007252000000721b0000007274000000725c0000007272000000727300000072770000007278000000da046a6f696e292c728100000072790000007282000000727c000000727d00000072530000007254000000725500000072560000007208000000da0a637572725f696e646578da0a637572725f7069656365da086f70706f6e656e74da0b70696563655f75707065727245000000da0e61747461636b5f766563746f7273da1169735f636173746c655f617474656d7074724c000000da0b6e6578745f766563746f72da0a6e6578745f696e6465787250000000da0d766563746f725f746f5f757365724e000000da10696e7465726d6564696174655f706f73da12696e7465726d6564696174655f696e646578da026c30da136f70706f6e656e745f61747461636b5f6d6170da026e79da076e5f696e646578da08726f6f6b5f696478da0b726f6f6b5f746f5f696478da0a6e6578745f7370616365da0a656e5f70617373616e74da1076616c69645f656e5f70617373616e74da10656e5f70617373616e745f696e6465787240000000724100000072420000007243000000723e000000723f000000da09636865636b6d617465727f000000da116f70706f6e656e745f696e5f636865636b720f000000720f0000007210000000da046d6f7665470100007374010000000208010801080108010c010a01080114010801120216011001080108010401040104010801080108010602040106020801060204010601080106010a01040106010a01040106010a01040106010a010a01140114010601140114010401060214010a0110010a010e010a010601040104010a010e011c0108010e011c0108021c010e0106010401080116011801020108010a010a01060110010e0114020c010601160106010a010201180202011601060110010a01160106010a010a0106011001060116010a010c02160106010a010a0106011001060116010a010a010c010a010a01120108010a010a010c0108020c0106010a0114010a01100104010a0124011201040108011201080118011c01180118010e01080108010a0110010a010a0110010a0110020e010a0118010a01140108021402040104010a01100106010a0108010601040102010c02040102010a02100106010a0108010601040102010c020401020108010a010801080106010a01060172a9000000e9ffffffff290272aa000000720200000072aa00000072aa000000290272aa00000072aa00000072aa000000290272aa0000007203000000728f0000002902728f000000720300000072aa000000290272aa000000720300000029027202000000720200000072aa0000002902720200000072aa00000029027202000000720300000029027204000000720300000029027202000000720300000072aa00000072aa000000290272aa00000072aa00000072aa0000002902720200000072aa00000072aa000000290272aa000000720300000072aa0000002902720300000072aa00000029027202000000720300000029027203000000720200000072aa000000290272aa000000720200000029027202000000720200000029027202000000720400000029027204000000720200000072aa000000290272aa000000720400000072aa0000002902720400000072aa000000728f00000029027202000000728f000000728f0000002902728f0000007202000000728f00000072aa0000002902728f00000072aa00000072aa000000728f000000290272aa000000728f00000029027202000000720300000072aa000000290272aa000000720300000029027203000000720200000072aa0000002902720300000072aa00000072aa00000072aa000000290272aa00000072aa00000072aa000000290272aa000000720200000072aa0000002902720200000072aa00000029027202000000720200000029014e29024646292e721b00000072210000007220000000da0d494e495449414c5f424f415244723100000072320000007233000000723400000072350000007236000000723c0000007238000000723a0000007239000000723b00000072300000007219000000da03737472720e000000da085f5f6578706f7274da04646963747211000000da04626f6f6c72140000007216000000da03696e74721c000000da057475706c65721f000000721e000000721800000072230000007225000000da03736574725200000072900000007259000000725c00000072720000007273000000727400000072770000007278000000727b000000728000000072a9000000720f000000720f000000720f0000007210000000da083c6d6f64756c653e01000000735c0000000801080204010801080106010801080106010e0106010c0108010c010c010801160108010a03060114041004100412051007100412041004100400011663161a12050401122f0401100712050401122f040110070e09060112050601