--41333375-49397760-3247867773=:9006 Content-Type: text/plain; Charset=US-ASCII Content-Transfer-Encoding: 7bit Folks, I've attached a proof-of-concept patch to import.c that implements the sys.import_hooks idea I outlined earlier. Here's an updated description. - sys.import_hooks is a list of hooks. - A hook is a callable object taking two arguments: 'modulename' and 'path'. 'path' is either the parents package's __path__ or None, 'modulename' is *always* a "simple" name: no dots. - Hooks are never called for modules already in sys.modules. - A hook either returns None ("module not found") or a two-tuple: (loadfunc, data). loadfunc is a callable object that will be called with two arguments: the 'fullname' and 'data'. 'data' is just an arbitrary object, private to the hook. The loaderfunc must return the imported module. It _may_ add the module to sys.modules, but it doesn't need to. - A hook is not supposed to fail: it should return None or a (loader, data) tuple. If a hook _does_ fail with an exception, the import is aborted and subsequent hooks won't get called. The exception will be propagated to the caller. (XXX this is perhaps brittle; maybe errors need to be ignored by default, or a warning should be issued instead.) sys.import_hooks currently gets filled with a default hook: imp.builtin_import_hook. This is simply a wrapper around find_module() and friends. Perhaps it's an idea to split it into discrete hooks for builtin, frozen, and file system imports. This can be done later. An alternative to the current default hook would be to keep sys.import_hooks empty by default and fall back to find_module/load_module if no hook managed to find/load the module. Pro: this would allow for some optimizations, as the hook mechanism would be bypassed (and therefore less code in import.c). Con: it would then be awkward to completely disable the builtin import mechanism, it's less transparent, less elegant. (Ok, I thought a bit more about this: I don't like it at all. All imports should be done by a hook on sys.import_hooks. If sys.import_hooks is empty, _any_ new import will fail.) Rationale: - Make writing import hooks simpler; this new scheme avoids much of the complexity involved in writing a traditional __import__ hook. Real rationale: - Allow the "Import from Zip archive" patch to be rewritten as an external module, avoiding the huge mess it is right now, as it touches more or less all of import.c and then some. Paul Moore is doing an admirable job to get it working and cleaned up, but I honestly don't see this getting into the core: it's such a huge and complex patch that it's almost impossible to properly review. It's a maintainance nightmare waiting to happen. And let's face it, import.c isn't all that maintainable as it is... Longer term rationale: - It would allow us to refactor the builtin import mechanism(s) by writing specialized hooks, replacing the current monolithic find_module/load_module code. Con: It is slower for first-time imports. If you care, go ahead and measure ;-) Comments? Just --41333375-49397760-3247867773=:9006 Content-Type: application/octet-stream; Name="newimporthook.patch"; X-Mac-Type="54455854"; X-Mac-Creator="522A6368" Content-Transfer-Encoding: base64 Content-Disposition: attachment; Filename="newimporthook.patch" SW5kZXg6IFB5dGhvbi9pbXBvcnQuYwo9PT09PT09PT09PT09PT09PT09PT09PT09 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ClJDUyBm aWxlOiAvY3Zzcm9vdC9weXRob24vcHl0aG9uL2Rpc3Qvc3JjL1B5dGhvbi9pbXBv cnQuYyx2CnJldHJpZXZpbmcgcmV2aXNpb24gMi4yMTEKZGlmZiAtYyAtcjIuMjEx IGltcG9ydC5jCioqKiBQeXRob24vaW1wb3J0LmMJMjkgTm92IDIwMDIgMjA6NDc6 NDAgLTAwMDAJMi4yMTEKLS0tIFB5dGhvbi9pbXBvcnQuYwkyIERlYyAyMDAyIDIz OjQwOjUwIC0wMDAwCioqKioqKioqKioqKioqKgoqKiogMTA1LDExMCAqKioqCi0t LSAxMDUsMTI4IC0tLS0KICB9OwogICNlbmRpZgogIAorIC8qIGltcG9ydF9ob29r cyBzdHVmZiwgcHJvYmFibHkgbmVlZHMgcmVvcmdhbml6YXRpb24gKi8KKyAvKiBm b3J3YXJkIGRlY2xzICovCisgc3RhdGljIEZJTEUgKmdldF9maWxlKGNoYXIgKnBh dGhuYW1lLCBQeU9iamVjdCAqZm9iLCBjaGFyICptb2RlKTsKKyBzdGF0aWMgUHlP YmplY3QgKmNhbGxfZmluZF9tb2R1bGUoY2hhciAqbmFtZSwgUHlPYmplY3QgKnBh dGgpOworIAorIC8qICJtYW51YWwiIGNvbnN0cnVjdGlvbiBvZiB0d28gQ0Z1bmN0 aW9uIG9iamVjdHM7IGNhbid0IHVzZSB0aGUKKyAgICByZWd1bGFyIG1lY2hhbmlz bSBhcyB3ZSBuZWVkIHRoZXNlIGZ1bmN0aW9uIG9iamVjdHMgZXZlbiBpZiB0aGUK KyAgICBpbXAgbW9kdWxlIGlzbid0IGltcG9ydGVkLiAqLworIHN0YXRpYyBQeU9i amVjdCAqaW1wX2J1aWx0aW5faW1wb3J0X2hvb2soUHlPYmplY3QgKnNlbGYsIFB5 T2JqZWN0ICphcmdzKTsKKyBzdGF0aWMgUHlNZXRob2REZWYgYnVpbHRpbl9pbXBv cnRfaG9va19kZWYgPSAKKyAJeyJidWlsdGluX2ltcG9ydF9ob29rIiwgaW1wX2J1 aWx0aW5faW1wb3J0X2hvb2ssIE1FVEhfVkFSQVJHUywgIlhYWCJ9OworIHN0YXRp YyBQeU9iamVjdCAqYnVpbHRpbl9pbXBvcnRfaG9va19mdW5jID0gTlVMTDsKKyAK KyBzdGF0aWMgUHlPYmplY3QgKmltcF9idWlsdGluX2xvYWRlcihQeU9iamVjdCAq c2VsZiwgUHlPYmplY3QgKmFyZ3MpOworIHN0YXRpYyBQeU1ldGhvZERlZiBidWls dGluX2xvYWRlcl9kZWYgPSAKKyAJeyJidWlsdGluX2xvYWRlciIsIGltcF9idWls dGluX2xvYWRlciwgTUVUSF9WQVJBUkdTLCAiWFhYIn07Cisgc3RhdGljIFB5T2Jq ZWN0ICpidWlsdGluX2xvYWRlcl9mdW5jID0gTlVMTDsKKyAKICAvKiBJbml0aWFs aXplIHRoaW5ncyAqLwogIAogIHZvaWQKKioqKioqKioqKioqKioqCioqKiAxMTQs MTE5ICoqKioKLS0tIDEzMiwxMzggLS0tLQogIAlzdHJ1Y3QgZmlsZWRlc2NyICpm aWxldGFiOwogIAlpbnQgY291bnREID0gMDsKICAJaW50IGNvdW50UyA9IDA7Cisg CVB5T2JqZWN0ICppbXBvcnRfaG9va3M7CiAgCiAgCS8qIHByZXBhcmUgX1B5SW1w b3J0X0ZpbGV0YWI6IGNvcHkgZW50cmllcyBmcm9tCiAgCSAgIF9QeUltcG9ydF9E eW5Mb2FkRmlsZXRhYiBhbmQgX1B5SW1wb3J0X1N0YW5kYXJkRmlsZXRhYi4KKioq KioqKioqKioqKioqCioqKiAxNTAsMTU1ICoqKioKLS0tIDE2OSwxODUgLS0tLQog IAkJICAgY29kZSBjcmVhdGVkIGluIG5vcm1hbCBvcGVyYXRpb24gbW9kZS4gKi8K ICAJCXB5Y19tYWdpYyA9IE1BR0lDICsgMTsKICAJfQorIAorIAkvKiBTZXR1cCBz eXMuaW1wb3J0X2hvb2tzOyBjcmVhdGUgZnVuY3Rpb24gb2JqZWN0cyBmb3IgdGhl CisgCSAgIGRlZmF1bHQgaG9vayBhbmQgbWF0Y2hpbmcgbG9hZGVyIGZ1bmN0aW9u cy4gKi8KKyAJYnVpbHRpbl9pbXBvcnRfaG9va19mdW5jID0gUHlDRnVuY3Rpb25f TmV3KCZidWlsdGluX2ltcG9ydF9ob29rX2RlZiwKKyAJCQkJCQkgICBOVUxMKTsK KyAJYnVpbHRpbl9sb2FkZXJfZnVuYyA9IFB5Q0Z1bmN0aW9uX05ldygmYnVpbHRp bl9sb2FkZXJfZGVmLCBOVUxMKTsKKyAJaW1wb3J0X2hvb2tzID0gUHlfQnVpbGRW YWx1ZSgiW09dIiwgYnVpbHRpbl9pbXBvcnRfaG9va19mdW5jKTsKKyAJaWYgKGlt cG9ydF9ob29rcyAhPSBOVUxMKSB7CisgCQlQeVN5c19TZXRPYmplY3QoImltcG9y dF9ob29rcyIsIGltcG9ydF9ob29rcyk7CisgCQlQeV9ERUNSRUYoaW1wb3J0X2hv b2tzKTsKKyAJfQogIH0KICAKICB2b2lkCioqKioqKioqKioqKioqKgoqKiogMjQ2 LDI1MiAqKioqCiAgCSJwYXRoIiwgImFyZ3YiLCAicHMxIiwgInBzMiIsICJleGl0 ZnVuYyIsCiAgCSJleGNfdHlwZSIsICJleGNfdmFsdWUiLCAiZXhjX3RyYWNlYmFj ayIsCiAgCSJsYXN0X3R5cGUiLCAibGFzdF92YWx1ZSIsICJsYXN0X3RyYWNlYmFj ayIsCiEgCU5VTEwKICB9OwogIAogIHN0YXRpYyBjaGFyKiBzeXNfZmlsZXNbXSA9 IHsKLS0tIDI3NiwyODIgLS0tLQogIAkicGF0aCIsICJhcmd2IiwgInBzMSIsICJw czIiLCAiZXhpdGZ1bmMiLAogIAkiZXhjX3R5cGUiLCAiZXhjX3ZhbHVlIiwgImV4 Y190cmFjZWJhY2siLAogIAkibGFzdF90eXBlIiwgImxhc3RfdmFsdWUiLCAibGFz dF90cmFjZWJhY2siLAohIAkiaW1wb3J0X2hvb2tzIiwgTlVMTAogIH07CiAgCiAg c3RhdGljIGNoYXIqIHN5c19maWxlc1tdID0gewoqKioqKioqKioqKioqKioKKioq IDE5NjEsMTk2NiAqKioqCi0tLSAxOTkxLDIxMTAgLS0tLQogIH0KICAKICBzdGF0 aWMgUHlPYmplY3QgKgorIGltcF9idWlsdGluX2ltcG9ydF9ob29rKFB5T2JqZWN0 ICpzZWxmLCBQeU9iamVjdCAqYXJncykgeworIAljaGFyICpuYW1lOworIAlQeU9i amVjdCAqcGF0aCwgKnJlczsKKyAJCisgCWlmICghUHlBcmdfUGFyc2VUdXBsZShh cmdzLCAic08iLCAmbmFtZSwgJnBhdGgpKQorIAkJcmV0dXJuIE5VTEw7CisgCWlm IChwYXRoID09IFB5X05vbmUpCisgCQlwYXRoID0gTlVMTDsKKyAJcmVzID0gY2Fs bF9maW5kX21vZHVsZShuYW1lLCBwYXRoKTsKKyAJaWYgKHJlcyA9PSBOVUxMKSB7 CisgCQlpZiAoIVB5RXJyX0V4Y2VwdGlvbk1hdGNoZXMoUHlFeGNfSW1wb3J0RXJy b3IpKQorIAkJCXJldHVybiBOVUxMOworIAkJUHlFcnJfQ2xlYXIoKTsKKyAJCVB5 X0lOQ1JFRihQeV9Ob25lKTsKKyAJCXJldHVybiBQeV9Ob25lOworIAl9CisgCXJl dHVybiBQeV9CdWlsZFZhbHVlKCIoT08pIiwgYnVpbHRpbl9sb2FkZXJfZnVuYywg cmVzKTsKKyB9CisgCisgc3RhdGljIFB5T2JqZWN0ICoKKyBpbXBfYnVpbHRpbl9s b2FkZXIoUHlPYmplY3QgKnNlbGYsIFB5T2JqZWN0ICphcmdzKSB7CisgCWNoYXIg KmZ1bGxuYW1lLCAqcGF0aG5hbWUsICpzdWZmaXgsICptb2RlOworIAlpbnQgdHlw ZTsKKyAJUHlPYmplY3QgKmRhdGEsICpmb2IsICptb2Q7CisgCUZJTEUgKmZwOwor IAorIAlpZiAoIVB5QXJnX1BhcnNlVHVwbGUoYXJncywgInNPOmJ1aWx0aW5fbG9h ZGVyIiwKKyAJCQkgICAgICAmZnVsbG5hbWUsICZkYXRhKSkKKyAJCXJldHVybiBO VUxMOworIAlpZiAoIVB5QXJnX1BhcnNlVHVwbGUoZGF0YSwgIk9zKHNzaSk6YnVp bHRpbl9sb2FkZXIiLAorIAkJCSAgICAgICZmb2IsICZwYXRobmFtZSwgJnN1ZmZp eCwKKyAJCQkgICAgICAmbW9kZSwgJnR5cGUpKQorIAkJcmV0dXJuIE5VTEw7Cisg CS8qIFhYWCBjaGVjayBtb2RlLCBhcyBpbiBsb2FkX21vZHVsZSwgYnV0IHRoZSBj b2RlIG5lZWRzIHJlZmFjdG9yaW5nICovCisgCWlmIChmb2IgPT0gUHlfTm9uZSkK KyAJCWZwID0gTlVMTDsKKyAJZWxzZSB7CisgCQlpZiAoIVB5RmlsZV9DaGVjayhm b2IpKSB7CisgCQkJUHlFcnJfU2V0U3RyaW5nKFB5RXhjX1ZhbHVlRXJyb3IsCisg CQkJCSJsb2FkX21vZHVsZSBhcmcjMiBzaG91bGQgYmUgYSBmaWxlIG9yIE5vbmUi KTsKKyAJCQlyZXR1cm4gTlVMTDsKKyAJCX0KKyAJCWZwID0gZ2V0X2ZpbGUocGF0 aG5hbWUsIGZvYiwgbW9kZSk7CisgCQlpZiAoZnAgPT0gTlVMTCkKKyAJCQlyZXR1 cm4gTlVMTDsKKyAJfQorIAltb2QgPSBsb2FkX21vZHVsZShmdWxsbmFtZSwgZnAs IHBhdGhuYW1lLCB0eXBlKTsKKyAJaWYgKGZwKQorIAkJZmNsb3NlKGZwKTsKKyAJ cmV0dXJuIG1vZDsKKyB9CisgCisgc3RhdGljIFB5T2JqZWN0ICoKKyBmaW5kX21v ZHVsZTIoY2hhciAqc3VibmFtZSwgUHlPYmplY3QgKnBhdGgpCisgeworIAlpbnQg aSwgbmhvb2tzOworIAlQeU9iamVjdCAqYXJncywgKnJlcyA9IE5VTEw7CisgCVB5 T2JqZWN0ICppbXBvcnRfaG9va3MgPSBQeVN5c19HZXRPYmplY3QoImltcG9ydF9o b29rcyIpOworIAorIAlpZiAoaW1wb3J0X2hvb2tzID09IE5VTEwgfHwgIVB5TGlz dF9DaGVjayhpbXBvcnRfaG9va3MpKSB7CisgCQlQeUVycl9TZXRTdHJpbmcoUHlF eGNfSW1wb3J0RXJyb3IsCisgCQkJCSJzeXMuaW1wb3J0X2hvb2tzIG11c3QgYmUg YSBsaXN0IG9mIGltcG9ydCBob29rcyIpOworIAkJcmV0dXJuIE5VTEw7CisgCX0K KyAJaWYgKHBhdGggPT0gTlVMTCkKKyAJCXBhdGggPSBQeV9Ob25lOworIAlhcmdz ID0gUHlfQnVpbGRWYWx1ZSgiKHNPKSIsIHN1Ym5hbWUsIHBhdGgpOworIAlpZiAo YXJncyA9PSBOVUxMKQorIAkJcmV0dXJuIE5VTEw7CisgCW5ob29rcyA9IFB5TGlz dF9TaXplKGltcG9ydF9ob29rcyk7CisgCWZvciAoaSA9IDA7IGkgPCBuaG9va3M7 IGkrKykgeworIAkJUHlPYmplY3QgKmhvb2sgPSBQeUxpc3RfR2V0SXRlbShpbXBv cnRfaG9va3MsIGkpOworIAkJaWYgKGhvb2sgPT0gTlVMTCkKKyAJCQlnb3RvIGVy cm9yOworIAkJcmVzID0gUHlPYmplY3RfQ2FsbChob29rLCBhcmdzLCBOVUxMKTsK KyAJCWlmIChyZXMgPT0gTlVMTCkKKyAJCQlnb3RvIGVycm9yOworIAkJaWYgKHJl cyAhPSBQeV9Ob25lKQorIAkJCWJyZWFrOworIAkJUHlfREVDUkVGKHJlcyk7Cisg CQlyZXMgPSBOVUxMOworIAkJY29udGludWU7CisgCX0KKyAJaWYgKHJlcyA9PSBO VUxMKSB7CisgCQlQeV9JTkNSRUYoUHlfTm9uZSk7CisgCQlyZXMgPSBQeV9Ob25l OworIAl9CisgZXJyb3I6CisgCVB5X0RFQ1JFRihhcmdzKTsKKyAJcmV0dXJuIHJl czsKKyB9CisgCisgc3RhdGljIFB5T2JqZWN0ICoKKyBsb2FkX21vZHVsZTIoY2hh ciAqZnVsbG5hbWUsIFB5T2JqZWN0ICpmaW5kZXJfcmVzdWx0KQorIHsKKyAJUHlP YmplY3QgKmxvYWRlcmZ1bmMsICpkYXRhLCAqYXJncywgKm1vZDsKKyAJCisgCWlm ICghUHlBcmdfUGFyc2VUdXBsZShmaW5kZXJfcmVzdWx0LCAiT08iLCAmbG9hZGVy ZnVuYywgJmRhdGEpKQorIAkJcmV0dXJuIE5VTEw7CisgCWFyZ3MgPSBQeV9CdWls ZFZhbHVlKCIoc08pIiwgZnVsbG5hbWUsIGRhdGEpOworIAlpZiAoYXJncyA9PSBO VUxMKQorIAkJcmV0dXJuIE5VTEw7CisgCW1vZCA9IFB5T2JqZWN0X0NhbGwobG9h ZGVyZnVuYywgYXJncywgTlVMTCk7CisgCVB5X0RFQ1JFRihhcmdzKTsKKyAJaWYg KG1vZCAhPSBOVUxMICYmIG1vZCAhPSBQeV9Ob25lKSB7CisgCQkvKiBpbnNlcnQg bW9kdWxlIGluIHN5cy5tb2R1bGVzLCBpZiBpdCBpc24ndCB0aGVyZSB5ZXQgKi8K KyAJCVB5T2JqZWN0ICptb2R1bGVzID0gUHlJbXBvcnRfR2V0TW9kdWxlRGljdCgp OworIAkJaWYgKFB5RGljdF9HZXRJdGVtU3RyaW5nKG1vZHVsZXMsIGZ1bGxuYW1l KSA9PSBOVUxMKQorIAkJCVB5RGljdF9TZXRJdGVtU3RyaW5nKG1vZHVsZXMsIGZ1 bGxuYW1lLCBtb2QpOworIAl9CisgCXJldHVybiBtb2Q7CisgfQorIAorIHN0YXRp YyBQeU9iamVjdCAqCiAgaW1wb3J0X3N1Ym1vZHVsZShQeU9iamVjdCAqbW9kLCBj aGFyICpzdWJuYW1lLCBjaGFyICpmdWxsbmFtZSkKICB7CiAgCVB5T2JqZWN0ICpt b2R1bGVzID0gUHlJbXBvcnRfR2V0TW9kdWxlRGljdCgpOwoqKioqKioqKioqKioq KioKKioqIDE5NzYsMTk4NCAqKioqCiAgCX0KICAJZWxzZSB7CiAgCQlQeU9iamVj dCAqcGF0aDsKLSAJCWNoYXIgYnVmW01BWFBBVEhMRU4rMV07Ci0gCQlzdHJ1Y3Qg ZmlsZWRlc2NyICpmZHA7Ci0gCQlGSUxFICpmcCA9IE5VTEw7CiAgCiAgCQlpZiAo bW9kID09IFB5X05vbmUpCiAgCQkJcGF0aCA9IE5VTEw7Ci0tLSAyMTIwLDIxMjUg LS0tLQoqKioqKioqKioqKioqKioKKioqIDE5OTEsMjAwOSAqKioqCiAgCQkJfQog IAkJfQogIAohIAkJYnVmWzBdID0gJ1wwJzsKISAJCWZkcCA9IGZpbmRfbW9kdWxl KHN1Ym5hbWUsIHBhdGgsIGJ1ZiwgTUFYUEFUSExFTisxLCAmZnApOwohIAkJUHlf WERFQ1JFRihwYXRoKTsKISAJCWlmIChmZHAgPT0gTlVMTCkgewohIAkJCWlmICgh UHlFcnJfRXhjZXB0aW9uTWF0Y2hlcyhQeUV4Y19JbXBvcnRFcnJvcikpCiEgCQkJ CXJldHVybiBOVUxMOwohIAkJCVB5RXJyX0NsZWFyKCk7CiAgCQkJUHlfSU5DUkVG KFB5X05vbmUpOwogIAkJCXJldHVybiBQeV9Ob25lOwogIAkJfQohIAkJbSA9IGxv YWRfbW9kdWxlKGZ1bGxuYW1lLCBmcCwgYnVmLCBmZHAtPnR5cGUpOwohIAkJaWYg KGZwKQohIAkJCWZjbG9zZShmcCk7CiAgCQlpZiAobW9kICE9IFB5X05vbmUpIHsK ICAJCQkvKiBJcnJlc3BlY3RpdmUgb2YgdGhlIHN1Y2Nlc3Mgb2YgdGhpcyBsb2Fk LCBtYWtlIGEKICAJCQkgICByZWZlcmVuY2UgdG8gaXQgaW4gdGhlIHBhcmVudCBw YWNrYWdlIG1vZHVsZS4KLS0tIDIxMzIsMjE0OCAtLS0tCiAgCQkJfQogIAkJfQog IAohIAkJcmVzID0gZmluZF9tb2R1bGUyKHN1Ym5hbWUsIHBhdGgpOwohIAkJaWYg KHJlcyA9PSBOVUxMKQohIAkJCS8qIGZpbmRpbmcgcmFpc2VkIGFuIGVycm9yICov CiEgCQkJcmV0dXJuIE5VTEw7CiEgCQlpZiAocmVzID09IFB5X05vbmUpIHsKISAJ CQkvKiB0aGUgbW9kdWxlIHdhc24ndCBmb3VuZCAqLwogIAkJCVB5X0lOQ1JFRihQ eV9Ob25lKTsKICAJCQlyZXR1cm4gUHlfTm9uZTsKICAJCX0KISAJCW0gPSBsb2Fk X21vZHVsZTIoZnVsbG5hbWUsIHJlcyk7CiEgCiAgCQlpZiAobW9kICE9IFB5X05v bmUpIHsKICAJCQkvKiBJcnJlc3BlY3RpdmUgb2YgdGhlIHN1Y2Nlc3Mgb2YgdGhp cyBsb2FkLCBtYWtlIGEKICAJCQkgICByZWZlcmVuY2UgdG8gaXQgaW4gdGhlIHBh cmVudCBwYWNrYWdlIG1vZHVsZS4KKioqKioqKioqKioqKioqCioqKiAyNzI0LDI3 MjkgKioqKgotLS0gMjg2MywyODcyIC0tLS0KICAJaWYgKHNldGludChkLCAiUFlf RlJPWkVOIiwgUFlfRlJPWkVOKSA8IDApIGdvdG8gZmFpbHVyZTsKICAJaWYgKHNl dGludChkLCAiUFlfQ09ERVJFU09VUkNFIiwgUFlfQ09ERVJFU09VUkNFKSA8IDAp IGdvdG8gZmFpbHVyZTsKICAKKyAJaWYgKFB5RGljdF9TZXRJdGVtU3RyaW5nKGQs ICJidWlsdGluX2ltcG9ydF9ob29rIiwgYnVpbHRpbl9pbXBvcnRfaG9va19mdW5j KSA8IDApCisgCQlnb3RvIGZhaWx1cmU7CisgCWlmIChQeURpY3RfU2V0SXRlbVN0 cmluZyhkLCAiYnVpbHRpbl9sb2FkZXIiLCBidWlsdGluX2xvYWRlcl9mdW5jKSA8 IDApCisgCQlnb3RvIGZhaWx1cmU7CiAgICBmYWlsdXJlOgogIAk7CiAgfQo= --41333375-49397760-3247867773=:9006--
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4