*In kali, need shebang at beginning of .py script(s)*
```bash
#!/bin/python3
```

# Strings
- single or double quotes
- triple quote for multi-line
- can concatenate
```python
#double quotes
print("Hello, world!")
#single quotes
print('Hello, world!')
#new line
print('/n')
#triple quote
print("""this string runs multiple lines!""")
#concatenate
print("this string is "+"awesome!")
```

# Math
- python has built-in math interpreter
- follows PEMDAS
```python
print(50 + 50) #add
print(50 - 50) #subtract
print(50 * 50) #multiply
print(50 / 50) #divide
print(50 ** 2) #exponents
print(50 % 6) #modulo
print(50 // 6) #no leftovers
```

# Variables & Methods
- variable = placeholder
	- can be called on
- methods = functions available for a given object
- float - number w/ decimal
```python
quote = "All if fair in love and war."
print(quote.upper()) #uppercase
print(quote.lower()) #lowercase
print(quote.title()) #titlecase
```
- integer - number w/ no decimal

# Functions
- functions - mini programs, organized block of code that is defined and can be called on
- define (def) then call
- can have single or multiple parameters
```python
print("Here is an example function:")

def who_am_i():
	name = "Ivan"
	age = "28"
	print("My name is" + name + "and I am" + str(age) + "years old.")

who_am_i
```

# Boolean Expressions
- true or false
- used a lot in looping and conditional statements with relational & boolean operators
```python
bool1 = true
bool2 = 3*3 == 9
bool3 = false
bool4 = 3*3 != 9

print(bool1, bool2, bool3, bool4)
print(type(bool1))

True True False False
<class 'bool'>
```

# Relational & Boolean Operators
- >  ,  <  ,  >=  ,  <=
- for or, only one has to be true
- can reference truth tables: 
```python
test_and = (7 > 5) and (5 < 7) #true
test_and2 = (7 > 5) and (5 > 7) #false
test_or = (7 > 5) or (5 > 7) #true
```

# Conditional Statements
- if, then, else
- think of an if else scenario
```python
#conditional statements
def drink(money):
	if money >= 2:
		return "You've got yourself a drink!"
	else"
		return: "NO drink for you!"

print(drink(3))
print(drink(1))
You've got yourself a drink!
NO drink for you!
```

```python
def alchohol(age,money):
	if (age >= 21) and (money >= 5):
		return "We're getting a drink!"
	elif (age >=21) and (money < 5):
		return "Come back with more money."
	elif (age < 21) and (money >= 5):
		return "Nice try, kid!"
	else:
		return "You're too poor and too young"

print(alcohol(21,5))
print(alcohol(21,4))
print(alcohol(20,4))
We're getting a drink!
Come back with more money.
You're too poor and too young
```

# Lists
- lists are data structures, mutable
- live in brackets []
- things in lists are called items
- item one is referred to as 0
- last number on list STOPS at that number, go up one number to include next item
- can use -1 (negative one) to select last item on the list
```python
#lists
movies = ["when Harry Met Sally", "The Hangover"]

print(movies[1])
The Hangover
print(movies[0])
When Harry Met Sally
```

# Tuples
- like lists, but immutable - must be changed at the code level only 
- use ()
```python
grades = ("a", "b", "c", "d", "f")
print(gared[1])
b

#this is immutable, cannot be changed via pop
```

# Looping
- while loop executes as long as something is true
- for loops - start to finish of an iterate
```python
#for loop
vegetables = ["cucumber", "spinach", "cabbage"]
for x in vegetables:
	print(x)

cucumber, spinash, cabbage

#while loop
i = 1
while i < 10:
	print(i)
	i += 1
```

# Importing Modules
- sys - system functions and parameters
- can import with alias
```python
import sys
print(sys.version)
from datetime import datetime as dt #imports a specific part
print(dt.now()))
```

#  Dictionaries
- key value pairs
- use {}
- can have nested lists []
- can pull values from dictionary
```python
drinks = {"White Russian": 7, "Lemon Drop": 8} #drink is key, price is value
print(drinks)
White Russian, Lemon Drop

employees = {"IT": ["Gene", "Lousie", "Teddy"], "HR": ["Jimmy", "Mort"]}
#add new pair
employees.update({"Sales": ["Andie", "Ollie"]})
print(employees)
{"IT": ["Gene", "Lousie", "Teddy"], "HR": ["Jimmy", "Mort"], "Sales": ["Andie", "Ollie"]}

#pull value
drinks['White Russian'] = 8
print(drinks.get("White Russian"))
8
```

# Sockets
- sockets connect two nodes together
	- port to and from IP address
	- AF_INET = ipv4
	- SOCK_STREAM = port
	- Start script >> can listen with netcat `nc -nvlp 4445`
```python
#!/usr/bin/env python

import socket

host = '127.0.0.1'
port = 4445

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
```

# Building a Port Scanner
- run script against IP in network >> provide IP >> checks if ports are open
```python
#!/usr/bin/env python3

import sys
from datetime import datetime as dt
import socket

#Define our target
if len(sys.argv) == 2:
  target = socket.gethostbyname(sys.argv[1]) # translates host to ipv4
else:
  print("Invalid number of args")
  print("Syntax: python3 port_scanner.py [ip/hostname]")
#Add pretty banner
print("Scannning target: " + target)
print("Time started: " + str(dt.now()))
print('-' * 50)

try:
  for port in range(1,65535):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    socket.setdefaulttimeout(0.5)
    result = s.connect_ex((target, port)) #returns an error indicator
    if result == 0:
      print("port {} is open".format(port))
    s.close 
except KeyboardInterrupt:
  print('\nExitting...')
  sys.exit()
except socket.gaierror:
  print("Hostname couldn't be resolved")
  sys.exit()
except socket.error:
  print("Couldn't connect to server")
  sys.exit()
```
