Blog Post

Browsing category

Curbside Challenge Using Python’s Async Capabilities

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.

Read more

RackAFX – Designing Audio Effect Plug-ins in C++

This is a quick post about a current book I am reading, and the awesome software that the author wrote to help students understand audio DSP theory as well as learn how to create audio plug-ins using this theory.  The book called Designing Audio Effect Plug-ins  in C++ written by Will Prikle.  If you have ever wanted to learn how to create audio effect plug-ins that can be used in your DAW’s then this is the book for you.  I’m currently about four of five chapters in and have already written small audio effects.  You write a gain controller plug-in in the first couple of chapters.  For those audio nerds out there you actually write two volume controllers fairly early in this book.  One linear volume controller, which we know doesn’t really follow true audio plug-in controls, and secondly the dB volume controller that we all know and love.  Right now I am currently reading through the theory heavy section of the book, and trying to soak it all in, but I think I am going to move on to the audio filter design IIR chapter and continue to come back to the theory chapter to grasp concepts better as I use them.  I highly recommend this book and will definitely be picking up Will’s other book on Designing Software Synthesizer Plug-Ins in C++ after I finish his current book.

Along with his incredible book, he wrote even better software, pictured above, to help facilitate students in learning how to create audio effect plug-ins.  Will’s software takes out the GUI implementation and update tracking code and gives you a clean user interface to prototype the plug-ins from his book, as well as experiment with your own plug-in creation when you feel confident.  You can use his simple GUI implementation and just focus on grasping the DSP theory and how it is implemented in code.  Or if you want you can design your own GUI.  One other cool feature of his software is that all plug-ins can be ported to VST, AU and even the newer AAX format can all be created from his great software.  I’ll write some more quick posts about Will’s software once I get a little better handle on it and create something cool.  For now back to reading the book and learning the ins and outs of building audio effects in C++.

Read more

Solar Doomsday

Yesterday I was bored at work and decided to see if I could get back into the Google Foo Bar challenge.  I once again tried all the known combinations that had gotten me in before, and surprise surprise… I got back in.  This time it was the solar doomsday challenge, which I have gotten before.  I intially solved this challenge in Java, and for this attempt I decided to try and solve it in Python.  Both answers are pretty similar, and I’m sure there is a more eloquent solution, but it’s what I came up with.  The Java version was done first, and then Python one follows the same algorithm, just with the Python syntax.  Both use recursion to solve the problem.  The main difference is in the data structure used to hold the final list.  In Java I used a deque, which is a faster version of a linked list when used a queue.  In Python I just went with a standard list and reversed the list before returning the final answer.  Both work, but Python’s seems easier and uses less space than the Java version.

Python Version




'''
Created on Feb 15, 2017



@author: Tony Harrell
'''
import math;



def answer(area):
    fList = [];



    solarPanelCalc(area, fList);
    fList.reverse();
    return fList;



def solarPanelCalc(area, fList):
    pArea = 0;



    if area >= 1 and area <= 1000000:
        tmp = int(math.sqrt(area));
        print tmp;
        if tmp <= 0:
            return pArea;
        else:
            pArea = int(math.pow(tmp, 2));
            nArea = area - pArea;
            solarPanelCalc(nArea, fList);
            fList.append(pArea);
        return pArea;



print answer(12);



Java Version


import java.util.ArrayDeque;
import java.util.Arrays;

public class SolarChallenge {

	public static int[] answer(int area){
		int[] finalList = {};
		ArrayDeque&amp;lt;Integer&amp;gt; areaQueue = new ArrayDeque&amp;lt;&amp;gt;();

		solarPanelCalc(area, areaQueue);

		finalList = new int[areaQueue.size()];
		for(int i=areaQueue.size()-1; i&amp;gt;=0; i--){
			finalList[i] = areaQueue.pop();
		}

		return finalList;
	}

	public static int solarPanelCalc(int area, ArrayDeque&amp;lt;Integer&amp;gt; aq){
		int panelArea = 0;

		if(area &amp;gt;= 1 &amp;amp;&amp;amp; area &amp;lt;= 1000000){
			int temp = (int) Math.sqrt(area);
			if(temp &amp;lt;= 0){
				return panelArea;
			}else{
				panelArea = (int) Math.pow(temp, 2);
				int nextArea = area - panelArea;
				solarPanelCalc(nextArea, aq);
				aq.add(panelArea);
			}
		}
		return panelArea;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] ans1 = answer(12);

		System.out.println(Arrays.toString(ans1));

	}

}

Read more

I Love Lance & Janice

Here’s another Google challenge I got.  I actually was looking for something in Python today and triggered the challenge again with “Python List Comprehension”.  So try searching for that if you are looking to get into the challenge.  As I have got this one before I did one in Java and one in Python.  The answers are both pretty similar, and I’m sure there is a more eloquent solution, but it’s what I came up with.  The Java version was done first, and then Python one follows the same algorithm, just with the Python syntax.  I tried doing the Python version different, without the hash.  It didn’t work as planned, but as I’m writing this I’m thinking I might be able to accomplish this converting to ASCII values on the passed in string and adding or subtracting 25 instead of making the alphabet hash.  We’ll see if I can get the implemented tomorrow.  If I do I’ll post that code.  Below is what the challenge question is and it needed to be solved in 48 hours.

Python Implementation

'''
Created on Jan 4, 2017

@author: Tony Harrell
'''

def answer(s):
	#alphaHash = {};
	alphaHash = makeHash();
	ns = &amp;quot;&amp;quot;;
	for i in s:
		if i in alphaHash:
			ns += alphaHash[i];
		else:
			ns += i;
	return ns;

def makeHash():
	alpha = [&amp;quot;a&amp;quot;,&amp;quot;b&amp;quot;,&amp;quot;c&amp;quot;,&amp;quot;d&amp;quot;,&amp;quot;e&amp;quot;,&amp;quot;f&amp;quot;,&amp;quot;g&amp;quot;,&amp;quot;h&amp;quot;,&amp;quot;i&amp;quot;,&amp;quot;j&amp;quot;,&amp;quot;k&amp;quot;,&amp;quot;l&amp;quot;,&amp;quot;m&amp;quot;,&amp;quot;n&amp;quot;,&amp;quot;o&amp;quot;,&amp;quot;p&amp;quot;,&amp;quot;q&amp;quot;,&amp;quot;r&amp;quot;,&amp;quot;s&amp;quot;,&amp;quot;t&amp;quot;,&amp;quot;u&amp;quot;,&amp;quot;v&amp;quot;,&amp;quot;w&amp;quot;,&amp;quot;x&amp;quot;,&amp;quot;y&amp;quot;,&amp;quot;z&amp;quot;];
	hash = {};
	for i in range(len(alpha)):
		hash[alpha[25-i]] = alpha[i];
	return hash;

#Lance Challenge
s = &amp;quot;vmxibkgrlm&amp;quot;;
s2 = &amp;quot;Yvzs! I xzm'g yvorvev Lzmxv olhg srh qly zg gsv xlolmb!!&amp;quot;;

print answer(s);

Java Implementation

import java.util.HashMap;

public class LanceLovesJaniceChallenge {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// Lance Challenge
		String s = &amp;quot;vmxibkgrlm&amp;quot;;
		String s2 = &amp;quot;Yvzs! I xzm'g yvorvev Lzmxv olhg srh qly zg gsv xlolmb!!&amp;quot;;

		String ans = answerLance(s2);
		System.out.println(ans);

	}

	public static String answerLance(String s){
		HashMap&amp;lt;String,String&amp;gt; hm = new HashMap&amp;lt;String,String&amp;gt;();
		StringBuilder sb = new StringBuilder();

		encodeAplhabet(hm);
		if(!s.isEmpty()){
			for(int i=0; i&amp;lt;s.length(); i++){
				if(hm.get(String.valueOf(s.charAt(i))) != null){
					sb.append(hm.get(String.valueOf(s.charAt(i))));
				}else{
					sb.append(s.charAt(i));
				}
			}
		}	
		return sb.toString();
	}

	public static void encodeAplhabet(HashMap&amp;lt;String,String&amp;gt; alphaMap){
		String[] alpha ={&amp;quot;a&amp;quot;,&amp;quot;b&amp;quot;,&amp;quot;c&amp;quot;,&amp;quot;d&amp;quot;,&amp;quot;e&amp;quot;,&amp;quot;f&amp;quot;,&amp;quot;g&amp;quot;,&amp;quot;h&amp;quot;,&amp;quot;i&amp;quot;,&amp;quot;j&amp;quot;,&amp;quot;k&amp;quot;,&amp;quot;l&amp;quot;,&amp;quot;m&amp;quot;,&amp;quot;n&amp;quot;,
				&amp;quot;o&amp;quot;,&amp;quot;p&amp;quot;,&amp;quot;q&amp;quot;,&amp;quot;r&amp;quot;,&amp;quot;s&amp;quot;,&amp;quot;t&amp;quot;,&amp;quot;u&amp;quot;,&amp;quot;v&amp;quot;,&amp;quot;w&amp;quot;,&amp;quot;x&amp;quot;,&amp;quot;y&amp;quot;,&amp;quot;z&amp;quot;};

		for(int i=0; i&amp;lt;alpha.length; i++){
			alphaMap.put(alpha[25-i], alpha[i]);
		}
	}

}

Read more