Added support for path generation.
diff --git a/userale/ale.py b/userale/ale.py
index eba2dd9..2f4ff13 100644
--- a/userale/ale.py
+++ b/userale/ale.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-#
 # Copyright 2016 The Charles Stark Draper Laboratory, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,231 +12,278 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# app reference to PyQT5 application (widget, application, desktop)
-# should developers be allowed to turn off global event (ignore hover/blur events, only track click events?)
-
-# Only support events, not signals (which are system level or signals emitted from various connected QtWidgets)
-# blur event
-
 from userale.logger import Logger
-
-from PyQt5.QtCore import *
-from PyQt5.QtWidgets import *
+from userale.version import __version__
+from PyQt5.QtCore import QObject, QEvent
 import datetime
 
-
 class Ale (QObject):
-	"""
-	UserAle.pyqt5 is one of the Software As A Sensor™ products. 
-	The goal of Software As A Sensor™ is to develop understanding of your users through their 
-	interactions with your software product. You can then apply that understanding to improve your 
-	product's design and functionality. UserAle.pyqt5 provides an easy way to generate highly detailed
-	log streams from a PyQt5 application. UserAle.pyqt5 intercepts all application events by letting 
-	the developer install an event filter in their application to generate detailed user logs. UserAle does 
-	not capture system level logs or events generated by a non-user (a.k.a. system and signals sent between QObjects).
-	"""
-	def __init__(self, 
-				 url="http://localhost:8000/logs",
-				 autostart=True,
-				 interval=5000,
-				 threshold=5,
-				 user=None,
-				 version=None,
-				 details=False,
-				 resolution=500):
-		"""
-		:param url: [string] The URL to which logs will be sent (can either be file:// or http://)
-		:param autorstart: [boolean] Should UserAle start auotmatically on app rendering
-		:param interval: [int] The minimum time interval in ms betweeen batch transmission of logs
-		:param user: [string] Identifier for the user of the application
-		:param version: [string] The application version
-		:param log_details: [string] Should detailed logs (key strokes, input/change values) be recorded
-		:param resolution: [int] Delay in ms between instances of high frequency logs like mouseovers, scrolls, etc
-		:param shutoff: [string] Turn off logging for specific events. For example, to ignore mousedown events, ['mousedown']
-	
-		A log will appear like this:
-		{
-			'target': ,
-			'path': ,
-			'clientTime': ,
-			'location': ,
-			'type': ,
-			'userAction': 'true',
-			'details' : [ ],
-			'userId': null,
-			'toolVersion': '1.0.0 alpha',
-			'useraleVersion': '1.0.0 alpha'
-		}
-		"""
-		QObject.__init__(self)
+    """
+    UserALE intercepts all application events by letting the developer install an event filter in their PyQT5 application to 
+    generate detailed user logs. UserAle does not capture system level logs or events generated by a non-user 
+    (a.k.a. system and signals sent between QObjects).
+    """
+    def __init__(self, 
+                 url="",
+                 autostart=True,
+                 interval=5000,
+                 user=None,
+                 version=None,
+                 details=False,
+                 resolution=500,
+                 shutoff=[]):
+        """
+        :param url: [str] The URL to which logs will be sent (can either be file:// or http://)
+        :param autostart: [bool] Should UserAle start auotmatically on app rendering
+        :param interval: [int] The minimum time interval in ms betweeen batch transmission of logs
+        :param user: [str] Identifier for the user of the application
+        :param version: [str] The application version
+        :param details: [bool] Should detailed logs (key strokes, input/change values) be recorded
+        :param resolution: [int] Delay in ms between instances of high frequency logs like mouseovers, scrolls, etc
+        :param shutoff: [list] Turn off logging for specific events. For example, to ignore mousedown events, ['mousedown']
+    
+        An example log will appear like this:
 
-		# UserAle Configuration
-		self.url = url
-		self.autostart = autostart
-		self.interval = interval
-		self.threshold = threshold
-		self.user = user
-		self.version = version
-		self.details = details
-		self.resolution = resolution
+        .. code-block:: python
 
-		# Store logs
-		self.logs = []
+            {
+                'target': ,
+                'path': ['Example', 'testLineEdit'],
+                'clientTime': ,
+                'location': {'x': 82, 'y': 0},
+                'type': 'dragstart',
+                'userAction': 'true',
+                'details' : [ ],
+                'userId': 'userABC1234',
+                'toolVersion': 'myApplication',
+                'useraleVersion': '1.0.0 alpha'
+            }
+        """
 
-		# Drag/Drop - track duration
-		self.dd = datetime.datetime.now ()
+        QObject.__init__(self)
 
-	def eventFilter(self, receiver, event):
-		'''
-		Event filter for capturing all events from a QApplication
-		'''
-		data = {}
+        # UserAle Configuration
+        self.url = url
+        self.autostart = autostart
+        self.interval = interval
+        self.user = user
+        self.version = version
+        self.details = details
+        self.resolution = resolution
 
-		if (event.type () == QEvent.MouseButtonDblClick):
-			# self.handleMouseEvents ("dblclick", event, receiver)
-			pass			
-		elif (event.type () == QEvent.MouseButtonPress):
-			data = self.handleMouseEvents ("mousedown", event, receiver)
-		elif (event.type () == QEvent.MouseButtonRelease):
-			data = self.handleMouseEvents ("mouseup", event, receiver)
-		elif (event.type () == QEvent.MouseMove):
-			data = self.handleMouseEvents ("mousemove", event, receiver)
-		elif (event.type () == QEvent.KeyPress):
-			data = self.handleKeyEvents ("keypress", event, receiver)
-		elif (event.type () == QEvent.KeyRelease):
-			data = self.handleKeyEvents ("keyrelease", event, receiver)
-		elif (event.type () == QEvent.Leave):
-			pass			
-		elif (event.type () == QEvent.Move):
-			pass			
-		elif (event.type () == QEvent.Resize):
-			pass			
-		elif (event.type () == QEvent.Scroll):
-			pass			
-		elif (event.type () == QEvent.DragEnter):
-			data = self.handleDragEvents ("dragstart", event, receiver)	
-		elif (event.type () == QEvent.DragLeave):
-			data = self.handleDragEvents ("dragleave", event, receiver)	
-		elif (event.type () == QEvent.DragMove):
-			data = self.handleDragEvents ("dragmove", event, receiver)	
-		elif (event.type () == QEvent.Drop):
-			data = self.handleDragEvents ("dragdrop", event, receiver)	
-		else:
-			pass	
+        # Store logs
+        self.logs = []
 
-		if data:
-			Logger.stdout (data)
+        # Drag/Drop - track duration
+        self.dd = datetime.datetime.now ()
 
-		return super(Ale, self).eventFilter(receiver, event)
-		# return True
+    def eventFilter(self, object, event):
+        '''
+        :param object: [QObject] The object being watched.
+        :param event: [QEvent] 
+        :return: [bool] Return true in order to filter the event out (stop it from being handled further). Otherwise return false.
+        
+        Filters events for the watched object (in this case, QApplication)
+        '''
 
-	def getSelector (self, element):
-		"""
-		Get target object's name (element defined by user or object class name)
-		"""
-		return element.objectName()
+        data = {}
+        
+        if (event.type () == QEvent.MouseButtonPress):
+            data = self.handleMouseEvents ("mousedown", event, object)
+        elif (event.type () == QEvent.MouseButtonRelease):
+            data = self.handleMouseEvents ("mouseup", event, object)
+        elif (event.type () == QEvent.MouseMove):
+            data = self.handleMouseEvents ("mousemove", event, object)
+        elif (event.type () == QEvent.KeyPress):
+            data = self.handleKeyEvents ("keypress", event, object)
+        elif (event.type () == QEvent.KeyRelease):
+            data = self.handleKeyEvents ("keyrelease", event, object)
+        elif (event.type () == QEvent.Leave):
+            data = self.handleLeaveEvents ("keyrelease", event, object)         
+        elif (event.type () == QEvent.Move):
+            data = self.handleMoveEvents ("keyrelease", event, object)          
+        elif (event.type () == QEvent.Resize):
+            data = self.handleResizeEvents ("keyrelease", event, object)            
+        elif (event.type () == QEvent.Scroll):
+            data = self.handleScrollEvents ("keyrelease", event, object)            
+        elif (event.type () == QEvent.DragEnter):
+            data = self.handleDragEvents ("dragstart", event, object)   
+        elif (event.type () == QEvent.DragLeave):
+            data = self.handleDragEvents ("dragleave", event, object)   
+        elif (event.type () == QEvent.DragMove):
+            data = self.handleDragEvents ("dragmove", event, object)    
+        elif (event.type () == QEvent.Drop):
+            data = self.handleDragEvents ("dragdrop", event, object)    
+        else:
+            pass    
 
-	def getLocation (self, event):
-		"""
-		Grab the x and y position of the mouse cursor, relative to the widget that received the event.
-		"""
-		try: 
-			pos = event.pos ()
-			loc = {"x" : pos.x (), "y" : pos.y ()}
-		except:
-			loc = None
-		return loc
+        if data:
+            Logger.stdout (data)
+        
+        # return super(Ale, self).eventFilter(object, event)
+        return False
 
-	def getPath (self, element):
-		"""
-		How to encode path for elements. Is it DOM hierachy? Or it is path of movement? 
-		DragnDrop Event: 
-		Distance?
-		"""
-		# Fetch parent
-		#meta = element.metaObject ()
-		p = element.parent ()
+    def getSelector (self, object):
+        """
+        :param object: [QObject] The base class for all Qt objects.
+        :return: [str] The Qt object's name
 
-		print (p)
-		# return p.metaObject().className () + ': ' + meta.className ()
+        Get target object's name (object defined by user or object's meta class name)
+        """
 
-	def getClientTime (self, element):
-		"""
-		Time event was triggered
-		"""
-		return str (datetime.datetime.now ())
+        return object.objectName() if object.objectName() else object.staticMetaObject.className()
 
-	def handleMouseEvents (self, event_type, event, receiver):
-		"""
-		Detailed log for a mouse event. 
-		"""
-		data = {
-			'target': self.getSelector (receiver) ,
-			'path': self.getPath (receiver),
-			'clientTime': self.getClientTime (event),	
-			'location': self.getLocation(event),
-			'type': event_type ,
-			'userAction': 'true',
-			'details' : [ ],
-			'userId': self.user,
-			'toolVersion': self.version,
-			'useraleVersion': '1.0.0 alpha'
-		}
+    def getLocation (self, event):
+        """
+        :param event: [QEvent] The base class for all event classes.
+        :return: [dict] A dictionary representation of the x and y positions of the mouse cursor.
 
-		return data
+        Grab the x and y position of the mouse cursor, relative to the widget that received the event.
+        """
 
-	def handleKeyEvents (self, event_type, event, receiver):
-		"""
-		Detailed log for a key event. Key name and code are tracked. 
-		"""
-		data = {
-			'target': self.getSelector (receiver) ,
-			'path': self.getPath (receiver),
-			'clientTime': self.getClientTime (event),	
-			'location': self.getLocation(event),
-			'type': event_type ,
-			'userAction': 'true',
-			'details' : {'key' : event.text (), 'keycode' : event.key ()},
-			'userId': self.user,
-			'toolVersion': self.version,
-			'useraleVersion': '1.0.0 alpha'
-		}
+        try: 
+            return {"x" : event.pos ().x (), "y" : event.pos ().y ()}
+        except:
+            return None
 
-		return data
+    def getPath (self, object):
+        """
+        :param object: [QObject] The base class for all Qt objects.
+        :return: [list] List of QObjects up to the child object.
 
-	def handleDragEvents (self, event_type, event, receiver):
-		"""
-		Detailed log for a drag event. When a user attempts a dragenter/drag move event, a timer is generated
-		to track duraction. Duraction will be stored in the drag drop event message. 
-		"""
-		res = {}
-		if event_type == 'dragstart':
-			# start timer
-			self.dd = datetime.datetime.now ()
-		elif event_type == 'dragdrop' or event_type == 'dragleave':
-			res = {"elapsed" : str (datetime.datetime.now () - self.dd)}
-			self.dd = datetime.datetime.now ()
-		else:
-			# drag move event - ignore
-			pass
+        Fetch the entire path up the root of the tree for a leaf node object.
+        Recursive operation.
+        """
 
-		data = {
-			'target': self.getSelector (receiver) ,
-			'path': self.getPath (receiver),
-			'clientTime': self.getClientTime (event),	
-			'location': self.getLocation(event),
-			'type': event_type ,
-			'userAction': 'true',
-			'details' : res,
-			'userId': self.user,
-			'toolVersion': self.version,
-			'useraleVersion': '1.0.0 alpha'
-		}
+        if object.parent() is not None:
+            return self.getPath (object.parent()) + [self.getSelector (object)]
+        else:
+            return [self.getSelector (object)]
 
-		return data
+    def getClientTime (self):
+        """
+        :return: [str] String representation of the time the event was triggered.
+        
+        Capture the time the event was captured. 
+        """
 
-	def handleMoveEvents (self, event_type, event, receiver):
-		"""
+        return str (datetime.datetime.now ())
 
-		"""
+    def handleMouseEvents (self, event_type, event, object):
+        """
+        :param event_type: [str] The string representation of the type of event being triggered by the user.
+        :param event: [QEvent] The base class for all event classes.
+        :param object: [QObject] The base class for all Qt objects.
+        :return: [dict] A userale log describing a mouse event.
 
+        Returns the userale log representing all mouse event data. 
+
+        .. code-block:: python
+
+        """
+        
+        return self.__create_msg (event_type, event, object)
+
+    def handleKeyEvents (self, event_type, event, object):
+        """
+        :param event_type: [str] The string representation of the type of event being triggered by the user.
+        :param event: [QEvent] The base class for all event classes.
+        :param object: [QObject] The base class for all Qt objects.
+        :return: [dict] A userale log describing a key event.
+
+        Returns the userale log representing all key events, including key name and key code.
+        """
+
+        details = {'key' : event.text (), 'keycode' : event.key ()}
+        return self.__create_msg (event_type, event, object, details=details)
+
+    def handleDragEvents (self, event_type, event, object):
+        """
+        :param event_type: [str] The string representation of the type of event being triggered by the user.
+        :param event: [QEvent] The base class for all event classes.
+        :param object: [QObject] The base class for all Qt objects.
+        :return: [dict] A userale log describing a drag event.
+
+        Returns the userale log representing all drag events. 
+        """
+
+        details = {}
+        if event_type == 'dragstart':
+            # start timer
+            self.dd = datetime.datetime.now ()
+        elif event_type == 'dragdrop' or event_type == 'dragleave':
+            details = {"elapsed" : str (datetime.datetime.now () - self.dd)}
+            self.dd = datetime.datetime.now ()
+        else:
+            # drag move event - ignore
+            pass
+
+        return self.__create_msg (event_type, event, object, details=details)
+
+    def handleMoveEvents (self, event_type, event, object):
+        """
+        :param event_type: [str] The string representation of the type of event being triggered by the user.
+        :param event: [QEvent] The base class for all event classes.
+        :param object: [QObject] The base class for all Qt objects.
+        :return: [dict] A userale log describing a drag event.
+
+        Returns the userale log representing all move events. 
+        """
+
+        pass
+
+    def handleLeaveEvents (self, event_type, event, object):
+        """
+        :param event_type: [str] The string representation of the type of event being triggered by the user.
+        :param event: [QEvent] The base class for all event classes.
+        :param object: [QObject] The base class for all Qt objects.
+        :return: [dict] A userale log describing a leave event.
+
+        Returns the userale log representing all leave events. 
+        """
+
+        pass
+
+    def handleResizeEvents (self, event_type, event, object):
+        """
+        :param event_type: [str] The string representation of the type of event being triggered by the user.
+        :param event: [QEvent] The base class for all event classes.
+        :param object: [QObject] The base class for all Qt objects.
+        :return: [dict] A userale log describing a resize event.
+
+        Returns the userale log representing all resize events. 
+        """
+
+        pass
+
+    def handleScrollEvents (self, event_type, event, object):
+        """
+        :param event_type: [str] The string representation of the type of event being triggered by the user.
+        :param event: [QEvent] The base class for all event classes.
+        :param object: [QObject] The base class for all Qt objects.
+        :return: [dict] A userale log describing a scroll event.
+
+        Returns the userale log representing all scroll events. 
+        """
+
+        pass
+
+    def __create_msg (self, event_type, event, object, details={}):
+        """
+        Geneate UserAle log describing an event.
+        """
+
+        data = {
+            'target': self.getSelector (object) ,
+            'path': self.getPath (object),
+            'clientTime': self.getClientTime (),    
+            'location': self.getLocation(event),
+            'type': event_type ,
+            'userAction': 'true',
+            'details' : details,
+            'userId': self.user,
+            'toolVersion': self.version,
+            'useraleVersion': __version__
+        }
+
+        return data