diff --git a/web/modules/custom/asc_courses/README.md b/web/modules/custom/asc_courses/README.md
index 0c565fa884757c41e3a2991571263e28d2482412..9f32360174aabd9113984c92a19fcc06b2a2909c 100644
--- a/web/modules/custom/asc_courses/README.md
+++ b/web/modules/custom/asc_courses/README.md
@@ -21,7 +21,7 @@ The module assumes the presence of a "Course" content type with the appropriate
 - Enter EIP consumer key(s) and secret(s) and select an EIP environment
 - Run `drush asc_courses:pull-all-dorgs` to fetch raw course data from EIP and store locally
 - Run `drush asc_courses:process-api-data` to process the raw course data into the `asc_courses_processed` database table
-- Run `drush sql-dump --ordered-dump --tables-list=asc_courses_api_data,asc_courses_processed > asc_courses_data.sql` to export the gathered data to a sql file
+- Run `drush sql-dump --tables-list=asc_courses_api_data,asc_courses_processed > asc_courses_data.sql` to export the gathered data to a sql file
 - Load the `asc_courses_data.sql` file to each site that wants to use the data.  I use [this pair of scripts](https://gist.github.com/weaver299/bf8eb877146a5deeab5f41392db65468) to load the data to every Pantheon site using one of my custom upstreams.
 
 ### Sites using the course data
@@ -32,4 +32,9 @@ The module assumes the presence of a "Course" content type with the appropriate
 - Select D-Org numbers (subjects) and/or specific EIP course IDs to import as Drupal nodes
 - The "Course Search" tab can be used for looking up EIP course IDs
 
+### TODO
+
+- Clean up process-api-data output
+- Consider not processing/updating unused fields (e.g. crse_offer_nbr, acad_career)
+- Store separate dates for last time course data (checked) was checked and last time content changed (changed)
 
diff --git a/web/modules/custom/asc_courses/scripts/backup_fresh.sh b/web/modules/custom/asc_courses/scripts/backup_fresh.sh
new file mode 100644
index 0000000000000000000000000000000000000000..6e169b57985d2809db6069401cefe0fb48550bc6
--- /dev/null
+++ b/web/modules/custom/asc_courses/scripts/backup_fresh.sh
@@ -0,0 +1,68 @@
+#!/usr/bin/env bash
+
+if [[ -z $1 ]]; then
+  echo; echo "Usage: $0 <site.env>";
+  echo; echo;
+  exit 1;
+fi
+
+# MacOS compatibility....
+if [[ "$OSTYPE" == *"darwin"* ]]; then
+  # echo "This is MacOS.  OSTYPE[$OSTYPE]";
+  if [[ -z `which gdate` ]]; then
+    echo; echo "'gdate' command not found.";
+    echo -n "The GNU version of the 'date' command is needed on MacOS. ";
+    echo "It is available as the 'gdate' command via the 'coreutils' Homebrew package.";
+    if [[ -z `which brew` ]]; then
+      echo;
+      echo "Homebrew is NOT installed. Homebrew and the 'coreutils' package need to be installed to proceed. Stopping.";
+      echo "Visit https://brew.sh/ for more information.";
+    else
+      echo; echo "Try installing the 'coreutils' package -- brew install coreutils";
+    fi
+    echo; echo;
+    exit 1;
+  else
+    DATE_CMD='gdate';
+  fi
+elif [[ "$OSTYPE" == *"linux"* ]]; then
+  # echo "This is Linux - OSTYPE[$OSTYPE]. Assuming 'date' command is available and GNU.";
+  DATE_CMD='date';
+else
+  echo; echo "Unable to determine OS type - \$OSTYPE[$OSTYPE] contains neither 'linux' nor 'darwin'. Stopping.";
+  echo; echo;
+  exit 1;
+fi
+
+
+MAX_AGE=3600;  # One hour = "fresh enough"
+
+# Returns unix timestamp with decimal
+BACKUP_DATE_UNIX=`terminus backup:info --field=date --format=string $1`;
+
+if [[ -z $BACKUP_DATE_UNIX ]]; then
+  BACKUP_DATE_UNIX=0;   # lol never!
+fi
+
+BACKUP_DATE_UNIX=${BACKUP_DATE_UNIX%.*};  # Strip decimal
+BACKUP_DATE_FRIENDLY=$($DATE_CMD -d @$BACKUP_DATE_UNIX);
+echo "Backup date: $BACKUP_DATE_FRIENDLY";
+
+NOW=`$DATE_CMD +%s -u`;
+BACKUP_AGE=`expr $NOW - $BACKUP_DATE_UNIX`;
+echo "Backup age: $BACKUP_AGE seconds";
+
+if [[ $BACKUP_AGE -gt $MAX_AGE ]]; then
+  # echo "Backup is stale - $BACKUP_DATE_FRIENDLY - $BACKUP_AGE seconds ago.";
+
+  # By convention, a non-zero exit code indicates an error condition.
+  # We will return the backup age in seconds, since it is stale.
+  exit $BACKUP_AGE;
+else
+  echo "Backup is fresh enough - $BACKUP_DATE_FRIENDLY - $BACKUP_AGE seconds ago.";
+
+  # By convention, exit code 0 means "success", so we will return 0
+  # to indicate success -- the backup is fresh
+  exit 0;
+fi
+
diff --git a/web/modules/custom/asc_courses/scripts/pull_courses_data.sh b/web/modules/custom/asc_courses/scripts/pull_courses_data.sh
new file mode 100644
index 0000000000000000000000000000000000000000..648ad7d27d0d1000adcc52582c5323c62d2af7bc
--- /dev/null
+++ b/web/modules/custom/asc_courses/scripts/pull_courses_data.sh
@@ -0,0 +1,107 @@
+#!/usr/bin/env bash
+
+USE_LANDO="y";
+
+LIGHT_GREEN='\x1B[92m';
+NC='\x1B[39m';
+
+echo;
+echo "//////////////////////// PRE-FLIGHT ///////////////////////";
+
+#TODAYS_DATE="`date +%Y-%m-%d`";
+#echo "Today's date: $TODAYS_DATE";
+YMD_HM=$(date +%Y%m%d_%H%M);
+echo "YYYYMMDD_HHMM = $YMD_HM";
+echo;
+
+
+# Are we using lando, or drush, or like what
+LANDO_CMD=$(which lando);
+# echo "Lando cmd: $LANDO_CMD";
+if [[ -z $LANDO_CMD ]]; then
+  echo; echo "'lando' command not found. We'll just call 'drush'."; echo;
+  DRUSH_CMD="drush";
+else
+  echo "Lando detected.";
+
+  if [[ -z $USE_LANDO ]]; then
+    echo -ne "Use lando site? (y/n) ";
+    read USE_LANDO;
+  fi
+  if [[ $USE_LANDO == 'y' || $USE_LANDO == 'yes' ]]; then
+    DRUSH_CMD="$LANDO_CMD drush";
+  else
+    DRUSH_CMD="drush";
+  fi
+  echo;
+fi
+
+
+# can connect to EIP over network?
+echo "Connectivity test...";
+if [[ ! -z $(which nc) ]]; then
+  nc -z -G 15 apig.eip.osu.edu 443;
+  CONNECT_EXIT=$?;
+else
+  curl -I --connect-timeout 15 https://apig.eip.osu.edu;
+  CONNECT_EXIT=$?;
+fi
+
+
+if [[ $CONNECT_EXIT -ne 0 ]]; then
+  echo "Unable to open a connection to apig.eip.osu.edu:443.. please check your network connection.";
+  exit;
+else
+  echo "Connectivity test succeeded.";
+fi
+
+echo;
+
+# Confirm we can connect to API and authenticate
+ACCESS_TOKEN_CMD="$DRUSH_CMD asc-courses-access-token";
+echo "Access TOKEN command: $ACCESS_TOKEN_CMD";
+eval $ACCESS_TOKEN_CMD;
+TOKEN_CMD_EXIT=$?;
+# echo; echo;
+# echo "Token cmd exit: $TOKEN_CMD_EXIT";
+# echo;
+
+if [[ $TOKEN_CMD_EXIT -ne 0 ]]; then
+  echo "Unable to get an EIP access token.  Check the API key configuration to make sure it's valid.";
+  echo;
+  echo;
+  exit;
+else
+  echo "API authentication succeeded.";
+  echo;
+fi
+
+echo;
+
+# drush asc_courses:pull-all-dorgs
+PULL_DORGS_CMD="$DRUSH_CMD asc_courses:pull-all-dorgs";
+echo "/////////////////// PULL DORGS FROM API ///////////////////";
+echo "Pull dorgs command: $PULL_DORGS_CMD";
+eval $PULL_DORGS_CMD;
+echo;
+
+
+# drush asc_courses:process-api-data
+echo "/////////////////// PROCESS API DATA //////////////////////";
+PROCESS_DATA_CMD="$DRUSH_CMD asc_courses:process-api-data";
+echo "Process api data command: $PROCESS_DATA_CMD";
+eval $PROCESS_DATA_CMD;
+echo;
+
+
+
+# # drush sql-dump --tables-list=asc_courses_api_data,asc_courses_processed > asc_courses_data.sql
+echo "/////////////////// EXPORT SQL DATA ///////////////////////";
+COURSES_DATA_FILE="asc_courses_data_${YMD_HM}.sql"
+echo "Courses data file: $COURSES_DATA_FILE"
+SQL_DUMP_CMD="$DRUSH_CMD sql-dump --tables-list=asc_courses_api_data,asc_courses_processed > $COURSES_DATA_FILE"
+echo "SQL dump command: $SQL_DUMP_CMD";
+eval $SQL_DUMP_CMD;
+echo;
+
+
diff --git a/web/modules/custom/asc_courses/scripts/query_all.sh b/web/modules/custom/asc_courses/scripts/query_all.sh
new file mode 100644
index 0000000000000000000000000000000000000000..67f94bb5ca4556358267fd0aa3fcaf93e8b58e56
--- /dev/null
+++ b/web/modules/custom/asc_courses/scripts/query_all.sh
@@ -0,0 +1,76 @@
+#!/usr/bin/env bash
+
+# Example usage:
+#   echo "select distinct type, count(*) from node group by 1 order by 2 desc;" > node_counts.sql
+#   ./query_all.sh node_counts.sql live | tee node_counts.txt
+
+UPSTREAM='b9baf7af-eb2c-4db5-81e6-32d3d9042572';
+
+# Check command line arguments
+if [[ -z $1 ]]; then
+  echo; echo "Usage: $0 <query_file> [environment]";
+  echo; echo;
+  exit 1;
+elif [[ ! -f $1 || ! -r $1 ]]; then
+  echo; echo "The filename '$1' doesn't exist, isn't readable, or isn't an ordinary file.";
+  echo; echo;
+  exit 1;
+fi
+
+
+# colors
+LIGHT_GREEN='\x1B[92m';
+LIGHT_RED='\x1B[91m';
+NC='\x1B[39m';
+
+
+# Default to 'dev' environment if none was specified
+if [[ -z $2 ]]; then
+  echo; echo "No environment specified, assuming dev.."; echo;
+  ENV='dev';
+else
+  ENV=$2;
+fi
+
+
+# ALL sites
+SITES=$(terminus site:list --upstream=$UPSTREAM --fields=name --format=string | sort);
+
+# Non-sandbox sites only
+# SITES=$(terminus site:list --upstream=$UPSTREAM --fields=name --format=string --filter=plan_name!=Sandbox | sort);
+
+
+for SITE_NAME in $SITES; do
+  echo -e "${LIGHT_GREEN}=== $SITE_NAME ===${NC}";
+
+  if [[ ! -f ./backup_fresh.sh || ! -x ./backup_fresh.sh ]]; then
+    echo "./backup_fresh.sh isn't an executable script... assuming all backups are stale..";
+    BACKUP_FRESH=1;
+  else
+    # BACKUP FRESHNESS SCRIPT: https://gist.github.com/weaver299/46257300e53fe50b2a0b929ab721860e
+    # Check if backup is "fresh" "enough"... (only if [[ $ENV == 'live' ]] maybe?)
+    ./backup_fresh.sh $SITE_NAME.$ENV;
+    BACKUP_FRESH=$?; # capture exit code
+  fi
+
+  if [[ $BACKUP_FRESH -gt 0 ]]; then
+    # 0 means "fresh enough", else the script returns the age in seconds
+    echo "Backup is stale - Creating a new one...";
+    # echo "terminus backup:create $SITE_NAME.$ENV --keep-for=30 --element=db";
+    terminus backup:create $SITE_NAME.$ENV --keep-for=30 --element=db;
+  fi
+
+  # Wake site  (only if [[ $ENV == 'live' ]] if you have no sandboxes?)
+  terminus env:wake $SITE_NAME.$ENV;
+
+  if [[ -z $(which pv) ]]; then
+    echo "'pv' command unavailable, using 'cat' instead...";
+    cat $1 | $(terminus connection:info --fields=mysql_command --format=string $SITE_NAME.$ENV);
+  else
+    echo "Using 'pv' command...";
+    pv $1 | $(terminus connection:info --fields=mysql_command --format=string $SITE_NAME.$ENV);
+  fi
+
+  echo;
+done
+
diff --git a/web/modules/custom/asc_courses/src/AscCoursesApi.php b/web/modules/custom/asc_courses/src/AscCoursesApi.php
index 32026d874d47d8d16f01a13641206a3e106b613b..81caad742b6cc7e591a902a80e17805aade03899 100644
--- a/web/modules/custom/asc_courses/src/AscCoursesApi.php
+++ b/web/modules/custom/asc_courses/src/AscCoursesApi.php
@@ -21,6 +21,7 @@ class AscCoursesApi {
   public $access_token_data;
   public $resolve_host;
   public $db;
+  public $ch;
 
 
   /**
@@ -82,6 +83,17 @@ public function __construct($config = null, $db = null, $environment = '') {
     if ($this->debug) echo "\n\n";
   }
 
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __destruct() {
+    if(!empty($this->ch)) {
+      curl_close($this->ch);
+    }
+  }
+
+
   /**
    * Return an access token. Fetch a new one if necessary.
    */
@@ -144,7 +156,7 @@ public function getAccessToken() {
   /**
    * Fetch a new access token via the API and return it
    */
-  protected function fetchAccessToken() {
+  public function fetchAccessToken() {
     if($this->debug) echo "============ AscCoursesApi::fetchAccessToken() =============\n";
 
     // get an access token
@@ -183,31 +195,33 @@ protected function fetchAccessToken() {
       "Authorization: Basic $bearer_auth",
     ];
 
-    $ch = curl_init();
-    curl_setopt($ch, CURLOPT_URL, $access_token_url);
+    if(empty($this->ch)) {
+      $this->ch = curl_init();
+    }
+    curl_setopt($this->ch, CURLOPT_URL, $access_token_url);
 
-    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
-    curl_setopt($ch, CURLOPT_POST, true);
-    // curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
-    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
-    curl_setopt($ch, CURLOPT_HTTPHEADER, $access_token_headers);
-    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
+    curl_setopt($this->ch, CURLOPT_CONNECTTIMEOUT, 5);
+    curl_setopt($this->ch, CURLOPT_POST, true);
+    // curl_setopt($this->ch, CURLOPT_POSTFIELDS, $post_data);
+    curl_setopt($this->ch, CURLOPT_TIMEOUT, 30);
+    curl_setopt($this->ch, CURLOPT_HTTPHEADER, $access_token_headers);
+    curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true);
+    curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, true);
 
     if(isset($this->resolve_host)) {
       if ($this->debug) echo "AscCoursesApi::fetchAccessToken() - Resolve host set: " . print_r($this->resolve_host, true) . "\n";
-      curl_setopt($ch, CURLOPT_RESOLVE, $this->resolve_host);
-      curl_setopt($ch, CURLOPT_PORT, constant($this->soip_constant_name));
+      curl_setopt($this->ch, CURLOPT_RESOLVE, $this->resolve_host);
+      curl_setopt($this->ch, CURLOPT_PORT, constant($this->soip_constant_name));
     }
 
     if($this->debug > 1) {
-      curl_setopt($ch, CURLOPT_VERBOSE, true);
+      curl_setopt($this->ch, CURLOPT_VERBOSE, true);
     }
 
     $access_token_start = microtime(true);
-    $access_token_result = curl_exec($ch);
-    $access_token_error = curl_error($ch);
-    curl_close($ch);
+    $access_token_result = curl_exec($this->ch);
+    $access_token_error = curl_error($this->ch);
+    // curl_close($ch);
     $access_token_finish = microtime(true);
     $access_token_seconds = $access_token_finish - $access_token_start;
     if ($this->debug) echo "AscCoursesApi::fetchAccessToken() - CURL error: " . print_r($access_token_error, true) . "\n";
@@ -273,32 +287,35 @@ public function fetchDorgCourses($dorg, $force = false) {
       "Authorization: Bearer $access_token"
     ];
 
-    $ch = curl_init();
-    curl_setopt($ch, CURLOPT_URL, $course_data_url);
+    if(empty($this->ch)) {
+      $this->ch = curl_init();
+    }
+
+    curl_setopt($this->ch, CURLOPT_URL, $course_data_url);
 
-    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
-    // curl_setopt($ch, CURLOPT_POST, true);
-    // curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
-    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
-    curl_setopt($ch, CURLOPT_HTTPHEADER, $course_data_headers);
-    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
+    curl_setopt($this->ch, CURLOPT_CONNECTTIMEOUT, 5);
+    // curl_setopt($this->ch, CURLOPT_POST, true);
+    // curl_setopt($this->ch, CURLOPT_POSTFIELDS, $post_data);
+    curl_setopt($this->ch, CURLOPT_TIMEOUT, 30);
+    curl_setopt($this->ch, CURLOPT_HTTPHEADER, $course_data_headers);
+    curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true);
+    curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, true);
 
     if(isset($this->resolve_host)) {
       if ($this->debug) echo "fetchDorgCourses() - Resolve host set: " . $this->resolve_host . "\n";
       // error_log("fetchDorgCourses() - Resolve host set: " . $this->resolve_host);
-      curl_setopt($ch, CURLOPT_RESOLVE, $this->resolve_host);
-      curl_setopt($ch, CURLOPT_PORT, constant($this->soip_constant_name));
+      curl_setopt($this->ch, CURLOPT_RESOLVE, $this->resolve_host);
+      curl_setopt($this->ch, CURLOPT_PORT, constant($this->soip_constant_name));
     }
 
     if($this->debug > 1) {
-      curl_setopt($ch, CURLOPT_VERBOSE, true);
+      curl_setopt($this->ch, CURLOPT_VERBOSE, true);
     }
 
     $curl_start = microtime(true);
-    $course_data_result = curl_exec($ch);
-    $curl_error = curl_error($ch);
-    curl_close($ch);
+    $course_data_result = curl_exec($this->ch);
+    $curl_error = curl_error($this->ch);
+    // curl_close($ch);
     $curl_finish = microtime(true);
     $curl_seconds = $curl_finish - $curl_start;
     if ($this->debug) echo "fetchDorgCourses() - CURL error: " . print_r($curl_error, true) . "\n";
@@ -309,8 +326,13 @@ public function fetchDorgCourses($dorg, $force = false) {
       return 0;
     }
     else {
-      if ($this->debug) echo "Course data length:" . strlen($course_data_result) . "\n";
-      if ($this->debug) echo "Course data in $curl_seconds seconds\n\n";
+      if ($this->debug) {
+        echo "Course data length:" . strlen($course_data_result) . "\n";
+        echo "Course data in $curl_seconds seconds\n\n";
+      }
+      else {
+        echo " - " . strlen($course_data_result) . " characters in " . round($curl_seconds, 2) . " seconds.";
+      }
 
 
       // $connection = \Drupal::database();
@@ -358,6 +380,7 @@ public function processDorgCourses($dorg) {
    */
   public function processPendingApiData($environment = null, $count = null) {
     if($this->debug) echo "============ AscCoursesApi::processPendingApiData() =============\n";
+    else echo "Processing pending API data ";
 
     $query = $this->db->select("asc_courses_api_data", "acad")
         ->fields("acad")
@@ -376,12 +399,14 @@ public function processPendingApiData($environment = null, $count = null) {
     $api_data_result = $query->execute();
     while($row = $api_data_result->fetchAssoc()) {
       if($row['request_type'] == 'crseinfo') {
+
         $this->processApiDorgCoursesRecord($row);
       }
       else {
         die("AscCoursesApi::processPendingApiData(): unexpected asc_course_api_data row request_type: " . $row['request_type']);
       }
     }
+    if(!$this->debug) echo " done!\n";
   }
 
   /**
@@ -398,6 +423,9 @@ public function processApiDorgCoursesRecord($row) {
       echo "processed: " . $row["processed"] . "\n";
       echo "json data length: " . strlen($row['raw_json']) . "\n";
     }
+    else {
+      echo '.';
+    }
 
     $json_data = json_decode($row['raw_json']);
     if(!$json_data) {
@@ -608,32 +636,34 @@ public function fetchDorgList() {
       if($this->debug) echo "D-org POST data: " . print_r($dorg_post_data, true) . "\n";
     */
 
-    $ch = curl_init();
-    curl_setopt($ch, CURLOPT_URL, $dorg_data_url);
+    if(empty($this->ch)) {
+      $this->ch = curl_init();
+    }
+    curl_setopt($this->ch, CURLOPT_URL, $dorg_data_url);
 
-    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
-    curl_setopt($ch, CURLOPT_POST, true);
-    curl_setopt($ch, CURLOPT_POSTFIELDS, $dorg_post_data);
-    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
-    curl_setopt($ch, CURLOPT_HTTPHEADER, $dorg_data_headers);
-    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
+    curl_setopt($this->ch, CURLOPT_CONNECTTIMEOUT, 5);
+    curl_setopt($this->ch, CURLOPT_POST, true);
+    curl_setopt($this->ch, CURLOPT_POSTFIELDS, $dorg_post_data);
+    curl_setopt($this->ch, CURLOPT_TIMEOUT, 30);
+    curl_setopt($this->ch, CURLOPT_HTTPHEADER, $dorg_data_headers);
+    curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true);
+    curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, true);
 
     if(isset($this->resolve_host)) {
       if ($this->debug) echo "fetchDorgList() - Resolve host set: " . $this->resolve_host . "\n";
       // error_log("fetchDorgList() - Resolve host set: " . $this->resolve_host);
-      curl_setopt($ch, CURLOPT_RESOLVE, $this->resolve_host);
-      curl_setopt($ch, CURLOPT_PORT, constant($this->soip_constant_name));
+      curl_setopt($this->ch, CURLOPT_RESOLVE, $this->resolve_host);
+      curl_setopt($this->ch, CURLOPT_PORT, constant($this->soip_constant_name));
     }
 
     if($this->debug > 1) {
-      curl_setopt($ch, CURLOPT_VERBOSE, true);
+      curl_setopt($this->ch, CURLOPT_VERBOSE, true);
     }
 
     $curl_start = microtime(true);
-    $dorg_data_result = curl_exec($ch);
-    $curl_error = curl_error($ch);
-    curl_close($ch);
+    $dorg_data_result = curl_exec($this->ch);
+    $curl_error = curl_error($this->ch);
+    // curl_close($this->ch);
     $curl_finish = microtime(true);
     $curl_seconds = $curl_finish - $curl_start;
     if ($this->debug) echo "fetchDorgList() - CURL error: " . print_r($curl_error, true) . "\n";
@@ -981,6 +1011,32 @@ public static function getDorgList() {
       'D0799' => [
         'name' => "Speech and Hearing",
       ],
+
+      // ENGINEERING DORGS
+      'D1407' => [
+        'name' => "Aeronautical and Astronautical Engineering",
+      ],
+      'D1425' => [
+        'name' => "Chemical and Biomolecular Engineering",
+      ],
+      'D1435' => [
+        'name' => "Computer Science and Engineering",
+      ],
+      'D1445' => [
+        'name' => "Electrical and Computer Engineering",
+      ],
+      'D1457' => [
+        'name' => "Integrated Systems Engineering",
+      ],
+      'D1468' => [
+        'name' => "Materials Science and Engineering",
+      ],
+      'D1470' => [
+        'name' => "Mechanical Engineering",
+      ],
+      'D1470' => [
+        'name' => "Nuclear Engineering",
+      ],
     ];
 
     return $dorgs;
diff --git a/web/modules/custom/asc_courses/src/Commands/AscCoursesCommands.php b/web/modules/custom/asc_courses/src/Commands/AscCoursesCommands.php
index 73d24484096a221db2c869f38436520982cb11ce..7032a5f5bece7f776d971659342665f52e283fa1 100644
--- a/web/modules/custom/asc_courses/src/Commands/AscCoursesCommands.php
+++ b/web/modules/custom/asc_courses/src/Commands/AscCoursesCommands.php
@@ -79,6 +79,40 @@ public function commandName($arg1, $options = ['option-name' => 'default']) {
   }
 
 
+  /**
+   * Retrieve an EIP access token
+   *
+   * @param array $options
+   *   An associative array of options whose values come from cli, aliases, config, etc.
+   * @option option-name
+   *   Description
+   * @usage asc-courses-access-token
+   *   Usage description
+   *
+   * @command asc_courses:access-token
+   * @aliases asc-courses-access-token
+   */
+  public function accessToken($options = ['option-name' => 'default']) {
+    $api = new AscCoursesApi();
+    // $api->debug = 1;
+    $result = $api->fetchAccessToken();
+
+    if(isset($result->error)) {
+      echo "\n";
+      echo "Error fetching access token: " . $result->error . " - " . $result->error_description . "\n";
+      return 1;
+    }
+    else if (isset($result->access_token)) {
+      echo "Access token: " . $result->access_token . "\n";
+      echo "Expires in " . $result->expires_in . " seconds.\n";
+      return 0;
+    }
+    else {
+      echo "Unrecogized response from API: " . print_r($result, true) . "\n";
+      return 1;
+    }
+  }
+
   /**
    * Pull fresh data for all D-Orgs from the API to database
    *
@@ -94,7 +128,7 @@ public function commandName($arg1, $options = ['option-name' => 'default']) {
    */
   public function pullAllDorgs($options = ['option-name' => 'default']) {
     $api = new AscCoursesApi();
-    $api->debug = 1;
+    $api->debug = 0;
 
     $dorgs = $api->getDorgList();
     $dorg_numbers = array_keys($dorgs);
@@ -102,14 +136,9 @@ public function pullAllDorgs($options = ['option-name' => 'default']) {
     echo "Dorg count: " . count($dorg_numbers) . "\n";
 
     foreach($dorg_numbers as $dorg_number) {
-
-        echo "=== $dorg_number - " . $dorgs[$dorg_number]["name"] . " ===\n";
-        $courses = $api->fetchDorgCourses($dorg_number);
-        // echo "courses type: " . gettype($courses) . "\n";
-        // $courses_vars = get_object_vars($courses);
-        // echo "vars: " . print_r(array_keys($courses_vars), true) . "\n";
-
-        echo "===================================\n";
+      echo "=== $dorg_number - " . $dorgs[$dorg_number]["name"];
+      $courses = $api->fetchDorgCourses($dorg_number, true);
+      echo "\n";
     }
 
   }
@@ -130,7 +159,7 @@ public function pullAllDorgs($options = ['option-name' => 'default']) {
    */
   public function processApiData($count = null, $options = ['option-name' => 'default']) {
     $api = new AscCoursesApi();
-    $api->debug = 1; // apparently we're hard-coding debug mode now
+    //$api->debug = 1; // apparently we're hard-coding debug mode now
 
     if(is_numeric($count)) {
       echo "count argument specified: $count\n";