text:
namespace audio {
namespace {

// Used to test whether the output AudioBuses have had all their values set to
// something finite.
constexpr float kInvalidAudioSample = std::numeric_limits<float>::infinity();

// The tones the source should generate into the left and right channels.
constexpr double kLeftChannelFrequency = 500.0;
constexpr double kRightChannelFrequency = 1200.0;
constexpr double kSourceVolume = 0.5;

// The duration of the audio that flows through the SnooperNode for each test.
constexpr base::TimeDelta kTestDuration = base::Seconds(10);

// The amount of time in the future where the inbound audio is being recorded.
// This simulates an audio output stream that has rendered audio that is
// scheduled to be played out in the near future.
constexpr base::TimeDelta kInputAdvanceTime = base::Milliseconds(2);

// Command-line switch to request dumping the recorded output to a WAV file for
// analyzing the recorded output from one of the tests.
constexpr base::StringPiece kDumpAsWavSwitch = "dump-as-wav";

// Test parameters.
struct InputAndOutputParams {
  media::AudioParameters input;
  media::AudioParameters output;
};

// Helper so that gtest can produce useful logging of the test parameters.
std::ostream& operator<<(std::ostream& out,
                         const InputAndOutputParams& test_params) {
  return out << "{input=" << test_params.input.AsHumanReadableString()
             << ", output=" << test_params.output.AsHumanReadableString()
             << "}";
}

class SnooperNodeTest : public testing::TestWithParam<InputAndOutputParams> {
 public:
  SnooperNodeTest() = default;
  ~SnooperNodeTest() override = default;

  const media::AudioParameters& input_params() const {
    return GetParam().input;
  }
  const media::AudioParameters& output_params() const {
    return GetParam().output;
  }
  base::TimeDelta output_delay() const { return output_delay_; }
  double max_relative_error() const { return max_relative_error_; }

  base::TestMockTimeTaskRunner* task_runner() const {
    return task_runner_.get();
  }
  FakeLoopbackGroupMember* group_member() { return &*group_member_; }
  SnooperNode* node() { return &*node_; }
  FakeConsumer* consumer() { return &*consumer_; }

  void SetUp() override {
    // Determine the amount of time in the past from which outbound audio should
    // be rendered. Use 20 ms as a reasonable baseline--the same as the initial
    // setting in audio::LoopbackStream--which will work for almost all normal
    // use cases.
    constexpr base::TimeDelta kBaselineOutputDelay = base::Milliseconds(20);
    output_delay_ = kBaselineOutputDelay;

    // Increase the output delay in special cases...
    if (input_params().sample_rate() < 32000) {
      // At the lower input sample rates (e.g., 8 kHz), prebufferring inside
      // SnooperNode's resampler becomes an issue: It uses a fixed size buffer
      // of 128 samples, which equates to a much longer duration of audio at the
      // lower sampling rates. With more buffering involved, the output delay
      // must be increased to avoid underruns.
      output_delay_ *= 2;
    } else if (input_params().GetBufferDuration() >
               output_params().GetBufferDuration()) {
      // For the HandlesBackwardsInput() test, the input goes backward by a full
      // buffer. If the duration of an input buffer is larger than an output
      // buffer, this could cause a brief moment of underrun (which is WAI!).
      // Rather than write lots of extra test code around such a specific
      // scenario, just fudge the delay up a little such that the underrun
      // cannot occur.
      output_delay_ += input_params().GetBufferDuration();
    }

    // Determine the maximum allowable error when measuring expected amplitudes.
    // This varies with the sampling rate because the loss of resolution at the
    // lower sampling rates can introduce error in the "amplitude-sensing
    // logic." Higher frequencies in the audio signal are especially vulnerable
    // to the error introduced by using low sampling rates.
    constexpr double kHighResAllowedError = 0.02;  // 2% at 48 kHz
    constexpr double kHighResSampleRate = 48000;
    constexpr double kLowResAllowedError = 0.10;  // 10% at 8 kHz
    constexpr double kLowResSampleRate = 8000;
    const int the_lower_sample_rate =
        std::min(input_params().sample_rate(), output_params().sample_rate());
    const double t = (the_lower_sample_rate - kHighResSampleRate) /
                     (kLowResSampleRate - kHighResSampleRate);
    max_relative_error_ =
        kHighResAllowedError + t * (kLowResAllowedError - kHighResAllowedError);

    // Initialize a test clock and task runner. The starting TimeTicks value is
    // "huge" to ensure time calculations are being tested for overflow cases.
    task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>(
        base::Time(), base::TimeTicks() + base::Microseconds(INT64_C(1) << 62));
  }

  void TearDown() override {
    // If the "dump-as-wav" command-line switch is present, dump whatever has
    // been recorded in the consumer.
    const base::FilePath path =
        base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
            kDumpAsWavSwitch);
    if (!path.empty()) {
      if (consumer_) {
        consumer_->SaveToFile(path);
      } else {
        LOG(ERROR) << "No consumer: ignoring --" << kDumpAsWavSwitch;
      }
    }
  }

  // Selects which frequency to return for each channel based on the input and
  // output channel layout.
  enum WhichFlow : int8_t {
    FOR_INPUT,
    FOR_SWAPPED_INPUT,
    FOR_OUTPUT,
    FOR_SWAPPED_OUTPUT,
  };

  double GetLeftChannelFrequency(WhichFlow which) const {
    switch (which) {
      case FOR_INPUT:
      case FOR_OUTPUT:
        return kLeftChannelFrequency;
      case FOR_SWAPPED_INPUT:
      case FOR_SWAPPED_OUTPUT:
        return kRightChannelFrequency;
    }
  }

  double GetRightChannelFrequency(WhichFlow which) const {
    switch (which) {
      // If the test parameters call for stereo→mono channel down-mixing, use
      // the left channel frequency again for the right channel input. Down-
      // mixing is tested elsewhere.
      case FOR_INPUT:
        return (output_params().channels() == 1 ? kLeftChannelFrequency
                                                : kRightChannelFrequency);
      case FOR_SWAPPED_INPUT:
        return (output_params().channels() == 1 ? kRightChannelFrequency
                                                : kLeftChannelFrequency);

      // If the input was monaural, the output's right channel should contain
      // the input's "left" channel frequency.
      case FOR_OUTPUT:
        return (input_params().channels() == 1 ? kLeftChannelFrequency
                                               : kRightChannelFrequency);
      case FOR_SWAPPED_OUTPUT:
        return (input_params().channels() == 1 ? kRightChannelFrequency
                                               : kLeftChannelFrequency);
    }
  }

  void CreateNewPipeline() {
    group_member_.emplace(input_params());
    group_member_->SetChannelTone(0, GetLeftChannelFrequency(FOR_INPUT));
    if (input_params().channels() > 1) {
      group_member_->SetChannelTone(1, GetRightChannelFrequency(FOR_INPUT));
    }
    group_member_->SetVolume(kSourceVolume);

    node_.emplace(input_params(), output_params());
    group_member_->StartSnooping(node());

    consumer_.emplace(output_params().channels(),
                      output_params().sample_rate());
  }

  // Have the SnooperNode render more output data and store it in the consumer
  // for later analysis.
  void RenderAndConsume(base::TimeTicks output_time) {
    // Assign invalid sample values to the AudioBus. Then, after the Render()
    // call, confirm that every sample was overwritten in the output AudioBus.
    const auto bus = media::AudioBus::Create(output_params());
    for (int ch = 0; ch < bus->channels(); ++ch) {
      std::fill_n(bus->channel(ch), bus->frames(), kInvalidAudioSample);
    }

    // If the SnooperNode provides a suggestion, check that |output_time| is
    // okay. Otherwise, Render() will be producing zero-fill gaps as the end of
    // |bus|. Don't do this check if there is already a test failure, and this
    // would just keep spamming the test output.
    if (!HasFailure()) {
      const absl::optional<base::TimeTicks> suggestion =
          node_->SuggestLatestRenderTime(bus->frames());
      if (suggestion) {
        EXPECT_LE(output_time, *suggestion)
            << "at frame=" << consumer_->GetRecordedFrameCount();
      }
    }

    node_->Render(output_time, bus.get());

    for (int ch = 0; ch < bus->channels(); ++ch) {
      EXPECT_FALSE(
          std::any_of(bus->channel(ch), bus->channel(ch) + bus->frames(),
                      [](float x) { return x == kInvalidAudioSample; }))
          << " at output_time=" << output_time << ", ch=" << ch;
    }
    consumer_->Consume(*bus);
  }

  // Post delayed tasks to schedule normal, uninterrupted input with the default
  // kInputAdvanceTime delay.
  void ScheduleDefaultInputTasks(double skew = 1.0) {
    const base::TimeTicks start_time = task_runner_->NowTicks();
    const base::TimeTicks end_time = start_time + kTestDuration;
    const double time_step = skew / input_params().sample_rate();
    for (int position = 0;; position += input_params().frames_per_buffer()) {
      const base::TimeTicks task_time =
          start_time + base::Seconds(position * time_step);
      if (task_time >= end_time) {
        break;
      }
      const base::TimeTicks reference_time = task_time + kInputAdvanceTime;
      task_runner_->PostDelayedTask(
          FROM_HERE,
          base::BindOnce(&FakeLoopbackGroupMember::RenderMoreAudio,
                         base::Unretained(group_member()), reference_time),
          task_time - start_time);
    }
  }

  // Post delayed tasks to schedule normal, uninterrupted output rendering to
  // occur at the default kCaptureDelay.
  void ScheduleDefaultRenderTasks(double skew = 1.0) {
    const base::TimeTicks start_time = task_runner_->NowTicks();
    const base::TimeTicks end_time = start_time + kTestDuration;
    const double time_step = skew / output_params().sample_rate();
    for (int position = 0;; position += output_params().frames_per_buffer()) {
      const base::TimeTicks task_time =
          start_time + base::Seconds(position * time_step);
      if (task_time >= end_time) {
        break;
      }
      const base::TimeTicks reference_time = task_time - output_delay();
      task_runner_->PostDelayedTask(
          FROM_HERE,
          base::BindOnce(&SnooperNodeTest::RenderAndConsume,
                         base::Unretained(this), reference_time),
          task_time - start_time);
    }
  }

  void RunAllPendingTasks() { task_runner_->FastForwardUntilNoTasksRemain(); }

 private:
  scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;

  // A suitable output delay to use for rendering audio from the pipeline. See
  // comments in SetUp() for further details.
  base::TimeDelta output_delay_;

  // The maximum allowable error relative to an expected amplitude.
  double max_relative_error_ = 0.0;

  // The pipeline from source to consumer.
  absl::optional<FakeLoopbackGroupMember> group_member_;
  absl::optional<SnooperNode> node_;
  absl::optional<FakeConsumer> consumer_;
};

// The skew test here is generating 10 seconds of audio per iteration, with
// 5*5=25 iterations. That's 250 seconds of audio being generated to check for
// skew-related issues. That's a lot of processing power needed! Thus, only
// enable this test on optimized, non-debug builds, where it will run in a
// reasonable amount of time. http://crbug.com/842428
#ifdef NDEBUG
#define MAYBE_ContinuousAudioFlowAdaptsToSkew ContinuousAudioFlowAdaptsToSkew
#else
#define MAYBE_ContinuousAudioFlowAdaptsToSkew \
  DISABLED_ContinuousAudioFlowAdaptsToSkew
#endif
// Tests that the internal time-stretching logic can handle various combinations
// of input and output skews.
TEST_P(SnooperNodeTest, MAYBE_ContinuousAudioFlowAdaptsToSkew) {
  // Note: A skew of 0.999 or 1.001 is very extreme. This is like saying the
  // clocks drift 1 ms for every second that goes by. If the implementation can
  // handle that, it's very likely to do a perfect job in-the-wild.
  for (double input_skew = 0.999; input_skew <= 1.001; input_skew += 0.0005) {
    for (double output_skew = 0.999; output_skew <= 1.001;
         output_skew += 0.0005) {
      SCOPED_TRACE(testing::Message() << "input_skew=" << input_skew
                                      << ", output_skew=" << output_skew);

      CreateNewPipeline();
      ScheduleDefaultInputTasks(input_skew);
      ScheduleDefaultRenderTasks(output_skew);
      RunAllPendingTasks();

      // All rendering for points-in-time before the audio from the source was
      // first recorded should be silence.
      const double expected_end_of_silence_position =
          ((input_skew * kInputAdvanceTime.InSecondsF()) +
           (output_skew * output_delay().InSecondsF())) *
          output_params().sample_rate();
      const double frames_in_one_millisecond =
          output_params().sample_rate() /
          double{base::Time::kMillisecondsPerSecond};
      EXPECT_NEAR(expected_end_of_silence_position,
                  consumer()->FindEndOfSilence(0, 0),
                  frames_in_one_millisecond);
      if (output_params().channels() > 1) {
        EXPECT_NEAR(expected_end_of_silence_position,
                    consumer()->FindEndOfSilence(1, 0),
                    frames_in_one_millisecond);
      }

      // Analyze the recording in several places for the expected tones.
      constexpr int kNumToneChecks = 16;
      for (int i = 1; i <= kNumToneChecks; ++i) {
        const int end_frame =
            consumer()->GetRecordedFrameCount() * i / kNumToneChecks;
        SCOPED_TRACE(testing::Message() << "end_frame=" << end_frame);
        EXPECT_NEAR(kSourceVolume,
                    consumer()->ComputeAmplitudeAt(
                        0, GetLeftChannelFrequency(FOR_OUTPUT), end_frame),
                    kSourceVolume * max_relative_error());
        if (output_params().channels() > 1) {
          EXPECT_NEAR(kSourceVolume,
                      consumer()->ComputeAmplitudeAt(
                          1, GetRightChannelFrequency(FOR_OUTPUT), end_frame),
                      kSourceVolume * max_relative_error());
        }
      }

      if (HasFailure()) {
        return;
      }
    }
  }
}

// Tests that gaps in the input are detected, are handled by introducing
// zero-fill gaps in the output, and don't throw-off the timing/synchronization
// between input and output.
TEST_P(SnooperNodeTest, HandlesMissingInput) {
  CreateNewPipeline();

  // Schedule all input tasks, with drops to occur once per second for 1/4
  // second duration.
  const base::TimeTicks start_time = task_runner()->NowTicks();
  const base::TimeTicks end_time = start_time + kTestDuration;
  const double time_step = 1.0 / input_params().sample_rate();
  const int input_frames_in_one_second = input_params().sample_rate();
  // Drop duration: 1/4 second in terms of frames, aligned to frame buffer size.
  const int drop_duration =
      ((input_frames_in_one_second / 4) / input_params().frames_per_buffer()) *
      input_params().frames_per_buffer();
  int next_drop_position = input_frames_in_one_second;
  for (int position = 0;; position += input_params().frames_per_buffer()) {
    if (position >= next_drop_position) {
      position += drop_duration;
      next_drop_position += input_frames_in_one_second;
    }
    const base::TimeTicks task_time =
        start_time + base::Seconds(position * time_step);
    if (task_time >= end_time) {
      break;
    }
    const base::TimeTicks reference_time = task_time + kInputAdvanceTime;
    task_runner()->PostDelayedTask(
        FROM_HERE,
        base::BindOnce(&FakeLoopbackGroupMember::RenderMoreAudio,
                       base::Unretained(group_member()), reference_time),
        task_time - start_time);
  }

  ScheduleDefaultRenderTasks();
  RunAllPendingTasks();

  // Check that there is silence in the drop positions, and that tones are
  // present around the silent sections. The ranges are adjusted to be 20 ms
  // away from the exact begin/end positions to account for a reasonable amount
  // of variance in due to the input buffer intervals.
  const int output_frames_in_one_second = output_params().sample_rate();
  const int output_frames_in_a_quarter_second = output_frames_in_one_second / 4;
  const int output_frames_in_20_milliseconds =
      output_frames_in_one_second * 20 / base::Time::kMillisecondsPerSecond;
  int output_silence_position =
      ((kInputAdvanceTime + output_delay()).InSecondsF() + 1.0) *
      output_params().sample_rate();
  for (int gap = 0; gap < 5; ++gap) {
    SCOPED_TRACE(testing::Message() << "gap=" << gap);

    // Just before the drop, there should be a tone.
    const int position_a_little_before_silence_begins =
        output_silence_position - output_frames_in_20_milliseconds;
    EXPECT_NEAR(
        kSourceVolume,
        consumer()->ComputeAmplitudeAt(0, GetLeftChannelFrequency(FOR_OUTPUT),
                                       position_a_little_before_silence_begins),
        kSourceVolume * max_relative_error());
    if (output_params().channels() > 1) {
      EXPECT_NEAR(kSourceVolume,
                  consumer()->ComputeAmplitudeAt(
                      1, GetRightChannelFrequency(FOR_OUTPUT),
                      position_a_little_before_silence_begins),
                  kSourceVolume * max_relative_error());
    }

    // There should be silence during the drop.
    const int position_a_little_after_silence_begins =
        output_silence_position + output_frames_in_20_milliseconds;
    const int position_a_little_before_silence_ends =
        position_a_little_after_silence_begins +
        output_frames_in_a_quarter_second -
        2 * output_frames_in_20_milliseconds;
    EXPECT_TRUE(
        consumer()->IsSilentInRange(0, position_a_little_after_silence_begins,
                                    position_a_little_before_silence_ends));

    // Finally, the tone should be back after the drop.
    const int position_a_little_after_silence_ends =
        position_a_little_before_silence_ends +
        2 * output_frames_in_20_milliseconds;
    EXPECT_NEAR(
        kSourceVolume,
        consumer()->ComputeAmplitudeAt(0, GetLeftChannelFrequency(FOR_OUTPUT),
                                       position_a_little_after_silence_ends),
        kSourceVolume * max_relative_error());
    if (output_params().channels() > 1) {
      EXPECT_NEAR(kSourceVolume,
                  consumer()->ComputeAmplitudeAt(
                      1, GetRightChannelFrequency(FOR_OUTPUT),
                      position_a_little_after_silence_ends),
                  kSourceVolume * max_relative_error());
    }
    output_silence_position += output_frames_in_one_second;
  }
}

// Tests that a backwards-jump in input reference timestamps doesn't attempt to
// "re-write history" and otherwise maintains the timing/synchronization between
// input and output. This is a regression test for http://crbug.com/934770.
TEST_P(SnooperNodeTest, HandlesBackwardsInput) {
  CreateNewPipeline();

  // Schedule all input tasks. At the halfway point, simulate a device change
  // that shifts the timestamps backward by one buffer duration, and the
  // left/right sound tones are swapped.
  const base::TimeTicks start_time = task_runner()->NowTicks();
  const base::TimeTicks end_time = start_time + kTestDuration;
  const double time_step = 1.0 / input_params().sample_rate();
  const int change_position =
      input_params().sample_rate() * kTestDuration.InSeconds() / 2;
  int position_offset = 0;
  for (int position = 0;; position += input_params().frames_per_buffer()) {
    const base::TimeTicks task_time =
        start_time + base::Seconds(position * time_step);
    if (task_time >= end_time) {
      break;
    }
    if (position_offset == 0 && position >= change_position) {
      position_offset = -input_params().frames_per_buffer();
      task_runner()->PostDelayedTask(
          FROM_HERE,
          base::BindOnce(
              [](SnooperNodeTest* test) {
                test->group_member()->SetChannelTone(
                    0, test->GetLeftChannelFrequency(FOR_SWAPPED_INPUT));
                if (test->input_params().channels() > 1) {
                  test->group_member()->SetChannelTone(
                      1, test->GetRightChannelFrequency(FOR_SWAPPED_INPUT));
                }
              },
              this),
          task_time - start_time);
    }
    const base::TimeTicks reference_time =
        start_time + kInputAdvanceTime +
        base::Seconds((position + position_offset) * time_step);
    task_runner()->PostDelayedTask(
        FROM_HERE,
        base::BindOnce(&FakeLoopbackGroupMember::RenderMoreAudio,
                       base::Unretained(group_member()), reference_time),
        task_time - start_time);
  }

  ScheduleDefaultRenderTasks();
  RunAllPendingTasks();

  // In the consumer's recording, there should be audio having the default tones
  // before before the halfway point. After the halfway point, the tones should
  // be swapped (left vs right). Sample once every second, starting at a
  // ~half-second offset.
  const int output_position_halfway =
      (kInputAdvanceTime + output_delay() + (kTestDuration / 2)).InSecondsF() *
      output_params().sample_rate();
  const int output_frames_in_one_second = output_params().sample_rate();
  int output_position =
      ((kInputAdvanceTime + output_delay()).InSecondsF() + 0.5) *
      output_params().sample_rate();
  for (int output_end = consumer()->GetRecordedFrameCount();
       output_position < output_end;
       output_position += output_frames_in_one_second) {
    const int left_ch_freq = (output_position < output_position_halfway)
                                 ? GetLeftChannelFrequency(FOR_OUTPUT)
                                 : GetLeftChannelFrequency(FOR_SWAPPED_OUTPUT);
    EXPECT_NEAR(
        kSourceVolume,
        consumer()->ComputeAmplitudeAt(0, left_ch_freq, output_position),
        kSourceVolume * max_relative_error());
    if (output_params().channels() > 1) {
      const int right_ch_freq =
          (output_position < output_position_halfway)
              ? GetRightChannelFrequency(FOR_OUTPUT)
              : GetRightChannelFrequency(FOR_SWAPPED_OUTPUT);
      EXPECT_NEAR(
          kSourceVolume,
          consumer()->ComputeAmplitudeAt(1, right_ch_freq, output_position),
          kSourceVolume * max_relative_error());
    }
  }
}

// Tests that reasonable render times are suggested as audio is feeding into, or
// not feeding into, the SnooperNode.
TEST_P(SnooperNodeTest, SuggestsRenderTimes) {
  constexpr base::TimeDelta kTwentyMilliseconds = base::Milliseconds(20);

  CreateNewPipeline();

  // Before any audio has flowed into the SnooperNode, there should be nothing
  // to base a suggestion on.
  EXPECT_FALSE(
      node()->SuggestLatestRenderTime(output_params().frames_per_buffer()));

  // Feed-in the first buffer and expect a render time suggestion that is
  // greater than 150% the output buffer's duration amount of time in the
  // past. (The extra 50% is a safety margin; see internal code comments for
  // further details.) The suggestion should also not be too far in the past.
  const base::TimeTicks first_input_time = task_runner()->NowTicks();
  group_member()->RenderMoreAudio(first_input_time);
  const absl::optional<base::TimeTicks> first_suggestion =
      node()->SuggestLatestRenderTime(output_params().frames_per_buffer());
  ASSERT_TRUE(first_suggestion);
  base::TimeTicks time_at_end_of_input =
      first_input_time + input_params().GetBufferDuration();
  const base::TimeDelta required_duration_buffered =
      output_params().GetBufferDuration() * 3 / 2;
  EXPECT_GT(time_at_end_of_input - required_duration_buffered,
            *first_suggestion);
  EXPECT_LT(
      time_at_end_of_input - required_duration_buffered - kTwentyMilliseconds,
      *first_suggestion);

  // If another suggestion is solicited before more input was provided,
  // SnooperNode shouldn't give one.
  for (int i = 0; i < 3; ++i) {
    EXPECT_FALSE(
        node()->SuggestLatestRenderTime(output_params().frames_per_buffer()));
  }

  // When feeding-in successive buffers, a new suggestion can be given after
  // each, reflecting the timing of the additional audio that has been buffered.
  for (int i = 1; i <= 3; ++i) {
    const base::TimeTicks next_input_time =
        first_input_time +
        base::Seconds(i * input_params().frames_per_buffer() /
                      static_cast<double>(input_params().sample_rate()));
    group_member()->RenderMoreAudio(next_input_time);
    const absl::optional<base::TimeTicks> next_suggestion =
        node()->SuggestLatestRenderTime(output_params().frames_per_buffer());
    ASSERT_TRUE(next_suggestion);
    time_at_end_of_input = next_input_time + input_params().GetBufferDuration();
    EXPECT_GT(time_at_end_of_input - required_duration_buffered,
              *next_suggestion);
    EXPECT_LT(
        time_at_end_of_input - required_duration_buffered - kTwentyMilliseconds,
        *next_suggestion);
  }
}

namespace {

// Used in the HandlesSeekedRenderTimes test below. Returns one of 10 possible
// tone frequencies to use at the specified time |offset| in the audio.
double MapTimeOffsetToATone(base::TimeDelta offset) {
  constexpr double kMinFrequency = 200;
  constexpr double kMaxFrequency = 2000;
  constexpr int kNumToneSteps = 10;

  const int64_t step_number = offset.IntDiv(kTestDuration / kNumToneSteps);
  const double t = static_cast<double>(step_number) / kNumToneSteps;
  return kMinFrequency + t * (kMaxFrequency - kMinFrequency);
}

}  // namespace

// Tests that the SnooperNode can be asked to seek (forward or backward) its
// Render() positions, as the needs of the system demand.
TEST_P(SnooperNodeTest, HandlesSeekedRenderTimes) {
  constexpr base::TimeDelta kQuarterSecond = base::Milliseconds(250);

  CreateNewPipeline();

  // Schedule input tasks where the audio tones are changed once per second, to
  // allow for identifying the timing of the audio in the consumer's recording
  // later on.
  const base::TimeTicks start_time = task_runner()->NowTicks();
  const base::TimeTicks end_time = start_time + kTestDuration;
  double time_step = 1.0 / input_params().sample_rate();
  for (int position = 0;; position += input_params().frames_per_buffer()) {
    const base::TimeTicks task_time =
        start_time + base::Seconds(position * time_step);
    if (task_time >= end_time) {
      break;
    }
    const base::TimeTicks reference_time = task_time + kInputAdvanceTime;
    task_runner()->PostDelayedTask(
        FROM_HERE,
        base::BindOnce(
            [](FakeLoopbackGroupMember* group_member,
               base::TimeTicks start_time, base::TimeTicks reference_time) {
              group_member->SetChannelTone(
                  FakeLoopbackGroupMember::kSetAllChannels,
                  MapTimeOffsetToATone(reference_time - start_time));
              group_member->RenderMoreAudio(reference_time);
            },
            group_member(), start_time, reference_time),
        task_time - start_time);
  }

  // Schedule normal render tasks for the first third of the test, then skip
  // back a quarter-second and run for another third of the test, then skip
  // forward a quarter-second and run to the end.
  time_step = 1.0 / output_params().sample_rate();
  for (int position = 0;; position += output_params().frames_per_buffer()) {
    const base::TimeTicks task_time =
        start_time + base::Seconds(position * time_step);
    if (task_time >= end_time) {
      break;
    }
    base::TimeDelta time_offset = task_time - start_time;
    if (time_offset < (kTestDuration / 3) ||
        time_offset >= (kTestDuration * 2 / 3)) {
      time_offset = base::TimeDelta();
    } else {
      time_offset = -kQuarterSecond;
    }
    const base::TimeTicks reference_time =
        task_time + time_offset - output_delay();
    task_runner()->PostDelayedTask(
        FROM_HERE,
        base::BindOnce(&SnooperNodeTest::RenderAndConsume,
                       base::Unretained(this), reference_time),
        task_time - start_time);
  }

  RunAllPendingTasks();

  // Examine the consumer's recorded audio for the expected audio signal: For
  // the first third of the test, the consumer should hear the first few tones.
  // Then, at the point where rendering seeked backward, there will be a
  // zero-fill gap for a quarter second, followed by the tone changes being
  // "late" by a quarter second. Finally, at the point where rendering seeked
  // forward, the tone changes will be shifted back again.
  const base::TimeDelta lead_in = kInputAdvanceTime + output_delay();
  for (base::TimeDelta recording_time = lead_in + kQuarterSecond;
       recording_time < kTestDuration; recording_time += kQuarterSecond) {
    const base::TimeDelta render_time = recording_time - kInputAdvanceTime;

    base::TimeDelta input_time =
        recording_time - lead_in - input_params().GetBufferDuration();
    // The recording is shifted forward during the middle-third of the test.
    if (render_time >= (kTestDuration / 3) &&
        render_time < (kTestDuration * 2 / 3)) {
      input_time -= kQuarterSecond;
    }

    const double expected_freq = MapTimeOffsetToATone(input_time);
    SCOPED_TRACE(testing::Message() << "recording_time=" << recording_time
                                    << ", expected_freq=" << expected_freq);
    const int position =
        output_params().sample_rate() * recording_time.InSecondsF() -
        output_params().frames_per_buffer();
    if (render_time >= (kTestDuration / 3) &&
        render_time < (kTestDuration / 3 + kQuarterSecond)) {
      // Special case: Expect the zero-fill gap immediately after the first
      // discontinuity.
      for (int ch = 0; ch < output_params().channels(); ++ch) {
        EXPECT_TRUE(consumer()->IsSilentInRange(
            ch, position - output_params().frames_per_buffer(), position));
      }
    } else {
      for (int ch = 0; ch < output_params().channels(); ++ch) {
        EXPECT_NEAR(kSourceVolume,
                    consumer()->ComputeAmplitudeAt(ch, expected_freq, position),
                    kSourceVolume * max_relative_error());
      }
    }
  }
}

InputAndOutputParams MakeParams(
    media::ChannelLayoutConfig input_channel_layout_config,
    int input_sample_rate,
    int input_frames_per_buffer,
    media::ChannelLayoutConfig output_channel_layout_config,
    int output_sample_rate,
    int output_frames_per_buffer) {
  return InputAndOutputParams{
      media::AudioParameters(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
                             input_channel_layout_config, input_sample_rate,
                             input_frames_per_buffer),
      media::AudioParameters(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
                             output_channel_layout_config, output_sample_rate,
                             output_frames_per_buffer)};
}

INSTANTIATE_TEST_SUITE_P(
    All,
    SnooperNodeTest,
    testing::Values(MakeParams(media::ChannelLayoutConfig::Stereo(),
                               48000,
                               480,
                               media::ChannelLayoutConfig::Stereo(),
                               48000,
                               480),
                    MakeParams(media::ChannelLayoutConfig::Stereo(),
                               48000,
                               64,
                               media::ChannelLayoutConfig::Stereo(),
                               48000,
                               480),
                    MakeParams(media::ChannelLayoutConfig::Stereo(),
                               44100,
                               64,
                               media::ChannelLayoutConfig::Stereo(),
                               48000,
                               480),
                    MakeParams(media::ChannelLayoutConfig::Stereo(),
                               48000,
                               512,
                               media::ChannelLayoutConfig::Stereo(),
                               44100,
                               441),
                    MakeParams(media::ChannelLayoutConfig::Mono(),
                               8000,
                               64,
                               media::ChannelLayoutConfig::Stereo(),
                               48000,
                               480),
                    MakeParams(media::ChannelLayoutConfig::Stereo(),
                               48000,
                               480,
                               media::ChannelLayoutConfig::Mono(),
                               8000,
                               80)));

}  // namespace
}  // namespace audio


text:
use strict;
use warnings;

binmode STDIN;

sub foffpeeks
{
    my $in = shift;

    $in =~ s/\(Incl(?:udes)? Sneak Peek[^\)]*\)?//g;
    $in =~ s/\s*$//g;
    return $in;
}

sub nul
{
    my $in = shift;
    $in =~ s/\0.*//;
    return $in;
}

my $inf = do { local $/ = undef; <STDIN>; };
my (
    $magic,
    $version, $startTime, $duration, $durationSeconds,
    $flags, $serviceData, $serviceName, $videoType, $audioType,
    $eventSeconds, $eventMinutes, $eventId, $eventStart, $eventEnd,
    $eventStatus, $eventNameLength, $eventParentalRate
) = unpack("A4(xxSLSS)<(Sx10a14A24CC)<(xxCCLLL)<CCC", $inf);
printf "top_version=\"%s 0x%04x\"\n", $magic, $version;
printf "top_start=0x%08x\ntop_start_wtf=\"(%d, %s)\"\n", $startTime, $startTime, scalar(localtime($startTime));
printf "top_duration=\"%d:%02d\"\n", $duration, $durationSeconds;
printf "top_flags=0x%04x\n", $flags;
printf "top_service=%s\n", quotemeta nul $serviceName;
printf "top_video_audio=\"%d %d\"\n", $videoType, $audioType;
printf "top_event_duration=\"%d:%02d\"\n", $eventMinutes, $eventSeconds;
printf "top_event_id=\"%d\"\n", $eventId;
#printf "#Event start/end: 0x%04x - 0x%04x\n", $eventStart, $eventEnd;
#printf "#Event status/name/parental rate: %d %d %d\n", $eventStatus, $eventNameLength, $eventParentalRate;
my $eventName = substr($inf, 0x57, $eventNameLength);
print "top_event_name=", quotemeta foffpeeks $eventName;
print "\n";
my $eventInfo = unpack("Z*", substr($inf, 0x57 + $eventNameLength, 273 - $eventNameLength));
print "top_event_info=", quotemeta foffpeeks $eventInfo;
print "\n";

redpajama_set_name: RedPajamaGithub


text:
redirect: /security/vuln/database
---


text:
package org.protobee.examples.emotion.modules;

import org.protobee.annotation.InjectLogger;
import org.protobee.compatability.Headers;
import org.protobee.events.BasicMessageReceivedEvent;
import org.protobee.events.ProtocolHandlersLoadedEvent;
import org.protobee.events.SessionClosingEvent;
import org.protobee.examples.emotion.Emotion;
import org.protobee.examples.emotion.EmotionProvider;
import org.protobee.examples.protos.Common.Header;
import org.protobee.examples.protos.EmotionProtos.EmotionMessage;
import org.protobee.guice.scopes.SessionScope;
import org.protobee.identity.NetworkIdentity;
import org.protobee.modules.ProtocolModule;
import org.protobee.network.ProtobeeMessageWriter;
import org.protobee.network.ProtobeeMessageWriter.HandshakeOptions;
import org.protobee.protocol.Protocol;
import org.protobee.protocol.ProtocolModel;
import org.protobee.session.SessionModel;
import org.slf4j.Logger;

import com.google.common.base.Preconditions;
import com.google.common.eventbus.Subscribe;
import com.google.inject.Inject;

@SessionScope
@Headers(required = {})
public class EmotionMessageModule extends ProtocolModule implements Runnable {

  @InjectLogger
  private Logger log;
  private final SessionModel session;
  private final ProtocolModel protocolModel;
  private final Protocol myProtocol;
  private final ProtobeeMessageWriter writer;
  private final NetworkIdentity identity;
  private final EmotionProvider emotionProvider;

  private Thread thread;
  private boolean running = false;

  @Inject
  public EmotionMessageModule(SessionModel session, @Emotion Protocol protocol,
      ProtobeeMessageWriter writer, NetworkIdentity identity, EmotionProvider emotionProvider,
      ProtocolModel protocolModel) {
    this.session = session;
    this.myProtocol = protocol;
    this.writer = writer;
    this.identity = identity;
    this.emotionProvider = emotionProvider;
    this.protocolModel = protocolModel;
  }

  @Subscribe
  public void protocolLoaded(ProtocolHandlersLoadedEvent event) {
    thread = new Thread(this, "Demo Thread");
    thread.start();
  }

  @Subscribe
  public void channelDisconnected(SessionClosingEvent event) {
    stopThread();
  }

  @Override
  public void run() {
    log.info("run");
    running = true;
    try {
      protocolModel.enterScope();
      identity.enterScope();

      while (running) {
        EmotionMessage sendingMessage =
            EmotionMessage
                .newBuilder()
                .setHeader(
                    Header.newBuilder().setTtl(1).setHops(0)
                        .setId(emotionProvider.getNewEmotionId()))
                .setEmotion(emotionProvider.getEmotion()).build();
        log.info("SENDING emotion message " + sendingMessage + " to "
            + session.getIdentity().getListeningAddress(myProtocol));
        writer.write(sendingMessage, HandshakeOptions.WAIT_FOR_HANDSHAKE);
        try {
          Thread.sleep(5000);
        } catch (InterruptedException e) {}
      }

    } finally {
      protocolModel.exitScope();
      identity.exitScope();
    }
  }

  public void stopThread() {
    log.info("Stoping emotion thread");
    running = false;
  }

  @Subscribe
  public void messageRecieved(BasicMessageReceivedEvent event) {
    Preconditions.checkArgument(event.getMessage() instanceof EmotionMessage,
        "Not an emotion message");
    EmotionMessage message = (EmotionMessage) event.getMessage();
    log.info("RECEIVED emotion message " + message);
  }

}


text:
namespace Data.DbClient.Fluent.Enums
{
    public enum LogicalOperatorType
    {
        And,
        Or
    }
}


text:
package edu.umass.cs.ciir.waltz.postings.extents;

/**
 * @author jfoley
 */
public final class Span {
  /** This is inclusive, so a span of
[0,3)
 includes
{0,1,2}
 (Calculus notation). */
  public final int begin;
  /** This is exclusive, so a span of
[0,3)
 includes
{0,1,2}
 (Calculus notation). */
  public final int end;

  /** No-args constructor used only for reflection */
  private Span() {
    begin = end = -1;
  }
  public Span(int begin, int end) {
    this.begin = begin;
    this.end = end;
  }

  public static Span of(int begin, int end) {
    return new Span(begin, end);
  }

  @Override
  public boolean equals(Object other) {
    if(other instanceof Span) {
      Span rhs = (Span) other;
      return (rhs.begin == begin) && (rhs.end == end);
    }
    return false;
  }

  @Override
  public String toString() {
    return "[" + begin + ',' + end + ')';
  }

  @Override
  public int hashCode() {
    return Integer.hashCode(begin) ^ Integer.hashCode(end);
  }

  public boolean contains(int pos) {
    return pos >= begin && pos < end;
  }

  public boolean overlaps(Span other) {
    return overlaps(other.begin, other.end);
  }
  public boolean overlaps(int begin, int end) {
    int al = this.begin;
    int bl = begin;
    int ar = this.end-1;
    int br = end-1;
    return ar >= bl && br >= al;
  }
}


text:
package org.kuali.kpme.tklm.time.user.pref;

import org.apache.commons.lang.StringUtils;
import org.kuali.kpme.core.util.TKUtils;
import org.kuali.kpme.tklm.api.time.user.pref.UserPreferencesContract;
import org.kuali.kpme.tklm.api.common.TkConstants;
import org.kuali.rice.krad.bo.PersistableBusinessObjectBase;

public class UserPreferences extends PersistableBusinessObjectBase implements UserPreferencesContract {
    public static final String CACHE_NAME = TkConstants.Namespace.NAMESPACE_PREFIX + "UserPreferences";

	private static final long serialVersionUID = 1L;
	private String principalId;
	private String timezone;

	public UserPreferences(){}

	public UserPreferences(String principalId, String timeZone){
		this.principalId = principalId;
		this.timezone = timeZone;
	}

	public void setTimezone(String timezone) {
		this.timezone = timezone;
	}

	public String getTimezone() {
        if (StringUtils.isEmpty(timezone))
            return TKUtils.getSystemTimeZone();

		return timezone;
	}

	public String getPrincipalId() {
		return principalId;
	}

	public void setPrincipalId(String principalId) {
		this.principalId = principalId;
	}

}


text:
// This file was automatically generated by the code gen tool - do not modify.

using System ;
using scg = System.Collections.Generic ;
using sd = System.Data ;
using sds = System.Data.SqlClient ;
using sr = System.Reflection ;
using mst = Microsoft.SqlServer.Types ;
using mss = Microsoft.SqlServer.Server ;
using acr = alby.codegen.runtime ;

namespace alby.northwind.codegen.table
{
	public partial class Region : acr.RowBase
	{
		public const string column٠RegionID  = "RegionID" ;
		public const string column٠RegionDescription  = "RegionDescription" ;

		public int? RegionID
		{
			get
			{
				return base.GetValueˡ<int?>( _dicˡ, column٠RegionID ) ;
			}
			set
			{
				base.SetValueˡ<int?>( _dicˡ, column٠RegionID, value, ref _dirtyˡ ) ;
			}
		}

		public string RegionDescription
		{
			get
			{
				return base.GetValueˡ<string>( _dicˡ, column٠RegionDescription ) ;
			}
			set
			{
				base.SetValueˡ<string>( _dicˡ, column٠RegionDescription, value, ref _dirtyˡ ) ;
			}
		}

		public Region() : base()
		{
			base._dicˡ[ column٠RegionID ] = null ;
			base._dicˡ[ column٠RegionDescription ] = null ;

			base._dicPKˡ[ column٠RegionID ] = null ;

		}

	}

}


text: <!-- TODO: 404 Template -->


text:
package config

//struct for container coreswitch:ospf
type OspfIp struct {
	// original -> coreswitch:authentication-key
	AuthenticationKey string `mapstructure:"authentication-key" json:"authentication-key,omitempty"`
	// original -> coreswitch:cost
	Cost uint16 `mapstructure:"cost" json:"cost,omitempty"`
	// original -> coreswitch:dead-interval
	DeadInterval uint16 `mapstructure:"dead-interval" json:"dead-interval,omitempty"`
	// original -> coreswitch:hello-interval
	HelloInterval uint16 `mapstructure:"hello-interval" json:"hello-interval,omitempty"`
	// original -> coreswitch:priority
	Priority string `mapstructure:"priority" json:"priority,omitempty"`
	// original -> coreswitch:retransmit-interval
	RetransmitInterval uint16 `mapstructure:"retransmit-interval" json:"retransmit-interval,omitempty"`
	// original -> coreswitch:transmit-delay
	TransmitDelay uint16 `mapstructure:"transmit-delay" json:"transmit-delay,omitempty"`
}

func (lhs *OspfIp) Equal(rhs *OspfIp) bool {
	if lhs == nil || rhs == nil {
		return false
	}
	if lhs.AuthenticationKey != rhs.AuthenticationKey {
		return false
	}
	if lhs.Cost != rhs.Cost {
		return false
	}
	if lhs.DeadInterval != rhs.DeadInterval {
		return false
	}
	if lhs.HelloInterval != rhs.HelloInterval {
		return false
	}
	if lhs.Priority != rhs.Priority {
		return false
	}
	if lhs.RetransmitInterval != rhs.RetransmitInterval {
		return false
	}
	if lhs.TransmitDelay != rhs.TransmitDelay {
		return false
	}
	return true
}

//struct for container coreswitch:ip
type Ip struct {
	// original -> coreswitch:ospf
	OspfIp OspfIp `mapstructure:"ospf" json:"ospf,omitempty"`
}

func (lhs *Ip) Equal(rhs *Ip) bool {
	if lhs == nil || rhs == nil {
		return false
	}
	if !lhs.OspfIp.Equal(&(rhs.OspfIp)) {
		return false
	}
	return true
}

//struct for container coreswitch:interface
type InterfaceIp struct {
	// original -> coreswitch:name
	Name string `mapstructure:"name" json:"name,omitempty"`
	// original -> coreswitch:ip
	Ip Ip `mapstructure:"ip" json:"ip,omitempty"`
}

func (lhs *InterfaceIp) Equal(rhs *InterfaceIp) bool {
	if lhs == nil || rhs == nil {
		return false
	}
	if lhs.Name != rhs.Name {
		return false
	}
	if !lhs.Ip.Equal(&(rhs.Ip)) {
		return false
	}
	return true
}

//struct for container coreswitch:ospf-if-param
type OspfIfParam struct {
	// original -> coreswitch:interfaces
	InterfaceIps []InterfaceIp `mapstructure:"interfaces" json:"interfaces,omitempty"`
}

func (lhs *OspfIfParam) Equal(rhs *OspfIfParam) bool {
	if lhs == nil || rhs == nil {
		return false
	}
	if len(lhs.InterfaceIps) != len(rhs.InterfaceIps) {
		return false
	}
	{
		lmap := make(map[string]*InterfaceIp)
		for i, l := range lhs.InterfaceIps {
			lmap[mapkey(i, string(l.Name))] = &lhs.InterfaceIps[i]
		}
		for i, r := range rhs.InterfaceIps {
			if l, y := lmap[mapkey(i, string(r.Name))]; !y {
				return false
			} else if !r.Equal(l) {
				return false
			}
		}
	}
	return true
}


text:
import codecs
import io
import os
import subprocess
import sys

from PIL import EpsImagePlugin

from .data import BarcodeType, barcode_types

__all__ = ["generate_barcode", "TreepoemError", "BarcodeType", "barcode_types"]

BASE_DIR = os.path.normpath(os.path.abspath(os.path.dirname(__file__)))
BWIPP_PATH = os.path.join(BASE_DIR, "postscriptbarcode", "barcode.ps")

BASE_PS = """\
{bwipp}

/Helvetica findfont 10 scalefont setfont
gsave
2 2 scale
10 10 moveto

{code}
/uk.co.terryburton.bwipp findresource exec
grestore

showpage
"""

# Error handling from:
# https://github.com/bwipp/postscriptbarcode/wiki/Developing-a-Frontend-to-BWIPP#use-bwipps-error-reporting  # noqa: B950
BBOX_TEMPLATE = (
    """\
%!PS

errordict begin
/handleerror {{
  $error begin
  errorname dup length string cvs 0 6 getinterval (bwipp.) eq {{
    (%stderr) (w) file
    dup (\nBWIPP ERROR: ) writestring
    dup errorname dup length string cvs writestring
    dup ( ) writestring
    dup errorinfo dup length string cvs writestring
    dup (\n) writestring
    dup flushfile end quit
  }} if
  end //handleerror exec
}} bind def
end

"""
    + BASE_PS
)

EPS_TEMPLATE = (
    """\
%!PS-Adobe-3.0 EPSF-3.0
{bbox}

"""
    + BASE_PS
)

class TreepoemError(RuntimeError):
    pass

# Inline the BWIPP code rather than using the run operator to execute
# it because the EpsImagePlugin runs Ghostscript with the SAFER flag,
# which disables file operations in the PS code.
def _read_file(file_path):
    with open(file_path) as f:
        return f.read()

BWIPP = _read_file(BWIPP_PATH)

def _get_bbox(code):
    full_code = BBOX_TEMPLATE.format(bwipp=BWIPP, code=code)
    ghostscript = _get_ghostscript_binary()
    gs_process = subprocess.Popen(
        [ghostscript, "-sDEVICE=bbox", "-dBATCH", "-dSAFER", "-"],
        universal_newlines=True,
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
    )
    _, err_output = gs_process.communicate(full_code)
    err_output = err_output.strip()
    # Unfortunately the error-handling in the postscript means that
    # returncode is 0 even if there was an error, but this gives
    # better error messages.
    if gs_process.returncode != 0 or "BWIPP ERROR:" in err_output:
        if err_output.startswith("BWIPP ERROR: "):
            err_output = err_output.replace("BWIPP ERROR: ", "", 1)
        raise TreepoemError(err_output)
    return err_output

def _get_ghostscript_binary():
    binary = "gs"

    if sys.platform.startswith("win"):
        binary = EpsImagePlugin.gs_windows_binary
        if not binary:
            raise TreepoemError(
                "Cannot determine path to ghostscript, is it installed?"
            )

    return binary

def _encode(data):
    if isinstance(data, str):
        data = data.encode("utf-8")
    return codecs.encode(data, "hex_codec").decode("ascii")

def _format_options(options):
    items = []
    for name, value in options.items():
        if isinstance(value, bool):
            if value:
                items.append(name)
        else:
            items.append("{}={}".format(name, value))
    return " ".join(items)

def _format_code(barcode_type, data, options):
    return "<{data}> <{options}> <{barcode_type}> cvn".format(
        data=_encode(data),
        options=_encode(_format_options(options)),
        barcode_type=_encode(barcode_type),
    )

def generate_barcode(barcode_type, data, options=None):
    if barcode_type not in barcode_types:
        raise NotImplementedError("unsupported barcode type {!r}".format(barcode_type))
    if options is None:
        options = {}
    code = _format_code(barcode_type, data, options)
    bbox_lines = _get_bbox(code)
    full_code = EPS_TEMPLATE.format(bbox=bbox_lines, bwipp=BWIPP, code=code)
    return EpsImagePlugin.EpsImageFile(io.BytesIO(full_code.encode("utf8")))


text:
using Sep.Git.Tfs.Core.TfsInterop;
using Sep.Git.Tfs.VsCommon;
using StructureMap.AutoMocking;
using Xunit;

namespace GitTfsTest.Core
{
    public class TfsApiBridgeTest
    {
        private RhinoAutoMocker<TfsApiBridge> _mocks;

        public TfsApiBridgeTest()
        {
            _mocks = new RhinoAutoMocker<TfsApiBridge>();
            _mocks.MockObjectFactory();
        }

        [Fact]
        public void ConvertsEnum()
        {
            Assert.Equal(OriginalEnum.Value2, _mocks.ClassUnderTest.Convert<OriginalEnum>(WrappedEnum.Value2));
        }

        [Fact]
        public void WrapsAndUnwrapsObject()
        {
            var originalObject = new OriginalType();
            var wrappedObject = _mocks.ClassUnderTest.Wrap<WrapperForOriginalType, OriginalType>(originalObject);
            Assert.Equal(originalObject, _mocks.ClassUnderTest.Unwrap<OriginalType>(wrappedObject));
        }

        [Fact]
        public void WrapsObjectWithBridge()
        {
            var originalObject = new OriginalType();
            var wrappedObject = _mocks.ClassUnderTest.Wrap<WrapperForOriginalTypeWithBridge, OriginalType>(originalObject);
            Assert.NotNull(wrappedObject.Bridge);
        }

        [Fact]
        public void WrapsAndUnwrapsArray()
        {
            var originalObjects = new [] { new OriginalType() };
            var wrappedObjects = _mocks.ClassUnderTest.Wrap<WrapperForOriginalType, OriginalType>(originalObjects);
            Assert.Equal(1, wrappedObjects.Length);
            Assert.Equal(originalObjects[0], _mocks.ClassUnderTest.Unwrap<OriginalType>(wrappedObjects)[0]);
        }

        [Fact]
        public void WrapsNullAsNull()
        {
            OriginalType obj = null;
            Assert.Null(_mocks.ClassUnderTest.Wrap<WrapperForOriginalType, OriginalType>(obj));
        }

        [Fact]
        public void WrapsNullArrayAsNull()
        {
            OriginalType [] obj = null;
            Assert.Null(_mocks.ClassUnderTest.Wrap<WrapperForOriginalType, OriginalType>(obj));
        }

        [Fact]
        public void UnwrapsNullAsNull()
        {
            WrapperForOriginalType obj = null;
            Assert.Null(_mocks.ClassUnderTest.Unwrap<OriginalType>(obj));
        }

        [Fact]
        public void UnwrapsNullArrayAsNull()
        {
            WrapperForOriginalType[] obj = null;
            Assert.Null(_mocks.ClassUnderTest.Unwrap<OriginalType>(obj));
        }

        public class OriginalType
        {
            public static int counter;
            public static object lockObject = new object();
            private readonly int _id;
            public OriginalType()
            {
                lock (lockObject)
                {
                    _id = ++counter;
                }
            }
            public override bool Equals(object obj)
            {
                return obj is OriginalType && ((OriginalType) obj)._id == _id;
            }
            public override int GetHashCode()
            {
                return _id;
            }
            public override string ToString()
            {
                return "OriginalObject:" + _id;
            }
        }
        interface IOriginalType {}
        public class WrapperForOriginalType : WrapperFor<OriginalType>, IOriginalType
        {
            public WrapperForOriginalType(OriginalType o) : base(o) {}
        }
        public class WrapperForOriginalTypeWithBridge : WrapperFor<OriginalType>, IOriginalType
        {
            public WrapperForOriginalTypeWithBridge(OriginalType o, TfsApiBridge b) : base(o)
            {
                Bridge = b;
            }
            public TfsApiBridge Bridge { get; private set; }
        }

        public enum OriginalEnum
        {
            Value1,
            Value2,
        };

        public enum WrappedEnum
        {
            Value1,
            Value2,
        };
    }
}


text:
<!DOCTYPE html>

    <title>Number Divided 5 and 7</title>
    <link type="text/css" rel="stylesheet" href="styles/js-console.css" />


text:
require 'erb'
require 'pathname'
require 'hanami/environment'
require 'hanami/utils/string'

module Hanami
  # @api private
  class Welcome
    # @api private
    def initialize(_app)
      @root = Pathname.new(__dir__).join('templates').realpath
    end

    # @api private
    def call(env)
      @request_path = env['REQUEST_PATH'] || ''
      @body = [ERB.new(@root.join('welcome.html.erb').read).result(binding)]

      [200, {}, @body]
    end

    # @api private
    def application_name
      " #{ app }" if container?
    end

    private

    # @api private
    def container?
      Environment.new.container?
    end

    # @api private
    def application_class
      Hanami.configuration.apps do |app|
        return app if @request_path.include?(app.path_prefix)
      end
    end

    # @api private
    def app
      application_class.app_name
    end
  end
end


text:
<?php
require_once('NameAutoComplete.php');

if(isset($_GET["q"]))
{
	$query = htmlspecialchars($_GET["q"]);

	$autocomplete = new NameAutoComplete();

	header('Content-Type: application/json');
	echo $autocomplete->getHintsJson($query);
}


text:
require('mini_magick')

module Aurita
module Plugins
module Wiki

  class MiniMagickRenderer

    @@logger = Aurita::Log::Class_Logger.new(self)

    def initialize(media_asset_instance)
      @media_asset = media_asset_instance
    end

    def import
    end

    def create_variants(variants={})
    end

    def create_pdf_preview()
    end

  end

end
end
end


text:
<?php

namespace allejo\DaPulse;

use allejo\DaPulse\Exceptions\InvalidObjectException;
use allejo\DaPulse\Objects\ApiObject;

/**
 * Class PulseNote
 *
 * @api
 * @package allejo\DaPulse
 * @since   0.1.0
 */
class PulseNote extends ApiObject
{
    const API_PREFIX = "pulses";

    // ================================================================================================================
    //   Instance Variables
    // ================================================================================================================

    /**
     * The collaboration box type (rich_text, file_list, faq_list).
     *
     * @var string
     */
    protected $type;

    /**
     * The note's title.
     *
     * @var string
     */
    protected $title;

    /**
     * The note's project_id.
     *
     * @var string
     */
    protected $project_id;

    /**
     * Describes who can edit this note. Can be either 'everyone' or 'owners'.
     *
     * @var string
     */
    protected $permissions;

    /**
     * The note's body
     *
     * @var string
     */
    protected $content;

    /**
     * Creation time.
     *
     * @var \DateTime
     */
    protected $created_at;

    /**
     * Last update time.
     *
     * @var \DateTime
     */
    protected $updated_at;

    /**
     * PulseNote constructor.
     *
     * @internal
     *
     * @param array $array
     */
    public function __construct ($array)
    {
        $this->arrayConstructionOnly = true;

        parent::__construct($array);
    }

    // ================================================================================================================
    //   Getter functions
    // ================================================================================================================

    /**
     * The collaboration box type (rich_text, file_list, faq_list).
     *
     * @api
     *
     * @since  0.1.0
     *
     * @return string
     */
    public function getType ()
    {
        return $this->type;
    }

    /**
     * The note's id.
     *
     * @api
     *
     * @since  0.1.0
     *
     * @return string
     */
    public function getId ()
    {
        return $this->id;
    }

    /**
     * The note's title.
     *
     * @api
     *
     * @since  0.1.0
     *
     * @return string
     */
    public function getTitle ()
    {
        return $this->title;
    }

    /**
     * The note's project_id.
     *
     * @api
     *
     * @since  0.1.0
     *
     * @return string
     */
    public function getPulseId ()
    {
        return $this->project_id;
    }

    /**
     * Describes who can edit this note. Can be either 'everyone' or 'owners'.
     *
     * @api
     *
     * @since  0.1.0
     *
     * @return string
     */
    public function getPermissions ()
    {
        return $this->permissions;
    }

    /**
     * The note's body.
     *
     * @api
     *
     * @since  0.1.0
     *
     * @return string
     */
    public function getContent ()
    {
        return $this->content;
    }

    /**
     * Creation time.
     *
     * @api
     *
     * @since  0.1.0
     *
     * @return \DateTime
     */
    public function getCreatedAt ()
    {
        self::lazyCast($this->created_at, '\DateTime');

        return $this->created_at;
    }

    /**
     * Last update time.
     *
     * @api
     *
     * @since  0.1.0
     *
     * @return \DateTime
     */
    public function getUpdatedAt ()
    {
        self::lazyCast($this->updated_at, '\DateTime');

        return $this->updated_at;
    }

    // ================================================================================================================
    //   Modification functions
    // ================================================================================================================

    /**
     * Edit a note's content or information. Set values to NULL in order to not update them
     *
     * @api
     *
     * @param  null|string        $title        The new title of the note
     * @param  null|string        $content      The new content of the note
     * @param  null|int|PulseUser $user         The new author of the note
     * @param  null|bool          $createUpdate Whether to create an update or not
     *
     * @since  0.1.0
     *
     * @throws InvalidObjectException    The object has already been deleted from DaPulse
     * @throws \InvalidArgumentException An update was to be created but no author for the update was specified
     *
     * @return $this
     */
    public function editNote ($title = null, $content = null, $user = null, $createUpdate = null)
    {
        $this->checkInvalid();

        if (!is_null($user))
        {
            $user = PulseUser::_castToInt($user);
        }

        $url        = $this->getNotesUrl();
        $postParams = [
            "id"      => $this->getPulseId(),
            "note_id" => $this->getId()
        ];

        self::setIfNotNullOrEmpty($postParams, "title", $title);
        self::setIfNotNullOrEmpty($postParams, "content", $content);
        self::setIfNotNullOrEmpty($postParams, "user_id", $user);
        self::setIfNotNullOrEmpty($postParams, "create_update", $createUpdate);

        if ($createUpdate && is_null($user))
        {
            throw new \InvalidArgumentException('The $user value must be set if an update is to be created');
        }

        $this->jsonResponse = self::sendPut($url, $postParams);
        $this->assignResults();

        return $this;
    }

    /**
     * Edit the title of the note only.
     *
     * **Note** This is a convenience function that just calls PulseNote->editNote(). In order to change multiple
     * values, use PulseNote->editNote() instead of chaining the individual edit functions because each convenience
     * function will make their own separate API call making the process significantly slower.
     *
     * @api
     *
     * @param  string $title The new title of the note
     *
     * @since  0.1.0
     *
     * @return $this
     */
    public function editTitle ($title)
    {
        return $this->editNote($title);
    }

    /**
     * Edit the content of the note only.
     *
     * **Note** This is a convenience function that just calls PulseNote->editNote(). In order to change multiple
     * values, use PulseNote->editNote() instead of chaining the individual edit functions because each convenience
     * function will make their own separate API call making the process significantly slower.
     *
     * @api
     *
     * @param  string $content The new content of the note
     *
     * @since  0.1.0
     *
     * @return $this
     */
    public function editContent ($content)
    {
        return $this->editNote(null, $content);
    }

    /**
     * Edit the author of the note only.
     *
     * **Note** This is a convenience function that just calls PulseNote->editNote(). In order to change multiple
     * values, use PulseNote->editNote() instead of chaining the individual edit functions because each convenience
     * function will make their own separate API call making the process significantly slower.
     *
     * @api
     *
     * @param  string $userId The new author of the note
     *
     * @since  0.1.0
     *
     * @return $this
     */
    public function editAuthor ($userId)
    {
        return $this->editNote(null, null, $userId);
    }

    /**
     * Delete this note
     *
     * @api
     *
     * @since 0.1.0
     *
     * @throws InvalidObjectException The object has already been deleted from DaPulse
     */
    public function deleteNote ()
    {
        $this->checkInvalid();

        self::sendDelete($this->getNotesUrl());

        $this->deletedObject = true;
    }

    private function getNotesUrl ()
    {
        return sprintf("%s/%s/notes/%s.json", self::apiEndpoint(), $this->getPulseId(), $this->getId());
    }
}


text:
#pragma once

#include "Document.h"
#include "ElementData.h"
#include "ShadowRootMode.h"
#include "SimulatedClickOptions.h"

namespace WebCore {

class AccessibleNode;
class CustomElementReactionQueue;
class DatasetDOMStringMap;
class DOMRect;
class DOMRectList;
class DOMTokenList;
class ElementRareData;
class HTMLDocument;
class IntSize;
class JSCustomElementInterface;
class KeyboardEvent;
class Locale;
class PlatformKeyboardEvent;
class PlatformMouseEvent;
class PlatformWheelEvent;
class PseudoElement;
class RenderTreePosition;
class WebAnimation;
struct ElementStyle;

enum SpellcheckAttributeState {
    SpellcheckAttributeTrue,
    SpellcheckAttributeFalse,
    SpellcheckAttributeDefault
};

enum class SelectionRevealMode {
    Reveal,
    RevealUpToMainFrame, // Scroll overflow and iframes, but not the main frame.
    DoNotReveal
};

class Element : public ContainerNode {
public:
    static Ref<Element> create(const QualifiedName&, Document&);
    virtual ~Element();

     bool hasAttribute(const QualifiedName&) const;
     const AtomicString& getAttribute(const QualifiedName&) const;
     void setAttribute(const QualifiedName&, const AtomicString& value);
     void setAttributeWithoutSynchronization(const QualifiedName&, const AtomicString& value);
    void setSynchronizedLazyAttribute(const QualifiedName&, const AtomicString& value);
    bool removeAttribute(const QualifiedName&);
    Vector<String> getAttributeNames() const;

    // Typed getters and setters for language bindings.
     int getIntegralAttribute(const QualifiedName& attributeName) const;
     void setIntegralAttribute(const QualifiedName& attributeName, int value);
     unsigned getUnsignedIntegralAttribute(const QualifiedName& attributeName) const;
     void setUnsignedIntegralAttribute(const QualifiedName& attributeName, unsigned value);

    // Call this to get the value of an attribute that is known not to be the style
    // attribute or one of the SVG animatable attributes.
    bool hasAttributeWithoutSynchronization(const QualifiedName&) const;
    const AtomicString& attributeWithoutSynchronization(const QualifiedName&) const;
#ifndef NDEBUG
     bool fastAttributeLookupAllowed(const QualifiedName&) const;
#endif

#ifdef DUMP_NODE_STATISTICS
    bool hasNamedNodeMap() const;
#endif
     bool hasAttributes() const;
    // This variant will not update the potentially invalid attributes. To be used when not interested
    // in style attribute or one of the SVG animation attributes.
    bool hasAttributesWithoutUpdate() const;

     bool hasAttribute(const AtomicString& name) const;
     bool hasAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const;

     const AtomicString& getAttribute(const AtomicString& name) const;
     const AtomicString& getAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const;

     ExceptionOr<void> setAttribute(const AtomicString& name, const AtomicString& value);
    static ExceptionOr<QualifiedName> parseAttributeName(const AtomicString& namespaceURI, const AtomicString& qualifiedName);
     ExceptionOr<void> setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value);

    const AtomicString& getIdAttribute() const;
    void setIdAttribute(const AtomicString&);

    const AtomicString& getNameAttribute() const;

    // Call this to get the value of the id attribute for style resolution purposes.
    // The value will already be lowercased if the document is in compatibility mode,
    // so this function is not suitable for non-style uses.
    const AtomicString& idForStyleResolution() const;

    // Internal methods that assume the existence of attribute storage, one should use hasAttributes()
    // before calling them.
    AttributeIteratorAccessor attributesIterator() const { return elementData()->attributesIterator(); }
    unsigned attributeCount() const;
    const Attribute& attributeAt(unsigned index) const;
    const Attribute* findAttributeByName(const QualifiedName&) const;
    unsigned findAttributeIndexByName(const QualifiedName& name) const { return elementData()->findAttributeIndexByName(name); }
    unsigned findAttributeIndexByName(const AtomicString& name, bool shouldIgnoreAttributeCase) const { return elementData()->findAttributeIndexByName(name, shouldIgnoreAttributeCase); }

     void scrollIntoView(bool alignToTop = true);
     void scrollIntoViewIfNeeded(bool centerIfNeeded = true);
     void scrollIntoViewIfNotVisible(bool centerIfNotVisible = true);

    //void scrollBy(const ScrollToOptions&);
    void scrollBy(double x, double y);
    //virtual void scrollTo(const ScrollToOptions&, ScrollClamping = ScrollClamping::Clamped);
    void scrollTo(double x, double y);

     void scrollByLines(int lines);
     void scrollByPages(int pages);

     double offsetLeft();
     double offsetTop();
     double offsetWidth();
     double offsetHeight();

    bool mayCauseRepaintInsideViewport(const IntRect* visibleRect = nullptr) const;

    // FIXME: Replace uses of offsetParent in the platform with calls
    // to the render layer and merge bindingsOffsetParent and offsetParent.
     Element* bindingsOffsetParent();

    const Element* rootElement() const;

    Element* offsetParent();
     double clientLeft();
     double clientTop();
     double clientWidth();
     double clientHeight();

    virtual int scrollLeft();
    virtual int scrollTop();
    virtual void setScrollLeft(int);
    virtual void setScrollTop(int);
    virtual int scrollWidth();
    virtual int scrollHeight();

     IntRect boundsInRootViewSpace();

     FloatRect boundingClientRect();

     Ref<DOMRectList> getClientRects();
    Ref<DOMRect> getBoundingClientRect();

    // Returns the absolute bounding box translated into client coordinates.
     IntRect clientRect() const;
    // Returns the absolute bounding box translated into screen coordinates.
     IntRect screenRect() const;

     bool removeAttribute(const AtomicString& name);
     bool removeAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName);

    Ref<Attr> detachAttribute(unsigned index);

     RefPtr<Attr> getAttributeNode(const AtomicString& name);
     RefPtr<Attr> getAttributeNodeNS(const AtomicString& namespaceURI, const AtomicString& localName);
     ExceptionOr<RefPtr<Attr>> setAttributeNode(Attr&);
     ExceptionOr<RefPtr<Attr>> setAttributeNodeNS(Attr&);
     ExceptionOr<Ref<Attr>> removeAttributeNode(Attr&);

    RefPtr<Attr> attrIfExists(const QualifiedName&);
    RefPtr<Attr> attrIfExists(const AtomicString& localName, bool shouldIgnoreAttributeCase);
    Ref<Attr> ensureAttr(const QualifiedName&);

    const Vector<RefPtr<Attr>>& attrNodeList();

    const QualifiedName& tagQName() const { return m_tagName; }
#if ENABLE(JIT)
    static ptrdiff_t tagQNameMemoryOffset() { return OBJECT_OFFSETOF(Element, m_tagName); }
#endif // ENABLE(JIT)
    String tagName() const { return nodeName(); }
    bool hasTagName(const QualifiedName& tagName) const { return m_tagName.matches(tagName); }
    bool hasTagName(const HTMLQualifiedName& tagName) const { return ContainerNode::hasTagName(tagName); }
    bool hasTagName(const MathMLQualifiedName& tagName) const { return ContainerNode::hasTagName(tagName); }
    bool hasTagName(const SVGQualifiedName& tagName) const { return ContainerNode::hasTagName(tagName); }

    // A fast function for checking the local name against another atomic string.
    bool hasLocalName(const AtomicString& other) const { return m_tagName.localName() == other; }

    const AtomicString& localName() const final { return m_tagName.localName(); }
    const AtomicString& prefix() const final { return m_tagName.prefix(); }
    const AtomicString& namespaceURI() const final { return m_tagName.namespaceURI(); }

    ExceptionOr<void> setPrefix(const AtomicString&) final;

    String nodeName() const override;

    Ref<Element> cloneElementWithChildren(Document&);
    Ref<Element> cloneElementWithoutChildren(Document&);

    void normalizeAttributes();
    String nodeNamePreservingCase() const;

     void setBooleanAttribute(const QualifiedName& name, bool);

    // For exposing to DOM only.
     NamedNodeMap& attributes() const;

    enum AttributeModificationReason {
        ModifiedDirectly,
        ModifiedByCloning
    };

    // This method is called whenever an attribute is added, changed or removed.
    virtual void attributeChanged(const QualifiedName&, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason = ModifiedDirectly);
    virtual void parseAttribute(const QualifiedName&, const AtomicString&) { }

    // Only called by the parser immediately after element construction.
    void parserSetAttributes(const Vector<Attribute>&);

    bool isEventHandlerAttribute(const Attribute&) const;
    bool isJavaScriptURLAttribute(const Attribute&) const;

    // Remove attributes that might introduce scripting from the vector leaving the element unchanged.
    void stripScriptingAttributes(Vector<Attribute>&) const;

    const ElementData* elementData() const { return m_elementData.get(); }
    static ptrdiff_t elementDataMemoryOffset() { return OBJECT_OFFSETOF(Element, m_elementData); }
    UniqueElementData& ensureUniqueElementData();

    void synchronizeAllAttributes() const;

    // Clones attributes only.
    void cloneAttributesFromElement(const Element&);

    // Clones all attribute-derived data, including subclass specifics (through copyNonAttributeProperties.)
    void cloneDataFromElement(const Element&);

    virtual void didMoveToNewDocument(Document& oldDocument, Document& newDocument);

    bool hasEquivalentAttributes(const Element* other) const;

    virtual void copyNonAttributePropertiesFromElement(const Element&) { }

    virtual RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&);
    virtual bool rendererIsNeeded(const RenderStyle&);

     ShadowRoot* shadowRoot() const;
    ShadowRoot* shadowRootForBindings(JSC::ExecState&) const;

    struct ShadowRootInit {
        ShadowRootMode mode;
    };
    ExceptionOr<ShadowRoot&> attachShadow(const ShadowRootInit&);

    RefPtr<ShadowRoot> userAgentShadowRoot() const;
     ShadowRoot& ensureUserAgentShadowRoot();
    void removeShadowRoot();

    void setIsDefinedCustomElement(JSCustomElementInterface&);
    void setIsFailedCustomElement(JSCustomElementInterface&);
    void setIsCustomElementUpgradeCandidate();
    void enqueueToUpgrade(JSCustomElementInterface&);
    CustomElementReactionQueue* reactionQueue() const;

    // FIXME: this should not be virtual, do not override this.
    virtual const AtomicString& shadowPseudoId() const;

    bool inActiveChain() const { return isUserActionElement() && isUserActionElementInActiveChain(); }
    bool active() const { return isUserActionElement() && isUserActionElementActive(); }
    bool hovered() const { return isUserActionElement() && isUserActionElementHovered(); }
    bool focused() const { return isUserActionElement() && isUserActionElementFocused(); }
    bool hasFocusWithin() const { return getFlag(HasFocusWithin); };

    virtual void setActive(bool flag = true, bool pause = false);
    virtual void setHovered(bool flag = true);
    virtual void setFocus(bool flag);
    void setHasFocusWithin(bool flag);

    bool tabIndexSetExplicitly() const;
    virtual bool supportsFocus() const;
    virtual bool isFocusable() const;
    virtual bool isKeyboardFocusable(KeyboardEvent&) const;
    virtual bool isMouseFocusable() const;

    virtual bool shouldUseInputMethod();

    virtual int tabIndex() const;
     void setTabIndex(int);
    virtual RefPtr<Element> focusDelegate();

    ExceptionOr<void> insertAdjacentHTML(const String& where, const String& html, std::optional<NodeVector&> addedNodes);

     ExceptionOr<Element*> insertAdjacentElement(const String& where, Element& newChild);
     ExceptionOr<void> insertAdjacentHTML(const String& where, const String& html);
     ExceptionOr<void> insertAdjacentText(const String& where, const String& text);

    const RenderStyle* computedStyle(PseudoId = NOPSEUDO) override;

    bool needsStyleInvalidation() const;

    // Methods for indicating the style is affected by dynamic updates (e.g., children changing, our position changing in our sibling list, etc.)
    bool styleAffectedByActive() const { return hasRareData() && rareDataStyleAffectedByActive(); }
    bool styleAffectedByEmpty() const { return hasRareData() && rareDataStyleAffectedByEmpty(); }
    bool styleAffectedByFocusWithin() const { return hasRareData() && rareDataStyleAffectedByFocusWithin(); }
    bool childrenAffectedByHover() const { return getFlag(ChildrenAffectedByHoverRulesFlag); }
    bool childrenAffectedByDrag() const { return hasRareData() && rareDataChildrenAffectedByDrag(); }
    bool childrenAffectedByFirstChildRules() const { return getFlag(ChildrenAffectedByFirstChildRulesFlag); }
    bool childrenAffectedByLastChildRules() const { return getFlag(ChildrenAffectedByLastChildRulesFlag); }
    bool childrenAffectedByBackwardPositionalRules() const { return hasRareData() && rareDataChildrenAffectedByBackwardPositionalRules(); }
    bool childrenAffectedByPropertyBasedBackwardPositionalRules() const { return hasRareData() && rareDataChildrenAffectedByPropertyBasedBackwardPositionalRules(); }
    bool affectsNextSiblingElementStyle() const { return getFlag(AffectsNextSiblingElementStyle); }
    unsigned childIndex() const { return hasRareData() ? rareDataChildIndex() : 0; }

    bool hasFlagsSetDuringStylingOfChildren() const;

    void setStyleAffectedByEmpty();
    void setStyleAffectedByFocusWithin();
    void setChildrenAffectedByHover() { setFlag(ChildrenAffectedByHoverRulesFlag); }
    void setStyleAffectedByActive();
    void setChildrenAffectedByDrag();
    void setChildrenAffectedByFirstChildRules() { setFlag(ChildrenAffectedByFirstChildRulesFlag); }
    void setChildrenAffectedByLastChildRules() { setFlag(ChildrenAffectedByLastChildRulesFlag); }
    void setChildrenAffectedByBackwardPositionalRules();
    void setChildrenAffectedByPropertyBasedBackwardPositionalRules();
    void setAffectsNextSiblingElementStyle() { setFlag(AffectsNextSiblingElementStyle); }
    void setStyleIsAffectedByPreviousSibling() { setFlag(StyleIsAffectedByPreviousSibling); }
    void setChildIndex(unsigned);

    AtomicString computeInheritedLanguage() const;
    Locale& locale() const;

    virtual void accessKeyAction(bool /*sendToAnyEvent*/) { }

    virtual bool isURLAttribute(const Attribute&) const { return false; }
    virtual bool attributeContainsURL(const Attribute& attribute) const { return isURLAttribute(attribute); }
    virtual String completeURLsInAttributeValue(const URL& base, const Attribute&) const;
    virtual bool isHTMLContentAttribute(const Attribute&) const { return false; }

     URL getURLAttribute(const QualifiedName&) const;
    URL getNonEmptyURLAttribute(const QualifiedName&) const;

    virtual const AtomicString& imageSourceURL() const;
    virtual String target() const { return String(); }

    //static AXTextStateChangeIntent defaultFocusTextStateChangeIntent() { return AXTextStateChangeIntent(AXTextStateChangeTypeSelectionMove, AXTextSelection { AXTextSelectionDirectionDiscontiguous, AXTextSelectionGranularityUnknown, true }); }
    void updateFocusAppearanceAfterAttachIfNeeded();
    virtual void focus(bool restorePreviousSelection = true, FocusDirection = FocusDirectionNone);
    virtual void updateFocusAppearance(SelectionRestorationMode, SelectionRevealMode = SelectionRevealMode::Reveal);
    virtual void blur();

     String innerHTML() const;
     String outerHTML() const;
     ExceptionOr<void> setInnerHTML(const String&);
     ExceptionOr<void> setOuterHTML(const String&);
     String innerText();
     String outerText();

    virtual String title() const;

    const AtomicString& pseudo() const;
     void setPseudo(const AtomicString&);

    //LayoutSize minimumSizeForResizing() const;
    //void setMinimumSizeForResizing(const LayoutSize&);

    // Use Document::registerForDocumentActivationCallbacks() to subscribe to these
    virtual void prepareForDocumentSuspension() { }
    virtual void resumeFromDocumentSuspension() { }

    // Use Document::registerForMediaVolumeCallbacks() to subscribe to this
    virtual void mediaVolumeDidChange() { }

    // Use Document::registerForPrivateBrowsingStateChangedCallbacks() to subscribe to this.
    virtual void privateBrowsingStateDidChange() { }

    virtual void willBecomeFullscreenElement();
    virtual void ancestorWillEnterFullscreen() { }
    virtual void didBecomeFullscreenElement() { }
    virtual void willStopBeingFullscreenElement() { }

#if ENABLE(VIDEO_TRACK)
    virtual void captionPreferencesChanged() { }
#endif

    bool isFinishedParsingChildren() const { return isParsingChildrenFinished(); }
    void finishParsingChildren() override;
    void beginParsingChildren() final;

     PseudoElement* beforePseudoElement() const;
     PseudoElement* afterPseudoElement() const;
    bool childNeedsShadowWalker() const;
    void didShadowTreeAwareChildrenChange();

    virtual bool matchesValidPseudoClass() const;
    virtual bool matchesInvalidPseudoClass() const;
    virtual bool matchesReadWritePseudoClass() const;
    virtual bool matchesIndeterminatePseudoClass() const;
    virtual bool matchesDefaultPseudoClass() const;
     ExceptionOr<bool> matches(const String& selectors);
     ExceptionOr<Element*> closest(const String& selectors);
    virtual bool shouldAppearIndeterminate() const;

     DOMTokenList& classList();

    DatasetDOMStringMap& dataset();

#if ENABLE(VIDEO)
    virtual bool isMediaElement() const { return false; }
#endif

    virtual bool isFormControlElement() const { return false; }
    virtual bool isSpinButtonElement() const { return false; }
    virtual bool isTextFormControl() const { return false; }
    virtual bool isOptionalFormControl() const { return false; }
    virtual bool isRequiredFormControl() const { return false; }
    virtual bool isInRange() const { return false; }
    virtual bool isOutOfRange() const { return false; }
    virtual bool isFrameElementBase() const { return false; }
    virtual bool isUploadButton() const { return false; }
    virtual bool isSliderContainerElement() const { return false; }

    bool canContainRangeEndPoint() const override;

    // Used for disabled form elements; if true, prevents mouse events from being dispatched
    // to event listeners, and prevents DOMActivate events from being sent at all.
    virtual bool isDisabledFormControl() const { return false; }

    virtual bool childShouldCreateRenderer(const Node&) const;

    bool hasPendingResources() const;
    void setHasPendingResources();
    void clearHasPendingResources();
    virtual void buildPendingResource() { };

    bool hasCSSAnimation() const;
    void setHasCSSAnimation();
    void clearHasCSSAnimation();

#if ENABLE(FULLSCREEN_API)
     bool containsFullScreenElement() const;
    void setContainsFullScreenElement(bool);
    void setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(bool);
     void webkitRequestFullscreen();
#endif

#if ENABLE(POINTER_LOCK)
     void requestPointerLock();
#endif

    bool isSpellCheckingEnabled() const;

    bool hasID() const;
    bool hasClass() const;
    bool hasName() const;
    const SpaceSplitString& classNames() const;

    IntPoint savedLayerScrollPosition() const;
    void setSavedLayerScrollPosition(const IntPoint&);

    bool dispatchMouseEvent(const PlatformMouseEvent&, const AtomicString& eventType, int clickCount = 0, Element* relatedTarget = nullptr);
    bool dispatchWheelEvent(const PlatformWheelEvent&);
    bool dispatchKeyEvent(const PlatformKeyboardEvent&);
    void dispatchSimulatedClick(Event* underlyingEvent, SimulatedClickMouseEventOptions = SendNoEvents, SimulatedClickVisualOptions = ShowPressedLook);
    void dispatchFocusInEvent(const AtomicString& eventType, RefPtr<Element>&& oldFocusedElement);
    void dispatchFocusOutEvent(const AtomicString& eventType, RefPtr<Element>&& newFocusedElement);
    virtual void dispatchFocusEvent(RefPtr<Element>&& oldFocusedElement, FocusDirection);
    virtual void dispatchBlurEvent(RefPtr<Element>&& newFocusedElement);
    void dispatchWebKitImageReadyEventForTesting();

     bool dispatchMouseForceWillBegin();

    //virtual void willRecalcStyle(Style::Change);
    //virtual void didRecalcStyle(Style::Change);
    virtual void willResetComputedStyle();
    virtual void willAttachRenderers();
    virtual void didAttachRenderers();
    virtual void willDetachRenderers();
    virtual void didDetachRenderers();
    virtual std::optional<ElementStyle> resolveCustomStyle(const RenderStyle& parentStyle, const RenderStyle* shadowHostStyle);

    LayoutRect absoluteEventHandlerBounds(bool& includesFixedPositionElements);

    const RenderStyle* existingComputedStyle() const;

    void setBeforePseudoElement(Ref<PseudoElement>&&);
    void setAfterPseudoElement(Ref<PseudoElement>&&);
    void clearBeforePseudoElement();
    void clearAfterPseudoElement();
    void resetComputedStyle();
    void resetStyleRelations();
    void clearStyleDerivedDataBeforeDetachingRenderer();
    void clearHoverAndActiveStatusBeforeDetachingRenderer();

     URL absoluteLinkURL() const;

#if ENABLE(TOUCH_EVENTS)
    bool allowsDoubleTapGesture() const override;
#endif

    StyleResolver& styleResolver();
    ElementStyle resolveStyle(const RenderStyle* parentStyle);

    // Invalidates the style of a single element. Style is resolved lazily.
    // Descendant elements are resolved as needed, for example if an inherited property changes.
    // This should be called whenever an element changes in a manner that can affect its style.
    void invalidateStyle();

    // As above but also call RenderElement::setStyle with StyleDifferenceRecompositeLayer flag for
    // the element even when the style doesn't change. This is mostly needed by the animation code.
     void invalidateStyleAndLayerComposition();

    // Invalidate the element and all its descendants. This is used when there is some sort of change
    // in the tree that may affect the style of any of the descendants and we don't know how to optimize
    // the case to limit the scope. This is expensive and should be avoided.
    void invalidateStyleForSubtree();

    // Invalidates renderers for the element and all its descendants causing them to be torn down
    // and rebuild during style resolution. Style is also recomputed. This is used in code dealing with
    // custom (not style based) renderers. This is expensive and should be avoided.
    // Elements newly added to the tree are also in this state.
    void invalidateStyleAndRenderersForSubtree();

    bool hasDisplayContents() const;
    void storeDisplayContentsStyle(std::unique_ptr<RenderStyle>);

    using ContainerNode::setAttributeEventListener;
    void setAttributeEventListener(const AtomicString& eventType, const QualifiedName& attributeName, const AtomicString& value);

    Element* findAnchorElementForLink(String& outAnchorName);

    AccessibleNode* existingAccessibleNode() const;
    AccessibleNode* accessibleNode();

    Vector<RefPtr<WebAnimation>> getAnimations();

protected:
    Element(const QualifiedName&, Document&, ConstructionType);

    InsertedIntoAncestorResult insertedIntoAncestor(InsertionType, ContainerNode&) override;
    void removedFromAncestor(RemovalType, ContainerNode&) override;
    void childrenChanged(const ChildChange&) override;
    void removeAllEventListeners() final;
    virtual void parserDidSetAttributes();

    void clearTabIndexExplicitlyIfNeeded();
    void setTabIndexExplicitly(int);

    // classAttributeChanged() exists to share code between
    // parseAttribute (called via setAttribute()) and
    // svgAttributeChanged (called when element.className.baseValue is set)
    void classAttributeChanged(const AtomicString& newClassString);

    void addShadowRoot(Ref<ShadowRoot>&&);

    static ExceptionOr<void> mergeWithNextTextNode(Text&);

private:
    bool isTextNode() const;

    bool isUserActionElementInActiveChain() const;
    bool isUserActionElementActive() const;
    bool isUserActionElementFocused() const;
    bool isUserActionElementHovered() const;

    virtual void didAddUserAgentShadowRoot(ShadowRoot&) { }

    // FIXME: Remove the need for Attr to call willModifyAttribute/didModifyAttribute.
    friend class Attr;

    enum SynchronizationOfLazyAttribute { NotInSynchronizationOfLazyAttribute = 0, InSynchronizationOfLazyAttribute };

    void didAddAttribute(const QualifiedName&, const AtomicString&);
    void willModifyAttribute(const QualifiedName&, const AtomicString& oldValue, const AtomicString& newValue);
    void didModifyAttribute(const QualifiedName&, const AtomicString& oldValue, const AtomicString& newValue);
    void didRemoveAttribute(const QualifiedName&, const AtomicString& oldValue);

    void synchronizeAttribute(const QualifiedName&) const;
    void synchronizeAttribute(const AtomicString& localName) const;

    void updateName(const AtomicString& oldName, const AtomicString& newName);
    void updateNameForTreeScope(TreeScope&, const AtomicString& oldName, const AtomicString& newName);
    void updateNameForDocument(HTMLDocument&, const AtomicString& oldName, const AtomicString& newName);

    enum class NotifyObservers { No, Yes };
    void updateId(const AtomicString& oldId, const AtomicString& newId, NotifyObservers = NotifyObservers::Yes);
    void updateIdForTreeScope(TreeScope&, const AtomicString& oldId, const AtomicString& newId, NotifyObservers = NotifyObservers::Yes);

    enum HTMLDocumentNamedItemMapsUpdatingCondition { AlwaysUpdateHTMLDocumentNamedItemMaps, UpdateHTMLDocumentNamedItemMapsOnlyIfDiffersFromNameAttribute };
    void updateIdForDocument(HTMLDocument&, const AtomicString& oldId, const AtomicString& newId, HTMLDocumentNamedItemMapsUpdatingCondition);
    void updateLabel(TreeScope&, const AtomicString& oldForAttributeValue, const AtomicString& newForAttributeValue);

    ExceptionOr<Node*> insertAdjacent(const String& where, Ref<Node>&& newChild);

    //void scrollByUnits(int units, ScrollGranularity);

    NodeType nodeType() const final;
    bool childTypeAllowed(NodeType) const final;

    void setAttributeInternal(unsigned index, const QualifiedName&, const AtomicString& value, SynchronizationOfLazyAttribute);
    void addAttributeInternal(const QualifiedName&, const AtomicString& value, SynchronizationOfLazyAttribute);
    void removeAttributeInternal(unsigned index, SynchronizationOfLazyAttribute);

    LayoutRect absoluteEventBounds(bool& boundsIncludeAllDescendantElements, bool& includesFixedPositionElements);
    LayoutRect absoluteEventBoundsOfElementAndDescendants(bool& includesFixedPositionElements);

#if ENABLE(TREE_DEBUGGING)
    void formatForDebugger(char* buffer, unsigned length) const override;
#endif

    // The cloneNode function is private so that non-virtual cloneElementWith/WithoutChildren are used instead.
    Ref<Node> cloneNodeInternal(Document&, CloningOperation) override;
    virtual Ref<Element> cloneElementWithoutAttributesAndChildren(Document&);

    const RenderStyle& resolveComputedStyle();
    const RenderStyle& resolvePseudoElementStyle(PseudoId);

    bool rareDataStyleAffectedByEmpty() const;
    bool rareDataStyleAffectedByFocusWithin() const;
    bool rareDataChildrenAffectedByHover() const;
    bool rareDataStyleAffectedByActive() const;
    bool rareDataChildrenAffectedByDrag() const;
    bool rareDataChildrenAffectedByLastChildRules() const;
    bool rareDataChildrenAffectedByBackwardPositionalRules() const;
    bool rareDataChildrenAffectedByPropertyBasedBackwardPositionalRules() const;
    unsigned rareDataChildIndex() const;

    SpellcheckAttributeState spellcheckAttributeState() const;

    void createUniqueElementData();

    ElementRareData* elementRareData() const;
    ElementRareData& ensureElementRareData();

    void detachAllAttrNodesFromElement();
    void detachAttrNodeFromElementWithValue(Attr*, const AtomicString& value);

    // Anyone thinking of using this should call document instead of ownerDocument.
    void ownerDocument() const = delete;

    void attachAttributeNodeIfNeeded(Attr&);

    QualifiedName m_tagName;
    RefPtr<ElementData> m_elementData;
};

inline bool Node::hasAttributes() const
{
    return is<Element>(*this) && downcast<Element>(*this).hasAttributes();
}

inline NamedNodeMap* Node::attributes() const
{
    return is<Element>(*this) ? &downcast<Element>(*this).attributes() : nullptr;
}

inline Element* Node::parentElement() const
{
    ContainerNode* parent = parentNode();
    return is<Element>(parent) ? downcast<Element>(parent) : nullptr;
}

inline const Element* Element::rootElement() const
{
    if (isConnected())
        return document().documentElement();

    const Element* highest = this;
    while (highest->parentElement())
        highest = highest->parentElement();
    return highest;
}

inline bool Element::hasAttributeWithoutSynchronization(const QualifiedName& name) const
{
    ASSERT(fastAttributeLookupAllowed(name));
    return elementData() && findAttributeByName(name);
}

inline const AtomicString& Element::attributeWithoutSynchronization(const QualifiedName& name) const
{
    ASSERT(fastAttributeLookupAllowed(name));
    if (elementData()) {
        if (const Attribute* attribute = findAttributeByName(name))
            return attribute->value();
    }
    return nullAtom();
}

inline bool Element::hasAttributesWithoutUpdate() const
{
    return elementData() && !elementData()->isEmpty();
}

inline const AtomicString& Element::idForStyleResolution() const
{
    return hasID() ? elementData()->idForStyleResolution() : nullAtom();
}

inline const AtomicString& Element::getIdAttribute() const
{
    //if (hasID())
        //return elementData()->findAttributeByName(HTMLNames::idAttr)->value();
    return nullAtom();
}

inline const AtomicString& Element::getNameAttribute() const
{
    //if (hasName())
       // return elementData()->findAttributeByName(HTMLNames::nameAttr)->value();
    return nullAtom();
}

inline void Element::setIdAttribute(const AtomicString& value)
{
    //setAttributeWithoutSynchronization(HTMLNames::idAttr, value);
}

inline const SpaceSplitString& Element::classNames() const
{
    ASSERT(hasClass());
    ASSERT(elementData());
    return elementData()->classNames();
}

inline unsigned Element::attributeCount() const
{
    ASSERT(elementData());
    return elementData()->length();
}

inline const Attribute& Element::attributeAt(unsigned index) const
{
    ASSERT(elementData());
    return elementData()->attributeAt(index);
}

inline const Attribute* Element::findAttributeByName(const QualifiedName& name) const
{
    ASSERT(elementData());
    return elementData()->findAttributeByName(name);
}

inline bool Element::hasID() const
{
    return elementData() && elementData()->hasID();
}

inline bool Element::hasClass() const
{
    return elementData() && elementData()->hasClass();
}

inline bool Element::hasName() const
{
    return elementData() && elementData()->hasName();
}

inline UniqueElementData& Element::ensureUniqueElementData()
{
    if (!elementData() || !elementData()->isUnique())
        createUniqueElementData();
    return static_cast<UniqueElementData&>(*m_elementData);
}

inline bool shouldIgnoreAttributeCase(const Element& element)
{
    return element.isHTMLElement() && element.document().isHTMLDocument();
}

inline void Element::setHasFocusWithin(bool flag)
{
    if (hasFocusWithin() == flag)
        return;
    setFlag(flag, HasFocusWithin);
    if (styleAffectedByFocusWithin())
        invalidateStyleForSubtree();
}

} // namespace WebCore

SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::Element)
    static bool isType(const WebCore::Node& node) { return node.isElementNode(); }
    static bool isType(const WebCore::EventTarget& target) { return is<WebCore::Node>(target) && isType(downcast<WebCore::Node>(target)); }
SPECIALIZE_TYPE_TRAITS_END()