text:
// Copyright 2008 Google Inc.

#include <stdio.h>
#include <vector>

#include "talk/base/gunit.h"
#include "talk/base/logging.h"
#include "talk/base/thread.h"
#include "talk/media/base/fakemediaprocessor.h"
#include "talk/media/base/fakevideocapturer.h"
#include "talk/media/base/testutils.h"
#include "talk/media/base/videocapturer.h"
#include "talk/media/base/videoprocessor.h"

// If HAS_I420_FRAME is not defined the video capturer will not be able to
// provide OnVideoFrame-callbacks since they require cricket::CapturedFrame to
// be decoded as a cricket::VideoFrame (i.e. an I420 frame). This functionality
// only exist if HAS_I420_FRAME is defined below. I420 frames are also a
// requirement for the VideoProcessors so they will not be called either.
#if defined(HAVE_WEBRTC_VIDEO)
#define HAS_I420_FRAME
#endif

using cricket::FakeVideoCapturer;

const int kMsCallbackWait = 500;
// For HD only the height matters.
const int kMinHdHeight = 720;

// Sets the elapsed time in the video frame to 0.
class VideoProcessor0 : public cricket::VideoProcessor {
 public:
  virtual void OnFrame(uint32 /*ssrc*/, cricket::VideoFrame* frame,
                       bool* drop_frame) {
    frame->SetElapsedTime(0u);
  }
};

// Adds one to the video frame's elapsed time. Note that VideoProcessor0 and
// VideoProcessor1 are not commutative.
class VideoProcessor1 : public cricket::VideoProcessor {
 public:
  virtual void OnFrame(uint32 /*ssrc*/, cricket::VideoFrame* frame,
                       bool* drop_frame) {
    int64 elapsed_time = frame->GetElapsedTime();
    frame->SetElapsedTime(elapsed_time + 1);
  }
};

class VideoCapturerTest
    : public sigslot::has_slots<>,
      public testing::Test {
 public:
  VideoCapturerTest()
      : capture_state_(cricket::CS_STOPPED),
        num_state_changes_(0),
        video_frames_received_(0),
        last_frame_elapsed_time_(0) {
    capturer_.SignalVideoFrame.connect(this, &VideoCapturerTest::OnVideoFrame);
    capturer_.SignalStateChange.connect(this,
                                        &VideoCapturerTest::OnStateChange);
  }

 protected:
  void OnVideoFrame(cricket::VideoCapturer*, const cricket::VideoFrame* frame) {
    ++video_frames_received_;
    last_frame_elapsed_time_ = frame->GetElapsedTime();
  }
  void OnStateChange(cricket::VideoCapturer*,
                     cricket::CaptureState capture_state) {
    capture_state_ = capture_state;
    ++num_state_changes_;
  }
  cricket::CaptureState capture_state() { return capture_state_; }
  int num_state_changes() { return num_state_changes_; }
  int video_frames_received() const {
    return video_frames_received_;
  }
  int64 last_frame_elapsed_time() const { return last_frame_elapsed_time_; }

  cricket::FakeVideoCapturer capturer_;
  cricket::CaptureState capture_state_;
  int num_state_changes_;
  int video_frames_received_;
  int64 last_frame_elapsed_time_;
};

TEST_F(VideoCapturerTest, CaptureState) {
  EXPECT_EQ(cricket::CS_RUNNING, capturer_.Start(cricket::VideoFormat(
      640,
      480,
      cricket::VideoFormat::FpsToInterval(30),
      cricket::FOURCC_I420)));
  EXPECT_TRUE(capturer_.IsRunning());
  EXPECT_EQ_WAIT(cricket::CS_RUNNING, capture_state(), kMsCallbackWait);
  EXPECT_EQ(1, num_state_changes());
  capturer_.Stop();
  EXPECT_EQ_WAIT(cricket::CS_STOPPED, capture_state(), kMsCallbackWait);
  EXPECT_EQ(2, num_state_changes());
  capturer_.Stop();
  talk_base::Thread::Current()->ProcessMessages(100);
  EXPECT_EQ(2, num_state_changes());
}

TEST_F(VideoCapturerTest, TestFourccMatch) {
  cricket::VideoFormat desired(640, 480,
                               cricket::VideoFormat::FpsToInterval(30),
                               cricket::FOURCC_ANY);
  cricket::VideoFormat best;
  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
  EXPECT_EQ(640, best.width);
  EXPECT_EQ(480, best.height);
  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);

  desired.fourcc = cricket::FOURCC_MJPG;
  EXPECT_FALSE(capturer_.GetBestCaptureFormat(desired, &best));

  desired.fourcc = cricket::FOURCC_I420;
  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
}

TEST_F(VideoCapturerTest, TestResolutionMatch) {
  cricket::VideoFormat desired(1920, 1080,
                               cricket::VideoFormat::FpsToInterval(30),
                               cricket::FOURCC_ANY);
  cricket::VideoFormat best;
  // Ask for FHD 1920x1080. Get HD 1280x720 which is the highest.
  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
  EXPECT_EQ(1280, best.width);
  EXPECT_EQ(720, best.height);
  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);

  desired.width = 360;
  desired.height = 250;
  // Ask for a little higher than QVGA. Get QVGA.
  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
  EXPECT_EQ(320, best.width);
  EXPECT_EQ(240, best.height);
  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);

  desired.width = 480;
  desired.height = 270;
  // Ask for HVGA. Get VGA.
  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
  EXPECT_EQ(640, best.width);
  EXPECT_EQ(480, best.height);
  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);

  desired.width = 320;
  desired.height = 240;
  // Ask for QVGA. Get QVGA.
  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
  EXPECT_EQ(320, best.width);
  EXPECT_EQ(240, best.height);
  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);

  desired.width = 80;
  desired.height = 60;
  // Ask for lower than QQVGA. Get QQVGA, which is the lowest.
  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
  EXPECT_EQ(160, best.width);
  EXPECT_EQ(120, best.height);
  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
}

TEST_F(VideoCapturerTest, TestHDResolutionMatch) {
  // Add some HD formats
  std::vector<cricket::VideoFormat> formats;
  formats.push_back(cricket::VideoFormat(320, 240,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  formats.push_back(cricket::VideoFormat(640, 480,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  formats.push_back(cricket::VideoFormat(960, 544,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  formats.push_back(cricket::VideoFormat(2592, 1944,
      cricket::VideoFormat::FpsToInterval(15), cricket::FOURCC_I420));
  capturer_.ResetSupportedFormats(formats);

  cricket::VideoFormat desired(960, 720,
                               cricket::VideoFormat::FpsToInterval(30),
                               cricket::FOURCC_ANY);
  cricket::VideoFormat best;
  // Ask for 960x720. Get qHD
  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
  EXPECT_EQ(960, best.width);
  EXPECT_EQ(544, best.height);
  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);

  desired.width = 360;
  desired.height = 250;
  // Ask for a litter higher than QVGA. Get QVGA.
  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
  EXPECT_EQ(320, best.width);
  EXPECT_EQ(240, best.height);
  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);

  desired.width = 480;
  desired.height = 270;
  // Ask for HVGA. Get VGA.
  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
  EXPECT_EQ(640, best.width);
  EXPECT_EQ(480, best.height);
  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);

  desired.width = 320;
  desired.height = 240;
  // Ask for QVGA. Get QVGA.
  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
  EXPECT_EQ(320, best.width);
  EXPECT_EQ(240, best.height);
  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);

  desired.width = 160;
  desired.height = 120;
  // Ask for lower than QVGA. Get QVGA, which is the lowest.
  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
  EXPECT_EQ(320, best.width);
  EXPECT_EQ(240, best.height);
  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);

  desired.width = 1280;
  desired.height = 720;
  // Ask for HD. Get qHD.
  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
  EXPECT_EQ(960, best.width);
  EXPECT_EQ(544, best.height);
  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);

  desired.width = 1920;
  desired.height = 1080;
  // Ask for 1080p. Get 2592x1944x15.
  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
  EXPECT_EQ(2592, best.width);
  EXPECT_EQ(1944, best.height);
  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(15), best.interval);
}

// Some cameras support 320x240 and 320x640. Verify we choose 320x240.
TEST_F(VideoCapturerTest, TestStrangeFormats) {
  std::vector<cricket::VideoFormat> supported_formats;
  supported_formats.push_back(cricket::VideoFormat(320, 240,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  supported_formats.push_back(cricket::VideoFormat(320, 640,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  capturer_.ResetSupportedFormats(supported_formats);

  std::vector<cricket::VideoFormat> required_formats;
  required_formats.push_back(cricket::VideoFormat(320, 240,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  required_formats.push_back(cricket::VideoFormat(320, 200,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  required_formats.push_back(cricket::VideoFormat(320, 180,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  cricket::VideoFormat best;
  for (size_t i = 0; i < required_formats.size(); ++i) {
    EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[i], &best));
    EXPECT_EQ(320, best.width);
    EXPECT_EQ(240, best.height);
  }

  supported_formats.clear();
  supported_formats.push_back(cricket::VideoFormat(320, 640,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  supported_formats.push_back(cricket::VideoFormat(320, 240,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  capturer_.ResetSupportedFormats(supported_formats);

  for (size_t i = 0; i < required_formats.size(); ++i) {
    EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[i], &best));
    EXPECT_EQ(320, best.width);
    EXPECT_EQ(240, best.height);
  }
}

// Some cameras only have very low fps. Verify we choose something sensible.
TEST_F(VideoCapturerTest, TestPoorFpsFormats) {
  // all formats are low framerate
  std::vector<cricket::VideoFormat> supported_formats;
  supported_formats.push_back(cricket::VideoFormat(320, 240,
      cricket::VideoFormat::FpsToInterval(10), cricket::FOURCC_I420));
  supported_formats.push_back(cricket::VideoFormat(640, 480,
      cricket::VideoFormat::FpsToInterval(7), cricket::FOURCC_I420));
  supported_formats.push_back(cricket::VideoFormat(1280, 720,
      cricket::VideoFormat::FpsToInterval(2), cricket::FOURCC_I420));
  capturer_.ResetSupportedFormats(supported_formats);

  std::vector<cricket::VideoFormat> required_formats;
  required_formats.push_back(cricket::VideoFormat(320, 240,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  required_formats.push_back(cricket::VideoFormat(640, 480,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  cricket::VideoFormat best;
  for (size_t i = 0; i < required_formats.size(); ++i) {
    EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[i], &best));
    EXPECT_EQ(required_formats[i].width, best.width);
    EXPECT_EQ(required_formats[i].height, best.height);
  }

  // Increase framerate of 320x240.  Expect low fps VGA avoided.
  // Except on Mac, where QVGA is avoid due to aspect ratio.
  supported_formats.clear();
  supported_formats.push_back(cricket::VideoFormat(320, 240,
      cricket::VideoFormat::FpsToInterval(15), cricket::FOURCC_I420));
  supported_formats.push_back(cricket::VideoFormat(640, 480,
      cricket::VideoFormat::FpsToInterval(7), cricket::FOURCC_I420));
  supported_formats.push_back(cricket::VideoFormat(1280, 720,
      cricket::VideoFormat::FpsToInterval(2), cricket::FOURCC_I420));
  capturer_.ResetSupportedFormats(supported_formats);

  for (size_t i = 0; i < required_formats.size(); ++i) {
    EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[i], &best));
    EXPECT_EQ(320, best.width);
    EXPECT_EQ(240, best.height);
  }
}

// Some cameras support same size with different frame rates. Verify we choose
// the frame rate properly.
TEST_F(VideoCapturerTest, TestSameSizeDifferentFpsFormats) {
  std::vector<cricket::VideoFormat> supported_formats;
  supported_formats.push_back(cricket::VideoFormat(320, 240,
      cricket::VideoFormat::FpsToInterval(10), cricket::FOURCC_I420));
  supported_formats.push_back(cricket::VideoFormat(320, 240,
      cricket::VideoFormat::FpsToInterval(20), cricket::FOURCC_I420));
  supported_formats.push_back(cricket::VideoFormat(320, 240,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  capturer_.ResetSupportedFormats(supported_formats);

  std::vector<cricket::VideoFormat> required_formats = supported_formats;
  cricket::VideoFormat best;
  for (size_t i = 0; i < required_formats.size(); ++i) {
    EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[i], &best));
    EXPECT_EQ(320, best.width);
    EXPECT_EQ(240, best.height);
    EXPECT_EQ(required_formats[i].interval, best.interval);
  }
}

// Some cameras support the correct resolution but at a lower fps than
// we'd like.  This tests we get the expected resolution and fps.
TEST_F(VideoCapturerTest, TestFpsFormats) {
  // We have VGA but low fps.  Choose VGA, not HD
  std::vector<cricket::VideoFormat> supported_formats;
  supported_formats.push_back(cricket::VideoFormat(1280, 720,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  supported_formats.push_back(cricket::VideoFormat(640, 480,
      cricket::VideoFormat::FpsToInterval(15), cricket::FOURCC_I420));
  supported_formats.push_back(cricket::VideoFormat(640, 400,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  supported_formats.push_back(cricket::VideoFormat(640, 360,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  capturer_.ResetSupportedFormats(supported_formats);

  std::vector<cricket::VideoFormat> required_formats;
  required_formats.push_back(cricket::VideoFormat(640, 480,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_ANY));
  required_formats.push_back(cricket::VideoFormat(640, 480,
      cricket::VideoFormat::FpsToInterval(20), cricket::FOURCC_ANY));
  required_formats.push_back(cricket::VideoFormat(640, 480,
      cricket::VideoFormat::FpsToInterval(10), cricket::FOURCC_ANY));
  cricket::VideoFormat best;

  // expect 30 fps to choose 15 fps format
  EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[0], &best));
  EXPECT_EQ(640, best.width);
  EXPECT_EQ(480, best.height);
  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(15), best.interval);

  // expect 20 fps to choose 15 fps format
  EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[1], &best));
  EXPECT_EQ(640, best.width);
  EXPECT_EQ(480, best.height);
  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(15), best.interval);

  // expect 10 fps to choose 15 fps format but set fps to 10
  EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[2], &best));
  EXPECT_EQ(640, best.width);
  EXPECT_EQ(480, best.height);
  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(10), best.interval);

  // We have VGA 60 fps and 15 fps.  Choose best fps.
  supported_formats.clear();
  supported_formats.push_back(cricket::VideoFormat(1280, 720,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  supported_formats.push_back(cricket::VideoFormat(640, 480,
      cricket::VideoFormat::FpsToInterval(60), cricket::FOURCC_MJPG));
  supported_formats.push_back(cricket::VideoFormat(640, 480,
      cricket::VideoFormat::FpsToInterval(15), cricket::FOURCC_I420));
  supported_formats.push_back(cricket::VideoFormat(640, 400,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  supported_formats.push_back(cricket::VideoFormat(640, 360,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  capturer_.ResetSupportedFormats(supported_formats);

  // expect 30 fps to choose 60 fps format, but will set best fps to 30
  EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[0], &best));
  EXPECT_EQ(640, best.width);
  EXPECT_EQ(480, best.height);
  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);

  // expect 20 fps to choose 60 fps format, but will set best fps to 20
  EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[1], &best));
  EXPECT_EQ(640, best.width);
  EXPECT_EQ(480, best.height);
  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(20), best.interval);

  // expect 10 fps to choose 10 fps
  EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[2], &best));
  EXPECT_EQ(640, best.width);
  EXPECT_EQ(480, best.height);
  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(10), best.interval);
}

TEST_F(VideoCapturerTest, TestRequest16x10_9) {
  std::vector<cricket::VideoFormat> supported_formats;
  // We do not support HD, expect 4x3 for 4x3, 16x10, and 16x9 requests.
  supported_formats.push_back(cricket::VideoFormat(640, 480,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  supported_formats.push_back(cricket::VideoFormat(640, 400,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  supported_formats.push_back(cricket::VideoFormat(640, 360,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  capturer_.ResetSupportedFormats(supported_formats);

  std::vector<cricket::VideoFormat> required_formats = supported_formats;
  cricket::VideoFormat best;
  // Expect 4x3, 16x10, and 16x9 requests are respected.
  for (size_t i = 0; i < required_formats.size(); ++i) {
    EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[i], &best));
    EXPECT_EQ(required_formats[i].width, best.width);
    EXPECT_EQ(required_formats[i].height, best.height);
  }

  // We do not support 16x9 HD, expect 4x3 for 4x3, 16x10, and 16x9 requests.
  supported_formats.clear();
  supported_formats.push_back(cricket::VideoFormat(960, 720,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  supported_formats.push_back(cricket::VideoFormat(640, 480,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  supported_formats.push_back(cricket::VideoFormat(640, 400,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  supported_formats.push_back(cricket::VideoFormat(640, 360,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  capturer_.ResetSupportedFormats(supported_formats);

  // Expect 4x3, 16x10, and 16x9 requests are respected.
  for (size_t i = 0; i < required_formats.size(); ++i) {
    EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[i], &best));
    EXPECT_EQ(required_formats[i].width, best.width);
    EXPECT_EQ(required_formats[i].height, best.height);
  }

  // We support 16x9HD, Expect 4x3, 16x10, and 16x9 requests are respected.
  supported_formats.clear();
  supported_formats.push_back(cricket::VideoFormat(1280, 720,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  supported_formats.push_back(cricket::VideoFormat(640, 480,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  supported_formats.push_back(cricket::VideoFormat(640, 400,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  supported_formats.push_back(cricket::VideoFormat(640, 360,
      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
  capturer_.ResetSupportedFormats(supported_formats);

  // Expect 4x3 for 4x3 and 16x10 requests.
  for (size_t i = 0; i < required_formats.size() - 1; ++i) {
    EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[i], &best));
    EXPECT_EQ(required_formats[i].width, best.width);
    EXPECT_EQ(required_formats[i].height, best.height);
  }

  // Expect 16x9 for 16x9 request.
  EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[2], &best));
  EXPECT_EQ(640, best.width);
  EXPECT_EQ(360, best.height);
}

#if defined(HAS_I420_FRAME)
TEST_F(VideoCapturerTest, VideoFrame) {
  EXPECT_EQ(cricket::CS_RUNNING, capturer_.Start(cricket::VideoFormat(
      640,
      480,
      cricket::VideoFormat::FpsToInterval(30),
      cricket::FOURCC_I420)));
  EXPECT_TRUE(capturer_.IsRunning());
  EXPECT_EQ(0, video_frames_received());
  EXPECT_TRUE(capturer_.CaptureFrame());
  EXPECT_EQ(1, video_frames_received());
}

TEST_F(VideoCapturerTest, ProcessorChainTest) {
  VideoProcessor0 processor0;
  VideoProcessor1 processor1;
  EXPECT_EQ(cricket::CS_RUNNING, capturer_.Start(cricket::VideoFormat(
      640,
      480,
      cricket::VideoFormat::FpsToInterval(30),
      cricket::FOURCC_I420)));
  EXPECT_TRUE(capturer_.IsRunning());
  EXPECT_EQ(0, video_frames_received());
  // First processor sets elapsed time to 0.
  capturer_.AddVideoProcessor(&processor0);
  // Second processor adds 1 to the elapsed time. I.e. a frames elapsed time
  // should now always be 1 (and not 0).
  capturer_.AddVideoProcessor(&processor1);
  EXPECT_TRUE(capturer_.CaptureFrame());
  EXPECT_EQ(1, video_frames_received());
  EXPECT_EQ(1u, last_frame_elapsed_time());
  capturer_.RemoveVideoProcessor(&processor1);
  EXPECT_TRUE(capturer_.CaptureFrame());
  // Since processor1 has been removed the elapsed time should now be 0.
  EXPECT_EQ(2, video_frames_received());
  EXPECT_EQ(0u, last_frame_elapsed_time());
}

TEST_F(VideoCapturerTest, ProcessorDropFrame) {
  cricket::FakeMediaProcessor dropping_processor_;
  dropping_processor_.set_drop_frames(true);
  EXPECT_EQ(cricket::CS_RUNNING, capturer_.Start(cricket::VideoFormat(
      640,
      480,
      cricket::VideoFormat::FpsToInterval(30),
      cricket::FOURCC_I420)));
  EXPECT_TRUE(capturer_.IsRunning());
  EXPECT_EQ(0, video_frames_received());
  // Install a processor that always drop frames.
  capturer_.AddVideoProcessor(&dropping_processor_);
  EXPECT_TRUE(capturer_.CaptureFrame());
  EXPECT_EQ(0, video_frames_received());
}
#endif  // HAS_I420_FRAME

bool HdFormatInList(const std::vector<cricket::VideoFormat>& formats) {
  for (std::vector<cricket::VideoFormat>::const_iterator found =
           formats.begin(); found != formats.end(); ++found) {
    if (found->height >= kMinHdHeight) {
      return true;
    }
  }
  return false;
}

TEST_F(VideoCapturerTest, Whitelist) {
  // The definition of HD only applies to the height. Set the HD width to the
  // smallest legal number to document this fact in this test.
  const int kMinHdWidth = 1;
  cricket::VideoFormat hd_format(kMinHdWidth,
                                 kMinHdHeight,
                                 cricket::VideoFormat::FpsToInterval(30),
                                 cricket::FOURCC_I420);
  cricket::VideoFormat vga_format(640, 480,
                                  cricket::VideoFormat::FpsToInterval(30),
                                  cricket::FOURCC_I420);
  std::vector<cricket::VideoFormat> formats = *capturer_.GetSupportedFormats();
  formats.push_back(hd_format);

  // Enable whitelist.  Expect HD not in list.
  capturer_.set_enable_camera_list(true);
  capturer_.ResetSupportedFormats(formats);
  EXPECT_TRUE(HdFormatInList(*capturer_.GetSupportedFormats()));
  capturer_.ConstrainSupportedFormats(vga_format);
  EXPECT_FALSE(HdFormatInList(*capturer_.GetSupportedFormats()));

  // Disable whitelist.  Expect HD in list.
  capturer_.set_enable_camera_list(false);
  capturer_.ResetSupportedFormats(formats);
  EXPECT_TRUE(HdFormatInList(*capturer_.GetSupportedFormats()));
  capturer_.ConstrainSupportedFormats(vga_format);
  EXPECT_TRUE(HdFormatInList(*capturer_.GetSupportedFormats()));
}


text:
import Ember from 'ember';

const { Route } = Ember;

export default Route.extend({
  databaseSchema: Ember.inject.service(),
  visibilityTypes: Ember.inject.service(),

  afterModel() {
    return Ember.RSVP.all([
      this.get('databaseSchema').fetchTables(),
      this.get('visibilityTypes').fetchVisibilityTypes()
    ]);
  }
});

redpajama_set_name: RedPajamaGithub


text:
package tp.pr5.Resources;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JPanel;

import tp.pr5.logic.Board;
import tp.pr5.logic.Game;
import tp.pr5.logic.GravityMove;

public class Resources {

	// Global Variables and Constants

	public static int
		DIMX_GRAVITY = 10, DIMY_GRAVITY = 10,
		SLEEPTIME = 1000; // Is not final, cause we can modify it on the program

	public static final String
		RESOURCES_URL = "src/icons/";

	public static final int
		MAX_STACK = 100,
		TILES_TO_WIN = 4,
		DIMX_CONNECT4 = 7, DIMY_CONNECT4 = 6,
		DIMX_COMPLICA = 4, DIMY_COMPLICA = 7,
		DIMX_REVERSI = 8, DIMY_REVERSI = 8;

	// Comprueba si alguna de las celdas empty, con el color del jugador actual, forman un posible movimiento

	public static boolean canMakeMove(Board b, Counter color) { // como se usa desde main y se usa una read only board no usar ningun metodo que sea para cambiar la tabla
		int column = 1, row = 1, total = 0;
		boolean valid = false;

		while(column <= b.getWidth() && !valid) {
			row = 1;
			while(row <= b.getHeight() && !valid) {
				if (b.getPosition(column, row) == Counter.EMPTY) {
					total = 0;
					total += checkHorizontal(b, color, column, row);	// True  = Left
					total += checkVertical(b, color, column, row); 	// False = Down
					total += checkDiagonal1(b, color, column, row);  // False = Bottom Right
					total += checkDiagonal2(b, color, column, row);  // False = Bottom Left

					if (total >= 1) valid = true;
				}
				row++;
			}
			column++;
		}
		return valid;
	}

	// CheckHorizontal: Function to Check left and right colors given a fixed position

	public static int checkHorizontal(Board b, Counter color, int x, int y) {
		int total = 0, accumulateTiles = 0, auxColumn = x;
		Counter nextColor = changeColor(color);

		// Check Left tiles
		while((auxColumn >= 1) && (b.getPosition(auxColumn - 1, y) == nextColor)) {
			auxColumn--; accumulateTiles++;
		}
		if (accumulateTiles >= 1 && (b.getPosition(auxColumn - 1, y) == color)) {
			total++;
		}
		// Check Right tiles
		auxColumn = x;
		while((auxColumn <= b.getWidth()) && (b.getPosition(auxColumn + 1, y) == nextColor)) {
			auxColumn++; accumulateTiles++;
		}
		if (accumulateTiles >= 1 && (b.getPosition(auxColumn + 1, y) == color)) {
			total++;
		}

		return total; // Sumar el número total de celdas válidas (formadas)
	}

	// CheckVertical: Function to Check top and bottom colors given a fixed position

	public static int checkVertical(Board b, Counter color, int x, int y) {
		int total = 0, accumulateTiles = 0, auxRow = y;
		Counter nextColor = changeColor(color);

		// Check up Tiles
		while((auxRow >= 1) && (b.getPosition(x, auxRow - 1) == nextColor)) {
			auxRow--; accumulateTiles++;
		}
		if (accumulateTiles >= 1 && (b.getPosition(x, auxRow - 1) == color)) {
			total++;
		}
		// Check Down tiles
		auxRow = y;
		while((auxRow <= b.getHeight()) && (b.getPosition(x, auxRow + 1) == nextColor)) {
			auxRow++; accumulateTiles++;
		}
		if (accumulateTiles >= 1 && (b.getPosition(x, auxRow + 1) == color)) {
			total++;
		}

		return total;
	}

	// CheckDiagonal1: Function to Check diagonals given a fixed position

	public static int checkDiagonal1(Board b, Counter color, int x, int y) {
		int total = 0, accumulateTiles = 0, auxColumn = x, auxRow = y;
		Counter nextColor = changeColor(color);

		// Check UpLeft
		while((auxColumn >= 1) && (auxRow >= 1) && (b.getPosition(auxColumn - 1, auxRow - 1) == nextColor)) {
			auxColumn--; auxRow--; accumulateTiles++;
		}
		if (accumulateTiles >= 1 && (b.getPosition(auxColumn - 1, auxRow - 1) == color)) {
			total++;
		}

		// Check DownRight
		auxColumn = x; auxRow = y;
		while((auxColumn <= b.getWidth()) && (auxRow <= b.getHeight()) && (b.getPosition(auxColumn + 1, auxRow + 1) == nextColor)) {
			auxColumn++; auxRow++; accumulateTiles++;
		}
		if (accumulateTiles >= 1 && (b.getPosition(auxColumn + 1, auxRow + 1) == color)) {
			total++;
		}

		return total;
	}

	// CheckDiagonal2: Function to Check diagonals given a fixed position

	public static int checkDiagonal2(Board b, Counter color, int x, int y) {
		int total = 0, accumulateTitles = 0, auxColumn = x, auxRow = y;
		Counter nextColor = changeColor(color);

		// Check Up Right
		while((auxColumn <= b.getWidth()) && (auxRow >= 1) && (b.getPosition(auxColumn + 1, auxRow - 1) == nextColor)) {
			auxColumn++; auxRow--; accumulateTitles++;
		}
		if (accumulateTitles >= 1 && (b.getPosition(auxColumn + 1, auxRow - 1) == color)) {
			total++;
		}

		// Check Bottom Left
		auxColumn = x; auxRow = y;
		while((auxColumn >= 1) && (auxRow <= b.getHeight()) && (b.getPosition(auxColumn - 1, auxRow + 1) == nextColor)) {
			auxColumn--; auxRow++; accumulateTitles++;
		}
		if (accumulateTitles >= 1 && (b.getPosition(auxColumn - 1, auxRow + 1) == color)) {
			total++;
		}

		return total;
	}

	public static Counter changeColor(Counter c) {
		if (c == Counter.WHITE) return Counter.BLACK;
		else if(c == Counter.BLACK) return Counter.WHITE;
		else return Counter.EMPTY;
	}

	// Checks if there's an empty cell given a column

	public static int freeRowPosition(int col, Board board) {
		int row = -1,
			y 	=  board.getHeight();
		boolean empty = false;

		while ((!empty) && (y >= 1)) {
			if (board.getPosition(col,y) == Counter.EMPTY) {
				empty = true;
				row = y;
			}
			else {
				y--;
			}
		}
		return row;
	}

	// This functions is used for the Undo Function
	// Which returns the first row occupied (means that is the last movement of the user in that colum)

	public static int occupiedRowPosition(Board board, int col) {
		int row, height, y = 1;
		boolean occupied = false;

		height = row = board.getHeight();

		while (!occupied && y <= height) {
			if (board.getPosition(col, y) != Counter.EMPTY)
				occupied = true;
				row = y;
			y++;
		}
		return row;
	}

	public static void whoMoves(Game game) {
		if (game.getTurn() == Counter.WHITE)
			System.out.println("White to move");
		else if (game.getTurn() == Counter.BLACK)
			System.out.println("Black to move");
	}

	public static void moveColumnDown(Board board, int column) {
		for (int i = board.getHeight(); i > 1; i--){
			board.setPosition(column, i, board.getPosition(column , i - 1));
		}
	}
	public static void moveColumnUp(Board board, int column) {
		for (int i = 1 ; i < board.getHeight(); i++){
			board.setPosition(column, i, board.getPosition(column, i + 1));
		}
	}

	// He tenido que escribir de nuevo la función de pedro para
	// que funcione el conecta 4.

	public static boolean fullColumn(int column, Board b) {
		boolean isFull = true;
		int row = b.getHeight();

		while ((isFull) && (row >= 1)) {
			if (b.getPosition(column, row) == Counter.EMPTY)
				isFull = false;
			row--;
		}

		return isFull;
	}

	public static void setGravityDimX(int x) {
		DIMX_GRAVITY = x;
	}
	public static void setGravityDimY(int y){
		DIMY_GRAVITY = y;
	}

	public static GravityMove applyGravity(Board board, int column, int row, Counter counter){
		int distRight, distLeft, distUp, distBottom;
		distLeft = column - 1;
		distRight = DIMX_GRAVITY - column;
		distUp = row-1;
		distBottom = DIMY_GRAVITY - row;
		double minDIM = 0;
		int minDimInt = 0;
		GravityMove movement = null;

		minDIM = Math.min(DIMX_GRAVITY, DIMY_GRAVITY);
		minDimInt = (int) Math.ceil(minDIM/2);

		if((distLeft == distRight) && (distUp == distBottom)) {
			movement = displaceCounter(board, column, row, 0, 0, counter);
		}
		else if (distLeft == distRight) {
			if (distUp < distBottom) {
				movement = displaceCounter(board, column, row, 0, -1, counter);
			}
			else if (distBottom < distUp) {
				movement = displaceCounter(board, column, row, 0, +1, counter);
			}
		}
		else if (distUp == distBottom) {
			if (distLeft < distRight) {
				movement = displaceCounter(board, column, row, -1, 0, counter);
			}
			else if (distLeft > distRight) {
				movement = displaceCounter(board, column, row, +1, 0, counter);
			}
		}
		else if ((distUp == distRight) && (distUp < minDimInt)) {
			movement = displaceCounter(board, column, row, +1, -1, counter);
		}
		else if ((distUp == distLeft) && (distUp < minDimInt)) {
			movement = displaceCounter(board, column, row, -1, -1, counter);
		}
		else if ((distBottom == distRight) && (distBottom < minDimInt)) {
			movement = displaceCounter(board, column, row, +1, +1, counter);
		}
		else if ((distBottom == distLeft) && (distBottom < minDimInt)){
			movement = displaceCounter(board, column, row, -1, +1, counter);
		}
		else if ((distUp < distRight) && (distUp < distLeft) && (distUp < distBottom)) {
			movement = displaceCounter(board, column, row, 0, -1, counter);
		}
		else if ((distRight < distUp) && (distRight < distLeft) && (distRight < distBottom)) {
			movement = displaceCounter(board, column, row, +1, 0, counter);
		}
		else if ((distLeft < distRight) && (distLeft < distUp) && (distLeft < distBottom)) {
			movement = displaceCounter(board, column, row, -1, 0, counter);
		}
		else if ((distBottom < distRight) && (distBottom < distLeft) && (distBottom < distUp)) {
			movement = displaceCounter(board, column, row, 0, +1, counter);
		}
		return movement;
	}

	public static GravityMove displaceCounter(Board board, int posCol, int posRow, int movCol, int movRow, Counter counter) {
		boolean ocuppy = false;
		int actualRow = posRow, actualColumn = posCol;

		if ((movCol == 0) && (movRow == 0))
			board.setPosition(actualColumn, actualRow, counter);

		while (!ocuppy){
			if (actualColumn > 1 && actualColumn < DIMX_GRAVITY && actualRow > 1 && actualRow < DIMY_GRAVITY) {
				if (board.getPosition(actualColumn + movCol, actualRow + movRow) != Counter.EMPTY) {
					ocuppy = true;
				}
				else{
					actualColumn += movCol;
					actualRow += movRow;
				}
			}
			else {
				ocuppy = true;
			}
		}
		return new GravityMove(actualColumn, actualRow, counter);
	}

	public static void help() {
		System.out.println("The available commands are:");
		System.out.println("");
		System.out.println("MAKE A MOVE: place a counter on the board.");
		System.out.println("UNDO: undo the last move of the game.");
		System.out.println("RESTART: restart the game.");
		System.out.println("PLAY [c4|co|gr] [dimX dimY]: change the type of game.");
		System.out.println("PLAYER [white|black] [human|random]: change the type of player.");
		System.out.println("EXIT: exit the application.");
		System.out.println("HELP: show this help.");
	}

	public static void helpInit() {
		System.out.println("usage: tp.pr3.Main [-g <game>] [-h] [-x <columnNumber>] [-y <rowNumber>]");
		System.out.println(" -g,--game <game>           Type of game (c4, co, gr, rv). By default, c4.");
		System.out.println(" -h,--help                  Displays this help.");
		System.out.println(" -u,--ui<tipo>              Type of interface (console,window).");
		System.out.println("                            by default console.");
		System.out.println(" -x,--dimX <columnNumber>   Number of columns on the board (Gravity only).");
		System.out.println("                            By default, 10.");
		System.out.println(" -y,--dimY <rowNumber>      Number of rows on the board (Gravity only). By");
		System.out.println("                            default, 10.");
	}

	//METHODS FOR THE VIEW
	public static GridBagConstraints configureConstraint(int fill, int gridX, int gridY, double weightX, double weightY) {
		GridBagConstraints c = new GridBagConstraints();
		c.fill = fill;
		c.gridx = gridX;
		c.gridy = gridY;
		c.weightx = weightX;
		c.weighty = weightY;
		return c;
	}

	public static JPanel createPanel(Color color, int x, int y) {
		JPanel panel = new JPanel();
		panel.setBackground(color);
		panel.setPreferredSize(new Dimension(x,y));
		panel.setVisible(true);
		return panel;
	}

	public static JButton createAuxButton(int w, int h, String name, String fileName, Color c, boolean border) {
		JButton b = new JButton();
		b.setBackground(c);
		b.setPreferredSize(new Dimension(w, h));
		if (fileName != "") b.setIcon(new ImageIcon(fileName));
		if (name != "") b.setText(name);
		if (!border) 	b.setBorder(null);
		return b;
	}

/*
	public static int menu(Game game, Scanner input) {
		int option = - 1;
		boolean valid = false;
		String optionString = "", lowerCaseStr;

		while (!valid) {

			 game.getBoard().printBoard();

			whoMoves(game);
			System.out.print ("Please enter a command: ");

			optionString = input.nextLine().toUpperCase();
			lowerCaseStr = optionString.toLowerCase();
			String[] words = optionString.split(" ");

			if (words.length == 1) {
				if (words[0].equals("UNDO")) {
					option = 1;
				}
				else if (words[0].equals("RESTART")) {
					option = 2;
				}
				else if (words[0].equals("EXIT")) {
					option = 3;
				}
				else if (words[0].equals("HELP")){
					option = 7;
				}
				else {
					System.err.println(lowerCaseStr + ": command not understood, please try again");
				}
			}
			else if (words.length == 2) {
				if (words[0].equals("PLAY")) {
					if (words[1].equals("C4")) {
						option = 4;
					}
					else if (words[1].equals("CO")) {
						option = 5;
					}
					else if (words[1].equals("RV")) {
						option = 12;
					}
					else {
						System.err.println(lowerCaseStr + ": command not understood, please try again");
					}
				}
				else {
					System.err.println(lowerCaseStr + ": command not understood, please try again");
				}
			}
			else if (words.length == 3) {
				if (words[0].equals("MAKE")) {
					if (words[1].equals("A")) {
						if (words[2].equals("MOVE")) {
							option = 0;
						}
						else {
							System.err.println(lowerCaseStr + ": command not understood, please try again");
						}
					}
					else {
						System.err.println(lowerCaseStr + ": command not understood, please try again");
					}

				}
				else if (words[0].equals("PLAYER")) {
					if (words[1].equals("WHITE")) {
						if(words[2].equals("HUMAN")) {
							option = 8; // WHITE HUMAN
						}
						else {
							option = 9; // WHITE RANDOM
						}
					}
					else if (words[1].equals("BLACK")) {
						if(words[2].equals("HUMAN")) {
							option = 10; // BLACK HUMAN
						}
						else {
							option = 11; // BLACK RANDOM
						}
					}
				}
				else {
					System.err.println(lowerCaseStr + ": command not understood, please try again");
				}

			}
			else if (words.length == 4){
				if (words[0].equals("PLAY")) {
					if (words[1].equals("GR")) {
						try {
							   Integer.parseInt(words[2]);
							   Integer.parseInt(words[3]);
							   if (Integer.parseInt(words[2]) < 1){
								   setGravityDimX(1);
							   }
							   else{
								   setGravityDimX(Integer.parseInt(words[2]));
							   }
							   if (Integer.parseInt(words[3]) < 1){
								   setGravityDimY(1);
							   }
							   else{
								   setGravityDimY(Integer.parseInt(words[3]));
							   }
							   option = 6;
							} catch (NumberFormatException e) {
								System.err.println(lowerCaseStr + ": command not understood, please try again");
							}
					}
				}
			}
			else {
				System.err.println(lowerCaseStr + ": command not understood, please try again");
			}

			if ((option >= 0) && (option <= 12)) {
				valid = true;
			}
		}
		return option;
	}
*/

}


text:
<?php

use Hubzero\Content\Migration\Base;

// No direct access
defined('_HZEXEC_') or die();

/**
 * Migration script for removing duplicate plugin entries while retaining proper parameters
 **/
class Migration20150828113153Core extends Base
{
	/**
	 * Up
	 **/
	public function up()
	{
		if ($this->db->tableExists('#__extensions'))
		{
			$query = "SELECT MIN(extension_id) AS min, MAX(extension_id) as max, folder, element FROM `#__extensions` WHERE type='plugin' GROUP BY folder, element HAVING COUNT(*) > 1;";

			$this->db->setQuery($query);

			if ($results = $this->db->loadObjectList())
			{
				foreach ($results as $result)
				{
					if (empty($result) || empty($result->min) || empty($result->max) || empty($result->folder) || empty($result->element))
					{
						continue;
					}

					$query = "UPDATE `#__extensions` AS e1, `#__extensions` e2 SET e1.params = e2.params WHERE e1.extension_id = " . $this->db->quote($result->min) . " AND e2.extension_id = " . $this->db->quote($result->max) . ";";
					$this->db->setQuery($query);
					$this->db->query();

					$query = "DELETE FROM `#__extensions` WHERE folder = " . $this->db->quote($result->folder) . " AND element = " . $this->db->quote($result->element) . " AND extension_id != " . $this->db->quote($result->min);
					$this->db->setQuery($query);
					$this->db->query();
				}
			}
		}
	}

	/**
	 * Down
	 **/
	public function down()
	{

	}
}


text:
layout: post
title: Two Ways to Script and Modularize GraphQL Schema
key: 20190307
tags: GraphQL Schema
---
# GraphQL Schema 的两种写法及模块化

上个礼拜学习了一下 GraphQL。我觉得入门的一个难点就是写 Schema,跟着 YouTube 教学视频和文档,学习了两种写法,一种是用 GraphQL 的 Schema 语法写,另一种是用 GraphQLSchema 构造器写。

## Using GraphQL Schema Language

内置的 Schema 语法是写在模板字符串里的,由 `buildSchema()` 创建。

<!--more-->

举个例子,有两个数据类型:`User` 和 `Post`,要求可以查询 User 和 Posts、可以创建 User 和 Post:

```js
const express = require('express');
const graphqlHTTP = require('express-graphql');
const { buildSchema } = require('graphql');

var rootSchema = buildSchema(`
  type User {
    id: String
    name: String
  }

  type Post {
    id: String
    title: String
    content: String
  }

  input PostInput {
    title: String,
    content: String
  }

  type RootQuery {
    user(id: String): User,
    posts: [Posts]
  }

  type RootMutation {
    createUser(name: String): User,
    createPost(newPost: PostInput): Post
  }
`);

const rootResolvers = {
  user: (id) => {
    return user;
  },
  posts: () => {
    return posts;
  },
  createUser: (name) => {
    return user;
  }
  createPost: (args) => {
    return post;
  }
};

const app = express();
app.use('/graphql', graphqlHTTP({
  schema: rootSchema,
  rootValue: rootResolvers,
  graphiql: true,
}));
app.listen(4000);
```

`rootResolvers` 中的 `user` 和 `posts` 是查询的方法,方法名要和 `schema` 中 `RootQuery` 一样,前者是具体实现,后者类似于登记声明。`createUser` 和 `createPost` 对数据进行了变更,所以要放在 `RootMutation` 中定义。对 `createPost` 的参数输入定义了一个新的类型 `PostInput`,也写在了 `schema` 中,用 `input` 定义,如果输入参数多,可用此法。

`rootResolvers` 中方法的具体内容省略了。

再看:

```js
app.use('/graphql', graphqlHTTP({
  schema: rootSchema,
  rootValue: rootResolvers,
  graphiql: true,
}));
```

把定义好的 `rootSchema` 和 `rootResolvers` 填进去,GraphQL 服务就可以使用了。

## Modularize for Schema Language

上文例子简单明了,但并不适于一般正经项目。因为数据不可能这么少,难道各种定义和方法都写在一个文件里?必须模块化。

首先 `rootSchema` 和 `rootResolvers` 要分成两个文件吧。然后继续细分。`rootSchema` 可分为 `userSchema` 和 `postSchema` 两种。以 `postSchema` 为例:

```js
module.exports.postSchema = `
type Post {
  id: String
  title: String
  content: String
}

input PostInput {
  title: String
  content: String
}`;

module.exports.postQuery = `posts: [Post]`;
module.exports.postMutation = `createPost(newPost: PostInput): Post`
```

因为 `schema` 实际由 Type、Query、Mutation 三种定义构成,所以每个 `schema` 模块最好定义三块内容。

全部定义好,在 `rootSchema` 中整合:

```js
const { userSchema, userQuery, userMutation } = require('./user.schema');
const { postSchema, postQuery, postMutation } = require('./post.schema');

const schemas = buildSchema(
  ``.concat(
    userSchema,
    postSchema,
    `
    type RootQuery {
      ${userQuery},
      ${postQuery}
    }

    type RootMutation {
      ${userMutation},
      ${postMutation}
    }

    schema {
      query: RootQuery
      mutation: RootMutation
    }
    `
  )
);

module.exports = schemas;
```

因为是字符串,所以可用 `concat` 来连接。一拼接就像样多了。

接着是 `rootResolvers` 的模块化。这个相对简单,就是定义好每种类型的 Query 和 Mutation 方法,然后整合起来:

```js
const userResolver = require('./user.resolver');
const postResolver = require('./post.resolver');

const resolvers = {
  ...userResolver,
  ...postResolver
}

module.exports = resolvers;
```

最后,原来的写法就变成了:

```js
const express = require('express');
const graphqlHTTP = require('express-graphql');
const rootSchema = require('./schemas/index');
const rootResolvers = require('./resolvers/index');

const app = express();
app.use('/graphql', graphqlHTTP({
   schema: rootSchema,
   rootValue: rootResolvers,
   graphiql: true,
}));

app.listen(4000);
```

## Using GraphQLSchema Constructor

用 Schema 语法有时觉得还是太 low 了,能不能更面向对象一些,更 programmatically 一些?可以的,用 `GraphQLSchema()` 来构造 schema。

写在一个文件里是这样的:

```js
const express = require('express');
const graphqlHTTP = require('express-graphql');
const graphql = require('graphql');

const UserType = new graphql.GraphQLObjectType({
  name: 'User',
  fields: {
    id: { type: graphql.GraphQLString },
    name: { type: graphql.GraphQLString },
  }
});

const PostType = new graphql.GraphQLObjectType({
  name: 'Post',
  fields: {
    id: { type: graphql.GraphQLString },
    title: { type: graphql.GraphQLString },
    content: { type: graphql.GraphQLString }
  }
});

const PostInput = new GraphQLInputObjectType({
  name: 'PostInput',
  fields: {
    title: { type: GraphQLString },
    content: { type: GraphQLString }
  }
});

const queryType = new graphql.GraphQLObjectType({
  name: 'Query',
  fields: {
    users: {
      type: new GraphQLList(UserType),
      args: null,
      resolve: (_, {id}) => {
        return user;
      }
    },
    createUser: {
      type: {
        name: { type: GraphQLString }
      },
      resolve: (_, args) => {
        return newUser;
      }
    },
    posts: {
      type: new GraphQLList(PostType),
      args: null,
      resolve: async () => {
        return posts;
      }
    },
    createPost: {
      type: PostType,
      args: {
        newPost: { type: PostInput }
      },
      resolve: (_, args) => {
        return newPost;
      }
    }
  }
});

var schema = new graphql.GraphQLSchema({query: queryType});

var app = express();
app.use('/graphql', graphqlHTTP({
  schema: schema,
  graphiql: true,
}));
app.listen(4000);
console.log('Running a GraphQL API server at localhost:4000/graphql');
```

注意它定义属性类型是用 `{ type: graphql.GraphQLString }` 这种方式的,还有数组类型是 `new GraphQLList(YourType)`。

## Modularize for GraphQLSchema

接下来用模块化的方式重构。方式很简单,Type 放在一个文件夹里,每个 Model 一个文件,Query 也是按 Model 分,再用一个 Index 整合。

Type 的例子:

```js
// post.type.js

const PostType = new GraphQLObjectType({
  name: 'Post',
  fields: () => ({
    id: { type: GraphQLString },
    title: { type: GraphQLString },
    content: { type: GraphQLString }
  })
});

module.exports.PostType = PostType;
```

输入参数类型可用 `GraphQLInputObjectType()` 定义:

```js
const PostInput = new GraphQLInputObjectType({
  name: 'PostInput',
  fields: {
    title: { type: GraphQLString },
    content: { type: GraphQLString }
  }
});

module.exports.PostInput = PostInput;
```

Query 的例子(具体定义省略):

```js
const { PostType, PostInput } = require('../types/post.query');

const postQueries = {
  posts: {
    type: new GraphQLList(PostType),
    args: null,
    resolve: async () => {
      return posts;
    }
  },
  createPost: {
    type: PostType,
    args: {
      newPost: { type: PostInput }
    },
    resolve: (_, args) => {
      return newPost;
    }
  }
}

module.exports.postQueries = postQueries;
```

整合 Query 如下所示:

```js
// queries/index.js

const { GraphQLObjectType } = require('graphql');
const { userQueries } = require('../queries/user.query');
const { postQueries } = require('../queries/post.query');

const QueryType = new GraphQLObjectType({
  name: 'QueryType',
  fields: {
    ...userQueries,
    ...postQueries
  }
});

module.exports = QueryType;
```

然后再用来构造 Schema:

```js
// schema.constructor.js

const { GraphQLSchema } = require('graphql');
const QueryType = require('./queries/index');

module.exports = new GraphQLSchema({
  query: QueryType
});
```

最后:

```js
const express = require('express');
const graphqlHTTP = require('express-graphql');
const schemaConstructor = require('./schema.constructor');

const app = express();
app.use('/graphql', graphqlHTTP({
   schema: schemaConstructor
   graphiql: true,
}));

app.listen(4000);
```

注意此时已经不需要 `rootValue` 了。

## To Be Continued

写了这么多,只是刚好用来查询而已,只能算入了个门。觉得 GraphQL 真的挺方便,我将继续深入学习和使用。


text:
Extending Numba
===============

.. module:: numba.extending

This chapter describes how to extend Numba to make it recognize and support
additional operations, functions or types.  Numba provides two categories
of APIs to this end:

* The high-level APIs provide abstracted entry points which are sufficient
  for simple uses.  They require little knowledge of Numba's internal
  compilation chain.

* The low-level APIs reflect Numba's internal compilation chain and allow
  flexible interaction with its various layers, but require more effort
  and experience with Numba internals.

It may be helpful for readers of this chapter to also read some of the
documents in the :doc:`developer manual </developer/index>`, especially
the :doc:`architecture document </developer/architecture>`.

.. toctree::

   high-level.rst
   low-level.rst
   interval-example.rst


text:
using System;
using System.Collections;
using R7.Documents.Models;
using R7.Documents.Tests.Models;
using R7.Documents.ViewModels;
using Xunit;

namespace R7.Documents.Tests.ViewModels
{
    public class DocumentViewModelComparerTests
    {
        [Fact]
        void DateComparisonTest ()
        {
            var colOrder = new DocumentsSortColumn {
                ColumnName = DocumentDisplayColumn.COLUMN_SORTORDER,
                Direction = SortDirection.Ascending
            };

            var colModifiedDate = new DocumentsSortColumn {
                ColumnName = DocumentDisplayColumn.COLUMN_MODIFIEDDATE,
                Direction = SortDirection.Ascending
            };

            var today = DateTime.Today;
            var docA = new TestDocumentViewModel (new TestDocument {
                ModifiedDate = today.AddMinutes (20)
            });

            var docB = new TestDocumentViewModel (new TestDocument {
                ModifiedDate = today.AddMinutes (10)
            });

            var comparer1 = new DocumentViewModelComparer (new ArrayList {colOrder, colModifiedDate});
            Assert.Equal (0, comparer1.Compare (docA, docA));

            // A > B
            Assert.Equal (1, comparer1.Compare (docA, docB));

            var comparer2 = new DocumentViewModelComparer (new ArrayList {colModifiedDate, colOrder});
            Assert.Equal (0, comparer2.Compare (docB, docB));

            // A == B, even if A.ModifiedDate != B.ModifiedDate
            Assert.True (docA.ModifiedDate != docB.ModifiedDate);
            Assert.Equal (0, comparer2.Compare (docA, docB));
        }
    }
}


text:
/**
 * Autogenerated by Thrift
 *
 * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
 */

#import <Foundation/Foundation.h>

#import <TProtocol.h>
#import <TApplicationException.h>
#import <TProtocolUtil.h>
#import <TProcessor.h>

#import "Errors.h"

@implementation ErrorsConstants
+ (void) initialize {
}
@end

@implementation EDAMUserException

- (id) init
{
  return [super initWithName: @"EDAMUserException" reason: @"unknown" userInfo: nil];
}
#if TARGET_OS_IPHONE || (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
@dynamic errorCode;
@dynamic parameter;
#endif

- (id) initWithErrorCode: (int) errorCode parameter: (NSString *) parameter
{
  self = [self init];
  __errorCode = errorCode;
  __errorCode_isset = YES;
  __parameter = [parameter retain];
  __parameter_isset = YES;
  return self;
}

- (id) initWithCoder: (NSCoder *) decoder
{
  self = [super initWithCoder: decoder];
  if ([decoder containsValueForKey: @"errorCode"])
  {
    __errorCode = [decoder decodeIntForKey: @"errorCode"];
    __errorCode_isset = YES;
  }
  if ([decoder containsValueForKey: @"parameter"])
  {
    __parameter = [[decoder decodeObjectForKey: @"parameter"] retain];
    __parameter_isset = YES;
  }
  return self;
}

- (void) encodeWithCoder: (NSCoder *) encoder
{
  [super encodeWithCoder: encoder];
  if (__errorCode_isset)
  {
    [encoder encodeInt: __errorCode forKey: @"errorCode"];
  }
  if (__parameter_isset)
  {
    [encoder encodeObject: __parameter forKey: @"parameter"];
  }
}

- (void) dealloc
{
  [__parameter release];
  [super dealloc];
}

- (int) errorCode {
  return __errorCode;
}

- (void) setErrorCode: (int) errorCode {
  __errorCode = errorCode;
  __errorCode_isset = YES;
}

- (BOOL) errorCodeIsSet {
  return __errorCode_isset;
}

- (void) unsetErrorCode {
  __errorCode_isset = NO;
}

- (NSString *) parameter {
  return [[__parameter retain] autorelease];
}

- (void) setParameter: (NSString *) parameter {
  [parameter retain];
  [__parameter release];
  __parameter = parameter;
  __parameter_isset = YES;
}

- (BOOL) parameterIsSet {
  return __parameter_isset;
}

- (void) unsetParameter {
  [__parameter release];
  __parameter = nil;
  __parameter_isset = NO;
}

- (void) read: (id <TProtocol>) inProtocol
{
  NSString * fieldName;
  int fieldType;
  int fieldID;

  [inProtocol readStructBeginReturningName: NULL];
  while (true)
  {
    [inProtocol readFieldBeginReturningName: &fieldName type: &fieldType fieldID: &fieldID];
    if (fieldType == TType_STOP) {
      break;
    }
    switch (fieldID)
    {
      case 1:
        if (fieldType == TType_I32) {
          int fieldValue = [inProtocol readI32];
          [self setErrorCode: fieldValue];
        } else {
          [TProtocolUtil skipType: fieldType onProtocol: inProtocol];
        }
        break;
      case 2:
        if (fieldType == TType_STRING) {
          NSString * fieldValue = [inProtocol readString];
          [self setParameter: fieldValue];
        } else {
          [TProtocolUtil skipType: fieldType onProtocol: inProtocol];
        }
        break;
      default:
        [TProtocolUtil skipType: fieldType onProtocol: inProtocol];
        break;
    }
    [inProtocol readFieldEnd];
  }
  [inProtocol readStructEnd];
}

- (void) write: (id <TProtocol>) outProtocol {
  [outProtocol writeStructBeginWithName: @"EDAMUserException"];
  if (__errorCode_isset) {
    [outProtocol writeFieldBeginWithName: @"errorCode" type: TType_I32 fieldID: 1];
    [outProtocol writeI32: __errorCode];
    [outProtocol writeFieldEnd];
  }
  if (__parameter_isset) {
    if (__parameter != nil) {
      [outProtocol writeFieldBeginWithName: @"parameter" type: TType_STRING fieldID: 2];
      [outProtocol writeString: __parameter];
      [outProtocol writeFieldEnd];
    }
  }
  [outProtocol writeFieldStop];
  [outProtocol writeStructEnd];
}

- (NSString *) description {
  NSMutableString * ms = [NSMutableString stringWithString: @"EDAMUserException("];
  [ms appendString: @"errorCode:"];
  [ms appendFormat: @"%i", __errorCode];
  [ms appendString: @",parameter:"];
  [ms appendFormat: @"\"%@\"", __parameter];
  [ms appendString: @")"];
  return [NSString stringWithString: ms];
}

@end

@implementation EDAMSystemException

- (id) init
{
  return [super initWithName: @"EDAMSystemException" reason: @"unknown" userInfo: nil];
}
#if TARGET_OS_IPHONE || (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
@dynamic errorCode;
@dynamic message;
#endif

- (id) initWithErrorCode: (int) errorCode message: (NSString *) message
{
  self = [self init];
  __errorCode = errorCode;
  __errorCode_isset = YES;
  __message = [message retain];
  __message_isset = YES;
  return self;
}

- (id) initWithCoder: (NSCoder *) decoder
{
  self = [super initWithCoder: decoder];
  if ([decoder containsValueForKey: @"errorCode"])
  {
    __errorCode = [decoder decodeIntForKey: @"errorCode"];
    __errorCode_isset = YES;
  }
  if ([decoder containsValueForKey: @"message"])
  {
    __message = [[decoder decodeObjectForKey: @"message"] retain];
    __message_isset = YES;
  }
  return self;
}

- (void) encodeWithCoder: (NSCoder *) encoder
{
  [super encodeWithCoder: encoder];
  if (__errorCode_isset)
  {
    [encoder encodeInt: __errorCode forKey: @"errorCode"];
  }
  if (__message_isset)
  {
    [encoder encodeObject: __message forKey: @"message"];
  }
}

- (void) dealloc
{
  [__message release];
  [super dealloc];
}

- (int) errorCode {
  return __errorCode;
}

- (void) setErrorCode: (int) errorCode {
  __errorCode = errorCode;
  __errorCode_isset = YES;
}

- (BOOL) errorCodeIsSet {
  return __errorCode_isset;
}

- (void) unsetErrorCode {
  __errorCode_isset = NO;
}

- (NSString *) message {
  return [[__message retain] autorelease];
}

- (void) setMessage: (NSString *) message {
  [message retain];
  [__message release];
  __message = message;
  __message_isset = YES;
}

- (BOOL) messageIsSet {
  return __message_isset;
}

- (void) unsetMessage {
  [__message release];
  __message = nil;
  __message_isset = NO;
}

- (void) read: (id <TProtocol>) inProtocol
{
  NSString * fieldName;
  int fieldType;
  int fieldID;

  [inProtocol readStructBeginReturningName: NULL];
  while (true)
  {
    [inProtocol readFieldBeginReturningName: &fieldName type: &fieldType fieldID: &fieldID];
    if (fieldType == TType_STOP) {
      break;
    }
    switch (fieldID)
    {
      case 1:
        if (fieldType == TType_I32) {
          int fieldValue = [inProtocol readI32];
          [self setErrorCode: fieldValue];
        } else {
          [TProtocolUtil skipType: fieldType onProtocol: inProtocol];
        }
        break;
      case 2:
        if (fieldType == TType_STRING) {
          NSString * fieldValue = [inProtocol readString];
          [self setMessage: fieldValue];
        } else {
          [TProtocolUtil skipType: fieldType onProtocol: inProtocol];
        }
        break;
      default:
        [TProtocolUtil skipType: fieldType onProtocol: inProtocol];
        break;
    }
    [inProtocol readFieldEnd];
  }
  [inProtocol readStructEnd];
}

- (void) write: (id <TProtocol>) outProtocol {
  [outProtocol writeStructBeginWithName: @"EDAMSystemException"];
  if (__errorCode_isset) {
    [outProtocol writeFieldBeginWithName: @"errorCode" type: TType_I32 fieldID: 1];
    [outProtocol writeI32: __errorCode];
    [outProtocol writeFieldEnd];
  }
  if (__message_isset) {
    if (__message != nil) {
      [outProtocol writeFieldBeginWithName: @"message" type: TType_STRING fieldID: 2];
      [outProtocol writeString: __message];
      [outProtocol writeFieldEnd];
    }
  }
  [outProtocol writeFieldStop];
  [outProtocol writeStructEnd];
}

- (NSString *) description {
  NSMutableString * ms = [NSMutableString stringWithString: @"EDAMSystemException("];
  [ms appendString: @"errorCode:"];
  [ms appendFormat: @"%i", __errorCode];
  [ms appendString: @",message:"];
  [ms appendFormat: @"\"%@\"", __message];
  [ms appendString: @")"];
  return [NSString stringWithString: ms];
}

@end

@implementation EDAMNotFoundException

- (id) init
{
  return [super initWithName: @"EDAMNotFoundException" reason: @"unknown" userInfo: nil];
}
#if TARGET_OS_IPHONE || (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
@dynamic identifier;
@dynamic key;
#endif

- (id) initWithIdentifier: (NSString *) identifier key: (NSString *) key
{
  self = [self init];
  __identifier = [identifier retain];
  __identifier_isset = YES;
  __key = [key retain];
  __key_isset = YES;
  return self;
}

- (id) initWithCoder: (NSCoder *) decoder
{
  self = [super initWithCoder: decoder];
  if ([decoder containsValueForKey: @"identifier"])
  {
    __identifier = [[decoder decodeObjectForKey: @"identifier"] retain];
    __identifier_isset = YES;
  }
  if ([decoder containsValueForKey: @"key"])
  {
    __key = [[decoder decodeObjectForKey: @"key"] retain];
    __key_isset = YES;
  }
  return self;
}

- (void) encodeWithCoder: (NSCoder *) encoder
{
  [super encodeWithCoder: encoder];
  if (__identifier_isset)
  {
    [encoder encodeObject: __identifier forKey: @"identifier"];
  }
  if (__key_isset)
  {
    [encoder encodeObject: __key forKey: @"key"];
  }
}

- (void) dealloc
{
  [__identifier release];
  [__key release];
  [super dealloc];
}

- (NSString *) identifier {
  return [[__identifier retain] autorelease];
}

- (void) setIdentifier: (NSString *) identifier {
  [identifier retain];
  [__identifier release];
  __identifier = identifier;
  __identifier_isset = YES;
}

- (BOOL) identifierIsSet {
  return __identifier_isset;
}

- (void) unsetIdentifier {
  [__identifier release];
  __identifier = nil;
  __identifier_isset = NO;
}

- (NSString *) key {
  return [[__key retain] autorelease];
}

- (void) setKey: (NSString *) key {
  [key retain];
  [__key release];
  __key = key;
  __key_isset = YES;
}

- (BOOL) keyIsSet {
  return __key_isset;
}

- (void) unsetKey {
  [__key release];
  __key = nil;
  __key_isset = NO;
}

- (void) read: (id <TProtocol>) inProtocol
{
  NSString * fieldName;
  int fieldType;
  int fieldID;

  [inProtocol readStructBeginReturningName: NULL];
  while (true)
  {
    [inProtocol readFieldBeginReturningName: &fieldName type: &fieldType fieldID: &fieldID];
    if (fieldType == TType_STOP) {
      break;
    }
    switch (fieldID)
    {
      case 1:
        if (fieldType == TType_STRING) {
          NSString * fieldValue = [inProtocol readString];
          [self setIdentifier: fieldValue];
        } else {
          [TProtocolUtil skipType: fieldType onProtocol: inProtocol];
        }
        break;
      case 2:
        if (fieldType == TType_STRING) {
          NSString * fieldValue = [inProtocol readString];
          [self setKey: fieldValue];
        } else {
          [TProtocolUtil skipType: fieldType onProtocol: inProtocol];
        }
        break;
      default:
        [TProtocolUtil skipType: fieldType onProtocol: inProtocol];
        break;
    }
    [inProtocol readFieldEnd];
  }
  [inProtocol readStructEnd];
}

- (void) write: (id <TProtocol>) outProtocol {
  [outProtocol writeStructBeginWithName: @"EDAMNotFoundException"];
  if (__identifier_isset) {
    if (__identifier != nil) {
      [outProtocol writeFieldBeginWithName: @"identifier" type: TType_STRING fieldID: 1];
      [outProtocol writeString: __identifier];
      [outProtocol writeFieldEnd];
    }
  }
  if (__key_isset) {
    if (__key != nil) {
      [outProtocol writeFieldBeginWithName: @"key" type: TType_STRING fieldID: 2];
      [outProtocol writeString: __key];
      [outProtocol writeFieldEnd];
    }
  }
  [outProtocol writeFieldStop];
  [outProtocol writeStructEnd];
}

- (NSString *) description {
  NSMutableString * ms = [NSMutableString stringWithString: @"EDAMNotFoundException("];
  [ms appendString: @"identifier:"];
  [ms appendFormat: @"\"%@\"", __identifier];
  [ms appendString: @",key:"];
  [ms appendFormat: @"\"%@\"", __key];
  [ms appendString: @")"];
  return [NSString stringWithString: ms];
}

@end


text:
var Emitter = require('events').EventEmitter,
    path = require('path'),
    im = require('imagemagick');

/*
 * filesystem storage
 * - save request.files to uploadPath
 * - if request.files.each has many versions
 *    process each version
 *    store each version to uploadPath
 *
 * aws storage
 * - upload request.files to S3
 * - if request.files.each has many versions
 *    process each version
 *    store each version to S3
 */
var Storage = require('./storage');
var FileSystemStorage = Storage.FileSystemStorage,
    AwsStorage = Storage.AwsStorage;

function generateNameWithVersion(file, version) {
  var extname = path.extname(file);
  return path.basename(file, extname) + "-" + version + extname;
}

function hasFiles(request) {
  return request.files && Object.keys(request.files).length > 0;
}

module.exports = function(options) {
  var uploadPath = options.path;
  var nameGenerator = options.nameGenerator;

  var emitter = new Emitter();
  var storage;

  if (options.storage && options.storage.name === "aws") {
    storage = new AwsStorage(options.storage.options);
  }
  else {
    storage = new FileSystemStorage(uploadPath);
  }

  return processUpload;

  function processUpload(req, res, next) {
    if (hasFiles(req)) {

      var counter = Object.keys(req.files).length;

      emitter.on('save', function() {
        counter -= 1;
        // console.log("Successfully saved, remain: %d", counter);
        if (counter === 0) {
          next();
        }
      });

      var end = res.end;
      res.end = function(data, encoding) {
        end.call(res, data, encoding);
        // process different versions
        if (req.files) {
          var versionCounter = 0;

          Object.keys(req.files).forEach(function(key) {
            var file = req.files[key];

            if (file.versions) {
              var versions = Object.keys(file.versions);
              versionCounter += versions.length;
              versions.forEach(function(type) {
                process.nextTick(function() {
                  processVersion(file, type);
                });
              });
            }
          });

          if (versionCounter > 0) {
            emitter.on('processed', function() {
              versionCounter -= 1;

              if (0 === versionCounter && req.files.versionMonitor) {
                req.files.versionMonitor.emit('complete');
              }
            });
          }
        }
      };

      for(var key in req.files) {
        var file = req.files[key];
        if ('function' === typeof nameGenerator) {
          file.dest = nameGenerator(file);
        }
        storage.save(file, mainFileStorageHandler(file, next));
      }
    }
    else {
      next();
    }
  }

  // Attributes `file.uri`, `file.name`, 'file.versions' can be used by controller code
  // others are attrs (like `file.dest`) ONLY for internal use
  function mainFileStorageHandler(file, next) {
    return function(err, dest) {
      if (err) {
        next(err);
      }
      else {
        file.uri = dest;
        file.name = path.basename(dest);

        emitter.emit('save');
      }
    };
  }

  function processVersion(file, version) {
    var size = file.versions[version];
    var destName = generateNameWithVersion(file.uri, version);
    var dest = path.join(path.dirname(file.path), destName);

    im.resize({
        srcPath: file.path,
        dstPath: dest,
        width: size[0],
        height: size[1]
      },
      resizeHandler(dest, destName, file.type));
  }

  function resizeHandler(src, dest, type) {
    var file = { path: src, dest: dest, type: type };

    return function(err) {
      if(err) {
        //TODO handle error
        //  remove src can occur an error for testing
        // console.log("Error in resizeHandler: %s", err);
      }
      else {
        storage.save(file, function(err, dest) {
          //TODO handle error
          // console.log('Processed file: %s', dest);
          emitter.emit('processed');
        });
      }
    };
  }
};


text:
#include "mirtk/Cofstream.h"

#include "mirtk/Config.h"       // WINDOWS
#include "mirtk/CommonConfig.h" // MIRTK_Common_WITH_ZLIB
#include "mirtk/Memory.h"       // swap16, swap32

#if MIRTK_Common_WITH_ZLIB
#  include <zlib.h>
#endif

namespace mirtk {

// -----------------------------------------------------------------------------
Cofstream::Cofstream(const char *fname)
:
  _File(nullptr),
  #if MIRTK_Common_WITH_ZLIB
    _ZFile(nullptr),
  #endif
  _Compressed(false),
  _Swapped(GetByteOrder() == LittleEndian)
{
  if (fname) Open(fname);
}

// -----------------------------------------------------------------------------
Cofstream::~Cofstream()
{
  Close();
}

// -----------------------------------------------------------------------------
void Cofstream::Open(const char *fname)
{
  Close();
  size_t len = strlen(fname);
  if (len == 0) {
    Throw(ERR_InvalidArgument, __func__, "Filename is empty");
  }
  if (len > 3 && (strncmp(fname + len-3, ".gz", 3) == 0 || strncmp(fname + len-3, ".GZ", 3) == 0)) {
    #if MIRTK_Common_WITH_ZLIB
      gzFile fp = gzopen(fname, "wb");
      if (fp == nullptr) {
        Throw(ERR_IOError, __func__, "Failed to open file ", fname);
      }
      _ZFile = fp;
      _Compressed = true;
    #else // MIRTK_Common_WITH_ZLIB
      Throw(ERR_IOError, __func__, "Cannot write compressed file when Common module not built WITH_ZLIB");
    #endif // MIRTK_Common_WITH_ZLIB
  } else {
    #ifdef WINDOWS
      errno_t err = fopen_s(&_File, fname, "wb");
      if (err != 0) _File = nullptr;
    #else
      _File = fopen(fname, "wb");
    #endif
    if (_File == nullptr) {
      Throw(ERR_IOError, __func__, "Failed to open file ", fname);
    }
    _Compressed = false;
  }
}

// -----------------------------------------------------------------------------
void Cofstream::Close()
{
  #if MIRTK_Common_WITH_ZLIB
    if (_ZFile != nullptr) {
      gzclose(reinterpret_cast<gzFile>(_ZFile));
      _ZFile = nullptr;
    }
  #endif // MIRTK_Common_WITH_ZLIB
  if (_File != nullptr) {
    fclose(_File);
    _File = nullptr;
  }
}

// -----------------------------------------------------------------------------
int Cofstream::IsCompressed() const
{
  return _Compressed ? 1 : 0;
}

// -----------------------------------------------------------------------------
void Cofstream::IsCompressed(int compressed)
{
  _Compressed = (compressed != 0);
}

// -----------------------------------------------------------------------------
int Cofstream::IsSwapped() const
{
  return _Swapped ? 1 : 0;
}

// -----------------------------------------------------------------------------
void Cofstream::IsSwapped(int swapped)
{
  _Swapped = (swapped != 0);
}

// -----------------------------------------------------------------------------
bool Cofstream::Write(const char *data, long offset, long length)
{
  #if MIRTK_Common_WITH_ZLIB
    if (_Compressed) {
      gzFile fp = reinterpret_cast<gzFile>(_ZFile);
      if (offset != -1) {
        if (gztell(fp) > offset) {
          Throw(ERR_IOError, __func__, "Writing compressed files only supports"
                " forward seek (pos=", gztell(fp), ", offset=", offset, ")");
        }
        gzseek(fp, offset, SEEK_SET);
      }
      return (gzwrite(fp, data, length) == length);
    }
  #endif // MIRTK_Common_WITH_ZLIB
  if (offset != -1) fseek(_File, offset, SEEK_SET);
  return (fwrite(data, length, 1, _File) == 1);
}

// -----------------------------------------------------------------------------
bool Cofstream::WriteAsChar(const char data, long offset)
{
  return Write(&data, offset, sizeof(const char));
}

// -----------------------------------------------------------------------------
bool Cofstream::WriteAsChar(const char *data, long length, long offset)
{
  return Write(data, offset, length*sizeof(const char));
}

// -----------------------------------------------------------------------------
bool Cofstream::WriteAsUChar(unsigned char data, long offset)
{
  return Write((const char *)&data, offset, sizeof(unsigned char));
}

// -----------------------------------------------------------------------------
bool Cofstream::WriteAsUChar(const unsigned char *data, long length, long offset)
{
  return Write((const char *)data, offset, length*sizeof(unsigned char));
}

// -----------------------------------------------------------------------------
bool Cofstream::WriteAsShort(short data, long offset)
{
  if (_Swapped) swap16((char *)&data, (char *)&data, 1);
  return Write((const char *)&data, offset, sizeof(short));
}

// -----------------------------------------------------------------------------
bool Cofstream::WriteAsShort(const short *data, long length, long offset)
{
  if (_Swapped) swap16((char *)data, (char *)data, length);
  if (!Write((const char *)data, offset, length*sizeof(short))) return false;
  if (_Swapped) swap16((char *)data, (char *)data, length);
  return true;
}

// -----------------------------------------------------------------------------
bool Cofstream::WriteAsUShort(unsigned short data, long offset)
{
  if (_Swapped) swap16((char *)&data, (char *)&data, 1);
  return Write((const char *)&data, offset, sizeof(unsigned short));
}

// -----------------------------------------------------------------------------
bool Cofstream::WriteAsUShort(const unsigned short *data, long length, long offset)
{
  if (_Swapped) swap16((char *)data, (char *)data, length);
  if (!Write((const char *)data, offset, length*sizeof(unsigned short))) return false;
  if (_Swapped) swap16((char *)data, (char *)data, length);
  return true;
}

// -----------------------------------------------------------------------------
bool Cofstream::WriteAsInt(int data, long offset)
{
  if (_Swapped) swap32((char *)&data, (char *)&data, 1);
  return Write((const char *)&data, offset, sizeof(int));
}

// -----------------------------------------------------------------------------
bool Cofstream::WriteAsInt(const int *data, long length, long offset)
{
  if (_Swapped) swap32((char *)data, (char *)data, length);
  if (!Write((const char *)data, offset, length*sizeof(int))) return false;
  if (_Swapped) swap32((char *)data, (char *)data, length);
  return true;
}

// -----------------------------------------------------------------------------
bool Cofstream::WriteAsUInt(unsigned int data, long offset)
{
  if (_Swapped) swap32((char *)&data, (char *)&data, 1);
  return Write((const char *)&data, offset, sizeof(unsigned int));
}

// -----------------------------------------------------------------------------
bool Cofstream::WriteAsUInt(const unsigned int *data, long length, long offset)
{
  if (_Swapped) swap32((char *)data, (char *)data, length);
  if (!Write((const char *)data, offset, length*sizeof(unsigned int))) return false;
  if (_Swapped) swap32((char *)data, (char *)data, length);
  return true;
}

// -----------------------------------------------------------------------------
bool Cofstream::WriteAsFloat(float data, long offset)
{
  if (_Swapped) swap32((char *)&data, (char *)&data, 1);
  return Write((const char *)&data, offset, sizeof(float));
}

// -----------------------------------------------------------------------------
bool Cofstream::WriteAsFloat(const float *data, long length, long offset)
{
  if (_Swapped) swap32((char *)data, (char *)data, length);
  if (!Write((const char *)data, offset, length*sizeof(float))) return false;
  if (_Swapped) swap32((char *)data, (char *)data, length);
  return true;
}

// -----------------------------------------------------------------------------
bool Cofstream::WriteAsDouble(const double *data, long length, long offset)
{
  if (_Swapped) swap64((char *)data, (char *)data, length);
  if (!Write((const char *)data, offset, length*sizeof(double))) return false;
  if (_Swapped) swap64((char *)data, (char *)data, length);
  return true;
}

// -----------------------------------------------------------------------------
bool Cofstream::WriteAsDouble(double data, long offset)
{
  if (_Swapped) swap64((char *)&data, (char *)&data, 1);
  return Write((const char *)&data, offset, sizeof(double));
}

// -----------------------------------------------------------------------------
bool Cofstream::WriteAsString(const char *data, long offset)
{
  #if MIRTK_Common_WITH_ZLIB
    if (_Compressed) {
      gzFile fp = reinterpret_cast<gzFile>(_ZFile);
      if (offset != -1) gzseek(fp, offset, SEEK_SET);
      return (gzputs(fp, data) > 0);
    }
  #endif // MIRTK_Common_WITH_ZLIB
  if (offset != -1) fseek(_File, offset, SEEK_SET);
  return (fputs(data, _File) != EOF);
}

} // namespace mirtk


text:
package achan.nl.uitstelgedrag.domain.models;

/**
 * Created by Etienne on 18-7-2016.
 */
public class Update {
    public int version;
    public String file;
    public String description;
}


text:
/* Style the tab */
div.tab {
    overflow: hidden;
    border: 1px solid #ccc;
    background-color: #f1f1f1;
}

/* Style the buttons inside the tab */
div.tab a {
    background-color: inherit;
    float: left;
    border: none;
    outline: none;
    cursor: pointer;
    padding: 14px 16px;
    transition: 0.3s;
}

/* Change background color of buttons on hover */
div.tab a:hover {
    background-color: #ddd;
}

/* Create an active/current tablink class */
div.tab a.active {
    background-color: #ccc;
}

/* Style the tab content */
.tabcontent {
    display: none;
    padding: 6px 12px;
    border: 1px solid #ccc;
    border-top: none;
}


text:
package samples.services;

public class GetFullQuoteResponse {

    private static final int COUNT = 365;
    TradingDay[] tradeHistory = null;

    public GetFullQuoteResponse() {
    }

    public GetFullQuoteResponse(String symbol) {
        tradeHistory = new TradingDay[COUNT];
        for (int i=0; i<COUNT; i++) {
            tradeHistory[i] = new TradingDay(i, new GetQuoteResponse(symbol));
        }
    }

    public TradingDay[] getTradeHistory() {
        return tradeHistory;
    }

    public void setTradeHistory(TradingDay[] tradeHistory) {
        this.tradeHistory = tradeHistory;
    }

}


text:
package org.apache.apex.malhar.lib.db.redshift;

import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import org.apache.apex.malhar.lib.fs.FSRecordCompactionOperator;
import org.apache.commons.io.FileUtils;
import com.datatorrent.api.Attribute;
import com.datatorrent.api.Context;
import com.datatorrent.lib.db.jdbc.JdbcTransactionalStore;

import static com.datatorrent.lib.helper.OperatorContextTestHelper.mockOperatorContext;
import static org.mockito.Mockito.when;

public class RedshiftJdbcTransactionalOperatorTest
{
  private String inputDir;
  private static final String FILE_1 = "file1.txt";
  private static final String FILE_2 = "file2.txt";
  private static final String FILE_1_DATA = "460|xkalk|665\n950|xkalk|152\n850|xsblk|252";
  private static final String FILE_2_DATA = "640|xkalk|655\n50|bcklk|52";
  private static FSRecordCompactionOperator.OutputMetaData file1Meta;
  private static FSRecordCompactionOperator.OutputMetaData file2Meta;
  private static List<FSRecordCompactionOperator.OutputMetaData> listOfFiles = new ArrayList<>();
  private static List<String> data = new ArrayList<>();

  public static class TestMeta extends TestWatcher
  {
    public String baseDirectory;
    Context.OperatorContext context;
    @Mock
    public Statement statement;
    @Mock
    public JdbcTransactionalStore store;
    @Mock
    public Connection conn;

    @Override
    protected void starting(org.junit.runner.Description description)
    {
      this.baseDirectory = "target/" + description.getClassName() + "/" + description.getMethodName();

      MockitoAnnotations.initMocks(this);

      try {
        when(store.getConnection()).thenReturn(conn);
        when(conn.createStatement()).thenReturn(statement);
      } catch (SQLException e) {
        throw new RuntimeException(e);
      }
    }

    @Override
    protected void finished(Description description)
    {
      try {
        FileUtils.deleteDirectory(new File(baseDirectory));
      } catch (IOException e) {
        throw new RuntimeException(e);
      }
    }
  }

  @Rule
  public TestMeta testMeta = new TestMeta();

  @Before
  public void setup() throws Exception
  {
    inputDir = testMeta.baseDirectory + File.separator + "input";

    File file1 = new File(inputDir + File.separator + FILE_1);
    file1Meta = new FSRecordCompactionOperator.OutputMetaData(file1.getPath(), file1.getName(), file1.length());
    FileUtils.writeStringToFile(file1, FILE_1_DATA);

    File file2 = new File(inputDir + File.separator + FILE_2);
    file2Meta = new FSRecordCompactionOperator.OutputMetaData(file2.getPath(), file2.getName(), file2.length());
    FileUtils.writeStringToFile(file2, FILE_2_DATA);
  }

  @Test
  public void TestBatchData() throws SQLException, IOException
  {
    RedshiftJdbcTransactionableTestOutputOperator operator = new RedshiftJdbcTransactionableTestOutputOperator();
    operator.setReaderMode("READ_FROM_S3");
    operator.setStore(testMeta.store);
    operator.setAccessKey("accessKey");
    operator.setSecretKey("secretKey");
    operator.setBucketName("bucketName");

    Attribute.AttributeMap attributeMap = new Attribute.AttributeMap.DefaultAttributeMap();
    attributeMap.put(Context.OperatorContext.SPIN_MILLIS, 500);
    attributeMap.put(Context.DAGContext.APPLICATION_PATH, testMeta.baseDirectory);
    testMeta.context = mockOperatorContext(1, attributeMap);;

    operator.setup(testMeta.context);
    operator.beginWindow(1);
    operator.input.process(file1Meta);
    operator.input.process(file2Meta);
    when(testMeta.statement.executeBatch()).thenReturn(executeBatch());
    operator.endWindow();
    Assert.assertEquals("Number of tuples in database", 5, data.size());
  }

  public int[] executeBatch() throws IOException
  {
    for (FSRecordCompactionOperator.OutputMetaData metaData: listOfFiles) {
      data.addAll(FileUtils.readLines(new File(metaData.getPath())));
    }
    return null;
  }

  @Test
  public void VerifyS3Properties()
  {
    RedshiftJdbcTransactionableTestOutputOperator operator = new RedshiftJdbcTransactionableTestOutputOperator();
    operator.setReaderMode("READ_FROM_S3");
    operator.setAccessKey("accessKey");
    operator.setSecretKey("secretKey");
    operator.setBucketName("bucketName");

    Assert.assertNotNull(operator.getBucketName());
  }

  @Test
  public void VerifyEMRProperties()
  {
    RedshiftJdbcTransactionableTestOutputOperator operator = new RedshiftJdbcTransactionableTestOutputOperator();
    operator.setReaderMode("READ_FROM_EMR");
    operator.setAccessKey("accessKey");
    operator.setSecretKey("secretKey");
    operator.setEmrClusterId("emrClusterId");

    Assert.assertNotNull(operator.getEmrClusterId());
  }

  public static class RedshiftJdbcTransactionableTestOutputOperator extends RedshiftJdbcTransactionableOutputOperator
  {
    @Override
    public void processTuple(FSRecordCompactionOperator.OutputMetaData tuple)
    {
      super.processTuple(tuple);
      listOfFiles.add(tuple);
    }
  }
}


text:
"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.xAxis = void 0;

var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));

var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));

var _omitBy = _interopRequireDefault(require("lodash/omitBy"));

var _isNull = _interopRequireDefault(require("lodash/isNull"));

var _excluded = ["x_axis_reversed", "x_axis_gridlines", "show_x_axis_ticks", "show_x_axis_label", "x_axis_label", "x_axis"];

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }

function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }

var deriveDefaults = function deriveDefaults(axisRaw, axisOfficial, measure) {
  var measureLabel = measure.label,
      measureViewLabel = measure.view_label;
  var _ref = axisRaw,
      x_axis_reversed = _ref.x_axis_reversed,
      x_axis_gridlines = _ref.x_axis_gridlines,
      show_x_axis_ticks = _ref.show_x_axis_ticks,
      show_x_axis_label = _ref.show_x_axis_label,
      _ref$x_axis_label = _ref.x_axis_label,
      x_axis_label = _ref$x_axis_label === void 0 ? measureLabel || measureViewLabel : _ref$x_axis_label;
  var _ref2 = axisOfficial,
      _ref2$gridlines = _ref2.gridlines,
      gridlines = _ref2$gridlines === void 0 ? x_axis_gridlines : _ref2$gridlines,
      _ref2$label = _ref2.label,
      label = _ref2$label === void 0 ? show_x_axis_label === false ? false : x_axis_label : _ref2$label,
      _ref2$reversed = _ref2.reversed,
      reversed = _ref2$reversed === void 0 ? x_axis_reversed : _ref2$reversed,
      _ref2$values = _ref2.values,
      values = _ref2$values === void 0 ? show_x_axis_ticks : _ref2$values;
  return {
    gridlines: typeof gridlines === 'undefined' ? true : gridlines,
    label: label === null ? false : label,
    reversed: !!reversed,
    values: typeof values === 'undefined' ? true : values
  };
};

var xAxis = function xAxis(_ref3) {
  var config = _ref3.config,
      data = _ref3.data,
      fields = _ref3.fields;
  var _config$x_axis_revers = config.x_axis_reversed,
      x_axis_reversed = _config$x_axis_revers === void 0 ? false : _config$x_axis_revers,
      _config$x_axis_gridli = config.x_axis_gridlines,
      x_axis_gridlines = _config$x_axis_gridli === void 0 ? true : _config$x_axis_gridli,
      _config$show_x_axis_t = config.show_x_axis_ticks,
      show_x_axis_ticks = _config$show_x_axis_t === void 0 ? true : _config$show_x_axis_t,
      _config$show_x_axis_l = config.show_x_axis_label,
      show_x_axis_label = _config$show_x_axis_l === void 0 ? true : _config$show_x_axis_l,
      x_axis_label = config.x_axis_label,
      _config$x_axis = config.x_axis,
      x_axis = _config$x_axis === void 0 ? [{}] : _config$x_axis,
      restConfig = (0, _objectWithoutProperties2["default"])(config, _excluded);
  var xAxisRaw = [{
    x_axis_reversed: x_axis_reversed,
    x_axis_gridlines: x_axis_gridlines,
    show_x_axis_ticks: show_x_axis_ticks,
    show_x_axis_label: show_x_axis_label,
    x_axis_label: x_axis_label
  }];
  var longestListLength = Math.max(xAxisRaw.length, x_axis.length);
  var xAxisWithDefaults = [];

  for (var i = 0; i < longestListLength; i++) {
    var _fields$dimensions;

    var rawAxisAtPosition = (0, _omitBy["default"])(xAxisRaw[i] || {}, _isNull["default"]);
    var officialAxisAtPosition = x_axis[i] || {};
    var measureAtPosition = (fields === null || fields === void 0 ? void 0 : (_fields$dimensions = fields.dimensions) === null || _fields$dimensions === void 0 ? void 0 : _fields$dimensions[i]) || {};
    xAxisWithDefaults[i] = deriveDefaults(rawAxisAtPosition, officialAxisAtPosition, measureAtPosition);
  }

  return {
    config: _objectSpread(_objectSpread({}, restConfig), {}, {
      x_axis: xAxisWithDefaults
    }),
    data: data,
    fields: fields
  };
};

exports.xAxis = xAxis;
//# sourceMappingURL=xAxis.js.map


text:
namespace StripeTests
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using Newtonsoft.Json;
    using Stripe;
    using Xunit;

    /// <summary>
    /// This test checks that <see cref="Stripe.StripeEntity" /> subclasses that have a
    /// <c>Deleted</c> property have <see cref="Newtonsoft.Json.NullValueHandling" />
    /// set to <see cref="Newtonsoft.Json.NullValueHandling.Ignore" /> so that the property is not
    /// serialized when its value is <c>null</c>.
    /// </summary>
    public class DontSerializeNullDeletedAttrs : WholesomeTest
    {
        private const string AssertionMessage =
            "Found at least one invalid Deleted property. Make sure that the property " +
            "has a JsonPropertyAttribute and that NullValueHandling is set to Ignore.";

        [Fact]
        public void Check()
        {
            List<string> results = new List<string>();

            // Get all StripeEntity subclasses
            var entityClasses = GetSubclassesOf(typeof(StripeEntity));

            foreach (Type entityClass in entityClasses)
            {
                foreach (PropertyInfo property in entityClass.GetProperties())
                {
                    if (property.Name != "Deleted")
                    {
                        continue;
                    }

                    // Check that property has a JsonPropertyAttribute
                    var attribute = property.GetCustomAttribute<JsonPropertyAttribute>();
                    if (attribute == null)
                    {
                        continue;
                    }

                    // Check that NullValueHanding is set to Ignore
                    if (attribute.NullValueHandling == NullValueHandling.Ignore)
                    {
                        continue;
                    }

                    results.Add($"{entityClass.Name}.{property.Name}");
                }
            }

            if (results.Any())
            {
                // Sort results alphabetically
                results = results.OrderBy(i => i).ToList();

                // Display our own error message (because Assert.Empty truncates the results)
                Console.WriteLine("Found invalid Deleted properties:");
                foreach (string item in results)
                {
                    Console.WriteLine($"- {item}");
                }

                // Actually fail test
                Assert.True(false, AssertionMessage);
            }
        }
    }
}
#endif