<commit_before>'use strict';

const NAMESPACE = 'urn:x-cast:com.google.ads.ima.cast';

class Player {
  /**
   * Represents the receiver
   * @param {!Object} mediaElement - the cast media player element
   */
  constructor(mediaElement) {
    /**
     * the fallback stream to play if loading fails
     * @type {string}
     * @private
     * @const
     */
    this.backupStream_ = 'http://storage.googleapis.com/testtopbox-public/' +
        'video_content/bbb/master.m3u8';

    /**
     * the cast context object provided by the CAF framework.
     * @type {!Object}
     * @private
     * @const
     */
    this.castContext_ = cast.framework.CastReceiverContext.getInstance();

    /**
     * the player manager object, provided by the CAF framework.
     * @type {!Object}
     * @private
     * @const
     */
    this.playerManager_ = this.castContext_.getPlayerManager();

    /**
     * the video player contained within the cast media player element.
     * @type {!HTMLMediaElement}
     * @private
     * @const
     */
    this.mediaElement_ = mediaElement.getMediaElement();

    /**
     * This is the stream manager object for IMA SDK.
     * @type {?Object}
     * @private
     */
    this.streamManager_ = null;

    /**
     * Stores the timestamp where playback will start, in seconds, for
     * bookmarking.
     * @type {number}
     * @private
     */
    this.startTime_ = 0;

    /**
     * Stores a flag to identify whether an ad is currently playing.
     * @type {boolean}
     * @private
     */
    this.adIsPlaying_ = false;

    /**
     * Stores the timestamp to seek to when ad completes, for snapback.
     * -1 indicates that snapback has not been requested.
     * @type {number}
     * @private
     */
    this.seekToTimeAfterAdBreak_ = -1;
  }

  /** Initializes CAF and IMA SDK */
  initialize() {
    // Map of namespace names to their types.
    const options = new cast.framework.CastReceiverOptions();
    options.customNamespaces = {};
    options.customNamespaces[NAMESPACE] =
        cast.framework.system.MessageType.STRING;
    this.castContext_.start(options);
    this.streamManager_ =
        new google.ima.dai.api.StreamManager(this.mediaElement_);
  }

  /** Attaches event listeners and other callbacks. */
  setupCallbacks() {
    // Receives messages from sender app.
    this.castContext_.addCustomMessageListener(NAMESPACE, (event) => {
      this.processSenderMessage_(event.data);
    });

    this.attachPlayerManagerCallbacks_();
    this.attachStreamManagerListeners_();
  }

  /**
   * Parses messages from sender apps. The message is a comma separated
   * string consisting of a function name followed by a set of parameters.
   * @param {string} message - The raw message from the sender app.
   * @private
   */
  processSenderMessage_(message) {
    console.log('Received message from sender: ' + message);
    const messageArray = message.split(',');
    const method = messageArray[0];
    switch (method) {
      case 'bookmark':
        const time = parseFloat(messageArray[1]);
        const bookmarkTime =
            this.streamManager_.contentTimeForStreamTime(time);
        this.broadcast('bookmark,' + bookmarkTime);
        this.bookmark(time);
        break;
      case 'getContentTime':
        const contentTime = this.getContentTime();
        this.broadcast('contentTime,' + contentTime);
        break;
      default:
        this.broadcast('Message not recognized');
        break;
    }
  }

  /**
   * Attaches message interceptors and event listeners to connet IMA to CAF.
   * @private
   */
  attachPlayerManagerCallbacks_() {
    // This intercepts the CAF load process, to load the IMA stream manager and
    // make a DAI stream request. It then injests the stream URL into the
    // original LOAD message, before passing it to CAF
    this.playerManager_.setMessageInterceptor(
        cast.framework.messages.MessageType.LOAD, (request) => {
          return this.initializeStreamManager_(request);
        });

    // This intercepts CAF seek requests to cancel them in the case that an ad
    // is playing, and to modify them to enable snapback
    this.playerManager_.setMessageInterceptor(
        cast.framework.messages.MessageType.SEEK, (seekRequest) => {
          return this.processSeekRequest_(seekRequest);
        });

    // This passes ID3 events from the stream to the IMA to allow for updating
    // stream events on the fly in live streams
    this.playerManager_.addEventListener(
        cast.framework.events.EventType.ID3, (event) => {
          // pass ID3 events from the stream to IMA to update live stream
          // cuepoints
          this.streamManager_.processMetadata(
              'ID3', event.segmentData, event.timestamp);
        });
  }

  /**
   * Attaches IMA event managers
   * @private
   */
  attachStreamManagerListeners_() {
    // This fires at the beginning of each ad break
    this.streamManager_.addEventListener(
        google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED, (event) => {
          this.startAdBreak_();
        });
    // This fires at the end of each ad break
    this.streamManager_.addEventListener(
        google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED, (event) => {
          this.endAdBreak_();
        });
    // This fires periodically while ads are playing
    this.streamManager_.addEventListener(
        google.ima.dai.api.StreamEvent.Type.AD_PROGRESS, (event) => {
          this.updateAdProgress_(event);
        });

    // Log the quartile events to the console for debugging
    const quartileEvents = [
      google.ima.dai.api.StreamEvent.Type.STARTED,
      google.ima.dai.api.StreamEvent.Type.FIRST_QUARTILE,
      google.ima.dai.api.StreamEvent.Type.MIDPOINT,
      google.ima.dai.api.StreamEvent.Type.THIRD_QUARTILE,
      google.ima.dai.api.StreamEvent.Type.COMPLETE
    ];
    this.streamManager_.addEventListener(quartileEvents, (event) => {
          console.log(`IMA SDK Event: ${event.type}`);
        }, false);
  }

  /**
   * initializes the IMA StreamManager and issues a stream request.
   * @param {!Object} request - The request data object from the CAF sender
   * @return {!Promise<!Object>} - The request object with added stream information
   * @private
   */
  initializeStreamManager_(request) {
    return new Promise((resolve, reject) => {
      // Set media info and resolve promise on successful stream request
      this.streamManager_.addEventListener(
          google.ima.dai.api.StreamEvent.Type.LOADED, (event) => {
            this.broadcast(
                'Stream request successful. Loading stream...');
            request.media.contentUrl = event.getStreamData().url;
            request.media.subtitles = event.getStreamData().subtitles;
            resolve(request);
          }, false);

      // Prepare backup stream and resolve promise on stream request error
      this.streamManager_.addEventListener(
          google.ima.dai.api.StreamEvent.Type.ERROR, (event) => {
            this.broadcast(
                'Stream request failed. Loading backup stream...');
            request.media.contentUrl = this.backupStream_;
            resolve(request);
          }, false);

      // Request Stream
      const imaRequestData = request.media.customData;
      this.startTime_ = imaRequestData.startTime;
      const streamRequest = (imaRequestData.assetKey) ?
          new google.ima.dai.api.LiveStreamRequest(imaRequestData) :
          new google.ima.dai.api.VODStreamRequest(imaRequestData);
      this.streamManager_.requestStream(streamRequest);
      document.getElementById('splash').style.display = 'none';

      // For VOD Streams, update start time on media element
      if (this.startTime_ &&
          request.media.streamType ===
              cast.framework.messages.StreamType.BUFFERED) {
        this.mediaElement_.currentTime =
            this.streamManager_.streamTimeForContentTime(this.startTime_);
      }
    });
  }

  /**
   * Intercepts requests to seek and injects necessary information for snapback.
   * Also prevents seeking while ads are playing.
   * @param {!Object} seekRequest - A CAF seek request
   * @return {!Object} - A potentially modified CAF seek request
   * @private
   */
  processSeekRequest_(seekRequest) {
    const seekTo = seekRequest.currentTime;
    const previousCuepoint =
        this.streamManager_.previousCuePointForStreamTime(seekTo);
    if (this.adIsPlaying_) {
      // effectively cancels seek request
      seekRequest.currentTime = this.mediaElement_.currentTime;
    } else if (!previousCuepoint.played) {
      // Adding 0.1 to cuepoint start time because of bug where stream
      // freezes when seeking to certain times in VOD streams.
      seekRequest.currentTime = previousCuepoint.start + 0.1;
      this.seekToTimeAfterAdBreak_ = seekTo;
    }
    return seekRequest;
  }

  /**
   * Sets flags and UI at the start of an ad break.
   * @private
   */
  startAdBreak_() {
    this.adIsPlaying_ = true;
    document.getElementById('ad-ui').style.display = 'block';
    this.broadcast('adBreakStarted');
  }

  /**
   * Sets flags and UI and triggers snapback at the end of an ad break.
   * @private
   */
  endAdBreak_() {
    this.adIsPlaying_ = false;
    document.getElementById('ad-ui').style.display = 'none';
    this.broadcast('adBreakEnded');
    // process any pending snapback request
    if (this.seekToTimeAfterAdBreak_ != -1) {
      this.seek(this.seekToTimeAfterAdBreak_);
      this.seekToTimeAfterAdBreak_ = -1;
    }
  }

  /**
   * Updates ad UI to display progress in ad break.
   * @param {!Object} event - The ad progress event from IMA
   * @private
   */
  updateAdProgress_(event) {
    const adData = event.getStreamData().adProgressData;
    document.getElementById('ad-position').textContext =
        parseInt(adData.adPosition, 10);
    document.getElementById('total-ads').textContext =
        parseInt(adData.totalAds, 10);
    document.getElementById('time-value').textContext = Math.ceil(
        parseFloat(adData.duration) - parseFloat(adData.currentTime));
    document.getElementById('ad-ui').style.display = 'block';
  }

  /**
   * Seeks video playback to specified time if not playing an ad.
   * @param {number} time - The target stream time in seconds, including ads.
   */
  seek(time) {
    if (time > 0 && !this.adIsPlaying_) {
      this.mediaElement_.currentTime = time;
      this.broadcast('Seeking to: ' + time);
    }
  }

  /**
   * Sets a bookmark to a specific time on future playback.
   * @param {number} time - The target stream time in seconds, including ads.
   */
  bookmark(time) {
    this.startTime_ = time;
  }

  /**
   * Gets the current timestamp in the stream, not including ads.
   * @return {number} - The stream time in seconds, without ads.
   */
  getContentTime() {
    const currentTime = this.mediaElement_.currentTime;
    return this.streamManager_.contentTimeForStreamTime(currentTime);
  }

  /**
   * Broadcasts a message to all attached CAF senders
   * @param {string} message - The message to be sent to attached senders
   */
  broadcast(message) {
    console.log(message);
    this.castContext_.sendCustomMessage(NAMESPACE, undefined, message);
  }
}
<commit_msg>Internal change<commit_after>'use strict';

const NAMESPACE = 'urn:x-cast:com.google.ads.ima.cast';

class Player {
  /**
   * Represents the receiver
   * @param {!Object} mediaElement - the cast media player element
   */
  constructor(mediaElement) {
    /**
     * the fallback stream to play if loading fails
     * @type {string}
     * @private
     * @const
     */
    this.backupStream_ = 'http://storage.googleapis.com/testtopbox-public/' +
        'video_content/bbb/master.m3u8';

    /**
     * the cast context object provided by the CAF framework.
     * @type {!Object}
     * @private
     * @const
     */
    this.castContext_ = cast.framework.CastReceiverContext.getInstance();

    /**
     * the player manager object, provided by the CAF framework.
     * @type {!Object}
     * @private
     * @const
     */
    this.playerManager_ = this.castContext_.getPlayerManager();

    /**
     * the video player contained within the cast media player element.
     * @type {!HTMLMediaElement}
     * @private
     * @const
     */
    this.mediaElement_ = mediaElement.getMediaElement();

    /**
     * This is the stream manager object for IMA SDK.
     * @type {?Object}
     * @private
     */
    this.streamManager_ = null;

    /**
     * Stores the timestamp where playback will start, in seconds, for
     * bookmarking.
     * @type {number}
     * @private
     */
    this.startTime_ = 0;

    /**
     * Stores a flag to identify whether an ad is currently playing.
     * @type {boolean}
     * @private
     */
    this.adIsPlaying_ = false;

    /**
     * Stores the timestamp to seek to when ad completes, for snapback.
     * -1 indicates that snapback has not been requested.
     * @type {number}
     * @private
     */
    this.seekToTimeAfterAdBreak_ = -1;
  }

  /** Initializes CAF and IMA SDK */
  initialize() {
    // Map of namespace names to their types.
    const options = new cast.framework.CastReceiverOptions();
    options.customNamespaces = {};
    options.customNamespaces[NAMESPACE] =
        cast.framework.system.MessageType.STRING;
    this.castContext_.start(options);
    this.streamManager_ =
        new google.ima.dai.api.StreamManager(this.mediaElement_);
  }

  /** Attaches event listeners and other callbacks. */
  setupCallbacks() {
    // Receives messages from sender app.
    this.castContext_.addCustomMessageListener(NAMESPACE, (event) => {
      this.processSenderMessage_(event.data);
    });

    this.attachPlayerManagerCallbacks_();
    this.attachStreamManagerListeners_();
  }

  /**
   * Parses messages from sender apps. The message is a comma separated
   * string consisting of a function name followed by a set of parameters.
   * @param {string} message - The raw message from the sender app.
   * @private
   */
  processSenderMessage_(message) {
    console.log('Received message from sender: ' + message);
    const messageArray = message.split(',');
    const method = messageArray[0];
    switch (method) {
      case 'bookmark':
        const time = parseFloat(messageArray[1]);
        const bookmarkTime =
            this.streamManager_.contentTimeForStreamTime(time);
        this.broadcast('bookmark,' + bookmarkTime);
        this.bookmark(time);
        break;
      case 'getContentTime':
        const contentTime = this.getContentTime();
        this.broadcast('contentTime,' + contentTime);
        break;
      default:
        this.broadcast('Message not recognized');
        break;
    }
  }

  /**
   * Attaches message interceptors and event listeners to connet IMA to CAF.
   * @private
   */
  attachPlayerManagerCallbacks_() {
    // This intercepts the CAF load process, to load the IMA stream manager and
    // make a DAI stream request. It then injests the stream URL into the
    // original LOAD message, before passing it to CAF
    this.playerManager_.setMessageInterceptor(
        cast.framework.messages.MessageType.LOAD, (request) => {
          return this.initializeStreamManager_(request);
        });

    // This intercepts CAF seek requests to cancel them in the case that an ad
    // is playing, and to modify them to enable snapback
    this.playerManager_.setMessageInterceptor(
        cast.framework.messages.MessageType.SEEK, (seekRequest) => {
          return this.processSeekRequest_(seekRequest);
        });

    // This passes ID3 events from the stream to the IMA to allow for updating
    // stream events on the fly in live streams
    this.playerManager_.addEventListener(
        cast.framework.events.EventType.ID3, (event) => {
          // pass ID3 events from the stream to IMA to update live stream
          // cuepoints
          this.streamManager_.processMetadata(
              'ID3', event.segmentData, event.timestamp);
        });

    this.playerManager_.addEventListener(
        [
          cast.framework.events.EventType.TIMED_METADATA_ENTER,
          cast.framework.events.EventType.TIMED_METADATA_CHANGED,
          cast.framework.events.EventType.TIMED_METADATA_EXIT,
        ],
        (event) => this.handleTimedMetadataEvent_(event));
  }

  /**
   * Handles timedmetadata updates from the player manager.
   * @param {!cast.framework.events.TimedMetadataEvent} event
   * @private
   */
  handleTimedMetadataEvent_(event) {
    if (!event.timedMetadataInfo) {
      return;
    }
    if (event.timedMetadataInfo.dashTimedMetadata &&
        event.timedMetadataInfo.dashTimedMetadata.eventElement) {
      this.streamManager_.processMetadata(
          event.timedMetadataInfo.dashTimedMetadata.schemeIdUri,
          event.timedMetadataInfo.dashTimedMetadata.eventElement.getAttribute(
              'messageData'),
          event.timedMetadataInfo.startTime);
    }
  }

  /**
   * Attaches IMA event managers
   * @private
   */
  attachStreamManagerListeners_() {
    // This fires at the beginning of each ad break
    this.streamManager_.addEventListener(
        google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED, (event) => {
          this.startAdBreak_();
        });
    // This fires at the end of each ad break
    this.streamManager_.addEventListener(
        google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED, (event) => {
          this.endAdBreak_();
        });
    // This fires periodically while ads are playing
    this.streamManager_.addEventListener(
        google.ima.dai.api.StreamEvent.Type.AD_PROGRESS, (event) => {
          this.updateAdProgress_(event);
        });

    // Log the quartile events to the console for debugging
    const quartileEvents = [
      google.ima.dai.api.StreamEvent.Type.STARTED,
      google.ima.dai.api.StreamEvent.Type.FIRST_QUARTILE,
      google.ima.dai.api.StreamEvent.Type.MIDPOINT,
      google.ima.dai.api.StreamEvent.Type.THIRD_QUARTILE,
      google.ima.dai.api.StreamEvent.Type.COMPLETE
    ];
    this.streamManager_.addEventListener(quartileEvents, (event) => {
          console.log(`IMA SDK Event: ${event.type}`);
        }, false);
  }

  /**
   * initializes the IMA StreamManager and issues a stream request.
   * @param {!Object} request - The request data object from the CAF sender
   * @return {!Promise<!Object>} - The request object with added stream information
   * @private
   */
  initializeStreamManager_(request) {
    return new Promise((resolve, reject) => {
      // Set media info and resolve promise on successful stream request
      this.streamManager_.addEventListener(
          google.ima.dai.api.StreamEvent.Type.LOADED, (event) => {
            this.broadcast(
                'Stream request successful. Loading stream...');
            request.media.contentUrl = event.getStreamData().url;
            request.media.subtitles = event.getStreamData().subtitles;
            if (event.getStreamData().manifestFormat.toLowerCase() == 'dash') {
              request.media.contentType = 'application/dash+xml';
            }
            resolve(request);
          }, false);

      // Prepare backup stream and resolve promise on stream request error
      this.streamManager_.addEventListener(
          google.ima.dai.api.StreamEvent.Type.ERROR, (event) => {
            this.broadcast(
                'Stream request failed. Loading backup stream...');
            request.media.contentUrl = this.backupStream_;
            resolve(request);
          }, false);

      // Request Stream
      const imaRequestData = request.media.customData;
      this.startTime_ = imaRequestData.startTime;
      const streamRequest = (imaRequestData.assetKey) ?
          new google.ima.dai.api.LiveStreamRequest(imaRequestData) :
          new google.ima.dai.api.VODStreamRequest(imaRequestData);
      this.streamManager_.requestStream(streamRequest);
      document.getElementById('splash').style.display = 'none';

      // For VOD Streams, update start time on media element
      if (this.startTime_ &&
          request.media.streamType ===
              cast.framework.messages.StreamType.BUFFERED) {
        this.mediaElement_.currentTime =
            this.streamManager_.streamTimeForContentTime(this.startTime_);
      }
    });
  }

  /**
   * Intercepts requests to seek and injects necessary information for snapback.
   * Also prevents seeking while ads are playing.
   * @param {!Object} seekRequest - A CAF seek request
   * @return {!Object} - A potentially modified CAF seek request
   * @private
   */
  processSeekRequest_(seekRequest) {
    const seekTo = seekRequest.currentTime;
    const previousCuepoint =
        this.streamManager_.previousCuePointForStreamTime(seekTo);
    if (this.adIsPlaying_) {
      // effectively cancels seek request
      seekRequest.currentTime = this.mediaElement_.currentTime;
    } else if (!previousCuepoint.played) {
      // Adding 0.1 to cuepoint start time because of bug where stream
      // freezes when seeking to certain times in VOD streams.
      seekRequest.currentTime = previousCuepoint.start + 0.1;
      this.seekToTimeAfterAdBreak_ = seekTo;
    }
    return seekRequest;
  }

  /**
   * Sets flags and UI at the start of an ad break.
   * @private
   */
  startAdBreak_() {
    this.adIsPlaying_ = true;
    document.getElementById('ad-ui').style.display = 'block';
    this.broadcast('adBreakStarted');
  }

  /**
   * Sets flags and UI and triggers snapback at the end of an ad break.
   * @private
   */
  endAdBreak_() {
    this.adIsPlaying_ = false;
    document.getElementById('ad-ui').style.display = 'none';
    this.broadcast('adBreakEnded');
    // process any pending snapback request
    if (this.seekToTimeAfterAdBreak_ != -1) {
      this.seek(this.seekToTimeAfterAdBreak_);
      this.seekToTimeAfterAdBreak_ = -1;
    }
  }

  /**
   * Updates ad UI to display progress in ad break.
   * @param {!Object} event - The ad progress event from IMA
   * @private
   */
  updateAdProgress_(event) {
    const adData = event.getStreamData().adProgressData;
    document.getElementById('ad-position').textContext =
        parseInt(adData.adPosition, 10);
    document.getElementById('total-ads').textContext =
        parseInt(adData.totalAds, 10);
    document.getElementById('time-value').textContext = Math.ceil(
        parseFloat(adData.duration) - parseFloat(adData.currentTime));
    document.getElementById('ad-ui').style.display = 'block';
  }

  /**
   * Seeks video playback to specified time if not playing an ad.
   * @param {number} time - The target stream time in seconds, including ads.
   */
  seek(time) {
    if (time > 0 && !this.adIsPlaying_) {
      this.mediaElement_.currentTime = time;
      this.broadcast('Seeking to: ' + time);
    }
  }

  /**
   * Sets a bookmark to a specific time on future playback.
   * @param {number} time - The target stream time in seconds, including ads.
   */
  bookmark(time) {
    this.startTime_ = time;
  }

  /**
   * Gets the current timestamp in the stream, not including ads.
   * @return {number} - The stream time in seconds, without ads.
   */
  getContentTime() {
    const currentTime = this.mediaElement_.currentTime;
    return this.streamManager_.contentTimeForStreamTime(currentTime);
  }

  /**
   * Broadcasts a message to all attached CAF senders
   * @param {string} message - The message to be sent to attached senders
   */
  broadcast(message) {
    console.log(message);
    this.castContext_.sendCustomMessage(NAMESPACE, undefined, message);
  }
}
<|endoftext|>


<commit_before>//Some small scripts written by The Oddball http://steamcommunity.com/id/TheOddball/ to automatically get keys from Humble Bundle or Bundle Stars.
//What these scripts do is simply, they get all the Steam keys from the Humble Bundle or Bundle Stars page, and puts them each in a newline, ready for use on either; This userscript: https://github.com/LiteOnE/Steam-Scripts/blob/master/Batch-Keys-Activator.user.js , or This program: https://github.com/Ezzpify/SteamBulkActivator

//Bundle Stars
$('.key.ng-scope').each(function() {
    $(this).find('.ng-scope').click();
});

function getKeys() {
    setTimeout(function() {
        var keys = "";
        $('.key-reveal-copy.ng-scope').each(function() {
            keys = keys + $(this).find('.input-group').find('.ng-valid').val() + '\n'
        });
        return keys;
    }, 1000);
}
var keys = getKeys();
var $temp = $("<textarea>");
$("body").append($temp);
$temp.val(keys).select();
document.execCommand("copy");
$temp.remove();

//Bundle Stars Minified
function getKeys(){setTimeout(function(){var e="";return $(".key-reveal-copy.ng-scope").each(function(){e=e+$(this).find(".input-group").find(".ng-valid").val()+"\n"}),e},1e3)}$(".key.ng-scope").each(function(){$(this).find(".ng-scope").click()});var keys=getKeys(),$temp=$("<textarea>");$("body").append($temp),$temp.val(keys).select(),document.execCommand("copy"),$temp.remove();

//Humble Bundle
$('.sr-unredeemed-button').each(function() {
    $(this).click();
});

function getKeys() {
    var keys = "";
    $('.keyfield-text').each(function() {
        keys = keys + $(this).text() + '\n'
    });
    return keys;
}
var keys = getKeys();
var $temp = $("<textarea>");
$("body").append($temp);
$temp.val(keys).select();
document.execCommand("copy");
$temp.remove();

//Humble Bundle Minified
function getKeys(){var e="";return $(".keyfield-text").each(function(){e=e+$(this).text()+"\n"}),e}$(".sr-unredeemed-button").each(function(){$(this).click()});var keys=getKeys(),$temp=$("<textarea>");$("body").append($temp),$temp.val(keys).select(),document.execCommand("copy"),$temp.remove();
<commit_msg>add pastebin for wulf's keybot<commit_after>//Some small scripts written by The Oddball http://steamcommunity.com/id/TheOddball/ to automatically get keys from Humble Bundle or Bundle Stars.
//What these scripts do is simply, they get all the Steam keys from the Humble Bundle or Bundle Stars page, and puts them each in a newline, ready for use on either; This userscript: https://github.com/LiteOnE/Steam-Scripts/blob/master/Batch-Keys-Activator.user.js , or This program: https://github.com/Ezzpify/SteamBulkActivator

//Bundle Stars
$('.key.ng-scope').each(function() {
    $(this).find('.ng-scope').click();
});

function getKeys() {
    setTimeout(function() {
        var keys = "";
        $('.key-reveal-copy.ng-scope').each(function() {
            keys = keys + $(this).find('.input-group').find('.ng-valid').val() + '\n'
        });
        return keys;
    }, 1000);
}
var keys = getKeys();
var $temp = $("<textarea>");
$("body").append($temp);
$temp.val(keys).select();
document.execCommand("copy");
$temp.remove();

//Bundle Stars Minified
function getKeys(){setTimeout(function(){var e="";return $(".key-reveal-copy.ng-scope").each(function(){e=e+$(this).find(".input-group").find(".ng-valid").val()+"\n"}),e},1e3)}$(".key.ng-scope").each(function(){$(this).find(".ng-scope").click()});var keys=getKeys(),$temp=$("<textarea>");$("body").append($temp),$temp.val(keys).select(),document.execCommand("copy"),$temp.remove();

//Humble Bundle
$('.sr-unredeemed-button').each(function() {
    $(this).click();
});

function getKeys() {
    var keys = "";
    $('.keyfield-text').each(function() {
        keys = keys + $(this).text() + '\n'
    });
    return keys;
}
var keys = getKeys();
var $temp = $("<textarea>");
$("body").append($temp);
$temp.val(keys).select();
document.execCommand("copy");
$temp.remove();

//Humble Bundle Minified
function getKeys(){var e="";return $(".keyfield-text").each(function(){e=e+$(this).text()+"\n"}),e}$(".sr-unredeemed-button").each(function(){$(this).click()});var keys=getKeys(),$temp=$("<textarea>");$("body").append($temp),$temp.val(keys).select(),document.execCommand("copy"),$temp.remove();

//Pastebin (for Wulf's Keybot)
$('#paste_code').text().match(/[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+/g).toString();
<|endoftext|>


<commit_before>/* global RTCPeerConnection */
// jshint unused:false

var cordova = window.cordova;

// Expose WebRTC Globals
if (cordova && cordova.plugins && cordova.plugins.iosrtc) {
  cordova.plugins.iosrtc.registerGlobals();
  //cordova.plugins.iosrtc.debug.enable('*', true);
  cordova.plugins.iosrtc.turnOnSpeaker(true);
  cordova.plugins.iosrtc.requestPermission(true, true, function (result) {
    console.log('requestPermission.result', result);
  });
}

//
// Container
//

document.body.innerHTML = "";
var appContainer = document.body;

//
// getUserMedia
//

var localStream;
var localVideoEl;
function TestGetUserMedia() {

  // Note: Support for Multiple TestRTCPeerConnection calls
  if (localStream) {

    // Close local Stream if already connected
    localStream.stop();

    // Clear local video element
    if (localVideoEl.srcObject) {
      localVideoEl.srcObject = null;
      appContainer.removeChild(localVideoEl);
    }
  }

  localVideoEl = document.createElement('video');
  localVideoEl.setAttribute('autoplay', 'autoplay');
  localVideoEl.setAttribute('playsinline', 'playsinline');

  // Note: Test CSS positioning
  localVideoEl.style.backgroundColor = 'purple'; // Cause zIndex - 1 failure
  localVideoEl.style.position = 'absolute';
  localVideoEl.style.top = 0;
  localVideoEl.style.left = 0;
  localVideoEl.style.width = "100px";
  localVideoEl.style.height = "100px";
  localVideoEl.style.transform = "scaleX(-1)";
  appContainer.appendChild(localVideoEl);

  navigator.mediaDevices.enumerateDevices().then(function (devices) {
      console.log('getMediaDevices.ok', devices);
      devices.forEach(function (device, idx) {
        console.log('getMediaDevices.devices', idx, device.label, device.kind, device.deviceId);
      });
  }, function (err) {
      console.log('getMediaDevices.err', err);
  });

  return navigator.mediaDevices.getUserMedia({
    video: true,
    audio: true
    /*
    video: {
      // Test Back Camera
      //deviceId: 'com.apple.avfoundation.avcapturedevice.built-in_video:0'
      //sourceId: 'com.apple.avfoundation.avcapturedevice.built-in_video:0'
      deviceId: {
        exact: 'com.apple.avfoundation.avcapturedevice.built-in_video:0'
      }
    },
    audio: {
      exact: 'Built-In Microphone'
    }*/
  }).then(function (stream) {

    console.log('getUserMedia.stream', stream);
    console.log('getUserMedia.stream.getTracks', stream.getTracks());

    // Note: Expose for debug
    localStream = stream;

    // Attach local stream to video element
    localVideoEl.srcObject = localStream;

    // Test HTML over Video element
    TestPluginMediaStreamRenderer(localVideoEl);

    return localStream;

  }).catch(function (err) {
    console.log('getUserMediaError', err, err.stack);
  });
}

var useAnimateVideo = false;
function TestPluginMediaStreamRenderer(localVideoEl) {

  // Animate video position
  var currentPosition = {
    x: 0,
    y: 0
  };

  var animateTimer;
  function animateVideo() {

    currentPosition.x = currentPosition.x < (window.innerWidth - parseInt(localVideoEl.style.width, 10)) ? currentPosition.x + 1 : 0;
    currentPosition.y = currentPosition.y < (window.innerHeight - parseInt(localVideoEl.style.height, 10)) ? currentPosition.y + 1 : 0;

    localVideoEl.style.top = currentPosition.y + 'px';
    localVideoEl.style.left = currentPosition.x + 'px';

    if (cordova && cordova.plugins && cordova.plugins.iosrtc) {
      //cordova.plugins.iosrtc.refreshVideos();
    }

    return (animateTimer = requestAnimationFrame(animateVideo));
  }

  if (useAnimateVideo) {
    animateTimer = animateVideo();
  }

  //
  // Test Video behind Element
  //

  // Note: Test HTML over video requiring Z-Index -1 and transparent <html> and <body>
  document.body.style.background = "transparent";
  document.documentElement.style.background = "transparent";
  localVideoEl.style.backgroundColor = '';
  localVideoEl.style.zIndex = -1;

  var overEl = document.createElement('button');
  overEl.style.backgroundColor = 'red';
  overEl.style.position = 'absolute';
  overEl.style.left = 0;
  overEl.style.top = 0;
  overEl.style.width = "100px";
  overEl.style.height = "100px";

  overEl.addEventListener('click', function () {
    overEl.style.backgroundColor = overEl.style.backgroundColor === 'red' ? 'green' : 'red';

    if (overEl.style.backgroundColor === 'red') {
      animateTimer = animateVideo();
    } else {
      cancelAnimationFrame(animateTimer);
    }
  });

  appContainer.appendChild(overEl);

  overEl.style.left = ((window.innerWidth / 2)  - parseInt(overEl.style.width, 10)) + 'px';
  overEl.style.top  = ((window.innerHeight / 2) - parseInt(overEl.style.height, 10)) + 'px';

}

//
// Test RTCPeerConnection
//

var peerConnectionConfig = {
    iceServers: [
      {
        urls: "stun:stun.stunprotocol.org"
      }
    ]
};
var pc1 = new RTCPeerConnection(peerConnectionConfig),
    pc2 = new RTCPeerConnection(peerConnectionConfig);

var sendChannel, receiveChannel;
function TestPeerDataChannel() {
  sendChannel = pc1.createDataChannel("sendChannel");

  sendChannel.addEventListener('message',  function (event) {
    console.log('sendChannel.message', event, event.data);
  });

  sendChannel.addEventListener('open', function (event) {
      console.log('sendChannel.open', event);
      sendChannel.send("data message Date: " + new Date());
  });

  sendChannel.addEventListener('close', function (event) {
      console.log('sendChannel.close', event);
  });

  pc2.addEventListener('datachannel', function (event) {
    receiveChannel = event.channel;
    receiveChannel.addEventListener('message',  function (event) {
      console.log('receiveChannel.message', event, event.data);
    });
    receiveChannel.addEventListener('open',  function (event) {
      console.log('receiveChannel.open', event);
    });
    receiveChannel.addEventListener('close',  function (event) {
      console.log('receiveChannel.close', event);
    });
  });
}

var peerVideoEl;
var peerStream;
function TestRTCPeerConnection(localStream) {

  // Note: Support for Multiple TestRTCPeerConnection calls
  if (peerStream) {

    // Close peer Stream if already connected
    peerStream.stop();

    // Clear peer video element
    if (peerVideoEl.srcObject) {
      peerVideoEl.srcObject = null;
      appContainer.removeChild(peerVideoEl);
    }

    // Disconnect peer
    if (pc1.iceConnectionState === 'completed') {
      pc1.close();

      // Current you cannot reuse previous RTCPeerConnection
      pc1 = new RTCPeerConnection();
      pc2 = new RTCPeerConnection();
    }
  }

  // Note: Deprecated but supported
  //pc1.addStream(localStream);

  // Note: Deprecated Test removeStream
  // pc1.removeStream(pc1.getLocalStreams()[0])

  // Note: Chrome Version 77.0.3865.90 (Official Build) still
  // require to use addStream without webrtc-adapter.
  localStream.getTracks().forEach(function (track) {
    console.log('addTrack', track);
    pc1.addTrack(track);
  });

  function onAddIceCandidate(pc, can) {
    console.log('addIceCandidate', pc, can);
    return can && pc.addIceCandidate(can).catch(function (err) {
      console.log('addIceCandidateError', err);
    });
  }

  pc1.addEventListener('icecandidate', function (e) {
    onAddIceCandidate(pc2, e.candidate);
  });

  pc2.addEventListener('icecandidate', function (e) {
    onAddIceCandidate(pc1, e.candidate);
  });

  pc2.addEventListener('track', function (e) {
    console.log('pc2.track', e);
  });

  pc2.addEventListener('removetrack', function (e) {
    console.log('pc2.removeTrack', e);
  });

  pc2.addEventListener('addstream', function (e) {
    console.log('pc2.addStream', e);
    peerVideoEl = document.createElement('video');
    peerVideoEl.setAttribute('autoplay', 'autoplay');
    peerVideoEl.setAttribute('playsinline', 'playsinline');

    // Note: Test Object-fix
    peerVideoEl.style.objectFit = "cover";

    // Note: Test CSS positioning
    peerVideoEl.style.backgroundColor = 'blue';
    peerVideoEl.style.position = 'fixed';
    peerVideoEl.style.width = "100px";
    peerVideoEl.style.height = "100px";
    peerVideoEl.style.top = 0;
    peerVideoEl.style.left = (window.innerWidth - parseInt(peerVideoEl.style.width, 10)) + 'px';
    appContainer.appendChild(peerVideoEl);

    // Note: Expose for debug
    peerStream = e.stream;

    // Attach peer stream to video element
    peerVideoEl.srcObject = peerStream;
  });

  pc1.addEventListener('iceconnectionstatechange', function (e) {
    console.log('pc1.iceConnectionState', e, pc1.iceConnectionState);

    if (pc1.iceConnectionState === 'completed') {
      console.log('pc1.getSenders', pc1.getSenders());
      console.log('pc2.getReceivers', pc2.getReceivers());
    }
  });

  pc1.addEventListener('icegatheringstatechange', function (e) {
    console.log('pc1.iceGatheringStateChange', e);
  });

  // https://stackoverflow.com/questions/48963787/failed-to-set-local-answer-sdp-called-in-wrong-state-kstable
  // https://bugs.chromium.org/p/chromium/issues/detail?id=740501
  var isNegotiating = false;
  pc1.addEventListener('signalingstatechange', function (e) {
    console.log('pc1.signalingstatechange',  e);
    isNegotiating = (pc1.signalingState !== "stable");
  });

  pc1.addEventListener('negotiationneeded', function (e) {

    if (isNegotiating) {
      // Should not trigger on iosrtc cause of PluginRTCPeerConnection.swift fix
      console.log("pc1.negotiatioNeeded", "SKIP nested negotiations");
      return;
    }
    isNegotiating = true;

    console.log('pc1.negotiatioNeeded', e);

    return pc1.createOffer().then(function (d) {
      var desc = {
        type: d.type,
        sdp: d.sdp
      };
      console.log('pc1.setLocalDescription', desc);
      return pc1.setLocalDescription(desc);
    }).then(function () {
      var desc = {
        type: pc1.localDescription.type,
        sdp: pc1.localDescription.sdp
      };
      console.log('pc2.setLocalDescription', desc);
      return pc2.setRemoteDescription(desc);
    }).then(function () {
      console.log('pc2.createAnswer');
      return pc2.createAnswer();
    }).then(function (d) {
      var desc = {
        type: d.type,
        sdp: d.sdp
      };
      console.log('pc2.setLocalDescription', desc);
      return pc2.setLocalDescription(d);
    }).then(function () {
      var desc = {
        type: pc2.localDescription.type,
        sdp: pc2.localDescription.sdp
      };
      console.log('pc1.setRemoteDescription', desc);
      return pc1.setRemoteDescription(desc);
    }).then(function () {
      TestMediaRenderCatpure(peerVideoEl);
      TestMediaRenderCatpure(localVideoEl);
      TestPeerDataChannel();
    }).catch(function (err) {
      console.log('pc1.createOfferError', err);
    });
  });
}

var canvasEl;
function TestMediaRenderCatpure(videoEl) {

  if (!canvasEl) {
    canvasEl = document.createElement('canvas');
  }

  var ctx = canvasEl.getContext("2d");
  canvasEl.style.position = 'absolute';
  canvasEl.style.left = 0;
  canvasEl.style.bottom = 0;
  appContainer.appendChild(canvasEl);
  var image = new Image();
  image.addEventListener('load', function() {
    canvasEl.width = image.width;
    canvasEl.height = image.height;
    ctx.drawImage(image, 0, 0);
  });
  videoEl.render.save(function (data) {
    image.src = "data:image/jpg;base64," + data;
  });
}

var testMediaRenderCatpureAnimateFrame;
function TestMediaRenderCatpureAnimate() {
  TestMediaRenderCatpure(peerVideoEl);
  testMediaRenderCatpureAnimateFrame = requestAnimationFrame(TestMediaRenderCatpureAnimate);
}

// Disabled to avoid confusion with remoteStream
var cloneStream;
var cloneVideoEl;
function TestPluginMediaStreamClone(mediaStream) {
  cloneVideoEl = document.createElement('video');
  cloneVideoEl.setAttribute('autoplay', 'autoplay');
  cloneVideoEl.setAttribute('playsinline', 'playsinline');
  cloneVideoEl.style.backgroundColor = 'purple';
  cloneVideoEl.style.position = 'absolute';
  cloneVideoEl.style.bottom = 0;
  cloneVideoEl.style.left = 0;
  cloneVideoEl.style.width = "100px";
  cloneVideoEl.style.height = "100px";
  cloneVideoEl.style.transform = "scaleX(-1)";

  cloneStream = mediaStream.clone();
  cloneVideoEl.srcObject = cloneStream;

  appContainer.appendChild(cloneVideoEl);
}

var useWebRTCAdapter = false;

// Expose webrtc-adapter
if (useWebRTCAdapter && typeof window.adapter === 'undefined') {

    // load adapter.js
    var version = 'latest';
    var script = document.createElement("script");
    script.type = "text/javascript";
    //script.src = "adapter-latest.js";
    script.src = "https://webrtc.github.io/adapter/adapter-" + version + ".js";
    script.async = false;
    document.getElementsByTagName("head")[0].appendChild(script);
    script.addEventListener('load', function () {
      console.log('useWebRTCAdapter.loaded', script.src);
      TestGetUserMedia().then(function (localStream) {
        TestRTCPeerConnection(localStream);
      });
    });
} else {
  TestGetUserMedia().then(function (localStream) {
    TestRTCPeerConnection(localStream);
  });
}

<commit_msg>Update renderer-and-libwebrtc-tests.js<commit_after>/* global RTCPeerConnection */
// jshint unused:false

var cordova = window.cordova;

// Expose WebRTC Globals
if (cordova && cordova.plugins && cordova.plugins.iosrtc) {
  cordova.plugins.iosrtc.registerGlobals();
  //cordova.plugins.iosrtc.debug.enable('*', true);
  cordova.plugins.iosrtc.turnOnSpeaker(true);
  cordova.plugins.iosrtc.requestPermission(true, true, function (result) {
    console.log('requestPermission.result', result);
  });
}

//
// Container
//

document.body.innerHTML = "";
var appContainer = document.body;

//
// getUserMedia
//

var localStream;
var localVideoEl;
function TestGetUserMedia() {

  // Note: Support for Multiple TestRTCPeerConnection calls
  if (localStream) {

    // Close local Stream if already connected
    localStream.stop();

    // Clear local video element
    if (localVideoEl.srcObject) {
      localVideoEl.srcObject = null;
      appContainer.removeChild(localVideoEl);
    }
  }

  localVideoEl = document.createElement('video');
  localVideoEl.setAttribute('autoplay', 'autoplay');
  localVideoEl.setAttribute('playsinline', 'playsinline');

  // Note: Test CSS positioning
  localVideoEl.style.backgroundColor = 'purple'; // Cause zIndex - 1 failure
  localVideoEl.style.position = 'absolute';
  localVideoEl.style.top = 0;
  localVideoEl.style.left = 0;
  localVideoEl.style.width = "100px";
  localVideoEl.style.height = "100px";
  localVideoEl.style.transform = "scaleX(-1)";
  appContainer.appendChild(localVideoEl);

  navigator.mediaDevices.enumerateDevices().then(function (devices) {
      console.log('getMediaDevices.ok', devices);
      devices.forEach(function (device, idx) {
        console.log('getMediaDevices.devices', idx, device.label, device.kind, device.deviceId);
      });
  }, function (err) {
      console.log('getMediaDevices.err', err);
  });

  return navigator.mediaDevices.getUserMedia({
    video: true,
    audio: true
    /*
    video: {
      // Test Back Camera
      //deviceId: 'com.apple.avfoundation.avcapturedevice.built-in_video:0'
      //sourceId: 'com.apple.avfoundation.avcapturedevice.built-in_video:0'
      deviceId: {
        exact: 'com.apple.avfoundation.avcapturedevice.built-in_video:0'
      }
    },
    audio: {
      exact: 'Built-In Microphone'
    }*/
  }).then(function (stream) {

    console.log('getUserMedia.stream', stream);
    console.log('getUserMedia.stream.getTracks', stream.getTracks());

    // Note: Expose for debug
    localStream = stream;

    // Attach local stream to video element
    localVideoEl.srcObject = localStream;

    // Test HTML over Video element
    TestPluginMediaStreamRenderer(localVideoEl);

    return localStream;

  }).catch(function (err) {
    console.log('getUserMediaError', err, err.stack);
  });
}

var useAnimateVideo = false;
function TestPluginMediaStreamRenderer(localVideoEl) {

  // Animate video position
  var currentPosition = {
    x: 0,
    y: 0
  };

  var animateTimer;
  function animateVideo() {

    currentPosition.x = currentPosition.x < (window.innerWidth - parseInt(localVideoEl.style.width, 10)) ? currentPosition.x + 1 : 0;
    currentPosition.y = currentPosition.y < (window.innerHeight - parseInt(localVideoEl.style.height, 10)) ? currentPosition.y + 1 : 0;

    localVideoEl.style.top = currentPosition.y + 'px';
    localVideoEl.style.left = currentPosition.x + 'px';

    if (cordova && cordova.plugins && cordova.plugins.iosrtc) {
      //cordova.plugins.iosrtc.refreshVideos();
    }

    return (animateTimer = requestAnimationFrame(animateVideo));
  }

  if (useAnimateVideo) {
    animateTimer = animateVideo();
  }

  //
  // Test Video behind Element
  //

  // Note: Test HTML over video requiring Z-Index -1 and transparent <html> and <body>
  document.body.style.background = "transparent";
  document.documentElement.style.background = "transparent";
  localVideoEl.style.backgroundColor = '';
  localVideoEl.style.zIndex = -1;

  var overEl = document.createElement('button');
  overEl.style.backgroundColor = 'red';
  overEl.style.position = 'absolute';
  overEl.style.left = 0;
  overEl.style.top = 0;
  overEl.style.width = "100px";
  overEl.style.height = "100px";

  overEl.addEventListener('click', function () {
    overEl.style.backgroundColor = overEl.style.backgroundColor === 'red' ? 'green' : 'red';

    if (overEl.style.backgroundColor === 'red') {
      animateTimer = animateVideo();
    } else {
      cancelAnimationFrame(animateTimer);
    }
  });

  appContainer.appendChild(overEl);

  overEl.style.left = ((window.innerWidth / 2)  - parseInt(overEl.style.width, 10)) + 'px';
  overEl.style.top  = ((window.innerHeight / 2) - parseInt(overEl.style.height, 10)) + 'px';

}

//
// Test RTCPeerConnection
//

var peerConnectionConfig = {
    offerToReceiveVideo: true,
    //iceTransportPolicy: 'relay',
    sdpSemantics: 'unified-plan',
    offerToReceiveAudio: true,
    //sdpSemantics: 'plan-b',
    //bundlePolicy: 'max-compat',
    //rtcpMuxPolicy: 'negotiate',
    iceServers: [
        {
            url: "stun:stun.stunprotocol.org"
        }
    ]
};
var pc1 = new RTCPeerConnection(peerConnectionConfig),
    pc2 = new RTCPeerConnection(peerConnectionConfig);

var sendChannel, receiveChannel;
function TestPeerDataChannel() {
  sendChannel = pc1.createDataChannel("sendChannel");

  sendChannel.addEventListener('message',  function (event) {
    console.log('sendChannel.message', event, event.data);
  });

  sendChannel.addEventListener('open', function (event) {
      console.log('sendChannel.open', event);
      sendChannel.send("data message Date: " + new Date());
  });

  sendChannel.addEventListener('close', function (event) {
      console.log('sendChannel.close', event);
  });

  pc2.addEventListener('datachannel', function (event) {
    receiveChannel = event.channel;
    receiveChannel.addEventListener('message',  function (event) {
      console.log('receiveChannel.message', event, event.data);
    });
    receiveChannel.addEventListener('open',  function (event) {
      console.log('receiveChannel.open', event);
    });
    receiveChannel.addEventListener('close',  function (event) {
      console.log('receiveChannel.close', event);
    });
  });
}

var peerVideoEl;
var peerStream;
function TestRTCPeerConnection(localStream) {

  // Note: Support for Multiple TestRTCPeerConnection calls
  if (peerStream) {

    // Close peer Stream if already connected
    peerStream.stop();

    // Clear peer video element
    if (peerVideoEl.srcObject) {
      peerVideoEl.srcObject = null;
      appContainer.removeChild(peerVideoEl);
    }

    // Disconnect peer
    if (pc1.iceConnectionState === 'completed') {
      pc1.close();

      // Current you cannot reuse previous RTCPeerConnection
      pc1 = new RTCPeerConnection();
      pc2 = new RTCPeerConnection();
    }
  }

  // Note: Deprecated but supported
  //pc1.addStream(localStream);

  // Note: Deprecated Test removeStream
  // pc1.removeStream(pc1.getLocalStreams()[0])

  // Note: Chrome Version 77.0.3865.90 (Official Build) still
  // require to use addStream without webrtc-adapter.
  localStream.getTracks().forEach(function (track) {
    console.log('addTrack', track);
    pc1.addTrack(track);
  });

  function onAddIceCandidate(pc, can) {
    console.log('addIceCandidate', pc, can);
    return can && pc.addIceCandidate(can).catch(function (err) {
      console.log('addIceCandidateError', err);
    });
  }

  pc1.addEventListener('icecandidate', function (e) {
    onAddIceCandidate(pc2, e.candidate);
  });

  pc2.addEventListener('icecandidate', function (e) {
    onAddIceCandidate(pc1, e.candidate);
  });

  pc2.addEventListener('track', function (e) {
    console.log('pc2.track', e);
  });

  pc2.addEventListener('removetrack', function (e) {
    console.log('pc2.removeTrack', e);
  });

  pc2.addEventListener('addstream', function (e) {
    console.log('pc2.addStream', e);
    peerVideoEl = document.createElement('video');
    peerVideoEl.setAttribute('autoplay', 'autoplay');
    peerVideoEl.setAttribute('playsinline', 'playsinline');

    // Note: Test Object-fix
    peerVideoEl.style.objectFit = "cover";

    // Note: Test CSS positioning
    peerVideoEl.style.backgroundColor = 'blue';
    peerVideoEl.style.position = 'fixed';
    peerVideoEl.style.width = "100px";
    peerVideoEl.style.height = "100px";
    peerVideoEl.style.top = 0;
    peerVideoEl.style.left = (window.innerWidth - parseInt(peerVideoEl.style.width, 10)) + 'px';
    appContainer.appendChild(peerVideoEl);

    // Note: Expose for debug
    peerStream = e.stream;

    // Attach peer stream to video element
    peerVideoEl.srcObject = peerStream;
  });

  pc1.addEventListener('iceconnectionstatechange', function (e) {
    console.log('pc1.iceConnectionState', e, pc1.iceConnectionState);

    if (pc1.iceConnectionState === 'completed') {
      console.log('pc1.getSenders', pc1.getSenders());
      console.log('pc2.getReceivers', pc2.getReceivers());
    }
  });

  pc1.addEventListener('icegatheringstatechange', function (e) {
    console.log('pc1.iceGatheringStateChange', e);
  });

  // https://stackoverflow.com/questions/48963787/failed-to-set-local-answer-sdp-called-in-wrong-state-kstable
  // https://bugs.chromium.org/p/chromium/issues/detail?id=740501
  var isNegotiating = false;
  pc1.addEventListener('signalingstatechange', function (e) {
    console.log('pc1.signalingstatechange',  e);
    isNegotiating = (pc1.signalingState !== "stable");
  });

  pc1.addEventListener('negotiationneeded', function (e) {

    if (isNegotiating) {
      // Should not trigger on iosrtc cause of PluginRTCPeerConnection.swift fix
      console.log("pc1.negotiatioNeeded", "SKIP nested negotiations");
      return;
    }
    isNegotiating = true;

    console.log('pc1.negotiatioNeeded', e);

    return pc1.createOffer().then(function (d) {
      var desc = {
        type: d.type,
        sdp: d.sdp
      };
      console.log('pc1.setLocalDescription', desc);
      return pc1.setLocalDescription(desc);
    }).then(function () {
      var desc = {
        type: pc1.localDescription.type,
        sdp: pc1.localDescription.sdp
      };
      console.log('pc2.setLocalDescription', desc);
      return pc2.setRemoteDescription(desc);
    }).then(function () {
      console.log('pc2.createAnswer');
      return pc2.createAnswer();
    }).then(function (d) {
      var desc = {
        type: d.type,
        sdp: d.sdp
      };
      console.log('pc2.setLocalDescription', desc);
      return pc2.setLocalDescription(d);
    }).then(function () {
      var desc = {
        type: pc2.localDescription.type,
        sdp: pc2.localDescription.sdp
      };
      console.log('pc1.setRemoteDescription', desc);
      return pc1.setRemoteDescription(desc);
    }).then(function () {
      TestMediaRenderCatpure(peerVideoEl);
      TestMediaRenderCatpure(localVideoEl);
      TestPeerDataChannel();
    }).catch(function (err) {
      console.log('pc1.createOfferError', err);
    });
  });
}

var canvasEl;
function TestMediaRenderCatpure(videoEl) {

  if (!canvasEl) {
    canvasEl = document.createElement('canvas');
  }

  var ctx = canvasEl.getContext("2d");
  canvasEl.style.position = 'absolute';
  canvasEl.style.left = 0;
  canvasEl.style.bottom = 0;
  appContainer.appendChild(canvasEl);
  var image = new Image();
  image.addEventListener('load', function() {
    canvasEl.width = image.width;
    canvasEl.height = image.height;
    ctx.drawImage(image, 0, 0);
  });
  videoEl.render.save(function (data) {
    image.src = "data:image/jpg;base64," + data;
  });
}

var testMediaRenderCatpureAnimateFrame;
function TestMediaRenderCatpureAnimate() {
  TestMediaRenderCatpure(peerVideoEl);
  testMediaRenderCatpureAnimateFrame = requestAnimationFrame(TestMediaRenderCatpureAnimate);
}

// Disabled to avoid confusion with remoteStream
var cloneStream;
var cloneVideoEl;
function TestPluginMediaStreamClone(mediaStream) {
  cloneVideoEl = document.createElement('video');
  cloneVideoEl.setAttribute('autoplay', 'autoplay');
  cloneVideoEl.setAttribute('playsinline', 'playsinline');
  cloneVideoEl.style.backgroundColor = 'purple';
  cloneVideoEl.style.position = 'absolute';
  cloneVideoEl.style.bottom = 0;
  cloneVideoEl.style.left = 0;
  cloneVideoEl.style.width = "100px";
  cloneVideoEl.style.height = "100px";
  cloneVideoEl.style.transform = "scaleX(-1)";

  cloneStream = mediaStream.clone();
  cloneVideoEl.srcObject = cloneStream;

  appContainer.appendChild(cloneVideoEl);
}

var useWebRTCAdapter = false;

// Expose webrtc-adapter
if (useWebRTCAdapter && typeof window.adapter === 'undefined') {

    // load adapter.js
    var version = 'latest';
    var script = document.createElement("script");
    script.type = "text/javascript";
    //script.src = "adapter-latest.js";
    script.src = "https://webrtc.github.io/adapter/adapter-" + version + ".js";
    script.async = false;
    document.getElementsByTagName("head")[0].appendChild(script);
    script.addEventListener('load', function () {
      console.log('useWebRTCAdapter.loaded', script.src);
      TestGetUserMedia().then(function (localStream) {
        TestRTCPeerConnection(localStream);
      });
    });
} else {
  TestGetUserMedia().then(function (localStream) {
    TestRTCPeerConnection(localStream);
  });
}

<|endoftext|>


<commit_before>gPlayer = {
  x: 0,
  y: 0,
  xVel: 0,
  yVel: 0,
  rad: 0,
  size: 20,
  speed: PLAYER_SPEED,
  allowFire: true,
  projectiles: [],
  fire: function() {
    if (this.allowFire) {
      this.projectiles.push(new Bolt(this.x, this.y, this.rad));
      this.allowFire = false;
      gAudio.eChan1.startBolt();
      setTimeout(function() { this.allowFire = true }.bind(this), Bolt.delay);
    }
  },
  collide: function(other) {
    var rayToCenter = Math.sqrt(Math.pow(other.x - this.x, 2) + Math.pow(other.y - this.y, 2));
    var collide = rayToCenter < this.size;

    if (!collide) {
      var lastX = this.x - this.xVel;
      var lastY = this.y - this.yVel;
      var lastRay = Math.sqrt(Math.pow(this.x - lastX, 2) + Math.pow(this.y - lastY, 2));
      collide = Math.sqrt(Math.pow(rayToCenter, 2) + Math.pow(lastRay)) < other.size;
    }

    return collide;
  },
  update: function() {
    var xAcc = 0;
    var yAcc = 0;
    this.xVel *= FRICTION;
    this.yVel *= FRICTION;
    if (gInput.isActive('thrust')) {
      this.speed = THRUSTER_SPEED;
      xAcc = Math.cos(this.rad);
      yAcc = Math.sin(this.rad);
    }
    else {
      this.speed = PLAYER_SPEED;
      if (gInput.isActive('left')) xAcc--;
      if (gInput.isActive('right')) xAcc++;
      if (gInput.isActive('up')) yAcc--;
      if (gInput.isActive('down')) yAcc++;
    }
    // this.xVel = Math.abs(this.xVel) > 2e-20 ? this.xVel + xAcc : 0;
    // this.yVel = Math.abs(this.yVel) > 2e-20 ? this.yVel + yAcc : 0;
    this.xVel += xAcc;
    this.yVel += yAcc;

    var collision;
    for (var i in gScene.targets) {
      collision = this.collide(gScene.targets[i]);
      if (collision) {
        this.xVel *= -1;
        this.yVel *= -1;
        break;
      }
    }
    this.x = Math.min(gScene.bounds.r - 20, Math.max(gScene.bounds.l + 20, this.x + this.xVel * this.speed));
    this.y = Math.min(gScene.bounds.b - 20, Math.max(gScene.bounds.t + 20, this.y + this.yVel * this.speed));

    this.rad = Math.atan2(gInput.mouseY - (this.y - gCamera.y), gInput.mouseX - (this.x - gCamera.x));

    if (gInput.isActive('fire')) this.fire();
    // Loop through projectiles and only keep the ones still in the level bounds
    var liveProjectiles = [];
    this.projectiles.forEach(function(p) {
      var collision;
      for (var i in gScene.targets) {
        collision = p.collide(gScene.targets[i]);
        if (collision) break;
      }
      if (!collision && gScene.bounds.collide(p)) p.dying = true;
      p.update();
      if (p.life > 0) liveProjectiles.push(p);
    });
    this.projectiles = liveProjectiles;
  },
  render: (function(context) {
    function render() {
      context.beginPath();
      context.moveTo(this.x + (PLAYER_RADIUS * Math.cos(this.rad)) - gCamera.x, this.y + (PLAYER_RADIUS * Math.sin(this.rad)) - gCamera.y);
      context.lineTo(this.x + ((PLAYER_RADIUS / 2) * Math.cos(this.rad + (Math.PI / 4))) - gCamera.x, this.y + ((PLAYER_RADIUS / 2) * Math.sin(this.rad + (Math.PI / 4))) - gCamera.y);
      context.lineTo(this.x + (PLAYER_RADIUS * Math.cos(this.rad + (Math.PI / 2))) - gCamera.x, this.y + (PLAYER_RADIUS * Math.sin(this.rad + (Math.PI / 2))) - gCamera.y);
      context.lineTo(this.x + ((PLAYER_RADIUS * 1.25) * Math.cos(this.rad + (Math.PI * 3 / 4))) - gCamera.x, this.y + ((PLAYER_RADIUS * 1.25) * Math.sin(this.rad + (Math.PI * 3 / 4))) - gCamera.y);
      context.lineTo(this.x + ((PLAYER_RADIUS / 2) * Math.cos(this.rad + Math.PI)) - gCamera.x, this.y + ((PLAYER_RADIUS / 2) * Math.sin(this.rad + Math.PI)) - gCamera.y);
      context.lineTo(this.x + ((PLAYER_RADIUS * 1.25) * Math.cos(this.rad - (Math.PI * 3 / 4))) - gCamera.x, this.y + ((PLAYER_RADIUS * 1.25) * Math.sin(this.rad - (Math.PI * 3 / 4))) - gCamera.y);
      context.lineTo(this.x + (PLAYER_RADIUS * Math.cos(this.rad - (Math.PI / 2))) - gCamera.x, this.y + (PLAYER_RADIUS * Math.sin(this.rad - (Math.PI / 2))) - gCamera.y);
      context.lineTo(this.x + ((PLAYER_RADIUS / 2) * Math.cos(this.rad - (Math.PI / 4))) - gCamera.x, this.y + ((PLAYER_RADIUS / 2) * Math.sin(this.rad - (Math.PI / 4))) - gCamera.y);
      context.closePath();

      context.fillStyle = '#49D';
      context.strokeStyle = '#FB7';
      context.lineWidth = 3;

      context.fill();
      context.stroke();
    }
    return render;
  })(gRenderer.context)
}
<commit_msg>Limit non-thruster player movement to within camera bounds<commit_after>gPlayer = {
  x: 0,
  y: 0,
  xVel: 0,
  yVel: 0,
  rad: 0,
  size: 20,
  speed: PLAYER_SPEED,
  allowFire: true,
  projectiles: [],
  fire: function() {
    if (this.allowFire) {
      this.projectiles.push(new Bolt(this.x, this.y, this.rad));
      this.allowFire = false;
      gAudio.eChan1.startBolt();
      setTimeout(function() { this.allowFire = true }.bind(this), Bolt.delay);
    }
  },
  collide: function(other) {
    var rayToCenter = Math.sqrt(Math.pow(other.x - this.x, 2) + Math.pow(other.y - this.y, 2));
    var collide = rayToCenter < this.size;

    if (!collide) {
      var lastX = this.x - this.xVel;
      var lastY = this.y - this.yVel;
      var lastRay = Math.sqrt(Math.pow(this.x - lastX, 2) + Math.pow(this.y - lastY, 2));
      collide = Math.sqrt(Math.pow(rayToCenter, 2) + Math.pow(lastRay)) < other.size;
    }

    return collide;
  },
  update: function() {
    var xAcc = 0;
    var yAcc = 0;
    this.xVel *= FRICTION;
    this.yVel *= FRICTION;
    if (gInput.isActive('thrust')) {
      this.speed = THRUSTER_SPEED;
      xAcc = Math.cos(this.rad);
      yAcc = Math.sin(this.rad);
    }
    else {
      this.speed = PLAYER_SPEED;
      if (gInput.isActive('left')) xAcc--;
      if (gInput.isActive('right')) xAcc++;
      if (gInput.isActive('up')) yAcc--;
      if (gInput.isActive('down')) yAcc++;
    }
    // this.xVel = Math.abs(this.xVel) > 2e-20 ? this.xVel + xAcc : 0;
    // this.yVel = Math.abs(this.yVel) > 2e-20 ? this.yVel + yAcc : 0;
    this.xVel += xAcc;
    this.yVel += yAcc;

    var collision;
    for (var i in gScene.targets) {
      collision = this.collide(gScene.targets[i]);
      if (collision) {
        this.xVel *= -1;
        this.yVel *= -1;
        break;
      }
    }
    this.x = Math.min(Math.min(gCamera.x + SCREEN_WIDTH, gScene.bounds.r) - 20, Math.max(Math.max(gCamera.x, gScene.bounds.l) + 20, this.x + this.xVel * this.speed));
    this.y = Math.min(Math.min(gCamera.y + SCREEN_HEIGHT, gScene.bounds.b) - 20, Math.max(Math.max(gCamera.y, gScene.bounds.t) + 20, this.y + this.yVel * this.speed));

    this.rad = Math.atan2(gInput.mouseY - (this.y - gCamera.y), gInput.mouseX - (this.x - gCamera.x));

    if (gInput.isActive('fire')) this.fire();
    // Loop through projectiles and only keep the ones still in the level bounds
    var liveProjectiles = [];
    this.projectiles.forEach(function(p) {
      var collision;
      for (var i in gScene.targets) {
        collision = p.collide(gScene.targets[i]);
        if (collision) break;
      }
      if (!collision && gScene.bounds.collide(p)) p.dying = true;
      p.update();
      if (p.life > 0) liveProjectiles.push(p);
    });
    this.projectiles = liveProjectiles;
  },
  render: (function(context) {
    function render() {
      context.beginPath();
      context.moveTo(this.x + (PLAYER_RADIUS * Math.cos(this.rad)) - gCamera.x, this.y + (PLAYER_RADIUS * Math.sin(this.rad)) - gCamera.y);
      context.lineTo(this.x + ((PLAYER_RADIUS / 2) * Math.cos(this.rad + (Math.PI / 4))) - gCamera.x, this.y + ((PLAYER_RADIUS / 2) * Math.sin(this.rad + (Math.PI / 4))) - gCamera.y);
      context.lineTo(this.x + (PLAYER_RADIUS * Math.cos(this.rad + (Math.PI / 2))) - gCamera.x, this.y + (PLAYER_RADIUS * Math.sin(this.rad + (Math.PI / 2))) - gCamera.y);
      context.lineTo(this.x + ((PLAYER_RADIUS * 1.25) * Math.cos(this.rad + (Math.PI * 3 / 4))) - gCamera.x, this.y + ((PLAYER_RADIUS * 1.25) * Math.sin(this.rad + (Math.PI * 3 / 4))) - gCamera.y);
      context.lineTo(this.x + ((PLAYER_RADIUS / 2) * Math.cos(this.rad + Math.PI)) - gCamera.x, this.y + ((PLAYER_RADIUS / 2) * Math.sin(this.rad + Math.PI)) - gCamera.y);
      context.lineTo(this.x + ((PLAYER_RADIUS * 1.25) * Math.cos(this.rad - (Math.PI * 3 / 4))) - gCamera.x, this.y + ((PLAYER_RADIUS * 1.25) * Math.sin(this.rad - (Math.PI * 3 / 4))) - gCamera.y);
      context.lineTo(this.x + (PLAYER_RADIUS * Math.cos(this.rad - (Math.PI / 2))) - gCamera.x, this.y + (PLAYER_RADIUS * Math.sin(this.rad - (Math.PI / 2))) - gCamera.y);
      context.lineTo(this.x + ((PLAYER_RADIUS / 2) * Math.cos(this.rad - (Math.PI / 4))) - gCamera.x, this.y + ((PLAYER_RADIUS / 2) * Math.sin(this.rad - (Math.PI / 4))) - gCamera.y);
      context.closePath();

      context.fillStyle = '#49D';
      context.strokeStyle = '#FB7';
      context.lineWidth = 3;

      context.fill();
      context.stroke();
    }
    return render;
  })(gRenderer.context)
}
<|endoftext|>


<commit_before>/**
 * Created by luki on 16.05.17.
 */
<commit_msg>Added missing filetrs directive<commit_after>window.angular.module('icdsApp').directive("filters", function() {
    var url = hqImport('hqwebapp/js/urllib.js').reverse;
    return {
        restrict:'E',
        scope: {
            data: '=',
        },
        bindToController: true,
        templateUrl: url('icds-ng-template', 'filters'),
        controller: function() {},
        controllerAs: "$ctrl",
    };
});<|endoftext|>


<commit_before>l = console.log();

function toNum(c) {
    switch(c) {
        case 'J':
            return 11;
            break;
        case 'Q':
            return 12;
            break;
        case 'K':
            return 13;
            break;
        case 'A':
            return 14;
            break;

        default:
            return card
    }
}

module.exports = {

    VERSION: "Jofogas's Zsozsobot v3.1",

  compute_avg_stack: function(players) {
      var sum = 0;
      for (var i in players) {
          sum += players.stack;
      }
      return sum / players.length;
  },

  bet_request: function(g) {
    var myself = g.players[g.in_action];

    if (myself.status != "active") {
        return "OK";
    }
    if (myself.hole_cards[1].rank == myself.hole_cards[1].rank) {
        return myself.stack;
    }
    var average_stack = compute_avg_stack(g.players);

    if (myself.stack > average_stack) {
        /* brave */
        var bet = g.current_buy_in - myself["bet"] + g.minimum_raise * 2;
        l("fearlessly raising: ", bet);
        return bet;
    }
    else {
        /* tight */
        l("fearfully not raising: ", 0);
        return 0;
    }
  },

    showdown: function(g) {
        return 'what is this for?';
    }
};
<commit_msg>fixed typo in card index<commit_after>l = console.log();

function toNum(c) {
    switch(c) {
        case 'J':
            return 11;
            break;
        case 'Q':
            return 12;
            break;
        case 'K':
            return 13;
            break;
        case 'A':
            return 14;
            break;

        default:
            return card
    }
}

module.exports = {

    VERSION: "Jofogas's Zsozsobot v3",

  compute_avg_stack: function(players) {
      var sum = 0;
      for (var i in players) {
          sum += players.stack;
      }
      return sum / players.count;
  },

  bet_request: function(g) {
    var myself = g.players[g.in_action];

    if (myself.status != "active") {
        return "OK";
    }
    if (myself.hole_cards[0].rank == myself.hole_cards[1].rank) {
        return myself.stack;
    }
    var average_stack = compute_avg_stack(g.players);

    if (myself.stack > average_stack) {
        /* brave */
        var bet = g.current_buy_in - myself["bet"] + g.minimum_raise * 2;
        l("fearlessly raising: ", bet);
        return bet;
    }
    else {
        /* tight */
        l("fearfully not raising: ", 0);
        return 0;
    }
  },

    showdown: function(g) {
        return 'what is this for?';
    }
};
<|endoftext|>


<commit_before>'use strict';

const getRanking = require('./ranking');

let gameState, myplayer;
module.exports = {
  VERSION: "Kickstarter",
  bet_request: function(game_state, bet) {
    new Promise((resolve, reject) => {
        gameState =  game_state;
        myplayer = game_state.players[game_state.in_action];
        console.log(myplayer.hole_cards);
        console.log(game_state);

        //Check for zero phase

        let promise;
        if(gameState.community_cards.length <= 3){
          promise = Promise.resolve(phase_zero());
        } else {
          promise = Promise.resolve(phase_two());
        }
        promise.then(resolve, reject);
    }).then(value => {
        bet(Math.round(value));
    }).catch(err => {
        console.log('ERROR', err);
    });
  },
  showdown: function(game_state) {
  }
};

function phase_zero (){

  const rank = evaluate(myplayer.hole_cards);
  console.log("phase zero", rank);
  if(rank >= 3){
    return minimalRaise();
  }else if (rank >= 1) {
    return call();
  }
  console.log('neither raise nor call');
  const highCards = myplayer.hole_cards.filter(isHighCard);
  if(highCards.length > 0 && isSmallBlind()) {
    console.log('we have a high card and it is still small blind - call!');
    return callMax(gameState.small_blind * 4);
  }
  return fold();
}

function phase_two (){
  console.log('phase 2!');
  const allCards = gameState.community_cards.map(item => item);
  myplayer.hole_cards.forEach(item => allCards.push(item));
  console.log('allcards', allCards);

  const numberOfPairs = pairsWithCommunity(myplayer.hole_cards[0], myplayer.hole_cards[1], gameState.community_cards);
  if(numberOfPairs >= 2) {
    return allIn();
  } else if(numberOfPairs === 1) {
    return minimalRaise(); // TODO: maybe more?
  }

  if(isSuited(myplayer.hole_cards)) {
    const suit = myplayer.hole_cards[0].suit;
    const suited = gameState.community_cards.filter(card => {
        return card.suit === suit;
    }).length;

    if(suited === 3) { // FLUSH!
        return allIn();
    } else if(suited == 2) {
        if(gameState.community_cards.length < 5) { // flush still possible
            return minimalRaise();
        } // else use ranking
    }
  }

  // const communityOnly = getRanking(gameState.community_cards);
  const withOurCards = getRanking(allCards);
  return getRanking(allCards).then((rankingData) => {
    const allCardsRank = rankingData.rank;
    console.log('got rank', allCardsRank);
    if(allCardsRank >= 8) {
        return allIn();
    } else if(allCardsRank >= 5) {
        return minimalRaise();
    } else if(allCardsRank >= 3) {
        return minimalRaise();
    } else if(allCardsRank >= 2) {
        return minimalRaise();
    } else if(allCardsRank >= 1) {
        return call();
    } else {
        return fold();
    }
  }, err => {
    console.log('ERROR could not get rank', err);
    return call();
  });

  // const rank = evaluate(myplayer.hole_cards);
  // if(rank === 3){
  //   return gameState.minimum_raise;
  // }else if (rank ===2) {
  //   return call();
  // }
  // return fold();
}

function evaluate (cards){
  const first = cards[0];
  const second = cards[1];
  if(first.rank === second.rank){ // check pair
    return 3;
  }else if(isSuited(cards)){
    return 2;
  } else if(isHighCard(first) || isHighCard(second) || areContinous(first, second)) {
    return 1;
  }else {
    return 0;
  }
}

function isHighCard(card) {
    const highCards = ['J', 'Q', 'A', 'K', '10'];
    return highCards.indexOf(card.rank.toUpperCase()) >= 0;
}

function isSmallBlind() {
    return gameState.current_buy_in === gameState.small_blind;
}

function callMax(max) {
    const called = call();
    return Math.min(max, called); // if "max" is selected, we fold
}

function isSuited(cards){
  const first = cards[0];
  const second = cards[1];
  if(first.suit === second.suit){
    return true;
  }
  return false;

}

function pairsWithCommunity(first, second, communityCards) {
    const pairs = communityCards.filter((commCard) => {
        return isPair(commCard, first) || isPair(commCard, second);
    });
    return pairs.length;
}

function isPair(first, second) {
    return first.rank === second.rank;
}

function areContinous(first, second) {
    const ranks = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A'];
    const firstValue = ranks.indexOf(first.rank);
    const secondValue = ranks.indexOf(second.rank);
    return ((firstValue + 1) == secondValue) || (firstValue == (secondValue + 1));
}

function call (){
  const c = gameState.current_buy_in - gameState.players[gameState.in_action].bet;
  return c;
}

function allIn(){
  const c = myplayer.stack;
  return c;
}

function fold(){
  return 0;
}

function minimalRaise() {
    const rand = Math.random();
    if(rand > 0.7) {
        return call() + rand * 10 * gameState.minimum_raise; // randomly higher
    } else {
        return call() + gameState.minimum_raise+100;
    }
}<commit_msg>minor<commit_after>'use strict';

const getRanking = require('./ranking');

let gameState, myplayer;
module.exports = {
  VERSION: "Kickstarter",
  bet_request: function(game_state, bet) {
    new Promise((resolve, reject) => {
        gameState =  game_state;
        myplayer = game_state.players[game_state.in_action];
        console.log(myplayer.hole_cards);
        console.log(game_state);

        //Check for zero phase

        let promise;
        if(gameState.community_cards.length <= 3){
          promise = Promise.resolve(phase_zero());
        } else {
          promise = Promise.resolve(phase_two());
        }
        promise.then(resolve, reject);
    }).then(value => {
        bet(Math.round(value));
    }).catch(err => {
        console.log('ERROR', err);
    });
  },
  showdown: function(game_state) {
  }
};

function phase_zero (){

  const rank = evaluate(myplayer.hole_cards);
  const highCards = myplayer.hole_cards.filter(isHighCard);
  if(highCards.length > 0 && isSmallBlind()) {
    console.log('we have a high card and it is still small blind - call!');
    return callMax(gameState.small_blind * 4);
  }

  const haveHighCard = highCards.length > 0;
  if(haveHighCard) {
    return callMax(4 * gameState.small_blind);
  }
  console.log("phase zero", rank);
  if(rank >= 3){
    return minimalRaise();
  }else if (rank >= 1) {
    return call();
  }
  console.log('neither raise nor call');
  return fold();
}

function phase_two (){
  console.log('phase 2!');
  const allCards = gameState.community_cards.map(item => item);
  myplayer.hole_cards.forEach(item => allCards.push(item));
  console.log('allcards', allCards);

  const numberOfPairs = pairsWithCommunity(myplayer.hole_cards[0], myplayer.hole_cards[1], gameState.community_cards);
  if(numberOfPairs >= 2) {
    return allIn();
  } else if(numberOfPairs === 1) {
    return minimalRaise(); // TODO: maybe more?
  }

  if(isSuited(myplayer.hole_cards)) {
    const suit = myplayer.hole_cards[0].suit;
    const suited = gameState.community_cards.filter(card => {
        return card.suit === suit;
    }).length;

    if(suited === 3) { // FLUSH!
        return allIn();
    } else if(suited == 2) {
        if(gameState.community_cards.length < 5) { // flush still possible
            return minimalRaise();
        } // else use ranking
    }
  }

  // const communityOnly = getRanking(gameState.community_cards);
  const withOurCards = getRanking(allCards);
  return getRanking(allCards).then((rankingData) => {
    const allCardsRank = rankingData.rank;
    console.log('got rank', allCardsRank);
    if(allCardsRank >= 8) {
        return allIn();
    } else if(allCardsRank >= 5) {
        return minimalRaise();
    } else if(allCardsRank >= 3) {
        return minimalRaise();
    } else if(allCardsRank >= 2) {
        return minimalRaise();
    } else if(allCardsRank >= 1) {
        return call();
    } else {
        return fold();
    }
  }, err => {
    console.log('ERROR could not get rank', err);
    return call();
  });

  // const rank = evaluate(myplayer.hole_cards);
  // if(rank === 3){
  //   return gameState.minimum_raise;
  // }else if (rank ===2) {
  //   return call();
  // }
  // return fold();
}

function evaluate (cards){
  const first = cards[0];
  const second = cards[1];
  if(first.rank === second.rank){ // check pair
    return 3;
  }else if(isSuited(cards)){
    return 2;
  } else if(isHighCard(first) || isHighCard(second) || areContinous(first, second)) {
    return 1;
  }else {
    return 0;
  }
}

function isHighCard(card) {
    const highCards = ['J', 'Q', 'A', 'K', '10'];
    return highCards.indexOf(card.rank.toUpperCase()) >= 0;
}

function isSmallBlind() {
    return gameState.current_buy_in === gameState.small_blind;
}

function callMax(max) {
    const called = call();
    return Math.min(max, called); // if "max" is selected, we fold
}

function isSuited(cards){
  const first = cards[0];
  const second = cards[1];
  if(first.suit === second.suit){
    return true;
  }
  return false;

}

function pairsWithCommunity(first, second, communityCards) {
    const pairs = communityCards.filter((commCard) => {
        return isPair(commCard, first) || isPair(commCard, second);
    });
    return pairs.length;
}

function isPair(first, second) {
    return first.rank === second.rank;
}

function areContinous(first, second) {
    const ranks = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A'];
    const firstValue = ranks.indexOf(first.rank);
    const secondValue = ranks.indexOf(second.rank);
    return ((firstValue + 1) == secondValue) || (firstValue == (secondValue + 1));
}

function call (){
  const c = gameState.current_buy_in - gameState.players[gameState.in_action].bet;
  return c;
}

function allIn(){
  const c = myplayer.stack;
  return c;
}

function fold(){
  return 0;
}

function minimalRaise() {
    const rand = Math.random();
    if(rand > 0.7) {
        return call() + rand * 10 * gameState.minimum_raise; // randomly higher
    } else {
        return call() + gameState.minimum_raise+100;
    }
}<|endoftext|>


<commit_before>app.SearchResults = {};

app.SearchResults.View = Backbone.View.extend({
  events: {
    "click a.list-group-item":"navigateToProfile"
  },

  template: _.template($('#search-template').html()),

  ajaxRequest: function(){
    var input = $(".form-control").val()
    Backbone.ajax({
      url: "/search",
      type: "get",
      data: {input: input}
    }).done(function(data){
      var templates = ""
      for (var i = 0; i < data.apis.length; i++){
        templates += this.template(data.apis[i])
      }
      $('#app-body').empty();
      $('#app-body').html(templates);
      $(".result").on('click', this.navigateToProfile);
    }.bind(this)).fail(function(){
    })
  },

  render: function(){
    this.ajaxRequest();
  },

  navigateToProfile: function(){
    event.preventDefault();
    var id = $(".container")[this.dataset.id].dataset.id
    app.router.navigate("api/" + id, true)
  }

})

<commit_msg>Changed where search list appends. Caution: May interfere with current version.<commit_after>app.SearchResults = {};

app.SearchResults.View = Backbone.View.extend({
  events: {
    "click a.list-group-item":"navigateToProfile"
  },

  template: _.template($('#search-template').html()),

  ajaxRequest: function(){
    var input = $(".form-control").val()
    Backbone.ajax({
      url: "/search",
      type: "get",
      data: {input: input}
    }).done(function(data){
      var templates = ""
      for (var i = 0; i < data.apis.length; i++){
        templates += this.template(data.apis[i])
      }
      $('#app-body').empty();
      $('#app-body').append('

');
      $('#search-list').html(templates);
      $(".result").on('click', this.navigateToProfile);
    }.bind(this)).fail(function(){
    })
  },

  render: function(){
    this.ajaxRequest();
  },

  navigateToProfile: function(){
    event.preventDefault();
    var id = $(".container")[this.dataset.id].dataset.id
    app.router.navigate("api/" + id, true)
  }

})

<|endoftext|>


<commit_before>'use strict';
const Base = require('yeoman-generator');

const plugins = require('../../utils/types').plugin;
const stringifyAble = require('../../utils').stringifyAble;
const path = require('path');
const fs = require('fs');
const glob = require('glob').sync;
const chalk = require('chalk');

function toJSONFromText(text) {
  const r = {};
  text.split('\n').forEach((line) => {
    const trimmedLine = line.trim();
    if (trimmedLine.length === 0) { // ignore empty lines (e.g. new line added by editor)
      return;
    }

    const splitPoint = trimmedLine.indexOf('=');
    const key = trimmedLine.slice(0, splitPoint);
    let value = trimmedLine.slice(splitPoint + 1);
    value = value.trim();
    if (!isNaN(parseFloat(value))) {
      value = parseFloat(value);
    }
    let obj = r;
    const keys = key.trim().split('.');
    keys.slice(0, keys.length - 1).forEach((k) => {
      if (!(k in obj)) {
        obj[k] = {};
      }
      obj = obj[k];
    });
    obj[keys[keys.length - 1]] = value;
  });
  return r;
}

/**
 * The outside key in the `.yo-rc.json` file where the configuration is saved.
 * Used to manually add key-value pairs to the `.yo-rc.json` file.
 */
const GENERATOR_PHOVEA_CONFIG = 'generator-phovea';

/**
 * Find the string in the plugin's `__init__.py` file and replace it with the new extension entry.
 */
const REPLACE_STRING_PYTHON_FILE = '# generator-phovea:end';

/**
 * Find the string in the plugin's `phovea.ts` file and replace it with the new extension entry.
 */
const REPLACE_STRING_JAVASCRIPT_FILE = '// generator-phovea:end';

class Generator extends Base {
  constructor(args, options) {
    super(args, options);
    this.basetype = 'web';
    this.new_ = null;
  }

  initializing() {
    this.composeWith(['phovea:_check-own-version', 'phovea:check-node-version']);
  }

  /**
   * Find all plugins in the workspace by checking if they have a `.yo-rc.json file`.
   * @returns {string} The name of the plugin directory
   */
  _findPluginsInWorkspace() {
    const files = glob('*/.yo-rc.json', {
      cwd: this.destinationPath()
    });
    return files.map(path.dirname);
  }

  /**
   * Prompt the user to choose the application he would like to add the extension to when the generator is executed from the workspace.
   */
  _chooseApplication() {
    return this.prompt([{
      type: 'list',
      name: 'plugin',
      choices: this._findPluginsInWorkspace(),
      message: 'Plugin/Application',
      when: this._isWorkspace()
    }]);
  }

  /**
   * Check if current directory is the workspace.
   */
  _isWorkspace() {
    return fs.existsSync(this.destinationPath('.yo-rc-workspace.json'));
  }

  /**
   * Reads a key in the `.yo.rc.json` either from the current directory or a subdirectory.
   * @param {string} path Directory name of the plugin, i.e., `phovea_core/`.
   * @param {string} key Key in the config file.
   * @return {string} The value of the key. Throws an error if the `.yo.rc.json` file has an invalid structure.
   */
  _readConfig(path, key) {
    try {
      if (path) {
        const config = this.fs.readJSON(this.destinationPath(path + '.yo-rc.json'), {})[GENERATOR_PHOVEA_CONFIG];
        return config[key]

      } else {
        this.config.get(key);
      }
    } catch (e) {
      throw new Error(chalk.red('Invalid `yo-rc.json` file in ' + path))
    }
  }

  /**
   * Saves configuration to the `.yo-rc.json file` either in the current directory or inside the plugin folder if the generator is executed from the workspace.
   * @param {*} path  Directory name of the plugin, i.e., `phovea_core/`.
   * @param {*} key Key in the config file.
   * @param {*} value Value to assign to key.
   */
  _writeConfig(path, key, value) {
    if (path) {
      const configFile = this.fs.readJSON(this.destinationPath(path + '.yo-rc.json'));
      configFile[GENERATOR_PHOVEA_CONFIG][key] = value;
      this.fs.writeJSON(this.destinationPath(path + '.yo-rc.json'), configFile);

    } else {
      this.config.set(key, value);
    }
  }

  async prompting() {
    const {plugin} = await this._chooseApplication();
    this.cwd = plugin ? plugin + '/' : '';

    const type = this._readConfig(this.cwd, 'type');
    const isHybridType = plugins.isTypeHybrid({type});

    return this.prompt([{
      type: 'list',
      name: 'basetype',
      choices: ['web', 'server'],
      message: 'Base Type',
      default: 'web',
      when: isHybridType
    }, {
      name: 'type',
      message: 'Type',
      required: true
    }, {
      name: 'id',
      message: 'ID',
      required: true
    }, {
      name: 'module',
      message: 'File Name',
      required: true
    }, {
      type: 'editor',
      name: 'extras',
      message: 'Extras (key=value)'
    }]).then((props) => {
      this.basetype = 'web';
      if ((isHybridType && props.basetype === 'server') || (!isHybridType && plugins.isTypeServer({type}))) {
        this.basetype = 'server';
      }
      this.new_ = {
        type: props.type,
        id: props.id,
        module: props.module,
        extras: toJSONFromText(props.extras)
      };
    });
  }

  writing() {
    const basekey = this.basetype === 'web' ? 'extensions' : 'sextensions';
    const arr = this._readConfig(this.cwd, basekey);
    arr.push(this.new_);
    this._writeConfig(this.cwd, basekey, arr);
    // inject new extension

    const d = stringifyAble(this.new_);

    if (this.basetype === 'web') {
      this._injectWebExtension(d, this.cwd);
    } else {
      this._injectServerExtension(d, this.cwd);
    }
  }

  /**
   * Tests if the string `// generator-phovea:end` and `# generator-phovea:end` exist in `phovea.ts` and `/__init__.py` respectively.
   * @param {string} target Target string file to be tested.
   * @param {string} string String to test with either `// generator-phovea:end` or `# generator-phovea:end`.
   * @param {string} filePath Path of the target file.
   */
  _testReplaceStringExists(target, string, filePath) {
    const regex = RegExp(string);
    if (!regex.test(target)) {
      throw new Error(chalk.red(`String "${string}" not found in ${filePath}.`));
    }
  }

  _injectWebExtension(d, cwd) {
    const pathToRegistry = fs.existsSync(cwd + 'src/phovea.ts') ? cwd + 'src/phovea.ts' : cwd + 'phovea.js'; // check if the project has a phovea.ts file in src folder or a phovea.js in plugin root
    const file = this.destinationPath(pathToRegistry);
    const old = this.fs.read(file);
    let absFile = '';
    let importFunction = '';

    this._testReplaceStringExists(old, REPLACE_STRING_JAVASCRIPT_FILE, pathToRegistry);

    if (fs.existsSync(cwd + 'src/phovea.ts')) {
      absFile = d.module.startsWith('~') ? d.module.slice(1) : `./${d.module.includes('.') ? d.module.slice(0, d.module.lastIndexOf('.')) : d.module}`;
      importFunction = `() => System.import('${absFile}')`; // TODO remove System.import for Typescript case when switching to Webpack 4 (see https://github.com/phovea/generator-phovea/issues/286#issuecomment-566553497)
    } else {
      absFile = d.module.startsWith('~') ? d.module.slice(1) : `./src/${d.module.includes('.') ? d.module.slice(0, d.module.lastIndexOf('.')) : d.module}`;
      importFunction = `function() { return import('${absFile}'); }`;
    }
    const text = `\n\n  registry.push('${d.type}', '${d.id}', ${importFunction}, ${d.stringify(d.extras, ' ')});\n  ${REPLACE_STRING_JAVASCRIPT_FILE}`; // indentation is 2 spaces
    const new_ = old.replace(`  ${REPLACE_STRING_JAVASCRIPT_FILE}`, text);  // also here indentation is 2 spaces
    this.fs.write(file, new_);

    const target = this.destinationPath(cwd + `src/${d.module}${d.module.includes('.') ? '' : '.ts'}`);
    if (absFile.startsWith('.') && !fs.existsSync(target)) {
      let source = this.templatePath(`${d.type}.tmpl.ts`);
      if (!fs.existsSync(source)) {
        source = this.templatePath('template.tmpl.ts');
      }
      const config = this._getModuleConfig(target);
      this.fs.copyTpl(source, target, Object.assign(config, d));
    }
  }

  _injectServerExtension(d, cwd) {
    const name = this._readConfig(cwd, 'name');
    const file = this.destinationPath(`${cwd}${name}/__init__.py`);
    const old = this.fs.read(file);
    const text = `\n\n  registry.append('${d.type}', '${d.id}', '${name}.${d.module}', ${d.stringifyPython(d.extras, '  ')})\n  ${REPLACE_STRING_PYTHON_FILE}`; // indentation is 2 spaces
    const new_ = old.replace(`  ${REPLACE_STRING_PYTHON_FILE}`, text); // also here indentation is 2 spaces
    this.fs.write(file, new_);

    this._testReplaceStringExists(old, REPLACE_STRING_PYTHON_FILE, file);

    const target = this.destinationPath(`${cwd}${name}/${d.module}.py`);
    if (!fs.existsSync(target)) {
      let source = this.templatePath(`${d.type}.tmpl.py`);
      if (!fs.existsSync(source)) {
        source = this.templatePath('template.tmpl.py');
      }
      const config = this._getModuleConfig(target);
      this.fs.copyTpl(source, target, Object.assign(config, d));
    }
  }

  _getModuleConfig(target) {
    return {
      moduleName: path.basename(target, path.extname(target))
    };
  }
}

module.exports = Generator;
<commit_msg>Minor fix<commit_after>'use strict';
const Base = require('yeoman-generator');

const plugins = require('../../utils/types').plugin;
const stringifyAble = require('../../utils').stringifyAble;
const path = require('path');
const fs = require('fs');
const glob = require('glob').sync;
const chalk = require('chalk');

function toJSONFromText(text) {
  const r = {};
  text.split('\n').forEach((line) => {
    const trimmedLine = line.trim();
    if (trimmedLine.length === 0) { // ignore empty lines (e.g. new line added by editor)
      return;
    }

    const splitPoint = trimmedLine.indexOf('=');
    const key = trimmedLine.slice(0, splitPoint);
    let value = trimmedLine.slice(splitPoint + 1);
    value = value.trim();
    if (!isNaN(parseFloat(value))) {
      value = parseFloat(value);
    }
    let obj = r;
    const keys = key.trim().split('.');
    keys.slice(0, keys.length - 1).forEach((k) => {
      if (!(k in obj)) {
        obj[k] = {};
      }
      obj = obj[k];
    });
    obj[keys[keys.length - 1]] = value;
  });
  return r;
}

/**
 * The outside key in the `.yo-rc.json` file where the configuration is saved.
 * Used to manually add key-value pairs to the `.yo-rc.json` file.
 */
const GENERATOR_PHOVEA_CONFIG = 'generator-phovea';

/**
 * Find the string in the plugin's `__init__.py` file and replace it with the new extension entry.
 */
const REPLACE_STRING_PYTHON_FILE = '# generator-phovea:end';

/**
 * Find the string in the plugin's `phovea.ts` file and replace it with the new extension entry.
 */
const REPLACE_STRING_JAVASCRIPT_FILE = '// generator-phovea:end';

class Generator extends Base {
  constructor(args, options) {
    super(args, options);
    this.basetype = 'web';
    this.new_ = null;
  }

  initializing() {
    this.composeWith(['phovea:_check-own-version', 'phovea:check-node-version']);
  }

  /**
   * Find all plugins in the workspace by checking if they have a `.yo-rc.json file`.
   * @returns {string} The name of the plugin directory
   */
  _findPluginsInWorkspace() {
    const files = glob('*/.yo-rc.json', {
      cwd: this.destinationPath()
    });
    return files.map(path.dirname);
  }

  /**
   * Prompt the user to choose the application he would like to add the extension to when the generator is executed from the workspace.
   */
  _chooseApplication() {
    return this.prompt([{
      type: 'list',
      name: 'plugin',
      choices: this._findPluginsInWorkspace(),
      message: 'Plugin/Application',
      when: this._isWorkspace()
    }]);
  }

  /**
   * Check if current directory is the workspace.
   */
  _isWorkspace() {
    return fs.existsSync(this.destinationPath('.yo-rc-workspace.json'));
  }

  /**
   * Reads a key in the `.yo.rc.json` either from the current directory or a subdirectory.
   * @param {string} path Directory name of the plugin, i.e., `phovea_core/`.
   * @param {string} key Key in the config file.
   * @return {string} The value of the key. Throws an error if the `.yo.rc.json` file has an invalid structure.
   */
  _readConfig(path, key) {
    try {
      if (path) {
        const config = this.fs.readJSON(this.destinationPath(path + '.yo-rc.json'), {})[GENERATOR_PHOVEA_CONFIG];
        return config[key]

      } else {
        return this.config.get(key);
      }
    } catch (e) {
      throw new Error(chalk.red('Invalid `yo-rc.json` file in ' + path))
    }
  }

  /**
   * Saves configuration to the `.yo-rc.json file` either in the current directory or inside the plugin folder if the generator is executed from the workspace.
   * @param {*} path  Directory name of the plugin, i.e., `phovea_core/`.
   * @param {*} key Key in the config file.
   * @param {*} value Value to assign to key.
   */
  _writeConfig(path, key, value) {
    if (path) {
      const configFile = this.fs.readJSON(this.destinationPath(path + '.yo-rc.json'));
      configFile[GENERATOR_PHOVEA_CONFIG][key] = value;
      this.fs.writeJSON(this.destinationPath(path + '.yo-rc.json'), configFile);

    } else {
      this.config.set(key, value);
    }
  }

  async prompting() {
    const {plugin} = await this._chooseApplication();
    this.cwd = plugin ? plugin + '/' : '';

    const type = this._readConfig(this.cwd, 'type');
    const isHybridType = plugins.isTypeHybrid({type});

    return this.prompt([{
      type: 'list',
      name: 'basetype',
      choices: ['web', 'server'],
      message: 'Base Type',
      default: 'web',
      when: isHybridType
    }, {
      name: 'type',
      message: 'Type',
      required: true
    }, {
      name: 'id',
      message: 'ID',
      required: true
    }, {
      name: 'module',
      message: 'File Name',
      required: true
    }, {
      type: 'editor',
      name: 'extras',
      message: 'Extras (key=value)'
    }]).then((props) => {
      this.basetype = 'web';
      if ((isHybridType && props.basetype === 'server') || (!isHybridType && plugins.isTypeServer({type}))) {
        this.basetype = 'server';
      }
      this.new_ = {
        type: props.type,
        id: props.id,
        module: props.module,
        extras: toJSONFromText(props.extras)
      };
    });
  }

  writing() {
    const basekey = this.basetype === 'web' ? 'extensions' : 'sextensions';
    const arr = this._readConfig(this.cwd, basekey);
    this.log(arr, this.cwd)
    arr.push(this.new_);
    this._writeConfig(this.cwd, basekey, arr);
    // inject new extension

    const d = stringifyAble(this.new_);

    if (this.basetype === 'web') {
      this._injectWebExtension(d, this.cwd);
    } else {
      this._injectServerExtension(d, this.cwd);
    }
  }

  /**
   * Tests if the string `// generator-phovea:end` and `# generator-phovea:end` exist in `phovea.ts` and `/__init__.py` respectively.
   * @param {string} target Target string file to be tested.
   * @param {string} string String to test with either `// generator-phovea:end` or `# generator-phovea:end`.
   * @param {string} filePath Path of the target file.
   */
  _testReplaceStringExists(target, string, filePath) {
    const regex = RegExp(string);
    if (!regex.test(target)) {
      throw new Error(chalk.red(`String "${string}" not found in ${filePath}.`));
    }
  }

  _injectWebExtension(d, cwd) {
    const pathToRegistry = fs.existsSync(cwd + 'src/phovea.ts') ? cwd + 'src/phovea.ts' : cwd + 'phovea.js'; // check if the project has a phovea.ts file in src folder or a phovea.js in plugin root
    const file = this.destinationPath(pathToRegistry);
    const old = this.fs.read(file);
    let absFile = '';
    let importFunction = '';

    this._testReplaceStringExists(old, REPLACE_STRING_JAVASCRIPT_FILE, pathToRegistry);

    if (fs.existsSync(cwd + 'src/phovea.ts')) {
      absFile = d.module.startsWith('~') ? d.module.slice(1) : `./${d.module.includes('.') ? d.module.slice(0, d.module.lastIndexOf('.')) : d.module}`;
      importFunction = `() => System.import('${absFile}')`; // TODO remove System.import for Typescript case when switching to Webpack 4 (see https://github.com/phovea/generator-phovea/issues/286#issuecomment-566553497)
    } else {
      absFile = d.module.startsWith('~') ? d.module.slice(1) : `./src/${d.module.includes('.') ? d.module.slice(0, d.module.lastIndexOf('.')) : d.module}`;
      importFunction = `function() { return import('${absFile}'); }`;
    }
    const text = `\n\n  registry.push('${d.type}', '${d.id}', ${importFunction}, ${d.stringify(d.extras, ' ')});\n  ${REPLACE_STRING_JAVASCRIPT_FILE}`; // indentation is 2 spaces
    const new_ = old.replace(`  ${REPLACE_STRING_JAVASCRIPT_FILE}`, text);  // also here indentation is 2 spaces
    this.fs.write(file, new_);

    const target = this.destinationPath(cwd + `src/${d.module}${d.module.includes('.') ? '' : '.ts'}`);
    if (absFile.startsWith('.') && !fs.existsSync(target)) {
      let source = this.templatePath(`${d.type}.tmpl.ts`);
      if (!fs.existsSync(source)) {
        source = this.templatePath('template.tmpl.ts');
      }
      const config = this._getModuleConfig(target);
      this.fs.copyTpl(source, target, Object.assign(config, d));
    }
  }

  _injectServerExtension(d, cwd) {
    const name = this._readConfig(cwd, 'name');
    const file = this.destinationPath(`${cwd}${name}/__init__.py`);
    const old = this.fs.read(file);
    const text = `\n\n  registry.append('${d.type}', '${d.id}', '${name}.${d.module}', ${d.stringifyPython(d.extras, '  ')})\n  ${REPLACE_STRING_PYTHON_FILE}`; // indentation is 2 spaces
    const new_ = old.replace(`  ${REPLACE_STRING_PYTHON_FILE}`, text); // also here indentation is 2 spaces
    this.fs.write(file, new_);

    this._testReplaceStringExists(old, REPLACE_STRING_PYTHON_FILE, file);

    const target = this.destinationPath(`${cwd}${name}/${d.module}.py`);
    if (!fs.existsSync(target)) {
      let source = this.templatePath(`${d.type}.tmpl.py`);
      if (!fs.existsSync(source)) {
        source = this.templatePath('template.tmpl.py');
      }
      const config = this._getModuleConfig(target);
      this.fs.copyTpl(source, target, Object.assign(config, d));
    }
  }

  _getModuleConfig(target) {
    return {
      moduleName: path.basename(target, path.extname(target))
    };
  }
}

module.exports = Generator;
<|endoftext|>