<commit_before>/**
 * The Blue Alliance API Library for node.js es6 v1.2.2
 * (c) 2014 Hamzah Khan [FRC 3188 (2010), FRC 3636 (2011-12), FRC 1540 (2013-14)]
 * Modified by Gus Caplan [FRC 3135 (2015-16)]
 * License: MIT
 */

/*
  TBA API docs are at: http://www.thebluealliance.com/apidocs
*/

const req = require('superagent');

const isDefined = variable => (typeof variable !== 'undefined' && variable !== null);

// you have to set a header in order to get the request methods
class initTBA {

  constructor (name, description, version) {
    // all TBA API v2 requests go to this root uri
    this.ROOT_URL = 'http://www.thebluealliance.com/api/v2/';
    this.headers = { 'X-TBA-App-Id': null };
    // set header or throw error
    if (isDefined(name) && isDefined(description) && isDefined(version)) {
      this.headers['X-TBA-App-Id'] = [name, description, version].join(':');
    } else {
      return new Error('can not set header with null or undefined values');
    }
    /*********************************************
    ****************** Aliases *******************
    **********************************************/
    this.getListOfTeams = this.getTeamList;
    this.getTeamById = this.getTeam;
    this.getEventsForTeam = this.getTeamEvents;
    this.getAwardsForTeamAtEvent = this.getTeamEventAwards;
    this.getMatchesForTeamAtEvent = this.getTeamEventMatches;
    this.getYearsParticipatedByTeam = this.getTeamYearsParticipated;
    this.getMediaForTeam = this.getTeamMedia;
    this.getEventHistoryForTeam = this.getTeamEventHistory;
    this.getAwardHistoryForTeam = this.getTeamAwardHistory;
    this.getRobotHistoryForTeam = this.getTeamRobotHistory;
    this.getDistrictHistoryForTeam = this.getTeamDistrictHistory;
    this.getListOfEvents = this.getEventList;
    this.getEventById = this.getEvent;
    this.getTeamsAtEvent = this.getEventTeams;
    this.getMatchesAtEvent = this.getEventMatches;
    this.getStatsAtEvent = this.getEventStats;
    this.getRankingsAtEvent = this.getEventRankings;
    this.getAwardsAtEvent = this.getEventAwards;
    this.getSingleMatchFromKey = this.getSingleMatch;
  }

  /*********************************************
  ************** Helper Functions **************
  **********************************************/

  // MVF - Most Valuable Function! in library
  // sends a request to the given url and then calls the callback
  tbaRequest (url, callback) {
    callback = callback || function (err, info) { console.log(err, info) }; // safety

    req.get(url)
    .set(this.headers)
    .end((err, res) => {
      if (!err) {
        if (res.statusCode === 200) {
          let info = res.body;

          // sets error to be null if there is a team, or null if no such team exists
          err = (info != null) ? null : new Error('Team did/does not exist in FIRST as of the desired year');

          // successful request
          callback(null, info);
        } else {
          // Unsuccessful because of 404 or something
          callback(new Error('Unsuccessful request to TBA'), null, null);
        }
      } else {
        // error in request
        callback(err, null, null);
      }
    });
  };

  yearValidation (year, callback) {
    // arguments validation for year and callback
    switch (typeof year) {
      case 'number':
        break;

      case 'function':
        callback = year;
        year = new Date().getFullYear();
        break;

      case 'undefined':
        year = new Date().getFullYear();
        break;
    }

    return { year: year, callback: callback };
  };

  /*********************************************
  ************* TBA Library Methods ************
  **********************************************/

  /**********************************************
  *************** TEAM REQUESTS *****************
  **********************************************/

  // 'Team List Request' on TBA API docs
  // gets all the teams on one page of the team list at TBA
  getTeamList (pageNum, callback) {
    let url = this.ROOT_URL + 'teams/' + pageNum;

    this.tbaRequest(url, callback);
  };

  // 'Team Request' on TBA API docs
  // gets one team's background info by its team id and year
  getTeam (teamId, callback) {
    let url = this.ROOT_URL + 'team/frc' + teamId;

    this.tbaRequest(url, callback);
  };

  // 'Team Events Request' on TBA API docs
  // gets all the team's events from a single year
  getTeamEvents (teamId, year, callback) {
    // Argument validation
    let validatedYear = this.yearValidation(year, callback);
    year = validatedYear.year;
    callback = validatedYear.callback || function (err, info) { console.log(err, info) };

    let url = this.ROOT_URL + 'team/frc' + teamId + '/' + year + '/events';
    this.tbaRequest(url, callback);
  };

  // 'Team Event Awards Request' on TBA API docs
  // gets all the teams awards for a single year at a single event
  getTeamEventAwards (teamId, eventId, year, callback) {
    // Argument validation
    let validatedYear = this.yearValidation(year, callback);
    year = validatedYear.year;
    callback = validatedYear.callback || function (err, info) { console.log(err, info) };

    let url = this.ROOT_URL + 'team/frc' + teamId + '/event/' + year + eventId + '/awards';
    this.tbaRequest(url, callback);
  };

  // 'Team Event Matches Request' on TBA API docs
  // gets all the team's matches at a single event in a single year
  getTeamEventMatches (teamId, eventId, year, callback) {
    // Argument validation
    let validatedYear = this.yearValidation(year, callback);
    year = validatedYear.year;
    callback = validatedYear.callback || function (err, info) { console.log(err, info) };

    let url = this.ROOT_URL + 'team/frc' + teamId + '/event/' + year + eventId + '/matches';
    this.tbaRequest(url, callback);
  };

  // 'Team Years Participated Request' on TBA API docs
  // returns array of years that the team has been participated in FIRST
  getTeamYearsParticipated (teamId, callback) {
    let url = this.ROOT_URL + 'team/frc' + teamId + '/years_participated';

    this.tbaRequest(url, callback);
  };

  // 'Team Media Request' on TBA API docs
  // gets all the teams media for a single year, as collected on TBA
  getTeamMedia (teamId, year, callback) {
    // Argument validation
    let validatedYear = this.yearValidation(year, callback);
    year = validatedYear.year;
    callback = validatedYear.callback || function (err, info) { console.log(err, info) };

    let url = this.ROOT_URL + 'team/frc' + teamId + '/' + year + '/media';
    this.tbaRequest(url, callback);
  };

    // 'Team History Events Request' on TBA API docs
  // gets all historical events for a given team
  getTeamEventHistory (teamId, callback) {
    let url = this.ROOT_URL + 'team/frc' + teamId + '/history/events';

    this.tbaRequest(url, callback);
  };

    // 'Team History Awards Request' on TBA API docs
  // gets all historical awards for a given team
  getTeamAwardHistory (teamId, callback) {
    let url = this.ROOT_URL + 'team/frc' + teamId + '/history/awards';

    this.tbaRequest(url, callback);
  };

    // 'Team History Robots Request' on TBA API docs
  // gets all historical robots for a given team
  getTeamRobotHistory (teamId, callback) {
    let url = this.ROOT_URL + 'team/frc' + teamId + '/history/robots';

    this.tbaRequest(url, callback);
  };

    // 'Team History Districts Request' on TBA API docs
  // gets all historical robots for a given team
  getTeamDistrictHistory (teamId, callback) {
    let url = this.ROOT_URL + 'team/frc' + teamId + '/history/districts';

    this.tbaRequest(url, callback);
  };

  /***********************************************
  *************** EVENT REQUESTS *****************
  ***********************************************/

  // 'Team List Request' on TBA API docs
  // gets all the events in FIRST in a single year
  getEventList (year, callback) {
    // Argument validation
    let validatedYear = this.yearValidation(year, callback);
    year = validatedYear.year;
    callback = validatedYear.callback || function (err, info) { console.log(err, info) };

    let url = this.ROOT_URL + 'events/' + year;
    this.tbaRequest(url, callback);
  };

  // 'Event Request' on TBA API docs
  // gets event info for a single year
  getEvent (eventId, year, callback) {
    // Argument validation
    let validatedYear = this.yearValidation(year, callback);
    year = validatedYear.year;
    callback = validatedYear.callback || function (err, info) { console.log(err, info) };

    let url = this.ROOT_URL + 'event/' + year + eventId;

    this.tbaRequest(url, callback);
  };

  // 'Event Teams Request' on TBA API docs
  // get all of the teams at an event
  getEventTeams (eventId, year, callback) {
    // Argument validation
    let validatedYear = this.yearValidation(year, callback);
    year = validatedYear.year;
    callback = validatedYear.callback || function (err, info) { console.log(err, info) };

    let url = this.ROOT_URL + 'event/' + year + eventId + '/teams';

    this.tbaRequest(url, callback);
  };

  // 'Event Matches Request' on TBA API docs
  // get all of the matches at an event
  getEventMatches (eventId, year, callback) {
    // Argument validation
    let validatedYear = this.yearValidation(year, callback);
    year = validatedYear.year;
    callback = validatedYear.callback || function (err, info) { console.log(err, info) };

    let url = this.ROOT_URL + 'event/' + year + eventId + '/matches';

    this.tbaRequest(url, callback);
  };

  // 'Event Stats Request' on TBA API docs
  // gets the stats for a single event
  getEventStats (eventId, year, callback) {
    // Argument validation
    let validatedYear = this.yearValidation(year, callback);
    year = validatedYear.year;
    callback = validatedYear.callback || function (err, info) { console.log(err, info) };

    let url = this.ROOT_URL + 'event/' + year + eventId + '/stats';
    this.tbaRequest(url, callback);
  };

  // 'Event Rankings Request' on TBA API docs
  // gets the rankings for a single event
  getEventRankings (eventId, year, callback) {
    // Argument validation
    let validatedYear = this.yearValidation(year, callback);
    year = validatedYear.year;
    callback = validatedYear.callback || function (err, info) { console.log(err, info) };

    let url = this.ROOT_URL + 'event/' + year + eventId + '/rankings';
    this.tbaRequest(url, callback);
  };

  // 'Event Awards Request' on TBA API docs
  // gets awards at an event in a single year
  getEventAwards (eventId, year, callback) {
    // Argument validation
    let validatedYear = this.yearValidation(year, callback);
    year = validatedYear.year;
    callback = validatedYear.callback || function (err, info) { console.log(err, info) };

    let url = this.ROOT_URL + 'event/' + year + eventId + '/awards';

    this.tbaRequest(url, callback);
  };

  // 'Single Match Request' on TBA API docs
  // Gets a single match based on match_key
  getSingleMatch (matchKey, callback) {
    let url = this.ROOT_URL + 'match/' + matchKey;

    this.tbaRequest(url, callback);
  };

};

module.exports = initTBA;
<commit_msg>update all the urls to template literals, and move the root url to tbaRequest because typing that every time sucks<commit_after>/**
 * The Blue Alliance API Library for node.js es6 v1.2.2
 * (c) 2014 Hamzah Khan [FRC 3188 (2010), FRC 3636 (2011-12), FRC 1540 (2013-14)]
 * Modified by Gus Caplan [FRC 3135 (2015-16)]
 * License: MIT
 */

/*
  TBA API docs are at: http://www.thebluealliance.com/apidocs
*/

const req = require('superagent');

const isDefined = variable => (typeof variable !== 'undefined' && variable !== null);

// you have to set a header in order to get the request methods
class initTBA {

  constructor (name, description, version) {
    // all TBA API v2 requests go to this root uri
    this.ROOT_URL = 'http://www.thebluealliance.com/api/v2';
    this.headers = { 'X-TBA-App-Id': null };
    // set header or throw error
    if (isDefined(name) && isDefined(description) && isDefined(version)) {
      this.headers['X-TBA-App-Id'] = [name, description, version].join(':');
    } else {
      return new Error('can not set header with null or undefined values');
    }
    /*********************************************
    ****************** Aliases *******************
    **********************************************/
    this.getListOfTeams = this.getTeamList;
    this.getTeamById = this.getTeam;
    this.getEventsForTeam = this.getTeamEvents;
    this.getAwardsForTeamAtEvent = this.getTeamEventAwards;
    this.getMatchesForTeamAtEvent = this.getTeamEventMatches;
    this.getYearsParticipatedByTeam = this.getTeamYearsParticipated;
    this.getMediaForTeam = this.getTeamMedia;
    this.getEventHistoryForTeam = this.getTeamEventHistory;
    this.getAwardHistoryForTeam = this.getTeamAwardHistory;
    this.getRobotHistoryForTeam = this.getTeamRobotHistory;
    this.getDistrictHistoryForTeam = this.getTeamDistrictHistory;
    this.getListOfEvents = this.getEventList;
    this.getEventById = this.getEvent;
    this.getTeamsAtEvent = this.getEventTeams;
    this.getMatchesAtEvent = this.getEventMatches;
    this.getStatsAtEvent = this.getEventStats;
    this.getRankingsAtEvent = this.getEventRankings;
    this.getAwardsAtEvent = this.getEventAwards;
    this.getSingleMatchFromKey = this.getSingleMatch;
  }

  /*********************************************
  ************** Helper Functions **************
  **********************************************/

  // MVF - Most Valuable Function! in library
  // sends a request to the given url and then calls the callback
  tbaRequest (url, callback) {
    callback = callback || function (err, info) { console.log(err, info) }; // safety

    req.get(this.ROOT_URL + url)
    .set(this.headers)
    .end((err, res) => {
      if (!err) {
        if (res.statusCode === 200) {
          let info = res.body;

          // sets error to be null if there is a team, or null if no such team exists
          err = (info != null) ? null : new Error('Team did/does not exist in FIRST as of the desired year');

          // successful request
          callback(null, info);
        } else {
          // Unsuccessful because of 404 or something
          callback(new Error('Unsuccessful request to TBA'), null, null);
        }
      } else {
        // error in request
        callback(err, null, null);
      }
    });
  };

  yearValidation (year, callback) {
    // arguments validation for year and callback
    switch (typeof year) {
      case 'number':
        break;

      case 'function':
        callback = year;
        year = new Date().getFullYear();
        break;

      case 'undefined':
        year = new Date().getFullYear();
        break;
    }

    return { year: year, callback: callback };
  };

  /*********************************************
  ************* TBA Library Methods ************
  **********************************************/

  /**********************************************
  *************** TEAM REQUESTS *****************
  **********************************************/

  // 'Team List Request' on TBA API docs
  // gets all the teams on one page of the team list at TBA
  getTeamList (pageNum, callback) {
    let url = this.ROOT_URL + 'teams/' + pageNum;

    this.tbaRequest(url, callback);
  };

  // 'Team Request' on TBA API docs
  // gets one team's background info by its team id and year
  getTeam (teamId, callback) {
    let url = `/team/frc${teamId}`;

    this.tbaRequest(url, callback);
  };

  // 'Team Events Request' on TBA API docs
  // gets all the team's events from a single year
  getTeamEvents (teamId, year, callback) {
    // Argument validation
    let validatedYear = this.yearValidation(year, callback);
    year = validatedYear.year;
    callback = validatedYear.callback || function (err, info) { console.log(err, info) };

    let url = `/team/frc${teamId}/${year}/events`;
    this.tbaRequest(url, callback);
  };

  // 'Team Event Awards Request' on TBA API docs
  // gets all the teams awards for a single year at a single event
  getTeamEventAwards (teamId, eventId, year, callback) {
    // Argument validation
    let validatedYear = this.yearValidation(year, callback);
    year = validatedYear.year;
    callback = validatedYear.callback || function (err, info) { console.log(err, info) };

    let url = `/team/frc${teamId}/event/${year}${eventId}/awards`;
    this.tbaRequest(url, callback);
  };

  // 'Team Event Matches Request' on TBA API docs
  // gets all the team's matches at a single event in a single year
  getTeamEventMatches (teamId, eventId, year, callback) {
    // Argument validation
    let validatedYear = this.yearValidation(year, callback);
    year = validatedYear.year;
    callback = validatedYear.callback || function (err, info) { console.log(err, info) };

    let url = `/team/frc${teamId}/event/${year}${eventId}/matches`;
    this.tbaRequest(url, callback);
  };

  // 'Team Years Participated Request' on TBA API docs
  // returns array of years that the team has been participated in FIRST
  getTeamYearsParticipated (teamId, callback) {
    let url = `/team/frc${teamId}/years_participated`;

    this.tbaRequest(url, callback);
  };

  // 'Team Media Request' on TBA API docs
  // gets all the teams media for a single year, as collected on TBA
  getTeamMedia (teamId, year, callback) {
    // Argument validation
    let validatedYear = this.yearValidation(year, callback);
    year = validatedYear.year;
    callback = validatedYear.callback || function (err, info) { console.log(err, info) };

    let url = `/team/frc${teamId}/${year}/media`;
    this.tbaRequest(url, callback);
  };

    // 'Team History Events Request' on TBA API docs
  // gets all historical events for a given team
  getTeamEventHistory (teamId, callback) {
    let url = `/team/frc${teamId}/history/events`;

    this.tbaRequest(url, callback);
  };

    // 'Team History Awards Request' on TBA API docs
  // gets all historical awards for a given team
  getTeamAwardHistory (teamId, callback) {
    let url = `/team/frc${teamId}/history/awards`;

    this.tbaRequest(url, callback);
  };

    // 'Team History Robots Request' on TBA API docs
  // gets all historical robots for a given team
  getTeamRobotHistory (teamId, callback) {
    let url = `/team/frc${teamId}/history/robots`;

    this.tbaRequest(url, callback);
  };

    // 'Team History Districts Request' on TBA API docs
  // gets all historical robots for a given team
  getTeamDistrictHistory (teamId, callback) {
    let url = `/team/frc${teamId}/history/districts`;

    this.tbaRequest(url, callback);
  };

  /***********************************************
  *************** EVENT REQUESTS *****************
  ***********************************************/

  // 'Team List Request' on TBA API docs
  // gets all the events in FIRST in a single year
  getEventList (year, callback) {
    // Argument validation
    let validatedYear = this.yearValidation(year, callback);
    year = validatedYear.year;
    callback = validatedYear.callback || function (err, info) { console.log(err, info) };

    let url = `/events/${year}`;
    this.tbaRequest(url, callback);
  };

  // 'Event Request' on TBA API docs
  // gets event info for a single year
  getEvent (eventId, year, callback) {
    // Argument validation
    let validatedYear = this.yearValidation(year, callback);
    year = validatedYear.year;
    callback = validatedYear.callback || function (err, info) { console.log(err, info) };

    let url = `/event/${year}${eventId}`;

    this.tbaRequest(url, callback);
  };

  // 'Event Teams Request' on TBA API docs
  // get all of the teams at an event
  getEventTeams (eventId, year, callback) {
    // Argument validation
    let validatedYear = this.yearValidation(year, callback);
    year = validatedYear.year;
    callback = validatedYear.callback || function (err, info) { console.log(err, info) };

    let url = `/event/${year}${eventId}/teams`;

    this.tbaRequest(url, callback);
  };

  // 'Event Matches Request' on TBA API docs
  // get all of the matches at an event
  getEventMatches (eventId, year, callback) {
    // Argument validation
    let validatedYear = this.yearValidation(year, callback);
    year = validatedYear.year;
    callback = validatedYear.callback || function (err, info) { console.log(err, info) };

    let url = `/event/${year}${eventId}/matches`;

    this.tbaRequest(url, callback);
  };

  // 'Event Stats Request' on TBA API docs
  // gets the stats for a single event
  getEventStats (eventId, year, callback) {
    // Argument validation
    let validatedYear = this.yearValidation(year, callback);
    year = validatedYear.year;
    callback = validatedYear.callback || function (err, info) { console.log(err, info) };

    let url = `/event/${year}${eventId}/stats`;
    this.tbaRequest(url, callback);
  };

  // 'Event Rankings Request' on TBA API docs
  // gets the rankings for a single event
  getEventRankings (eventId, year, callback) {
    // Argument validation
    let validatedYear = this.yearValidation(year, callback);
    year = validatedYear.year;
    callback = validatedYear.callback || function (err, info) { console.log(err, info) };

    let url = `/event/${year}${eventId}/rankings`;
    this.tbaRequest(url, callback);
  };

  // 'Event Awards Request' on TBA API docs
  // gets awards at an event in a single year
  getEventAwards (eventId, year, callback) {
    // Argument validation
    let validatedYear = this.yearValidation(year, callback);
    year = validatedYear.year;
    callback = validatedYear.callback || function (err, info) { console.log(err, info) };

    let url = `/event/${year}${eventId}/awards`;

    this.tbaRequest(url, callback);
  };

  // 'Single Match Request' on TBA API docs
  // Gets a single match based on match_key
  getSingleMatch (matchKey, callback) {
    let url = `/match/${matchKey}`;

    this.tbaRequest(url, callback);
  };

};

module.exports = initTBA;
<|endoftext|>


<commit_before>// From govuk_elements/public/javascripts/vendor/details.polyfill.js
// <details> polyfill
// http://caniuse.com/#feat=details

// FF Support for HTML5's <details> and <summary>
// https://bugzilla.mozilla.org/show_bug.cgi?id=591737

// http://www.sitepoint.com/fixing-the-details-element/

(function () {

  // We'll need the getBoundingClientRect function for the
  // hash scripting, so if it's not supported just return,
  // then the elements will remain in their default open state
  if (typeof(document.createElement('span').getBoundingClientRect) == 'undefined') { return; }

  // Add event construct for modern browsers or IE
  // which fires the callback with a pre-converted target reference
  function addEvent(node, type, callback) {
    if (node.addEventListener) {
      node.addEventListener(type, function (e) {
        callback(e, e.target);

      }, false);
    } else if (node.attachEvent) {
      node.attachEvent('on' + type, function (e) {
        callback(e, e.srcElement);
      });
    }
  }

  // Handle cross-modal click events
  function addClickEvent(node, callback) {
    // Prevent space(32) from scrolling the page
    addEvent(node, 'keypress', function (e, target) {
      if (target.nodeName === "SUMMARY") {
        if (e.keyCode === 32) {
          if (e.preventDefault) {
            e.preventDefault();
          } else {
            e.returnValue = false;
          }
        }
      }
    });
    // When the key comes up - check if it is enter(13) or space(32)
    addEvent(node, 'keyup', function (e, target) {
      if (e.keyCode === 13 || e.keyCode === 32) { callback(e, target); }
    });
    addEvent(node, 'mouseup', function (e, target) {
      callback(e, target);
    });
  }

  // Get the nearest ancestor element of a node that matches a given tag name
  function getAncestor(node, match) {
    do {
      if (!node || node.nodeName.toLowerCase() === match) {
        break;
      }
    } while (node = node.parentNode);

    return node;
  }

  // Create a started flag so we can prevent the initialisation
  // function firing from both DOMContentLoaded and window.onload
  var started = false;

  // Initialisation function
  function addDetailsPolyfill(list) {

    // If this has already happened, just return
    // else set the flag so it doesn't happen again
    if (started) {
      return;
    }
    started = true;

    // Get the collection of details elements, but if that's empty
    // then we don't need to bother with the rest of the scripting
    if ((list = document.getElementsByTagName('details')).length === 0) {
      return;
    }

    // else iterate through them to apply their initial state
    var n = list.length, i = 0;
    for (n; i < n; i++) {
      var details = list[i];

      // Detect native implementations
      details.__native = typeof(details.open) == 'boolean';

      // Save shortcuts to the inner summary and content elements
      details.__summary = details.getElementsByTagName('summary').item(0);
      details.__content = details.getElementsByTagName('div').item(0);

      // If the content doesn't have an ID, assign it one now
      // which we'll need for the summary's aria-controls assignment
      if (!details.__content.id) {
        details.__content.id = 'details-content-' + i;
      }

      // Add ARIA role="group" to details
      details.setAttribute('role', 'group');

      // Add role=button to summary
      details.__summary.setAttribute('role', 'button');

      // Add aria-controls
      details.__summary.setAttribute('aria-controls', details.__content.id);

      // Set tabindex so the summary is keyboard accessible
      // details.__summary.setAttribute('tabindex', 0);
      // http://www.saliences.com/browserBugs/tabIndex.html
      details.__summary.tabIndex = 0;

      // Detect initial open/closed state

      // Native support - has 'open' attribute
      if (details.open === true) {
        details.__summary.setAttribute('aria-expanded', 'true');
        details.__content.setAttribute('aria-hidden', 'false');
        details.__content.style.display = 'block';
      }

      // Native support - doesn't have 'open' attribute
      if (details.open === false) {
        details.__summary.setAttribute('aria-expanded', 'false');
        details.__content.setAttribute('aria-hidden', 'true');
        details.__content.style.display = 'none';
      }

      // If this is not a native implementation
      if (!details.__native) {

        // Add an arrow
        var twisty = document.createElement('i');

        // Check for the 'open' attribute
        // If open exists, but isn't supported it won't have a value
        if (details.getAttribute('open') === "") {
          details.__summary.setAttribute('aria-expanded', 'true');
          details.__content.setAttribute('aria-hidden', 'false');
        }

        // If open doesn't exist - it will be null or undefined
        if (details.getAttribute('open') == null || details.getAttribute('open') == "undefined" ) {
          details.__summary.setAttribute('aria-expanded', 'false');
          details.__content.setAttribute('aria-hidden', 'true');
          details.__content.style.display = 'none';
        }

      }

      // Create a circular reference from the summary back to its
      // parent details element, for convenience in the click handler
      details.__summary.__details = details;

      // If this is not a native implementation, create an arrow
      // inside the summary
      if (!details.__native) {

        var twisty = document.createElement('i');

        if (details.getAttribute('open') === "") {
          twisty.className = 'arrow arrow-open';
          twisty.appendChild(document.createTextNode('\u25bc'));
        } else {
          twisty.className = 'arrow arrow-closed';
          twisty.appendChild(document.createTextNode('\u25ba'));
        }

        details.__summary.__twisty = details.__summary.insertBefore(twisty, details.__summary.firstChild);
        details.__summary.__twisty.setAttribute('aria-hidden', 'true');

      }
    }

    // Define a statechange function that updates aria-expanded and style.display
    // to either expand or collapse the region (ie. invert the current state)
    // or to set a specific state if the expanded flag is strictly true or false
    // then update the twisty if we have one with a correpsonding glyph
    function statechange(summary, expanded) {
      var hidden = summary.__details.__content.getAttribute('aria-hidden') == 'true';

      if (typeof(expanded) == 'undefined') {
        expanded = summary.__details.__content.getAttribute('aria-expanded') == 'true';
      } else if (expanded === false) {
        summary.__details.setAttribute('open', 'open');
      } else if (expanded === true) {
        summary.__details.removeAttribute('open');
      }

      summary.__details.__content.setAttribute('aria-expanded', (expanded ? 'false' : 'true'));
      summary.__details.__content.setAttribute('aria-hidden', (hidden ? 'false' : 'true'));
      summary.__details.__content.style.display = (expanded ? 'none' : 'block');

      if (summary.__twisty) {
        summary.__twisty.firstChild.nodeValue = (expanded ? '\u25ba' : '\u25bc');
        summary.__twisty.setAttribute('class', (expanded ? 'arrow arrow-closed' : 'arrow arrow-open'));
      }

      return true;
    }

    // Bind a click event to handle summary elements
    // if the target is not inside a summary element, just return true
    // to pass-through the event, else call and return the statechange function
    // which also returns true to pass-through the remaining event
    addClickEvent(document, function (e, summary) {
      if (!(summary = getAncestor(summary, 'summary'))) {
        return true;
      }
      return statechange(summary);
    });

    // Define an autostate function that identifies whether a target
    // is or is inside a details region, and if so expand that region
    // then iterate up the DOM expanding any ancestors, then finally
    // return the original target if applicable, or null if not
    function autostate(target, expanded, ancestor) {
      if (typeof(ancestor) == 'undefined') {
        if (!(target = getAncestor(target, 'details'))) {
          return null;
        }
        ancestor = target;
      } else {
        if (!(ancestor = getAncestor(ancestor, 'details'))) {
          return target;
        }
      }

      statechange(ancestor.__summary, expanded);

      return autostate(target, expanded, ancestor.parentNode);
    }

    // Then if we have a location hash, call the autostate
    // function now with the target element it refers to
    if (location.hash) {
      autostate(document.getElementById(location.hash.substr(1)), false);
    }

    // Bind a click event to handle internal page links
    // ignoring links to other pages, else passing the target it
    // refers to to the autostate function, and if that returns a target
    // auto-scroll the page so that the browser jumps to that target
    // then return true anyway so that the address-bar hash updates
    addEvent(document, 'click', function (e, target) {
      if (!target.href) {
        return true;
      }
      if ((target = target.href.split('#')).length == 1) {
        return true;
      }
      if (document.location.href.split('#')[0] != target[0]) {
        return true;
      }
      if (target = autostate(document.getElementById(target[1]), false)) {
        window.scrollBy(0, target.getBoundingClientRect().top);
      }
      return true;
    });
  }

  // Bind two load events for modern and older browsers
  // If the first one fires it will set a flag to block the second one
  // but if it's not supported then the second one will fire
  addEvent(document, 'DOMContentLoaded', addDetailsPolyfill);
  addEvent(window, 'load', addDetailsPolyfill);

})();
<commit_msg>Update details polyfill<commit_after>// <details> polyfill
// http://caniuse.com/#feat=details

// FF Support for HTML5's <details> and <summary>
// https://bugzilla.mozilla.org/show_bug.cgi?id=591737

// http://www.sitepoint.com/fixing-the-details-element/

;(function () {
  'use strict'

  var NATIVE_DETAILS = typeof document.createElement('details').open === 'boolean'
  var KEY_ENTER = 13
  var KEY_SPACE = 32

  // Add event construct for modern browsers or IE
  // which fires the callback with a pre-converted target reference
  function addEvent (node, type, callback) {
    if (node.addEventListener) {
      node.addEventListener(type, function (e) {
        callback(e, e.target)
      }, false)
    } else if (node.attachEvent) {
      node.attachEvent('on' + type, function (e) {
        callback(e, e.srcElement)
      })
    }
  }

  // Cross-browser character code / key pressed
  function charCode (e) {
    return (typeof e.which === 'number') ? e.which : e.keyCode
  }

  // Cross-browser preventing default action
  function preventDefault (e) {
    if (e.preventDefault) {
      e.preventDefault()
    } else {
      e.returnValue = false
    }
  }

  // Handle cross-modal click events
  function addClickEvent (node, callback) {
    addEvent(node, 'keypress', function (e, target) {
      // When the key gets pressed - check if it is enter or space
      if (charCode(e) === KEY_ENTER || charCode(e) === KEY_SPACE) {
        if (target.nodeName.toLowerCase() === 'summary') {
          // Prevent space from scrolling the page
          // and enter from submitting a form
          preventDefault(e)
          // Click to let the click event do all the necessary action
          if (target.click) {
            target.click()
          } else {
            // except Safari 5.1 and under don't support .click() here
            callback(e, target)
          }
        }
      }
    })

    // Prevent keyup to prevent clicking twice in Firefox when using space key
    addEvent(node, 'keyup', function (e, target) {
      if (charCode(e) === KEY_SPACE) {
        if (target.nodeName === 'SUMMARY') {
          preventDefault(e)
        }
      }
    })

    addEvent(node, 'click', function (e, target) {
      callback(e, target)
    })
  }

  // Get the nearest ancestor element of a node that matches a given tag name
  function getAncestor (node, match) {
    do {
      if (!node || node.nodeName.toLowerCase() === match) {
        break
      }
      node = node.parentNode
    } while (node)

    return node
  }

  // Create a started flag so we can prevent the initialisation
  // function firing from both DOMContentLoaded and window.onload
  var started = false

  // Initialisation function
  function addDetailsPolyfill (list) {
    // If this has already happened, just return
    // else set the flag so it doesn't happen again
    if (started) {
      return
    }
    started = true

    // Get the collection of details elements, but if that's empty
    // then we don't need to bother with the rest of the scripting
    if ((list = document.getElementsByTagName('details')).length === 0) {
      return
    }

    // else iterate through them to apply their initial state
    var n = list.length
    var i = 0
    for (i; i < n; i++) {
      var details = list[i]

      // Save shortcuts to the inner summary and content elements
      details.__summary = details.getElementsByTagName('summary').item(0)
      details.__content = details.getElementsByTagName('div').item(0)

      // If the content doesn't have an ID, assign it one now
      // which we'll need for the summary's aria-controls assignment
      if (!details.__content.id) {
        details.__content.id = 'details-content-' + i
      }

      // Add ARIA role="group" to details
      details.setAttribute('role', 'group')

      // Add role=button to summary
      details.__summary.setAttribute('role', 'button')

      // Add aria-controls
      details.__summary.setAttribute('aria-controls', details.__content.id)

      // Set tabIndex so the summary is keyboard accessible for non-native elements
      // http://www.saliences.com/browserBugs/tabIndex.html
      if (!NATIVE_DETAILS) {
        details.__summary.tabIndex = 0
      }

      // Detect initial open state
      var openAttr = details.getAttribute('open') !== null
      if (openAttr === true) {
        details.__summary.setAttribute('aria-expanded', 'true')
        details.__content.setAttribute('aria-hidden', 'false')
      } else {
        details.__summary.setAttribute('aria-expanded', 'false')
        details.__content.setAttribute('aria-hidden', 'true')
        if (!NATIVE_DETAILS) {
          details.__content.style.display = 'none'
        }
      }

      // Create a circular reference from the summary back to its
      // parent details element, for convenience in the click handler
      details.__summary.__details = details

      // If this is not a native implementation, create an arrow
      // inside the summary
      if (!NATIVE_DETAILS) {
        var twisty = document.createElement('i')

        if (openAttr === true) {
          twisty.className = 'arrow arrow-open'
          twisty.appendChild(document.createTextNode('\u25bc'))
        } else {
          twisty.className = 'arrow arrow-closed'
          twisty.appendChild(document.createTextNode('\u25ba'))
        }

        details.__summary.__twisty = details.__summary.insertBefore(twisty, details.__summary.firstChild)
        details.__summary.__twisty.setAttribute('aria-hidden', 'true')
      }
    }

    // Define a statechange function that updates aria-expanded and style.display
    // Also update the arrow position
    function statechange (summary) {
      var expanded = summary.__details.__summary.getAttribute('aria-expanded') === 'true'
      var hidden = summary.__details.__content.getAttribute('aria-hidden') === 'true'

      summary.__details.__summary.setAttribute('aria-expanded', (expanded ? 'false' : 'true'))
      summary.__details.__content.setAttribute('aria-hidden', (hidden ? 'false' : 'true'))

      if (!NATIVE_DETAILS) {
        summary.__details.__content.style.display = (expanded ? 'none' : '')

        var hasOpenAttr = summary.__details.getAttribute('open') !== null
        if (!hasOpenAttr) {
          summary.__details.setAttribute('open', 'open')
        } else {
          summary.__details.removeAttribute('open')
        }
      }

      if (summary.__twisty) {
        summary.__twisty.firstChild.nodeValue = (expanded ? '\u25ba' : '\u25bc')
        summary.__twisty.setAttribute('class', (expanded ? 'arrow arrow-closed' : 'arrow arrow-open'))
      }

      return true
    }

    // Bind a click event to handle summary elements
    addClickEvent(document, function (e, summary) {
      if (!(summary = getAncestor(summary, 'summary'))) {
        return true
      }
      return statechange(summary)
    })
  }

  // Bind two load events for modern and older browsers
  // If the first one fires it will set a flag to block the second one
  // but if it's not supported then the second one will fire
  addEvent(document, 'DOMContentLoaded', addDetailsPolyfill)
  addEvent(window, 'load', addDetailsPolyfill)
})()
<|endoftext|>


<commit_before>/* eslint key-spacing:0 */
export default () => ({
  compiler_fail_on_warning : false,
  compiler_hash_type       : 'chunkhash',
  compiler_devtool         : null,
  compiler_stats           : {
    chunks : true,
    chunkModules : true,
    colors : true
  },
  compiler_public_path: `http://${config.server_host}:${config.server_port}/`
});
<commit_msg>test mongolab<commit_after>/* eslint key-spacing:0 */
export default () => ({
  compiler_fail_on_warning : false,
  compiler_hash_type       : 'chunkhash',
  compiler_devtool         : null,
  compiler_stats           : {
    chunks : true,
    chunkModules : true,
    colors : true
  },
  compiler_public_path: `http://localhost:8080/`
});
<|endoftext|>


<commit_before>var express = require("express"),
    router = express.Router();
var locks = require('locks');

var mutex = locks.createMutex();
/*
This is the build route
Usage:
deploy.thisisimp.com/a427f694-0a21-11e5-a6c0-1697f925ec7b/:environment/:repository
environment - either "dev" or "prod"
repository - either "frontend" or "api"
 */

router.route("/:env/:repo").get(function(req, res) {
    console.log("Attempting to get lock");
    if (mutex.tryLock()) {
        console.log('We got the lock!');
        var util  = require('util'),
            spawn = require('child_process').spawn;

        if(req.params.env === "dev" && req.params.repo === "frontend"){
            var child = spawn('sh', ['/home/ubuntu/deploy/frontend/build-frontend-dev.sh']);

            child.stdout.on('data', function (data) {
                res.write(data.toString());
                console.log(data.toString());
            });

            child.stderr.on('data', function (data) {
                res.write(data.toString());
                console.log(data.toString());
            });

            child.on('close', function (code) {
                res.write("Finished building! Grats!");
                console.log("User finished building");
                mutex.unlock();
                res.end();
            });
        }
        else if(req.params.env === "dev" && req.params.repo === "api"){
            var child = spawn('sh', ['/home/ubuntu/deploy/api/build-api-dev.sh']);
            child.stdout.on('data', function (data) {
                res.write(data.toString());
                console.log(data.toString());
            });

            child.stderr.on('data', function (data) {
                console.log(data.toString());
                res.write(data.toString());
            });

            child.on('close', function (code) {
                res.write("Finished building! Grats!");
                console.log("User finished building");
                mutex.unlock();
                res.end();
            });
        }
        else if(req.params.env === "prod" && req.params.repo === "frontend"){
            var child = spawn('sh', ['/home/ubuntu/deploy/frontend/build-frontend-prod.sh']);
            child.stdout.on('data', function (data) {
                res.write(data.toString());
                console.log(data.toString());
            });

            child.stderr.on('data', function (data) {
                res.write(data.toString());
                console.log(data.toString());
            });

            child.on('close', function (code) {
                res.write("Finished building! Grats!");
                console.log("User finished building");
                mutex.unlock();
                res.end();
            });
        }
        else if(req.params.env === "prod" && req.params.repo === "api"){
            var child = spawn('sh', ['/home/ubuntu/deploy/api/build-api-prod.sh']);
            child.stdout.on('data', function (data) {
                res.write(data.toString());
                console.log(data.toString());
            });

            child.stderr.on('data', function (data) {
                res.write(data.toString());
                console.log(data.toString());
            });

            child.on('close', function (code) {
                res.write("Finished building! Grats!");
                console.log("User finished building");
                mutex.unlock();
                res.end();
            });
        }
        else{
            console.log("User used route improperly");
            mutex.unlock();
            req.status(404).send("Route used improperly");
        }
    } else {
        console.log('Could not get the lock at this time');
        res.status(500).send("Someone else is building at this time, please wait a few minutes and try again");
    }

});

module.exports = router;
<commit_msg>Update a427f694-0a21-11e5-a6c0-1697f925ec7b.js<commit_after>var express = require("express"),
    router = express.Router();
var locks = require('locks');

var mutex = locks.createMutex();
/*
This is the build route
Usage:
deploy.thisisimp.com/a427f694-0a21-11e5-a6c0-1697f925ec7b/:environment/:repository
environment - either "dev" or "prod"
repository - either "frontend" or "api"
 */

router.route("/:env/:repo").get(function(req, res) {
    console.log("Request information");
    console.log("Body:");
    console.log(req.body);
    console.log("Cookies:");
    console.log(req.cookies);
    console.log("XHR:");
    console.log(req.xhr);
    console.log("Attempting to get lock");
    if (mutex.tryLock()) {
        console.log('We got the lock!');
        var util  = require('util'),
            spawn = require('child_process').spawn;

        if(req.params.env === "dev" && req.params.repo === "frontend"){
            var child = spawn('sh', ['/home/ubuntu/deploy/frontend/build-frontend-dev.sh']);

            child.stdout.on('data', function (data) {
                res.write(data.toString());
                console.log(data.toString());
            });

            child.stderr.on('data', function (data) {
                res.write(data.toString());
                console.log(data.toString());
            });

            child.on('close', function (code) {
                res.write("Finished building! Grats!");
                console.log("User finished building");
                mutex.unlock();
                res.end();
            });
        }
        else if(req.params.env === "dev" && req.params.repo === "api"){
            var child = spawn('sh', ['/home/ubuntu/deploy/api/build-api-dev.sh']);
            child.stdout.on('data', function (data) {
                res.write(data.toString());
                console.log(data.toString());
            });

            child.stderr.on('data', function (data) {
                console.log(data.toString());
                res.write(data.toString());
            });

            child.on('close', function (code) {
                res.write("Finished building! Grats!");
                console.log("User finished building");
                mutex.unlock();
                res.end();
            });
        }
        else if(req.params.env === "prod" && req.params.repo === "frontend"){
            var child = spawn('sh', ['/home/ubuntu/deploy/frontend/build-frontend-prod.sh']);
            child.stdout.on('data', function (data) {
                res.write(data.toString());
                console.log(data.toString());
            });

            child.stderr.on('data', function (data) {
                res.write(data.toString());
                console.log(data.toString());
            });

            child.on('close', function (code) {
                res.write("Finished building! Grats!");
                console.log("User finished building");
                mutex.unlock();
                res.end();
            });
        }
        else if(req.params.env === "prod" && req.params.repo === "api"){
            var child = spawn('sh', ['/home/ubuntu/deploy/api/build-api-prod.sh']);
            child.stdout.on('data', function (data) {
                res.write(data.toString());
                console.log(data.toString());
            });

            child.stderr.on('data', function (data) {
                res.write(data.toString());
                console.log(data.toString());
            });

            child.on('close', function (code) {
                res.write("Finished building! Grats!");
                console.log("User finished building");
                mutex.unlock();
                res.end();
            });
        }
        else{
            console.log("User used route improperly");
            mutex.unlock();
            req.status(404).send("Route used improperly");
        }
    } else {
        console.log('Could not get the lock at this time');
        res.status(500).send("Someone else is building at this time, please wait a few minutes and try again");
    }

});

module.exports = router;
<|endoftext|>


<commit_before>"use strict";

(function(){
    var bannerStatus;
    var interstitialStatus;

    var banner;
    var interstitial;
    var demoPosition;

    var backgroundTexture;
    var button1Texture;
    var button2Texture;

    var adService;

    var container;

    function createBanner() {

        banner = adService.createBanner();

        banner.on("load", function(){
            console.log("Banner loaded " + banner.width, banner.height);
            bannerStatus.text = "Banner loaded";
        });

        banner.on("fail", function(){
            console.log("Banner failed to load");
            bannerStatus.text = "Banner failed";
        });

        banner.on("show", function(){
            console.log("Banner shown a modal content");
            bannerStatus.text = "Banner show modal content";
        });

        banner.on("dismiss", function(){
            console.log("Banner dismissed the modal content");
            bannerStatus.text = "Banner dismissed modal";
        });
    }

    function createInterstitial() {

        interstitial = adService.createInterstitial();

        interstitial.on("load", function(){
            console.log("Interstitial loaded");
            interstitialStatus.text = "Interstitial loaded";
        });
        interstitial.on("fail", function(){
            console.log("Interstitial failed");
            interstitialStatus.text = "Interstitial failed";
        });
        interstitial.on("show", function(){
            console.log("Interstitial shown");
            interstitialStatus.text = "Interstitial shown";
        });
        interstitial.on("dismiss", function(){
            console.log("Interstitial dismissed");
            interstitialStatus.text = "Interstitial dismissed";
        });
    }

    function showProviderSelector() {

        var btnTestAdmob = createButton("Test AdMob", function(){
            if (!window.Cocoon || !Cocoon.Ad || !Cocoon.Ad.AdMob) {
                alert('Cocoon AdMob plugin not installed');
                return;
            }
            adService = Cocoon.Ad.AdMob;
            adService.configure({
                 ios: {
                      banner:"ca-app-pub-7686972479101507/8873903476",
                      interstitial:"ca-app-pub-7686972479101507/8873903476",
                 },
                 android: {
                      banner:"ca-app-pub-7686972479101507/4443703872",
                      interstitial:"ca-app-pub-7686972479101507/4443703872"
                 }
            });

        });
        var btnTestMoPub = createButton("Test MoPub", function(){

            if (!window.Cocoon || !Cocoon.Ad || !Cocoon.Ad.MoPub) {
                alert('Cocoon MoPub plugin not installed');
                return;
            }
            adService = Cocoon.Ad.MoPub;
            adService.configure({
                 ios: {
                      banner:"agltb3B1Yi1pbmNyDQsSBFNpdGUY5dDoEww",
                      bannerIpad:"agltb3B1Yi1pbmNyDQsSBFNpdGUYk8vlEww", //optional
                      interstitial:"agltb3B1Yi1pbmNyDQsSBFNpdGUYjf30Eww",
                      interstitialIpad:"agltb3B1Yi1pbmNyDQsSBFNpdGUYjf30Eww", //optional
                 },
                 android: {
                      banner:"68949c5d9de74b79bb79aa29c203ca02",
                      interstitial:"74a813ae7a404881bf17eb8d1b0aa943"
                 }
            });
            showControls();
        });

        btnTestAdmob.position.set(0, -50);
        container.addChild(btnTestAdmob);

        btnTestMoPub.position.set(0, 50);
        container.addChild(btnTestMoPub);
    }

    function showControls() {
        container.removeChildren();
        if (adService) {
            createBanner();
            createInterstitial();
        }

         //Add buttons
        var btnShowBanner = createButton("Show banner", function(){
            banner.show();
        });
        var btnHideBanner = createButton("Hide banner", function(){
            banner.hide();
        });
        var btnChangePosition = createButton("Change position", function(){
            if (demoPosition == Cocoon.Ad.BannerLayout.BOTTOM_CENTER) {
                demoPosition = Cocoon.Ad.BannerLayout.TOP_CENTER;
            }
            else {
                demoPosition = Cocoon.Ad.BannerLayout.BOTTOM_CENTER;
            }
            banner.setLayout(demoPosition);
        });
        var btnLoadBanner = createButton("Load banner", function(){
            bannerStatus.text = "Loading...";
            banner.load();
        });

        btnShowBanner.position.set(150, -150);
        container.addChild(btnShowBanner);

        btnHideBanner.position.set(150, -50);
        container.addChild(btnHideBanner);

        btnChangePosition.position.set(150, 50);
        container.addChild(btnChangePosition);

        btnLoadBanner.position.set(150, 150);
        container.addChild(btnLoadBanner);

        var btnShowInterstitial = createButton("Show interstial", function(){
            interstitial.show();
        });

        var btnLoadInterstitial = createButton("Load interstial", function(){
            interstitialStatus.text = "Loading...";
            interstitial.load();
        });

        btnShowInterstitial.position.set(-150, -50);
        container.addChild(btnShowInterstitial);

        btnLoadInterstitial.position.set(-150, 50);
        container.addChild(btnLoadInterstitial);

        bannerStatus = createText("Created", 30, "#000");
        interstitialStatus = createText("Created", 30, "#000");

        bannerStatus.position.set(150, 250);
        container.addChild(bannerStatus);

        interstitialStatus.position.set(-150, 250);
        container.addChild(interstitialStatus);
    }

    function initDemo(){

        var renderer = PIXI.autoDetectRenderer(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.view);

        var W = 800;
        var H = 600;

        //load resources
        backgroundTexture = PIXI.Texture.fromImage('./images/background.jpg');
        button1Texture = PIXI.Texture.fromImage('./images/button1.png');
        button2Texture = PIXI.Texture.fromImage('./images/button2.png');

        var stage = new PIXI.Container();
        stage.interactive = true;

        //Add background
        var background = new PIXI.Sprite(backgroundTexture);
        background.width = renderer.width;
        background.height = renderer.height;
        stage.addChild(background);

        var scale = Math.min(renderer.width/W, renderer.height/H);
        container = new PIXI.Container();
        container.scale.set(scale, scale);
        container.position.set(renderer.width/2, renderer.height/2);
        stage.addChild(container);

        showProviderSelector();
        // start animating
        animate();
        function animate() {
            requestAnimationFrame(animate);
            renderer.render(stage);
        }
    }

    function createButton(text, callback) {

        var button = new PIXI.Sprite(button1Texture);
        button.anchor.set(0.5, 0.5);
        button.interactive = true;
        button.addChild(createText(text));

        button.mousedown = button.touchstart = function(){
            this.texture = button2Texture;
            callback();
        };

        button.mouseup = button.touchend = function(){
            this.texture = button1Texture;
        };

        return button;
    }

    function createText(text, size, fill){
        size = size || 25;
        fill = fill || "#ffffff";
        var txt = new PIXI.Text(text, {
            fill: fill,
            font: size + "px Arial"
        });
        txt.anchor.set(0.5, 0.5);

        return txt;
    }

    if (window.cordova) {
        document.addEventListener("deviceready", initDemo);
    }
    else {
        window.onload = initDemo;
    }

})();

<commit_msg>show admob controls<commit_after>"use strict";

(function(){
    var bannerStatus;
    var interstitialStatus;

    var banner;
    var interstitial;
    var demoPosition;

    var backgroundTexture;
    var button1Texture;
    var button2Texture;

    var adService;

    var container;

    function createBanner() {

        banner = adService.createBanner();

        banner.on("load", function(){
            console.log("Banner loaded " + banner.width, banner.height);
            bannerStatus.text = "Banner loaded";
        });

        banner.on("fail", function(){
            console.log("Banner failed to load");
            bannerStatus.text = "Banner failed";
        });

        banner.on("show", function(){
            console.log("Banner shown a modal content");
            bannerStatus.text = "Banner show modal content";
        });

        banner.on("dismiss", function(){
            console.log("Banner dismissed the modal content");
            bannerStatus.text = "Banner dismissed modal";
        });
    }

    function createInterstitial() {

        interstitial = adService.createInterstitial();

        interstitial.on("load", function(){
            console.log("Interstitial loaded");
            interstitialStatus.text = "Interstitial loaded";
        });
        interstitial.on("fail", function(){
            console.log("Interstitial failed");
            interstitialStatus.text = "Interstitial failed";
        });
        interstitial.on("show", function(){
            console.log("Interstitial shown");
            interstitialStatus.text = "Interstitial shown";
        });
        interstitial.on("dismiss", function(){
            console.log("Interstitial dismissed");
            interstitialStatus.text = "Interstitial dismissed";
        });
    }

    function showProviderSelector() {

        var btnTestAdmob = createButton("Test AdMob", function(){
            if (!window.Cocoon || !Cocoon.Ad || !Cocoon.Ad.AdMob) {
                alert('Cocoon AdMob plugin not installed');
                return;
            }
            adService = Cocoon.Ad.AdMob;
            adService.configure({
                 ios: {
                      banner:"ca-app-pub-7686972479101507/8873903476",
                      interstitial:"ca-app-pub-7686972479101507/8873903476",
                 },
                 android: {
                      banner:"ca-app-pub-7686972479101507/4443703872",
                      interstitial:"ca-app-pub-7686972479101507/4443703872"
                 }
            });
            showControls();

        });
        var btnTestMoPub = createButton("Test MoPub", function(){

            if (!window.Cocoon || !Cocoon.Ad || !Cocoon.Ad.MoPub) {
                alert('Cocoon MoPub plugin not installed');
                return;
            }
            adService = Cocoon.Ad.MoPub;
            adService.configure({
                 ios: {
                      banner:"agltb3B1Yi1pbmNyDQsSBFNpdGUY5dDoEww",
                      bannerIpad:"agltb3B1Yi1pbmNyDQsSBFNpdGUYk8vlEww", //optional
                      interstitial:"agltb3B1Yi1pbmNyDQsSBFNpdGUYjf30Eww",
                      interstitialIpad:"agltb3B1Yi1pbmNyDQsSBFNpdGUYjf30Eww", //optional
                 },
                 android: {
                      banner:"68949c5d9de74b79bb79aa29c203ca02",
                      interstitial:"74a813ae7a404881bf17eb8d1b0aa943"
                 }
            });
            showControls();
        });

        btnTestAdmob.position.set(0, -50);
        container.addChild(btnTestAdmob);

        btnTestMoPub.position.set(0, 50);
        container.addChild(btnTestMoPub);
    }

    function showControls() {
        container.removeChildren();
        if (adService) {
            createBanner();
            createInterstitial();
        }

         //Add buttons
        var btnShowBanner = createButton("Show banner", function(){
            banner.show();
        });
        var btnHideBanner = createButton("Hide banner", function(){
            banner.hide();
        });
        var btnChangePosition = createButton("Change position", function(){
            if (demoPosition == Cocoon.Ad.BannerLayout.BOTTOM_CENTER) {
                demoPosition = Cocoon.Ad.BannerLayout.TOP_CENTER;
            }
            else {
                demoPosition = Cocoon.Ad.BannerLayout.BOTTOM_CENTER;
            }
            banner.setLayout(demoPosition);
        });
        var btnLoadBanner = createButton("Load banner", function(){
            bannerStatus.text = "Loading...";
            banner.load();
        });

        btnShowBanner.position.set(150, -150);
        container.addChild(btnShowBanner);

        btnHideBanner.position.set(150, -50);
        container.addChild(btnHideBanner);

        btnChangePosition.position.set(150, 50);
        container.addChild(btnChangePosition);

        btnLoadBanner.position.set(150, 150);
        container.addChild(btnLoadBanner);

        var btnShowInterstitial = createButton("Show interstial", function(){
            interstitial.show();
        });

        var btnLoadInterstitial = createButton("Load interstial", function(){
            interstitialStatus.text = "Loading...";
            interstitial.load();
        });

        btnShowInterstitial.position.set(-150, -50);
        container.addChild(btnShowInterstitial);

        btnLoadInterstitial.position.set(-150, 50);
        container.addChild(btnLoadInterstitial);

        bannerStatus = createText("Created", 30, "#000");
        interstitialStatus = createText("Created", 30, "#000");

        bannerStatus.position.set(150, 250);
        container.addChild(bannerStatus);

        interstitialStatus.position.set(-150, 250);
        container.addChild(interstitialStatus);
    }

    function initDemo(){

        var renderer = PIXI.autoDetectRenderer(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.view);

        var W = 800;
        var H = 600;

        //load resources
        backgroundTexture = PIXI.Texture.fromImage('./images/background.jpg');
        button1Texture = PIXI.Texture.fromImage('./images/button1.png');
        button2Texture = PIXI.Texture.fromImage('./images/button2.png');

        var stage = new PIXI.Container();
        stage.interactive = true;

        //Add background
        var background = new PIXI.Sprite(backgroundTexture);
        background.width = renderer.width;
        background.height = renderer.height;
        stage.addChild(background);

        var scale = Math.min(renderer.width/W, renderer.height/H);
        container = new PIXI.Container();
        container.scale.set(scale, scale);
        container.position.set(renderer.width/2, renderer.height/2);
        stage.addChild(container);

        showProviderSelector();
        // start animating
        animate();
        function animate() {
            requestAnimationFrame(animate);
            renderer.render(stage);
        }
    }

    function createButton(text, callback) {

        var button = new PIXI.Sprite(button1Texture);
        button.anchor.set(0.5, 0.5);
        button.interactive = true;
        button.addChild(createText(text));

        button.mousedown = button.touchstart = function(){
            this.texture = button2Texture;
            callback();
        };

        button.mouseup = button.touchend = function(){
            this.texture = button1Texture;
        };

        return button;
    }

    function createText(text, size, fill){
        size = size || 25;
        fill = fill || "#ffffff";
        var txt = new PIXI.Text(text, {
            fill: fill,
            font: size + "px Arial"
        });
        txt.anchor.set(0.5, 0.5);

        return txt;
    }

    if (window.cordova) {
        document.addEventListener("deviceready", initDemo);
    }
    else {
        window.onload = initDemo;
    }

})();

<|endoftext|>


<commit_before>$(function(){
    $('body').addClass('js-on');

    // A - Z Sorting
    $('.alpha-sort a').click(function(e){
        e.preventDefault();
        var term = $(this).text();
        var $sites = $('.sites section');

        $sites.show().filter(function() {
            var text = $(this).find('.site-header').text().replace(/\s+/g, ' ').toLowerCase().substr(1,1);
            return !~text.indexOf(term);
        }).hide();

        if ( ! $('.site-block').is(':visible')) {
            $('.no-results').show();
        }
    });

    // Difficulty sorting
    $('.diff-sort a').click(function(e){
        e.preventDefault();
        var term = $(this).text().toLowerCase();
        var $sites = $('.sites section');

        $sites.show().filter(function() {
            var text = $(this).find('.site-difficulty').text().replace(/\s+/g, ' ').toLowerCase();
            return !~text.indexOf(term);
        }).hide();

        if ( ! $('.site-block').is(':visible')) {
            $('.no-results').show();
        }
    });

    // Popular sorting
    $('button.popular').click(function(e){
        e.preventDefault();
        var term = "popular";
        var $sites = $('.sites section');

        $sites.show().filter(function() {
            var text = $(this).find('.meta').text().replace(/\s+/g, ' ').toLowerCase();
            return !~text.indexOf(term);
        }).hide();

        if ( ! $('.site-block').is(':visible')) {
            $('.no-results').show();
        }
    });

    // Clear search and sorting
    $('button.reset').click(function(e){
        var $sites = $('.sites section');
        $sites.show();
        $('.no-results').hide();
        $('input').val('');
    });

    // When the search field changes, update the hash
    $('input').on('input', function(){
        window.location.hash = $(this).val();
    });

    // Call updateSearch when hash changes
    $(window).on('hashchange', function() {
        updateSearch();
    });

    // Search function
    function updateSearch() {
        if ($('.no-results').is(':visible')) {
            $('.no-results').hide();
        }

        var hash = document.location.hash.toLowerCase();
        var term = hash.substr(1);

        var $sites = $('.sites section');

        $sites.show().filter(function() {
            var text = $(this).find('.site-header').text().replace(/\s+/g, ' ').toLowerCase();
            return !~text.indexOf(term);
        }).hide();

        if ( ! $('.site-block').is(':visible')) {
            $('.no-results').show();
        }

        // Insert the term into the field
        // (sometimes this is missed if the hash is changed directly)
        $('#search').val(window.location.hash.substr(1));
    }

    // Update search results on page load (if there is a hash)
    if (window.location.hash !== "" && window.location.hash !== "#") {
        // Insert the term into the field
        $('#search').val(window.location.hash.substr(1));

        // Update the results
        updateSearch();
    }

    $('.site a').prop('title', '');

    // jQuery ScrollTo plugin from http://lions-mark.com/jquery/scrollTo/

    $.fn.scrollTo = function( target, options, callback ){
        if(typeof options == 'function' && arguments.length == 2){ callback = options; options = target; }
        var settings = $.extend({
            scrollTarget  : target,
            offsetTop     : 50,
            duration      : 500,
            easing        : 'swing'
        }, options);
        return this.each(function(){
            var scrollPane = $(this);
            var scrollTarget = (typeof settings.scrollTarget == "number") ? settings.scrollTarget : $(settings.scrollTarget);
            var scrollY = (typeof scrollTarget == "number") ? scrollTarget : scrollTarget.offset().top + scrollPane.scrollTop() - parseInt(settings.offsetTop);
            scrollPane.animate({scrollTop : scrollY }, parseInt(settings.duration), settings.easing, function(){
                if (typeof callback == 'function') { callback.call(this); }
            });
        });
    }

    // Banner scroll to bottom

    $('.banner').click(function(e) {
        e.preventDefault();
        $('body').scrollTo('.banner-block');
    });

    $('.info').click(function(e) {
        e.preventDefault();
        $('body').scrollTo('.about');
    });

    // create the keys and konami variables
    var keys = [],
    konami = "38,38,40,40,37,39,37,39,66,65";

    $(document).keydown(function(e){
        keys.push(e.keyCode);

        // and check to see if the user has entered the Konami code
        if (keys.toString().indexOf(konami) >= 0) {

            // do something such as:
            (function(){
                $('.site-block:first').after('
NSA
Difficulty: impossible

No Info Available

'
                    +'
GCHQ
Difficulty: impossible

No Info Available

');
            })();

            // and finally clean up the keys array
            keys = [];
        }
    });
});

// Load Facebook after page load
window.onload = function() {

    $('#search').focus();

    (function(d, s, id) {
        var js, fjs = d.getElementsByTagName(s)[0];
        if (d.getElementById(id)) return;
        js = d.createElement(s); js.id = id;
        js.src = "//connect.facebook.net/en_GB/all.js#xfbml=1";
        fjs.parentNode.insertBefore(js, fjs);
    }(document, 'script', 'facebook-jssdk'));

    console.log('Welcome to justdelete.me. We currently have ' + $('.site-block').length + ' services listed.');
};
<commit_msg>Add a hash update timer to prevent excessive changes<commit_after>$(function(){
    $('body').addClass('js-on');

    // A - Z Sorting
    $('.alpha-sort a').click(function(e){
        e.preventDefault();
        var term = $(this).text();
        var $sites = $('.sites section');

        $sites.show().filter(function() {
            var text = $(this).find('.site-header').text().replace(/\s+/g, ' ').toLowerCase().substr(1,1);
            return !~text.indexOf(term);
        }).hide();

        if ( ! $('.site-block').is(':visible')) {
            $('.no-results').show();
        }
    });

    // Difficulty sorting
    $('.diff-sort a').click(function(e){
        e.preventDefault();
        var term = $(this).text().toLowerCase();
        var $sites = $('.sites section');

        $sites.show().filter(function() {
            var text = $(this).find('.site-difficulty').text().replace(/\s+/g, ' ').toLowerCase();
            return !~text.indexOf(term);
        }).hide();

        if ( ! $('.site-block').is(':visible')) {
            $('.no-results').show();
        }
    });

    // Popular sorting
    $('button.popular').click(function(e){
        e.preventDefault();
        var term = "popular";
        var $sites = $('.sites section');

        $sites.show().filter(function() {
            var text = $(this).find('.meta').text().replace(/\s+/g, ' ').toLowerCase();
            return !~text.indexOf(term);
        }).hide();

        if ( ! $('.site-block').is(':visible')) {
            $('.no-results').show();
        }
    });

    // Clear search and sorting
    $('button.reset').click(function(e){
        var $sites = $('.sites section');
        $sites.show();
        $('.no-results').hide();
        $('input').val('');
    });

    // When the search field changes, update the hash
    var hashUpdateTimer;
    $('input').on('input', function(){
        window.clearTimeout(hashUpdateTimer);
        hashUpdateTimer = setTimeout(setWindowHash, 250, $(this).val());
    });

    function setWindowHash(value) {
        window.location.hash = value;
    }

    // Call updateSearch when hash changes
    $(window).on('hashchange', function() {
        updateSearch();
    });

    // Search function
    function updateSearch() {
        if ($('.no-results').is(':visible')) {
            $('.no-results').hide();
        }

        var hash = document.location.hash.toLowerCase();
        var term = hash.substr(1);

        var $sites = $('.sites section');

        $sites.show().filter(function() {
            var text = $(this).find('.site-header').text().replace(/\s+/g, ' ').toLowerCase();
            return !~text.indexOf(term);
        }).hide();

        if ( ! $('.site-block').is(':visible')) {
            $('.no-results').show();
        }

        // Insert the term into the field
        // (sometimes this is missed if the hash is changed directly)
        $('#search').val(window.location.hash.substr(1));
    }

    // Update search results on page load (if there is a hash)
    if (window.location.hash !== "" && window.location.hash !== "#") {
        // Insert the term into the field
        $('#search').val(window.location.hash.substr(1));

        // Update the results
        updateSearch();
    }

    $('.site a').prop('title', '');

    // jQuery ScrollTo plugin from http://lions-mark.com/jquery/scrollTo/

    $.fn.scrollTo = function( target, options, callback ){
        if(typeof options == 'function' && arguments.length == 2){ callback = options; options = target; }
        var settings = $.extend({
            scrollTarget  : target,
            offsetTop     : 50,
            duration      : 500,
            easing        : 'swing'
        }, options);
        return this.each(function(){
            var scrollPane = $(this);
            var scrollTarget = (typeof settings.scrollTarget == "number") ? settings.scrollTarget : $(settings.scrollTarget);
            var scrollY = (typeof scrollTarget == "number") ? scrollTarget : scrollTarget.offset().top + scrollPane.scrollTop() - parseInt(settings.offsetTop);
            scrollPane.animate({scrollTop : scrollY }, parseInt(settings.duration), settings.easing, function(){
                if (typeof callback == 'function') { callback.call(this); }
            });
        });
    }

    // Banner scroll to bottom

    $('.banner').click(function(e) {
        e.preventDefault();
        $('body').scrollTo('.banner-block');
    });

    $('.info').click(function(e) {
        e.preventDefault();
        $('body').scrollTo('.about');
    });

    // create the keys and konami variables
    var keys = [],
    konami = "38,38,40,40,37,39,37,39,66,65";

    $(document).keydown(function(e){
        keys.push(e.keyCode);

        // and check to see if the user has entered the Konami code
        if (keys.toString().indexOf(konami) >= 0) {

            // do something such as:
            (function(){
                $('.site-block:first').after('
NSA
Difficulty: impossible

No Info Available

'
                    +'
GCHQ
Difficulty: impossible

No Info Available

');
            })();

            // and finally clean up the keys array
            keys = [];
        }
    });
});

// Load Facebook after page load
window.onload = function() {

    $('#search').focus();

    (function(d, s, id) {
        var js, fjs = d.getElementsByTagName(s)[0];
        if (d.getElementById(id)) return;
        js = d.createElement(s); js.id = id;
        js.src = "//connect.facebook.net/en_GB/all.js#xfbml=1";
        fjs.parentNode.insertBefore(js, fjs);
    }(document, 'script', 'facebook-jssdk'));

    console.log('Welcome to justdelete.me. We currently have ' + $('.site-block').length + ' services listed.');
};
<|endoftext|>


<commit_before>// Amara, universalsubtitles.org
//
// Copyright (C) 2012 Participatory Culture Foundation
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see
// http://www.gnu.org/licenses/agpl-3.0.html.

(function() {

    var root, SubtitleListController, SubtitleListItemController,
        HelperSelectorController;

    root = this;

    /**
     * Responsible for everything that touches subtitles as a group,
     * souch as populating the list with actual data, removing subs,
     * adding subs.
     * @param $scope
     * @param SubtitleStorage
     * @constructor
     */
    SubtitleListController = function($scope, SubtitleStorage) {
        $scope.getSubtitles = function(languageCode, versionNumber) {
            // if this version has no default source translation language
            // it will be empty, in which case we want to wait for user
            // interaction to request a reference subtitle set.
            if (!languageCode || !versionNumber){
                $scope.status = 'idle';
                return;
            }
            $scope.status = 'loading';
            $scope.items = SubtitleStorage.getSubtitles(languageCode, versionNumber, function(subtitlesXML) {
                $scope.onSubtitlesFetched(subtitlesXML);
            });
        };
        /**
         * Once we have the dfxp from the server,
         * massage the data as a simpler object and set it on the
         * template. Angular will pick up the change (from the broadcast)
         * and will re-render the UI.
         * @param dfxpXML
         */
        $scope.onSubtitlesFetched = function (dfxpXML) {

            this.dfxpWrapper = new AmaraDFXPParser();
            this.dfxpWrapper.init(dfxpXML);
            // now populate the subtitles scope var
            // and let angular build the UI
            var subtitles = this.dfxpWrapper.getSubtitles();
            // preallocate array, gives us a small perf gain
            // on ie / safari
            var subtitlesData = new Array(subtitles.length);
            for (var i=0; i < subtitles.length; i++){
                subtitlesData[i] =  {
                    index: i,
                    startTime: this.dfxpWrapper.startTime(subtitles.eq(i).get(0)),
                    endTime: this.dfxpWrapper.endTime(subtitles.eq(i).get(0)),
                    text: this.dfxpWrapper.contentRendered(subtitles.eq(i).get(0))
                };
            }
            $scope.subtitlesData = subtitlesData;
            // only let the descendant scope know of this, no need to propagate
            // upwards
            $scope.status = 'ready';
            $scope.$broadcast("onSubtitlesFetched");

        };
        $scope.setSelectedIndex = function(index){
            $scope.selectedIndex = index;
            $scope.$digest();
        };

        $scope.setVideoID = function(videoID){
            $scope.videoID = videoID;
        };

        $scope.setLanguageCode = function(languageCode){
            $scope.languageCode = languageCode;
        };
        $scope.saveSubtitles = function(){
            SubtitleStorage.saveSubtitles($scope.videoID,
                                          $scope.languageCode,
                                          this.dfxpWrapper.xmlToString(true, true));
            $scope.status = 'saving';
        };
    };

    /**
     * Responsible for actions on one subtitle: editing, selecting.
     * @param $scope
     * @constructor
     */
    SubtitleListItemController = function($scope, SubtitleStorage) {
        // we expect to have on the scope the object that
        // SubtitleListController.onSubtitlesFetched
        // has created from the dfxp

        var initialText;
        $scope.isEditing = false;
        $scope.toHTML = function(markupLikeText) {
        };

        $scope.startEditingMode = function() {
            initialText =  this.dfxpWrapper.content($scope.subtitle.index);
            $scope.isEditing  = true;
            // fix me, this should return the markdown text
            return initialText;
        };
        $scope.finishEditingMode = function(newValue){
            $scope.isEditing  = false;
            this.dfxpWrapper.content($scope.getSubtitleNode(), newValue);
            $scope.subtitle.text = this.dfxpWrapper.contentRendered($scope.getSubtitleNode());
            if ($scope.subtitle.text != initialText){
                // mark dirty variable on root scope so we can allow
                // saving the session
                $scope.$root.$emit("onWorkDone");
            }
        };

        $scope.getSubtitleNode = function() {
            return this.dfxpWrapper.getSubtitle($scope.subtitle.index);
        };

        $scope.setEditable = function(isEditable) {
        };

        $scope.textChanged = function(newText) {
            $scope.subtitle.text = newText;
        };
    };

    HelperSelectorController = function($scope, SubtitleStorage,
                                        SubtitleListFinder) {

        $scope.getPrimaryAudioLanguage = function(languages) {
            return _.find(languages, function(language) {
                return language.is_primary_audio_language;
            });
        };

        $scope.languageSelectChanged = function(lang) {
            var vers, language;

            if (lang) {
                language = lang;
            } else {
                language = $scope.language;
            }

            vers =_.sortBy(language.versions, function(item) {
                return item.number;
            });
            $scope.versions = vers.reverse();
            if (vers.length && vers.length > 0) {
                $scope.version = $scope.versions[0];
            }
        };

        SubtitleStorage.getLanguages(function(languages) {
            $scope.languages = languages;
            $scope.language = _.find(languages, function(item) {
                return item.editingLanguage;
            });
            $scope.languageSelectChanged($scope.language);
        });

        $scope.versionChanged = function(newVersion, oldVersion) {
            if (!newVersion) {
                return;
            }
            var subtitles = newVersion.subtitlesXML;

            if (!subtitles) {
                throw Error("Version doesn't contain subs.");
            }
            var refSubList = SubtitleListFinder.get('reference-subtitle-set');
            refSubList.scope.onSubtitlesFetched(subtitles);
        };

        $scope.$watch('version', $scope.versionChanged);
    };

    SaveSessionButtonController = function($scope, SubtitleListFinder){
        // since the button can be outside of the subtitle list directive
        // we need the service to find out which set we're saving.
        $scope.saveSession = function(){
            SubtitleListFinder.get('working-subtitle-set').scope.saveSubtitles();
        };
        $scope.$root.$on("onWorkDone", function(){
            $scope.canSave = '';
            $scope.$digest();
        });
    };
    // exports
    root.SubtitleListController = SubtitleListController;
    root.SubtitleListItemController = SubtitleListItemController;
    root.HelperSelectorController = HelperSelectorController;

}).call(this);
<commit_msg>Don't leak SaveSession var<commit_after>// Amara, universalsubtitles.org
//
// Copyright (C) 2012 Participatory Culture Foundation
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see
// http://www.gnu.org/licenses/agpl-3.0.html.

(function() {

    var root, SubtitleListController, SubtitleListItemController,
        HelperSelectorController, SaveSessionButtonController;

    root = this;

    /**
     * Responsible for everything that touches subtitles as a group,
     * souch as populating the list with actual data, removing subs,
     * adding subs.
     * @param $scope
     * @param SubtitleStorage
     * @constructor
     */
    SubtitleListController = function($scope, SubtitleStorage) {
        $scope.getSubtitles = function(languageCode, versionNumber) {
            // if this version has no default source translation language
            // it will be empty, in which case we want to wait for user
            // interaction to request a reference subtitle set.
            if (!languageCode || !versionNumber){
                $scope.status = 'idle';
                return;
            }
            $scope.status = 'loading';
            $scope.items = SubtitleStorage.getSubtitles(languageCode, versionNumber, function(subtitlesXML) {
                $scope.onSubtitlesFetched(subtitlesXML);
            });
        };
        /**
         * Once we have the dfxp from the server,
         * massage the data as a simpler object and set it on the
         * template. Angular will pick up the change (from the broadcast)
         * and will re-render the UI.
         * @param dfxpXML
         */
        $scope.onSubtitlesFetched = function (dfxpXML) {

            this.dfxpWrapper = new AmaraDFXPParser();
            this.dfxpWrapper.init(dfxpXML);
            // now populate the subtitles scope var
            // and let angular build the UI
            var subtitles = this.dfxpWrapper.getSubtitles();
            // preallocate array, gives us a small perf gain
            // on ie / safari
            var subtitlesData = new Array(subtitles.length);
            for (var i=0; i < subtitles.length; i++){
                subtitlesData[i] =  {
                    index: i,
                    startTime: this.dfxpWrapper.startTime(subtitles.eq(i).get(0)),
                    endTime: this.dfxpWrapper.endTime(subtitles.eq(i).get(0)),
                    text: this.dfxpWrapper.contentRendered(subtitles.eq(i).get(0))
                };
            }
            $scope.subtitlesData = subtitlesData;
            // only let the descendant scope know of this, no need to propagate
            // upwards
            $scope.status = 'ready';
            $scope.$broadcast("onSubtitlesFetched");

        };
        $scope.setSelectedIndex = function(index){
            $scope.selectedIndex = index;
            $scope.$digest();
        };

        $scope.setVideoID = function(videoID){
            $scope.videoID = videoID;
        };

        $scope.setLanguageCode = function(languageCode){
            $scope.languageCode = languageCode;
        };
        $scope.saveSubtitles = function(){
            SubtitleStorage.saveSubtitles($scope.videoID,
                                          $scope.languageCode,
                                          this.dfxpWrapper.xmlToString(true, true));
            $scope.status = 'saving';
        };
    };

    /**
     * Responsible for actions on one subtitle: editing, selecting.
     * @param $scope
     * @constructor
     */
    SubtitleListItemController = function($scope, SubtitleStorage) {
        // we expect to have on the scope the object that
        // SubtitleListController.onSubtitlesFetched
        // has created from the dfxp

        var initialText;
        $scope.isEditing = false;
        $scope.toHTML = function(markupLikeText) {
        };

        $scope.startEditingMode = function() {
            initialText =  this.dfxpWrapper.content($scope.subtitle.index);
            $scope.isEditing  = true;
            // fix me, this should return the markdown text
            return initialText;
        };
        $scope.finishEditingMode = function(newValue){
            $scope.isEditing  = false;
            this.dfxpWrapper.content($scope.getSubtitleNode(), newValue);
            $scope.subtitle.text = this.dfxpWrapper.contentRendered($scope.getSubtitleNode());
            if ($scope.subtitle.text != initialText){
                // mark dirty variable on root scope so we can allow
                // saving the session
                $scope.$root.$emit("onWorkDone");
            }
        };

        $scope.getSubtitleNode = function() {
            return this.dfxpWrapper.getSubtitle($scope.subtitle.index);
        };

        $scope.setEditable = function(isEditable) {
        };

        $scope.textChanged = function(newText) {
            $scope.subtitle.text = newText;
        };
    };

    HelperSelectorController = function($scope, SubtitleStorage,
                                        SubtitleListFinder) {

        $scope.getPrimaryAudioLanguage = function(languages) {
            return _.find(languages, function(language) {
                return language.is_primary_audio_language;
            });
        };

        $scope.languageSelectChanged = function(lang) {
            var vers, language;

            if (lang) {
                language = lang;
            } else {
                language = $scope.language;
            }

            vers =_.sortBy(language.versions, function(item) {
                return item.number;
            });
            $scope.versions = vers.reverse();
            if (vers.length && vers.length > 0) {
                $scope.version = $scope.versions[0];
            }
        };

        SubtitleStorage.getLanguages(function(languages) {
            $scope.languages = languages;
            $scope.language = _.find(languages, function(item) {
                return item.editingLanguage;
            });
            $scope.languageSelectChanged($scope.language);
        });

        $scope.versionChanged = function(newVersion, oldVersion) {
            if (!newVersion) {
                return;
            }
            var subtitles = newVersion.subtitlesXML;

            if (!subtitles) {
                throw Error("Version doesn't contain subs.");
            }
            var refSubList = SubtitleListFinder.get('reference-subtitle-set');
            refSubList.scope.onSubtitlesFetched(subtitles);
        };

        $scope.$watch('version', $scope.versionChanged);
    };

    SaveSessionButtonController = function($scope, SubtitleListFinder){
        // since the button can be outside of the subtitle list directive
        // we need the service to find out which set we're saving.
        $scope.saveSession = function(){
            SubtitleListFinder.get('working-subtitle-set').scope.saveSubtitles();
        };
        $scope.$root.$on("onWorkDone", function(){
            $scope.canSave = '';
            $scope.$digest();
        });
    };
    // exports
    root.SubtitleListController = SubtitleListController;
    root.SubtitleListItemController = SubtitleListItemController;
    root.HelperSelectorController = HelperSelectorController;

}).call(this);
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { Button } from 'react-bootstrap';

import app   from '../../utils/app';

import AppActions from '../../actions/AppActions';

const shell = electron.shell;

/*
|--------------------------------------------------------------------------
| Child - About
|--------------------------------------------------------------------------
*/

export default class SettingsAbout extends Component {

    constructor(props) {

        super(props);
        this.state = {};
    }

    render() {

        let self = this;
        let museeksLogo = 'dist/' + require('../../../images/logos/museeks.png'); // sth wrong with that, need some check with Webpack

        // Don't add yourself here please, I'll do it myself
        let contributors = [
            {
                name: 'Alba de Zanet',
                pseudo: 'Alba',
                feature: 'Museeks logo',
                url: 'https://www.behance.net/albadezanet'
            },
            {
                name: 'Moritz',
                pseudo: 'mrzmyr',
                feature: 'repeat feature',
                url: 'https://github.com/mrzmyr'
            },
            {
                name: 'Jonathan Alpay',
                pseudo: 'Suriteka',
                feature: 'icons editing',
                url: 'http://twitter.com/Suriteka '
            }
        ];

        let contributorsList = contributors.map(function(data, index) {
            return (

                    { data.name } ({ data.pseudo }): { data.feature }

            )
        });

        return (

About Museeks

                        Museeks { app.version } - museeks.io
                        <Button bsSize='small'  className='update-checker' onClick={ this.checkForUpdate.bind(null) }>Check for update</Button>

Contributors

Made with ♥ by Pierre de la Martinière (KeitIG) and a bunch of great people:

                            { contributorsList }

        );
    }

    openLink(link, e) {
        e.preventDefault();
        shell.openExternal(link);
    }

    checkForUpdate() {
        AppActions.app.checkForUpdate();
    }
}
<commit_msg>Update contributors list<commit_after>import React, { Component } from 'react';
import { Button } from 'react-bootstrap';

import app   from '../../utils/app';

import AppActions from '../../actions/AppActions';

const shell = electron.shell;

/*
|--------------------------------------------------------------------------
| Child - About
|--------------------------------------------------------------------------
*/

export default class SettingsAbout extends Component {

    constructor(props) {

        super(props);
        this.state = {};
    }

    render() {

        let self = this;
        let museeksLogo = 'dist/' + require('../../../images/logos/museeks.png'); // sth wrong with that, need some check with Webpack

        // Don't add yourself here please, I'll do it myself
        let contributors = [
            {
                name: 'Alba de Zanet',
                pseudo: 'Alba',
                feature: 'Museeks logo',
                url: 'https://www.behance.net/albadezanet'
            },
            {
                name: 'Moritz',
                pseudo: 'mrzmyr',
                feature: 'repeat feature',
                url: 'https://github.com/mrzmyr'
            },
            {
                name: 'Jonathan Alpay',
                pseudo: 'Suriteka',
                feature: 'icons editing',
                url: 'http://twitter.com/Suriteka '
            },
            {
                name: 'Yury Solovyov',
                pseudo: 'YurySolovyov',
                feature: 'Build improvements',
                url: 'https://github.com/YurySolovyov'
            }
        ];

        let contributorsList = contributors.map(function(data, index) {
            return (

                    { data.name } ({ data.pseudo }): { data.feature }

            )
        });

        return (

About Museeks

                        Museeks { app.version } - museeks.io
                        <Button bsSize='small'  className='update-checker' onClick={ this.checkForUpdate.bind(null) }>Check for update</Button>

Contributors

Made with ♥ by Pierre de la Martinière (KeitIG) and a bunch of great people:

                            { contributorsList }

        );
    }

    openLink(link, e) {
        e.preventDefault();
        shell.openExternal(link);
    }

    checkForUpdate() {
        AppActions.app.checkForUpdate();
    }
}
<|endoftext|>