diff --git a/README.md b/README.md index 499ab1abb6c9322233c2b50b84ba71fe2a505bb9..7d5e1b0965f828c945f99377fbe1d1f315363795 100644 --- a/README.md +++ b/README.md @@ -294,4 +294,81 @@ def myfun(): return 42 ``` Since the aux/bibtex databases are just dictionaries it is easy to join them together from different sources. - I have written reference tags to lecture and exercise material as well as my notes and it makes reference management very easy. \ No newline at end of file + I have written reference tags to lecture and exercise material as well as my notes and it makes reference management very easy. + + +## Advanced block processing +The default behavior for code removal (#!b and #!f-tags) is to simply remove the code and insert the number of missing lines. +We can easily create more interesting behavior. The code for the following example can be found in `examples/b_example.py` and will deal with the following problem: +```python +import numpy as np +# Implement a sieve here. +def primes_sieve(limit): + limitn = limit+1 #!b + primes = range(2, limitn) + for i in primes: + factors = list(range(i, limitn, i)) + for f in factors[1:]: + if f in primes: + primes.remove(f) + return primes #!b +# Example use: print(primes_sieve(42)) +``` +The example shows how we can easily define custom functions for processing the code which is to be removed. +All such a function need is to take a list of lines (to be obfuscated) and return a new list of lines (the obfuscated code). +A couple of short examples: +### Permute lines +This example simple randomly permutes the line and prefix them with a comment tag to ensure the code still compiles +```python +import numpy as np +# Implement a sieve here. +def primes_sieve(limit): + # primes.remove(f) + # if f in primes: + # factors = list(range(i, limitn, i)) + # for i in primes: + # + # limitn = limit+1 + # return primes + # primes = range(2, limitn) + # for f in factors[1:]: +# Example use: print(primes_sieve(42)) +raise NotImplementedError('Complete the above program') +``` +### Partial replacement +This example replaces non-keyword, non-special-symbol parts of the lines: +```python +import numpy as np +# Implement a sieve here. +def primes_sieve(limit): + # ?????? = ?????+1 + # ?????? = ?????(2, ??????) + # + # for ? in ??????: + # ??????? = ????(?????(?, ??????, ?)) + # for ? in ???????[1:]: + # if ? in ??????: + # ??????.??????(?) + # return ?????? +# Example use: print(primes_sieve(42)) +raise NotImplementedError('Complete the above program') +``` + +### Half of the solution +The final solution display half of the proposed solution: +```python +import numpy as np +# Implement a sieve here. +def primes_sieve(limit): + # limitn =???????? + # primes = ran????????????? + # + # for i in???????? + # factors = list(ra?????????????????? + # for f in f??????????? + # if f in???????? + # primes.r???????? + # return??????? +# Example use: print(primes_sieve(42)) +raise NotImplementedError('Complete the above program') +``` \ No newline at end of file diff --git a/docs/README.jinja.md b/docs/README.jinja.md index 667a54ce03fbd77fcca74df8e3aa4ebf4d91fe41..19ad495414bb8df962ded21085a8fefcdf771a2c 100644 --- a/docs/README.jinja.md +++ b/docs/README.jinja.md @@ -154,3 +154,30 @@ And this then produce the output: ``` Since the aux/bibtex databases are just dictionaries it is easy to join them together from different sources. I have written reference tags to lecture and exercise material as well as my notes and it makes reference management very easy. + + +## Advanced block processing +The default behavior for code removal (#!b and #!f-tags) is to simply remove the code and insert the number of missing lines. +We can easily create more interesting behavior. The code for the following example can be found in `examples/b_example.py` and will deal with the following problem: +```python +{{ cs101_output.sieve_py }} +``` +The example shows how we can easily define custom functions for processing the code which is to be removed. +All such a function need is to take a list of lines (to be obfuscated) and return a new list of lines (the obfuscated code). +A couple of short examples: +### Permute lines +This example simple randomly permutes the line and prefix them with a comment tag to ensure the code still compiles +```python +{{ cs101_output.obscure_1_py }} +``` +### Partial replacement +This example replaces non-keyword, non-special-symbol parts of the lines: +```python +{{ cs101_output.obscure_2_py }} +``` + +### Half of the solution +The final solution display half of the proposed solution: +```python +{{ cs101_output.obscure_3_py }} +``` diff --git a/examples/block_processor.py b/examples/b_example.py similarity index 64% rename from examples/block_processor.py rename to examples/b_example.py index c8662f7f5baa7c158e26f8565a62c8bf66e67acb..7a6fc82a0671645bffedfc38d57e60c4e23224d5 100644 --- a/examples/block_processor.py +++ b/examples/b_example.py @@ -1,7 +1,7 @@ -from snipper.fix_s import get_s #!s +from snipper.fix_s import get_s from snipper.block_parsing import block_split import textwrap -import numpy as np +import numpy as np #!s # Implement a sieve here. def primes_sieve(limit): @@ -14,13 +14,23 @@ def primes_sieve(limit): if f in primes: primes.remove(f) return primes #!b -#!s -def obscure(blk, fun): +# Example use: print(primes_sieve(42)) #!s + + +def wspace(l): + whitespace = " " * (len(l) - len(l.lstrip())) + return whitespace + + + +def obscure(blk, fun, outfile): blok = block_split(blk, "#!b") lines2 = blok['first'] + fun(blok['block']) + blok['last'] + lines2.append( wspace(lines2[-1] ) + "raise NotImplementedError('Complete the above program')" ) s = '\n'.join(lines2) - print(s) + with open(outfile, 'w') as f: + f.write(s) return s # driver program @@ -29,6 +39,9 @@ if __name__ == '__main__': s = f.read().splitlines() blk = get_s(s)[''] + with open("cs101_output/sieve.py", 'w') as f: + f.write('\n'.join(blk)) + def cmnt(lines): whitespace = " " * (len(lines[0]) - len(lines[0].lstrip())) lines = textwrap.dedent("\n".join(lines)).splitlines() @@ -41,7 +54,7 @@ if __name__ == '__main__': lines = textwrap.indent("\n".join(lines), whitespace).splitlines() return lines - obscure(blk, f1) + obscure(blk, f1, 'cs101_output/obscure_1.py') def f2(lines): lines, whitespace = cmnt(lines) @@ -60,4 +73,13 @@ if __name__ == '__main__': lines = textwrap.indent("\n".join(lines), whitespace).splitlines() return lines - obscure(blk, f2) + obscure(blk, f2, 'cs101_output/obscure_2.py') + + def f3(lines): + lines = [ (l.strip(), len(l.strip()), wspace(l)) for l in lines ] + lines = [ wp + l[:k//2] + "?"*(k-k//2) for l, k, wp in lines] + lines, whitespace = cmnt(lines) + lines = textwrap.indent("\n".join(lines), whitespace).splitlines() + return lines + + obscure(blk, f3, 'cs101_output/obscure_3.py') diff --git a/examples/cs101_output/obscure_1.py b/examples/cs101_output/obscure_1.py new file mode 100644 index 0000000000000000000000000000000000000000..db01c5146cc1f699b9a2f1cef1c611c78d61239f --- /dev/null +++ b/examples/cs101_output/obscure_1.py @@ -0,0 +1,16 @@ +import numpy as np + +# Implement a sieve here. +def primes_sieve(limit): + # primes.remove(f) + # if f in primes: + # factors = list(range(i, limitn, i)) + # for i in primes: + # + # limitn = limit+1 + # return primes + # primes = range(2, limitn) + # for f in factors[1:]: + +# Example use: print(primes_sieve(42)) +raise NotImplementedError('Complete the above program') \ No newline at end of file diff --git a/examples/cs101_output/obscure_2.py b/examples/cs101_output/obscure_2.py new file mode 100644 index 0000000000000000000000000000000000000000..2174af647c07ae59305e3ab55976a9c41c7f762e --- /dev/null +++ b/examples/cs101_output/obscure_2.py @@ -0,0 +1,16 @@ +import numpy as np + +# Implement a sieve here. +def primes_sieve(limit): + # ?????? = ?????+1 + # ?????? = ?????(2, ??????) + # + # for ? in ??????: + # ??????? = ????(?????(?, ??????, ?)) + # for ? in ???????[1:]: + # if ? in ??????: + # ??????.??????(?) + # return ?????? + +# Example use: print(primes_sieve(42)) +raise NotImplementedError('Complete the above program') \ No newline at end of file diff --git a/examples/cs101_output/obscure_3.py b/examples/cs101_output/obscure_3.py new file mode 100644 index 0000000000000000000000000000000000000000..83c6d4fac9565cdfd84dad2b49ad0af308b95f80 --- /dev/null +++ b/examples/cs101_output/obscure_3.py @@ -0,0 +1,16 @@ +import numpy as np + +# Implement a sieve here. +def primes_sieve(limit): + # limitn =???????? + # primes = ran????????????? + # + # for i in???????? + # factors = list(ra?????????????????? + # for f in f??????????? + # if f in???????? + # primes.r???????? + # return??????? + +# Example use: print(primes_sieve(42)) +raise NotImplementedError('Complete the above program') \ No newline at end of file diff --git a/examples/cs101_output/sieve.py b/examples/cs101_output/sieve.py new file mode 100644 index 0000000000000000000000000000000000000000..79f9205d646942c8a6d5529c066c0722e105dc94 --- /dev/null +++ b/examples/cs101_output/sieve.py @@ -0,0 +1,15 @@ +import numpy as np + +# Implement a sieve here. +def primes_sieve(limit): + limitn = limit+1 #!b + primes = range(2, limitn) + + for i in primes: + factors = list(range(i, limitn, i)) + for f in factors[1:]: + if f in primes: + primes.remove(f) + return primes #!b + +# Example use: print(primes_sieve(42)) \ No newline at end of file