<commit_before>/** Represents a single project in the work carousel */
import Parallax3D from '../parallax';

export class CarouselCard {
  constructor(elem, tags) {
    this.elem = elem;
    this.elem.classList.add('carousel-card');
    // Move elem into a wrapper div
    this.wrapper = document.createElement('div');
    this.wrapper.className = 'carousel-card-wrapper';
    this.elem.parentNode.insertBefore(this.wrapper, this.elem);
    this.wrapper.appendChild(this.elem);

    this.tags = tags || elem.dataset.tags.split(',').map(t => t.trim());
    this.titleElem = elem.getElementsByTagName('h1')[0];

    this.transitionTime = this.baseTransitionTime = 0.5;
    this.parallax = new Parallax3D(this.elem);

    // Title manipulation interface

    const _this2 = this;
    /**
     * Interface for updating styles on the title.
     * Examples:
     *   this.title.translate = '-10px'
     *   this.title.opacity = 0.5
     */
    this.title = {
      _apply() {
        _this2.titleElem.style.transform = `translateZ(25px) translateX(${this._translate})`;
        _this2.titleElem.style.opacity = this._opacity;
      },
      get translate() { return this._translate; },
      set translate(t) { this._translate = t; this._apply(); },
      get opacity() { return this._opacity; },
      set opacity(o) { this._opacity = o; this._apply(); },
    };
  }

  /**
   * Update the card wrapper's CSS in order to reflect changes that were made to its JS
   * representation.
   */
  _applyTransform() {
    this.wrapper.style.transform = [
      'translate(-50%, -50%)',
      `translateX(${this._translate})`,
    ].join(' ');
  }

  // Translation

  get translate() { return this._translate; }
  set translate(val) { this._translate = val; this._applyTransform(); }

  // Transition time

  get transitionTime() { return this._transitionTime; }
  set transitionTime(secs) {
    this._transitionTime = secs;
    this.wrapper.style.transition = `transform ${secs}s`;
    this.titleElem.style.transition = `transform ${secs}s, opacity ${secs}s`;
  }
}

/** Collects and orchestrates multiple CarouselCards */
export class Carousel {
  constructor(cards) {
    this.cards = cards;
    this._position = 0;
    // Trigger immediate layout of cards
    this.position = this._position;
  }

  // Transition time logic

  get baseTransitionTime() {
    const answer = this.cards[0].baseTransitionTime;
    // Warn if not every card has the same baseTransitionTime
    if (!this.cards.every(card => card.baseTransitionTime === answer)) console.warn('Carousel.baseTransitionTime called but baseTransitionTime of cards is inconsistent');
    return answer;
  }
  get transitionTime() {
    const answer = this.cards[0].transitionTime;
    // Warn if not every card has the same transitionTime
    if (!this.cards.every(card => card.transitionTime === answer)) console.warn('Carousel.transitionTime called but transitionTime of cards is inconsistent');
    return answer;
  }
  set transitionTime(secs) {
    this.cards.forEach((c) => { c.transitionTime = secs; });
  }

  // Rearrange

  get position() { return this._position; }
  set position(pos) {
    const delta = Math.abs(this._position - pos);
    // mx + b
    this.transitionTime = ((0.5 * this.baseTransitionTime) * (delta - 1)) + this.baseTransitionTime;

    this.cards.forEach((card, index) => {
      const cardPosition = index - pos;
      const cardTranslation = `${48 * cardPosition}vw`;
      card.translate = cardTranslation;
      if (cardPosition === 0) {
        card.title.opacity = 1;
        card.title.translate = 0;
      } else {
        card.title.opacity = 0;
        card.title.translate = (pos > this._position) ? '5vw' : '-5vw';
      }
    });

    this._position = pos;
  }
}
<commit_msg>Add method for animated disabling of card parallax effect<commit_after>/** Represents a single project in the work carousel */
import Parallax3D from '../parallax';

export class CarouselCard {
  constructor(elem, tags) {
    this.elem = elem;
    this.elem.classList.add('carousel-card');
    // Move elem into a wrapper div
    this.wrapper = document.createElement('div');
    this.wrapper.className = 'carousel-card-wrapper';
    this.elem.parentNode.insertBefore(this.wrapper, this.elem);
    this.wrapper.appendChild(this.elem);

    this.tags = tags || elem.dataset.tags.split(',').map(t => t.trim());
    this.titleElem = elem.getElementsByTagName('h1')[0];

    this.transitionTime = this.baseTransitionTime = 0.5;
    this.parallax = new Parallax3D(this.elem);

    // Title manipulation interface

    const _this2 = this;
    /**
     * Interface for updating styles on the title.
     * Examples:
     *   this.title.translate = '-10px'
     *   this.title.opacity = 0.5
     */
    this.title = {
      _apply() {
        _this2.titleElem.style.transform = `translateZ(25px) translateX(${this._translate})`;
        _this2.titleElem.style.opacity = this._opacity;
      },
      get translate() { return this._translate; },
      set translate(t) { this._translate = t; this._apply(); },
      get opacity() { return this._opacity; },
      set opacity(o) { this._opacity = o; this._apply(); },
    };
  }

  /**
   * Update the card wrapper's CSS in order to reflect changes that were made to its JS
   * representation.
   */
  _applyTransform() {
    this.wrapper.style.transform = [
      'translate(-50%, -50%)',
      `translateX(${this._translate})`,
    ].join(' ');
  }

  // Translation

  get translate() { return this._translate; }
  set translate(val) { this._translate = val; this._applyTransform(); }

  // Transition time

  get transitionTime() { return this._transitionTime; }
  set transitionTime(secs) {
    this._transitionTime = secs;
    this.wrapper.style.transition = `transform ${secs}s`;
    this.titleElem.style.transition = `transform ${secs}s, opacity ${secs}s`;
  }

  setEnabled(enable = true) {
    const totalTime = this.transitionTime * 1000;
    const startTime = new Date();

    function step(parallax) {
      const timeElapsed = new Date() - startTime;
      // Still going
      if (timeElapsed < totalTime) {
        const progress = (timeElapsed / totalTime);
        if (enable) parallax.rotmax = progress * 10;
        else parallax.rotmax = (1 - progress) * 10;
        parallax.rotate();
        requestAnimationFrame(() => step(parallax));
      } else {
        parallax.rotmax = enable ? 10 : 0;
      }
    }
    step(this.parallax);
  }
}

/** Collects and orchestrates multiple CarouselCards */
export class Carousel {
  constructor(cards) {
    this.cards = cards;
    this._position = 0;
    // Trigger immediate layout of cards
    this.position = this._position;
  }

  // Transition time logic

  get baseTransitionTime() {
    const answer = this.cards[0].baseTransitionTime;
    // Warn if not every card has the same baseTransitionTime
    if (!this.cards.every(card => card.baseTransitionTime === answer)) console.warn('Carousel.baseTransitionTime called but baseTransitionTime of cards is inconsistent');
    return answer;
  }
  get transitionTime() {
    const answer = this.cards[0].transitionTime;
    // Warn if not every card has the same transitionTime
    if (!this.cards.every(card => card.transitionTime === answer)) console.warn('Carousel.transitionTime called but transitionTime of cards is inconsistent');
    return answer;
  }
  set transitionTime(secs) {
    this.cards.forEach((c) => { c.transitionTime = secs; });
  }

  // Rearrange

  get position() { return this._position; }
  set position(pos) {
    const delta = Math.abs(this._position - pos);
    // mx + b
    this.transitionTime = ((0.5 * this.baseTransitionTime) * (delta - 1)) + this.baseTransitionTime;

    this.cards.forEach((card, index) => {
      const cardPosition = index - pos;
      const cardTranslation = `${48 * cardPosition}vw`;
      card.translate = cardTranslation;
      if (cardPosition === 0) {
        card.title.opacity = 1;
        card.title.translate = 0;
      } else {
        card.title.opacity = 0;
        card.title.translate = (pos > this._position) ? '5vw' : '-5vw';
      }
    });

    this._position = pos;
  }
}
<|endoftext|>


<commit_before>(function(){

    'use strict';

    window.App = window.App || {};
    App.BASE = App.HOST = (function() {
        var origin = location.origin;
        // remove the trailer port number if running on local
        if (origin.match(/[0-9]{4,4}/)) {
            origin = origin.split(':');
            origin.pop();
            origin = origin.join(':') + ':5000';
        } else {
            origin += ':5000';
        }
        return origin;
    })();
    App.Components = {
        timeline: false,
        graph: false,
        insights: false
    };
    App.DEBUG = false;

    // get wrapper, logs and calls the callback or fail fn
    App.utils.httpGet = function httpGet(url, params, success, fail) {
        if (App.DEBUG) {
            console.log('[GET] ' + url);
        }
        if (typeof params === 'function') {
            params = {};
            success = arguments[1];
            fail = arguments[2];
        } else {
            if (App.DEBUG) {
                console.log('[GET] params: ', params);
            }
        }
        if (!success) {
            console.error('[GET] no success handler supplied');
        }
        return $.get(url, params || {}).done(success).fail(fail || displayFailMessage);
    };

    App.Router = Backbone.Router.extend({
        routes: {
            ':user/:repo/timeline': 'timeline',
            ':user/:repo'         : 'timeline',
            ':user/:repo/graphs'  : 'graphs',
            ':user/:repo/insights': 'insights',
            '*index'              : 'index'
        }
    });

    App.Views = {};
    App.Views.Topbar = Backbone.View.extend({
        el: $('#topbar .menu'),
        events: {
            'click li': 'changeView'
        },

        changeView: function(item) {
            var $el = $(item.target);
            var action = $el.text().toLowerCase();
            location.hash = '/' + App.REPO + '/' + action;
            $('.menu li').removeClass('selected');
            $('li[data-tab=tab-' + action + ']').addClass('selected');
        }
    });

    App.Views.RepoSelector = Backbone.View.extend({
        el: $('#repo-select-trigger'),
        initialize: function() {
            getAllRepos(addRepos);
        },
        events: {
            'click'   : 'toggle',
            'click li': 'switchRepo'
        },
        toggle: function() {
            var $container = $('.repo-select');
            var $repoList = $('ul', $container);

            $container.toggleClass('hidden');
            $repoList.addClass('show--fade-in');

            if ($container.hasClass('hidden')) {
                $('.show--fade-in').removeClass('show--fade-in');
            } else {
                var cb = this.hideTooltip.bind(this);
                $(window).on('keydown', cb);
            }
        },
        hideTooltip: function(e) {
            if (e.keyCode == 27) { // ESC
                $(window).off('keydown');
                this.toggle();
            }

        },
        switchRepo: function(event) {
            $('.menu li').removeClass('selected');
            // remove all the events in the timeline
            // leave in only the loading spinner
            var repo = $(event.target).text();
            emptyTimeline();
            location.hash = '/' + repo + '/timeline';
        }
    });

    App.Views.PullIssueBadge = Backbone.View.extend({
        el: $('#pull-issue-badges'),
        initialize: function() {
            populateOpenIssues();
            populateOpenPulls();
        }
    });

    var topbar = new App.Views.Topbar();
    var repoSelecttor = new App.Views.RepoSelector();
    var pullIssueBadge;
    var appRouter = new App.Router();

    appRouter.on('route:index', function() {
        getRandomRepo(function(repo) {
            location.hash = '/' + repo + '/timeline';
        });
    });

    function initIssuePullBadges() {
        pullIssueBadge = new App.Views.PullIssueBadge();
    }

    appRouter.on('route:insights', function(user, repo){
        if (App.DEBUG) {
            console.log('[INSIGHTS]');
        }
        if (arguments.length > 3) {
            console.error('Bad request. Format is /<user>/<repo>/insights');
            if (App.DEBUG) {
                console.log(arguments);
            }
            return;
        }
        checkForRepo(user, repo, function(res) {
            if (res) {

                App.REPO = user + '/' + repo;
                App.BASE = App.HOST + '/' + App.REPO;

                $('#user-repo').text(App.REPO);

                if (!App.Components.insights) {
                    drawInsights();
                    App.Components.insights = true;
                }
                $('.tab').hide();
                $('#tab-insights').removeClass('hide').show();

                stopScrollListener();
                initIssuePullBadges();

            }
        });
    });

    appRouter.on('route:graphs', function(user, repo) {
        if (App.DEBUG) {
            console.log('[GRAPHS]');
        }
        if (arguments.length > 3) {
            console.error('Bad request. Format is /<user>/<repo>/graph');
            if (App.DEBUG) {
                console.log(arguments);
            }
            return;
        }
        checkForRepo(user, repo, function(res) {
            if (res) {

                App.REPO = user + '/' + repo;
                App.BASE = App.HOST + '/' + App.REPO;

                $('#user-repo').text(App.REPO);

                if (!App.Components.graph) {
                    drawGraphs();
                    App.Components.graph = true;
                }
                $('.tab').hide();
                $('#tab-graphs').show();

                stopScrollListener();
                initIssuePullBadges();

            }
        });
    });

    appRouter.on('route:timeline', function(user, repo) {
        checkForRepo(user, repo, function(res) {
            if (res) {
                if (App.DEBUG) {
                    console.log('[TIMELINE] ' + user + ' ' + repo);
                }
                $('.tab').hide();
                $('#tab-timeline').show();

                App.REPO = user + '/' + repo;
                App.BASE = App.HOST + '/' + App.REPO;

                $('#user-repo').text(App.REPO);

                if (!App.Components.timeline) {
                    initTimeline();
                    App.Components.timeline = true;
                }
                initIssuePullBadges();
                addScrollListener();
            } else {
                console.error('No such repo');
            }
        });
    });

    function checkForRepo(user, repo, fn) {
        var url = App.HOST + '/available_repos';
        var s = user + '/' + repo;
        App.utils.httpGet(url, {name: 'andrei'}, function(data) {
            var r = data.data.some(function(repo) {
                return repo.match(s);
            });
            fn(r);
        });
    }

    function getAllRepos(cb) {
        var url = App.HOST + '/available_repos';
        App.utils.httpGet(url, cb);
    }

    // make a request for all available repos
    // call the callback with a random repo
    function getRandomRepo(fn) {
        getAllRepos(function(data) {
            var idx = parseInt(Math.random() * 100 % data.data.length, 10);
            var randomRepo = data.data[idx];
            fn(randomRepo);
        });
    }

    // generic fail method for logging
    function logFailure(data) {
        if (App.DEBUG) {
            console.log('Request failed.');
            console.log(data);
        }
    }

    // populate repo tooltip with all available repos
    function addRepos (data) {
        var $container = $('.repo-select');

        var $repoList = $('ul', $container);
        data.data.forEach(function (repo) {
            // TODO add actual links
            var repoLink = $('').text(repo);
            var repoLI = $('
').append(repoLink);
            $repoList.append(repoLI);
        });
    }

    function initTimeline() {
        emptyTimeline();
        populateTimeline();
    }

    function addScrollListener() {
        var $timeline = $('#timeline');
        $(document).on('scroll', function () {
            if (App.DEBUG) {
                console.log('[TIMELINE] scroll listener');
            }
            if($(window).scrollTop() + $(window).height() >= $(document).height() - 10) {
                populateTimeline(App.PER_PAGE, $timeline.children('.timeline-item').length);
            }
        });
    }

    function stopScrollListener() {
        $(document).off('scroll');
    }

    function populateOpenIssues() {
        App.utils.httpGet(App.BASE + "/issues_count", function (data) {
            var count = data.data.open;
            var $el = $('#open-issues-count');
            var url = 'http://github.com/' + App.REPO + '/issues?state=open';

            $el.text(count).attr('href', url);
        });
    }

    function populateOpenPulls() {
        App.utils.httpGet(App.BASE + "/pulls_count", function (data) {
            var count = data.data.open;
            var $el = $('#open-pulls-count');
            var url = 'http://github.com/' + App.REPO + '/pulls?state=open';

            $el.text(count).attr('href', url);
        });
    }

    Backbone.history.start();

    $(window).on('hashchange', function(e) {
        // if hash has changed but it's the same repo
        if (location.hash.match(App.REPO)) return;
        App.Components = {
            timeline: false,
            graph: false,
            insights: false
        };
    });

})();

function logFailure(msg) {
    console.log('[FAILURE]', msg.statusText);
}

function displayFailMessage(fail) {

    var $tabContainer = $('#tab-container');

    if (fail.status != 404) {
        logFailure(fail);
        return;
    }

    $('#counts-container').remove();
    $tabContainer.empty();

    var msg = "
No data for this repository yet. Retrying in 2 minutes.
";
    $tabContainer.append(msg);

    setTimeout(function() {
        location.reload();
    }, 1000 * 60 * 2);
}
<commit_msg>Cleanup<commit_after>(function(){

    'use strict';

    window.App = window.App || {};
    App.BASE = App.HOST = (function() {
        var origin = location.origin;
        // remove the trailer port number if running on local
        if (origin.match(/[0-9]{4,4}/)) {
            origin = origin.split(':');
            origin.pop();
            origin = origin.join(':') + ':5000';
        } else {
            origin += ':5000';
        }
        return origin;
    })();
    App.Components = {
        timeline: false,
        graph: false,
        insights: false
    };
    App.DEBUG = false;

    // get wrapper, logs and calls the callback or fail fn
    App.utils.httpGet = function httpGet(url, params, success, fail) {
        if (App.DEBUG) {
            console.log('[GET] ' + url);
        }
        if (typeof params === 'function') {
            params = {};
            success = arguments[1];
            fail = arguments[2];
        } else {
            if (App.DEBUG) {
                console.log('[GET] params: ', params);
            }
        }
        if (!success) {
            console.error('[GET] no success handler supplied');
        }
        return $.get(url, params || {}).done(success).fail(fail || displayFailMessage);
    };

    App.Router = Backbone.Router.extend({
        routes: {
            ':user/:repo/timeline': 'timeline',
            ':user/:repo'         : 'timeline',
            ':user/:repo/graphs'  : 'graphs',
            ':user/:repo/insights': 'insights',
            '*index'              : 'index'
        }
    });

    App.Views = {};
    App.Views.Topbar = Backbone.View.extend({
        el: $('#topbar .menu'),
        events: {
            'click li': 'changeView'
        },

        changeView: function(item) {
            var $el = $(item.target);
            var action = $el.text().toLowerCase();
            location.hash = '/' + App.REPO + '/' + action;
            $('.menu li').removeClass('selected');
            $('li[data-tab=tab-' + action + ']').addClass('selected');
        }
    });

    App.Views.RepoSelector = Backbone.View.extend({
        el: $('#repo-select-trigger'),
        initialize: function() {
            getAllRepos(addRepos);
        },
        events: {
            'click'   : 'toggle',
            'click li': 'switchRepo'
        },
        toggle: function() {
            var $container = $('.repo-select');
            var $repoList = $('ul', $container);

            $container.toggleClass('hidden');
            $repoList.addClass('show--fade-in');

            if ($container.hasClass('hidden')) {
                $('.show--fade-in').removeClass('show--fade-in');
            } else {
                var cb = this.hideTooltip.bind(this);
                $(window).on('keydown', cb);
            }
        },
        hideTooltip: function(e) {
            if (e.keyCode == 27) { // ESC
                $(window).off('keydown');
                this.toggle();
            }

        },
        switchRepo: function(event) {
            $('.menu li').removeClass('selected');
            // remove all the events in the timeline
            // leave in only the loading spinner
            var repo = $(event.target).text();
            emptyTimeline();
            location.hash = '/' + repo + '/timeline';
        }
    });

    App.Views.PullIssueBadge = Backbone.View.extend({
        el: $('#pull-issue-badges'),
        initialize: function() {
            populateOpenIssues();
            populateOpenPulls();
        }
    });

    var topbar = new App.Views.Topbar();
    var repoSelecttor = new App.Views.RepoSelector();
    var pullIssueBadge;
    var appRouter = new App.Router();

    appRouter.on('route:index', function() {
        getRandomRepo(function(repo) {
            location.hash = '/' + repo + '/timeline';
        });
    });

    function initIssuePullBadges() {
        pullIssueBadge = new App.Views.PullIssueBadge();
    }

    appRouter.on('route:insights', function(user, repo){
        if (App.DEBUG) {
            console.log('[INSIGHTS]');
        }
        if (arguments.length > 3) {
            console.error('Bad request. Format is /<user>/<repo>/insights');
            if (App.DEBUG) {
                console.log(arguments);
            }
            return;
        }
        checkForRepo(user, repo, function(res) {
            if (res) {

                App.REPO = user + '/' + repo;
                App.BASE = App.HOST + '/' + App.REPO;

                $('#user-repo').text(App.REPO);

                if (!App.Components.insights) {
                    drawInsights();
                    App.Components.insights = true;
                }
                $('.tab').hide();
                $('#tab-insights').removeClass('hide').show();

                stopScrollListener();
                initIssuePullBadges();

            }
        });
    });

    appRouter.on('route:graphs', function(user, repo) {
        if (App.DEBUG) {
            console.log('[GRAPHS]');
        }
        if (arguments.length > 3) {
            console.error('Bad request. Format is /<user>/<repo>/graph');
            if (App.DEBUG) {
                console.log(arguments);
            }
            return;
        }
        checkForRepo(user, repo, function(res) {
            if (res) {

                App.REPO = user + '/' + repo;
                App.BASE = App.HOST + '/' + App.REPO;

                $('#user-repo').text(App.REPO);

                if (!App.Components.graph) {
                    drawGraphs();
                    App.Components.graph = true;
                }
                $('.tab').hide();
                $('#tab-graphs').show();

                stopScrollListener();
                initIssuePullBadges();

            }
        });
    });

    appRouter.on('route:timeline', function(user, repo) {
        checkForRepo(user, repo, function(res) {
            if (res) {
                if (App.DEBUG) {
                    console.log('[TIMELINE] ' + user + ' ' + repo);
                }
                $('.tab').hide();
                $('#tab-timeline').show();

                App.REPO = user + '/' + repo;
                App.BASE = App.HOST + '/' + App.REPO;

                $('#user-repo').text(App.REPO);

                if (!App.Components.timeline) {
                    initTimeline();
                    App.Components.timeline = true;
                }
                initIssuePullBadges();
                addScrollListener();
            } else {
                console.error('No such repo');
            }
        });
    });

    function checkForRepo(user, repo, fn) {
        var url = App.HOST + '/available_repos';
        var s = user + '/' + repo;
        App.utils.httpGet(url, function(data) {
            var r = data.data.some(function(repo) {
                return repo.match(s);
            });
            fn(r);
        });
    }

    function getAllRepos(cb) {
        var url = App.HOST + '/available_repos';
        App.utils.httpGet(url, cb);
    }

    // make a request for all available repos
    // call the callback with a random repo
    function getRandomRepo(fn) {
        getAllRepos(function(data) {
            var idx = parseInt(Math.random() * 100 % data.data.length, 10);
            var randomRepo = data.data[idx];
            fn(randomRepo);
        });
    }

    // generic fail method for logging
    function logFailure(data) {
        if (App.DEBUG) {
            console.log('Request failed.');
            console.log(data);
        }
    }

    // populate repo tooltip with all available repos
    function addRepos (data) {
        var $container = $('.repo-select');

        var $repoList = $('ul', $container);
        data.data.forEach(function (repo) {
            // TODO add actual links
            var repoLink = $('').text(repo);
            var repoLI = $('
').append(repoLink);
            $repoList.append(repoLI);
        });
    }

    function initTimeline() {
        emptyTimeline();
        populateTimeline();
    }

    function addScrollListener() {
        var $timeline = $('#timeline');
        $(document).on('scroll', function () {
            if (App.DEBUG) {
                console.log('[TIMELINE] scroll listener');
            }
            if($(window).scrollTop() + $(window).height() >= $(document).height() - 10) {
                populateTimeline(App.PER_PAGE, $timeline.children('.timeline-item').length);
            }
        });
    }

    function stopScrollListener() {
        $(document).off('scroll');
    }

    function populateOpenIssues() {
        App.utils.httpGet(App.BASE + "/issues_count", function (data) {
            var count = data.data.open;
            var $el = $('#open-issues-count');
            var url = 'http://github.com/' + App.REPO + '/issues?state=open';

            $el.text(count).attr('href', url);
        });
    }

    function populateOpenPulls() {
        App.utils.httpGet(App.BASE + "/pulls_count", function (data) {
            var count = data.data.open;
            var $el = $('#open-pulls-count');
            var url = 'http://github.com/' + App.REPO + '/pulls?state=open';

            $el.text(count).attr('href', url);
        });
    }

    Backbone.history.start();

    $(window).on('hashchange', function(e) {
        // if hash has changed but it's the same repo
        if (location.hash.match(App.REPO)) return;
        App.Components = {
            timeline: false,
            graph: false,
            insights: false
        };
    });

})();

function logFailure(msg) {
    console.log('[FAILURE]', msg.statusText);
}

function displayFailMessage(fail) {

    var $tabContainer = $('#tab-container');

    if (fail.status != 404) {
        logFailure(fail);
        return;
    }

    $('#counts-container').remove();
    $tabContainer.empty();

    var msg = "
No data for this repository yet. Retrying in 2 minutes.
";
    $tabContainer.append(msg);

    setTimeout(function() {
        location.reload();
    }, 1000 * 60 * 2);
}
<|endoftext|>


<commit_before>angular.module('ui.bootstrap-slider', [])
    .directive('slider', ['$parse', '$timeout', '$rootScope', function ($parse, $timeout, $rootScope) {
        return {
            restrict: 'AE',
            replace: true,
            template: '
<input class="slider-input" type="text" style="width:100%" />
',
            require: 'ngModel',
            scope: {
                max: "=",
                min: "=",
                step: "=",
                value: "=",
                ngModel: '=',
                ngDisabled: '=',
                range: '=',
                sliderid: '=',
                ticks: '=',
                ticksLabels: '=',
                ticksSnapBounds: '=',
                ticksPositions: '=',
                scale: '=',
                focus: '=',
                formatter: '&',
                onStartSlide: '&',
                onStopSlide: '&',
                onSlide: '&'
            },
            link: function ($scope, element, attrs, ngModelCtrl, $compile) {
                var ngModelDeregisterFn, ngDisabledDeregisterFn;

                var slider = initSlider();

                function initSlider() {
                    var options = {};

                    function setOption(key, value, defaultValue) {
                        options[key] = value || defaultValue;
                    }

                    function setFloatOption(key, value, defaultValue) {
                        options[key] = value || value === 0 ? parseFloat(value) : defaultValue;
                    }

                    function setBooleanOption(key, value, defaultValue) {
                        options[key] = value ? value + '' === 'true' : defaultValue;
                    }

                    function getArrayOrValue(value) {
                        return (angular.isString(value) && value.indexOf("[") === 0) ? angular.fromJson(value) : value;
                    }

                    setOption('id', $scope.sliderid);
                    setOption('orientation', attrs.orientation, 'horizontal');
                    setOption('selection', attrs.selection, 'before');
                    setOption('handle', attrs.handle, 'round');
                    setOption('tooltip', attrs.sliderTooltip || attrs.tooltip, 'show');
                    setOption('tooltip_position', attrs.sliderTooltipPosition, 'top');
                    setOption('tooltipseparator', attrs.tooltipseparator, ':');
                    setOption('ticks', $scope.ticks);
                    setOption('ticks_labels', $scope.ticksLabels);
                    setOption('ticks_snap_bounds', $scope.ticksSnapBounds);
                    setOption('ticks_positions', $scope.ticksPositions);
                    setOption('scale', $scope.scale, 'linear');
                    setOption('focus', $scope.focus);

                    setFloatOption('min', $scope.min, 0);
                    setFloatOption('max', $scope.max, 10);
                    setFloatOption('step', $scope.step, 1);
                    var strNbr = options.step + '';
                    var dotPos = strNbr.search(/[^.,]*$/);
                    var decimals = strNbr.substring(dotPos);
                    setFloatOption('precision', attrs.precision, decimals.length);

                    setBooleanOption('tooltip_split', attrs.tooltipsplit, false);
                    setBooleanOption('enabled', attrs.enabled, true);
                    setBooleanOption('naturalarrowkeys', attrs.naturalarrowkeys, false);
                    setBooleanOption('reversed', attrs.reversed, false);

                    setBooleanOption('range', $scope.range, false);
                    if (options.range) {
                        if (angular.isArray($scope.value)) {
                            options.value = $scope.value;
                        }
                        else if (angular.isString($scope.value)) {
                            options.value = getArrayOrValue($scope.value);
                            if (!angular.isArray(options.value)) {
                                var value = parseFloat($scope.value);
                                if (isNaN(value)) value = 5;

                                if (value < $scope.min) {
                                    value = $scope.min;
                                    options.value = [value, options.max];
                                }
                                else if (value > $scope.max) {
                                    value = $scope.max;
                                    options.value = [options.min, value];
                                }
                                else {
                                    options.value = [options.min, options.max];
                                }
                            }
                        }
                        else {
                            options.value = [options.min, options.max]; // This is needed, because of value defined at $.fn.slider.defaults - default value 5 prevents creating range slider
                        }
                        $scope.ngModel = options.value; // needed, otherwise turns value into [null, ##]
                    }
                    else {
                        setFloatOption('value', $scope.value, 5);
                    }

                    if (attrs.formatter) {
                        options.formatter = function(value) {
                            return $scope.formatter({value: value});
                        }
                    }

                    // check if slider jQuery plugin exists
                    if ('$' in window && $.fn.slider) {
                        // adding methods to jQuery slider plugin prototype
                        $.fn.slider.constructor.prototype.disable = function () {
                            this.picker.off();
                        };
                        $.fn.slider.constructor.prototype.enable = function () {
                            this.picker.on();
                        };
                    }

                    // destroy previous slider to reset all options
                    if (element[0].__slider)
                        element[0].__slider.destroy();

                    var slider = new Slider(element[0].getElementsByClassName('slider-input')[0], options);
                    element[0].__slider = slider;

                    // everything that needs slider element
                    var updateEvent = getArrayOrValue(attrs.updateevent);
                    if (angular.isString(updateEvent)) {
                        // if only single event name in string
                        updateEvent = [updateEvent];
                    }
                    else {
                        // default to slide event
                        updateEvent = ['slide'];
                    }
                    angular.forEach(updateEvent, function (sliderEvent) {
                        slider.on(sliderEvent, function (ev) {
                            ngModelCtrl.$setViewValue(ev);
                        });
                    });
                    slider.on('change', function (ev) {
                        ngModelCtrl.$setViewValue(ev.newValue);
                    });

                    // Event listeners
                    var sliderEvents = {
                        slideStart: 'onStartSlide',
                        slide: 'onSlide',
                        slideStop: 'onStopSlide'
                    };
                    angular.forEach(sliderEvents, function (sliderEventAttr, sliderEvent) {
                        var fn = $parse(attrs[sliderEventAttr.toLowerCase()]);
                        slider.on(sliderEvent, function (ev) {
                            if ($scope[sliderEventAttr]) {
                                $scope.$apply(function () {
                                    fn($scope.$parent, { $event: sliderEvent, value: ev });
                                });
                            }
                        });
                    });

                    // deregister ngDisabled watcher to prevent memory leaks
                    if (angular.isFunction(ngDisabledDeregisterFn)) {
                        ngDisabledDeregisterFn();
                        ngDisabledDeregisterFn = null;
                    }

                    ngDisabledDeregisterFn = $scope.$watch('ngDisabled', function (value) {
                        if (value) {
                            slider.disable();
                        }
                        else {
                            slider.enable();
                        }
                    });

                    // deregister ngModel watcher to prevent memory leaks
                    if (angular.isFunction(ngModelDeregisterFn)) ngModelDeregisterFn();
                    ngModelDeregisterFn = $scope.$watch('ngModel', function (value) {
                        if($scope.range){
                            slider.setValue(value);
                        }else{
                            slider.setValue(parseFloat(value));
                        }
                        slider.relayout();
                    }, true);

                    return slider;
                }

                var watchers = ['min', 'max', 'step', 'range', 'scale'];
                angular.forEach(watchers, function (prop) {
                    $scope.$watch(prop, function () {
                        slider = initSlider();
                    });
                });

                $scope.$on('slider:relayout', function() {
                    slider.relayout();
                });
            }
        };
    }])
;
<commit_msg>add ticksLabels on watchers array<commit_after>angular.module('ui.bootstrap-slider', [])
    .directive('slider', ['$parse', '$timeout', '$rootScope', function ($parse, $timeout, $rootScope) {
        return {
            restrict: 'AE',
            replace: true,
            template: '
<input class="slider-input" type="text" style="width:100%" />
',
            require: 'ngModel',
            scope: {
                max: "=",
                min: "=",
                step: "=",
                value: "=",
                ngModel: '=',
                ngDisabled: '=',
                range: '=',
                sliderid: '=',
                ticks: '=',
                ticksLabels: '=',
                ticksSnapBounds: '=',
                ticksPositions: '=',
                scale: '=',
                focus: '=',
                formatter: '&',
                onStartSlide: '&',
                onStopSlide: '&',
                onSlide: '&'
            },
            link: function ($scope, element, attrs, ngModelCtrl, $compile) {
                var ngModelDeregisterFn, ngDisabledDeregisterFn;

                var slider = initSlider();

                function initSlider() {
                    var options = {};

                    function setOption(key, value, defaultValue) {
                        options[key] = value || defaultValue;
                    }

                    function setFloatOption(key, value, defaultValue) {
                        options[key] = value || value === 0 ? parseFloat(value) : defaultValue;
                    }

                    function setBooleanOption(key, value, defaultValue) {
                        options[key] = value ? value + '' === 'true' : defaultValue;
                    }

                    function getArrayOrValue(value) {
                        return (angular.isString(value) && value.indexOf("[") === 0) ? angular.fromJson(value) : value;
                    }

                    setOption('id', $scope.sliderid);
                    setOption('orientation', attrs.orientation, 'horizontal');
                    setOption('selection', attrs.selection, 'before');
                    setOption('handle', attrs.handle, 'round');
                    setOption('tooltip', attrs.sliderTooltip || attrs.tooltip, 'show');
                    setOption('tooltip_position', attrs.sliderTooltipPosition, 'top');
                    setOption('tooltipseparator', attrs.tooltipseparator, ':');
                    setOption('ticks', $scope.ticks);
                    setOption('ticks_labels', $scope.ticksLabels);
                    setOption('ticks_snap_bounds', $scope.ticksSnapBounds);
                    setOption('ticks_positions', $scope.ticksPositions);
                    setOption('scale', $scope.scale, 'linear');
                    setOption('focus', $scope.focus);

                    setFloatOption('min', $scope.min, 0);
                    setFloatOption('max', $scope.max, 10);
                    setFloatOption('step', $scope.step, 1);
                    var strNbr = options.step + '';
                    var dotPos = strNbr.search(/[^.,]*$/);
                    var decimals = strNbr.substring(dotPos);
                    setFloatOption('precision', attrs.precision, decimals.length);

                    setBooleanOption('tooltip_split', attrs.tooltipsplit, false);
                    setBooleanOption('enabled', attrs.enabled, true);
                    setBooleanOption('naturalarrowkeys', attrs.naturalarrowkeys, false);
                    setBooleanOption('reversed', attrs.reversed, false);

                    setBooleanOption('range', $scope.range, false);
                    if (options.range) {
                        if (angular.isArray($scope.value)) {
                            options.value = $scope.value;
                        }
                        else if (angular.isString($scope.value)) {
                            options.value = getArrayOrValue($scope.value);
                            if (!angular.isArray(options.value)) {
                                var value = parseFloat($scope.value);
                                if (isNaN(value)) value = 5;

                                if (value < $scope.min) {
                                    value = $scope.min;
                                    options.value = [value, options.max];
                                }
                                else if (value > $scope.max) {
                                    value = $scope.max;
                                    options.value = [options.min, value];
                                }
                                else {
                                    options.value = [options.min, options.max];
                                }
                            }
                        }
                        else {
                            options.value = [options.min, options.max]; // This is needed, because of value defined at $.fn.slider.defaults - default value 5 prevents creating range slider
                        }
                        $scope.ngModel = options.value; // needed, otherwise turns value into [null, ##]
                    }
                    else {
                        setFloatOption('value', $scope.value, 5);
                    }

                    if (attrs.formatter) {
                        options.formatter = function(value) {
                            return $scope.formatter({value: value});
                        }
                    }

                    // check if slider jQuery plugin exists
                    if ('$' in window && $.fn.slider) {
                        // adding methods to jQuery slider plugin prototype
                        $.fn.slider.constructor.prototype.disable = function () {
                            this.picker.off();
                        };
                        $.fn.slider.constructor.prototype.enable = function () {
                            this.picker.on();
                        };
                    }

                    // destroy previous slider to reset all options
                    if (element[0].__slider)
                        element[0].__slider.destroy();

                    var slider = new Slider(element[0].getElementsByClassName('slider-input')[0], options);
                    element[0].__slider = slider;

                    // everything that needs slider element
                    var updateEvent = getArrayOrValue(attrs.updateevent);
                    if (angular.isString(updateEvent)) {
                        // if only single event name in string
                        updateEvent = [updateEvent];
                    }
                    else {
                        // default to slide event
                        updateEvent = ['slide'];
                    }
                    angular.forEach(updateEvent, function (sliderEvent) {
                        slider.on(sliderEvent, function (ev) {
                            ngModelCtrl.$setViewValue(ev);
                        });
                    });
                    slider.on('change', function (ev) {
                        ngModelCtrl.$setViewValue(ev.newValue);
                    });

                    // Event listeners
                    var sliderEvents = {
                        slideStart: 'onStartSlide',
                        slide: 'onSlide',
                        slideStop: 'onStopSlide'
                    };
                    angular.forEach(sliderEvents, function (sliderEventAttr, sliderEvent) {
                        var fn = $parse(attrs[sliderEventAttr.toLowerCase()]);
                        slider.on(sliderEvent, function (ev) {
                            if ($scope[sliderEventAttr]) {
                                $scope.$apply(function () {
                                    fn($scope.$parent, { $event: sliderEvent, value: ev });
                                });
                            }
                        });
                    });

                    // deregister ngDisabled watcher to prevent memory leaks
                    if (angular.isFunction(ngDisabledDeregisterFn)) {
                        ngDisabledDeregisterFn();
                        ngDisabledDeregisterFn = null;
                    }

                    ngDisabledDeregisterFn = $scope.$watch('ngDisabled', function (value) {
                        if (value) {
                            slider.disable();
                        }
                        else {
                            slider.enable();
                        }
                    });

                    // deregister ngModel watcher to prevent memory leaks
                    if (angular.isFunction(ngModelDeregisterFn)) ngModelDeregisterFn();
                    ngModelDeregisterFn = $scope.$watch('ngModel', function (value) {
                        if($scope.range){
                            slider.setValue(value);
                        }else{
                            slider.setValue(parseFloat(value));
                        }
                        slider.relayout();
                    }, true);

                    return slider;
                }

                var watchers = ['min', 'max', 'step', 'range', 'scale', 'ticksLabels'];
                angular.forEach(watchers, function (prop) {
                    $scope.$watch(prop, function () {
                        slider = initSlider();
                    });
                });

                $scope.$on('slider:relayout', function() {
                    slider.relayout();
                });
            }
        };
    }])
;
<|endoftext|>


<commit_before>const express = require('express');
const path = require('path');
const fs = require('fs');
const pug = require('pug');
const request = require('request');
const cheerio = require('cheerio');

const app = express();

app.set('views', './views')
app.set('view engine', 'pug');
app.use(express.static(path.join(__dirname, '/')));

//
// API: /
// --------------------------------------------------------------------------
app.get('/', function(req, res) {

	// Scrape GO Transit main page
  const url = 'http://www.gotransit.com/publicroot/en/default.aspx';
  var timestamp;
  var trainsArr = [];

  // Supply formatted, scraped data to render of pug
  request(url, function(error, response, html) {
		if (!error) {
			var name, status, smallDelay, bigDelay;
			var names = [];
	    var $ = cheerio.load(html);
	    timestamp = $('.timestamp div span').html();
	    // Returns all train lines
	    var trains = $('#rtab1 .gridStatusTrain tbody tr');
	    // If empty, no trains are delayed
	    var trainsDelayed = trains.has('.delayLink');

	    for (var i = 0; i < trains.length; i++) {
	    	name = $(trains[i.toString()]).find('.gridStatusWidthOne').text();
	    	// console.log(name);

	    	// Set default status to On time
	    	status = "On time";
	    	// Check if
 contains info within one of its children
	    	smallDelay = $(trains[i.toString()]).has('.delayLink');
	    	// Check if
 has link to URL with additional info
	    	bigDelay = $(trains[i.toString()]).has('.moreInfoLink');

	    	// If
 contains an element
	    	// with either .delayLink or
	    	// .moreInfoLink, it's delayed
	    	if (smallDelay.length > 0) {
	    		status = "Delayed";

	    		// If the current retrieved train line is delayed,
	    		// find info about it
	    		var statusText, direction, details;
	    		var statusArr = [];
	    		var statusPopovers = $(trains[i.toString()]).find('.messageDisrp');

		    	for (var j = 0; j < statusPopovers.length; j++) {
		    		if ($(statusPopovers[j.toString()]).find('h3').text() === name) {
		    			direction = $(statusPopovers[j.toString()]).find('.subtitle h4').text();
		    			details = $(statusPopovers[j.toString()]).find('li > span');

		    			for (var k = 0; k < details.length; k++) {
		    				// Iterate through known delays,
		    				// save their data to statusArr[]
		    				var detail = details[k.toString()];
		    				// Data within the . Contains up to 7 children. (As of 12/01/2016)
			    			// Counts text as an Object?
			    			// [0] = Which train time is delayed (e.x., Union Station 22:13 - Aldershot GO 23:31)
			    			// [1] =

			    			// [2] = Length of delay (e.x., Delay of 7m:53s)
			    			// [3] =

			    			// [4] = State of train (e.x., Moving)
			    			// [5] =

			    			// [6] = Additional state of train (e.x., Waiting on a train ahead)
		    				statusArr.push({
		    					"delayDirection": direction,
		    					"delayedTrain": detail.children[0].data,
		    					"delayLength": detail.children[2].data,
		    					"delayStatus": detail.children[4].data
		    				});
		    			}

		    			// Data within the . Contains up to 7 children. (As of 12/01/2016)
		    			// Counts text as an Object?
		    			// [0] = Which train time is delayed (e.x., Union Station 22:13 - Aldershot GO 23:31)
		    			// [1] =

		    			// [2] = Length of delay (e.x., Delay of 7m:53s)
		    			// [3] =

		    			// [4] = State of train (e.x., Moving)
		    			// [5] =

		    			// [6] = Additional state of train (e.x., Waiting on a train ahead)
		    		}
		    	}
	    	}
	    	else if (bigDelay.length > 0) {
	    		status = "Delayed";

	    		// If the current retrieved train line is delayed,
	    		// find info about it
	    		var statusText, details;
	    		var statusArr = [];
	    		var moreInfoURL = $(trains[i.toString()]).find('.moreInfoLink').attr('href');

	    		request(moreInfoURL, function(error, response, html) {
	    			if (!error) {
					    var $ = cheerio.load(html);
					    var content = $('.tabs_tab').prop('style');
					    console.log(content);
					    statusArr.push({
					    	"delayMsg": "Errro retrieving message"
					    })
					  }
	    		});
	    	}

	    	// Push retrieved train line info
	    	// to trains array
	    	trainsArr.push({
	    		"name": name,
	    		"status": status,
	    		"direction": direction,
	    		"details": statusArr
	    	})
	    }
    }
    res.render('index', { "retrieveTime": timestamp, "trains": trainsArr });
	});
});

//
// API: /fetch
// --------------------------------------------------------------------------
app.get('/fetch', (req, res) => {
	var url = 'http://www.gotransit.com/publicroot/en/default.aspx';
	var trainsArr = [];
	var timestamp;

	request(url, function(error, response, html) {
		if (!error) {
      var $ = cheerio.load(html);
	    timestamp = $('.timestamp div span').html();
	    // Returns all train lines
	    var trains = $('#rtab1 .gridStatusTrain tbody tr');
	    // If empty, no trains are delayed
	    var trainsDelayed = trains.has('.delayLink');

	    for (var i = 0; i < trains.length; i++) {
	    	var name = $(trains[i.toString()]).find('.gridStatusWidthOne').text();
	    	var status = $(trains[i.toString()]).has('.delayLink').length === 0 ? "On time" : "Delayed";

	    	// Push retrieved train line info
	    	// to trains array
	    	trainsArr.push({
	    		"name": name,
	    		"status": status
	    	})
	    }
    }
    res.json({"timestamp": timestamp, "trains": trainsArr});
	});
});

app.trainsAreDelayed = function() {
	var url = 'http://www.gotransit.com/publicroot/en/default.aspx';

  request(url, function(error, response, html) {
      if (!error) {
          // Next, we'll utilize the cheerio library on the returned html which will essentially give us jQuery functionality
          var $ = cheerio.load(html);
          var trains = $('.gridStatusTrain tbody tr');
          var trainsDelayed = trains.has('.delayLink');

          // If trainsDelayed.length is 0, none are delayed
          if (trainsDelayed.length === 0) {
          	return false;
          }
          else {
          	return true;
          }
      }
  });
}

app.listen(process.env.PORT || 5000);

exports = module.exports = app;<commit_msg>Keep track of delayed train names in array visible to bigDelay section<commit_after>const express = require('express');
const path = require('path');
const fs = require('fs');
const pug = require('pug');
const request = require('request');
const cheerio = require('cheerio');

const app = express();

app.set('views', './views')
app.set('view engine', 'pug');
app.use(express.static(path.join(__dirname, '/')));

//
// API: /
// --------------------------------------------------------------------------
app.get('/', function(req, res) {

	// Scrape GO Transit main page
  const url = 'http://www.gotransit.com/publicroot/en/default.aspx';
  var timestamp;
  var trainsArr = [];

  // Supply formatted, scraped data to render of pug
  request(url, function(error, response, html) {
		if (!error) {
			var name, status, smallDelay, bigDelay;
			var names = [];
	    var $ = cheerio.load(html);
	    timestamp = $('.timestamp div span').html();
	    // Returns all train lines
	    var trains = $('#rtab1 .gridStatusTrain tbody tr');
	    // If empty, no trains are delayed
	    var trainsDelayed = trains.has('.delayLink');

	    for (var i = 0; i < trains.length; i++) {
	    	name = $(trains[i.toString()]).find('.gridStatusWidthOne').text();
	    	// console.log(name);

	    	// Set default status to On time
	    	status = "On time";
	    	// Check if
 contains info within one of its children
	    	smallDelay = $(trains[i.toString()]).has('.delayLink');
	    	// Check if
 has link to URL with additional info
	    	bigDelay = $(trains[i.toString()]).has('.moreInfoLink');

	    	// If
 contains an element
	    	// with either .delayLink or
	    	// .moreInfoLink, it's delayed
	    	if (smallDelay.length > 0) {
	    		status = "Delayed";

	    		// If the current retrieved train line is delayed,
	    		// find info about it
	    		var statusText, direction, details;
	    		var statusArr = [];
	    		var statusPopovers = $(trains[i.toString()]).find('.messageDisrp');

		    	for (var j = 0; j < statusPopovers.length; j++) {
		    		if ($(statusPopovers[j.toString()]).find('h3').text() === name) {
		    			direction = $(statusPopovers[j.toString()]).find('.subtitle h4').text();
		    			details = $(statusPopovers[j.toString()]).find('li > span');

		    			for (var k = 0; k < details.length; k++) {
		    				// Iterate through known delays,
		    				// save their data to statusArr[]
		    				var detail = details[k.toString()];
		    				// Data within the . Contains up to 7 children. (As of 12/01/2016)
			    			// Counts text as an Object?
			    			// [0] = Which train time is delayed (e.x., Union Station 22:13 - Aldershot GO 23:31)
			    			// [1] =

			    			// [2] = Length of delay (e.x., Delay of 7m:53s)
			    			// [3] =

			    			// [4] = State of train (e.x., Moving)
			    			// [5] =

			    			// [6] = Additional state of train (e.x., Waiting on a train ahead)
		    				statusArr.push({
		    					"delayDirection": direction,
		    					"delayedTrain": detail.children[0].data,
		    					"delayLength": detail.children[2].data,
		    					"delayStatus": detail.children[4].data
		    				});
		    			}

		    			// Data within the . Contains up to 7 children. (As of 12/01/2016)
		    			// Counts text as an Object?
		    			// [0] = Which train time is delayed (e.x., Union Station 22:13 - Aldershot GO 23:31)
		    			// [1] =

		    			// [2] = Length of delay (e.x., Delay of 7m:53s)
		    			// [3] =

		    			// [4] = State of train (e.x., Moving)
		    			// [5] =

		    			// [6] = Additional state of train (e.x., Waiting on a train ahead)
		    		}
		    	}
	    	}
	    	else if (bigDelay.length > 0) {
	    		names.push(name);
	    		status = "Delayed";

	    		// If the current retrieved train line is delayed,
	    		// find info about it
	    		var statusText, details;
	    		var statusArr = [];
	    		var moreInfoURL = $(trains[i.toString()]).find('.moreInfoLink').attr('href');

	    		request(moreInfoURL, function(error, response, html) {
	    			if (!error) {
					    var $ = cheerio.load(html);
					    var content = $('.tabs_tab').prop('style');
					    console.log(content);
					    statusArr.push({
					    	"delayMsg": "Errro retrieving message"
					    })
					  }
	    		});
	    	}

	    	// Push retrieved train line info
	    	// to trains array
	    	trainsArr.push({
	    		"name": name,
	    		"status": status,
	    		"direction": direction,
	    		"details": statusArr
	    	})
	    }
    }
    res.render('index', { "retrieveTime": timestamp, "trains": trainsArr });
	});
});

//
// API: /fetch
// --------------------------------------------------------------------------
app.get('/fetch', (req, res) => {
	var url = 'http://www.gotransit.com/publicroot/en/default.aspx';
	var trainsArr = [];
	var timestamp;

	request(url, function(error, response, html) {
		if (!error) {
      var $ = cheerio.load(html);
	    timestamp = $('.timestamp div span').html();
	    // Returns all train lines
	    var trains = $('#rtab1 .gridStatusTrain tbody tr');
	    // If empty, no trains are delayed
	    var trainsDelayed = trains.has('.delayLink');

	    for (var i = 0; i < trains.length; i++) {
	    	var name = $(trains[i.toString()]).find('.gridStatusWidthOne').text();
	    	var status = $(trains[i.toString()]).has('.delayLink').length === 0 ? "On time" : "Delayed";

	    	// Push retrieved train line info
	    	// to trains array
	    	trainsArr.push({
	    		"name": name,
	    		"status": status
	    	})
	    }
    }
    res.json({"timestamp": timestamp, "trains": trainsArr});
	});
});

app.trainsAreDelayed = function() {
	var url = 'http://www.gotransit.com/publicroot/en/default.aspx';

  request(url, function(error, response, html) {
      if (!error) {
          // Next, we'll utilize the cheerio library on the returned html which will essentially give us jQuery functionality
          var $ = cheerio.load(html);
          var trains = $('.gridStatusTrain tbody tr');
          var trainsDelayed = trains.has('.delayLink');

          // If trainsDelayed.length is 0, none are delayed
          if (trainsDelayed.length === 0) {
          	return false;
          }
          else {
          	return true;
          }
      }
  });
}

app.listen(process.env.PORT || 5000);

exports = module.exports = app;<|endoftext|>


<commit_before>Seed({
		name : "Mold.DNA.UrlRouter",
		dna : "dna",
		author : "Jan Kaufmann",
		include : [
			"Mold.Lib.GlobalEvents",
			"Mold.Lib.UrlRouter"
		]
	},
	{
		name : "urlrouter",
		create : function(seed){

			if(typeof seed.func === "object"){
				var urlRouter = new Mold.Lib.UrlRouter(seed);
				//Mold.DNA.UrlRouter.init(seed);
				urlRouter.initRoutes();
				if(typeof window != "undefined" && window){
					if(seed.onhashchange && seed.onhashchange === "update"){
						window.addEventListener("hashchange", urlRouter.initRoutes, false);
					}
				}else if(Mold.isNodeJS){
					Mold.Lib.GlobalEvents.on("location.update", function(data){
						urlRouter.setLocation(data.data.location );
						urlRouter.setServerParameter(data.data.request, data.data.response, data.data.session);
						urlRouter.initRoutes();
					});
				}
			}

		}
	}
);<commit_msg>GlobalEvents renamed to Observer<commit_after>Seed({
		name : "Mold.DNA.UrlRouter",
		dna : "dna",
		author : "Jan Kaufmann",
		include : [
			"Mold.Lib.Observer",
			"Mold.Lib.UrlRouter"
		]
	},
	{
		name : "urlrouter",
		create : function(seed){

			if(typeof seed.func === "object"){
				var urlRouter = new Mold.Lib.UrlRouter(seed);
				//Mold.DNA.UrlRouter.init(seed);
				urlRouter.initRoutes();
				if(typeof window != "undefined" && window){
					if(seed.onhashchange && seed.onhashchange === "update"){
						window.addEventListener("hashchange", urlRouter.initRoutes, false);
					}
				}else if(Mold.isNodeJS){
					Mold.Lib.Observer.sub("location.update", function(data){
						urlRouter.setLocation(data.data.location );
						urlRouter.setServerParameter(data.data.request, data.data.response, data.data.session);
						urlRouter.initRoutes();
					});
				}
			}

		}
	}
);<|endoftext|>


<commit_before>var NUM_COLUMNS = 12;

/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_new(performance) {

  var div = document.createElement("div");
  div.id = makeid(20);
  var name = performance.name;

  div.comm = comm_new(div, performance.name); //Create comm object for communictiation with the server.
  performance.comm = div.comm;

  performance.add_notify_rank(p_div_rank_updated, div);
  performance.add_notify_score(p_div_score_updated, div);

  var row = document.createElement("div");
  row.className = 'row';
  var column = document.createElement('div');
  column.className = 'small-11 columns';
  column.innerHTML = "
 " + name + "
";
  row.appendChild(column);

  var column = document.createElement("div");
  column.className = 'small-1 columns';

  var remove_me = make_remove_me_div(div);
  column.appendChild(remove_me);
  row.appendChild(column);

  div.appendChild(row);

  div.column_length = {Judges: slam.num_judges, Time: 2, Penalty: 1, Score: 1, Subscore: 1, "Total Score": 1, Rank:1};
  div.titles = ["Judges", "Time", "Penalty", "Score", "Subscore", "Total Score", "Rank"];
  p_div_build_columns_hash(div);

  div.performance = performance;

//  p_div_build_titles_row(div);
  p_div_build_sub_titles(div);
  p_div_build_data_row(div);
  p_div_build_footers(div);

  div.style.backgroundColor = '#F4F4F4';
  div.style.borderStyle = 'solid';
  div.style.borderWidth = '1px';

  row = document.createElement("div");
  row.className = "row";

  column = document.createElement("div");
  column.className = "small-12 columns";
  column.style.minHeight = "15px"; //http://stackoverflow.com/a/25431669

  row.appendChild(column);
  div.appendChild(row);

  return div;
}

/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_build_columns_hash(div) {

  var num_columns = 12;

  var columns = div.columns = {};
  var titles = div.titles;

  var remaining_columns = num_columns;
  for (var i=0; i<titles.length; i++) {
    columns[titles[i]] = remaining_columns;
    remaining_columns -= div.column_length[titles[i]];

    if (i > 0) {
      for (j=0; j<i; j++) {
	columns[titles[j]] = div.column_length[titles[j]];
      }
    }
  }
}
/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_build_titles_row(div) {

  var row = document.createElement("div");
  row.className = "row";

  for (var i=0; i<div.titles.length; i++) {

    var column = document.createElement("div");
    column.className = "small-" + div.columns[div.titles[i]] + " columns";
    column.innerHTML = "" + div.titles[i] + "";

    row.appendChild(column);

  }
  div.appendChild(row);
}
/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_build_sub_titles(div) {

  var num_columns = 12;

  var row = document.createElement("div");
  row.className = "row";

  // Add Judges
  var column;
  for (var i=0; i<slam.num_judges; i++) {

    column = document.createElement("div");

    column.className = "small-1 columns";
    column.innerHTML = "" + (i + 1) + "";

    row.appendChild(column);
  }
  // Add Timel
  column = document.createElement("div");
  column.className = "small-1 columns";
  column.innerHTML = "m";
  row.appendChild(column);

  column = document.createElement("div");
  column.className = "small-" + (num_columns - slam.num_judges -1) + " columns";
  column.innerHTML = "s";
  row.appendChild(column);

  div.appendChild(row);
}

/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_setup_indexes(div) {

  div.data_columns = [];
  div.indexes = {};

  var i = slam.num_judges;

  div.indexes.minutes_i = i++;
  div.indexes.seconds_i = i++;
  div.indexes.penalty_i = i++;
  div.indexes.score_i = i++;
  div.indexes.subscore_i = i++;
  div.indexes.total_score_i = i++;
  div.indexes.rank = i;
}
/*----------------------------------------------------------------------------------------------------------------------------------*/
function format_value(value) {

  // Return a value that has at most one decimal place.
  return Math.round(value * 100) / 100;
}
/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_update_data_column(div, index, value) {
  div.data_columns[index].innerHTML = format_value(value);
}

/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_score_updated(div, performance) {

  p_div_update_data_column(div, div.indexes.score_i, performance.score);
  p_div_update_data_column(div, div.indexes.subscore_i, performance.subscore);
  p_div_update_data_column(div, div.indexes.total_score_i, performance.poet.total_score);

  var min_i = performance.min_judge;
  var max_i = performance.max_judge;

  if (slam.do_not_include_min_and_max_scores) {
    for (var i=0; i<slam.num_judges; i++)
      div.footers[i].innerHTML = "

";

    div.footers[min_i].innerHTML = "LOW";
    div.footers[min_i].style.color = "red";

    div.footers[max_i].innerHTML = "HIGH";
    div.footers[max_i].style.color = "red";
  }
  // Time Penalty

  var time_penalty = performance.calculate_time_penalty() * -1;
  if (time_penalty != 0){
    div.footers[slam.num_judges].innerHTML = "P:";
    div.footers[slam.num_judges].style.color = "green";
    div.footers[slam.num_judges + 1].innerHTML = time_penalty;
    div.footers[slam.num_judges + 1].style.color = "green";
  }
  else {
    div.footers[slam.num_judges].innerHTML = "

";
    div.footers[slam.num_judges + 1].innerHTML = "

";
  }
}
/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_rank_updated (div, performance) {

  div.data_columns[div.indexes.rank].innerHTML = performance.rank;
}
/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_get_time(div) {

  var minutes = parse_int_or_return_zero(div.data_columns[div.indexes.minutes_i].value);
  var seconds = parse_int_or_return_zero(div.data_columns[div.indexes.seconds_i].value);

  return {minutes: minutes, seconds: seconds};
}

/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_input_entered(input) {

  if (!login_info.is_logged_in)
    return;

  var i = parseInt(input.getAttribute('data-index'));
  var div = input.div;
  var performance = div.performance;

  var value = parse_float_or_return_zero(input.value);

  switch (i)
  {
    case div.indexes.minutes_i:
    case div.indexes.seconds_i:
      var time = p_div_get_time(div);
      performance.set_time(time.minutes, time.seconds);
      set_time_request(performance.comm, time.minutes, time.seconds);
      break;
    case div.indexes.penalty_i:
      performance.set_penalty(value);
      set_penalty_request(performance.comm, value);
      break;
    default:
      if (i >= 0 && i < div.indexes.minutes_i) {
	var value = input.value /= 10;
	input.value = value;
	performance.judge(i, value);
	judge_request(performance.comm, i, value);
      }
  }
}

/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_set_score(p_div, judge_i, value) {

  p_div.data_columns[judge_i].value = value;
  p_div.performance.judge(judge_i, value);
}

/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_set_time(p_div, minutes, seconds) {

  var i = p_div.indexes.minutes_i;

  p_div.data_columns[i].value = minutes;
  p_div.data_columns[++i].value = seconds;

  p_div.performance.set_time(minutes, seconds);
}

/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_set_penalty(p_div, value) {

  var i = p_div.indexes.penalty_i;

  p_div.data_columns[i].value = value;

  p_div.performance.set_penalty(value);
}
/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_build_data_row(div) {

  p_div_setup_indexes(div);

  var row = document.createElement("div");
  row.className = "row";

  var num_columns = slam.num_judges + 3; // Judges + Minutes + Seconds + Penalty

  var i;
  for (i=0; i<num_columns; i++) {
    var column = document.createElement("div");
    column.className = "small-1 columns";

    var input = document.createElement("input");
    input.div = div;
    input.className =  "scorekeeper_input";
    input.setAttribute('size', 4);
    input.setAttribute('onchange', 'p_div_input_entered(this)');
    input.setAttribute('data-index', i);

    if (!login_info.is_logged_in)
      input.setAttribute('readonly', null);

    column.appendChild(input);
    div.data_columns.push(input);

    row.appendChild(column);
  }

  num_columns = 12;
  for (; i< num_columns; i++) {

    var column = document.createElement("div");
    column.className = "small-1 columns";
    row.appendChild(column);

    div.data_columns.push(column);
  }

  div.appendChild(row);
}
/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_build_footers(div) {

  div.footers = [];

  var num_columns = 12;
  var row = document.createElement("div");
  row.className = "row";

  for (var i=0; i<num_columns; i++) {

    var column = document.createElement("div");
    column.className = "small-1 columns";
    column.innerHTML = "

";

    row.appendChild(column);
    div.footers.push(column);
  }

  div.appendChild(row);
}
/*----------------------------------------------------------------------------------------------------------------------------------*/

<commit_msg>setting input.type = "number" to make it easier to enter scores/times/penalties<commit_after>var NUM_COLUMNS = 12;

/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_new(performance) {

  var div = document.createElement("div");
  div.id = makeid(20);
  var name = performance.name;

  div.comm = comm_new(div, performance.name); //Create comm object for communictiation with the server.
  performance.comm = div.comm;

  performance.add_notify_rank(p_div_rank_updated, div);
  performance.add_notify_score(p_div_score_updated, div);

  var row = document.createElement("div");
  row.className = 'row';
  var column = document.createElement('div');
  column.className = 'small-11 columns';
  column.innerHTML = "
 " + name + "
";
  row.appendChild(column);

  var column = document.createElement("div");
  column.className = 'small-1 columns';

  var remove_me = make_remove_me_div(div);
  column.appendChild(remove_me);
  row.appendChild(column);

  div.appendChild(row);

  div.column_length = {Judges: slam.num_judges, Time: 2, Penalty: 1, Score: 1, Subscore: 1, "Total Score": 1, Rank:1};
  div.titles = ["Judges", "Time", "Penalty", "Score", "Subscore", "Total Score", "Rank"];
  p_div_build_columns_hash(div);

  div.performance = performance;

//  p_div_build_titles_row(div);
  p_div_build_sub_titles(div);
  p_div_build_data_row(div);
  p_div_build_footers(div);

  div.style.backgroundColor = '#F4F4F4';
  div.style.borderStyle = 'solid';
  div.style.borderWidth = '1px';

  row = document.createElement("div");
  row.className = "row";

  column = document.createElement("div");
  column.className = "small-12 columns";
  column.style.minHeight = "15px"; //http://stackoverflow.com/a/25431669

  row.appendChild(column);
  div.appendChild(row);

  return div;
}

/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_build_columns_hash(div) {

  var num_columns = 12;

  var columns = div.columns = {};
  var titles = div.titles;

  var remaining_columns = num_columns;
  for (var i=0; i<titles.length; i++) {
    columns[titles[i]] = remaining_columns;
    remaining_columns -= div.column_length[titles[i]];

    if (i > 0) {
      for (j=0; j<i; j++) {
	columns[titles[j]] = div.column_length[titles[j]];
      }
    }
  }
}
/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_build_titles_row(div) {

  var row = document.createElement("div");
  row.className = "row";

  for (var i=0; i<div.titles.length; i++) {

    var column = document.createElement("div");
    column.className = "small-" + div.columns[div.titles[i]] + " columns";
    column.innerHTML = "" + div.titles[i] + "";

    row.appendChild(column);

  }
  div.appendChild(row);
}
/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_build_sub_titles(div) {

  var num_columns = 12;

  var row = document.createElement("div");
  row.className = "row";

  // Add Judges
  var column;
  for (var i=0; i<slam.num_judges; i++) {

    column = document.createElement("div");

    column.className = "small-1 columns";
    column.innerHTML = "" + (i + 1) + "";

    row.appendChild(column);
  }
  // Add Timel
  column = document.createElement("div");
  column.className = "small-1 columns";
  column.innerHTML = "m";
  row.appendChild(column);

  column = document.createElement("div");
  column.className = "small-" + (num_columns - slam.num_judges -1) + " columns";
  column.innerHTML = "s";
  row.appendChild(column);

  div.appendChild(row);
}

/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_setup_indexes(div) {

  div.data_columns = [];
  div.indexes = {};

  var i = slam.num_judges;

  div.indexes.minutes_i = i++;
  div.indexes.seconds_i = i++;
  div.indexes.penalty_i = i++;
  div.indexes.score_i = i++;
  div.indexes.subscore_i = i++;
  div.indexes.total_score_i = i++;
  div.indexes.rank = i;
}
/*----------------------------------------------------------------------------------------------------------------------------------*/
function format_value(value) {

  // Return a value that has at most one decimal place.
  return Math.round(value * 100) / 100;
}
/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_update_data_column(div, index, value) {
  div.data_columns[index].innerHTML = format_value(value);
}

/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_score_updated(div, performance) {

  p_div_update_data_column(div, div.indexes.score_i, performance.score);
  p_div_update_data_column(div, div.indexes.subscore_i, performance.subscore);
  p_div_update_data_column(div, div.indexes.total_score_i, performance.poet.total_score);

  var min_i = performance.min_judge;
  var max_i = performance.max_judge;

  if (slam.do_not_include_min_and_max_scores) {
    for (var i=0; i<slam.num_judges; i++)
      div.footers[i].innerHTML = "

";

    div.footers[min_i].innerHTML = "LOW";
    div.footers[min_i].style.color = "red";

    div.footers[max_i].innerHTML = "HIGH";
    div.footers[max_i].style.color = "red";
  }
  // Time Penalty

  var time_penalty = performance.calculate_time_penalty() * -1;
  if (time_penalty != 0){
    div.footers[slam.num_judges].innerHTML = "P:";
    div.footers[slam.num_judges].style.color = "green";
    div.footers[slam.num_judges + 1].innerHTML = time_penalty;
    div.footers[slam.num_judges + 1].style.color = "green";
  }
  else {
    div.footers[slam.num_judges].innerHTML = "

";
    div.footers[slam.num_judges + 1].innerHTML = "

";
  }
}
/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_rank_updated (div, performance) {

  div.data_columns[div.indexes.rank].innerHTML = performance.rank;
}
/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_get_time(div) {

  var minutes = parse_int_or_return_zero(div.data_columns[div.indexes.minutes_i].value);
  var seconds = parse_int_or_return_zero(div.data_columns[div.indexes.seconds_i].value);

  return {minutes: minutes, seconds: seconds};
}

/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_input_entered(input) {

  if (!login_info.is_logged_in)
    return;

  var i = parseInt(input.getAttribute('data-index'));
  var div = input.div;
  var performance = div.performance;

  var value = parse_float_or_return_zero(input.value);

  switch (i)
  {
    case div.indexes.minutes_i:
    case div.indexes.seconds_i:
      var time = p_div_get_time(div);
      performance.set_time(time.minutes, time.seconds);
      set_time_request(performance.comm, time.minutes, time.seconds);
      break;
    case div.indexes.penalty_i:
      performance.set_penalty(value);
      set_penalty_request(performance.comm, value);
      break;
    default:
      if (i >= 0 && i < div.indexes.minutes_i) {
	var value = input.value /= 10;
	input.value = value;
	performance.judge(i, value);
	judge_request(performance.comm, i, value);
      }
  }
}

/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_set_score(p_div, judge_i, value) {

  p_div.data_columns[judge_i].value = value;
  p_div.performance.judge(judge_i, value);
}

/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_set_time(p_div, minutes, seconds) {

  var i = p_div.indexes.minutes_i;

  p_div.data_columns[i].value = minutes;
  p_div.data_columns[++i].value = seconds;

  p_div.performance.set_time(minutes, seconds);
}

/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_set_penalty(p_div, value) {

  var i = p_div.indexes.penalty_i;

  p_div.data_columns[i].value = value;

  p_div.performance.set_penalty(value);
}
/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_build_data_row(div) {

  p_div_setup_indexes(div);

  var row = document.createElement("div");
  row.className = "row";

  var num_columns = slam.num_judges + 3; // Judges + Minutes + Seconds + Penalty

  var i;
  for (i=0; i<num_columns; i++) {
    var column = document.createElement("div");
    column.className = "small-1 columns";

    var input = document.createElement("input");
    input.div = div;
    input.className =  "scorekeeper_input";
    input.setAttribute('size', 4);
    input.setAttribute('onchange', 'p_div_input_entered(this)');
    input.setAttribute('data-index', i);
    input.type = "number";

    if (!login_info.is_logged_in)
      input.setAttribute('readonly', null);

    column.appendChild(input);
    div.data_columns.push(input);

    row.appendChild(column);
  }

  num_columns = 12;
  for (; i< num_columns; i++) {

    var column = document.createElement("div");
    column.className = "small-1 columns";
    row.appendChild(column);

    div.data_columns.push(column);
  }

  div.appendChild(row);
}
/*----------------------------------------------------------------------------------------------------------------------------------*/
function p_div_build_footers(div) {

  div.footers = [];

  var num_columns = 12;
  var row = document.createElement("div");
  row.className = "row";

  for (var i=0; i<num_columns; i++) {

    var column = document.createElement("div");
    column.className = "small-1 columns";
    column.innerHTML = "

";

    row.appendChild(column);
    div.footers.push(column);
  }

  div.appendChild(row);
}
/*----------------------------------------------------------------------------------------------------------------------------------*/

<|endoftext|>