<jupyter_start><jupyter_text>This is a Jupyter NotebookYou can write Python code and it will execute. You can write the typical 'hello world' program like this:```pythonprint('hello world')```You can execute by pressing shift-enter. Try it! You can also click the Run button in the toolbar.<jupyter_code>print('hello world')<jupyter_output>hello world<jupyter_text>Exercise 1You can do a lot more than just print "hello world"This is a fully functioning Python3 interpreter so you can write functions and objects like in the next box.Try printing the 21st Fibonacci number below instead of the 11th. You can add caching if you want to practice coding in Python.<jupyter_code># Exercise 1

def fib(n):
    if n in (0,1):
        return 1
    else:
        return fib(n-1) + fib(n-2)
print(fib(20))<jupyter_output>10946<jupyter_text>A few things you should remember in Python 3Strings and bytes are now different```pythons = 'hello world'b = b'hello world'```These may look the same but the 'b' prefix means that the variable `b` is bytes whereas the variable `s` is a string. Basically, the on-disk characters on the system are bytes and the actual symbols in unicode are strings. A good explanation of the difference is [here](http://www.diveintopython3.net/strings.html).<jupyter_code>s = 'hello world'
b = b'hello world'
print(s==b) # False
# You convert from string to bytes this way:
hello_world_bytes = s.encode('ascii')
print(hello_world_bytes == b) # True
# You convert from bytes to string this way:
hello_world_string = b.decode('ascii')
print(hello_world_string == s) # True<jupyter_output>False
True
True<jupyter_text>ImportsYou already have unit tests that are written for you.Your task is to make them pass.We can import various modules to make our experience using Jupyter more pleasant.This way, making everything work will be a lot easier.<jupyter_code># this is how you import an entire module
import helper
# this is how you import a particular function, class or constant
from helper import little_endian_to_int
# used in the next exercise
some_long_variable_name = 'something'<jupyter_output><empty_output><jupyter_text>Exercise 2 Jupyter TipsThe two most useful commands are tab and shift-tabTab lets you tab-complete. Try pressing tab after the `some` below. This will complete to the variable name that's there from the last cell.Shift-Tab gives you a function/method signature. Try pressing shift-tab after the `little_endian_to_int` below. That's also there from the last cell.<jupyter_code># Exercise 2

some_long_variable_name
little_endian_to_int(b'\x00')<jupyter_output><empty_output><jupyter_text>Exercise 3Open [helper.py](/edit/session0/helper.py) and implement the `bytes_to_str` and `str_to_bytes` functions. Once you're done editing, run the cell below. Make [this test](/edit/session0/helper.py) pass: `helper.py:HelperTest:test_bytes`<jupyter_code># Exercise 3

reload(helper)
run(helper.HelperTest('test_bytes'))<jupyter_output>.
----------------------------------------------------------------------
Ran 1 test in 0.003s

OK<jupyter_text>Getting HelpIf you can't get this, there's a [complete directory](/tree/session0/complete) that has the [helper.py file](/edit/session0/complete/helper.py) and the [session0.ipynb file](/notebooks/session0/complete/session0.ipynb) which you can use to get the answers.  Useful Python 3 IdiomsYou can reverse a list by using `[::-1]`:```pythona = [1, 2, 3, 4, 5]print(a[::-1])  [5, 4, 3, 2, 1]```Also works on both strings and bytes:```pythons = 'hello world'print(s[::-1])  'dlrow olleh'b = b'hello world'print(b[::-1])  b'dlrow olleh'```Indexing bytes will get you the numerical value:```pythonprint(b'&'[0])  38 since & is charcter 38```You can do the reverse by using bytes:```pythonprint(bytes([38]))  b'&'```<jupyter_code>a = [1, 2, 3, 4, 5]
print(a[::-1]) # [5, 4, 3, 2, 1]
s = 'hello world'
print(s[::-1]) # 'dlrow olleh'
b = b'hello world'
print(b[::-1]) # b'dlrow olleh'
print(b'&'[0]) # 38 since & charcter #38
print(bytes([38])) # b'&'<jupyter_output>[5, 4, 3, 2, 1]
dlrow olleh
b'dlrow olleh'
38
b'&'<jupyter_text>Python TricksHere is how we convert binary to/from hex:<jupyter_code>print(b'hello world'.hex())
print(bytes.fromhex('68656c6c6f20776f726c64'))<jupyter_output>68656c6c6f20776f726c64
b'hello world'<jupyter_text>Exercise 4Reverse this hex dump: `b010a49c82b4bc84cc1dfd6e09b2b8114d016041efaf591eca88959e327dd29a`Hint: you'll want to turn this into binary data, reverse and turn it into hex again<jupyter_code># Exercise 4

h = 'b010a49c82b4bc84cc1dfd6e09b2b8114d016041efaf591eca88959e327dd29a'
# convert to binary (bytes.fromhex)
b = bytes.fromhex(h)
# reverse ([::-1])
b_rev = b[::-1]
# convert to hex()
h_rev = b_rev.hex()
# print the result
print(h_rev)<jupyter_output>9ad27d329e9588ca1e59afef4160014d11b8b2096efd1dcc84bcb4829ca410b0<jupyter_text>Modular ArithmeticIf you don't remember Modular Arithmetic, it's this function on python```python39 % 12```The result is 3 because that is the remainder after division (39 / 12 == 3 + 3/12).Some people like to call it "wrap-around" math. If it helps, think of modular arithmetic like a clock:![clock](http://latex.artofproblemsolving.com/f/4/d/f4daa2601de14fddf3d8441e16cc322a25e85354.png)Think of taking the modulo as asking the question "what hour will it be 39 hours from now?"If you're still confused, please take a look at [this](https://www.khanacademy.org/computing/computer-science/cryptography/modarithmetic/a/what-is-modular-arithmetic) article.<jupyter_code>print(39 % 12)<jupyter_output>3<jupyter_text>Exercise 5Find the modulo 19 of these numbers:* 99* \\(456 \cdot 444\\)* \\(9^{77}\\)(note python uses ** to do exponentiation)<jupyter_code># Exercise 5

prime = 19
print(99 % prime)
print(456*444 % prime)
print(9**77 % prime)<jupyter_output>4
0
16<jupyter_text>Converting from bytes to int and backConverting from bytes to integer requires learning about Big and Little Endian encoding. Essentially any number greater than 255 can be encoded in two ways, with the "Big End" going first or the "Little End" going first.Normal human reading is from the "Big End". For example 123 is read as 100 + 20 + 3. Some computer systems encode integers with the "Little End" first.A number like 500 is encoded this way in Big Endian:0x01f4 (256 + 244)But this way in Little Endian:0xf401 (244 + 256)In Python we can convert an integer to big or little endian using a built-in method:```pythonn = 1234567890big_endian = n.to_bytes(4, 'big')   b'\x49\x96\x02\xd2'little_endian = n.to_bytes(4, 'little')   b'\xd2\x02\x96\x49'```We can also convert from bytes to an integer this way:```pythonbig_endian = b'\x49\x96\x02\xd2'n = int.from_bytes(big_endian, 'big')   1234567890little_endian = b'\xd2\x02\x96\x49'n = int.from_bytes(little_endian, 'little')   1234567890```<jupyter_code>n = 1234567890
big_endian = n.to_bytes(4, 'big')
little_endian = n.to_bytes(4, 'little')
print(big_endian.hex())
print(little_endian.hex())
print(int.from_bytes(big_endian, 'big'))
print(int.from_bytes(little_endian, 'little'))<jupyter_output>499602d2
d2029649
1234567890
1234567890<jupyter_text>Exercise 6Convert the following:* 8675309 to 8 bytes in big endian* interpret ```b'\x11\x22\x33\x44\x55'``` as a little endian integer<jupyter_code># Exercise 6

n = 8675309
print(n.to_bytes(8, 'big'))
little_endian = b'\x11\x22\x33\x44\x55'
print(int.from_bytes(little_endian, 'little'))<jupyter_output>b'\x00\x00\x00\x00\x00\x84_\xed'
366216421905<jupyter_text>Exercise 7We'll want to convert from little-endian bytes to an integer often, so write a function that will do this. Make [this test](/edit/session0/helper.py) pass: `helper.py:HelperTest:test_little_endian_to_int`<jupyter_code># Exercise 7

reload(helper)
run(helper.HelperTest('test_little_endian_to_int'))<jupyter_output>.
----------------------------------------------------------------------
Ran 1 test in 0.004s

OK<jupyter_text>Exercise 8Similarly, we'll want to do the inverse operation, so write a function that will convert an integer to little-endian bytes given the number and the number of bytes it should take up. Make [this test](/edit/session0/helper.py) pass: `helper.py:HelperTest:test_int_to_little_endian`<jupyter_code># Exercise 8

reload(helper)
run(helper.HelperTest('test_int_to_little_endian'))<jupyter_output>.
----------------------------------------------------------------------
Ran 1 test in 0.003s

OK
StarcoderdataJupyterStructuredCleanDedup