8
\$\begingroup\$

I made this project that simulates a frozen yogurt shop, where you can pick your flavor, toppings, and sauces and then pay for it. I'm a beginner at python and this is my first project. I don't even know where this idea came from - I was hungry I guess. I feel like this code is unnecessarily long and redundant though, and I would like to receive some feedback how to make this more advanced.

The first coding file is the main, the second coding file is where I put some of the functions, and the third file is a text file of the (very long) menu. The menu can be changed without affecting the code. If anyone could take the time to look at this that would be amazing.

import functions

menu_file = open("menu.txt", "r+")
menu = menu_file.readlines()
flavors = []
toppings = []
sauces = []
flavor_dictionary = {}
topping_dictionary = {}
sauce_dictionary = {}
price = 0

wants_toppings = ""
order_toppings = []
no_more_toppings = False
order_topping = 0
wants_more_toppings = False
wants_toppings_input = False

wants_sauces = ""
order_sauces = []
no_more_sauces = False
order_sauce = 0
wants_more_sauces = False
wants_sauces_input = False

# Create lists for flavors, toppings, and sauces
for i in range(menu.index("Flavors:\n")+1, menu.index("Toppings:\n")-1):
    flavors.append(menu[i].rstrip("\n"))
    flavor_dictionary[i] = flavors[i - 1]
for i in range(menu.index("Toppings:\n")+1, menu.index("Sauces:\n")-1):
    toppings.append(menu[i].rstrip("\n"))
    topping_dictionary[(i - menu.index("Toppings:\n"))] = toppings[(i - menu.index("Toppings:\n")) - 1]
for i in range(menu.index("Sauces:\n")+1, menu.index(menu[-1])+1):
    sauces.append(menu[i].rstrip("\n"))
    sauce_dictionary[(i - menu.index("Sauces:\n"))] = sauces[(i - menu.index("Sauces:\n")) - 1]
menu_file.close()

# Ask customer if they want to order
print("\n✧༺♥༻∞ Welcome to Sweet Frost Frozen Yogurt Shop ∞༺♥༻✧")
wants_to_order = input("Would you like to place an order? [Yes/No] ")
asking = True
while asking:
    if wants_to_order.upper() == "YES" or wants_to_order.upper() == "Y":
        ordering = True
        break
    elif wants_to_order.upper() == "NO" or wants_to_order.upper() == "N":
        ordering = False
        paying = False
        break
    elif wants_to_order.upper() != "YES" and wants_to_order.upper() != "Y" and wants_to_order.upper() != "NO" and wants_to_order.upper() != "N":
        print("Invalid input")
        wants_to_order = input("Would you like to place an order? [Yes/No] ")
        continue

# Take size of order
while ordering:
    order_size = input("\nWhat size cup would you like?\n[a] Small - $3.00\n[b] Medium - $4.00\n[c] Large - $6.00\n")
    while (order_size.lower() != "a" and order_size.lower() != "b" and order_size.lower() != "c"):
        print("Invalid input")
        order_size = input("What size cup would you like?\n[a] Small\n[b] Medium\n[c] Large\n")
    if order_size.lower() == "a":
        size = "Small"
        price = price + 3.00
    elif order_size.lower() == "b":
        size = "Medium"
        price = price + 4.00
    elif order_size.lower() == "c":
        size = "Large"
        price = price + 6.00

# Take flavor of order
    print("What flavor would you like for your " + size.lower() + " frozen yogurt?")
    for i in range(len(flavors)):
        print("[" + str(i+1) + "] " + flavors[i])
    order_flavor = input()
    while order_flavor.isdigit() == False or int(order_flavor) == 0 or int(order_flavor) > len(flavors):
        print("Invalid input\nWhat flavor would you like for your " + size.lower() + " frozen yogurt? ")
        order_flavor = input()

    # Take toppings and sauces of order
    if order_flavor.isdigit() == True and int(order_flavor) <= len(flavors) and int(order_flavor) > 0:
        functions.run_choices("topping", toppings, size, flavor_dictionary, topping_dictionary, order_flavor, wants_toppings, order_toppings, no_more_toppings, order_topping, wants_more_toppings)
        functions.choices("topping", toppings, size, flavor_dictionary, topping_dictionary, order_flavor, wants_toppings, order_toppings, no_more_toppings, order_topping, wants_more_toppings, wants_toppings_input)
        functions.run_choices("sauce", sauces, size, flavor_dictionary, sauce_dictionary, order_flavor, wants_sauces, order_sauces, no_more_sauces, order_sauce, wants_more_sauces)
        functions.choices("sauce", sauces, size, flavor_dictionary, sauce_dictionary, order_flavor, wants_sauces, order_sauces, no_more_sauces, order_sauce, wants_more_sauces, wants_sauces_input)

   # Ask customer if they want to make another purchase
    wants_to_order = input("Would you like to make another purchase? [Yes/No] ")
    if wants_to_order.upper() != "YES" and wants_to_order.upper() != "Y" and wants_to_order.upper() != "NO" and wants_to_order.upper() != "N":
        valid_order_input = False
        while valid_order_input != True:
            print("Invalid input")
            wants_to_order = input("Would you like to place an order? [Yes/No] ")
    elif wants_to_order.upper() == "YES" or wants_to_order.upper() == "Y":
        ordering = True
        paying = False
    elif wants_to_order.upper() == "NO" or wants_to_order.upper() == "N":
        ordering = False
        paying = True

# Take payment from customer
while paying:
    print("\nThank you for your purchase at Sweet Frost Yogurt Shop! Your total is $" + str(price) + "0")
    cash_amount = input("Please enter your cash amount: $")
    converted_cash_amount = functions.check_cash(cash_amount)

# Customer overpaid or paid exact amount
    if converted_cash_amount >= price:
        change = "{:.2f}".format(converted_cash_amount - price)
        print("Your change is $" + change)
        break

# Customer underpaid
    elif converted_cash_amount < price:
        enough_cash = False
        while not enough_cash:
            amount_owed = price - converted_cash_amount
            formatted_amount_owed = "{:.2f}".format(amount_owed)
            cash_amount = input("You still owe $" + formatted_amount_owed + ". Please enter your remaining cash amount: $")
            converted_cash_amount = functions.check_cash(cash_amount)
            if converted_cash_amount >= amount_owed:
                change = converted_cash_amount - amount_owed
                formatted_change = "{:.2f}".format(change)
                print("Your change is $" + formatted_change)
                enough_cash = True
                paying = False
            elif converted_cash_amount < float(amount_owed):
                price = float(amount_owed)
                enough_cash = False
                continue

print("✧༺♥༻∞ Thanks for stopping by! ∞༺♥༻✧")

# Print out list of toppings and sauces
def run_choices(type, list_of_type, size, flavor_dictionary, type_dictionary, order_flavor, wants_type, order_types, no_more_types, order_type, wants_more_type):
    print("\nCheck out our " + type + " menu:")
    for i in range(len(list_of_type)):
        print("[" + str(i + 1) + "] " + list_of_type[i])

# Get the toppings and sauces the customer wants
def choices(type, list_of_type, size, flavor_dictionary, type_dictionary, order_flavor, wants_type, order_types, no_more_types, order_type, wants_more_type, wants_type_input):
    wants_type = input("Would you like to add any " + type + "s" + " to your " + size.lower() + " " + flavor_dictionary[int(order_flavor)].lower() + " frozen yogurt? [Yes/No] ")
    while wants_type_input == False:
        if wants_type.upper() == "NO" or wants_type.upper() == "N":
            wants_type_input = True
        elif wants_type.upper() == "YES" or wants_type.upper() == "Y":
            order_types = []
            no_more_types = False
            while no_more_types != True:
                print("What " + type + " would you like?")
                order_type = input()
                while order_type.isdigit() == False or int(order_type) == 0 or int(order_type) > len(list_of_type):
                    print("Invalid input\nWhat " + type + " would you like?")
                    order_type = input()
                if order_type.isdigit() == True and int(order_type) <= len(list_of_type) and int(order_type) > 0:
                    order_types.append(order_type)
                    wants_more_type = input("Would you like to add another " + type + "? [Yes/No] ")
                    if wants_more_type.upper() == "NO" or wants_more_type.upper() == "N":
                        print("Your " + flavor_dictionary[
                            int(order_flavor)].lower() + " frozen yogurt will have the following " + type + "s: ")
                        for i in range(len(order_types)):
                            order_types[i] = type_dictionary[int(order_types[i])]
                        print(order_types)
                        no_more_types = True
                        wants_type_input = True
                    elif wants_more_type.upper() == "YES" or wants_more_type.upper() == "Y":
                        no_more_types = False
        elif wants_type.upper() != "YES" and wants_type.upper() != "Y" and wants_type.upper() != "NO" and wants_type.upper() != "N":
            print("Invalid input")
            wants_type = input(
                "Would you like to add any " + type + "s" + " to your " + size.lower() + " " + flavor_dictionary[
                    int(order_flavor)].lower() + " frozen yogurt? [Yes/No] ")
            if wants_type.upper() == "NO" or wants_type.upper() == "N":
                break
            if wants_type.upper() == "Yes" or wants_type.upper() == "Y":
                wants_type_input = False

# Check if cash input is valid
def check_cash(cash_amount):
    accept_cash = False
    while not accept_cash:
        try:
            converted_cash_amount = float(cash_amount)
            accept_cash = True
        except ValueError:
            print("Invalid input")
            cash_amount = input("Please enter your cash amount: $")
            accept_cash = False
    converted_cash_amount = float(cash_amount)
    return converted_cash_amount
Flavors:
Banana
Blueberry
Blue raspberry
Brownie batter
Bubblegum
Butter pecan
Cake batter
Carrot cake
Cheesecake
Chocolate
Coconut
Coffee
Cookie dough
Cookies and cream
Cotton candy
Dulce de leche
French vanilla
Green apple
Honey dew
Lemon
Mango
Mint chocolate chip
Orange creamsicle
Peach
Peanut butter
Peppermint candy cane
Pistachio
Pumpkin pie
Red velvet
S'mores
Snickerdoodle
Strawberry
Strawberry banana
Strawberry kiwi
Vanilla
Watermelon

Toppings:
Almonds
Andes chocolate mints
Bananas
Blueberries
Brownie bites
Cheesecake bites
Chocolate chips
Cinnamon Toast Crunch
Coconut shavings
Cookie dough bites
Frosted animal crackers
Fruity Pebbles
Graham crackers
Granola
Gummy bears
Jelly beans
Kit Kat
Kiwi
M&M's
Marshmallows
Oreo crumbs
Peanut butter chips
Peanuts
Pecans
Pineapple
Reese's peanut butter cups
Reese's Pieces
Pretzels
Pumpkin pie bites
Rainbow sprinkles
Snickers
Strawberries
Waffle cone
Walnuts
White chocolate chips

Sauces:
Butterscotch sauce
Caramel sauce
Chocolate syrup
Honey
Marshmallow cream
Peanut butter sauce
Strawberry syrup
Whipped cream
White chocolate syrup
\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

Great start for a beginner. There's a lot to cover here.

It's not hugely useful to have a functions module, and since you're starting off in procedural programming, basically everything should be in a function - including all of the code in your first text block which currently sits in the global namespace.

You've not helped yourself in the format of menu.txt. All of your parsing code can go away if you migrate to a machine-legible format like JSON.

The string ✧༺♥༻∞ should be stored to some kind of constant, and a function made to print a banner surrounded by this string and then its reverse.

[Yes/No], for people used to Backus-Naur-form user interfaces, is not strictly what we would expect. Square brackets mean "optional". Instead consider (yes|no).

This kind of check:

if wants_to_order.upper() == "YES" or wants_to_order.upper() == "Y"

can be simplified, reasonably, to only care about the first letter:

if wants_to_order.upper().startswith('Y')

In your validation code, you write this twice:

    wants_to_order = input("Would you like to place an order? [Yes/No] ")

Write it only once, at the start of the loop.

Don't hard-code $3.00 into prompt strings like

"\nWhat size cup would you like?\n[a] Small - $3.00\n[b] Medium - $4.00\n[c] Large - $6.00\n"

Instead, store that number once as a float or Decimal, and then write out an interpolated f-string that formats that quantity using currency which will also include your dollar sign. This will also replace your "{:.2f}".format.

This:

    price = price + 3.00

can be replaced with in-place addition:

    price += SMALL_PRICE

Don't name a variable type - that shadows a built-in.

More broadly, it's very important that you use a good IDE like PyCharm, and actually listen to its recommendations. Some things it will tell you to fix:

  • you have various PEP8 formatting violations
  • you have some non-standard indentation
  • you have some redundant parentheses
  • you have some lines that are too long and need to be broken up by the use of parenthesized expressions
  • you have some chained comparisons that can be simplified

Of course while working through those suggestions, don't just accept them blindly: learn the rules that the linter follows and why they exist.

Procedurally: I suggest that while you chew on the above,

  • wait a few days before accepting an answer to your question, to allow for more feedback
  • don't update your existing question's code blocks with refactored code
  • once you're ready, come back to this site and post a new question with your refactored code
  • if you have brief questions I can address them in comments on this answer
  • if you have longer-form questions I will spin up a chat room to address them.

Suggested

If I had to write this, it would look very vaguely like this. It's not the only way to implement this application, but it should give you some food for thought.

menu.json

{
  "flavors": [
    "banana",
    "blueberry",
    "blue raspberry",
    "brownie batter",
    "bubblegum",
    "butter pecan",
    "cake batter",
    "carrot cake",
    "cheesecake",
    "chocolate",
    "coconut",
    "coffee",
    "cookie dough",
    "cookies and cream",
    "cotton candy",
    "dulce de leche",
    "french vanilla",
    "green apple",
    "honey dew",
    "lemon",
    "mango",
    "mint chocolate chip",
    "orange creamsicle",
    "peach",
    "peanut butter",
    "peppermint candy cane",
    "pistachio",
    "pumpkin pie",
    "red velvet",
    "s'mores",
    "snickerdoodle",
    "strawberry",
    "strawberry banana",
    "strawberry kiwi",
    "vanilla",
    "watermelon"
  ],
  "toppings": [
    "almonds",
    "andes chocolate mints",
    "bananas",
    "blueberries",
    "brownie bites",
    "cheesecake bites",
    "chocolate chips",
    "cinnamon toast crunch",
    "coconut shavings",
    "cookie dough bites",
    "frosted animal crackers",
    "fruity pebbles",
    "graham crackers",
    "granola",
    "gummy bears",
    "jelly beans",
    "kit kat",
    "kiwi",
    "m&m's",
    "marshmallows",
    "oreo crumbs",
    "peanut butter chips",
    "peanuts",
    "pecans",
    "pineapple",
    "reese's peanut butter cups",
    "reese's pieces",
    "pretzels",
    "pumpkin pie bites",
    "rainbow sprinkles",
    "snickers",
    "strawberries",
    "waffle cone",
    "walnuts",
    "white chocolate chips"
  ],
  "sauces": [
    "butterscotch sauce",
    "caramel sauce",
    "chocolate syrup",
    "honey",
    "marshmallow cream",
    "peanut butter sauce",
    "strawberry syrup",
    "whipped cream",
    "white chocolate syrup"
  ]
}

Python application

import json
from locale import currency, localeconv, setlocale, LC_ALL
from typing import Iterator, Sequence


SIZE_PRICES = {'s': 3, 'm': 4, 'l': 6}

SIZE_TITLES = {
    title[0]: title
    for title in ('small', 'medium', 'large')
}


setlocale(LC_ALL, '')  # Local currency formatting


with open('menu.json') as menu_file:
    menu = json.load(menu_file)
flavors = menu['flavors']
toppings = menu['toppings']
sauces = menu['sauces']


def banner(title: str) -> None:
    decor = '✧༺♥༻∞'
    print(f'{decor} {title} {decor[::-1]}')


def ask_yn(title: str) -> bool:
    prompt = f'{title} (y|n)? '
    while True:
        answer = input(prompt).lower()
        if answer.startswith('y'):
            return True
        if answer.startswith('n'):
            return False
        print('Invalid input')


def ask_option_letters(
    title: str,
    options: dict[str, str],  # letter, description
) -> str:
    prompt = (
        f'{title}?\n'
        + '\n'.join(
            f'  {letter.upper()}: {desc}'
            for letter, desc in options.items()
        )
        + '\n> '
    )

    while True:
        answer = input(prompt)[:1].lower()
        if answer in options:
            return answer
        print('Invalid input')


def ask_sequence(title: str, options: Sequence[str]) -> str:
    prompt = (
        f'{title}?\n'
        + '\n'.join(
            f'  {i}. {option.title()}'
            for i, option in enumerate(options, 1)
        )
        + '\n> '
    )

    while True:
        answer = input(prompt)
        if answer.isnumeric() and 0 < (i := int(answer)) <= len(options):
            return options[i - 1]
        print('Invalid input')


def show_menu(item_type: str, options: Sequence[str]) -> None:
    print(f'Check out our {item_type} menu:')
    print('\n'.join(
        f'  {i}. {option.title()}'
        for i, option in enumerate(options, 1)
    ))


def ask_menu(
    item_type: str,
    collection_name: str,
    options: Sequence[str],
) -> Iterator[str]:
    show_menu(item_type, options)

    more_prompt = f'Would you like to add a {item_type} to your {collection_name}'
    item_prompt = f'What {item_type} would you like? '

    while ask_yn(more_prompt):
        answer = input(item_prompt)
        if answer.isnumeric() and 0 < (i := int(answer)) <= len(options):
            yield options[i - 1]
        else:
            print('Invalid input')


def ask_cash(price: float) -> None:
    curr = localeconv()['currency_symbol']
    prompt = f'Please enter your cash amount: {curr}'

    while price > 0:
        print(f'You owe {currency(price)}.')
        while True:
            try:
                cash = float(input(prompt))
                if cash > 0:
                    break
            except ValueError:
                pass
            print('Invalid input')

        price -= cash

    print(f'Your change is {currency(-price)}.')


def choose_menu(item_type: str, collection_name: str, options: Sequence[str]) -> None:
    ordered = tuple(ask_menu(
        item_type=item_type, collection_name=collection_name, options=options,
    ))
    if ordered:
        ordered_desc = ', '.join(choice.title() for choice in ordered)
    else:
        ordered_desc = 'none chosen'

    print(
        f'Your {collection_name} will have the following {item_type}s: {ordered_desc}.\n'
    )


def take_order() -> float:
    size = ask_option_letters(
        title='What size cup would you like',
        options={
            letter: f'{name.title()} - {currency(SIZE_PRICES[letter])}'
            for letter, name in SIZE_TITLES.items()
        },
    )
    print()

    flavor = ask_sequence(
        title=f'What flavor would you like for your {SIZE_TITLES[size]} frozen yogurt',
        options=flavors,
    )
    print()

    description = f'{SIZE_TITLES[size]} {flavor} frozen yogurt'
    choose_menu(item_type='topping', collection_name=description, options=toppings)
    choose_menu(item_type='sauce', collection_name=description, options=sauces)

    return SIZE_PRICES[size]


def order_prices() -> Iterator[float]:
    while ask_yn('Would you like to add an order'):
        print()
        yield take_order()


def main() -> None:
    banner('Welcome to Sweet Frost Frozen Yogurt Shop')
    print()

    price = sum(order_prices())
    if price > 0:
        print('\nThank you for your purchase at Sweet Frost Yogurt Shop!')
        ask_cash(price)

    print()
    banner('Thanks for stopping by!')


if __name__ == '__main__':
    main()

Output

✧༺♥༻∞ Welcome to Sweet Frost Frozen Yogurt Shop ∞༻♥༺✧

Would you like to add an order (y|n)? y

What size cup would you like?
  S: Small - $3.00
  M: Medium - $4.00
  L: Large - $6.00
> m

What flavor would you like for your medium frozen yogurt?
  1. Banana
  2. Blueberry
  3. Blue Raspberry
  4. Brownie Batter
  5. Bubblegum
  6. Butter Pecan
  7. Cake Batter
  8. Carrot Cake
  9. Cheesecake
  10. Chocolate
  11. Coconut
  12. Coffee
  13. Cookie Dough
  14. Cookies And Cream
  15. Cotton Candy
  16. Dulce De Leche
  17. French Vanilla
  18. Green Apple
  19. Honey Dew
  20. Lemon
  21. Mango
  22. Mint Chocolate Chip
  23. Orange Creamsicle
  24. Peach
  25. Peanut Butter
  26. Peppermint Candy Cane
  27. Pistachio
  28. Pumpkin Pie
  29. Red Velvet
  30. S'Mores
  31. Snickerdoodle
  32. Strawberry
  33. Strawberry Banana
  34. Strawberry Kiwi
  35. Vanilla
  36. Watermelon
> 27

Check out our topping menu:
  1. Almonds
  2. Andes Chocolate Mints
  3. Bananas
  4. Blueberries
  5. Brownie Bites
  6. Cheesecake Bites
  7. Chocolate Chips
  8. Cinnamon Toast Crunch
  9. Coconut Shavings
  10. Cookie Dough Bites
  11. Frosted Animal Crackers
  12. Fruity Pebbles
  13. Graham Crackers
  14. Granola
  15. Gummy Bears
  16. Jelly Beans
  17. Kit Kat
  18. Kiwi
  19. M&M'S
  20. Marshmallows
  21. Oreo Crumbs
  22. Peanut Butter Chips
  23. Peanuts
  24. Pecans
  25. Pineapple
  26. Reese'S Peanut Butter Cups
  27. Reese'S Pieces
  28. Pretzels
  29. Pumpkin Pie Bites
  30. Rainbow Sprinkles
  31. Snickers
  32. Strawberries
  33. Waffle Cone
  34. Walnuts
  35. White Chocolate Chips
Would you like to add a topping to your medium pistachio frozen yogurt (y|n)? n
Your medium pistachio frozen yogurt will have the following toppings: none chosen.

Check out our sauce menu:
  1. Butterscotch Sauce
  2. Caramel Sauce
  3. Chocolate Syrup
  4. Honey
  5. Marshmallow Cream
  6. Peanut Butter Sauce
  7. Strawberry Syrup
  8. Whipped Cream
  9. White Chocolate Syrup
Would you like to add a sauce to your medium pistachio frozen yogurt (y|n)? y
What sauce would you like? 2
Would you like to add a sauce to your medium pistachio frozen yogurt (y|n)? y
What sauce would you like? 8
Would you like to add a sauce to your medium pistachio frozen yogurt (y|n)? n
Your medium pistachio frozen yogurt will have the following sauces: Caramel Sauce, Whipped Cream.

Would you like to add an order (y|n)? n

Thank you for your purchase at Sweet Frost Yogurt Shop!
You owe $4.00.
Please enter your cash amount: $2
You owe $2.00.
Please enter your cash amount: $5
Your change is $3.00.

✧༺♥༻∞ Thanks for stopping by! ∞༻♥༺✧
\$\endgroup\$
1
\$\begingroup\$

As Reinderien mentions, there is a lot to cover here.


menu_file = open("menu.txt", "r+")
menu = menu_file.readlines()
<<< 33 lines omitted >>>
menu_file.close()

Why is menu_file left open for so many lines? After menu_file.readlines(), the entire file has been read into memory. It can be closed immediately.

menu_file = open("menu.txt", "r+")
menu = menu_file.readlines()
menu_file.close()

But it would be better to use Python with statement to automatically close the resource at the end of the with block.

with open("menu.txt", "r+") as menu_file:
    menu = menu_file.readlines()

def run_choices(type, list_of_type, size, flavor_dictionary, type_dictionary, order_flavor, wants_type, order_types, no_more_types, order_type, wants_more_type):
    print("\nCheck out our " + type + " menu:")
    for i in range(len(list_of_type)):
        print("[" + str(i + 1) + "] " + list_of_type[i])

This function takes a whopping 11 arguments. How many are used? Only 2? Why are you passing in the extra 9 arguments??? Remove them!

Along this line, choices also takes too many parameters.

def run_choices(type, list_of_type):
    print("\nCheck out our " + type + " menu:")
    for i in range(len(list_of_type)):
        print("[" + str(i + 1) + "] " + list_of_type[i])

A better name is required. run_choices is doesn't make much sense, as nothing is being ran. "Show" or "Display" would be better. "list_of_" is redundant. A plural name would imply a multitude. Type hints would be make it better:

def display_menu(category: str, items: list[str]) -> None:
    print("\nCheck out our " + category + " menu:")
    for num, item in enumerate(items, 1):
        print(f"[{num}] {item}")

While close, order_type.isdigit() is not quite what you want. "¹²₁₂⓷".isdigit() returns True because superscript digits, subscript digits and circled numbers are still digits. The function you want is .isdecimal()


Why do you use both flavor, topping and sauce lists AND dictionaries? You don't need both. Choose either a list or a dictionary.


You are missing maraschino cherries; you need to add them.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.