 
 # define auth obj; used for init auth & fetches
 authClient = new gapi.auth.JWT(
-    config.ga.clientEmail,
-    config.ga.privateKeyPath,
-    null, # key as string, not needed due to key file
-    [config.ga.scopeUri]
+  config.ga.clientEmail,
+  if process.env.NODE_ENV is 'development' then config.ga.privateKeyPath else null, # key as .pem file
+  if process.env.NODE_ENV is 'production' then config.ga.privateKeyContent else null,
+  [config.ga.scopeUri]
 )
 
 # auth on bootstrap
 authPromise = new Promise (resolve, reject) ->
   console.log "[INFO] OAuthing w/ GA..."
-  # console.log "console.log config.ga.privateKeyPath = " + config.ga.privateKeyPath
-  # returns expires_in: 1395623939 and refresh_token: 'jwt-placeholder', not sure if 16 days or 44 yrs -_-
-  if !config.ga.privateKeyPath?
-    error = new Error "[ERROR] process.env.APP_GA_KEY_PATH mismatch or #{ config.ga.privateKeyPath }"
-    reject error
-  else
-    authClient.authorize (err, token) ->
-      if err
-        error = new Error "[ERROR] OAuth, err = #{ err }"
-        console.error error
-        reject error
-      else
-        console.info "[SUCCESS] server OAuthed w/ GA."
-        resolve token
-      return
+  authClient.authorize (err, token) ->
+    # returns expires_in: 1395623939 and refresh_token: 'jwt-placeholder', not sure if 16 days or 44 yrs -_-
+    if err
+      error = new Error "[ERROR] OAuth error; err = #{ err }"
+      reject error
+    else
+      console.info "[SUCCESS] server OAuthed w/ GA."
+      gapi.discover('analytics', 'v3').withAuthClient(authClient).execute (err, client) ->
+        if err
+          error = new Error "[ERROR] gapi.discover.execute, err = #{ err }"
+          reject error
+        else resolve client # reuse this client
+        return
+    return
   return
 
 fetch = (key) ->
-  ->
+  (client) -> # client returned from gapi.discover.execute
     query = queries[key]
-    promises = []
+    queryPromises = []
 
     query.queryObjs.forEach (queryObj) ->
       promise = new Promise (resolve, reject) ->
-        gapi.discover('analytics', 'v3').execute (err, client) ->
+        client.analytics.data.ga.get(queryObj).execute (err, result) ->
           if err
-            error = new Error "[ERROR] error with gapi.discover.execute, err = #{ err }"
+            error = new Error "[ERROR] client.analytics.data.ga.get, err = #{ err.message }"
             reject error
-          else
-            client.analytics.data.ga.get queryObj
-              .withAuthClient authClient
-              .execute (err, result) ->
-                if err
-                  error = new Error "[ERROR] error when fetching via GA API, err = #{ err }"
-                  reject error
-                else resolve result
-                return
+          else resolve result
           return
         return
-      promises.push promise
-      return
-
-    Promise.all(promises).then(query.transform).catch (err) -> console.error err; return
+      queryPromises.push promise
+      return
+
+    Promise.all(queryPromises).then query.transform
+    # err catched in cache.coffee .catch (err) -> console.error err; return
 
 ###
 # define queries

      'end-date': 'yesterday'
      'metrics': 'ga:users,ga:pageviews'
      'dimensions': 'ga:pagePathLevel2'
      'filters': 'ga:pagePathLevel1=@installed' # =@ contains substring
      'sort': '-ga:pageviews'
      'max-results': 3500
    }

      'end-date': '8daysAgo'
      'metrics': 'ga:users,ga:pageviews'
      'dimensions': 'ga:pagePathLevel2'
      'filters': 'ga:pagePathLevel1=@installed'
      'sort': '-ga:pageviews'
      'max-results': 3500
    }
  ]
  transform: (data) ->
    current = data[0].rows[..19] # TODO: ranking range as arg
    prior = data[1].rows[..29]

    _transform = (d, i) ->
      d[0] = util.removeSlash d[0]
      d[1] = +d[1]; d[2] = +d[2]
      d.push i + 1 # rank
      return
    current.forEach _transform
    prior.forEach _transform

    result = current.map (d) ->
      bName: d[0]
      bRank: current: d[3]
      bUsers: current: d[1] # ga:users
      bInstalls: current: d[2] # ga:pageviews

    ghPromises = []
    result.forEach (pkg) ->
      priorPkg = _find prior, (d) -> d[0] is pkg.bName
      if priorPkg?
        pkg.bRank.prior = priorPkg[3]
        pkg.bUsers.prior = priorPkg[1]
        pkg.bInstalls.prior = priorPkg[2]
      else
        throw new Error "[ERROR] no prior period data for package #{ pkg.bName }"
      ghPromises.push gh.appendData pkg
      return

    Promise.all(ghPromises).then -> result

queries.geo =
  queryObjs: [
