diff --git a/extras/build_whitelist.py b/extras/build_whitelist.py new file mode 100644 index 000000000..d93d8d90a --- /dev/null +++ b/extras/build_whitelist.py @@ -0,0 +1,17 @@ +import sys +import os +import os.path as pth +import hashlib + +output = open("whitelist_hashes.txt", mode="w") + +for root, dirs, files in os.walk(sys.argv[1]): + for filename in files: + path = pth.join(pth.dirname(pth.abspath(sys.argv[0])), + root, filename) + hash = hashlib.sha1(open(path).read()).hexdigest() + print path, hash + output.write(hash + "\n") + +output.close() + diff --git a/validator/hashes.txt b/validator/hashes.txt deleted file mode 100644 index 17e26c40a..000000000 --- a/validator/hashes.txt +++ /dev/null @@ -1,72 +0,0 @@ -2c11746af7d894ed4b92d3fa69d6432eaad20343 -77c33a86bb26834d52ccd7b908290d7a4444564e -c34d6c84ec67d4a61af87b1634bc007f2d46ba91 -97e561dfeb842c21b35e6f9963914316221cca1d -fa05290dadfb7d2659a55c50b77595e23f999a74 -08341cd159e29f561ca0ec16c99bf4b85e43d30f -d3b30b0fead39e4c40fb0c91408e74439020a279 -84b1514a01def3bc0b52f6fa03d0d9fa349bef72 -4c12e01d990bd2b1075812d9f28e3ffa50ca59df -ddb4126bf4713cb4e0f2310401e58cb9e3f98997 -9d6f8bdcadd59eba977e9e31066bf393c9fdf8a4 -4a2c9fd552e1ca9ad66feaaad365990b1e664a8f -88c03b5c437ac3551661ecfbe6e1de155c3099c4 -24fdaa88685c8b2dadcc94559ceef318fdcd115b -24dd74d65d2e02aae973af97ebbb31b9820a5bbb -788bb58005b75a004cd7abbd26f942eea0391f47 -07c089df7b7a5da16f434870087d6b0e1c45d3b5 -31555f340a206de7622fb760718ef4a1b296ed44 -16306f8187df578589821e6eb6b807ac4d467d1f -384cbfe95d92a30d7c86ac07ea5de56f79c15f6a -0cafb88edcaebad82c207cdf124de1889364c9f3 -ca0aea084a63d0a56e1bbf17fde5061f631b391f -71adcc2cae87e412e521e4a7276efeaee2347927 -d97ecac3f1b3ccf1f0f68434e8406f87f5acc907 -2710cce192fcc4dc676d9572cd852f104ea59387 -c82ea9768b18696832408b6cc729e2e121def691 -6463e558dd79d51a2e8464806824c7bbc18c77fd -677c1ad6d84705c818d63a43298ee3a12959c1b3 -3bb92e84642c03cf0fe49174d0e1c420d46d2e18 -0d2bc9db63acd9cc238a4925e79f9a3079490970 -6869cb783670d6a4923aaccfe4331015961ed8d6 -8963108fa84c2033a1052d47079d7f75a7e5b60e -20860bad9c83c3890be57052f009b9d97848c9ec -9025fe9334566eb919ddca85a8f949b01c7d837d -55c7f265deba4afc1335071fafbbf7fda8f02bbe -1be9c3684054001f53fa7ff6d85ec3cb573a9cd2 -c10dbe0c2b23444d0794f3376398702d84f41583 -3aca6488dfb65cf0e600a7a70376ca1354b7377c -e0c497fc264d7706da23235266ed52acf2c7b89a -83d1b489e30275a03f568f7e3fa6537d695e0197 -6be187a67b639b65dc8427eb8e790e42bbe4d7dd -fed603a4db640b82de54b246de4be7a1cffa8780 -f0b95e99225f314fbe37ccf6b74ce2f916c517de -3dc9f7c2642efff4482e68c9d9df874bf98f5bcb -f3abd53f3725675e3e049c414749e16df11951ba -7b9e8594368d30387059e5fdef9d662095dbbf7a -6b911b0dc178423b946b0299851d9661004c21ef -bff995d3a845903f281b0b51fea421059459a808 -265a86a9d9df5dfdbad77e06c85605bec4beb32a -2c13dad3020d417aa841afbdba8548572533f9c3 -f02e1f7f1bb966d5fcf16b03daa79ee077a993f8 -b5efe44645f5358e3d785091af3440f80afa85e3 -65cbff4e9d95d47a6f31d96ab4ea361c1f538a7b -d3e67a40156f1ea0bb5110246d967da3258f2d83 -72db638e9516db4e13952e0beec37e8bb7d0b12d -e5335c2a82f26e49b1324edc21e452de040d5cdc -e956e4de8f223992e2d1362d78c5b5bb33e27497 -84067c2604750933d3fe048c1f45c1c9d8f9038c -65bfcaccbf4cf0ea3c34c86e495967fd3318540c -879550d2acbdb1679ec3163a73a6dd6f8374882e -015cf89260f3e8f0b86f5a17558125c933692989 -278d68b8e9edad4895836e272fbc8f78ec4f2f3e -c147a1a86a2c33e60f160b8861501f43f4638c8d -0b3effe3da813132e92d5f873ada776fd1c17f32 -4540775a3cb3fd95d5d344f88e74867b6f6c5573 -c9664029b47f98b41c1606e387605561006c50b7 -21a72032fbddf0f2edf9af79cbdcc2453ebc793d -a488f653834a3146793e15bdbd11266a3d9ba3ed -0bb3166ecb1bcf5111ddf59b1813cbfa513be60f -66851ab2133e27b97c4f3048416b947aa7ed82c5 -5847ed101f55d51c53538a7078971e7de8fb6762 -e96461c6c19608f528b4a3c33a032b697b999b62 diff --git a/validator/testcases/content.py b/validator/testcases/content.py index f317560b5..625c7358b 100644 --- a/validator/testcases/content.py +++ b/validator/testcases/content.py @@ -1,4 +1,4 @@ - +import hashlib from StringIO import StringIO from validator import decorator @@ -48,6 +48,10 @@ def test_packed_packages(err, package_contents=None, xpi_package=None): "Tests XPI and JAR files for naughty content." processed_files = 0 + + hash_whitelist = [x[:-1] for x in + open(os.path.join(os.path.dirname(__file__), + 'whitelist_hashes.txt')).readlines()] # Iterate each item in the package. for name, data in package_contents.items(): @@ -67,6 +71,16 @@ def test_packed_packages(err, package_contents=None, xpi_package=None): "It is recommended that you delete the file"], name) + try: + file_data = xpi_package.read(name) + except KeyError: # pragma: no cover + _read_error(err, name) + + # Skip over whitelisted hashes + hash = hashlib.sha1(file_data).hexdigest() + if hash in hash_whitelist: + continue + processed = False # If that item is a container file, unzip it and scan it. if data["extension"] == "jar": @@ -79,7 +93,7 @@ def test_packed_packages(err, package_contents=None, xpi_package=None): is_subpackage = name.count("/") > 0 # Unpack the package and load it up. - package = StringIO(xpi_package.read(name)) + package = StringIO(file_data) sub_xpi = XPIManager(package, name, is_subpackage) if not sub_xpi.zf: err.error(("testcases_content", @@ -109,7 +123,7 @@ def test_packed_packages(err, package_contents=None, xpi_package=None): # found in multi-extension packages. # Unpack! - package = StringIO(xpi_package.read(name)) + package = StringIO(file_data) err.push_state(data["name_lower"]) @@ -122,54 +136,38 @@ def test_packed_packages(err, package_contents=None, xpi_package=None): elif data["extension"] in ("xul", "xml", "html", "xhtml"): - try: - file_data = xpi_package.read(name) - except KeyError: # pragma: no cover - _read_error(err, name) - else: - parser = testendpoint_markup.MarkupParser(err) - parser.process(name, - file_data, - data["extension"]) - - processed = True + parser = testendpoint_markup.MarkupParser(err) + parser.process(name, + file_data, + data["extension"]) + + processed = True elif data["extension"] in ("css", "js", "jsm"): - try: - file_data = xpi_package.read(name) - if not file_data: - continue - - first_char = ord(file_data[0]) - if first_char > 126 or first_char < 32: - file_data = file_data[3:] - # Removed: INFO about BOM because it was too frequent. - - except KeyError: # pragma: no cover - _read_error(err, name) - else: - if data["extension"] == "css": - testendpoint_css.test_css_file(err, - name, - file_data) - elif data["extension"] in ("js", "jsm"): - testendpoint_js.test_js_file(err, - name, - file_data) - + if not file_data: + continue + + first_char = ord(file_data[0]) + if first_char > 126 or first_char < 32: + file_data = file_data[3:] + # Removed: INFO about BOM because it was too frequent. + + if data["extension"] == "css": + testendpoint_css.test_css_file(err, + name, + file_data) + elif data["extension"] in ("js", "jsm"): + testendpoint_js.test_js_file(err, + name, + file_data) # This is tested in test_langpack.py if err.detected_type == PACKAGE_LANGPACK and not processed: - try: - file_data = xpi_package.read(name) - except KeyError: # pragma: no cover - _read_error(err, name) - else: - testendpoint_langpack.test_unsafe_html(err, - name, - file_data) + testendpoint_langpack.test_unsafe_html(err, + name, + file_data) # This aids in creating unit tests. processed_files += 1 diff --git a/validator/testcases/whitelist_hashes.txt b/validator/testcases/whitelist_hashes.txt new file mode 100644 index 000000000..c3082df50 --- /dev/null +++ b/validator/testcases/whitelist_hashes.txt @@ -0,0 +1,248 @@ +c78073909ff787c120c5e8d0432122bd6cc702e8 +6b6ba702c0b16bea1864d59746774791329511ba +e9ef6be95a130ac73b8d3a9f9b4e647f49861e9c +5d7b34ef39a616136d72982a7ef84a4d6f477d72 +b0424e627009ae58967553344385a0491ec0a7f5 +4f2abc0ec67080193ed2b9d672fedf9f27053e08 +3df1792284f7b51d92e9837d45d3af372f6e0c6e +31a3cc3536b26a1bae53249cf442bc7fdd733209 +48d09b6e77e2bd52bad0b66a296d80418f38dc95 +a4887d067ad6176d5e6c426bbfb7655a14d34e22 +53ac8daf8c4547a5d6eddadb99bc55a57ef57052 +bdd6c0b37a5bab2b40bde7e4a4043f1f707fa6a2 +46b2d09e184bb183e53a27cb165d6190341abe01 +75d422fd83cf9d61bcbf8fec07774655970b3c16 +3b8aa54e2113e83158142838089e9b23e947b198 +e94c5694f1115b1313125d4fa6a5cd90c75a36e6 +2f848a79b0671464a83709e00c1147234490ea95 +fedaf6024bc6ba87c48bad00cfbd64ad37ed234c +0a4220c9da0d3124df6afb304d0be8bc8c44d01e +c0179f716f5a01d6a56c984d4d91e23773f4a992 +4c56660dc9706d7977768c5dbcfd18784a6de78d +167a15d6bf8df53e7cff8ece132b752fbfb51951 +7c9de790253e1de40b9a8932807e97ec61edbeff +3d51a2309b5139363db1bff2641131727eb754d9 +1250448ee159389e74686dd3205669f514a8141c +e678f228511e6d54f4c7ebbaae2ba70c65529fa6 +274add3b427e0ec7b4d3ee31e092fa40dfc11a54 +ed3318ba36f6bdf880ca28f54225628816a0d0da +59b882c64980a1435b2026ccb5450929631e5c68 +a8f7ecfa1c06b2ef94211e6414072bfddf93965d +9b3d08c6aa5fa4882c0bccf5a3f37b83031e748b +59333e4fc8a1caad315c52b0cee51326dd80be33 +41535b3cf9d51068d10c4a78fe4eab811a33bce7 +f4c1d10d2a166e1ecd1fb8915bae9bd00b962e22 +d9dcf12dc9e82a983ddd97a31c4df2a44cb6f76d +8630675640300173946284a9f585ffc3bc72ce0c +73ffbc69db4281ddefaf5469ae390b4004926368 +1ad666124c9bac2e99b3d6a6974b9c0cea395df6 +12a1f915aa67565a82c29812320a0cf996908652 +83d8f6c453a734b4d9145e0ada3f3dcb932d0b1d +0c4284ca2d37cebfdc61fda706b3ad4bf8923894 +4143fd40deb93b168688d71cf54727a29bc16992 +f49fe34a05476ebac98d9509ca3ce37d04685407 +d542f1ceb3d81745a9987374880e190a0b9bcf13 +865f4b4d58761b4d652994fa2564c0dd563a3207 +58501cfc2a894f07dccfa198a910dabf803215a5 +0e93dccffd6ffc2779a63bff8f8c094741fa2913 +5f77de5b9833df5599157c6c262298338439c30e +2abfce8a3a7214920c2dbf81b773141a33b7e2a3 +98718ae00b3abb881e4de09b511131613dc0feab +e6e90a597f0ba6e128460a652e079bd83a573dfa +ef614b7086f497e4603e3ad03f9db5cfddca4428 +faf853141a9c00740071569ba07701a796cb6487 +63a32f5788f8fcd73050cb7a29670c5874202dee +2035adfd9103d35eed951e72e3e7d0648aa9946f +4f26a8a8447b4d2d1f32ecac537877eadda816e0 +1c077cfcfcd72a06aca771113eaaeb99892792d5 +bd3b5cb03cc95e7bbe8568cedfb51666ee1d039c +35a7f4f416f82508dde73d29e0dfc5936c39501e +2a62ace9f1bd93a3d9a5f7d27ddd7ef643ebf3b6 +65d7472c398389f2949563f96bab3439100dd40a +a8b9c705dd6d424f4432d78414bd0eb06402ef72 +1ee146c086c76a9a9ef1982da4f2ac7bed724846 +c2d9fcb4398924042bcb973c60ebc34675eb62a7 +604a5a3143c9578104d2d794ab233a12cd62314c +b7677b1ebee4732b809189e3fa6e03c3831e3a47 +bfb2993a20a4c9b1435221f87f6fc863b88f1a8d +2309545dbeddfb5f17b1116f6c5be5e13392b003 +3344f35bb128564124ef161585ae3b57fb2ad4e9 +2b53d42dddd2b0f8e58a989008e1268290f0d0f9 +94e0f55f9680bae9c7c46ff97a43c0d4f96ecdac +17905577e197bf823cf4ca3bb2523c00dabfc8ed +9edd823cb1ded6c2a1962c99ca69e0c4a5348fea +275dfe87beca92223f1fa937456e1aa8cc1428fd +e5ec1ce98e9f4a5554186983db413d09fcd740bd +ad6cbce93f61c6b0db13916c3d4f69e652c24f69 +723e273c5934f59c1fbecc52ecc820fa891389c8 +f0c4a68751b1e6e197ae3e4f20118131c7bbc3da +d3993aa58465fbaf7361a153f840957930297125 +8105658a79525568ed35f87eb935427ab8f33349 +caaf61bb5d33c625714b170c3eb0a5254940542f +0b2d400d3162142217857768e7f4779253540d80 +77df07717e76bc16c364c29928e939b660272e30 +9f4fabaf4a83109eead9097a368f633be114e8f8 +e0617fc7d0948d70fa42007e8f83b0fcf00e2acb +e230233dd73cddc54eeabef992a8f69535d72e56 +8dd78b1b2affb21f80e54b5cb62197541c69baa5 +4852f25cf990a45c32f7da115605973645d22e5b +00c6f79a678a6aec3eeb47b272d704b87ba33141 +9ac68a019a39649061518278b22eef866025bfc7 +d0af3ee2435a6e47322ad2822309dfe46358434c +7291fc93b5acfdbe178369105537128d1efe98b8 +16f4f76405cbaf3f252101a6d57f1264e830b208 +31e0156d3044ad07b24dd40b4c41da50eb421098 +64c6446328d365bee3641e90a6fa6219a41d7596 +5dd165e1ce499e7b734cfb8b23aa84c53f41e34c +64c6446328d365bee3641e90a6fa6219a41d7596 +a7def92fd6efb62d63dc4f7823ff99091b082fca +c586cf886a809062dee3b063a9a7effdf1abb8b0 +da39a3ee5e6b4b0d3255bfef95601890afd80709 +f1a7ce0ba24912203ee0413073ab705ba55400f7 +da39a3ee5e6b4b0d3255bfef95601890afd80709 +64c6446328d365bee3641e90a6fa6219a41d7596 +abcb52add9d5f2b0fbe6671cd0f7a1d7da6b2d37 +1785a52ba1e464d14fa71bceeef407cca668f0c5 +64c6446328d365bee3641e90a6fa6219a41d7596 +02b44083e325e4793270dec2fd8a705be80afcef +4e4ee9105ef26d3123b76d85f752888041c54db4 +64c6446328d365bee3641e90a6fa6219a41d7596 +382062cc3d5bcc0b1e67f74f0797f5a5086e478b +83d0b0dd7f3b66e29ffd1a09577d2440c8ec9d91 +0f2a32e1f4e29076dd9943baf1ee94ee0a862501 +64c6446328d365bee3641e90a6fa6219a41d7596 +5d20e6cb397a26eca51cddaa97d7531ed17a34ab +64c6446328d365bee3641e90a6fa6219a41d7596 +ebfa6b0b4118d2c131654cea3c6b7081001e00b7 +68d0ea44ff19f77bbda79ab4493debf5f6d2000f +2b7d5b1752d73e0de64f8002703e9aafe0dba5f7 +64c6446328d365bee3641e90a6fa6219a41d7596 +319e65d40bf4057bf1ddf8c61ae333fcf4fc0d24 +71853c6197a6a7f222db0f1978c7cb232b87c5ee +b8c26c01d251dde40c3e82ebb5d1a81ee4c2abe6 +0c74f1e3da7dd4acaf04e4602463b4ad50e3e62e +64c6446328d365bee3641e90a6fa6219a41d7596 +a363b3b8288f65a910453624fd654e3bf80cfed8 +f05bffa027e1f77afb0b5223535c49d949c60b13 +9272d9e6b56477a2850203b9c9c3dc7c2c8f9c32 +64c6446328d365bee3641e90a6fa6219a41d7596 +da39a3ee5e6b4b0d3255bfef95601890afd80709 +53bbf7b6380c647c49b06bdfa9158e07dd0944bc +64c6446328d365bee3641e90a6fa6219a41d7596 +7bee7f4a7e3f5f22b3bf9b7936e562f682a1bc53 +7bee7f4a7e3f5f22b3bf9b7936e562f682a1bc53 +8e7f524fb522e17506e8756771f920b13023362e +975783faab2ab971e287f43259aed99cc1e923a8 +64c6446328d365bee3641e90a6fa6219a41d7596 +757eb49d39a2f8b92f23a2edec4041292d7a2770 +d9ddac2a3feb997b851419cd868662f206d0a069 +d177ac4d4ccec95097046f8f20caf62a5922bf61 +511ded6c35fb9e9892e2d17a57d0f8bacd153ba8 +722b96aeb53f7ac8f812e9b63f4bbafa7ab18a6f +41bb27195021ac219b4be075187b842bb7a7ab1d +7ded44700f3e7b8a897214b2f8bd9057614ca808 +e146421839259cfda71659cc9a884c93ea57c062 +5c372ab96c721258c5c12bb8ead291bbba5dace6 +9cc5a6e4a42b3f3801cbfbbff89cfa07e8eb1ced +25092ffda5ceefee8ed710f6507eec995cbcbdf8 +8a4b752e7d81ef91eb266f1b6ca778adba6a0293 +da39a3ee5e6b4b0d3255bfef95601890afd80709 +38d1e553eb2e2e2e85999b5601c498c0f7c33942 +2c8531b0fe646d34ea195e22940e67ea6bc6f82f +5be5bf4e70a31504be94479958f3754a83fe76d9 +3557fe3397f13b90afcf99e858a74e57a033adf5 +d0a326ea96c4138bd8d2ae06d8a3ade9035bcc20 +63668896bf632665d503c999923ccb076d73d0fe +0e99f7e42056d93337f1f563b73d49b8a75e6a6d +f6b772c352b48997267d01c523e059995d082280 +3e3280ac32caf03ad996391987258a89e1aadafe +aa8d7ad05e120b3845a1163d0c95aabf8fc0295b +23d415ac71cedf6d1636f269f680f3845ba7ff1d +b37609c77c8e140b20e14e7041ae125c10f34154 +29e2b12fcad666ecb390ee15c32a614be53cfe94 +332bc86664ac67ffb6bcb31e44140633c9e3e531 +ed2e36aa03894210357ea63309e69e4fe6dc88bd +bfdcf8a17d78cef163795c2f40ed7fd247f74537 +101f991bd7b1ef9bbb1833caa8c3db788354328f +72dac552747b3ddf8b721ca01997c18f1fd78f19 +1171b987220cc31176f8c98f2cde433a051ebc8b +8ee0df618dbdfc4504a7b2b94ee92a4d1a2d7b32 +0c1af85f326b78e8c437094abf220e988736216a +085d7cbfe90f7b5dac957caf42540af5531e7a29 +2482bd7588388bdc38fb02074d1d9d3164c6a650 +46757d6caf06a9a0186056dc8d1f9cbc83838d8c +546d673e6e6709adf1dd863b87913d9fd1c2e5b8 +c9cb4383ae419cd6a7b474f614f2a0785ed3a0e7 +3bb6a13b304e29bc6318e15e0db27cd865d2ee9f +a3111de2b318b62f62097d87ec45528024f2c787 +72c3a75f3fa615aa0e80c329dfff1e404bb0a364 +d3d7b744a11335857aeb4d40cfa57910770962e8 +3afe2b21766e4bd70d8ceb1bf508885d43a07cdd +5517f2a2032f59220236fc50369b9ab6f3c9e096 +27e101af0e01835b0d6a36ac90a214688f00265f +f1ffbe3be94e7837b0d2bab388db1ea972144332 +ae113dfb29ea55fff93faf06e8b607cce630b764 +e6ba79076cfc5ac627f26c04f73aab476fb3c483 +8a04bbb5762fd87e0065cc8e2d559e756b226c80 +059a05e8c91321cb7ff16c5730f97c9e75b899e4 +cb2f85229d1cc1f90b5c0b38a8ef2fe7dd3809e9 +380f0fbf831d5bff0c8d9f9b384bf9a32c5afe8c +ef083d368a3b5935d7126b0d5bfd763462650548 +583f6caaddff8474b9a4a1a3937c7d720f0b1426 +41da0b33fd4a5f4242aa6d7a8ef72db2bba827da +efa9898fe72827bef2e6d1e96acb9f75890abf2d +c57c1c85a90c4763416ebaea6236f50b0cc886a1 +41c8ab8fc41b9ac6efbbcb2875c5e779007e8c77 +79e77bfbd37ebc63ea479e12c920182b961ebe7e +558cb033d321ebfd001fc1188f3eff9f0e162400 +d4ef2d96c395a6a2f71f321fd2bad95023f95a32 +a55fa98d660369a073a7f655b0cc29a0bd687084 +9533b69f1f589e8fb86bbe8868e09f6acc904859 +33b705f8ed2ed8ab215e2d8c801ac9d15e23874c +16e861197d79343580fb104fcac3d9ec52ac943e +f5d78f276713b2ec21ff9da8668e05023e635e01 +bbf7183bb51718ab42ce194ae795c7a95c8dcede +0596bb33c3ac2f65a1cf44a8f8f51a341313403c +31ab70afe1dd7677dd27bf5cc8161aeec89c65fe +97312d71cc2222668eacce85666bf254d8c233a7 +2e40a5e7eccdff057b0563f9892bc5dfd9561bbe +6d930a9ea9bf8a9ad5c62730c03d0bd671785ece +d7ad051b4cd2b6010b664100bc16d4028d06575b +c9a90c7d2ff9ba7898d59bfa7320be5e6b4c9213 +bf90633a9c6e4ab0736c53282d647f836a207a2d +e5cfac3d6315170ff399ac3b298316c780f07492 +2c53193943818d4b32e7bc93831d1bc848dcc97e +1c0b89f1c15d3b09557bfe9e14cd0a198951e66b +9d98fe0f6052a56f2ae7c6133bf0db108560f7db +72fc26649c78ef61746ebc90225af23a14c12d70 +a23bfe53b73490b6631af71db3b6d1725fa82ccb +f292a635070071403cb07a4a6e28df025fb931e4 +269849283390dd37dc6cfbfdd8646807942a5f51 +0dd1da32a92b2f5548f6642b08fd30303531e7ca +477d838ead852deeec21e151c3634f492cb9ae5a +8d7c4be093542ea378471c41610b07365e9e96a4 +5bd24793eb0a90a90c39bdcf8ac38972ba0d1500 +3411c9e1154e09b312c7b6fd99a114ef98b353dd +edb38ccfcf532841ecc01386c598d39eae083d8c +285224dc7e622894f4b3552e601851fcf2261762 +5165109f4ed354f3b142452c6b3ab0252fb7e243 +191d21a6f16c13e3231a7dfb6be771e267772701 +8b47f866818291ea0cd12eb6c53bd46bb127774b +7733f41b7603f2d64668ae4c9a09cb2e900f8aa0 +a8f6e80f013578d1142199fbaaa946d0ca23adf9 +ae61280b95af4afd8d5332ea7aa2c66890a9729d +9785ae8aa9603c024a45aced9555c34d96826cc1 +ae9c18d0feda3c6a14a2a59b168921a143bc40fa +073295d442743af472985f10cb94302d7135a064 +8e8d58f6b46d1f2570f0e41f27282c6c5e30358b +814b53b9e6a6d80d849b15d586e512d4286255d8 +2af066d31cd230775e77738c5a2b5cd0b402d522 +5a00e90091d59fc660f699f1db115a360e3f4855 +cce68b5f5a70ca325ac619166e28eed57f5c95ad +f5b72313fc51a89fe0e14ebb820a759e4073393f +5e2d3484ddab0c75ae6e8a76a7812430af7184d7 +6f9222e5df5a03274effe02cfd50a84b8b7f9665 +5ae4cb609f1cb54e2ca88c0850f839e04ac97c95 +57f215aa45476193273bfc45057af98ba131ccba +d15edcfb9e67f7e90632cad9d6d479b587105aa0 +c2bb3097fb9a26135307d337e307c0104ee18570