<commit_before>import React, { PropTypes } from 'react';

import ChangesLinks from 'es6!display/changes/links';
import { ChangesPage, APINotLoadedPage } from 'es6!display/page_chrome';
import { Grid } from 'es6!display/grid';
import { SingleBuildStatus } from 'es6!display/changes/builds';
import { TimeText, display_duration_pieces } from 'es6!display/time';
import { WaitingLiveText } from 'es6!display/changes/build_text';
import { get_runnable_condition,
         get_runnable_condition_color_cls,
         is_waiting } from 'es6!display/changes/build_conditions';

import * as api from 'es6!server/api';

import * as utils from 'es6!utils/utils';

// how often to hit the api server for updates
var POLL_INTERVAL = 10000;

/*
 * Modern query params:
 * - branch: select branch to display.
 * - project: pass multiple times to select projects to display. The value
 *   should be a project slug. All projects should be for the same repo.
 *
 * Antiquated query params: main (multiple times)
 * - The first main parameter determines the list of commits to show.
 *   Additional main parameters will show latest builds for that commit.
 * - A parameter can be just a project slug, or slug::branch.
 */
var PusherPage = React.createClass({

  getInitialTitle: function() {
    return 'Dashboard';
  },

  getInitialState: function() {
    var endpoints = this.getEndpoints();

    var state = {};
    _.each(_.keys(endpoints), key => {
      state[key] = null;
    });
    return state;
  },

  componentDidMount: function() {
    api.fetch(this, this.getEndpoints());

    this.updateInProgress = false;
    this.refreshTimer = window.setInterval(__ => {
      if (!this.isMounted()) {
        return;
      }
      this.liveUpdate();
    }, POLL_INTERVAL);
  },

  render: function() {
    if (this.updateInProgress) {
      if (api.allLoaded(_.values(this.state.liveUpdate))) {
        this.updateInProgress = false;
        utils.async(__ => {
          var emptyLiveUpdate = _.mapObject(this.getEndpoints(), (v, k) => null);
          this.setState(_.extend(
            {liveUpdate: emptyLiveUpdate},
            this.state.liveUpdate));
        });
      }
    }

    var [slugs, branch] = this.getSlugsAndBranch();
    var endpoints = this.getEndpoints();
    var apiResponses = _.map(endpoints, (v, k) => this.state[k]);

    if (!api.allLoaded(apiResponses)) {
      return <APINotLoadedPage calls={apiResponses} widget={false} />; 
    }

    // Adding key=current timestamp forces us to unmount/remount
    // PusherPageContent every re-render. This seems to prevent crazy memory
    // leaks, albeit at the cost of slightly less responsiveness (which is fine
    // for a dashboard.) I think I could solve this in a more sophisticated
    // way, but this is fine for now.
    return <ChangesPage widget={false}>
      <PusherPageContent
        slugs={slugs}
        branch={branch}
        fetchedState={this.state}
        key={+Date.now()}
      />
    </ChangesPage>;
  },

  getSlugsAndBranch() {
    var queryParams = URI(window.location.href).search(true);

    var slugs, branch;
    if (queryParams['project']) {
      // Modern parameters.
      slugs = queryParams['project'];
      if (!_.isArray(slugs)) {
        slugs = [slugs];
      }
      if (queryParams['branch']) {
        branch = queryParams['branch'];
      }
    } else {
      // Antiquated parameters.
      var mains = queryParams['main'];
      if (!_.isArray(mains)) {
        mains = [mains];
      }
      slugs = [];
      _.each(mains, main => {
        let [slug, temp_branch] = mains.split('::');
        slugs.push(slug);
        if (!branch && temp_branch) {
          branch = temp_branch;
        }
      });
    }

    return [slugs, branch];
  },

  getEndpoints() {
    var queryParams = URI(window.location.href).search(true);
    let per_page = '50';
    if (queryParams['per_page']) {
      per_page = queryParams['per_page'];
    }
<commit_msg>fix typo on pusher page<commit_after>import React, { PropTypes } from 'react';

import ChangesLinks from 'es6!display/changes/links';
import { ChangesPage, APINotLoadedPage } from 'es6!display/page_chrome';
import { Grid } from 'es6!display/grid';
import { SingleBuildStatus } from 'es6!display/changes/builds';
import { TimeText, display_duration_pieces } from 'es6!display/time';
import { WaitingLiveText } from 'es6!display/changes/build_text';
import { get_runnable_condition,
         get_runnable_condition_color_cls,
         is_waiting } from 'es6!display/changes/build_conditions';

import * as api from 'es6!server/api';

import * as utils from 'es6!utils/utils';

// how often to hit the api server for updates
var POLL_INTERVAL = 10000;

/*
 * Modern query params:
 * - branch: select branch to display.
 * - project: pass multiple times to select projects to display. The value
 *   should be a project slug. All projects should be for the same repo.
 *
 * Antiquated query params: main (multiple times)
 * - The first main parameter determines the list of commits to show.
 *   Additional main parameters will show latest builds for that commit.
 * - A parameter can be just a project slug, or slug::branch.
 */
var PusherPage = React.createClass({

  getInitialTitle: function() {
    return 'Dashboard';
  },

  getInitialState: function() {
    var endpoints = this.getEndpoints();

    var state = {};
    _.each(_.keys(endpoints), key => {
      state[key] = null;
    });
    return state;
  },

  componentDidMount: function() {
    api.fetch(this, this.getEndpoints());

    this.updateInProgress = false;
    this.refreshTimer = window.setInterval(__ => {
      if (!this.isMounted()) {
        return;
      }
      this.liveUpdate();
    }, POLL_INTERVAL);
  },

  render: function() {
    if (this.updateInProgress) {
      if (api.allLoaded(_.values(this.state.liveUpdate))) {
        this.updateInProgress = false;
        utils.async(__ => {
          var emptyLiveUpdate = _.mapObject(this.getEndpoints(), (v, k) => null);
          this.setState(_.extend(
            {liveUpdate: emptyLiveUpdate},
            this.state.liveUpdate));
        });
      }
    }

    var [slugs, branch] = this.getSlugsAndBranch();
    var endpoints = this.getEndpoints();
    var apiResponses = _.map(endpoints, (v, k) => this.state[k]);

    if (!api.allLoaded(apiResponses)) {
      return <APINotLoadedPage calls={apiResponses} widget={false} />; 
    }

    // Adding key=current timestamp forces us to unmount/remount
    // PusherPageContent every re-render. This seems to prevent crazy memory
    // leaks, albeit at the cost of slightly less responsiveness (which is fine
    // for a dashboard.) I think I could solve this in a more sophisticated
    // way, but this is fine for now.
    return <ChangesPage widget={false}>
      <PusherPageContent
        slugs={slugs}
        branch={branch}
        fetchedState={this.state}
        key={+Date.now()}
      />
    </ChangesPage>;
  },

  getSlugsAndBranch() {
    var queryParams = URI(window.location.href).search(true);

    var slugs, branch;
    if (queryParams['project']) {
      // Modern parameters.
      slugs = queryParams['project'];
      if (!_.isArray(slugs)) {
        slugs = [slugs];
      }
      if (queryParams['branch']) {
        branch = queryParams['branch'];
      }
    } else {
      // Antiquated parameters.
      var mains = queryParams['main'];
      if (!_.isArray(mains)) {
        mains = [mains];
      }
      slugs = [];
      _.each(mains, main => {
        let [slug, temp_branch] = main.split('::');
        slugs.push(slug);
        if (!branch && temp_branch) {
          branch = temp_branch;
        }
      });
    }

    return [slugs, branch];
  },

  getEndpoints() {
    var queryParams = URI(window.location.href).search(true);
    let per_page = '50';
    if (queryParams['per_page']) {
      per_page = queryParams['per_page'];
    }

{'fraction_non_alphanumeric': 0.12823425470150196, 'fraction_numerical': 0.004038874163826834, 'mean_word_length': 2.7859531772575252, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3922447', 'n_tokens_mistral': 2424, 'n_tokens_neox': 2376, 'n_words': 632}