text:
from __future__ import absolute_import
from builtins import str
from builtins import range

import msgpack
import gevent.pool
import gevent.queue
import gevent.event
import gevent.local
import gevent.lock
import logging
import sys

from . import gevent_zmq as zmq
from .exceptions import TimeoutExpired
from .context import Context
from .channel_base import ChannelBase

if sys.version_info < (2, 7):
    def get_pyzmq_frame_buffer(frame):
        return frame.buffer[:]
else:
    def get_pyzmq_frame_buffer(frame):
        return frame.buffer

# gevent <= 1.1.0.rc5 is missing the Python3 __next__ method.
if sys.version_info >= (3, 0) and gevent.version_info <= (1, 1, 0, 'rc', '5'):
    setattr(gevent.queue.Channel, '__next__', gevent.queue.Channel.next)

logger = logging.getLogger(__name__)

class SequentialSender(object):

    def __init__(self, socket):
        self._socket = socket

    def _send(self, parts):
        e = None
        for i in range(len(parts) - 1):
            try:
                self._socket.send(parts[i], copy=False, flags=zmq.SNDMORE)
            except (gevent.GreenletExit, gevent.Timeout) as e:
                if i == 0:
                    raise
                self._socket.send(parts[i], copy=False, flags=zmq.SNDMORE)
        try:
            self._socket.send(parts[-1], copy=False)
        except (gevent.GreenletExit, gevent.Timeout) as e:
            self._socket.send(parts[-1], copy=False)
        if e:
            raise e

    def __call__(self, parts, timeout=None):
        if timeout:
            with gevent.Timeout(timeout):
                self._send(parts)
        else:
            self._send(parts)

class SequentialReceiver(object):

    def __init__(self, socket):
        self._socket = socket

    def _recv(self):
        e = None
        parts = []
        while True:
            try:
                part = self._socket.recv(copy=False)
            except (gevent.GreenletExit, gevent.Timeout) as e:
                if len(parts) == 0:
                    raise
                part = self._socket.recv(copy=False)
            parts.append(part)
            if not part.more:
                break
        if e:
            raise e
        return parts

    def __call__(self, timeout=None):
        if timeout:
            with gevent.Timeout(timeout):
                return self._recv()
        else:
            return self._recv()

class Sender(SequentialSender):

    def __init__(self, socket):
        self._socket = socket
        self._send_queue = gevent.queue.Channel()
        self._send_task = gevent.spawn(self._sender)

    def close(self):
        if self._send_task:
            self._send_task.kill()

    def _sender(self):
        for parts in self._send_queue:
            super(Sender, self)._send(parts)

    def __call__(self, parts, timeout=None):
        try:
            self._send_queue.put(parts, timeout=timeout)
        except gevent.queue.Full:
            raise TimeoutExpired(timeout)

class Receiver(SequentialReceiver):

    def __init__(self, socket):
        self._socket = socket
        self._recv_queue = gevent.queue.Channel()
        self._recv_task = gevent.spawn(self._recver)

    def close(self):
        if self._recv_task:
            self._recv_task.kill()
        self._recv_queue = None

    def _recver(self):
        while True:
            parts = super(Receiver, self)._recv()
            self._recv_queue.put(parts)

    def __call__(self, timeout=None):
        try:
            return self._recv_queue.get(timeout=timeout)
        except gevent.queue.Empty:
            raise TimeoutExpired(timeout)

class Event(object):

    __slots__ = ['_name', '_args', '_header', '_identity']

    # protocol details:
    #  - `name` and `header` keys must be unicode strings.
    #  - `message_id` and 'response_to' values are opaque bytes string.
    #  - `v' value is an integer.
    def __init__(self, name, args, context, header=None):
        self._name = name
        self._args = args
        if header is None:
            self._header = {u'message_id': context.new_msgid(), u'v': 3}
        else:
            self._header = header
        self._identity = None

    @property
    def header(self):
        return self._header

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, v):
        self._name = v

    @property
    def args(self):
        return self._args

    @property
    def identity(self):
        return self._identity

    @identity.setter
    def identity(self, v):
        self._identity = v

    def pack(self):
        payload = (self._header, self._name, self._args)
        r = msgpack.Packer(use_bin_type=True).pack(payload)
        return r

    @staticmethod
    def unpack(blob):
        unpacker = msgpack.Unpacker(raw=False)
        unpacker.feed(blob)
        unpacked_msg = unpacker.unpack()

        try:
            (header, name, args) = unpacked_msg
        except Exception as e:
            raise Exception('invalid msg format "{0}": {1}'.format(
                unpacked_msg, e))

        # Backward compatibility
        if not isinstance(header, dict):
            header = {}

        return Event(name, args, None, header)

    def __str__(self, ignore_args=False):
        if ignore_args:
            args = '[...]'
        else:
            args = self._args
            try:
                args = '<<{0}>>'.format(str(self.unpack(self._args)))
            except Exception:
                pass
        if self._identity:
            identity = ', '.join(repr(x.bytes) for x in self._identity)
            return '<{0}> {1} {2} {3}'.format(identity, self._name,
                    self._header, args)
        return '{0} {1} {2}'.format(self._name, self._header, args)

class Events(ChannelBase):
    def __init__(self, zmq_socket_type, context=None):
        self._debug = False
        self._zmq_socket_type = zmq_socket_type
        self._context = context or Context.get_instance()
        self._socket = self._context.socket(zmq_socket_type)

        if zmq_socket_type in (zmq.PUSH, zmq.PUB, zmq.DEALER, zmq.ROUTER):
            self._send = Sender(self._socket)
        elif zmq_socket_type in (zmq.REQ, zmq.REP):
            self._send = SequentialSender(self._socket)
        else:
            self._send = None

        if zmq_socket_type in (zmq.PULL, zmq.SUB, zmq.DEALER, zmq.ROUTER):
            self._recv = Receiver(self._socket)
        elif zmq_socket_type in (zmq.REQ, zmq.REP):
            self._recv = SequentialReceiver(self._socket)
        else:
            self._recv = None

    @property
    def recv_is_supported(self):
        return self._recv is not None

    @property
    def emit_is_supported(self):
        return self._send is not None

    def __del__(self):
        try:
            if not self._socket.closed:
                self.close()
        except (AttributeError, TypeError):
            pass

    def close(self):
        try:
            self._send.close()
        except (AttributeError, TypeError, gevent.GreenletExit):
            pass
        try:
            self._recv.close()
        except (AttributeError, TypeError, gevent.GreenletExit):
            pass
        self._socket.close()

    @property
    def debug(self):
        return self._debug

    @debug.setter
    def debug(self, v):
        if v != self._debug:
            self._debug = v
            if self._debug:
                logger.debug('debug enabled')
            else:
                logger.debug('debug disabled')

    def _resolve_endpoint(self, endpoint, resolve=True):
        if resolve:
            endpoint = self._context.hook_resolve_endpoint(endpoint)
        if isinstance(endpoint, (tuple, list)):
            r = []
            for sub_endpoint in endpoint:
                r.extend(self._resolve_endpoint(sub_endpoint, resolve))
            return r
        return [endpoint]

    def connect(self, endpoint, resolve=True):
        r = []
        for endpoint_ in self._resolve_endpoint(endpoint, resolve):
            r.append(self._socket.connect(endpoint_))
            logger.debug('connected to %s (status=%s)', endpoint_, r[-1])
        return r

    def bind(self, endpoint, resolve=True):
        r = []
        for endpoint_ in self._resolve_endpoint(endpoint, resolve):
            r.append(self._socket.bind(endpoint_))
            logger.debug('bound to %s (status=%s)', endpoint_, r[-1])
        return r

    def disconnect(self, endpoint, resolve=True):
        r = []
        for endpoint_ in self._resolve_endpoint(endpoint, resolve):
            r.append(self._socket.disconnect(endpoint_))
            logger.debug('disconnected from %s (status=%s)', endpoint_, r[-1])
        return r

    def new_event(self, name, args, xheader=None):
        event = Event(name, args, context=self._context)
        if xheader:
            event.header.update(xheader)
        return event

    def emit_event(self, event, timeout=None):
        if self._debug:
            logger.debug('--> %s', event)
        if event.identity:
            parts = list(event.identity or list())
            parts.extend([b'', event.pack()])
        elif self._zmq_socket_type in (zmq.DEALER, zmq.ROUTER):
            parts = (b'', event.pack())
        else:
            parts = (event.pack(),)
        self._send(parts, timeout)

    def recv(self, timeout=None):
        parts = self._recv(timeout=timeout)
        if len(parts) > 2:
            identity = parts[0:-2]
            blob = parts[-1]
        elif len(parts) == 2:
            identity = parts[0:-1]
            blob = parts[-1]
        else:
            identity = None
            blob = parts[0]
        event = Event.unpack(get_pyzmq_frame_buffer(blob))
        event.identity = identity
        if self._debug:
            logger.debug('<-- %s', event)
        return event

    def setsockopt(self, *args):
        return self._socket.setsockopt(*args)

    @property
    def context(self):
        return self._context


text:
// eslint-disable-next-line max-len
import config from "../../../config";
import log from "../../../log";
import Manifest, {
  Adaptation,
  areSameContent,
  ISegment,
  Period,
  Representation,
} from "../../../manifest";
import objectAssign from "../../../utils/object_assign";
import { IBufferedChunk, IEndOfSegmentInfos } from "../../segment_buffers";
import {
  IBufferedHistoryEntry,
  IChunkContext,
} from "../../segment_buffers/inventory";

interface IContentContext {
  adaptation: Adaptation;
  manifest: Manifest;
  period: Period;
  representation: Representation;
}

/** Arguments for `getNeededSegments`. */
export interface IGetNeededSegmentsArguments {
  /** The content we want to load segments for */
  content: IContentContext;
  /**
   * The current playing position.
   * Important to avoid asking for segments on the same exact position, which
   * can be problematic in some browsers.
   */
  currentPlaybackTime: number;
  /**
   * This threshold defines a bitrate from which "fast-switching" is disabled.
   * For example with a fastSwitchThreshold set to `100`, segments with a
   * bitrate of `90` can be replaced. But segments with a bitrate of `100`
   * onward won't be replaced by higher quality segments.
   * Set to `undefined` to indicate that there's no threshold (anything can be
   * replaced by higher-quality segments).
   */
  fastSwitchThreshold : number | undefined;
  /** The range we want to fill with segments. */
  neededRange : { start: number; end: number };
  /** The list of segments that are already in the process of being pushed. */
  segmentsBeingPushed : IEndOfSegmentInfos[];
  /**
   * Information on the segments already in the buffer, in chronological order.
   *
   * The data for the whole buffer is not necessary, as only data around the
   * current range will be looked at.
   * It is important to include segments close to - though not in - that range
   * (let's say around 5 seconds) however to avoid some segments being
   * re-requested.
   */
  bufferedSegments : IBufferedChunk[];

  /**
   * maxBufferSize is the maximum memory in kilobytes that the buffer should take
   */
  maxBufferSize: number;

  getBufferedHistory : (context : IChunkContext) => IBufferedHistoryEntry[];
}

interface INeededSegments {
  /** Segments that should be loaded right now, by chronological order. */
  segmentsToLoad: ISegment[];
  /**
   * Segments that should be loaded, but not right now, due to some other
   * constraints, such as memory limitations.
   */
  segmentsOnHold : ISegment[];
  /**
   * If `true` the buffer is currently full according to the given limits.
   * Memory should be freed if possible, for example by cleaning the buffers.
   */
  isBufferFull: boolean;
}
/**
 * Return the list of segments that can currently be downloaded to fill holes
 * in the buffer in the given range, including already-pushed segments currently
 * incomplete in the buffer.
 * This list might also include already-loaded segments in a higher bitrate,
 * according to the given configuration.
 * Excludes segment that are already being pushed.
 * @param {Object} args
 * @returns {Array.<Object>}
 */
export default function getNeededSegments({
  bufferedSegments,
  content,
  currentPlaybackTime,
  fastSwitchThreshold,
  getBufferedHistory,
  neededRange,
  segmentsBeingPushed,
  maxBufferSize,
} : IGetNeededSegmentsArguments) : INeededSegments {
  const { adaptation, representation } = content;
  let availableBufferSize = getAvailableBufferSize(bufferedSegments,
                                                   segmentsBeingPushed,
                                                   maxBufferSize);

  const availableSegmentsForRange = representation.index
    .getSegments(neededRange.start, neededRange.end - neededRange.start);

  // Remove from `bufferedSegments` any segments we would prefer to replace:
  //   - segments in the wrong track / bad quality
  //   - garbage-collected segments
  const segmentsToKeep = bufferedSegments
    .filter((bufferedSegment) => !shouldContentBeReplaced(bufferedSegment.infos,
                                                          content,
                                                          currentPlaybackTime,
                                                          fastSwitchThreshold))
    .filter((currentSeg, i, consideredSegments) => {
      const prevSeg = i === 0 ? null :
                                consideredSegments[i - 1];
      const nextSeg = i >= consideredSegments.length - 1 ? null :
                                                           consideredSegments[i + 1];

      let lazySegmentHistory : IBufferedHistoryEntry[] | null = null;
      if (doesStartSeemGarbageCollected(currentSeg, prevSeg, neededRange.start)) {
        lazySegmentHistory = getBufferedHistory(currentSeg.infos);
        if (shouldReloadSegmentGCedAtTheStart(lazySegmentHistory,
                                              currentSeg.bufferedStart)) {
          return false;
        }
        log.debug("Stream: skipping segment gc-ed at the start",
                  currentSeg.start,
                  currentSeg.bufferedStart);
      }
      if (doesEndSeemGarbageCollected(currentSeg, nextSeg, neededRange.end)) {
        lazySegmentHistory = lazySegmentHistory ?? getBufferedHistory(currentSeg.infos);
        if (shouldReloadSegmentGCedAtTheEnd(lazySegmentHistory,
                                            currentSeg.bufferedEnd)) {
          return false;
        }
        log.debug("Stream: skipping segment gc-ed at the end",
                  currentSeg.end,
                  currentSeg.bufferedEnd);
      }
      return true;
    });
  const { MINIMUM_SEGMENT_SIZE,
          MIN_BUFFER_AHEAD } = config.getCurrent();
  let shouldStopLoadingSegments = false;
  /**
   * Epsilon compensating for rounding errors when comparing the start and end
   * time of multiple segments.
   */
  const ROUNDING_ERROR = Math.min(1 / 60, MINIMUM_SEGMENT_SIZE);
  let isBufferFull = false;
  const segmentsOnHold : ISegment[] = [];
  const segmentsToLoad = availableSegmentsForRange.filter(segment => {
    const contentObject = objectAssign({ segment }, content);

    // First, check that the segment is not already being pushed
    if (segmentsBeingPushed.length > 0) {
      const isAlreadyBeingPushed = segmentsBeingPushed
        .some((pendingSegment) => areSameContent(contentObject, pendingSegment));
      if (isAlreadyBeingPushed) {
        return false;
      }
    }

    const { duration, time, end } = segment;
    if (segment.isInit) {
      return true; // never skip initialization segments
    }
    if (shouldStopLoadingSegments) {
      segmentsOnHold.push(segment);
      return false;
    }
    if (segment.complete && duration < MINIMUM_SEGMENT_SIZE) {
      return false; // too small, don't download
    }

    // Check if the same segment from another Representation is not already
    // being pushed.
    if (segmentsBeingPushed.length > 0) {
      const waitForPushedSegment = segmentsBeingPushed.some((pendingSegment) => {
        if (pendingSegment.period.id !== content.period.id ||
            pendingSegment.adaptation.id !== content.adaptation.id)
        {
          return false;
        }
        const { segment: oldSegment } = pendingSegment;
        if ((oldSegment.time - ROUNDING_ERROR) > time) {
          return false;
        }
        if ((oldSegment.end + ROUNDING_ERROR) < end) {
          return false;
        }
        return !shouldContentBeReplaced(pendingSegment,
                                        contentObject,
                                        currentPlaybackTime,
                                        fastSwitchThreshold);
      });
      if (waitForPushedSegment) {
        return false;
      }
    }

    // check if the segment is already downloaded
    for (let i = 0; i < segmentsToKeep.length; i++) {
      const completeSeg = segmentsToKeep[i];
      const areFromSamePeriod = completeSeg.infos.period.id === content.period.id;
      // Check if content are from same period, as there can't be overlapping
      // periods, we should consider a segment as already downloaded if
      // it is from same period (but can be from different adaptation or
      // representation)
      if (areFromSamePeriod) {
        const completeSegInfos = completeSeg.infos.segment;
        if (time - completeSegInfos.time > -ROUNDING_ERROR &&
            completeSegInfos.end - end > -ROUNDING_ERROR)
        {
          return false; // already downloaded
        }
      }
    }

    const estimatedSegmentSize = (duration * content.representation.bitrate); // in bits
    if (availableBufferSize - estimatedSegmentSize < 0) {
      isBufferFull = true;
      if (time > neededRange.start + MIN_BUFFER_AHEAD) {
        shouldStopLoadingSegments = true;
        segmentsOnHold.push(segment);
        return false;
      }
    }

    // check if the browser is not just garbage collecting it
    const segmentHistory = getBufferedHistory(contentObject);
    if (segmentHistory.length > 1) {
      const lastTimeItWasPushed = segmentHistory[segmentHistory.length - 1];
      const beforeLastTimeItWasPushed = segmentHistory[segmentHistory.length - 2];
      if (lastTimeItWasPushed.buffered === null &&
          beforeLastTimeItWasPushed.buffered === null
      ) {
        log.warn("Stream: Segment GCed multiple times in a row, ignoring it.",
                 "If this happens a lot and lead to unpleasant experience, please " +
                 " check your device's available memory. If it's low when this message " +
                 "is emitted, you might want to update the RxPlayer's settings (" +
                 "`maxBufferAhead`, `maxVideoBufferSize` etc.) so less memory is used " +
                 "by regular media data buffering." +
                 adaptation.type,
                 representation.id,
                 segment.time);
        return false;
      }
    }

    // check if there is an hole in place of the segment currently
    for (let i = 0; i < segmentsToKeep.length; i++) {
      const completeSeg = segmentsToKeep[i];

      // For the first already-loaded segment, take the first one ending after
      // this one' s start
      if ((completeSeg.end + ROUNDING_ERROR) > time) {
        const shouldLoad = completeSeg.start > time + ROUNDING_ERROR ||
                           getLastContiguousSegment(segmentsToKeep, i).end <
                             end - ROUNDING_ERROR;
        if (shouldLoad) {
          availableBufferSize -= estimatedSegmentSize;
        }
        return shouldLoad;
      }
    }
    availableBufferSize -= estimatedSegmentSize;
    return true;
  });
  return { segmentsToLoad, segmentsOnHold, isBufferFull };

}
/**
 * Compute the estimated available buffer size in memory in kilobytes
 * @param bufferedSegments
 * @param segmentsBeingPushed
 * @param maxVideoBufferSize
 * @returns availableBufferSize in bits
 */
function getAvailableBufferSize(
  bufferedSegments: IBufferedChunk[],
  segmentsBeingPushed: IEndOfSegmentInfos[],
  maxVideoBufferSize: number
) : number {
  let availableBufferSize = maxVideoBufferSize * 8000; // in bits
  availableBufferSize -= segmentsBeingPushed.reduce((size, segment) => {
    const { bitrate } = segment.representation;
    // Not taking into account the fact that the segment
    // can still be generated and the duration not fully exact
    const { duration } = segment.segment;
    return size + (bitrate * duration);
  }, 0);
  return bufferedSegments.reduce((size, chunk) => {
    if (chunk.chunkSize !== undefined) {
      return size - (chunk.chunkSize * 8); // in bits
    } else {
      return size;
    }

  } , availableBufferSize);
}

/**
 * From the given array of buffered chunks (`bufferedSegments`) returns the last
 * buffered chunk contiguous with the one at the `startIndex` index given.
 * @param {Array.<Object>}
 * @param {number} startIndex
 * @returns {Object}
 */
function getLastContiguousSegment(
  bufferedSegments : IBufferedChunk[],
  startIndex : number
) : IBufferedChunk {
  let j = startIndex + 1;
  const { MINIMUM_SEGMENT_SIZE } = config.getCurrent();
  /**
   * Epsilon compensating for rounding errors when comparing the start and end
   * time of multiple segments.
   */
  const ROUNDING_ERROR = Math.min(1 / 60, MINIMUM_SEGMENT_SIZE);
  // go through all contiguous segments and take the last one
  while (j < bufferedSegments.length - 1 &&
         (bufferedSegments[j - 1].end + ROUNDING_ERROR) >
          bufferedSegments[j].start)
  {
    j++;
  }
  j--; // index of last contiguous segment
  return bufferedSegments[j];
}

/**
 * Returns `true` if segments linked to the given `oldContent` currently present
 * in the buffer should be replaced by segments coming from `currentContent`.
 * @param {Object} oldContent
 * @param {Object} currentContent
 * @param {number} currentPlaybackTime
 * @param {number} [fastSwitchThreshold]
 * @returns {boolean}
 */
function shouldContentBeReplaced(
  oldContent : IEndOfSegmentInfos,
  currentContent : { adaptation : Adaptation;
                     period : Period;
                     representation : Representation; },
  currentPlaybackTime: number,
  fastSwitchThreshold? : number
) : boolean {
  const { CONTENT_REPLACEMENT_PADDING } = config.getCurrent();
  if (oldContent.period.id !== currentContent.period.id) {
    return false; // keep segments from another Period by default.
  }

  const { segment } = oldContent;
  if (segment.time < (currentPlaybackTime + CONTENT_REPLACEMENT_PADDING)) {
    return false;
  }

  if (oldContent.adaptation.id !== currentContent.adaptation.id) {
    return true; // replace segments from another Adaptation
  }

  return canFastSwitch(oldContent.representation,
                       currentContent.representation,
                       fastSwitchThreshold);
}

/**
 * Returns `true` if segments from the new Representation can replace
 * previously-loaded segments from the old Representation given.
 *
 * This behavior is called "fast-switching".
 * @param {Object} oldSegmentRepresentation
 * @param {Object} newSegmentRepresentation
 * @param {number|undefined} fastSwitchThreshold
 * @returns {boolean}
 */
function canFastSwitch(
  oldSegmentRepresentation : Representation,
  newSegmentRepresentation : Representation,
  fastSwitchThreshold : number | undefined
) : boolean {
  const oldContentBitrate = oldSegmentRepresentation.bitrate;
  const { BITRATE_REBUFFERING_RATIO } = config.getCurrent();
  if (fastSwitchThreshold === undefined) {
    // only re-load comparatively-poor bitrates for the same Adaptation.
    const bitrateCeil = oldContentBitrate * BITRATE_REBUFFERING_RATIO;
    return newSegmentRepresentation.bitrate > bitrateCeil;
  }
  return oldContentBitrate < fastSwitchThreshold &&
         newSegmentRepresentation.bitrate > oldContentBitrate;
}

/**
 * From buffered segment information, return `true` if the given `currentSeg`
 * might have been garbage collected at the start.
 * Return `false` if the segment is complete at least from `maximumStartTime`.
 * @param {Object} currentSeg - The segment information for the segment in
 * question.
 * @param {Object|null} prevSeg - The segment information for the previous
 * buffered segment, if one (`null` if none).
 * @param {number} maximumStartTime - Only consider the data after that time.
 * If `currentSeg` has only been garbage collected for some data which is before
 * that time, we will return `false`.
 */
function doesStartSeemGarbageCollected(
  currentSeg : IBufferedChunk,
  prevSeg : IBufferedChunk | null,
  maximumStartTime : number
) {
  const { MAX_TIME_MISSING_FROM_COMPLETE_SEGMENT } = config.getCurrent();
  if (currentSeg.bufferedStart === undefined)  {
    log.warn("Stream: Start of a segment unknown. " +
             "Assuming it is garbage collected by default.",
             currentSeg.start);
    return true;
  }

  if (prevSeg !== null && prevSeg.bufferedEnd !== undefined &&
      (currentSeg.bufferedStart - prevSeg.bufferedEnd < 0.1))
  {
    return false;
  }

  if (maximumStartTime < currentSeg.bufferedStart &&
      currentSeg.bufferedStart - currentSeg.start >
        MAX_TIME_MISSING_FROM_COMPLETE_SEGMENT)
  {
    log.info("Stream: The start of the wanted segment has been garbage collected",
             currentSeg.start,
             currentSeg.bufferedStart);
    return true;
  }

  return false;
}

/**
 * From buffered segment information, return `true` if the given `currentSeg`
 * might have been garbage collected at the end.
 * Return `false` if the segment is complete at least until `minimumEndTime`.
 * @param {Object} currentSeg - The segment information for the segment in
 * question.
 * @param {Object|null} nextSeg - The segment information for the next buffered
 * segment, if one (`null` if none).
 * @param {number} minimumEndTime - Only consider the data before that time.
 * If `currentSeg` has only been garbage collected for some data which is after
 * that time, we will return `false`.
 */
function doesEndSeemGarbageCollected(
  currentSeg : IBufferedChunk,
  nextSeg : IBufferedChunk | null,
  minimumEndTime : number
) {
  const { MAX_TIME_MISSING_FROM_COMPLETE_SEGMENT } = config.getCurrent();
  if (currentSeg.bufferedEnd === undefined)  {
    log.warn("Stream: End of a segment unknown. " +
             "Assuming it is garbage collected by default.",
             currentSeg.end);
    return true;
  }

  if (nextSeg !== null && nextSeg.bufferedStart !== undefined &&
      (nextSeg.bufferedStart - currentSeg.bufferedEnd < 0.1))
  {
    return false;
  }

  if (minimumEndTime > currentSeg.bufferedEnd &&
      currentSeg.end - currentSeg.bufferedEnd > MAX_TIME_MISSING_FROM_COMPLETE_SEGMENT)
  {
    log.info("Stream: The end of the wanted segment has been garbage collected",
             currentSeg.start,
             currentSeg.bufferedStart);
    return true;
  }

  return false;
}

/**
 * Returns `true` if a segment that has been garbage-collected at the start
 * might profit from being re-loaded.
 *
 * Returns `false` if we have a high chance of staying in the same situation
 * after re-loading the segment.
 *
 * This function takes in argument the entries of a SegmentBuffer's history
 * related to the corresponding segment and check if the segment appeared
 * garbage-collected at the start directly after the last few times it was
 * pushed, indicating that the issue might be sourced at a browser issue instead
 * of classical garbage collection.
 *
 * @param {Array.<Object>} segmentEntries
 * @param {number|undefined} currentBufferedStart
 * @returns {boolean}
 */
function shouldReloadSegmentGCedAtTheStart(
  segmentEntries : IBufferedHistoryEntry[],
  currentBufferedStart : number | undefined
) : boolean {
  if (segmentEntries.length < 2) {
    return true;
  }

  const lastEntry = segmentEntries[segmentEntries.length - 1];
  const lastBufferedStart = lastEntry.buffered?.start;

  // If the current segment's buffered start is much higher than what it
  // initially was when we pushed it, the segment has a very high chance of
  // having been truly garbage-collected.
  if (currentBufferedStart !== undefined &&
      lastBufferedStart !== undefined &&
      currentBufferedStart - lastBufferedStart > 0.05)
  {
    return true;
  }

  const prevEntry = segmentEntries[segmentEntries.length - 2];
  const prevBufferedStart = prevEntry.buffered?.start;

  if (prevBufferedStart === undefined || lastBufferedStart === undefined) {
    return true;
  }

  // Compare `bufferedStart` from the last time this segment was pushed
  // (`entry.bufferedStart`) to the previous time it was pushed
  // (`prevSegEntry.bufferedStart`).
  //
  // If in both cases, we notice that their initial `bufferedStart` are close,
  // it means that in recent history the same segment has been accused to be
  // garbage collected two times at roughly the same positions just after being
  // pushed.
  // This is very unlikely and might be linked to either a content or browser
  // issue. In that case, don't try to reload.
  return Math.abs(prevBufferedStart - lastBufferedStart) > 0.01;
}

/**
 * Returns `true` if a segment that has been garbage-collected at the end
 * might profit from being re-loaded.
 *
 * Returns `false` if we have a high chance of staying in the same situation
 * after re-loading the segment.
 *
 * This function takes in argument the entries of a SegmentBuffer's history
 * related to the corresponding segment and check if the segment appeared
 * garbage-collected at the end directly after the last few times it was
 * pushed, indicating that the issue might be sourced at a browser issue instead
 * of classical garbage collection.
 *
 * @param {Array.<Object>} segmentEntries
 * @param {number|undefined} currentBufferedEnd
 * @returns {boolean}
 */
function shouldReloadSegmentGCedAtTheEnd(
  segmentEntries : IBufferedHistoryEntry[],
  currentBufferedEnd : number | undefined
) : boolean {
  if (segmentEntries.length < 2) {
    return true;
  }
  const lastEntry = segmentEntries[segmentEntries.length - 1];
  const lastBufferedEnd = lastEntry.buffered?.end;

  // If the current segment's buffered end is much lower than what it
  // initially was when we pushed it, the segment has a very high chance of
  // having been truly garbage-collected.
  if (currentBufferedEnd !== undefined &&
      lastBufferedEnd !== undefined &&
      lastBufferedEnd - currentBufferedEnd > 0.05)
  {
    return true;
  }

  const prevEntry = segmentEntries[segmentEntries.length - 2];
  const prevBufferedEnd = prevEntry.buffered?.end;

  if (prevBufferedEnd === undefined || lastBufferedEnd === undefined) {
    return true;
  }

  // Compare `bufferedEnd` from the last time this segment was pushed
  // (`entry.bufferedEnd`) to the previous time it was pushed
  // (`prevSegEntry.bufferedEnd`).
  //
  // If in both cases, we notice that their initial `bufferedEnd` are close,
  // it means that in recent history the same segment has been accused to be
  // garbage collected two times at roughly the same positions just after being
  // pushed.
  // This is very unlikely and might be linked to either a content or browser
  // issue. In that case, don't try to reload.
  return Math.abs(prevBufferedEnd - lastBufferedEnd) > 0.01;
}

redpajama_set_name: RedPajamaGithub


text:
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.4.2_04" class="java.beans.XMLDecoder">
    <object class="org.jdesktop.lg3d.displayserver.LgConfig">
        <void property="x11IntegrationEnabled">
            <boolean>false</boolean>
        </void>
        <void property="clientServer">
            <boolean>false</boolean>
        </void>
        <void property="foundationWinSys">
            <string>org.jdesktop.lg3d.displayserver.fws.awt.WinSysAWT</string>
        </void>
    </object>
</java>


text:
package com.dell.doradus.search.query;

public class AllQuery implements Query {

	@Override
	public String toString() {
		return "True";
	}
}


text:
package com.jdml.cucumber.js.execution;

import com.intellij.execution.ExecutionException;
import com.intellij.execution.Executor;
import com.intellij.execution.configurations.*;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.openapi.options.SettingsEditor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.util.net.NetUtils;
import com.jdml.cucumber.js.execution.ui.CucumberConfigurationEditor;
import com.jetbrains.nodejs.debug.NodeJSDebuggableConfiguration;
import com.jetbrains.nodejs.debug.NodeJSFileFinder;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.IOException;

public class CucumberRunConfiguration
        extends LocatableConfigurationBase
        implements NodeJSDebuggableConfiguration
{
    private final CucumberRunConfigurationParameters parameters = new CucumberRunConfigurationParameters();

    protected CucumberRunConfiguration(Project project, ConfigurationFactory factory, String name)
    {
        super(project, factory, name);
    }

    @NotNull
    public SettingsEditor<CucumberRunConfiguration> getConfigurationEditor()
    {
        return new CucumberConfigurationEditor(getProject());
    }

    @Nullable
    public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment env)
            throws ExecutionException
    {
        return createState(env, -1);
    }

    @NotNull
    public RunProfileState createState(@NotNull ExecutionEnvironment environment, int debugPort)
        throws ExecutionException
    {
        checkConfigurationForState();
        CucumberRunSettings settings = new CucumberRunSettings.Builder()
                .setArguments(parameters.getArguments())
                .setCucumberPath(parameters.getCucumberPath())
                .setFeaturePath(parameters.getFeaturePath())
                .setDebugPort(debugPort)
                .setTags(parameters.getTags())
                .build();
        return new CucumberRunProfileState(this, settings, environment);
    }

    private void checkConfigurationForState() throws ExecutionException {
        try {
            checkConfiguration();
        }
        catch (RuntimeConfigurationError e) {
            throw new ExecutionException(e.getMessage(), e);
        }
        catch (RuntimeConfigurationException e) {
            /* ignored in other plugins, not sure why, should investigate */
        }
    }

    public void checkConfiguration()
            throws RuntimeConfigurationException
    {
        String path = this.parameters.getFeaturePath();
        if ((path == null) || (VirtualFileManager.getInstance().findFileByUrl(VfsUtilCore.pathToUrl(path)) == null)) {
            throw new RuntimeConfigurationException("Can't find file: " + path);
        }
    }

    public void writeExternal(Element element)
            throws WriteExternalException
    {
        super.writeExternal(element);
        CucumberRunConfigurationParametersSerializer.write(element, parameters);
    }

    public void readExternal(Element element)
            throws InvalidDataException
    {
        super.readExternal(element);
        CucumberRunConfigurationParametersSerializer.readInto(element, parameters);
    }

    public CucumberRunConfigurationParameters getRunnerParameters()
    {
        return this.parameters;
    }

    @Override
    public String getHost() {
        return "127.0.0.1";
    }

    @Override
    public int computeDebugPort() throws ExecutionException {
        try {
            return NetUtils.findAvailableSocketPort();
        }
        catch (IOException e) {
            throw new ExecutionException("Cannot find available port for debugging", e);
        }
    }

    @NotNull
    @Override
    public NodeJSFileFinder createFileFinder() {
        return new NodeJSFileFinder(getProject());
    }
}