Contract con_game_manager_impl_v1


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