project1.sh

#!/bin/bash

# This is the URL from which we will retrieve the movie list
url=http://www.movies.com/rss-feeds/top-ten-box-office-rss

# infinite loop!
while true; do
   clear # clear screen

   # Load the movie records into the variable webdata as a string
   webdata=$(curl $url 2> /dev/null)

   # Print the title of each movie
   #-> $"" [dollar sign + quotes] is a special quote that will cause 
   #  backslash-escaped characters to be replaced 
   #  as specified by the ANSI C standard.
   #  In effect, echo will recognize newline characters correctly.
   echo $"$webdata" | sed -En 's/<title><!\[CDATA\[(.*)\]\]><\/title>/\1/p' 
   # -E parameter: use the extended RegEx syntax
   # -n parameter: suppress automatic printing of pattern space
   # /p: print only the modified text.
   # -> So why do "-n /p"? Because by default, sed will print both modified and unmodified lines.
   #    However, we want only the modified expressions to be printed. "-n /p" will do exactly that.

   # Use the line break as a delimiter
   IFS=$'\n'  
   #-> $''[dollar sign + quotes] has the same purpose as in the preceding lines,
   # i.e., interpreting newline characters correctly.  

   # Extract movie descriptions and use them to create an array of movie descriptions. 
   # $(echo ... p') will return a multi-line string. The outer parenthese that encloses this $(echo...)
   # statement will parse this string with the delimiter chosen above (IFS) and create an array.
   desc=($(echo $"$webdata" | sed -En 's/<description><!\[CDATA\[(.*)\]\]><\/description>/"\1"/p'))
   # -> $""[dollar sign + double quotes] will cause the string to be translated according to the 
   #    current locale.

   # Print a blank line. With -e option, echo can handle backslash escapes.
   echo -e "\n"
   
   # -p option allows 'read' to print a string before reading the user's input.
   # First display the instruction, and then take the user input to the varaible $REPLY
   read -p "Choose a movie (1-10) > "
   
   # Display the movie description of the user's choice
   echo -e "\nMovie $REPLY \nSynopsis\n\n${desc[$REPLY]}"
   echo -e "\nPress enter to return"
   
   # Wait until the user presses enter.
   read 
done

project2a.py

#! /usr/bin/env python
import sys

#Check for correct commandline arguments
if len(sys.argv) < 2:
	print "Usage: python project2a.py restaurants.txt"
	exit(-1)

#Open restaurants.txt
IN= open(sys.argv[1], 'r')

#Read first line
read= IN.readline()

#Initialize the adjacency list to be empty
friends= {}
#Loop through each restaurant entry in the file
while read:
	#Get two halves: t[0] = People, t[1] = Restaurant
    t= read.split(';')
    #names will contain the list of all names in the current line
    names= t[0].split(',')
    #Go through each name in the list
    for i in range(len(names)):
		#Go through every other name after the current name
	    for j in range(i+1, len(names)):
		#The following two lines will create an empty adjacency list
		#  only if the names do not already exist in "friends" dictionary.
		#  This is the initialization as given in Hint 2 of the problem
		#  statement
		friends.setdefault(names[i], {})
		friends.setdefault(names[j], {})
		#Set the value in the adjancency list for (Name1, Name2)
		#   and (Name2, Name1) to 1 to signify that we found an occurence
		#   of the both of them dining together
		friends[names[i]][names[j]]=1
		friends[names[j]][names[i]]=1
    #Read the next line from the file
    read= IN.readline()

#For each person in the adjacency list...
for i in friends:
	#...Print his name
    print i+":",
    #For each person that "i" dined with...
    for j in friends[i]:
		#...Print the other person's name.
		#   The comma here signifies no newline should be
		#   printed at the end
	    print j,
    #Print a new line
    print

project2b.py

#! /usr/bin/env python
import sys
# open the file specified as the second argument for reading
IN = open(sys.argv[2], 'r')
# store the name of the person specified as root in the first argument
root = sys.argv[1]
# read the first line from the file
read = IN.readline()
# initialize an empty dictionary called friends
# which will contain the adjacency list similar to project 2a
friends = {}
while read:  # while there are more lines to read
    t = read.split(';')  # split the line with semicolon as the separator and store it ina list
    names = t[0].split(',')  # split individual names and save it in names
    for i in range(len(names)):  # Loop through each name
        for j in range(i + 1, len(names)):  # Nested loop to store friends
            #initialize the dictionary for names[i]
            friends.setdefault(names[i], {})
            # initialize the dictionary for names[j]
            friends.setdefault(names[j], {})
            # mark the two persons represented by names[i] and names[j] as friends
            friends[names[i]][names[j]] = 1
            # mark the two persons as friends in the reverse order as well
            friends[names[j]][names[i]] = 1
    #continue reading the next line
    read = IN.readline()

# initialize an empty dictionary to store the distance
dist = {}
# as we are starting from the root the distance from root to itself is obviously 0
# By adding root to the 'dist' directory we are also marking the root as visited
dist[root] = 0
# The root node is enqueued as specified by the BFS algorithm
# a python list is used to implement the queue (as the list is conceptually similar to
# a queue and it supports all the operations of a queue)
queue = [root]
# loop till there are elements present in the queue
while queue:
    # Dequeue (or pop or remove) the top element from the queue and save it in 'n'
    n = queue.pop(0)
    # Use the adjacency list built previously to find all the friends and loop through each of them.
    # For each friend of 'n' we check if the friend has been visited by BFS before.
    # If not, we add it into 'dist' to mark it as visited
    # This check is required as we stop the algorithm when we have visited all friends (same as when queue is empty)
    # If we don't check this, the algorithm will run in an infinite loop
    for i in friends[n]:
        # if the friend has not been visited (meaning it doesn't have an entry in the dictionary 'dist'
        if i not in dist:
            # append (enqueue) unvisited friend to queue
            queue.append(i)
            # Add one to the distance value of the node (n) popped from the queue at the start of the loop
            # This gives the cumulative distance of the current foodie from the root
            dist[i] = dist[n] + 1

# After BFS is done, 'dist' will contain all the foodies reachable from the root and
# also their distance from the root
# loop through the keys of the dictionary and print the name, distance of each foodie
for name in dist:
    print name, dist[name]