/**
  * Perform a RESTful API call
  * @param str $verb The RESTful verb (use constants: CANVAS_API_DELETE, CANVAS_API_GET, CANVAS_API_POST, CANVAS_API_PUT)
  * @param str $path Path to the particular RESTful command
  * @param array $data Associative array of parameters to for the RESTful command
  * @param bool $throwsExceptions = false Catch or throw Pest exceptions (sometimes useful to catch them elsewhere...)
  * @param bool $paginated = false Internal use only
  */
 public function call($verb, $path, $data = array(), $throwsExceptions = false, $paginated = false)
 {
     $response = null;
     /* Get as much information from the API at a time as possible (reducing API calls, etc. */
     if (!isset($data['per_page'])) {
         $data['per_page'] = '50';
     }
     $clientRetryCount = 0;
     $serverRetryCount = 0;
     do {
         $retry = false;
         try {
             if ($paginated) {
                 $response = $this->pagePest->{$verb}($path, $data, $this->buildCanvasAuthorizationHeader());
             } else {
                 $this->pagePest = $this->pest;
                 $this->lastCall['verb'] = $verb;
                 $this->lastCall['path'] = $path;
                 $this->lastCall['data'] = $data;
                 $this->lastCall['throwsExceptions'] = $throwsExceptions;
                 $response = $this->pest->{$verb}($path, $data, $this->buildCanvasAuthorizationHeader());
             }
         } catch (Pest_ServerError $e) {
             if ($throwsExceptions & CANVAS_API_EXCEPTION_SERVER) {
                 throw $e;
             } else {
                 /* who knows what goes on in the server's mind... try again */
                 $serverRetryCount++;
                 $retry = true;
                 debug_log('Retrying after Canvas API server error. ' . substr($e->getMessage(), 0, CANVAS_API_EXCEPTION_MAX_LENGTH));
             }
         } catch (Pest_ClientError $e) {
             if ($throwsExceptions & CANVAS_API_EXCEPTION_CLIENT) {
                 throw $e;
             } else {
                 /* I just watched the Canvas API throw an unauthorized error when, in fact,
                    I was authorized. Everything gets retried a few times before I give up */
                 $clientRetryCount++;
                 $retry = true;
                 debug_log('Retrying after Canvas API client error. ' . substr($e->getMessage(), 0, CANVAS_API_EXCEPTION_MAX_LENGTH));
             }
         } catch (Exception $e) {
             // treat an empty reply as a server error (which, BTW, it dang well is)
             if ($e->getMessage() == 'Empty reply from server') {
                 $serverRetryCount++;
                 $retry = true;
                 debug_log('Retrying after empty reply from server. ' . substr($e->getMessage(), 0, CANVAS_API_EXCEPTION_MAX_LENGTH));
             } else {
                 displayError(array('Error' => $e->getMessage(), 'Verb' => $verb, 'Path' => $path, 'Data' => $data), true, 'API Error', 'Something went awry in the API');
                 exit;
             }
         }
     } while ($retry == true && $clientRetryCount < API_CLIENT_ERROR_RETRIES && $serverRetryCount < API_SERVER_ERROR_RETRIES);
     if ($clientRetryCount == API_CLIENT_ERROR_RETRIES) {
         displayError(array('Status' => $this->pest->lastStatus(), 'Error' => $this->pest->lastBody(), 'Verb' => $verb, 'Path' => $path, 'Data' => $data), true, 'Probable Client Error', 'After trying ' . API_CLIENT_ERROR_RETRIES . ' times, we still got this error message from the API. (Remember to check to be sure that the object ID passed to the API is valid and exists if the API tells you that you\'re not authorized... because you\'re not authorized to work with things that don\'t exist!)');
         exit;
     }
     if ($serverRetryCount == API_SERVER_ERROR_RETRIES) {
         displayError(array('Status' => $this->pest->lastStatus(), 'Error' => $this->pest->lastBody(), 'Verb' => $verb, 'Path' => $path, 'Data' => $data), true, 'Probable Server Error', 'After trying ' . API_CLIENT_ERROR_RETRIES . ' times, we still got this error message from the API.');
         exit;
     }
     $this->lastCall['response'] = json_decode($response, true);
     $this->processPaginationLinks();
     displayError(array('API Call' => array('Verb' => $verb, 'Path' => $path, 'Data' => $data), 'Response' => $this->lastCall['response']), true, 'API Call', null, DEBUGGING_CANVAS_API);
     return $this->lastCall['response'];
 }