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