Quick Intro:
I randomly got a lunch bag from my mom a couple months back. It was a light bright blue bag that had Curbside printed on the side. I had seen there tents outside of Target and Oakridge mall before, but didn’t really know what they did as a company. I got the gist of what they did, made online storefronts for brick and mortar stores that either don’t want to invest in online storefronts, or want to build in a drive up delivery aspect to their current online storefronts. I did a lot more research online to see what this company was about. Through my research I stumbled across their career section. I always look at companies career sections just to see what’s out there, and I am trying to find a development roll. In looking at the career section of the website I found a challenge. It ask “Want the fast track? It gave a single curl command, and thus the trip down Curbside’s rabbit hole started. Below is what it looks like on their website.

Figuring Out The Challenge:
That simple curl command when entered responds with another simple line of text…
On the right track. You can start here: “/start”
So, of course I append start to the URL and get another line of text reading…
“Session” header is missing. “/get-session” to get a session id.
Ok, another piece to the puzzle. So, next I get my session ID and send it with the /start request and get another line of text…
There is something we want to tell you, let’s see if you can figure this out by finding all of our secrets
That’s all it said, but if you looked at the entire response from the server we quickly find out that the response was a json response with more information than the displaying text. This is when I start thinking that I should start using JavaScript or Python to figure this out. If session id headers and json responses are going to be part of this challenge then it’ll probably be easier with some sort of RESTful library. I decided on Python because I had used it before in a web crawling application and it was super easy and fast to use when it came to RESTful APIs. Now everything was setup and I could easily make GET requests with specific headers that were responding with json. I’m trying not to go into too much detail in case you want to attempt the challenge yourself, but basically the responses had a key that contained a list that needed to be traversed. I started with a simple breadth first traversal and quickly found out that this tree was deeper than I expected. So I changed tactics and went to a depth first traversal. This was a better attempt at the problem because I found out how deep the tree was and got a couple of the secret message, but still my allotted session time was timing out.
Because I kept running into session time out issues no matter what I tried, I turned to Python’s built-in asynchronous library to help. The async package along with an asynchronous HTTP client/server library called “aiohttp”. Now I could get all calls handled in a timely fashion and only had to deal with curve balls that the challenge throws at you, I’ll let those who want to try discover what they are…
The Code:
<code lang="python"> ''' Python v.3.6</code> @author: Tony Harrell ''' import itertools import asyncio import aiohttp async def fetch(url, session): async with session.get(url) as response: print(response) return await response.json() async def fetch_node(url, header, session): # sleep the coroutine for 1 second to make # sure we don't get 429 responses await asyncio.sleep(1) async with session.get(url, headers=header) as resp: if resp.status == 429 or resp.status != 200: print(resp) assert resp.status == 200 return await resp.json() async def bound_fetch_node(sem, url, header, session): #use a semaphore to control amount of requests async with sem: return await fetch_node(url, header, session) async def run(url,json_list, s_header, session): secret = [] next_list = [] sem = asyncio.Semaphore(200) if type(json_list) is dict: next_list = json_list['next'] else: tmp_list = [n['next'] if len(n['next'])!=32 else [''.join(n['next'])] for n in json_list if 'next' in n] next_list = list(itertools.chain(*tmp_list)) print("next level size = "+str(len(next_list))) for i in next_list: # async futures used to keep the response # in order and alive through all the calls task = asyncio.ensure_future(bound_fetch_node(sem, url.format(i), s_header, session)) secret.append(task) responses = asyncio.gather(*secret, loop=loop) return await responses async def run_start(): session_url = "https://challenge.curbside.com/get-session" url = "https://challenge.curbside.com/{}" # get all responses within one Client session, # keep connection alive for all requests. # limit the amount of connections to 200 to not get 429 response async with aiohttp.ClientSession() as session: s = await fetch(session_url, session) print(s) s_header = {"Session": s['session']} print(s_header) s = await fetch_node(url.format("start"), s_header, session) # loop until response object is empty while s: s = await run(url, s, s_header, session) # if secret is in any of the dict's decode response if any(d.get('secret') for d in s): decoded_message = decode_response(s) print("Done traveling down the secret path...!") print("Here is the secret message...") print() print(decoded_message) def decode_response(result): entire_response = [n['secret'] for n in result] return ''.join(entire_response) # create async event loop and futures then run until the loop is finished # Report all mistakes managing asynchronous resources. loop = asyncio.get_event_loop() future = asyncio.ensure_future(run_start()) loop.run_until_complete(future)
Final Thoughts:
Just a final note this was a fun challenge and I’ll leave it to you to find what the message says. I found out, and actually sent in a resume. Haven’t heard anything back. So either A, my code sucked and didn’t meet their standards, or B they aren’t hiring or something happened to my email. If you looking to try the challenge use my code as a reference point, but know it probably sucks and doesn’t meet their standards. At any rate this was fun to solve, and like the Google FooBar challenges its just fun solving coding riddles.