Contract con_game_manager_impl_v1
Creator | ae9cfa894495930b8d2f1707ab936325b5c848ace677bb8ba41dfe7dcdb3e3e6 |
Creation Hash | 46d1f9195ae01a46ea068680a76022e79462b3e8e0c883331c830827dbd8eb69 |
Created On | 841 days ago - 12/29/2021, 8:45:06 PM UTC+0 |
Contract Code
1
# con_game_manager_impl_v1
2
# owner: con_game_manager_v1
3
4
I = importlib
5
6
CONTRACT_FOR_GAME_TYPE = Variable()
7
8
9
@construct
10
def init():
11
CONTRACT_FOR_GAME_TYPE.set({
12
'checkers': 'con_checkers_v1',
13
'chess': 'con_chess_v1',
14
'go': 'con_go_v1',
15
})
16
17
18
def reset_game_state(state: dict, initial_state: dict):
19
creator_team = state['creator_team']
20
opponent_team = state['opponent_team']
21
22
state.clear()
23
24
state['current_player'] = initial_state['current_player']
25
state['board'] = initial_state['board']
26
# Swap teams
27
state['creator_team'] = opponent_team
28
state['opponent_team'] = creator_team
29
30
31
def play_again(state: dict, initial_state: dict):
32
assert state.get('completed') is not None and state['completed'], 'Game has not completed yet.'
33
reset_game_state(state, initial_state)
34
35
36
def next_round(state: dict, initial_state: dict):
37
assert state.get('winner') is not None or state.get('stalemate'), 'Previous round has not completed yet.'
38
assert state.get('completed') is None or not state['completed'], 'Rounds have completed. Please play again.'
39
creator_paid = state.get('creator_paid')
40
opponent_paid = state.get('opponent_paid')
41
creator_wins = state.get('creator_wins')
42
opponent_wins = state.get('opponent_wins')
43
reset_game_state(state, initial_state)
44
if creator_paid is not None:
45
state['creator_paid'] = creator_paid
46
if opponent_paid is not None:
47
state['opponent_paid'] = opponent_paid
48
if creator_wins is not None:
49
state['creator_wins'] = creator_wins
50
if opponent_wins is not None:
51
state['opponent_wins'] = opponent_wins
52
53
54
def create_game(payload: dict, caller: str, metadata: Any) -> str:
55
other_player = payload.get('other_player')
56
public = payload.get('public', False)
57
creator_first = payload.get('creator_first', True)
58
wager = payload.get('wager', 0)
59
rounds = payload.get('rounds', 1)
60
game_type = payload.get('type')
61
game_name = payload.get('game_name', payload.get('name'))
62
63
contract_for_game_type = CONTRACT_FOR_GAME_TYPE.get()
64
65
assert game_type in contract_for_game_type, 'Invalid game type.'
66
67
initial_state = I.import_module(contract_for_game_type[game_type]).get_initial_state()
68
69
assert public or other_player is not None, 'No opponent specified in private game.'
70
assert not (public and other_player is not None), 'Opponent specified in public game.'
71
assert isinstance(wager, int) or isinstance(wager, float), 'Wager must be numeric.'
72
assert wager >= 0, 'Wager cannot be negative.'
73
assert isinstance(rounds, int), 'Rounds must be an integer.'
74
assert rounds >= 1, 'Rounds must be >= 1.'
75
76
game_state = initial_state.copy()
77
78
if not creator_first:
79
tmp = game_state['opponent_team']
80
game_state['opponent_team'] = game_state['creator_team']
81
game_state['creator_team'] = tmp
82
83
game_metadata = {}
84
85
game_id = hashlib.sha3(caller+str(now))
86
87
assert metadata[game_type, game_id, 'state'] is None, 'Game already exists.'
88
89
game_metadata['creator'] = caller
90
game_metadata['public'] = public
91
game_metadata['rounds'] = rounds
92
if game_name is not None:
93
game_metadata['name'] = game_name
94
95
if wager > 0:
96
I.import_module(ctx.owner).force_deposit(
97
amount=wager,
98
main_account=caller,
99
)
100
game_metadata['wager'] = wager
101
102
game_state['creator_paid'] = True
103
104
add_game_for_user(caller, game_type, game_id, metadata)
105
106
if other_player is not None:
107
game_metadata['opponent'] = other_player
108
add_game_for_user(other_player, game_type, game_id, metadata)
109
else:
110
# Public
111
public_games = metadata[game_type, 'public'] or []
112
public_games.append(game_id)
113
metadata[game_type, 'public'] = public_games
114
115
# Update state
116
set_game_state(metadata, game_type, game_id, game_state)
117
set_game_metadata(metadata, game_type, game_id, game_metadata)
118
119
# Return game_id
120
return game_id
121
122
123
def add_game_for_user(player: str, game_type: str, game_id: str, metadata: Any):
124
num_games = metadata[game_type, player, 'count'] or 0
125
num_games += 1
126
metadata[game_type, player, 'count'] = num_games
127
metadata[game_type, player, f'game-{num_games}'] = game_id
128
129
130
def store_historical_state(state: dict, game_type: str, game_id: str, metadata: Any):
131
history_count = metadata[game_type, game_id, 'history-count'] or 0
132
history_count += 1
133
metadata[game_type, game_id, 'history', history_count] = state
134
metadata[game_type, game_id, 'history-count'] = history_count
135
136
137
def get_game_state(metadata: Any, game_type: str, game_id: str) -> dict:
138
game_state = metadata[game_type, game_id, 'state']
139
assert game_state is not None, 'Game does not exist.'
140
return game_state
141
142
143
def set_game_state(metadata: Any, game_type: str, game_id: str, state: dict):
144
metadata[game_type, game_id, 'state'] = state
145
146
147
def get_game_metadata(metadata: Any, game_type: str, game_id: str) -> dict:
148
game_state = metadata[game_type, game_id, 'metadata']
149
assert game_state is not None, 'Game does not exist.'
150
return game_state
151
152
153
def set_game_metadata(metadata: Any, game_type: str, game_id: str, state: dict):
154
metadata[game_type, game_id, 'metadata'] = state
155
156
157
def assert_in_game(caller: str, game_metadata: dict):
158
assert game_metadata['creator'] == caller or game_metadata['opponent'] == caller, 'You are not in this game.'
159
160
161
def assert_both_parties_paid(game_state: dict):
162
assert 'creator_paid' in game_state and game_state['creator_paid'], 'Creator has not paid yet.'
163
assert 'opponent_paid' in game_state and game_state['opponent_paid'], 'Opponent has not paid.'
164
165
166
def assert_round_not_completed(game_state: dict):
167
assert game_state.get('winner') is None and game_state.get('stalemate') is None, 'This round has already completed.'
168
169
170
def assert_round_completed(game_state: dict):
171
assert game_state.get('winner') is not None or game_state.get('stalemate'), 'This round has not yet completed.'
172
173
174
def handle_round_end(game_state: dict, game_metadata: dict):
175
if game_state.get('stalemate'):
176
return
177
winner = game_state['winner']
178
wager = game_metadata.get('wager', 0)
179
creator_team = game_state['creator_team']
180
if creator_team == winner:
181
winner_address = game_metadata['creator']
182
game_state['creator_wins'] = game_state.get('creator_wins', 0) + 1
183
else:
184
winner_address = game_metadata['opponent']
185
game_state['opponent_wins'] = game_state.get('opponent_wins', 0) + 1
186
rounds = game_metadata.get('rounds', 1)
187
creator_wins = game_state.get('creator_wins', 0)
188
opponent_wins = game_state.get('opponent_wins', 0)
189
if creator_wins > rounds // 2 or opponent_wins > rounds // 2:
190
game_state['completed'] = True
191
if wager > 0:
192
amount_to_pay = 0.0
193
if game_state.get('opponent_paid'):
194
amount_to_pay += wager
195
if game_state.get('creator_paid'):
196
amount_to_pay += wager
197
if amount_to_pay > 0:
198
I.import_module(ctx.owner).force_withdraw(
199
player=winner_address,
200
amount=amount_to_pay
201
)
202
203
@export
204
def interact(payload: dict, state: dict, caller: str) -> Any:
205
metadata = state['metadata']
206
owner = state['owner']
207
action = payload['action']
208
209
if action == 'create':
210
return create_game(payload, caller, metadata)
211
elif action == 'update_contracts':
212
assert caller == owner.get(), 'Only the owner can call update_contracts.'
213
CONTRACT_FOR_GAME_TYPE.set(payload['contracts'])
214
else:
215
game_id = payload['game_id']
216
game_type = payload['type']
217
game_state = get_game_state(metadata, game_type, game_id)
218
game_metadata = get_game_metadata(metadata, game_type, game_id)
219
is_creator = game_metadata['creator'] == caller
220
contract_for_game_type = CONTRACT_FOR_GAME_TYPE.get()
221
222
if action != 'join':
223
assert_in_game(caller, game_metadata)
224
225
assert game_type in contract_for_game_type, 'Invalid game type.'
226
227
if action == 'pay_up':
228
wager = game_metadata.get('wager', 0)
229
assert wager > 0, 'No need to pay up.'
230
I.import_module(ctx.owner).force_deposit(
231
amount=wager,
232
main_account=caller,
233
)
234
if is_creator:
235
assert not game_state.get('creator_paid'), 'Already paid.'
236
game_state['creator_paid'] = True
237
else:
238
assert not game_state.get('opponent_paid'), 'Already paid.'
239
game_state['opponent_paid'] = True
240
241
elif action == 'forfeit_round':
242
assert_round_not_completed(game_state)
243
assert_both_parties_paid(game_state)
244
if is_creator:
245
winner = game_state['opponent_team']
246
else:
247
winner = game_state['creator_team']
248
game_state['winner'] = winner
249
handle_round_end(game_state, game_metadata)
250
251
elif action == 'request_end':
252
assert_round_not_completed(game_state)
253
assert_both_parties_paid(game_state)
254
assert game_state.get('creator_requested_end') is None and game_state.get('opponent_requested_end') is None, 'End request has already been submitted.'
255
if is_creator:
256
game_state['creator_requested_end'] = True
257
else:
258
game_state['opponent_requested_end'] = True
259
260
elif action == 'accept_end':
261
assert_round_not_completed(game_state)
262
assert_both_parties_paid(game_state)
263
assert game_state.get('creator_accepted_end') is None and game_state.get('opponent_accepted_end') is None, 'End request has already been accepted.'
264
if is_creator:
265
assert game_state['opponent_requested_end'], 'Opponent did not request an end to this round.'
266
game_state['creator_accepted_end'] = True
267
else:
268
assert game_state['creator_requested_end'], 'Creator did not request an end to this round.'
269
game_state['opponent_accepted_end'] = True
270
contract = I.import_module(contract_for_game_type[game_type])
271
contract.force_end_round(game_state, game_metadata)
272
handle_round_end(game_state, game_metadata)
273
274
elif action == 'early_end':
275
if is_creator:
276
# Assert creator paid and opponent did not
277
assert 'creator_paid' in game_state and game_state['creator_paid'], 'You did not pay yet.'
278
assert 'opponent_paid' not in game_state or not game_state['opponent_paid'], 'Opponent has already paid.'
279
del game_state['creator_paid']
280
else:
281
assert 'opponent_paid' in game_state and game_state['opponent_paid'], 'You did not pay yet.'
282
assert 'creator_paid' not in game_state or not game_state['creator_paid'], 'Opponent has already paid.'
283
del game_state['opponent_paid']
284
285
contract = I.import_module(contract_for_game_type[game_type])
286
contract.force_end_round(game_state, game_metadata)
287
wager = game_state.get('wager', 0)
288
if wager > 0:
289
I.import_module(ctx.owner).force_withdraw(
290
player=caller,
291
amount=wager
292
)
293
294
elif action == 'enforce_time_limit':
295
# TODO implement this guy
296
pass
297
298
elif action == 'next_round':
299
store_historical_state(game_state, game_type, game_id, metadata)
300
initial_state = I.import_module(contract_for_game_type[game_type]).get_initial_state()
301
next_round(game_state, initial_state)
302
303
elif action == 'play_again':
304
store_historical_state(game_state, game_type, game_id, metadata)
305
initial_state = I.import_module(contract_for_game_type[game_type]).get_initial_state()
306
play_again(game_state, initial_state)
307
wager = game_metadata.get('wager', 0)
308
if wager > 0:
309
I.import_module(ctx.owner).force_deposit(
310
amount=wager,
311
main_account=caller,
312
)
313
if is_creator:
314
game_state['creator_paid'] = True
315
else:
316
game_state['opponent_paid'] = True
317
else:
318
game_state['opponent_paid'] = True
319
game_state['creator_paid'] = True
320
321
elif action == 'join':
322
public = game_metadata['public']
323
opponent = game_metadata.get('opponent')
324
if public:
325
assert opponent is None, 'There is already an opponent.'
326
else:
327
assert opponent == caller, 'You were not invited.'
328
assert caller != game_metadata['creator'], 'You are the creator of this game.'
329
game_metadata['opponent'] = caller
330
wager = game_metadata.get('wager', 0)
331
if wager > 0:
332
I.import_module(ctx.owner).force_deposit(
333
amount=wager,
334
main_account=caller,
335
)
336
game_state['opponent_paid'] = True
337
if public:
338
add_game_for_user(caller, game_type, game_id, metadata)
339
set_game_metadata(metadata, game_type, game_id, game_metadata)
340
341
elif action == 'move':
342
assert_round_not_completed(game_state)
343
if is_creator:
344
team = game_state['creator_team']
345
assert game_state['creator_paid'], 'You have not paid yet.'
346
else:
347
team = game_state['opponent_team']
348
assert game_state.get('opponent_paid'), 'You have not paid yet.'
349
I.import_module(contract_for_game_type[game_type]).move(
350
caller=caller,
351
team=team,
352
payload=payload,
353
state=game_state,
354
metadata=game_metadata,
355
)
356
if game_state.get('winner') is not None:
357
assert_both_parties_paid(game_state)
358
handle_round_end(game_state, game_metadata)
359
360
else:
361
assert False, f'Unknown action: {action}.'
362
363
# Update game state
364
set_game_state(metadata, game_type, game_id, game_state)
365
Byte Code
e30000000000000000000000000600000040000000733e01000065005a0165026400640164028d025a036403640484005a046505650564059c026406640784045a066505650564059c026408640984045a076505650564059c02640a640b84045a0865056509650a6509640c9c04640d640e84045a0b650965096509650a640f9c046410641184045a0c650565096509650a64129c046413641484045a0d650a65096509650564159c046416641784045a0e650a65096509650564189c046419641a84045a0f650a65096509650564159c04641b641c84045a10650a65096509650564189c04641d641e84045a1165096505641f9c026420642184045a12650564229c016423642484045a13650564229c016425642684045a14650564229c016427642884045a156505650564299c02642a642b84045a16651764008301650565056509650a642c9c04642d642e840483015a18642f53002930da18636f6e5f67616d655f6d616e616765725f696d706c5f7631da16434f4e54524143545f464f525f47414d455f545950452902da08636f6e7472616374da046e616d65630000000000000000000000000500000043000000731600000074006a0164016402640364049c03830101006400530029054eda0f636f6e5f636865636b6572735f7631da0c636f6e5f63686573735f7631da09636f6e5f676f5f76312903da08636865636b657273da056368657373da02676f2902da185f5f434f4e54524143545f464f525f47414d455f54595045da03736574a900720d000000720d000000da00da045f5f5f5f06000000730400000000010601720f0000002902da057374617465da0d696e697469616c5f737461746563020000000000000004000000030000004300000073440000007c00640119007d027c00640219007d037c006a00830001007c01640319007c0064033c007c01640419007c0064043c007c037c0064013c007c027c0064023c006400530029054eda0c63726561746f725f7465616dda0d6f70706f6e656e745f7465616dda0e63757272656e745f706c61796572da05626f6172642901da05636c65617229047210000000721100000072120000007213000000720d000000720d000000720e000000da125f5f72657365745f67616d655f73746174650b000000730e00000000010801080108010c010c0108017217000000630200000000000000020000000300000043000000732c0000007c006a006401830164006b0972167c0064011900731e740164028301820174027c007c01830201006400530029034eda09636f6d706c657465647a1b47616d6520686173206e6f7420636f6d706c65746564207965742e2903da03676574da0e417373657274696f6e4572726f727217000000290272100000007211000000720d000000720d000000720e000000da0c5f5f706c61795f616761696e150000007306000000000118010601721b00000063020000000000000006000000030000004300000073b60000007c006a006401830164006b0973207c006a0064028301732074016403830182017c006a006404830164006b0873407c00640419000c00734074016405830182017c006a00640683017d027c006a00640783017d037c006a00640883017d047c006a00640983017d0574027c007c01830201007c0264006b0972827c027c0064063c007c0364006b0972927c037c0064073c007c0464006b0972a27c047c0064083c007c0564006b0972b27c057c0064093c0064005300290a4eda0677696e6e6572da097374616c656d6174657a2550726576696f757320726f756e6420686173206e6f7420636f6d706c65746564207965742e72180000007a29526f756e6473206861766520636f6d706c657465642e20506c6561736520706c617920616761696e2eda0c63726561746f725f70616964da0d6f70706f6e656e745f70616964da0c63726561746f725f77696e73da0d6f70706f6e656e745f77696e7329037219000000721a0000007217000000290672100000007211000000721e000000721f00000072200000007221000000720d000000720d000000720e000000da0c5f5f6e6578745f726f756e641b000000732200000000011a0106011a0106010a010a010a010a010a01080108010801080108010801080172220000002904da077061796c6f6164da0663616c6c6572da086d65746164617461da0672657475726e63030000000000000011000000050000004300000073260200007c006a00640183017d037c006a006402640383027d047c006a006404640583027d057c006a006406640783027d067c006a006408640983027d077c006a00640a83017d087c006a00640b7c006a00640c830183027d0974016a0083007d0a7c087c0a6b06736e7402640d8301820174036a047c0a7c08190083016a0583007d0b7c0473947c0364006b0973947402640e830182017c046f9e7c0364006b090c0073aa7402640f8301820174067c067407830273c674067c067408830273c674026410830182017c0664076b0573d6740264118301820174067c077407830273e874026412830182017c0764096b0573f874026413830182017c0b6a0983007d0c7c05900173227c0c641419007d0d7c0c641519007c0c64143c007c0d7c0c64153c0069007d0e740a6a0b7c01740c740d8301170083017d0f7c027c087c0f64166603190064006b089001735474026417830182017c017c0e64183c007c047c0e64023c007c077c0e64083c007c0964006b099001727e7c097c0e640c3c007c0664076b04900172a674036a04740e6a0f83016a107c067c0164198d0201007c067c0e64063c0064057c0c641a3c0074117c017c087c0f7c02830401007c0364006b09900172de7c037c0e641b3c0074117c037c087c0f7c02830401006e287c027c08640266021900900170ee67007d107c106a127c0f830101007c107c027c08640266023c0074137c027c087c0f7c0c8304010074147c027c087c0f7c0e830401007c0f5300291c4eda0c6f746865725f706c61796572da067075626c696346da0d63726561746f725f666972737454da057761676572e900000000da06726f756e6473e901000000da0474797065da0967616d655f6e616d6572040000007a12496e76616c69642067616d6520747970652e7a264e6f206f70706f6e656e742073706563696669656420696e20707269766174652067616d652e7a224f70706f6e656e742073706563696669656420696e207075626c69632067616d652e7a165761676572206d757374206265206e756d657269632e7a1957616765722063616e6e6f74206265206e656761746976652e7a1a526f756e6473206d75737420626520616e20696e74656765722e7a14526f756e6473206d757374206265203e3d20312e7213000000721200000072100000007a1447616d6520616c7265616479206578697374732eda0763726561746f722902da06616d6f756e74da0c6d61696e5f6163636f756e74721e000000da086f70706f6e656e7429157219000000720b000000721a000000da0149da0d696d706f72745f6d6f64756c65da116765745f696e697469616c5f7374617465da0a6973696e7374616e6365da03696e74da05666c6f6174da04636f7079da07686173686c6962da0473686133da03737472da036e6f77da03637478da056f776e6572da0d666f7263655f6465706f736974da135f5f6164645f67616d655f666f725f75736572da06617070656e64da105f5f7365745f67616d655f7374617465da135f5f7365745f67616d655f6d657461646174612911722300000072240000007225000000722700000072280000007229000000722a000000722c000000da0967616d655f74797065722f000000da16636f6e74726163745f666f725f67616d655f747970657211000000da0a67616d655f7374617465da03746d70da0d67616d655f6d65746164617461da0767616d655f6964da0c7075626c69635f67616d6573720d000000720d000000720e000000da0d5f5f6372656174655f67616d652f000000735e00000000010a010c010c010c010c010a011201080110011202140110010601160106011001120110010801060108010c010801040112010c0110010801080108010a0108010a010e010801080108010e010a010801100212010a010c010e010e01724d0000002904da06706c617965727246000000724b000000722500000063040000000000000005000000060000004300000073400000007c037c017c00640166031900701064027d047c04640337007d047c047c037c017c00640166033c007c027c037c017c0064047c049b009d0266033c006400530029054eda05636f756e74722b000000722d0000007a0567616d652d720d0000002905724e0000007246000000724b0000007225000000da096e756d5f67616d6573720d000000720d000000720e00000072420000006300000073080000000002120108010e017242000000290472100000007246000000724b0000007225000000630400000000000000050000000600000043000000733c0000007c037c017c02640166031900701064027d047c04640337007d047c007c037c017c0264047c0466043c007c047c037c017c02640166033c006400530029054e7a0d686973746f72792d636f756e74722b000000722d000000da07686973746f7279720d000000290572100000007246000000724b0000007225000000da0d686973746f72795f636f756e74720d000000720d000000720e000000da185f5f73746f72655f686973746f726963616c5f73746174656b000000730800000000021201080110017253000000290472250000007246000000724b000000722600000063030000000000000004000000040000004300000073220000007c007c017c026401660319007d037c0364006b09731e74006402830182017c03530029034e72100000007a1447616d6520646f6573206e6f742065786973742e2901721a000000290472250000007246000000724b0000007248000000720d000000720d000000720e000000da105f5f6765745f67616d655f737461746573000000730600000000010e0110017254000000290472250000007246000000724b000000721000000063040000000000000004000000050000004300000073120000007c037c007c017c02640166033c006400530029024e7210000000720d000000290472250000007246000000724b0000007210000000720d000000720d000000720e00000072440000007900000073020000000001724400000063030000000000000004000000040000004300000073220000007c007c017c026401660319007d037c0364006b09731e74006402830182017c03530029034e72250000007a1447616d6520646f6573206e6f742065786973742e2901721a000000290472250000007246000000724b0000007248000000720d000000720d000000720e000000da135f5f6765745f67616d655f6d657461646174617d000000730600000000010e011001725500000063040000000000000004000000050000004300000073120000007c037c007c017c02640166033c006400530029024e7225000000720d000000290472250000007246000000724b0000007210000000720d000000720d000000720e00000072450000008300000073020000000002724500000029027224000000724a00000063020000000000000002000000020000004300000073240000007c01640119007c006b0273207c01640219007c006b02732074006403830182016400530029044e723000000072330000007a19596f7520617265206e6f7420696e20746869732067616d652e2901721a00000029027224000000724a000000720d000000720d000000720e000000da105f5f6173736572745f696e5f67616d6588000000730400000000011201725600000029017248000000630100000000000000010000000200000043000000733400000064017c006b0672107c00640119007318740064028301820164037c006b0672287c0064031900733074006404830182016400530029054e721e0000007a1943726561746f7220686173206e6f742070616964207965742e721f0000007a164f70706f6e656e7420686173206e6f7420706169642e2901721a00000029017248000000720d000000720d000000720e000000da1a5f5f6173736572745f626f74685f706172746965735f706169648d00000073080000000001120106011201725700000063010000000000000001000000020000004300000073280000007c006a006401830164006b08721c7c006a006402830164006b08732474016403830182016400530029044e721c000000721d0000007a215468697320726f756e642068617320616c726561647920636f6d706c657465642e29027219000000721a00000029017248000000720d000000720d000000720e000000da1c5f5f6173736572745f726f756e645f6e6f745f636f6d706c6574656494000000730400000000011601725800000063010000000000000001000000020000004300000073240000007c006a006401830164006b0973207c006a0064028301732074016403830182016400530029044e721c000000721d0000007a215468697320726f756e6420686173206e6f742079657420636f6d706c657465642e29027219000000721a00000029017248000000720d000000720d000000720e000000da185f5f6173736572745f726f756e645f636f6d706c6574656499000000730400000000011a01725900000029027248000000724a0000006302000000000000000a0000000400000043000000730c0100007c006a0064018301720e640053007c00640219007d027c016a006403640483027d037c00640519007d047c047c026b0272507c01640619007d057c006a00640764048302640817007c0064073c006e1c7c01640919007d057c006a00640a64048302640817007c00640a3c007c016a00640b640883027d067c006a006407640483027d077c006a00640a640483027d087c077c06640c1a006b0473aa7c087c06640c1a006b0490017208640d7c00640e3c007c0364046b04900172087401640f83017d097c006a006410830172d67c097c0337007d097c006a006411830172e87c097c0337007d097c0964046b049001720874026a0374046a0583016a067c057c0964128d0201006400530029134e721d000000721c000000722a000000722b000000721200000072300000007220000000722d00000072330000007221000000722c000000e9020000005472180000007a03302e30721f000000721e0000002902724e000000723100000029077219000000da07646563696d616c72340000007235000000723f0000007240000000da0e666f7263655f7769746864726177290a7248000000724a000000721c000000722a0000007212000000da0e77696e6e65725f61646472657373722c00000072200000007221000000da0d616d6f756e745f746f5f706179720d000000720d000000720e000000da125f5f68616e646c655f726f756e645f656e649e000000733000000000010a01040108010c010801080108011602080114010c010c010c011a0108010a0108010a0108010a0108010a010c01725f0000002904722300000072100000007224000000722600000063030000000000000013000000070000004300000073b00500007c01640119007d037c01640219007d047c00640319007d057c0564046b02722c74007c007c027c03830353007c0564056b02725a7c027c046a0183006b027348740264068301820174036a047c00640719008301010090056e527c00640819007d067c00640919007d0774057c037c077c0683037d0874067c037c077c0683037d097c09640a19007c026b027d0a74036a0183007d0b7c05640b6b0372a874077c027c09830201007c077c0b6b0673b87402640c830182017c05640d6b029001723c7c096a01640e640f83027d0c7c0c640f6b0473de740264108301820174086a09740a6a0b83016a0c7c0c7c0264118d0201007c0a9001721a7c086a01641283010c0090017310740264138301820164147c0864123c006e1e7c086a01641583010c0090017330740264138301820164147c0864153c0090046e627c0564166b0290017284740d7c0883010100740e7c08830101007c0a900172667c08641719007d0d6e087c08641819007d0d7c0d7c0864193c00740f7c087c098302010090046e1a7c05641a6b02900172e2740d7c0883010100740e7c08830101007c086a01641b830164006b08900172be7c086a01641c830164006b08900173c67402641d830182017c0a900172d664147c08641b3c006e0864147c08641c3c0090036ebc7c05641e6b0290027288740d7c0883010100740e7c08830101007c086a01641f830164006b089002721c7c086a016420830164006b089002732474026421830182017c0a900272467c08641c19009002733c740264228301820164147c08641f3c006e1a7c08641b190090027358740264238301820164147c0864203c0074086a097c0b7c07190083017d0e7c0e6a107c087c0983020100740f7c087c098302010090036e167c0564246b02900372647c0a900272da64127c086b06900272ac7c0864121900900273b4740264258301820164157c086b07900273d27c08641519000c00900273d274026426830182017c0864123d006e4064157c086b06900272ee7c0864151900900273f6740264258301820164127c086b07900373147c08641219000c009003731474026426830182017c0864153d0074086a097c0b7c07190083017d0e7c0e6a107c087c09830201007c086a01640e640f83027d0c7c0c640f6b049005729e74086a09740a6a0b83016a117c027c0c64278d02010090026e3a7c0564286b029003727290026e2c7c0564296b02900372aa74127c087c077c067c038304010074086a097c0b7c07190083016a1383007d0f74147c087c0f8302010090016ef47c05642a6b029004723874127c087c077c067c038304010074086a097c0b7c07190083016a1383007d0f74157c087c0f830201007c096a01640e640f83027d0c7c0c640f6b049004722474086a09740a6a0b83016a0c7c0c7c0264118d0201007c0a9004721a64147c0864123c006e0864147c0864153c006e1064147c0864153c0064147c0864123c0090016e667c05640b6b02900472f67c09642b19007d107c096a01642c83017d117c109004726e7c1164006b08900473807402642d830182016e127c117c026b02900473807402642e830182017c027c09640a19006b03900473967402642f830182017c027c09642c3c007c096a01640e640f83027d0c7c0c640f6b04900472ca74086a09740a6a0b83016a0c7c0c7c0264118d02010064147c0864153c007c10900472e674167c027c077c067c038304010074177c037c077c067c09830401006ea87c0564306b0290057288740d7c08830101007c0a9005722a7c08641819007d127c08641219009005734674026431830182016e1c7c08641719007d127c086a016415830190057346740264318301820174086a097c0b7c07190083016a187c027c127c007c087c0964328d0501007c086a016419830164006b099005729e740e7c0883010100740f7c087c09830201006e1664339005739e740264347c059b0064359d038301820174197c037c077c067c08830401006400530029364e72250000007240000000da06616374696f6eda06637265617465da107570646174655f636f6e7472616374737a294f6e6c7920746865206f776e65722063616e2063616c6c207570646174655f636f6e7472616374732eda09636f6e747261637473724b000000722e0000007230000000da046a6f696e7a12496e76616c69642067616d6520747970652eda067061795f7570722a000000722b0000007a124e6f206e65656420746f207061792075702e290272310000007232000000721e0000007a0d416c726561647920706169642e54721f000000da0d666f72666569745f726f756e6472130000007212000000721c000000da0b726571756573745f656e64da1563726561746f725f7265717565737465645f656e64da166f70706f6e656e745f7265717565737465645f656e647a27456e6420726571756573742068617320616c7265616479206265656e207375626d69747465642eda0a6163636570745f656e64da1463726561746f725f61636365707465645f656e64da156f70706f6e656e745f61636365707465645f656e647a26456e6420726571756573742068617320616c7265616479206265656e2061636365707465642e7a2e4f70706f6e656e7420646964206e6f74207265717565737420616e20656e6420746f207468697320726f756e642e7a2d43726561746f7220646964206e6f74207265717565737420616e20656e6420746f207468697320726f756e642eda096561726c795f656e647a14596f7520646964206e6f7420706179207965742e7a1a4f70706f6e656e742068617320616c726561647920706169642e2902724e0000007231000000da12656e666f7263655f74696d655f6c696d6974da0a6e6578745f726f756e64da0a706c61795f616761696e722800000072330000007a1d546865726520697320616c726561647920616e206f70706f6e656e742e7a15596f752077657265206e6f7420696e76697465642e7a21596f7520617265207468652063726561746f72206f6620746869732067616d652eda046d6f76657a16596f752068617665206e6f742070616964207965742e29057224000000da047465616d722300000072100000007225000000467a10556e6b6e6f776e20616374696f6e3a20da012e291a724d0000007219000000721a000000720b000000720c00000072540000007255000000725600000072340000007235000000723f0000007240000000724100000072580000007257000000725f000000da0f666f7263655f656e645f726f756e64725c000000725300000072360000007222000000721b00000072420000007245000000727100000072440000002913722300000072100000007224000000722500000072400000007260000000724b00000072460000007248000000724a000000da0a69735f63726561746f727247000000722a000000721c00000072030000007211000000722800000072330000007272000000720d000000720d000000720e000000da08696e746572616374ba0000007306010000000208010801080108010c0108010e0106011202080108010c010c010c01080108010a0110010a010c0110010e010801060116010a0216010c010a010801080106010a02080108010e010a010801080108011001100106010a020c010a010801080108011001100106010c0106010a020c01060108010e010c010e010a0106010c0110010c01120108020c0110010c01120106010e010c010c010a010e010c010a0104010a010e0112020e010a010e0112020a010c010a010e01080106010a020a0208010c010a0108010a010601140212011001060108010c010a010e010801080106010e0110010a01080106010801140208010e0106010e0108010801100108010c02160172760000004e2919da09696d706f72746c69627234000000da085661726961626c65720b000000720f000000da04646963747217000000721b0000007222000000723d000000da03416e79724d0000007242000000725300000072540000007244000000725500000072450000007256000000725700000072580000007259000000725f000000da085f5f6578706f72747276000000720d000000720d000000720d000000720e000000da083c6d6f64756c653e01000000732e0000000401040108030805100a10061014143406010e0706010e0714061404140606010e0410050e070e050e05101c0601