<commit_before>goog.provide('ol.control.Zoom');

goog.require('ol.event');
goog.require('ol.control.Control');

goog.require('goog.dom');

/**
 * @constructor
 * @extends {ol.control.Control}
 * @param {boolean|undefined} opt_autoActivate
 */
ol.control.Zoom = function(opt_autoActivate) {

    goog.base(this, opt_autoActivate);

    /**
     * @type {Node}
     */
    this.inButton_ = null;

    /**
     * @type {Node}
     */
    this.outButton_ = null;

    /**
     * Activate this control when it is added to a map.  Default is true.
     *
     * @type {boolean}
     */
    this.autoActivate_ =
        goog.isDef(opt_autoActivate) ? opt_autoActivate : true;

};
goog.inherits(ol.control.Zoom, ol.control.Control);

/**
 * @param {ol.Map} map
 */
ol.control.Zoom.prototype.setMap = function(map) {
    var container = goog.dom.createDom('div', ol.control.Zoom.RES.CLS);
    this.inButton_ = goog.dom.createDom(
        'div', ol.control.Zoom.RES.IN_CLS,
        goog.dom.createDom('a', {'href': '#zoomIn'})
    );
    goog.dom.setTextContent(
        /** @type {Element} */ (this.inButton_.firstChild),
        ol.control.Zoom.RES.IN_TEXT
    );
    this.outButton_ = goog.dom.createDom(
        'div', ol.control.Zoom.RES.OUT_CLS,
        goog.dom.createDom('a', {'href': '#zoomOut'})
    );
    goog.dom.setTextContent(
        /** @type {Element} */ (this.outButton_.firstChild),
        ol.control.Zoom.RES.OUT_TEXT
    );
    goog.dom.append(container, this.inButton_, this.outButton_);

    var overlay = map.getStaticOverlay();
    if (goog.isDefAndNotNull(overlay)) {
        goog.dom.append(overlay, container);
    }
    goog.base(this, 'setMap', map);
};

/** @inheritDoc */
ol.control.Zoom.prototype.activate = function() {
    var active = goog.base(this, 'activate');
    if (active) {
        goog.events.listen(this.inButton_, 'click', this.handleIn, false, this);
        goog.events.listen(this.outButton_, 'click', this.handleOut, false, this);
    }
    return active;
};

/** @inheritDoc */
ol.control.Zoom.prototype.deactivate = function() {
    var inactive = goog.base(this, 'deactivate');
    if (inactive) {
        goog.events.unlisten(this.inButton_, 'click', this.handleIn, false, this);
        goog.events.unlisten(this.outButton_, 'click', this.handleOut, false, this);
    }
    return inactive;
};

/**
 * @param {Event} evt
 */
ol.control.Zoom.prototype.handleIn = function(evt) {
    this.map_.zoomIn();
    evt.preventDefault();
    evt.stopPropagation();
};

/**
 * @param {Event} evt
 */
ol.control.Zoom.prototype.handleOut = function(evt) {
    this.map_.zoomOut();
    evt.preventDefault();
    evt.stopPropagation();
};

ol.control.Zoom.prototype.destroy = function() {
    goog.dom.removeNode(goog.dom.getElementByClass(
        ol.control.Zoom.RES.CLS,
        /** @type {Element} */ (this.map_.getStaticOverlay())
    ));
    goog.base(this, 'destroy');
};

ol.control.addControl('zoom', ol.control.Zoom);

ol.control.Zoom.RES = {
    CLS: 'ol-control-zoom',
    IN_CLS: 'ol-control-zoom-in',
    OUT_CLS: 'ol-control-zoom-out',
    IN_TEXT: '+',
    OUT_TEXT: '\u2013'
};<commit_msg>ol.control.Zoom no longer require ol.event<commit_after>goog.provide('ol.control.Zoom');

goog.require('ol.control.Control');

goog.require('goog.dom');

/**
 * @constructor
 * @extends {ol.control.Control}
 * @param {boolean|undefined} opt_autoActivate
 */
ol.control.Zoom = function(opt_autoActivate) {

    goog.base(this, opt_autoActivate);

    /**
     * @type {Node}
     */
    this.inButton_ = null;

    /**
     * @type {Node}
     */
    this.outButton_ = null;

    /**
     * Activate this control when it is added to a map.  Default is true.
     *
     * @type {boolean}
     */
    this.autoActivate_ =
        goog.isDef(opt_autoActivate) ? opt_autoActivate : true;

};
goog.inherits(ol.control.Zoom, ol.control.Control);

/**
 * @param {ol.Map} map
 */
ol.control.Zoom.prototype.setMap = function(map) {
    var container = goog.dom.createDom('div', ol.control.Zoom.RES.CLS);
    this.inButton_ = goog.dom.createDom(
        'div', ol.control.Zoom.RES.IN_CLS,
        goog.dom.createDom('a', {'href': '#zoomIn'})
    );
    goog.dom.setTextContent(
        /** @type {Element} */ (this.inButton_.firstChild),
        ol.control.Zoom.RES.IN_TEXT
    );
    this.outButton_ = goog.dom.createDom(
        'div', ol.control.Zoom.RES.OUT_CLS,
        goog.dom.createDom('a', {'href': '#zoomOut'})
    );
    goog.dom.setTextContent(
        /** @type {Element} */ (this.outButton_.firstChild),
        ol.control.Zoom.RES.OUT_TEXT
    );
    goog.dom.append(container, this.inButton_, this.outButton_);

    var overlay = map.getStaticOverlay();
    if (goog.isDefAndNotNull(overlay)) {
        goog.dom.append(overlay, container);
    }
    goog.base(this, 'setMap', map);
};

/** @inheritDoc */
ol.control.Zoom.prototype.activate = function() {
    var active = goog.base(this, 'activate');
    if (active) {
        goog.events.listen(this.inButton_, 'click', this.handleIn, false, this);
        goog.events.listen(this.outButton_, 'click', this.handleOut, false, this);
    }
    return active;
};

/** @inheritDoc */
ol.control.Zoom.prototype.deactivate = function() {
    var inactive = goog.base(this, 'deactivate');
    if (inactive) {
        goog.events.unlisten(this.inButton_, 'click', this.handleIn, false, this);
        goog.events.unlisten(this.outButton_, 'click', this.handleOut, false, this);
    }
    return inactive;
};

/**
 * @param {Event} evt
 */
ol.control.Zoom.prototype.handleIn = function(evt) {
    this.map_.zoomIn();
    evt.preventDefault();
    evt.stopPropagation();
};

/**
 * @param {Event} evt
 */
ol.control.Zoom.prototype.handleOut = function(evt) {
    this.map_.zoomOut();
    evt.preventDefault();
    evt.stopPropagation();
};

ol.control.Zoom.prototype.destroy = function() {
    goog.dom.removeNode(goog.dom.getElementByClass(
        ol.control.Zoom.RES.CLS,
        /** @type {Element} */ (this.map_.getStaticOverlay())
    ));
    goog.base(this, 'destroy');
};

ol.control.addControl('zoom', ol.control.Zoom);

ol.control.Zoom.RES = {
    CLS: 'ol-control-zoom',
    IN_CLS: 'ol-control-zoom-in',
    OUT_CLS: 'ol-control-zoom-out',
    IN_TEXT: '+',
    OUT_TEXT: '\u2013'
};
<|endoftext|>


<commit_before>// Support for focus/navigation from an external source (e.g. background script).
async function focus(hash) {
  let tab = await AsyncChrome.tabs.getCurrent();
  await AsyncChrome.tabs.update(tab.id, { active: true, highlighted: true });
  await AsyncChrome.windows.update(tab.windowId, { focused: true });
  window.location.hash = hash;
}

function isEmpty(obj) {
  for (let prop in obj) {
    if (obj.hasOwnProperty(prop)) {
      return false;
    }
  }
  return true;
}

function appendNotificationSounds(elem, sounds, selected) {
  for (let sound of sounds) {
    let option = document.createElement('option');
    option.appendChild(document.createTextNode(sound.name));
    option.dataset.file = sound.file;
    option.selected = (sound.file == selected);
    elem.appendChild(option);
  }
}

function arraysEqual(p, q) {
  p = p || [];
  q = q || [];
  return p.length === q.length
      && p.every((e, i) => e == q[i]);
}

function appendTimerSounds(elem, sounds, selected) {
  for (let sound of sounds) {
    let option = document.createElement('option');
    option.appendChild(document.createTextNode(sound.name));
    option.dataset.files = JSON.stringify(sound.files);
    option.selected = arraysEqual(sound.files, selected);
    elem.appendChild(option);
  }
}

function playSound(control) {
  if (control.selectedIndex === 0) {
    return;
  }

  let option = control.options[control.selectedIndex];
  let audio = new Audio();
  audio.src = option.dataset.file;
  audio.play();
}

async function createMetronome(soundControl, bpmControl) {
  let option = soundControl.options[soundControl.selectedIndex];
  let files = JSON.parse(option.dataset.files);
  if (!files) {
    return null;
  }

  let bpm = +bpmControl.value;
  if (isNaN(bpm) || bpm <= 0 || bpm > 1000) {
    return null;
  }

  return await Metronome.create(files, (60 / bpm) * 1000);
}

function loadSettingGroup(name, settings, notificationSounds, timerSounds) {
  let duration = document.getElementById(`${name}-duration`);
  let desktopNotification = document.getElementById(`${name}-desktop-notification`);
  let newTabNotification = document.getElementById(`${name}-new-tab-notification`);
  let soundsSelect = document.getElementById(`${name}-sounds`);

  let timerSoundSelect = document.getElementById(`${name}-timer-sounds`);
  if (timerSoundSelect != null) {
    let metronome = null;
    let timerSoundBpm = document.getElementById(`${name}-timer-sound-bpm`);
    let timerSoundPreview = document.getElementById(`${name}-timer-sound-preview`);
    let timerSoundIcon = document.querySelector(`#${name}-timer-sound-preview i`);

    const updatePreview = () => {
      if (+timerSoundBpm.value && !timerSoundBpm.disabled) {
        timerSoundPreview.style.display = null;
      } else {
        timerSoundPreview.style.display = 'none';
      }
    };

    timerSoundBpm.disabled = !settings.timerSound;
    timerSoundBpm.value = settings.timerSound ? settings.timerSound.bpm : '';
    timerSoundBpm.addEventListener('input', () => {
      updatePreview();
    });

    timerSoundSelect.addEventListener('change', () => {
      if (timerSoundBpm.value === '') {
        timerSoundBpm.value = 60;
      }
      timerSoundBpm.disabled = timerSoundSelect.selectedIndex == 0;
      if (timerSoundBpm.disabled) {
        timerSoundBpm.value = '';
      }
      updatePreview();
    });

    let mutex = new Mutex();
    timerSoundPreview.addEventListener('mouseover', async () => {
      await mutex.exclusive(async () => {
        timerSoundIcon.classList.remove('icon-play');
        timerSoundIcon.classList.add('icon-spin', 'animate-spin');
        if (metronome) {
          await metronome.close();
        }
        metronome = await createMetronome(timerSoundSelect, timerSoundBpm);
        if (metronome) {
          await metronome.start();
        }
      });
    });

    timerSoundPreview.addEventListener('mouseout', async () => {
      await mutex.exclusive(async () => {
        timerSoundIcon.classList.remove('icon-spin', 'animate-spin');
        timerSoundIcon.classList.add('icon-play');
        if (metronome) {
          await metronome.close();
        }
      });
    });

    let sounds = [{ name: T('none'), files: null }].concat(timerSounds);
    let selectedSounds = settings.timerSound ? settings.timerSound.files : null;
    appendTimerSounds(timerSoundSelect, sounds, selectedSounds);
    updatePreview();
  }

  soundsSelect.addEventListener('change', () => playSound(soundsSelect));

  duration.value = settings.duration;
  desktopNotification.checked = settings.notifications.desktop;
  newTabNotification.checked = settings.notifications.tab;

  let sounds = [{ name: T('none'), file: null }].concat(notificationSounds);
  appendNotificationSounds(soundsSelect, sounds, settings.notifications.sound);
}

async function loadSettings() {
  let settings = await BackgroundClient.getSettings();
  let notificationSounds = await BackgroundClient.getNotificationSounds();
  let timerSounds = await BackgroundClient.getTimerSounds();

  loadSettingGroup('focus', settings.focus, notificationSounds, timerSounds);
  loadSettingGroup('short-break', settings.shortBreak, notificationSounds, timerSounds);
  loadSettingGroup('long-break', settings.longBreak, notificationSounds, timerSounds);

  let longBreakInterval = document.getElementById('long-break-interval');

  let updateLongBreak = () => {
    let fields = document.getElementById('long-break');
    fields.disabled = longBreakInterval.value == 0;
  };

  longBreakInterval.value = settings.longBreak.interval;
  longBreakInterval.addEventListener('change', updateLongBreak);
  updateLongBreak();

  return settings;
}

function getSettingGroup(name) {
  let duration = document.getElementById(`${name}-duration`);
  let desktopNotification = document.getElementById(`${name}-desktop-notification`);
  let newTabNotification = document.getElementById(`${name}-new-tab-notification`);
  let notificationSounds = document.getElementById(`${name}-sounds`);
  let timerSounds = document.getElementById(`${name}-timer-sounds`);

  let soundFile = null;
  if (notificationSounds.selectedIndex > 0) {
    let option = notificationSounds.options[notificationSounds.selectedIndex];
    soundFile = option.dataset.file;
  }

  let timerSound = null;
  if (timerSounds) {
    let timerSoundBpm = document.getElementById(`${name}-timer-sound-bpm`);
    let bpm = +timerSoundBpm.value;
    if (timerSounds.selectedIndex > 0 && bpm > 0) {
      let selectedSound = timerSounds.options[timerSounds.selectedIndex];
      timerSound = {
        files: JSON.parse(selectedSound.dataset.files),
        bpm: bpm
      };
    }
  }

  return {
    duration: duration.value,
    timerSound: timerSound,
    notifications: {
      desktop: desktopNotification.checked,
      tab: newTabNotification.checked,
      sound: soundFile
    }
  };
}

async function saveSettings(settings) {
  settings.focus = getSettingGroup('focus');
  settings.shortBreak = getSettingGroup('short-break');
  settings.longBreak = getSettingGroup('long-break');

  let longBreakInterval = document.getElementById('long-break-interval');
  settings.longBreak.interval = longBreakInterval.value;

  let result = await BackgroundClient.setSettings(settings);
  if (result.error) {
    // TODO
  }
}

async function exportHistory() {
  let json = JSON.stringify(await BackgroundClient.getRawHistory());
  let link = document.createElement('a');
  link.download = 'history.json';
  link.href = 'data:application/octet-stream,' + encodeURIComponent(json);
  link.click();
}

function importHistory() {
  let input = document.createElement('input');
  input.type = 'file';
  input.accept = '.json';
  input.onchange = e => {
    let file = e.target.files[0];
    let reader = new FileReader();
    reader.onload = async f => {
      try {
        let content = f.target.result;
        let history = JSON.parse(content);

        if (!confirm(T('confirm_import'))) {
          return;
        }

        let result = await BackgroundClient.setRawHistory(history);
        if (result !== true) {
          alert(T('import_failed', `${result}`));
          return;
        }
      } catch (ex) {
        alert(T('import_failed', `${ex}`));
        return;
      }
      await loadHistory(true);
    };
    reader.readAsText(file);
  };
  input.click();
}

async function loadHistory(reload = false) {
  if (this.loaded && !reload) {
    return;
  } else {
    this.loaded = true;
  }

  let now = new Date();
  let start = new Date(now.getFullYear(), now.getMonth(), now.getDate());

  // Start at the first Sunday at least 39 weeks (~9 months) ago.
  start.setDate(start.getDate() - 273);
  start.setDate(start.getDate() - start.getDay());

  let stats = await BackgroundClient.getHistory(+start);

  for (let bucket of ['day', 'week', 'month', 'period', 'total']) {
    let stat = document.getElementById(`stat-${bucket}`);
    let count = stats[bucket];

    if (bucket === 'period') {
      stat.innerText = T('last_9_months', pomodoroCount(count));
    } else {
      stat.innerText = count.toLocaleString();
    }

    let el = document.getElementById(`average-${bucket}`);
    if (el) {
      let formatted = stats[`${bucket}Average`].toLocaleString(navigator.language, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
      el.innerText = T('average_stat', formatted);
    }
  };

  let monthEl = document.getElementById('bucket-month');
  monthEl.innerText = T('in_month', Locale.format('%B')(now));

  let daySection = document.getElementById('day-distribution-section');
  let weekSection = document.getElementById('week-distribution-section');
  let heatmapSection = document.getElementById('heatmap-section');

  let verb = (stats.pomodoros.length === 0) ? 'add' : 'remove';
  [daySection, weekSection].forEach(s => s.classList[verb]('empty'));

  createWeekDistribution('#week-distribution', stats.pomodoros);
  createOptionGroup('.day-distribution', bucket =>
    createDayDistribution('#day-distribution', bucket, stats.pomodoros)
  );

  verb = isEmpty(stats.daily) ? 'add' : 'remove';
  heatmapSection.classList[verb]('empty');

  createHeatmap(stats.daily, start, '#heatmap');
}

function createOptionGroup(selector, callback) {
  let group = document.querySelectorAll(selector);
  for (let el of group) {
    el.onclick = e => {
      for (let el of group) {
        let action = el === e.target ? 'add' : 'remove';
        el.classList[action]('active');
      }
      callback(el.dataset.value);
    };
  }

  document.querySelector(`${selector}.active`).click();
}

function selectTab(id) {
  let active = id.substring(1).toLowerCase();
  if (active === 'history') {
    loadHistory();
  }

  document.title = `${T(active)} · ${T('app_name_short')}`;

  ['settings', 'history', 'feedback'].forEach(name => {
    document.getElementById(`${name}-tab`).classList.remove('active');
    document.getElementById(`${name}-page`).classList.remove('active');
  });

  document.getElementById(`${active}-tab`).classList.add('active');
  document.getElementById(`${active}-page`).classList.add('active');

  window.requestAnimationFrame(() => window.scrollTo(0, 0));
}

async function load() {
  let settings = await loadSettings();

  let manifest = chrome.runtime.getManifest();
  let version = document.getElementById('version');
  version.innerText = manifest.version;

  let inputs = document.querySelectorAll('#settings input[type="checkbox"], #settings select');
  inputs.forEach(input => input.addEventListener('change', () => saveSettings(settings)));

  let texts = document.querySelectorAll('#settings input[type="text"]');
  texts.forEach(text => text.addEventListener('input', () => saveSettings(settings)));

  let hash = window.location.hash || '#settings';
  selectTab(hash);

  document.getElementById('export-history').onclick = exportHistory;
  document.getElementById('import-history').onclick = importHistory;

  window.addEventListener('popstate', function(e) {
    selectTab(window.location.hash);
  });
}

document.addEventListener('DOMContentLoaded', load);
<commit_msg>Automatically reload metronome preview when settings change.<commit_after>// Support for focus/navigation from an external source (e.g. background script).
async function focus(hash) {
  let tab = await AsyncChrome.tabs.getCurrent();
  await AsyncChrome.tabs.update(tab.id, { active: true, highlighted: true });
  await AsyncChrome.windows.update(tab.windowId, { focused: true });
  window.location.hash = hash;
}

function isEmpty(obj) {
  for (let prop in obj) {
    if (obj.hasOwnProperty(prop)) {
      return false;
    }
  }
  return true;
}

function appendNotificationSounds(elem, sounds, selected) {
  for (let sound of sounds) {
    let option = document.createElement('option');
    option.appendChild(document.createTextNode(sound.name));
    option.dataset.file = sound.file;
    option.selected = (sound.file == selected);
    elem.appendChild(option);
  }
}

function arraysEqual(p, q) {
  p = p || [];
  q = q || [];
  return p.length === q.length
      && p.every((e, i) => e == q[i]);
}

function appendTimerSounds(elem, sounds, selected) {
  for (let sound of sounds) {
    let option = document.createElement('option');
    option.appendChild(document.createTextNode(sound.name));
    option.dataset.files = JSON.stringify(sound.files);
    option.selected = arraysEqual(sound.files, selected);
    elem.appendChild(option);
  }
}

function playSound(control) {
  if (control.selectedIndex === 0) {
    return;
  }

  let option = control.options[control.selectedIndex];
  let audio = new Audio();
  audio.src = option.dataset.file;
  audio.play();
}

async function createMetronome(soundControl, bpmControl) {
  let option = soundControl.options[soundControl.selectedIndex];
  let files = JSON.parse(option.dataset.files);
  if (!files) {
    return null;
  }

  let bpm = +bpmControl.value;
  if (isNaN(bpm) || bpm <= 0 || bpm > 1000) {
    return null;
  }

  return await Metronome.create(files, (60 / bpm) * 1000);
}

function loadSettingGroup(name, settings, notificationSounds, timerSounds) {
  let duration = document.getElementById(`${name}-duration`);
  let desktopNotification = document.getElementById(`${name}-desktop-notification`);
  let newTabNotification = document.getElementById(`${name}-new-tab-notification`);
  let soundsSelect = document.getElementById(`${name}-sounds`);

  let timerSoundSelect = document.getElementById(`${name}-timer-sounds`);
  if (timerSoundSelect != null) {
    let metronome = null;
    let timerSoundBpm = document.getElementById(`${name}-timer-sound-bpm`);
    let timerSoundPreview = document.getElementById(`${name}-timer-sound-preview`);
    let timerSoundIcon = document.querySelector(`#${name}-timer-sound-preview i`);

    const updatePreview = () => {
      if (+timerSoundBpm.value && !timerSoundBpm.disabled) {
        timerSoundPreview.style.display = null;
      } else {
        timerSoundPreview.style.display = 'none';
      }
    };

    const reloadMetronome = async () => {
      if (metronome) {
        await metronome.close();
      }
      metronome = await createMetronome(timerSoundSelect, timerSoundBpm);
      if (metronome) {
        await metronome.start();
      }
    };

    timerSoundBpm.disabled = !settings.timerSound;
    timerSoundBpm.value = settings.timerSound ? settings.timerSound.bpm : '';
    timerSoundBpm.addEventListener('input', async () => {
      await mutex.exclusive(async () => {
        updatePreview();
        await reloadMetronome();
      });
    });

    timerSoundSelect.addEventListener('change', async () => {
      await mutex.exclusive(async () => {
        if (timerSoundBpm.value === '') {
          timerSoundBpm.value = 60;
        }
        timerSoundBpm.disabled = timerSoundSelect.selectedIndex == 0;
        if (timerSoundBpm.disabled) {
          timerSoundBpm.value = '';
        }
        updatePreview();
        await reloadMetronome();
      });
    });

    let mutex = new Mutex();
    timerSoundPreview.addEventListener('mouseover', async () => {
      await mutex.exclusive(async () => {
        timerSoundIcon.classList.remove('icon-play');
        timerSoundIcon.classList.add('icon-spin', 'animate-spin');
        await reloadMetronome();
      });
    });

    timerSoundPreview.addEventListener('mouseout', async () => {
      await mutex.exclusive(async () => {
        timerSoundIcon.classList.remove('icon-spin', 'animate-spin');
        timerSoundIcon.classList.add('icon-play');
        if (metronome) {
          await metronome.close();
        }
      });
    });

    let sounds = [{ name: T('none'), files: null }].concat(timerSounds);
    let selectedSounds = settings.timerSound ? settings.timerSound.files : null;
    appendTimerSounds(timerSoundSelect, sounds, selectedSounds);
    updatePreview();
  }

  soundsSelect.addEventListener('change', () => playSound(soundsSelect));

  duration.value = settings.duration;
  desktopNotification.checked = settings.notifications.desktop;
  newTabNotification.checked = settings.notifications.tab;

  let sounds = [{ name: T('none'), file: null }].concat(notificationSounds);
  appendNotificationSounds(soundsSelect, sounds, settings.notifications.sound);
}

async function loadSettings() {
  let settings = await BackgroundClient.getSettings();
  let notificationSounds = await BackgroundClient.getNotificationSounds();
  let timerSounds = await BackgroundClient.getTimerSounds();

  loadSettingGroup('focus', settings.focus, notificationSounds, timerSounds);
  loadSettingGroup('short-break', settings.shortBreak, notificationSounds, timerSounds);
  loadSettingGroup('long-break', settings.longBreak, notificationSounds, timerSounds);

  let longBreakInterval = document.getElementById('long-break-interval');

  let updateLongBreak = () => {
    let fields = document.getElementById('long-break');
    fields.disabled = longBreakInterval.value == 0;
  };

  longBreakInterval.value = settings.longBreak.interval;
  longBreakInterval.addEventListener('change', updateLongBreak);
  updateLongBreak();

  return settings;
}

function getSettingGroup(name) {
  let duration = document.getElementById(`${name}-duration`);
  let desktopNotification = document.getElementById(`${name}-desktop-notification`);
  let newTabNotification = document.getElementById(`${name}-new-tab-notification`);
  let notificationSounds = document.getElementById(`${name}-sounds`);
  let timerSounds = document.getElementById(`${name}-timer-sounds`);

  let soundFile = null;
  if (notificationSounds.selectedIndex > 0) {
    let option = notificationSounds.options[notificationSounds.selectedIndex];
    soundFile = option.dataset.file;
  }

  let timerSound = null;
  if (timerSounds) {
    let timerSoundBpm = document.getElementById(`${name}-timer-sound-bpm`);
    let bpm = +timerSoundBpm.value;
    if (timerSounds.selectedIndex > 0 && bpm > 0) {
      let selectedSound = timerSounds.options[timerSounds.selectedIndex];
      timerSound = {
        files: JSON.parse(selectedSound.dataset.files),
        bpm: bpm
      };
    }
  }

  return {
    duration: duration.value,
    timerSound: timerSound,
    notifications: {
      desktop: desktopNotification.checked,
      tab: newTabNotification.checked,
      sound: soundFile
    }
  };
}

async function saveSettings(settings) {
  settings.focus = getSettingGroup('focus');
  settings.shortBreak = getSettingGroup('short-break');
  settings.longBreak = getSettingGroup('long-break');

  let longBreakInterval = document.getElementById('long-break-interval');
  settings.longBreak.interval = longBreakInterval.value;

  let result = await BackgroundClient.setSettings(settings);
  if (result.error) {
    // TODO
  }
}

async function exportHistory() {
  let json = JSON.stringify(await BackgroundClient.getRawHistory());
  let link = document.createElement('a');
  link.download = 'history.json';
  link.href = 'data:application/octet-stream,' + encodeURIComponent(json);
  link.click();
}

function importHistory() {
  let input = document.createElement('input');
  input.type = 'file';
  input.accept = '.json';
  input.onchange = e => {
    let file = e.target.files[0];
    let reader = new FileReader();
    reader.onload = async f => {
      try {
        let content = f.target.result;
        let history = JSON.parse(content);

        if (!confirm(T('confirm_import'))) {
          return;
        }

        let result = await BackgroundClient.setRawHistory(history);
        if (result !== true) {
          alert(T('import_failed', `${result}`));
          return;
        }
      } catch (ex) {
        alert(T('import_failed', `${ex}`));
        return;
      }
      await loadHistory(true);
    };
    reader.readAsText(file);
  };
  input.click();
}

async function loadHistory(reload = false) {
  if (this.loaded && !reload) {
    return;
  } else {
    this.loaded = true;
  }

  let now = new Date();
  let start = new Date(now.getFullYear(), now.getMonth(), now.getDate());

  // Start at the first Sunday at least 39 weeks (~9 months) ago.
  start.setDate(start.getDate() - 273);
  start.setDate(start.getDate() - start.getDay());

  let stats = await BackgroundClient.getHistory(+start);

  for (let bucket of ['day', 'week', 'month', 'period', 'total']) {
    let stat = document.getElementById(`stat-${bucket}`);
    let count = stats[bucket];

    if (bucket === 'period') {
      stat.innerText = T('last_9_months', pomodoroCount(count));
    } else {
      stat.innerText = count.toLocaleString();
    }

    let el = document.getElementById(`average-${bucket}`);
    if (el) {
      let formatted = stats[`${bucket}Average`].toLocaleString(navigator.language, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
      el.innerText = T('average_stat', formatted);
    }
  };

  let monthEl = document.getElementById('bucket-month');
  monthEl.innerText = T('in_month', Locale.format('%B')(now));

  let daySection = document.getElementById('day-distribution-section');
  let weekSection = document.getElementById('week-distribution-section');
  let heatmapSection = document.getElementById('heatmap-section');

  let verb = (stats.pomodoros.length === 0) ? 'add' : 'remove';
  [daySection, weekSection].forEach(s => s.classList[verb]('empty'));

  createWeekDistribution('#week-distribution', stats.pomodoros);
  createOptionGroup('.day-distribution', bucket =>
    createDayDistribution('#day-distribution', bucket, stats.pomodoros)
  );

  verb = isEmpty(stats.daily) ? 'add' : 'remove';
  heatmapSection.classList[verb]('empty');

  createHeatmap(stats.daily, start, '#heatmap');
}

function createOptionGroup(selector, callback) {
  let group = document.querySelectorAll(selector);
  for (let el of group) {
    el.onclick = e => {
      for (let el of group) {
        let action = el === e.target ? 'add' : 'remove';
        el.classList[action]('active');
      }
      callback(el.dataset.value);
    };
  }

  document.querySelector(`${selector}.active`).click();
}

function selectTab(id) {
  let active = id.substring(1).toLowerCase();
  if (active === 'history') {
    loadHistory();
  }

  document.title = `${T(active)} · ${T('app_name_short')}`;

  ['settings', 'history', 'feedback'].forEach(name => {
    document.getElementById(`${name}-tab`).classList.remove('active');
    document.getElementById(`${name}-page`).classList.remove('active');
  });

  document.getElementById(`${active}-tab`).classList.add('active');
  document.getElementById(`${active}-page`).classList.add('active');

  window.requestAnimationFrame(() => window.scrollTo(0, 0));
}

async function load() {
  let settings = await loadSettings();

  let manifest = chrome.runtime.getManifest();
  let version = document.getElementById('version');
  version.innerText = manifest.version;

  let inputs = document.querySelectorAll('#settings input[type="checkbox"], #settings select');
  inputs.forEach(input => input.addEventListener('change', () => saveSettings(settings)));

  let texts = document.querySelectorAll('#settings input[type="text"]');
  texts.forEach(text => text.addEventListener('input', () => saveSettings(settings)));

  let hash = window.location.hash || '#settings';
  selectTab(hash);

  document.getElementById('export-history').onclick = exportHistory;
  document.getElementById('import-history').onclick = importHistory;

  window.addEventListener('popstate', function(e) {
    selectTab(window.location.hash);
  });
}

document.addEventListener('DOMContentLoaded', load);
<|endoftext|>


<commit_before>'use strict';

const stripJs = require('strip-js');
const globalHooks = require('../../../hooks');
const hooks = require('feathers-hooks');
const auth = require('feathers-authentication');

const getAverageRating = function(submissions,gradeSystem){
    // Durchschnittsnote berechnen
    if (submissions.length > 0) {
        // Nur bewertete Abgaben einbeziehen
        let submissiongrades = submissions.filter(function(sub){return Number.isInteger(sub.grade);});
        // Abgaben vorhanden?
        if(submissiongrades.length > 0){
            // Noten aus Abgabe auslesen
            submissiongrades = submissiongrades.map(function (sub) {
                return sub.grade;
            });
            // Durchschnittsnote berechnen
            const ratingsum = submissiongrades.reduce(function(a, b) { return a + b; }, 0);
            return (ratingsum / submissiongrades.length).toFixed(2);
        }
    }
    return undefined;
};

const filterApplicableHomework = hook => {
    let data = hook.result.data || hook.result;
    data = data.filter(function (c) {
        return (new Date(c.availableDate).getTime() < Date.now()
            && c.courseId != null
            && ((c.courseId.userIds || []).indexOf(hook.params.account.userId) != -1) && !c.private)
          || JSON.stringify(c.teacherId) == JSON.stringify(hook.params.account.userId);
    });
    return Promise.resolve(hook);
};

const addStats = hook => {
    let data = hook.result.data || hook.result;
    const submissionService = hook.app.service('/submissions');
    return submissionService.find({query: {
            homeworkId: {$in: data.map(function(n){
                return n._id;
            })}
        }}).then((submissions) => {
            data = data.map(function(e){
                var c = JSON.parse(JSON.stringify(e)) // don't know why, but without this line it's not working :/
                c.stats = {
                    userCount: c.courseId.userIds.length,
                    submissionCount: submissions.data.filter(function(n){return JSON.stringify(c._id) == JSON.stringify(n.homeworkId)
                        && n.comment != undefined && n.comment != ""}).length,
                    submissionPercentage: submissions.data.filter(function(n){return JSON.stringify(c._id) == JSON.stringify(n.homeworkId)
                        && n.comment != undefined && n.comment != ""}).length/c.courseId.userIds.length,
                    gradeCount: submissions.data.filter(function(n){return JSON.stringify(c._id) == JSON.stringify(n.homeworkId)
                        && n.gradeComment != '' && Number.isInteger(n.grade)}).length,
                    gradePercentage: submissions.data.filter(function(n){return JSON.stringify(c._id) == JSON.stringify(n.homeworkId)
                        && n.gradeComment != '' && Number.isInteger(n.grade)}).length/c.courseId.userIds.length,
                    averageGrade: getAverageRating(submissions.data, c.courseId.gradeSystem)
                };
                return c;
            });
            (hook.result.data)?(hook.result.data = data):(hook.result = data);
    });
}

exports.before = {
    all: [auth.hooks.authenticate('jwt'), (hook) => {
        if (hook.data && hook.data.description) {
            hook.data.description = stripJs(hook.data.description);
        }

        return hook;
    }],
    find: [globalHooks.mapPaginationQuery.bind(this)],
    get: [],
    create: [],
    update: [],
    patch: [],
    remove: []
};

exports.after = {
  all: [],
  find: [filterApplicableHomework, addStats],
  get: [],
  create: [],
  update: [],
  patch: [],
  remove: []
};
<commit_msg>percentage = 0-100 and not 0-1 :white_check_mark:<commit_after>'use strict';

const stripJs = require('strip-js');
const globalHooks = require('../../../hooks');
const hooks = require('feathers-hooks');
const auth = require('feathers-authentication');

const getAverageRating = function(submissions,gradeSystem){
    // Durchschnittsnote berechnen
    if (submissions.length > 0) {
        // Nur bewertete Abgaben einbeziehen
        let submissiongrades = submissions.filter(function(sub){return Number.isInteger(sub.grade);});
        // Abgaben vorhanden?
        if(submissiongrades.length > 0){
            // Noten aus Abgabe auslesen
            submissiongrades = submissiongrades.map(function (sub) {
                return sub.grade;
            });
            // Durchschnittsnote berechnen
            const ratingsum = submissiongrades.reduce(function(a, b) { return a + b; }, 0);
            return (ratingsum / submissiongrades.length).toFixed(2);
        }
    }
    return undefined;
};

const filterApplicableHomework = hook => {
    let data = hook.result.data || hook.result;
    data = data.filter(function (c) {
        return (new Date(c.availableDate).getTime() < Date.now()
            && c.courseId != null
            && ((c.courseId.userIds || []).indexOf(hook.params.account.userId) != -1) && !c.private)
          || JSON.stringify(c.teacherId) == JSON.stringify(hook.params.account.userId);
    });
    return Promise.resolve(hook);
};

const addStats = hook => {
    let data = hook.result.data || hook.result;
    const submissionService = hook.app.service('/submissions');
    return submissionService.find({query: {
            homeworkId: {$in: data.map(function(n){
                return n._id;
            })}
        }}).then((submissions) => {
            data = data.map(function(e){
                var c = JSON.parse(JSON.stringify(e)) // don't know why, but without this line it's not working :/
                c.stats = {
                    userCount: c.courseId.userIds.length,
                    submissionCount: submissions.data.filter(function(n){return JSON.stringify(c._id) == JSON.stringify(n.homeworkId)
                        && n.comment != undefined && n.comment != ""}).length,
                    submissionPercentage: (submissions.data.filter(function(n){return JSON.stringify(c._id) == JSON.stringify(n.homeworkId)
                        && n.comment != undefined && n.comment != ""}).length/c.courseId.userIds.length)*100,
                    gradeCount: submissions.data.filter(function(n){return JSON.stringify(c._id) == JSON.stringify(n.homeworkId)
                        && n.gradeComment != '' && Number.isInteger(n.grade)}).length,
                    gradePercentage: (submissions.data.filter(function(n){return JSON.stringify(c._id) == JSON.stringify(n.homeworkId)
                        && n.gradeComment != '' && Number.isInteger(n.grade)}).length/c.courseId.userIds.length)*100,
                    averageGrade: getAverageRating(submissions.data, c.courseId.gradeSystem)
                };
                return c;
            });
            (hook.result.data)?(hook.result.data = data):(hook.result = data);
    });
}

exports.before = {
    all: [auth.hooks.authenticate('jwt'), (hook) => {
        if (hook.data && hook.data.description) {
            hook.data.description = stripJs(hook.data.description);
        }

        return hook;
    }],
    find: [globalHooks.mapPaginationQuery.bind(this)],
    get: [],
    create: [],
    update: [],
    patch: [],
    remove: []
};

exports.after = {
  all: [],
  find: [filterApplicableHomework, addStats],
  get: [],
  create: [],
  update: [],
  patch: [],
  remove: []
};
<|endoftext|>


<commit_before>/**
 * @overview NotificationFactory
 * @ngdoc service
 *
 * @description a factory service that provide a service to construct
 * new Notification. The Notification object is used to configure and
 * display desktop notifications to the user. So, after we construct the
 * Notification, the notification dialog will show up.
 */
angular.module('ng-kabam-notification')
  .factory('NotificationFactory', ['$window',
    function($window) {
      return {
        createNotification: function(options) {
          if (options.notificationType === 'broadcast') {
            new Notification('Broadcast', {
              body: options.data.message
            });
          } else if (options.notificationType === 'notify' &&
            options.data.type && options.data.type === 'default') {

            // required data payload structures
            // {
            //   user: {
            //     username: 'user2'
            //   },
            //   message: {
            //     from: 'user1',
            //     text: 'Hi'
            //   },
            //   type: 'default'
            // }
            new Notification('Notification from ' + options.data.message.from, {
              body: options.data.message.text
            });
          } else if (options.notificationType === 'notify' &&
            options.data.type && options.data.type === 'call') {
            // required data payload structures
            // user: {
            //   username: 'callee'
            // },
            // message: {
            //   callee: 'callee',
            //   caller: 'caller',
            //   roomId: '34e971f0-7b67-4506-8f96-9855163477fc'
            // },
            // type: 'call'
            var callNotification = new Notification('You got call!', {
              body: options.data.message.caller + ' is calling. Click this notification to accept'
            });

            // when the notification window clicked then redirect to room view
            callNotification.addEventListener('click', function() {
              $window.open('/home#/call/room/' + options.data.message.roomId,
                '_self');
              // $window.open('/', '_self');
              callNotification.close();
            });

          }
        }
      };
    }
  ]);<commit_msg>chore(*): remove dead codes<commit_after>/**
 * @overview NotificationFactory
 * @ngdoc service
 *
 * @description a factory service that provide a service to construct
 * new Notification. The Notification object is used to configure and
 * display desktop notifications to the user. So, after we construct the
 * Notification, the notification dialog will show up.
 */
angular.module('ng-kabam-notification')
  .factory('NotificationFactory', ['$window',
    function($window) {
      return {
        createNotification: function(options) {
          if (options.notificationType === 'broadcast') {
            new Notification('Broadcast', {
              body: options.data.message
            });
          } else if (options.notificationType === 'notify' &&
            options.data.type && options.data.type === 'default') {

            // required data payload structures
            // {
            //   user: {
            //     username: 'user2'
            //   },
            //   message: {
            //     from: 'user1',
            //     text: 'Hi'
            //   },
            //   type: 'default'
            // }
            new Notification('Notification from ' + options.data.message.from, {
              body: options.data.message.text
            });
          } else if (options.notificationType === 'notify' &&
            options.data.type && options.data.type === 'call') {
            // required data payload structures
            // user: {
            //   username: 'callee'
            // },
            // message: {
            //   callee: 'callee',
            //   caller: 'caller',
            //   roomId: '34e971f0-7b67-4506-8f96-9855163477fc'
            // },
            // type: 'call'
            var callNotification = new Notification('You got call!', {
              body: options.data.message.caller + ' is calling. Click this notification to accept'
            });

            // when the notification window clicked then redirect to room view
            callNotification.addEventListener('click', function() {
              $window.open('/home#/call/room/' + options.data.message.roomId,
                '_self');
              callNotification.close();
            });

          }
        }
      };
    }
  ]);<|endoftext|>


<commit_before>'use strict';
var config = require('../../configs');

var http = require('http');

/**
 *The AlexaSkill Module that has the AlexaSkill prototype and helper functions
 */

var apiKey=config.getAPIKey();
var i=0,j=0;
/**
 * This function will return the train status as a string.
 * Sample output : Train departed from KARUKKUTTY(KUC) and late by 24 minutes.
 */
exports.getJsonLiveStatus= function (train_no,doj,eventCallback){

    var url =config.getBaseUrl()+"live/train/"+train_no+"/doj/"+doj+"/apikey/"+apiKey+"/";
    var state="";
    var status= "";
    http.get(url, function(res) {
        var body = '';

        res.on('data', function (chunk) {
            body += chunk;
        });

        res.on('end', function () {
            var stringResult = JSON.parse(body);
            var status=stringResult.position;
            if(stringResult.response_code!='200')
                    status="There was an error processing your request.";
            var result={speech:status,status:stringResult.position,heading:'Train Number: '+train_no};
            eventCallback(result);

        });
    }).on('error', function (e) {
        console.log("Got error: ", e);
        status= "Sorry, we could not process your request.";

        var result={speech:status,status:status,heading:null};
        eventCallback(result);
    });
   return status;
}

/**
 * This function will return the stations in a route as a string.
 * Sample output : KANYAKUMARI,Source,14:10,1,  NAGARCOIL JN,14:30,14:35,1,  KULITTHURAI,15:14,15:15,1,  TRIVANDRUM CNTL,15:55,16:00,1,  KOLLAM JN,17:00,17:05,1,  KAYANKULAM,17:34,17:36,1 (Station     **name,Arriavl time,Departure time,Day of arrival.)
 */
exports.getJsonTrainRoute=function (train_no,eventCallback){

    var url =config.getBaseUrl()+'route/train/'+train_no+'/apikey/'+ apiKey+'/';
       var station_string="";
    var state = "";
    http.get(url, function(res) {
        var body = '';

        res.on('data', function (chunk) {
            body += chunk;
        });

        res.on('end', function () {
            var stringResult = JSON.parse(body);
            var station_names=[];
            var station_arrival=[];
            var station_dep=[];
            var day=[];
            for (i=0; i<stringResult.route.length; i++){
                station_names[i]=stringResult.route[i].fullname;
                station_arrival[i]=stringResult.route[i].scharr;
                station_dep[i]=stringResult.route[i].schdep;
                day[i]=stringResult.route[i].day;
                }
             var m=0;
             var update=Math.ceil(((stringResult.route.length-2)/5));
             var source_=station_names[0];
             var dest_=station_names[i-1];

             station_string=station_string+"The train starts from "+source_+" at "+station_dep[0]+" and arrives  "+dest_+" at "+station_arrival[i-1]+" on day "+day[i-1]+" passing through ";
            for (j=0; j<i-1; j=j+update){
               m=j+1;
              if((j+update)<(i-1))
                 station_string=station_string+station_names[j]+",";
                else
                 station_string=station_string+" and "+station_names[j]+".";
               }
               if(stringResult.response_code!='200')
                    station_string="There was an error processing your request.";
            var result={speech:station_string,status:station_string,heading:"Route of Train Number: "+train_no};
            eventCallback(result);

        });
    }).on('error', function (e) {
        console.log("Got error: ", e);
        status= "Sorry, we could not process your request.";
        var result={speech:status,status:status,heading:null};
        eventCallback(result);
    });
}

/**
 * This function will return the seat availability as string.
 * Sample output : AVAILABLE 11

*/
exports.getJsonSeatAvailability = function (train_no, source, dest, date, _class, quota,eventCallback){
    var url =config.getBaseUrl() +'/check_seat/train/'+train_no+'/source/'+ source +'/dest/'+dest+'/date/'+ date+'/class/'+_class+'/quota/'+quota+'/apikey/'+ apiKey+'/';
    var status = "";
      http.get(url, function(res) {
        var body = '';

        res.on('data', function (chunk) {
            body += chunk;
        });

        res.on('end', function () {
            var stringResult = JSON.parse(body);
            var index3=0;
            var index4=0;
            var status=stringResult.availability[0].status;
            if(status.indexOf('AVAILABLE')>-1)
            {
                var index_=status.indexOf('AVAILABLE');
                var available=status.substring(index_+10);
            }
            status=available+" seats are available.";
            if(status.charAt(0)=='G'&&status.charAt(1)=='N'&&status.charAt(2)=='W')
               {
                 index3=status.indexOf("/WL");
                 index4=status.indexOf("\n",index3);
                 var waiting=status.substring(index3+3,index3+8);
                 var status=waiting+" seats are in waiting list.";
                }
                if(stringResult.response_code!='200')
                    status="There was an error processing your request.";
             var result={speech:status,status:status,heading:"Seat availability of Train: "+train_no};
             eventCallback(result);
        });
    }).on('error', function (e) {
             var result={speech:"Sorry, we could not process your request.",status:"Sorry, we could not process your request.",heading:null};
             eventCallback(result);
    });
}

/**
 * This function will return the train numbers of trains between stations as a string.
 * Sample output : 12617  16382  16346  19577  16334

*/
exports.getJsonTrainBtw =function (source, dest, date, eventCallback){
         var mon= date.substring(5,7);
         var day= date.substring(8);
         date=day+"-"+mon;
         var url=config.getBaseUrl()+"between/source/"+source+"/dest/"+dest+"/date/"+date+"/apikey/"+apiKey+"/";
         var stat="";
         var train_string="";
        http.get(url, function(res) {
        var body = '';

        res.on('data', function (chunk) {
            body += chunk;
        });

        res.on('end', function () {
            var stringResult = JSON.parse(body);
            var train_no=[];
            var src_departure_time=[];
            var dest_arrival_time=[];
            var days=[];
            var index=0;
            for(i=0; i<stringResult["train"].length; i++){
                days[i]="";
                train_no[i]=stringResult["train"][i].number;
                src_departure_time[i]=stringResult["train"][i].src_departure_time;
                dest_arrival_time[i]=stringResult["train"][i].dest_arrival_time;
                for  (j=0; j<stringResult["train"][i]["days"].length; j++){
                        if(stringResult["train"][i]["days"][j].runs==="Y")
                          {
                            switch(j){
                               case 0: days[i]=days[i]+"monday, ";
                                       break;
                               case 1: days[i]=days[i]+"tuesday, ";
                                       break;
                               case 2: days[i]=days[i]+"wednesday, ";
                                       break;
                               case 3: days[i]=days[i]+"thursday, ";
                                       break;
                               case 4: days[i]=days[i]+"friday, ";
                                       break;
                               case 5: days[i]=days[i]+"saturday, ";
                                       break;
                               case 6: days[i]=days[i]+"sunday, ";
                                       break;
                              }
                            }
                     }
              }
             stat= stat+ "Total "+i+" trains are there.";
             var m=0;
            for (j=0; j<i; j++){
               m=j+1;
               if(m<=3)
                 {
                  stat = stat + "Train "+m+ '.';
                   stat = stat+" Source departure time :"+src_departure_time[j]+", Destination arrival time "+dest_arrival_time[j]+", Days of run "+days[j]+".";
                   }
               train_string = train_string + "Train "+m+ '\n';
               train_string =train_string+" Source departure time :"+src_departure_time[j]+"\n Destination arrival time "+dest_arrival_time[j]+"\n Days of run "+days[j]+"\n";

               }

               if(stringResult.response_code!='200'){
                    train_string="There was an error processing your request.";
                     stat=train	_string;
                   }
             stat=stat+ "For details of all other trains see the result card."
             var result={speech:stat,status:train_string,heading:"Trains running between "+source+" and "+dest};
             eventCallback(result);

        });
    }).on('error', function (e) {
        console.log("Got error: ", e);
        train_string = "sorry, we could not process your request.";
        var result={speech:train_string,status:train_string,heading:null};
        eventCallback(result);
    });
}

exports.getJsonPNRstatus=function (pnr_no, eventCallback){
    var result="";
    var stat="";
      var train_name="Hi";
     var url =config.getBaseUrl() +'pnr_status/pnr/'+pnr_no+'/apikey/'+ apiKey+'/';
    http.get(url, function(res) {
        var body = '';

        res.on('data', function (chunk) {
            body += chunk;
        });

        res.on('end', function () {
           var train_no;
            var doj="";
            var Class="";
            var chart_prepared="";
            var total_passengers;
            var booking_status=[];
            var current_status=[];
            var coach_position =[];
            var stringResult = JSON.parse(body);
             var c="";
            train_no= stringResult.train_no;
            doj= stringResult.doj;
            Class= stringResult.class;
            chart_prepared= stringResult.chart_prepared;
            total_passengers= stringResult.total_passengers;
           result= result+"Starting date is "+doj+"\n Class is "+Class+"\n Chart prepared "+chart_prepared+"\n Total number of passengers "+total_passengers+"\n Details of each passengers\n";
           result= result+"Starting date is "+doj+". Class is "+Class+". Chart prepared "+chart_prepared+". Total number of passengers "+total_passengers+". Details of each passengers.";

            for ( i=0; i<stringResult["passengers"].length; i++){
               booking_status[i]=stringResult["passengers"][i].booking_status;
               current_status[i]=stringResult["passengers"][i].current_status;
               coach_position[i]=stringResult["passengers"][i].coach_position;

              }
             var m=0;
            for (j=0; j<i; j++){
               m=j+1;
               result = result + "passenger "+m+ '\n';
               result=result+" Booking status "+booking_status[j]+"\n Current status "+current_status[j]+"\n Coach position "+coach_position[j]+"\n";
               if(current_status[j]==="CAN/MOD")
                  current_status[j]="cancelled or modified.";
              if(current_status[j]==="CNF/Confirmed")
                  {
                    if(chart_prepared==="Y")
                      {
                        c=current_status[j];
                        current_status[j]= "confirmed, coach and berth position is "+ c+".";
                       }
                     else
                           current_status[j]="confirmed, Coach/Berth number will be available after chart preparation.";
                  }
               stat=stat+" passenger "+m+", current status is "+current_status[j]+".";
               }

               stat=stat+" For further details see the result card.";
                if(stringResult.response_code=='410'){
                    result="PNR does not exist.";
                    stat=result;
                   }
            var result1={speech:stat,status:result,heading:"PNR status of: "+pnr_no};

            eventCallback(result1);

        });
    }).on('error', function (e) {
        console.log("Got error: ", e);
         result = "sorry, we could not process your request.";
        var result1={speech:result,status:result,heading:null};
        eventCallback(result1);
    });
}

exports.getJsonTrainArrivals=function (station_code,hrs, eventCallback){
    var result="";
    var url =config.getBaseUrl() +'arrivals/station/'+station_code+'/hours/'+hrs+'/apikey/'+ apiKey+'/';

    http.get(url, function(res) {
        var body = '';

        res.on('data', function (chunk) {
            body += chunk;
        });

        res.on('end', function () {
           var train_no=[];
            var actdep=[];
            var delaydep=[];
            var scharr=[];
            var delayarr=[];
            var schdep =[];
            var stringResult = JSON.parse(body);
             for (i=0; i<stringResult["train"].length; i++){
                train_no[i]=stringResult["train"][i].number;
                scharr[i]=stringResult["train"][i].scharr;
                delayarr[i]=stringResult["train"][i].delayarr;
                schdep[i]=stringResult["train"][i].schdep;
                actdep[i]=stringResult["train"][i].actdep;
                delaydep[i]=stringResult["train"][i].delaydep;

              }
             var m=0;
            for ( j=0; j<i; j++){
               m=j+1;
               result = result + "Train "+m+ '.';
               result=result+", Scheduled arrival "+scharr[j]+", Delayed arrival "+delayarr[j]+", Scheduled departure "+schdep[j]+", actual departure "+actdep[j]+", delayed departure "+delaydep[j]+".";

               }
               if(stringResult.response_code!='200')
                    result="There was an error processing your request.";
            var result1={speech:result,status:result,heading:"Train arrivals at station: "+station_code};
            eventCallback(result1);

        });
    }).on('error', function (e) {
        console.log("Got error: ", e);
         result = "sorry, we could not process your request.";
         var result1={speech:result,status:result,heading:null};
         eventCallback(result1);
    });
}

/*exports.getJsonTrainName = function (train_no){
    var state="";
    var result="";
    var url =baseUrl +'/name_number/train/'+train_no+'/apikey/'+ apikey+'/';
    http.get(url, function(res) {
        var body = '';

        res.on('data', function (chunk) {
            body += chunk;
        });

        res.on('end', function () {
            var stringResult = JSON.stringify(body);
            var index=0;
            var index2=0
            var train_numbers=[];
            var train_string="";
            var index=stringResult.indexOf("name")
            var index1=stringResult.indexOf("}",index)
            var name =stringResult.substring(index+10,index1-8);
            result=name;
            if(stringResult.indexOf("error") > -1) {
                 state = "error";
                }
            else
                 state = "success";

        });
    }).on('error', function (e) {
        state = "error";
    });
}

function numberToName(train_no,eventCallback){
    var baseURL="http://api.railwayapi.com";
    var apiKey="bkxel1825";
    var state="";
    var result="";
    var url =baseURL +'/name_number/train/'+train_no+'/apikey/'+ apiKey+'/';
    http.get(url, function(res) {
        var body = '';

        res.on('data', function (chunk) {
            body += chunk;
        });

        res.on('end', function () {
            var stringResult = JSON.parse(body);
            eventCallback(stringResult.train.name);

        });
    }).on('error', function (e) {
        state = "error";
    });
}
*/

<commit_msg>Minor bugfix. -Snippy<commit_after>'use strict';
var config = require('../../configs');

var http = require('http');

/**
 *The AlexaSkill Module that has the AlexaSkill prototype and helper functions
 */

var apiKey=config.getAPIKey();
var i=0,j=0;
/**
 * This function will return the train status as a string.
 * Sample output : Train departed from KARUKKUTTY(KUC) and late by 24 minutes.
 */
exports.getJsonLiveStatus= function (train_no,doj,eventCallback){

    var url =config.getBaseUrl()+"live/train/"+train_no+"/doj/"+doj+"/apikey/"+apiKey+"/";
    var state="";
    var status= "";
    http.get(url, function(res) {
        var body = '';

        res.on('data', function (chunk) {
            body += chunk;
        });

        res.on('end', function () {
            var stringResult = JSON.parse(body);
            var status=stringResult.position;
            if(stringResult.response_code!='200')
                    status="There was an error processing your request.";
            var result={speech:status,status:stringResult.position,heading:'Train Number: '+train_no};
            eventCallback(result);

        });
    }).on('error', function (e) {
        console.log("Got error: ", e);
        status= "Sorry, we could not process your request.";

        var result={speech:status,status:status,heading:null};
        eventCallback(result);
    });
   return status;
}

/**
 * This function will return the stations in a route as a string.
 * Sample output : KANYAKUMARI,Source,14:10,1,  NAGARCOIL JN,14:30,14:35,1,  KULITTHURAI,15:14,15:15,1,  TRIVANDRUM CNTL,15:55,16:00,1,  KOLLAM JN,17:00,17:05,1,  KAYANKULAM,17:34,17:36,1 (Station     **name,Arriavl time,Departure time,Day of arrival.)
 */
exports.getJsonTrainRoute=function (train_no,eventCallback){

    var url =config.getBaseUrl()+'route/train/'+train_no+'/apikey/'+ apiKey+'/';
       var station_string="";
    var state = "";
    http.get(url, function(res) {
        var body = '';

        res.on('data', function (chunk) {
            body += chunk;
        });

        res.on('end', function () {
            var stringResult = JSON.parse(body);
            var station_names=[];
            var station_arrival=[];
            var station_dep=[];
            var day=[];
            for (i=0; i<stringResult.route.length; i++){
                station_names[i]=stringResult.route[i].fullname;
                station_arrival[i]=stringResult.route[i].scharr;
                station_dep[i]=stringResult.route[i].schdep;
                day[i]=stringResult.route[i].day;
                }
             var m=0;
             var update=Math.ceil(((stringResult.route.length-2)/5));
             var source_=station_names[0];
             var dest_=station_names[i-1];

             station_string=station_string+"The train starts from "+source_+" at "+station_dep[0]+" and arrives  "+dest_+" at "+station_arrival[i-1]+" on day "+day[i-1]+" passing through ";
            for (j=0; j<i-1; j=j+update){
               m=j+1;
              if((j+update)<(i-1))
                 station_string=station_string+station_names[j]+",";
                else
                 station_string=station_string+" and "+station_names[j]+".";
               }
               if(stringResult.response_code!='200')
                    station_string="There was an error processing your request.";
            var result={speech:station_string,status:station_string,heading:"Route of Train Number: "+train_no};
            eventCallback(result);

        });
    }).on('error', function (e) {
        console.log("Got error: ", e);
        status= "Sorry, we could not process your request.";
        var result={speech:status,status:status,heading:null};
        eventCallback(result);
    });
}

/**
 * This function will return the seat availability as string.
 * Sample output : AVAILABLE 11

*/
exports.getJsonSeatAvailability = function (train_no, source, dest, date, _class, quota,eventCallback){
    var url =config.getBaseUrl() +'/check_seat/train/'+train_no+'/source/'+ source +'/dest/'+dest+'/date/'+ date+'/class/'+_class+'/quota/'+quota+'/apikey/'+ apiKey+'/';
    var status = "";
      http.get(url, function(res) {
        var body = '';

        res.on('data', function (chunk) {
            body += chunk;
        });

        res.on('end', function () {
            var stringResult = JSON.parse(body);
            var index3=0;
            var index4=0;
            var status=stringResult.availability[0].status;
            if(status.indexOf('AVAILABLE')>-1)
            {
                var index_=status.indexOf('AVAILABLE');
                var available=status.substring(index_+10);
            }
            status=available+" seats are available.";
            if(status.charAt(0)=='G'&&status.charAt(1)=='N'&&status.charAt(2)=='W')
               {
                 index3=status.indexOf("/WL");
                 index4=status.indexOf("\n",index3);
                 var waiting=status.substring(index3+3,index3+8);
                 var status=waiting+" seats are in waiting list.";
                }
                if(stringResult.response_code!='200')
                    status="There was an error processing your request.";
             var result={speech:status,status:status,heading:"Seat availability of Train: "+train_no};
             eventCallback(result);
        });
    }).on('error', function (e) {
             var result={speech:"Sorry, we could not process your request.",status:"Sorry, we could not process your request.",heading:null};
             eventCallback(result);
    });
}

/**
 * This function will return the train numbers of trains between stations as a string.
 * Sample output : 12617  16382  16346  19577  16334

*/
exports.getJsonTrainBtw =function (source, dest, date, eventCallback){
         var mon= date.substring(5,7);
         var day= date.substring(8);
         date=day+"-"+mon;
         var url=config.getBaseUrl()+"between/source/"+source+"/dest/"+dest+"/date/"+date+"/apikey/"+apiKey+"/";
         var stat="";
         var train_string="";
        http.get(url, function(res) {
        var body = '';

        res.on('data', function (chunk) {
            body += chunk;
        });

        res.on('end', function () {
            var stringResult = JSON.parse(body);
            var train_no=[];
            var src_departure_time=[];
            var dest_arrival_time=[];
            var days=[];
            var index=0;
            for(i=0; i<stringResult["train"].length; i++){
                days[i]="";
                train_no[i]=stringResult["train"][i].number;
                src_departure_time[i]=stringResult["train"][i].src_departure_time;
                dest_arrival_time[i]=stringResult["train"][i].dest_arrival_time;
                for  (j=0; j<stringResult["train"][i]["days"].length; j++){
                        if(stringResult["train"][i]["days"][j].runs==="Y")
                          {
                            switch(j){
                               case 0: days[i]=days[i]+"monday, ";
                                       break;
                               case 1: days[i]=days[i]+"tuesday, ";
                                       break;
                               case 2: days[i]=days[i]+"wednesday, ";
                                       break;
                               case 3: days[i]=days[i]+"thursday, ";
                                       break;
                               case 4: days[i]=days[i]+"friday, ";
                                       break;
                               case 5: days[i]=days[i]+"saturday, ";
                                       break;
                               case 6: days[i]=days[i]+"sunday, ";
                                       break;
                              }
                            }
                     }
              }
             stat= stat+ "Total "+i+" trains are there.";
             var m=0;
            for (j=0; j<i; j++){
               m=j+1;
               if(m<=3)
                 {
                  stat = stat + "Train "+m+ '.';
                   stat = stat+" Source departure time :"+src_departure_time[j]+", Destination arrival time "+dest_arrival_time[j]+", Days of run "+days[j]+".";
                   }
               train_string = train_string + "Train "+m+ '\n';
               train_string =train_string+" Source departure time :"+src_departure_time[j]+"\n Destination arrival time "+dest_arrival_time[j]+"\n Days of run "+days[j]+"\n";

               }

               if(stringResult.response_code!='200'){
                    train_string="There was an error processing your request.";
                     stat=train	_string;
                   }
             stat=stat+ "For details of all other trains see the result card."
             var result={speech:stat,status:train_string,heading:"Trains running between "+source+" and "+dest};
             eventCallback(result);

        });
    }).on('error', function (e) {
        console.log("Got error: ", e);
        train_string = "sorry, we could not process your request.";
        var result={speech:train_string,status:train_string,heading:null};
        eventCallback(result);
    });
}

exports.getJsonPNRstatus=function (pnr_no, eventCallback){
    var result="";
    var stat="";
      var train_name="Hi";
     var url =config.getBaseUrl() +'pnr_status/pnr/'+pnr_no+'/apikey/'+ apiKey+'/';
    http.get(url, function(res) {
        var body = '';

        res.on('data', function (chunk) {
            body += chunk;
        });

        res.on('end', function () {
           var train_no;
            var doj="";
            var Class="";
            var chart_prepared="";
            var total_passengers;
            var booking_status=[];
            var current_status=[];
            var coach_position =[];
            var stringResult = JSON.parse(body);
             var c="";
            train_no= stringResult.train_no;
            doj= stringResult.doj;
            Class= stringResult.class;
            chart_prepared= stringResult.chart_prepared;
            total_passengers= stringResult.total_passengers;
           result= result+"Starting date is "+doj+"\n Class is "+Class+"\n Chart prepared "+chart_prepared+"\n Total number of passengers "+total_passengers+"\n Details of each passengers\n";
           result= result+"Starting date is "+doj+". Class is "+Class+". Chart prepared "+chart_prepared+". Total number of passengers "+total_passengers+". Details of each passengers.";

            for ( i=0; i<stringResult["passengers"].length; i++){
               booking_status[i]=stringResult["passengers"][i].booking_status;
               current_status[i]=stringResult["passengers"][i].current_status;
               coach_position[i]=stringResult["passengers"][i].coach_position;

              }
             var m=0;
            for (j=0; j<i; j++){
               m=j+1;
               result = result + "passenger "+m+ '\n';
               result=result+" Booking status "+booking_status[j]+"\n Current status "+current_status[j]+"\n Coach position "+coach_position[j]+"\n";
               if(current_status[j]==="CAN/MOD")
                  current_status[j]="cancelled or modified.";
              if(current_status[j]==="CNF/Confirmed")
                  {
                    if(chart_prepared==="Y")
                      {
                        c=current_status[j];
                        current_status[j]= "confirmed, coach and berth position is "+ c+".";
                       }
                     else
                           current_status[j]="confirmed, Coach/Berth number will be available after chart preparation.";
                  }
               stat=stat+" passenger "+m+", current status is "+current_status[j]+".";
               }

               stat=stat+" For further details see the result card.";
                if(stringResult.response_code=='410'){
                    result="PNR does not exist.";
                    stat=result;
                   }
            var result1={speech:stat,status:result,heading:"PNR status of: "+pnr_no};

            eventCallback(result1);

        });
    }).on('error', function (e) {
        console.log("Got error: ", e);
         result = "sorry, we could not process your request.";
        var result1={speech:result,status:result,heading:null};
        eventCallback(result1);
    });
}

exports.getJsonTrainArrivals=function (station_code,hrs, eventCallback){
    var result="";
    var url =config.getBaseUrl() +'arrivals/station/'+station_code+'/hours/'+hrs+'/apikey/'+ apiKey+'/';

    http.get(url, function(res) {
        var body = '';

        res.on('data', function (chunk) {
            body += chunk;
        });

        res.on('end', function () {
           var train_no=[];
            var actdep=[];
            var delaydep=[];
            var scharr=[];
            var delayarr=[];
            var schdep =[];
            var stringResult = JSON.parse(body);
             for (i=0; i<stringResult["train"].length; i++){
                train_no[i]=stringResult["train"][i].number;
                scharr[i]=stringResult["train"][i].scharr;
                delayarr[i]=stringResult["train"][i].delayarr;
                schdep[i]=stringResult["train"][i].schdep;
                actdep[i]=stringResult["train"][i].actdep;
                delaydep[i]=stringResult["train"][i].delaydep;

              }
             var m=0;
            for ( j=0; j<i; j++){
               m=j+1;
               result = result + "Train "+train_no[j]+ '.';
               result=result+", Scheduled arrival "+scharr[j]+", Delayed arrival "+delayarr[j]+", Scheduled departure "+schdep[j]+", actual departure "+actdep[j]+", delayed departure "+delaydep[j]+".";

               }
               if(stringResult.response_code!='200')
                    result="There was an error processing your request.";
            var result1={speech:result,status:result,heading:"Train arrivals at station: "+station_code};
            eventCallback(result1);

        });
    }).on('error', function (e) {
        console.log("Got error: ", e);
         result = "sorry, we could not process your request.";
         var result1={speech:result,status:result,heading:null};
         eventCallback(result1);
    });
}

/*exports.getJsonTrainName = function (train_no){
    var state="";
    var result="";
    var url =baseUrl +'/name_number/train/'+train_no+'/apikey/'+ apikey+'/';
    http.get(url, function(res) {
        var body = '';

        res.on('data', function (chunk) {
            body += chunk;
        });

        res.on('end', function () {
            var stringResult = JSON.stringify(body);
            var index=0;
            var index2=0
            var train_numbers=[];
            var train_string="";
            var index=stringResult.indexOf("name")
            var index1=stringResult.indexOf("}",index)
            var name =stringResult.substring(index+10,index1-8);
            result=name;
            if(stringResult.indexOf("error") > -1) {
                 state = "error";
                }
            else
                 state = "success";

        });
    }).on('error', function (e) {
        state = "error";
    });
}

function numberToName(train_no,eventCallback){
    var baseURL="http://api.railwayapi.com";
    var apiKey="bkxel1825";
    var state="";
    var result="";
    var url =baseURL +'/name_number/train/'+train_no+'/apikey/'+ apiKey+'/';
    http.get(url, function(res) {
        var body = '';

        res.on('data', function (chunk) {
            body += chunk;
        });

        res.on('end', function () {
            var stringResult = JSON.parse(body);
            eventCallback(stringResult.train.name);

        });
    }).on('error', function (e) {
        state = "error";
    });
}
*/

<|endoftext|>