Пример #1
0
import moment from 'moment-timezone';
/**
 *
 * This file replaces the original scheduler object used by Timekit.io
 * A compilation step substitutes the original reference to a reference
 * to this object.
 *
 */
let findTime = () => {};
let createBooking = () => {};
let userTimezone = {
  timezone: moment.tz.guess(),
  utc_offset: moment().utcOffset(),
};

const scheduler = {
  configure() { return this; },
  setUser() { return this; },
  include() { return this; },
  headers() { return this; },
  getUserTimezone: () => Promise.resolve({ data: userTimezone }),
  findTime: data => Promise.resolve(findTime(data)), // to be overridden by controller
  createBooking: data => createBooking(data), // to be overridden by controller
  setFindTime(f) { findTime = f; },
  setCreateBooking(f) { createBooking = f; },
  setUserTimezone(tz) { userTimezone = tz; },
};

export default scheduler;
Пример #2
0
 function setDateAndTime (time) {
   time = time || moment();
   eventTime.val(time.format('HH:mm'));
   eventDate.val(time.format('YYYY-MM-DD'));
 }
Пример #3
0
 it('should re-normalize to US/Pacific by default on switch to timezoneAware', function() {
   thisTd.applyNewTimePrefs({timezoneAware: true});
   var datum = _.find(thisTd.data, {type: 'basal'});
   expect(datum.normalTime).to.equal(moment(datum.deviceTime).tz('US/Pacific').toISOString());
 });
Пример #4
0
  this.GetOpeningTimes = function(callback) {
    // check we've been configured correctly
    if (!self.calendar_URL || !self.calendar_VStarget) return self.Error("Orlando Park ID calendar " + self.park_id + " not configured.", null, callback);

    // get today's date in local time and the ending date for our schedule fetch
    var today = moment().tz(self.park_timezone);
    var endDay = moment().add(self.scheduleMaxDates, 'days').tz(self.park_timezone);

    // So. Orlando's calendar page uses ASPX ViewStates etc, and seems to have an encrpyted view state.
    // Rather than try to interfere with that, I'm just sending POST data directly and letting the server
    //  create us a Viewstate and generally side-stepping that pain.

    // The POST data needs two keys to update the viewstate:
    //  __EVENTTARGET: "UniversalStudiosFloridaCalendar$ECalendar" (or similar)
    //  __EVENTARGUMENT: Z[number of days to start of the month from 2000-01-01]

    var Y2K = moment("2000-01-01", "YYYY-MM-DD");

    // get today's date and the current month
    var requestStart = moment.range(Y2K, moment(today.format("YYYY-MM"), "YYYY-MM")).diff("days");

    // get formatted end date for fetching
    var requestEnd = moment.range(Y2K, moment(endDay.format("YYYY-MM"), "YYYY-MM")).diff("days");

    // get list of month calendars to process (either just this month, or this month and next)
    var todo = [requestStart];
    if (requestEnd != requestStart) {
      todo.push(requestEnd);
    }

    var schedule = [];
    var startDateFound = false;

    async.eachSeries(todo, function(calendarMonth, callback) {
      var requestObj = {
        url: self.calendar_URL,
        method: "POST",
        formData: {
          __EVENTTARGET: self.calendar_VStarget,
          __EVENTARGUMENT: "V" + calendarMonth,
        }
      };

      self.MakeNetworkRequest(requestObj, function(err, resp, body) {
        if (err) return self.Error("Error fetching calendar page", err, callback);

        // parse returned HTML
        self.ParseCalendar(body, function(err, data) {
          if (err) return self.Error("Failed to parse calendar page HTML", err, callback);

          // loop through returned dates
          for (var i = 0, date; date = data[i++];) {
            // don't start adding to return object until we find our start date value
            if (!startDateFound && !schedule.length) {
              if (!moment(date.date).isSameOrAfter(today, "day")) continue;
              startDateFound = true;
            }

            // add to returned schedule
            schedule.push(date);

            if (moment(date.date).isSameOrAfter(endDay, "date")) {
              // reached desired end date, return
              return callback(null);
            }
          }

          // not reached end date yet, return for next async series to process
          return callback(null);
        });
      });
    }, function(err) {
      self.Dbg("FDSAfdsfds");
      if (err) return self.Error("Failed to fetch calendar data", err, callback);
      return callback(null, schedule);
    });
  };
Пример #5
0
Activity.prototype.endUnix = function () {
  return this.state.endUnix || moment().add(2, 'hours').unix();
};
Пример #6
0
 "Thanksgiving": (function (year) {
         var first = new Date(year, 10, 1),
             dayOfWeek = first.getDay();
         return moment("{0}-11-{1}".format(year, 22 + (11 - dayOfWeek) % 7));
     })(year),
Пример #7
0
        var day = newDate.getDate();
        return day+'/'+month;
    },

    startAutomaticTimestamps: function(_tz, _interval) {
        var tz = _tz || "UTC";
        var interval = _interval || 20; // Secs
        util.printTimestampsNow(null, null, null, tz);
        var interval_id = setInterval(function() {
            util.printTimestampsNow(null, null, null, tz);
        }, 1000*interval);
        return interval_id;
    },

    from_now(ms) {
        return moment(ms).fromNow();
    },

    hours_until(ms) {
        let now = new Date().getTime();
        let secs_until = Math.round((ms - now)/1000);
        return parseInt(secs_until / 60.0 / 60.0);
    },

    timesince(ms) {
        let LEVELS = [
            { label: "second", cutoff: 60, recent: true, seconds: 1 },
            { label: "minute", cutoff: 60, seconds: 60 },
            { label: "hour", cutoff: 24, seconds: 60*60 },
            { label: "day", cutoff: 30, seconds: 60*60*24 }
        ];
Пример #8
0
 }).filter(function (dose) {
     // in date range
     var date = moment(dose.date);
     return !(date.isBefore(startFilter) || date.isAfter(endFilter));
 });
Пример #9
0
    }, function (err, resp, body) {
      if (err) return self.Error("Error getting opening schedule data", err, callback);

      if (!body || !body.agenda || !Array.isArray(body.agenda)) return self.Error("No opening data returned by API", body, callback);

      var schedule = [];

      var endDay = moment().add(self.scheduleMaxDates, 'days');
      var reTime = /(\d+)h - (\d+|Minuit)(?:h?)/ig;

      for (var i = 0, agenda; agenda = body.agenda[i++];) {
        var day = moment.tz(agenda.jour, "DD-MM-YYYY", self.park_timezone);
        var item = {
          date: day.format(self.dateFormat)
        };

        if (day.isAfter(endDay)) {
          break;
        }

        if (agenda.type === "D") {
          item.type = "Closed";
        } else if (agenda.type === "A") {
          item.type = "Operating";
          var resultRe;
          var firstResult = true;
          while ((resultRe = reTime.exec(agenda.horaire)) !== null) {
            // - Normal time
            if (firstResult === true) {
              item.openingTime = day.clone().hours(parseInt(resultRe[1])).minutes(0).seconds(0).format(self.timeFormat);
              if (resultRe[2] === "Minuit") {
                item.closingTime = day.clone().hours(23).minutes(59).seconds(59).format(self.timeFormat);
              } else {
                item.closingTime = day.clone().hours(parseInt(resultRe[2])).minutes(0).seconds(0).format(self.timeFormat);
              }
              firstResult = false;
            } else {
              // - Special time
              item.special = item.special || [];
              var specialItem = {
                type: "Event"
              };
              specialItem.openingTime = day.clone().hours(parseInt(resultRe[1])).minutes(0).seconds(0).format(self.timeFormat);
              if (resultRe[2] === "Minuit") {
                specialItem.closingTime = day.clone().hours(23).minutes(59).seconds(59).format(self.timeFormat);
              } else {
                specialItem.closingTime = day.clone().hours(parseInt(resultRe[2])).minutes(0).seconds(0).format(self.timeFormat);
              }
              item.special.push(specialItem);
            }
          }

        } else {
          self.Dbg("Unknown agenda type :", agenda.type);
          continue;
        }

        schedule.push(item);
      }

      return callback(null, schedule);
    });
function isGameUpcoming(data) {
  return data.unixMillisecondsStartTime > moment().valueOf();
}
Пример #11
0
 events = events.map(function (event) {
     event.happened = moment.tz(event.date, tz).isBefore(moment());
     return event;
 });
Пример #12
0
events.on('token.added', function (tokenModel) {
    models.User.edit({last_seen: moment().toDate()}, {id: tokenModel.get('user_id')})
        .catch(function (err) {
            logging.error(new errors.GhostError({err: err, level: 'critical'}));
        });
});
Пример #13
0
exports.addCustomFinancialDetails = function(req, res) {
    
console.log('req.body before ' , req.body);

 var merchantFields = [
          'merchant_type' ,
          'organization' ,
          'description' ,
          'currency_code',
          'master_card' ,
          'discover' ,
          'american_express' ,
          'visa'
          ];


if (req.body.merchant_type == "CyberSource" || req.body.merchant_type == "BeanStream" || req.body.merchant_type == "Authorize.NET Card Present" || req.body.merchant_type == "Do Not Use" || req.body.merchant_type == "DirectPay" || req.body.merchant_type == "ICICI Bank" || req.body.merchant_type == "Alignet" ||  req.body.merchant_type == "PagoEfectivo" || req.body.merchant_type == "CC Avenue"  || req.body.merchant_type == "PayGate") 
                { 
                  merchantFields.push('memo');
                  merchantFields.push('keyfile_name');
                  merchantFields.push('store_number');
                  merchantFields.push('account_password');
                  merchantFields.push('account_id');
                  merchantFields.push('vendor');
                  merchantFields.push('key');
                }

if (req.body.merchant_type == "CardConnect") 
                {
                  merchantFields.push('memo');
                  merchantFields.push('store_number');
                  merchantFields.push('account_password');
                  merchantFields.push('account_id');
                  merchantFields.push('zero_auth');
                }

if (req.body.merchant_type == "First Data") 
                { 
                  merchantFields.push('memo');
                  merchantFields.push('keyfile_name');
                  merchantFields.push('store_number');
                  merchantFields.push('account_password');
                  merchantFields.push('account_id');
                  merchantFields.push('key');
                }
if (req.body.merchant_type == "Authorize.NET") 
                { 
                  merchantFields.push('memo');
                  merchantFields.push('store_number');
                  merchantFields.push('account_password');
                  merchantFields.push('key');
                }

if (req.body.merchant_type == "PayFlow") 
                { 
                  merchantFields.push('memo');
                  merchantFields.push('store_number');
                  merchantFields.push('account_password');
                  merchantFields.push('account_id');
                  merchantFields.push('vendor');
                  merchantFields.push('key');
                  merchantFields.push('capture_mode');
                }
if (req.body.merchant_type == "PayPal Express") 
                { 
                  merchantFields.push('memo');
                  merchantFields.push('store_number');
                  merchantFields.push('account_password');
                  merchantFields.push('account_id');
                  merchantFields.push('key');
                }

if (req.body.merchant_type == "Stripe") 
                {
                merchantFields.push('account_id'); 
                merchantFields.push('zero_auth'); 
                }

if (req.body.merchant_type == "GoEmerchant") 
                { 
                  merchantFields.push('store_number');
                  merchantFields.push('account_id');
                  merchantFields.push('key');
                  merchantFields.push('zero_auth');
                }

if (req.body.merchant_type == "Cielo") 
                { 
                  merchantFields.push('memo');
                  merchantFields.push('keyfile_name');
                  merchantFields.push('account_password');
                  merchantFields.push('account_id');
                  merchantFields.push('vendor');
                }

if (req.body.merchant_type == "AirPay") 
                { 
                  merchantFields.push('store_number');
                  merchantFields.push('account_password');
                  merchantFields.push('account_id');
                  merchantFields.push('key');
                }

if (req.body.merchant_type == "FirstDataGlobalGatewayE4") 
                { 
                  merchantFields.push('store_number');
                  merchantFields.push('account_password');
                  merchantFields.push('account_id');
                  merchantFields.push('vendor');
                  merchantFields.push('zero_auth');
                }

if (req.body.merchant_type == "T1 Authorize.Net Emulator" || req.body.merchant_type == "Transact Authorize.NET Emulator" || req.body.merchant_type == "NMI Authorize.NET Emulator") 
                { 
                  merchantFields.push('memo');
                  merchantFields.push('store_number');
                  merchantFields.push('account_password');
                  merchantFields.push('key');
                }

if (req.body.merchant_type == "GoCoin") 
                { 
                  merchantFields.push('account_id');
                  merchantFields.push('key');
                }


console.log('merchantFields ' , merchantFields);

var fieldsData = '';

// insert into ages set `name` = 'testing name' , `age` = 26
for (var index in merchantFields) {
    merchantFieldName = merchantFields[index];

        if (req.body[merchantFieldName] == undefined) {
            req.body[merchantFieldName] = '';
        }
        fieldsData+= " `"+merchantFieldName+"` = '" + req.body[merchantFieldName]+ "', ";

    }

 
console.log('fieldsData ' , fieldsData);


    var curtime = moment().format('YYYY-MM-DD HH:mm:ss');
    req.body.created = curtime;
    req.body.modified = curtime;

    if (req.body.merchant_type && req.body.currency_code) {
        if (req.body.id && req.body.id != "" && req.body.id != undefined) {

        var query = "UPDATE `custom_financial_settings` SET "+ fieldsData +" `modified` = '" + req.body.modified + "' WHERE seller_id= '" + req.body.seller_id + "' && id=" + req.body.id;
        } else {
        var query = "INSERT INTO `custom_financial_settings` SET "+ fieldsData +" seller_id = "+req.body.seller_id +" , `created` = '" + req.body.created +"'";
             }


        if (query != "") {
            console.log('query', query)
            connection.query(query, function(err7, results) {
                if (err7) {
                    res.json({ error: err7,code: 101});
                }
                res.json({ result: results, code: 200 });
            });
        }
    } else {
        res.json({ error: 'Enter all required fields',  code: 101});
    }

    

}
Пример #14
0
 convertDateObjectToUtc: function convertDateObjectToUtc(date) {
   return moment(date).tz('Etc/Universal');
 },
Пример #15
0
 "Independence Day": (function (year) {
     var fourth = new Date(year, 6, 4),
         dayOfWeek = fourth.getDay(),
         observed = dayOfWeek === 0 ? 5  : dayOfWeek === 6 ? 3 : 4;
     return moment(new Date(year, 6, observed));
 })(year),
Пример #16
0
            } else {
                return 200;
            }
        },
        permissions: true,
        query(frame) {
            const defaults = {
                dismissible: true,
                location: 'bottom',
                status: 'alert',
                id: ObjectId.generate()
            };

            const overrides = {
                seen: false,
                addedAt: moment().toDate()
            };

            let notificationsToCheck = frame.data.notifications;
            let notificationsToAdd = [];

            const allNotifications = _private.fetchAllNotifications();

            notificationsToCheck.forEach((notification) => {
                const isDuplicate = allNotifications.find((n) => {
                    return n.id === notification.id;
                });

                if (!isDuplicate) {
                    notificationsToAdd.push(Object.assign({}, defaults, notification, overrides));
                }
Пример #17
0
 "Veterans Day": (function (year) {
         var eleventh = new Date(year, 10, 11),
             dayOfWeek = eleventh.getDay(),
             observed = dayOfWeek === 0 ? 12  : dayOfWeek === 6 ? 10 : 11;
         return moment(new Date(year, 10, observed));
     })(year),
Пример #18
0
 allNotifications.forEach((notification) => {
     notification.addedAt = moment(notification.addedAt).toDate();
 });
Пример #19
0
        });
    },

    /**
     * The `routes.yaml` file offers a way to configure your Ghost blog. It's currently a setting feature
     * we have added. That's why the `routes.yaml` file is treated as a "setting" right now.
     * If we want to add single permissions for this file (e.g. upload/download routes.yaml), we can add later.
     *
     * How does it work?
     *
     * - we first reset all url generators (each url generator belongs to one express router)
     *   - we don't destroy the resources, we only release them (this avoids reloading all resources from the db again)
     * - then we reload the whole site app, which will reset all routers and re-create the url generators
     */
    upload(options) {
        const backupRoutesPath = path.join(config.getContentPath('settings'), `routes-${moment().format('YYYY-MM-DD-HH-mm-ss')}.yaml`);

        return localUtils.handlePermissions('settings', 'edit')(options)
            .then(() => {
                return fs.copy(`${config.getContentPath('settings')}/routes.yaml`, backupRoutesPath);
            })
            .then(() => {
                return fs.copy(options.path, `${config.getContentPath('settings')}/routes.yaml`);
            })
            .then(() => {
                urlService.resetGenerators({releaseResourcesOnly: true});
            })
            .then(() => {
                const siteApp = require('../../web/site/app');

                try {
Пример #20
0
 $elem.on('plotselected', function (event, ranges) {
   timefilter.time.from = moment(ranges.xaxis.from);
   timefilter.time.to = moment(ranges.xaxis.to);
   timefilter.time.mode = 'absolute';
   $scope.search();
 });
Пример #21
0
 printTime: function(date_object) {
     var dt = moment(date_object);
     return dt.format("HH:mm");
 },
Пример #22
0
 options.xaxis.tickFormatter = function (val) {
   return moment(val).format(format);
 };
Пример #23
0
Activity.prototype.startUnix = function () {
  return this.state.startUnix || moment().unix();
};
Пример #24
0
(function () {
   "use strict";

	var _ = require("lodash"),
        moment = require("moment-timezone"),
        geocoder = require("./geocoder"),
        repo = require("./repository"),
		q = require("q");

	require("stringformat").extendString("format");
    
    var schedules = {
        "blue": {
            start: moment("2015-11-01")
        },
        "yellow": {
            start: moment("2015-11-08")
        }
    };
    
    var now = moment(),
        week = now.get("week"),
        month = now.get("month"),
        year = now.get("year"),
        isLastWeekOfYear = week >= 52 || (week === 1 && month === 11);
    
    var holidays = {
        "New Year’s Day": moment("{0}-01-01".format(!isLastWeekOfYear ? year : year + 1)),
        "MLK Jr Day": (function (year) {
                var first = new Date(year, 1, 1),
                    dayOfWeek = first.getDay();
                return moment("{0}-01-{1}".format(year, 15 + (4 - dayOfWeek) % 7));
            })(year),
        "Memorial Day": (function (year) {
                var first = new Date(year, 4, 1),
                    dayOfWeek = first.getDay();               
                return moment("{0}-05-{1}".format(year, 25 + (12 - dayOfWeek) % 7));
            })(year),
        "Independence Day": (function (year) {
            var fourth = new Date(year, 6, 4),
                dayOfWeek = fourth.getDay(),
                observed = dayOfWeek === 0 ? 5  : dayOfWeek === 6 ? 3 : 4;
            return moment(new Date(year, 6, observed));
        })(year),
        "Labor Day": (function (year) {
                var date = moment().set('year', year).set('month', 8).set('date', 1).isoWeekday(8);
                if(date.date() == 8) { 
                    date = date.isoWeekday(-6)
                }
                return date;
            })(year),            
        "Veterans Day": (function (year) {
                var eleventh = new Date(year, 10, 11),
                    dayOfWeek = eleventh.getDay(),
                    observed = dayOfWeek === 0 ? 12  : dayOfWeek === 6 ? 13 : 11;
                return moment(new Date(year, 10, observed));
            })(year),
        "Veterans Day": (function (year) {
                var eleventh = new Date(year, 10, 11),
                    dayOfWeek = eleventh.getDay(),
                    observed = dayOfWeek === 0 ? 12  : dayOfWeek === 6 ? 10 : 11;
                return moment(new Date(year, 10, observed));
            })(year),
        "Thanksgiving": (function (year) {
                var first = new Date(year, 10, 1),
                    dayOfWeek = first.getDay();
                return moment("{0}-11-{1}".format(year, 22 + (11 - dayOfWeek) % 7));
            })(year),
        "Christmas": moment("{0}-12-25".format(year))
    };
    
    var geocodeAddress = function(address) {
        var deferred = q.defer();
        geocoder.getCoordinates(address).then(function(result) {
            if (result && result.lat && result.lng) {
              deferred.resolve({
                address: address,
                coordinates: [result.lat, result.lng]
              });
            } else {
              deferred.reject("No coordinates returned");
            }
          },
          deferred.reject);
        return deferred.promise;
      };

	var service = (function () {

		var isHolidayWeek = function (date) {
            return getHolidayWeekday(date) !== null;
        };

		var getHolidayWeekday = function (date) {
            var today = moment(date || (new Date())).tz("America/New_York").startOf("day"),
                startOfWeek = today.clone().subtract(today.weekday(), "days"),
                weekdayRange = [startOfWeek.clone().add(1, "days"), startOfWeek.clone().add(6, "days")];
                
            var holidayInWeek = null;
                
            var hasHolidayAfterMonday = _.some(holidays, function (holiday) {
                var isInWeek = holiday.isBetween(weekdayRange[0].subtract(1, "second"), weekdayRange[1].add(1, "second")) && holiday.weekday() > 1;
                if (isInWeek) {
                    holidayInWeek = holiday;
                } 
                return isInWeek;
            });
                
            var hasHolidayBeforeFriday = _.some(holidays, function (holiday) {
                var isInWeek = holiday.isBetween(weekdayRange[0].subtract(1, "second"), weekdayRange[1].add(1, "second")) && holiday.weekday() < 5;
                if (isInWeek) {
                    holidayInWeek = holiday;
                } 
                return isInWeek;
            });
            
            return hasHolidayBeforeFriday ? holidayInWeek : null;
        };

		var isRecyclingWeek = function (cycle, day) {
            var today = moment(day || (new Date())).tz("America/New_York").startOf("day"),
                startOfWeek = today.clone().subtract(today.weekday(), "days");
                
            var seedRecyclingWeek = schedules[String(cycle).toLowerCase()].start;
            
            var weeksAgo = seedRecyclingWeek.diff(startOfWeek, "weeks");
            
            var isRecycling = weeksAgo % 2 === 0;
            
            return isRecycling;
        };
        
		var getNextTwoWeeks = function (day) {
            var today = moment().tz("America/New_York").startOf("day");
            
            if (today.weekday() >= 6) {
                today = today.add(1, "days");
            }
            
            var startOfWeek = today.clone().subtract(today.weekday(), "days"),
                nextTwoWeeks = Array.apply(0, new Array(14)).map(function (o, i) {
                    try {
                        var day = startOfWeek.clone().add(i, "days"),
                            holidayInWeek = getHolidayWeekday(startOfWeek.clone().add(Math.floor(i / 7), "weeks"));
                        return {
                            day: day,
                            cycle: isRecyclingWeek("blue", day) ? "Blue" : "Yellow",
                            isHoliday: holidayInWeek !== null ? (holidayInWeek.date() === day.date()) : false,
                            holiday: _.find(Object.keys(holidays), function (name) {
                                return holidayInWeek ? (holidayInWeek.date() === holidays[name].date() && holidayInWeek.month() === holidays[name].month()) : null
                            }) || null 
                        };
                    }
                    catch (ex) {
                        console.log(ex);
                    }
                });
            
            return nextTwoWeeks;
        };
        
        var subscribe = function (data) {
            if (data.phoneNumber && data.day) {
                var notification = {
                    number: data.phoneNumber,
                    day: Number(data.day)
                };
                var value = repo.put("Notification", notification);
                return Boolean(value);
            }
            return false;
        }

		return {
            geocodeAddress: geocodeAddress,
			isHolidayWeek: isHolidayWeek,
            isRecyclingWeek: isRecyclingWeek,
            getNextTwoWeeks: getNextTwoWeeks,
            subscribe: subscribe
		};
	})();

	module.exports = service;
})();
Пример #25
0
export const getPrettyTzDate = (date, timezone = 'UTC', format = DefaultDateFormat) => (
  moment(date).tz(timezone).format(format)
);
Пример #26
0
 "MLK Jr Day": (function (year) {
         var first = new Date(year, 1, 1),
             dayOfWeek = first.getDay();
         return moment("{0}-01-{1}".format(year, 15 + (4 - dayOfWeek) % 7));
     })(year),
Пример #27
0
 it('should always cover at least 24 hours, even if there is only one point-in-time datum', function() {
   var first = fills[0], last = fills[fills.length - 1];
   expect(last.normalEnd).to.be.at.least(moment(first.normalTime).add(1, 'days').toISOString());
 });
Пример #28
0
 "Memorial Day": (function (year) {
         var first = new Date(year, 4, 1),
             dayOfWeek = first.getDay();               
         return moment("{0}-05-{1}".format(year, 25 + (12 - dayOfWeek) % 7));
     })(year),
Пример #29
0
 formattedTipOffTime = () => {
   let tipOff = moment(this.props.pool.tournament.tip_off).tz('America/New_York')
   return `${tipOff.format('dddd MMMM D, Y')} at ${tipOff.format('h:mma z')}`
 }
  $scope.refreshFocusData = function (fromDate, toDate) {

    // Counter to keep track of the queries to populate the chart.
    let awaitingCount = 4;

    // This object is used to store the results of individual remote requests
    // before we transform it into the final data and apply it to $scope. Otherwise
    // we might trigger multiple $digest cycles and depending on how deep $watches
    // listen for changes we could miss updates.
    const refreshFocusData = {};

    // finish() function, called after each data set has been loaded and processed.
    // The last one to call it will trigger the page render.
    function finish() {
      awaitingCount--;
      if (awaitingCount === 0) {
        // Tell the results container directives to render the focus chart.
        refreshFocusData.focusChartData = processDataForFocusAnomalies(
          refreshFocusData.focusChartData,
          refreshFocusData.anomalyRecords,
          $scope.timeFieldName);

        refreshFocusData.focusChartData = processScheduledEventsForChart(
          refreshFocusData.focusChartData,
          refreshFocusData.scheduledEvents);

        // All the data is ready now for a scope update.
        // Use $evalAsync to ensure the update happens after the child scope is updated with the new data.
        $scope.$evalAsync(() => {
          $scope = Object.assign($scope, refreshFocusData);
          console.log('Time series explorer focus chart data set:', $scope.focusChartData);

          $scope.loading = false;
        });
      }
    }

    const detectorIndex = +$scope.detectorId;
    const nonBlankEntities = _.filter($scope.entities, entity => entity.fieldValue.length > 0);

    // Calculate the aggregation interval for the focus chart.
    const bounds = { min: moment(fromDate), max: moment(toDate) };
    $scope.focusAggregationInterval = calculateAggregationInterval(bounds, CHARTS_POINT_TARGET, CHARTS_POINT_TARGET);

    // Ensure the search bounds align to the bucketing interval so that the first and last buckets are complete.
    // For sum or count detectors, short buckets would hold smaller values, and model bounds would also be affected
    // to some extent with all detector functions if not searching complete buckets.
    const searchBounds = getBoundsRoundedToInterval(bounds, $scope.focusAggregationInterval, false);

    // Query 1 - load metric data across selected time range.
    mlTimeSeriesSearchService.getMetricData(
      $scope.selectedJob,
      detectorIndex,
      nonBlankEntities,
      searchBounds.min.valueOf(),
      searchBounds.max.valueOf(),
      $scope.focusAggregationInterval.expression
    ).then((resp) => {
      refreshFocusData.focusChartData = processMetricPlotResults(resp.results, $scope.modelPlotEnabled);
      $scope.showModelBoundsCheckbox = ($scope.modelPlotEnabled === true) &&
        (refreshFocusData.focusChartData.length > 0);
      finish();
    }).catch((resp) => {
      console.log('Time series explorer - error getting metric data from elasticsearch:', resp);
    });

    // Query 2 - load all the records across selected time range for the chart anomaly markers.
    mlResultsService.getRecordsForCriteria(
      [$scope.selectedJob.job_id],
      $scope.criteriaFields,
      0,
      searchBounds.min.valueOf(),
      searchBounds.max.valueOf(),
      ANOMALIES_TABLE_DEFAULT_QUERY_SIZE
    ).then((resp) => {
      // Sort in descending time order before storing in scope.
      refreshFocusData.anomalyRecords = _.chain(resp.records)
        .sortBy(record => record[$scope.timeFieldName])
        .reverse()
        .value();
      console.log('Time series explorer anomalies:', refreshFocusData.anomalyRecords);
      finish();
    });

    // Query 3 - load any scheduled events for the selected job.
    mlResultsService.getScheduledEventsByBucket(
      [$scope.selectedJob.job_id],
      searchBounds.min.valueOf(),
      searchBounds.max.valueOf(),
      $scope.focusAggregationInterval.expression,
      1,
      MAX_SCHEDULED_EVENTS
    ).then((resp) => {
      refreshFocusData.scheduledEvents = resp.events[$scope.selectedJob.job_id];
      finish();
    }).catch((resp) => {
      console.log('Time series explorer - error getting scheduled events from elasticsearch:', resp);
    });

    // Query 4 - load any annotations for the selected job.
    if (mlAnnotationsEnabled) {
      ml.annotations.getAnnotations({
        jobIds: [$scope.selectedJob.job_id],
        earliestMs: searchBounds.min.valueOf(),
        latestMs: searchBounds.max.valueOf(),
        maxAnnotations: ANNOTATIONS_TABLE_DEFAULT_QUERY_SIZE
      }).then((resp) => {
        refreshFocusData.focusAnnotationData = resp.annotations[$scope.selectedJob.job_id]
          .sort((a, b) => {
            return a.timestamp - b.timestamp;
          })
          .map((d, i) => {
            d.key = String.fromCharCode(65 + i);
            return d;
          });

        finish();
      }).catch(() => {
        // silent fail
        refreshFocusData.focusAnnotationData = [];
        finish();
      });
    } else {
      finish();
    }

    // Plus query for forecast data if there is a forecastId stored in the appState.
    const forecastId = _.get($scope, 'appState.mlTimeSeriesExplorer.forecastId');
    if (forecastId !== undefined) {
      awaitingCount++;
      let aggType = undefined;
      const detector = $scope.selectedJob.analysis_config.detectors[detectorIndex];
      const esAgg = mlFunctionToESAggregation(detector.function);
      if ($scope.modelPlotEnabled === false && (esAgg === 'sum' || esAgg === 'count')) {
        aggType = { avg: 'sum', max: 'sum', min: 'sum' };
      }

      mlForecastService.getForecastData(
        $scope.selectedJob,
        detectorIndex,
        forecastId,
        nonBlankEntities,
        searchBounds.min.valueOf(),
        searchBounds.max.valueOf(),
        $scope.focusAggregationInterval.expression,
        aggType)
        .then((resp) => {
          refreshFocusData.focusForecastData = processForecastResults(resp.results);
          refreshFocusData.showForecastCheckbox = (refreshFocusData.focusForecastData.length > 0);
          finish();
        }).catch((resp) => {
          console.log(`Time series explorer - error loading data for forecast ID ${forecastId}`, resp);
        });
    }

    // Load the data for the anomalies table.
    loadAnomaliesTableData(searchBounds.min.valueOf(), searchBounds.max.valueOf());

  };