nsRefPtr<MediaDecoderReader::SeekPromise>
MediaSourceReader::Seek(int64_t aTime, int64_t aIgnored /* Used only for ogg which is non-MSE */)
{
  MSE_DEBUG("Seek(aTime=%lld, aEnd=%lld, aCurrent=%lld)",
            aTime);

  MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty());
  MOZ_DIAGNOSTIC_ASSERT(mAudioPromise.IsEmpty());
  MOZ_DIAGNOSTIC_ASSERT(mVideoPromise.IsEmpty());
  nsRefPtr<SeekPromise> p = mSeekPromise.Ensure(__func__);

  if (IsShutdown()) {
    mSeekPromise.Reject(NS_ERROR_FAILURE, __func__);
    return p;
  }

  // Store pending seek target in case the track buffers don't contain
  // the desired time and we delay doing the seek.
  mPendingSeekTime = aTime;

  {
    ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
    mWaitingForSeekData = true;
    mDropAudioBeforeThreshold = false;
    mDropVideoBeforeThreshold = false;
    mTimeThreshold = 0;
  }

  AttemptSeek();
  return p;
}
nsRefPtr<MediaDecoderReader::SeekPromise>
MediaSourceReader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime,
                        int64_t aCurrentTime)
{
  MSE_DEBUG("MediaSourceReader(%p)::Seek(aTime=%lld, aStart=%lld, aEnd=%lld, aCurrent=%lld)",
            this, aTime, aStartTime, aEndTime, aCurrentTime);

  mSeekPromise.RejectIfExists(NS_OK, __func__);
  nsRefPtr<SeekPromise> p = mSeekPromise.Ensure(__func__);

  if (IsShutdown()) {
    mSeekPromise.Reject(NS_ERROR_FAILURE, __func__);
    return p;
  }

  // Store pending seek target in case the track buffers don't contain
  // the desired time and we delay doing the seek.
  mPendingSeekTime = aTime;
  mPendingStartTime = aStartTime;
  mPendingEndTime = aEndTime;
  mPendingCurrentTime = aCurrentTime;

  // Only increment the number of expected OnSeekCompleted
  // notifications if we weren't already waiting for AttemptSeek
  // to complete (and they would have been accounted for already).
  {
    ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());

    if (!mWaitingForSeekData) {
      mWaitingForSeekData = true;
      if (mAudioTrack) {
        mPendingSeeks++;
      }
      if (mVideoTrack) {
        mPendingSeeks++;
      }
    }
  }

  AttemptSeek();
  return p;
}
void ProgramData::Parse(const std::string& Source)
{
	auto MovePointerLambda = [&](Instruction::value_type x)
	{
		if (Text.back() == Instruction::Type::MovePointer)
		{
			Text.back().Value += x;

			// Remove instructions that have no effect
			if (!Text.back().Value)
				Text.pop_back();
		}
		else
		{
			Text.emplace_back(Instruction::Type::MovePointer, x);
		}
	};

	auto AdditionLambda = [&](Instruction::value_type x)
	{
		if (Text.back() == Instruction::Type::Addition)
		{
			Text.back().Value += x;

			// Remove instructions that have no effect
			if (!Text.back().Value)
				Text.pop_back();
		}
		else if (Text.back() == Instruction::Type::Reset
			&& Text.back().Value == 1
			&& Text.back().Offset == 0)
		{
			Text.pop_back();

			Text.emplace_back(Instruction::Type::Set, x);
		}
		else if (Text.back() == Instruction::Type::Set)
		{
			Text.back().Value += x;
		}
		else
		{
			Text.emplace_back(Instruction::Type::Addition, x);
		}
	};
	
	for (auto Char : Source)
	{
		switch (Char)
		{
		case '>':
			MovePointerLambda(1);
			break;
		case '<':
			MovePointerLambda(-1);
			break;
		case '+':
			AdditionLambda(1);
			break;
		case '-':
			AdditionLambda(-1);
			break;
		case '.':
			Text.emplace_back(Instruction::Type::Output);
			break;
		case ',':
			Text.emplace_back(Instruction::Type::Input);
			break;
		case '[':
			Text.emplace_back(Instruction::Type::LoopStart);
			break;
		case ']':
			Instruction* const BeginPointer = [&]
			{
				auto Iterator = std::find(std::rbegin(Text), std::rend(Text), Instruction::Type::LoopStart);
				
				if (Iterator == std::rend(Text))
					throw bf::exception::UnmatchedClose();

				return &*Iterator;
			}();
			Instruction* const EndPointer = std::data(Text) + std::size(Text);

			if (DropEmptyLoop(BeginPointer, EndPointer))
				break;
			if (AttemptReset(BeginPointer, EndPointer))
				break;
			if (AttemptSeek(BeginPointer, EndPointer))
				break;
			if (AttemptMultiplication(BeginPointer, EndPointer))
				break;

			Text.emplace_back(Instruction::Type::LoopEnd);
			break;
		}
	}
}