def generate_ghid_parser(): ghid_parser = SmartyParser() ghid_parser["algo"] = ParseHelper(parsers.Int8(signed=False)) ghid_parser["address"] = None @references(ghid_parser) def _ghid_format(self, algo): try: self["address"] = _hash_algo_lookup[algo] except KeyError as e: print(algo) raise ValueError("Improper hash algorithm declaration.") from e ghid_parser["algo"].register_callback("prepack", _ghid_format) ghid_parser["algo"].register_callback("postunpack", _ghid_format) # Don't forget to transform the object back to a utils.Ghid ghid_parser.register_callback("postunpack", _ghid_transform, modify=True) return ghid_parser
def generate_ghid_parser(): ghid_parser = SmartyParser() ghid_parser['algo'] = ParseHelper(parsers.Int8(signed=False)) ghid_parser['address'] = None @references(ghid_parser) def _ghid_format(self, algo): try: self['address'] = _hash_algo_lookup[algo] except KeyError as e: print(algo) raise ValueError('Improper hash algorithm declaration.') from e ghid_parser['algo'].register_callback('prepack', _ghid_format) ghid_parser['algo'].register_callback('postunpack', _ghid_format) # Don't forget to transform the object back to a utils.Ghid ghid_parser.register_callback('postunpack', _ghid_transform, modify=True) return ghid_parser
from smartyparse import references from smartyparse.parsers import Blob from smartyparse.parsers import Int8 from smartyparse.parsers import Int16 from smartyparse.parsers import Int32 from smartyparse.parsers import Int64 from smartyparse.parsers import Null # ############################################### # Testing # ############################################### if __name__ == '__main__': # Generic format tf_1 = SmartyParser() tf_1['magic'] = ParseHelper(Blob(length=4)) tf_1['version'] = ParseHelper(Int32(signed=False)) tf_1['cipher'] = ParseHelper(Int8(signed=False)) tf_1['body1_length'] = ParseHelper(Int32(signed=False)) tf_1['body1'] = ParseHelper(Blob()) tf_1['body2_length'] = ParseHelper(Int32(signed=False)) tf_1['body2'] = ParseHelper(Blob()) tf_1.link_length('body1', 'body1_length') tf_1.link_length('body2', 'body2_length') # Nested formats tf_nest = SmartyParser() tf_nest['first'] = tf_1 tf_nest['second'] = tf_1
from smartyparse import SmartyParser from smartyparse import ParseHelper from smartyparse.parsers import Blob from smartyparse.parsers import Int8 from smartyparse.parsers import Int16 from smartyparse.parsers import Int32 from smartyparse.parsers import Int64 from smartyparse.parsers import Null # ############################################### # Setup # ############################################### test_format = SmartyParser() test_format['magic'] = ParseHelper(Blob(length=4)) test_format['version'] = ParseHelper(Int32(signed=False)) test_format['cipher'] = ParseHelper(Int8(signed=False)) test_format['body1_length'] = ParseHelper(Int32(signed=False)) test_format['body1'] = ParseHelper(Blob()) test_format['body2_length'] = ParseHelper(Int32(signed=False)) test_format['body2'] = ParseHelper(Blob()) test_format.link_length('body1', 'body1_length') test_format.link_length('body2', 'body2_length') test_nest = SmartyParser() test_nest['first'] = test_format test_nest['second'] = test_format tv1 = {}
_pubkey_parsers_exchange = {} _pubkey_parsers_exchange[0] = ParseHelper( parsers.Literal(_dummy_pubkey, verify=False)) _pubkey_parsers_exchange[1] = ParseHelper(parsers.Blob(length=32)) _pubkey_parsers_exchange[2] = ParseHelper(parsers.Blob(length=32)) # ---------------------------------------------------------------------- # Use this whenever a GHID list is required _ghidlist = generate_ghidlist_parser() # ---------------------------------------------------------------------- # GIDC format blocks _gidc = SmartyParser() _gidc['magic'] = ParseHelper(parsers.Literal(b'GIDC')) _gidc['version'] = ParseHelper(parsers.Int32(signed=False)) _gidc['cipher'] = ParseHelper(parsers.Int8(signed=False)) _gidc['body'] = None _gidc['ghid'] = generate_ghid_parser() _gidc['signature'] = ParseHelper(parsers.Null()) _gidc_lookup = {} _gidc_lookup[2] = SmartyParser() _gidc_lookup[2]['signature_key'] = None _gidc_lookup[2]['encryption_key'] = None _gidc_lookup[2]['exchange_key'] = None _gidc_cipher_update = _callback_multi( _gen_body_update(_gidc, _pubkey_parsers_sig, 'signature_key'),
'sig': 512, 'mac': 64, 'asym': 512, 'seed': 0 } } # ---------------------------------------------------------------------- # Misc objects class SecurityError(RuntimeError): pass _secret_parser = SmartyParser() _secret_parser['magic'] = ParseHelper(parsers.Literal(b'SH')) _secret_parser['version'] = ParseHelper(parsers.Int16(signed=False)) _secret_parser['cipher'] = ParseHelper(parsers.Int8(signed=False)) _secret_parser['key'] = None _secret_parser['seed'] = None def _secret_cipher_update(cipher): key_length = cipher_length_lookup[cipher]['key'] seed_length = cipher_length_lookup[cipher]['seed'] _secret_parser['key'] = ParseHelper(parsers.Blob(length=key_length)) _secret_parser['seed'] = ParseHelper(parsers.Blob(length=seed_length)) _secret_parser['cipher'].register_callback('prepack', _secret_cipher_update)
_pubkey_parsers_encrypt[2] = ParseHelper(parsers.Blob(length=512)) _pubkey_parsers_exchange = {} _pubkey_parsers_exchange[0] = ParseHelper(parsers.Literal(_dummy_pubkey, verify=False)) _pubkey_parsers_exchange[1] = ParseHelper(parsers.Blob(length=32)) _pubkey_parsers_exchange[2] = ParseHelper(parsers.Blob(length=32)) # ---------------------------------------------------------------------- # Use this whenever a GHID list is required _ghidlist = generate_ghidlist_parser() # ---------------------------------------------------------------------- # GIDC format blocks _gidc = SmartyParser() _gidc["magic"] = ParseHelper(parsers.Literal(b"GIDC")) _gidc["version"] = ParseHelper(parsers.Int32(signed=False)) _gidc["cipher"] = ParseHelper(parsers.Int8(signed=False)) _gidc["body"] = None _gidc["ghid"] = generate_ghid_parser() _gidc["signature"] = ParseHelper(parsers.Null()) _gidc_lookup = {} _gidc_lookup[2] = SmartyParser() _gidc_lookup[2]["signature_key"] = None _gidc_lookup[2]["encryption_key"] = None _gidc_lookup[2]["exchange_key"] = None _gidc_cipher_update = _callback_multi( _gen_body_update(_gidc, _pubkey_parsers_sig, "signature_key"),
def run(): # Generic format tf_1 = SmartyParser() tf_1['magic'] = ParseHelper(Blob(length=4)) tf_1['version'] = ParseHelper(Int32(signed=False)) tf_1['cipher'] = ParseHelper(Int8(signed=False)) tf_1['body1_length'] = ParseHelper(Int32(signed=False)) tf_1['body1'] = ParseHelper(Blob()) tf_1['body2_length'] = ParseHelper(Int32(signed=False)) tf_1['body2'] = ParseHelper(Blob()) tf_1.link_length('body1', 'body1_length') tf_1.link_length('body2', 'body2_length') # Nested formats tf_nest = SmartyParser() tf_nest['first'] = tf_1 tf_nest['second'] = tf_1 tf_nest2 = SmartyParser() tf_nest2['_0'] = ParseHelper(Int32()) tf_nest2['_1'] = tf_1 tf_nest2['_2'] = ParseHelper(Int32()) # More exhaustive, mostly deterministic format tf_2 = SmartyParser() tf_2['_0'] = ParseHelper(parsers.Null()) tf_2['_1'] = ParseHelper(parsers.Int8(signed=True)) tf_2['_2'] = ParseHelper(parsers.Int8(signed=False)) tf_2['_3'] = ParseHelper(parsers.Int16(signed=True)) tf_2['_4'] = ParseHelper(parsers.Int16(signed=False)) tf_2['_5'] = ParseHelper(parsers.Int32(signed=True)) tf_2['_6'] = ParseHelper(parsers.Int32(signed=False)) tf_2['_7'] = ParseHelper(parsers.Int64(signed=True)) tf_2['_8'] = ParseHelper(parsers.Int64(signed=False)) tf_2['_9'] = ParseHelper(parsers.Float(double=False)) tf_2['_10'] = ParseHelper(parsers.Float()) tf_2['_11'] = ParseHelper(parsers.ByteBool()) tf_2['_12'] = ParseHelper(parsers.Padding(length=4)) tf_2['_13'] = ParseHelper(parsers.String()) tv1 = {} tv1['magic'] = b'[00]' tv1['version'] = 1 tv1['cipher'] = 2 tv1['body1'] = b'[tv1 byte string, first]' tv1['body2'] = b'[tv1 byte string, 2nd]' tv2 = {} tv2['magic'] = b'[aa]' tv2['version'] = 5 tv2['cipher'] = 6 tv2['body1'] = b'[new test byte string, first]' tv2['body2'] = b'[new test byte string, 2nd]' tv3 = {'first': copy.deepcopy(tv1), 'second': copy.deepcopy(tv2)} tv4 = {} tv4['_0'] = None tv4['_1'] = -10 tv4['_2'] = 11 tv4['_3'] = -300 tv4['_4'] = 301 tv4['_5'] = -100000 tv4['_6'] = 100001 tv4['_7'] = -10000000000 tv4['_8'] = 10000000001 tv4['_9'] = 11.11 tv4['_10'] = 1e-50 tv4['_11'] = True tv4['_12'] = None tv4['_13'] = 'EOF' tv5 = {} tv5['_0'] = 42 tv5['_1'] = copy.deepcopy(tv1) tv5['_2'] = -42 print('-----------------------------------------------') print('Testing all "other" parsers...') # print(' ', tv4) bites4 = tf_2.pack(tv4) # print('Successfully packed.') # print(' ', bytes(bites4)) recycle4 = tf_2.unpack(bites4) # Note that numerical precision prevents us from easily: # assert recycle4 == tv4 # print('Successfully reunpacked.') # print(recycle4) # print(' ', tv5) bites5 = tf_nest2.pack(tv5) # print('Successfully packed.') # print(' ', bytes(bites5)) recycle5 = tf_nest2.unpack(bites5) assert recycle5 == tv5 print('Successfully reunpacked.') # print(recycle5) # print('-----------------------------------------------') print('-----------------------------------------------') print('Starting TV1, serial...') # print(' ', tv1) bites1 = tf_1.pack(tv1) # print('Successfully packed.') # print(' ', bytes(bites1)) recycle1 = tf_1.unpack(bites1) assert recycle1 == tv1 print('Successfully reunpacked.') # print(recycle1) # print('-----------------------------------------------') print('-----------------------------------------------') print('Starting TV2, serial...') # print(' ', tv2) bites2 = tf_1.pack(tv2) # print('Successfully packed.') # print(' ', bytes(bites2)) recycle2 = tf_1.unpack(bites2) assert recycle2 == tv2 print('Successfully reunpacked.') # print(recycle2) # print('-----------------------------------------------') print('-----------------------------------------------') print('Starting TV1, TV2 parallel...') # print(' ', tv1) bites1 = tf_1.pack(tv1) # print('Successfully packed TV1.') # print(' ', bytes(bites1)) # print(' ', tv2) bites2 = tf_1.pack(tv2) # print('Successfully packed TV2.') # print(' ', bytes(bites2)) recycle1 = tf_1.unpack(bites1) assert recycle1 == tv1 print('Successfully reunpacked TV1.') # print(recycle1) recycle2 = tf_1.unpack(bites2) assert recycle2 == tv2 print('Successfully reunpacked TV2.') # print(recycle2) print('-----------------------------------------------') print('Starting (nested) TV3...') # print(tv3) bites3 = tf_nest.pack(tv3) # print('-----------------------------------------------') # print('Successfully packed.') # print(bytes(bites3)) # print('-----------------------------------------------') recycle3 = tf_nest.unpack(bites3) assert recycle3 == tv3 print('Successfully reunpacked.') # print(recycle3) print('-----------------------------------------------') print('Testing toggle...') parent = SmartyParser() parent['switch'] = ParseHelper(Int8(signed=False)) parent['light'] = None @references(parent) def decide(self, switch): if switch == 1: self['light'] = ParseHelper(Int8()) else: self['light'] = ParseHelper(Blob(length=11)) parent['switch'].register_callback('prepack', decide) parent['switch'].register_callback('postunpack', decide) off = {'switch': 1, 'light': -55} on = {'switch': 0, 'light': b'Hello world'} o1 = parent.pack(off) o2 = parent.pack(on) assert parent.unpack(o1) == off assert parent.unpack(o2) == on print('Success.') # ----------------------------------------------------------------- print('-----------------------------------------------') print('Testing listyparser...') pastr = SmartyParser() pastr['length'] = ParseHelper(parsers.Int8(signed=False)) pastr['body'] = ParseHelper(parsers.String()) pastr.link_length('body', 'length') tag_typed = SmartyParser() tag_typed['tag'] = ParseHelper(parsers.Int8(signed=False)) tag_typed['toggle'] = None @references(tag_typed) def switch(self, tag): if tag == 0: self['toggle'] = ParseHelper(parsers.Int8(signed=False)) elif tag == 1: self['toggle'] = ParseHelper(parsers.Int16(signed=False)) elif tag == 2: self['toggle'] = ParseHelper(parsers.Int32(signed=False)) elif tag == 3: self['toggle'] = ParseHelper(parsers.Int64(signed=False)) else: self['toggle'] = pastr tag_typed['tag'].register_callback('prepack', switch) tag_typed['tag'].register_callback('postunpack', switch) tf_list = ListyParser(parsers=[tag_typed]) tv_list = [{ 'tag': 0, 'toggle': 5 }, { 'tag': 1, 'toggle': 51 }, { 'tag': 65, 'toggle': { 'body': 'hello world' } }, { 'tag': 2, 'toggle': 3453 }] tv_list_pack = tf_list.pack(tv_list) for it1, it2 in zip(tv_list, tf_list.unpack(tv_list_pack)): assert it1 == it2 print('Success.') # assert tf_list.unpack(tv_list_pack) == tv_list print('Testing nested explicit listyparser...') tf_list_nest = SmartyParser() tf_list_nest['_0'] = ParseHelper(parsers.Int8(signed=False)) tf_list_nest['_1'] = ParseHelper(parsers.Int16(signed=False)) tf_list_nest['_2'] = tf_list tf_list_nest['_3'] = ParseHelper(parsers.Int8(signed=False)) tf_list_nest.link_length('_2', '_1') tv_list_nest = { '_0': 12, '_2': copy.deepcopy(tv_list), '_3': 14, } tv_list_nest_pack = tf_list_nest.pack(tv_list_nest) tv_list_nest_recycle = tf_list_nest.unpack(tv_list_nest_pack) print('No errors, but no test for equivalency yet.') print('Testing nested implicit listyparser.') terminant = ParseHelper(parsers.Literal(b'h', verify=False)) tf_exlist = ListyParser(parsers=[tag_typed], terminant=terminant) tf_exlist_nest = SmartyParser() tf_exlist_nest['_0'] = ParseHelper(parsers.Int8(signed=False)) tf_exlist_nest['_2'] = tf_exlist tf_exlist_nest['_3'] = ParseHelper(parsers.Int8(signed=False)) tv_exlist_pack = tf_exlist_nest.pack(tv_list_nest) tv_exlist_recycle = tf_exlist_nest.unpack(tv_exlist_pack) print('No errors, but no test for equivalency yet.') # Can do some kind of check for len of self.obj to determine if there's # only a single entry in the smartyparser, and thereby expand any # objects to pack or objects unpacked. print('-----------------------------------------------')
def run(): # Generic format tf_1 = SmartyParser() tf_1['magic'] = ParseHelper(Blob(length=4)) tf_1['version'] = ParseHelper(Int32(signed=False)) tf_1['cipher'] = ParseHelper(Int8(signed=False)) tf_1['body1_length'] = ParseHelper(Int32(signed=False)) tf_1['body1'] = ParseHelper(Blob()) tf_1['body2_length'] = ParseHelper(Int32(signed=False)) tf_1['body2'] = ParseHelper(Blob()) tf_1.link_length('body1', 'body1_length') tf_1.link_length('body2', 'body2_length') # Nested formats tf_nest = SmartyParser() tf_nest['first'] = tf_1 tf_nest['second'] = tf_1 tf_nest2 = SmartyParser() tf_nest2['_0'] = ParseHelper(Int32()) tf_nest2['_1'] = tf_1 tf_nest2['_2'] = ParseHelper(Int32()) # More exhaustive, mostly deterministic format tf_2 = SmartyParser() tf_2['_0'] = ParseHelper(parsers.Null()) tf_2['_1'] = ParseHelper(parsers.Int8(signed=True)) tf_2['_2'] = ParseHelper(parsers.Int8(signed=False)) tf_2['_3'] = ParseHelper(parsers.Int16(signed=True)) tf_2['_4'] = ParseHelper(parsers.Int16(signed=False)) tf_2['_5'] = ParseHelper(parsers.Int32(signed=True)) tf_2['_6'] = ParseHelper(parsers.Int32(signed=False)) tf_2['_7'] = ParseHelper(parsers.Int64(signed=True)) tf_2['_8'] = ParseHelper(parsers.Int64(signed=False)) tf_2['_9'] = ParseHelper(parsers.Float(double=False)) tf_2['_10'] = ParseHelper(parsers.Float()) tf_2['_11'] = ParseHelper(parsers.ByteBool()) tf_2['_12'] = ParseHelper(parsers.Padding(length=4)) tf_2['_13'] = ParseHelper(parsers.String()) tv1 = {} tv1['magic'] = b'[00]' tv1['version'] = 1 tv1['cipher'] = 2 tv1['body1'] = b'[tv1 byte string, first]' tv1['body2'] = b'[tv1 byte string, 2nd]' tv2 = {} tv2['magic'] = b'[aa]' tv2['version'] = 5 tv2['cipher'] = 6 tv2['body1'] = b'[new test byte string, first]' tv2['body2'] = b'[new test byte string, 2nd]' tv3 = { 'first': copy.deepcopy(tv1), 'second': copy.deepcopy(tv2) } tv4 = {} tv4['_0'] = None tv4['_1'] = -10 tv4['_2'] = 11 tv4['_3'] = -300 tv4['_4'] = 301 tv4['_5'] = -100000 tv4['_6'] = 100001 tv4['_7'] = -10000000000 tv4['_8'] = 10000000001 tv4['_9'] = 11.11 tv4['_10'] = 1e-50 tv4['_11'] = True tv4['_12'] = None tv4['_13'] = 'EOF' tv5 = {} tv5['_0'] = 42 tv5['_1'] = copy.deepcopy(tv1) tv5['_2'] = -42 print('-----------------------------------------------') print('Testing all "other" parsers...') # print(' ', tv4) bites4 = tf_2.pack(tv4) # print('Successfully packed.') # print(' ', bytes(bites4)) recycle4 = tf_2.unpack(bites4) # Note that numerical precision prevents us from easily: # assert recycle4 == tv4 # print('Successfully reunpacked.') # print(recycle4) # print(' ', tv5) bites5 = tf_nest2.pack(tv5) # print('Successfully packed.') # print(' ', bytes(bites5)) recycle5 = tf_nest2.unpack(bites5) assert recycle5 == tv5 print('Successfully reunpacked.') # print(recycle5) # print('-----------------------------------------------') print('-----------------------------------------------') print('Starting TV1, serial...') # print(' ', tv1) bites1 = tf_1.pack(tv1) # print('Successfully packed.') # print(' ', bytes(bites1)) recycle1 = tf_1.unpack(bites1) assert recycle1 == tv1 print('Successfully reunpacked.') # print(recycle1) # print('-----------------------------------------------') print('-----------------------------------------------') print('Starting TV2, serial...') # print(' ', tv2) bites2 = tf_1.pack(tv2) # print('Successfully packed.') # print(' ', bytes(bites2)) recycle2 = tf_1.unpack(bites2) assert recycle2 == tv2 print('Successfully reunpacked.') # print(recycle2) # print('-----------------------------------------------') print('-----------------------------------------------') print('Starting TV1, TV2 parallel...') # print(' ', tv1) bites1 = tf_1.pack(tv1) # print('Successfully packed TV1.') # print(' ', bytes(bites1)) # print(' ', tv2) bites2 = tf_1.pack(tv2) # print('Successfully packed TV2.') # print(' ', bytes(bites2)) recycle1 = tf_1.unpack(bites1) assert recycle1 == tv1 print('Successfully reunpacked TV1.') # print(recycle1) recycle2 = tf_1.unpack(bites2) assert recycle2 == tv2 print('Successfully reunpacked TV2.') # print(recycle2) print('-----------------------------------------------') print('Starting (nested) TV3...') # print(tv3) bites3 = tf_nest.pack(tv3) # print('-----------------------------------------------') # print('Successfully packed.') # print(bytes(bites3)) # print('-----------------------------------------------') recycle3 = tf_nest.unpack(bites3) assert recycle3 == tv3 print('Successfully reunpacked.') # print(recycle3) print('-----------------------------------------------') print('Testing toggle...') parent = SmartyParser() parent['switch'] = ParseHelper(Int8(signed=False)) parent['light'] = None @references(parent) def decide(self, switch): if switch == 1: self['light'] = ParseHelper(Int8()) else: self['light'] = ParseHelper(Blob(length=11)) parent['switch'].register_callback('prepack', decide) parent['switch'].register_callback('postunpack', decide) off = {'switch': 1, 'light': -55} on = {'switch': 0, 'light': b'Hello world'} o1 = parent.pack(off) o2 = parent.pack(on) assert parent.unpack(o1) == off assert parent.unpack(o2) == on print('Success.') # ----------------------------------------------------------------- print('-----------------------------------------------') print('Testing listyparser...') pastr = SmartyParser() pastr['length'] = ParseHelper(parsers.Int8(signed=False)) pastr['body'] = ParseHelper(parsers.String()) pastr.link_length('body', 'length') tag_typed = SmartyParser() tag_typed['tag'] = ParseHelper(parsers.Int8(signed=False)) tag_typed['toggle'] = None @references(tag_typed) def switch(self, tag): if tag == 0: self['toggle'] = ParseHelper(parsers.Int8(signed=False)) elif tag == 1: self['toggle'] = ParseHelper(parsers.Int16(signed=False)) elif tag == 2: self['toggle'] = ParseHelper(parsers.Int32(signed=False)) elif tag == 3: self['toggle'] = ParseHelper(parsers.Int64(signed=False)) else: self['toggle'] = pastr tag_typed['tag'].register_callback('prepack', switch) tag_typed['tag'].register_callback('postunpack', switch) tf_list = ListyParser(parsers=[tag_typed]) tv_list = [ {'tag': 0, 'toggle': 5}, {'tag': 1, 'toggle': 51}, {'tag': 65, 'toggle': {'body': 'hello world'}}, {'tag': 2, 'toggle': 3453} ] tv_list_pack = tf_list.pack(tv_list) for it1, it2 in zip(tv_list, tf_list.unpack(tv_list_pack)): assert it1 == it2 print('Success.') # assert tf_list.unpack(tv_list_pack) == tv_list print('Testing nested explicit listyparser...') tf_list_nest = SmartyParser() tf_list_nest['_0'] = ParseHelper(parsers.Int8(signed=False)) tf_list_nest['_1'] = ParseHelper(parsers.Int16(signed=False)) tf_list_nest['_2'] = tf_list tf_list_nest['_3'] = ParseHelper(parsers.Int8(signed=False)) tf_list_nest.link_length('_2', '_1') tv_list_nest = { '_0': 12, '_2': copy.deepcopy(tv_list), '_3': 14, } tv_list_nest_pack = tf_list_nest.pack(tv_list_nest) tv_list_nest_recycle = tf_list_nest.unpack(tv_list_nest_pack) print('No errors, but no test for equivalency yet.') print('Testing nested implicit listyparser.') terminant = ParseHelper(parsers.Literal(b'h', verify=False)) tf_exlist = ListyParser(parsers=[tag_typed], terminant=terminant) tf_exlist_nest = SmartyParser() tf_exlist_nest['_0'] = ParseHelper(parsers.Int8(signed=False)) tf_exlist_nest['_2'] = tf_exlist tf_exlist_nest['_3'] = ParseHelper(parsers.Int8(signed=False)) tv_exlist_pack = tf_exlist_nest.pack(tv_list_nest) tv_exlist_recycle = tf_exlist_nest.unpack(tv_exlist_pack) print('No errors, but no test for equivalency yet.') # Can do some kind of check for len of self.obj to determine if there's # only a single entry in the smartyparser, and thereby expand any # objects to pack or objects unpacked. print('-----------------------------------------------')