Zomato SDE-1 Interview Experience: Questions and Answers
#zomato
#sde-1
#backend-interview-experience
My Zomato SDE-1 interview ran for about four hours with a ten-minute break. Round 1 covered a deep dive into my resume, a Zomato-style food delivery design, Bloom filters, WebRTC, SQL vs NoSQL and one DSA problem (find two numbers that appear once). Round 2, the manager round, had two DSA problems: fewest jumps when you can also jump to equal values and a matrix row and column reversal problem. Below I explain each one, slow solution first, with code that was compiled and run by our editors.
| Topic | Round | Core idea | Time and space |
|---|---|---|---|
| Resume deep dive | 1 | Know every line you wrote | n/a |
| Food delivery system | 1 | State machine, Strategy, Observer, idempotency | n/a |
| Bloom filter | 1 | "No" is certain, "yes" is probable | O(k) per check |
| WebRTC | 1 | Signaling, SDP, ICE, STUN, TURN | n/a |
| SQL vs NoSQL | 1 | Choose by access pattern | n/a |
| Two numbers appear once | 1 | XOR and the lowest set bit | O(n), O(1) |
| Fewest jumps, same-value moves | 2 | BFS, clear each value's list once | O(n), O(n) |
| Matrix reversals | 2 | Max of four mirror cells | O(n²), O(1) |
What this post covers
Most interview experience posts list question names and stop there. This one goes further: what was asked, how to think through each question and where people usually slip.
I have 0 to 1 years of experience, so this was an SDE-1 loop. If you are at the same stage, I hope this helps your preparation.
What did my Zomato SDE-1 interview day look like?
It was one long day. About four hours in total, with one ten-minute break in the middle.
Round 1 was a mix: my resume first, then a design problem, then a few concept questions, then one coding problem. After the break came the manager round with two coding problems.
Nothing in the list was exotic. It was the range that was demanding: from talking about my own project, to designing a food delivery app, to explaining how two browsers connect for a video call, to writing BFS. So prepare wide, at a calm medium depth, instead of going extremely deep on one topic.
One small practical tip: do not plan anything for the evening after. You will want to rest.
How did the resume deep dive go?
Quick answer: know the problem, your exact part, one thing that went wrong and one thing you would change, for every project on your resume.
Round 1 started with a deep dive into my resume.
In a resume deep dive, expect the questions to keep coming back to "why." Typical ones:
- Why did you pick this database?
- What happens if two users hit the same endpoint at the same moment?
- What breaks first if traffic grows ten times?
Here is what to take from it. A resume line is a promise. If it says "used Redis for caching," you must be able to explain what you cached, how long it lived and what happens on a cache miss. You will not know every answer and that is fine. The thing that works is saying, "I have not tested that, but my guess is this and here is how I would check." That is far better than a confident wrong answer.
If you do one thing tonight: pick two projects. For each, write four lines: the problem, your part, one thing that went wrong, one thing you would change. Say them out loud once. It feels silly and it works.
How do you design a food delivery system in an interview?
Quick answer: list the nouns, model the order as a state machine, use Strategy for rider assignment and Observer for notifications and protect payments with idempotency keys.
Since it was Zomato, the design question was about food delivery: customers order from restaurants and a delivery partner brings the food. If you are interviewing at a food delivery company, please practise this one. It is the most predictable question you will get.
Start with scope. Is it one restaurant per order? Can the customer cancel? Are riders assigned automatically? Simple answers are fine: one restaurant per order, automatic assignment, cancellation allowed early. Asking takes thirty seconds and shows you think before you build.
Step 1: Write down the nouns
Classes usually come from nouns in the problem.
Customer ---- places ----> Order ----> OrderItem ----> MenuItem
| |
| belongs to
v v
DeliveryPartner Restaurant
|
Payment, Address, Notification
Step 2: Draw the order lifecycle
This is the part I would spend the most effort on, because it is simple and it shows structure. An order must not jump from "preparing" to "delivered." Put that rule in one place.
PLACED ──► ACCEPTED ──► PREPARING ──► PICKED_UP ──► DELIVERED
│ │
└───────────┴──────► CANCELLED (only before preparation starts)
Here is a small version, compiled and run. It has the rules, a listener for notifications and a rider assignment strategy.
import java.util.*;
public class FoodOrderDemo {
enum Status { PLACED, ACCEPTED, PREPARING, PICKED_UP, DELIVERED, CANCELLED }
static final Map<Status, Set<Status>> NEXT = new EnumMap<>(Status.class);
static {
NEXT.put(Status.PLACED, EnumSet.of(Status.ACCEPTED, Status.CANCELLED));
NEXT.put(Status.ACCEPTED, EnumSet.of(Status.PREPARING, Status.CANCELLED));
NEXT.put(Status.PREPARING, EnumSet.of(Status.PICKED_UP));
NEXT.put(Status.PICKED_UP, EnumSet.of(Status.DELIVERED));
NEXT.put(Status.DELIVERED, EnumSet.noneOf(Status.class));
NEXT.put(Status.CANCELLED, EnumSet.noneOf(Status.class));
}
interface Listener { void onChange(String orderId, Status from, Status to); }
static class Order {
final String id; Status status = Status.PLACED;
final List<Listener> listeners = new ArrayList<>();
Order(String id) { this.id = id; }
synchronized void moveTo(Status to) {
if (!NEXT.get(status).contains(to))
throw new IllegalStateException(status + " -> " + to + " not allowed");
Status old = status; status = to;
for (Listener l : listeners) l.onChange(id, old, to);
}
}
record Rider(String name, double km) {}
interface AssignStrategy { Rider pick(List<Rider> free); }
static class Nearest implements AssignStrategy {
public Rider pick(List<Rider> free) {
return Collections.min(free, Comparator.comparingDouble(Rider::km));
}
}
public static void main(String[] a) {
Order o = new Order("ORD-1");
o.listeners.add((id, f, t) -> System.out.println("notify customer: " + id + " " + f + " -> " + t));
o.moveTo(Status.ACCEPTED); o.moveTo(Status.PREPARING);
try { o.moveTo(Status.DELIVERED); }
catch (IllegalStateException e) { System.out.println("blocked: " + e.getMessage()); }
o.moveTo(Status.PICKED_UP); o.moveTo(Status.DELIVERED);
System.out.println(new Nearest().pick(List.of(
new Rider("A", 2.4), new Rider("B", 0.9), new Rider("C", 1.7))));
}
}
What it printed:
notify customer: ORD-1 PLACED -> ACCEPTED
notify customer: ORD-1 ACCEPTED -> PREPARING
blocked: PREPARING -> DELIVERED not allowed
notify customer: ORD-1 PREPARING -> PICKED_UP
notify customer: ORD-1 PICKED_UP -> DELIVERED
Rider[name=B, km=0.9]
Step 3: Use a pattern only where it helps
Do not sprinkle pattern names to sound smart. Use each where the problem asks for it.
| Need | Pattern | Why |
|---|---|---|
| Tell customer, restaurant and rider when status changes | Observer | One change, many listeners |
| Order moves only in allowed steps | State | The rules live in one place |
| Choose a rider by nearest, least busy or best rated | Strategy | Swap the rule without touching Order |
| Pay by card, UPI or wallet | Factory with a common Payment interface |
Add a method without rewriting checkout |
Follow-ups worth preparing for
If I were you, I would get these ready. They are the natural next questions for this design.
Two riders get the same order at the same moment. What now? Make assignment one atomic step. Across many servers that means a conditional update in the database, such as "set the rider only if no rider is set yet." The second request fails and tries the next rider. A Java lock only protects one process and you will have many.
The customer taps "Pay" twice. Attach an idempotency key to every payment request. The server stores the key with its result. The second tap finds the same key and returns the stored result, so the customer is charged once.
How does it scale ten times? Keep app servers stateless behind a load balancer. Use a database for orders and payments, a cache for menus (read far more than written) and a queue for notifications so a slow SMS never blocks an order.
You will not design everything in the time you get. Cover the core well and say out loud what you left out.
What is a Bloom filter and how do you explain it in an interview?
Quick answer: a Bloom filter is a bit array plus a few hash functions that tells you an item is either definitely not in a set or probably in it. It uses very little memory and never gives false negatives if you only add items.
A Bloom filter question came up in Round 1. Here is how I would explain it now, in plain words.
You have a long row of bits, all 0. To add an item, run it through a few hash functions. Each hash points to one position. Set those positions to 1. To check an item, hash it the same way. If any position is 0, the item was never added. If all are 1, it is probably there.
add("pizza") -> hashes point to bits 2, 9, 14 -> set them to 1
add("burger") -> hashes point to bits 5, 9, 11 -> set them to 1
bit position: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
bits: 0 0 1 0 0 1 0 0 0 1 0 1 0 0 1 0
check("pasta") -> bits 3, 5, 12 -> bit 3 is 0 -> "definitely NOT added"
check("pizza") -> bits 2, 9, 14 -> all 1 -> "probably added"
If you remember only one line, make it this: "No" means definitely no. "Yes" means probably yes, so check the real store.
A few things interviewers like to hear:
- Why use it: tiny memory and fast answers. If most lookups are for things that do not exist, you skip a database hit.
- False negatives: none, as long as you only add.
- Deleting: you cannot clear a bit, because other items may share it. A counting Bloom filter uses small counters to allow deletes.
- A food-delivery example: "Has this user already seen this restaurant card?" A wrongly skipped card costs almost nothing.
The numbers, measured
Formulas are easy to repeat and easy to get wrong, so the numbers below were measured with a real implementation. It held 100,000 items and was then checked against 200,000 items that were never added.
| Bits per item | Hash functions | False negatives | Measured false positives | Formula | Memory |
|---|---|---|---|---|---|
| 5 | 3 | 0 | 9.18% | 9.18% | 61 KB |
| 10 | 7 | 0 | 0.80% | 0.82% | 122 KB |
| 15 | 10 | 0 | 0.08% | 0.07% | 183 KB |
Zero false negatives every time, just as promised. And ten bits per item already gets you under one percent errors, for about 122 KB per 100,000 items. That is why people like this structure.
To reproduce it: the test used double hashing. Take a SHA-256 digest of the item, split it into two 64-bit numbers a and b (forcing b odd) and use positions (a + i*b) mod m for i = 0 .. k-1. Added items were user0 ... user99999, test items were other0 ... other199999. A different hash gives slightly different numbers, but they stay close to the formula.
import hashlib
class Bloom:
def __init__(s, m, k): s.m, s.k, s.bits = m, k, bytearray((m + 7) // 8)
def _idx(s, item):
h = hashlib.sha256(item.encode()).digest()
a = int.from_bytes(h[:8], 'big'); b = int.from_bytes(h[8:16], 'big') | 1
return [(a + i * b) % s.m for i in range(s.k)]
def add(s, item):
for i in s._idx(item): s.bits[i >> 3] |= 1 << (i & 7)
def has(s, item):
return all(s.bits[i >> 3] & (1 << (i & 7)) for i in s._idx(item))
Handy formulas if asked: best hash count is about (m/n) * ln 2 and false positive rate is about (1 - e^(-kn/m))^k, where m is bits, n is items and k is the hash count.
How does WebRTC work? (SDP, ICE, STUN and TURN explained)
Quick answer: WebRTC lets two browsers exchange audio, video or data directly. They first swap connection details through a signaling server (which you build), then use ICE with STUN and, if needed, TURN to find a working network path.
WebRTC was part of Round 1. For an SDE-1 you do not need to have built it. You need a clear mental picture, so here is a useful one.
The idea. Two browsers talk straight to each other. That is faster and cheaper than pushing every video frame through your server.
The catch. WebRTC does not tell the browsers how to find each other. That first conversation is called signaling and you build it yourself, often with a WebSocket server.
Browser A Signaling server Browser B
| 1. offer (SDP) ------->|--------------------------->|
| |<---- 2. answer (SDP) ------|
| 3. ICE candidates ---->|--------------------------->|
|<--------------------------- 4. ICE candidates -------|
| |
|<============= 5. direct media / data ===============>|
Now each word, in the order I would explain it:
- SDP offer and answer. Each side describes what it can do: codecs, media types and so on. A sends an offer. B sends back an answer.
- NAT. Most devices sit behind a router and have no public address, so reaching them directly is hard.
- ICE candidates. Each browser collects possible network paths to itself and shares them. They try the paths and pick one that works.
- STUN server. A small helper that tells a browser what its public address looks like from outside.
- TURN server. If no direct path works, media is relayed through a TURN server. It works on almost any network but costs bandwidth, so it is the fallback.
- Why UDP, usually. Live media normally goes over UDP, because a late packet is useless and waiting for a resend makes a call lag. ICE can fall back to TCP and TURN can relay over TCP or TLS on strict networks that block UDP.
WebSocket or WebRTC for a chat app? For plain text chat, WebSocket is simpler: one persistent connection to your server, which can also store messages. WebRTC pays off for audio, video or large peer-to-peer data.
Webhook, Server-Sent Events, WebSocket: what is the difference? A webhook is one server calling another server's URL when something happens. Server-Sent Events is a one-way stream from server to browser over HTTP. WebSocket is two-way.
SQL or NoSQL for a food delivery app?
Quick answer: choose by access pattern, not by popularity. Orders and payments fit SQL because they need transactions. Fast-changing data like rider location fits a key-value store.
A common answer to this is "NoSQL scales better." That is half a thought. Say how you will read and write the data instead.
| Data | A sensible choice | Reason |
|---|---|---|
| Orders and payments | SQL | Needs transactions. Money must not be half-saved |
| Menus and restaurant details | Document store, or SQL with a cache | Read a lot, shaped differently per restaurant |
| Rider live location | Key-value or in-memory store | Updated every few seconds, only the latest value matters |
| Search by dish name | A search engine | Text search is its own job |
This is one reasonable split, not the only one. A small team can start with only SQL and add other stores when a real need shows up. Saying that out loud shows maturity.
When would you avoid NoSQL? When you need joins across many tables and multi-row transactions with strong consistency, as in payments.
How do you find two numbers that appear once when all others appear twice?
Quick answer: XOR the whole array to get p ^ q, take the lowest set bit of that value, split the array by that bit and XOR each group. O(n) time, O(1) space. This is the same idea as LeetCode 260 (Single Number III).
This was my DSA problem in Round 1. Here is how I would walk through it, slow first, then fast.
Pause and try it. Before you read on, think about how you would do it with a hash map. Then ask yourself whether you can drop the extra space.
Brute force
Count every value in a hash map and keep those with count 1. O(n) time and O(n) space. It is correct and the natural next question is whether you can avoid the extra space.
The XOR idea
Three facts:
x ^ x = 0x ^ 0 = x- XOR does not care about order
XOR the whole array and every pair cancels. What is left is p ^ q, where p and q are the two answers.
Since p and q are different, p ^ q is not zero, so some bit is 1. At that bit, p and q differ. Grab the lowest set bit with all & -all. Split the array into numbers with that bit set and numbers without it. p lands in one group and q in the other and every pair stays together. XOR each group and you have both answers.
static int[] twoUnique(int[] a) {
int all = 0;
for (int x : a) all ^= x; // all = p ^ q
int bit = all & -all; // lowest bit where p and q differ
int p = 0, q = 0;
for (int x : a) {
if ((x & bit) != 0) p ^= x; else q ^= x;
}
return new int[]{Math.min(p, q), Math.max(p, q)};
}
Time O(n), space O(1).
Tested against the hash map version on 5,000 random arrays, including negative numbers, with 0 mismatches. On [1, 2, 3, 2, 1, 5] it returns [3, 5].
Why does all & -all give the lowest set bit? In two's complement, -all flips every bit and adds one. The add carries through the trailing zeros and stops at the lowest set bit. Only that bit is 1 in both all and -all, so the AND keeps just that one.
What if three numbers appear once? This simple split does not extend directly. There are harder bit-manipulation approaches, but in an interview I would fall back to a hash map and explain why.
How do you find the fewest jumps when you can also jump to equal values?
Quick answer: treat indices as nodes in an unweighted graph and run BFS. Keep a map from value to indices and clear each value's list after its first use so the work stays linear. This is the same idea as LeetCode 1345 (Jump Game IV).
This was the first problem in the manager round.
The problem. Start at index 0. From index i you may move to i - 1, to i + 1, or to any other index with the same value as a[i]. Each move costs 1. Find the fewest moves to reach the last index.
Example: [100, -23, -23, 404, 100, 23, 23, 23, 3, 404] gives 3. The path: index 0 to index 4 (both 100), then index 4 to index 3 (one step left), then index 3 to index 9 (both 404).
How to think about it. Equal-cost moves and the word "fewest" point to shortest path on an unweighted graph. That means BFS. Each index is a node. Edges go to i - 1, i + 1 and every index with the same value.
The first version and its trap. Build a map from value to a list of indices, then BFS, scanning the same-value list at every visit. Now imagine the array holds one value everywhere. Every visit scans a list of about n entries and you do that n times. That is O(n²) and "what if everything is equal?" is exactly the follow-up to expect.
The fix. The first time you use a value's list, you queue everything in it. After that it has nothing new to give. So remove it from the map. Each list is scanned once.
static int minJumps(int[] a) {
int n = a.length;
if (n == 1) return 0;
Map<Integer, List<Integer>> g = new HashMap<>();
for (int i = 0; i < n; i++) g.computeIfAbsent(a[i], k -> new ArrayList<>()).add(i);
boolean[] seen = new boolean[n];
Deque<Integer> q = new ArrayDeque<>();
q.add(0); seen[0] = true;
int d = 0;
while (!q.isEmpty()) {
for (int s = q.size(); s > 0; s--) {
int i = q.poll();
if (i == n - 1) return d;
List<Integer> same = g.get(a[i]);
if (same != null) { // use each value's list only once
for (int j : same) if (!seen[j]) { seen[j] = true; q.add(j); }
g.remove(a[i]);
}
if (i - 1 >= 0 && !seen[i - 1]) { seen[i - 1] = true; q.add(i - 1); }
if (i + 1 < n && !seen[i + 1]) { seen[i + 1] = true; q.add(i + 1); }
}
d++;
}
return -1;
}
Time O(n), space O(n).
Tested: three versions (slow BFS, fast BFS and a plain version that relaxes every edge until nothing changes) agreed on 5,000 random small arrays, with 0 mismatches. Then the bad case, every value equal except the last:
| Version | Array size | Time |
|---|---|---|
| Fast (clears the list) | 200,000 | 29 ms |
| Slow (rescans the list) | 20,000 | 2,367 ms |
The slow version has a tenth of the input and is about 80 times slower. On 200,000 it ran so long it had to be stopped. That is what O(n²) looks like in real life.
Why BFS and not DFS? BFS reaches nodes in order of distance, so the first time it reaches the last index is the shortest. DFS can find a longer path first.
Why is removing the list safe? At first use, every index in that list is already queued at the smallest distance it can ever have. Later visits through the same value cannot do better.
How do you maximize the top-left corner of a matrix after row and column reversals?
Quick answer: for every cell in the top-left quarter, take the maximum of its four mirror cells and add them up. O(n²) time, O(1) space. This is the same idea as the HackerRank problem Flipping the Matrix.
This was the second manager-round problem. It looks scary and then collapses into a few lines, which is why I like it.
The problem. You have a square matrix of even size 2n x 2n. You may reverse any row or any column, any number of times, in any order. Then you add up the top-left n x n block. Make that sum as large as possible.
Brute force. Try every order of reversals and keep the best. It blows up fast: a 4 by 4 matrix has 165,888 reachable matrices.
The observation. Reversing a row sends a cell to its mirror in the same row. Reversing a column sends it to its mirror in the same column. So the cell at (i, j) can only ever sit in four places (with N = 2n):
(i, j) (i, N-1-j)
(N-1-i, j) (N-1-i, N-1-j)
And any one of those four values can be placed in the corner cell (i, j). So for each cell of the top-left block, take the maximum of its four mirror cells and add them up.
static int maxTopLeft(int[][] m) {
int N = m.length, h = N / 2, sum = 0;
for (int i = 0; i < h; i++)
for (int j = 0; j < h; j++)
sum += Math.max(
Math.max(m[i][j], m[i][N - 1 - j]),
Math.max(m[N - 1 - i][j], m[N - 1 - i][N - 1 - j]));
return sum;
}
Time O(n²), space O(1). For the 4 by 4 grid numbered 1 to 16, the answer is 54, made of 16, 15, 12 and 11 from the four mirror groups.
Tested against an exhaustive search over every reachable matrix, on 360 random 2 by 2 matrices and 10 random 4 by 4 matrices, with 0 mismatches.
A mistake that is easy to make. When you label a 4 by 4 grid a to p row by row, it is tempting to say "a can become a, c, m, o." The exhaustive search says otherwise:
acan becomea, d, m, p(the four corners)bcan becomeb, c, n, o
Draw the four mirror cells on paper once. That is when it clicks.
Why can the four be picked independently? The groups never overlap, so putting one group's best value into its corner does not disturb another group. If you are unsure in the room, say you trust a small brute-force check more than your own proof and offer to walk through a 2 by 2 example.
What topics should you prepare for a Zomato SDE-1 loop?
Looking back, the whole day followed one pattern and this is the checklist I would hand to a friend.
- DSA: arrays and hashing, two pointers, sliding window, BFS and DFS on graphs, basic dynamic programming, bit tricks like XOR, heaps for greedy problems.
- LLD: entities from nouns, SOLID, Strategy, Observer, State, Factory, thread safety, idempotency.
- System design basics: load balancer, caching, queues, database choice, sharding, rate limiting, CDN.
- Networking: HTTP, TCP vs UDP, DNS, WebSocket, webhooks, SSE and the WebRTC handshake with STUN and TURN.
- Databases: indexes, transactions and ACID, SQL vs NoSQL by access pattern, a simple view of consistency.
- Your own resume: every line, every technology, every number.
A one-week plan I would follow
| Day | Focus | What "done" looks like |
|---|---|---|
| 1 | Resume and two projects | Four lines per project, said out loud |
| 2 | Arrays, hashing, XOR tricks | Solve the two-numbers problem from scratch, brute force first |
| 3 | BFS and DFS on graphs | Solve the jump problem and explain why clearing the list matters |
| 4 | Matrix and grid problems | Solve the mirror-cell problem on paper for 4 by 4 |
| 5 | LLD | Build the food delivery skeleton, then a parking lot |
| 6 | Bloom filter, WebRTC, SQL vs NoSQL, caching, queues | Two-minute spoken answer for each |
| 7 | Mock run | One DSA, one design, one resume walkthrough, back to back, with a ten-minute break |
Habits for a long day. Ask scope questions before you design. Keep one sentence ready for "I am not sure." Say the slow way first, then the better way. Drink water in the break.
Mistakes I would avoid.
- Jumping straight to the optimal solution and skipping the brute force. The brute force shows how you think.
- Naming five design patterns because they sound good.
- Saying "NoSQL scales better" with no reason attached.
- Going silent when stuck. Think out loud, even if it is messy.
Frequently asked questions about the Zomato SDE-1 interview
1. How long was the Zomato SDE-1 interview?
Mine took about four hours in total, with a ten-minute break between Round 1 and the manager round.
2. Does Zomato ask DSA for freshers?
In my loop, yes: one DSA problem in Round 1 and two in the manager round. Explaining each step mattered along with the code.
3. What LLD question can I expect in a Zomato SDE-1 interview?
In my case it was a food delivery system. Know the entities, the order lifecycle, a rider assignment strategy and how to avoid double payments.
4. Do I need to know WebRTC for an SDE-1 role?
You do not need to have built it, but you should explain signaling, SDP, ICE, STUN, TURN and why media usually uses UDP.
5. How do I explain a Bloom filter in an interview?
A bit array plus a few hash functions. "No" means definitely not present. "Yes" means probably present. It saves memory and deletions need a counting version.
6. How do I find two unique numbers when every other number appears twice?
XOR everything to get p ^ q. Use the lowest set bit of that value to split the array into two groups. XOR each group. O(n) time and O(1) space.
7. How do I solve the minimum jumps problem with same-value moves?
Run BFS over indices with a map from value to indices. Clear each value's list after its first use so the total work stays linear.
8. How do I solve the matrix reversal problem?
For every cell in the top-left quarter, take the maximum of its four mirror positions and add them up.
9. SQL or NoSQL for a food delivery app?
Orders and payments in SQL for transactions. Fast-changing data like rider location in a key-value store. Choose by access pattern.
10. How should I prepare for a Zomato SDE-1 interview in a week?
Spend one day each on your resume projects, hashing and XOR, graphs, matrix problems, LLD and concepts, then finish with a full mock run. A day-by-day table is above.
Final thoughts
If I had to sum up the whole day in one line: practise explaining your thinking out loud. Not reciting, thinking. If you can explain why something works in short, clear sentences, you can handle a topic you have never seen before.
Pick one section above, try it before reading my answer and then compare. That is the best practice I know.
If this helped, send it to a friend who has a Zomato loop coming up. And if anything here is unclear, ask in the comments and I will fix it.
