Contract con_poker_1_card_games_v3


Contract Code


  
1 # con_poker_1_card_games_v3
2 import con_rsa_encryption as rsa
3 import con_phi_lst001 as phi
4
5 phi_balances = ForeignHash(foreign_contract='con_phi_lst001', foreign_name='balances')
6
7 games = Hash(default_value=None)
8 hands = Hash(default_value=None)
9 game_names = Hash(default_value=None)
10 players_games = Hash(default_value=[])
11 players_invites = Hash(default_value=[])
12 messages_hash = Hash(default_value=[])
13 player_metadata_contract = Variable()
14 owner = Variable()
15
16 MAX_PLAYERS = 50
17 MAX_RANDOM_NUMBER = 99999999
18 ONE_CARD_POKER = 0
19 BLIND_POKER = 1
20
21 DECK = [
22 '2c', '2d', '2h', '2s',
23 '3c', '3d', '3h', '3s',
24 '4c', '4d', '4h', '4s',
25 '5c', '5d', '5h', '5s',
26 '6c', '6d', '6h', '6s',
27 '7c', '7d', '7h', '7s',
28 '8c', '8d', '8h', '8s',
29 '9c', '9d', '9h', '9s',
30 'Tc', 'Td', 'Th', 'Ts',
31 'Jc', 'Jd', 'Jh', 'Js',
32 'Qc', 'Qd', 'Qh', 'Qs',
33 'Kc', 'Kd', 'Kh', 'Ks',
34 'Ac', 'Ad', 'Ah', 'As',
35 ]
36
37 RANKS = {
38 '2c': 13, '2d': 13, '2h': 13, '2s': 13,
39 '3c': 12, '3d': 12, '3h': 12, '3s': 12,
40 '4c': 11, '4d': 11, '4h': 11, '4s': 11,
41 '5c': 10, '5d': 10, '5h': 10, '5s': 10,
42 '6c': 9, '6d': 9, '6h': 9, '6s': 9,
43 '7c': 8, '7d': 8, '7h': 8, '7s': 8,
44 '8c': 7, '8d': 7, '8h': 7, '8s': 7,
45 '9c': 6, '9d': 6, '9h': 6, '9s': 6,
46 'Tc': 5, 'Td': 5, 'Th': 5, 'Ts': 5,
47 'Jc': 4, 'Jd': 4, 'Jh': 4, 'Js': 4,
48 'Qc': 3, 'Qd': 3, 'Qh': 3, 'Qs': 3,
49 'Kc': 2, 'Kd': 2, 'Kh': 2, 'Ks': 2,
50 'Ac': 1, 'Ad': 1, 'Ah': 1, 'As': 1,
51 }
52
53
54 random.seed()
55
56
57 @construct
58 def seed():
59 owner.set(ctx.caller)
60 player_metadata_contract.set('con_gamma_phi_profile_v4')
61
62
63 @export
64 def update_player_metadata_contract(contract: str):
65 assert ctx.caller == owner.get(), 'Only the owner can call update_player_metadata_contract()'
66 player_metadata_contract.set(contract)
67
68
69 def get_players_and_assert_exists(game_id: str) -> dict:
70 players = games[game_id, 'players']
71 assert players is not None, f'Game {game_id} does not exist.'
72 return players
73
74
75 def create_game_id(creator: str) -> str:
76 return hashlib.sha3(":".join([creator, str(now)]))
77
78
79 def create_hand_id(game_id: str) -> str:
80 return hashlib.sha3(":".join([game_id, str(now)]))
81
82
83 @export
84 def game_message(game_id: str, message: str):
85 player = ctx.caller
86 players = get_players_and_assert_exists(game_id)
87 assert player in players, 'You do not belong to this game.'
88 messages = messages_hash[game_id, player] or []
89 messages.append(message)
90 messages_hash[game_id, player] = messages
91
92
93 @export
94 def hand_message(hand_id: str, message: str):
95 player = ctx.caller
96 active_players = hands[hand_id, 'active_players']
97 assert player in active_players, 'You do not belong to this hand.'
98 messages = messages_hash[hand_id, player] or []
99 messages.append(message)
100 messages_hash[hand_id, player] = messages
101
102
103 @export
104 def add_chips_to_game(game_id: str, amount: float):
105 player = ctx.caller
106 assert amount > 0, 'Amount must be a positive number'
107
108 players = get_players_and_assert_exists(game_id)
109 assert player in players, 'You do not belong to this game.'
110
111 games[game_id, player] = (games[game_id, player] or 0.0) + amount
112 assert phi_balances[player, ctx.this] >= amount, 'You have not approved enough for this amount of chips'
113 phi.transfer_from(amount, ctx.this, player)
114
115
116 @export
117 def withdraw_chips_from_game(game_id: str, amount: float):
118 player = ctx.caller
119 assert amount > 0, 'Amount must be a positive number'
120
121 players = get_players_and_assert_exists(game_id)
122 assert player in players, 'You do not belong to this game.'
123
124 current_chip_count = games[game_id, player]
125
126 assert current_chip_count >= amount, 'You cannot withdraw more than you have.'
127
128 games[game_id, player] = current_chip_count - amount
129 phi.transfer(
130 amount=amount,
131 to=player
132 )
133
134
135 @export
136 def respond_to_invite(game_id: str, accept: bool):
137 player = ctx.caller
138 player_invites = players_invites[player] or []
139 players = get_players_and_assert_exists(game_id)
140 assert player not in players, 'You are already a part of this game.'
141 assert len(players) < MAX_PLAYERS, f'Only {MAX_PLAYERS} are allowed to play at the same time.'
142 declined = players_invites[player, 'declined'] or []
143 assert game_id in player_invites or game_id in declined or games[game_id, 'public'], 'You have not been invited to this game.'
144 if game_id in player_invites:
145 player_invites.remove(game_id)
146 players_invites[player] = player_invites
147 players_invites[player, game_id] = accept
148 if accept:
149 if game_id in declined:
150 declined.remove(game_id)
151 players_invites[player, 'declined'] = declined
152 players.append(player)
153 games[game_id, 'players'] = players
154 players_games[player] = (players_games[player] or []) + [game_id]
155 else:
156 if game_id not in declined:
157 declined.append(game_id)
158 players_invites[player, 'declined'] = declined
159
160
161 @export
162 def decline_all_invites():
163 # Nuclear option
164 player = ctx.caller
165 invites = players_invites[player] or []
166 for invite in invites:
167 players_invites[player, invite] = False
168 players_invites[player] = []
169
170
171 def send_invite_requests(game_id: str, others: list):
172 for other in others:
173 player_invites = players_invites[other] or []
174 player_invites.append(game_id)
175 players_invites[other] = player_invites
176
177
178 def validate_game_name(name: str):
179 assert name is not None and len(name) > 0, 'Game name cannot be null or empty'
180 assert isinstance(name, str), 'Game name must be a string.'
181 assert len(name) <= 24, 'Game name cannot be longer than 24 characters.'
182 assert all([c.isalnum() or c in ('_', '-') for c in name]), 'Game name has invalid characters. Each character must be alphanumeric, a hyphen, or an underscore.'
183 assert name[0] not in ('-', '_') and name[-1] not in ('-', '_'), 'Game name cannot start or end with a hyphen or underscore.'
184
185
186 @export
187 def start_game(name: str, other_players: list, ante: float, public: bool = False) -> str:
188 creator = ctx.caller
189
190 assert ante >= 0, 'Ante must be non-negative.'
191 assert creator not in other_players, f'Caller can\'t be in other_players input.'
192 #assert other_players is not None and (len(other_players) > 0), 'You cannot play by yourself!'
193 assert len(other_players) < MAX_PLAYERS, f'Only {MAX_PLAYERS} are allowed to play at the same time.'
194
195 game_id = create_game_id(creator=creator)
196
197 assert games[game_id, 'creator'] is None, f'Game {game_id} has already been created.'
198
199 validate_game_name(name)
200 assert game_names[name] is None, f'Game {name} has already been created.'
201 game_names[name] = game_id
202
203 games[game_id, 'players'] = [creator]
204 games[game_id, 'ante'] = ante
205 games[game_id, 'creator'] = creator
206 games[game_id, 'invitees'] = other_players
207 games[game_id, 'public'] = public
208
209 players_games[creator] = (players_games[creator] or []) + [game_id]
210 send_invite_requests(game_id, other_players)
211
212 return game_id
213
214
215 @export
216 def add_player_to_game(game_id: str, player_to_add: str):
217 player = ctx.caller
218 assert player != player_to_add, 'You cannot add yourself to a game.'
219 creator = games[game_id, 'creator']
220 assert player == creator, 'Only the game creator can add players.'
221 players = get_players_and_assert_exists(game_id)
222 assert player_to_add not in players, 'Player is already in the game.'
223 invitees = games[game_id, 'invitees']
224 assert player_to_add not in invitees, 'Player has already been invited.'
225 invitees.append(player_to_add)
226 assert len(players) < MAX_PLAYERS, f'Only {MAX_PLAYERS} are allowed to play at the same time.'
227 games[game_id, 'invitees'] = invitees
228 send_invite_requests(game_id, [player_to_add])
229
230
231 @export
232 def leave_game(game_id: str):
233 player = ctx.caller
234 players = get_players_and_assert_exists(game_id)
235 assert player in players, 'You are not in this game.'
236
237 chips = games[game_id, player]
238 assert chips is None or chips == 0, 'You still have chips in this game. Please withdraw them before leaving.'
239
240 player_games = players_games[player]
241 player_games.remove(game_id)
242 players_games[player] = player_games
243 players.remove(player)
244 games[game_id, 'players'] = players
245
246 hand_id = games[game_id, 'current_hand']
247
248 if hand_id is not None:
249 # Check some stuff
250 active_players = hands[hand_id, 'active_players'] or []
251 if player in active_players:
252 folded = hands[hand_id, 'folded']
253 all_in = hands[hand_id, 'all_in']
254 next_better = hands[hand_id, 'next_better']
255 if next_better == player:
256 # Check for next better before removing player from hand state
257 next_better = get_next_better(active_players, folded, all_in, player)
258 hands[hand_id, 'next_better'] = next_better
259 active_players.remove(player)
260 hands[hand_id, 'active_players'] = active_players
261 if player in folded:
262 folded.remove(player)
263 hands[hand_id, 'folded'] = folded
264 if player in all_in:
265 all_in.remove(player)
266 hands[hand_id, 'all_in'] = all_in
267
268
269 @export
270 def start_hand(game_id: str, game_type: int) -> str:
271 dealer = ctx.caller
272 assert game_type == ONE_CARD_POKER or game_type == BLIND_POKER, 'Invalid game type.'
273
274 players = get_players_and_assert_exists(game_id)
275 assert dealer in players, 'You are not a part of this game.'
276 assert len(players) > 1, 'You cannot start a hand by yourself.'
277
278 previous_hand_id = games[game_id, 'current_hand']
279 if previous_hand_id is not None:
280 assert hands[previous_hand_id, 'payed_out'], 'The previous hand has not been payed out yet.'
281
282 hand_id = create_game_id(game_id)
283 # Update game state
284 games[game_id, 'current_hand'] = hand_id
285 # Update hand state
286 hands[hand_id, 'game_id'] = game_id
287 hands[hand_id, 'game_type'] = game_type
288 hands[hand_id, 'dealer'] = dealer
289 hands[hand_id, 'folded'] = []
290 hands[hand_id, 'completed'] = False
291 hands[hand_id, 'payed_out'] = False
292 hands[hand_id, 'reached_dealer'] = False
293 hands[hand_id, 'active_players'] = []
294 hands[hand_id, 'current_bet'] = 0
295 hands[hand_id, 'all_in'] = []
296 return hand_id
297
298
299 def active_player_sort(players: list) -> int:
300 def sort(player):
301 return players.index(player)
302 return sort
303
304
305 @export
306 def ante_up(hand_id: str):
307 player = ctx.caller
308 game_id = hands[hand_id, 'game_id']
309 assert game_id is not None, 'This game does not exist.'
310 players = get_players_and_assert_exists(game_id)
311 assert player in players, 'You are not a part of this game.'
312 ante = games[game_id, 'ante']
313 chips = games[game_id, player]
314 assert chips is not None and chips >= ante, 'You do not have enough chips.'
315 active_players = hands[hand_id, 'active_players'] or []
316 assert player not in active_players, 'You have already paid the ante.'
317 # Pay ante
318 hands[hand_id, player, 'bet'] = ante
319 hands[hand_id, player, 'max_bet'] = chips
320 games[game_id, player] -= ante
321 # Update hand state
322 active_players.append(player)
323 active_players.sort(key=active_player_sort(players))
324 hands[hand_id, 'active_players'] = active_players
325 hands[hand_id, 'current_bet'] = ante
326 if chips == ante:
327 # All in
328 all_in = hands[hand_id, 'all_in']
329 all_in.append(player)
330 hands[hand_id, 'all_in'] = all_in
331
332
333 @export
334 def deal_cards(hand_id: str):
335 dealer = ctx.caller
336
337 active_players = hands[hand_id, 'active_players']
338
339 assert dealer == hands[hand_id, 'dealer'], 'You are not the dealer.'
340 assert len(active_players) > 1, f'Not enough active players: {len(active_players)} <= 1'
341 assert dealer in active_players, 'You are not actively part of this hand.'
342
343 game_type = hands[hand_id, 'game_type']
344
345 player_metadata = ForeignHash(foreign_contract=player_metadata_contract.get(), foreign_name='metadata')
346
347 cards = DECK
348 random.shuffle(cards)
349
350 for i in range(len(active_players)):
351 player = active_players[i]
352 player_key = player_metadata[player, 'public_rsa_key']
353 assert player_key is not None, f'Player {player} has not setup their encryption keys.'
354 keys = player_key.split('|')
355 assert len(keys) == 2, 'Invalid keys'
356
357 if game_type == ONE_CARD_POKER:
358 player_hand = cards[i: i+1]
359 else:
360 # Player's hand is actually everyone elses hand
361 player_hand = cards[0:i] + cards[i+1:len(active_players)]
362 assert len(player_hand) == len(active_players)-1, f'Something went wrong. {len(player_hand)} != {len(active_players)-1}'
363
364 player_hand_str = ",".join(player_hand)
365 salt = str(random.randint(0, MAX_RANDOM_NUMBER))
366
367 player_hand_str_with_salt = f'{player_hand_str}:{salt}'
368
369 # Encrypt players hand with their personal keys
370 player_encrypted_hand = rsa.encrypt(
371 message_str=player_hand_str_with_salt,
372 n=int(keys[0]),
373 e=int(keys[1])
374 )
375
376 # For verification purposes
377 house_encrypted_hand = hashlib.sha3(player_hand_str_with_salt)
378
379 hands[hand_id, player, 'player_encrypted_hand'] = player_encrypted_hand
380 hands[hand_id, player, 'house_encrypted_hand'] = house_encrypted_hand
381
382 # Update hand state
383 all_in = hands[hand_id, 'all_in']
384 hands[hand_id, 'next_better'] = get_next_better(active_players, [], all_in, dealer)
385 ante = games[hands[hand_id, 'game_id'], 'ante']
386 hands[hand_id, 'pot'] = ante * len(active_players)
387
388
389 def get_next_better(players: list, folded: list, all_in: list, current_better: str) -> str:
390 if len(folded) >= len(players) - 1:
391 return None # No one needs to bet, only one player left in the hand
392 if len(players) == len(all_in):
393 return None # No one needs to bet, everyone is all in
394 non_folded_players = [p for p in players if p not in folded and p not in all_in]
395 current_index = non_folded_players.index(current_better)
396 assert current_index >= 0, 'Current better has folded, which does not make sense.'
397 return non_folded_players[(current_index + 1) % len(non_folded_players)]
398
399
400 @export
401 def bet_check_or_fold(hand_id: str, bet: float):
402 player = ctx.caller
403
404 assert hands[hand_id, player, 'player_encrypted_hand'] is not None, 'Hand does not exist'
405 assert not hands[hand_id, 'completed'], 'This hand has already completed.'
406 assert hands[hand_id, 'next_better'] == player, 'It is not your turn to bet.'
407
408 active_players = hands[hand_id, 'active_players']
409 folded = hands[hand_id, 'folded']
410
411 call_bet = hands[hand_id, 'current_bet'] or 0.0
412 player_previous_bet = hands[hand_id, player, 'bet'] or 0.0
413 dealer = hands[hand_id, 'dealer']
414
415 if dealer == player:
416 # Been around the circle once
417 hands[hand_id, 'reached_dealer'] = True
418 reached_dealer = True
419 else:
420 reached_dealer = hands[hand_id, 'reached_dealer']
421
422 all_in = hands[hand_id, 'all_in']
423 next_better = get_next_better(active_players, folded, all_in, player)
424
425 if next_better is None:
426 # No need to bet, this is the end of the hand
427 hands[hand_id, 'completed'] = True
428
429 else:
430 if bet < 0:
431 # Folding
432 folded.append(player)
433 hands[hand_id, 'folded'] = folded
434 if player in all_in:
435 all_in.remove(player)
436 hands[hand_id, 'all_in'] = all_in
437 if len(folded) == len(active_players) - 1:
438 hands[hand_id, 'completed'] = True
439 elif bet == 0:
440 # Checking
441 max_bet = hands[hand_id, player, 'max_bet']
442 if max_bet == player_previous_bet and player not in all_in:
443 all_in.append(player)
444 hands[hand_id, 'all_in'] = all_in
445 assert max_bet == player_previous_bet or player_previous_bet >= call_bet, 'Cannot check in this scenario. Current bet is above your bet and you are not all in.'
446 next_players_bet = hands[hand_id, next_better, 'bet']
447 if next_players_bet is not None and next_players_bet == call_bet and reached_dealer:
448 # Betting is over (TODO allow reraise)
449 hands[hand_id, 'completed'] = True
450 else:
451 # Betting
452 game_id = hands[hand_id, 'game_id']
453 assert games[game_id, player] >= bet, 'You do not have enough chips to make this bet'
454 current_bet = player_previous_bet + bet
455 max_bet = hands[hand_id, player, 'max_bet']
456 if max_bet == current_bet and player not in all_in:
457 all_in.append(player)
458 hands[hand_id, 'all_in'] = all_in
459 assert max_bet == current_bet or current_bet >= call_bet, 'Current bet is above your bet and you did not go all in.'
460 hands[hand_id, player, 'bet'] = current_bet
461 hands[hand_id, 'current_bet'] = current_bet
462 hands[hand_id, 'pot'] += bet
463 games[game_id, player] -= bet
464
465 hands[hand_id, 'next_better'] = next_better
466
467
468 @export
469 def verify_hand(hand_id: str, player_hand_str: str) -> str:
470 # TODO allow user to not verify onchain to hide bluffs
471
472 player = ctx.caller
473 assert hands[hand_id, 'completed'], 'This hand has not completed yet.'
474 folded = hands[hand_id, 'folded']
475 assert player not in folded, 'No need to verify your hand because you folded.'
476 active_players = hands[hand_id, 'active_players']
477 assert player in active_players, 'You are not an active player in this hand.'
478
479 # Check if player has bet enough
480 bet_should_equal = hands[hand_id, 'current_bet']
481 assert bet_should_equal is not None, 'There is no current bet.'
482
483 player_bet = hands[hand_id, player, 'bet']
484 assert player_bet is not None, 'You have not bet yet.'
485
486 assert bet_should_equal == player_bet, 'Bets have not stabilized.'
487
488 # For verification purposes
489 house_encrypted_hand = hashlib.sha3(player_hand_str)
490
491 previous_house_encrypted_hand = hands[hand_id, player, 'house_encrypted_hand']
492
493 verified = previous_house_encrypted_hand is not None and \
494 previous_house_encrypted_hand == house_encrypted_hand
495
496 if not verified:
497 # BAD ACTOR NEEDS TO BE PUNISHED
498 folded.append(player)
499 hands[hand_id, 'folded'] = folded
500
501 return 'Verification failed. Your hand has been forfeited.'
502
503 else:
504 cards = player_hand_str.split(':')[0].split(',')
505
506 game_type = hands[hand_id, 'game_type']
507
508 if game_type == ONE_CARD_POKER:
509 rank = RANKS[cards[0]]
510 hands[hand_id, player, 'rank'] = rank
511 hands[hand_id, player, 'hand'] = cards
512 else:
513 j = 0
514 for p in active_players:
515 if p != player:
516 if p not in folded:
517 card = cards[j]
518 rank = RANKS[card]
519 hands[hand_id, p, 'rank'] = rank
520 hands[hand_id, p, 'hand'] = card
521 j += 1
522
523 return 'Verification succeeded.'
524
525
526 def find_winners(ranks: dict, players: list) -> list:
527 sorted_rank_values = sorted(ranks.keys())
528 player_set = set(players)
529 for rank in sorted_rank_values:
530 players_with_rank = ranks[rank]
531 intersection = player_set.intersection(set(players_with_rank))
532 if len(intersection) > 0:
533 # Found players
534 winners = list(intersection)
535 break
536 return winners
537
538
539 def calculate_ranks(hand_id: str, players: list) -> dict:
540 ranks = {}
541 for p in players:
542 rank = hands[hand_id, p, 'rank']
543 assert rank is not None, f'Player {p} has not verified their hand yet.'
544 if rank not in ranks:
545 ranks[rank] = []
546 ranks[rank].append(p)
547 return ranks
548
549
550 @export
551 def payout_hand(hand_id: str):
552 pot = hands[hand_id, 'pot']
553 assert pot > 0, 'There is no pot to claim!'
554 assert not hands[hand_id, 'payed_out'], 'This hand has already been payed out.'
555
556 folded = hands[hand_id, 'folded']
557 all_in = hands[hand_id, 'all_in']
558 active_players = hands[hand_id, 'active_players']
559
560 remaining = [p for p in active_players if p not in folded]
561 assert len(remaining) > 0, 'There are no remaining players.'
562
563 payouts = {}
564
565 if len(remaining) == 1:
566 # Just pay out, everyone else folded
567 payouts[remaining[0]] = pot
568 else:
569 ranks = calculate_ranks(hand_id, remaining)
570 if len(all_in) > 0:
571 # Need to calculate split pots
572 all_in_map = {}
573 for player in all_in:
574 # Check all in amount
575 amount = hands[hand_id, player, 'max_bet']
576 all_in_map[player] = amount
577 pots = sorted(set(all_in_map.values()))
578 total_payed_out = 0
579 for bet in pots:
580 players_in_pot = []
581 for player in remaining:
582 if player not in all_in_map or all_in_map[player] >= bet:
583 players_in_pot.append(player)
584 pot_winners = find_winners(ranks, players_in_pot)
585 pot_payout = bet * len(players_in_pot)
586 total_payed_out += pot_payout
587 payout = pot_payout / len(pot_winners)
588 for winner in pot_winners:
589 if winner not in payouts:
590 payouts[winner] = 0
591 payouts[winner] += payout
592 remaining_to_payout = pot - total_payed_out
593 not_all_in = set(remaining).difference(set(all_in))
594 assert remaining_to_payout == 0 or len(not_all_in) > 0, 'Invalid state when calculating side pots.'
595 if remaining_to_payout > 0:
596 if len(not_all_in) == 1:
597 winners = not_all_in
598 else:
599 winners = find_winners(ranks, not_all_in)
600 payout = remaining_to_payout / len(winners)
601 for winner in winners:
602 if winner not in payouts:
603 payouts[winner] = 0
604 payouts[winner] += payout
605 else:
606 winners = find_winners(ranks, remaining)
607 payout = pot / len(winners)
608 for winner in winners:
609 payouts[winner] = payout
610
611 game_id = hands[hand_id, 'game_id']
612 for player, payout in payouts.items():
613 games[game_id, player] += payout
614
615 hands[hand_id, 'winners'] = list(payouts.keys())
616 hands[hand_id, 'payed_out'] = True
617
618
619 @export
620 def emergency_withdraw(amount: float):
621 assert ctx.caller == owner.get(), 'Only the owner can call emergency_withdraw()'
622 phi.transfer(
623 amount=amount,
624 to=ctx.caller
625 )
626
627
628 @export
629 def emergency_game_update(keys: list, value: Any):
630 assert ctx.caller == owner.get(), 'Only the owner can call emergency_game_update()'
631 if len(keys) == 1:
632 games[keys[0]] = value
633 elif len(keys) == 2:
634 games[keys[0], keys[1]] = value
635 elif len(keys) == 3:
636 games[keys[0], keys[1], keys[2]] = value
637 elif len(keys) == 4:
638 games[keys[0], keys[1], keys[2], keys[3]] = value
639
640
641 @export
642 def emergency_hand_update(keys: list, value: Any):
643 assert ctx.caller == owner.get(), 'Only the owner can call emergency_hand_update()'
644 if len(keys) == 1:
645 hands[keys[0]] = value
646 elif len(keys) == 2:
647 hands[keys[0], keys[1]] = value
648 elif len(keys) == 3:
649 hands[keys[0], keys[1], keys[2]] = value
650 elif len(keys) == 4:
651 hands[keys[0], keys[1], keys[2], keys[3]] = value
652
653
654 @export
655 def change_ownership(new_owner: str):
656 assert ctx.caller == owner.get(), 'Only the owner can change ownership!'
657
658 owner.set(new_owner)

Byte Code

e3000000000000000000000000350000004000000073f8030000640064016c005a01640064016c025a036504640264036404640564068d045a05650664016404640764088d035a07650664016404640964088d035a08650664016404640a64088d035a09650667006404640b64088d035a0a650667006404640c64088d035a0b650667006404640d64088d035a0c650d6404640e640f8d025a0e650d64046410640f8d025a0f64115a1064125a1164005a1264135a13641464156416641764186419641a641b641c641d641e641f6420642164226423642464256426642764286429642a642b642c642d642e642f6430643164326433643464356436643764386439643a643b643c643d643e643f6440644164426443644464456446644767345a1464486448644864486449644964496449644a644a644a644a644b644b644b644b644c644c644c644c644d644d644d644d644e644e644e644e644f644f644f644f6450645064506450645164516451645164526452645264526453645364536453641364136413641364549c345a1565166a17830001006455645684005a18651964048301651a64579c0164586459840483015a1b651a651c645a9c02645b645c84045a1d651a651a645d9c02645e645f84045a1e651a651a645a9c026460646184045a1f651964048301651a651a64629c0264636464840483015a20651964048301651a651a64659c0264666467840483015a21651964048301651a652264689c026469646a840483015a23651964048301651a652264689c02646b646c840483015a24651964048301651a6525646d9c02646e646f840483015a2665196404830164706471840083015a27651a652864729c026473647484045a29651a64759c016476647784045a2a65196404830164a9651a652865226525651a64799c05647a647b840583015a2b651964048301651a651a647c9c02647d647e840483015a2c651964048301651a647f9c0164806481840483015a2d651964048301651a652e651a64829c0364836484840483015a2f6528652e64859c026486648784045a30651964048301651a64889c016489648a840483015a31651964048301651a64889c01648b648c840483015a32652865286528651a651a648d9c05648e648f84045a33651964048301651a652264909c0264916492840483015a34651964048301651a651a651a64939c0364946495840483015a35651c6528652864969c036497649884045a36651a6528651c64999c03649a649b84045a37651964048301651a64889c01649c649d840483015a386519640483016522649e9c01649f64a0840483015a396519640483016528653a64a19c0264a264a3840483015a3b6519640483016528653a64a19c0264a464a5840483015a3c651964048301651a64a69c0164a764a8840483015a3d6401530029aae9000000004eda0e636f6e5f7068695f6c7374303031da0862616c616e636573da19636f6e5f706f6b65725f315f636172645f67616d65735f7633da0c7068695f62616c616e6365732904da10666f726569676e5f636f6e7472616374da0c666f726569676e5f6e616d65da08636f6e7472616374da046e616d65da0567616d65732903da0d64656661756c745f76616c756572080000007209000000da0568616e6473da0a67616d655f6e616d6573da0d706c61796572735f67616d6573da0f706c61796572735f696e7669746573da0d6d657373616765735f68617368da18706c617965725f6d657461646174615f636f6e7472616374290272080000007209000000da056f776e6572e93200000069ffe0f505e901000000da023263da023264da023268da023273da023363da023364da023368da023373da023463da023464da023468da023473da023563da023564da023568da023573da023663da023664da023668da023673da023763da023764da023768da023773da023863da023864da023868da023873da023963da023964da023968da023973da025463da025464da025468da025473da024a63da024a64da024a68da024a73da025163da025164da025168da025173da024b63da024b64da024b68da024b73da024163da024164da024168da024173e90d000000e90c000000e90b000000e90a000000e909000000e908000000e907000000e906000000e905000000e904000000e903000000e902000000293472150000007216000000721700000072180000007219000000721a000000721b000000721c000000721d000000721e000000721f0000007220000000722100000072220000007223000000722400000072250000007226000000722700000072280000007229000000722a000000722b000000722c000000722d000000722e000000722f0000007230000000723100000072320000007233000000723400000072350000007236000000723700000072380000007239000000723a000000723b000000723c000000723d000000723e000000723f000000724000000072410000007242000000724300000072440000007245000000724600000072470000007248000000630000000000000000000000000200000043000000731a00000074006a0174026a038301010074046a016401830101006400530029024eda18636f6e5f67616d6d615f7068695f70726f66696c655f76342905da075f5f6f776e6572da03736574da03637478da0663616c6c6572da1a5f5f706c617965725f6d657461646174615f636f6e7472616374a900725b000000725b000000da00da045f5f5f5f28000000730400000000010c01725d00000029017208000000630100000000000000010000000200000043000000732400000074006a0174026a0383006b027316740464018301820174056a067c00830101006400530029024e7a394f6e6c7920746865206f776e65722063616e2063616c6c207570646174655f706c617965725f6d657461646174615f636f6e747261637428292907725800000072590000007256000000da03676574da0e417373657274696f6e4572726f72725a000000725700000029017208000000725b000000725b000000725c000000da1f7570646174655f706c617965725f6d657461646174615f636f6e74726163742d000000730600000000021001060172600000002902da0767616d655f6964da0672657475726e630100000000000000020000000400000043000000732800000074007c006401660219007d017c0164006b097324740164027c009b0064039d03830182017c01530029044eda07706c61796572737a0547616d65207a1020646f6573206e6f742065786973742e2902da075f5f67616d6573725f000000290272610000007263000000725b000000725b000000725c000000da1f5f5f6765745f706c61796572735f616e645f6173736572745f65786973747334000000730600000000010c01180172650000002902da0763726561746f727262000000630100000000000000010000000500000043000000731800000074006a0164016a027c00740374048301670283018301530029024efa013a2905da07686173686c6962da0473686133da046a6f696eda03737472da036e6f7729017266000000725b000000725b000000725c000000da105f5f6372656174655f67616d655f69643a00000073020000000001726d000000630100000000000000010000000500000043000000731800000074006a0164016a027c00740374048301670283018301530029024e7267000000290572680000007269000000726a000000726b000000726c00000029017261000000725b000000725b000000725c000000da105f5f6372656174655f68616e645f69643e00000073020000000001726e00000029027261000000da076d657373616765630200000000000000050000000400000043000000734800000074006a017d0274027c0083017d037c027c036b06731e740364018301820174047c007c0266021900702c67007d047c046a057c01830101007c0474047c007c0266023c006400530029024e7a1f596f7520646f206e6f742062656c6f6e6720746f20746869732067616d652e2906725800000072590000007265000000725f000000da0f5f5f6d657373616765735f68617368da06617070656e6429057261000000726f000000da06706c617965727263000000da086d65737361676573725b000000725b000000725c000000da0c67616d655f6d65737361676542000000730c000000000206010801100110010a0172740000002902da0768616e645f6964726f000000630200000000000000050000000400000043000000734c00000074006a017d0274027c006401660219007d037c027c036b067322740364028301820174047c007c0266021900703067007d047c046a057c01830101007c0474047c007c0266023c006400530029034eda0e6163746976655f706c61796572737a1f596f7520646f206e6f742062656c6f6e6720746f20746869732068616e642e290672580000007259000000da075f5f68616e6473725f0000007270000000727100000029057275000000726f000000727200000072760000007273000000725b000000725b000000725c000000da0c68616e645f6d6573736167654c000000730c000000000206010c01100110010a01727800000029027261000000da06616d6f756e74630200000000000000040000000400000043000000737c00000074006a017d027c0164016b047316740264028301820174037c0083017d037c027c036b06732e740264038301820174047c007c026602190070407405640483017c01170074047c007c0266023c0074067c0274006a07660219007c016b057368740264058301820174086a097c0174006a077c02830301006400530029064e72010000007a20416d6f756e74206d757374206265206120706f736974697665206e756d6265727a1f596f7520646f206e6f742062656c6f6e6720746f20746869732067616d652e7a03302e307a35596f752068617665206e6f7420617070726f76656420656e6f75676820666f72207468697320616d6f756e74206f66206368697073290a72580000007259000000725f00000072650000007264000000da07646563696d616cda0e5f5f7068695f62616c616e636573da0474686973da03706869da0d7472616e736665725f66726f6d29047261000000727900000072720000007263000000725b000000725b000000725c000000da116164645f63686970735f746f5f67616d655600000073120000000002060110010801100112010e010c010e01727f000000630200000000000000050000000400000043000000736c00000074006a017d027c0164016b047316740264028301820174037c0083017d037c027c036b06732e740264038301820174047c007c02660219007d047c047c016b05734a74026404830182017c047c01180074047c007c0266023c0074056a067c017c0264058d0201006400530029064e72010000007a20416d6f756e74206d757374206265206120706f736974697665206e756d6265727a1f596f7520646f206e6f742062656c6f6e6720746f20746869732067616d652e7a27596f752063616e6e6f74207769746864726177206d6f7265207468616e20796f7520686176652e29027279000000da02746f290772580000007259000000725f00000072650000007264000000727d000000da087472616e7366657229057261000000727900000072720000007263000000da1263757272656e745f636869705f636f756e74725b000000725b000000725c000000da1877697468647261775f63686970735f66726f6d5f67616d65630000007310000000000206011001080110010c0110011001728300000029027261000000da06616363657074630200000000000000060000000400000043000000731401000074006a017d0274027c021900701067007d0374037c0083017d047c027c046b07732a740464018301820174057c04830174066b0073467404640274069b0064039d038301820174027c02640466021900705467007d057c007c036b06737a7c007c056b06737a74077c00640566021900737a74046406830182017c007c036b0672947c036a087c00830101007c0374027c023c007c0174027c027c0066023c007c0172f07c007c056b0672c27c056a087c00830101007c0574027c02640466023c007c046a097c02830101007c0474077c00640766023c00740a7c02190070e267007c0067011700740a7c023c006e207c007c056b07900172107c056a097c00830101007c0574027c02640466023c006400530029084e7a24596f752061726520616c726561647920612070617274206f6620746869732067616d652e7a054f6e6c79207a262061726520616c6c6f77656420746f20706c6179206174207468652073616d652074696d652eda086465636c696e6564da067075626c69637a27596f752068617665206e6f74206265656e20696e766974656420746f20746869732067616d652e7263000000290b72580000007259000000da115f5f706c61796572735f696e76697465737265000000725f000000da036c656eda0b4d41585f504c41594552537264000000da0672656d6f76657271000000da0f5f5f706c61796572735f67616d65732906726100000072840000007272000000da0e706c617965725f696e766974657372630000007285000000725b000000725b000000725c000000da11726573706f6e645f746f5f696e766974656f000000732e000000000206010c01080110010601160110011201120108010a0108010c01040108010a010c010a010c0118010a010a01728d000000630000000000000000030000000500000043000000733800000074006a017d0074027c001900701067007d0178187c0144005d107d02640174027c007c0266023c0071185700670074027c003c006400530029024e46290372580000007259000000728700000029037272000000da07696e7669746573da06696e76697465725b000000725b000000725c000000da136465636c696e655f616c6c5f696e76697465738a000000730a000000000206010c010a011001729000000029027261000000da066f74686572736302000000000000000400000004000000430000007330000000782a7c0144005d227d0274007c021900701467007d037c036a017c00830101007c0374007c023c00710657006400530029014e290272870000007271000000290472610000007291000000da056f74686572728c000000725b000000725b000000725c000000da165f5f73656e645f696e766974655f726571756573747393000000730800000000010a010c010a0172930000002901720900000063010000000000000001000000030000004300000073800000007c0064006b09721474007c00830164016b04731c740164028301820174027c0074038302732e740164038301820174007c00830164046b017342740164058301820174046406640784007c00440083018301735c74016408830182017c0064011900640d6b0772747c00640e1900640f6b07737c7401640c830182016400530029104e72010000007a2147616d65206e616d652063616e6e6f74206265206e756c6c206f7220656d7074797a1b47616d65206e616d65206d757374206265206120737472696e672ee9180000007a2e47616d65206e616d652063616e6e6f74206265206c6f6e676572207468616e20323420636861726163746572732e630100000000000000020000000500000053000000731c00000067007c005d147d017c016a00830070167c0164026b069102710453002903da015ffa012d2902729500000072960000002901da076973616c6e756d2902da022e30da0163725b000000725b000000725c000000fa0a3c6c697374636f6d703e9f000000730200000006007a285f5f76616c69646174655f67616d655f6e616d652e3c6c6f63616c733e2e3c6c697374636f6d703e7a6247616d65206e616d652068617320696e76616c696420636861726163746572732e204561636820636861726163746572206d75737420626520616c7068616e756d657269632c20612068797068656e2c206f7220616e20756e64657273636f72652e7296000000729500000072140000007a3a47616d65206e616d652063616e6e6f74207374617274206f7220656e64207769746820612068797068656e206f7220756e64657273636f72652e290272960000007295000000e9ffffffff29027296000000729500000029057288000000725f000000da0a6973696e7374616e6365726b000000da03616c6c29017209000000725b000000725b000000725c000000da145f5f76616c69646174655f67616d655f6e616d659a000000731000000000010e010e0112011401140106011a01729e0000004629057209000000da0d6f746865725f706c6179657273da04616e74657286000000726200000063040000000000000006000000040000004300000073fa00000074006a017d047c0264016b05731674026402830182017c047c016b077326740264038301820174037c01830174046b0073427402640474049b0064059d038301820174057c0464068d017d0574067c0564076602190064006b08736c740264087c059b0064099d038301820174077c008301010074087c00190064006b087390740264087c009b0064099d03830182017c0574087c003c007c04670174067c05640a66023c007c0274067c05640b66023c007c0474067c05640766023c007c0174067c05640c66023c007c0374067c05640d66023c0074097c04190070e067007c056701170074097c043c00740a7c057c01830201007c055300290e4e72010000007a1a416e7465206d757374206265206e6f6e2d6e656761746976652e7a2743616c6c65722063616e277420626520696e206f746865725f706c617965727320696e7075742e7a054f6e6c79207a262061726520616c6c6f77656420746f20706c6179206174207468652073616d652074696d652e2901726600000072660000007a0547616d65207a1a2068617320616c7265616479206265656e20637265617465642e726300000072a0000000da08696e7669746565737286000000290b72580000007259000000725f00000072880000007289000000726d0000007264000000729e000000da0c5f5f67616d655f6e616d6573728b000000729300000029067209000000729f00000072a0000000728600000072660000007261000000725b000000725b000000725c000000da0a73746172745f67616d65a500000073260000000003060110011001060116010a010a01160108011c0108010e010c010c010c010c0116010a0172a300000029027261000000da0d706c617965725f746f5f61646463020000000000000006000000040000004300000073a800000074006a017d027c027c016b037316740264018301820174037c006402660219007d037c027c036b027332740264038301820174047c0083017d047c017c046b07734a740264048301820174037c006405660219007d057c017c056b07736674026406830182017c056a057c018301010074067c04830174076b00738c7402640774079b0064089d03830182017c0574037c00640566023c0074087c007c016701830201006400530029094e7a22596f752063616e6e6f742061646420796f757273656c6620746f20612067616d652e72660000007a264f6e6c79207468652067616d652063726561746f722063616e2061646420706c61796572732e7a1e506c6179657220697320616c726561647920696e207468652067616d652e72a10000007a20506c617965722068617320616c7265616479206265656e20696e76697465642e7a054f6e6c79207a262061726520616c6c6f77656420746f20706c6179206174207468652073616d652074696d652e290972580000007259000000725f0000007264000000726500000072710000007288000000728900000072930000002906726100000072a400000072720000007266000000726300000072a1000000725b000000725b000000725c000000da126164645f706c617965725f746f5f67616d65bd000000731a0000000002060110010c011001080110010c0110010a01060116010c0172a5000000290172610000006301000000000000000a0000000500000043000000734201000074006a017d0174027c0083017d027c017c026b06731e740364018301820174047c007c01660219007d037c0364006b0873427c0364026b027342740364038301820174057c0119007d047c046a067c00830101007c0474057c013c007c026a067c01830101007c0274047c00640466023c0074047c006405660219007d057c0564006b099001723e74077c05640666021900709667007d067c017c066b069001723e74077c056407660219007d0774077c056408660219007d0874077c056409660219007d097c097c016b0272e874087c067c077c087c0183047d097c0974077c05640966023c007c066a067c01830101007c0674077c05640666023c007c017c076b069001721e7c076a067c01830101007c0774077c05640766023c007c017c086b069001723e7c086a067c01830101007c0874077c05640866023c0064005300290a4e7a19596f7520617265206e6f7420696e20746869732067616d652e72010000007a47596f75207374696c6c206861766520636869707320696e20746869732067616d652e20506c65617365207769746864726177207468656d206265666f7265206c656176696e672e7263000000da0c63757272656e745f68616e647276000000da06666f6c646564da06616c6c5f696eda0b6e6578745f6265747465722909725800000072590000007265000000725f0000007264000000728b000000728a0000007277000000da115f5f6765745f6e6578745f626574746572290a726100000072720000007263000000da056368697073da0c706c617965725f67616d65737275000000727600000072a700000072a800000072a9000000725b000000725b000000725c000000da0a6c656176655f67616d65ce000000733a00000000020601080110010c01180108010a0108010a010c010c010a0110010a010c010c010c010801060108010c010a010c010a010a010c010a010a0172ad00000029037261000000da0967616d655f747970657262000000630200000000000000060000000400000043000000730201000074006a017d027c0174026b02731e7c0174036b02731e740464018301820174057c0083017d037c027c036b067336740464028301820174067c03830164036b04734a740464048301820174077c006405660219007d047c0464006b09727274087c046406660219007372740464078301820174097c0083017d057c0574077c00640566023c007c0074087c05640866023c007c0174087c05640966023c007c0274087c05640a66023c00670074087c05640b66023c00640c74087c05640d66023c00640c74087c05640666023c00640c74087c05640e66023c00670074087c05640f66023c00641074087c05641166023c00670074087c05641266023c007c05530029134e7a12496e76616c69642067616d6520747970652e7a20596f7520617265206e6f7420612070617274206f6620746869732067616d652e72140000007a24596f752063616e6e6f7420737461727420612068616e6420627920796f757273656c662e72a6000000da0970617965645f6f75747a2d5468652070726576696f75732068616e6420686173206e6f74206265656e207061796564206f7574207965742e726100000072ae000000da066465616c657272a700000046da09636f6d706c65746564da0e726561636865645f6465616c657272760000007201000000da0b63757272656e745f62657472a8000000290a72580000007259000000da0e4f4e455f434152445f504f4b4552da0b424c494e445f504f4b4552725f0000007265000000728800000072640000007277000000726d0000002906726100000072ae00000072b00000007263000000da1070726576696f75735f68616e645f69647275000000725b000000725b000000725c000000da0a73746172745f68616e64ef000000732c0000000002060118010801100114010c0108010e01060108010c010c010c010c010c010c010c010c010c010c010c0172b70000002902726300000072620000006301000000000000000200000003000000030000007310000000870066016401640284087d017c01530029034e630100000000000000010000000200000013000000730a00000088006a007c008301530029014e2901da05696e6465782901727200000029017263000000725b000000725c000000da065f5f736f72740b010000730200000000017a245f5f6163746976655f706c617965725f736f72742e3c6c6f63616c733e2e5f5f736f7274725b0000002902726300000072b9000000725b00000029017263000000725c000000da145f5f6163746976655f706c617965725f736f727409010000730400000000020c0272ba00000029017275000000630100000000000000080000000500000043000000731c01000074006a017d0174027c006401660219007d027c0264006b097322740364028301820174047c0283017d037c017c036b06733a740364038301820174057c026404660219007d0474057c027c01660219007d057c0564006b0972627c057c046b05736a740364058301820174027c00640666021900707867007d067c017c066b07738a74036407830182017c0474027c007c01640866033c007c0574027c007c01640966033c0074057c027c016602050019007c04380003003c007c066a067c01830101007c066a0774087c038301640a8d0101007c0674027c00640666023c007c0474027c00640b66023c007c057c046b029001721874027c00640c660219007d077c076a067c01830101007c0774027c00640c66023c0064005300290d4e72610000007a19546869732067616d6520646f6573206e6f742065786973742e7a20596f7520617265206e6f7420612070617274206f6620746869732067616d652e72a00000007a1d596f7520646f206e6f74206861766520656e6f7567682063686970732e72760000007a1f596f75206861766520616c726561647920706169642074686520616e74652eda03626574da076d61785f6265742901da036b657972b300000072a80000002909725800000072590000007277000000725f000000726500000072640000007271000000da04736f727472ba0000002908727500000072720000007261000000726300000072a000000072ab000000727600000072a8000000725b000000725b000000725c000000da07616e74655f757010010000732a000000000206010c011001080110010c010c011801100110010e010e0114010a0110010c010c010a010c010a0172bf000000630100000000000000120000000700000043000000731a02000074006a017d0174027c006401660219007d027c0174027c006402660219006b02732a740364038301820174047c02830164046b04734a7403640574047c0283019b0064069d03830182017c017c026b06735a740364078301820174027c006408660219007d03740574066a0783006409640a640b640c8d047d0474087d0574096a0a7c058301010090017840740b74047c0283018301440090015d2e7d067c027c0619007d077c047c07640d660219007d087c0864006b0973ca7403640e7c079b00640f9d03830182017c086a0c641083017d0974047c09830164116b0273e874036412830182017c03740d6b02900172047c057c067c0664041700850219007d0a6e567c0564137c06850219007c057c066404170074047c0283018502190017007d0a74047c0a830174047c028301640418006b029001735a7403641474047c0a83019b00641574047c028301640418009b009d048301820164166a0e7c0a83017d0b740f74096a1064137411830283017d0c7c0b9b0064177c0c9b009d037d0d74126a137c0d74147c0964131900830174147c0964041900830164188d037d0e74156a167c0d83017d0f7c0e74027c007c07641966033c007c0f74027c007c07641a66033c007198570074027c00641b660219007d1074177c0267007c107c01830474027c00641c66023c00741874027c00641d66021900641e660219007d117c1174047c028301140074027c00641f66023c006400530029204e727600000072b00000007a17596f7520617265206e6f7420746865206465616c65722e72140000007a1b4e6f7420656e6f7567682061637469766520706c61796572733a207a05203c3d20317a27596f7520617265206e6f74206163746976656c792070617274206f6620746869732068616e642e72ae000000da086d657461646174617204000000da0f706c617965725f6d6574616461746129047206000000720700000072080000007209000000da0e7075626c69635f7273615f6b65797a07506c61796572207a2520686173206e6f7420736574757020746865697220656e6372797074696f6e206b6579732efa017c72540000007a0c496e76616c6964206b65797372010000007a16536f6d657468696e672077656e742077726f6e672e207a0420213d20fa012c72670000002903da0b6d6573736167655f737472da016eda0165da15706c617965725f656e637279707465645f68616e64da14686f7573655f656e637279707465645f68616e6472a800000072a9000000726100000072a0000000da03706f742919725800000072590000007277000000725f0000007288000000da0b466f726569676e48617368725a000000725e000000da044445434bda0672616e646f6dda0773687566666c65da0572616e6765da0573706c697472b4000000726a000000726b000000da0772616e64696e74da114d41585f52414e444f4d5f4e554d424552da03727361da07656e6372797074da03696e747268000000726900000072aa00000072640000002912727500000072b0000000727600000072ae000000da115f5f706c617965725f6d65746164617461da056361726473da01697272000000da0a706c617965725f6b6579da046b657973da0b706c617965725f68616e64da0f706c617965725f68616e645f737472da0473616c74da19706c617965725f68616e645f7374725f776974685f73616c7472c800000072c900000072a800000072a0000000725b000000725b000000725c000000da0a6465616c5f6361726473290100007348000000000206010c01180106011a0110010c01020108010a0104010a01160108010c0118010a0114010a01120220010c012a010a0110010e0104011c010a020e0112010c0106011001140172df0000002905726300000072a700000072a8000000da0e63757272656e745f6265747465727262000000630400000000000000060000000400000003000000736e00000074008801830174007c008301640118006b0572186400530074007c0083017400880083016b02722c640053008700870166026402640384087c00440083017d047c046a017c0383017d057c0564046b05735a74026405830182017c047c056401170074007c04830116001900530029064e7214000000630100000000000000020000000400000013000000732000000067007c005d187d017c0188016b0772047c0188006b0772047c01910271045300725b000000725b00000029027298000000da0170290272a800000072a7000000725b000000725c000000729a00000059010000730400000006000c017a255f5f6765745f6e6578745f6265747465722e3c6c6f63616c733e2e3c6c697374636f6d703e72010000007a3543757272656e74206265747465722068617320666f6c6465642c20776869636820646f6573206e6f74206d616b652073656e73652e2903728800000072b8000000725f0000002906726300000072a700000072a800000072e0000000da126e6f6e5f666f6c6465645f706c6179657273da0d63757272656e745f696e646578725b000000290272a800000072a7000000725c00000072aa0000005301000073100000000002140104011001040114020a01100172aa0000002902727500000072bb0000006302000000000000000f000000050000004300000073c202000074006a017d0274027c007c0264016603190064006b097320740364028301820174027c006403660219000c007336740364048301820174027c006405660219007c026b02734e740364068301820174027c006407660219007d0374027c006408660219007d0474027c0064096602190070787404640a83017d0574027c007c02640b66031900708e7404640a83017d0674027c00640c660219007d077c077c026b0272b6640d74027c00640e66023c00640d7d086e0c74027c00640e660219007d0874027c00640f660219007d0974057c037c047c097c0283047d0a7c0a64006b0872f4640d74027c00640366023c0090016ebe7c0164106b009001725a7c046a067c02830101007c0474027c00640866023c007c027c096b06900172347c096a077c02830101007c0974027c00640f66023c0074087c04830174087c038301641118006b02900272b2640d74027c00640366023c0090016e587c0164106b02900172ee74027c007c026412660319007d0b7c0b7c066b029001729c7c027c096b079001729c7c096a067c02830101007c0974027c00640f66023c007c0b7c066b02900173b87c067c056b05900173b8740364138301820174027c007c0a640b660319007d0c7c0c64006b09900272b27c0c7c056b02900272b27c08900272b2640d74027c00640366023c006ec474027c006414660219007d0d74097c0d7c02660219007c016b059002731474036415830182017c067c0117007d0e74027c007c026412660319007d0b7c0b7c0e6b02900272547c027c096b07900272547c096a067c02830101007c0974027c00640f66023c007c0b7c0e6b02900273707c0e7c056b059002737074036416830182017c0e74027c007c02640b66033c007c0e74027c00640966023c0074027c0064176602050019007c01370003003c0074097c0d7c026602050019007c01380003003c007c0a74027c00640566023c006400530029184e72c80000007a1348616e6420646f6573206e6f7420657869737472b10000007a20546869732068616e642068617320616c726561647920636f6d706c657465642e72a90000007a1b4974206973206e6f7420796f7572207475726e20746f206265742e727600000072a700000072b30000007a03302e3072bb00000072b00000005472b200000072a80000007201000000721400000072bc0000007a5443616e6e6f7420636865636b20696e2074686973207363656e6172696f2e2043757272656e74206265742069732061626f766520796f75722062657420616e6420796f7520617265206e6f7420616c6c20696e2e72610000007a2d596f7520646f206e6f74206861766520656e6f75676820636869707320746f206d616b652074686973206265747a3843757272656e74206265742069732061626f766520796f75722062657420616e6420796f7520646964206e6f7420676f20616c6c20696e2e72ca000000290a725800000072590000007277000000725f000000727a00000072aa0000007271000000728a00000072880000007264000000290f727500000072bb0000007272000000727600000072a7000000da0863616c6c5f626574da13706c617965725f70726576696f75735f62657472b000000072b200000072a800000072a900000072bc000000da106e6578745f706c61796572735f626574726100000072b3000000725b000000725b000000725c000000da116265745f636865636b5f6f725f666f6c64600100007368000000000206010c010e01100106010a010e010c010c01140116010c0108010c0106020c010c010e01080110010a010a010c010a010a010c01160110010a010e0114010a010c011c010e01140106010e020c010a01100108010e0114010a010c011c010e010c011401140172e70000002903727500000072dc0000007262000000630200000000000000100000000600000043000000739a01000074006a017d0274027c00640166021900731a740364028301820174027c006403660219007d037c027c036b077336740364048301820174027c006405660219007d047c027c046b067352740364068301820174027c006407660219007d057c0564006b09736e740364088301820174027c007c026409660319007d067c0664006b09738c7403640a830182017c057c066b02739c7403640b8301820174046a057c0183017d0774027c007c02640c660319007d087c0864006b096fc27c087c076b027d097c0973e27c036a067c02830101007c0374027c00640366023c00640d53007c016a07640e8301640f19006a07641083017d0a74027c006411660219007d0b7c0b74086b029001723674097c0a640f190019007d0c7c0c74027c007c02641266033c007c0a74027c007c02641366033c006e5c640f7d0d78567c0444005d4e7d0e7c0e7c026b03900172407c0e7c036b07900172847c0a7c0d19007d0f74097c0f19007d0c7c0c74027c007c0e641266033c007c0f74027c007c0e641366033c007c0d641437007d0d900171405700641553006400530029164e72b10000007a20546869732068616e6420686173206e6f7420636f6d706c65746564207965742e72a70000007a2f4e6f206e65656420746f2076657269667920796f75722068616e64206265636175736520796f7520666f6c6465642e72760000007a2a596f7520617265206e6f7420616e2061637469766520706c6179657220696e20746869732068616e642e72b30000007a185468657265206973206e6f2063757272656e74206265742e72bb0000007a15596f752068617665206e6f7420626574207965742e7a19426574732068617665206e6f742073746162696c697a65642e72c90000007a32566572696669636174696f6e206661696c65642e20596f75722068616e6420686173206265656e20666f726665697465642e7267000000720100000072c400000072ae000000da0472616e6bda0468616e6472140000007a17566572696669636174696f6e207375636365656465642e290a725800000072590000007277000000725f00000072680000007269000000727100000072d000000072b4000000da0552414e4b532910727500000072dc000000727200000072a70000007276000000da106265745f73686f756c645f657175616cda0a706c617965725f62657472c9000000da1d70726576696f75735f686f7573655f656e637279707465645f68616e64da08766572696669656472d700000072ae00000072e8000000da016a72e1000000da0463617264725b000000725b000000725c000000da0b7665726966795f68616e649a01000073480000000002060114010c0110010c0110010c0110010e01100110010a01060108010801080104010a010c01040214010c010a010c010e01100204010a010a010a01080108010e010e010e0172f10000002903da0572616e6b7372630000007262000000630200000000000000080000000400000043000000735200000074007c006a01830083017d0274027c0183017d0378387c0244005d307d047c007c0419007d057c036a0374027c05830183017d0674047c06830164016b04721a74057c0683017d075000711a57007c07530029024e72010000002906da06736f7274656472da0000007257000000da0c696e74657273656374696f6e7288000000da046c697374290872f20000007263000000da12736f727465645f72616e6b5f76616c756573da0a706c617965725f73657472e8000000da11706c61796572735f776974685f72616e6b72f4000000da0777696e6e657273725b000000725b000000725c000000da0e5f5f66696e645f77696e6e657273c4010000731200000000010c0108010a0108010e010c010801060172fa0000002903727500000072630000007262000000630200000000000000050000000500000043000000735a00000069007d0278507c0144005d487d0374007c007c036401660319007d047c0464006b097334740164027c039b0064039d03830182017c047c026b07724467007c027c043c007c027c0419006a027c0383010100710a57007c02530029044e72e80000007a07506c61796572207a2120686173206e6f742076657269666965642074686569722068616e64207965742e29037277000000725f000000727100000029057275000000726300000072f200000072e100000072e8000000725b000000725b000000725c000000da115f5f63616c63756c6174655f72616e6b73d00100007310000000000104010a010e01180108010801120172fb00000063010000000000000016000000070000000300000073bc02000074007c006401660219007d017c0164026b04731c740164038301820174007c006404660219000c007332740164058301820174007c00640666021900890074007c006407660219007d0274007c006408660219007d03870066016409640a84087c03440083017d0474027c04830164026b04737c7401640b8301820169007d0574027c048301640c6b02729c7c017c057c04640219003c0090016ec474037c007c0483027d0674027c02830164026b049002723269007d0778227c0244005d1a7d0874007c007c08640d660319007d097c097c077c083c0071be5700740474057c076a068300830183017d0a64027d0b789e7c0a44005d967d0c67007d0d788c7c0444005d847d087c087c076b07900173207c077c0819007c0c6b05900172047c0d6a077c088301010074087c067c0d83027d0e7c0c74027c0d830114007d0f7c0b7c0f37007d0b7c0f74027c0e83011b007d1078307c0e44005d287d117c117c056b079001727064027c057c113c007c057c11050019007c10370003003c009001715a570090017104570071f657007c017c0b18007d1274057c0483016a0974057c02830183017d137c1264026b02900173ca74027c13830164026b04900173ca7401640e830182017c1264026b049002726074027c138301640c6b02900172e87c137d146e0a74087c067c1383027d147c1274027c1483011b007d1078607c1444005d287d117c117c056b079002721a64027c057c113c007c057c11050019007c10370003003c009002710457006e2e74087c067c0483027d147c0174027c1483011b007d1078167c1444005d0e7d117c107c057c113c009002714e570074007c00640f660219007d15782a7c056a0a830044005d1e5c027d087d10740b7c157c086602050019007c10370003003c00900271765700740c7c056a0d8300830174007c00641066023c00641174007c00640466023c006400530029124e72ca00000072010000007a195468657265206973206e6f20706f7420746f20636c61696d2172af0000007a25546869732068616e642068617320616c7265616479206265656e207061796564206f75742e72a700000072a80000007276000000630100000000000000020000000400000013000000731800000067007c005d107d017c0188006b0772047c01910271045300725b000000725b0000002902729800000072e1000000290172a7000000725b000000725c000000729a000000e4010000730200000006007a1f7061796f75745f68616e642e3c6c6f63616c733e2e3c6c697374636f6d703e7a1f546865726520617265206e6f2072656d61696e696e6720706c61796572732e721400000072bc0000007a29496e76616c6964207374617465207768656e2063616c63756c6174696e67207369646520706f74732e726100000072f900000054290e7277000000725f000000728800000072fb00000072f30000007257000000da0676616c756573727100000072fa000000da0a646966666572656e6365da056974656d73726400000072f500000072da0000002916727500000072ca00000072a80000007276000000da0972656d61696e696e67da077061796f75747372f2000000da0a616c6c5f696e5f6d617072720000007279000000da04706f7473da0f746f74616c5f70617965645f6f757472bb000000da0e706c61796572735f696e5f706f74da0b706f745f77696e6e657273da0a706f745f7061796f7574da067061796f7574da0677696e6e6572da1372656d61696e696e675f746f5f7061796f7574da0a6e6f745f616c6c5f696e72f90000007261000000725b000000290172a7000000725c000000da0b7061796f75745f68616e64db010000736e00000000020c011001100106010c010c010c011201140104010c0110020a010e0104010a010e010c01100104010a0104010a0118010a010a010c0108010c010a010a010801200108011201100110010a010e0106020a010c010a010a01080118020a010c010a010e010c0112011a011401720b01000029017279000000630100000000000000010000000400000043000000732a00000074006a0174026a0383006b027316740464018301820174056a067c0074006a0164028d0201006400530029034e7a2c4f6e6c7920746865206f776e65722063616e2063616c6c20656d657267656e63795f776974686472617728292902727900000072800000002907725800000072590000007256000000725e000000725f000000727d000000728100000029017279000000725b000000725b000000725c000000da12656d657267656e63795f7769746864726177190200007306000000000210010601720c010000290272da000000da0576616c756563020000000000000002000000070000004300000073aa00000074006a0174026a0383006b027316740464018301820174057c00830164026b0272307c0174067c00640319003c006e7674057c00830164046b0272527c0174067c00640319007c006402190066023c006e5474057c00830164056b02727a7c0174067c00640319007c00640219007c006404190066033c006e2c74057c00830164066b0272a67c0174067c00640319007c00640219007c00640419007c006405190066043c006400530029074e7a2f4f6e6c7920746865206f776e65722063616e2063616c6c20656d657267656e63795f67616d655f7570646174652829721400000072010000007254000000725300000072520000002907725800000072590000007256000000725e000000725f00000072880000007264000000290272da000000720d010000725b000000725b000000725c000000da15656d657267656e63795f67616d655f7570646174652002000073140000000002100106010c010e010c0116010c011c010c01720e01000063020000000000000002000000070000004300000073aa00000074006a0174026a0383006b027316740464018301820174057c00830164026b0272307c0174067c00640319003c006e7674057c00830164046b0272527c0174067c00640319007c006402190066023c006e5474057c00830164056b02727a7c0174067c00640319007c00640219007c006404190066033c006e2c74057c00830164066b0272a67c0174067c00640319007c00640219007c00640419007c006405190066043c006400530029074e7a2f4f6e6c7920746865206f776e65722063616e2063616c6c20656d657267656e63795f68616e645f7570646174652829721400000072010000007254000000725300000072520000002907725800000072590000007256000000725e000000725f00000072880000007277000000290272da000000720d010000725b000000725b000000725c000000da15656d657267656e63795f68616e645f7570646174652e02000073140000000002100106010c010e010c0116010c011c010c01720f0100002901da096e65775f6f776e6572630100000000000000010000000200000043000000732400000074006a0174026a0383006b027316740464018301820174026a057c00830101006400530029024e7a244f6e6c7920746865206f776e65722063616e206368616e6765206f776e657273686970212906725800000072590000007256000000725e000000725f000000725700000029017210010000725b000000725b000000725c000000da106368616e67655f6f776e6572736869703c0200007304000000000216017211010000290146293eda12636f6e5f7273615f656e6372797074696f6e72d30000007202000000727d00000072cb000000727b000000da04486173687264000000727700000072a2000000728b00000072870000007270000000da085661726961626c65725a0000007256000000728900000072d200000072b400000072b500000072cc00000072ea00000072cd000000da0473656564725d000000da085f5f6578706f7274726b0000007260000000da04646963747265000000726d000000726e00000072740000007278000000da05666c6f6174727f0000007283000000da04626f6f6c728d000000729000000072f50000007293000000729e00000072a300000072a500000072ad00000072d500000072b700000072ba00000072bf00000072df00000072aa00000072e700000072f100000072fa00000072fb000000720b010000720c010000da03416e79720e010000720f0100007211010000725b000000725b000000725b000000725c000000da083c6d6f64756c653e0100000073ae00000008010801040104010801060108010601080104010a0104010a0104010a0104010a01040108010c01040104010401040116011801180118010e010c010e0110011001100110011401080308050601100610061004100406011209060112090601120c0601120b0601121a100910070e0b06010a011016060112100601102006011419100706011018060110290601100c0601123906011429120c120b0601103d060110060601120d0601120d0601