diff --git a/assets/adjectives.txt b/assets/adjectives.txt
new file mode 100644
index 0000000..81f7688
--- /dev/null
+++ b/assets/adjectives.txt
@@ -0,0 +1,1896 @@
+aback
+abaft
+abandoned
+abashed
+aberrant
+abhorrent
+abiding
+abject
+ablaze
+able
+abnormal
+aboard
+aboriginal
+abortive
+abounding
+abrasive
+abrupt
+absent
+absolute
+absorbed
+absorbing
+abstracted
+absurd
+abundant
+abusive
+academic
+acceptable
+accessible
+accidental
+acclaimed
+accomplished
+accurate
+aching
+acid
+acidic
+acoustic
+acrid
+acrobatic
+active
+actual
+actually
+ad hoc
+adamant
+adaptable
+addicted
+adept
+adhesive
+adjoining
+admirable
+admired
+adolescent
+adorable
+adored
+advanced
+adventurous
+affectionate
+afraid
+aged
+aggravating
+aggressive
+agile
+agitated
+agonizing
+agreeable
+ahead
+ajar
+alarmed
+alarming
+alcoholic
+alert
+alienated
+alike
+alive
+all
+alleged
+alluring
+aloof
+altruistic
+amazing
+ambiguous
+ambitious
+amiable
+ample
+amuck
+amused
+amusing
+anchored
+ancient
+ancient
+angelic
+angry
+angry
+anguished
+animated
+annoyed
+annoying
+annual
+another
+antique
+antsy
+anxious
+any
+apathetic
+appetizing
+apprehensive
+appropriate
+apt
+aquatic
+arctic
+arid
+aromatic
+arrogant
+artistic
+ashamed
+aspiring
+assorted
+assured
+astonishing
+athletic
+attached
+attentive
+attractive
+auspicious
+austere
+authentic
+authorized
+automatic
+available
+avaricious
+average
+awake
+aware
+awesome
+awful
+awkward
+axiomatic
+babyish
+back
+bad
+baggy
+barbarous
+bare
+barren
+bashful
+basic
+batty
+bawdy
+beautiful
+beefy
+befitting
+belated
+belligerent
+beloved
+beneficial
+bent
+berserk
+best
+better
+bewildered
+bewitched
+big
+big-hearted
+billowy
+biodegradable
+bite-sized
+biting
+bitter
+bizarre
+black
+black-and-white
+bland
+blank
+blaring
+bleak
+blind
+blissful
+blond
+bloody
+blue
+blue-eyed
+blushing
+bogus
+boiling
+bold
+bony
+boorish
+bored
+boring
+bossy
+both
+bouncy
+boundless
+bountiful
+bowed
+brainy
+brash
+brave
+brawny
+breakable
+breezy
+brief
+bright
+brilliant
+brisk
+broad
+broken
+bronze
+brown
+bruised
+bubbly
+bulky
+bumpy
+buoyant
+burdensome
+burly
+bustling
+busy
+buttery
+buzzing
+cagey
+calculating
+callous
+calm
+candid
+canine
+capable
+capital
+capricious
+carefree
+careful
+careless
+caring
+cautious
+cavernous
+ceaseless
+celebrated
+certain
+changeable
+charming
+cheap
+cheeky
+cheerful
+cheery
+chemical
+chief
+childlike
+chilly
+chivalrous
+chubby
+chunky
+circular
+clammy
+classic
+classy
+clean
+clear
+clear-cut
+clever
+cloistered
+close
+closed
+cloudy
+clueless
+clumsy
+cluttered
+coarse
+coherent
+cold
+colorful
+colorless
+colossal
+colossal
+combative
+comfortable
+common
+compassionate
+competent
+complete
+complex
+complicated
+composed
+concerned
+concrete
+condemned
+condescending
+confused
+conscious
+considerate
+constant
+contemplative
+content
+conventional
+convincing
+convoluted
+cooing
+cooked
+cool
+cooperative
+coordinated
+corny
+corrupt
+costly
+courageous
+courteous
+cowardly
+crabby
+crafty
+craven
+crazy
+creamy
+creative
+creepy
+criminal
+crisp
+critical
+crooked
+crowded
+cruel
+crushing
+cuddly
+cultivated
+cultured
+cumbersome
+curious
+curly
+curved
+curvy
+cut
+cute
+cylindrical
+cynical
+daffy
+daily
+damaged
+damaging
+damp
+dangerous
+dapper
+dapper
+daring
+dark
+darling
+dashing
+dazzling
+dead
+deadly
+deadpan
+deafening
+dear
+dearest
+debonair
+decayed
+deceitful
+decent
+decimal
+decisive
+decorous
+deep
+deeply
+defeated
+defective
+defenseless
+defensive
+defiant
+deficient
+definite
+delayed
+delectable
+delicate
+delicious
+delightful
+delirious
+demanding
+demonic
+dense
+dental
+dependable
+dependent
+depraved
+depressed
+deranged
+descriptive
+deserted
+despicable
+detailed
+determined
+devilish
+devoted
+didactic
+different
+difficult
+digital
+dilapidated
+diligent
+dim
+diminutive
+dimpled
+dimwitted
+direct
+direful
+dirty
+disagreeable
+disastrous
+discreet
+discrete
+disfigured
+disguised
+disgusted
+disgusting
+dishonest
+disillusioned
+disloyal
+dismal
+dispensable
+distant
+distinct
+distorted
+distraught
+distressed
+disturbed
+divergent
+dizzy
+domineering
+dopey
+doting
+double
+doubtful
+downright
+drab
+draconian
+drafty
+drained
+dramatic
+dreary
+droopy
+drunk
+dry
+dual
+dull
+dull
+dusty
+dutiful
+dynamic
+dysfunctional
+each
+eager
+early
+earnest
+earsplitting
+earthy
+easy
+easy-going
+eatable
+economic
+ecstatic
+edible
+educated
+efficacious
+efficient
+eight
+elaborate
+elastic
+elated
+elderly
+electric
+elegant
+elementary
+elfin
+elite
+elliptical
+emaciated
+embarrassed
+embellished
+eminent
+emotional
+empty
+enchanted
+enchanting
+encouraging
+endurable
+energetic
+enlightened
+enormous
+enraged
+entertaining
+enthusiastic
+entire
+envious
+envious
+equable
+equal
+equatorial
+erect
+erratic
+essential
+esteemed
+ethereal
+ethical
+euphoric
+evanescent
+evasive
+even
+evergreen
+everlasting
+every
+evil
+exalted
+exasperated
+excellent
+excitable
+excited
+exciting
+exclusive
+exemplary
+exhausted
+exhilarated
+exotic
+expensive
+experienced
+expert
+extensive
+extra-large
+extraneous
+extra-small
+extroverted
+exuberant
+exultant
+fabulous
+faded
+failing
+faint
+fair
+faithful
+fake
+fallacious
+false
+familiar
+famous
+fanatical
+fancy
+fantastic
+far
+faraway
+far-flung
+far-off
+fascinated
+fast
+fat
+fatal
+fatherly
+faulty
+favorable
+favorite
+fearful
+fearless
+feeble
+feigned
+feisty
+feline
+female
+feminine
+fertile
+festive
+few
+fickle
+fierce
+filthy
+fine
+finicky
+finished
+firm
+first
+firsthand
+fitting
+five
+fixed
+flagrant
+flaky
+flamboyant
+flashy
+flat
+flawed
+flawless
+flickering
+flimsy
+flippant
+floppy
+flowery
+flufy
+fluid
+flustered
+fluttering
+foamy
+focused
+fond
+foolhardy
+foolish
+forceful
+foregoing
+forgetful
+forked
+formal
+forsaken
+forthright
+fortunate
+four
+fragile
+fragrant
+frail
+frank
+frantic
+frayed
+free
+freezing
+French
+frequent
+fresh
+fretful
+friendly
+frightened
+frightening
+frigid
+frilly
+frivolous
+frizzy
+front
+frosty
+frothy
+frozen
+frugal
+fruitful
+frustrating
+full
+fumbling
+fumbling
+functional
+funny
+furry
+furtive
+fussy
+future
+futuristic
+fuzzy
+gabby
+gainful
+gamy
+gaping
+gargantuan
+garrulous
+gaseous
+gaudy
+general
+general
+generous
+gentle
+genuine
+ghastly
+giant
+giddy
+gifted
+gigantic
+giving
+glamorous
+glaring
+glass
+gleaming
+gleeful
+glib
+glistening
+glittering
+gloomy
+glorious
+glossy
+glum
+godly
+golden
+good
+good-natured
+goofy
+gorgeous
+graceful
+gracious
+grand
+grandiose
+grandiose
+granular
+grateful
+gratis
+grave
+gray
+greasy
+great
+greedy
+green
+gregarious
+grey
+grieving
+grim
+grimy
+gripping
+grizzled
+groovy
+gross
+grotesque
+grouchy
+grounded
+growing
+growling
+grown
+grubby
+gruesome
+grumpy
+guarded
+guiltless
+guilty
+gullible
+gummy
+gusty
+guttural
+habitual
+hairy
+half
+half
+hallowed
+halting
+handmade
+handsome
+handsomely
+handy
+hanging
+hapless
+happy
+happy-go-lucky
+hard
+hard-to-find
+harebrained
+harmful
+harmless
+harmonious
+harsh
+hasty
+hateful
+haunting
+heady
+healthy
+heartbreaking
+heartfelt
+hearty
+heavenly
+heavy
+hefty
+hellish
+helpful
+helpless
+hesitant
+hidden
+hideous
+high
+highfalutin
+high-level
+high-pitched
+hilarious
+hissing
+historical
+hoarse
+holistic
+hollow
+homeless
+homely
+honest
+honorable
+honored
+hopeful
+horrible
+horrific
+hospitable
+hot
+huge
+hulking
+humble
+humdrum
+humiliating
+humming
+humongous
+humorous
+hungry
+hurried
+hurt
+hurtful
+hushed
+husky
+hypnotic
+hysterical
+icky
+icy
+ideal
+ideal
+idealistic
+identical
+idiotic
+idle
+idolized
+ignorant
+ill
+illegal
+ill-fated
+ill-informed
+illiterate
+illustrious
+imaginary
+imaginative
+immaculate
+immaterial
+immediate
+immense
+imminent
+impartial
+impassioned
+impeccable
+imperfect
+imperturbable
+impish
+impolite
+important
+imported
+impossible
+impractical
+impressionable
+impressive
+improbable
+impure
+inborn
+incandescent
+incomparable
+incompatible
+incompetent
+incomplete
+inconclusive
+inconsequential
+incredible
+indelible
+indolent
+industrious
+inexpensive
+inexperienced
+infamous
+infantile
+infatuated
+inferior
+infinite
+informal
+innate
+innocent
+inquisitive
+insecure
+insidious
+insignificant
+insistent
+instinctive
+instructive
+insubstantial
+intelligent
+intent
+intentional
+interesting
+internal
+international
+intrepid
+intrigued
+invincible
+irate
+ironclad
+irresponsible
+irritable
+irritating
+itchy
+jaded
+jagged
+jam-packed
+jaunty
+jazzy
+jealous
+jittery
+jobless
+joint
+jolly
+jovial
+joyful
+joyous
+jubilant
+judicious
+juicy
+jumbled
+jumbo
+jumpy
+jumpy
+junior
+juvenile
+kaleidoscopic
+kaput
+keen
+key
+kind
+kindhearted
+kindly
+klutzy
+knobby
+knotty
+knowing
+knowledgeable
+known
+kooky
+kosher
+labored
+lackadaisical
+lacking
+lame
+lame
+lamentable
+languid
+lanky
+large
+last
+lasting
+late
+laughable
+lavish
+lawful
+lazy
+leading
+leafy
+lean
+learned
+left
+legal
+legitimate
+lethal
+level
+lewd
+light
+lighthearted
+likable
+like
+likeable
+likely
+limited
+limp
+limping
+linear
+lined
+liquid
+literate
+little
+live
+lively
+livid
+living
+loathsome
+lone
+lonely
+long
+longing
+long-term
+loose
+lopsided
+lost
+loud
+loutish
+lovable
+lovely
+loving
+low
+lowly
+loyal
+lucky
+ludicrous
+lumbering
+luminous
+lumpy
+lush
+lustrous
+luxuriant
+luxurious
+lying
+lyrical
+macabre
+macho
+mad
+maddening
+made-up
+madly
+magenta
+magical
+magnificent
+majestic
+major
+makeshift
+male
+malicious
+mammoth
+maniacal
+many
+marked
+married
+marvelous
+masculine
+massive
+material
+materialistic
+mature
+meager
+mealy
+mean
+measly
+meaty
+medical
+mediocre
+medium
+meek
+melancholy
+mellow
+melodic
+melted
+memorable
+menacing
+merciful
+mere
+merry
+messy
+metallic
+mighty
+mild
+military
+milky
+mindless
+miniature
+minor
+minty
+minute
+miscreant
+miserable
+miserly
+misguided
+mistaken
+misty
+mixed
+moaning
+modern
+modest
+moist
+moldy
+momentous
+monstrous
+monthly
+monumental
+moody
+moral
+mortified
+motherly
+motionless
+mountainous
+muddled
+muddy
+muffled
+multicolored
+mundane
+mundane
+murky
+mushy
+musty
+mute
+muted
+mysterious
+naive
+nappy
+narrow
+nasty
+natural
+naughty
+nauseating
+nautical
+near
+neat
+nebulous
+necessary
+needless
+needy
+negative
+neglected
+negligible
+neighboring
+neighborly
+nervous
+nervous
+new
+next
+nice
+nice
+nifty
+nimble
+nine
+nippy
+nocturnal
+noiseless
+noisy
+nonchalant
+nondescript
+nonsensical
+nonstop
+normal
+nostalgic
+nosy
+notable
+noted
+noteworthy
+novel
+noxious
+null
+numb
+numberless
+numerous
+nutritious
+nutty
+oafish
+obedient
+obeisant
+obese
+oblivious
+oblong
+obnoxious
+obscene
+obsequious
+observant
+obsolete
+obtainable
+obvious
+occasional
+oceanic
+odd
+oddball
+offbeat
+offensive
+official
+oily
+old
+old-fashioned
+omniscient
+one
+onerous
+only
+open
+opposite
+optimal
+optimistic
+opulent
+orange
+orderly
+ordinary
+organic
+original
+ornate
+ornery
+ossified
+other
+our
+outgoing
+outlandish
+outlying
+outrageous
+outstanding
+oval
+overconfident
+overcooked
+overdue
+overjoyed
+overlooked
+overrated
+overt
+overwrought
+painful
+painstaking
+palatable
+pale
+paltry
+panicky
+panoramic
+parallel
+parched
+parsimonious
+partial
+passionate
+past
+pastel
+pastoral
+pathetic
+peaceful
+penitent
+peppery
+perfect
+perfumed
+periodic
+perky
+permissible
+perpetual
+perplexed
+personal
+pertinent
+pesky
+pessimistic
+petite
+petty
+petty
+phobic
+phony
+physical
+picayune
+piercing
+pink
+piquant
+pitiful
+placid
+plain
+plaintive
+plant
+plastic
+plausible
+playful
+pleasant
+pleased
+pleasing
+plucky
+plump
+plush
+pointed
+pointless
+poised
+polished
+polite
+political
+pompous
+poor
+popular
+portly
+posh
+positive
+possessive
+possible
+potable
+powerful
+powerless
+practical
+precious
+premium
+present
+present
+prestigious
+pretty
+previous
+pricey
+prickly
+primary
+prime
+pristine
+private
+prize
+probable
+productive
+profitable
+profuse
+proper
+protective
+proud
+prudent
+psychedelic
+psychotic
+public
+puffy
+pumped
+punctual
+pungent
+puny
+pure
+purple
+purring
+pushy
+pushy
+putrid
+puzzled
+puzzling
+quack
+quaint
+quaint
+qualified
+quarrelsome
+quarterly
+queasy
+querulous
+questionable
+quick
+quickest
+quick-witted
+quiet
+quintessential
+quirky
+quixotic
+quixotic
+quizzical
+rabid
+racial
+radiant
+ragged
+rainy
+rambunctious
+rampant
+rapid
+rare
+rash
+raspy
+ratty
+raw
+ready
+real
+realistic
+reasonable
+rebel
+recent
+receptive
+reckless
+recondite
+rectangular
+red
+redundant
+reflecting
+reflective
+regal
+regular
+reliable
+relieved
+remarkable
+reminiscent
+remorseful
+remote
+repentant
+repulsive
+required
+resolute
+resonant
+respectful
+responsible
+responsive
+revolving
+rewarding
+rhetorical
+rich
+right
+righteous
+rightful
+rigid
+ringed
+ripe
+ritzy
+roasted
+robust
+romantic
+roomy
+rosy
+rotating
+rotten
+rotund
+rough
+round
+rowdy
+royal
+rubbery
+ruddy
+rude
+rundown
+runny
+rural
+rustic rusty
+ruthless
+sable
+sad
+safe
+salty
+same
+sandy
+sane
+sarcastic
+sardonic
+sassy
+satisfied
+satisfying
+savory
+scaly
+scandalous
+scant
+scarce
+scared
+scary
+scattered
+scented
+scholarly
+scientific
+scintillating
+scornful
+scratchy
+scrawny
+screeching
+second
+secondary
+second-hand
+secret
+secretive
+sedate
+seemly
+selective
+self-assured
+selfish
+self-reliant
+sentimental
+separate
+serene
+serious
+serpentine
+several
+severe
+shabby
+shadowy
+shady
+shaggy
+shaky
+shallow
+shameful
+shameless
+sharp
+shimmering
+shiny
+shivering
+shocked
+shocking
+shoddy
+short
+short-term
+showy
+shrill
+shut
+shy
+sick
+silent
+silky
+silly
+silver
+similar
+simple
+simplistic
+sincere
+sinful
+single
+six
+sizzling
+skeletal
+skillful
+skinny
+sleepy
+slight
+slim
+slimy
+slippery
+sloppy
+slow
+slushy
+small
+smarmy
+smart
+smelly
+smiling
+smoggy
+smooth
+smug
+snappy
+snarling
+sneaky
+sniveling
+snobbish
+snoopy
+snotty
+sociable
+soft
+soggy
+solid
+somber
+some
+sophisticated
+sordid
+sore
+sorrowful
+soulful
+soupy
+sour
+sour
+Spanish
+sparkling
+sparse
+special
+specific
+spectacular
+speedy
+spherical
+spicy
+spiffy
+spiky
+spirited
+spiritual
+spiteful
+splendid
+spooky
+spotless
+spotted
+spotty
+spry
+spurious
+squalid
+square
+squeaky
+squealing
+squeamish
+squiggly
+stable
+staid
+stained
+staking
+stale
+standard
+standing
+starchy
+stark
+starry
+statuesque
+steadfast
+steady
+steel
+steep
+stereotyped
+sticky
+stiff
+stimulating
+stingy
+stormy
+stout
+straight
+strange
+strict
+strident
+striking
+striped
+strong
+studious
+stunning
+stunning
+stupendous
+stupid
+sturdy
+stylish
+subdued
+submissive
+subsequent
+substantial
+subtle
+suburban
+successful
+succinct
+succulent
+sudden
+sugary
+sulky
+sunny
+super
+superb
+superficial
+superior
+supportive
+supreme
+sure-footed
+surprised
+suspicious
+svelte
+swanky
+sweaty
+sweet
+sweltering
+swift
+sympathetic
+symptomatic
+synonymous
+taboo
+tacit
+tacky
+talented
+talkative
+tall
+tame
+tan
+tangible
+tangy
+tart
+tasteful
+tasteless
+tasty
+tattered
+taut
+tawdry
+tearful
+tedious
+teeming
+teeny
+teeny-tiny
+telling
+temporary
+tempting
+ten
+tender
+tense
+tenuous
+tepid
+terrible
+terrific
+tested
+testy
+thankful
+that
+therapeutic
+these
+thick
+thin
+thinkable
+third
+thirsty
+this
+thorny
+thorough
+those
+thoughtful
+thoughtless
+threadbare
+threatening
+three
+thrifty
+thundering
+thunderous
+tidy
+tight
+tightfisted
+timely
+tinted
+tiny
+tired
+tiresome
+toothsome
+torn
+torpid
+total
+tough
+towering
+tragic
+trained
+tranquil
+trashy
+traumatic
+treasured
+tremendous
+triangular
+tricky
+trifling
+trim
+trite
+trivial
+troubled
+truculent
+true
+trusting
+trustworthy
+trusty
+truthful
+tubby
+turbulent
+twin
+two
+typical
+ubiquitous
+ugliest
+ugly
+ultimate
+ultra
+unable
+unaccountable
+unarmed
+unaware
+unbecoming
+unbiased
+uncomfortable
+uncommon
+unconscious
+uncovered
+understated
+understood
+undesirable
+unequal
+unequaled
+uneven
+unfinished
+unfit
+unfolded
+unfortunate
+unhappy
+unhealthy
+uniform
+unimportant
+uninterested
+unique
+united
+unkempt
+unknown
+unlawful
+unlined
+unlucky
+unnatural
+unpleasant
+unrealistic
+unripe
+unruly
+unselfish
+unsightly
+unsteady
+unsuitable
+unsung
+untidy
+untimely
+untried
+untrue
+unused
+unusual
+unwelcome
+unwieldy
+unwitting
+unwritten
+upbeat
+uppity
+upright
+upset
+uptight
+urban
+usable
+used
+used
+useful
+useless
+utilized
+utopian
+utter
+uttermost
+vacant
+vacuous
+vagabond
+vague
+vain
+valid
+valuable
+vapid
+variable
+various
+vast
+velvety
+venerated
+vengeful
+venomous
+verdant
+verifiable
+versed
+vexed
+vibrant
+vicious
+victorious
+vigilant
+vigorous
+villainous
+violent
+violet
+virtual
+virtuous
+visible
+vital
+vivacious
+vivid
+voiceless
+volatile
+voluminous
+voracious
+vulgar
+wacky
+waggish
+waiting
+wakeful
+wan
+wandering
+wanting
+warlike
+warm
+warmhearted
+warped
+wary
+wasteful
+watchful
+waterlogged
+watery
+wavy
+weak
+wealthy
+weary
+webbed
+wee
+weekly
+weepy
+weighty
+weird
+welcome
+well-documented
+well-groomed
+well-informed
+well-lit
+well-made
+well-off
+well-to-do
+well-worn
+wet
+which
+whimsical
+whirlwind
+whispered
+whispering
+white
+whole
+wholesale
+whopping
+wicked
+wide
+wide-eyed
+wiggly
+wild
+willing
+wilted
+winding
+windy
+winged
+wiry
+wise
+wistful
+witty
+wobbly
+woebegone
+woeful
+womanly
+wonderful
+wooden
+woozy
+wordy
+workable
+worldly
+worn
+worried
+worrisome
+worse
+worst
+worthless
+worthwhile
+worthy
+wrathful
+wretched
+writhing
+wrong
+wry
+xenophobic
+yawning
+yearly
+yellow
+yellowish
+yielding
+young
+youthful
+yummy
+zany
+zealous
+zesty
+zigzag
+zippy
+zonked
diff --git a/assets/login_generator.py b/assets/login_generator.py
new file mode 100644
index 0000000..29b7974
--- /dev/null
+++ b/assets/login_generator.py
@@ -0,0 +1,56 @@
+import random
+import string
+
+
+def load_file(filename):
+ """
+ We load a file and make a list out of it. Note that the same function is
+ used for both files (both adjectives and subjects). Functions should be
+ made as generic as possible.
+
+ There IS a problem you can fix, some logins will have spaces in them. Try
+ to remove them in this function!
+ """
+ words = []
+ with open(filename, "r") as fp:
+ lines = fp.readlines()
+ for line in lines:
+ words.append(line.strip()) # what does strip() do, what does append() do? remember CTRL+Q!
+ return words
+
+
+def generate_username():
+ """
+ We'll generate a random pair of adjectives and subjects from two wordlists.
+ You NEED to have both files in you python project for this to work! Note
+ the capitalize method call to make it all prettier...
+ """
+ adjectives = load_file("./adjectives.txt")
+ subjects = load_file("./subjects.txt")
+ adjective = random.choice(adjectives)
+ subject = random.choice(subjects)
+ username = adjective.capitalize() + subject.capitalize()
+ return username
+
+
+def generate_password(length=10, complictated=True):
+ """
+ We generate a password with default settings. You can overide these by
+ changing the arguments in the function call.
+ """
+ password = ""
+ if complictated:
+ chars = string.ascii_letters + string.digits + string.punctuation
+ else:
+ chars = string.ascii_letters
+ for i in range(0, length):
+ password += random.choice(chars)
+ return password
+
+
+if __name__ == "__main__":
+ # let's do some testing!
+ username_test = generate_username()
+ print(username_test)
+ password_test = generate_password()
+ print(password_test)
diff --git a/assets/pwd_cli.py b/assets/pwd_cli.py
new file mode 100644
index 0000000..c5f3830
--- /dev/null
+++ b/assets/pwd_cli.py
@@ -0,0 +1,61 @@
+import login_generator
+
+
+def prompt():
+ """
+ We prompt but you KNOW how this works!
+ """
+ response = ""
+ while not response.isdigit():
+ response = input("how many login pairs would you like to create?")
+ return int(response)
+
+
+def how_long():
+ """
+ And again... (we could combine both prompts, but how?)
+ """
+ response = ""
+ while not response.isdigit():
+ response = input("how long should the password be?")
+ return int(response)
+
+
+def complex_or_not():
+ response = ""
+ while response.lower() not in ["y", "n"]:
+ response = input("you want complex passwords? (y/n)")
+ if response.lower() == "y":
+ return True
+ else:
+ return False
+
+
+def create_login(length, complicated):
+ """
+ We use our library to generate the username and password. The double return
+ might look confusing but just look at the for loop in the generate_logins
+ functions and you'll see how it unpacks...
+ """
+ username = login_generator.generate_username()
+ password = login_generator.generate_password(length, complicated)
+ return username, password
+
+
+def generate_logins(number, length, complicated):
+ """
+ Easy no? But what does the i do? Do we really need it's value?
+ """
+ for i in range(0, number):
+ username, password = create_login(length, complicated)
+ print("username {}: {}".format(i, username))
+ print("password {}: {}".format(i, password))
+
+
+if __name__ == "__main__":
+ # Here we go!
+ number_of_logins = prompt()
+ complicted = complex_or_not()
+ length = how_long()
+ generate_logins(number_of_logins, length, complicted)
+
diff --git a/assets/subjects.txt b/assets/subjects.txt
new file mode 100644
index 0000000..52736ce
--- /dev/null
+++ b/assets/subjects.txt
@@ -0,0 +1,239 @@
+Aardvark
+African elephant
+Albatross
+Alley cat
+Alligator
+Amphibian
+Ant
+Anteater
+Antelope
+Ape
+Armadillo
+Asian elephant
+Baboon
+Badger
+Bat
+Bear
+Beaver
+Beetle
+Billy goat
+Bison
+Boar
+Bobcat
+Bovine
+Bronco
+Buck
+Buffalo
+Bug
+Bull
+Bunny
+BunnyCalf
+Camel
+Canary
+Canine
+Caribou
+Cat
+Caterpillar
+Centipede
+Chanticleer
+Cheetah
+Chick
+Chimpanzee
+Chinchilla
+Chipmunk
+Clam
+Cockatiel
+Colt
+Condor
+Cougar
+Cow
+Coyote
+Crab
+Crane
+Creature
+Crocodile
+Crow
+Cub
+Cur
+Cygnet
+Deer
+Dingo
+Dodo
+Doe
+Dog
+Dolphin
+Donkey
+Dove
+Drake
+Duck
+Eagle
+Egret
+Elephant
+Elk
+Emu
+Ewe
+Falcon
+Fawn
+Feline
+Ferret
+Flamingo
+Flee
+Flies
+Foal
+Fowl
+Fox
+Frog
+Gander
+Gazelle
+Gelding
+Gerbil
+Gibbon
+Giraffe
+Goat
+Goose
+Gopher
+Gorilla
+Grizzly bear
+Guinea pig
+Hamster
+Hare
+Hawk
+Hedgehog
+Heifer
+Hippopotamus
+Horse
+Hound
+Hummingbird
+Hyena
+Ibis
+Iguana
+Jackal
+Jackrabbit
+Jaguar
+Javalina
+Jellyfish
+Jenny
+Joey
+Kangaroo
+Kid
+Kitten
+Kiwi
+Koala
+Komodo dragon
+Krill
+Lamb
+Lemming
+Lemur
+Leopard
+Lion
+Lioness
+Llama
+Lobster
+Lynx
+Macaw
+Manatee
+Marmoset
+Marmot
+Mink
+Minnow
+Mite
+Mockingbird
+Mole
+Mongoose
+Mongrel
+Monkey
+Moose
+Mouse
+Mule
+Mustang
+Mutt
+Nag
+Narwhale
+Newt
+Ocelot
+Octopus
+Opossum
+Orangutan
+Orca
+Osprey
+Ostrich
+Otter
+Owl
+Ox
+Pachyderm
+Panda
+Panther
+Parakeet
+Parrot
+Peacock
+Pelican
+Penguin
+Pheasant
+Pig
+Pigeon
+Piglet
+Platypus
+Pony
+Pooch
+Porcupine
+Porpoise
+Primate
+Puppy
+Pussycat
+Rabbit
+Raccoon
+Ram
+Rat
+Reptiles
+Rhinoceros
+Robin
+Rooster
+Salamander
+Sea lion
+Seagull
+Seal
+Sheep
+Sidewinder
+Skunk
+Sloth
+Snail
+Snake
+Songbird
+Sow
+Spider
+Squid
+Squirrel
+Stallion
+Steer
+Stork
+Stork
+Swan
+Tadpole
+Tapir
+Terrapin
+Thoroughbred
+Tiger
+Toad
+Tortoise
+Toucan
+Turkey
+Uakari
+Unicorn
+Vixen
+Vole
+Vulture
+Wallaby
+Walrus
+Warthog
+Wasp
+Weasel
+Whale
+Wildebeast
+Wolf
+Wombat
+Woodpecker
+Worm
+X-ray fish
+Yak
+Zebra
+
diff --git a/learning_python3.md b/learning_python3.md
index e14a8da..7109132 100644
--- a/learning_python3.md
+++ b/learning_python3.md
@@ -1072,67 +1072,815 @@ There are a couple of things you should definitely read up on.
# While loop
-TODO guess the number exercise
+We started our python journey with fully linear code.
+Next we saw functions which are first **defined** and called afterwards.
+Now we'll have a look at **loops**.
+In python there are **two** types of loops, a **while** and a **for** loop.
+We'll start with the while loop which I see as a loop in *time*.
+The for loop is a loop in *space* but we'll get to that one later.
+
+The concept of a while loop is pretty simple.
+Code **within** the loop will be executed as long as a **condition** is met.
+Consider the code below.
+
+```python3
+import time
+
+counter = 0
+print("before the loop, counter: {}".format(counter))
+
+while counter <= 10:
+ print("inside the loop, counter: {}".format(counter))
+ counter += 1
+ time.sleep(1)
+
+print("after the loop, counter: {}".format(counter))
+```
+
+Two *extra* things might look new to you here.
+First the `import time` and `time.sleep(1)`, can you tell me what it does?
+Next the `counter += 1` which is called [incrementing](https://stackoverflow.com/questions/1485841/behaviour-of-increment-and-decrement-operators-in-python).
+You'll find this feature in most languages.
+You can think of it's syntax as *counter equals itself plus 1*.
+The *1* can be any number you want though!
+
+When learning the `while` [keyword](https://docs.python.org/3/reference/compound_stmts.html#the-while-statement) there is a *second* keyword you should learn.
+It comes in very handy when constructing [infinite loops](https://en.wikipedia.org/wiki/Infinite_loop).
+Consider the following code.
+
+```python3
+import time
+
+counter = 0
+print("before the loop, counter: {}".format(counter))
+
+while True:
+ print("inside the loop, counter: {}".format(counter))
+ counter += 1
+ time.sleep(1)
+
+print("after the loop, counter: {}".format(counter))
+```
+
+The `while True` condition is *always* `True` so the loop will **never** exit!
+This is what we call an infinite loop.
+The `break` keyword was added to the language so we can *break out* of a loop.
+The logic is as follows.
+
+```python3
+import time
+
+counter = 0
+print("before the loop, counter: {}".format(counter))
+
+while True:
+ print("inside the loop, counter: {}".format(counter))
+ counter += 1
+ if counter >= 10:
+ print("I'll break now!")
+ break
+ time.sleep(1)
+
+print("after the loop, counter: {}".format(counter))
+```
+
+Infinite loops are a cornerstone of modern programming.
+While they might look scary, don't overthink it, you'll get used to them very quickly.
+
+⛑ **When testing out an infinite loop it's sometimes handy to insert a `time.sleep` in it to slow down the execution a bit so you can wrap your head around what's happening.**
+
+🏃 Try it
+---
+
+Go back to the Celsius to Farenheit converter and add a while loop to ensure the user put's in only numbers.
+
+
+# Coding challenge - Guess the number
+
+Now that you know how to repeat code execution we can create our first game!
+Everybody knows the *guess the number* game.
+The computer chooses a *random* number and the user has to *guess* which number it is.
+At each try the computer will till you if the user's number is bigger or smaller *than* the one the computer has in mind.
+The flow of the game could be as follows.
+
+```
+I have a number in mind...
+What's your guess? 50
+my number is bigger
+What's your guess? 80
+my number is smaller
+What's your guess? blabla
+that's not a number! try again...
+What's your guess? 76
+yes, that's right! you win!
+bye bye...
+```
+
+
+ Spoiler warning
+
+```python3
+import random
+
+
+def ask_for_number():
+ result = input("What's your guess? ")
+ if result.isdigit():
+ number = int(result)
+ return number
+ else:
+ return None
+
+
+if __name__ == "__main__":
+ number_to_guess = random.randint(0, 100)
+ print("I have a number in mind...")
+ while True:
+ user_number = ask_for_number()
+ if user_number is None:
+ print("that's not a number! try again...")
+ continue
+ elif number_to_guess == user_number:
+ print("yes, that's right! you win!")
+ break
+ elif number_to_guess > user_number:
+ print("my number is bigger")
+ elif number_to_guess < user_number:
+ print("my number is smaller")
+ print("bye bye...")
+```
+
+
+
+🏃 Try it
+---
+
+My *solution* is very basic.
+Think of some ways to improve on it.
+Can you limit the number of tries?
+Can you add a feature to let the user play a *second* game after he/she wins or loses?
+Coming up with challenges is on of the most *challenging* aspect op learning how to program.
+Your thought process will send you of into unknown territory and will force you to expand you knowledge.
+We'll get back to this thought process later, but if you feel like an extra challenge go for it!
# Lists
+The different built-in objects we've seen until now, such as `str` and `int` are simple [text](https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str) and [numeric](https://docs.python.org/3/library/stdtypes.html#numeric-types-int-float-complex) types.
+There are other classes of objects that server different purposes.
+One of these *groups* is called [sequence types](https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range).
+
+A list in python is pretty much exactly what you think it is.
+It is an *object* that groups together *other* objects.
+Sounds complicated?
+Have a look at the following.
+
+```python3
+my_numbers = [1, 2, 44, 60, 70]
+print(my_numbers)
+```
+
+Easy right?
+Compared to [other languages](https://www.cplusplus.com/reference/list/list/) lists in python are *very* flexible.
+They can contain objects of different types, and their length can be changed at any time.
+Programmers coming from other languages often find this flexibility of python a bug but you should see it as a feature.
+
+```python3
+favorite_number = 7
+name = "wouter"
+date = [1986, 10, 7]
+values = [1, date, favorite_number, "hello world", name]
+
+print(values)
+```
+
+The code above is just an illustration of the flexibility of lists.
+
## Creating lists
-## Picking elements
+Creating lists can be done in two ways, either by using the **square brackets** `[]` or by calling `list`.
+When calling `list` it takes **one argument**, which python will iterate over.
+For example:
-## Slicing lists
+```python3
+>>> first_list = ["hello", "world", "!"]
+>>> first_list
+['hello', 'world', '!']
+>>> second_list = list("hello world !")
+>>> second_list
+['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', ' ', '!']
+>>>
+```
+
+## List methods
+
+As a `list` is a different type of object, it has different methods you can invoke on it.
+When using tab complete in the python shell we get the following.
+
+```python3
+>>> second_list.
+second_list.append( second_list.count( second_list.insert( second_list.reverse(
+second_list.clear( second_list.extend( second_list.pop( second_list.sort(
+second_list.copy( second_list.index( second_list.remove(
+>>> second_list.
+```
+
+One of the most used methods is `append`.
+It is used to add an element to the end of the list.
+The second most used method is the `pop` one.
+Read the shell code below and you'll understand immediately what they do.
+
+```python3
+>>> first_list
+['hello', 'world', '!']
+>>> first_list.append("coucou")
+>>> first_list
+['hello', 'world', '!', 'coucou']
+>>> first_list.pop()
+'coucou'
+>>> first_list
+['hello', 'world', '!']
+>>>
+```
+
+🏃 Try it
+---
+
+Look at all the methods you can invoke on a list and try them out.
+Remember to read the documentation!
+
+## Picking elements and slicing lists
+
+We can pick elements from the list of slice the list as we please.
+A code block speaks more than words.
+
+```python3
+>>> long_list
+['I', 'am', 'a', 'very', 'long', 'list', 'of', 'words', 'that', 'make', 'little', 'actual', 'sense']
+>>> long_list[7]
+'words'
+>>> long_list[7:9]
+['words', 'that']
+>>> long_list[7:]
+['words', 'that', 'make', 'little', 'actual', 'sense']
+>>> long_list[:7]
+['I', 'am', 'a', 'very', 'long', 'list', 'of']
+>>> long_list[-1]
+'sense'
+>>> long_list[0]
+'I'
+>>>
+```
+
+⛑ **In programming we start counting at 0 because 0 and nothing are not the same thing.**
+
+🏃 Try it
+---
+
+Slice and dice away!
+A handy method of the `str` class is `split` which will cut up a string into separate elements.
+The result will be a `list` on which you can use `list` methods.
# For loop
-TODO say hello to my friends exercise
-TODO simple ROT13 cryptography with multiple libs
+I mentioned the for loop, which is a loop in space, when we saw the `while` loop.
+The [keyword](https://docs.python.org/3/reference/compound_stmts.html#the-for-statement) in question is, surprise surprise, `for`!
+I see it as a loop in space because it will run *for each element in a sequence* which in my mind is something of substance.
+Your logical mileage may vary but as long as you understand the following code block we're good.
+
+```python3
+import time
+
+friends = ["max", "mike", "alice", "steve", "rosa", "hans"]
+
+print("The door opens and in walk my {} friends!".format(len(friends)))
+
+for friend in friends:
+ print("Hello {}!".format(friend.capitalize()))
+ time.sleep(1)
+
+print("{} closes the door behind him...".format(friend.capitalize()))
+```
# Coding challenge - Cheerleader chant
-TODO nested for loop exercise
+Can you make me a program that outputs this type of cheerleader chant?
+You can make it *prettier* by importing your `pretty_print` function, plus you can add some `time.sleep` in it to make it more *musical*.
+
+```
+Give me an m
+M
+Give me an a
+A
+Give me an x
+X
+Gooooooooo, MAX!
+Give me an m
+M
+Give me an i
+I
+Give me an k
+K
+Give me an e
+E
+Gooooooooo, MIKE!
+Give me an c
+C
+Give me an a
+A
+Give me an m
+M
+Give me an i
+I
+Give me an l
+L
+Give me an l
+L
+Give me an e
+E
+Gooooooooo, CAMILLE!
+```
+
+
+ Spoiler warning
+
+```python3
+friends = ["max", "mike", "camille"]
+
+
+for friend in friends:
+ for letter in friend:
+ print("Give me an {}".format(letter))
+ print("{}".format(letter.upper()))
+ print("Gooooooooo, {}!".format(friend.upper()))
+```
+
+
+
+# Coding challenge - ROT13
+
+ROT13 is one of the oldest cryptographic cyphers know to mankind.
+It dates back to the Roman empire and is also known as a [Caesar cypher](https://en.wikipedia.org/wiki/Caesar_cipher).
+The algorithm is pretty simple, you just shift a letter 13 places in the alphabet so `a` becomes `n` or `x` becomes `k`.
+Have a look at [this](https://rot13.com/) website to see the cypher in action.
+Now, can you make a program that encrypts a phrase with ROT13?
+Something along these lines:
+
+```python3
+What's your secret? hello world!
+encoded secret: uryyb jbeyq!
+```
+
+
+ Spoiler warning
+
+```python3
+import string
+
+
+def encode_rot(msg, rot=13):
+ msg = msg.lower()
+ letters = list(string.ascii_lowercase)
+ coded_msg = []
+ for letter in msg:
+ if letter not in letters:
+ coded_msg.append(letter)
+ else:
+ idx = letters.index(letter) + rot
+ coded_letter = letters[idx % len(letters)]
+ coded_msg.append(coded_letter)
+ coded_msg = "".join(coded_msg)
+ return coded_msg
+
+
+def decode_rot(msg, rot=13):
+ pass
+
+
+if __name__ == "__main__":
+ clear_message = input("What's your secret? ")
+ encoded_message = encode_rot(clear_message)
+ print("encoded secret: {}".format(encoded_message))
+```
+
+
+
+🏃 Try it
+---
+
+To make things more interesting you can add a decode function.
+Plus you could add a prompt that asks how big the shift should be (ROT13, ROT16, ...).
+
+# List comprehension
+
+This is a bit of an advanced topic but I'm putting it here to show you a very unique and powerful feature of python.
+It's an *in-line* combination of `list`, `for` and conditional logic which allows us to make lists of lists which obey certain conditions.
+You can [learn](https://12ft.io/proxy?q=https%3A%2F%2Frealpython.com%2Flist-comprehension-python%2F) about it online.
+
+```python3
+mixed_list = ["one", "2", "three", "4", "5", "six6", "se7en", "8"]
+
+digits = [d for d in mixed_list if d.isdigit()]
+
+print(digits)
+```
+
+The code above can be recreated **without** list comprehension as well, it will just be *a lot* longer.
+
+```python3
+mixed_list = ["one", "2", "three", "4", "5", "six6", "se7en", "8"]
+
+digits = []
+for d in mixed_list:
+ if d.isdigit():
+ digits.append(d)
+
+print(digits)
+```
+
+As the `d` in the list comprehension is **always** a digit, we can convert it to an integer on the spot!
+
+```python3
+mixed_list = ["one", "2", "three", "4", "5", "six6", "se7en", "8"]
+
+digits = [int(d) for d in mixed_list if d.isdigit()]
+
+print(digits)
+```
# Handling files
+When we `import` a library python will read and execute the file in question.
+We can also just *read* a simple text file and *use* the data that's in the file.
+There are two ways of reading a file, one more *pythonic* and one more linear.
+I'll outline both and you can use whichever seems more logical to you.
+
## Reading from a file
+### In-line way
+
+The builtin function `open` is what's new here.
+It takes two arguments, one is the [path](https://en.wikipedia.org/wiki/Path_(computing)) and the other is a *mode*.
+The most used modes are **read** or **write**, and this as either **text** or **binary**.
+Have a look at the documentation to discover more modes.
+
+```python3
+fp = open("./examples/data.txt", "r")
+data = fp.readlines()
+print("file contains: {}".format(data))
+fp.close()
+```
+
+### Pythonic way
+
+The *exact* same thing can be done in a more pythonic way as follows.
+The beauty of the `with` syntax is that the `close` function call is implied by the indentation.
+I personally prefer this way of reading and writing files but you do you!
+
+```python3
+file_to_open = "./examples/data.txt"
+
+with open(file_to_open, "r") as fp:
+ data = fp.readlines()
+ print("file contains: {}".format(data))
+
+print("{} has {} lines".format(file_to_open, len(data)))
+```
+
## Writing to a file
-## csv, JSON and yaml
+Writing to a file can also be done in two ways, a pythonic and *less* pythonic way.
+As I prefer the pythonic way I'll only showcase that one but you'll be able to easily adapt the code yourself.
+The only difference is the **mode** we use to `open` the file.
-## pickle
+```python3
+first_name = input("what's your first name? ")
+last_name = input("what's your last name? ")
+birthday = input("what's your date of birth? ")
+
+data = [first_name, last_name, birthday]
+
+file_to_open = "./examples/test.tmp"
+
+with open(file_to_open, "w") as fp:
+ for element in data:
+ fp.write("{}\n".format(element))
+print("done!")
+```
+
+There is also a way to write a batch of lines to a file in one go.
+This is done as follows.
+But, you'll notice there is no **newline** added after each element.
+
+```python3
+data = ["wouter", "gordts", "1986"]
+
+file_to_open = "./examples/test.tmp"
+
+with open(file_to_open, "w") as fp:
+ fp.writelines(data)
+```
# Coding challenge - Login generator
-TODO write a login generator as a library with a cli as program
-BONUS argparse, save to file, read from file
+Can you write me a program that creates random, but easy to remember, usernames?
+Plus, for each username also a *not-so-easy-to-remember* password?
+Maybe with a bit of flexibility?
+For example variable password length?
+
+This is an exercise you can take pretty far if you plan it out properly.
+I would advise you to write the **generator** functions as a library.
+Then import those functions into the program where you implement the user facing logic.
+By doing so you can reuse your code for multiple interfaces (CLI, TUI, [argparse](https://docs.python.org/3/howto/argparse.html)).
+If you want to you can also **save** your logins to a file!
+
+An example of the output I expect:
+
+```
+how many login pairs would you like to create?3
+you want complex passwords? (y/n)y
+how long should the password be?32
+username 0: EarnestCrocodile
+password 0: :sdGV&[FDYZZ|RXUpZeo`J&t@*Z>^fEW
+username 1: AbstractedDragon
+password 1: 32hz5&C@
+ Spoiler warning
+
+This spoiler warning is in multiple steps.
+If you're unsure how to generate the *random-yet-easy-to-remember* have a look at [this file](./assets/subjects.txt) and [this file](./assets/adjectives.txt).
+
+**Stop here and try it out!**
+
+If you're unsure how to tackle the *library part* of this exercise, have a look at [this file](./assets/login_generator.py).
+Don't just copy this code, read it and recreate it yourself!
+
+**Stop here and try it out!**
+
+Once the library is done you can code the *interface*.
+For some inspiration for a simple question/response system you can have a look [here](./assets/pwd_cli.py).
+
+
# Dictionaries as data containers
-TODO adapt the login generator to output a dict
+Of the *built-in* types we first say `str`, `int` and `float`.
+Next we saw *sequence* types such as `list` and `tupple`.
+Now we'll dive into a **mapping type** called `dict`.
+I advise you to have a look at the [reference pages](https://docs.python.org/3/library/stdtypes.html#mapping-types-dict) when in doubt.
-# Creating our own classes
+A dictionary is *kind* of like a list but it has **two** objects per **element**.
+We call them **key** and **value**.
+There are a couple of rules you need to be aware of though.
-## Class examples
+1. In a `dict` the keys have to be **unique**.
+2. A dictionary is **unordered** meaning the *first* element is not garanteed to remain the first over the lifespan of the dictionary.
+3. The keys used must be **hashable**.
+
+Let's visualize a legal dictionary!
+It's declared with **curly brackets** as follows `{}`.
+
+```python3
+my_data = {"key": "value", "name": "wouter", "age": 35}
+
+same_data_different_layout = {
+ "key": "value",
+ "name": "wouter",
+ "age": 35,
+ }
+```
+
+Let's have a look at the **methods** we can invoke on a `dict`.
+
+```python3
+>>> my_data = {"key": "value", "name": "wouter", "age": 35,}
+>>> my_data.
+my_data.clear( my_data.get( my_data.pop( my_data.update(
+my_data.copy( my_data.items( my_data.popitem( my_data.values(
+my_data.fromkeys( my_data.keys( my_data.setdefault(
+>>> my_data.keys()
+dict_keys(['key', 'name', 'age'])
+>>> my_data.values()
+dict_values(['value', 'wouter', 35])
+>>> my_data.items()
+dict_items([('key', 'value'), ('name', 'wouter'), ('age', 35)])
+>>> for key, value in my_data.items():
+... print("key is {}".format(key))
+... print("value is {}".format(value))
+...
+key is key
+value is value
+key is name
+value is wouter
+key is age
+value is 35
+>>>
+```
+
+We can reference specific **values** corresponding to specific **keys** as follows.
+
+```pythons
+>>> my_data["name"]
+'wouter'
+>>> my_data["age"]
+35
+>>>
+```
+
+We can use dictionaries as data containers and put them in a list to group together similar data elements.
+The code below should explain it quite nicely.
+
+```python3
+login_ovh = {"username": "EarnestCrocodile", "password": ":sdGV&[FDYZZ|RXUpZeo`J&t@*Z>^fEW"}
+login_mailbox = {"username": "AbstractedDragon", "password": "32hz5&C@
+ Spoiler warning
+
+```python3
+import argparse
+import pathlib
+
+
+def read_taskfile(taskfile_path):
+ tasks = []
+ if not pathlib.Path(taskfile_path).exists():
+ return tasks
+ with open(taskfile_path, "r") as fp:
+ lines = fp.readlines()
+ for line in lines:
+ task = line.strip()
+ tasks.append(task)
+ return tasks
+
+
+def write_taskfile(taskfile_path, tasks):
+ with open(taskfile_path, "w") as fp:
+ for task in tasks:
+ fp.write("{}\n".format(task))
+
+
+def show_tasks(tasks):
+ counter = 0
+ for task in tasks:
+ print("ID: {} --- {}".format(counter, task))
+ counter += 1
+
+
+def add_task(tasks, task):
+ tasks.append(task)
+ return tasks
+
+
+def delete_task(tasks, task_id):
+ tasks.pop(task_id)
+ return tasks
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--file", "-f", default="./todo.tasks", help="path to your todo file")
+ subparser = parser.add_subparsers()
+ add = subparser.add_parser("add", help="adds a todo item to you todo list")
+ add.add_argument("task", nargs="*")
+ delete = subparser.add_parser("delete", help="deletes an item from your todo list")
+ delete.add_argument("idx", type=int, nargs="*")
+ show = subparser.add_parser("show", help="show all your tasks")
+ show.add_argument("show", action="store_true")
+ args = parser.parse_args()
+
+ taskfile = args.file
+ tasks = read_taskfile(taskfile)
+
+ if "task" in args:
+ tasks = add_task(tasks, " ".join(args.task))
+ write_taskfile(taskfile, tasks)
+ elif "idx" in args:
+ for idx in args.idx:
+ tasks = delete_task(tasks, idx)
+ write_taskfile(taskfile, tasks)
+ elif args.show:
+ show_tasks(tasks)
+```
+
+
+# Text based databases
+
+The todo list example from before is handy but quite *limited* as a database.
+As is it only holds one form or information and that is the *actual task*.
+What if we want to add urgency or mark tasks complete (instead of deleting)?
+This can be done by grouping data together.
+We already saw a dictionaries which are good mapping structures but how can we save them to disk?
+A hacky way would be to write a python file containing the `dict` and `import` it when we need it.
+But there are better ways.
+
+
+# Now for some useful scripting
+
+With everything we have learned up until now you can start doing some interesting and useful things.
+Have a look at [these exercises](https://gitea.86thumbs.net/waldek/linux_course_doc/src/branch/master/modules/qualifying/exercise_python.md).
+You can try them out at your own pace.
+I can give some hints or pointers if needed, either in class or individually.
+Don't hesitate to ask for help!
+
+# Creating our own objects
+
+## First some *abstract* examples
TODO simple animal or vehicle exercise
-TODO task manager
## Class inheritance
TODO shapes and surfaces
-TODO superhero game
-## Improve the login generator
+## Now some *practical* improvements
+
+### Improve the login generator
TODO convert the login generator to a class
+### Improve the task manager
+
+TODO convert the task manager to a class
+
# Infinite programs
* insist on the nature of scripts we did up until now
## Logic breakdown of a simple game
-TODO hangman exercise
+```
+***********************
+* welcome to hangman! *
+***********************
+
+guess the hidden word below
+---------------------------
+word: *****
+guess a letter: a
+word: a****
+guess a letter: l
+word: a**l*
+guess a letter: p
+word: appl*
+guess a letter: e
+word: apple
+*****************
+* you found it! *
+*****************
+do you want to play a new game? (Y/N)
+```
## Trivial pursuit multiple choice game