diff --git a/modules/aruco/CMakeLists.txt b/modules/aruco/CMakeLists.txt index 78da1c8e783..600c0d60cef 100644 --- a/modules/aruco/CMakeLists.txt +++ b/modules/aruco/CMakeLists.txt @@ -1,5 +1,5 @@ set(the_description "ArUco Marker Detection") -ocv_define_module(aruco opencv_core opencv_imgproc opencv_3d opencv_calib WRAP python java objc js) +ocv_define_module(aruco opencv_core opencv_imgproc opencv_3d opencv_calib opencv_objdetect WRAP python java objc js) ocv_include_directories(${CMAKE_CURRENT_BINARY_DIR}) ocv_add_testdata(samples/ contrib/aruco diff --git a/modules/aruco/include/opencv2/aruco.hpp b/modules/aruco/include/opencv2/aruco.hpp index 3213c595089..4c5e44a3c04 100644 --- a/modules/aruco/include/opencv2/aruco.hpp +++ b/modules/aruco/include/opencv2/aruco.hpp @@ -1,25 +1,35 @@ // This file is part of OpenCV project. // It is subject to the license terms in the LICENSE file found in the top-level directory // of this distribution and at http://opencv.org/license.html -#ifndef __OPENCV_ARUCO_HPP__ -#define __OPENCV_ARUCO_HPP__ +#ifndef OPENCV_ARUCO_HPP +#define OPENCV_ARUCO_HPP -#include "opencv2/aruco_detector.hpp" -#include "opencv2/aruco/aruco_calib_pose.hpp" +#include "opencv2/objdetect/aruco_detector.hpp" +#include "opencv2/aruco/aruco_calib.hpp" namespace cv { namespace aruco { - /** -@deprecated Use class ArucoDetector + * @defgroup aruco Aruco markers, module functionality was moved to objdetect module + * @{ + * ArUco Marker Detection, module functionality was moved to objdetect module + * @sa ArucoDetector, CharucoDetector, Board, GridBoard, CharucoBoard + * @} + */ + +//! @addtogroup aruco +//! @{ + +/** @brief detect markers +@deprecated Use class ArucoDetector::detectMarkers */ CV_EXPORTS_W void detectMarkers(InputArray image, const Ptr &dictionary, OutputArrayOfArrays corners, - OutputArray ids, const Ptr ¶meters = DetectorParameters::create(), + OutputArray ids, const Ptr ¶meters = makePtr(), OutputArrayOfArrays rejectedImgPoints = noArray()); -/** -@deprecated Use class ArucoDetector +/** @brief refine detected markers +@deprecated Use class ArucoDetector::refineDetectedMarkers */ CV_EXPORTS_W void refineDetectedMarkers(InputArray image,const Ptr &board, InputOutputArrayOfArrays detectedCorners, @@ -27,7 +37,64 @@ CV_EXPORTS_W void refineDetectedMarkers(InputArray image,const Ptr &boar InputArray cameraMatrix = noArray(), InputArray distCoeffs = noArray(), float minRepDistance = 10.f, float errorCorrectionRate = 3.f, bool checkAllOrders = true, OutputArray recoveredIdxs = noArray(), - const Ptr ¶meters = DetectorParameters::create()); + const Ptr ¶meters = makePtr()); + +/** @brief draw planar board +@deprecated Use Board::generateImage +*/ +CV_EXPORTS_W void drawPlanarBoard(const Ptr &board, Size outSize, OutputArray img, int marginSize, + int borderBits); + +/** @brief get board object and image points +@deprecated Use Board::matchImagePoints +*/ +CV_EXPORTS_W void getBoardObjectAndImagePoints(const Ptr &board, InputArrayOfArrays detectedCorners, + InputArray detectedIds, OutputArray objPoints, OutputArray imgPoints); + + +/** @deprecated Use cv::solvePnP + */ +CV_EXPORTS_W int estimatePoseBoard(InputArrayOfArrays corners, InputArray ids, const Ptr &board, + InputArray cameraMatrix, InputArray distCoeffs, InputOutputArray rvec, + InputOutputArray tvec, bool useExtrinsicGuess = false); + +/** + * @brief Pose estimation for a ChArUco board given some of their corners + * @param charucoCorners vector of detected charuco corners + * @param charucoIds list of identifiers for each corner in charucoCorners + * @param board layout of ChArUco board. + * @param cameraMatrix input 3x3 floating-point camera matrix + * \f$A = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$ + * @param distCoeffs vector of distortion coefficients + * \f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6],[s_1, s_2, s_3, s_4]])\f$ of 4, 5, 8 or 12 elements + * @param rvec Output vector (e.g. cv::Mat) corresponding to the rotation vector of the board + * (see cv::Rodrigues). + * @param tvec Output vector (e.g. cv::Mat) corresponding to the translation vector of the board. + * @param useExtrinsicGuess defines whether initial guess for \b rvec and \b tvec will be used or not. + * + * This function estimates a Charuco board pose from some detected corners. + * The function checks if the input corners are enough and valid to perform pose estimation. + * If pose estimation is valid, returns true, else returns false. + * @sa use cv::drawFrameAxes to get world coordinate system axis for object points + */ +CV_EXPORTS_W bool estimatePoseCharucoBoard(InputArray charucoCorners, InputArray charucoIds, + const Ptr &board, InputArray cameraMatrix, + InputArray distCoeffs, InputOutputArray rvec, + InputOutputArray tvec, bool useExtrinsicGuess = false); + +/** @deprecated Use cv::solvePnP + */ +CV_EXPORTS_W void estimatePoseSingleMarkers(InputArrayOfArrays corners, float markerLength, + InputArray cameraMatrix, InputArray distCoeffs, + OutputArray rvecs, OutputArray tvecs, OutputArray objPoints = noArray(), + const Ptr& estimateParameters = makePtr()); + + +/** @deprecated Use CharucoBoard::checkCharucoCornersCollinear + */ +CV_EXPORTS_W bool testCharucoCornersCollinear(const Ptr &board, InputArray charucoIds); + +//! @} } } diff --git a/modules/aruco/include/opencv2/aruco/aruco_calib_pose.hpp b/modules/aruco/include/opencv2/aruco/aruco_calib.hpp similarity index 54% rename from modules/aruco/include/opencv2/aruco/aruco_calib_pose.hpp rename to modules/aruco/include/opencv2/aruco/aruco_calib.hpp index 7f6624ccde4..fc86dab8439 100644 --- a/modules/aruco/include/opencv2/aruco/aruco_calib_pose.hpp +++ b/modules/aruco/include/opencv2/aruco/aruco_calib.hpp @@ -1,10 +1,9 @@ // This file is part of OpenCV project. // It is subject to the license terms in the LICENSE file found in the top-level directory // of this distribution and at http://opencv.org/license.html -#ifndef __OPENCV_ARUCO_CALIB_POSE_HPP__ -#define __OPENCV_ARUCO_CALIB_POSE_HPP__ -#include -#include +#ifndef OPENCV_ARUCO_CALIB_POSE_HPP +#define OPENCV_ARUCO_CALIB_POSE_HPP +#include namespace cv { namespace aruco { @@ -13,28 +12,31 @@ namespace aruco { //! @{ /** @brief rvec/tvec define the right handed coordinate system of the marker. - * PatternPos defines center this system and axes direction. + * + * PatternPositionType defines center this system and axes direction. * Axis X (red color) - first coordinate, axis Y (green color) - second coordinate, * axis Z (blue color) - third coordinate. - * @sa estimatePoseSingleMarkers(), @ref tutorial_aruco_detection + * @sa estimatePoseSingleMarkers(), check tutorial_aruco_detection in aruco contrib */ -enum PatternPos { +enum PatternPositionType { /** @brief The marker coordinate system is centered on the middle of the marker. + * * The coordinates of the four corners (CCW order) of the marker in its own coordinate system are: * (-markerLength/2, markerLength/2, 0), (markerLength/2, markerLength/2, 0), * (markerLength/2, -markerLength/2, 0), (-markerLength/2, -markerLength/2, 0). * * These pattern points define this coordinate system: - * ![Image with axes drawn](images/singlemarkersaxes.jpg) + * ![Image with axes drawn](tutorials/images/singlemarkersaxes.jpg) */ ARUCO_CCW_CENTER, /** @brief The marker coordinate system is centered on the top-left corner of the marker. + * * The coordinates of the four corners (CW order) of the marker in its own coordinate system are: * (0, 0, 0), (markerLength, 0, 0), * (markerLength, markerLength, 0), (0, markerLength, 0). * * These pattern points define this coordinate system: - * ![Image with axes drawn](images/singlemarkersaxes2.jpg) + * ![Image with axes drawn](tutorials/images/singlemarkersaxes2.jpg) * * These pattern dots are convenient to use with a chessboard/ChArUco board. */ @@ -42,114 +44,22 @@ enum PatternPos { }; /** @brief Pose estimation parameters - * @param pattern Defines center this system and axes direction (default PatternPos::ARUCO_CCW_CENTER). + * + * @param pattern Defines center this system and axes direction (default PatternPositionType::ARUCO_CCW_CENTER). * @param useExtrinsicGuess Parameter used for SOLVEPNP_ITERATIVE. If true (1), the function uses the provided * rvec and tvec values as initial approximations of the rotation and translation vectors, respectively, and further * optimizes them (default false). * @param solvePnPMethod Method for solving a PnP problem: see @ref calib3d_solvePnP_flags (default SOLVEPNP_ITERATIVE). - * @sa PatternPos, solvePnP(), @ref tutorial_aruco_detection + * @sa PatternPositionType, solvePnP(), check tutorial_aruco_detection in aruco contrib */ -struct CV_EXPORTS_W EstimateParameters { - CV_PROP_RW PatternPos pattern; +struct CV_EXPORTS_W_SIMPLE EstimateParameters { + CV_PROP_RW PatternPositionType pattern; CV_PROP_RW bool useExtrinsicGuess; - CV_PROP_RW SolvePnPMethod solvePnPMethod; + CV_PROP_RW int solvePnPMethod; - EstimateParameters(): pattern(ARUCO_CCW_CENTER), useExtrinsicGuess(false), - solvePnPMethod(SOLVEPNP_ITERATIVE) {} - - CV_WRAP static Ptr create() { - return makePtr(); - } + CV_WRAP EstimateParameters(); }; - -/** - * @brief Pose estimation for single markers - * - * @param corners vector of already detected markers corners. For each marker, its four corners - * are provided, (e.g std::vector > ). For N detected markers, - * the dimensions of this array should be Nx4. The order of the corners should be clockwise. - * @sa detectMarkers - * @param markerLength the length of the markers' side. The returning translation vectors will - * be in the same unit. Normally, unit is meters. - * @param cameraMatrix input 3x3 floating-point camera matrix - * \f$A = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$ - * @param distCoeffs vector of distortion coefficients - * \f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6],[s_1, s_2, s_3, s_4]])\f$ of 4, 5, 8 or 12 elements - * @param rvecs array of output rotation vectors (@sa Rodrigues) (e.g. std::vector). - * Each element in rvecs corresponds to the specific marker in imgPoints. - * @param tvecs array of output translation vectors (e.g. std::vector). - * Each element in tvecs corresponds to the specific marker in imgPoints. - * @param objPoints array of object points of all the marker corners - * @param estimateParameters set the origin of coordinate system and the coordinates of the four corners of the marker - * (default estimateParameters.pattern = PatternPos::ARUCO_CCW_CENTER, estimateParameters.useExtrinsicGuess = false, - * estimateParameters.solvePnPMethod = SOLVEPNP_ITERATIVE). - * - * This function receives the detected markers and returns their pose estimation respect to - * the camera individually. So for each marker, one rotation and translation vector is returned. - * The returned transformation is the one that transforms points from each marker coordinate system - * to the camera coordinate system. - * The marker coordinate system is centered on the middle (by default) or on the top-left corner of the marker, - * with the Z axis perpendicular to the marker plane. - * estimateParameters defines the coordinates of the four corners of the marker in its own coordinate system (by default) are: - * (-markerLength/2, markerLength/2, 0), (markerLength/2, markerLength/2, 0), - * (markerLength/2, -markerLength/2, 0), (-markerLength/2, -markerLength/2, 0) - * @sa use cv::drawFrameAxes to get world coordinate system axis for object points - * @sa @ref tutorial_aruco_detection - * @sa EstimateParameters - * @sa PatternPos - */ -CV_EXPORTS_W void estimatePoseSingleMarkers(InputArrayOfArrays corners, float markerLength, - InputArray cameraMatrix, InputArray distCoeffs, - OutputArray rvecs, OutputArray tvecs, OutputArray objPoints = noArray(), - const Ptr& estimateParameters = EstimateParameters::create()); - -/** - * @brief Pose estimation for a board of markers - * - * @param corners vector of already detected markers corners. For each marker, its four corners - * are provided, (e.g std::vector > ). For N detected markers, the - * dimensions of this array should be Nx4. The order of the corners should be clockwise. - * @param ids list of identifiers for each marker in corners - * @param board layout of markers in the board. The layout is composed by the marker identifiers - * and the positions of each marker corner in the board reference system. - * @param cameraMatrix input 3x3 floating-point camera matrix - * \f$A = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$ - * @param distCoeffs vector of distortion coefficients - * \f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6],[s_1, s_2, s_3, s_4]])\f$ of 4, 5, 8 or 12 elements - * @param rvec Output vector (e.g. cv::Mat) corresponding to the rotation vector of the board - * (see cv::Rodrigues). Used as initial guess if not empty. - * @param tvec Output vector (e.g. cv::Mat) corresponding to the translation vector of the board. - * @param useExtrinsicGuess defines whether initial guess for \b rvec and \b tvec will be used or not. - * Used as initial guess if not empty. - * - * This function receives the detected markers and returns the pose of a marker board composed - * by those markers. - * A Board of marker has a single world coordinate system which is defined by the board layout. - * The returned transformation is the one that transforms points from the board coordinate system - * to the camera coordinate system. - * Input markers that are not included in the board layout are ignored. - * The function returns the number of markers from the input employed for the board pose estimation. - * Note that returning a 0 means the pose has not been estimated. - * @sa use cv::drawFrameAxes to get world coordinate system axis for object points - */ -CV_EXPORTS_W int estimatePoseBoard(InputArrayOfArrays corners, InputArray ids, const Ptr &board, - InputArray cameraMatrix, InputArray distCoeffs, InputOutputArray rvec, - InputOutputArray tvec, bool useExtrinsicGuess = false); - -/** - * @brief Given a board configuration and a set of detected markers, returns the corresponding - * image points and object points to call solvePnP - * - * @param board Marker board layout. - * @param detectedCorners List of detected marker corners of the board. - * @param detectedIds List of identifiers for each marker. - * @param objPoints Vector of vectors of board marker points in the board coordinate space. - * @param imgPoints Vector of vectors of the projections of board marker corner points. -*/ -CV_EXPORTS_W void getBoardObjectAndImagePoints(const Ptr &board, InputArrayOfArrays detectedCorners, - InputArray detectedIds, OutputArray objPoints, OutputArray imgPoints); - /** * @brief Calibrate a camera using aruco markers * @@ -203,29 +113,6 @@ CV_EXPORTS_W double calibrateCameraAruco(InputArrayOfArrays corners, InputArray const TermCriteria& criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 30, DBL_EPSILON)); -/** - * @brief Pose estimation for a ChArUco board given some of their corners - * @param charucoCorners vector of detected charuco corners - * @param charucoIds list of identifiers for each corner in charucoCorners - * @param board layout of ChArUco board. - * @param cameraMatrix input 3x3 floating-point camera matrix - * \f$A = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$ - * @param distCoeffs vector of distortion coefficients - * \f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6],[s_1, s_2, s_3, s_4]])\f$ of 4, 5, 8 or 12 elements - * @param rvec Output vector (e.g. cv::Mat) corresponding to the rotation vector of the board - * (see cv::Rodrigues). - * @param tvec Output vector (e.g. cv::Mat) corresponding to the translation vector of the board. - * @param useExtrinsicGuess defines whether initial guess for \b rvec and \b tvec will be used or not. - * - * This function estimates a Charuco board pose from some detected corners. - * The function checks if the input corners are enough and valid to perform pose estimation. - * If pose estimation is valid, returns true, else returns false. - * @sa use cv::drawFrameAxes to get world coordinate system axis for object points - */ -CV_EXPORTS_W bool estimatePoseCharucoBoard(InputArray charucoCorners, InputArray charucoIds, - const Ptr &board, InputArray cameraMatrix, - InputArray distCoeffs, InputOutputArray rvec, - InputOutputArray tvec, bool useExtrinsicGuess = false); /** * @brief Calibrate a camera using Charuco corners diff --git a/modules/aruco/include/opencv2/aruco/board.hpp b/modules/aruco/include/opencv2/aruco/board.hpp deleted file mode 100644 index 85c8369e91f..00000000000 --- a/modules/aruco/include/opencv2/aruco/board.hpp +++ /dev/null @@ -1,243 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html -#ifndef __OPENCV_ARUCO_BOARD_HPP__ -#define __OPENCV_ARUCO_BOARD_HPP__ - -#include -#include - -namespace cv { -namespace aruco { -//! @addtogroup aruco -//! @{ - -class Dictionary; - -/** - * @brief Board of markers - * - * A board is a set of markers in the 3D space with a common coordinate system. - * The common form of a board of marker is a planar (2D) board, however any 3D layout can be used. - * A Board object is composed by: - * - The object points of the marker corners, i.e. their coordinates respect to the board system. - * - The dictionary which indicates the type of markers of the board - * - The identifier of all the markers in the board. - */ -class CV_EXPORTS_W Board { -public: - CV_WRAP Board(); - - /** @brief Provide way to create Board by passing necessary data. Specially needed in Python. - * @param objPoints array of object points of all the marker corners in the board - * @param dictionary the dictionary of markers employed for this board - * @param ids vector of the identifiers of the markers in the board - */ - CV_WRAP static Ptr create(InputArrayOfArrays objPoints, const Ptr &dictionary, InputArray ids); - - /** @brief Set ids vector - * @param ids vector of the identifiers of the markers in the board (should be the same size - * as objPoints) - * - * Recommended way to set ids vector, which will fail if the size of ids does not match size - * of objPoints. - */ - CV_WRAP void setIds(InputArray ids); - - /** @brief change id for ids[index] - * @param index - element index in ids - * @param newId - new value for ids[index], should be less than Dictionary size - */ - CV_WRAP void changeId(int index, int newId); - /** @brief return ids - */ - CV_WRAP const std::vector& getIds() const; - - /** @brief set dictionary - */ - CV_WRAP void setDictionary(const Ptr &dictionary); - - /** @brief return dictionary - */ - CV_WRAP Ptr getDictionary() const; - - /** @brief set objPoints - */ - CV_WRAP void setObjPoints(const std::vector > &objPoints); - - /** @brief get objPoints - */ - CV_WRAP const std::vector >& getObjPoints() const; - - /** @brief get rightBottomBorder - */ - CV_WRAP const Point3f& getRightBottomBorder() const; - -protected: - /** @brief array of object points of all the marker corners in the board each marker include its 4 corners in this order: - * - objPoints[i][0] - left-top point of i-th marker - * - objPoints[i][1] - right-top point of i-th marker - * - objPoints[i][2] - right-bottom point of i-th marker - * - objPoints[i][3] - left-bottom point of i-th marker - * - * Markers are placed in a certain order - row by row, left to right in every row. - * For M markers, the size is Mx4. - */ - CV_PROP std::vector > objPoints; - - /// the dictionary of markers employed for this board - CV_PROP Ptr dictionary; - - /// coordinate of the bottom right corner of the board, is set when calling the function create() - CV_PROP Point3f rightBottomBorder; - - /** @brief vector of the identifiers of the markers in the board (same size than objPoints) - * The identifiers refers to the board dictionary - */ - CV_PROP_RW std::vector ids; -}; - -/** - * @brief Draw a planar board - * @sa drawPlanarBoard - * - * @param board layout of the board that will be drawn. The board should be planar, - * z coordinate is ignored - * @param outSize size of the output image in pixels. - * @param img output image with the board. The size of this image will be outSize - * and the board will be on the center, keeping the board proportions. - * @param marginSize minimum margins (in pixels) of the board in the output image - * @param borderBits width of the marker borders. - * - * This function return the image of a planar board, ready to be printed. It assumes - * the Board layout specified is planar by ignoring the z coordinates of the object points. - */ -CV_EXPORTS_W void drawPlanarBoard(const Ptr &board, Size outSize, OutputArray img, - int marginSize = 0, int borderBits = 1); - -/** - * @brief Planar board with grid arrangement of markers - * More common type of board. All markers are placed in the same plane in a grid arrangement. - * The board can be drawn using drawPlanarBoard() function (@sa drawPlanarBoard) - */ - -class CV_EXPORTS_W GridBoard : public Board { -public: - CV_WRAP GridBoard(); - /** - * @brief Draw a GridBoard - * - * @param outSize size of the output image in pixels. - * @param img output image with the board. The size of this image will be outSize - * and the board will be on the center, keeping the board proportions. - * @param marginSize minimum margins (in pixels) of the board in the output image - * @param borderBits width of the marker borders. - * - * This function return the image of the GridBoard, ready to be printed. - */ - CV_WRAP void draw(Size outSize, OutputArray img, int marginSize = 0, int borderBits = 1); - - /** - * @brief Create a GridBoard object - * - * @param markersX number of markers in X direction - * @param markersY number of markers in Y direction - * @param markerLength marker side length (normally in meters) - * @param markerSeparation separation between two markers (same unit as markerLength) - * @param dictionary dictionary of markers indicating the type of markers - * @param firstMarker id of first marker in dictionary to use on board. - * @return the output GridBoard object - * - * This functions creates a GridBoard object given the number of markers in each direction and - * the marker size and marker separation. - */ - CV_WRAP static Ptr create(int markersX, int markersY, float markerLength, float markerSeparation, - const Ptr &dictionary, int firstMarker = 0); - - CV_WRAP Size getGridSize() const; - CV_WRAP float getMarkerLength() const; - CV_WRAP float getMarkerSeparation() const; - -protected: - struct GridImpl; - Ptr gridImpl; - friend class CharucoBoard; -}; - -/** - * @brief ChArUco board - * Specific class for ChArUco boards. A ChArUco board is a planar board where the markers are placed - * inside the white squares of a chessboard. The benefits of ChArUco boards is that they provide - * both, ArUco markers versatility and chessboard corner precision, which is important for - * calibration and pose estimation. - * This class also allows the easy creation and drawing of ChArUco boards. - */ -class CV_EXPORTS_W CharucoBoard : public Board { -public: - CV_WRAP CharucoBoard(); - - // vector of chessboard 3D corners precalculated - CV_PROP std::vector chessboardCorners; - - // for each charuco corner, nearest marker id and nearest marker corner id of each marker - CV_PROP std::vector > nearestMarkerIdx; - CV_PROP std::vector > nearestMarkerCorners; - - /** @brief Draw a ChArUco board - * - * @param outSize size of the output image in pixels. - * @param img output image with the board. The size of this image will be outSize - * and the board will be on the center, keeping the board proportions. - * @param marginSize minimum margins (in pixels) of the board in the output image - * @param borderBits width of the marker borders. - * - * This function return the image of the ChArUco board, ready to be printed. - */ - CV_WRAP void draw(Size outSize, OutputArray img, int marginSize = 0, int borderBits = 1); - - - /** @brief Create a CharucoBoard object - * @param squaresX number of chessboard squares in X direction - * @param squaresY number of chessboard squares in Y direction - * @param squareLength chessboard square side length (normally in meters) - * @param markerLength marker side length (same unit than squareLength) - * @param dictionary dictionary of markers indicating the type of markers. - * The first markers in the dictionary are used to fill the white chessboard squares. - * @return the output CharucoBoard object - * - * This functions creates a CharucoBoard object given the number of squares in each direction - * and the size of the markers and chessboard squares. - */ - CV_WRAP static Ptr create(int squaresX, int squaresY, float squareLength, - float markerLength, const Ptr &dictionary); - - CV_WRAP Size getChessboardSize() const; - CV_WRAP float getSquareLength() const; - CV_WRAP float getMarkerLength() const; - -protected: - struct CharucoImpl; - Ptr charucoImpl; -}; - -/** - * @brief test whether the ChArUco markers are collinear - * - * @param board layout of ChArUco board. - * @param charucoIds list of identifiers for each corner in charucoCorners per frame. - * @return bool value, 1 (true) if detected corners form a line, 0 (false) if they do not. - * solvePnP, calibration functions will fail if the corners are collinear (true). - * - * The number of ids in charucoIDs should be <= the number of chessboard corners in the board. - * This functions checks whether the charuco corners are on a straight line (returns true, if so), or not (false). - * Axis parallel, as well as diagonal and other straight lines detected. Degenerate cases: - * for number of charucoIDs <= 2,the function returns true. - */ -CV_EXPORTS_W bool testCharucoCornersCollinear(const Ptr &board, InputArray charucoIds); - -//! @} - -} -} - -#endif diff --git a/modules/aruco/include/opencv2/aruco/charuco.hpp b/modules/aruco/include/opencv2/aruco/charuco.hpp index d961c7ef00e..7bc7c06b79d 100644 --- a/modules/aruco/include/opencv2/aruco/charuco.hpp +++ b/modules/aruco/include/opencv2/aruco/charuco.hpp @@ -1,14 +1,14 @@ // This file is part of OpenCV project. // It is subject to the license terms in the LICENSE file found in the top-level directory // of this distribution and at http://opencv.org/license.html -#ifndef __OPENCV_CHARUCO_HPP__ -#define __OPENCV_CHARUCO_HPP__ +#ifndef OPENCV_CHARUCO_HPP +#define OPENCV_CHARUCO_HPP #include #include #include -#include -#include +#include +#include namespace cv { @@ -40,6 +40,8 @@ namespace aruco { * Only visible corners are returned. For each corner, its corresponding identifier is * also returned in charucoIds. * The function returns the number of interpolated corners. + * + * @deprecated Use CharucoDetector::detectBoard */ CV_EXPORTS_W int interpolateCornersCharuco(InputArrayOfArrays markerCorners, InputArray markerIds, InputArray image, const Ptr &board, @@ -47,21 +49,6 @@ CV_EXPORTS_W int interpolateCornersCharuco(InputArrayOfArrays markerCorners, Inp InputArray cameraMatrix = noArray(), InputArray distCoeffs = noArray(), int minMarkers = 2); -/** - * @brief Draws a set of Charuco corners - * @param image input/output image. It must have 1 or 3 channels. The number of channels is not - * altered. - * @param charucoCorners vector of detected charuco corners - * @param charucoIds list of identifiers for each corner in charucoCorners - * @param cornerColor color of the square surrounding each corner - * - * This function draws a set of detected Charuco corners. If identifiers vector is provided, it also - * draws the id of each corner. - */ -CV_EXPORTS_W void drawDetectedCornersCharuco(InputOutputArray image, InputArray charucoCorners, - InputArray charucoIds = noArray(), - Scalar cornerColor = Scalar(255, 0, 0)); - /** * @brief Detect ChArUco Diamond markers * @@ -83,40 +70,17 @@ CV_EXPORTS_W void drawDetectedCornersCharuco(InputOutputArray image, InputArray * This function detects Diamond markers from the previous detected ArUco markers. The diamonds * are returned in the diamondCorners and diamondIds parameters. If camera calibration parameters * are provided, the diamond search is based on reprojection. If not, diamond search is based on - * homography. Homography is faster than reprojection but can slightly reduce the detection rate. + * homography. Homography is faster than reprojection, but less accurate. + * + * @deprecated Use CharucoDetector::detectDiamonds */ CV_EXPORTS_W void detectCharucoDiamond(InputArray image, InputArrayOfArrays markerCorners, InputArray markerIds, float squareMarkerLengthRate, OutputArrayOfArrays diamondCorners, OutputArray diamondIds, InputArray cameraMatrix = noArray(), InputArray distCoeffs = noArray(), - Ptr dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::PREDEFINED_DICTIONARY_NAME::DICT_4X4_50)); - - - -/** - * @brief Draw a set of detected ChArUco Diamond markers - * - * @param image input/output image. It must have 1 or 3 channels. The number of channels is not - * altered. - * @param diamondCorners positions of diamond corners in the same format returned by - * detectCharucoDiamond(). (e.g std::vector > ). For N detected markers, - * the dimensions of this array should be Nx4. The order of the corners should be clockwise. - * @param diamondIds vector of identifiers for diamonds in diamondCorners, in the same format - * returned by detectCharucoDiamond() (e.g. std::vector). - * Optional, if not provided, ids are not painted. - * @param borderColor color of marker borders. Rest of colors (text color and first corner color) - * are calculated based on this one. - * - * Given an array of detected diamonds, this functions draws them in the image. The marker borders - * are painted and the markers identifiers if provided. - * Useful for debugging purposes. - */ -CV_EXPORTS_W void drawDetectedDiamonds(InputOutputArray image, InputArrayOfArrays diamondCorners, - InputArray diamondIds = noArray(), - Scalar borderColor = Scalar(0, 0, 255)); - - + Ptr dictionary = makePtr + (getPredefinedDictionary(PredefinedDictionaryType::DICT_4X4_50))); /** @@ -134,8 +98,8 @@ CV_EXPORTS_W void drawDetectedDiamonds(InputOutputArray image, InputArrayOfArray * This function return the image of a ChArUco marker, ready to be printed. */ CV_EXPORTS_W void drawCharucoDiamond(const Ptr &dictionary, Vec4i ids, int squareLength, - int markerLength, OutputArray img, int marginSize = 0, - int borderBits = 1); + int markerLength, OutputArray img, int marginSize = 0, + int borderBits = 1); //! @} } diff --git a/modules/aruco/include/opencv2/aruco/dictionary.hpp b/modules/aruco/include/opencv2/aruco/dictionary.hpp deleted file mode 100644 index cc692cf4890..00000000000 --- a/modules/aruco/include/opencv2/aruco/dictionary.hpp +++ /dev/null @@ -1,187 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html -#ifndef __OPENCV_DICTIONARY_HPP__ -#define __OPENCV_DICTIONARY_HPP__ - -#include - -namespace cv { -namespace aruco { - -//! @addtogroup aruco -//! @{ - - -/** - * @brief Dictionary/Set of markers. It contains the inner codification - * - * bytesList contains the marker codewords where - * - bytesList.rows is the dictionary size - * - each marker is encoded using `nbytes = ceil(markerSize*markerSize/8.)` - * - each row contains all 4 rotations of the marker, so its length is `4*nbytes` - * - * `bytesList.ptr(i)[k*nbytes + j]` is then the j-th byte of i-th marker, in its k-th rotation. - */ -class CV_EXPORTS_W Dictionary { - - public: - CV_PROP_RW Mat bytesList; // marker code information - CV_PROP_RW int markerSize; // number of bits per dimension - CV_PROP_RW int maxCorrectionBits; // maximum number of bits that can be corrected - - - Dictionary(const Mat &_bytesList = Mat(), int _markerSize = 0, int _maxcorr = 0); - - - /** - * Dictionary(const Dictionary &_dictionary); - */ - Dictionary(const Ptr &dictionary); - - - /** @brief returns generateCustomDictionary(nMarkers, markerSize, randomSeed) - * @see generateCustomDictionary - */ - CV_WRAP_AS(create) static Ptr create(int nMarkers, int markerSize, int randomSeed=0); - - - /** @brief returns generateCustomDictionary(nMarkers, markerSize, baseDictionary, randomSeed) - * @see generateCustomDictionary - */ - CV_WRAP_AS(create_from) static Ptr create(int nMarkers, int markerSize, - const Ptr &baseDictionary, int randomSeed=0); - - /** - * @brief Read a new dictionary from FileNode. Format:\n - * nmarkers: 35\n - * markersize: 6\n - * maxCorrectionBits: 5\n - * marker_0: "101011111011111001001001101100000000"\n - * ...\n - * marker_34: "011111010000111011111110110101100101" - */ - CV_WRAP bool readDictionary(const cv::FileNode& fn); - - /** - * @brief Write a dictionary to FileStorage. Format is the same as in readDictionary(). - */ - CV_WRAP void writeDictionary(Ptr& fs); - - /** - * @see getPredefinedDictionary - */ - CV_WRAP static Ptr get(int dict); - - /** - * @brief Given a matrix of bits. Returns whether if marker is identified or not. - * It returns by reference the correct id (if any) and the correct rotation - */ - CV_WRAP bool identify(const Mat &onlyBits, CV_OUT int &idx, CV_OUT int &rotation, double maxCorrectionRate) const; - - /** - * @brief Returns the distance of the input bits to the specific id. If allRotations is true, - * the four posible bits rotation are considered - */ - CV_WRAP int getDistanceToId(InputArray bits, int id, bool allRotations = true) const; - - - /** - * @brief Draw a canonical marker image - */ - CV_WRAP void drawMarker(int id, int sidePixels, OutputArray _img, int borderBits = 1) const; - - - /** - * @brief Transform matrix of bits to list of bytes in the 4 rotations - */ - CV_WRAP static Mat getByteListFromBits(const Mat &bits); - - - /** - * @brief Transform list of bytes to matrix of bits - */ - CV_WRAP static Mat getBitsFromByteList(const Mat &byteList, int markerSize); -}; - - - - -/** - * @brief Predefined markers dictionaries/sets - * Each dictionary indicates the number of bits and the number of markers contained - * - DICT_ARUCO_ORIGINAL: standard ArUco Library Markers. 1024 markers, 5x5 bits, 0 minimum - distance - */ -enum PREDEFINED_DICTIONARY_NAME { - DICT_4X4_50 = 0, ///< 4x4 bits, minimum hamming distance between any two codes = 4, 50 codes - DICT_4X4_100, ///< 4x4 bits, minimum hamming distance between any two codes = 3, 100 codes - DICT_4X4_250, ///< 4x4 bits, minimum hamming distance between any two codes = 3, 250 codes - DICT_4X4_1000, ///< 4x4 bits, minimum hamming distance between any two codes = 2, 1000 codes - DICT_5X5_50, ///< 5x5 bits, minimum hamming distance between any two codes = 8, 50 codes - DICT_5X5_100, ///< 5x5 bits, minimum hamming distance between any two codes = 7, 100 codes - DICT_5X5_250, ///< 5x5 bits, minimum hamming distance between any two codes = 6, 250 codes - DICT_5X5_1000, ///< 5x5 bits, minimum hamming distance between any two codes = 5, 1000 codes - DICT_6X6_50, ///< 6x6 bits, minimum hamming distance between any two codes = 13, 50 codes - DICT_6X6_100, ///< 6x6 bits, minimum hamming distance between any two codes = 12, 100 codes - DICT_6X6_250, ///< 6x6 bits, minimum hamming distance between any two codes = 11, 250 codes - DICT_6X6_1000, ///< 6x6 bits, minimum hamming distance between any two codes = 9, 1000 codes - DICT_7X7_50, ///< 7x7 bits, minimum hamming distance between any two codes = 19, 50 codes - DICT_7X7_100, ///< 7x7 bits, minimum hamming distance between any two codes = 18, 100 codes - DICT_7X7_250, ///< 7x7 bits, minimum hamming distance between any two codes = 17, 250 codes - DICT_7X7_1000, ///< 7x7 bits, minimum hamming distance between any two codes = 14, 1000 codes - DICT_ARUCO_ORIGINAL, ///< 6x6 bits, minimum hamming distance between any two codes = 3, 1024 codes - DICT_APRILTAG_16h5, ///< 4x4 bits, minimum hamming distance between any two codes = 5, 30 codes - DICT_APRILTAG_25h9, ///< 5x5 bits, minimum hamming distance between any two codes = 9, 35 codes - DICT_APRILTAG_36h10, ///< 6x6 bits, minimum hamming distance between any two codes = 10, 2320 codes - DICT_APRILTAG_36h11 ///< 6x6 bits, minimum hamming distance between any two codes = 11, 587 codes -}; - - -/** - * @brief Returns one of the predefined dictionaries defined in PREDEFINED_DICTIONARY_NAME - */ -CV_EXPORTS Ptr getPredefinedDictionary(PREDEFINED_DICTIONARY_NAME name); - - -/** - * @brief Returns one of the predefined dictionaries referenced by DICT_*. - */ -CV_EXPORTS_W Ptr getPredefinedDictionary(int dict); - - -/** - * @see generateCustomDictionary - */ -CV_EXPORTS_AS(custom_dictionary) Ptr generateCustomDictionary( - int nMarkers, - int markerSize, - int randomSeed=0); - - -/** - * @brief Generates a new customizable marker dictionary - * - * @param nMarkers number of markers in the dictionary - * @param markerSize number of bits per dimension of each markers - * @param baseDictionary Include the markers in this dictionary at the beginning (optional) - * @param randomSeed a user supplied seed for theRNG() - * - * This function creates a new dictionary composed by nMarkers markers and each markers composed - * by markerSize x markerSize bits. If baseDictionary is provided, its markers are directly - * included and the rest are generated based on them. If the size of baseDictionary is higher - * than nMarkers, only the first nMarkers in baseDictionary are taken and no new marker is added. - */ -CV_EXPORTS_AS(custom_dictionary_from) Ptr generateCustomDictionary( - int nMarkers, - int markerSize, - const Ptr &baseDictionary, - int randomSeed=0); - - - -//! @} -} -} - -#endif diff --git a/modules/aruco/include/opencv2/aruco_detector.hpp b/modules/aruco/include/opencv2/aruco_detector.hpp deleted file mode 100644 index f3342ebe76d..00000000000 --- a/modules/aruco/include/opencv2/aruco_detector.hpp +++ /dev/null @@ -1,436 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html -#ifndef __OPENCV_ARUCO_DETECTOR_HPP__ -#define __OPENCV_ARUCO_DETECTOR_HPP__ -#include -#include - -/** - * @defgroup aruco ArUco Marker Detection - * This module is dedicated to square fiducial markers (also known as Augmented Reality Markers) - * These markers are useful for easy, fast and robust camera pose estimation. - * - * The main functionality of ArucoDetector class is: - * - Detection of markers in an image - * - * There are even more functionalities implemented in charuco.hpp and aruco_calib_pose.hpp: - * - Pose estimation from a single marker or from a board/set of markers - * - Detection of ChArUco board for high subpixel accuracy - * - Camera calibration from both, ArUco boards and ChArUco boards. - * - Detection of ChArUco diamond markers - * The samples directory includes easy examples of how to use the module. - * - * The implementation is based on the ArUco Library by R. Muñoz-Salinas and S. Garrido-Jurado @cite Aruco2014. - * - * Markers can also be detected based on the AprilTag 2 @cite wang2016iros fiducial detection method. - * - * @sa S. Garrido-Jurado, R. Muñoz-Salinas, F. J. Madrid-Cuevas, and M. J. Marín-Jiménez. 2014. - * "Automatic generation and detection of highly reliable fiducial markers under occlusion". - * Pattern Recogn. 47, 6 (June 2014), 2280-2292. DOI=10.1016/j.patcog.2014.01.005 - * - * @sa http://www.uco.es/investiga/grupos/ava/node/26 - * - * This module has been originally developed by Sergio Garrido-Jurado as a project - * for Google Summer of Code 2015 (GSoC 15). - * - * -*/ - -namespace cv { -namespace aruco { - -//! @addtogroup aruco -//! @{ - -enum CornerRefineMethod{ - CORNER_REFINE_NONE, ///< Tag and corners detection based on the ArUco approach - CORNER_REFINE_SUBPIX, ///< ArUco approach and refine the corners locations using corner subpixel accuracy - CORNER_REFINE_CONTOUR, ///< ArUco approach and refine the corners locations using the contour-points line fitting - CORNER_REFINE_APRILTAG, ///< Tag and corners detection based on the AprilTag 2 approach @cite wang2016iros -}; - -/** - * @brief struct DetectorParameters is used by ArucoDetector - */ -struct CV_EXPORTS_W DetectorParameters { - DetectorParameters() { - adaptiveThreshWinSizeMin = 3; - adaptiveThreshWinSizeMax = 23; - adaptiveThreshWinSizeStep = 10; - adaptiveThreshConstant = 7; - minMarkerPerimeterRate = 0.03; - maxMarkerPerimeterRate = 4.; - polygonalApproxAccuracyRate = 0.03; - minCornerDistanceRate = 0.05; - minDistanceToBorder = 3; - minMarkerDistanceRate = 0.05; - cornerRefinementMethod = CORNER_REFINE_NONE; - cornerRefinementWinSize = 5; - cornerRefinementMaxIterations = 30; - cornerRefinementMinAccuracy = 0.1; - markerBorderBits = 1; - perspectiveRemovePixelPerCell = 4; - perspectiveRemoveIgnoredMarginPerCell = 0.13; - maxErroneousBitsInBorderRate = 0.35; - minOtsuStdDev = 5.0; - errorCorrectionRate = 0.6; - aprilTagQuadDecimate = 0.0; - aprilTagQuadSigma = 0.0; - aprilTagMinClusterPixels = 5; - aprilTagMaxNmaxima = 10; - aprilTagCriticalRad = (float)(10* CV_PI /180); - aprilTagMaxLineFitMse = 10.0; - aprilTagMinWhiteBlackDiff = 5; - aprilTagDeglitch = 0; - detectInvertedMarker = false; - useAruco3Detection = false; - minSideLengthCanonicalImg = 32; - minMarkerLengthRatioOriginalImg = 0.0; - }; - - /** @brief Create a new set of DetectorParameters with default values. - */ - CV_WRAP static Ptr create() { - Ptr params = makePtr(); - return params; - } - - /** - * @brief Read a new set of DetectorParameters from FileNode (use FileStorage.root()). - */ - CV_WRAP bool readDetectorParameters(const FileNode& fn); - - /** - * @brief Write a set of DetectorParameters to FileStorage - */ - CV_WRAP bool writeDetectorParameters(const Ptr& fs); - - /// minimum window size for adaptive thresholding before finding contours (default 3). - CV_PROP_RW int adaptiveThreshWinSizeMin; - - /// maximum window size for adaptive thresholding before finding contours (default 23). - CV_PROP_RW int adaptiveThreshWinSizeMax; - - /// increments from adaptiveThreshWinSizeMin to adaptiveThreshWinSizeMax during the thresholding (default 10). - CV_PROP_RW int adaptiveThreshWinSizeStep; - - /// constant for adaptive thresholding before finding contours (default 7) - CV_PROP_RW double adaptiveThreshConstant; - - /** @brief determine minimum perimeter for marker contour to be detected. This is defined as a rate respect to the - * maximum dimension of the input image (default 0.03). - */ - CV_PROP_RW double minMarkerPerimeterRate; - - /** @brief determine maximum perimeter for marker contour to be detected. This is defined as a rate respect to - * the maximum dimension of the input image (default 4.0). - */ - CV_PROP_RW double maxMarkerPerimeterRate; - - /// minimum accuracy during the polygonal approximation process to determine which contours are squares. (default 0.03) - CV_PROP_RW double polygonalApproxAccuracyRate; - - /// minimum distance between corners for detected markers relative to its perimeter (default 0.05) - CV_PROP_RW double minCornerDistanceRate; - - /// minimum distance of any corner to the image border for detected markers (in pixels) (default 3) - CV_PROP_RW int minDistanceToBorder; - - /** @brief minimum mean distance beetween two marker corners to be considered imilar, so that the - * smaller one is removed. The rate is relative to the smaller perimeter of the two markers (default 0.05). - */ - CV_PROP_RW double minMarkerDistanceRate; - - /** @brief default CORNER_REFINE_NONE. - * 0:CORNER_REFINE_NONE, no refinement. - * 1: CORNER_REFINE_SUBPIX, do subpixel refinement. - * 2: CORNER_REFINE_CONTOUR use contour-Points, - * 3: CORNER_REFINE_APRILTAG use the AprilTag2 approach). - */ - CV_PROP_RW int cornerRefinementMethod; - - /// window size for the corner refinement process (in pixels) (default 5). - CV_PROP_RW int cornerRefinementWinSize; - - /// maximum number of iterations for stop criteria of the corner refinement process (default 30). - CV_PROP_RW int cornerRefinementMaxIterations; - - /// minimum error for the stop cristeria of the corner refinement process (default: 0.1) - CV_PROP_RW double cornerRefinementMinAccuracy; - - /// number of bits of the marker border, i.e. marker border width (default 1). - CV_PROP_RW int markerBorderBits; - - /// number of bits (per dimension) for each cell of the marker when removing the perspective (default 4). - CV_PROP_RW int perspectiveRemovePixelPerCell; - - /** @brief width of the margin of pixels on each cell not considered for the - * determination of the cell bit. Represents the rate respect to the total size of the cell, i.e. - * perspectiveRemovePixelPerCell (default 0.13) - */ - CV_PROP_RW double perspectiveRemoveIgnoredMarginPerCell; - - /** @brief maximum number of accepted erroneous bits in the border (i.e. number of allowed - * white bits in the border). Represented as a rate respect to the total number of bits per marker (default 0.35). - */ - CV_PROP_RW double maxErroneousBitsInBorderRate; - - /** @brief minimun standard deviation in pixels values during the decodification step to apply Otsu - * thresholding (otherwise, all the bits are set to 0 or 1 depending on mean higher than 128 or not) (default 5.0) - */ - CV_PROP_RW double minOtsuStdDev; - - /// error correction rate respect to the maximun error correction capability for each dictionary (default 0.6). - CV_PROP_RW double errorCorrectionRate; - - /** @brief April :: User-configurable parameters. - * detection of quads can be done on a lower-resolution image, improving speed at a cost of - * pose accuracy and a slight decrease in detection rate. Decoding the binary payload is still - */ - CV_PROP_RW float aprilTagQuadDecimate; - - /// what Gaussian blur should be applied to the segmented image (used for quad detection?) - CV_PROP_RW float aprilTagQuadSigma; - - // April :: Internal variables - /// reject quads containing too few pixels (default 5). - CV_PROP_RW int aprilTagMinClusterPixels; - - /// how many corner candidates to consider when segmenting a group of pixels into a quad (default 10). - CV_PROP_RW int aprilTagMaxNmaxima; - - /** @brief reject quads where pairs of edges have angles that are close to straight or close to 180 degrees. - * Zero means that no quads are rejected. (In radians) (default 10*PI/180) - */ - CV_PROP_RW float aprilTagCriticalRad; - - /// when fitting lines to the contours, what is the maximum mean squared error - CV_PROP_RW float aprilTagMaxLineFitMse; - - /** @brief when we build our model of black & white pixels, we add an extra check that the - * white model must be (overall) brighter than the black model. How much brighter? (in pixel values, [0,255]). - * (default 5) - */ - CV_PROP_RW int aprilTagMinWhiteBlackDiff; - - /// should the thresholded image be deglitched? Only useful for very noisy images (default 0). - CV_PROP_RW int aprilTagDeglitch; - - /** @brief to check if there is a white marker. In order to generate a "white" marker just invert a - * normal marker by using a tilde, ~markerImage. (default false) - */ - CV_PROP_RW bool detectInvertedMarker; - - /** @brief new Aruco functionality proposed in the paper: - * Romero-Ramirez et al: Speeded up detection of squared fiducial markers (2018) - * https://www.researchgate.net/publication/325787310_Speeded_Up_Detection_of_Squared_Fiducial_Markers - */ - - /// to enable the new and faster Aruco detection strategy. - CV_PROP_RW bool useAruco3Detection; - - /// minimum side length of a marker in the canonical image. Latter is the binarized image in which contours are searched. - CV_PROP_RW int minSideLengthCanonicalImg; - - /// range [0,1], eq (2) from paper. The parameter tau_i has a direct influence on the processing speed. - CV_PROP_RW float minMarkerLengthRatioOriginalImg; -}; - -/** - * @brief struct RefineParameters is used by ArucoDetector - */ -struct CV_EXPORTS_W RefineParameters { - RefineParameters() { - minRepDistance = 10.f; - errorCorrectionRate = 3.f; - checkAllOrders = true; - } - - RefineParameters(float _minRepDistance, float _errorCorrectionRate, bool _checkAllOrders): - minRepDistance(_minRepDistance), errorCorrectionRate(_errorCorrectionRate), checkAllOrders(_checkAllOrders) {} - - CV_WRAP static Ptr create(float _minRepDistance = 10.f, float _errorCorrectionRate = 3.f, - bool _checkAllOrders = true) { - return makePtr(_minRepDistance, _errorCorrectionRate, _checkAllOrders); - } - - - /** - * @brief Read a new set of RefineParameters from FileNode (use FileStorage.root()). - */ - CV_WRAP bool readRefineParameters(const FileNode& fn); - - /** @brief Write a set of RefineParameters to FileStorage - */ - CV_WRAP bool writeRefineParameters(const Ptr& fs); - - /** @brief minRepDistance minimum distance between the corners of the rejected candidate and the reprojected marker in - * order to consider it as a correspondence. - */ - CV_PROP_RW float minRepDistance; - /** @brief minRepDistance rate of allowed erroneous bits respect to the error correction - * capability of the used dictionary. -1 ignores the error correction step. - */ - CV_PROP_RW float errorCorrectionRate; - /** @brief checkAllOrders consider the four posible corner orders in the rejectedCorners array. - * If it set to false, only the provided corner order is considered (default true). - */ - CV_PROP_RW bool checkAllOrders; -}; - -/** - * @brief The main functionality of ArucoDetector class is detection of markers in an image with detectMarkers() method. - * After detecting some markers in the image, you can try to find undetected markers from this dictionary with - * refineDetectedMarkers() method. - * @see DetectorParameters, RefineParameters - */ -class CV_EXPORTS_W ArucoDetector : public Algorithm -{ -public: - /// dictionary indicates the type of markers that will be searched - CV_PROP_RW Ptr dictionary; - - /// marker detection parameters, check DetectorParameters docs to see available settings - CV_PROP_RW Ptr params; - - /// marker refine parameters - CV_PROP_RW Ptr refineParams; - - /** - * @brief Basic ArucoDetector constructor - * @param _dictionary indicates the type of markers that will be searched - * @param _params marker detection parameters - * @param _refineParams marker refine detection parameters - */ - CV_WRAP ArucoDetector(const Ptr &_dictionary = getPredefinedDictionary(DICT_4X4_50), - const Ptr &_params = DetectorParameters::create(), - const Ptr &_refineParams = RefineParameters::create()): - dictionary(_dictionary), params(_params), refineParams(_refineParams) {} - - CV_WRAP static Ptr create(const Ptr &_dictionary, const Ptr &_params) { - return makePtr(_dictionary, _params); - } - - /** - * @brief Basic marker detection - * - * @param image input image - * @param corners vector of detected marker corners. For each marker, its four corners - * are provided, (e.g std::vector > ). For N detected markers, - * the dimensions of this array is Nx4. The order of the corners is clockwise. - * @param ids vector of identifiers of the detected markers. The identifier is of type int - * (e.g. std::vector). For N detected markers, the size of ids is also N. - * The identifiers have the same order than the markers in the imgPoints array. - * @param rejectedImgPoints contains the imgPoints of those squares whose inner code has not a - * correct codification. Useful for debugging purposes. - * - * Performs marker detection in the input image. Only markers included in the specific dictionary - * are searched. For each detected marker, it returns the 2D position of its corner in the image - * and its corresponding identifier. - * Note that this function does not perform pose estimation. - * @note The function does not correct lens distortion or takes it into account. It's recommended to undistort - * input image with corresponging camera model, if camera parameters are known - * @sa undistort, estimatePoseSingleMarkers, estimatePoseBoard - */ - CV_WRAP void detectMarkers(InputArray image, OutputArrayOfArrays corners, OutputArray ids, - OutputArrayOfArrays rejectedImgPoints = noArray()); - - /** - * @brief Refind not detected markers based on the already detected and the board layout - * - * @param image input image - * @param board layout of markers in the board. - * @param detectedCorners vector of already detected marker corners. - * @param detectedIds vector of already detected marker identifiers. - * @param rejectedCorners vector of rejected candidates during the marker detection process. - * @param cameraMatrix optional input 3x3 floating-point camera matrix - * \f$A = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$ - * @param distCoeffs optional vector of distortion coefficients - * \f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6],[s_1, s_2, s_3, s_4]])\f$ of 4, 5, 8 or 12 elements - * @param recoveredIdxs Optional array to returns the indexes of the recovered candidates in the - * original rejectedCorners array. - * - * This function tries to find markers that were not detected in the basic detecMarkers function. - * First, based on the current detected marker and the board layout, the function interpolates - * the position of the missing markers. Then it tries to find correspondence between the reprojected - * markers and the rejected candidates based on the minRepDistance and errorCorrectionRate - * parameters. - * If camera parameters and distortion coefficients are provided, missing markers are reprojected - * using projectPoint function. If not, missing marker projections are interpolated using global - * homography, and all the marker corners in the board must have the same Z coordinate. - */ - CV_WRAP void refineDetectedMarkers(InputArray image, const Ptr &board, - InputOutputArrayOfArrays detectedCorners, - InputOutputArray detectedIds, InputOutputArrayOfArrays rejectedCorners, - InputArray cameraMatrix = noArray(), InputArray distCoeffs = noArray(), - OutputArray recoveredIdxs = noArray()); - - /** @brief Stores algorithm parameters in a file storage - */ - virtual void write(FileStorage& fs) const override { - Ptr pfs = makePtr(fs); - dictionary->writeDictionary(pfs); - params->writeDetectorParameters(pfs); - refineParams->writeRefineParameters(pfs); - } - - /** @brief simplified API for language bindings - * @overload - */ - CV_WRAP void write(const String& fileName) const { - FileStorage fs(fileName, FileStorage::WRITE); - write(fs); - } - - /** @brief Reads algorithm parameters from a file storage - */ - CV_WRAP virtual void read(const FileNode& fn) override { - dictionary->readDictionary(fn); - params->readDetectorParameters(fn); - refineParams->readRefineParameters(fn); - } -}; - -/** - * @brief Draw detected markers in image - * - * @param image input/output image. It must have 1 or 3 channels. The number of channels is not - * altered. - * @param corners positions of marker corners on input image. - * (e.g std::vector > ). For N detected markers, the dimensions of - * this array should be Nx4. The order of the corners should be clockwise. - * @param ids vector of identifiers for markers in markersCorners . - * Optional, if not provided, ids are not painted. - * @param borderColor color of marker borders. Rest of colors (text color and first corner color) - * are calculated based on this one to improve visualization. - * - * Given an array of detected marker corners and its corresponding ids, this functions draws - * the markers in the image. The marker borders are painted and the markers identifiers if provided. - * Useful for debugging purposes. - * - */ -CV_EXPORTS_W void drawDetectedMarkers(InputOutputArray image, InputArrayOfArrays corners, - InputArray ids = noArray(), Scalar borderColor = Scalar(0, 255, 0)); - -/** - * @brief Draw a canonical marker image - * - * @param dictionary dictionary of markers indicating the type of markers - * @param id identifier of the marker that will be returned. It has to be a valid id - * in the specified dictionary. - * @param sidePixels size of the image in pixels - * @param img output image with the marker - * @param borderBits width of the marker border. - * - * This function returns a marker image in its canonical form (i.e. ready to be printed) - */ -CV_EXPORTS_W void drawMarker(const Ptr &dictionary, int id, int sidePixels, OutputArray img, - int borderBits = 1); - -//! @} - -} -} - -#endif diff --git a/modules/aruco/misc/java/test/ArucoTest.java b/modules/aruco/misc/java/test/ArucoTest.java deleted file mode 100644 index 6e70eab1752..00000000000 --- a/modules/aruco/misc/java/test/ArucoTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.opencv.test.aruco; - -import java.util.ArrayList; -import java.util.List; - -import org.opencv.test.OpenCVTestCase; -import org.opencv.core.Scalar; -import org.opencv.core.Mat; -import org.opencv.core.CvType; -import org.opencv.aruco.*; - - -public class ArucoTest extends OpenCVTestCase { - - public void testArucoIssue3133() { - byte[][] marker = {{0,1,1},{1,1,1},{0,1,1}}; - Dictionary dictionary = Dictionary.create(1, 3); - dictionary.set_maxCorrectionBits(0); - Mat markerBits = new Mat(3, 3, CvType.CV_8UC1); - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - markerBits.put(i, j, marker[i][j]); - } - } - - Mat markerCompressed = Dictionary.getByteListFromBits(markerBits); - assertMatNotEqual(markerCompressed, dictionary.get_bytesList()); - - dictionary.set_bytesList(markerCompressed); - assertMatEqual(markerCompressed, dictionary.get_bytesList()); - } - - public void testArucoDetector() { - Dictionary dictionary = Dictionary.get(0); - DetectorParameters detectorParameters = DetectorParameters.create(); - ArucoDetector detector = ArucoDetector.create(dictionary, detectorParameters); - - Mat markerImage = new Mat(); - int id = 1, offset = 5, size = 40; - Aruco.drawMarker(dictionary, id, size, markerImage, detectorParameters.get_markerBorderBits()); - - Mat image = new Mat(markerImage.rows() + 2*offset, markerImage.cols() + 2*offset, - CvType.CV_8UC1, new Scalar(255)); - Mat m = image.submat(offset, size+offset, offset, size+offset); - markerImage.copyTo(m); - - List corners = new ArrayList(); - Mat ids = new Mat(); - detector.detectMarkers(image, corners, ids); - - assertEquals(1, corners.size()); - Mat res = corners.get(0); - assertArrayEquals(new double[]{offset, offset}, res.get(0, 0), 0.0); - assertArrayEquals(new double[]{size + offset - 1, offset}, res.get(0, 1), 0.0); - assertArrayEquals(new double[]{size + offset - 1, size + offset - 1}, res.get(0, 2), 0.0); - assertArrayEquals(new double[]{offset, size + offset - 1}, res.get(0, 3), 0.0); - } -} diff --git a/modules/aruco/misc/objc/gen_dict.json b/modules/aruco/misc/objc/gen_dict.json index ae74ae0fc98..d62cab1b91f 100644 --- a/modules/aruco/misc/objc/gen_dict.json +++ b/modules/aruco/misc/objc/gen_dict.json @@ -1,12 +1,10 @@ { "AdditionalImports" : { - "*" : [ "\"aruco.hpp\"" ], - "CharucoBoard" : [ "\"aruco/charuco.hpp\"" ], - "Dictionary" : [ "\"aruco/dictionary.hpp\"" ] + "*" : [ "\"aruco.hpp\"", "\"aruco/charuco.hpp\"" ] }, "func_arg_fix" : { - "Board" : { - "(void)setIds:(Mat*)ids" : { "setIds" : {"name" : "setIdsMat"} } + "Aruco" : { + "estimatePoseSingleMarkers" : { "estimateParameters" : {"defval" : "cv::makePtr()"} } } } } diff --git a/modules/aruco/misc/pattern_generator/MarkerPrinter.py b/modules/aruco/misc/pattern_generator/MarkerPrinter.py index 301f4f918fe..2ce69f97f06 100644 --- a/modules/aruco/misc/pattern_generator/MarkerPrinter.py +++ b/modules/aruco/misc/pattern_generator/MarkerPrinter.py @@ -39,7 +39,7 @@ def SaveArucoDictBytesList(filePath = "arucoDictBytesList.npz"): arucoDictBytesList = {} for name, flag in dictInfo: - arucoDict = aruco.Dictionary_get(flag) + arucoDict = aruco.getPredefinedDictionary(flag) arucoDictBytesList[name] = arucoDict.bytesList np.savez_compressed(filePath, **arucoDictBytesList) @@ -409,8 +409,8 @@ def GenChessMarkerImage(filePath, chessboardSize, squareLength, subSize=None, pa subChessboardBlockX = np.clip ( np.arange(0, subSize[0] * subDivide[0] + 1, subSize[0]), 0, chessboardSize[0]) subChessboardBlockY = np.clip ( np.arange(0, subSize[1] * subDivide[1] + 1, subSize[1]), 0, chessboardSize[1]) - subChessboardSliceX = subChessboardBlockX.astype(np.float) * squareLength - subChessboardSliceY = subChessboardBlockY.astype(np.float) * squareLength + subChessboardSliceX = subChessboardBlockX.astype(float) * squareLength + subChessboardSliceY = subChessboardBlockY.astype(float) * squareLength for subXID in range(subDivide[0]): for subYID in range(subDivide[1]): @@ -722,8 +722,8 @@ def GenCharucoMarkerImage(filePath, dictionary, chessboardSize, squareLength, ma subChessboardBlockX = np.clip ( np.arange(0, subSize[0] * subDivide[0] + 1, subSize[0]), 0, chessboardSize[0]) subChessboardBlockY = np.clip ( np.arange(0, subSize[1] * subDivide[1] + 1, subSize[1]), 0, chessboardSize[1]) - subChessboardSliceX = subChessboardBlockX.astype(np.float) * squareLength - subChessboardSliceY = subChessboardBlockY.astype(np.float) * squareLength + subChessboardSliceX = subChessboardBlockX.astype(float) * squareLength + subChessboardSliceY = subChessboardBlockY.astype(float) * squareLength for subXID in range(subDivide[0]): for subYID in range(subDivide[1]): @@ -922,8 +922,8 @@ def GenArucoGridMarkerImage(filePath, dictionary, chessboardSize, markerLength, subChessboardBlockX = np.clip ( np.arange(0, subSize[0] * subDivide[0] + 1, subSize[0]), 0, chessboardSize[0]) subChessboardBlockY = np.clip ( np.arange(0, subSize[1] * subDivide[1] + 1, subSize[1]), 0, chessboardSize[1]) - subChessboardSliceX = subChessboardBlockX.astype(np.float) * (markerLength + markerSeparation) - subChessboardSliceY = subChessboardBlockY.astype(np.float) * (markerLength + markerSeparation) + subChessboardSliceX = subChessboardBlockX.astype(float) * (markerLength + markerSeparation) + subChessboardSliceY = subChessboardBlockY.astype(float) * (markerLength + markerSeparation) subChessboardSliceX[-1] -= markerSeparation subChessboardSliceY[-1] -= markerSeparation diff --git a/modules/aruco/misc/python/test/test_aruco.py b/modules/aruco/misc/python/test/test_aruco.py index ebbb86622ab..d3f381b9b56 100644 --- a/modules/aruco/misc/python/test/test_aruco.py +++ b/modules/aruco/misc/python/test/test_aruco.py @@ -11,88 +11,13 @@ class aruco_test(NewOpenCVTests): - def test_idsAccessibility(self): - - ids = np.arange(17) - rev_ids = ids[::-1] - - aruco_dict = cv.aruco.Dictionary_get(cv.aruco.DICT_5X5_250) - board = cv.aruco.CharucoBoard_create(7, 5, 1, 0.5, aruco_dict) - - np.testing.assert_array_equal(board.getIds().squeeze(), ids) - - board.setIds(rev_ids) - np.testing.assert_array_equal(board.getIds().squeeze(), rev_ids) - - board.setIds(ids) - np.testing.assert_array_equal(board.getIds().squeeze(), ids) - - with self.assertRaises(cv.error): - board.setIds(np.array([0])) - - def test_drawCharucoDiamond(self): - aruco_dict = cv.aruco.Dictionary_get(cv.aruco.DICT_4X4_50) - img = cv.aruco.drawCharucoDiamond(aruco_dict, np.array([0, 1, 2, 3]), 100, 80) - self.assertTrue(img is not None) - - def test_write_read_dict(self): - - try: - aruco_dict = cv.aruco.getPredefinedDictionary(cv.aruco.DICT_5X5_50) - markers_gold = aruco_dict.bytesList - - # write aruco_dict - filename = "test_dict.yml" - fs_write = cv.FileStorage(filename, cv.FileStorage_WRITE) - aruco_dict.writeDictionary(fs_write) - fs_write.release() - - # reset aruco_dict - aruco_dict = cv.aruco.getPredefinedDictionary(cv.aruco.DICT_6X6_250) - - # read aruco_dict - fs_read = cv.FileStorage(filename, cv.FileStorage_READ) - aruco_dict.readDictionary(fs_read.root()) - fs_read.release() - - # check equal - self.assertEqual(aruco_dict.markerSize, 5) - self.assertEqual(aruco_dict.maxCorrectionBits, 3) - np.testing.assert_array_equal(aruco_dict.bytesList, markers_gold) - - finally: - if os.path.exists(filename): - os.remove(filename) - - def test_identify(self): - aruco_dict = cv.aruco.Dictionary_get(cv.aruco.DICT_4X4_50) - expected_idx = 9 - expected_rotation = 2 - bit_marker = np.array([[0, 1, 1, 0], [1, 0, 1, 0], [1, 1, 1, 1], [0, 0, 1, 1]], dtype=np.uint8) - - check, idx, rotation = aruco_dict.identify(bit_marker, 0) - - self.assertTrue(check, True) - self.assertEqual(idx, expected_idx) - self.assertEqual(rotation, expected_rotation) - - def test_getDistanceToId(self): - aruco_dict = cv.aruco.Dictionary_get(cv.aruco.DICT_4X4_50) - idx = 7 - rotation = 3 - bit_marker = np.array([[0, 1, 0, 1], [0, 1, 1, 1], [1, 1, 0, 0], [0, 1, 0, 0]], dtype=np.uint8) - dist = aruco_dict.getDistanceToId(bit_marker, idx) - - self.assertEqual(dist, 0) - - def test_aruco_detector(self): - aruco_params = cv.aruco.DetectorParameters_create() - aruco_dict = cv.aruco.Dictionary_get(cv.aruco.DICT_4X4_250) - aruco_detector = cv.aruco.ArucoDetector_create(aruco_dict, aruco_params) + def test_aruco_detect_markers(self): + aruco_params = cv.aruco.DetectorParameters() + aruco_dict = cv.aruco.getPredefinedDictionary(cv.aruco.DICT_4X4_250) id = 2 marker_size = 100 offset = 10 - img_marker = cv.aruco.drawMarker(aruco_dict, id, marker_size, aruco_params.markerBorderBits) + img_marker = cv.aruco.generateImageMarker(aruco_dict, id, marker_size, aruco_params.markerBorderBits) img_marker = np.pad(img_marker, pad_width=offset, mode='constant', constant_values=255) gold_corners = np.array([[offset, offset],[marker_size+offset-1.0,offset], [marker_size+offset-1.0,marker_size+offset-1.0], @@ -100,40 +25,15 @@ def test_aruco_detector(self): expected_corners, expected_ids, expected_rejected = cv.aruco.detectMarkers(img_marker, aruco_dict, parameters=aruco_params) - corners, ids, rejected = aruco_detector.detectMarkers(img_marker) - - self.assertEqual(1, len(ids)) - self.assertEqual(id, ids[0]) - for i in range(0, len(ids)): - np.testing.assert_array_equal(expected_corners[i], corners[i]) - np.testing.assert_array_equal(gold_corners, corners[i].reshape(4, 2)) + self.assertEqual(1, len(expected_ids)) + self.assertEqual(id, expected_ids[0]) + for i in range(0, len(expected_corners)): + np.testing.assert_array_equal(gold_corners, expected_corners[i].reshape(4, 2)) - def test_aruco_detector_refine(self): - aruco_params = cv.aruco.DetectorParameters_create() - aruco_dict = cv.aruco.Dictionary_get(cv.aruco.DICT_4X4_250) - aruco_detector = cv.aruco.ArucoDetector_create(aruco_dict, aruco_params) - board_size = (3, 4) - board = cv.aruco.GridBoard_create(board_size[0], board_size[1], 5.0, 1.0, aruco_dict) - board_image = board.draw((board_size[0]*50, board_size[1]*50), marginSize=10) - - corners, ids, rejected = aruco_detector.detectMarkers(board_image) - self.assertEqual(board_size[0]*board_size[1], len(ids)) - - part_corners, part_ids, part_rejected = corners[:-1], ids[:-1], list(rejected) - part_rejected.append(corners[-1]) - - refine_corners, refine_ids, refine_rejected, recovered_ids = aruco_detector.refineDetectedMarkers(board_image, board, part_corners, part_ids, part_rejected) - refine_corners_c, _, _, _ = cv.aruco.refineDetectedMarkers(board_image, board, part_corners, part_ids, part_rejected) - - self.assertEqual(board_size[0] * board_size[1], len(refine_ids)) - self.assertEqual(1, len(recovered_ids)) - - for i in range(0, len(ids)): - np.testing.assert_array_equal(refine_corners_c[i], refine_corners[i]) - #self.assertEqual(ids[-1], recovered_ids[0]) - self.assertEqual(ids[-1], refine_ids[-1]) - self.assertEqual((1, 4, 2), refine_corners[0].shape) - np.testing.assert_array_equal(corners, refine_corners) + def test_drawCharucoDiamond(self): + aruco_dict = cv.aruco.getPredefinedDictionary(cv.aruco.DICT_4X4_50) + img = cv.aruco.drawCharucoDiamond(aruco_dict, np.array([0, 1, 2, 3]), 100, 80) + self.assertTrue(img is not None) if __name__ == '__main__': NewOpenCVTests.bootstrap() diff --git a/modules/aruco/perf/perf_aruco.cpp b/modules/aruco/perf/perf_aruco.cpp deleted file mode 100644 index 6cde729ff2e..00000000000 --- a/modules/aruco/perf/perf_aruco.cpp +++ /dev/null @@ -1,300 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html -#include "perf_precomp.hpp" - -namespace opencv_test { -using namespace perf; - -typedef tuple UseArucoParams; -typedef TestBaseWithParam EstimateAruco; -#define ESTIMATE_PARAMS Combine(Values(false, true), Values(-1)) - -static double deg2rad(double deg) { return deg * CV_PI / 180.; } - -class MarkerPainter -{ -private: - int imgMarkerSize = 0; - Mat cameraMatrix; -public: - MarkerPainter(const int size) - { - setImgMarkerSize(size); - } - - void setImgMarkerSize(const int size) - { - imgMarkerSize = size; - cameraMatrix = Mat::eye(3, 3, CV_64FC1); - cameraMatrix.at(0, 0) = cameraMatrix.at(1, 1) = imgMarkerSize; - cameraMatrix.at(0, 2) = imgMarkerSize / 2.0; - cameraMatrix.at(1, 2) = imgMarkerSize / 2.0; - } - - static std::pair getSyntheticRT(double yaw, double pitch, double distance) - { - auto rvec_tvec = std::make_pair(Mat(3, 1, CV_64FC1), Mat(3, 1, CV_64FC1)); - Mat& rvec = rvec_tvec.first; - Mat& tvec = rvec_tvec.second; - - // Rvec - // first put the Z axis aiming to -X (like the camera axis system) - Mat rotZ(3, 1, CV_64FC1); - rotZ.ptr(0)[0] = 0; - rotZ.ptr(0)[1] = 0; - rotZ.ptr(0)[2] = -0.5 * CV_PI; - - Mat rotX(3, 1, CV_64FC1); - rotX.ptr(0)[0] = 0.5 * CV_PI; - rotX.ptr(0)[1] = 0; - rotX.ptr(0)[2] = 0; - - Mat camRvec, camTvec; - composeRT(rotZ, Mat(3, 1, CV_64FC1, Scalar::all(0)), rotX, Mat(3, 1, CV_64FC1, Scalar::all(0)), - camRvec, camTvec); - - // now pitch and yaw angles - Mat rotPitch(3, 1, CV_64FC1); - rotPitch.ptr(0)[0] = 0; - rotPitch.ptr(0)[1] = pitch; - rotPitch.ptr(0)[2] = 0; - - Mat rotYaw(3, 1, CV_64FC1); - rotYaw.ptr(0)[0] = yaw; - rotYaw.ptr(0)[1] = 0; - rotYaw.ptr(0)[2] = 0; - - composeRT(rotPitch, Mat(3, 1, CV_64FC1, Scalar::all(0)), rotYaw, - Mat(3, 1, CV_64FC1, Scalar::all(0)), rvec, tvec); - - // compose both rotations - composeRT(camRvec, Mat(3, 1, CV_64FC1, Scalar::all(0)), rvec, - Mat(3, 1, CV_64FC1, Scalar::all(0)), rvec, tvec); - - // Tvec, just move in z (camera) direction the specific distance - tvec.ptr(0)[0] = 0.; - tvec.ptr(0)[1] = 0.; - tvec.ptr(0)[2] = distance; - return rvec_tvec; -} - - std::pair > getProjectMarker(int id, double yaw, double pitch, - const Ptr& parameters, - const Ptr& dictionary) - { - auto marker_corners = std::make_pair(Mat(imgMarkerSize, imgMarkerSize, CV_8UC1, Scalar::all(255)), vector()); - Mat& img = marker_corners.first; - vector& corners = marker_corners.second; - - // canonical image - const int markerSizePixels = static_cast(imgMarkerSize/sqrt(2.f)); - aruco::drawMarker(dictionary, id, markerSizePixels, img, parameters->markerBorderBits); - - // get rvec and tvec for the perspective - const double distance = 0.1; - auto rvec_tvec = MarkerPainter::getSyntheticRT(yaw, pitch, distance); - Mat& rvec = rvec_tvec.first; - Mat& tvec = rvec_tvec.second; - - const float markerLength = 0.05f; - vector markerObjPoints; - markerObjPoints.emplace_back(Point3f(-markerLength / 2.f, +markerLength / 2.f, 0)); - markerObjPoints.emplace_back(markerObjPoints[0] + Point3f(markerLength, 0, 0)); - markerObjPoints.emplace_back(markerObjPoints[0] + Point3f(markerLength, -markerLength, 0)); - markerObjPoints.emplace_back(markerObjPoints[0] + Point3f(0, -markerLength, 0)); - - // project markers and draw them - Mat distCoeffs(5, 1, CV_64FC1, Scalar::all(0)); - projectPoints(markerObjPoints, rvec, tvec, cameraMatrix, distCoeffs, corners); - - vector originalCorners; - originalCorners.emplace_back(Point2f(0.f, 0.f)); - originalCorners.emplace_back(originalCorners[0]+Point2f((float)markerSizePixels, 0)); - originalCorners.emplace_back(originalCorners[0]+Point2f((float)markerSizePixels, (float)markerSizePixels)); - originalCorners.emplace_back(originalCorners[0]+Point2f(0, (float)markerSizePixels)); - - Mat transformation = getPerspectiveTransform(originalCorners, corners); - - warpPerspective(img, img, transformation, Size(imgMarkerSize, imgMarkerSize), INTER_NEAREST, BORDER_CONSTANT, - Scalar::all(255)); - return marker_corners; - } - - std::pair > > getProjectMarkersTile(const int numMarkers, - const Ptr& params, - const Ptr& dictionary) - { - Mat tileImage(imgMarkerSize*numMarkers, imgMarkerSize*numMarkers, CV_8UC1, Scalar::all(255)); - map > idCorners; - - int iter = 0, pitch = 0, yaw = 0; - for (int i = 0; i < numMarkers; i++) - { - for (int j = 0; j < numMarkers; j++) - { - int currentId = iter; - auto marker_corners = getProjectMarker(currentId, deg2rad(70+yaw), deg2rad(pitch), params, dictionary); - Point2i startPoint(j*imgMarkerSize, i*imgMarkerSize); - Mat tmp_roi = tileImage(Rect(startPoint.x, startPoint.y, imgMarkerSize, imgMarkerSize)); - marker_corners.first.copyTo(tmp_roi); - - for (Point2f& point: marker_corners.second) - point += static_cast(startPoint); - idCorners[currentId] = marker_corners.second; - auto test = idCorners[currentId]; - yaw = (yaw + 10) % 51; // 70+yaw >= 70 && 70+yaw <= 120 - iter++; - } - pitch = (pitch + 60) % 360; - } - return std::make_pair(tileImage, idCorners); - } -}; - -static inline double getMaxDistance(map > &golds, const vector& ids, - const vector >& corners) -{ - std::map mapDist; - for (const auto& el : golds) - mapDist[el.first] = std::numeric_limits::max(); - for (size_t i = 0; i < ids.size(); i++) - { - int id = ids[i]; - const auto gold_corners = golds.find(id); - if (gold_corners != golds.end()) { - double distance = 0.; - for (int c = 0; c < 4; c++) - distance = std::max(distance, cv::norm(gold_corners->second[c] - corners[i][c])); - mapDist[id] = distance; - } - } - return std::max_element(std::begin(mapDist), std::end(mapDist), - [](const pair& p1, const pair& p2){return p1.second < p2.second;})->second; -} - -PERF_TEST_P(EstimateAruco, ArucoFirst, ESTIMATE_PARAMS) -{ - UseArucoParams testParams = GetParam(); - Ptr dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250); - Ptr detectorParams = aruco::DetectorParameters::create(); - detectorParams->minDistanceToBorder = 1; - detectorParams->markerBorderBits = 1; - detectorParams->cornerRefinementMethod = cv::aruco::CORNER_REFINE_SUBPIX; - - const int markerSize = 100; - const int numMarkersInRow = 9; - //USE_ARUCO3 - detectorParams->useAruco3Detection = get<0>(testParams); - if (detectorParams->useAruco3Detection) { - detectorParams->minSideLengthCanonicalImg = 32; - detectorParams->minMarkerLengthRatioOriginalImg = 0.04f / numMarkersInRow; - } - aruco::ArucoDetector detector(dictionary, detectorParams); - MarkerPainter painter(markerSize); - auto image_map = painter.getProjectMarkersTile(numMarkersInRow, detectorParams, dictionary); - - // detect markers - vector > corners; - vector ids; - TEST_CYCLE() - { - detector.detectMarkers(image_map.first, corners, ids); - } - ASSERT_EQ(numMarkersInRow*numMarkersInRow, static_cast(ids.size())); - double maxDistance = getMaxDistance(image_map.second, ids, corners); - ASSERT_LT(maxDistance, 3.); - SANITY_CHECK_NOTHING(); -} - -PERF_TEST_P(EstimateAruco, ArucoSecond, ESTIMATE_PARAMS) -{ - UseArucoParams testParams = GetParam(); - Ptr dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250); - Ptr detectorParams = aruco::DetectorParameters::create(); - detectorParams->minDistanceToBorder = 1; - detectorParams->markerBorderBits = 1; - detectorParams->cornerRefinementMethod = cv::aruco::CORNER_REFINE_SUBPIX; - - //USE_ARUCO3 - detectorParams->useAruco3Detection = get<0>(testParams); - if (detectorParams->useAruco3Detection) { - detectorParams->minSideLengthCanonicalImg = 64; - detectorParams->minMarkerLengthRatioOriginalImg = 0.f; - } - aruco::ArucoDetector detector(dictionary, detectorParams); - const int markerSize = 200; - const int numMarkersInRow = 11; - MarkerPainter painter(markerSize); - auto image_map = painter.getProjectMarkersTile(numMarkersInRow, detectorParams, dictionary); - - // detect markers - vector > corners; - vector ids; - TEST_CYCLE() - { - detector.detectMarkers(image_map.first, corners, ids); - } - ASSERT_EQ(numMarkersInRow*numMarkersInRow, static_cast(ids.size())); - double maxDistance = getMaxDistance(image_map.second, ids, corners); - ASSERT_LT(maxDistance, 3.); - SANITY_CHECK_NOTHING(); -} - -struct Aruco3Params -{ - bool useAruco3Detection = false; - float minMarkerLengthRatioOriginalImg = 0.f; - int minSideLengthCanonicalImg = 0; - - Aruco3Params(bool useAruco3, float minMarkerLen, int minSideLen): useAruco3Detection(useAruco3), - minMarkerLengthRatioOriginalImg(minMarkerLen), - minSideLengthCanonicalImg(minSideLen) {} - friend std::ostream& operator<<(std::ostream& os, const Aruco3Params& d) - { - os << d.useAruco3Detection << " " << d.minMarkerLengthRatioOriginalImg << " " << d.minSideLengthCanonicalImg; - return os; - } -}; -typedef tuple> ArucoTestParams; - -typedef TestBaseWithParam EstimateLargeAruco; -#define ESTIMATE_FHD_PARAMS Combine(Values(Aruco3Params(false, 0.f, 0), Aruco3Params(true, 0.f, 32), \ -Aruco3Params(true, 0.015f, 32), Aruco3Params(true, 0.f, 16), Aruco3Params(true, 0.0069f, 16)), \ -Values(std::make_pair(1440, 1), std::make_pair(480, 3), std::make_pair(144, 10))) - -PERF_TEST_P(EstimateLargeAruco, ArucoFHD, ESTIMATE_FHD_PARAMS) -{ - ArucoTestParams testParams = GetParam(); - Ptr dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250); - Ptr detectorParams = aruco::DetectorParameters::create(); - detectorParams->minDistanceToBorder = 1; - detectorParams->markerBorderBits = 1; - detectorParams->cornerRefinementMethod = cv::aruco::CORNER_REFINE_SUBPIX; - - //USE_ARUCO3 - detectorParams->useAruco3Detection = get<0>(testParams).useAruco3Detection; - if (detectorParams->useAruco3Detection) { - detectorParams->minSideLengthCanonicalImg = get<0>(testParams).minSideLengthCanonicalImg; - detectorParams->minMarkerLengthRatioOriginalImg = get<0>(testParams).minMarkerLengthRatioOriginalImg; - } - aruco::ArucoDetector detector(dictionary, detectorParams); - const int markerSize = get<1>(testParams).first; // 1440 or 480 or 144 - const int numMarkersInRow = get<1>(testParams).second; // 1 or 3 or 144 - MarkerPainter painter(markerSize); // num pixels is 1440x1440 as in FHD 1920x1080 - auto image_map = painter.getProjectMarkersTile(numMarkersInRow, detectorParams, dictionary); - - // detect markers - vector > corners; - vector ids; - TEST_CYCLE() - { - detector.detectMarkers(image_map.first, corners, ids); - } - ASSERT_EQ(numMarkersInRow*numMarkersInRow, static_cast(ids.size())); - double maxDistance = getMaxDistance(image_map.second, ids, corners); - ASSERT_LT(maxDistance, 3.); - SANITY_CHECK_NOTHING(); -} - -} diff --git a/modules/aruco/perf/perf_precomp.hpp b/modules/aruco/perf/perf_precomp.hpp index a72903624c8..73b72d77211 100644 --- a/modules/aruco/perf/perf_precomp.hpp +++ b/modules/aruco/perf/perf_precomp.hpp @@ -5,7 +5,5 @@ #define __OPENCV_PERF_PRECOMP_HPP__ #include "opencv2/ts.hpp" -#include "opencv2/aruco_detector.hpp" -#include "opencv2/calib3d.hpp" #endif diff --git a/modules/aruco/samples/aruco_dict_utils.cpp b/modules/aruco/samples/aruco_dict_utils.cpp index ab32f4f58a9..75fd2ee8b92 100644 --- a/modules/aruco/samples/aruco_dict_utils.cpp +++ b/modules/aruco/samples/aruco_dict_utils.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include using namespace cv; @@ -28,8 +28,8 @@ static inline int _getSelfDistance(const Mat &marker) { return minHamming; } -static inline int getFlipDistanceToId(Ptr dict, InputArray bits, int id, bool allRotations = true) { - Mat bytesList = dict->bytesList; +static inline int getFlipDistanceToId(const aruco::Dictionary& dict, InputArray bits, int id, bool allRotations = true) { + Mat bytesList = dict.bytesList; CV_Assert(id >= 0 && id < bytesList.rows); unsigned int nRotations = 4; @@ -74,12 +74,13 @@ static inline int getFlipDistanceToId(Ptr dict, InputArray bi return currentMinDistance; } -static inline Ptr generateCustomAsymmetricDictionary(int nMarkers, int markerSize, - const Ptr &baseDictionary, int randomSeed) { +static inline aruco::Dictionary generateCustomAsymmetricDictionary(int nMarkers, int markerSize, + const aruco::Dictionary &baseDictionary, + int randomSeed) { RNG rng((uint64)(randomSeed)); - Ptr out = makePtr(); - out->markerSize = markerSize; + aruco::Dictionary out; + out.markerSize = markerSize; // theoretical maximum intermarker distance // See S. Garrido-Jurado, R. Muñoz-Salinas, F. J. Madrid-Cuevas, and M. J. Marín-Jiménez. 2014. @@ -89,16 +90,16 @@ static inline Ptr generateCustomAsymmetricDictionary(int nMar int tau = 2 * (int)std::floor(float(C) * 4.f / 3.f); // if baseDictionary is provided, calculate its intermarker distance - if(baseDictionary->bytesList.rows > 0) { - CV_Assert(baseDictionary->markerSize == markerSize); - out->bytesList = baseDictionary->bytesList.clone(); + if(baseDictionary.bytesList.rows > 0) { + CV_Assert(baseDictionary.markerSize == markerSize); + out.bytesList = baseDictionary.bytesList.clone(); int minDistance = markerSize * markerSize + 1; - for(int i = 0; i < out->bytesList.rows; i++) { - Mat markerBytes = out->bytesList.rowRange(i, i + 1); + for(int i = 0; i < out.bytesList.rows; i++) { + Mat markerBytes = out.bytesList.rowRange(i, i + 1); Mat markerBits = aruco::Dictionary::getBitsFromByteList(markerBytes, markerSize); minDistance = min(minDistance, _getSelfDistance(markerBits)); - for(int j = i + 1; j < out->bytesList.rows; j++) { + for(int j = i + 1; j < out.bytesList.rows; j++) { minDistance = min(minDistance, getFlipDistanceToId(out, markerBits, j)); } } @@ -113,7 +114,7 @@ static inline Ptr generateCustomAsymmetricDictionary(int nMar const int maxUnproductiveIterations = 5000; int unproductiveIterations = 0; - while(out->bytesList.rows < nMarkers) { + while(out.bytesList.rows < nMarkers) { Mat currentMarker(markerSize, markerSize, CV_8UC1, Scalar::all(0)); rng.fill(currentMarker, RNG::UNIFORM, 0, 2); @@ -123,7 +124,7 @@ static inline Ptr generateCustomAsymmetricDictionary(int nMar // if self distance is better or equal than current best option, calculate distance // to previous accepted markers if(selfDistance >= bestTau) { - for(int i = 0; i < out->bytesList.rows; i++) { + for(int i = 0; i < out.bytesList.rows; i++) { int currentDistance = getFlipDistanceToId(out, currentMarker, i); minDistance = min(currentDistance, minDistance); if(minDistance <= bestTau) { @@ -137,7 +138,7 @@ static inline Ptr generateCustomAsymmetricDictionary(int nMar unproductiveIterations = 0; bestTau = 0; Mat bytes = aruco::Dictionary::getByteListFromBits(currentMarker); - out->bytesList.push_back(bytes); + out.bytesList.push_back(bytes); } else { unproductiveIterations++; @@ -153,41 +154,41 @@ static inline Ptr generateCustomAsymmetricDictionary(int nMar tau = bestTau; bestTau = 0; Mat bytes = aruco::Dictionary::getByteListFromBits(bestMarker); - out->bytesList.push_back(bytes); + out.bytesList.push_back(bytes); } } } // update the maximum number of correction bits for the generated dictionary - out->maxCorrectionBits = (tau - 1) / 2; + out.maxCorrectionBits = (tau - 1) / 2; return out; } -static inline int getMinDistForDict(const Ptr& dict) { - const int dict_size = dict->bytesList.rows; - const int marker_size = dict->markerSize; +static inline int getMinDistForDict(const aruco::Dictionary& dict) { + const int dict_size = dict.bytesList.rows; + const int marker_size = dict.markerSize; int minDist = marker_size * marker_size; for (int i = 0; i < dict_size; i++) { - Mat row = dict->bytesList.row(i); - Mat marker = dict->getBitsFromByteList(row, marker_size); + Mat row = dict.bytesList.row(i); + Mat marker = dict.getBitsFromByteList(row, marker_size); for (int j = 0; j < dict_size; j++) { if (j != i) { - minDist = min(dict->getDistanceToId(marker, j), minDist); + minDist = min(dict.getDistanceToId(marker, j), minDist); } } } return minDist; } -static inline int getMinAsymDistForDict(const Ptr& dict) { - const int dict_size = dict->bytesList.rows; - const int marker_size = dict->markerSize; +static inline int getMinAsymDistForDict(const aruco::Dictionary& dict) { + const int dict_size = dict.bytesList.rows; + const int marker_size = dict.markerSize; int minDist = marker_size * marker_size; for (int i = 0; i < dict_size; i++) { - Mat row = dict->bytesList.row(i); - Mat marker = dict->getBitsFromByteList(row, marker_size); + Mat row = dict.bytesList.row(i); + Mat marker = dict.getBitsFromByteList(row, marker_size); for (int j = 0; j < dict_size; j++) { if (j != i) @@ -229,14 +230,14 @@ int main(int argc, char *argv[]) int markerSize = parser.get("markerSize"); bool checkFlippedMarkers = parser.get("r"); - Ptr dictionary = aruco::getPredefinedDictionary(0); + aruco::Dictionary dictionary = aruco::getPredefinedDictionary(0); if (parser.has("d")) { int dictionaryId = parser.get("d"); - dictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId)); + dictionary = aruco::getPredefinedDictionary(aruco::PredefinedDictionaryType(dictionaryId)); } else if (parser.has("cd")) { FileStorage fs(parser.get("cd"), FileStorage::READ); - bool readOk = dictionary->aruco::Dictionary::readDictionary(fs.root()); + bool readOk = dictionary.aruco::Dictionary::readDictionary(fs.root()); if(!readOk) { cerr << "Invalid dictionary file" << endl; return 0; @@ -249,12 +250,12 @@ int main(int argc, char *argv[]) if (!outputFile.empty() && nMarkers > 0 && markerSize > 0) { - Ptr fs = makePtr(outputFile, FileStorage::WRITE); + FileStorage fs(outputFile, FileStorage::WRITE); if (checkFlippedMarkers) - dictionary = generateCustomAsymmetricDictionary(nMarkers, markerSize, makePtr(), 0); + dictionary = generateCustomAsymmetricDictionary(nMarkers, markerSize, aruco::Dictionary(), 0); else - dictionary = aruco::generateCustomDictionary(nMarkers, markerSize, makePtr(), 0); - dictionary->writeDictionary(fs); + dictionary = aruco::extendDictionary(nMarkers, markerSize, aruco::Dictionary(), 0); + dictionary.writeDictionary(fs); } if (checkFlippedMarkers) { diff --git a/modules/aruco/samples/aruco_samples_utility.hpp b/modules/aruco/samples/aruco_samples_utility.hpp index ebdbcc1d7ec..6387bfc3ef5 100644 --- a/modules/aruco/samples/aruco_samples_utility.hpp +++ b/modules/aruco/samples/aruco_samples_utility.hpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include diff --git a/modules/aruco/samples/calibrate_camera.cpp b/modules/aruco/samples/calibrate_camera.cpp index 3e55e5e32e7..3620f502484 100644 --- a/modules/aruco/samples/calibrate_camera.cpp +++ b/modules/aruco/samples/calibrate_camera.cpp @@ -40,8 +40,8 @@ the use of this software, even if advised of the possibility of such damage. #include #include #include -#include -#include +#include +#include #include #include #include @@ -103,10 +103,10 @@ int main(int argc, char *argv[]) { if(parser.get("zt")) calibrationFlags |= CALIB_ZERO_TANGENT_DIST; if(parser.get("pc")) calibrationFlags |= CALIB_FIX_PRINCIPAL_POINT; - Ptr detectorParams = aruco::DetectorParameters::create(); + aruco::DetectorParameters detectorParams; if(parser.has("dp")) { FileStorage fs(parser.get("dp"), FileStorage::READ); - bool readOk = detectorParams->readDetectorParameters(fs.root()); + bool readOk = detectorParams.readDetectorParameters(fs.root()); if(!readOk) { cerr << "Invalid detector parameters file" << endl; return 0; @@ -136,14 +136,14 @@ int main(int argc, char *argv[]) { waitTime = 10; } - Ptr dictionary = aruco::getPredefinedDictionary(0); + aruco::Dictionary dictionary = aruco::getPredefinedDictionary(0); if (parser.has("d")) { int dictionaryId = parser.get("d"); - dictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId)); + dictionary = aruco::getPredefinedDictionary(aruco::PredefinedDictionaryType(dictionaryId)); } else if (parser.has("cd")) { FileStorage fs(parser.get("cd"), FileStorage::READ); - bool readOk = dictionary->aruco::Dictionary::readDictionary(fs.root()); + bool readOk = dictionary.aruco::Dictionary::readDictionary(fs.root()); if(!readOk) { cerr << "Invalid dictionary file" << endl; return 0; @@ -155,8 +155,7 @@ int main(int argc, char *argv[]) { } // create board object - Ptr gridboard = - aruco::GridBoard::create(markersX, markersY, markerLength, markerSeparation, dictionary); + Ptr gridboard = new aruco::GridBoard(Size(markersX, markersY), markerLength, markerSeparation, dictionary); Ptr board = gridboard.staticCast(); // collected frames for calibration @@ -177,7 +176,7 @@ int main(int argc, char *argv[]) { detector.detectMarkers(image, corners, ids, rejected); // refind strategy to detect more markers - if(refindStrategy) detector.refineDetectedMarkers(image, board, corners, ids, rejected); + if(refindStrategy) detector.refineDetectedMarkers(image, *board, corners, ids, rejected); // draw results image.copyTo(imageCopy); diff --git a/modules/aruco/samples/calibrate_camera_charuco.cpp b/modules/aruco/samples/calibrate_camera_charuco.cpp index 986475e4c1e..7ea6ff8d840 100644 --- a/modules/aruco/samples/calibrate_camera_charuco.cpp +++ b/modules/aruco/samples/calibrate_camera_charuco.cpp @@ -103,7 +103,7 @@ int main(int argc, char *argv[]) { if(parser.get("zt")) calibrationFlags |= CALIB_ZERO_TANGENT_DIST; if(parser.get("pc")) calibrationFlags |= CALIB_FIX_PRINCIPAL_POINT; - Ptr detectorParams = aruco::DetectorParameters::create(); + Ptr detectorParams = makePtr(); if(parser.has("dp")) { FileStorage fs(parser.get("dp"), FileStorage::READ); bool readOk = detectorParams->readDetectorParameters(fs.root()); @@ -136,14 +136,14 @@ int main(int argc, char *argv[]) { waitTime = 10; } - Ptr dictionary = aruco::getPredefinedDictionary(0); + aruco::Dictionary dictionary = aruco::getPredefinedDictionary(0); if (parser.has("d")) { int dictionaryId = parser.get("d"); - dictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId)); + dictionary = aruco::getPredefinedDictionary(aruco::PredefinedDictionaryType(dictionaryId)); } else if (parser.has("cd")) { FileStorage fs(parser.get("cd"), FileStorage::READ); - bool readOk = dictionary->aruco::Dictionary::readDictionary(fs.root()); + bool readOk = dictionary.aruco::Dictionary::readDictionary(fs.root()); if(!readOk) { cerr << "Invalid dictionary file" << endl; return 0; @@ -155,8 +155,7 @@ int main(int argc, char *argv[]) { } // create charuco board object - Ptr charucoboard = - aruco::CharucoBoard::create(squaresX, squaresY, squareLength, markerLength, dictionary); + Ptr charucoboard = new aruco::CharucoBoard(Size(squaresX, squaresY), squareLength, markerLength, dictionary); Ptr board = charucoboard.staticCast(); // collect data from each frame @@ -173,7 +172,7 @@ int main(int argc, char *argv[]) { vector< vector< Point2f > > corners, rejected; // detect markers - aruco::detectMarkers(image, dictionary, corners, ids, detectorParams, rejected); + aruco::detectMarkers(image, makePtr(dictionary), corners, ids, detectorParams, rejected); // refind strategy to detect more markers if(refindStrategy) aruco::refineDetectedMarkers(image, board, corners, ids, rejected); diff --git a/modules/aruco/samples/create_board.cpp b/modules/aruco/samples/create_board.cpp index 242688e5cb7..adb3a1947aa 100644 --- a/modules/aruco/samples/create_board.cpp +++ b/modules/aruco/samples/create_board.cpp @@ -38,7 +38,7 @@ the use of this software, even if advised of the possibility of such damage. #include -#include +#include #include #include "aruco_samples_utility.hpp" @@ -96,14 +96,14 @@ int main(int argc, char *argv[]) { imageSize.height = markersY * (markerLength + markerSeparation) - markerSeparation + 2 * margins; - Ptr dictionary = aruco::getPredefinedDictionary(0); + aruco::Dictionary dictionary = aruco::getPredefinedDictionary(0); if (parser.has("d")) { int dictionaryId = parser.get("d"); - dictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId)); + dictionary = aruco::getPredefinedDictionary(aruco::PredefinedDictionaryType(dictionaryId)); } else if (parser.has("cd")) { FileStorage fs(parser.get("cd"), FileStorage::READ); - bool readOk = dictionary->aruco::Dictionary::readDictionary(fs.root()); + bool readOk = dictionary.aruco::Dictionary::readDictionary(fs.root()); if(!readOk) { std::cerr << "Invalid dictionary file" << std::endl; @@ -115,12 +115,11 @@ int main(int argc, char *argv[]) { return 0; } - Ptr board = aruco::GridBoard::create(markersX, markersY, float(markerLength), - float(markerSeparation), dictionary); + aruco::GridBoard board(Size(markersX, markersY), float(markerLength), float(markerSeparation), dictionary); // show created board Mat boardImage; - board->draw(imageSize, boardImage, margins, borderBits); + board.generateImage(imageSize, boardImage, margins, borderBits); if(showImage) { imshow("board", boardImage); diff --git a/modules/aruco/samples/create_board_charuco.cpp b/modules/aruco/samples/create_board_charuco.cpp index c9ece573b3f..2a32500f700 100644 --- a/modules/aruco/samples/create_board_charuco.cpp +++ b/modules/aruco/samples/create_board_charuco.cpp @@ -93,14 +93,14 @@ int main(int argc, char *argv[]) { return 0; } - Ptr dictionary = aruco::getPredefinedDictionary(0); + aruco::Dictionary dictionary = aruco::getPredefinedDictionary(0); if (parser.has("d")) { int dictionaryId = parser.get("d"); - dictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId)); + dictionary = aruco::getPredefinedDictionary(aruco::PredefinedDictionaryType(dictionaryId)); } else if (parser.has("cd")) { FileStorage fs(parser.get("cd"), FileStorage::READ); - bool readOk = dictionary->aruco::Dictionary::readDictionary(fs.root()); + bool readOk = dictionary.aruco::Dictionary::readDictionary(fs.root()); if(!readOk) { std::cerr << "Invalid dictionary file" << std::endl; return 0; @@ -115,12 +115,11 @@ int main(int argc, char *argv[]) { imageSize.width = squaresX * squareLength + 2 * margins; imageSize.height = squaresY * squareLength + 2 * margins; - Ptr board = aruco::CharucoBoard::create(squaresX, squaresY, (float)squareLength, - (float)markerLength, dictionary); + aruco::CharucoBoard board(Size(squaresX, squaresY), (float)squareLength, (float)markerLength, dictionary); // show created board Mat boardImage; - board->draw(imageSize, boardImage, margins, borderBits); + board.generateImage(imageSize, boardImage, margins, borderBits); if(showImage) { imshow("board", boardImage); diff --git a/modules/aruco/samples/create_diamond.cpp b/modules/aruco/samples/create_diamond.cpp index 66aec22743c..1ccc0cd351a 100644 --- a/modules/aruco/samples/create_diamond.cpp +++ b/modules/aruco/samples/create_diamond.cpp @@ -86,8 +86,7 @@ int main(int argc, char *argv[]) { return 0; } - Ptr dictionary = - aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId)); + aruco::Dictionary dictionary = aruco::getPredefinedDictionary(aruco::PredefinedDictionaryType(dictionaryId)); istringstream ss(idsString); vector< string > splittedIds; @@ -104,7 +103,7 @@ int main(int argc, char *argv[]) { ids[i] = atoi(splittedIds[i].c_str()); Mat markerImg; - aruco::drawCharucoDiamond(dictionary, ids, squareLength, markerLength, markerImg, margins, + aruco::drawCharucoDiamond(makePtr(dictionary), ids, squareLength, markerLength, markerImg, margins, borderBits); if(showImage) { diff --git a/modules/aruco/samples/create_marker.cpp b/modules/aruco/samples/create_marker.cpp index 73ce21880f6..199817ca18f 100644 --- a/modules/aruco/samples/create_marker.cpp +++ b/modules/aruco/samples/create_marker.cpp @@ -38,7 +38,7 @@ the use of this software, even if advised of the possibility of such damage. #include -#include +#include #include #include "aruco_samples_utility.hpp" @@ -84,14 +84,14 @@ int main(int argc, char *argv[]) { return 0; } - Ptr dictionary = aruco::getPredefinedDictionary(0); + aruco::Dictionary dictionary = aruco::getPredefinedDictionary(0); if (parser.has("d")) { int dictionaryId = parser.get("d"); - dictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId)); + dictionary = aruco::getPredefinedDictionary(aruco::PredefinedDictionaryType(dictionaryId)); } else if (parser.has("cd")) { FileStorage fs(parser.get("cd"), FileStorage::READ); - bool readOk = dictionary->aruco::Dictionary::readDictionary(fs.root()); + bool readOk = dictionary.aruco::Dictionary::readDictionary(fs.root()); if(!readOk) { std::cerr << "Invalid dictionary file" << std::endl; return 0; @@ -103,7 +103,7 @@ int main(int argc, char *argv[]) { } Mat markerImg; - aruco::drawMarker(dictionary, markerId, markerSize, markerImg, borderBits); + aruco::generateImageMarker(dictionary, markerId, markerSize, markerImg, borderBits); if(showImage) { imshow("marker", markerImg); diff --git a/modules/aruco/samples/detect_board.cpp b/modules/aruco/samples/detect_board.cpp index 7f9c3d1ebc7..a5cd16e4895 100644 --- a/modules/aruco/samples/detect_board.cpp +++ b/modules/aruco/samples/detect_board.cpp @@ -38,8 +38,7 @@ the use of this software, even if advised of the possibility of such damage. #include -#include -#include +#include #include #include #include "aruco_samples_utility.hpp" @@ -98,16 +97,16 @@ int main(int argc, char *argv[]) { } } - Ptr detectorParams = aruco::DetectorParameters::create(); + aruco::DetectorParameters detectorParams; if(parser.has("dp")) { FileStorage fs(parser.get("dp"), FileStorage::READ); - bool readOk = detectorParams->readDetectorParameters(fs.root()); + bool readOk = detectorParams.readDetectorParameters(fs.root()); if(!readOk) { cerr << "Invalid detector parameters file" << endl; return 0; } } - detectorParams->cornerRefinementMethod = aruco::CORNER_REFINE_SUBPIX; // do corner refinement in markers + detectorParams.cornerRefinementMethod = aruco::CORNER_REFINE_SUBPIX; // do corner refinement in markers String video; if(parser.has("v")) { @@ -119,14 +118,14 @@ int main(int argc, char *argv[]) { return 0; } - Ptr dictionary = aruco::getPredefinedDictionary(0); + aruco::Dictionary dictionary = aruco::getPredefinedDictionary(0); if (parser.has("d")) { int dictionaryId = parser.get("d"); - dictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId)); + dictionary = aruco::getPredefinedDictionary(aruco::PredefinedDictionaryType(dictionaryId)); } else if (parser.has("cd")) { FileStorage fs(parser.get("cd"), FileStorage::READ); - bool readOk = dictionary->aruco::Dictionary::readDictionary(fs.root()); + bool readOk = dictionary.aruco::Dictionary::readDictionary(fs.root()); if(!readOk) { cerr << "Invalid dictionary file" << endl; return 0; @@ -151,8 +150,7 @@ int main(int argc, char *argv[]) { markerSeparation); // create board object - Ptr gridboard = - aruco::GridBoard::create(markersX, markersY, markerLength, markerSeparation, dictionary); + Ptr gridboard = new aruco::GridBoard(Size(markersX, markersY), markerLength, markerSeparation, dictionary); Ptr board = gridboard.staticCast(); double totalTime = 0; @@ -173,14 +171,21 @@ int main(int argc, char *argv[]) { // refind strategy to detect more markers if(refindStrategy) - detector.refineDetectedMarkers(image, board, corners, ids, rejected, camMatrix, + detector.refineDetectedMarkers(image, *board, corners, ids, rejected, camMatrix, distCoeffs); // estimate board pose int markersOfBoardDetected = 0; - if(ids.size() > 0) - markersOfBoardDetected = - aruco::estimatePoseBoard(corners, ids, board, camMatrix, distCoeffs, rvec, tvec); + if(!ids.empty()) { + // Get object and image points for the solvePnP function + cv::Mat objPoints, imgPoints; + board->matchImagePoints(corners, ids, objPoints, imgPoints); + + // Find pose + cv::solvePnP(objPoints, imgPoints, camMatrix, distCoeffs, rvec, tvec); + + markersOfBoardDetected = (int)objPoints.total() / 4; + } double currentTime = ((double)getTickCount() - tick) / getTickFrequency(); totalTime += currentTime; @@ -192,11 +197,11 @@ int main(int argc, char *argv[]) { // draw results image.copyTo(imageCopy); - if(ids.size() > 0) { + if(!ids.empty()) { aruco::drawDetectedMarkers(imageCopy, corners, ids); } - if(showRejected && rejected.size() > 0) + if(showRejected && !rejected.empty()) aruco::drawDetectedMarkers(imageCopy, rejected, noArray(), Scalar(100, 0, 255)); if(markersOfBoardDetected > 0) diff --git a/modules/aruco/samples/detect_board_charuco.cpp b/modules/aruco/samples/detect_board_charuco.cpp index f413cef9fb3..68290e58d30 100644 --- a/modules/aruco/samples/detect_board_charuco.cpp +++ b/modules/aruco/samples/detect_board_charuco.cpp @@ -99,7 +99,7 @@ int main(int argc, char *argv[]) { } } - Ptr detectorParams = aruco::DetectorParameters::create(); + Ptr detectorParams = makePtr(); if(parser.has("dp")) { FileStorage fs(parser.get("dp"), FileStorage::READ); bool readOk = detectorParams->readDetectorParameters(fs.root()); @@ -114,14 +114,14 @@ int main(int argc, char *argv[]) { return 0; } - Ptr dictionary = aruco::getPredefinedDictionary(0); + aruco::Dictionary dictionary = aruco::getPredefinedDictionary(0); if (parser.has("d")) { int dictionaryId = parser.get("d"); - dictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId)); + dictionary = aruco::getPredefinedDictionary(aruco::PredefinedDictionaryType(dictionaryId)); } else if (parser.has("cd")) { FileStorage fs(parser.get("cd"), FileStorage::READ); - bool readOk = dictionary->aruco::Dictionary::readDictionary(fs.root()); + bool readOk = dictionary.aruco::Dictionary::readDictionary(fs.root()); if(!readOk) { cerr << "Invalid dictionary file" << endl; return 0; @@ -145,8 +145,7 @@ int main(int argc, char *argv[]) { float axisLength = 0.5f * ((float)min(squaresX, squaresY) * (squareLength)); // create charuco board object - Ptr charucoboard = - aruco::CharucoBoard::create(squaresX, squaresY, squareLength, markerLength, dictionary); + Ptr charucoboard = new aruco::CharucoBoard(Size(squaresX, squaresY), squareLength, markerLength, dictionary); Ptr board = charucoboard.staticCast(); double totalTime = 0; @@ -164,7 +163,7 @@ int main(int argc, char *argv[]) { Vec3d rvec, tvec; // detect markers - aruco::detectMarkers(image, dictionary, markerCorners, markerIds, detectorParams, + aruco::detectMarkers(image, makePtr(dictionary), markerCorners, markerIds, detectorParams, rejectedMarkers); // refind strategy to detect more markers @@ -182,8 +181,8 @@ int main(int argc, char *argv[]) { // estimate charuco board pose bool validPose = false; if(camMatrix.total() != 0) - validPose = aruco::estimatePoseCharucoBoard(charucoCorners, charucoIds, charucoboard, - camMatrix, distCoeffs, rvec, tvec); + validPose = estimatePoseCharucoBoard(charucoCorners, charucoIds, charucoboard, + camMatrix, distCoeffs, rvec, tvec); diff --git a/modules/aruco/samples/detect_diamonds.cpp b/modules/aruco/samples/detect_diamonds.cpp index e5255a6602c..8baa267858a 100644 --- a/modules/aruco/samples/detect_diamonds.cpp +++ b/modules/aruco/samples/detect_diamonds.cpp @@ -87,7 +87,7 @@ int main(int argc, char *argv[]) { bool autoScale = parser.has("as"); float autoScaleFactor = autoScale ? parser.get("as") : 1.f; - Ptr detectorParams = aruco::DetectorParameters::create(); + Ptr detectorParams = makePtr(); if(parser.has("dp")) { FileStorage fs(parser.get("dp"), FileStorage::READ); bool readOk = detectorParams->readDetectorParameters(fs.root()); @@ -98,9 +98,9 @@ int main(int argc, char *argv[]) { } if (parser.has("refine")) { //override cornerRefinementMethod read from config file - detectorParams->cornerRefinementMethod = parser.get("refine"); + detectorParams->cornerRefinementMethod = parser.get("refine"); } - std::cout << "Corner refinement method (0: None, 1: Subpixel, 2:contour, 3: AprilTag 2): " << detectorParams->cornerRefinementMethod << std::endl; + std::cout << "Corner refinement method (0: None, 1: Subpixel, 2:contour, 3: AprilTag 2): " << (int)detectorParams->cornerRefinementMethod << std::endl; int camId = parser.get("ci"); String video; @@ -114,14 +114,14 @@ int main(int argc, char *argv[]) { return 0; } - Ptr dictionary = aruco::getPredefinedDictionary(0); + aruco::Dictionary dictionary = aruco::getPredefinedDictionary(0); if (parser.has("d")) { int dictionaryId = parser.get("d"); - dictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId)); + dictionary = aruco::getPredefinedDictionary(aruco::PredefinedDictionaryType(dictionaryId)); } else if (parser.has("cd")) { FileStorage fs(parser.get("cd"), FileStorage::READ); - bool readOk = dictionary->aruco::Dictionary::readDictionary(fs.root()); + bool readOk = dictionary.aruco::Dictionary::readDictionary(fs.root()); if(!readOk) { cerr << "Invalid dictionary file" << endl; return 0; @@ -166,7 +166,7 @@ int main(int argc, char *argv[]) { vector< Vec3d > rvecs, tvecs; // detect markers - aruco::detectMarkers(image, dictionary, markerCorners, markerIds, detectorParams, + aruco::detectMarkers(image, makePtr(dictionary), markerCorners, markerIds, detectorParams, rejectedMarkers); // detect diamonds diff --git a/modules/aruco/samples/detect_markers.cpp b/modules/aruco/samples/detect_markers.cpp index de38c2a1b2c..97f5cb26a19 100644 --- a/modules/aruco/samples/detect_markers.cpp +++ b/modules/aruco/samples/detect_markers.cpp @@ -38,8 +38,7 @@ the use of this software, even if advised of the possibility of such damage. #include -#include -#include +#include #include #include "aruco_samples_utility.hpp" @@ -81,10 +80,10 @@ int main(int argc, char *argv[]) { bool estimatePose = parser.has("c"); float markerLength = parser.get("l"); - Ptr detectorParams = aruco::DetectorParameters::create(); + aruco::DetectorParameters detectorParams; if(parser.has("dp")) { FileStorage fs(parser.get("dp"), FileStorage::READ); - bool readOk = detectorParams->readDetectorParameters(fs.root()); + bool readOk = detectorParams.readDetectorParameters(fs.root()); if(!readOk) { cerr << "Invalid detector parameters file" << endl; return 0; @@ -93,9 +92,9 @@ int main(int argc, char *argv[]) { if (parser.has("refine")) { //override cornerRefinementMethod read from config file - detectorParams->cornerRefinementMethod = parser.get("refine"); + detectorParams.cornerRefinementMethod = parser.get("refine"); } - std::cout << "Corner refinement method (0: None, 1: Subpixel, 2:contour, 3: AprilTag 2): " << detectorParams->cornerRefinementMethod << std::endl; + std::cout << "Corner refinement method (0: None, 1: Subpixel, 2:contour, 3: AprilTag 2): " << (int)detectorParams.cornerRefinementMethod << std::endl; int camId = parser.get("ci"); @@ -109,14 +108,14 @@ int main(int argc, char *argv[]) { return 0; } - Ptr dictionary = aruco::getPredefinedDictionary(0); + aruco::Dictionary dictionary = aruco::getPredefinedDictionary(0); if (parser.has("d")) { int dictionaryId = parser.get("d"); - dictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId)); + dictionary = aruco::getPredefinedDictionary(aruco::PredefinedDictionaryType(dictionaryId)); } else if (parser.has("cd")) { FileStorage fs(parser.get("cd"), FileStorage::READ); - bool readOk = dictionary->aruco::Dictionary::readDictionary(fs.root()); + bool readOk = dictionary.aruco::Dictionary::readDictionary(fs.root()); if(!readOk) { std::cerr << "Invalid dictionary file" << std::endl; return 0; @@ -149,6 +148,13 @@ int main(int argc, char *argv[]) { double totalTime = 0; int totalIterations = 0; + // Set coordinate system + cv::Mat objPoints(4, 1, CV_32FC3); + objPoints.ptr(0)[0] = Vec3f(-markerLength/2.f, markerLength/2.f, 0); + objPoints.ptr(0)[1] = Vec3f(markerLength/2.f, markerLength/2.f, 0); + objPoints.ptr(0)[2] = Vec3f(markerLength/2.f, -markerLength/2.f, 0); + objPoints.ptr(0)[3] = Vec3f(-markerLength/2.f, -markerLength/2.f, 0); + while(inputVideo.grab()) { Mat image, imageCopy; inputVideo.retrieve(image); @@ -157,13 +163,19 @@ int main(int argc, char *argv[]) { vector< int > ids; vector< vector< Point2f > > corners, rejected; - vector< Vec3d > rvecs, tvecs; // detect markers and estimate pose detector.detectMarkers(image, corners, ids, rejected); - if(estimatePose && ids.size() > 0) - aruco::estimatePoseSingleMarkers(corners, markerLength, camMatrix, distCoeffs, rvecs, - tvecs); + + size_t nMarkers = corners.size(); + vector rvecs(nMarkers), tvecs(nMarkers); + + if(estimatePose && !ids.empty()) { + // Calculate pose for each marker + for (size_t i = 0; i < nMarkers; i++) { + solvePnP(objPoints, corners.at(i), camMatrix, distCoeffs, rvecs.at(i), tvecs.at(i)); + } + } double currentTime = ((double)getTickCount() - tick) / getTickFrequency(); totalTime += currentTime; @@ -175,7 +187,7 @@ int main(int argc, char *argv[]) { // draw results image.copyTo(imageCopy); - if(ids.size() > 0) { + if(!ids.empty()) { aruco::drawDetectedMarkers(imageCopy, corners, ids); if(estimatePose) { @@ -184,7 +196,7 @@ int main(int argc, char *argv[]) { } } - if(showRejected && rejected.size() > 0) + if(showRejected && !rejected.empty()) aruco::drawDetectedMarkers(imageCopy, rejected, noArray(), Scalar(100, 0, 255)); imshow("out", imageCopy); diff --git a/modules/aruco/samples/tutorial_charuco_create_detect.cpp b/modules/aruco/samples/tutorial_charuco_create_detect.cpp index 1c47003b57a..0e0d027a3ca 100644 --- a/modules/aruco/samples/tutorial_charuco_create_detect.cpp +++ b/modules/aruco/samples/tutorial_charuco_create_detect.cpp @@ -13,11 +13,11 @@ const char* keys = "{c | | Put value of c=1 to create charuco board static inline void createBoard() { - cv::Ptr dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); + cv::aruco::Dictionary dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); //! [createBoard] - cv::Ptr board = cv::aruco::CharucoBoard::create(5, 7, 0.04f, 0.02f, dictionary); + cv::aruco::CharucoBoard board(cv::Size(5, 7), 0.04f, 0.02f, dictionary); cv::Mat boardImage; - board->draw(cv::Size(600, 500), boardImage, 10, 1); + board.generateImage(cv::Size(600, 500), boardImage, 10, 1); //! [createBoard] cv::imwrite("BoardImage.jpg", boardImage); } @@ -36,9 +36,9 @@ static inline void detectCharucoBoardWithCalibrationPose() std::cerr << "Invalid camera file" << std::endl; } else { //! [dictboard] - cv::Ptr dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); - cv::Ptr board = cv::aruco::CharucoBoard::create(5, 7, 0.04f, 0.02f, dictionary); - cv::Ptr params = cv::aruco::DetectorParameters::create(); + cv::aruco::Dictionary dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); + cv::Ptr board = new cv::aruco::CharucoBoard(cv::Size(5, 7), 0.04f, 0.02f, dictionary); + cv::Ptr params = cv::makePtr(); //! [dictboard] while (inputVideo.grab()) { //! [inputImg] @@ -50,7 +50,7 @@ static inline void detectCharucoBoardWithCalibrationPose() //! [midcornerdet] std::vector markerIds; std::vector > markerCorners; - cv::aruco::detectMarkers(image, board->getDictionary(), markerCorners, markerIds, params); + cv::aruco::detectMarkers(image, cv::makePtr(board->getDictionary()), markerCorners, markerIds, params); //! [midcornerdet] // if at least one marker detected if (markerIds.size() > 0) { @@ -89,10 +89,10 @@ static inline void detectCharucoBoardWithoutCalibration() { cv::VideoCapture inputVideo; inputVideo.open(0); - cv::Ptr dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); - cv::Ptr board = cv::aruco::CharucoBoard::create(5, 7, 0.04f, 0.02f, dictionary); + cv::aruco::Dictionary dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); + cv::Ptr board = new cv::aruco::CharucoBoard(cv::Size(5, 7), 0.04f, 0.02f, dictionary); - cv::Ptr params = cv::aruco::DetectorParameters::create(); + cv::Ptr params = cv::makePtr(); params->cornerRefinementMethod = cv::aruco::CORNER_REFINE_NONE; while (inputVideo.grab()) { cv::Mat image, imageCopy; @@ -100,7 +100,7 @@ static inline void detectCharucoBoardWithoutCalibration() image.copyTo(imageCopy); std::vector markerIds; std::vector > markerCorners; - cv::aruco::detectMarkers(image, board->getDictionary(), markerCorners, markerIds, params); + cv::aruco::detectMarkers(image, cv::makePtr(board->getDictionary()), markerCorners, markerIds, params); //or //cv::aruco::detectMarkers(image, dictionary, markerCorners, markerIds, params); // if at least one marker detected diff --git a/modules/aruco/src/apriltag/apriltag_quad_thresh.cpp b/modules/aruco/src/apriltag/apriltag_quad_thresh.cpp deleted file mode 100644 index 1cacbeefab7..00000000000 --- a/modules/aruco/src/apriltag/apriltag_quad_thresh.cpp +++ /dev/null @@ -1,1666 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. -// -// Copyright (C) 2013-2016, The Regents of The University of Michigan. -// -// This software was developed in the APRIL Robotics Lab under the -// direction of Edwin Olson, ebolson@umich.edu. This software may be -// available under alternative licensing terms; contact the address above. -// -// The views and conclusions contained in the software and documentation are those -// of the authors and should not be interpreted as representing official policies, -// either expressed or implied, of the Regents of The University of Michigan. - -// limitation: image size must be <32768 in width and height. This is -// because we use a fixed-point 16 bit integer representation with one -// fractional bit. - -#include "../precomp.hpp" -#include "apriltag_quad_thresh.hpp" - -//#define APRIL_DEBUG -#ifdef APRIL_DEBUG - #include "opencv2/imgcodecs.hpp" - #include -#endif - -namespace cv { -namespace aruco { - -static void ptsort_(struct pt *pts, int sz); // forward delaration - -static inline -void ptsort(struct pt *pts, int sz) -{ -#define MAYBE_SWAP(arr,apos,bpos) \ - if (arr[apos].theta > arr[bpos].theta) { \ - tmp = arr[apos]; arr[apos] = arr[bpos]; arr[bpos] = tmp; \ - }; - - if (sz <= 1) - return; - - if (sz == 2) { - struct pt tmp; - MAYBE_SWAP(pts, 0, 1); - return; - } - - // NB: Using less-branch-intensive sorting networks here on the - // hunch that it's better for performance. - if (sz == 3) { // 3 element bubble sort is optimal - struct pt tmp; - MAYBE_SWAP(pts, 0, 1); - MAYBE_SWAP(pts, 1, 2); - MAYBE_SWAP(pts, 0, 1); - return; - } - - if (sz == 4) { // 4 element optimal sorting network. - struct pt tmp; - MAYBE_SWAP(pts, 0, 1); // sort each half, like a merge sort - MAYBE_SWAP(pts, 2, 3); - MAYBE_SWAP(pts, 0, 2); // minimum value is now at 0. - MAYBE_SWAP(pts, 1, 3); // maximum value is now at end. - MAYBE_SWAP(pts, 1, 2); // that only leaves the middle two. - return; - } - - if (sz == 5) { - // this 9-step swap is optimal for a sorting network, but two - // steps slower than a generic sort. - struct pt tmp; - MAYBE_SWAP(pts, 0, 1); // sort each half (3+2), like a merge sort - MAYBE_SWAP(pts, 3, 4); - MAYBE_SWAP(pts, 1, 2); - MAYBE_SWAP(pts, 0, 1); - MAYBE_SWAP(pts, 0, 3); // minimum element now at 0 - MAYBE_SWAP(pts, 2, 4); // maximum element now at end - MAYBE_SWAP(pts, 1, 2); // now resort the three elements 1-3. - MAYBE_SWAP(pts, 2, 3); - MAYBE_SWAP(pts, 1, 2); - return; - } - -#undef MAYBE_SWAP - - ptsort_(pts, sz); -} - -void ptsort_(struct pt *pts, int sz) -{ - // a merge sort with temp storage. - - // Use stack storage if it's not too big. - cv::AutoBuffer _tmp_stack(sz); - memcpy(_tmp_stack.data(), pts, sizeof(struct pt) * sz); - - int asz = sz/2; - int bsz = sz - asz; - - struct pt *as = &_tmp_stack[0]; - struct pt *bs = &_tmp_stack[asz]; - - ptsort(as, asz); - ptsort(bs, bsz); - -#define MERGE(apos,bpos) \ - if (as[apos].theta < bs[bpos].theta) \ - pts[outpos++] = as[apos++]; \ - else \ - pts[outpos++] = bs[bpos++]; - - int apos = 0, bpos = 0, outpos = 0; - while (apos + 8 < asz && bpos + 8 < bsz) { - MERGE(apos,bpos); MERGE(apos,bpos); MERGE(apos,bpos); MERGE(apos,bpos); - MERGE(apos,bpos); MERGE(apos,bpos); MERGE(apos,bpos); MERGE(apos,bpos); - } - - while (apos < asz && bpos < bsz) { - MERGE(apos,bpos); - } - - if (apos < asz) - memcpy(&pts[outpos], &as[apos], (asz-apos)*sizeof(struct pt)); - if (bpos < bsz) - memcpy(&pts[outpos], &bs[bpos], (bsz-bpos)*sizeof(struct pt)); - -#undef MERGE -} - -/** - * lfps contains *cumulative* moments for N points, with - * index j reflecting points [0,j] (inclusive). - * fit a line to the points [i0, i1] (inclusive). i0, i1 are both (0, sz) - * if i1 < i0, we treat this as a wrap around. - */ -void fit_line(struct line_fit_pt *lfps, int sz, int i0, int i1, double *lineparm, double *err, double *mse){ - CV_Assert(i0 != i1); - CV_Assert(i0 >= 0 && i1 >= 0 && i0 < sz && i1 < sz); - - double Mx, My, Mxx, Myy, Mxy, W; - int N; // how many points are included in the set? - - if (i0 < i1) { - N = i1 - i0 + 1; - - Mx = lfps[i1].Mx; - My = lfps[i1].My; - Mxx = lfps[i1].Mxx; - Mxy = lfps[i1].Mxy; - Myy = lfps[i1].Myy; - W = lfps[i1].W; - - if (i0 > 0) { - Mx -= lfps[i0-1].Mx; - My -= lfps[i0-1].My; - Mxx -= lfps[i0-1].Mxx; - Mxy -= lfps[i0-1].Mxy; - Myy -= lfps[i0-1].Myy; - W -= lfps[i0-1].W; - } - - } else { - // i0 > i1, e.g. [15, 2]. Wrap around. - CV_Assert(i0 > 0); - - Mx = lfps[sz-1].Mx - lfps[i0-1].Mx; - My = lfps[sz-1].My - lfps[i0-1].My; - Mxx = lfps[sz-1].Mxx - lfps[i0-1].Mxx; - Mxy = lfps[sz-1].Mxy - lfps[i0-1].Mxy; - Myy = lfps[sz-1].Myy - lfps[i0-1].Myy; - W = lfps[sz-1].W - lfps[i0-1].W; - - Mx += lfps[i1].Mx; - My += lfps[i1].My; - Mxx += lfps[i1].Mxx; - Mxy += lfps[i1].Mxy; - Myy += lfps[i1].Myy; - W += lfps[i1].W; - - N = sz - i0 + i1 + 1; - } - - CV_Assert(N >= 2); - - double Ex = Mx / W; - double Ey = My / W; - double Cxx = Mxx / W - Ex*Ex; - double Cxy = Mxy / W - Ex*Ey; - double Cyy = Myy / W - Ey*Ey; - - double nx, ny; - - if (1) { - // on iOS about 5% of total CPU spent in these trig functions. - // 85 ms per frame on 5S, example.pnm - // - // XXX this was using the double-precision atan2. Was there a case where - // we needed that precision? Seems doubtful. - float normal_theta = float(.5f * (CV_PI / 180)) * cv::fastAtan2((float)(-2*Cxy), (float)(Cyy - Cxx)); - nx = cosf(normal_theta); - ny = sinf(normal_theta); - } else { - // 73.5 ms per frame on 5S, example.pnm - double ty = -2*Cxy; - double tx = (Cyy - Cxx); - double mag = ty*ty + tx*tx; - - if (mag == 0) { - nx = 1; - ny = 0; - } else { - float norm = sqrtf((float)(ty*ty + tx*tx)); - tx /= norm; - - // ty is now sin(2theta) - // tx is now cos(2theta). We want sin(theta) and cos(theta) - - // due to precision err, tx could still have slightly too large magnitude. - if (tx > 1) { - ny = 0; - nx = 1; - } else if (tx < -1) { - ny = 1; - nx = 0; - } else { - // half angle formula - ny = sqrtf((1.0f - (float)tx)*0.5f); - nx = sqrtf((1.0f + (float)tx)*0.5f); - - // pick a consistent branch cut - if (ty < 0) - ny = - ny; - } - } - } - - if (lineparm) { - lineparm[0] = Ex; - lineparm[1] = Ey; - lineparm[2] = nx; - lineparm[3] = ny; - } - - // sum of squared errors = - // - // SUM_i ((p_x - ux)*nx + (p_y - uy)*ny)^2 - // SUM_i nx*nx*(p_x - ux)^2 + 2nx*ny(p_x -ux)(p_y-uy) + ny*ny*(p_y-uy)*(p_y-uy) - // nx*nx*SUM_i((p_x -ux)^2) + 2nx*ny*SUM_i((p_x-ux)(p_y-uy)) + ny*ny*SUM_i((p_y-uy)^2) - // - // nx*nx*N*Cxx + 2nx*ny*N*Cxy + ny*ny*N*Cyy - - // sum of squared errors - if (err) - *err = nx*nx*N*Cxx + 2*nx*ny*N*Cxy + ny*ny*N*Cyy; - - // mean squared error - if (mse) - *mse = nx*nx*Cxx + 2*nx*ny*Cxy + ny*ny*Cyy; -} - -int err_compare_descending(const void *_a, const void *_b){ - const double *a = (const double*)_a; - const double *b = (const double*)_b; - - return ((*a) < (*b)) ? 1 : -1; -} - -/** - 1. Identify A) white points near a black point and B) black points near a white point. - - 2. Find the connected components within each of the classes above, - yielding clusters of "white-near-black" and - "black-near-white". (These two classes are kept separate). Each - segment has a unique id. - - 3. For every pair of "white-near-black" and "black-near-white" - clusters, find the set of points that are in one and adjacent to the - other. In other words, a "boundary" layer between the two - clusters. (This is actually performed by iterating over the pixels, - rather than pairs of clusters.) Critically, this helps keep nearby - edges from becoming connected. - **/ -int quad_segment_maxima(const Ptr &td, int sz, struct line_fit_pt *lfps, int indices[4]){ - - // ksz: when fitting points, how many points on either side do we consider? - // (actual "kernel" width is 2ksz). - // - // This value should be about: 0.5 * (points along shortest edge). - // - // If all edges were equally-sized, that would give a value of - // sz/8. We make it somewhat smaller to account for tags at high - // aspects. - - // XXX Tunable. Maybe make a multiple of JPEG block size to increase robustness - // to JPEG compression artifacts? - //int ksz = imin(20, sz / 12); - int ksz = 20 < (sz/12)? 20: (sz/12); - - // can't fit a quad if there are too few points. - if (ksz < 2) - return 0; - - // printf("sz %5d, ksz %3d\n", sz, ksz); - - std::vector errs(sz); - - for (int i = 0; i < sz; i++) { - fit_line(lfps, sz, (i + sz - ksz) % sz, (i + ksz) % sz, NULL, &errs[i], NULL); - } - - // apply a low-pass filter to errs - if (1) { - std::vector y(sz); - - // how much filter to apply? - - // XXX Tunable - double sigma = 1; // was 3 - - // cutoff = exp(-j*j/(2*sigma*sigma)); - // log(cutoff) = -j*j / (2*sigma*sigma) - // log(cutoff)*2*sigma*sigma = -j*j; - - // how big a filter should we use? We make our kernel big - // enough such that we represent any values larger than - // 'cutoff'. - - // XXX Tunable (though not super useful to change) - double cutoff = 0.05; - int fsz = cvFloor(sqrt(-log(cutoff)*2*sigma*sigma)) + 1; - fsz = 2*fsz + 1; - - // For default values of cutoff = 0.05, sigma = 3, - // we have fsz = 17. - std::vector f(fsz); - - for (int i = 0; i < fsz; i++) { - int j = i - fsz / 2; - f[i] = (float)exp(-j*j/(2*sigma*sigma)); - } - - for (int iy = 0; iy < sz; iy++) { - double acc = 0; - - for (int i = 0; i < fsz; i++) { - acc += errs[(iy + i - fsz / 2 + sz) % sz] * f[i]; - } - y[iy] = acc; - } - copy(y.begin(), y.end(), errs.begin()); - } - - std::vector maxima(sz); - std::vector maxima_errs(sz); - int nmaxima = 0; - - for (int i = 0; i < sz; i++) { - if (errs[i] > errs[(i+1)%sz] && errs[i] > errs[(i+sz-1)%sz]) { - maxima[nmaxima] = i; - maxima_errs[nmaxima] = errs[i]; - nmaxima++; - } - } - // if we didn't get at least 4 maxima, we can't fit a quad. - if (nmaxima < 4) - return 0; - - // select only the best maxima if we have too many - int max_nmaxima = td->aprilTagMaxNmaxima; - - if (nmaxima > max_nmaxima) { - std::vector maxima_errs_copy(maxima_errs.begin(), maxima_errs.begin()+nmaxima); - - // throw out all but the best handful of maxima. Sorts descending. - qsort(maxima_errs_copy.data(), nmaxima, sizeof(double), err_compare_descending); - - double maxima_thresh = maxima_errs_copy[max_nmaxima]; - int out = 0; - for (int in = 0; in < nmaxima; in++) { - if (maxima_errs[in] <= maxima_thresh) - continue; - maxima[out++] = maxima[in]; - } - nmaxima = out; - } - - int best_indices[4]; - double best_error = HUGE_VALF; - - double err01, err12, err23, err30; - double mse01, mse12, mse23, mse30; - double params01[4], params12[4], params23[4], params30[4]; - - // disallow quads where the angle is less than a critical value. - double max_dot = std::cos(td->aprilTagCriticalRad); //25*M_PI/180); - - for (int m0 = 0; m0 < nmaxima - 3; m0++) { - int i0 = maxima[m0]; - - for (int m1 = m0+1; m1 < nmaxima - 2; m1++) { - int i1 = maxima[m1]; - - fit_line(lfps, sz, i0, i1, params01, &err01, &mse01); - - if (mse01 > td->aprilTagMaxLineFitMse) - continue; - - for (int m2 = m1+1; m2 < nmaxima - 1; m2++) { - int i2 = maxima[m2]; - - fit_line(lfps, sz, i1, i2, params12, &err12, &mse12); - if (mse12 > td->aprilTagMaxLineFitMse) - continue; - - double dot = params01[2]*params12[2] + params01[3]*params12[3]; - if (fabs(dot) > max_dot) - continue; - - for (int m3 = m2+1; m3 < nmaxima; m3++) { - int i3 = maxima[m3]; - - fit_line(lfps, sz, i2, i3, params23, &err23, &mse23); - if (mse23 > td->aprilTagMaxLineFitMse) - continue; - - fit_line(lfps, sz, i3, i0, params30, &err30, &mse30); - if (mse30 > td->aprilTagMaxLineFitMse) - continue; - - double err = err01 + err12 + err23 + err30; - if (err < best_error) { - best_error = err; - best_indices[0] = i0; - best_indices[1] = i1; - best_indices[2] = i2; - best_indices[3] = i3; - } - } - } - } - } - - if (best_error == HUGE_VALF) - return 0; - - for (int i = 0; i < 4; i++) - indices[i] = best_indices[i]; - - if (best_error / sz < td->aprilTagMaxLineFitMse) - return 1; - return 0; -} - -/** - * returns 0 if the cluster looks bad. - */ -int quad_segment_agg(int sz, struct line_fit_pt *lfps, int indices[4]){ - //int sz = zarray_size(cluster); - - zmaxheap_t *heap = zmaxheap_create(sizeof(struct remove_vertex*)); - - // We will initially allocate sz rvs. We then have two types of - // iterations: some iterations that are no-ops in terms of - // allocations, and those that remove a vertex and allocate two - // more children. This will happen at most (sz-4) times. Thus we - // need: sz + 2*(sz-4) entries. - - int rvalloc_pos = 0; - int rvalloc_size = 3*sz; - cv::AutoBuffer rvalloc_(std::max(1, rvalloc_size)); - memset(rvalloc_.data(), 0, sizeof(rvalloc_[0]) * rvalloc_.size()); // TODO Add AutoBuffer zero fill - struct remove_vertex *rvalloc = rvalloc_.data(); - cv::AutoBuffer segs_(std::max(1, sz)); // TODO Add AutoBuffer zero fill - memset(segs_.data(), 0, sizeof(segs_[0]) * segs_.size()); - struct segment *segs = segs_.data(); - - // populate with initial entries - for (int i = 0; i < sz; i++) { - struct remove_vertex *rv = &rvalloc[rvalloc_pos++]; - rv->i = i; - if (i == 0) { - rv->left = sz-1; - rv->right = 1; - } else { - rv->left = i-1; - rv->right = (i+1) % sz; - } - - fit_line(lfps, sz, rv->left, rv->right, NULL, NULL, &rv->err); - - //TODO is finite CV_Assert(): - CV_DbgAssert (!cvIsNaN(-rv->err) && "zmaxheap_add: Trying to add non-finite number to heap. NaN's prohibited, could allow INF with testing"); - zmaxheap_add(heap, &rv, (float)-rv->err); - - segs[i].left = rv->left; - segs[i].right = rv->right; - segs[i].is_vertex = 1; - } - - int nvertices = sz; - - while (nvertices > 4) { - CV_Assert(rvalloc_pos < rvalloc_size); - - struct remove_vertex *rv; - float err; - - int res = zmaxheap_remove_max(heap, &rv, &err); - if (!res) - return 0; - CV_Assert(res); - - // is this remove_vertex valid? (Or has one of the left/right - // vertices changes since we last looked?) - if (!segs[rv->i].is_vertex || - !segs[rv->left].is_vertex || - !segs[rv->right].is_vertex) { - continue; - } - - // we now merge. - CV_Assert(segs[rv->i].is_vertex); - - segs[rv->i].is_vertex = 0; - segs[rv->left].right = rv->right; - segs[rv->right].left = rv->left; - - // create the join to the left - if (1) { - struct remove_vertex *child = &rvalloc[rvalloc_pos++]; - child->i = rv->left; - child->left = segs[rv->left].left; - child->right = rv->right; - - fit_line(lfps, sz, child->left, child->right, NULL, NULL, &child->err); - - //TODO is finite CV_Assert(): - CV_DbgAssert (!cvIsNaN(-child->err) && "zmaxheap_add: Trying to add non-finite number to heap. NaN's prohibited, could allow INF with testing"); - zmaxheap_add(heap, &child, (float)-child->err); - } - - // create the join to the right - if (1) { - struct remove_vertex *child = &rvalloc[rvalloc_pos++]; - child->i = rv->right; - child->left = rv->left; - child->right = segs[rv->right].right; - - fit_line(lfps, sz, child->left, child->right, NULL, NULL, &child->err); - - //TODO is finite CV_Assert(): - CV_DbgAssert (!cvIsNaN(-child->err) && "zmaxheap_add: Trying to add non-finite number to heap. NaN's prohibited, could allow INF with testing"); - zmaxheap_add(heap, &child, (float)-child->err); - } - - // we now have one less vertex - nvertices--; - } - - zmaxheap_destroy(heap); - - int idx = 0; - for (int i = 0; i < sz; i++) { - if (segs[i].is_vertex) { - indices[idx++] = i; - } - } - - return 1; -} - -#define DO_UNIONFIND(dx, dy) if (im.data[y*s + dy*s + x + dx] == v) unionfind_connect(uf, y*w + x, y*w + dy*w + x + dx); -static void do_unionfind_line(unionfind_t *uf, Mat &im, int w, int s, int y){ - CV_Assert(y+1 < im.rows); - CV_Assert(!im.empty()); - - for (int x = 1; x < w - 1; x++) { - uint8_t v = im.data[y*s + x]; - - if (v == 127) - continue; - - // (dx,dy) pairs for 8 connectivity: - // (REFERENCE) (1, 0) - // (-1, 1) (0, 1) (1, 1) - // - DO_UNIONFIND(1, 0); - DO_UNIONFIND(0, 1); - if (v == 255) { - DO_UNIONFIND(-1, 1); - DO_UNIONFIND(1, 1); - } - } -} -#undef DO_UNIONFIND - -/** - * return 1 if the quad looks okay, 0 if it should be discarded - * quad - **/ -int fit_quad(const Ptr &_params, const Mat im, zarray_t *cluster, struct sQuad *quad){ - CV_Assert(cluster != NULL); - - int res = 0; - - int sz = _zarray_size(cluster); - if (sz < 4) // can't fit a quad to less than 4 points - return 0; - - ///////////////////////////////////////////////////////////// - // Step 1. Sort points so they wrap around the center of the - // quad. We will constrain our quad fit to simply partition this - // ordered set into 4 groups. - - // compute a bounding box so that we can order the points - // according to their angle WRT the center. - int32_t xmax = 0, xmin = INT32_MAX, ymax = 0, ymin = INT32_MAX; - - for (int pidx = 0; pidx < sz; pidx++) { - struct pt *p; - _zarray_get_volatile(cluster, pidx, &p); - - //(a > b) ? a : b; - //xmax = imax(xmax, p->x); - //xmin = imin(xmin, p->x); - //ymax = imax(ymax, p->y); - //ymin = imin(ymin, p->y); - - xmax = xmax > p->x? xmax : p->x; - xmin = xmin < p->x? xmin : p->x; - - ymax = ymax > p->y? ymax : p->y; - ymin = ymin < p->y? ymin : p->y; - } - - // add some noise to (cx,cy) so that pixels get a more diverse set - // of theta estimates. This will help us remove more points. - // (Only helps a small amount. The actual noise values here don't - // matter much at all, but we want them [-1, 1]. (XXX with - // fixed-point, should range be bigger?) - double cx = (xmin + xmax) * 0.5 + 0.05118; - double cy = (ymin + ymax) * 0.5 + -0.028581; - - double dot = 0; - - for (int pidx = 0; pidx < sz; pidx++) { - struct pt *p; - _zarray_get_volatile(cluster, pidx, &p); - - double dx = p->x - cx; - double dy = p->y - cy; - - p->theta = cv::fastAtan2((float)dy, (float)dx) * (float)(CV_PI/180); - - dot += dx*p->gx + dy*p->gy; - } - - // Ensure that the black border is inside the white border. - if (dot < 0) - return 0; - - // we now sort the points according to theta. This is a preparatory - // step for segmenting them into four lines. - if (1) { - // zarray_sort(cluster, pt_compare_theta); - ptsort((struct pt*) cluster->data, sz); - - // remove duplicate points. (A byproduct of our segmentation system.) - if (1) { - int outpos = 1; - - struct pt *last; - _zarray_get_volatile(cluster, 0, &last); - - for (int i = 1; i < sz; i++) { - - struct pt *p; - _zarray_get_volatile(cluster, i, &p); - - if (p->x != last->x || p->y != last->y) { - - if (i != outpos) { - struct pt *out; - _zarray_get_volatile(cluster, outpos, &out); - memcpy(out, p, sizeof(struct pt)); - } - - outpos++; - } - - last = p; - } - - cluster->size = outpos; - sz = outpos; - } - - } else { - // This is a counting sort in which we retain at most one - // point for every bucket; the bucket index is computed from - // theta. Since a good quad completes a complete revolution, - // there's reason to think that we should get a good - // distribution of thetas. We might "lose" a few points due - // to collisions, but this shouldn't affect quality very much. - - // XXX tunable. Increase to reduce the likelihood of "losing" - // points due to collisions. - int nbuckets = 4*sz; - -#define ASSOC 2 - std::vector > v(nbuckets, std::vector(ASSOC)); - - // put each point into a bucket. - for (int i = 0; i < sz; i++) { - struct pt *p; - _zarray_get_volatile(cluster, i, &p); - - CV_Assert(p->theta >= -CV_PI && p->theta <= CV_PI); - - int bucket = cvFloor((nbuckets - 1) * (p->theta + CV_PI) / (2*CV_PI)); - CV_Assert(bucket >= 0 && bucket < nbuckets); - - for (int j = 0; j < ASSOC; j++) { - if (v[bucket][j].theta == 0) { - v[bucket][j] = *p; - break; - } - } - } - - // collect the points from the buckets and put them back into the array. - int outsz = 0; - for (int i = 0; i < nbuckets; i++) { - for (int j = 0; j < ASSOC; j++) { - if (v[i][j].theta != 0) { - _zarray_set(cluster, outsz, &v[i][j], NULL); - outsz++; - } - } - } - - _zarray_truncate(cluster, outsz); - sz = outsz; - } - - if (sz < 4) - return 0; - - ///////////////////////////////////////////////////////////// - // Step 2. Precompute statistics that allow line fit queries to be - // efficiently computed for any contiguous range of indices. - - cv::AutoBuffer lfps_(sz); - memset(lfps_.data(), 0, sizeof(lfps_[0]) * lfps_.size()); // TODO Add AutoBuffer zero fill - struct line_fit_pt *lfps = lfps_.data(); - - for (int i = 0; i < sz; i++) { - struct pt *p; - _zarray_get_volatile(cluster, i, &p); - - if (i > 0) { - memcpy(&lfps[i], &lfps[i-1], sizeof(struct line_fit_pt)); - } - - if (0) { - // we now undo our fixed-point arithmetic. - double delta = 0.5; - double x = p->x * .5 + delta; - double y = p->y * .5 + delta; - double W; - - for (int dy = -1; dy <= 1; dy++) { - int iy = cvFloor(y + dy); - - if (iy < 0 || iy + 1 >= im.rows) - continue; - - for (int dx = -1; dx <= 1; dx++) { - int ix = cvFloor(x + dx); - - if (ix < 0 || ix + 1 >= im.cols) - continue; - - int grad_x = im.data[iy * im.cols + ix + 1] - - im.data[iy * im.cols + ix - 1]; - - int grad_y = im.data[(iy+1) * im.cols + ix] - - im.data[(iy-1) * im.cols + ix]; - - W = sqrtf(float(grad_x*grad_x + grad_y*grad_y)) + 1; - - // double fx = x + dx, fy = y + dy; - double fx = ix + .5, fy = iy + .5; - lfps[i].Mx += W * fx; - lfps[i].My += W * fy; - lfps[i].Mxx += W * fx * fx; - lfps[i].Mxy += W * fx * fy; - lfps[i].Myy += W * fy * fy; - lfps[i].W += W; - } - } - } else { - // we now undo our fixed-point arithmetic. - double delta = 0.5; // adjust for pixel center bias - double x = p->x * .5 + delta; - double y = p->y * .5 + delta; - int ix = cvFloor(x), iy = cvFloor(y); - double W = 1; - - if (ix > 0 && ix+1 < im.cols && iy > 0 && iy+1 < im.rows) { - int grad_x = im.data[iy * im.cols + ix + 1] - - im.data[iy * im.cols + ix - 1]; - - int grad_y = im.data[(iy+1) * im.cols + ix] - - im.data[(iy-1) * im.cols + ix]; - - // XXX Tunable. How to shape the gradient magnitude? - W = sqrt(grad_x*grad_x + grad_y*grad_y) + 1; - } - - double fx = x, fy = y; - lfps[i].Mx += W * fx; - lfps[i].My += W * fy; - lfps[i].Mxx += W * fx * fx; - lfps[i].Mxy += W * fx * fy; - lfps[i].Myy += W * fy * fy; - lfps[i].W += W; - } - } - - int indices[4]; - if (1) { - if (!quad_segment_maxima(_params, _zarray_size(cluster), lfps, indices)) - goto finish; - } else { - if (!quad_segment_agg(sz, lfps, indices)) - goto finish; - } - - // printf("%d %d %d %d\n", indices[0], indices[1], indices[2], indices[3]); - - if (0) { - // no refitting here; just use those points as the vertices. - // Note, this is useful for debugging, but pretty bad in - // practice since this code path also omits several - // plausibility checks that save us tons of time in quad - // decoding. - for (int i = 0; i < 4; i++) { - struct pt *p; - _zarray_get_volatile(cluster, indices[i], &p); - - quad->p[i][0] = (float)(.5*p->x); // undo fixed-point arith. - quad->p[i][1] = (float)(.5*p->y); - } - - res = 1; - - } else { - double lines[4][4]; - - for (int i = 0; i < 4; i++) { - int i0 = indices[i]; - int i1 = indices[(i+1)&3]; - - if (0) { - // if there are enough points, skip the points near the corners - // (because those tend not to be very good.) - if (i1-i0 > 8) { - int t = (i1-i0)/6; - if (t < 0) - t = -t; - - i0 = (i0 + t) % sz; - i1 = (i1 + sz - t) % sz; - } - } - - double err; - fit_line(lfps, sz, i0, i1, lines[i], NULL, &err); - - if (err > _params->aprilTagMaxLineFitMse) { - res = 0; - goto finish; - } - } - - for (int i = 0; i < 4; i++) { - // solve for the intersection of lines (i) and (i+1)&3. - // p0 + lambda0*u0 = p1 + lambda1*u1, where u0 and u1 - // are the line directions. - // - // lambda0*u0 - lambda1*u1 = (p1 - p0) - // - // rearrange (solve for lambdas) - // - // [u0_x -u1_x ] [lambda0] = [ p1_x - p0_x ] - // [u0_y -u1_y ] [lambda1] [ p1_y - p0_y ] - // - // remember that lines[i][0,1] = p, lines[i][2,3] = NORMAL vector. - // We want the unit vector, so we need the perpendiculars. Thus, below - // we have swapped the x and y components and flipped the y components. - - const int i1 = (i + 1) & 3; - double A00 = lines[i][3], A01 = -lines[i1][3]; - double A10 = -lines[i][2], A11 = lines[i1][2]; - double B0 = -lines[i][0] + lines[i1][0]; - double B1 = -lines[i][1] + lines[i1][1]; - - double det = A00 * A11 - A10 * A01; - if (fabs(det) < 0.001) { - res = 0; - goto finish; - } - - // inverse. - double det_inv = 1.0 / det; - double W00 = A11 * det_inv, W01 = -A01 * det_inv; - - // solve - double L0 = W00*B0 + W01*B1; - - // compute intersection - quad->p[i][0] = (float)(lines[i][0] + L0*A00); - quad->p[i][1] = (float)(lines[i][1] + L0*A10); - -#if !defined(NDEBUG) - { - // we should get the same intersection starting - // from point p1 and moving L1*u1. - double W10 = -A10 * det_inv, W11 = A00 * det_inv; - double L1 = W10*B0 + W11*B1; - - double x = lines[i1][0] - L1*A01; - double y = lines[i1][1] - L1*A11; - - CV_Assert(fabs(x - quad->p[i][0]) < 0.001); - CV_Assert(fabs(y - quad->p[i][1]) < 0.001); - } -#endif // NDEBUG - - res = 1; - } - } - - // reject quads that are too small - if (1) { - double area = 0; - - // get area of triangle formed by points 0, 1, 2, 0 - double length[3], p; - for (int i = 0; i < 3; i++) { - int idxa = i; // 0, 1, 2, - int idxb = (i+1) % 3; // 1, 2, 0 - //length[i] = sqrt( - // sq(quad->p[idxb][0] - quad->p[idxa][0]) - // + sq(quad->p[idxb][1] - quad->p[idxa][1])); - double sq1 = quad->p[idxb][0] - quad->p[idxa][0]; - sq1 = sq1 * sq1; - double sq2 = quad->p[idxb][1] - quad->p[idxa][1]; - sq2 = sq2 * sq2; - length[i] = sqrt(sq1 + sq2); - } - p = (length[0] + length[1] + length[2]) / 2; - - area += sqrt(p*(p-length[0])*(p-length[1])*(p-length[2])); - - // get area of triangle formed by points 2, 3, 0, 2 - for (int i = 0; i < 3; i++) { - int idxs[] = { 2, 3, 0, 2 }; - int idxa = idxs[i]; - int idxb = idxs[i+1]; - //length[i] = sqrt( - // sq(quad->p[idxb][0] - quad->p[idxa][0]) - // + sq(quad->p[idxb][1] - quad->p[idxa][1])); - double sq1 = quad->p[idxb][0] - quad->p[idxa][0]; - sq1 = sq1 * sq1; - double sq2 = quad->p[idxb][1] - quad->p[idxa][1]; - sq2 = sq2 * sq2; - length[i] = sqrt(sq1 + sq2); - } - p = (length[0] + length[1] + length[2]) / 2; - - area += sqrt(p*(p-length[0])*(p-length[1])*(p-length[2])); - - // we don't actually know the family yet (quad detection is generic.) - // This threshold is based on a 6x6 tag (which is actually 8x8) - // int d = fam->d + fam->black_border*2; - int d = 8; - if (area < d*d) { - res = 0; - goto finish; - } - } - - // reject quads whose cumulative angle change isn't equal to 2PI - if(1){ - double total = 0; - - for (int i = 0; i < 4; i++) { - int i0 = i, i1 = (i+1)&3, i2 = (i+2)&3; - - double theta0 = atan2f(quad->p[i0][1] - quad->p[i1][1], - quad->p[i0][0] - quad->p[i1][0]); - double theta1 = atan2f(quad->p[i2][1] - quad->p[i1][1], - quad->p[i2][0] - quad->p[i1][0]); - - double dtheta = theta0 - theta1; - if (dtheta < 0) - dtheta += 2*CV_PI; - - if (dtheta < _params->aprilTagCriticalRad || dtheta > (CV_PI - _params->aprilTagCriticalRad)) - res = 0; - - total += dtheta; - } - - // looking for 2PI - if (total < 6.2 || total > 6.4) { - res = 0; - goto finish; - } - } - - finish: - - return res; -} - - -static void do_quad(int nCidx0, int nCidx1, zarray_t &nClusters, int nW, int nH, zarray_t *nquads, const Ptr &td, const Mat im){ - - CV_Assert(nquads != NULL); - - //struct quad_task *task = (struct quad_task*) p; - - //zarray_t *clusters = nClusters; - zarray_t *quads = nquads; - int w = nW, h = nH; - - for (int cidx = nCidx0; cidx < nCidx1; cidx++) { - - zarray_t *cluster; - _zarray_get(&nClusters, cidx, &cluster); - - if (_zarray_size(cluster) < td->aprilTagMinClusterPixels) - continue; - - // a cluster should contain only boundary points around the - // tag. it cannot be bigger than the whole screen. (Reject - // large connected blobs that will be prohibitively slow to - // fit quads to.) A typical point along an edge is added three - // times (because it has 3 neighbors). The maximum perimeter - // is 2w+2h. - if (_zarray_size(cluster) > 3*(2*w+2*h)) { - continue; - } - - struct sQuad quad; - memset(&quad, 0, sizeof(struct sQuad)); - - if (fit_quad(td, im, cluster, &quad)) { - //pthread_mutex_lock(&td.mutex); - _zarray_add(quads, &quad); - //pthread_mutex_unlock(&td.mutex); - } - } -} - -void threshold(const Mat mIm, const Ptr ¶meters, Mat& mThresh){ - int w = mIm.cols, h = mIm.rows; - int s = (unsigned) mIm.step; - CV_Assert(w < 32768); - CV_Assert(h < 32768); - - CV_Assert(mThresh.step == (unsigned)s); - - // The idea is to find the maximum and minimum values in a - // window around each pixel. If it's a contrast-free region - // (max-min is small), don't try to binarize. Otherwise, - // threshold according to (max+min)/2. - // - // Mark low-contrast regions with value 127 so that we can skip - // future work on these areas too. - - // however, computing max/min around every pixel is needlessly - // expensive. We compute max/min for tiles. To avoid artifacts - // that arise when high-contrast features appear near a tile - // edge (and thus moving from one tile to another results in a - // large change in max/min value), the max/min values used for - // any pixel are computed from all 3x3 surrounding tiles. Thus, - // the max/min sampling area for nearby pixels overlap by at least - // one tile. - // - // The important thing is that the windows be large enough to - // capture edge transitions; the tag does not need to fit into - // a tile. - - // XXX Tunable. Generally, small tile sizes--- so long as they're - // large enough to span a single tag edge--- seem to be a winner. - const int tilesz = 4; - - // the last (possibly partial) tiles along each row and column will - // just use the min/max value from the last full tile. - int tw = w / tilesz; - int th = h / tilesz; - - uint8_t *im_max = (uint8_t*)calloc(tw*th, sizeof(uint8_t)); - uint8_t *im_min = (uint8_t*)calloc(tw*th, sizeof(uint8_t)); - - - // first, collect min/max statistics for each tile - for (int ty = 0; ty < th; ty++) { - for (int tx = 0; tx < tw; tx++) { - uint8_t max = 0, min = 255; - - for (int dy = 0; dy < tilesz; dy++) { - - for (int dx = 0; dx < tilesz; dx++) { - - uint8_t v = mIm.data[(ty*tilesz+dy)*s + tx*tilesz + dx]; - if (v < min) - min = v; - if (v > max) - max = v; - } - } - im_max[ty*tw+tx] = max; - im_min[ty*tw+tx] = min; - } - } - - // second, apply 3x3 max/min convolution to "blur" these values - // over larger areas. This reduces artifacts due to abrupt changes - // in the threshold value. - uint8_t *im_max_tmp = (uint8_t*)calloc(tw*th, sizeof(uint8_t)); - uint8_t *im_min_tmp = (uint8_t*)calloc(tw*th, sizeof(uint8_t)); - - for (int ty = 0; ty < th; ty++) { - for (int tx = 0; tx < tw; tx++) { - uint8_t max = 0, min = 255; - - for (int dy = -1; dy <= 1; dy++) { - if (ty+dy < 0 || ty+dy >= th) - continue; - for (int dx = -1; dx <= 1; dx++) { - if (tx+dx < 0 || tx+dx >= tw) - continue; - - uint8_t m = im_max[(ty+dy)*tw+tx+dx]; - if (m > max) - max = m; - m = im_min[(ty+dy)*tw+tx+dx]; - if (m < min) - min = m; - } - } - - im_max_tmp[ty*tw + tx] = max; - im_min_tmp[ty*tw + tx] = min; - } - } - free(im_max); - free(im_min); - im_max = im_max_tmp; - im_min = im_min_tmp; - - for (int ty = 0; ty < th; ty++) { - for (int tx = 0; tx < tw; tx++) { - - int min_ = im_min[ty*tw + tx]; - int max_ = im_max[ty*tw + tx]; - - // low contrast region? (no edges) - if (max_ - min_ < parameters->aprilTagMinWhiteBlackDiff) { - for (int dy = 0; dy < tilesz; dy++) { - int y = ty*tilesz + dy; - - for (int dx = 0; dx < tilesz; dx++) { - int x = tx*tilesz + dx; - - //threshim->buf[y*s+x] = 127; - mThresh.data[y*s+x] = 127; - } - } - continue; - } - - // otherwise, actually threshold this tile. - - // argument for biasing towards dark; specular highlights - // can be substantially brighter than white tag parts - uint8_t thresh = saturate_cast((max_ + min_) / 2); - - for (int dy = 0; dy < tilesz; dy++) { - int y = ty*tilesz + dy; - - for (int dx = 0; dx < tilesz; dx++) { - int x = tx*tilesz + dx; - - uint8_t v = mIm.data[y*s+x]; - mThresh.data[y*s+x] = (v > thresh) ? 255 : 0; - } - } - } - } - - // we skipped over the non-full-sized tiles above. Fix those now. - for (int y = 0; y < h; y++) { - - // what is the first x coordinate we need to process in this row? - - int x0; - - if (y >= th*tilesz) { - x0 = 0; // we're at the bottom; do the whole row. - } else { - x0 = tw*tilesz; // we only need to do the right most part. - } - - // compute tile coordinates and clamp. - int ty = y / tilesz; - if (ty >= th) - ty = th - 1; - - for (int x = x0; x < w; x++) { - int tx = x / tilesz; - if (tx >= tw) - tx = tw - 1; - - int max = im_max[ty*tw + tx]; - int min = im_min[ty*tw + tx]; - int thresh = min + (max - min) / 2; - - uint8_t v = mIm.data[y*s+x]; - if (v > thresh){ - mThresh.data[y*s+x] = 255; - } - else{ - mThresh.data[y*s+x] = 0; - } - } - } - free(im_min); - free(im_max); - - // this is a dilate/erode deglitching scheme that does not improve - // anything as far as I can tell. - if (parameters->aprilTagDeglitch) { - Mat tmp(h,w, mIm.type()); - for (int y = 1; y + 1 < h; y++) { - for (int x = 1; x + 1 < w; x++) { - uint8_t max = 0; - for (int dy = -1; dy <= 1; dy++) { - for (int dx = -1; dx <= 1; dx++) { - uint8_t v = mThresh.data[(y+dy)*s + x + dx]; - if (v > max) - max = v; - } - } - tmp.data[y*s+x] = max; - } - } - - for (int y = 1; y + 1 < h; y++) { - for (int x = 1; x + 1 < w; x++) { - uint8_t min = 255; - for (int dy = -1; dy <= 1; dy++) { - for (int dx = -1; dx <= 1; dx++) { - uint8_t v = tmp.data[(y+dy)*s + x + dx]; - if (v < min) - min = v; - } - } - mThresh.data[y*s+x] = min; - } - } - } - -} - -#ifdef APRIL_DEBUG -static void _darken(const Mat &im){ - for (int y = 0; y < im.rows; y++) { - for (int x = 0; x < im.cols; x++) { - im.data[im.cols*y+x] /= 2; - } - } -} -#endif - -zarray_t *apriltag_quad_thresh(const Ptr ¶meters, const Mat & mImg, std::vector > &contours){ - - //////////////////////////////////////////////////////// - // step 1. threshold the image, creating the edge image. - - int w = mImg.cols, h = mImg.rows; - - Mat thold(h, w, mImg.type()); - threshold(mImg, parameters, thold); - - int ts = thold.cols; - -#ifdef APRIL_DEBUG - imwrite("2.2 debug_threshold.pnm", thold); -#endif - - //////////////////////////////////////////////////////// - // step 2. find connected components. - - unionfind_t *uf = unionfind_create(w * h); - - // TODO PARALLELIZE - for (int y = 0; y < h - 1; y++) { - do_unionfind_line(uf, thold, w, ts, y); - } - - // XXX sizing?? - int nclustermap = 2*w*h - 1; - - struct uint64_zarray_entry **clustermap = (struct uint64_zarray_entry**)calloc(nclustermap, sizeof(struct uint64_zarray_entry*)); - - for (int y = 1; y < h-1; y++) { - for (int x = 1; x < w-1; x++) { - - uint8_t v0 = thold.data[y*ts + x]; - if (v0 == 127) - continue; - - // XXX don't query this until we know we need it? - uint64_t rep0 = unionfind_get_representative(uf, y*w + x); - - // whenever we find two adjacent pixels such that one is - // white and the other black, we add the point half-way - // between them to a cluster associated with the unique - // ids of the white and black regions. - // - // We additionally compute the gradient direction (i.e., which - // direction was the white pixel?) Note: if (v1-v0) == 255, then - // (dx,dy) points towards the white pixel. if (v1-v0) == -255, then - // (dx,dy) points towards the black pixel. p.gx and p.gy will thus - // be -255, 0, or 255. - // - // Note that any given pixel might be added to multiple - // different clusters. But in the common case, a given - // pixel will be added multiple times to the same cluster, - // which increases the size of the cluster and thus the - // computational costs. - // - // A possible optimization would be to combine entries - // within the same cluster. - -#define DO_CONN(dx, dy) \ - if (1) { \ - uint8_t v1 = thold.data[y*ts + dy*ts + x + dx]; \ - \ - if (v0 + v1 == 255) { \ - uint64_t rep1 = unionfind_get_representative(uf, y*w + dy*w + x + dx); \ - uint64_t clusterid; \ - if (rep0 < rep1) \ - clusterid = (rep1 << 32) + rep0; \ - else \ - clusterid = (rep0 << 32) + rep1; \ - \ - /* XXX lousy hash function */ \ - uint32_t clustermap_bucket = u64hash_2(clusterid) % nclustermap; \ - struct uint64_zarray_entry *entry = clustermap[clustermap_bucket]; \ - while (entry && entry->id != clusterid) { \ - entry = entry->next; \ - } \ - \ - if (!entry) { \ - entry = (struct uint64_zarray_entry*)calloc(1, sizeof(struct uint64_zarray_entry)); \ - entry->id = clusterid; \ - entry->cluster = _zarray_create(sizeof(struct pt)); \ - entry->next = clustermap[clustermap_bucket]; \ - clustermap[clustermap_bucket] = entry; \ - } \ - \ - struct pt p; \ - p.x = saturate_cast(2*x + dx); \ - p.y = saturate_cast(2*y + dy); \ - p.gx = saturate_cast(dx*((int) v1-v0)); \ - p.gy = saturate_cast(dy*((int) v1-v0)); \ - _zarray_add(entry->cluster, &p); \ - } \ - } - - // do 4 connectivity. NB: Arguments must be [-1, 1] or we'll overflow .gx, .gy - DO_CONN(1, 0); - DO_CONN(0, 1); - - // do 8 connectivity - DO_CONN(-1, 1); - DO_CONN(1, 1); -} -} -#undef DO_CONN - -#ifdef APRIL_DEBUG -Mat out = Mat::zeros(h, w, CV_8UC3); - -uint32_t *colors = (uint32_t*) calloc(w*h, sizeof(*colors)); - -for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++) { - uint32_t v = unionfind_get_representative(uf, y*w+x); - - if (unionfind_get_set_size(uf, v) < parameters->aprilTagMinClusterPixels) - continue; - - uint32_t color = colors[v]; - uint8_t r = color >> 16, - g = color >> 8, - b = color; - - if (color == 0) { - const int bias = 50; - r = bias + (random() % (200-bias)); - g = bias + (random() % (200-bias)); - b = bias + (random() % (200-bias)); - colors[v] = (r << 16) | (g << 8) | b; - } - out.at(y, x)[0]=b; - out.at(y, x)[1]=g; - out.at(y, x)[2]=r; - } -} -free(colors); -imwrite("2.3 debug_segmentation.pnm", out); -out = Mat::zeros(h, w, CV_8UC3); -#endif - - //////////////////////////////////////////////////////// - // step 3. process each connected component. - zarray_t *clusters = _zarray_create(sizeof(zarray_t*)); //, uint64_zarray_hash_size(clustermap)); - CV_Assert(clusters != NULL); - - for (int i = 0; i < nclustermap; i++) { - for (struct uint64_zarray_entry *entry = clustermap[i]; entry; entry = entry->next) { - // XXX reject clusters here? - _zarray_add(clusters, &entry->cluster); - } - } - -#ifdef APRIL_DEBUG -for (int i = 0; i < _zarray_size(clusters); i++) { - zarray_t *cluster; - _zarray_get(clusters, i, &cluster); - - uint32_t r, g, b; - - const int bias = 50; - r = bias + (random() % (200-bias)); - g = bias + (random() % (200-bias)); - b = bias + (random() % (200-bias)); - - for (int j = 0; j < _zarray_size(cluster); j++) { - struct pt *p; - _zarray_get_volatile(cluster, j, &p); - - int x = p->x / 2; - int y = p->y / 2; - out.at(y, x)[0]=b; - out.at(y, x)[1]=g; - out.at(y, x)[2]=r; - } -} - -imwrite("2.4 debug_clusters.pnm", out); -out = Mat::zeros(h, w, CV_8UC3); -#endif - - for (int i = 0; i < _zarray_size(clusters); i++) { - zarray_t *cluster; - _zarray_get(clusters, i, &cluster); - - std::vector cnt; - for (int j = 0; j < _zarray_size(cluster); j++) { - struct pt *p; - _zarray_get_volatile(cluster, j, &p); - - Point pnt(p->x, p->y); - cnt.push_back(pnt); - } - contours.push_back(cnt); - } - - for (int i = 0; i < nclustermap; i++) { - struct uint64_zarray_entry *entry = clustermap[i]; - while (entry) { - struct uint64_zarray_entry *tmp = entry->next; - free(entry); - entry = tmp; - } - } - free(clustermap); - - zarray_t *quads = _zarray_create(sizeof(struct sQuad)); - - //int chunksize = 1 + sz / (APRILTAG_TASKS_PER_THREAD_TARGET * numberOfThreads); - int chunksize = std::max(1, h / (10 * getNumThreads())); - int sz = _zarray_size(clusters); - - // TODO PARALLELIZE - for (int i = 0; i < sz; i += chunksize) { - int min = sz < (i+chunksize)? sz: (i+chunksize); - do_quad(i, min, *clusters, w, h, quads, parameters, mImg); - } - -#ifdef APRIL_DEBUG -mImg.copyTo(out); -_darken(out); -_darken(out); -srandom(0); - -for (int i = 0; i < _zarray_size(quads); i++) { - struct sQuad *quad; - _zarray_get_volatile(quads, i, &quad); - - float rgb[3]; - int bias = 100; - - for (int i = 0; i < 3; i++) - rgb[i] = bias + (random() % (255-bias)); - - line(out, Point(quad->p[0][0], quad->p[0][1]), Point(quad->p[1][0], quad->p[1][1]), rgb[i]); - line(out, Point(quad->p[1][0], quad->p[1][1]), Point(quad->p[2][0], quad->p[2][1]), rgb[i]); - line(out, Point(quad->p[2][0], quad->p[2][1]), Point(quad->p[3][0], quad->p[3][1]), rgb[i]); - line(out, Point(quad->p[3][0], quad->p[3][1]), Point(quad->p[0][0], quad->p[0][1]), rgb[i]); -} -imwrite("2.5 debug_lines.pnm", out); -#endif - - unionfind_destroy(uf); - - for (int i = 0; i < _zarray_size(clusters); i++) { - zarray_t *cluster; - _zarray_get(clusters, i, &cluster); - _zarray_destroy(cluster); - } - _zarray_destroy(clusters); - return quads; -} - -void _apriltag(Mat im_orig, const Ptr & _params, std::vector > &candidates, - std::vector > &contours){ - - /////////////////////////////////////////////////////////// - /// Step 1. Detect quads according to requested image decimation - /// and blurring parameters. - Mat quad_im; - - if (_params->aprilTagQuadDecimate > 1){ - resize(im_orig, quad_im, Size(), 1/_params->aprilTagQuadDecimate, 1/_params->aprilTagQuadDecimate, INTER_AREA); - } - else { - im_orig.copyTo(quad_im); - } - - // Apply a Blur - if (_params->aprilTagQuadSigma != 0) { - // compute a reasonable kernel width by figuring that the - // kernel should go out 2 std devs. - // - // max sigma ksz - // 0.499 1 (disabled) - // 0.999 3 - // 1.499 5 - // 1.999 7 - - float sigma = fabsf((float) _params->aprilTagQuadSigma); - - int ksz = cvFloor(4 * sigma); // 2 std devs in each direction - ksz |= 1; // make odd number - - if (ksz > 1) { - if (_params->aprilTagQuadSigma > 0) - GaussianBlur(quad_im, quad_im, Size(ksz, ksz), sigma, sigma, BORDER_REPLICATE); - else { - Mat orig; - quad_im.copyTo(orig); - GaussianBlur(quad_im, quad_im, Size(ksz, ksz), sigma, sigma, BORDER_REPLICATE); - - // SHARPEN the image by subtracting the low frequency components. - for (int y = 0; y < orig.rows; y++) { - for (int x = 0; x < orig.cols; x++) { - int vorig = orig.data[y*orig.step + x]; - int vblur = quad_im.data[y*quad_im.step + x]; - - int v = 2*vorig - vblur; - if (v < 0) - v = 0; - if (v > 255) - v = 255; - - quad_im.data[y*quad_im.step + x] = (uint8_t) v; - } - } - } - } - } - -#ifdef APRIL_DEBUG - imwrite("1.1 debug_preprocess.pnm", quad_im); -#endif - - /////////////////////////////////////////////////////////// - /// Step 2. do the Threshold :: get the set of candidate quads - zarray_t *quads = apriltag_quad_thresh(_params, quad_im, contours); - - CV_Assert(quads != NULL); - - // adjust centers of pixels so that they correspond to the - // original full-resolution image. - if (_params->aprilTagQuadDecimate > 1) { - for (int i = 0; i < _zarray_size(quads); i++) { - struct sQuad *q; - _zarray_get_volatile(quads, i, &q); - for (int j = 0; j < 4; j++) { - q->p[j][0] *= _params->aprilTagQuadDecimate; - q->p[j][1] *= _params->aprilTagQuadDecimate; - } - } - } - -#ifdef APRIL_DEBUG - Mat im_quads = im_orig.clone(); - im_quads = im_quads*0.5; - srandom(0); - - for (int i = 0; i < _zarray_size(quads); i++) { - struct sQuad *quad; - _zarray_get_volatile(quads, i, &quad); - - const int bias = 100; - int color = bias + (random() % (255-bias)); - - line(im_quads, Point(quad->p[0][0], quad->p[0][1]), Point(quad->p[1][0], quad->p[1][1]), color, 1); - line(im_quads, Point(quad->p[1][0], quad->p[1][1]), Point(quad->p[2][0], quad->p[2][1]), color, 1); - line(im_quads, Point(quad->p[2][0], quad->p[2][1]), Point(quad->p[3][0], quad->p[3][1]), color, 1); - line(im_quads, Point(quad->p[3][0], quad->p[3][1]), Point(quad->p[0][0], quad->p[0][1]), color, 1); - } - imwrite("1.2 debug_quads_raw.pnm", im_quads); -#endif - - //////////////////////////////////////////////////////////////// - /// Step 3. Save the output :: candidate corners - for (int i = 0; i < _zarray_size(quads); i++) { - struct sQuad *quad; - _zarray_get_volatile(quads, i, &quad); - - std::vector corners; - corners.push_back(Point2f(quad->p[3][0], quad->p[3][1])); //pA - corners.push_back(Point2f(quad->p[0][0], quad->p[0][1])); //pB - corners.push_back(Point2f(quad->p[1][0], quad->p[1][1])); //pC - corners.push_back(Point2f(quad->p[2][0], quad->p[2][1])); //pD - - candidates.push_back(corners); - } - - _zarray_destroy(quads); -} - -}} diff --git a/modules/aruco/src/apriltag/apriltag_quad_thresh.hpp b/modules/aruco/src/apriltag/apriltag_quad_thresh.hpp deleted file mode 100644 index 2b8647ca15d..00000000000 --- a/modules/aruco/src/apriltag/apriltag_quad_thresh.hpp +++ /dev/null @@ -1,119 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. -// -// Copyright (C) 2013-2016, The Regents of The University of Michigan. -// -// This software was developed in the APRIL Robotics Lab under the -// direction of Edwin Olson, ebolson@umich.edu. This software may be -// available under alternative licensing terms; contact the address above. -// -// The views and conclusions contained in the software and documentation are those -// of the authors and should not be interpreted as representing official policies, -// either expressed or implied, of the Regents of The University of Michigan. - -// limitation: image size must be <32768 in width and height. This is -// because we use a fixed-point 16 bit integer representation with one -// fractional bit. - -#ifndef _OPENCV_APRIL_QUAD_THRESH_HPP_ -#define _OPENCV_APRIL_QUAD_THRESH_HPP_ - -#include -#include "opencv2/aruco_detector.hpp" -#include "unionfind.hpp" -#include "zmaxheap.hpp" -#include "zarray.hpp" - -namespace cv { -namespace aruco { - -static inline uint32_t u64hash_2(uint64_t x) { - return uint32_t((2654435761UL * x) >> 32); -} - -struct uint64_zarray_entry{ - uint64_t id; - zarray_t *cluster; - - struct uint64_zarray_entry *next; -}; - -struct pt{ - // Note: these represent 2*actual value. - uint16_t x, y; - float theta; - int16_t gx, gy; -}; - -struct remove_vertex{ - int i; // which vertex to remove? - int left, right; // left vertex, right vertex - - double err; -}; - -struct segment{ - int is_vertex; - - // always greater than zero, but right can be > size, which denotes - // a wrap around back to the beginning of the points. and left < right. - int left, right; -}; - -struct line_fit_pt{ - double Mx, My; - double Mxx, Myy, Mxy; - double W; // total weight -}; - -/** - * lfps contains *cumulative* moments for N points, with - * index j reflecting points [0,j] (inclusive). - * fit a line to the points [i0, i1] (inclusive). i0, i1 are both (0, sz) - * if i1 < i0, we treat this as a wrap around. - */ -void fit_line(struct line_fit_pt *lfps, int sz, int i0, int i1, double *lineparm, double *err, double *mse); - -int err_compare_descending(const void *_a, const void *_b); - -/** - 1. Identify A) white points near a black point and B) black points near a white point. - - 2. Find the connected components within each of the classes above, - yielding clusters of "white-near-black" and - "black-near-white". (These two classes are kept separate). Each - segment has a unique id. - - 3. For every pair of "white-near-black" and "black-near-white" - clusters, find the set of points that are in one and adjacent to the - other. In other words, a "boundary" layer between the two - clusters. (This is actually performed by iterating over the pixels, - rather than pairs of clusters.) Critically, this helps keep nearby - edges from becoming connected. - **/ -int quad_segment_maxima(const Ptr &td, int sz, struct line_fit_pt *lfps, int indices[4]); - -/** - * returns 0 if the cluster looks bad. - */ -int quad_segment_agg(int sz, struct line_fit_pt *lfps, int indices[4]); - -/** - * return 1 if the quad looks okay, 0 if it should be discarded - * quad - **/ -int fit_quad(const Ptr &_params, const Mat im, zarray_t *cluster, struct sQuad *quad); - - -void threshold(const Mat mIm, const Ptr ¶meters, Mat& mThresh); - - -zarray_t *apriltag_quad_thresh(const Ptr ¶meters, const Mat & mImg, - std::vector > &contours); - -void _apriltag(Mat im_orig, const Ptr & _params, std::vector > &candidates, - std::vector > &contours); - -}} -#endif diff --git a/modules/aruco/src/apriltag/predefined_dictionaries_apriltag.hpp b/modules/aruco/src/apriltag/predefined_dictionaries_apriltag.hpp deleted file mode 100644 index cad9802f538..00000000000 --- a/modules/aruco/src/apriltag/predefined_dictionaries_apriltag.hpp +++ /dev/null @@ -1,14900 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. - -namespace { - -/** - * Dictionaries are stored as a list of bytes in its four rotations. - * On each rotation, the marker is divided in bytes assuming a row-major order. - * This format allows a faster marker identification. - * For a dictionary composed by M markers of NxN bits, the structure dimensions should be: - * const char name[nMarkers][4rotations][nBytes], or more specifically: - * const char name[M][4][ceil(NxN/8)] - * The element [i][j][k] represents the k-th byte of the i-th marker in the dictionary - * in its j-th rotation. - * Each rotation implies a 90 degree rotation of the marker in anticlockwise direction. - */ -static unsigned char DICT_APRILTAG_16h5_BYTES[][4][2] = -{ - { {216, 196}, - {128, 190}, - {35, 27}, - {125, 1} - }, - { {165, 116}, - {106, 120}, - {46, 165}, - {30, 86} - }, - { {86, 44}, - {134, 209}, - {52, 106}, - {139, 97} - }, - { {157, 162}, - {195, 78}, - {69, 185}, - {114, 195} - }, - { {101, 158}, - {105, 211}, - {121, 166}, - {203, 150} - }, - { {214, 254}, - {167, 251}, - {127, 107}, - {223, 229} - }, - { {26, 205}, - {148, 55}, - {179, 88}, - {236, 41} - }, - { {162, 231}, - {31, 58}, - {231, 69}, - {92, 248} - }, - { {154, 127}, - {183, 61}, - {254, 89}, - {188, 237} - }, - { {182, 168}, - {142, 75}, - {21, 109}, - {210, 113} - }, - { {208, 28}, - {160, 153}, - {56, 11}, - {153, 5} - }, - { {213, 15}, - {209, 217}, - {240, 171}, - {155, 139} - }, - { {33, 176}, - {106, 2}, - {13, 132}, - {64, 86} - }, - { {108, 226}, - {11, 230}, - {71, 54}, - {103, 208} - }, - { {78, 49}, - {54, 196}, - {140, 114}, - {35, 108} - }, - { {8, 245}, - {50, 54}, - {175, 16}, - {108, 76} - }, - { {60, 144}, - {168, 70}, - {9, 60}, - {98, 21} - }, - { {45, 201}, - {88, 103}, - {147, 180}, - {230, 26} - }, - { {192, 165}, - {18, 154}, - {165, 3}, - {89, 72} - }, - { {241, 98}, - {203, 168}, - {70, 143}, - {21, 211} - }, - { {236, 135}, - {25, 222}, - {225, 55}, - {123, 152} - }, - { {169, 234}, - {75, 47}, - {87, 149}, - {244, 210} - }, - { {66, 251}, - {55, 163}, - {223, 66}, - {197, 236} - }, - { {184, 56}, - {170, 13}, - {28, 29}, - {176, 85} - }, - { {59, 151}, - {253, 22}, - {233, 220}, - {104, 191} - }, - { {181, 206}, - {201, 123}, - {115, 173}, - {222, 147} - }, - { {250, 181}, - {190, 158}, - {173, 95}, - {121, 125} - }, - { {12, 171}, - {19, 71}, - {213, 48}, - {226, 200} - }, - { {83, 224}, - {198, 162}, - {7, 202}, - {69, 99} - }, - { {116, 245}, - {186, 242}, - {175, 46}, - {79, 93} - } -}; - - - -static unsigned char DICT_APRILTAG_25h9_BYTES[][4][4] = -{ - { {143, 211, 170, 1}, - {234, 146, 237, 1}, - {170, 229, 248, 1}, - {219, 164, 171, 1} - }, - { {109, 139, 39, 1}, - {170, 251, 21, 0}, - {242, 104, 219, 0}, - {84, 111, 170, 1} - }, - { {22, 208, 222, 1}, - {94, 6, 244, 1}, - {189, 133, 180, 0}, - {151, 176, 61, 0} - }, - { {179, 147, 87, 1}, - {62, 118, 217, 0}, - {245, 100, 230, 1}, - {77, 183, 62, 0} - }, - { {115, 40, 116, 1}, - {28, 189, 146, 0}, - {151, 10, 103, 0}, - {36, 222, 156, 0} - }, - { {221, 18, 172, 0}, - {164, 145, 124, 1}, - {26, 164, 93, 1}, - {159, 68, 146, 1} - }, - { {103, 234, 238, 0}, - {98, 191, 182, 1}, - {59, 171, 243, 0}, - {182, 254, 163, 0} - }, - { {213, 186, 96, 1}, - {46, 157, 78, 0}, - {131, 46, 213, 1}, - {57, 92, 186, 0} - }, - { {231, 69, 93, 1}, - {89, 117, 157, 1}, - {221, 81, 115, 1}, - {220, 215, 77, 0} - }, - { {17, 101, 123, 0}, - {85, 214, 3, 1}, - {111, 83, 68, 0}, - {224, 53, 213, 0} - }, - { {228, 155, 129, 0}, - {34, 105, 109, 0}, - {64, 236, 147, 1}, - {91, 75, 34, 0} - }, - { {130, 77, 138, 0}, - {65, 10, 169, 1}, - {40, 217, 32, 1}, - {202, 168, 65, 0} - }, - { {117, 19, 219, 0}, - {52, 119, 101, 1}, - {109, 228, 87, 0}, - {211, 119, 22, 0} - }, - { {152, 112, 167, 1}, - {204, 194, 122, 0}, - {242, 135, 12, 1}, - {47, 33, 153, 1} - }, - { {75, 152, 26, 1}, - {154, 27, 192, 1}, - {172, 12, 233, 0}, - {129, 236, 44, 1} - }, - { {65, 65, 182, 1}, - {88, 147, 49, 0}, - {182, 193, 65, 0}, - {70, 100, 141, 0} - }, - { {172, 7, 198, 1}, - {169, 38, 61, 0}, - {177, 240, 26, 1}, - {94, 50, 74, 1} - }, - { {129, 217, 185, 0}, - {82, 216, 105, 1}, - {78, 205, 192, 1}, - {203, 13, 165, 0} - }, - { {35, 119, 206, 1}, - {105, 54, 243, 1}, - {185, 247, 98, 0}, - {231, 182, 75, 0} - }, - { {144, 92, 117, 0}, - {85, 204, 88, 0}, - {87, 29, 4, 1}, - {13, 25, 213, 0} - }, - { {138, 62, 250, 0}, - {177, 142, 234, 1}, - {47, 190, 40, 1}, - {171, 184, 198, 1} - }, - { {63, 236, 133, 1}, - {207, 120, 182, 0}, - {208, 155, 254, 0}, - {54, 143, 121, 1} - }, - { {70, 169, 59, 0}, - {18, 203, 135, 1}, - {110, 74, 177, 0}, - {240, 233, 164, 0} - }, - { {162, 116, 1, 1}, - {73, 96, 202, 0}, - {192, 23, 34, 1}, - {41, 131, 73, 0} - }, - { {52, 42, 195, 1}, - {44, 110, 38, 0}, - {225, 170, 22, 0}, - {50, 59, 26, 0} - }, - { {37, 240, 225, 0}, - {66, 244, 102, 0}, - {67, 135, 210, 0}, - {51, 23, 161, 0} - }, - { {144, 226, 137, 0}, - {102, 64, 42, 1}, - {72, 163, 132, 1}, - {170, 1, 51, 0} - }, - { {15, 33, 102, 1}, - {136, 150, 151, 0}, - {179, 66, 120, 0}, - {116, 180, 136, 1} - }, - { {165, 79, 19, 0}, - {113, 122, 13, 0}, - {100, 121, 82, 1}, - {88, 47, 71, 0} - }, - { {221, 124, 193, 0}, - {197, 93, 110, 0}, - {65, 159, 93, 1}, - {59, 93, 81, 1} - }, - { {254, 142, 154, 0}, - {183, 43, 172, 1}, - {44, 184, 191, 1}, - {154, 234, 118, 1} - }, - { {10, 11, 60, 1}, - {184, 136, 145, 1}, - {158, 104, 40, 0}, - {196, 136, 142, 1} - }, - { {139, 80, 95, 0}, - {208, 86, 216, 1}, - {125, 5, 104, 1}, - {141, 181, 5, 1} - }, - { {13, 198, 237, 1}, - {235, 212, 52, 1}, - {219, 177, 216, 0}, - {150, 21, 235, 1} - }, - { {115, 137, 157, 0}, - {22, 121, 177, 1}, - {92, 200, 231, 0}, - {198, 207, 52, 0} - } -}; - - - -static unsigned char DICT_APRILTAG_36h10_BYTES[][4][5] = -{ - { {225, 101, 73, 83, 8}, - {49, 6, 165, 238, 1}, - {28, 169, 42, 104, 7}, - {135, 122, 86, 8, 12} - }, - { {50, 53, 132, 160, 4}, - {65, 139, 98, 33, 2}, - {32, 82, 26, 196, 12}, - {72, 68, 109, 24, 2} - }, - { {107, 237, 252, 94, 4}, - {43, 167, 244, 249, 13}, - {39, 163, 251, 125, 6}, - {185, 242, 254, 93, 4} - }, - { {217, 189, 115, 45, 4}, - {123, 106, 82, 246, 12}, - {43, 76, 235, 217, 11}, - {54, 244, 165, 109, 14} - }, - { {87, 115, 222, 38, 12}, - {233, 207, 79, 209, 1}, - {54, 71, 188, 238, 10}, - {136, 191, 47, 57, 7} - }, - { {245, 43, 80, 249, 12}, - {161, 42, 235, 222, 10}, - {57, 240, 173, 74, 15}, - {87, 189, 117, 72, 5} - }, - { {46, 91, 153, 155, 12}, - {210, 166, 237, 21, 11}, - {61, 153, 157, 167, 4}, - {218, 139, 118, 84, 11} - }, - { {127, 167, 237, 114, 2}, - {179, 155, 190, 233, 5}, - {68, 235, 126, 95, 14}, - {169, 119, 221, 156, 13} - }, - { {72, 191, 207, 28, 10}, - {123, 243, 157, 160, 8}, - {83, 143, 63, 209, 2}, - {16, 91, 156, 253, 14} - }, - { {235, 64, 193, 206, 10}, - {58, 180, 33, 203, 3}, - {87, 56, 48, 45, 7}, - {205, 56, 66, 213, 12} - }, - { {215, 152, 253, 186, 6}, - {240, 185, 214, 211, 15}, - {101, 219, 241, 158, 11}, - {252, 182, 185, 208, 15} - }, - { {92, 212, 54, 176, 14}, - {194, 93, 211, 176, 6}, - {112, 214, 194, 179, 10}, - {96, 220, 187, 164, 3} - }, - { {114, 66, 21, 239, 14}, - {24, 61, 107, 157, 3}, - {127, 122, 132, 36, 14}, - {203, 157, 107, 193, 8} - }, - { {200, 18, 236, 76, 1}, - {110, 161, 12, 138, 4}, - {131, 35, 116, 129, 3}, - {37, 19, 8, 87, 6} - }, - { {27, 178, 99, 54, 1}, - {127, 72, 154, 65, 5}, - {134, 204, 100, 221, 8}, - {168, 37, 145, 47, 14} - }, - { {185, 202, 170, 229, 1}, - {14, 204, 62, 78, 14}, - {138, 117, 85, 57, 13}, - {119, 39, 195, 55, 0} - }, - { {55, 38, 64, 234, 9}, - {165, 40, 43, 105, 3}, - {149, 112, 38, 78, 12}, - {201, 109, 65, 74, 5} - }, - { {141, 86, 137, 137, 9}, - {214, 164, 13, 102, 2}, - {153, 25, 22, 171, 1}, - {70, 107, 2, 86, 11} - }, - { {220, 110, 245, 96, 5}, - {183, 141, 74, 186, 12}, - {160, 106, 247, 99, 11}, - {53, 213, 43, 30, 13} - }, - { {81, 225, 58, 109, 5}, - {13, 110, 86, 220, 4}, - {171, 101, 200, 120, 10}, - {35, 182, 167, 107, 0} - }, - { {40, 201, 94, 212, 13}, - {46, 71, 245, 24, 10}, - {178, 183, 169, 49, 4}, - {81, 138, 254, 39, 4} - }, - { {155, 25, 144, 102, 13}, - {78, 138, 67, 91, 9}, - {182, 96, 153, 141, 9}, - {157, 172, 37, 23, 2} - }, - { {198, 37, 228, 219, 13}, - {165, 163, 193, 175, 7}, - {189, 178, 122, 70, 3}, - {239, 88, 60, 90, 5} - }, - { {238, 221, 198, 163, 3}, - {230, 215, 50, 167, 11}, - {204, 86, 59, 183, 7}, - {222, 84, 206, 182, 7} - }, - { {168, 123, 189, 36, 7}, - {95, 151, 110, 18, 12}, - {226, 75, 221, 225, 5}, - {52, 135, 110, 159, 10} - }, - { {38, 247, 86, 43, 7}, - {229, 119, 122, 53, 1}, - {237, 70, 174, 246, 4}, - {138, 197, 238, 234, 7} - }, - { {119, 95, 17, 146, 15}, - {212, 30, 233, 241, 11}, - {244, 152, 143, 174, 14}, - {216, 249, 119, 130, 11} - }, - { {227, 232, 42, 118, 0}, - {9, 68, 182, 203, 13}, - {6, 229, 65, 124, 7}, - {189, 54, 210, 41, 0} - }, - { {219, 116, 9, 26, 8}, - {83, 44, 133, 227, 1}, - {21, 137, 2, 237, 11}, - {140, 122, 19, 76, 10} - }, - { {166, 92, 117, 179, 8}, - {240, 5, 163, 55, 15}, - {28, 218, 227, 166, 5}, - {254, 204, 90, 0, 15} - }, - { {247, 162, 51, 66, 4}, - {145, 72, 120, 219, 5}, - {36, 44, 196, 94, 15}, - {173, 177, 225, 40, 9} - }, - { {45, 210, 218, 190, 4}, - {234, 228, 254, 80, 3}, - {39, 213, 180, 187, 4}, - {192, 167, 242, 117, 7} - }, - { {158, 138, 87, 237, 4}, - {186, 105, 90, 31, 10}, - {43, 126, 165, 23, 9}, - {95, 133, 169, 101, 13} - }, - { {192, 186, 16, 180, 12}, - {73, 0, 219, 146, 10}, - {50, 208, 133, 208, 3}, - {84, 157, 176, 9, 2} - }, - { {19, 70, 233, 230, 12}, - {56, 140, 79, 105, 7}, - {54, 121, 118, 44, 8}, - {233, 111, 35, 17, 12} - }, - { {177, 22, 100, 69, 12}, - {104, 9, 105, 110, 4}, - {58, 34, 102, 136, 13}, - {39, 105, 105, 1, 6} - }, - { {74, 118, 173, 59, 12}, - {83, 165, 207, 165, 5}, - {61, 203, 86, 229, 2}, - {170, 95, 58, 92, 10} - }, - { {133, 254, 70, 49, 2}, - {225, 85, 154, 102, 8}, - {72, 198, 39, 250, 1}, - {22, 101, 154, 168, 7} - }, - { {173, 105, 121, 110, 10}, - {187, 54, 39, 90, 13}, - {87, 105, 233, 107, 5}, - {181, 174, 70, 205, 13} - }, - { {32, 21, 210, 100, 6}, - {104, 210, 98, 56, 0}, - {98, 100, 186, 128, 4}, - {1, 196, 100, 177, 6} - }, - { {147, 181, 91, 6, 6}, - {121, 90, 84, 115, 1}, - {102, 13, 170, 220, 9}, - {140, 226, 165, 169, 14} - }, - { {202, 157, 31, 171, 6}, - {82, 115, 86, 183, 11}, - {109, 95, 139, 149, 3}, - {222, 214, 172, 228, 10} - }, - { {187, 35, 104, 210, 14}, - {35, 26, 237, 75, 7}, - {116, 177, 108, 77, 13}, - {237, 43, 117, 140, 4} - }, - { {52, 107, 195, 95, 14}, - {185, 254, 233, 12, 9}, - {127, 172, 61, 98, 12}, - {147, 9, 119, 249, 13} - }, - { {160, 207, 113, 248, 9}, - {52, 38, 187, 58, 14}, - {145, 248, 239, 48, 5}, - {117, 205, 214, 66, 12} - }, - { {83, 31, 184, 90, 9}, - {68, 170, 141, 249, 13}, - {149, 161, 223, 140, 10}, - {185, 251, 21, 82, 2} - }, - { {241, 127, 53, 41, 9}, - {85, 47, 43, 246, 12}, - {153, 74, 207, 232, 15}, - {54, 253, 79, 74, 10} - }, - { {152, 80, 211, 144, 5}, - {118, 204, 192, 18, 2}, - {160, 156, 176, 161, 9}, - {68, 128, 51, 54, 14} - }, - { {123, 240, 90, 34, 5}, - {103, 76, 118, 209, 1}, - {164, 69, 160, 253, 14}, - {136, 182, 227, 46, 6} - }, - { {197, 168, 151, 126, 5}, - {157, 225, 210, 218, 9}, - {167, 238, 145, 90, 3}, - {149, 180, 184, 123, 9} - }, - { {22, 216, 30, 157, 5}, - {204, 109, 212, 21, 10}, - {171, 151, 129, 182, 8}, - {90, 130, 187, 99, 3} - }, - { {180, 132, 224, 47, 5}, - {172, 168, 114, 38, 5}, - {175, 64, 114, 18, 13}, - {166, 68, 225, 83, 5} - }, - { {237, 52, 164, 150, 13}, - {207, 129, 225, 226, 7}, - {182, 146, 82, 203, 7}, - {228, 120, 120, 31, 3} - }, - { {9, 146, 15, 177, 3}, - {86, 81, 158, 68, 2}, - {200, 223, 4, 153, 0}, - {66, 39, 152, 166, 10} - }, - { {251, 90, 185, 188, 11}, - {94, 188, 175, 211, 14}, - {211, 217, 213, 173, 15}, - {124, 191, 83, 215, 10} - }, - { {37, 6, 52, 30, 11}, - {140, 49, 169, 112, 5}, - {215, 130, 198, 10, 4}, - {160, 233, 88, 195, 1} - }, - { {224, 145, 168, 72, 15}, - {68, 178, 117, 138, 4}, - {241, 33, 88, 144, 7}, - {37, 26, 228, 210, 2} - }, - { {194, 115, 147, 11, 8}, - {81, 230, 9, 151, 1}, - {29, 12, 156, 228, 3}, - {142, 153, 6, 120, 10} - }, - { {16, 43, 26, 208, 4}, - {1, 74, 204, 24, 10}, - {32, 181, 141, 64, 8}, - {81, 131, 53, 40, 0} - }, - { {56, 215, 41, 175, 4}, - {90, 46, 126, 36, 7}, - {47, 89, 78, 177, 12}, - {226, 71, 231, 69, 10} - }, - { {214, 63, 130, 165, 12}, - {201, 202, 75, 167, 10}, - {58, 84, 31, 198, 11}, - {94, 93, 37, 57, 3} - }, - { {93, 176, 247, 42, 2}, - {243, 249, 18, 208, 5}, - {69, 78, 240, 219, 10}, - {160, 180, 137, 252, 15} - }, - { {115, 36, 212, 252, 10}, - {41, 185, 163, 249, 2}, - {83, 242, 178, 76, 14}, - {73, 252, 89, 217, 4} - }, - { {71, 220, 230, 148, 6}, - {232, 213, 208, 225, 14}, - {98, 150, 115, 190, 2}, - {120, 112, 186, 177, 7} - }, - { {221, 26, 76, 114, 14}, - {226, 25, 207, 202, 9}, - {116, 227, 37, 139, 11}, - {149, 63, 57, 132, 7} - }, - { {154, 222, 49, 181, 1}, - {94, 12, 154, 55, 14}, - {138, 216, 199, 181, 9}, - {126, 197, 147, 7, 10} - }, - { {76, 25, 234, 75, 9}, - {230, 226, 5, 140, 13}, - {157, 37, 121, 131, 2}, - {179, 26, 4, 118, 7} - }, - { {129, 149, 32, 65, 5}, - {68, 2, 80, 110, 4}, - {168, 32, 74, 152, 1}, - {39, 96, 164, 2, 2} - }, - { {208, 173, 68, 239, 5}, - {45, 43, 82, 174, 11}, - {175, 114, 43, 80, 11}, - {215, 84, 173, 75, 4} - }, - { {169, 3, 2, 54, 13}, - {14, 66, 235, 66, 1}, - {182, 196, 12, 9, 5}, - {132, 45, 116, 39, 0} - }, - { {90, 99, 243, 101, 13}, - {63, 206, 75, 157, 4}, - {186, 108, 252, 101, 10}, - {43, 157, 39, 63, 12} - }, - { {167, 56, 140, 168, 15}, - {197, 177, 103, 67, 10}, - {241, 83, 17, 206, 5}, - {92, 46, 104, 218, 3} - }, - { {193, 252, 209, 46, 0}, - {121, 164, 18, 242, 9}, - {7, 72, 179, 248, 3}, - {148, 244, 130, 89, 14} - }, - { {18, 162, 88, 245, 0}, - {41, 8, 158, 29, 2}, - {10, 241, 164, 84, 8}, - {75, 135, 145, 9, 4} - }, - { {176, 210, 149, 151, 0}, - {88, 141, 184, 22, 3}, - {14, 154, 148, 176, 13}, - {198, 129, 219, 17, 10} - }, - { {172, 158, 132, 125, 4}, - {202, 161, 250, 46, 8}, - {43, 226, 23, 147, 5}, - {23, 69, 248, 85, 3} - }, - { {112, 105, 55, 71, 12}, - {25, 79, 97, 156, 13}, - {62, 46, 201, 96, 14}, - {179, 152, 111, 41, 8} - }, - { {68, 181, 20, 179, 2}, - {193, 19, 146, 180, 3}, - {76, 210, 138, 210, 2}, - {194, 212, 156, 136, 3} - }, - { {231, 77, 237, 224, 10}, - {176, 151, 39, 235, 14}, - {80, 123, 123, 46, 7}, - {125, 126, 78, 144, 13} - }, - { {53, 29, 98, 66, 10}, - {224, 90, 33, 104, 13}, - {84, 36, 107, 138, 12}, - {177, 104, 69, 160, 7} - }, - { {142, 125, 171, 62, 10}, - {219, 246, 135, 35, 13}, - {87, 205, 91, 231, 1}, - {188, 78, 22, 253, 11} - }, - { {82, 219, 5, 133, 6}, - {88, 31, 88, 133, 10}, - {106, 26, 13, 180, 10}, - {90, 17, 175, 129, 10} - }, - { {240, 135, 244, 59, 6}, - {32, 187, 250, 182, 5}, - {109, 194, 254, 16, 15}, - {166, 213, 253, 208, 4} - }, - { {78, 144, 152, 110, 1}, - {206, 160, 22, 153, 1}, - {135, 97, 144, 151, 2}, - {137, 150, 128, 87, 3} - }, - { {210, 100, 39, 89, 9}, - {21, 109, 129, 175, 4}, - {153, 174, 66, 100, 11}, - {47, 88, 27, 106, 8} - }, - { {36, 194, 245, 253, 5}, - {188, 165, 250, 28, 6}, - {171, 250, 244, 50, 4}, - {99, 133, 250, 83, 13} - }, - { {50, 142, 228, 41, 3}, - {36, 185, 58, 37, 12}, - {201, 66, 119, 20, 12}, - {58, 69, 201, 210, 4} - }, - { {107, 62, 162, 144, 11}, - {71, 208, 169, 225, 14}, - {208, 148, 87, 205, 6}, - {120, 121, 80, 190, 2} - }, - { {217, 65, 43, 194, 11}, - {22, 94, 5, 202, 7}, - {212, 61, 72, 41, 11}, - {229, 58, 7, 166, 8} - }, - { {156, 165, 116, 197, 7}, - {175, 27, 80, 62, 6}, - {234, 50, 234, 83, 9}, - {103, 192, 173, 143, 5} - }, - { {17, 109, 219, 74, 15}, - {53, 254, 69, 120, 9}, - {245, 45, 187, 104, 8}, - {145, 234, 39, 250, 12} - }, - { {174, 87, 71, 134, 8}, - {250, 71, 41, 35, 3}, - {22, 30, 46, 167, 5}, - {204, 73, 78, 37, 15} - }, - { {114, 224, 117, 97, 4}, - {49, 13, 114, 157, 4}, - {40, 106, 224, 116, 14}, - {43, 148, 235, 8, 12} - }, - { {198, 150, 180, 86, 6}, - {200, 145, 216, 187, 5}, - {102, 162, 214, 150, 3}, - {173, 209, 184, 145, 3} - }, - { {168, 197, 195, 205, 1}, - {62, 230, 48, 46, 2}, - {139, 60, 58, 49, 5}, - {71, 64, 198, 119, 12} - }, - { {91, 21, 74, 119, 1}, - {110, 74, 134, 237, 1}, - {142, 229, 42, 141, 10}, - {139, 118, 21, 39, 6} - }, - { {205, 163, 184, 200, 5}, - {135, 162, 92, 218, 6}, - {161, 49, 220, 91, 3}, - {101, 179, 164, 94, 1} - }, - { {74, 204, 221, 214, 7}, - {62, 149, 212, 185, 11}, - {230, 187, 179, 53, 2}, - {217, 210, 186, 151, 12} - }, - { {102, 82, 239, 170, 15}, - {244, 245, 111, 129, 7}, - {245, 95, 116, 166, 6}, - {232, 31, 106, 242, 15} - }, - { {173, 218, 37, 160, 0}, - {210, 5, 58, 66, 14}, - {0, 90, 69, 187, 5}, - {116, 37, 202, 4, 11} - }, - { {252, 230, 67, 94, 0}, - {187, 108, 184, 170, 1}, - {7, 172, 38, 115, 15}, - {133, 81, 211, 109, 13} - }, - { {187, 145, 56, 91, 8}, - {66, 42, 181, 95, 5}, - {29, 161, 200, 157, 13}, - {175, 170, 213, 68, 2} - }, - { {52, 217, 147, 145, 4}, - {208, 206, 240, 20, 10}, - {40, 156, 153, 178, 12}, - {82, 128, 247, 48, 11} - }, - { {160, 29, 41, 117, 12}, - {88, 2, 231, 46, 12}, - {58, 233, 75, 128, 5}, - {55, 78, 116, 1, 10} - }, - { {197, 91, 119, 176, 10}, - {240, 87, 139, 210, 14}, - {80, 222, 237, 170, 3}, - {116, 189, 30, 160, 15} - }, - { {180, 103, 48, 193, 10}, - {129, 30, 41, 62, 6}, - {88, 48, 206, 98, 13}, - {103, 201, 71, 136, 1} - }, - { {79, 215, 217, 189, 10}, - {250, 182, 159, 245, 2}, - {91, 217, 190, 191, 2}, - {74, 255, 150, 213, 15} - }, - { {62, 239, 157, 76, 6}, - {155, 191, 124, 57, 8}, - {99, 43, 159, 119, 12}, - {25, 195, 239, 221, 9} - }, - { {211, 16, 230, 71, 6}, - {104, 217, 64, 207, 5}, - {110, 38, 112, 140, 11}, - {175, 48, 41, 177, 6} - }, - { {150, 212, 131, 130, 1}, - {212, 204, 16, 35, 3}, - {132, 28, 18, 182, 9}, - {204, 64, 131, 50, 11} - }, - { {190, 66, 191, 212, 9}, - {158, 205, 173, 27, 6}, - {146, 191, 212, 39, 13}, - {109, 139, 91, 55, 9} - }, - { {66, 18, 49, 102, 9}, - {92, 0, 11, 153, 5}, - {150, 104, 196, 132, 2}, - {169, 157, 0, 3, 10} - }, - { {51, 202, 85, 219, 9}, - {52, 45, 185, 93, 11}, - {157, 186, 165, 60, 12}, - {219, 169, 219, 66, 12} - }, - { {165, 14, 174, 0, 13}, - {132, 193, 109, 98, 12}, - {176, 7, 87, 10, 5}, - {52, 107, 104, 50, 1} - }, - { {86, 110, 32, 220, 13}, - {141, 44, 201, 169, 14}, - {179, 176, 71, 102, 10}, - {121, 89, 51, 75, 1} - }, - { {126, 177, 2, 164, 3}, - {207, 90, 50, 129, 2}, - {194, 84, 8, 215, 14}, - {72, 20, 197, 175, 3} - }, - { {175, 51, 166, 149, 7}, - {207, 211, 232, 71, 6}, - {234, 150, 92, 207, 5}, - {110, 33, 124, 191, 3} - }, - { {144, 39, 133, 201, 15}, - {21, 187, 73, 46, 2}, - {249, 58, 30, 64, 9}, - {71, 73, 45, 218, 8} - }, - { {26, 175, 114, 194, 0}, - {35, 74, 24, 57, 15}, - {4, 52, 239, 85, 8}, - {249, 193, 133, 44, 4} - }, - { {140, 72, 88, 22, 8}, - {170, 4, 133, 18, 9}, - {22, 129, 161, 35, 1}, - {148, 138, 18, 5, 5} - }, - { {221, 184, 28, 187, 8}, - {195, 41, 151, 214, 11}, - {29, 211, 129, 219, 11}, - {214, 190, 153, 76, 3} - }, - { {41, 92, 192, 64, 12}, - {98, 132, 97, 104, 8}, - {48, 32, 51, 169, 4}, - {17, 104, 98, 20, 6} - }, - { {204, 21, 5, 90, 14}, - {210, 51, 193, 170, 1}, - {117, 170, 10, 131, 3}, - {133, 88, 60, 196, 11} - }, - { {218, 107, 24, 244, 9}, - {15, 14, 143, 155, 10}, - {146, 241, 141, 101, 11}, - {93, 159, 23, 15, 0} - }, - { {167, 135, 108, 37, 9}, - {172, 3, 63, 103, 4}, - {154, 67, 110, 30, 5}, - {46, 111, 204, 3, 5} - }, - { {246, 183, 42, 152, 5}, - {197, 106, 252, 163, 6}, - {161, 149, 78, 214, 15}, - {108, 83, 245, 106, 3} - }, - { {176, 8, 245, 30, 13}, - {60, 169, 225, 18, 13}, - {183, 138, 241, 0, 13}, - {180, 136, 121, 83, 12} - }, - { {75, 168, 124, 205, 13}, - {47, 33, 85, 221, 14}, - {187, 51, 225, 93, 2}, - {123, 186, 168, 79, 4} - }, - { {132, 228, 215, 70, 3}, - {189, 213, 16, 58, 1}, - {198, 46, 178, 114, 1}, - {133, 192, 138, 187, 13} - }, - { {108, 145, 86, 98, 0}, - {226, 67, 50, 152, 1}, - {4, 102, 168, 147, 6}, - {129, 148, 204, 36, 7} - }, - { {161, 89, 232, 111, 0}, - {104, 166, 38, 78, 13}, - {15, 97, 121, 168, 5}, - {183, 38, 70, 81, 6} - }, - { {240, 101, 172, 214, 8}, - {9, 143, 165, 170, 7}, - {22, 179, 90, 96, 15}, - {229, 90, 95, 25, 0} - }, - { {151, 176, 34, 145, 10}, - {193, 88, 145, 71, 6}, - {88, 148, 64, 222, 9}, - {110, 40, 145, 168, 3} - }, - { {191, 36, 1, 206, 6}, - {155, 56, 96, 107, 3}, - {103, 56, 2, 79, 13}, - {205, 96, 97, 205, 9} - }, - { {164, 202, 31, 226, 1}, - {148, 69, 62, 26, 11}, - {132, 127, 133, 50, 5}, - {213, 135, 202, 34, 9} - }, - { {17, 222, 135, 135, 9}, - {92, 205, 25, 100, 11}, - {158, 30, 23, 184, 8}, - {210, 105, 139, 51, 10} - }, - { {57, 73, 184, 51, 5}, - {6, 142, 230, 84, 13}, - {172, 193, 217, 41, 12}, - {178, 166, 119, 22, 0} - }, - { {134, 25, 53, 96, 13}, - {212, 3, 67, 27, 12}, - {176, 106, 201, 134, 1}, - {61, 140, 44, 2, 11} - }, - { {200, 75, 66, 10, 11}, - {38, 118, 9, 130, 9}, - {213, 4, 45, 33, 3}, - {148, 25, 6, 230, 4} - }, - { {81, 136, 22, 43, 15}, - {4, 121, 83, 212, 9}, - {253, 70, 129, 24, 10}, - {146, 188, 169, 226, 0} - }, - { {198, 116, 204, 159, 0}, - {233, 165, 132, 167, 3}, - {15, 147, 50, 230, 3}, - {206, 82, 26, 89, 7} - }, - { {168, 22, 147, 66, 12}, - {82, 192, 105, 58, 1}, - {52, 44, 150, 129, 5}, - {133, 201, 96, 52, 10} - }, - { {91, 182, 26, 190, 12}, - {75, 104, 223, 241, 3}, - {55, 213, 134, 221, 10}, - {200, 255, 177, 109, 2} - }, - { {64, 57, 11, 138, 10}, - {81, 114, 5, 128, 11}, - {85, 29, 9, 192, 2}, - {208, 26, 4, 232, 10} - }, - { {49, 229, 119, 99, 10}, - {49, 95, 51, 124, 5}, - {92, 110, 234, 120, 12}, - {163, 236, 207, 168, 12} - }, - { {138, 181, 190, 128, 6}, - {67, 211, 84, 51, 6}, - {96, 23, 218, 213, 1}, - {108, 194, 172, 188, 2} - }, - { {232, 127, 242, 172, 9}, - {111, 230, 43, 178, 14}, - {147, 84, 255, 225, 7}, - {116, 221, 70, 127, 6} - }, - { {133, 144, 118, 85, 9}, - {236, 65, 145, 94, 4}, - {154, 166, 224, 154, 1}, - {39, 168, 152, 35, 7} - }, - { {173, 4, 85, 41, 5}, - {182, 33, 98, 118, 0}, - {169, 74, 162, 11, 5}, - {6, 228, 104, 70, 13} - }, - { {94, 100, 156, 243, 5}, - {135, 141, 198, 189, 3}, - {172, 243, 146, 103, 10}, - {203, 214, 59, 30, 1} - }, - { {113, 188, 174, 157, 13}, - {77, 233, 245, 228, 14}, - {187, 151, 83, 216, 14}, - {114, 122, 249, 123, 2} - }, - { {202, 194, 32, 47, 13}, - {14, 36, 91, 135, 5}, - {191, 64, 68, 53, 3}, - {174, 29, 162, 71, 0} - }, - { {237, 109, 12, 225, 0}, - {131, 7, 38, 238, 10}, - {8, 115, 11, 107, 7}, - {87, 118, 78, 12, 1} - }, - { {211, 179, 54, 142, 8}, - {73, 107, 25, 211, 7}, - {23, 22, 204, 220, 11}, - {236, 185, 141, 105, 2} - }, - { {88, 251, 152, 132, 4}, - {75, 142, 92, 144, 10}, - {34, 17, 157, 241, 10}, - {80, 147, 167, 29, 2} - }, - { {66, 176, 73, 175, 12}, - {121, 32, 87, 133, 3}, - {63, 89, 32, 212, 2}, - {202, 30, 160, 73, 14} - }, - { {165, 172, 222, 241, 10}, - {161, 209, 183, 126, 10}, - {88, 247, 179, 90, 5}, - {87, 238, 216, 184, 5} - }, - { {126, 74, 98, 45, 6}, - {170, 124, 106, 133, 12}, - {107, 68, 101, 39, 14}, - {58, 21, 99, 229, 5} - }, - { {93, 233, 95, 78, 9}, - {191, 111, 21, 216, 9}, - {151, 47, 169, 123, 10}, - {145, 186, 143, 111, 13} - }, - { {34, 197, 24, 23, 9}, - {12, 6, 181, 53, 1}, - {158, 129, 138, 52, 4}, - {138, 202, 214, 3, 0} - }, - { {115, 117, 108, 186, 5}, - {101, 47, 230, 225, 7}, - {165, 211, 106, 236, 14}, - {232, 118, 127, 74, 6} - }, - { {80, 47, 87, 216, 11}, - {53, 123, 137, 184, 10}, - {209, 190, 175, 64, 10}, - {81, 217, 29, 234, 12} - }, - { {154, 160, 25, 211, 11}, - {23, 24, 149, 31, 3}, - {220, 185, 128, 85, 9}, - {207, 138, 145, 142, 8} - }, - { {61, 180, 129, 166, 15}, - {223, 152, 115, 96, 3}, - {246, 88, 18, 219, 12}, - {192, 108, 225, 159, 11} - }, - { {39, 218, 159, 156, 8}, - {216, 229, 189, 81, 10}, - {19, 159, 149, 190, 4}, - {88, 171, 218, 113, 11} - }, - { {58, 103, 134, 237, 6}, - {11, 255, 106, 45, 2}, - {107, 118, 30, 101, 12}, - {75, 69, 111, 253, 0} - }, - { {132, 55, 15, 143, 6}, - {217, 115, 76, 38, 3}, - {111, 31, 14, 194, 1}, - {198, 67, 44, 233, 11} - }, - { {53, 66, 74, 6, 5}, - {172, 76, 108, 64, 1}, - {166, 5, 36, 42, 12}, - {128, 35, 99, 35, 5} - }, - { {131, 37, 139, 194, 7}, - {21, 210, 68, 107, 3}, - {228, 61, 26, 76, 1}, - {205, 98, 36, 186, 8} - }, - { {6, 72, 246, 57, 4}, - {160, 229, 194, 21, 12}, - {41, 198, 241, 38, 0}, - {58, 132, 58, 112, 5} - }, - { {46, 148, 213, 97, 12}, - {242, 129, 115, 61, 0}, - {56, 106, 178, 151, 4}, - {11, 204, 232, 20, 15} - }, - { {72, 50, 160, 103, 2}, - {75, 144, 10, 140, 5}, - {78, 96, 84, 193, 2}, - {163, 21, 0, 157, 2} - }, - { {228, 117, 33, 147, 1}, - {213, 6, 160, 166, 7}, - {140, 152, 74, 226, 7}, - {230, 80, 86, 10, 11} - }, - { {110, 253, 140, 158, 9}, - {207, 167, 181, 161, 11}, - {151, 147, 27, 247, 6}, - {216, 90, 222, 95, 3} - }, - { {0, 211, 242, 119, 9}, - {108, 198, 155, 28, 5}, - {158, 228, 252, 176, 0}, - {163, 141, 150, 51, 6} - }, - { {99, 216, 68, 68, 11}, - {108, 21, 49, 201, 8}, - {210, 34, 33, 188, 6}, - {25, 56, 202, 131, 6} - }, - { {249, 28, 183, 98, 7}, - {86, 217, 98, 250, 13}, - {228, 110, 211, 137, 15}, - {181, 244, 105, 182, 10} - }, - { {148, 34, 208, 61, 7}, - {173, 184, 202, 22, 0}, - {235, 192, 180, 66, 9}, - {6, 133, 49, 219, 5} - }, - { {187, 200, 20, 31, 6}, - {10, 61, 240, 87, 9}, - {111, 130, 129, 61, 13}, - {158, 160, 251, 197, 0} - }, - { {69, 152, 237, 76, 14}, - {248, 177, 85, 200, 12}, - {115, 43, 113, 154, 2}, - {49, 58, 168, 209, 15} - }, - { {83, 226, 244, 224, 9}, - {37, 141, 27, 217, 6}, - {144, 114, 244, 124, 10}, - {105, 189, 139, 26, 4} - }, - { {241, 178, 125, 130, 9}, - {117, 9, 61, 210, 7}, - {148, 27, 228, 216, 15}, - {228, 187, 201, 10, 14} - }, - { {42, 202, 178, 62, 9}, - {14, 228, 187, 17, 13}, - {151, 196, 213, 53, 4}, - {184, 141, 210, 119, 0} - }, - { {123, 122, 214, 143, 9}, - {111, 237, 41, 213, 11}, - {159, 22, 181, 237, 14}, - {218, 185, 75, 127, 6} - }, - { {130, 225, 42, 209, 13}, - {5, 70, 213, 15, 6}, - {184, 181, 72, 116, 1}, - {111, 10, 182, 42, 0} - }, - { {37, 245, 188, 164, 11}, - {205, 151, 55, 112, 6}, - {210, 83, 218, 250, 4}, - {96, 238, 206, 155, 3} - }, - { {150, 173, 51, 250, 11}, - {149, 122, 147, 59, 15}, - {213, 252, 203, 86, 9}, - {253, 204, 149, 234, 9} - }, - { {116, 221, 218, 89, 11}, - {228, 254, 181, 188, 8}, - {217, 165, 187, 178, 14}, - {19, 218, 215, 242, 7} - }, - { {190, 51, 16, 82, 7}, - {199, 26, 232, 27, 1}, - {228, 160, 140, 199, 13}, - {141, 129, 117, 142, 3} - }, - { {175, 106, 142, 227, 12}, - {131, 197, 111, 79, 11}, - {60, 119, 21, 111, 5}, - {223, 47, 106, 60, 1} - }, - { {80, 157, 15, 85, 14}, - {88, 91, 213, 172, 8}, - {122, 175, 11, 144, 10}, - {19, 90, 189, 161, 10} - }, - { {90, 168, 135, 202, 13}, - {23, 233, 81, 137, 11}, - {181, 62, 17, 85, 10}, - {217, 24, 169, 126, 8} - }, - { {248, 216, 14, 113, 13}, - {70, 77, 247, 142, 8}, - {184, 231, 1, 177, 15}, - {23, 30, 251, 38, 2} - }, - { {18, 41, 212, 58, 0}, - {33, 171, 130, 17, 9}, - {5, 194, 185, 68, 8}, - {152, 132, 29, 88, 4} - }, - { {58, 213, 230, 98, 8}, - {98, 207, 51, 41, 5}, - {20, 102, 122, 181, 12}, - {169, 76, 207, 52, 6} - }, - { {68, 63, 156, 94, 2}, - {201, 179, 140, 184, 9}, - {71, 163, 159, 194, 2}, - {145, 211, 28, 217, 3} - }, - { {53, 224, 26, 247, 2}, - {137, 92, 182, 92, 3}, - {78, 245, 128, 122, 12}, - {195, 166, 211, 169, 1} - }, - { {82, 84, 77, 114, 6}, - {112, 29, 198, 169, 1}, - {100, 235, 34, 164, 10}, - {137, 86, 59, 128, 14} - }, - { {8, 222, 33, 65, 9}, - {86, 4, 25, 44, 12}, - {152, 40, 71, 177, 0}, - {51, 73, 130, 6, 10} - }, - { {151, 233, 242, 229, 5}, - {173, 206, 82, 95, 14}, - {170, 116, 249, 126, 9}, - {127, 164, 167, 59, 5} - }, - { {117, 185, 123, 135, 5}, - {253, 74, 116, 212, 15}, - {174, 29, 233, 218, 14}, - {242, 178, 229, 43, 15} - }, - { {28, 149, 63, 106, 13}, - {214, 107, 87, 56, 5}, - {181, 111, 202, 147, 8}, - {161, 206, 173, 102, 11} - }, - { {72, 136, 208, 174, 15}, - {46, 176, 83, 144, 11}, - {247, 80, 177, 17, 2}, - {208, 156, 160, 215, 4} - }, - { {35, 82, 133, 125, 8}, - {88, 165, 171, 77, 0}, - {27, 234, 20, 172, 4}, - {11, 45, 90, 81, 10} - }, - { {145, 10, 12, 159, 8}, - {8, 41, 141, 70, 11}, - {31, 147, 5, 8, 9}, - {214, 43, 25, 65, 0} - }, - { {114, 106, 253, 204, 4}, - {57, 173, 108, 153, 14}, - {35, 59, 245, 100, 14}, - {121, 147, 107, 89, 12} - }, - { {70, 182, 223, 184, 12}, - {241, 225, 223, 177, 2}, - {49, 223, 182, 214, 2}, - {72, 223, 184, 120, 15} - }, - { {55, 30, 152, 201, 12}, - {192, 168, 109, 125, 10}, - {57, 49, 151, 142, 12}, - {91, 235, 97, 80, 3} - }, - { {242, 133, 64, 180, 10}, - {40, 26, 179, 163, 2}, - {82, 208, 42, 20, 15}, - {76, 92, 213, 129, 4} - }, - { {155, 53, 4, 69, 10}, - {75, 27, 1, 111, 0}, - {90, 34, 10, 205, 9}, - {15, 104, 13, 141, 2} - }, - { {138, 236, 145, 248, 13}, - {23, 164, 211, 59, 10}, - {177, 248, 147, 117, 1}, - {93, 204, 178, 94, 8} - }, - { {173, 85, 173, 77, 15}, - {222, 183, 101, 110, 4}, - {251, 43, 90, 171, 5}, - {39, 106, 110, 215, 11} - }, - { {42, 24, 202, 208, 2}, - {98, 208, 164, 9, 10}, - {64, 181, 49, 133, 4}, - {89, 2, 80, 180, 6} - }, - { {237, 2, 60, 165, 10}, - {138, 17, 47, 214, 6}, - {90, 83, 196, 11, 7}, - {102, 191, 72, 133, 1} - }, - { {190, 137, 112, 155, 1}, - {166, 42, 176, 23, 15}, - {141, 144, 233, 23, 13}, - {254, 128, 213, 70, 5} - }, - { {66, 233, 185, 200, 9}, - {21, 166, 21, 153, 14}, - {145, 57, 217, 116, 2}, - {121, 154, 134, 90, 8} - }, - { {224, 185, 52, 114, 9}, - {69, 3, 179, 154, 13}, - {148, 226, 201, 208, 7}, - {181, 156, 220, 10, 2} - }, - { {135, 32, 220, 54, 11}, - {173, 145, 135, 83, 1}, - {214, 195, 176, 78, 1}, - {140, 174, 24, 155, 5} - }, - { {93, 132, 96, 137, 7}, - {166, 56, 80, 228, 6}, - {233, 16, 98, 27, 10}, - {98, 112, 161, 198, 5} - }, - { {144, 204, 205, 2, 15}, - {52, 157, 85, 34, 9}, - {244, 11, 51, 48, 9}, - {148, 74, 171, 146, 12} - }, - { {140, 134, 212, 168, 8}, - {162, 161, 27, 50, 2}, - {17, 82, 182, 19, 1}, - {68, 205, 136, 84, 5} - }, - { {120, 169, 76, 36, 12}, - {43, 11, 119, 128, 8}, - {50, 67, 41, 81, 14}, - {16, 30, 237, 13, 4} - }, - { {182, 101, 251, 203, 12}, - {177, 238, 101, 63, 7}, - {61, 61, 250, 102, 13}, - {239, 202, 103, 120, 13} - }, - { {39, 167, 32, 26, 6}, - {129, 50, 248, 97, 5}, - {101, 128, 78, 94, 4}, - {168, 97, 244, 200, 1} - }, - { {193, 202, 69, 13, 5}, - {60, 37, 88, 198, 8}, - {171, 10, 37, 56, 3}, - {22, 49, 170, 67, 12} - }, - { {75, 38, 242, 6, 13}, - {47, 192, 73, 241, 5}, - {182, 4, 246, 77, 2}, - {168, 249, 32, 63, 4} - }, - { {146, 37, 46, 39, 11}, - {13, 91, 7, 39, 5}, - {222, 71, 74, 68, 9}, - {174, 78, 13, 171, 0} - }, - { {240, 175, 98, 24, 8}, - {33, 106, 185, 162, 12}, - {17, 132, 111, 80, 15}, - {52, 89, 213, 104, 4} - }, - { {50, 161, 124, 11, 6}, - {33, 59, 116, 21, 5}, - {109, 3, 232, 84, 12}, - {170, 130, 237, 200, 4} - }, - { {107, 9, 58, 162, 14}, - {2, 82, 103, 209, 15}, - {116, 85, 201, 13, 6}, - {248, 190, 100, 164, 0} - }, - { {134, 231, 189, 205, 5}, - {157, 167, 92, 63, 6}, - {171, 59, 222, 118, 1}, - {111, 195, 174, 91, 9} - }, - { {70, 76, 128, 181, 11}, - {140, 148, 131, 165, 10}, - {218, 208, 19, 38, 2}, - {90, 92, 18, 147, 1} - }, - { {110, 146, 188, 233, 7}, - {198, 177, 126, 157, 6}, - {233, 115, 212, 151, 6}, - {107, 151, 232, 214, 3} - }, - { {10, 141, 210, 173, 4}, - {42, 226, 82, 53, 10}, - {43, 84, 187, 21, 0}, - {90, 196, 164, 117, 4} - }, - { {133, 26, 254, 234, 9}, - {228, 225, 15, 90, 15}, - {149, 119, 245, 138, 1}, - {245, 175, 8, 114, 7} - }, - { {102, 122, 112, 73, 9}, - {229, 36, 41, 157, 12}, - {153, 32, 229, 230, 6}, - {59, 153, 66, 74, 7} - }, - { {113, 49, 97, 102, 13}, - {125, 10, 99, 200, 5}, - {182, 104, 104, 200, 14}, - {161, 60, 101, 11, 14} - }, - { {197, 119, 160, 82, 15}, - {197, 150, 201, 234, 5}, - {244, 160, 94, 234, 3}, - {165, 121, 54, 154, 3} - }, - { {224, 70, 76, 187, 12}, - {32, 37, 239, 166, 3}, - {61, 211, 38, 32, 7}, - {198, 95, 122, 64, 4} - }, - { {244, 9, 85, 141, 10}, - {184, 59, 33, 150, 10}, - {91, 26, 169, 2, 15}, - {86, 152, 77, 193, 13} - }, - { {34, 79, 148, 169, 9}, - {4, 167, 43, 53, 10}, - {153, 82, 159, 36, 4}, - {90, 205, 78, 82, 0} - }, - { {229, 88, 200, 244, 13}, - {236, 132, 231, 202, 10}, - {178, 241, 49, 170, 7}, - {85, 62, 114, 19, 7} - }, - { {243, 18, 209, 192, 11}, - {116, 152, 41, 219, 2}, - {208, 56, 180, 140, 15}, - {77, 185, 65, 146, 14} - }, - { {41, 114, 88, 124, 11}, - {111, 52, 175, 88, 0}, - {211, 225, 164, 233, 4}, - {1, 175, 82, 207, 6} - }, - { {65, 179, 38, 98, 4}, - {65, 67, 90, 200, 5}, - {36, 102, 76, 216, 2}, - {161, 53, 172, 40, 2} - }, - { {218, 87, 244, 214, 12}, - {106, 143, 201, 187, 7}, - {54, 178, 254, 165, 11}, - {237, 217, 63, 21, 6} - }, - { {186, 1, 109, 186, 9}, - {54, 43, 167, 3, 7}, - {149, 219, 104, 5, 13}, - {236, 14, 93, 70, 12} - }, - { {53, 137, 198, 176, 5}, - {164, 203, 242, 64, 10}, - {160, 214, 57, 26, 12}, - {80, 36, 253, 50, 5} - }, - { {223, 69, 8, 189, 5}, - {142, 46, 198, 231, 2}, - {171, 209, 10, 47, 11}, - {78, 118, 55, 71, 1} - }, - { {50, 82, 34, 250, 8}, - {64, 108, 171, 9, 7}, - {21, 244, 68, 164, 12}, - {233, 13, 83, 96, 2} - }, - { {87, 54, 121, 125, 4}, - {249, 40, 206, 253, 4}, - {43, 233, 230, 206, 10}, - {43, 247, 49, 73, 15} - }, - { {100, 77, 74, 190, 10}, - {168, 118, 167, 160, 11}, - {87, 213, 43, 34, 6}, - {208, 94, 86, 225, 5} - }, - { {13, 189, 14, 79, 10}, - {203, 115, 21, 108, 9}, - {95, 39, 11, 219, 0}, - {147, 106, 140, 237, 3} - }, - { {20, 18, 155, 246, 13}, - {220, 200, 207, 24, 3}, - {182, 253, 148, 130, 8}, - {193, 143, 49, 51, 11} - }, - { {160, 137, 141, 158, 1}, - {28, 163, 180, 2, 11}, - {135, 155, 25, 16, 5}, - {212, 2, 220, 83, 8} - }, - { {116, 80, 182, 226, 11}, - {196, 221, 35, 152, 7}, - {212, 118, 208, 162, 14}, - {225, 156, 75, 178, 3} - }, - { {224, 228, 28, 54, 7}, - {13, 21, 246, 178, 1}, - {230, 195, 130, 112, 7}, - {132, 214, 250, 139, 0} - }, - { {105, 149, 101, 253, 11}, - {126, 51, 179, 236, 6}, - {219, 250, 106, 153, 6}, - {99, 124, 220, 199, 14} - }, - { {103, 160, 233, 22, 8}, - {185, 128, 181, 193, 5}, - {22, 137, 112, 94, 6}, - {168, 58, 208, 25, 13} - }, - { {25, 252, 180, 77, 12}, - {75, 173, 81, 124, 12}, - {59, 34, 211, 249, 8}, - {51, 232, 171, 93, 2} - }, - { {240, 254, 74, 108, 6}, - {105, 124, 126, 170, 8}, - {99, 101, 39, 240, 15}, - {21, 87, 227, 233, 6} - }, - { {78, 229, 220, 11, 14}, - {163, 183, 85, 181, 1}, - {125, 3, 186, 119, 2}, - {138, 218, 174, 220, 5} - }, - { {178, 90, 177, 231, 7}, - {92, 156, 106, 31, 15}, - {238, 120, 213, 164, 13}, - {255, 133, 99, 147, 10} - }, - { {84, 197, 166, 143, 13}, - {140, 239, 81, 164, 7}, - {191, 22, 90, 50, 10}, - {226, 88, 175, 115, 1} - }, - { {247, 21, 47, 212, 3}, - {220, 91, 164, 235, 6}, - {194, 191, 74, 142, 15}, - {109, 114, 93, 163, 11} - }, - { {79, 145, 125, 232, 10}, - {242, 51, 23, 217, 6}, - {81, 123, 232, 159, 2}, - {105, 190, 140, 196, 15} - }, - { {9, 53, 24, 238, 6}, - {75, 50, 70, 120, 3}, - {103, 113, 138, 201, 0}, - {193, 230, 36, 205, 2} - }, - { {170, 77, 229, 141, 6}, - {58, 183, 96, 39, 14}, - {107, 26, 123, 37, 5}, - {126, 64, 110, 213, 12} - }, - { {251, 189, 163, 100, 14}, - {91, 218, 115, 235, 12}, - {114, 108, 91, 221, 15}, - {61, 124, 229, 189, 10} - }, - { {194, 140, 79, 157, 13}, - {60, 97, 213, 167, 10}, - {187, 159, 35, 20, 3}, - {94, 90, 184, 99, 12} - }, - { {221, 221, 90, 236, 8}, - {234, 110, 23, 250, 10}, - {19, 117, 171, 187, 11}, - {85, 254, 135, 101, 7} - }, - { {154, 123, 45, 105, 4}, - {83, 47, 78, 15, 12}, - {41, 107, 77, 229, 9}, - {63, 7, 47, 76, 10} - }, - { {218, 46, 220, 145, 1}, - {39, 137, 140, 183, 10}, - {136, 147, 183, 69, 11}, - {94, 211, 25, 30, 4} - }, - { {18, 21, 66, 25, 5}, - {100, 106, 192, 37, 0}, - {169, 132, 42, 132, 8}, - {10, 64, 53, 98, 6} - }, - { {58, 253, 126, 65, 13}, - {103, 79, 117, 61, 12}, - {184, 39, 235, 245, 12}, - {59, 202, 239, 46, 6} - }, - { {210, 145, 48, 33, 12}, - {64, 10, 83, 151, 4}, - {56, 64, 200, 148, 11}, - {46, 156, 165, 0, 2} - }, - { {136, 91, 123, 237, 6}, - {122, 118, 78, 30, 14}, - {107, 125, 237, 161, 1}, - {119, 135, 38, 229, 14} - }, - { {255, 26, 148, 3, 13}, - {198, 137, 105, 215, 9}, - {188, 2, 149, 143, 15}, - {158, 185, 105, 22, 3} - }, - { {138, 210, 5, 218, 10}, - {82, 53, 153, 11, 3}, - {85, 186, 4, 181, 1}, - {205, 9, 154, 196, 10} - }, - { {124, 254, 229, 86, 14}, - {251, 157, 249, 168, 13}, - {118, 170, 119, 243, 14}, - {177, 89, 251, 157, 15} - }, - { {15, 29, 188, 45, 9}, - {206, 163, 7, 117, 12}, - {155, 67, 219, 143, 0}, - {58, 238, 12, 87, 3} - }, - { {173, 125, 51, 119, 9}, - {223, 70, 163, 126, 13}, - {158, 236, 203, 235, 5}, - {183, 236, 86, 47, 11} - }, - { {94, 35, 218, 148, 5}, - {175, 202, 204, 145, 2}, - {162, 149, 188, 71, 10}, - {72, 147, 53, 63, 5} - }, - { {202, 135, 100, 114, 13}, - {38, 3, 219, 171, 5}, - {180, 226, 110, 21, 3}, - {173, 93, 188, 6, 4} - }, - { {42, 52, 86, 226, 7}, - {103, 81, 98, 57, 3}, - {228, 118, 162, 197, 4}, - {201, 196, 104, 174, 6} - }, - { {179, 128, 104, 125, 6}, - {40, 56, 246, 79, 4}, - {107, 225, 96, 28, 13}, - {47, 38, 241, 193, 4} - }, - { {73, 224, 165, 31, 6}, - {27, 181, 208, 196, 5}, - {111, 138, 80, 121, 2}, - {162, 48, 186, 221, 8} - }, - { {144, 226, 83, 62, 9}, - {61, 108, 155, 18, 1}, - {151, 204, 164, 112, 9}, - {132, 141, 147, 107, 12} - }, - { {221, 1, 6, 99, 13}, - {134, 75, 67, 206, 1}, - {188, 102, 8, 11, 11}, - {135, 60, 45, 38, 1} - }, - { {118, 160, 92, 144, 8}, - {161, 9, 181, 145, 2}, - {16, 147, 160, 86, 14}, - {72, 154, 217, 8, 5} - }, - { {14, 217, 3, 223, 6}, - {218, 118, 208, 13, 11}, - {111, 188, 9, 183, 0}, - {219, 0, 182, 229, 11} - }, - { {43, 112, 183, 113, 13}, - {87, 197, 227, 93, 4}, - {184, 238, 208, 237, 4}, - {43, 172, 122, 62, 10} - }, - { {78, 140, 226, 119, 3}, - {174, 208, 146, 173, 13}, - {206, 228, 115, 23, 2}, - {187, 84, 144, 183, 5} - }, - { {164, 109, 4, 140, 4}, - {137, 39, 96, 34, 10}, - {35, 18, 11, 98, 5}, - {84, 64, 110, 73, 1} - }, - { {174, 72, 136, 91, 10}, - {130, 180, 165, 15, 9}, - {93, 161, 17, 39, 5}, - {159, 10, 82, 212, 1} - }, - { {10, 163, 70, 143, 3}, - {47, 115, 24, 5, 3}, - {207, 22, 44, 85, 0}, - {202, 1, 140, 239, 4} - }, - { {106, 225, 111, 19, 7}, - {55, 87, 244, 133, 5}, - {236, 143, 104, 117, 6}, - {170, 18, 254, 174, 12} - }, - { {149, 35, 13, 186, 13}, - {149, 43, 207, 66, 3}, - {181, 219, 12, 74, 9}, - {196, 47, 61, 74, 9} - }, - { {228, 136, 181, 77, 4}, - {152, 161, 112, 158, 12}, - {43, 42, 209, 18, 7}, - {55, 144, 232, 81, 9} - }, - { {121, 10, 75, 108, 10}, - {58, 120, 47, 200, 8}, - {83, 109, 37, 9, 14}, - {17, 63, 65, 229, 12} - }, - { {64, 35, 127, 147, 9}, - {53, 67, 141, 148, 7}, - {156, 159, 236, 64, 2}, - {226, 155, 28, 42, 12} - }, - { {45, 191, 41, 200, 3}, - {215, 50, 60, 104, 14}, - {193, 57, 79, 219, 4}, - {113, 99, 196, 206, 11} - }, - { {202, 214, 76, 54, 0}, - {106, 5, 158, 163, 1}, - {6, 195, 38, 181, 3}, - {140, 87, 154, 5, 6} - }, - { {211, 175, 89, 151, 10}, - {57, 26, 157, 247, 11}, - {94, 153, 175, 92, 11}, - {222, 251, 149, 137, 12} - }, - { {157, 46, 167, 143, 5}, - {159, 233, 72, 102, 15}, - {175, 30, 87, 75, 9}, - {246, 97, 41, 127, 9} - }, - { {34, 211, 98, 6, 7}, - {108, 86, 120, 1, 5}, - {230, 4, 108, 180, 4}, - {168, 1, 230, 163, 6} - }, - { {204, 169, 43, 134, 6}, - {155, 82, 84, 130, 15}, - {102, 29, 73, 83, 3}, - {244, 18, 164, 173, 9} - }, - { {85, 43, 159, 167, 1}, - {157, 203, 14, 212, 11}, - {142, 95, 157, 74, 10}, - {210, 183, 13, 59, 9} - }, - { {203, 178, 173, 205, 11}, - {95, 177, 29, 207, 6}, - {219, 59, 84, 221, 3}, - {111, 59, 136, 223, 10} - }, - { {68, 250, 70, 198, 7}, - {237, 85, 88, 136, 11}, - {230, 54, 37, 242, 2}, - {209, 17, 170, 171, 7} - }, - { {231, 38, 143, 185, 7}, - {149, 241, 238, 231, 2}, - {233, 223, 22, 78, 7}, - {78, 119, 120, 250, 9} - }, - { {36, 175, 23, 170, 2}, - {145, 115, 58, 48, 11}, - {69, 94, 143, 82, 4}, - {208, 197, 204, 232, 9} - }, - { {67, 232, 194, 173, 10}, - {41, 244, 19, 197, 10}, - {91, 84, 49, 124, 2}, - {90, 60, 130, 249, 4} - }, - { {145, 205, 26, 71, 13}, - {12, 78, 85, 126, 9}, - {190, 37, 139, 56, 9}, - {151, 234, 167, 35, 0} - }, - { {104, 5, 2, 194, 10}, - {2, 82, 33, 168, 3}, - {84, 52, 10, 1, 6}, - {193, 88, 68, 164, 0} - }, - { {5, 213, 122, 29, 10}, - {232, 118, 149, 116, 4}, - {91, 133, 234, 186, 0}, - {34, 234, 150, 225, 7} - }, - { {88, 51, 178, 20, 8}, - {75, 202, 137, 144, 4}, - {18, 132, 220, 193, 10}, - {32, 153, 21, 61, 2} - }, - { {207, 23, 24, 178, 4}, - {194, 2, 206, 243, 3}, - {36, 209, 142, 143, 3}, - {204, 247, 52, 4, 3} - }, - { {86, 20, 124, 139, 2}, - {224, 57, 4, 181, 7}, - {77, 19, 226, 134, 10}, - {234, 210, 9, 192, 7} - }, - { {254, 81, 189, 45, 1}, - {222, 175, 38, 151, 4}, - {139, 75, 216, 167, 15}, - {46, 150, 79, 87, 11} - }, - { {48, 238, 165, 168, 4}, - {17, 173, 122, 32, 14}, - {33, 90, 87, 112, 12}, - {112, 69, 235, 88, 8} - }, - { {94, 27, 78, 166, 2}, - {234, 91, 14, 129, 11}, - {70, 87, 45, 135, 10}, - {216, 23, 13, 165, 7} - }, - { {37, 57, 142, 52, 3}, - {205, 211, 166, 64, 8}, - {194, 199, 25, 202, 4}, - {16, 38, 92, 187, 3} - }, - { {71, 238, 53, 187, 2}, - {145, 53, 154, 245, 15}, - {77, 218, 199, 126, 2}, - {250, 245, 154, 200, 9} - }, - { {105, 226, 147, 152, 11}, - {23, 244, 185, 208, 2}, - {209, 156, 148, 121, 6}, - {64, 185, 210, 254, 8} - }, - { {203, 235, 3, 139, 4}, - {19, 102, 88, 199, 11}, - {45, 28, 13, 125, 3}, - {222, 49, 166, 108, 8} - }, - { {151, 33, 193, 117, 9}, - {189, 138, 131, 79, 0}, - {154, 232, 56, 78, 9}, - {15, 44, 21, 27, 13} - }, - { {117, 81, 72, 151, 9}, - {236, 14, 165, 196, 3}, - {158, 145, 40, 170, 14}, - {194, 58, 87, 3, 7} - }, - { {87, 243, 99, 229, 3}, - {253, 94, 26, 205, 6}, - {202, 124, 108, 254, 10}, - {107, 53, 135, 171, 15} - }, - { {174, 100, 20, 104, 0}, - {131, 37, 34, 59, 0}, - {1, 98, 130, 103, 5}, - {13, 196, 74, 76, 1} - }, - { {126, 147, 161, 155, 5}, - {214, 170, 248, 133, 7}, - {173, 152, 92, 151, 14}, - {234, 17, 245, 86, 11} - }, - { {169, 131, 209, 245, 2}, - {58, 146, 186, 94, 2}, - {74, 248, 188, 25, 5}, - {71, 165, 212, 149, 12} - }, - { {100, 91, 1, 175, 9}, - {220, 38, 43, 132, 11}, - {159, 88, 13, 162, 6}, - {210, 29, 70, 67, 11} - }, - { {13, 167, 121, 86, 5}, - {191, 2, 220, 120, 5}, - {166, 169, 238, 91, 0}, - {161, 227, 180, 15, 13} - }, - { {114, 16, 159, 147, 13}, - {84, 201, 229, 149, 3}, - {188, 159, 144, 132, 14}, - {202, 154, 121, 50, 10} - }, - { {141, 12, 71, 198, 11}, - {190, 81, 1, 106, 11}, - {214, 62, 35, 11, 1}, - {213, 104, 8, 167, 13} - }, - { {109, 229, 76, 66, 3}, - {167, 23, 52, 232, 1}, - {196, 35, 42, 123, 6}, - {129, 114, 206, 142, 5} - }, - { {241, 35, 191, 102, 11}, - {29, 219, 47, 218, 5}, - {214, 111, 220, 72, 15}, - {165, 191, 77, 187, 8} - }, - { {180, 231, 234, 99, 7}, - {165, 222, 126, 46, 5}, - {236, 101, 126, 114, 13}, - {167, 71, 231, 186, 5} - }, - { {229, 224, 226, 108, 5}, - {173, 228, 114, 202, 4}, - {163, 100, 112, 122, 7}, - {37, 52, 226, 123, 5} - }, - { {90, 49, 4, 158, 15}, - {79, 59, 193, 129, 3}, - {247, 146, 8, 197, 10}, - {200, 24, 61, 207, 2} - }, - { {137, 248, 81, 23, 11}, - {127, 20, 145, 86, 9}, - {222, 136, 161, 249, 1}, - {150, 168, 146, 143, 14} - }, - { {111, 187, 159, 46, 10}, - {219, 243, 63, 209, 9}, - {87, 79, 157, 223, 6}, - {152, 191, 204, 253, 11} - }, - { {80, 175, 172, 250, 6}, - {1, 187, 222, 168, 15}, - {101, 243, 95, 80, 10}, - {241, 87, 189, 216, 0} - }, - { {181, 113, 7, 57, 6}, - {209, 127, 226, 70, 0}, - {105, 206, 8, 234, 13}, - {6, 36, 127, 232, 11} - }, - { {121, 119, 47, 9, 2}, - {83, 127, 44, 228, 4}, - {73, 15, 78, 233, 14}, - {34, 115, 79, 236, 10} - }, - { {177, 29, 65, 73, 3}, - {116, 58, 32, 110, 8}, - {201, 40, 43, 136, 13}, - {23, 96, 69, 194, 14} - }, - { {29, 227, 35, 74, 14}, - {147, 126, 89, 72, 5}, - {117, 44, 76, 123, 8}, - {161, 41, 167, 236, 9} - }, - { {179, 148, 34, 108, 13}, - {76, 104, 115, 107, 4}, - {179, 100, 66, 156, 13}, - {45, 108, 225, 99, 2} - }, - { {44, 126, 92, 173, 1}, - {239, 37, 46, 52, 10}, - {139, 83, 167, 227, 4}, - {82, 199, 74, 79, 7} - }, - { {95, 115, 48, 151, 13}, - {207, 14, 201, 213, 7}, - {190, 144, 204, 239, 10}, - {234, 185, 55, 15, 3} - }, - { {69, 251, 224, 160, 13}, - {229, 134, 91, 192, 14}, - {176, 80, 125, 250, 2}, - {112, 61, 166, 26, 7} - }, - { {9, 122, 74, 176, 0}, - {99, 68, 142, 64, 10}, - {0, 213, 37, 233, 0}, - {80, 39, 18, 44, 6} - }, - { {179, 119, 146, 163, 10}, - {65, 222, 43, 119, 3}, - {92, 84, 158, 236, 13}, - {206, 237, 71, 184, 2} - }, - { {98, 35, 175, 220, 7}, - {29, 243, 236, 137, 6}, - {227, 191, 92, 68, 6}, - {105, 19, 124, 251, 8} - }, - { {108, 155, 99, 108, 9}, - {254, 98, 59, 136, 12}, - {147, 108, 109, 147, 6}, - {49, 29, 196, 103, 15} - }, - { {155, 78, 142, 46, 9}, - {14, 237, 15, 99, 9}, - {151, 71, 23, 45, 9}, - {156, 111, 11, 119, 0} - }, - { {249, 195, 194, 21, 3}, - {46, 222, 184, 198, 0}, - {202, 132, 60, 57, 15}, - {6, 49, 215, 183, 4} - }, - { {119, 43, 15, 234, 11}, - {149, 123, 47, 201, 11}, - {213, 127, 13, 78, 14}, - {217, 63, 77, 234, 9} - }, - { {102, 250, 154, 171, 4}, - {193, 228, 126, 149, 11}, - {45, 85, 149, 246, 6}, - {218, 151, 226, 120, 3} - }, - { {116, 98, 77, 223, 13}, - {189, 45, 237, 140, 3}, - {191, 187, 36, 98, 14}, - {195, 27, 123, 75, 13} - }, - { {25, 222, 78, 102, 4}, - {106, 77, 94, 104, 9}, - {38, 103, 39, 185, 8}, - {145, 103, 171, 37, 6} - }, - { {148, 41, 230, 53, 14}, - {169, 219, 195, 6, 12}, - {122, 198, 121, 66, 9}, - {54, 12, 61, 185, 5} - }, - { {76, 236, 163, 246, 4}, - {155, 196, 210, 168, 15}, - {38, 252, 83, 115, 2}, - {241, 84, 178, 61, 9} - }, - { {164, 180, 6, 106, 6}, - {193, 113, 114, 42, 1}, - {101, 102, 2, 210, 5}, - {133, 68, 232, 232, 3} - }, - { {30, 86, 88, 215, 4}, - {234, 12, 204, 61, 3}, - {46, 177, 166, 167, 8}, - {203, 195, 51, 5, 7} - }, - { {219, 73, 192, 161, 2}, - {34, 158, 2, 199, 10}, - {72, 80, 57, 45, 11}, - {94, 52, 7, 148, 4} - }, - { {79, 81, 144, 218, 7}, - {198, 182, 192, 217, 3}, - {229, 176, 152, 175, 2}, - {201, 176, 54, 214, 3} - }, - { {1, 67, 44, 173, 5}, - {12, 39, 78, 68, 6}, - {171, 83, 76, 40, 0}, - {98, 39, 46, 67, 0} - }, - { {82, 252, 40, 115, 9}, - {69, 12, 151, 173, 13}, - {156, 225, 67, 244, 10}, - {187, 94, 147, 10, 2} - }, - { {67, 147, 62, 210, 15}, - {68, 83, 221, 217, 7}, - {244, 183, 204, 156, 2}, - {233, 187, 188, 162, 2} - }, - { {107, 7, 29, 172, 0}, - {26, 35, 46, 241, 2}, - {3, 91, 142, 13, 6}, - {72, 247, 76, 69, 8} - }, - { {81, 13, 171, 142, 1}, - {28, 234, 4, 224, 15}, - {135, 29, 91, 8, 10}, - {240, 114, 5, 115, 8} - }, - { {80, 201, 26, 157, 10}, - {8, 126, 149, 148, 10}, - {91, 149, 137, 48, 10}, - {82, 154, 151, 225, 0} - }, - { {95, 229, 148, 45, 0}, - {139, 175, 18, 245, 0}, - {11, 66, 154, 127, 10}, - {10, 244, 143, 93, 1} - }, - { {88, 194, 177, 178, 10}, - {18, 156, 155, 144, 7}, - {84, 216, 212, 49, 10}, - {224, 157, 147, 148, 8} - }, - { {137, 65, 77, 139, 14}, - {50, 55, 69, 70, 3}, - {125, 27, 40, 41, 1}, - {198, 42, 46, 196, 12} - }, - { {132, 10, 38, 120, 5}, - {132, 97, 202, 10, 12}, - {161, 230, 69, 2, 1}, - {53, 5, 56, 98, 1} - }, - { {185, 96, 91, 1, 13}, - {55, 76, 101, 86, 0}, - {184, 13, 160, 105, 13}, - {6, 170, 99, 46, 12} - }, - { {20, 186, 220, 247, 7}, - {237, 153, 222, 28, 11}, - {238, 243, 181, 210, 8}, - {211, 135, 185, 155, 7} - }, - { {246, 219, 203, 198, 4}, - {248, 206, 124, 139, 11}, - {38, 61, 61, 182, 15}, - {221, 19, 231, 49, 15} - }, - { {192, 171, 73, 169, 0}, - {49, 34, 30, 134, 10}, - {9, 89, 45, 80, 3}, - {86, 23, 132, 72, 12} - }, - { {153, 38, 27, 157, 2}, - {27, 120, 140, 118, 2}, - {75, 157, 134, 73, 9}, - {70, 227, 17, 237, 8} - }, - { {97, 25, 251, 19, 6}, - {112, 210, 228, 212, 13}, - {108, 141, 249, 136, 6}, - {178, 178, 116, 176, 14} - }, - { {136, 247, 2, 236, 5}, - {79, 102, 90, 42, 2}, - {163, 116, 14, 241, 1}, - {69, 69, 166, 111, 2} - }, - { {59, 109, 198, 146, 3}, - {39, 223, 160, 97, 11}, - {196, 150, 59, 109, 12}, - {216, 96, 95, 190, 4} - }, - { {78, 98, 149, 182, 0}, - {155, 133, 138, 145, 3}, - {6, 218, 148, 103, 2}, - {200, 149, 26, 29, 9} - }, - { {217, 253, 38, 220, 10}, - {75, 127, 145, 234, 14}, - {83, 182, 75, 249, 11}, - {117, 120, 159, 237, 2} - }, - { {185, 170, 215, 180, 13}, - {63, 201, 251, 82, 10}, - {178, 222, 181, 89, 13}, - {84, 173, 249, 63, 12} - }, - { {77, 237, 86, 136, 15}, - {167, 119, 81, 240, 10}, - {241, 22, 171, 123, 2}, - {80, 248, 174, 238, 5} - }, - { {32, 85, 135, 53, 1}, - {92, 199, 162, 36, 0}, - {138, 206, 26, 160, 4}, - {2, 68, 94, 51, 10} - }, - { {229, 194, 49, 87, 1}, - {156, 4, 184, 222, 5}, - {142, 168, 196, 58, 7}, - {167, 177, 210, 3, 9} - }, - { {203, 185, 136, 37, 6}, - {75, 146, 86, 199, 8}, - {106, 65, 25, 221, 3}, - {30, 54, 164, 157, 2} - }, - { {43, 23, 42, 185, 9}, - {70, 98, 175, 101, 6}, - {153, 213, 78, 141, 4}, - {106, 111, 84, 102, 2} - }, - { {171, 204, 25, 105, 3}, - {22, 52, 54, 127, 8}, - {201, 105, 131, 61, 5}, - {31, 230, 194, 198, 8} - }, - { {136, 158, 50, 170, 15}, - {70, 112, 91, 50, 15}, - {245, 84, 199, 145, 1}, - {244, 205, 160, 230, 2} - }, - { {13, 103, 151, 181, 12}, - {155, 199, 203, 116, 2}, - {58, 222, 158, 107, 0}, - {66, 237, 62, 61, 9} - }, - { {110, 236, 61, 135, 6}, - {155, 21, 116, 181, 15}, - {110, 27, 195, 119, 6}, - {250, 210, 234, 141, 9} - }, - { {163, 18, 150, 137, 14}, - {64, 241, 105, 87, 2}, - {121, 22, 148, 140, 5}, - {78, 169, 104, 240, 2} - }, - { {49, 39, 126, 125, 11}, - {45, 123, 175, 124, 4}, - {219, 231, 238, 72, 12}, - {35, 239, 93, 235, 4} - }, - { {197, 59, 33, 41, 14}, - {209, 50, 75, 198, 12}, - {121, 72, 77, 202, 3}, - {54, 61, 36, 200, 11} - }, - { {14, 92, 116, 153, 15}, - {230, 53, 193, 53, 14}, - {249, 146, 227, 167, 0}, - {122, 200, 58, 198, 7} - }, - { {206, 216, 31, 33, 1}, - {214, 69, 22, 151, 8}, - {136, 79, 129, 183, 3}, - {30, 150, 138, 38, 11} - }, - { {17, 190, 238, 22, 3}, - {109, 217, 156, 96, 13}, - {198, 135, 119, 216, 8}, - {176, 99, 153, 187, 6} - }, - { {91, 246, 119, 192, 6}, - {115, 93, 88, 249, 6}, - {96, 62, 230, 253, 10}, - {105, 241, 171, 172, 14} - }, - { {205, 49, 157, 20, 14}, - {219, 147, 197, 210, 0}, - {114, 139, 152, 203, 3}, - {4, 186, 60, 157, 11} - }, - { {33, 104, 14, 72, 13}, - {5, 101, 101, 72, 8}, - {177, 39, 1, 104, 4}, - {17, 42, 106, 106, 0} - }, - { {40, 39, 132, 250, 11}, - {7, 179, 171, 40, 3}, - {213, 242, 30, 65, 4}, - {193, 77, 92, 222, 0} - }, - { {168, 244, 166, 26, 0}, - {67, 229, 176, 34, 5}, - {5, 134, 82, 241, 5}, - {164, 64, 218, 124, 2} - }, - { {49, 118, 81, 59, 4}, - {113, 44, 234, 116, 1}, - {45, 200, 166, 232, 12}, - {130, 229, 115, 72, 14} - }, - { {247, 105, 206, 110, 2}, - {169, 255, 38, 203, 9}, - {71, 103, 57, 110, 15}, - {157, 54, 79, 249, 5} - }, - { {83, 146, 163, 177, 13}, - {84, 200, 219, 197, 6}, - {184, 220, 84, 156, 10}, - {106, 61, 177, 50, 10} - }, - { {88, 101, 173, 108, 15}, - {31, 191, 71, 168, 4}, - {243, 107, 90, 97, 10}, - {33, 94, 47, 223, 8} - }, - { {190, 115, 121, 11, 0}, - {243, 46, 44, 23, 5}, - {13, 9, 236, 231, 13}, - {174, 131, 71, 76, 15} - }, - { {90, 232, 238, 91, 11}, - {39, 253, 149, 141, 13}, - {221, 167, 113, 117, 10}, - {187, 26, 155, 254, 4} - }, - { {139, 106, 57, 122, 0}, - {19, 36, 142, 91, 13}, - {5, 233, 197, 109, 1}, - {189, 167, 18, 76, 8} - }, - { {163, 233, 94, 124, 14}, - {41, 119, 247, 91, 8}, - {115, 231, 169, 124, 5}, - {29, 174, 254, 233, 4} - }, - { {91, 159, 159, 132, 13}, - {94, 203, 93, 241, 10}, - {178, 31, 159, 157, 10}, - {88, 251, 173, 55, 10} - }, - { {47, 75, 147, 199, 11}, - {158, 214, 41, 93, 11}, - {222, 60, 157, 47, 4}, - {219, 169, 70, 183, 9} - }, - { {76, 117, 32, 169, 6}, - {195, 54, 66, 164, 6}, - {105, 80, 74, 227, 2}, - {98, 84, 38, 204, 3} - }, - { {98, 163, 2, 254, 14}, - {9, 114, 251, 137, 3}, - {119, 244, 12, 84, 6}, - {201, 29, 244, 233, 0} - }, - { {103, 190, 132, 139, 7}, - {197, 177, 120, 229, 11}, - {237, 18, 23, 222, 6}, - {218, 113, 232, 218, 3} - }, - { {183, 81, 31, 133, 12}, - {216, 79, 101, 87, 2}, - {58, 31, 136, 174, 13}, - {78, 170, 111, 33, 11} - }, - { {24, 89, 92, 70, 7}, - {110, 31, 68, 24, 9}, - {230, 35, 169, 161, 8}, - {145, 130, 47, 135, 6} - }, - { {21, 230, 55, 117, 0}, - {153, 77, 154, 124, 4}, - {10, 238, 198, 122, 8}, - {35, 229, 155, 41, 9} - }, - { {152, 85, 193, 87, 13}, - {126, 142, 193, 46, 1}, - {190, 168, 58, 161, 9}, - {135, 72, 55, 23, 14} - }, - { {221, 31, 87, 116, 9}, - {254, 75, 139, 250, 8}, - {146, 238, 175, 139, 11}, - {21, 253, 29, 39, 15} - }, - { {116, 139, 16, 186, 5}, - {132, 42, 250, 144, 11}, - {165, 208, 141, 18, 14}, - {208, 149, 245, 66, 1} - }, - { {28, 253, 149, 152, 1}, - {215, 175, 144, 48, 10}, - {129, 154, 155, 243, 8}, - {80, 192, 159, 94, 11} - }, - { {99, 111, 43, 206, 2}, - {25, 118, 44, 233, 15}, - {71, 61, 79, 108, 6}, - {249, 115, 70, 233, 8} - }, - { {175, 140, 36, 152, 13}, - {134, 33, 241, 99, 14}, - {177, 146, 67, 31, 5}, - {124, 104, 248, 70, 1} - }, - { {33, 45, 73, 54, 5}, - {61, 2, 230, 96, 9}, - {166, 201, 43, 72, 4}, - {144, 102, 116, 11, 12} - }, - { {173, 161, 22, 32, 14}, - {131, 83, 115, 82, 0}, - {112, 70, 136, 91, 5}, - {4, 172, 236, 172, 1} - }, - { {239, 49, 13, 89, 13}, - {215, 35, 229, 207, 0}, - {185, 171, 8, 207, 7}, - {15, 58, 124, 78, 11} - }, - { {155, 50, 155, 65, 14}, - {83, 216, 77, 95, 0}, - {120, 45, 148, 205, 9}, - {15, 171, 33, 188, 10} - }, - { {95, 76, 1, 168, 15}, - {150, 60, 67, 225, 10}, - {241, 88, 3, 47, 10}, - {88, 124, 35, 198, 9} - }, - { {110, 151, 175, 238, 0}, - {218, 227, 62, 169, 7}, - {7, 127, 94, 151, 6}, - {233, 87, 204, 117, 11} - }, - { {129, 68, 91, 180, 8}, - {56, 68, 135, 114, 2}, - {18, 221, 162, 40, 1}, - {68, 238, 18, 33, 12} - }, - { {196, 142, 130, 78, 7}, - {140, 240, 88, 170, 9}, - {231, 36, 23, 18, 3}, - {149, 81, 160, 243, 1} - }, - { {225, 39, 182, 160, 12}, - {1, 195, 107, 242, 6}, - {48, 86, 222, 72, 7}, - {100, 253, 108, 56, 0} - }, - { {88, 201, 151, 188, 7}, - {30, 255, 210, 144, 10}, - {227, 222, 153, 49, 10}, - {80, 148, 191, 247, 8} - }, - { {37, 121, 224, 205, 7}, - {237, 182, 96, 76, 14}, - {235, 48, 121, 234, 4}, - {115, 32, 102, 219, 7} - }, - { {107, 93, 4, 34, 7}, - {70, 23, 98, 225, 9}, - {228, 66, 11, 173, 6}, - {152, 116, 110, 134, 2} - }, - { {109, 39, 67, 156, 2}, - {187, 114, 168, 224, 2}, - {67, 156, 46, 75, 6}, - {64, 113, 84, 237, 13} - }, - { {168, 101, 37, 190, 2}, - {27, 55, 162, 34, 7}, - {71, 218, 74, 97, 5}, - {228, 68, 94, 205, 8} - }, - { {197, 187, 243, 235, 0}, - {241, 226, 26, 222, 15}, - {13, 124, 253, 218, 3}, - {247, 181, 132, 120, 15} - }, - { {224, 138, 63, 86, 10}, - {24, 81, 189, 154, 13}, - {86, 175, 197, 16, 7}, - {181, 155, 216, 161, 8} - }, - { {209, 250, 49, 233, 7}, - {85, 60, 90, 222, 14}, - {233, 120, 197, 248, 11}, - {119, 181, 163, 202, 10} - }, - { {102, 72, 123, 117, 10}, - {184, 84, 167, 157, 12}, - {90, 237, 225, 38, 6}, - {59, 158, 82, 161, 13} - }, - { {152, 233, 237, 143, 5}, - {63, 175, 84, 6, 15}, - {175, 27, 121, 113, 9}, - {246, 2, 175, 95, 12} - }, - { {156, 76, 216, 209, 15}, - {166, 156, 197, 62, 10}, - {248, 177, 179, 35, 9}, - {87, 202, 51, 150, 5} - }, - { {219, 162, 17, 122, 14}, - {19, 56, 219, 219, 1}, - {117, 232, 132, 93, 11}, - {141, 189, 177, 204, 8} - }, - { {252, 157, 45, 143, 13}, - {222, 43, 117, 166, 15}, - {191, 27, 75, 147, 15}, - {246, 90, 237, 71, 11} - }, - { {42, 216, 44, 171, 15}, - {70, 53, 119, 5, 15}, - {253, 83, 65, 181, 4}, - {250, 14, 234, 198, 2} - }, - { {203, 77, 206, 196, 5}, - {46, 199, 68, 235, 10}, - {162, 55, 59, 45, 3}, - {93, 114, 46, 55, 4} - }, - { {212, 230, 126, 105, 10}, - {161, 125, 31, 190, 4}, - {89, 103, 230, 114, 11}, - {39, 223, 139, 232, 5} - }, - { {182, 118, 99, 52, 5}, - {253, 76, 234, 35, 4}, - {162, 204, 102, 230, 13}, - {44, 69, 115, 43, 15} - }, - { {129, 161, 64, 232, 13}, - {37, 34, 83, 74, 2}, - {177, 112, 40, 88, 1}, - {69, 44, 164, 74, 4} - }, - { {36, 248, 181, 42, 13}, - {213, 165, 115, 16, 13}, - {181, 74, 209, 242, 4}, - {176, 140, 234, 90, 11} - }, - { {33, 212, 75, 137, 7}, - {116, 116, 116, 100, 2}, - {233, 29, 34, 184, 4}, - {66, 98, 226, 226, 14} - }, - { {143, 130, 58, 23, 11}, - {142, 80, 157, 87, 5}, - {222, 133, 196, 31, 1}, - {174, 171, 144, 167, 1} - }, - { {246, 113, 26, 188, 10}, - {201, 126, 167, 147, 2}, - {83, 213, 136, 230, 15}, - {76, 158, 87, 233, 3} - }, - { {63, 94, 2, 121, 7}, - {198, 124, 234, 109, 8}, - {233, 228, 7, 175, 12}, - {27, 101, 115, 230, 3} - }, - { {205, 212, 228, 99, 15}, - {230, 149, 83, 238, 5}, - {252, 98, 114, 187, 3}, - {167, 124, 170, 150, 7} - }, - { {89, 70, 5, 49, 5}, - {22, 13, 202, 228, 0}, - {168, 202, 6, 41, 10}, - {2, 117, 59, 6, 8} - }, - { {32, 186, 102, 97, 13}, - {101, 65, 123, 12, 12}, - {184, 102, 101, 208, 4}, - {51, 13, 232, 42, 6} - }, - { {151, 191, 26, 90, 0}, - {193, 106, 156, 123, 9}, - {5, 165, 143, 222, 9}, - {157, 227, 149, 104, 3} - }, - { {126, 66, 218, 161, 8}, - {162, 204, 47, 149, 2}, - {24, 85, 180, 39, 14}, - {74, 159, 67, 52, 5} - }, - { {98, 148, 45, 213, 5}, - {92, 1, 244, 173, 6}, - {170, 187, 66, 148, 6}, - {107, 82, 248, 3, 10} - }, - { {177, 229, 50, 4, 7}, - {13, 94, 112, 114, 4}, - {226, 4, 202, 120, 13}, - {36, 224, 231, 171, 0} - }, - { {222, 100, 233, 20, 12}, - {187, 140, 197, 163, 4}, - {50, 137, 114, 103, 11}, - {44, 90, 51, 29, 13} - }, - { {71, 94, 177, 229, 0}, - {216, 132, 10, 253, 14}, - {10, 120, 215, 174, 2}, - {123, 245, 2, 17, 11} - }, - { {25, 165, 108, 166, 9}, - {47, 11, 23, 96, 7}, - {150, 83, 106, 89, 8}, - {224, 110, 141, 15, 4} - }, - { {149, 5, 117, 79, 13}, - {188, 43, 65, 126, 5}, - {191, 42, 234, 10, 9}, - {167, 232, 45, 67, 13} - }, - { {54, 171, 61, 147, 0}, - {145, 11, 188, 21, 15}, - {12, 155, 205, 86, 12}, - {250, 131, 221, 8, 9} - }, - { {87, 132, 157, 120, 1}, - {148, 169, 150, 249, 0}, - {129, 235, 146, 30, 10}, - {9, 246, 153, 82, 9} - }, - { {164, 135, 244, 206, 4}, - {168, 163, 120, 58, 7}, - {39, 50, 254, 18, 5}, - {229, 193, 236, 81, 5} - }, - { {177, 1, 150, 215, 4}, - {8, 203, 224, 94, 3}, - {46, 182, 152, 8, 13}, - {199, 160, 125, 49, 0} - }, - { {202, 139, 220, 248, 6}, - {34, 179, 222, 155, 10}, - {97, 243, 189, 21, 3}, - {93, 151, 188, 212, 4} - }, - { {241, 104, 15, 187, 1}, - {21, 109, 166, 198, 11}, - {141, 223, 1, 104, 15}, - {214, 54, 91, 106, 8} - }, - { {119, 235, 139, 132, 9}, - {157, 206, 61, 193, 10}, - {146, 29, 29, 126, 14}, - {88, 59, 199, 59, 9} - }, - { {2, 83, 18, 189, 4}, - {72, 102, 202, 21, 2}, - {43, 212, 140, 164, 0}, - {74, 133, 54, 97, 2} - }, - { {29, 42, 141, 92, 1}, - {159, 169, 140, 72, 8}, - {131, 171, 21, 75, 8}, - {17, 35, 25, 95, 9} - }, - { {39, 117, 108, 47, 10}, - {233, 55, 39, 101, 5}, - {95, 67, 106, 238, 4}, - {170, 110, 78, 201, 7} - }, - { {61, 80, 83, 188, 9}, - {254, 108, 163, 80, 2}, - {147, 220, 160, 171, 12}, - {64, 172, 83, 103, 15} - }, - { {120, 181, 174, 182, 4}, - {75, 203, 246, 160, 7}, - {38, 215, 90, 209, 14}, - {224, 86, 253, 61, 2} - }, - { {42, 93, 133, 78, 1}, - {94, 167, 32, 41, 9}, - {135, 42, 27, 165, 4}, - {153, 64, 78, 87, 10} - }, - { {0, 239, 149, 206, 12}, - {25, 167, 89, 56, 11}, - {55, 58, 159, 112, 0}, - {209, 201, 174, 89, 8} - }, - { {198, 248, 201, 176, 10}, - {241, 148, 151, 131, 10}, - {80, 217, 49, 246, 3}, - {92, 30, 146, 152, 15} - }, - { {52, 138, 244, 180, 8}, - {168, 137, 187, 16, 14}, - {18, 210, 245, 18, 12}, - {112, 141, 217, 17, 5} - }, - { {154, 221, 191, 118, 3}, - {94, 223, 150, 59, 13}, - {198, 239, 219, 181, 9}, - {189, 198, 159, 183, 10} - }, - { {68, 183, 153, 113, 1}, - {213, 130, 158, 188, 0}, - {136, 233, 158, 210, 2}, - {3, 215, 148, 26, 11} - }, - { {53, 31, 237, 192, 9}, - {244, 139, 45, 104, 14}, - {144, 59, 127, 138, 12}, - {113, 107, 77, 18, 15} - }, - { {240, 132, 133, 185, 5}, - {20, 169, 242, 166, 2}, - {169, 218, 18, 16, 15}, - {70, 84, 249, 82, 8} - }, - { {130, 188, 93, 116, 5}, - {125, 1, 214, 59, 8}, - {162, 235, 163, 212, 1}, - {29, 198, 184, 11, 14} - }, - { {58, 134, 179, 151, 15}, - {30, 216, 249, 53, 7}, - {254, 156, 214, 21, 12}, - {234, 201, 241, 183, 8} - }, - { {140, 232, 137, 29, 15}, - {159, 180, 213, 6, 8}, - {251, 137, 17, 115, 1}, - {22, 10, 178, 223, 9} - }, - { {63, 123, 205, 83, 8}, - {243, 143, 173, 77, 9}, - {28, 171, 61, 239, 12}, - {155, 43, 95, 28, 15} - }, - { {180, 13, 145, 70, 7}, - {156, 154, 96, 58, 9}, - {230, 40, 155, 2, 13}, - {149, 192, 101, 147, 9} - }, - { {109, 172, 86, 182, 6}, - {171, 81, 242, 240, 11}, - {102, 214, 163, 91, 6}, - {208, 244, 248, 173, 5} - }, - { {88, 149, 105, 0, 13}, - {118, 10, 85, 160, 4}, - {176, 9, 106, 145, 10}, - {32, 90, 165, 6, 14} - }, - { {76, 163, 63, 89, 3}, - {151, 115, 156, 156, 4}, - {201, 175, 204, 83, 2}, - {35, 147, 156, 238, 9} - }, - { {53, 167, 215, 80, 1}, - {181, 203, 184, 120, 0}, - {128, 174, 190, 90, 12}, - {1, 225, 221, 58, 13} - }, - { {22, 233, 116, 244, 11}, - {173, 31, 147, 25, 14}, - {210, 242, 233, 118, 8}, - {121, 140, 159, 139, 5} - }, - { {106, 219, 126, 99, 3}, - {102, 87, 62, 157, 13}, - {204, 103, 237, 181, 6}, - {187, 151, 206, 166, 6} - }, - { {172, 254, 199, 138, 5}, - {247, 229, 120, 34, 11}, - {165, 30, 55, 243, 5}, - {212, 65, 234, 126, 15} - }, - { {195, 109, 112, 53, 6}, - {41, 22, 194, 247, 12}, - {106, 192, 235, 108, 3}, - {62, 244, 54, 137, 4} - }, - { {133, 82, 84, 245, 6}, - {232, 21, 202, 94, 2}, - {106, 242, 164, 170, 1}, - {71, 165, 58, 129, 7} - }, - { {211, 112, 148, 110, 7}, - {77, 189, 66, 219, 1}, - {231, 98, 144, 236, 11}, - {141, 180, 43, 219, 2} - }, - { {157, 177, 206, 126, 12}, - {235, 235, 215, 74, 1}, - {55, 231, 56, 219, 9}, - {133, 46, 189, 125, 7} - }, - { {163, 136, 217, 180, 14}, - {56, 144, 247, 83, 10}, - {114, 217, 177, 28, 5}, - {92, 174, 240, 145, 12} - }, - { {98, 252, 134, 118, 14}, - {73, 213, 243, 169, 9}, - {118, 230, 19, 244, 6}, - {153, 92, 250, 185, 2} - }, - { {209, 228, 206, 15, 2}, - {41, 253, 20, 230, 1}, - {79, 7, 50, 120, 11}, - {134, 114, 139, 249, 4} - }, - { {224, 197, 119, 135, 0}, - {56, 71, 48, 182, 7}, - {14, 30, 234, 48, 7}, - {230, 208, 206, 33, 12} - }, - { {136, 137, 241, 121, 7}, - {54, 178, 210, 30, 12}, - {233, 232, 249, 17, 1}, - {55, 132, 180, 214, 12} - }, - { {175, 103, 124, 158, 0}, - {171, 39, 172, 115, 7}, - {7, 147, 238, 111, 5}, - {236, 227, 94, 77, 5} - }, - { {250, 135, 32, 206, 8}, - {10, 42, 57, 171, 7}, - {23, 48, 78, 21, 15}, - {237, 89, 197, 69, 0} - }, - { {32, 136, 108, 197, 14}, - {40, 17, 117, 12, 14}, - {122, 51, 97, 16, 4}, - {115, 10, 232, 129, 4} - }, - { {26, 153, 204, 140, 14}, - {106, 187, 85, 1, 10}, - {115, 19, 57, 149, 8}, - {88, 10, 173, 213, 6} - }, - { {136, 165, 101, 91, 1}, - {55, 35, 144, 46, 5}, - {141, 170, 106, 81, 1}, - {167, 64, 156, 78, 12} - }, - { {214, 247, 236, 2, 5}, - {229, 143, 92, 163, 5}, - {164, 3, 126, 246, 11}, - {172, 83, 175, 26, 7} - }, - { {244, 246, 145, 8, 4}, - {209, 172, 120, 178, 0}, - {33, 8, 150, 242, 15}, - {4, 209, 227, 88, 11} - }, - { {76, 10, 202, 63, 5}, - {174, 224, 206, 132, 9}, - {175, 197, 53, 3, 2}, - {146, 23, 48, 119, 5} - }, - { {31, 5, 164, 12, 7}, - {142, 187, 64, 97, 4}, - {227, 2, 90, 15, 8}, - {40, 96, 45, 215, 1} - }, - { {250, 93, 132, 124, 6}, - {74, 191, 226, 171, 8}, - {99, 226, 27, 165, 15}, - {29, 84, 127, 213, 2} - }, - { {19, 29, 173, 215, 12}, - {88, 139, 197, 109, 15}, - {62, 187, 91, 140, 8}, - {251, 106, 61, 17, 10} - }, - { {195, 96, 214, 57, 15}, - {37, 245, 195, 215, 0}, - {249, 198, 176, 108, 3}, - {14, 188, 58, 250, 4} - }, - { {126, 199, 122, 149, 3}, - {174, 94, 188, 181, 6}, - {202, 149, 238, 55, 14}, - {106, 211, 215, 167, 5} - }, - { {45, 212, 161, 248, 1}, - {214, 164, 178, 104, 6}, - {129, 248, 82, 187, 4}, - {97, 100, 210, 86, 11} - }, - { {196, 27, 169, 22, 11}, - {220, 146, 141, 130, 13}, - {214, 137, 93, 130, 3}, - {180, 27, 20, 147, 11} - }, - { {174, 83, 48, 32, 14}, - {194, 22, 107, 19, 4}, - {112, 64, 204, 167, 5}, - {44, 141, 102, 132, 3} - }, - { {137, 195, 118, 107, 2}, - {34, 119, 26, 94, 5}, - {77, 102, 236, 57, 1}, - {167, 165, 142, 228, 4} - }, - { {17, 167, 104, 69, 2}, - {41, 26, 28, 108, 4}, - {74, 33, 110, 88, 8}, - {35, 99, 133, 137, 4} - }, - { {115, 24, 54, 184, 10}, - {64, 121, 163, 209, 14}, - {81, 214, 193, 140, 14}, - {120, 188, 89, 224, 2} - }, - { {152, 195, 136, 238, 2}, - {10, 190, 30, 10, 3}, - {71, 113, 28, 49, 9}, - {197, 7, 135, 213, 0} - }, - { {50, 158, 254, 117, 6}, - {104, 217, 254, 61, 12}, - {106, 231, 247, 148, 12}, - {59, 199, 249, 177, 6} - }, - { {235, 41, 103, 213, 2}, - {59, 83, 160, 207, 14}, - {74, 190, 105, 77, 7}, - {127, 48, 92, 173, 12} - }, - { {118, 246, 246, 147, 13}, - {229, 205, 249, 181, 7}, - {188, 150, 246, 246, 14}, - {234, 217, 251, 58, 7} - }, - { {75, 54, 229, 94, 10}, - {123, 177, 137, 233, 5}, - {87, 170, 118, 205, 2}, - {169, 121, 24, 221, 14} - }, - { {18, 100, 241, 41, 15}, - {53, 188, 67, 53, 4}, - {249, 72, 242, 100, 8}, - {42, 204, 35, 218, 12} - }, - { {195, 216, 179, 216, 12}, - {80, 228, 209, 219, 14}, - {49, 188, 209, 188, 3}, - {125, 184, 178, 112, 10} - }, - { {184, 252, 222, 50, 9}, - {103, 205, 183, 50, 9}, - {148, 199, 179, 241, 13}, - {148, 206, 219, 62, 6} - }, - { {53, 97, 247, 116, 12}, - {185, 207, 227, 88, 4}, - {50, 238, 248, 106, 12}, - {33, 172, 127, 57, 13} - }, - { {116, 255, 31, 22, 6}, - {217, 95, 252, 176, 9}, - {102, 143, 143, 242, 14}, - {144, 211, 255, 169, 11} - }, - { {29, 80, 232, 123, 6}, - {226, 188, 198, 76, 5}, - {109, 225, 112, 171, 8}, - {163, 38, 51, 212, 7} - }, - { {71, 201, 216, 44, 9}, - {172, 166, 23, 209, 8}, - {147, 65, 185, 62, 2}, - {24, 190, 134, 83, 5} - }, - { {198, 131, 135, 46, 9}, - {156, 227, 27, 131, 1}, - {151, 78, 28, 22, 3}, - {140, 29, 140, 115, 9} - }, - { {182, 245, 65, 140, 14}, - {249, 62, 113, 35, 2}, - {115, 24, 42, 246, 13}, - {76, 72, 231, 201, 15} - }, - { {209, 45, 250, 27, 10}, - {33, 250, 133, 246, 13}, - {93, 133, 251, 72, 11}, - {182, 250, 21, 248, 4} - }, - { {123, 222, 164, 209, 14}, - {66, 157, 249, 237, 14}, - {120, 178, 87, 189, 14}, - {123, 121, 251, 148, 2} - }, - { {148, 215, 11, 206, 8}, - {216, 110, 29, 42, 3}, - {23, 61, 14, 178, 9}, - {197, 75, 135, 97, 11} - }, - { {139, 161, 235, 181, 10}, - {59, 210, 151, 71, 6}, - {90, 221, 120, 93, 1}, - {110, 46, 148, 189, 12} - }, - { {2, 76, 23, 111, 5}, - {28, 101, 66, 61, 9}, - {175, 110, 131, 36, 0}, - {155, 196, 42, 99, 8} - }, - { {54, 104, 158, 115, 11}, - {133, 221, 167, 29, 9}, - {220, 231, 145, 102, 12}, - {155, 142, 91, 186, 1} - }, - { {208, 33, 104, 228, 4}, - {41, 10, 70, 138, 6}, - {34, 113, 104, 64, 11}, - {101, 22, 37, 9, 4} - }, - { {155, 143, 16, 45, 14}, - {10, 58, 91, 119, 8}, - {123, 64, 143, 29, 9}, - {30, 237, 165, 197, 0} - }, - { {126, 132, 92, 39, 11}, - {174, 25, 55, 181, 1}, - {222, 67, 162, 23, 14}, - {138, 222, 201, 135, 5} - }, - { {118, 223, 8, 118, 12}, - {200, 14, 255, 169, 9}, - {54, 225, 15, 182, 14}, - {153, 95, 247, 1, 3} - }, - { {251, 188, 21, 149, 7}, - {95, 25, 240, 247, 10}, - {234, 154, 131, 221, 15}, - {94, 240, 249, 143, 10} - }, - { {70, 128, 175, 59, 2}, - {144, 241, 150, 133, 5}, - {77, 207, 80, 22, 2}, - {170, 22, 152, 240, 9} - }, - { {209, 94, 13, 85, 9}, - {92, 13, 141, 238, 8}, - {154, 171, 7, 168, 11}, - {23, 123, 27, 3, 10} - }, - { {140, 34, 108, 129, 4}, - {163, 1, 76, 6, 6}, - {40, 19, 100, 67, 1}, - {102, 3, 40, 12, 5} - }, - { {118, 43, 180, 156, 1}, - {141, 171, 168, 145, 14}, - {131, 146, 221, 70, 14}, - {120, 145, 93, 91, 1} - }, - { {115, 86, 122, 41, 0}, - {96, 108, 46, 245, 4}, - {9, 69, 230, 172, 14}, - {42, 247, 67, 96, 6} - }, - { {65, 92, 222, 11, 1}, - {100, 229, 4, 244, 9}, - {141, 7, 179, 168, 2}, - {146, 242, 10, 114, 6} - }, - { {9, 152, 244, 128, 11}, - {102, 145, 17, 80, 14}, - {208, 18, 241, 153, 0}, - {112, 168, 136, 150, 6} - }, - { {227, 53, 25, 14, 13}, - {93, 34, 101, 243, 1}, - {183, 9, 138, 204, 7}, - {140, 250, 100, 75, 10} - }, - { {54, 133, 243, 244, 3}, - {188, 218, 178, 57, 6}, - {194, 252, 250, 22, 12}, - {105, 196, 213, 179, 13} - }, - { {149, 140, 227, 231, 8}, - {184, 200, 19, 110, 15}, - {30, 124, 115, 26, 9}, - {247, 108, 129, 49, 13} - }, - { {119, 22, 87, 104, 15}, - {244, 121, 107, 249, 0}, - {241, 110, 166, 142, 14}, - {9, 253, 105, 226, 15} - }, - { {192, 211, 150, 95, 4}, - {72, 231, 216, 158, 1}, - {47, 166, 156, 176, 3}, - {135, 145, 190, 113, 2} - }, - { {212, 159, 135, 115, 2}, - {208, 219, 154, 174, 9}, - {76, 238, 31, 146, 11}, - {151, 85, 157, 176, 11} - }, - { {69, 191, 48, 71, 8}, - {201, 2, 25, 252, 13}, - {30, 32, 207, 218, 2}, - {179, 249, 132, 9, 3} - }, - { {178, 247, 139, 151, 9}, - {93, 206, 189, 39, 3}, - {158, 157, 30, 244, 13}, - {206, 75, 215, 59, 10} - }, - { {182, 81, 172, 193, 7}, - {196, 159, 100, 15, 6}, - {232, 51, 88, 166, 13}, - {111, 2, 111, 146, 3} - }, - { {18, 188, 225, 89, 10}, - {113, 184, 145, 45, 12}, - {89, 168, 115, 212, 8}, - {59, 72, 145, 216, 14} - }, - { {142, 109, 66, 22, 5}, - {175, 70, 192, 35, 9}, - {166, 132, 43, 103, 1}, - {156, 64, 54, 47, 5} - }, - { {247, 219, 218, 17, 6}, - {224, 222, 252, 215, 8}, - {104, 133, 189, 190, 15}, - {30, 179, 247, 176, 7} - }, - { {95, 40, 2, 124, 14}, - {139, 120, 195, 201, 8}, - {115, 228, 1, 79, 10}, - {25, 60, 49, 237, 1} - }, - { {2, 18, 169, 157, 14}, - {88, 176, 205, 5, 6}, - {123, 153, 84, 132, 0}, - {106, 11, 48, 209, 10} - }, - { {191, 254, 168, 18, 10}, - {195, 156, 189, 99, 13}, - {84, 129, 87, 255, 13}, - {188, 107, 211, 156, 3} - }, - { {186, 49, 92, 161, 1}, - {103, 11, 38, 23, 2}, - {136, 83, 168, 197, 13}, - {78, 134, 77, 14, 6} - }, - { {7, 242, 225, 29, 7}, - {253, 180, 216, 69, 4}, - {235, 136, 116, 254, 0}, - {42, 33, 178, 219, 15} - }, - { {234, 79, 43, 164, 13}, - {30, 70, 111, 163, 14}, - {178, 93, 79, 37, 7}, - {124, 95, 102, 39, 8} - }, - { {165, 190, 34, 214, 12}, - {201, 64, 249, 106, 15}, - {54, 180, 71, 218, 5}, - {245, 105, 240, 41, 3} - }, - { {241, 169, 225, 184, 14}, - {49, 186, 243, 194, 14}, - {113, 216, 121, 88, 15}, - {116, 60, 245, 216, 12} - }, - { {202, 168, 155, 183, 7}, - {31, 208, 214, 151, 11}, - {238, 221, 145, 85, 3}, - {222, 150, 176, 191, 8} - }, - { {84, 134, 196, 245, 2}, - {168, 153, 154, 172, 2}, - {74, 242, 54, 18, 10}, - {67, 85, 153, 145, 5} - }, - { {53, 121, 76, 30, 4}, - {233, 47, 228, 64, 9}, - {39, 131, 41, 234, 12}, - {144, 34, 127, 73, 7} - }, - { {110, 216, 72, 137, 8}, - {226, 36, 53, 133, 10}, - {25, 17, 33, 183, 6}, - {90, 26, 194, 68, 7} - }, - { {186, 232, 137, 103, 6}, - {27, 156, 118, 15, 9}, - {110, 105, 17, 117, 13}, - {159, 6, 227, 157, 8} - }, - { {148, 192, 40, 189, 0}, - {136, 44, 150, 6, 6}, - {11, 209, 64, 50, 9}, - {102, 6, 147, 65, 1} - }, - { {115, 76, 162, 183, 6}, - {8, 220, 226, 229, 15}, - {110, 212, 83, 44, 14}, - {250, 116, 115, 177, 0} - }, - { {47, 241, 60, 122, 11}, - {199, 55, 183, 89, 5}, - {213, 227, 200, 255, 4}, - {169, 174, 222, 206, 3} - }, - { {204, 2, 99, 100, 7}, - {190, 80, 74, 138, 4}, - {226, 108, 100, 3, 3}, - {37, 21, 32, 167, 13} - }, - { {222, 144, 69, 41, 2}, - {242, 57, 18, 135, 0}, - {73, 74, 32, 151, 11}, - {14, 20, 137, 196, 15} - }, - { {2, 43, 108, 122, 15}, - {37, 51, 207, 9, 13}, - {245, 227, 109, 68, 0}, - {185, 15, 60, 202, 4} - }, - { {64, 75, 24, 30, 13}, - {12, 38, 205, 144, 9}, - {183, 129, 141, 32, 2}, - {144, 155, 54, 67, 0} - }, - { {44, 49, 42, 198, 5}, - {207, 66, 100, 8, 7}, - {166, 53, 72, 195, 4}, - {225, 2, 100, 47, 3} - }, - { {191, 189, 15, 65, 6}, - {211, 91, 116, 111, 8}, - {104, 47, 11, 223, 13}, - {31, 98, 237, 172, 11} - }, - { {232, 58, 99, 203, 12}, - {115, 96, 105, 142, 15}, - {61, 60, 101, 193, 7}, - {247, 25, 96, 108, 14} - }, - { {231, 89, 156, 35, 2}, - {192, 151, 38, 215, 9}, - {76, 67, 153, 174, 7}, - {158, 182, 78, 144, 3} - }, - { {255, 230, 113, 141, 6}, - {187, 60, 120, 247, 6}, - {107, 24, 230, 127, 15}, - {110, 241, 227, 205, 13} - }, - { {197, 136, 65, 238, 2}, - {184, 48, 18, 202, 11}, - {71, 120, 33, 26, 3}, - {213, 52, 128, 193, 13} - }, - { {171, 180, 217, 16, 2}, - {115, 144, 180, 115, 0}, - {64, 137, 178, 221, 5}, - {12, 226, 208, 156, 14} - }, - { {10, 23, 123, 120, 4}, - {114, 98, 206, 57, 4}, - {33, 237, 238, 133, 0}, - {41, 199, 52, 100, 14} - }, - { {78, 123, 115, 156, 14}, - {251, 118, 201, 145, 14}, - {115, 156, 237, 231, 2}, - {120, 153, 54, 237, 15} - }, - { {34, 227, 251, 26, 1}, - {53, 230, 188, 17, 5}, - {133, 141, 252, 116, 4}, - {168, 131, 214, 122, 12} - }, - { {54, 93, 186, 61, 2}, - {200, 254, 166, 53, 12}, - {75, 197, 219, 166, 12}, - {58, 198, 87, 241, 3} - }, - { {59, 220, 189, 56, 4}, - {82, 173, 246, 113, 12}, - {33, 203, 211, 189, 12}, - {56, 230, 251, 84, 10} - }, - { {200, 199, 188, 19, 5}, - {6, 135, 220, 182, 5}, - {172, 131, 222, 49, 3}, - {166, 211, 190, 22, 0} - }, - { {91, 16, 250, 200, 6}, - {98, 248, 68, 217, 6}, - {97, 53, 240, 141, 10}, - {105, 178, 33, 244, 6} - }, - { {208, 249, 92, 92, 11}, - {109, 63, 149, 154, 8}, - {211, 163, 169, 240, 11}, - {21, 154, 159, 203, 6} - }, - { {153, 6, 142, 77, 7}, - {14, 249, 76, 110, 0}, - {235, 39, 22, 9, 9}, - {7, 99, 41, 247, 0} - }, - { {200, 39, 17, 208, 2}, - {19, 18, 136, 186, 2}, - {64, 184, 142, 65, 3}, - {69, 209, 20, 140, 8} - }, - { {164, 84, 34, 73, 9}, - {196, 100, 33, 46, 4}, - {153, 36, 66, 162, 5}, - {39, 72, 66, 98, 3} - }, - { {169, 103, 185, 198, 3}, - {31, 150, 44, 122, 7}, - {198, 57, 222, 105, 5}, - {229, 227, 70, 159, 8} - }, - { {227, 227, 61, 193, 6}, - {17, 23, 124, 223, 6}, - {104, 59, 204, 124, 7}, - {111, 179, 238, 136, 8} - }, - { {242, 227, 250, 36, 6}, - {41, 222, 126, 147, 4}, - {98, 69, 252, 116, 15}, - {44, 151, 231, 185, 4} - }, - { {171, 214, 110, 194, 10}, - {98, 85, 61, 107, 7}, - {84, 55, 102, 189, 5}, - {237, 107, 202, 164, 6} - }, - { {150, 166, 172, 174, 12}, - {137, 169, 95, 35, 7}, - {55, 83, 86, 86, 9}, - {236, 79, 169, 89, 1} - }, - { {17, 94, 218, 37, 15}, - {108, 220, 79, 116, 8}, - {250, 69, 183, 168, 8}, - {18, 239, 35, 179, 6} - }, - { {224, 72, 217, 79, 9}, - {60, 164, 37, 158, 9}, - {159, 41, 177, 32, 7}, - {151, 154, 66, 83, 12} - }, - { {62, 162, 162, 69, 13}, - {143, 200, 121, 13, 4}, - {186, 36, 84, 87, 12}, - {43, 9, 225, 63, 1} - }, - { {147, 122, 113, 157, 10}, - {121, 60, 137, 87, 14}, - {91, 152, 229, 236, 9}, - {126, 169, 19, 201, 14} - }, - { {109, 101, 53, 32, 4}, - {147, 7, 98, 240, 4}, - {32, 74, 202, 107, 6}, - {32, 244, 110, 12, 9} - }, - { {218, 6, 151, 74, 11}, - {22, 249, 9, 187, 1}, - {213, 46, 150, 5, 11}, - {141, 217, 9, 246, 8} - }, - { {20, 176, 37, 32, 10}, - {209, 25, 19, 0, 4}, - {80, 74, 64, 210, 8}, - {32, 12, 137, 136, 11} - }, - { {122, 150, 135, 109, 5}, - {94, 233, 122, 173, 0}, - {171, 110, 22, 149, 14}, - {11, 85, 233, 119, 10} - }, - { {221, 120, 18, 100, 5}, - {207, 76, 66, 218, 8}, - {162, 100, 129, 235, 11}, - {21, 180, 35, 47, 3} - }, - { {130, 195, 122, 162, 9}, - {36, 70, 31, 19, 7}, - {148, 85, 236, 52, 1}, - {236, 143, 134, 34, 4} - }, - { {151, 25, 250, 15, 4}, - {232, 234, 68, 87, 13}, - {47, 5, 249, 142, 9}, - {190, 162, 37, 113, 7} - }, - { {58, 108, 193, 181, 7}, - {63, 156, 226, 37, 10}, - {234, 216, 51, 101, 12}, - {90, 68, 115, 159, 12} - }, - { {97, 33, 177, 73, 13}, - {21, 162, 97, 220, 4}, - {185, 40, 216, 72, 6}, - {35, 184, 100, 90, 8} - }, - { {208, 123, 6, 29, 14}, - {73, 127, 201, 134, 8}, - {123, 134, 13, 224, 11}, - {22, 25, 63, 233, 2} - }, - { {69, 190, 247, 38, 9}, - {253, 193, 27, 240, 13}, - {150, 78, 247, 218, 2}, - {176, 253, 136, 59, 15} - }, - { {157, 70, 148, 66, 4}, - {130, 141, 72, 122, 1}, - {36, 34, 150, 43, 9}, - {133, 225, 43, 20, 1} - }, - { {77, 251, 186, 241, 4}, - {195, 198, 222, 220, 14}, - {40, 245, 221, 251, 2}, - {115, 183, 182, 60, 3} - }, - { {200, 236, 99, 163, 1}, - {55, 68, 18, 166, 15}, - {140, 92, 99, 113, 3}, - {246, 84, 130, 46, 12} - }, - { {41, 38, 49, 96, 9}, - {23, 0, 43, 120, 4}, - {144, 104, 198, 73, 4}, - {33, 237, 64, 14, 8} - }, - { {34, 234, 181, 80, 10}, - {17, 149, 185, 25, 12}, - {80, 170, 213, 116, 4}, - {57, 137, 218, 152, 8} - }, - { {12, 83, 62, 124, 9}, - {206, 103, 143, 24, 4}, - {147, 231, 204, 163, 0}, - {33, 143, 30, 103, 3} - }, - { {241, 209, 122, 65, 9}, - {100, 78, 53, 222, 4}, - {152, 37, 232, 184, 15}, - {39, 186, 199, 34, 6} - }, - { {190, 41, 45, 21, 12}, - {155, 11, 229, 7, 12}, - {58, 139, 73, 71, 13}, - {62, 10, 125, 13, 9} - }, - { {173, 236, 230, 5, 15}, - {175, 213, 113, 102, 12}, - {250, 6, 115, 123, 5}, - {54, 104, 234, 191, 5} - }, - { {23, 198, 147, 157, 3}, - {156, 252, 152, 117, 2}, - {203, 156, 150, 62, 8}, - {74, 225, 147, 243, 9} - }, - { {76, 195, 212, 88, 9}, - {166, 167, 153, 152, 0}, - {145, 162, 188, 51, 2}, - {1, 153, 158, 86, 5} - }, - { {154, 214, 102, 33, 4}, - {98, 77, 90, 39, 4}, - {40, 70, 102, 181, 9}, - {46, 69, 171, 36, 6} - }, - { {19, 133, 65, 215, 3}, - {60, 26, 144, 109, 3}, - {206, 184, 42, 28, 8}, - {203, 96, 149, 131, 12} - }, - { {86, 15, 151, 244, 5}, - {156, 203, 202, 185, 10}, - {162, 254, 159, 6, 10}, - {89, 213, 61, 51, 9} - }, - { {166, 192, 165, 246, 0}, - {152, 133, 178, 11, 7}, - {6, 250, 80, 54, 5}, - {237, 4, 218, 17, 9} - }, - { {95, 226, 229, 89, 8}, - {179, 173, 153, 205, 4}, - {25, 170, 116, 127, 10}, - {43, 57, 155, 92, 13} - }, - { {67, 190, 136, 118, 5}, - {77, 128, 222, 233, 9}, - {166, 225, 23, 220, 2}, - {153, 119, 176, 27, 2} - }, - { {8, 144, 129, 205, 4}, - {90, 160, 80, 12, 2}, - {43, 56, 16, 145, 0}, - {67, 0, 160, 85, 10} - }, - { {77, 234, 23, 239, 15}, - {159, 117, 91, 220, 11}, - {255, 126, 133, 123, 2}, - {211, 189, 170, 239, 9} - }, - { {124, 58, 173, 18, 0}, - {211, 137, 172, 128, 13}, - {4, 139, 85, 195, 14}, - {176, 19, 89, 28, 11} - }, - { {67, 86, 162, 174, 9}, - {76, 228, 11, 225, 7}, - {151, 84, 86, 172, 2}, - {232, 125, 2, 115, 2} - }, - { {236, 183, 0, 75, 5}, - {199, 34, 120, 174, 1}, - {173, 32, 14, 211, 7}, - {135, 81, 228, 78, 3} - }, - { {247, 97, 178, 178, 7}, - {133, 222, 226, 211, 7}, - {228, 212, 216, 110, 15}, - {236, 180, 119, 186, 1} - }, - { {137, 36, 99, 124, 13}, - {63, 96, 195, 106, 4}, - {179, 236, 98, 73, 1}, - {37, 108, 48, 111, 12} - }, - { {114, 58, 98, 179, 1}, - {101, 72, 170, 133, 15}, - {140, 212, 101, 196, 14}, - {250, 21, 81, 42, 6} - }, - { {41, 180, 125, 69, 1}, - {127, 1, 52, 124, 4}, - {138, 43, 226, 217, 4}, - {35, 226, 200, 15, 14} - }, - { {18, 107, 239, 149, 10}, - {57, 223, 141, 5, 14}, - {90, 159, 125, 100, 8}, - {122, 11, 31, 185, 12} - }, - { {161, 94, 96, 121, 10}, - {96, 52, 171, 110, 12}, - {89, 224, 103, 168, 5}, - {55, 109, 82, 192, 6} - }, - { {126, 76, 172, 58, 13}, - {134, 173, 231, 161, 13}, - {181, 195, 83, 39, 14}, - {184, 94, 123, 86, 1} - }, - { {114, 142, 21, 50, 3}, - {20, 25, 186, 177, 9}, - {196, 202, 135, 20, 14}, - {152, 213, 217, 130, 8} - }, - { {50, 5, 228, 151, 0}, - {40, 139, 160, 37, 7}, - {14, 146, 122, 4, 12}, - {234, 64, 93, 17, 4} - }, - { {20, 99, 87, 142, 15}, - {189, 127, 73, 16, 3}, - {247, 30, 172, 98, 8}, - {192, 137, 47, 235, 13} - }, - { {70, 114, 172, 144, 8}, - {193, 133, 141, 129, 6}, - {16, 147, 84, 230, 2}, - {104, 27, 26, 24, 3} - }, - { {218, 88, 222, 192, 8}, - {98, 205, 5, 155, 10}, - {16, 55, 177, 165, 11}, - {93, 154, 11, 52, 6} - }, - { {201, 31, 228, 54, 4}, - {106, 131, 202, 226, 13}, - {38, 194, 127, 137, 3}, - {180, 117, 60, 21, 6} - }, - { {161, 197, 254, 154, 12}, - {32, 231, 245, 114, 7}, - {53, 151, 250, 56, 5}, - {228, 234, 254, 112, 4} - }, - { {247, 70, 210, 71, 7}, - {172, 220, 104, 255, 1}, - {238, 36, 182, 46, 15}, - {143, 241, 99, 179, 5} - }, - { {56, 73, 248, 205, 2}, - {42, 190, 36, 28, 14}, - {75, 49, 249, 33, 12}, - {115, 130, 71, 213, 4} - }, - { {186, 114, 36, 10, 6}, - {67, 61, 104, 3, 5}, - {101, 2, 68, 229, 13}, - {172, 1, 107, 204, 2} - }, - { {100, 162, 99, 127, 3}, - {189, 112, 186, 140, 5}, - {207, 236, 100, 82, 6}, - {163, 21, 208, 235, 13} - }, - { {132, 80, 221, 43, 3}, - {244, 181, 6, 22, 1}, - {205, 75, 176, 162, 1}, - {134, 134, 10, 210, 15} - }, - { {233, 134, 163, 18, 6}, - {18, 208, 248, 226, 5}, - {100, 140, 86, 25, 7}, - {164, 113, 240, 180, 8} - }, - { {31, 106, 10, 155, 13}, - {135, 108, 205, 69, 11}, - {189, 149, 5, 111, 8}, - {218, 43, 51, 110, 1} - }, - { {193, 131, 19, 193, 9}, - {20, 66, 25, 222, 2}, - {152, 60, 140, 24, 3}, - {71, 185, 132, 34, 8} - }, - { {68, 244, 102, 59, 11}, - {229, 117, 147, 164, 5}, - {221, 198, 98, 242, 2}, - {162, 92, 154, 234, 7} - }, - { {1, 157, 216, 198, 10}, - {104, 146, 21, 120, 11}, - {86, 49, 187, 152, 0}, - {209, 234, 132, 145, 6} - }, - { {207, 106, 252, 4, 8}, - {171, 133, 13, 211, 12}, - {18, 3, 245, 111, 3}, - {60, 187, 10, 29, 5} - }, - { {146, 174, 195, 5, 6}, - {57, 216, 88, 39, 8}, - {106, 12, 55, 84, 9}, - {30, 65, 161, 185, 12} - }, - { {37, 21, 93, 154, 5}, - {244, 35, 228, 112, 3}, - {165, 155, 170, 138, 4}, - {192, 226, 124, 66, 15} - }, - { {22, 10, 92, 69, 6}, - {168, 25, 76, 29, 8}, - {106, 35, 165, 6, 8}, - {27, 131, 41, 129, 5} - }, - { {42, 195, 144, 107, 5}, - {6, 166, 122, 29, 1}, - {173, 96, 156, 53, 4}, - {139, 133, 230, 86, 0} - }, - { {46, 122, 182, 246, 15}, - {207, 213, 235, 25, 15}, - {246, 246, 213, 231, 4}, - {249, 141, 122, 191, 3} - }, - { {158, 250, 147, 214, 12}, - {219, 204, 217, 27, 11}, - {54, 188, 149, 247, 9}, - {221, 137, 179, 61, 11} - }, - { {70, 52, 147, 36, 2}, - {217, 208, 2, 177, 0}, - {66, 76, 146, 198, 2}, - {8, 212, 0, 185, 11} - }, - { {10, 253, 84, 150, 12}, - {107, 7, 209, 49, 11}, - {54, 146, 171, 245, 0}, - {216, 200, 190, 13, 6} - }, - { {176, 98, 61, 37, 0}, - {25, 13, 46, 22, 4}, - {10, 75, 196, 96, 13}, - {38, 135, 75, 9, 8} - }, - { {145, 210, 194, 45, 8}, - {104, 236, 27, 70, 0}, - {27, 68, 52, 184, 9}, - {6, 45, 131, 113, 6} - }, - { {180, 12, 140, 215, 2}, - {136, 153, 164, 46, 11}, - {78, 179, 19, 2, 13}, - {215, 66, 89, 145, 1} - }, - { {159, 137, 21, 197, 9}, - {158, 11, 17, 95, 10}, - {154, 58, 137, 31, 9}, - {95, 168, 141, 7, 9} - }, - { {231, 171, 31, 92, 9}, - {157, 99, 189, 219, 8}, - {147, 175, 141, 94, 7}, - {29, 187, 220, 107, 9} - }, - { {64, 95, 208, 111, 7}, - {108, 182, 74, 188, 9}, - {239, 96, 191, 160, 2}, - {147, 213, 38, 211, 6} - }, - { {107, 30, 197, 224, 6}, - {114, 145, 106, 233, 10}, - {96, 122, 55, 141, 6}, - {89, 117, 104, 148, 14} - }, - { {172, 27, 229, 165, 10}, - {250, 147, 43, 6, 14}, - {90, 90, 125, 131, 5}, - {118, 13, 76, 149, 15} - }, - { {230, 47, 3, 108, 10}, - {153, 114, 43, 171, 8}, - {83, 108, 15, 70, 7}, - {29, 93, 68, 233, 9} - }, - { {127, 229, 102, 248, 8}, - {163, 111, 179, 233, 6}, - {17, 246, 106, 127, 14}, - {105, 124, 223, 108, 5} - }, - { {163, 194, 62, 50, 14}, - {0, 85, 255, 83, 5}, - {116, 199, 196, 60, 5}, - {172, 175, 250, 160, 0} - }, - { {148, 62, 117, 118, 6}, - {249, 25, 202, 58, 13}, - {102, 234, 231, 194, 9}, - {181, 197, 57, 137, 15} - }, - { {52, 186, 30, 90, 15}, - {197, 121, 253, 24, 9}, - {245, 167, 133, 210, 12}, - {145, 139, 249, 234, 3} - }, - { {3, 165, 18, 156, 11}, - {13, 114, 145, 113, 2}, - {211, 148, 138, 92, 0}, - {72, 232, 148, 235, 0} - }, - { {37, 82, 144, 131, 7}, - {196, 148, 104, 84, 3}, - {236, 16, 148, 170, 4}, - {194, 161, 98, 146, 3} - }, - { {152, 56, 107, 83, 15}, - {119, 88, 197, 14, 13}, - {252, 173, 97, 193, 9}, - {183, 10, 49, 174, 14} - }, - { {81, 8, 229, 57, 2}, - {48, 185, 130, 196, 12}, - {73, 202, 113, 8, 10}, - {50, 52, 25, 208, 12} - }, - { {109, 47, 236, 46, 14}, - {171, 179, 111, 224, 13}, - {119, 67, 127, 75, 6}, - {176, 127, 108, 221, 5} - }, - { {82, 188, 16, 202, 10}, - {65, 56, 17, 185, 11}, - {85, 48, 131, 212, 10}, - {217, 216, 129, 200, 2} - }, - { {179, 40, 54, 67, 10}, - {1, 89, 33, 95, 13}, - {92, 38, 193, 76, 13}, - {191, 168, 73, 168, 0} - }, - { {119, 53, 50, 215, 6}, - {201, 90, 224, 253, 7}, - {110, 180, 202, 206, 14}, - {235, 240, 117, 169, 3} - }, - { {60, 107, 123, 81, 7}, - {183, 94, 236, 28, 12}, - {232, 173, 237, 99, 12}, - {51, 131, 119, 174, 13} - }, - { {58, 210, 85, 76, 8}, - {122, 45, 57, 25, 0}, - {19, 42, 164, 181, 12}, - {9, 137, 203, 69, 14} - }, - { {121, 133, 192, 110, 10}, - {42, 186, 51, 232, 1}, - {87, 96, 58, 25, 14}, - {129, 124, 197, 213, 4} - }, - { {197, 187, 154, 199, 7}, - {205, 210, 92, 222, 11}, - {238, 53, 157, 218, 3}, - {215, 179, 164, 187, 3} - }, - { {12, 197, 122, 240, 11}, - {166, 86, 151, 56, 6}, - {208, 245, 234, 51, 0}, - {97, 206, 150, 166, 5} - }, - { {248, 208, 240, 214, 2}, - {106, 156, 176, 154, 7}, - {70, 176, 240, 177, 15}, - {229, 144, 211, 149, 6} - }, - { {129, 63, 211, 226, 11}, - {117, 210, 11, 122, 11}, - {212, 124, 191, 200, 1}, - {213, 237, 4, 186, 14} - }, - { {13, 236, 216, 183, 12}, - {171, 132, 215, 116, 11}, - {62, 209, 179, 123, 0}, - {210, 238, 178, 29, 5} - }, - { {27, 74, 227, 19, 2}, - {50, 220, 136, 69, 13}, - {76, 140, 117, 45, 8}, - {186, 33, 19, 180, 12} - }, - { {210, 32, 64, 67, 5}, - {37, 8, 64, 143, 1}, - {172, 32, 32, 68, 11}, - {143, 16, 33, 10, 4} - }, - { {20, 134, 143, 224, 4}, - {144, 201, 94, 40, 2}, - {32, 127, 22, 18, 8}, - {65, 71, 169, 48, 9} - }, - { {129, 156, 58, 252, 10}, - {72, 112, 151, 122, 14}, - {83, 245, 195, 152, 1}, - {117, 238, 144, 225, 2} - }, - { {69, 204, 88, 112, 14}, - {160, 20, 215, 248, 8}, - {112, 225, 163, 58, 2}, - {17, 254, 178, 128, 5} - }, - { {85, 209, 44, 27, 7}, - {196, 63, 212, 196, 5}, - {237, 131, 72, 186, 10}, - {162, 50, 191, 194, 3} - }, - { {124, 82, 159, 25, 14}, - {210, 253, 237, 148, 0}, - {121, 143, 148, 163, 14}, - {2, 155, 123, 244, 11} - }, - { {112, 145, 54, 145, 1}, - {68, 75, 176, 148, 6}, - {136, 150, 200, 144, 14}, - {98, 144, 221, 34, 2} - }, - { {252, 90, 66, 132, 10}, - {234, 92, 41, 130, 10}, - {82, 20, 37, 163, 15}, - {84, 25, 67, 165, 7} - }, - { {87, 151, 148, 193, 3}, - {196, 155, 24, 253, 2}, - {200, 50, 158, 158, 10}, - {75, 241, 141, 146, 3} - }, - { {165, 209, 196, 248, 2}, - {224, 183, 178, 74, 2}, - {65, 242, 56, 186, 5}, - {69, 36, 222, 208, 7} - }, - { {129, 60, 188, 144, 8}, - {65, 129, 133, 114, 14}, - {16, 147, 211, 200, 1}, - {116, 234, 24, 24, 2} - }, - { {9, 113, 70, 213, 3}, - {111, 87, 128, 76, 2}, - {202, 182, 40, 233, 0}, - {67, 32, 30, 175, 6} - }, - { {106, 207, 210, 216, 5}, - {38, 230, 248, 185, 10}, - {161, 180, 191, 53, 6}, - {89, 209, 246, 118, 4} - }, - { {115, 244, 119, 116, 9}, - {125, 77, 179, 249, 4}, - {146, 238, 226, 252, 14}, - {41, 252, 219, 43, 14} - }, - { {245, 157, 172, 185, 10}, - {192, 187, 183, 230, 14}, - {89, 211, 91, 154, 15}, - {118, 126, 221, 208, 3} - }, - { {202, 249, 118, 232, 4}, - {99, 103, 82, 155, 14}, - {33, 118, 233, 245, 3}, - {125, 148, 174, 108, 6} - }, - { {145, 223, 213, 147, 14}, - {112, 159, 217, 118, 11}, - {124, 154, 191, 184, 9}, - {214, 233, 191, 144, 14} - }, - { {151, 224, 139, 96, 13}, - {149, 204, 87, 75, 0}, - {176, 109, 16, 126, 9}, - {13, 46, 163, 58, 9} - }, - { {171, 24, 195, 41, 7}, - {118, 240, 98, 71, 8}, - {233, 76, 49, 141, 5}, - {30, 36, 96, 246, 14} - }, - { {12, 117, 233, 207, 4}, - {251, 166, 68, 44, 7}, - {47, 57, 122, 227, 0}, - {227, 66, 38, 93, 15} - }, - { {18, 88, 90, 126, 11}, - {108, 124, 135, 25, 9}, - {215, 229, 161, 164, 8}, - {153, 142, 19, 227, 6} - }, - { {226, 61, 82, 49, 9}, - {101, 66, 163, 183, 8}, - {152, 196, 171, 196, 7}, - {30, 220, 84, 42, 6} - }, - { {148, 62, 206, 46, 10}, - {233, 249, 15, 34, 9}, - {87, 71, 55, 194, 9}, - {148, 79, 9, 249, 7} - }, - { {77, 128, 42, 254, 11}, - {142, 112, 151, 200, 7}, - {215, 245, 64, 27, 2}, - {225, 62, 144, 231, 1} - }, - { {99, 222, 29, 74, 1}, - {84, 37, 60, 249, 9}, - {133, 43, 135, 188, 6}, - {153, 243, 202, 66, 10} - }, - { {234, 149, 240, 24, 8}, - {98, 162, 177, 179, 4}, - {17, 128, 250, 149, 7}, - {44, 216, 212, 84, 6} - }, - { {20, 204, 99, 128, 10}, - {176, 92, 17, 32, 14}, - {80, 28, 99, 50, 8}, - {112, 72, 131, 160, 13} - }, - { {200, 176, 49, 75, 15}, - {87, 48, 81, 158, 5}, - {253, 40, 192, 209, 3}, - {167, 152, 160, 206, 10} - }, - { {158, 5, 82, 110, 15}, - {174, 122, 67, 59, 1}, - {247, 100, 170, 7, 9}, - {141, 204, 37, 231, 5} - }, - { {90, 49, 246, 81, 3}, - {103, 219, 128, 157, 4}, - {200, 166, 248, 197, 10}, - {43, 144, 29, 190, 6} - }, - { {2, 64, 141, 174, 9}, - {28, 165, 7, 1, 3}, - {151, 91, 16, 36, 0}, - {200, 14, 10, 83, 8} - }, - { {3, 39, 204, 189, 6}, - {41, 179, 206, 101, 2}, - {107, 211, 62, 76, 0}, - {74, 103, 60, 217, 4} - }, - { {57, 199, 200, 136, 5}, - {38, 174, 124, 96, 2}, - {161, 17, 62, 57, 12}, - {64, 99, 231, 86, 4} - }, - { {29, 241, 95, 61, 5}, - {255, 111, 214, 84, 0}, - {171, 207, 168, 251, 8}, - {2, 166, 191, 111, 15} - }, - { {53, 248, 87, 146, 8}, - {241, 77, 177, 80, 11}, - {20, 158, 161, 250, 12}, - {208, 168, 219, 40, 15} - }, - { {246, 170, 194, 38, 15}, - {173, 216, 123, 131, 9}, - {246, 68, 53, 86, 15}, - {156, 29, 225, 187, 5} - }, - { {231, 224, 91, 154, 9}, - {181, 100, 181, 211, 3}, - {149, 157, 160, 126, 7}, - {204, 186, 210, 106, 13} - }, - { {35, 84, 88, 78, 2}, - {104, 52, 36, 121, 1}, - {71, 33, 162, 172, 4}, - {137, 226, 66, 193, 6} - }, - { {168, 240, 123, 208, 12}, - {115, 68, 245, 26, 6}, - {48, 189, 224, 241, 5}, - {101, 138, 242, 44, 14} - }, - { {31, 123, 242, 62, 3}, - {239, 254, 138, 81, 13}, - {199, 196, 253, 239, 8}, - {184, 165, 23, 255, 7} - }, - { {166, 34, 215, 254, 13}, - {189, 225, 235, 27, 3}, - {183, 254, 180, 70, 5}, - {205, 141, 120, 123, 13} - }, - { {60, 224, 174, 102, 10}, - {139, 221, 55, 8, 5}, - {86, 103, 80, 115, 12}, - {161, 14, 203, 189, 1} - }, - { {157, 234, 252, 246, 9}, - {175, 141, 159, 90, 15}, - {150, 243, 245, 123, 9}, - {245, 175, 155, 31, 5} - }, - { {118, 28, 15, 110, 1}, - {220, 105, 38, 169, 9}, - {135, 111, 3, 134, 14}, - {153, 86, 73, 99, 11} - }, - { {23, 229, 15, 201, 12}, - {145, 111, 85, 109, 2}, - {57, 63, 10, 126, 8}, - {75, 106, 175, 104, 9} - }, - { {107, 215, 2, 212, 12}, - {74, 70, 249, 233, 2}, - {50, 180, 14, 189, 6}, - {73, 121, 246, 37, 2} - }, - { {86, 44, 136, 80, 8}, - {129, 136, 133, 169, 8}, - {16, 161, 19, 70, 10}, - {25, 90, 17, 24, 1} - }, - { {117, 18, 248, 29, 15}, - {236, 184, 237, 212, 4}, - {251, 129, 244, 138, 14}, - {34, 187, 113, 211, 7} - }, - { {126, 225, 73, 21, 0}, - {187, 14, 180, 133, 0}, - {10, 137, 40, 119, 14}, - {10, 18, 215, 13, 13} - }, - { {16, 118, 198, 246, 1}, - {109, 205, 138, 40, 3}, - {134, 246, 54, 224, 8}, - {193, 69, 27, 59, 6} - }, - { {212, 235, 35, 223, 2}, - {153, 126, 152, 142, 15}, - {79, 188, 77, 114, 11}, - {247, 17, 151, 233, 9} - }, - { {40, 207, 171, 134, 10}, - {26, 214, 61, 32, 15}, - {86, 29, 95, 49, 4}, - {240, 75, 198, 181, 8} - }, - { {172, 20, 113, 133, 3}, - {254, 16, 32, 54, 6}, - {202, 24, 226, 131, 5}, - {102, 192, 64, 135, 15} - }, - { {175, 152, 175, 103, 14}, - {218, 209, 119, 79, 13}, - {126, 111, 81, 159, 5}, - {191, 46, 232, 181, 11} - }, - { {193, 158, 114, 157, 1}, - {108, 96, 152, 246, 14}, - {139, 148, 231, 152, 3}, - {118, 241, 144, 99, 6} - }, - { {207, 95, 181, 152, 6}, - {210, 183, 200, 243, 14}, - {97, 154, 223, 175, 3}, - {124, 241, 62, 212, 11} - }, - { {213, 221, 187, 147, 2}, - {208, 222, 148, 246, 15}, - {76, 157, 219, 186, 11}, - {246, 242, 151, 176, 11} - }, - { {79, 134, 37, 109, 3}, - {158, 49, 26, 237, 4}, - {203, 106, 70, 31, 2}, - {43, 117, 136, 199, 9} - }, - { {106, 36, 71, 111, 0}, - {59, 97, 34, 173, 1}, - {15, 110, 34, 69, 6}, - {139, 84, 72, 109, 12} - }, - { {128, 45, 147, 26, 1}, - {21, 226, 128, 50, 9}, - {133, 140, 155, 64, 1}, - {148, 192, 20, 122, 8} - }, - { {29, 205, 131, 180, 9}, - {158, 206, 147, 96, 10}, - {146, 220, 27, 59, 8}, - {80, 108, 151, 55, 9} - }, - { {218, 134, 193, 229, 12}, - {58, 136, 91, 175, 2}, - {58, 120, 54, 21, 11}, - {79, 93, 161, 21, 12} - }, - { {230, 246, 109, 46, 3}, - {253, 53, 62, 163, 5}, - {199, 75, 102, 246, 7}, - {172, 87, 202, 203, 15} - }, - { {61, 137, 16, 149, 7}, - {142, 26, 240, 84, 10}, - {234, 144, 137, 27, 12}, - {82, 160, 245, 135, 1} - }, - { {210, 121, 65, 88, 12}, - {113, 46, 193, 139, 8}, - {49, 168, 41, 228, 11}, - {29, 24, 55, 72, 14} - }, - { {160, 175, 28, 189, 14}, - {9, 51, 255, 54, 10}, - {123, 211, 143, 80, 5}, - {86, 207, 252, 201, 0} - }, - { {1, 87, 110, 34, 13}, - {100, 71, 79, 96, 5}, - {180, 71, 110, 168, 0}, - {160, 111, 46, 34, 6} - }, - { {87, 248, 236, 245, 8}, - {233, 141, 151, 205, 14}, - {26, 243, 113, 254, 10}, - {123, 62, 155, 25, 7} - }, - { {106, 255, 41, 18, 1}, - {87, 6, 188, 161, 13}, - {132, 137, 79, 245, 6}, - {184, 83, 214, 14, 10} - }, - { {251, 33, 174, 202, 0}, - {3, 235, 36, 203, 7}, - {5, 55, 88, 77, 15}, - {237, 50, 77, 124, 0} - }, - { {11, 139, 189, 114, 11}, - {22, 147, 159, 89, 13}, - {212, 235, 221, 29, 0}, - {185, 175, 156, 150, 8} - }, - { {212, 152, 51, 194, 13}, - {212, 72, 81, 154, 15}, - {180, 60, 193, 146, 11}, - {245, 152, 161, 34, 11} - }, - { {225, 75, 0, 230, 14}, - {8, 22, 107, 202, 11}, - {118, 112, 13, 40, 7}, - {213, 61, 102, 129, 0} - }, - { {26, 95, 155, 85, 5}, - {94, 206, 204, 61, 8}, - {170, 173, 159, 165, 8}, - {27, 195, 55, 55, 10} - }, - { {240, 142, 136, 165, 15}, - {12, 152, 127, 166, 10}, - {250, 81, 23, 16, 15}, - {86, 95, 225, 147, 0} - }, - { {167, 153, 98, 167, 6}, - {232, 82, 114, 71, 15}, - {110, 84, 105, 158, 5}, - {254, 36, 228, 161, 7} - }, - { {117, 137, 204, 235, 6}, - {160, 187, 118, 204, 11}, - {109, 115, 57, 26, 14}, - {211, 54, 237, 208, 5} - }, - { {146, 223, 143, 67, 12}, - {80, 207, 93, 47, 9}, - {60, 47, 31, 180, 9}, - {159, 75, 175, 48, 10} - }, - { {174, 86, 155, 223, 2}, - {218, 244, 172, 63, 3}, - {79, 189, 150, 167, 5}, - {207, 195, 82, 245, 11} - }, - { {210, 12, 103, 74, 4}, - {48, 105, 64, 171, 13}, - {37, 46, 99, 4, 11}, - {189, 80, 41, 96, 12} - }, - { {40, 70, 65, 78, 7}, - {62, 52, 104, 40, 1}, - {231, 40, 38, 33, 4}, - {129, 65, 98, 199, 12} - }, - { {108, 201, 54, 127, 1}, - {142, 103, 178, 156, 13}, - {143, 230, 201, 51, 6}, - {179, 148, 222, 103, 1} - }, - { {194, 238, 156, 100, 12}, - {9, 133, 95, 187, 8}, - {50, 99, 151, 116, 3}, - {29, 223, 170, 25, 0} - }, - { {36, 163, 220, 7, 0}, - {169, 131, 60, 20, 1}, - {14, 3, 188, 82, 4}, - {130, 131, 204, 25, 5} - }, - { {41, 169, 53, 183, 11}, - {31, 19, 179, 84, 15}, - {222, 218, 201, 89, 4}, - {242, 172, 220, 143, 8} - }, - { {105, 9, 143, 242, 0}, - {18, 195, 166, 200, 11}, - {4, 255, 25, 9, 6}, - {209, 54, 92, 52, 8} - }, - { {221, 179, 45, 144, 2}, - {211, 27, 156, 194, 6}, - {64, 155, 76, 219, 11}, - {100, 51, 157, 140, 11} - }, - { {17, 24, 73, 168, 13}, - {116, 40, 71, 64, 10}, - {177, 89, 33, 136, 8}, - {80, 46, 33, 66, 14} - }, - { {182, 179, 217, 164, 5}, - {253, 138, 126, 19, 2}, - {162, 89, 188, 214, 13}, - {76, 135, 229, 27, 15} - }, - { {160, 207, 230, 60, 2}, - {40, 247, 186, 34, 12}, - {67, 198, 127, 48, 5}, - {52, 69, 222, 241, 4} - }, - { {55, 59, 166, 59, 8}, - {193, 235, 171, 69, 13}, - {29, 198, 93, 206, 12}, - {186, 45, 93, 120, 3} - }, - { {161, 242, 208, 206, 8}, - {105, 164, 57, 90, 3}, - {23, 48, 180, 248, 5}, - {197, 169, 194, 89, 6} - }, - { {86, 143, 18, 81, 15}, - {132, 90, 217, 189, 8}, - {248, 164, 143, 22, 10}, - {27, 217, 181, 162, 1} - }, - { {194, 231, 12, 94, 10}, - {9, 55, 157, 171, 1}, - {87, 163, 14, 116, 3}, - {141, 91, 158, 201, 0} - }, - { {156, 25, 191, 90, 0}, - {210, 235, 132, 26, 13}, - {5, 175, 217, 131, 9}, - {181, 130, 29, 116, 11} - }, - { {117, 207, 171, 65, 6}, - {144, 222, 124, 236, 12}, - {104, 45, 95, 58, 14}, - {51, 115, 231, 176, 9} - }, - { {126, 204, 41, 109, 0}, - {154, 44, 54, 173, 12}, - {11, 105, 67, 55, 14}, - {59, 86, 195, 69, 9} - }, - { {243, 91, 227, 26, 14}, - {112, 254, 233, 195, 13}, - {117, 140, 125, 172, 15}, - {188, 57, 119, 240, 14} - }, - { {190, 117, 133, 241, 8}, - {211, 143, 163, 47, 2}, - {24, 250, 26, 231, 13}, - {79, 76, 95, 28, 11} - }, - { {33, 154, 217, 93, 10}, - {120, 176, 189, 92, 8}, - {91, 169, 181, 152, 4}, - {19, 171, 208, 209, 14} - }, - { {187, 162, 184, 116, 12}, - {11, 136, 255, 91, 4}, - {50, 225, 212, 93, 13}, - {45, 175, 241, 29, 0} - }, - { {24, 170, 15, 78, 6}, - {27, 121, 92, 8, 9}, - {103, 47, 5, 81, 8}, - {145, 3, 169, 237, 8} - }, - { {141, 163, 255, 65, 12}, - {179, 195, 93, 94, 4}, - {56, 47, 252, 91, 1}, - {39, 171, 172, 60, 13} - }, - { {204, 241, 13, 15, 1}, - {223, 39, 20, 134, 1}, - {143, 11, 8, 243, 3}, - {134, 18, 142, 79, 11} - }, - { {15, 249, 178, 82, 13}, - {199, 198, 209, 89, 13}, - {180, 164, 217, 255, 0}, - {185, 168, 182, 62, 3} - }, - { {1, 159, 5, 220, 10}, - {88, 51, 153, 104, 10}, - {83, 186, 15, 152, 0}, - {81, 105, 156, 193, 10} - }, - { {223, 138, 224, 53, 4}, - {170, 136, 218, 199, 12}, - {42, 192, 117, 31, 11}, - {62, 53, 177, 21, 5} - }, - { {206, 123, 160, 13, 5}, - {207, 166, 72, 135, 12}, - {171, 0, 93, 231, 3}, - {62, 17, 38, 95, 3} - }, - { {217, 125, 237, 88, 6}, - {115, 191, 196, 234, 12}, - {97, 171, 123, 233, 11}, - {53, 114, 63, 220, 14} - }, - { {181, 147, 30, 12, 6}, - {200, 123, 124, 82, 0}, - {99, 7, 140, 154, 13}, - {4, 163, 237, 225, 3} - }, - { {18, 139, 154, 110, 4}, - {8, 234, 94, 25, 9}, - {39, 101, 157, 20, 8}, - {153, 135, 165, 113, 0} - }, - { {242, 22, 60, 166, 3}, - {76, 25, 46, 179, 7}, - {198, 83, 198, 132, 15}, - {236, 215, 73, 131, 2} - }, - { {232, 10, 7, 115, 7}, - {22, 81, 234, 142, 9}, - {236, 238, 5, 1, 7}, - {151, 21, 120, 166, 8} - }, - { {122, 115, 30, 194, 4}, - {67, 79, 108, 153, 3}, - {36, 55, 140, 229, 14}, - {201, 147, 111, 44, 2} - }, - { {53, 218, 126, 240, 11}, - {228, 93, 191, 88, 14}, - {208, 247, 229, 186, 12}, - {113, 175, 219, 162, 7} - }, - { {153, 130, 253, 45, 1}, - {62, 169, 30, 86, 4}, - {139, 75, 244, 25, 9}, - {38, 167, 137, 87, 12} - }, - { {223, 169, 37, 94, 13}, - {159, 43, 209, 203, 13}, - {183, 170, 73, 95, 11}, - {189, 56, 189, 79, 9} - }, - { {165, 30, 214, 188, 15}, - {236, 241, 235, 114, 10}, - {243, 214, 183, 138, 5}, - {84, 237, 120, 243, 7} - }, - { {36, 8, 213, 209, 9}, - {180, 129, 161, 28, 10}, - {152, 186, 177, 2, 4}, - {83, 136, 88, 18, 13} - }, - { {181, 248, 233, 45, 6}, - {249, 188, 118, 70, 12}, - {107, 73, 113, 250, 13}, - {54, 38, 227, 217, 15} - }, - { {145, 54, 188, 78, 0}, - {73, 169, 12, 122, 5}, - {7, 35, 214, 200, 9}, - {165, 227, 9, 89, 2} - }, - { {174, 88, 224, 232, 5}, - {230, 164, 98, 11, 14}, - {161, 112, 113, 167, 5}, - {125, 4, 98, 86, 7} - }, - { {47, 128, 197, 170, 11}, - {182, 177, 51, 65, 3}, - {213, 90, 48, 31, 4}, - {200, 44, 200, 214, 13} - }, - { {218, 73, 123, 17, 9}, - {54, 78, 133, 151, 12}, - {152, 141, 233, 37, 11}, - {62, 154, 23, 38, 12} - }, - { {162, 246, 228, 83, 14}, - {97, 149, 249, 47, 5}, - {124, 162, 118, 244, 5}, - {175, 73, 250, 152, 6} - }, - { {33, 39, 109, 132, 12}, - {57, 3, 109, 96, 6}, - {50, 27, 110, 72, 4}, - {96, 107, 108, 9, 12} - }, - { {107, 121, 40, 104, 12}, - {67, 38, 103, 201, 12}, - {49, 97, 73, 237, 6}, - {57, 62, 102, 76, 2} - }, - { {157, 218, 93, 177, 13}, - {246, 13, 223, 86, 10}, - {184, 219, 165, 187, 9}, - {86, 175, 187, 6, 15} - }, - { {47, 207, 178, 181, 5}, - {142, 198, 250, 117, 14}, - {170, 212, 223, 63, 4}, - {122, 229, 246, 55, 1} - }, - { {175, 32, 71, 30, 8}, - {187, 97, 161, 67, 1}, - {23, 142, 32, 79, 5}, - {140, 40, 88, 109, 13} - }, - { {234, 199, 75, 58, 9}, - {54, 102, 191, 163, 1}, - {149, 205, 46, 53, 7}, - {140, 95, 214, 102, 12} - }, - { {204, 229, 29, 252, 14}, - {155, 55, 215, 186, 2}, - {115, 251, 138, 115, 3}, - {69, 222, 190, 205, 9} - }, - { {97, 48, 133, 50, 1}, - {85, 129, 162, 192, 1}, - {132, 202, 16, 200, 6}, - {128, 52, 88, 26, 10} - }, - { {180, 146, 25, 41, 1}, - {212, 40, 62, 22, 0}, - {137, 73, 132, 146, 13}, - {6, 135, 193, 66, 11} - }, - { {193, 207, 189, 157, 10}, - {24, 183, 157, 246, 14}, - {91, 155, 223, 56, 3}, - {118, 251, 158, 209, 8} - }, - { {8, 221, 26, 54, 6}, - {74, 86, 214, 48, 9}, - {102, 197, 139, 177, 0}, - {144, 198, 182, 165, 2} - }, - { {120, 67, 92, 168, 15}, - {38, 63, 111, 144, 2}, - {241, 83, 172, 33, 14}, - {64, 159, 111, 198, 4} - }, - { {32, 220, 186, 83, 14}, - {64, 212, 245, 60, 13}, - {124, 165, 211, 176, 4}, - {179, 202, 242, 176, 2} - }, - { {227, 132, 165, 236, 6}, - {24, 177, 114, 235, 6}, - {99, 122, 82, 28, 7}, - {109, 116, 232, 209, 8} - }, - { {131, 145, 171, 122, 13}, - {84, 226, 215, 75, 5}, - {181, 237, 88, 156, 1}, - {173, 46, 180, 114, 10} - }, - { {114, 38, 60, 80, 11}, - {5, 25, 173, 185, 4}, - {208, 163, 198, 68, 14}, - {41, 219, 89, 138, 0} - }, - { {242, 174, 11, 171, 12}, - {17, 104, 127, 167, 11}, - {61, 93, 7, 84, 15}, - {222, 95, 225, 104, 8} - }, - { {46, 136, 9, 214, 3}, - {158, 16, 180, 9, 11}, - {198, 185, 1, 23, 4}, - {217, 2, 208, 135, 9} - }, - { {183, 203, 246, 151, 12}, - {168, 207, 249, 87, 15}, - {62, 150, 253, 62, 13}, - {254, 169, 255, 49, 5} - }, - { {49, 251, 244, 57, 14}, - {97, 191, 251, 84, 12}, - {121, 194, 253, 248, 12}, - {50, 173, 255, 216, 6} - }, - { {142, 199, 82, 154, 6}, - {162, 118, 216, 51, 3}, - {101, 148, 174, 55, 1}, - {204, 193, 182, 228, 5} - }, - { {94, 235, 242, 10, 12}, - {163, 238, 89, 145, 13}, - {53, 4, 253, 119, 10}, - {184, 153, 167, 124, 5} - }, - { {227, 59, 129, 212, 12}, - {89, 130, 233, 203, 10}, - {50, 184, 29, 204, 7}, - {93, 57, 116, 25, 10} - }, - { {172, 124, 242, 222, 10}, - {235, 244, 161, 58, 15}, - {87, 180, 243, 227, 5}, - {245, 200, 82, 253, 7} - }, - { {78, 1, 1, 147, 2}, - {146, 18, 128, 133, 3}, - {76, 152, 8, 7, 2}, - {202, 16, 20, 132, 9} - }, - { {201, 144, 131, 96, 5}, - {86, 192, 82, 202, 0}, - {160, 108, 16, 153, 3}, - {5, 52, 160, 54, 10} - }, - { {245, 102, 105, 160, 13}, - {181, 12, 111, 226, 6}, - {176, 89, 102, 106, 15}, - {100, 127, 99, 10, 13} - }, - { {44, 3, 150, 212, 14}, - {138, 211, 233, 24, 2}, - {114, 182, 156, 3, 4}, - {65, 137, 124, 181, 1} - }, - { {118, 193, 117, 204, 7}, - {188, 63, 112, 153, 6}, - {227, 58, 232, 54, 14}, - {105, 144, 239, 195, 13} - }, - { {176, 251, 83, 107, 5}, - {117, 110, 122, 30, 9}, - {173, 108, 173, 240, 13}, - {151, 133, 231, 106, 14} - }, - { {135, 53, 206, 169, 8}, - {225, 227, 7, 103, 2}, - {25, 87, 58, 206, 1}, - {78, 110, 12, 120, 7} - }, - { {231, 139, 244, 106, 11}, - {164, 179, 59, 219, 13}, - {213, 98, 253, 30, 7}, - {189, 189, 204, 210, 5} - }, - { {185, 178, 1, 226, 1}, - {87, 8, 58, 74, 3}, - {132, 120, 4, 217, 13}, - {197, 37, 193, 14, 10} - }, - { {44, 230, 244, 199, 9}, - {175, 133, 57, 60, 7}, - {158, 50, 246, 115, 4}, - {227, 201, 202, 31, 5} - }, - { {240, 26, 58, 172, 4}, - {72, 104, 110, 146, 14}, - {35, 85, 197, 128, 15}, - {116, 151, 97, 97, 2} - }, - { {107, 29, 238, 143, 4}, - {106, 227, 100, 229, 15}, - {47, 23, 123, 141, 6}, - {250, 114, 108, 117, 6} - }, - { {10, 99, 89, 22, 11}, - {63, 22, 141, 17, 1}, - {214, 137, 172, 101, 0}, - {136, 139, 22, 143, 12} - }, - { {61, 80, 237, 142, 0}, - {250, 173, 36, 64, 7}, - {7, 27, 112, 171, 12}, - {224, 34, 75, 85, 15} - }, - { {12, 234, 137, 42, 4}, - {147, 164, 94, 0, 9}, - {37, 73, 21, 115, 0}, - {144, 7, 162, 92, 9} - }, - { {146, 159, 44, 154, 3}, - {68, 59, 156, 35, 15}, - {197, 147, 79, 148, 9}, - {252, 67, 157, 194, 2} - }, - { {144, 185, 171, 44, 8}, - {89, 234, 23, 2, 12}, - {19, 77, 89, 208, 9}, - {52, 14, 133, 121, 10} - }, - { {96, 223, 140, 227, 4}, - {64, 135, 126, 172, 11}, - {44, 115, 31, 176, 6}, - {211, 87, 238, 16, 2} - }, - { {211, 163, 99, 9, 11}, - {53, 122, 25, 199, 4}, - {217, 12, 108, 92, 11}, - {46, 57, 133, 234, 12} - }, - { {37, 61, 159, 195, 3}, - {213, 211, 36, 124, 11}, - {204, 63, 155, 202, 4}, - {211, 226, 76, 186, 11} - }, - { {48, 25, 30, 15, 13}, - {76, 107, 101, 20, 9}, - {191, 7, 137, 128, 12}, - {146, 138, 109, 99, 2} - }, - { {90, 151, 28, 16, 1}, - {70, 11, 156, 177, 0}, - {128, 131, 142, 149, 10}, - {8, 211, 157, 6, 2} - }, - { {42, 15, 107, 51, 10}, - {50, 82, 175, 37, 13}, - {92, 205, 111, 5, 4}, - {186, 79, 84, 164, 12} - }, - { {106, 117, 209, 236, 0}, - {123, 166, 34, 185, 2}, - {3, 120, 186, 229, 6}, - {73, 212, 70, 93, 14} - }, - { {30, 157, 187, 139, 1}, - {214, 234, 20, 53, 15}, - {141, 29, 219, 151, 8}, - {250, 194, 133, 118, 11} - }, - { {47, 58, 225, 220, 9}, - {255, 160, 169, 73, 14}, - {147, 184, 117, 207, 4}, - {121, 41, 80, 95, 15} - }, - { {99, 208, 151, 52, 7}, - {92, 213, 242, 209, 0}, - {226, 206, 144, 188, 6}, - {8, 180, 250, 179, 10} - }, - { {216, 157, 137, 67, 7}, - {86, 154, 84, 174, 9}, - {236, 41, 27, 145, 11}, - {151, 82, 165, 150, 10} - }, - { {131, 189, 136, 80, 11}, - {69, 146, 149, 107, 8}, - {208, 161, 27, 220, 1}, - {29, 106, 148, 154, 2} - }, - { {34, 78, 125, 138, 14}, - {48, 53, 109, 49, 15}, - {117, 27, 231, 36, 4}, - {248, 203, 106, 192, 12} - }, - { {121, 75, 63, 158, 10}, - {26, 127, 173, 208, 15}, - {87, 159, 205, 41, 14}, - {240, 187, 95, 229, 8} - }, - { {141, 51, 167, 110, 15}, - {223, 243, 75, 74, 5}, - {247, 110, 92, 203, 1}, - {165, 45, 44, 255, 11} - }, - { {33, 133, 188, 205, 7}, - {12, 179, 116, 124, 6}, - {235, 51, 218, 24, 4}, - {99, 226, 236, 211, 0} - }, - { {240, 218, 227, 80, 3}, - {116, 220, 184, 138, 12}, - {192, 172, 117, 176, 15}, - {53, 17, 211, 178, 14} - }, - { {204, 223, 42, 42, 8}, - {194, 102, 31, 162, 13}, - {21, 69, 79, 179, 3}, - {180, 95, 134, 100, 3} - }, - { {56, 130, 84, 157, 1}, - {46, 41, 184, 20, 2}, - {139, 146, 164, 17, 12}, - {66, 129, 217, 71, 4} - }, - { {110, 45, 44, 91, 14}, - {131, 51, 229, 173, 13}, - {125, 163, 75, 71, 6}, - {187, 90, 124, 204, 1} - }, - { {122, 43, 200, 47, 2}, - {43, 186, 46, 133, 9}, - {79, 65, 61, 69, 14}, - {154, 23, 69, 221, 4} - }, - { {87, 219, 131, 112, 8}, - {208, 206, 155, 201, 8}, - {16, 236, 29, 190, 10}, - {25, 61, 151, 48, 11} - }, - { {201, 217, 206, 10, 6}, - {98, 247, 84, 194, 9}, - {101, 7, 57, 185, 3}, - {148, 50, 174, 244, 6} - }, - { {140, 81, 7, 168, 12}, - {210, 103, 67, 2, 2}, - {49, 94, 8, 163, 1}, - {68, 12, 46, 100, 11} - }, - { {189, 143, 171, 242, 11}, - {150, 218, 191, 106, 15}, - {212, 253, 95, 27, 13}, - {245, 111, 213, 182, 9} - }, - { {100, 133, 26, 10, 13}, - {132, 98, 117, 176, 1}, - {181, 5, 138, 18, 6}, - {128, 218, 228, 98, 1} - }, - { {220, 109, 58, 176, 4}, - {131, 78, 198, 178, 14}, - {32, 213, 203, 99, 11}, - {116, 214, 55, 44, 1} - }, - { {231, 251, 25, 168, 3}, - {213, 54, 62, 211, 10}, - {193, 89, 141, 254, 7}, - {92, 183, 198, 202, 11} - }, - { {177, 204, 84, 80, 5}, - {36, 13, 240, 122, 8}, - {160, 162, 163, 56, 13}, - {21, 224, 251, 2, 4} - }, - { {97, 110, 245, 148, 7}, - {61, 149, 232, 240, 14}, - {226, 154, 247, 104, 6}, - {112, 241, 122, 155, 12} - }, - { {147, 83, 11, 252, 1}, - {92, 110, 142, 75, 2}, - {131, 253, 12, 172, 9}, - {77, 39, 23, 99, 10} - }, - { {27, 41, 1, 82, 8}, - {19, 10, 129, 73, 9}, - {20, 168, 9, 77, 8}, - {153, 40, 21, 12, 8} - }, - { {197, 245, 7, 104, 1}, - {213, 103, 18, 234, 0}, - {129, 110, 10, 250, 3}, - {5, 116, 142, 106, 11} - }, - { {52, 186, 247, 153, 2}, - {241, 249, 184, 20, 14}, - {73, 158, 245, 210, 12}, - {114, 129, 217, 248, 15} - }, - { {169, 176, 189, 187, 13}, - {87, 161, 247, 86, 7}, - {189, 219, 208, 217, 5}, - {230, 174, 248, 94, 10} - }, - { {149, 57, 193, 12, 5}, - {253, 170, 64, 66, 8}, - {163, 8, 57, 202, 9}, - {20, 32, 37, 91, 15} - }, - { {50, 223, 204, 191, 2}, - {104, 191, 190, 37, 11}, - {79, 211, 63, 180, 12}, - {218, 71, 223, 209, 6} - }, - { {237, 234, 172, 111, 7}, - {143, 181, 126, 206, 13}, - {239, 99, 85, 123, 7}, - {183, 55, 234, 223, 1} - }, - { {77, 86, 15, 172, 10}, - {218, 117, 15, 224, 2}, - {83, 95, 6, 171, 2}, - {64, 127, 10, 229, 11} - }, - { {116, 172, 190, 43, 0}, - {129, 233, 54, 180, 13}, - {13, 71, 211, 82, 14}, - {178, 214, 201, 120, 1} - }, - { {35, 182, 120, 236, 5}, - {109, 32, 126, 121, 6}, - {163, 113, 230, 220, 4}, - {105, 231, 224, 75, 6} - }, - { {232, 210, 137, 53, 1}, - {94, 132, 190, 134, 0}, - {138, 201, 20, 177, 7}, - {6, 23, 210, 23, 10} - }, - { {235, 150, 185, 93, 6}, - {90, 176, 252, 255, 4}, - {107, 169, 214, 157, 7}, - {47, 243, 240, 213, 10} - }, - { {85, 145, 91, 105, 0}, - {240, 106, 22, 220, 0}, - {9, 109, 168, 154, 10}, - {3, 182, 133, 96, 15} - }, - { {40, 186, 189, 218, 6}, - {83, 177, 252, 24, 15}, - {101, 187, 213, 209, 4}, - {241, 131, 248, 220, 10} - }, - { {35, 163, 75, 130, 11}, - {53, 82, 61, 65, 3}, - {212, 29, 44, 92, 4}, - {200, 43, 196, 170, 12} - }, - { {193, 172, 20, 84, 10}, - {9, 17, 145, 250, 8}, - {82, 162, 131, 88, 3}, - {21, 248, 152, 137, 0} - }, - { {100, 182, 175, 131, 2}, - {209, 209, 60, 164, 7}, - {76, 31, 86, 210, 6}, - {226, 83, 200, 184, 11} - }, - { {82, 25, 155, 54, 1}, - {92, 202, 134, 145, 9}, - {134, 205, 153, 132, 10}, - {152, 150, 21, 51, 10} - }, - { {99, 183, 61, 54, 4}, - {89, 3, 254, 241, 5}, - {38, 203, 206, 220, 6}, - {168, 247, 252, 9, 10} - }, - { {192, 85, 112, 85, 8}, - {104, 6, 129, 190, 4}, - {26, 160, 234, 160, 3}, - {39, 216, 22, 1, 6} - }, - { {52, 181, 171, 169, 13}, - {213, 234, 119, 36, 6}, - {185, 93, 90, 210, 12}, - {98, 78, 229, 122, 11} - }, - { {4, 214, 173, 116, 7}, - {220, 149, 222, 40, 4}, - {226, 235, 86, 178, 0}, - {33, 71, 186, 147, 11} - }, - { {58, 185, 185, 47, 15}, - {95, 186, 119, 21, 13}, - {255, 73, 217, 213, 12}, - {186, 142, 229, 223, 10} - }, - { {30, 193, 204, 115, 3}, - {166, 159, 150, 13, 1}, - {204, 227, 56, 55, 8}, - {139, 6, 159, 150, 5} - }, - { {227, 95, 151, 12, 12}, - {88, 231, 105, 243, 8}, - {51, 14, 159, 172, 7}, - {28, 249, 110, 113, 10} - }, - { {82, 233, 202, 244, 7}, - {45, 222, 214, 137, 10}, - {226, 245, 57, 116, 10}, - {89, 22, 183, 187, 4} - }, - { {171, 99, 139, 22, 6}, - {27, 214, 236, 67, 1}, - {102, 141, 28, 109, 5}, - {140, 35, 118, 189, 8} - }, - { {138, 229, 208, 83, 7}, - {39, 150, 208, 63, 1}, - {236, 160, 186, 117, 1}, - {143, 192, 182, 158, 4} - }, - { {103, 173, 81, 43, 1}, - {181, 34, 50, 245, 9}, - {141, 72, 171, 94, 6}, - {154, 244, 196, 74, 13} - }, - { {179, 24, 122, 4, 11}, - {108, 88, 37, 83, 12}, - {210, 5, 225, 140, 13}, - {60, 170, 65, 163, 6} - }, - { {60, 198, 137, 195, 8}, - {146, 140, 61, 44, 3}, - {28, 57, 22, 51, 12}, - {195, 75, 195, 20, 9} - }, - { {250, 116, 11, 175, 7}, - {95, 124, 102, 167, 3}, - {239, 93, 2, 229, 15}, - {206, 86, 99, 239, 10} - }, - { {4, 250, 221, 72, 11}, - {245, 181, 29, 24, 8}, - {209, 43, 181, 242, 0}, - {17, 139, 138, 218, 15} - }, - { {153, 138, 132, 196, 12}, - {10, 137, 89, 74, 10}, - {50, 50, 21, 25, 9}, - {85, 41, 169, 21, 0} - }, - { {63, 252, 218, 241, 1}, - {231, 204, 182, 125, 10}, - {136, 245, 179, 255, 12}, - {91, 230, 211, 62, 7} - }, - { {148, 250, 34, 140, 9}, - {205, 108, 25, 2, 14}, - {147, 20, 69, 242, 9}, - {116, 9, 131, 107, 3} - }, - { {228, 237, 60, 145, 13}, - {133, 7, 245, 182, 14}, - {184, 147, 203, 114, 7}, - {118, 218, 254, 10, 1} - }, - { {3, 55, 138, 20, 12}, - {73, 194, 205, 97, 0}, - {50, 133, 30, 204, 0}, - {8, 107, 52, 57, 2} - }, - { {216, 27, 34, 208, 1}, - {70, 74, 136, 138, 14}, - {128, 180, 77, 129, 11}, - {117, 17, 21, 38, 2} - }, - { {25, 91, 18, 85, 10}, - {74, 94, 137, 92, 8}, - {90, 164, 141, 169, 8}, - {19, 169, 23, 165, 2} - }, - { {33, 72, 120, 182, 2}, - {40, 20, 166, 80, 15}, - {70, 209, 225, 40, 4}, - {240, 166, 82, 129, 4} - }, - { {40, 93, 236, 19, 2}, - {98, 151, 164, 36, 13}, - {76, 131, 123, 161, 4}, - {178, 66, 94, 148, 6} - }, - { {123, 100, 52, 77, 7}, - {15, 61, 96, 253, 4}, - {235, 34, 194, 109, 14}, - {43, 240, 107, 207, 0} - }, - { {98, 75, 151, 138, 7}, - {20, 247, 104, 145, 11}, - {229, 30, 157, 36, 6}, - {216, 145, 110, 242, 8} - }, - { {103, 119, 188, 11, 1}, - {197, 167, 44, 245, 5}, - {141, 3, 222, 238, 6}, - {170, 243, 78, 90, 3} - }, - { {144, 144, 113, 245, 10}, - {120, 24, 147, 30, 6}, - {90, 248, 224, 144, 9}, - {103, 140, 145, 129, 14} - }, - { {37, 206, 233, 123, 13}, - {180, 164, 255, 108, 13}, - {189, 233, 119, 58, 4}, - {179, 111, 242, 82, 13} - }, - { {253, 83, 136, 111, 13}, - {206, 174, 111, 206, 1}, - {191, 97, 28, 171, 15}, - {135, 63, 103, 87, 3} - }, - { {231, 105, 53, 36, 11}, - {157, 23, 35, 211, 12}, - {210, 74, 201, 110, 7}, - {60, 188, 78, 139, 9} - }, - { {24, 201, 137, 127, 9}, - {30, 174, 151, 12, 9}, - {159, 233, 25, 49, 8}, - {147, 14, 151, 87, 8} - }, - { {101, 96, 64, 176, 10}, - {161, 20, 163, 192, 2}, - {80, 208, 32, 106, 6}, - {64, 60, 82, 136, 5} - }, - { {56, 46, 157, 194, 13}, - {23, 137, 109, 56, 11}, - {180, 59, 151, 65, 12}, - {209, 203, 105, 30, 8} - }, - { {205, 242, 177, 37, 13}, - {223, 132, 91, 214, 4}, - {186, 72, 212, 251, 3}, - {38, 189, 162, 31, 11} - }, - { {9, 78, 179, 61, 6}, - {26, 244, 202, 116, 12}, - {107, 204, 215, 41, 0}, - {50, 229, 50, 245, 8} - }, - { {57, 223, 214, 61, 1}, - {110, 239, 186, 116, 8}, - {139, 198, 191, 185, 12}, - {18, 229, 223, 119, 6} - }, - { {249, 54, 192, 90, 7}, - {103, 184, 232, 234, 1}, - {229, 160, 54, 201, 15}, - {133, 113, 113, 222, 6} - }, - { {119, 243, 69, 1, 5}, - {245, 15, 120, 197, 0}, - {168, 10, 44, 254, 14}, - {10, 49, 239, 10, 15} - }, - { {229, 170, 108, 152, 3}, - {165, 49, 188, 194, 14}, - {193, 147, 101, 90, 7}, - {116, 51, 216, 202, 5} - }, - { {176, 232, 167, 19, 14}, - {17, 221, 241, 6, 13}, - {124, 142, 81, 112, 13}, - {182, 8, 251, 184, 8} - }, - { {221, 219, 120, 40, 6}, - {226, 62, 94, 210, 12}, - {97, 65, 237, 187, 11}, - {52, 183, 167, 196, 7} - }, - { {59, 9, 157, 107, 2}, - {18, 187, 38, 93, 9}, - {77, 107, 153, 13, 12}, - {155, 166, 77, 212, 8} - }, - { {64, 234, 217, 35, 3}, - {53, 148, 30, 148, 9}, - {204, 73, 181, 112, 2}, - {146, 151, 130, 154, 12} - }, - { {26, 247, 252, 44, 4}, - {107, 175, 94, 49, 4}, - {35, 67, 254, 245, 8}, - {40, 199, 175, 93, 6} - }, - { {60, 154, 211, 10, 11}, - {246, 248, 57, 16, 9}, - {213, 12, 181, 147, 12}, - {144, 137, 193, 246, 15} - }, - { {179, 6, 81, 36, 2}, - {56, 24, 42, 115, 0}, - {66, 72, 166, 12, 13}, - {12, 229, 65, 129, 12} - }, - { {50, 189, 243, 128, 9}, - {117, 202, 49, 49, 14}, - {144, 28, 251, 212, 12}, - {120, 200, 197, 58, 14} - }, - { {108, 225, 50, 82, 6}, - {131, 86, 240, 152, 5}, - {100, 164, 200, 115, 6}, - {161, 144, 246, 172, 1} - }, - { {87, 93, 59, 77, 8}, - {216, 110, 5, 253, 12}, - {27, 45, 203, 174, 10}, - {59, 250, 7, 97, 11} - }, - { {50, 250, 120, 150, 11}, - {109, 28, 189, 17, 15}, - {214, 145, 229, 244, 12}, - {248, 139, 211, 139, 6} - }, - { {201, 37, 74, 207, 11}, - {47, 114, 5, 238, 3}, - {223, 53, 42, 73, 3}, - {199, 122, 4, 239, 4} - }, - { {91, 227, 88, 153, 8}, - {35, 46, 157, 213, 2}, - {25, 145, 172, 125, 10}, - {74, 187, 151, 76, 4} - }, - { {162, 249, 225, 35, 2}, - {113, 150, 50, 7, 13}, - {76, 72, 121, 244, 5}, - {190, 4, 198, 152, 14} - }, - { {119, 181, 82, 205, 9}, - {237, 106, 49, 253, 2}, - {155, 52, 170, 222, 14}, - {75, 248, 197, 107, 7} - }, - { {176, 219, 205, 212, 10}, - {120, 159, 189, 10, 10}, - {82, 187, 61, 176, 13}, - {85, 11, 223, 145, 14} - }, - { {203, 147, 21, 157, 14}, - {90, 51, 217, 215, 2}, - {123, 154, 140, 157, 3}, - {78, 185, 188, 197, 10} - }, - { {126, 39, 103, 62, 11}, - {191, 123, 171, 161, 5}, - {215, 206, 110, 71, 14}, - {168, 93, 93, 239, 13} - }, - { {27, 68, 157, 3, 7}, - {22, 157, 68, 117, 1}, - {236, 11, 146, 45, 8}, - {138, 226, 43, 150, 8} - }, - { {214, 213, 57, 224, 1}, - {212, 14, 22, 187, 6}, - {128, 121, 202, 182, 11}, - {109, 214, 135, 2, 11} - }, - { {153, 17, 59, 93, 5}, - {94, 106, 196, 94, 4}, - {171, 173, 200, 137, 9}, - {39, 162, 53, 103, 10} - }, - { {237, 201, 222, 175, 0}, - {170, 231, 54, 214, 11}, - {15, 87, 185, 59, 7}, - {214, 182, 206, 117, 5} - }, - { {152, 79, 114, 58, 0}, - {34, 110, 138, 50, 13}, - {5, 196, 239, 33, 9}, - {180, 197, 23, 100, 4} - }, - { {146, 177, 194, 94, 11}, - {109, 250, 145, 11, 1}, - {215, 164, 56, 212, 9}, - {141, 8, 149, 251, 6} - }, - { {233, 83, 55, 170, 15}, - {86, 119, 107, 210, 7}, - {245, 94, 204, 169, 7}, - {228, 189, 110, 230, 10} - }, - { {184, 249, 145, 224, 11}, - {87, 158, 51, 26, 10}, - {208, 120, 153, 241, 13}, - {85, 140, 199, 158, 10} - }, - { {54, 190, 41, 6, 4}, - {217, 8, 124, 33, 13}, - {38, 9, 71, 214, 12}, - {184, 67, 225, 9, 11} - }, - { {109, 88, 75, 223, 15}, - {254, 116, 229, 204, 11}, - {255, 189, 33, 171, 6}, - {211, 58, 114, 231, 15} - }, - { {124, 73, 255, 32, 11}, - {182, 223, 39, 144, 12}, - {208, 79, 249, 35, 14}, - {48, 158, 79, 182, 13} - }, - { {204, 4, 237, 38, 9}, - {190, 129, 7, 162, 5}, - {150, 75, 114, 3, 3}, - {164, 94, 8, 23, 13} - }, - { {126, 191, 195, 88, 12}, - {243, 234, 249, 169, 8}, - {49, 172, 63, 215, 14}, - {25, 89, 245, 124, 15} - }, - { {35, 71, 74, 52, 11}, - {44, 86, 175, 97, 0}, - {210, 197, 46, 44, 4}, - {8, 111, 86, 163, 4} - }, - { {247, 2, 101, 153, 14}, - {176, 57, 233, 199, 6}, - {121, 154, 100, 14, 15}, - {110, 57, 121, 192, 13} - }, - { {183, 134, 11, 177, 9}, - {148, 72, 191, 103, 2}, - {152, 221, 6, 30, 13}, - {78, 111, 209, 34, 9} - }, - { {29, 237, 84, 211, 10}, - {163, 31, 145, 124, 11}, - {92, 178, 171, 123, 8}, - {211, 232, 159, 140, 5} - }, - { {19, 129, 28, 244, 14}, - {8, 27, 215, 89, 2}, - {114, 243, 136, 28, 8}, - {73, 174, 189, 129, 0} - }, - { {38, 136, 183, 166, 7}, - {156, 209, 114, 17, 15}, - {230, 94, 209, 22, 4}, - {248, 132, 232, 179, 9} - }, - { {218, 189, 5, 242, 12}, - {83, 11, 211, 171, 11}, - {52, 250, 11, 213, 11}, - {221, 92, 189, 12, 10} - }, - { {179, 196, 25, 242, 6}, - {16, 28, 246, 123, 3}, - {100, 249, 130, 60, 13}, - {205, 230, 243, 128, 8} - }, - { {3, 88, 126, 158, 12}, - {104, 101, 197, 81, 15}, - {55, 151, 225, 172, 0}, - {248, 170, 58, 97, 6} - }, - { {138, 226, 81, 223, 4}, - {59, 36, 216, 31, 3}, - {47, 184, 164, 117, 1}, - {207, 129, 178, 77, 12} - }, - { {116, 44, 226, 207, 6}, - {169, 248, 96, 172, 15}, - {111, 52, 115, 66, 14}, - {243, 80, 97, 249, 5} - }, - { {80, 87, 235, 180, 4}, - {120, 206, 206, 160, 6}, - {34, 221, 126, 160, 10}, - {96, 87, 55, 49, 14} - }, - { {234, 122, 109, 152, 13}, - {119, 37, 237, 131, 14}, - {177, 155, 101, 229, 7}, - {124, 27, 122, 78, 14} - }, - { {81, 124, 23, 242, 2}, - {81, 93, 130, 248, 11}, - {68, 254, 131, 232, 10}, - {209, 244, 27, 168, 10} - }, - { {116, 206, 76, 238, 0}, - {168, 45, 62, 168, 11}, - {7, 115, 39, 50, 14}, - {209, 87, 203, 65, 5} - }, - { {235, 112, 71, 178, 6}, - {115, 85, 226, 195, 3}, - {100, 222, 32, 237, 7}, - {204, 52, 122, 172, 14} - }, - { {44, 21, 121, 54, 0}, - {250, 2, 166, 48, 5}, - {6, 201, 234, 131, 4}, - {160, 198, 84, 5, 15} - }, - { {10, 102, 96, 115, 1}, - {39, 4, 138, 45, 5}, - {140, 224, 102, 101, 0}, - {171, 69, 18, 14, 4} - }, - { {15, 250, 22, 84, 3}, - {207, 85, 152, 89, 8}, - {194, 166, 133, 255, 0}, - {25, 161, 154, 175, 3} - }, - { {248, 13, 152, 242, 6}, - {2, 154, 230, 186, 11}, - {100, 241, 155, 1, 15}, - {213, 214, 117, 148, 0} - }, - { {17, 81, 213, 137, 2}, - {112, 191, 0, 84, 2}, - {73, 26, 184, 168, 8}, - {66, 160, 15, 208, 14} - }, - { {90, 127, 72, 72, 2}, - {99, 62, 12, 169, 8}, - {65, 33, 47, 229, 10}, - {25, 83, 7, 204, 6} - }, - { {220, 246, 137, 159, 6}, - {219, 188, 220, 166, 3}, - {111, 153, 22, 243, 11}, - {198, 83, 179, 221, 11} - }, - { {142, 116, 239, 41, 6}, - {243, 245, 70, 39, 4}, - {105, 79, 114, 231, 1}, - {46, 70, 42, 252, 15} - }, - { {122, 205, 165, 235, 5}, - {22, 175, 114, 173, 15}, - {173, 122, 91, 53, 14}, - {251, 84, 239, 86, 8} - }, - { {73, 74, 158, 70, 15}, - {14, 213, 77, 216, 9}, - {246, 39, 149, 41, 2}, - {145, 187, 42, 183, 0} - }, - { {92, 188, 59, 49, 3}, - {215, 88, 150, 180, 12}, - {200, 205, 195, 211, 10}, - {50, 214, 145, 174, 11} - }, - { {24, 172, 214, 61, 15}, - {47, 249, 211, 52, 8}, - {251, 198, 179, 81, 8}, - {18, 204, 185, 255, 4} - }, - { {128, 152, 198, 222, 6}, - {104, 241, 208, 10, 11}, - {103, 182, 49, 144, 1}, - {213, 0, 184, 241, 6} - }, - { {171, 158, 93, 173, 10}, - {122, 49, 63, 119, 10}, - {91, 91, 167, 157, 5}, - {94, 239, 200, 197, 14} - }, - { {187, 215, 181, 242, 15}, - {86, 159, 251, 123, 7}, - {244, 250, 222, 189, 13}, - {237, 237, 255, 150, 10} - }, - { {231, 64, 19, 227, 5}, - {148, 68, 98, 223, 3}, - {172, 124, 128, 46, 7}, - {207, 180, 98, 34, 9} - }, - { {185, 180, 142, 161, 12}, - {67, 201, 119, 102, 2}, - {56, 87, 18, 217, 13}, - {70, 110, 233, 60, 2} - }, - { {45, 174, 203, 210, 6}, - {179, 208, 252, 104, 11}, - {100, 189, 55, 91, 4}, - {209, 99, 240, 188, 13} - }, - { {14, 251, 136, 89, 3}, - {199, 182, 156, 13, 8}, - {201, 161, 29, 247, 0}, - {27, 3, 150, 222, 3} - }, - { {140, 253, 170, 193, 1}, - {199, 198, 20, 46, 14}, - {136, 53, 91, 243, 1}, - {119, 66, 134, 62, 3} - }, - { {80, 221, 255, 96, 6}, - {112, 223, 86, 184, 12}, - {96, 111, 251, 176, 10}, - {49, 214, 175, 176, 14} - }, - { {171, 67, 201, 91, 13}, - {54, 166, 237, 79, 1}, - {189, 169, 60, 45, 5}, - {143, 43, 118, 86, 12} - }, - { {80, 242, 159, 163, 14}, - {81, 221, 95, 148, 3}, - {124, 95, 148, 240, 10}, - {194, 159, 171, 184, 10} - }, - { {128, 166, 71, 246, 14}, - {57, 81, 219, 42, 3}, - {118, 254, 38, 80, 1}, - {197, 77, 184, 169, 12} - }, - { {60, 168, 157, 27, 10}, - {147, 185, 181, 20, 9}, - {93, 139, 145, 83, 12}, - {146, 138, 217, 220, 9} - }, - { {24, 77, 221, 97, 1}, - {54, 143, 6, 60, 8}, - {136, 107, 187, 33, 8}, - {19, 198, 15, 22, 12} - }, - { {83, 127, 71, 115, 5}, - {117, 79, 202, 237, 9}, - {172, 238, 47, 236, 10}, - {155, 117, 63, 42, 14} - }, - { {164, 149, 152, 181, 4}, - {200, 130, 246, 54, 2}, - {42, 209, 154, 146, 5}, - {70, 198, 244, 17, 3} - }, - { {58, 161, 233, 220, 1}, - {63, 170, 180, 9, 6}, - {131, 185, 120, 85, 12}, - {105, 2, 213, 95, 12} - }, - { {72, 193, 6, 108, 11}, - {14, 119, 19, 136, 0}, - {211, 102, 8, 49, 2}, - {1, 28, 142, 231, 0} - }, - { {227, 219, 6, 53, 1}, - {76, 71, 186, 199, 8}, - {138, 198, 13, 188, 7}, - {30, 53, 222, 35, 2} - }, - { {26, 241, 58, 17, 0}, - {67, 78, 148, 21, 4}, - {8, 133, 200, 245, 8}, - {42, 130, 151, 44, 2} - }, - { {137, 31, 189, 213, 1}, - {94, 131, 140, 126, 14}, - {138, 187, 223, 137, 1}, - {119, 227, 28, 23, 10} - }, - { {142, 68, 6, 133, 7}, - {142, 85, 64, 39, 2}, - {234, 22, 2, 39, 1}, - {78, 64, 42, 167, 1} - }, - { {135, 127, 42, 107, 5}, - {197, 102, 78, 111, 13}, - {173, 101, 79, 238, 1}, - {191, 103, 38, 106, 3} - }, - { {122, 152, 134, 35, 6}, - {66, 217, 114, 133, 9}, - {108, 70, 17, 149, 14}, - {154, 20, 233, 180, 2} - }, - { {228, 197, 141, 119, 10}, - {152, 151, 183, 174, 1}, - {94, 235, 26, 50, 7}, - {135, 94, 222, 145, 9} - }, - { {70, 156, 46, 177, 8}, - {192, 65, 151, 165, 14}, - {24, 215, 67, 150, 2}, - {122, 94, 152, 32, 3} - }, - { {165, 170, 62, 63, 8}, - {137, 97, 191, 86, 13}, - {31, 199, 197, 90, 5}, - {182, 175, 216, 105, 1} - }, - { {14, 105, 46, 93, 5}, - {143, 103, 196, 13, 12}, - {171, 167, 73, 103, 0}, - {59, 2, 62, 111, 1} - }, - { {6, 57, 165, 147, 9}, - {213, 131, 129, 5, 15}, - {156, 154, 89, 198, 0}, - {250, 8, 28, 26, 11} - }, - { {96, 63, 93, 167, 6}, - {121, 19, 110, 180, 11}, - {110, 91, 175, 192, 6}, - {210, 215, 108, 137, 14} - }, - { {72, 219, 238, 150, 9}, - {110, 199, 157, 128, 15}, - {150, 151, 125, 177, 2}, - {240, 27, 158, 55, 6} - }, - { {95, 215, 109, 233, 5}, - {246, 47, 94, 237, 6}, - {169, 123, 110, 191, 10}, - {107, 119, 175, 70, 15} - }, - { {101, 185, 180, 188, 6}, - {201, 179, 242, 208, 14}, - {99, 210, 217, 218, 6}, - {112, 180, 252, 217, 3} - }, - { {6, 179, 0, 213, 15}, - {205, 18, 217, 13, 2}, - {250, 176, 12, 214, 0}, - {75, 9, 180, 139, 3} - }, - { {76, 98, 251, 222, 11}, - {191, 244, 141, 152, 7}, - {215, 189, 244, 99, 2}, - {225, 155, 18, 255, 13} - }, - { {154, 177, 225, 193, 15}, - {119, 154, 81, 15, 6}, - {248, 56, 120, 213, 9}, - {111, 8, 165, 158, 14} - }, - { {116, 98, 52, 56, 13}, - {133, 45, 235, 144, 4}, - {177, 194, 196, 98, 14}, - {32, 157, 123, 74, 1} - }, - { {229, 34, 138, 114, 8}, - {129, 192, 175, 202, 1}, - {20, 229, 20, 74, 7}, - {133, 63, 80, 56, 1} - }, - { {20, 217, 9, 82, 15}, - {212, 30, 213, 8, 9}, - {244, 169, 9, 178, 8}, - {145, 10, 183, 130, 11} - }, - { {218, 24, 89, 233, 7}, - {118, 56, 70, 159, 10}, - {233, 121, 161, 133, 11}, - {95, 150, 33, 198, 14} - }, - { {38, 80, 144, 16, 9}, - {196, 132, 161, 17, 0}, - {144, 128, 144, 166, 4}, - {8, 136, 82, 18, 3} - }, - { {25, 235, 51, 121, 9}, - {23, 110, 155, 92, 12}, - {153, 236, 205, 121, 8}, - {51, 173, 151, 110, 8} - }, - { {105, 80, 30, 18, 12}, - {66, 69, 229, 208, 1}, - {52, 135, 128, 169, 6}, - {128, 186, 122, 36, 2} - }, - { {150, 139, 94, 59, 15}, - {164, 123, 223, 23, 9}, - {253, 199, 173, 22, 9}, - {158, 143, 189, 226, 5} - }, - { {218, 116, 48, 6, 5}, - {79, 12, 64, 179, 5}, - {166, 0, 194, 229, 11}, - {172, 208, 35, 15, 2} - }, - { {25, 179, 22, 144, 13}, - {71, 75, 217, 80, 2}, - {176, 150, 140, 217, 8}, - {64, 169, 189, 46, 2} - }, - { {25, 3, 122, 37, 8}, - {42, 74, 15, 84, 4}, - {26, 69, 236, 9, 8}, - {34, 175, 5, 37, 4} - }, - { {45, 131, 24, 137, 9}, - {134, 34, 61, 84, 2}, - {153, 17, 140, 27, 4}, - {66, 171, 196, 70, 1} - }, - { {90, 179, 165, 245, 1}, - {95, 139, 154, 141, 6}, - {138, 250, 92, 213, 10}, - {107, 21, 157, 31, 10} - }, - { {122, 166, 126, 219, 8}, - {35, 105, 189, 189, 7}, - {29, 183, 230, 85, 14}, - {235, 219, 217, 108, 4} - }, - { {74, 39, 236, 111, 9}, - {47, 163, 15, 173, 5}, - {159, 99, 126, 69, 2}, - {171, 95, 12, 95, 4} - }, - { {199, 32, 161, 106, 9}, - {149, 160, 3, 203, 5}, - {149, 104, 80, 78, 3}, - {173, 60, 0, 90, 9} - }, - { {70, 101, 77, 162, 0}, - {177, 7, 6, 161, 3}, - {4, 91, 42, 102, 2}, - {200, 86, 14, 8, 13} - }, - { {69, 170, 40, 84, 15}, - {141, 16, 221, 200, 12}, - {242, 161, 69, 90, 2}, - {49, 59, 176, 139, 1} - }, - { {174, 121, 83, 131, 6}, - {243, 86, 96, 23, 11}, - {108, 28, 169, 231, 5}, - {222, 128, 102, 172, 15} - }, - { {156, 98, 82, 80, 12}, - {163, 76, 201, 26, 0}, - {48, 164, 164, 99, 9}, - {5, 137, 51, 44, 5} - }, - { {12, 88, 52, 54, 3}, - {206, 21, 130, 16, 13}, - {198, 194, 193, 163, 0}, - {176, 132, 26, 135, 3} - }, - { {74, 45, 0, 174, 1}, - {15, 34, 2, 161, 11}, - {135, 80, 11, 69, 2}, - {216, 84, 4, 79, 0} - }, - { {116, 221, 28, 199, 10}, - {200, 31, 53, 188, 11}, - {94, 51, 139, 178, 14}, - {211, 218, 207, 129, 3} - }, - { {255, 184, 139, 185, 11}, - {215, 248, 183, 199, 10}, - {217, 221, 17, 223, 15}, - {94, 62, 209, 254, 11} - }, - { {72, 11, 173, 35, 1}, - {22, 131, 14, 132, 13}, - {140, 75, 93, 1, 2}, - {178, 23, 12, 22, 8} - }, - { {7, 41, 136, 152, 1}, - {133, 162, 132, 65, 10}, - {129, 145, 25, 78, 0}, - {88, 34, 20, 90, 1} - }, - { {230, 29, 184, 139, 11}, - {196, 178, 37, 183, 15}, - {221, 17, 219, 134, 7}, - {254, 218, 68, 210, 3} - }, - { {115, 138, 131, 230, 3}, - {28, 216, 58, 201, 11}, - {198, 124, 21, 28, 14}, - {217, 53, 193, 179, 8} - }, - { {39, 0, 88, 211, 10}, - {160, 16, 165, 93, 3}, - {92, 177, 160, 14, 4}, - {203, 170, 80, 128, 5} - }, - { {99, 133, 237, 25, 0}, - {48, 163, 180, 229, 4}, - {9, 139, 122, 28, 6}, - {42, 114, 220, 80, 12} - }, - { {43, 58, 207, 150, 12}, - {123, 193, 237, 65, 11}, - {54, 159, 53, 205, 4}, - {216, 43, 120, 61, 14} - }, - { {219, 208, 152, 69, 3}, - {78, 156, 20, 223, 0}, - {202, 33, 144, 189, 11}, - {15, 178, 131, 151, 2} - }, - { {157, 205, 210, 135, 6}, - {170, 222, 80, 118, 11}, - {110, 20, 187, 59, 9}, - {214, 224, 167, 181, 5} - }, - { {49, 244, 150, 171, 1}, - {69, 237, 50, 116, 3}, - {141, 86, 146, 248, 12}, - {194, 228, 203, 122, 2} - }, - { {31, 47, 77, 37, 3}, - {191, 27, 14, 101, 8}, - {202, 75, 47, 79, 8}, - {26, 103, 13, 143, 13} - }, - { {238, 22, 15, 225, 14}, - {210, 81, 111, 175, 2}, - {120, 127, 6, 135, 7}, - {79, 95, 104, 164, 11} - }, - { {10, 161, 221, 53, 1}, - {63, 131, 150, 21, 0}, - {138, 203, 184, 85, 0}, - {10, 134, 156, 31, 12} - }, - { {86, 173, 47, 172, 10}, - {153, 123, 23, 161, 14}, - {83, 95, 75, 86, 10}, - {120, 94, 141, 233, 9} - }, - { {211, 126, 245, 50, 15}, - {117, 157, 203, 243, 13}, - {244, 202, 247, 236, 11}, - {188, 253, 59, 154, 14} - }, - { {26, 77, 168, 98, 11}, - {6, 158, 7, 41, 13}, - {212, 97, 91, 37, 8}, - {185, 78, 7, 150, 0} - }, - { {14, 14, 83, 226, 12}, - {178, 64, 75, 57, 11}, - {52, 124, 167, 7, 0}, - {217, 205, 32, 36, 13} - }, - { {186, 19, 25, 227, 12}, - {82, 10, 111, 31, 3}, - {60, 121, 140, 133, 13}, - {207, 143, 101, 4, 10} - }, - { {166, 38, 10, 6, 2}, - {137, 80, 44, 35, 1}, - {70, 5, 6, 70, 5}, - {140, 67, 64, 169, 1} - }, - { {59, 165, 11, 14, 1}, - {31, 106, 52, 97, 1}, - {135, 13, 10, 93, 12}, - {136, 98, 197, 111, 8} - }, - { {38, 36, 208, 138, 6}, - {161, 176, 96, 49, 3}, - {101, 16, 178, 70, 4}, - {200, 192, 96, 216, 5} - }, - { {34, 170, 93, 184, 11}, - {53, 49, 191, 17, 10}, - {209, 219, 165, 84, 4}, - {88, 143, 216, 202, 12} - }, - { {204, 89, 30, 234, 11}, - {198, 119, 7, 154, 11}, - {213, 119, 137, 163, 3}, - {213, 158, 14, 230, 3} - }, - { {93, 163, 232, 36, 7}, - {175, 154, 94, 192, 4}, - {226, 65, 124, 91, 10}, - {32, 55, 165, 159, 5} - }, - { {49, 70, 31, 250, 13}, - {20, 109, 239, 120, 3}, - {181, 255, 134, 40, 12}, - {193, 239, 123, 98, 8} - }, - { {225, 228, 77, 220, 5}, - {61, 37, 244, 234, 2}, - {163, 187, 34, 120, 7}, - {69, 114, 250, 75, 12} - }, - { {44, 242, 109, 104, 5}, - {247, 37, 126, 8, 4}, - {161, 107, 100, 243, 4}, - {33, 7, 234, 78, 15} - }, - { {188, 184, 23, 132, 2}, - {219, 89, 48, 18, 10}, - {66, 30, 129, 211, 13}, - {84, 128, 201, 173, 11} - }, - { {229, 105, 162, 218, 12}, - {129, 230, 225, 202, 15}, - {53, 180, 89, 106, 7}, - {245, 56, 118, 120, 1} - }, - { {126, 187, 69, 235, 1}, - {247, 43, 58, 141, 11}, - {141, 122, 45, 215, 14}, - {219, 21, 205, 78, 15} - }, - { {95, 193, 180, 208, 10}, - {130, 159, 145, 217, 6}, - {80, 178, 216, 63, 10}, - {105, 184, 159, 148, 1} - }, - { {67, 231, 225, 87, 9}, - {61, 134, 153, 237, 5}, - {158, 168, 126, 124, 2}, - {171, 121, 150, 27, 12} - }, - { {74, 231, 170, 10, 11}, - {7, 246, 29, 161, 5}, - {213, 5, 94, 117, 2}, - {168, 91, 134, 254, 0} - }, - { {165, 185, 85, 105, 15}, - {245, 51, 115, 94, 8}, - {249, 106, 169, 218, 5}, - {23, 172, 236, 202, 15} - }, - { {224, 84, 118, 144, 13}, - {100, 69, 225, 178, 6}, - {176, 150, 226, 160, 7}, - {100, 216, 122, 34, 6} - }, - { {210, 45, 14, 153, 2}, - {1, 123, 132, 167, 10}, - {73, 151, 11, 68, 11}, - {94, 82, 29, 232, 0} - }, - { {24, 168, 223, 230, 1}, - {63, 201, 22, 24, 11}, - {134, 127, 177, 81, 8}, - {209, 134, 137, 63, 12} - }, - { {69, 219, 175, 11, 10}, - {208, 247, 29, 196, 13}, - {93, 15, 93, 186, 2}, - {178, 59, 142, 240, 11} - }, - { {120, 139, 137, 141, 8}, - {26, 170, 61, 132, 10}, - {27, 25, 29, 17, 14}, - {82, 27, 197, 85, 8} - }, - { {241, 221, 156, 23, 1}, - {76, 143, 180, 246, 9}, - {142, 131, 155, 184, 15}, - {150, 242, 223, 19, 2} - }, - { {168, 83, 82, 179, 8}, - {98, 70, 171, 22, 3}, - {28, 212, 172, 161, 5}, - {198, 141, 86, 36, 6} - }, - { {168, 106, 55, 142, 9}, - {31, 101, 41, 18, 15}, - {151, 30, 197, 97, 5}, - {244, 137, 74, 111, 8} - }, - { {189, 126, 84, 235, 14}, - {227, 61, 107, 126, 11}, - {125, 114, 167, 235, 13}, - {215, 237, 107, 204, 7} - }, - { {223, 220, 164, 141, 1}, - {206, 173, 16, 231, 14}, - {139, 18, 83, 191, 11}, - {126, 112, 139, 87, 3} - }, - { {164, 184, 123, 136, 7}, - {245, 112, 116, 18, 14}, - {225, 29, 225, 210, 5}, - {116, 130, 224, 234, 15} - }, - { {156, 22, 106, 229, 0}, - {234, 72, 14, 46, 6}, - {10, 117, 102, 131, 9}, - {103, 71, 1, 37, 7} - }, - { {7, 66, 172, 242, 15}, - {132, 149, 207, 73, 7}, - {244, 243, 84, 46, 0}, - {233, 47, 58, 146, 1} - }, - { {76, 120, 158, 87, 8}, - {203, 197, 133, 156, 9}, - {30, 167, 145, 227, 2}, - {147, 154, 26, 61, 3} - }, - { {154, 239, 33, 84, 12}, - {27, 14, 217, 43, 12}, - {50, 168, 79, 117, 9}, - {61, 73, 183, 13, 8} - }, - { {114, 33, 143, 98, 6}, - {17, 219, 102, 137, 1}, - {100, 111, 24, 68, 14}, - {137, 22, 109, 184, 8} - }, - { {144, 22, 79, 84, 2}, - {120, 89, 140, 42, 0}, - {66, 175, 38, 128, 9}, - {5, 67, 25, 161, 14} - }, - { {255, 38, 45, 47, 8}, - {155, 41, 47, 231, 5}, - {31, 75, 70, 79, 15}, - {174, 127, 73, 77, 9} - }, - { {155, 75, 33, 101, 11}, - {30, 30, 11, 79, 12}, - {218, 104, 77, 45, 9}, - {63, 45, 7, 135, 8} - }, - { {157, 250, 242, 161, 11}, - {231, 220, 27, 86, 14}, - {216, 84, 245, 251, 9}, - {118, 173, 131, 190, 7} - }, - { {88, 151, 203, 43, 2}, - {114, 250, 30, 164, 1}, - {77, 77, 62, 145, 10}, - {130, 87, 133, 244, 14} - }, - { {71, 47, 124, 245, 10}, - {169, 19, 143, 253, 14}, - {90, 243, 239, 78, 2}, - {123, 255, 28, 137, 5} - }, - { {231, 58, 247, 133, 1}, - {253, 193, 40, 215, 14}, - {138, 30, 245, 206, 7}, - {126, 177, 72, 59, 15} - }, - { {207, 215, 242, 172, 4}, - {234, 230, 90, 243, 6}, - {35, 84, 254, 191, 3}, - {108, 245, 166, 117, 7} - }, - { {34, 145, 90, 60, 13}, - {108, 98, 247, 17, 0}, - {179, 197, 168, 148, 4}, - {8, 142, 244, 99, 6} - }, - { {34, 133, 70, 209, 9}, - {36, 67, 177, 45, 2}, - {152, 182, 42, 20, 4}, - {75, 72, 220, 34, 4} - }, - { {114, 208, 93, 189, 9}, - {124, 45, 183, 149, 2}, - {155, 219, 160, 180, 14}, - {74, 158, 219, 67, 14} - }, - { {66, 217, 149, 82, 0}, - {80, 135, 144, 153, 9}, - {4, 170, 153, 180, 2}, - {153, 144, 158, 16, 10} - }, - { {138, 133, 121, 144, 1}, - {54, 2, 148, 51, 6}, - {128, 153, 234, 21, 1}, - {108, 194, 148, 6, 12} - }, - { {197, 198, 42, 24, 4}, - {128, 100, 220, 226, 4}, - {33, 133, 70, 58, 3}, - {36, 115, 178, 96, 1} - }, - { {233, 151, 88, 80, 13}, - {102, 2, 253, 250, 0}, - {176, 161, 174, 153, 7}, - {5, 251, 244, 6, 6} - }, - { {14, 234, 177, 70, 7}, - {159, 148, 88, 25, 13}, - {230, 40, 213, 119, 0}, - {185, 129, 162, 159, 9} - }, - { {145, 53, 173, 2, 13}, - {85, 139, 69, 98, 5}, - {180, 11, 90, 200, 9}, - {164, 106, 45, 26, 10} - }, - { {190, 141, 200, 78, 4}, - {170, 170, 116, 43, 9}, - {39, 33, 59, 23, 13}, - {157, 66, 229, 85, 5} - }, - { {173, 173, 184, 75, 2}, - {131, 178, 52, 126, 13}, - {77, 33, 219, 91, 5}, - {183, 226, 196, 220, 1} - }, - { {239, 18, 224, 176, 8}, - {226, 128, 171, 195, 6}, - {16, 208, 116, 143, 7}, - {108, 61, 80, 20, 7} - }, - { {110, 30, 54, 228, 4}, - {202, 65, 106, 185, 14}, - {34, 118, 199, 135, 6}, - {121, 213, 104, 37, 3} - }, - { {182, 167, 125, 25, 13}, - {181, 43, 253, 55, 4}, - {185, 139, 238, 86, 13}, - {46, 203, 253, 74, 13} - }, - { {23, 86, 83, 139, 13}, - {244, 108, 73, 117, 3}, - {189, 28, 166, 174, 8}, - {202, 233, 35, 98, 15} - }, - { {95, 18, 213, 36, 1}, - {254, 137, 10, 209, 0}, - {130, 74, 180, 143, 10}, - {8, 181, 9, 23, 15} - }, - { {70, 117, 172, 246, 3}, - {205, 151, 134, 169, 7}, - {198, 243, 90, 230, 2}, - {233, 86, 30, 155, 3} - }, - { {60, 106, 94, 42, 12}, - {163, 109, 111, 16, 9}, - {53, 71, 165, 99, 12}, - {144, 143, 107, 108, 5} - }, - { {36, 27, 3, 248, 15}, - {212, 114, 235, 8, 10}, - {241, 252, 13, 130, 4}, - {81, 13, 116, 226, 11} - }, - { {174, 183, 170, 241, 10}, - {195, 210, 191, 47, 6}, - {88, 245, 94, 215, 5}, - {111, 79, 212, 188, 3} - }, - { {128, 123, 11, 149, 5}, - {93, 70, 204, 6, 10}, - {170, 157, 13, 224, 1}, - {86, 3, 54, 43, 10} - }, - { {6, 123, 185, 142, 2}, - {217, 182, 12, 17, 15}, - {71, 25, 221, 230, 0}, - {248, 131, 6, 217, 11} - }, - { {187, 205, 97, 202, 11}, - {54, 62, 49, 107, 15}, - {213, 56, 107, 61, 13}, - {253, 104, 199, 198, 12} - }, - { {102, 111, 155, 27, 2}, - {145, 246, 172, 181, 9}, - {77, 141, 159, 102, 6}, - {154, 211, 86, 248, 9} - }, - { {220, 128, 108, 119, 5}, - {174, 9, 214, 142, 5}, - {174, 227, 96, 19, 11}, - {167, 22, 185, 7, 5} - }, - { {244, 76, 119, 37, 13}, - {188, 77, 99, 182, 12}, - {186, 78, 227, 34, 15}, - {54, 220, 107, 35, 13} - }, - { {114, 219, 75, 25, 1}, - {116, 110, 188, 133, 8}, - {137, 141, 45, 180, 14}, - {26, 19, 215, 98, 14} - }, - { {16, 18, 108, 127, 9}, - {108, 41, 143, 12, 5}, - {159, 227, 100, 128, 8}, - {163, 15, 25, 67, 6} - }, - { {162, 1, 124, 141, 13}, - {44, 35, 101, 23, 6}, - {187, 19, 232, 4, 5}, - {110, 138, 108, 67, 4} - }, - { {92, 43, 98, 199, 13}, - {175, 74, 73, 140, 15}, - {190, 52, 109, 67, 10}, - {243, 25, 37, 47, 5} - }, - { {246, 17, 249, 50, 13}, - {244, 138, 231, 147, 5}, - {180, 201, 248, 134, 15}, - {172, 158, 117, 18, 15} - }, - { {29, 202, 246, 89, 3}, - {166, 253, 152, 92, 12}, - {201, 166, 245, 59, 8}, - {51, 161, 155, 246, 5} - }, - { {246, 222, 90, 183, 0}, - {232, 76, 190, 183, 11}, - {14, 213, 167, 182, 15}, - {222, 215, 211, 33, 7} - }, - { {2, 227, 95, 133, 4}, - {57, 71, 92, 21, 2}, - {42, 31, 172, 116, 0}, - {74, 131, 174, 41, 12} - }, - { {154, 82, 200, 49, 13}, - {102, 140, 207, 7, 0}, - {184, 193, 52, 165, 9}, - {14, 15, 51, 22, 6} - }, - { {201, 156, 238, 248, 13}, - {102, 225, 215, 234, 14}, - {177, 247, 115, 153, 3}, - {117, 126, 184, 118, 6} - }, - { {164, 0, 185, 178, 3}, - {148, 144, 166, 18, 7}, - {196, 217, 208, 2, 5}, - {228, 134, 80, 146, 9} - }, - { {83, 189, 160, 149, 3}, - {77, 154, 144, 229, 14}, - {202, 144, 91, 220, 10}, - {122, 112, 149, 155, 2} - }, - { {229, 156, 80, 168, 12}, - {224, 32, 115, 242, 10}, - {49, 80, 163, 154, 7}, - {84, 252, 224, 64, 7} - }, - { {171, 95, 148, 193, 7}, - {70, 151, 104, 127, 10}, - {232, 50, 159, 173, 5}, - {95, 225, 110, 150, 2} - }, - { {154, 1, 159, 43, 13}, - {22, 235, 71, 23, 1}, - {189, 79, 152, 5, 9}, - {142, 142, 45, 118, 8} - }, - { {179, 111, 58, 61, 12}, - {9, 110, 239, 119, 12}, - {59, 197, 207, 108, 13}, - {62, 239, 119, 105, 0} - }, - { {192, 187, 244, 25, 3}, - {101, 179, 152, 150, 12}, - {201, 130, 253, 208, 3}, - {54, 145, 156, 218, 6} - }, - { {20, 123, 78, 197, 0}, - {233, 79, 12, 12, 10}, - {10, 55, 45, 226, 8}, - {83, 3, 15, 41, 7} - }, - { {90, 199, 71, 252, 14}, - {58, 127, 219, 169, 2}, - {115, 254, 46, 53, 10}, - {73, 93, 191, 229, 12} - }, - { {55, 33, 111, 157, 0}, - {185, 107, 164, 69, 6}, - {11, 159, 104, 78, 12}, - {106, 34, 93, 105, 13} - }, - { {1, 111, 252, 42, 3}, - {37, 183, 14, 112, 13}, - {197, 67, 255, 104, 0}, - {176, 231, 14, 218, 4} - }, - { {89, 15, 175, 61, 8}, - {26, 235, 143, 228, 12}, - {27, 207, 95, 9, 10}, - {50, 127, 29, 117, 8} - }, - { {153, 1, 84, 216, 10}, - {34, 59, 129, 90, 2}, - {81, 178, 168, 9, 9}, - {69, 168, 29, 196, 4} - }, - { {67, 238, 76, 167, 7}, - {45, 21, 94, 229, 11}, - {238, 83, 39, 124, 2}, - {218, 119, 170, 139, 4} - }, - { {54, 90, 193, 205, 0}, - {248, 172, 40, 13, 10}, - {11, 56, 53, 166, 12}, - {91, 1, 67, 81, 15} - }, - { {131, 166, 230, 183, 5}, - {45, 193, 218, 103, 7}, - {174, 214, 118, 92, 1}, - {238, 101, 184, 59, 4} - }, - { {19, 38, 191, 52, 9}, - {29, 201, 143, 113, 4}, - {146, 207, 214, 76, 8}, - {40, 239, 25, 59, 8} - }, - { {75, 112, 99, 4, 11}, - {127, 84, 1, 193, 4}, - {210, 12, 96, 237, 2}, - {40, 56, 2, 175, 14} - }, - { {138, 249, 189, 185, 10}, - {83, 183, 151, 23, 14}, - {89, 219, 217, 245, 1}, - {126, 142, 158, 220, 10} - }, - { {210, 150, 211, 86, 13}, - {124, 200, 217, 187, 1}, - {182, 172, 182, 148, 11}, - {141, 217, 177, 51, 14} - }, - { {191, 171, 59, 228, 2}, - {155, 90, 62, 91, 14}, - {66, 125, 205, 95, 13}, - {125, 167, 197, 173, 9} - }, - { {174, 86, 204, 98, 6}, - {226, 149, 110, 43, 1}, - {100, 99, 54, 167, 5}, - {141, 71, 106, 148, 7} - }, - { {178, 87, 177, 0, 1}, - {84, 142, 40, 51, 4}, - {128, 8, 222, 164, 13}, - {44, 193, 71, 18, 10} - }, - { {62, 59, 212, 245, 0}, - {235, 139, 170, 29, 10}, - {10, 242, 189, 199, 12}, - {91, 133, 93, 29, 7} - }, - { {81, 226, 98, 81, 13}, - {37, 76, 217, 204, 4}, - {184, 164, 100, 120, 10}, - {35, 57, 179, 42, 4} - }, - { {109, 172, 163, 64, 13}, - {151, 192, 113, 232, 12}, - {176, 44, 83, 91, 6}, - {49, 120, 224, 62, 9} - }, - { {140, 97, 186, 38, 3}, - {143, 214, 6, 18, 5}, - {198, 69, 216, 99, 1}, - {164, 134, 6, 191, 1} - }, - { {188, 245, 45, 34, 0}, - {211, 15, 54, 34, 5}, - {4, 75, 74, 243, 13}, - {164, 70, 207, 12, 11} - }, - { {211, 103, 251, 121, 3}, - {53, 254, 142, 255, 4}, - {201, 237, 254, 108, 11}, - {47, 247, 23, 250, 12} - }, - { {84, 87, 19, 84, 12}, - {216, 78, 201, 184, 0}, - {50, 172, 142, 162, 10}, - {1, 217, 55, 33, 11} - }, - { {252, 69, 102, 73, 14}, - {162, 127, 97, 174, 4}, - {121, 38, 106, 35, 15}, - {39, 88, 111, 228, 5} - }, - { {201, 116, 9, 180, 3}, - {95, 20, 134, 226, 2}, - {194, 217, 2, 233, 3}, - {68, 118, 18, 143, 10} - }, - { {219, 223, 58, 117, 6}, - {74, 94, 222, 255, 12}, - {106, 229, 207, 189, 11}, - {63, 247, 183, 165, 2} - }, - { {124, 198, 54, 99, 4}, - {130, 77, 122, 188, 5}, - {44, 102, 198, 51, 14}, - {163, 213, 235, 36, 1} - }, - { {199, 37, 21, 237, 7}, - {157, 51, 66, 255, 2}, - {235, 122, 138, 78, 3}, - {79, 244, 44, 203, 9} - }, - { {243, 129, 78, 141, 3}, - {44, 123, 52, 199, 2}, - {203, 23, 40, 28, 15}, - {78, 50, 205, 227, 4} - }, - { {1, 97, 236, 83, 14}, - {33, 151, 197, 76, 5}, - {124, 163, 120, 104, 0}, - {163, 42, 62, 152, 4} - }, - { {185, 10, 129, 53, 14}, - {26, 152, 235, 70, 8}, - {122, 200, 21, 9, 13}, - {22, 45, 113, 149, 8} - }, - { {206, 10, 5, 154, 5}, - {150, 33, 200, 131, 11}, - {165, 154, 5, 7, 3}, - {220, 17, 56, 70, 9} - }, - { {177, 143, 157, 57, 3}, - {20, 187, 190, 118, 8}, - {201, 203, 159, 24, 13}, - {22, 231, 221, 210, 8} - }, - { {148, 176, 8, 30, 13}, - {205, 40, 213, 2, 1}, - {183, 129, 0, 210, 9}, - {132, 10, 177, 75, 3} - }, - { {80, 66, 146, 213, 15}, - {12, 220, 201, 156, 2}, - {250, 180, 148, 32, 10}, - {67, 153, 51, 179, 0} - }, - { {35, 150, 114, 80, 11}, - {100, 80, 185, 121, 4}, - {208, 164, 230, 156, 4}, - {41, 233, 208, 162, 6} - }, - { {68, 239, 204, 54, 11}, - {173, 151, 159, 160, 9}, - {214, 195, 63, 114, 2}, - {144, 95, 158, 155, 5} - }, - { {31, 253, 132, 177, 6}, - {195, 159, 210, 101, 10}, - {104, 210, 27, 255, 8}, - {90, 100, 191, 156, 3} - }, - { {197, 49, 181, 191, 8}, - {217, 163, 131, 214, 7}, - {31, 218, 216, 202, 3}, - {230, 188, 28, 89, 11} - }, - { {22, 150, 178, 17, 4}, - {192, 200, 216, 53, 4}, - {40, 132, 214, 150, 8}, - {42, 193, 177, 48, 3} - }, - { {38, 79, 248, 144, 13}, - {164, 134, 237, 49, 14}, - {176, 145, 255, 38, 4}, - {120, 203, 118, 18, 5} - }, - { {246, 196, 223, 173, 7}, - {188, 253, 118, 183, 2}, - {235, 95, 178, 54, 15}, - {78, 214, 235, 243, 13} - }, - { {156, 24, 84, 188, 5}, - {238, 41, 194, 18, 10}, - {163, 210, 161, 131, 9}, - {84, 132, 57, 71, 7} - }, - { {19, 208, 219, 228, 10}, - {120, 220, 23, 89, 2}, - {82, 125, 176, 188, 8}, - {73, 174, 131, 177, 14} - }, - { {249, 179, 22, 59, 4}, - {67, 107, 250, 214, 1}, - {45, 198, 140, 217, 15}, - {134, 181, 253, 108, 2} - }, - { {81, 149, 114, 252, 7}, - {108, 122, 210, 248, 6}, - {227, 244, 234, 152, 10}, - {97, 244, 181, 227, 6} - }, - { {242, 39, 249, 70, 5}, - {61, 138, 108, 187, 5}, - {166, 41, 254, 68, 15}, - {173, 211, 101, 27, 12} - }, - { {102, 190, 189, 206, 13}, - {221, 161, 125, 185, 15}, - {183, 59, 215, 214, 6}, - {249, 219, 232, 91, 11} - }, - { {214, 222, 191, 213, 4}, - {216, 205, 220, 191, 14}, - {42, 191, 215, 182, 11}, - {127, 211, 187, 49, 11} - }, - { {42, 6, 160, 45, 8}, - {10, 160, 43, 37, 4}, - {27, 64, 86, 5, 4}, - {42, 77, 64, 85, 0} - }, - { {20, 53, 95, 118, 11}, - {253, 91, 135, 56, 1}, - {214, 239, 170, 194, 8}, - {129, 206, 29, 171, 15} - }, - { {10, 147, 60, 139, 0}, - {66, 35, 28, 21, 7}, - {13, 19, 204, 149, 0}, - {234, 131, 140, 68, 2} - }, - { {41, 181, 114, 31, 7}, - {111, 114, 240, 116, 5}, - {239, 132, 234, 217, 4}, - {162, 224, 244, 239, 6} - }, - { {10, 176, 119, 109, 10}, - {123, 113, 19, 29, 4}, - {91, 110, 224, 213, 0}, - {43, 140, 136, 237, 14} - }, - { {73, 99, 125, 47, 0}, - {59, 39, 14, 212, 5}, - {15, 75, 236, 105, 2}, - {162, 183, 14, 77, 12} - }, - { {129, 17, 157, 135, 11}, - {92, 147, 5, 86, 3}, - {222, 27, 152, 136, 1}, - {198, 170, 12, 147, 10} - }, - { {140, 179, 51, 58, 10}, - {211, 114, 155, 18, 5}, - {85, 204, 204, 211, 1}, - {164, 141, 148, 236, 11} - }, - { {178, 29, 155, 97, 0}, - {80, 202, 38, 63, 8}, - {8, 109, 155, 132, 13}, - {31, 198, 69, 48, 10} - }, - { {188, 118, 206, 213, 10}, - {235, 221, 173, 46, 2}, - {90, 183, 54, 227, 13}, - {71, 75, 91, 189, 7} - }, - { {160, 15, 75, 230, 8}, - {56, 66, 47, 42, 11}, - {22, 125, 47, 0, 5}, - {213, 79, 68, 33, 12} - }, - { {68, 168, 183, 24, 8}, - {145, 225, 145, 144, 12}, - {17, 142, 209, 82, 2}, - {48, 152, 152, 120, 9} - }, - { {192, 147, 189, 209, 12}, - {80, 131, 221, 158, 6}, - {56, 187, 220, 144, 3}, - {103, 155, 188, 16, 10} - }, - { {67, 88, 203, 57, 12}, - {112, 228, 199, 197, 8}, - {57, 205, 49, 172, 2}, - {26, 62, 50, 112, 14} - }, - { {138, 61, 137, 8, 12}, - {83, 162, 69, 35, 8}, - {49, 9, 27, 197, 1}, - {28, 74, 36, 92, 10} - }, - { {252, 190, 21, 102, 11}, - {223, 25, 59, 186, 9}, - {214, 106, 135, 211, 15}, - {149, 221, 201, 143, 11} - }, - { {203, 103, 181, 191, 5}, - {31, 167, 202, 247, 7}, - {175, 218, 222, 109, 3}, - {238, 245, 62, 95, 8} - }, - { {233, 7, 248, 189, 4}, - {42, 162, 238, 246, 6}, - {43, 209, 254, 9, 7}, - {102, 247, 116, 85, 4} - }, - { {75, 186, 42, 243, 10}, - {67, 80, 159, 205, 15}, - {92, 245, 69, 221, 2}, - {251, 63, 144, 172, 2} - }, - { {113, 234, 245, 7, 10}, - {57, 157, 57, 212, 13}, - {94, 10, 245, 120, 14}, - {178, 185, 203, 153, 12} - }, - { {147, 43, 182, 127, 6}, - {9, 251, 202, 95, 13}, - {111, 230, 221, 76, 9}, - {191, 165, 61, 249, 0} - }, - { {83, 241, 61, 70, 1}, - {93, 15, 20, 217, 5}, - {134, 43, 200, 252, 10}, - {169, 178, 143, 11, 10} - }, - { {99, 45, 7, 61, 3}, - {29, 115, 162, 229, 8}, - {203, 206, 11, 76, 6}, - {26, 116, 92, 235, 8} - }, - { {187, 21, 254, 209, 0}, - {98, 203, 164, 127, 6}, - {8, 183, 250, 141, 13}, - {111, 226, 93, 52, 6} - }, - { {249, 117, 16, 139, 12}, - {67, 46, 97, 246, 3}, - {61, 16, 138, 233, 15}, - {198, 248, 103, 76, 2} - }, - { {82, 137, 180, 183, 15}, - {12, 155, 211, 149, 15}, - {254, 210, 217, 20, 10}, - {250, 156, 189, 147, 0} - }, - { {27, 210, 12, 213, 13}, - {78, 13, 221, 77, 2}, - {186, 179, 4, 189, 8}, - {75, 43, 187, 7, 2} - }, - { {177, 242, 231, 215, 11}, - {125, 221, 185, 78, 7}, - {222, 190, 116, 248, 13}, - {231, 41, 219, 187, 14} - }, - { {59, 199, 234, 23, 8}, - {42, 206, 189, 101, 5}, - {30, 133, 126, 61, 12}, - {170, 107, 215, 53, 4} - }, - { {129, 160, 44, 14, 10}, - {9, 49, 21, 66, 5}, - {87, 3, 64, 88, 1}, - {164, 42, 136, 201, 0} - }, - { {175, 47, 221, 40, 8}, - {179, 163, 47, 115, 8}, - {17, 75, 191, 79, 5}, - {28, 239, 76, 92, 13} - }, - { {102, 160, 63, 60, 5}, - {157, 97, 246, 145, 4}, - {163, 207, 192, 86, 6}, - {40, 150, 248, 107, 9} - }, - { {97, 107, 54, 64, 2}, - {1, 87, 40, 216, 12}, - {64, 38, 205, 104, 6}, - {49, 177, 78, 168, 0} - }, - { {179, 110, 223, 102, 4}, - {57, 205, 110, 123, 9}, - {38, 111, 183, 108, 13}, - {157, 231, 107, 57, 12} - }, - { {221, 206, 234, 142, 13}, - {174, 236, 93, 226, 15}, - {183, 21, 119, 59, 11}, - {244, 123, 163, 119, 5} - }, - { {191, 161, 228, 191, 4}, - {171, 171, 242, 71, 7}, - {47, 210, 120, 95, 13}, - {238, 36, 253, 93, 5} - }, - { {181, 50, 205, 129, 2}, - {241, 153, 44, 70, 2}, - {72, 27, 52, 202, 13}, - {70, 35, 73, 152, 15} - }, - { {93, 75, 26, 56, 8}, - {130, 110, 143, 208, 8}, - {17, 197, 141, 43, 10}, - {16, 191, 23, 100, 1} - }, - { {178, 246, 24, 165, 12}, - {73, 12, 127, 55, 2}, - {58, 81, 134, 244, 13}, - {78, 207, 227, 9, 2} - }, - { {56, 237, 90, 165, 11}, - {47, 94, 55, 52, 10}, - {218, 85, 171, 113, 12}, - {82, 206, 199, 175, 4} - }, - { {73, 219, 225, 19, 5}, - {118, 134, 216, 196, 13}, - {172, 136, 125, 185, 2}, - {178, 49, 182, 22, 14} - }, - { {73, 170, 182, 189, 9}, - {15, 225, 155, 212, 14}, - {155, 214, 213, 89, 2}, - {114, 189, 152, 127, 0} - }, - { {84, 139, 234, 26, 2}, - {160, 250, 156, 128, 13}, - {69, 133, 125, 18, 10}, - {176, 19, 149, 240, 5} - }, - { {157, 15, 70, 19, 1}, - {166, 75, 136, 102, 9}, - {140, 134, 47, 11, 9}, - {150, 97, 29, 38, 5} - }, - { {102, 97, 19, 14, 1}, - {157, 102, 32, 145, 1}, - {135, 12, 136, 102, 6}, - {136, 144, 70, 107, 9} - }, - { {248, 9, 47, 37, 2}, - {26, 91, 38, 134, 12}, - {74, 79, 73, 1, 15}, - {54, 22, 77, 165, 8} - }, - { {11, 201, 149, 46, 14}, - {26, 183, 83, 81, 9}, - {119, 74, 153, 61, 0}, - {152, 172, 174, 213, 8} - }, - { {184, 19, 104, 249, 3}, - {102, 58, 174, 14, 6}, - {201, 241, 108, 129, 13}, - {103, 7, 85, 198, 6} - }, - { {247, 151, 168, 45, 7}, - {204, 186, 126, 231, 4}, - {235, 65, 94, 158, 15}, - {46, 119, 229, 211, 3} - }, - { {64, 198, 85, 224, 12}, - {48, 5, 91, 184, 2}, - {48, 122, 166, 48, 2}, - {65, 221, 170, 0, 12} - }, - { {119, 132, 246, 36, 5}, - {172, 201, 114, 241, 4}, - {162, 70, 242, 30, 14}, - {40, 244, 233, 51, 5} - }, - { {67, 149, 31, 37, 8}, - {88, 67, 23, 245, 0}, - {26, 79, 138, 156, 2}, - {10, 254, 140, 33, 10} - }, - { {45, 159, 144, 243, 0}, - {194, 130, 186, 124, 11}, - {12, 240, 159, 155, 4}, - {211, 229, 212, 20, 3} - }, - { {146, 221, 176, 205, 11}, - {76, 190, 17, 63, 14}, - {219, 48, 219, 180, 9}, - {127, 200, 135, 211, 2} - }, - { {246, 199, 216, 26, 12}, - {160, 174, 253, 179, 1}, - {53, 129, 190, 54, 15}, - {140, 219, 247, 80, 5} - }, - { {24, 194, 89, 137, 6}, - {50, 60, 92, 20, 2}, - {105, 25, 164, 49, 8}, - {66, 131, 163, 196, 12} - }, - { {191, 94, 230, 119, 1}, - {238, 205, 170, 111, 13}, - {142, 230, 119, 175, 13}, - {191, 101, 91, 55, 7} - }, - { {154, 185, 210, 41, 10}, - {99, 250, 19, 23, 8}, - {89, 68, 185, 213, 9}, - {30, 140, 133, 252, 6} - }, - { {85, 134, 127, 171, 1}, - {180, 105, 30, 244, 7}, - {141, 95, 230, 26, 10}, - {226, 247, 137, 98, 13} - }, - { {184, 210, 232, 62, 14}, - {106, 188, 255, 2, 5}, - {119, 193, 116, 177, 13}, - {164, 15, 243, 213, 6} - }, - { {8, 95, 31, 243, 10}, - {82, 87, 143, 60, 11}, - {92, 255, 143, 161, 0}, - {211, 207, 30, 164, 10} - }, - { {18, 244, 23, 56, 3}, - {85, 125, 146, 49, 0}, - {193, 206, 130, 244, 8}, - {8, 196, 155, 234, 10} - }, - { {166, 113, 141, 223, 14}, - {217, 183, 229, 15, 3}, - {127, 187, 24, 230, 5}, - {207, 10, 126, 217, 11} - }, - { {192, 142, 206, 109, 0}, - {40, 225, 30, 174, 8}, - {11, 103, 55, 16, 3}, - {23, 87, 136, 113, 4} - }, - { {109, 149, 12, 180, 7}, - {206, 19, 246, 224, 2}, - {226, 211, 10, 155, 6}, - {64, 118, 252, 135, 3} - }, - { {150, 47, 248, 18, 6}, - {161, 154, 204, 51, 13}, - {100, 129, 255, 70, 9}, - {188, 195, 53, 152, 5} - }, - { {100, 178, 210, 193, 10}, - {225, 208, 57, 156, 2}, - {88, 52, 180, 210, 6}, - {67, 153, 192, 184, 7} - }, - { {171, 232, 165, 221, 12}, - {27, 165, 241, 79, 14}, - {59, 186, 81, 125, 5}, - {127, 40, 250, 93, 8} - }, - { {1, 1, 118, 119, 7}, - {44, 83, 194, 92, 5}, - {238, 230, 232, 8, 0}, - {163, 164, 60, 163, 4} - }, - { {122, 87, 242, 127, 10}, - {106, 254, 171, 189, 5}, - {95, 228, 254, 165, 14}, - {171, 221, 87, 245, 6} - }, - { {49, 50, 151, 33, 7}, - {85, 217, 106, 84, 0}, - {232, 78, 148, 200, 12}, - {2, 165, 105, 186, 10} - }, - { {84, 80, 181, 69, 13}, - {220, 141, 65, 156, 4}, - {186, 42, 208, 162, 10}, - {35, 152, 43, 19, 11} - }, - { {11, 87, 84, 254, 5}, - {110, 39, 202, 121, 3}, - {167, 242, 174, 173, 0}, - {201, 229, 62, 71, 6} - }, - { {182, 45, 55, 60, 6}, - {153, 123, 226, 51, 12}, - {99, 206, 203, 70, 13}, - {60, 196, 125, 233, 9} - }, - { {148, 78, 188, 41, 1}, - {132, 173, 14, 54, 12}, - {137, 67, 215, 34, 9}, - {54, 199, 11, 82, 1} - }, - { {212, 209, 225, 203, 8}, - {240, 174, 17, 142, 7}, - {29, 56, 120, 178, 11}, - {231, 24, 135, 80, 15} - }, - { {41, 127, 114, 212, 15}, - {111, 86, 233, 120, 14}, - {242, 180, 239, 233, 4}, - {113, 233, 118, 175, 6} - }, - { {185, 41, 143, 89, 11}, - {23, 251, 165, 78, 8}, - {217, 175, 25, 73, 13}, - {23, 42, 93, 254, 8} - }, - { {156, 178, 65, 173, 13}, - {255, 40, 91, 6, 2}, - {187, 88, 36, 211, 9}, - {70, 13, 161, 79, 15} - }, - { {9, 10, 241, 177, 13}, - {54, 128, 203, 84, 14}, - {184, 216, 245, 9, 0}, - {114, 173, 48, 22, 12} - }, - { {16, 185, 135, 171, 7}, - {85, 251, 82, 4, 11}, - {237, 94, 25, 208, 8}, - {210, 4, 173, 250, 10} - }, - { {126, 194, 225, 64, 6}, - {178, 156, 120, 137, 4}, - {96, 40, 116, 55, 14}, - {41, 17, 227, 148, 13} - }, - { {67, 167, 86, 127, 1}, - {45, 99, 154, 253, 1}, - {143, 230, 174, 92, 2}, - {139, 245, 156, 107, 4} - }, - { {26, 3, 90, 19, 6}, - {34, 90, 204, 21, 1}, - {108, 133, 172, 5, 8}, - {138, 131, 53, 164, 4} - }, - { {29, 135, 214, 9, 13}, - {166, 235, 89, 116, 0}, - {185, 6, 190, 27, 8}, - {2, 233, 173, 118, 5} - }, - { {166, 252, 66, 185, 15}, - {229, 116, 243, 39, 10}, - {249, 212, 35, 246, 5}, - {94, 76, 242, 234, 7} - }, - { {107, 129, 183, 247, 6}, - {26, 211, 242, 221, 7}, - {110, 254, 216, 29, 6}, - {235, 180, 252, 181, 8} - }, - { {69, 254, 109, 129, 14}, - {241, 21, 93, 228, 14}, - {120, 27, 103, 250, 2}, - {114, 123, 170, 136, 15} - }, - { {53, 236, 43, 184, 7}, - {149, 124, 246, 96, 14}, - {225, 221, 67, 122, 12}, - {112, 102, 243, 234, 9} - }, - { {49, 88, 4, 149, 14}, - {72, 29, 225, 68, 10}, - {122, 146, 1, 168, 12}, - {82, 40, 123, 129, 2} - }, - { {152, 19, 34, 45, 15}, - {78, 122, 75, 6, 4}, - {251, 68, 76, 129, 9}, - {38, 13, 37, 231, 2} - }, - { {154, 159, 90, 231, 3}, - {110, 90, 30, 63, 11}, - {206, 117, 175, 149, 9}, - {223, 199, 133, 167, 6} - }, - { {212, 231, 111, 182, 1}, - {189, 79, 158, 162, 7}, - {134, 223, 110, 114, 11}, - {228, 87, 159, 43, 13} - }, - { {229, 90, 150, 106, 14}, - {192, 245, 107, 218, 9}, - {117, 102, 149, 170, 7}, - {149, 189, 106, 240, 3} - }, - { {79, 187, 212, 222, 13}, - {239, 163, 217, 217, 11}, - {183, 178, 189, 223, 2}, - {217, 185, 188, 95, 7} - }, - { {121, 157, 133, 152, 15}, - {86, 187, 241, 224, 10}, - {241, 154, 27, 153, 14}, - {80, 120, 253, 214, 10} - }, - { {9, 112, 158, 165, 9}, - {79, 197, 7, 84, 2}, - {154, 87, 144, 233, 0}, - {66, 174, 10, 63, 2} - }, - { {3, 87, 205, 203, 8}, - {112, 167, 13, 109, 3}, - {29, 59, 62, 172, 0}, - {203, 107, 14, 80, 14} - }, - { {212, 185, 186, 58, 5}, - {197, 234, 214, 146, 13}, - {165, 197, 217, 210, 11}, - {180, 150, 181, 122, 3} - }, - { {24, 64, 161, 74, 8}, - {18, 172, 1, 8, 5}, - {21, 40, 80, 33, 8}, - {161, 8, 3, 84, 8} - }, - { {118, 93, 35, 164, 0}, - {216, 78, 34, 161, 14}, - {2, 92, 75, 166, 14}, - {120, 84, 71, 33, 11} - }, - { {215, 210, 250, 82, 11}, - {228, 220, 157, 219, 5}, - {212, 165, 244, 190, 11}, - {173, 187, 147, 178, 7} - }, - { {112, 131, 115, 144, 14}, - {48, 90, 249, 144, 6}, - {112, 156, 236, 16, 14}, - {96, 153, 245, 160, 12} - }, - { {54, 219, 219, 178, 9}, - {244, 206, 191, 17, 11}, - {148, 221, 189, 182, 12}, - {216, 143, 215, 50, 15} - }, - { {238, 65, 132, 139, 9}, - {134, 167, 33, 135, 3}, - {157, 18, 24, 39, 7}, - {206, 24, 78, 86, 1} - }, - { {82, 197, 48, 152, 6}, - {0, 62, 208, 177, 6}, - {97, 144, 202, 52, 10}, - {104, 208, 183, 192, 0} - }, - { {252, 86, 183, 22, 2}, - {218, 221, 168, 178, 5}, - {70, 142, 214, 163, 15}, - {164, 209, 91, 181, 11} - }, - { {116, 165, 189, 128, 1}, - {149, 139, 52, 176, 6}, - {128, 27, 218, 82, 14}, - {96, 210, 205, 26, 9} - }, - { {149, 143, 205, 134, 4}, - {184, 139, 92, 98, 11}, - {38, 27, 63, 26, 9}, - {212, 99, 173, 17, 13} - }, - { {217, 178, 146, 205, 0}, - {75, 232, 24, 222, 2}, - {11, 52, 148, 217, 11}, - {71, 177, 129, 125, 2} - }, - { {167, 235, 71, 193, 10}, - {177, 87, 57, 79, 10}, - {88, 62, 45, 126, 5}, - {95, 41, 206, 168, 13} - }, - { {79, 1, 94, 2, 9}, - {166, 67, 5, 209, 1}, - {148, 7, 168, 15, 2}, - {136, 186, 12, 38, 5} - }, - { {106, 36, 9, 113, 10}, - {19, 16, 167, 173, 0}, - {88, 233, 2, 69, 6}, - {11, 94, 80, 140, 8} - }, - { {206, 68, 49, 8, 9}, - {150, 36, 1, 179, 4}, - {145, 8, 194, 39, 3}, - {44, 216, 2, 70, 9} - }, - { {49, 255, 30, 233, 10}, - {65, 127, 63, 124, 10}, - {89, 119, 143, 248, 12}, - {83, 239, 207, 232, 2} - }, - { {20, 10, 7, 54, 11}, - {156, 89, 139, 0, 9}, - {214, 206, 5, 2, 8}, - {144, 13, 25, 163, 9} - }, - { {70, 59, 86, 20, 0}, - {233, 67, 136, 145, 8}, - {2, 134, 173, 198, 2}, - {24, 145, 28, 41, 7} - }, - { {59, 6, 12, 183, 14}, - {10, 25, 239, 101, 3}, - {126, 211, 6, 13, 12}, - {202, 111, 121, 133, 0} - }, - { {183, 192, 126, 222, 10}, - {168, 125, 181, 91, 7}, - {87, 183, 224, 62, 13}, - {237, 170, 219, 225, 5} - }, - { {131, 167, 59, 199, 12}, - {25, 66, 93, 127, 7}, - {62, 61, 206, 92, 1}, - {239, 235, 164, 41, 8} - }, - { {169, 68, 61, 125, 8}, - {26, 37, 167, 126, 4}, - {27, 235, 194, 41, 5}, - {39, 238, 90, 69, 8} - }, - { {89, 62, 133, 40, 0}, - {83, 169, 10, 224, 8}, - {1, 74, 23, 201, 10}, - {16, 117, 9, 92, 10} - }, - { {91, 223, 9, 190, 3}, - {94, 62, 158, 225, 11}, - {199, 217, 15, 189, 10}, - {216, 119, 151, 199, 10} - }, - { {90, 199, 81, 168, 1}, - {54, 46, 26, 177, 2}, - {129, 88, 174, 53, 10}, - {72, 213, 135, 70, 12} - }, - { {172, 197, 14, 185, 6}, - {130, 119, 246, 38, 2}, - {105, 215, 10, 51, 5}, - {70, 70, 254, 228, 1} - }, - { {140, 158, 159, 124, 11}, - {222, 241, 159, 58, 8}, - {211, 239, 151, 147, 1}, - {21, 207, 152, 247, 11} - }, - { {94, 223, 124, 158, 10}, - {234, 63, 157, 177, 15}, - {87, 147, 239, 183, 10}, - {248, 219, 159, 197, 7} - }, - { {194, 247, 145, 150, 7}, - {93, 150, 216, 179, 3}, - {230, 152, 158, 244, 3}, - {204, 209, 182, 155, 10} - }, - { {104, 128, 250, 139, 3}, - {38, 240, 52, 148, 7}, - {205, 21, 240, 17, 6}, - {226, 146, 192, 246, 4} - }, - { {164, 118, 61, 185, 15}, - {213, 53, 239, 54, 6}, - {249, 219, 198, 226, 5}, - {102, 207, 122, 202, 11} - }, - { {232, 136, 149, 37, 11}, - {30, 145, 51, 150, 8}, - {218, 74, 145, 17, 7}, - {22, 156, 200, 151, 8} - }, - { {94, 137, 11, 42, 0}, - {146, 106, 22, 129, 9}, - {5, 77, 9, 23, 10}, - {152, 22, 133, 100, 9} - }, - { {168, 252, 52, 240, 6}, - {67, 21, 242, 58, 14}, - {96, 242, 195, 241, 5}, - {117, 196, 250, 140, 2} - }, - { {102, 80, 220, 156, 14}, - {232, 181, 229, 145, 2}, - {115, 147, 176, 166, 6}, - {72, 154, 122, 209, 7} - }, - { {217, 235, 112, 198, 6}, - {43, 30, 88, 218, 15}, - {102, 48, 237, 121, 11}, - {245, 177, 167, 141, 4} - }, - { {6, 57, 26, 27, 7}, - {197, 114, 196, 21, 9}, - {237, 133, 137, 198, 0}, - {154, 130, 52, 234, 3} - }, - { {100, 213, 236, 219, 14}, - {224, 183, 245, 172, 7}, - {125, 179, 122, 178, 6}, - {227, 90, 254, 208, 7} - }, - { {80, 23, 140, 98, 3}, - {68, 155, 14, 168, 1}, - {196, 99, 30, 128, 10}, - {129, 87, 13, 146, 2} - }, - { {128, 175, 91, 93, 8}, - {57, 98, 157, 62, 8}, - {27, 173, 175, 80, 1}, - {23, 203, 148, 105, 12} - }, - { {178, 110, 247, 189, 9}, - {61, 237, 171, 55, 14}, - {155, 222, 247, 100, 13}, - {126, 205, 91, 123, 12} - }, - { {210, 217, 41, 11, 11}, - {84, 62, 21, 135, 13}, - {221, 9, 73, 180, 11}, - {190, 26, 135, 194, 10} - }, - { {142, 230, 136, 246, 1}, - {143, 132, 158, 43, 3}, - {134, 241, 22, 119, 1}, - {205, 71, 146, 31, 1} - }, - { {144, 133, 126, 179, 5}, - {36, 75, 214, 54, 7}, - {172, 215, 234, 16, 9}, - {230, 198, 189, 34, 4} - }, - { {214, 244, 185, 51, 14}, - {209, 156, 215, 183, 5}, - {124, 201, 210, 246, 11}, - {174, 222, 179, 152, 11} - }, - { {68, 17, 154, 175, 12}, - {200, 226, 71, 148, 3}, - {63, 85, 152, 130, 2}, - {194, 158, 36, 113, 3} - }, - { {48, 177, 90, 93, 2}, - {105, 122, 180, 28, 0}, - {75, 165, 168, 208, 12}, - {3, 130, 213, 233, 6} - }, - { {66, 57, 254, 118, 6}, - {105, 211, 198, 153, 13}, - {102, 231, 249, 196, 2}, - {185, 150, 60, 185, 6} - }, - { {108, 223, 228, 140, 12}, - {234, 167, 121, 160, 14}, - {51, 18, 127, 179, 6}, - {112, 89, 238, 85, 7} - }, - { {110, 159, 250, 19, 0}, - {226, 194, 188, 181, 13}, - {12, 133, 255, 151, 6}, - {186, 211, 212, 52, 7} - }, - { {251, 180, 205, 219, 9}, - {119, 169, 181, 239, 3}, - {157, 187, 50, 221, 15}, - {207, 122, 217, 94, 14} - }, - { {106, 94, 54, 11, 12}, - {66, 101, 105, 181, 13}, - {61, 6, 199, 165, 6}, - {186, 217, 106, 100, 2} - }, - { {187, 128, 110, 3, 5}, - {38, 73, 116, 71, 5}, - {172, 7, 96, 29, 13}, - {174, 34, 233, 38, 4} - }, - { {151, 235, 197, 191, 10}, - {185, 191, 155, 71, 11}, - {95, 218, 61, 126, 9}, - {222, 45, 159, 217, 13} - }, - { {15, 117, 226, 80, 2}, - {227, 214, 128, 105, 4}, - {64, 164, 122, 239, 0}, - {41, 96, 22, 188, 7} - }, - { {11, 49, 73, 156, 8}, - {123, 34, 133, 65, 2}, - {19, 153, 40, 205, 0}, - {72, 42, 20, 77, 14} - }, - { {215, 174, 213, 193, 8}, - {177, 137, 25, 255, 10}, - {24, 58, 183, 94, 11}, - {95, 249, 137, 24, 13} - }, - { {210, 248, 182, 187, 9}, - {69, 237, 147, 151, 15}, - {157, 214, 209, 244, 11}, - {254, 156, 155, 122, 2} - }, - { {34, 55, 245, 42, 9}, - {117, 163, 43, 49, 5}, - {149, 74, 254, 196, 4}, - {168, 205, 76, 90, 14} - }, - { {68, 127, 202, 153, 4}, - {225, 230, 204, 164, 10}, - {41, 149, 63, 226, 2}, - {82, 83, 54, 120, 7} - }, - { {141, 146, 126, 41, 15}, - {230, 113, 95, 86, 4}, - {249, 71, 228, 155, 1}, - {38, 175, 168, 230, 7} - }, - { {13, 54, 100, 46, 5}, - {239, 33, 74, 96, 5}, - {167, 66, 102, 203, 0}, - {160, 101, 40, 79, 7} - }, - { {213, 191, 237, 221, 12}, - {249, 171, 221, 238, 14}, - {59, 187, 127, 218, 11}, - {119, 123, 189, 89, 15} - }, - { {139, 198, 212, 229, 1}, - {46, 133, 26, 127, 2}, - {138, 114, 182, 61, 1}, - {79, 229, 138, 23, 4} - }, - { {221, 244, 124, 110, 1}, - {239, 45, 22, 250, 5}, - {135, 99, 226, 251, 11}, - {165, 246, 139, 79, 7} - }, - { {69, 159, 45, 147, 1}, - {212, 3, 156, 228, 15}, - {140, 155, 79, 154, 2}, - {242, 115, 156, 2, 11} - }, - { {134, 21, 175, 172, 5}, - {220, 227, 70, 35, 6}, - {163, 95, 90, 134, 1}, - {108, 70, 44, 115, 11} - }, - { {52, 174, 42, 121, 9}, - {133, 104, 191, 44, 12}, - {153, 229, 71, 82, 12}, - {51, 79, 209, 106, 1} - }, - { {246, 135, 29, 191, 4}, - {152, 43, 254, 183, 3}, - {47, 219, 142, 22, 15}, - {206, 215, 253, 65, 9} - }, - { {22, 183, 193, 11, 4}, - {241, 170, 88, 37, 1}, - {45, 8, 62, 214, 8}, - {138, 65, 165, 88, 15} - }, - { {122, 54, 203, 160, 5}, - {119, 200, 110, 161, 2}, - {160, 93, 54, 197, 14}, - {72, 87, 97, 62, 14} - }, - { {127, 66, 16, 98, 10}, - {130, 28, 43, 217, 1}, - {84, 96, 132, 47, 14}, - {137, 189, 67, 132, 1} - }, - { {103, 112, 117, 206, 8}, - {249, 37, 33, 217, 7}, - {23, 58, 224, 238, 6}, - {233, 184, 74, 73, 15} - }, - { {167, 70, 60, 209, 12}, - {128, 5, 237, 127, 6}, - {56, 179, 198, 46, 5}, - {111, 235, 122, 0, 1} - }, - { {153, 117, 131, 110, 2}, - {91, 254, 2, 106, 1}, - {71, 108, 26, 233, 9}, - {133, 100, 7, 253, 10} - }, - { {81, 145, 211, 21, 9}, - {124, 202, 145, 212, 0}, - {154, 140, 184, 152, 10}, - {2, 184, 149, 51, 14} - }, - { {53, 76, 2, 185, 8}, - {128, 108, 163, 100, 10}, - {25, 212, 3, 42, 12}, - {82, 108, 83, 96, 1} - }, - { {208, 27, 128, 57, 5}, - {68, 170, 202, 134, 8}, - {169, 192, 29, 128, 11}, - {22, 21, 53, 82, 2} - }, - { {123, 39, 171, 229, 3}, - {31, 218, 46, 237, 6}, - {202, 125, 94, 77, 14}, - {107, 119, 69, 191, 8} - }, - { {168, 140, 171, 169, 4}, - {18, 224, 118, 38, 14}, - {41, 93, 83, 17, 5}, - {118, 70, 224, 116, 8} - }, - { {138, 112, 46, 100, 13}, - {79, 69, 71, 11, 4}, - {178, 103, 64, 229, 1}, - {45, 14, 42, 47, 2} - }, - { {17, 144, 216, 79, 13}, - {108, 168, 85, 92, 1}, - {191, 33, 176, 152, 8}, - {131, 170, 161, 83, 6} - }, - { {168, 56, 156, 230, 8}, - {75, 129, 39, 26, 11}, - {22, 115, 145, 193, 5}, - {213, 142, 72, 29, 2} - }, - { {99, 172, 245, 8, 11}, - {53, 177, 49, 241, 12}, - {209, 10, 243, 92, 6}, - {56, 248, 200, 218, 12} - }, - { {153, 224, 174, 41, 11}, - {7, 253, 23, 70, 4}, - {217, 71, 80, 121, 9}, - {38, 46, 139, 254, 0} - }, - { {232, 139, 97, 157, 3}, - {62, 50, 184, 134, 14}, - {203, 152, 109, 17, 7}, - {118, 17, 212, 199, 12} - }, - { {17, 175, 187, 184, 0}, - {17, 234, 158, 112, 14}, - {1, 221, 223, 88, 8}, - {112, 231, 149, 120, 8} - }, - { {98, 250, 27, 120, 14}, - {81, 116, 255, 153, 8}, - {113, 237, 133, 244, 6}, - {25, 159, 242, 232, 10} - }, - { {241, 171, 236, 42, 5}, - {37, 171, 126, 194, 13}, - {165, 67, 125, 88, 15}, - {180, 55, 237, 90, 4} - }, - { {164, 120, 185, 64, 2}, - {209, 148, 36, 26, 12}, - {64, 41, 209, 226, 5}, - {53, 130, 66, 152, 11} - }, - { {78, 147, 112, 26, 3}, - {230, 50, 152, 145, 5}, - {197, 128, 236, 151, 2}, - {168, 145, 148, 198, 7} - }, - { {93, 31, 190, 33, 6}, - {194, 219, 78, 244, 12}, - {104, 71, 223, 139, 10}, - {50, 247, 45, 180, 3} - }, - { {222, 153, 178, 148, 7}, - {206, 218, 208, 147, 14}, - {226, 148, 217, 151, 11}, - {124, 144, 181, 183, 3} - }, - { {119, 8, 209, 116, 7}, - {188, 152, 226, 217, 8}, - {226, 232, 177, 14, 14}, - {25, 180, 113, 147, 13} - }, - { {187, 192, 140, 154, 8}, - {2, 173, 181, 67, 3}, - {21, 147, 16, 61, 13}, - {204, 42, 219, 84, 0} - }, - { {234, 28, 8, 68, 4}, - {74, 0, 100, 171, 8}, - {34, 33, 3, 133, 7}, - {29, 82, 96, 5, 2} - }, - { {184, 154, 172, 7, 8}, - {74, 137, 61, 6, 13}, - {30, 3, 85, 145, 13}, - {182, 11, 201, 21, 2} - }, - { {151, 79, 121, 58, 13}, - {180, 46, 207, 115, 13}, - {181, 201, 239, 46, 9}, - {188, 239, 55, 66, 13} - }, - { {124, 55, 168, 31, 9}, - {207, 170, 173, 164, 5}, - {159, 129, 94, 195, 14}, - {162, 91, 85, 95, 3} - }, - { {132, 5, 69, 184, 11}, - {180, 51, 131, 34, 2}, - {209, 218, 42, 2, 1}, - {68, 76, 28, 194, 13} - }, - { {137, 136, 232, 242, 10}, - {34, 144, 151, 74, 15}, - {84, 241, 113, 25, 1}, - {245, 46, 144, 148, 4} - }, - { {122, 5, 47, 138, 7}, - {22, 123, 100, 161, 7}, - {229, 31, 74, 5, 14}, - {232, 82, 109, 230, 8} - }, - { {192, 107, 231, 168, 3}, - {53, 247, 10, 130, 14}, - {193, 94, 125, 96, 3}, - {116, 21, 14, 250, 12} - }, - { {225, 214, 143, 229, 13}, - {92, 197, 127, 238, 2}, - {186, 127, 22, 184, 7}, - {71, 127, 234, 51, 10} - }, - { {135, 193, 94, 208, 1}, - {164, 71, 148, 91, 2}, - {128, 183, 168, 62, 1}, - {77, 162, 158, 34, 5} - }, - { {177, 141, 71, 4, 14}, - {56, 91, 113, 98, 8}, - {114, 14, 43, 24, 13}, - {20, 104, 237, 161, 12} - }, - { {185, 96, 48, 55, 10}, - {11, 28, 163, 86, 5}, - {94, 192, 192, 105, 13}, - {166, 172, 83, 141, 0} - }, - { {57, 22, 249, 242, 5}, - {118, 136, 238, 120, 7}, - {164, 249, 246, 137, 12}, - {225, 231, 113, 22, 14} - }, - { {91, 245, 56, 225, 10}, - {67, 30, 23, 253, 6}, - {88, 113, 202, 253, 10}, - {107, 254, 135, 140, 2} - }, - { {69, 2, 140, 137, 3}, - {132, 177, 12, 196, 2}, - {201, 19, 20, 10, 2}, - {66, 51, 8, 210, 1} - }, - { {139, 247, 79, 21, 14}, - {123, 87, 221, 103, 0}, - {122, 143, 46, 253, 1}, - {14, 107, 190, 173, 14} - }, - { {52, 169, 38, 14, 14}, - {137, 123, 113, 0, 13}, - {119, 6, 73, 82, 12}, - {176, 8, 237, 233, 1} - }, - { {254, 161, 180, 87, 2}, - {139, 155, 176, 159, 5}, - {78, 162, 216, 87, 15}, - {175, 144, 221, 157, 1} - }, - { {170, 172, 74, 33, 2}, - {35, 80, 54, 39, 8}, - {72, 69, 35, 85, 5}, - {30, 70, 192, 172, 4} - }, - { {199, 149, 142, 146, 10}, - {192, 211, 149, 227, 3}, - {84, 151, 26, 158, 3}, - {204, 122, 156, 176, 3} - }, - { {77, 114, 150, 13, 7}, - {207, 245, 72, 212, 0}, - {235, 6, 148, 235, 2}, - {2, 177, 42, 255, 3} - }, - { {198, 113, 60, 138, 13}, - {197, 39, 69, 147, 7}, - {181, 19, 200, 230, 3}, - {236, 154, 46, 74, 3} - }, - { {26, 219, 8, 147, 10}, - {66, 30, 157, 5, 11}, - {92, 145, 13, 181, 8}, - {218, 11, 151, 132, 2} - }, - { {235, 178, 94, 21, 3}, - {111, 81, 188, 215, 0}, - {202, 135, 164, 221, 7}, - {14, 179, 216, 175, 6} - }, - { {26, 140, 101, 49, 13}, - {54, 9, 211, 37, 12}, - {184, 202, 99, 21, 8}, - {58, 76, 185, 6, 12} - }, - { {184, 194, 144, 210, 13}, - {6, 140, 249, 26, 3}, - {180, 176, 148, 49, 13}, - {197, 137, 243, 22, 0} - }, - { {237, 10, 185, 59, 12}, - {146, 160, 239, 214, 13}, - {61, 201, 213, 11, 7}, - {182, 191, 112, 84, 9} - }, - { {53, 64, 254, 171, 14}, - {160, 253, 103, 84, 7}, - {125, 87, 240, 42, 12}, - {226, 174, 107, 240, 5} - }, - { {77, 141, 169, 163, 10}, - {146, 146, 23, 228, 15}, - {92, 89, 91, 27, 2}, - {242, 126, 132, 148, 9} - }, - { {25, 111, 83, 7, 9}, - {63, 78, 9, 116, 9}, - {158, 12, 175, 105, 8}, - {146, 233, 7, 47, 12} - }, - { {170, 161, 45, 108, 8}, - {27, 35, 55, 11, 4}, - {19, 107, 72, 85, 5}, - {45, 14, 204, 77, 8} - }, - { {212, 51, 219, 225, 6}, - {241, 218, 78, 158, 2}, - {104, 125, 188, 194, 11}, - {71, 151, 37, 184, 15} - }, - { {41, 68, 117, 210, 10}, - {50, 21, 161, 120, 7}, - {84, 186, 226, 41, 4}, - {225, 232, 90, 132, 12} - }, - { {222, 189, 217, 145, 6}, - {243, 154, 212, 183, 10}, - {104, 153, 187, 215, 11}, - {94, 210, 181, 156, 15} - }, - { {123, 98, 241, 8, 1}, - {55, 172, 40, 209, 4}, - {129, 8, 244, 109, 14}, - {40, 177, 67, 94, 12} - }, - { {16, 243, 23, 219, 8}, - {81, 111, 153, 28, 3}, - {29, 190, 140, 240, 8}, - {195, 137, 159, 104, 10} - }, - { {184, 117, 135, 64, 5}, - {87, 207, 96, 42, 0}, - {160, 46, 26, 225, 13}, - {5, 64, 111, 62, 10} - }, - { {154, 182, 79, 175, 0}, - {123, 105, 30, 39, 3}, - {15, 95, 38, 213, 9}, - {206, 71, 137, 109, 14} - }, - { {212, 4, 243, 160, 1}, - {180, 200, 2, 178, 6}, - {128, 92, 242, 2, 11}, - {100, 212, 1, 50, 13} - }, - { {225, 106, 123, 127, 5}, - {61, 100, 238, 222, 13}, - {175, 237, 229, 104, 7}, - {183, 183, 114, 107, 12} - }, - { {12, 218, 188, 26, 8}, - {194, 165, 157, 16, 13}, - {21, 131, 213, 179, 0}, - {176, 139, 154, 84, 3} - }, - { {4, 96, 183, 149, 11}, - {157, 213, 129, 20, 6}, - {218, 158, 208, 98, 0}, - {98, 136, 26, 187, 9} - }, - { {28, 206, 196, 143, 3}, - {174, 189, 24, 36, 11}, - {207, 18, 55, 51, 8}, - {210, 65, 139, 215, 5} - }, - { {35, 222, 229, 165, 12}, - {120, 133, 123, 101, 14}, - {58, 90, 119, 188, 4}, - {122, 109, 234, 17, 14} - }, - { {99, 5, 255, 232, 5}, - {52, 227, 102, 249, 6}, - {161, 127, 250, 12, 6}, - {105, 246, 108, 114, 12} - }, - { {225, 195, 39, 185, 4}, - {16, 103, 250, 198, 6}, - {41, 222, 76, 56, 7}, - {102, 53, 254, 96, 8} - }, - { {140, 43, 164, 30, 0}, - {139, 163, 136, 2, 13}, - {7, 130, 93, 67, 1}, - {180, 1, 28, 93, 1} - }, - { {28, 217, 222, 180, 0}, - {234, 207, 150, 16, 10}, - {2, 215, 185, 179, 8}, - {80, 134, 159, 53, 7} - }, - { {85, 100, 240, 183, 1}, - {173, 140, 130, 244, 7}, - {142, 208, 242, 106, 10}, - {226, 244, 19, 27, 5} - }, - { {176, 199, 42, 118, 10}, - {8, 94, 191, 42, 5}, - {86, 229, 78, 48, 13}, - {165, 79, 215, 161, 0} - }, - { {231, 13, 80, 70, 9}, - {172, 2, 33, 251, 9}, - {150, 32, 171, 14, 7}, - {157, 248, 68, 3, 5} - }, - { {50, 149, 124, 126, 3}, - {108, 59, 182, 57, 5}, - {199, 227, 234, 148, 12}, - {169, 198, 221, 195, 6} - }, - { {71, 130, 81, 20, 11}, - {188, 16, 153, 209, 0}, - {210, 136, 164, 30, 2}, - {8, 185, 144, 131, 13} - }, - { {120, 242, 17, 22, 15}, - {95, 28, 249, 144, 1}, - {246, 136, 132, 241, 14}, - {128, 153, 243, 143, 10} - }, - { {144, 251, 64, 119, 10}, - {105, 30, 155, 14, 9}, - {94, 224, 45, 240, 9}, - {151, 13, 151, 137, 6} - }, - { {162, 111, 219, 64, 3}, - {53, 214, 44, 59, 8}, - {192, 45, 191, 100, 5}, - {29, 195, 70, 186, 12} - }, - { {36, 36, 50, 53, 7}, - {141, 80, 226, 52, 4}, - {234, 196, 194, 66, 4}, - {34, 196, 112, 171, 1} - }, - { {135, 138, 180, 213, 3}, - {140, 145, 152, 95, 14}, - {202, 178, 213, 30, 1}, - {127, 161, 152, 147, 1} - }, - { {238, 169, 194, 236, 0}, - {171, 226, 50, 139, 10}, - {3, 116, 57, 87, 7}, - {93, 20, 196, 125, 5} - }, - { {194, 91, 81, 134, 10}, - {120, 22, 9, 147, 11}, - {86, 24, 173, 164, 3}, - {220, 153, 6, 129, 14} - }, - { {154, 26, 220, 22, 4}, - {106, 137, 204, 19, 9}, - {38, 131, 181, 133, 9}, - {156, 131, 57, 21, 6} - }, - { {115, 131, 224, 101, 1}, - {44, 138, 58, 205, 4}, - {138, 96, 124, 28, 14}, - {43, 53, 197, 19, 4} - }, - { {25, 137, 191, 169, 14}, - {18, 251, 87, 84, 14}, - {121, 95, 217, 25, 8}, - {114, 174, 173, 244, 8} - }, - { {29, 136, 219, 124, 13}, - {190, 232, 215, 88, 8}, - {179, 237, 177, 27, 8}, - {17, 174, 177, 119, 13} - }, - { {58, 57, 201, 98, 1}, - {119, 138, 38, 9, 9}, - {132, 105, 57, 197, 12}, - {153, 6, 69, 30, 14} - }, - { {196, 95, 111, 141, 1}, - {252, 103, 12, 166, 14}, - {139, 31, 111, 162, 3}, - {118, 83, 14, 99, 15} - }, - { {127, 212, 244, 88, 13}, - {230, 173, 241, 249, 4}, - {177, 162, 242, 191, 14}, - {41, 248, 251, 86, 7} - }, - { {235, 94, 5, 198, 13}, - {94, 5, 105, 235, 11}, - {182, 58, 7, 173, 7}, - {221, 121, 106, 7, 10} - }, - { {0, 222, 87, 31, 10}, - {120, 117, 153, 52, 9}, - {95, 142, 167, 176, 0}, - {146, 201, 154, 225, 14} - }, - { {48, 182, 57, 119, 2}, - {89, 24, 190, 60, 5}, - {78, 233, 198, 208, 12}, - {163, 199, 209, 137, 10} - }, - { {217, 17, 79, 9, 9}, - {118, 107, 5, 198, 0}, - {153, 15, 40, 137, 11}, - {6, 58, 13, 102, 14} - }, - { {11, 138, 78, 254, 13}, - {46, 97, 223, 73, 11}, - {183, 247, 37, 29, 0}, - {217, 47, 184, 103, 4} - }, - { {150, 200, 148, 195, 5}, - {132, 141, 80, 31, 11}, - {172, 50, 145, 54, 9}, - {223, 128, 171, 18, 1} - }, - { {222, 86, 207, 27, 9}, - {246, 237, 141, 167, 1}, - {157, 143, 54, 167, 11}, - {142, 91, 27, 118, 15} - }, - { {233, 20, 44, 234, 11}, - {70, 49, 39, 234, 7}, - {213, 115, 66, 137, 7}, - {229, 126, 72, 198, 2} - }, - { {166, 193, 149, 63, 7}, - {156, 183, 242, 23, 1}, - {239, 202, 152, 54, 5}, - {142, 132, 254, 211, 9} - }, - { {112, 249, 99, 53, 11}, - {125, 94, 179, 132, 12}, - {218, 204, 105, 240, 14}, - {50, 28, 215, 171, 14} - }, - { {60, 210, 112, 229, 12}, - {234, 12, 123, 28, 6}, - {58, 112, 228, 179, 12}, - {99, 141, 227, 5, 7} - }, - { {67, 44, 58, 151, 8}, - {9, 64, 133, 245, 15}, - {30, 149, 195, 76, 2}, - {250, 250, 16, 41, 0} - }, - { {96, 54, 213, 83, 2}, - {113, 145, 168, 188, 1}, - {76, 170, 182, 192, 6}, - {131, 209, 88, 152, 14} - }, - { {135, 118, 248, 196, 14}, - {233, 148, 77, 123, 6}, - {114, 49, 246, 238, 1}, - {109, 235, 34, 153, 7} - }, - { {32, 85, 144, 158, 12}, - {72, 166, 225, 48, 3}, - {55, 144, 154, 160, 4}, - {192, 200, 118, 81, 2} - }, - { {51, 149, 147, 18, 0}, - {80, 202, 176, 113, 1}, - {4, 140, 154, 156, 12}, - {136, 224, 213, 48, 10} - }, - { {61, 129, 11, 57, 10}, - {146, 122, 183, 68, 0}, - {89, 205, 8, 27, 12}, - {2, 46, 213, 228, 9} - }, - { {39, 67, 30, 187, 2}, - {128, 119, 174, 85, 3}, - {77, 215, 140, 46, 4}, - {202, 167, 94, 224, 1} - }, - { {240, 133, 185, 233, 2}, - {16, 186, 54, 190, 6}, - {73, 121, 218, 16, 15}, - {103, 214, 197, 208, 8} - }, - { {163, 11, 146, 226, 0}, - {0, 194, 42, 91, 11}, - {4, 116, 157, 12, 5}, - {221, 165, 68, 48, 0} - }, - { {220, 20, 37, 232, 5}, - {214, 41, 66, 170, 6}, - {161, 122, 66, 131, 11}, - {101, 84, 41, 70, 11} - }, - { {180, 171, 135, 231, 11}, - {157, 219, 59, 14, 11}, - {222, 126, 29, 82, 13}, - {215, 13, 205, 187, 9} - }, - { {143, 183, 62, 39, 0}, - {203, 67, 30, 119, 5}, - {14, 71, 206, 223, 1}, - {174, 231, 140, 45, 3} - }, - { {255, 211, 18, 95, 2}, - {202, 126, 184, 223, 1}, - {79, 164, 140, 191, 15}, - {143, 177, 215, 229, 3} - }, - { {5, 76, 149, 162, 10}, - {144, 149, 3, 112, 11}, - {84, 90, 147, 42, 0}, - {208, 236, 10, 144, 9} - }, - { {29, 121, 189, 67, 6}, - {211, 159, 68, 92, 13}, - {108, 43, 217, 235, 8}, - {179, 162, 47, 156, 11} - }, - { {49, 220, 189, 155, 11}, - {84, 189, 181, 116, 15}, - {221, 155, 211, 184, 12}, - {242, 234, 219, 210, 10} - }, - { {93, 131, 76, 204, 2}, - {170, 59, 28, 200, 2}, - {67, 51, 44, 27, 10}, - {65, 51, 141, 197, 5} - }, - { {184, 110, 95, 128, 10}, - {51, 93, 45, 50, 10}, - {80, 31, 167, 97, 13}, - {84, 203, 75, 172, 12} - }, - { {221, 181, 2, 55, 14}, - {203, 90, 211, 230, 1}, - {126, 196, 10, 219, 11}, - {134, 124, 181, 173, 3} - }, - { {204, 212, 249, 32, 2}, - {242, 148, 22, 178, 4}, - {64, 73, 242, 179, 3}, - {36, 214, 130, 148, 15} - }, - { {222, 175, 20, 123, 3}, - {135, 59, 154, 191, 9}, - {205, 226, 143, 87, 11}, - {159, 213, 157, 206, 1} - }, - { {157, 32, 19, 22, 15}, - {159, 88, 193, 82, 1}, - {246, 140, 128, 75, 9}, - {132, 168, 49, 175, 9} - }, - { {124, 189, 240, 175, 1}, - {239, 170, 50, 180, 15}, - {143, 80, 251, 211, 14}, - {242, 212, 197, 95, 7} - }, - { {34, 195, 216, 114, 10}, - {32, 150, 191, 25, 1}, - {84, 225, 188, 52, 4}, - {137, 143, 214, 144, 4} - }, - { {69, 199, 100, 214, 12}, - {168, 7, 217, 232, 7}, - {54, 178, 110, 58, 2}, - {225, 121, 190, 1, 5} - }, - { {141, 147, 90, 116, 0}, - {234, 66, 158, 90, 0}, - {2, 229, 172, 155, 1}, - {5, 167, 148, 37, 7} - }, - { {177, 161, 236, 16, 8}, - {33, 139, 181, 66, 4}, - {16, 131, 120, 88, 13}, - {36, 42, 221, 24, 4} - }, - { {208, 121, 53, 51, 6}, - {81, 31, 194, 150, 13}, - {108, 202, 201, 224, 11}, - {182, 148, 63, 136, 10} - }, - { {74, 81, 93, 164, 6}, - {122, 23, 70, 145, 2}, - {98, 91, 168, 165, 2}, - {72, 150, 46, 133, 14} - }, - { {58, 45, 19, 35, 5}, - {23, 74, 98, 53, 9}, - {172, 76, 139, 69, 12}, - {154, 196, 101, 46, 8} - }, - { {236, 65, 230, 22, 1}, - {174, 199, 160, 130, 5}, - {134, 134, 120, 35, 7}, - {164, 16, 94, 55, 5} - }, - { {127, 172, 78, 24, 2}, - {163, 121, 180, 225, 8}, - {65, 135, 35, 95, 14}, - {24, 114, 217, 236, 5} - }, - { {115, 198, 100, 107, 13}, - {36, 45, 123, 237, 5}, - {189, 98, 102, 60, 14}, - {171, 125, 235, 66, 4} - }, - { {77, 251, 76, 21, 7}, - {239, 23, 220, 196, 8}, - {234, 131, 45, 251, 2}, - {18, 51, 190, 143, 7} - }, - { {229, 15, 78, 90, 11}, - {164, 115, 173, 234, 9}, - {213, 167, 47, 10, 7}, - {149, 123, 92, 226, 5} - }, - { {122, 161, 57, 166, 0}, - {27, 10, 54, 145, 7}, - {6, 89, 200, 85, 14}, - {232, 150, 197, 13, 8} - }, - { {18, 122, 254, 87, 13}, - {109, 205, 205, 29, 13}, - {190, 167, 245, 228, 8}, - {187, 139, 59, 59, 6} - }, - { {168, 230, 106, 159, 15}, - {47, 116, 253, 38, 7}, - {255, 149, 102, 113, 5}, - {230, 75, 242, 239, 4} - }, - { {89, 155, 96, 189, 8}, - {106, 42, 155, 196, 14}, - {27, 208, 109, 153, 10}, - {114, 61, 149, 69, 6} - }, - { {49, 234, 54, 102, 9}, - {13, 77, 59, 88, 13}, - {150, 102, 197, 120, 12}, - {177, 173, 203, 43, 0} - }, - { {55, 203, 228, 166, 3}, - {172, 159, 58, 65, 15}, - {198, 82, 125, 62, 12}, - {248, 37, 207, 147, 5} - }, - { {134, 60, 248, 42, 13}, - {229, 160, 71, 51, 13}, - {181, 65, 243, 198, 1}, - {188, 206, 32, 90, 7} - }, - { {14, 181, 149, 30, 6}, - {219, 179, 208, 49, 1}, - {103, 138, 154, 215, 0}, - {136, 192, 188, 221, 11} - }, - { {197, 251, 85, 118, 12}, - {249, 7, 219, 218, 9}, - {54, 234, 173, 250, 3}, - {149, 189, 190, 9, 15} - }, - { {123, 128, 210, 239, 5}, - {46, 232, 114, 221, 3}, - {175, 116, 176, 29, 14}, - {203, 180, 225, 119, 4} - }, - { {195, 179, 195, 50, 10}, - {113, 210, 155, 195, 1}, - {84, 204, 60, 220, 3}, - {140, 61, 148, 184, 14} - }, - { {103, 62, 26, 116, 11}, - {205, 80, 175, 249, 8}, - {210, 229, 135, 206, 6}, - {25, 255, 80, 171, 3} - }, - { {146, 201, 210, 150, 1}, - {44, 206, 144, 19, 11}, - {134, 148, 185, 52, 9}, - {220, 128, 151, 51, 4} - }, - { {127, 25, 25, 12, 11}, - {222, 58, 37, 209, 8}, - {211, 9, 137, 143, 14}, - {24, 186, 69, 199, 11} - }, - { {144, 112, 164, 195, 10}, - {65, 157, 1, 14, 7}, - {92, 50, 80, 224, 9}, - {231, 8, 11, 152, 2} - }, - { {113, 67, 83, 178, 1}, - {52, 78, 170, 208, 3}, - {132, 220, 172, 40, 14}, - {192, 181, 87, 34, 12} - }, - { {251, 75, 181, 78, 15}, - {30, 191, 105, 219, 13}, - {247, 42, 221, 45, 15}, - {189, 185, 111, 215, 8} - }, - { {197, 129, 104, 9, 8}, - {160, 34, 21, 198, 4}, - {25, 1, 104, 26, 3}, - {38, 58, 132, 64, 5} - }, - { {43, 241, 86, 121, 0}, - {99, 103, 178, 93, 0}, - {9, 230, 168, 253, 4}, - {11, 164, 222, 108, 6} - }, - { {139, 50, 134, 244, 8}, - {75, 193, 139, 75, 2}, - {18, 246, 20, 205, 1}, - {77, 45, 24, 61, 2} - }, - { {35, 88, 1, 235, 6}, - {80, 52, 98, 77, 11}, - {109, 120, 1, 172, 4}, - {219, 36, 98, 192, 10} - }, - { {42, 83, 143, 50, 8}, - {82, 199, 175, 1, 1}, - {20, 207, 28, 165, 4}, - {136, 15, 94, 52, 10} - }, - { {16, 109, 126, 84, 8}, - {41, 79, 133, 56, 12}, - {18, 167, 235, 96, 8}, - {49, 202, 31, 41, 4} - }, - { {70, 253, 197, 231, 10}, - {249, 151, 19, 173, 11}, - {94, 122, 59, 246, 2}, - {219, 92, 142, 153, 15} - }, - { {69, 106, 10, 93, 0}, - {137, 100, 140, 204, 8}, - {11, 165, 5, 106, 2}, - {19, 51, 18, 105, 1} - }, - { {217, 50, 39, 125, 10}, - {91, 121, 139, 206, 4}, - {91, 238, 68, 201, 11}, - {39, 61, 25, 237, 10} - }, - { {97, 59, 235, 152, 1}, - {117, 226, 172, 192, 14}, - {129, 157, 125, 200, 6}, - {112, 51, 84, 122, 14} - }, - { {191, 19, 181, 70, 0}, - {218, 139, 40, 91, 5}, - {6, 42, 220, 143, 13}, - {173, 161, 77, 21, 11} - }, - { {130, 186, 168, 203, 13}, - {69, 160, 93, 15, 15}, - {189, 49, 85, 212, 1}, - {255, 11, 160, 90, 2} - }, - { {81, 205, 99, 27, 3}, - {52, 126, 144, 228, 13}, - {205, 140, 107, 56, 10}, - {178, 112, 151, 226, 12} - }, - { {112, 171, 240, 76, 7}, - {45, 186, 120, 152, 12}, - {227, 32, 253, 80, 14}, - {49, 145, 229, 219, 4} - }, - { {170, 102, 185, 24, 7}, - {23, 180, 236, 51, 4}, - {225, 137, 214, 101, 5}, - {44, 195, 114, 222, 8} - }, - { {140, 20, 60, 97, 6}, - {194, 17, 70, 62, 4}, - {104, 99, 194, 131, 1}, - {39, 198, 40, 132, 3} - }, - { {241, 160, 157, 75, 0}, - {17, 169, 52, 222, 1}, - {13, 43, 144, 88, 15}, - {135, 178, 201, 88, 8} - }, - { {95, 27, 95, 220, 4}, - {250, 107, 204, 217, 10}, - {35, 191, 173, 143, 10}, - {89, 179, 61, 101, 15} - }, - { {104, 72, 189, 153, 8}, - {18, 165, 165, 148, 14}, - {25, 155, 209, 33, 6}, - {114, 154, 90, 84, 8} - }, - { {235, 245, 28, 134, 10}, - {75, 23, 53, 243, 3}, - {86, 19, 138, 253, 7}, - {204, 250, 206, 141, 2} - }, - { {201, 92, 23, 53, 15}, - {94, 85, 195, 246, 8}, - {250, 206, 131, 169, 3}, - {22, 252, 58, 167, 10} - }, - { {164, 229, 178, 170, 9}, - {133, 230, 51, 50, 7}, - {149, 84, 218, 114, 5}, - {228, 204, 198, 122, 1} - }, - { {137, 187, 40, 109, 9}, - {79, 34, 31, 78, 12}, - {155, 97, 77, 217, 1}, - {55, 47, 132, 79, 2} - }, - { {252, 83, 211, 81, 9}, - {246, 206, 169, 158, 0}, - {152, 172, 188, 163, 15}, - {7, 153, 87, 54, 15} - }, - { {132, 250, 176, 250, 11}, - {197, 180, 155, 26, 15}, - {213, 240, 213, 242, 1}, - {245, 141, 146, 218, 3} - }, - { {135, 156, 9, 173, 7}, - {220, 48, 86, 103, 10}, - {235, 89, 3, 158, 1}, - {94, 102, 160, 195, 11} - }, - { {84, 19, 120, 184, 10}, - {224, 58, 143, 144, 6}, - {81, 209, 236, 130, 10}, - {96, 159, 21, 192, 7} - }, - { {93, 207, 118, 108, 5}, - {174, 111, 90, 248, 12}, - {163, 102, 239, 59, 10}, - {49, 245, 175, 103, 5} - }, - { {15, 128, 112, 181, 8}, - {170, 0, 147, 85, 6}, - {26, 208, 224, 31, 0}, - {106, 172, 144, 5, 5} - }, - { {208, 181, 28, 15, 14}, - {73, 59, 85, 182, 1}, - {127, 3, 138, 208, 11}, - {134, 218, 173, 201, 2} - }, - { {132, 202, 160, 119, 12}, - {136, 132, 219, 14, 13}, - {62, 224, 85, 50, 1}, - {183, 13, 178, 17, 1} - }, - { {237, 211, 180, 253, 12}, - {202, 167, 251, 222, 6}, - {59, 242, 220, 187, 7}, - {103, 189, 254, 85, 3} - }, - { {54, 161, 151, 8, 4}, - {145, 235, 112, 17, 0}, - {33, 14, 152, 86, 12}, - {8, 128, 237, 120, 9} - }, - { {140, 65, 87, 242, 7}, - {182, 87, 194, 26, 3}, - {228, 254, 168, 35, 1}, - {197, 132, 62, 166, 13} - }, - { {236, 146, 34, 145, 13}, - {198, 64, 249, 134, 6}, - {184, 148, 68, 147, 7}, - {102, 25, 240, 38, 3} - }, - { {44, 51, 74, 17, 10}, - {227, 82, 173, 4, 0}, - {88, 133, 44, 195, 4}, - {2, 11, 84, 172, 7} - }, - { {149, 119, 148, 119, 8}, - {201, 143, 139, 126, 1}, - {30, 226, 158, 234, 9}, - {135, 237, 31, 25, 3} - }, - { {79, 158, 57, 137, 13}, - {214, 32, 93, 245, 14}, - {185, 25, 199, 159, 2}, - {122, 251, 160, 70, 11} - }, - { {181, 203, 34, 59, 11}, - {132, 126, 187, 70, 13}, - {221, 196, 77, 58, 13}, - {182, 45, 215, 226, 1} - }, - { {238, 226, 189, 59, 11}, - {151, 181, 191, 151, 5}, - {221, 203, 212, 119, 7}, - {174, 159, 218, 222, 9} - }, - { {133, 212, 25, 195, 12}, - {208, 4, 85, 126, 3}, - {60, 57, 130, 186, 1}, - {199, 234, 162, 0, 11} - }, - { {186, 35, 215, 19, 11}, - {55, 219, 169, 23, 1}, - {220, 142, 188, 69, 13}, - {142, 137, 93, 190, 12} - }, - { {141, 72, 238, 157, 1}, - {174, 229, 132, 70, 14}, - {139, 151, 113, 43, 1}, - {118, 34, 26, 119, 5} - }, - { {120, 69, 116, 14, 9}, - {46, 47, 33, 176, 5}, - {151, 2, 234, 33, 14}, - {160, 216, 79, 71, 4} - }, - { {100, 231, 234, 47, 8}, - {169, 230, 63, 164, 5}, - {31, 69, 126, 114, 6}, - {162, 95, 198, 121, 5} - }, - { {100, 118, 246, 62, 4}, - {233, 229, 234, 176, 5}, - {39, 198, 246, 226, 6}, - {160, 213, 122, 121, 7} - }, - { {14, 238, 158, 149, 0}, - {139, 197, 156, 53, 10}, - {10, 151, 151, 119, 0}, - {90, 195, 154, 61, 1} - }, - { {220, 175, 168, 110, 11}, - {143, 186, 31, 170, 13}, - {215, 97, 95, 83, 11}, - {181, 95, 133, 223, 1} - }, - { {135, 109, 56, 242, 14}, - {129, 22, 199, 123, 15}, - {116, 241, 203, 110, 1}, - {253, 238, 54, 136, 1} - }, - { {59, 235, 39, 76, 5}, - {31, 111, 120, 73, 12}, - {163, 46, 77, 125, 12}, - {57, 33, 239, 111, 8} - }, - { {184, 191, 89, 23, 4}, - {123, 10, 252, 54, 9}, - {46, 137, 175, 209, 13}, - {150, 195, 245, 13, 14} - }, - { {171, 32, 236, 13, 0}, - {43, 161, 36, 71, 4}, - {11, 3, 112, 77, 5}, - {46, 34, 72, 93, 4} - }, - { {13, 85, 26, 83, 3}, - {198, 86, 132, 124, 1}, - {204, 165, 138, 171, 0}, - {131, 226, 22, 166, 3} - }, - { {164, 73, 46, 167, 8}, - {136, 71, 39, 6, 15}, - {30, 87, 73, 34, 5}, - {246, 14, 78, 33, 1} - }, - { {93, 108, 92, 103, 6}, - {171, 29, 70, 252, 9}, - {110, 99, 163, 107, 10}, - {147, 246, 43, 141, 5} - }, - { {153, 4, 153, 70, 10}, - {26, 152, 5, 122, 1}, - {86, 41, 146, 9, 9}, - {133, 234, 1, 149, 8} - }, - { {10, 157, 128, 226, 6}, - {66, 146, 82, 41, 11}, - {100, 112, 27, 149, 0}, - {217, 68, 164, 148, 2} - }, - { {105, 134, 183, 41, 15}, - {22, 241, 123, 244, 4}, - {249, 78, 214, 25, 6}, - {34, 253, 232, 246, 8} - }, - { {143, 173, 130, 44, 13}, - {143, 226, 83, 99, 8}, - {179, 68, 27, 95, 1}, - {28, 108, 164, 127, 1} - }, - { {226, 67, 95, 38, 3}, - {60, 87, 46, 147, 1}, - {198, 79, 172, 36, 7}, - {140, 151, 78, 163, 12} - }, - { {209, 155, 215, 78, 11}, - {124, 251, 25, 218, 9}, - {215, 46, 189, 152, 11}, - {149, 185, 141, 243, 14} - }, - { {196, 218, 25, 133, 15}, - {220, 20, 93, 150, 10}, - {250, 25, 133, 178, 3}, - {86, 155, 162, 131, 11} - }, - { {26, 193, 30, 251, 4}, - {2, 111, 214, 29, 3}, - {45, 247, 136, 53, 8}, - {203, 134, 191, 100, 0} - }, - { {17, 45, 28, 17, 1}, - {5, 11, 132, 116, 8}, - {136, 131, 139, 72, 8}, - {18, 226, 29, 10, 0} - }, - { {45, 76, 8, 144, 6}, - {130, 20, 228, 96, 10}, - {96, 145, 3, 43, 4}, - {80, 98, 114, 132, 1} - }, - { {108, 235, 79, 250, 4}, - {179, 103, 254, 136, 11}, - {37, 255, 45, 115, 6}, - {209, 23, 254, 108, 13} - }, - { {171, 203, 198, 115, 11}, - {38, 215, 187, 79, 9}, - {220, 230, 61, 61, 5}, - {159, 45, 222, 182, 4} - }, - { {40, 32, 233, 173, 13}, - {63, 160, 103, 4, 6}, - {187, 89, 112, 65, 4}, - {98, 14, 96, 95, 12} - }, - { {127, 250, 209, 178, 2}, - {243, 156, 186, 209, 11}, - {68, 216, 181, 255, 14}, - {216, 181, 211, 156, 15} - }, - { {27, 102, 106, 88, 7}, - {39, 124, 204, 105, 4}, - {225, 165, 102, 109, 8}, - {41, 99, 51, 238, 4} - }, - { {164, 137, 72, 44, 7}, - {172, 50, 118, 2, 8}, - {227, 65, 41, 18, 5}, - {20, 6, 228, 195, 5} - }, - { {141, 42, 28, 71, 0}, - {139, 1, 12, 94, 9}, - {14, 35, 133, 75, 1}, - {151, 163, 8, 13, 1} - }, - { {125, 182, 84, 216, 0}, - {227, 41, 184, 248, 2}, - {1, 178, 166, 219, 14}, - {65, 241, 217, 76, 7} - }, - { {179, 222, 10, 136, 11}, - {68, 124, 61, 99, 10}, - {209, 21, 7, 188, 13}, - {92, 107, 195, 226, 2} - }, - { {214, 120, 202, 34, 1}, - {229, 204, 6, 131, 9}, - {132, 69, 49, 230, 11}, - {156, 22, 3, 58, 7} - }, - { {136, 97, 82, 97, 11}, - {39, 86, 3, 30, 0}, - {216, 100, 168, 97, 1}, - {7, 140, 6, 174, 4} - }, - { {0, 238, 90, 84, 7}, - {45, 84, 220, 56, 8}, - {226, 165, 167, 112, 0}, - {17, 195, 178, 171, 4} - }, - { {84, 105, 30, 139, 4}, - {129, 111, 68, 148, 11}, - {45, 23, 137, 98, 10}, - {210, 146, 47, 104, 1} - }, - { {128, 254, 13, 106, 8}, - {81, 37, 31, 42, 9}, - {21, 107, 7, 240, 1}, - {149, 79, 138, 72, 10} - }, - { {195, 127, 154, 209, 2}, - {65, 214, 140, 255, 10}, - {72, 181, 159, 236, 3}, - {95, 243, 22, 184, 2} - }, - { {57, 235, 155, 203, 12}, - {19, 238, 125, 92, 11}, - {61, 61, 157, 121, 12}, - {211, 171, 231, 124, 8} - }, - { {156, 205, 246, 33, 8}, - {162, 207, 19, 54, 12}, - {24, 70, 251, 51, 9}, - {54, 204, 143, 52, 5} - }, - { {83, 192, 184, 251, 11}, - {4, 188, 151, 221, 7}, - {221, 241, 208, 60, 10}, - {235, 190, 147, 210, 0} - }, - { {159, 93, 81, 153, 0}, - {242, 46, 128, 119, 10}, - {9, 152, 171, 175, 9}, - {94, 224, 23, 68, 15} - }, - { {208, 152, 110, 185, 3}, - {100, 121, 150, 134, 14}, - {201, 215, 97, 144, 11}, - {118, 22, 153, 226, 6} - }, - { {21, 133, 42, 206, 6}, - {136, 122, 84, 104, 7}, - {103, 53, 74, 26, 8}, - {225, 98, 165, 225, 1} - }, - { {144, 212, 121, 19, 3}, - {116, 28, 148, 54, 5}, - {204, 137, 226, 176, 9}, - {166, 194, 147, 130, 14} - }, - { {44, 22, 172, 202, 12}, - {194, 161, 109, 40, 7}, - {53, 51, 86, 131, 4}, - {225, 75, 104, 84, 3} - }, - { {112, 226, 233, 181, 14}, - {57, 156, 255, 132, 6}, - {122, 217, 116, 112, 14}, - {98, 31, 243, 153, 12} - }, - { {36, 160, 106, 178, 15}, - {165, 80, 247, 0, 7}, - {244, 213, 96, 82, 4}, - {224, 14, 240, 170, 5} - }, - { {114, 1, 237, 44, 10}, - {56, 187, 39, 129, 4}, - {83, 75, 120, 4, 14}, - {40, 30, 77, 209, 12} - }, - { {76, 99, 9, 66, 8}, - {147, 6, 13, 136, 1}, - {20, 41, 12, 99, 2}, - {129, 27, 6, 12, 9} - }, - { {6, 185, 203, 230, 13}, - {253, 194, 87, 9, 11}, - {182, 125, 57, 214, 0}, - {217, 14, 164, 59, 15} - }, - { {215, 246, 104, 218, 12}, - {225, 44, 221, 235, 7}, - {53, 177, 102, 254, 11}, - {237, 123, 179, 72, 7} - }, - { {129, 109, 246, 113, 1}, - {37, 199, 130, 126, 12}, - {136, 230, 251, 104, 1}, - {55, 228, 30, 58, 4} - }, - { {88, 117, 65, 240, 5}, - {119, 14, 194, 168, 2}, - {160, 248, 42, 225, 10}, - {65, 84, 55, 14, 14} - }, - { {74, 115, 6, 33, 0}, - {67, 71, 10, 133, 0}, - {8, 70, 12, 229, 2}, - {10, 21, 14, 44, 2} - }, - { {72, 9, 86, 13, 1}, - {46, 99, 0, 148, 8}, - {139, 6, 169, 1, 2}, - {18, 144, 12, 103, 4} - }, - { {59, 153, 72, 245, 11}, - {110, 26, 183, 77, 10}, - {218, 241, 41, 157, 12}, - {91, 46, 213, 135, 6} - }, - { {54, 150, 213, 148, 6}, - {248, 153, 248, 49, 2}, - {98, 154, 182, 150, 12}, - {72, 193, 249, 145, 15} - }, - { {81, 34, 220, 136, 12}, - {33, 169, 77, 208, 2}, - {49, 19, 180, 72, 10}, - {64, 187, 41, 88, 4} - }, - { {168, 69, 58, 219, 0}, - {2, 102, 164, 62, 7}, - {13, 181, 202, 33, 5}, - {231, 194, 86, 100, 0} - }, - { {180, 120, 208, 7, 12}, - {233, 140, 97, 22, 9}, - {62, 0, 177, 226, 13}, - {150, 136, 99, 25, 7} - }, - { {213, 175, 225, 90, 1}, - {181, 170, 152, 234, 13}, - {133, 168, 127, 90, 11}, - {181, 113, 149, 90, 13} - }, - { {4, 255, 169, 156, 13}, - {221, 166, 221, 32, 14}, - {179, 153, 95, 242, 0}, - {112, 75, 182, 91, 11} - }, - { {178, 170, 134, 106, 1}, - {5, 233, 58, 11, 9}, - {133, 102, 21, 84, 13}, - {157, 5, 201, 122, 0} - }, - { {33, 202, 57, 14, 7}, - {28, 52, 124, 80, 13}, - {231, 9, 197, 56, 4}, - {176, 163, 226, 195, 8} - }, - { {217, 149, 56, 136, 0}, - {66, 42, 20, 242, 6}, - {1, 17, 202, 153, 11}, - {100, 242, 133, 68, 2} - }, - { {158, 66, 134, 121, 2}, - {130, 253, 138, 15, 0}, - {73, 230, 20, 39, 9}, - {15, 5, 27, 244, 1} - }, - { {35, 126, 230, 40, 15}, - {101, 245, 107, 97, 12}, - {241, 70, 119, 236, 4}, - {56, 109, 106, 250, 6} - }, - { {223, 217, 194, 111, 1}, - {238, 238, 18, 207, 9}, - {143, 100, 57, 191, 11}, - {159, 52, 135, 119, 7} - }, - { {134, 37, 95, 146, 14}, - {177, 83, 197, 51, 3}, - {116, 159, 170, 70, 1}, - {204, 202, 60, 168, 13} - }, - { {89, 24, 159, 35, 8}, - {82, 201, 7, 212, 9}, - {28, 79, 145, 137, 10}, - {146, 190, 9, 52, 10} - }, - { {83, 168, 9, 113, 7}, - {21, 24, 214, 205, 8}, - {232, 233, 1, 92, 10}, - {27, 54, 177, 138, 8} - }, - { {8, 171, 22, 118, 15}, - {15, 83, 219, 24, 9}, - {246, 230, 141, 81, 0}, - {145, 141, 188, 175, 0} - }, - { {249, 140, 152, 28, 13}, - {14, 168, 245, 242, 8}, - {179, 129, 147, 25, 15}, - {20, 250, 241, 87, 0} - }, - { {249, 136, 239, 149, 11}, - {62, 217, 181, 198, 14}, - {218, 159, 113, 25, 15}, - {118, 58, 217, 183, 12} - }, - { {31, 2, 254, 30, 14}, - {170, 249, 205, 81, 5}, - {119, 135, 244, 15, 8}, - {168, 171, 57, 245, 5} - }, - { {104, 234, 254, 163, 13}, - {39, 197, 127, 148, 15}, - {188, 87, 245, 113, 6}, - {242, 159, 234, 62, 4} - }, - { {126, 145, 79, 240, 6}, - {242, 91, 246, 137, 2}, - {96, 255, 40, 151, 14}, - {73, 22, 253, 164, 15} - }, - { {44, 149, 20, 92, 13}, - {206, 35, 241, 56, 0}, - {179, 162, 138, 147, 4}, - {1, 200, 252, 71, 3} - }, - { {62, 147, 44, 208, 8}, - {194, 11, 189, 9, 6}, - {16, 179, 76, 151, 12}, - {105, 11, 221, 4, 3} - }, - { {183, 92, 175, 40, 3}, - {212, 253, 38, 99, 12}, - {193, 79, 83, 174, 13}, - {60, 102, 75, 242, 11} - }, - { {186, 245, 114, 60, 11}, - {111, 126, 179, 51, 4}, - {211, 196, 234, 245, 13}, - {44, 204, 215, 239, 6} - }, - { {121, 203, 18, 140, 13}, - {14, 110, 121, 208, 10}, - {179, 20, 141, 57, 14}, - {80, 185, 231, 103, 0} - }, - { {64, 87, 46, 30, 0}, - {72, 103, 140, 160, 5}, - {7, 135, 78, 160, 2}, - {160, 83, 30, 97, 2} - }, - { {82, 212, 150, 97, 15}, - {68, 221, 83, 189, 0}, - {248, 102, 146, 180, 10}, - {11, 220, 171, 178, 2} - }, - { {177, 112, 92, 13, 10}, - {105, 61, 37, 86, 0}, - {91, 3, 160, 232, 13}, - {6, 170, 75, 201, 6} - }, - { {99, 49, 219, 103, 3}, - {125, 210, 38, 221, 1}, - {206, 109, 184, 204, 6}, - {139, 182, 68, 187, 14} - }, - { {16, 154, 188, 196, 1}, - {76, 137, 28, 24, 14}, - {130, 51, 213, 144, 8}, - {113, 131, 137, 19, 2} - }, - { {96, 60, 124, 104, 15}, - {101, 49, 103, 184, 12}, - {241, 99, 227, 192, 6}, - {49, 222, 104, 202, 6} - }, - { {115, 50, 161, 255, 11}, - {93, 184, 171, 205, 7}, - {223, 248, 84, 204, 14}, - {235, 61, 81, 219, 10} - }, - { {61, 143, 96, 230, 4}, - {170, 10, 122, 104, 15}, - {38, 112, 111, 27, 12}, - {241, 101, 229, 5, 5} - }, - { {202, 97, 172, 50, 9}, - {7, 135, 135, 131, 5}, - {148, 195, 88, 101, 3}, - {172, 30, 30, 30, 0} - }, - { {132, 25, 50, 28, 14}, - {200, 114, 193, 18, 12}, - {115, 132, 201, 130, 1}, - {52, 136, 52, 225, 3} - }, - { {171, 167, 29, 138, 7}, - {23, 51, 124, 115, 3}, - {229, 27, 142, 93, 5}, - {204, 227, 236, 206, 8} - }, - { {220, 105, 76, 91, 7}, - {167, 63, 196, 142, 9}, - {237, 163, 41, 99, 11}, - {151, 18, 63, 206, 5} - }, - { {244, 156, 252, 224, 5}, - {228, 137, 118, 186, 14}, - {160, 115, 243, 146, 15}, - {117, 214, 233, 18, 7} - }, - { {200, 69, 243, 60, 3}, - {62, 246, 130, 178, 4}, - {195, 204, 250, 33, 3}, - {36, 212, 22, 247, 12} - }, - { {104, 74, 251, 82, 12}, - {50, 196, 237, 152, 13}, - {52, 173, 245, 33, 6}, - {177, 155, 114, 52, 12} - }, - { {214, 20, 91, 29, 3}, - {252, 120, 132, 183, 0}, - {203, 141, 162, 134, 11}, - {14, 210, 17, 227, 15} - }, - { {16, 253, 223, 173, 12}, - {121, 239, 87, 52, 10}, - {59, 95, 187, 240, 8}, - {82, 206, 175, 121, 14} - }, - { {31, 139, 72, 20, 8}, - {170, 10, 157, 65, 8}, - {18, 129, 45, 31, 8}, - {24, 43, 149, 5, 5} - }, - { {156, 50, 163, 233, 3}, - {215, 248, 10, 14, 6}, - {201, 124, 84, 195, 9}, - {103, 5, 1, 254, 11} - }, - { {157, 108, 124, 56, 7}, - {167, 61, 198, 114, 12}, - {225, 195, 227, 107, 9}, - {52, 230, 59, 206, 5} - }, - { {183, 3, 177, 221, 5}, - {156, 170, 232, 95, 6}, - {171, 184, 220, 14, 13}, - {111, 161, 117, 83, 9} - }, - { {111, 221, 59, 152, 0}, - {210, 102, 180, 241, 14}, - {1, 157, 203, 191, 6}, - {120, 242, 214, 100, 11} - }, - { {178, 62, 176, 218, 4}, - {65, 168, 232, 59, 15}, - {37, 176, 215, 196, 13}, - {253, 193, 113, 88, 2} - }, - { {115, 173, 103, 162, 0}, - {49, 75, 50, 225, 15}, - {4, 94, 107, 92, 14}, - {248, 116, 205, 40, 12} - }, - { {83, 97, 3, 190, 8}, - {25, 110, 131, 193, 3}, - {23, 220, 8, 108, 10}, - {200, 60, 23, 105, 8} - }, - { {214, 122, 66, 252, 3}, - {237, 124, 138, 139, 10}, - {195, 244, 37, 230, 11}, - {93, 21, 19, 235, 7} - }, - { {31, 40, 119, 191, 6}, - {187, 121, 194, 85, 15}, - {111, 222, 225, 79, 8}, - {250, 164, 57, 237, 13} - }, - { {45, 103, 170, 137, 12}, - {131, 230, 109, 100, 6}, - {57, 21, 94, 107, 4}, - {98, 107, 102, 124, 1} - }, - { {168, 55, 137, 133, 0}, - {91, 130, 44, 38, 2}, - {10, 25, 30, 193, 5}, - {70, 67, 68, 29, 10} - }, - { {47, 235, 63, 25, 12}, - {147, 103, 253, 85, 12}, - {57, 143, 205, 127, 4}, - {58, 171, 254, 108, 9} - }, - { {41, 160, 212, 118, 5}, - {47, 129, 242, 88, 1}, - {166, 226, 176, 89, 4}, - {129, 164, 248, 31, 4} - }, - { {65, 177, 230, 167, 15}, - {109, 211, 83, 196, 7}, - {254, 86, 120, 216, 2}, - {226, 60, 172, 187, 6} - }, - { {248, 93, 126, 140, 7}, - {110, 127, 100, 178, 14}, - {227, 23, 235, 161, 15}, - {116, 210, 111, 231, 6} - }, - { {133, 48, 143, 35, 4}, - {209, 193, 70, 70, 1}, - {44, 79, 16, 202, 1}, - {134, 38, 40, 56, 11} - }, - { {121, 131, 156, 71, 5}, - {14, 139, 124, 220, 1}, - {174, 35, 156, 25, 14}, - {131, 179, 237, 23, 0} - }, - { {75, 124, 102, 113, 8}, - {99, 69, 131, 237, 12}, - {24, 230, 99, 237, 2}, - {59, 124, 26, 44, 6} - }, - { {231, 237, 2, 5, 2}, - {137, 86, 48, 231, 8}, - {74, 4, 11, 126, 7}, - {30, 112, 198, 169, 1} - }, - { {57, 33, 5, 61, 13}, - {31, 43, 227, 68, 0}, - {187, 202, 8, 73, 12}, - {2, 44, 125, 79, 8} - }, - { {46, 92, 218, 7, 3}, - {238, 212, 36, 53, 9}, - {206, 5, 179, 167, 4}, - {154, 194, 66, 183, 7} - }, - { {191, 65, 151, 115, 14}, - {146, 223, 227, 95, 1}, - {124, 238, 152, 47, 13}, - {143, 172, 127, 180, 9} - }, - { {229, 242, 167, 113, 14}, - {209, 213, 251, 206, 4}, - {120, 238, 84, 250, 7}, - {39, 61, 250, 184, 11} - }, - { {189, 13, 222, 45, 14}, - {170, 251, 103, 118, 8}, - {123, 71, 187, 11, 13}, - {22, 238, 109, 245, 5} - }, - { {104, 73, 143, 23, 14}, - {26, 215, 229, 132, 9}, - {126, 143, 25, 33, 6}, - {146, 26, 126, 181, 8} - }, - { {183, 56, 155, 230, 11}, - {221, 216, 39, 91, 11}, - {214, 125, 145, 206, 13}, - {221, 174, 65, 187, 11} - }, - { {41, 127, 247, 175, 7}, - {127, 247, 106, 116, 15}, - {239, 94, 255, 233, 4}, - {242, 229, 110, 255, 14} - }, - { {177, 201, 139, 131, 7}, - {20, 222, 116, 70, 11}, - {236, 29, 25, 56, 13}, - {214, 34, 231, 178, 8} - }, - { {112, 239, 122, 3, 2}, - {33, 94, 60, 180, 13}, - {76, 5, 239, 112, 14}, - {178, 211, 199, 168, 4} - }, - { {155, 66, 34, 76, 0}, - {10, 108, 8, 75, 4}, - {3, 36, 68, 45, 9}, - {45, 33, 3, 101, 0} - }, - { {45, 220, 24, 13, 15}, - {206, 52, 117, 116, 8}, - {251, 1, 131, 187, 4}, - {18, 234, 226, 199, 3} - }, - { {10, 189, 5, 237, 15}, - {95, 51, 83, 45, 10}, - {251, 122, 11, 213, 0}, - {91, 76, 172, 207, 10} - }, - { {225, 190, 133, 89, 1}, - {85, 161, 184, 238, 8}, - {137, 170, 23, 216, 7}, - {23, 113, 216, 90, 10} - }, - { {145, 183, 86, 114, 7}, - {101, 91, 218, 122, 1}, - {228, 230, 174, 216, 9}, - {133, 229, 189, 170, 6} - }, - { {45, 22, 243, 125, 11}, - {254, 240, 171, 124, 4}, - {219, 236, 246, 139, 4}, - {35, 237, 80, 247, 15} - }, - { {39, 176, 238, 193, 6}, - {225, 209, 116, 77, 6}, - {104, 55, 112, 222, 4}, - {107, 34, 232, 184, 7} - }, - { {108, 133, 130, 249, 13}, - {134, 226, 243, 172, 2}, - {185, 244, 26, 19, 6}, - {67, 92, 244, 118, 1} - }, - { {115, 83, 40, 110, 3}, - {76, 62, 46, 201, 5}, - {199, 97, 76, 172, 14}, - {169, 55, 71, 195, 2} - }, - { {97, 193, 148, 57, 1}, - {4, 167, 178, 212, 0}, - {137, 194, 152, 56, 6}, - {2, 180, 222, 82, 0} - }, - { {123, 144, 243, 154, 9}, - {118, 232, 177, 209, 7}, - {149, 156, 240, 157, 14}, - {232, 184, 209, 118, 14} - }, - { {199, 152, 208, 205, 5}, - {236, 160, 80, 223, 10}, - {171, 48, 177, 158, 3}, - {95, 176, 160, 83, 7} - }, - { {40, 109, 39, 77, 11}, - {31, 119, 33, 44, 12}, - {219, 46, 75, 97, 4}, - {51, 72, 78, 239, 8} - }, - { {217, 203, 12, 182, 4}, - {10, 15, 222, 194, 11}, - {38, 211, 13, 57, 11}, - {212, 55, 191, 5, 0} - }, - { {74, 39, 247, 51, 6}, - {51, 211, 202, 181, 5}, - {108, 206, 254, 69, 2}, - {170, 213, 60, 188, 12} - }, - { {58, 192, 163, 225, 10}, - {18, 220, 51, 13, 6}, - {88, 124, 80, 53, 12}, - {107, 12, 195, 180, 8} - }, - { {7, 221, 220, 229, 7}, - {236, 151, 86, 125, 10}, - {234, 115, 187, 190, 0}, - {91, 230, 174, 147, 7} - }, - { {136, 88, 155, 155, 11}, - {86, 244, 133, 22, 11}, - {221, 157, 145, 161, 1}, - {214, 138, 18, 246, 10} - }, - { {138, 23, 163, 27, 11}, - {86, 242, 137, 39, 5}, - {221, 140, 94, 133, 1}, - {174, 73, 20, 246, 10} - }, - { {238, 5, 82, 209, 7}, - {166, 82, 224, 191, 2}, - {232, 180, 170, 7, 7}, - {79, 208, 116, 166, 5} - }, - { {187, 95, 31, 51, 1}, - {86, 79, 174, 119, 9}, - {140, 207, 143, 173, 13}, - {158, 231, 95, 38, 10} - }, - { {208, 60, 187, 190, 2}, - {89, 248, 134, 178, 15}, - {71, 221, 211, 192, 11}, - {244, 214, 17, 249, 10} - }, - { {152, 244, 149, 172, 6}, - {91, 189, 82, 50, 2}, - {99, 90, 146, 241, 9}, - {68, 196, 171, 221, 10} - }, - { {197, 139, 251, 112, 15}, - {180, 210, 223, 218, 12}, - {240, 237, 253, 26, 3}, - {53, 191, 180, 178, 13} - }, - { {122, 253, 6, 239, 8}, - {75, 111, 51, 173, 11}, - {31, 118, 11, 245, 14}, - {219, 92, 207, 109, 2} - }, - { {81, 109, 127, 193, 5}, - {53, 79, 68, 252, 14}, - {168, 63, 235, 104, 10}, - {115, 242, 47, 42, 12} - }, - { {187, 149, 178, 239, 2}, - {74, 250, 50, 127, 7}, - {79, 116, 218, 157, 13}, - {239, 228, 197, 245, 2} - }, - { {74, 73, 174, 244, 10}, - {10, 215, 135, 137, 14}, - {82, 247, 89, 37, 2}, - {121, 30, 30, 181, 0} - }, - { {121, 22, 119, 209, 9}, - {118, 73, 169, 252, 6}, - {152, 190, 230, 137, 14}, - {99, 249, 89, 38, 14} - }, - { {171, 195, 19, 250, 3}, - {22, 118, 186, 91, 3}, - {197, 252, 140, 61, 5}, - {205, 165, 214, 230, 8} - }, - { {97, 72, 188, 236, 1}, - {12, 165, 38, 216, 14}, - {131, 115, 209, 40, 6}, - {113, 182, 74, 83, 0} - }, - { {189, 91, 56, 250, 15}, - {198, 62, 239, 90, 15}, - {245, 241, 205, 171, 13}, - {245, 175, 119, 198, 3} - }, - { {167, 203, 22, 91, 5}, - {132, 103, 248, 95, 9}, - {173, 166, 141, 62, 5}, - {159, 161, 254, 98, 1} - }, - { {122, 215, 157, 221, 12}, - {90, 175, 253, 189, 2}, - {59, 187, 158, 181, 14}, - {75, 219, 255, 85, 10} - }, - { {30, 33, 123, 48, 10}, - {179, 90, 135, 17, 4}, - {80, 205, 232, 71, 8}, - {40, 142, 21, 172, 13} - }, - { {7, 106, 159, 128, 15}, - {149, 213, 77, 81, 10}, - {240, 31, 149, 110, 0}, - {88, 171, 42, 186, 9} - }, - { {66, 20, 244, 73, 5}, - {100, 161, 64, 189, 4}, - {169, 34, 242, 132, 2}, - {43, 208, 40, 82, 6} - }, - { {90, 77, 21, 204, 4}, - {26, 47, 64, 185, 10}, - {35, 58, 139, 37, 10}, - {89, 208, 47, 69, 8} - }, - { {42, 237, 24, 136, 14}, - {3, 54, 117, 49, 10}, - {113, 17, 139, 117, 4}, - {88, 202, 230, 204, 0} - }, - { {74, 162, 225, 254, 13}, - {63, 160, 219, 137, 7}, - {183, 248, 116, 85, 2}, - {233, 29, 176, 95, 12} - }, - { {132, 142, 174, 178, 2}, - {128, 209, 158, 34, 15}, - {68, 215, 87, 18, 1}, - {244, 71, 152, 176, 1} - }, - { {51, 40, 220, 225, 13}, - {37, 137, 103, 93, 10}, - {184, 115, 177, 76, 12}, - {91, 174, 105, 26, 4} - }, - { {58, 219, 131, 61, 10}, - {90, 254, 187, 5, 8}, - {91, 204, 29, 181, 12}, - {26, 13, 215, 245, 10} - }, - { {115, 169, 29, 159, 13}, - {29, 43, 245, 213, 11}, - {191, 155, 137, 92, 14}, - {218, 186, 253, 75, 8} - }, - { {4, 109, 218, 103, 10}, - {169, 214, 7, 60, 9}, - {94, 101, 187, 98, 0}, - {147, 206, 6, 185, 5} - }, - { {58, 203, 120, 189, 13}, - {46, 46, 255, 21, 14}, - {187, 209, 237, 53, 12}, - {122, 143, 247, 71, 4} - }, - { {206, 153, 231, 26, 12}, - {242, 227, 209, 131, 13}, - {53, 142, 121, 151, 3}, - {188, 24, 188, 116, 15} - }, - { {165, 37, 165, 84, 6}, - {153, 147, 224, 106, 4}, - {98, 170, 90, 74, 5}, - {37, 96, 124, 153, 9} - }, - { {240, 63, 168, 232, 1}, - {69, 170, 46, 170, 14}, - {129, 113, 95, 192, 15}, - {117, 87, 69, 90, 2} - }, - { {118, 229, 192, 251, 1}, - {165, 174, 178, 173, 3}, - {141, 240, 58, 118, 14}, - {203, 84, 215, 90, 5} - }, - { {227, 99, 237, 110, 12}, - {57, 167, 111, 203, 5}, - {55, 107, 124, 108, 7}, - {173, 63, 110, 89, 12} - }, - { {116, 249, 37, 224, 5}, - {213, 15, 114, 136, 14}, - {160, 122, 73, 242, 14}, - {113, 20, 239, 10, 11} - }, - { {198, 217, 168, 122, 2}, - {192, 182, 150, 139, 13}, - {69, 225, 89, 182, 3}, - {189, 22, 150, 208, 3} - }, - { {13, 96, 234, 117, 11}, - {175, 212, 135, 76, 4}, - {218, 229, 112, 107, 0}, - {35, 46, 18, 191, 5} - }, - { {51, 227, 74, 122, 13}, - {37, 110, 255, 73, 1}, - {181, 229, 44, 124, 12}, - {137, 47, 247, 106, 4} - }, - { {113, 122, 201, 96, 4}, - {113, 140, 110, 200, 8}, - {32, 105, 53, 232, 14}, - {17, 55, 99, 24, 14} - }, - { {152, 138, 48, 249, 12}, - {2, 40, 219, 30, 14}, - {57, 240, 197, 17, 9}, - {119, 141, 177, 68, 0} - }, - { {46, 163, 26, 179, 12}, - {131, 66, 255, 21, 3}, - {60, 213, 140, 87, 4}, - {202, 143, 244, 44, 1} - }, - { {172, 182, 25, 142, 10}, - {219, 48, 61, 50, 3}, - {87, 25, 134, 211, 5}, - {196, 203, 192, 205, 11} - }, - { {240, 101, 182, 107, 5}, - {5, 239, 98, 190, 5}, - {173, 102, 218, 96, 15}, - {167, 212, 111, 122, 0} - }, - { {168, 198, 88, 212, 0}, - {42, 4, 188, 58, 2}, - {2, 177, 166, 49, 5}, - {69, 195, 210, 5, 4} - }, - { {204, 173, 140, 128, 11}, - {135, 147, 21, 162, 10}, - {208, 19, 27, 83, 3}, - {84, 90, 140, 158, 1} - }, - { {163, 169, 133, 130, 14}, - {17, 147, 113, 67, 11}, - {116, 26, 25, 92, 5}, - {220, 40, 236, 152, 8} - }, - { {236, 44, 102, 29, 0}, - {171, 97, 160, 166, 12}, - {11, 134, 99, 67, 7}, - {54, 80, 88, 109, 5} - }, - { {25, 228, 167, 179, 8}, - {19, 205, 147, 100, 7}, - {28, 222, 82, 121, 8}, - {226, 108, 155, 60, 8} - }, - { {141, 26, 103, 29, 6}, - {250, 113, 200, 70, 12}, - {107, 142, 101, 139, 1}, - {54, 33, 56, 229, 15} - }, - { {178, 43, 3, 194, 13}, - {21, 74, 105, 11, 11}, - {180, 60, 13, 68, 13}, - {221, 9, 101, 42, 8} - }, - { {233, 107, 129, 42, 2}, - {19, 182, 42, 194, 9}, - {69, 72, 29, 105, 7}, - {148, 53, 70, 220, 8} - }, - { {175, 188, 151, 185, 4}, - {211, 225, 242, 119, 10}, - {41, 222, 147, 223, 5}, - {94, 228, 248, 124, 11} - }, - { {46, 29, 146, 160, 8}, - {194, 194, 35, 49, 10}, - {16, 84, 155, 135, 4}, - {88, 204, 68, 52, 3} - }, - { {20, 26, 214, 160, 3}, - {228, 217, 10, 16, 10}, - {192, 86, 181, 130, 8}, - {80, 133, 9, 178, 7} - }, - { {181, 12, 21, 252, 0}, - {152, 41, 162, 122, 10}, - {3, 250, 131, 10, 13}, - {85, 228, 89, 65, 9} - }, - { {95, 40, 182, 146, 9}, - {135, 201, 129, 209, 15}, - {148, 150, 209, 79, 10}, - {248, 184, 25, 62, 1} - }, - { {5, 73, 160, 42, 15}, - {132, 182, 67, 64, 13}, - {245, 64, 89, 42, 0}, - {176, 44, 38, 210, 1} - }, - { {170, 29, 19, 140, 15}, - {94, 114, 97, 51, 10}, - {243, 28, 139, 133, 5}, - {92, 200, 100, 231, 10} - }, - { {214, 197, 212, 242, 6}, - {160, 159, 210, 187, 3}, - {100, 242, 186, 54, 11}, - {205, 212, 191, 144, 5} - }, - { {175, 39, 99, 231, 15}, - {191, 82, 107, 111, 7}, - {254, 124, 110, 79, 5}, - {239, 109, 100, 175, 13} - }, - { {13, 30, 84, 39, 10}, - {234, 17, 11, 116, 9}, - {94, 66, 167, 139, 0}, - {146, 237, 8, 133, 7} - }, - { {105, 13, 29, 67, 9}, - {22, 3, 37, 252, 9}, - {156, 43, 139, 9, 6}, - {147, 250, 76, 6, 8} - }, - { {142, 118, 82, 211, 11}, - {231, 84, 137, 63, 3}, - {220, 180, 166, 231, 1}, - {207, 201, 18, 174, 7} - }, - { {183, 231, 13, 198, 11}, - {157, 31, 61, 107, 3}, - {214, 59, 14, 126, 13}, - {205, 107, 207, 139, 9} - }, - { {91, 61, 61, 135, 11}, - {95, 27, 5, 245, 15}, - {222, 27, 203, 205, 10}, - {250, 250, 13, 143, 10} - }, - { {79, 134, 142, 113, 6}, - {130, 209, 222, 237, 0}, - {104, 231, 22, 31, 2}, - {11, 119, 184, 180, 1} - }, - { {177, 31, 187, 167, 12}, - {88, 202, 111, 118, 15}, - {62, 93, 223, 136, 13}, - {246, 239, 101, 49, 10} - }, - { {128, 174, 197, 152, 2}, - {49, 177, 152, 34, 10}, - {65, 154, 55, 80, 1}, - {84, 65, 152, 216, 12} - }, - { {213, 231, 198, 181, 15}, - {173, 223, 219, 230, 2}, - {250, 214, 62, 122, 11}, - {70, 125, 191, 187, 5} - }, - { {93, 45, 129, 118, 3}, - {159, 154, 130, 232, 9}, - {198, 232, 27, 75, 10}, - {145, 116, 21, 159, 9} - }, - { {203, 168, 201, 76, 1}, - {63, 160, 20, 203, 8}, - {131, 41, 49, 93, 3}, - {29, 50, 128, 95, 12} - }, - { {103, 230, 75, 17, 3}, - {181, 84, 188, 229, 0}, - {200, 141, 38, 126, 6}, - {10, 115, 210, 170, 13} - }, - { {250, 67, 80, 92, 14}, - {42, 62, 233, 155, 0}, - {115, 160, 172, 37, 15}, - {13, 153, 119, 197, 4} - }, - { {240, 150, 174, 222, 7}, - {76, 249, 252, 170, 7}, - {231, 183, 86, 144, 15}, - {229, 83, 249, 243, 2} - }, - { {71, 218, 157, 211, 11}, - {212, 149, 157, 221, 11}, - {220, 187, 149, 190, 2}, - {219, 187, 154, 146, 11} - }, - { {154, 5, 75, 133, 14}, - {58, 90, 69, 39, 2}, - {122, 29, 42, 5, 9}, - {78, 74, 37, 165, 12} - }, - { {120, 108, 53, 241, 11}, - {23, 29, 163, 188, 14}, - {216, 250, 195, 97, 14}, - {115, 220, 91, 142, 8} - }, - { {147, 175, 244, 140, 6}, - {41, 187, 88, 115, 14}, - {99, 18, 255, 92, 9}, - {124, 225, 173, 217, 4} - }, - { {42, 176, 175, 52, 11}, - {95, 209, 183, 1, 4}, - {210, 207, 80, 213, 4}, - {40, 14, 216, 191, 10} - }, - { {240, 11, 250, 99, 1}, - {36, 202, 46, 158, 13}, - {140, 101, 253, 0, 15}, - {183, 151, 69, 50, 4} - }, - { {76, 166, 198, 133, 5}, - {175, 193, 88, 164, 2}, - {170, 22, 54, 83, 2}, - {66, 81, 168, 63, 5} - }, - { {186, 20, 227, 14, 1}, - {126, 232, 32, 35, 5}, - {135, 12, 114, 133, 13}, - {172, 64, 65, 119, 14} - }, - { {33, 208, 242, 145, 8}, - {96, 196, 177, 84, 6}, - {24, 148, 240, 184, 4}, - {98, 168, 210, 48, 6} - }, - { {195, 163, 48, 100, 2}, - {9, 18, 26, 219, 4}, - {66, 96, 204, 92, 3}, - {45, 181, 132, 137, 0} - }, - { {55, 157, 233, 153, 7}, - {244, 186, 244, 101, 14}, - {233, 153, 123, 158, 12}, - {122, 98, 245, 210, 15} - }, - { {34, 132, 160, 94, 1}, - {12, 160, 176, 41, 5}, - {135, 160, 82, 20, 4}, - {169, 64, 208, 83, 0} - }, - { {111, 213, 214, 14, 1}, - {238, 231, 48, 241, 1}, - {135, 6, 186, 191, 6}, - {136, 240, 206, 119, 7} - }, - { {203, 84, 111, 171, 13}, - {118, 101, 71, 231, 7}, - {189, 95, 98, 173, 3}, - {238, 126, 42, 102, 14} - }, - { {156, 42, 145, 229, 8}, - {155, 136, 11, 30, 10}, - {26, 120, 149, 67, 9}, - {87, 141, 1, 29, 9} - }, - { {61, 210, 148, 126, 15}, - {206, 189, 251, 88, 1}, - {247, 226, 148, 187, 12}, - {129, 173, 251, 215, 3} - }, - { {100, 83, 228, 51, 13}, - {228, 135, 235, 132, 5}, - {188, 194, 124, 162, 6}, - {162, 29, 126, 18, 7} - }, - { {43, 198, 86, 24, 12}, - {34, 101, 249, 113, 0}, - {49, 134, 166, 61, 4}, - {8, 233, 250, 100, 4} - }, - { {37, 39, 183, 207, 14}, - {153, 243, 105, 124, 7}, - {127, 62, 222, 74, 4}, - {227, 233, 108, 249, 9} - }, - { {22, 36, 199, 38, 13}, - {189, 201, 67, 33, 1}, - {182, 78, 50, 70, 8}, - {136, 76, 41, 59, 13} - }, - { {202, 176, 164, 248, 14}, - {67, 177, 211, 139, 6}, - {113, 242, 80, 213, 3}, - {109, 28, 184, 220, 2} - }, - { {193, 236, 138, 99, 14}, - {1, 212, 87, 238, 9}, - {124, 101, 19, 120, 3}, - {151, 126, 162, 184, 0} - }, - { {82, 142, 30, 232, 13}, - {4, 105, 95, 185, 10}, - {177, 119, 135, 20, 10}, - {89, 223, 169, 98, 0} - }, - { {254, 163, 79, 210, 9}, - {183, 75, 189, 139, 3}, - {148, 191, 44, 87, 15}, - {205, 27, 221, 46, 13} - }, - { {92, 145, 249, 82, 6}, - {242, 154, 212, 152, 5}, - {100, 169, 248, 147, 10}, - {161, 146, 181, 148, 15} - }, - { {42, 103, 218, 12, 8}, - {43, 230, 45, 49, 0}, - {19, 5, 190, 101, 4}, - {8, 203, 70, 125, 4} - }, - { {111, 147, 7, 201, 2}, - {210, 115, 56, 205, 2}, - {73, 62, 12, 159, 6}, - {75, 49, 204, 228, 11} - }, - { {27, 127, 101, 218, 0}, - {115, 47, 136, 105, 15}, - {5, 186, 111, 237, 8}, - {249, 97, 31, 76, 14} - }, - { {96, 94, 48, 82, 3}, - {68, 20, 168, 184, 13}, - {196, 160, 199, 160, 6}, - {177, 209, 82, 130, 2} - }, - { {187, 3, 116, 51, 0}, - {34, 11, 170, 87, 5}, - {12, 194, 236, 13, 13}, - {174, 165, 93, 4, 4} - }, - { {245, 150, 230, 89, 11}, - {228, 249, 185, 238, 4}, - {217, 166, 118, 154, 15}, - {39, 121, 217, 242, 7} - }, - { {146, 81, 227, 36, 14}, - {120, 222, 67, 3, 4}, - {114, 76, 120, 164, 9}, - {44, 12, 39, 177, 14} - }, - { {37, 129, 147, 161, 3}, - {148, 210, 50, 84, 2}, - {200, 92, 152, 26, 4}, - {66, 164, 196, 178, 9} - }, - { {179, 35, 202, 164, 8}, - {41, 202, 47, 67, 2}, - {18, 85, 60, 76, 13}, - {76, 47, 69, 57, 4} - }, - { {141, 73, 29, 60, 1}, - {158, 39, 134, 82, 8}, - {131, 203, 137, 43, 1}, - {20, 166, 30, 71, 9} - }, - { {227, 51, 36, 195, 13}, - {69, 3, 105, 207, 7}, - {188, 50, 76, 204, 7}, - {239, 57, 108, 10, 2} - }, - { {184, 54, 252, 47, 7}, - {111, 185, 110, 54, 5}, - {239, 67, 246, 193, 13}, - {166, 199, 105, 223, 6} - }, - { {237, 209, 46, 107, 4}, - {194, 103, 118, 206, 5}, - {45, 103, 72, 187, 7}, - {167, 54, 238, 100, 3} - }, - { {235, 71, 59, 247, 10}, - {26, 86, 175, 255, 7}, - {94, 253, 206, 45, 7}, - {239, 255, 86, 165, 8} - }, - { {20, 242, 111, 82, 9}, - {245, 77, 157, 8, 5}, - {148, 175, 100, 242, 8}, - {161, 11, 155, 42, 15} - }, - { {205, 127, 26, 185, 15}, - {199, 118, 207, 246, 10}, - {249, 213, 143, 235, 3}, - {86, 255, 54, 238, 3} - }, - { {198, 53, 226, 175, 3}, - {237, 242, 2, 167, 7}, - {207, 84, 122, 198, 3}, - {238, 84, 4, 251, 7} - }, - { {215, 249, 12, 215, 3}, - {205, 31, 148, 207, 11}, - {206, 179, 9, 254, 11}, - {223, 50, 159, 139, 3} - }, - { {83, 21, 215, 208, 12}, - {112, 203, 193, 249, 2}, - {48, 190, 186, 140, 10}, - {73, 248, 61, 48, 14} - }, - { {86, 18, 116, 213, 1}, - {236, 9, 136, 157, 6}, - {138, 178, 228, 134, 10}, - {107, 145, 25, 3, 7} - }, - { {181, 26, 186, 149, 2}, - {200, 216, 172, 86, 14}, - {74, 149, 213, 138, 13}, - {118, 163, 81, 177, 3} - }, - { {98, 62, 7, 58, 4}, - {81, 97, 234, 161, 9}, - {37, 206, 7, 196, 6}, - {152, 85, 120, 104, 10} - }, - { {235, 252, 157, 72, 14}, - {83, 181, 117, 251, 8}, - {113, 43, 147, 253, 7}, - {29, 250, 234, 220, 10} - }, - { {129, 51, 86, 47, 14}, - {105, 115, 75, 86, 1}, - {127, 70, 172, 200, 1}, - {134, 173, 44, 233, 6} - }, - { {125, 43, 146, 2, 6}, - {131, 218, 104, 208, 9}, - {100, 4, 157, 75, 14}, - {144, 177, 101, 188, 1} - }, - { {144, 85, 192, 202, 6}, - {96, 190, 64, 42, 3}, - {101, 48, 58, 160, 9}, - {197, 64, 39, 208, 6} - }, - { {205, 132, 181, 92, 15}, - {158, 177, 209, 250, 4}, - {243, 170, 210, 27, 3}, - {37, 248, 184, 215, 9} - }, - { {11, 54, 92, 9, 4}, - {99, 33, 76, 117, 0}, - {41, 3, 166, 205, 0}, - {10, 227, 40, 76, 6} - }, - { {190, 98, 7, 5, 10}, - {155, 93, 41, 7, 0}, - {90, 14, 4, 103, 13}, - {14, 9, 75, 173, 9} - }, - { {39, 38, 95, 35, 12}, - {177, 65, 111, 117, 1}, - {60, 79, 166, 78, 4}, - {138, 239, 104, 40, 13} - }, - { {100, 138, 166, 99, 10}, - {128, 209, 59, 140, 13}, - {92, 102, 85, 18, 6}, - {179, 29, 200, 176, 1} - }, - { {254, 101, 69, 2, 13}, - {183, 15, 97, 163, 1}, - {180, 10, 42, 103, 15}, - {140, 88, 111, 14, 13} - }, - { {167, 99, 68, 48, 13}, - {165, 7, 235, 67, 0}, - {176, 194, 44, 110, 5}, - {12, 45, 126, 10, 5} - }, - { {217, 192, 126, 10, 8}, - {34, 109, 21, 210, 5}, - {21, 7, 224, 57, 11}, - {164, 186, 139, 100, 4} - }, - { {29, 104, 212, 20, 13}, - {175, 141, 193, 80, 8}, - {178, 130, 177, 107, 8}, - {16, 168, 59, 31, 5} - }, - { {203, 197, 40, 112, 3}, - {6, 22, 150, 235, 4}, - {192, 225, 74, 61, 3}, - {45, 118, 150, 134, 0} - }, - { {228, 40, 28, 188, 9}, - {141, 33, 167, 146, 10}, - {147, 211, 129, 66, 7}, - {84, 158, 88, 75, 1} - }, - { {225, 221, 170, 221, 6}, - {72, 246, 244, 238, 14}, - {107, 181, 91, 184, 7}, - {119, 114, 246, 241, 2} - }, - { {244, 239, 90, 230, 13}, - {173, 78, 127, 186, 11}, - {182, 117, 175, 114, 15}, - {213, 223, 231, 43, 5} - }, - { {122, 159, 45, 115, 15}, - {86, 27, 255, 173, 13}, - {252, 235, 79, 149, 14}, - {187, 95, 253, 134, 10} - }, - { {189, 215, 111, 86, 6}, - {250, 95, 252, 106, 5}, - {102, 175, 110, 187, 13}, - {165, 99, 255, 165, 15} - }, - { {79, 139, 34, 80, 4}, - {130, 66, 216, 201, 12}, - {32, 164, 77, 31, 2}, - {57, 49, 180, 36, 1} - }, - { {104, 156, 225, 61, 6}, - {122, 176, 242, 164, 12}, - {107, 200, 115, 145, 6}, - {50, 84, 240, 213, 14} - }, - { {23, 125, 226, 145, 13}, - {229, 206, 193, 101, 14}, - {184, 148, 123, 238, 8}, - {122, 104, 55, 58, 7} - }, - { {101, 27, 125, 109, 2}, - {248, 51, 46, 220, 12}, - {75, 107, 237, 138, 6}, - {51, 183, 76, 193, 15} - }, - { {230, 30, 244, 128, 14}, - {224, 145, 105, 179, 14}, - {112, 18, 247, 134, 7}, - {124, 217, 104, 144, 7} - }, - { {10, 131, 197, 183, 14}, - {58, 147, 219, 5, 3}, - {126, 218, 60, 21, 0}, - {202, 13, 188, 149, 12} - }, - { {113, 216, 247, 205, 5}, - {124, 237, 112, 220, 14}, - {171, 62, 241, 184, 14}, - {115, 176, 235, 115, 14} - }, - { {119, 102, 40, 235, 6}, - {129, 60, 110, 237, 7}, - {109, 113, 70, 110, 14}, - {235, 119, 99, 200, 1} - }, - { {164, 71, 35, 16, 2}, - {144, 86, 168, 34, 4}, - {64, 140, 78, 34, 5}, - {36, 65, 86, 160, 9} - }, - { {141, 28, 30, 136, 7}, - {198, 113, 68, 114, 10}, - {225, 23, 131, 139, 1}, - {84, 226, 40, 230, 3} - }, - { {174, 5, 207, 117, 0}, - {186, 195, 166, 47, 0}, - {10, 239, 58, 7, 5}, - {15, 70, 92, 53, 13} - }, - { {242, 185, 238, 5, 10}, - {105, 219, 53, 135, 12}, - {90, 7, 121, 212, 15}, - {62, 26, 205, 185, 6} - }, - { {150, 184, 220, 80, 14}, - {225, 153, 213, 27, 8}, - {112, 163, 177, 214, 9}, - {29, 138, 185, 152, 7} - }, - { {191, 140, 179, 54, 4}, - {154, 200, 242, 115, 13}, - {38, 204, 211, 31, 13}, - {188, 228, 241, 53, 9} - }, - { {77, 139, 178, 107, 7}, - {134, 242, 90, 220, 13}, - {237, 100, 221, 27, 2}, - {179, 181, 164, 246, 1} - }, - { {48, 111, 43, 129, 9}, - {21, 78, 45, 36, 14}, - {152, 29, 79, 96, 12}, - {114, 75, 71, 42, 8} - }, - { {134, 223, 39, 101, 6}, - {216, 87, 90, 47, 12}, - {106, 110, 79, 182, 1}, - {63, 69, 174, 161, 11} - }, - { {201, 63, 168, 244, 10}, - {75, 146, 143, 234, 14}, - {82, 241, 95, 201, 3}, - {117, 127, 20, 157, 2} - }, - { {178, 101, 205, 76, 0}, - {57, 175, 36, 43, 0}, - {3, 43, 58, 100, 13}, - {13, 66, 79, 89, 12} - }, - { {230, 107, 232, 211, 7}, - {165, 150, 236, 143, 15}, - {236, 177, 125, 102, 7}, - {255, 19, 118, 154, 5} - }, - { {172, 157, 252, 25, 5}, - {230, 163, 244, 54, 12}, - {169, 131, 251, 147, 5}, - {54, 194, 252, 86, 7} - }, - { {177, 19, 196, 190, 12}, - {104, 171, 235, 66, 3}, - {55, 210, 60, 136, 13}, - {196, 45, 125, 81, 6} - }, - { {211, 223, 9, 161, 13}, - {84, 14, 95, 231, 10}, - {184, 89, 15, 188, 11}, - {94, 127, 167, 2, 10} - }, - { {238, 69, 143, 67, 7}, - {150, 215, 100, 175, 1}, - {236, 47, 26, 39, 7}, - {143, 82, 110, 182, 9} - }, - { {103, 202, 12, 176, 9}, - {132, 5, 191, 193, 10}, - {144, 211, 5, 62, 6}, - {88, 63, 218, 2, 1} - }, - { {179, 49, 95, 108, 5}, - {125, 107, 102, 91, 0}, - {163, 111, 168, 204, 13}, - {13, 166, 109, 107, 14} - }, - { {51, 113, 11, 210, 2}, - {81, 94, 164, 73, 3}, - {68, 189, 8, 236, 12}, - {201, 34, 87, 168, 10} - }, - { {155, 233, 139, 184, 6}, - {19, 254, 214, 67, 10}, - {97, 221, 25, 125, 9}, - {92, 38, 183, 252, 8} - }, - { {65, 191, 62, 12, 5}, - {77, 99, 92, 240, 12}, - {163, 7, 207, 216, 2}, - {48, 243, 172, 107, 2} - }, - { {39, 180, 57, 11, 8}, - {209, 32, 53, 117, 5}, - {29, 9, 194, 222, 4}, - {170, 234, 192, 72, 11} - }, - { {22, 194, 235, 111, 10}, - {184, 252, 31, 13, 5}, - {95, 109, 116, 54, 8}, - {171, 15, 131, 241, 13} - }, - { {180, 216, 190, 76, 8}, - {200, 237, 53, 26, 12}, - {19, 39, 209, 178, 13}, - {53, 138, 203, 113, 3} - }, - { {157, 108, 51, 41, 10}, - {147, 124, 3, 118, 12}, - {89, 76, 195, 107, 9}, - {54, 236, 3, 236, 9} - }, - { {62, 93, 56, 87, 15}, - {206, 30, 229, 61, 13}, - {254, 161, 203, 167, 12}, - {187, 202, 119, 135, 3} - }, - { {180, 100, 140, 48, 10}, - {129, 157, 167, 34, 0}, - {80, 195, 18, 98, 13}, - {4, 78, 91, 152, 1} - }, - { {93, 101, 141, 153, 11}, - {151, 191, 133, 228, 2}, - {217, 155, 26, 107, 10}, - {66, 122, 31, 222, 9} - }, - { {75, 57, 30, 253, 8}, - {75, 99, 135, 221, 10}, - {27, 247, 137, 205, 2}, - {91, 190, 28, 109, 2} - }, - { {159, 102, 246, 244, 7}, - {175, 221, 202, 123, 6}, - {226, 246, 246, 111, 9}, - {109, 229, 59, 191, 5} - }, - { {99, 251, 122, 188, 8}, - {105, 102, 191, 209, 14}, - {19, 213, 237, 252, 6}, - {120, 191, 214, 105, 6} - }, - { {48, 213, 149, 195, 13}, - {84, 143, 113, 60, 3}, - {188, 58, 154, 176, 12}, - {195, 200, 239, 18, 10} - }, - { {44, 228, 218, 91, 8}, - {163, 228, 181, 60, 1}, - {29, 165, 178, 115, 4}, - {131, 202, 210, 124, 5} - }, - { {123, 79, 47, 122, 4}, - {18, 111, 238, 233, 13}, - {37, 239, 79, 45, 14}, - {185, 119, 127, 100, 8} - }, - { {80, 165, 170, 211, 11}, - {5, 218, 149, 172, 7}, - {220, 181, 90, 80, 10}, - {227, 90, 149, 186, 0} - }, - { {53, 99, 219, 99, 9}, - {181, 206, 47, 92, 1}, - {156, 109, 188, 106, 12}, - {131, 175, 71, 58, 13} - }, - { {202, 17, 193, 89, 1}, - {118, 162, 128, 143, 0}, - {137, 168, 56, 133, 3}, - {15, 16, 20, 86, 14} - }, - { {119, 153, 15, 22, 8}, - {216, 75, 181, 193, 9}, - {22, 143, 9, 158, 14}, - {152, 58, 221, 33, 11} - }, - { {6, 232, 6, 138, 11}, - {133, 117, 17, 1, 11}, - {213, 22, 1, 118, 0}, - {216, 8, 138, 234, 1} - }, - { {88, 242, 76, 249, 1}, - {103, 45, 158, 140, 2}, - {137, 243, 36, 241, 10}, - {67, 23, 155, 78, 6} - }, - { {87, 131, 120, 211, 4}, - {160, 10, 220, 221, 7}, - {44, 177, 236, 30, 10}, - {235, 179, 181, 0, 5} - }, - { {102, 199, 182, 12, 6}, - {136, 247, 120, 177, 4}, - {99, 6, 222, 54, 6}, - {40, 209, 238, 241, 1} - }, - { {120, 143, 69, 72, 0}, - {50, 43, 56, 168, 8}, - {1, 42, 47, 17, 14}, - {17, 81, 205, 68, 12} - }, - { {233, 239, 208, 58, 13}, - {39, 166, 251, 242, 9}, - {181, 192, 191, 121, 7}, - {148, 253, 246, 94, 4} - }, - { {39, 212, 15, 163, 10}, - {208, 85, 55, 101, 3}, - {92, 95, 2, 190, 4}, - {202, 110, 202, 160, 11} - }, - { {125, 42, 249, 128, 10}, - {179, 152, 45, 208, 14}, - {80, 25, 245, 75, 14}, - {112, 187, 65, 156, 13} - }, - { {86, 144, 82, 117, 6}, - {232, 88, 210, 157, 0}, - {106, 228, 160, 150, 10}, - {11, 148, 177, 161, 7} - }, - { {30, 225, 231, 61, 2}, - {187, 255, 146, 5, 4}, - {75, 206, 120, 119, 8}, - {42, 4, 159, 253, 13} - }, - { {254, 157, 166, 210, 9}, - {198, 203, 177, 171, 15}, - {148, 182, 91, 151, 15}, - {253, 88, 221, 54, 3} - }, - { {75, 222, 118, 252, 11}, - {110, 117, 155, 249, 14}, - {211, 246, 231, 189, 2}, - {121, 253, 154, 231, 6} - }, - { {50, 21, 75, 223, 8}, - {120, 106, 165, 45, 3}, - {31, 189, 42, 132, 12}, - {203, 74, 85, 97, 14} - }, - { {141, 94, 72, 11, 6}, - {226, 52, 76, 102, 9}, - {109, 1, 39, 171, 1}, - {150, 99, 34, 196, 7} - }, - { {85, 153, 228, 23, 12}, - {232, 139, 209, 196, 13}, - {62, 130, 121, 154, 10}, - {178, 56, 189, 17, 7} - }, - { {127, 178, 100, 131, 2}, - {227, 25, 56, 197, 7}, - {76, 18, 100, 223, 14}, - {234, 49, 201, 140, 7} - }, - { {6, 201, 57, 111, 3}, - {156, 54, 22, 29, 13}, - {207, 105, 201, 54, 0}, - {187, 134, 134, 195, 9} - }, - { {66, 202, 124, 45, 2}, - {40, 53, 30, 149, 12}, - {75, 67, 229, 52, 2}, - {58, 151, 138, 193, 4} - }, - { {78, 192, 248, 186, 12}, - {162, 164, 215, 145, 7}, - {53, 209, 240, 55, 2}, - {232, 158, 178, 84, 5} - }, - { {45, 113, 131, 30, 11}, - {223, 246, 161, 64, 1}, - {215, 140, 24, 235, 4}, - {128, 40, 86, 255, 11} - }, - { {128, 130, 234, 70, 4}, - {40, 192, 92, 10, 5}, - {38, 37, 116, 16, 1}, - {165, 3, 160, 49, 4} - }, - { {172, 206, 58, 52, 3}, - {142, 84, 190, 50, 12}, - {194, 197, 199, 51, 5}, - {52, 199, 210, 167, 1} - }, - { {88, 160, 32, 181, 13}, - {15, 8, 211, 132, 6}, - {186, 208, 64, 81, 10}, - {98, 28, 177, 15, 0} - }, - { {114, 159, 129, 35, 8}, - {80, 138, 59, 165, 9}, - {28, 72, 31, 148, 14}, - {154, 93, 197, 16, 10} - }, - { {123, 5, 90, 20, 12}, - {42, 74, 229, 241, 0}, - {50, 133, 170, 13, 14}, - {8, 250, 117, 37, 4} - }, - { {150, 248, 124, 233, 1}, - {229, 45, 22, 31, 14}, - {137, 115, 225, 246, 9}, - {127, 134, 139, 74, 7} - }, - { {41, 99, 28, 75, 10}, - {3, 55, 45, 92, 1}, - {93, 35, 140, 105, 4}, - {131, 171, 78, 204, 0} - }, - { {157, 226, 24, 237, 14}, - {139, 60, 95, 94, 2}, - {123, 113, 132, 123, 9}, - {71, 175, 163, 205, 1} - }, - { {58, 230, 175, 66, 4}, - {19, 205, 124, 41, 5}, - {36, 47, 86, 117, 12}, - {169, 67, 235, 60, 8} - }, - { {180, 56, 174, 163, 3}, - {197, 217, 38, 6, 15}, - {204, 87, 81, 194, 13}, - {246, 6, 73, 186, 3} - }, - { {208, 70, 61, 144, 7}, - {20, 29, 204, 178, 6}, - {224, 155, 198, 32, 11}, - {100, 211, 59, 130, 8} - }, - { {187, 32, 151, 39, 0}, - {27, 201, 34, 87, 1}, - {14, 78, 144, 77, 13}, - {142, 164, 73, 61, 8} - }, - { {229, 143, 37, 62, 0}, - {152, 35, 186, 226, 13}, - {7, 202, 79, 26, 7}, - {180, 117, 220, 65, 9} - }, - { {194, 117, 158, 53, 4}, - {73, 199, 198, 183, 0}, - {42, 199, 154, 228, 3}, - {14, 214, 62, 57, 2} - }, - { {10, 66, 188, 132, 7}, - {14, 149, 76, 17, 6}, - {226, 19, 212, 37, 0}, - {104, 131, 42, 151, 0} - }, - { {173, 67, 236, 130, 11}, - {166, 151, 45, 66, 7}, - {212, 19, 124, 43, 5}, - {228, 43, 78, 150, 5} - }, - { {61, 136, 115, 251, 11}, - {182, 120, 179, 92, 15}, - {221, 252, 225, 27, 12}, - {243, 172, 209, 230, 13} - }, - { {102, 161, 166, 184, 11}, - {133, 243, 179, 129, 6}, - {209, 214, 88, 86, 6}, - {104, 28, 220, 250, 1} - }, - { {221, 141, 175, 200, 4}, - {146, 235, 84, 234, 14}, - {33, 63, 91, 27, 11}, - {117, 114, 173, 116, 9} - }, - { {21, 7, 218, 203, 3}, - {164, 250, 12, 124, 3}, - {205, 53, 190, 10, 8}, - {195, 227, 5, 242, 5} - }, - { {137, 254, 190, 99, 3}, - {71, 213, 30, 126, 13}, - {204, 103, 215, 249, 1}, - {183, 231, 138, 190, 2} - }, - { {25, 7, 189, 144, 10}, - {18, 155, 141, 112, 6}, - {80, 155, 222, 9, 8}, - {96, 235, 29, 148, 8} - }, - { {98, 241, 188, 178, 14}, - {65, 151, 247, 145, 7}, - {116, 211, 216, 244, 6}, - {232, 158, 254, 152, 2} - }, - { {14, 147, 144, 200, 10}, - {194, 178, 25, 25, 2}, - {81, 48, 156, 151, 0}, - {73, 137, 132, 212, 3} - }, - { {102, 251, 212, 124, 10}, - {233, 183, 187, 153, 8}, - {83, 226, 189, 246, 6}, - {25, 157, 222, 217, 7} - }, - { {203, 127, 203, 186, 5}, - {119, 230, 206, 227, 11}, - {165, 221, 63, 237, 3}, - {220, 119, 54, 126, 14} - }, - { {72, 77, 150, 114, 5}, - {6, 199, 194, 184, 9}, - {164, 230, 155, 33, 2}, - {145, 212, 62, 54, 0} - }, - { {182, 201, 156, 184, 13}, - {132, 175, 247, 19, 10}, - {177, 211, 153, 54, 13}, - {92, 142, 255, 82, 1} - }, - { {214, 73, 19, 109, 6}, - {152, 126, 66, 159, 8}, - {107, 108, 137, 38, 11}, - {31, 148, 39, 225, 9} - }, - { {13, 229, 2, 166, 2}, - {139, 86, 18, 96, 3}, - {70, 84, 10, 123, 0}, - {192, 100, 134, 173, 1} - }, - { {249, 154, 61, 119, 4}, - {90, 9, 254, 222, 13}, - {46, 235, 197, 153, 15}, - {183, 183, 249, 5, 10} - }, - { {124, 20, 82, 167, 4}, - {234, 72, 98, 180, 3}, - {46, 84, 162, 131, 14}, - {194, 212, 97, 37, 7} - }, - { {57, 81, 76, 89, 15}, - {102, 63, 229, 76, 0}, - {249, 163, 40, 169, 12}, - {3, 42, 127, 198, 6} - }, - { {202, 63, 57, 87, 14}, - {91, 18, 205, 191, 13}, - {126, 169, 207, 197, 3}, - {191, 219, 52, 141, 10} - }, - { {219, 212, 95, 243, 10}, - {114, 93, 151, 255, 3}, - {92, 255, 162, 189, 11}, - {207, 254, 155, 164, 14} - }, - { {113, 246, 139, 38, 2}, - {89, 220, 62, 224, 1}, - {70, 77, 22, 248, 14}, - {128, 119, 195, 185, 10} - }, - { {61, 34, 41, 13, 7}, - {159, 56, 108, 68, 4}, - {235, 9, 68, 75, 12}, - {34, 35, 97, 207, 9} - }, - { {154, 77, 130, 207, 12}, - {10, 238, 65, 47, 11}, - {63, 52, 27, 37, 9}, - {223, 72, 39, 117, 0} - }, - { {16, 141, 72, 139, 2}, - {32, 58, 20, 36, 11}, - {77, 17, 43, 16, 8}, - {210, 66, 133, 192, 4} - }, - { {66, 66, 157, 48, 14}, - {16, 149, 207, 145, 0}, - {112, 203, 148, 36, 2}, - {8, 159, 58, 144, 8} - }, - { {191, 242, 183, 46, 9}, - {223, 237, 59, 83, 5}, - {151, 78, 212, 255, 13}, - {172, 173, 203, 127, 11} - }, - { {137, 69, 178, 16, 8}, - {2, 198, 129, 114, 4}, - {16, 132, 218, 41, 1}, - {36, 232, 22, 52, 0} - }, - { {156, 83, 206, 106, 1}, - {230, 239, 14, 10, 1}, - {133, 103, 60, 163, 9}, - {133, 7, 15, 118, 7} - }, - { {246, 110, 46, 178, 11}, - {133, 93, 175, 163, 15}, - {212, 215, 71, 102, 15}, - {252, 95, 91, 170, 1} - }, - { {123, 135, 22, 82, 6}, - {2, 91, 248, 249, 1}, - {100, 166, 142, 29, 14}, - {137, 241, 253, 164, 0} - }, - { {117, 48, 198, 172, 7}, - {237, 249, 98, 192, 2}, - {227, 86, 48, 202, 14}, - {64, 52, 105, 251, 7} - }, - { {219, 148, 76, 224, 4}, - {98, 9, 86, 235, 2}, - {32, 115, 34, 157, 11}, - {77, 118, 169, 4, 6} - }, - { {64, 156, 92, 188, 6}, - {104, 49, 214, 176, 10}, - {99, 211, 163, 144, 2}, - {80, 214, 184, 193, 6} - }, - { {96, 119, 25, 168, 12}, - {81, 38, 111, 176, 2}, - {49, 89, 142, 224, 6}, - {64, 223, 102, 72, 10} - }, - { {100, 136, 107, 16, 1}, - {180, 64, 180, 128, 12}, - {128, 141, 97, 18, 6}, - {48, 18, 208, 34, 13} - }, - { {33, 158, 169, 148, 0}, - {88, 128, 188, 96, 14}, - {2, 153, 87, 152, 4}, - {112, 99, 208, 17, 10} - }, - { {146, 100, 250, 242, 11}, - {37, 220, 135, 59, 7}, - {212, 245, 242, 100, 9}, - {237, 206, 19, 186, 4} - }, - { {214, 14, 81, 55, 9}, - {188, 8, 139, 183, 9}, - {158, 200, 167, 6, 11}, - {158, 221, 17, 3, 13} - }, - { {6, 232, 25, 146, 12}, - {145, 4, 213, 17, 11}, - {52, 153, 129, 118, 0}, - {216, 138, 178, 8, 9} - }, - { {101, 196, 213, 201, 3}, - {180, 181, 48, 252, 2}, - {201, 58, 178, 58, 6}, - {67, 240, 202, 210, 13} - }, - { {91, 1, 85, 227, 4}, - {50, 11, 66, 221, 3}, - {44, 122, 168, 13, 10}, - {203, 180, 45, 4, 12} - }, - { {93, 64, 143, 102, 1}, - {158, 205, 6, 200, 1}, - {134, 111, 16, 43, 10}, - {129, 54, 11, 55, 9} - }, - { {61, 239, 243, 168, 13}, - {183, 238, 123, 112, 14}, - {177, 92, 255, 123, 12}, - {112, 237, 231, 126, 13} - }, - { {83, 37, 200, 86, 6}, - {41, 154, 196, 233, 1}, - {102, 161, 58, 76, 10}, - {137, 114, 53, 153, 4} - }, - { {18, 10, 174, 82, 10}, - {0, 217, 141, 9, 13}, - {84, 167, 85, 4, 8}, - {185, 11, 25, 176, 0} - }, - { {155, 29, 191, 200, 11}, - {86, 251, 5, 123, 14}, - {209, 63, 219, 141, 9}, - {125, 234, 13, 246, 10} - }, - { {207, 183, 171, 86, 8}, - {219, 194, 157, 235, 5}, - {22, 173, 94, 223, 3}, - {173, 123, 148, 61, 11} - }, - { {42, 141, 220, 32, 7}, - {38, 147, 118, 49, 8}, - {224, 67, 187, 21, 4}, - {24, 198, 236, 150, 4} - }, - { {142, 106, 174, 19, 3}, - {135, 213, 140, 7, 13}, - {204, 135, 85, 103, 1}, - {190, 3, 26, 190, 1} - }, - { {171, 253, 77, 159, 3}, - {127, 55, 180, 103, 11}, - {207, 155, 43, 253, 5}, - {222, 98, 222, 207, 14} - }, - { {45, 9, 17, 6, 12}, - {154, 2, 97, 80, 9}, - {54, 8, 137, 11, 4}, - {144, 168, 100, 5, 9} - }, - { {168, 207, 127, 12, 12}, - {58, 103, 125, 50, 12}, - {51, 15, 239, 49, 5}, - {52, 203, 238, 101, 12} - }, - { {166, 83, 153, 76, 7}, - {220, 182, 108, 27, 0}, - {227, 41, 156, 166, 5}, - {13, 131, 102, 211, 11} - }, - { {135, 166, 224, 109, 0}, - {169, 160, 26, 111, 4}, - {11, 96, 118, 94, 1}, - {47, 101, 128, 89, 5} - }, - { {59, 232, 221, 151, 0}, - {59, 141, 180, 85, 11}, - {14, 155, 177, 125, 12}, - {218, 162, 219, 29, 12} - }, - { {209, 178, 226, 250, 9}, - {101, 232, 155, 202, 7}, - {149, 244, 116, 216, 11}, - {229, 61, 145, 122, 6} - }, - { {0, 188, 184, 78, 7}, - {77, 176, 84, 56, 13}, - {231, 33, 211, 208, 0}, - {177, 194, 160, 219, 2} - }, - { {166, 167, 158, 98, 11}, - {133, 211, 63, 59, 1}, - {212, 103, 158, 86, 5}, - {141, 207, 204, 186, 1} - }, - { {200, 134, 91, 1, 3}, - {54, 80, 28, 182, 0}, - {200, 13, 166, 17, 3}, - {6, 211, 128, 166, 12} - }, - { {12, 255, 119, 177, 9}, - {247, 71, 155, 52, 14}, - {152, 222, 239, 243, 0}, - {114, 205, 158, 46, 15} - }, - { {142, 29, 220, 148, 3}, - {238, 147, 132, 51, 10}, - {194, 147, 187, 135, 1}, - {92, 194, 28, 151, 7} - }, - { {18, 244, 200, 158, 7}, - {109, 188, 212, 33, 3}, - {231, 145, 50, 244, 8}, - {200, 66, 179, 219, 6} - }, - { {221, 245, 180, 168, 13}, - {199, 175, 83, 242, 6}, - {177, 82, 218, 251, 11}, - {100, 252, 175, 94, 3} - }, - { {97, 194, 86, 250, 10}, - {32, 117, 187, 216, 3}, - {85, 246, 164, 56, 6}, - {193, 189, 218, 224, 4} - }, - { {34, 2, 81, 216, 5}, - {52, 32, 232, 25, 2}, - {161, 184, 164, 4, 4}, - {73, 129, 112, 66, 12} - }, - { {160, 222, 24, 47, 2}, - {72, 52, 62, 54, 9}, - {79, 65, 135, 176, 5}, - {150, 199, 194, 193, 2} - }, - { {203, 116, 62, 141, 0}, - {75, 101, 4, 247, 6}, - {11, 23, 194, 237, 3}, - {110, 242, 10, 109, 2} - }, - { {32, 93, 174, 186, 9}, - {68, 231, 167, 32, 15}, - {149, 215, 91, 160, 4}, - {240, 78, 94, 114, 2} - }, - { {182, 151, 72, 253, 13}, - {236, 42, 255, 47, 2}, - {187, 241, 46, 150, 13}, - {79, 79, 245, 67, 7} - }, - { {244, 165, 139, 213, 6}, - {153, 218, 244, 174, 2}, - {106, 189, 26, 82, 15}, - {71, 82, 245, 185, 9} - }, - { {137, 147, 208, 12, 15}, - {110, 178, 89, 82, 0}, - {243, 0, 188, 153, 1}, - {4, 169, 164, 215, 6} - }, - { {43, 161, 206, 80, 15}, - {39, 211, 245, 73, 0}, - {240, 167, 56, 93, 4}, - {9, 42, 252, 190, 4} - }, - { {84, 31, 38, 148, 10}, - {200, 91, 137, 160, 14}, - {82, 150, 79, 130, 10}, - {112, 89, 29, 161, 3} - }, - { {250, 73, 70, 153, 5}, - {38, 111, 224, 135, 10}, - {169, 150, 41, 37, 15}, - {94, 16, 127, 102, 4} - }, - { {143, 119, 77, 200, 6}, - {243, 55, 76, 107, 2}, - {97, 59, 46, 239, 1}, - {77, 99, 46, 204, 15} - }, - { {21, 73, 52, 191, 10}, - {136, 63, 131, 84, 15}, - {95, 210, 201, 42, 8}, - {242, 172, 31, 193, 1} - }, - { {160, 179, 125, 121, 0}, - {113, 35, 190, 30, 4}, - {9, 235, 236, 208, 5}, - {39, 135, 220, 72, 14} - }, - { {94, 29, 64, 6, 12}, - {234, 10, 65, 161, 9}, - {54, 0, 43, 135, 10}, - {152, 88, 37, 5, 7} - }, - { {247, 121, 227, 64, 9}, - {245, 206, 33, 203, 12}, - {144, 44, 121, 238, 15}, - {61, 56, 71, 58, 15} - }, - { {126, 60, 103, 41, 12}, - {243, 105, 99, 165, 12}, - {57, 78, 99, 199, 14}, - {58, 92, 105, 108, 15} - }, - { {38, 10, 20, 204, 8}, - {136, 33, 41, 25, 10}, - {19, 50, 133, 6, 4}, - {89, 137, 72, 65, 1} - }, - { {210, 180, 127, 62, 15}, - {125, 121, 215, 179, 5}, - {247, 207, 226, 212, 11}, - {172, 222, 185, 235, 14} - }, - { {52, 74, 22, 15, 2}, - {136, 125, 40, 20, 9}, - {79, 6, 133, 34, 12}, - {146, 129, 75, 225, 1} - }, - { {240, 88, 87, 246, 9}, - {124, 77, 163, 154, 11}, - {150, 254, 161, 160, 15}, - {213, 156, 91, 35, 14} - }, - { {200, 222, 73, 90, 3}, - {118, 52, 156, 170, 9}, - {197, 169, 39, 177, 3}, - {149, 83, 146, 198, 14} - }, - { {41, 152, 52, 89, 7}, - {70, 49, 240, 92, 12}, - {233, 162, 193, 153, 4}, - {51, 160, 248, 198, 2} - }, - { {192, 28, 220, 163, 10}, - {96, 145, 7, 182, 11}, - {92, 83, 179, 128, 3}, - {214, 222, 8, 144, 6} - }, - { {17, 134, 214, 198, 15}, - {44, 217, 89, 120, 3}, - {246, 54, 182, 24, 8}, - {193, 233, 169, 179, 4} - }, - { {199, 106, 99, 224, 0}, - {177, 68, 10, 203, 14}, - {0, 124, 101, 110, 3}, - {125, 53, 2, 40, 13} - }, - { {250, 63, 143, 86, 4}, - {91, 203, 236, 171, 9}, - {38, 175, 31, 197, 15}, - {157, 83, 125, 61, 10} - }, - { {30, 208, 47, 67, 7}, - {214, 93, 84, 13, 5}, - {236, 47, 64, 183, 8}, - {171, 2, 171, 166, 11} - }, - { {167, 132, 152, 85, 15}, - {140, 144, 245, 127, 0}, - {250, 161, 146, 30, 5}, - {15, 234, 240, 147, 1} - }, - { {12, 209, 94, 200, 6}, - {226, 119, 84, 24, 2}, - {97, 55, 168, 179, 0}, - {65, 130, 174, 228, 7} - }, - { {222, 242, 230, 20, 0}, - {235, 205, 152, 131, 4}, - {2, 134, 116, 247, 11}, - {44, 17, 155, 61, 7} - }, - { {172, 114, 24, 123, 12}, - {195, 36, 239, 30, 1}, - {61, 225, 132, 227, 5}, - {135, 143, 114, 76, 3} - }, - { {103, 201, 15, 119, 7}, - {156, 87, 246, 205, 9}, - {238, 239, 9, 62, 6}, - {155, 54, 254, 163, 9} - }, - { {7, 91, 205, 34, 11}, - {244, 151, 15, 65, 9}, - {212, 75, 61, 174, 0}, - {152, 47, 14, 146, 15} - }, - { {201, 190, 213, 237, 13}, - {127, 161, 91, 254, 10}, - {187, 122, 183, 217, 3}, - {87, 253, 168, 95, 14} - }, - { {106, 147, 24, 117, 4}, - {74, 2, 254, 157, 0}, - {42, 225, 140, 149, 6}, - {11, 151, 244, 5, 2} - }, - { {107, 212, 146, 123, 3}, - {70, 244, 178, 253, 1}, - {205, 228, 146, 189, 6}, - {139, 244, 210, 246, 2} - }, - { {118, 132, 7, 115, 8}, - {144, 73, 179, 173, 1}, - {28, 238, 2, 22, 14}, - {139, 92, 217, 32, 9} - }, - { {181, 12, 26, 120, 15}, - {132, 120, 231, 122, 8}, - {241, 229, 131, 10, 13}, - {21, 238, 113, 226, 1} - }, - { {153, 76, 54, 246, 14}, - {10, 93, 195, 122, 15}, - {118, 246, 195, 41, 9}, - {245, 236, 59, 165, 0} - }, - { {33, 245, 36, 87, 11}, - {77, 23, 177, 108, 5}, - {222, 162, 74, 248, 4}, - {163, 104, 222, 139, 2} - }, - { {97, 170, 231, 238, 4}, - {57, 225, 122, 200, 15}, - {39, 126, 117, 88, 6}, - {241, 53, 232, 121, 12} - }, - { {36, 1, 140, 232, 5}, - {132, 163, 102, 8, 2}, - {161, 115, 24, 2, 4}, - {65, 6, 108, 82, 1} - }, - { {97, 41, 206, 35, 10}, - {33, 211, 39, 196, 9}, - {92, 71, 57, 72, 6}, - {146, 62, 76, 184, 4} - }, - { {164, 226, 123, 199, 10}, - {185, 84, 61, 30, 7}, - {94, 61, 228, 114, 5}, - {231, 139, 194, 169, 13} - }, - { {182, 249, 62, 111, 6}, - {201, 127, 118, 31, 13}, - {111, 103, 201, 246, 13}, - {191, 134, 239, 233, 3} - }, - { {184, 158, 66, 250, 4}, - {98, 104, 250, 42, 11}, - {37, 244, 39, 145, 13}, - {213, 69, 241, 100, 6} - }, - { {205, 168, 178, 163, 12}, - {131, 192, 83, 214, 15}, - {60, 84, 209, 91, 3}, - {246, 188, 160, 60, 1} - }, - { {76, 57, 177, 159, 7}, - {223, 178, 192, 148, 15}, - {239, 152, 217, 195, 2}, - {242, 144, 52, 223, 11} - }, - { {185, 129, 38, 244, 2}, - {10, 91, 178, 74, 6}, - {66, 246, 72, 25, 13}, - {101, 36, 221, 165, 0} - }, - { {14, 11, 250, 182, 8}, - {170, 194, 143, 17, 15}, - {22, 213, 253, 7, 0}, - {248, 143, 20, 53, 5} - }, - { {242, 177, 157, 60, 6}, - {89, 187, 246, 147, 0}, - {99, 203, 152, 212, 15}, - {12, 150, 253, 217, 10} - }, - { {62, 75, 92, 90, 2}, - {162, 63, 172, 25, 9}, - {69, 163, 173, 39, 12}, - {153, 131, 95, 196, 5} - }, - { {53, 13, 105, 45, 8}, - {184, 42, 39, 100, 12}, - {27, 73, 107, 10, 12}, - {50, 110, 69, 65, 13} - }, - { {180, 35, 142, 37, 5}, - {141, 203, 110, 6, 0}, - {170, 71, 28, 66, 13}, - {6, 7, 109, 59, 1} - }, - { {69, 98, 201, 154, 0}, - {177, 164, 140, 192, 3}, - {5, 153, 52, 106, 2}, - {192, 51, 18, 88, 13} - }, - { {180, 56, 177, 59, 0}, - {209, 168, 162, 22, 13}, - {13, 200, 209, 194, 13}, - {182, 132, 81, 88, 11} - }, - { {131, 20, 145, 146, 14}, - {80, 144, 193, 115, 3}, - {116, 152, 146, 140, 1}, - {204, 232, 48, 144, 10} - }, - { {255, 9, 118, 5, 7}, - {174, 91, 96, 215, 12}, - {234, 6, 233, 15, 15}, - {62, 176, 109, 167, 5} - }, - { {76, 85, 220, 22, 13}, - {238, 135, 197, 176, 1}, - {182, 131, 186, 163, 2}, - {128, 218, 62, 23, 7} - }, - { {104, 114, 128, 201, 15}, - {71, 180, 105, 140, 2}, - {249, 48, 20, 225, 6}, - {67, 25, 98, 222, 2} - }, - { {118, 171, 174, 160, 4}, - {129, 203, 126, 129, 14}, - {32, 87, 93, 86, 14}, - {120, 23, 237, 56, 1} - }, - { {145, 170, 76, 41, 14}, - {33, 57, 95, 70, 8}, - {121, 67, 37, 88, 9}, - {22, 47, 169, 200, 4} - }, - { {172, 153, 124, 202, 8}, - {226, 35, 53, 26, 15}, - {21, 51, 233, 147, 5}, - {245, 138, 204, 68, 7} - }, - { {14, 211, 209, 214, 1}, - {254, 134, 152, 25, 3}, - {134, 184, 188, 183, 0}, - {201, 129, 150, 23, 15} - }, - { {186, 245, 248, 135, 3}, - {111, 158, 52, 55, 7}, - {206, 17, 250, 245, 13}, - {238, 194, 199, 159, 6} - }, - { {24, 203, 208, 54, 12}, - {42, 142, 219, 16, 9}, - {54, 192, 189, 49, 8}, - {144, 141, 183, 21, 4} - }, - { {230, 136, 49, 122, 7}, - {148, 48, 242, 155, 13}, - {229, 232, 193, 22, 7}, - {189, 148, 240, 194, 9} - }, - { {38, 93, 140, 24, 7}, - {196, 183, 228, 33, 8}, - {225, 131, 27, 166, 4}, - {24, 66, 126, 210, 3} - }, - { {37, 253, 177, 16, 7}, - {213, 150, 240, 112, 12}, - {224, 136, 219, 250, 4}, - {48, 224, 246, 154, 11} - }, - { {46, 105, 226, 33, 9}, - {167, 198, 35, 5, 12}, - {152, 68, 121, 103, 4}, - {58, 12, 70, 62, 5} - }, - { {148, 212, 15, 127, 5}, - {220, 109, 214, 46, 1}, - {175, 239, 2, 178, 9}, - {135, 70, 187, 99, 11} - }, - { {104, 227, 24, 161, 2}, - {3, 22, 62, 148, 2}, - {72, 81, 140, 113, 6}, - {66, 151, 198, 140, 0} - }, - { {115, 38, 168, 12, 2}, - {9, 184, 44, 225, 4}, - {67, 1, 86, 76, 14}, - {40, 115, 65, 217, 0} - }, - { {8, 225, 19, 56, 4}, - {19, 102, 210, 16, 0}, - {33, 204, 136, 113, 0}, - {0, 132, 182, 108, 8} - }, - { {30, 74, 153, 58, 11}, - {150, 188, 143, 17, 9}, - {213, 201, 149, 39, 8}, - {152, 143, 19, 214, 9} - }, - { {56, 123, 230, 193, 11}, - {103, 223, 41, 12, 14}, - {216, 54, 125, 225, 12}, - {115, 9, 79, 190, 6} - }, - { {23, 164, 136, 165, 2}, - {137, 152, 22, 101, 2}, - {74, 81, 18, 94, 8}, - {74, 102, 129, 153, 1} - }, - { {100, 67, 135, 200, 8}, - {144, 231, 41, 136, 2}, - {17, 62, 28, 34, 6}, - {65, 25, 78, 112, 9} - }, - { {110, 7, 130, 143, 7}, - {142, 242, 104, 165, 3}, - {239, 20, 30, 7, 6}, - {202, 81, 100, 247, 1} - }, - { {184, 128, 233, 2, 2}, - {50, 152, 52, 2, 5}, - {68, 9, 112, 17, 13}, - {164, 2, 193, 148, 12} - }, - { {62, 14, 185, 83, 2}, - {146, 152, 172, 61, 13}, - {76, 169, 215, 7, 12}, - {187, 195, 81, 148, 9} - }, - { {143, 140, 17, 176, 2}, - {146, 16, 146, 115, 10}, - {64, 216, 131, 31, 1}, - {92, 228, 144, 132, 9} - }, - { {27, 141, 195, 155, 13}, - {54, 234, 209, 101, 11}, - {189, 156, 59, 29, 8}, - {218, 104, 181, 118, 12} - }, - { {238, 130, 108, 30, 9}, - {174, 33, 189, 131, 5}, - {151, 131, 100, 23, 7}, - {172, 27, 216, 71, 5} - }, - { {149, 96, 110, 240, 8}, - {161, 77, 135, 74, 6}, - {16, 247, 96, 106, 9}, - {101, 46, 27, 40, 5} - }, - { {80, 228, 38, 86, 2}, - {9, 93, 144, 168, 5}, - {70, 166, 66, 112, 10}, - {161, 80, 155, 169, 0} - }, - { {212, 77, 143, 180, 2}, - {152, 223, 134, 162, 10}, - {66, 223, 27, 34, 11}, - {84, 86, 31, 177, 9} - }, - { {5, 79, 54, 9, 7}, - {132, 119, 72, 116, 12}, - {233, 6, 207, 42, 0}, - {50, 225, 46, 226, 1} - }, - { {165, 246, 91, 233, 9}, - {245, 100, 63, 126, 2}, - {153, 125, 166, 250, 5}, - {71, 239, 194, 106, 15} - }, - { {246, 67, 68, 234, 5}, - {164, 47, 106, 139, 3}, - {165, 114, 44, 38, 15}, - {205, 21, 111, 66, 5} - }, - { {85, 81, 175, 40, 13}, - {212, 239, 71, 192, 4}, - {177, 79, 88, 170, 10}, - {32, 62, 47, 114, 11} - }, - { {27, 94, 104, 63, 5}, - {110, 44, 206, 101, 13}, - {175, 193, 103, 173, 8}, - {186, 103, 51, 71, 6} - }, - { {6, 118, 167, 222, 12}, - {217, 229, 201, 41, 7}, - {55, 190, 86, 230, 0}, - {233, 73, 58, 121, 11} - }, - { {70, 176, 31, 231, 11}, - {221, 81, 23, 157, 3}, - {222, 127, 128, 214, 2}, - {203, 158, 136, 171, 11} - }, - { {38, 80, 223, 195, 0}, - {240, 197, 36, 29, 3}, - {12, 63, 176, 166, 4}, - {203, 130, 74, 48, 15} - }, - { {52, 1, 83, 23, 3}, - {188, 90, 160, 20, 1}, - {206, 140, 168, 2, 12}, - {130, 128, 85, 163, 13} - }, - { {185, 183, 76, 10, 12}, - {99, 43, 125, 98, 1}, - {53, 3, 46, 217, 13}, - {132, 107, 237, 76, 6} - }, - { {103, 124, 93, 21, 5}, - {253, 5, 228, 245, 8}, - {170, 139, 163, 238, 6}, - {26, 242, 122, 11, 15} - }, - { {62, 14, 116, 210, 9}, - {166, 9, 169, 57, 15}, - {148, 178, 231, 7, 12}, - {249, 201, 89, 6, 5} - }, - { {135, 91, 221, 123, 4}, - {240, 167, 206, 95, 9}, - {45, 235, 189, 174, 1}, - {159, 167, 62, 80, 15} - }, - { {243, 250, 71, 202, 15}, - {117, 125, 121, 203, 11}, - {245, 62, 37, 252, 15}, - {221, 57, 235, 234, 14} - }, - { {215, 194, 170, 201, 7}, - {132, 252, 92, 207, 6}, - {233, 53, 84, 62, 11}, - {111, 51, 163, 242, 1} - }, - { {9, 112, 244, 98, 8}, - {99, 133, 3, 88, 5}, - {20, 98, 240, 233, 0}, - {161, 172, 10, 28, 6} - }, - { {49, 139, 231, 50, 10}, - {48, 219, 187, 64, 13}, - {84, 206, 125, 24, 12}, - {176, 45, 221, 176, 12} - }, - { {250, 59, 245, 187, 4}, - {115, 171, 234, 151, 15}, - {45, 218, 253, 197, 15}, - {254, 149, 125, 92, 14} - }, - { {119, 186, 106, 0, 14}, - {225, 88, 125, 193, 12}, - {112, 5, 101, 222, 14}, - {56, 59, 225, 168, 7} - }, - { {245, 7, 16, 43, 15}, - {132, 58, 107, 246, 1}, - {253, 64, 142, 10, 15}, - {134, 253, 101, 194, 1} - }, - { {55, 185, 16, 190, 8}, - {201, 42, 179, 81, 11}, - {23, 208, 137, 222, 12}, - {216, 172, 213, 73, 3} - }, - { {154, 36, 87, 204, 1}, - {63, 105, 0, 59, 2}, - {131, 62, 162, 69, 9}, - {77, 192, 9, 111, 12} - }, - { {86, 238, 203, 19, 12}, - {177, 204, 221, 165, 9}, - {60, 141, 55, 118, 10}, - {154, 91, 179, 56, 13} - }, - { {19, 93, 119, 167, 4}, - {120, 79, 66, 117, 15}, - {46, 94, 235, 172, 8}, - {250, 228, 47, 33, 14} - }, - { {13, 146, 253, 48, 4}, - {242, 129, 222, 80, 4}, - {32, 203, 244, 155, 0}, - {32, 167, 184, 20, 15} - }, - { {237, 122, 230, 34, 3}, - {231, 213, 42, 194, 13}, - {196, 70, 117, 235, 7}, - {180, 53, 74, 190, 7} - }, - { {141, 125, 109, 37, 12}, - {251, 7, 71, 102, 12}, - {58, 75, 107, 235, 1}, - {54, 110, 46, 13, 15} - }, - { {120, 62, 207, 103, 3}, - {127, 217, 46, 172, 9}, - {206, 111, 55, 193, 14}, - {147, 87, 73, 191, 14} - }, - { {62, 116, 93, 252, 6}, - {251, 61, 230, 57, 2}, - {99, 251, 162, 231, 12}, - {73, 198, 123, 205, 15} - }, - { {188, 170, 218, 5, 10}, - {171, 216, 61, 22, 8}, - {90, 5, 181, 83, 13}, - {22, 139, 193, 189, 5} - }, - { {13, 162, 38, 20, 8}, - {139, 65, 153, 64, 4}, - {18, 134, 68, 91, 0}, - {32, 41, 152, 45, 1} - }, - { {134, 217, 94, 7, 10}, - {232, 87, 21, 23, 9}, - {94, 7, 169, 182, 1}, - {158, 138, 142, 161, 7} - }, - { {37, 126, 156, 27, 14}, - {193, 181, 237, 116, 9}, - {125, 131, 151, 234, 4}, - {146, 235, 122, 216, 3} - }, - { {221, 222, 210, 16, 1}, - {230, 204, 152, 242, 8}, - {128, 132, 183, 187, 11}, - {20, 241, 147, 54, 7} - }, - { {233, 1, 205, 160, 13}, - {54, 131, 103, 194, 2}, - {176, 91, 56, 9, 7}, - {68, 62, 108, 22, 12} - }, - { {119, 152, 12, 57, 4}, - {192, 41, 246, 197, 8}, - {41, 195, 1, 158, 14}, - {26, 54, 249, 64, 3} - }, - { {209, 14, 75, 139, 7}, - {52, 120, 76, 230, 11}, - {237, 29, 39, 8, 11}, - {214, 115, 33, 226, 12} - }, - { {226, 178, 81, 251, 9}, - {117, 32, 187, 159, 3}, - {157, 248, 164, 212, 7}, - {207, 157, 208, 74, 14} - }, - { {108, 39, 137, 18, 7}, - {151, 146, 236, 160, 1}, - {228, 137, 30, 67, 6}, - {128, 83, 116, 158, 9} - }, - { {78, 213, 70, 229, 4}, - {234, 71, 82, 173, 2}, - {42, 118, 42, 183, 2}, - {75, 84, 174, 37, 7} - }, - { {240, 6, 14, 244, 9}, - {12, 73, 175, 170, 2}, - {146, 247, 6, 0, 15}, - {69, 95, 89, 35, 0} - }, - { {179, 69, 148, 196, 9}, - {12, 143, 33, 123, 2}, - {146, 50, 154, 44, 13}, - {77, 232, 79, 19, 0} - }, - { {183, 99, 0, 71, 12}, - {137, 14, 105, 79, 1}, - {62, 32, 12, 110, 13}, - {143, 41, 103, 9, 1} - }, - { {124, 196, 229, 3, 1}, - {182, 141, 48, 164, 5}, - {140, 10, 114, 51, 14}, - {162, 80, 203, 22, 13} - }, - { {86, 1, 102, 16, 6}, - {160, 91, 192, 129, 4}, - {96, 134, 104, 6, 10}, - {40, 16, 61, 160, 5} - }, - { {82, 75, 187, 242, 15}, - {20, 222, 207, 153, 15}, - {244, 253, 221, 36, 10}, - {249, 159, 55, 178, 8} - }, - { {142, 50, 98, 30, 15}, - {239, 112, 201, 3, 5}, - {247, 132, 100, 199, 1}, - {172, 9, 48, 239, 7} - }, - { {66, 68, 75, 195, 9}, - {52, 68, 5, 173, 3}, - {156, 61, 34, 36, 2}, - {203, 90, 2, 34, 12} - }, - { {139, 101, 126, 225, 12}, - {35, 71, 71, 127, 6}, - {56, 119, 234, 109, 1}, - {111, 238, 46, 44, 4} - }, - { {53, 42, 182, 84, 7}, - {141, 217, 232, 88, 12}, - {226, 166, 213, 74, 12}, - {49, 161, 121, 187, 1} - }, - { {231, 165, 75, 233, 2}, - {177, 114, 54, 239, 2}, - {73, 125, 42, 94, 7}, - {79, 118, 196, 232, 13} - }, - { {120, 30, 244, 21, 3}, - {110, 153, 168, 180, 12}, - {202, 130, 247, 129, 14}, - {50, 209, 89, 151, 6} - }, - { {50, 242, 74, 129, 2}, - {97, 92, 60, 5, 2}, - {72, 21, 36, 244, 12}, - {74, 3, 195, 168, 6} - }, - { {40, 17, 16, 119, 11}, - {78, 18, 163, 28, 1}, - {222, 224, 136, 129, 4}, - {131, 140, 84, 135, 2} - }, - { {37, 203, 65, 84, 13}, - {188, 6, 249, 72, 8}, - {178, 168, 45, 58, 4}, - {17, 41, 246, 3, 13} - }, - { {167, 103, 245, 103, 1}, - {189, 135, 42, 127, 5}, - {142, 106, 254, 110, 5}, - {175, 229, 78, 27, 13} - }, - { {91, 165, 158, 70, 11}, - {15, 219, 21, 249, 1}, - {214, 39, 154, 93, 10}, - {137, 250, 141, 191, 0} - }, - { {88, 61, 62, 106, 2}, - {67, 123, 6, 184, 13}, - {69, 103, 203, 193, 10}, - {177, 214, 13, 236, 2} - }, - { {191, 77, 67, 125, 10}, - {186, 126, 163, 111, 8}, - {91, 236, 43, 47, 13}, - {31, 108, 87, 229, 13} - }, - { {160, 164, 162, 247, 2}, - {9, 208, 178, 46, 7}, - {78, 244, 82, 80, 5}, - {231, 68, 208, 185, 0} - }, - { {93, 52, 153, 184, 6}, - {211, 184, 198, 240, 2}, - {97, 217, 146, 203, 10}, - {64, 246, 49, 220, 11} - }, - { {211, 7, 214, 157, 5}, - {44, 235, 200, 247, 2}, - {171, 150, 190, 12, 11}, - {78, 241, 61, 115, 4} - }, - { {155, 172, 247, 16, 14}, - {51, 217, 209, 115, 12}, - {112, 142, 243, 93, 9}, - {60, 232, 185, 188, 12} - }, - { {196, 108, 246, 252, 13}, - {173, 229, 195, 186, 14}, - {179, 246, 243, 98, 3}, - {117, 220, 58, 123, 5} - }, - { {184, 1, 141, 118, 12}, - {26, 139, 231, 10, 1}, - {54, 235, 24, 1, 13}, - {133, 14, 125, 21, 8} - }, - { {232, 151, 127, 181, 13}, - {126, 67, 255, 182, 6}, - {186, 223, 238, 145, 7}, - {102, 223, 252, 39, 14} - }, - { {11, 60, 141, 188, 5}, - {95, 161, 198, 97, 10}, - {163, 219, 19, 205, 0}, - {88, 102, 56, 95, 10} - }, - { {20, 20, 133, 139, 8}, - {208, 169, 1, 36, 3}, - {29, 26, 18, 130, 8}, - {194, 72, 9, 80, 11} - }, - { {115, 104, 16, 10, 4}, - {1, 44, 96, 209, 9}, - {37, 0, 129, 108, 14}, - {152, 176, 99, 72, 0} - }, - { {18, 132, 134, 239, 3}, - {12, 249, 18, 45, 3}, - {207, 118, 18, 20, 8}, - {203, 68, 137, 243, 0} - }, - { {210, 252, 86, 125, 0}, - {105, 109, 146, 191, 8}, - {11, 230, 163, 244, 11}, - {31, 212, 155, 105, 6} - }, - { {91, 207, 66, 130, 14}, - {34, 94, 89, 225, 11}, - {116, 20, 47, 61, 10}, - {216, 121, 167, 164, 4} - }, - { {73, 183, 123, 167, 3}, - {127, 82, 30, 244, 7}, - {206, 93, 238, 217, 2}, - {226, 247, 132, 175, 14} - }, - { {97, 229, 12, 169, 15}, - {5, 55, 119, 228, 2}, - {249, 83, 10, 120, 6}, - {66, 126, 238, 202, 0} - }, - { {28, 221, 19, 226, 0}, - {210, 78, 18, 56, 11}, - {4, 124, 139, 179, 8}, - {209, 196, 135, 36, 11} - }, - { {241, 23, 253, 83, 15}, - {116, 155, 237, 254, 5}, - {252, 171, 254, 136, 15}, - {167, 251, 125, 146, 14} - }, - { {141, 51, 92, 19, 13}, - {231, 3, 205, 86, 1}, - {188, 131, 172, 203, 1}, - {134, 171, 60, 14, 7} - }, - { {248, 223, 155, 48, 4}, - {82, 206, 254, 178, 8}, - {32, 205, 159, 177, 15}, - {20, 215, 247, 52, 10} - }, - { {205, 115, 59, 196, 0}, - {219, 70, 12, 218, 6}, - {2, 61, 204, 235, 3}, - {101, 179, 6, 45, 11} - }, - { {35, 29, 150, 151, 9}, - {76, 195, 161, 117, 11}, - {158, 150, 155, 140, 4}, - {218, 232, 92, 51, 2} - }, - { {44, 151, 177, 71, 6}, - {218, 146, 120, 60, 5}, - {110, 40, 222, 147, 4}, - {163, 193, 228, 149, 11} - }, - { {230, 105, 156, 80, 1}, - {133, 135, 164, 155, 8}, - {128, 163, 153, 102, 7}, - {29, 146, 94, 26, 1} - }, - { {181, 161, 208, 86, 14}, - {169, 154, 241, 90, 1}, - {118, 160, 184, 90, 13}, - {133, 168, 245, 153, 5} - }, - { {60, 125, 33, 88, 4}, - {211, 46, 224, 40, 12}, - {33, 168, 75, 227, 12}, - {49, 64, 119, 76, 11} - }, - { {173, 20, 11, 20, 5}, - {222, 64, 228, 98, 0}, - {162, 141, 2, 139, 5}, - {4, 98, 112, 39, 11} - }, - { {251, 9, 110, 114, 3}, - {38, 91, 166, 203, 13}, - {196, 231, 105, 13, 15}, - {189, 54, 93, 166, 4} - }, - { {23, 132, 105, 191, 13}, - {188, 40, 215, 101, 7}, - {191, 217, 98, 30, 8}, - {234, 110, 177, 67, 13} - }, - { {36, 48, 61, 47, 6}, - {217, 49, 102, 20, 5}, - {111, 75, 192, 194, 4}, - {162, 134, 104, 201, 11} - }, - { {235, 214, 231, 21, 5}, - {126, 197, 248, 231, 4}, - {170, 142, 118, 189, 7}, - {46, 113, 250, 55, 14} - }, - { {147, 91, 170, 215, 11}, - {76, 222, 141, 79, 15}, - {222, 181, 93, 172, 9}, - {255, 43, 23, 179, 2} - }, - { {209, 95, 34, 205, 13}, - {76, 110, 73, 238, 14}, - {187, 52, 79, 168, 11}, - {119, 121, 39, 99, 2} - }, - { {55, 178, 213, 83, 15}, - {245, 153, 249, 93, 1}, - {252, 170, 180, 222, 12}, - {139, 169, 249, 154, 15} - }, - { {211, 101, 213, 98, 8}, - {49, 143, 3, 251, 1}, - {20, 106, 186, 108, 11}, - {141, 252, 15, 24, 12} - }, - { {29, 118, 183, 146, 15}, - {215, 221, 201, 112, 7}, - {244, 158, 214, 235, 8}, - {224, 233, 59, 190, 11} - }, - { {87, 185, 126, 171, 11}, - {229, 123, 23, 213, 15}, - {221, 87, 233, 222, 10}, - {250, 190, 141, 234, 7} - }, - { {9, 11, 171, 164, 4}, - {26, 194, 78, 64, 14}, - {34, 93, 93, 9, 0}, - {112, 39, 36, 53, 8} - }, - { {163, 131, 97, 118, 11}, - {60, 18, 187, 75, 5}, - {214, 232, 108, 28, 5}, - {173, 45, 212, 131, 12} - }, - { {156, 250, 125, 156, 6}, - {251, 61, 220, 18, 14}, - {99, 155, 229, 243, 9}, - {116, 131, 187, 205, 15} - }, - { {76, 134, 94, 122, 15}, - {166, 113, 223, 184, 1}, - {245, 231, 166, 19, 2}, - {129, 223, 184, 230, 5} - }, - { {249, 13, 22, 148, 11}, - {14, 91, 161, 242, 10}, - {210, 150, 139, 9, 15}, - {84, 248, 93, 167, 0} - }, - { {120, 93, 12, 212, 1}, - {78, 15, 164, 168, 10}, - {130, 179, 11, 161, 14}, - {81, 82, 95, 7, 2} - }, - { {51, 98, 95, 192, 1}, - {53, 77, 44, 89, 2}, - {128, 63, 164, 108, 12}, - {73, 163, 75, 42, 12} - }, - { {0, 213, 240, 148, 3}, - {108, 150, 144, 48, 6}, - {194, 144, 250, 176, 0}, - {96, 192, 150, 147, 6} - }, - { {167, 185, 175, 176, 8}, - {209, 195, 183, 67, 14}, - {16, 223, 89, 222, 5}, - {124, 46, 220, 56, 11} - }, - { {223, 59, 151, 88, 10}, - {211, 251, 137, 219, 8}, - {81, 174, 157, 207, 11}, - {29, 185, 29, 252, 11} - }, - { {182, 138, 31, 89, 2}, - {144, 121, 188, 31, 8}, - {73, 175, 133, 22, 13}, - {31, 131, 217, 224, 9} - }, - { {103, 50, 106, 212, 0}, - {233, 64, 172, 201, 6}, - {2, 181, 100, 206, 6}, - {105, 51, 80, 41, 7} - }, - { {7, 184, 90, 134, 3}, - {237, 80, 20, 81, 11}, - {198, 21, 161, 222, 0}, - {216, 162, 128, 171, 7} - }, - { {37, 38, 25, 247, 15}, - {157, 16, 239, 124, 3}, - {254, 249, 134, 74, 4}, - {195, 239, 112, 139, 9} - }, - { {130, 206, 71, 104, 3}, - {52, 117, 26, 43, 8}, - {193, 110, 39, 52, 1}, - {29, 69, 138, 226, 12} - }, - { {108, 230, 33, 121, 12}, - {147, 36, 251, 172, 4}, - {57, 232, 70, 115, 6}, - {35, 93, 242, 76, 9} - }, - { {98, 230, 221, 55, 8}, - {57, 133, 191, 181, 1}, - {30, 203, 182, 116, 6}, - {138, 223, 218, 25, 12} - }, - { {62, 92, 11, 17, 10}, - {210, 92, 165, 37, 8}, - {88, 141, 3, 167, 12}, - {26, 74, 83, 164, 11} - }, - { {57, 245, 112, 80, 8}, - {99, 14, 177, 120, 4}, - {16, 160, 234, 249, 12}, - {33, 232, 215, 12, 6} - }, - { {214, 87, 51, 142, 6}, - {216, 126, 72, 179, 7}, - {103, 28, 206, 166, 11}, - {236, 209, 39, 225, 11} - }, - { {192, 98, 168, 92, 12}, - {9, 164, 205, 138, 4}, - {51, 161, 84, 96, 3}, - {37, 27, 50, 89, 0} - }, - { {131, 220, 0, 222, 5}, - {76, 36, 208, 107, 11}, - {167, 176, 3, 188, 1}, - {221, 96, 178, 67, 2} - }, - { {177, 33, 195, 250, 3}, - {53, 250, 162, 74, 3}, - {197, 252, 56, 72, 13}, - {197, 36, 85, 250, 12} - }, - { {227, 149, 10, 113, 14}, - {64, 82, 247, 239, 0}, - {120, 229, 10, 156, 7}, - {15, 126, 244, 160, 2} - }, - { {113, 29, 253, 190, 8}, - {120, 171, 167, 240, 15}, - {23, 219, 251, 136, 14}, - {240, 254, 93, 81, 14} - }, - { {130, 171, 112, 191, 2}, - {41, 50, 154, 23, 15}, - {79, 208, 237, 84, 1}, - {254, 133, 148, 201, 4} - }, - { {93, 123, 132, 66, 1}, - {199, 143, 8, 200, 9}, - {132, 34, 29, 235, 10}, - {145, 49, 15, 30, 3} - }, - { {103, 239, 52, 200, 12}, - {129, 39, 121, 249, 14}, - {49, 50, 207, 126, 6}, - {121, 249, 238, 72, 1} - }, - { {202, 53, 231, 230, 13}, - {127, 195, 67, 171, 7}, - {182, 126, 122, 197, 3}, - {237, 92, 44, 63, 14} - }, - { {36, 1, 77, 111, 11}, - {188, 51, 39, 12, 1}, - {223, 107, 40, 2, 4}, - {131, 14, 76, 195, 13} - }, - { {183, 239, 157, 161, 14}, - {145, 159, 127, 119, 10}, - {120, 91, 159, 126, 13}, - {94, 239, 239, 152, 9} - }, - { {176, 76, 172, 188, 7}, - {12, 189, 230, 34, 14}, - {227, 211, 83, 32, 13}, - {116, 70, 123, 211, 0} - }, - { {193, 166, 3, 154, 8}, - {17, 96, 153, 226, 3}, - {21, 156, 6, 88, 3}, - {196, 121, 144, 104, 8} - }, - { {197, 1, 82, 163, 10}, - {160, 82, 3, 214, 3}, - {92, 84, 168, 10, 3}, - {198, 188, 4, 160, 5} - }, - { {220, 202, 43, 43, 7}, - {150, 124, 94, 134, 13}, - {237, 77, 69, 51, 11}, - {182, 23, 163, 230, 9} - }, - { {88, 6, 54, 143, 3}, - {14, 121, 8, 180, 7}, - {207, 22, 198, 1, 10}, - {226, 209, 9, 231, 0} - }, - { {139, 223, 114, 151, 10}, - {106, 86, 153, 119, 15}, - {94, 148, 239, 189, 1}, - {254, 233, 150, 165, 6} - }, - { {118, 72, 225, 171, 10}, - {176, 188, 35, 133, 15}, - {93, 88, 113, 38, 14}, - {250, 28, 67, 208, 13} - }, - { {224, 20, 244, 247, 7}, - {108, 145, 226, 190, 7}, - {238, 242, 242, 128, 7}, - {231, 212, 120, 147, 6} - }, - { {113, 170, 60, 249, 0}, - {1, 41, 190, 220, 14}, - {9, 243, 197, 88, 14}, - {115, 183, 217, 72, 0} - }, - { {156, 171, 243, 108, 14}, - {187, 250, 91, 26, 12}, - {115, 108, 253, 83, 9}, - {53, 141, 165, 253, 13} - }, - { {135, 84, 73, 90, 15}, - {244, 52, 197, 107, 1}, - {245, 169, 34, 174, 1}, - {141, 106, 50, 194, 15} - }, - { {154, 153, 213, 71, 2}, - {122, 155, 16, 31, 9}, - {78, 42, 185, 149, 9}, - {159, 128, 141, 149, 14} - }, - { {231, 44, 187, 69, 6}, - {153, 208, 100, 255, 12}, - {106, 45, 211, 78, 7}, - {63, 242, 96, 185, 9} - }, - { {196, 176, 203, 147, 1}, - {245, 192, 148, 134, 3}, - {140, 157, 48, 210, 3}, - {198, 18, 144, 58, 15} - }, - { {137, 237, 4, 93, 7}, - {15, 55, 208, 110, 8}, - {235, 162, 11, 121, 1}, - {23, 96, 190, 207, 0} - }, - { {199, 169, 10, 58, 11}, - {133, 114, 151, 195, 9}, - {213, 197, 9, 94, 3}, - {156, 62, 148, 234, 1} - }, - { {65, 90, 235, 196, 2}, - {120, 212, 12, 200, 14}, - {66, 61, 117, 168, 2}, - {113, 51, 2, 177, 14} - }, - { {127, 85, 215, 48, 2}, - {242, 223, 162, 241, 0}, - {64, 206, 186, 175, 14}, - {8, 244, 95, 180, 15} - }, - { {17, 75, 16, 122, 6}, - {0, 62, 202, 88, 9}, - {101, 224, 141, 40, 8}, - {145, 165, 55, 192, 0} - }, - { {230, 235, 111, 39, 4}, - {185, 71, 126, 135, 13}, - {46, 79, 109, 118, 7}, - {190, 23, 238, 41, 13} - }, - { {132, 244, 176, 135, 15}, - {205, 148, 81, 54, 7}, - {254, 16, 210, 242, 1}, - {230, 200, 162, 155, 3} - }, - { {91, 222, 44, 8, 8}, - {66, 45, 29, 225, 12}, - {17, 3, 71, 189, 10}, - {56, 123, 139, 68, 2} - }, - { {205, 253, 149, 194, 7}, - {215, 151, 80, 250, 11}, - {228, 58, 155, 251, 3}, - {213, 240, 174, 158, 11} - }, - { {51, 193, 37, 123, 3}, - {20, 63, 178, 77, 5}, - {205, 234, 72, 60, 12}, - {171, 36, 223, 194, 8} - }, - { {99, 27, 71, 141, 15}, - {124, 115, 105, 197, 10}, - {251, 30, 45, 140, 6}, - {90, 57, 108, 227, 14} - }, - { {229, 239, 80, 81, 11}, - {165, 22, 185, 254, 8}, - {216, 160, 175, 122, 7}, - {23, 249, 214, 138, 5} - }, - { {65, 141, 160, 190, 12}, - {8, 162, 211, 224, 15}, - {55, 208, 91, 24, 2}, - {240, 124, 180, 81, 0} - }, - { {193, 184, 36, 139, 1}, - {69, 33, 16, 198, 15}, - {141, 18, 65, 216, 3}, - {246, 48, 136, 74, 2} - }, - { {118, 222, 87, 133, 11}, - {252, 93, 57, 181, 10}, - {218, 30, 167, 182, 14}, - {90, 217, 203, 163, 15} - }, - { {219, 201, 87, 218, 6}, - {50, 127, 208, 219, 11}, - {101, 190, 169, 61, 11}, - {221, 176, 191, 228, 12} - }, - { {202, 225, 244, 5, 4}, - {43, 135, 80, 151, 4}, - {42, 2, 248, 117, 3}, - {46, 144, 174, 29, 4} - }, - { {145, 76, 36, 42, 2}, - {0, 61, 2, 98, 13}, - {69, 66, 67, 40, 9}, - {180, 100, 11, 192, 0} - }, - { {69, 163, 208, 168, 2}, - {161, 178, 26, 208, 2}, - {65, 80, 188, 90, 2}, - {64, 181, 132, 216, 5} - }, - { {136, 154, 125, 93, 13}, - {126, 33, 221, 30, 12}, - {187, 171, 229, 145, 1}, - {55, 139, 184, 71, 14} - }, - { {154, 61, 179, 211, 2}, - {83, 218, 128, 63, 15}, - {76, 188, 219, 197, 9}, - {255, 192, 21, 188, 10} - }, - { {208, 44, 134, 112, 15}, - {5, 217, 195, 170, 8}, - {240, 230, 19, 64, 11}, - {21, 92, 57, 186, 0} - }, - { {21, 123, 52, 80, 12}, - {193, 15, 201, 88, 12}, - {48, 162, 205, 234, 8}, - {49, 169, 63, 8, 3} - }, - { {137, 13, 55, 91, 10}, - {18, 115, 129, 126, 13}, - {93, 174, 203, 9, 1}, - {183, 232, 28, 228, 8} - }, - { {137, 27, 201, 59, 10}, - {114, 178, 143, 70, 9}, - {93, 201, 61, 137, 1}, - {150, 47, 20, 212, 14} - }, - { {138, 2, 216, 10, 3}, - {38, 176, 12, 19, 1}, - {197, 1, 180, 5, 1}, - {140, 131, 0, 214, 4} - }, - { {30, 93, 243, 65, 14}, - {242, 222, 65, 61, 12}, - {120, 44, 251, 167, 8}, - {59, 200, 39, 180, 15} - }, - { {120, 109, 137, 131, 2}, - {19, 158, 36, 164, 11}, - {76, 25, 27, 97, 14}, - {210, 82, 71, 156, 8} - }, - { {172, 247, 228, 126, 13}, - {239, 167, 251, 42, 5}, - {183, 226, 126, 243, 5}, - {165, 77, 254, 95, 7} - }, - { {28, 22, 226, 90, 0}, - {226, 232, 136, 40, 5}, - {5, 164, 118, 131, 8}, - {161, 65, 17, 116, 7} - }, - { {46, 169, 4, 13, 9}, - {143, 35, 49, 5, 8}, - {155, 2, 9, 87, 4}, - {26, 8, 204, 79, 1} - }, - { {243, 38, 138, 238, 5}, - {13, 232, 110, 235, 3}, - {167, 117, 22, 76, 15}, - {205, 119, 97, 123, 0} - }, - { {128, 232, 75, 204, 11}, - {61, 116, 21, 10, 10}, - {211, 61, 33, 112, 1}, - {85, 10, 130, 235, 12} - }, - { {162, 190, 211, 245, 12}, - {121, 192, 251, 63, 10}, - {58, 252, 183, 212, 5}, - {95, 205, 240, 57, 14} - }, - { {179, 172, 4, 251, 2}, - {1, 57, 178, 111, 11}, - {77, 242, 3, 92, 13}, - {223, 100, 217, 200, 0} - }, - { {132, 89, 129, 25, 2}, - {208, 182, 128, 6, 8}, - {73, 136, 25, 162, 1}, - {22, 0, 22, 208, 11} - }, - { {96, 167, 159, 201, 4}, - {17, 227, 124, 188, 2}, - {41, 63, 158, 80, 6}, - {67, 211, 236, 120, 8} - }, - { {19, 143, 250, 197, 9}, - {44, 202, 29, 125, 14}, - {154, 53, 255, 28, 8}, - {123, 235, 133, 51, 4} - }, - { {214, 125, 112, 144, 3}, - {229, 30, 128, 179, 14}, - {192, 144, 235, 230, 11}, - {124, 208, 23, 138, 7} - }, - { {43, 138, 160, 242, 5}, - {6, 128, 250, 73, 15}, - {164, 240, 85, 29, 4}, - {249, 37, 240, 22, 0} - }, - { {41, 131, 176, 59, 10}, - {2, 178, 187, 84, 5}, - {93, 192, 220, 25, 4}, - {162, 173, 212, 212, 0} - }, - { {140, 215, 81, 28, 8}, - {250, 38, 153, 50, 0}, - {19, 136, 174, 179, 1}, - {4, 201, 150, 69, 15} - }, - { {47, 222, 77, 2, 12}, - {242, 5, 125, 97, 9}, - {52, 11, 39, 191, 4}, - {152, 107, 234, 4, 15} - }, - { {213, 4, 207, 5, 12}, - {184, 201, 69, 230, 0}, - {58, 15, 50, 10, 11}, - {6, 122, 41, 49, 13} - }, - { {186, 231, 214, 153, 0}, - {35, 239, 184, 55, 2}, - {9, 150, 190, 117, 13}, - {78, 193, 223, 124, 4} - }, - { {156, 243, 126, 164, 13}, - {239, 79, 95, 18, 6}, - {178, 87, 236, 243, 9}, - {100, 143, 175, 47, 7} - }, - { {143, 79, 97, 177, 14}, - {178, 22, 203, 103, 14}, - {120, 216, 111, 47, 1}, - {126, 109, 54, 132, 13} - }, - { {137, 255, 175, 206, 6}, - {91, 247, 92, 106, 15}, - {103, 63, 95, 249, 1}, - {245, 99, 174, 253, 10} - }, - { {124, 126, 177, 202, 2}, - {211, 188, 40, 184, 15}, - {69, 56, 215, 227, 14}, - {241, 209, 67, 220, 11} - }, - { {150, 194, 61, 167, 11}, - {156, 29, 31, 23, 7}, - {222, 91, 196, 54, 9}, - {238, 143, 139, 131, 9} - } -}; - - - -static unsigned char DICT_APRILTAG_36h11_BYTES[][4][5] = -{ - { {33, 161, 70, 186, 11}, - {37, 115, 179, 64, 3}, - {213, 214, 40, 88, 4}, - {192, 44, 220, 234, 4} - }, - { {146, 209, 143, 233, 11}, - {84, 255, 23, 15, 2}, - {217, 127, 24, 180, 9}, - {79, 14, 143, 242, 10} - }, - { {112, 137, 1, 75, 11}, - {20, 58, 49, 140, 9}, - {221, 40, 9, 16, 14}, - {147, 24, 197, 194, 8} - }, - { {25, 57, 121, 226, 7}, - {119, 26, 70, 88, 15}, - {228, 121, 233, 201, 8}, - {241, 166, 37, 142, 14} - }, - { {68, 21, 61, 61, 7}, - {220, 51, 198, 180, 4}, - {235, 203, 202, 130, 2}, - {34, 214, 60, 195, 11} - }, - { {53, 205, 91, 140, 15}, - {188, 126, 117, 112, 10}, - {243, 29, 171, 58, 12}, - {80, 234, 231, 227, 13} - }, - { {161, 11, 165, 106, 0}, - {16, 163, 42, 74, 13}, - {5, 106, 93, 8, 5}, - {181, 37, 76, 80, 8} - }, - { {43, 135, 74, 96, 8}, - {34, 66, 63, 105, 0}, - {16, 101, 46, 29, 4}, - {9, 111, 196, 36, 4} - }, - { {181, 127, 184, 212, 4}, - {201, 142, 236, 122, 14}, - {34, 177, 223, 234, 13}, - {117, 227, 119, 25, 3} - }, - { {78, 32, 181, 166, 4}, - {155, 129, 66, 145, 7}, - {38, 90, 208, 71, 2}, - {232, 148, 40, 29, 9} - }, - { {97, 216, 151, 242, 12}, - {80, 197, 243, 216, 11}, - {52, 254, 145, 184, 6}, - {209, 188, 250, 48, 10} - }, - { {171, 52, 105, 255, 12}, - {123, 32, 231, 111, 7}, - {63, 249, 98, 205, 5}, - {239, 110, 112, 77, 14} - }, - { {89, 76, 164, 92, 2}, - {10, 189, 128, 232, 12}, - {67, 162, 83, 41, 10}, - {49, 112, 27, 213, 0} - }, - { {250, 28, 45, 46, 2}, - {90, 57, 38, 163, 13}, - {71, 75, 67, 133, 15}, - {188, 86, 73, 197, 10} - }, - { {151, 194, 75, 151, 2}, - {184, 92, 156, 71, 3}, - {78, 157, 36, 62, 9}, - {206, 35, 147, 161, 13} - }, - { {117, 146, 134, 36, 10}, - {200, 217, 59, 192, 0}, - {82, 70, 20, 154, 14}, - {0, 61, 201, 177, 3} - }, - { {28, 170, 254, 153, 10}, - {163, 249, 157, 20, 14}, - {89, 151, 245, 83, 8}, - {114, 139, 153, 252, 5} - }, - { {50, 54, 221, 193, 6}, - {113, 153, 108, 61, 2}, - {104, 59, 182, 196, 12}, - {75, 195, 105, 152, 14} - }, - { {136, 78, 82, 125, 6}, - {42, 116, 202, 62, 8}, - {107, 228, 167, 33, 1}, - {23, 197, 50, 229, 4} - }, - { {87, 113, 168, 199, 14}, - {201, 158, 69, 205, 7}, - {126, 49, 88, 238, 10}, - {235, 58, 39, 153, 3} - }, - { {245, 41, 37, 184, 1}, - {149, 43, 162, 194, 14}, - {129, 218, 73, 74, 15}, - {116, 52, 93, 74, 9} - }, - { {46, 89, 204, 26, 1}, - {230, 167, 164, 1, 9}, - {133, 131, 57, 167, 4}, - {152, 2, 94, 86, 7} - }, - { {127, 165, 138, 179, 1}, - {135, 202, 182, 229, 3}, - {140, 213, 26, 95, 14}, - {202, 118, 213, 62, 1} - }, - { {235, 67, 56, 79, 9}, - {14, 38, 45, 223, 5}, - {159, 33, 204, 45, 7}, - {175, 187, 70, 71, 0} - }, - { {57, 19, 213, 52, 5}, - {126, 139, 234, 80, 0}, - {162, 202, 188, 137, 12}, - {0, 165, 125, 23, 14} - }, - { {215, 155, 26, 59, 5}, - {196, 106, 222, 215, 9}, - {173, 197, 141, 158, 11}, - {158, 183, 181, 98, 3} - }, - { {13, 251, 231, 104, 13}, - {247, 231, 91, 72, 12}, - {177, 110, 125, 251, 0}, - {49, 45, 174, 126, 15} - }, - { {92, 215, 160, 49, 13}, - {198, 142, 219, 164, 4}, - {184, 192, 94, 179, 10}, - {34, 93, 183, 22, 3} - }, - { {185, 200, 247, 164, 11}, - {62, 221, 51, 82, 14}, - {210, 94, 241, 57, 13}, - {116, 172, 203, 183, 12} - }, - { {70, 152, 126, 6, 11}, - {236, 81, 21, 145, 13}, - {214, 7, 225, 150, 2}, - {184, 154, 136, 163, 7} - }, - { {110, 12, 93, 82, 7}, - {182, 17, 228, 185, 9}, - {228, 171, 163, 7, 6}, - {153, 210, 120, 134, 13} - }, - { {91, 197, 103, 187, 4}, - {50, 111, 210, 229, 7}, - {45, 222, 106, 61, 10}, - {234, 116, 191, 100, 12} - }, - { {30, 99, 2, 188, 2}, - {139, 126, 138, 1, 2}, - {67, 212, 12, 103, 8}, - {72, 5, 23, 237, 1} - }, - { {138, 199, 208, 70, 10}, - {42, 150, 25, 59, 1}, - {86, 32, 190, 53, 1}, - {141, 201, 134, 149, 4} - }, - { {166, 95, 226, 50, 6}, - {224, 214, 234, 35, 13}, - {100, 196, 127, 166, 5}, - {188, 69, 118, 176, 7} - }, - { {84, 0, 235, 97, 6}, - {176, 216, 70, 140, 4}, - {104, 109, 112, 2, 10}, - {35, 22, 33, 176, 13} - }, - { {247, 160, 102, 131, 6}, - {161, 89, 112, 199, 7}, - {108, 22, 96, 94, 15}, - {238, 48, 233, 168, 5} - }, - { {45, 208, 175, 223, 6}, - {218, 245, 244, 76, 7}, - {111, 191, 80, 187, 4}, - {227, 34, 250, 245, 11} - }, - { {59, 156, 182, 11, 1}, - {70, 233, 48, 117, 13}, - {141, 6, 211, 157, 12}, - {186, 224, 201, 118, 2} - }, - { {173, 106, 28, 175, 9}, - {143, 37, 47, 86, 11}, - {159, 83, 133, 107, 5}, - {214, 175, 74, 79, 1} - }, - { {147, 182, 46, 251, 5}, - {69, 105, 222, 111, 7}, - {173, 247, 70, 220, 9}, - {239, 103, 185, 106, 2} - }, - { {187, 33, 13, 147, 13}, - {23, 11, 229, 71, 3}, - {188, 155, 8, 77, 13}, - {206, 42, 125, 14, 8} - }, - { {222, 229, 80, 148, 11}, - {175, 30, 145, 179, 2}, - {210, 144, 170, 119, 11}, - {76, 216, 151, 143, 5} - }, - { {160, 205, 20, 121, 11}, - {4, 55, 179, 62, 8}, - {217, 226, 139, 48, 5}, - {23, 204, 222, 194, 0} - }, - { {42, 35, 171, 178, 7}, - {23, 210, 238, 1, 7}, - {228, 221, 92, 69, 4}, - {232, 7, 116, 190, 8} - }, - { {79, 103, 244, 181, 15}, - {175, 151, 203, 245, 6}, - {250, 210, 254, 111, 2}, - {106, 253, 62, 159, 5} - }, - { {88, 168, 21, 129, 8}, - {19, 9, 17, 148, 10}, - {24, 26, 129, 81, 10}, - {82, 152, 137, 12, 8} - }, - { {116, 52, 39, 214, 4}, - {217, 73, 224, 168, 7}, - {38, 190, 66, 194, 14}, - {225, 80, 121, 41, 11} - }, - { {29, 236, 64, 135, 4}, - {171, 12, 80, 100, 11}, - {46, 16, 35, 123, 8}, - {210, 96, 163, 13, 5} - }, - { {137, 42, 179, 160, 2}, - {19, 208, 10, 82, 14}, - {64, 92, 213, 73, 1}, - {116, 165, 0, 188, 8} - }, - { {56, 213, 116, 46, 14}, - {106, 63, 115, 48, 5}, - {119, 66, 234, 177, 12}, - {160, 204, 239, 197, 6} - }, - { {12, 67, 86, 122, 1}, - {166, 103, 138, 24, 1}, - {133, 230, 172, 35, 0}, - {129, 133, 30, 102, 5} - }, - { {93, 179, 17, 203, 1}, - {215, 42, 24, 220, 3}, - {141, 56, 140, 219, 10}, - {195, 177, 133, 78, 11} - }, - { {201, 87, 202, 31, 9}, - {110, 230, 141, 230, 1}, - {159, 133, 62, 169, 3}, - {134, 123, 22, 119, 6} - }, - { {162, 36, 87, 130, 3}, - {53, 81, 32, 51, 3}, - {196, 30, 162, 68, 5}, - {204, 192, 72, 170, 12} - }, - { {41, 172, 233, 143, 3}, - {63, 176, 52, 100, 15}, - {207, 25, 115, 89, 4}, - {242, 98, 192, 223, 12} - }, - { {204, 197, 44, 82, 8}, - {130, 7, 149, 170, 5}, - {20, 163, 74, 51, 3}, - {165, 90, 158, 4, 1} - }, - { {218, 139, 53, 120, 12}, - {18, 43, 219, 155, 12}, - {49, 234, 205, 21, 11}, - {61, 157, 189, 68, 8} - }, - { {213, 180, 185, 227, 6}, - {209, 152, 86, 254, 7}, - {108, 121, 210, 218, 11}, - {231, 246, 161, 152, 11} - }, - { {172, 156, 221, 60, 14}, - {250, 177, 247, 50, 8}, - {115, 203, 179, 147, 5}, - {20, 206, 248, 213, 15} - }, - { {203, 218, 168, 57, 1}, - {70, 164, 158, 199, 12}, - {137, 193, 85, 189, 3}, - {62, 55, 146, 86, 2} - }, - { {25, 134, 37, 107, 1}, - {22, 41, 26, 108, 5}, - {141, 106, 70, 25, 8}, - {163, 101, 137, 70, 8} - }, - { {186, 230, 204, 136, 9}, - {39, 173, 61, 35, 2}, - {145, 19, 54, 117, 13}, - {76, 75, 203, 94, 4} - }, - { {223, 145, 177, 14, 5}, - {222, 170, 80, 211, 5}, - {167, 8, 216, 159, 11}, - {172, 176, 165, 87, 11} - }, - { {161, 169, 213, 167, 5}, - {61, 131, 114, 86, 11}, - {174, 90, 185, 88, 5}, - {214, 164, 236, 27, 12} - }, - { {43, 101, 26, 169, 13}, - {7, 102, 103, 117, 2}, - {185, 85, 138, 109, 4}, - {74, 238, 102, 110, 0} - }, - { {77, 92, 46, 25, 13}, - {198, 101, 197, 228, 12}, - {185, 135, 67, 171, 2}, - {50, 122, 58, 102, 3} - }, - { {91, 22, 55, 54, 11}, - {94, 89, 139, 241, 5}, - {214, 206, 198, 141, 10}, - {168, 253, 25, 167, 10} - }, - { {247, 83, 214, 10, 8}, - {224, 239, 41, 211, 1}, - {21, 6, 188, 174, 15}, - {140, 185, 79, 112, 7} - }, - { {94, 132, 179, 125, 2}, - {154, 248, 146, 189, 4}, - {75, 236, 210, 23, 10}, - {43, 212, 145, 245, 9} - }, - { {252, 228, 58, 159, 2}, - {139, 124, 180, 182, 7}, - {79, 149, 194, 115, 15}, - {230, 210, 211, 237, 1} - }, - { {187, 146, 109, 26, 6}, - {114, 57, 252, 67, 5}, - {101, 139, 100, 157, 13}, - {172, 35, 249, 196, 14} - }, - { {237, 141, 35, 110, 5}, - {158, 98, 114, 234, 13}, - {167, 108, 75, 27, 7}, - {181, 116, 228, 103, 9} - }, - { {106, 248, 70, 243, 7}, - {103, 85, 242, 141, 11}, - {236, 246, 33, 245, 6}, - {219, 20, 250, 174, 6} - }, - { {234, 86, 165, 19, 8}, - {82, 133, 169, 167, 5}, - {28, 138, 86, 165, 7}, - {174, 89, 90, 20, 10} - }, - { {93, 73, 113, 70, 12}, - {186, 14, 65, 216, 13}, - {54, 40, 233, 43, 10}, - {177, 184, 39, 5, 13} - }, - { {71, 3, 96, 236, 10}, - {168, 50, 11, 201, 6}, - {83, 112, 108, 14, 2}, - {105, 61, 4, 193, 5} - }, - { {140, 75, 205, 103, 10}, - {186, 151, 15, 14, 9}, - {94, 107, 61, 35, 1}, - {151, 15, 14, 149, 13} - }, - { {41, 95, 57, 1, 14}, - {82, 22, 109, 116, 12}, - {120, 9, 207, 169, 4}, - {50, 235, 102, 132, 10} - }, - { {246, 181, 119, 233, 7}, - {245, 123, 114, 191, 6}, - {233, 126, 234, 214, 15}, - {111, 212, 237, 234, 15} - }, - { {82, 6, 2, 245, 10}, - {8, 88, 139, 173, 2}, - {90, 244, 6, 4, 10}, - {75, 93, 17, 161, 0} - }, - { {181, 17, 148, 146, 14}, - {192, 155, 225, 82, 3}, - {116, 146, 152, 138, 13}, - {196, 168, 125, 144, 3} - }, - { {72, 226, 153, 171, 7}, - {23, 180, 94, 148, 3}, - {237, 89, 148, 113, 2}, - {194, 151, 162, 222, 8} - }, - { {183, 159, 87, 55, 10}, - {248, 91, 187, 119, 9}, - {94, 206, 175, 158, 13}, - {158, 237, 221, 161, 15} - }, - { {168, 20, 198, 131, 14}, - {98, 209, 97, 38, 3}, - {124, 22, 50, 129, 5}, - {198, 72, 104, 180, 6} - }, - { {45, 169, 0, 88, 3}, - {135, 50, 176, 72, 8}, - {193, 160, 9, 91, 4}, - {17, 32, 212, 206, 1} - }, - { {212, 171, 164, 121, 7}, - {133, 187, 218, 142, 12}, - {233, 226, 93, 82, 11}, - {55, 21, 189, 218, 1} - }, - { {152, 42, 14, 101, 12}, - {11, 73, 79, 14, 8}, - {58, 103, 5, 65, 9}, - {23, 15, 41, 45, 0} - }, - { {244, 128, 204, 193, 5}, - {164, 137, 116, 142, 2}, - {168, 51, 48, 18, 15}, - {71, 18, 233, 18, 5} - }, - { {11, 32, 234, 115, 2}, - {35, 208, 134, 77, 5}, - {76, 229, 112, 77, 0}, - {171, 38, 16, 188, 4} - }, - { {169, 80, 103, 16, 10}, - {114, 85, 161, 66, 4}, - {80, 142, 96, 169, 5}, - {36, 40, 90, 164, 14} - }, - { {4, 134, 226, 238, 1}, - {172, 224, 26, 40, 7}, - {135, 116, 118, 18, 0}, - {225, 69, 128, 115, 5} - }, - { {176, 169, 114, 97, 5}, - {37, 74, 114, 30, 12}, - {168, 100, 233, 80, 13}, - {55, 132, 229, 42, 4} - }, - { {231, 63, 58, 37, 7}, - {205, 82, 110, 247, 12}, - {234, 69, 207, 206, 7}, - {62, 247, 100, 171, 3} - }, - { {23, 226, 5, 185, 8}, - {145, 45, 155, 69, 2}, - {25, 218, 4, 126, 8}, - {74, 45, 155, 72, 9} - }, - { {236, 154, 178, 178, 4}, - {194, 192, 250, 146, 15}, - {36, 212, 213, 147, 7}, - {244, 149, 240, 52, 3} - }, - { {217, 51, 158, 7, 6}, - {75, 219, 76, 214, 1}, - {110, 7, 156, 201, 11}, - {134, 179, 45, 189, 2} - }, - { {235, 136, 116, 249, 9}, - {38, 33, 179, 223, 14}, - {153, 242, 225, 29, 7}, - {127, 188, 216, 70, 4} - }, - { {148, 32, 165, 92, 12}, - {153, 169, 193, 10, 4}, - {51, 170, 80, 66, 9}, - {37, 8, 57, 89, 9} - }, - { {227, 100, 255, 153, 2}, - {49, 245, 164, 247, 6}, - {73, 159, 242, 108, 7}, - {110, 242, 90, 248, 12} - }, - { {138, 76, 184, 240, 10}, - {2, 148, 135, 59, 14}, - {80, 241, 211, 37, 1}, - {125, 206, 18, 148, 0} - }, - { {247, 42, 238, 118, 6}, - {169, 217, 238, 203, 13}, - {102, 231, 117, 78, 15}, - {189, 55, 121, 185, 5} - }, - { {115, 204, 107, 86, 9}, - {60, 76, 181, 233, 13}, - {150, 173, 99, 60, 14}, - {185, 122, 211, 35, 12} - }, - { {201, 156, 166, 165, 9}, - {78, 193, 19, 230, 14}, - {154, 86, 83, 153, 3}, - {118, 124, 136, 55, 2} - }, - { {54, 106, 12, 83, 5}, - {133, 13, 236, 13, 9}, - {172, 163, 5, 102, 12}, - {155, 3, 123, 10, 1} - }, - { {80, 158, 81, 148, 3}, - {124, 24, 152, 176, 10}, - {194, 152, 167, 144, 10}, - {80, 209, 145, 131, 14} - }, - { {186, 109, 34, 125, 1}, - {15, 110, 162, 47, 12}, - {139, 228, 75, 101, 13}, - {63, 68, 87, 111, 0} - }, - { {210, 172, 241, 99, 11}, - {53, 152, 19, 191, 13}, - {220, 104, 243, 84, 11}, - {191, 220, 129, 154, 12} - }, - { {217, 137, 254, 246, 8}, - {42, 203, 151, 218, 15}, - {22, 247, 249, 25, 11}, - {245, 190, 157, 53, 4} - }, - { {100, 23, 7, 187, 2}, - {208, 115, 170, 164, 3}, - {77, 222, 14, 130, 6}, - {194, 85, 92, 224, 11} - }, - { {249, 189, 49, 42, 11}, - {87, 58, 51, 242, 13}, - {213, 72, 203, 217, 15}, - {180, 252, 197, 206, 10} - }, - { {119, 115, 156, 32, 7}, - {197, 159, 110, 209, 0}, - {224, 67, 156, 238, 14}, - {8, 183, 111, 154, 3} - }, - { {104, 191, 141, 27, 15}, - {87, 179, 253, 164, 9}, - {253, 139, 31, 209, 6}, - {146, 91, 252, 222, 10} - }, - { {222, 221, 132, 166, 14}, - {202, 159, 83, 163, 11}, - {118, 82, 27, 183, 11}, - {220, 92, 175, 149, 3} - }, - { {66, 234, 236, 73, 11}, - {37, 181, 29, 141, 12}, - {217, 35, 117, 116, 2}, - {59, 27, 138, 218, 4} - }, - { {48, 43, 104, 213, 3}, - {45, 26, 172, 12, 14}, - {202, 177, 109, 64, 12}, - {115, 3, 85, 139, 4} - }, - { {78, 187, 147, 12, 14}, - {219, 242, 89, 145, 8}, - {115, 12, 157, 215, 2}, - {24, 153, 164, 253, 11} - }, - { {67, 156, 93, 155, 5}, - {116, 33, 212, 245, 11}, - {173, 155, 163, 156, 2}, - {218, 242, 184, 66, 14} - }, - { {225, 252, 146, 40, 13}, - {69, 228, 115, 242, 8}, - {177, 68, 147, 248, 7}, - {20, 252, 226, 122, 2} - }, - { {248, 166, 168, 212, 10}, - {11, 152, 189, 170, 6}, - {82, 177, 86, 81, 15}, - {101, 91, 209, 157, 0} - }, - { {181, 57, 2, 161, 8}, - {193, 74, 35, 70, 10}, - {24, 84, 9, 202, 13}, - {86, 44, 69, 40, 3} - }, - { {177, 99, 71, 94, 14}, - {57, 127, 233, 74, 1}, - {119, 174, 44, 104, 13}, - {133, 41, 127, 233, 12} - }, - { {173, 47, 90, 242, 9}, - {167, 66, 175, 122, 11}, - {148, 245, 175, 75, 5}, - {213, 239, 84, 46, 5} - }, - { {170, 181, 220, 133, 0}, - {107, 131, 52, 55, 2}, - {10, 19, 186, 213, 5}, - {78, 194, 204, 29, 6} - }, - { {179, 236, 37, 120, 6}, - {17, 61, 242, 107, 12}, - {97, 234, 67, 124, 13}, - {61, 100, 251, 200, 8} - }, - { {71, 153, 196, 64, 5}, - {228, 131, 80, 201, 8}, - {160, 34, 57, 158, 2}, - {25, 48, 172, 18, 7} - }, - { {139, 198, 141, 192, 4}, - {18, 133, 92, 107, 2}, - {32, 59, 22, 61, 1}, - {77, 99, 170, 20, 8} - }, - { {112, 47, 21, 221, 14}, - {25, 59, 233, 188, 10}, - {123, 186, 143, 64, 14}, - {83, 217, 125, 201, 8} - }, - { {180, 34, 147, 218, 9}, - {149, 232, 169, 26, 3}, - {149, 188, 148, 66, 13}, - {197, 137, 81, 122, 9} - }, - { {26, 202, 208, 56, 2}, - {34, 188, 154, 17, 8}, - {65, 192, 181, 53, 8}, - {24, 133, 147, 212, 4} - }, - { {129, 51, 99, 151, 1}, - {125, 66, 136, 70, 7}, - {142, 156, 108, 200, 1}, - {230, 33, 20, 43, 14} - }, - { {14, 105, 42, 215, 0}, - {139, 70, 132, 13, 15}, - {14, 181, 73, 103, 0}, - {251, 2, 22, 45, 1} - }, - { {138, 208, 92, 91, 9}, - {102, 37, 149, 31, 1}, - {157, 163, 160, 181, 1}, - {143, 138, 154, 70, 6} - }, - { {133, 230, 84, 193, 11}, - {165, 21, 25, 126, 2}, - {216, 50, 166, 122, 1}, - {71, 233, 138, 138, 5} - }, - { {61, 10, 194, 179, 11}, - {166, 216, 171, 68, 11}, - {220, 212, 53, 11, 12}, - {210, 45, 81, 182, 5} - }, - { {75, 191, 160, 85, 2}, - {75, 146, 152, 237, 12}, - {74, 160, 95, 221, 2}, - {59, 113, 148, 157, 2} - }, - { {114, 45, 222, 48, 6}, - {33, 219, 230, 177, 8}, - {96, 199, 187, 68, 14}, - {24, 214, 125, 184, 4} - }, - { {54, 157, 26, 205, 2}, - {200, 122, 52, 61, 10}, - {75, 53, 139, 150, 12}, - {91, 194, 197, 225, 3} - }, - { {162, 217, 148, 230, 0}, - {72, 135, 50, 27, 11}, - {6, 114, 153, 180, 5}, - {221, 132, 206, 17, 2} - }, - { {95, 173, 145, 57, 13}, - {151, 170, 211, 245, 8}, - {185, 200, 155, 95, 10}, - {26, 252, 181, 94, 9} - }, - { {87, 83, 90, 233, 6}, - {224, 126, 78, 221, 2}, - {105, 117, 172, 174, 10}, - {75, 183, 39, 224, 7} - }, - { {95, 94, 241, 212, 6}, - {250, 156, 200, 249, 14}, - {98, 184, 247, 175, 10}, - {121, 241, 51, 149, 15} - }, - { {235, 195, 230, 172, 12}, - {42, 231, 123, 195, 6}, - {51, 86, 124, 61, 7}, - {108, 61, 238, 117, 4} - }, - { {10, 153, 200, 53, 13}, - {110, 130, 215, 5, 8}, - {186, 193, 57, 149, 0}, - {26, 14, 180, 23, 6} - }, - { {84, 99, 228, 154, 5}, - {165, 175, 200, 128, 7}, - {165, 146, 124, 98, 10}, - {224, 17, 63, 90, 5} - }, - { {37, 103, 104, 147, 10}, - {161, 22, 173, 100, 7}, - {92, 145, 110, 106, 4}, - {226, 107, 86, 136, 5} - }, - { {171, 237, 55, 6, 4}, - {27, 71, 112, 115, 13}, - {38, 14, 203, 125, 5}, - {188, 224, 238, 45, 8} - }, - { {89, 189, 222, 217, 4}, - {99, 235, 212, 252, 10}, - {41, 183, 187, 217, 10}, - {83, 242, 189, 124, 6} - }, - { {100, 250, 4, 192, 9}, - {197, 5, 57, 136, 10}, - {144, 50, 5, 242, 6}, - {81, 25, 202, 10, 3} - }, - { {37, 14, 68, 231, 5}, - {172, 1, 106, 108, 11}, - {174, 114, 39, 10, 4}, - {211, 101, 104, 3, 5} - }, - { {229, 138, 55, 75, 12}, - {144, 97, 121, 222, 13}, - {61, 46, 197, 26, 7}, - {183, 185, 232, 96, 9} - }, - { {36, 202, 165, 116, 1}, - {156, 133, 186, 8, 12}, - {130, 234, 85, 50, 4}, - {49, 5, 218, 19, 9} - }, - { {228, 44, 246, 88, 8}, - {161, 225, 161, 186, 12}, - {17, 166, 243, 66, 7}, - {53, 216, 88, 120, 5} - }, - { {110, 162, 56, 83, 8}, - {131, 0, 189, 157, 5}, - {28, 161, 196, 87, 6}, - {171, 155, 208, 12, 1} - }, - { {247, 88, 19, 2, 5}, - {212, 76, 96, 211, 9}, - {164, 12, 129, 174, 15}, - {156, 176, 99, 34, 11} - }, - { {12, 235, 51, 187, 13}, - {151, 102, 219, 20, 15}, - {189, 220, 205, 115, 0}, - {242, 141, 182, 110, 9} - }, - { {120, 106, 232, 103, 0}, - {43, 140, 46, 140, 13}, - {14, 97, 117, 97, 14}, - {179, 23, 67, 29, 4} - }, - { {240, 222, 140, 150, 9}, - {76, 141, 189, 162, 11}, - {150, 147, 23, 176, 15}, - {212, 91, 219, 19, 2} - }, - { {38, 200, 30, 254, 6}, - {136, 117, 246, 25, 11}, - {103, 247, 129, 54, 4}, - {217, 134, 250, 225, 1} - }, - { {105, 244, 137, 8, 6}, - {83, 180, 116, 224, 0}, - {97, 9, 18, 249, 6}, - {0, 114, 226, 220, 10} - }, - { {63, 191, 146, 164, 13}, - {207, 202, 123, 113, 10}, - {178, 84, 159, 223, 12}, - {88, 237, 229, 63, 3} - }, - { {214, 85, 90, 118, 0}, - {232, 78, 134, 187, 1}, - {6, 229, 170, 166, 11}, - {141, 214, 23, 33, 7} - }, - { {156, 202, 226, 54, 13}, - {174, 204, 219, 2, 13}, - {182, 196, 117, 51, 9}, - {180, 13, 179, 55, 5} - }, - { {178, 86, 193, 106, 3}, - {116, 188, 42, 43, 1}, - {197, 104, 54, 164, 13}, - {141, 69, 67, 210, 14} - }, - { {215, 138, 199, 34, 1}, - {180, 201, 26, 195, 9}, - {132, 78, 53, 30, 11}, - {156, 53, 137, 50, 13} - }, - { {45, 193, 254, 38, 2}, - {170, 215, 54, 80, 5}, - {70, 71, 248, 59, 4}, - {160, 166, 206, 181, 5} - }, - { {175, 32, 81, 9, 0}, - {179, 32, 32, 87, 0}, - {9, 8, 160, 79, 5}, - {14, 160, 64, 76, 13} - }, - { {147, 44, 8, 175, 14}, - {9, 56, 71, 103, 11}, - {127, 81, 3, 76, 9}, - {222, 110, 33, 201, 0} - }, - { {83, 254, 202, 119, 5}, - {109, 204, 222, 237, 9}, - {174, 229, 55, 252, 10}, - {155, 119, 179, 59, 6} - }, - { {93, 41, 36, 151, 10}, - {139, 27, 129, 196, 15}, - {94, 146, 73, 75, 10}, - {242, 56, 29, 141, 1} - }, - { {47, 16, 26, 34, 11}, - {198, 80, 39, 81, 1}, - {212, 69, 128, 143, 4}, - {136, 174, 64, 166, 3} - }, - { {198, 173, 22, 177, 4}, - {129, 67, 210, 183, 10}, - {40, 214, 139, 86, 3}, - {94, 212, 188, 40, 1} - }, - { {210, 236, 164, 178, 0}, - {1, 141, 146, 163, 15}, - {4, 210, 83, 116, 11}, - {252, 84, 155, 24, 0} - }, - { {166, 250, 96, 61, 4}, - {233, 36, 250, 7, 12}, - {43, 192, 101, 246, 5}, - {62, 5, 242, 73, 7} - }, - { {48, 87, 195, 182, 9}, - {124, 206, 171, 32, 3}, - {150, 220, 62, 160, 12}, - {192, 77, 87, 51, 14} - }, - { {232, 23, 181, 77, 2}, - {90, 179, 40, 190, 4}, - {75, 42, 222, 129, 7}, - {39, 209, 76, 213, 10} - }, - { {64, 171, 252, 62, 0}, - {41, 163, 158, 144, 13}, - {7, 195, 253, 80, 2}, - {176, 151, 156, 89, 4} - }, - { {245, 58, 209, 110, 7}, - {253, 184, 106, 218, 9}, - {231, 104, 181, 202, 15}, - {149, 181, 97, 219, 15} - }, - { {54, 243, 160, 110, 8}, - {201, 174, 59, 9, 5}, - {23, 96, 92, 246, 12}, - {169, 13, 199, 89, 3} - }, - { {39, 120, 46, 65, 8}, - {193, 69, 37, 77, 12}, - {24, 39, 65, 238, 4}, - {59, 42, 74, 40, 3} - }, - { {62, 144, 98, 20, 6}, - {234, 88, 240, 1, 4}, - {98, 132, 96, 151, 12}, - {40, 0, 241, 165, 7} - }, - { {1, 253, 122, 212, 14}, - {105, 86, 213, 120, 14}, - {114, 181, 235, 248, 0}, - {113, 234, 182, 169, 6} - }, - { {200, 118, 91, 198, 4}, - {123, 68, 76, 186, 3}, - {38, 61, 166, 225, 3}, - {197, 211, 34, 45, 14} - }, - { {173, 61, 130, 21, 15}, - {207, 210, 225, 102, 8}, - {250, 132, 27, 203, 5}, - {22, 104, 116, 191, 3} - }, - { {150, 49, 122, 39, 14}, - {233, 90, 71, 23, 5}, - {126, 69, 232, 198, 9}, - {174, 142, 37, 169, 7} - }, - { {5, 248, 19, 202, 6}, - {209, 116, 80, 88, 11}, - {101, 60, 129, 250, 0}, - {209, 160, 162, 232, 11} - }, - { {14, 122, 220, 34, 14}, - {227, 149, 79, 17, 9}, - {116, 67, 181, 231, 0}, - {152, 143, 42, 156, 7} - }, - { {191, 82, 196, 165, 0}, - {234, 141, 42, 71, 2}, - {10, 82, 52, 175, 13}, - {78, 37, 75, 21, 7} - }, - { {114, 79, 106, 226, 14}, - {32, 94, 111, 169, 15}, - {116, 117, 111, 36, 14}, - {249, 95, 103, 160, 4} - }, - { {84, 15, 215, 234, 8}, - {176, 235, 11, 184, 11}, - {21, 126, 191, 2, 10}, - {209, 221, 13, 112, 13} - }, - { {156, 150, 47, 116, 1}, - {222, 73, 158, 42, 4}, - {130, 239, 70, 147, 9}, - {37, 71, 153, 39, 11} - }, - { {38, 64, 66, 176, 1}, - {164, 68, 162, 1, 2}, - {128, 212, 32, 38, 4}, - {72, 4, 82, 34, 5} - }, - { {25, 124, 183, 117, 4}, - {91, 205, 194, 124, 12}, - {42, 238, 211, 233, 8}, - {51, 228, 59, 61, 10} - }, - { {31, 43, 184, 80, 13}, - {135, 138, 205, 89, 12}, - {176, 161, 221, 79, 8}, - {57, 171, 53, 30, 1} - }, - { {200, 125, 108, 42, 13}, - {103, 39, 71, 162, 13}, - {181, 67, 107, 225, 3}, - {180, 94, 46, 78, 6} - }, - { {220, 141, 45, 237, 14}, - {154, 59, 87, 174, 14}, - {123, 123, 75, 19, 11}, - {119, 94, 173, 197, 9} - }, - { {203, 107, 1, 115, 8}, - {19, 6, 139, 207, 9}, - {28, 232, 13, 109, 3}, - {159, 61, 22, 12, 8} - }, - { {190, 66, 16, 54, 8}, - {138, 12, 171, 19, 1}, - {22, 192, 132, 39, 13}, - {140, 141, 83, 5, 1} - }, - { {187, 70, 34, 167, 7}, - {14, 92, 106, 103, 7}, - {238, 84, 70, 45, 13}, - {238, 101, 99, 167, 0} - }, - { {115, 50, 38, 239, 8}, - {73, 105, 43, 205, 7}, - {31, 118, 68, 204, 14}, - {235, 61, 73, 105, 2} - }, - { {73, 51, 173, 227, 9}, - {87, 131, 15, 204, 7}, - {156, 123, 92, 201, 2}, - {227, 63, 12, 30, 10} - }, - { {31, 28, 137, 108, 7}, - {222, 184, 70, 105, 8}, - {227, 105, 19, 143, 8}, - {25, 102, 33, 215, 11} - }, - { {137, 118, 101, 171, 10}, - {115, 53, 11, 102, 7}, - {93, 90, 102, 233, 1}, - {230, 109, 10, 204, 14} - }, - { {146, 244, 107, 161, 2}, - {113, 92, 22, 39, 6}, - {72, 93, 98, 244, 9}, - {110, 70, 131, 168, 14} - }, - { {41, 121, 129, 118, 7}, - {95, 150, 226, 72, 9}, - {230, 232, 25, 233, 4}, - {145, 36, 118, 159, 10} - }, - { {173, 112, 44, 248, 13}, - {199, 37, 231, 74, 6}, - {177, 243, 64, 235, 5}, - {101, 46, 122, 78, 3} - }, - { {71, 49, 152, 185, 0}, - {193, 162, 134, 213, 2}, - {9, 209, 152, 206, 2}, - {74, 182, 20, 88, 3} - }, - { {236, 46, 142, 6, 11}, - {143, 209, 45, 162, 9}, - {214, 7, 23, 67, 7}, - {148, 91, 72, 191, 1} - }, - { {54, 161, 214, 152, 0}, - {161, 235, 176, 17, 2}, - {1, 150, 184, 86, 12}, - {72, 128, 221, 120, 5} - }, - { {165, 206, 134, 80, 15}, - {132, 213, 249, 106, 8}, - {240, 166, 23, 58, 5}, - {21, 105, 250, 178, 1} - }, - { {99, 120, 112, 52, 8}, - {105, 4, 163, 209, 12}, - {18, 192, 225, 236, 6}, - {56, 188, 82, 9, 6} - }, - { {243, 171, 65, 212, 6}, - {57, 26, 248, 203, 10}, - {98, 184, 45, 92, 15}, - {93, 49, 245, 137, 12} - }, - { {230, 3, 42, 139, 5}, - {132, 98, 108, 135, 7}, - {173, 21, 76, 6, 7}, - {238, 19, 100, 98, 1} - }, - { {76, 17, 238, 199, 3}, - {238, 211, 4, 140, 7}, - {206, 55, 120, 131, 2}, - {227, 18, 12, 183, 7} - }, - { {38, 29, 229, 13, 6}, - {248, 179, 96, 37, 12}, - {107, 10, 123, 134, 4}, - {58, 64, 108, 209, 15} - }, - { {41, 102, 22, 227, 2}, - {3, 85, 42, 124, 3}, - {76, 118, 134, 105, 4}, - {195, 229, 74, 172, 0} - }, - { {55, 207, 241, 160, 10}, - {176, 158, 59, 113, 14}, - {80, 88, 255, 62, 12}, - {120, 237, 199, 144, 13} - }, - { {196, 87, 132, 122, 11}, - {196, 183, 139, 170, 1}, - {213, 226, 30, 162, 3}, - {133, 93, 30, 210, 3} - }, - { {119, 110, 82, 255, 9}, - {173, 108, 171, 253, 11}, - {159, 244, 167, 110, 14}, - {219, 253, 83, 107, 5} - }, - { {152, 8, 25, 187, 9}, - {22, 40, 135, 22, 11}, - {157, 217, 129, 1, 9}, - {214, 142, 17, 70, 8} - }, - { {80, 203, 43, 93, 8}, - {24, 110, 157, 140, 12}, - {27, 173, 77, 48, 10}, - {51, 27, 151, 97, 8} - }, - { {139, 105, 24, 6, 3}, - {15, 22, 4, 83, 9}, - {198, 1, 137, 109, 1}, - {156, 162, 6, 143, 0} - }, - { {18, 217, 194, 206, 9}, - {108, 238, 17, 9, 11}, - {151, 52, 57, 180, 8}, - {217, 8, 135, 115, 6} - }, - { {21, 140, 46, 115, 8}, - {128, 73, 151, 108, 13}, - {28, 231, 67, 26, 8}, - {179, 110, 153, 32, 1} - }, - { {107, 132, 1, 94, 10}, - {26, 48, 177, 233, 1}, - {87, 168, 2, 29, 6}, - {137, 120, 208, 197, 8} - }, - { {103, 105, 93, 185, 15}, - {181, 55, 231, 213, 10}, - {249, 219, 169, 110, 6}, - {90, 190, 126, 202, 13} - }, - { {62, 114, 116, 92, 1}, - {239, 45, 168, 25, 4}, - {131, 162, 228, 231, 12}, - {41, 129, 91, 79, 7} - }, - { {1, 202, 26, 87, 1}, - {12, 68, 156, 92, 9}, - {142, 165, 133, 56, 0}, - {147, 163, 146, 35, 0} - }, - { {34, 231, 3, 111, 5}, - {29, 102, 122, 45, 1}, - {175, 108, 14, 116, 4}, - {139, 69, 230, 107, 8} - }, - { {213, 220, 237, 174, 1}, - {252, 173, 22, 226, 15}, - {135, 91, 115, 186, 11}, - {244, 118, 139, 83, 15} - }, - { {128, 149, 50, 197, 11}, - {76, 82, 17, 62, 6}, - {218, 52, 202, 144, 1}, - {103, 200, 132, 163, 2} - }, - { {247, 228, 233, 213, 4}, - {185, 140, 244, 239, 6}, - {42, 185, 114, 126, 15}, - {111, 114, 243, 25, 13} - }, - { {89, 216, 79, 156, 11}, - {126, 125, 149, 192, 10}, - {211, 159, 33, 185, 10}, - {80, 58, 155, 231, 14} - }, - { {244, 46, 208, 133, 1}, - {173, 136, 40, 182, 10}, - {138, 16, 183, 66, 15}, - {86, 209, 65, 27, 5} - }, - { {93, 180, 169, 31, 10}, - {219, 184, 149, 228, 5}, - {95, 137, 82, 219, 10}, - {162, 122, 145, 221, 11} - }, - { {13, 88, 229, 177, 15}, - {246, 149, 195, 68, 14}, - {248, 218, 113, 171, 0}, - {114, 44, 58, 150, 15} - }, - { {105, 251, 159, 164, 3}, - {95, 215, 62, 208, 10}, - {194, 95, 157, 249, 6}, - {80, 183, 206, 191, 10} - }, - { {41, 186, 81, 246, 0}, - {123, 0, 186, 88, 11}, - {6, 248, 165, 217, 4}, - {209, 165, 208, 13, 14} - }, - { {88, 124, 103, 66, 7}, - {119, 93, 64, 168, 13}, - {228, 46, 99, 225, 10}, - {177, 80, 43, 174, 14} - }, - { {216, 185, 2, 30, 13}, - {79, 106, 209, 130, 9}, - {183, 132, 9, 209, 11}, - {148, 24, 181, 111, 2} - }, - { {187, 89, 68, 73, 14}, - {98, 63, 97, 79, 8}, - {121, 34, 41, 173, 13}, - {31, 40, 111, 196, 6} - }, - { {170, 35, 31, 53, 10}, - {27, 83, 175, 23, 0}, - {90, 207, 140, 69, 5}, - {14, 143, 92, 173, 8} - }, - { {13, 149, 148, 63, 4}, - {202, 163, 210, 116, 1}, - {47, 194, 154, 155, 0}, - {130, 228, 188, 85, 3} - }, - { {222, 196, 97, 37, 7}, - {190, 28, 82, 167, 4}, - {234, 72, 98, 55, 11}, - {46, 84, 163, 135, 13} - }, - { {5, 161, 105, 48, 13}, - {181, 2, 215, 64, 4}, - {176, 201, 104, 90, 0}, - {32, 46, 180, 10, 13} - }, - { {226, 81, 46, 181, 8}, - {72, 71, 167, 135, 6}, - {26, 215, 72, 164, 7}, - {110, 30, 94, 33, 2} - }, - { {171, 72, 226, 220, 0}, - {42, 228, 160, 75, 14}, - {3, 180, 113, 45, 5}, - {125, 32, 82, 117, 4} - }, - { {12, 182, 132, 148, 15}, - {207, 145, 217, 32, 2}, - {242, 146, 22, 211, 0}, - {64, 73, 184, 159, 3} - }, - { {146, 122, 107, 91, 1}, - {117, 108, 140, 15, 13}, - {141, 173, 101, 228, 9}, - {191, 3, 19, 106, 14} - }, - { {187, 144, 243, 69, 0}, - {122, 200, 48, 95, 4}, - {10, 44, 240, 157, 13}, - {47, 160, 193, 53, 14} - }, - { {99, 46, 143, 173, 0}, - {25, 225, 46, 229, 10}, - {11, 95, 23, 76, 6}, - {90, 119, 72, 121, 8} - }, - { {194, 238, 175, 42, 7}, - {21, 245, 94, 163, 13}, - {229, 79, 87, 116, 3}, - {188, 87, 170, 250, 8} - }, - { {30, 178, 175, 57, 13}, - {215, 233, 223, 5, 4}, - {185, 207, 84, 215, 8}, - {42, 15, 185, 126, 11} - }, - { {81, 21, 72, 197, 2}, - {104, 26, 4, 236, 2}, - {74, 49, 42, 136, 10}, - {67, 114, 5, 129, 6} - }, - { {70, 147, 213, 222, 4}, - {248, 163, 216, 153, 3}, - {39, 186, 188, 150, 2}, - {201, 145, 188, 81, 15} - }, - { {136, 142, 145, 97, 13}, - {22, 128, 91, 62, 8}, - {184, 104, 151, 17, 1}, - {23, 205, 160, 22, 8} - }, - { {104, 131, 111, 244, 15}, - {62, 83, 255, 136, 6}, - {242, 255, 108, 17, 6}, - {97, 31, 252, 167, 12} - }, - { {81, 189, 46, 68, 1}, - {77, 75, 20, 232, 12}, - {130, 39, 75, 216, 10}, - {49, 114, 141, 43, 2} - }, - { {122, 10, 196, 14, 9}, - {46, 169, 41, 129, 9}, - {151, 2, 53, 5, 14}, - {152, 25, 73, 87, 4} - }, - { {139, 183, 98, 180, 10}, - {107, 82, 155, 99, 6}, - {82, 212, 110, 221, 1}, - {108, 109, 148, 173, 6} - }, - { {28, 175, 131, 161, 10}, - {147, 218, 27, 36, 10}, - {88, 92, 31, 83, 8}, - {82, 77, 133, 188, 9} - }, - { {194, 112, 11, 187, 13}, - {85, 100, 199, 135, 3}, - {189, 221, 0, 228, 3}, - {206, 30, 50, 106, 10} - }, - { {251, 46, 208, 154, 10}, - {35, 184, 169, 243, 11}, - {85, 144, 183, 77, 15}, - {220, 249, 81, 220, 4} - }, - { {248, 82, 2, 148, 14}, - {74, 92, 233, 130, 2}, - {114, 148, 4, 161, 15}, - {68, 25, 115, 165, 2} - }, - { {122, 161, 4, 202, 6}, - {3, 59, 112, 137, 3}, - {101, 50, 8, 85, 14}, - {201, 16, 237, 204, 0} - }, - { {106, 150, 210, 188, 11}, - {110, 240, 187, 177, 2}, - {211, 212, 182, 149, 6}, - {72, 221, 208, 247, 6} - }, - { {40, 242, 236, 117, 14}, - {107, 149, 255, 12, 4}, - {122, 227, 116, 241, 4}, - {35, 15, 250, 157, 6} - }, - { {96, 112, 101, 235, 4}, - {113, 37, 98, 140, 7}, - {45, 122, 96, 224, 6}, - {227, 20, 106, 72, 14} - }, - { {122, 217, 179, 168, 12}, - {82, 238, 115, 145, 14}, - {49, 92, 217, 181, 14}, - {120, 156, 231, 116, 10} - }, - { {53, 114, 214, 203, 15}, - {229, 253, 105, 92, 3}, - {253, 54, 180, 234, 12}, - {195, 169, 107, 250, 7} - }, - { {212, 38, 239, 184, 15}, - {181, 249, 207, 162, 6}, - {241, 223, 118, 66, 11}, - {100, 95, 57, 250, 13} - }, - { {100, 238, 77, 186, 10}, - {177, 53, 191, 160, 11}, - {85, 219, 39, 114, 6}, - {208, 95, 218, 200, 13} - }, - { {152, 61, 122, 143, 1}, - {111, 106, 4, 54, 15}, - {143, 21, 235, 193, 9}, - {246, 194, 5, 111, 6} - }, - { {140, 163, 31, 73, 9}, - {151, 99, 29, 30, 0}, - {153, 47, 140, 83, 1}, - {7, 139, 140, 110, 9} - }, - { {2, 84, 87, 180, 6}, - {120, 85, 194, 49, 2}, - {98, 222, 162, 164, 0}, - {72, 196, 58, 161, 14} - }, - { {213, 58, 228, 20, 9}, - {237, 137, 137, 194, 12}, - {146, 130, 117, 202, 11}, - {52, 57, 25, 27, 7} - }, - { {157, 60, 100, 57, 6}, - {227, 57, 194, 102, 12}, - {105, 194, 99, 203, 9}, - {54, 100, 57, 204, 7} - }, - { {121, 83, 50, 238, 5}, - {78, 110, 106, 216, 7}, - {167, 116, 204, 169, 14}, - {225, 181, 103, 103, 2} - }, - { {112, 136, 77, 102, 4}, - {56, 9, 118, 136, 9}, - {38, 107, 33, 16, 14}, - {145, 22, 233, 1, 12} - }, - { {29, 211, 82, 141, 8}, - {234, 110, 25, 84, 2}, - {27, 20, 172, 187, 8}, - {66, 169, 135, 101, 7} - }, - { {216, 229, 29, 36, 6}, - {27, 31, 86, 178, 0}, - {98, 75, 138, 113, 11}, - {4, 214, 175, 141, 8} - }, - { {214, 2, 156, 163, 8}, - {128, 137, 15, 151, 3}, - {28, 83, 148, 6, 11}, - {206, 159, 9, 16, 1} - }, - { {217, 74, 182, 16, 12}, - {2, 205, 201, 210, 12}, - {48, 134, 213, 41, 11}, - {52, 185, 59, 52, 0} - }, - { {118, 107, 184, 136, 0}, - {129, 174, 44, 145, 14}, - {1, 17, 221, 102, 14}, - {120, 147, 71, 88, 1} - }, - { {253, 12, 107, 49, 9}, - {182, 72, 167, 230, 12}, - {152, 205, 99, 11, 15}, - {54, 126, 81, 38, 13} - }, - { {59, 255, 139, 157, 1}, - {95, 238, 188, 101, 10}, - {139, 157, 31, 253, 12}, - {90, 99, 215, 127, 10} - }, - { {231, 134, 244, 212, 14}, - {168, 145, 249, 251, 6}, - {114, 178, 246, 30, 7}, - {109, 249, 248, 145, 5} - }, - { {212, 230, 185, 183, 9}, - {157, 140, 159, 182, 7}, - {158, 217, 214, 114, 11}, - {230, 223, 147, 27, 9} - }, - { {207, 168, 187, 54, 9}, - {159, 192, 151, 211, 13}, - {150, 205, 209, 95, 3}, - {188, 190, 144, 63, 9} - }, - { {32, 164, 54, 108, 6}, - {9, 113, 114, 56, 4}, - {99, 102, 194, 80, 4}, - {33, 196, 232, 233, 0} - }, - { {92, 239, 185, 83, 6}, - {147, 158, 220, 188, 13}, - {108, 169, 223, 115, 10}, - {179, 211, 183, 156, 9} - }, - { {15, 6, 182, 96, 5}, - {134, 193, 74, 121, 4}, - {160, 102, 214, 15, 0}, - {41, 229, 40, 54, 1} - }, - { {187, 81, 210, 94, 7}, - {110, 254, 224, 91, 1}, - {231, 164, 184, 173, 13}, - {141, 160, 119, 247, 6} - }, - { {247, 226, 98, 100, 1}, - {173, 76, 58, 203, 4}, - {130, 100, 100, 126, 15}, - {45, 53, 195, 43, 5} - }, - { {129, 253, 169, 133, 5}, - {93, 134, 84, 102, 14}, - {170, 25, 91, 248, 1}, - {118, 98, 166, 27, 10} - }, - { {34, 65, 219, 197, 9}, - {60, 198, 37, 29, 2}, - {154, 61, 184, 36, 4}, - {75, 138, 70, 51, 12} - }, - { {86, 251, 75, 40, 0}, - {241, 110, 30, 129, 8}, - {1, 77, 45, 246, 10}, - {24, 23, 135, 104, 15} - }, - { {237, 166, 76, 109, 0}, - {171, 33, 62, 238, 0}, - {11, 99, 38, 91, 7}, - {7, 119, 200, 77, 5} - }, - { {206, 123, 8, 15, 4}, - {203, 38, 76, 135, 9}, - {47, 1, 13, 231, 3}, - {158, 19, 38, 77, 3} - }, - { {97, 146, 238, 126, 9}, - {108, 225, 191, 200, 5}, - {151, 231, 116, 152, 6}, - {161, 63, 216, 115, 6} - }, - { {148, 63, 245, 18, 4}, - {241, 139, 200, 50, 13}, - {36, 138, 255, 194, 9}, - {180, 193, 61, 24, 15} - }, - { {136, 179, 190, 173, 15}, - {79, 243, 95, 22, 6}, - {251, 87, 220, 209, 1}, - {102, 143, 172, 255, 2} - }, - { {155, 39, 229, 141, 0}, - {59, 171, 8, 103, 6}, - {11, 26, 126, 77, 9}, - {110, 97, 13, 93, 12} - }, - { {190, 11, 69, 253, 2}, - {186, 59, 170, 15, 10}, - {75, 250, 45, 7, 13}, - {95, 5, 93, 197, 13} - }, - { {105, 251, 58, 114, 10}, - {67, 86, 191, 216, 13}, - {84, 229, 205, 249, 6}, - {177, 191, 214, 172, 2} - }, - { {97, 56, 58, 131, 2}, - {65, 80, 36, 212, 15}, - {76, 21, 193, 200, 6}, - {242, 178, 64, 168, 2} - }, - { {102, 136, 99, 155, 3}, - {180, 112, 176, 133, 15}, - {205, 156, 97, 22, 6}, - {250, 16, 208, 226, 13} - }, - { {84, 208, 28, 153, 2}, - {192, 61, 148, 148, 2}, - {73, 147, 128, 178, 10}, - {66, 146, 155, 192, 3} - }, - { {144, 177, 12, 2, 10}, - {65, 27, 21, 2, 1}, - {84, 3, 8, 208, 9}, - {132, 10, 141, 136, 2} - }, - { {246, 103, 252, 109, 1}, - {173, 175, 46, 191, 4}, - {139, 99, 254, 102, 15}, - {47, 215, 79, 91, 5} - }, - { {122, 205, 117, 129, 3}, - {54, 31, 48, 181, 14}, - {200, 26, 235, 53, 14}, - {122, 208, 207, 134, 12} - }, - { {58, 189, 7, 246, 1}, - {95, 75, 178, 41, 11}, - {134, 254, 11, 213, 12}, - {217, 68, 221, 47, 10} - }, - { {84, 48, 18, 71, 3}, - {205, 88, 0, 156, 1}, - {206, 36, 128, 194, 10}, - {131, 144, 1, 171, 3} - }, - { {6, 119, 148, 213, 8}, - {201, 135, 137, 61, 2}, - {26, 178, 158, 230, 0}, - {75, 201, 30, 25, 3} - }, - { {168, 85, 177, 32, 1}, - {86, 134, 34, 50, 4}, - {128, 72, 218, 161, 5}, - {36, 196, 70, 22, 10} - }, - { {156, 180, 215, 253, 11}, - {255, 249, 147, 62, 2}, - {219, 254, 178, 211, 9}, - {71, 204, 153, 255, 15} - }, - { {49, 161, 147, 230, 10}, - {25, 218, 51, 88, 3}, - {86, 124, 152, 88, 12}, - {193, 172, 197, 185, 8} - }, - { {61, 163, 183, 109, 4}, - {155, 235, 122, 92, 4}, - {43, 110, 220, 91, 12}, - {35, 165, 237, 125, 9} - }, - { {65, 83, 241, 224, 4}, - {112, 134, 74, 216, 6}, - {32, 120, 252, 168, 2}, - {97, 181, 38, 16, 14} - }, - { {85, 68, 51, 91, 5}, - {148, 108, 192, 252, 5}, - {173, 172, 194, 42, 10}, - {163, 240, 51, 98, 9} - }, - { {146, 246, 18, 73, 13}, - {69, 108, 89, 63, 0}, - {185, 36, 134, 244, 9}, - {15, 201, 163, 106, 2} - }, - { {38, 154, 53, 248, 10}, - {208, 49, 187, 25, 14}, - {81, 250, 197, 150, 4}, - {121, 141, 216, 192, 11} - }, - { {4, 38, 119, 137, 6}, - {177, 113, 72, 52, 6}, - {105, 30, 230, 66, 0}, - {98, 193, 40, 232, 13} - }, - { {148, 135, 205, 198, 15}, - {188, 155, 93, 42, 3}, - {246, 59, 62, 18, 9}, - {197, 75, 173, 147, 13} - }, - { {78, 167, 231, 217, 12}, - {179, 227, 217, 173, 6}, - {57, 190, 126, 87, 2}, - {107, 89, 188, 124, 13} - }, - { {46, 54, 115, 69, 11}, - {255, 80, 41, 61, 4}, - {218, 44, 230, 199, 4}, - {43, 201, 64, 175, 15} - }, - { {58, 94, 143, 48, 4}, - {82, 205, 238, 33, 8}, - {32, 207, 23, 165, 12}, - {24, 71, 123, 52, 10} - }, - { {118, 217, 250, 167, 7}, - {236, 222, 118, 149, 15}, - {238, 85, 249, 182, 14}, - {250, 150, 231, 179, 7} - }, - { {100, 228, 234, 29, 15}, - {173, 244, 245, 164, 4}, - {251, 133, 114, 114, 6}, - {34, 90, 242, 251, 5} - }, - { {18, 167, 180, 52, 13}, - {13, 139, 219, 49, 4}, - {178, 194, 222, 84, 8}, - {40, 205, 189, 27, 0} - }, - { {73, 115, 217, 85, 3}, - {127, 150, 140, 220, 0}, - {202, 169, 188, 233, 2}, - {3, 179, 22, 159, 14} - }, - { {205, 180, 24, 151, 5}, - {207, 0, 212, 246, 3}, - {174, 145, 130, 219, 3}, - {198, 242, 176, 15, 3} - }, - { {139, 218, 118, 210, 14}, - {98, 85, 217, 91, 15}, - {116, 182, 229, 189, 1}, - {253, 169, 186, 164, 6} - }, - { {245, 74, 77, 236, 8}, - {184, 45, 47, 202, 10}, - {19, 123, 37, 42, 15}, - {85, 63, 75, 65, 13} - }, - { {129, 22, 22, 248, 10}, - {64, 113, 139, 122, 2}, - {81, 246, 134, 136, 1}, - {69, 237, 24, 224, 2} - }, - { {64, 54, 244, 230, 11}, - {109, 145, 11, 184, 7}, - {214, 114, 246, 192, 2}, - {225, 221, 8, 155, 6} - }, - { {39, 54, 40, 42, 6}, - {193, 48, 110, 97, 5}, - {101, 65, 70, 206, 4}, - {168, 103, 96, 200, 3} - }, - { {164, 19, 210, 41, 15}, - {228, 242, 107, 22, 0}, - {249, 68, 188, 130, 5}, - {6, 141, 100, 242, 7} - }, - { {144, 31, 228, 193, 7}, - {100, 155, 72, 46, 14}, - {232, 50, 127, 128, 9}, - {119, 65, 45, 146, 6} - }, - { {154, 191, 206, 86, 14}, - {107, 219, 221, 43, 9}, - {118, 167, 63, 213, 9}, - {157, 75, 189, 189, 6} - }, - { {45, 50, 91, 158, 15}, - {255, 112, 237, 80, 3}, - {247, 157, 164, 203, 4}, - {192, 171, 112, 239, 15} - }, - { {217, 144, 31, 106, 9}, - {86, 105, 23, 218, 1}, - {149, 111, 128, 153, 11}, - {133, 190, 137, 102, 10} - }, - { {58, 166, 79, 173, 14}, - {59, 121, 127, 37, 2}, - {123, 95, 38, 85, 12}, - {74, 79, 233, 237, 12} - }, - { {101, 40, 141, 96, 11}, - {149, 145, 39, 200, 8}, - {208, 107, 17, 74, 6}, - {17, 62, 72, 154, 9} - }, - { {10, 83, 233, 96, 11}, - {118, 150, 15, 9, 4}, - {208, 105, 124, 165, 0}, - {41, 15, 6, 150, 14} - }, - { {233, 224, 156, 62, 4}, - {11, 165, 246, 210, 1}, - {39, 195, 144, 121, 7}, - {132, 182, 250, 93, 0} - }, - { {77, 155, 120, 99, 13}, - {230, 2, 95, 220, 13}, - {188, 97, 237, 155, 2}, - {179, 191, 164, 6, 7} - }, - { {217, 139, 180, 131, 3}, - {6, 155, 24, 214, 15}, - {204, 18, 221, 25, 11}, - {246, 177, 141, 150, 0} - }, - { {52, 177, 129, 237, 7}, - {221, 186, 114, 12, 2}, - {235, 120, 24, 210, 12}, - {67, 4, 229, 219, 11} - }, - { {91, 55, 63, 73, 0}, - {83, 107, 12, 253, 4}, - {9, 47, 206, 205, 10}, - {43, 243, 13, 108, 10} - }, - { {133, 114, 183, 185, 1}, - {213, 229, 138, 86, 6}, - {137, 222, 212, 234, 1}, - {102, 165, 26, 122, 11} - }, - { {44, 93, 5, 106, 4}, - {210, 39, 98, 40, 9}, - {37, 106, 11, 163, 4}, - {145, 68, 110, 68, 11} - }, - { {228, 103, 18, 150, 13}, - {141, 70, 233, 178, 3}, - {182, 148, 142, 98, 7}, - {196, 217, 118, 43, 1} - }, - { {42, 8, 214, 247, 8}, - {42, 193, 163, 29, 11}, - {30, 246, 177, 5, 4}, - {219, 140, 88, 53, 4} - }, - { {69, 41, 73, 198, 1}, - {189, 2, 4, 200, 11}, - {134, 57, 41, 74, 2}, - {209, 50, 4, 11, 13} - }, - { {37, 1, 236, 91, 7}, - {164, 179, 228, 76, 5}, - {237, 163, 120, 10, 4}, - {163, 34, 124, 210, 5} - }, - { {184, 245, 71, 121, 12}, - {115, 111, 243, 46, 0}, - {57, 238, 42, 241, 13}, - {7, 76, 255, 108, 14} - }, - { {163, 183, 234, 75, 3}, - {101, 242, 60, 111, 5}, - {205, 37, 126, 220, 5}, - {175, 99, 196, 250, 6} - }, - { {68, 61, 107, 155, 4}, - {241, 98, 196, 164, 15}, - {45, 157, 107, 194, 2}, - {242, 82, 52, 104, 15} - }, - { {190, 45, 203, 132, 8}, - {187, 202, 37, 35, 10}, - {18, 29, 59, 71, 13}, - {92, 74, 69, 61, 13} - }, - { {181, 31, 196, 126, 12}, - {232, 171, 235, 106, 9}, - {55, 226, 63, 138, 13}, - {149, 109, 125, 81, 7} - }, - { {111, 56, 207, 152, 8}, - {243, 225, 165, 193, 10}, - {17, 159, 49, 207, 6}, - {88, 58, 88, 124, 15} - }, - { {144, 242, 254, 147, 4}, - {97, 205, 220, 22, 7}, - {44, 151, 244, 240, 9}, - {230, 131, 187, 56, 6} - }, - { {7, 253, 84, 10, 11}, - {229, 55, 17, 113, 9}, - {213, 2, 171, 254, 0}, - {152, 232, 142, 202, 7} - }, - { {238, 83, 195, 208, 8}, - {242, 198, 169, 139, 2}, - {16, 188, 60, 167, 7}, - {77, 25, 86, 52, 15} - }, - { {247, 9, 142, 188, 10}, - {136, 251, 167, 195, 10}, - {83, 215, 25, 14, 15}, - {92, 62, 93, 241, 1} - }, - { {101, 70, 124, 48, 9}, - {164, 5, 175, 240, 4}, - {144, 195, 230, 42, 6}, - {32, 255, 90, 2, 5} - }, - { {174, 111, 215, 151, 14}, - {187, 215, 233, 55, 11}, - {126, 158, 191, 103, 5}, - {222, 201, 126, 189, 13} - }, - { {139, 196, 115, 158, 9}, - {62, 100, 145, 115, 7}, - {151, 156, 226, 61, 1}, - {236, 232, 146, 103, 12} - }, - { {151, 25, 48, 254, 4}, - {200, 42, 194, 91, 15}, - {39, 240, 201, 142, 9}, - {253, 164, 53, 65, 3} - }, - { {154, 117, 45, 245, 7}, - {95, 31, 198, 47, 6}, - {234, 251, 74, 229, 9}, - {111, 70, 63, 143, 10} - }, - { {189, 71, 254, 83, 14}, - {162, 223, 237, 126, 5}, - {124, 167, 254, 43, 13}, - {167, 235, 127, 180, 5} - }, - { {111, 21, 48, 146, 8}, - {194, 2, 161, 241, 7}, - {20, 144, 202, 143, 6}, - {232, 248, 84, 4, 3} - }, - { {93, 225, 204, 72, 9}, - {167, 175, 21, 200, 0}, - {145, 35, 56, 123, 10}, - {1, 58, 143, 94, 5} - }, - { {17, 28, 227, 220, 13}, - {124, 232, 193, 104, 14}, - {179, 188, 115, 136, 8}, - {113, 104, 49, 115, 14} - }, - { {164, 199, 225, 87, 12}, - {184, 134, 249, 46, 5}, - {62, 168, 126, 50, 5}, - {167, 73, 246, 17, 13} - }, - { {85, 38, 145, 17, 2}, - {145, 152, 136, 244, 0}, - {72, 136, 150, 74, 10}, - {2, 241, 17, 152, 9} - }, - { {157, 101, 17, 128, 5}, - {151, 14, 64, 114, 2}, - {160, 24, 138, 107, 9}, - {68, 224, 39, 14, 9} - }, - { {102, 99, 193, 203, 3}, - {181, 182, 40, 141, 3}, - {205, 56, 60, 102, 6}, - {203, 17, 70, 218, 13} - }, - { {191, 197, 148, 0, 2}, - {130, 159, 48, 115, 0}, - {64, 2, 154, 63, 13}, - {12, 224, 207, 148, 1} - }, - { {58, 53, 0, 56, 7}, - {71, 58, 226, 33, 0}, - {225, 192, 10, 197, 12}, - {8, 68, 117, 206, 2} - }, - { {118, 212, 246, 121, 12}, - {224, 237, 243, 189, 4}, - {57, 230, 242, 182, 14}, - {43, 220, 251, 112, 7} - }, - { {68, 111, 38, 103, 11}, - {141, 87, 11, 172, 13}, - {222, 102, 79, 98, 2}, - {179, 93, 14, 171, 1} - }, - { {23, 174, 89, 233, 7}, - {181, 56, 94, 125, 10}, - {233, 121, 167, 94, 8}, - {91, 231, 161, 202, 13} - }, - { {54, 19, 45, 99, 14}, - {208, 27, 111, 13, 5}, - {124, 107, 76, 134, 12}, - {171, 15, 109, 128, 11} - }, - { {142, 7, 73, 43, 15}, - {182, 50, 79, 39, 1}, - {253, 73, 46, 7, 1}, - {142, 79, 36, 198, 13} - }, - { {24, 138, 205, 223, 1}, - {62, 169, 156, 12, 11}, - {143, 187, 53, 17, 8}, - {211, 3, 153, 87, 12} - }, - { {237, 144, 82, 208, 2}, - {226, 80, 176, 218, 2}, - {64, 180, 160, 155, 7}, - {69, 176, 208, 164, 7} - }, - { {91, 107, 208, 31, 5}, - {47, 174, 200, 213, 9}, - {175, 128, 189, 109, 10}, - {154, 177, 55, 95, 4} - }, - { {132, 164, 208, 112, 14}, - {161, 144, 211, 58, 0}, - {112, 224, 178, 82, 1}, - {5, 204, 176, 152, 5} - }, - { {201, 178, 163, 175, 4}, - {91, 224, 90, 198, 7}, - {47, 92, 84, 217, 3}, - {230, 53, 160, 125, 10} - }, - { {171, 24, 133, 47, 12}, - {90, 161, 99, 71, 9}, - {63, 74, 17, 141, 5}, - {158, 44, 104, 85, 10} - }, - { {157, 233, 24, 57, 0}, - {131, 46, 150, 86, 8}, - {9, 193, 137, 123, 9}, - {22, 166, 151, 76, 1} - }, - { {53, 118, 238, 158, 0}, - {233, 237, 172, 96, 7}, - {7, 151, 118, 234, 12}, - {224, 99, 91, 121, 7} - }, - { {232, 208, 13, 33, 0}, - {82, 5, 54, 134, 0}, - {8, 75, 0, 177, 7}, - {6, 22, 202, 4, 10} - }, - { {112, 155, 90, 149, 12}, - {104, 74, 253, 148, 10}, - {58, 149, 173, 144, 14}, - {82, 155, 245, 33, 6} - }, - { {169, 2, 42, 49, 4}, - {2, 64, 238, 70, 4}, - {40, 197, 68, 9, 5}, - {38, 39, 112, 36, 0} - }, - { {160, 62, 162, 185, 12}, - {65, 224, 235, 38, 14}, - {57, 212, 87, 192, 5}, - {118, 77, 112, 120, 2} - }, - { {30, 88, 158, 197, 14}, - {202, 221, 69, 29, 10}, - {122, 55, 145, 167, 8}, - {91, 138, 43, 181, 3} - }, - { {116, 71, 14, 237, 13}, - {140, 111, 111, 172, 2}, - {187, 119, 14, 34, 14}, - {67, 95, 111, 99, 1} - }, - { {54, 189, 68, 21, 9}, - {237, 11, 177, 37, 8}, - {154, 130, 43, 214, 12}, - {26, 72, 221, 11, 7} - }, - { {183, 248, 210, 81, 6}, - {225, 220, 240, 95, 8}, - {104, 164, 177, 254, 13}, - {31, 160, 243, 184, 7} - }, - { {220, 222, 75, 250, 5}, - {246, 108, 222, 170, 11}, - {165, 253, 39, 179, 11}, - {213, 87, 179, 102, 15} - }, - { {158, 218, 153, 195, 0}, - {210, 140, 28, 31, 11}, - {12, 57, 149, 183, 9}, - {223, 131, 131, 20, 11} - }, - { {143, 251, 152, 168, 11}, - {199, 182, 31, 83, 10}, - {209, 81, 157, 255, 1}, - {92, 175, 134, 222, 3} - }, - { {154, 199, 119, 231, 1}, - {62, 79, 26, 63, 7}, - {142, 126, 238, 53, 9}, - {239, 197, 143, 39, 12} - }, - { {141, 10, 83, 203, 3}, - {182, 112, 8, 94, 11}, - {205, 60, 165, 11, 1}, - {215, 161, 0, 230, 13} - }, - { {201, 237, 29, 206, 13}, - {31, 39, 85, 250, 11}, - {183, 59, 139, 121, 3}, - {213, 250, 174, 79, 8} - }, - { {194, 56, 83, 94, 10}, - {121, 112, 129, 155, 9}, - {87, 172, 161, 196, 3}, - {157, 152, 16, 233, 14} - }, - { {238, 74, 166, 67, 7}, - {134, 213, 104, 143, 13}, - {236, 38, 85, 39, 7}, - {191, 17, 106, 182, 1} - }, - { {205, 131, 69, 161, 14}, - {178, 19, 91, 198, 2}, - {120, 90, 44, 27, 3}, - {70, 61, 172, 132, 13} - }, - { {90, 25, 224, 90, 14}, - {98, 186, 193, 137, 13}, - {117, 160, 121, 133, 10}, - {185, 24, 53, 212, 6} - }, - { {150, 215, 128, 210, 5}, - {196, 142, 216, 43, 3}, - {164, 176, 30, 182, 9}, - {205, 65, 183, 18, 3} - }, - { {226, 200, 133, 24, 5}, - {20, 165, 240, 131, 8}, - {161, 138, 17, 52, 7}, - {28, 16, 250, 82, 8} - }, - { {197, 49, 79, 141, 11}, - {253, 115, 5, 198, 2}, - {219, 31, 40, 202, 3}, - {70, 58, 12, 235, 15} - }, - { {164, 124, 55, 238, 1}, - {221, 101, 34, 58, 15}, - {135, 126, 195, 226, 5}, - {245, 196, 74, 107, 11} - }, - { {29, 130, 198, 248, 12}, - {162, 233, 219, 72, 2}, - {49, 246, 52, 27, 8}, - {65, 45, 185, 116, 5} - }, - { {50, 92, 92, 108, 8}, - {104, 45, 39, 57, 8}, - {19, 99, 163, 164, 12}, - {25, 206, 75, 65, 6} - }, - { {93, 157, 27, 174, 0}, - {218, 106, 22, 240, 11}, - {7, 93, 139, 155, 10}, - {208, 246, 133, 101, 11} - }, - { {149, 73, 224, 117, 14}, - {168, 158, 195, 78, 12}, - {122, 224, 121, 42, 9}, - {55, 44, 55, 145, 5} - }, - { {138, 104, 69, 193, 5}, - {55, 5, 64, 15, 10}, - {168, 58, 33, 101, 1}, - {95, 0, 42, 14, 12} - }, - { {173, 249, 241, 15, 14}, - {251, 182, 113, 86, 13}, - {127, 8, 249, 251, 5}, - {182, 168, 230, 221, 15} - }, - { {149, 206, 243, 11, 0}, - {176, 236, 24, 118, 13}, - {13, 12, 247, 58, 9}, - {182, 225, 131, 112, 13} - }, - { {113, 147, 59, 32, 13}, - {84, 74, 127, 208, 4}, - {176, 77, 204, 152, 14}, - {32, 191, 229, 34, 10} - }, - { {31, 13, 227, 166, 15}, - {190, 218, 67, 97, 15}, - {246, 92, 123, 15, 8}, - {248, 108, 37, 183, 13} - }, - { {89, 111, 91, 186, 6}, - {51, 126, 206, 240, 11}, - {101, 221, 175, 105, 10}, - {208, 247, 55, 236, 12} - }, - { {205, 97, 217, 243, 4}, - {179, 134, 198, 222, 3}, - {44, 249, 184, 107, 3}, - {199, 182, 54, 28, 13} - }, - { {164, 120, 173, 50, 8}, - {209, 133, 167, 2, 13}, - {20, 203, 81, 226, 5}, - {180, 14, 90, 24, 11} - }, - { {218, 222, 64, 18, 15}, - {102, 28, 217, 163, 9}, - {244, 128, 39, 181, 11}, - {156, 89, 179, 134, 6} - }, - { {209, 87, 100, 55, 0}, - {104, 15, 138, 230, 5}, - {14, 194, 110, 168, 11}, - {166, 117, 31, 1, 6} - }, - { {58, 43, 245, 210, 2}, - {51, 155, 168, 25, 15}, - {68, 186, 253, 69, 12}, - {249, 129, 93, 156, 12} - }, - { {35, 3, 227, 72, 13}, - {52, 226, 105, 73, 4}, - {177, 44, 124, 12, 4}, - {41, 41, 100, 114, 12} - }, - { {65, 185, 191, 154, 9}, - {85, 227, 149, 208, 15}, - {149, 159, 217, 216, 2}, - {240, 186, 156, 122, 10} - }, - { {90, 78, 147, 238, 3}, - {30, 252, 10, 185, 11}, - {199, 124, 151, 37, 10}, - {217, 213, 3, 247, 8} - }, - { {70, 43, 68, 81, 2}, - {161, 19, 136, 141, 8}, - {72, 162, 45, 70, 2}, - {27, 17, 28, 136, 5} - }, - { {78, 1, 113, 156, 1}, - {190, 34, 128, 145, 6}, - {131, 152, 232, 7, 2}, - {104, 144, 20, 71, 13} - }, - { {115, 160, 217, 19, 7}, - {53, 152, 244, 213, 1}, - {236, 137, 176, 92, 14}, - {138, 178, 241, 154, 12} - }, - { {147, 43, 65, 109, 13}, - {61, 42, 75, 79, 8}, - {187, 104, 45, 76, 9}, - {31, 45, 37, 75, 12} - }, - { {255, 75, 97, 90, 7}, - {182, 62, 232, 203, 13}, - {229, 168, 109, 47, 15}, - {189, 49, 119, 198, 13} - }, - { {44, 136, 15, 26, 12}, - {146, 97, 245, 0, 9}, - {53, 143, 1, 19, 4}, - {144, 10, 248, 100, 9} - }, - { {111, 59, 182, 170, 1}, - {199, 227, 42, 209, 15}, - {133, 86, 221, 207, 6}, - {248, 181, 76, 126, 3} - }, - { {71, 109, 33, 174, 6}, - {153, 54, 66, 225, 15}, - {103, 88, 75, 110, 2}, - {248, 116, 38, 201, 9} - }, - { {249, 194, 144, 104, 8}, - {2, 172, 59, 218, 0}, - {17, 96, 148, 57, 15}, - {5, 189, 195, 84, 0} - }, - { {118, 129, 17, 33, 0}, - {144, 10, 50, 149, 0}, - {8, 72, 136, 22, 14}, - {10, 148, 197, 0, 9} - }, - { {98, 52, 88, 245, 5}, - {109, 0, 230, 189, 2}, - {170, 241, 162, 196, 6}, - {75, 214, 112, 11, 6} - }, - { {243, 25, 25, 225, 15}, - {84, 26, 103, 223, 10}, - {248, 121, 137, 140, 15}, - {95, 190, 101, 130, 10} - }, - { {239, 71, 167, 221, 1}, - {158, 231, 168, 239, 6}, - {139, 190, 94, 47, 7}, - {111, 113, 94, 119, 9} - }, - { {198, 199, 119, 128, 8}, - {176, 71, 25, 179, 6}, - {16, 30, 238, 54, 3}, - {108, 217, 142, 32, 13} - }, - { {238, 201, 111, 9, 6}, - {178, 119, 116, 135, 12}, - {105, 15, 105, 55, 7}, - {62, 18, 238, 228, 13} - }, - { {155, 60, 155, 218, 15}, - {87, 248, 197, 123, 11}, - {245, 189, 147, 205, 9}, - {221, 234, 49, 254, 10} - }, - { {111, 212, 50, 87, 3}, - {206, 84, 176, 253, 5}, - {206, 164, 194, 191, 6}, - {171, 240, 210, 167, 3} - }, - { {96, 231, 208, 170, 9}, - {37, 166, 59, 176, 3}, - {149, 80, 190, 112, 6}, - {192, 221, 198, 90, 4} - }, - { {6, 81, 205, 163, 4}, - {240, 135, 70, 5, 3}, - {44, 91, 56, 166, 0}, - {202, 6, 46, 16, 15} - }, - { {226, 172, 192, 78, 7}, - {45, 176, 112, 171, 9}, - {231, 32, 51, 84, 7}, - {157, 80, 224, 219, 4} - }, - { {148, 96, 209, 162, 2}, - {177, 156, 2, 18, 3}, - {68, 88, 176, 98, 9}, - {196, 132, 3, 152, 13} - }, - { {130, 183, 155, 23, 7}, - {93, 210, 220, 55, 1}, - {238, 141, 158, 212, 1}, - {142, 195, 180, 187, 10} - }, - { {78, 177, 137, 244, 11}, - {223, 146, 151, 137, 2}, - {210, 249, 24, 215, 2}, - {73, 30, 148, 159, 11} - }, - { {203, 249, 195, 177, 14}, - {115, 214, 211, 199, 10}, - {120, 220, 57, 253, 3}, - {94, 60, 182, 188, 14} - }, - { {111, 108, 100, 132, 1}, - {175, 5, 32, 225, 14}, - {130, 18, 99, 111, 6}, - {120, 112, 74, 15, 5} - }, - { {229, 78, 80, 162, 14}, - {160, 20, 107, 242, 11}, - {116, 80, 167, 42, 7}, - {212, 253, 98, 128, 5} - }, - { {99, 47, 48, 242, 3}, - {5, 18, 170, 249, 15}, - {196, 240, 207, 76, 6}, - {249, 245, 84, 138, 0} - }, - { {179, 187, 61, 230, 12}, - {89, 11, 127, 91, 15}, - {54, 123, 205, 220, 13}, - {253, 175, 237, 9, 10} - }, - { {99, 49, 245, 56, 3}, - {117, 179, 162, 209, 4}, - {193, 202, 248, 204, 6}, - {40, 180, 92, 218, 14} - }, - { {188, 161, 218, 254, 5}, - {175, 234, 246, 26, 3}, - {167, 245, 184, 83, 13}, - {197, 134, 245, 127, 5} - }, - { {209, 129, 108, 171, 9}, - {36, 43, 23, 198, 7}, - {157, 83, 104, 24, 11}, - {230, 62, 141, 66, 4} - }, - { {13, 132, 7, 172, 10}, - {154, 113, 19, 96, 2}, - {83, 94, 2, 27, 0}, - {64, 108, 136, 229, 9} - }, - { {121, 78, 29, 126, 5}, - {30, 45, 238, 248, 9}, - {167, 235, 135, 41, 14}, - {145, 247, 123, 71, 8} - }, - { {146, 222, 101, 68, 2}, - {120, 29, 24, 43, 12}, - {66, 42, 103, 180, 9}, - {61, 65, 139, 129, 14} - }, - { {101, 20, 151, 148, 9}, - {220, 193, 161, 240, 2}, - {146, 158, 146, 138, 6}, - {64, 248, 88, 51, 11} - }, - { {51, 247, 81, 113, 2}, - {113, 30, 186, 125, 0}, - {72, 232, 174, 252, 12}, - {11, 229, 215, 136, 14} - }, - { {60, 156, 233, 25, 5}, - {246, 168, 244, 36, 12}, - {169, 137, 115, 147, 12}, - {50, 66, 241, 86, 15} - }, - { {126, 203, 129, 215, 10}, - {154, 158, 185, 141, 11}, - {94, 184, 29, 55, 14}, - {219, 25, 215, 149, 9} - }, - { {237, 225, 64, 23, 8}, - {171, 6, 177, 198, 1}, - {30, 128, 40, 123, 7}, - {134, 56, 214, 13, 5} - }, - { {192, 155, 14, 226, 12}, - {64, 67, 95, 138, 11}, - {52, 119, 13, 144, 3}, - {213, 31, 172, 32, 2} - }, - { {20, 230, 31, 119, 4}, - {153, 77, 222, 60, 1}, - {46, 239, 134, 114, 8}, - {131, 199, 187, 41, 9} - }, - { {109, 51, 102, 73, 10}, - {227, 115, 41, 204, 4}, - {89, 38, 108, 203, 6}, - {35, 57, 76, 236, 7} - }, - { {134, 93, 208, 136, 0}, - {224, 166, 0, 51, 10}, - {1, 16, 187, 166, 1}, - {92, 192, 6, 80, 7} - }, - { {247, 33, 75, 251, 8}, - {177, 106, 167, 207, 3}, - {29, 253, 40, 78, 15}, - {207, 62, 85, 104, 13} - }, - { {216, 185, 194, 226, 2}, - {99, 218, 18, 138, 11}, - {68, 116, 57, 209, 11}, - {213, 20, 133, 188, 6} - }, - { {153, 167, 7, 55, 15}, - {31, 91, 219, 102, 1}, - {254, 206, 14, 89, 9}, - {134, 109, 189, 175, 8} - }, - { {192, 236, 249, 12, 9}, - {61, 164, 21, 178, 12}, - {147, 9, 243, 112, 3}, - {52, 218, 130, 91, 12} - }, - { {187, 139, 38, 224, 1}, - {6, 75, 58, 75, 14}, - {128, 118, 77, 29, 13}, - {125, 37, 205, 38, 0} - }, - { {5, 103, 143, 202, 12}, - {145, 231, 77, 104, 3}, - {53, 63, 30, 106, 0}, - {193, 107, 46, 120, 9} - }, - { {51, 180, 131, 131, 4}, - {81, 200, 112, 101, 3}, - {44, 28, 18, 220, 12}, - {202, 96, 225, 56, 10} - }, - { {235, 157, 132, 184, 3}, - {70, 179, 178, 227, 10}, - {193, 210, 27, 157, 7}, - {92, 116, 220, 214, 2} - }, - { {124, 162, 119, 234, 2}, - {179, 121, 58, 152, 7}, - {69, 126, 228, 83, 14}, - {225, 149, 201, 236, 13} - }, - { {2, 175, 95, 102, 11}, - {61, 83, 31, 57, 9}, - {214, 111, 175, 84, 0}, - {153, 207, 140, 171, 12} - }, - { {74, 103, 140, 18, 2}, - {3, 151, 140, 161, 1}, - {68, 131, 30, 101, 2}, - {136, 83, 30, 156, 0} - }, - { {18, 21, 146, 191, 3}, - {76, 250, 130, 53, 3}, - {207, 212, 154, 132, 8}, - {202, 196, 21, 243, 2} - }, - { {204, 130, 180, 140, 9}, - {142, 161, 25, 146, 6}, - {147, 18, 212, 19, 3}, - {100, 153, 136, 87, 1} - }, - { {119, 203, 233, 15, 12}, - {184, 174, 125, 197, 13}, - {63, 9, 125, 62, 14}, - {186, 59, 231, 81, 13} - }, - { {94, 247, 215, 147, 1}, - {247, 207, 152, 181, 3}, - {140, 158, 190, 247, 10}, - {202, 209, 159, 62, 15} - }, - { {17, 121, 71, 153, 5}, - {117, 111, 192, 68, 10}, - {169, 158, 41, 232, 8}, - {82, 32, 63, 106, 14} - }, - { {52, 77, 95, 151, 0}, - {184, 79, 164, 52, 11}, - {14, 159, 171, 34, 12}, - {210, 194, 95, 33, 13} - }, - { {223, 47, 18, 231, 2}, - {139, 90, 10, 255, 11}, - {78, 116, 143, 79, 11}, - {223, 245, 5, 173, 1} - }, - { {17, 66, 119, 179, 7}, - {52, 93, 202, 84, 7}, - {236, 222, 228, 40, 8}, - {226, 165, 59, 162, 12} - }, - { {11, 143, 167, 61, 5}, - {30, 227, 218, 101, 12}, - {171, 206, 95, 29, 0}, - {58, 101, 188, 119, 8} - }, - { {54, 225, 111, 66, 3}, - {181, 95, 52, 9, 5}, - {196, 47, 104, 118, 12}, - {169, 2, 207, 170, 13} - }, - { {5, 116, 2, 183, 14}, - {201, 84, 195, 100, 3}, - {126, 212, 2, 234, 0}, - {194, 108, 50, 169, 3} - }, - { {195, 66, 66, 58, 7}, - {36, 116, 202, 195, 1}, - {229, 196, 36, 44, 3}, - {140, 53, 50, 226, 4} - }, - { {117, 140, 52, 218, 11}, - {132, 57, 177, 248, 15}, - {213, 178, 195, 26, 14}, - {241, 248, 217, 194, 1} - }, - { {103, 220, 97, 97, 4}, - {240, 4, 114, 237, 12}, - {40, 104, 99, 190, 6}, - {59, 116, 226, 0, 15} - }, - { {41, 178, 34, 6, 8}, - {75, 64, 57, 64, 5}, - {22, 4, 68, 217, 4}, - {160, 41, 192, 45, 2} - }, - { {113, 1, 175, 15, 10}, - {24, 251, 37, 196, 5}, - {95, 15, 88, 8, 14}, - {162, 58, 77, 241, 8} - }, - { {84, 210, 43, 199, 5}, - {220, 76, 92, 140, 7}, - {174, 61, 68, 178, 10}, - {227, 19, 163, 35, 11} - }, - { {144, 139, 163, 175, 9}, - {28, 234, 27, 6, 15}, - {159, 92, 93, 16, 9}, - {246, 13, 133, 115, 8} - }, - { {235, 104, 201, 181, 1}, - {63, 132, 166, 199, 10}, - {138, 217, 49, 109, 7}, - {94, 54, 82, 31, 12} - }, - { {38, 5, 212, 66, 12}, - {160, 131, 97, 57, 1}, - {52, 34, 186, 6, 4}, - {137, 200, 108, 16, 5} - }, - { {106, 184, 139, 127, 4}, - {91, 224, 246, 141, 9}, - {47, 237, 17, 213, 6}, - {155, 22, 240, 125, 10} - }, - { {32, 124, 118, 87, 13}, - {109, 69, 225, 60, 13}, - {190, 166, 227, 224, 4}, - {179, 200, 122, 43, 6} - }, - { {55, 121, 64, 210, 0}, - {225, 14, 160, 73, 11}, - {4, 176, 41, 238, 12}, - {217, 32, 87, 8, 7} - }, - { {172, 46, 183, 123, 6}, - {147, 241, 234, 62, 13}, - {109, 238, 215, 67, 5}, - {183, 197, 120, 252, 9} - }, - { {62, 135, 49, 142, 12}, - {154, 42, 121, 49, 7}, - {55, 24, 206, 23, 12}, - {232, 201, 229, 69, 9} - }, - { {71, 175, 234, 26, 10}, - {161, 242, 157, 225, 13}, - {85, 133, 127, 94, 2}, - {184, 123, 148, 248, 5} - }, - { {70, 222, 53, 183, 4}, - {216, 5, 218, 181, 15}, - {46, 218, 199, 182, 2}, - {250, 213, 186, 1, 11} - }, - { {72, 163, 107, 161, 0}, - {51, 66, 30, 132, 6}, - {8, 93, 108, 81, 2}, - {98, 23, 132, 44, 12} - }, - { {240, 113, 21, 54, 11}, - {93, 31, 163, 146, 1}, - {214, 202, 136, 224, 15}, - {132, 156, 95, 139, 10} - }, - { {150, 63, 135, 237, 4}, - {217, 235, 74, 47, 10}, - {43, 126, 31, 198, 9}, - {95, 69, 45, 121, 11} - }, - { {216, 58, 185, 150, 5}, - {95, 136, 204, 146, 15}, - {166, 153, 213, 193, 11}, - {244, 147, 49, 31, 10} - }, - { {123, 46, 181, 160, 15}, - {23, 153, 107, 241, 14}, - {240, 90, 215, 77, 14}, - {120, 253, 105, 158, 8} - }, - { {182, 173, 250, 243, 2}, - {161, 218, 182, 63, 15}, - {76, 245, 251, 86, 13}, - {255, 198, 213, 184, 5} - }, - { {135, 224, 122, 78, 10}, - {169, 116, 21, 91, 5}, - {87, 37, 224, 126, 1}, - {173, 170, 130, 233, 5} - }, - { {123, 69, 24, 244, 14}, - {10, 30, 231, 249, 2}, - {114, 241, 138, 45, 14}, - {73, 254, 119, 133, 0} - }, - { {144, 100, 163, 115, 8}, - {17, 204, 131, 46, 5}, - {28, 236, 82, 96, 9}, - {167, 76, 19, 56, 8} - }, - { {60, 36, 44, 161, 2}, - {131, 25, 38, 36, 6}, - {72, 83, 66, 67, 12}, - {98, 70, 73, 140, 1} - }, - { {150, 178, 92, 74, 4}, - {225, 41, 92, 27, 1}, - {37, 35, 164, 214, 9}, - {141, 131, 169, 72, 7} - }, - { {139, 1, 216, 58, 12}, - {34, 162, 199, 83, 1}, - {53, 193, 184, 13, 1}, - {140, 174, 52, 84, 4} - }, - { {229, 28, 206, 178, 5}, - {228, 193, 230, 226, 11}, - {164, 215, 51, 138, 7}, - {212, 118, 120, 50, 7} - }, - { {72, 15, 88, 219, 0}, - {34, 34, 140, 188, 11}, - {13, 177, 175, 1, 2}, - {211, 211, 20, 68, 4} - }, - { {186, 226, 149, 134, 7}, - {31, 157, 120, 19, 3}, - {230, 26, 148, 117, 13}, - {204, 129, 235, 159, 8} - }, - { {137, 252, 15, 186, 0}, - {83, 101, 150, 98, 11}, - {5, 223, 3, 249, 1}, - {212, 102, 154, 108, 10} - }, - { {221, 6, 71, 94, 9}, - {190, 105, 137, 234, 1}, - {151, 174, 38, 11, 11}, - {133, 121, 25, 103, 13} - }, - { {247, 254, 70, 180, 12}, - {233, 77, 251, 227, 10}, - {50, 214, 39, 254, 15}, - {92, 125, 251, 41, 7} - }, - { {67, 206, 240, 38, 13}, - {44, 132, 91, 241, 13}, - {182, 64, 247, 60, 2}, - {184, 253, 162, 19, 4} - }, - { {99, 147, 88, 90, 2}, - {96, 50, 188, 217, 1}, - {69, 161, 172, 156, 6}, - {137, 179, 212, 192, 6} - }, - { {135, 180, 4, 69, 6}, - {201, 17, 80, 111, 0}, - {106, 34, 2, 222, 1}, - {15, 96, 168, 137, 3} - }, - { {79, 164, 124, 190, 10}, - {171, 49, 151, 241, 7}, - {87, 211, 226, 95, 2}, - {232, 254, 152, 205, 5} - }, - { {118, 25, 249, 85, 10}, - {248, 154, 165, 157, 12}, - {90, 169, 249, 134, 14}, - {59, 154, 85, 145, 15} - }, - { {81, 185, 161, 51, 0}, - {81, 138, 146, 196, 13}, - {12, 200, 89, 216, 10}, - {178, 52, 149, 24, 10} - }, - { {21, 51, 99, 124, 7}, - {253, 122, 202, 72, 4}, - {227, 236, 108, 202, 8}, - {33, 37, 53, 235, 15} - }, - { {117, 135, 169, 114, 10}, - {144, 154, 191, 232, 5}, - {84, 233, 94, 26, 14}, - {161, 127, 213, 144, 9} - }, - { {96, 222, 17, 98, 2}, - {80, 20, 58, 184, 9}, - {68, 104, 135, 176, 6}, - {145, 213, 194, 128, 10} - }, - { {125, 76, 230, 138, 14}, - {162, 253, 97, 224, 15}, - {117, 22, 115, 43, 14}, - {240, 120, 107, 244, 5} - }, - { {175, 19, 94, 129, 12}, - {226, 67, 109, 87, 2}, - {56, 23, 172, 143, 5}, - {78, 171, 108, 36, 7} - }, - { {49, 201, 182, 71, 12}, - {8, 207, 113, 92, 13}, - {62, 38, 217, 56, 12}, - {179, 168, 239, 49, 0} - }, - { {172, 67, 216, 21, 5}, - {174, 134, 236, 22, 0}, - {170, 129, 188, 35, 5}, - {6, 131, 118, 23, 5} - }, - { {216, 83, 225, 207, 11}, - {126, 190, 9, 142, 7}, - {223, 56, 124, 161, 11}, - {231, 25, 7, 215, 14} - }, - { {79, 205, 197, 207, 0}, - {186, 167, 16, 237, 11}, - {15, 58, 59, 63, 2}, - {219, 112, 142, 85, 13} - }, - { {238, 105, 111, 210, 13}, - {183, 71, 229, 139, 15}, - {180, 191, 105, 103, 7}, - {253, 26, 126, 46, 13} - }, - { {183, 22, 24, 71, 5}, - {204, 8, 108, 127, 1}, - {174, 33, 134, 142, 13}, - {143, 227, 97, 3, 3} - }, - { {185, 180, 184, 120, 1}, - {71, 168, 182, 122, 4}, - {129, 225, 210, 217, 13}, - {37, 230, 209, 94, 2} - }, - { {50, 133, 121, 80, 5}, - {52, 10, 244, 57, 4}, - {160, 169, 234, 20, 12}, - {41, 194, 245, 2, 12} - }, - { {149, 233, 71, 119, 1}, - {189, 79, 146, 78, 9}, - {142, 238, 41, 122, 9}, - {151, 36, 159, 43, 13} - }, - { {154, 160, 48, 46, 2}, - {11, 56, 18, 19, 5}, - {71, 64, 192, 85, 9}, - {172, 132, 129, 205, 0} - }, - { {236, 24, 40, 209, 7}, - {198, 16, 228, 142, 14}, - {232, 177, 65, 131, 7}, - {119, 18, 112, 134, 3} - }, - { {188, 80, 121, 99, 5}, - {246, 12, 102, 30, 5}, - {172, 105, 224, 163, 13}, - {167, 134, 99, 6, 15} - }, - { {135, 133, 193, 183, 9}, - {188, 130, 147, 103, 3}, - {158, 216, 58, 30, 1}, - {206, 108, 148, 19, 13} - }, - { {211, 122, 173, 183, 10}, - {89, 157, 143, 199, 15}, - {94, 219, 85, 236, 11}, - {254, 63, 27, 153, 10} - }, - { {129, 127, 2, 206, 0}, - {73, 102, 8, 106, 11}, - {7, 52, 15, 232, 1}, - {213, 97, 6, 105, 2} - }, - { {253, 99, 223, 176, 10}, - {179, 223, 175, 210, 2}, - {80, 223, 188, 107, 15}, - {68, 191, 95, 188, 13} - }, - { {81, 10, 193, 175, 2}, - {56, 184, 10, 196, 11}, - {79, 88, 53, 8, 10}, - {210, 53, 1, 209, 12} - }, - { {61, 30, 223, 141, 3}, - {254, 249, 44, 116, 10}, - {203, 31, 183, 139, 12}, - {82, 227, 73, 247, 15} - }, - { {244, 183, 58, 64, 2}, - {193, 90, 60, 186, 4}, - {64, 37, 206, 210, 15}, - {37, 211, 197, 168, 3} - }, - { {55, 215, 137, 233, 12}, - {208, 174, 127, 109, 2}, - {57, 121, 30, 190, 12}, - {75, 111, 231, 80, 11} - }, - { {143, 17, 199, 124, 10}, - {250, 243, 131, 75, 0}, - {83, 238, 56, 143, 1}, - {13, 44, 28, 245, 15} - }, - { {196, 189, 3, 107, 14}, - {209, 114, 83, 174, 9}, - {125, 108, 11, 210, 3}, - {151, 92, 164, 232, 11} - }, - { {125, 250, 153, 92, 9}, - {223, 172, 189, 216, 8}, - {147, 169, 149, 251, 14}, - {17, 187, 211, 95, 11} - }, - { {123, 20, 232, 37, 1}, - {110, 136, 38, 229, 4}, - {138, 65, 114, 141, 14}, - {42, 118, 65, 23, 6} - }, - { {202, 7, 14, 127, 4}, - {10, 99, 206, 175, 1}, - {47, 231, 14, 5, 3}, - {143, 87, 60, 101, 0} - }, - { {92, 34, 219, 205, 5}, - {191, 232, 76, 156, 2}, - {171, 61, 180, 67, 10}, - {67, 147, 33, 127, 13} - }, - { {160, 219, 114, 108, 8}, - {104, 102, 59, 26, 12}, - {19, 100, 237, 176, 5}, - {53, 141, 198, 97, 6} - }, - { {107, 119, 118, 222, 2}, - {107, 119, 168, 249, 7}, - {71, 182, 238, 237, 6}, - {233, 241, 94, 237, 6} - }, - { {128, 245, 142, 116, 8}, - {73, 199, 151, 42, 0}, - {18, 231, 26, 240, 1}, - {5, 78, 158, 57, 2} - }, - { {225, 172, 31, 244, 10}, - {25, 81, 183, 250, 10}, - {82, 255, 131, 88, 7}, - {85, 254, 216, 169, 8} - }, - { {27, 186, 234, 133, 12}, - {107, 200, 93, 69, 14}, - {58, 21, 117, 221, 8}, - {122, 43, 161, 61, 6} - }, - { {38, 172, 85, 127, 12}, - {185, 33, 243, 61, 9}, - {63, 234, 163, 86, 4}, - {155, 204, 248, 73, 13} - }, - { {229, 209, 239, 53, 7}, - {252, 215, 246, 198, 4}, - {234, 207, 120, 186, 7}, - {38, 54, 254, 179, 15} - }, - { {31, 41, 212, 225, 0}, - {163, 139, 2, 93, 10}, - {8, 114, 185, 79, 8}, - {91, 164, 13, 28, 5} - }, - { {69, 159, 187, 21, 11}, - {220, 210, 157, 244, 12}, - {218, 141, 223, 154, 2}, - {50, 251, 148, 179, 11} - }, - { {212, 176, 73, 85, 9}, - {253, 8, 149, 142, 0}, - {154, 169, 32, 210, 11}, - {7, 26, 145, 11, 15} - }, - { {108, 183, 10, 207, 8}, - {203, 98, 61, 172, 3}, - {31, 53, 14, 211, 6}, - {195, 91, 196, 109, 3} - }, - { {248, 97, 122, 81, 8}, - {35, 78, 165, 158, 4}, - {24, 165, 232, 97, 15}, - {39, 154, 87, 44, 4} - }, - { {195, 145, 218, 195, 4}, - {96, 194, 84, 223, 3}, - {44, 53, 184, 156, 3}, - {207, 178, 164, 48, 6} - }, - { {81, 35, 94, 44, 12}, - {41, 107, 79, 208, 0}, - {51, 71, 172, 72, 10}, - {0, 191, 45, 105, 4} - }, - { {116, 64, 124, 79, 14}, - {168, 61, 101, 156, 5}, - {127, 35, 224, 34, 14}, - {163, 154, 107, 193, 5} - }, - { {223, 22, 9, 162, 4}, - {210, 8, 78, 227, 3}, - {36, 89, 6, 143, 11}, - {204, 119, 33, 4, 11} - }, - { {206, 210, 125, 193, 7}, - {246, 21, 92, 159, 6}, - {232, 59, 228, 183, 3}, - {111, 147, 170, 134, 15} - } -}; - -}//namespace diff --git a/modules/aruco/src/apriltag/unionfind.hpp b/modules/aruco/src/apriltag/unionfind.hpp deleted file mode 100644 index 1affa6b93c2..00000000000 --- a/modules/aruco/src/apriltag/unionfind.hpp +++ /dev/null @@ -1,133 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. -// -// Copyright (C) 2013-2016, The Regents of The University of Michigan. -// -// This software was developed in the APRIL Robotics Lab under the -// direction of Edwin Olson, ebolson@umich.edu. This software may be -// available under alternative licensing terms; contact the address above. -// -// The views and conclusions contained in the software and documentation are those -// of the authors and should not be interpreted as representing official policies, -// either expressed or implied, of the Regents of The University of Michigan. -#ifndef _OPENCV_UNIONFIND_HPP_ -#define _OPENCV_UNIONFIND_HPP_ - -#include -#include -namespace cv { -namespace aruco { - -typedef struct unionfind unionfind_t; -struct unionfind{ - uint32_t maxid; - struct ufrec *data; -}; - -struct ufrec{ - // the parent of this node. If a node's parent is its own index, - // then it is a root. - uint32_t parent; - - // for the root of a connected component, the number of components - // connected to it. For intermediate values, it's not meaningful. - uint32_t size; -}; - -static inline unionfind_t *unionfind_create(uint32_t maxid){ - unionfind_t *uf = (unionfind_t*) calloc(1, sizeof(unionfind_t)); - uf->maxid = maxid; - uf->data = (struct ufrec*) malloc((maxid+1) * sizeof(struct ufrec)); - for (unsigned int i = 0; i <= maxid; i++) { - uf->data[i].size = 1; - uf->data[i].parent = i; - } - return uf; -} - -static inline void unionfind_destroy(unionfind_t *uf){ - free(uf->data); - free(uf); -} - -/* -static inline uint32_t unionfind_get_representative(unionfind_t *uf, uint32_t id) -{ - // base case: a node is its own parent - if (uf->data[id].parent == id) - return id; - - // otherwise, recurse - uint32_t root = unionfind_get_representative(uf, uf->data[id].parent); - - // short circuit the path. [XXX This write prevents tail recursion] - uf->data[id].parent = root; - - return root; -} - */ - -// this one seems to be every-so-slightly faster than the recursive -// version above. -static inline uint32_t unionfind_get_representative(unionfind_t *uf, uint32_t id){ - uint32_t root = id; - - // chase down the root - while (uf->data[root].parent != root) { - root = uf->data[root].parent; - } - - // go back and collapse the tree. - // - // XXX: on some of our workloads that have very shallow trees - // (e.g. image segmentation), we are actually faster not doing - // this... - while (uf->data[id].parent != root) { - uint32_t tmp = uf->data[id].parent; - uf->data[id].parent = root; - id = tmp; - } - - return root; -} - -static inline uint32_t unionfind_get_set_size(unionfind_t *uf, uint32_t id){ - uint32_t repid = unionfind_get_representative(uf, id); - return uf->data[repid].size; -} - -static inline uint32_t unionfind_connect(unionfind_t *uf, uint32_t aid, uint32_t bid){ - uint32_t aroot = unionfind_get_representative(uf, aid); - uint32_t broot = unionfind_get_representative(uf, bid); - - if (aroot == broot) - return aroot; - - // we don't perform "union by rank", but we perform a similar - // operation (but probably without the same asymptotic guarantee): - // We join trees based on the number of *elements* (as opposed to - // rank) contained within each tree. I.e., we use size as a proxy - // for rank. In my testing, it's often *faster* to use size than - // rank, perhaps because the rank of the tree isn't that critical - // if there are very few nodes in it. - uint32_t asize = uf->data[aroot].size; - uint32_t bsize = uf->data[broot].size; - - // optimization idea: We could shortcut some or all of the tree - // that is grafted onto the other tree. Pro: those nodes were just - // read and so are probably in cache. Con: it might end up being - // wasted effort -- the tree might be grafted onto another tree in - // a moment! - if (asize > bsize) { - uf->data[broot].parent = aroot; - uf->data[aroot].size += bsize; - return aroot; - } else { - uf->data[aroot].parent = broot; - uf->data[broot].size += asize; - return broot; - } -} -}} -#endif diff --git a/modules/aruco/src/apriltag/zarray.hpp b/modules/aruco/src/apriltag/zarray.hpp deleted file mode 100644 index 91933c5f5f8..00000000000 --- a/modules/aruco/src/apriltag/zarray.hpp +++ /dev/null @@ -1,150 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. -// -// Copyright (C) 2013-2016, The Regents of The University of Michigan. -// -// This software was developed in the APRIL Robotics Lab under the -// direction of Edwin Olson, ebolson@umich.edu. This software may be -// available under alternative licensing terms; contact the address above. -// -// The views and conclusions contained in the software and documentation are those -// of the authors and should not be interpreted as representing official policies, -// either expressed or implied, of the Regents of The University of Michigan. -#ifndef _OPENCV_ZARRAY_HPP_ -#define _OPENCV_ZARRAY_HPP_ - -#include -#include - -namespace cv { -namespace aruco { - - -struct sQuad{ - float p[4][2]; // corners -}; - -/** - * Defines a structure which acts as a resize-able array ala Java's ArrayList. - */ -typedef struct zarray zarray_t; -struct zarray{ - size_t el_sz; // size of each element - - int size; // how many elements? - int alloc; // we've allocated storage for how many elements? - char *data; -}; - -/** - * Creates and returns a variable array structure capable of holding elements of - * the specified size. It is the caller's responsibility to call zarray_destroy() - * on the returned array when it is no longer needed. - */ -inline static zarray_t *_zarray_create(size_t el_sz){ - zarray_t *za = (zarray_t*) calloc(1, sizeof(zarray_t)); - za->el_sz = el_sz; - return za; -} - -/** - * Frees all resources associated with the variable array structure which was - * created by zarray_create(). After calling, 'za' will no longer be valid for storage. - */ -inline static void _zarray_destroy(zarray_t *za){ - if (za == NULL) - return; - - if (za->data != NULL) - free(za->data); - memset(za, 0, sizeof(zarray_t)); - free(za); -} - -/** - * Retrieves the number of elements currently being contained by the passed - * array, which may be different from its capacity. The index of the last element - * in the array will be one less than the returned value. - */ -inline static int _zarray_size(const zarray_t *za){ - return za->size; -} - -/** - * Allocates enough internal storage in the supplied variable array structure to - * guarantee that the supplied number of elements (capacity) can be safely stored. - */ -inline static void _zarray_ensure_capacity(zarray_t *za, int capacity){ - if (capacity <= za->alloc) - return; - - while (za->alloc < capacity) { - za->alloc *= 2; - if (za->alloc < 8) - za->alloc = 8; - } - - za->data = (char*) realloc(za->data, za->alloc * za->el_sz); -} - -/** - * Adds a new element to the end of the supplied array, and sets its value - * (by copying) from the data pointed to by the supplied pointer 'p'. - * Automatically ensures that enough storage space is available for the new element. - */ -inline static void _zarray_add(zarray_t *za, const void *p){ - _zarray_ensure_capacity(za, za->size + 1); - - memcpy(&za->data[za->size*za->el_sz], p, za->el_sz); - za->size++; -} - -/** - * Retrieves the element from the supplied array located at the zero-based - * index of 'idx' and copies its value into the variable pointed to by the pointer - * 'p'. - */ -inline static void _zarray_get(const zarray_t *za, int idx, void *p){ - CV_DbgAssert(idx >= 0); - CV_DbgAssert(idx < za->size); - - memcpy(p, &za->data[idx*za->el_sz], za->el_sz); -} - -/** - * Similar to zarray_get(), but returns a "live" pointer to the internal - * storage, avoiding a memcpy. This pointer is not valid across - * operations which might move memory around (i.e. zarray_remove_value(), - * zarray_remove_index(), zarray_insert(), zarray_sort(), zarray_clear()). - * 'p' should be a pointer to the pointer which will be set to the internal address. - */ -inline static void _zarray_get_volatile(const zarray_t *za, int idx, void *p){ - CV_DbgAssert(idx >= 0); - CV_DbgAssert(idx < za->size); - - *((void**) p) = &za->data[idx*za->el_sz]; -} - -inline static void _zarray_truncate(zarray_t *za, int sz){ - za->size = sz; -} - -/** - * Sets the value of the current element at index 'idx' by copying its value from - * the data pointed to by 'p'. The previous value of the changed element will be - * copied into the data pointed to by 'outp' if it is not null. - */ -static inline void _zarray_set(zarray_t *za, int idx, const void *p, void *outp){ - CV_DbgAssert(idx >= 0); - CV_DbgAssert(idx < za->size); - - if (outp != NULL) - memcpy(outp, &za->data[idx*za->el_sz], za->el_sz); - - memcpy(&za->data[idx*za->el_sz], p, za->el_sz); -} - -} -} -#endif diff --git a/modules/aruco/src/apriltag/zmaxheap.cpp b/modules/aruco/src/apriltag/zmaxheap.cpp deleted file mode 100644 index f3b315e7317..00000000000 --- a/modules/aruco/src/apriltag/zmaxheap.cpp +++ /dev/null @@ -1,207 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. -// -// Copyright (C) 2013-2016, The Regents of The University of Michigan. -// -// This software was developed in the APRIL Robotics Lab under the -// direction of Edwin Olson, ebolson@umich.edu. This software may be -// available under alternative licensing terms; contact the address above. -// -// The views and conclusions contained in the software and documentation are those -// of the authors and should not be interpreted as representing official policies, -// either expressed or implied, of the Regents of The University of Michigan. - -#include "../precomp.hpp" -#include "zmaxheap.hpp" - - -// 0 -// 1 2 -// 3 4 5 6 -// 7 8 9 10 11 12 13 14 -// -// Children of node i: 2*i+1, 2*i+2 -// Parent of node i: (i-1) / 2 -// -// Heap property: a parent is greater than (or equal to) its children. - -#define MIN_CAPACITY 16 -namespace cv { -namespace aruco { -struct zmaxheap -{ - size_t el_sz; - - int size; - int alloc; - - float *values; - char *data; - - void (*swap)(zmaxheap_t *heap, int a, int b); -}; - -static inline void _swap_default(zmaxheap_t *heap, int a, int b) -{ - float t = heap->values[a]; - heap->values[a] = heap->values[b]; - heap->values[b] = t; - - cv::AutoBuffer tmp(heap->el_sz); - memcpy(tmp.data(), &heap->data[a*heap->el_sz], heap->el_sz); - memcpy(&heap->data[a*heap->el_sz], &heap->data[b*heap->el_sz], heap->el_sz); - memcpy(&heap->data[b*heap->el_sz], tmp.data(), heap->el_sz); -} - -static inline void _swap_pointer(zmaxheap_t *heap, int a, int b) -{ - float t = heap->values[a]; - heap->values[a] = heap->values[b]; - heap->values[b] = t; - - void **pp = (void**) heap->data; - void *tmp = pp[a]; - pp[a] = pp[b]; - pp[b] = tmp; -} - - -zmaxheap_t *zmaxheap_create(size_t el_sz) -{ - zmaxheap_t *heap = (zmaxheap_t*)calloc(1, sizeof(zmaxheap_t)); - heap->el_sz = el_sz; - - heap->swap = _swap_default; - - if (el_sz == sizeof(void*)) - heap->swap = _swap_pointer; - - return heap; -} - -void zmaxheap_destroy(zmaxheap_t *heap) -{ - free(heap->values); - free(heap->data); - memset(heap, 0, sizeof(zmaxheap_t)); - free(heap); -} - -static void _zmaxheap_ensure_capacity(zmaxheap_t *heap, int capacity) -{ - if (heap->alloc >= capacity) - return; - - int newcap = heap->alloc; - - while (newcap < capacity) { - if (newcap < MIN_CAPACITY) { - newcap = MIN_CAPACITY; - continue; - } - - newcap *= 2; - } - - heap->values = (float*)realloc(heap->values, newcap * sizeof(float)); - heap->data = (char*)realloc(heap->data, newcap * heap->el_sz); - heap->alloc = newcap; -} - -void zmaxheap_add(zmaxheap_t *heap, void *p, float v) -{ - _zmaxheap_ensure_capacity(heap, heap->size + 1); - - int idx = heap->size; - - heap->values[idx] = v; - memcpy(&heap->data[idx*heap->el_sz], p, heap->el_sz); - - heap->size++; - - while (idx > 0) { - - int parent = (idx - 1) / 2; - - // we're done! - if (heap->values[parent] >= v) - break; - - // else, swap and recurse upwards. - heap->swap(heap, idx, parent); - idx = parent; - } -} - -// Removes the item in the heap at the given index. Returns 1 if the -// item existed. 0 Indicates an invalid idx (heap is smaller than -// idx). This is mostly intended to be used by zmaxheap_remove_max. -static int zmaxheap_remove_index(zmaxheap_t *heap, int idx, void *p, float *v) -{ - if (idx >= heap->size) - return 0; - - // copy out the requested element from the heap. - if (v != NULL) - *v = heap->values[idx]; - if (p != NULL) - memcpy(p, &heap->data[idx*heap->el_sz], heap->el_sz); - - heap->size--; - - // If this element is already the last one, then there's nothing - // for us to do. - if (idx == heap->size) - return 1; - - // copy last element to first element. (which probably upsets - // the heap property). - heap->values[idx] = heap->values[heap->size]; - memcpy(&heap->data[idx*heap->el_sz], &heap->data[heap->el_sz * heap->size], heap->el_sz); - - // now fix the heap. Note, as we descend, we're "pushing down" - // the same node the entire time. Thus, while the index of the - // parent might change, the parent_score doesn't. - int parent = idx; - float parent_score = heap->values[idx]; - - // descend, fixing the heap. - while (parent < heap->size) { - - int left = 2*parent + 1; - int right = left + 1; - -// assert(parent_score == heap->values[parent]); - - float left_score = (left < heap->size) ? heap->values[left] : -INFINITY; - float right_score = (right < heap->size) ? heap->values[right] : -INFINITY; - - // put the biggest of (parent, left, right) as the parent. - - // already okay? - if (parent_score >= left_score && parent_score >= right_score) - break; - - // if we got here, then one of the children is bigger than the parent. - if (left_score >= right_score) { - CV_Assert(left < heap->size); - heap->swap(heap, parent, left); - parent = left; - } else { - // right_score can't be less than left_score if right_score is -INFINITY. - CV_Assert(right < heap->size); - heap->swap(heap, parent, right); - parent = right; - } - } - - return 1; -} - -int zmaxheap_remove_max(zmaxheap_t *heap, void *p, float *v) -{ - return zmaxheap_remove_index(heap, 0, p, v); -} - -}} diff --git a/modules/aruco/src/apriltag/zmaxheap.hpp b/modules/aruco/src/apriltag/zmaxheap.hpp deleted file mode 100644 index 7055e512f68..00000000000 --- a/modules/aruco/src/apriltag/zmaxheap.hpp +++ /dev/null @@ -1,42 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. -// -// Copyright (C) 2013-2016, The Regents of The University of Michigan. -// -// This software was developed in the APRIL Robotics Lab under the -// direction of Edwin Olson, ebolson@umich.edu. This software may be -// available under alternative licensing terms; contact the address above. -// -// The views and conclusions contained in the software and documentation are those -// of the authors and should not be interpreted as representing official policies, -// either expressed or implied, of the Regents of The University of Michigan. -#ifndef _OPENCV_ZMAXHEAP_HPP_ -#define _OPENCV_ZMAXHEAP_HPP_ - -#include -#include -#include - -namespace cv { -namespace aruco { -typedef struct zmaxheap zmaxheap_t; - -typedef struct zmaxheap_iterator zmaxheap_iterator_t; -struct zmaxheap_iterator { - zmaxheap_t *heap; - int in, out; -}; - -zmaxheap_t *zmaxheap_create(size_t el_sz); - -void zmaxheap_destroy(zmaxheap_t *heap); - -void zmaxheap_add(zmaxheap_t *heap, void *p, float v); - -// returns 0 if the heap is empty, so you can do -// while (zmaxheap_remove_max(...)) { } -int zmaxheap_remove_max(zmaxheap_t *heap, void *p, float *v); - -}} -#endif diff --git a/modules/aruco/src/aruco.cpp b/modules/aruco/src/aruco.cpp index 92abb40ae83..3d43e94247f 100644 --- a/modules/aruco/src/aruco.cpp +++ b/modules/aruco/src/aruco.cpp @@ -2,7 +2,9 @@ // It is subject to the license terms in the LICENSE file found in the top-level directory // of this distribution and at http://opencv.org/license.html +#include "precomp.hpp" #include "opencv2/aruco.hpp" +#include namespace cv { namespace aruco { @@ -12,7 +14,7 @@ using namespace std; void detectMarkers(InputArray _image, const Ptr &_dictionary, OutputArrayOfArrays _corners, OutputArray _ids, const Ptr &_params, OutputArrayOfArrays _rejectedImgPoints) { - ArucoDetector detector(_dictionary, _params); + ArucoDetector detector(*_dictionary, *_params); detector.detectMarkers(_image, _corners, _ids, _rejectedImgPoints); } @@ -22,11 +24,158 @@ void refineDetectedMarkers(InputArray _image, const Ptr &_board, InputArray _distCoeffs, float minRepDistance, float errorCorrectionRate, bool checkAllOrders, OutputArray _recoveredIdxs, const Ptr &_params) { - Ptr refineParams = RefineParameters::create(minRepDistance, errorCorrectionRate, checkAllOrders); - ArucoDetector detector(_board->getDictionary(), _params, refineParams); - detector.refineDetectedMarkers(_image, _board, _detectedCorners, _detectedIds, _rejectedCorners, _cameraMatrix, + RefineParameters refineParams(minRepDistance, errorCorrectionRate, checkAllOrders); + ArucoDetector detector(_board->getDictionary(), *_params, refineParams); + detector.refineDetectedMarkers(_image, *_board, _detectedCorners, _detectedIds, _rejectedCorners, _cameraMatrix, _distCoeffs, _recoveredIdxs); } +void drawPlanarBoard(const Ptr &board, Size outSize, const _OutputArray &img, int marginSize, int borderBits) { + board->generateImage(outSize, img, marginSize, borderBits); +} + +void getBoardObjectAndImagePoints(const Ptr &board, InputArrayOfArrays detectedCorners, InputArray detectedIds, + OutputArray objPoints, OutputArray imgPoints) { + board->matchImagePoints(detectedCorners, detectedIds, objPoints, imgPoints); +} + +int estimatePoseBoard(InputArrayOfArrays corners, InputArray ids, const Ptr &board, + InputArray cameraMatrix, InputArray distCoeffs, InputOutputArray rvec, + InputOutputArray tvec, bool useExtrinsicGuess) { + CV_Assert(corners.total() == ids.total()); + + // get object and image points for the solvePnP function + Mat objPoints, imgPoints; + board->matchImagePoints(corners, ids, objPoints, imgPoints); + + CV_Assert(imgPoints.total() == objPoints.total()); + + if(objPoints.total() == 0) // 0 of the detected markers in board + return 0; + + solvePnP(objPoints, imgPoints, cameraMatrix, distCoeffs, rvec, tvec, useExtrinsicGuess); + + // divide by four since all the four corners are concatenated in the array for each marker + return (int)objPoints.total() / 4; +} + + +/** + * Check if a set of 3d points are enough for calibration. Z coordinate is ignored. + * Only axis parallel lines are considered + */ +static bool _arePointsEnoughForPoseEstimation(const vector &points) { + if(points.size() < 4) return false; + + vector sameXValue; // different x values in points + vector sameXCounter; // number of points with the x value in sameXValue + for(unsigned int i = 0; i < points.size(); i++) { + bool found = false; + for(unsigned int j = 0; j < sameXValue.size(); j++) { + if(sameXValue[j] == points[i].x) { + found = true; + sameXCounter[j]++; + } + } + if(!found) { + sameXValue.push_back(points[i].x); + sameXCounter.push_back(1); + } + } + + // count how many x values has more than 2 points + int moreThan2 = 0; + for(unsigned int i = 0; i < sameXCounter.size(); i++) { + if(sameXCounter[i] >= 2) moreThan2++; + } + + // if we have more than 1 two xvalues with more than 2 points, calibration is ok + if(moreThan2 > 1) + return true; + return false; +} + +bool estimatePoseCharucoBoard(InputArray charucoCorners, InputArray charucoIds, + const Ptr &board, InputArray cameraMatrix, + InputArray distCoeffs, InputOutputArray rvec, + InputOutputArray tvec, bool useExtrinsicGuess) { + CV_Assert((charucoCorners.getMat().total() == charucoIds.getMat().total())); + + // need, at least, 4 corners + if(charucoIds.getMat().total() < 4) return false; + + vector objPoints; + objPoints.reserve(charucoIds.getMat().total()); + for(unsigned int i = 0; i < charucoIds.getMat().total(); i++) { + int currId = charucoIds.getMat().at< int >(i); + CV_Assert(currId >= 0 && currId < (int)board->getChessboardCorners().size()); + objPoints.push_back(board->getChessboardCorners()[currId]); + } + + // points need to be in different lines, check if detected points are enough + if(!_arePointsEnoughForPoseEstimation(objPoints)) return false; + + solvePnP(objPoints, charucoCorners, cameraMatrix, distCoeffs, rvec, tvec, useExtrinsicGuess); + return true; +} + +bool testCharucoCornersCollinear(const Ptr &board, InputArray charucoIds) { + return board->checkCharucoCornersCollinear(charucoIds); +} + +/** + * @brief Return object points for the system centered in a middle (by default) or in a top left corner of single + * marker, given the marker length + */ +static Mat _getSingleMarkerObjectPoints(float markerLength, const EstimateParameters& estimateParameters) { + CV_Assert(markerLength > 0); + Mat objPoints(4, 1, CV_32FC3); + // set coordinate system in the top-left corner of the marker, with Z pointing out + if (estimateParameters.pattern == ARUCO_CW_TOP_LEFT_CORNER) { + objPoints.ptr(0)[0] = Vec3f(0.f, 0.f, 0); + objPoints.ptr(0)[1] = Vec3f(markerLength, 0.f, 0); + objPoints.ptr(0)[2] = Vec3f(markerLength, markerLength, 0); + objPoints.ptr(0)[3] = Vec3f(0.f, markerLength, 0); + } + else if (estimateParameters.pattern == ARUCO_CCW_CENTER) { + objPoints.ptr(0)[0] = Vec3f(-markerLength/2.f, markerLength/2.f, 0); + objPoints.ptr(0)[1] = Vec3f(markerLength/2.f, markerLength/2.f, 0); + objPoints.ptr(0)[2] = Vec3f(markerLength/2.f, -markerLength/2.f, 0); + objPoints.ptr(0)[3] = Vec3f(-markerLength/2.f, -markerLength/2.f, 0); + } + else + CV_Error(Error::StsBadArg, "Unknown estimateParameters pattern"); + return objPoints; +} + +void estimatePoseSingleMarkers(InputArrayOfArrays _corners, float markerLength, + InputArray _cameraMatrix, InputArray _distCoeffs, + OutputArray _rvecs, OutputArray _tvecs, OutputArray _objPoints, + const Ptr& estimateParameters) { + CV_Assert(markerLength > 0); + + Mat markerObjPoints = _getSingleMarkerObjectPoints(markerLength, *estimateParameters); + int nMarkers = (int)_corners.total(); + _rvecs.create(nMarkers, 1, CV_64FC3); + _tvecs.create(nMarkers, 1, CV_64FC3); + + Mat rvecs = _rvecs.getMat(), tvecs = _tvecs.getMat(); + + //// for each marker, calculate its pose + parallel_for_(Range(0, nMarkers), [&](const Range& range) { + const int begin = range.start; + const int end = range.end; + + for (int i = begin; i < end; i++) { + solvePnP(markerObjPoints, _corners.getMat(i), _cameraMatrix, _distCoeffs, rvecs.at(i), + tvecs.at(i), estimateParameters->useExtrinsicGuess, estimateParameters->solvePnPMethod); + } + }); + + if(_objPoints.needed()){ + markerObjPoints.convertTo(_objPoints, -1); + } +} + } } diff --git a/modules/aruco/src/aruco_calib.cpp b/modules/aruco/src/aruco_calib.cpp new file mode 100644 index 00000000000..7b6ff4ff9a9 --- /dev/null +++ b/modules/aruco/src/aruco_calib.cpp @@ -0,0 +1,98 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html + +#include +#include + +namespace cv { +namespace aruco { +using namespace std; + +EstimateParameters::EstimateParameters() : pattern(ARUCO_CCW_CENTER), useExtrinsicGuess(false), + solvePnPMethod(SOLVEPNP_ITERATIVE) {} + +double calibrateCameraAruco(InputArrayOfArrays _corners, InputArray _ids, InputArray _counter, + const Ptr &board, Size imageSize, InputOutputArray _cameraMatrix, + InputOutputArray _distCoeffs, OutputArrayOfArrays _rvecs, + OutputArrayOfArrays _tvecs, + OutputArray _stdDeviationsIntrinsics, + OutputArray _stdDeviationsExtrinsics, + OutputArray _perViewErrors, + int flags, const TermCriteria& criteria) { + // for each frame, get properly processed imagePoints and objectPoints for the calibrateCamera + // function + vector processedObjectPoints, processedImagePoints; + size_t nFrames = _counter.total(); + int markerCounter = 0; + for(size_t frame = 0; frame < nFrames; frame++) { + int nMarkersInThisFrame = _counter.getMat().ptr< int >()[frame]; + vector thisFrameCorners; + vector thisFrameIds; + + CV_Assert(nMarkersInThisFrame > 0); + + thisFrameCorners.reserve((size_t) nMarkersInThisFrame); + thisFrameIds.reserve((size_t) nMarkersInThisFrame); + for(int j = markerCounter; j < markerCounter + nMarkersInThisFrame; j++) { + thisFrameCorners.push_back(_corners.getMat(j)); + thisFrameIds.push_back(_ids.getMat().ptr< int >()[j]); + } + markerCounter += nMarkersInThisFrame; + Mat currentImgPoints, currentObjPoints; + board->matchImagePoints(thisFrameCorners, thisFrameIds, currentObjPoints, + currentImgPoints); + if(currentImgPoints.total() > 0 && currentObjPoints.total() > 0) { + processedImagePoints.push_back(currentImgPoints); + processedObjectPoints.push_back(currentObjPoints); + } + } + return calibrateCamera(processedObjectPoints, processedImagePoints, imageSize, _cameraMatrix, _distCoeffs, _rvecs, + _tvecs, _stdDeviationsIntrinsics, _stdDeviationsExtrinsics, _perViewErrors, flags, criteria); +} + +double calibrateCameraAruco(InputArrayOfArrays _corners, InputArray _ids, InputArray _counter, const Ptr &board, + Size imageSize, InputOutputArray _cameraMatrix, InputOutputArray _distCoeffs, + OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs, int flags, const TermCriteria& criteria) { + return calibrateCameraAruco(_corners, _ids, _counter, board, imageSize, _cameraMatrix, _distCoeffs, + _rvecs, _tvecs, noArray(), noArray(), noArray(), flags, criteria); +} + +double calibrateCameraCharuco(InputArrayOfArrays _charucoCorners, InputArrayOfArrays _charucoIds, + const Ptr &_board, Size imageSize, + InputOutputArray _cameraMatrix, InputOutputArray _distCoeffs, + OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs, + OutputArray _stdDeviationsIntrinsics, + OutputArray _stdDeviationsExtrinsics, + OutputArray _perViewErrors, + int flags, const TermCriteria& criteria) { + CV_Assert(_charucoIds.total() > 0 && (_charucoIds.total() == _charucoCorners.total())); + + // Join object points of charuco corners in a single vector for calibrateCamera() function + vector > allObjPoints; + allObjPoints.resize(_charucoIds.total()); + for(unsigned int i = 0; i < _charucoIds.total(); i++) { + unsigned int nCorners = (unsigned int)_charucoIds.getMat(i).total(); + CV_Assert(nCorners > 0 && nCorners == _charucoCorners.getMat(i).total()); + allObjPoints[i].reserve(nCorners); + + for(unsigned int j = 0; j < nCorners; j++) { + int pointId = _charucoIds.getMat(i).at< int >(j); + CV_Assert(pointId >= 0 && pointId < (int)_board->getChessboardCorners().size()); + allObjPoints[i].push_back(_board->getChessboardCorners()[pointId]); + } + } + return calibrateCamera(allObjPoints, _charucoCorners, imageSize, _cameraMatrix, _distCoeffs, _rvecs, _tvecs, + _stdDeviationsIntrinsics, _stdDeviationsExtrinsics, _perViewErrors, flags, criteria); +} + +double calibrateCameraCharuco(InputArrayOfArrays _charucoCorners, InputArrayOfArrays _charucoIds, + const Ptr &_board, Size imageSize, InputOutputArray _cameraMatrix, + InputOutputArray _distCoeffs, OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs, + int flags, const TermCriteria& criteria) { +return calibrateCameraCharuco(_charucoCorners, _charucoIds, _board, imageSize, _cameraMatrix, _distCoeffs, _rvecs, + _tvecs, noArray(), noArray(), noArray(), flags, criteria); +} + +} +} diff --git a/modules/aruco/src/aruco_calib_pose.cpp b/modules/aruco/src/aruco_calib_pose.cpp deleted file mode 100644 index 1290126d5c7..00000000000 --- a/modules/aruco/src/aruco_calib_pose.cpp +++ /dev/null @@ -1,257 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html - -#include - -namespace cv { -namespace aruco { -using namespace std; - -void getBoardObjectAndImagePoints(const Ptr &board, InputArrayOfArrays detectedCorners, InputArray detectedIds, - OutputArray objPoints, OutputArray imgPoints) { - CV_Assert(board->getIds().size() == board->getObjPoints().size()); - CV_Assert(detectedIds.total() == detectedCorners.total()); - - size_t nDetectedMarkers = detectedIds.total(); - - vector objPnts; - objPnts.reserve(nDetectedMarkers); - - vector imgPnts; - imgPnts.reserve(nDetectedMarkers); - - // look for detected markers that belong to the board and get their information - for(unsigned int i = 0; i < nDetectedMarkers; i++) { - int currentId = detectedIds.getMat().ptr< int >(0)[i]; - for(unsigned int j = 0; j < board->getIds().size(); j++) { - if(currentId == board->getIds()[j]) { - for(int p = 0; p < 4; p++) { - objPnts.push_back(board->getObjPoints()[j][p]); - imgPnts.push_back(detectedCorners.getMat(i).ptr< Point2f >(0)[p]); - } - } - } - } - - // create output - Mat(objPnts).copyTo(objPoints); - Mat(imgPnts).copyTo(imgPoints); -} - -/** - * @brief Return object points for the system centered in a middle (by default) or in a top left corner of single - * marker, given the marker length - */ -static Mat _getSingleMarkerObjectPoints(float markerLength, const EstimateParameters& estimateParameters) { - CV_Assert(markerLength > 0); - Mat objPoints(4, 1, CV_32FC3); - // set coordinate system in the top-left corner of the marker, with Z pointing out - if (estimateParameters.pattern == ARUCO_CW_TOP_LEFT_CORNER) { - objPoints.ptr(0)[0] = Vec3f(0.f, 0.f, 0); - objPoints.ptr(0)[1] = Vec3f(markerLength, 0.f, 0); - objPoints.ptr(0)[2] = Vec3f(markerLength, markerLength, 0); - objPoints.ptr(0)[3] = Vec3f(0.f, markerLength, 0); - } - else if (estimateParameters.pattern == ARUCO_CCW_CENTER) { - objPoints.ptr(0)[0] = Vec3f(-markerLength/2.f, markerLength/2.f, 0); - objPoints.ptr(0)[1] = Vec3f(markerLength/2.f, markerLength/2.f, 0); - objPoints.ptr(0)[2] = Vec3f(markerLength/2.f, -markerLength/2.f, 0); - objPoints.ptr(0)[3] = Vec3f(-markerLength/2.f, -markerLength/2.f, 0); - } - else - CV_Error(Error::StsBadArg, "Unknown estimateParameters pattern"); - return objPoints; -} - -void estimatePoseSingleMarkers(InputArrayOfArrays _corners, float markerLength, - InputArray _cameraMatrix, InputArray _distCoeffs, - OutputArray _rvecs, OutputArray _tvecs, OutputArray _objPoints, - const Ptr& estimateParameters) { - CV_Assert(markerLength > 0); - - Mat markerObjPoints = _getSingleMarkerObjectPoints(markerLength, *estimateParameters); - int nMarkers = (int)_corners.total(); - _rvecs.create(nMarkers, 1, CV_64FC3); - _tvecs.create(nMarkers, 1, CV_64FC3); - - Mat rvecs = _rvecs.getMat(), tvecs = _tvecs.getMat(); - - //// for each marker, calculate its pose - parallel_for_(Range(0, nMarkers), [&](const Range& range) { - const int begin = range.start; - const int end = range.end; - - for (int i = begin; i < end; i++) { - solvePnP(markerObjPoints, _corners.getMat(i), _cameraMatrix, _distCoeffs, rvecs.at(i), - tvecs.at(i), estimateParameters->useExtrinsicGuess, estimateParameters->solvePnPMethod); - } - }); - - if(_objPoints.needed()){ - markerObjPoints.convertTo(_objPoints, -1); - } -} - -int estimatePoseBoard(InputArrayOfArrays _corners, InputArray _ids, const Ptr &board, - InputArray _cameraMatrix, InputArray _distCoeffs, InputOutputArray _rvec, - InputOutputArray _tvec, bool useExtrinsicGuess) { - CV_Assert(_corners.total() == _ids.total()); - - // get object and image points for the solvePnP function - Mat objPoints, imgPoints; - getBoardObjectAndImagePoints(board, _corners, _ids, objPoints, imgPoints); - - CV_Assert(imgPoints.total() == objPoints.total()); - - if(objPoints.total() == 0) // 0 of the detected markers in board - return 0; - - solvePnP(objPoints, imgPoints, _cameraMatrix, _distCoeffs, _rvec, _tvec, useExtrinsicGuess); - - // divide by four since all the four corners are concatenated in the array for each marker - return (int)objPoints.total() / 4; -} - -/** - * Check if a set of 3d points are enough for calibration. Z coordinate is ignored. - * Only axis parallel lines are considered - */ -static bool _arePointsEnoughForPoseEstimation(const vector &points) { - if(points.size() < 4) return false; - - vector sameXValue; // different x values in points - vector sameXCounter; // number of points with the x value in sameXValue - for(unsigned int i = 0; i < points.size(); i++) { - bool found = false; - for(unsigned int j = 0; j < sameXValue.size(); j++) { - if(sameXValue[j] == points[i].x) { - found = true; - sameXCounter[j]++; - } - } - if(!found) { - sameXValue.push_back(points[i].x); - sameXCounter.push_back(1); - } - } - - // count how many x values has more than 2 points - int moreThan2 = 0; - for(unsigned int i = 0; i < sameXCounter.size(); i++) { - if(sameXCounter[i] >= 2) moreThan2++; - } - - // if we have more than 1 two xvalues with more than 2 points, calibration is ok - if(moreThan2 > 1) - return true; - return false; -} - -bool estimatePoseCharucoBoard(InputArray _charucoCorners, InputArray _charucoIds, - const Ptr &_board, InputArray _cameraMatrix, InputArray _distCoeffs, - InputOutputArray _rvec, InputOutputArray _tvec, bool useExtrinsicGuess) { - CV_Assert((_charucoCorners.getMat().total() == _charucoIds.getMat().total())); - - // need, at least, 4 corners - if(_charucoIds.getMat().total() < 4) return false; - - vector objPoints; - objPoints.reserve(_charucoIds.getMat().total()); - for(unsigned int i = 0; i < _charucoIds.getMat().total(); i++) { - int currId = _charucoIds.getMat().at< int >(i); - CV_Assert(currId >= 0 && currId < (int)_board->chessboardCorners.size()); - objPoints.push_back(_board->chessboardCorners[currId]); - } - - // points need to be in different lines, check if detected points are enough - if(!_arePointsEnoughForPoseEstimation(objPoints)) return false; - - solvePnP(objPoints, _charucoCorners, _cameraMatrix, _distCoeffs, _rvec, _tvec, useExtrinsicGuess); - return true; -} - -double calibrateCameraAruco(InputArrayOfArrays _corners, InputArray _ids, InputArray _counter, - const Ptr &board, Size imageSize, InputOutputArray _cameraMatrix, - InputOutputArray _distCoeffs, OutputArrayOfArrays _rvecs, - OutputArrayOfArrays _tvecs, - OutputArray _stdDeviationsIntrinsics, - OutputArray _stdDeviationsExtrinsics, - OutputArray _perViewErrors, - int flags, const TermCriteria& criteria) { - // for each frame, get properly processed imagePoints and objectPoints for the calibrateCamera - // function - vector processedObjectPoints, processedImagePoints; - size_t nFrames = _counter.total(); - int markerCounter = 0; - for(size_t frame = 0; frame < nFrames; frame++) { - int nMarkersInThisFrame = _counter.getMat().ptr< int >()[frame]; - vector thisFrameCorners; - vector thisFrameIds; - - CV_Assert(nMarkersInThisFrame > 0); - - thisFrameCorners.reserve((size_t) nMarkersInThisFrame); - thisFrameIds.reserve((size_t) nMarkersInThisFrame); - for(int j = markerCounter; j < markerCounter + nMarkersInThisFrame; j++) { - thisFrameCorners.push_back(_corners.getMat(j)); - thisFrameIds.push_back(_ids.getMat().ptr< int >()[j]); - } - markerCounter += nMarkersInThisFrame; - Mat currentImgPoints, currentObjPoints; - getBoardObjectAndImagePoints(board, thisFrameCorners, thisFrameIds, currentObjPoints, - currentImgPoints); - if(currentImgPoints.total() > 0 && currentObjPoints.total() > 0) { - processedImagePoints.push_back(currentImgPoints); - processedObjectPoints.push_back(currentObjPoints); - } - } - return calibrateCamera(processedObjectPoints, processedImagePoints, imageSize, _cameraMatrix, _distCoeffs, _rvecs, - _tvecs, _stdDeviationsIntrinsics, _stdDeviationsExtrinsics, _perViewErrors, flags, criteria); -} - -double calibrateCameraAruco(InputArrayOfArrays _corners, InputArray _ids, InputArray _counter, const Ptr &board, - Size imageSize, InputOutputArray _cameraMatrix, InputOutputArray _distCoeffs, - OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs, int flags, const TermCriteria& criteria) { - return calibrateCameraAruco(_corners, _ids, _counter, board, imageSize, _cameraMatrix, _distCoeffs, - _rvecs, _tvecs, noArray(), noArray(), noArray(), flags, criteria); -} - -double calibrateCameraCharuco(InputArrayOfArrays _charucoCorners, InputArrayOfArrays _charucoIds, - const Ptr &_board, Size imageSize, - InputOutputArray _cameraMatrix, InputOutputArray _distCoeffs, - OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs, - OutputArray _stdDeviationsIntrinsics, - OutputArray _stdDeviationsExtrinsics, - OutputArray _perViewErrors, - int flags, const TermCriteria& criteria) { - CV_Assert(_charucoIds.total() > 0 && (_charucoIds.total() == _charucoCorners.total())); - - // Join object points of charuco corners in a single vector for calibrateCamera() function - vector > allObjPoints; - allObjPoints.resize(_charucoIds.total()); - for(unsigned int i = 0; i < _charucoIds.total(); i++) { - unsigned int nCorners = (unsigned int)_charucoIds.getMat(i).total(); - CV_Assert(nCorners > 0 && nCorners == _charucoCorners.getMat(i).total()); - allObjPoints[i].reserve(nCorners); - - for(unsigned int j = 0; j < nCorners; j++) { - int pointId = _charucoIds.getMat(i).at< int >(j); - CV_Assert(pointId >= 0 && pointId < (int)_board->chessboardCorners.size()); - allObjPoints[i].push_back(_board->chessboardCorners[pointId]); - } - } - return calibrateCamera(allObjPoints, _charucoCorners, imageSize, _cameraMatrix, _distCoeffs, _rvecs, _tvecs, - _stdDeviationsIntrinsics, _stdDeviationsExtrinsics, _perViewErrors, flags, criteria); -} - -double calibrateCameraCharuco(InputArrayOfArrays _charucoCorners, InputArrayOfArrays _charucoIds, - const Ptr &_board, Size imageSize, InputOutputArray _cameraMatrix, - InputOutputArray _distCoeffs, OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs, - int flags, const TermCriteria& criteria) { -return calibrateCameraCharuco(_charucoCorners, _charucoIds, _board, imageSize, _cameraMatrix, _distCoeffs, _rvecs, - _tvecs, noArray(), noArray(), noArray(), flags, criteria); -} - -} -} diff --git a/modules/aruco/src/aruco_detector.cpp b/modules/aruco/src/aruco_detector.cpp deleted file mode 100644 index 45f7cc101b8..00000000000 --- a/modules/aruco/src/aruco_detector.cpp +++ /dev/null @@ -1,1261 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html - -#include "precomp.hpp" -#include -#include "opencv2/aruco_detector.hpp" -#include "opencv2/aruco/aruco_calib_pose.hpp" -#include "aruco_utils.hpp" -#include "apriltag/apriltag_quad_thresh.hpp" -#include - -namespace cv { -namespace aruco { - -using namespace std; - -static inline bool readWrite(DetectorParameters ¶ms, const Ptr& readNode = nullptr, - const Ptr& writeStorage = nullptr) { - CV_Assert(!readNode.empty() || !writeStorage.empty()); - bool check = false; - - check |= readWriteParameter("adaptiveThreshWinSizeMin", params.adaptiveThreshWinSizeMin, readNode, writeStorage); - check |= readWriteParameter("adaptiveThreshWinSizeMax", params.adaptiveThreshWinSizeMax, readNode, writeStorage); - check |= readWriteParameter("adaptiveThreshWinSizeStep", params.adaptiveThreshWinSizeStep, readNode, writeStorage); - check |= readWriteParameter("adaptiveThreshConstant", params.adaptiveThreshConstant, readNode, writeStorage); - check |= readWriteParameter("minMarkerPerimeterRate", params.minMarkerPerimeterRate, readNode, writeStorage); - check |= readWriteParameter("maxMarkerPerimeterRate", params.maxMarkerPerimeterRate, readNode, writeStorage); - check |= readWriteParameter("polygonalApproxAccuracyRate", params.polygonalApproxAccuracyRate, - readNode, writeStorage); - check |= readWriteParameter("minCornerDistanceRate", params.minCornerDistanceRate, readNode, writeStorage); - check |= readWriteParameter("minDistanceToBorder", params.minDistanceToBorder, readNode, writeStorage); - check |= readWriteParameter("minMarkerDistanceRate", params.minMarkerDistanceRate, readNode, writeStorage); - check |= readWriteParameter("cornerRefinementMethod", params.cornerRefinementMethod, readNode, writeStorage); - check |= readWriteParameter("cornerRefinementWinSize", params.cornerRefinementWinSize, readNode, writeStorage); - check |= readWriteParameter("cornerRefinementMaxIterations", params.cornerRefinementMaxIterations, - readNode, writeStorage); - check |= readWriteParameter("cornerRefinementMinAccuracy", params.cornerRefinementMinAccuracy, - readNode, writeStorage); - check |= readWriteParameter("markerBorderBits", params.markerBorderBits, readNode, writeStorage); - check |= readWriteParameter("perspectiveRemovePixelPerCell", params.perspectiveRemovePixelPerCell, - readNode, writeStorage); - check |= readWriteParameter("perspectiveRemoveIgnoredMarginPerCell", params.perspectiveRemoveIgnoredMarginPerCell, - readNode, writeStorage); - check |= readWriteParameter("maxErroneousBitsInBorderRate", params.maxErroneousBitsInBorderRate, - readNode, writeStorage); - check |= readWriteParameter("minOtsuStdDev", params.minOtsuStdDev, readNode, writeStorage); - check |= readWriteParameter("errorCorrectionRate", params.errorCorrectionRate, readNode, writeStorage); - // new aruco 3 functionality - check |= readWriteParameter("useAruco3Detection", params.useAruco3Detection, readNode, writeStorage); - check |= readWriteParameter("minSideLengthCanonicalImg", params.minSideLengthCanonicalImg, readNode, writeStorage); - check |= readWriteParameter("minMarkerLengthRatioOriginalImg", params.minMarkerLengthRatioOriginalImg, - readNode, writeStorage); - return check; -} - -bool DetectorParameters::readDetectorParameters(const FileNode& fn) { - if(fn.empty()) - return false; - Ptr pfn = makePtr(fn); - return readWrite(*this, pfn); -} - -bool DetectorParameters::writeDetectorParameters(const Ptr& fs) -{ - if (fs.empty() && !fs->isOpened()) - return false; - return readWrite(*this, nullptr, fs); -} - -static inline bool readWrite(RefineParameters& refineParameters, const Ptr& readNode, - const Ptr& writeStorage = nullptr) { - CV_Assert(!readNode.empty() || !writeStorage.empty()); - bool check = false; - - check |= readWriteParameter("minRepDistance", refineParameters.minRepDistance, readNode, writeStorage); - check |= readWriteParameter("errorCorrectionRate", refineParameters.errorCorrectionRate, readNode, writeStorage); - check |= readWriteParameter("checkAllOrders", refineParameters.checkAllOrders, readNode, writeStorage); - return check; -} - -bool RefineParameters::readRefineParameters(const FileNode &fn) { - if(fn.empty()) - return false; - Ptr pfn = makePtr(fn); - return readWrite(*this, pfn); -} - -bool RefineParameters::writeRefineParameters(const Ptr &fs) { - if(fs.empty()) - return false; - return readWrite(*this, nullptr, fs); -} - -/** - * @brief Threshold input image using adaptive thresholding - */ -static void _threshold(InputArray _in, OutputArray _out, int winSize, double constant) { - - CV_Assert(winSize >= 3); - if(winSize % 2 == 0) winSize++; // win size must be odd - adaptiveThreshold(_in, _out, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, winSize, constant); -} - - -/** - * @brief Given a tresholded image, find the contours, calculate their polygonal approximation - * and take those that accomplish some conditions - */ -static void _findMarkerContours(const Mat &in, vector< vector< Point2f > > &candidates, - vector< vector< Point > > &contoursOut, double minPerimeterRate, - double maxPerimeterRate, double accuracyRate, - double minCornerDistanceRate, int minDistanceToBorder, int minSize) { - - CV_Assert(minPerimeterRate > 0 && maxPerimeterRate > 0 && accuracyRate > 0 && - minCornerDistanceRate >= 0 && minDistanceToBorder >= 0); - - // calculate maximum and minimum sizes in pixels - unsigned int minPerimeterPixels = - (unsigned int)(minPerimeterRate * max(in.cols, in.rows)); - unsigned int maxPerimeterPixels = - (unsigned int)(maxPerimeterRate * max(in.cols, in.rows)); - - // for aruco3 functionality - if (minSize != 0) { - minPerimeterPixels = 4*minSize; - } - - Mat contoursImg; - in.copyTo(contoursImg); - vector< vector< Point > > contours; - findContours(contoursImg, contours, RETR_LIST, CHAIN_APPROX_NONE); - // now filter list of contours - for(unsigned int i = 0; i < contours.size(); i++) { - // check perimeter - if(contours[i].size() < minPerimeterPixels || contours[i].size() > maxPerimeterPixels) - continue; - - // check is square and is convex - vector< Point > approxCurve; - approxPolyDP(contours[i], approxCurve, double(contours[i].size()) * accuracyRate, true); - if(approxCurve.size() != 4 || !isContourConvex(approxCurve)) continue; - - // check min distance between corners - double minDistSq = - max(contoursImg.cols, contoursImg.rows) * max(contoursImg.cols, contoursImg.rows); - for(int j = 0; j < 4; j++) { - double d = (double)(approxCurve[j].x - approxCurve[(j + 1) % 4].x) * - (double)(approxCurve[j].x - approxCurve[(j + 1) % 4].x) + - (double)(approxCurve[j].y - approxCurve[(j + 1) % 4].y) * - (double)(approxCurve[j].y - approxCurve[(j + 1) % 4].y); - minDistSq = min(minDistSq, d); - } - double minCornerDistancePixels = double(contours[i].size()) * minCornerDistanceRate; - if(minDistSq < minCornerDistancePixels * minCornerDistancePixels) continue; - - // check if it is too near to the image border - bool tooNearBorder = false; - for(int j = 0; j < 4; j++) { - if(approxCurve[j].x < minDistanceToBorder || approxCurve[j].y < minDistanceToBorder || - approxCurve[j].x > contoursImg.cols - 1 - minDistanceToBorder || - approxCurve[j].y > contoursImg.rows - 1 - minDistanceToBorder) - tooNearBorder = true; - } - if(tooNearBorder) continue; - - // if it passes all the test, add to candidates vector - vector< Point2f > currentCandidate; - currentCandidate.resize(4); - for(int j = 0; j < 4; j++) { - currentCandidate[j] = Point2f((float)approxCurve[j].x, (float)approxCurve[j].y); - } - candidates.push_back(currentCandidate); - contoursOut.push_back(contours[i]); - } -} - - -/** - * @brief Assure order of candidate corners is clockwise direction - */ -static void _reorderCandidatesCorners(vector< vector< Point2f > > &candidates) { - - for(unsigned int i = 0; i < candidates.size(); i++) { - double dx1 = candidates[i][1].x - candidates[i][0].x; - double dy1 = candidates[i][1].y - candidates[i][0].y; - double dx2 = candidates[i][2].x - candidates[i][0].x; - double dy2 = candidates[i][2].y - candidates[i][0].y; - double crossProduct = (dx1 * dy2) - (dy1 * dx2); - - if(crossProduct < 0.0) { // not clockwise direction - swap(candidates[i][1], candidates[i][3]); - } - } -} - -/** - * @brief to make sure that the corner's order of both candidates (default/white) is the same - */ -static vector alignContourOrder(Point2f corner, vector< Point2f > candidate) { - uint8_t r=0; - double min = cv::norm( Vec2f( corner - candidate[0] ), NORM_L2SQR); - for(uint8_t pos=1; pos < 4; pos++) { - double nDiff = cv::norm( Vec2f( corner - candidate[pos] ), NORM_L2SQR); - if(nDiff < min){ - r = pos; - min =nDiff; - } - } - std::rotate(candidate.begin(), candidate.begin() + r, candidate.end()); - return candidate; -} - -/** - * @brief Check candidates that are too close to each other, save the potential candidates - * (i.e. biggest/smallest contour) and remove the rest - */ -static void _filterTooCloseCandidates(const vector< vector< Point2f > > &candidatesIn, - vector< vector< vector< Point2f > > > &candidatesSetOut, - const vector< vector< Point > > &contoursIn, - vector< vector< vector< Point > > > &contoursSetOut, - double minMarkerDistanceRate, bool detectInvertedMarker) { - - CV_Assert(minMarkerDistanceRate >= 0); - vector candGroup; - candGroup.resize(candidatesIn.size(), -1); - vector< vector > groupedCandidates; - for(unsigned int i = 0; i < candidatesIn.size(); i++) { - bool isSingleContour = true; - for(unsigned int j = i + 1; j < candidatesIn.size(); j++) { - - int minimumPerimeter = min((int)contoursIn[i].size(), (int)contoursIn[j].size() ); - - // fc is the first corner considered on one of the markers, 4 combinations are possible - for(int fc = 0; fc < 4; fc++) { - double distSq = 0; - for(int c = 0; c < 4; c++) { - // modC is the corner considering first corner is fc - int modC = (c + fc) % 4; - distSq += (candidatesIn[i][modC].x - candidatesIn[j][c].x) * - (candidatesIn[i][modC].x - candidatesIn[j][c].x) + - (candidatesIn[i][modC].y - candidatesIn[j][c].y) * - (candidatesIn[i][modC].y - candidatesIn[j][c].y); - } - distSq /= 4.; - - // if mean square distance is too low, remove the smaller one of the two markers - double minMarkerDistancePixels = double(minimumPerimeter) * minMarkerDistanceRate; - if(distSq < minMarkerDistancePixels * minMarkerDistancePixels) { - isSingleContour = false; - // i and j are not related to a group - if(candGroup[i]<0 && candGroup[j]<0){ - // mark candidates with their corresponding group number - candGroup[i] = candGroup[j] = (int)groupedCandidates.size(); - - // create group - vector grouped; - grouped.push_back(i); - grouped.push_back(j); - groupedCandidates.push_back( grouped ); - } - // i is related to a group - else if(candGroup[i] > -1 && candGroup[j] == -1){ - int group = candGroup[i]; - candGroup[j] = group; - - // add to group - groupedCandidates[group].push_back( j ); - } - // j is related to a group - else if(candGroup[j] > -1 && candGroup[i] == -1){ - int group = candGroup[j]; - candGroup[i] = group; - - // add to group - groupedCandidates[group].push_back( i ); - } - } - } - } - if (isSingleContour && candGroup[i] < 0) - { - candGroup[i] = (int)groupedCandidates.size(); - vector grouped; - grouped.push_back(i); - grouped.push_back(i); // step "save possible candidates" require minimum 2 elements - groupedCandidates.push_back(grouped); - } - } - - // save possible candidates - candidatesSetOut.clear(); - contoursSetOut.clear(); - - vector< vector< Point2f > > biggerCandidates; - vector< vector< Point > > biggerContours; - vector< vector< Point2f > > smallerCandidates; - vector< vector< Point > > smallerContours; - - // save possible candidates - for(unsigned int i = 0; i < groupedCandidates.size(); i++) { - unsigned int smallerIdx = groupedCandidates[i][0]; - unsigned int biggerIdx = smallerIdx; - double smallerArea = contourArea(candidatesIn[smallerIdx]); - double biggerArea = smallerArea; - - // evaluate group elements - for(unsigned int j = 1; j < groupedCandidates[i].size(); j++) { - unsigned int currIdx = groupedCandidates[i][j]; - double currArea = contourArea(candidatesIn[currIdx]); - - // check if current contour is bigger - if(currArea >= biggerArea) { - biggerIdx = currIdx; - biggerArea = currArea; - } - - // check if current contour is smaller - if(currArea < smallerArea && detectInvertedMarker) { - smallerIdx = currIdx; - smallerArea = currArea; - } - } - - // add contours and candidates - biggerCandidates.push_back(candidatesIn[biggerIdx]); - biggerContours.push_back(contoursIn[biggerIdx]); - if(detectInvertedMarker) { - smallerCandidates.push_back(alignContourOrder(candidatesIn[biggerIdx][0], candidatesIn[smallerIdx])); - smallerContours.push_back(contoursIn[smallerIdx]); - } - } - // to preserve the structure :: candidateSet< defaultCandidates, whiteCandidates > - // default candidates - candidatesSetOut.push_back(biggerCandidates); - contoursSetOut.push_back(biggerContours); - // white candidates - candidatesSetOut.push_back(smallerCandidates); - contoursSetOut.push_back(smallerContours); -} - -/** - * @brief Initial steps on finding square candidates - */ -static void _detectInitialCandidates(const Mat &grey, vector< vector< Point2f > > &candidates, - vector< vector< Point > > &contours, - const Ptr ¶ms) { - - CV_Assert(params->adaptiveThreshWinSizeMin >= 3 && params->adaptiveThreshWinSizeMax >= 3); - CV_Assert(params->adaptiveThreshWinSizeMax >= params->adaptiveThreshWinSizeMin); - CV_Assert(params->adaptiveThreshWinSizeStep > 0); - - // number of window sizes (scales) to apply adaptive thresholding - int nScales = (params->adaptiveThreshWinSizeMax - params->adaptiveThreshWinSizeMin) / - params->adaptiveThreshWinSizeStep + 1; - - vector< vector< vector< Point2f > > > candidatesArrays((size_t) nScales); - vector< vector< vector< Point > > > contoursArrays((size_t) nScales); - - ////for each value in the interval of thresholding window sizes - parallel_for_(Range(0, nScales), [&](const Range& range) { - const int begin = range.start; - const int end = range.end; - - for (int i = begin; i < end; i++) { - int currScale = params->adaptiveThreshWinSizeMin + i * params->adaptiveThreshWinSizeStep; - // threshold - Mat thresh; - _threshold(grey, thresh, currScale, params->adaptiveThreshConstant); - - // detect rectangles - _findMarkerContours(thresh, candidatesArrays[i], contoursArrays[i], - params->minMarkerPerimeterRate, params->maxMarkerPerimeterRate, - params->polygonalApproxAccuracyRate, params->minCornerDistanceRate, - params->minDistanceToBorder, params->minSideLengthCanonicalImg); - } - }); - // join candidates - for(int i = 0; i < nScales; i++) { - for(unsigned int j = 0; j < candidatesArrays[i].size(); j++) { - candidates.push_back(candidatesArrays[i][j]); - contours.push_back(contoursArrays[i][j]); - } - } -} - - -/** - * @brief Detect square candidates in the input image - */ -static void _detectCandidates(InputArray _grayImage, vector< vector< vector< Point2f > > >& candidatesSetOut, - vector< vector< vector< Point > > >& contoursSetOut, const Ptr &_params) { - Mat grey = _grayImage.getMat(); - CV_DbgAssert(grey.total() != 0); - CV_DbgAssert(grey.type() == CV_8UC1); - - /// 1. DETECT FIRST SET OF CANDIDATES - vector< vector< Point2f > > candidates; - vector< vector< Point > > contours; - _detectInitialCandidates(grey, candidates, contours, _params); - /// 2. SORT CORNERS - _reorderCandidatesCorners(candidates); - - /// 3. FILTER OUT NEAR CANDIDATE PAIRS - // save the outter/inner border (i.e. potential candidates) - _filterTooCloseCandidates(candidates, candidatesSetOut, contours, contoursSetOut, - _params->minMarkerDistanceRate, _params->detectInvertedMarker); -} - - -/** - * @brief Given an input image and candidate corners, extract the bits of the candidate, including - * the border bits - */ -static Mat _extractBits(InputArray _image, const vector& corners, int markerSize, - int markerBorderBits, int cellSize, double cellMarginRate, double minStdDevOtsu) { - CV_Assert(_image.getMat().channels() == 1); - CV_Assert(corners.size() == 4ull); - CV_Assert(markerBorderBits > 0 && cellSize > 0 && cellMarginRate >= 0 && cellMarginRate <= 1); - CV_Assert(minStdDevOtsu >= 0); - - // number of bits in the marker - int markerSizeWithBorders = markerSize + 2 * markerBorderBits; - int cellMarginPixels = int(cellMarginRate * cellSize); - - Mat resultImg; // marker image after removing perspective - int resultImgSize = markerSizeWithBorders * cellSize; - Mat resultImgCorners(4, 1, CV_32FC2); - resultImgCorners.ptr< Point2f >(0)[0] = Point2f(0, 0); - resultImgCorners.ptr< Point2f >(0)[1] = Point2f((float)resultImgSize - 1, 0); - resultImgCorners.ptr< Point2f >(0)[2] = - Point2f((float)resultImgSize - 1, (float)resultImgSize - 1); - resultImgCorners.ptr< Point2f >(0)[3] = Point2f(0, (float)resultImgSize - 1); - - // remove perspective - Mat transformation = getPerspectiveTransform(corners, resultImgCorners); - warpPerspective(_image, resultImg, transformation, Size(resultImgSize, resultImgSize), - INTER_NEAREST); - - // output image containing the bits - Mat bits(markerSizeWithBorders, markerSizeWithBorders, CV_8UC1, Scalar::all(0)); - - // check if standard deviation is enough to apply Otsu - // if not enough, it probably means all bits are the same color (black or white) - Mat mean, stddev; - // Remove some border just to avoid border noise from perspective transformation - Mat innerRegion = resultImg.colRange(cellSize / 2, resultImg.cols - cellSize / 2) - .rowRange(cellSize / 2, resultImg.rows - cellSize / 2); - meanStdDev(innerRegion, mean, stddev); - if(stddev.ptr< double >(0)[0] < minStdDevOtsu) { - // all black or all white, depending on mean value - if(mean.ptr< double >(0)[0] > 127) - bits.setTo(1); - else - bits.setTo(0); - return bits; - } - - // now extract code, first threshold using Otsu - threshold(resultImg, resultImg, 125, 255, THRESH_BINARY | THRESH_OTSU); - - // for each cell - for(int y = 0; y < markerSizeWithBorders; y++) { - for(int x = 0; x < markerSizeWithBorders; x++) { - int Xstart = x * (cellSize) + cellMarginPixels; - int Ystart = y * (cellSize) + cellMarginPixels; - Mat square = resultImg(Rect(Xstart, Ystart, cellSize - 2 * cellMarginPixels, - cellSize - 2 * cellMarginPixels)); - // count white pixels on each cell to assign its value - size_t nZ = (size_t) countNonZero(square); - if(nZ > square.total() / 2) bits.at< unsigned char >(y, x) = 1; - } - } - - return bits; -} - - - -/** - * @brief Return number of erroneous bits in border, i.e. number of white bits in border. - */ -static int _getBorderErrors(const Mat &bits, int markerSize, int borderSize) { - - int sizeWithBorders = markerSize + 2 * borderSize; - - CV_Assert(markerSize > 0 && bits.cols == sizeWithBorders && bits.rows == sizeWithBorders); - - int totalErrors = 0; - for(int y = 0; y < sizeWithBorders; y++) { - for(int k = 0; k < borderSize; k++) { - if(bits.ptr< unsigned char >(y)[k] != 0) totalErrors++; - if(bits.ptr< unsigned char >(y)[sizeWithBorders - 1 - k] != 0) totalErrors++; - } - } - for(int x = borderSize; x < sizeWithBorders - borderSize; x++) { - for(int k = 0; k < borderSize; k++) { - if(bits.ptr< unsigned char >(k)[x] != 0) totalErrors++; - if(bits.ptr< unsigned char >(sizeWithBorders - 1 - k)[x] != 0) totalErrors++; - } - } - return totalErrors; -} - - -/** - * @brief Tries to identify one candidate given the dictionary - * @return candidate typ. zero if the candidate is not valid, - * 1 if the candidate is a black candidate (default candidate) - * 2 if the candidate is a white candidate - */ -static uint8_t _identifyOneCandidate(const Ptr& dictionary, InputArray _image, - const vector& _corners, int& idx, - const Ptr& params, int& rotation, - const float scale = 1.f) { - CV_DbgAssert(_corners.size() == 4); - CV_DbgAssert(_image.getMat().total() != 0); - CV_DbgAssert(params->markerBorderBits > 0); - uint8_t typ=1; - // get bits - // scale corners to the correct size to search on the corresponding image pyramid - vector scaled_corners(4); - for (int i = 0; i < 4; ++i) { - scaled_corners[i].x = _corners[i].x * scale; - scaled_corners[i].y = _corners[i].y * scale; - } - - Mat candidateBits = - _extractBits(_image, scaled_corners, dictionary->markerSize, params->markerBorderBits, - params->perspectiveRemovePixelPerCell, - params->perspectiveRemoveIgnoredMarginPerCell, params->minOtsuStdDev); - - // analyze border bits - int maximumErrorsInBorder = - int(dictionary->markerSize * dictionary->markerSize * params->maxErroneousBitsInBorderRate); - int borderErrors = - _getBorderErrors(candidateBits, dictionary->markerSize, params->markerBorderBits); - - // check if it is a white marker - if(params->detectInvertedMarker){ - // to get from 255 to 1 - Mat invertedImg = ~candidateBits-254; - int invBError = _getBorderErrors(invertedImg, dictionary->markerSize, params->markerBorderBits); - // white marker - if(invBError maximumErrorsInBorder) return 0; // border is wrong - - // take only inner bits - Mat onlyBits = - candidateBits.rowRange(params->markerBorderBits, - candidateBits.rows - params->markerBorderBits) - .colRange(params->markerBorderBits, candidateBits.cols - params->markerBorderBits); - - // try to indentify the marker - if(!dictionary->identify(onlyBits, idx, rotation, params->errorCorrectionRate)) - return 0; - - return typ; -} - -/** - * @brief rotate the initial corner to get to the right position - */ -static void correctCornerPosition( vector< Point2f >& _candidate, int rotate){ - std::rotate(_candidate.begin(), _candidate.begin() + 4 - rotate, _candidate.end()); -} - -static size_t _findOptPyrImageForCanonicalImg( - const std::vector& img_pyr, - const int scaled_width, - const int cur_perimeter, - const int min_perimeter) { - CV_Assert(scaled_width > 0); - size_t optLevel = 0; - float dist = std::numeric_limits::max(); - for (size_t i = 0; i < img_pyr.size(); ++i) { - const float scale = img_pyr[i].cols / static_cast(scaled_width); - const float perimeter_scaled = cur_perimeter * scale; - // instead of std::abs() favor the larger pyramid level by checking if the distance is postive - // will slow down the algorithm but find more corners in the end - const float new_dist = perimeter_scaled - min_perimeter; - if (new_dist < dist && new_dist > 0.f) { - dist = new_dist; - optLevel = i; - } - } - return optLevel; -} - -/** - * @brief Identify square candidates according to a marker dictionary - */ - -static void _identifyCandidates(InputArray grey, - const std::vector& image_pyr, - vector< vector< vector< Point2f > > >& _candidatesSet, - vector< vector< vector > >& _contoursSet, const Ptr &_dictionary, - vector< vector< Point2f > >& _accepted, vector< vector >& _contours, vector< int >& ids, - const Ptr ¶ms, - OutputArrayOfArrays _rejected = noArray()) { - CV_DbgAssert(grey.getMat().total() != 0); - CV_DbgAssert(grey.getMat().type() == CV_8UC1); - int ncandidates = (int)_candidatesSet[0].size(); - vector< vector< Point2f > > accepted; - vector< vector< Point2f > > rejected; - vector< vector< Point > > contours; - - vector< int > idsTmp(ncandidates, -1); - vector< int > rotated(ncandidates, 0); - vector< uint8_t > validCandidates(ncandidates, 0); - - //// Analyze each of the candidates - parallel_for_(Range(0, ncandidates), [&](const Range &range) { - const int begin = range.start; - const int end = range.end; - - vector< vector< Point2f > >& candidates = params->detectInvertedMarker ? _candidatesSet[1] : _candidatesSet[0]; - vector< vector< Point > >& contourS = params->detectInvertedMarker ? _contoursSet[1] : _contoursSet[0]; - - for(int i = begin; i < end; i++) { - int currId = -1; - // implements equation (4) - if (params->useAruco3Detection) { - const int perimeterOfContour = static_cast(contourS[i].size()); - const int min_perimeter = params->minSideLengthCanonicalImg * 4; - const size_t nearestImgId = _findOptPyrImageForCanonicalImg(image_pyr, grey.cols(), perimeterOfContour, min_perimeter); - const float scale = image_pyr[nearestImgId].cols / static_cast(grey.cols()); - - validCandidates[i] = _identifyOneCandidate(_dictionary, image_pyr[nearestImgId], candidates[i], currId, params, rotated[i], scale); - } - else { - validCandidates[i] = _identifyOneCandidate(_dictionary, grey, candidates[i], currId, params, rotated[i]); - } - - if(validCandidates[i] > 0) - idsTmp[i] = currId; - } - }); - - for(int i = 0; i < ncandidates; i++) { - if(validCandidates[i] > 0) { - // to choose the right set of candidates :: 0 for default, 1 for white markers - uint8_t set = validCandidates[i]-1; - - // shift corner positions to the correct rotation - correctCornerPosition(_candidatesSet[set][i], rotated[i]); - - if( !params->detectInvertedMarker && validCandidates[i] == 2 ) - continue; - - // add valid candidate - accepted.push_back(_candidatesSet[set][i]); - ids.push_back(idsTmp[i]); - - contours.push_back(_contoursSet[set][i]); - - } else { - rejected.push_back(_candidatesSet[0][i]); - } - } - - // parse output - _accepted = accepted; - - _contours= contours; - - if(_rejected.needed()) { - _copyVector2Output(rejected, _rejected); - } -} - -/** - * Line fitting A * B = C :: Called from function refineCandidateLines - * @param nContours, contour-container - */ -static Point3f _interpolate2Dline(const std::vector& nContours){ - CV_Assert(nContours.size() >= 2); - float minX, minY, maxX, maxY; - minX = maxX = nContours[0].x; - minY = maxY = nContours[0].y; - - for(unsigned int i = 0; i< nContours.size(); i++){ - minX = nContours[i].x < minX ? nContours[i].x : minX; - minY = nContours[i].y < minY ? nContours[i].y : minY; - maxX = nContours[i].x > maxX ? nContours[i].x : maxX; - maxY = nContours[i].y > maxY ? nContours[i].y : maxY; - } - - Mat A = Mat::ones((int)nContours.size(), 2, CV_32F); // Coefficient Matrix (N x 2) - Mat B((int)nContours.size(), 1, CV_32F); // Variables Matrix (N x 1) - Mat C; // Constant - - if(maxX - minX > maxY - minY){ - for(unsigned int i =0; i < nContours.size(); i++){ - A.at(i,0)= nContours[i].x; - B.at(i,0)= nContours[i].y; - } - - solve(A, B, C, DECOMP_NORMAL); - - return Point3f(C.at(0, 0), -1., C.at(1, 0)); - } - else{ - for(unsigned int i =0; i < nContours.size(); i++){ - A.at(i,0)= nContours[i].y; - B.at(i,0)= nContours[i].x; - } - - solve(A, B, C, DECOMP_NORMAL); - - return Point3f(-1., C.at(0, 0), C.at(1, 0)); - } - -} - -/** - * Find the Point where the lines crosses :: Called from function refineCandidateLines - * @param nLine1 - * @param nLine2 - * @return Crossed Point - */ -static Point2f _getCrossPoint(Point3f nLine1, Point3f nLine2){ - Matx22f A(nLine1.x, nLine1.y, nLine2.x, nLine2.y); - Vec2f B(-nLine1.z, -nLine2.z); - return Vec2f(A.solve(B).val); -} - -/** - * Refine Corners using the contour vector :: Called from function detectMarkers - * @param nContours, contour-container - * @param nCorners, candidate Corners - * @param camMatrix, cameraMatrix input 3x3 floating-point camera matrix - * @param distCoeff, distCoeffs vector of distortion coefficient - */ -static void _refineCandidateLines(std::vector& nContours, std::vector& nCorners){ - vector contour2f(nContours.begin(), nContours.end()); - /* 5 groups :: to group the edges - * 4 - classified by its corner - * extra group - (temporary) if contours do not begin with a corner - */ - vector cntPts[5]; - int cornerIndex[4]={-1}; - int group=4; - - for ( unsigned int i =0; i < nContours.size(); i++ ) { - for(unsigned int j=0; j<4; j++){ - if ( nCorners[j] == contour2f[i] ){ - cornerIndex[j] = i; - group=j; - } - } - cntPts[group].push_back(contour2f[i]); - } - for (int i = 0; i < 4; i++) - { - CV_Assert(cornerIndex[i] != -1); - } - // saves extra group into corresponding - if( !cntPts[4].empty() ){ - for( unsigned int i=0; i < cntPts[4].size() ; i++ ) - cntPts[group].push_back(cntPts[4].at(i)); - cntPts[4].clear(); - } - - //Evaluate contour direction :: using the position of the detected corners - int inc=1; - - inc = ( (cornerIndex[0] > cornerIndex[1]) && (cornerIndex[3] > cornerIndex[0]) ) ? -1:inc; - inc = ( (cornerIndex[2] > cornerIndex[3]) && (cornerIndex[1] > cornerIndex[2]) ) ? -1:inc; - - // calculate the line :: who passes through the grouped points - Point3f lines[4]; - for(int i=0; i<4; i++){ - lines[i]=_interpolate2Dline(cntPts[i]); - } - - /* - * calculate the corner :: where the lines crosses to each other - * clockwise direction no clockwise direction - * 0 1 - * .---. 1 .---. 2 - * | | | | - * 3 .___. 0 .___. - * 2 3 - */ - for(int i=0; i < 4; i++){ - if(inc<0) - nCorners[i] = _getCrossPoint(lines[ i ], lines[ (i+1)%4 ]); // 01 12 23 30 - else - nCorners[i] = _getCrossPoint(lines[ i ], lines[ (i+3)%4 ]); // 30 01 12 23 - } -} - -static inline void findCornerInPyrImage(const float scale_init, const int closest_pyr_image_idx, - const std::vector& grey_pyramid, Mat corners, - const Ptr& params) { - // scale them to the closest pyramid level - if (scale_init != 1.f) - corners *= scale_init; // scale_init * scale_pyr - for (int idx = closest_pyr_image_idx - 1; idx >= 0; --idx) { - // scale them to new pyramid level - corners *= 2.f; // *= scale_pyr; - // use larger win size for larger images - const int subpix_win_size = std::max(grey_pyramid[idx].cols, grey_pyramid[idx].rows) > 1080 ? 5 : 3; - cornerSubPix(grey_pyramid[idx], corners, - Size(subpix_win_size, subpix_win_size), - Size(-1, -1), - TermCriteria(TermCriteria::MAX_ITER | TermCriteria::EPS, - params->cornerRefinementMaxIterations, - params->cornerRefinementMinAccuracy)); - } -} - -void ArucoDetector::detectMarkers(InputArray _image, OutputArrayOfArrays _corners, OutputArray _ids, - OutputArrayOfArrays _rejectedImgPoints) { - CV_Assert(!_image.empty()); - CV_Assert(params->markerBorderBits > 0); - // check that the parameters are set correctly if Aruco3 is used - CV_Assert(!(params->useAruco3Detection == true && - params->minSideLengthCanonicalImg == 0 && - params->minMarkerLengthRatioOriginalImg == 0.0)); - - Mat grey; - _convertToGrey(_image.getMat(), grey); - - // Aruco3 functionality is the extension of Aruco. - // The description can be found in: - // [1] Speeded up detection of squared fiducial markers, 2018, FJ Romera-Ramirez et al. - // if Aruco3 functionality if not wanted - // change some parameters to be sure to turn it off - if (!params->useAruco3Detection) { - params->minMarkerLengthRatioOriginalImg = 0.0; - params->minSideLengthCanonicalImg = 0; - } - else { - // always turn on corner refinement in case of Aruco3, due to upsampling - params->cornerRefinementMethod = CORNER_REFINE_SUBPIX; - // only CORNER_REFINE_SUBPIX implement correctly for useAruco3Detection - // Todo: update other CORNER_REFINE methods - } - - /// Step 0: equation (2) from paper [1] - const float fxfy = (!params->useAruco3Detection ? 1.f : params->minSideLengthCanonicalImg / - (params->minSideLengthCanonicalImg + std::max(grey.cols, grey.rows)*params->minMarkerLengthRatioOriginalImg)); - - /// Step 1: create image pyramid. Section 3.4. in [1] - std::vector grey_pyramid; - int closest_pyr_image_idx = 0, num_levels = 0; - //// Step 1.1: resize image with equation (1) from paper [1] - if (params->useAruco3Detection) { - const float scale_pyr = 2.f; - const float img_area = static_cast(grey.rows*grey.cols); - const float min_area_marker = static_cast(params->minSideLengthCanonicalImg*params->minSideLengthCanonicalImg); - // find max level - num_levels = static_cast(log2(img_area / min_area_marker)/scale_pyr); - // the closest pyramid image to the downsampled segmentation image - // will later be used as start index for corner upsampling - const float scale_img_area = img_area * fxfy * fxfy; - closest_pyr_image_idx = cvRound(log2(img_area / scale_img_area)/scale_pyr); - } - cv::buildPyramid(grey, grey_pyramid, num_levels); - - // resize to segmentation image - // in this reduces size the contours will be detected - if (fxfy != 1.f) - cv::resize(grey, grey, cv::Size(cvRound(fxfy * grey.cols), cvRound(fxfy * grey.rows))); - - /// STEP 2: Detect marker candidates - vector< vector< Point2f > > candidates; - vector< vector< Point > > contours; - vector< int > ids; - - vector< vector< vector< Point2f > > > candidatesSet; - vector< vector< vector< Point > > > contoursSet; - - /// STEP 2.a Detect marker candidates :: using AprilTag - if(params->cornerRefinementMethod == CORNER_REFINE_APRILTAG){ - _apriltag(grey, params, candidates, contours); - - candidatesSet.push_back(candidates); - contoursSet.push_back(contours); - } - /// STEP 2.b Detect marker candidates :: traditional way - else - _detectCandidates(grey, candidatesSet, contoursSet, params); - - /// STEP 2: Check candidate codification (identify markers) - _identifyCandidates(grey, grey_pyramid, candidatesSet, contoursSet, dictionary, - candidates, contours, ids, params, _rejectedImgPoints); - - /// STEP 3: Corner refinement :: use corner subpix - if( params->cornerRefinementMethod == CORNER_REFINE_SUBPIX ) { - CV_Assert(params->cornerRefinementWinSize > 0 && params->cornerRefinementMaxIterations > 0 && - params->cornerRefinementMinAccuracy > 0); - // Do subpixel estimation. In Aruco3 start on the lowest pyramid level and upscale the corners - parallel_for_(Range(0, (int)candidates.size()), [&](const Range& range) { - const int begin = range.start; - const int end = range.end; - - for (int i = begin; i < end; i++) { - if (params->useAruco3Detection) { - const float scale_init = (float) grey_pyramid[closest_pyr_image_idx].cols / grey.cols; - findCornerInPyrImage(scale_init, closest_pyr_image_idx, grey_pyramid, Mat(candidates[i]), params); - } - else - cornerSubPix(grey, Mat(candidates[i]), - Size(params->cornerRefinementWinSize, params->cornerRefinementWinSize), - Size(-1, -1), - TermCriteria(TermCriteria::MAX_ITER | TermCriteria::EPS, - params->cornerRefinementMaxIterations, - params->cornerRefinementMinAccuracy)); - } - }); - } - - /// STEP 3, Optional : Corner refinement :: use contour container - if( params->cornerRefinementMethod == CORNER_REFINE_CONTOUR){ - - if(! _ids.empty()){ - - // do corner refinement using the contours for each detected markers - parallel_for_(Range(0, (int)candidates.size()), [&](const Range& range) { - for (int i = range.start; i < range.end; i++) { - _refineCandidateLines(contours[i], candidates[i]); - } - }); - } - } - - if (params->cornerRefinementMethod != CORNER_REFINE_SUBPIX && fxfy != 1.f) { - // only CORNER_REFINE_SUBPIX implement correctly for useAruco3Detection - // Todo: update other CORNER_REFINE methods - - // scale to orignal size, this however will lead to inaccurate detections! - for (auto &vecPoints : candidates) - for (auto &point : vecPoints) - point *= 1.f/fxfy; - } - - // copy to output arrays - _copyVector2Output(candidates, _corners); - Mat(ids).copyTo(_ids); -} - -/** - * Project board markers that are not included in the list of detected markers - */ -static void _projectUndetectedMarkers(const Ptr &_board, InputOutputArrayOfArrays _detectedCorners, - InputOutputArray _detectedIds, InputArray _cameraMatrix, InputArray _distCoeffs, - vector >& _undetectedMarkersProjectedCorners, - OutputArray _undetectedMarkersIds) { - // first estimate board pose with the current avaible markers - Mat rvec, tvec; - int boardDetectedMarkers = aruco::estimatePoseBoard(_detectedCorners, _detectedIds, _board, - _cameraMatrix, _distCoeffs, rvec, tvec); - - // at least one marker from board so rvec and tvec are valid - if(boardDetectedMarkers == 0) return; - - // search undetected markers and project them using the previous pose - vector > undetectedCorners; - vector undetectedIds; - for(unsigned int i = 0; i < _board->getIds().size(); i++) { - int foundIdx = -1; - for(unsigned int j = 0; j < _detectedIds.total(); j++) { - if(_board->getIds()[i] == _detectedIds.getMat().ptr< int >()[j]) { - foundIdx = j; - break; - } - } - - // not detected - if(foundIdx == -1) { - undetectedCorners.push_back(vector()); - undetectedIds.push_back(_board->getIds()[i]); - projectPoints(_board->getObjPoints()[i], rvec, tvec, _cameraMatrix, _distCoeffs, - undetectedCorners.back()); - } - } - // parse output - Mat(undetectedIds).copyTo(_undetectedMarkersIds); - _undetectedMarkersProjectedCorners = undetectedCorners; -} - -/** - * Interpolate board markers that are not included in the list of detected markers using - * global homography - */ -static void _projectUndetectedMarkers(const Ptr &_board, InputOutputArrayOfArrays _detectedCorners, - InputOutputArray _detectedIds, - vector >& _undetectedMarkersProjectedCorners, - OutputArray _undetectedMarkersIds) { - // check board points are in the same plane, if not, global homography cannot be applied - CV_Assert(_board->getObjPoints().size() > 0); - CV_Assert(_board->getObjPoints()[0].size() > 0); - float boardZ = _board->getObjPoints()[0][0].z; - for(unsigned int i = 0; i < _board->getObjPoints().size(); i++) { - for(unsigned int j = 0; j < _board->getObjPoints()[i].size(); j++) - CV_Assert(boardZ == _board->getObjPoints()[i][j].z); - } - - vector detectedMarkersObj2DAll; // Object coordinates (without Z) of all the detected - // marker corners in a single vector - vector imageCornersAll; // Image corners of all detected markers in a single vector - vector > undetectedMarkersObj2D; // Object coordinates (without Z) of all - // missing markers in different vectors - vector undetectedMarkersIds; // ids of missing markers - // find markers included in board, and missing markers from board. Fill the previous vectors - for(unsigned int j = 0; j < _board->getIds().size(); j++) { - bool found = false; - for(unsigned int i = 0; i < _detectedIds.total(); i++) { - if(_detectedIds.getMat().ptr< int >()[i] == _board->getIds()[j]) { - for(int c = 0; c < 4; c++) { - imageCornersAll.push_back(_detectedCorners.getMat(i).ptr< Point2f >()[c]); - detectedMarkersObj2DAll.push_back( - Point2f(_board->getObjPoints()[j][c].x, _board->getObjPoints()[j][c].y)); - } - found = true; - break; - } - } - if(!found) { - undetectedMarkersObj2D.push_back(vector()); - for(int c = 0; c < 4; c++) { - undetectedMarkersObj2D.back().push_back( - Point2f(_board->getObjPoints()[j][c].x, _board->getObjPoints()[j][c].y)); - } - undetectedMarkersIds.push_back(_board->getIds()[j]); - } - } - if(imageCornersAll.size() == 0) return; - - // get homography from detected markers - Mat transformation = findHomography(detectedMarkersObj2DAll, imageCornersAll); - - _undetectedMarkersProjectedCorners.resize(undetectedMarkersIds.size()); - - // for each undetected marker, apply transformation - for(unsigned int i = 0; i < undetectedMarkersObj2D.size(); i++) { - perspectiveTransform(undetectedMarkersObj2D[i], _undetectedMarkersProjectedCorners[i], transformation); - } - Mat(undetectedMarkersIds).copyTo(_undetectedMarkersIds); -} - - -void ArucoDetector::refineDetectedMarkers(InputArray _image, const Ptr &_board, - InputOutputArrayOfArrays _detectedCorners, InputOutputArray _detectedIds, - InputOutputArrayOfArrays _rejectedCorners, InputArray _cameraMatrix, - InputArray _distCoeffs, OutputArray _recoveredIdxs) { - CV_Assert(refineParams->minRepDistance > 0); - - if(_detectedIds.total() == 0 || _rejectedCorners.total() == 0) return; - - // get projections of missing markers in the board - vector< vector< Point2f > > undetectedMarkersCorners; - vector< int > undetectedMarkersIds; - if(_cameraMatrix.total() != 0) { - // reproject based on camera projection model - _projectUndetectedMarkers(_board, _detectedCorners, _detectedIds, _cameraMatrix, _distCoeffs, - undetectedMarkersCorners, undetectedMarkersIds); - - } else { - // reproject based on global homography - _projectUndetectedMarkers(_board, _detectedCorners, _detectedIds, undetectedMarkersCorners, - undetectedMarkersIds); - } - - // list of missing markers indicating if they have been assigned to a candidate - vector< bool > alreadyIdentified(_rejectedCorners.total(), false); - - // maximum bits that can be corrected - int maxCorrectionRecalculated = - int(double(dictionary->maxCorrectionBits) * refineParams->errorCorrectionRate); - - Mat grey; - _convertToGrey(_image, grey); - - // vector of final detected marker corners and ids - vector > finalAcceptedCorners; - vector< int > finalAcceptedIds; - // fill with the current markers - finalAcceptedCorners.resize(_detectedCorners.total()); - finalAcceptedIds.resize(_detectedIds.total()); - for(unsigned int i = 0; i < _detectedIds.total(); i++) { - finalAcceptedCorners[i] = _detectedCorners.getMat(i).clone(); - finalAcceptedIds[i] = _detectedIds.getMat().ptr< int >()[i]; - } - vector< int > recoveredIdxs; // original indexes of accepted markers in _rejectedCorners - - // for each missing marker, try to find a correspondence - for(unsigned int i = 0; i < undetectedMarkersIds.size(); i++) { - - // best match at the moment - int closestCandidateIdx = -1; - double closestCandidateDistance = refineParams->minRepDistance * refineParams->minRepDistance + 1; - Mat closestRotatedMarker; - - for(unsigned int j = 0; j < _rejectedCorners.total(); j++) { - if(alreadyIdentified[j]) continue; - - // check distance - double minDistance = closestCandidateDistance + 1; - bool valid = false; - int validRot = 0; - for(int c = 0; c < 4; c++) { // first corner in rejected candidate - double currentMaxDistance = 0; - for(int k = 0; k < 4; k++) { - Point2f rejCorner = _rejectedCorners.getMat(j).ptr< Point2f >()[(c + k) % 4]; - Point2f distVector = undetectedMarkersCorners[i][k] - rejCorner; - double cornerDist = distVector.x * distVector.x + distVector.y * distVector.y; - currentMaxDistance = max(currentMaxDistance, cornerDist); - } - // if distance is better than current best distance - if(currentMaxDistance < closestCandidateDistance) { - valid = true; - validRot = c; - minDistance = currentMaxDistance; - } - if(!refineParams->checkAllOrders) break; - } - - if(!valid) continue; - - // apply rotation - Mat rotatedMarker; - if(refineParams->checkAllOrders) { - rotatedMarker = Mat(4, 1, CV_32FC2); - for(int c = 0; c < 4; c++) - rotatedMarker.ptr< Point2f >()[c] = - _rejectedCorners.getMat(j).ptr< Point2f >()[(c + 4 + validRot) % 4]; - } - else rotatedMarker = _rejectedCorners.getMat(j); - - // last filter, check if inner code is close enough to the assigned marker code - int codeDistance = 0; - // if errorCorrectionRate, dont check code - if(refineParams->errorCorrectionRate >= 0) { - - // extract bits - Mat bits = _extractBits( - grey, rotatedMarker, dictionary->markerSize, params->markerBorderBits, - params->perspectiveRemovePixelPerCell, - params->perspectiveRemoveIgnoredMarginPerCell, params->minOtsuStdDev); - - Mat onlyBits = - bits.rowRange(params->markerBorderBits, bits.rows - params->markerBorderBits) - .colRange(params->markerBorderBits, bits.rows - params->markerBorderBits); - - codeDistance = - dictionary->getDistanceToId(onlyBits, undetectedMarkersIds[i], false); - } - - // if everythin is ok, assign values to current best match - if(refineParams->errorCorrectionRate < 0 || codeDistance < maxCorrectionRecalculated) { - closestCandidateIdx = j; - closestCandidateDistance = minDistance; - closestRotatedMarker = rotatedMarker; - } - } - - // if at least one good match, we have rescue the missing marker - if(closestCandidateIdx >= 0) { - - // subpixel refinement - if(params->cornerRefinementMethod == CORNER_REFINE_SUBPIX) { - CV_Assert(params->cornerRefinementWinSize > 0 && - params->cornerRefinementMaxIterations > 0 && - params->cornerRefinementMinAccuracy > 0); - cornerSubPix(grey, closestRotatedMarker, - Size(params->cornerRefinementWinSize, params->cornerRefinementWinSize), - Size(-1, -1), TermCriteria(TermCriteria::MAX_ITER | TermCriteria::EPS, - params->cornerRefinementMaxIterations, - params->cornerRefinementMinAccuracy)); - } - - // remove from rejected - alreadyIdentified[closestCandidateIdx] = true; - - // add to detected - finalAcceptedCorners.push_back(closestRotatedMarker); - finalAcceptedIds.push_back(undetectedMarkersIds[i]); - - // add the original index of the candidate - recoveredIdxs.push_back(closestCandidateIdx); - } - } - - // parse output - if(finalAcceptedIds.size() != _detectedIds.total()) { - // parse output - Mat(finalAcceptedIds).copyTo(_detectedIds); - _copyVector2Output(finalAcceptedCorners, _detectedCorners); - - // recalculate _rejectedCorners based on alreadyIdentified - vector > finalRejected; - for(unsigned int i = 0; i < alreadyIdentified.size(); i++) { - if(!alreadyIdentified[i]) { - finalRejected.push_back(_rejectedCorners.getMat(i).clone()); - } - } - _copyVector2Output(finalRejected, _rejectedCorners); - - if(_recoveredIdxs.needed()) { - Mat(recoveredIdxs).copyTo(_recoveredIdxs); - } - } -} - - -void drawDetectedMarkers(InputOutputArray _image, InputArrayOfArrays _corners, - InputArray _ids, Scalar borderColor) { - CV_Assert(_image.getMat().total() != 0 && - (_image.getMat().channels() == 1 || _image.getMat().channels() == 3)); - CV_Assert((_corners.total() == _ids.total()) || _ids.total() == 0); - - // calculate colors - Scalar textColor, cornerColor; - textColor = cornerColor = borderColor; - swap(textColor.val[0], textColor.val[1]); // text color just sawp G and R - swap(cornerColor.val[1], cornerColor.val[2]); // corner color just sawp G and B - - int nMarkers = (int)_corners.total(); - for(int i = 0; i < nMarkers; i++) { - Mat currentMarker = _corners.getMat(i); - CV_Assert(currentMarker.total() == 4 && currentMarker.type() == CV_32FC2); - - // draw marker sides - for(int j = 0; j < 4; j++) { - Point2f p0, p1; - p0 = currentMarker.ptr< Point2f >(0)[j]; - p1 = currentMarker.ptr< Point2f >(0)[(j + 1) % 4]; - line(_image, p0, p1, borderColor, 1); - } - // draw first corner mark - rectangle(_image, currentMarker.ptr< Point2f >(0)[0] - Point2f(3, 3), - currentMarker.ptr< Point2f >(0)[0] + Point2f(3, 3), cornerColor, 1, LINE_AA); - - // draw ID - if(_ids.total() != 0) { - Point2f cent(0, 0); - for(int p = 0; p < 4; p++) - cent += currentMarker.ptr< Point2f >(0)[p]; - cent = cent / 4.; - stringstream s; - s << "id=" << _ids.getMat().ptr< int >(0)[i]; - putText(_image, s.str(), cent, FONT_HERSHEY_SIMPLEX, 0.5, textColor, 2); - } - } -} - -void drawMarker(const Ptr &dictionary, int id, int sidePixels, OutputArray _img, int borderBits) { - dictionary->drawMarker(id, sidePixels, _img, borderBits); -} - -} -} diff --git a/modules/aruco/src/aruco_utils.cpp b/modules/aruco/src/aruco_utils.cpp deleted file mode 100644 index 8d680848caa..00000000000 --- a/modules/aruco/src/aruco_utils.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html - -#include "aruco_utils.hpp" -#include - -namespace cv { -namespace aruco { -using namespace std; - -void _copyVector2Output(std::vector > &vec, OutputArrayOfArrays out, const float scale) { - out.create((int)vec.size(), 1, CV_32FC2); - if(out.isMatVector()) { - for (unsigned int i = 0; i < vec.size(); i++) { - out.create(4, 1, CV_32FC2, i); - Mat &m = out.getMatRef(i); - Mat(Mat(vec[i]).t()*scale).copyTo(m); - } - } - else if(out.isUMatVector()) { - for (unsigned int i = 0; i < vec.size(); i++) { - out.create(4, 1, CV_32FC2, i); - UMat &m = out.getUMatRef(i); - Mat(Mat(vec[i]).t()*scale).copyTo(m); - } - } - else if(out.kind() == _OutputArray::STD_VECTOR_VECTOR){ - for (unsigned int i = 0; i < vec.size(); i++) { - out.create(4, 1, CV_32FC2, i); - Mat m = out.getMat(i); - Mat(Mat(vec[i]).t()*scale).copyTo(m); - } - } - else { - CV_Error(cv::Error::StsNotImplemented, - "Only Mat vector, UMat vector, and vector OutputArrays are currently supported."); - } -} - -void _convertToGrey(InputArray _in, OutputArray _out) { - CV_Assert(_in.type() == CV_8UC1 || _in.type() == CV_8UC3); - if(_in.type() == CV_8UC3) - cvtColor(_in, _out, COLOR_BGR2GRAY); - else - _in.copyTo(_out); -} - -} -} diff --git a/modules/aruco/src/aruco_utils.hpp b/modules/aruco/src/aruco_utils.hpp deleted file mode 100644 index 029cd3fa81d..00000000000 --- a/modules/aruco/src/aruco_utils.hpp +++ /dev/null @@ -1,44 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html -#ifndef __OPENCV_ARUCO_UTILS_HPP__ -#define __OPENCV_ARUCO_UTILS_HPP__ - -#include -#include - -namespace cv { -namespace aruco { - -/** - * @brief Copy the contents of a corners vector to an OutputArray, settings its size. - */ -void _copyVector2Output(std::vector > &vec, OutputArrayOfArrays out, const float scale = 1.f); - -/** - * @brief Convert input image to gray if it is a 3-channels image - */ -void _convertToGrey(InputArray _in, OutputArray _out); - -template -inline bool readParameter(const std::string& name, T& parameter, const FileNode& node) -{ - if (!node.empty() && !node[name].empty()) { - node[name] >> parameter; - return true; - } - return false; -} - -template -inline bool readWriteParameter(const std::string& name, T& parameter, const Ptr readNode = nullptr, - const Ptr writeStorage = nullptr) { - if (!readNode.empty()) - return readParameter(name, parameter, *readNode); - *writeStorage << name << parameter; - return true; -} - -} -} -#endif diff --git a/modules/aruco/src/board.cpp b/modules/aruco/src/board.cpp deleted file mode 100644 index 53352f35f58..00000000000 --- a/modules/aruco/src/board.cpp +++ /dev/null @@ -1,467 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html - -#include -#include -#include - -namespace cv { -namespace aruco { -using namespace std; - -/** @brief Implementation of drawPlanarBoard that accepts a raw Board pointer. - */ -static void _drawPlanarBoardImpl(Board *_board, Size outSize, OutputArray _img, int marginSize, int borderBits) { - CV_Assert(!outSize.empty()); - CV_Assert(marginSize >= 0); - - _img.create(outSize, CV_8UC1); - Mat out = _img.getMat(); - out.setTo(Scalar::all(255)); - out.adjustROI(-marginSize, -marginSize, -marginSize, -marginSize); - - // calculate max and min values in XY plane - CV_Assert(_board->getObjPoints().size() > 0); - float minX, maxX, minY, maxY; - minX = maxX = _board->getObjPoints()[0][0].x; - minY = maxY = _board->getObjPoints()[0][0].y; - - for(unsigned int i = 0; i < _board->getObjPoints().size(); i++) { - for(int j = 0; j < 4; j++) { - minX = min(minX, _board->getObjPoints()[i][j].x); - maxX = max(maxX, _board->getObjPoints()[i][j].x); - minY = min(minY, _board->getObjPoints()[i][j].y); - maxY = max(maxY, _board->getObjPoints()[i][j].y); - } - } - - float sizeX = maxX - minX; - float sizeY = maxY - minY; - - // proportion transformations - float xReduction = sizeX / float(out.cols); - float yReduction = sizeY / float(out.rows); - - // determine the zone where the markers are placed - if(xReduction > yReduction) { - int nRows = int(sizeY / xReduction); - int rowsMargins = (out.rows - nRows) / 2; - out.adjustROI(-rowsMargins, -rowsMargins, 0, 0); - } else { - int nCols = int(sizeX / yReduction); - int colsMargins = (out.cols - nCols) / 2; - out.adjustROI(0, 0, -colsMargins, -colsMargins); - } - - // now paint each marker - Dictionary &dictionary = *(_board->getDictionary()); - Mat marker; - Point2f outCorners[3]; - Point2f inCorners[3]; - for(unsigned int m = 0; m < _board->getObjPoints().size(); m++) { - // transform corners to markerZone coordinates - for(int j = 0; j < 3; j++) { - Point2f pf = Point2f(_board->getObjPoints()[m][j].x, _board->getObjPoints()[m][j].y); - // move top left to 0, 0 - pf -= Point2f(minX, minY); - pf.x = pf.x / sizeX * float(out.cols); - pf.y = pf.y / sizeY * float(out.rows); - outCorners[j] = pf; - } - - // get marker - Size dst_sz(outCorners[2] - outCorners[0]); // assuming CCW order - dst_sz.width = dst_sz.height = std::min(dst_sz.width, dst_sz.height); //marker should be square - dictionary.drawMarker(_board->getIds()[m], dst_sz.width, marker, borderBits); - - if((outCorners[0].y == outCorners[1].y) && (outCorners[1].x == outCorners[2].x)) { - // marker is aligned to image axes - marker.copyTo(out(Rect(outCorners[0], dst_sz))); - continue; - } - - // interpolate tiny marker to marker position in markerZone - inCorners[0] = Point2f(-0.5f, -0.5f); - inCorners[1] = Point2f(marker.cols - 0.5f, -0.5f); - inCorners[2] = Point2f(marker.cols - 0.5f, marker.rows - 0.5f); - - // remove perspective - Mat transformation = getAffineTransform(inCorners, outCorners); - warpAffine(marker, out, transformation, out.size(), INTER_LINEAR, - BORDER_TRANSPARENT); - } -} - -void drawPlanarBoard(const Ptr &_board, Size outSize, OutputArray _img, int marginSize, - int borderBits) { - _drawPlanarBoardImpl(_board, outSize, _img, marginSize, borderBits); -} - -struct GridBoard::GridImpl { - GridImpl(){}; - // number of markers in X and Y directions - int sizeX = 3, sizeY = 3; - - // marker side length (normally in meters) - float markerLength = 1.f; - - // separation between markers in the grid - float markerSeparation = .5f; -}; - -GridBoard::GridBoard(): gridImpl(makePtr()) {} - -Board::Board(): dictionary(makePtr(getPredefinedDictionary(PREDEFINED_DICTIONARY_NAME::DICT_4X4_50))) {} - -Ptr Board::create(InputArrayOfArrays objPoints, const Ptr &dictionary, InputArray ids) { - CV_Assert(objPoints.total() == ids.total()); - CV_Assert(objPoints.type() == CV_32FC3 || objPoints.type() == CV_32FC1); - - std::vector > obj_points_vector; - Point3f rightBottomBorder = Point3f(0.f, 0.f, 0.f); - for (unsigned int i = 0; i < objPoints.total(); i++) { - std::vector corners; - Mat corners_mat = objPoints.getMat(i); - - if (corners_mat.type() == CV_32FC1) - corners_mat = corners_mat.reshape(3); - CV_Assert(corners_mat.total() == 4); - - for (int j = 0; j < 4; j++) { - const Point3f &corner = corners_mat.at(j); - corners.push_back(corner); - rightBottomBorder.x = std::max(rightBottomBorder.x, corner.x); - rightBottomBorder.y = std::max(rightBottomBorder.y, corner.y); - rightBottomBorder.z = std::max(rightBottomBorder.z, corner.z); - } - obj_points_vector.push_back(corners); - } - Ptr res = makePtr(); - ids.copyTo(res->ids); - res->objPoints = obj_points_vector; - res->dictionary = cv::makePtr(dictionary); - res->rightBottomBorder = rightBottomBorder; - return res; -} - -void Board::setIds(InputArray ids_) { - CV_Assert(objPoints.size() == ids_.total()); - ids_.copyTo(this->ids); -} - -Ptr Board::getDictionary() const { - return this->dictionary; -} - -void Board::setDictionary(const Ptr &_dictionary) { - this->dictionary = _dictionary; -} - -const std::vector >& Board::getObjPoints() const { - return this->objPoints; -} - -void Board::setObjPoints(const vector> &_objPoints) { - CV_Assert(!_objPoints.empty()); - this->objPoints = _objPoints; - rightBottomBorder = _objPoints.front().front(); - for (size_t i = 0; i < this->objPoints.size(); i++) { - for (int j = 0; j < 4; j++) { - const Point3f &corner = this->objPoints[i][j]; - rightBottomBorder.x = std::max(rightBottomBorder.x, corner.x); - rightBottomBorder.y = std::max(rightBottomBorder.y, corner.y); - rightBottomBorder.z = std::max(rightBottomBorder.z, corner.z); - } - } -} - -const Point3f& Board::getRightBottomBorder() const { - return this->rightBottomBorder; -} - -const std::vector& Board::getIds() const { - return this->ids; -} - -void Board::changeId(int index, int newId) { - CV_Assert(index >= 0 && index < (int)ids.size()); - CV_Assert(newId >= 0 && newId < dictionary->bytesList.rows); - this->ids[index] = newId; -} - -Ptr GridBoard::create(int markersX, int markersY, float markerLength, float markerSeparation, - const Ptr &dictionary, int firstMarker) { - CV_Assert(markersX > 0 && markersY > 0 && markerLength > 0 && markerSeparation > 0); - Ptr res = makePtr(); - res->gridImpl->sizeX = markersX; - res->gridImpl->sizeY = markersY; - res->gridImpl->markerLength = markerLength; - res->gridImpl->markerSeparation = markerSeparation; - res->setDictionary(dictionary); - - size_t totalMarkers = (size_t) markersX * markersY; - res->ids.resize(totalMarkers); - std::vector > objPoints; - objPoints.reserve(totalMarkers); - - // fill ids with first identifiers - for (unsigned int i = 0; i < totalMarkers; i++) { - res->ids[i] = i + firstMarker; - } - - // calculate Board objPoints - for (int y = 0; y < markersY; y++) { - for (int x = 0; x < markersX; x++) { - vector corners(4); - corners[0] = Point3f(x * (markerLength + markerSeparation), - y * (markerLength + markerSeparation), 0); - corners[1] = corners[0] + Point3f(markerLength, 0, 0); - corners[2] = corners[0] + Point3f(markerLength, markerLength, 0); - corners[3] = corners[0] + Point3f(0, markerLength, 0); - objPoints.push_back(corners); - } - } - res->setObjPoints(objPoints); - res->rightBottomBorder = Point3f(markersX * markerLength + markerSeparation * (markersX - 1), - markersY * markerLength + markerSeparation * (markersY - 1), 0.f); - return res; -} - -void GridBoard::draw(Size outSize, OutputArray _img, int marginSize, int borderBits) { - _drawPlanarBoardImpl((Board*)this, outSize, _img, marginSize, borderBits); -} - -Size GridBoard::getGridSize() const { - return Size(gridImpl->sizeX, gridImpl->sizeY); -} - -float GridBoard::getMarkerLength() const { - return gridImpl->markerLength; -} - -float GridBoard::getMarkerSeparation() const { - return gridImpl->markerSeparation; -} - -struct CharucoBoard::CharucoImpl : GridBoard::GridImpl { - // size of chessboard squares side (normally in meters) - float squareLength; - - // marker side length (normally in meters) - float markerLength; -}; - -CharucoBoard::CharucoBoard(): charucoImpl(makePtr()) {} - -void CharucoBoard::draw(Size outSize, OutputArray _img, int marginSize, int borderBits) { - CV_Assert(!outSize.empty()); - CV_Assert(marginSize >= 0); - - _img.create(outSize, CV_8UC1); - _img.setTo(255); - Mat out = _img.getMat(); - Mat noMarginsImg = - out.colRange(marginSize, out.cols - marginSize).rowRange(marginSize, out.rows - marginSize); - - double totalLengthX, totalLengthY; - totalLengthX = charucoImpl->squareLength * charucoImpl->sizeX; - totalLengthY = charucoImpl->squareLength * charucoImpl->sizeY; - - // proportional transformation - double xReduction = totalLengthX / double(noMarginsImg.cols); - double yReduction = totalLengthY / double(noMarginsImg.rows); - - // determine the zone where the chessboard is placed - Mat chessboardZoneImg; - if(xReduction > yReduction) { - int nRows = int(totalLengthY / xReduction); - int rowsMargins = (noMarginsImg.rows - nRows) / 2; - chessboardZoneImg = noMarginsImg.rowRange(rowsMargins, noMarginsImg.rows - rowsMargins); - } else { - int nCols = int(totalLengthX / yReduction); - int colsMargins = (noMarginsImg.cols - nCols) / 2; - chessboardZoneImg = noMarginsImg.colRange(colsMargins, noMarginsImg.cols - colsMargins); - } - - // determine the margins to draw only the markers - // take the minimum just to be sure - double squareSizePixels = min(double(chessboardZoneImg.cols) / double(charucoImpl->sizeX), - double(chessboardZoneImg.rows) / double(charucoImpl->sizeY)); - - double diffSquareMarkerLength = (charucoImpl->squareLength - charucoImpl->markerLength) / 2; - int diffSquareMarkerLengthPixels = - int(diffSquareMarkerLength * squareSizePixels / charucoImpl->squareLength); - - // draw markers - Mat markersImg; - _drawPlanarBoardImpl(this, chessboardZoneImg.size(), markersImg, diffSquareMarkerLengthPixels, borderBits); - markersImg.copyTo(chessboardZoneImg); - - // now draw black squares - for(int y = 0; y < charucoImpl->sizeY; y++) { - for(int x = 0; x < charucoImpl->sizeX; x++) { - - if(y % 2 != x % 2) continue; // white corner, dont do anything - - double startX, startY; - startX = squareSizePixels * double(x); - startY = squareSizePixels * double(y); - - Mat squareZone = chessboardZoneImg.rowRange(int(startY), int(startY + squareSizePixels)) - .colRange(int(startX), int(startX + squareSizePixels)); - - squareZone.setTo(0); - } - } -} - -/** - * Fill nearestMarkerIdx and nearestMarkerCorners arrays - */ -static inline void _getNearestMarkerCorners(CharucoBoard &board, float squareLength) { - board.nearestMarkerIdx.resize(board.chessboardCorners.size()); - board.nearestMarkerCorners.resize(board.chessboardCorners.size()); - - unsigned int nMarkers = (unsigned int)board.getIds().size(); - unsigned int nCharucoCorners = (unsigned int)board.chessboardCorners.size(); - for(unsigned int i = 0; i < nCharucoCorners; i++) { - double minDist = -1; // distance of closest markers - Point3f charucoCorner = board.chessboardCorners[i]; - for(unsigned int j = 0; j < nMarkers; j++) { - // calculate distance from marker center to charuco corner - Point3f center = Point3f(0, 0, 0); - for(unsigned int k = 0; k < 4; k++) - center += board.getObjPoints()[j][k]; - center /= 4.; - double sqDistance; - Point3f distVector = charucoCorner - center; - sqDistance = distVector.x * distVector.x + distVector.y * distVector.y; - if(j == 0 || fabs(sqDistance - minDist) < cv::pow(0.01 * squareLength, 2)) { - // if same minimum distance (or first iteration), add to nearestMarkerIdx vector - board.nearestMarkerIdx[i].push_back(j); - minDist = sqDistance; - } else if(sqDistance < minDist) { - // if finding a closest marker to the charuco corner - board.nearestMarkerIdx[i].clear(); // remove any previous added marker - board.nearestMarkerIdx[i].push_back(j); // add the new closest marker index - minDist = sqDistance; - } - } - // for each of the closest markers, search the marker corner index closer - // to the charuco corner - for(unsigned int j = 0; j < board.nearestMarkerIdx[i].size(); j++) { - board.nearestMarkerCorners[i].resize(board.nearestMarkerIdx[i].size()); - double minDistCorner = -1; - for(unsigned int k = 0; k < 4; k++) { - double sqDistance; - Point3f distVector = charucoCorner - board.getObjPoints()[board.nearestMarkerIdx[i][j]][k]; - sqDistance = distVector.x * distVector.x + distVector.y * distVector.y; - if(k == 0 || sqDistance < minDistCorner) { - // if this corner is closer to the charuco corner, assing its index - // to nearestMarkerCorners - minDistCorner = sqDistance; - board.nearestMarkerCorners[i][j] = k; - } - } - } - } -} - -Ptr CharucoBoard::create(int squaresX, int squaresY, float squareLength, - float markerLength, const Ptr &dictionary) { - CV_Assert(squaresX > 1 && squaresY > 1 && markerLength > 0 && squareLength > markerLength); - Ptr res = makePtr(); - - res->charucoImpl->sizeX = squaresX; - res->charucoImpl->sizeY = squaresY; - res->charucoImpl->squareLength = squareLength; - res->charucoImpl->markerLength = markerLength; - res->setDictionary(dictionary); - std::vector > objPoints; - - float diffSquareMarkerLength = (squareLength - markerLength) / 2; - // calculate Board objPoints - for(int y = 0; y < squaresY; y++) { - for(int x = 0; x < squaresX; x++) { - - if(y % 2 == x % 2) continue; // black corner, no marker here - - vector corners(4); - corners[0] = Point3f(x * squareLength + diffSquareMarkerLength, - y * squareLength + diffSquareMarkerLength, 0); - corners[1] = corners[0] + Point3f(markerLength, 0, 0); - corners[2] = corners[0] + Point3f(markerLength, markerLength, 0); - corners[3] = corners[0] + Point3f(0, markerLength, 0); - objPoints.push_back(corners); - // first ids in dictionary - int nextId = (int)res->ids.size(); - res->ids.push_back(nextId); - } - } - res->setObjPoints(objPoints); - - // now fill chessboardCorners - for(int y = 0; y < squaresY - 1; y++) { - for(int x = 0; x < squaresX - 1; x++) { - Point3f corner; - corner.x = (x + 1) * squareLength; - corner.y = (y + 1) * squareLength; - corner.z = 0; - res->chessboardCorners.push_back(corner); - } - } - res->rightBottomBorder = Point3f(squaresX * squareLength, - squaresY * squareLength, 0.f); - _getNearestMarkerCorners(*res, res->charucoImpl->squareLength); - return res; -} - -Size CharucoBoard::getChessboardSize() const { return Size(charucoImpl->sizeX, charucoImpl->sizeY); } - -float CharucoBoard::getSquareLength() const { return charucoImpl->squareLength; } - -float CharucoBoard::getMarkerLength() const { return charucoImpl->markerLength; } - -bool testCharucoCornersCollinear(const Ptr &_board, InputArray _charucoIds) { - unsigned int nCharucoCorners = (unsigned int)_charucoIds.getMat().total(); - if (nCharucoCorners <= 2) - return true; - - // only test if there are 3 or more corners - CV_Assert( _board->chessboardCorners.size() >= _charucoIds.getMat().total()); - - Vec point0( _board->chessboardCorners[_charucoIds.getMat().at< int >(0)].x, - _board->chessboardCorners[_charucoIds.getMat().at< int >(0)].y, 1); - - Vec point1( _board->chessboardCorners[_charucoIds.getMat().at< int >(1)].x, - _board->chessboardCorners[_charucoIds.getMat().at< int >(1)].y, 1); - - // create a line from the first two points. - Vec testLine = point0.cross(point1); - Vec testPoint(0, 0, 1); - - double divisor = sqrt(testLine[0]*testLine[0] + testLine[1]*testLine[1]); - CV_Assert(divisor != 0.0); - - // normalize the line with normal - testLine /= divisor; - - double dotProduct; - for (unsigned int i = 2; i < nCharucoCorners; i++){ - testPoint(0) = _board->chessboardCorners[_charucoIds.getMat().at< int >(i)].x; - testPoint(1) = _board->chessboardCorners[_charucoIds.getMat().at< int >(i)].y; - - // if testPoint is on testLine, dotProduct will be zero (or very, very close) - dotProduct = testPoint.dot(testLine); - - if (std::abs(dotProduct) > 1e-6){ - return false; - } - } - // no points found that were off of testLine, return true that all points collinear. - return true; -} - -} -} diff --git a/modules/aruco/src/charuco.cpp b/modules/aruco/src/charuco.cpp index 431d514fad0..88c88ae29b2 100644 --- a/modules/aruco/src/charuco.cpp +++ b/modules/aruco/src/charuco.cpp @@ -3,8 +3,8 @@ // of this distribution and at http://opencv.org/license.html #include "precomp.hpp" +#include #include "opencv2/aruco/charuco.hpp" -#include #include #include @@ -15,12 +15,9 @@ using namespace std; /** * Remove charuco corners if any of their minMarkers closest markers has not been detected */ -static int _filterCornersWithoutMinMarkers(const Ptr &_board, - InputArray _allCharucoCorners, - InputArray _allCharucoIds, - InputArray _allArucoIds, int minMarkers, - OutputArray _filteredCharucoCorners, - OutputArray _filteredCharucoIds) { +static int _filterCornersWithoutMinMarkers(const Ptr &_board, InputArray _allCharucoCorners, + InputArray _allCharucoIds, InputArray _allArucoIds, int minMarkers, + OutputArray _filteredCharucoCorners, OutputArray _filteredCharucoIds) { CV_Assert(minMarkers >= 0 && minMarkers <= 2); @@ -31,8 +28,8 @@ static int _filterCornersWithoutMinMarkers(const Ptr &_board, int currentCharucoId = _allCharucoIds.getMat().at< int >(i); int totalMarkers = 0; // nomber of closest marker detected // look for closest markers - for(unsigned int m = 0; m < _board->nearestMarkerIdx[currentCharucoId].size(); m++) { - int markerId = _board->getIds()[_board->nearestMarkerIdx[currentCharucoId][m]]; + for(unsigned int m = 0; m < _board->getNearestMarkerIdx()[currentCharucoId].size(); m++) { + int markerId = _board->getIds()[_board->getNearestMarkerIdx()[currentCharucoId][m]]; bool found = false; for(unsigned int k = 0; k < _allArucoIds.getMat().total(); k++) { if(_allArucoIds.getMat().at< int >(k) == markerId) { @@ -59,10 +56,8 @@ static int _filterCornersWithoutMinMarkers(const Ptr &_board, * @brief From all projected chessboard corners, select those inside the image and apply subpixel * refinement. Returns number of valid corners. */ -static int _selectAndRefineChessboardCorners(InputArray _allCorners, InputArray _image, - OutputArray _selectedCorners, - OutputArray _selectedIds, - const vector< Size > &winSizes) { +static int _selectAndRefineChessboardCorners(InputArray _allCorners, InputArray _image, OutputArray _selectedCorners, + OutputArray _selectedIds, const vector< Size > &winSizes) { const int minDistToBorder = 2; // minimum distance of the corner to the image border // remaining corners, ids and window refinement sizes after removing corners outside the image @@ -91,7 +86,7 @@ static int _selectAndRefineChessboardCorners(InputArray _allCorners, InputArray else grey = _image.getMat(); - const Ptr params = DetectorParameters::create(); // use default params for corner refinement + DetectorParameters params; // use default params for corner refinement //// For each of the charuco corners, apply subpixel refinement using its correspondind winSize parallel_for_(Range(0, (int)filteredChessboardImgPoints.size()), [&](const Range& range) { @@ -103,12 +98,12 @@ static int _selectAndRefineChessboardCorners(InputArray _allCorners, InputArray in.push_back(filteredChessboardImgPoints[i] - Point2f(0.5, 0.5)); // adjust sub-pixel coordinates for cornerSubPix Size winSize = filteredWinSizes[i]; if (winSize.height == -1 || winSize.width == -1) - winSize = Size(params->cornerRefinementWinSize, params->cornerRefinementWinSize); + winSize = Size(params.cornerRefinementWinSize, params.cornerRefinementWinSize); cornerSubPix(grey, in, winSize, Size(), TermCriteria(TermCriteria::MAX_ITER | TermCriteria::EPS, - params->cornerRefinementMaxIterations, - params->cornerRefinementMinAccuracy)); + params.cornerRefinementMaxIterations, + params.cornerRefinementMinAccuracy)); filteredChessboardImgPoints[i] = in[0] + Point2f(0.5, 0.5); } @@ -134,15 +129,15 @@ static void _getMaximumSubPixWindowSizes(InputArrayOfArrays markerCorners, Input for(unsigned int i = 0; i < nCharucoCorners; i++) { if(charucoCorners.getMat().at< Point2f >(i) == Point2f(-1, -1)) continue; - if(board->nearestMarkerIdx[i].size() == 0) continue; + if(board->getNearestMarkerIdx()[i].empty()) continue; double minDist = -1; int counter = 0; // calculate the distance to each of the closest corner of each closest marker - for(unsigned int j = 0; j < board->nearestMarkerIdx[i].size(); j++) { + for(unsigned int j = 0; j < board->getNearestMarkerIdx()[i].size(); j++) { // find marker - int markerId = board->getIds()[board->nearestMarkerIdx[i][j]]; + int markerId = board->getIds()[board->getNearestMarkerIdx()[i][j]]; int markerIdx = -1; for(unsigned int k = 0; k < markerIds.getMat().total(); k++) { if(markerIds.getMat().at< int >(k) == markerId) { @@ -152,7 +147,7 @@ static void _getMaximumSubPixWindowSizes(InputArrayOfArrays markerCorners, Input } if(markerIdx == -1) continue; Point2f markerCorner = - markerCorners.getMat(markerIdx).at< Point2f >(board->nearestMarkerCorners[i][j]); + markerCorners.getMat(markerIdx).at< Point2f >(board->getNearestMarkerCorners()[i][j]); Point2f charucoCorner = charucoCorners.getMat().at< Point2f >(i); double dist = norm(markerCorner - charucoCorner); if(minDist == -1) minDist = dist; // if first distance, just assign it @@ -177,12 +172,10 @@ static void _getMaximumSubPixWindowSizes(InputArrayOfArrays markerCorners, Input /** * Interpolate charuco corners using approximated pose estimation */ -static int _interpolateCornersCharucoApproxCalib(InputArrayOfArrays _markerCorners, - InputArray _markerIds, InputArray _image, - const Ptr &_board, +static int _interpolateCornersCharucoApproxCalib(InputArrayOfArrays _markerCorners, InputArray _markerIds, + InputArray _image, const Ptr &_board, InputArray _cameraMatrix, InputArray _distCoeffs, - OutputArray _charucoCorners, - OutputArray _charucoIds) { + OutputArray _charucoCorners, OutputArray _charucoIds) { CV_Assert(_image.getMat().channels() == 1 || _image.getMat().channels() == 3); CV_Assert(_markerCorners.total() == _markerIds.getMat().total() && @@ -201,7 +194,7 @@ static int _interpolateCornersCharucoApproxCalib(InputArrayOfArrays _markerCorne // project chessboard corners vector< Point2f > allChessboardImgPoints; - projectPoints(_board->chessboardCorners, approximatedRvec, approximatedTvec, _cameraMatrix, + projectPoints(_board->getChessboardCorners(), approximatedRvec, approximatedTvec, _cameraMatrix, _distCoeffs, allChessboardImgPoints); @@ -220,11 +213,9 @@ static int _interpolateCornersCharucoApproxCalib(InputArrayOfArrays _markerCorne /** * Interpolate charuco corners using local homography */ -static int _interpolateCornersCharucoLocalHom(InputArrayOfArrays _markerCorners, - InputArray _markerIds, InputArray _image, - const Ptr &_board, - OutputArray _charucoCorners, - OutputArray _charucoIds) { +static int _interpolateCornersCharucoLocalHom(InputArrayOfArrays _markerCorners, InputArray _markerIds, + InputArray _image, const Ptr &_board, + OutputArray _charucoCorners, OutputArray _charucoIds) { CV_Assert(_image.getMat().channels() == 1 || _image.getMat().channels() == 3); CV_Assert(_markerCorners.total() == _markerIds.getMat().total() && @@ -258,17 +249,17 @@ static int _interpolateCornersCharucoLocalHom(InputArrayOfArrays _markerCorners, validTransform[i] = std::abs(det) > 1e-6; } - unsigned int nCharucoCorners = (unsigned int)_board->chessboardCorners.size(); + unsigned int nCharucoCorners = (unsigned int)_board->getChessboardCorners().size(); vector< Point2f > allChessboardImgPoints(nCharucoCorners, Point2f(-1, -1)); // for each charuco corner, calculate its interpolation position based on the closest markers // homographies for(unsigned int i = 0; i < nCharucoCorners; i++) { - Point2f objPoint2D = Point2f(_board->chessboardCorners[i].x, _board->chessboardCorners[i].y); + Point2f objPoint2D = Point2f(_board->getChessboardCorners()[i].x, _board->getChessboardCorners()[i].y); vector< Point2f > interpolatedPositions; - for(unsigned int j = 0; j < _board->nearestMarkerIdx[i].size(); j++) { - int markerId = _board->getIds()[_board->nearestMarkerIdx[i][j]]; + for(unsigned int j = 0; j < _board->getNearestMarkerIdx()[i].size(); j++) { + int markerId = _board->getIds()[_board->getNearestMarkerIdx()[i][j]]; int markerIdx = -1; for(unsigned int k = 0; k < _markerIds.getMat().total(); k++) { if(_markerIds.getMat().at< int >(k) == markerId) { @@ -317,14 +308,12 @@ int interpolateCornersCharuco(InputArrayOfArrays _markerCorners, InputArray _mar // if camera parameters are avaible, use approximated calibration if(_cameraMatrix.total() != 0) { - _interpolateCornersCharucoApproxCalib(_markerCorners, _markerIds, _image, _board, - _cameraMatrix, _distCoeffs, _charucoCorners, - _charucoIds); + _interpolateCornersCharucoApproxCalib(_markerCorners, _markerIds, _image, _board, _cameraMatrix, _distCoeffs, + _charucoCorners, _charucoIds); } // else use local homography else { - _interpolateCornersCharucoLocalHom(_markerCorners, _markerIds, _image, _board, - _charucoCorners, _charucoIds); + _interpolateCornersCharucoLocalHom(_markerCorners, _markerIds, _image, _board, _charucoCorners, _charucoIds); } // to return a charuco corner, its closest aruco markers should have been detected @@ -333,45 +322,13 @@ int interpolateCornersCharuco(InputArrayOfArrays _markerCorners, InputArray _mar } -void drawDetectedCornersCharuco(InputOutputArray _image, InputArray _charucoCorners, - InputArray _charucoIds, Scalar cornerColor) { - - CV_Assert(_image.getMat().total() != 0 && - (_image.getMat().channels() == 1 || _image.getMat().channels() == 3)); - CV_Assert((_charucoCorners.getMat().total() == _charucoIds.getMat().total()) || - _charucoIds.getMat().total() == 0); - - unsigned int nCorners = (unsigned int)_charucoCorners.getMat().total(); - for(unsigned int i = 0; i < nCorners; i++) { - Point2f corner = _charucoCorners.getMat().at< Point2f >(i); - - // draw first corner mark - rectangle(_image, corner - Point2f(3, 3), corner + Point2f(3, 3), cornerColor, 1, LINE_AA); - - // draw ID - if(_charucoIds.total() != 0) { - int id = _charucoIds.getMat().at< int >(i); - stringstream s; - s << "id=" << id; - putText(_image, s.str(), corner + Point2f(5, -5), FONT_HERSHEY_SIMPLEX, 0.5, - cornerColor, 2); - } - } -} - - -void detectCharucoDiamond(InputArray _image, InputArrayOfArrays _markerCorners, - InputArray _markerIds, float squareMarkerLengthRate, - OutputArrayOfArrays _diamondCorners, OutputArray _diamondIds, +void detectCharucoDiamond(InputArray _image, InputArrayOfArrays _markerCorners, InputArray _markerIds, + float squareMarkerLengthRate, OutputArrayOfArrays _diamondCorners, OutputArray _diamondIds, InputArray _cameraMatrix, InputArray _distCoeffs, Ptr dictionary) { CV_Assert(_markerIds.total() > 0 && _markerIds.total() == _markerCorners.total()); const float minRepDistanceRate = 1.302455f; - // create Charuco board layout for diamond (3x3 layout) - Ptr _charucoDiamondLayout = CharucoBoard::create(3, 3, squareMarkerLengthRate, 1., dictionary); - - vector< vector< Point2f > > diamondCorners; vector< Vec4i > diamondIds; @@ -421,18 +378,20 @@ void detectCharucoDiamond(InputArray _image, InputArrayOfArrays _markerCorners, } if(candidates.size() < 3) break; // we need at least 3 free markers // modify charuco layout id to make sure all the ids are different than current id + vector tmpIds(4); for(int k = 1; k < 4; k++) - _charucoDiamondLayout->changeId(k, currentId + 1 + k); + tmpIds[k] = currentId + 1 + k; // current id is assigned to [0], so it is the marker on the top - _charucoDiamondLayout->changeId(0, currentId); + tmpIds[0] = currentId; + // create Charuco board layout for diamond (3x3 layout) + Ptr _charucoDiamondLayout = new CharucoBoard(Size(3, 3), squareMarkerLengthRate, 1., *dictionary, tmpIds); // try to find the rest of markers in the diamond vector< int > acceptedIdxs; - Ptr _b = _charucoDiamondLayout.staticCast(); - Ptr refineParameters = makePtr(minRepDistance, -1, false); - ArucoDetector detector(dictionary, DetectorParameters::create(), refineParameters); - detector.refineDetectedMarkers(grey, _b, currentMarker, currentMarkerId, candidates, noArray(), noArray(), - acceptedIdxs); + RefineParameters refineParameters(minRepDistance, -1.f, false); + ArucoDetector detector(*dictionary, DetectorParameters(), refineParameters); + detector.refineDetectedMarkers(grey, *_charucoDiamondLayout, currentMarker, currentMarkerId, candidates, + noArray(), noArray(), acceptedIdxs); // if found, we have a diamond if(currentMarker.size() == 4) { @@ -492,59 +451,14 @@ void drawCharucoDiamond(const Ptr &dictionary, Vec4i ids, int square CV_Assert(squareLength > 0 && markerLength > 0 && squareLength > markerLength); CV_Assert(marginSize >= 0 && borderBits > 0); - // create a charuco board similar to a charuco marker and print it - Ptr board = - CharucoBoard::create(3, 3, (float)squareLength, (float)markerLength, dictionary); - // assign the charuco marker ids + vector tmpIds(4); for(int i = 0; i < 4; i++) - board->changeId(i, ids[i]); - + tmpIds[i] = ids[i]; + // create a charuco board similar to a charuco marker and print it + CharucoBoard board(Size(3, 3), (float)squareLength, (float)markerLength, *dictionary, tmpIds); Size outSize(3 * squareLength + 2 * marginSize, 3 * squareLength + 2 * marginSize); - board->draw(outSize, _img, marginSize, borderBits); -} - - -void drawDetectedDiamonds(InputOutputArray _image, InputArrayOfArrays _corners, - InputArray _ids, Scalar borderColor) { - CV_Assert(_image.getMat().total() != 0 && - (_image.getMat().channels() == 1 || _image.getMat().channels() == 3)); - CV_Assert((_corners.total() == _ids.total()) || _ids.total() == 0); - - // calculate colors - Scalar textColor, cornerColor; - textColor = cornerColor = borderColor; - swap(textColor.val[0], textColor.val[1]); // text color just sawp G and R - swap(cornerColor.val[1], cornerColor.val[2]); // corner color just sawp G and B - - int nMarkers = (int)_corners.total(); - for(int i = 0; i < nMarkers; i++) { - Mat currentMarker = _corners.getMat(i); - CV_Assert(currentMarker.total() == 4 && currentMarker.type() == CV_32FC2); - - // draw marker sides - for(int j = 0; j < 4; j++) { - Point2f p0, p1; - p0 = currentMarker.at< Point2f >(j); - p1 = currentMarker.at< Point2f >((j + 1) % 4); - line(_image, p0, p1, borderColor, 1); - } - - // draw first corner mark - rectangle(_image, currentMarker.at< Point2f >(0) - Point2f(3, 3), - currentMarker.at< Point2f >(0) + Point2f(3, 3), cornerColor, 1, LINE_AA); - - // draw id composed by four numbers - if(_ids.total() != 0) { - Point2f cent(0, 0); - for(int p = 0; p < 4; p++) - cent += currentMarker.at< Point2f >(p); - cent = cent / 4.; - stringstream s; - s << "id=" << _ids.getMat().at< Vec4i >(i); - putText(_image, s.str(), cent, FONT_HERSHEY_SIMPLEX, 0.5, textColor, 2); - } - } + board.generateImage(outSize, _img, marginSize, borderBits); } } diff --git a/modules/aruco/src/dictionary.cpp b/modules/aruco/src/dictionary.cpp deleted file mode 100644 index 5672538f293..00000000000 --- a/modules/aruco/src/dictionary.cpp +++ /dev/null @@ -1,465 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html - -#include -#include "opencv2/core/hal/hal.hpp" - -#include "precomp.hpp" -#include "aruco_utils.hpp" -#include "predefined_dictionaries.hpp" -#include "apriltag/predefined_dictionaries_apriltag.hpp" -#include - -namespace cv { -namespace aruco { - -using namespace std; - - -Dictionary::Dictionary(const Ptr &_dictionary) { - markerSize = _dictionary->markerSize; - maxCorrectionBits = _dictionary->maxCorrectionBits; - bytesList = _dictionary->bytesList.clone(); -} - - -Dictionary::Dictionary(const Mat &_bytesList, int _markerSize, int _maxcorr) { - markerSize = _markerSize; - maxCorrectionBits = _maxcorr; - bytesList = _bytesList; -} - - -Ptr Dictionary::create(int nMarkers, int markerSize, int randomSeed) { - const Ptr baseDictionary = makePtr(); - return create(nMarkers, markerSize, baseDictionary, randomSeed); -} - - -Ptr Dictionary::create(int nMarkers, int markerSize, - const Ptr &baseDictionary, int randomSeed) { - return generateCustomDictionary(nMarkers, markerSize, baseDictionary, randomSeed); -} - - -bool Dictionary::readDictionary(const cv::FileNode& fn) { - int nMarkers = 0, _markerSize = 0; - if (fn.empty() || !readParameter("nmarkers", nMarkers, fn) || !readParameter("markersize", _markerSize, fn)) - return false; - Mat bytes(0, 0, CV_8UC1), marker(_markerSize, _markerSize, CV_8UC1); - std::string markerString; - for (int i = 0; i < nMarkers; i++) { - std::ostringstream ostr; - ostr << i; - if (!readParameter("marker_" + ostr.str(), markerString, fn)) - return false; - for (int j = 0; j < (int) markerString.size(); j++) - marker.at(j) = (markerString[j] == '0') ? 0 : 1; - bytes.push_back(Dictionary::getByteListFromBits(marker)); - } - int _maxCorrectionBits = 0; - readParameter("maxCorrectionBits", _maxCorrectionBits, fn); - *this = Dictionary(bytes, _markerSize, _maxCorrectionBits); - return true; -} - - -void Dictionary::writeDictionary(Ptr& fs) { - *fs << "nmarkers" << bytesList.rows; - *fs << "markersize" << markerSize; - *fs << "maxCorrectionBits" << maxCorrectionBits; - for (int i = 0; i < bytesList.rows; i++) { - Mat row = bytesList.row(i);; - Mat bitMarker = getBitsFromByteList(row, markerSize); - std::ostringstream ostr; - ostr << i; - string markerName = "marker_" + ostr.str(); - string marker; - for (int j = 0; j < markerSize * markerSize; j++) - marker.push_back(bitMarker.at(j) + '0'); - *fs << markerName << marker; - } -} - - -Ptr Dictionary::get(int dict) { - return getPredefinedDictionary(dict); -} - - -bool Dictionary::identify(const Mat &onlyBits, int &idx, int &rotation, double maxCorrectionRate) const { - CV_Assert(onlyBits.rows == markerSize && onlyBits.cols == markerSize); - - int maxCorrectionRecalculed = int(double(maxCorrectionBits) * maxCorrectionRate); - - // get as a byte list - Mat candidateBytes = getByteListFromBits(onlyBits); - - idx = -1; // by default, not found - - // search closest marker in dict - for(int m = 0; m < bytesList.rows; m++) { - int currentMinDistance = markerSize * markerSize + 1; - int currentRotation = -1; - for(unsigned int r = 0; r < 4; r++) { - int currentHamming = cv::hal::normHamming( - bytesList.ptr(m)+r*candidateBytes.cols, - candidateBytes.ptr(), - candidateBytes.cols); - - if(currentHamming < currentMinDistance) { - currentMinDistance = currentHamming; - currentRotation = r; - } - } - - // if maxCorrection is fulfilled, return this one - if(currentMinDistance <= maxCorrectionRecalculed) { - idx = m; - rotation = currentRotation; - break; - } - } - - return idx != -1; -} - - -int Dictionary::getDistanceToId(InputArray bits, int id, bool allRotations) const { - - CV_Assert(id >= 0 && id < bytesList.rows); - - unsigned int nRotations = 4; - if(!allRotations) nRotations = 1; - - Mat candidateBytes = getByteListFromBits(bits.getMat()); - int currentMinDistance = int(bits.total() * bits.total()); - for(unsigned int r = 0; r < nRotations; r++) { - int currentHamming = cv::hal::normHamming( - bytesList.ptr(id) + r*candidateBytes.cols, - candidateBytes.ptr(), - candidateBytes.cols); - - if(currentHamming < currentMinDistance) { - currentMinDistance = currentHamming; - } - } - return currentMinDistance; -} - - -void Dictionary::drawMarker(int id, int sidePixels, OutputArray _img, int borderBits) const { - CV_Assert(sidePixels >= (markerSize + 2*borderBits)); - CV_Assert(id < bytesList.rows); - CV_Assert(borderBits > 0); - - _img.create(sidePixels, sidePixels, CV_8UC1); - - // create small marker with 1 pixel per bin - Mat tinyMarker(markerSize + 2 * borderBits, markerSize + 2 * borderBits, CV_8UC1, - Scalar::all(0)); - Mat innerRegion = tinyMarker.rowRange(borderBits, tinyMarker.rows - borderBits) - .colRange(borderBits, tinyMarker.cols - borderBits); - // put inner bits - Mat bits = 255 * getBitsFromByteList(bytesList.rowRange(id, id + 1), markerSize); - CV_Assert(innerRegion.total() == bits.total()); - bits.copyTo(innerRegion); - - // resize tiny marker to output size - cv::resize(tinyMarker, _img.getMat(), _img.getMat().size(), 0, 0, INTER_NEAREST); -} - - -Mat Dictionary::getByteListFromBits(const Mat &bits) { - // integer ceil - int nbytes = (bits.cols * bits.rows + 8 - 1) / 8; - - Mat candidateByteList(1, nbytes, CV_8UC4, Scalar::all(0)); - unsigned char currentBit = 0; - int currentByte = 0; - - // the 4 rotations - uchar* rot0 = candidateByteList.ptr(); - uchar* rot1 = candidateByteList.ptr() + 1*nbytes; - uchar* rot2 = candidateByteList.ptr() + 2*nbytes; - uchar* rot3 = candidateByteList.ptr() + 3*nbytes; - - for(int row = 0; row < bits.rows; row++) { - for(int col = 0; col < bits.cols; col++) { - // circular shift - rot0[currentByte] <<= 1; - rot1[currentByte] <<= 1; - rot2[currentByte] <<= 1; - rot3[currentByte] <<= 1; - // set bit - rot0[currentByte] |= bits.at(row, col); - rot1[currentByte] |= bits.at(col, bits.cols - 1 - row); - rot2[currentByte] |= bits.at(bits.rows - 1 - row, bits.cols - 1 - col); - rot3[currentByte] |= bits.at(bits.rows - 1 - col, row); - currentBit++; - if(currentBit == 8) { - // next byte - currentBit = 0; - currentByte++; - } - } - } - return candidateByteList; -} - - -Mat Dictionary::getBitsFromByteList(const Mat &byteList, int markerSize) { - CV_Assert(byteList.total() > 0 && - byteList.total() >= (unsigned int)markerSize * markerSize / 8 && - byteList.total() <= (unsigned int)markerSize * markerSize / 8 + 1); - Mat bits(markerSize, markerSize, CV_8UC1, Scalar::all(0)); - - unsigned char base2List[] = { 128, 64, 32, 16, 8, 4, 2, 1 }; - int currentByteIdx = 0; - // we only need the bytes in normal rotation - unsigned char currentByte = byteList.ptr()[0]; - int currentBit = 0; - for(int row = 0; row < bits.rows; row++) { - for(int col = 0; col < bits.cols; col++) { - if(currentByte >= base2List[currentBit]) { - bits.at< unsigned char >(row, col) = 1; - currentByte -= base2List[currentBit]; - } - currentBit++; - if(currentBit == 8) { - currentByteIdx++; - currentByte = byteList.ptr()[currentByteIdx]; - // if not enough bits for one more byte, we are in the end - // update bit position accordingly - if(8 * (currentByteIdx + 1) > (int)bits.total()) - currentBit = 8 * (currentByteIdx + 1) - (int)bits.total(); - else - currentBit = 0; // ok, bits enough for next byte - } - } - } - return bits; -} - - -Ptr getPredefinedDictionary(PREDEFINED_DICTIONARY_NAME name) { - // DictionaryData constructors calls - // moved out of globals so construted on first use, which allows lazy-loading of opencv dll - static const Dictionary DICT_ARUCO_DATA = Dictionary(Mat(1024, (5 * 5 + 7) / 8, CV_8UC4, (uchar*)DICT_ARUCO_BYTES), 5, 0); - - static const Dictionary DICT_4X4_50_DATA = Dictionary(Mat(50, (4 * 4 + 7) / 8, CV_8UC4, (uchar*)DICT_4X4_1000_BYTES), 4, 1); - static const Dictionary DICT_4X4_100_DATA = Dictionary(Mat(100, (4 * 4 + 7) / 8, CV_8UC4, (uchar*)DICT_4X4_1000_BYTES), 4, 1); - static const Dictionary DICT_4X4_250_DATA = Dictionary(Mat(250, (4 * 4 + 7) / 8, CV_8UC4, (uchar*)DICT_4X4_1000_BYTES), 4, 1); - static const Dictionary DICT_4X4_1000_DATA = Dictionary(Mat(1000, (4 * 4 + 7) / 8, CV_8UC4, (uchar*)DICT_4X4_1000_BYTES), 4, 0); - - static const Dictionary DICT_5X5_50_DATA = Dictionary(Mat(50, (5 * 5 + 7) / 8, CV_8UC4, (uchar*)DICT_5X5_1000_BYTES), 5, 3); - static const Dictionary DICT_5X5_100_DATA = Dictionary(Mat(100, (5 * 5 + 7) / 8, CV_8UC4, (uchar*)DICT_5X5_1000_BYTES), 5, 3); - static const Dictionary DICT_5X5_250_DATA = Dictionary(Mat(250, (5 * 5 + 7) / 8, CV_8UC4, (uchar*)DICT_5X5_1000_BYTES), 5, 2); - static const Dictionary DICT_5X5_1000_DATA = Dictionary(Mat(1000, (5 * 5 + 7) / 8, CV_8UC4, (uchar*)DICT_5X5_1000_BYTES), 5, 2); - - static const Dictionary DICT_6X6_50_DATA = Dictionary(Mat(50, (6 * 6 + 7) / 8, CV_8UC4, (uchar*)DICT_6X6_1000_BYTES), 6, 6); - static const Dictionary DICT_6X6_100_DATA = Dictionary(Mat(100, (6 * 6 + 7) / 8, CV_8UC4, (uchar*)DICT_6X6_1000_BYTES), 6, 5); - static const Dictionary DICT_6X6_250_DATA = Dictionary(Mat(250, (6 * 6 + 7) / 8, CV_8UC4, (uchar*)DICT_6X6_1000_BYTES), 6, 5); - static const Dictionary DICT_6X6_1000_DATA = Dictionary(Mat(1000, (6 * 6 + 7) / 8, CV_8UC4, (uchar*)DICT_6X6_1000_BYTES), 6, 4); - - static const Dictionary DICT_7X7_50_DATA = Dictionary(Mat(50, (7 * 7 + 7) / 8, CV_8UC4, (uchar*)DICT_7X7_1000_BYTES), 7, 9); - static const Dictionary DICT_7X7_100_DATA = Dictionary(Mat(100, (7 * 7 + 7) / 8, CV_8UC4, (uchar*)DICT_7X7_1000_BYTES), 7, 8); - static const Dictionary DICT_7X7_250_DATA = Dictionary(Mat(250, (7 * 7 + 7) / 8, CV_8UC4, (uchar*)DICT_7X7_1000_BYTES), 7, 8); - static const Dictionary DICT_7X7_1000_DATA = Dictionary(Mat(1000, (7 * 7 + 7) / 8, CV_8UC4, (uchar*)DICT_7X7_1000_BYTES), 7, 6); - - static const Dictionary DICT_APRILTAG_16h5_DATA = Dictionary(Mat(30, (4 * 4 + 7) / 8, CV_8UC4, (uchar*)DICT_APRILTAG_16h5_BYTES), 4, 0); - static const Dictionary DICT_APRILTAG_25h9_DATA = Dictionary(Mat(35, (5 * 5 + 7) / 8, CV_8UC4, (uchar*)DICT_APRILTAG_25h9_BYTES), 5, 0); - static const Dictionary DICT_APRILTAG_36h10_DATA = Dictionary(Mat(2320, (6 * 6 + 7) / 8, CV_8UC4, (uchar*)DICT_APRILTAG_36h10_BYTES), 6, 0); - static const Dictionary DICT_APRILTAG_36h11_DATA = Dictionary(Mat(587, (6 * 6 + 7) / 8, CV_8UC4, (uchar*)DICT_APRILTAG_36h11_BYTES), 6, 0); - - switch(name) { - - case DICT_ARUCO_ORIGINAL: - return makePtr(DICT_ARUCO_DATA); - - case DICT_4X4_50: - return makePtr(DICT_4X4_50_DATA); - case DICT_4X4_100: - return makePtr(DICT_4X4_100_DATA); - case DICT_4X4_250: - return makePtr(DICT_4X4_250_DATA); - case DICT_4X4_1000: - return makePtr(DICT_4X4_1000_DATA); - - case DICT_5X5_50: - return makePtr(DICT_5X5_50_DATA); - case DICT_5X5_100: - return makePtr(DICT_5X5_100_DATA); - case DICT_5X5_250: - return makePtr(DICT_5X5_250_DATA); - case DICT_5X5_1000: - return makePtr(DICT_5X5_1000_DATA); - - case DICT_6X6_50: - return makePtr(DICT_6X6_50_DATA); - case DICT_6X6_100: - return makePtr(DICT_6X6_100_DATA); - case DICT_6X6_250: - return makePtr(DICT_6X6_250_DATA); - case DICT_6X6_1000: - return makePtr(DICT_6X6_1000_DATA); - - case DICT_7X7_50: - return makePtr(DICT_7X7_50_DATA); - case DICT_7X7_100: - return makePtr(DICT_7X7_100_DATA); - case DICT_7X7_250: - return makePtr(DICT_7X7_250_DATA); - case DICT_7X7_1000: - return makePtr(DICT_7X7_1000_DATA); - - case DICT_APRILTAG_16h5: - return makePtr(DICT_APRILTAG_16h5_DATA); - case DICT_APRILTAG_25h9: - return makePtr(DICT_APRILTAG_25h9_DATA); - case DICT_APRILTAG_36h10: - return makePtr(DICT_APRILTAG_36h10_DATA); - case DICT_APRILTAG_36h11: - return makePtr(DICT_APRILTAG_36h11_DATA); - - } - return makePtr(DICT_4X4_50_DATA); -} - - -Ptr getPredefinedDictionary(int dict) { - return getPredefinedDictionary(PREDEFINED_DICTIONARY_NAME(dict)); -} - - -/** - * @brief Generates a random marker Mat of size markerSize x markerSize - */ -static Mat _generateRandomMarker(int markerSize, RNG &rng) { - Mat marker(markerSize, markerSize, CV_8UC1, Scalar::all(0)); - for(int i = 0; i < markerSize; i++) { - for(int j = 0; j < markerSize; j++) { - unsigned char bit = (unsigned char) (rng.uniform(0,2)); - marker.at< unsigned char >(i, j) = bit; - } - } - return marker; -} - -/** - * @brief Calculate selfDistance of the codification of a marker Mat. Self distance is the Hamming - * distance of the marker to itself in the other rotations. - * See S. Garrido-Jurado, R. Muñoz-Salinas, F. J. Madrid-Cuevas, and M. J. Marín-Jiménez. 2014. - * "Automatic generation and detection of highly reliable fiducial markers under occlusion". - * Pattern Recogn. 47, 6 (June 2014), 2280-2292. DOI=10.1016/j.patcog.2014.01.005 - */ -static int _getSelfDistance(const Mat &marker) { - Mat bytes = Dictionary::getByteListFromBits(marker); - int minHamming = (int)marker.total() + 1; - for(int r = 1; r < 4; r++) { - int currentHamming = cv::hal::normHamming(bytes.ptr(), bytes.ptr() + bytes.cols*r, bytes.cols); - if(currentHamming < minHamming) minHamming = currentHamming; - } - return minHamming; -} - - -Ptr generateCustomDictionary(int nMarkers, int markerSize, - const Ptr &baseDictionary, int randomSeed) { - RNG rng((uint64)(randomSeed)); - - Ptr out = makePtr(); - out->markerSize = markerSize; - - // theoretical maximum intermarker distance - // See S. Garrido-Jurado, R. Muñoz-Salinas, F. J. Madrid-Cuevas, and M. J. Marín-Jiménez. 2014. - // "Automatic generation and detection of highly reliable fiducial markers under occlusion". - // Pattern Recogn. 47, 6 (June 2014), 2280-2292. DOI=10.1016/j.patcog.2014.01.005 - int C = (int)std::floor(float(markerSize * markerSize) / 4.f); - int tau = 2 * (int)std::floor(float(C) * 4.f / 3.f); - - // if baseDictionary is provided, calculate its intermarker distance - if(baseDictionary->bytesList.rows > 0) { - CV_Assert(baseDictionary->markerSize == markerSize); - out->bytesList = baseDictionary->bytesList.clone(); - - int minDistance = markerSize * markerSize + 1; - for(int i = 0; i < out->bytesList.rows; i++) { - Mat markerBytes = out->bytesList.rowRange(i, i + 1); - Mat markerBits = Dictionary::getBitsFromByteList(markerBytes, markerSize); - minDistance = min(minDistance, _getSelfDistance(markerBits)); - for(int j = i + 1; j < out->bytesList.rows; j++) { - minDistance = min(minDistance, out->getDistanceToId(markerBits, j)); - } - } - tau = minDistance; - } - - // current best option - int bestTau = 0; - Mat bestMarker; - - // after these number of unproductive iterations, the best option is accepted - const int maxUnproductiveIterations = 5000; - int unproductiveIterations = 0; - - while(out->bytesList.rows < nMarkers) { - Mat currentMarker = _generateRandomMarker(markerSize, rng); - - int selfDistance = _getSelfDistance(currentMarker); - int minDistance = selfDistance; - - // if self distance is better or equal than current best option, calculate distance - // to previous accepted markers - if(selfDistance >= bestTau) { - for(int i = 0; i < out->bytesList.rows; i++) { - int currentDistance = out->getDistanceToId(currentMarker, i); - minDistance = min(currentDistance, minDistance); - if(minDistance <= bestTau) { - break; - } - } - } - - // if distance is high enough, accept the marker - if(minDistance >= tau) { - unproductiveIterations = 0; - bestTau = 0; - Mat bytes = Dictionary::getByteListFromBits(currentMarker); - out->bytesList.push_back(bytes); - } else { - unproductiveIterations++; - - // if distance is not enough, but is better than the current best option - if(minDistance > bestTau) { - bestTau = minDistance; - bestMarker = currentMarker; - } - - // if number of unproductive iterarions has been reached, accept the current best option - if(unproductiveIterations == maxUnproductiveIterations) { - unproductiveIterations = 0; - tau = bestTau; - bestTau = 0; - Mat bytes = Dictionary::getByteListFromBits(bestMarker); - out->bytesList.push_back(bytes); - } - } - } - - // update the maximum number of correction bits for the generated dictionary - out->maxCorrectionBits = (tau - 1) / 2; - - return out; -} - - -Ptr generateCustomDictionary(int nMarkers, int markerSize, int randomSeed) { - Ptr baseDictionary = makePtr(); - return generateCustomDictionary(nMarkers, markerSize, baseDictionary, randomSeed); -} - - -} -} diff --git a/modules/aruco/src/predefined_dictionaries.hpp b/modules/aruco/src/predefined_dictionaries.hpp deleted file mode 100644 index f3431830598..00000000000 --- a/modules/aruco/src/predefined_dictionaries.hpp +++ /dev/null @@ -1,20127 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html - -namespace { - - - -/** - * Dictionaries are stored as a list of bytes in its four rotations - * On each rotation, the marker is divided in bytes assuming a row-major order - * This format allows a faster marker identification. - * For a dictionary composed by M markers of NxN bits, the structure dimensions should be: - * const char name[nMarkers][4rotations][nBytes], or more specifically: - * const char name[M][4][ceil(NxN/8)] - * The element [i][j][k] represents the k-th byte of the i-th marker in the dictionary - * in its j-th rotation. - * Each rotation implies a 90 degree rotation of the marker in anticlockwise direction. - */ - -static unsigned char DICT_ARUCO_BYTES[][4][4] = { - { { 132, 33, 8, 0 }, - { 0, 0, 15, 1 }, - { 8, 66, 16, 1 }, - { 248, 0, 0, 0 }, }, - { { 132, 33, 11, 1 }, - { 8, 66, 15, 1 }, - { 232, 66, 16, 1 }, - { 248, 33, 8, 0 }, }, - { { 132, 33, 4, 1 }, - { 8, 0, 31, 0 }, - { 144, 66, 16, 1 }, - { 124, 0, 8, 0 }, }, - { { 132, 33, 7, 0 }, - { 0, 66, 31, 0 }, - { 112, 66, 16, 1 }, - { 124, 33, 0, 0 }, }, - { { 132, 33, 120, 0 }, - { 16, 132, 15, 1 }, - { 15, 66, 16, 1 }, - { 248, 16, 132, 0 }, }, - { { 132, 33, 123, 1 }, - { 24, 198, 15, 1 }, - { 239, 66, 16, 1 }, - { 248, 49, 140, 0 }, }, - { { 132, 33, 116, 1 }, - { 24, 132, 31, 0 }, - { 151, 66, 16, 1 }, - { 124, 16, 140, 0 }, }, - { { 132, 33, 119, 0 }, - { 16, 198, 31, 0 }, - { 119, 66, 16, 1 }, - { 124, 49, 132, 0 }, }, - { { 132, 32, 152, 0 }, - { 16, 0, 46, 1 }, - { 12, 130, 16, 1 }, - { 186, 0, 4, 0 }, }, - { { 132, 32, 155, 1 }, - { 24, 66, 46, 1 }, - { 236, 130, 16, 1 }, - { 186, 33, 12, 0 }, }, - { { 132, 32, 148, 1 }, - { 24, 0, 62, 0 }, - { 148, 130, 16, 1 }, - { 62, 0, 12, 0 }, }, - { { 132, 32, 151, 0 }, - { 16, 66, 62, 0 }, - { 116, 130, 16, 1 }, - { 62, 33, 4, 0 }, }, - { { 132, 32, 232, 0 }, - { 0, 132, 46, 1 }, - { 11, 130, 16, 1 }, - { 186, 16, 128, 0 }, }, - { { 132, 32, 235, 1 }, - { 8, 198, 46, 1 }, - { 235, 130, 16, 1 }, - { 186, 49, 136, 0 }, }, - { { 132, 32, 228, 1 }, - { 8, 132, 62, 0 }, - { 147, 130, 16, 1 }, - { 62, 16, 136, 0 }, }, - { { 132, 32, 231, 0 }, - { 0, 198, 62, 0 }, - { 115, 130, 16, 1 }, - { 62, 49, 128, 0 }, }, - { { 132, 47, 8, 0 }, - { 33, 8, 15, 1 }, - { 8, 122, 16, 1 }, - { 248, 8, 66, 0 }, }, - { { 132, 47, 11, 1 }, - { 41, 74, 15, 1 }, - { 232, 122, 16, 1 }, - { 248, 41, 74, 0 }, }, - { { 132, 47, 4, 1 }, - { 41, 8, 31, 0 }, - { 144, 122, 16, 1 }, - { 124, 8, 74, 0 }, }, - { { 132, 47, 7, 0 }, - { 33, 74, 31, 0 }, - { 112, 122, 16, 1 }, - { 124, 41, 66, 0 }, }, - { { 132, 47, 120, 0 }, - { 49, 140, 15, 1 }, - { 15, 122, 16, 1 }, - { 248, 24, 198, 0 }, }, - { { 132, 47, 123, 1 }, - { 57, 206, 15, 1 }, - { 239, 122, 16, 1 }, - { 248, 57, 206, 0 }, }, - { { 132, 47, 116, 1 }, - { 57, 140, 31, 0 }, - { 151, 122, 16, 1 }, - { 124, 24, 206, 0 }, }, - { { 132, 47, 119, 0 }, - { 49, 206, 31, 0 }, - { 119, 122, 16, 1 }, - { 124, 57, 198, 0 }, }, - { { 132, 46, 152, 0 }, - { 49, 8, 46, 1 }, - { 12, 186, 16, 1 }, - { 186, 8, 70, 0 }, }, - { { 132, 46, 155, 1 }, - { 57, 74, 46, 1 }, - { 236, 186, 16, 1 }, - { 186, 41, 78, 0 }, }, - { { 132, 46, 148, 1 }, - { 57, 8, 62, 0 }, - { 148, 186, 16, 1 }, - { 62, 8, 78, 0 }, }, - { { 132, 46, 151, 0 }, - { 49, 74, 62, 0 }, - { 116, 186, 16, 1 }, - { 62, 41, 70, 0 }, }, - { { 132, 46, 232, 0 }, - { 33, 140, 46, 1 }, - { 11, 186, 16, 1 }, - { 186, 24, 194, 0 }, }, - { { 132, 46, 235, 1 }, - { 41, 206, 46, 1 }, - { 235, 186, 16, 1 }, - { 186, 57, 202, 0 }, }, - { { 132, 46, 228, 1 }, - { 41, 140, 62, 0 }, - { 147, 186, 16, 1 }, - { 62, 24, 202, 0 }, }, - { { 132, 46, 231, 0 }, - { 33, 206, 62, 0 }, - { 115, 186, 16, 1 }, - { 62, 57, 194, 0 }, }, - { { 132, 19, 8, 0 }, - { 32, 0, 77, 1 }, - { 8, 100, 16, 1 }, - { 217, 0, 2, 0 }, }, - { { 132, 19, 11, 1 }, - { 40, 66, 77, 1 }, - { 232, 100, 16, 1 }, - { 217, 33, 10, 0 }, }, - { { 132, 19, 4, 1 }, - { 40, 0, 93, 0 }, - { 144, 100, 16, 1 }, - { 93, 0, 10, 0 }, }, - { { 132, 19, 7, 0 }, - { 32, 66, 93, 0 }, - { 112, 100, 16, 1 }, - { 93, 33, 2, 0 }, }, - { { 132, 19, 120, 0 }, - { 48, 132, 77, 1 }, - { 15, 100, 16, 1 }, - { 217, 16, 134, 0 }, }, - { { 132, 19, 123, 1 }, - { 56, 198, 77, 1 }, - { 239, 100, 16, 1 }, - { 217, 49, 142, 0 }, }, - { { 132, 19, 116, 1 }, - { 56, 132, 93, 0 }, - { 151, 100, 16, 1 }, - { 93, 16, 142, 0 }, }, - { { 132, 19, 119, 0 }, - { 48, 198, 93, 0 }, - { 119, 100, 16, 1 }, - { 93, 49, 134, 0 }, }, - { { 132, 18, 152, 0 }, - { 48, 0, 108, 1 }, - { 12, 164, 16, 1 }, - { 155, 0, 6, 0 }, }, - { { 132, 18, 155, 1 }, - { 56, 66, 108, 1 }, - { 236, 164, 16, 1 }, - { 155, 33, 14, 0 }, }, - { { 132, 18, 148, 1 }, - { 56, 0, 124, 0 }, - { 148, 164, 16, 1 }, - { 31, 0, 14, 0 }, }, - { { 132, 18, 151, 0 }, - { 48, 66, 124, 0 }, - { 116, 164, 16, 1 }, - { 31, 33, 6, 0 }, }, - { { 132, 18, 232, 0 }, - { 32, 132, 108, 1 }, - { 11, 164, 16, 1 }, - { 155, 16, 130, 0 }, }, - { { 132, 18, 235, 1 }, - { 40, 198, 108, 1 }, - { 235, 164, 16, 1 }, - { 155, 49, 138, 0 }, }, - { { 132, 18, 228, 1 }, - { 40, 132, 124, 0 }, - { 147, 164, 16, 1 }, - { 31, 16, 138, 0 }, }, - { { 132, 18, 231, 0 }, - { 32, 198, 124, 0 }, - { 115, 164, 16, 1 }, - { 31, 49, 130, 0 }, }, - { { 132, 29, 8, 0 }, - { 1, 8, 77, 1 }, - { 8, 92, 16, 1 }, - { 217, 8, 64, 0 }, }, - { { 132, 29, 11, 1 }, - { 9, 74, 77, 1 }, - { 232, 92, 16, 1 }, - { 217, 41, 72, 0 }, }, - { { 132, 29, 4, 1 }, - { 9, 8, 93, 0 }, - { 144, 92, 16, 1 }, - { 93, 8, 72, 0 }, }, - { { 132, 29, 7, 0 }, - { 1, 74, 93, 0 }, - { 112, 92, 16, 1 }, - { 93, 41, 64, 0 }, }, - { { 132, 29, 120, 0 }, - { 17, 140, 77, 1 }, - { 15, 92, 16, 1 }, - { 217, 24, 196, 0 }, }, - { { 132, 29, 123, 1 }, - { 25, 206, 77, 1 }, - { 239, 92, 16, 1 }, - { 217, 57, 204, 0 }, }, - { { 132, 29, 116, 1 }, - { 25, 140, 93, 0 }, - { 151, 92, 16, 1 }, - { 93, 24, 204, 0 }, }, - { { 132, 29, 119, 0 }, - { 17, 206, 93, 0 }, - { 119, 92, 16, 1 }, - { 93, 57, 196, 0 }, }, - { { 132, 28, 152, 0 }, - { 17, 8, 108, 1 }, - { 12, 156, 16, 1 }, - { 155, 8, 68, 0 }, }, - { { 132, 28, 155, 1 }, - { 25, 74, 108, 1 }, - { 236, 156, 16, 1 }, - { 155, 41, 76, 0 }, }, - { { 132, 28, 148, 1 }, - { 25, 8, 124, 0 }, - { 148, 156, 16, 1 }, - { 31, 8, 76, 0 }, }, - { { 132, 28, 151, 0 }, - { 17, 74, 124, 0 }, - { 116, 156, 16, 1 }, - { 31, 41, 68, 0 }, }, - { { 132, 28, 232, 0 }, - { 1, 140, 108, 1 }, - { 11, 156, 16, 1 }, - { 155, 24, 192, 0 }, }, - { { 132, 28, 235, 1 }, - { 9, 206, 108, 1 }, - { 235, 156, 16, 1 }, - { 155, 57, 200, 0 }, }, - { { 132, 28, 228, 1 }, - { 9, 140, 124, 0 }, - { 147, 156, 16, 1 }, - { 31, 24, 200, 0 }, }, - { { 132, 28, 231, 0 }, - { 1, 206, 124, 0 }, - { 115, 156, 16, 1 }, - { 31, 57, 192, 0 }, }, - { { 133, 225, 8, 0 }, - { 66, 16, 15, 1 }, - { 8, 67, 208, 1 }, - { 248, 4, 33, 0 }, }, - { { 133, 225, 11, 1 }, - { 74, 82, 15, 1 }, - { 232, 67, 208, 1 }, - { 248, 37, 41, 0 }, }, - { { 133, 225, 4, 1 }, - { 74, 16, 31, 0 }, - { 144, 67, 208, 1 }, - { 124, 4, 41, 0 }, }, - { { 133, 225, 7, 0 }, - { 66, 82, 31, 0 }, - { 112, 67, 208, 1 }, - { 124, 37, 33, 0 }, }, - { { 133, 225, 120, 0 }, - { 82, 148, 15, 1 }, - { 15, 67, 208, 1 }, - { 248, 20, 165, 0 }, }, - { { 133, 225, 123, 1 }, - { 90, 214, 15, 1 }, - { 239, 67, 208, 1 }, - { 248, 53, 173, 0 }, }, - { { 133, 225, 116, 1 }, - { 90, 148, 31, 0 }, - { 151, 67, 208, 1 }, - { 124, 20, 173, 0 }, }, - { { 133, 225, 119, 0 }, - { 82, 214, 31, 0 }, - { 119, 67, 208, 1 }, - { 124, 53, 165, 0 }, }, - { { 133, 224, 152, 0 }, - { 82, 16, 46, 1 }, - { 12, 131, 208, 1 }, - { 186, 4, 37, 0 }, }, - { { 133, 224, 155, 1 }, - { 90, 82, 46, 1 }, - { 236, 131, 208, 1 }, - { 186, 37, 45, 0 }, }, - { { 133, 224, 148, 1 }, - { 90, 16, 62, 0 }, - { 148, 131, 208, 1 }, - { 62, 4, 45, 0 }, }, - { { 133, 224, 151, 0 }, - { 82, 82, 62, 0 }, - { 116, 131, 208, 1 }, - { 62, 37, 37, 0 }, }, - { { 133, 224, 232, 0 }, - { 66, 148, 46, 1 }, - { 11, 131, 208, 1 }, - { 186, 20, 161, 0 }, }, - { { 133, 224, 235, 1 }, - { 74, 214, 46, 1 }, - { 235, 131, 208, 1 }, - { 186, 53, 169, 0 }, }, - { { 133, 224, 228, 1 }, - { 74, 148, 62, 0 }, - { 147, 131, 208, 1 }, - { 62, 20, 169, 0 }, }, - { { 133, 224, 231, 0 }, - { 66, 214, 62, 0 }, - { 115, 131, 208, 1 }, - { 62, 53, 161, 0 }, }, - { { 133, 239, 8, 0 }, - { 99, 24, 15, 1 }, - { 8, 123, 208, 1 }, - { 248, 12, 99, 0 }, }, - { { 133, 239, 11, 1 }, - { 107, 90, 15, 1 }, - { 232, 123, 208, 1 }, - { 248, 45, 107, 0 }, }, - { { 133, 239, 4, 1 }, - { 107, 24, 31, 0 }, - { 144, 123, 208, 1 }, - { 124, 12, 107, 0 }, }, - { { 133, 239, 7, 0 }, - { 99, 90, 31, 0 }, - { 112, 123, 208, 1 }, - { 124, 45, 99, 0 }, }, - { { 133, 239, 120, 0 }, - { 115, 156, 15, 1 }, - { 15, 123, 208, 1 }, - { 248, 28, 231, 0 }, }, - { { 133, 239, 123, 1 }, - { 123, 222, 15, 1 }, - { 239, 123, 208, 1 }, - { 248, 61, 239, 0 }, }, - { { 133, 239, 116, 1 }, - { 123, 156, 31, 0 }, - { 151, 123, 208, 1 }, - { 124, 28, 239, 0 }, }, - { { 133, 239, 119, 0 }, - { 115, 222, 31, 0 }, - { 119, 123, 208, 1 }, - { 124, 61, 231, 0 }, }, - { { 133, 238, 152, 0 }, - { 115, 24, 46, 1 }, - { 12, 187, 208, 1 }, - { 186, 12, 103, 0 }, }, - { { 133, 238, 155, 1 }, - { 123, 90, 46, 1 }, - { 236, 187, 208, 1 }, - { 186, 45, 111, 0 }, }, - { { 133, 238, 148, 1 }, - { 123, 24, 62, 0 }, - { 148, 187, 208, 1 }, - { 62, 12, 111, 0 }, }, - { { 133, 238, 151, 0 }, - { 115, 90, 62, 0 }, - { 116, 187, 208, 1 }, - { 62, 45, 103, 0 }, }, - { { 133, 238, 232, 0 }, - { 99, 156, 46, 1 }, - { 11, 187, 208, 1 }, - { 186, 28, 227, 0 }, }, - { { 133, 238, 235, 1 }, - { 107, 222, 46, 1 }, - { 235, 187, 208, 1 }, - { 186, 61, 235, 0 }, }, - { { 133, 238, 228, 1 }, - { 107, 156, 62, 0 }, - { 147, 187, 208, 1 }, - { 62, 28, 235, 0 }, }, - { { 133, 238, 231, 0 }, - { 99, 222, 62, 0 }, - { 115, 187, 208, 1 }, - { 62, 61, 227, 0 }, }, - { { 133, 211, 8, 0 }, - { 98, 16, 77, 1 }, - { 8, 101, 208, 1 }, - { 217, 4, 35, 0 }, }, - { { 133, 211, 11, 1 }, - { 106, 82, 77, 1 }, - { 232, 101, 208, 1 }, - { 217, 37, 43, 0 }, }, - { { 133, 211, 4, 1 }, - { 106, 16, 93, 0 }, - { 144, 101, 208, 1 }, - { 93, 4, 43, 0 }, }, - { { 133, 211, 7, 0 }, - { 98, 82, 93, 0 }, - { 112, 101, 208, 1 }, - { 93, 37, 35, 0 }, }, - { { 133, 211, 120, 0 }, - { 114, 148, 77, 1 }, - { 15, 101, 208, 1 }, - { 217, 20, 167, 0 }, }, - { { 133, 211, 123, 1 }, - { 122, 214, 77, 1 }, - { 239, 101, 208, 1 }, - { 217, 53, 175, 0 }, }, - { { 133, 211, 116, 1 }, - { 122, 148, 93, 0 }, - { 151, 101, 208, 1 }, - { 93, 20, 175, 0 }, }, - { { 133, 211, 119, 0 }, - { 114, 214, 93, 0 }, - { 119, 101, 208, 1 }, - { 93, 53, 167, 0 }, }, - { { 133, 210, 152, 0 }, - { 114, 16, 108, 1 }, - { 12, 165, 208, 1 }, - { 155, 4, 39, 0 }, }, - { { 133, 210, 155, 1 }, - { 122, 82, 108, 1 }, - { 236, 165, 208, 1 }, - { 155, 37, 47, 0 }, }, - { { 133, 210, 148, 1 }, - { 122, 16, 124, 0 }, - { 148, 165, 208, 1 }, - { 31, 4, 47, 0 }, }, - { { 133, 210, 151, 0 }, - { 114, 82, 124, 0 }, - { 116, 165, 208, 1 }, - { 31, 37, 39, 0 }, }, - { { 133, 210, 232, 0 }, - { 98, 148, 108, 1 }, - { 11, 165, 208, 1 }, - { 155, 20, 163, 0 }, }, - { { 133, 210, 235, 1 }, - { 106, 214, 108, 1 }, - { 235, 165, 208, 1 }, - { 155, 53, 171, 0 }, }, - { { 133, 210, 228, 1 }, - { 106, 148, 124, 0 }, - { 147, 165, 208, 1 }, - { 31, 20, 171, 0 }, }, - { { 133, 210, 231, 0 }, - { 98, 214, 124, 0 }, - { 115, 165, 208, 1 }, - { 31, 53, 163, 0 }, }, - { { 133, 221, 8, 0 }, - { 67, 24, 77, 1 }, - { 8, 93, 208, 1 }, - { 217, 12, 97, 0 }, }, - { { 133, 221, 11, 1 }, - { 75, 90, 77, 1 }, - { 232, 93, 208, 1 }, - { 217, 45, 105, 0 }, }, - { { 133, 221, 4, 1 }, - { 75, 24, 93, 0 }, - { 144, 93, 208, 1 }, - { 93, 12, 105, 0 }, }, - { { 133, 221, 7, 0 }, - { 67, 90, 93, 0 }, - { 112, 93, 208, 1 }, - { 93, 45, 97, 0 }, }, - { { 133, 221, 120, 0 }, - { 83, 156, 77, 1 }, - { 15, 93, 208, 1 }, - { 217, 28, 229, 0 }, }, - { { 133, 221, 123, 1 }, - { 91, 222, 77, 1 }, - { 239, 93, 208, 1 }, - { 217, 61, 237, 0 }, }, - { { 133, 221, 116, 1 }, - { 91, 156, 93, 0 }, - { 151, 93, 208, 1 }, - { 93, 28, 237, 0 }, }, - { { 133, 221, 119, 0 }, - { 83, 222, 93, 0 }, - { 119, 93, 208, 1 }, - { 93, 61, 229, 0 }, }, - { { 133, 220, 152, 0 }, - { 83, 24, 108, 1 }, - { 12, 157, 208, 1 }, - { 155, 12, 101, 0 }, }, - { { 133, 220, 155, 1 }, - { 91, 90, 108, 1 }, - { 236, 157, 208, 1 }, - { 155, 45, 109, 0 }, }, - { { 133, 220, 148, 1 }, - { 91, 24, 124, 0 }, - { 148, 157, 208, 1 }, - { 31, 12, 109, 0 }, }, - { { 133, 220, 151, 0 }, - { 83, 90, 124, 0 }, - { 116, 157, 208, 1 }, - { 31, 45, 101, 0 }, }, - { { 133, 220, 232, 0 }, - { 67, 156, 108, 1 }, - { 11, 157, 208, 1 }, - { 155, 28, 225, 0 }, }, - { { 133, 220, 235, 1 }, - { 75, 222, 108, 1 }, - { 235, 157, 208, 1 }, - { 155, 61, 233, 0 }, }, - { { 133, 220, 228, 1 }, - { 75, 156, 124, 0 }, - { 147, 157, 208, 1 }, - { 31, 28, 233, 0 }, }, - { { 133, 220, 231, 0 }, - { 67, 222, 124, 0 }, - { 115, 157, 208, 1 }, - { 31, 61, 225, 0 }, }, - { { 130, 97, 8, 0 }, - { 64, 0, 139, 1 }, - { 8, 67, 32, 1 }, - { 232, 128, 1, 0 }, }, - { { 130, 97, 11, 1 }, - { 72, 66, 139, 1 }, - { 232, 67, 32, 1 }, - { 232, 161, 9, 0 }, }, - { { 130, 97, 4, 1 }, - { 72, 0, 155, 0 }, - { 144, 67, 32, 1 }, - { 108, 128, 9, 0 }, }, - { { 130, 97, 7, 0 }, - { 64, 66, 155, 0 }, - { 112, 67, 32, 1 }, - { 108, 161, 1, 0 }, }, - { { 130, 97, 120, 0 }, - { 80, 132, 139, 1 }, - { 15, 67, 32, 1 }, - { 232, 144, 133, 0 }, }, - { { 130, 97, 123, 1 }, - { 88, 198, 139, 1 }, - { 239, 67, 32, 1 }, - { 232, 177, 141, 0 }, }, - { { 130, 97, 116, 1 }, - { 88, 132, 155, 0 }, - { 151, 67, 32, 1 }, - { 108, 144, 141, 0 }, }, - { { 130, 97, 119, 0 }, - { 80, 198, 155, 0 }, - { 119, 67, 32, 1 }, - { 108, 177, 133, 0 }, }, - { { 130, 96, 152, 0 }, - { 80, 0, 170, 1 }, - { 12, 131, 32, 1 }, - { 170, 128, 5, 0 }, }, - { { 130, 96, 155, 1 }, - { 88, 66, 170, 1 }, - { 236, 131, 32, 1 }, - { 170, 161, 13, 0 }, }, - { { 130, 96, 148, 1 }, - { 88, 0, 186, 0 }, - { 148, 131, 32, 1 }, - { 46, 128, 13, 0 }, }, - { { 130, 96, 151, 0 }, - { 80, 66, 186, 0 }, - { 116, 131, 32, 1 }, - { 46, 161, 5, 0 }, }, - { { 130, 96, 232, 0 }, - { 64, 132, 170, 1 }, - { 11, 131, 32, 1 }, - { 170, 144, 129, 0 }, }, - { { 130, 96, 235, 1 }, - { 72, 198, 170, 1 }, - { 235, 131, 32, 1 }, - { 170, 177, 137, 0 }, }, - { { 130, 96, 228, 1 }, - { 72, 132, 186, 0 }, - { 147, 131, 32, 1 }, - { 46, 144, 137, 0 }, }, - { { 130, 96, 231, 0 }, - { 64, 198, 186, 0 }, - { 115, 131, 32, 1 }, - { 46, 177, 129, 0 }, }, - { { 130, 111, 8, 0 }, - { 97, 8, 139, 1 }, - { 8, 123, 32, 1 }, - { 232, 136, 67, 0 }, }, - { { 130, 111, 11, 1 }, - { 105, 74, 139, 1 }, - { 232, 123, 32, 1 }, - { 232, 169, 75, 0 }, }, - { { 130, 111, 4, 1 }, - { 105, 8, 155, 0 }, - { 144, 123, 32, 1 }, - { 108, 136, 75, 0 }, }, - { { 130, 111, 7, 0 }, - { 97, 74, 155, 0 }, - { 112, 123, 32, 1 }, - { 108, 169, 67, 0 }, }, - { { 130, 111, 120, 0 }, - { 113, 140, 139, 1 }, - { 15, 123, 32, 1 }, - { 232, 152, 199, 0 }, }, - { { 130, 111, 123, 1 }, - { 121, 206, 139, 1 }, - { 239, 123, 32, 1 }, - { 232, 185, 207, 0 }, }, - { { 130, 111, 116, 1 }, - { 121, 140, 155, 0 }, - { 151, 123, 32, 1 }, - { 108, 152, 207, 0 }, }, - { { 130, 111, 119, 0 }, - { 113, 206, 155, 0 }, - { 119, 123, 32, 1 }, - { 108, 185, 199, 0 }, }, - { { 130, 110, 152, 0 }, - { 113, 8, 170, 1 }, - { 12, 187, 32, 1 }, - { 170, 136, 71, 0 }, }, - { { 130, 110, 155, 1 }, - { 121, 74, 170, 1 }, - { 236, 187, 32, 1 }, - { 170, 169, 79, 0 }, }, - { { 130, 110, 148, 1 }, - { 121, 8, 186, 0 }, - { 148, 187, 32, 1 }, - { 46, 136, 79, 0 }, }, - { { 130, 110, 151, 0 }, - { 113, 74, 186, 0 }, - { 116, 187, 32, 1 }, - { 46, 169, 71, 0 }, }, - { { 130, 110, 232, 0 }, - { 97, 140, 170, 1 }, - { 11, 187, 32, 1 }, - { 170, 152, 195, 0 }, }, - { { 130, 110, 235, 1 }, - { 105, 206, 170, 1 }, - { 235, 187, 32, 1 }, - { 170, 185, 203, 0 }, }, - { { 130, 110, 228, 1 }, - { 105, 140, 186, 0 }, - { 147, 187, 32, 1 }, - { 46, 152, 203, 0 }, }, - { { 130, 110, 231, 0 }, - { 97, 206, 186, 0 }, - { 115, 187, 32, 1 }, - { 46, 185, 195, 0 }, }, - { { 130, 83, 8, 0 }, - { 96, 0, 201, 1 }, - { 8, 101, 32, 1 }, - { 201, 128, 3, 0 }, }, - { { 130, 83, 11, 1 }, - { 104, 66, 201, 1 }, - { 232, 101, 32, 1 }, - { 201, 161, 11, 0 }, }, - { { 130, 83, 4, 1 }, - { 104, 0, 217, 0 }, - { 144, 101, 32, 1 }, - { 77, 128, 11, 0 }, }, - { { 130, 83, 7, 0 }, - { 96, 66, 217, 0 }, - { 112, 101, 32, 1 }, - { 77, 161, 3, 0 }, }, - { { 130, 83, 120, 0 }, - { 112, 132, 201, 1 }, - { 15, 101, 32, 1 }, - { 201, 144, 135, 0 }, }, - { { 130, 83, 123, 1 }, - { 120, 198, 201, 1 }, - { 239, 101, 32, 1 }, - { 201, 177, 143, 0 }, }, - { { 130, 83, 116, 1 }, - { 120, 132, 217, 0 }, - { 151, 101, 32, 1 }, - { 77, 144, 143, 0 }, }, - { { 130, 83, 119, 0 }, - { 112, 198, 217, 0 }, - { 119, 101, 32, 1 }, - { 77, 177, 135, 0 }, }, - { { 130, 82, 152, 0 }, - { 112, 0, 232, 1 }, - { 12, 165, 32, 1 }, - { 139, 128, 7, 0 }, }, - { { 130, 82, 155, 1 }, - { 120, 66, 232, 1 }, - { 236, 165, 32, 1 }, - { 139, 161, 15, 0 }, }, - { { 130, 82, 148, 1 }, - { 120, 0, 248, 0 }, - { 148, 165, 32, 1 }, - { 15, 128, 15, 0 }, }, - { { 130, 82, 151, 0 }, - { 112, 66, 248, 0 }, - { 116, 165, 32, 1 }, - { 15, 161, 7, 0 }, }, - { { 130, 82, 232, 0 }, - { 96, 132, 232, 1 }, - { 11, 165, 32, 1 }, - { 139, 144, 131, 0 }, }, - { { 130, 82, 235, 1 }, - { 104, 198, 232, 1 }, - { 235, 165, 32, 1 }, - { 139, 177, 139, 0 }, }, - { { 130, 82, 228, 1 }, - { 104, 132, 248, 0 }, - { 147, 165, 32, 1 }, - { 15, 144, 139, 0 }, }, - { { 130, 82, 231, 0 }, - { 96, 198, 248, 0 }, - { 115, 165, 32, 1 }, - { 15, 177, 131, 0 }, }, - { { 130, 93, 8, 0 }, - { 65, 8, 201, 1 }, - { 8, 93, 32, 1 }, - { 201, 136, 65, 0 }, }, - { { 130, 93, 11, 1 }, - { 73, 74, 201, 1 }, - { 232, 93, 32, 1 }, - { 201, 169, 73, 0 }, }, - { { 130, 93, 4, 1 }, - { 73, 8, 217, 0 }, - { 144, 93, 32, 1 }, - { 77, 136, 73, 0 }, }, - { { 130, 93, 7, 0 }, - { 65, 74, 217, 0 }, - { 112, 93, 32, 1 }, - { 77, 169, 65, 0 }, }, - { { 130, 93, 120, 0 }, - { 81, 140, 201, 1 }, - { 15, 93, 32, 1 }, - { 201, 152, 197, 0 }, }, - { { 130, 93, 123, 1 }, - { 89, 206, 201, 1 }, - { 239, 93, 32, 1 }, - { 201, 185, 205, 0 }, }, - { { 130, 93, 116, 1 }, - { 89, 140, 217, 0 }, - { 151, 93, 32, 1 }, - { 77, 152, 205, 0 }, }, - { { 130, 93, 119, 0 }, - { 81, 206, 217, 0 }, - { 119, 93, 32, 1 }, - { 77, 185, 197, 0 }, }, - { { 130, 92, 152, 0 }, - { 81, 8, 232, 1 }, - { 12, 157, 32, 1 }, - { 139, 136, 69, 0 }, }, - { { 130, 92, 155, 1 }, - { 89, 74, 232, 1 }, - { 236, 157, 32, 1 }, - { 139, 169, 77, 0 }, }, - { { 130, 92, 148, 1 }, - { 89, 8, 248, 0 }, - { 148, 157, 32, 1 }, - { 15, 136, 77, 0 }, }, - { { 130, 92, 151, 0 }, - { 81, 74, 248, 0 }, - { 116, 157, 32, 1 }, - { 15, 169, 69, 0 }, }, - { { 130, 92, 232, 0 }, - { 65, 140, 232, 1 }, - { 11, 157, 32, 1 }, - { 139, 152, 193, 0 }, }, - { { 130, 92, 235, 1 }, - { 73, 206, 232, 1 }, - { 235, 157, 32, 1 }, - { 139, 185, 201, 0 }, }, - { { 130, 92, 228, 1 }, - { 73, 140, 248, 0 }, - { 147, 157, 32, 1 }, - { 15, 152, 201, 0 }, }, - { { 130, 92, 231, 0 }, - { 65, 206, 248, 0 }, - { 115, 157, 32, 1 }, - { 15, 185, 193, 0 }, }, - { { 131, 161, 8, 0 }, - { 2, 16, 139, 1 }, - { 8, 66, 224, 1 }, - { 232, 132, 32, 0 }, }, - { { 131, 161, 11, 1 }, - { 10, 82, 139, 1 }, - { 232, 66, 224, 1 }, - { 232, 165, 40, 0 }, }, - { { 131, 161, 4, 1 }, - { 10, 16, 155, 0 }, - { 144, 66, 224, 1 }, - { 108, 132, 40, 0 }, }, - { { 131, 161, 7, 0 }, - { 2, 82, 155, 0 }, - { 112, 66, 224, 1 }, - { 108, 165, 32, 0 }, }, - { { 131, 161, 120, 0 }, - { 18, 148, 139, 1 }, - { 15, 66, 224, 1 }, - { 232, 148, 164, 0 }, }, - { { 131, 161, 123, 1 }, - { 26, 214, 139, 1 }, - { 239, 66, 224, 1 }, - { 232, 181, 172, 0 }, }, - { { 131, 161, 116, 1 }, - { 26, 148, 155, 0 }, - { 151, 66, 224, 1 }, - { 108, 148, 172, 0 }, }, - { { 131, 161, 119, 0 }, - { 18, 214, 155, 0 }, - { 119, 66, 224, 1 }, - { 108, 181, 164, 0 }, }, - { { 131, 160, 152, 0 }, - { 18, 16, 170, 1 }, - { 12, 130, 224, 1 }, - { 170, 132, 36, 0 }, }, - { { 131, 160, 155, 1 }, - { 26, 82, 170, 1 }, - { 236, 130, 224, 1 }, - { 170, 165, 44, 0 }, }, - { { 131, 160, 148, 1 }, - { 26, 16, 186, 0 }, - { 148, 130, 224, 1 }, - { 46, 132, 44, 0 }, }, - { { 131, 160, 151, 0 }, - { 18, 82, 186, 0 }, - { 116, 130, 224, 1 }, - { 46, 165, 36, 0 }, }, - { { 131, 160, 232, 0 }, - { 2, 148, 170, 1 }, - { 11, 130, 224, 1 }, - { 170, 148, 160, 0 }, }, - { { 131, 160, 235, 1 }, - { 10, 214, 170, 1 }, - { 235, 130, 224, 1 }, - { 170, 181, 168, 0 }, }, - { { 131, 160, 228, 1 }, - { 10, 148, 186, 0 }, - { 147, 130, 224, 1 }, - { 46, 148, 168, 0 }, }, - { { 131, 160, 231, 0 }, - { 2, 214, 186, 0 }, - { 115, 130, 224, 1 }, - { 46, 181, 160, 0 }, }, - { { 131, 175, 8, 0 }, - { 35, 24, 139, 1 }, - { 8, 122, 224, 1 }, - { 232, 140, 98, 0 }, }, - { { 131, 175, 11, 1 }, - { 43, 90, 139, 1 }, - { 232, 122, 224, 1 }, - { 232, 173, 106, 0 }, }, - { { 131, 175, 4, 1 }, - { 43, 24, 155, 0 }, - { 144, 122, 224, 1 }, - { 108, 140, 106, 0 }, }, - { { 131, 175, 7, 0 }, - { 35, 90, 155, 0 }, - { 112, 122, 224, 1 }, - { 108, 173, 98, 0 }, }, - { { 131, 175, 120, 0 }, - { 51, 156, 139, 1 }, - { 15, 122, 224, 1 }, - { 232, 156, 230, 0 }, }, - { { 131, 175, 123, 1 }, - { 59, 222, 139, 1 }, - { 239, 122, 224, 1 }, - { 232, 189, 238, 0 }, }, - { { 131, 175, 116, 1 }, - { 59, 156, 155, 0 }, - { 151, 122, 224, 1 }, - { 108, 156, 238, 0 }, }, - { { 131, 175, 119, 0 }, - { 51, 222, 155, 0 }, - { 119, 122, 224, 1 }, - { 108, 189, 230, 0 }, }, - { { 131, 174, 152, 0 }, - { 51, 24, 170, 1 }, - { 12, 186, 224, 1 }, - { 170, 140, 102, 0 }, }, - { { 131, 174, 155, 1 }, - { 59, 90, 170, 1 }, - { 236, 186, 224, 1 }, - { 170, 173, 110, 0 }, }, - { { 131, 174, 148, 1 }, - { 59, 24, 186, 0 }, - { 148, 186, 224, 1 }, - { 46, 140, 110, 0 }, }, - { { 131, 174, 151, 0 }, - { 51, 90, 186, 0 }, - { 116, 186, 224, 1 }, - { 46, 173, 102, 0 }, }, - { { 131, 174, 232, 0 }, - { 35, 156, 170, 1 }, - { 11, 186, 224, 1 }, - { 170, 156, 226, 0 }, }, - { { 131, 174, 235, 1 }, - { 43, 222, 170, 1 }, - { 235, 186, 224, 1 }, - { 170, 189, 234, 0 }, }, - { { 131, 174, 228, 1 }, - { 43, 156, 186, 0 }, - { 147, 186, 224, 1 }, - { 46, 156, 234, 0 }, }, - { { 131, 174, 231, 0 }, - { 35, 222, 186, 0 }, - { 115, 186, 224, 1 }, - { 46, 189, 226, 0 }, }, - { { 131, 147, 8, 0 }, - { 34, 16, 201, 1 }, - { 8, 100, 224, 1 }, - { 201, 132, 34, 0 }, }, - { { 131, 147, 11, 1 }, - { 42, 82, 201, 1 }, - { 232, 100, 224, 1 }, - { 201, 165, 42, 0 }, }, - { { 131, 147, 4, 1 }, - { 42, 16, 217, 0 }, - { 144, 100, 224, 1 }, - { 77, 132, 42, 0 }, }, - { { 131, 147, 7, 0 }, - { 34, 82, 217, 0 }, - { 112, 100, 224, 1 }, - { 77, 165, 34, 0 }, }, - { { 131, 147, 120, 0 }, - { 50, 148, 201, 1 }, - { 15, 100, 224, 1 }, - { 201, 148, 166, 0 }, }, - { { 131, 147, 123, 1 }, - { 58, 214, 201, 1 }, - { 239, 100, 224, 1 }, - { 201, 181, 174, 0 }, }, - { { 131, 147, 116, 1 }, - { 58, 148, 217, 0 }, - { 151, 100, 224, 1 }, - { 77, 148, 174, 0 }, }, - { { 131, 147, 119, 0 }, - { 50, 214, 217, 0 }, - { 119, 100, 224, 1 }, - { 77, 181, 166, 0 }, }, - { { 131, 146, 152, 0 }, - { 50, 16, 232, 1 }, - { 12, 164, 224, 1 }, - { 139, 132, 38, 0 }, }, - { { 131, 146, 155, 1 }, - { 58, 82, 232, 1 }, - { 236, 164, 224, 1 }, - { 139, 165, 46, 0 }, }, - { { 131, 146, 148, 1 }, - { 58, 16, 248, 0 }, - { 148, 164, 224, 1 }, - { 15, 132, 46, 0 }, }, - { { 131, 146, 151, 0 }, - { 50, 82, 248, 0 }, - { 116, 164, 224, 1 }, - { 15, 165, 38, 0 }, }, - { { 131, 146, 232, 0 }, - { 34, 148, 232, 1 }, - { 11, 164, 224, 1 }, - { 139, 148, 162, 0 }, }, - { { 131, 146, 235, 1 }, - { 42, 214, 232, 1 }, - { 235, 164, 224, 1 }, - { 139, 181, 170, 0 }, }, - { { 131, 146, 228, 1 }, - { 42, 148, 248, 0 }, - { 147, 164, 224, 1 }, - { 15, 148, 170, 0 }, }, - { { 131, 146, 231, 0 }, - { 34, 214, 248, 0 }, - { 115, 164, 224, 1 }, - { 15, 181, 162, 0 }, }, - { { 131, 157, 8, 0 }, - { 3, 24, 201, 1 }, - { 8, 92, 224, 1 }, - { 201, 140, 96, 0 }, }, - { { 131, 157, 11, 1 }, - { 11, 90, 201, 1 }, - { 232, 92, 224, 1 }, - { 201, 173, 104, 0 }, }, - { { 131, 157, 4, 1 }, - { 11, 24, 217, 0 }, - { 144, 92, 224, 1 }, - { 77, 140, 104, 0 }, }, - { { 131, 157, 7, 0 }, - { 3, 90, 217, 0 }, - { 112, 92, 224, 1 }, - { 77, 173, 96, 0 }, }, - { { 131, 157, 120, 0 }, - { 19, 156, 201, 1 }, - { 15, 92, 224, 1 }, - { 201, 156, 228, 0 }, }, - { { 131, 157, 123, 1 }, - { 27, 222, 201, 1 }, - { 239, 92, 224, 1 }, - { 201, 189, 236, 0 }, }, - { { 131, 157, 116, 1 }, - { 27, 156, 217, 0 }, - { 151, 92, 224, 1 }, - { 77, 156, 236, 0 }, }, - { { 131, 157, 119, 0 }, - { 19, 222, 217, 0 }, - { 119, 92, 224, 1 }, - { 77, 189, 228, 0 }, }, - { { 131, 156, 152, 0 }, - { 19, 24, 232, 1 }, - { 12, 156, 224, 1 }, - { 139, 140, 100, 0 }, }, - { { 131, 156, 155, 1 }, - { 27, 90, 232, 1 }, - { 236, 156, 224, 1 }, - { 139, 173, 108, 0 }, }, - { { 131, 156, 148, 1 }, - { 27, 24, 248, 0 }, - { 148, 156, 224, 1 }, - { 15, 140, 108, 0 }, }, - { { 131, 156, 151, 0 }, - { 19, 90, 248, 0 }, - { 116, 156, 224, 1 }, - { 15, 173, 100, 0 }, }, - { { 131, 156, 232, 0 }, - { 3, 156, 232, 1 }, - { 11, 156, 224, 1 }, - { 139, 156, 224, 0 }, }, - { { 131, 156, 235, 1 }, - { 11, 222, 232, 1 }, - { 235, 156, 224, 1 }, - { 139, 189, 232, 0 }, }, - { { 131, 156, 228, 1 }, - { 11, 156, 248, 0 }, - { 147, 156, 224, 1 }, - { 15, 156, 232, 0 }, }, - { { 131, 156, 231, 0 }, - { 3, 222, 248, 0 }, - { 115, 156, 224, 1 }, - { 15, 189, 224, 0 }, }, - { { 188, 33, 8, 0 }, - { 132, 32, 15, 1 }, - { 8, 66, 30, 1 }, - { 248, 2, 16, 1 }, }, - { { 188, 33, 11, 1 }, - { 140, 98, 15, 1 }, - { 232, 66, 30, 1 }, - { 248, 35, 24, 1 }, }, - { { 188, 33, 4, 1 }, - { 140, 32, 31, 0 }, - { 144, 66, 30, 1 }, - { 124, 2, 24, 1 }, }, - { { 188, 33, 7, 0 }, - { 132, 98, 31, 0 }, - { 112, 66, 30, 1 }, - { 124, 35, 16, 1 }, }, - { { 188, 33, 120, 0 }, - { 148, 164, 15, 1 }, - { 15, 66, 30, 1 }, - { 248, 18, 148, 1 }, }, - { { 188, 33, 123, 1 }, - { 156, 230, 15, 1 }, - { 239, 66, 30, 1 }, - { 248, 51, 156, 1 }, }, - { { 188, 33, 116, 1 }, - { 156, 164, 31, 0 }, - { 151, 66, 30, 1 }, - { 124, 18, 156, 1 }, }, - { { 188, 33, 119, 0 }, - { 148, 230, 31, 0 }, - { 119, 66, 30, 1 }, - { 124, 51, 148, 1 }, }, - { { 188, 32, 152, 0 }, - { 148, 32, 46, 1 }, - { 12, 130, 30, 1 }, - { 186, 2, 20, 1 }, }, - { { 188, 32, 155, 1 }, - { 156, 98, 46, 1 }, - { 236, 130, 30, 1 }, - { 186, 35, 28, 1 }, }, - { { 188, 32, 148, 1 }, - { 156, 32, 62, 0 }, - { 148, 130, 30, 1 }, - { 62, 2, 28, 1 }, }, - { { 188, 32, 151, 0 }, - { 148, 98, 62, 0 }, - { 116, 130, 30, 1 }, - { 62, 35, 20, 1 }, }, - { { 188, 32, 232, 0 }, - { 132, 164, 46, 1 }, - { 11, 130, 30, 1 }, - { 186, 18, 144, 1 }, }, - { { 188, 32, 235, 1 }, - { 140, 230, 46, 1 }, - { 235, 130, 30, 1 }, - { 186, 51, 152, 1 }, }, - { { 188, 32, 228, 1 }, - { 140, 164, 62, 0 }, - { 147, 130, 30, 1 }, - { 62, 18, 152, 1 }, }, - { { 188, 32, 231, 0 }, - { 132, 230, 62, 0 }, - { 115, 130, 30, 1 }, - { 62, 51, 144, 1 }, }, - { { 188, 47, 8, 0 }, - { 165, 40, 15, 1 }, - { 8, 122, 30, 1 }, - { 248, 10, 82, 1 }, }, - { { 188, 47, 11, 1 }, - { 173, 106, 15, 1 }, - { 232, 122, 30, 1 }, - { 248, 43, 90, 1 }, }, - { { 188, 47, 4, 1 }, - { 173, 40, 31, 0 }, - { 144, 122, 30, 1 }, - { 124, 10, 90, 1 }, }, - { { 188, 47, 7, 0 }, - { 165, 106, 31, 0 }, - { 112, 122, 30, 1 }, - { 124, 43, 82, 1 }, }, - { { 188, 47, 120, 0 }, - { 181, 172, 15, 1 }, - { 15, 122, 30, 1 }, - { 248, 26, 214, 1 }, }, - { { 188, 47, 123, 1 }, - { 189, 238, 15, 1 }, - { 239, 122, 30, 1 }, - { 248, 59, 222, 1 }, }, - { { 188, 47, 116, 1 }, - { 189, 172, 31, 0 }, - { 151, 122, 30, 1 }, - { 124, 26, 222, 1 }, }, - { { 188, 47, 119, 0 }, - { 181, 238, 31, 0 }, - { 119, 122, 30, 1 }, - { 124, 59, 214, 1 }, }, - { { 188, 46, 152, 0 }, - { 181, 40, 46, 1 }, - { 12, 186, 30, 1 }, - { 186, 10, 86, 1 }, }, - { { 188, 46, 155, 1 }, - { 189, 106, 46, 1 }, - { 236, 186, 30, 1 }, - { 186, 43, 94, 1 }, }, - { { 188, 46, 148, 1 }, - { 189, 40, 62, 0 }, - { 148, 186, 30, 1 }, - { 62, 10, 94, 1 }, }, - { { 188, 46, 151, 0 }, - { 181, 106, 62, 0 }, - { 116, 186, 30, 1 }, - { 62, 43, 86, 1 }, }, - { { 188, 46, 232, 0 }, - { 165, 172, 46, 1 }, - { 11, 186, 30, 1 }, - { 186, 26, 210, 1 }, }, - { { 188, 46, 235, 1 }, - { 173, 238, 46, 1 }, - { 235, 186, 30, 1 }, - { 186, 59, 218, 1 }, }, - { { 188, 46, 228, 1 }, - { 173, 172, 62, 0 }, - { 147, 186, 30, 1 }, - { 62, 26, 218, 1 }, }, - { { 188, 46, 231, 0 }, - { 165, 238, 62, 0 }, - { 115, 186, 30, 1 }, - { 62, 59, 210, 1 }, }, - { { 188, 19, 8, 0 }, - { 164, 32, 77, 1 }, - { 8, 100, 30, 1 }, - { 217, 2, 18, 1 }, }, - { { 188, 19, 11, 1 }, - { 172, 98, 77, 1 }, - { 232, 100, 30, 1 }, - { 217, 35, 26, 1 }, }, - { { 188, 19, 4, 1 }, - { 172, 32, 93, 0 }, - { 144, 100, 30, 1 }, - { 93, 2, 26, 1 }, }, - { { 188, 19, 7, 0 }, - { 164, 98, 93, 0 }, - { 112, 100, 30, 1 }, - { 93, 35, 18, 1 }, }, - { { 188, 19, 120, 0 }, - { 180, 164, 77, 1 }, - { 15, 100, 30, 1 }, - { 217, 18, 150, 1 }, }, - { { 188, 19, 123, 1 }, - { 188, 230, 77, 1 }, - { 239, 100, 30, 1 }, - { 217, 51, 158, 1 }, }, - { { 188, 19, 116, 1 }, - { 188, 164, 93, 0 }, - { 151, 100, 30, 1 }, - { 93, 18, 158, 1 }, }, - { { 188, 19, 119, 0 }, - { 180, 230, 93, 0 }, - { 119, 100, 30, 1 }, - { 93, 51, 150, 1 }, }, - { { 188, 18, 152, 0 }, - { 180, 32, 108, 1 }, - { 12, 164, 30, 1 }, - { 155, 2, 22, 1 }, }, - { { 188, 18, 155, 1 }, - { 188, 98, 108, 1 }, - { 236, 164, 30, 1 }, - { 155, 35, 30, 1 }, }, - { { 188, 18, 148, 1 }, - { 188, 32, 124, 0 }, - { 148, 164, 30, 1 }, - { 31, 2, 30, 1 }, }, - { { 188, 18, 151, 0 }, - { 180, 98, 124, 0 }, - { 116, 164, 30, 1 }, - { 31, 35, 22, 1 }, }, - { { 188, 18, 232, 0 }, - { 164, 164, 108, 1 }, - { 11, 164, 30, 1 }, - { 155, 18, 146, 1 }, }, - { { 188, 18, 235, 1 }, - { 172, 230, 108, 1 }, - { 235, 164, 30, 1 }, - { 155, 51, 154, 1 }, }, - { { 188, 18, 228, 1 }, - { 172, 164, 124, 0 }, - { 147, 164, 30, 1 }, - { 31, 18, 154, 1 }, }, - { { 188, 18, 231, 0 }, - { 164, 230, 124, 0 }, - { 115, 164, 30, 1 }, - { 31, 51, 146, 1 }, }, - { { 188, 29, 8, 0 }, - { 133, 40, 77, 1 }, - { 8, 92, 30, 1 }, - { 217, 10, 80, 1 }, }, - { { 188, 29, 11, 1 }, - { 141, 106, 77, 1 }, - { 232, 92, 30, 1 }, - { 217, 43, 88, 1 }, }, - { { 188, 29, 4, 1 }, - { 141, 40, 93, 0 }, - { 144, 92, 30, 1 }, - { 93, 10, 88, 1 }, }, - { { 188, 29, 7, 0 }, - { 133, 106, 93, 0 }, - { 112, 92, 30, 1 }, - { 93, 43, 80, 1 }, }, - { { 188, 29, 120, 0 }, - { 149, 172, 77, 1 }, - { 15, 92, 30, 1 }, - { 217, 26, 212, 1 }, }, - { { 188, 29, 123, 1 }, - { 157, 238, 77, 1 }, - { 239, 92, 30, 1 }, - { 217, 59, 220, 1 }, }, - { { 188, 29, 116, 1 }, - { 157, 172, 93, 0 }, - { 151, 92, 30, 1 }, - { 93, 26, 220, 1 }, }, - { { 188, 29, 119, 0 }, - { 149, 238, 93, 0 }, - { 119, 92, 30, 1 }, - { 93, 59, 212, 1 }, }, - { { 188, 28, 152, 0 }, - { 149, 40, 108, 1 }, - { 12, 156, 30, 1 }, - { 155, 10, 84, 1 }, }, - { { 188, 28, 155, 1 }, - { 157, 106, 108, 1 }, - { 236, 156, 30, 1 }, - { 155, 43, 92, 1 }, }, - { { 188, 28, 148, 1 }, - { 157, 40, 124, 0 }, - { 148, 156, 30, 1 }, - { 31, 10, 92, 1 }, }, - { { 188, 28, 151, 0 }, - { 149, 106, 124, 0 }, - { 116, 156, 30, 1 }, - { 31, 43, 84, 1 }, }, - { { 188, 28, 232, 0 }, - { 133, 172, 108, 1 }, - { 11, 156, 30, 1 }, - { 155, 26, 208, 1 }, }, - { { 188, 28, 235, 1 }, - { 141, 238, 108, 1 }, - { 235, 156, 30, 1 }, - { 155, 59, 216, 1 }, }, - { { 188, 28, 228, 1 }, - { 141, 172, 124, 0 }, - { 147, 156, 30, 1 }, - { 31, 26, 216, 1 }, }, - { { 188, 28, 231, 0 }, - { 133, 238, 124, 0 }, - { 115, 156, 30, 1 }, - { 31, 59, 208, 1 }, }, - { { 189, 225, 8, 0 }, - { 198, 48, 15, 1 }, - { 8, 67, 222, 1 }, - { 248, 6, 49, 1 }, }, - { { 189, 225, 11, 1 }, - { 206, 114, 15, 1 }, - { 232, 67, 222, 1 }, - { 248, 39, 57, 1 }, }, - { { 189, 225, 4, 1 }, - { 206, 48, 31, 0 }, - { 144, 67, 222, 1 }, - { 124, 6, 57, 1 }, }, - { { 189, 225, 7, 0 }, - { 198, 114, 31, 0 }, - { 112, 67, 222, 1 }, - { 124, 39, 49, 1 }, }, - { { 189, 225, 120, 0 }, - { 214, 180, 15, 1 }, - { 15, 67, 222, 1 }, - { 248, 22, 181, 1 }, }, - { { 189, 225, 123, 1 }, - { 222, 246, 15, 1 }, - { 239, 67, 222, 1 }, - { 248, 55, 189, 1 }, }, - { { 189, 225, 116, 1 }, - { 222, 180, 31, 0 }, - { 151, 67, 222, 1 }, - { 124, 22, 189, 1 }, }, - { { 189, 225, 119, 0 }, - { 214, 246, 31, 0 }, - { 119, 67, 222, 1 }, - { 124, 55, 181, 1 }, }, - { { 189, 224, 152, 0 }, - { 214, 48, 46, 1 }, - { 12, 131, 222, 1 }, - { 186, 6, 53, 1 }, }, - { { 189, 224, 155, 1 }, - { 222, 114, 46, 1 }, - { 236, 131, 222, 1 }, - { 186, 39, 61, 1 }, }, - { { 189, 224, 148, 1 }, - { 222, 48, 62, 0 }, - { 148, 131, 222, 1 }, - { 62, 6, 61, 1 }, }, - { { 189, 224, 151, 0 }, - { 214, 114, 62, 0 }, - { 116, 131, 222, 1 }, - { 62, 39, 53, 1 }, }, - { { 189, 224, 232, 0 }, - { 198, 180, 46, 1 }, - { 11, 131, 222, 1 }, - { 186, 22, 177, 1 }, }, - { { 189, 224, 235, 1 }, - { 206, 246, 46, 1 }, - { 235, 131, 222, 1 }, - { 186, 55, 185, 1 }, }, - { { 189, 224, 228, 1 }, - { 206, 180, 62, 0 }, - { 147, 131, 222, 1 }, - { 62, 22, 185, 1 }, }, - { { 189, 224, 231, 0 }, - { 198, 246, 62, 0 }, - { 115, 131, 222, 1 }, - { 62, 55, 177, 1 }, }, - { { 189, 239, 8, 0 }, - { 231, 56, 15, 1 }, - { 8, 123, 222, 1 }, - { 248, 14, 115, 1 }, }, - { { 189, 239, 11, 1 }, - { 239, 122, 15, 1 }, - { 232, 123, 222, 1 }, - { 248, 47, 123, 1 }, }, - { { 189, 239, 4, 1 }, - { 239, 56, 31, 0 }, - { 144, 123, 222, 1 }, - { 124, 14, 123, 1 }, }, - { { 189, 239, 7, 0 }, - { 231, 122, 31, 0 }, - { 112, 123, 222, 1 }, - { 124, 47, 115, 1 }, }, - { { 189, 239, 120, 0 }, - { 247, 188, 15, 1 }, - { 15, 123, 222, 1 }, - { 248, 30, 247, 1 }, }, - { { 189, 239, 123, 1 }, - { 255, 254, 15, 1 }, - { 239, 123, 222, 1 }, - { 248, 63, 255, 1 }, }, - { { 189, 239, 116, 1 }, - { 255, 188, 31, 0 }, - { 151, 123, 222, 1 }, - { 124, 30, 255, 1 }, }, - { { 189, 239, 119, 0 }, - { 247, 254, 31, 0 }, - { 119, 123, 222, 1 }, - { 124, 63, 247, 1 }, }, - { { 189, 238, 152, 0 }, - { 247, 56, 46, 1 }, - { 12, 187, 222, 1 }, - { 186, 14, 119, 1 }, }, - { { 189, 238, 155, 1 }, - { 255, 122, 46, 1 }, - { 236, 187, 222, 1 }, - { 186, 47, 127, 1 }, }, - { { 189, 238, 148, 1 }, - { 255, 56, 62, 0 }, - { 148, 187, 222, 1 }, - { 62, 14, 127, 1 }, }, - { { 189, 238, 151, 0 }, - { 247, 122, 62, 0 }, - { 116, 187, 222, 1 }, - { 62, 47, 119, 1 }, }, - { { 189, 238, 232, 0 }, - { 231, 188, 46, 1 }, - { 11, 187, 222, 1 }, - { 186, 30, 243, 1 }, }, - { { 189, 238, 235, 1 }, - { 239, 254, 46, 1 }, - { 235, 187, 222, 1 }, - { 186, 63, 251, 1 }, }, - { { 189, 238, 228, 1 }, - { 239, 188, 62, 0 }, - { 147, 187, 222, 1 }, - { 62, 30, 251, 1 }, }, - { { 189, 238, 231, 0 }, - { 231, 254, 62, 0 }, - { 115, 187, 222, 1 }, - { 62, 63, 243, 1 }, }, - { { 189, 211, 8, 0 }, - { 230, 48, 77, 1 }, - { 8, 101, 222, 1 }, - { 217, 6, 51, 1 }, }, - { { 189, 211, 11, 1 }, - { 238, 114, 77, 1 }, - { 232, 101, 222, 1 }, - { 217, 39, 59, 1 }, }, - { { 189, 211, 4, 1 }, - { 238, 48, 93, 0 }, - { 144, 101, 222, 1 }, - { 93, 6, 59, 1 }, }, - { { 189, 211, 7, 0 }, - { 230, 114, 93, 0 }, - { 112, 101, 222, 1 }, - { 93, 39, 51, 1 }, }, - { { 189, 211, 120, 0 }, - { 246, 180, 77, 1 }, - { 15, 101, 222, 1 }, - { 217, 22, 183, 1 }, }, - { { 189, 211, 123, 1 }, - { 254, 246, 77, 1 }, - { 239, 101, 222, 1 }, - { 217, 55, 191, 1 }, }, - { { 189, 211, 116, 1 }, - { 254, 180, 93, 0 }, - { 151, 101, 222, 1 }, - { 93, 22, 191, 1 }, }, - { { 189, 211, 119, 0 }, - { 246, 246, 93, 0 }, - { 119, 101, 222, 1 }, - { 93, 55, 183, 1 }, }, - { { 189, 210, 152, 0 }, - { 246, 48, 108, 1 }, - { 12, 165, 222, 1 }, - { 155, 6, 55, 1 }, }, - { { 189, 210, 155, 1 }, - { 254, 114, 108, 1 }, - { 236, 165, 222, 1 }, - { 155, 39, 63, 1 }, }, - { { 189, 210, 148, 1 }, - { 254, 48, 124, 0 }, - { 148, 165, 222, 1 }, - { 31, 6, 63, 1 }, }, - { { 189, 210, 151, 0 }, - { 246, 114, 124, 0 }, - { 116, 165, 222, 1 }, - { 31, 39, 55, 1 }, }, - { { 189, 210, 232, 0 }, - { 230, 180, 108, 1 }, - { 11, 165, 222, 1 }, - { 155, 22, 179, 1 }, }, - { { 189, 210, 235, 1 }, - { 238, 246, 108, 1 }, - { 235, 165, 222, 1 }, - { 155, 55, 187, 1 }, }, - { { 189, 210, 228, 1 }, - { 238, 180, 124, 0 }, - { 147, 165, 222, 1 }, - { 31, 22, 187, 1 }, }, - { { 189, 210, 231, 0 }, - { 230, 246, 124, 0 }, - { 115, 165, 222, 1 }, - { 31, 55, 179, 1 }, }, - { { 189, 221, 8, 0 }, - { 199, 56, 77, 1 }, - { 8, 93, 222, 1 }, - { 217, 14, 113, 1 }, }, - { { 189, 221, 11, 1 }, - { 207, 122, 77, 1 }, - { 232, 93, 222, 1 }, - { 217, 47, 121, 1 }, }, - { { 189, 221, 4, 1 }, - { 207, 56, 93, 0 }, - { 144, 93, 222, 1 }, - { 93, 14, 121, 1 }, }, - { { 189, 221, 7, 0 }, - { 199, 122, 93, 0 }, - { 112, 93, 222, 1 }, - { 93, 47, 113, 1 }, }, - { { 189, 221, 120, 0 }, - { 215, 188, 77, 1 }, - { 15, 93, 222, 1 }, - { 217, 30, 245, 1 }, }, - { { 189, 221, 123, 1 }, - { 223, 254, 77, 1 }, - { 239, 93, 222, 1 }, - { 217, 63, 253, 1 }, }, - { { 189, 221, 116, 1 }, - { 223, 188, 93, 0 }, - { 151, 93, 222, 1 }, - { 93, 30, 253, 1 }, }, - { { 189, 221, 119, 0 }, - { 215, 254, 93, 0 }, - { 119, 93, 222, 1 }, - { 93, 63, 245, 1 }, }, - { { 189, 220, 152, 0 }, - { 215, 56, 108, 1 }, - { 12, 157, 222, 1 }, - { 155, 14, 117, 1 }, }, - { { 189, 220, 155, 1 }, - { 223, 122, 108, 1 }, - { 236, 157, 222, 1 }, - { 155, 47, 125, 1 }, }, - { { 189, 220, 148, 1 }, - { 223, 56, 124, 0 }, - { 148, 157, 222, 1 }, - { 31, 14, 125, 1 }, }, - { { 189, 220, 151, 0 }, - { 215, 122, 124, 0 }, - { 116, 157, 222, 1 }, - { 31, 47, 117, 1 }, }, - { { 189, 220, 232, 0 }, - { 199, 188, 108, 1 }, - { 11, 157, 222, 1 }, - { 155, 30, 241, 1 }, }, - { { 189, 220, 235, 1 }, - { 207, 254, 108, 1 }, - { 235, 157, 222, 1 }, - { 155, 63, 249, 1 }, }, - { { 189, 220, 228, 1 }, - { 207, 188, 124, 0 }, - { 147, 157, 222, 1 }, - { 31, 30, 249, 1 }, }, - { { 189, 220, 231, 0 }, - { 199, 254, 124, 0 }, - { 115, 157, 222, 1 }, - { 31, 63, 241, 1 }, }, - { { 186, 97, 8, 0 }, - { 196, 32, 139, 1 }, - { 8, 67, 46, 1 }, - { 232, 130, 17, 1 }, }, - { { 186, 97, 11, 1 }, - { 204, 98, 139, 1 }, - { 232, 67, 46, 1 }, - { 232, 163, 25, 1 }, }, - { { 186, 97, 4, 1 }, - { 204, 32, 155, 0 }, - { 144, 67, 46, 1 }, - { 108, 130, 25, 1 }, }, - { { 186, 97, 7, 0 }, - { 196, 98, 155, 0 }, - { 112, 67, 46, 1 }, - { 108, 163, 17, 1 }, }, - { { 186, 97, 120, 0 }, - { 212, 164, 139, 1 }, - { 15, 67, 46, 1 }, - { 232, 146, 149, 1 }, }, - { { 186, 97, 123, 1 }, - { 220, 230, 139, 1 }, - { 239, 67, 46, 1 }, - { 232, 179, 157, 1 }, }, - { { 186, 97, 116, 1 }, - { 220, 164, 155, 0 }, - { 151, 67, 46, 1 }, - { 108, 146, 157, 1 }, }, - { { 186, 97, 119, 0 }, - { 212, 230, 155, 0 }, - { 119, 67, 46, 1 }, - { 108, 179, 149, 1 }, }, - { { 186, 96, 152, 0 }, - { 212, 32, 170, 1 }, - { 12, 131, 46, 1 }, - { 170, 130, 21, 1 }, }, - { { 186, 96, 155, 1 }, - { 220, 98, 170, 1 }, - { 236, 131, 46, 1 }, - { 170, 163, 29, 1 }, }, - { { 186, 96, 148, 1 }, - { 220, 32, 186, 0 }, - { 148, 131, 46, 1 }, - { 46, 130, 29, 1 }, }, - { { 186, 96, 151, 0 }, - { 212, 98, 186, 0 }, - { 116, 131, 46, 1 }, - { 46, 163, 21, 1 }, }, - { { 186, 96, 232, 0 }, - { 196, 164, 170, 1 }, - { 11, 131, 46, 1 }, - { 170, 146, 145, 1 }, }, - { { 186, 96, 235, 1 }, - { 204, 230, 170, 1 }, - { 235, 131, 46, 1 }, - { 170, 179, 153, 1 }, }, - { { 186, 96, 228, 1 }, - { 204, 164, 186, 0 }, - { 147, 131, 46, 1 }, - { 46, 146, 153, 1 }, }, - { { 186, 96, 231, 0 }, - { 196, 230, 186, 0 }, - { 115, 131, 46, 1 }, - { 46, 179, 145, 1 }, }, - { { 186, 111, 8, 0 }, - { 229, 40, 139, 1 }, - { 8, 123, 46, 1 }, - { 232, 138, 83, 1 }, }, - { { 186, 111, 11, 1 }, - { 237, 106, 139, 1 }, - { 232, 123, 46, 1 }, - { 232, 171, 91, 1 }, }, - { { 186, 111, 4, 1 }, - { 237, 40, 155, 0 }, - { 144, 123, 46, 1 }, - { 108, 138, 91, 1 }, }, - { { 186, 111, 7, 0 }, - { 229, 106, 155, 0 }, - { 112, 123, 46, 1 }, - { 108, 171, 83, 1 }, }, - { { 186, 111, 120, 0 }, - { 245, 172, 139, 1 }, - { 15, 123, 46, 1 }, - { 232, 154, 215, 1 }, }, - { { 186, 111, 123, 1 }, - { 253, 238, 139, 1 }, - { 239, 123, 46, 1 }, - { 232, 187, 223, 1 }, }, - { { 186, 111, 116, 1 }, - { 253, 172, 155, 0 }, - { 151, 123, 46, 1 }, - { 108, 154, 223, 1 }, }, - { { 186, 111, 119, 0 }, - { 245, 238, 155, 0 }, - { 119, 123, 46, 1 }, - { 108, 187, 215, 1 }, }, - { { 186, 110, 152, 0 }, - { 245, 40, 170, 1 }, - { 12, 187, 46, 1 }, - { 170, 138, 87, 1 }, }, - { { 186, 110, 155, 1 }, - { 253, 106, 170, 1 }, - { 236, 187, 46, 1 }, - { 170, 171, 95, 1 }, }, - { { 186, 110, 148, 1 }, - { 253, 40, 186, 0 }, - { 148, 187, 46, 1 }, - { 46, 138, 95, 1 }, }, - { { 186, 110, 151, 0 }, - { 245, 106, 186, 0 }, - { 116, 187, 46, 1 }, - { 46, 171, 87, 1 }, }, - { { 186, 110, 232, 0 }, - { 229, 172, 170, 1 }, - { 11, 187, 46, 1 }, - { 170, 154, 211, 1 }, }, - { { 186, 110, 235, 1 }, - { 237, 238, 170, 1 }, - { 235, 187, 46, 1 }, - { 170, 187, 219, 1 }, }, - { { 186, 110, 228, 1 }, - { 237, 172, 186, 0 }, - { 147, 187, 46, 1 }, - { 46, 154, 219, 1 }, }, - { { 186, 110, 231, 0 }, - { 229, 238, 186, 0 }, - { 115, 187, 46, 1 }, - { 46, 187, 211, 1 }, }, - { { 186, 83, 8, 0 }, - { 228, 32, 201, 1 }, - { 8, 101, 46, 1 }, - { 201, 130, 19, 1 }, }, - { { 186, 83, 11, 1 }, - { 236, 98, 201, 1 }, - { 232, 101, 46, 1 }, - { 201, 163, 27, 1 }, }, - { { 186, 83, 4, 1 }, - { 236, 32, 217, 0 }, - { 144, 101, 46, 1 }, - { 77, 130, 27, 1 }, }, - { { 186, 83, 7, 0 }, - { 228, 98, 217, 0 }, - { 112, 101, 46, 1 }, - { 77, 163, 19, 1 }, }, - { { 186, 83, 120, 0 }, - { 244, 164, 201, 1 }, - { 15, 101, 46, 1 }, - { 201, 146, 151, 1 }, }, - { { 186, 83, 123, 1 }, - { 252, 230, 201, 1 }, - { 239, 101, 46, 1 }, - { 201, 179, 159, 1 }, }, - { { 186, 83, 116, 1 }, - { 252, 164, 217, 0 }, - { 151, 101, 46, 1 }, - { 77, 146, 159, 1 }, }, - { { 186, 83, 119, 0 }, - { 244, 230, 217, 0 }, - { 119, 101, 46, 1 }, - { 77, 179, 151, 1 }, }, - { { 186, 82, 152, 0 }, - { 244, 32, 232, 1 }, - { 12, 165, 46, 1 }, - { 139, 130, 23, 1 }, }, - { { 186, 82, 155, 1 }, - { 252, 98, 232, 1 }, - { 236, 165, 46, 1 }, - { 139, 163, 31, 1 }, }, - { { 186, 82, 148, 1 }, - { 252, 32, 248, 0 }, - { 148, 165, 46, 1 }, - { 15, 130, 31, 1 }, }, - { { 186, 82, 151, 0 }, - { 244, 98, 248, 0 }, - { 116, 165, 46, 1 }, - { 15, 163, 23, 1 }, }, - { { 186, 82, 232, 0 }, - { 228, 164, 232, 1 }, - { 11, 165, 46, 1 }, - { 139, 146, 147, 1 }, }, - { { 186, 82, 235, 1 }, - { 236, 230, 232, 1 }, - { 235, 165, 46, 1 }, - { 139, 179, 155, 1 }, }, - { { 186, 82, 228, 1 }, - { 236, 164, 248, 0 }, - { 147, 165, 46, 1 }, - { 15, 146, 155, 1 }, }, - { { 186, 82, 231, 0 }, - { 228, 230, 248, 0 }, - { 115, 165, 46, 1 }, - { 15, 179, 147, 1 }, }, - { { 186, 93, 8, 0 }, - { 197, 40, 201, 1 }, - { 8, 93, 46, 1 }, - { 201, 138, 81, 1 }, }, - { { 186, 93, 11, 1 }, - { 205, 106, 201, 1 }, - { 232, 93, 46, 1 }, - { 201, 171, 89, 1 }, }, - { { 186, 93, 4, 1 }, - { 205, 40, 217, 0 }, - { 144, 93, 46, 1 }, - { 77, 138, 89, 1 }, }, - { { 186, 93, 7, 0 }, - { 197, 106, 217, 0 }, - { 112, 93, 46, 1 }, - { 77, 171, 81, 1 }, }, - { { 186, 93, 120, 0 }, - { 213, 172, 201, 1 }, - { 15, 93, 46, 1 }, - { 201, 154, 213, 1 }, }, - { { 186, 93, 123, 1 }, - { 221, 238, 201, 1 }, - { 239, 93, 46, 1 }, - { 201, 187, 221, 1 }, }, - { { 186, 93, 116, 1 }, - { 221, 172, 217, 0 }, - { 151, 93, 46, 1 }, - { 77, 154, 221, 1 }, }, - { { 186, 93, 119, 0 }, - { 213, 238, 217, 0 }, - { 119, 93, 46, 1 }, - { 77, 187, 213, 1 }, }, - { { 186, 92, 152, 0 }, - { 213, 40, 232, 1 }, - { 12, 157, 46, 1 }, - { 139, 138, 85, 1 }, }, - { { 186, 92, 155, 1 }, - { 221, 106, 232, 1 }, - { 236, 157, 46, 1 }, - { 139, 171, 93, 1 }, }, - { { 186, 92, 148, 1 }, - { 221, 40, 248, 0 }, - { 148, 157, 46, 1 }, - { 15, 138, 93, 1 }, }, - { { 186, 92, 151, 0 }, - { 213, 106, 248, 0 }, - { 116, 157, 46, 1 }, - { 15, 171, 85, 1 }, }, - { { 186, 92, 232, 0 }, - { 197, 172, 232, 1 }, - { 11, 157, 46, 1 }, - { 139, 154, 209, 1 }, }, - { { 186, 92, 235, 1 }, - { 205, 238, 232, 1 }, - { 235, 157, 46, 1 }, - { 139, 187, 217, 1 }, }, - { { 186, 92, 228, 1 }, - { 205, 172, 248, 0 }, - { 147, 157, 46, 1 }, - { 15, 154, 217, 1 }, }, - { { 186, 92, 231, 0 }, - { 197, 238, 248, 0 }, - { 115, 157, 46, 1 }, - { 15, 187, 209, 1 }, }, - { { 187, 161, 8, 0 }, - { 134, 48, 139, 1 }, - { 8, 66, 238, 1 }, - { 232, 134, 48, 1 }, }, - { { 187, 161, 11, 1 }, - { 142, 114, 139, 1 }, - { 232, 66, 238, 1 }, - { 232, 167, 56, 1 }, }, - { { 187, 161, 4, 1 }, - { 142, 48, 155, 0 }, - { 144, 66, 238, 1 }, - { 108, 134, 56, 1 }, }, - { { 187, 161, 7, 0 }, - { 134, 114, 155, 0 }, - { 112, 66, 238, 1 }, - { 108, 167, 48, 1 }, }, - { { 187, 161, 120, 0 }, - { 150, 180, 139, 1 }, - { 15, 66, 238, 1 }, - { 232, 150, 180, 1 }, }, - { { 187, 161, 123, 1 }, - { 158, 246, 139, 1 }, - { 239, 66, 238, 1 }, - { 232, 183, 188, 1 }, }, - { { 187, 161, 116, 1 }, - { 158, 180, 155, 0 }, - { 151, 66, 238, 1 }, - { 108, 150, 188, 1 }, }, - { { 187, 161, 119, 0 }, - { 150, 246, 155, 0 }, - { 119, 66, 238, 1 }, - { 108, 183, 180, 1 }, }, - { { 187, 160, 152, 0 }, - { 150, 48, 170, 1 }, - { 12, 130, 238, 1 }, - { 170, 134, 52, 1 }, }, - { { 187, 160, 155, 1 }, - { 158, 114, 170, 1 }, - { 236, 130, 238, 1 }, - { 170, 167, 60, 1 }, }, - { { 187, 160, 148, 1 }, - { 158, 48, 186, 0 }, - { 148, 130, 238, 1 }, - { 46, 134, 60, 1 }, }, - { { 187, 160, 151, 0 }, - { 150, 114, 186, 0 }, - { 116, 130, 238, 1 }, - { 46, 167, 52, 1 }, }, - { { 187, 160, 232, 0 }, - { 134, 180, 170, 1 }, - { 11, 130, 238, 1 }, - { 170, 150, 176, 1 }, }, - { { 187, 160, 235, 1 }, - { 142, 246, 170, 1 }, - { 235, 130, 238, 1 }, - { 170, 183, 184, 1 }, }, - { { 187, 160, 228, 1 }, - { 142, 180, 186, 0 }, - { 147, 130, 238, 1 }, - { 46, 150, 184, 1 }, }, - { { 187, 160, 231, 0 }, - { 134, 246, 186, 0 }, - { 115, 130, 238, 1 }, - { 46, 183, 176, 1 }, }, - { { 187, 175, 8, 0 }, - { 167, 56, 139, 1 }, - { 8, 122, 238, 1 }, - { 232, 142, 114, 1 }, }, - { { 187, 175, 11, 1 }, - { 175, 122, 139, 1 }, - { 232, 122, 238, 1 }, - { 232, 175, 122, 1 }, }, - { { 187, 175, 4, 1 }, - { 175, 56, 155, 0 }, - { 144, 122, 238, 1 }, - { 108, 142, 122, 1 }, }, - { { 187, 175, 7, 0 }, - { 167, 122, 155, 0 }, - { 112, 122, 238, 1 }, - { 108, 175, 114, 1 }, }, - { { 187, 175, 120, 0 }, - { 183, 188, 139, 1 }, - { 15, 122, 238, 1 }, - { 232, 158, 246, 1 }, }, - { { 187, 175, 123, 1 }, - { 191, 254, 139, 1 }, - { 239, 122, 238, 1 }, - { 232, 191, 254, 1 }, }, - { { 187, 175, 116, 1 }, - { 191, 188, 155, 0 }, - { 151, 122, 238, 1 }, - { 108, 158, 254, 1 }, }, - { { 187, 175, 119, 0 }, - { 183, 254, 155, 0 }, - { 119, 122, 238, 1 }, - { 108, 191, 246, 1 }, }, - { { 187, 174, 152, 0 }, - { 183, 56, 170, 1 }, - { 12, 186, 238, 1 }, - { 170, 142, 118, 1 }, }, - { { 187, 174, 155, 1 }, - { 191, 122, 170, 1 }, - { 236, 186, 238, 1 }, - { 170, 175, 126, 1 }, }, - { { 187, 174, 148, 1 }, - { 191, 56, 186, 0 }, - { 148, 186, 238, 1 }, - { 46, 142, 126, 1 }, }, - { { 187, 174, 151, 0 }, - { 183, 122, 186, 0 }, - { 116, 186, 238, 1 }, - { 46, 175, 118, 1 }, }, - { { 187, 174, 232, 0 }, - { 167, 188, 170, 1 }, - { 11, 186, 238, 1 }, - { 170, 158, 242, 1 }, }, - { { 187, 174, 235, 1 }, - { 175, 254, 170, 1 }, - { 235, 186, 238, 1 }, - { 170, 191, 250, 1 }, }, - { { 187, 174, 228, 1 }, - { 175, 188, 186, 0 }, - { 147, 186, 238, 1 }, - { 46, 158, 250, 1 }, }, - { { 187, 174, 231, 0 }, - { 167, 254, 186, 0 }, - { 115, 186, 238, 1 }, - { 46, 191, 242, 1 }, }, - { { 187, 147, 8, 0 }, - { 166, 48, 201, 1 }, - { 8, 100, 238, 1 }, - { 201, 134, 50, 1 }, }, - { { 187, 147, 11, 1 }, - { 174, 114, 201, 1 }, - { 232, 100, 238, 1 }, - { 201, 167, 58, 1 }, }, - { { 187, 147, 4, 1 }, - { 174, 48, 217, 0 }, - { 144, 100, 238, 1 }, - { 77, 134, 58, 1 }, }, - { { 187, 147, 7, 0 }, - { 166, 114, 217, 0 }, - { 112, 100, 238, 1 }, - { 77, 167, 50, 1 }, }, - { { 187, 147, 120, 0 }, - { 182, 180, 201, 1 }, - { 15, 100, 238, 1 }, - { 201, 150, 182, 1 }, }, - { { 187, 147, 123, 1 }, - { 190, 246, 201, 1 }, - { 239, 100, 238, 1 }, - { 201, 183, 190, 1 }, }, - { { 187, 147, 116, 1 }, - { 190, 180, 217, 0 }, - { 151, 100, 238, 1 }, - { 77, 150, 190, 1 }, }, - { { 187, 147, 119, 0 }, - { 182, 246, 217, 0 }, - { 119, 100, 238, 1 }, - { 77, 183, 182, 1 }, }, - { { 187, 146, 152, 0 }, - { 182, 48, 232, 1 }, - { 12, 164, 238, 1 }, - { 139, 134, 54, 1 }, }, - { { 187, 146, 155, 1 }, - { 190, 114, 232, 1 }, - { 236, 164, 238, 1 }, - { 139, 167, 62, 1 }, }, - { { 187, 146, 148, 1 }, - { 190, 48, 248, 0 }, - { 148, 164, 238, 1 }, - { 15, 134, 62, 1 }, }, - { { 187, 146, 151, 0 }, - { 182, 114, 248, 0 }, - { 116, 164, 238, 1 }, - { 15, 167, 54, 1 }, }, - { { 187, 146, 232, 0 }, - { 166, 180, 232, 1 }, - { 11, 164, 238, 1 }, - { 139, 150, 178, 1 }, }, - { { 187, 146, 235, 1 }, - { 174, 246, 232, 1 }, - { 235, 164, 238, 1 }, - { 139, 183, 186, 1 }, }, - { { 187, 146, 228, 1 }, - { 174, 180, 248, 0 }, - { 147, 164, 238, 1 }, - { 15, 150, 186, 1 }, }, - { { 187, 146, 231, 0 }, - { 166, 246, 248, 0 }, - { 115, 164, 238, 1 }, - { 15, 183, 178, 1 }, }, - { { 187, 157, 8, 0 }, - { 135, 56, 201, 1 }, - { 8, 92, 238, 1 }, - { 201, 142, 112, 1 }, }, - { { 187, 157, 11, 1 }, - { 143, 122, 201, 1 }, - { 232, 92, 238, 1 }, - { 201, 175, 120, 1 }, }, - { { 187, 157, 4, 1 }, - { 143, 56, 217, 0 }, - { 144, 92, 238, 1 }, - { 77, 142, 120, 1 }, }, - { { 187, 157, 7, 0 }, - { 135, 122, 217, 0 }, - { 112, 92, 238, 1 }, - { 77, 175, 112, 1 }, }, - { { 187, 157, 120, 0 }, - { 151, 188, 201, 1 }, - { 15, 92, 238, 1 }, - { 201, 158, 244, 1 }, }, - { { 187, 157, 123, 1 }, - { 159, 254, 201, 1 }, - { 239, 92, 238, 1 }, - { 201, 191, 252, 1 }, }, - { { 187, 157, 116, 1 }, - { 159, 188, 217, 0 }, - { 151, 92, 238, 1 }, - { 77, 158, 252, 1 }, }, - { { 187, 157, 119, 0 }, - { 151, 254, 217, 0 }, - { 119, 92, 238, 1 }, - { 77, 191, 244, 1 }, }, - { { 187, 156, 152, 0 }, - { 151, 56, 232, 1 }, - { 12, 156, 238, 1 }, - { 139, 142, 116, 1 }, }, - { { 187, 156, 155, 1 }, - { 159, 122, 232, 1 }, - { 236, 156, 238, 1 }, - { 139, 175, 124, 1 }, }, - { { 187, 156, 148, 1 }, - { 159, 56, 248, 0 }, - { 148, 156, 238, 1 }, - { 15, 142, 124, 1 }, }, - { { 187, 156, 151, 0 }, - { 151, 122, 248, 0 }, - { 116, 156, 238, 1 }, - { 15, 175, 116, 1 }, }, - { { 187, 156, 232, 0 }, - { 135, 188, 232, 1 }, - { 11, 156, 238, 1 }, - { 139, 158, 240, 1 }, }, - { { 187, 156, 235, 1 }, - { 143, 254, 232, 1 }, - { 235, 156, 238, 1 }, - { 139, 191, 248, 1 }, }, - { { 187, 156, 228, 1 }, - { 143, 188, 248, 0 }, - { 147, 156, 238, 1 }, - { 15, 158, 248, 1 }, }, - { { 187, 156, 231, 0 }, - { 135, 254, 248, 0 }, - { 115, 156, 238, 1 }, - { 15, 191, 240, 1 }, }, - { { 76, 33, 8, 0 }, - { 128, 1, 7, 1 }, - { 8, 66, 25, 0 }, - { 240, 64, 0, 1 }, }, - { { 76, 33, 11, 1 }, - { 136, 67, 7, 1 }, - { 232, 66, 25, 0 }, - { 240, 97, 8, 1 }, }, - { { 76, 33, 4, 1 }, - { 136, 1, 23, 0 }, - { 144, 66, 25, 0 }, - { 116, 64, 8, 1 }, }, - { { 76, 33, 7, 0 }, - { 128, 67, 23, 0 }, - { 112, 66, 25, 0 }, - { 116, 97, 0, 1 }, }, - { { 76, 33, 120, 0 }, - { 144, 133, 7, 1 }, - { 15, 66, 25, 0 }, - { 240, 80, 132, 1 }, }, - { { 76, 33, 123, 1 }, - { 152, 199, 7, 1 }, - { 239, 66, 25, 0 }, - { 240, 113, 140, 1 }, }, - { { 76, 33, 116, 1 }, - { 152, 133, 23, 0 }, - { 151, 66, 25, 0 }, - { 116, 80, 140, 1 }, }, - { { 76, 33, 119, 0 }, - { 144, 199, 23, 0 }, - { 119, 66, 25, 0 }, - { 116, 113, 132, 1 }, }, - { { 76, 32, 152, 0 }, - { 144, 1, 38, 1 }, - { 12, 130, 25, 0 }, - { 178, 64, 4, 1 }, }, - { { 76, 32, 155, 1 }, - { 152, 67, 38, 1 }, - { 236, 130, 25, 0 }, - { 178, 97, 12, 1 }, }, - { { 76, 32, 148, 1 }, - { 152, 1, 54, 0 }, - { 148, 130, 25, 0 }, - { 54, 64, 12, 1 }, }, - { { 76, 32, 151, 0 }, - { 144, 67, 54, 0 }, - { 116, 130, 25, 0 }, - { 54, 97, 4, 1 }, }, - { { 76, 32, 232, 0 }, - { 128, 133, 38, 1 }, - { 11, 130, 25, 0 }, - { 178, 80, 128, 1 }, }, - { { 76, 32, 235, 1 }, - { 136, 199, 38, 1 }, - { 235, 130, 25, 0 }, - { 178, 113, 136, 1 }, }, - { { 76, 32, 228, 1 }, - { 136, 133, 54, 0 }, - { 147, 130, 25, 0 }, - { 54, 80, 136, 1 }, }, - { { 76, 32, 231, 0 }, - { 128, 199, 54, 0 }, - { 115, 130, 25, 0 }, - { 54, 113, 128, 1 }, }, - { { 76, 47, 8, 0 }, - { 161, 9, 7, 1 }, - { 8, 122, 25, 0 }, - { 240, 72, 66, 1 }, }, - { { 76, 47, 11, 1 }, - { 169, 75, 7, 1 }, - { 232, 122, 25, 0 }, - { 240, 105, 74, 1 }, }, - { { 76, 47, 4, 1 }, - { 169, 9, 23, 0 }, - { 144, 122, 25, 0 }, - { 116, 72, 74, 1 }, }, - { { 76, 47, 7, 0 }, - { 161, 75, 23, 0 }, - { 112, 122, 25, 0 }, - { 116, 105, 66, 1 }, }, - { { 76, 47, 120, 0 }, - { 177, 141, 7, 1 }, - { 15, 122, 25, 0 }, - { 240, 88, 198, 1 }, }, - { { 76, 47, 123, 1 }, - { 185, 207, 7, 1 }, - { 239, 122, 25, 0 }, - { 240, 121, 206, 1 }, }, - { { 76, 47, 116, 1 }, - { 185, 141, 23, 0 }, - { 151, 122, 25, 0 }, - { 116, 88, 206, 1 }, }, - { { 76, 47, 119, 0 }, - { 177, 207, 23, 0 }, - { 119, 122, 25, 0 }, - { 116, 121, 198, 1 }, }, - { { 76, 46, 152, 0 }, - { 177, 9, 38, 1 }, - { 12, 186, 25, 0 }, - { 178, 72, 70, 1 }, }, - { { 76, 46, 155, 1 }, - { 185, 75, 38, 1 }, - { 236, 186, 25, 0 }, - { 178, 105, 78, 1 }, }, - { { 76, 46, 148, 1 }, - { 185, 9, 54, 0 }, - { 148, 186, 25, 0 }, - { 54, 72, 78, 1 }, }, - { { 76, 46, 151, 0 }, - { 177, 75, 54, 0 }, - { 116, 186, 25, 0 }, - { 54, 105, 70, 1 }, }, - { { 76, 46, 232, 0 }, - { 161, 141, 38, 1 }, - { 11, 186, 25, 0 }, - { 178, 88, 194, 1 }, }, - { { 76, 46, 235, 1 }, - { 169, 207, 38, 1 }, - { 235, 186, 25, 0 }, - { 178, 121, 202, 1 }, }, - { { 76, 46, 228, 1 }, - { 169, 141, 54, 0 }, - { 147, 186, 25, 0 }, - { 54, 88, 202, 1 }, }, - { { 76, 46, 231, 0 }, - { 161, 207, 54, 0 }, - { 115, 186, 25, 0 }, - { 54, 121, 194, 1 }, }, - { { 76, 19, 8, 0 }, - { 160, 1, 69, 1 }, - { 8, 100, 25, 0 }, - { 209, 64, 2, 1 }, }, - { { 76, 19, 11, 1 }, - { 168, 67, 69, 1 }, - { 232, 100, 25, 0 }, - { 209, 97, 10, 1 }, }, - { { 76, 19, 4, 1 }, - { 168, 1, 85, 0 }, - { 144, 100, 25, 0 }, - { 85, 64, 10, 1 }, }, - { { 76, 19, 7, 0 }, - { 160, 67, 85, 0 }, - { 112, 100, 25, 0 }, - { 85, 97, 2, 1 }, }, - { { 76, 19, 120, 0 }, - { 176, 133, 69, 1 }, - { 15, 100, 25, 0 }, - { 209, 80, 134, 1 }, }, - { { 76, 19, 123, 1 }, - { 184, 199, 69, 1 }, - { 239, 100, 25, 0 }, - { 209, 113, 142, 1 }, }, - { { 76, 19, 116, 1 }, - { 184, 133, 85, 0 }, - { 151, 100, 25, 0 }, - { 85, 80, 142, 1 }, }, - { { 76, 19, 119, 0 }, - { 176, 199, 85, 0 }, - { 119, 100, 25, 0 }, - { 85, 113, 134, 1 }, }, - { { 76, 18, 152, 0 }, - { 176, 1, 100, 1 }, - { 12, 164, 25, 0 }, - { 147, 64, 6, 1 }, }, - { { 76, 18, 155, 1 }, - { 184, 67, 100, 1 }, - { 236, 164, 25, 0 }, - { 147, 97, 14, 1 }, }, - { { 76, 18, 148, 1 }, - { 184, 1, 116, 0 }, - { 148, 164, 25, 0 }, - { 23, 64, 14, 1 }, }, - { { 76, 18, 151, 0 }, - { 176, 67, 116, 0 }, - { 116, 164, 25, 0 }, - { 23, 97, 6, 1 }, }, - { { 76, 18, 232, 0 }, - { 160, 133, 100, 1 }, - { 11, 164, 25, 0 }, - { 147, 80, 130, 1 }, }, - { { 76, 18, 235, 1 }, - { 168, 199, 100, 1 }, - { 235, 164, 25, 0 }, - { 147, 113, 138, 1 }, }, - { { 76, 18, 228, 1 }, - { 168, 133, 116, 0 }, - { 147, 164, 25, 0 }, - { 23, 80, 138, 1 }, }, - { { 76, 18, 231, 0 }, - { 160, 199, 116, 0 }, - { 115, 164, 25, 0 }, - { 23, 113, 130, 1 }, }, - { { 76, 29, 8, 0 }, - { 129, 9, 69, 1 }, - { 8, 92, 25, 0 }, - { 209, 72, 64, 1 }, }, - { { 76, 29, 11, 1 }, - { 137, 75, 69, 1 }, - { 232, 92, 25, 0 }, - { 209, 105, 72, 1 }, }, - { { 76, 29, 4, 1 }, - { 137, 9, 85, 0 }, - { 144, 92, 25, 0 }, - { 85, 72, 72, 1 }, }, - { { 76, 29, 7, 0 }, - { 129, 75, 85, 0 }, - { 112, 92, 25, 0 }, - { 85, 105, 64, 1 }, }, - { { 76, 29, 120, 0 }, - { 145, 141, 69, 1 }, - { 15, 92, 25, 0 }, - { 209, 88, 196, 1 }, }, - { { 76, 29, 123, 1 }, - { 153, 207, 69, 1 }, - { 239, 92, 25, 0 }, - { 209, 121, 204, 1 }, }, - { { 76, 29, 116, 1 }, - { 153, 141, 85, 0 }, - { 151, 92, 25, 0 }, - { 85, 88, 204, 1 }, }, - { { 76, 29, 119, 0 }, - { 145, 207, 85, 0 }, - { 119, 92, 25, 0 }, - { 85, 121, 196, 1 }, }, - { { 76, 28, 152, 0 }, - { 145, 9, 100, 1 }, - { 12, 156, 25, 0 }, - { 147, 72, 68, 1 }, }, - { { 76, 28, 155, 1 }, - { 153, 75, 100, 1 }, - { 236, 156, 25, 0 }, - { 147, 105, 76, 1 }, }, - { { 76, 28, 148, 1 }, - { 153, 9, 116, 0 }, - { 148, 156, 25, 0 }, - { 23, 72, 76, 1 }, }, - { { 76, 28, 151, 0 }, - { 145, 75, 116, 0 }, - { 116, 156, 25, 0 }, - { 23, 105, 68, 1 }, }, - { { 76, 28, 232, 0 }, - { 129, 141, 100, 1 }, - { 11, 156, 25, 0 }, - { 147, 88, 192, 1 }, }, - { { 76, 28, 235, 1 }, - { 137, 207, 100, 1 }, - { 235, 156, 25, 0 }, - { 147, 121, 200, 1 }, }, - { { 76, 28, 228, 1 }, - { 137, 141, 116, 0 }, - { 147, 156, 25, 0 }, - { 23, 88, 200, 1 }, }, - { { 76, 28, 231, 0 }, - { 129, 207, 116, 0 }, - { 115, 156, 25, 0 }, - { 23, 121, 192, 1 }, }, - { { 77, 225, 8, 0 }, - { 194, 17, 7, 1 }, - { 8, 67, 217, 0 }, - { 240, 68, 33, 1 }, }, - { { 77, 225, 11, 1 }, - { 202, 83, 7, 1 }, - { 232, 67, 217, 0 }, - { 240, 101, 41, 1 }, }, - { { 77, 225, 4, 1 }, - { 202, 17, 23, 0 }, - { 144, 67, 217, 0 }, - { 116, 68, 41, 1 }, }, - { { 77, 225, 7, 0 }, - { 194, 83, 23, 0 }, - { 112, 67, 217, 0 }, - { 116, 101, 33, 1 }, }, - { { 77, 225, 120, 0 }, - { 210, 149, 7, 1 }, - { 15, 67, 217, 0 }, - { 240, 84, 165, 1 }, }, - { { 77, 225, 123, 1 }, - { 218, 215, 7, 1 }, - { 239, 67, 217, 0 }, - { 240, 117, 173, 1 }, }, - { { 77, 225, 116, 1 }, - { 218, 149, 23, 0 }, - { 151, 67, 217, 0 }, - { 116, 84, 173, 1 }, }, - { { 77, 225, 119, 0 }, - { 210, 215, 23, 0 }, - { 119, 67, 217, 0 }, - { 116, 117, 165, 1 }, }, - { { 77, 224, 152, 0 }, - { 210, 17, 38, 1 }, - { 12, 131, 217, 0 }, - { 178, 68, 37, 1 }, }, - { { 77, 224, 155, 1 }, - { 218, 83, 38, 1 }, - { 236, 131, 217, 0 }, - { 178, 101, 45, 1 }, }, - { { 77, 224, 148, 1 }, - { 218, 17, 54, 0 }, - { 148, 131, 217, 0 }, - { 54, 68, 45, 1 }, }, - { { 77, 224, 151, 0 }, - { 210, 83, 54, 0 }, - { 116, 131, 217, 0 }, - { 54, 101, 37, 1 }, }, - { { 77, 224, 232, 0 }, - { 194, 149, 38, 1 }, - { 11, 131, 217, 0 }, - { 178, 84, 161, 1 }, }, - { { 77, 224, 235, 1 }, - { 202, 215, 38, 1 }, - { 235, 131, 217, 0 }, - { 178, 117, 169, 1 }, }, - { { 77, 224, 228, 1 }, - { 202, 149, 54, 0 }, - { 147, 131, 217, 0 }, - { 54, 84, 169, 1 }, }, - { { 77, 224, 231, 0 }, - { 194, 215, 54, 0 }, - { 115, 131, 217, 0 }, - { 54, 117, 161, 1 }, }, - { { 77, 239, 8, 0 }, - { 227, 25, 7, 1 }, - { 8, 123, 217, 0 }, - { 240, 76, 99, 1 }, }, - { { 77, 239, 11, 1 }, - { 235, 91, 7, 1 }, - { 232, 123, 217, 0 }, - { 240, 109, 107, 1 }, }, - { { 77, 239, 4, 1 }, - { 235, 25, 23, 0 }, - { 144, 123, 217, 0 }, - { 116, 76, 107, 1 }, }, - { { 77, 239, 7, 0 }, - { 227, 91, 23, 0 }, - { 112, 123, 217, 0 }, - { 116, 109, 99, 1 }, }, - { { 77, 239, 120, 0 }, - { 243, 157, 7, 1 }, - { 15, 123, 217, 0 }, - { 240, 92, 231, 1 }, }, - { { 77, 239, 123, 1 }, - { 251, 223, 7, 1 }, - { 239, 123, 217, 0 }, - { 240, 125, 239, 1 }, }, - { { 77, 239, 116, 1 }, - { 251, 157, 23, 0 }, - { 151, 123, 217, 0 }, - { 116, 92, 239, 1 }, }, - { { 77, 239, 119, 0 }, - { 243, 223, 23, 0 }, - { 119, 123, 217, 0 }, - { 116, 125, 231, 1 }, }, - { { 77, 238, 152, 0 }, - { 243, 25, 38, 1 }, - { 12, 187, 217, 0 }, - { 178, 76, 103, 1 }, }, - { { 77, 238, 155, 1 }, - { 251, 91, 38, 1 }, - { 236, 187, 217, 0 }, - { 178, 109, 111, 1 }, }, - { { 77, 238, 148, 1 }, - { 251, 25, 54, 0 }, - { 148, 187, 217, 0 }, - { 54, 76, 111, 1 }, }, - { { 77, 238, 151, 0 }, - { 243, 91, 54, 0 }, - { 116, 187, 217, 0 }, - { 54, 109, 103, 1 }, }, - { { 77, 238, 232, 0 }, - { 227, 157, 38, 1 }, - { 11, 187, 217, 0 }, - { 178, 92, 227, 1 }, }, - { { 77, 238, 235, 1 }, - { 235, 223, 38, 1 }, - { 235, 187, 217, 0 }, - { 178, 125, 235, 1 }, }, - { { 77, 238, 228, 1 }, - { 235, 157, 54, 0 }, - { 147, 187, 217, 0 }, - { 54, 92, 235, 1 }, }, - { { 77, 238, 231, 0 }, - { 227, 223, 54, 0 }, - { 115, 187, 217, 0 }, - { 54, 125, 227, 1 }, }, - { { 77, 211, 8, 0 }, - { 226, 17, 69, 1 }, - { 8, 101, 217, 0 }, - { 209, 68, 35, 1 }, }, - { { 77, 211, 11, 1 }, - { 234, 83, 69, 1 }, - { 232, 101, 217, 0 }, - { 209, 101, 43, 1 }, }, - { { 77, 211, 4, 1 }, - { 234, 17, 85, 0 }, - { 144, 101, 217, 0 }, - { 85, 68, 43, 1 }, }, - { { 77, 211, 7, 0 }, - { 226, 83, 85, 0 }, - { 112, 101, 217, 0 }, - { 85, 101, 35, 1 }, }, - { { 77, 211, 120, 0 }, - { 242, 149, 69, 1 }, - { 15, 101, 217, 0 }, - { 209, 84, 167, 1 }, }, - { { 77, 211, 123, 1 }, - { 250, 215, 69, 1 }, - { 239, 101, 217, 0 }, - { 209, 117, 175, 1 }, }, - { { 77, 211, 116, 1 }, - { 250, 149, 85, 0 }, - { 151, 101, 217, 0 }, - { 85, 84, 175, 1 }, }, - { { 77, 211, 119, 0 }, - { 242, 215, 85, 0 }, - { 119, 101, 217, 0 }, - { 85, 117, 167, 1 }, }, - { { 77, 210, 152, 0 }, - { 242, 17, 100, 1 }, - { 12, 165, 217, 0 }, - { 147, 68, 39, 1 }, }, - { { 77, 210, 155, 1 }, - { 250, 83, 100, 1 }, - { 236, 165, 217, 0 }, - { 147, 101, 47, 1 }, }, - { { 77, 210, 148, 1 }, - { 250, 17, 116, 0 }, - { 148, 165, 217, 0 }, - { 23, 68, 47, 1 }, }, - { { 77, 210, 151, 0 }, - { 242, 83, 116, 0 }, - { 116, 165, 217, 0 }, - { 23, 101, 39, 1 }, }, - { { 77, 210, 232, 0 }, - { 226, 149, 100, 1 }, - { 11, 165, 217, 0 }, - { 147, 84, 163, 1 }, }, - { { 77, 210, 235, 1 }, - { 234, 215, 100, 1 }, - { 235, 165, 217, 0 }, - { 147, 117, 171, 1 }, }, - { { 77, 210, 228, 1 }, - { 234, 149, 116, 0 }, - { 147, 165, 217, 0 }, - { 23, 84, 171, 1 }, }, - { { 77, 210, 231, 0 }, - { 226, 215, 116, 0 }, - { 115, 165, 217, 0 }, - { 23, 117, 163, 1 }, }, - { { 77, 221, 8, 0 }, - { 195, 25, 69, 1 }, - { 8, 93, 217, 0 }, - { 209, 76, 97, 1 }, }, - { { 77, 221, 11, 1 }, - { 203, 91, 69, 1 }, - { 232, 93, 217, 0 }, - { 209, 109, 105, 1 }, }, - { { 77, 221, 4, 1 }, - { 203, 25, 85, 0 }, - { 144, 93, 217, 0 }, - { 85, 76, 105, 1 }, }, - { { 77, 221, 7, 0 }, - { 195, 91, 85, 0 }, - { 112, 93, 217, 0 }, - { 85, 109, 97, 1 }, }, - { { 77, 221, 120, 0 }, - { 211, 157, 69, 1 }, - { 15, 93, 217, 0 }, - { 209, 92, 229, 1 }, }, - { { 77, 221, 123, 1 }, - { 219, 223, 69, 1 }, - { 239, 93, 217, 0 }, - { 209, 125, 237, 1 }, }, - { { 77, 221, 116, 1 }, - { 219, 157, 85, 0 }, - { 151, 93, 217, 0 }, - { 85, 92, 237, 1 }, }, - { { 77, 221, 119, 0 }, - { 211, 223, 85, 0 }, - { 119, 93, 217, 0 }, - { 85, 125, 229, 1 }, }, - { { 77, 220, 152, 0 }, - { 211, 25, 100, 1 }, - { 12, 157, 217, 0 }, - { 147, 76, 101, 1 }, }, - { { 77, 220, 155, 1 }, - { 219, 91, 100, 1 }, - { 236, 157, 217, 0 }, - { 147, 109, 109, 1 }, }, - { { 77, 220, 148, 1 }, - { 219, 25, 116, 0 }, - { 148, 157, 217, 0 }, - { 23, 76, 109, 1 }, }, - { { 77, 220, 151, 0 }, - { 211, 91, 116, 0 }, - { 116, 157, 217, 0 }, - { 23, 109, 101, 1 }, }, - { { 77, 220, 232, 0 }, - { 195, 157, 100, 1 }, - { 11, 157, 217, 0 }, - { 147, 92, 225, 1 }, }, - { { 77, 220, 235, 1 }, - { 203, 223, 100, 1 }, - { 235, 157, 217, 0 }, - { 147, 125, 233, 1 }, }, - { { 77, 220, 228, 1 }, - { 203, 157, 116, 0 }, - { 147, 157, 217, 0 }, - { 23, 92, 233, 1 }, }, - { { 77, 220, 231, 0 }, - { 195, 223, 116, 0 }, - { 115, 157, 217, 0 }, - { 23, 125, 225, 1 }, }, - { { 74, 97, 8, 0 }, - { 192, 1, 131, 1 }, - { 8, 67, 41, 0 }, - { 224, 192, 1, 1 }, }, - { { 74, 97, 11, 1 }, - { 200, 67, 131, 1 }, - { 232, 67, 41, 0 }, - { 224, 225, 9, 1 }, }, - { { 74, 97, 4, 1 }, - { 200, 1, 147, 0 }, - { 144, 67, 41, 0 }, - { 100, 192, 9, 1 }, }, - { { 74, 97, 7, 0 }, - { 192, 67, 147, 0 }, - { 112, 67, 41, 0 }, - { 100, 225, 1, 1 }, }, - { { 74, 97, 120, 0 }, - { 208, 133, 131, 1 }, - { 15, 67, 41, 0 }, - { 224, 208, 133, 1 }, }, - { { 74, 97, 123, 1 }, - { 216, 199, 131, 1 }, - { 239, 67, 41, 0 }, - { 224, 241, 141, 1 }, }, - { { 74, 97, 116, 1 }, - { 216, 133, 147, 0 }, - { 151, 67, 41, 0 }, - { 100, 208, 141, 1 }, }, - { { 74, 97, 119, 0 }, - { 208, 199, 147, 0 }, - { 119, 67, 41, 0 }, - { 100, 241, 133, 1 }, }, - { { 74, 96, 152, 0 }, - { 208, 1, 162, 1 }, - { 12, 131, 41, 0 }, - { 162, 192, 5, 1 }, }, - { { 74, 96, 155, 1 }, - { 216, 67, 162, 1 }, - { 236, 131, 41, 0 }, - { 162, 225, 13, 1 }, }, - { { 74, 96, 148, 1 }, - { 216, 1, 178, 0 }, - { 148, 131, 41, 0 }, - { 38, 192, 13, 1 }, }, - { { 74, 96, 151, 0 }, - { 208, 67, 178, 0 }, - { 116, 131, 41, 0 }, - { 38, 225, 5, 1 }, }, - { { 74, 96, 232, 0 }, - { 192, 133, 162, 1 }, - { 11, 131, 41, 0 }, - { 162, 208, 129, 1 }, }, - { { 74, 96, 235, 1 }, - { 200, 199, 162, 1 }, - { 235, 131, 41, 0 }, - { 162, 241, 137, 1 }, }, - { { 74, 96, 228, 1 }, - { 200, 133, 178, 0 }, - { 147, 131, 41, 0 }, - { 38, 208, 137, 1 }, }, - { { 74, 96, 231, 0 }, - { 192, 199, 178, 0 }, - { 115, 131, 41, 0 }, - { 38, 241, 129, 1 }, }, - { { 74, 111, 8, 0 }, - { 225, 9, 131, 1 }, - { 8, 123, 41, 0 }, - { 224, 200, 67, 1 }, }, - { { 74, 111, 11, 1 }, - { 233, 75, 131, 1 }, - { 232, 123, 41, 0 }, - { 224, 233, 75, 1 }, }, - { { 74, 111, 4, 1 }, - { 233, 9, 147, 0 }, - { 144, 123, 41, 0 }, - { 100, 200, 75, 1 }, }, - { { 74, 111, 7, 0 }, - { 225, 75, 147, 0 }, - { 112, 123, 41, 0 }, - { 100, 233, 67, 1 }, }, - { { 74, 111, 120, 0 }, - { 241, 141, 131, 1 }, - { 15, 123, 41, 0 }, - { 224, 216, 199, 1 }, }, - { { 74, 111, 123, 1 }, - { 249, 207, 131, 1 }, - { 239, 123, 41, 0 }, - { 224, 249, 207, 1 }, }, - { { 74, 111, 116, 1 }, - { 249, 141, 147, 0 }, - { 151, 123, 41, 0 }, - { 100, 216, 207, 1 }, }, - { { 74, 111, 119, 0 }, - { 241, 207, 147, 0 }, - { 119, 123, 41, 0 }, - { 100, 249, 199, 1 }, }, - { { 74, 110, 152, 0 }, - { 241, 9, 162, 1 }, - { 12, 187, 41, 0 }, - { 162, 200, 71, 1 }, }, - { { 74, 110, 155, 1 }, - { 249, 75, 162, 1 }, - { 236, 187, 41, 0 }, - { 162, 233, 79, 1 }, }, - { { 74, 110, 148, 1 }, - { 249, 9, 178, 0 }, - { 148, 187, 41, 0 }, - { 38, 200, 79, 1 }, }, - { { 74, 110, 151, 0 }, - { 241, 75, 178, 0 }, - { 116, 187, 41, 0 }, - { 38, 233, 71, 1 }, }, - { { 74, 110, 232, 0 }, - { 225, 141, 162, 1 }, - { 11, 187, 41, 0 }, - { 162, 216, 195, 1 }, }, - { { 74, 110, 235, 1 }, - { 233, 207, 162, 1 }, - { 235, 187, 41, 0 }, - { 162, 249, 203, 1 }, }, - { { 74, 110, 228, 1 }, - { 233, 141, 178, 0 }, - { 147, 187, 41, 0 }, - { 38, 216, 203, 1 }, }, - { { 74, 110, 231, 0 }, - { 225, 207, 178, 0 }, - { 115, 187, 41, 0 }, - { 38, 249, 195, 1 }, }, - { { 74, 83, 8, 0 }, - { 224, 1, 193, 1 }, - { 8, 101, 41, 0 }, - { 193, 192, 3, 1 }, }, - { { 74, 83, 11, 1 }, - { 232, 67, 193, 1 }, - { 232, 101, 41, 0 }, - { 193, 225, 11, 1 }, }, - { { 74, 83, 4, 1 }, - { 232, 1, 209, 0 }, - { 144, 101, 41, 0 }, - { 69, 192, 11, 1 }, }, - { { 74, 83, 7, 0 }, - { 224, 67, 209, 0 }, - { 112, 101, 41, 0 }, - { 69, 225, 3, 1 }, }, - { { 74, 83, 120, 0 }, - { 240, 133, 193, 1 }, - { 15, 101, 41, 0 }, - { 193, 208, 135, 1 }, }, - { { 74, 83, 123, 1 }, - { 248, 199, 193, 1 }, - { 239, 101, 41, 0 }, - { 193, 241, 143, 1 }, }, - { { 74, 83, 116, 1 }, - { 248, 133, 209, 0 }, - { 151, 101, 41, 0 }, - { 69, 208, 143, 1 }, }, - { { 74, 83, 119, 0 }, - { 240, 199, 209, 0 }, - { 119, 101, 41, 0 }, - { 69, 241, 135, 1 }, }, - { { 74, 82, 152, 0 }, - { 240, 1, 224, 1 }, - { 12, 165, 41, 0 }, - { 131, 192, 7, 1 }, }, - { { 74, 82, 155, 1 }, - { 248, 67, 224, 1 }, - { 236, 165, 41, 0 }, - { 131, 225, 15, 1 }, }, - { { 74, 82, 148, 1 }, - { 248, 1, 240, 0 }, - { 148, 165, 41, 0 }, - { 7, 192, 15, 1 }, }, - { { 74, 82, 151, 0 }, - { 240, 67, 240, 0 }, - { 116, 165, 41, 0 }, - { 7, 225, 7, 1 }, }, - { { 74, 82, 232, 0 }, - { 224, 133, 224, 1 }, - { 11, 165, 41, 0 }, - { 131, 208, 131, 1 }, }, - { { 74, 82, 235, 1 }, - { 232, 199, 224, 1 }, - { 235, 165, 41, 0 }, - { 131, 241, 139, 1 }, }, - { { 74, 82, 228, 1 }, - { 232, 133, 240, 0 }, - { 147, 165, 41, 0 }, - { 7, 208, 139, 1 }, }, - { { 74, 82, 231, 0 }, - { 224, 199, 240, 0 }, - { 115, 165, 41, 0 }, - { 7, 241, 131, 1 }, }, - { { 74, 93, 8, 0 }, - { 193, 9, 193, 1 }, - { 8, 93, 41, 0 }, - { 193, 200, 65, 1 }, }, - { { 74, 93, 11, 1 }, - { 201, 75, 193, 1 }, - { 232, 93, 41, 0 }, - { 193, 233, 73, 1 }, }, - { { 74, 93, 4, 1 }, - { 201, 9, 209, 0 }, - { 144, 93, 41, 0 }, - { 69, 200, 73, 1 }, }, - { { 74, 93, 7, 0 }, - { 193, 75, 209, 0 }, - { 112, 93, 41, 0 }, - { 69, 233, 65, 1 }, }, - { { 74, 93, 120, 0 }, - { 209, 141, 193, 1 }, - { 15, 93, 41, 0 }, - { 193, 216, 197, 1 }, }, - { { 74, 93, 123, 1 }, - { 217, 207, 193, 1 }, - { 239, 93, 41, 0 }, - { 193, 249, 205, 1 }, }, - { { 74, 93, 116, 1 }, - { 217, 141, 209, 0 }, - { 151, 93, 41, 0 }, - { 69, 216, 205, 1 }, }, - { { 74, 93, 119, 0 }, - { 209, 207, 209, 0 }, - { 119, 93, 41, 0 }, - { 69, 249, 197, 1 }, }, - { { 74, 92, 152, 0 }, - { 209, 9, 224, 1 }, - { 12, 157, 41, 0 }, - { 131, 200, 69, 1 }, }, - { { 74, 92, 155, 1 }, - { 217, 75, 224, 1 }, - { 236, 157, 41, 0 }, - { 131, 233, 77, 1 }, }, - { { 74, 92, 148, 1 }, - { 217, 9, 240, 0 }, - { 148, 157, 41, 0 }, - { 7, 200, 77, 1 }, }, - { { 74, 92, 151, 0 }, - { 209, 75, 240, 0 }, - { 116, 157, 41, 0 }, - { 7, 233, 69, 1 }, }, - { { 74, 92, 232, 0 }, - { 193, 141, 224, 1 }, - { 11, 157, 41, 0 }, - { 131, 216, 193, 1 }, }, - { { 74, 92, 235, 1 }, - { 201, 207, 224, 1 }, - { 235, 157, 41, 0 }, - { 131, 249, 201, 1 }, }, - { { 74, 92, 228, 1 }, - { 201, 141, 240, 0 }, - { 147, 157, 41, 0 }, - { 7, 216, 201, 1 }, }, - { { 74, 92, 231, 0 }, - { 193, 207, 240, 0 }, - { 115, 157, 41, 0 }, - { 7, 249, 193, 1 }, }, - { { 75, 161, 8, 0 }, - { 130, 17, 131, 1 }, - { 8, 66, 233, 0 }, - { 224, 196, 32, 1 }, }, - { { 75, 161, 11, 1 }, - { 138, 83, 131, 1 }, - { 232, 66, 233, 0 }, - { 224, 229, 40, 1 }, }, - { { 75, 161, 4, 1 }, - { 138, 17, 147, 0 }, - { 144, 66, 233, 0 }, - { 100, 196, 40, 1 }, }, - { { 75, 161, 7, 0 }, - { 130, 83, 147, 0 }, - { 112, 66, 233, 0 }, - { 100, 229, 32, 1 }, }, - { { 75, 161, 120, 0 }, - { 146, 149, 131, 1 }, - { 15, 66, 233, 0 }, - { 224, 212, 164, 1 }, }, - { { 75, 161, 123, 1 }, - { 154, 215, 131, 1 }, - { 239, 66, 233, 0 }, - { 224, 245, 172, 1 }, }, - { { 75, 161, 116, 1 }, - { 154, 149, 147, 0 }, - { 151, 66, 233, 0 }, - { 100, 212, 172, 1 }, }, - { { 75, 161, 119, 0 }, - { 146, 215, 147, 0 }, - { 119, 66, 233, 0 }, - { 100, 245, 164, 1 }, }, - { { 75, 160, 152, 0 }, - { 146, 17, 162, 1 }, - { 12, 130, 233, 0 }, - { 162, 196, 36, 1 }, }, - { { 75, 160, 155, 1 }, - { 154, 83, 162, 1 }, - { 236, 130, 233, 0 }, - { 162, 229, 44, 1 }, }, - { { 75, 160, 148, 1 }, - { 154, 17, 178, 0 }, - { 148, 130, 233, 0 }, - { 38, 196, 44, 1 }, }, - { { 75, 160, 151, 0 }, - { 146, 83, 178, 0 }, - { 116, 130, 233, 0 }, - { 38, 229, 36, 1 }, }, - { { 75, 160, 232, 0 }, - { 130, 149, 162, 1 }, - { 11, 130, 233, 0 }, - { 162, 212, 160, 1 }, }, - { { 75, 160, 235, 1 }, - { 138, 215, 162, 1 }, - { 235, 130, 233, 0 }, - { 162, 245, 168, 1 }, }, - { { 75, 160, 228, 1 }, - { 138, 149, 178, 0 }, - { 147, 130, 233, 0 }, - { 38, 212, 168, 1 }, }, - { { 75, 160, 231, 0 }, - { 130, 215, 178, 0 }, - { 115, 130, 233, 0 }, - { 38, 245, 160, 1 }, }, - { { 75, 175, 8, 0 }, - { 163, 25, 131, 1 }, - { 8, 122, 233, 0 }, - { 224, 204, 98, 1 }, }, - { { 75, 175, 11, 1 }, - { 171, 91, 131, 1 }, - { 232, 122, 233, 0 }, - { 224, 237, 106, 1 }, }, - { { 75, 175, 4, 1 }, - { 171, 25, 147, 0 }, - { 144, 122, 233, 0 }, - { 100, 204, 106, 1 }, }, - { { 75, 175, 7, 0 }, - { 163, 91, 147, 0 }, - { 112, 122, 233, 0 }, - { 100, 237, 98, 1 }, }, - { { 75, 175, 120, 0 }, - { 179, 157, 131, 1 }, - { 15, 122, 233, 0 }, - { 224, 220, 230, 1 }, }, - { { 75, 175, 123, 1 }, - { 187, 223, 131, 1 }, - { 239, 122, 233, 0 }, - { 224, 253, 238, 1 }, }, - { { 75, 175, 116, 1 }, - { 187, 157, 147, 0 }, - { 151, 122, 233, 0 }, - { 100, 220, 238, 1 }, }, - { { 75, 175, 119, 0 }, - { 179, 223, 147, 0 }, - { 119, 122, 233, 0 }, - { 100, 253, 230, 1 }, }, - { { 75, 174, 152, 0 }, - { 179, 25, 162, 1 }, - { 12, 186, 233, 0 }, - { 162, 204, 102, 1 }, }, - { { 75, 174, 155, 1 }, - { 187, 91, 162, 1 }, - { 236, 186, 233, 0 }, - { 162, 237, 110, 1 }, }, - { { 75, 174, 148, 1 }, - { 187, 25, 178, 0 }, - { 148, 186, 233, 0 }, - { 38, 204, 110, 1 }, }, - { { 75, 174, 151, 0 }, - { 179, 91, 178, 0 }, - { 116, 186, 233, 0 }, - { 38, 237, 102, 1 }, }, - { { 75, 174, 232, 0 }, - { 163, 157, 162, 1 }, - { 11, 186, 233, 0 }, - { 162, 220, 226, 1 }, }, - { { 75, 174, 235, 1 }, - { 171, 223, 162, 1 }, - { 235, 186, 233, 0 }, - { 162, 253, 234, 1 }, }, - { { 75, 174, 228, 1 }, - { 171, 157, 178, 0 }, - { 147, 186, 233, 0 }, - { 38, 220, 234, 1 }, }, - { { 75, 174, 231, 0 }, - { 163, 223, 178, 0 }, - { 115, 186, 233, 0 }, - { 38, 253, 226, 1 }, }, - { { 75, 147, 8, 0 }, - { 162, 17, 193, 1 }, - { 8, 100, 233, 0 }, - { 193, 196, 34, 1 }, }, - { { 75, 147, 11, 1 }, - { 170, 83, 193, 1 }, - { 232, 100, 233, 0 }, - { 193, 229, 42, 1 }, }, - { { 75, 147, 4, 1 }, - { 170, 17, 209, 0 }, - { 144, 100, 233, 0 }, - { 69, 196, 42, 1 }, }, - { { 75, 147, 7, 0 }, - { 162, 83, 209, 0 }, - { 112, 100, 233, 0 }, - { 69, 229, 34, 1 }, }, - { { 75, 147, 120, 0 }, - { 178, 149, 193, 1 }, - { 15, 100, 233, 0 }, - { 193, 212, 166, 1 }, }, - { { 75, 147, 123, 1 }, - { 186, 215, 193, 1 }, - { 239, 100, 233, 0 }, - { 193, 245, 174, 1 }, }, - { { 75, 147, 116, 1 }, - { 186, 149, 209, 0 }, - { 151, 100, 233, 0 }, - { 69, 212, 174, 1 }, }, - { { 75, 147, 119, 0 }, - { 178, 215, 209, 0 }, - { 119, 100, 233, 0 }, - { 69, 245, 166, 1 }, }, - { { 75, 146, 152, 0 }, - { 178, 17, 224, 1 }, - { 12, 164, 233, 0 }, - { 131, 196, 38, 1 }, }, - { { 75, 146, 155, 1 }, - { 186, 83, 224, 1 }, - { 236, 164, 233, 0 }, - { 131, 229, 46, 1 }, }, - { { 75, 146, 148, 1 }, - { 186, 17, 240, 0 }, - { 148, 164, 233, 0 }, - { 7, 196, 46, 1 }, }, - { { 75, 146, 151, 0 }, - { 178, 83, 240, 0 }, - { 116, 164, 233, 0 }, - { 7, 229, 38, 1 }, }, - { { 75, 146, 232, 0 }, - { 162, 149, 224, 1 }, - { 11, 164, 233, 0 }, - { 131, 212, 162, 1 }, }, - { { 75, 146, 235, 1 }, - { 170, 215, 224, 1 }, - { 235, 164, 233, 0 }, - { 131, 245, 170, 1 }, }, - { { 75, 146, 228, 1 }, - { 170, 149, 240, 0 }, - { 147, 164, 233, 0 }, - { 7, 212, 170, 1 }, }, - { { 75, 146, 231, 0 }, - { 162, 215, 240, 0 }, - { 115, 164, 233, 0 }, - { 7, 245, 162, 1 }, }, - { { 75, 157, 8, 0 }, - { 131, 25, 193, 1 }, - { 8, 92, 233, 0 }, - { 193, 204, 96, 1 }, }, - { { 75, 157, 11, 1 }, - { 139, 91, 193, 1 }, - { 232, 92, 233, 0 }, - { 193, 237, 104, 1 }, }, - { { 75, 157, 4, 1 }, - { 139, 25, 209, 0 }, - { 144, 92, 233, 0 }, - { 69, 204, 104, 1 }, }, - { { 75, 157, 7, 0 }, - { 131, 91, 209, 0 }, - { 112, 92, 233, 0 }, - { 69, 237, 96, 1 }, }, - { { 75, 157, 120, 0 }, - { 147, 157, 193, 1 }, - { 15, 92, 233, 0 }, - { 193, 220, 228, 1 }, }, - { { 75, 157, 123, 1 }, - { 155, 223, 193, 1 }, - { 239, 92, 233, 0 }, - { 193, 253, 236, 1 }, }, - { { 75, 157, 116, 1 }, - { 155, 157, 209, 0 }, - { 151, 92, 233, 0 }, - { 69, 220, 236, 1 }, }, - { { 75, 157, 119, 0 }, - { 147, 223, 209, 0 }, - { 119, 92, 233, 0 }, - { 69, 253, 228, 1 }, }, - { { 75, 156, 152, 0 }, - { 147, 25, 224, 1 }, - { 12, 156, 233, 0 }, - { 131, 204, 100, 1 }, }, - { { 75, 156, 155, 1 }, - { 155, 91, 224, 1 }, - { 236, 156, 233, 0 }, - { 131, 237, 108, 1 }, }, - { { 75, 156, 148, 1 }, - { 155, 25, 240, 0 }, - { 148, 156, 233, 0 }, - { 7, 204, 108, 1 }, }, - { { 75, 156, 151, 0 }, - { 147, 91, 240, 0 }, - { 116, 156, 233, 0 }, - { 7, 237, 100, 1 }, }, - { { 75, 156, 232, 0 }, - { 131, 157, 224, 1 }, - { 11, 156, 233, 0 }, - { 131, 220, 224, 1 }, }, - { { 75, 156, 235, 1 }, - { 139, 223, 224, 1 }, - { 235, 156, 233, 0 }, - { 131, 253, 232, 1 }, }, - { { 75, 156, 228, 1 }, - { 139, 157, 240, 0 }, - { 147, 156, 233, 0 }, - { 7, 220, 232, 1 }, }, - { { 75, 156, 231, 0 }, - { 131, 223, 240, 0 }, - { 115, 156, 233, 0 }, - { 7, 253, 224, 1 }, }, - { { 116, 33, 8, 0 }, - { 4, 33, 7, 1 }, - { 8, 66, 23, 0 }, - { 240, 66, 16, 0 }, }, - { { 116, 33, 11, 1 }, - { 12, 99, 7, 1 }, - { 232, 66, 23, 0 }, - { 240, 99, 24, 0 }, }, - { { 116, 33, 4, 1 }, - { 12, 33, 23, 0 }, - { 144, 66, 23, 0 }, - { 116, 66, 24, 0 }, }, - { { 116, 33, 7, 0 }, - { 4, 99, 23, 0 }, - { 112, 66, 23, 0 }, - { 116, 99, 16, 0 }, }, - { { 116, 33, 120, 0 }, - { 20, 165, 7, 1 }, - { 15, 66, 23, 0 }, - { 240, 82, 148, 0 }, }, - { { 116, 33, 123, 1 }, - { 28, 231, 7, 1 }, - { 239, 66, 23, 0 }, - { 240, 115, 156, 0 }, }, - { { 116, 33, 116, 1 }, - { 28, 165, 23, 0 }, - { 151, 66, 23, 0 }, - { 116, 82, 156, 0 }, }, - { { 116, 33, 119, 0 }, - { 20, 231, 23, 0 }, - { 119, 66, 23, 0 }, - { 116, 115, 148, 0 }, }, - { { 116, 32, 152, 0 }, - { 20, 33, 38, 1 }, - { 12, 130, 23, 0 }, - { 178, 66, 20, 0 }, }, - { { 116, 32, 155, 1 }, - { 28, 99, 38, 1 }, - { 236, 130, 23, 0 }, - { 178, 99, 28, 0 }, }, - { { 116, 32, 148, 1 }, - { 28, 33, 54, 0 }, - { 148, 130, 23, 0 }, - { 54, 66, 28, 0 }, }, - { { 116, 32, 151, 0 }, - { 20, 99, 54, 0 }, - { 116, 130, 23, 0 }, - { 54, 99, 20, 0 }, }, - { { 116, 32, 232, 0 }, - { 4, 165, 38, 1 }, - { 11, 130, 23, 0 }, - { 178, 82, 144, 0 }, }, - { { 116, 32, 235, 1 }, - { 12, 231, 38, 1 }, - { 235, 130, 23, 0 }, - { 178, 115, 152, 0 }, }, - { { 116, 32, 228, 1 }, - { 12, 165, 54, 0 }, - { 147, 130, 23, 0 }, - { 54, 82, 152, 0 }, }, - { { 116, 32, 231, 0 }, - { 4, 231, 54, 0 }, - { 115, 130, 23, 0 }, - { 54, 115, 144, 0 }, }, - { { 116, 47, 8, 0 }, - { 37, 41, 7, 1 }, - { 8, 122, 23, 0 }, - { 240, 74, 82, 0 }, }, - { { 116, 47, 11, 1 }, - { 45, 107, 7, 1 }, - { 232, 122, 23, 0 }, - { 240, 107, 90, 0 }, }, - { { 116, 47, 4, 1 }, - { 45, 41, 23, 0 }, - { 144, 122, 23, 0 }, - { 116, 74, 90, 0 }, }, - { { 116, 47, 7, 0 }, - { 37, 107, 23, 0 }, - { 112, 122, 23, 0 }, - { 116, 107, 82, 0 }, }, - { { 116, 47, 120, 0 }, - { 53, 173, 7, 1 }, - { 15, 122, 23, 0 }, - { 240, 90, 214, 0 }, }, - { { 116, 47, 123, 1 }, - { 61, 239, 7, 1 }, - { 239, 122, 23, 0 }, - { 240, 123, 222, 0 }, }, - { { 116, 47, 116, 1 }, - { 61, 173, 23, 0 }, - { 151, 122, 23, 0 }, - { 116, 90, 222, 0 }, }, - { { 116, 47, 119, 0 }, - { 53, 239, 23, 0 }, - { 119, 122, 23, 0 }, - { 116, 123, 214, 0 }, }, - { { 116, 46, 152, 0 }, - { 53, 41, 38, 1 }, - { 12, 186, 23, 0 }, - { 178, 74, 86, 0 }, }, - { { 116, 46, 155, 1 }, - { 61, 107, 38, 1 }, - { 236, 186, 23, 0 }, - { 178, 107, 94, 0 }, }, - { { 116, 46, 148, 1 }, - { 61, 41, 54, 0 }, - { 148, 186, 23, 0 }, - { 54, 74, 94, 0 }, }, - { { 116, 46, 151, 0 }, - { 53, 107, 54, 0 }, - { 116, 186, 23, 0 }, - { 54, 107, 86, 0 }, }, - { { 116, 46, 232, 0 }, - { 37, 173, 38, 1 }, - { 11, 186, 23, 0 }, - { 178, 90, 210, 0 }, }, - { { 116, 46, 235, 1 }, - { 45, 239, 38, 1 }, - { 235, 186, 23, 0 }, - { 178, 123, 218, 0 }, }, - { { 116, 46, 228, 1 }, - { 45, 173, 54, 0 }, - { 147, 186, 23, 0 }, - { 54, 90, 218, 0 }, }, - { { 116, 46, 231, 0 }, - { 37, 239, 54, 0 }, - { 115, 186, 23, 0 }, - { 54, 123, 210, 0 }, }, - { { 116, 19, 8, 0 }, - { 36, 33, 69, 1 }, - { 8, 100, 23, 0 }, - { 209, 66, 18, 0 }, }, - { { 116, 19, 11, 1 }, - { 44, 99, 69, 1 }, - { 232, 100, 23, 0 }, - { 209, 99, 26, 0 }, }, - { { 116, 19, 4, 1 }, - { 44, 33, 85, 0 }, - { 144, 100, 23, 0 }, - { 85, 66, 26, 0 }, }, - { { 116, 19, 7, 0 }, - { 36, 99, 85, 0 }, - { 112, 100, 23, 0 }, - { 85, 99, 18, 0 }, }, - { { 116, 19, 120, 0 }, - { 52, 165, 69, 1 }, - { 15, 100, 23, 0 }, - { 209, 82, 150, 0 }, }, - { { 116, 19, 123, 1 }, - { 60, 231, 69, 1 }, - { 239, 100, 23, 0 }, - { 209, 115, 158, 0 }, }, - { { 116, 19, 116, 1 }, - { 60, 165, 85, 0 }, - { 151, 100, 23, 0 }, - { 85, 82, 158, 0 }, }, - { { 116, 19, 119, 0 }, - { 52, 231, 85, 0 }, - { 119, 100, 23, 0 }, - { 85, 115, 150, 0 }, }, - { { 116, 18, 152, 0 }, - { 52, 33, 100, 1 }, - { 12, 164, 23, 0 }, - { 147, 66, 22, 0 }, }, - { { 116, 18, 155, 1 }, - { 60, 99, 100, 1 }, - { 236, 164, 23, 0 }, - { 147, 99, 30, 0 }, }, - { { 116, 18, 148, 1 }, - { 60, 33, 116, 0 }, - { 148, 164, 23, 0 }, - { 23, 66, 30, 0 }, }, - { { 116, 18, 151, 0 }, - { 52, 99, 116, 0 }, - { 116, 164, 23, 0 }, - { 23, 99, 22, 0 }, }, - { { 116, 18, 232, 0 }, - { 36, 165, 100, 1 }, - { 11, 164, 23, 0 }, - { 147, 82, 146, 0 }, }, - { { 116, 18, 235, 1 }, - { 44, 231, 100, 1 }, - { 235, 164, 23, 0 }, - { 147, 115, 154, 0 }, }, - { { 116, 18, 228, 1 }, - { 44, 165, 116, 0 }, - { 147, 164, 23, 0 }, - { 23, 82, 154, 0 }, }, - { { 116, 18, 231, 0 }, - { 36, 231, 116, 0 }, - { 115, 164, 23, 0 }, - { 23, 115, 146, 0 }, }, - { { 116, 29, 8, 0 }, - { 5, 41, 69, 1 }, - { 8, 92, 23, 0 }, - { 209, 74, 80, 0 }, }, - { { 116, 29, 11, 1 }, - { 13, 107, 69, 1 }, - { 232, 92, 23, 0 }, - { 209, 107, 88, 0 }, }, - { { 116, 29, 4, 1 }, - { 13, 41, 85, 0 }, - { 144, 92, 23, 0 }, - { 85, 74, 88, 0 }, }, - { { 116, 29, 7, 0 }, - { 5, 107, 85, 0 }, - { 112, 92, 23, 0 }, - { 85, 107, 80, 0 }, }, - { { 116, 29, 120, 0 }, - { 21, 173, 69, 1 }, - { 15, 92, 23, 0 }, - { 209, 90, 212, 0 }, }, - { { 116, 29, 123, 1 }, - { 29, 239, 69, 1 }, - { 239, 92, 23, 0 }, - { 209, 123, 220, 0 }, }, - { { 116, 29, 116, 1 }, - { 29, 173, 85, 0 }, - { 151, 92, 23, 0 }, - { 85, 90, 220, 0 }, }, - { { 116, 29, 119, 0 }, - { 21, 239, 85, 0 }, - { 119, 92, 23, 0 }, - { 85, 123, 212, 0 }, }, - { { 116, 28, 152, 0 }, - { 21, 41, 100, 1 }, - { 12, 156, 23, 0 }, - { 147, 74, 84, 0 }, }, - { { 116, 28, 155, 1 }, - { 29, 107, 100, 1 }, - { 236, 156, 23, 0 }, - { 147, 107, 92, 0 }, }, - { { 116, 28, 148, 1 }, - { 29, 41, 116, 0 }, - { 148, 156, 23, 0 }, - { 23, 74, 92, 0 }, }, - { { 116, 28, 151, 0 }, - { 21, 107, 116, 0 }, - { 116, 156, 23, 0 }, - { 23, 107, 84, 0 }, }, - { { 116, 28, 232, 0 }, - { 5, 173, 100, 1 }, - { 11, 156, 23, 0 }, - { 147, 90, 208, 0 }, }, - { { 116, 28, 235, 1 }, - { 13, 239, 100, 1 }, - { 235, 156, 23, 0 }, - { 147, 123, 216, 0 }, }, - { { 116, 28, 228, 1 }, - { 13, 173, 116, 0 }, - { 147, 156, 23, 0 }, - { 23, 90, 216, 0 }, }, - { { 116, 28, 231, 0 }, - { 5, 239, 116, 0 }, - { 115, 156, 23, 0 }, - { 23, 123, 208, 0 }, }, - { { 117, 225, 8, 0 }, - { 70, 49, 7, 1 }, - { 8, 67, 215, 0 }, - { 240, 70, 49, 0 }, }, - { { 117, 225, 11, 1 }, - { 78, 115, 7, 1 }, - { 232, 67, 215, 0 }, - { 240, 103, 57, 0 }, }, - { { 117, 225, 4, 1 }, - { 78, 49, 23, 0 }, - { 144, 67, 215, 0 }, - { 116, 70, 57, 0 }, }, - { { 117, 225, 7, 0 }, - { 70, 115, 23, 0 }, - { 112, 67, 215, 0 }, - { 116, 103, 49, 0 }, }, - { { 117, 225, 120, 0 }, - { 86, 181, 7, 1 }, - { 15, 67, 215, 0 }, - { 240, 86, 181, 0 }, }, - { { 117, 225, 123, 1 }, - { 94, 247, 7, 1 }, - { 239, 67, 215, 0 }, - { 240, 119, 189, 0 }, }, - { { 117, 225, 116, 1 }, - { 94, 181, 23, 0 }, - { 151, 67, 215, 0 }, - { 116, 86, 189, 0 }, }, - { { 117, 225, 119, 0 }, - { 86, 247, 23, 0 }, - { 119, 67, 215, 0 }, - { 116, 119, 181, 0 }, }, - { { 117, 224, 152, 0 }, - { 86, 49, 38, 1 }, - { 12, 131, 215, 0 }, - { 178, 70, 53, 0 }, }, - { { 117, 224, 155, 1 }, - { 94, 115, 38, 1 }, - { 236, 131, 215, 0 }, - { 178, 103, 61, 0 }, }, - { { 117, 224, 148, 1 }, - { 94, 49, 54, 0 }, - { 148, 131, 215, 0 }, - { 54, 70, 61, 0 }, }, - { { 117, 224, 151, 0 }, - { 86, 115, 54, 0 }, - { 116, 131, 215, 0 }, - { 54, 103, 53, 0 }, }, - { { 117, 224, 232, 0 }, - { 70, 181, 38, 1 }, - { 11, 131, 215, 0 }, - { 178, 86, 177, 0 }, }, - { { 117, 224, 235, 1 }, - { 78, 247, 38, 1 }, - { 235, 131, 215, 0 }, - { 178, 119, 185, 0 }, }, - { { 117, 224, 228, 1 }, - { 78, 181, 54, 0 }, - { 147, 131, 215, 0 }, - { 54, 86, 185, 0 }, }, - { { 117, 224, 231, 0 }, - { 70, 247, 54, 0 }, - { 115, 131, 215, 0 }, - { 54, 119, 177, 0 }, }, - { { 117, 239, 8, 0 }, - { 103, 57, 7, 1 }, - { 8, 123, 215, 0 }, - { 240, 78, 115, 0 }, }, - { { 117, 239, 11, 1 }, - { 111, 123, 7, 1 }, - { 232, 123, 215, 0 }, - { 240, 111, 123, 0 }, }, - { { 117, 239, 4, 1 }, - { 111, 57, 23, 0 }, - { 144, 123, 215, 0 }, - { 116, 78, 123, 0 }, }, - { { 117, 239, 7, 0 }, - { 103, 123, 23, 0 }, - { 112, 123, 215, 0 }, - { 116, 111, 115, 0 }, }, - { { 117, 239, 120, 0 }, - { 119, 189, 7, 1 }, - { 15, 123, 215, 0 }, - { 240, 94, 247, 0 }, }, - { { 117, 239, 123, 1 }, - { 127, 255, 7, 1 }, - { 239, 123, 215, 0 }, - { 240, 127, 255, 0 }, }, - { { 117, 239, 116, 1 }, - { 127, 189, 23, 0 }, - { 151, 123, 215, 0 }, - { 116, 94, 255, 0 }, }, - { { 117, 239, 119, 0 }, - { 119, 255, 23, 0 }, - { 119, 123, 215, 0 }, - { 116, 127, 247, 0 }, }, - { { 117, 238, 152, 0 }, - { 119, 57, 38, 1 }, - { 12, 187, 215, 0 }, - { 178, 78, 119, 0 }, }, - { { 117, 238, 155, 1 }, - { 127, 123, 38, 1 }, - { 236, 187, 215, 0 }, - { 178, 111, 127, 0 }, }, - { { 117, 238, 148, 1 }, - { 127, 57, 54, 0 }, - { 148, 187, 215, 0 }, - { 54, 78, 127, 0 }, }, - { { 117, 238, 151, 0 }, - { 119, 123, 54, 0 }, - { 116, 187, 215, 0 }, - { 54, 111, 119, 0 }, }, - { { 117, 238, 232, 0 }, - { 103, 189, 38, 1 }, - { 11, 187, 215, 0 }, - { 178, 94, 243, 0 }, }, - { { 117, 238, 235, 1 }, - { 111, 255, 38, 1 }, - { 235, 187, 215, 0 }, - { 178, 127, 251, 0 }, }, - { { 117, 238, 228, 1 }, - { 111, 189, 54, 0 }, - { 147, 187, 215, 0 }, - { 54, 94, 251, 0 }, }, - { { 117, 238, 231, 0 }, - { 103, 255, 54, 0 }, - { 115, 187, 215, 0 }, - { 54, 127, 243, 0 }, }, - { { 117, 211, 8, 0 }, - { 102, 49, 69, 1 }, - { 8, 101, 215, 0 }, - { 209, 70, 51, 0 }, }, - { { 117, 211, 11, 1 }, - { 110, 115, 69, 1 }, - { 232, 101, 215, 0 }, - { 209, 103, 59, 0 }, }, - { { 117, 211, 4, 1 }, - { 110, 49, 85, 0 }, - { 144, 101, 215, 0 }, - { 85, 70, 59, 0 }, }, - { { 117, 211, 7, 0 }, - { 102, 115, 85, 0 }, - { 112, 101, 215, 0 }, - { 85, 103, 51, 0 }, }, - { { 117, 211, 120, 0 }, - { 118, 181, 69, 1 }, - { 15, 101, 215, 0 }, - { 209, 86, 183, 0 }, }, - { { 117, 211, 123, 1 }, - { 126, 247, 69, 1 }, - { 239, 101, 215, 0 }, - { 209, 119, 191, 0 }, }, - { { 117, 211, 116, 1 }, - { 126, 181, 85, 0 }, - { 151, 101, 215, 0 }, - { 85, 86, 191, 0 }, }, - { { 117, 211, 119, 0 }, - { 118, 247, 85, 0 }, - { 119, 101, 215, 0 }, - { 85, 119, 183, 0 }, }, - { { 117, 210, 152, 0 }, - { 118, 49, 100, 1 }, - { 12, 165, 215, 0 }, - { 147, 70, 55, 0 }, }, - { { 117, 210, 155, 1 }, - { 126, 115, 100, 1 }, - { 236, 165, 215, 0 }, - { 147, 103, 63, 0 }, }, - { { 117, 210, 148, 1 }, - { 126, 49, 116, 0 }, - { 148, 165, 215, 0 }, - { 23, 70, 63, 0 }, }, - { { 117, 210, 151, 0 }, - { 118, 115, 116, 0 }, - { 116, 165, 215, 0 }, - { 23, 103, 55, 0 }, }, - { { 117, 210, 232, 0 }, - { 102, 181, 100, 1 }, - { 11, 165, 215, 0 }, - { 147, 86, 179, 0 }, }, - { { 117, 210, 235, 1 }, - { 110, 247, 100, 1 }, - { 235, 165, 215, 0 }, - { 147, 119, 187, 0 }, }, - { { 117, 210, 228, 1 }, - { 110, 181, 116, 0 }, - { 147, 165, 215, 0 }, - { 23, 86, 187, 0 }, }, - { { 117, 210, 231, 0 }, - { 102, 247, 116, 0 }, - { 115, 165, 215, 0 }, - { 23, 119, 179, 0 }, }, - { { 117, 221, 8, 0 }, - { 71, 57, 69, 1 }, - { 8, 93, 215, 0 }, - { 209, 78, 113, 0 }, }, - { { 117, 221, 11, 1 }, - { 79, 123, 69, 1 }, - { 232, 93, 215, 0 }, - { 209, 111, 121, 0 }, }, - { { 117, 221, 4, 1 }, - { 79, 57, 85, 0 }, - { 144, 93, 215, 0 }, - { 85, 78, 121, 0 }, }, - { { 117, 221, 7, 0 }, - { 71, 123, 85, 0 }, - { 112, 93, 215, 0 }, - { 85, 111, 113, 0 }, }, - { { 117, 221, 120, 0 }, - { 87, 189, 69, 1 }, - { 15, 93, 215, 0 }, - { 209, 94, 245, 0 }, }, - { { 117, 221, 123, 1 }, - { 95, 255, 69, 1 }, - { 239, 93, 215, 0 }, - { 209, 127, 253, 0 }, }, - { { 117, 221, 116, 1 }, - { 95, 189, 85, 0 }, - { 151, 93, 215, 0 }, - { 85, 94, 253, 0 }, }, - { { 117, 221, 119, 0 }, - { 87, 255, 85, 0 }, - { 119, 93, 215, 0 }, - { 85, 127, 245, 0 }, }, - { { 117, 220, 152, 0 }, - { 87, 57, 100, 1 }, - { 12, 157, 215, 0 }, - { 147, 78, 117, 0 }, }, - { { 117, 220, 155, 1 }, - { 95, 123, 100, 1 }, - { 236, 157, 215, 0 }, - { 147, 111, 125, 0 }, }, - { { 117, 220, 148, 1 }, - { 95, 57, 116, 0 }, - { 148, 157, 215, 0 }, - { 23, 78, 125, 0 }, }, - { { 117, 220, 151, 0 }, - { 87, 123, 116, 0 }, - { 116, 157, 215, 0 }, - { 23, 111, 117, 0 }, }, - { { 117, 220, 232, 0 }, - { 71, 189, 100, 1 }, - { 11, 157, 215, 0 }, - { 147, 94, 241, 0 }, }, - { { 117, 220, 235, 1 }, - { 79, 255, 100, 1 }, - { 235, 157, 215, 0 }, - { 147, 127, 249, 0 }, }, - { { 117, 220, 228, 1 }, - { 79, 189, 116, 0 }, - { 147, 157, 215, 0 }, - { 23, 94, 249, 0 }, }, - { { 117, 220, 231, 0 }, - { 71, 255, 116, 0 }, - { 115, 157, 215, 0 }, - { 23, 127, 241, 0 }, }, - { { 114, 97, 8, 0 }, - { 68, 33, 131, 1 }, - { 8, 67, 39, 0 }, - { 224, 194, 17, 0 }, }, - { { 114, 97, 11, 1 }, - { 76, 99, 131, 1 }, - { 232, 67, 39, 0 }, - { 224, 227, 25, 0 }, }, - { { 114, 97, 4, 1 }, - { 76, 33, 147, 0 }, - { 144, 67, 39, 0 }, - { 100, 194, 25, 0 }, }, - { { 114, 97, 7, 0 }, - { 68, 99, 147, 0 }, - { 112, 67, 39, 0 }, - { 100, 227, 17, 0 }, }, - { { 114, 97, 120, 0 }, - { 84, 165, 131, 1 }, - { 15, 67, 39, 0 }, - { 224, 210, 149, 0 }, }, - { { 114, 97, 123, 1 }, - { 92, 231, 131, 1 }, - { 239, 67, 39, 0 }, - { 224, 243, 157, 0 }, }, - { { 114, 97, 116, 1 }, - { 92, 165, 147, 0 }, - { 151, 67, 39, 0 }, - { 100, 210, 157, 0 }, }, - { { 114, 97, 119, 0 }, - { 84, 231, 147, 0 }, - { 119, 67, 39, 0 }, - { 100, 243, 149, 0 }, }, - { { 114, 96, 152, 0 }, - { 84, 33, 162, 1 }, - { 12, 131, 39, 0 }, - { 162, 194, 21, 0 }, }, - { { 114, 96, 155, 1 }, - { 92, 99, 162, 1 }, - { 236, 131, 39, 0 }, - { 162, 227, 29, 0 }, }, - { { 114, 96, 148, 1 }, - { 92, 33, 178, 0 }, - { 148, 131, 39, 0 }, - { 38, 194, 29, 0 }, }, - { { 114, 96, 151, 0 }, - { 84, 99, 178, 0 }, - { 116, 131, 39, 0 }, - { 38, 227, 21, 0 }, }, - { { 114, 96, 232, 0 }, - { 68, 165, 162, 1 }, - { 11, 131, 39, 0 }, - { 162, 210, 145, 0 }, }, - { { 114, 96, 235, 1 }, - { 76, 231, 162, 1 }, - { 235, 131, 39, 0 }, - { 162, 243, 153, 0 }, }, - { { 114, 96, 228, 1 }, - { 76, 165, 178, 0 }, - { 147, 131, 39, 0 }, - { 38, 210, 153, 0 }, }, - { { 114, 96, 231, 0 }, - { 68, 231, 178, 0 }, - { 115, 131, 39, 0 }, - { 38, 243, 145, 0 }, }, - { { 114, 111, 8, 0 }, - { 101, 41, 131, 1 }, - { 8, 123, 39, 0 }, - { 224, 202, 83, 0 }, }, - { { 114, 111, 11, 1 }, - { 109, 107, 131, 1 }, - { 232, 123, 39, 0 }, - { 224, 235, 91, 0 }, }, - { { 114, 111, 4, 1 }, - { 109, 41, 147, 0 }, - { 144, 123, 39, 0 }, - { 100, 202, 91, 0 }, }, - { { 114, 111, 7, 0 }, - { 101, 107, 147, 0 }, - { 112, 123, 39, 0 }, - { 100, 235, 83, 0 }, }, - { { 114, 111, 120, 0 }, - { 117, 173, 131, 1 }, - { 15, 123, 39, 0 }, - { 224, 218, 215, 0 }, }, - { { 114, 111, 123, 1 }, - { 125, 239, 131, 1 }, - { 239, 123, 39, 0 }, - { 224, 251, 223, 0 }, }, - { { 114, 111, 116, 1 }, - { 125, 173, 147, 0 }, - { 151, 123, 39, 0 }, - { 100, 218, 223, 0 }, }, - { { 114, 111, 119, 0 }, - { 117, 239, 147, 0 }, - { 119, 123, 39, 0 }, - { 100, 251, 215, 0 }, }, - { { 114, 110, 152, 0 }, - { 117, 41, 162, 1 }, - { 12, 187, 39, 0 }, - { 162, 202, 87, 0 }, }, - { { 114, 110, 155, 1 }, - { 125, 107, 162, 1 }, - { 236, 187, 39, 0 }, - { 162, 235, 95, 0 }, }, - { { 114, 110, 148, 1 }, - { 125, 41, 178, 0 }, - { 148, 187, 39, 0 }, - { 38, 202, 95, 0 }, }, - { { 114, 110, 151, 0 }, - { 117, 107, 178, 0 }, - { 116, 187, 39, 0 }, - { 38, 235, 87, 0 }, }, - { { 114, 110, 232, 0 }, - { 101, 173, 162, 1 }, - { 11, 187, 39, 0 }, - { 162, 218, 211, 0 }, }, - { { 114, 110, 235, 1 }, - { 109, 239, 162, 1 }, - { 235, 187, 39, 0 }, - { 162, 251, 219, 0 }, }, - { { 114, 110, 228, 1 }, - { 109, 173, 178, 0 }, - { 147, 187, 39, 0 }, - { 38, 218, 219, 0 }, }, - { { 114, 110, 231, 0 }, - { 101, 239, 178, 0 }, - { 115, 187, 39, 0 }, - { 38, 251, 211, 0 }, }, - { { 114, 83, 8, 0 }, - { 100, 33, 193, 1 }, - { 8, 101, 39, 0 }, - { 193, 194, 19, 0 }, }, - { { 114, 83, 11, 1 }, - { 108, 99, 193, 1 }, - { 232, 101, 39, 0 }, - { 193, 227, 27, 0 }, }, - { { 114, 83, 4, 1 }, - { 108, 33, 209, 0 }, - { 144, 101, 39, 0 }, - { 69, 194, 27, 0 }, }, - { { 114, 83, 7, 0 }, - { 100, 99, 209, 0 }, - { 112, 101, 39, 0 }, - { 69, 227, 19, 0 }, }, - { { 114, 83, 120, 0 }, - { 116, 165, 193, 1 }, - { 15, 101, 39, 0 }, - { 193, 210, 151, 0 }, }, - { { 114, 83, 123, 1 }, - { 124, 231, 193, 1 }, - { 239, 101, 39, 0 }, - { 193, 243, 159, 0 }, }, - { { 114, 83, 116, 1 }, - { 124, 165, 209, 0 }, - { 151, 101, 39, 0 }, - { 69, 210, 159, 0 }, }, - { { 114, 83, 119, 0 }, - { 116, 231, 209, 0 }, - { 119, 101, 39, 0 }, - { 69, 243, 151, 0 }, }, - { { 114, 82, 152, 0 }, - { 116, 33, 224, 1 }, - { 12, 165, 39, 0 }, - { 131, 194, 23, 0 }, }, - { { 114, 82, 155, 1 }, - { 124, 99, 224, 1 }, - { 236, 165, 39, 0 }, - { 131, 227, 31, 0 }, }, - { { 114, 82, 148, 1 }, - { 124, 33, 240, 0 }, - { 148, 165, 39, 0 }, - { 7, 194, 31, 0 }, }, - { { 114, 82, 151, 0 }, - { 116, 99, 240, 0 }, - { 116, 165, 39, 0 }, - { 7, 227, 23, 0 }, }, - { { 114, 82, 232, 0 }, - { 100, 165, 224, 1 }, - { 11, 165, 39, 0 }, - { 131, 210, 147, 0 }, }, - { { 114, 82, 235, 1 }, - { 108, 231, 224, 1 }, - { 235, 165, 39, 0 }, - { 131, 243, 155, 0 }, }, - { { 114, 82, 228, 1 }, - { 108, 165, 240, 0 }, - { 147, 165, 39, 0 }, - { 7, 210, 155, 0 }, }, - { { 114, 82, 231, 0 }, - { 100, 231, 240, 0 }, - { 115, 165, 39, 0 }, - { 7, 243, 147, 0 }, }, - { { 114, 93, 8, 0 }, - { 69, 41, 193, 1 }, - { 8, 93, 39, 0 }, - { 193, 202, 81, 0 }, }, - { { 114, 93, 11, 1 }, - { 77, 107, 193, 1 }, - { 232, 93, 39, 0 }, - { 193, 235, 89, 0 }, }, - { { 114, 93, 4, 1 }, - { 77, 41, 209, 0 }, - { 144, 93, 39, 0 }, - { 69, 202, 89, 0 }, }, - { { 114, 93, 7, 0 }, - { 69, 107, 209, 0 }, - { 112, 93, 39, 0 }, - { 69, 235, 81, 0 }, }, - { { 114, 93, 120, 0 }, - { 85, 173, 193, 1 }, - { 15, 93, 39, 0 }, - { 193, 218, 213, 0 }, }, - { { 114, 93, 123, 1 }, - { 93, 239, 193, 1 }, - { 239, 93, 39, 0 }, - { 193, 251, 221, 0 }, }, - { { 114, 93, 116, 1 }, - { 93, 173, 209, 0 }, - { 151, 93, 39, 0 }, - { 69, 218, 221, 0 }, }, - { { 114, 93, 119, 0 }, - { 85, 239, 209, 0 }, - { 119, 93, 39, 0 }, - { 69, 251, 213, 0 }, }, - { { 114, 92, 152, 0 }, - { 85, 41, 224, 1 }, - { 12, 157, 39, 0 }, - { 131, 202, 85, 0 }, }, - { { 114, 92, 155, 1 }, - { 93, 107, 224, 1 }, - { 236, 157, 39, 0 }, - { 131, 235, 93, 0 }, }, - { { 114, 92, 148, 1 }, - { 93, 41, 240, 0 }, - { 148, 157, 39, 0 }, - { 7, 202, 93, 0 }, }, - { { 114, 92, 151, 0 }, - { 85, 107, 240, 0 }, - { 116, 157, 39, 0 }, - { 7, 235, 85, 0 }, }, - { { 114, 92, 232, 0 }, - { 69, 173, 224, 1 }, - { 11, 157, 39, 0 }, - { 131, 218, 209, 0 }, }, - { { 114, 92, 235, 1 }, - { 77, 239, 224, 1 }, - { 235, 157, 39, 0 }, - { 131, 251, 217, 0 }, }, - { { 114, 92, 228, 1 }, - { 77, 173, 240, 0 }, - { 147, 157, 39, 0 }, - { 7, 218, 217, 0 }, }, - { { 114, 92, 231, 0 }, - { 69, 239, 240, 0 }, - { 115, 157, 39, 0 }, - { 7, 251, 209, 0 }, }, - { { 115, 161, 8, 0 }, - { 6, 49, 131, 1 }, - { 8, 66, 231, 0 }, - { 224, 198, 48, 0 }, }, - { { 115, 161, 11, 1 }, - { 14, 115, 131, 1 }, - { 232, 66, 231, 0 }, - { 224, 231, 56, 0 }, }, - { { 115, 161, 4, 1 }, - { 14, 49, 147, 0 }, - { 144, 66, 231, 0 }, - { 100, 198, 56, 0 }, }, - { { 115, 161, 7, 0 }, - { 6, 115, 147, 0 }, - { 112, 66, 231, 0 }, - { 100, 231, 48, 0 }, }, - { { 115, 161, 120, 0 }, - { 22, 181, 131, 1 }, - { 15, 66, 231, 0 }, - { 224, 214, 180, 0 }, }, - { { 115, 161, 123, 1 }, - { 30, 247, 131, 1 }, - { 239, 66, 231, 0 }, - { 224, 247, 188, 0 }, }, - { { 115, 161, 116, 1 }, - { 30, 181, 147, 0 }, - { 151, 66, 231, 0 }, - { 100, 214, 188, 0 }, }, - { { 115, 161, 119, 0 }, - { 22, 247, 147, 0 }, - { 119, 66, 231, 0 }, - { 100, 247, 180, 0 }, }, - { { 115, 160, 152, 0 }, - { 22, 49, 162, 1 }, - { 12, 130, 231, 0 }, - { 162, 198, 52, 0 }, }, - { { 115, 160, 155, 1 }, - { 30, 115, 162, 1 }, - { 236, 130, 231, 0 }, - { 162, 231, 60, 0 }, }, - { { 115, 160, 148, 1 }, - { 30, 49, 178, 0 }, - { 148, 130, 231, 0 }, - { 38, 198, 60, 0 }, }, - { { 115, 160, 151, 0 }, - { 22, 115, 178, 0 }, - { 116, 130, 231, 0 }, - { 38, 231, 52, 0 }, }, - { { 115, 160, 232, 0 }, - { 6, 181, 162, 1 }, - { 11, 130, 231, 0 }, - { 162, 214, 176, 0 }, }, - { { 115, 160, 235, 1 }, - { 14, 247, 162, 1 }, - { 235, 130, 231, 0 }, - { 162, 247, 184, 0 }, }, - { { 115, 160, 228, 1 }, - { 14, 181, 178, 0 }, - { 147, 130, 231, 0 }, - { 38, 214, 184, 0 }, }, - { { 115, 160, 231, 0 }, - { 6, 247, 178, 0 }, - { 115, 130, 231, 0 }, - { 38, 247, 176, 0 }, }, - { { 115, 175, 8, 0 }, - { 39, 57, 131, 1 }, - { 8, 122, 231, 0 }, - { 224, 206, 114, 0 }, }, - { { 115, 175, 11, 1 }, - { 47, 123, 131, 1 }, - { 232, 122, 231, 0 }, - { 224, 239, 122, 0 }, }, - { { 115, 175, 4, 1 }, - { 47, 57, 147, 0 }, - { 144, 122, 231, 0 }, - { 100, 206, 122, 0 }, }, - { { 115, 175, 7, 0 }, - { 39, 123, 147, 0 }, - { 112, 122, 231, 0 }, - { 100, 239, 114, 0 }, }, - { { 115, 175, 120, 0 }, - { 55, 189, 131, 1 }, - { 15, 122, 231, 0 }, - { 224, 222, 246, 0 }, }, - { { 115, 175, 123, 1 }, - { 63, 255, 131, 1 }, - { 239, 122, 231, 0 }, - { 224, 255, 254, 0 }, }, - { { 115, 175, 116, 1 }, - { 63, 189, 147, 0 }, - { 151, 122, 231, 0 }, - { 100, 222, 254, 0 }, }, - { { 115, 175, 119, 0 }, - { 55, 255, 147, 0 }, - { 119, 122, 231, 0 }, - { 100, 255, 246, 0 }, }, - { { 115, 174, 152, 0 }, - { 55, 57, 162, 1 }, - { 12, 186, 231, 0 }, - { 162, 206, 118, 0 }, }, - { { 115, 174, 155, 1 }, - { 63, 123, 162, 1 }, - { 236, 186, 231, 0 }, - { 162, 239, 126, 0 }, }, - { { 115, 174, 148, 1 }, - { 63, 57, 178, 0 }, - { 148, 186, 231, 0 }, - { 38, 206, 126, 0 }, }, - { { 115, 174, 151, 0 }, - { 55, 123, 178, 0 }, - { 116, 186, 231, 0 }, - { 38, 239, 118, 0 }, }, - { { 115, 174, 232, 0 }, - { 39, 189, 162, 1 }, - { 11, 186, 231, 0 }, - { 162, 222, 242, 0 }, }, - { { 115, 174, 235, 1 }, - { 47, 255, 162, 1 }, - { 235, 186, 231, 0 }, - { 162, 255, 250, 0 }, }, - { { 115, 174, 228, 1 }, - { 47, 189, 178, 0 }, - { 147, 186, 231, 0 }, - { 38, 222, 250, 0 }, }, - { { 115, 174, 231, 0 }, - { 39, 255, 178, 0 }, - { 115, 186, 231, 0 }, - { 38, 255, 242, 0 }, }, - { { 115, 147, 8, 0 }, - { 38, 49, 193, 1 }, - { 8, 100, 231, 0 }, - { 193, 198, 50, 0 }, }, - { { 115, 147, 11, 1 }, - { 46, 115, 193, 1 }, - { 232, 100, 231, 0 }, - { 193, 231, 58, 0 }, }, - { { 115, 147, 4, 1 }, - { 46, 49, 209, 0 }, - { 144, 100, 231, 0 }, - { 69, 198, 58, 0 }, }, - { { 115, 147, 7, 0 }, - { 38, 115, 209, 0 }, - { 112, 100, 231, 0 }, - { 69, 231, 50, 0 }, }, - { { 115, 147, 120, 0 }, - { 54, 181, 193, 1 }, - { 15, 100, 231, 0 }, - { 193, 214, 182, 0 }, }, - { { 115, 147, 123, 1 }, - { 62, 247, 193, 1 }, - { 239, 100, 231, 0 }, - { 193, 247, 190, 0 }, }, - { { 115, 147, 116, 1 }, - { 62, 181, 209, 0 }, - { 151, 100, 231, 0 }, - { 69, 214, 190, 0 }, }, - { { 115, 147, 119, 0 }, - { 54, 247, 209, 0 }, - { 119, 100, 231, 0 }, - { 69, 247, 182, 0 }, }, - { { 115, 146, 152, 0 }, - { 54, 49, 224, 1 }, - { 12, 164, 231, 0 }, - { 131, 198, 54, 0 }, }, - { { 115, 146, 155, 1 }, - { 62, 115, 224, 1 }, - { 236, 164, 231, 0 }, - { 131, 231, 62, 0 }, }, - { { 115, 146, 148, 1 }, - { 62, 49, 240, 0 }, - { 148, 164, 231, 0 }, - { 7, 198, 62, 0 }, }, - { { 115, 146, 151, 0 }, - { 54, 115, 240, 0 }, - { 116, 164, 231, 0 }, - { 7, 231, 54, 0 }, }, - { { 115, 146, 232, 0 }, - { 38, 181, 224, 1 }, - { 11, 164, 231, 0 }, - { 131, 214, 178, 0 }, }, - { { 115, 146, 235, 1 }, - { 46, 247, 224, 1 }, - { 235, 164, 231, 0 }, - { 131, 247, 186, 0 }, }, - { { 115, 146, 228, 1 }, - { 46, 181, 240, 0 }, - { 147, 164, 231, 0 }, - { 7, 214, 186, 0 }, }, - { { 115, 146, 231, 0 }, - { 38, 247, 240, 0 }, - { 115, 164, 231, 0 }, - { 7, 247, 178, 0 }, }, - { { 115, 157, 8, 0 }, - { 7, 57, 193, 1 }, - { 8, 92, 231, 0 }, - { 193, 206, 112, 0 }, }, - { { 115, 157, 11, 1 }, - { 15, 123, 193, 1 }, - { 232, 92, 231, 0 }, - { 193, 239, 120, 0 }, }, - { { 115, 157, 4, 1 }, - { 15, 57, 209, 0 }, - { 144, 92, 231, 0 }, - { 69, 206, 120, 0 }, }, - { { 115, 157, 7, 0 }, - { 7, 123, 209, 0 }, - { 112, 92, 231, 0 }, - { 69, 239, 112, 0 }, }, - { { 115, 157, 120, 0 }, - { 23, 189, 193, 1 }, - { 15, 92, 231, 0 }, - { 193, 222, 244, 0 }, }, - { { 115, 157, 123, 1 }, - { 31, 255, 193, 1 }, - { 239, 92, 231, 0 }, - { 193, 255, 252, 0 }, }, - { { 115, 157, 116, 1 }, - { 31, 189, 209, 0 }, - { 151, 92, 231, 0 }, - { 69, 222, 252, 0 }, }, - { { 115, 157, 119, 0 }, - { 23, 255, 209, 0 }, - { 119, 92, 231, 0 }, - { 69, 255, 244, 0 }, }, - { { 115, 156, 152, 0 }, - { 23, 57, 224, 1 }, - { 12, 156, 231, 0 }, - { 131, 206, 116, 0 }, }, - { { 115, 156, 155, 1 }, - { 31, 123, 224, 1 }, - { 236, 156, 231, 0 }, - { 131, 239, 124, 0 }, }, - { { 115, 156, 148, 1 }, - { 31, 57, 240, 0 }, - { 148, 156, 231, 0 }, - { 7, 206, 124, 0 }, }, - { { 115, 156, 151, 0 }, - { 23, 123, 240, 0 }, - { 116, 156, 231, 0 }, - { 7, 239, 116, 0 }, }, - { { 115, 156, 232, 0 }, - { 7, 189, 224, 1 }, - { 11, 156, 231, 0 }, - { 131, 222, 240, 0 }, }, - { { 115, 156, 235, 1 }, - { 15, 255, 224, 1 }, - { 235, 156, 231, 0 }, - { 131, 255, 248, 0 }, }, - { { 115, 156, 228, 1 }, - { 15, 189, 240, 0 }, - { 147, 156, 231, 0 }, - { 7, 222, 248, 0 }, }, - { { 115, 156, 231, 0 }, - { 7, 255, 240, 0 }, - { 115, 156, 231, 0 }, - { 7, 255, 240, 0 }, }, -}; - -static unsigned char DICT_4X4_1000_BYTES[][4][2] = - { { { 181, 50 }, - { 235, 72 }, - { 76, 173 }, - { 18, 215 }, }, - { { 15, 154 }, - { 101, 71 }, - { 89, 240 }, - { 226, 166 }, }, - { { 51, 45 }, - { 222, 17 }, - { 180, 204 }, - { 136, 123 }, }, - { { 153, 70 }, - { 193, 60 }, - { 98, 153 }, - { 60, 131 }, }, - { { 84, 158 }, - { 161, 211 }, - { 121, 42 }, - { 203, 133 }, }, - { { 121, 205 }, - { 216, 183 }, - { 179, 158 }, - { 237, 27 }, }, - { { 158, 46 }, - { 135, 93 }, - { 116, 121 }, - { 186, 225 }, }, - { { 196, 242 }, - { 35, 234 }, - { 79, 35 }, - { 87, 196 }, }, - { { 254, 218 }, - { 173, 239 }, - { 91, 127 }, - { 247, 181 }, }, - { { 207, 86 }, - { 101, 252 }, - { 106, 243 }, - { 63, 166 }, }, - { { 249, 145 }, - { 248, 142 }, - { 137, 159 }, - { 113, 31 }, }, - { { 17, 167 }, - { 211, 18 }, - { 229, 136 }, - { 72, 203 }, }, - { { 14, 183 }, - { 55, 86 }, - { 237, 112 }, - { 106, 236 }, }, - { { 42, 15 }, - { 29, 21 }, - { 240, 84 }, - { 168, 184 }, }, - { { 36, 177 }, - { 58, 66 }, - { 141, 36 }, - { 66, 92 }, }, - { { 38, 62 }, - { 47, 81 }, - { 124, 100 }, - { 138, 244 }, }, - { { 70, 101 }, - { 22, 240 }, - { 166, 98 }, - { 15, 104 }, }, - { { 102, 0 }, - { 12, 192 }, - { 0, 102 }, - { 3, 48 }, }, - { { 108, 94 }, - { 41, 245 }, - { 122, 54 }, - { 175, 148 }, }, - { { 118, 175 }, - { 159, 211 }, - { 245, 110 }, - { 203, 249 }, }, - { { 134, 139 }, - { 21, 75 }, - { 209, 97 }, - { 210, 168 }, }, - { { 176, 43 }, - { 155, 9 }, - { 212, 13 }, - { 144, 217 }, }, - { { 204, 213 }, - { 48, 254 }, - { 171, 51 }, - { 127, 12 }, }, - { { 221, 130 }, - { 193, 206 }, - { 65, 187 }, - { 115, 131 }, }, - { { 254, 71 }, - { 157, 252 }, - { 226, 127 }, - { 63, 185 }, }, - { { 148, 113 }, - { 178, 104 }, - { 142, 41 }, - { 22, 77 }, }, - { { 172, 228 }, - { 10, 126 }, - { 39, 53 }, - { 126, 80 }, }, - { { 165, 84 }, - { 104, 120 }, - { 42, 165 }, - { 30, 22 }, }, - { { 33, 35 }, - { 91, 0 }, - { 196, 132 }, - { 0, 218 }, }, - { { 52, 111 }, - { 155, 113 }, - { 246, 44 }, - { 142, 217 }, }, - { { 68, 21 }, - { 48, 208 }, - { 168, 34 }, - { 11, 12 }, }, - { { 87, 178 }, - { 231, 194 }, - { 77, 234 }, - { 67, 231 }, }, - { { 158, 207 }, - { 149, 127 }, - { 243, 121 }, - { 254, 169 }, }, - { { 240, 203 }, - { 153, 171 }, - { 211, 15 }, - { 213, 153 }, }, - { { 8, 174 }, - { 3, 23 }, - { 117, 16 }, - { 232, 192 }, }, - { { 9, 41 }, - { 82, 5 }, - { 148, 144 }, - { 160, 74 }, }, - { { 24, 117 }, - { 178, 52 }, - { 174, 24 }, - { 44, 77 }, }, - { { 4, 255 }, - { 51, 115 }, - { 255, 32 }, - { 206, 204 }, }, - { { 13, 246 }, - { 99, 118 }, - { 111, 176 }, - { 110, 198 }, }, - { { 28, 90 }, - { 161, 101 }, - { 90, 56 }, - { 166, 133 }, }, - { { 23, 24 }, - { 228, 65 }, - { 24, 232 }, - { 130, 39 }, }, - { { 42, 40 }, - { 14, 5 }, - { 20, 84 }, - { 160, 112 }, }, - { { 50, 140 }, - { 140, 19 }, - { 49, 76 }, - { 200, 49 }, }, - { { 56, 178 }, - { 171, 6 }, - { 77, 28 }, - { 96, 213 }, }, - { { 36, 232 }, - { 10, 99 }, - { 23, 36 }, - { 198, 80 }, }, - { { 46, 235 }, - { 31, 103 }, - { 215, 116 }, - { 230, 248 }, }, - { { 45, 63 }, - { 123, 85 }, - { 252, 180 }, - { 170, 222 }, }, - { { 75, 100 }, - { 70, 180 }, - { 38, 210 }, - { 45, 98 }, }, - { { 80, 46 }, - { 131, 145 }, - { 116, 10 }, - { 137, 193 }, }, - { { 80, 19 }, - { 177, 128 }, - { 200, 10 }, - { 1, 141 }, }, - { { 81, 148 }, - { 224, 146 }, - { 41, 138 }, - { 73, 7 }, }, - { { 85, 104 }, - { 194, 225 }, - { 22, 170 }, - { 135, 67 }, }, - { { 93, 65 }, - { 208, 228 }, - { 130, 186 }, - { 39, 11 }, }, - { { 95, 151 }, - { 245, 214 }, - { 233, 250 }, - { 107, 175 }, }, - { { 104, 1 }, - { 24, 132 }, - { 128, 22 }, - { 33, 24 }, }, - { { 104, 103 }, - { 27, 180 }, - { 230, 22 }, - { 45, 216 }, }, - { { 97, 36 }, - { 74, 144 }, - { 36, 134 }, - { 9, 82 }, }, - { { 97, 233 }, - { 90, 163 }, - { 151, 134 }, - { 197, 90 }, }, - { { 107, 18 }, - { 109, 132 }, - { 72, 214 }, - { 33, 182 }, }, - { { 111, 229 }, - { 94, 246 }, - { 167, 246 }, - { 111, 122 }, }, - { { 103, 223 }, - { 125, 243 }, - { 251, 230 }, - { 207, 190 }, }, - { { 126, 27 }, - { 189, 197 }, - { 216, 126 }, - { 163, 189 }, }, - { { 128, 160 }, - { 2, 10 }, - { 5, 1 }, - { 80, 64 }, }, - { { 131, 68 }, - { 68, 56 }, - { 34, 193 }, - { 28, 34 }, }, - { { 139, 162 }, - { 71, 14 }, - { 69, 209 }, - { 112, 226 }, }, - { { 147, 122 }, - { 231, 41 }, - { 94, 201 }, - { 148, 231 }, }, - { { 132, 108 }, - { 2, 121 }, - { 54, 33 }, - { 158, 64 }, }, - { { 133, 42 }, - { 67, 73 }, - { 84, 161 }, - { 146, 194 }, }, - { { 133, 156 }, - { 96, 91 }, - { 57, 161 }, - { 218, 6 }, }, - { { 156, 137 }, - { 144, 79 }, - { 145, 57 }, - { 242, 9 }, }, - { { 159, 161 }, - { 214, 78 }, - { 133, 249 }, - { 114, 107 }, }, - { { 187, 124 }, - { 238, 61 }, - { 62, 221 }, - { 188, 119 }, }, - { { 188, 4 }, - { 136, 92 }, - { 32, 61 }, - { 58, 17 }, }, - { { 182, 91 }, - { 189, 105 }, - { 218, 109 }, - { 150, 189 }, }, - { { 191, 200 }, - { 204, 111 }, - { 19, 253 }, - { 246, 51 }, }, - { { 183, 171 }, - { 223, 75 }, - { 213, 237 }, - { 210, 251 }, }, - { { 202, 31 }, - { 53, 157 }, - { 248, 83 }, - { 185, 172 }, }, - { { 201, 98 }, - { 67, 172 }, - { 70, 147 }, - { 53, 194 }, }, - { { 217, 88 }, - { 224, 173 }, - { 26, 155 }, - { 181, 7 }, }, - { { 211, 213 }, - { 244, 186 }, - { 171, 203 }, - { 93, 47 }, }, - { { 204, 152 }, - { 32, 207 }, - { 25, 51 }, - { 243, 4 }, }, - { { 199, 160 }, - { 70, 202 }, - { 5, 227 }, - { 83, 98 }, }, - { { 197, 55 }, - { 115, 216 }, - { 236, 163 }, - { 27, 206 }, }, - { { 233, 93 }, - { 120, 189 }, - { 186, 151 }, - { 189, 30 }, }, - { { 249, 37 }, - { 218, 156 }, - { 164, 159 }, - { 57, 91 }, }, - { { 251, 187 }, - { 255, 143 }, - { 221, 223 }, - { 241, 255 }, }, - { { 238, 42 }, - { 15, 205 }, - { 84, 119 }, - { 179, 240 }, }, - { { 247, 77 }, - { 220, 249 }, - { 178, 239 }, - { 159, 59 }, }, - { { 53, 117 }, - { 250, 112 }, - { 174, 172 }, - { 14, 95 }, }, - { { 138, 173 }, - { 22, 31 }, - { 181, 81 }, - { 248, 104 }, }, - { { 118, 23 }, - { 189, 208 }, - { 232, 110 }, - { 11, 189 }, }, - { { 10, 207 }, - { 21, 55 }, - { 243, 80 }, - { 236, 168 }, }, - { { 6, 75 }, - { 21, 97 }, - { 210, 96 }, - { 134, 168 }, }, - { { 45, 193 }, - { 88, 102 }, - { 131, 180 }, - { 102, 26 }, }, - { { 73, 216 }, - { 96, 167 }, - { 27, 146 }, - { 229, 6 }, }, - { { 67, 244 }, - { 102, 178 }, - { 47, 194 }, - { 77, 102 }, }, - { { 79, 54 }, - { 103, 212 }, - { 108, 242 }, - { 43, 230 }, }, - { { 79, 211 }, - { 117, 230 }, - { 203, 242 }, - { 103, 174 }, }, - { { 105, 228 }, - { 74, 182 }, - { 39, 150 }, - { 109, 82 }, }, - { { 112, 199 }, - { 153, 178 }, - { 227, 14 }, - { 77, 153 }, }, - { { 122, 110 }, - { 143, 181 }, - { 118, 94 }, - { 173, 241 }, }, - { { 180, 234 }, - { 139, 107 }, - { 87, 45 }, - { 214, 209 }, }, - { { 237, 79 }, - { 89, 253 }, - { 242, 183 }, - { 191, 154 }, }, - { { 252, 231 }, - { 155, 254 }, - { 231, 63 }, - { 127, 217 }, }, - { { 254, 166 }, - { 143, 222 }, - { 101, 127 }, - { 123, 241 }, }, - { { 0, 37 }, - { 18, 16 }, - { 164, 0 }, - { 8, 72 }, }, - { { 0, 67 }, - { 17, 32 }, - { 194, 0 }, - { 4, 136 }, }, - { { 10, 136 }, - { 4, 7 }, - { 17, 80 }, - { 224, 32 }, }, - { { 10, 134 }, - { 5, 22 }, - { 97, 80 }, - { 104, 160 }, }, - { { 2, 111 }, - { 23, 49 }, - { 246, 64 }, - { 140, 232 }, }, - { { 0, 28 }, - { 32, 17 }, - { 56, 0 }, - { 136, 4 }, }, - { { 0, 151 }, - { 49, 18 }, - { 233, 0 }, - { 72, 140 }, }, - { { 8, 55 }, - { 51, 20 }, - { 236, 16 }, - { 40, 204 }, }, - { { 10, 49 }, - { 54, 4 }, - { 140, 80 }, - { 32, 108 }, }, - { { 9, 198 }, - { 65, 54 }, - { 99, 144 }, - { 108, 130 }, }, - { { 11, 1 }, - { 84, 4 }, - { 128, 208 }, - { 32, 42 }, }, - { { 9, 251 }, - { 115, 39 }, - { 223, 144 }, - { 228, 206 }, }, - { { 11, 88 }, - { 100, 37 }, - { 26, 208 }, - { 164, 38 }, }, - { { 16, 130 }, - { 129, 2 }, - { 65, 8 }, - { 64, 129 }, }, - { { 24, 45 }, - { 146, 21 }, - { 180, 24 }, - { 168, 73 }, }, - { { 16, 120 }, - { 162, 33 }, - { 30, 8 }, - { 132, 69 }, }, - { { 16, 115 }, - { 179, 32 }, - { 206, 8 }, - { 4, 205 }, }, - { { 18, 116 }, - { 166, 48 }, - { 46, 72 }, - { 12, 101 }, }, - { { 18, 177 }, - { 182, 2 }, - { 141, 72 }, - { 64, 109 }, }, - { { 26, 249 }, - { 182, 39 }, - { 159, 88 }, - { 228, 109 }, }, - { { 19, 6 }, - { 197, 16 }, - { 96, 200 }, - { 8, 163 }, }, - { { 12, 14 }, - { 1, 85 }, - { 112, 48 }, - { 170, 128 }, }, - { { 12, 241 }, - { 50, 102 }, - { 143, 48 }, - { 102, 76 }, }, - { { 4, 51 }, - { 51, 64 }, - { 204, 32 }, - { 2, 204 }, }, - { { 12, 159 }, - { 49, 87 }, - { 249, 48 }, - { 234, 140 }, }, - { { 14, 242 }, - { 39, 102 }, - { 79, 112 }, - { 102, 228 }, }, - { { 14, 253 }, - { 54, 119 }, - { 191, 112 }, - { 238, 108 }, }, - { { 7, 76 }, - { 68, 113 }, - { 50, 224 }, - { 142, 34 }, }, - { { 15, 164 }, - { 70, 86 }, - { 37, 240 }, - { 106, 98 }, }, - { { 7, 47 }, - { 87, 81 }, - { 244, 224 }, - { 138, 234 }, }, - { { 5, 181 }, - { 114, 82 }, - { 173, 160 }, - { 74, 78 }, }, - { { 15, 145 }, - { 116, 70 }, - { 137, 240 }, - { 98, 46 }, }, - { { 7, 219 }, - { 117, 99 }, - { 219, 224 }, - { 198, 174 }, }, - { { 30, 228 }, - { 134, 118 }, - { 39, 120 }, - { 110, 97 }, }, - { { 20, 57 }, - { 178, 65 }, - { 156, 40 }, - { 130, 77 }, }, - { { 29, 128 }, - { 192, 70 }, - { 1, 184 }, - { 98, 3 }, }, - { { 21, 200 }, - { 192, 99 }, - { 19, 168 }, - { 198, 3 }, }, - { { 31, 139 }, - { 213, 71 }, - { 209, 248 }, - { 226, 171 }, }, - { { 21, 186 }, - { 227, 67 }, - { 93, 168 }, - { 194, 199 }, }, - { { 29, 177 }, - { 242, 70 }, - { 141, 184 }, - { 98, 79 }, }, - { { 32, 128 }, - { 8, 2 }, - { 1, 4 }, - { 64, 16 }, }, - { { 40, 233 }, - { 26, 39 }, - { 151, 20 }, - { 228, 88 }, }, - { { 34, 162 }, - { 15, 2 }, - { 69, 68 }, - { 64, 240 }, }, - { { 40, 83 }, - { 57, 36 }, - { 202, 20 }, - { 36, 156 }, }, - { { 42, 240 }, - { 46, 38 }, - { 15, 84 }, - { 100, 116 }, }, - { { 34, 247 }, - { 63, 50 }, - { 239, 68 }, - { 76, 252 }, }, - { { 41, 64 }, - { 72, 36 }, - { 2, 148 }, - { 36, 18 }, }, - { { 33, 70 }, - { 73, 48 }, - { 98, 132 }, - { 12, 146 }, }, - { { 41, 185 }, - { 122, 7 }, - { 157, 148 }, - { 224, 94 }, }, - { { 43, 156 }, - { 108, 23 }, - { 57, 212 }, - { 232, 54 }, }, - { { 43, 178 }, - { 111, 6 }, - { 77, 212 }, - { 96, 246 }, }, - { { 56, 202 }, - { 137, 39 }, - { 83, 28 }, - { 228, 145 }, }, - { { 56, 46 }, - { 139, 21 }, - { 116, 28 }, - { 168, 209 }, }, - { { 48, 7 }, - { 153, 16 }, - { 224, 12 }, - { 8, 153 }, }, - { { 56, 231 }, - { 155, 54 }, - { 231, 28 }, - { 108, 217 }, }, - { { 58, 73 }, - { 156, 37 }, - { 146, 92 }, - { 164, 57 }, }, - { { 58, 101 }, - { 158, 52 }, - { 166, 92 }, - { 44, 121 }, }, - { { 50, 93 }, - { 188, 49 }, - { 186, 76 }, - { 140, 61 }, }, - { { 59, 136 }, - { 204, 7 }, - { 17, 220 }, - { 224, 51 }, }, - { { 57, 29 }, - { 248, 21 }, - { 184, 156 }, - { 168, 31 }, }, - { { 59, 211 }, - { 253, 38 }, - { 203, 220 }, - { 100, 191 }, }, - { { 38, 71 }, - { 29, 112 }, - { 226, 100 }, - { 14, 184 }, }, - { { 39, 128 }, - { 76, 66 }, - { 1, 228 }, - { 66, 50 }, }, - { { 47, 170 }, - { 79, 71 }, - { 85, 244 }, - { 226, 242 }, }, - { { 45, 20 }, - { 104, 84 }, - { 40, 180 }, - { 42, 22 }, }, - { { 37, 222 }, - { 105, 115 }, - { 123, 164 }, - { 206, 150 }, }, - { { 37, 83 }, - { 121, 96 }, - { 202, 164 }, - { 6, 158 }, }, - { { 47, 119 }, - { 127, 116 }, - { 238, 244 }, - { 46, 254 }, }, - { { 52, 72 }, - { 136, 97 }, - { 18, 44 }, - { 134, 17 }, }, - { { 60, 168 }, - { 138, 71 }, - { 21, 60 }, - { 226, 81 }, }, - { { 60, 65 }, - { 152, 100 }, - { 130, 60 }, - { 38, 25 }, }, - { { 52, 13 }, - { 152, 81 }, - { 176, 44 }, - { 138, 25 }, }, - { { 52, 251 }, - { 187, 99 }, - { 223, 44 }, - { 198, 221 }, }, - { { 54, 154 }, - { 173, 67 }, - { 89, 108 }, - { 194, 181 }, }, - { { 61, 224 }, - { 202, 102 }, - { 7, 188 }, - { 102, 83 }, }, - { { 53, 106 }, - { 203, 97 }, - { 86, 172 }, - { 134, 211 }, }, - { { 61, 9 }, - { 216, 69 }, - { 144, 188 }, - { 162, 27 }, }, - { { 61, 237 }, - { 218, 119 }, - { 183, 188 }, - { 238, 91 }, }, - { { 63, 196 }, - { 204, 118 }, - { 35, 252 }, - { 110, 51 }, }, - { { 63, 108 }, - { 206, 117 }, - { 54, 252 }, - { 174, 115 }, }, - { { 55, 206 }, - { 205, 115 }, - { 115, 236 }, - { 206, 179 }, }, - { { 61, 92 }, - { 232, 117 }, - { 58, 188 }, - { 174, 23 }, }, - { { 61, 118 }, - { 235, 116 }, - { 110, 188 }, - { 46, 215 }, }, - { { 55, 176 }, - { 238, 66 }, - { 13, 236 }, - { 66, 119 }, }, - { { 63, 23 }, - { 253, 84 }, - { 232, 252 }, - { 42, 191 }, }, - { { 63, 255 }, - { 255, 119 }, - { 255, 252 }, - { 238, 255 }, }, - { { 72, 229 }, - { 18, 182 }, - { 167, 18 }, - { 109, 72 }, }, - { { 66, 104 }, - { 6, 161 }, - { 22, 66 }, - { 133, 96 }, }, - { { 74, 45 }, - { 22, 149 }, - { 180, 82 }, - { 169, 104 }, }, - { { 65, 96 }, - { 66, 160 }, - { 6, 130 }, - { 5, 66 }, }, - { { 73, 81 }, - { 112, 164 }, - { 138, 146 }, - { 37, 14 }, }, - { { 65, 221 }, - { 112, 179 }, - { 187, 130 }, - { 205, 14 }, }, - { { 75, 223 }, - { 117, 183 }, - { 251, 210 }, - { 237, 174 }, }, - { { 88, 79 }, - { 145, 181 }, - { 242, 26 }, - { 173, 137 }, }, - { { 90, 72 }, - { 132, 165 }, - { 18, 90 }, - { 165, 33 }, }, - { { 88, 22 }, - { 161, 148 }, - { 104, 26 }, - { 41, 133 }, }, - { { 80, 93 }, - { 176, 177 }, - { 186, 10 }, - { 141, 13 }, }, - { { 90, 250 }, - { 167, 167 }, - { 95, 90 }, - { 229, 229 }, }, - { { 90, 181 }, - { 182, 150 }, - { 173, 90 }, - { 105, 109 }, }, - { { 81, 35 }, - { 211, 128 }, - { 196, 138 }, - { 1, 203 }, }, - { { 91, 138 }, - { 197, 135 }, - { 81, 218 }, - { 225, 163 }, }, - { { 89, 25 }, - { 240, 133 }, - { 152, 154 }, - { 161, 15 }, }, - { { 81, 53 }, - { 242, 144 }, - { 172, 138 }, - { 9, 79 }, }, - { { 76, 105 }, - { 18, 229 }, - { 150, 50 }, - { 167, 72 }, }, - { { 70, 193 }, - { 20, 226 }, - { 131, 98 }, - { 71, 40 }, }, - { { 78, 11 }, - { 21, 197 }, - { 208, 114 }, - { 163, 168 }, }, - { { 68, 95 }, - { 49, 241 }, - { 250, 34 }, - { 143, 140 }, }, - { { 78, 89 }, - { 52, 229 }, - { 154, 114 }, - { 167, 44 }, }, - { { 77, 131 }, - { 81, 198 }, - { 193, 178 }, - { 99, 138 }, }, - { { 77, 125 }, - { 114, 245 }, - { 190, 178 }, - { 175, 78 }, }, - { { 71, 216 }, - { 100, 227 }, - { 27, 226 }, - { 199, 38 }, }, - { { 71, 115 }, - { 119, 224 }, - { 206, 226 }, - { 7, 238 }, }, - { { 92, 133 }, - { 144, 214 }, - { 161, 58 }, - { 107, 9 }, }, - { { 94, 68 }, - { 132, 244 }, - { 34, 122 }, - { 47, 33 }, }, - { { 86, 43 }, - { 151, 193 }, - { 212, 106 }, - { 131, 233 }, }, - { { 92, 187 }, - { 179, 199 }, - { 221, 58 }, - { 227, 205 }, }, - { { 85, 195 }, - { 209, 226 }, - { 195, 170 }, - { 71, 139 }, }, - { { 95, 110 }, - { 199, 245 }, - { 118, 250 }, - { 175, 227 }, }, - { { 95, 235 }, - { 215, 231 }, - { 215, 250 }, - { 231, 235 }, }, - { { 93, 18 }, - { 225, 196 }, - { 72, 186 }, - { 35, 135 }, }, - { { 85, 94 }, - { 225, 241 }, - { 122, 170 }, - { 143, 135 }, }, - { { 98, 112 }, - { 46, 160 }, - { 14, 70 }, - { 5, 116 }, }, - { { 98, 21 }, - { 60, 144 }, - { 168, 70 }, - { 9, 60 }, }, - { { 97, 194 }, - { 73, 162 }, - { 67, 134 }, - { 69, 146 }, }, - { { 107, 32 }, - { 78, 132 }, - { 4, 214 }, - { 33, 114 }, }, - { { 99, 69 }, - { 92, 176 }, - { 162, 198 }, - { 13, 58 }, }, - { { 107, 92 }, - { 108, 181 }, - { 58, 214 }, - { 173, 54 }, }, - { { 107, 91 }, - { 125, 165 }, - { 218, 214 }, - { 165, 190 }, }, - { { 120, 12 }, - { 136, 149 }, - { 48, 30 }, - { 169, 17 }, }, - { { 122, 207 }, - { 157, 183 }, - { 243, 94 }, - { 237, 185 }, }, - { { 120, 127 }, - { 187, 181 }, - { 254, 30 }, - { 173, 221 }, }, - { { 121, 128 }, - { 200, 134 }, - { 1, 158 }, - { 97, 19 }, }, - { { 113, 229 }, - { 218, 178 }, - { 167, 142 }, - { 77, 91 }, }, - { { 113, 116 }, - { 234, 176 }, - { 46, 142 }, - { 13, 87 }, }, - { { 121, 182 }, - { 235, 150 }, - { 109, 158 }, - { 105, 215 }, }, - { { 113, 211 }, - { 249, 162 }, - { 203, 142 }, - { 69, 159 }, }, - { { 123, 51 }, - { 255, 132 }, - { 204, 222 }, - { 33, 255 }, }, - { { 100, 106 }, - { 11, 225 }, - { 86, 38 }, - { 135, 208 }, }, - { { 102, 168 }, - { 14, 195 }, - { 21, 102 }, - { 195, 112 }, }, - { { 110, 167 }, - { 31, 214 }, - { 229, 118 }, - { 107, 248 }, }, - { { 110, 145 }, - { 60, 198 }, - { 137, 118 }, - { 99, 60 }, }, - { { 101, 34 }, - { 75, 192 }, - { 68, 166 }, - { 3, 210 }, }, - { { 109, 203 }, - { 89, 231 }, - { 211, 182 }, - { 231, 154 }, }, - { { 103, 141 }, - { 92, 211 }, - { 177, 230 }, - { 203, 58 }, }, - { { 109, 49 }, - { 122, 196 }, - { 140, 182 }, - { 35, 94 }, }, - { { 126, 128 }, - { 140, 198 }, - { 1, 126 }, - { 99, 49 }, }, - { { 126, 226 }, - { 143, 230 }, - { 71, 126 }, - { 103, 241 }, }, - { { 126, 141 }, - { 156, 215 }, - { 177, 126 }, - { 235, 57 }, }, - { { 116, 210 }, - { 169, 226 }, - { 75, 46 }, - { 71, 149 }, }, - { { 124, 50 }, - { 171, 196 }, - { 76, 62 }, - { 35, 213 }, }, - { { 126, 53 }, - { 190, 212 }, - { 172, 126 }, - { 43, 125 }, }, - { { 117, 171 }, - { 219, 195 }, - { 213, 174 }, - { 195, 219 }, }, - { { 119, 5 }, - { 220, 208 }, - { 160, 238 }, - { 11, 59 }, }, - { { 127, 43 }, - { 223, 197 }, - { 212, 254 }, - { 163, 251 }, }, - { { 125, 218 }, - { 233, 231 }, - { 91, 190 }, - { 231, 151 }, }, - { { 127, 146 }, - { 237, 198 }, - { 73, 254 }, - { 99, 183 }, }, - { { 128, 117 }, - { 50, 56 }, - { 174, 1 }, - { 28, 76 }, }, - { { 128, 243 }, - { 51, 42 }, - { 207, 1 }, - { 84, 204 }, }, - { { 129, 166 }, - { 67, 26 }, - { 101, 129 }, - { 88, 194 }, }, - { { 137, 237 }, - { 82, 63 }, - { 183, 145 }, - { 252, 74 }, }, - { { 129, 252 }, - { 98, 59 }, - { 63, 129 }, - { 220, 70 }, }, - { { 152, 166 }, - { 131, 30 }, - { 101, 25 }, - { 120, 193 }, }, - { { 154, 32 }, - { 134, 12 }, - { 4, 89 }, - { 48, 97 }, }, - { { 145, 67 }, - { 209, 40 }, - { 194, 137 }, - { 20, 139 }, }, - { { 153, 249 }, - { 242, 47 }, - { 159, 153 }, - { 244, 79 }, }, - { { 145, 147 }, - { 241, 10 }, - { 201, 137 }, - { 80, 143 }, }, - { { 155, 212 }, - { 228, 62 }, - { 43, 217 }, - { 124, 39 }, }, - { { 132, 9 }, - { 16, 73 }, - { 144, 33 }, - { 146, 8 }, }, - { { 132, 107 }, - { 19, 105 }, - { 214, 33 }, - { 150, 200 }, }, - { { 134, 196 }, - { 4, 122 }, - { 35, 97 }, - { 94, 32 }, }, - { { 142, 100 }, - { 6, 124 }, - { 38, 113 }, - { 62, 96 }, }, - { { 134, 26 }, - { 37, 73 }, - { 88, 97 }, - { 146, 164 }, }, - { { 133, 78 }, - { 65, 121 }, - { 114, 161 }, - { 158, 130 }, }, - { { 141, 203 }, - { 81, 111 }, - { 211, 177 }, - { 246, 138 }, }, - { { 133, 103 }, - { 83, 120 }, - { 230, 161 }, - { 30, 202 }, }, - { { 133, 175 }, - { 83, 91 }, - { 245, 161 }, - { 218, 202 }, }, - { { 133, 215 }, - { 113, 122 }, - { 235, 161 }, - { 94, 142 }, }, - { { 135, 179 }, - { 119, 74 }, - { 205, 225 }, - { 82, 238 }, }, - { { 156, 225 }, - { 146, 110 }, - { 135, 57 }, - { 118, 73 }, }, - { { 156, 242 }, - { 163, 110 }, - { 79, 57 }, - { 118, 197 }, }, - { { 148, 23 }, - { 177, 88 }, - { 232, 41 }, - { 26, 141 }, }, - { { 149, 0 }, - { 192, 72 }, - { 0, 169 }, - { 18, 3 }, }, - { { 149, 162 }, - { 195, 74 }, - { 69, 169 }, - { 82, 195 }, }, - { { 157, 35 }, - { 211, 76 }, - { 196, 185 }, - { 50, 203 }, }, - { { 159, 98 }, - { 199, 108 }, - { 70, 249 }, - { 54, 227 }, }, - { { 157, 82 }, - { 225, 108 }, - { 74, 185 }, - { 54, 135 }, }, - { { 149, 218 }, - { 225, 107 }, - { 91, 169 }, - { 214, 135 }, }, - { { 160, 197 }, - { 24, 58 }, - { 163, 5 }, - { 92, 24 }, }, - { { 170, 205 }, - { 28, 63 }, - { 179, 85 }, - { 252, 56 }, }, - { { 162, 216 }, - { 44, 43 }, - { 27, 69 }, - { 212, 52 }, }, - { { 162, 87 }, - { 61, 56 }, - { 234, 69 }, - { 28, 188 }, }, - { { 169, 61 }, - { 122, 29 }, - { 188, 149 }, - { 184, 94 }, }, - { { 169, 87 }, - { 121, 60 }, - { 234, 149 }, - { 60, 158 }, }, - { { 171, 82 }, - { 109, 44 }, - { 74, 213 }, - { 52, 182 }, }, - { { 163, 54 }, - { 111, 24 }, - { 108, 197 }, - { 24, 246 }, }, - { { 163, 89 }, - { 124, 41 }, - { 154, 197 }, - { 148, 62 }, }, - { { 176, 244 }, - { 170, 58 }, - { 47, 13 }, - { 92, 85 }, }, - { { 184, 18 }, - { 169, 12 }, - { 72, 29 }, - { 48, 149 }, }, - { { 176, 191 }, - { 187, 27 }, - { 253, 13 }, - { 216, 221 }, }, - { { 178, 157 }, - { 188, 27 }, - { 185, 77 }, - { 216, 61 }, }, - { { 187, 237 }, - { 222, 63 }, - { 183, 221 }, - { 252, 123 }, }, - { { 185, 114 }, - { 235, 44 }, - { 78, 157 }, - { 52, 215 }, }, - { { 185, 150 }, - { 233, 30 }, - { 105, 157 }, - { 120, 151 }, }, - { { 164, 195 }, - { 25, 106 }, - { 195, 37 }, - { 86, 152 }, }, - { { 172, 210 }, - { 41, 110 }, - { 75, 53 }, - { 118, 148 }, }, - { { 174, 177 }, - { 62, 78 }, - { 141, 117 }, - { 114, 124 }, }, - { { 165, 130 }, - { 73, 74 }, - { 65, 165 }, - { 82, 146 }, }, - { { 175, 101 }, - { 94, 124 }, - { 166, 245 }, - { 62, 122 }, }, - { { 165, 123 }, - { 123, 105 }, - { 222, 165 }, - { 150, 222 }, }, - { { 175, 250 }, - { 111, 111 }, - { 95, 245 }, - { 246, 246 }, }, - { { 180, 100 }, - { 138, 120 }, - { 38, 45 }, - { 30, 81 }, }, - { { 188, 98 }, - { 139, 108 }, - { 70, 61 }, - { 54, 209 }, }, - { { 180, 129 }, - { 152, 74 }, - { 129, 45 }, - { 82, 25 }, }, - { { 182, 160 }, - { 142, 74 }, - { 5, 109 }, - { 82, 113 }, }, - { { 190, 238 }, - { 143, 127 }, - { 119, 125 }, - { 254, 241 }, }, - { { 190, 13 }, - { 156, 93 }, - { 176, 125 }, - { 186, 57 }, }, - { { 188, 217 }, - { 184, 111 }, - { 155, 61 }, - { 246, 29 }, }, - { { 190, 248 }, - { 174, 111 }, - { 31, 125 }, - { 246, 117 }, }, - { { 181, 40 }, - { 202, 73 }, - { 20, 173 }, - { 146, 83 }, }, - { { 183, 9 }, - { 220, 73 }, - { 144, 237 }, - { 146, 59 }, }, - { { 183, 210 }, - { 237, 106 }, - { 75, 237 }, - { 86, 183 }, }, - { { 192, 234 }, - { 3, 171 }, - { 87, 3 }, - { 213, 192 }, }, - { { 192, 25 }, - { 48, 137 }, - { 152, 3 }, - { 145, 12 }, }, - { { 192, 253 }, - { 50, 187 }, - { 191, 3 }, - { 221, 76 }, }, - { { 200, 211 }, - { 49, 174 }, - { 203, 19 }, - { 117, 140 }, }, - { { 202, 90 }, - { 37, 173 }, - { 90, 83 }, - { 181, 164 }, }, - { { 193, 77 }, - { 80, 185 }, - { 178, 131 }, - { 157, 10 }, }, - { { 201, 180 }, - { 98, 158 }, - { 45, 147 }, - { 121, 70 }, }, - { { 193, 87 }, - { 113, 184 }, - { 234, 131 }, - { 29, 142 }, }, - { { 195, 152 }, - { 100, 139 }, - { 25, 195 }, - { 209, 38 }, }, - { { 195, 29 }, - { 116, 153 }, - { 184, 195 }, - { 153, 46 }, }, - { { 216, 128 }, - { 128, 142 }, - { 1, 27 }, - { 113, 1 }, }, - { { 216, 239 }, - { 147, 191 }, - { 247, 27 }, - { 253, 201 }, }, - { { 218, 43 }, - { 151, 141 }, - { 212, 91 }, - { 177, 233 }, }, - { { 208, 30 }, - { 161, 153 }, - { 120, 11 }, - { 153, 133 }, }, - { { 209, 5 }, - { 208, 152 }, - { 160, 139 }, - { 25, 11 }, }, - { { 211, 173 }, - { 214, 155 }, - { 181, 203 }, - { 217, 107 }, }, - { { 219, 167 }, - { 215, 158 }, - { 229, 219 }, - { 121, 235 }, }, - { { 196, 201 }, - { 16, 235 }, - { 147, 35 }, - { 215, 8 }, }, - { { 204, 120 }, - { 34, 237 }, - { 30, 51 }, - { 183, 68 }, }, - { { 205, 69 }, - { 80, 252 }, - { 162, 179 }, - { 63, 10 }, }, - { { 197, 11 }, - { 81, 201 }, - { 208, 163 }, - { 147, 138 }, }, - { { 207, 207 }, - { 85, 255 }, - { 243, 243 }, - { 255, 170 }, }, - { { 220, 172 }, - { 130, 223 }, - { 53, 59 }, - { 251, 65 }, }, - { { 212, 2 }, - { 129, 200 }, - { 64, 43 }, - { 19, 129 }, }, - { { 220, 99 }, - { 147, 236 }, - { 198, 59 }, - { 55, 201 }, }, - { { 212, 39 }, - { 147, 216 }, - { 228, 43 }, - { 27, 201 }, }, - { { 212, 245 }, - { 178, 250 }, - { 175, 43 }, - { 95, 77 }, }, - { { 214, 120 }, - { 166, 233 }, - { 30, 107 }, - { 151, 101 }, }, - { { 222, 184 }, - { 166, 207 }, - { 29, 123 }, - { 243, 101 }, }, - { { 221, 230 }, - { 195, 254 }, - { 103, 187 }, - { 127, 195 }, }, - { { 213, 93 }, - { 240, 249 }, - { 186, 171 }, - { 159, 15 }, }, - { { 221, 189 }, - { 242, 223 }, - { 189, 187 }, - { 251, 79 }, }, - { { 223, 29 }, - { 244, 221 }, - { 184, 251 }, - { 187, 47 }, }, - { { 226, 202 }, - { 13, 171 }, - { 83, 71 }, - { 213, 176 }, }, - { { 234, 107 }, - { 31, 173 }, - { 214, 87 }, - { 181, 248 }, }, - { { 224, 180 }, - { 42, 154 }, - { 45, 7 }, - { 89, 84 }, }, - { { 226, 56 }, - { 46, 137 }, - { 28, 71 }, - { 145, 116 }, }, - { { 226, 212 }, - { 44, 186 }, - { 43, 71 }, - { 93, 52 }, }, - { { 227, 34 }, - { 79, 136 }, - { 68, 199 }, - { 17, 242 }, }, - { { 225, 216 }, - { 104, 171 }, - { 27, 135 }, - { 213, 22 }, }, - { { 240, 3 }, - { 153, 136 }, - { 192, 15 }, - { 17, 153 }, }, - { { 242, 204 }, - { 140, 187 }, - { 51, 79 }, - { 221, 49 }, }, - { { 248, 246 }, - { 171, 190 }, - { 111, 31 }, - { 125, 213 }, }, - { { 241, 73 }, - { 216, 169 }, - { 146, 143 }, - { 149, 27 }, }, - { { 243, 234 }, - { 207, 171 }, - { 87, 207 }, - { 213, 243 }, }, - { { 241, 156 }, - { 232, 155 }, - { 57, 143 }, - { 217, 23 }, }, - { { 249, 245 }, - { 250, 190 }, - { 175, 159 }, - { 125, 95 }, }, - { { 241, 59 }, - { 251, 137 }, - { 220, 143 }, - { 145, 223 }, }, - { { 236, 141 }, - { 24, 223 }, - { 177, 55 }, - { 251, 24 }, }, - { { 238, 201 }, - { 28, 239 }, - { 147, 119 }, - { 247, 56 }, }, - { { 230, 15 }, - { 29, 217 }, - { 240, 103 }, - { 155, 184 }, }, - { { 228, 247 }, - { 59, 250 }, - { 239, 39 }, - { 95, 220 }, }, - { { 231, 96 }, - { 78, 232 }, - { 6, 231 }, - { 23, 114 }, }, - { { 239, 232 }, - { 78, 239 }, - { 23, 247 }, - { 247, 114 }, }, - { { 237, 178 }, - { 107, 206 }, - { 77, 183 }, - { 115, 214 }, }, - { { 229, 21 }, - { 120, 216 }, - { 168, 167 }, - { 27, 30 }, }, - { { 239, 209 }, - { 124, 238 }, - { 139, 247 }, - { 119, 62 }, }, - { { 244, 134 }, - { 137, 218 }, - { 97, 47 }, - { 91, 145 }, }, - { { 252, 1 }, - { 152, 204 }, - { 128, 63 }, - { 51, 25 }, }, - { { 246, 195 }, - { 157, 234 }, - { 195, 111 }, - { 87, 185 }, }, - { { 244, 124 }, - { 170, 249 }, - { 62, 47 }, - { 159, 85 }, }, - { { 252, 147 }, - { 185, 206 }, - { 201, 63 }, - { 115, 157 }, }, - { { 245, 66 }, - { 201, 232 }, - { 66, 175 }, - { 23, 147 }, }, - { { 253, 152 }, - { 232, 207 }, - { 25, 191 }, - { 243, 23 }, }, - { { 245, 61 }, - { 250, 217 }, - { 188, 175 }, - { 155, 95 }, }, - { { 2, 189 }, - { 54, 19 }, - { 189, 64 }, - { 200, 108 }, }, - { { 0, 225 }, - { 18, 34 }, - { 135, 0 }, - { 68, 72 }, }, - { { 2, 226 }, - { 7, 34 }, - { 71, 64 }, - { 68, 224 }, }, - { { 2, 174 }, - { 7, 19 }, - { 117, 64 }, - { 200, 224 }, }, - { { 8, 120 }, - { 34, 37 }, - { 30, 16 }, - { 164, 68 }, }, - { { 0, 116 }, - { 34, 48 }, - { 46, 0 }, - { 12, 68 }, }, - { { 8, 158 }, - { 33, 23 }, - { 121, 16 }, - { 232, 132 }, }, - { { 8, 209 }, - { 48, 38 }, - { 139, 16 }, - { 100, 12 }, }, - { { 8, 125 }, - { 50, 53 }, - { 190, 16 }, - { 172, 76 }, }, - { { 10, 50 }, - { 39, 4 }, - { 76, 80 }, - { 32, 228 }, }, - { { 10, 222 }, - { 37, 55 }, - { 123, 80 }, - { 236, 164 }, }, - { { 2, 81 }, - { 52, 32 }, - { 138, 64 }, - { 4, 44 }, }, - { { 1, 162 }, - { 67, 2 }, - { 69, 128 }, - { 64, 194 }, }, - { { 3, 128 }, - { 68, 2 }, - { 1, 192 }, - { 64, 34 }, }, - { { 11, 131 }, - { 85, 6 }, - { 193, 208 }, - { 96, 170 }, }, - { { 11, 75 }, - { 85, 37 }, - { 210, 208 }, - { 164, 170 }, }, - { { 11, 39 }, - { 87, 20 }, - { 228, 208 }, - { 40, 234 }, }, - { { 11, 239 }, - { 87, 55 }, - { 247, 208 }, - { 236, 234 }, }, - { { 9, 182 }, - { 99, 22 }, - { 109, 144 }, - { 104, 198 }, }, - { { 9, 89 }, - { 112, 37 }, - { 154, 144 }, - { 164, 14 }, }, - { { 9, 147 }, - { 113, 6 }, - { 201, 144 }, - { 96, 142 }, }, - { { 11, 248 }, - { 102, 39 }, - { 31, 208 }, - { 228, 102 }, }, - { { 3, 217 }, - { 116, 35 }, - { 155, 192 }, - { 196, 46 }, }, - { { 3, 241 }, - { 118, 34 }, - { 143, 192 }, - { 68, 110 }, }, - { { 16, 196 }, - { 128, 50 }, - { 35, 8 }, - { 76, 1 }, }, - { { 24, 171 }, - { 147, 7 }, - { 213, 24 }, - { 224, 201 }, }, - { { 26, 160 }, - { 134, 6 }, - { 5, 88 }, - { 96, 97 }, }, - { { 26, 4 }, - { 132, 20 }, - { 32, 88 }, - { 40, 33 }, }, - { { 26, 108 }, - { 134, 53 }, - { 54, 88 }, - { 172, 97 }, }, - { { 26, 174 }, - { 135, 23 }, - { 117, 88 }, - { 232, 225 }, }, - { { 18, 137 }, - { 148, 3 }, - { 145, 72 }, - { 192, 41 }, }, - { { 16, 23 }, - { 177, 16 }, - { 232, 8 }, - { 8, 141 }, }, - { { 26, 243 }, - { 183, 38 }, - { 207, 88 }, - { 100, 237 }, }, - { { 25, 64 }, - { 192, 36 }, - { 2, 152 }, - { 36, 3 }, }, - { { 17, 2 }, - { 193, 0 }, - { 64, 136 }, - { 0, 131 }, }, - { { 17, 43 }, - { 211, 1 }, - { 212, 136 }, - { 128, 203 }, }, - { { 17, 207 }, - { 209, 51 }, - { 243, 136 }, - { 204, 139 }, }, - { { 27, 34 }, - { 199, 4 }, - { 68, 216 }, - { 32, 227 }, }, - { { 19, 46 }, - { 199, 17 }, - { 116, 200 }, - { 136, 227 }, }, - { { 17, 21 }, - { 240, 16 }, - { 168, 136 }, - { 8, 15 }, }, - { { 19, 187 }, - { 247, 3 }, - { 221, 200 }, - { 192, 239 }, }, - { { 12, 32 }, - { 2, 68 }, - { 4, 48 }, - { 34, 64 }, }, - { { 12, 201 }, - { 16, 103 }, - { 147, 48 }, - { 230, 8 }, }, - { { 12, 220 }, - { 32, 119 }, - { 59, 48 }, - { 238, 4 }, }, - { { 12, 54 }, - { 35, 84 }, - { 108, 48 }, - { 42, 196 }, }, - { { 6, 20 }, - { 36, 80 }, - { 40, 96 }, - { 10, 36 }, }, - { { 6, 114 }, - { 39, 96 }, - { 78, 96 }, - { 6, 228 }, }, - { { 13, 97 }, - { 82, 100 }, - { 134, 176 }, - { 38, 74 }, }, - { { 5, 13 }, - { 80, 81 }, - { 176, 160 }, - { 138, 10 }, }, - { { 13, 143 }, - { 81, 87 }, - { 241, 176 }, - { 234, 138 }, }, - { { 15, 224 }, - { 70, 102 }, - { 7, 240 }, - { 102, 98 }, }, - { { 15, 73 }, - { 84, 101 }, - { 146, 240 }, - { 166, 42 }, }, - { { 7, 133 }, - { 84, 82 }, - { 161, 224 }, - { 74, 42 }, }, - { { 5, 144 }, - { 96, 66 }, - { 9, 160 }, - { 66, 6 }, }, - { { 13, 51 }, - { 115, 68 }, - { 204, 176 }, - { 34, 206 }, }, - { { 15, 150 }, - { 101, 86 }, - { 105, 240 }, - { 106, 166 }, }, - { { 15, 118 }, - { 103, 116 }, - { 110, 240 }, - { 46, 230 }, }, - { { 20, 96 }, - { 130, 96 }, - { 6, 40 }, - { 6, 65 }, }, - { { 28, 141 }, - { 144, 87 }, - { 177, 56 }, - { 234, 9 }, }, - { { 20, 218 }, - { 161, 99 }, - { 91, 40 }, - { 198, 133 }, }, - { { 28, 115 }, - { 179, 100 }, - { 206, 56 }, - { 38, 205 }, }, - { { 30, 148 }, - { 164, 86 }, - { 41, 120 }, - { 106, 37 }, }, - { { 30, 186 }, - { 167, 71 }, - { 93, 120 }, - { 226, 229 }, }, - { { 22, 217 }, - { 180, 99 }, - { 155, 104 }, - { 198, 45 }, }, - { { 30, 61 }, - { 182, 85 }, - { 188, 120 }, - { 170, 109 }, }, - { { 22, 251 }, - { 183, 99 }, - { 223, 104 }, - { 198, 237 }, }, - { { 29, 233 }, - { 210, 103 }, - { 151, 184 }, - { 230, 75 }, }, - { { 29, 254 }, - { 227, 119 }, - { 127, 184 }, - { 238, 199 }, }, - { { 31, 159 }, - { 245, 87 }, - { 249, 248 }, - { 234, 175 }, }, - { { 40, 139 }, - { 25, 7 }, - { 209, 20 }, - { 224, 152 }, }, - { { 32, 175 }, - { 27, 19 }, - { 245, 4 }, - { 200, 216 }, }, - { { 34, 14 }, - { 13, 17 }, - { 112, 68 }, - { 136, 176 }, }, - { { 34, 169 }, - { 30, 3 }, - { 149, 68 }, - { 192, 120 }, }, - { { 42, 141 }, - { 28, 23 }, - { 177, 84 }, - { 232, 56 }, }, - { { 42, 163 }, - { 31, 6 }, - { 197, 84 }, - { 96, 248 }, }, - { { 42, 239 }, - { 31, 55 }, - { 247, 84 }, - { 236, 248 }, }, - { { 40, 144 }, - { 40, 6 }, - { 9, 20 }, - { 96, 20 }, }, - { { 40, 59 }, - { 59, 5 }, - { 220, 20 }, - { 160, 220 }, }, - { { 42, 88 }, - { 44, 37 }, - { 26, 84 }, - { 164, 52 }, }, - { { 34, 51 }, - { 63, 0 }, - { 204, 68 }, - { 0, 252 }, }, - { { 33, 160 }, - { 74, 2 }, - { 5, 132 }, - { 64, 82 }, }, - { { 33, 2 }, - { 73, 0 }, - { 64, 132 }, - { 0, 146 }, }, - { { 33, 165 }, - { 90, 18 }, - { 165, 132 }, - { 72, 90 }, }, - { { 33, 199 }, - { 89, 50 }, - { 227, 132 }, - { 76, 154 }, }, - { { 43, 3 }, - { 93, 4 }, - { 192, 212 }, - { 32, 186 }, }, - { { 35, 103 }, - { 95, 48 }, - { 230, 196 }, - { 12, 250 }, }, - { { 41, 48 }, - { 106, 4 }, - { 12, 148 }, - { 32, 86 }, }, - { { 41, 210 }, - { 105, 38 }, - { 75, 148 }, - { 100, 150 }, }, - { { 43, 25 }, - { 124, 5 }, - { 152, 212 }, - { 160, 62 }, }, - { { 43, 155 }, - { 125, 7 }, - { 217, 212 }, - { 224, 190 }, }, - { { 43, 151 }, - { 125, 22 }, - { 233, 212 }, - { 104, 190 }, }, - { { 56, 40 }, - { 138, 5 }, - { 20, 28 }, - { 160, 81 }, }, - { { 56, 165 }, - { 154, 22 }, - { 165, 28 }, - { 104, 89 }, }, - { { 58, 134 }, - { 141, 22 }, - { 97, 92 }, - { 104, 177 }, }, - { { 50, 1 }, - { 156, 0 }, - { 128, 76 }, - { 0, 57 }, }, - { { 56, 159 }, - { 185, 23 }, - { 249, 28 }, - { 232, 157 }, }, - { { 50, 210 }, - { 173, 34 }, - { 75, 76 }, - { 68, 181 }, }, - { { 58, 153 }, - { 188, 7 }, - { 153, 92 }, - { 224, 61 }, }, - { { 58, 213 }, - { 188, 54 }, - { 171, 92 }, - { 108, 61 }, }, - { { 57, 232 }, - { 202, 39 }, - { 23, 156 }, - { 228, 83 }, }, - { { 59, 193 }, - { 220, 38 }, - { 131, 220 }, - { 100, 59 }, }, - { { 51, 67 }, - { 221, 32 }, - { 194, 204 }, - { 4, 187 }, }, - { { 59, 231 }, - { 223, 54 }, - { 231, 220 }, - { 108, 251 }, }, - { { 49, 154 }, - { 233, 3 }, - { 89, 140 }, - { 192, 151 }, }, - { { 51, 144 }, - { 236, 2 }, - { 9, 204 }, - { 64, 55 }, }, - { { 59, 158 }, - { 237, 23 }, - { 121, 220 }, - { 232, 183 }, }, - { { 36, 196 }, - { 8, 114 }, - { 35, 36 }, - { 78, 16 }, }, - { { 44, 74 }, - { 9, 101 }, - { 82, 52 }, - { 166, 144 }, }, - { { 44, 173 }, - { 26, 87 }, - { 181, 52 }, - { 234, 88 }, }, - { { 44, 207 }, - { 25, 119 }, - { 243, 52 }, - { 238, 152 }, }, - { { 44, 103 }, - { 27, 116 }, - { 230, 52 }, - { 46, 216 }, }, - { { 38, 234 }, - { 15, 99 }, - { 87, 100 }, - { 198, 240 }, }, - { { 46, 229 }, - { 30, 118 }, - { 167, 116 }, - { 110, 120 }, }, - { { 44, 112 }, - { 42, 100 }, - { 14, 52 }, - { 38, 84 }, }, - { { 46, 18 }, - { 45, 68 }, - { 72, 116 }, - { 34, 180 }, }, - { { 46, 209 }, - { 60, 102 }, - { 139, 116 }, - { 102, 60 }, }, - { { 46, 57 }, - { 62, 69 }, - { 156, 116 }, - { 162, 124 }, }, - { { 37, 100 }, - { 74, 112 }, - { 38, 164 }, - { 14, 82 }, }, - { { 37, 231 }, - { 91, 114 }, - { 231, 164 }, - { 78, 218 }, }, - { { 47, 204 }, - { 76, 119 }, - { 51, 244 }, - { 238, 50 }, }, - { { 45, 188 }, - { 106, 87 }, - { 61, 180 }, - { 234, 86 }, }, - { { 45, 113 }, - { 122, 100 }, - { 142, 180 }, - { 38, 94 }, }, - { { 37, 213 }, - { 120, 114 }, - { 171, 164 }, - { 78, 30 }, }, - { { 37, 155 }, - { 121, 67 }, - { 217, 164 }, - { 194, 158 }, }, - { { 39, 16 }, - { 108, 64 }, - { 8, 228 }, - { 2, 54 }, }, - { { 47, 124 }, - { 110, 117 }, - { 62, 244 }, - { 174, 118 }, }, - { { 39, 242 }, - { 111, 98 }, - { 79, 228 }, - { 70, 246 }, }, - { { 39, 58 }, - { 111, 65 }, - { 92, 228 }, - { 130, 246 }, }, - { { 47, 182 }, - { 111, 86 }, - { 109, 244 }, - { 106, 246 }, }, - { { 39, 211 }, - { 125, 98 }, - { 203, 228 }, - { 70, 190 }, }, - { { 47, 179 }, - { 127, 70 }, - { 205, 244 }, - { 98, 254 }, }, - { { 39, 31 }, - { 125, 81 }, - { 248, 228 }, - { 138, 190 }, }, - { { 60, 75 }, - { 153, 101 }, - { 210, 60 }, - { 166, 153 }, }, - { { 54, 192 }, - { 140, 98 }, - { 3, 108 }, - { 70, 49 }, }, - { { 54, 238 }, - { 143, 115 }, - { 119, 108 }, - { 206, 241 }, }, - { { 62, 233 }, - { 158, 103 }, - { 151, 124 }, - { 230, 121 }, }, - { { 52, 184 }, - { 170, 67 }, - { 29, 44 }, - { 194, 85 }, }, - { { 60, 20 }, - { 168, 84 }, - { 40, 60 }, - { 42, 21 }, }, - { { 60, 82 }, - { 169, 100 }, - { 74, 60 }, - { 38, 149 }, }, - { { 52, 114 }, - { 171, 96 }, - { 78, 44 }, - { 6, 213 }, }, - { { 52, 126 }, - { 171, 113 }, - { 126, 44 }, - { 142, 213 }, }, - { { 52, 191 }, - { 187, 83 }, - { 253, 44 }, - { 202, 221 }, }, - { { 62, 113 }, - { 190, 100 }, - { 142, 124 }, - { 38, 125 }, }, - { { 62, 83 }, - { 189, 100 }, - { 202, 124 }, - { 38, 189 }, }, - { { 61, 140 }, - { 200, 87 }, - { 49, 188 }, - { 234, 19 }, }, - { { 53, 162 }, - { 203, 66 }, - { 69, 172 }, - { 66, 211 }, }, - { { 53, 46 }, - { 203, 81 }, - { 116, 172 }, - { 138, 211 }, }, - { { 53, 45 }, - { 218, 81 }, - { 180, 172 }, - { 138, 91 }, }, - { { 55, 172 }, - { 206, 83 }, - { 53, 236 }, - { 202, 115 }, }, - { { 53, 112 }, - { 234, 96 }, - { 14, 172 }, - { 6, 87 }, }, - { { 55, 250 }, - { 239, 99 }, - { 95, 236 }, - { 198, 247 }, }, - { { 63, 241 }, - { 254, 102 }, - { 143, 252 }, - { 102, 127 }, }, - { { 63, 219 }, - { 253, 103 }, - { 219, 252 }, - { 230, 191 }, }, - { { 72, 196 }, - { 0, 182 }, - { 35, 18 }, - { 109, 0 }, }, - { { 72, 233 }, - { 18, 167 }, - { 151, 18 }, - { 229, 72 }, }, - { { 74, 194 }, - { 5, 166 }, - { 67, 82 }, - { 101, 160 }, }, - { { 74, 65 }, - { 20, 164 }, - { 130, 82 }, - { 37, 40 }, }, - { { 66, 235 }, - { 23, 163 }, - { 215, 66 }, - { 197, 232 }, }, - { { 72, 19 }, - { 49, 132 }, - { 200, 18 }, - { 33, 140 }, }, - { { 74, 216 }, - { 36, 167 }, - { 27, 82 }, - { 229, 36 }, }, - { { 66, 253 }, - { 54, 179 }, - { 191, 66 }, - { 205, 108 }, }, - { { 74, 23 }, - { 53, 148 }, - { 232, 82 }, - { 41, 172 }, }, - { { 73, 99 }, - { 83, 164 }, - { 198, 146 }, - { 37, 202 }, }, - { { 67, 110 }, - { 71, 177 }, - { 118, 194 }, - { 141, 226 }, }, - { { 65, 58 }, - { 99, 129 }, - { 92, 130 }, - { 129, 198 }, }, - { { 73, 177 }, - { 114, 134 }, - { 141, 146 }, - { 97, 78 }, }, - { { 65, 61 }, - { 114, 145 }, - { 188, 130 }, - { 137, 78 }, }, - { { 75, 146 }, - { 101, 134 }, - { 73, 210 }, - { 97, 166 }, }, - { { 75, 155 }, - { 117, 135 }, - { 217, 210 }, - { 225, 174 }, }, - { { 67, 63 }, - { 119, 145 }, - { 252, 194 }, - { 137, 238 }, }, - { { 88, 34 }, - { 131, 132 }, - { 68, 26 }, - { 33, 193 }, }, - { { 80, 170 }, - { 131, 131 }, - { 85, 10 }, - { 193, 193 }, }, - { { 88, 39 }, - { 147, 148 }, - { 228, 26 }, - { 41, 201 }, }, - { { 82, 200 }, - { 132, 163 }, - { 19, 74 }, - { 197, 33 }, }, - { { 82, 132 }, - { 132, 146 }, - { 33, 74 }, - { 73, 33 }, }, - { { 82, 10 }, - { 133, 129 }, - { 80, 74 }, - { 129, 161 }, }, - { { 90, 15 }, - { 149, 149 }, - { 240, 90 }, - { 169, 169 }, }, - { { 88, 152 }, - { 160, 135 }, - { 25, 26 }, - { 225, 5 }, }, - { { 88, 92 }, - { 160, 181 }, - { 58, 26 }, - { 173, 5 }, }, - { { 80, 219 }, - { 177, 163 }, - { 219, 10 }, - { 197, 141 }, }, - { { 80, 247 }, - { 179, 178 }, - { 239, 10 }, - { 77, 205 }, }, - { { 90, 244 }, - { 166, 182 }, - { 47, 90 }, - { 109, 101 }, }, - { { 81, 236 }, - { 194, 179 }, - { 55, 138 }, - { 205, 67 }, }, - { { 81, 66 }, - { 193, 160 }, - { 66, 138 }, - { 5, 131 }, }, - { { 81, 13 }, - { 208, 145 }, - { 176, 138 }, - { 137, 11 }, }, - { { 91, 3 }, - { 213, 132 }, - { 192, 218 }, - { 33, 171 }, }, - { { 83, 235 }, - { 215, 163 }, - { 215, 202 }, - { 197, 235 }, }, - { { 81, 118 }, - { 227, 176 }, - { 110, 138 }, - { 13, 199 }, }, - { { 89, 113 }, - { 242, 164 }, - { 142, 154 }, - { 37, 79 }, }, - { { 81, 147 }, - { 241, 130 }, - { 201, 138 }, - { 65, 143 }, }, - { { 83, 249 }, - { 246, 163 }, - { 159, 202 }, - { 197, 111 }, }, - { { 91, 179 }, - { 247, 134 }, - { 205, 218 }, - { 97, 239 }, }, - { { 83, 151 }, - { 245, 146 }, - { 233, 202 }, - { 73, 175 }, }, - { { 76, 76 }, - { 0, 245 }, - { 50, 50 }, - { 175, 0 }, }, - { { 68, 75 }, - { 17, 225 }, - { 210, 34 }, - { 135, 136 }, }, - { { 76, 35 }, - { 19, 196 }, - { 196, 50 }, - { 35, 200 }, }, - { { 70, 140 }, - { 4, 211 }, - { 49, 98 }, - { 203, 32 }, }, - { { 78, 39 }, - { 23, 212 }, - { 228, 114 }, - { 43, 232 }, }, - { { 70, 144 }, - { 36, 194 }, - { 9, 98 }, - { 67, 36 }, }, - { { 78, 212 }, - { 36, 246 }, - { 43, 114 }, - { 111, 36 }, }, - { { 69, 206 }, - { 65, 243 }, - { 115, 162 }, - { 207, 130 }, }, - { { 69, 229 }, - { 82, 242 }, - { 167, 162 }, - { 79, 74 }, }, - { { 69, 39 }, - { 83, 208 }, - { 228, 162 }, - { 11, 202 }, }, - { { 79, 193 }, - { 84, 230 }, - { 131, 242 }, - { 103, 42 }, }, - { { 71, 5 }, - { 84, 208 }, - { 160, 226 }, - { 11, 42 }, }, - { { 69, 52 }, - { 98, 208 }, - { 44, 162 }, - { 11, 70 }, }, - { { 69, 114 }, - { 99, 224 }, - { 78, 162 }, - { 7, 198 }, }, - { { 92, 200 }, - { 128, 231 }, - { 19, 58 }, - { 231, 1 }, }, - { { 92, 14 }, - { 129, 213 }, - { 112, 58 }, - { 171, 129 }, }, - { { 84, 235 }, - { 147, 227 }, - { 215, 42 }, - { 199, 201 }, }, - { { 86, 137 }, - { 148, 195 }, - { 145, 106 }, - { 195, 41 }, }, - { { 86, 67 }, - { 149, 224 }, - { 194, 106 }, - { 7, 169 }, }, - { { 94, 231 }, - { 151, 246 }, - { 231, 122 }, - { 111, 233 }, }, - { { 92, 112 }, - { 162, 228 }, - { 14, 58 }, - { 39, 69 }, }, - { { 84, 178 }, - { 163, 194 }, - { 77, 42 }, - { 67, 197 }, }, - { { 94, 121 }, - { 182, 229 }, - { 158, 122 }, - { 167, 109 }, }, - { { 86, 243 }, - { 183, 226 }, - { 207, 106 }, - { 71, 237 }, }, - { { 93, 163 }, - { 211, 198 }, - { 197, 186 }, - { 99, 203 }, }, - { { 93, 242 }, - { 227, 230 }, - { 79, 186 }, - { 103, 199 }, }, - { { 85, 29 }, - { 240, 209 }, - { 184, 170 }, - { 139, 15 }, }, - { { 93, 157 }, - { 240, 215 }, - { 185, 186 }, - { 235, 15 }, }, - { { 87, 252 }, - { 230, 243 }, - { 63, 234 }, - { 207, 103 }, }, - { { 87, 210 }, - { 229, 226 }, - { 75, 234 }, - { 71, 167 }, }, - { { 95, 115 }, - { 247, 228 }, - { 206, 250 }, - { 39, 239 }, }, - { { 104, 45 }, - { 26, 149 }, - { 180, 22 }, - { 169, 88 }, }, - { { 104, 195 }, - { 25, 166 }, - { 195, 22 }, - { 101, 152 }, }, - { { 104, 135 }, - { 25, 150 }, - { 225, 22 }, - { 105, 152 }, }, - { { 106, 74 }, - { 13, 165 }, - { 82, 86 }, - { 165, 176 }, }, - { { 98, 105 }, - { 30, 161 }, - { 150, 70 }, - { 133, 120 }, }, - { { 96, 185 }, - { 58, 131 }, - { 157, 6 }, - { 193, 92 }, }, - { { 104, 255 }, - { 59, 183 }, - { 255, 22 }, - { 237, 220 }, }, - { { 106, 220 }, - { 44, 183 }, - { 59, 86 }, - { 237, 52 }, }, - { { 106, 218 }, - { 45, 167 }, - { 91, 86 }, - { 229, 180 }, }, - { { 106, 62 }, - { 47, 149 }, - { 124, 86 }, - { 169, 244 }, }, - { { 106, 81 }, - { 60, 164 }, - { 138, 86 }, - { 37, 60 }, }, - { { 106, 49 }, - { 62, 132 }, - { 140, 86 }, - { 33, 124 }, }, - { { 98, 215 }, - { 61, 178 }, - { 235, 70 }, - { 77, 188 }, }, - { { 97, 204 }, - { 72, 179 }, - { 51, 134 }, - { 205, 18 }, }, - { { 107, 130 }, - { 77, 134 }, - { 65, 214 }, - { 97, 178 }, }, - { { 107, 227 }, - { 95, 166 }, - { 199, 214 }, - { 101, 250 }, }, - { { 105, 58 }, - { 107, 133 }, - { 92, 150 }, - { 161, 214 }, }, - { { 97, 158 }, - { 105, 147 }, - { 121, 134 }, - { 201, 150 }, }, - { { 97, 149 }, - { 120, 146 }, - { 169, 134 }, - { 73, 30 }, }, - { { 97, 117 }, - { 122, 176 }, - { 174, 134 }, - { 13, 94 }, }, - { { 105, 95 }, - { 121, 181 }, - { 250, 150 }, - { 173, 158 }, }, - { { 105, 55 }, - { 123, 148 }, - { 236, 150 }, - { 41, 222 }, }, - { { 99, 218 }, - { 109, 163 }, - { 91, 198 }, - { 197, 182 }, }, - { { 112, 2 }, - { 137, 128 }, - { 64, 14 }, - { 1, 145 }, }, - { { 120, 99 }, - { 155, 164 }, - { 198, 30 }, - { 37, 217 }, }, - { { 112, 79 }, - { 153, 177 }, - { 242, 14 }, - { 141, 153 }, }, - { { 114, 202 }, - { 141, 163 }, - { 83, 78 }, - { 197, 177 }, }, - { { 122, 173 }, - { 158, 151 }, - { 181, 94 }, - { 233, 121 }, }, - { { 112, 123 }, - { 187, 161 }, - { 222, 14 }, - { 133, 221 }, }, - { { 122, 20 }, - { 172, 148 }, - { 40, 94 }, - { 41, 53 }, }, - { { 122, 249 }, - { 190, 167 }, - { 159, 94 }, - { 229, 125 }, }, - { { 122, 211 }, - { 189, 166 }, - { 203, 94 }, - { 101, 189 }, }, - { { 122, 187 }, - { 191, 135 }, - { 221, 94 }, - { 225, 253 }, }, - { { 121, 226 }, - { 203, 166 }, - { 71, 158 }, - { 101, 211 }, }, - { { 113, 41 }, - { 218, 129 }, - { 148, 142 }, - { 129, 91 }, }, - { { 123, 103 }, - { 223, 180 }, - { 230, 222 }, - { 45, 251 }, }, - { { 113, 208 }, - { 232, 162 }, - { 11, 142 }, - { 69, 23 }, }, - { { 121, 57 }, - { 250, 133 }, - { 156, 158 }, - { 161, 95 }, }, - { { 115, 48 }, - { 238, 128 }, - { 12, 206 }, - { 1, 119 }, }, - { { 115, 185 }, - { 254, 131 }, - { 157, 206 }, - { 193, 127 }, }, - { { 115, 83 }, - { 253, 160 }, - { 202, 206 }, - { 5, 191 }, }, - { { 115, 255 }, - { 255, 179 }, - { 255, 206 }, - { 205, 255 }, }, - { { 108, 136 }, - { 8, 199 }, - { 17, 54 }, - { 227, 16 }, }, - { { 100, 9 }, - { 24, 193 }, - { 144, 38 }, - { 131, 24 }, }, - { { 108, 67 }, - { 25, 228 }, - { 194, 54 }, - { 39, 152 }, }, - { { 102, 6 }, - { 13, 208 }, - { 96, 102 }, - { 11, 176 }, }, - { { 102, 131 }, - { 29, 194 }, - { 193, 102 }, - { 67, 184 }, }, - { { 100, 176 }, - { 42, 194 }, - { 13, 38 }, - { 67, 84 }, }, - { { 100, 218 }, - { 41, 227 }, - { 91, 38 }, - { 199, 148 }, }, - { { 110, 159 }, - { 61, 215 }, - { 249, 118 }, - { 235, 188 }, }, - { { 103, 200 }, - { 76, 227 }, - { 19, 230 }, - { 199, 50 }, }, - { { 111, 238 }, - { 79, 247 }, - { 119, 246 }, - { 239, 242 }, }, - { { 109, 59 }, - { 123, 197 }, - { 220, 182 }, - { 163, 222 }, }, - { { 111, 210 }, - { 109, 230 }, - { 75, 246 }, - { 103, 182 }, }, - { { 116, 128 }, - { 136, 194 }, - { 1, 46 }, - { 67, 17 }, }, - { { 124, 171 }, - { 155, 199 }, - { 213, 62 }, - { 227, 217 }, }, - { { 126, 104 }, - { 142, 229 }, - { 22, 126 }, - { 167, 113 }, }, - { { 126, 2 }, - { 141, 196 }, - { 64, 126 }, - { 35, 177 }, }, - { { 124, 156 }, - { 168, 215 }, - { 57, 62 }, - { 235, 21 }, }, - { { 116, 54 }, - { 171, 208 }, - { 108, 46 }, - { 11, 213 }, }, - { { 124, 17 }, - { 184, 196 }, - { 136, 62 }, - { 35, 29 }, }, - { { 126, 222 }, - { 173, 247 }, - { 123, 126 }, - { 239, 181 }, }, - { { 126, 182 }, - { 175, 214 }, - { 109, 126 }, - { 107, 245 }, }, - { { 118, 219 }, - { 189, 227 }, - { 219, 110 }, - { 199, 189 }, }, - { { 125, 196 }, - { 200, 246 }, - { 35, 190 }, - { 111, 19 }, }, - { { 125, 138 }, - { 201, 199 }, - { 81, 190 }, - { 227, 147 }, }, - { { 117, 109 }, - { 218, 241 }, - { 182, 174 }, - { 143, 91 }, }, - { { 119, 136 }, - { 204, 195 }, - { 17, 238 }, - { 195, 51 }, }, - { { 119, 32 }, - { 206, 192 }, - { 4, 238 }, - { 3, 115 }, }, - { { 119, 65 }, - { 220, 224 }, - { 130, 238 }, - { 7, 59 }, }, - { { 117, 56 }, - { 234, 193 }, - { 28, 174 }, - { 131, 87 }, }, - { { 117, 190 }, - { 235, 211 }, - { 125, 174 }, - { 203, 215 }, }, - { { 125, 155 }, - { 249, 199 }, - { 217, 190 }, - { 227, 159 }, }, - { { 119, 87 }, - { 253, 240 }, - { 234, 238 }, - { 15, 191 }, }, - { { 136, 40 }, - { 2, 13 }, - { 20, 17 }, - { 176, 64 }, }, - { { 128, 172 }, - { 2, 27 }, - { 53, 1 }, - { 216, 64 }, }, - { { 136, 13 }, - { 16, 29 }, - { 176, 17 }, - { 184, 8 }, }, - { { 136, 103 }, - { 19, 60 }, - { 230, 17 }, - { 60, 200 }, }, - { { 130, 78 }, - { 5, 57 }, - { 114, 65 }, - { 156, 160 }, }, - { { 138, 161 }, - { 22, 14 }, - { 133, 81 }, - { 112, 104 }, }, - { { 130, 43 }, - { 23, 9 }, - { 212, 65 }, - { 144, 232 }, }, - { { 128, 24 }, - { 32, 9 }, - { 24, 1 }, - { 144, 4 }, }, - { { 136, 249 }, - { 50, 47 }, - { 159, 17 }, - { 244, 76 }, }, - { { 128, 157 }, - { 48, 27 }, - { 185, 1 }, - { 216, 12 }, }, - { { 138, 156 }, - { 36, 31 }, - { 57, 81 }, - { 248, 36 }, }, - { { 130, 49 }, - { 54, 8 }, - { 140, 65 }, - { 16, 108 }, }, - { { 138, 117 }, - { 54, 60 }, - { 174, 81 }, - { 60, 108 }, }, - { { 130, 151 }, - { 53, 26 }, - { 233, 65 }, - { 88, 172 }, }, - { { 129, 9 }, - { 80, 9 }, - { 144, 129 }, - { 144, 10 }, }, - { { 129, 235 }, - { 83, 43 }, - { 215, 129 }, - { 212, 202 }, }, - { { 129, 7 }, - { 81, 24 }, - { 224, 129 }, - { 24, 138 }, }, - { { 139, 40 }, - { 70, 13 }, - { 20, 209 }, - { 176, 98 }, }, - { { 139, 172 }, - { 70, 31 }, - { 53, 209 }, - { 248, 98 }, }, - { { 131, 46 }, - { 71, 25 }, - { 116, 193 }, - { 152, 226 }, }, - { { 131, 229 }, - { 86, 58 }, - { 167, 193 }, - { 92, 106 }, }, - { { 129, 80 }, - { 96, 40 }, - { 10, 129 }, - { 20, 6 }, }, - { { 137, 50 }, - { 99, 12 }, - { 76, 145 }, - { 48, 198 }, }, - { { 139, 122 }, - { 103, 45 }, - { 94, 209 }, - { 180, 230 }, }, - { { 139, 150 }, - { 101, 30 }, - { 105, 209 }, - { 120, 166 }, }, - { { 131, 125 }, - { 118, 57 }, - { 190, 193 }, - { 156, 110 }, }, - { { 144, 135 }, - { 145, 26 }, - { 225, 9 }, - { 88, 137 }, }, - { { 154, 252 }, - { 166, 63 }, - { 63, 89 }, - { 252, 101 }, }, - { { 146, 245 }, - { 182, 58 }, - { 175, 73 }, - { 92, 109 }, }, - { { 145, 170 }, - { 195, 11 }, - { 85, 137 }, - { 208, 195 }, }, - { { 147, 65 }, - { 212, 40 }, - { 130, 201 }, - { 20, 43 }, }, - { { 147, 37 }, - { 214, 24 }, - { 164, 201 }, - { 24, 107 }, }, - { { 155, 235 }, - { 215, 47 }, - { 215, 217 }, - { 244, 235 }, }, - { { 153, 52 }, - { 226, 28 }, - { 44, 153 }, - { 56, 71 }, }, - { { 145, 247 }, - { 243, 58 }, - { 239, 137 }, - { 92, 207 }, }, - { { 155, 218 }, - { 229, 47 }, - { 91, 217 }, - { 244, 167 }, }, - { { 147, 86 }, - { 229, 56 }, - { 106, 201 }, - { 28, 167 }, }, - { { 132, 66 }, - { 1, 104 }, - { 66, 33 }, - { 22, 128 }, }, - { { 140, 129 }, - { 16, 78 }, - { 129, 49 }, - { 114, 8 }, }, - { { 140, 79 }, - { 17, 125 }, - { 242, 49 }, - { 190, 136 }, }, - { { 134, 72 }, - { 4, 105 }, - { 18, 97 }, - { 150, 32 }, }, - { { 134, 166 }, - { 7, 90 }, - { 101, 97 }, - { 90, 224 }, }, - { { 142, 3 }, - { 21, 76 }, - { 192, 113 }, - { 50, 168 }, }, - { { 134, 227 }, - { 23, 106 }, - { 199, 97 }, - { 86, 232 }, }, - { { 134, 111 }, - { 23, 121 }, - { 246, 97 }, - { 158, 232 }, }, - { { 142, 175 }, - { 23, 95 }, - { 245, 113 }, - { 250, 232 }, }, - { { 132, 94 }, - { 33, 121 }, - { 122, 33 }, - { 158, 132 }, }, - { { 132, 119 }, - { 51, 120 }, - { 238, 33 }, - { 30, 204 }, }, - { { 134, 250 }, - { 39, 107 }, - { 95, 97 }, - { 214, 228 }, }, - { { 142, 30 }, - { 37, 93 }, - { 120, 113 }, - { 186, 164 }, }, - { { 142, 55 }, - { 55, 92 }, - { 236, 113 }, - { 58, 236 }, }, - { { 135, 10 }, - { 69, 73 }, - { 80, 225 }, - { 146, 162 }, }, - { { 143, 138 }, - { 69, 79 }, - { 81, 241 }, - { 242, 162 }, }, - { { 143, 38 }, - { 71, 92 }, - { 100, 241 }, - { 58, 226 }, }, - { { 135, 33 }, - { 86, 72 }, - { 132, 225 }, - { 18, 106 }, }, - { { 135, 13 }, - { 84, 89 }, - { 176, 225 }, - { 154, 42 }, }, - { { 133, 114 }, - { 99, 104 }, - { 78, 161 }, - { 22, 198 }, }, - { { 135, 62 }, - { 103, 89 }, - { 124, 225 }, - { 154, 230 }, }, - { { 156, 67 }, - { 145, 108 }, - { 194, 57 }, - { 54, 137 }, }, - { { 158, 97 }, - { 150, 108 }, - { 134, 121 }, - { 54, 105 }, }, - { { 148, 88 }, - { 160, 105 }, - { 26, 41 }, - { 150, 5 }, }, - { { 148, 248 }, - { 162, 107 }, - { 31, 41 }, - { 214, 69 }, }, - { { 156, 50 }, - { 163, 76 }, - { 76, 57 }, - { 50, 197 }, }, - { { 148, 118 }, - { 163, 120 }, - { 110, 41 }, - { 30, 197 }, }, - { { 148, 177 }, - { 178, 74 }, - { 141, 41 }, - { 82, 77 }, }, - { { 148, 221 }, - { 176, 123 }, - { 187, 41 }, - { 222, 13 }, }, - { { 148, 155 }, - { 177, 75 }, - { 217, 41 }, - { 210, 141 }, }, - { { 156, 219 }, - { 177, 111 }, - { 219, 57 }, - { 246, 141 }, }, - { { 158, 156 }, - { 164, 95 }, - { 57, 121 }, - { 250, 37 }, }, - { { 158, 210 }, - { 165, 110 }, - { 75, 121 }, - { 118, 165 }, }, - { { 150, 25 }, - { 180, 73 }, - { 152, 105 }, - { 146, 45 }, }, - { { 158, 177 }, - { 182, 78 }, - { 141, 121 }, - { 114, 109 }, }, - { { 149, 105 }, - { 210, 105 }, - { 150, 169 }, - { 150, 75 }, }, - { { 159, 109 }, - { 214, 125 }, - { 182, 249 }, - { 190, 107 }, }, - { { 151, 43 }, - { 215, 73 }, - { 212, 233 }, - { 146, 235 }, }, - { { 149, 182 }, - { 227, 90 }, - { 109, 169 }, - { 90, 199 }, }, - { { 149, 185 }, - { 242, 75 }, - { 157, 169 }, - { 210, 79 }, }, - { { 157, 61 }, - { 242, 93 }, - { 188, 185 }, - { 186, 79 }, }, - { { 157, 87 }, - { 241, 124 }, - { 234, 185 }, - { 62, 143 }, }, - { { 168, 236 }, - { 10, 63 }, - { 55, 21 }, - { 252, 80 }, }, - { { 168, 37 }, - { 26, 28 }, - { 164, 21 }, - { 56, 88 }, }, - { { 162, 172 }, - { 14, 27 }, - { 53, 69 }, - { 216, 112 }, }, - { { 162, 2 }, - { 13, 8 }, - { 64, 69 }, - { 16, 176 }, }, - { { 170, 102 }, - { 15, 60 }, - { 102, 85 }, - { 60, 240 }, }, - { { 170, 143 }, - { 29, 31 }, - { 241, 85 }, - { 248, 184 }, }, - { { 170, 231 }, - { 31, 62 }, - { 231, 85 }, - { 124, 248 }, }, - { { 168, 48 }, - { 42, 12 }, - { 12, 21 }, - { 48, 84 }, }, - { { 168, 122 }, - { 43, 45 }, - { 94, 21 }, - { 180, 212 }, }, - { { 168, 246 }, - { 43, 62 }, - { 111, 21 }, - { 124, 212 }, }, - { { 168, 147 }, - { 57, 14 }, - { 201, 21 }, - { 112, 156 }, }, - { { 162, 20 }, - { 44, 24 }, - { 40, 69 }, - { 24, 52 }, }, - { { 170, 52 }, - { 46, 28 }, - { 44, 85 }, - { 56, 116 }, }, - { { 162, 114 }, - { 47, 40 }, - { 78, 69 }, - { 20, 244 }, }, - { { 170, 242 }, - { 47, 46 }, - { 79, 85 }, - { 116, 244 }, }, - { { 162, 241 }, - { 62, 42 }, - { 143, 69 }, - { 84, 124 }, }, - { { 161, 64 }, - { 72, 40 }, - { 2, 133 }, - { 20, 18 }, }, - { { 169, 10 }, - { 73, 13 }, - { 80, 149 }, - { 176, 146 }, }, - { { 161, 38 }, - { 75, 24 }, - { 100, 133 }, - { 24, 210 }, }, - { { 169, 197 }, - { 88, 62 }, - { 163, 149 }, - { 124, 26 }, }, - { { 169, 207 }, - { 89, 63 }, - { 243, 149 }, - { 252, 154 }, }, - { { 161, 52 }, - { 106, 24 }, - { 44, 133 }, - { 24, 86 }, }, - { { 169, 18 }, - { 105, 12 }, - { 72, 149 }, - { 48, 150 }, }, - { { 161, 250 }, - { 107, 43 }, - { 95, 133 }, - { 212, 214 }, }, - { { 171, 152 }, - { 108, 15 }, - { 25, 213 }, - { 240, 54 }, }, - { { 163, 247 }, - { 127, 58 }, - { 239, 197 }, - { 92, 254 }, }, - { { 176, 6 }, - { 137, 24 }, - { 96, 13 }, - { 24, 145 }, }, - { { 176, 69 }, - { 152, 56 }, - { 162, 13 }, - { 28, 25 }, }, - { { 184, 141 }, - { 152, 31 }, - { 177, 29 }, - { 248, 25 }, }, - { { 178, 132 }, - { 140, 26 }, - { 33, 77 }, - { 88, 49 }, }, - { { 184, 240 }, - { 170, 46 }, - { 15, 29 }, - { 116, 85 }, }, - { { 184, 85 }, - { 184, 60 }, - { 170, 29 }, - { 60, 29 }, }, - { { 178, 118 }, - { 175, 56 }, - { 110, 77 }, - { 28, 245 }, }, - { { 186, 145 }, - { 188, 14 }, - { 137, 93 }, - { 112, 61 }, }, - { { 178, 113 }, - { 190, 40 }, - { 142, 77 }, - { 20, 125 }, }, - { { 185, 192 }, - { 200, 46 }, - { 3, 157 }, - { 116, 19 }, }, - { { 185, 66 }, - { 201, 44 }, - { 66, 157 }, - { 52, 147 }, }, - { { 185, 42 }, - { 203, 13 }, - { 84, 157 }, - { 176, 211 }, }, - { { 179, 140 }, - { 204, 27 }, - { 49, 205 }, - { 216, 51 }, }, - { { 179, 202 }, - { 205, 43 }, - { 83, 205 }, - { 212, 179 }, }, - { { 187, 102 }, - { 207, 60 }, - { 102, 221 }, - { 60, 243 }, }, - { { 179, 15 }, - { 221, 25 }, - { 240, 205 }, - { 152, 187 }, }, - { { 177, 218 }, - { 233, 43 }, - { 91, 141 }, - { 212, 151 }, }, - { { 187, 20 }, - { 236, 28 }, - { 40, 221 }, - { 56, 55 }, }, - { { 187, 246 }, - { 239, 62 }, - { 111, 221 }, - { 124, 247 }, }, - { { 179, 19 }, - { 253, 8 }, - { 200, 205 }, - { 16, 191 }, }, - { { 164, 104 }, - { 10, 105 }, - { 22, 37 }, - { 150, 80 }, }, - { { 172, 44 }, - { 10, 93 }, - { 52, 53 }, - { 186, 80 }, }, - { { 172, 161 }, - { 26, 78 }, - { 133, 53 }, - { 114, 88 }, }, - { { 172, 235 }, - { 27, 111 }, - { 215, 53 }, - { 246, 216 }, }, - { { 172, 199 }, - { 25, 126 }, - { 227, 53 }, - { 126, 152 }, }, - { { 164, 103 }, - { 27, 120 }, - { 230, 37 }, - { 30, 216 }, }, - { { 166, 192 }, - { 12, 106 }, - { 3, 101 }, - { 86, 48 }, }, - { { 174, 224 }, - { 14, 110 }, - { 7, 117 }, - { 118, 112 }, }, - { { 166, 35 }, - { 31, 72 }, - { 196, 101 }, - { 18, 248 }, }, - { { 173, 232 }, - { 74, 111 }, - { 23, 181 }, - { 246, 82 }, }, - { { 165, 204 }, - { 72, 123 }, - { 51, 165 }, - { 222, 18 }, }, - { { 167, 236 }, - { 78, 123 }, - { 55, 229 }, - { 222, 114 }, }, - { { 173, 124 }, - { 106, 125 }, - { 62, 181 }, - { 190, 86 }, }, - { { 165, 26 }, - { 105, 73 }, - { 88, 165 }, - { 146, 150 }, }, - { { 165, 145 }, - { 120, 74 }, - { 137, 165 }, - { 82, 30 }, }, - { { 173, 25 }, - { 120, 77 }, - { 152, 181 }, - { 178, 30 }, }, - { { 165, 151 }, - { 121, 90 }, - { 233, 165 }, - { 90, 158 }, }, - { { 180, 109 }, - { 154, 121 }, - { 182, 45 }, - { 158, 89 }, }, - { { 190, 203 }, - { 157, 111 }, - { 211, 125 }, - { 246, 185 }, }, - { { 188, 58 }, - { 171, 77 }, - { 92, 61 }, - { 178, 213 }, }, - { { 188, 245 }, - { 186, 126 }, - { 175, 61 }, - { 126, 93 }, }, - { { 190, 189 }, - { 190, 95 }, - { 189, 125 }, - { 250, 125 }, }, - { { 190, 243 }, - { 191, 110 }, - { 207, 125 }, - { 118, 253 }, }, - { { 181, 37 }, - { 218, 88 }, - { 164, 173 }, - { 26, 91 }, }, - { { 181, 143 }, - { 217, 91 }, - { 241, 173 }, - { 218, 155 }, }, - { { 183, 104 }, - { 206, 105 }, - { 22, 237 }, - { 150, 115 }, }, - { { 191, 228 }, - { 206, 126 }, - { 39, 253 }, - { 126, 115 }, }, - { { 189, 254 }, - { 235, 127 }, - { 127, 189 }, - { 254, 215 }, }, - { { 189, 157 }, - { 248, 95 }, - { 185, 189 }, - { 250, 31 }, }, - { { 181, 245 }, - { 250, 122 }, - { 175, 173 }, - { 94, 95 }, }, - { { 181, 243 }, - { 251, 106 }, - { 207, 173 }, - { 86, 223 }, }, - { { 191, 176 }, - { 238, 78 }, - { 13, 253 }, - { 114, 119 }, }, - { { 183, 90 }, - { 237, 105 }, - { 90, 237 }, - { 150, 183 }, }, - { { 191, 62 }, - { 239, 93 }, - { 124, 253 }, - { 186, 247 }, }, - { { 183, 57 }, - { 254, 73 }, - { 156, 237 }, - { 146, 127 }, }, - { { 191, 213 }, - { 252, 126 }, - { 171, 253 }, - { 126, 63 }, }, - { { 183, 29 }, - { 252, 89 }, - { 184, 237 }, - { 154, 63 }, }, - { { 191, 53 }, - { 254, 92 }, - { 172, 253 }, - { 58, 127 }, }, - { { 183, 127 }, - { 255, 121 }, - { 254, 237 }, - { 158, 255 }, }, - { { 200, 1 }, - { 16, 140 }, - { 128, 19 }, - { 49, 8 }, }, - { { 192, 165 }, - { 18, 154 }, - { 165, 3 }, - { 89, 72 }, }, - { { 194, 130 }, - { 5, 138 }, - { 65, 67 }, - { 81, 160 }, }, - { { 200, 189 }, - { 50, 159 }, - { 189, 19 }, - { 249, 76 }, }, - { { 194, 252 }, - { 38, 187 }, - { 63, 67 }, - { 221, 100 }, }, - { { 202, 145 }, - { 52, 142 }, - { 137, 83 }, - { 113, 44 }, }, - { { 194, 91 }, - { 53, 169 }, - { 218, 67 }, - { 149, 172 }, }, - { { 201, 68 }, - { 64, 188 }, - { 34, 147 }, - { 61, 2 }, }, - { { 193, 42 }, - { 67, 137 }, - { 84, 131 }, - { 145, 194 }, }, - { { 195, 192 }, - { 68, 170 }, - { 3, 195 }, - { 85, 34 }, }, - { { 201, 122 }, - { 99, 173 }, - { 94, 147 }, - { 181, 198 }, }, - { { 193, 185 }, - { 114, 139 }, - { 157, 131 }, - { 209, 78 }, }, - { { 201, 117 }, - { 114, 188 }, - { 174, 147 }, - { 61, 78 }, }, - { { 193, 247 }, - { 115, 186 }, - { 239, 131 }, - { 93, 206 }, }, - { { 203, 177 }, - { 118, 142 }, - { 141, 211 }, - { 113, 110 }, }, - { { 208, 108 }, - { 130, 185 }, - { 54, 11 }, - { 157, 65 }, }, - { { 216, 135 }, - { 145, 158 }, - { 225, 27 }, - { 121, 137 }, }, - { { 208, 175 }, - { 147, 155 }, - { 245, 11 }, - { 217, 201 }, }, - { { 218, 196 }, - { 132, 190 }, - { 35, 91 }, - { 125, 33 }, }, - { { 210, 12 }, - { 132, 153 }, - { 48, 75 }, - { 153, 33 }, }, - { { 218, 9 }, - { 148, 141 }, - { 144, 91 }, - { 177, 41 }, }, - { { 208, 48 }, - { 162, 136 }, - { 12, 11 }, - { 17, 69 }, }, - { { 216, 148 }, - { 160, 158 }, - { 41, 27 }, - { 121, 5 }, }, - { { 208, 58 }, - { 163, 137 }, - { 92, 11 }, - { 145, 197 }, }, - { { 208, 182 }, - { 163, 154 }, - { 109, 11 }, - { 89, 197 }, }, - { { 208, 117 }, - { 178, 184 }, - { 174, 11 }, - { 29, 77 }, }, - { { 210, 118 }, - { 167, 184 }, - { 110, 75 }, - { 29, 229 }, }, - { { 218, 93 }, - { 180, 189 }, - { 186, 91 }, - { 189, 45 }, }, - { { 218, 53 }, - { 182, 156 }, - { 172, 91 }, - { 57, 109 }, }, - { { 210, 23 }, - { 181, 152 }, - { 232, 75 }, - { 25, 173 }, }, - { { 217, 2 }, - { 193, 140 }, - { 64, 155 }, - { 49, 131 }, }, - { { 211, 232 }, - { 198, 171 }, - { 23, 203 }, - { 213, 99 }, }, - { { 211, 229 }, - { 214, 186 }, - { 167, 203 }, - { 93, 107 }, }, - { { 209, 154 }, - { 225, 139 }, - { 89, 139 }, - { 209, 135 }, }, - { { 209, 246 }, - { 227, 186 }, - { 111, 139 }, - { 93, 199 }, }, - { { 209, 81 }, - { 240, 168 }, - { 138, 139 }, - { 21, 15 }, }, - { { 219, 20 }, - { 228, 156 }, - { 40, 219 }, - { 57, 39 }, }, - { { 211, 62 }, - { 231, 153 }, - { 124, 203 }, - { 153, 231 }, }, - { { 211, 211 }, - { 245, 170 }, - { 203, 203 }, - { 85, 175 }, }, - { { 196, 96 }, - { 2, 232 }, - { 6, 35 }, - { 23, 64 }, }, - { { 204, 167 }, - { 19, 222 }, - { 229, 51 }, - { 123, 200 }, }, - { { 198, 66 }, - { 5, 232 }, - { 66, 99 }, - { 23, 160 }, }, - { { 198, 71 }, - { 21, 248 }, - { 226, 99 }, - { 31, 168 }, }, - { { 206, 231 }, - { 23, 254 }, - { 231, 115 }, - { 127, 232 }, }, - { { 196, 92 }, - { 32, 249 }, - { 58, 35 }, - { 159, 4 }, }, - { { 204, 29 }, - { 48, 221 }, - { 184, 51 }, - { 187, 12 }, }, - { { 204, 53 }, - { 50, 220 }, - { 172, 51 }, - { 59, 76 }, }, - { { 198, 188 }, - { 38, 219 }, - { 61, 99 }, - { 219, 100 }, }, - { { 205, 168 }, - { 66, 207 }, - { 21, 179 }, - { 243, 66 }, }, - { { 197, 12 }, - { 64, 217 }, - { 48, 163 }, - { 155, 2 }, }, - { { 197, 228 }, - { 66, 250 }, - { 39, 163 }, - { 95, 66 }, }, - { { 197, 194 }, - { 65, 234 }, - { 67, 163 }, - { 87, 130 }, }, - { { 205, 45 }, - { 82, 221 }, - { 180, 179 }, - { 187, 74 }, }, - { { 205, 89 }, - { 112, 237 }, - { 154, 179 }, - { 183, 14 }, }, - { { 205, 149 }, - { 112, 222 }, - { 169, 179 }, - { 123, 14 }, }, - { { 197, 147 }, - { 113, 202 }, - { 201, 163 }, - { 83, 142 }, }, - { { 199, 95 }, - { 117, 249 }, - { 250, 227 }, - { 159, 174 }, }, - { { 212, 197 }, - { 144, 250 }, - { 163, 43 }, - { 95, 9 }, }, - { { 222, 136 }, - { 132, 207 }, - { 17, 123 }, - { 243, 33 }, }, - { { 214, 36 }, - { 134, 216 }, - { 36, 107 }, - { 27, 97 }, }, - { { 222, 236 }, - { 134, 255 }, - { 55, 123 }, - { 255, 97 }, }, - { { 214, 226 }, - { 135, 234 }, - { 71, 107 }, - { 87, 225 }, }, - { { 222, 198 }, - { 133, 254 }, - { 99, 123 }, - { 127, 161 }, }, - { { 222, 35 }, - { 151, 204 }, - { 196, 123 }, - { 51, 233 }, }, - { { 220, 220 }, - { 160, 255 }, - { 59, 59 }, - { 255, 5 }, }, - { { 220, 26 }, - { 161, 205 }, - { 88, 59 }, - { 179, 133 }, }, - { { 212, 17 }, - { 176, 200 }, - { 136, 43 }, - { 19, 13 }, }, - { { 222, 84 }, - { 164, 252 }, - { 42, 123 }, - { 63, 37 }, }, - { { 214, 148 }, - { 164, 218 }, - { 41, 107 }, - { 91, 37 }, }, - { { 222, 157 }, - { 180, 223 }, - { 185, 123 }, - { 251, 45 }, }, - { { 221, 129 }, - { 208, 206 }, - { 129, 187 }, - { 115, 11 }, }, - { { 213, 165 }, - { 210, 218 }, - { 165, 171 }, - { 91, 75 }, }, - { { 215, 172 }, - { 198, 219 }, - { 53, 235 }, - { 219, 99 }, }, - { { 215, 102 }, - { 199, 248 }, - { 102, 235 }, - { 31, 227 }, }, - { { 223, 169 }, - { 214, 207 }, - { 149, 251 }, - { 243, 107 }, }, - { { 213, 220 }, - { 224, 251 }, - { 59, 171 }, - { 223, 7 }, }, - { { 221, 31 }, - { 241, 221 }, - { 248, 187 }, - { 187, 143 }, }, - { { 223, 240 }, - { 230, 238 }, - { 15, 251 }, - { 119, 103 }, }, - { { 226, 72 }, - { 12, 169 }, - { 18, 71 }, - { 149, 48 }, }, - { { 226, 232 }, - { 14, 171 }, - { 23, 71 }, - { 213, 112 }, }, - { { 226, 7 }, - { 29, 152 }, - { 224, 71 }, - { 25, 184 }, }, - { { 224, 93 }, - { 56, 185 }, - { 186, 7 }, - { 157, 28 }, }, - { { 234, 245 }, - { 62, 190 }, - { 175, 87 }, - { 125, 124 }, }, - { { 235, 38 }, - { 79, 156 }, - { 100, 215 }, - { 57, 242 }, }, - { { 235, 237 }, - { 94, 191 }, - { 183, 215 }, - { 253, 122 }, }, - { { 225, 82 }, - { 105, 168 }, - { 74, 135 }, - { 21, 150 }, }, - { { 225, 126 }, - { 107, 185 }, - { 126, 135 }, - { 157, 214 }, }, - { { 233, 219 }, - { 121, 175 }, - { 219, 151 }, - { 245, 158 }, }, - { { 248, 6 }, - { 137, 156 }, - { 96, 31 }, - { 57, 145 }, }, - { { 240, 238 }, - { 139, 187 }, - { 119, 15 }, - { 221, 209 }, }, - { { 248, 161 }, - { 154, 142 }, - { 133, 31 }, - { 113, 89 }, }, - { { 250, 0 }, - { 140, 140 }, - { 0, 95 }, - { 49, 49 }, }, - { { 250, 194 }, - { 141, 174 }, - { 67, 95 }, - { 117, 177 }, }, - { { 240, 155 }, - { 185, 139 }, - { 217, 15 }, - { 209, 157 }, }, - { { 250, 244 }, - { 174, 190 }, - { 47, 95 }, - { 125, 117 }, }, - { { 250, 60 }, - { 174, 157 }, - { 60, 95 }, - { 185, 117 }, }, - { { 242, 252 }, - { 174, 187 }, - { 63, 79 }, - { 221, 117 }, }, - { { 242, 189 }, - { 190, 155 }, - { 189, 79 }, - { 217, 125 }, }, - { { 242, 147 }, - { 189, 138 }, - { 201, 79 }, - { 81, 189 }, }, - { { 241, 96 }, - { 202, 168 }, - { 6, 143 }, - { 21, 83 }, }, - { { 249, 236 }, - { 202, 191 }, - { 55, 159 }, - { 253, 83 }, }, - { { 241, 70 }, - { 201, 184 }, - { 98, 143 }, - { 29, 147 }, }, - { { 249, 225 }, - { 218, 174 }, - { 135, 159 }, - { 117, 91 }, }, - { { 243, 72 }, - { 204, 169 }, - { 18, 207 }, - { 149, 51 }, }, - { { 243, 174 }, - { 207, 155 }, - { 117, 207 }, - { 217, 243 }, }, - { { 243, 193 }, - { 220, 170 }, - { 131, 207 }, - { 85, 59 }, }, - { { 243, 139 }, - { 221, 139 }, - { 209, 207 }, - { 209, 187 }, }, - { { 243, 167 }, - { 223, 154 }, - { 229, 207 }, - { 89, 251 }, }, - { { 241, 115 }, - { 251, 168 }, - { 206, 143 }, - { 21, 223 }, }, - { { 241, 151 }, - { 249, 154 }, - { 233, 143 }, - { 89, 159 }, }, - { { 243, 244 }, - { 238, 186 }, - { 47, 207 }, - { 93, 119 }, }, - { { 251, 50 }, - { 239, 140 }, - { 76, 223 }, - { 49, 247 }, }, - { { 228, 7 }, - { 25, 216 }, - { 224, 39 }, - { 27, 152 }, }, - { { 230, 77 }, - { 28, 249 }, - { 178, 103 }, - { 159, 56 }, }, - { { 236, 85 }, - { 56, 252 }, - { 170, 55 }, - { 63, 28 }, }, - { { 237, 192 }, - { 72, 238 }, - { 3, 183 }, - { 119, 18 }, }, - { { 237, 133 }, - { 88, 222 }, - { 161, 183 }, - { 123, 26 }, }, - { { 239, 162 }, - { 79, 206 }, - { 69, 247 }, - { 115, 242 }, }, - { { 231, 78 }, - { 77, 249 }, - { 114, 231 }, - { 159, 178 }, }, - { { 229, 213 }, - { 120, 250 }, - { 171, 167 }, - { 95, 30 }, }, - { { 239, 80 }, - { 108, 236 }, - { 10, 247 }, - { 55, 54 }, }, - { { 244, 34 }, - { 139, 200 }, - { 68, 47 }, - { 19, 209 }, }, - { { 244, 137 }, - { 152, 203 }, - { 145, 47 }, - { 211, 25 }, }, - { { 244, 41 }, - { 154, 201 }, - { 148, 47 }, - { 147, 89 }, }, - { { 246, 106 }, - { 143, 233 }, - { 86, 111 }, - { 151, 241 }, }, - { { 254, 11 }, - { 157, 205 }, - { 208, 127 }, - { 179, 185 }, }, - { { 254, 111 }, - { 159, 253 }, - { 246, 127 }, - { 191, 249 }, }, - { { 244, 149 }, - { 184, 218 }, - { 169, 47 }, - { 91, 29 }, }, - { { 244, 53 }, - { 186, 216 }, - { 172, 47 }, - { 27, 93 }, }, - { { 244, 31 }, - { 185, 217 }, - { 248, 47 }, - { 155, 157 }, }, - { { 246, 176 }, - { 174, 202 }, - { 13, 111 }, - { 83, 117 }, }, - { { 245, 232 }, - { 202, 235 }, - { 23, 175 }, - { 215, 83 }, }, - { { 245, 197 }, - { 216, 250 }, - { 163, 175 }, - { 95, 27 }, }, - { { 253, 35 }, - { 219, 204 }, - { 196, 191 }, - { 51, 219 }, }, - { { 255, 192 }, - { 204, 238 }, - { 3, 255 }, - { 119, 51 }, }, - { { 247, 204 }, - { 204, 251 }, - { 51, 239 }, - { 223, 51 }, }, - { { 247, 233 }, - { 222, 235 }, - { 151, 239 }, - { 215, 123 }, }, - { { 245, 188 }, - { 234, 219 }, - { 61, 175 }, - { 219, 87 }, }, - { { 253, 246 }, - { 235, 254 }, - { 111, 191 }, - { 127, 215 }, }, - { { 245, 217 }, - { 248, 235 }, - { 155, 175 }, - { 215, 31 }, }, - { { 253, 151 }, - { 249, 222 }, - { 233, 191 }, - { 123, 159 }, }, - { { 253, 63 }, - { 251, 221 }, - { 252, 191 }, - { 187, 223 }, }, - { { 255, 156 }, - { 236, 223 }, - { 57, 255 }, - { 251, 55 }, }, - { { 255, 90 }, - { 237, 237 }, - { 90, 255 }, - { 183, 183 }, }, - { { 247, 254 }, - { 239, 251 }, - { 127, 239 }, - { 223, 247 }, }, - { { 255, 17 }, - { 252, 204 }, - { 136, 255 }, - { 51, 63 }, }, - { { 247, 191 }, - { 255, 219 }, - { 253, 239 }, - { 219, 255 }, }, }; - -static unsigned char DICT_5X5_1000_BYTES[][4][4] = - { { { 162, 217, 94, 0 }, - { 82, 46, 217, 1 }, - { 61, 77, 162, 1 }, - { 205, 186, 37, 0 }, }, - { { 14, 3, 115, 0 }, - { 176, 198, 133, 0 }, - { 103, 96, 56, 0 }, - { 80, 177, 134, 1 }, }, - { { 215, 135, 110, 1 }, - { 47, 151, 157, 1 }, - { 187, 112, 245, 1 }, - { 220, 244, 250, 0 }, }, - { { 129, 202, 251, 1 }, - { 122, 222, 40, 1 }, - { 239, 169, 192, 1 }, - { 138, 61, 175, 0 }, }, - { { 215, 90, 146, 0 }, - { 116, 27, 236, 0 }, - { 36, 173, 117, 1 }, - { 27, 236, 23, 0 }, }, - { { 234, 4, 22, 1 }, - { 153, 35, 152, 0 }, - { 180, 16, 43, 1 }, - { 12, 226, 76, 1 }, }, - { { 105, 235, 246, 0 }, - { 242, 191, 51, 0 }, - { 55, 235, 203, 0 }, - { 102, 126, 167, 1 }, }, - { { 113, 10, 53, 1 }, - { 60, 249, 16, 0 }, - { 214, 40, 71, 0 }, - { 4, 79, 158, 0 }, }, - { { 134, 176, 153, 0 }, - { 18, 64, 238, 1 }, - { 76, 134, 176, 1 }, - { 187, 129, 36, 0 }, }, - { { 152, 159, 210, 1 }, - { 191, 14, 105, 0 }, - { 165, 252, 140, 1 }, - { 75, 56, 126, 1 }, }, - { { 158, 119, 1, 1 }, - { 237, 64, 207, 0 }, - { 192, 119, 60, 1 }, - { 121, 129, 91, 1 }, }, - { { 209, 109, 96, 0 }, - { 69, 157, 11, 0 }, - { 3, 91, 69, 1 }, - { 104, 92, 209, 0 }, }, - { { 243, 21, 136, 1 }, - { 13, 49, 233, 1 }, - { 136, 212, 103, 1 }, - { 203, 198, 88, 0 }, }, - { { 47, 56, 179, 0 }, - { 144, 250, 230, 0 }, - { 102, 142, 122, 0 }, - { 51, 175, 132, 1 }, }, - { { 254, 126, 84, 0 }, - { 245, 45, 222, 0 }, - { 21, 63, 63, 1 }, - { 61, 218, 87, 1 }, }, - { { 40, 241, 191, 1 }, - { 218, 226, 115, 1 }, - { 254, 199, 138, 0 }, - { 231, 35, 173, 1 }, }, - { { 75, 211, 172, 0 }, - { 226, 145, 241, 1 }, - { 26, 229, 233, 0 }, - { 199, 196, 163, 1 }, }, - { { 95, 81, 55, 1 }, - { 220, 211, 213, 0 }, - { 246, 69, 125, 0 }, - { 85, 229, 157, 1 }, }, - { { 123, 38, 226, 0 }, - { 165, 183, 162, 0 }, - { 35, 178, 111, 0 }, - { 34, 246, 210, 1 }, }, - { { 131, 14, 244, 0 }, - { 49, 156, 184, 0 }, - { 23, 184, 96, 1 }, - { 14, 156, 198, 0 }, }, - { { 150, 237, 58, 1 }, - { 95, 138, 143, 1 }, - { 174, 91, 180, 1 }, - { 248, 168, 253, 0 }, }, - { { 168, 114, 32, 0 }, - { 224, 160, 74, 0 }, - { 2, 39, 10, 1 }, - { 41, 2, 131, 1 }, }, - { { 181, 134, 80, 1 }, - { 63, 52, 12, 0 }, - { 133, 48, 214, 1 }, - { 24, 22, 126, 0 }, }, - { { 93, 9, 111, 0 }, - { 132, 223, 21, 1 }, - { 123, 72, 93, 0 }, - { 212, 125, 144, 1 }, }, - { { 206, 104, 17, 1 }, - { 216, 73, 142, 0 }, - { 196, 11, 57, 1 }, - { 56, 201, 13, 1 }, }, - { { 210, 204, 185, 0 }, - { 87, 201, 168, 1 }, - { 78, 153, 165, 1 }, - { 138, 201, 245, 0 }, }, - { { 225, 231, 69, 1 }, - { 107, 117, 27, 0 }, - { 209, 115, 195, 1 }, - { 108, 87, 107, 0 }, }, - { { 17, 33, 35, 0 }, - { 4, 210, 3, 0 }, - { 98, 66, 68, 0 }, - { 96, 37, 144, 0 }, }, - { { 29, 203, 57, 0 }, - { 246, 216, 5, 1 }, - { 78, 105, 220, 0 }, - { 208, 13, 183, 1 }, }, - { { 18, 17, 29, 1 }, - { 28, 64, 209, 1 }, - { 220, 68, 36, 0 }, - { 197, 129, 28, 0 }, }, - { { 19, 155, 183, 0 }, - { 54, 218, 241, 0 }, - { 118, 236, 228, 0 }, - { 71, 173, 182, 0 }, }, - { { 27, 68, 57, 1 }, - { 221, 208, 128, 1 }, - { 206, 17, 108, 0 }, - { 128, 133, 221, 1 }, }, - { { 32, 104, 103, 0 }, - { 64, 238, 18, 0 }, - { 115, 11, 2, 0 }, - { 36, 59, 129, 0 }, }, - { { 37, 85, 100, 0 }, - { 65, 180, 85, 0 }, - { 19, 85, 82, 0 }, - { 85, 22, 193, 0 }, }, - { { 35, 33, 221, 0 }, - { 16, 116, 179, 1 }, - { 93, 194, 98, 0 }, - { 230, 151, 4, 0 }, }, - { { 61, 55, 245, 0 }, - { 181, 244, 119, 0 }, - { 87, 246, 94, 0 }, - { 119, 23, 214, 1 }, }, - { { 76, 197, 86, 0 }, - { 211, 7, 21, 0 }, - { 53, 81, 153, 0 }, - { 84, 112, 101, 1 }, }, - { { 65, 104, 128, 1 }, - { 72, 25, 34, 0 }, - { 128, 139, 65, 0 }, - { 34, 76, 9, 0 }, }, - { { 77, 86, 142, 1 }, - { 233, 19, 116, 1 }, - { 184, 181, 89, 0 }, - { 151, 100, 75, 1 }, }, - { { 67, 30, 57, 0 }, - { 49, 217, 192, 1 }, - { 78, 60, 97, 0 }, - { 129, 205, 198, 0 }, }, - { { 86, 148, 18, 1 }, - { 31, 3, 196, 0 }, - { 164, 20, 181, 0 }, - { 17, 224, 124, 0 }, }, - { { 82, 151, 207, 0 }, - { 39, 71, 241, 1 }, - { 121, 244, 165, 0 }, - { 199, 241, 114, 0 }, }, - { { 108, 36, 251, 1 }, - { 153, 231, 38, 1 }, - { 239, 146, 27, 0 }, - { 178, 115, 204, 1 }, }, - { { 97, 132, 236, 1 }, - { 11, 181, 48, 1 }, - { 155, 144, 195, 0 }, - { 134, 86, 232, 0 }, }, - { { 109, 63, 24, 1 }, - { 185, 57, 71, 1 }, - { 140, 126, 91, 0 }, - { 241, 78, 78, 1 }, }, - { { 116, 177, 61, 0 }, - { 22, 225, 87, 1 }, - { 94, 70, 151, 0 }, - { 245, 67, 180, 0 }, }, - { { 116, 220, 203, 1 }, - { 79, 111, 100, 1 }, - { 233, 157, 151, 0 }, - { 147, 123, 121, 0 }, }, - { { 124, 164, 3, 0 }, - { 135, 99, 6, 0 }, - { 96, 18, 159, 0 }, - { 48, 99, 112, 1 }, }, - { { 122, 200, 146, 1 }, - { 222, 43, 160, 0 }, - { 164, 137, 175, 0 }, - { 2, 234, 61, 1 }, }, - { { 123, 91, 235, 1 }, - { 236, 255, 225, 1 }, - { 235, 237, 111, 0 }, - { 195, 255, 155, 1 }, }, - { { 141, 172, 114, 0 }, - { 147, 158, 14, 0 }, - { 39, 26, 216, 1 }, - { 56, 60, 228, 1 }, }, - { { 141, 105, 60, 1 }, - { 216, 152, 31, 1 }, - { 158, 75, 88, 1 }, - { 252, 12, 141, 1 }, }, - { { 143, 28, 5, 1 }, - { 137, 88, 220, 0 }, - { 208, 28, 120, 1 }, - { 29, 141, 72, 1 }, }, - { { 139, 74, 34, 1 }, - { 232, 154, 136, 0 }, - { 162, 41, 104, 1 }, - { 8, 172, 139, 1 }, }, - { { 151, 253, 165, 0 }, - { 71, 216, 255, 0 }, - { 82, 223, 244, 1 }, - { 127, 141, 241, 0 }, }, - { { 172, 101, 198, 1 }, - { 201, 38, 63, 0 }, - { 177, 211, 26, 1 }, - { 126, 50, 73, 1 }, }, - { { 172, 195, 248, 0 }, - { 242, 164, 45, 1 }, - { 15, 225, 154, 1 }, - { 218, 18, 167, 1 }, }, - { { 161, 23, 239, 1 }, - { 41, 246, 121, 1 }, - { 251, 244, 66, 1 }, - { 207, 55, 202, 0 }, }, - { { 167, 9, 19, 1 }, - { 24, 122, 141, 0 }, - { 228, 72, 114, 1 }, - { 88, 175, 12, 0 }, }, - { { 171, 111, 145, 0 }, - { 241, 120, 171, 0 }, - { 68, 251, 106, 1 }, - { 106, 143, 71, 1 }, }, - { { 185, 237, 248, 1 }, - { 223, 188, 43, 1 }, - { 143, 219, 206, 1 }, - { 234, 30, 253, 1 }, }, - { { 178, 100, 158, 0 }, - { 85, 34, 186, 1 }, - { 60, 147, 38, 1 }, - { 174, 162, 85, 0 }, }, - { { 190, 93, 195, 0 }, - { 197, 110, 237, 0 }, - { 97, 221, 62, 1 }, - { 91, 187, 81, 1 }, }, - { { 196, 5, 67, 1 }, - { 9, 71, 13, 0 }, - { 225, 80, 17, 1 }, - { 88, 113, 72, 0 }, }, - { { 200, 163, 238, 1 }, - { 170, 135, 59, 1 }, - { 187, 226, 137, 1 }, - { 238, 112, 170, 1 }, }, - { { 194, 117, 197, 0 }, - { 65, 69, 251, 0 }, - { 81, 215, 33, 1 }, - { 111, 209, 65, 0 }, }, - { { 198, 194, 214, 1 }, - { 122, 7, 188, 0 }, - { 181, 161, 177, 1 }, - { 30, 240, 47, 0 }, }, - { { 217, 102, 212, 1 }, - { 253, 21, 58, 0 }, - { 149, 179, 77, 1 }, - { 46, 84, 95, 1 }, }, - { { 221, 94, 185, 1 }, - { 253, 217, 108, 1 }, - { 206, 189, 93, 1 }, - { 155, 77, 223, 1 }, }, - { { 244, 234, 25, 0 }, - { 118, 105, 14, 1 }, - { 76, 43, 151, 1 }, - { 184, 75, 55, 0 }, }, - { { 243, 178, 148, 0 }, - { 54, 49, 250, 0 }, - { 20, 166, 231, 1 }, - { 47, 198, 54, 0 }, }, - { { 122, 186, 5, 0 }, - { 166, 105, 210, 0 }, - { 80, 46, 175, 0 }, - { 37, 203, 50, 1 }, }, - { { 216, 141, 41, 1 }, - { 143, 201, 9, 1 }, - { 202, 88, 141, 1 }, - { 200, 73, 248, 1 }, }, - { { 12, 103, 50, 1 }, - { 249, 130, 7, 0 }, - { 166, 115, 24, 0 }, - { 112, 32, 207, 1 }, }, - { { 21, 89, 12, 1 }, - { 76, 24, 85, 1 }, - { 152, 77, 84, 0 }, - { 213, 12, 25, 0 }, }, - { { 76, 116, 192, 1 }, - { 201, 5, 102, 0 }, - { 129, 151, 25, 0 }, - { 51, 80, 73, 1 }, }, - { { 84, 3, 14, 0 }, - { 36, 3, 21, 1 }, - { 56, 96, 21, 0 }, - { 212, 96, 18, 0 }, }, - { { 160, 208, 172, 0 }, - { 66, 160, 120, 1 }, - { 26, 133, 130, 1 }, - { 143, 2, 161, 0 }, }, - { { 194, 152, 166, 0 }, - { 2, 139, 248, 0 }, - { 50, 140, 161, 1 }, - { 15, 232, 160, 0 }, }, - { { 203, 104, 150, 0 }, - { 208, 27, 186, 0 }, - { 52, 139, 105, 1 }, - { 46, 236, 5, 1 }, }, - { { 253, 105, 209, 0 }, - { 212, 125, 47, 0 }, - { 69, 203, 95, 1 }, - { 122, 95, 21, 1 }, }, - { { 4, 145, 90, 1 }, - { 26, 6, 69, 1 }, - { 173, 68, 144, 0 }, - { 209, 48, 44, 0 }, }, - { { 12, 222, 112, 0 }, - { 243, 140, 68, 0 }, - { 7, 61, 152, 0 }, - { 17, 24, 231, 1 }, }, - { { 5, 170, 62, 0 }, - { 50, 154, 22, 1 }, - { 62, 42, 208, 0 }, - { 180, 44, 166, 0 }, }, - { { 1, 99, 183, 1 }, - { 120, 210, 51, 0 }, - { 246, 227, 64, 0 }, - { 102, 37, 143, 0 }, }, - { { 9, 145, 68, 1 }, - { 138, 20, 81, 0 }, - { 145, 68, 200, 0 }, - { 69, 20, 40, 1 }, }, - { { 9, 105, 83, 1 }, - { 216, 94, 3, 0 }, - { 229, 75, 72, 0 }, - { 96, 61, 13, 1 }, }, - { { 6, 37, 161, 1 }, - { 9, 192, 167, 0 }, - { 194, 210, 48, 0 }, - { 114, 129, 200, 0 }, }, - { { 3, 61, 226, 1 }, - { 9, 158, 227, 0 }, - { 163, 222, 96, 0 }, - { 99, 188, 200, 0 }, }, - { { 7, 213, 6, 1 }, - { 75, 18, 213, 0 }, - { 176, 85, 240, 0 }, - { 85, 164, 105, 0 }, }, - { { 15, 143, 170, 0 }, - { 163, 154, 165, 1 }, - { 42, 248, 248, 0 }, - { 210, 172, 226, 1 }, }, - { { 28, 116, 60, 1 }, - { 221, 128, 86, 1 }, - { 158, 23, 28, 0 }, - { 181, 0, 221, 1 }, }, - { { 25, 29, 145, 1 }, - { 157, 88, 97, 0 }, - { 196, 220, 76, 0 }, - { 67, 13, 92, 1 }, }, - { { 22, 27, 35, 1 }, - { 44, 202, 197, 0 }, - { 226, 108, 52, 0 }, - { 81, 169, 154, 0 }, }, - { { 22, 210, 141, 1 }, - { 110, 64, 244, 1 }, - { 216, 165, 180, 0 }, - { 151, 129, 59, 0 }, }, - { { 23, 78, 198, 1 }, - { 109, 30, 180, 0 }, - { 177, 185, 116, 0 }, - { 22, 188, 91, 0 }, }, - { { 19, 226, 177, 0 }, - { 118, 208, 162, 0 }, - { 70, 163, 228, 0 }, - { 34, 133, 183, 0 }, }, - { { 31, 126, 250, 1 }, - { 253, 158, 230, 1 }, - { 175, 191, 124, 0 }, - { 179, 188, 223, 1 }, }, - { { 41, 15, 112, 0 }, - { 177, 188, 1, 0 }, - { 7, 120, 74, 0 }, - { 64, 30, 198, 1 }, }, - { { 34, 71, 126, 1 }, - { 121, 166, 145, 1 }, - { 191, 113, 34, 0 }, - { 196, 178, 207, 0 }, }, - { { 42, 23, 192, 1 }, - { 169, 36, 225, 0 }, - { 129, 244, 42, 0 }, - { 67, 146, 74, 1 }, }, - { { 42, 251, 100, 1 }, - { 234, 172, 211, 0 }, - { 147, 111, 170, 0 }, - { 101, 154, 171, 1 }, }, - { { 35, 240, 4, 0 }, - { 66, 48, 210, 0 }, - { 16, 7, 226, 0 }, - { 37, 134, 33, 0 }, }, - { { 39, 205, 252, 0 }, - { 83, 188, 181, 1 }, - { 31, 217, 242, 0 }, - { 214, 158, 229, 0 }, }, - { { 35, 106, 172, 0 }, - { 96, 184, 178, 1 }, - { 26, 171, 98, 0 }, - { 166, 142, 131, 0 }, }, - { { 47, 123, 47, 0 }, - { 224, 250, 215, 1 }, - { 122, 111, 122, 0 }, - { 245, 175, 131, 1 }, }, - { { 52, 144, 196, 0 }, - { 6, 36, 116, 0 }, - { 17, 132, 150, 0 }, - { 23, 18, 48, 0 }, }, - { { 48, 9, 214, 1 }, - { 28, 46, 49, 0 }, - { 181, 200, 6, 0 }, - { 70, 58, 28, 0 }, }, - { { 52, 94, 16, 1 }, - { 125, 40, 68, 0 }, - { 132, 61, 22, 0 }, - { 17, 10, 95, 0 }, }, - { { 57, 82, 232, 0 }, - { 228, 180, 96, 1 }, - { 11, 165, 78, 0 }, - { 131, 22, 147, 1 }, }, - { { 50, 0, 113, 0 }, - { 20, 228, 128, 0 }, - { 71, 0, 38, 0 }, - { 0, 147, 148, 0 }, }, - { { 54, 231, 29, 0 }, - { 119, 96, 151, 1 }, - { 92, 115, 182, 0 }, - { 244, 131, 119, 0 }, }, - { { 68, 138, 4, 1 }, - { 42, 9, 20, 0 }, - { 144, 40, 145, 0 }, - { 20, 72, 42, 0 }, }, - { { 68, 236, 254, 1 }, - { 91, 143, 54, 1 }, - { 191, 155, 145, 0 }, - { 182, 120, 237, 0 }, }, - { { 69, 31, 114, 1 }, - { 57, 159, 69, 0 }, - { 167, 124, 81, 0 }, - { 81, 124, 206, 0 }, }, - { { 69, 74, 149, 0 }, - { 112, 89, 52, 0 }, - { 84, 169, 81, 0 }, - { 22, 77, 7, 0 }, }, - { { 70, 19, 190, 1 }, - { 56, 131, 245, 1 }, - { 190, 228, 49, 0 }, - { 215, 224, 142, 0 }, }, - { { 78, 131, 9, 0 }, - { 162, 65, 133, 1 }, - { 72, 96, 185, 0 }, - { 208, 193, 34, 1 }, }, - { { 71, 114, 153, 1 }, - { 120, 81, 230, 1 }, - { 204, 167, 113, 0 }, - { 179, 197, 15, 0 }, }, - { { 79, 130, 125, 1 }, - { 186, 213, 148, 1 }, - { 223, 32, 249, 0 }, - { 148, 213, 174, 1 }, }, - { { 92, 55, 141, 1 }, - { 173, 65, 119, 1 }, - { 216, 246, 29, 0 }, - { 247, 65, 90, 1 }, }, - { { 88, 253, 119, 0 }, - { 215, 207, 83, 0 }, - { 119, 95, 141, 0 }, - { 101, 121, 245, 1 }, }, - { { 81, 183, 248, 0 }, - { 55, 149, 99, 1 }, - { 15, 246, 197, 0 }, - { 227, 84, 246, 0 }, }, - { { 89, 58, 251, 0 }, - { 180, 223, 98, 1 }, - { 111, 174, 77, 0 }, - { 163, 125, 150, 1 }, }, - { { 90, 153, 153, 0 }, - { 150, 73, 225, 1 }, - { 76, 204, 173, 0 }, - { 195, 201, 52, 1 }, }, - { { 83, 1, 240, 1 }, - { 28, 149, 161, 0 }, - { 135, 192, 101, 0 }, - { 66, 212, 156, 0 }, }, - { { 83, 204, 103, 1 }, - { 79, 223, 144, 0 }, - { 243, 25, 229, 0 }, - { 4, 253, 249, 0 }, }, - { { 83, 110, 1, 0 }, - { 101, 89, 130, 0 }, - { 64, 59, 101, 0 }, - { 32, 205, 83, 0 }, }, - { { 91, 37, 175, 1 }, - { 141, 211, 179, 1 }, - { 250, 210, 109, 0 }, - { 230, 229, 216, 1 }, }, - { { 95, 213, 204, 1 }, - { 207, 21, 245, 1 }, - { 153, 213, 253, 0 }, - { 215, 212, 121, 1 }, }, - { { 101, 102, 66, 1 }, - { 105, 55, 6, 0 }, - { 161, 51, 83, 0 }, - { 48, 118, 75, 0 }, }, - { { 101, 199, 175, 0 }, - { 99, 243, 53, 1 }, - { 122, 241, 211, 0 }, - { 214, 103, 227, 0 }, }, - { { 102, 55, 81, 0 }, - { 49, 101, 199, 0 }, - { 69, 118, 51, 0 }, - { 113, 211, 70, 0 }, }, - { { 103, 12, 197, 1 }, - { 9, 125, 180, 0 }, - { 209, 152, 115, 0 }, - { 22, 223, 72, 0 }, }, - { { 112, 150, 93, 1 }, - { 63, 101, 80, 1 }, - { 221, 52, 135, 0 }, - { 133, 83, 126, 0 }, }, - { { 124, 99, 128, 1 }, - { 236, 33, 39, 0 }, - { 128, 227, 31, 0 }, - { 114, 66, 27, 1 }, }, - { { 121, 171, 169, 0 }, - { 166, 249, 35, 1 }, - { 74, 234, 207, 0 }, - { 226, 79, 178, 1 }, }, - { { 114, 61, 70, 0 }, - { 5, 47, 211, 0 }, - { 49, 94, 39, 0 }, - { 101, 250, 80, 0 }, }, - { { 115, 229, 178, 1 }, - { 95, 179, 163, 0 }, - { 166, 211, 231, 0 }, - { 98, 230, 253, 0 }, }, - { { 132, 38, 140, 0 }, - { 33, 0, 62, 1 }, - { 24, 178, 16, 1 }, - { 190, 0, 66, 0 }, }, - { { 137, 241, 1, 0 }, - { 194, 80, 75, 0 }, - { 64, 71, 200, 1 }, - { 105, 5, 33, 1 }, }, - { { 134, 174, 233, 1 }, - { 43, 204, 174, 1 }, - { 203, 186, 176, 1 }, - { 186, 153, 234, 0 }, }, - { { 138, 35, 249, 1 }, - { 184, 196, 171, 1 }, - { 207, 226, 40, 1 }, - { 234, 145, 142, 1 }, }, - { { 148, 53, 113, 1 }, - { 29, 196, 79, 0 }, - { 199, 86, 20, 1 }, - { 121, 17, 220, 0 }, }, - { { 156, 69, 27, 0 }, - { 213, 66, 13, 1 }, - { 108, 81, 28, 1 }, - { 216, 33, 85, 1 }, }, - { { 149, 31, 164, 1 }, - { 45, 152, 125, 0 }, - { 146, 252, 84, 1 }, - { 95, 12, 218, 0 }, }, - { { 150, 141, 144, 0 }, - { 23, 8, 173, 0 }, - { 4, 216, 180, 1 }, - { 90, 136, 116, 0 }, }, - { { 151, 38, 183, 0 }, - { 53, 210, 190, 0 }, - { 118, 178, 116, 1 }, - { 62, 165, 214, 0 }, }, - { { 155, 55, 103, 0 }, - { 165, 214, 219, 0 }, - { 115, 118, 108, 1 }, - { 109, 181, 210, 1 }, }, - { { 155, 198, 224, 1 }, - { 239, 148, 168, 0 }, - { 131, 177, 236, 1 }, - { 10, 148, 251, 1 }, }, - { { 160, 154, 110, 1 }, - { 42, 174, 88, 1 }, - { 187, 44, 130, 1 }, - { 141, 58, 170, 0 }, }, - { { 164, 82, 134, 1 }, - { 104, 34, 124, 0 }, - { 176, 165, 18, 1 }, - { 31, 34, 11, 0 }, }, - { { 168, 176, 133, 1 }, - { 138, 96, 122, 0 }, - { 208, 134, 138, 1 }, - { 47, 3, 40, 1 }, }, - { { 173, 155, 66, 0 }, - { 162, 62, 77, 0 }, - { 33, 108, 218, 1 }, - { 89, 62, 34, 1 }, }, - { { 175, 240, 88, 1 }, - { 218, 52, 206, 1 }, - { 141, 7, 250, 1 }, - { 185, 150, 45, 1 }, }, - { { 176, 46, 99, 1 }, - { 45, 238, 10, 0 }, - { 227, 58, 6, 1 }, - { 40, 59, 218, 0 }, }, - { { 176, 15, 24, 0 }, - { 53, 40, 9, 1 }, - { 12, 120, 6, 1 }, - { 200, 10, 86, 0 }, }, - { { 188, 234, 178, 1 }, - { 254, 170, 46, 0 }, - { 166, 171, 158, 1 }, - { 58, 42, 191, 1 }, }, - { { 190, 196, 76, 1 }, - { 207, 36, 156, 1 }, - { 153, 17, 190, 1 }, - { 156, 146, 121, 1 }, }, - { { 179, 130, 250, 0 }, - { 54, 182, 168, 1 }, - { 47, 160, 230, 1 }, - { 138, 182, 182, 0 }, }, - { { 179, 88, 60, 1 }, - { 92, 184, 216, 1 }, - { 158, 13, 102, 1 }, - { 141, 142, 157, 0 }, }, - { { 191, 69, 238, 0 }, - { 197, 182, 189, 1 }, - { 59, 209, 126, 1 }, - { 222, 182, 209, 1 }, }, - { { 191, 86, 51, 1 }, - { 253, 242, 204, 0 }, - { 230, 53, 126, 1 }, - { 25, 167, 223, 1 }, }, - { { 196, 58, 240, 0 }, - { 48, 141, 110, 0 }, - { 7, 174, 17, 1 }, - { 59, 88, 134, 0 }, }, - { { 204, 233, 131, 0 }, - { 194, 75, 47, 0 }, - { 96, 203, 153, 1 }, - { 122, 105, 33, 1 }, }, - { { 197, 51, 0, 1 }, - { 40, 17, 79, 0 }, - { 128, 102, 81, 1 }, - { 121, 68, 10, 0 }, }, - { { 205, 34, 99, 1 }, - { 168, 215, 14, 0 }, - { 227, 34, 89, 1 }, - { 56, 117, 138, 1 }, }, - { { 198, 8, 138, 1 }, - { 8, 11, 172, 1 }, - { 168, 136, 49, 1 }, - { 154, 232, 8, 0 }, }, - { { 198, 148, 63, 0 }, - { 19, 195, 220, 1 }, - { 126, 20, 177, 1 }, - { 157, 225, 228, 0 }, }, - { { 202, 238, 132, 1 }, - { 235, 9, 186, 0 }, - { 144, 187, 169, 1 }, - { 46, 200, 107, 1 }, }, - { { 207, 167, 18, 1 }, - { 187, 19, 143, 0 }, - { 164, 114, 249, 1 }, - { 120, 228, 110, 1 }, }, - { { 203, 97, 226, 1 }, - { 200, 151, 171, 0 }, - { 163, 195, 105, 1 }, - { 106, 244, 137, 1 }, }, - { { 208, 2, 233, 0 }, - { 36, 197, 40, 1 }, - { 75, 160, 5, 1 }, - { 138, 81, 146, 0 }, }, - { { 220, 183, 70, 0 }, - { 167, 7, 95, 0 }, - { 49, 118, 157, 1 }, - { 125, 112, 114, 1 }, }, - { { 217, 139, 132, 1 }, - { 174, 25, 57, 0 }, - { 144, 232, 205, 1 }, - { 78, 76, 58, 1 }, }, - { { 217, 206, 178, 0 }, - { 247, 155, 40, 0 }, - { 38, 185, 205, 1 }, - { 10, 108, 247, 1 }, }, - { { 210, 153, 64, 1 }, - { 14, 13, 201, 0 }, - { 129, 76, 165, 1 }, - { 73, 216, 56, 0 }, }, - { { 210, 209, 23, 0 }, - { 86, 67, 217, 0 }, - { 116, 69, 165, 1 }, - { 77, 225, 53, 0 }, }, - { { 222, 90, 110, 1 }, - { 236, 143, 220, 1 }, - { 187, 45, 61, 1 }, - { 157, 248, 155, 1 }, }, - { { 218, 71, 66, 1 }, - { 237, 7, 137, 0 }, - { 161, 113, 45, 1 }, - { 72, 240, 91, 1 }, }, - { { 219, 60, 16, 0 }, - { 149, 25, 202, 0 }, - { 4, 30, 109, 1 }, - { 41, 204, 84, 1 }, }, - { { 219, 143, 201, 0 }, - { 167, 93, 169, 1 }, - { 73, 248, 237, 1 }, - { 202, 221, 114, 1 }, }, - { { 232, 24, 227, 1 }, - { 136, 239, 104, 0 }, - { 227, 140, 11, 1 }, - { 11, 123, 136, 1 }, }, - { { 229, 28, 111, 0 }, - { 1, 255, 92, 1 }, - { 123, 28, 83, 1 }, - { 157, 127, 192, 0 }, }, - { { 225, 174, 56, 1 }, - { 59, 185, 10, 1 }, - { 142, 58, 195, 1 }, - { 168, 78, 238, 0 }, }, - { { 237, 185, 123, 1 }, - { 154, 255, 79, 1 }, - { 239, 78, 219, 1 }, - { 249, 127, 172, 1 }, }, - { { 233, 224, 50, 0 }, - { 210, 179, 10, 0 }, - { 38, 3, 203, 1 }, - { 40, 102, 165, 1 }, }, - { { 235, 93, 12, 0 }, - { 193, 57, 217, 1 }, - { 24, 93, 107, 1 }, - { 205, 206, 65, 1 }, }, - { { 239, 249, 157, 0 }, - { 210, 121, 255, 1 }, - { 92, 207, 251, 1 }, - { 255, 207, 37, 1 }, }, - { { 248, 17, 1, 0 }, - { 132, 97, 73, 0 }, - { 64, 68, 15, 1 }, - { 73, 67, 16, 1 }, }, - { { 248, 7, 211, 0 }, - { 181, 103, 41, 0 }, - { 101, 240, 15, 1 }, - { 74, 115, 86, 1 }, }, - { { 246, 2, 32, 1 }, - { 44, 161, 140, 0 }, - { 130, 32, 55, 1 }, - { 24, 194, 154, 0 }, }, - { { 246, 27, 95, 1 }, - { 60, 111, 221, 1 }, - { 253, 108, 55, 1 }, - { 221, 251, 30, 0 }, }, - { { 254, 181, 237, 0 }, - { 135, 229, 255, 1 }, - { 91, 214, 191, 1 }, - { 255, 211, 240, 1 }, }, - { { 250, 51, 56, 1 }, - { 188, 161, 203, 1 }, - { 142, 102, 47, 1 }, - { 233, 194, 158, 1 }, }, - { { 250, 74, 193, 1 }, - { 236, 109, 168, 0 }, - { 193, 169, 47, 1 }, - { 10, 219, 27, 1 }, }, - { { 247, 47, 112, 1 }, - { 61, 189, 143, 0 }, - { 135, 122, 119, 1 }, - { 120, 222, 222, 0 }, }, - { { 247, 234, 252, 1 }, - { 126, 189, 190, 1 }, - { 159, 171, 247, 1 }, - { 190, 222, 191, 0 }, }, - { { 255, 24, 148, 1 }, - { 156, 57, 252, 0 }, - { 148, 140, 127, 1 }, - { 31, 206, 28, 1 }, }, - { { 251, 163, 94, 0 }, - { 182, 55, 155, 1 }, - { 61, 98, 239, 1 }, - { 236, 246, 54, 1 }, }, - { { 104, 184, 47, 0 }, - { 130, 235, 82, 1 }, - { 122, 14, 139, 0 }, - { 165, 107, 160, 1 }, }, - { { 153, 15, 11, 1 }, - { 173, 90, 9, 1 }, - { 232, 120, 76, 1 }, - { 200, 45, 90, 1 }, }, - { { 153, 216, 38, 1 }, - { 206, 154, 88, 0 }, - { 178, 13, 204, 1 }, - { 13, 44, 185, 1 }, }, - { { 228, 95, 14, 1 }, - { 105, 43, 93, 1 }, - { 184, 125, 19, 1 }, - { 221, 106, 75, 0 }, }, - { { 29, 16, 110, 1 }, - { 140, 150, 84, 1 }, - { 187, 4, 92, 0 }, - { 149, 52, 152, 1 }, }, - { { 42, 193, 48, 1 }, - { 218, 160, 129, 0 }, - { 134, 65, 170, 0 }, - { 64, 130, 173, 1 }, }, - { { 52, 65, 99, 1 }, - { 76, 230, 5, 0 }, - { 227, 65, 22, 0 }, - { 80, 51, 153, 0 }, }, - { { 55, 192, 116, 1 }, - { 94, 180, 148, 0 }, - { 151, 1, 246, 0 }, - { 20, 150, 189, 0 }, }, - { { 63, 53, 203, 1 }, - { 141, 118, 231, 1 }, - { 233, 214, 126, 0 }, - { 243, 183, 88, 1 }, }, - { { 86, 160, 76, 0 }, - { 6, 5, 150, 1 }, - { 25, 2, 181, 0 }, - { 180, 208, 48, 0 }, }, - { { 87, 56, 57, 1 }, - { 28, 217, 198, 1 }, - { 206, 14, 117, 0 }, - { 177, 205, 156, 0 }, }, - { { 102, 152, 184, 0 }, - { 18, 169, 228, 1 }, - { 14, 140, 179, 0 }, - { 147, 202, 164, 0 }, }, - { { 115, 165, 23, 0 }, - { 23, 115, 147, 0 }, - { 116, 82, 231, 0 }, - { 100, 231, 116, 0 }, }, - { { 127, 44, 253, 1 }, - { 157, 253, 182, 1 }, - { 223, 154, 127, 0 }, - { 182, 223, 220, 1 }, }, - { { 139, 71, 233, 0 }, - { 225, 212, 169, 1 }, - { 75, 241, 104, 1 }, - { 202, 149, 195, 1 }, }, - { { 165, 195, 151, 0 }, - { 114, 114, 61, 0 }, - { 116, 225, 210, 1 }, - { 94, 39, 39, 0 }, }, - { { 169, 169, 235, 0 }, - { 130, 254, 43, 1 }, - { 107, 202, 202, 1 }, - { 234, 63, 160, 1 }, }, - { { 181, 25, 183, 0 }, - { 20, 250, 125, 0 }, - { 118, 204, 86, 1 }, - { 95, 47, 148, 0 }, }, - { { 178, 218, 153, 1 }, - { 126, 104, 232, 1 }, - { 204, 173, 166, 1 }, - { 139, 139, 63, 0 }, }, - { { 196, 193, 244, 0 }, - { 82, 133, 61, 0 }, - { 23, 193, 145, 1 }, - { 94, 80, 165, 0 }, }, - { { 202, 185, 30, 0 }, - { 146, 11, 219, 1 }, - { 60, 78, 169, 1 }, - { 237, 232, 36, 1 }, }, - { { 216, 111, 163, 1 }, - { 237, 203, 43, 0 }, - { 226, 251, 13, 1 }, - { 106, 105, 219, 1 }, }, - { { 223, 141, 142, 0 }, - { 135, 27, 189, 1 }, - { 56, 216, 253, 1 }, - { 222, 236, 112, 1 }, }, - { { 229, 102, 143, 1 }, - { 105, 115, 62, 1 }, - { 248, 179, 83, 1 }, - { 190, 103, 75, 0 }, }, - { { 237, 71, 26, 1 }, - { 249, 51, 13, 1 }, - { 172, 113, 91, 1 }, - { 216, 102, 79, 1 }, }, - { { 240, 103, 134, 1 }, - { 109, 35, 59, 0 }, - { 176, 243, 7, 1 }, - { 110, 98, 91, 0 }, }, - { { 4, 41, 238, 1 }, - { 8, 142, 55, 1 }, - { 187, 202, 16, 0 }, - { 246, 56, 136, 0 }, }, - { { 0, 35, 71, 1 }, - { 40, 70, 19, 0 }, - { 241, 98, 0, 0 }, - { 100, 49, 10, 0 }, }, - { { 0, 162, 251, 0 }, - { 50, 198, 34, 1 }, - { 111, 162, 128, 0 }, - { 162, 49, 166, 0 }, }, - { { 4, 200, 206, 0 }, - { 66, 14, 52, 1 }, - { 57, 137, 144, 0 }, - { 150, 56, 33, 0 }, }, - { { 0, 210, 225, 1 }, - { 106, 196, 96, 0 }, - { 195, 165, 128, 0 }, - { 3, 17, 171, 0 }, }, - { { 12, 10, 15, 0 }, - { 160, 74, 20, 1 }, - { 120, 40, 24, 0 }, - { 148, 41, 2, 1 }, }, - { { 8, 139, 198, 0 }, - { 162, 14, 49, 0 }, - { 49, 232, 136, 0 }, - { 70, 56, 34, 1 }, }, - { { 12, 134, 91, 0 }, - { 179, 70, 4, 1 }, - { 109, 48, 152, 0 }, - { 144, 49, 102, 1 }, }, - { { 5, 129, 253, 0 }, - { 18, 212, 53, 1 }, - { 95, 192, 208, 0 }, - { 214, 21, 164, 0 }, }, - { { 1, 113, 30, 0 }, - { 80, 18, 83, 1 }, - { 60, 71, 64, 0 }, - { 229, 36, 5, 0 }, }, - { { 1, 194, 21, 1 }, - { 122, 80, 16, 0 }, - { 212, 33, 192, 0 }, - { 4, 5, 47, 0 }, }, - { { 1, 231, 113, 0 }, - { 115, 212, 3, 0 }, - { 71, 115, 192, 0 }, - { 96, 21, 231, 0 }, }, - { { 9, 41, 191, 0 }, - { 144, 218, 51, 1 }, - { 126, 202, 72, 0 }, - { 230, 45, 132, 1 }, }, - { { 13, 16, 27, 1 }, - { 152, 82, 68, 1 }, - { 236, 4, 88, 0 }, - { 145, 37, 12, 1 }, }, - { { 13, 5, 24, 0 }, - { 145, 16, 5, 1 }, - { 12, 80, 88, 0 }, - { 208, 4, 68, 1 }, }, - { { 13, 237, 47, 1 }, - { 203, 218, 23, 1 }, - { 250, 91, 216, 0 }, - { 244, 45, 233, 1 }, }, - { { 13, 102, 222, 0 }, - { 241, 22, 54, 1 }, - { 61, 179, 88, 0 }, - { 182, 52, 71, 1 }, }, - { { 9, 242, 118, 0 }, - { 242, 150, 82, 0 }, - { 55, 39, 200, 0 }, - { 37, 52, 167, 1 }, }, - { { 2, 208, 130, 1 }, - { 74, 2, 224, 0 }, - { 160, 133, 160, 0 }, - { 3, 160, 41, 0 }, }, - { { 2, 98, 201, 0 }, - { 96, 68, 162, 1 }, - { 73, 163, 32, 0 }, - { 162, 145, 3, 0 }, }, - { { 6, 243, 169, 0 }, - { 98, 192, 231, 1 }, - { 74, 231, 176, 0 }, - { 243, 129, 163, 0 }, }, - { { 6, 239, 35, 0 }, - { 99, 202, 135, 0 }, - { 98, 123, 176, 0 }, - { 112, 169, 227, 0 }, }, - { { 14, 62, 18, 0 }, - { 177, 10, 198, 0 }, - { 36, 62, 56, 0 }, - { 49, 168, 70, 1 }, }, - { { 10, 154, 221, 1 }, - { 186, 76, 240, 1 }, - { 221, 172, 168, 0 }, - { 135, 153, 46, 1 }, }, - { { 10, 97, 109, 1 }, - { 200, 196, 147, 1 }, - { 219, 67, 40, 0 }, - { 228, 145, 137, 1 }, }, - { { 10, 255, 81, 0 }, - { 243, 76, 195, 0 }, - { 69, 127, 168, 0 }, - { 97, 153, 103, 1 }, }, - { { 7, 230, 114, 1 }, - { 123, 150, 134, 0 }, - { 167, 51, 240, 0 }, - { 48, 180, 239, 0 }, }, - { { 11, 154, 1, 0 }, - { 162, 88, 192, 0 }, - { 64, 44, 232, 0 }, - { 1, 141, 34, 1 }, }, - { { 15, 208, 142, 0 }, - { 194, 18, 244, 1 }, - { 56, 133, 248, 0 }, - { 151, 164, 33, 1 }, }, - { { 15, 73, 147, 0 }, - { 208, 90, 165, 0 }, - { 100, 201, 120, 0 }, - { 82, 173, 5, 1 }, }, - { { 15, 247, 123, 0 }, - { 243, 214, 199, 1 }, - { 111, 119, 248, 0 }, - { 241, 181, 231, 1 }, }, - { { 16, 158, 96, 1 }, - { 47, 140, 64, 0 }, - { 131, 60, 132, 0 }, - { 1, 24, 250, 0 }, }, - { { 16, 81, 237, 0 }, - { 68, 196, 113, 1 }, - { 91, 197, 4, 0 }, - { 199, 17, 145, 0 }, }, - { { 20, 122, 222, 1 }, - { 124, 14, 118, 1 }, - { 189, 175, 20, 0 }, - { 183, 56, 31, 0 }, }, - { { 28, 133, 62, 1 }, - { 159, 130, 21, 1 }, - { 190, 80, 156, 0 }, - { 212, 32, 252, 1 }, }, - { { 28, 35, 104, 0 }, - { 164, 132, 7, 1 }, - { 11, 98, 28, 0 }, - { 240, 16, 146, 1 }, }, - { { 24, 199, 52, 0 }, - { 247, 128, 17, 0 }, - { 22, 113, 140, 0 }, - { 68, 0, 247, 1 }, }, - { { 21, 251, 130, 1 }, - { 110, 26, 103, 0 }, - { 160, 239, 212, 0 }, - { 115, 44, 59, 0 }, }, - { { 17, 78, 147, 1 }, - { 125, 90, 32, 0 }, - { 228, 185, 68, 0 }, - { 2, 45, 95, 0 }, }, - { { 25, 160, 234, 1 }, - { 142, 150, 34, 1 }, - { 171, 130, 204, 0 }, - { 162, 52, 184, 1 }, }, - { { 18, 24, 76, 0 }, - { 4, 12, 208, 1 }, - { 25, 12, 36, 0 }, - { 133, 152, 16, 0 }, }, - { { 18, 163, 174, 0 }, - { 38, 130, 179, 1 }, - { 58, 226, 164, 0 }, - { 230, 160, 178, 0 }, }, - { { 30, 172, 60, 0 }, - { 151, 136, 150, 1 }, - { 30, 26, 188, 0 }, - { 180, 136, 244, 1 }, }, - { { 30, 201, 108, 0 }, - { 198, 140, 149, 1 }, - { 27, 73, 188, 0 }, - { 212, 152, 177, 1 }, }, - { { 30, 233, 163, 1 }, - { 206, 202, 167, 0 }, - { 226, 203, 188, 0 }, - { 114, 169, 185, 1 }, }, - { { 26, 118, 216, 0 }, - { 245, 4, 226, 1 }, - { 13, 183, 44, 0 }, - { 163, 144, 87, 1 }, }, - { { 19, 182, 7, 1 }, - { 47, 82, 210, 0 }, - { 240, 54, 228, 0 }, - { 37, 165, 122, 0 }, }, - { { 23, 70, 188, 0 }, - { 117, 144, 180, 1 }, - { 30, 177, 116, 0 }, - { 150, 132, 215, 0 }, }, - { { 31, 21, 121, 0 }, - { 149, 212, 197, 1 }, - { 79, 84, 124, 0 }, - { 209, 149, 212, 1 }, }, - { { 27, 35, 125, 0 }, - { 180, 212, 147, 1 }, - { 95, 98, 108, 0 }, - { 228, 149, 150, 1 }, }, - { { 27, 191, 146, 0 }, - { 183, 26, 227, 0 }, - { 36, 254, 236, 0 }, - { 99, 172, 118, 1 }, }, - { { 31, 150, 154, 1 }, - { 191, 18, 228, 1 }, - { 172, 180, 252, 0 }, - { 147, 164, 126, 1 }, }, - { { 27, 72, 235, 0 }, - { 196, 222, 160, 1 }, - { 107, 137, 108, 0 }, - { 130, 189, 145, 1 }, }, - { { 32, 12, 253, 0 }, - { 17, 236, 48, 1 }, - { 95, 152, 2, 0 }, - { 134, 27, 196, 0 }, }, - { { 32, 23, 86, 0 }, - { 49, 38, 81, 0 }, - { 53, 116, 2, 0 }, - { 69, 50, 70, 0 }, }, - { { 40, 1, 153, 1 }, - { 152, 96, 33, 1 }, - { 204, 192, 10, 0 }, - { 194, 3, 12, 1 }, }, - { { 44, 50, 55, 1 }, - { 184, 226, 86, 0 }, - { 246, 38, 26, 0 }, - { 53, 35, 142, 1 }, }, - { { 37, 140, 230, 0 }, - { 3, 190, 52, 0 }, - { 51, 152, 210, 0 }, - { 22, 62, 224, 0 }, }, - { { 33, 30, 140, 0 }, - { 33, 56, 112, 1 }, - { 24, 188, 66, 0 }, - { 135, 14, 66, 0 }, }, - { { 45, 125, 105, 0 }, - { 193, 252, 71, 1 }, - { 75, 95, 90, 0 }, - { 241, 31, 193, 1 }, }, - { { 41, 192, 73, 0 }, - { 194, 116, 0, 1 }, - { 73, 1, 202, 0 }, - { 128, 23, 33, 1 }, }, - { { 38, 177, 32, 0 }, - { 2, 160, 199, 0 }, - { 2, 70, 178, 0 }, - { 113, 130, 160, 0 }, }, - { { 38, 128, 28, 1 }, - { 26, 32, 148, 1 }, - { 156, 0, 178, 0 }, - { 148, 130, 44, 0 }, }, - { { 34, 180, 26, 0 }, - { 19, 34, 194, 1 }, - { 44, 22, 162, 0 }, - { 161, 162, 100, 0 }, }, - { { 38, 42, 68, 1 }, - { 40, 44, 150, 0 }, - { 145, 42, 50, 0 }, - { 52, 154, 10, 0 }, }, - { { 38, 171, 89, 0 }, - { 50, 108, 135, 1 }, - { 77, 106, 178, 0 }, - { 240, 155, 38, 0 }, }, - { { 38, 201, 132, 0 }, - { 66, 40, 181, 0 }, - { 16, 201, 178, 0 }, - { 86, 138, 33, 0 }, }, - { { 42, 48, 98, 1 }, - { 136, 166, 194, 0 }, - { 163, 6, 42, 0 }, - { 33, 178, 136, 1 }, }, - { { 46, 50, 173, 0 }, - { 160, 224, 246, 1 }, - { 90, 166, 58, 0 }, - { 183, 131, 130, 1 }, }, - { { 35, 63, 1, 1 }, - { 41, 120, 195, 0 }, - { 192, 126, 98, 0 }, - { 97, 143, 74, 0 }, }, - { { 35, 131, 80, 0 }, - { 50, 52, 129, 0 }, - { 5, 96, 226, 0 }, - { 64, 150, 38, 0 }, }, - { { 39, 100, 46, 1 }, - { 73, 178, 150, 1 }, - { 186, 19, 114, 0 }, - { 180, 166, 201, 0 }, }, - { { 39, 212, 176, 1 }, - { 91, 176, 228, 0 }, - { 134, 149, 242, 0 }, - { 19, 134, 237, 0 }, }, - { { 47, 186, 44, 1 }, - { 170, 184, 214, 1 }, - { 154, 46, 250, 0 }, - { 181, 142, 170, 1 }, }, - { { 43, 38, 186, 1 }, - { 185, 178, 162, 1 }, - { 174, 178, 106, 0 }, - { 162, 166, 206, 1 }, }, - { { 48, 11, 141, 0 }, - { 36, 104, 49, 1 }, - { 88, 232, 6, 0 }, - { 198, 11, 18, 0 }, }, - { { 52, 38, 146, 1 }, - { 61, 34, 38, 0 }, - { 164, 178, 22, 0 }, - { 50, 34, 94, 0 }, }, - { { 48, 130, 25, 0 }, - { 54, 96, 0, 1 }, - { 76, 32, 134, 0 }, - { 128, 3, 54, 0 }, }, - { { 48, 123, 44, 1 }, - { 108, 168, 83, 1 }, - { 154, 111, 6, 0 }, - { 229, 10, 155, 0 }, }, - { { 60, 184, 59, 1 }, - { 158, 234, 70, 1 }, - { 238, 14, 158, 0 }, - { 177, 43, 188, 1 }, }, - { { 60, 38, 15, 1 }, - { 173, 98, 22, 1 }, - { 248, 50, 30, 0 }, - { 180, 35, 90, 1 }, }, - { { 56, 233, 220, 0 }, - { 214, 44, 51, 1 }, - { 29, 203, 142, 0 }, - { 230, 26, 53, 1 }, }, - { { 60, 192, 247, 0 }, - { 214, 230, 52, 0 }, - { 119, 129, 158, 0 }, - { 22, 51, 181, 1 }, }, - { { 56, 247, 84, 1 }, - { 255, 36, 83, 0 }, - { 149, 119, 142, 0 }, - { 101, 18, 127, 1 }, }, - { { 49, 5, 180, 1 }, - { 29, 176, 49, 0 }, - { 150, 208, 70, 0 }, - { 70, 6, 220, 0 }, }, - { { 53, 184, 254, 1 }, - { 30, 190, 118, 1 }, - { 191, 142, 214, 0 }, - { 183, 62, 188, 0 }, }, - { { 53, 178, 211, 1 }, - { 62, 118, 102, 0 }, - { 229, 166, 214, 0 }, - { 51, 55, 62, 0 }, }, - { { 57, 155, 206, 1 }, - { 174, 62, 113, 1 }, - { 185, 236, 206, 0 }, - { 199, 62, 58, 1 }, }, - { { 57, 109, 46, 0 }, - { 197, 186, 19, 1 }, - { 58, 91, 78, 0 }, - { 228, 46, 209, 1 }, }, - { { 61, 224, 131, 1 }, - { 206, 114, 38, 0 }, - { 224, 131, 222, 0 }, - { 50, 39, 57, 1 }, }, - { { 57, 244, 208, 0 }, - { 215, 52, 98, 0 }, - { 5, 151, 206, 0 }, - { 35, 22, 117, 1 }, }, - { { 57, 255, 32, 0 }, - { 231, 184, 67, 0 }, - { 2, 127, 206, 0 }, - { 97, 14, 243, 1 }, }, - { { 57, 199, 136, 1 }, - { 239, 48, 33, 1 }, - { 136, 241, 206, 0 }, - { 194, 6, 123, 1 }, }, - { { 54, 15, 36, 0 }, - { 37, 168, 149, 0 }, - { 18, 120, 54, 0 }, - { 84, 138, 210, 0 }, }, - { { 50, 30, 213, 0 }, - { 53, 108, 240, 0 }, - { 85, 188, 38, 0 }, - { 7, 155, 86, 0 }, }, - { { 54, 191, 209, 1 }, - { 63, 108, 231, 0 }, - { 197, 254, 182, 0 }, - { 115, 155, 126, 0 }, }, - { { 54, 70, 235, 0 }, - { 101, 230, 164, 1 }, - { 107, 177, 54, 0 }, - { 146, 179, 211, 0 }, }, - { { 58, 45, 168, 0 }, - { 133, 168, 163, 1 }, - { 10, 218, 46, 0 }, - { 226, 138, 208, 1 }, }, - { { 58, 147, 187, 0 }, - { 182, 226, 225, 1 }, - { 110, 228, 174, 0 }, - { 195, 163, 182, 1 }, }, - { { 55, 149, 173, 0 }, - { 7, 240, 245, 1 }, - { 90, 212, 246, 0 }, - { 215, 135, 240, 0 }, }, - { { 55, 4, 147, 0 }, - { 21, 114, 164, 0 }, - { 100, 144, 118, 0 }, - { 18, 167, 84, 0 }, }, - { { 51, 160, 216, 1 }, - { 30, 52, 162, 1 }, - { 141, 130, 230, 0 }, - { 162, 150, 60, 0 }, }, - { { 55, 67, 167, 0 }, - { 100, 242, 181, 0 }, - { 114, 225, 118, 0 }, - { 86, 167, 147, 0 }, }, - { { 51, 250, 92, 0 }, - { 118, 60, 210, 1 }, - { 29, 47, 230, 0 }, - { 165, 158, 55, 0 }, }, - { { 63, 131, 110, 0 }, - { 166, 182, 149, 1 }, - { 59, 96, 254, 0 }, - { 212, 182, 178, 1 }, }, - { { 63, 107, 96, 0 }, - { 228, 188, 135, 0 }, - { 3, 107, 126, 0 }, - { 112, 158, 147, 1 }, }, - { { 64, 225, 205, 0 }, - { 66, 69, 51, 1 }, - { 89, 195, 129, 0 }, - { 230, 81, 33, 0 }, }, - { { 76, 144, 234, 0 }, - { 130, 135, 100, 1 }, - { 43, 132, 153, 0 }, - { 147, 112, 160, 1 }, }, - { { 72, 154, 105, 1 }, - { 170, 205, 64, 1 }, - { 203, 44, 137, 0 }, - { 129, 89, 170, 1 }, }, - { { 76, 190, 247, 0 }, - { 179, 207, 118, 0 }, - { 119, 190, 153, 0 }, - { 55, 121, 230, 1 }, }, - { { 72, 235, 138, 1 }, - { 234, 11, 35, 1 }, - { 168, 235, 137, 0 }, - { 226, 104, 43, 1 }, }, - { { 72, 211, 7, 1 }, - { 234, 67, 81, 0 }, - { 240, 101, 137, 0 }, - { 69, 97, 43, 1 }, }, - { { 76, 90, 152, 1 }, - { 248, 9, 100, 1 }, - { 140, 173, 25, 0 }, - { 147, 72, 15, 1 }, }, - { { 65, 36, 19, 1 }, - { 25, 83, 2, 0 }, - { 228, 18, 65, 0 }, - { 32, 101, 76, 0 }, }, - { { 77, 11, 248, 0 }, - { 176, 157, 37, 1 }, - { 15, 232, 89, 0 }, - { 210, 92, 134, 1 }, }, - { { 73, 91, 189, 1 }, - { 248, 217, 113, 1 }, - { 222, 237, 73, 0 }, - { 199, 77, 143, 1 }, }, - { { 70, 141, 101, 0 }, - { 3, 205, 149, 0 }, - { 83, 88, 177, 0 }, - { 84, 217, 224, 0 }, }, - { { 66, 181, 107, 1 }, - { 11, 199, 195, 1 }, - { 235, 86, 161, 0 }, - { 225, 241, 232, 0 }, }, - { { 70, 92, 131, 0 }, - { 65, 75, 228, 0 }, - { 96, 157, 49, 0 }, - { 19, 233, 65, 0 }, }, - { { 70, 244, 103, 0 }, - { 67, 199, 214, 0 }, - { 115, 23, 177, 0 }, - { 53, 241, 225, 0 }, }, - { { 70, 121, 187, 0 }, - { 80, 203, 231, 1 }, - { 110, 207, 49, 0 }, - { 243, 233, 133, 0 }, }, - { { 74, 163, 157, 1 }, - { 186, 65, 179, 1 }, - { 220, 226, 169, 0 }, - { 230, 193, 46, 1 }, }, - { { 78, 65, 78, 1 }, - { 200, 7, 149, 1 }, - { 185, 65, 57, 0 }, - { 212, 240, 9, 1 }, }, - { { 78, 75, 194, 0 }, - { 224, 15, 165, 0 }, - { 33, 233, 57, 0 }, - { 82, 248, 3, 1 }, }, - { { 67, 137, 211, 1 }, - { 26, 95, 161, 0 }, - { 229, 200, 225, 0 }, - { 66, 253, 44, 0 }, }, - { { 71, 170, 200, 1 }, - { 42, 29, 166, 1 }, - { 137, 170, 241, 0 }, - { 178, 220, 42, 0 }, }, - { { 67, 59, 19, 0 }, - { 48, 91, 195, 0 }, - { 100, 110, 97, 0 }, - { 97, 237, 6, 0 }, }, - { { 71, 74, 105, 1 }, - { 104, 221, 132, 1 }, - { 203, 41, 113, 0 }, - { 144, 221, 139, 0 }, }, - { { 79, 22, 235, 1 }, - { 169, 215, 228, 1 }, - { 235, 180, 121, 0 }, - { 147, 245, 202, 1 }, }, - { { 79, 69, 160, 0 }, - { 193, 145, 165, 0 }, - { 2, 209, 121, 0 }, - { 82, 196, 193, 1 }, }, - { { 80, 145, 108, 1 }, - { 14, 133, 81, 1 }, - { 155, 68, 133, 0 }, - { 197, 80, 184, 0 }, }, - { { 84, 16, 187, 0 }, - { 20, 195, 100, 1 }, - { 110, 132, 21, 0 }, - { 147, 97, 148, 0 }, }, - { { 80, 90, 77, 1 }, - { 108, 77, 80, 1 }, - { 217, 45, 5, 0 }, - { 133, 89, 27, 0 }, }, - { { 80, 114, 212, 0 }, - { 116, 5, 114, 0 }, - { 21, 167, 5, 0 }, - { 39, 80, 23, 0 }, }, - { { 84, 234, 241, 1 }, - { 126, 205, 38, 0 }, - { 199, 171, 149, 0 }, - { 50, 89, 191, 0 }, }, - { { 88, 9, 195, 1 }, - { 140, 79, 33, 0 }, - { 225, 200, 13, 0 }, - { 66, 121, 24, 1 }, }, - { { 92, 89, 121, 0 }, - { 212, 205, 69, 1 }, - { 79, 77, 29, 0 }, - { 209, 89, 149, 1 }, }, - { { 88, 107, 27, 0 }, - { 244, 75, 3, 1 }, - { 108, 107, 13, 0 }, - { 224, 105, 23, 1 }, }, - { { 81, 52, 246, 1 }, - { 29, 151, 114, 0 }, - { 183, 150, 69, 0 }, - { 39, 116, 220, 0 }, }, - { { 85, 169, 118, 1 }, - { 30, 159, 23, 0 }, - { 183, 74, 213, 0 }, - { 116, 124, 188, 0 }, }, - { { 85, 151, 183, 1 }, - { 63, 211, 117, 0 }, - { 246, 244, 213, 0 }, - { 87, 101, 254, 0 }, }, - { { 85, 72, 67, 1 }, - { 76, 95, 4, 0 }, - { 225, 9, 85, 0 }, - { 16, 125, 25, 0 }, }, - { { 81, 203, 28, 0 }, - { 118, 25, 17, 1 }, - { 28, 105, 197, 0 }, - { 196, 76, 55, 0 }, }, - { { 89, 103, 105, 1 }, - { 237, 213, 3, 1 }, - { 203, 115, 77, 0 }, - { 224, 85, 219, 1 }, }, - { { 89, 87, 155, 0 }, - { 245, 83, 97, 1 }, - { 108, 245, 77, 0 }, - { 195, 101, 87, 1 }, }, - { { 86, 160, 171, 1 }, - { 14, 195, 166, 1 }, - { 234, 130, 181, 0 }, - { 178, 225, 184, 0 }, }, - { { 82, 76, 88, 0 }, - { 85, 13, 128, 1 }, - { 13, 25, 37, 0 }, - { 128, 216, 85, 0 }, }, - { { 86, 87, 68, 1 }, - { 109, 5, 213, 0 }, - { 145, 117, 53, 0 }, - { 85, 208, 91, 0 }, }, - { { 94, 1, 56, 0 }, - { 148, 129, 133, 1 }, - { 14, 64, 61, 0 }, - { 208, 192, 148, 1 }, }, - { { 90, 1, 255, 0 }, - { 148, 199, 177, 1 }, - { 127, 192, 45, 0 }, - { 198, 241, 148, 1 }, }, - { { 90, 53, 19, 1 }, - { 157, 67, 195, 0 }, - { 228, 86, 45, 0 }, - { 97, 225, 92, 1 }, }, - { { 94, 29, 215, 1 }, - { 157, 79, 245, 0 }, - { 245, 220, 61, 0 }, - { 87, 249, 92, 1 }, }, - { { 94, 146, 70, 1 }, - { 174, 7, 212, 0 }, - { 177, 36, 189, 0 }, - { 21, 240, 58, 1 }, }, - { { 90, 108, 162, 0 }, - { 197, 139, 162, 0 }, - { 34, 155, 45, 0 }, - { 34, 232, 209, 1 }, }, - { { 87, 57, 5, 0 }, - { 4, 89, 215, 0 }, - { 80, 78, 117, 0 }, - { 117, 205, 16, 0 }, }, - { { 87, 185, 238, 0 }, - { 6, 159, 247, 1 }, - { 59, 206, 245, 0 }, - { 247, 252, 176, 0 }, }, - { { 83, 27, 44, 1 }, - { 44, 153, 209, 1 }, - { 154, 108, 101, 0 }, - { 197, 204, 154, 0 }, }, - { { 87, 134, 8, 0 }, - { 39, 17, 132, 1 }, - { 8, 48, 245, 0 }, - { 144, 196, 114, 0 }, }, - { { 87, 179, 31, 1 }, - { 62, 83, 215, 1 }, - { 252, 102, 245, 0 }, - { 245, 229, 62, 0 }, }, - { { 87, 175, 125, 0 }, - { 55, 221, 151, 1 }, - { 95, 122, 245, 0 }, - { 244, 221, 246, 0 }, }, - { { 83, 240, 235, 0 }, - { 70, 215, 226, 1 }, - { 107, 135, 229, 0 }, - { 163, 245, 177, 0 }, }, - { { 91, 30, 236, 0 }, - { 165, 157, 240, 1 }, - { 27, 188, 109, 0 }, - { 135, 220, 210, 1 }, }, - { { 95, 6, 166, 1 }, - { 173, 147, 180, 0 }, - { 178, 176, 125, 0 }, - { 22, 228, 218, 1 }, }, - { { 95, 46, 87, 1 }, - { 189, 95, 150, 0 }, - { 245, 58, 125, 0 }, - { 52, 253, 94, 1 }, }, - { { 91, 89, 192, 0 }, - { 196, 29, 225, 0 }, - { 1, 205, 109, 0 }, - { 67, 220, 17, 1 }, }, - { { 91, 221, 125, 1 }, - { 223, 221, 209, 1 }, - { 223, 93, 237, 0 }, - { 197, 221, 253, 1 }, }, - { { 91, 78, 47, 0 }, - { 229, 219, 144, 1 }, - { 122, 57, 109, 0 }, - { 132, 237, 211, 1 }, }, - { { 95, 111, 137, 1 }, - { 237, 89, 167, 1 }, - { 200, 251, 125, 0 }, - { 242, 205, 91, 1 }, }, - { { 91, 99, 218, 0 }, - { 244, 23, 163, 1 }, - { 45, 227, 109, 0 }, - { 226, 244, 23, 1 }, }, - { { 96, 32, 36, 1 }, - { 8, 161, 18, 0 }, - { 146, 2, 3, 0 }, - { 36, 66, 136, 0 }, }, - { { 100, 167, 30, 1 }, - { 59, 35, 23, 1 }, - { 188, 114, 147, 0 }, - { 244, 98, 110, 0 }, }, - { { 96, 84, 84, 1 }, - { 89, 37, 80, 0 }, - { 149, 21, 3, 0 }, - { 5, 82, 77, 0 }, }, - { { 104, 166, 103, 0 }, - { 163, 231, 18, 0 }, - { 115, 50, 139, 0 }, - { 36, 115, 226, 1 }, }, - { { 108, 235, 188, 1 }, - { 250, 169, 55, 1 }, - { 158, 235, 155, 0 }, - { 246, 74, 175, 1 }, }, - { { 105, 70, 205, 1 }, - { 233, 117, 48, 1 }, - { 217, 177, 75, 0 }, - { 134, 87, 75, 1 }, }, - { { 109, 243, 169, 1 }, - { 234, 241, 103, 1 }, - { 202, 231, 219, 0 }, - { 243, 71, 171, 1 }, }, - { { 109, 94, 31, 0 }, - { 241, 123, 84, 1 }, - { 124, 61, 91, 0 }, - { 149, 111, 71, 1 }, }, - { { 102, 32, 99, 0 }, - { 0, 231, 134, 0 }, - { 99, 2, 51, 0 }, - { 48, 243, 128, 0 }, }, - { { 102, 219, 83, 1 }, - { 122, 111, 197, 0 }, - { 229, 109, 179, 0 }, - { 81, 251, 47, 0 }, }, - { { 98, 215, 16, 1 }, - { 123, 33, 193, 0 }, - { 132, 117, 163, 0 }, - { 65, 194, 111, 0 }, }, - { { 106, 165, 84, 1 }, - { 155, 37, 147, 0 }, - { 149, 82, 171, 0 }, - { 100, 210, 108, 1 }, }, - { { 110, 46, 41, 1 }, - { 169, 233, 134, 1 }, - { 202, 58, 59, 0 }, - { 176, 203, 202, 1 }, }, - { { 103, 54, 146, 0 }, - { 49, 51, 230, 0 }, - { 36, 182, 115, 0 }, - { 51, 230, 70, 0 }, }, - { { 103, 196, 202, 0 }, - { 67, 55, 164, 1 }, - { 41, 145, 243, 0 }, - { 146, 246, 97, 0 }, }, - { { 99, 83, 34, 1 }, - { 104, 179, 193, 0 }, - { 162, 101, 99, 0 }, - { 65, 230, 139, 0 }, }, - { { 107, 59, 196, 1 }, - { 168, 61, 243, 0 }, - { 145, 238, 107, 0 }, - { 103, 222, 10, 1 }, }, - { { 111, 22, 80, 1 }, - { 185, 53, 196, 0 }, - { 133, 52, 123, 0 }, - { 17, 214, 78, 1 }, }, - { { 107, 88, 37, 1 }, - { 200, 249, 208, 0 }, - { 210, 13, 107, 0 }, - { 5, 207, 137, 1 }, }, - { { 111, 99, 213, 1 }, - { 248, 117, 183, 0 }, - { 213, 227, 123, 0 }, - { 118, 215, 15, 1 }, }, - { { 112, 192, 248, 1 }, - { 94, 165, 32, 1 }, - { 143, 129, 135, 0 }, - { 130, 82, 189, 0 }, }, - { { 116, 215, 208, 0 }, - { 119, 37, 101, 0 }, - { 5, 245, 151, 0 }, - { 83, 82, 119, 0 }, }, - { { 113, 43, 110, 1 }, - { 44, 191, 19, 1 }, - { 187, 106, 71, 0 }, - { 228, 126, 154, 0 }, }, - { { 113, 121, 27, 1 }, - { 92, 123, 67, 1 }, - { 236, 79, 71, 0 }, - { 225, 111, 29, 0 }, }, - { { 113, 66, 210, 0 }, - { 116, 55, 32, 0 }, - { 37, 161, 71, 0 }, - { 2, 118, 23, 0 }, }, - { { 113, 99, 253, 0 }, - { 116, 245, 51, 1 }, - { 95, 227, 71, 0 }, - { 230, 87, 151, 0 }, }, - { { 117, 254, 122, 1 }, - { 127, 191, 70, 1 }, - { 175, 63, 215, 0 }, - { 177, 126, 255, 0 }, }, - { { 125, 152, 140, 0 }, - { 134, 57, 116, 1 }, - { 24, 140, 223, 0 }, - { 151, 78, 48, 1 }, }, - { { 125, 185, 247, 0 }, - { 150, 255, 119, 0 }, - { 119, 206, 223, 0 }, - { 119, 127, 180, 1 }, }, - { { 125, 19, 147, 1 }, - { 188, 115, 101, 0 }, - { 228, 228, 95, 0 }, - { 83, 103, 30, 1 }, }, - { { 121, 71, 103, 0 }, - { 229, 247, 17, 0 }, - { 115, 113, 79, 0 }, - { 68, 119, 211, 1 }, }, - { { 125, 223, 195, 0 }, - { 231, 127, 101, 0 }, - { 97, 253, 223, 0 }, - { 83, 127, 115, 1 }, }, - { { 121, 239, 82, 1 }, - { 255, 63, 3, 0 }, - { 165, 123, 207, 0 }, - { 96, 126, 127, 1 }, }, - { { 114, 0, 182, 0 }, - { 20, 163, 176, 0 }, - { 54, 128, 39, 0 }, - { 6, 226, 148, 0 }, }, - { { 118, 68, 152, 1 }, - { 93, 33, 164, 1 }, - { 140, 145, 55, 0 }, - { 146, 194, 93, 0 }, }, - { { 118, 122, 66, 0 }, - { 100, 47, 198, 0 }, - { 33, 47, 55, 0 }, - { 49, 250, 19, 0 }, }, - { { 126, 11, 181, 1 }, - { 188, 233, 181, 0 }, - { 214, 232, 63, 0 }, - { 86, 203, 158, 1 }, }, - { { 115, 58, 225, 1 }, - { 44, 253, 226, 0 }, - { 195, 174, 103, 0 }, - { 35, 223, 154, 0 }, }, - { { 119, 139, 59, 1 }, - { 62, 251, 133, 1 }, - { 238, 104, 247, 0 }, - { 208, 239, 190, 0 }, }, - { { 119, 93, 234, 0 }, - { 69, 191, 229, 1 }, - { 43, 221, 119, 0 }, - { 211, 254, 209, 0 }, }, - { { 127, 76, 0, 1 }, - { 205, 57, 132, 0 }, - { 128, 25, 127, 0 }, - { 16, 206, 89, 1 }, }, - { { 123, 117, 224, 1 }, - { 205, 181, 227, 0 }, - { 131, 215, 111, 0 }, - { 99, 214, 217, 1 }, }, - { { 127, 226, 186, 0 }, - { 246, 179, 166, 1 }, - { 46, 163, 255, 0 }, - { 178, 230, 183, 1 }, }, - { { 128, 176, 67, 1 }, - { 10, 70, 74, 0 }, - { 225, 6, 128, 1 }, - { 41, 49, 40, 0 }, }, - { { 128, 188, 61, 0 }, - { 19, 200, 90, 1 }, - { 94, 30, 128, 1 }, - { 173, 9, 228, 0 }, }, - { { 128, 50, 88, 0 }, - { 48, 4, 74, 1 }, - { 13, 38, 0, 1 }, - { 169, 16, 6, 0 }, }, - { { 128, 92, 26, 1 }, - { 89, 10, 72, 1 }, - { 172, 29, 0, 1 }, - { 137, 40, 77, 0 }, }, - { { 132, 251, 36, 0 }, - { 98, 136, 95, 0 }, - { 18, 111, 144, 1 }, - { 125, 8, 163, 0 }, }, - { { 128, 127, 245, 1 }, - { 121, 204, 123, 0 }, - { 215, 255, 0, 1 }, - { 111, 25, 207, 0 }, }, - { { 136, 45, 197, 1 }, - { 137, 76, 59, 0 }, - { 209, 218, 8, 1 }, - { 110, 25, 72, 1 }, }, - { { 136, 153, 224, 1 }, - { 138, 140, 105, 0 }, - { 131, 204, 136, 1 }, - { 75, 24, 168, 1 }, }, - { { 136, 25, 149, 0 }, - { 144, 72, 121, 0 }, - { 84, 204, 8, 1 }, - { 79, 9, 4, 1 }, }, - { { 133, 29, 199, 1 }, - { 9, 94, 125, 0 }, - { 241, 220, 80, 1 }, - { 95, 61, 72, 0 }, }, - { { 129, 187, 135, 0 }, - { 34, 90, 123, 0 }, - { 112, 238, 192, 1 }, - { 111, 45, 34, 0 }, }, - { { 129, 225, 96, 1 }, - { 74, 148, 11, 0 }, - { 131, 67, 192, 1 }, - { 104, 20, 169, 0 }, }, - { { 133, 126, 33, 1 }, - { 105, 216, 78, 0 }, - { 194, 63, 80, 1 }, - { 57, 13, 203, 0 }, }, - { { 129, 242, 146, 0 }, - { 114, 18, 106, 0 }, - { 36, 167, 192, 1 }, - { 43, 36, 39, 0 }, }, - { { 137, 61, 108, 1 }, - { 137, 156, 91, 1 }, - { 155, 94, 72, 1 }, - { 237, 28, 200, 1 }, }, - { { 137, 100, 178, 1 }, - { 217, 146, 42, 0 }, - { 166, 147, 72, 1 }, - { 42, 36, 205, 1 }, }, - { { 141, 212, 30, 1 }, - { 219, 18, 92, 1 }, - { 188, 21, 216, 1 }, - { 157, 36, 109, 1 }, }, - { { 137, 94, 209, 1 }, - { 249, 92, 104, 0 }, - { 197, 189, 72, 1 }, - { 11, 29, 79, 1 }, }, - { { 138, 4, 172, 0 }, - { 129, 128, 184, 1 }, - { 26, 144, 40, 1 }, - { 142, 128, 192, 1 }, }, - { { 142, 200, 22, 0 }, - { 210, 10, 156, 0 }, - { 52, 9, 184, 1 }, - { 28, 168, 37, 1 }, }, - { { 142, 242, 252, 1 }, - { 250, 132, 254, 1 }, - { 159, 167, 184, 1 }, - { 191, 144, 175, 1 }, }, - { { 131, 11, 137, 0 }, - { 32, 88, 169, 1 }, - { 72, 232, 96, 1 }, - { 202, 141, 2, 0 }, }, - { { 135, 43, 109, 0 }, - { 32, 220, 159, 1 }, - { 91, 106, 112, 1 }, - { 252, 157, 130, 0 }, }, - { { 135, 69, 49, 0 }, - { 81, 208, 141, 0 }, - { 70, 81, 112, 1 }, - { 88, 133, 197, 0 }, }, - { { 131, 108, 120, 1 }, - { 89, 156, 138, 1 }, - { 143, 27, 96, 1 }, - { 168, 156, 205, 0 }, }, - { { 135, 238, 13, 0 }, - { 99, 88, 158, 1 }, - { 88, 59, 240, 1 }, - { 188, 141, 99, 0 }, }, - { { 139, 177, 43, 1 }, - { 138, 210, 203, 1 }, - { 234, 70, 232, 1 }, - { 233, 165, 168, 1 }, }, - { { 139, 145, 216, 0 }, - { 146, 20, 233, 1 }, - { 13, 196, 232, 1 }, - { 203, 148, 36, 1 }, }, - { { 139, 89, 102, 0 }, - { 192, 158, 217, 0 }, - { 51, 77, 104, 1 }, - { 77, 188, 129, 1 }, }, - { { 143, 229, 85, 0 }, - { 211, 84, 159, 0 }, - { 85, 83, 248, 1 }, - { 124, 149, 101, 1 }, }, - { { 143, 243, 101, 1 }, - { 234, 212, 223, 0 }, - { 211, 103, 248, 1 }, - { 125, 149, 171, 1 }, }, - { { 148, 26, 21, 0 }, - { 52, 72, 92, 0 }, - { 84, 44, 20, 1 }, - { 29, 9, 22, 0 }, }, - { { 144, 225, 167, 0 }, - { 70, 194, 59, 0 }, - { 114, 195, 132, 1 }, - { 110, 33, 177, 0 }, }, - { { 144, 71, 255, 0 }, - { 117, 198, 57, 1 }, - { 127, 241, 4, 1 }, - { 206, 49, 215, 0 }, }, - { { 156, 188, 213, 0 }, - { 151, 76, 126, 0 }, - { 85, 158, 156, 1 }, - { 63, 25, 116, 1 }, }, - { { 152, 146, 244, 0 }, - { 182, 132, 120, 0 }, - { 23, 164, 140, 1 }, - { 15, 16, 182, 1 }, }, - { { 156, 83, 168, 1 }, - { 236, 128, 109, 1 }, - { 138, 229, 28, 1 }, - { 219, 0, 155, 1 }, }, - { { 152, 195, 107, 0 }, - { 230, 198, 9, 1 }, - { 107, 97, 140, 1 }, - { 200, 49, 179, 1 }, }, - { { 152, 114, 63, 1 }, - { 252, 194, 90, 1 }, - { 254, 39, 12, 1 }, - { 173, 33, 159, 1 }, }, - { { 145, 19, 213, 0 }, - { 52, 84, 121, 0 }, - { 85, 228, 68, 1 }, - { 79, 21, 22, 0 }, }, - { { 149, 191, 251, 0 }, - { 55, 222, 111, 1 }, - { 111, 254, 212, 1 }, - { 251, 61, 246, 0 }, }, - { { 149, 69, 22, 1 }, - { 93, 18, 29, 0 }, - { 180, 81, 84, 1 }, - { 92, 36, 93, 0 }, }, - { { 149, 238, 216, 0 }, - { 119, 28, 46, 1 }, - { 13, 187, 212, 1 }, - { 186, 28, 119, 0 }, }, - { { 157, 214, 4, 0 }, - { 231, 16, 92, 0 }, - { 16, 53, 220, 1 }, - { 29, 4, 115, 1 }, }, - { { 157, 98, 112, 0 }, - { 244, 148, 14, 0 }, - { 7, 35, 92, 1 }, - { 56, 20, 151, 1 }, }, - { { 150, 175, 206, 0 }, - { 39, 14, 191, 1 }, - { 57, 250, 180, 1 }, - { 254, 184, 114, 0 }, }, - { { 150, 186, 24, 1 }, - { 62, 8, 206, 1 }, - { 140, 46, 180, 1 }, - { 185, 136, 62, 0 }, }, - { { 150, 217, 61, 1 }, - { 94, 200, 221, 1 }, - { 222, 77, 180, 1 }, - { 221, 137, 189, 0 }, }, - { { 158, 33, 46, 0 }, - { 132, 130, 159, 1 }, - { 58, 66, 60, 1 }, - { 252, 160, 144, 1 }, }, - { { 154, 185, 132, 0 }, - { 134, 8, 251, 0 }, - { 16, 206, 172, 1 }, - { 111, 136, 48, 1 }, }, - { { 154, 129, 79, 1 }, - { 142, 70, 153, 1 }, - { 249, 64, 172, 1 }, - { 204, 177, 56, 1 }, }, - { { 154, 59, 54, 1 }, - { 188, 138, 219, 0 }, - { 182, 110, 44, 1 }, - { 109, 168, 158, 1 }, }, - { { 158, 195, 37, 0 }, - { 230, 192, 157, 0 }, - { 82, 97, 188, 1 }, - { 92, 129, 179, 1 }, }, - { { 147, 149, 40, 0 }, - { 7, 144, 201, 1 }, - { 10, 84, 228, 1 }, - { 201, 132, 240, 0 }, }, - { { 151, 50, 46, 1 }, - { 44, 146, 222, 1 }, - { 186, 38, 116, 1 }, - { 189, 164, 154, 0 }, }, - { { 151, 211, 152, 0 }, - { 118, 16, 237, 1 }, - { 12, 229, 244, 1 }, - { 219, 132, 55, 0 }, }, - { { 155, 157, 163, 1 }, - { 143, 218, 233, 0 }, - { 226, 220, 236, 1 }, - { 75, 173, 248, 1 }, }, - { { 159, 28, 240, 0 }, - { 149, 156, 236, 0 }, - { 7, 156, 124, 1 }, - { 27, 156, 212, 1 }, }, - { { 159, 51, 82, 1 }, - { 188, 22, 207, 0 }, - { 165, 102, 124, 1 }, - { 121, 180, 30, 1 }, }, - { { 155, 250, 202, 0 }, - { 230, 30, 234, 1 }, - { 41, 175, 236, 1 }, - { 171, 188, 51, 1 }, }, - { { 159, 250, 148, 0 }, - { 246, 24, 254, 0 }, - { 20, 175, 252, 1 }, - { 63, 140, 55, 1 }, }, - { { 160, 60, 203, 1 }, - { 9, 110, 106, 1 }, - { 233, 158, 2, 1 }, - { 171, 59, 72, 0 }, }, - { { 164, 168, 105, 0 }, - { 2, 236, 14, 1 }, - { 75, 10, 146, 1 }, - { 184, 27, 160, 0 }, }, - { { 160, 179, 245, 0 }, - { 50, 228, 123, 0 }, - { 87, 230, 130, 1 }, - { 111, 19, 166, 0 }, }, - { { 164, 106, 191, 0 }, - { 112, 234, 62, 1 }, - { 126, 171, 18, 1 }, - { 190, 43, 135, 0 }, }, - { { 160, 91, 120, 1 }, - { 120, 172, 73, 1 }, - { 143, 109, 2, 1 }, - { 201, 26, 143, 0 }, }, - { { 168, 104, 152, 1 }, - { 216, 40, 42, 1 }, - { 140, 139, 10, 1 }, - { 170, 10, 13, 1 }, }, - { { 172, 205, 54, 1 }, - { 219, 170, 29, 0 }, - { 182, 89, 154, 1 }, - { 92, 42, 237, 1 }, }, - { { 172, 220, 121, 1 }, - { 219, 236, 76, 1 }, - { 207, 29, 154, 1 }, - { 153, 27, 237, 1 }, }, - { { 161, 73, 35, 0 }, - { 64, 250, 9, 0 }, - { 98, 73, 66, 1 }, - { 72, 47, 129, 0 }, }, - { { 161, 67, 217, 0 }, - { 112, 116, 41, 1 }, - { 77, 225, 66, 1 }, - { 202, 23, 7, 0 }, }, - { { 173, 176, 209, 0 }, - { 146, 116, 110, 0 }, - { 69, 134, 218, 1 }, - { 59, 23, 36, 1 }, }, - { { 169, 155, 28, 1 }, - { 186, 56, 89, 1 }, - { 156, 108, 202, 1 }, - { 205, 14, 46, 1 }, }, - { { 169, 138, 215, 1 }, - { 186, 126, 56, 0 }, - { 245, 168, 202, 1 }, - { 14, 63, 46, 1 }, }, - { { 173, 84, 106, 1 }, - { 201, 182, 76, 1 }, - { 171, 21, 90, 1 }, - { 153, 54, 201, 1 }, }, - { { 173, 235, 81, 1 }, - { 250, 124, 15, 0 }, - { 197, 107, 218, 1 }, - { 120, 31, 47, 1 }, }, - { { 166, 29, 142, 0 }, - { 1, 42, 253, 1 }, - { 56, 220, 50, 1 }, - { 223, 170, 64, 0 }, }, - { { 166, 92, 102, 1 }, - { 73, 174, 220, 0 }, - { 179, 29, 50, 1 }, - { 29, 186, 201, 0 }, }, - { { 174, 188, 36, 0 }, - { 131, 168, 222, 0 }, - { 18, 30, 186, 1 }, - { 61, 138, 224, 1 }, }, - { { 170, 171, 48, 0 }, - { 178, 168, 139, 0 }, - { 6, 106, 170, 1 }, - { 104, 138, 166, 1 }, }, - { { 174, 204, 216, 0 }, - { 211, 44, 172, 1 }, - { 13, 153, 186, 1 }, - { 154, 154, 101, 1 }, }, - { { 170, 237, 187, 0 }, - { 211, 234, 171, 1 }, - { 110, 219, 170, 1 }, - { 234, 171, 229, 1 }, }, - { { 174, 227, 205, 1 }, - { 234, 100, 191, 1 }, - { 217, 227, 186, 1 }, - { 254, 147, 43, 1 }, }, - { { 167, 54, 8, 1 }, - { 41, 48, 206, 1 }, - { 136, 54, 114, 1 }, - { 185, 134, 74, 0 }, }, - { { 163, 236, 229, 0 }, - { 67, 252, 186, 0 }, - { 83, 155, 226, 1 }, - { 46, 159, 225, 0 }, }, - { { 163, 193, 155, 1 }, - { 90, 114, 169, 1 }, - { 236, 193, 226, 1 }, - { 202, 167, 45, 0 }, }, - { { 167, 250, 58, 0 }, - { 114, 186, 206, 1 }, - { 46, 47, 242, 1 }, - { 185, 174, 167, 0 }, }, - { { 175, 165, 105, 1 }, - { 139, 244, 143, 1 }, - { 203, 82, 250, 1 }, - { 248, 151, 232, 1 }, }, - { { 175, 200, 189, 1 }, - { 218, 248, 188, 1 }, - { 222, 137, 250, 1 }, - { 158, 143, 173, 1 }, }, - { { 175, 239, 164, 0 }, - { 227, 184, 191, 0 }, - { 18, 251, 250, 1 }, - { 126, 142, 227, 1 }, }, - { { 171, 103, 246, 0 }, - { 241, 182, 187, 0 }, - { 55, 243, 106, 1 }, - { 110, 182, 199, 1 }, }, - { { 180, 28, 82, 0 }, - { 21, 46, 76, 0 }, - { 37, 28, 22, 1 }, - { 25, 58, 84, 0 }, }, - { { 180, 63, 68, 1 }, - { 45, 44, 95, 0 }, - { 145, 126, 22, 1 }, - { 125, 26, 90, 0 }, }, - { { 180, 240, 202, 0 }, - { 70, 38, 110, 1 }, - { 41, 135, 150, 1 }, - { 187, 50, 49, 0 }, }, - { { 184, 24, 45, 0 }, - { 132, 232, 88, 1 }, - { 90, 12, 14, 1 }, - { 141, 11, 144, 1 }, }, - { { 188, 191, 136, 1 }, - { 175, 40, 111, 1 }, - { 136, 254, 158, 1 }, - { 251, 10, 122, 1 }, }, - { { 184, 142, 4, 1 }, - { 175, 40, 24, 0 }, - { 144, 56, 142, 1 }, - { 12, 10, 122, 1 }, }, - { { 188, 120, 40, 1 }, - { 204, 168, 78, 1 }, - { 138, 15, 30, 1 }, - { 185, 10, 153, 1 }, }, - { { 184, 200, 67, 1 }, - { 206, 110, 8, 0 }, - { 225, 9, 142, 1 }, - { 8, 59, 57, 1 }, }, - { { 188, 243, 60, 1 }, - { 254, 160, 95, 1 }, - { 158, 103, 158, 1 }, - { 253, 2, 191, 1 }, }, - { { 181, 19, 12, 0 }, - { 36, 48, 93, 1 }, - { 24, 100, 86, 1 }, - { 221, 6, 18, 0 }, }, - { { 177, 63, 106, 0 }, - { 37, 190, 75, 1 }, - { 43, 126, 70, 1 }, - { 233, 62, 210, 0 }, }, - { { 177, 101, 123, 1 }, - { 93, 246, 11, 1 }, - { 239, 83, 70, 1 }, - { 232, 55, 221, 0 }, }, - { { 177, 203, 237, 0 }, - { 102, 252, 57, 1 }, - { 91, 233, 198, 1 }, - { 206, 31, 179, 0 }, }, - { { 177, 194, 103, 1 }, - { 110, 246, 24, 0 }, - { 243, 33, 198, 1 }, - { 12, 55, 187, 0 }, }, - { { 177, 90, 242, 1 }, - { 124, 190, 104, 0 }, - { 167, 173, 70, 1 }, - { 11, 62, 159, 0 }, }, - { { 181, 238, 31, 1 }, - { 127, 122, 30, 1 }, - { 252, 59, 214, 1 }, - { 188, 47, 127, 0 }, }, - { { 185, 144, 112, 1 }, - { 158, 180, 72, 0 }, - { 135, 4, 206, 1 }, - { 9, 22, 188, 1 }, }, - { { 185, 163, 64, 1 }, - { 174, 52, 11, 0 }, - { 129, 98, 206, 1 }, - { 104, 22, 58, 1 }, }, - { { 185, 120, 90, 0 }, - { 212, 62, 74, 1 }, - { 45, 15, 78, 1 }, - { 169, 62, 21, 1 }, }, - { { 185, 247, 203, 0 }, - { 231, 118, 107, 1 }, - { 105, 247, 206, 1 }, - { 235, 55, 115, 1 }, }, - { { 182, 5, 1, 1 }, - { 13, 96, 141, 0 }, - { 192, 80, 54, 1 }, - { 88, 131, 88, 0 }, }, - { { 178, 255, 194, 0 }, - { 103, 46, 235, 0 }, - { 33, 255, 166, 1 }, - { 107, 186, 115, 0 }, }, - { { 178, 123, 21, 0 }, - { 116, 104, 219, 0 }, - { 84, 111, 38, 1 }, - { 109, 139, 23, 0 }, }, - { { 178, 110, 90, 1 }, - { 125, 46, 138, 1 }, - { 173, 59, 38, 1 }, - { 168, 186, 95, 0 }, }, - { { 190, 181, 243, 1 }, - { 159, 230, 239, 0 }, - { 231, 214, 190, 1 }, - { 123, 179, 252, 1 }, }, - { { 186, 167, 161, 0 }, - { 167, 224, 171, 0 }, - { 66, 242, 174, 1 }, - { 106, 131, 242, 1 }, }, - { { 186, 114, 10, 1 }, - { 236, 34, 202, 1 }, - { 168, 39, 46, 1 }, - { 169, 162, 27, 1 }, }, - { { 179, 48, 64, 0 }, - { 4, 52, 202, 0 }, - { 1, 6, 102, 1 }, - { 41, 150, 16, 0 }, }, - { { 183, 181, 52, 1 }, - { 31, 176, 223, 0 }, - { 150, 86, 246, 1 }, - { 125, 134, 252, 0 }, }, - { { 183, 105, 76, 0 }, - { 68, 60, 159, 1 }, - { 25, 75, 118, 1 }, - { 252, 158, 17, 0 }, }, - { { 183, 197, 193, 0 }, - { 71, 116, 173, 0 }, - { 65, 209, 246, 1 }, - { 90, 151, 113, 0 }, }, - { { 179, 87, 222, 0 }, - { 117, 54, 249, 1 }, - { 61, 245, 102, 1 }, - { 207, 182, 87, 0 }, }, - { { 187, 84, 251, 0 }, - { 213, 246, 232, 1 }, - { 111, 149, 110, 1 }, - { 139, 183, 213, 1 }, }, - { { 187, 202, 108, 1 }, - { 238, 188, 152, 1 }, - { 155, 41, 238, 1 }, - { 140, 158, 187, 1 }, }, - { { 187, 251, 225, 1 }, - { 238, 252, 235, 0 }, - { 195, 239, 238, 1 }, - { 107, 159, 187, 1 }, }, - { { 191, 246, 134, 1 }, - { 239, 50, 254, 0 }, - { 176, 183, 254, 1 }, - { 63, 166, 123, 1 }, }, - { { 196, 45, 124, 0 }, - { 17, 141, 31, 1 }, - { 31, 90, 17, 1 }, - { 252, 88, 196, 0 }, }, - { { 200, 28, 52, 0 }, - { 145, 137, 88, 0 }, - { 22, 28, 9, 1 }, - { 13, 72, 196, 1 }, }, - { { 204, 67, 229, 1 }, - { 232, 197, 61, 0 }, - { 211, 225, 25, 1 }, - { 94, 81, 139, 1 }, }, - { { 197, 53, 174, 1 }, - { 9, 147, 127, 1 }, - { 186, 214, 81, 1 }, - { 255, 100, 200, 0 }, }, - { { 193, 146, 192, 0 }, - { 34, 21, 104, 0 }, - { 1, 164, 193, 1 }, - { 11, 84, 34, 0 }, }, - { { 197, 35, 247, 0 }, - { 48, 215, 63, 0 }, - { 119, 226, 81, 1 }, - { 126, 117, 134, 0 }, }, - { { 193, 159, 254, 0 }, - { 51, 159, 121, 1 }, - { 63, 252, 193, 1 }, - { 207, 124, 230, 0 }, }, - { { 193, 84, 97, 0 }, - { 65, 213, 72, 0 }, - { 67, 21, 65, 1 }, - { 9, 85, 193, 0 }, }, - { { 193, 87, 130, 0 }, - { 97, 19, 105, 0 }, - { 32, 245, 65, 1 }, - { 75, 100, 67, 0 }, }, - { { 193, 199, 55, 1 }, - { 123, 211, 25, 0 }, - { 246, 113, 193, 1 }, - { 76, 101, 239, 0 }, }, - { { 201, 140, 239, 1 }, - { 139, 223, 56, 1 }, - { 251, 152, 201, 1 }, - { 142, 125, 232, 1 }, }, - { { 205, 240, 111, 0 }, - { 194, 215, 94, 1 }, - { 123, 7, 217, 1 }, - { 189, 117, 161, 1 }, }, - { { 201, 95, 103, 1 }, - { 233, 223, 89, 0 }, - { 243, 125, 73, 1 }, - { 77, 125, 203, 1 }, }, - { { 201, 119, 241, 0 }, - { 241, 213, 107, 0 }, - { 71, 247, 73, 1 }, - { 107, 85, 199, 1 }, }, - { { 205, 226, 149, 1 }, - { 250, 81, 62, 0 }, - { 212, 163, 217, 1 }, - { 62, 69, 47, 1 }, }, - { { 198, 191, 7, 1 }, - { 43, 75, 223, 0 }, - { 240, 126, 177, 1 }, - { 125, 233, 106, 0 }, }, - { { 198, 191, 184, 0 }, - { 51, 137, 239, 1 }, - { 14, 254, 177, 1 }, - { 251, 200, 230, 0 }, }, - { { 198, 219, 201, 1 }, - { 106, 77, 237, 1 }, - { 201, 237, 177, 1 }, - { 219, 217, 43, 0 }, }, - { { 202, 49, 136, 0 }, - { 128, 1, 235, 1 }, - { 8, 198, 41, 1 }, - { 235, 192, 0, 1 }, }, - { { 206, 222, 45, 1 }, - { 235, 201, 220, 1 }, - { 218, 61, 185, 1 }, - { 157, 201, 235, 1 }, }, - { { 199, 120, 44, 1 }, - { 72, 153, 222, 1 }, - { 154, 15, 113, 1 }, - { 189, 204, 137, 0 }, }, - { { 203, 171, 75, 1 }, - { 170, 95, 139, 1 }, - { 233, 106, 233, 1 }, - { 232, 253, 42, 1 }, }, - { { 207, 67, 191, 0 }, - { 240, 211, 189, 1 }, - { 126, 225, 121, 1 }, - { 222, 229, 135, 1 }, }, - { { 208, 174, 86, 1 }, - { 63, 15, 26, 0 }, - { 181, 58, 133, 1 }, - { 44, 120, 126, 0 }, }, - { { 208, 115, 51, 0 }, - { 116, 195, 75, 0 }, - { 102, 103, 5, 1 }, - { 105, 97, 151, 0 }, }, - { { 216, 20, 152, 0 }, - { 149, 1, 104, 1 }, - { 12, 148, 13, 1 }, - { 139, 64, 84, 1 }, }, - { { 220, 96, 159, 1 }, - { 220, 67, 62, 1 }, - { 252, 131, 29, 1 }, - { 190, 97, 29, 1 }, }, - { { 213, 117, 88, 0 }, - { 85, 21, 79, 1 }, - { 13, 87, 85, 1 }, - { 249, 84, 85, 0 }, }, - { { 209, 224, 215, 0 }, - { 86, 87, 58, 0 }, - { 117, 131, 197, 1 }, - { 46, 117, 53, 0 }, }, - { { 213, 251, 177, 0 }, - { 118, 217, 111, 0 }, - { 70, 239, 213, 1 }, - { 123, 77, 183, 0 }, }, - { { 213, 218, 116, 1 }, - { 126, 157, 92, 0 }, - { 151, 45, 213, 1 }, - { 29, 92, 191, 0 }, }, - { { 221, 60, 116, 1 }, - { 157, 157, 94, 0 }, - { 151, 30, 93, 1 }, - { 61, 92, 220, 1 }, }, - { { 221, 151, 109, 0 }, - { 167, 213, 93, 1 }, - { 91, 116, 221, 1 }, - { 221, 85, 242, 1 }, }, - { { 217, 27, 49, 0 }, - { 180, 217, 73, 0 }, - { 70, 108, 77, 1 }, - { 73, 77, 150, 1 }, }, - { { 217, 98, 166, 0 }, - { 228, 147, 58, 0 }, - { 50, 163, 77, 1 }, - { 46, 100, 147, 1 }, }, - { { 210, 171, 124, 1 }, - { 62, 141, 155, 1 }, - { 159, 106, 165, 1 }, - { 236, 216, 190, 0 }, }, - { { 210, 197, 236, 0 }, - { 71, 133, 185, 1 }, - { 27, 209, 165, 1 }, - { 206, 208, 241, 0 }, }, - { { 210, 202, 106, 0 }, - { 102, 143, 136, 1 }, - { 43, 41, 165, 1 }, - { 136, 248, 179, 0 }, }, - { { 210, 107, 214, 0 }, - { 116, 15, 187, 0 }, - { 53, 235, 37, 1 }, - { 110, 248, 23, 0 }, }, - { { 222, 155, 52, 0 }, - { 182, 137, 221, 0 }, - { 22, 108, 189, 1 }, - { 93, 200, 182, 1 }, }, - { { 222, 146, 158, 0 }, - { 182, 3, 252, 1 }, - { 60, 164, 189, 1 }, - { 159, 224, 54, 1 }, }, - { { 218, 96, 216, 1 }, - { 220, 5, 170, 1 }, - { 141, 131, 45, 1 }, - { 170, 208, 29, 1 }, }, - { { 215, 57, 178, 1 }, - { 28, 155, 239, 0 }, - { 166, 206, 117, 1 }, - { 123, 236, 156, 0 }, }, - { { 215, 95, 38, 0 }, - { 101, 155, 221, 0 }, - { 50, 125, 117, 1 }, - { 93, 236, 211, 0 }, }, - { { 223, 1, 65, 1 }, - { 140, 85, 141, 0 }, - { 193, 64, 125, 1 }, - { 88, 213, 24, 1 }, }, - { { 223, 121, 15, 1 }, - { 204, 91, 223, 1 }, - { 248, 79, 125, 1 }, - { 253, 237, 25, 1 }, }, - { { 219, 247, 116, 0 }, - { 247, 149, 219, 0 }, - { 23, 119, 237, 1 }, - { 109, 212, 247, 1 }, }, - { { 224, 67, 79, 1 }, - { 104, 103, 25, 1 }, - { 249, 97, 3, 1 }, - { 204, 115, 11, 0 }, }, - { { 224, 198, 227, 0 }, - { 99, 231, 40, 0 }, - { 99, 177, 131, 1 }, - { 10, 115, 227, 0 }, }, - { { 236, 56, 189, 1 }, - { 152, 233, 126, 1 }, - { 222, 142, 27, 1 }, - { 191, 75, 140, 1 }, }, - { { 236, 81, 253, 0 }, - { 208, 229, 125, 1 }, - { 95, 197, 27, 1 }, - { 223, 83, 133, 1 }, }, - { { 229, 141, 36, 0 }, - { 3, 185, 29, 0 }, - { 18, 88, 211, 1 }, - { 92, 78, 224, 0 }, }, - { { 229, 5, 121, 1 }, - { 25, 245, 13, 1 }, - { 207, 80, 83, 1 }, - { 216, 87, 204, 0 }, }, - { { 225, 78, 248, 0 }, - { 113, 189, 40, 1 }, - { 15, 185, 67, 1 }, - { 138, 94, 199, 0 }, }, - { { 229, 87, 220, 1 }, - { 121, 53, 125, 1 }, - { 157, 245, 83, 1 }, - { 223, 86, 79, 0 }, }, - { { 225, 247, 242, 1 }, - { 123, 183, 107, 0 }, - { 167, 247, 195, 1 }, - { 107, 118, 239, 0 }, }, - { { 226, 133, 77, 0 }, - { 3, 101, 153, 1 }, - { 89, 80, 163, 1 }, - { 204, 211, 96, 0 }, }, - { { 226, 24, 26, 0 }, - { 16, 43, 200, 1 }, - { 44, 12, 35, 1 }, - { 137, 234, 4, 0 }, }, - { { 226, 43, 203, 0 }, - { 32, 111, 171, 1 }, - { 105, 234, 35, 1 }, - { 234, 251, 2, 0 }, }, - { { 230, 236, 2, 0 }, - { 67, 43, 142, 0 }, - { 32, 27, 179, 1 }, - { 56, 234, 97, 0 }, }, - { { 230, 98, 129, 0 }, - { 96, 97, 174, 0 }, - { 64, 163, 51, 1 }, - { 58, 195, 3, 0 }, }, - { { 234, 38, 64, 0 }, - { 161, 37, 138, 0 }, - { 1, 50, 43, 1 }, - { 40, 210, 66, 1 }, }, - { { 234, 224, 196, 0 }, - { 194, 37, 186, 0 }, - { 17, 131, 171, 1 }, - { 46, 210, 33, 1 }, }, - { { 234, 114, 148, 1 }, - { 248, 33, 250, 0 }, - { 148, 167, 43, 1 }, - { 47, 194, 15, 1 }, }, - { { 227, 17, 63, 1 }, - { 24, 243, 217, 1 }, - { 254, 68, 99, 1 }, - { 205, 231, 140, 0 }, }, - { { 231, 11, 230, 1 }, - { 40, 191, 189, 0 }, - { 179, 232, 115, 1 }, - { 94, 254, 138, 0 }, }, - { { 227, 100, 241, 1 }, - { 89, 245, 170, 0 }, - { 199, 147, 99, 1 }, - { 42, 215, 205, 0 }, }, - { { 231, 250, 226, 1 }, - { 106, 191, 238, 0 }, - { 163, 175, 243, 1 }, - { 59, 254, 171, 0 }, }, - { { 227, 219, 243, 0 }, - { 114, 255, 233, 0 }, - { 103, 237, 227, 1 }, - { 75, 255, 167, 0 }, }, - { { 239, 135, 98, 0 }, - { 163, 183, 141, 0 }, - { 35, 112, 251, 1 }, - { 88, 246, 226, 1 }, }, - { { 239, 93, 112, 0 }, - { 209, 189, 205, 0 }, - { 7, 93, 123, 1 }, - { 89, 222, 197, 1 }, }, - { { 235, 102, 14, 0 }, - { 225, 51, 154, 1 }, - { 56, 51, 107, 1 }, - { 172, 230, 67, 1 }, }, - { { 239, 74, 60, 0 }, - { 240, 185, 156, 1 }, - { 30, 41, 123, 1 }, - { 156, 206, 135, 1 }, }, - { { 240, 178, 33, 1 }, - { 46, 225, 74, 0 }, - { 194, 38, 135, 1 }, - { 41, 67, 186, 0 }, }, - { { 240, 175, 79, 0 }, - { 39, 111, 27, 1 }, - { 121, 122, 135, 1 }, - { 236, 123, 114, 0 }, }, - { { 244, 159, 60, 1 }, - { 63, 169, 93, 1 }, - { 158, 124, 151, 1 }, - { 221, 74, 254, 0 }, }, - { { 240, 245, 4, 0 }, - { 71, 33, 91, 0 }, - { 16, 87, 135, 1 }, - { 109, 66, 113, 0 }, }, - { { 240, 242, 120, 0 }, - { 118, 165, 74, 1 }, - { 15, 39, 135, 1 }, - { 169, 82, 183, 0 }, }, - { { 248, 52, 99, 0 }, - { 133, 231, 74, 0 }, - { 99, 22, 15, 1 }, - { 41, 115, 208, 1 }, }, - { { 252, 219, 143, 0 }, - { 230, 107, 125, 1 }, - { 120, 237, 159, 1 }, - { 223, 107, 51, 1 }, }, - { { 252, 254, 77, 1 }, - { 239, 109, 94, 1 }, - { 217, 63, 159, 1 }, - { 189, 91, 123, 1 }, }, - { { 253, 176, 69, 1 }, - { 142, 117, 94, 0 }, - { 209, 6, 223, 1 }, - { 61, 87, 56, 1 }, }, - { { 253, 51, 235, 0 }, - { 164, 247, 111, 1 }, - { 107, 230, 95, 1 }, - { 251, 119, 146, 1 }, }, - { { 249, 196, 217, 1 }, - { 223, 117, 40, 1 }, - { 205, 145, 207, 1 }, - { 138, 87, 125, 1 }, }, - { { 242, 35, 145, 1 }, - { 60, 97, 171, 0 }, - { 196, 226, 39, 1 }, - { 106, 195, 30, 0 }, }, - { { 246, 210, 251, 1 }, - { 126, 231, 236, 1 }, - { 239, 165, 183, 1 }, - { 155, 243, 191, 0 }, }, - { { 254, 239, 211, 1 }, - { 255, 111, 175, 0 }, - { 229, 251, 191, 1 }, - { 122, 251, 127, 1 }, }, - { { 243, 176, 58, 1 }, - { 30, 179, 202, 1 }, - { 174, 6, 231, 1 }, - { 169, 230, 188, 0 }, }, - { { 247, 138, 77, 1 }, - { 46, 125, 156, 1 }, - { 217, 40, 247, 1 }, - { 156, 223, 58, 0 }, }, - { { 243, 143, 157, 1 }, - { 63, 121, 185, 1 }, - { 220, 248, 231, 1 }, - { 206, 207, 126, 0 }, }, - { { 247, 242, 39, 0 }, - { 102, 243, 222, 0 }, - { 114, 39, 247, 1 }, - { 61, 231, 179, 0 }, }, - { { 255, 189, 133, 1 }, - { 143, 121, 255, 0 }, - { 208, 222, 255, 1 }, - { 127, 207, 120, 1 }, }, - { { 255, 38, 197, 1 }, - { 173, 117, 190, 0 }, - { 209, 178, 127, 1 }, - { 62, 215, 90, 1 }, }, - { { 251, 224, 97, 0 }, - { 198, 245, 138, 0 }, - { 67, 3, 239, 1 }, - { 40, 215, 177, 1 }, }, - { { 255, 220, 26, 0 }, - { 215, 59, 204, 1 }, - { 44, 29, 255, 1 }, - { 153, 238, 117, 1 }, }, - { { 25, 248, 99, 1 }, - { 206, 222, 66, 0 }, - { 227, 15, 204, 0 }, - { 33, 61, 185, 1 }, }, - { { 169, 93, 31, 1 }, - { 217, 122, 89, 1 }, - { 252, 93, 74, 1 }, - { 205, 47, 77, 1 }, }, - { { 0, 184, 72, 1 }, - { 10, 12, 66, 1 }, - { 137, 14, 128, 0 }, - { 161, 24, 40, 0 }, }, - { { 0, 236, 225, 0 }, - { 67, 204, 34, 0 }, - { 67, 155, 128, 0 }, - { 34, 25, 225, 0 }, }, - { { 8, 97, 102, 0 }, - { 192, 134, 19, 0 }, - { 51, 67, 8, 0 }, - { 100, 48, 129, 1 }, }, - { { 8, 244, 131, 0 }, - { 195, 66, 98, 0 }, - { 96, 151, 136, 0 }, - { 35, 33, 97, 1 }, }, - { { 12, 248, 157, 0 }, - { 210, 72, 118, 1 }, - { 92, 143, 152, 0 }, - { 183, 9, 37, 1 }, }, - { { 8, 192, 62, 1 }, - { 218, 130, 16, 1 }, - { 190, 1, 136, 0 }, - { 132, 32, 173, 1 }, }, - { { 1, 57, 192, 0 }, - { 0, 28, 99, 0 }, - { 1, 206, 64, 0 }, - { 99, 28, 0, 0 }, }, - { { 1, 40, 10, 0 }, - { 0, 26, 2, 1 }, - { 40, 10, 64, 0 }, - { 160, 44, 0, 0 }, }, - { { 1, 190, 179, 1 }, - { 59, 218, 98, 0 }, - { 230, 190, 192, 0 }, - { 35, 45, 238, 0 }, }, - { { 13, 128, 85, 0 }, - { 146, 84, 20, 0 }, - { 85, 0, 216, 0 }, - { 20, 21, 36, 1 }, }, - { { 13, 175, 99, 1 }, - { 171, 222, 7, 0 }, - { 227, 122, 216, 0 }, - { 112, 61, 234, 1 }, }, - { { 6, 181, 236, 0 }, - { 3, 132, 247, 1 }, - { 27, 214, 176, 0 }, - { 247, 144, 224, 0 }, }, - { { 2, 153, 54, 1 }, - { 26, 138, 209, 0 }, - { 182, 76, 160, 0 }, - { 69, 168, 172, 0 }, }, - { { 6, 182, 143, 0 }, - { 35, 66, 246, 1 }, - { 120, 182, 176, 0 }, - { 183, 161, 98, 0 }, }, - { { 6, 125, 64, 1 }, - { 73, 12, 199, 0 }, - { 129, 95, 48, 0 }, - { 113, 152, 73, 0 }, }, - { { 2, 114, 104, 1 }, - { 104, 132, 194, 1 }, - { 139, 39, 32, 0 }, - { 161, 144, 139, 0 }, }, - { { 6, 203, 237, 1 }, - { 106, 204, 181, 1 }, - { 219, 233, 176, 0 }, - { 214, 153, 171, 0 }, }, - { { 14, 15, 61, 0 }, - { 177, 200, 149, 1 }, - { 94, 120, 56, 0 }, - { 212, 137, 198, 1 }, }, - { { 14, 213, 203, 0 }, - { 195, 70, 229, 1 }, - { 105, 213, 184, 0 }, - { 211, 177, 97, 1 }, }, - { { 3, 125, 39, 1 }, - { 73, 218, 211, 0 }, - { 242, 95, 96, 0 }, - { 101, 173, 201, 0 }, }, - { { 3, 233, 143, 0 }, - { 66, 90, 179, 1 }, - { 120, 203, 224, 0 }, - { 230, 173, 33, 0 }, }, - { { 7, 250, 159, 1 }, - { 122, 90, 246, 1 }, - { 252, 175, 240, 0 }, - { 183, 173, 47, 0 }, }, - { { 11, 76, 16, 0 }, - { 209, 24, 128, 0 }, - { 4, 25, 104, 0 }, - { 0, 140, 69, 1 }, }, - { { 16, 185, 87, 1 }, - { 30, 78, 83, 0 }, - { 245, 78, 132, 0 }, - { 101, 57, 60, 0 }, }, - { { 16, 22, 41, 0 }, - { 37, 192, 64, 1 }, - { 74, 52, 4, 0 }, - { 129, 1, 210, 0 }, }, - { { 16, 98, 139, 1 }, - { 108, 66, 34, 1 }, - { 232, 163, 4, 0 }, - { 162, 33, 27, 0 }, }, - { { 24, 157, 182, 0 }, - { 151, 138, 113, 0 }, - { 54, 220, 140, 0 }, - { 71, 40, 244, 1 }, }, - { { 24, 109, 0, 1 }, - { 205, 8, 3, 0 }, - { 128, 91, 12, 0 }, - { 96, 8, 89, 1 }, }, - { { 28, 118, 42, 0 }, - { 229, 130, 70, 1 }, - { 42, 55, 28, 0 }, - { 177, 32, 211, 1 }, }, - { { 24, 95, 228, 1 }, - { 237, 140, 113, 0 }, - { 147, 253, 12, 0 }, - { 71, 24, 219, 1 }, }, - { { 28, 66, 22, 0 }, - { 244, 2, 20, 0 }, - { 52, 33, 28, 0 }, - { 20, 32, 23, 1 }, }, - { { 17, 60, 169, 0 }, - { 5, 216, 98, 1 }, - { 74, 158, 68, 0 }, - { 163, 13, 208, 0 }, }, - { { 17, 152, 57, 1 }, - { 30, 216, 64, 1 }, - { 206, 12, 196, 0 }, - { 129, 13, 188, 0 }, }, - { { 21, 58, 99, 0 }, - { 36, 222, 70, 0 }, - { 99, 46, 84, 0 }, - { 49, 61, 146, 0 }, }, - { { 21, 18, 117, 1 }, - { 60, 212, 84, 0 }, - { 215, 36, 84, 0 }, - { 21, 21, 158, 0 }, }, - { { 21, 222, 162, 0 }, - { 103, 154, 100, 0 }, - { 34, 189, 212, 0 }, - { 19, 44, 243, 0 }, }, - { { 21, 106, 24, 1 }, - { 124, 24, 6, 1 }, - { 140, 43, 84, 0 }, - { 176, 12, 31, 0 }, }, - { { 29, 209, 40, 0 }, - { 198, 144, 69, 1 }, - { 10, 69, 220, 0 }, - { 209, 4, 177, 1 }, }, - { { 29, 113, 148, 1 }, - { 220, 16, 119, 0 }, - { 148, 199, 92, 0 }, - { 119, 4, 29, 1 }, }, - { { 18, 57, 139, 1 }, - { 12, 74, 227, 1 }, - { 232, 206, 36, 0 }, - { 227, 169, 24, 0 }, }, - { { 18, 5, 152, 0 }, - { 21, 0, 161, 1 }, - { 12, 208, 36, 0 }, - { 194, 128, 84, 0 }, }, - { { 22, 2, 152, 1 }, - { 60, 0, 164, 1 }, - { 140, 160, 52, 0 }, - { 146, 128, 30, 0 }, }, - { { 26, 52, 127, 1 }, - { 157, 198, 210, 1 }, - { 255, 22, 44, 0 }, - { 165, 177, 220, 1 }, }, - { { 30, 220, 239, 1 }, - { 207, 206, 244, 1 }, - { 251, 157, 188, 0 }, - { 151, 185, 249, 1 }, }, - { { 30, 112, 115, 0 }, - { 212, 198, 198, 0 }, - { 103, 7, 60, 0 }, - { 49, 177, 149, 1 }, }, - { { 26, 67, 149, 0 }, - { 244, 64, 177, 0 }, - { 84, 225, 44, 0 }, - { 70, 129, 23, 1 }, }, - { { 26, 126, 27, 1 }, - { 253, 74, 194, 1 }, - { 236, 63, 44, 0 }, - { 161, 169, 95, 1 }, }, - { { 23, 173, 194, 0 }, - { 7, 30, 167, 0 }, - { 33, 218, 244, 0 }, - { 114, 188, 112, 0 }, }, - { { 19, 25, 222, 1 }, - { 28, 30, 241, 1 }, - { 189, 204, 100, 0 }, - { 199, 188, 28, 0 }, }, - { { 27, 168, 147, 1 }, - { 158, 90, 162, 0 }, - { 228, 138, 236, 0 }, - { 34, 173, 60, 1 }, }, - { { 27, 147, 73, 1 }, - { 174, 84, 193, 1 }, - { 201, 100, 236, 0 }, - { 193, 149, 58, 1 }, }, - { { 27, 208, 27, 0 }, - { 214, 82, 192, 1 }, - { 108, 5, 236, 0 }, - { 129, 165, 53, 1 }, }, - { { 31, 66, 219, 1 }, - { 252, 86, 164, 1 }, - { 237, 161, 124, 0 }, - { 146, 181, 31, 1 }, }, - { { 32, 185, 170, 0 }, - { 2, 170, 99, 1 }, - { 42, 206, 130, 0 }, - { 227, 42, 160, 0 }, }, - { { 36, 196, 186, 0 }, - { 83, 162, 36, 1 }, - { 46, 145, 146, 0 }, - { 146, 34, 229, 0 }, }, - { { 40, 173, 5, 0 }, - { 131, 104, 19, 0 }, - { 80, 90, 138, 0 }, - { 100, 11, 96, 1 }, }, - { { 44, 35, 100, 1 }, - { 168, 164, 23, 0 }, - { 147, 98, 26, 0 }, - { 116, 18, 138, 1 }, }, - { { 44, 14, 154, 1 }, - { 185, 42, 36, 1 }, - { 172, 184, 26, 0 }, - { 146, 42, 78, 1 }, }, - { { 44, 81, 3, 1 }, - { 200, 98, 69, 0 }, - { 224, 69, 26, 0 }, - { 81, 35, 9, 1 }, }, - { { 37, 197, 207, 1 }, - { 75, 118, 53, 1 }, - { 249, 209, 210, 0 }, - { 214, 55, 105, 0 }, }, - { { 37, 200, 211, 1 }, - { 90, 126, 36, 0 }, - { 229, 137, 210, 0 }, - { 18, 63, 45, 0 }, }, - { { 33, 119, 232, 1 }, - { 105, 180, 99, 1 }, - { 139, 247, 66, 0 }, - { 227, 22, 203, 0 }, }, - { { 34, 141, 218, 1 }, - { 27, 46, 161, 1 }, - { 173, 216, 162, 0 }, - { 194, 186, 108, 0 }, }, - { { 34, 10, 238, 0 }, - { 32, 174, 176, 1 }, - { 59, 168, 34, 0 }, - { 134, 186, 130, 0 }, }, - { { 46, 134, 44, 0 }, - { 163, 160, 148, 1 }, - { 26, 48, 186, 0 }, - { 148, 130, 226, 1 }, }, - { { 42, 182, 47, 1 }, - { 171, 226, 210, 1 }, - { 250, 54, 170, 0 }, - { 165, 163, 234, 1 }, }, - { { 39, 60, 45, 0 }, - { 1, 248, 214, 1 }, - { 90, 30, 114, 0 }, - { 181, 143, 192, 0 }, }, - { { 39, 157, 74, 0 }, - { 3, 62, 197, 1 }, - { 41, 92, 242, 0 }, - { 209, 190, 96, 0 }, }, - { { 39, 155, 7, 1 }, - { 42, 122, 213, 0 }, - { 240, 108, 242, 0 }, - { 85, 175, 42, 0 }, }, - { { 35, 87, 132, 0 }, - { 97, 48, 241, 0 }, - { 16, 245, 98, 0 }, - { 71, 134, 67, 0 }, }, - { { 35, 78, 67, 1 }, - { 105, 126, 128, 0 }, - { 225, 57, 98, 0 }, - { 0, 191, 75, 0 }, }, - { { 47, 171, 185, 1 }, - { 186, 248, 167, 1 }, - { 206, 234, 250, 0 }, - { 242, 143, 174, 1 }, }, - { { 48, 176, 46, 1 }, - { 14, 162, 82, 1 }, - { 186, 6, 134, 0 }, - { 165, 34, 184, 0 }, }, - { { 48, 40, 122, 0 }, - { 20, 174, 2, 1 }, - { 47, 10, 6, 0 }, - { 160, 58, 148, 0 }, }, - { { 52, 253, 160, 1 }, - { 79, 168, 103, 0 }, - { 130, 223, 150, 0 }, - { 115, 10, 249, 0 }, }, - { { 60, 214, 137, 0 }, - { 231, 96, 100, 1 }, - { 72, 181, 158, 0 }, - { 147, 3, 115, 1 }, }, - { { 56, 126, 182, 0 }, - { 245, 170, 114, 0 }, - { 54, 191, 14, 0 }, - { 39, 42, 215, 1 }, }, - { { 49, 0, 109, 0 }, - { 4, 244, 16, 1 }, - { 91, 0, 70, 0 }, - { 132, 23, 144, 0 }, }, - { { 49, 23, 219, 1 }, - { 61, 118, 97, 1 }, - { 237, 244, 70, 0 }, - { 195, 55, 94, 0 }, }, - { { 49, 167, 119, 1 }, - { 63, 246, 19, 0 }, - { 247, 114, 198, 0 }, - { 100, 55, 254, 0 }, }, - { { 61, 128, 10, 1 }, - { 142, 50, 4, 1 }, - { 168, 0, 222, 0 }, - { 144, 38, 56, 1 }, }, - { { 61, 226, 157, 0 }, - { 246, 112, 54, 1 }, - { 92, 163, 222, 0 }, - { 182, 7, 55, 1 }, }, - { { 54, 106, 119, 1 }, - { 124, 238, 150, 0 }, - { 247, 43, 54, 0 }, - { 52, 187, 159, 0 }, }, - { { 54, 199, 190, 1 }, - { 127, 162, 181, 1 }, - { 190, 241, 182, 0 }, - { 214, 162, 255, 0 }, }, - { { 62, 187, 41, 0 }, - { 166, 232, 199, 1 }, - { 74, 110, 190, 0 }, - { 241, 139, 178, 1 }, }, - { { 62, 104, 154, 0 }, - { 212, 42, 166, 1 }, - { 44, 139, 62, 0 }, - { 178, 170, 21, 1 }, }, - { { 62, 95, 2, 1 }, - { 237, 42, 197, 0 }, - { 160, 125, 62, 0 }, - { 81, 170, 91, 1 }, }, - { { 58, 86, 206, 1 }, - { 237, 38, 240, 1 }, - { 185, 181, 46, 0 }, - { 135, 178, 91, 1 }, }, - { { 62, 95, 252, 0 }, - { 245, 172, 245, 1 }, - { 31, 253, 62, 0 }, - { 215, 154, 215, 1 }, }, - { { 51, 185, 172, 0 }, - { 6, 184, 243, 1 }, - { 26, 206, 230, 0 }, - { 231, 142, 176, 0 }, }, - { { 51, 84, 174, 0 }, - { 69, 178, 240, 1 }, - { 58, 149, 102, 0 }, - { 135, 166, 209, 0 }, }, - { { 63, 25, 160, 0 }, - { 132, 184, 229, 0 }, - { 2, 204, 126, 0 }, - { 83, 142, 144, 1 }, }, - { { 59, 173, 97, 1 }, - { 143, 252, 131, 0 }, - { 195, 90, 238, 0 }, - { 96, 159, 248, 1 }, }, - { { 59, 112, 47, 1 }, - { 204, 242, 210, 1 }, - { 250, 7, 110, 0 }, - { 165, 167, 153, 1 }, }, - { { 59, 235, 58, 1 }, - { 254, 186, 131, 1 }, - { 174, 107, 238, 0 }, - { 224, 174, 191, 1 }, }, - { { 64, 83, 90, 0 }, - { 112, 7, 65, 1 }, - { 45, 101, 1, 0 }, - { 193, 112, 7, 0 }, }, - { { 65, 152, 22, 0 }, - { 18, 27, 80, 0 }, - { 52, 12, 193, 0 }, - { 5, 108, 36, 0 }, }, - { { 65, 143, 177, 0 }, - { 51, 217, 33, 0 }, - { 70, 248, 193, 0 }, - { 66, 77, 230, 0 }, }, - { { 69, 217, 33, 1 }, - { 74, 217, 69, 0 }, - { 194, 77, 209, 0 }, - { 81, 77, 169, 0 }, }, - { { 69, 235, 1, 0 }, - { 98, 89, 7, 0 }, - { 64, 107, 209, 0 }, - { 112, 77, 35, 0 }, }, - { { 73, 157, 82, 0 }, - { 147, 31, 65, 0 }, - { 37, 92, 201, 0 }, - { 65, 124, 100, 1 }, }, - { { 66, 56, 79, 1 }, - { 8, 79, 210, 1 }, - { 249, 14, 33, 0 }, - { 165, 249, 8, 0 }, }, - { { 74, 166, 163, 1 }, - { 171, 195, 162, 0 }, - { 226, 178, 169, 0 }, - { 34, 225, 234, 1 }, }, - { { 74, 197, 42, 1 }, - { 203, 131, 129, 1 }, - { 170, 81, 169, 0 }, - { 192, 224, 233, 1 }, }, - { { 74, 200, 115, 0 }, - { 210, 207, 128, 0 }, - { 103, 9, 169, 0 }, - { 0, 249, 165, 1 }, }, - { { 71, 180, 198, 1 }, - { 11, 23, 246, 0 }, - { 177, 150, 241, 0 }, - { 55, 244, 104, 0 }, }, - { { 67, 147, 93, 0 }, - { 50, 85, 209, 1 }, - { 93, 100, 225, 0 }, - { 197, 213, 38, 0 }, }, - { { 67, 120, 117, 0 }, - { 80, 221, 210, 0 }, - { 87, 15, 97, 0 }, - { 37, 221, 133, 0 }, }, - { { 79, 58, 175, 1 }, - { 168, 219, 246, 1 }, - { 250, 174, 121, 0 }, - { 183, 237, 138, 1 }, }, - { { 79, 135, 68, 1 }, - { 171, 21, 149, 0 }, - { 145, 112, 249, 0 }, - { 84, 212, 106, 1 }, }, - { { 79, 135, 223, 0 }, - { 179, 87, 181, 1 }, - { 125, 240, 249, 0 }, - { 214, 245, 102, 1 }, }, - { { 79, 196, 222, 1 }, - { 219, 23, 180, 1 }, - { 189, 145, 249, 0 }, - { 150, 244, 109, 1 }, }, - { { 84, 31, 71, 0 }, - { 37, 79, 85, 0 }, - { 113, 124, 21, 0 }, - { 85, 121, 82, 0 }, }, - { { 80, 31, 148, 0 }, - { 53, 9, 113, 0 }, - { 20, 252, 5, 0 }, - { 71, 72, 86, 0 }, }, - { { 92, 145, 67, 0 }, - { 134, 71, 69, 0 }, - { 97, 68, 157, 0 }, - { 81, 113, 48, 1 }, }, - { { 88, 189, 239, 1 }, - { 143, 207, 115, 1 }, - { 251, 222, 141, 0 }, - { 231, 121, 248, 1 }, }, - { { 92, 221, 7, 1 }, - { 207, 75, 85, 0 }, - { 240, 93, 157, 0 }, - { 85, 105, 121, 1 }, }, - { { 92, 102, 88, 1 }, - { 253, 5, 6, 1 }, - { 141, 51, 29, 0 }, - { 176, 80, 95, 1 }, }, - { { 92, 219, 50, 1 }, - { 254, 139, 69, 0 }, - { 166, 109, 157, 0 }, - { 81, 104, 191, 1 }, }, - { { 85, 69, 212, 0 }, - { 85, 21, 53, 0 }, - { 21, 209, 85, 0 }, - { 86, 84, 85, 0 }, }, - { { 81, 68, 62, 0 }, - { 85, 147, 16, 1 }, - { 62, 17, 69, 0 }, - { 132, 100, 213, 0 }, }, - { { 81, 231, 230, 0 }, - { 103, 151, 51, 0 }, - { 51, 243, 197, 0 }, - { 102, 116, 243, 0 }, }, - { { 89, 11, 167, 0 }, - { 164, 219, 49, 0 }, - { 114, 232, 77, 0 }, - { 70, 109, 146, 1 }, }, - { { 93, 186, 56, 1 }, - { 190, 153, 70, 1 }, - { 142, 46, 221, 0 }, - { 177, 76, 190, 1 }, }, - { { 93, 166, 55, 1 }, - { 191, 211, 22, 0 }, - { 246, 50, 221, 0 }, - { 52, 101, 254, 1 }, }, - { { 89, 249, 149, 0 }, - { 214, 89, 115, 0 }, - { 84, 207, 205, 0 }, - { 103, 77, 53, 1 }, }, - { { 93, 255, 236, 0 }, - { 231, 157, 119, 1 }, - { 27, 255, 221, 0 }, - { 247, 92, 243, 1 }, }, - { { 82, 157, 58, 0 }, - { 23, 139, 193, 1 }, - { 46, 92, 165, 0 }, - { 193, 232, 244, 0 }, }, - { { 86, 58, 151, 0 }, - { 52, 75, 246, 0 }, - { 116, 174, 53, 0 }, - { 55, 233, 22, 0 }, }, - { { 82, 99, 34, 0 }, - { 100, 131, 131, 0 }, - { 34, 99, 37, 0 }, - { 96, 224, 147, 0 }, }, - { { 82, 203, 49, 1 }, - { 126, 201, 129, 0 }, - { 198, 105, 165, 0 }, - { 64, 201, 191, 0 }, }, - { { 90, 139, 204, 1 }, - { 174, 13, 177, 1 }, - { 153, 232, 173, 0 }, - { 198, 216, 58, 1 }, }, - { { 83, 33, 106, 0 }, - { 4, 151, 131, 1 }, - { 43, 66, 101, 0 }, - { 224, 244, 144, 0 }, }, - { { 87, 245, 17, 0 }, - { 87, 81, 199, 0 }, - { 68, 87, 245, 0 }, - { 113, 197, 117, 0 }, }, - { { 95, 220, 33, 0 }, - { 199, 217, 196, 0 }, - { 66, 29, 253, 0 }, - { 17, 205, 241, 1 }, }, - { { 96, 140, 28, 0 }, - { 19, 41, 16, 1 }, - { 28, 24, 131, 0 }, - { 132, 74, 100, 0 }, }, - { { 96, 162, 213, 1 }, - { 58, 101, 50, 0 }, - { 213, 162, 131, 0 }, - { 38, 83, 46, 0 }, }, - { { 96, 222, 5, 1 }, - { 107, 105, 80, 0 }, - { 208, 61, 131, 0 }, - { 5, 75, 107, 0 }, }, - { { 108, 76, 110, 0 }, - { 193, 175, 20, 1 }, - { 59, 25, 27, 0 }, - { 148, 122, 193, 1 }, }, - { { 104, 82, 12, 0 }, - { 224, 33, 80, 1 }, - { 24, 37, 11, 0 }, - { 133, 66, 3, 1 }, }, - { { 101, 59, 167, 0 }, - { 32, 251, 119, 0 }, - { 114, 238, 83, 0 }, - { 119, 111, 130, 0 }, }, - { { 97, 170, 234, 0 }, - { 34, 191, 34, 1 }, - { 43, 170, 195, 0 }, - { 162, 126, 162, 0 }, }, - { { 101, 113, 110, 1 }, - { 72, 183, 87, 1 }, - { 187, 71, 83, 0 }, - { 245, 118, 137, 0 }, }, - { { 101, 124, 89, 1 }, - { 89, 125, 70, 1 }, - { 205, 31, 83, 0 }, - { 177, 95, 77, 0 }, }, - { { 105, 131, 46, 1 }, - { 170, 179, 17, 1 }, - { 186, 96, 203, 0 }, - { 196, 102, 170, 1 }, }, - { { 109, 196, 12, 0 }, - { 195, 49, 20, 1 }, - { 24, 17, 219, 0 }, - { 148, 70, 97, 1 }, }, - { { 109, 210, 20, 1 }, - { 250, 49, 84, 0 }, - { 148, 37, 219, 0 }, - { 21, 70, 47, 1 }, }, - { { 98, 150, 165, 1 }, - { 43, 225, 240, 0 }, - { 210, 180, 163, 0 }, - { 7, 195, 234, 0 }, }, - { { 98, 117, 38, 1 }, - { 73, 163, 211, 0 }, - { 178, 87, 35, 0 }, - { 101, 226, 201, 0 }, }, - { { 98, 100, 214, 1 }, - { 89, 39, 178, 0 }, - { 181, 147, 35, 0 }, - { 38, 242, 77, 0 }, }, - { { 98, 91, 220, 1 }, - { 120, 45, 241, 1 }, - { 157, 237, 35, 0 }, - { 199, 218, 15, 0 }, }, - { { 110, 51, 2, 1 }, - { 168, 35, 199, 0 }, - { 160, 102, 59, 0 }, - { 113, 226, 10, 1 }, }, - { { 110, 90, 137, 0 }, - { 224, 105, 228, 1 }, - { 72, 173, 59, 0 }, - { 147, 203, 3, 1 }, }, - { { 99, 209, 212, 0 }, - { 82, 53, 241, 0 }, - { 21, 197, 227, 0 }, - { 71, 214, 37, 0 }, }, - { { 99, 75, 129, 1 }, - { 104, 121, 161, 0 }, - { 192, 233, 99, 0 }, - { 66, 207, 11, 0 }, }, - { { 107, 56, 145, 1 }, - { 152, 121, 226, 0 }, - { 196, 142, 107, 0 }, - { 35, 207, 12, 1 }, }, - { { 107, 122, 42, 0 }, - { 224, 187, 194, 1 }, - { 42, 47, 107, 0 }, - { 161, 238, 131, 1 }, }, - { { 116, 56, 51, 0 }, - { 20, 235, 70, 0 }, - { 102, 14, 23, 0 }, - { 49, 107, 148, 0 }, }, - { { 112, 6, 44, 0 }, - { 37, 161, 16, 1 }, - { 26, 48, 7, 0 }, - { 132, 66, 210, 0 }, }, - { { 116, 170, 141, 1 }, - { 46, 105, 54, 1 }, - { 216, 170, 151, 0 }, - { 182, 75, 58, 0 }, }, - { { 116, 76, 143, 0 }, - { 69, 107, 52, 1 }, - { 120, 153, 23, 0 }, - { 150, 107, 81, 0 }, }, - { { 124, 183, 167, 0 }, - { 167, 227, 119, 0 }, - { 114, 246, 159, 0 }, - { 119, 99, 242, 1 }, }, - { { 120, 3, 22, 1 }, - { 188, 35, 17, 0 }, - { 180, 96, 15, 0 }, - { 68, 98, 30, 1 }, }, - { { 124, 199, 198, 1 }, - { 239, 39, 53, 0 }, - { 177, 241, 159, 0 }, - { 86, 114, 123, 1 }, }, - { { 117, 182, 4, 1 }, - { 47, 49, 86, 0 }, - { 144, 54, 215, 0 }, - { 53, 70, 122, 0 }, }, - { { 113, 254, 101, 0 }, - { 103, 253, 82, 0 }, - { 83, 63, 199, 0 }, - { 37, 95, 243, 0 }, }, - { { 113, 79, 154, 1 }, - { 125, 59, 33, 1 }, - { 172, 249, 71, 0 }, - { 194, 110, 95, 0 }, }, - { { 121, 32, 119, 0 }, - { 148, 247, 18, 0 }, - { 119, 2, 79, 0 }, - { 36, 119, 148, 1 }, }, - { { 125, 121, 205, 0 }, - { 196, 125, 119, 1 }, - { 89, 207, 95, 0 }, - { 247, 95, 17, 1 }, }, - { { 125, 67, 92, 0 }, - { 244, 53, 21, 1 }, - { 29, 97, 95, 0 }, - { 212, 86, 23, 1 }, }, - { { 125, 127, 59, 0 }, - { 245, 251, 71, 1 }, - { 110, 127, 95, 0 }, - { 241, 111, 215, 1 }, }, - { { 118, 85, 8, 0 }, - { 69, 33, 197, 1 }, - { 8, 85, 55, 0 }, - { 209, 194, 81, 0 }, }, - { { 122, 152, 199, 0 }, - { 134, 111, 240, 0 }, - { 113, 140, 175, 0 }, - { 7, 251, 48, 1 }, }, - { { 126, 19, 192, 0 }, - { 164, 37, 229, 0 }, - { 1, 228, 63, 0 }, - { 83, 210, 18, 1 }, }, - { { 126, 94, 89, 1 }, - { 253, 109, 196, 1 }, - { 205, 61, 63, 0 }, - { 145, 219, 95, 1 }, }, - { { 115, 36, 132, 0 }, - { 5, 49, 178, 0 }, - { 16, 146, 103, 0 }, - { 38, 198, 80, 0 }, }, - { { 115, 46, 39, 1 }, - { 45, 251, 146, 0 }, - { 242, 58, 103, 0 }, - { 36, 239, 218, 0 }, }, - { { 115, 139, 84, 1 }, - { 62, 61, 145, 0 }, - { 149, 104, 231, 0 }, - { 68, 222, 62, 0 }, }, - { { 132, 4, 34, 0 }, - { 1, 130, 12, 0 }, - { 34, 16, 16, 1 }, - { 24, 32, 192, 0 }, }, - { { 128, 232, 46, 0 }, - { 66, 138, 26, 1 }, - { 58, 11, 128, 1 }, - { 172, 40, 161, 0 }, }, - { { 128, 237, 48, 0 }, - { 83, 136, 11, 0 }, - { 6, 91, 128, 1 }, - { 104, 8, 229, 0 }, }, - { { 140, 53, 96, 0 }, - { 129, 132, 79, 0 }, - { 3, 86, 24, 1 }, - { 121, 16, 192, 1 }, }, - { { 140, 120, 240, 1 }, - { 216, 140, 110, 0 }, - { 135, 143, 24, 1 }, - { 59, 24, 141, 1 }, }, - { { 136, 194, 128, 1 }, - { 234, 0, 40, 0 }, - { 128, 161, 136, 1 }, - { 10, 0, 43, 1 }, }, - { { 129, 26, 100, 1 }, - { 40, 156, 88, 0 }, - { 147, 44, 64, 1 }, - { 13, 28, 138, 0 }, }, - { { 129, 38, 163, 0 }, - { 33, 210, 42, 0 }, - { 98, 178, 64, 1 }, - { 42, 37, 194, 0 }, }, - { { 133, 154, 140, 1 }, - { 42, 24, 124, 1 }, - { 152, 172, 208, 1 }, - { 159, 12, 42, 0 }, }, - { { 137, 19, 23, 1 }, - { 184, 82, 89, 0 }, - { 244, 100, 72, 1 }, - { 77, 37, 14, 1 }, }, - { { 130, 9, 37, 0 }, - { 0, 200, 153, 0 }, - { 82, 72, 32, 1 }, - { 76, 137, 128, 0 }, }, - { { 130, 183, 201, 1 }, - { 43, 68, 235, 1 }, - { 201, 246, 160, 1 }, - { 235, 145, 106, 0 }, }, - { { 142, 185, 191, 1 }, - { 154, 202, 255, 1 }, - { 254, 206, 184, 1 }, - { 255, 169, 172, 1 }, }, - { { 138, 159, 236, 0 }, - { 163, 140, 249, 1 }, - { 27, 252, 168, 1 }, - { 207, 152, 226, 1 }, }, - { { 142, 228, 226, 0 }, - { 195, 134, 174, 0 }, - { 35, 147, 184, 1 }, - { 58, 176, 225, 1 }, }, - { { 135, 32, 232, 0 }, - { 0, 148, 174, 1 }, - { 11, 130, 112, 1 }, - { 186, 148, 128, 0 }, }, - { { 135, 205, 96, 1 }, - { 75, 156, 141, 0 }, - { 131, 89, 240, 1 }, - { 88, 156, 233, 0 }, }, - { { 135, 71, 172, 1 }, - { 105, 144, 189, 1 }, - { 154, 241, 112, 1 }, - { 222, 132, 203, 0 }, }, - { { 139, 10, 91, 0 }, - { 176, 94, 136, 1 }, - { 109, 40, 104, 1 }, - { 136, 189, 6, 1 }, }, - { { 139, 92, 190, 1 }, - { 217, 154, 248, 1 }, - { 190, 157, 104, 1 }, - { 143, 172, 205, 1 }, }, - { { 143, 213, 180, 0 }, - { 211, 144, 253, 0 }, - { 22, 213, 248, 1 }, - { 95, 132, 229, 1 }, }, - { { 139, 118, 41, 0 }, - { 225, 208, 202, 1 }, - { 74, 55, 104, 1 }, - { 169, 133, 195, 1 }, }, - { { 148, 51, 175, 0 }, - { 36, 194, 127, 1 }, - { 122, 230, 20, 1 }, - { 255, 33, 146, 0 }, }, - { { 144, 85, 72, 1 }, - { 77, 4, 73, 1 }, - { 137, 85, 4, 1 }, - { 201, 16, 89, 0 }, }, - { { 156, 62, 39, 0 }, - { 165, 202, 94, 0 }, - { 114, 62, 28, 1 }, - { 61, 41, 210, 1 }, }, - { { 152, 151, 159, 0 }, - { 183, 66, 121, 1 }, - { 124, 244, 140, 1 }, - { 207, 33, 118, 1 }, }, - { { 152, 88, 144, 1 }, - { 220, 8, 104, 0 }, - { 132, 141, 12, 1 }, - { 11, 8, 29, 1 }, }, - { { 149, 182, 31, 0 }, - { 55, 82, 94, 1 }, - { 124, 54, 212, 1 }, - { 189, 37, 118, 0 }, }, - { { 145, 64, 55, 0 }, - { 84, 210, 24, 0 }, - { 118, 1, 68, 1 }, - { 12, 37, 149, 0 }, }, - { { 157, 179, 128, 0 }, - { 166, 16, 111, 0 }, - { 0, 230, 220, 1 }, - { 123, 4, 50, 1 }, }, - { { 153, 65, 137, 1 }, - { 204, 80, 41, 1 }, - { 200, 193, 76, 1 }, - { 202, 5, 25, 1 }, }, - { { 146, 173, 38, 0 }, - { 7, 138, 155, 0 }, - { 50, 90, 164, 1 }, - { 108, 168, 240, 0 }, }, - { { 146, 101, 228, 1 }, - { 77, 132, 187, 0 }, - { 147, 211, 36, 1 }, - { 110, 144, 217, 0 }, }, - { { 146, 111, 141, 1 }, - { 109, 72, 187, 1 }, - { 216, 251, 36, 1 }, - { 238, 137, 91, 0 }, }, - { { 150, 94, 153, 0 }, - { 117, 72, 236, 1 }, - { 76, 189, 52, 1 }, - { 155, 137, 87, 0 }, }, - { { 154, 11, 77, 0 }, - { 164, 76, 153, 1 }, - { 89, 104, 44, 1 }, - { 204, 153, 18, 1 }, }, - { { 154, 221, 17, 0 }, - { 215, 72, 201, 0 }, - { 68, 93, 172, 1 }, - { 73, 137, 117, 1 }, }, - { { 147, 246, 156, 1 }, - { 127, 16, 250, 1 }, - { 156, 183, 228, 1 }, - { 175, 132, 127, 0 }, }, - { { 159, 52, 189, 1 }, - { 157, 208, 254, 1 }, - { 222, 150, 124, 1 }, - { 191, 133, 220, 1 }, }, - { { 159, 80, 9, 0 }, - { 196, 80, 204, 1 }, - { 72, 5, 124, 1 }, - { 153, 133, 17, 1 }, }, - { { 160, 153, 27, 1 }, - { 26, 106, 73, 1 }, - { 236, 76, 130, 1 }, - { 201, 43, 44, 0 }, }, - { { 164, 15, 234, 0 }, - { 33, 174, 45, 1 }, - { 43, 248, 18, 1 }, - { 218, 58, 194, 0 }, }, - { { 160, 15, 83, 1 }, - { 57, 110, 9, 0 }, - { 229, 120, 2, 1 }, - { 72, 59, 78, 0 }, }, - { { 168, 2, 105, 1 }, - { 168, 228, 8, 1 }, - { 203, 32, 10, 1 }, - { 136, 19, 138, 1 }, }, - { { 172, 27, 205, 1 }, - { 168, 108, 125, 1 }, - { 217, 236, 26, 1 }, - { 223, 27, 10, 1 }, }, - { { 172, 135, 77, 0 }, - { 163, 100, 29, 1 }, - { 89, 112, 154, 1 }, - { 220, 19, 98, 1 }, }, - { { 172, 118, 200, 0 }, - { 225, 36, 110, 1 }, - { 9, 183, 26, 1 }, - { 187, 18, 67, 1 }, }, - { { 165, 68, 167, 0 }, - { 65, 242, 60, 0 }, - { 114, 145, 82, 1 }, - { 30, 39, 193, 0 }, }, - { { 161, 244, 92, 0 }, - { 83, 52, 90, 1 }, - { 29, 23, 194, 1 }, - { 173, 22, 101, 0 }, }, - { { 169, 157, 169, 0 }, - { 131, 248, 105, 1 }, - { 74, 220, 202, 1 }, - { 203, 15, 224, 1 }, }, - { { 169, 135, 255, 0 }, - { 179, 246, 57, 1 }, - { 127, 240, 202, 1 }, - { 206, 55, 230, 1 }, }, - { { 169, 71, 98, 1 }, - { 233, 182, 9, 0 }, - { 163, 113, 74, 1 }, - { 72, 54, 203, 1 }, }, - { { 166, 129, 114, 1 }, - { 26, 166, 141, 0 }, - { 167, 64, 178, 1 }, - { 88, 178, 172, 0 }, }, - { { 166, 249, 172, 1 }, - { 74, 168, 255, 1 }, - { 154, 207, 178, 1 }, - { 255, 138, 169, 0 }, }, - { { 162, 196, 38, 0 }, - { 67, 162, 152, 0 }, - { 50, 17, 162, 1 }, - { 12, 162, 225, 0 }, }, - { { 170, 53, 101, 1 }, - { 137, 228, 219, 0 }, - { 211, 86, 42, 1 }, - { 109, 147, 200, 1 }, }, - { { 170, 168, 102, 0 }, - { 130, 174, 154, 0 }, - { 51, 10, 170, 1 }, - { 44, 186, 160, 1 }, }, - { { 170, 200, 143, 0 }, - { 194, 106, 184, 1 }, - { 120, 137, 170, 1 }, - { 142, 171, 33, 1 }, }, - { { 167, 110, 148, 1 }, - { 121, 56, 190, 0 }, - { 148, 187, 114, 1 }, - { 62, 142, 79, 0 }, }, - { { 175, 4, 36, 1 }, - { 137, 176, 156, 0 }, - { 146, 16, 122, 1 }, - { 28, 134, 200, 1 }, }, - { { 176, 65, 44, 0 }, - { 68, 160, 25, 1 }, - { 26, 65, 6, 1 }, - { 204, 2, 145, 0 }, }, - { { 176, 208, 227, 0 }, - { 70, 230, 104, 0 }, - { 99, 133, 134, 1 }, - { 11, 51, 177, 0 }, }, - { { 176, 237, 129, 1 }, - { 79, 104, 43, 0 }, - { 192, 219, 134, 1 }, - { 106, 11, 121, 0 }, }, - { { 180, 231, 236, 0 }, - { 103, 164, 63, 1 }, - { 27, 243, 150, 1 }, - { 254, 18, 243, 0 }, }, - { { 184, 160, 236, 1 }, - { 142, 164, 58, 1 }, - { 155, 130, 142, 1 }, - { 174, 18, 184, 1 }, }, - { { 184, 188, 60, 1 }, - { 159, 168, 90, 1 }, - { 158, 30, 142, 1 }, - { 173, 10, 252, 1 }, }, - { { 177, 102, 224, 1 }, - { 109, 180, 42, 0 }, - { 131, 179, 70, 1 }, - { 42, 22, 219, 0 }, }, - { { 189, 49, 10, 1 }, - { 140, 50, 79, 1 }, - { 168, 70, 94, 1 }, - { 249, 38, 24, 1 }, }, - { { 189, 63, 186, 1 }, - { 189, 186, 111, 1 }, - { 174, 254, 94, 1 }, - { 251, 46, 222, 1 }, }, - { { 185, 190, 220, 0 }, - { 183, 60, 122, 1 }, - { 29, 190, 206, 1 }, - { 175, 30, 118, 1 }, }, - { { 178, 58, 240, 1 }, - { 60, 172, 234, 0 }, - { 135, 174, 38, 1 }, - { 43, 154, 158, 0 }, }, - { { 182, 207, 169, 0 }, - { 103, 232, 173, 1 }, - { 74, 249, 182, 1 }, - { 218, 139, 243, 0 }, }, - { { 186, 35, 226, 1 }, - { 172, 166, 171, 0 }, - { 163, 226, 46, 1 }, - { 106, 178, 154, 1 }, }, - { { 183, 36, 171, 1 }, - { 13, 242, 174, 1 }, - { 234, 146, 118, 1 }, - { 186, 167, 216, 0 }, }, - { { 183, 41, 251, 0 }, - { 20, 254, 175, 1 }, - { 111, 202, 118, 1 }, - { 250, 191, 148, 0 }, }, - { { 179, 174, 8, 0 }, - { 39, 56, 138, 1 }, - { 8, 58, 230, 1 }, - { 168, 142, 114, 0 }, }, - { { 183, 86, 202, 1 }, - { 109, 54, 236, 1 }, - { 169, 181, 118, 1 }, - { 155, 182, 91, 0 }, }, - { { 191, 168, 244, 0 }, - { 150, 188, 190, 0 }, - { 23, 138, 254, 1 }, - { 62, 158, 180, 1 }, }, - { { 191, 148, 18, 1 }, - { 159, 50, 204, 0 }, - { 164, 20, 254, 1 }, - { 25, 166, 124, 1 }, }, - { { 191, 122, 64, 1 }, - { 236, 60, 206, 0 }, - { 129, 47, 126, 1 }, - { 57, 158, 27, 1 }, }, - { { 196, 133, 200, 0 }, - { 3, 5, 45, 1 }, - { 9, 208, 145, 1 }, - { 218, 80, 96, 0 }, }, - { { 192, 14, 9, 1 }, - { 41, 73, 8, 1 }, - { 200, 56, 1, 1 }, - { 136, 73, 74, 0 }, }, - { { 192, 112, 254, 0 }, - { 80, 135, 122, 1 }, - { 63, 135, 1, 1 }, - { 175, 112, 133, 0 }, }, - { { 204, 116, 17, 0 }, - { 209, 65, 78, 0 }, - { 68, 23, 25, 1 }, - { 57, 65, 69, 1 }, }, - { { 193, 8, 90, 1 }, - { 24, 31, 8, 1 }, - { 173, 8, 65, 1 }, - { 136, 124, 12, 0 }, }, - { { 193, 47, 130, 1 }, - { 41, 27, 43, 0 }, - { 160, 250, 65, 1 }, - { 106, 108, 74, 0 }, }, - { { 193, 35, 120, 0 }, - { 48, 149, 11, 1 }, - { 15, 98, 65, 1 }, - { 232, 84, 134, 0 }, }, - { { 198, 52, 219, 1 }, - { 25, 71, 238, 1 }, - { 237, 150, 49, 1 }, - { 187, 241, 76, 0 }, }, - { { 198, 164, 244, 1 }, - { 27, 133, 190, 0 }, - { 151, 146, 177, 1 }, - { 62, 208, 236, 0 }, }, - { { 194, 228, 25, 0 }, - { 83, 65, 138, 1 }, - { 76, 19, 161, 1 }, - { 168, 193, 101, 0 }, }, - { { 195, 29, 35, 0 }, - { 1, 219, 201, 0 }, - { 98, 92, 97, 1 }, - { 73, 237, 192, 0 }, }, - { { 195, 242, 196, 1 }, - { 106, 21, 250, 0 }, - { 145, 167, 225, 1 }, - { 47, 212, 43, 0 }, }, - { { 199, 95, 223, 0 }, - { 113, 95, 253, 1 }, - { 125, 253, 113, 1 }, - { 223, 253, 71, 0 }, }, - { { 203, 101, 189, 0 }, - { 209, 209, 187, 1 }, - { 94, 211, 105, 1 }, - { 238, 197, 197, 1 }, }, - { { 203, 199, 15, 1 }, - { 235, 83, 153, 1 }, - { 248, 113, 233, 1 }, - { 204, 229, 107, 1 }, }, - { { 207, 246, 185, 0 }, - { 243, 209, 238, 1 }, - { 78, 183, 249, 1 }, - { 187, 197, 231, 1 }, }, - { { 212, 84, 239, 0 }, - { 69, 199, 124, 1 }, - { 123, 149, 21, 1 }, - { 159, 113, 209, 0 }, }, - { { 212, 251, 220, 0 }, - { 118, 13, 127, 1 }, - { 29, 239, 149, 1 }, - { 255, 88, 55, 0 }, }, - { { 220, 232, 84, 0 }, - { 214, 13, 30, 0 }, - { 21, 11, 157, 1 }, - { 60, 88, 53, 1 }, }, - { { 213, 177, 150, 0 }, - { 22, 19, 127, 0 }, - { 52, 198, 213, 1 }, - { 127, 100, 52, 0 }, }, - { { 209, 159, 7, 1 }, - { 47, 91, 89, 0 }, - { 240, 124, 197, 1 }, - { 77, 109, 122, 0 }, }, - { { 209, 93, 126, 1 }, - { 93, 159, 89, 1 }, - { 191, 93, 69, 1 }, - { 205, 124, 221, 0 }, }, - { { 217, 164, 134, 1 }, - { 143, 19, 58, 0 }, - { 176, 146, 205, 1 }, - { 46, 100, 120, 1 }, }, - { { 221, 9, 48, 1 }, - { 156, 153, 13, 0 }, - { 134, 72, 93, 1 }, - { 88, 76, 156, 1 }, }, - { { 217, 180, 57, 1 }, - { 159, 209, 74, 1 }, - { 206, 22, 205, 1 }, - { 169, 69, 252, 1 }, }, - { { 221, 171, 105, 1 }, - { 174, 221, 15, 1 }, - { 203, 106, 221, 1 }, - { 248, 93, 186, 1 }, }, - { { 217, 203, 66, 0 }, - { 230, 31, 9, 0 }, - { 33, 105, 205, 1 }, - { 72, 124, 51, 1 }, }, - { { 210, 33, 13, 0 }, - { 4, 65, 155, 1 }, - { 88, 66, 37, 1 }, - { 236, 193, 16, 0 }, }, - { { 214, 73, 4, 0 }, - { 68, 9, 157, 0 }, - { 16, 73, 53, 1 }, - { 92, 200, 17, 0 }, }, - { { 210, 216, 219, 0 }, - { 86, 79, 232, 1 }, - { 109, 141, 165, 1 }, - { 139, 249, 53, 0 }, }, - { { 218, 63, 69, 1 }, - { 173, 77, 219, 0 }, - { 209, 126, 45, 1 }, - { 109, 217, 90, 1 }, }, - { { 218, 125, 218, 0 }, - { 213, 15, 235, 1 }, - { 45, 223, 45, 1 }, - { 235, 248, 85, 1 }, }, - { { 218, 211, 230, 0 }, - { 230, 135, 249, 0 }, - { 51, 229, 173, 1 }, - { 79, 240, 179, 1 }, }, - { { 211, 51, 189, 0 }, - { 52, 209, 251, 1 }, - { 94, 230, 101, 1 }, - { 239, 197, 150, 0 }, }, - { { 215, 225, 237, 1 }, - { 78, 213, 191, 1 }, - { 219, 195, 245, 1 }, - { 254, 213, 185, 0 }, }, - { { 219, 197, 122, 0 }, - { 215, 151, 137, 1 }, - { 47, 81, 237, 1 }, - { 200, 244, 245, 1 }, }, - { { 224, 128, 59, 1 }, - { 26, 227, 8, 1 }, - { 238, 0, 131, 1 }, - { 136, 99, 172, 0 }, }, - { { 224, 207, 105, 1 }, - { 107, 237, 9, 1 }, - { 203, 121, 131, 1 }, - { 200, 91, 235, 0 }, }, - { { 228, 71, 48, 1 }, - { 121, 161, 13, 0 }, - { 134, 113, 19, 1 }, - { 88, 66, 207, 0 }, }, - { { 232, 29, 86, 1 }, - { 153, 47, 89, 0 }, - { 181, 92, 11, 1 }, - { 77, 122, 76, 1 }, }, - { { 232, 243, 72, 1 }, - { 234, 37, 75, 1 }, - { 137, 103, 139, 1 }, - { 233, 82, 43, 1 }, }, - { { 232, 254, 175, 0 }, - { 227, 235, 122, 1 }, - { 122, 191, 139, 1 }, - { 175, 107, 227, 1 }, }, - { { 236, 231, 159, 0 }, - { 243, 99, 63, 1 }, - { 124, 243, 155, 1 }, - { 254, 99, 103, 1 }, }, - { { 225, 60, 212, 1 }, - { 25, 61, 122, 0 }, - { 149, 158, 67, 1 }, - { 47, 94, 76, 0 }, }, - { { 229, 204, 106, 1 }, - { 75, 191, 12, 1 }, - { 171, 25, 211, 1 }, - { 152, 126, 233, 0 }, }, - { { 233, 175, 154, 0 }, - { 179, 59, 43, 1 }, - { 44, 250, 203, 1 }, - { 234, 110, 102, 1 }, }, - { { 227, 0, 237, 0 }, - { 0, 245, 184, 1 }, - { 91, 128, 99, 1 }, - { 142, 215, 128, 0 }, }, - { { 231, 177, 14, 0 }, - { 2, 51, 223, 1 }, - { 56, 70, 243, 1 }, - { 253, 230, 32, 0 }, }, - { { 227, 192, 126, 0 }, - { 82, 183, 152, 1 }, - { 63, 1, 227, 1 }, - { 140, 246, 165, 0 }, }, - { { 235, 140, 163, 0 }, - { 131, 251, 168, 0 }, - { 98, 152, 235, 1 }, - { 10, 239, 224, 1 }, }, - { { 235, 159, 109, 1 }, - { 171, 253, 217, 1 }, - { 219, 124, 235, 1 }, - { 205, 223, 234, 1 }, }, - { { 239, 65, 11, 0 }, - { 192, 115, 141, 1 }, - { 104, 65, 123, 1 }, - { 216, 231, 1, 1 }, }, - { { 239, 194, 195, 0 }, - { 226, 119, 172, 0 }, - { 97, 161, 251, 1 }, - { 26, 247, 35, 1 }, }, - { { 240, 168, 32, 0 }, - { 6, 169, 10, 0 }, - { 2, 10, 135, 1 }, - { 40, 74, 176, 0 }, }, - { { 244, 25, 211, 0 }, - { 20, 111, 109, 0 }, - { 101, 204, 23, 1 }, - { 91, 123, 20, 0 }, }, - { { 244, 133, 191, 1 }, - { 31, 227, 61, 1 }, - { 254, 208, 151, 1 }, - { 222, 99, 252, 0 }, }, - { { 240, 106, 204, 0 }, - { 100, 45, 58, 1 }, - { 25, 171, 7, 1 }, - { 174, 90, 19, 0 }, }, - { { 240, 123, 107, 1 }, - { 108, 239, 75, 1 }, - { 235, 111, 7, 1 }, - { 233, 123, 155, 0 }, }, - { { 244, 251, 170, 0 }, - { 102, 171, 111, 1 }, - { 42, 239, 151, 1 }, - { 251, 106, 179, 0 }, }, - { { 252, 198, 47, 0 }, - { 231, 227, 28, 1 }, - { 122, 49, 159, 1 }, - { 156, 99, 243, 1 }, }, - { { 248, 111, 16, 0 }, - { 245, 41, 11, 0 }, - { 4, 123, 15, 1 }, - { 104, 74, 87, 1 }, }, - { { 252, 127, 120, 1 }, - { 253, 173, 79, 1 }, - { 143, 127, 31, 1 }, - { 249, 90, 223, 1 }, }, - { { 241, 171, 217, 0 }, - { 54, 125, 43, 1 }, - { 77, 234, 199, 1 }, - { 234, 95, 54, 0 }, }, - { { 245, 81, 143, 1 }, - { 76, 115, 125, 1 }, - { 248, 197, 87, 1 }, - { 223, 103, 25, 0 }, }, - { { 241, 248, 166, 1 }, - { 78, 187, 122, 0 }, - { 178, 143, 199, 1 }, - { 47, 110, 185, 0 }, }, - { { 241, 86, 24, 0 }, - { 117, 49, 72, 1 }, - { 12, 53, 71, 1 }, - { 137, 70, 87, 0 }, }, - { { 253, 132, 196, 0 }, - { 135, 53, 60, 0 }, - { 17, 144, 223, 1 }, - { 30, 86, 112, 1 }, }, - { { 249, 141, 114, 1 }, - { 159, 191, 9, 0 }, - { 167, 88, 207, 1 }, - { 72, 126, 252, 1 }, }, - { { 253, 15, 85, 1 }, - { 189, 125, 29, 0 }, - { 213, 120, 95, 1 }, - { 92, 95, 94, 1 }, }, - { { 242, 156, 111, 1 }, - { 15, 239, 216, 1 }, - { 251, 28, 167, 1 }, - { 141, 251, 248, 0 }, }, - { { 246, 136, 24, 1 }, - { 30, 41, 140, 1 }, - { 140, 8, 183, 1 }, - { 152, 202, 60, 0 }, }, - { { 246, 7, 197, 0 }, - { 37, 101, 189, 0 }, - { 81, 240, 55, 1 }, - { 94, 211, 82, 0 }, }, - { { 242, 65, 215, 0 }, - { 84, 103, 185, 0 }, - { 117, 193, 39, 1 }, - { 78, 243, 21, 0 }, }, - { { 246, 241, 27, 0 }, - { 86, 99, 207, 1 }, - { 108, 71, 183, 1 }, - { 249, 227, 53, 0 }, }, - { { 242, 230, 203, 1 }, - { 111, 103, 170, 1 }, - { 233, 179, 167, 1 }, - { 170, 243, 123, 0 }, }, - { { 250, 213, 32, 1 }, - { 207, 161, 201, 0 }, - { 130, 85, 175, 1 }, - { 73, 194, 249, 1 }, }, - { { 254, 67, 233, 0 }, - { 228, 229, 173, 1 }, - { 75, 225, 63, 1 }, - { 218, 211, 147, 1 }, }, - { { 243, 251, 142, 0 }, - { 102, 59, 251, 1 }, - { 56, 239, 231, 1 }, - { 239, 238, 51, 0 }, }, - { { 255, 187, 218, 0 }, - { 182, 63, 239, 1 }, - { 45, 238, 255, 1 }, - { 251, 254, 54, 1 }, }, - { { 251, 201, 14, 1 }, - { 206, 59, 153, 1 }, - { 184, 73, 239, 1 }, - { 204, 238, 57, 1 }, }, }; - -static unsigned char DICT_6X6_1000_BYTES[][4][5] = - { { { 30, 61, 216, 42, 6 }, - { 227, 186, 70, 49, 9 }, - { 101, 65, 187, 199, 8 }, - { 152, 198, 37, 220, 7 }, }, - { { 14, 251, 163, 137, 1 }, - { 215, 230, 24, 5, 14 }, - { 137, 28, 93, 247, 0 }, - { 122, 1, 134, 126, 11 }, }, - { { 21, 144, 126, 172, 13 }, - { 236, 105, 87, 80, 6 }, - { 179, 87, 224, 154, 8 }, - { 96, 174, 169, 99, 7 }, }, - { { 201, 27, 48, 105, 14 }, - { 66, 50, 75, 222, 12 }, - { 121, 96, 205, 137, 3 }, - { 55, 189, 36, 196, 2 }, }, - { { 214, 7, 214, 225, 5 }, - { 164, 203, 74, 191, 2 }, - { 168, 118, 190, 6, 11 }, - { 79, 213, 45, 50, 5 }, }, - { { 216, 232, 224, 230, 8 }, - { 43, 140, 19, 138, 15 }, - { 22, 112, 113, 113, 11 }, - { 245, 28, 131, 29, 4 }, }, - { { 66, 104, 180, 31, 5 }, - { 13, 165, 192, 149, 13 }, - { 175, 130, 209, 100, 2 }, - { 186, 144, 58, 91, 0 }, }, - { { 136, 165, 15, 41, 10 }, - { 19, 115, 23, 38, 0 }, - { 89, 79, 10, 81, 1 }, - { 6, 78, 140, 236, 8 }, }, - { { 48, 125, 82, 79, 13 }, - { 109, 110, 97, 60, 9 }, - { 191, 36, 171, 224, 12 }, - { 147, 200, 103, 107, 6 }, }, - { { 60, 47, 52, 179, 12 }, - { 131, 11, 235, 52, 15 }, - { 60, 210, 207, 67, 12 }, - { 242, 205, 125, 12, 1 }, }, - { { 69, 223, 199, 78, 3 }, - { 252, 247, 24, 232, 9 }, - { 199, 46, 63, 186, 2 }, - { 145, 113, 142, 243, 15 }, }, - { { 72, 216, 91, 37, 7 }, - { 126, 84, 86, 148, 8 }, - { 234, 77, 161, 177, 2 }, - { 18, 150, 162, 167, 14 }, }, - { { 113, 5, 88, 252, 6 }, - { 40, 58, 230, 248, 2 }, - { 99, 241, 170, 8, 14 }, - { 65, 246, 117, 193, 4 }, }, - { { 134, 220, 250, 208, 7 }, - { 228, 212, 212, 59, 14 }, - { 224, 181, 243, 182, 1 }, - { 125, 194, 178, 178, 7 }, }, - { { 141, 114, 169, 63, 6 }, - { 219, 180, 206, 70, 5 }, - { 111, 201, 84, 235, 1 }, - { 166, 39, 50, 221, 11 }, }, - { { 162, 184, 157, 205, 14 }, - { 89, 177, 117, 31, 10 }, - { 123, 59, 145, 212, 5 }, - { 95, 138, 232, 217, 10 }, }, - { { 9, 253, 30, 156, 4 }, - { 75, 103, 212, 112, 10 }, - { 35, 151, 139, 249, 0 }, - { 80, 226, 190, 109, 2 }, }, - { { 21, 77, 189, 24, 15 }, - { 148, 191, 197, 112, 12 }, - { 241, 139, 219, 42, 8 }, - { 48, 234, 63, 210, 9 }, }, - { { 48, 10, 49, 14, 2 }, - { 24, 56, 40, 16, 13 }, - { 71, 8, 197, 0, 12 }, - { 176, 129, 65, 193, 8 }, }, - { { 72, 7, 239, 175, 13 }, - { 62, 227, 79, 164, 7 }, - { 191, 95, 126, 1, 2 }, - { 226, 95, 44, 119, 12 }, }, - { { 86, 223, 17, 219, 6 }, - { 208, 62, 216, 189, 11 }, - { 109, 184, 143, 182, 10 }, - { 219, 209, 183, 192, 11 }, }, - { { 102, 136, 50, 116, 12 }, - { 136, 64, 243, 153, 12 }, - { 50, 228, 193, 22, 6 }, - { 57, 156, 240, 33, 1 }, }, - { { 118, 232, 203, 120, 1 }, - { 181, 236, 182, 137, 8 }, - { 129, 237, 49, 118, 14 }, - { 25, 22, 211, 122, 13 }, }, - { { 154, 83, 217, 207, 3 }, - { 126, 190, 12, 31, 3 }, - { 207, 57, 188, 165, 9 }, - { 207, 131, 7, 215, 14 }, }, - { { 169, 203, 132, 2, 4 }, - { 2, 135, 120, 66, 9 }, - { 36, 2, 29, 57, 5 }, - { 148, 33, 238, 20, 0 }, }, - { { 198, 117, 73, 73, 0 }, - { 241, 38, 4, 175, 0 }, - { 9, 41, 42, 230, 3 }, - { 15, 82, 6, 72, 15 }, }, - { { 193, 210, 136, 148, 1 }, - { 76, 132, 156, 194, 2 }, - { 130, 145, 20, 184, 3 }, - { 68, 51, 146, 19, 2 }, }, - { { 231, 72, 8, 82, 11 }, - { 132, 20, 165, 203, 9 }, - { 212, 161, 1, 46, 7 }, - { 157, 58, 82, 130, 1 }, }, - { { 234, 47, 202, 132, 8 }, - { 43, 194, 45, 163, 10 }, - { 18, 21, 63, 69, 7 }, - { 92, 91, 68, 61, 4 }, }, - { { 233, 99, 183, 123, 1 }, - { 23, 231, 170, 222, 5 }, - { 141, 238, 220, 105, 7 }, - { 167, 181, 94, 126, 8 }, }, - { { 250, 54, 101, 42, 15 }, - { 119, 57, 107, 163, 5 }, - { 245, 74, 102, 197, 15 }, - { 172, 93, 105, 206, 14 }, }, - { { 6, 91, 255, 123, 13 }, - { 244, 231, 207, 29, 13 }, - { 189, 239, 253, 166, 0 }, - { 187, 143, 62, 114, 15 }, }, - { { 5, 65, 215, 45, 6 }, - { 184, 247, 66, 84, 0 }, - { 107, 78, 184, 42, 0 }, - { 2, 164, 46, 241, 13 }, }, - { { 12, 247, 36, 106, 2 }, - { 195, 55, 26, 40, 5 }, - { 69, 98, 78, 243, 0 }, - { 161, 69, 142, 204, 3 }, }, - { { 19, 56, 163, 158, 11 }, - { 93, 248, 129, 65, 15 }, - { 215, 156, 81, 204, 8 }, - { 248, 40, 17, 251, 10 }, }, - { { 21, 168, 147, 231, 4 }, - { 153, 200, 82, 92, 11 }, - { 46, 124, 145, 90, 8 }, - { 211, 164, 161, 57, 9 }, }, - { { 58, 65, 126, 233, 14 }, - { 34, 127, 103, 29, 6 }, - { 121, 119, 232, 37, 12 }, - { 107, 142, 111, 228, 4 }, }, - { { 79, 17, 226, 108, 0 }, - { 234, 226, 2, 201, 4 }, - { 3, 100, 120, 143, 2 }, - { 41, 52, 4, 117, 7 }, }, - { { 83, 13, 182, 210, 0 }, - { 0, 203, 128, 249, 15 }, - { 4, 182, 219, 12, 10 }, - { 249, 240, 29, 48, 0 }, }, - { { 88, 155, 250, 227, 4 }, - { 98, 202, 94, 156, 15 }, - { 44, 117, 253, 145, 10 }, - { 243, 151, 165, 52, 6 }, }, - { { 100, 9, 232, 160, 11 }, - { 164, 146, 39, 128, 14 }, - { 208, 81, 121, 2, 6 }, - { 112, 30, 68, 146, 5 }, }, - { { 96, 83, 122, 137, 1 }, - { 100, 102, 44, 148, 6 }, - { 137, 21, 236, 160, 6 }, - { 98, 147, 70, 98, 6 }, }, - { { 97, 89, 6, 155, 10 }, - { 64, 119, 161, 196, 11 }, - { 93, 150, 9, 168, 6 }, - { 210, 56, 94, 224, 2 }, }, - { { 107, 255, 120, 215, 11 }, - { 111, 22, 189, 253, 15 }, - { 222, 177, 239, 253, 6 }, - { 251, 251, 214, 143, 6 }, }, - { { 112, 173, 150, 164, 15 }, - { 13, 219, 115, 176, 10 }, - { 242, 86, 155, 80, 14 }, - { 80, 220, 237, 187, 0 }, }, - { { 117, 132, 111, 113, 10 }, - { 176, 89, 183, 236, 4 }, - { 88, 239, 98, 26, 14 }, - { 35, 126, 217, 160, 13 }, }, - { { 122, 149, 25, 47, 12 }, - { 90, 42, 119, 181, 1 }, - { 63, 73, 138, 149, 14 }, - { 138, 222, 229, 69, 10 }, }, - { { 134, 9, 118, 10, 10 }, - { 160, 115, 1, 19, 13 }, - { 85, 6, 233, 6, 1 }, - { 188, 136, 12, 224, 5 }, }, - { { 138, 45, 68, 195, 15 }, - { 39, 19, 65, 47, 11 }, - { 252, 50, 43, 69, 1 }, - { 223, 72, 44, 142, 4 }, }, - { { 147, 235, 120, 177, 4 }, - { 33, 14, 222, 87, 14 }, - { 40, 209, 237, 124, 9 }, - { 126, 167, 183, 8, 4 }, }, - { { 152, 141, 168, 77, 4 }, - { 10, 170, 84, 46, 12 }, - { 43, 33, 91, 17, 9 }, - { 55, 66, 165, 85, 0 }, }, - { { 158, 222, 43, 60, 8 }, - { 218, 108, 159, 35, 12 }, - { 19, 205, 71, 183, 9 }, - { 60, 79, 147, 101, 11 }, }, - { { 165, 41, 224, 123, 8 }, - { 161, 162, 163, 78, 13 }, - { 29, 224, 121, 74, 5 }, - { 183, 44, 84, 88, 5 }, }, - { { 181, 147, 184, 85, 15 }, - { 204, 154, 253, 94, 4 }, - { 250, 161, 220, 154, 13 }, - { 39, 171, 245, 147, 3 }, }, - { { 183, 248, 228, 38, 15 }, - { 237, 157, 115, 67, 13 }, - { 246, 66, 113, 254, 13 }, - { 188, 44, 235, 155, 7 }, }, - { { 188, 32, 82, 37, 14 }, - { 171, 88, 99, 22, 0 }, - { 122, 68, 160, 67, 13 }, - { 6, 140, 97, 173, 5 }, }, - { { 192, 68, 135, 118, 5 }, - { 28, 197, 194, 170, 1 }, - { 166, 238, 18, 32, 3 }, - { 133, 84, 58, 51, 8 }, }, - { { 196, 195, 36, 37, 9 }, - { 140, 7, 27, 134, 4 }, - { 154, 66, 76, 50, 3 }, - { 38, 29, 142, 3, 1 }, }, - { { 197, 169, 27, 216, 13 }, - { 149, 98, 213, 218, 10 }, - { 177, 189, 137, 90, 3 }, - { 85, 186, 180, 106, 9 }, }, - { { 206, 115, 230, 178, 12 }, - { 227, 199, 203, 131, 7 }, - { 52, 214, 124, 231, 3 }, - { 236, 29, 62, 60, 7 }, }, - { { 205, 12, 166, 39, 2 }, - { 138, 209, 2, 230, 13 }, - { 78, 70, 83, 11, 3 }, - { 182, 116, 8, 181, 1 }, }, - { { 201, 67, 93, 68, 13 }, - { 62, 7, 77, 218, 0 }, - { 178, 43, 172, 41, 3 }, - { 5, 187, 46, 7, 12 }, }, - { { 207, 190, 128, 243, 4 }, - { 195, 128, 218, 239, 11 }, - { 44, 240, 23, 223, 3 }, - { 223, 117, 176, 28, 3 }, }, - { { 229, 125, 21, 135, 7 }, - { 221, 23, 96, 246, 11 }, - { 238, 26, 139, 234, 7 }, - { 214, 240, 110, 139, 11 }, }, - { { 239, 198, 133, 142, 9 }, - { 158, 165, 57, 227, 3 }, - { 151, 26, 22, 63, 7 }, - { 204, 121, 202, 87, 9 }, }, - { { 247, 126, 243, 119, 2 }, - { 249, 220, 170, 255, 13 }, - { 78, 236, 247, 238, 15 }, - { 191, 245, 83, 185, 15 }, }, - { { 44, 228, 63, 37, 4 }, - { 155, 69, 118, 52, 4 }, - { 42, 79, 194, 115, 4 }, - { 34, 198, 234, 45, 9 }, }, - { { 43, 220, 255, 75, 3 }, - { 118, 245, 52, 125, 13 }, - { 205, 47, 243, 189, 4 }, - { 187, 226, 202, 246, 14 }, }, - { { 55, 199, 221, 189, 10 }, - { 184, 191, 191, 117, 2 }, - { 91, 219, 190, 62, 12 }, - { 74, 239, 223, 209, 13 }, }, - { { 161, 162, 84, 224, 15 }, - { 37, 17, 123, 90, 2 }, - { 240, 114, 164, 88, 5 }, - { 69, 173, 232, 138, 4 }, }, - { { 169, 130, 193, 187, 5 }, - { 54, 160, 250, 70, 3 }, - { 173, 216, 52, 25, 5 }, - { 198, 37, 240, 86, 12 }, }, - { { 216, 27, 73, 176, 8 }, - { 114, 10, 143, 130, 10 }, - { 16, 217, 45, 129, 11 }, - { 84, 31, 21, 4, 14 }, }, - { { 3, 88, 41, 248, 6 }, - { 80, 52, 198, 73, 14 }, - { 97, 249, 65, 172, 0 }, - { 121, 38, 50, 192, 10 }, }, - { { 7, 196, 9, 95, 12 }, - { 152, 36, 213, 109, 1 }, - { 63, 169, 2, 62, 0 }, - { 139, 106, 178, 65, 9 }, }, - { { 15, 226, 102, 23, 11 }, - { 175, 85, 153, 69, 5 }, - { 222, 134, 100, 127, 0 }, - { 170, 41, 154, 175, 5 }, }, - { { 20, 72, 54, 68, 1 }, - { 140, 77, 0, 24, 12 }, - { 130, 38, 193, 34, 8 }, - { 49, 128, 11, 35, 1 }, }, - { { 16, 173, 95, 251, 7 }, - { 53, 123, 214, 60, 11 }, - { 237, 255, 171, 80, 8 }, - { 211, 198, 189, 234, 12 }, }, - { { 18, 130, 149, 83, 15 }, - { 20, 153, 217, 29, 1 }, - { 252, 170, 148, 20, 8 }, - { 139, 137, 185, 146, 8 }, }, - { { 22, 225, 49, 132, 12 }, - { 153, 14, 81, 17, 6 }, - { 50, 24, 200, 118, 8 }, - { 104, 136, 167, 9, 9 }, }, - { { 24, 122, 73, 107, 0 }, - { 115, 44, 14, 12, 9 }, - { 13, 105, 37, 225, 8 }, - { 147, 7, 3, 76, 14 }, }, - { { 26, 232, 134, 17, 2 }, - { 3, 221, 144, 5, 8 }, - { 72, 134, 17, 117, 8 }, - { 26, 0, 155, 188, 0 }, }, - { { 25, 19, 174, 10, 1 }, - { 70, 235, 12, 64, 5 }, - { 133, 7, 92, 137, 8 }, - { 160, 35, 13, 118, 2 }, }, - { { 27, 103, 181, 161, 7 }, - { 23, 159, 74, 117, 6 }, - { 232, 90, 222, 109, 8 }, - { 106, 229, 47, 158, 8 }, }, - { { 37, 220, 149, 240, 11 }, - { 212, 149, 179, 120, 10 }, - { 208, 250, 147, 186, 4 }, - { 81, 236, 218, 146, 11 }, }, - { { 40, 137, 97, 247, 6 }, - { 58, 18, 242, 12, 15 }, - { 110, 248, 105, 17, 4 }, - { 243, 4, 244, 133, 12 }, }, - { { 51, 84, 20, 106, 10 }, - { 64, 61, 35, 121, 1 }, - { 85, 98, 130, 172, 12 }, - { 137, 236, 75, 192, 2 }, }, - { { 49, 193, 108, 31, 7 }, - { 44, 63, 244, 68, 5 }, - { 239, 131, 104, 56, 12 }, - { 162, 34, 255, 195, 4 }, }, - { { 51, 203, 24, 198, 6 }, - { 8, 30, 124, 89, 11 }, - { 102, 49, 141, 60, 12 }, - { 217, 163, 231, 129, 0 }, }, - { { 62, 207, 228, 144, 15 }, - { 166, 159, 249, 33, 14 }, - { 240, 146, 127, 55, 12 }, - { 120, 73, 255, 150, 5 }, }, - { { 70, 69, 24, 163, 15 }, - { 132, 22, 71, 181, 3 }, - { 252, 81, 138, 38, 2 }, - { 202, 222, 38, 130, 1 }, }, - { { 68, 186, 112, 182, 7 }, - { 237, 16, 218, 144, 15 }, - { 230, 208, 229, 210, 2 }, - { 240, 149, 176, 139, 7 }, }, - { { 65, 156, 98, 62, 8 }, - { 104, 96, 147, 224, 13 }, - { 23, 196, 99, 152, 2 }, - { 176, 124, 144, 97, 6 }, }, - { { 72, 209, 145, 74, 1 }, - { 86, 166, 16, 152, 1 }, - { 133, 40, 152, 177, 2 }, - { 129, 144, 134, 86, 10 }, }, - { { 84, 244, 153, 246, 13 }, - { 221, 140, 215, 184, 3 }, - { 182, 249, 146, 242, 10 }, - { 193, 222, 179, 27, 11 }, }, - { { 87, 90, 156, 129, 3 }, - { 196, 157, 12, 213, 10 }, - { 200, 19, 149, 174, 10 }, - { 90, 179, 11, 146, 3 }, }, - { { 85, 131, 85, 178, 12 }, - { 176, 11, 219, 208, 3 }, - { 52, 218, 172, 26, 10 }, - { 192, 189, 189, 0, 13 }, }, - { { 87, 183, 118, 16, 15 }, - { 229, 91, 217, 241, 4 }, - { 240, 134, 238, 222, 10 }, - { 40, 249, 189, 170, 7 }, }, - { { 92, 52, 54, 254, 4 }, - { 203, 105, 194, 184, 7 }, - { 39, 246, 194, 195, 10 }, - { 225, 212, 57, 109, 3 }, }, - { { 92, 72, 252, 119, 14 }, - { 170, 157, 199, 156, 13 }, - { 126, 227, 241, 35, 10 }, - { 179, 158, 59, 149, 5 }, }, - { { 94, 110, 239, 64, 2 }, - { 179, 221, 12, 169, 12 }, - { 64, 47, 119, 103, 10 }, - { 57, 83, 11, 188, 13 }, }, - { { 95, 35, 59, 111, 15 }, - { 159, 122, 79, 221, 5 }, - { 255, 109, 204, 79, 10 }, - { 171, 191, 37, 239, 9 }, }, - { { 91, 116, 42, 99, 2 }, - { 67, 92, 6, 237, 5 }, - { 76, 101, 66, 237, 10 }, - { 171, 118, 3, 172, 2 }, }, - { { 101, 15, 163, 58, 14 }, - { 144, 242, 235, 224, 13 }, - { 117, 204, 95, 10, 6 }, - { 176, 125, 116, 240, 9 }, }, - { { 101, 211, 23, 92, 12 }, - { 216, 103, 249, 216, 0 }, - { 51, 174, 140, 186, 6 }, - { 1, 185, 254, 97, 11 }, }, - { { 106, 156, 36, 90, 14 }, - { 66, 49, 241, 169, 13 }, - { 117, 162, 67, 149, 6 }, - { 185, 88, 248, 196, 2 }, }, - { { 105, 197, 243, 4, 2 }, - { 58, 214, 48, 240, 4 }, - { 66, 12, 250, 57, 6 }, - { 32, 240, 198, 181, 12 }, }, - { { 105, 210, 72, 78, 10 }, - { 106, 52, 61, 200, 1 }, - { 87, 33, 36, 185, 6 }, - { 129, 59, 194, 197, 6 }, }, - { { 116, 121, 226, 222, 6 }, - { 233, 254, 224, 136, 15 }, - { 103, 180, 121, 226, 14 }, - { 241, 16, 119, 249, 7 }, }, - { { 114, 207, 35, 234, 11 }, - { 20, 126, 59, 169, 15 }, - { 213, 124, 79, 52, 14 }, - { 249, 93, 199, 226, 8 }, }, - { { 119, 177, 220, 65, 4 }, - { 225, 139, 116, 221, 0 }, - { 40, 35, 184, 222, 14 }, - { 11, 178, 237, 24, 7 }, }, - { { 126, 12, 7, 33, 7 }, - { 150, 89, 98, 165, 8 }, - { 232, 78, 3, 7, 14 }, - { 26, 84, 105, 166, 9 }, }, - { { 122, 105, 112, 100, 7 }, - { 47, 30, 98, 153, 12 }, - { 226, 96, 233, 101, 14 }, - { 57, 148, 103, 143, 4 }, }, - { { 120, 178, 216, 112, 7 }, - { 103, 152, 254, 152, 0 }, - { 224, 225, 180, 209, 14 }, - { 1, 151, 241, 158, 6 }, }, - { { 121, 197, 133, 121, 4 }, - { 18, 175, 242, 236, 0 }, - { 41, 234, 26, 57, 14 }, - { 3, 116, 255, 84, 8 }, }, - { { 134, 111, 89, 252, 6 }, - { 185, 54, 206, 59, 10 }, - { 99, 249, 175, 102, 1 }, - { 93, 199, 54, 201, 13 }, }, - { { 130, 246, 114, 127, 5 }, - { 109, 100, 218, 63, 5 }, - { 175, 228, 230, 244, 1 }, - { 175, 197, 178, 107, 6 }, }, - { { 133, 78, 47, 65, 4 }, - { 144, 69, 76, 110, 12 }, - { 40, 47, 71, 42, 1 }, - { 55, 99, 42, 32, 9 }, }, - { { 154, 17, 133, 147, 4 }, - { 82, 139, 192, 7, 3 }, - { 44, 154, 24, 133, 9 }, - { 206, 0, 61, 20, 10 }, }, - { { 156, 113, 96, 201, 7 }, - { 231, 62, 64, 14, 6 }, - { 233, 48, 104, 227, 9 }, - { 103, 0, 39, 206, 7 }, }, - { { 157, 209, 148, 253, 8 }, - { 202, 175, 147, 94, 2 }, - { 27, 242, 152, 187, 9 }, - { 71, 172, 159, 85, 3 }, }, - { { 162, 30, 18, 227, 8 }, - { 64, 64, 43, 63, 11 }, - { 28, 116, 135, 132, 5 }, - { 223, 205, 64, 32, 2 }, }, - { { 174, 112, 28, 130, 12 }, - { 195, 5, 101, 19, 3 }, - { 52, 19, 128, 231, 5 }, - { 204, 138, 106, 12, 3 }, }, - { { 173, 1, 33, 156, 1 }, - { 158, 34, 160, 66, 6 }, - { 131, 152, 72, 11, 5 }, - { 100, 32, 84, 71, 9 }, }, - { { 176, 53, 31, 158, 14 }, - { 89, 123, 229, 50, 3 }, - { 119, 159, 138, 192, 13 }, - { 196, 202, 125, 233, 10 }, }, - { { 182, 74, 216, 13, 4 }, - { 168, 172, 108, 23, 8 }, - { 43, 1, 181, 38, 13 }, - { 30, 131, 99, 81, 5 }, }, - { { 181, 55, 49, 75, 4 }, - { 209, 42, 104, 126, 5 }, - { 45, 40, 206, 202, 13 }, - { 167, 225, 101, 72, 11 }, }, - { { 190, 170, 199, 227, 11 }, - { 183, 217, 59, 15, 11 }, - { 220, 126, 53, 87, 13 }, - { 223, 13, 201, 190, 13 }, }, - { { 187, 104, 61, 188, 15 }, - { 31, 61, 231, 83, 14 }, - { 243, 219, 193, 109, 13 }, - { 124, 174, 123, 207, 8 }, }, - { { 198, 114, 247, 44, 1 }, - { 253, 229, 10, 147, 4 }, - { 131, 78, 244, 230, 3 }, - { 44, 149, 10, 123, 15 }, }, - { { 193, 231, 77, 186, 11 }, - { 53, 55, 159, 226, 3 }, - { 213, 219, 46, 120, 3 }, - { 196, 127, 158, 202, 12 }, }, - { { 203, 85, 238, 89, 13 }, - { 102, 231, 197, 239, 4 }, - { 185, 167, 122, 173, 3 }, - { 47, 122, 62, 118, 6 }, }, - { { 203, 160, 83, 114, 4 }, - { 51, 64, 210, 219, 1 }, - { 36, 236, 160, 93, 3 }, - { 141, 180, 176, 44, 12 }, }, - { { 208, 9, 15, 207, 1 }, - { 28, 107, 4, 142, 11 }, - { 143, 63, 9, 0, 11 }, - { 215, 18, 13, 99, 8 }, }, - { { 208, 108, 58, 213, 4 }, - { 9, 76, 196, 190, 14 }, - { 42, 181, 195, 96, 11 }, - { 119, 210, 51, 41, 0 }, }, - { { 211, 241, 32, 87, 4 }, - { 73, 14, 208, 207, 5 }, - { 46, 160, 72, 252, 11 }, - { 175, 48, 183, 9, 2 }, }, - { { 230, 227, 59, 26, 7 }, - { 149, 118, 252, 147, 5 }, - { 229, 141, 204, 118, 7 }, - { 172, 147, 246, 234, 9 }, }, - { { 227, 83, 62, 164, 10 }, - { 72, 87, 47, 211, 6 }, - { 82, 87, 204, 172, 7 }, - { 108, 191, 78, 161, 2 }, }, - { { 232, 6, 142, 177, 4 }, - { 2, 193, 238, 166, 2 }, - { 40, 215, 22, 1, 7 }, - { 70, 87, 120, 52, 0 }, }, - { { 236, 7, 192, 89, 7 }, - { 166, 178, 232, 174, 0 }, - { 233, 160, 62, 3, 7 }, - { 7, 81, 116, 214, 5 }, }, - { { 234, 243, 128, 61, 10 }, - { 75, 182, 187, 135, 0 }, - { 91, 192, 28, 245, 7 }, - { 14, 29, 214, 221, 2 }, }, - { { 246, 59, 39, 216, 8 }, - { 209, 107, 169, 139, 14 }, - { 17, 190, 77, 198, 15 }, - { 125, 25, 93, 104, 11 }, }, - { { 243, 7, 152, 55, 9 }, - { 12, 138, 175, 247, 1 }, - { 158, 193, 158, 12, 15 }, - { 142, 255, 85, 19, 0 }, }, - { { 254, 75, 186, 155, 9 }, - { 134, 238, 173, 151, 15 }, - { 157, 149, 221, 39, 15 }, - { 254, 155, 87, 118, 1 }, }, - { { 171, 165, 125, 134, 11 }, - { 63, 19, 53, 115, 7 }, - { 214, 27, 234, 93, 5 }, - { 236, 234, 204, 143, 12 }, }, - { { 192, 209, 98, 90, 11 }, - { 100, 118, 145, 138, 5 }, - { 213, 164, 104, 176, 3 }, - { 165, 24, 150, 226, 6 }, }, - { { 19, 206, 123, 174, 7 }, - { 60, 124, 94, 113, 15 }, - { 231, 93, 231, 60, 8 }, - { 248, 231, 163, 227, 12 }, }, - { { 78, 129, 253, 97, 7 }, - { 182, 147, 86, 157, 4 }, - { 232, 107, 248, 23, 2 }, - { 43, 150, 172, 150, 13 }, }, - { { 86, 224, 118, 50, 0 }, - { 161, 77, 146, 145, 5 }, - { 4, 198, 224, 118, 10 }, - { 168, 148, 155, 40, 5 }, }, - { { 106, 112, 138, 84, 0 }, - { 75, 196, 164, 137, 0 }, - { 2, 165, 16, 229, 6 }, - { 9, 18, 82, 61, 2 }, }, - { { 114, 168, 152, 161, 8 }, - { 1, 136, 55, 149, 10 }, - { 24, 81, 145, 84, 14 }, - { 90, 158, 193, 24, 0 }, }, - { { 129, 93, 66, 248, 0 }, - { 96, 102, 130, 106, 10 }, - { 1, 244, 43, 168, 1 }, - { 85, 100, 22, 96, 6 }, }, - { { 207, 76, 195, 213, 15 }, - { 190, 212, 193, 239, 10 }, - { 250, 188, 51, 47, 3 }, - { 95, 120, 50, 183, 13 }, }, - { { 214, 187, 101, 134, 4 }, - { 249, 11, 88, 131, 15 }, - { 38, 26, 109, 214, 11 }, - { 252, 17, 173, 9, 15 }, }, - { { 236, 211, 19, 163, 1 }, - { 214, 70, 58, 150, 3 }, - { 140, 92, 140, 179, 7 }, - { 198, 149, 198, 38, 11 }, }, - { { 245, 33, 245, 32, 7 }, - { 181, 155, 98, 210, 4 }, - { 224, 74, 248, 74, 15 }, - { 36, 180, 109, 154, 13 }, }, - { { 249, 31, 165, 223, 7 }, - { 94, 187, 232, 238, 15 }, - { 239, 186, 95, 137, 15 }, - { 247, 113, 125, 215, 10 }, }, - { { 0, 36, 244, 122, 7 }, - { 37, 177, 194, 56, 5 }, - { 229, 226, 242, 64, 0 }, - { 161, 196, 56, 218, 4 }, }, - { { 0, 8, 77, 136, 2 }, - { 48, 49, 4, 0, 10 }, - { 65, 27, 33, 0, 0 }, - { 80, 2, 8, 192, 12 }, }, - { { 4, 60, 194, 242, 9 }, - { 229, 192, 131, 40, 11 }, - { 148, 244, 51, 194, 0 }, - { 209, 76, 16, 58, 7 }, }, - { { 4, 123, 80, 33, 1 }, - { 229, 6, 10, 20, 8 }, - { 136, 64, 173, 226, 0 }, - { 18, 133, 6, 10, 7 }, }, - { { 6, 122, 228, 193, 13 }, - { 229, 133, 73, 13, 14 }, - { 184, 50, 117, 230, 0 }, - { 123, 9, 42, 26, 7 }, }, - { { 0, 170, 150, 138, 3 }, - { 5, 241, 24, 16, 11 }, - { 197, 22, 149, 80, 0 }, - { 208, 129, 136, 250, 0 }, }, - { { 4, 209, 56, 233, 4 }, - { 192, 38, 86, 28, 6 }, - { 41, 113, 200, 178, 0 }, - { 99, 134, 166, 64, 3 }, }, - { { 5, 16, 168, 13, 10 }, - { 200, 176, 5, 68, 4 }, - { 91, 1, 80, 138, 0 }, - { 34, 42, 0, 209, 3 }, }, - { { 1, 64, 176, 0, 7 }, - { 4, 148, 64, 80, 4 }, - { 224, 0, 208, 40, 0 }, - { 32, 160, 34, 146, 0 }, }, - { { 1, 157, 156, 238, 1 }, - { 76, 163, 22, 120, 11 }, - { 135, 115, 155, 152, 0 }, - { 209, 230, 140, 83, 2 }, }, - { { 8, 16, 87, 227, 11 }, - { 118, 81, 3, 28, 3 }, - { 220, 126, 160, 129, 0 }, - { 195, 140, 8, 166, 14 }, }, - { { 8, 107, 151, 182, 6 }, - { 27, 215, 202, 16, 11 }, - { 102, 222, 157, 97, 0 }, - { 208, 133, 62, 189, 8 }, }, - { { 14, 232, 184, 96, 10 }, - { 131, 148, 23, 25, 12 }, - { 80, 97, 209, 119, 0 }, - { 57, 142, 130, 156, 1 }, }, - { { 11, 108, 118, 185, 11 }, - { 39, 117, 131, 117, 14 }, - { 217, 214, 227, 109, 0 }, - { 122, 236, 26, 238, 4 }, }, - { { 15, 220, 185, 140, 11 }, - { 222, 180, 21, 113, 14 }, - { 211, 25, 211, 191, 0 }, - { 120, 234, 130, 215, 11 }, }, - { { 15, 202, 207, 58, 0 }, - { 178, 229, 158, 65, 9 }, - { 5, 207, 53, 63, 0 }, - { 152, 39, 154, 116, 13 }, }, - { { 20, 36, 159, 217, 8 }, - { 145, 233, 133, 60, 2 }, - { 25, 191, 146, 66, 8 }, - { 67, 202, 25, 120, 9 }, }, - { { 20, 7, 32, 31, 13 }, - { 140, 42, 201, 36, 5 }, - { 191, 128, 78, 2, 8 }, - { 162, 73, 53, 67, 1 }, }, - { { 21, 9, 16, 213, 7 }, - { 140, 26, 192, 92, 10 }, - { 234, 176, 137, 10, 8 }, - { 83, 160, 53, 131, 1 }, }, - { { 19, 92, 215, 48, 7 }, - { 116, 221, 194, 113, 8 }, - { 224, 206, 179, 172, 8 }, - { 24, 228, 59, 178, 14 }, }, - { { 17, 71, 154, 187, 6 }, - { 0, 254, 206, 116, 3 }, - { 109, 213, 158, 40, 8 }, - { 194, 231, 55, 240, 0 }, }, - { { 28, 185, 169, 35, 8 }, - { 211, 138, 23, 4, 13 }, - { 28, 73, 89, 211, 8 }, - { 178, 14, 133, 28, 11 }, }, - { { 28, 221, 7, 118, 6 }, - { 218, 95, 210, 40, 9 }, - { 102, 238, 11, 179, 8 }, - { 145, 68, 191, 165, 11 }, }, - { { 31, 46, 124, 36, 11 }, - { 175, 25, 15, 113, 12 }, - { 210, 67, 231, 79, 8 }, - { 56, 239, 9, 143, 5 }, }, - { { 25, 102, 66, 71, 7 }, - { 47, 92, 72, 108, 1 }, - { 238, 36, 38, 105, 8 }, - { 131, 97, 35, 175, 4 }, }, - { { 25, 87, 212, 200, 4 }, - { 98, 175, 72, 120, 2 }, - { 33, 50, 190, 169, 8 }, - { 65, 225, 47, 84, 6 }, }, - { { 31, 168, 244, 240, 4 }, - { 163, 137, 210, 89, 14 }, - { 32, 242, 241, 95, 8 }, - { 121, 164, 185, 28, 5 }, }, - { { 27, 130, 70, 237, 8 }, - { 42, 105, 27, 77, 2 }, - { 27, 118, 36, 29, 8 }, - { 75, 45, 137, 101, 4 }, }, - { { 27, 174, 225, 15, 14 }, - { 59, 184, 89, 101, 13 }, - { 127, 8, 119, 93, 8 }, - { 186, 105, 161, 221, 12 }, }, - { { 34, 164, 182, 60, 10 }, - { 9, 241, 179, 49, 4 }, - { 83, 198, 210, 84, 4 }, - { 40, 204, 216, 249, 0 }, }, - { { 34, 191, 144, 18, 15 }, - { 69, 146, 249, 49, 9 }, - { 244, 128, 159, 212, 4 }, - { 152, 201, 244, 154, 2 }, }, - { { 35, 44, 21, 180, 0 }, - { 25, 1, 162, 113, 10 }, - { 2, 218, 131, 76, 4 }, - { 88, 228, 88, 9, 8 }, }, - { { 37, 90, 169, 102, 12 }, - { 216, 132, 111, 72, 13 }, - { 54, 105, 85, 170, 4 }, - { 177, 47, 98, 17, 11 }, }, - { { 39, 165, 175, 169, 7 }, - { 149, 243, 118, 101, 6 }, - { 233, 95, 90, 94, 4 }, - { 106, 102, 236, 250, 9 }, }, - { { 37, 244, 14, 66, 5 }, - { 197, 69, 116, 104, 1 }, - { 164, 39, 2, 250, 4 }, - { 129, 98, 234, 42, 3 }, }, - { { 40, 102, 85, 205, 14 }, - { 59, 53, 105, 60, 2 }, - { 123, 58, 166, 97, 4 }, - { 67, 201, 106, 205, 12 }, }, - { { 44, 66, 126, 14, 0 }, - { 170, 101, 44, 16, 5 }, - { 7, 7, 228, 35, 4 }, - { 160, 131, 74, 101, 5 }, }, - { { 42, 185, 124, 189, 0 }, - { 107, 35, 182, 21, 14 }, - { 11, 211, 233, 213, 4 }, - { 122, 134, 220, 77, 6 }, }, - { { 41, 70, 225, 210, 3 }, - { 54, 148, 168, 104, 7 }, - { 196, 184, 118, 41, 4 }, - { 225, 97, 82, 150, 12 }, }, - { { 45, 166, 40, 65, 0 }, - { 131, 0, 60, 108, 4 }, - { 8, 33, 70, 91, 4 }, - { 35, 99, 192, 12, 1 }, }, - { { 43, 251, 32, 154, 6 }, - { 67, 54, 248, 65, 15 }, - { 101, 144, 77, 253, 4 }, - { 248, 33, 246, 204, 2 }, }, - { { 54, 140, 214, 107, 12 }, - { 160, 233, 115, 61, 9 }, - { 61, 102, 179, 22, 12 }, - { 155, 204, 233, 112, 5 }, }, - { { 52, 135, 119, 124, 7 }, - { 188, 123, 250, 56, 4 }, - { 227, 238, 238, 18, 12 }, - { 33, 197, 253, 227, 13 }, }, - { { 52, 221, 235, 132, 0 }, - { 248, 206, 52, 32, 14 }, - { 2, 29, 123, 178, 12 }, - { 112, 66, 199, 49, 15 }, }, - { { 55, 145, 247, 111, 1 }, - { 252, 235, 50, 93, 5 }, - { 143, 110, 248, 158, 12 }, - { 171, 164, 205, 115, 15 }, }, - { { 58, 34, 142, 23, 5 }, - { 15, 201, 236, 5, 1 }, - { 174, 135, 20, 69, 12 }, - { 138, 3, 121, 63, 0 }, }, - { { 62, 19, 189, 64, 8 }, - { 210, 139, 45, 25, 4 }, - { 16, 43, 220, 135, 12 }, - { 41, 139, 77, 20, 11 }, }, - { { 60, 152, 67, 202, 2 }, - { 242, 120, 48, 8, 11 }, - { 69, 60, 33, 147, 12 }, - { 209, 0, 193, 228, 15 }, }, - { { 57, 88, 157, 23, 9 }, - { 94, 141, 165, 84, 9 }, - { 158, 139, 145, 169, 12 }, - { 146, 170, 91, 23, 10 }, }, - { { 57, 116, 218, 238, 11 }, - { 111, 252, 39, 120, 3 }, - { 215, 117, 178, 233, 12 }, - { 193, 238, 67, 255, 6 }, }, - { { 63, 109, 188, 115, 1 }, - { 135, 143, 166, 125, 13 }, - { 140, 227, 219, 111, 12 }, - { 187, 230, 95, 30, 1 }, }, - { { 61, 107, 192, 80, 12 }, - { 163, 142, 233, 72, 8 }, - { 48, 160, 61, 107, 12 }, - { 17, 41, 119, 28, 5 }, }, - { { 57, 171, 39, 73, 7 }, - { 23, 123, 120, 76, 12 }, - { 233, 46, 77, 89, 12 }, - { 51, 33, 237, 238, 8 }, }, - { { 70, 2, 78, 37, 14 }, - { 168, 81, 79, 133, 0 }, - { 122, 71, 36, 6, 2 }, - { 10, 31, 40, 161, 5 }, }, - { { 70, 130, 186, 11, 12 }, - { 128, 224, 93, 149, 5 }, - { 61, 5, 212, 22, 2 }, - { 170, 155, 160, 112, 1 }, }, - { { 66, 233, 205, 90, 14 }, - { 49, 183, 213, 137, 9 }, - { 117, 171, 57, 116, 2 }, - { 153, 26, 190, 216, 12 }, }, - { { 68, 201, 183, 179, 15 }, - { 148, 215, 211, 148, 15 }, - { 252, 222, 217, 50, 2 }, - { 242, 156, 190, 178, 9 }, }, - { { 64, 199, 212, 30, 9 }, - { 44, 167, 153, 176, 1 }, - { 151, 130, 190, 48, 2 }, - { 128, 217, 158, 83, 4 }, }, - { { 70, 210, 180, 204, 14 }, - { 200, 181, 89, 153, 6 }, - { 115, 50, 212, 182, 2 }, - { 105, 153, 170, 209, 3 }, }, - { { 67, 25, 83, 86, 11 }, - { 124, 82, 129, 217, 9 }, - { 214, 172, 169, 140, 2 }, - { 153, 184, 20, 163, 14 }, }, - { { 65, 34, 230, 221, 9 }, - { 45, 225, 137, 204, 6 }, - { 155, 182, 116, 72, 2 }, - { 99, 57, 24, 123, 4 }, }, - { { 71, 83, 165, 154, 11 }, - { 212, 183, 137, 193, 7 }, - { 213, 154, 92, 174, 2 }, - { 232, 57, 30, 210, 11 }, }, - { { 78, 30, 241, 224, 8 }, - { 242, 128, 11, 185, 14 }, - { 16, 120, 247, 135, 2 }, - { 121, 221, 0, 20, 15 }, }, - { { 78, 74, 192, 150, 0 }, - { 170, 132, 136, 129, 11 }, - { 6, 144, 53, 39, 2 }, - { 216, 17, 18, 21, 5 }, }, - { { 78, 95, 170, 6, 15 }, - { 206, 214, 77, 161, 13 }, - { 246, 5, 95, 167, 2 }, - { 184, 91, 38, 183, 3 }, }, - { { 74, 141, 50, 148, 3 }, - { 14, 82, 144, 177, 14 }, - { 194, 148, 203, 21, 2 }, - { 120, 208, 148, 167, 0 }, }, - { { 73, 21, 148, 179, 9 }, - { 70, 131, 131, 244, 3 }, - { 156, 210, 154, 137, 2 }, - { 194, 252, 28, 22, 2 }, }, - { { 77, 77, 219, 98, 1 }, - { 182, 198, 6, 248, 9 }, - { 132, 109, 187, 43, 2 }, - { 145, 246, 6, 54, 13 }, }, - { { 75, 167, 97, 232, 1 }, - { 55, 34, 26, 233, 6 }, - { 129, 120, 110, 93, 2 }, - { 105, 117, 132, 78, 12 }, }, - { { 73, 212, 131, 216, 14 }, - { 82, 244, 209, 232, 2 }, - { 113, 188, 18, 185, 2 }, - { 65, 120, 178, 244, 10 }, }, - { { 86, 41, 14, 246, 12 }, - { 137, 75, 199, 137, 11 }, - { 54, 247, 9, 70, 10 }, - { 217, 30, 61, 41, 1 }, }, - { { 83, 126, 213, 255, 12 }, - { 121, 173, 203, 253, 11 }, - { 63, 250, 183, 236, 10 }, - { 219, 253, 59, 89, 14 }, }, - { { 85, 245, 167, 175, 10 }, - { 217, 255, 19, 228, 7 }, - { 95, 94, 90, 250, 10 }, - { 226, 124, 143, 249, 11 }, }, - { { 85, 213, 234, 100, 15 }, - { 236, 222, 87, 232, 4 }, - { 242, 101, 122, 186, 10 }, - { 33, 126, 167, 179, 7 }, }, - { { 88, 27, 171, 29, 10 }, - { 90, 250, 141, 132, 12 }, - { 91, 141, 93, 129, 10 }, - { 50, 27, 21, 245, 10 }, }, - { { 94, 190, 146, 109, 13 }, - { 207, 232, 91, 189, 8 }, - { 187, 100, 151, 215, 10 }, - { 27, 221, 161, 127, 3 }, }, - { { 95, 16, 249, 155, 5 }, - { 246, 168, 196, 213, 7 }, - { 173, 153, 240, 143, 10 }, - { 234, 178, 49, 86, 15 }, }, - { { 93, 30, 223, 165, 12 }, - { 250, 201, 79, 244, 10 }, - { 58, 95, 183, 139, 10 }, - { 82, 255, 41, 53, 15 }, }, - { { 95, 113, 141, 240, 2 }, - { 211, 159, 134, 201, 2 }, - { 64, 251, 24, 239, 10 }, - { 73, 54, 31, 156, 11 }, }, - { { 93, 225, 30, 70, 8 }, - { 139, 79, 21, 216, 1 }, - { 22, 39, 136, 123, 10 }, - { 129, 186, 143, 45, 1 }, }, - { { 96, 51, 187, 36, 7 }, - { 93, 210, 110, 144, 4 }, - { 226, 77, 220, 192, 6 }, - { 32, 151, 100, 187, 10 }, }, - { { 100, 88, 26, 254, 1 }, - { 204, 100, 166, 152, 11 }, - { 135, 245, 129, 162, 6 }, - { 209, 150, 82, 99, 3 }, }, - { { 99, 200, 221, 167, 6 }, - { 56, 149, 118, 213, 11 }, - { 110, 91, 177, 60, 6 }, - { 218, 182, 234, 145, 12 }, }, - { { 97, 218, 61, 143, 13 }, - { 92, 37, 125, 212, 15 }, - { 191, 27, 197, 184, 6 }, - { 242, 187, 234, 67, 10 }, }, - { { 110, 58, 34, 175, 10 }, - { 203, 112, 43, 133, 15 }, - { 95, 84, 69, 199, 6 }, - { 250, 29, 64, 237, 3 }, }, - { { 110, 97, 5, 183, 1 }, - { 159, 7, 162, 133, 3 }, - { 142, 218, 8, 103, 6 }, - { 202, 20, 94, 15, 9 }, }, - { { 106, 137, 169, 232, 12 }, - { 18, 162, 119, 137, 14 }, - { 49, 121, 89, 21, 6 }, - { 121, 30, 228, 84, 8 }, }, - { { 106, 151, 34, 79, 5 }, - { 78, 98, 120, 173, 5 }, - { 175, 36, 78, 149, 6 }, - { 171, 81, 228, 103, 2 }, }, - { { 107, 18, 195, 128, 1 }, - { 118, 192, 40, 193, 2 }, - { 128, 28, 52, 141, 6 }, - { 72, 49, 64, 54, 14 }, }, - { { 107, 104, 75, 34, 10 }, - { 51, 84, 39, 193, 9 }, - { 84, 77, 33, 109, 6 }, - { 152, 62, 66, 172, 12 }, }, - { { 111, 148, 193, 87, 9 }, - { 254, 128, 177, 237, 1 }, - { 158, 168, 50, 159, 6 }, - { 139, 120, 208, 23, 15 }, }, - { { 109, 166, 254, 160, 13 }, - { 167, 193, 127, 240, 6 }, - { 176, 87, 246, 91, 6 }, - { 96, 255, 232, 62, 5 }, }, - { { 111, 234, 202, 69, 7 }, - { 175, 212, 124, 205, 8 }, - { 234, 37, 53, 127, 6 }, - { 27, 51, 226, 191, 5 }, }, - { { 112, 61, 56, 166, 0 }, - { 73, 10, 38, 176, 15 }, - { 6, 81, 203, 192, 14 }, - { 240, 214, 69, 9, 2 }, }, - { { 118, 108, 53, 231, 8 }, - { 153, 13, 35, 189, 15 }, - { 30, 122, 195, 102, 14 }, - { 251, 220, 75, 9, 9 }, }, - { { 112, 74, 13, 255, 6 }, - { 24, 61, 238, 140, 11 }, - { 111, 251, 5, 32, 14 }, - { 211, 23, 123, 193, 8 }, }, - { { 117, 120, 169, 200, 0 }, - { 209, 172, 36, 200, 14 }, - { 1, 57, 81, 234, 14 }, - { 113, 50, 67, 88, 11 }, }, - { { 113, 74, 112, 19, 8 }, - { 32, 12, 169, 212, 13 }, - { 28, 128, 229, 40, 14 }, - { 178, 185, 83, 0, 4 }, }, - { { 117, 127, 140, 187, 9 }, - { 197, 175, 175, 228, 11 }, - { 157, 211, 31, 234, 14 }, - { 210, 127, 95, 90, 3 }, }, - { { 124, 35, 104, 51, 1 }, - { 167, 10, 174, 132, 5 }, - { 140, 193, 108, 67, 14 }, - { 162, 23, 85, 14, 5 }, }, - { { 124, 181, 167, 211, 1 }, - { 215, 203, 176, 172, 7 }, - { 140, 190, 90, 211, 14 }, - { 227, 80, 221, 62, 11 }, }, - { { 124, 248, 44, 237, 14 }, - { 203, 61, 119, 140, 14 }, - { 123, 115, 65, 243, 14 }, - { 115, 30, 235, 205, 3 }, }, - { { 127, 36, 226, 52, 15 }, - { 175, 216, 227, 225, 4 }, - { 242, 196, 114, 79, 14 }, - { 40, 124, 113, 191, 5 }, }, - { { 127, 71, 41, 141, 8 }, - { 154, 46, 45, 229, 6 }, - { 27, 25, 78, 47, 14 }, - { 106, 123, 71, 69, 9 }, }, - { { 134, 216, 3, 209, 9 }, - { 212, 68, 145, 15, 10 }, - { 152, 188, 1, 182, 1 }, - { 95, 8, 146, 34, 11 }, }, - { { 131, 139, 27, 161, 3 }, - { 20, 82, 30, 87, 10 }, - { 200, 93, 141, 28, 1 }, - { 94, 167, 132, 162, 8 }, }, - { { 135, 162, 121, 197, 9 }, - { 189, 0, 29, 95, 6 }, - { 154, 57, 228, 94, 1 }, - { 111, 171, 128, 11, 13 }, }, - { { 138, 67, 100, 140, 14 }, - { 42, 55, 73, 3, 6 }, - { 115, 18, 108, 37, 1 }, - { 108, 9, 46, 197, 4 }, }, - { { 136, 147, 59, 76, 8 }, - { 90, 98, 29, 26, 4 }, - { 19, 45, 204, 145, 1 }, - { 37, 139, 132, 101, 10 }, }, - { { 143, 33, 223, 78, 3 }, - { 191, 243, 4, 91, 1 }, - { 199, 47, 184, 79, 1 }, - { 141, 162, 12, 255, 13 }, }, - { { 141, 132, 53, 114, 9 }, - { 150, 1, 147, 122, 5 }, - { 148, 234, 194, 27, 1 }, - { 165, 236, 152, 6, 9 }, }, - { { 141, 136, 215, 31, 13 }, - { 190, 225, 209, 86, 9 }, - { 191, 142, 177, 27, 1 }, - { 150, 168, 184, 119, 13 }, }, - { { 137, 159, 120, 252, 13 }, - { 110, 34, 223, 122, 14 }, - { 179, 241, 239, 153, 1 }, - { 117, 239, 180, 71, 6 }, }, - { { 146, 107, 22, 121, 12 }, - { 1, 111, 203, 31, 8 }, - { 57, 230, 141, 100, 9 }, - { 31, 141, 63, 104, 0 }, }, - { { 148, 142, 34, 241, 2 }, - { 128, 88, 154, 46, 14 }, - { 72, 244, 71, 18, 9 }, - { 119, 69, 145, 160, 1 }, }, - { { 144, 229, 230, 49, 7 }, - { 37, 223, 210, 38, 4 }, - { 232, 198, 122, 112, 9 }, - { 38, 68, 191, 186, 4 }, }, - { { 150, 216, 133, 42, 1 }, - { 212, 173, 18, 3, 9 }, - { 133, 74, 17, 182, 9 }, - { 156, 4, 139, 82, 11 }, }, - { { 149, 57, 59, 164, 6 }, - { 217, 90, 70, 82, 14 }, - { 98, 93, 201, 202, 9 }, - { 116, 166, 37, 169, 11 }, }, - { { 149, 60, 251, 77, 13 }, - { 253, 232, 69, 126, 12 }, - { 187, 45, 243, 202, 9 }, - { 55, 234, 33, 123, 15 }, }, - { { 145, 62, 170, 18, 6 }, - { 65, 216, 204, 98, 13 }, - { 100, 133, 87, 200, 9 }, - { 180, 99, 49, 184, 2 }, }, - { { 151, 111, 90, 175, 9 }, - { 173, 110, 15, 119, 11 }, - { 159, 85, 175, 110, 9 }, - { 222, 239, 7, 107, 5 }, }, - { { 145, 178, 41, 253, 10 }, - { 89, 56, 159, 78, 6 }, - { 91, 249, 68, 216, 9 }, - { 103, 47, 145, 201, 10 }, }, - { { 145, 211, 250, 118, 1 }, - { 108, 206, 158, 90, 5 }, - { 134, 229, 252, 184, 9 }, - { 165, 167, 151, 51, 6 }, }, - { { 154, 112, 134, 200, 8 }, - { 67, 237, 1, 11, 2 }, - { 17, 54, 16, 229, 9 }, - { 77, 8, 11, 124, 2 }, }, - { { 152, 142, 205, 3, 1 }, - { 54, 137, 28, 38, 9 }, - { 140, 11, 55, 17, 9 }, - { 150, 67, 137, 22, 12 }, }, - { { 152, 199, 16, 151, 10 }, - { 10, 30, 153, 54, 3 }, - { 94, 144, 142, 49, 9 }, - { 198, 201, 151, 133, 0 }, }, - { { 157, 203, 235, 70, 6 }, - { 186, 222, 92, 74, 13 }, - { 102, 45, 125, 59, 9 }, - { 181, 35, 167, 181, 13 }, }, - { { 164, 40, 245, 182, 14 }, - { 185, 145, 227, 18, 15 }, - { 118, 218, 241, 66, 5 }, - { 244, 140, 120, 153, 13 }, }, - { { 163, 55, 241, 121, 3 }, - { 117, 178, 170, 127, 4 }, - { 201, 232, 254, 204, 5 }, - { 47, 229, 84, 218, 14 }, }, - { { 163, 68, 64, 245, 10 }, - { 40, 20, 163, 111, 2 }, - { 90, 240, 34, 44, 5 }, - { 79, 108, 82, 129, 4 }, }, - { { 161, 127, 173, 133, 8 }, - { 89, 135, 45, 102, 14 }, - { 26, 27, 95, 232, 5 }, - { 118, 107, 78, 25, 10 }, }, - { { 167, 210, 150, 35, 13 }, - { 196, 197, 123, 87, 1 }, - { 188, 70, 148, 190, 5 }, - { 142, 173, 234, 50, 3 }, }, - { { 168, 69, 112, 43, 11 }, - { 38, 54, 35, 54, 5 }, - { 221, 64, 234, 33, 5 }, - { 166, 204, 70, 198, 4 }, }, - { { 174, 72, 127, 160, 9 }, - { 182, 69, 39, 19, 14 }, - { 144, 95, 225, 39, 5 }, - { 124, 142, 74, 38, 13 }, }, - { { 172, 79, 182, 214, 8 }, - { 138, 199, 169, 58, 15 }, - { 22, 182, 223, 35, 5 }, - { 245, 201, 94, 53, 1 }, }, - { { 168, 168, 211, 133, 3 }, - { 63, 208, 48, 22, 10 }, - { 202, 28, 177, 81, 5 }, - { 86, 128, 192, 191, 12 }, }, - { { 169, 139, 10, 203, 8 }, - { 2, 98, 61, 78, 11 }, - { 29, 53, 13, 25, 5 }, - { 215, 43, 196, 100, 0 }, }, - { { 173, 254, 140, 222, 2 }, - { 203, 181, 188, 106, 11 }, - { 71, 179, 23, 251, 5 }, - { 213, 99, 218, 221, 3 }, }, - { { 180, 239, 46, 46, 14 }, - { 137, 127, 127, 34, 13 }, - { 119, 71, 79, 114, 13 }, - { 180, 79, 239, 233, 1 }, }, - { { 183, 153, 137, 199, 0 }, - { 216, 138, 52, 79, 11 }, - { 14, 57, 25, 158, 13 }, - { 223, 34, 197, 17, 11 }, }, - { { 190, 12, 162, 14, 12 }, - { 138, 232, 97, 35, 13 }, - { 55, 4, 83, 7, 13 }, - { 188, 72, 97, 117, 1 }, }, - { { 188, 112, 34, 122, 9 }, - { 199, 108, 163, 10, 5 }, - { 149, 228, 64, 227, 13 }, - { 165, 12, 83, 110, 3 }, }, - { { 190, 188, 47, 145, 10 }, - { 211, 89, 181, 39, 14 }, - { 88, 159, 67, 215, 13 }, - { 126, 74, 217, 172, 11 }, }, - { { 184, 233, 10, 152, 3 }, - { 7, 126, 180, 2, 10 }, - { 193, 149, 9, 113, 13 }, - { 84, 2, 215, 238, 0 }, }, - { { 189, 10, 48, 236, 8 }, - { 138, 40, 43, 90, 14 }, - { 19, 112, 197, 11, 13 }, - { 117, 173, 65, 69, 1 }, }, - { { 194, 2, 224, 243, 1 }, - { 36, 128, 138, 143, 7 }, - { 140, 240, 116, 4, 3 }, - { 239, 21, 16, 18, 4 }, }, - { { 194, 107, 50, 227, 7 }, - { 5, 86, 74, 159, 15 }, - { 236, 116, 205, 100, 3 }, - { 255, 149, 38, 170, 0 }, }, - { { 198, 202, 66, 106, 8 }, - { 160, 100, 27, 139, 9 }, - { 21, 100, 37, 54, 3 }, - { 157, 29, 130, 96, 5 }, }, - { { 199, 30, 238, 104, 14 }, - { 224, 241, 79, 235, 12 }, - { 113, 103, 119, 142, 3 }, - { 61, 127, 40, 240, 7 }, }, - { { 199, 125, 46, 145, 3 }, - { 197, 87, 132, 231, 14 }, - { 200, 151, 75, 238, 3 }, - { 126, 114, 30, 170, 3 }, }, - { { 206, 60, 32, 116, 2 }, - { 203, 16, 130, 171, 12 }, - { 66, 224, 67, 199, 3 }, - { 61, 84, 16, 141, 3 }, }, - { { 204, 74, 185, 197, 7 }, - { 158, 148, 76, 158, 14 }, - { 234, 57, 213, 35, 3 }, - { 119, 147, 34, 151, 9 }, }, - { { 206, 247, 99, 220, 13 }, - { 255, 102, 217, 171, 6 }, - { 179, 188, 110, 247, 3 }, - { 109, 89, 182, 111, 15 }, }, - { { 205, 67, 34, 202, 2 }, - { 130, 118, 8, 202, 7 }, - { 69, 52, 76, 43, 3 }, - { 229, 49, 6, 228, 1 }, }, - { { 207, 183, 204, 29, 0 }, - { 235, 163, 156, 231, 0 }, - { 11, 131, 62, 223, 3 }, - { 14, 115, 156, 93, 7 }, }, - { { 201, 206, 200, 53, 10 }, - { 42, 148, 159, 230, 8 }, - { 90, 193, 55, 57, 3 }, - { 22, 127, 146, 149, 4 }, }, - { { 207, 243, 75, 113, 3 }, - { 247, 86, 158, 207, 0 }, - { 200, 237, 44, 255, 3 }, - { 15, 55, 150, 174, 15 }, }, - { { 214, 46, 123, 112, 13 }, - { 181, 72, 207, 187, 12 }, - { 176, 237, 231, 70, 11 }, - { 61, 223, 49, 42, 13 }, }, - { { 212, 23, 75, 59, 4 }, - { 240, 106, 206, 166, 1 }, - { 45, 205, 46, 130, 11 }, - { 134, 87, 53, 96, 15 }, }, - { { 215, 141, 250, 151, 14 }, - { 168, 218, 213, 247, 15 }, - { 126, 149, 251, 30, 11 }, - { 254, 250, 181, 177, 5 }, }, - { { 209, 216, 245, 85, 1 }, - { 124, 141, 144, 222, 12 }, - { 138, 170, 241, 184, 11 }, - { 55, 176, 155, 19, 14 }, }, - { { 213, 207, 225, 211, 9 }, - { 180, 142, 153, 238, 15 }, - { 156, 184, 127, 58, 11 }, - { 247, 121, 151, 18, 13 }, }, - { { 218, 22, 168, 204, 9 }, - { 78, 168, 13, 171, 6 }, - { 147, 49, 86, 133, 11 }, - { 109, 91, 1, 87, 2 }, }, - { { 216, 76, 68, 133, 9 }, - { 46, 13, 1, 166, 10 }, - { 154, 18, 35, 33, 11 }, - { 86, 88, 11, 7, 4 }, }, - { { 220, 217, 114, 142, 13 }, - { 238, 110, 81, 146, 15 }, - { 183, 20, 233, 179, 11 }, - { 244, 152, 167, 103, 7 }, }, - { { 223, 103, 17, 126, 8 }, - { 155, 46, 139, 251, 1 }, - { 23, 232, 142, 111, 11 }, - { 141, 253, 23, 77, 9 }, }, - { { 219, 153, 125, 230, 7 }, - { 126, 27, 86, 219, 15 }, - { 230, 123, 233, 157, 11 }, - { 253, 182, 173, 135, 14 }, }, - { { 221, 171, 142, 49, 14 }, - { 131, 219, 223, 198, 8 }, - { 120, 199, 29, 91, 11 }, - { 22, 63, 189, 188, 1 }, }, - { { 224, 25, 8, 76, 13 }, - { 76, 34, 101, 138, 8 }, - { 179, 33, 9, 128, 7 }, - { 21, 26, 100, 67, 2 }, }, - { { 230, 54, 218, 82, 1 }, - { 229, 192, 172, 187, 1 }, - { 132, 165, 182, 198, 7 }, - { 141, 211, 80, 58, 7 }, }, - { { 226, 172, 199, 155, 0 }, - { 49, 225, 176, 167, 11 }, - { 13, 158, 51, 84, 7 }, - { 222, 80, 216, 120, 12 }, }, - { { 228, 141, 33, 98, 0 }, - { 144, 2, 50, 170, 13 }, - { 4, 104, 75, 18, 7 }, - { 181, 84, 196, 0, 9 }, }, - { { 226, 254, 208, 197, 1 }, - { 109, 132, 56, 191, 10 }, - { 138, 48, 183, 244, 7 }, - { 95, 209, 194, 27, 6 }, }, - { { 225, 58, 125, 2, 10 }, - { 113, 17, 45, 210, 13 }, - { 84, 11, 229, 200, 7 }, - { 180, 187, 72, 136, 14 }, }, - { { 231, 208, 91, 142, 5 }, - { 252, 100, 116, 211, 3 }, - { 167, 29, 160, 190, 7 }, - { 204, 178, 226, 99, 15 }, }, - { { 236, 48, 156, 107, 5 }, - { 199, 161, 102, 158, 1 }, - { 173, 99, 144, 195, 7 }, - { 135, 150, 104, 94, 3 }, }, - { { 236, 170, 73, 210, 0 }, - { 179, 0, 188, 138, 11 }, - { 4, 185, 37, 83, 7 }, - { 213, 19, 208, 12, 13 }, }, - { { 238, 179, 122, 196, 6 }, - { 235, 82, 124, 155, 6 }, - { 98, 53, 236, 215, 7 }, - { 109, 147, 228, 173, 7 }, }, - { { 232, 224, 103, 46, 2 }, - { 59, 117, 50, 130, 5 }, - { 71, 78, 96, 113, 7 }, - { 164, 20, 202, 237, 12 }, }, - { { 234, 229, 213, 36, 12 }, - { 59, 135, 115, 179, 0 }, - { 50, 74, 186, 117, 7 }, - { 12, 220, 238, 29, 12 }, }, - { { 237, 107, 28, 44, 2 }, - { 139, 55, 46, 210, 8 }, - { 67, 67, 141, 107, 7 }, - { 20, 183, 78, 205, 1 }, }, - { { 235, 200, 175, 29, 6 }, - { 26, 245, 244, 199, 12 }, - { 107, 143, 81, 61, 7 }, - { 62, 50, 250, 245, 8 }, }, - { { 242, 5, 98, 212, 5 }, - { 44, 74, 224, 171, 6 }, - { 162, 180, 106, 4, 15 }, - { 109, 80, 117, 35, 4 }, }, - { { 246, 25, 188, 251, 2 }, - { 192, 187, 166, 159, 15 }, - { 77, 243, 217, 134, 15 }, - { 255, 150, 93, 208, 3 }, }, - { { 246, 163, 92, 109, 11 }, - { 173, 59, 63, 159, 0 }, - { 219, 99, 172, 86, 15 }, - { 15, 159, 205, 203, 5 }, }, - { { 244, 241, 189, 15, 0 }, - { 217, 175, 52, 150, 5 }, - { 15, 11, 216, 242, 15 }, - { 166, 146, 207, 89, 11 }, }, - { { 241, 106, 155, 67, 5 }, - { 21, 204, 108, 222, 9 }, - { 172, 45, 149, 104, 15 }, - { 151, 179, 99, 58, 8 }, }, - { { 241, 178, 145, 41, 14 }, - { 81, 184, 123, 214, 0 }, - { 121, 72, 148, 216, 15 }, - { 6, 189, 225, 216, 10 }, }, - { { 250, 84, 91, 243, 5 }, - { 118, 76, 230, 191, 3 }, - { 172, 253, 162, 165, 15 }, - { 207, 214, 115, 38, 14 }, }, - { { 254, 110, 134, 124, 6 }, - { 139, 253, 234, 171, 8 }, - { 99, 230, 23, 103, 15 }, - { 29, 85, 123, 253, 1 }, }, - { { 249, 13, 185, 67, 2 }, - { 18, 154, 36, 254, 13 }, - { 76, 41, 219, 9, 15 }, - { 183, 242, 69, 148, 8 }, }, - { { 249, 105, 102, 43, 13 }, - { 39, 111, 99, 198, 13 }, - { 189, 70, 105, 105, 15 }, - { 182, 60, 111, 110, 4 }, }, - { { 251, 65, 203, 72, 4 }, - { 50, 238, 100, 203, 0 }, - { 33, 45, 56, 45, 15 }, - { 13, 50, 103, 116, 12 }, }, - { { 253, 87, 191, 152, 5 }, - { 214, 239, 236, 242, 6 }, - { 161, 159, 222, 171, 15 }, - { 100, 243, 127, 118, 11 }, }, - { { 251, 152, 144, 126, 6 }, - { 74, 184, 242, 219, 9 }, - { 103, 224, 145, 157, 15 }, - { 157, 180, 241, 213, 2 }, }, - { { 255, 234, 33, 198, 3 }, - { 159, 28, 56, 203, 15 }, - { 198, 56, 69, 127, 15 }, - { 253, 49, 195, 143, 9 }, }, - { { 163, 165, 111, 69, 0 }, - { 57, 67, 52, 111, 4 }, - { 10, 47, 106, 92, 5 }, - { 47, 98, 204, 41, 12 }, }, - { { 161, 152, 104, 48, 2 }, - { 96, 16, 182, 66, 12 }, - { 64, 193, 97, 152, 5 }, - { 52, 38, 208, 128, 6 }, }, - { { 15, 55, 131, 43, 0 }, - { 211, 226, 10, 101, 1 }, - { 13, 76, 30, 207, 0 }, - { 138, 101, 4, 124, 11 }, }, - { { 38, 236, 72, 39, 2 }, - { 169, 20, 54, 37, 9 }, - { 78, 65, 35, 118, 4 }, - { 154, 70, 194, 137, 5 }, }, - { { 65, 152, 184, 168, 15 }, - { 68, 176, 87, 208, 14 }, - { 241, 81, 209, 152, 2 }, - { 112, 190, 160, 210, 2 }, }, - { { 78, 181, 67, 138, 4 }, - { 243, 98, 80, 161, 3 }, - { 37, 28, 42, 215, 2 }, - { 200, 80, 164, 108, 15 }, }, - { { 99, 197, 227, 123, 10 }, - { 48, 246, 179, 237, 5 }, - { 93, 236, 122, 60, 6 }, - { 171, 124, 214, 240, 12 }, }, - { { 110, 89, 221, 230, 12 }, - { 250, 135, 103, 153, 11 }, - { 54, 123, 185, 167, 6 }, - { 217, 158, 110, 21, 15 }, }, - { { 128, 212, 89, 240, 8 }, - { 112, 4, 151, 58, 2 }, - { 16, 249, 162, 176, 1 }, - { 69, 206, 146, 0, 14 }, }, - { { 152, 8, 136, 159, 13 }, - { 14, 168, 197, 6, 11 }, - { 191, 145, 17, 1, 9 }, - { 214, 10, 49, 87, 0 }, }, - { { 163, 6, 103, 166, 15 }, - { 60, 81, 107, 99, 7 }, - { 246, 94, 102, 12, 5 }, - { 236, 109, 104, 163, 12 }, }, - { { 2, 25, 166, 20, 7 }, - { 76, 211, 192, 1, 12 }, - { 226, 134, 89, 132, 0 }, - { 56, 0, 60, 179, 2 }, }, - { { 2, 21, 202, 78, 2 }, - { 104, 242, 4, 41, 1 }, - { 71, 37, 58, 132, 0 }, - { 137, 66, 4, 241, 6 }, }, - { { 0, 104, 204, 57, 9 }, - { 37, 165, 135, 4, 8 }, - { 153, 195, 49, 96, 0 }, - { 18, 14, 26, 90, 4 }, }, - { { 0, 161, 19, 254, 8 }, - { 25, 98, 147, 24, 3 }, - { 23, 252, 136, 80, 0 }, - { 193, 140, 148, 105, 8 }, }, - { { 2, 185, 86, 117, 5 }, - { 109, 67, 210, 29, 8 }, - { 170, 230, 169, 212, 0 }, - { 27, 132, 188, 43, 6 }, }, - { { 2, 198, 187, 83, 2 }, - { 16, 212, 156, 61, 5 }, - { 76, 173, 214, 52, 0 }, - { 171, 195, 146, 176, 8 }, }, - { { 2, 243, 31, 29, 9 }, - { 93, 103, 157, 21, 0 }, - { 155, 143, 140, 244, 0 }, - { 10, 139, 158, 107, 10 }, }, - { { 7, 42, 193, 126, 3 }, - { 189, 176, 138, 73, 9 }, - { 199, 232, 53, 78, 0 }, - { 153, 37, 16, 219, 13 }, }, - { { 7, 55, 141, 151, 2 }, - { 217, 147, 140, 101, 3 }, - { 78, 155, 30, 206, 0 }, - { 202, 99, 28, 153, 11 }, }, - { { 1, 111, 31, 231, 5 }, - { 29, 71, 78, 124, 11 }, - { 174, 127, 143, 104, 0 }, - { 211, 231, 46, 43, 8 }, }, - { { 1, 119, 48, 21, 5 }, - { 77, 6, 200, 116, 4 }, - { 170, 128, 206, 232, 0 }, - { 34, 225, 54, 11, 2 }, }, - { { 7, 149, 114, 65, 10 }, - { 224, 82, 17, 125, 4 }, - { 88, 36, 234, 158, 0 }, - { 43, 232, 132, 160, 7 }, }, - { { 7, 200, 163, 134, 14 }, - { 152, 212, 81, 65, 15 }, - { 118, 28, 81, 62, 0 }, - { 248, 40, 162, 177, 9 }, }, - { { 5, 254, 251, 247, 9 }, - { 253, 196, 159, 124, 15 }, - { 158, 253, 247, 250, 0 }, - { 243, 239, 146, 59, 15 }, }, - { { 12, 21, 243, 16, 1 }, - { 246, 194, 128, 48, 4 }, - { 128, 140, 250, 131, 0 }, - { 32, 192, 20, 54, 15 }, }, - { { 10, 68, 98, 226, 14 }, - { 34, 84, 67, 41, 7 }, - { 116, 116, 98, 37, 0 }, - { 233, 76, 34, 164, 4 }, }, - { { 8, 94, 55, 238, 9 }, - { 94, 101, 11, 56, 15 }, - { 151, 126, 199, 161, 0 }, - { 241, 205, 10, 103, 10 }, }, - { { 8, 82, 222, 18, 13 }, - { 102, 197, 205, 16, 1 }, - { 180, 135, 180, 161, 0 }, - { 128, 139, 58, 54, 6 }, }, - { { 12, 102, 136, 3, 9 }, - { 135, 132, 13, 36, 1 }, - { 156, 1, 22, 99, 0 }, - { 130, 75, 2, 30, 1 }, }, - { { 8, 140, 186, 71, 15 }, - { 14, 208, 85, 60, 13 }, - { 254, 37, 211, 17, 0 }, - { 179, 202, 160, 183, 0 }, }, - { { 12, 172, 39, 30, 5 }, - { 159, 97, 208, 32, 13 }, - { 167, 142, 67, 83, 0 }, - { 176, 64, 184, 111, 9 }, }, - { { 8, 179, 56, 11, 15 }, - { 71, 50, 93, 20, 5 }, - { 253, 1, 204, 209, 0 }, - { 162, 139, 164, 206, 2 }, }, - { { 12, 162, 165, 217, 4 }, - { 147, 161, 216, 12, 6 }, - { 41, 186, 84, 83, 0 }, - { 99, 1, 184, 92, 9 }, }, - { { 8, 227, 82, 192, 1 }, - { 39, 70, 24, 24, 2 }, - { 128, 52, 172, 113, 0 }, - { 65, 129, 134, 46, 4 }, }, - { { 14, 255, 68, 245, 14 }, - { 235, 23, 219, 45, 10 }, - { 122, 242, 47, 247, 0 }, - { 91, 77, 190, 141, 7 }, }, - { { 14, 255, 93, 234, 11 }, - { 247, 55, 31, 57, 11 }, - { 213, 123, 175, 247, 0 }, - { 217, 207, 142, 206, 15 }, }, - { { 11, 52, 109, 201, 14 }, - { 115, 49, 69, 109, 6 }, - { 121, 59, 98, 205, 0 }, - { 107, 106, 40, 204, 14 }, }, - { { 13, 9, 254, 187, 3 }, - { 166, 243, 134, 84, 15 }, - { 205, 215, 249, 11, 0 }, - { 242, 166, 28, 246, 5 }, }, - { { 15, 16, 170, 146, 6 }, - { 194, 208, 196, 65, 7 }, - { 100, 149, 80, 143, 0 }, - { 232, 34, 48, 180, 3 }, }, - { { 13, 31, 101, 167, 14 }, - { 250, 19, 75, 100, 15 }, - { 126, 90, 111, 139, 0 }, - { 242, 109, 44, 133, 15 }, }, - { { 15, 177, 95, 160, 0 }, - { 243, 67, 22, 81, 2 }, - { 0, 95, 168, 223, 0 }, - { 72, 166, 140, 44, 15 }, }, - { { 13, 162, 5, 35, 3 }, - { 151, 17, 26, 68, 1 }, - { 204, 74, 4, 91, 0 }, - { 130, 37, 136, 142, 9 }, }, - { { 13, 175, 35, 219, 11 }, - { 151, 114, 153, 108, 15 }, - { 221, 188, 79, 91, 0 }, - { 243, 105, 148, 238, 9 }, }, - { { 11, 240, 165, 238, 4 }, - { 91, 165, 82, 73, 7 }, - { 39, 122, 80, 253, 0 }, - { 233, 36, 170, 93, 10 }, }, - { { 13, 200, 153, 251, 14 }, - { 146, 180, 215, 92, 11 }, - { 125, 249, 145, 59, 0 }, - { 211, 174, 178, 212, 9 }, }, - { { 15, 253, 48, 39, 7 }, - { 207, 22, 82, 117, 13 }, - { 238, 64, 203, 255, 0 }, - { 186, 228, 166, 143, 3 }, }, - { { 11, 199, 93, 86, 2 }, - { 58, 23, 156, 121, 1 }, - { 70, 171, 174, 61, 0 }, - { 137, 227, 158, 133, 12 }, }, - { { 18, 47, 163, 1, 13 }, - { 21, 202, 73, 37, 12 }, - { 184, 12, 95, 68, 8 }, - { 58, 73, 37, 58, 8 }, }, - { { 18, 117, 72, 114, 5 }, - { 101, 14, 198, 41, 1 }, - { 164, 225, 42, 228, 8 }, - { 137, 70, 55, 10, 6 }, }, - { { 16, 79, 174, 98, 7 }, - { 4, 223, 78, 40, 13 }, - { 228, 103, 95, 32, 8 }, - { 177, 71, 47, 178, 0 }, }, - { { 16, 140, 138, 232, 11 }, - { 4, 248, 23, 40, 10 }, - { 209, 117, 19, 16, 8 }, - { 81, 78, 129, 242, 0 }, }, - { { 16, 243, 244, 46, 14 }, - { 105, 191, 91, 16, 5 }, - { 119, 66, 252, 240, 8 }, - { 160, 141, 175, 217, 6 }, }, - { { 19, 55, 238, 112, 2 }, - { 97, 219, 142, 105, 4 }, - { 64, 231, 126, 204, 8 }, - { 41, 103, 29, 184, 6 }, }, - { { 23, 11, 35, 235, 0 }, - { 144, 106, 10, 77, 15 }, - { 13, 124, 77, 14, 8 }, - { 251, 37, 5, 96, 9 }, }, - { { 21, 2, 111, 27, 11 }, - { 180, 121, 141, 68, 5 }, - { 221, 143, 100, 10, 8 }, - { 162, 43, 25, 226, 13 }, }, - { { 17, 161, 171, 203, 2 }, - { 17, 250, 20, 76, 7 }, - { 77, 61, 88, 88, 8 }, - { 227, 34, 133, 248, 8 }, }, - { { 19, 166, 74, 200, 13 }, - { 37, 104, 93, 105, 2 }, - { 177, 53, 38, 92, 8 }, - { 73, 107, 161, 106, 4 }, }, - { { 23, 142, 53, 205, 3 }, - { 156, 57, 24, 125, 14 }, - { 203, 58, 199, 30, 8 }, - { 123, 225, 137, 195, 9 }, }, - { { 21, 139, 229, 157, 12 }, - { 184, 171, 217, 68, 14 }, - { 59, 154, 125, 26, 8 }, - { 114, 41, 189, 81, 13 }, }, - { { 23, 166, 249, 125, 4 }, - { 185, 168, 222, 125, 4 }, - { 43, 233, 246, 94, 8 }, - { 43, 231, 177, 89, 13 }, }, - { { 21, 220, 164, 180, 4 }, - { 200, 141, 210, 96, 14 }, - { 34, 210, 83, 186, 8 }, - { 112, 100, 187, 17, 3 }, }, - { { 17, 223, 5, 67, 12 }, - { 80, 15, 89, 108, 9 }, - { 60, 42, 15, 184, 8 }, - { 147, 105, 175, 0, 10 }, }, - { { 21, 210, 1, 147, 5 }, - { 212, 12, 216, 68, 3 }, - { 172, 152, 4, 186, 8 }, - { 194, 33, 179, 2, 11 }, }, - { { 24, 31, 173, 250, 10 }, - { 82, 187, 143, 40, 15 }, - { 85, 251, 95, 129, 8 }, - { 241, 79, 29, 212, 10 }, }, - { { 28, 64, 14, 171, 13 }, - { 134, 109, 71, 4, 3 }, - { 189, 87, 0, 35, 8 }, - { 194, 14, 43, 102, 1 }, }, - { { 30, 76, 93, 61, 2 }, - { 186, 61, 134, 53, 8 }, - { 75, 203, 163, 39, 8 }, - { 26, 198, 27, 197, 13 }, }, - { { 24, 111, 246, 127, 9 }, - { 47, 239, 139, 60, 13 }, - { 159, 230, 255, 97, 8 }, - { 179, 205, 31, 127, 4 }, }, - { { 24, 87, 52, 184, 15 }, - { 70, 63, 203, 48, 6 }, - { 241, 210, 206, 161, 8 }, - { 96, 205, 63, 198, 2 }, }, - { { 30, 86, 137, 227, 4 }, - { 210, 140, 78, 45, 3 }, - { 44, 121, 22, 167, 8 }, - { 203, 71, 35, 20, 11 }, }, - { { 26, 149, 209, 132, 5 }, - { 126, 138, 80, 49, 2 }, - { 162, 24, 186, 149, 8 }, - { 72, 192, 165, 23, 14 }, }, - { { 24, 167, 255, 2, 10 }, - { 51, 219, 29, 48, 5 }, - { 84, 15, 254, 81, 8 }, - { 160, 203, 141, 188, 12 }, }, - { { 24, 158, 177, 201, 14 }, - { 82, 184, 89, 60, 14 }, - { 121, 56, 215, 145, 8 }, - { 115, 201, 161, 212, 10 }, }, - { { 28, 178, 10, 96, 10 }, - { 195, 88, 31, 8, 0 }, - { 80, 101, 4, 211, 8 }, - { 1, 15, 129, 172, 3 }, }, - { { 28, 146, 53, 136, 1 }, - { 214, 41, 24, 16, 6 }, - { 129, 26, 196, 147, 8 }, - { 96, 129, 137, 70, 11 }, }, - { { 28, 147, 183, 214, 13 }, - { 222, 203, 217, 24, 7 }, - { 182, 190, 220, 147, 8 }, - { 225, 137, 189, 55, 11 }, }, - { { 26, 202, 188, 88, 1 }, - { 6, 173, 156, 25, 12 }, - { 129, 163, 213, 53, 8 }, - { 57, 131, 155, 86, 0 }, }, - { { 28, 226, 172, 181, 8 }, - { 139, 141, 159, 4, 6 }, - { 26, 211, 84, 115, 8 }, - { 98, 15, 155, 29, 1 }, }, - { { 27, 121, 237, 6, 4 }, - { 123, 143, 68, 65, 13 }, - { 38, 11, 121, 237, 8 }, - { 184, 34, 47, 29, 14 }, }, - { { 31, 106, 57, 19, 2 }, - { 147, 28, 140, 85, 13 }, - { 76, 137, 197, 111, 8 }, - { 186, 163, 19, 140, 9 }, }, - { { 29, 152, 56, 117, 0 }, - { 202, 8, 150, 92, 12 }, - { 10, 225, 193, 155, 8 }, - { 51, 166, 145, 5, 3 }, }, - { { 32, 13, 193, 3, 15 }, - { 52, 146, 97, 36, 9 }, - { 252, 8, 59, 0, 4 }, - { 146, 72, 100, 146, 12 }, }, - { { 38, 53, 212, 232, 0 }, - { 225, 163, 34, 57, 2 }, - { 1, 114, 186, 198, 4 }, - { 73, 196, 76, 88, 7 }, }, - { { 38, 117, 44, 47, 8 }, - { 201, 39, 39, 37, 5 }, - { 31, 67, 74, 230, 4 }, - { 170, 78, 78, 73, 3 }, }, - { { 32, 83, 133, 143, 6 }, - { 88, 183, 104, 4, 3 }, - { 111, 26, 28, 160, 4 }, - { 194, 1, 110, 209, 10 }, }, - { { 34, 136, 31, 122, 3 }, - { 20, 113, 182, 25, 9 }, - { 197, 239, 129, 20, 4 }, - { 153, 134, 216, 226, 8 }, }, - { { 39, 44, 250, 229, 5 }, - { 173, 192, 102, 125, 14 }, - { 170, 117, 243, 78, 4 }, - { 123, 230, 96, 59, 5 }, }, - { { 33, 107, 76, 67, 11 }, - { 37, 23, 45, 76, 9 }, - { 220, 35, 45, 104, 4 }, - { 147, 43, 78, 138, 4 }, }, - { { 37, 188, 103, 11, 10 }, - { 241, 113, 49, 100, 13 }, - { 93, 14, 99, 218, 4 }, - { 178, 104, 200, 232, 15 }, }, - { { 33, 163, 233, 176, 14 }, - { 49, 146, 255, 64, 6 }, - { 112, 217, 124, 88, 4 }, - { 96, 47, 244, 152, 12 }, }, - { { 33, 150, 242, 145, 15 }, - { 100, 208, 249, 116, 6 }, - { 248, 148, 246, 152, 4 }, - { 98, 233, 240, 178, 6 }, }, - { { 39, 162, 43, 140, 10 }, - { 153, 112, 61, 65, 6 }, - { 83, 29, 68, 94, 4 }, - { 104, 43, 192, 233, 9 }, }, - { { 39, 159, 72, 50, 8 }, - { 224, 2, 191, 97, 9 }, - { 20, 193, 47, 158, 4 }, - { 152, 111, 212, 0, 7 }, }, - { { 35, 226, 188, 201, 7 }, - { 5, 181, 124, 93, 6 }, - { 233, 51, 212, 124, 4 }, - { 107, 163, 234, 218, 0 }, }, - { { 33, 194, 87, 244, 1 }, - { 60, 69, 186, 88, 2 }, - { 130, 254, 164, 56, 4 }, - { 65, 165, 218, 35, 12 }, }, - { { 39, 207, 186, 248, 11 }, - { 132, 246, 191, 121, 14 }, - { 209, 245, 223, 62, 4 }, - { 121, 239, 214, 242, 1 }, }, - { { 42, 47, 189, 228, 11 }, - { 31, 147, 47, 57, 14 }, - { 210, 123, 223, 69, 4 }, - { 121, 207, 76, 159, 8 }, }, - { { 42, 84, 58, 140, 12 }, - { 74, 100, 101, 49, 6 }, - { 51, 21, 194, 165, 4 }, - { 104, 202, 98, 101, 2 }, }, - { { 42, 209, 187, 151, 15 }, - { 94, 214, 245, 21, 7 }, - { 254, 157, 216, 181, 4 }, - { 234, 138, 246, 183, 10 }, }, - { { 40, 255, 58, 99, 1 }, - { 71, 70, 62, 60, 13 }, - { 140, 101, 207, 241, 4 }, - { 179, 199, 198, 46, 2 }, }, - { { 43, 84, 197, 185, 8 }, - { 114, 165, 163, 101, 2 }, - { 25, 218, 50, 173, 4 }, - { 74, 108, 90, 84, 14 }, }, - { { 45, 97, 175, 26, 10 }, - { 147, 247, 165, 64, 5 }, - { 85, 143, 88, 107, 4 }, - { 160, 42, 94, 252, 9 }, }, - { { 43, 188, 219, 62, 6 }, - { 123, 240, 246, 113, 9 }, - { 103, 205, 179, 221, 4 }, - { 152, 230, 240, 253, 14 }, }, - { { 45, 159, 154, 13, 2 }, - { 202, 242, 60, 116, 8 }, - { 75, 5, 159, 155, 4 }, - { 18, 227, 196, 245, 3 }, }, - { { 47, 187, 114, 106, 3 }, - { 231, 114, 58, 89, 13 }, - { 197, 100, 237, 223, 4 }, - { 185, 165, 196, 238, 7 }, }, - { { 43, 217, 204, 255, 7 }, - { 110, 183, 246, 77, 11 }, - { 239, 243, 57, 189, 4 }, - { 219, 38, 254, 215, 6 }, }, - { { 41, 198, 223, 142, 12 }, - { 58, 229, 125, 112, 3 }, - { 55, 31, 182, 57, 4 }, - { 192, 235, 234, 117, 12 }, }, - { { 52, 12, 63, 195, 5 }, - { 148, 73, 100, 60, 15 }, - { 172, 63, 195, 2, 12 }, - { 243, 194, 105, 34, 9 }, }, - { { 48, 3, 27, 40, 14 }, - { 16, 122, 111, 16, 0 }, - { 113, 77, 140, 0, 12 }, - { 0, 143, 101, 224, 8 }, }, - { { 48, 113, 29, 236, 3 }, - { 93, 63, 38, 24, 2 }, - { 195, 123, 136, 224, 12 }, - { 65, 134, 79, 203, 10 }, }, - { { 52, 76, 222, 162, 10 }, - { 160, 221, 39, 48, 11 }, - { 84, 87, 179, 34, 12 }, - { 208, 206, 75, 176, 5 }, }, - { { 50, 122, 138, 139, 12 }, - { 65, 236, 109, 5, 11 }, - { 61, 21, 21, 228, 12 }, - { 218, 11, 99, 120, 2 }, }, - { { 54, 87, 99, 215, 2 }, - { 248, 94, 168, 45, 7 }, - { 78, 188, 110, 166, 12 }, - { 235, 65, 87, 161, 15 }, }, - { { 52, 141, 50, 170, 6 }, - { 128, 122, 114, 48, 15 }, - { 101, 84, 203, 18, 12 }, - { 240, 196, 229, 224, 1 }, }, - { { 54, 129, 250, 177, 1 }, - { 164, 202, 182, 21, 6 }, - { 136, 213, 248, 22, 12 }, - { 106, 134, 213, 50, 5 }, }, - { { 54, 153, 111, 21, 13 }, - { 252, 75, 245, 5, 12 }, - { 186, 143, 105, 150, 12 }, - { 58, 10, 253, 35, 15 }, }, - { { 50, 204, 108, 49, 14 }, - { 32, 29, 247, 37, 12 }, - { 120, 195, 99, 52, 12 }, - { 58, 78, 251, 128, 4 }, }, - { { 54, 224, 7, 77, 4 }, - { 153, 109, 112, 13, 0 }, - { 43, 46, 0, 118, 12 }, - { 11, 0, 235, 105, 9 }, }, - { { 51, 64, 141, 156, 5 }, - { 28, 173, 228, 65, 2 }, - { 163, 155, 16, 44, 12 }, - { 72, 34, 123, 83, 8 }, }, - { { 51, 125, 174, 182, 10 }, - { 73, 223, 167, 97, 15 }, - { 86, 215, 91, 236, 12 }, - { 248, 110, 95, 185, 2 }, }, - { { 49, 94, 255, 61, 1 }, - { 124, 237, 174, 116, 12 }, - { 139, 207, 247, 168, 12 }, - { 50, 231, 91, 115, 14 }, }, - { { 53, 164, 249, 40, 11 }, - { 181, 184, 55, 112, 4 }, - { 209, 73, 242, 90, 12 }, - { 32, 238, 193, 218, 13 }, }, - { { 51, 134, 161, 198, 4 }, - { 24, 136, 120, 105, 7 }, - { 38, 56, 86, 28, 12 }, - { 233, 97, 225, 17, 8 }, }, - { { 53, 232, 26, 158, 12 }, - { 137, 108, 245, 80, 11 }, - { 55, 149, 129, 122, 12 }, - { 208, 170, 243, 105, 1 }, }, - { { 55, 216, 88, 186, 3 }, - { 228, 60, 182, 81, 11 }, - { 197, 209, 161, 190, 12 }, - { 216, 166, 211, 194, 7 }, }, - { { 56, 21, 51, 89, 12 }, - { 82, 106, 225, 60, 4 }, - { 57, 172, 202, 129, 12 }, - { 35, 200, 117, 100, 10 }, }, - { { 56, 27, 98, 106, 12 }, - { 98, 106, 107, 8, 13 }, - { 53, 100, 109, 129, 12 }, - { 177, 13, 101, 100, 6 }, }, - { { 58, 54, 80, 219, 10 }, - { 99, 56, 169, 61, 3 }, - { 93, 176, 166, 197, 12 }, - { 203, 201, 81, 204, 6 }, }, - { { 56, 136, 209, 242, 9 }, - { 54, 136, 179, 24, 11 }, - { 148, 248, 177, 17, 12 }, - { 209, 140, 209, 22, 12 }, }, - { { 58, 204, 141, 200, 2 }, - { 18, 189, 52, 41, 10 }, - { 65, 59, 19, 53, 12 }, - { 89, 66, 203, 212, 8 }, }, - { { 60, 252, 249, 7, 11 }, - { 255, 156, 53, 52, 13 }, - { 222, 9, 243, 243, 12 }, - { 178, 202, 195, 159, 15 }, }, - { { 60, 246, 137, 57, 12 }, - { 211, 172, 255, 36, 0 }, - { 57, 201, 22, 243, 12 }, - { 2, 79, 243, 92, 11 }, }, - { { 59, 15, 174, 199, 9 }, - { 14, 203, 45, 109, 15 }, - { 158, 55, 95, 13, 12 }, - { 251, 107, 77, 55, 0 }, }, - { { 61, 11, 95, 245, 6 }, - { 186, 91, 238, 92, 10 }, - { 106, 255, 173, 11, 12 }, - { 83, 167, 125, 165, 13 }, }, - { { 57, 73, 131, 170, 6 }, - { 18, 254, 98, 64, 11 }, - { 101, 92, 25, 41, 12 }, - { 208, 36, 103, 244, 8 }, }, - { { 61, 92, 175, 229, 6 }, - { 218, 221, 102, 108, 14 }, - { 106, 127, 83, 171, 12 }, - { 115, 102, 107, 181, 11 }, }, - { { 59, 111, 209, 254, 2 }, - { 59, 190, 170, 121, 11 }, - { 71, 248, 191, 109, 12 }, - { 217, 229, 87, 221, 12 }, }, - { { 61, 114, 229, 206, 7 }, - { 255, 189, 104, 72, 7 }, - { 231, 58, 116, 235, 12 }, - { 225, 33, 107, 223, 15 }, }, - { { 59, 165, 24, 48, 4 }, - { 3, 10, 246, 113, 0 }, - { 32, 193, 138, 93, 12 }, - { 8, 230, 245, 12, 0 }, }, - { { 59, 215, 215, 116, 14 }, - { 122, 223, 251, 121, 0 }, - { 114, 238, 190, 189, 12 }, - { 9, 237, 255, 181, 14 }, }, - { { 66, 21, 7, 134, 1 }, - { 92, 67, 0, 161, 3 }, - { 134, 30, 10, 132, 2 }, - { 200, 80, 12, 35, 10 }, }, - { { 68, 42, 51, 204, 5 }, - { 157, 96, 72, 152, 14 }, - { 163, 60, 197, 66, 2 }, - { 113, 145, 32, 107, 9 }, }, - { { 64, 105, 62, 32, 12 }, - { 1, 71, 71, 144, 12 }, - { 48, 71, 201, 96, 2 }, - { 48, 158, 46, 40, 0 }, }, - { { 68, 76, 84, 241, 12 }, - { 160, 5, 195, 188, 10 }, - { 56, 242, 163, 34, 2 }, - { 83, 220, 58, 0, 5 }, }, - { { 64, 78, 207, 5, 5 }, - { 60, 197, 76, 164, 8 }, - { 170, 15, 55, 32, 2 }, - { 18, 83, 42, 51, 12 }, }, - { { 64, 223, 74, 196, 6 }, - { 104, 86, 92, 168, 10 }, - { 98, 53, 47, 176, 2 }, - { 81, 83, 166, 161, 6 }, }, - { { 70, 218, 103, 26, 14 }, - { 240, 117, 217, 129, 13 }, - { 117, 142, 101, 182, 2 }, - { 184, 25, 186, 224, 15 }, }, - { { 67, 32, 239, 178, 13 }, - { 53, 193, 199, 193, 7 }, - { 180, 223, 112, 76, 2 }, - { 232, 62, 56, 58, 12 }, }, - { { 65, 99, 121, 242, 7 }, - { 53, 22, 206, 216, 7 }, - { 228, 249, 236, 104, 2 }, - { 225, 183, 54, 138, 12 }, }, - { { 71, 127, 169, 44, 10 }, - { 217, 182, 15, 225, 12 }, - { 83, 73, 95, 238, 2 }, - { 56, 127, 6, 217, 11 }, }, - { { 67, 168, 36, 115, 10 }, - { 1, 17, 147, 205, 13 }, - { 92, 226, 65, 92, 2 }, - { 187, 60, 152, 136, 0 }, }, - { { 69, 174, 2, 166, 1 }, - { 141, 64, 26, 224, 11 }, - { 134, 84, 7, 90, 2 }, - { 208, 117, 128, 43, 1 }, }, - { { 72, 29, 125, 107, 6 }, - { 114, 51, 70, 188, 13 }, - { 109, 107, 235, 129, 2 }, - { 179, 214, 44, 196, 14 }, }, - { { 72, 68, 41, 14, 4 }, - { 26, 36, 68, 160, 5 }, - { 39, 9, 66, 33, 2 }, - { 160, 82, 34, 69, 8 }, }, - { { 76, 93, 176, 242, 6 }, - { 194, 150, 194, 184, 15 }, - { 100, 240, 219, 163, 2 }, - { 241, 212, 54, 148, 3 }, }, - { { 72, 79, 166, 76, 0 }, - { 10, 231, 8, 168, 12 }, - { 3, 38, 95, 33, 2 }, - { 49, 81, 14, 117, 0 }, }, - { { 72, 129, 242, 45, 11 }, - { 46, 242, 19, 148, 4 }, - { 219, 68, 248, 17, 2 }, - { 34, 156, 132, 247, 4 }, }, - { { 72, 140, 105, 154, 11 }, - { 54, 48, 149, 160, 15 }, - { 213, 153, 99, 17, 2 }, - { 240, 90, 144, 198, 12 }, }, - { { 76, 230, 39, 197, 2 }, - { 155, 85, 24, 172, 6 }, - { 74, 62, 70, 115, 2 }, - { 99, 81, 138, 173, 9 }, }, - { { 79, 61, 163, 205, 7 }, - { 223, 242, 64, 237, 14 }, - { 235, 60, 91, 207, 2 }, - { 123, 112, 36, 255, 11 }, }, - { { 73, 73, 253, 184, 8 }, - { 50, 167, 135, 208, 14 }, - { 17, 219, 249, 41, 2 }, - { 112, 190, 30, 84, 12 }, }, - { { 77, 89, 111, 25, 7 }, - { 246, 119, 196, 196, 12 }, - { 233, 143, 105, 171, 2 }, - { 50, 50, 62, 230, 15 }, }, - { { 79, 79, 213, 39, 11 }, - { 190, 151, 11, 245, 9 }, - { 222, 74, 191, 47, 2 }, - { 154, 253, 14, 151, 13 }, }, - { { 75, 148, 100, 228, 11 }, - { 110, 17, 19, 233, 6 }, - { 210, 114, 98, 157, 2 }, - { 105, 124, 136, 135, 6 }, }, - { { 77, 160, 106, 169, 14 }, - { 163, 112, 87, 196, 6 }, - { 121, 85, 96, 91, 2 }, - { 98, 62, 160, 236, 5 }, }, - { { 75, 146, 209, 251, 2 }, - { 114, 176, 154, 221, 3 }, - { 77, 248, 180, 157, 2 }, - { 203, 181, 144, 212, 14 }, }, - { { 79, 237, 128, 190, 11 }, - { 143, 182, 147, 225, 11 }, - { 215, 208, 27, 127, 2 }, - { 216, 124, 150, 223, 1 }, }, - { { 73, 250, 110, 175, 3 }, - { 111, 117, 30, 196, 15 }, - { 207, 87, 101, 249, 2 }, - { 242, 55, 138, 239, 6 }, }, - { { 84, 32, 172, 167, 7 }, - { 141, 153, 70, 132, 7 }, - { 238, 83, 80, 66, 10 }, - { 226, 22, 41, 155, 1 }, }, - { { 84, 25, 164, 142, 8 }, - { 200, 171, 1, 128, 15 }, - { 23, 18, 89, 130, 10 }, - { 240, 24, 13, 81, 3 }, }, - { { 86, 116, 218, 31, 8 }, - { 233, 236, 133, 181, 1 }, - { 31, 133, 178, 230, 10 }, - { 138, 218, 19, 121, 7 }, }, - { { 82, 70, 69, 212, 11 }, - { 60, 29, 137, 169, 2 }, - { 210, 186, 38, 36, 10 }, - { 73, 89, 27, 131, 12 }, }, - { { 80, 153, 112, 192, 3 }, - { 100, 26, 16, 152, 14 }, - { 192, 48, 233, 144, 10 }, - { 113, 144, 133, 130, 6 }, }, - { { 82, 162, 196, 106, 5 }, - { 37, 169, 90, 137, 1 }, - { 165, 98, 52, 84, 10 }, - { 137, 21, 169, 90, 4 }, }, - { { 80, 232, 170, 66, 4 }, - { 1, 204, 84, 136, 13 }, - { 36, 37, 81, 112, 10 }, - { 177, 18, 163, 56, 0 }, }, - { { 82, 242, 173, 89, 8 }, - { 81, 173, 157, 141, 4 }, - { 25, 171, 84, 244, 10 }, - { 43, 27, 155, 88, 10 }, }, - { { 82, 218, 235, 246, 10 }, - { 120, 220, 159, 137, 15 }, - { 86, 253, 117, 180, 10 }, - { 249, 31, 147, 177, 14 }, }, - { { 85, 46, 248, 226, 2 }, - { 161, 152, 14, 248, 15 }, - { 68, 113, 247, 74, 10 }, - { 241, 247, 1, 152, 5 }, }, - { { 81, 65, 96, 182, 2 }, - { 40, 30, 130, 192, 7 }, - { 70, 208, 104, 40, 10 }, - { 224, 52, 23, 129, 4 }, }, - { { 85, 104, 6, 21, 8 }, - { 137, 77, 129, 196, 8 }, - { 26, 134, 1, 106, 10 }, - { 18, 56, 27, 41, 1 }, }, - { { 83, 74, 126, 75, 13 }, - { 36, 109, 77, 221, 13 }, - { 189, 39, 229, 44, 10 }, - { 187, 187, 43, 98, 4 }, }, - { { 83, 107, 211, 224, 11 }, - { 53, 222, 11, 217, 10 }, - { 208, 124, 189, 108, 10 }, - { 89, 189, 7, 186, 12 }, }, - { { 87, 114, 130, 210, 7 }, - { 197, 220, 200, 201, 3 }, - { 228, 180, 20, 238, 10 }, - { 201, 49, 51, 186, 3 }, }, - { { 87, 129, 213, 88, 2 }, - { 176, 187, 144, 217, 0 }, - { 65, 170, 184, 30, 10 }, - { 9, 176, 157, 208, 13 }, }, - { { 87, 164, 195, 74, 8 }, - { 177, 232, 17, 233, 1 }, - { 21, 44, 50, 94, 10 }, - { 137, 120, 129, 120, 13 }, }, - { { 81, 151, 175, 148, 8 }, - { 88, 203, 157, 224, 6 }, - { 18, 159, 94, 152, 10 }, - { 96, 123, 157, 49, 10 }, }, - { { 87, 143, 23, 115, 11 }, - { 148, 91, 155, 253, 9 }, - { 220, 238, 143, 30, 10 }, - { 155, 253, 157, 162, 9 }, }, - { { 85, 194, 224, 207, 0 }, - { 168, 172, 24, 204, 7 }, - { 15, 48, 116, 58, 10 }, - { 227, 49, 131, 81, 5 }, }, - { { 87, 246, 164, 229, 1 }, - { 205, 141, 26, 237, 6 }, - { 138, 114, 86, 254, 10 }, - { 107, 117, 139, 27, 3 }, }, - { { 92, 5, 94, 2, 5 }, - { 166, 75, 68, 176, 1 }, - { 164, 7, 170, 3, 10 }, - { 128, 210, 45, 38, 5 }, }, - { { 94, 56, 204, 77, 0 }, - { 235, 169, 4, 141, 8 }, - { 11, 35, 49, 199, 10 }, - { 27, 18, 9, 93, 7 }, }, - { { 94, 101, 102, 31, 5 }, - { 175, 111, 192, 165, 5 }, - { 175, 134, 106, 103, 10 }, - { 170, 80, 63, 111, 5 }, }, - { { 90, 165, 235, 123, 5 }, - { 55, 234, 214, 173, 5 }, - { 173, 237, 122, 85, 10 }, - { 171, 86, 181, 126, 12 }, }, - { { 94, 173, 81, 224, 13 }, - { 183, 10, 83, 185, 10 }, - { 176, 120, 171, 87, 10 }, - { 89, 220, 165, 14, 13 }, }, - { { 88, 179, 133, 252, 1 }, - { 95, 171, 154, 136, 2 }, - { 131, 250, 28, 209, 10 }, - { 65, 21, 157, 95, 10 }, }, - { { 90, 197, 248, 110, 0 }, - { 42, 174, 22, 185, 5 }, - { 7, 97, 250, 53, 10 }, - { 169, 214, 135, 85, 4 }, }, - { { 88, 241, 107, 96, 0 }, - { 115, 78, 22, 136, 4 }, - { 0, 109, 104, 241, 10 }, - { 33, 22, 135, 44, 14 }, }, - { { 91, 48, 177, 32, 8 }, - { 83, 136, 3, 209, 4 }, - { 16, 72, 208, 205, 10 }, - { 40, 188, 1, 28, 10 }, }, - { { 95, 52, 239, 231, 11 }, - { 255, 217, 7, 237, 7 }, - { 222, 127, 114, 207, 10 }, - { 235, 126, 9, 191, 15 }, }, - { { 89, 64, 115, 102, 9 }, - { 62, 76, 3, 216, 5 }, - { 150, 108, 224, 41, 10 }, - { 161, 188, 3, 39, 12 }, }, - { { 93, 105, 19, 173, 1 }, - { 159, 110, 2, 212, 10 }, - { 139, 92, 137, 107, 10 }, - { 82, 180, 7, 111, 9 }, }, - { { 89, 82, 185, 227, 11 }, - { 86, 156, 15, 220, 7 }, - { 220, 121, 212, 169, 10 }, - { 227, 191, 3, 150, 10 }, }, - { { 93, 70, 244, 172, 2 }, - { 170, 189, 10, 240, 6 }, - { 67, 82, 246, 43, 10 }, - { 96, 245, 11, 213, 5 }, }, - { { 95, 128, 157, 46, 8 }, - { 154, 169, 23, 209, 1 }, - { 23, 75, 144, 31, 10 }, - { 136, 190, 137, 85, 9 }, }, - { { 95, 224, 251, 80, 14 }, - { 179, 220, 213, 217, 4 }, - { 112, 173, 240, 127, 10 }, - { 41, 186, 179, 188, 13 }, }, - { { 95, 235, 211, 215, 0 }, - { 187, 206, 152, 221, 11 }, - { 14, 188, 189, 127, 10 }, - { 219, 177, 151, 61, 13 }, }, - { { 100, 105, 134, 115, 5 }, - { 133, 199, 226, 140, 9 }, - { 172, 230, 25, 98, 6 }, - { 147, 20, 126, 58, 1 }, }, - { { 96, 188, 232, 205, 8 }, - { 105, 160, 53, 172, 14 }, - { 27, 49, 115, 208, 6 }, - { 115, 90, 192, 89, 6 }, }, - { { 100, 158, 227, 5, 6 }, - { 248, 208, 120, 164, 12 }, - { 106, 12, 119, 146, 6 }, - { 50, 81, 224, 177, 15 }, }, - { { 98, 212, 165, 37, 13 }, - { 92, 133, 115, 165, 4 }, - { 186, 74, 82, 180, 6 }, - { 42, 92, 234, 19, 10 }, }, - { { 98, 246, 143, 142, 3 }, - { 93, 245, 60, 161, 3 }, - { 199, 31, 22, 244, 6 }, - { 200, 83, 202, 251, 10 }, }, - { { 101, 96, 72, 36, 7 }, - { 173, 20, 102, 192, 0 }, - { 226, 65, 32, 106, 6 }, - { 0, 54, 98, 139, 5 }, }, - { { 99, 180, 12, 145, 8 }, - { 65, 1, 181, 229, 2 }, - { 24, 147, 2, 220, 6 }, - { 74, 122, 216, 8, 2 }, }, - { { 99, 159, 233, 153, 13 }, - { 116, 162, 253, 229, 14 }, - { 185, 153, 127, 156, 6 }, - { 122, 123, 244, 82, 14 }, }, - { { 101, 237, 229, 156, 7 }, - { 189, 183, 240, 224, 14 }, - { 227, 154, 123, 122, 6 }, - { 112, 112, 254, 219, 13 }, }, - { { 103, 235, 231, 112, 4 }, - { 177, 199, 250, 201, 12 }, - { 32, 238, 125, 126, 6 }, - { 57, 53, 254, 56, 13 }, }, - { { 106, 1, 200, 157, 4 }, - { 42, 162, 228, 133, 2 }, - { 43, 145, 56, 5, 6 }, - { 74, 18, 116, 85, 4 }, }, - { { 104, 61, 242, 11, 0 }, - { 99, 226, 32, 180, 13 }, - { 13, 4, 251, 193, 6 }, - { 178, 208, 68, 124, 6 }, }, - { { 104, 24, 102, 125, 13 }, - { 110, 97, 227, 140, 12 }, - { 187, 230, 97, 129, 6 }, - { 51, 28, 120, 103, 6 }, }, - { { 108, 84, 97, 80, 15 }, - { 246, 20, 225, 168, 4 }, - { 240, 168, 98, 163, 6 }, - { 33, 88, 114, 134, 15 }, }, - { { 104, 75, 24, 245, 13 }, - { 14, 6, 239, 156, 10 }, - { 186, 241, 141, 33, 6 }, - { 83, 159, 118, 7, 0 }, }, - { { 104, 79, 21, 129, 0 }, - { 18, 7, 40, 180, 10 }, - { 8, 26, 143, 33, 6 }, - { 82, 209, 78, 4, 8 }, }, - { { 110, 110, 244, 89, 0 }, - { 163, 165, 168, 189, 12 }, - { 9, 162, 247, 103, 6 }, - { 59, 209, 90, 92, 5 }, }, - { { 110, 152, 128, 38, 5 }, - { 206, 128, 114, 129, 9 }, - { 166, 64, 17, 151, 6 }, - { 152, 20, 224, 23, 3 }, }, - { { 110, 144, 99, 51, 3 }, - { 246, 80, 178, 133, 5 }, - { 204, 204, 96, 151, 6 }, - { 170, 20, 208, 166, 15 }, }, - { { 110, 241, 228, 10, 7 }, - { 231, 183, 112, 129, 5 }, - { 229, 2, 120, 247, 6 }, - { 168, 16, 238, 222, 7 }, }, - { { 108, 195, 36, 252, 0 }, - { 138, 39, 186, 136, 6 }, - { 3, 242, 76, 51, 6 }, - { 97, 21, 222, 69, 1 }, }, - { { 105, 0, 81, 91, 15 }, - { 54, 48, 225, 220, 1 }, - { 253, 168, 160, 9, 6 }, - { 131, 184, 112, 198, 12 }, }, - { { 107, 64, 14, 250, 12 }, - { 2, 101, 231, 201, 3 }, - { 53, 247, 0, 45, 6 }, - { 201, 62, 122, 100, 0 }, }, - { { 107, 124, 181, 68, 7 }, - { 95, 149, 96, 249, 12 }, - { 226, 42, 211, 237, 6 }, - { 57, 240, 106, 159, 10 }, }, - { { 105, 172, 245, 202, 2 }, - { 51, 177, 48, 248, 15 }, - { 69, 58, 243, 89, 6 }, - { 241, 240, 200, 220, 12 }, }, - { { 105, 167, 102, 247, 12 }, - { 43, 67, 251, 236, 7 }, - { 62, 246, 110, 89, 6 }, - { 227, 125, 252, 45, 4 }, }, - { { 109, 235, 50, 140, 11 }, - { 143, 118, 57, 208, 14 }, - { 211, 20, 205, 123, 6 }, - { 112, 185, 198, 239, 1 }, }, - { { 116, 23, 252, 110, 12 }, - { 232, 171, 111, 184, 5 }, - { 55, 99, 254, 130, 14 }, - { 161, 223, 109, 81, 7 }, }, - { { 112, 97, 170, 185, 4 }, - { 1, 238, 230, 132, 6 }, - { 41, 213, 88, 96, 14 }, - { 98, 22, 119, 120, 0 }, }, - { { 116, 67, 17, 82, 1 }, - { 148, 14, 168, 152, 1 }, - { 132, 168, 140, 34, 14 }, - { 129, 145, 87, 2, 9 }, }, - { { 112, 185, 187, 138, 9 }, - { 85, 234, 53, 144, 15 }, - { 149, 29, 217, 208, 14 }, - { 240, 154, 197, 122, 10 }, }, - { { 118, 148, 62, 229, 4 }, - { 200, 73, 118, 189, 6 }, - { 42, 119, 194, 150, 14 }, - { 107, 214, 233, 33, 3 }, }, - { { 118, 188, 96, 18, 9 }, - { 229, 8, 177, 161, 13 }, - { 148, 128, 99, 214, 14 }, - { 184, 88, 209, 10, 7 }, }, - { { 112, 155, 7, 165, 4 }, - { 88, 75, 122, 132, 10 }, - { 42, 94, 13, 144, 14 }, - { 82, 21, 237, 33, 10 }, }, - { { 116, 139, 191, 1, 3 }, - { 148, 219, 60, 148, 12 }, - { 200, 15, 221, 18, 14 }, - { 50, 147, 205, 178, 9 }, }, - { { 114, 248, 93, 79, 11 }, - { 125, 61, 53, 157, 9 }, - { 223, 43, 161, 244, 14 }, - { 155, 154, 203, 203, 14 }, }, - { { 118, 211, 218, 167, 15 }, - { 236, 222, 127, 149, 3 }, - { 254, 85, 188, 182, 14 }, - { 202, 159, 231, 179, 7 }, }, - { { 117, 36, 208, 249, 9 }, - { 165, 168, 163, 252, 2 }, - { 153, 240, 178, 74, 14 }, - { 67, 252, 81, 90, 5 }, }, - { { 117, 60, 188, 48, 6 }, - { 193, 153, 230, 240, 12 }, - { 96, 195, 211, 202, 14 }, - { 48, 246, 121, 152, 3 }, }, - { { 119, 3, 201, 213, 15 }, - { 188, 154, 237, 205, 2 }, - { 250, 185, 60, 14, 14 }, - { 75, 59, 117, 147, 13 }, }, - { { 113, 69, 59, 42, 5 }, - { 20, 110, 102, 240, 5 }, - { 165, 77, 202, 40, 14 }, - { 160, 246, 103, 98, 8 }, }, - { { 115, 108, 25, 223, 1 }, - { 29, 44, 164, 253, 11 }, - { 143, 185, 131, 108, 14 }, - { 219, 242, 83, 75, 8 }, }, - { { 113, 72, 238, 44, 10 }, - { 40, 253, 39, 192, 12 }, - { 83, 71, 113, 40, 14 }, - { 48, 62, 75, 241, 4 }, }, - { { 115, 111, 34, 124, 0 }, - { 9, 110, 170, 233, 12 }, - { 3, 228, 79, 108, 14 }, - { 57, 117, 87, 105, 0 }, }, - { { 115, 145, 99, 174, 14 }, - { 120, 122, 115, 193, 7 }, - { 119, 92, 104, 156, 14 }, - { 232, 60, 229, 225, 14 }, }, - { { 117, 131, 158, 142, 9 }, - { 140, 235, 61, 208, 3 }, - { 151, 23, 156, 26, 14 }, - { 192, 187, 205, 115, 1 }, }, - { { 119, 191, 100, 123, 6 }, - { 225, 59, 250, 237, 13 }, - { 109, 226, 111, 222, 14 }, - { 187, 117, 253, 200, 7 }, }, - { { 115, 229, 189, 18, 10 }, - { 17, 159, 181, 241, 5 }, - { 84, 139, 218, 124, 14 }, - { 168, 250, 223, 152, 8 }, }, - { { 115, 207, 104, 128, 3 }, - { 36, 30, 60, 225, 14 }, - { 192, 17, 111, 60, 14 }, - { 120, 115, 199, 130, 4 }, }, - { { 113, 247, 74, 10, 0 }, - { 97, 110, 60, 224, 1 }, - { 5, 5, 46, 248, 14 }, - { 128, 115, 199, 104, 6 }, }, - { { 120, 45, 207, 39, 6 }, - { 59, 219, 102, 164, 9 }, - { 110, 79, 59, 65, 14 }, - { 146, 86, 109, 189, 12 }, }, - { { 124, 2, 58, 157, 7 }, - { 142, 120, 236, 148, 6 }, - { 235, 149, 196, 3, 14 }, - { 98, 147, 113, 231, 1 }, }, - { { 122, 92, 206, 58, 4 }, - { 98, 237, 230, 161, 9 }, - { 37, 199, 51, 165, 14 }, - { 152, 86, 123, 116, 6 }, }, - { { 122, 114, 16, 7, 7 }, - { 79, 28, 104, 149, 1 }, - { 238, 0, 132, 229, 14 }, - { 138, 145, 99, 143, 2 }, }, - { { 126, 178, 36, 208, 11 }, - { 199, 25, 185, 137, 6 }, - { 208, 178, 68, 215, 14 }, - { 105, 25, 217, 142, 3 }, }, - { { 120, 253, 197, 213, 2 }, - { 123, 159, 176, 172, 10 }, - { 74, 186, 59, 241, 14 }, - { 83, 80, 223, 157, 14 }, }, - { { 126, 232, 117, 158, 9 }, - { 191, 45, 177, 145, 15 }, - { 151, 154, 225, 119, 14 }, - { 248, 152, 219, 79, 13 }, }, - { { 123, 28, 43, 68, 14 }, - { 90, 88, 101, 233, 12 }, - { 114, 45, 67, 141, 14 }, - { 57, 122, 97, 165, 10 }, }, - { { 127, 4, 160, 250, 2 }, - { 130, 184, 162, 233, 7 }, - { 69, 240, 82, 15, 14 }, - { 233, 116, 81, 212, 1 }, }, - { { 123, 39, 78, 235, 3 }, - { 39, 123, 46, 237, 3 }, - { 205, 119, 46, 77, 14 }, - { 203, 119, 77, 238, 4 }, }, - { { 125, 38, 127, 122, 1 }, - { 183, 105, 174, 248, 5 }, - { 133, 239, 230, 75, 14 }, - { 161, 247, 89, 110, 13 }, }, - { { 127, 50, 169, 94, 10 }, - { 219, 184, 173, 201, 5 }, - { 87, 169, 84, 207, 14 }, - { 169, 59, 81, 221, 11 }, }, - { { 121, 180, 170, 170, 7 }, - { 71, 248, 118, 224, 7 }, - { 229, 85, 82, 217, 14 }, - { 224, 118, 225, 254, 2 }, }, - { { 125, 176, 215, 37, 3 }, - { 255, 217, 50, 212, 0 }, - { 202, 78, 176, 219, 14 }, - { 2, 180, 201, 191, 15 }, }, - { { 127, 147, 79, 12, 2 }, - { 250, 123, 60, 193, 0 }, - { 67, 15, 44, 159, 14 }, - { 8, 51, 205, 229, 15 }, }, - { { 125, 252, 16, 66, 2 }, - { 195, 28, 48, 248, 9 }, - { 68, 32, 131, 251, 14 }, - { 145, 240, 195, 140, 3 }, }, - { { 125, 213, 216, 211, 15 }, - { 230, 158, 245, 252, 3 }, - { 252, 177, 186, 187, 14 }, - { 195, 250, 247, 150, 7 }, }, - { { 128, 56, 32, 103, 11 }, - { 77, 16, 3, 14, 13 }, - { 222, 96, 65, 192, 1 }, - { 183, 12, 0, 139, 2 }, }, - { { 132, 17, 185, 214, 3 }, - { 220, 146, 132, 26, 7 }, - { 198, 185, 216, 130, 1 }, - { 229, 130, 20, 147, 11 }, }, - { { 128, 3, 252, 100, 10 }, - { 40, 147, 15, 26, 4 }, - { 82, 99, 252, 0, 1 }, - { 37, 143, 12, 145, 4 }, }, - { { 130, 59, 15, 187, 10 }, - { 81, 115, 143, 7, 11 }, - { 93, 223, 13, 196, 1 }, - { 222, 15, 28, 232, 10 }, }, - { { 134, 42, 167, 117, 10 }, - { 153, 209, 139, 15, 12 }, - { 90, 238, 85, 70, 1 }, - { 63, 13, 24, 185, 9 }, }, - { { 132, 27, 89, 75, 7 }, - { 244, 50, 76, 30, 9 }, - { 237, 41, 173, 130, 1 }, - { 151, 131, 36, 194, 15 }, }, - { { 130, 68, 49, 200, 10 }, - { 16, 52, 1, 59, 6 }, - { 81, 56, 194, 36, 1 }, - { 109, 200, 2, 192, 8 }, }, - { { 130, 89, 216, 117, 3 }, - { 108, 150, 134, 31, 8 }, - { 202, 225, 185, 164, 1 }, - { 31, 134, 22, 147, 6 }, }, - { { 132, 72, 31, 220, 14 }, - { 152, 117, 197, 26, 10 }, - { 115, 191, 129, 34, 1 }, - { 85, 138, 58, 225, 9 }, }, - { { 130, 181, 229, 107, 4 }, - { 113, 163, 82, 47, 5 }, - { 45, 106, 122, 212, 1 }, - { 175, 68, 172, 88, 14 }, }, - { { 128, 183, 10, 183, 0 }, - { 73, 66, 158, 38, 3 }, - { 14, 213, 14, 208, 1 }, - { 198, 71, 148, 41, 2 }, }, - { { 134, 178, 80, 25, 10 }, - { 225, 48, 153, 23, 0 }, - { 89, 128, 164, 214, 1 }, - { 14, 137, 144, 200, 7 }, }, - { { 128, 204, 47, 123, 8 }, - { 16, 101, 151, 46, 13 }, - { 29, 239, 67, 48, 1 }, - { 183, 78, 154, 96, 8 }, }, - { { 134, 253, 182, 100, 8 }, - { 201, 199, 19, 59, 12 }, - { 18, 102, 219, 246, 1 }, - { 61, 204, 142, 57, 3 }, }, - { { 129, 121, 60, 62, 9 }, - { 77, 39, 135, 82, 13 }, - { 151, 195, 201, 232, 1 }, - { 180, 174, 30, 75, 2 }, }, - { { 133, 96, 132, 133, 11 }, - { 141, 149, 1, 70, 2 }, - { 218, 18, 16, 106, 1 }, - { 70, 40, 10, 155, 1 }, }, - { { 131, 98, 22, 146, 5 }, - { 5, 69, 200, 83, 3 }, - { 164, 150, 132, 108, 1 }, - { 204, 161, 58, 42, 0 }, }, - { { 131, 128, 229, 221, 15 }, - { 60, 177, 209, 79, 6 }, - { 251, 186, 112, 28, 1 }, - { 111, 40, 184, 211, 12 }, }, - { { 135, 160, 76, 203, 2 }, - { 161, 49, 20, 79, 3 }, - { 77, 51, 32, 94, 1 }, - { 207, 34, 136, 200, 5 }, }, - { { 135, 184, 138, 180, 13 }, - { 205, 192, 215, 67, 10 }, - { 178, 213, 17, 222, 1 }, - { 92, 46, 176, 59, 3 }, }, - { { 142, 2, 6, 56, 4 }, - { 130, 97, 202, 3, 0 }, - { 33, 198, 4, 7, 1 }, - { 12, 5, 56, 100, 1 }, }, - { { 140, 54, 125, 172, 7 }, - { 255, 49, 78, 50, 6 }, - { 227, 91, 230, 195, 1 }, - { 100, 199, 40, 207, 15 }, }, - { { 140, 65, 233, 44, 2 }, - { 186, 182, 6, 2, 4 }, - { 67, 73, 120, 35, 1 }, - { 36, 6, 6, 213, 13 }, }, - { { 140, 152, 59, 175, 12 }, - { 218, 96, 87, 22, 15 }, - { 63, 93, 193, 147, 1 }, - { 246, 142, 160, 101, 11 }, }, - { { 136, 244, 107, 79, 11 }, - { 127, 116, 21, 46, 5 }, - { 223, 45, 98, 241, 1 }, - { 167, 74, 130, 239, 14 }, }, - { { 143, 44, 197, 204, 4 }, - { 187, 161, 64, 107, 10 }, - { 35, 58, 51, 79, 1 }, - { 93, 96, 40, 93, 13 }, }, - { { 141, 55, 126, 115, 3 }, - { 231, 83, 142, 126, 5 }, - { 204, 231, 238, 203, 1 }, - { 167, 231, 28, 174, 7 }, }, - { { 139, 69, 79, 63, 7 }, - { 62, 119, 198, 103, 1 }, - { 239, 207, 42, 45, 1 }, - { 142, 102, 62, 231, 12 }, }, - { { 141, 86, 37, 150, 0 }, - { 218, 5, 136, 98, 7 }, - { 6, 154, 70, 171, 1 }, - { 228, 97, 26, 5, 11 }, }, - { { 139, 191, 24, 57, 2 }, - { 67, 50, 158, 119, 8 }, - { 73, 193, 143, 221, 1 }, - { 30, 231, 148, 204, 2 }, }, - { { 141, 166, 67, 9, 4 }, - { 179, 96, 88, 102, 0 }, - { 41, 12, 38, 91, 1 }, - { 6, 97, 160, 108, 13 }, }, - { { 141, 208, 202, 166, 8 }, - { 234, 196, 23, 66, 3 }, - { 22, 85, 48, 187, 1 }, - { 196, 46, 130, 53, 7 }, }, - { { 139, 246, 152, 79, 4 }, - { 75, 164, 92, 127, 1 }, - { 47, 33, 150, 253, 1 }, - { 143, 227, 162, 93, 2 }, }, - { { 144, 18, 153, 165, 4 }, - { 88, 136, 78, 22, 2 }, - { 42, 89, 148, 128, 9 }, - { 70, 135, 33, 17, 10 }, }, - { { 150, 46, 4, 135, 5 }, - { 141, 9, 72, 39, 11 }, - { 174, 18, 7, 70, 9 }, - { 222, 65, 41, 11, 1 }, }, - { { 146, 92, 163, 212, 0 }, - { 88, 204, 128, 43, 14 }, - { 2, 188, 83, 164, 9 }, - { 125, 64, 19, 49, 10 }, }, - { { 146, 133, 143, 119, 10 }, - { 24, 219, 151, 47, 1 }, - { 94, 239, 26, 20, 9 }, - { 143, 78, 157, 177, 8 }, }, - { { 148, 169, 61, 69, 10 }, - { 153, 27, 21, 30, 12 }, - { 90, 43, 201, 82, 9 }, - { 55, 138, 141, 137, 9 }, }, - { { 145, 32, 243, 51, 2 }, - { 49, 216, 130, 86, 5 }, - { 76, 204, 240, 72, 9 }, - { 166, 164, 17, 184, 12 }, }, - { { 145, 39, 109, 79, 3 }, - { 61, 59, 12, 110, 5 }, - { 207, 43, 110, 72, 9 }, - { 167, 99, 13, 203, 12 }, }, - { { 151, 51, 253, 233, 10 }, - { 241, 187, 15, 95, 6 }, - { 89, 123, 252, 206, 9 }, - { 111, 175, 13, 216, 15 }, }, - { { 151, 72, 243, 129, 3 }, - { 180, 220, 0, 87, 14 }, - { 200, 28, 241, 46, 9 }, - { 126, 160, 3, 178, 13 }, }, - { { 151, 159, 160, 6, 9 }, - { 204, 138, 25, 99, 13 }, - { 150, 0, 95, 158, 9 }, - { 188, 105, 133, 19, 3 }, }, - { { 147, 208, 63, 215, 12 }, - { 88, 77, 213, 95, 7 }, - { 62, 191, 192, 188, 9 }, - { 239, 170, 187, 33, 10 }, }, - { { 149, 252, 208, 110, 0 }, - { 233, 172, 18, 122, 9 }, - { 7, 96, 179, 250, 9 }, - { 149, 228, 131, 89, 7 }, }, - { { 147, 195, 178, 11, 1 }, - { 4, 238, 24, 87, 5 }, - { 141, 4, 220, 60, 9 }, - { 174, 161, 135, 114, 0 }, }, - { { 145, 195, 66, 1, 14 }, - { 32, 94, 89, 70, 0 }, - { 120, 4, 44, 56, 9 }, - { 6, 41, 167, 160, 4 }, }, - { { 158, 10, 212, 208, 9 }, - { 166, 137, 137, 27, 10 }, - { 144, 178, 181, 7, 9 }, - { 93, 137, 25, 22, 5 }, }, - { { 158, 62, 24, 70, 8 }, - { 203, 8, 13, 59, 9 }, - { 22, 33, 135, 199, 9 }, - { 157, 203, 1, 13, 3 }, }, - { { 154, 97, 122, 220, 9 }, - { 47, 110, 133, 27, 6 }, - { 147, 181, 232, 101, 9 }, - { 109, 138, 23, 111, 4 }, }, - { { 152, 200, 135, 101, 13 }, - { 30, 205, 83, 14, 8 }, - { 186, 110, 17, 49, 9 }, - { 23, 12, 171, 55, 8 }, }, - { { 152, 193, 223, 48, 9 }, - { 54, 207, 151, 18, 0 }, - { 144, 207, 184, 49, 9 }, - { 4, 142, 159, 54, 12 }, }, - { { 158, 249, 40, 250, 12 }, - { 195, 46, 215, 11, 15 }, - { 53, 241, 73, 247, 9 }, - { 253, 14, 183, 76, 3 }, }, - { { 158, 240, 171, 22, 1 }, - { 223, 204, 148, 3, 5 }, - { 134, 141, 80, 247, 9 }, - { 172, 2, 147, 63, 11 }, }, - { { 152, 251, 117, 9, 13 }, - { 119, 47, 89, 22, 12 }, - { 185, 10, 237, 241, 9 }, - { 54, 137, 175, 78, 14 }, }, - { { 159, 32, 1, 53, 4 }, - { 155, 8, 194, 71, 0 }, - { 42, 200, 0, 79, 9 }, - { 14, 36, 49, 13, 9 }, }, - { { 153, 18, 120, 7, 12 }, - { 106, 8, 77, 86, 5 }, - { 62, 1, 228, 137, 9 }, - { 166, 171, 33, 5, 6 }, }, - { { 155, 131, 245, 126, 11 }, - { 62, 187, 155, 91, 5 }, - { 215, 234, 252, 29, 9 }, - { 173, 173, 157, 215, 12 }, }, - { { 153, 249, 200, 173, 5 }, - { 111, 174, 86, 70, 10 }, - { 171, 81, 57, 249, 9 }, - { 86, 38, 167, 95, 6 }, }, - { { 157, 228, 46, 236, 2 }, - { 139, 125, 22, 106, 6 }, - { 67, 119, 66, 123, 9 }, - { 101, 102, 139, 237, 1 }, }, - { { 155, 219, 144, 210, 3 }, - { 70, 158, 152, 91, 11 }, - { 196, 176, 157, 189, 9 }, - { 221, 161, 151, 150, 2 }, }, - { { 159, 254, 132, 153, 15 }, - { 199, 189, 217, 103, 10 }, - { 249, 146, 23, 255, 9 }, - { 94, 105, 187, 222, 3 }, }, - { { 162, 66, 140, 215, 9 }, - { 12, 133, 173, 15, 3 }, - { 158, 179, 20, 36, 5 }, - { 207, 11, 90, 19, 0 }, }, - { { 164, 205, 25, 53, 7 }, - { 156, 22, 246, 54, 8 }, - { 234, 201, 139, 50, 5 }, - { 22, 198, 246, 131, 9 }, }, - { { 166, 213, 162, 25, 0 }, - { 192, 230, 176, 39, 4 }, - { 9, 132, 90, 182, 5 }, - { 46, 64, 214, 112, 3 }, }, - { { 160, 223, 192, 176, 6 }, - { 96, 150, 250, 34, 10 }, - { 96, 208, 63, 176, 5 }, - { 84, 69, 246, 144, 6 }, }, - { { 163, 49, 180, 144, 4 }, - { 65, 131, 224, 83, 6 }, - { 32, 146, 216, 204, 5 }, - { 108, 160, 124, 24, 2 }, }, - { { 167, 32, 134, 58, 15 }, - { 133, 241, 227, 67, 1 }, - { 245, 198, 16, 78, 5 }, - { 140, 44, 120, 250, 1 }, }, - { { 167, 56, 45, 40, 13 }, - { 213, 33, 103, 67, 12 }, - { 177, 75, 65, 206, 5 }, - { 60, 46, 104, 74, 11 }, }, - { { 163, 63, 204, 220, 14 }, - { 105, 179, 237, 107, 10 }, - { 115, 179, 63, 204, 5 }, - { 93, 107, 124, 217, 6 }, }, - { { 165, 62, 179, 132, 11 }, - { 221, 208, 41, 114, 14 }, - { 210, 28, 215, 202, 5 }, - { 116, 233, 64, 187, 11 }, }, - { { 161, 112, 26, 189, 7 }, - { 77, 116, 230, 86, 2 }, - { 235, 213, 128, 232, 5 }, - { 70, 166, 114, 235, 2 }, }, - { { 167, 103, 101, 55, 9 }, - { 189, 7, 171, 103, 5 }, - { 158, 202, 110, 110, 5 }, - { 174, 109, 94, 11, 13 }, }, - { { 165, 123, 102, 174, 4 }, - { 233, 103, 106, 66, 15 }, - { 39, 86, 109, 234, 5 }, - { 244, 37, 110, 105, 7 }, }, - { { 161, 213, 29, 147, 2 }, - { 80, 23, 180, 118, 3 }, - { 76, 155, 138, 184, 5 }, - { 198, 226, 222, 128, 10 }, }, - { { 163, 248, 233, 155, 14 }, - { 113, 180, 245, 71, 15 }, - { 125, 153, 113, 252, 5 }, - { 254, 42, 242, 216, 14 }, }, - { { 165, 211, 131, 218, 3 }, - { 212, 246, 184, 74, 3 }, - { 197, 188, 28, 186, 5 }, - { 197, 33, 214, 242, 11 }, }, - { { 165, 214, 235, 188, 6 }, - { 248, 244, 254, 98, 6 }, - { 99, 221, 118, 186, 5 }, - { 100, 103, 242, 241, 15 }, }, - { { 170, 38, 227, 151, 9 }, - { 63, 192, 169, 39, 7 }, - { 158, 156, 118, 69, 5 }, - { 238, 73, 80, 63, 12 }, }, - { { 174, 30, 201, 63, 12 }, - { 250, 160, 239, 39, 9 }, - { 63, 201, 55, 135, 5 }, - { 158, 79, 112, 85, 15 }, }, - { { 172, 119, 184, 237, 2 }, - { 203, 182, 46, 62, 6 }, - { 75, 113, 222, 227, 5 }, - { 103, 199, 70, 221, 3 }, }, - { { 170, 169, 238, 77, 15 }, - { 47, 243, 117, 15, 12 }, - { 251, 39, 121, 85, 5 }, - { 63, 10, 236, 255, 4 }, }, - { { 170, 128, 121, 170, 6 }, - { 50, 48, 118, 19, 7 }, - { 101, 89, 224, 21, 5 }, - { 236, 134, 224, 196, 12 }, }, - { { 174, 194, 96, 202, 1 }, - { 166, 36, 56, 11, 7 }, - { 133, 48, 100, 55, 5 }, - { 237, 1, 194, 70, 5 }, }, - { { 169, 58, 152, 98, 11 }, - { 71, 144, 47, 90, 9 }, - { 212, 97, 149, 201, 5 }, - { 149, 175, 64, 158, 2 }, }, - { { 171, 18, 81, 200, 12 }, - { 114, 32, 105, 91, 2 }, - { 49, 56, 164, 141, 5 }, - { 77, 169, 96, 68, 14 }, }, - { { 173, 102, 219, 216, 13 }, - { 183, 228, 237, 122, 2 }, - { 177, 189, 182, 107, 5 }, - { 69, 235, 114, 126, 13 }, }, - { { 173, 82, 221, 74, 1 }, - { 246, 165, 44, 90, 1 }, - { 133, 43, 180, 171, 5 }, - { 133, 163, 74, 86, 15 }, }, - { { 169, 182, 113, 16, 8 }, - { 115, 0, 185, 114, 4 }, - { 16, 136, 230, 217, 5 }, - { 36, 233, 208, 12, 14 }, }, - { { 173, 186, 226, 53, 0 }, - { 235, 192, 186, 70, 12 }, - { 10, 196, 117, 219, 5 }, - { 54, 37, 208, 61, 7 }, }, - { { 173, 151, 65, 223, 12 }, - { 250, 34, 249, 110, 3 }, - { 63, 184, 46, 155, 5 }, - { 199, 105, 244, 69, 15 }, }, - { { 171, 243, 182, 44, 7 }, - { 79, 247, 122, 83, 4 }, - { 227, 70, 220, 253, 5 }, - { 44, 165, 238, 255, 2 }, }, - { { 182, 34, 108, 113, 12 }, - { 161, 9, 239, 15, 4 }, - { 56, 227, 100, 70, 13 }, - { 47, 15, 121, 8, 5 }, }, - { { 180, 30, 37, 122, 7 }, - { 212, 57, 234, 42, 13 }, - { 229, 234, 71, 130, 13 }, - { 181, 69, 121, 194, 11 }, }, - { { 182, 55, 195, 138, 3 }, - { 245, 250, 40, 35, 3 }, - { 197, 28, 62, 198, 13 }, - { 204, 65, 69, 250, 15 }, }, - { { 176, 76, 212, 55, 0 }, - { 40, 141, 162, 54, 9 }, - { 14, 194, 179, 32, 13 }, - { 150, 196, 91, 17, 4 }, }, - { { 178, 127, 139, 5, 3 }, - { 93, 222, 44, 39, 8 }, - { 202, 13, 31, 228, 13 }, - { 30, 67, 71, 187, 10 }, }, - { { 176, 173, 216, 34, 5 }, - { 37, 138, 118, 50, 9 }, - { 164, 65, 187, 80, 13 }, - { 148, 198, 229, 26, 4 }, }, - { { 180, 155, 130, 43, 11 }, - { 196, 250, 59, 6, 9 }, - { 221, 68, 29, 146, 13 }, - { 150, 13, 197, 242, 3 }, }, - { { 176, 211, 78, 194, 3 }, - { 100, 95, 60, 10, 3 }, - { 196, 55, 44, 176, 13 }, - { 197, 3, 207, 162, 6 }, }, - { { 177, 61, 126, 195, 14 }, - { 97, 91, 101, 126, 15 }, - { 124, 55, 235, 200, 13 }, - { 247, 234, 109, 168, 6 }, }, - { { 177, 6, 164, 99, 14 }, - { 0, 153, 107, 110, 5 }, - { 124, 98, 86, 8, 13 }, - { 167, 109, 105, 144, 0 }, }, - { { 179, 43, 116, 63, 14 }, - { 41, 59, 235, 87, 13 }, - { 127, 194, 237, 76, 13 }, - { 190, 173, 125, 201, 4 }, }, - { { 183, 31, 214, 70, 15 }, - { 236, 219, 105, 123, 9 }, - { 246, 38, 191, 142, 13 }, - { 157, 233, 109, 179, 7 }, }, - { { 177, 110, 241, 244, 5 }, - { 61, 140, 234, 122, 14 }, - { 162, 248, 247, 104, 13 }, - { 117, 229, 115, 27, 12 }, }, - { { 177, 126, 83, 138, 14 }, - { 113, 124, 105, 114, 11 }, - { 117, 28, 167, 232, 13 }, - { 212, 233, 99, 232, 14 }, }, - { { 183, 98, 223, 55, 7 }, - { 189, 221, 238, 87, 1 }, - { 238, 207, 180, 110, 13 }, - { 142, 167, 123, 187, 13 }, }, - { { 177, 169, 248, 148, 9 }, - { 45, 138, 181, 82, 14 }, - { 146, 145, 249, 88, 13 }, - { 116, 170, 213, 27, 4 }, }, - { { 179, 183, 217, 210, 4 }, - { 113, 138, 252, 123, 3 }, - { 36, 185, 190, 220, 13 }, - { 205, 227, 245, 24, 14 }, }, - { { 179, 238, 187, 76, 6 }, - { 25, 252, 124, 123, 12 }, - { 99, 45, 215, 124, 13 }, - { 61, 227, 227, 249, 8 }, }, - { { 184, 44, 165, 82, 4 }, - { 19, 137, 224, 42, 13 }, - { 36, 170, 83, 65, 13 }, - { 181, 64, 121, 28, 8 }, }, - { { 184, 20, 13, 235, 15 }, - { 86, 57, 103, 46, 3 }, - { 253, 123, 2, 129, 13 }, - { 199, 78, 105, 198, 10 }, }, - { { 188, 25, 220, 199, 7 }, - { 238, 155, 100, 30, 11 }, - { 238, 51, 185, 131, 13 }, - { 215, 130, 109, 151, 7 }, }, - { { 188, 84, 38, 185, 6 }, - { 194, 125, 226, 38, 6 }, - { 105, 214, 66, 163, 13 }, - { 102, 68, 123, 228, 3 }, }, - { { 190, 103, 55, 196, 5 }, - { 159, 79, 104, 59, 6 }, - { 162, 62, 206, 103, 13 }, - { 109, 193, 111, 47, 9 }, }, - { { 184, 250, 232, 211, 5 }, - { 103, 140, 252, 14, 15 }, - { 172, 177, 117, 241, 13 }, - { 247, 3, 243, 30, 6 }, }, - { { 190, 194, 26, 55, 8 }, - { 138, 76, 191, 23, 1 }, - { 30, 197, 132, 55, 13 }, - { 142, 143, 211, 37, 1 }, }, - { { 187, 24, 207, 164, 11 }, - { 126, 217, 39, 67, 10 }, - { 210, 95, 49, 141, 13 }, - { 92, 46, 73, 183, 14 }, }, - { { 189, 1, 126, 246, 13 }, - { 174, 75, 231, 90, 7 }, - { 182, 247, 232, 11, 13 }, - { 229, 174, 125, 39, 5 }, }, - { { 189, 34, 47, 210, 7 }, - { 151, 89, 236, 74, 7 }, - { 228, 191, 68, 75, 13 }, - { 229, 35, 121, 174, 9 }, }, - { { 189, 2, 85, 133, 5 }, - { 190, 9, 104, 86, 2 }, - { 170, 26, 164, 11, 13 }, - { 70, 161, 105, 7, 13 }, }, - { { 185, 114, 78, 96, 5 }, - { 103, 77, 110, 74, 0 }, - { 160, 103, 36, 233, 13 }, - { 5, 39, 107, 46, 6 }, }, - { { 189, 119, 92, 22, 15 }, - { 239, 31, 237, 114, 1 }, - { 246, 131, 174, 235, 13 }, - { 132, 235, 127, 143, 7 }, }, - { { 185, 136, 172, 46, 1 }, - { 14, 169, 54, 66, 13 }, - { 135, 67, 81, 25, 13 }, - { 180, 38, 201, 87, 0 }, }, - { { 191, 160, 38, 103, 5 }, - { 143, 73, 114, 79, 5 }, - { 174, 102, 64, 95, 13 }, - { 175, 36, 233, 47, 1 }, }, - { { 185, 130, 150, 168, 6 }, - { 2, 249, 122, 82, 2 }, - { 97, 86, 148, 25, 13 }, - { 68, 165, 233, 244, 0 }, }, - { { 189, 135, 23, 24, 10 }, - { 146, 123, 185, 114, 0 }, - { 81, 142, 142, 27, 13 }, - { 4, 233, 221, 228, 9 }, }, - { { 191, 190, 239, 45, 7 }, - { 255, 249, 126, 103, 12 }, - { 235, 79, 119, 223, 13 }, - { 62, 103, 233, 255, 15 }, }, - { { 189, 250, 159, 0, 7 }, - { 215, 221, 124, 82, 8 }, - { 224, 15, 149, 251, 13 }, - { 20, 163, 235, 190, 11 }, }, - { { 194, 112, 53, 187, 8 }, - { 81, 37, 131, 151, 7 }, - { 29, 218, 192, 228, 3 }, - { 238, 156, 26, 72, 10 }, }, - { { 196, 108, 5, 172, 13 }, - { 157, 37, 67, 162, 10 }, - { 179, 90, 3, 98, 3 }, - { 84, 92, 42, 75, 9 }, }, - { { 196, 121, 84, 220, 3 }, - { 237, 55, 128, 154, 10 }, - { 195, 178, 169, 226, 3 }, - { 85, 144, 30, 203, 7 }, }, - { { 194, 106, 81, 13, 8 }, - { 57, 36, 9, 151, 8 }, - { 27, 8, 165, 100, 3 }, - { 30, 153, 2, 73, 12 }, }, - { { 198, 164, 159, 104, 4 }, - { 145, 225, 86, 187, 0 }, - { 33, 111, 146, 86, 3 }, - { 13, 214, 168, 120, 9 }, }, - { { 192, 158, 44, 235, 4 }, - { 64, 33, 94, 174, 15 }, - { 45, 115, 71, 144, 3 }, - { 247, 87, 168, 64, 2 }, }, - { { 198, 146, 33, 73, 13 }, - { 212, 32, 89, 143, 4 }, - { 185, 40, 68, 150, 3 }, - { 47, 25, 160, 66, 11 }, }, - { { 196, 186, 131, 207, 8 }, - { 217, 224, 25, 142, 11 }, - { 31, 60, 21, 210, 3 }, - { 215, 25, 128, 121, 11 }, }, - { { 198, 231, 133, 67, 11 }, - { 149, 151, 25, 175, 1 }, - { 220, 42, 30, 118, 3 }, - { 143, 89, 142, 154, 9 }, }, - { { 198, 215, 175, 70, 4 }, - { 216, 199, 92, 171, 5 }, - { 38, 47, 94, 182, 3 }, - { 173, 83, 174, 49, 11 }, }, - { { 197, 54, 85, 77, 11 }, - { 253, 49, 9, 254, 0 }, - { 219, 42, 166, 202, 3 }, - { 7, 249, 8, 203, 15 }, }, - { { 195, 147, 255, 13, 7 }, - { 124, 243, 92, 215, 4 }, - { 235, 15, 252, 156, 3 }, - { 46, 179, 172, 243, 14 }, }, - { { 193, 245, 112, 165, 10 }, - { 105, 22, 19, 246, 6 }, - { 90, 80, 234, 248, 3 }, - { 102, 252, 134, 137, 6 }, }, - { { 204, 57, 113, 197, 0 }, - { 251, 2, 0, 158, 14 }, - { 10, 56, 233, 195, 3 }, - { 119, 144, 4, 13, 15 }, }, - { { 200, 2, 137, 73, 2 }, - { 18, 176, 12, 142, 0 }, - { 73, 41, 20, 1, 3 }, - { 7, 19, 0, 212, 8 }, }, - { { 200, 124, 100, 74, 5 }, - { 103, 37, 64, 170, 13 }, - { 165, 34, 99, 225, 3 }, - { 181, 80, 42, 78, 6 }, }, - { { 202, 103, 225, 13, 7 }, - { 63, 182, 72, 167, 4 }, - { 235, 8, 126, 101, 3 }, - { 46, 81, 38, 223, 12 }, }, - { { 200, 153, 231, 66, 2 }, - { 114, 211, 16, 138, 13 }, - { 68, 46, 121, 145, 3 }, - { 181, 16, 140, 180, 14 }, }, - { { 200, 170, 178, 16, 5 }, - { 7, 192, 216, 146, 12 }, - { 160, 132, 213, 81, 3 }, - { 52, 145, 176, 62, 0 }, }, - { { 204, 166, 213, 159, 3 }, - { 191, 177, 152, 182, 3 }, - { 207, 154, 182, 83, 3 }, - { 198, 209, 152, 223, 13 }, }, - { { 202, 229, 134, 251, 14 }, - { 3, 247, 211, 175, 3 }, - { 125, 246, 26, 117, 3 }, - { 207, 92, 190, 252, 0 }, }, - { { 202, 217, 124, 49, 15 }, - { 102, 23, 215, 151, 12 }, - { 248, 195, 233, 181, 3 }, - { 62, 158, 190, 134, 6 }, }, - { { 206, 228, 202, 14, 6 }, - { 171, 244, 84, 163, 1 }, - { 103, 5, 50, 119, 3 }, - { 140, 82, 162, 253, 5 }, }, - { { 203, 45, 164, 50, 12 }, - { 3, 131, 195, 227, 13 }, - { 52, 194, 91, 77, 3 }, - { 188, 124, 60, 28, 0 }, }, - { { 203, 87, 214, 130, 2 }, - { 98, 215, 8, 243, 3 }, - { 68, 22, 190, 173, 3 }, - { 204, 241, 14, 180, 6 }, }, - { { 201, 144, 33, 177, 0 }, - { 82, 0, 146, 198, 6 }, - { 8, 216, 64, 153, 3 }, - { 102, 52, 144, 4, 10 }, }, - { { 201, 130, 95, 176, 10 }, - { 50, 81, 159, 210, 2 }, - { 80, 223, 164, 25, 3 }, - { 68, 191, 152, 164, 12 }, }, - { { 203, 158, 212, 36, 7 }, - { 110, 145, 90, 243, 8 }, - { 226, 66, 183, 157, 3 }, - { 28, 245, 168, 151, 6 }, }, - { { 205, 134, 171, 157, 13 }, - { 158, 224, 221, 230, 6 }, - { 187, 157, 86, 27, 3 }, - { 102, 123, 176, 119, 9 }, }, - { { 201, 201, 176, 119, 5 }, - { 14, 134, 210, 222, 13 }, - { 174, 224, 217, 57, 3 }, - { 183, 180, 182, 23, 0 }, }, - { { 201, 250, 31, 99, 2 }, - { 83, 85, 30, 222, 9 }, - { 76, 111, 133, 249, 3 }, - { 151, 183, 138, 172, 10 }, }, - { { 203, 247, 64, 6, 9 }, - { 111, 6, 25, 227, 1 }, - { 150, 0, 46, 253, 3 }, - { 140, 121, 134, 15, 6 }, }, - { { 205, 218, 13, 28, 15 }, - { 222, 53, 221, 194, 8 }, - { 243, 139, 5, 187, 3 }, - { 20, 59, 186, 199, 11 }, }, - { { 208, 11, 130, 83, 15 }, - { 4, 218, 201, 142, 9 }, - { 252, 164, 29, 0, 11 }, - { 151, 25, 53, 178, 0 }, }, - { { 212, 59, 207, 214, 15 }, - { 253, 219, 205, 138, 11 }, - { 246, 191, 61, 194, 11 }, - { 213, 27, 61, 187, 15 }, }, - { { 214, 98, 171, 209, 11 }, - { 149, 220, 141, 143, 6 }, - { 216, 189, 84, 102, 11 }, - { 111, 27, 19, 186, 9 }, }, - { { 212, 102, 200, 58, 15 }, - { 165, 188, 207, 162, 1 }, - { 245, 193, 54, 98, 11 }, - { 132, 95, 51, 218, 5 }, }, - { { 209, 32, 28, 120, 10 }, - { 1, 57, 135, 218, 0 }, - { 81, 227, 128, 72, 11 }, - { 5, 190, 25, 200, 0 }, }, - { { 211, 57, 65, 195, 9 }, - { 117, 10, 1, 207, 11 }, - { 156, 56, 41, 204, 11 }, - { 223, 56, 5, 10, 14 }, }, - { { 209, 7, 160, 253, 4 }, - { 8, 170, 202, 238, 6 }, - { 43, 240, 94, 8, 11 }, - { 103, 117, 53, 81, 0 }, }, - { { 209, 149, 58, 14, 2 }, - { 72, 122, 20, 242, 5 }, - { 71, 5, 202, 152, 11 }, - { 164, 242, 133, 225, 2 }, }, - { { 215, 189, 66, 29, 13 }, - { 237, 106, 209, 231, 8 }, - { 187, 132, 43, 222, 11 }, - { 30, 120, 181, 107, 7 }, }, - { { 215, 192, 166, 80, 13 }, - { 132, 205, 209, 203, 4 }, - { 176, 166, 80, 62, 11 }, - { 45, 56, 187, 50, 1 }, }, - { { 215, 229, 141, 245, 12 }, - { 153, 143, 215, 239, 2 }, - { 58, 251, 26, 126, 11 }, - { 79, 126, 191, 25, 9 }, }, - { { 215, 197, 83, 246, 7 }, - { 188, 94, 210, 251, 3 }, - { 230, 252, 170, 62, 11 }, - { 205, 244, 183, 163, 13 }, }, - { { 213, 254, 112, 184, 8 }, - { 225, 44, 155, 242, 14 }, - { 17, 208, 231, 250, 11 }, - { 116, 253, 147, 72, 7 }, }, - { { 216, 12, 185, 190, 6 }, - { 26, 184, 198, 178, 15 }, - { 103, 217, 211, 1, 11 }, - { 244, 214, 49, 213, 8 }, }, - { { 222, 52, 186, 37, 6 }, - { 203, 216, 70, 183, 4 }, - { 106, 69, 210, 199, 11 }, - { 46, 214, 33, 189, 3 }, }, - { { 220, 14, 198, 139, 14 }, - { 162, 249, 73, 166, 11 }, - { 125, 22, 55, 3, 11 }, - { 214, 89, 41, 244, 5 }, }, - { { 222, 3, 247, 164, 11 }, - { 190, 219, 11, 147, 6 }, - { 210, 94, 252, 7, 11 }, - { 108, 157, 13, 183, 13 }, }, - { { 218, 93, 11, 138, 2 }, - { 82, 126, 4, 163, 11 }, - { 69, 29, 11, 165, 11 }, - { 220, 82, 7, 228, 10 }, }, - { { 216, 113, 249, 127, 15 }, - { 127, 190, 199, 158, 5 }, - { 255, 233, 248, 225, 11 }, - { 167, 158, 55, 223, 14 }, }, - { { 220, 189, 130, 231, 2 }, - { 203, 218, 18, 174, 11 }, - { 78, 116, 27, 211, 11 }, - { 215, 84, 133, 189, 3 }, }, - { { 220, 176, 90, 229, 5 }, - { 239, 72, 86, 158, 2 }, - { 170, 117, 160, 211, 11 }, - { 71, 150, 161, 47, 7 }, }, - { { 218, 147, 222, 80, 0 }, - { 98, 203, 156, 155, 0 }, - { 0, 167, 188, 149, 11 }, - { 13, 147, 157, 52, 6 }, }, - { { 218, 183, 241, 191, 8 }, - { 123, 170, 155, 183, 7 }, - { 31, 216, 254, 213, 11 }, - { 238, 221, 149, 93, 14 }, }, - { { 222, 159, 2, 50, 14 }, - { 194, 90, 219, 163, 9 }, - { 116, 196, 15, 151, 11 }, - { 156, 93, 181, 164, 3 }, }, - { { 218, 196, 13, 85, 0 }, - { 26, 13, 148, 175, 0 }, - { 10, 171, 2, 53, 11 }, - { 15, 82, 155, 5, 8 }, }, - { { 220, 197, 171, 128, 14 }, - { 146, 222, 85, 162, 6 }, - { 112, 29, 90, 51, 11 }, - { 100, 90, 167, 180, 9 }, }, - { { 218, 194, 178, 58, 10 }, - { 2, 252, 155, 147, 5 }, - { 85, 196, 212, 53, 11 }, - { 172, 157, 147, 244, 0 }, }, - { { 218, 218, 88, 253, 0 }, - { 106, 44, 158, 159, 10 }, - { 11, 241, 165, 181, 11 }, - { 95, 151, 147, 69, 6 }, }, - { { 217, 37, 142, 168, 1 }, - { 7, 235, 6, 226, 2 }, - { 129, 87, 26, 73, 11 }, - { 68, 118, 13, 126, 0 }, }, - { { 221, 5, 118, 59, 14 }, - { 162, 123, 195, 246, 5 }, - { 125, 198, 234, 11, 11 }, - { 166, 252, 61, 228, 5 }, }, - { { 221, 46, 153, 8, 12 }, - { 147, 168, 77, 242, 8 }, - { 49, 9, 151, 75, 11 }, - { 20, 251, 33, 92, 9 }, }, - { { 217, 85, 104, 199, 5 }, - { 110, 14, 68, 238, 7 }, - { 174, 49, 106, 169, 11 }, - { 231, 114, 39, 7, 6 }, }, - { { 219, 80, 109, 76, 3 }, - { 126, 61, 4, 203, 4 }, - { 195, 43, 96, 173, 11 }, - { 45, 50, 11, 199, 14 }, }, - { { 223, 104, 170, 56, 8 }, - { 131, 236, 135, 195, 12 }, - { 17, 197, 81, 111, 11 }, - { 60, 62, 19, 124, 1 }, }, - { { 219, 66, 135, 167, 5 }, - { 30, 205, 74, 199, 3 }, - { 174, 94, 20, 45, 11 }, - { 206, 53, 43, 55, 8 }, }, - { { 219, 129, 40, 179, 13 }, - { 6, 10, 215, 199, 7 }, - { 188, 209, 72, 29, 11 }, - { 238, 62, 181, 6, 0 }, }, - { { 217, 163, 194, 250, 13 }, - { 39, 234, 219, 202, 3 }, - { 181, 244, 60, 89, 11 }, - { 197, 61, 181, 126, 4 }, }, - { { 221, 179, 56, 211, 8 }, - { 195, 10, 157, 222, 7 }, - { 28, 177, 204, 219, 11 }, - { 231, 187, 149, 12, 3 }, }, - { { 217, 202, 123, 155, 1 }, - { 54, 108, 156, 214, 15 }, - { 141, 157, 229, 57, 11 }, - { 246, 179, 147, 102, 12 }, }, - { { 219, 246, 158, 176, 7 }, - { 71, 221, 222, 243, 2 }, - { 224, 215, 150, 253, 11 }, - { 76, 247, 187, 190, 2 }, }, - { { 226, 8, 108, 175, 8 }, - { 40, 33, 39, 135, 15 }, - { 31, 83, 97, 4, 7 }, - { 254, 30, 72, 65, 4 }, }, - { { 224, 27, 171, 150, 4 }, - { 88, 194, 236, 130, 15 }, - { 38, 157, 93, 128, 7 }, - { 244, 19, 116, 49, 10 }, }, - { { 224, 72, 115, 243, 0 }, - { 48, 68, 162, 158, 15 }, - { 12, 252, 225, 32, 7 }, - { 247, 148, 82, 32, 12 }, }, - { { 228, 117, 169, 91, 14 }, - { 209, 182, 229, 174, 5 }, - { 125, 169, 90, 226, 7 }, - { 167, 90, 118, 216, 11 }, }, - { { 230, 128, 236, 116, 9 }, - { 172, 129, 183, 139, 4 }, - { 146, 227, 112, 22, 7 }, - { 45, 30, 216, 19, 5 }, }, - { { 226, 175, 118, 72, 7 }, - { 37, 115, 120, 187, 12 }, - { 225, 38, 239, 84, 7 }, - { 61, 209, 236, 234, 4 }, }, - { { 224, 162, 200, 17, 13 }, - { 37, 128, 253, 134, 0 }, - { 184, 129, 52, 80, 7 }, - { 6, 27, 240, 26, 4 }, }, - { { 226, 203, 113, 80, 12 }, - { 48, 6, 249, 155, 12 }, - { 48, 168, 237, 52, 7 }, - { 61, 153, 246, 0, 12 }, }, - { { 224, 210, 73, 197, 15 }, - { 124, 20, 125, 142, 2 }, - { 250, 57, 36, 176, 7 }, - { 71, 27, 226, 131, 14 }, }, - { { 225, 12, 194, 130, 9 }, - { 36, 192, 33, 226, 11 }, - { 148, 20, 51, 8, 7 }, - { 212, 120, 64, 50, 4 }, }, - { { 225, 127, 68, 52, 3 }, - { 109, 23, 170, 226, 8 }, - { 194, 194, 47, 232, 7 }, - { 20, 117, 94, 139, 6 }, }, - { { 231, 173, 69, 177, 14 }, - { 177, 19, 243, 231, 10 }, - { 120, 218, 43, 94, 7 }, - { 94, 124, 252, 136, 13 }, }, - { { 225, 182, 90, 159, 9 }, - { 109, 96, 189, 246, 3 }, - { 159, 149, 166, 216, 7 }, - { 198, 251, 208, 107, 6 }, }, - { { 231, 252, 32, 65, 12 }, - { 193, 4, 113, 239, 12 }, - { 56, 32, 67, 254, 7 }, - { 63, 120, 226, 8, 3 }, }, - { { 238, 51, 65, 56, 1 }, - { 247, 34, 170, 131, 0 }, - { 129, 200, 44, 199, 7 }, - { 12, 21, 84, 78, 15 }, }, - { { 238, 124, 54, 51, 4 }, - { 195, 69, 226, 183, 13 }, - { 44, 198, 195, 231, 7 }, - { 190, 212, 122, 44, 3 }, }, - { { 236, 112, 123, 248, 10 }, - { 243, 116, 167, 154, 6 }, - { 81, 253, 224, 227, 7 }, - { 101, 158, 82, 236, 15 }, }, - { { 232, 123, 59, 230, 14 }, - { 91, 86, 111, 154, 15 }, - { 118, 125, 205, 225, 7 }, - { 245, 159, 102, 173, 10 }, }, - { { 232, 149, 232, 57, 1 }, - { 102, 162, 182, 166, 4 }, - { 137, 193, 122, 145, 7 }, - { 38, 86, 212, 86, 6 }, }, - { { 238, 172, 9, 125, 5 }, - { 159, 32, 246, 175, 8 }, - { 171, 233, 3, 87, 7 }, - { 31, 86, 240, 79, 9 }, }, - { { 236, 161, 201, 55, 4 }, - { 187, 130, 246, 134, 1 }, - { 46, 201, 56, 83, 7 }, - { 134, 22, 244, 29, 13 }, }, - { { 232, 151, 189, 197, 5 }, - { 94, 131, 124, 190, 6 }, - { 170, 59, 222, 145, 7 }, - { 103, 211, 236, 23, 10 }, }, - { { 232, 204, 18, 29, 0 }, - { 10, 100, 176, 182, 8 }, - { 11, 132, 131, 49, 7 }, - { 22, 208, 210, 101, 0 }, }, - { { 238, 193, 29, 105, 8 }, - { 146, 39, 55, 159, 0 }, - { 25, 107, 136, 55, 7 }, - { 15, 158, 206, 68, 9 }, }, - { { 237, 7, 255, 219, 10 }, - { 178, 243, 173, 254, 7 }, - { 93, 191, 254, 11, 7 }, - { 231, 251, 92, 244, 13 }, }, - { { 237, 105, 243, 54, 11 }, - { 191, 214, 163, 210, 13 }, - { 214, 204, 249, 107, 7 }, - { 180, 188, 86, 191, 13 }, }, - { { 237, 118, 20, 181, 12 }, - { 203, 5, 235, 246, 2 }, - { 58, 210, 134, 235, 7 }, - { 70, 253, 122, 13, 3 }, }, - { { 239, 132, 33, 209, 7 }, - { 150, 16, 240, 239, 6 }, - { 232, 184, 66, 31, 7 }, - { 111, 112, 240, 134, 9 }, }, - { { 235, 245, 218, 120, 2 }, - { 99, 246, 182, 251, 0 }, - { 65, 229, 186, 253, 7 }, - { 13, 246, 214, 252, 6 }, }, - { { 233, 249, 229, 214, 13 }, - { 127, 135, 241, 202, 15 }, - { 182, 186, 121, 249, 7 }, - { 245, 56, 254, 31, 14 }, }, - { { 235, 211, 15, 145, 9 }, - { 86, 71, 189, 199, 2 }, - { 152, 159, 12, 189, 7 }, - { 78, 59, 222, 38, 10 }, }, - { { 233, 219, 241, 32, 9 }, - { 118, 134, 59, 210, 12 }, - { 144, 72, 253, 185, 7 }, - { 52, 189, 198, 22, 14 }, }, - { { 244, 41, 139, 109, 8 }, - { 153, 234, 39, 142, 8 }, - { 27, 109, 25, 66, 15 }, - { 23, 30, 69, 121, 9 }, }, - { { 246, 10, 52, 34, 5 }, - { 132, 9, 106, 147, 13 }, - { 164, 66, 197, 6, 15 }, - { 188, 149, 105, 2, 1 }, }, - { { 244, 88, 85, 155, 1 }, - { 244, 45, 160, 150, 11 }, - { 141, 154, 161, 162, 15 }, - { 214, 144, 91, 66, 15 }, }, - { { 242, 118, 55, 97, 3 }, - { 85, 93, 42, 191, 4 }, - { 200, 110, 198, 228, 15 }, - { 47, 213, 75, 170, 10 }, }, - { { 244, 75, 10, 224, 6 }, - { 128, 94, 110, 138, 10 }, - { 96, 117, 13, 34, 15 }, - { 85, 23, 103, 160, 1 }, }, - { { 246, 110, 129, 75, 12 }, - { 145, 172, 105, 175, 9 }, - { 61, 40, 23, 102, 15 }, - { 159, 89, 99, 88, 9 }, }, - { { 246, 67, 29, 76, 6 }, - { 152, 63, 108, 155, 0 }, - { 99, 43, 140, 38, 15 }, - { 13, 147, 111, 193, 9 }, }, - { { 244, 87, 34, 238, 1 }, - { 204, 110, 42, 170, 7 }, - { 135, 116, 78, 162, 15 }, - { 229, 85, 71, 99, 3 }, }, - { { 244, 153, 83, 229, 11 }, - { 252, 90, 51, 158, 10 }, - { 218, 124, 169, 146, 15 }, - { 87, 156, 197, 163, 15 }, }, - { { 240, 252, 47, 27, 5 }, - { 85, 109, 244, 166, 13 }, - { 173, 143, 67, 240, 15 }, - { 182, 82, 251, 106, 10 }, }, - { { 247, 9, 30, 9, 12 }, - { 128, 107, 101, 215, 8 }, - { 57, 7, 137, 14, 15 }, - { 30, 186, 109, 96, 1 }, }, - { { 247, 38, 87, 194, 0 }, - { 177, 73, 40, 251, 3 }, - { 4, 62, 166, 78, 15 }, - { 205, 241, 73, 40, 13 }, }, - { { 241, 133, 27, 198, 13 }, - { 28, 74, 117, 250, 3 }, - { 182, 61, 138, 24, 15 }, - { 197, 250, 229, 35, 8 }, }, - { { 243, 136, 98, 232, 1 }, - { 36, 104, 50, 203, 14 }, - { 129, 116, 97, 28, 15 }, - { 125, 52, 193, 98, 4 }, }, - { { 247, 169, 183, 234, 6 }, - { 145, 251, 114, 219, 15 }, - { 101, 126, 217, 94, 15 }, - { 253, 180, 237, 248, 9 }, }, - { { 247, 138, 138, 92, 2 }, - { 136, 248, 188, 203, 8 }, - { 67, 165, 21, 30, 15 }, - { 29, 51, 209, 241, 1 }, }, - { { 243, 237, 194, 21, 2 }, - { 41, 222, 176, 231, 8 }, - { 74, 132, 59, 124, 15 }, - { 30, 112, 215, 185, 4 }, }, - { { 245, 245, 148, 242, 4 }, - { 193, 143, 242, 250, 3 }, - { 36, 242, 154, 250, 15 }, - { 197, 244, 255, 24, 3 }, }, - { { 248, 15, 62, 15, 4 }, - { 10, 107, 108, 182, 13 }, - { 47, 7, 207, 1, 15 }, - { 182, 211, 109, 101, 0 }, }, - { { 252, 190, 99, 125, 14 }, - { 251, 120, 251, 174, 12 }, - { 123, 236, 103, 211, 15 }, - { 55, 93, 241, 237, 15 }, }, - { { 248, 237, 33, 73, 11 }, - { 23, 62, 49, 174, 12 }, - { 217, 40, 75, 113, 15 }, - { 55, 88, 199, 206, 8 }, }, - { { 250, 216, 194, 128, 14 }, - { 98, 220, 113, 131, 10 }, - { 112, 20, 49, 181, 15 }, - { 92, 24, 227, 180, 6 }, }, - { { 254, 229, 5, 156, 6 }, - { 155, 63, 240, 163, 2 }, - { 99, 154, 10, 119, 15 }, - { 76, 80, 255, 205, 9 }, }, - { { 254, 196, 253, 27, 8 }, - { 178, 173, 181, 183, 5 }, - { 29, 139, 242, 55, 15 }, - { 174, 218, 219, 84, 13 }, }, - { { 250, 210, 225, 31, 4 }, - { 122, 172, 248, 135, 5 }, - { 47, 136, 116, 181, 15 }, - { 174, 17, 243, 85, 14 }, }, - { { 252, 195, 230, 115, 2 }, - { 162, 223, 186, 142, 5 }, - { 76, 230, 124, 51, 15 }, - { 167, 21, 223, 180, 5 }, }, - { { 249, 63, 162, 110, 11 }, - { 79, 250, 43, 234, 13 }, - { 215, 100, 95, 201, 15 }, - { 181, 125, 69, 255, 2 }, }, - { { 251, 86, 194, 94, 3 }, - { 110, 252, 168, 235, 1 }, - { 199, 164, 54, 173, 15 }, - { 141, 113, 83, 247, 6 }, }, - { { 255, 78, 140, 162, 15 }, - { 134, 157, 111, 227, 11 }, - { 244, 83, 23, 47, 15 }, - { 220, 127, 107, 150, 1 }, }, - { { 255, 79, 112, 226, 4 }, - { 162, 14, 106, 251, 15 }, - { 36, 112, 239, 47, 15 }, - { 253, 245, 103, 4, 5 }, }, - { { 249, 177, 42, 52, 9 }, - { 79, 74, 183, 194, 4 }, - { 146, 197, 72, 217, 15 }, - { 36, 62, 213, 47, 2 }, }, - { { 255, 135, 146, 120, 1 }, - { 134, 234, 186, 251, 0 }, - { 129, 228, 158, 31, 15 }, - { 13, 245, 213, 118, 1 }, }, - { { 249, 195, 188, 9, 10 }, - { 2, 191, 61, 214, 4 }, - { 89, 3, 220, 57, 15 }, - { 38, 187, 207, 212, 0 }, }, - { { 255, 202, 25, 209, 12 }, - { 146, 12, 253, 223, 10 }, - { 56, 185, 133, 63, 15 }, - { 95, 187, 243, 4, 9 }, }, - { { 255, 239, 23, 165, 10 }, - { 155, 95, 59, 247, 10 }, - { 90, 94, 143, 127, 15 }, - { 94, 253, 207, 173, 9 }, }, - { { 253, 254, 218, 140, 1 }, - { 239, 236, 60, 242, 10 }, - { 131, 21, 183, 251, 15 }, - { 84, 243, 195, 127, 7 }, }, - { { 6, 66, 233, 9, 7 }, - { 180, 180, 76, 5, 4 }, - { 233, 9, 116, 38, 0 }, - { 42, 3, 34, 210, 13 }, }, - { { 3, 36, 36, 70, 13 }, - { 13, 1, 65, 105, 5 }, - { 182, 34, 66, 76, 0 }, - { 169, 104, 40, 11, 0 }, }, - { { 7, 94, 92, 135, 12 }, - { 232, 5, 77, 117, 11 }, - { 62, 19, 167, 174, 0 }, - { 218, 235, 42, 1, 7 }, }, - { { 7, 136, 66, 250, 6 }, - { 160, 112, 210, 73, 11 }, - { 101, 244, 33, 30, 0 }, - { 217, 36, 176, 224, 5 }, }, - { { 10, 7, 178, 27, 11 }, - { 6, 242, 137, 53, 5 }, - { 221, 132, 222, 5, 0 }, - { 170, 201, 20, 246, 0 }, }, - { { 16, 148, 220, 241, 14 }, - { 96, 153, 215, 60, 2 }, - { 120, 243, 178, 144, 8 }, - { 67, 206, 185, 144, 6 }, }, - { { 22, 162, 90, 176, 15 }, - { 165, 88, 223, 17, 2 }, - { 240, 213, 164, 86, 8 }, - { 72, 143, 177, 170, 5 }, }, - { { 16, 253, 203, 109, 14 }, - { 121, 254, 87, 44, 8 }, - { 123, 109, 59, 240, 8 }, - { 19, 78, 167, 249, 14 }, }, - { { 17, 52, 172, 162, 12 }, - { 65, 137, 71, 96, 7 }, - { 52, 83, 82, 200, 8 }, - { 224, 110, 41, 24, 2 }, }, - { { 17, 166, 62, 16, 1 }, - { 5, 73, 156, 112, 4 }, - { 128, 135, 198, 88, 8 }, - { 32, 227, 153, 42, 0 }, }, - { { 30, 88, 44, 226, 2 }, - { 194, 29, 6, 9, 15 }, - { 68, 115, 65, 167, 8 }, - { 249, 6, 11, 132, 3 }, }, - { { 24, 99, 58, 139, 0 }, - { 3, 110, 12, 20, 7 }, - { 13, 21, 204, 97, 8 }, - { 226, 131, 7, 108, 0 }, }, - { { 26, 99, 1, 47, 13 }, - { 31, 46, 75, 5, 1 }, - { 191, 72, 12, 101, 8 }, - { 138, 13, 39, 79, 8 }, }, - { { 26, 241, 71, 206, 15 }, - { 127, 127, 81, 9, 3 }, - { 247, 62, 40, 245, 8 }, - { 201, 8, 175, 239, 14 }, }, - { { 25, 108, 177, 139, 1 }, - { 23, 172, 0, 116, 15 }, - { 141, 24, 211, 105, 8 }, - { 242, 224, 3, 94, 8 }, }, - { { 29, 149, 207, 92, 12 }, - { 250, 235, 213, 104, 0 }, - { 51, 175, 58, 155, 8 }, - { 1, 106, 189, 117, 15 }, }, - { { 25, 158, 56, 146, 2 }, - { 66, 24, 156, 112, 15 }, - { 68, 145, 199, 153, 8 }, - { 240, 227, 145, 132, 2 }, }, - { { 31, 252, 86, 35, 10 }, - { 227, 93, 19, 117, 9 }, - { 92, 70, 163, 255, 8 }, - { 154, 236, 139, 172, 7 }, }, - { { 36, 27, 41, 179, 3 }, - { 212, 18, 174, 4, 15 }, - { 204, 217, 77, 130, 4 }, - { 242, 7, 84, 130, 11 }, }, - { { 38, 231, 136, 133, 0 }, - { 137, 134, 60, 37, 2 }, - { 10, 17, 30, 118, 4 }, - { 74, 67, 198, 25, 1 }, }, - { { 33, 7, 54, 188, 1 }, - { 12, 99, 170, 112, 6 }, - { 131, 214, 206, 8, 4 }, - { 96, 229, 92, 99, 0 }, }, - { { 40, 77, 70, 86, 10 }, - { 42, 87, 161, 40, 9 }, - { 86, 166, 43, 33, 4 }, - { 145, 72, 94, 165, 4 }, }, - { { 46, 236, 227, 69, 8 }, - { 187, 196, 49, 45, 12 }, - { 26, 44, 115, 119, 4 }, - { 59, 72, 194, 61, 13 }, }, - { { 45, 79, 225, 77, 4 }, - { 186, 166, 104, 108, 12 }, - { 43, 40, 127, 43, 4 }, - { 51, 97, 102, 85, 13 }, }, - { { 45, 138, 40, 60, 7 }, - { 142, 48, 254, 64, 12 }, - { 227, 193, 69, 27, 4 }, - { 48, 39, 240, 199, 1 }, }, - { { 52, 248, 62, 55, 1 }, - { 205, 77, 182, 20, 13 }, - { 142, 199, 193, 242, 12 }, - { 178, 134, 219, 43, 3 }, }, - { { 56, 99, 93, 125, 8 }, - { 59, 47, 175, 28, 0 }, - { 27, 235, 172, 97, 12 }, - { 3, 143, 95, 77, 12 }, }, - { { 63, 162, 28, 196, 12 }, - { 139, 9, 125, 89, 2 }, - { 50, 51, 132, 95, 12 }, - { 73, 171, 233, 13, 1 }, }, - { { 66, 221, 151, 174, 14 }, - { 88, 247, 83, 177, 11 }, - { 119, 94, 155, 180, 2 }, - { 216, 220, 174, 241, 10 }, }, - { { 68, 223, 18, 214, 11 }, - { 204, 86, 153, 184, 11 }, - { 214, 180, 143, 178, 2 }, - { 209, 217, 150, 163, 3 }, }, - { { 65, 58, 205, 236, 8 }, - { 121, 161, 15, 200, 10 }, - { 19, 123, 53, 200, 2 }, - { 81, 63, 8, 89, 14 }, }, - { { 65, 192, 219, 73, 4 }, - { 48, 228, 84, 220, 0 }, - { 41, 45, 176, 56, 2 }, - { 3, 178, 162, 112, 12 }, }, - { { 76, 180, 0, 200, 13 }, - { 199, 32, 81, 168, 2 }, - { 177, 48, 2, 211, 2 }, - { 65, 88, 160, 78, 3 }, }, - { { 73, 35, 72, 149, 2 }, - { 43, 18, 140, 196, 2 }, - { 74, 145, 44, 73, 2 }, - { 66, 51, 20, 141, 4 }, }, - { { 82, 55, 185, 92, 6 }, - { 89, 186, 204, 185, 4 }, - { 99, 169, 222, 196, 10 }, - { 41, 211, 53, 217, 10 }, }, - { { 82, 81, 56, 221, 10 }, - { 72, 62, 133, 157, 6 }, - { 91, 177, 200, 164, 10 }, - { 107, 154, 23, 193, 2 }, }, - { { 94, 113, 146, 65, 3 }, - { 199, 222, 0, 157, 0 }, - { 200, 36, 152, 231, 10 }, - { 11, 144, 7, 190, 3 }, }, - { { 92, 178, 113, 235, 13 }, - { 247, 40, 91, 156, 7 }, - { 189, 120, 228, 211, 10 }, - { 227, 157, 161, 78, 15 }, }, - { { 91, 238, 55, 54, 6 }, - { 27, 93, 218, 241, 13 }, - { 102, 206, 199, 125, 10 }, - { 184, 245, 187, 173, 8 }, }, - { { 96, 5, 132, 21, 2 }, - { 8, 147, 160, 164, 0 }, - { 74, 130, 26, 0, 6 }, - { 2, 80, 92, 145, 0 }, }, - { { 100, 8, 128, 51, 8 }, - { 128, 128, 163, 132, 9 }, - { 28, 192, 17, 2, 6 }, - { 146, 28, 80, 16, 1 }, }, - { { 110, 40, 135, 140, 3 }, - { 159, 241, 32, 129, 10 }, - { 195, 30, 17, 71, 6 }, - { 88, 16, 72, 255, 9 }, }, - { { 108, 85, 84, 181, 7 }, - { 238, 23, 226, 180, 2 }, - { 234, 210, 170, 163, 6 }, - { 66, 212, 126, 135, 7 }, }, - { { 104, 186, 254, 70, 1 }, - { 111, 193, 60, 152, 13 }, - { 134, 39, 245, 209, 6 }, - { 177, 147, 200, 63, 6 }, }, - { { 104, 179, 85, 202, 7 }, - { 119, 51, 120, 152, 3 }, - { 229, 58, 172, 209, 6 }, - { 193, 145, 236, 206, 14 }, }, - { { 117, 156, 155, 102, 9 }, - { 220, 200, 55, 248, 9 }, - { 150, 109, 147, 154, 14 }, - { 145, 254, 193, 51, 11 }, }, - { { 124, 11, 200, 10, 0 }, - { 162, 170, 44, 128, 9 }, - { 5, 1, 61, 3, 14 }, - { 144, 19, 69, 84, 5 }, }, - { { 126, 89, 104, 196, 9 }, - { 238, 14, 37, 137, 14 }, - { 146, 49, 105, 167, 14 }, - { 121, 26, 71, 7, 7 }, }, - { { 120, 111, 61, 52, 5 }, - { 31, 15, 238, 176, 12 }, - { 162, 203, 207, 97, 14 }, - { 48, 215, 127, 15, 8 }, }, - { { 120, 193, 191, 255, 10 }, - { 26, 255, 183, 156, 7 }, - { 95, 255, 216, 49, 14 }, - { 227, 158, 223, 245, 8 }, }, - { { 122, 218, 185, 69, 10 }, - { 90, 156, 61, 157, 12 }, - { 90, 41, 213, 181, 14 }, - { 59, 155, 195, 149, 10 }, }, - { { 128, 60, 123, 156, 0 }, - { 121, 96, 132, 50, 14 }, - { 3, 157, 227, 192, 1 }, - { 116, 194, 16, 105, 14 }, }, - { { 135, 20, 88, 249, 7 }, - { 228, 48, 198, 127, 2 }, - { 233, 241, 162, 142, 1 }, - { 79, 230, 48, 194, 7 }, }, - { { 131, 27, 5, 165, 13 }, - { 92, 3, 75, 71, 10 }, - { 186, 90, 13, 140, 1 }, - { 94, 45, 44, 3, 10 }, }, - { { 136, 59, 180, 103, 4 }, - { 75, 131, 74, 30, 13 }, - { 46, 98, 221, 193, 1 }, - { 183, 133, 44, 29, 2 }, }, - { { 140, 169, 136, 156, 0 }, - { 139, 162, 148, 2, 10 }, - { 3, 145, 25, 83, 1 }, - { 84, 2, 148, 93, 1 }, }, - { { 142, 177, 3, 26, 11 }, - { 215, 114, 145, 3, 1 }, - { 213, 140, 8, 215, 1 }, - { 140, 8, 148, 238, 11 }, }, - { { 143, 39, 191, 54, 4 }, - { 155, 195, 206, 115, 5 }, - { 38, 207, 222, 79, 1 }, - { 172, 231, 60, 61, 9 }, }, - { { 143, 22, 179, 202, 0 }, - { 210, 224, 8, 123, 7 }, - { 5, 60, 214, 143, 1 }, - { 237, 225, 0, 116, 11 }, }, - { { 148, 24, 222, 74, 0 }, - { 224, 233, 4, 26, 9 }, - { 5, 39, 177, 130, 9 }, - { 149, 130, 9, 112, 7 }, }, - { { 147, 69, 36, 197, 0 }, - { 8, 15, 0, 111, 6 }, - { 10, 50, 74, 44, 9 }, - { 111, 96, 15, 1, 0 }, }, - { { 156, 253, 156, 216, 5 }, - { 199, 175, 212, 58, 10 }, - { 161, 179, 155, 243, 9 }, - { 85, 194, 191, 94, 3 }, }, - { { 155, 34, 55, 120, 13 }, - { 23, 105, 203, 91, 4 }, - { 177, 238, 196, 77, 9 }, - { 45, 173, 57, 110, 8 }, }, - { { 153, 250, 163, 209, 6 }, - { 83, 220, 216, 78, 14 }, - { 104, 188, 85, 249, 9 }, - { 119, 33, 179, 188, 10 }, }, - { { 162, 159, 28, 84, 3 }, - { 76, 19, 188, 59, 8 }, - { 194, 163, 143, 148, 5 }, - { 29, 195, 220, 131, 2 }, }, - { { 172, 79, 91, 26, 11 }, - { 182, 118, 173, 50, 9 }, - { 213, 141, 175, 35, 5 }, - { 148, 203, 86, 230, 13 }, }, - { { 172, 191, 109, 54, 6 }, - { 251, 19, 254, 34, 13 }, - { 102, 203, 111, 211, 5 }, - { 180, 71, 252, 141, 15 }, }, - { { 169, 185, 76, 64, 8 }, - { 99, 3, 53, 74, 8 }, - { 16, 35, 41, 217, 5 }, - { 21, 42, 204, 12, 6 }, }, - { { 182, 40, 233, 2, 12 }, - { 177, 136, 101, 3, 13 }, - { 52, 9, 113, 70, 13 }, - { 188, 10, 97, 24, 13 }, }, - { { 180, 109, 218, 222, 0 }, - { 169, 238, 164, 58, 11 }, - { 7, 181, 187, 98, 13 }, - { 213, 194, 87, 121, 5 }, }, - { { 178, 110, 246, 10, 1 }, - { 37, 237, 40, 51, 13 }, - { 133, 6, 247, 100, 13 }, - { 188, 193, 75, 122, 4 }, }, - { { 179, 37, 153, 105, 14 }, - { 17, 186, 103, 127, 0 }, - { 121, 105, 154, 76, 13 }, - { 15, 238, 101, 216, 8 }, }, - { { 179, 80, 40, 17, 5 }, - { 68, 12, 228, 71, 4 }, - { 168, 129, 64, 172, 13 }, - { 46, 34, 115, 2, 2 }, }, - { { 190, 28, 27, 59, 6 }, - { 210, 120, 230, 55, 9 }, - { 109, 205, 131, 135, 13 }, - { 158, 198, 113, 228, 11 }, }, - { { 188, 127, 85, 99, 14 }, - { 243, 31, 107, 62, 9 }, - { 124, 106, 175, 227, 13 }, - { 151, 205, 111, 140, 15 }, }, - { { 188, 175, 230, 141, 5 }, - { 175, 235, 120, 38, 14 }, - { 171, 22, 127, 83, 13 }, - { 118, 65, 237, 127, 5 }, }, - { { 189, 37, 146, 140, 4 }, - { 139, 234, 96, 114, 2 }, - { 35, 20, 154, 75, 13 }, - { 68, 224, 101, 125, 1 }, }, - { { 196, 27, 214, 183, 1 }, - { 236, 195, 138, 150, 11 }, - { 142, 214, 189, 130, 3 }, - { 214, 149, 28, 51, 7 }, }, - { { 198, 99, 190, 252, 14 }, - { 137, 247, 207, 155, 6 }, - { 115, 247, 220, 102, 3 }, - { 109, 159, 62, 249, 1 }, }, - { { 198, 86, 130, 19, 13 }, - { 196, 196, 201, 167, 1 }, - { 188, 132, 22, 166, 3 }, - { 142, 89, 50, 50, 3 }, }, - { { 198, 139, 73, 36, 10 }, - { 184, 18, 31, 131, 8 }, - { 82, 73, 45, 22, 3 }, - { 28, 31, 132, 129, 13 }, }, - { { 193, 61, 206, 190, 2 }, - { 105, 243, 134, 226, 11 }, - { 71, 215, 59, 200, 3 }, - { 212, 118, 28, 249, 6 }, }, - { { 197, 25, 109, 109, 1 }, - { 252, 35, 6, 206, 12 }, - { 139, 107, 105, 138, 3 }, - { 55, 54, 12, 67, 15 }, }, - { { 199, 77, 61, 239, 11 }, - { 156, 55, 7, 255, 15 }, - { 223, 123, 203, 46, 3 }, - { 255, 254, 14, 195, 9 }, }, - { { 193, 90, 43, 220, 9 }, - { 92, 100, 141, 202, 14 }, - { 147, 189, 69, 168, 3 }, - { 117, 59, 18, 99, 10 }, }, - { { 202, 35, 114, 33, 12 }, - { 35, 66, 75, 151, 4 }, - { 56, 68, 236, 69, 3 }, - { 46, 157, 36, 44, 4 }, }, - { { 207, 199, 244, 213, 9 }, - { 174, 135, 153, 255, 6 }, - { 154, 178, 254, 63, 3 }, - { 111, 249, 158, 23, 5 }, }, - { { 208, 49, 39, 226, 6 }, - { 81, 91, 66, 138, 7 }, - { 100, 126, 72, 192, 11 }, - { 229, 20, 45, 168, 10 }, }, - { { 212, 119, 84, 14, 0 }, - { 233, 47, 8, 178, 1 }, - { 7, 2, 174, 226, 11 }, - { 132, 209, 15, 73, 7 }, }, - { { 209, 134, 49, 90, 2 }, - { 16, 56, 152, 250, 5 }, - { 69, 168, 198, 24, 11 }, - { 165, 241, 145, 192, 8 }, }, - { { 219, 76, 100, 122, 11 }, - { 38, 61, 131, 235, 13 }, - { 213, 226, 99, 45, 11 }, - { 189, 124, 27, 198, 4 }, }, - { { 219, 132, 135, 144, 8 }, - { 18, 201, 145, 227, 2 }, - { 16, 158, 18, 29, 11 }, - { 76, 120, 153, 52, 8 }, }, - { { 223, 222, 6, 112, 0 }, - { 194, 77, 154, 235, 8 }, - { 0, 230, 7, 191, 11 }, - { 29, 117, 155, 36, 3 }, }, - { { 226, 41, 186, 96, 0 }, - { 1, 194, 38, 155, 12 }, - { 0, 101, 217, 68, 7 }, - { 61, 150, 68, 56, 0 }, }, - { { 225, 64, 224, 141, 6 }, - { 40, 180, 96, 198, 6 }, - { 107, 16, 112, 40, 7 }, - { 102, 48, 98, 209, 4 }, }, - { { 225, 154, 144, 165, 2 }, - { 72, 144, 58, 214, 10 }, - { 74, 80, 149, 152, 7 }, - { 86, 181, 192, 145, 2 }, }, - { { 231, 242, 192, 250, 9 }, - { 229, 164, 187, 203, 3 }, - { 149, 240, 52, 254, 7 }, - { 205, 61, 210, 90, 7 }, }, - { { 238, 173, 190, 131, 8 }, - { 131, 195, 53, 183, 15 }, - { 28, 23, 219, 87, 7 }, - { 254, 218, 204, 60, 1 }, }, - { { 240, 28, 242, 124, 1 }, - { 108, 232, 162, 186, 12 }, - { 131, 228, 243, 128, 15 }, - { 53, 212, 81, 115, 6 }, }, - { { 247, 101, 168, 38, 4 }, - { 137, 142, 102, 227, 5 }, - { 38, 65, 90, 110, 15 }, - { 172, 118, 103, 25, 1 }, }, - { { 247, 236, 195, 164, 13 }, - { 189, 204, 115, 227, 10 }, - { 178, 92, 51, 126, 15 }, - { 92, 124, 227, 59, 13 }, }, - { { 248, 45, 84, 113, 4 }, - { 35, 11, 226, 190, 8 }, - { 40, 226, 171, 65, 15 }, - { 23, 212, 125, 12, 4 }, }, - { { 254, 133, 143, 205, 11 }, - { 158, 251, 53, 175, 2 }, - { 219, 63, 26, 23, 15 }, - { 79, 90, 205, 247, 9 }, }, - { { 248, 227, 91, 11, 6 }, - { 51, 126, 124, 150, 1 }, - { 109, 13, 172, 113, 15 }, - { 134, 147, 231, 236, 12 }, }, - { { 254, 214, 62, 31, 15 }, - { 206, 125, 253, 183, 5 }, - { 255, 135, 198, 183, 15 }, - { 174, 219, 251, 231, 3 }, }, }; - -static unsigned char DICT_7X7_1000_BYTES[][4][7] = - { { { 221, 92, 108, 165, 202, 10, 1 }, - { 99, 179, 173, 228, 49, 180, 0 }, - { 168, 41, 210, 155, 29, 93, 1 }, - { 22, 198, 19, 218, 230, 227, 0 }, }, - { { 228, 27, 241, 62, 64, 171, 0 }, - { 17, 253, 137, 11, 181, 42, 1 }, - { 106, 129, 62, 71, 236, 19, 1 }, - { 170, 86, 232, 72, 223, 196, 0 }, }, - { { 158, 170, 43, 172, 93, 39, 1 }, - { 163, 182, 158, 145, 75, 171, 1 }, - { 242, 93, 26, 234, 42, 188, 1 }, - { 234, 233, 68, 188, 182, 226, 1 }, }, - { { 166, 103, 5, 183, 233, 76, 0 }, - { 221, 48, 50, 221, 165, 172, 0 }, - { 25, 75, 246, 208, 115, 50, 1 }, - { 26, 210, 221, 166, 6, 93, 1 }, }, - { { 198, 188, 123, 19, 50, 86, 0 }, - { 253, 193, 139, 113, 154, 97, 0 }, - { 53, 38, 100, 111, 30, 177, 1 }, - { 67, 44, 199, 104, 193, 223, 1 }, }, - { { 88, 128, 20, 35, 89, 238, 0 }, - { 4, 122, 28, 80, 184, 133, 1 }, - { 59, 205, 98, 20, 0, 141, 0 }, - { 208, 142, 133, 28, 47, 16, 0 }, }, - { { 211, 107, 190, 111, 84, 72, 0 }, - { 164, 240, 198, 70, 247, 63, 0 }, - { 9, 21, 123, 62, 235, 101, 1 }, - { 126, 119, 177, 49, 135, 146, 1 }, }, - { { 60, 161, 109, 136, 139, 219, 0 }, - { 37, 14, 191, 169, 44, 198, 0 }, - { 109, 232, 136, 219, 66, 158, 0 }, - { 49, 154, 74, 254, 184, 82, 0 }, }, - { { 137, 7, 31, 86, 150, 158, 0 }, - { 112, 74, 104, 49, 231, 125, 0 }, - { 60, 180, 181, 124, 112, 72, 1 }, - { 95, 115, 198, 11, 41, 7, 0 }, }, - { { 187, 101, 177, 141, 110, 63, 0 }, - { 200, 86, 142, 255, 101, 242, 1 }, - { 126, 59, 88, 198, 211, 110, 1 }, - { 167, 211, 127, 184, 181, 9, 1 }, }, - { { 245, 0, 209, 130, 244, 144, 1 }, - { 11, 88, 37, 139, 208, 113, 0 }, - { 132, 151, 160, 197, 128, 87, 1 }, - { 71, 5, 232, 210, 13, 104, 0 }, }, - { { 2, 38, 112, 184, 84, 26, 0 }, - { 208, 112, 139, 128, 96, 75, 0 }, - { 44, 21, 14, 135, 50, 32, 0 }, - { 105, 3, 0, 232, 135, 5, 1 }, }, - { { 84, 243, 107, 151, 72, 240, 1 }, - { 55, 25, 135, 197, 159, 200, 1 }, - { 135, 137, 116, 235, 103, 149, 0 }, - { 137, 252, 209, 240, 204, 118, 0 }, }, - { { 158, 36, 136, 70, 35, 153, 1 }, - { 235, 14, 86, 34, 161, 96, 0 }, - { 204, 226, 49, 8, 146, 60, 1 }, - { 3, 66, 162, 53, 56, 107, 1 }, }, - { { 189, 255, 50, 107, 201, 203, 1 }, - { 71, 255, 254, 76, 174, 186, 0 }, - { 233, 201, 235, 38, 127, 222, 1 }, - { 46, 186, 153, 63, 255, 241, 0 }, }, - { { 206, 17, 5, 176, 90, 151, 1 }, - { 147, 63, 8, 177, 20, 229, 0 }, - { 244, 173, 6, 208, 68, 57, 1 }, - { 83, 148, 70, 136, 126, 100, 1 }, }, - { { 211, 240, 97, 114, 31, 139, 0 }, - { 144, 45, 223, 37, 248, 177, 0 }, - { 104, 252, 39, 67, 7, 229, 1 }, - { 70, 143, 210, 125, 218, 4, 1 }, }, - { { 1, 225, 158, 206, 200, 237, 1 }, - { 38, 92, 98, 150, 175, 150, 1 }, - { 219, 137, 185, 188, 195, 192, 0 }, - { 180, 250, 180, 163, 29, 50, 0 }, }, - { { 38, 203, 204, 42, 112, 120, 1 }, - { 175, 176, 1, 14, 172, 79, 1 }, - { 143, 7, 42, 25, 233, 178, 0 }, - { 249, 26, 184, 64, 6, 250, 1 }, }, - { { 56, 125, 77, 118, 65, 19, 0 }, - { 112, 183, 95, 13, 133, 68, 0 }, - { 100, 65, 55, 89, 95, 14, 0 }, - { 17, 80, 216, 125, 118, 135, 0 }, }, - { { 58, 144, 74, 233, 225, 233, 1 }, - { 174, 63, 117, 200, 42, 2, 1 }, - { 203, 195, 203, 169, 4, 174, 0 }, - { 160, 42, 9, 215, 126, 58, 1 }, }, - { { 70, 212, 132, 123, 60, 221, 0 }, - { 221, 45, 64, 86, 248, 199, 0 }, - { 93, 158, 111, 16, 149, 177, 0 }, - { 113, 143, 181, 1, 90, 93, 1 }, }, - { { 72, 146, 167, 222, 158, 43, 1 }, - { 18, 7, 232, 163, 251, 143, 1 }, - { 234, 60, 189, 242, 164, 137, 0 }, - { 248, 239, 226, 139, 240, 36, 0 }, }, - { { 94, 118, 195, 228, 152, 168, 0 }, - { 193, 43, 103, 135, 51, 137, 1 }, - { 10, 140, 147, 225, 183, 61, 0 }, - { 200, 230, 112, 243, 106, 65, 1 }, }, - { { 116, 162, 222, 250, 47, 136, 1 }, - { 59, 104, 87, 170, 250, 142, 0 }, - { 136, 250, 47, 189, 162, 151, 0 }, - { 56, 175, 170, 245, 11, 110, 0 }, }, - { { 148, 93, 226, 40, 19, 89, 0 }, - { 69, 165, 149, 38, 38, 99, 0 }, - { 77, 100, 10, 35, 221, 20, 1 }, - { 99, 50, 50, 84, 210, 209, 0 }, }, - { { 155, 18, 149, 100, 237, 163, 1 }, - { 138, 127, 124, 3, 65, 188, 1 }, - { 226, 219, 147, 84, 164, 108, 1 }, - { 158, 193, 96, 31, 127, 40, 1 }, }, - { { 161, 212, 148, 45, 130, 248, 0 }, - { 68, 105, 32, 110, 41, 118, 1 }, - { 15, 160, 218, 20, 149, 194, 1 }, - { 183, 74, 59, 2, 75, 17, 0 }, }, - { { 187, 120, 230, 49, 108, 208, 1 }, - { 158, 187, 135, 78, 66, 244, 0 }, - { 133, 155, 70, 51, 143, 110, 1 }, - { 23, 161, 57, 112, 238, 188, 1 }, }, - { { 203, 181, 221, 203, 219, 24, 0 }, - { 224, 83, 115, 227, 188, 247, 0 }, - { 12, 109, 233, 221, 214, 233, 1 }, - { 119, 158, 227, 231, 101, 3, 1 }, }, - { { 211, 229, 238, 183, 131, 51, 0 }, - { 240, 36, 191, 230, 159, 116, 1 }, - { 102, 96, 246, 187, 211, 229, 1 }, - { 151, 124, 179, 254, 146, 7, 1 }, }, - { { 242, 148, 35, 63, 209, 156, 1 }, - { 210, 57, 180, 89, 187, 99, 0 }, - { 156, 197, 254, 98, 20, 167, 1 }, - { 99, 110, 205, 22, 206, 37, 1 }, }, - { { 253, 214, 209, 159, 59, 230, 1 }, - { 95, 75, 29, 255, 153, 187, 1 }, - { 179, 238, 124, 197, 181, 223, 1 }, - { 238, 204, 255, 220, 105, 125, 0 }, }, - { { 58, 70, 36, 238, 132, 238, 1 }, - { 198, 42, 236, 156, 225, 14, 1 }, - { 187, 144, 187, 146, 49, 46, 0 }, - { 184, 67, 156, 155, 170, 49, 1 }, }, - { { 98, 24, 126, 36, 59, 15, 0 }, - { 168, 229, 153, 56, 51, 133, 0 }, - { 120, 110, 18, 63, 12, 35, 0 }, - { 80, 230, 14, 76, 211, 138, 1 }, }, - { { 10, 205, 67, 111, 157, 195, 0 }, - { 196, 174, 121, 69, 207, 131, 0 }, - { 97, 220, 251, 97, 89, 168, 0 }, - { 96, 249, 209, 79, 58, 145, 1 }, }, - { { 14, 64, 212, 195, 142, 2, 0 }, - { 129, 66, 105, 230, 192, 132, 0 }, - { 32, 56, 225, 149, 129, 56, 0 }, - { 16, 129, 179, 203, 33, 64, 1 }, }, - { { 20, 159, 217, 160, 98, 36, 0 }, - { 105, 241, 5, 179, 12, 8, 1 }, - { 18, 35, 2, 205, 252, 148, 0 }, - { 136, 24, 102, 208, 71, 203, 0 }, }, - { { 25, 162, 225, 26, 101, 237, 0 }, - { 28, 30, 151, 19, 232, 26, 1 }, - { 91, 211, 44, 67, 162, 204, 0 }, - { 172, 11, 228, 116, 188, 28, 0 }, }, - { { 43, 80, 130, 126, 27, 52, 0 }, - { 144, 35, 80, 62, 131, 211, 1 }, - { 22, 108, 63, 32, 133, 106, 0 }, - { 229, 224, 190, 5, 98, 4, 1 }, }, - { { 41, 105, 56, 146, 159, 163, 0 }, - { 48, 206, 186, 172, 196, 145, 1 }, - { 98, 252, 164, 142, 75, 74, 0 }, - { 196, 145, 154, 174, 185, 134, 0 }, }, - { { 44, 247, 84, 219, 244, 86, 1 }, - { 95, 83, 107, 220, 204, 79, 0 }, - { 181, 23, 237, 149, 119, 154, 0 }, - { 121, 25, 157, 235, 101, 125, 0 }, }, - { { 53, 233, 63, 158, 54, 124, 0 }, - { 61, 192, 134, 189, 239, 87, 1 }, - { 31, 54, 60, 254, 75, 214, 0 }, - { 245, 123, 222, 176, 129, 222, 0 }, }, - { { 63, 116, 171, 216, 61, 243, 1 }, - { 255, 15, 222, 143, 66, 211, 1 }, - { 231, 222, 13, 234, 151, 126, 0 }, - { 229, 161, 120, 189, 248, 127, 1 }, }, - { { 68, 208, 41, 244, 255, 64, 0 }, - { 61, 49, 240, 165, 89, 129, 0 }, - { 1, 127, 151, 202, 5, 145, 0 }, - { 64, 205, 82, 135, 198, 94, 0 }, }, - { { 72, 64, 228, 132, 42, 245, 0 }, - { 12, 14, 129, 182, 17, 196, 1 }, - { 87, 170, 16, 147, 129, 9, 0 }, - { 145, 196, 54, 192, 184, 24, 0 }, }, - { { 95, 25, 19, 104, 52, 2, 0 }, - { 137, 227, 76, 1, 86, 19, 0 }, - { 32, 22, 11, 100, 76, 125, 0 }, - { 100, 53, 64, 25, 99, 200, 1 }, }, - { { 94, 178, 114, 64, 61, 93, 1 }, - { 143, 71, 215, 16, 122, 201, 0 }, - { 221, 94, 1, 39, 38, 189, 0 }, - { 73, 175, 4, 117, 241, 120, 1 }, }, - { { 111, 155, 36, 31, 21, 194, 0 }, - { 149, 139, 152, 72, 221, 31, 0 }, - { 33, 212, 124, 18, 108, 251, 0 }, - { 124, 93, 137, 12, 232, 212, 1 }, }, - { { 114, 170, 249, 32, 168, 227, 1 }, - { 174, 236, 175, 11, 24, 136, 1 }, - { 227, 138, 130, 79, 170, 167, 0 }, - { 136, 140, 104, 122, 155, 186, 1 }, }, - { { 121, 136, 117, 59, 134, 54, 1 }, - { 18, 226, 173, 121, 216, 86, 1 }, - { 182, 48, 238, 87, 8, 207, 0 }, - { 181, 13, 207, 90, 163, 164, 0 }, }, - { { 123, 231, 19, 174, 121, 81, 1 }, - { 206, 118, 22, 141, 159, 219, 0 }, - { 197, 79, 58, 228, 115, 239, 0 }, - { 109, 252, 216, 180, 55, 57, 1 }, }, - { { 133, 106, 70, 201, 89, 224, 0 }, - { 5, 152, 83, 196, 2, 191, 1 }, - { 3, 205, 73, 177, 43, 80, 1 }, - { 254, 160, 17, 229, 12, 208, 0 }, }, - { { 142, 63, 238, 242, 217, 81, 1 }, - { 247, 183, 243, 130, 134, 237, 0 }, - { 197, 77, 167, 187, 254, 56, 1 }, - { 91, 176, 160, 231, 246, 247, 1 }, }, - { { 173, 56, 205, 33, 115, 103, 1 }, - { 47, 183, 27, 123, 0, 53, 1 }, - { 243, 103, 66, 89, 142, 90, 1 }, - { 214, 0, 111, 108, 118, 250, 0 }, }, - { { 177, 55, 37, 48, 185, 63, 1 }, - { 90, 37, 190, 25, 36, 253, 1 }, - { 254, 78, 134, 82, 118, 70, 1 }, - { 223, 146, 76, 62, 210, 45, 0 }, }, - { { 186, 195, 128, 210, 81, 219, 0 }, - { 148, 30, 92, 142, 172, 105, 0 }, - { 109, 197, 37, 128, 225, 174, 1 }, - { 75, 26, 184, 157, 60, 20, 1 }, }, - { { 193, 117, 109, 93, 24, 166, 1 }, - { 114, 9, 203, 85, 21, 183, 1 }, - { 178, 140, 93, 91, 87, 65, 1 }, - { 246, 212, 85, 105, 200, 39, 0 }, }, - { { 206, 97, 211, 126, 229, 17, 0 }, - { 153, 118, 115, 7, 215, 98, 0 }, - { 68, 83, 191, 101, 195, 57, 1 }, - { 35, 117, 240, 103, 55, 76, 1 }, }, - { { 210, 92, 152, 54, 221, 91, 1 }, - { 246, 245, 60, 6, 241, 225, 0 }, - { 237, 93, 182, 12, 157, 37, 1 }, - { 67, 199, 176, 30, 87, 183, 1 }, }, - { { 208, 106, 145, 233, 239, 206, 1 }, - { 14, 248, 126, 247, 112, 170, 0 }, - { 185, 251, 203, 196, 171, 5, 1 }, - { 42, 135, 119, 191, 15, 184, 0 }, }, - { { 73, 228, 227, 141, 169, 90, 1 }, - { 78, 2, 187, 199, 59, 210, 0 }, - { 173, 74, 216, 227, 147, 201, 0 }, - { 37, 238, 113, 238, 160, 57, 0 }, }, - { { 82, 209, 159, 40, 31, 179, 0 }, - { 160, 109, 28, 39, 94, 199, 1 }, - { 102, 252, 10, 124, 197, 165, 0 }, - { 241, 189, 114, 28, 91, 2, 1 }, }, - { { 2, 24, 175, 24, 115, 160, 1 }, - { 186, 153, 144, 35, 2, 7, 1 }, - { 130, 231, 12, 122, 140, 32, 0 }, - { 240, 32, 98, 4, 204, 174, 1 }, }, - { { 5, 192, 75, 56, 81, 119, 0 }, - { 53, 52, 25, 21, 10, 83, 1 }, - { 119, 69, 14, 105, 1, 208, 0 }, - { 229, 40, 84, 76, 22, 86, 0 }, }, - { { 15, 88, 169, 33, 137, 159, 0 }, - { 161, 175, 184, 87, 32, 208, 0 }, - { 124, 200, 194, 74, 141, 120, 0 }, - { 5, 130, 117, 14, 250, 194, 1 }, }, - { { 15, 206, 165, 68, 68, 26, 0 }, - { 193, 146, 200, 7, 105, 92, 0 }, - { 44, 17, 17, 82, 185, 248, 0 }, - { 29, 75, 112, 9, 164, 193, 1 }, }, - { { 21, 238, 211, 115, 20, 216, 1 }, - { 87, 232, 71, 71, 234, 89, 0 }, - { 141, 148, 103, 101, 187, 212, 0 }, - { 77, 43, 241, 113, 11, 245, 0 }, }, - { { 22, 241, 226, 252, 69, 158, 1 }, - { 147, 57, 223, 150, 111, 66, 0 }, - { 188, 209, 31, 163, 199, 180, 0 }, - { 33, 123, 52, 253, 206, 100, 1 }, }, - { { 30, 94, 76, 65, 59, 115, 0 }, - { 237, 135, 93, 100, 0, 205, 1 }, - { 103, 110, 65, 25, 61, 60, 0 }, - { 217, 128, 19, 93, 112, 219, 1 }, }, - { { 31, 194, 82, 102, 200, 118, 1 }, - { 135, 114, 109, 20, 139, 216, 1 }, - { 183, 9, 179, 37, 33, 252, 0 }, - { 141, 232, 148, 91, 39, 112, 1 }, }, - { { 39, 33, 22, 246, 49, 159, 1 }, - { 155, 108, 90, 152, 167, 85, 0 }, - { 252, 198, 55, 180, 66, 114, 0 }, - { 85, 114, 140, 173, 27, 108, 1 }, }, - { { 39, 155, 122, 137, 27, 220, 0 }, - { 165, 201, 145, 248, 46, 219, 0 }, - { 29, 236, 72, 175, 108, 242, 0 }, - { 109, 186, 15, 196, 201, 210, 1 }, }, - { { 46, 12, 48, 75, 106, 108, 0 }, - { 205, 210, 192, 120, 160, 130, 1 }, - { 27, 43, 105, 6, 24, 58, 0 }, - { 160, 130, 143, 1, 165, 217, 1 }, }, - { { 47, 169, 226, 121, 230, 43, 0 }, - { 153, 182, 235, 106, 110, 18, 1 }, - { 106, 51, 207, 35, 202, 250, 0 }, - { 164, 59, 43, 107, 182, 204, 1 }, }, - { { 44, 207, 211, 2, 147, 19, 1 }, - { 67, 198, 57, 47, 142, 73, 0 }, - { 228, 100, 160, 101, 249, 154, 0 }, - { 73, 56, 250, 78, 49, 225, 0 }, }, - { { 49, 83, 3, 2, 18, 230, 1 }, - { 6, 9, 12, 61, 134, 25, 1 }, - { 179, 164, 32, 96, 101, 70, 0 }, - { 204, 48, 222, 24, 72, 48, 0 }, }, - { { 48, 120, 115, 90, 253, 41, 1 }, - { 26, 213, 247, 13, 226, 131, 1 }, - { 202, 95, 173, 103, 15, 6, 0 }, - { 224, 163, 216, 119, 213, 172, 0 }, }, - { { 55, 226, 67, 44, 167, 160, 1 }, - { 139, 40, 55, 45, 75, 26, 1 }, - { 130, 242, 154, 97, 35, 246, 0 }, - { 172, 105, 90, 118, 10, 104, 1 }, }, - { { 76, 11, 79, 138, 255, 84, 0 }, - { 45, 146, 49, 177, 214, 207, 0 }, - { 21, 127, 168, 249, 104, 25, 0 }, - { 121, 181, 198, 198, 36, 218, 0 }, }, - { { 78, 218, 184, 202, 73, 33, 1 }, - { 163, 215, 208, 134, 152, 138, 1 }, - { 194, 73, 41, 142, 173, 185, 0 }, - { 168, 140, 176, 133, 245, 226, 1 }, }, - { { 76, 218, 221, 21, 152, 110, 0 }, - { 53, 195, 41, 87, 57, 141, 1 }, - { 59, 12, 212, 93, 173, 153, 0 }, - { 216, 206, 117, 74, 97, 214, 0 }, }, - { { 86, 123, 85, 187, 37, 96, 1 }, - { 159, 225, 23, 197, 212, 14, 1 }, - { 131, 82, 110, 213, 111, 53, 0 }, - { 184, 21, 209, 244, 67, 252, 1 }, }, - { { 84, 151, 117, 241, 41, 203, 0 }, - { 93, 109, 221, 193, 60, 140, 0 }, - { 105, 202, 71, 215, 116, 149, 0 }, - { 24, 158, 65, 221, 219, 93, 0 }, }, - { { 84, 152, 140, 205, 4, 162, 0 }, - { 33, 137, 76, 194, 89, 6, 1 }, - { 34, 144, 89, 152, 140, 149, 0 }, - { 176, 77, 33, 153, 72, 194, 0 }, }, - { { 94, 110, 164, 168, 119, 169, 0 }, - { 201, 190, 150, 166, 112, 15, 1 }, - { 74, 247, 10, 146, 187, 61, 0 }, - { 248, 7, 50, 180, 190, 201, 1 }, }, - { { 99, 4, 81, 119, 99, 178, 0 }, - { 216, 120, 89, 105, 145, 80, 1 }, - { 38, 227, 119, 69, 16, 99, 0 }, - { 133, 68, 203, 77, 15, 13, 1 }, }, - { { 105, 226, 58, 120, 116, 228, 1 }, - { 62, 122, 194, 28, 90, 27, 1 }, - { 147, 151, 15, 46, 35, 203, 0 }, - { 236, 45, 28, 33, 175, 62, 0 }, }, - { { 109, 23, 226, 74, 80, 28, 1 }, - { 67, 19, 193, 26, 182, 91, 0 }, - { 156, 5, 41, 35, 244, 91, 0 }, - { 109, 54, 172, 65, 228, 97, 0 }, }, - { { 112, 62, 128, 226, 203, 177, 0 }, - { 64, 189, 118, 170, 144, 200, 1 }, - { 70, 233, 163, 128, 190, 7, 0 }, - { 137, 132, 170, 183, 94, 129, 0 }, }, - { { 119, 80, 90, 139, 20, 43, 1 }, - { 163, 69, 13, 204, 242, 19, 1 }, - { 234, 20, 104, 173, 5, 119, 0 }, - { 228, 39, 153, 216, 81, 98, 1 }, }, - { { 130, 100, 225, 43, 36, 151, 1 }, - { 202, 44, 139, 87, 192, 98, 0 }, - { 244, 146, 106, 67, 147, 32, 1 }, - { 35, 1, 245, 104, 154, 41, 1 }, }, - { { 131, 253, 167, 209, 241, 197, 0 }, - { 220, 157, 242, 215, 14, 53, 0 }, - { 81, 199, 197, 242, 223, 224, 1 }, - { 86, 56, 117, 167, 220, 157, 1 }, }, - { { 147, 189, 107, 77, 96, 125, 1 }, - { 238, 149, 199, 81, 47, 114, 1 }, - { 223, 3, 89, 107, 94, 228, 1 }, - { 167, 122, 69, 113, 212, 187, 1 }, }, - { { 148, 216, 165, 194, 122, 237, 1 }, - { 15, 157, 196, 183, 168, 165, 1 }, - { 219, 175, 33, 210, 141, 148, 1 }, - { 210, 138, 246, 145, 220, 248, 0 }, }, - { { 148, 247, 189, 26, 15, 79, 1 }, - { 119, 69, 158, 55, 236, 174, 0 }, - { 249, 120, 44, 94, 247, 148, 1 }, - { 58, 155, 246, 60, 209, 119, 0 }, }, - { { 152, 241, 170, 62, 148, 248, 0 }, - { 52, 43, 166, 6, 239, 99, 1 }, - { 15, 148, 190, 42, 199, 140, 1 }, - { 227, 123, 176, 50, 234, 22, 0 }, }, - { { 169, 138, 223, 140, 87, 40, 0 }, - { 32, 210, 17, 171, 107, 63, 1 }, - { 10, 117, 24, 253, 168, 202, 1 }, - { 254, 107, 106, 196, 37, 130, 0 }, }, - { { 177, 14, 54, 223, 65, 63, 0 }, - { 80, 212, 220, 216, 163, 126, 1 }, - { 126, 65, 125, 182, 56, 70, 1 }, - { 191, 98, 141, 157, 149, 133, 0 }, }, - { { 185, 234, 28, 100, 226, 107, 0 }, - { 44, 246, 110, 44, 41, 60, 1 }, - { 107, 35, 147, 28, 43, 206, 1 }, - { 158, 74, 26, 59, 55, 154, 0 }, }, - { { 188, 38, 74, 240, 242, 183, 1 }, - { 123, 62, 111, 184, 2, 105, 1 }, - { 246, 167, 135, 169, 50, 30, 1 }, - { 203, 32, 14, 251, 62, 111, 0 }, }, - { { 189, 63, 146, 218, 126, 170, 0 }, - { 89, 219, 78, 170, 230, 187, 1 }, - { 42, 191, 45, 164, 254, 94, 1 }, - { 238, 179, 170, 185, 109, 205, 0 }, }, - { { 192, 53, 46, 74, 202, 87, 0 }, - { 100, 21, 234, 48, 150, 230, 0 }, - { 117, 41, 169, 58, 86, 1, 1 }, - { 51, 180, 134, 43, 212, 19, 0 }, }, - { { 194, 54, 220, 36, 22, 128, 1 }, - { 226, 105, 3, 34, 81, 45, 0 }, - { 128, 180, 18, 29, 182, 33, 1 }, - { 90, 69, 34, 96, 75, 35, 1 }, }, - { { 211, 79, 245, 172, 136, 118, 1 }, - { 198, 224, 173, 151, 21, 254, 1 }, - { 183, 8, 154, 215, 249, 101, 1 }, - { 191, 212, 116, 218, 131, 177, 1 }, }, - { { 215, 6, 210, 240, 31, 150, 0 }, - { 209, 104, 93, 178, 82, 249, 0 }, - { 52, 252, 7, 165, 176, 117, 1 }, - { 79, 165, 38, 221, 11, 69, 1 }, }, - { { 216, 50, 245, 201, 86, 5, 0 }, - { 0, 87, 199, 243, 80, 47, 0 }, - { 80, 53, 73, 215, 166, 13, 1 }, - { 122, 5, 103, 241, 245, 0, 0 }, }, - { { 216, 217, 65, 4, 131, 170, 0 }, - { 0, 139, 61, 37, 61, 32, 1 }, - { 42, 224, 144, 65, 77, 141, 1 }, - { 130, 94, 82, 94, 104, 128, 0 }, }, - { { 224, 211, 100, 108, 77, 209, 1 }, - { 6, 61, 209, 12, 93, 238, 0 }, - { 197, 217, 27, 19, 101, 131, 1 }, - { 59, 221, 24, 69, 222, 48, 0 }, }, - { { 225, 232, 37, 60, 152, 205, 0 }, - { 20, 172, 162, 29, 57, 183, 0 }, - { 89, 140, 158, 82, 11, 195, 1 }, - { 118, 206, 92, 34, 154, 148, 0 }, }, - { { 229, 118, 79, 139, 232, 157, 1 }, - { 107, 29, 35, 221, 178, 254, 0 }, - { 220, 139, 232, 249, 55, 83, 1 }, - { 63, 166, 221, 226, 92, 107, 0 }, }, - { { 232, 80, 250, 159, 250, 74, 0 }, - { 60, 83, 169, 238, 179, 163, 0 }, - { 41, 47, 252, 175, 133, 11, 1 }, - { 98, 230, 187, 202, 229, 30, 0 }, }, - { { 235, 128, 234, 240, 130, 92, 1 }, - { 182, 34, 225, 186, 58, 112, 0 }, - { 157, 32, 135, 171, 128, 235, 1 }, - { 7, 46, 46, 195, 162, 54, 1 }, }, - { { 239, 108, 113, 174, 69, 200, 1 }, - { 199, 250, 147, 141, 241, 50, 0 }, - { 137, 209, 58, 199, 27, 123, 1 }, - { 38, 71, 216, 228, 175, 241, 1 }, }, - { { 247, 217, 64, 237, 177, 12, 0 }, - { 137, 161, 117, 220, 61, 51, 0 }, - { 24, 70, 219, 129, 77, 247, 1 }, - { 102, 94, 29, 215, 66, 200, 1 }, }, - { { 254, 214, 40, 241, 92, 60, 1 }, - { 243, 51, 196, 220, 120, 233, 1 }, - { 158, 29, 71, 138, 53, 191, 1 }, - { 203, 143, 29, 145, 230, 103, 1 }, }, - { { 20, 199, 225, 220, 124, 3, 1 }, - { 91, 20, 205, 135, 77, 139, 0 }, - { 224, 31, 29, 195, 241, 148, 0 }, - { 104, 217, 112, 217, 148, 109, 0 }, }, - { { 34, 236, 79, 160, 255, 225, 0 }, - { 236, 188, 51, 173, 74, 133, 1 }, - { 67, 255, 130, 249, 27, 162, 0 }, - { 208, 169, 90, 230, 30, 155, 1 }, }, - { { 164, 134, 72, 34, 231, 234, 0 }, - { 109, 56, 57, 40, 232, 40, 1 }, - { 43, 243, 162, 9, 48, 146, 1 }, - { 138, 11, 138, 78, 14, 91, 0 }, }, - { { 179, 172, 156, 128, 134, 12, 1 }, - { 226, 192, 38, 186, 104, 52, 0 }, - { 152, 48, 128, 156, 154, 230, 1 }, - { 22, 11, 46, 178, 1, 163, 1 }, }, - { { 235, 197, 247, 106, 12, 68, 0 }, - { 196, 98, 193, 31, 222, 182, 0 }, - { 17, 24, 43, 119, 209, 235, 1 }, - { 54, 189, 252, 65, 163, 17, 1 }, }, - { { 0, 36, 28, 209, 199, 244, 0 }, - { 116, 88, 114, 240, 64, 68, 1 }, - { 23, 241, 197, 156, 18, 0, 0 }, - { 145, 1, 7, 167, 13, 23, 0 }, }, - { { 0, 65, 85, 60, 228, 236, 0 }, - { 28, 120, 33, 21, 101, 6, 1 }, - { 27, 147, 158, 85, 65, 0, 0 }, - { 176, 83, 84, 66, 15, 28, 0 }, }, - { { 2, 119, 133, 135, 91, 48, 1 }, - { 194, 17, 18, 231, 133, 205, 1 }, - { 134, 109, 112, 208, 247, 32, 0 }, - { 217, 208, 243, 164, 68, 33, 1 }, }, - { { 1, 218, 232, 155, 2, 227, 0 }, - { 52, 141, 137, 230, 136, 26, 1 }, - { 99, 160, 108, 139, 173, 192, 0 }, - { 172, 8, 179, 200, 216, 150, 0 }, }, - { { 4, 40, 5, 26, 111, 159, 0 }, - { 25, 156, 26, 49, 224, 198, 0 }, - { 124, 251, 44, 80, 10, 16, 0 }, - { 49, 131, 198, 44, 28, 204, 0 }, }, - { { 7, 145, 0, 75, 83, 171, 0 }, - { 129, 29, 88, 96, 172, 19, 1 }, - { 106, 229, 105, 0, 68, 240, 0 }, - { 228, 26, 131, 13, 92, 64, 1 }, }, - { { 10, 89, 153, 210, 227, 215, 1 }, - { 190, 223, 120, 183, 132, 64, 0 }, - { 245, 227, 165, 204, 205, 40, 0 }, - { 1, 16, 246, 143, 125, 190, 1 }, }, - { { 9, 178, 243, 249, 248, 177, 1 }, - { 26, 127, 227, 195, 10, 219, 1 }, - { 198, 143, 207, 231, 166, 200, 0 }, - { 237, 168, 97, 227, 255, 44, 0 }, }, - { { 13, 49, 205, 127, 92, 218, 1 }, - { 55, 59, 75, 67, 229, 215, 0 }, - { 173, 157, 127, 89, 198, 88, 0 }, - { 117, 211, 225, 105, 110, 118, 0 }, }, - { { 14, 110, 159, 79, 116, 37, 1 }, - { 235, 214, 66, 87, 195, 15, 1 }, - { 210, 23, 121, 124, 187, 56, 0 }, - { 248, 97, 245, 33, 53, 235, 1 }, }, - { { 23, 114, 128, 242, 245, 110, 0 }, - { 157, 49, 126, 150, 224, 25, 1 }, - { 59, 87, 167, 128, 167, 116, 0 }, - { 204, 3, 180, 191, 70, 92, 1 }, }, - { { 22, 255, 97, 63, 186, 238, 0 }, - { 221, 169, 175, 117, 173, 139, 1 }, - { 59, 174, 254, 67, 127, 180, 0 }, - { 232, 218, 215, 122, 202, 221, 1 }, }, - { { 25, 50, 221, 83, 147, 173, 1 }, - { 50, 79, 119, 115, 160, 29, 1 }, - { 218, 228, 229, 93, 166, 76, 0 }, - { 220, 2, 231, 119, 121, 38, 0 }, }, - { { 30, 55, 90, 161, 138, 28, 1 }, - { 227, 99, 39, 240, 38, 200, 0 }, - { 156, 40, 194, 173, 118, 60, 0 }, - { 9, 178, 7, 242, 99, 99, 1 }, }, - { { 30, 243, 155, 67, 46, 40, 0 }, - { 169, 67, 70, 103, 238, 136, 1 }, - { 10, 58, 97, 108, 231, 188, 0 }, - { 136, 187, 243, 49, 97, 74, 1 }, }, - { { 35, 152, 218, 66, 102, 77, 0 }, - { 172, 213, 65, 58, 234, 16, 0 }, - { 89, 51, 33, 45, 140, 226, 0 }, - { 4, 43, 174, 65, 85, 154, 1 }, }, - { { 35, 183, 98, 39, 73, 166, 1 }, - { 194, 57, 155, 88, 143, 152, 1 }, - { 178, 201, 114, 35, 118, 226, 0 }, - { 140, 248, 141, 108, 206, 33, 1 }, }, - { { 39, 232, 89, 247, 30, 7, 0 }, - { 177, 228, 75, 253, 201, 145, 0 }, - { 112, 60, 119, 205, 11, 242, 0 }, - { 68, 201, 223, 233, 19, 198, 1 }, }, - { { 41, 207, 36, 233, 56, 245, 0 }, - { 76, 174, 192, 220, 12, 223, 1 }, - { 87, 142, 75, 146, 121, 202, 0 }, - { 253, 152, 29, 129, 186, 153, 0 }, }, - { { 43, 202, 225, 232, 241, 71, 1 }, - { 142, 182, 249, 159, 8, 27, 0 }, - { 241, 71, 139, 195, 169, 234, 0 }, - { 108, 8, 124, 207, 182, 184, 1 }, }, - { { 46, 52, 167, 60, 136, 145, 0 }, - { 209, 47, 162, 11, 3, 198, 0 }, - { 68, 136, 158, 114, 150, 58, 0 }, - { 49, 224, 104, 34, 250, 69, 1 }, }, - { { 44, 130, 54, 130, 20, 241, 1 }, - { 7, 78, 128, 136, 202, 77, 1 }, - { 199, 148, 32, 182, 32, 154, 0 }, - { 217, 41, 136, 128, 185, 112, 0 }, }, - { { 52, 119, 39, 34, 124, 128, 0 }, - { 73, 57, 134, 13, 198, 141, 0 }, - { 0, 159, 34, 114, 119, 22, 0 }, - { 88, 177, 216, 48, 206, 73, 0 }, }, - { { 62, 106, 78, 239, 207, 36, 0 }, - { 161, 178, 119, 252, 195, 142, 1 }, - { 18, 121, 251, 185, 43, 62, 0 }, - { 184, 225, 159, 247, 38, 194, 1 }, }, - { { 61, 189, 0, 186, 135, 236, 0 }, - { 85, 171, 54, 184, 236, 18, 1 }, - { 27, 240, 174, 128, 94, 222, 0 }, - { 164, 27, 142, 182, 106, 213, 0 }, }, - { { 65, 89, 70, 17, 248, 154, 0 }, - { 24, 153, 41, 68, 54, 213, 0 }, - { 44, 143, 196, 49, 77, 65, 0 }, - { 85, 182, 17, 74, 76, 140, 0 }, }, - { { 66, 160, 192, 80, 251, 19, 1 }, - { 154, 20, 123, 34, 24, 193, 0 }, - { 228, 111, 133, 1, 130, 161, 0 }, - { 65, 140, 34, 111, 20, 44, 1 }, }, - { { 66, 215, 59, 80, 17, 218, 1 }, - { 246, 73, 216, 5, 62, 73, 0 }, - { 173, 196, 5, 110, 117, 161, 0 }, - { 73, 62, 80, 13, 201, 55, 1 }, }, - { { 71, 21, 159, 236, 40, 89, 1 }, - { 239, 101, 64, 131, 55, 214, 0 }, - { 205, 10, 27, 252, 212, 113, 0 }, - { 53, 246, 96, 129, 83, 123, 1 }, }, - { { 72, 72, 74, 156, 121, 141, 1 }, - { 58, 158, 17, 148, 51, 131, 0 }, - { 216, 207, 28, 169, 9, 9, 0 }, - { 96, 230, 20, 196, 60, 174, 0 }, }, - { { 75, 141, 239, 56, 120, 19, 0 }, - { 248, 182, 137, 3, 30, 215, 0 }, - { 100, 15, 14, 123, 216, 233, 0 }, - { 117, 188, 96, 72, 182, 143, 1 }, }, - { { 72, 197, 79, 119, 42, 255, 1 }, - { 126, 46, 73, 117, 191, 196, 1 }, - { 255, 170, 119, 121, 81, 137, 0 }, - { 145, 254, 215, 73, 58, 63, 0 }, }, - { { 73, 205, 149, 222, 250, 38, 0 }, - { 88, 210, 104, 183, 157, 151, 1 }, - { 50, 47, 189, 212, 217, 201, 0 }, - { 244, 220, 246, 139, 37, 141, 0 }, }, - { { 74, 248, 19, 154, 40, 250, 0 }, - { 156, 203, 10, 133, 186, 194, 1 }, - { 47, 138, 44, 228, 15, 169, 0 }, - { 161, 174, 208, 168, 105, 156, 1 }, }, - { { 76, 39, 45, 47, 65, 165, 0 }, - { 97, 62, 146, 81, 149, 14, 1 }, - { 82, 193, 122, 90, 114, 25, 0 }, - { 184, 84, 197, 36, 190, 67, 0 }, }, - { { 76, 63, 202, 163, 60, 106, 1 }, - { 111, 163, 11, 194, 246, 137, 1 }, - { 171, 30, 98, 169, 254, 25, 0 }, - { 200, 183, 161, 232, 98, 251, 0 }, }, - { { 76, 105, 150, 233, 240, 91, 0 }, - { 13, 246, 106, 198, 54, 71, 0 }, - { 109, 7, 203, 180, 203, 25, 0 }, - { 113, 54, 49, 171, 55, 216, 0 }, }, - { { 83, 59, 100, 210, 198, 162, 0 }, - { 144, 153, 239, 160, 212, 28, 1 }, - { 34, 177, 165, 147, 110, 101, 0 }, - { 156, 21, 130, 251, 204, 132, 1 }, }, - { { 81, 70, 77, 104, 180, 53, 1 }, - { 106, 36, 101, 21, 80, 95, 1 }, - { 214, 22, 139, 89, 49, 69, 0 }, - { 253, 5, 84, 83, 18, 43, 0 }, }, - { { 81, 86, 86, 98, 113, 201, 1 }, - { 78, 125, 85, 4, 178, 29, 0 }, - { 201, 199, 35, 53, 53, 69, 0 }, - { 92, 38, 144, 85, 95, 57, 0 }, }, - { { 80, 115, 53, 140, 113, 223, 1 }, - { 14, 93, 158, 149, 53, 79, 0 }, - { 253, 199, 24, 214, 103, 5, 0 }, - { 121, 86, 84, 188, 221, 56, 0 }, }, - { { 84, 74, 231, 46, 2, 158, 1 }, - { 3, 168, 141, 55, 179, 78, 0 }, - { 188, 160, 58, 115, 169, 21, 0 }, - { 57, 102, 246, 88, 138, 224, 0 }, }, - { { 84, 219, 22, 238, 94, 71, 0 }, - { 5, 245, 76, 180, 223, 143, 0 }, - { 113, 61, 59, 180, 109, 149, 0 }, - { 120, 253, 150, 153, 87, 208, 0 }, }, - { { 86, 240, 240, 30, 140, 100, 1 }, - { 151, 65, 167, 22, 217, 130, 1 }, - { 147, 24, 188, 7, 135, 181, 0 }, - { 160, 205, 180, 114, 193, 116, 1 }, }, - { { 91, 106, 3, 196, 23, 123, 1 }, - { 134, 134, 94, 165, 115, 89, 1 }, - { 239, 116, 17, 224, 43, 109, 0 }, - { 205, 103, 82, 189, 48, 176, 1 }, }, - { { 91, 249, 239, 82, 25, 108, 1 }, - { 182, 131, 215, 23, 190, 149, 1 }, - { 155, 76, 37, 123, 207, 237, 0 }, - { 212, 190, 244, 117, 224, 182, 1 }, }, - { { 92, 116, 249, 2, 251, 190, 0 }, - { 105, 91, 191, 55, 176, 193, 1 }, - { 62, 239, 160, 79, 151, 29, 0 }, - { 193, 134, 246, 126, 237, 75, 0 }, }, - { { 94, 157, 11, 47, 79, 122, 1 }, - { 231, 179, 28, 97, 255, 194, 1 }, - { 175, 121, 122, 104, 92, 189, 0 }, - { 161, 255, 195, 28, 102, 243, 1 }, }, - { { 99, 67, 213, 185, 201, 130, 0 }, - { 144, 120, 57, 207, 20, 158, 0 }, - { 32, 201, 206, 213, 225, 99, 0 }, - { 60, 148, 121, 206, 15, 4, 1 }, }, - { { 96, 93, 164, 245, 22, 155, 1 }, - { 82, 173, 200, 238, 117, 69, 0 }, - { 236, 180, 87, 146, 221, 3, 0 }, - { 81, 87, 59, 137, 218, 165, 0 }, }, - { { 100, 136, 47, 135, 72, 47, 0 }, - { 33, 148, 136, 217, 187, 132, 1 }, - { 122, 9, 112, 250, 8, 147, 0 }, - { 144, 238, 205, 136, 148, 194, 0 }, }, - { { 104, 106, 145, 148, 102, 64, 0 }, - { 28, 210, 2, 175, 81, 8, 0 }, - { 1, 51, 20, 196, 171, 11, 0 }, - { 8, 69, 122, 160, 37, 156, 0 }, }, - { { 108, 55, 209, 238, 204, 101, 1 }, - { 71, 119, 99, 155, 213, 138, 1 }, - { 211, 25, 187, 197, 246, 27, 0 }, - { 168, 213, 236, 227, 119, 113, 0 }, }, - { { 109, 89, 245, 135, 43, 42, 0 }, - { 9, 195, 153, 239, 181, 148, 1 }, - { 42, 106, 112, 215, 205, 91, 0 }, - { 148, 214, 251, 204, 225, 200, 0 }, }, - { { 115, 31, 7, 158, 40, 12, 0 }, - { 216, 129, 4, 153, 183, 158, 0 }, - { 24, 10, 60, 240, 124, 103, 0 }, - { 60, 246, 204, 144, 64, 141, 1 }, }, - { { 114, 38, 22, 146, 200, 199, 1 }, - { 214, 92, 46, 152, 146, 140, 0 }, - { 241, 137, 164, 180, 50, 39, 0 }, - { 24, 164, 140, 186, 29, 53, 1 }, }, - { { 115, 131, 239, 207, 199, 93, 1 }, - { 166, 20, 245, 251, 255, 94, 0 }, - { 221, 113, 249, 251, 224, 231, 0 }, - { 61, 127, 239, 215, 148, 50, 1 }, }, - { { 113, 246, 244, 181, 170, 13, 0 }, - { 88, 101, 167, 254, 57, 156, 0 }, - { 88, 42, 214, 151, 183, 199, 0 }, - { 28, 206, 63, 242, 211, 13, 0 }, }, - { { 118, 16, 2, 241, 170, 59, 0 }, - { 153, 37, 108, 232, 50, 192, 1 }, - { 110, 42, 199, 160, 4, 55, 0 }, - { 129, 166, 11, 155, 82, 76, 1 }, }, - { { 118, 84, 255, 84, 38, 33, 0 }, - { 249, 69, 197, 47, 83, 4, 1 }, - { 66, 50, 21, 127, 149, 55, 0 }, - { 144, 101, 122, 81, 209, 79, 1 }, }, - { { 122, 227, 200, 30, 38, 54, 0 }, - { 184, 2, 15, 62, 221, 74, 1 }, - { 54, 50, 60, 9, 227, 175, 0 }, - { 169, 93, 190, 120, 32, 14, 1 }, }, - { { 126, 32, 91, 27, 109, 102, 0 }, - { 189, 82, 31, 89, 210, 130, 1 }, - { 51, 91, 108, 109, 2, 63, 0 }, - { 160, 165, 205, 124, 37, 94, 1 }, }, - { { 124, 113, 102, 127, 179, 75, 1 }, - { 31, 39, 255, 108, 183, 7, 0 }, - { 233, 102, 255, 51, 71, 31, 0 }, - { 112, 118, 155, 127, 242, 124, 0 }, }, - { { 126, 136, 249, 129, 71, 26, 0 }, - { 161, 210, 157, 235, 120, 64, 0 }, - { 44, 113, 64, 207, 136, 191, 0 }, - { 1, 15, 107, 220, 165, 194, 1 }, }, - { { 127, 189, 182, 243, 152, 70, 0 }, - { 213, 227, 238, 218, 158, 149, 0 }, - { 49, 12, 231, 182, 222, 255, 0 }, - { 84, 188, 173, 187, 227, 213, 1 }, }, - { { 131, 186, 63, 66, 156, 103, 0 }, - { 164, 197, 234, 17, 202, 189, 1 }, - { 115, 28, 161, 126, 46, 224, 1 }, - { 222, 169, 196, 43, 209, 146, 1 }, }, - { { 131, 179, 163, 188, 159, 85, 1 }, - { 150, 37, 178, 179, 79, 251, 0 }, - { 213, 124, 158, 226, 230, 224, 1 }, - { 111, 249, 102, 166, 210, 52, 1 }, }, - { { 134, 184, 56, 238, 195, 91, 1 }, - { 167, 245, 250, 160, 169, 98, 0 }, - { 237, 97, 187, 142, 14, 176, 1 }, - { 35, 74, 130, 175, 215, 242, 1 }, }, - { { 138, 251, 116, 46, 23, 43, 0 }, - { 128, 231, 155, 36, 237, 47, 1 }, - { 106, 116, 58, 23, 111, 168, 1 }, - { 250, 91, 146, 108, 243, 128, 1 }, }, - { { 142, 5, 134, 252, 131, 42, 0 }, - { 209, 34, 120, 162, 39, 38, 1 }, - { 42, 96, 159, 176, 208, 56, 1 }, - { 178, 114, 34, 143, 34, 69, 1 }, }, - { { 143, 72, 60, 30, 32, 231, 0 }, - { 189, 206, 136, 20, 129, 54, 1 }, - { 115, 130, 60, 30, 9, 120, 1 }, - { 182, 64, 148, 8, 185, 222, 1 }, }, - { { 142, 83, 181, 252, 28, 224, 0 }, - { 149, 107, 192, 135, 69, 175, 1 }, - { 3, 156, 31, 214, 229, 56, 1 }, - { 250, 209, 112, 129, 235, 84, 1 }, }, - { { 141, 157, 35, 130, 73, 96, 0 }, - { 69, 147, 144, 129, 142, 176, 1 }, - { 3, 73, 32, 226, 92, 216, 1 }, - { 134, 184, 192, 132, 228, 209, 0 }, }, - { { 141, 185, 144, 117, 146, 156, 1 }, - { 19, 235, 98, 114, 45, 113, 0 }, - { 156, 164, 215, 4, 206, 216, 1 }, - { 71, 90, 39, 35, 107, 228, 0 }, }, - { { 144, 19, 230, 225, 162, 176, 0 }, - { 8, 41, 229, 226, 6, 108, 1 }, - { 6, 162, 195, 179, 228, 4, 1 }, - { 155, 48, 35, 211, 202, 8, 0 }, }, - { { 147, 155, 55, 123, 26, 144, 1 }, - { 146, 233, 196, 97, 142, 255, 0 }, - { 132, 172, 111, 118, 108, 228, 1 }, - { 127, 184, 195, 17, 203, 164, 1 }, }, - { { 151, 14, 49, 237, 242, 168, 1 }, - { 203, 248, 228, 225, 33, 59, 1 }, - { 138, 167, 219, 198, 56, 116, 1 }, - { 238, 66, 67, 147, 143, 233, 1 }, }, - { { 151, 52, 94, 59, 153, 170, 0 }, - { 241, 105, 63, 64, 162, 183, 1 }, - { 42, 204, 238, 61, 22, 116, 1 }, - { 246, 162, 129, 126, 75, 71, 1 }, }, - { { 149, 122, 253, 44, 125, 85, 0 }, - { 45, 245, 151, 23, 65, 255, 0 }, - { 85, 95, 26, 95, 175, 84, 1 }, - { 127, 193, 116, 116, 215, 218, 0 }, }, - { { 151, 221, 14, 6, 20, 80, 1 }, - { 231, 129, 4, 4, 207, 117, 0 }, - { 133, 20, 48, 56, 93, 244, 1 }, - { 87, 121, 144, 16, 64, 243, 1 }, }, - { { 154, 154, 4, 227, 189, 68, 1 }, - { 142, 163, 116, 208, 200, 173, 0 }, - { 145, 94, 227, 144, 44, 172, 1 }, - { 90, 137, 133, 151, 98, 184, 1 }, }, - { { 155, 190, 173, 173, 13, 248, 1 }, - { 230, 171, 150, 195, 105, 254, 1 }, - { 143, 216, 90, 218, 190, 236, 1 }, - { 191, 203, 97, 180, 234, 179, 1 }, }, - { { 157, 103, 144, 38, 24, 93, 0 }, - { 69, 102, 6, 22, 165, 249, 0 }, - { 93, 12, 50, 4, 243, 92, 1 }, - { 79, 210, 180, 48, 51, 81, 0 }, }, - { { 159, 129, 201, 246, 175, 127, 0 }, - { 189, 38, 125, 179, 237, 240, 1 }, - { 127, 122, 183, 201, 192, 252, 1 }, - { 135, 219, 230, 223, 50, 94, 1 }, }, - { { 159, 247, 196, 109, 149, 97, 1 }, - { 199, 39, 119, 70, 77, 63, 1 }, - { 195, 84, 219, 17, 247, 252, 1 }, - { 254, 89, 49, 119, 114, 113, 1 }, }, - { { 167, 3, 62, 38, 186, 122, 0 }, - { 173, 96, 168, 40, 167, 253, 1 }, - { 47, 46, 178, 62, 96, 114, 1 }, - { 223, 242, 138, 10, 131, 90, 1 }, }, - { { 166, 79, 109, 144, 30, 111, 0 }, - { 245, 132, 137, 189, 100, 173, 1 }, - { 123, 60, 4, 219, 121, 50, 1 }, - { 218, 147, 94, 200, 144, 215, 1 }, }, - { { 166, 84, 136, 155, 103, 3, 0 }, - { 249, 21, 24, 238, 192, 34, 0 }, - { 96, 115, 108, 136, 149, 50, 1 }, - { 34, 1, 187, 140, 84, 79, 1 }, }, - { { 164, 250, 171, 52, 23, 138, 0 }, - { 49, 169, 154, 47, 107, 41, 0 }, - { 40, 244, 22, 106, 175, 146, 1 }, - { 74, 107, 122, 44, 202, 198, 0 }, }, - { { 169, 35, 165, 79, 219, 255, 1 }, - { 6, 30, 250, 123, 165, 255, 1 }, - { 255, 237, 249, 82, 226, 74, 1 }, - { 255, 210, 239, 47, 188, 48, 0 }, }, - { { 175, 22, 89, 55, 116, 14, 1 }, - { 251, 115, 9, 89, 225, 57, 0 }, - { 184, 23, 118, 77, 52, 122, 1 }, - { 78, 67, 205, 72, 103, 111, 1 }, }, - { { 174, 60, 2, 96, 17, 226, 1 }, - { 199, 171, 90, 8, 2, 33, 1 }, - { 163, 196, 3, 32, 30, 58, 1 }, - { 194, 32, 8, 45, 106, 241, 1 }, }, - { { 174, 166, 70, 29, 70, 134, 0 }, - { 209, 26, 11, 120, 75, 46, 0 }, - { 48, 177, 92, 49, 50, 186, 1 }, - { 58, 105, 15, 104, 44, 69, 1 }, }, - { { 174, 169, 188, 206, 254, 64, 0 }, - { 173, 210, 226, 170, 205, 167, 0 }, - { 1, 63, 185, 158, 202, 186, 1 }, - { 114, 217, 170, 163, 165, 218, 1 }, }, - { { 177, 170, 233, 41, 210, 190, 0 }, - { 32, 184, 175, 123, 40, 123, 1 }, - { 62, 165, 202, 75, 170, 198, 1 }, - { 239, 10, 111, 122, 142, 130, 0 }, }, - { { 179, 236, 199, 247, 61, 40, 0 }, - { 216, 160, 87, 207, 235, 181, 1 }, - { 10, 94, 119, 241, 155, 230, 1 }, - { 214, 235, 249, 245, 2, 141, 1 }, }, - { { 179, 242, 249, 209, 5, 96, 1 }, - { 182, 65, 215, 207, 72, 56, 1 }, - { 131, 80, 69, 207, 167, 230, 1 }, - { 142, 9, 121, 245, 193, 54, 1 }, }, - { { 183, 83, 178, 95, 132, 147, 0 }, - { 145, 77, 236, 78, 199, 122, 0 }, - { 100, 144, 253, 38, 229, 118, 1 }, - { 47, 113, 185, 27, 217, 68, 1 }, }, - { { 180, 99, 115, 84, 106, 222, 0 }, - { 29, 88, 207, 61, 39, 232, 0 }, - { 61, 171, 21, 103, 99, 22, 1 }, - { 11, 242, 94, 121, 141, 92, 0 }, }, - { { 182, 97, 89, 33, 192, 136, 0 }, - { 161, 120, 39, 77, 36, 32, 0 }, - { 8, 129, 194, 77, 67, 54, 1 }, - { 2, 18, 89, 114, 15, 66, 1 }, }, - { { 186, 184, 208, 95, 68, 186, 1 }, - { 146, 219, 79, 74, 233, 98, 1 }, - { 174, 145, 125, 5, 142, 174, 1 }, - { 163, 75, 169, 121, 109, 164, 1 }, }, - { { 186, 192, 40, 124, 16, 3, 1 }, - { 178, 38, 204, 12, 9, 35, 0 }, - { 224, 4, 31, 10, 1, 174, 1 }, - { 98, 72, 24, 25, 178, 38, 1 }, }, - { { 188, 9, 19, 77, 135, 103, 0 }, - { 5, 198, 124, 121, 71, 34, 1 }, - { 115, 112, 217, 100, 72, 30, 1 }, - { 162, 113, 79, 31, 49, 208, 0 }, }, - { { 190, 60, 15, 68, 249, 12, 0 }, - { 233, 147, 118, 25, 35, 165, 0 }, - { 24, 79, 145, 120, 30, 62, 1 }, - { 82, 226, 76, 55, 100, 203, 1 }, }, - { { 193, 39, 249, 24, 172, 4, 0 }, - { 120, 64, 163, 19, 84, 186, 0 }, - { 16, 26, 140, 79, 242, 65, 1 }, - { 46, 149, 100, 98, 129, 15, 0 }, }, - { { 194, 54, 103, 175, 248, 99, 1 }, - { 206, 53, 171, 193, 147, 175, 1 }, - { 227, 15, 250, 243, 54, 33, 1 }, - { 250, 228, 193, 234, 214, 57, 1 }, }, - { { 194, 202, 232, 228, 90, 50, 0 }, - { 160, 176, 201, 166, 25, 233, 1 }, - { 38, 45, 19, 139, 169, 161, 1 }, - { 203, 204, 50, 201, 134, 130, 1 }, }, - { { 198, 18, 22, 32, 228, 28, 0 }, - { 137, 113, 32, 16, 114, 108, 0 }, - { 28, 19, 130, 52, 36, 49, 1 }, - { 27, 39, 4, 2, 71, 72, 1 }, }, - { { 199, 229, 93, 208, 65, 150, 0 }, - { 241, 88, 91, 149, 28, 116, 0 }, - { 52, 193, 5, 221, 83, 241, 1 }, - { 23, 28, 84, 237, 13, 71, 1 }, }, - { { 202, 89, 204, 102, 248, 236, 0 }, - { 172, 187, 97, 22, 181, 165, 1 }, - { 27, 143, 179, 25, 205, 41, 1 }, - { 210, 214, 180, 67, 110, 154, 1 }, }, - { { 200, 251, 13, 58, 124, 119, 1 }, - { 62, 183, 10, 21, 220, 239, 1 }, - { 247, 31, 46, 88, 111, 137, 1 }, - { 251, 157, 212, 40, 118, 190, 0 }, }, - { { 204, 35, 191, 4, 244, 230, 0 }, - { 45, 90, 170, 19, 87, 45, 1 }, - { 51, 151, 144, 126, 226, 25, 1 }, - { 218, 117, 100, 42, 173, 90, 0 }, }, - { { 204, 185, 29, 222, 17, 77, 0 }, - { 53, 199, 82, 145, 189, 39, 0 }, - { 89, 68, 61, 220, 78, 153, 1 }, - { 114, 94, 196, 165, 113, 214, 0 }, }, - { { 214, 71, 53, 203, 221, 81, 1 }, - { 199, 84, 244, 197, 212, 239, 0 }, - { 197, 93, 233, 214, 113, 53, 1 }, - { 123, 149, 209, 151, 149, 113, 1 }, }, - { { 212, 80, 13, 82, 140, 243, 1 }, - { 55, 13, 108, 5, 208, 228, 1 }, - { 231, 152, 165, 88, 5, 21, 1 }, - { 147, 133, 208, 27, 88, 118, 0 }, }, - { { 214, 126, 50, 1, 136, 117, 0 }, - { 197, 197, 166, 84, 18, 232, 1 }, - { 87, 8, 192, 38, 63, 53, 1 }, - { 139, 164, 21, 50, 209, 209, 1 }, }, - { { 214, 239, 103, 48, 199, 69, 1 }, - { 215, 180, 183, 53, 94, 44, 0 }, - { 209, 113, 134, 115, 123, 181, 1 }, - { 26, 61, 86, 118, 150, 245, 1 }, }, - { { 217, 10, 193, 255, 8, 72, 0 }, - { 20, 162, 69, 195, 177, 186, 0 }, - { 9, 8, 127, 193, 168, 77, 1 }, - { 46, 198, 225, 209, 34, 148, 0 }, }, - { { 218, 68, 144, 181, 192, 149, 0 }, - { 208, 126, 36, 214, 17, 96, 0 }, - { 84, 129, 214, 132, 145, 45, 1 }, - { 3, 68, 53, 146, 63, 5, 1 }, }, - { { 218, 142, 240, 138, 31, 78, 1 }, - { 198, 194, 157, 178, 248, 171, 0 }, - { 185, 124, 40, 135, 184, 173, 1 }, - { 106, 143, 166, 220, 161, 177, 1 }, }, - { { 226, 186, 72, 154, 71, 244, 1 }, - { 182, 153, 19, 184, 216, 106, 1 }, - { 151, 241, 44, 137, 46, 163, 1 }, - { 171, 13, 142, 228, 76, 182, 1 }, }, - { { 226, 251, 142, 197, 152, 25, 0 }, - { 160, 133, 98, 206, 63, 237, 0 }, - { 76, 12, 209, 184, 239, 163, 1 }, - { 91, 254, 57, 163, 80, 130, 1 }, }, - { { 229, 62, 6, 191, 131, 16, 1 }, - { 83, 161, 50, 232, 147, 126, 0 }, - { 132, 96, 254, 176, 62, 83, 1 }, - { 63, 100, 139, 166, 66, 229, 0 }, }, - { { 230, 135, 176, 105, 180, 112, 0 }, - { 205, 96, 224, 74, 92, 107, 1 }, - { 7, 22, 203, 6, 240, 179, 1 }, - { 235, 29, 41, 3, 131, 89, 1 }, }, - { { 229, 161, 35, 223, 231, 210, 0 }, - { 29, 24, 250, 233, 223, 114, 0 }, - { 37, 243, 253, 226, 66, 211, 1 }, - { 39, 125, 203, 175, 140, 92, 0 }, }, - { { 228, 231, 74, 54, 176, 3, 0 }, - { 121, 36, 43, 12, 159, 41, 0 }, - { 96, 6, 182, 41, 115, 147, 1 }, - { 74, 124, 152, 106, 18, 79, 0 }, }, - { { 235, 25, 74, 181, 219, 227, 0 }, - { 180, 191, 57, 232, 23, 177, 1 }, - { 99, 237, 214, 169, 76, 107, 1 }, - { 198, 244, 11, 206, 126, 150, 1 }, }, - { { 235, 104, 214, 214, 135, 188, 0 }, - { 144, 202, 115, 190, 243, 116, 1 }, - { 30, 240, 181, 181, 139, 107, 1 }, - { 151, 103, 190, 231, 41, 132, 1 }, }, - { { 239, 76, 157, 25, 92, 242, 0 }, - { 245, 218, 8, 79, 80, 247, 1 }, - { 39, 157, 76, 92, 153, 123, 1 }, - { 247, 133, 121, 8, 45, 215, 1 }, }, - { { 240, 140, 65, 178, 161, 79, 1 }, - { 94, 164, 61, 153, 184, 32, 0 }, - { 249, 66, 166, 193, 24, 135, 1 }, - { 2, 14, 204, 222, 18, 189, 0 }, }, - { { 245, 42, 227, 102, 145, 91, 0 }, - { 5, 164, 255, 11, 179, 121, 0 }, - { 109, 68, 179, 99, 170, 87, 1 }, - { 79, 102, 232, 127, 146, 208, 0 }, }, - { { 247, 127, 207, 238, 89, 167, 0 }, - { 225, 189, 95, 159, 151, 191, 1 }, - { 114, 205, 59, 249, 255, 119, 1 }, - { 254, 244, 252, 253, 94, 195, 1 }, }, - { { 248, 218, 47, 9, 127, 235, 0 }, - { 44, 159, 156, 109, 122, 175, 1 }, - { 107, 255, 72, 122, 45, 143, 1 }, - { 250, 175, 91, 28, 252, 154, 0 }, }, - { { 252, 25, 236, 171, 9, 228, 1 }, - { 39, 171, 149, 218, 148, 166, 1 }, - { 147, 200, 106, 155, 204, 31, 1 }, - { 178, 148, 173, 212, 234, 242, 0 }, }, - { { 147, 75, 97, 136, 48, 21, 0 }, - { 136, 132, 133, 149, 4, 123, 0 }, - { 84, 6, 8, 195, 105, 100, 1 }, - { 111, 16, 84, 208, 144, 136, 1 }, }, - { { 200, 173, 102, 37, 128, 21, 1 }, - { 66, 166, 163, 80, 31, 100, 0 }, - { 212, 0, 210, 51, 90, 137, 1 }, - { 19, 124, 5, 98, 178, 161, 0 }, }, - { { 28, 218, 21, 111, 160, 160, 1 }, - { 11, 235, 100, 69, 137, 14, 1 }, - { 130, 130, 251, 84, 45, 156, 0 }, - { 184, 72, 209, 19, 107, 232, 0 }, }, - { { 35, 147, 244, 147, 165, 30, 0 }, - { 152, 65, 185, 218, 236, 92, 0 }, - { 60, 82, 228, 151, 228, 226, 0 }, - { 29, 27, 173, 206, 193, 12, 1 }, }, - { { 47, 88, 146, 189, 228, 140, 1 }, - { 155, 251, 32, 222, 99, 18, 0 }, - { 152, 147, 222, 164, 141, 122, 0 }, - { 36, 99, 61, 130, 111, 236, 1 }, }, - { { 67, 161, 247, 150, 104, 223, 0 }, - { 156, 92, 139, 147, 191, 212, 0 }, - { 125, 139, 52, 247, 194, 225, 0 }, - { 21, 254, 228, 232, 157, 28, 1 }, }, - { { 73, 80, 111, 179, 116, 206, 1 }, - { 62, 59, 137, 213, 242, 21, 0 }, - { 185, 151, 102, 251, 5, 73, 0 }, - { 84, 39, 213, 200, 238, 62, 0 }, }, - { { 82, 96, 94, 14, 152, 127, 0 }, - { 164, 68, 47, 20, 179, 199, 1 }, - { 127, 12, 184, 61, 3, 37, 0 }, - { 241, 230, 148, 122, 17, 18, 1 }, }, - { { 82, 145, 24, 227, 252, 161, 0 }, - { 168, 125, 100, 192, 220, 129, 1 }, - { 66, 159, 227, 140, 68, 165, 0 }, - { 192, 157, 129, 147, 95, 10, 1 }, }, - { { 101, 223, 133, 82, 42, 63, 1 }, - { 91, 133, 72, 63, 188, 220, 1 }, - { 254, 42, 37, 80, 253, 211, 0 }, - { 157, 158, 254, 9, 80, 237, 0 }, }, - { { 113, 72, 12, 215, 43, 160, 0 }, - { 56, 136, 84, 236, 145, 148, 1 }, - { 2, 234, 117, 152, 9, 71, 0 }, - { 148, 196, 155, 149, 8, 142, 0 }, }, - { { 142, 6, 96, 125, 160, 37, 0 }, - { 217, 38, 225, 80, 1, 42, 1 }, - { 82, 2, 223, 3, 48, 56, 1 }, - { 170, 64, 5, 67, 178, 77, 1 }, }, - { { 150, 170, 33, 3, 84, 112, 1 }, - { 135, 144, 134, 65, 200, 105, 1 }, - { 135, 21, 96, 66, 42, 180, 1 }, - { 203, 9, 193, 48, 132, 240, 1 }, }, - { { 161, 37, 174, 137, 93, 100, 1 }, - { 102, 16, 146, 218, 70, 183, 1 }, - { 147, 93, 72, 186, 210, 66, 1 }, - { 246, 177, 45, 164, 132, 51, 0 }, }, - { { 188, 234, 86, 10, 46, 231, 1 }, - { 15, 206, 15, 60, 202, 174, 1 }, - { 243, 186, 40, 53, 43, 158, 1 }, - { 186, 169, 158, 120, 57, 248, 0 }, }, - { { 194, 210, 70, 164, 139, 68, 0 }, - { 132, 33, 49, 180, 27, 172, 0 }, - { 17, 104, 146, 177, 37, 161, 1 }, - { 26, 236, 22, 198, 66, 16, 1 }, }, - { { 218, 226, 149, 139, 69, 176, 0 }, - { 128, 90, 22, 199, 216, 110, 1 }, - { 6, 209, 104, 212, 163, 173, 1 }, - { 187, 13, 241, 180, 45, 0, 1 }, }, - { { 236, 63, 99, 213, 29, 216, 0 }, - { 85, 139, 211, 201, 119, 233, 0 }, - { 13, 220, 85, 227, 126, 27, 1 }, - { 75, 247, 73, 229, 232, 213, 0 }, }, - { { 255, 105, 45, 60, 107, 15, 0 }, - { 185, 182, 158, 61, 53, 182, 0 }, - { 120, 107, 30, 90, 75, 127, 1 }, - { 54, 214, 94, 60, 182, 206, 1 }, }, - { { 0, 28, 79, 167, 70, 146, 1 }, - { 98, 185, 9, 225, 195, 68, 0 }, - { 164, 177, 114, 249, 28, 0, 0 }, - { 17, 97, 195, 200, 78, 163, 0 }, }, - { { 2, 24, 244, 93, 202, 150, 0 }, - { 144, 217, 233, 114, 1, 198, 0 }, - { 52, 169, 221, 23, 140, 32, 0 }, - { 49, 192, 39, 75, 205, 132, 1 }, }, - { { 3, 209, 163, 72, 235, 88, 0 }, - { 140, 17, 240, 39, 46, 210, 0 }, - { 13, 107, 137, 98, 197, 224, 0 }, - { 37, 186, 114, 7, 196, 24, 1 }, }, - { { 4, 27, 131, 253, 41, 154, 1 }, - { 27, 169, 88, 195, 39, 202, 0 }, - { 172, 202, 95, 224, 236, 16, 0 }, - { 41, 242, 97, 141, 74, 236, 0 }, }, - { { 9, 141, 142, 139, 148, 215, 1 }, - { 102, 142, 40, 210, 206, 87, 0 }, - { 245, 148, 232, 184, 216, 200, 0 }, - { 117, 57, 165, 138, 56, 179, 0 }, }, - { { 8, 163, 222, 26, 89, 139, 0 }, - { 48, 94, 27, 2, 174, 143, 0 }, - { 104, 205, 44, 61, 226, 136, 0 }, - { 120, 186, 160, 108, 61, 6, 0 }, }, - { { 11, 188, 12, 8, 32, 24, 0 }, - { 232, 131, 2, 0, 40, 86, 0 }, - { 12, 2, 8, 24, 30, 232, 0 }, - { 53, 10, 0, 32, 96, 139, 1 }, }, - { { 8, 180, 118, 44, 124, 199, 0 }, - { 76, 127, 139, 16, 75, 135, 0 }, - { 113, 159, 26, 55, 22, 136, 0 }, - { 112, 233, 4, 104, 255, 25, 0 }, }, - { { 8, 252, 181, 200, 85, 47, 1 }, - { 66, 215, 218, 151, 104, 7, 1 }, - { 250, 85, 9, 214, 159, 136, 0 }, - { 240, 11, 116, 173, 245, 161, 0 }, }, - { { 14, 22, 54, 84, 254, 34, 0 }, - { 217, 83, 232, 32, 67, 141, 1 }, - { 34, 63, 149, 54, 52, 56, 0 }, - { 216, 225, 2, 11, 229, 77, 1 }, }, - { { 18, 44, 177, 159, 7, 34, 1 }, - { 210, 192, 158, 227, 193, 2, 1 }, - { 162, 112, 124, 198, 154, 36, 0 }, - { 160, 65, 227, 188, 129, 165, 1 }, }, - { { 18, 69, 156, 171, 22, 232, 0 }, - { 228, 104, 4, 230, 228, 7, 1 }, - { 11, 180, 106, 156, 209, 36, 0 }, - { 240, 19, 179, 144, 11, 19, 1 }, }, - { { 19, 147, 126, 245, 174, 67, 1 }, - { 190, 101, 237, 224, 79, 156, 0 }, - { 225, 58, 215, 191, 100, 228, 0 }, - { 28, 249, 3, 219, 211, 62, 1 }, }, - { { 22, 41, 244, 18, 48, 140, 0 }, - { 153, 200, 135, 18, 164, 5, 0 }, - { 24, 134, 36, 23, 202, 52, 0 }, - { 80, 18, 164, 112, 137, 204, 1 }, }, - { { 21, 124, 103, 88, 122, 66, 0 }, - { 93, 145, 207, 37, 2, 151, 0 }, - { 33, 47, 13, 115, 31, 84, 0 }, - { 116, 160, 82, 121, 196, 221, 0 }, }, - { { 21, 204, 177, 89, 131, 214, 1 }, - { 87, 200, 252, 119, 8, 82, 0 }, - { 181, 224, 205, 70, 153, 212, 0 }, - { 37, 8, 119, 31, 137, 245, 0 }, }, - { { 23, 227, 47, 161, 221, 185, 0 }, - { 161, 60, 182, 197, 110, 221, 1 }, - { 78, 221, 194, 250, 99, 244, 0 }, - { 221, 187, 81, 182, 158, 66, 1 }, }, - { { 27, 70, 90, 142, 239, 10, 1 }, - { 234, 82, 61, 164, 227, 154, 0 }, - { 168, 123, 184, 173, 49, 108, 0 }, - { 44, 227, 146, 222, 37, 43, 1 }, }, - { { 27, 105, 78, 73, 179, 188, 1 }, - { 170, 138, 119, 116, 38, 87, 1 }, - { 158, 230, 201, 57, 75, 108, 0 }, - { 245, 50, 23, 119, 40, 170, 1 }, }, - { { 27, 196, 203, 219, 144, 138, 1 }, - { 242, 10, 109, 199, 170, 19, 0 }, - { 168, 132, 237, 233, 145, 236, 0 }, - { 100, 42, 241, 219, 40, 39, 1 }, }, - { { 31, 44, 109, 141, 119, 17, 1 }, - { 235, 150, 151, 225, 65, 87, 0 }, - { 196, 119, 88, 219, 26, 124, 0 }, - { 117, 65, 67, 244, 180, 235, 1 }, }, - { { 31, 87, 63, 15, 8, 234, 1 }, - { 231, 75, 140, 69, 167, 158, 1 }, - { 171, 136, 120, 126, 117, 124, 0 }, - { 188, 242, 209, 24, 233, 115, 1 }, }, - { { 28, 109, 100, 176, 216, 126, 1 }, - { 87, 178, 175, 148, 36, 197, 1 }, - { 191, 13, 134, 147, 91, 28, 0 }, - { 209, 146, 20, 250, 166, 245, 0 }, }, - { { 31, 214, 51, 233, 39, 78, 1 }, - { 207, 99, 220, 245, 106, 26, 0 }, - { 185, 114, 75, 230, 53, 252, 0 }, - { 44, 43, 87, 157, 227, 121, 1 }, }, - { { 31, 237, 94, 0, 105, 171, 1 }, - { 235, 222, 31, 4, 46, 148, 1 }, - { 234, 203, 0, 61, 91, 252, 0 }, - { 148, 186, 16, 124, 61, 235, 1 }, }, - { { 32, 25, 133, 43, 191, 166, 0 }, - { 8, 169, 56, 123, 196, 135, 1 }, - { 50, 254, 234, 80, 204, 2, 0 }, - { 240, 145, 239, 14, 74, 136, 0 }, }, - { { 34, 61, 51, 120, 7, 207, 0 }, - { 212, 237, 218, 57, 102, 2, 0 }, - { 121, 240, 15, 102, 94, 34, 0 }, - { 32, 51, 78, 45, 219, 149, 1 }, }, - { { 32, 99, 33, 28, 107, 49, 0 }, - { 24, 20, 146, 45, 5, 202, 1 }, - { 70, 107, 28, 66, 99, 2, 0 }, - { 169, 208, 90, 36, 148, 12, 0 }, }, - { { 34, 110, 87, 72, 118, 216, 1 }, - { 206, 216, 67, 45, 98, 79, 0 }, - { 141, 183, 9, 117, 59, 34, 0 }, - { 121, 35, 90, 97, 13, 185, 1 }, }, - { { 32, 116, 241, 178, 248, 194, 1 }, - { 94, 121, 171, 143, 128, 129, 0 }, - { 161, 143, 166, 199, 151, 2, 0 }, - { 64, 128, 248, 234, 207, 61, 0 }, }, - { { 33, 172, 61, 93, 237, 110, 0 }, - { 124, 208, 250, 89, 105, 150, 1 }, - { 59, 91, 221, 94, 26, 194, 0 }, - { 180, 203, 77, 47, 133, 159, 0 }, }, - { { 33, 195, 23, 29, 144, 62, 1 }, - { 18, 64, 40, 93, 47, 95, 1 }, - { 190, 4, 220, 116, 97, 194, 0 }, - { 253, 122, 93, 10, 1, 36, 0 }, }, - { { 39, 47, 226, 196, 67, 84, 0 }, - { 197, 144, 211, 186, 7, 88, 0 }, - { 21, 97, 17, 163, 250, 114, 0 }, - { 13, 112, 46, 229, 132, 209, 1 }, }, - { { 39, 159, 50, 224, 232, 133, 0 }, - { 201, 253, 224, 152, 14, 152, 0 }, - { 80, 139, 131, 166, 124, 242, 0 }, - { 12, 184, 12, 131, 223, 201, 1 }, }, - { { 38, 190, 33, 114, 154, 9, 1 }, - { 211, 165, 226, 41, 168, 137, 0 }, - { 200, 44, 167, 66, 62, 178, 0 }, - { 72, 138, 202, 35, 210, 229, 1 }, }, - { { 42, 3, 57, 247, 158, 125, 1 }, - { 182, 102, 224, 249, 229, 201, 1 }, - { 223, 60, 247, 206, 96, 42, 0 }, - { 201, 211, 207, 131, 179, 54, 1 }, }, - { { 43, 24, 147, 239, 72, 235, 0 }, - { 132, 255, 72, 203, 163, 146, 1 }, - { 107, 137, 123, 228, 140, 106, 0 }, - { 164, 226, 233, 137, 127, 144, 1 }, }, - { { 41, 20, 232, 100, 42, 8, 0 }, - { 104, 35, 193, 42, 33, 144, 0 }, - { 8, 42, 19, 11, 148, 74, 0 }, - { 4, 194, 42, 65, 226, 11, 0 }, }, - { { 41, 104, 166, 84, 120, 185, 0 }, - { 24, 158, 194, 14, 35, 213, 1 }, - { 78, 143, 21, 50, 139, 74, 0 }, - { 213, 226, 56, 33, 188, 140, 0 }, }, - { { 42, 193, 129, 37, 248, 55, 0 }, - { 136, 54, 40, 95, 13, 193, 1 }, - { 118, 15, 210, 64, 193, 170, 0 }, - { 193, 216, 125, 10, 54, 8, 1 }, }, - { { 40, 212, 32, 190, 102, 221, 1 }, - { 94, 63, 128, 188, 233, 66, 0 }, - { 221, 179, 62, 130, 21, 138, 0 }, - { 33, 75, 158, 128, 254, 61, 0 }, }, - { { 41, 251, 7, 40, 147, 64, 0 }, - { 4, 163, 50, 45, 14, 31, 0 }, - { 1, 100, 138, 112, 111, 202, 0 }, - { 124, 56, 90, 38, 98, 144, 0 }, }, - { { 45, 79, 27, 209, 68, 171, 0 }, - { 113, 222, 72, 205, 102, 24, 1 }, - { 106, 145, 69, 236, 121, 90, 0 }, - { 140, 51, 89, 137, 61, 199, 0 }, }, - { { 44, 77, 58, 93, 125, 209, 0 }, - { 125, 222, 208, 76, 71, 195, 0 }, - { 69, 223, 93, 46, 89, 26, 0 }, - { 97, 241, 25, 5, 189, 223, 0 }, }, - { { 46, 201, 163, 115, 80, 78, 1 }, - { 151, 178, 200, 95, 174, 1, 0 }, - { 185, 5, 103, 98, 201, 186, 0 }, - { 64, 58, 253, 9, 166, 244, 1 }, }, - { { 47, 242, 157, 56, 166, 39, 0 }, - { 185, 103, 42, 63, 72, 30, 1 }, - { 114, 50, 142, 92, 167, 250, 0 }, - { 188, 9, 126, 42, 115, 78, 1 }, }, - { { 51, 14, 242, 29, 118, 78, 0 }, - { 220, 208, 141, 122, 99, 27, 0 }, - { 57, 55, 92, 39, 184, 102, 0 }, - { 108, 99, 47, 88, 133, 157, 1 }, }, - { { 51, 46, 161, 171, 153, 4, 0 }, - { 192, 160, 182, 219, 128, 155, 0 }, - { 16, 76, 234, 194, 186, 102, 0 }, - { 108, 128, 237, 182, 130, 129, 1 }, }, - { { 49, 41, 200, 243, 224, 220, 1 }, - { 62, 184, 103, 218, 164, 80, 0 }, - { 157, 131, 231, 137, 202, 70, 0 }, - { 5, 18, 173, 243, 14, 190, 0 }, }, - { { 53, 0, 254, 245, 196, 8, 0 }, - { 49, 112, 229, 202, 99, 20, 0 }, - { 8, 17, 215, 191, 128, 86, 0 }, - { 20, 99, 41, 211, 135, 70, 0 }, }, - { { 55, 36, 110, 62, 36, 63, 0 }, - { 249, 36, 143, 24, 227, 86, 1 }, - { 126, 18, 62, 59, 18, 118, 0 }, - { 181, 99, 140, 120, 146, 79, 1 }, }, - { { 53, 81, 121, 197, 146, 92, 1 }, - { 39, 65, 229, 253, 37, 81, 0 }, - { 157, 36, 209, 207, 69, 86, 0 }, - { 69, 82, 95, 211, 193, 114, 0 }, }, - { { 54, 184, 189, 91, 81, 60, 0 }, - { 177, 209, 214, 91, 168, 71, 1 }, - { 30, 69, 109, 94, 142, 182, 0 }, - { 241, 10, 237, 53, 197, 198, 1 }, }, - { { 54, 221, 188, 202, 44, 119, 0 }, - { 237, 197, 204, 158, 204, 198, 1 }, - { 119, 26, 41, 158, 221, 182, 0 }, - { 177, 153, 188, 153, 209, 219, 1 }, }, - { { 55, 221, 249, 250, 116, 140, 0 }, - { 249, 249, 197, 159, 236, 19, 0 }, - { 24, 151, 47, 207, 221, 246, 0 }, - { 100, 27, 252, 209, 207, 207, 1 }, }, - { { 57, 8, 64, 158, 68, 97, 1 }, - { 22, 150, 5, 136, 193, 18, 1 }, - { 195, 17, 60, 129, 8, 78, 0 }, - { 164, 65, 136, 208, 52, 180, 0 }, }, - { { 59, 1, 93, 14, 177, 201, 1 }, - { 174, 78, 53, 9, 165, 23, 0 }, - { 201, 198, 184, 93, 64, 110, 0 }, - { 116, 82, 200, 86, 57, 58, 1 }, }, - { { 58, 14, 216, 225, 88, 0, 1 }, - { 226, 242, 69, 202, 0, 137, 0 }, - { 128, 13, 67, 141, 184, 46, 0 }, - { 72, 128, 41, 209, 39, 163, 1 }, }, - { { 56, 110, 40, 10, 241, 243, 1 }, - { 110, 158, 190, 12, 128, 75, 1 }, - { 231, 199, 168, 10, 59, 14, 0 }, - { 233, 0, 152, 62, 188, 187, 0 }, }, - { { 57, 97, 243, 168, 199, 88, 1 }, - { 6, 114, 183, 175, 102, 82, 0 }, - { 141, 113, 138, 231, 195, 78, 0 }, - { 37, 51, 122, 246, 167, 48, 0 }, }, - { { 57, 175, 5, 221, 138, 171, 1 }, - { 82, 142, 110, 233, 45, 158, 1 }, - { 234, 168, 221, 208, 122, 206, 0 }, - { 188, 218, 75, 187, 56, 165, 0 }, }, - { { 57, 172, 253, 140, 32, 166, 1 }, - { 106, 202, 143, 155, 9, 22, 1 }, - { 178, 130, 24, 223, 154, 206, 0 }, - { 180, 72, 108, 248, 169, 171, 0 }, }, - { { 56, 215, 227, 25, 189, 206, 1 }, - { 94, 11, 189, 95, 110, 139, 0 }, - { 185, 222, 204, 99, 245, 142, 0 }, - { 104, 187, 125, 94, 232, 61, 0 }, }, - { { 62, 29, 177, 174, 155, 223, 1 }, - { 199, 239, 188, 187, 165, 195, 0 }, - { 253, 236, 186, 198, 220, 62, 0 }, - { 97, 210, 238, 158, 251, 241, 1 }, }, - { { 63, 57, 54, 16, 131, 58, 1 }, - { 147, 195, 190, 40, 38, 84, 1 }, - { 174, 96, 132, 54, 78, 126, 0 }, - { 149, 50, 10, 62, 225, 228, 1 }, }, - { { 61, 68, 172, 103, 73, 121, 1 }, - { 103, 54, 212, 78, 161, 212, 1 }, - { 207, 73, 115, 26, 145, 94, 0 }, - { 149, 194, 185, 21, 182, 115, 0 }, }, - { { 62, 216, 120, 160, 212, 247, 1 }, - { 167, 255, 173, 156, 72, 65, 1 }, - { 247, 149, 130, 143, 13, 190, 0 }, - { 193, 9, 28, 218, 255, 242, 1 }, }, - { { 67, 45, 92, 111, 10, 140, 0 }, - { 224, 232, 67, 112, 181, 150, 0 }, - { 24, 168, 123, 29, 90, 97, 0 }, - { 52, 214, 135, 97, 11, 131, 1 }, }, - { { 66, 52, 3, 145, 156, 82, 1 }, - { 214, 1, 42, 193, 82, 193, 0 }, - { 165, 28, 196, 224, 22, 33, 0 }, - { 65, 165, 65, 170, 64, 53, 1 }, }, - { { 64, 59, 107, 130, 137, 239, 0 }, - { 36, 141, 187, 145, 182, 136, 1 }, - { 123, 200, 160, 235, 110, 1, 0 }, - { 136, 182, 196, 238, 216, 146, 0 }, }, - { { 67, 109, 145, 73, 70, 116, 0 }, - { 196, 208, 66, 119, 84, 82, 1 }, - { 23, 49, 73, 68, 219, 97, 0 }, - { 165, 21, 119, 33, 5, 145, 1 }, }, - { { 67, 151, 133, 107, 233, 44, 1 }, - { 202, 49, 112, 83, 188, 158, 1 }, - { 154, 75, 235, 80, 244, 225, 0 }, - { 188, 158, 229, 7, 70, 41, 1 }, }, - { { 71, 29, 159, 177, 209, 0, 1 }, - { 243, 241, 48, 195, 22, 21, 0 }, - { 128, 69, 198, 252, 220, 113, 0 }, - { 84, 52, 97, 134, 71, 231, 1 }, }, - { { 70, 43, 251, 166, 87, 121, 0 }, - { 165, 244, 147, 163, 247, 73, 1 }, - { 79, 117, 50, 239, 234, 49, 0 }, - { 201, 119, 226, 228, 151, 210, 1 }, }, - { { 70, 92, 73, 248, 0, 58, 1 }, - { 243, 161, 73, 133, 48, 66, 1 }, - { 174, 0, 15, 201, 29, 49, 0 }, - { 161, 6, 80, 201, 66, 231, 1 }, }, - { { 69, 118, 247, 32, 48, 38, 1 }, - { 75, 97, 139, 23, 18, 29, 1 }, - { 178, 6, 2, 119, 183, 81, 0 }, - { 220, 36, 116, 104, 195, 105, 0 }, }, - { { 70, 168, 40, 69, 154, 252, 0 }, - { 165, 136, 226, 112, 57, 193, 1 }, - { 31, 172, 209, 10, 10, 177, 0 }, - { 193, 206, 7, 35, 136, 210, 1 }, }, - { { 68, 160, 107, 94, 1, 10, 0 }, - { 49, 0, 219, 1, 187, 2, 0 }, - { 40, 64, 61, 107, 2, 145, 0 }, - { 32, 110, 192, 109, 128, 70, 0 }, }, - { { 69, 185, 78, 113, 53, 37, 0 }, - { 57, 165, 83, 80, 94, 21, 1 }, - { 82, 86, 71, 57, 78, 209, 0 }, - { 212, 61, 5, 101, 82, 206, 0 }, }, - { { 75, 113, 215, 160, 253, 197, 1 }, - { 142, 127, 51, 151, 86, 149, 0 }, - { 209, 223, 130, 245, 199, 105, 0 }, - { 84, 181, 116, 230, 127, 56, 1 }, }, - { { 79, 60, 121, 82, 108, 209, 1 }, - { 255, 223, 195, 1, 208, 208, 0 }, - { 197, 155, 37, 79, 30, 121, 0 }, - { 5, 133, 192, 97, 253, 255, 1 }, }, - { { 79, 178, 80, 33, 70, 98, 0 }, - { 133, 115, 11, 96, 88, 24, 1 }, - { 35, 49, 66, 5, 38, 249, 0 }, - { 140, 13, 3, 104, 103, 80, 1 }, }, - { { 79, 239, 177, 247, 108, 238, 1 }, - { 223, 250, 202, 215, 253, 152, 1 }, - { 187, 155, 119, 198, 251, 249, 0 }, - { 140, 223, 245, 169, 175, 253, 1 }, }, - { { 82, 75, 82, 250, 189, 204, 0 }, - { 156, 232, 117, 148, 246, 139, 0 }, - { 25, 222, 175, 165, 105, 37, 0 }, - { 104, 183, 148, 215, 11, 156, 1 }, }, - { { 83, 200, 244, 221, 123, 200, 1 }, - { 158, 216, 213, 230, 57, 151, 0 }, - { 137, 239, 93, 151, 137, 229, 0 }, - { 116, 206, 51, 213, 141, 188, 1 }, }, - { { 87, 5, 99, 141, 134, 48, 0 }, - { 193, 0, 165, 225, 87, 82, 1 }, - { 6, 48, 216, 227, 80, 117, 0 }, - { 165, 117, 67, 210, 128, 65, 1 }, }, - { { 85, 75, 225, 85, 227, 0, 0 }, - { 25, 144, 245, 103, 21, 24, 0 }, - { 0, 99, 213, 67, 233, 85, 0 }, - { 12, 84, 115, 87, 132, 204, 0 }, }, - { { 85, 138, 47, 175, 183, 98, 0 }, - { 45, 160, 188, 225, 219, 31, 1 }, - { 35, 118, 250, 250, 40, 213, 0 }, - { 252, 109, 195, 158, 130, 218, 0 }, }, - { { 84, 153, 49, 31, 160, 83, 0 }, - { 29, 197, 172, 65, 157, 66, 0 }, - { 101, 2, 252, 70, 76, 149, 0 }, - { 33, 92, 193, 26, 209, 220, 0 }, }, - { { 88, 13, 255, 122, 69, 176, 1 }, - { 114, 250, 213, 3, 214, 70, 1 }, - { 134, 209, 47, 127, 216, 13, 0 }, - { 177, 53, 224, 85, 175, 167, 0 }, }, - { { 90, 18, 17, 208, 247, 52, 1 }, - { 154, 83, 116, 177, 80, 73, 1 }, - { 150, 119, 133, 196, 36, 45, 0 }, - { 201, 5, 70, 151, 101, 44, 1 }, }, - { { 95, 17, 24, 22, 24, 164, 0 }, - { 177, 75, 4, 16, 149, 145, 1 }, - { 18, 140, 52, 12, 68, 125, 0 }, - { 196, 212, 132, 16, 105, 70, 1 }, }, - { { 93, 61, 87, 179, 227, 47, 0 }, - { 89, 247, 63, 241, 182, 20, 1 }, - { 122, 99, 230, 245, 94, 93, 0 }, - { 148, 54, 199, 254, 119, 205, 0 }, }, - { { 93, 74, 155, 244, 162, 166, 0 }, - { 57, 234, 108, 183, 19, 24, 1 }, - { 50, 162, 151, 236, 169, 93, 0 }, - { 140, 100, 118, 155, 43, 206, 0 }, }, - { { 94, 137, 78, 179, 16, 89, 0 }, - { 181, 166, 5, 192, 190, 69, 0 }, - { 77, 4, 102, 185, 72, 189, 0 }, - { 81, 62, 129, 208, 50, 214, 1 }, }, - { { 95, 182, 4, 116, 142, 30, 1 }, - { 211, 35, 110, 48, 121, 220, 0 }, - { 188, 56, 151, 16, 54, 253, 0 }, - { 29, 207, 6, 59, 98, 101, 1 }, }, - { { 95, 252, 162, 7, 10, 47, 1 }, - { 195, 135, 142, 118, 187, 144, 1 }, - { 250, 40, 112, 34, 159, 253, 0 }, - { 132, 238, 183, 56, 240, 225, 1 }, }, - { { 98, 20, 52, 163, 198, 43, 1 }, - { 194, 117, 168, 232, 240, 4, 1 }, - { 234, 49, 226, 150, 20, 35, 0 }, - { 144, 7, 139, 138, 215, 33, 1 }, }, - { { 96, 69, 249, 159, 75, 213, 0 }, - { 116, 92, 145, 255, 149, 194, 0 }, - { 85, 233, 124, 207, 209, 3, 0 }, - { 33, 212, 255, 196, 157, 23, 0 }, }, - { { 96, 94, 235, 202, 23, 75, 1 }, - { 102, 133, 217, 175, 242, 11, 0 }, - { 233, 116, 41, 235, 189, 3, 0 }, - { 104, 39, 250, 205, 208, 179, 0 }, }, - { { 97, 111, 101, 43, 244, 79, 0 }, - { 76, 180, 171, 93, 244, 31, 0 }, - { 121, 23, 234, 83, 123, 67, 0 }, - { 124, 23, 221, 106, 150, 153, 0 }, }, - { { 96, 111, 231, 237, 175, 53, 0 }, - { 72, 164, 243, 255, 87, 206, 1 }, - { 86, 122, 219, 243, 251, 3, 0 }, - { 185, 245, 127, 231, 146, 137, 0 }, }, - { { 98, 227, 54, 39, 167, 213, 0 }, - { 140, 108, 178, 124, 223, 76, 0 }, - { 85, 242, 242, 54, 99, 163, 0 }, - { 25, 125, 159, 38, 155, 24, 1 }, }, - { { 101, 50, 13, 146, 242, 6, 0 }, - { 57, 17, 42, 185, 144, 29, 0 }, - { 48, 39, 164, 216, 38, 83, 0 }, - { 92, 4, 206, 170, 68, 78, 0 }, }, - { { 101, 174, 116, 178, 81, 246, 0 }, - { 85, 248, 155, 152, 152, 93, 1 }, - { 55, 197, 38, 151, 58, 211, 0 }, - { 221, 12, 140, 236, 143, 213, 0 }, }, - { { 106, 37, 233, 73, 31, 2, 1 }, - { 226, 2, 219, 107, 84, 131, 0 }, - { 160, 124, 73, 75, 210, 43, 0 }, - { 96, 149, 107, 109, 160, 35, 1 }, }, - { { 105, 154, 22, 139, 171, 78, 0 }, - { 12, 195, 56, 248, 186, 158, 0 }, - { 57, 106, 232, 180, 44, 203, 0 }, - { 60, 174, 143, 142, 97, 152, 0 }, }, - { { 104, 159, 185, 186, 26, 80, 0 }, - { 116, 227, 128, 171, 156, 203, 0 }, - { 5, 44, 46, 206, 252, 139, 0 }, - { 105, 156, 234, 128, 227, 151, 0 }, }, - { { 104, 172, 27, 248, 226, 27, 1 }, - { 122, 246, 106, 169, 58, 66, 0 }, - { 236, 35, 143, 236, 26, 139, 0 }, - { 33, 46, 74, 171, 55, 175, 0 }, }, - { { 107, 204, 220, 27, 224, 85, 0 }, - { 252, 214, 33, 94, 152, 86, 0 }, - { 85, 3, 236, 29, 153, 235, 0 }, - { 53, 12, 189, 66, 53, 159, 1 }, }, - { { 110, 70, 68, 174, 42, 27, 1 }, - { 203, 38, 9, 172, 177, 206, 0 }, - { 236, 42, 58, 145, 49, 59, 0 }, - { 57, 198, 154, 200, 50, 105, 1 }, }, - { { 110, 91, 221, 156, 85, 145, 1 }, - { 179, 223, 17, 143, 85, 79, 0 }, - { 196, 213, 28, 221, 237, 59, 0 }, - { 121, 85, 120, 196, 125, 230, 1 }, }, - { { 110, 114, 103, 14, 62, 109, 0 }, - { 141, 7, 131, 61, 243, 143, 1 }, - { 91, 62, 56, 115, 39, 59, 0 }, - { 248, 231, 222, 96, 240, 88, 1 }, }, - { { 111, 134, 147, 35, 45, 171, 0 }, - { 201, 110, 24, 75, 250, 152, 1 }, - { 106, 218, 98, 100, 176, 251, 0 }, - { 140, 175, 233, 12, 59, 73, 1 }, }, - { { 108, 137, 244, 64, 218, 114, 1 }, - { 7, 210, 233, 42, 28, 197, 1 }, - { 167, 45, 129, 23, 200, 155, 0 }, - { 209, 156, 42, 75, 165, 240, 0 }, }, - { { 111, 156, 82, 187, 178, 211, 1 }, - { 223, 239, 41, 232, 154, 83, 0 }, - { 229, 166, 238, 165, 28, 251, 0 }, - { 101, 44, 139, 202, 123, 253, 1 }, }, - { { 111, 148, 127, 90, 90, 175, 1 }, - { 243, 95, 201, 57, 186, 151, 1 }, - { 250, 173, 45, 127, 20, 251, 0 }, - { 244, 174, 206, 73, 253, 103, 1 }, }, - { { 110, 168, 22, 55, 188, 108, 1 }, - { 159, 226, 34, 88, 251, 133, 1 }, - { 155, 30, 246, 52, 10, 187, 0 }, - { 208, 239, 141, 34, 35, 252, 1 }, }, - { { 110, 177, 138, 108, 23, 81, 0 }, - { 165, 39, 82, 42, 95, 67, 0 }, - { 69, 116, 27, 40, 198, 187, 0 }, - { 97, 125, 42, 37, 114, 82, 1 }, }, - { { 111, 200, 142, 200, 247, 162, 0 }, - { 169, 154, 120, 174, 90, 23, 1 }, - { 34, 247, 137, 184, 137, 251, 0 }, - { 244, 45, 58, 143, 44, 202, 1 }, }, - { { 115, 81, 80, 190, 35, 239, 0 }, - { 156, 109, 29, 188, 181, 18, 1 }, - { 123, 226, 62, 133, 69, 103, 0 }, - { 164, 86, 158, 220, 91, 28, 1 }, }, - { { 112, 139, 71, 240, 27, 189, 0 }, - { 16, 172, 85, 185, 62, 205, 1 }, - { 94, 236, 7, 241, 104, 135, 0 }, - { 217, 190, 78, 213, 26, 132, 0 }, }, - { { 112, 149, 37, 251, 26, 110, 1 }, - { 86, 33, 204, 249, 188, 135, 1 }, - { 187, 44, 111, 210, 84, 135, 0 }, - { 240, 158, 207, 153, 194, 53, 0 }, }, - { { 114, 158, 255, 114, 99, 90, 0 }, - { 252, 241, 221, 43, 186, 76, 0 }, - { 45, 99, 39, 127, 188, 167, 0 }, - { 25, 46, 234, 93, 199, 159, 1 }, }, - { { 112, 171, 227, 124, 150, 208, 1 }, - { 22, 168, 231, 43, 95, 75, 0 }, - { 133, 180, 159, 99, 234, 135, 0 }, - { 105, 125, 106, 115, 138, 180, 0 }, }, - { { 114, 245, 151, 82, 179, 142, 0 }, - { 216, 73, 126, 63, 190, 5, 0 }, - { 56, 230, 165, 116, 215, 167, 0 }, - { 80, 62, 254, 63, 73, 13, 1 }, }, - { { 118, 5, 164, 230, 226, 221, 0 }, - { 205, 60, 228, 186, 181, 68, 0 }, - { 93, 163, 179, 146, 208, 55, 0 }, - { 17, 86, 174, 147, 158, 89, 1 }, }, - { { 116, 17, 6, 76, 105, 165, 0 }, - { 9, 29, 84, 24, 23, 134, 1 }, - { 82, 203, 25, 48, 68, 23, 0 }, - { 176, 244, 12, 21, 92, 72, 0 }, }, - { { 118, 36, 17, 60, 244, 246, 1 }, - { 223, 120, 46, 25, 81, 67, 1 }, - { 183, 151, 158, 68, 18, 55, 0 }, - { 225, 69, 76, 58, 15, 125, 1 }, }, - { { 116, 101, 193, 88, 187, 101, 1 }, - { 95, 4, 119, 63, 20, 131, 1 }, - { 211, 110, 141, 65, 211, 23, 0 }, - { 224, 148, 126, 119, 16, 125, 0 }, }, - { { 119, 125, 91, 58, 188, 225, 0 }, - { 253, 237, 39, 13, 214, 147, 1 }, - { 67, 158, 174, 109, 95, 119, 0 }, - { 228, 181, 216, 114, 91, 223, 1 }, }, - { { 119, 182, 15, 188, 123, 59, 0 }, - { 249, 53, 30, 169, 59, 223, 1 }, - { 110, 111, 30, 248, 54, 247, 0 }, - { 253, 238, 74, 188, 86, 79, 1 }, }, - { { 118, 180, 133, 0, 61, 168, 1 }, - { 203, 9, 22, 11, 120, 133, 1 }, - { 138, 222, 0, 80, 150, 183, 0 }, - { 208, 143, 104, 52, 72, 105, 1 }, }, - { { 117, 238, 187, 75, 14, 98, 1 }, - { 103, 192, 206, 111, 218, 154, 1 }, - { 163, 56, 105, 110, 187, 215, 0 }, - { 172, 173, 251, 57, 129, 243, 0 }, }, - { { 118, 250, 208, 216, 178, 184, 0 }, - { 153, 201, 103, 174, 56, 75, 1 }, - { 14, 166, 141, 133, 175, 183, 0 }, - { 233, 14, 58, 243, 73, 204, 1 }, }, - { { 120, 75, 97, 130, 218, 8, 1 }, - { 2, 146, 165, 173, 180, 137, 0 }, - { 136, 45, 160, 195, 105, 15, 0 }, - { 72, 150, 218, 210, 164, 160, 0 }, }, - { { 122, 187, 251, 47, 52, 31, 1 }, - { 170, 231, 143, 91, 255, 75, 0 }, - { 252, 22, 122, 111, 238, 175, 0 }, - { 105, 127, 237, 120, 243, 170, 1 }, }, - { { 127, 39, 5, 215, 84, 100, 0 }, - { 213, 18, 70, 217, 213, 29, 1 }, - { 19, 21, 117, 208, 114, 127, 0 }, - { 220, 85, 205, 177, 36, 85, 1 }, }, - { { 125, 227, 180, 31, 248, 152, 0 }, - { 25, 90, 166, 78, 189, 223, 0 }, - { 12, 143, 252, 22, 227, 223, 0 }, - { 125, 222, 185, 50, 173, 76, 0 }, }, - { { 127, 237, 141, 135, 251, 207, 1 }, - { 239, 158, 62, 255, 189, 149, 0 }, - { 249, 239, 240, 216, 219, 255, 0 }, - { 84, 222, 255, 190, 60, 251, 1 }, }, - { { 126, 246, 82, 55, 17, 197, 0 }, - { 213, 111, 23, 92, 155, 9, 0 }, - { 81, 196, 118, 37, 55, 191, 0 }, - { 72, 108, 157, 116, 123, 85, 1 }, }, - { { 129, 31, 240, 203, 185, 104, 1 }, - { 78, 193, 241, 194, 164, 187, 1 }, - { 139, 78, 233, 135, 252, 64, 1 }, - { 238, 146, 161, 199, 193, 185, 0 }, }, - { { 128, 46, 234, 6, 149, 52, 0 }, - { 96, 128, 179, 18, 195, 105, 1 }, - { 22, 84, 176, 43, 186, 0, 1 }, - { 203, 97, 164, 102, 128, 131, 0 }, }, - { { 130, 73, 255, 59, 138, 203, 1 }, - { 182, 236, 169, 103, 166, 166, 0 }, - { 233, 168, 238, 127, 201, 32, 1 }, - { 50, 178, 243, 74, 155, 182, 1 }, }, - { { 129, 200, 212, 49, 219, 37, 0 }, - { 16, 244, 49, 118, 8, 181, 1 }, - { 82, 109, 198, 21, 137, 192, 1 }, - { 214, 136, 55, 70, 23, 132, 0 }, }, - { { 132, 43, 15, 88, 160, 122, 0 }, - { 61, 128, 106, 1, 38, 110, 1 }, - { 47, 2, 141, 120, 106, 16, 1 }, - { 187, 50, 64, 43, 0, 222, 0 }, }, - { { 133, 43, 127, 179, 216, 14, 0 }, - { 49, 240, 171, 209, 166, 189, 0 }, - { 56, 13, 230, 255, 106, 80, 1 }, - { 94, 178, 197, 234, 135, 198, 0 }, }, - { { 134, 32, 167, 236, 235, 192, 1 }, - { 143, 56, 242, 163, 3, 166, 0 }, - { 129, 235, 155, 242, 130, 48, 1 }, - { 50, 224, 98, 167, 142, 120, 1 }, }, - { { 134, 89, 195, 75, 94, 119, 1 }, - { 135, 149, 73, 119, 198, 227, 1 }, - { 247, 61, 105, 97, 205, 48, 1 }, - { 227, 177, 247, 73, 84, 240, 1 }, }, - { { 135, 96, 6, 117, 87, 9, 0 }, - { 145, 52, 82, 100, 99, 53, 0 }, - { 72, 117, 87, 48, 3, 112, 1 }, - { 86, 99, 19, 37, 22, 68, 1 }, }, - { { 132, 219, 148, 26, 247, 200, 0 }, - { 29, 217, 48, 38, 236, 47, 0 }, - { 9, 247, 172, 20, 237, 144, 1 }, - { 122, 27, 178, 6, 77, 220, 0 }, }, - { { 138, 22, 181, 10, 57, 125, 0 }, - { 204, 71, 144, 19, 160, 239, 1 }, - { 95, 78, 40, 86, 180, 40, 1 }, - { 251, 130, 228, 4, 241, 25, 1 }, }, - { { 138, 63, 78, 17, 183, 8, 0 }, - { 248, 131, 51, 96, 102, 45, 0 }, - { 8, 118, 196, 57, 126, 40, 1 }, - { 90, 51, 3, 102, 96, 143, 1 }, }, - { { 137, 70, 134, 138, 98, 190, 0 }, - { 72, 26, 8, 182, 162, 126, 1 }, - { 62, 163, 40, 176, 177, 72, 1 }, - { 191, 34, 182, 136, 44, 9, 0 }, }, - { { 139, 122, 129, 163, 127, 219, 0 }, - { 140, 191, 26, 231, 224, 249, 0 }, - { 109, 255, 98, 192, 175, 104, 1 }, - { 79, 131, 243, 172, 126, 152, 1 }, }, - { { 137, 134, 220, 73, 174, 214, 0 }, - { 108, 74, 105, 114, 72, 254, 0 }, - { 53, 186, 201, 29, 176, 200, 1 }, - { 63, 137, 39, 75, 41, 27, 0 }, }, - { { 137, 153, 52, 70, 112, 178, 1 }, - { 10, 219, 200, 0, 141, 117, 1 }, - { 166, 135, 49, 22, 76, 200, 1 }, - { 215, 88, 128, 9, 237, 168, 0 }, }, - { { 139, 205, 202, 224, 85, 9, 1 }, - { 226, 182, 81, 134, 110, 49, 0 }, - { 200, 85, 3, 169, 217, 232, 1 }, - { 70, 59, 48, 197, 54, 163, 1 }, }, - { { 139, 222, 241, 118, 82, 104, 1 }, - { 214, 243, 193, 39, 169, 57, 1 }, - { 139, 37, 55, 71, 189, 232, 1 }, - { 206, 74, 242, 65, 231, 181, 1 }, }, - { { 142, 18, 98, 26, 198, 81, 1 }, - { 151, 23, 161, 32, 194, 106, 0 }, - { 197, 49, 172, 35, 36, 56, 1 }, - { 43, 33, 130, 66, 244, 116, 1 }, }, - { { 141, 46, 148, 181, 204, 168, 0 }, - { 81, 250, 34, 194, 97, 188, 1 }, - { 10, 153, 214, 148, 186, 88, 1 }, - { 158, 195, 33, 162, 47, 197, 0 }, }, - { { 140, 75, 185, 11, 82, 34, 0 }, - { 33, 210, 136, 103, 132, 43, 1 }, - { 34, 37, 104, 78, 233, 24, 1 }, - { 234, 16, 243, 8, 165, 194, 0 }, }, - { { 141, 153, 201, 208, 216, 171, 1 }, - { 51, 159, 105, 131, 44, 177, 1 }, - { 234, 141, 133, 201, 204, 216, 1 }, - { 198, 154, 96, 203, 124, 230, 0 }, }, - { { 144, 17, 129, 73, 60, 185, 1 }, - { 10, 13, 68, 67, 100, 227, 1 }, - { 206, 158, 73, 64, 196, 4, 1 }, - { 227, 147, 97, 17, 88, 40, 0 }, }, - { { 146, 45, 168, 84, 94, 84, 1 }, - { 246, 144, 198, 50, 69, 225, 0 }, - { 149, 61, 21, 10, 218, 36, 1 }, - { 67, 209, 38, 49, 132, 183, 1 }, }, - { { 144, 78, 120, 161, 56, 250, 1 }, - { 110, 232, 141, 196, 32, 233, 1 }, - { 175, 142, 66, 143, 57, 4, 1 }, - { 203, 130, 17, 216, 139, 187, 0 }, }, - { { 144, 151, 90, 16, 127, 241, 0 }, - { 124, 93, 21, 32, 78, 233, 1 }, - { 71, 255, 4, 45, 116, 132, 1 }, - { 203, 185, 2, 84, 93, 31, 0 }, }, - { { 144, 179, 61, 187, 100, 42, 0 }, - { 56, 113, 142, 193, 236, 46, 1 }, - { 42, 19, 110, 222, 102, 132, 1 }, - { 186, 27, 193, 184, 199, 14, 0 }, }, - { { 147, 192, 227, 79, 19, 241, 0 }, - { 132, 12, 213, 103, 139, 115, 1 }, - { 71, 228, 121, 99, 129, 228, 1 }, - { 231, 104, 243, 85, 152, 16, 1 }, }, - { { 151, 73, 34, 81, 12, 38, 0 }, - { 145, 128, 204, 84, 70, 176, 1 }, - { 50, 24, 69, 34, 73, 116, 1 }, - { 134, 177, 21, 25, 128, 196, 1 }, }, - { { 151, 74, 87, 164, 6, 195, 0 }, - { 133, 236, 13, 165, 67, 60, 0 }, - { 97, 176, 18, 245, 41, 116, 1 }, - { 30, 97, 82, 216, 27, 208, 1 }, }, - { { 150, 115, 104, 38, 246, 150, 1 }, - { 171, 57, 175, 52, 197, 105, 0 }, - { 180, 183, 178, 11, 103, 52, 1 }, - { 75, 81, 150, 122, 206, 106, 1 }, }, - { { 149, 138, 223, 218, 96, 3, 1 }, - { 59, 212, 77, 131, 138, 62, 0 }, - { 224, 3, 45, 253, 168, 212, 1 }, - { 62, 40, 224, 217, 21, 238, 0 }, }, - { { 150, 175, 46, 35, 58, 45, 0 }, - { 233, 164, 134, 112, 174, 173, 1 }, - { 90, 46, 98, 58, 122, 180, 1 }, - { 218, 186, 135, 48, 146, 203, 1 }, }, - { { 155, 7, 68, 229, 222, 47, 0 }, - { 192, 54, 109, 240, 101, 189, 1 }, - { 122, 61, 211, 145, 112, 108, 1 }, - { 222, 211, 7, 219, 54, 1, 1 }, }, - { { 152, 75, 88, 148, 206, 180, 0 }, - { 48, 218, 37, 180, 69, 232, 1 }, - { 22, 185, 148, 141, 105, 12, 1 }, - { 139, 209, 22, 210, 45, 134, 0 }, }, - { { 153, 122, 202, 55, 11, 119, 1 }, - { 54, 167, 31, 118, 131, 248, 1 }, - { 247, 104, 118, 41, 175, 76, 1 }, - { 143, 224, 183, 124, 114, 182, 0 }, }, - { { 156, 0, 144, 208, 133, 65, 1 }, - { 23, 70, 116, 130, 64, 32, 0 }, - { 193, 80, 133, 132, 128, 28, 1 }, - { 2, 1, 32, 151, 49, 116, 0 }, }, - { { 157, 117, 4, 69, 227, 242, 1 }, - { 79, 27, 126, 100, 5, 116, 1 }, - { 167, 227, 209, 16, 87, 92, 1 }, - { 151, 80, 19, 63, 108, 121, 0 }, }, - { { 160, 66, 244, 31, 20, 137, 1 }, - { 18, 76, 129, 78, 225, 47, 0 }, - { 200, 148, 124, 23, 161, 2, 1 }, - { 122, 67, 185, 64, 153, 36, 0 }, }, - { { 160, 154, 32, 41, 137, 97, 0 }, - { 4, 165, 176, 72, 8, 170, 1 }, - { 67, 72, 202, 2, 44, 130, 1 }, - { 170, 136, 9, 6, 210, 144, 0 }, }, - { { 161, 151, 65, 181, 6, 20, 0 }, - { 80, 33, 1, 249, 77, 120, 0 }, - { 20, 48, 86, 193, 116, 194, 1 }, - { 15, 89, 79, 192, 66, 5, 0 }, }, - { { 162, 199, 179, 237, 218, 219, 0 }, - { 196, 124, 232, 239, 47, 235, 0 }, - { 109, 173, 219, 230, 241, 162, 1 }, - { 107, 250, 123, 139, 159, 17, 1 }, }, - { { 163, 237, 115, 3, 171, 156, 0 }, - { 200, 200, 179, 125, 174, 240, 0 }, - { 28, 234, 224, 103, 91, 226, 1 }, - { 7, 186, 223, 102, 137, 137, 1 }, }, - { { 164, 14, 153, 123, 197, 24, 0 }, - { 113, 240, 112, 75, 224, 106, 0 }, - { 12, 81, 239, 76, 184, 18, 1 }, - { 43, 3, 233, 7, 7, 199, 0 }, }, - { { 166, 46, 211, 181, 170, 239, 0 }, - { 221, 236, 43, 251, 35, 168, 1 }, - { 123, 170, 214, 229, 186, 50, 1 }, - { 138, 226, 111, 234, 27, 221, 1 }, }, - { { 166, 72, 83, 81, 97, 91, 1 }, - { 159, 212, 89, 77, 34, 96, 0 }, - { 237, 67, 69, 101, 9, 50, 1 }, - { 3, 34, 89, 77, 21, 252, 1 }, }, - { { 166, 88, 46, 241, 183, 120, 1 }, - { 191, 161, 240, 236, 98, 101, 1 }, - { 143, 118, 199, 186, 13, 50, 1 }, - { 211, 35, 27, 135, 194, 254, 1 }, }, - { { 167, 125, 62, 203, 3, 105, 0 }, - { 229, 197, 210, 236, 166, 54, 1 }, - { 75, 96, 105, 190, 95, 114, 1 }, - { 182, 50, 155, 165, 209, 211, 1 }, }, - { { 165, 183, 40, 12, 100, 157, 0 }, - { 105, 29, 130, 24, 109, 122, 0 }, - { 92, 147, 24, 10, 118, 210, 1 }, - { 47, 91, 12, 32, 220, 75, 0 }, }, - { { 164, 207, 91, 78, 212, 244, 0 }, - { 101, 216, 97, 29, 207, 107, 1 }, - { 23, 149, 185, 109, 121, 146, 1 }, - { 235, 121, 220, 67, 13, 211, 0 }, }, - { { 171, 21, 211, 205, 48, 133, 0 }, - { 200, 79, 65, 219, 7, 51, 0 }, - { 80, 134, 89, 229, 212, 106, 1 }, - { 102, 112, 109, 193, 121, 9, 1 }, }, - { { 171, 47, 103, 30, 208, 8, 1 }, - { 210, 146, 163, 9, 167, 63, 0 }, - { 136, 5, 188, 115, 122, 106, 1 }, - { 126, 114, 200, 98, 164, 165, 1 }, }, - { { 168, 43, 177, 100, 80, 17, 1 }, - { 2, 246, 194, 11, 5, 105, 0 }, - { 196, 5, 19, 70, 234, 10, 1 }, - { 75, 80, 104, 33, 183, 160, 0 }, }, - { { 168, 67, 58, 121, 199, 250, 1 }, - { 54, 122, 248, 108, 102, 106, 1 }, - { 175, 241, 207, 46, 97, 10, 1 }, - { 171, 51, 27, 15, 175, 54, 0 }, }, - { { 168, 95, 145, 245, 169, 81, 0 }, - { 92, 231, 112, 207, 5, 232, 0 }, - { 69, 74, 215, 196, 253, 10, 1 }, - { 11, 208, 121, 135, 115, 157, 0 }, }, - { { 168, 126, 123, 132, 128, 94, 1 }, - { 102, 195, 171, 157, 35, 104, 0 }, - { 189, 0, 144, 239, 63, 10, 1 }, - { 11, 98, 92, 234, 225, 179, 0 }, }, - { { 168, 132, 121, 195, 96, 56, 1 }, - { 106, 82, 193, 201, 168, 96, 1 }, - { 142, 3, 97, 207, 16, 138, 1 }, - { 131, 10, 201, 193, 165, 43, 0 }, }, - { { 171, 163, 68, 207, 130, 112, 0 }, - { 132, 2, 99, 232, 141, 126, 1 }, - { 7, 32, 249, 145, 98, 234, 1 }, - { 191, 88, 139, 227, 32, 16, 1 }, }, - { { 171, 230, 49, 247, 179, 118, 0 }, - { 220, 98, 250, 253, 137, 121, 1 }, - { 55, 102, 247, 198, 51, 234, 1 }, - { 207, 72, 223, 175, 163, 29, 1 }, }, - { { 172, 22, 16, 22, 73, 151, 0 }, - { 81, 95, 24, 24, 129, 232, 0 }, - { 116, 201, 52, 4, 52, 26, 1 }, - { 11, 192, 140, 12, 125, 69, 0 }, }, - { { 174, 39, 216, 18, 235, 36, 1 }, - { 251, 82, 51, 58, 132, 168, 1 }, - { 146, 107, 164, 13, 242, 58, 1 }, - { 138, 144, 174, 102, 37, 111, 1 }, }, - { { 175, 59, 230, 2, 186, 159, 1 }, - { 139, 143, 171, 58, 166, 253, 0 }, - { 252, 174, 160, 51, 238, 122, 1 }, - { 95, 178, 174, 106, 248, 232, 1 }, }, - { { 174, 70, 26, 234, 137, 71, 1 }, - { 231, 102, 120, 156, 130, 170, 0 }, - { 241, 72, 171, 172, 49, 58, 1 }, - { 42, 160, 156, 143, 51, 115, 1 }, }, - { { 173, 66, 113, 218, 119, 159, 1 }, - { 27, 94, 217, 189, 224, 123, 0 }, - { 252, 247, 45, 199, 33, 90, 1 }, - { 111, 3, 222, 205, 189, 108, 0 }, }, - { { 173, 88, 23, 206, 43, 193, 1 }, - { 15, 207, 80, 173, 131, 182, 0 }, - { 193, 234, 57, 244, 13, 90, 1 }, - { 54, 224, 218, 133, 121, 248, 0 }, }, - { { 172, 151, 210, 208, 179, 77, 0 }, - { 93, 71, 113, 186, 46, 41, 0 }, - { 89, 102, 133, 165, 244, 154, 1 }, - { 74, 58, 46, 199, 113, 93, 0 }, }, - { { 173, 190, 197, 66, 11, 202, 0 }, - { 69, 139, 91, 43, 168, 188, 0 }, - { 41, 232, 33, 81, 190, 218, 1 }, - { 30, 138, 234, 109, 104, 209, 0 }, }, - { { 175, 250, 80, 85, 120, 101, 0 }, - { 157, 215, 67, 92, 9, 185, 1 }, - { 83, 15, 85, 5, 47, 250, 1 }, - { 206, 200, 29, 97, 117, 220, 1 }, }, - { { 176, 31, 206, 26, 12, 146, 1 }, - { 114, 137, 13, 10, 198, 238, 0 }, - { 164, 152, 44, 57, 252, 6, 1 }, - { 59, 177, 168, 88, 72, 167, 0 }, }, - { { 177, 112, 134, 190, 143, 137, 0 }, - { 16, 45, 54, 174, 227, 182, 0 }, - { 72, 248, 190, 176, 135, 70, 1 }, - { 54, 227, 186, 182, 90, 4, 0 }, }, - { { 183, 222, 54, 61, 41, 2, 0 }, - { 217, 225, 156, 76, 11, 190, 0 }, - { 32, 74, 94, 54, 61, 246, 1 }, - { 62, 232, 25, 28, 195, 205, 1 }, }, - { { 180, 229, 14, 234, 89, 126, 0 }, - { 101, 48, 94, 156, 174, 231, 1 }, - { 63, 77, 43, 184, 83, 150, 1 }, - { 243, 186, 156, 189, 6, 83, 0 }, }, - { { 186, 59, 44, 235, 91, 138, 0 }, - { 160, 187, 222, 232, 164, 175, 0 }, - { 40, 237, 107, 154, 110, 46, 1 }, - { 122, 146, 139, 189, 238, 130, 1 }, }, - { { 187, 123, 82, 243, 209, 20, 0 }, - { 144, 243, 119, 220, 134, 121, 0 }, - { 20, 69, 231, 165, 111, 110, 1 }, - { 79, 48, 157, 247, 103, 132, 1 }, }, - { { 186, 116, 182, 71, 89, 86, 1 }, - { 198, 83, 222, 94, 131, 229, 0 }, - { 181, 77, 113, 54, 151, 46, 1 }, - { 83, 224, 189, 61, 229, 49, 1 }, }, - { { 186, 139, 73, 97, 25, 111, 1 }, - { 166, 166, 93, 89, 44, 169, 1 }, - { 251, 76, 67, 73, 104, 174, 1 }, - { 202, 154, 77, 93, 50, 178, 1 }, }, - { { 187, 152, 233, 200, 28, 89, 0 }, - { 164, 135, 197, 139, 104, 243, 0 }, - { 77, 28, 9, 203, 140, 238, 1 }, - { 103, 139, 104, 209, 240, 146, 1 }, }, - { { 188, 30, 177, 81, 156, 163, 1 }, - { 83, 207, 236, 75, 64, 169, 1 }, - { 226, 156, 197, 70, 188, 30, 1 }, - { 202, 129, 105, 27, 249, 229, 0 }, }, - { { 188, 42, 52, 17, 27, 68, 1 }, - { 23, 194, 150, 120, 0, 173, 0 }, - { 145, 108, 68, 22, 42, 30, 1 }, - { 90, 128, 15, 52, 161, 244, 0 }, }, - { { 189, 81, 101, 27, 30, 213, 0 }, - { 21, 15, 133, 125, 196, 247, 0 }, - { 85, 188, 108, 83, 69, 94, 1 }, - { 119, 145, 223, 80, 248, 84, 0 }, }, - { { 190, 112, 117, 173, 51, 180, 1 }, - { 139, 107, 151, 253, 1, 103, 1 }, - { 150, 230, 90, 215, 7, 62, 1 }, - { 243, 64, 95, 244, 235, 104, 1 }, }, - { { 189, 255, 164, 161, 70, 198, 1 }, - { 71, 187, 142, 254, 76, 60, 0 }, - { 177, 177, 66, 146, 255, 222, 1 }, - { 30, 25, 63, 184, 238, 241, 0 }, }, - { { 193, 4, 151, 159, 155, 192, 0 }, - { 84, 72, 48, 227, 147, 183, 0 }, - { 1, 236, 252, 244, 144, 65, 1 }, - { 118, 228, 227, 134, 9, 21, 0 }, }, - { { 193, 30, 33, 36, 254, 38, 1 }, - { 74, 177, 168, 49, 81, 185, 1 }, - { 178, 63, 146, 66, 60, 65, 1 }, - { 206, 197, 70, 10, 198, 169, 0 }, }, - { { 192, 237, 72, 64, 106, 165, 0 }, - { 104, 156, 67, 52, 28, 160, 1 }, - { 82, 171, 1, 9, 91, 129, 1 }, - { 130, 156, 22, 97, 28, 139, 0 }, }, - { { 192, 234, 184, 166, 4, 229, 0 }, - { 36, 236, 130, 150, 217, 40, 1 }, - { 83, 144, 50, 142, 171, 129, 1 }, - { 138, 77, 180, 160, 155, 146, 0 }, }, - { { 198, 87, 250, 41, 77, 82, 1 }, - { 231, 113, 153, 70, 86, 234, 0 }, - { 165, 89, 74, 47, 245, 49, 1 }, - { 43, 181, 49, 76, 199, 115, 1 }, }, - { { 200, 111, 63, 193, 206, 104, 0 }, - { 100, 210, 226, 229, 118, 172, 1 }, - { 11, 57, 193, 254, 123, 9, 1 }, - { 154, 183, 83, 163, 165, 147, 0 }, }, - { { 200, 99, 86, 204, 12, 4, 1 }, - { 2, 66, 67, 148, 87, 174, 0 }, - { 144, 24, 25, 181, 99, 9, 1 }, - { 58, 245, 20, 225, 33, 32, 0 }, }, - { { 201, 215, 21, 97, 151, 171, 1 }, - { 66, 111, 120, 101, 124, 61, 1 }, - { 234, 244, 195, 84, 117, 201, 1 }, - { 222, 31, 83, 15, 123, 33, 0 }, }, - { { 203, 227, 118, 18, 26, 242, 1 }, - { 150, 74, 139, 36, 158, 253, 1 }, - { 167, 172, 36, 55, 99, 233, 1 }, - { 223, 188, 146, 104, 169, 52, 1 }, }, - { { 204, 23, 188, 202, 55, 164, 1 }, - { 107, 75, 208, 178, 212, 47, 1 }, - { 146, 246, 41, 158, 244, 25, 1 }, - { 250, 21, 166, 133, 233, 107, 0 }, }, - { { 204, 223, 166, 39, 145, 190, 0 }, - { 65, 171, 184, 86, 191, 109, 1 }, - { 62, 196, 242, 50, 253, 153, 1 }, - { 219, 126, 181, 14, 234, 193, 0 }, }, - { { 204, 235, 235, 67, 36, 93, 0 }, - { 45, 134, 195, 87, 254, 104, 0 }, - { 93, 18, 97, 107, 235, 153, 1 }, - { 11, 63, 245, 97, 176, 218, 0 }, }, - { { 209, 53, 155, 82, 5, 119, 0 }, - { 116, 69, 94, 19, 214, 112, 1 }, - { 119, 80, 37, 108, 214, 69, 1 }, - { 135, 53, 228, 61, 81, 23, 0 }, }, - { { 209, 91, 212, 112, 60, 106, 0 }, - { 28, 225, 77, 6, 116, 189, 1 }, - { 43, 30, 7, 21, 237, 69, 1 }, - { 222, 151, 48, 89, 67, 156, 0 }, }, - { { 215, 26, 117, 66, 163, 79, 1 }, - { 143, 197, 253, 49, 176, 60, 0 }, - { 249, 98, 161, 87, 44, 117, 1 }, - { 30, 6, 198, 95, 209, 248, 1 }, }, - { { 215, 230, 123, 63, 234, 215, 1 }, - { 255, 124, 175, 117, 155, 250, 0 }, - { 245, 171, 254, 111, 51, 245, 1 }, - { 47, 236, 215, 122, 159, 127, 1 }, }, - { { 219, 2, 186, 238, 81, 189, 1 }, - { 162, 126, 212, 146, 179, 123, 1 }, - { 222, 197, 59, 174, 160, 109, 1 }, - { 239, 102, 164, 149, 191, 34, 1 }, }, - { { 216, 126, 223, 70, 165, 187, 1 }, - { 106, 207, 127, 7, 243, 108, 1 }, - { 238, 210, 177, 125, 191, 13, 1 }, - { 155, 103, 240, 127, 121, 171, 0 }, }, - { { 216, 131, 133, 71, 132, 38, 1 }, - { 2, 2, 108, 83, 221, 44, 1 }, - { 178, 16, 241, 80, 224, 141, 1 }, - { 154, 93, 229, 27, 32, 32, 0 }, }, - { { 218, 189, 22, 192, 207, 231, 0 }, - { 196, 223, 126, 176, 94, 164, 1 }, - { 115, 249, 129, 180, 94, 173, 1 }, - { 146, 189, 6, 191, 125, 145, 1 }, }, - { { 219, 226, 77, 128, 236, 124, 1 }, - { 174, 18, 39, 149, 120, 252, 1 }, - { 159, 27, 128, 217, 35, 237, 1 }, - { 159, 143, 84, 242, 36, 58, 1 }, }, - { { 217, 244, 154, 237, 44, 69, 0 }, - { 108, 103, 70, 214, 91, 178, 0 }, - { 81, 26, 91, 172, 151, 205, 1 }, - { 38, 237, 53, 177, 115, 27, 0 }, }, - { { 222, 24, 187, 178, 78, 206, 1 }, - { 183, 251, 140, 179, 242, 160, 0 }, - { 185, 185, 38, 238, 140, 61, 1 }, - { 2, 167, 230, 152, 239, 246, 1 }, }, - { { 221, 25, 226, 31, 178, 162, 1 }, - { 27, 139, 173, 98, 151, 51, 1 }, - { 162, 166, 252, 35, 204, 93, 1 }, - { 230, 116, 163, 90, 232, 236, 0 }, }, - { { 222, 44, 65, 181, 149, 43, 0 }, - { 209, 166, 63, 193, 113, 33, 1 }, - { 106, 84, 214, 193, 26, 61, 1 }, - { 194, 71, 65, 254, 50, 197, 1 }, }, - { { 220, 75, 143, 150, 13, 97, 0 }, - { 53, 134, 20, 135, 215, 172, 1 }, - { 67, 88, 52, 248, 233, 29, 1 }, - { 154, 245, 240, 148, 48, 214, 0 }, }, - { { 221, 148, 173, 142, 18, 115, 1 }, - { 103, 7, 140, 163, 153, 119, 1 }, - { 231, 36, 56, 218, 148, 221, 1 }, - { 247, 76, 226, 152, 240, 115, 0 }, }, - { { 221, 209, 152, 178, 105, 248, 1 }, - { 63, 123, 20, 134, 188, 240, 1 }, - { 143, 203, 38, 140, 197, 221, 1 }, - { 135, 158, 176, 148, 111, 126, 0 }, }, - { { 225, 16, 129, 210, 125, 199, 0 }, - { 28, 29, 88, 155, 208, 177, 0 }, - { 113, 223, 37, 192, 132, 67, 1 }, - { 70, 133, 236, 141, 92, 28, 0 }, }, - { { 226, 29, 244, 60, 230, 69, 1 }, - { 222, 245, 161, 58, 85, 38, 0 }, - { 209, 51, 158, 23, 220, 35, 1 }, - { 50, 85, 46, 66, 215, 189, 1 }, }, - { { 227, 42, 142, 26, 117, 17, 0 }, - { 184, 148, 18, 10, 210, 127, 0 }, - { 68, 87, 44, 56, 170, 99, 1 }, - { 127, 37, 168, 36, 20, 142, 1 }, }, - { { 230, 127, 34, 189, 228, 63, 1 }, - { 219, 181, 170, 220, 119, 106, 1 }, - { 254, 19, 222, 162, 127, 51, 1 }, - { 171, 119, 29, 170, 214, 237, 1 }, }, - { { 230, 201, 244, 50, 47, 175, 1 }, - { 155, 236, 153, 62, 252, 164, 1 }, - { 250, 250, 38, 23, 201, 179, 1 }, - { 146, 159, 190, 76, 155, 236, 1 }, }, - { { 233, 65, 95, 6, 96, 115, 0 }, - { 44, 86, 9, 13, 151, 116, 1 }, - { 103, 3, 48, 125, 65, 75, 1 }, - { 151, 116, 216, 72, 53, 26, 0 }, }, - { { 232, 162, 221, 84, 147, 113, 0 }, - { 52, 70, 115, 43, 25, 109, 1 }, - { 71, 100, 149, 93, 162, 139, 1 }, - { 219, 76, 106, 103, 49, 22, 0 }, }, - { { 232, 216, 146, 243, 185, 171, 1 }, - { 26, 239, 120, 206, 186, 161, 1 }, - { 234, 206, 231, 164, 141, 139, 1 }, - { 194, 174, 185, 143, 123, 172, 0 }, }, - { { 234, 224, 242, 13, 25, 46, 0 }, - { 128, 66, 155, 94, 59, 163, 1 }, - { 58, 76, 88, 39, 131, 171, 1 }, - { 226, 238, 61, 108, 161, 0, 1 }, }, - { { 237, 183, 135, 120, 221, 244, 0 }, - { 85, 59, 114, 27, 94, 255, 1 }, - { 23, 221, 143, 112, 246, 219, 1 }, - { 255, 189, 108, 39, 110, 85, 0 }, }, - { { 237, 243, 41, 3, 202, 39, 1 }, - { 35, 23, 170, 125, 156, 184, 1 }, - { 242, 41, 224, 74, 103, 219, 1 }, - { 142, 156, 223, 42, 244, 98, 0 }, }, - { { 242, 9, 23, 170, 178, 81, 0 }, - { 140, 228, 36, 169, 150, 103, 0 }, - { 69, 38, 170, 244, 72, 39, 1 }, - { 115, 52, 202, 146, 19, 152, 1 }, }, - { { 242, 87, 191, 49, 98, 230, 1 }, - { 254, 121, 140, 127, 22, 44, 1 }, - { 179, 163, 70, 126, 245, 39, 1 }, - { 154, 52, 127, 24, 207, 63, 1 }, }, - { { 240, 161, 59, 114, 216, 194, 0 }, - { 52, 120, 238, 9, 158, 161, 0 }, - { 33, 141, 167, 110, 66, 135, 1 }, - { 66, 188, 200, 59, 143, 22, 0 }, }, - { { 242, 204, 10, 145, 3, 251, 0 }, - { 244, 140, 28, 236, 58, 96, 1 }, - { 111, 224, 68, 168, 25, 167, 1 }, - { 131, 46, 27, 156, 24, 151, 1 }, }, - { { 240, 197, 80, 127, 169, 160, 1 }, - { 90, 104, 117, 76, 157, 162, 1 }, - { 130, 202, 255, 5, 81, 135, 1 }, - { 162, 220, 153, 87, 11, 45, 0 }, }, - { { 241, 197, 159, 71, 93, 153, 1 }, - { 98, 92, 84, 79, 255, 245, 0 }, - { 204, 221, 113, 124, 209, 199, 1 }, - { 87, 255, 249, 21, 29, 35, 0 }, }, - { { 240, 244, 101, 147, 182, 176, 1 }, - { 90, 9, 167, 237, 216, 101, 1 }, - { 134, 182, 228, 211, 23, 135, 1 }, - { 211, 13, 219, 242, 200, 45, 0 }, }, - { { 244, 0, 37, 19, 37, 72, 0 }, - { 29, 0, 148, 73, 240, 36, 0 }, - { 9, 82, 100, 82, 0, 23, 1 }, - { 18, 7, 201, 20, 128, 92, 0 }, }, - { { 244, 111, 108, 190, 223, 216, 1 }, - { 119, 184, 183, 172, 245, 239, 0 }, - { 141, 253, 190, 155, 123, 23, 1 }, - { 123, 215, 154, 246, 142, 247, 0 }, }, - { { 247, 104, 114, 223, 78, 225, 0 }, - { 149, 220, 199, 236, 211, 178, 1 }, - { 67, 185, 125, 167, 11, 119, 1 }, - { 166, 229, 155, 241, 157, 212, 1 }, }, - { { 251, 140, 211, 46, 207, 23, 0 }, - { 192, 246, 61, 59, 219, 242, 0 }, - { 116, 121, 186, 101, 152, 239, 1 }, - { 39, 237, 238, 94, 55, 129, 1 }, }, - { { 249, 145, 73, 232, 47, 176, 0 }, - { 40, 43, 85, 169, 92, 242, 1 }, - { 6, 250, 11, 201, 68, 207, 1 }, - { 167, 157, 74, 213, 106, 10, 0 }, }, - { { 251, 204, 144, 194, 16, 228, 0 }, - { 196, 202, 68, 158, 152, 49, 1 }, - { 19, 132, 33, 132, 153, 239, 1 }, - { 198, 12, 188, 145, 41, 145, 1 }, }, - { { 248, 252, 106, 92, 170, 113, 1 }, - { 126, 135, 231, 44, 27, 226, 1 }, - { 199, 42, 157, 43, 31, 143, 1 }, - { 163, 236, 26, 115, 240, 191, 0 }, }, - { { 254, 15, 171, 22, 40, 191, 1 }, - { 251, 142, 140, 27, 183, 232, 1 }, - { 254, 138, 52, 106, 248, 63, 1 }, - { 139, 246, 236, 24, 184, 239, 1 }, }, - { { 252, 66, 14, 134, 208, 220, 0 }, - { 37, 26, 36, 156, 179, 109, 0 }, - { 29, 133, 176, 184, 33, 31, 1 }, - { 91, 102, 156, 146, 44, 82, 0 }, }, - { { 252, 124, 113, 120, 44, 31, 0 }, - { 89, 231, 207, 29, 112, 226, 0 }, - { 124, 26, 15, 71, 31, 31, 1 }, - { 35, 135, 92, 121, 243, 205, 0 }, }, - { { 255, 159, 183, 150, 227, 134, 1 }, - { 219, 219, 188, 187, 159, 60, 0 }, - { 176, 227, 180, 246, 252, 255, 1 }, - { 30, 124, 238, 158, 237, 237, 1 }, }, - { { 112, 127, 0, 71, 111, 110, 0 }, - { 76, 145, 94, 124, 245, 136, 1 }, - { 59, 123, 113, 0, 127, 7, 0 }, - { 136, 215, 159, 61, 68, 153, 0 }, }, - { { 131, 238, 196, 68, 55, 228, 0 }, - { 204, 136, 83, 54, 73, 61, 1 }, - { 19, 246, 17, 17, 187, 224, 1 }, - { 222, 73, 54, 101, 8, 153, 1 }, }, - { { 1, 32, 180, 5, 180, 95, 1 }, - { 14, 68, 170, 82, 97, 85, 0 }, - { 253, 22, 208, 22, 130, 64, 0 }, - { 85, 67, 37, 42, 145, 56, 0 }, }, - { { 0, 59, 124, 20, 69, 167, 0 }, - { 48, 221, 155, 16, 69, 12, 1 }, - { 114, 209, 20, 31, 110, 0, 0 }, - { 152, 81, 4, 108, 221, 134, 0 }, }, - { { 3, 79, 186, 190, 163, 12, 0 }, - { 248, 224, 176, 182, 167, 26, 0 }, - { 24, 98, 190, 174, 249, 96, 0 }, - { 44, 114, 182, 134, 131, 143, 1 }, }, - { { 1, 86, 37, 1, 21, 142, 0 }, - { 64, 9, 152, 85, 96, 29, 0 }, - { 56, 212, 64, 82, 53, 64, 0 }, - { 92, 3, 85, 12, 200, 1, 0 }, }, - { { 1, 143, 230, 168, 33, 42, 0 }, - { 72, 160, 153, 130, 46, 30, 1 }, - { 42, 66, 10, 179, 248, 192, 0 }, - { 188, 58, 32, 204, 130, 137, 0 }, }, - { { 0, 175, 103, 1, 210, 134, 0 }, - { 64, 152, 171, 113, 14, 13, 0 }, - { 48, 165, 192, 115, 122, 128, 0 }, - { 88, 56, 71, 106, 140, 129, 0 }, }, - { { 0, 217, 16, 247, 55, 249, 0 }, - { 28, 237, 80, 228, 237, 65, 1 }, - { 79, 246, 119, 132, 77, 128, 0 }, - { 193, 91, 147, 133, 91, 156, 0 }, }, - { { 3, 240, 9, 255, 186, 56, 0 }, - { 184, 33, 98, 229, 169, 211, 1 }, - { 14, 46, 255, 200, 7, 224, 0 }, - { 229, 202, 211, 163, 66, 14, 1 }, }, - { { 5, 92, 205, 107, 57, 177, 1 }, - { 107, 173, 81, 71, 128, 215, 1 }, - { 198, 206, 107, 89, 157, 80, 0 }, - { 245, 128, 241, 69, 90, 235, 0 }, }, - { { 6, 109, 146, 36, 128, 158, 1 }, - { 195, 232, 42, 22, 39, 64, 0 }, - { 188, 128, 146, 36, 219, 48, 0 }, - { 1, 114, 52, 42, 11, 225, 1 }, }, - { { 4, 166, 38, 247, 185, 66, 1 }, - { 95, 32, 250, 192, 139, 141, 0 }, - { 161, 78, 247, 178, 50, 144, 0 }, - { 88, 232, 129, 175, 130, 125, 0 }, }, - { { 4, 196, 160, 187, 5, 176, 0 }, - { 81, 40, 144, 198, 200, 66, 1 }, - { 6, 208, 110, 130, 145, 144, 0 }, - { 161, 9, 177, 132, 138, 69, 0 }, }, - { { 9, 4, 240, 102, 157, 166, 0 }, - { 64, 106, 249, 18, 193, 145, 1 }, - { 50, 220, 179, 7, 144, 72, 0 }, - { 196, 193, 164, 79, 171, 1, 0 }, }, - { { 8, 63, 162, 23, 251, 204, 1 }, - { 94, 155, 178, 114, 167, 137, 0 }, - { 153, 239, 244, 34, 254, 8, 0 }, - { 72, 242, 167, 38, 236, 189, 0 }, }, - { { 10, 107, 164, 59, 63, 71, 1 }, - { 158, 166, 154, 118, 196, 143, 0 }, - { 241, 126, 110, 18, 235, 40, 0 }, - { 120, 145, 183, 44, 178, 188, 1 }, }, - { { 9, 147, 68, 160, 208, 252, 0 }, - { 4, 59, 33, 144, 44, 93, 1 }, - { 31, 133, 130, 145, 100, 200, 0 }, - { 221, 26, 4, 194, 110, 16, 0 }, }, - { { 8, 210, 94, 4, 114, 98, 1 }, - { 46, 83, 9, 36, 11, 13, 1 }, - { 163, 39, 16, 61, 37, 136, 0 }, - { 216, 104, 18, 72, 101, 58, 0 }, }, - { { 14, 39, 43, 135, 201, 75, 1 }, - { 231, 22, 186, 193, 167, 136, 0 }, - { 233, 73, 240, 234, 114, 56, 0 }, - { 8, 242, 193, 174, 180, 115, 1 }, }, - { { 15, 42, 254, 150, 218, 227, 0 }, - { 181, 222, 171, 162, 131, 157, 1 }, - { 99, 173, 180, 191, 170, 120, 0 }, - { 220, 224, 162, 234, 189, 214, 1 }, }, - { { 13, 94, 114, 56, 152, 3, 0 }, - { 81, 231, 169, 4, 2, 155, 0 }, - { 96, 12, 142, 39, 61, 88, 0 }, - { 108, 160, 16, 74, 243, 197, 0 }, }, - { { 14, 87, 112, 167, 99, 99, 1 }, - { 207, 119, 153, 228, 133, 8, 1 }, - { 227, 99, 114, 135, 117, 56, 0 }, - { 136, 80, 147, 204, 247, 121, 1 }, }, - { { 13, 106, 169, 220, 27, 63, 0 }, - { 49, 134, 218, 183, 33, 219, 1 }, - { 126, 108, 29, 202, 171, 88, 0 }, - { 237, 194, 118, 173, 176, 198, 0 }, }, - { { 13, 118, 154, 128, 113, 208, 1 }, - { 111, 91, 18, 134, 2, 89, 0 }, - { 133, 199, 0, 172, 183, 88, 0 }, - { 77, 32, 48, 164, 109, 123, 0 }, }, - { { 14, 124, 197, 35, 226, 204, 1 }, - { 207, 187, 35, 119, 160, 4, 0 }, - { 153, 163, 226, 81, 159, 56, 0 }, - { 16, 2, 247, 98, 110, 249, 1 }, }, - { { 15, 139, 106, 20, 246, 21, 0 }, - { 185, 150, 161, 48, 79, 89, 0 }, - { 84, 55, 148, 43, 104, 248, 0 }, - { 77, 121, 6, 66, 180, 206, 1 }, }, - { { 13, 171, 134, 215, 206, 17, 1 }, - { 19, 150, 98, 226, 207, 220, 0 }, - { 196, 57, 245, 176, 234, 216, 0 }, - { 29, 249, 163, 163, 52, 228, 0 }, }, - { { 15, 203, 199, 97, 60, 150, 1 }, - { 139, 170, 73, 87, 78, 221, 0 }, - { 180, 158, 67, 113, 233, 248, 0 }, - { 93, 185, 117, 73, 42, 232, 1 }, }, - { { 14, 236, 63, 51, 174, 17, 1 }, - { 251, 230, 162, 101, 202, 196, 0 }, - { 196, 58, 230, 126, 27, 184, 0 }, - { 17, 169, 211, 34, 179, 239, 1 }, }, - { { 17, 15, 152, 165, 71, 82, 0 }, - { 100, 240, 28, 226, 69, 88, 0 }, - { 37, 113, 82, 140, 248, 68, 0 }, - { 13, 81, 35, 156, 7, 147, 0 }, }, - { { 17, 119, 210, 131, 226, 153, 0 }, - { 72, 93, 39, 230, 166, 88, 0 }, - { 76, 163, 224, 165, 247, 68, 0 }, - { 13, 50, 179, 242, 93, 9, 0 }, }, - { { 17, 151, 181, 190, 81, 161, 0 }, - { 80, 125, 148, 131, 141, 31, 1 }, - { 66, 197, 62, 214, 244, 196, 0 }, - { 252, 88, 224, 148, 223, 5, 0 }, }, - { { 18, 155, 152, 58, 105, 111, 1 }, - { 190, 245, 28, 18, 172, 138, 1 }, - { 251, 75, 46, 12, 236, 164, 0 }, - { 168, 154, 164, 28, 87, 190, 1 }, }, - { { 19, 233, 65, 189, 245, 218, 0 }, - { 156, 184, 63, 197, 109, 83, 0 }, - { 45, 215, 222, 193, 75, 228, 0 }, - { 101, 91, 81, 254, 14, 156, 1 }, }, - { { 22, 13, 83, 212, 169, 87, 0 }, - { 221, 196, 125, 145, 7, 192, 0 }, - { 117, 74, 149, 229, 88, 52, 0 }, - { 1, 240, 68, 223, 17, 221, 1 }, }, - { { 22, 61, 21, 111, 231, 73, 0 }, - { 205, 245, 118, 97, 229, 6, 0 }, - { 73, 115, 251, 84, 94, 52, 0 }, - { 48, 83, 195, 55, 87, 217, 1 }, }, - { { 20, 130, 100, 0, 95, 151, 1 }, - { 3, 28, 157, 48, 72, 205, 0 }, - { 244, 253, 0, 19, 32, 148, 0 }, - { 89, 137, 6, 92, 156, 96, 0 }, }, - { { 21, 130, 161, 143, 42, 56, 1 }, - { 11, 0, 132, 227, 169, 218, 1 }, - { 142, 42, 120, 194, 160, 212, 0 }, - { 173, 202, 227, 144, 128, 104, 0 }, }, - { { 21, 153, 34, 53, 74, 250, 0 }, - { 21, 185, 140, 96, 47, 208, 1 }, - { 47, 169, 86, 34, 76, 212, 0 }, - { 133, 250, 3, 24, 206, 212, 0 }, }, - { { 23, 156, 89, 25, 214, 46, 0 }, - { 241, 209, 45, 113, 104, 19, 1 }, - { 58, 53, 204, 77, 28, 244, 0 }, - { 228, 11, 71, 90, 69, 199, 1 }, }, - { { 21, 165, 87, 175, 25, 244, 1 }, - { 71, 104, 23, 209, 143, 215, 1 }, - { 151, 204, 122, 245, 82, 212, 0 }, - { 245, 248, 197, 244, 11, 113, 0 }, }, - { { 22, 185, 129, 147, 151, 243, 0 }, - { 149, 141, 62, 227, 204, 65, 1 }, - { 103, 244, 228, 192, 206, 180, 0 }, - { 193, 25, 227, 190, 88, 212, 1 }, }, - { { 20, 212, 174, 31, 83, 198, 0 }, - { 117, 25, 156, 118, 139, 7, 0 }, - { 49, 229, 124, 58, 149, 148, 0 }, - { 112, 104, 183, 28, 204, 87, 0 }, }, - { { 22, 222, 188, 166, 177, 46, 1 }, - { 235, 225, 188, 150, 169, 13, 1 }, - { 186, 70, 178, 158, 189, 180, 0 }, - { 216, 74, 180, 158, 195, 235, 1 }, }, - { { 21, 215, 231, 50, 136, 117, 0 }, - { 85, 37, 165, 23, 142, 220, 1 }, - { 87, 8, 166, 115, 245, 212, 0 }, - { 157, 184, 244, 82, 210, 85, 0 }, }, - { { 27, 5, 137, 184, 14, 199, 1 }, - { 246, 46, 12, 179, 68, 146, 0 }, - { 241, 184, 14, 200, 208, 108, 0 }, - { 36, 145, 102, 152, 58, 55, 1 }, }, - { { 24, 76, 13, 17, 16, 216, 1 }, - { 118, 138, 4, 69, 32, 69, 0 }, - { 141, 132, 68, 88, 25, 12, 0 }, - { 81, 2, 81, 16, 40, 183, 0 }, }, - { { 27, 80, 19, 3, 222, 147, 1 }, - { 130, 95, 44, 101, 194, 209, 0 }, - { 228, 189, 224, 100, 5, 108, 0 }, - { 69, 161, 211, 26, 125, 32, 1 }, }, - { { 26, 117, 67, 117, 230, 58, 0 }, - { 216, 51, 111, 101, 103, 64, 1 }, - { 46, 51, 215, 97, 87, 44, 0 }, - { 129, 115, 83, 123, 102, 13, 1 }, }, - { { 25, 139, 44, 109, 101, 206, 0 }, - { 44, 186, 220, 80, 109, 30, 0 }, - { 57, 211, 91, 26, 104, 204, 0 }, - { 60, 91, 5, 29, 174, 154, 0 }, }, - { { 24, 157, 237, 154, 191, 3, 0 }, - { 120, 135, 189, 163, 204, 135, 0 }, - { 96, 126, 172, 219, 220, 140, 0 }, - { 112, 153, 226, 222, 240, 143, 0 }, }, - { { 26, 163, 189, 21, 22, 74, 1 }, - { 182, 66, 142, 99, 109, 13, 0 }, - { 169, 52, 84, 94, 226, 172, 0 }, - { 88, 91, 99, 56, 161, 54, 1 }, }, - { { 24, 191, 221, 217, 136, 80, 1 }, - { 118, 195, 103, 195, 12, 206, 0 }, - { 133, 8, 205, 221, 254, 140, 0 }, - { 57, 152, 97, 243, 97, 183, 0 }, }, - { { 26, 187, 197, 128, 248, 166, 1 }, - { 138, 155, 47, 147, 12, 141, 1 }, - { 178, 143, 128, 209, 238, 172, 0 }, - { 216, 152, 100, 250, 108, 168, 1 }, }, - { { 24, 202, 200, 115, 174, 12, 1 }, - { 58, 162, 101, 118, 232, 136, 0 }, - { 152, 58, 231, 9, 169, 140, 0 }, - { 8, 139, 183, 83, 34, 174, 0 }, }, - { { 26, 251, 85, 224, 195, 153, 1 }, - { 130, 255, 119, 165, 44, 76, 0 }, - { 204, 225, 131, 213, 111, 172, 0 }, - { 25, 26, 82, 247, 127, 160, 1 }, }, - { { 25, 252, 172, 250, 123, 235, 0 }, - { 124, 191, 222, 166, 168, 151, 1 }, - { 107, 239, 47, 154, 159, 204, 0 }, - { 244, 138, 178, 189, 254, 159, 0 }, }, - { { 31, 33, 77, 51, 43, 129, 0 }, - { 185, 46, 23, 97, 132, 148, 0 }, - { 64, 234, 102, 89, 66, 124, 0 }, - { 20, 144, 195, 116, 58, 78, 1 }, }, - { { 29, 104, 97, 97, 80, 45, 1 }, - { 3, 182, 199, 85, 32, 17, 1 }, - { 218, 5, 67, 67, 11, 92, 0 }, - { 196, 2, 85, 113, 182, 224, 0 }, }, - { { 29, 113, 17, 105, 159, 205, 1 }, - { 7, 111, 118, 117, 100, 147, 0 }, - { 217, 252, 203, 68, 71, 92, 0 }, - { 100, 147, 87, 55, 123, 112, 0 }, }, - { { 28, 115, 52, 93, 58, 61, 1 }, - { 27, 71, 198, 116, 37, 207, 1 }, - { 222, 46, 93, 22, 103, 28, 0 }, - { 249, 210, 23, 49, 241, 108, 0 }, }, - { { 30, 167, 7, 22, 61, 22, 1 }, - { 219, 2, 30, 17, 207, 205, 0 }, - { 180, 94, 52, 112, 114, 188, 0 }, - { 89, 249, 196, 60, 32, 109, 1 }, }, - { { 32, 22, 241, 69, 239, 16, 1 }, - { 74, 81, 241, 107, 65, 200, 0 }, - { 132, 123, 209, 71, 180, 2, 0 }, - { 9, 193, 107, 71, 197, 41, 0 }, }, - { { 33, 37, 79, 144, 49, 77, 0 }, - { 124, 4, 19, 153, 38, 21, 0 }, - { 89, 70, 4, 249, 82, 66, 0 }, - { 84, 50, 76, 228, 16, 31, 0 }, }, - { { 35, 45, 115, 235, 220, 62, 1 }, - { 194, 240, 235, 217, 230, 211, 1 }, - { 190, 29, 235, 231, 90, 98, 0 }, - { 229, 179, 205, 235, 135, 161, 1 }, }, - { { 35, 72, 62, 43, 100, 184, 1 }, - { 170, 248, 128, 76, 226, 86, 1 }, - { 142, 147, 106, 62, 9, 98, 0 }, - { 181, 35, 153, 0, 143, 170, 1 }, }, - { { 35, 86, 58, 73, 248, 94, 1 }, - { 238, 81, 232, 92, 34, 219, 0 }, - { 189, 15, 201, 46, 53, 98, 0 }, - { 109, 162, 29, 11, 197, 59, 1 }, }, - { { 34, 138, 184, 17, 107, 194, 0 }, - { 188, 216, 152, 106, 8, 136, 0 }, - { 33, 235, 68, 14, 168, 162, 0 }, - { 8, 136, 43, 12, 141, 158, 1 }, }, - { { 32, 167, 72, 150, 66, 82, 1 }, - { 118, 16, 11, 168, 141, 72, 0 }, - { 165, 33, 52, 137, 114, 130, 0 }, - { 9, 88, 138, 232, 4, 55, 0 }, }, - { { 34, 164, 248, 245, 231, 39, 1 }, - { 250, 116, 251, 250, 73, 0, 1 }, - { 242, 115, 215, 143, 146, 162, 0 }, - { 128, 73, 47, 239, 151, 47, 1 }, }, - { { 33, 239, 227, 53, 220, 27, 1 }, - { 82, 180, 171, 79, 111, 217, 0 }, - { 236, 29, 214, 99, 251, 194, 0 }, - { 77, 251, 121, 106, 150, 165, 0 }, }, - { { 33, 255, 170, 148, 240, 254, 0 }, - { 124, 153, 170, 158, 47, 89, 1 }, - { 63, 135, 148, 170, 255, 194, 0 }, - { 205, 122, 60, 170, 204, 159, 0 }, }, - { { 37, 48, 68, 183, 73, 106, 0 }, - { 21, 49, 27, 200, 161, 148, 1 }, - { 43, 73, 118, 145, 6, 82, 0 }, - { 148, 194, 137, 236, 70, 84, 0 }, }, - { { 38, 55, 142, 202, 57, 200, 0 }, - { 237, 9, 82, 138, 166, 143, 0 }, - { 9, 206, 41, 184, 246, 50, 0 }, - { 120, 178, 168, 165, 72, 91, 1 }, }, - { { 39, 67, 65, 27, 226, 165, 0 }, - { 153, 28, 33, 125, 132, 26, 1 }, - { 82, 163, 236, 65, 97, 114, 0 }, - { 172, 16, 223, 66, 28, 76, 1 }, }, - { { 39, 119, 180, 37, 12, 229, 0 }, - { 197, 109, 130, 94, 69, 156, 1 }, - { 83, 152, 82, 22, 247, 114, 0 }, - { 156, 209, 61, 32, 219, 81, 1 }, }, - { { 36, 140, 97, 44, 211, 5, 0 }, - { 65, 180, 177, 57, 9, 3, 0 }, - { 80, 101, 154, 67, 24, 146, 0 }, - { 96, 72, 78, 70, 150, 193, 0 }, }, - { { 39, 181, 134, 58, 242, 110, 1 }, - { 223, 49, 42, 58, 174, 23, 1 }, - { 187, 39, 174, 48, 214, 242, 0 }, - { 244, 58, 174, 42, 70, 125, 1 }, }, - { { 37, 192, 47, 169, 170, 233, 1 }, - { 47, 44, 160, 237, 42, 150, 1 }, - { 203, 170, 202, 250, 1, 210, 0 }, - { 180, 170, 91, 130, 154, 122, 0 }, }, - { { 37, 193, 244, 243, 24, 172, 1 }, - { 19, 104, 193, 222, 172, 149, 1 }, - { 154, 140, 103, 151, 193, 210, 0 }, - { 212, 154, 189, 193, 139, 100, 0 }, }, - { { 38, 223, 180, 89, 168, 216, 1 }, - { 223, 201, 224, 78, 44, 206, 0 }, - { 141, 138, 205, 22, 253, 178, 0 }, - { 57, 154, 57, 3, 201, 253, 1 }, }, - { { 36, 229, 181, 254, 134, 140, 0 }, - { 81, 104, 226, 191, 237, 6, 0 }, - { 24, 176, 191, 214, 211, 146, 0 }, - { 48, 91, 254, 163, 139, 69, 0 }, }, - { { 36, 250, 147, 106, 49, 84, 1 }, - { 15, 225, 82, 31, 138, 75, 0 }, - { 149, 70, 43, 100, 175, 146, 0 }, - { 105, 40, 252, 37, 67, 248, 0 }, }, - { { 41, 33, 120, 64, 98, 223, 1 }, - { 46, 94, 203, 56, 36, 80, 0 }, - { 253, 163, 1, 15, 66, 74, 0 }, - { 5, 18, 14, 105, 189, 58, 0 }, }, - { { 42, 47, 218, 50, 70, 201, 1 }, - { 246, 254, 3, 42, 230, 8, 0 }, - { 201, 177, 38, 45, 250, 42, 0 }, - { 8, 51, 170, 96, 63, 183, 1 }, }, - { { 40, 62, 63, 42, 103, 4, 0 }, - { 104, 243, 146, 57, 194, 14, 0 }, - { 16, 115, 42, 126, 62, 10, 0 }, - { 56, 33, 206, 36, 231, 139, 0 }, }, - { { 43, 205, 185, 118, 1, 186, 0 }, - { 240, 234, 216, 15, 173, 80, 1 }, - { 46, 192, 55, 78, 217, 234, 0 }, - { 133, 90, 248, 13, 171, 135, 1 }, }, - { { 40, 234, 218, 205, 222, 126, 1 }, - { 38, 210, 107, 254, 107, 203, 1 }, - { 191, 61, 217, 173, 171, 138, 0 }, - { 233, 235, 63, 235, 37, 178, 0 }, }, - { { 44, 77, 140, 242, 231, 58, 1 }, - { 123, 178, 120, 174, 228, 68, 1 }, - { 174, 115, 167, 152, 217, 26, 0 }, - { 145, 19, 186, 143, 38, 239, 0 }, }, - { { 46, 88, 0, 228, 62, 206, 0 }, - { 141, 171, 72, 188, 97, 129, 0 }, - { 57, 190, 19, 128, 13, 58, 0 }, - { 64, 195, 30, 137, 106, 216, 1 }, }, - { { 45, 129, 187, 116, 79, 227, 1 }, - { 55, 126, 216, 43, 79, 144, 1 }, - { 227, 249, 23, 110, 192, 218, 0 }, - { 132, 249, 106, 13, 191, 118, 0 }, }, - { { 44, 145, 67, 129, 237, 29, 0 }, - { 9, 23, 49, 217, 110, 192, 0 }, - { 92, 91, 192, 225, 68, 154, 0 }, - { 1, 187, 77, 198, 116, 72, 0 }, }, - { { 45, 180, 8, 215, 116, 177, 1 }, - { 123, 31, 66, 200, 201, 81, 1 }, - { 198, 151, 117, 136, 22, 218, 0 }, - { 197, 73, 137, 161, 124, 111, 0 }, }, - { { 44, 224, 23, 61, 89, 3, 1 }, - { 19, 118, 26, 77, 11, 135, 0 }, - { 224, 77, 94, 116, 3, 154, 0 }, - { 112, 232, 89, 44, 55, 100, 0 }, }, - { { 48, 9, 23, 86, 236, 208, 1 }, - { 30, 216, 100, 9, 199, 196, 0 }, - { 133, 155, 181, 116, 72, 6, 0 }, - { 17, 241, 200, 19, 13, 188, 0 }, }, - { { 51, 70, 13, 15, 126, 150, 0 }, - { 232, 24, 12, 125, 193, 223, 0 }, - { 52, 191, 120, 88, 49, 102, 0 }, - { 125, 193, 223, 24, 12, 11, 1 }, }, - { { 50, 113, 60, 116, 164, 89, 0 }, - { 188, 101, 230, 12, 101, 68, 0 }, - { 77, 18, 151, 30, 71, 38, 0 }, - { 17, 83, 24, 51, 211, 30, 1 }, }, - { { 48, 167, 239, 179, 52, 231, 1 }, - { 126, 44, 143, 219, 206, 13, 1 }, - { 243, 150, 102, 251, 242, 134, 0 }, - { 216, 57, 237, 248, 154, 63, 0 }, }, - { { 48, 183, 244, 73, 95, 202, 0 }, - { 68, 89, 223, 106, 108, 143, 0 }, - { 41, 253, 73, 23, 246, 134, 0 }, - { 120, 155, 43, 125, 205, 17, 0 }, }, - { { 51, 236, 16, 56, 154, 82, 0 }, - { 212, 224, 46, 44, 8, 211, 0 }, - { 37, 44, 142, 4, 27, 230, 0 }, - { 101, 136, 26, 58, 3, 149, 1 }, }, - { { 53, 106, 133, 153, 65, 91, 0 }, - { 21, 148, 30, 207, 32, 94, 0 }, - { 109, 65, 76, 208, 171, 86, 0 }, - { 61, 2, 121, 188, 20, 212, 0 }, }, - { { 54, 125, 199, 249, 16, 137, 1 }, - { 211, 173, 71, 207, 38, 7, 0 }, - { 200, 132, 79, 241, 223, 54, 0 }, - { 112, 50, 121, 241, 90, 229, 1 }, }, - { { 53, 145, 236, 15, 52, 5, 1 }, - { 43, 5, 133, 90, 205, 23, 0 }, - { 208, 22, 120, 27, 196, 214, 0 }, - { 116, 89, 173, 80, 208, 106, 0 }, }, - { { 58, 31, 122, 71, 185, 141, 0 }, - { 232, 207, 245, 88, 167, 137, 0 }, - { 88, 206, 241, 47, 124, 46, 0 }, - { 72, 242, 141, 87, 249, 139, 1 }, }, - { { 58, 86, 77, 209, 166, 203, 1 }, - { 254, 15, 109, 237, 96, 12, 0 }, - { 233, 178, 197, 217, 53, 46, 0 }, - { 24, 3, 91, 219, 120, 63, 1 }, }, - { { 57, 105, 99, 159, 57, 176, 1 }, - { 26, 138, 151, 205, 135, 211, 1 }, - { 134, 206, 124, 227, 75, 78, 0 }, - { 229, 240, 217, 244, 168, 172, 0 }, }, - { { 59, 96, 103, 17, 227, 243, 0 }, - { 156, 30, 191, 109, 2, 84, 1 }, - { 103, 227, 196, 115, 3, 110, 0 }, - { 149, 32, 91, 126, 188, 28, 1 }, }, - { { 57, 204, 214, 65, 214, 205, 1 }, - { 70, 222, 101, 126, 106, 21, 0 }, - { 217, 181, 193, 53, 153, 206, 0 }, - { 84, 43, 63, 83, 61, 177, 0 }, }, - { { 60, 51, 21, 240, 128, 231, 0 }, - { 21, 111, 110, 153, 4, 12, 1 }, - { 115, 128, 135, 212, 102, 30, 0 }, - { 152, 16, 76, 187, 123, 84, 0 }, }, - { { 60, 51, 197, 75, 3, 115, 1 }, - { 7, 7, 95, 107, 132, 78, 1 }, - { 231, 96, 105, 81, 230, 30, 0 }, - { 185, 16, 235, 125, 112, 112, 0 }, }, - { { 61, 98, 186, 75, 99, 200, 0 }, - { 45, 90, 214, 110, 162, 26, 0 }, - { 9, 227, 105, 46, 163, 94, 0 }, - { 44, 34, 187, 53, 173, 90, 0 }, }, - { { 61, 117, 9, 162, 109, 95, 1 }, - { 111, 55, 30, 157, 228, 208, 0 }, - { 253, 91, 34, 200, 87, 94, 0 }, - { 5, 147, 220, 188, 118, 123, 0 }, }, - { { 63, 152, 179, 12, 62, 51, 1 }, - { 139, 199, 140, 43, 75, 211, 1 }, - { 230, 62, 24, 102, 140, 254, 0 }, - { 229, 233, 106, 24, 241, 232, 1 }, }, - { { 62, 205, 175, 189, 212, 43, 0 }, - { 241, 182, 172, 207, 111, 7, 1 }, - { 106, 21, 222, 250, 217, 190, 0 }, - { 240, 123, 121, 154, 182, 199, 1 }, }, - { { 63, 213, 180, 83, 119, 231, 1 }, - { 223, 95, 220, 126, 204, 21, 1 }, - { 243, 247, 101, 22, 213, 254, 0 }, - { 212, 25, 191, 29, 253, 125, 1 }, }, - { { 60, 233, 181, 48, 105, 180, 0 }, - { 25, 250, 150, 31, 12, 196, 1 }, - { 22, 203, 6, 86, 203, 158, 0 }, - { 145, 152, 124, 52, 175, 204, 0 }, }, - { { 64, 3, 93, 254, 66, 40, 1 }, - { 50, 112, 65, 161, 181, 14, 1 }, - { 138, 33, 63, 221, 96, 1, 0 }, - { 184, 86, 194, 193, 7, 38, 0 }, }, - { { 67, 106, 171, 8, 205, 110, 1 }, - { 166, 144, 186, 23, 114, 154, 1 }, - { 187, 89, 136, 106, 171, 97, 0 }, - { 172, 167, 116, 46, 132, 178, 1 }, }, - { { 67, 113, 229, 169, 206, 30, 1 }, - { 130, 49, 171, 247, 116, 214, 0 }, - { 188, 57, 202, 211, 199, 97, 0 }, - { 53, 151, 119, 234, 198, 32, 1 }, }, - { { 65, 168, 233, 191, 52, 145, 0 }, - { 56, 172, 131, 195, 217, 83, 0 }, - { 68, 150, 126, 203, 138, 193, 0 }, - { 101, 77, 225, 224, 154, 142, 0 }, }, - { { 65, 202, 197, 166, 227, 19, 0 }, - { 8, 180, 57, 167, 153, 92, 0 }, - { 100, 99, 178, 209, 169, 193, 0 }, - { 29, 76, 242, 206, 22, 136, 0 }, }, - { { 66, 247, 60, 189, 2, 52, 0 }, - { 240, 97, 130, 244, 29, 78, 1 }, - { 22, 32, 94, 158, 119, 161, 0 }, - { 185, 92, 23, 160, 195, 7, 1 }, }, - { { 68, 39, 29, 179, 182, 219, 1 }, - { 127, 108, 42, 225, 244, 77, 0 }, - { 237, 182, 230, 220, 114, 17, 0 }, - { 89, 23, 195, 170, 27, 127, 0 }, }, - { { 68, 76, 27, 64, 24, 97, 1 }, - { 103, 196, 64, 5, 18, 129, 1 }, - { 195, 12, 1, 108, 25, 17, 0 }, - { 192, 164, 80, 1, 17, 243, 0 }, }, - { { 70, 74, 152, 175, 201, 220, 0 }, - { 165, 248, 48, 214, 177, 202, 0 }, - { 29, 201, 250, 140, 169, 49, 0 }, - { 41, 198, 181, 134, 15, 210, 1 }, }, - { { 70, 131, 6, 249, 199, 224, 1 }, - { 151, 56, 112, 224, 94, 14, 1 }, - { 131, 241, 207, 176, 96, 177, 0 }, - { 184, 61, 3, 135, 14, 116, 1 }, }, - { { 68, 140, 202, 221, 114, 250, 1 }, - { 127, 152, 73, 226, 59, 67, 1 }, - { 175, 167, 93, 169, 152, 145, 0 }, - { 225, 110, 35, 201, 12, 255, 0 }, }, - { { 70, 158, 58, 59, 116, 65, 1 }, - { 255, 245, 128, 64, 218, 11, 0 }, - { 193, 23, 110, 46, 60, 177, 0 }, - { 104, 45, 129, 0, 215, 255, 1 }, }, - { { 73, 31, 143, 197, 190, 227, 0 }, - { 108, 143, 104, 227, 87, 157, 1 }, - { 99, 190, 209, 248, 252, 73, 0 }, - { 220, 245, 99, 139, 120, 155, 0 }, }, - { { 73, 75, 34, 203, 253, 35, 1 }, - { 10, 150, 248, 196, 214, 155, 1 }, - { 226, 95, 233, 162, 105, 73, 0 }, - { 236, 181, 145, 143, 180, 168, 0 }, }, - { { 73, 91, 8, 111, 19, 202, 1 }, - { 38, 171, 88, 100, 181, 27, 0 }, - { 169, 228, 123, 8, 109, 73, 0 }, - { 108, 86, 147, 13, 106, 178, 0 }, }, - { { 74, 177, 68, 70, 10, 33, 1 }, - { 130, 7, 67, 32, 157, 132, 1 }, - { 194, 40, 49, 17, 70, 169, 0 }, - { 144, 220, 130, 97, 112, 32, 1 }, }, - { { 75, 195, 24, 213, 28, 201, 0 }, - { 180, 78, 64, 196, 125, 153, 0 }, - { 73, 156, 85, 140, 97, 233, 0 }, - { 76, 223, 17, 129, 57, 22, 1 }, }, - { { 76, 116, 244, 77, 39, 23, 1 }, - { 75, 71, 219, 118, 81, 70, 0 }, - { 244, 114, 89, 23, 151, 25, 0 }, - { 49, 69, 55, 109, 241, 105, 0 }, }, - { { 78, 157, 120, 2, 250, 136, 1 }, - { 235, 219, 161, 32, 188, 129, 0 }, - { 136, 175, 160, 15, 92, 185, 0 }, - { 64, 158, 130, 66, 237, 235, 1 }, }, - { { 79, 168, 131, 36, 88, 72, 0 }, - { 133, 178, 2, 3, 59, 145, 0 }, - { 9, 13, 18, 96, 138, 249, 0 }, - { 68, 238, 96, 32, 38, 208, 1 }, }, - { { 77, 204, 62, 66, 47, 44, 0 }, - { 105, 194, 208, 52, 250, 148, 1 }, - { 26, 122, 33, 62, 25, 217, 0 }, - { 148, 175, 150, 5, 161, 203, 0 }, }, - { { 77, 205, 182, 47, 105, 192, 1 }, - { 79, 250, 144, 70, 159, 150, 0 }, - { 129, 203, 122, 54, 217, 217, 0 }, - { 52, 252, 177, 4, 175, 249, 0 }, }, - { { 76, 252, 81, 246, 35, 2, 0 }, - { 89, 227, 91, 165, 153, 0, 0 }, - { 32, 98, 55, 197, 31, 153, 0 }, - { 0, 76, 210, 237, 99, 205, 0 }, }, - { { 77, 248, 189, 181, 78, 179, 0 }, - { 49, 255, 138, 231, 89, 212, 1 }, - { 102, 185, 86, 222, 143, 217, 0 }, - { 149, 205, 115, 168, 255, 198, 0 }, }, - { { 78, 254, 206, 197, 81, 2, 1 }, - { 227, 147, 91, 198, 27, 13, 0 }, - { 160, 69, 81, 185, 191, 185, 0 }, - { 88, 108, 49, 237, 100, 227, 1 }, }, - { { 83, 45, 244, 148, 190, 11, 1 }, - { 218, 196, 175, 162, 117, 149, 0 }, - { 232, 62, 148, 151, 218, 101, 0 }, - { 84, 215, 34, 250, 145, 173, 1 }, }, - { { 83, 55, 48, 177, 237, 76, 1 }, - { 222, 113, 182, 208, 116, 152, 0 }, - { 153, 91, 198, 134, 118, 101, 0 }, - { 12, 151, 5, 182, 199, 61, 1 }, }, - { { 81, 138, 115, 76, 78, 26, 0 }, - { 0, 208, 205, 33, 123, 218, 0 }, - { 44, 57, 25, 103, 40, 197, 0 }, - { 45, 239, 66, 89, 133, 128, 0 }, }, - { { 81, 173, 41, 83, 250, 51, 0 }, - { 120, 148, 238, 97, 156, 209, 1 }, - { 102, 47, 229, 74, 90, 197, 0 }, - { 197, 156, 195, 59, 148, 143, 0 }, }, - { { 80, 244, 139, 181, 87, 23, 1 }, - { 114, 53, 30, 247, 91, 65, 0 }, - { 244, 117, 86, 232, 151, 133, 0 }, - { 65, 109, 119, 188, 86, 39, 0 }, }, - { { 83, 242, 216, 169, 125, 63, 0 }, - { 168, 117, 31, 214, 120, 219, 1 }, - { 126, 95, 74, 141, 167, 229, 0 }, - { 237, 143, 53, 252, 87, 10, 1 }, }, - { { 87, 46, 51, 92, 65, 229, 1 }, - { 215, 220, 214, 17, 19, 26, 1 }, - { 211, 193, 29, 102, 58, 117, 0 }, - { 172, 100, 68, 53, 157, 245, 1 }, }, - { { 85, 97, 138, 153, 243, 43, 1 }, - { 59, 20, 62, 230, 54, 19, 1 }, - { 234, 103, 204, 168, 195, 85, 0 }, - { 228, 54, 51, 190, 20, 110, 0 }, }, - { { 84, 114, 176, 221, 66, 144, 1 }, - { 19, 89, 198, 230, 17, 74, 0 }, - { 132, 161, 93, 134, 167, 21, 0 }, - { 41, 68, 51, 177, 205, 100, 0 }, }, - { { 87, 120, 188, 172, 178, 210, 1 }, - { 175, 233, 174, 166, 17, 87, 0 }, - { 165, 166, 154, 158, 143, 117, 0 }, - { 117, 68, 50, 186, 203, 250, 1 }, }, - { { 85, 178, 111, 85, 255, 238, 1 }, - { 63, 25, 255, 113, 123, 157, 1 }, - { 187, 255, 213, 123, 38, 213, 0 }, - { 220, 239, 71, 127, 204, 126, 0 }, }, - { { 87, 215, 193, 128, 15, 12, 1 }, - { 195, 1, 21, 183, 124, 152, 0 }, - { 152, 120, 0, 193, 245, 245, 0 }, - { 12, 159, 118, 212, 64, 97, 1 }, }, - { { 85, 243, 37, 159, 247, 53, 0 }, - { 25, 21, 182, 245, 221, 95, 1 }, - { 86, 119, 252, 210, 103, 213, 0 }, - { 253, 93, 215, 182, 212, 76, 0 }, }, - { { 90, 0, 169, 237, 210, 158, 0 }, - { 160, 58, 236, 243, 49, 67, 0 }, - { 60, 165, 219, 202, 128, 45, 0 }, - { 97, 70, 103, 155, 174, 2, 1 }, }, - { { 89, 39, 61, 104, 89, 78, 1 }, - { 102, 114, 222, 17, 52, 159, 0 }, - { 185, 77, 11, 94, 114, 77, 0 }, - { 124, 150, 68, 61, 167, 51, 0 }, }, - { { 89, 73, 179, 211, 30, 79, 0 }, - { 20, 198, 204, 247, 246, 145, 0 }, - { 121, 60, 101, 230, 201, 77, 0 }, - { 68, 183, 247, 153, 177, 148, 0 }, }, - { { 91, 92, 30, 37, 185, 241, 1 }, - { 238, 239, 52, 68, 19, 213, 1 }, - { 199, 206, 210, 60, 29, 109, 0 }, - { 213, 228, 17, 22, 123, 187, 1 }, }, - { { 89, 81, 133, 145, 139, 249, 0 }, - { 20, 15, 52, 231, 52, 212, 1 }, - { 79, 232, 196, 208, 197, 77, 0 }, - { 149, 150, 115, 150, 120, 20, 0 }, }, - { { 91, 156, 92, 115, 202, 248, 1 }, - { 246, 251, 101, 96, 184, 212, 1 }, - { 143, 169, 231, 29, 28, 237, 0 }, - { 149, 142, 131, 83, 111, 183, 1 }, }, - { { 90, 148, 209, 233, 34, 152, 1 }, - { 202, 107, 69, 227, 56, 66, 0 }, - { 140, 162, 75, 197, 148, 173, 0 }, - { 33, 14, 99, 209, 107, 41, 1 }, }, - { { 88, 170, 155, 107, 27, 52, 0 }, - { 32, 226, 86, 115, 154, 203, 1 }, - { 22, 108, 107, 108, 170, 141, 0 }, - { 233, 172, 231, 53, 35, 130, 0 }, }, - { { 90, 202, 163, 22, 250, 87, 1 }, - { 158, 150, 172, 55, 155, 201, 0 }, - { 245, 47, 180, 98, 169, 173, 0 }, - { 73, 236, 246, 26, 180, 188, 1 }, }, - { { 88, 216, 190, 3, 241, 57, 0 }, - { 40, 215, 180, 70, 186, 69, 1 }, - { 78, 71, 224, 62, 141, 141, 0 }, - { 209, 46, 177, 22, 245, 138, 0 }, }, - { { 90, 253, 27, 96, 216, 252, 0 }, - { 228, 251, 102, 21, 62, 193, 1 }, - { 31, 141, 131, 108, 95, 173, 0 }, - { 193, 190, 84, 51, 111, 147, 1 }, }, - { { 93, 40, 12, 244, 83, 170, 1 }, - { 51, 186, 94, 160, 49, 21, 1 }, - { 170, 229, 23, 152, 10, 93, 0 }, - { 212, 70, 2, 189, 46, 230, 0 }, }, - { { 94, 52, 215, 24, 145, 91, 0 }, - { 213, 71, 63, 3, 50, 71, 0 }, - { 109, 68, 140, 117, 150, 61, 0 }, - { 113, 38, 96, 126, 113, 85, 1 }, }, - { { 94, 140, 231, 129, 51, 103, 0 }, - { 205, 134, 157, 243, 26, 5, 1 }, - { 115, 102, 64, 243, 152, 189, 0 }, - { 208, 44, 103, 220, 176, 217, 1 }, }, - { { 92, 240, 52, 170, 32, 5, 0 }, - { 9, 103, 134, 148, 152, 6, 0 }, - { 80, 2, 42, 150, 7, 157, 0 }, - { 48, 12, 148, 176, 243, 72, 0 }, }, - { { 99, 47, 8, 198, 1, 227, 0 }, - { 228, 140, 90, 136, 149, 24, 1 }, - { 99, 192, 49, 136, 122, 99, 0 }, - { 140, 84, 136, 173, 24, 147, 1 }, }, - { { 97, 34, 240, 131, 154, 222, 0 }, - { 4, 72, 171, 250, 176, 217, 0 }, - { 61, 172, 224, 135, 162, 67, 0 }, - { 77, 134, 175, 234, 137, 16, 0 }, }, - { { 97, 64, 6, 28, 66, 91, 1 }, - { 22, 20, 8, 44, 51, 86, 0 }, - { 237, 33, 28, 48, 1, 67, 0 }, - { 53, 102, 26, 8, 20, 52, 0 }, }, - { { 99, 104, 252, 248, 31, 16, 0 }, - { 176, 224, 211, 174, 80, 215, 0 }, - { 4, 124, 15, 159, 139, 99, 0 }, - { 117, 133, 58, 229, 131, 134, 1 }, }, - { { 98, 163, 80, 160, 5, 206, 1 }, - { 134, 104, 27, 152, 124, 8, 0 }, - { 185, 208, 2, 133, 98, 163, 0 }, - { 8, 31, 12, 236, 11, 48, 1 }, }, - { { 96, 207, 8, 137, 207, 134, 1 }, - { 98, 152, 56, 252, 92, 138, 0 }, - { 176, 249, 200, 136, 121, 131, 0 }, - { 40, 157, 31, 142, 12, 163, 0 }, }, - { { 100, 31, 102, 147, 38, 250, 0 }, - { 93, 137, 137, 232, 246, 76, 1 }, - { 47, 178, 100, 179, 124, 19, 0 }, - { 153, 55, 139, 200, 200, 221, 0 }, }, - { { 103, 84, 36, 66, 155, 194, 1 }, - { 199, 9, 248, 44, 144, 149, 0 }, - { 161, 236, 161, 18, 21, 115, 0 }, - { 84, 132, 154, 15, 200, 113, 1 }, }, - { { 103, 94, 109, 245, 161, 167, 0 }, - { 249, 173, 249, 221, 17, 28, 1 }, - { 114, 194, 215, 219, 61, 115, 0 }, - { 156, 68, 93, 207, 218, 207, 1 }, }, - { { 100, 112, 128, 63, 112, 33, 0 }, - { 25, 53, 2, 78, 145, 3, 1 }, - { 66, 7, 126, 0, 135, 19, 0 }, - { 224, 68, 185, 32, 86, 76, 0 }, }, - { { 101, 113, 143, 62, 145, 182, 1 }, - { 51, 41, 58, 31, 151, 87, 1 }, - { 182, 196, 190, 120, 199, 83, 0 }, - { 245, 116, 252, 46, 74, 102, 0 }, }, - { { 103, 153, 192, 236, 194, 232, 1 }, - { 135, 185, 97, 170, 61, 18, 1 }, - { 139, 161, 155, 129, 204, 243, 0 }, - { 164, 94, 42, 195, 78, 240, 1 }, }, - { { 102, 181, 191, 1, 79, 214, 0 }, - { 229, 89, 154, 123, 94, 196, 0 }, - { 53, 249, 64, 126, 214, 179, 0 }, - { 17, 189, 111, 44, 205, 83, 1 }, }, - { { 103, 209, 57, 91, 135, 184, 0 }, - { 177, 73, 240, 109, 252, 82, 1 }, - { 14, 240, 237, 78, 69, 243, 0 }, - { 165, 31, 219, 7, 201, 70, 1 }, }, - { { 101, 214, 185, 83, 116, 18, 0 }, - { 121, 81, 200, 79, 216, 89, 0 }, - { 36, 23, 101, 78, 181, 211, 0 }, - { 77, 13, 249, 9, 197, 79, 0 }, }, - { { 107, 53, 69, 174, 190, 183, 0 }, - { 200, 47, 43, 185, 213, 215, 1 }, - { 118, 190, 186, 209, 86, 107, 0 }, - { 245, 213, 206, 234, 122, 9, 1 }, }, - { { 106, 85, 31, 116, 156, 15, 1 }, - { 242, 103, 104, 29, 119, 133, 0 }, - { 248, 28, 151, 124, 85, 43, 0 }, - { 80, 247, 92, 11, 115, 39, 1 }, }, - { { 105, 214, 240, 35, 1, 52, 0 }, - { 64, 99, 145, 94, 152, 88, 1 }, - { 22, 64, 98, 7, 181, 203, 0 }, - { 141, 12, 189, 68, 227, 1, 0 }, }, - { { 107, 214, 206, 166, 84, 232, 1 }, - { 230, 59, 1, 142, 251, 29, 1 }, - { 139, 149, 50, 185, 181, 235, 0 }, - { 220, 111, 184, 192, 110, 51, 1 }, }, - { { 108, 83, 126, 168, 65, 235, 0 }, - { 37, 127, 153, 140, 54, 14, 1 }, - { 107, 193, 10, 191, 101, 27, 0 }, - { 184, 54, 24, 204, 255, 82, 0 }, }, - { { 110, 99, 164, 20, 64, 36, 1 }, - { 147, 18, 130, 30, 21, 12, 1 }, - { 146, 1, 20, 18, 227, 59, 0 }, - { 152, 84, 60, 32, 164, 100, 1 }, }, - { { 108, 120, 204, 22, 132, 88, 1 }, - { 55, 131, 35, 14, 241, 68, 0 }, - { 141, 16, 180, 25, 143, 27, 0 }, - { 17, 71, 184, 98, 96, 246, 0 }, }, - { { 108, 206, 226, 122, 51, 47, 0 }, - { 89, 166, 217, 62, 186, 11, 1 }, - { 122, 102, 47, 35, 185, 155, 0 }, - { 232, 46, 190, 77, 178, 205, 0 }, }, - { { 111, 226, 98, 8, 71, 155, 0 }, - { 129, 30, 155, 44, 122, 90, 0 }, - { 108, 241, 8, 35, 35, 251, 0 }, - { 45, 47, 26, 108, 188, 64, 1 }, }, - { { 113, 2, 15, 225, 198, 243, 0 }, - { 36, 60, 108, 233, 82, 92, 1 }, - { 103, 177, 195, 248, 32, 71, 0 }, - { 157, 37, 75, 155, 30, 18, 0 }, }, - { { 113, 1, 66, 223, 219, 44, 0 }, - { 16, 16, 117, 248, 183, 147, 1 }, - { 26, 109, 253, 161, 64, 71, 0 }, - { 228, 246, 143, 215, 4, 4, 0 }, }, - { { 114, 10, 186, 206, 130, 96, 0 }, - { 164, 192, 228, 170, 147, 10, 1 }, - { 3, 32, 185, 174, 168, 39, 0 }, - { 168, 100, 170, 147, 129, 146, 1 }, }, - { { 114, 76, 255, 13, 215, 153, 0 }, - { 224, 220, 181, 111, 115, 71, 0 }, - { 76, 245, 216, 127, 153, 39, 0 }, - { 113, 103, 123, 86, 157, 131, 1 }, }, - { { 112, 148, 200, 167, 175, 228, 0 }, - { 108, 41, 53, 250, 217, 128, 1 }, - { 19, 250, 242, 137, 148, 135, 0 }, - { 128, 205, 175, 214, 74, 27, 0 }, }, - { { 115, 219, 92, 88, 31, 37, 1 }, - { 178, 197, 85, 60, 92, 159, 1 }, - { 210, 124, 13, 29, 109, 231, 0 }, - { 252, 157, 30, 85, 81, 166, 1 }, }, - { { 113, 220, 240, 226, 63, 213, 1 }, - { 78, 237, 213, 190, 216, 209, 0 }, - { 213, 254, 35, 135, 157, 199, 0 }, - { 69, 141, 190, 213, 219, 185, 0 }, }, - { { 115, 240, 217, 222, 113, 35, 1 }, - { 186, 85, 95, 143, 153, 19, 1 }, - { 226, 71, 61, 205, 135, 231, 0 }, - { 228, 76, 248, 253, 85, 46, 1 }, }, - { { 117, 16, 178, 106, 60, 109, 0 }, - { 13, 101, 196, 26, 242, 147, 1 }, - { 91, 30, 43, 38, 132, 87, 0 }, - { 228, 167, 172, 17, 211, 88, 0 }, }, - { { 117, 125, 232, 146, 6, 63, 0 }, - { 113, 133, 143, 190, 244, 80, 1 }, - { 126, 48, 36, 139, 223, 87, 0 }, - { 133, 23, 190, 248, 208, 199, 0 }, }, - { { 116, 159, 153, 133, 17, 253, 0 }, - { 101, 205, 20, 219, 61, 73, 1 }, - { 95, 196, 80, 204, 252, 151, 0 }, - { 201, 94, 109, 148, 89, 211, 0 }, }, - { { 122, 14, 219, 24, 154, 237, 0 }, - { 244, 206, 37, 59, 50, 139, 1 }, - { 91, 172, 140, 109, 184, 47, 0 }, - { 232, 166, 110, 82, 57, 151, 1 }, }, - { { 121, 22, 143, 58, 72, 165, 1 }, - { 114, 63, 4, 27, 146, 158, 1 }, - { 210, 137, 46, 120, 180, 79, 0 }, - { 188, 164, 236, 16, 126, 39, 0 }, }, - { { 121, 188, 129, 6, 112, 53, 0 }, - { 72, 151, 6, 27, 153, 81, 1 }, - { 86, 7, 48, 64, 158, 207, 0 }, - { 197, 76, 236, 48, 116, 137, 0 }, }, - { { 125, 77, 194, 163, 143, 129, 1 }, - { 67, 174, 53, 238, 214, 144, 0 }, - { 192, 248, 226, 161, 217, 95, 0 }, - { 4, 181, 187, 214, 58, 225, 0 }, }, - { { 124, 135, 26, 99, 181, 78, 0 }, - { 109, 98, 124, 88, 254, 9, 0 }, - { 57, 86, 227, 44, 112, 159, 0 }, - { 72, 63, 141, 31, 35, 91, 0 }, }, - { { 127, 162, 123, 214, 2, 146, 1 }, - { 179, 74, 207, 169, 155, 88, 0 }, - { 164, 160, 53, 239, 34, 255, 0 }, - { 13, 108, 202, 249, 169, 102, 1 }, }, - { { 125, 171, 223, 59, 221, 197, 1 }, - { 55, 254, 55, 91, 222, 159, 0 }, - { 209, 221, 238, 125, 234, 223, 0 }, - { 124, 189, 237, 118, 63, 246, 0 }, }, - { { 125, 187, 65, 173, 85, 124, 1 }, - { 7, 179, 23, 217, 125, 91, 1 }, - { 159, 85, 90, 193, 110, 223, 0 }, - { 237, 95, 77, 244, 102, 240, 0 }, }, - { { 131, 4, 66, 138, 233, 199, 0 }, - { 204, 28, 57, 144, 130, 178, 0 }, - { 113, 203, 168, 161, 16, 96, 1 }, - { 38, 160, 132, 206, 28, 25, 1 }, }, - { { 131, 43, 42, 216, 218, 107, 1 }, - { 182, 148, 234, 160, 38, 187, 1 }, - { 235, 45, 141, 170, 106, 96, 1 }, - { 238, 178, 2, 171, 148, 182, 1 }, }, - { { 129, 42, 82, 146, 228, 127, 0 }, - { 28, 212, 43, 144, 226, 120, 1 }, - { 127, 19, 164, 165, 42, 64, 1 }, - { 143, 35, 132, 234, 21, 156, 0 }, }, - { { 129, 56, 22, 164, 149, 242, 0 }, - { 4, 233, 58, 128, 67, 117, 1 }, - { 39, 212, 146, 180, 14, 64, 1 }, - { 215, 97, 0, 174, 75, 144, 0 }, }, - { { 129, 100, 221, 191, 156, 110, 1 }, - { 118, 96, 43, 215, 225, 183, 1 }, - { 187, 28, 254, 221, 147, 64, 1 }, - { 246, 195, 245, 234, 3, 55, 0 }, }, - { { 129, 123, 93, 252, 187, 253, 1 }, - { 62, 237, 115, 181, 37, 255, 1 }, - { 223, 238, 159, 221, 111, 64, 1 }, - { 255, 210, 86, 231, 91, 190, 0 }, }, - { { 130, 178, 225, 68, 80, 78, 0 }, - { 132, 17, 203, 19, 41, 41, 0 }, - { 57, 5, 17, 67, 166, 160, 1 }, - { 74, 74, 100, 105, 196, 16, 1 }, }, - { { 128, 247, 188, 97, 25, 21, 0 }, - { 96, 101, 210, 86, 12, 237, 0 }, - { 84, 76, 67, 30, 247, 128, 1 }, - { 91, 152, 53, 37, 211, 3, 0 }, }, - { { 135, 52, 106, 165, 125, 200, 0 }, - { 237, 57, 147, 192, 99, 177, 0 }, - { 9, 223, 82, 171, 22, 112, 1 }, - { 70, 227, 1, 228, 206, 91, 1 }, }, - { { 132, 140, 23, 210, 149, 239, 1 }, - { 87, 204, 120, 145, 234, 37, 1 }, - { 251, 212, 165, 244, 24, 144, 1 }, - { 210, 43, 196, 143, 25, 245, 0 }, }, - { { 132, 150, 182, 186, 170, 44, 0 }, - { 89, 97, 160, 178, 170, 174, 1 }, - { 26, 42, 174, 182, 180, 144, 1 }, - { 186, 170, 166, 130, 195, 77, 0 }, }, - { { 135, 156, 185, 242, 219, 180, 0 }, - { 241, 249, 240, 179, 136, 241, 1 }, - { 22, 237, 167, 206, 156, 240, 1 }, - { 199, 136, 230, 135, 207, 199, 1 }, }, - { { 132, 196, 118, 79, 240, 21, 1 }, - { 75, 84, 225, 84, 139, 103, 0 }, - { 212, 7, 249, 55, 17, 144, 1 }, - { 115, 104, 149, 67, 149, 105, 0 }, }, - { { 135, 196, 142, 129, 238, 18, 1 }, - { 235, 16, 40, 230, 74, 244, 0 }, - { 164, 59, 192, 184, 145, 240, 1 }, - { 23, 169, 51, 138, 4, 107, 1 }, }, - { { 133, 225, 245, 45, 64, 89, 1 }, - { 7, 116, 131, 71, 45, 118, 0 }, - { 205, 1, 90, 87, 195, 208, 1 }, - { 55, 90, 113, 96, 151, 112, 0 }, }, - { { 137, 14, 35, 66, 210, 193, 1 }, - { 70, 158, 224, 33, 130, 57, 0 }, - { 193, 165, 161, 98, 56, 72, 1 }, - { 78, 32, 194, 3, 188, 177, 0 }, }, - { { 138, 56, 218, 197, 237, 134, 1 }, - { 170, 219, 123, 210, 67, 160, 0 }, - { 176, 219, 209, 173, 142, 40, 1 }, - { 2, 225, 37, 239, 109, 170, 1 }, }, - { { 138, 149, 152, 168, 110, 21, 0 }, - { 232, 119, 0, 178, 76, 226, 0 }, - { 84, 59, 10, 140, 212, 168, 1 }, - { 35, 153, 38, 128, 119, 11, 1 }, }, - { { 141, 29, 47, 20, 46, 123, 1 }, - { 127, 135, 136, 33, 103, 244, 1 }, - { 239, 58, 20, 122, 92, 88, 1 }, - { 151, 243, 66, 8, 240, 255, 0 }, }, - { { 141, 111, 99, 41, 14, 170, 1 }, - { 67, 170, 139, 101, 102, 186, 1 }, - { 170, 184, 74, 99, 123, 88, 1 }, - { 174, 179, 83, 104, 170, 225, 0 }, }, - { { 142, 178, 140, 83, 176, 124, 1 }, - { 191, 3, 98, 82, 168, 109, 1 }, - { 159, 6, 229, 24, 166, 184, 1 }, - { 219, 10, 165, 35, 96, 126, 1 }, }, - { { 142, 222, 235, 43, 219, 30, 1 }, - { 227, 179, 185, 119, 170, 235, 0 }, - { 188, 109, 234, 107, 189, 184, 1 }, - { 107, 170, 247, 78, 230, 227, 1 }, }, - { { 141, 245, 6, 243, 158, 250, 0 }, - { 85, 43, 106, 228, 238, 245, 1 }, - { 47, 188, 231, 176, 87, 216, 1 }, - { 215, 187, 147, 171, 106, 85, 0 }, }, - { { 144, 23, 149, 47, 152, 143, 0 }, - { 64, 109, 44, 83, 165, 175, 0 }, - { 120, 140, 250, 84, 244, 4, 1 }, - { 122, 210, 229, 26, 91, 1, 0 }, }, - { { 145, 35, 7, 27, 254, 232, 0 }, - { 28, 24, 38, 97, 230, 191, 1 }, - { 11, 191, 236, 112, 98, 68, 1 }, - { 254, 179, 195, 50, 12, 28, 0 }, }, - { { 144, 37, 85, 177, 206, 2, 1 }, - { 82, 112, 47, 225, 68, 164, 0 }, - { 160, 57, 198, 213, 82, 4, 1 }, - { 18, 145, 67, 250, 7, 37, 0 }, }, - { { 144, 40, 188, 66, 77, 232, 0 }, - { 36, 216, 214, 2, 224, 164, 1 }, - { 11, 217, 33, 30, 138, 4, 1 }, - { 146, 131, 160, 53, 141, 146, 0 }, }, - { { 144, 57, 208, 138, 32, 54, 1 }, - { 10, 193, 15, 146, 132, 98, 1 }, - { 182, 2, 40, 133, 206, 4, 1 }, - { 163, 16, 164, 248, 65, 168, 0 }, }, - { { 147, 79, 149, 211, 130, 90, 0 }, - { 212, 192, 108, 231, 164, 124, 0 }, - { 45, 32, 229, 212, 249, 100, 1 }, - { 31, 18, 243, 155, 1, 149, 1 }, }, - { { 146, 164, 210, 234, 226, 74, 0 }, - { 204, 112, 111, 162, 170, 34, 0 }, - { 41, 35, 171, 165, 146, 164, 1 }, - { 34, 42, 162, 251, 7, 25, 1 }, }, - { { 145, 180, 112, 9, 138, 92, 1 }, - { 70, 65, 167, 112, 40, 242, 0 }, - { 157, 40, 200, 7, 22, 196, 1 }, - { 39, 138, 7, 114, 193, 49, 0 }, }, - { { 147, 222, 25, 219, 41, 219, 1 }, - { 254, 205, 92, 197, 168, 250, 0 }, - { 237, 202, 109, 204, 61, 228, 1 }, - { 47, 138, 209, 157, 89, 191, 1 }, }, - { { 145, 229, 150, 87, 118, 92, 0 }, - { 92, 80, 70, 118, 239, 117, 0 }, - { 29, 55, 117, 52, 211, 196, 1 }, - { 87, 123, 183, 49, 5, 29, 0 }, }, - { { 146, 236, 144, 218, 63, 135, 0 }, - { 216, 204, 94, 182, 200, 163, 0 }, - { 112, 254, 45, 132, 155, 164, 1 }, - { 98, 137, 182, 189, 25, 141, 1 }, }, - { { 146, 252, 112, 168, 201, 176, 0 }, - { 192, 249, 183, 132, 8, 226, 1 }, - { 6, 201, 138, 135, 31, 164, 1 }, - { 163, 136, 16, 246, 207, 129, 1 }, }, - { { 149, 25, 170, 136, 106, 158, 1 }, - { 43, 153, 140, 178, 38, 242, 0 }, - { 188, 171, 8, 170, 204, 84, 1 }, - { 39, 178, 38, 152, 204, 234, 0 }, }, - { { 148, 82, 41, 183, 65, 127, 0 }, - { 53, 53, 156, 213, 161, 104, 1 }, - { 127, 65, 118, 202, 37, 20, 1 }, - { 139, 66, 213, 156, 214, 86, 0 }, }, - { { 148, 87, 59, 92, 68, 38, 1 }, - { 115, 81, 204, 21, 71, 42, 1 }, - { 178, 17, 29, 110, 117, 20, 1 }, - { 170, 113, 84, 25, 197, 103, 0 }, }, - { { 151, 82, 5, 249, 168, 20, 0 }, - { 153, 33, 100, 213, 0, 254, 0 }, - { 20, 10, 207, 208, 37, 116, 1 }, - { 63, 128, 85, 147, 66, 76, 1 }, }, - { { 150, 156, 251, 61, 143, 160, 1 }, - { 243, 233, 181, 99, 75, 162, 1 }, - { 130, 248, 222, 111, 156, 180, 1 }, - { 162, 233, 99, 86, 203, 231, 1 }, }, - { { 151, 163, 111, 26, 69, 144, 1 }, - { 179, 24, 151, 1, 206, 126, 0 }, - { 132, 209, 44, 123, 98, 244, 1 }, - { 63, 57, 192, 116, 140, 102, 1 }, }, - { { 151, 170, 229, 229, 236, 98, 0 }, - { 141, 176, 239, 195, 73, 188, 1 }, - { 35, 27, 211, 211, 170, 244, 1 }, - { 158, 201, 97, 251, 134, 216, 1 }, }, - { { 151, 229, 170, 59, 113, 88, 1 }, - { 255, 48, 150, 70, 174, 115, 0 }, - { 141, 71, 110, 42, 211, 244, 1 }, - { 103, 58, 177, 52, 134, 127, 1 }, }, - { { 154, 32, 49, 130, 105, 146, 1 }, - { 138, 90, 158, 129, 128, 224, 0 }, - { 164, 203, 32, 198, 2, 44, 1 }, - { 3, 128, 192, 188, 173, 40, 1 }, }, - { { 153, 69, 56, 75, 61, 53, 1 }, - { 106, 70, 212, 84, 196, 243, 1 }, - { 214, 94, 105, 14, 81, 76, 1 }, - { 231, 145, 149, 21, 177, 43, 0 }, }, - { { 154, 177, 236, 143, 208, 111, 1 }, - { 166, 23, 175, 210, 173, 39, 1 }, - { 251, 5, 248, 155, 198, 172, 1 }, - { 242, 90, 165, 250, 244, 50, 1 }, }, - { { 154, 213, 151, 178, 63, 108, 1 }, - { 222, 99, 20, 183, 238, 165, 1 }, - { 155, 126, 38, 244, 213, 172, 1 }, - { 210, 187, 246, 148, 99, 61, 1 }, }, - { { 153, 249, 19, 79, 121, 230, 0 }, - { 12, 219, 94, 85, 143, 179, 1 }, - { 51, 207, 121, 100, 79, 204, 1 }, - { 230, 248, 213, 61, 109, 152, 0 }, }, - { { 158, 24, 232, 0, 191, 106, 1 }, - { 175, 131, 189, 34, 96, 161, 1 }, - { 171, 126, 128, 11, 140, 60, 1 }, - { 194, 131, 34, 94, 224, 250, 1 }, }, - { { 159, 72, 93, 163, 29, 40, 1 }, - { 163, 226, 21, 197, 224, 181, 1 }, - { 138, 92, 98, 221, 9, 124, 1 }, - { 214, 131, 209, 212, 35, 226, 1 }, }, - { { 159, 84, 21, 142, 137, 140, 0 }, - { 193, 75, 52, 149, 161, 182, 0 }, - { 24, 200, 184, 212, 21, 124, 1 }, - { 54, 194, 212, 150, 105, 65, 1 }, }, - { { 157, 106, 155, 82, 57, 78, 1 }, - { 63, 194, 94, 23, 162, 185, 0 }, - { 185, 78, 37, 108, 171, 92, 1 }, - { 78, 162, 244, 61, 33, 254, 0 }, }, - { { 158, 111, 156, 10, 159, 118, 0 }, - { 229, 194, 62, 54, 196, 239, 1 }, - { 55, 124, 168, 28, 251, 60, 1 }, - { 251, 145, 182, 62, 33, 211, 1 }, }, - { { 160, 9, 100, 5, 91, 91, 0 }, - { 4, 148, 153, 104, 37, 229, 0 }, - { 109, 109, 80, 19, 72, 2, 1 }, - { 83, 210, 11, 76, 148, 144, 0 }, }, - { { 162, 60, 219, 252, 54, 178, 0 }, - { 248, 233, 75, 171, 67, 99, 1 }, - { 38, 182, 31, 237, 158, 34, 1 }, - { 227, 97, 106, 233, 75, 143, 1 }, }, - { { 163, 91, 247, 118, 247, 143, 0 }, - { 152, 253, 249, 63, 231, 61, 0 }, - { 120, 247, 183, 119, 237, 98, 1 }, - { 94, 115, 254, 79, 223, 140, 1 }, }, - { { 162, 157, 115, 18, 132, 59, 0 }, - { 208, 197, 169, 9, 238, 96, 1 }, - { 110, 16, 164, 103, 92, 162, 1 }, - { 131, 59, 200, 74, 209, 133, 1 }, }, - { { 160, 206, 10, 169, 116, 87, 0 }, - { 108, 180, 8, 220, 74, 107, 0 }, - { 117, 23, 74, 168, 57, 130, 1 }, - { 107, 41, 29, 136, 22, 155, 0 }, }, - { { 160, 220, 172, 38, 43, 179, 1 }, - { 106, 173, 152, 46, 137, 228, 1 }, - { 230, 234, 50, 26, 157, 130, 1 }, - { 147, 200, 186, 12, 218, 171, 0 }, }, - { { 162, 245, 118, 116, 106, 43, 1 }, - { 218, 117, 203, 44, 47, 164, 1 }, - { 234, 43, 23, 55, 87, 162, 1 }, - { 146, 250, 26, 105, 215, 45, 1 }, }, - { { 166, 47, 214, 238, 159, 142, 1 }, - { 195, 232, 123, 186, 231, 175, 0 }, - { 184, 252, 187, 181, 250, 50, 1 }, - { 122, 243, 174, 239, 11, 225, 1 }, }, - { { 165, 56, 116, 248, 96, 115, 1 }, - { 31, 245, 203, 136, 0, 118, 1 }, - { 231, 3, 15, 151, 14, 82, 1 }, - { 183, 0, 8, 233, 215, 252, 0 }, }, - { { 164, 94, 71, 141, 231, 74, 0 }, - { 77, 145, 57, 237, 99, 46, 0 }, - { 41, 115, 216, 241, 61, 18, 1 }, - { 58, 99, 91, 206, 68, 217, 0 }, }, - { { 167, 93, 87, 124, 48, 116, 1 }, - { 223, 225, 65, 29, 7, 119, 1 }, - { 151, 6, 31, 117, 93, 114, 1 }, - { 247, 112, 92, 65, 67, 253, 1 }, }, - { { 166, 114, 149, 34, 69, 134, 0 }, - { 129, 121, 26, 31, 192, 44, 0 }, - { 48, 209, 34, 84, 167, 50, 1 }, - { 26, 1, 252, 44, 79, 64, 1 }, }, - { { 165, 131, 104, 82, 20, 90, 0 }, - { 53, 0, 201, 8, 236, 121, 0 }, - { 45, 20, 37, 11, 96, 210, 1 }, - { 79, 27, 136, 73, 128, 86, 0 }, }, - { { 164, 155, 84, 147, 194, 3, 0 }, - { 17, 213, 41, 232, 140, 44, 0 }, - { 96, 33, 228, 149, 108, 146, 1 }, - { 26, 24, 139, 202, 85, 196, 0 }, }, - { { 166, 189, 42, 131, 213, 14, 0 }, - { 225, 145, 186, 216, 238, 33, 0 }, - { 56, 85, 224, 170, 94, 178, 1 }, - { 66, 59, 141, 174, 196, 195, 1 }, }, - { { 169, 7, 89, 5, 251, 125, 0 }, - { 108, 86, 49, 121, 37, 249, 1 }, - { 95, 111, 208, 77, 112, 74, 1 }, - { 207, 210, 79, 70, 53, 27, 0 }, }, - { { 169, 21, 217, 154, 37, 235, 1 }, - { 126, 79, 25, 139, 228, 50, 1 }, - { 235, 210, 44, 205, 212, 74, 1 }, - { 166, 19, 232, 204, 121, 63, 0 }, }, - { { 171, 34, 146, 112, 50, 2, 0 }, - { 152, 98, 74, 42, 2, 57, 0 }, - { 32, 38, 7, 36, 162, 106, 1 }, - { 78, 32, 42, 41, 35, 12, 1 }, }, - { { 169, 55, 228, 166, 33, 245, 1 }, - { 78, 47, 147, 154, 133, 124, 1 }, - { 215, 194, 50, 147, 246, 74, 1 }, - { 159, 80, 172, 228, 250, 57, 0 }, }, - { { 170, 114, 189, 81, 74, 123, 0 }, - { 180, 87, 202, 111, 32, 236, 1 }, - { 111, 41, 69, 94, 167, 42, 1 }, - { 155, 130, 123, 41, 245, 22, 1 }, }, - { { 168, 137, 199, 107, 240, 9, 0 }, - { 8, 182, 97, 75, 174, 39, 0 }, - { 72, 7, 235, 113, 200, 138, 1 }, - { 114, 58, 233, 67, 54, 136, 0 }, }, - { { 170, 213, 171, 110, 131, 212, 1 }, - { 230, 43, 240, 63, 143, 98, 0 }, - { 149, 224, 187, 106, 213, 170, 1 }, - { 35, 120, 254, 7, 234, 51, 1 }, }, - { { 168, 211, 200, 181, 190, 175, 0 }, - { 56, 47, 41, 254, 109, 169, 1 }, - { 122, 190, 214, 137, 229, 138, 1 }, - { 202, 219, 63, 202, 122, 14, 0 }, }, - { { 174, 20, 19, 54, 167, 164, 0 }, - { 217, 107, 48, 57, 195, 32, 1 }, - { 18, 242, 182, 100, 20, 58, 1 }, - { 130, 97, 206, 6, 107, 77, 1 }, }, - { { 173, 100, 135, 249, 112, 220, 1 }, - { 95, 58, 66, 223, 34, 119, 0 }, - { 157, 135, 79, 240, 147, 90, 1 }, - { 119, 34, 125, 161, 46, 125, 0 }, }, - { { 175, 121, 76, 217, 234, 209, 1 }, - { 191, 159, 99, 236, 4, 246, 0 }, - { 197, 171, 205, 153, 79, 122, 1 }, - { 55, 144, 27, 227, 124, 254, 1 }, }, - { { 173, 154, 157, 184, 0, 254, 1 }, - { 55, 235, 8, 155, 40, 126, 1 }, - { 191, 128, 14, 220, 172, 218, 1 }, - { 191, 10, 108, 136, 107, 246, 0 }, }, - { { 175, 156, 136, 245, 213, 82, 0 }, - { 245, 179, 120, 202, 73, 113, 0 }, - { 37, 85, 215, 136, 156, 250, 1 }, - { 71, 73, 41, 143, 102, 215, 1 }, }, - { { 173, 207, 238, 79, 108, 35, 0 }, - { 105, 150, 201, 78, 207, 190, 1 }, - { 98, 27, 121, 59, 249, 218, 1 }, - { 190, 249, 185, 73, 180, 203, 0 }, }, - { { 173, 247, 163, 231, 58, 61, 1 }, - { 75, 39, 194, 255, 175, 249, 1 }, - { 222, 46, 115, 226, 247, 218, 1 }, - { 207, 250, 255, 161, 242, 105, 0 }, }, - { { 178, 65, 252, 215, 31, 187, 0 }, - { 176, 76, 221, 238, 229, 229, 1 }, - { 110, 252, 117, 159, 193, 38, 1 }, - { 211, 211, 187, 221, 153, 6, 1 }, }, - { { 179, 66, 216, 120, 217, 241, 1 }, - { 182, 124, 117, 14, 0, 251, 1 }, - { 199, 205, 143, 13, 161, 102, 1 }, - { 239, 128, 56, 87, 31, 54, 1 }, }, - { { 178, 97, 81, 226, 141, 99, 0 }, - { 132, 100, 127, 141, 196, 160, 1 }, - { 99, 88, 163, 197, 67, 38, 1 }, - { 130, 145, 216, 255, 19, 16, 1 }, }, - { { 179, 99, 173, 194, 60, 10, 1 }, - { 170, 0, 206, 143, 228, 189, 0 }, - { 168, 30, 33, 218, 227, 102, 1 }, - { 94, 147, 248, 185, 128, 42, 1 }, }, - { { 179, 122, 143, 78, 111, 189, 1 }, - { 170, 157, 86, 63, 227, 254, 1 }, - { 222, 251, 57, 120, 175, 102, 1 }, - { 191, 227, 254, 53, 92, 170, 1 }, }, - { { 176, 177, 13, 218, 203, 9, 1 }, - { 50, 21, 118, 169, 172, 166, 0 }, - { 200, 105, 173, 216, 70, 134, 1 }, - { 50, 154, 202, 183, 84, 38, 0 }, }, - { { 176, 187, 235, 133, 79, 183, 0 }, - { 32, 157, 159, 251, 79, 232, 1 }, - { 118, 249, 80, 235, 238, 134, 1 }, - { 139, 249, 111, 252, 220, 130, 0 }, }, - { { 177, 195, 46, 176, 79, 2, 0 }, - { 48, 48, 156, 172, 78, 188, 0 }, - { 32, 121, 6, 186, 97, 198, 1 }, - { 30, 185, 26, 156, 134, 6, 0 }, }, - { { 177, 202, 162, 122, 198, 206, 0 }, - { 20, 184, 236, 62, 234, 58, 0 }, - { 57, 177, 175, 34, 169, 198, 1 }, - { 46, 43, 190, 27, 142, 148, 0 }, }, - { { 180, 119, 47, 73, 43, 245, 0 }, - { 109, 13, 214, 125, 6, 238, 1 }, - { 87, 234, 73, 122, 119, 22, 1 }, - { 187, 176, 95, 53, 216, 91, 0 }, }, - { { 181, 174, 77, 39, 89, 131, 1 }, - { 99, 188, 31, 73, 137, 189, 0 }, - { 224, 205, 114, 89, 58, 214, 1 }, - { 94, 200, 201, 124, 30, 227, 0 }, }, - { { 183, 210, 205, 142, 206, 219, 0 }, - { 165, 29, 45, 175, 233, 254, 0 }, - { 109, 185, 184, 217, 165, 246, 1 }, - { 63, 203, 250, 218, 92, 82, 1 }, }, - { { 182, 235, 156, 93, 104, 151, 0 }, - { 185, 220, 78, 94, 13, 238, 0 }, - { 116, 139, 93, 28, 235, 182, 1 }, - { 59, 216, 61, 57, 29, 206, 1 }, }, - { { 180, 244, 103, 243, 78, 87, 0 }, - { 85, 53, 207, 253, 202, 228, 0 }, - { 117, 57, 103, 243, 23, 150, 1 }, - { 19, 169, 223, 249, 214, 85, 0 }, }, - { { 184, 15, 212, 222, 49, 7, 1 }, - { 90, 198, 93, 154, 133, 47, 0 }, - { 240, 70, 61, 149, 248, 14, 1 }, - { 122, 80, 172, 221, 49, 173, 0 }, }, - { { 184, 57, 126, 65, 128, 2, 0 }, - { 32, 195, 239, 72, 6, 36, 0 }, - { 32, 0, 193, 63, 78, 14, 1 }, - { 18, 48, 9, 123, 225, 130, 0 }, }, - { { 184, 56, 131, 182, 233, 190, 0 }, - { 24, 187, 62, 155, 163, 224, 1 }, - { 62, 203, 182, 224, 142, 14, 1 }, - { 131, 226, 236, 190, 110, 140, 0 }, }, - { { 184, 108, 6, 172, 40, 232, 0 }, - { 76, 170, 6, 140, 35, 166, 1 }, - { 11, 138, 26, 176, 27, 14, 1 }, - { 178, 226, 24, 176, 42, 153, 0 }, }, - { { 185, 136, 183, 154, 126, 192, 1 }, - { 30, 218, 132, 171, 202, 183, 0 }, - { 129, 191, 44, 246, 136, 206, 1 }, - { 118, 169, 234, 144, 173, 188, 0 }, }, - { { 184, 156, 165, 183, 60, 206, 0 }, - { 92, 171, 140, 219, 233, 165, 0 }, - { 57, 158, 118, 210, 156, 142, 1 }, - { 82, 203, 237, 152, 234, 157, 0 }, }, - { { 186, 207, 131, 167, 229, 28, 1 }, - { 202, 178, 52, 223, 239, 104, 0 }, - { 156, 83, 242, 224, 249, 174, 1 }, - { 11, 123, 253, 150, 38, 169, 1 }, }, - { { 184, 231, 17, 147, 88, 172, 1 }, - { 82, 90, 6, 221, 172, 169, 1 }, - { 154, 141, 100, 196, 115, 142, 1 }, - { 202, 154, 221, 176, 45, 37, 0 }, }, - { { 189, 114, 116, 100, 13, 206, 1 }, - { 7, 107, 223, 28, 97, 188, 0 }, - { 185, 216, 19, 23, 39, 94, 1 }, - { 30, 195, 28, 125, 235, 112, 0 }, }, - { { 188, 125, 134, 57, 75, 186, 1 }, - { 83, 187, 30, 110, 38, 230, 1 }, - { 174, 233, 78, 48, 223, 30, 1 }, - { 179, 178, 59, 60, 110, 229, 0 }, }, - { { 195, 30, 73, 175, 1, 169, 1 }, - { 226, 173, 17, 193, 177, 58, 1 }, - { 202, 192, 122, 201, 60, 97, 1 }, - { 174, 70, 193, 196, 90, 163, 1 }, }, - { { 192, 46, 91, 239, 41, 95, 0 }, - { 108, 228, 91, 209, 179, 234, 0 }, - { 125, 74, 123, 237, 58, 1, 1 }, - { 43, 230, 197, 237, 19, 155, 0 }, }, - { { 193, 78, 242, 15, 34, 121, 1 }, - { 78, 196, 129, 102, 179, 122, 1 }, - { 207, 34, 120, 39, 185, 65, 1 }, - { 175, 102, 179, 64, 145, 185, 0 }, }, - { { 193, 129, 72, 108, 154, 70, 1 }, - { 38, 32, 105, 48, 29, 179, 0 }, - { 177, 44, 155, 9, 64, 193, 1 }, - { 102, 220, 6, 75, 2, 50, 0 }, }, - { { 193, 153, 177, 237, 205, 191, 1 }, - { 2, 253, 248, 211, 125, 242, 1 }, - { 254, 217, 219, 198, 204, 193, 1 }, - { 167, 223, 101, 143, 223, 160, 0 }, }, - { { 193, 146, 177, 38, 19, 223, 1 }, - { 6, 109, 152, 51, 185, 121, 0 }, - { 253, 228, 50, 70, 164, 193, 1 }, - { 79, 78, 230, 12, 219, 48, 0 }, }, - { { 195, 183, 213, 56, 210, 51, 1 }, - { 210, 117, 43, 35, 28, 127, 1 }, - { 230, 37, 142, 85, 246, 225, 1 }, - { 255, 28, 98, 106, 87, 37, 1 }, }, - { { 193, 215, 25, 188, 235, 129, 1 }, - { 122, 125, 48, 165, 29, 186, 0 }, - { 192, 235, 158, 204, 117, 193, 1 }, - { 46, 220, 82, 134, 95, 47, 0 }, }, - { { 193, 246, 67, 78, 186, 232, 1 }, - { 78, 9, 99, 37, 187, 187, 1 }, - { 139, 174, 185, 97, 55, 193, 1 }, - { 238, 238, 210, 99, 72, 57, 0 }, }, - { { 196, 56, 145, 7, 35, 108, 1 }, - { 15, 193, 18, 115, 177, 32, 1 }, - { 155, 98, 112, 68, 142, 17, 1 }, - { 130, 70, 231, 36, 65, 248, 0 }, }, - { { 198, 77, 74, 227, 205, 183, 0 }, - { 225, 188, 121, 212, 214, 224, 1 }, - { 118, 217, 227, 169, 89, 49, 1 }, - { 131, 181, 149, 207, 30, 195, 1 }, }, - { { 199, 83, 172, 246, 95, 75, 1 }, - { 183, 53, 216, 166, 245, 189, 0 }, - { 233, 125, 55, 154, 229, 113, 1 }, - { 94, 215, 178, 141, 214, 118, 1 }, }, - { { 197, 126, 74, 113, 2, 75, 0 }, - { 117, 165, 75, 100, 50, 56, 0 }, - { 105, 32, 71, 41, 63, 81, 1 }, - { 14, 38, 19, 105, 82, 215, 0 }, }, - { { 198, 116, 217, 128, 138, 199, 1 }, - { 231, 77, 43, 183, 16, 160, 0 }, - { 241, 168, 128, 205, 151, 49, 1 }, - { 2, 132, 118, 234, 89, 115, 1 }, }, - { { 197, 136, 152, 47, 230, 202, 1 }, - { 47, 248, 40, 98, 249, 50, 0 }, - { 169, 179, 250, 12, 136, 209, 1 }, - { 38, 79, 163, 10, 15, 250, 0 }, }, - { { 197, 174, 39, 8, 53, 94, 1 }, - { 79, 128, 154, 17, 122, 127, 0 }, - { 189, 86, 8, 114, 58, 209, 1 }, - { 127, 47, 68, 44, 128, 249, 0 }, }, - { { 199, 188, 103, 248, 187, 33, 1 }, - { 219, 165, 243, 161, 26, 183, 1 }, - { 194, 110, 143, 243, 30, 241, 1 }, - { 246, 172, 66, 231, 210, 237, 1 }, }, - { { 196, 190, 140, 164, 243, 99, 0 }, - { 109, 181, 58, 162, 25, 45, 1 }, - { 99, 103, 146, 152, 190, 145, 1 }, - { 218, 76, 34, 174, 86, 219, 0 }, }, - { { 203, 15, 36, 114, 82, 53, 0 }, - { 208, 182, 192, 48, 148, 125, 1 }, - { 86, 37, 39, 18, 120, 105, 1 }, - { 223, 20, 134, 1, 182, 133, 1 }, }, - { { 201, 72, 89, 111, 111, 39, 1 }, - { 42, 246, 89, 117, 209, 178, 1 }, - { 242, 123, 123, 77, 9, 73, 1 }, - { 166, 197, 215, 77, 55, 170, 0 }, }, - { { 200, 85, 15, 64, 161, 129, 0 }, - { 104, 15, 112, 5, 22, 36, 0 }, - { 64, 194, 129, 120, 85, 9, 1 }, - { 18, 52, 80, 7, 120, 11, 0 }, }, - { { 203, 90, 139, 223, 86, 169, 0 }, - { 176, 159, 64, 231, 243, 59, 1 }, - { 74, 181, 125, 232, 173, 105, 1 }, - { 238, 103, 243, 129, 124, 134, 1 }, }, - { { 200, 115, 24, 175, 214, 16, 0 }, - { 32, 115, 34, 228, 213, 107, 0 }, - { 4, 53, 250, 140, 103, 9, 1 }, - { 107, 85, 147, 162, 103, 2, 0 }, }, - { { 201, 159, 158, 95, 56, 56, 0 }, - { 120, 195, 64, 66, 191, 255, 1 }, - { 14, 14, 125, 60, 252, 201, 1 }, - { 255, 254, 161, 1, 97, 143, 0 }, }, - { { 202, 191, 51, 44, 49, 240, 0 }, - { 204, 235, 146, 1, 31, 107, 1 }, - { 7, 198, 26, 102, 126, 169, 1 }, - { 235, 124, 64, 36, 235, 153, 1 }, }, - { { 201, 233, 181, 7, 221, 84, 0 }, - { 4, 210, 178, 87, 221, 245, 0 }, - { 21, 93, 240, 86, 203, 201, 1 }, - { 87, 221, 245, 38, 165, 144, 0 }, }, - { { 203, 240, 30, 59, 146, 129, 0 }, - { 176, 111, 34, 100, 154, 55, 0 }, - { 64, 164, 238, 60, 7, 233, 1 }, - { 118, 44, 147, 34, 123, 6, 1 }, }, - { { 204, 2, 72, 129, 217, 10, 0 }, - { 33, 18, 57, 192, 48, 169, 0 }, - { 40, 77, 192, 137, 32, 25, 1 }, - { 74, 134, 1, 206, 36, 66, 0 }, }, - { { 206, 44, 78, 124, 45, 3, 1 }, - { 251, 166, 91, 0, 83, 166, 0 }, - { 224, 90, 31, 57, 26, 57, 1 }, - { 50, 229, 0, 109, 50, 239, 1 }, }, - { { 205, 131, 179, 65, 153, 204, 1 }, - { 7, 74, 240, 83, 62, 185, 0 }, - { 153, 204, 193, 102, 224, 217, 1 }, - { 78, 190, 101, 7, 169, 112, 0 }, }, - { { 206, 128, 171, 157, 219, 17, 1 }, - { 179, 22, 176, 227, 27, 227, 0 }, - { 196, 109, 220, 234, 128, 185, 1 }, - { 99, 236, 99, 134, 180, 102, 1 }, }, - { { 204, 183, 70, 234, 75, 14, 1 }, - { 67, 51, 91, 176, 190, 174, 0 }, - { 184, 105, 43, 177, 118, 153, 1 }, - { 58, 190, 134, 237, 102, 97, 0 }, }, - { { 207, 228, 35, 113, 192, 123, 1 }, - { 215, 54, 234, 69, 58, 112, 1 }, - { 239, 1, 199, 98, 19, 249, 1 }, - { 135, 46, 81, 43, 182, 117, 1 }, }, - { { 205, 246, 59, 148, 188, 171, 1 }, - { 123, 79, 170, 133, 123, 185, 1 }, - { 234, 158, 148, 238, 55, 217, 1 }, - { 206, 239, 80, 170, 249, 111, 0 }, }, - { { 211, 23, 149, 186, 69, 222, 1 }, - { 214, 121, 28, 147, 244, 126, 0 }, - { 189, 209, 46, 212, 244, 101, 1 }, - { 63, 23, 228, 156, 79, 53, 1 }, }, - { { 208, 58, 34, 105, 80, 179, 0 }, - { 0, 189, 206, 64, 18, 107, 1 }, - { 102, 133, 75, 34, 46, 5, 1 }, - { 235, 36, 1, 57, 222, 128, 0 }, }, - { { 211, 54, 150, 219, 2, 36, 1 }, - { 210, 65, 70, 242, 146, 62, 1 }, - { 146, 32, 109, 180, 182, 101, 1 }, - { 190, 36, 167, 177, 65, 37, 1 }, }, - { { 210, 86, 224, 221, 145, 27, 0 }, - { 208, 5, 253, 198, 49, 107, 0 }, - { 108, 68, 221, 131, 181, 37, 1 }, - { 107, 70, 49, 223, 208, 5, 1 }, }, - { { 210, 188, 170, 228, 3, 129, 0 }, - { 224, 173, 214, 162, 27, 32, 0 }, - { 64, 224, 19, 170, 158, 165, 1 }, - { 2, 108, 34, 181, 218, 131, 1 }, }, - { { 211, 196, 238, 80, 249, 166, 0 }, - { 248, 24, 253, 22, 26, 181, 1 }, - { 50, 207, 133, 59, 145, 229, 1 }, - { 214, 172, 52, 95, 140, 15, 1 }, }, - { { 211, 228, 7, 252, 5, 226, 1 }, - { 214, 40, 94, 133, 91, 54, 1 }, - { 163, 208, 31, 240, 19, 229, 1 }, - { 182, 109, 80, 189, 10, 53, 1 }, }, - { { 211, 252, 28, 167, 191, 2, 0 }, - { 232, 225, 62, 228, 217, 181, 0 }, - { 32, 126, 242, 156, 31, 229, 1 }, - { 86, 205, 147, 190, 67, 139, 1 }, }, - { { 215, 68, 167, 168, 172, 223, 0 }, - { 205, 44, 172, 151, 114, 246, 0 }, - { 125, 154, 138, 242, 145, 117, 1 }, - { 55, 167, 116, 154, 154, 89, 1 }, }, - { { 214, 159, 244, 68, 89, 83, 0 }, - { 197, 213, 221, 2, 29, 237, 0 }, - { 101, 77, 17, 23, 252, 181, 1 }, - { 91, 220, 32, 93, 213, 209, 1 }, }, - { { 212, 175, 147, 230, 193, 68, 0 }, - { 69, 240, 118, 147, 159, 40, 0 }, - { 17, 65, 179, 228, 250, 149, 1 }, - { 10, 124, 228, 183, 7, 209, 0 }, }, - { { 217, 18, 102, 139, 15, 210, 1 }, - { 6, 11, 157, 224, 210, 254, 0 }, - { 165, 248, 104, 179, 36, 77, 1 }, - { 63, 165, 131, 220, 232, 48, 0 }, }, - { { 216, 81, 88, 45, 224, 190, 1 }, - { 42, 123, 45, 84, 53, 98, 1 }, - { 190, 131, 218, 13, 69, 13, 1 }, - { 163, 86, 21, 90, 111, 42, 0 }, }, - { { 216, 99, 102, 115, 129, 229, 0 }, - { 20, 46, 247, 84, 150, 44, 1 }, - { 83, 192, 231, 51, 99, 13, 1 }, - { 154, 52, 149, 119, 186, 20, 0 }, }, - { { 219, 108, 88, 112, 132, 206, 1 }, - { 246, 234, 111, 20, 112, 48, 0 }, - { 185, 144, 135, 13, 27, 109, 1 }, - { 6, 7, 20, 123, 43, 183, 1 }, }, - { { 217, 99, 155, 60, 255, 211, 0 }, - { 60, 126, 62, 39, 87, 251, 0 }, - { 101, 255, 158, 108, 227, 77, 1 }, - { 111, 245, 114, 62, 63, 30, 0 }, }, - { { 216, 138, 98, 229, 71, 244, 0 }, - { 4, 186, 213, 240, 91, 104, 1 }, - { 23, 241, 83, 163, 40, 141, 1 }, - { 139, 109, 7, 213, 174, 144, 0 }, }, - { { 217, 153, 210, 99, 213, 126, 1 }, - { 6, 243, 125, 82, 254, 113, 1 }, - { 191, 85, 227, 37, 204, 205, 1 }, - { 199, 63, 165, 95, 103, 176, 0 }, }, - { { 217, 162, 40, 145, 224, 209, 0 }, - { 60, 30, 166, 192, 24, 120, 0 }, - { 69, 131, 196, 138, 34, 205, 1 }, - { 15, 12, 1, 178, 188, 30, 0 }, }, - { { 219, 244, 50, 154, 65, 205, 0 }, - { 212, 95, 150, 148, 186, 50, 0 }, - { 89, 193, 44, 166, 23, 237, 1 }, - { 38, 46, 148, 180, 253, 21, 1 }, }, - { { 220, 29, 107, 96, 189, 237, 0 }, - { 109, 175, 245, 17, 118, 161, 1 }, - { 91, 222, 131, 107, 92, 29, 1 }, - { 194, 183, 68, 87, 250, 219, 0 }, }, - { { 222, 26, 217, 103, 197, 109, 0 }, - { 165, 247, 117, 83, 241, 40, 1 }, - { 91, 81, 243, 77, 172, 61, 1 }, - { 138, 71, 229, 87, 119, 210, 1 }, }, - { { 221, 114, 161, 214, 214, 204, 1 }, - { 23, 27, 230, 183, 241, 57, 0 }, - { 153, 181, 181, 194, 167, 93, 1 }, - { 78, 71, 246, 179, 236, 116, 0 }, }, - { { 221, 116, 213, 91, 237, 200, 1 }, - { 95, 91, 119, 71, 240, 182, 0 }, - { 137, 219, 237, 85, 151, 93, 1 }, - { 54, 135, 241, 119, 109, 125, 0 }, }, - { { 221, 134, 26, 161, 4, 19, 1 }, - { 99, 102, 12, 192, 90, 120, 0 }, - { 228, 16, 66, 172, 48, 221, 1 }, - { 15, 45, 1, 152, 51, 99, 0 }, }, - { { 223, 175, 27, 5, 181, 189, 1 }, - { 235, 206, 54, 81, 127, 121, 1 }, - { 222, 214, 208, 108, 122, 253, 1 }, - { 207, 127, 69, 54, 57, 235, 1 }, }, - { { 222, 176, 237, 214, 204, 22, 1 }, - { 179, 19, 239, 147, 217, 228, 0 }, - { 180, 25, 181, 219, 134, 189, 1 }, - { 19, 205, 228, 251, 228, 102, 1 }, }, - { { 223, 230, 10, 66, 93, 241, 0 }, - { 229, 30, 86, 4, 218, 249, 1 }, - { 71, 221, 33, 40, 51, 253, 1 }, - { 207, 173, 144, 53, 60, 83, 1 }, }, - { { 221, 251, 88, 81, 243, 143, 0 }, - { 57, 223, 127, 116, 60, 57, 0 }, - { 120, 231, 197, 13, 111, 221, 1 }, - { 78, 30, 23, 127, 125, 206, 0 }, }, - { { 227, 22, 68, 69, 140, 160, 0 }, - { 192, 9, 97, 72, 81, 188, 1 }, - { 2, 152, 209, 17, 52, 99, 1 }, - { 158, 197, 9, 67, 72, 1, 1 }, }, - { { 226, 26, 171, 99, 248, 21, 1 }, - { 170, 181, 224, 91, 146, 233, 0 }, - { 212, 15, 227, 106, 172, 35, 1 }, - { 75, 164, 237, 3, 214, 170, 1 }, }, - { { 226, 90, 168, 144, 16, 221, 1 }, - { 182, 141, 128, 158, 48, 105, 0 }, - { 221, 132, 4, 138, 173, 35, 1 }, - { 75, 6, 60, 128, 216, 182, 1 }, }, - { { 224, 126, 198, 224, 106, 118, 1 }, - { 78, 177, 75, 190, 18, 236, 1 }, - { 183, 43, 3, 177, 191, 3, 1 }, - { 155, 164, 62, 233, 70, 185, 0 }, }, - { { 225, 117, 204, 107, 230, 146, 0 }, - { 104, 57, 107, 110, 212, 118, 0 }, - { 36, 179, 235, 25, 215, 67, 1 }, - { 55, 21, 187, 107, 78, 11, 0 }, }, - { { 224, 221, 231, 62, 185, 106, 0 }, - { 92, 161, 185, 15, 191, 167, 1 }, - { 43, 78, 190, 115, 221, 131, 1 }, - { 242, 254, 248, 78, 194, 157, 0 }, }, - { { 231, 26, 89, 61, 43, 68, 0 }, - { 189, 225, 17, 121, 17, 186, 0 }, - { 17, 106, 94, 77, 44, 115, 1 }, - { 46, 196, 79, 68, 67, 222, 1 }, }, - { { 230, 61, 186, 78, 33, 23, 0 }, - { 233, 197, 218, 26, 151, 98, 0 }, - { 116, 66, 57, 46, 222, 51, 1 }, - { 35, 116, 172, 45, 209, 203, 1 }, }, - { { 231, 80, 110, 107, 241, 111, 0 }, - { 173, 53, 249, 92, 178, 55, 1 }, - { 123, 71, 235, 59, 5, 115, 1 }, - { 246, 38, 157, 79, 214, 90, 1 }, }, - { { 229, 83, 212, 72, 59, 179, 0 }, - { 9, 77, 89, 46, 20, 255, 1 }, - { 102, 238, 9, 21, 229, 83, 1 }, - { 255, 148, 58, 77, 89, 72, 0 }, }, - { { 228, 120, 9, 177, 15, 166, 1 }, - { 51, 169, 26, 253, 80, 160, 1 }, - { 178, 248, 70, 200, 15, 19, 1 }, - { 130, 133, 95, 172, 74, 230, 0 }, }, - { { 229, 122, 161, 185, 186, 74, 1 }, - { 31, 161, 170, 239, 48, 187, 0 }, - { 169, 46, 206, 194, 175, 83, 1 }, - { 110, 134, 123, 170, 194, 252, 0 }, }, - { { 231, 124, 180, 146, 88, 174, 1 }, - { 211, 217, 138, 158, 176, 181, 1 }, - { 186, 141, 36, 150, 159, 115, 1 }, - { 214, 134, 188, 168, 205, 229, 1 }, }, - { { 230, 164, 245, 240, 132, 66, 1 }, - { 215, 96, 235, 139, 88, 36, 0 }, - { 161, 16, 135, 215, 146, 179, 1 }, - { 18, 13, 104, 235, 131, 117, 1 }, }, - { { 229, 213, 42, 118, 142, 25, 1 }, - { 115, 37, 224, 44, 255, 240, 0 }, - { 204, 56, 183, 42, 85, 211, 1 }, - { 7, 255, 154, 3, 210, 103, 0 }, }, - { { 231, 215, 202, 210, 228, 123, 1 }, - { 255, 21, 105, 142, 254, 120, 1 }, - { 239, 19, 165, 169, 245, 243, 1 }, - { 143, 63, 184, 203, 84, 127, 1 }, }, - { { 228, 239, 89, 211, 239, 61, 1 }, - { 123, 212, 115, 253, 252, 232, 1 }, - { 222, 123, 229, 205, 123, 147, 1 }, - { 139, 159, 223, 231, 21, 239, 0 }, }, - { { 235, 27, 228, 239, 142, 205, 0 }, - { 132, 175, 225, 250, 245, 190, 0 }, - { 89, 184, 251, 147, 236, 107, 1 }, - { 62, 215, 175, 195, 250, 144, 1 }, }, - { { 233, 50, 9, 4, 85, 129, 1 }, - { 34, 31, 18, 9, 81, 57, 0 }, - { 192, 213, 16, 72, 38, 75, 1 }, - { 78, 69, 72, 36, 124, 34, 0 }, }, - { { 235, 52, 254, 217, 172, 58, 1 }, - { 250, 67, 235, 202, 114, 246, 1 }, - { 174, 26, 205, 191, 150, 107, 1 }, - { 183, 167, 41, 235, 225, 47, 1 }, }, - { { 234, 78, 19, 245, 78, 30, 0 }, - { 208, 242, 72, 253, 115, 232, 0 }, - { 60, 57, 87, 228, 57, 43, 1 }, - { 11, 231, 95, 137, 39, 133, 1 }, }, - { { 233, 176, 103, 32, 6, 254, 0 }, - { 4, 43, 139, 57, 122, 116, 1 }, - { 63, 176, 2, 115, 6, 203, 1 }, - { 151, 47, 78, 104, 234, 16, 0 }, }, - { { 234, 213, 177, 80, 109, 191, 0 }, - { 216, 95, 216, 31, 124, 224, 1 }, - { 126, 219, 5, 70, 213, 171, 1 }, - { 131, 159, 124, 13, 253, 13, 1 }, }, - { { 239, 10, 161, 134, 54, 174, 0 }, - { 137, 138, 136, 187, 241, 57, 1 }, - { 58, 182, 48, 194, 168, 123, 1 }, - { 206, 71, 238, 136, 168, 200, 1 }, }, - { { 237, 54, 239, 15, 39, 238, 1 }, - { 111, 11, 155, 123, 243, 62, 1 }, - { 187, 242, 120, 123, 182, 91, 1 }, - { 190, 103, 239, 108, 232, 123, 0 }, }, - { { 237, 74, 130, 29, 33, 213, 0 }, - { 29, 142, 16, 94, 19, 122, 0 }, - { 85, 194, 92, 32, 169, 91, 1 }, - { 47, 100, 61, 4, 56, 220, 0 }, }, - { { 236, 96, 189, 109, 140, 6, 0 }, - { 33, 98, 234, 95, 81, 166, 0 }, - { 48, 24, 219, 94, 131, 27, 1 }, - { 50, 197, 125, 43, 163, 66, 0 }, }, - { { 239, 130, 202, 100, 252, 71, 0 }, - { 173, 54, 105, 26, 91, 185, 0 }, - { 113, 31, 147, 41, 160, 251, 1 }, - { 78, 237, 44, 75, 54, 90, 1 }, }, - { { 238, 161, 127, 189, 151, 92, 0 }, - { 181, 98, 179, 249, 127, 103, 0 }, - { 29, 116, 222, 255, 66, 187, 1 }, - { 115, 127, 79, 230, 163, 86, 1 }, }, - { { 238, 209, 152, 137, 82, 229, 1 }, - { 167, 95, 0, 254, 28, 35, 1 }, - { 211, 165, 72, 140, 197, 187, 1 }, - { 226, 28, 63, 128, 125, 114, 1 }, }, - { { 241, 9, 85, 233, 4, 138, 1 }, - { 2, 232, 77, 201, 116, 54, 0 }, - { 168, 144, 75, 213, 72, 71, 1 }, - { 54, 23, 73, 217, 11, 160, 0 }, }, - { { 243, 42, 138, 178, 12, 104, 1 }, - { 182, 160, 6, 138, 242, 184, 1 }, - { 139, 24, 38, 168, 170, 103, 1 }, - { 142, 167, 168, 176, 2, 182, 1 }, }, - { { 243, 71, 148, 129, 100, 1, 1 }, - { 202, 84, 4, 206, 84, 60, 0 }, - { 192, 19, 64, 148, 241, 103, 1 }, - { 30, 21, 57, 144, 21, 41, 1 }, }, - { { 243, 136, 79, 37, 132, 41, 1 }, - { 162, 164, 37, 73, 123, 52, 1 }, - { 202, 16, 210, 121, 8, 231, 1 }, - { 150, 111, 73, 82, 18, 162, 1 }, }, - { { 240, 162, 31, 6, 126, 77, 1 }, - { 46, 84, 6, 57, 251, 173, 0 }, - { 217, 63, 48, 124, 34, 135, 1 }, - { 90, 239, 206, 48, 21, 58, 0 }, }, - { { 243, 170, 11, 255, 165, 205, 0 }, - { 188, 172, 118, 217, 251, 58, 0 }, - { 89, 210, 255, 232, 42, 231, 1 }, - { 46, 111, 205, 183, 26, 158, 1 }, }, - { { 240, 175, 124, 121, 142, 228, 0 }, - { 116, 232, 231, 120, 92, 174, 1 }, - { 19, 184, 207, 31, 122, 135, 1 }, - { 186, 157, 15, 115, 139, 151, 0 }, }, - { { 240, 217, 16, 212, 202, 31, 1 }, - { 18, 213, 108, 188, 61, 224, 0 }, - { 252, 41, 149, 132, 77, 135, 1 }, - { 3, 222, 30, 155, 85, 164, 0 }, }, - { { 245, 75, 179, 178, 85, 245, 1 }, - { 23, 252, 148, 159, 214, 121, 1 }, - { 215, 213, 38, 230, 233, 87, 1 }, - { 207, 53, 252, 148, 159, 244, 0 }, }, - { { 246, 81, 96, 41, 26, 234, 1 }, - { 135, 41, 141, 108, 52, 163, 1 }, - { 171, 172, 74, 3, 69, 55, 1 }, - { 226, 150, 27, 88, 202, 112, 1 }, }, - { { 246, 117, 82, 145, 217, 185, 1 }, - { 211, 93, 55, 204, 54, 225, 1 }, - { 206, 205, 196, 165, 87, 55, 1 }, - { 195, 182, 25, 246, 93, 101, 1 }, }, - { { 245, 114, 198, 173, 192, 65, 0 }, - { 5, 53, 39, 206, 19, 62, 0 }, - { 65, 1, 218, 177, 167, 87, 1 }, - { 62, 100, 57, 242, 86, 80, 0 }, }, - { { 247, 124, 210, 85, 227, 70, 0 }, - { 221, 209, 127, 126, 19, 48, 0 }, - { 49, 99, 213, 37, 159, 119, 1 }, - { 6, 100, 63, 127, 69, 221, 1 }, }, - { { 246, 132, 78, 31, 171, 28, 0 }, - { 249, 0, 53, 120, 187, 230, 0 }, - { 28, 106, 252, 57, 16, 183, 1 }, - { 51, 238, 143, 86, 0, 79, 1 }, }, - { { 248, 61, 136, 57, 165, 1, 1 }, - { 122, 167, 54, 74, 84, 34, 0 }, - { 192, 82, 206, 8, 222, 15, 1 }, - { 34, 21, 41, 54, 114, 175, 0 }, }, - { { 251, 54, 195, 223, 220, 215, 1 }, - { 214, 31, 111, 219, 211, 251, 0 }, - { 245, 157, 253, 225, 182, 111, 1 }, - { 111, 229, 237, 251, 124, 53, 1 }, }, - { { 248, 76, 172, 3, 76, 20, 1 }, - { 98, 146, 132, 94, 208, 228, 0 }, - { 148, 25, 96, 26, 153, 15, 1 }, - { 19, 133, 189, 16, 164, 163, 0 }, }, - { { 251, 160, 208, 185, 211, 75, 1 }, - { 150, 118, 63, 234, 56, 51, 0 }, - { 233, 101, 206, 133, 130, 239, 1 }, - { 102, 14, 43, 254, 55, 52, 1 }, }, - { { 250, 195, 132, 204, 125, 54, 1 }, - { 138, 18, 92, 158, 93, 239, 1 }, - { 182, 95, 25, 144, 225, 175, 1 }, - { 251, 221, 60, 157, 36, 40, 1 }, }, - { { 249, 231, 61, 60, 30, 97, 1 }, - { 118, 102, 134, 45, 93, 191, 1 }, - { 195, 60, 30, 94, 115, 207, 1 }, - { 254, 221, 90, 48, 179, 55, 0 }, }, - { { 248, 255, 88, 101, 6, 119, 1 }, - { 102, 231, 79, 124, 93, 104, 1 }, - { 247, 48, 83, 13, 127, 143, 1 }, - { 139, 93, 31, 121, 115, 179, 0 }, }, - { { 253, 11, 219, 85, 100, 56, 1 }, - { 59, 210, 69, 75, 119, 120, 1 }, - { 142, 19, 85, 109, 232, 95, 1 }, - { 143, 119, 105, 81, 37, 238, 0 }, }, - { { 253, 22, 174, 228, 229, 62, 1 }, - { 107, 51, 252, 154, 115, 124, 1 }, - { 190, 83, 147, 186, 180, 95, 1 }, - { 159, 103, 44, 159, 230, 107, 0 }, }, - { { 254, 73, 163, 120, 194, 52, 0 }, - { 145, 178, 228, 63, 22, 98, 1 }, - { 22, 33, 143, 98, 201, 63, 1 }, - { 163, 52, 126, 19, 166, 196, 1 }, }, - { { 253, 132, 226, 198, 107, 168, 1 }, - { 75, 26, 213, 170, 187, 176, 1 }, - { 138, 235, 49, 163, 144, 223, 1 }, - { 134, 238, 170, 213, 172, 105, 0 }, }, - { { 252, 149, 79, 148, 230, 207, 0 }, - { 125, 31, 45, 185, 127, 36, 0 }, - { 121, 179, 148, 249, 84, 159, 1 }, - { 18, 127, 78, 218, 124, 95, 0 }, }, - { { 254, 165, 35, 88, 48, 164, 1 }, - { 219, 10, 198, 25, 30, 35, 1 }, - { 146, 134, 13, 98, 82, 191, 1 }, - { 226, 60, 76, 49, 168, 109, 1 }, }, - { { 254, 168, 217, 255, 176, 118, 0 }, - { 189, 226, 111, 219, 153, 99, 1 }, - { 55, 6, 255, 205, 138, 191, 1 }, - { 227, 76, 237, 251, 35, 222, 1 }, }, - { { 255, 195, 135, 255, 162, 252, 1 }, - { 159, 42, 100, 255, 191, 126, 1 }, - { 159, 162, 255, 240, 225, 255, 1 }, - { 191, 126, 255, 147, 42, 124, 1 }, }, - { { 95, 114, 124, 241, 17, 248, 0 }, - { 181, 107, 215, 196, 48, 93, 1 }, - { 15, 196, 71, 159, 39, 125, 0 }, - { 221, 6, 17, 245, 235, 86, 1 }, }, - { { 135, 81, 63, 164, 61, 190, 1 }, - { 171, 105, 152, 149, 103, 245, 1 }, - { 190, 222, 18, 254, 69, 112, 1 }, - { 215, 243, 84, 140, 203, 106, 1 }, }, - { { 198, 147, 77, 53, 31, 189, 0 }, - { 177, 45, 17, 113, 125, 237, 1 }, - { 94, 252, 86, 89, 100, 177, 1 }, - { 219, 223, 71, 68, 90, 70, 1 }, }, - { { 231, 230, 150, 226, 6, 159, 1 }, - { 195, 108, 74, 190, 250, 124, 0 }, - { 252, 176, 35, 180, 179, 243, 1 }, - { 31, 47, 190, 169, 27, 97, 1 }, }, }; -} diff --git a/modules/aruco/test/test_aruco_tutorial.cpp b/modules/aruco/test/test_aruco_tutorial.cpp new file mode 100644 index 00000000000..11d4595ff28 --- /dev/null +++ b/modules/aruco/test/test_aruco_tutorial.cpp @@ -0,0 +1,216 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#include "test_precomp.hpp" +#include "opencv2/objdetect/aruco_detector.hpp" + +namespace opencv_test { namespace { + + +TEST(CV_ArucoTutorial, can_find_singlemarkersoriginal) +{ + string img_path = cvtest::findDataFile("singlemarkersoriginal.jpg", false); + Mat image = imread(img_path); + aruco::ArucoDetector detector(aruco::getPredefinedDictionary(aruco::DICT_6X6_250)); + + vector ids; + vector > corners, rejected; + const size_t N = 6ull; + // corners of ArUco markers with indices goldCornersIds + const int goldCorners[N][8] = { {359,310, 404,310, 410,350, 362,350}, {427,255, 469,256, 477,289, 434,288}, + {233,273, 190,273, 196,241, 237,241}, {298,185, 334,186, 335,212, 297,211}, + {425,163, 430,186, 394,186, 390,162}, {195,155, 230,155, 227,178, 190,178} }; + const int goldCornersIds[N] = { 40, 98, 62, 23, 124, 203}; + map mapGoldCorners; + for (size_t i = 0; i < N; i++) + mapGoldCorners[goldCornersIds[i]] = goldCorners[i]; + + detector.detectMarkers(image, corners, ids, rejected); + + ASSERT_EQ(N, ids.size()); + for (size_t i = 0; i < N; i++) + { + int arucoId = ids[i]; + ASSERT_EQ(4ull, corners[i].size()); + ASSERT_TRUE(mapGoldCorners.find(arucoId) != mapGoldCorners.end()); + for (int j = 0; j < 4; j++) + { + EXPECT_NEAR(static_cast(mapGoldCorners[arucoId][j * 2]), corners[i][j].x, 1.f); + EXPECT_NEAR(static_cast(mapGoldCorners[arucoId][j * 2 + 1]), corners[i][j].y, 1.f); + } + } +} + +TEST(CV_ArucoTutorial, can_find_gboriginal) +{ + string imgPath = cvtest::findDataFile("gboriginal.png", false); + Mat image = imread(imgPath); + string dictPath = cvtest::findDataFile("tutorial_dict.yml", false); + aruco::Dictionary dictionary; + + FileStorage fs(dictPath, FileStorage::READ); + dictionary.aruco::Dictionary::readDictionary(fs.root()); // set marker from tutorial_dict.yml + aruco::DetectorParameters detectorParams; + + aruco::ArucoDetector detector(dictionary, detectorParams); + + vector ids; + vector > corners, rejected; + const size_t N = 35ull; + // corners of ArUco markers with indices 0, 1, ..., 34 + const int goldCorners[N][8] = { {252,74, 286,81, 274,102, 238,95}, {295,82, 330,89, 319,111, 282,104}, + {338,91, 375,99, 365,121, 327,113}, {383,100, 421,107, 412,130, 374,123}, + {429,109, 468,116, 461,139, 421,132}, {235,100, 270,108, 257,130, 220,122}, + {279,109, 316,117, 304,140, 266,133}, {324,119, 362,126, 352,150, 313,143}, + {371,128, 410,136, 400,161, 360,152}, {418,139, 459,145, 451,170, 410,163}, + {216,128, 253,136, 239,161, 200,152}, {262,138, 300,146, 287,172, 248,164}, + {309,148, 349,156, 337,183, 296,174}, {358,158, 398,167, 388,194, 346,185}, + {407,169, 449,176, 440,205, 397,196}, {196,158, 235,168, 218,195, 179,185}, + {243,170, 283,178, 269,206, 228,197}, {293,180, 334,190, 321,218, 279,209}, + {343,192, 385,200, 374,230, 330,220}, {395,203, 438,211, 429,241, 384,233}, + {174,192, 215,201, 197,231, 156,221}, {223,204, 265,213, 249,244, 207,234}, + {275,215, 317,225, 303,257, 259,246}, {327,227, 371,238, 359,270, 313,259}, + {381,240, 426,249, 416,282, 369,273}, {151,228, 193,238, 173,271, 130,260}, + {202,241, 245,251, 228,285, 183,274}, {255,254, 300,264, 284,299, 238,288}, + {310,267, 355,278, 342,314, 295,302}, {366,281, 413,290, 402,327, 353,317}, + {125,267, 168,278, 147,314, 102,303}, {178,281, 223,293, 204,330, 157,317}, + {233,296, 280,307, 263,346, 214,333}, {291,310, 338,322, 323,363, 274,349}, + {349,325, 399,336, 386,378, 335,366} }; + map mapGoldCorners; + for (int i = 0; i < static_cast(N); i++) + mapGoldCorners[i] = goldCorners[i]; + + detector.detectMarkers(image, corners, ids, rejected); + + ASSERT_EQ(N, ids.size()); + for (size_t i = 0; i < N; i++) + { + int arucoId = ids[i]; + ASSERT_EQ(4ull, corners[i].size()); + ASSERT_TRUE(mapGoldCorners.find(arucoId) != mapGoldCorners.end()); + for (int j = 0; j < 4; j++) + { + EXPECT_NEAR(static_cast(mapGoldCorners[arucoId][j*2]), corners[i][j].x, 1.f); + EXPECT_NEAR(static_cast(mapGoldCorners[arucoId][j*2+1]), corners[i][j].y, 1.f); + } + } +} + +TEST(CV_ArucoTutorial, can_find_choriginal) +{ + string imgPath = cvtest::findDataFile("choriginal.jpg", false); + Mat image = imread(imgPath); + aruco::ArucoDetector detector(aruco::getPredefinedDictionary(aruco::DICT_6X6_250)); + + vector< int > ids; + vector< vector< Point2f > > corners, rejected; + const size_t N = 17ull; + // corners of aruco markers with indices goldCornersIds + const int goldCorners[N][8] = { {268,77, 290,80, 286,97, 263,94}, {360,90, 382,93, 379,111, 357,108}, + {211,106, 233,109, 228,127, 205,123}, {306,120, 328,124, 325,142, 302,138}, + {402,135, 425,139, 423,157, 400,154}, {247,152, 271,155, 267,174, 242,171}, + {347,167, 371,171, 369,191, 344,187}, {185,185, 209,189, 203,210, 178,206}, + {288,201, 313,206, 309,227, 284,223}, {393,218, 418,222, 416,245, 391,241}, + {223,240, 250,244, 244,268, 217,263}, {333,258, 359,262, 356,286, 329,282}, + {152,281, 179,285, 171,312, 143,307}, {267,300, 294,305, 289,331, 261,327}, + {383,319, 410,324, 408,351, 380,347}, {194,347, 223,352, 216,382, 186,377}, + {315,368, 345,373, 341,403, 310,398} }; + map mapGoldCorners; + for (int i = 0; i < static_cast(N); i++) + mapGoldCorners[i] = goldCorners[i]; + + detector.detectMarkers(image, corners, ids, rejected); + + ASSERT_EQ(N, ids.size()); + for (size_t i = 0; i < N; i++) + { + int arucoId = ids[i]; + ASSERT_EQ(4ull, corners[i].size()); + ASSERT_TRUE(mapGoldCorners.find(arucoId) != mapGoldCorners.end()); + for (int j = 0; j < 4; j++) + { + EXPECT_NEAR(static_cast(mapGoldCorners[arucoId][j * 2]), corners[i][j].x, 1.f); + EXPECT_NEAR(static_cast(mapGoldCorners[arucoId][j * 2 + 1]), corners[i][j].y, 1.f); + } + } +} + +TEST(CV_ArucoTutorial, can_find_chocclusion) +{ + string imgPath = cvtest::findDataFile("chocclusion_original.jpg", false); + Mat image = imread(imgPath); + aruco::ArucoDetector detector(aruco::getPredefinedDictionary(aruco::DICT_6X6_250)); + + vector< int > ids; + vector< vector< Point2f > > corners, rejected; + const size_t N = 13ull; + // corners of aruco markers with indices goldCornersIds + const int goldCorners[N][8] = { {301,57, 322,62, 317,79, 295,73}, {391,80, 413,85, 408,103, 386,97}, + {242,79, 264,85, 256,102, 234,96}, {334,103, 357,109, 352,126, 329,121}, + {428,129, 451,134, 448,152, 425,146}, {274,128, 296,134, 290,153, 266,147}, + {371,154, 394,160, 390,180, 366,174}, {208,155, 232,161, 223,181, 199,175}, + {309,182, 333,188, 327,209, 302,203}, {411,210, 436,216, 432,238, 407,231}, + {241,212, 267,219, 258,242, 232,235}, {167,244, 194,252, 183,277, 156,269}, + {202,314, 230,322, 220,349, 191,341} }; + map mapGoldCorners; + const int goldCornersIds[N] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 15}; + for (int i = 0; i < static_cast(N); i++) + mapGoldCorners[goldCornersIds[i]] = goldCorners[i]; + + detector.detectMarkers(image, corners, ids, rejected); + + ASSERT_EQ(N, ids.size()); + for (size_t i = 0; i < N; i++) + { + int arucoId = ids[i]; + ASSERT_EQ(4ull, corners[i].size()); + ASSERT_TRUE(mapGoldCorners.find(arucoId) != mapGoldCorners.end()); + for (int j = 0; j < 4; j++) + { + EXPECT_NEAR(static_cast(mapGoldCorners[arucoId][j * 2]), corners[i][j].x, 1.f); + EXPECT_NEAR(static_cast(mapGoldCorners[arucoId][j * 2 + 1]), corners[i][j].y, 1.f); + } + } +} + +TEST(CV_ArucoTutorial, can_find_diamondmarkers) +{ + string imgPath = cvtest::findDataFile("diamondmarkers.png", false); + Mat image = imread(imgPath); + + string dictPath = cvtest::findDataFile("tutorial_dict.yml", false); + aruco::Dictionary dictionary; + FileStorage fs(dictPath, FileStorage::READ); + dictionary.aruco::Dictionary::readDictionary(fs.root()); // set marker from tutorial_dict.yml + + string detectorPath = cvtest::findDataFile("detector_params.yml", false); + fs = FileStorage(detectorPath, FileStorage::READ); + aruco::DetectorParameters detectorParams; + detectorParams.readDetectorParameters(fs.root()); + detectorParams.cornerRefinementMethod = aruco::CORNER_REFINE_APRILTAG; + + aruco::ArucoDetector detector(dictionary, detectorParams); + + vector< int > ids; + vector< vector< Point2f > > corners, rejected; + const size_t N = 12ull; + // corner indices of ArUco markers + const int goldCornersIds[N] = { 4, 12, 11, 3, 12, 10, 12, 10, 10, 11, 2, 11 }; + map counterGoldCornersIds; + for (int i = 0; i < static_cast(N); i++) + counterGoldCornersIds[goldCornersIds[i]]++; + + detector.detectMarkers(image, corners, ids, rejected); + map counterRes; + for (size_t i = 0; i < N; i++) + { + int arucoId = ids[i]; + counterRes[arucoId]++; + } + + ASSERT_EQ(N, ids.size()); + EXPECT_EQ(counterGoldCornersIds, counterRes); // check the number of ArUco markers +} + +}} // namespace diff --git a/modules/aruco/test/test_aruco_utils.hpp b/modules/aruco/test/test_aruco_utils.hpp index 9ae94f789ef..63b307a9c03 100644 --- a/modules/aruco/test/test_aruco_utils.hpp +++ b/modules/aruco/test/test_aruco_utils.hpp @@ -65,14 +65,14 @@ static inline void projectMarker(Mat& img, Ptr board, int markerIn // canonical image Mat markerImg; const int markerSizePixels = 100; - aruco::drawMarker(board->getDictionary(), board->getIds()[markerIndex], markerSizePixels, markerImg, markerBorder); + aruco::generateImageMarker(board->getDictionary(), board->getIds()[markerIndex], markerSizePixels, markerImg, markerBorder); // projected corners Mat distCoeffs(5, 1, CV_64FC1, Scalar::all(0)); vector corners; // get max coordinate of board - Point3f maxCoord = board->getRightBottomBorder(); + Point3f maxCoord = board->getRightBottomCorner(); // copy objPoints vector objPoints = board->getObjPoints()[markerIndex]; // move the marker to the origin @@ -122,6 +122,117 @@ static inline Mat projectBoard(Ptr& board, Mat cameraMatrix, d return img; } +int getBoardPose(InputArrayOfArrays corners, InputArray ids, const Ptr &board, + InputArray cameraMatrix, InputArray distCoeffs, InputOutputArray rvec, + InputOutputArray tvec, bool useExtrinsicGuess = false) { + CV_Assert(corners.total() == ids.total()); + Mat objPoints, imgPoints; // get object and image points for the solvePnP function + board->matchImagePoints(corners, ids, objPoints, imgPoints); + CV_Assert(imgPoints.total() == objPoints.total()); + + if(objPoints.total() == 0) // 0 of the detected markers in board + return 0; + solvePnP(objPoints, imgPoints, cameraMatrix, distCoeffs, rvec, tvec, useExtrinsicGuess); + + // divide by four since all the four corners are concatenated in the array for each marker + return (int)objPoints.total() / 4; +} + +/** Check if a set of 3d points are enough for calibration. Z coordinate is ignored. Only axis parallel lines are considered */ +static bool _arePointsEnoughForPoseEstimation(const std::vector &points) { + if(points.size() < 4) return false; + + std::vector sameXValue; // different x values in points + std::vector sameXCounter; // number of points with the x value in sameXValue + for(unsigned int i = 0; i < points.size(); i++) { + bool found = false; + for(unsigned int j = 0; j < sameXValue.size(); j++) { + if(sameXValue[j] == points[i].x) { + found = true; + sameXCounter[j]++; + } + } + if(!found) { + sameXValue.push_back(points[i].x); + sameXCounter.push_back(1); + } + } + + // count how many x values has more than 2 points + int moreThan2 = 0; + for(unsigned int i = 0; i < sameXCounter.size(); i++) { + if(sameXCounter[i] >= 2) moreThan2++; + } + + // if we have more than 1 two xvalues with more than 2 points, calibration is ok + if(moreThan2 > 1) + return true; + return false; +} + +bool getCharucoBoardPose(InputArray charucoCorners, InputArray charucoIds, const Ptr &board, + InputArray cameraMatrix, InputArray distCoeffs, InputOutputArray rvec, InputOutputArray tvec, + bool useExtrinsicGuess = false) { + CV_Assert((charucoCorners.getMat().total() == charucoIds.getMat().total())); + if(charucoIds.getMat().total() < 4) return false; // need, at least, 4 corners + + std::vector objPoints; + objPoints.reserve(charucoIds.getMat().total()); + for(unsigned int i = 0; i < charucoIds.getMat().total(); i++) { + int currId = charucoIds.getMat().at< int >(i); + CV_Assert(currId >= 0 && currId < (int)board->getChessboardCorners().size()); + objPoints.push_back(board->getChessboardCorners()[currId]); + } + + // points need to be in different lines, check if detected points are enough + if(!_arePointsEnoughForPoseEstimation(objPoints)) return false; + + solvePnP(objPoints, charucoCorners, cameraMatrix, distCoeffs, rvec, tvec, useExtrinsicGuess); + return true; +} + + +/** + * @brief Return object points for the system centered in a middle (by default) or in a top left corner of single + * marker, given the marker length + */ +static Mat _getSingleMarkerObjectPoints(float markerLength, bool use_aruco_ccw_center) { + CV_Assert(markerLength > 0); + Mat objPoints(4, 1, CV_32FC3); + // set coordinate system in the top-left corner of the marker, with Z pointing out + if (use_aruco_ccw_center) { + objPoints.ptr(0)[0] = Vec3f(-markerLength/2.f, markerLength/2.f, 0); + objPoints.ptr(0)[1] = Vec3f(markerLength/2.f, markerLength/2.f, 0); + objPoints.ptr(0)[2] = Vec3f(markerLength/2.f, -markerLength/2.f, 0); + objPoints.ptr(0)[3] = Vec3f(-markerLength/2.f, -markerLength/2.f, 0); + } + else { + objPoints.ptr(0)[0] = Vec3f(0.f, 0.f, 0); + objPoints.ptr(0)[1] = Vec3f(markerLength, 0.f, 0); + objPoints.ptr(0)[2] = Vec3f(markerLength, markerLength, 0); + objPoints.ptr(0)[3] = Vec3f(0.f, markerLength, 0); + } + return objPoints; +} + +void getMarkersPoses(InputArrayOfArrays corners, float markerLength, InputArray cameraMatrix, InputArray distCoeffs, + OutputArray _rvecs, OutputArray _tvecs, OutputArray objPoints = noArray(), + bool use_aruco_ccw_center = true, SolvePnPMethod solvePnPMethod = SolvePnPMethod::SOLVEPNP_ITERATIVE) { + CV_Assert(markerLength > 0); + Mat markerObjPoints = _getSingleMarkerObjectPoints(markerLength, use_aruco_ccw_center); + int nMarkers = (int)corners.total(); + _rvecs.create(nMarkers, 1, CV_64FC3); + _tvecs.create(nMarkers, 1, CV_64FC3); + + Mat rvecs = _rvecs.getMat(), tvecs = _tvecs.getMat(); + for (int i = 0; i < nMarkers; i++) + solvePnP(markerObjPoints, corners.getMat(i), cameraMatrix, distCoeffs, rvecs.at(i), tvecs.at(i), + solvePnPMethod); + + if(objPoints.needed()) + markerObjPoints.convertTo(objPoints, -1); +} + } } diff --git a/modules/aruco/test/test_arucodetection.cpp b/modules/aruco/test/test_arucodetection.cpp deleted file mode 100644 index 78ec99cc054..00000000000 --- a/modules/aruco/test/test_arucodetection.cpp +++ /dev/null @@ -1,814 +0,0 @@ -/* -By downloading, copying, installing or using the software you agree to this -license. If you do not agree to this license, do not download, install, -copy or use the software. - - License Agreement - For Open Source Computer Vision Library - (3-clause BSD License) - -Copyright (C) 2013, OpenCV Foundation, all rights reserved. -Third party copyrights are property of their respective owners. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the names of the copyright holders nor the names of the contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -This software is provided by the copyright holders and contributors "as is" and -any express or implied warranties, including, but not limited to, the implied -warranties of merchantability and fitness for a particular purpose are -disclaimed. In no event shall copyright holders or contributors be liable for -any direct, indirect, incidental, special, exemplary, or consequential damages -(including, but not limited to, procurement of substitute goods or services; -loss of use, data, or profits; or business interruption) however caused -and on any theory of liability, whether in contract, strict liability, -or tort (including negligence or otherwise) arising in any way out of -the use of this software, even if advised of the possibility of such damage. -*/ - -#include "test_precomp.hpp" -#include - -namespace opencv_test { namespace { - -/** - * @brief Draw 2D synthetic markers and detect them - */ -class CV_ArucoDetectionSimple : public cvtest::BaseTest { - public: - CV_ArucoDetectionSimple(); - - protected: - void run(int); -}; - - -CV_ArucoDetectionSimple::CV_ArucoDetectionSimple() {} - - -void CV_ArucoDetectionSimple::run(int) { - aruco::ArucoDetector detector(aruco::getPredefinedDictionary(aruco::DICT_6X6_250)); - - // 20 images - for(int i = 0; i < 20; i++) { - - const int markerSidePixels = 100; - int imageSize = markerSidePixels * 2 + 3 * (markerSidePixels / 2); - - // draw synthetic image and store marker corners and ids - vector< vector< Point2f > > groundTruthCorners; - vector< int > groundTruthIds; - Mat img = Mat(imageSize, imageSize, CV_8UC1, Scalar::all(255)); - for(int y = 0; y < 2; y++) { - for(int x = 0; x < 2; x++) { - Mat marker; - int id = i * 4 + y * 2 + x; - aruco::drawMarker(detector.dictionary, id, markerSidePixels, marker); - Point2f firstCorner = - Point2f(markerSidePixels / 2.f + x * (1.5f * markerSidePixels), - markerSidePixels / 2.f + y * (1.5f * markerSidePixels)); - Mat aux = img.colRange((int)firstCorner.x, (int)firstCorner.x + markerSidePixels) - .rowRange((int)firstCorner.y, (int)firstCorner.y + markerSidePixels); - marker.copyTo(aux); - groundTruthIds.push_back(id); - groundTruthCorners.push_back(vector< Point2f >()); - groundTruthCorners.back().push_back(firstCorner); - groundTruthCorners.back().push_back(firstCorner + Point2f(markerSidePixels - 1, 0)); - groundTruthCorners.back().push_back( - firstCorner + Point2f(markerSidePixels - 1, markerSidePixels - 1)); - groundTruthCorners.back().push_back(firstCorner + Point2f(0, markerSidePixels - 1)); - } - } - if(i % 2 == 1) img.convertTo(img, CV_8UC3); - - // detect markers - vector< vector< Point2f > > corners; - vector< int > ids; - - detector.detectMarkers(img, corners, ids); - - // check detection results - for(unsigned int m = 0; m < groundTruthIds.size(); m++) { - int idx = -1; - for(unsigned int k = 0; k < ids.size(); k++) { - if(groundTruthIds[m] == ids[k]) { - idx = (int)k; - break; - } - } - if(idx == -1) { - ts->printf(cvtest::TS::LOG, "Marker not detected"); - ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); - return; - } - - for(int c = 0; c < 4; c++) { - double dist = cv::norm(groundTruthCorners[m][c] - corners[idx][c]); // TODO cvtest - if(dist > 0.001) { - ts->printf(cvtest::TS::LOG, "Incorrect marker corners position"); - ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); - return; - } - } - } - } -} - - -static double deg2rad(double deg) { return deg * CV_PI / 180.; } - -/** - * @brief Get rvec and tvec from yaw, pitch and distance - */ -static void getSyntheticRT(double yaw, double pitch, double distance, Mat &rvec, Mat &tvec) { - - rvec = Mat(3, 1, CV_64FC1); - tvec = Mat(3, 1, CV_64FC1); - - // Rvec - // first put the Z axis aiming to -X (like the camera axis system) - Mat rotZ(3, 1, CV_64FC1); - rotZ.ptr< double >(0)[0] = 0; - rotZ.ptr< double >(0)[1] = 0; - rotZ.ptr< double >(0)[2] = -0.5 * CV_PI; - - Mat rotX(3, 1, CV_64FC1); - rotX.ptr< double >(0)[0] = 0.5 * CV_PI; - rotX.ptr< double >(0)[1] = 0; - rotX.ptr< double >(0)[2] = 0; - - Mat camRvec, camTvec; - composeRT(rotZ, Mat(3, 1, CV_64FC1, Scalar::all(0)), rotX, Mat(3, 1, CV_64FC1, Scalar::all(0)), - camRvec, camTvec); - - // now pitch and yaw angles - Mat rotPitch(3, 1, CV_64FC1); - rotPitch.ptr< double >(0)[0] = 0; - rotPitch.ptr< double >(0)[1] = pitch; - rotPitch.ptr< double >(0)[2] = 0; - - Mat rotYaw(3, 1, CV_64FC1); - rotYaw.ptr< double >(0)[0] = yaw; - rotYaw.ptr< double >(0)[1] = 0; - rotYaw.ptr< double >(0)[2] = 0; - - composeRT(rotPitch, Mat(3, 1, CV_64FC1, Scalar::all(0)), rotYaw, - Mat(3, 1, CV_64FC1, Scalar::all(0)), rvec, tvec); - - // compose both rotations - composeRT(camRvec, Mat(3, 1, CV_64FC1, Scalar::all(0)), rvec, - Mat(3, 1, CV_64FC1, Scalar::all(0)), rvec, tvec); - - // Tvec, just move in z (camera) direction the specific distance - tvec.ptr< double >(0)[0] = 0.; - tvec.ptr< double >(0)[1] = 0.; - tvec.ptr< double >(0)[2] = distance; -} - -/** - * @brief Create a synthetic image of a marker with perspective - */ -static Mat projectMarker(Ptr &dictionary, int id, Mat cameraMatrix, double yaw, - double pitch, double distance, Size imageSize, int markerBorder, - vector< Point2f > &corners, int encloseMarker=0) { - - // canonical image - Mat marker, markerImg; - const int markerSizePixels = 100; - - aruco::drawMarker(dictionary, id, markerSizePixels, marker, markerBorder); - marker.copyTo(markerImg); - - if(encloseMarker){ //to enclose the marker - int enclose = int(marker.rows/4); - markerImg = Mat::zeros(marker.rows+(2*enclose), marker.cols+(enclose*2), CV_8UC1); - - Mat field= markerImg.rowRange(int(enclose), int(markerImg.rows-enclose)) - .colRange(int(0), int(markerImg.cols)); - field.setTo(255); - field= markerImg.rowRange(int(0), int(markerImg.rows)) - .colRange(int(enclose), int(markerImg.cols-enclose)); - field.setTo(255); - - field = markerImg(Rect(enclose,enclose,marker.rows,marker.cols)); - marker.copyTo(field); - } - - // get rvec and tvec for the perspective - Mat rvec, tvec; - getSyntheticRT(yaw, pitch, distance, rvec, tvec); - - const float markerLength = 0.05f; - vector< Point3f > markerObjPoints; - markerObjPoints.push_back(Point3f(-markerLength / 2.f, +markerLength / 2.f, 0)); - markerObjPoints.push_back(markerObjPoints[0] + Point3f(markerLength, 0, 0)); - markerObjPoints.push_back(markerObjPoints[0] + Point3f(markerLength, -markerLength, 0)); - markerObjPoints.push_back(markerObjPoints[0] + Point3f(0, -markerLength, 0)); - - // project markers and draw them - Mat distCoeffs(5, 1, CV_64FC1, Scalar::all(0)); - projectPoints(markerObjPoints, rvec, tvec, cameraMatrix, distCoeffs, corners); - - vector< Point2f > originalCorners; - originalCorners.push_back(Point2f(0+float(encloseMarker*markerSizePixels/4), 0+float(encloseMarker*markerSizePixels/4))); - originalCorners.push_back(originalCorners[0]+Point2f((float)markerSizePixels, 0)); - originalCorners.push_back(originalCorners[0]+Point2f((float)markerSizePixels, (float)markerSizePixels)); - originalCorners.push_back(originalCorners[0]+Point2f(0, (float)markerSizePixels)); - - Mat transformation = getPerspectiveTransform(originalCorners, corners); - - Mat img(imageSize, CV_8UC1, Scalar::all(255)); - Mat aux; - const char borderValue = 127; - warpPerspective(markerImg, aux, transformation, imageSize, INTER_NEAREST, BORDER_CONSTANT, - Scalar::all(borderValue)); - - // copy only not-border pixels - for(int y = 0; y < aux.rows; y++) { - for(int x = 0; x < aux.cols; x++) { - if(aux.at< unsigned char >(y, x) == borderValue) continue; - img.at< unsigned char >(y, x) = aux.at< unsigned char >(y, x); - } - } - - return img; -} - -enum class ArucoAlgParams -{ - USE_DEFAULT = 0, - USE_APRILTAG=1, /// Detect marker candidates :: using AprilTag - DETECT_INVERTED_MARKER, /// Check if there is a white marker - USE_ARUCO3 /// Check if aruco3 should be used -}; - - -/** - * @brief Draws markers in perspective and detect them - */ -class CV_ArucoDetectionPerspective : public cvtest::BaseTest { - public: - CV_ArucoDetectionPerspective(ArucoAlgParams arucoAlgParam) : arucoAlgParams(arucoAlgParam) {} - - protected: - void run(int); - ArucoAlgParams arucoAlgParams; -}; - - -void CV_ArucoDetectionPerspective::run(int) { - - int iter = 0; - int szEnclosed = 0; - Mat cameraMatrix = Mat::eye(3, 3, CV_64FC1); - Size imgSize(500, 500); - cameraMatrix.at< double >(0, 0) = cameraMatrix.at< double >(1, 1) = 650; - cameraMatrix.at< double >(0, 2) = imgSize.width / 2; - cameraMatrix.at< double >(1, 2) = imgSize.height / 2; - Ptr params = aruco::DetectorParameters::create(); - params->minDistanceToBorder = 1; - aruco::ArucoDetector detector(aruco::getPredefinedDictionary(aruco::DICT_6X6_250), params); - - // detect from different positions - for(double distance = 0.1; distance < 0.7; distance += 0.2) { - for(int pitch = 0; pitch < 360; pitch += (distance == 0.1? 60:180)) { - for(int yaw = 70; yaw <= 120; yaw += 40){ - int currentId = iter % 250; - int markerBorder = iter % 2 + 1; - iter++; - vector< Point2f > groundTruthCorners; - - params->markerBorderBits = markerBorder; - - /// create synthetic image - Mat img= - projectMarker(detector.dictionary, currentId, cameraMatrix, deg2rad(yaw), deg2rad(pitch), - distance, imgSize, markerBorder, groundTruthCorners, szEnclosed); - // marker :: Inverted - if(ArucoAlgParams::DETECT_INVERTED_MARKER == arucoAlgParams){ - img = ~img; - params->detectInvertedMarker = true; - } - - if(ArucoAlgParams::USE_APRILTAG == arucoAlgParams){ - params->cornerRefinementMethod = cv::aruco::CORNER_REFINE_APRILTAG; - } - - if (ArucoAlgParams::USE_ARUCO3 == arucoAlgParams) { - params->useAruco3Detection = true; - params->cornerRefinementMethod = cv::aruco::CORNER_REFINE_SUBPIX; - } - - // detect markers - vector< vector< Point2f > > corners; - vector< int > ids; - detector.detectMarkers(img, corners, ids); - - // check results - if(ids.size() != 1 || (ids.size() == 1 && ids[0] != currentId)) { - if(ids.size() != 1) - ts->printf(cvtest::TS::LOG, "Incorrect number of detected markers"); - else - ts->printf(cvtest::TS::LOG, "Incorrect marker id"); - ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); - return; - } - for(int c = 0; c < 4; c++) { - double dist = cv::norm(groundTruthCorners[c] - corners[0][c]); // TODO cvtest - if(dist > 5) { - ts->printf(cvtest::TS::LOG, "Incorrect marker corners position"); - ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); - return; - } - } - } - } - // change the state :: to detect an enclosed inverted marker - if(ArucoAlgParams::DETECT_INVERTED_MARKER == arucoAlgParams && distance == 0.1){ - distance -= 0.1; - szEnclosed++; - } - } -} - - -/** - * @brief Check max and min size in marker detection parameters - */ -class CV_ArucoDetectionMarkerSize : public cvtest::BaseTest { - public: - CV_ArucoDetectionMarkerSize(); - - protected: - void run(int); -}; - - -CV_ArucoDetectionMarkerSize::CV_ArucoDetectionMarkerSize() {} - - -void CV_ArucoDetectionMarkerSize::run(int) { - Ptr params = aruco::DetectorParameters::create(); - aruco::ArucoDetector detector(aruco::getPredefinedDictionary(aruco::DICT_6X6_250), params); - int markerSide = 20; - int imageSize = 200; - - // 10 cases - for(int i = 0; i < 10; i++) { - Mat marker; - int id = 10 + i * 20; - - // create synthetic image - Mat img = Mat(imageSize, imageSize, CV_8UC1, Scalar::all(255)); - aruco::drawMarker(detector.dictionary, id, markerSide, marker); - Mat aux = img.colRange(30, 30 + markerSide).rowRange(50, 50 + markerSide); - marker.copyTo(aux); - - vector< vector< Point2f > > corners; - vector< int > ids; - - // set a invalid minMarkerPerimeterRate - params->minMarkerPerimeterRate = min(4., (4. * markerSide) / float(imageSize) + 0.1); - detector.detectMarkers(img, corners, ids); - if(corners.size() != 0) { - ts->printf(cvtest::TS::LOG, "Error in DetectorParameters::minMarkerPerimeterRate"); - ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); - return; - } - - // set an valid minMarkerPerimeterRate - params->minMarkerPerimeterRate = max(0., (4. * markerSide) / float(imageSize) - 0.1); - detector.detectMarkers(img, corners, ids); - if(corners.size() != 1 || (corners.size() == 1 && ids[0] != id)) { - ts->printf(cvtest::TS::LOG, "Error in DetectorParameters::minMarkerPerimeterRate"); - ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); - return; - } - - // set a invalid maxMarkerPerimeterRate - params->maxMarkerPerimeterRate = min(4., (4. * markerSide) / float(imageSize) - 0.1); - detector.detectMarkers(img, corners, ids); - if(corners.size() != 0) { - ts->printf(cvtest::TS::LOG, "Error in DetectorParameters::maxMarkerPerimeterRate"); - ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); - return; - } - - // set an valid maxMarkerPerimeterRate - params->maxMarkerPerimeterRate = max(0., (4. * markerSide) / float(imageSize) + 0.1); - detector.detectMarkers(img, corners, ids); - if(corners.size() != 1 || (corners.size() == 1 && ids[0] != id)) { - ts->printf(cvtest::TS::LOG, "Error in DetectorParameters::maxMarkerPerimeterRate"); - ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); - return; - } - } -} - - -/** - * @brief Check error correction in marker bits - */ -class CV_ArucoBitCorrection : public cvtest::BaseTest { - public: - CV_ArucoBitCorrection(); - - protected: - void run(int); -}; - - -CV_ArucoBitCorrection::CV_ArucoBitCorrection() {} - - -void CV_ArucoBitCorrection::run(int) { - - Ptr _dictionary1 = aruco::getPredefinedDictionary(aruco::DICT_6X6_250); - Ptr _dictionary2 = aruco::getPredefinedDictionary(aruco::DICT_6X6_250); - aruco::Dictionary &dictionary1 = *_dictionary1; - aruco::Dictionary &dictionary2 = *_dictionary2; - Ptr params = aruco::DetectorParameters::create(); - aruco::ArucoDetector detector1(_dictionary1, params); - int markerSide = 50; - int imageSize = 150; - - // 10 markers - for(int l = 0; l < 10; l++) { - Mat marker; - int id = 10 + l * 20; - - Mat currentCodeBytes = dictionary1.bytesList.rowRange(id, id + 1); - - // 5 valid cases - for(int i = 0; i < 5; i++) { - // how many bit errors (the error is low enough so it can be corrected) - params->errorCorrectionRate = 0.2 + i * 0.1; - int errors = - (int)std::floor(dictionary1.maxCorrectionBits * params->errorCorrectionRate - 1.); - - // create erroneous marker in currentCodeBits - Mat currentCodeBits = - aruco::Dictionary::getBitsFromByteList(currentCodeBytes, dictionary1.markerSize); - for(int e = 0; e < errors; e++) { - currentCodeBits.ptr< unsigned char >()[2 * e] = - !currentCodeBits.ptr< unsigned char >()[2 * e]; - } - - // add erroneous marker to dictionary2 in order to create the erroneous marker image - Mat currentCodeBytesError = aruco::Dictionary::getByteListFromBits(currentCodeBits); - currentCodeBytesError.copyTo(dictionary2.bytesList.rowRange(id, id + 1)); - Mat img = Mat(imageSize, imageSize, CV_8UC1, Scalar::all(255)); - dictionary2.drawMarker(id, markerSide, marker); - Mat aux = img.colRange(30, 30 + markerSide).rowRange(50, 50 + markerSide); - marker.copyTo(aux); - - // try to detect using original dictionary - vector< vector< Point2f > > corners; - vector< int > ids; - detector1.detectMarkers(img, corners, ids); - if(corners.size() != 1 || (corners.size() == 1 && ids[0] != id)) { - ts->printf(cvtest::TS::LOG, "Error in bit correction"); - ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); - return; - } - } - - // 5 invalid cases - for(int i = 0; i < 5; i++) { - // how many bit errors (the error is too high to be corrected) - params->errorCorrectionRate = 0.2 + i * 0.1; - int errors = - (int)std::floor(dictionary1.maxCorrectionBits * params->errorCorrectionRate + 1.); - - // create erroneous marker in currentCodeBits - Mat currentCodeBits = - aruco::Dictionary::getBitsFromByteList(currentCodeBytes, dictionary1.markerSize); - for(int e = 0; e < errors; e++) { - currentCodeBits.ptr< unsigned char >()[2 * e] = - !currentCodeBits.ptr< unsigned char >()[2 * e]; - } - - // dictionary3 is only composed by the modified marker (in its original form) - Ptr _dictionary3 = makePtr( - dictionary2.bytesList.rowRange(id, id + 1).clone(), - dictionary1.markerSize, - dictionary1.maxCorrectionBits); - aruco::ArucoDetector detector3(_dictionary3, params); - // add erroneous marker to dictionary2 in order to create the erroneous marker image - Mat currentCodeBytesError = aruco::Dictionary::getByteListFromBits(currentCodeBits); - currentCodeBytesError.copyTo(dictionary2.bytesList.rowRange(id, id + 1)); - Mat img = Mat(imageSize, imageSize, CV_8UC1, Scalar::all(255)); - dictionary2.drawMarker(id, markerSide, marker); - Mat aux = img.colRange(30, 30 + markerSide).rowRange(50, 50 + markerSide); - marker.copyTo(aux); - - // try to detect using dictionary3, it should fail - vector< vector< Point2f > > corners; - vector< int > ids; - detector3.detectMarkers(img, corners, ids); - if(corners.size() != 0) { - ts->printf(cvtest::TS::LOG, "Error in DetectorParameters::errorCorrectionRate"); - ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); - return; - } - } - } -} - -typedef CV_ArucoDetectionPerspective CV_AprilTagDetectionPerspective; -typedef CV_ArucoDetectionPerspective CV_InvertedArucoDetectionPerspective; -typedef CV_ArucoDetectionPerspective CV_Aruco3DetectionPerspective; - -TEST(CV_InvertedArucoDetectionPerspective, algorithmic) { - CV_InvertedArucoDetectionPerspective test(ArucoAlgParams::DETECT_INVERTED_MARKER); - test.safe_run(); -} - -TEST(CV_AprilTagDetectionPerspective, algorithmic) { - CV_AprilTagDetectionPerspective test(ArucoAlgParams::USE_APRILTAG); - test.safe_run(); -} - -TEST(CV_Aruco3DetectionPerspective, algorithmic) { - CV_Aruco3DetectionPerspective test(ArucoAlgParams::USE_ARUCO3); - test.safe_run(); -} - -TEST(CV_ArucoDetectionSimple, algorithmic) { - CV_ArucoDetectionSimple test; - test.safe_run(); -} - -TEST(CV_ArucoDetectionPerspective, algorithmic) { - CV_ArucoDetectionPerspective test(ArucoAlgParams::USE_DEFAULT); - test.safe_run(); -} - -TEST(CV_ArucoDetectionMarkerSize, algorithmic) { - CV_ArucoDetectionMarkerSize test; - test.safe_run(); -} - -TEST(CV_ArucoBitCorrection, algorithmic) { - CV_ArucoBitCorrection test; - test.safe_run(); -} - -TEST(CV_ArucoTutorial, can_find_singlemarkersoriginal) -{ - string img_path = cvtest::findDataFile("singlemarkersoriginal.jpg", false); - Mat image = imread(img_path); - aruco::ArucoDetector detector(aruco::getPredefinedDictionary(aruco::DICT_6X6_250)); - - vector< int > ids; - vector< vector< Point2f > > corners, rejected; - const size_t N = 6ull; - // corners of ArUco markers with indices goldCornersIds - const int goldCorners[N][8] = { {359,310, 404,310, 410,350, 362,350}, {427,255, 469,256, 477,289, 434,288}, - {233,273, 190,273, 196,241, 237,241}, {298,185, 334,186, 335,212, 297,211}, - {425,163, 430,186, 394,186, 390,162}, {195,155, 230,155, 227,178, 190,178} }; - const int goldCornersIds[N] = { 40, 98, 62, 23, 124, 203}; - map mapGoldCorners; - for (size_t i = 0; i < N; i++) - mapGoldCorners[goldCornersIds[i]] = goldCorners[i]; - - detector.detectMarkers(image, corners, ids, rejected); - - ASSERT_EQ(N, ids.size()); - for (size_t i = 0; i < N; i++) - { - int arucoId = ids[i]; - ASSERT_EQ(4ull, corners[i].size()); - ASSERT_TRUE(mapGoldCorners.find(arucoId) != mapGoldCorners.end()); - for (int j = 0; j < 4; j++) - { - EXPECT_NEAR(static_cast(mapGoldCorners[arucoId][j * 2]), corners[i][j].x, 1.f); - EXPECT_NEAR(static_cast(mapGoldCorners[arucoId][j * 2 + 1]), corners[i][j].y, 1.f); - } - } -} - -TEST(CV_ArucoTutorial, can_find_gboriginal) -{ - string imgPath = cvtest::findDataFile("gboriginal.png", false); - Mat image = imread(imgPath); - string dictPath = cvtest::findDataFile("tutorial_dict.yml", false); - Ptr dictionary = makePtr(); - - FileStorage fs(dictPath, FileStorage::READ); - dictionary->aruco::Dictionary::readDictionary(fs.root()); // set marker from tutorial_dict.yml - Ptr detectorParams = aruco::DetectorParameters::create(); - - aruco::ArucoDetector detector(dictionary, detectorParams); - - vector< int > ids; - vector< vector< Point2f > > corners, rejected; - const size_t N = 35ull; - // corners of ArUco markers with indices 0, 1, ..., 34 - const int goldCorners[N][8] = { {252,74, 286,81, 274,102, 238,95}, {295,82, 330,89, 319,111, 282,104}, - {338,91, 375,99, 365,121, 327,113}, {383,100, 421,107, 412,130, 374,123}, - {429,109, 468,116, 461,139, 421,132}, {235,100, 270,108, 257,130, 220,122}, - {279,109, 316,117, 304,140, 266,133}, {324,119, 362,126, 352,150, 313,143}, - {371,128, 410,136, 400,161, 360,152}, {418,139, 459,145, 451,170, 410,163}, - {216,128, 253,136, 239,161, 200,152}, {262,138, 300,146, 287,172, 248,164}, - {309,148, 349,156, 337,183, 296,174}, {358,158, 398,167, 388,194, 346,185}, - {407,169, 449,176, 440,205, 397,196}, {196,158, 235,168, 218,195, 179,185}, - {243,170, 283,178, 269,206, 228,197}, {293,180, 334,190, 321,218, 279,209}, - {343,192, 385,200, 374,230, 330,220}, {395,203, 438,211, 429,241, 384,233}, - {174,192, 215,201, 197,231, 156,221}, {223,204, 265,213, 249,244, 207,234}, - {275,215, 317,225, 303,257, 259,246}, {327,227, 371,238, 359,270, 313,259}, - {381,240, 426,249, 416,282, 369,273}, {151,228, 193,238, 173,271, 130,260}, - {202,241, 245,251, 228,285, 183,274}, {255,254, 300,264, 284,299, 238,288}, - {310,267, 355,278, 342,314, 295,302}, {366,281, 413,290, 402,327, 353,317}, - {125,267, 168,278, 147,314, 102,303}, {178,281, 223,293, 204,330, 157,317}, - {233,296, 280,307, 263,346, 214,333}, {291,310, 338,322, 323,363, 274,349}, - {349,325, 399,336, 386,378, 335,366} }; - map mapGoldCorners; - for (int i = 0; i < static_cast(N); i++) - mapGoldCorners[i] = goldCorners[i]; - - detector.detectMarkers(image, corners, ids, rejected); - - - ASSERT_EQ(N, ids.size()); - for (size_t i = 0; i < N; i++) - { - int arucoId = ids[i]; - ASSERT_EQ(4ull, corners[i].size()); - ASSERT_TRUE(mapGoldCorners.find(arucoId) != mapGoldCorners.end()); - for (int j = 0; j < 4; j++) - { - EXPECT_NEAR(static_cast(mapGoldCorners[arucoId][j*2]), corners[i][j].x, 1.f); - EXPECT_NEAR(static_cast(mapGoldCorners[arucoId][j*2+1]), corners[i][j].y, 1.f); - } - } -} - -TEST(CV_ArucoDetectMarkers, regression_3192) -{ - aruco::ArucoDetector detector(aruco::getPredefinedDictionary(aruco::DICT_4X4_50)); - vector< int > markerIds; - vector > markerCorners; - string imgPath = cvtest::findDataFile("aruco/regression_3192.png"); - Mat image = imread(imgPath); - const size_t N = 2ull; - const int goldCorners[N][8] = { {345,120, 520,120, 520,295, 345,295}, {101,114, 270,112, 276,287, 101,287} }; - const int goldCornersIds[N] = { 6, 4 }; - map mapGoldCorners; - for (size_t i = 0; i < N; i++) - mapGoldCorners[goldCornersIds[i]] = goldCorners[i]; - - detector.detectMarkers(image, markerCorners, markerIds); - - ASSERT_EQ(N, markerIds.size()); - for (size_t i = 0; i < N; i++) - { - int arucoId = markerIds[i]; - ASSERT_EQ(4ull, markerCorners[i].size()); - ASSERT_TRUE(mapGoldCorners.find(arucoId) != mapGoldCorners.end()); - for (int j = 0; j < 4; j++) - { - EXPECT_NEAR(static_cast(mapGoldCorners[arucoId][j * 2]), markerCorners[i][j].x, 1.f); - EXPECT_NEAR(static_cast(mapGoldCorners[arucoId][j * 2 + 1]), markerCorners[i][j].y, 1.f); - } - } -} - -TEST(CV_ArucoDetectMarkers, regression_2492) -{ - aruco::ArucoDetector detector(aruco::getPredefinedDictionary(aruco::DICT_5X5_50)); - detector.params->minMarkerDistanceRate = 0.026; - vector< int > markerIds; - vector > markerCorners; - string imgPath = cvtest::findDataFile("aruco/regression_2492.png"); - Mat image = imread(imgPath); - const size_t N = 8ull; - const int goldCorners[N][8] = { {179,139, 179,95, 223,95, 223,139}, {99,139, 99,95, 143,95, 143,139}, - {19,139, 19,95, 63,95, 63,139}, {256,140, 256,93, 303,93, 303,140}, - {256,62, 259,21, 300,23, 297,64}, {99,21, 143,17, 147,60, 103,64}, - {69,61, 28,61, 14,21, 58,17}, {174,62, 182,13, 230,19, 223,68} }; - const int goldCornersIds[N] = {13, 13, 13, 13, 1, 15, 14, 4}; - map > mapGoldCorners; - for (size_t i = 0; i < N; i++) - mapGoldCorners[goldCornersIds[i]].push_back(goldCorners[i]); - - detector.detectMarkers(image, markerCorners, markerIds); - - ASSERT_EQ(N, markerIds.size()); - for (size_t i = 0; i < N; i++) - { - int arucoId = markerIds[i]; - ASSERT_EQ(4ull, markerCorners[i].size()); - ASSERT_TRUE(mapGoldCorners.find(arucoId) != mapGoldCorners.end()); - float totalDist = 8.f; - for (size_t k = 0ull; k < mapGoldCorners[arucoId].size(); k++) - { - float dist = 0.f; - for (int j = 0; j < 4; j++) // total distance up to 4 points - { - dist += abs(mapGoldCorners[arucoId][k][j * 2] - markerCorners[i][j].x); - dist += abs(mapGoldCorners[arucoId][k][j * 2 + 1] - markerCorners[i][j].y); - } - totalDist = min(totalDist, dist); - } - EXPECT_LT(totalDist, 8.f); - } -} - -struct ArucoThreading: public testing::TestWithParam -{ - struct NumThreadsSetter { - NumThreadsSetter(const int num_threads) - : original_num_threads_(cv::getNumThreads()) { - cv::setNumThreads(num_threads); - } - - ~NumThreadsSetter() { - cv::setNumThreads(original_num_threads_); - } - private: - int original_num_threads_; - }; -}; - -TEST_P(ArucoThreading, number_of_threads_does_not_change_results) -{ - // We are not testing against different dictionaries - // As we are interested mostly in small images, smaller - // markers is better -> 4x4 - aruco::ArucoDetector detector(aruco::getPredefinedDictionary(aruco::DICT_4X4_50)); - - // Height of the test image can be chosen quite freely - // We aim to test against small images as in those the - // number of threads has most effect - const int height_img = 20; - // Just to get nice white boarder - const int shift = height_img > 10 ? 5 : 1; - const int height_marker = height_img-2*shift; - - // Create a test image - cv::Mat img_marker; - cv::aruco::drawMarker(detector.dictionary, 23, height_marker, img_marker, 1); - - // Copy to bigger image to get a white border - cv::Mat img(height_img, height_img, CV_8UC1, cv::Scalar(255)); - img_marker.copyTo(img(cv::Rect(shift, shift, height_marker, height_marker))); - - detector.params->cornerRefinementMethod = GetParam(); - - std::vector > original_corners; - std::vector original_ids; - { - NumThreadsSetter thread_num_setter(1); - detector.detectMarkers(img, original_corners, original_ids); - } - - ASSERT_EQ(original_ids.size(), 1ull); - ASSERT_EQ(original_corners.size(), 1ull); - - int num_threads_to_test[] = { 2, 8, 16, 32, height_img-1, height_img, height_img+1}; - - for (size_t i_num_threads = 0; i_num_threads < sizeof(num_threads_to_test)/sizeof(int); ++i_num_threads) { - NumThreadsSetter thread_num_setter(num_threads_to_test[i_num_threads]); - - std::vector > corners; - std::vector ids; - detector.detectMarkers(img, corners, ids); - - // If we don't find any markers, the test is broken - ASSERT_EQ(ids.size(), 1ull); - - // Make sure we got the same result as the first time - ASSERT_EQ(corners.size(), original_corners.size()); - ASSERT_EQ(ids.size(), original_ids.size()); - ASSERT_EQ(ids.size(), corners.size()); - for (size_t i = 0; i < corners.size(); ++i) { - EXPECT_EQ(ids[i], original_ids[i]); - for (size_t j = 0; j < corners[i].size(); ++j) { - EXPECT_NEAR(corners[i][j].x, original_corners[i][j].x, 0.1f); - EXPECT_NEAR(corners[i][j].y, original_corners[i][j].y, 0.1f); - } - } - } -} - -INSTANTIATE_TEST_CASE_P( - CV_ArucoDetectMarkers, ArucoThreading, - ::testing::Values( - cv::aruco::CORNER_REFINE_NONE, - cv::aruco::CORNER_REFINE_SUBPIX, - cv::aruco::CORNER_REFINE_CONTOUR, - cv::aruco::CORNER_REFINE_APRILTAG - )); - -}} // namespace diff --git a/modules/aruco/test/test_boarddetection.cpp b/modules/aruco/test/test_boarddetection.cpp deleted file mode 100644 index 148c6d440d0..00000000000 --- a/modules/aruco/test/test_boarddetection.cpp +++ /dev/null @@ -1,332 +0,0 @@ -/* -By downloading, copying, installing or using the software you agree to this -license. If you do not agree to this license, do not download, install, -copy or use the software. - - License Agreement - For Open Source Computer Vision Library - (3-clause BSD License) - -Copyright (C) 2013, OpenCV Foundation, all rights reserved. -Third party copyrights are property of their respective owners. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the names of the copyright holders nor the names of the contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -This software is provided by the copyright holders and contributors "as is" and -any express or implied warranties, including, but not limited to, the implied -warranties of merchantability and fitness for a particular purpose are -disclaimed. In no event shall copyright holders or contributors be liable for -any direct, indirect, incidental, special, exemplary, or consequential damages -(including, but not limited to, procurement of substitute goods or services; -loss of use, data, or profits; or business interruption) however caused -and on any theory of liability, whether in contract, strict liability, -or tort (including negligence or otherwise) arising in any way out of -the use of this software, even if advised of the possibility of such damage. -*/ - - -#include "test_precomp.hpp" -#include "test_aruco_utils.hpp" - -namespace opencv_test { namespace { - -enum class ArucoAlgParams -{ - USE_DEFAULT = 0, - USE_ARUCO3 = 1 -}; - -/** - * @brief Check pose estimation of aruco board - */ -class CV_ArucoBoardPose : public cvtest::BaseTest { - public: - CV_ArucoBoardPose(ArucoAlgParams arucoAlgParams) - { - Ptr params; - Ptr dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250); - params = aruco::DetectorParameters::create(); - params->minDistanceToBorder = 3; - if (arucoAlgParams == ArucoAlgParams::USE_ARUCO3) { - params->useAruco3Detection = true; - params->cornerRefinementMethod = aruco::CORNER_REFINE_SUBPIX; - params->minSideLengthCanonicalImg = 16; - params->errorCorrectionRate = 0.8; - } - detector = aruco::ArucoDetector(dictionary, params); - } - - protected: - aruco::ArucoDetector detector; - void run(int); -}; - - -void CV_ArucoBoardPose::run(int) { - int iter = 0; - Mat cameraMatrix = Mat::eye(3, 3, CV_64FC1); - Size imgSize(500, 500); - Ptr gridboard = aruco::GridBoard::create(3, 3, 0.02f, 0.005f, detector.dictionary); - Ptr board = gridboard.staticCast(); - cameraMatrix.at< double >(0, 0) = cameraMatrix.at< double >(1, 1) = 650; - cameraMatrix.at< double >(0, 2) = imgSize.width / 2; - cameraMatrix.at< double >(1, 2) = imgSize.height / 2; - Mat distCoeffs(5, 1, CV_64FC1, Scalar::all(0)); - - // for different perspectives - for(double distance = 0.2; distance <= 0.4; distance += 0.15) { - for(int yaw = -55; yaw <= 50; yaw += 25) { - for(int pitch = -55; pitch <= 50; pitch += 25) { - vector tmpIds; - for(unsigned int i = 0; i < gridboard->getIds().size(); i++) - tmpIds.push_back((iter + int(i)) % 250); - gridboard->setIds(tmpIds); - int markerBorder = iter % 2 + 1; - iter++; - // create synthetic image - Mat img = projectBoard(gridboard, cameraMatrix, deg2rad(yaw), deg2rad(pitch), distance, - imgSize, markerBorder); - vector > corners; - vector ids; - detector.params->markerBorderBits = markerBorder; - detector.detectMarkers(img, corners, ids); - - ASSERT_EQ(ids.size(), gridboard->getIds().size()); - - // estimate pose - Mat rvec, tvec; - aruco::estimatePoseBoard(corners, ids, board, cameraMatrix, distCoeffs, rvec, tvec); - - // check axes - vector axes = getAxis(cameraMatrix, distCoeffs, rvec, tvec, gridboard->getRightBottomBorder().x); - vector topLeft = getMarkerById(gridboard->getIds()[0], corners, ids); - ASSERT_NEAR(topLeft[0].x, axes[0].x, 2.f); - ASSERT_NEAR(topLeft[0].y, axes[0].y, 2.f); - vector topRight = getMarkerById(gridboard->getIds()[2], corners, ids); - ASSERT_NEAR(topRight[1].x, axes[1].x, 2.f); - ASSERT_NEAR(topRight[1].y, axes[1].y, 2.f); - vector bottomLeft = getMarkerById(gridboard->getIds()[6], corners, ids); - ASSERT_NEAR(bottomLeft[3].x, axes[2].x, 2.f); - ASSERT_NEAR(bottomLeft[3].y, axes[2].y, 2.f); - - // check estimate result - for(unsigned int i = 0; i < ids.size(); i++) { - int foundIdx = -1; - for(unsigned int j = 0; j < gridboard->getIds().size(); j++) { - if(gridboard->getIds()[j] == ids[i]) { - foundIdx = int(j); - break; - } - } - - if(foundIdx == -1) { - ts->printf(cvtest::TS::LOG, "Marker detected with wrong ID in Board test"); - ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); - return; - } - - vector< Point2f > projectedCorners; - projectPoints(gridboard->getObjPoints()[foundIdx], rvec, tvec, cameraMatrix, distCoeffs, - projectedCorners); - - for(int c = 0; c < 4; c++) { - double repError = cv::norm(projectedCorners[c] - corners[i][c]); // TODO cvtest - if(repError > 5.) { - ts->printf(cvtest::TS::LOG, "Corner reprojection error too high"); - ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); - return; - } - } - } - } - } - } -} - - - -/** - * @brief Check refine strategy - */ -class CV_ArucoRefine : public cvtest::BaseTest { - public: - CV_ArucoRefine(ArucoAlgParams arucoAlgParams) - { - Ptr dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250); - Ptr params = aruco::DetectorParameters::create(); - params->minDistanceToBorder = 3; - params->cornerRefinementMethod = aruco::CORNER_REFINE_SUBPIX; - if (arucoAlgParams == ArucoAlgParams::USE_ARUCO3) - params->useAruco3Detection = true; - Ptr refineParams = makePtr(10, 3., true); - detector = aruco::ArucoDetector(dictionary, params, refineParams); - } - - protected: - aruco::ArucoDetector detector; - void run(int); -}; - - -void CV_ArucoRefine::run(int) { - - int iter = 0; - Mat cameraMatrix = Mat::eye(3, 3, CV_64FC1); - Size imgSize(500, 500); - Ptr gridboard = aruco::GridBoard::create(3, 3, 0.02f, 0.005f, detector.dictionary); - Ptr board = gridboard.staticCast(); - cameraMatrix.at< double >(0, 0) = cameraMatrix.at< double >(1, 1) = 650; - cameraMatrix.at< double >(0, 2) = imgSize.width / 2; - cameraMatrix.at< double >(1, 2) = imgSize.height / 2; - Mat distCoeffs(5, 1, CV_64FC1, Scalar::all(0)); - - // for different perspectives - for(double distance = 0.2; distance <= 0.4; distance += 0.2) { - for(int yaw = -60; yaw < 60; yaw += 30) { - for(int pitch = -60; pitch <= 60; pitch += 30) { - vector tmpIds; - for(unsigned int i = 0; i < gridboard->getIds().size(); i++) - tmpIds.push_back(iter + int(i) % 250); - gridboard->setIds(tmpIds); - int markerBorder = iter % 2 + 1; - iter++; - - // create synthetic image - Mat img = projectBoard(gridboard, cameraMatrix, deg2rad(yaw), deg2rad(pitch), distance, - imgSize, markerBorder); - // detect markers - vector > corners, rejected; - vector ids; - detector.params->markerBorderBits = markerBorder; - detector.detectMarkers(img, corners, ids, rejected); - - // remove a marker from detection - int markersBeforeDelete = (int)ids.size(); - if(markersBeforeDelete < 2) continue; - - rejected.push_back(corners[0]); - corners.erase(corners.begin(), corners.begin() + 1); - ids.erase(ids.begin(), ids.begin() + 1); - - // try to refind the erased marker - detector.refineDetectedMarkers(img, board, corners, ids, rejected, cameraMatrix, - distCoeffs, noArray()); - - // check result - if((int)ids.size() < markersBeforeDelete) { - ts->printf(cvtest::TS::LOG, "Error in refine detected markers"); - ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); - return; - } - } - } - } -} - - - - -TEST(CV_ArucoBoardPose, accuracy) { - CV_ArucoBoardPose test(ArucoAlgParams::USE_DEFAULT); - test.safe_run(); -} - -typedef CV_ArucoBoardPose CV_Aruco3BoardPose; -TEST(CV_Aruco3BoardPose, accuracy) { - CV_Aruco3BoardPose test(ArucoAlgParams::USE_ARUCO3); - test.safe_run(); -} - -typedef CV_ArucoRefine CV_Aruco3Refine; - -TEST(CV_ArucoRefine, accuracy) { - CV_ArucoRefine test(ArucoAlgParams::USE_DEFAULT); - test.safe_run(); -} - -TEST(CV_Aruco3Refine, accuracy) { - CV_Aruco3Refine test(ArucoAlgParams::USE_ARUCO3); - test.safe_run(); -} - -TEST(CV_ArucoBoardPose, CheckNegativeZ) -{ - double matrixData[9] = { -3.9062571886921410e+02, 0., 4.2350000000000000e+02, - 0., 3.9062571886921410e+02, 2.3950000000000000e+02, - 0., 0., 1 }; - cv::Mat cameraMatrix = cv::Mat(3, 3, CV_64F, matrixData); - - cv::Ptr boardPtr = makePtr(); - cv::aruco::Board& board = *boardPtr; - - vector pts3d1, pts3d2; - pts3d1.push_back(cv::Point3f(0.326198f, -0.030621f, 0.303620f)); - pts3d1.push_back(cv::Point3f(0.325340f, -0.100594f, 0.301862f)); - pts3d1.push_back(cv::Point3f(0.255859f, -0.099530f, 0.293416f)); - pts3d1.push_back(cv::Point3f(0.256717f, -0.029557f, 0.295174f)); - - pts3d2.push_back(cv::Point3f(-0.033144f, -0.034819f, 0.245216f)); - pts3d2.push_back(cv::Point3f(-0.035507f, -0.104705f, 0.241987f)); - pts3d2.push_back(cv::Point3f(-0.105289f, -0.102120f, 0.237120f)); - pts3d2.push_back(cv::Point3f(-0.102926f, -0.032235f, 0.240349f)); - - board.setObjPoints({pts3d1, pts3d2}); - board.setIds(vector{0, 1}); - - vector > corners; - vector pts2d; - pts2d.push_back(cv::Point2f(37.7f, 203.3f)); - pts2d.push_back(cv::Point2f(38.5f, 120.5f)); - pts2d.push_back(cv::Point2f(105.5f, 115.8f)); - pts2d.push_back(cv::Point2f(104.2f, 202.7f)); - corners.push_back(pts2d); - pts2d.clear(); - pts2d.push_back(cv::Point2f(476.0f, 184.2f)); - pts2d.push_back(cv::Point2f(479.6f, 73.8f)); - pts2d.push_back(cv::Point2f(590.9f, 77.0f)); - pts2d.push_back(cv::Point2f(587.5f, 188.1f)); - corners.push_back(pts2d); - - Vec3d rvec, tvec; - int nUsed = cv::aruco::estimatePoseBoard(corners, board.getIds(), boardPtr, cameraMatrix, Mat(), rvec, tvec); - ASSERT_EQ(nUsed, 2); - - cv::Matx33d rotm; cv::Point3d out; - cv::Rodrigues(rvec, rotm); - out = cv::Point3d(tvec) + rotm*Point3d(board.getObjPoints()[0][0]); - ASSERT_GT(out.z, 0); - - corners.clear(); pts2d.clear(); - pts2d.push_back(cv::Point2f(38.4f, 204.5f)); - pts2d.push_back(cv::Point2f(40.0f, 124.7f)); - pts2d.push_back(cv::Point2f(102.0f, 119.1f)); - pts2d.push_back(cv::Point2f(99.9f, 203.6f)); - corners.push_back(pts2d); - pts2d.clear(); - pts2d.push_back(cv::Point2f(476.0f, 184.3f)); - pts2d.push_back(cv::Point2f(479.2f, 75.1f)); - pts2d.push_back(cv::Point2f(588.7f, 79.2f)); - pts2d.push_back(cv::Point2f(586.3f, 188.5f)); - corners.push_back(pts2d); - - nUsed = cv::aruco::estimatePoseBoard(corners, board.getIds(), boardPtr, cameraMatrix, Mat(), rvec, tvec, true); - ASSERT_EQ(nUsed, 2); - - cv::Rodrigues(rvec, rotm); - out = cv::Point3d(tvec) + rotm*Point3d(board.getObjPoints()[0][0]); - ASSERT_GT(out.z, 0); -} - -}} // namespace diff --git a/modules/aruco/test/test_charucodetection.cpp b/modules/aruco/test/test_charucodetection.cpp deleted file mode 100644 index 99b87264df5..00000000000 --- a/modules/aruco/test/test_charucodetection.cpp +++ /dev/null @@ -1,822 +0,0 @@ -/* -By downloading, copying, installing or using the software you agree to this -license. If you do not agree to this license, do not download, install, -copy or use the software. - - License Agreement - For Open Source Computer Vision Library - (3-clause BSD License) - -Copyright (C) 2013, OpenCV Foundation, all rights reserved. -Third party copyrights are property of their respective owners. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the names of the copyright holders nor the names of the contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -This software is provided by the copyright holders and contributors "as is" and -any express or implied warranties, including, but not limited to, the implied -warranties of merchantability and fitness for a particular purpose are -disclaimed. In no event shall copyright holders or contributors be liable for -any direct, indirect, incidental, special, exemplary, or consequential damages -(including, but not limited to, procurement of substitute goods or services; -loss of use, data, or profits; or business interruption) however caused -and on any theory of liability, whether in contract, strict liability, -or tort (including negligence or otherwise) arising in any way out of -the use of this software, even if advised of the possibility of such damage. -*/ - - -#include "test_precomp.hpp" -#include "test_aruco_utils.hpp" - -namespace opencv_test { namespace { - -/** - * @brief Get a synthetic image of Chessboard in perspective - */ -static Mat projectChessboard(int squaresX, int squaresY, float squareSize, Size imageSize, - Mat cameraMatrix, Mat rvec, Mat tvec) { - - Mat img(imageSize, CV_8UC1, Scalar::all(255)); - Mat distCoeffs(5, 1, CV_64FC1, Scalar::all(0)); - - for(int y = 0; y < squaresY; y++) { - float startY = float(y) * squareSize; - for(int x = 0; x < squaresX; x++) { - if(y % 2 != x % 2) continue; - float startX = float(x) * squareSize; - - vector< Point3f > squareCorners; - squareCorners.push_back(Point3f(startX, startY, 0) - Point3f(squaresX*squareSize/2.f, squaresY*squareSize/2.f, 0.f)); - squareCorners.push_back(squareCorners[0] + Point3f(squareSize, 0, 0)); - squareCorners.push_back(squareCorners[0] + Point3f(squareSize, squareSize, 0)); - squareCorners.push_back(squareCorners[0] + Point3f(0, squareSize, 0)); - - vector< vector< Point2f > > projectedCorners; - projectedCorners.push_back(vector< Point2f >()); - projectPoints(squareCorners, rvec, tvec, cameraMatrix, distCoeffs, projectedCorners[0]); - - vector< vector< Point > > projectedCornersInt; - projectedCornersInt.push_back(vector< Point >()); - - for(int k = 0; k < 4; k++) - projectedCornersInt[0] - .push_back(Point((int)projectedCorners[0][k].x, (int)projectedCorners[0][k].y)); - - fillPoly(img, projectedCornersInt, Scalar::all(0)); - } - } - - return img; -} - - -/** - * @brief Check pose estimation of charuco board - */ -static Mat projectCharucoBoard(Ptr &board, Mat cameraMatrix, double yaw, - double pitch, double distance, Size imageSize, int markerBorder, - Mat &rvec, Mat &tvec) { - - getSyntheticRT(yaw, pitch, distance, rvec, tvec); - - // project markers - Mat img = Mat(imageSize, CV_8UC1, Scalar::all(255)); - for(unsigned int indexMarker = 0; indexMarker < board->getIds().size(); indexMarker++) { - projectMarker(img, board.staticCast(), indexMarker, cameraMatrix, rvec, - tvec, markerBorder); - } - - // project chessboard - Mat chessboard = - projectChessboard(board->getChessboardSize().width, board->getChessboardSize().height, - board->getSquareLength(), imageSize, cameraMatrix, rvec, tvec); - - for(unsigned int i = 0; i < chessboard.total(); i++) { - if(chessboard.ptr< unsigned char >()[i] == 0) { - img.ptr< unsigned char >()[i] = 0; - } - } - - return img; -} - -/** - * @brief Check Charuco detection - */ -class CV_CharucoDetection : public cvtest::BaseTest { - public: - CV_CharucoDetection(); - - protected: - void run(int); -}; - - -CV_CharucoDetection::CV_CharucoDetection() {} - - -void CV_CharucoDetection::run(int) { - - int iter = 0; - Mat cameraMatrix = Mat::eye(3, 3, CV_64FC1); - Size imgSize(500, 500); - Ptr params = aruco::DetectorParameters::create(); - params->minDistanceToBorder = 3; - aruco::ArucoDetector detector(aruco::getPredefinedDictionary(aruco::DICT_6X6_250), params); - Ptr board = aruco::CharucoBoard::create(4, 4, 0.03f, 0.015f, detector.dictionary); - - cameraMatrix.at(0, 0) = cameraMatrix.at(1, 1) = 600; - cameraMatrix.at(0, 2) = imgSize.width / 2; - cameraMatrix.at(1, 2) = imgSize.height / 2; - - Mat distCoeffs(5, 1, CV_64FC1, Scalar::all(0)); - - // for different perspectives - for(double distance = 0.2; distance <= 0.4; distance += 0.2) { - for(int yaw = -55; yaw <= 50; yaw += 25) { - for(int pitch = -55; pitch <= 50; pitch += 25) { - - int markerBorder = iter % 2 + 1; - iter++; - - // create synthetic image - Mat rvec, tvec; - Mat img = projectCharucoBoard(board, cameraMatrix, deg2rad(yaw), deg2rad(pitch), - distance, imgSize, markerBorder, rvec, tvec); - - // detect markers - vector > corners; - vector ids; - - detector.params->markerBorderBits = markerBorder; - detector.detectMarkers(img, corners, ids); - - if(ids.size() == 0) { - ts->printf(cvtest::TS::LOG, "Marker detection failed"); - ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); - return; - } - - // interpolate charuco corners - vector charucoCorners; - vector charucoIds; - - if(iter % 2 == 0) { - aruco::interpolateCornersCharuco(corners, ids, img, board, charucoCorners, - charucoIds); - } else { - aruco::interpolateCornersCharuco(corners, ids, img, board, charucoCorners, - charucoIds, cameraMatrix, distCoeffs); - } - - // check results - vector< Point2f > projectedCharucoCorners; - - // copy chessboardCorners - vector copyChessboardCorners = board->chessboardCorners; - // move copyChessboardCorners points - for (size_t i = 0; i < copyChessboardCorners.size(); i++) - copyChessboardCorners[i] -= board->getRightBottomBorder() / 2.f; - projectPoints(copyChessboardCorners, rvec, tvec, cameraMatrix, distCoeffs, - projectedCharucoCorners); - - for(unsigned int i = 0; i < charucoIds.size(); i++) { - - int currentId = charucoIds[i]; - - if(currentId >= (int)board->chessboardCorners.size()) { - ts->printf(cvtest::TS::LOG, "Invalid Charuco corner id"); - ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); - return; - } - - double repError = cv::norm(charucoCorners[i] - projectedCharucoCorners[currentId]); // TODO cvtest - - - if(repError > 5.) { - ts->printf(cvtest::TS::LOG, "Charuco corner reprojection error too high"); - ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); - return; - } - } - } - } - } -} - - - -/** - * @brief Check charuco pose estimation - */ -class CV_CharucoPoseEstimation : public cvtest::BaseTest { - public: - CV_CharucoPoseEstimation(); - - protected: - void run(int); -}; - - -CV_CharucoPoseEstimation::CV_CharucoPoseEstimation() {} - - -void CV_CharucoPoseEstimation::run(int) { - - int iter = 0; - Mat cameraMatrix = Mat::eye(3, 3, CV_64FC1); - Size imgSize(500, 500); - Ptr params = aruco::DetectorParameters::create(); - params->minDistanceToBorder = 3; - aruco::ArucoDetector detector(aruco::getPredefinedDictionary(aruco::DICT_6X6_250), params); - Ptr board = aruco::CharucoBoard::create(4, 4, 0.03f, 0.015f, detector.dictionary); - - cameraMatrix.at< double >(0, 0) = cameraMatrix.at< double >(1, 1) = 650; - cameraMatrix.at< double >(0, 2) = imgSize.width / 2; - cameraMatrix.at< double >(1, 2) = imgSize.height / 2; - - Mat distCoeffs(5, 1, CV_64FC1, Scalar::all(0)); - // for different perspectives - for(double distance = 0.2; distance <= 0.3; distance += 0.1) { - for(int yaw = -55; yaw <= 50; yaw += 25) { - for(int pitch = -55; pitch <= 50; pitch += 25) { - - int markerBorder = iter % 2 + 1; - iter++; - - // get synthetic image - Mat rvec, tvec; - Mat img = projectCharucoBoard(board, cameraMatrix, deg2rad(yaw), deg2rad(pitch), - distance, imgSize, markerBorder, rvec, tvec); - - // detect markers - vector< vector< Point2f > > corners; - vector< int > ids; - detector.params->markerBorderBits = markerBorder; - detector.detectMarkers(img, corners, ids); - - ASSERT_EQ(ids.size(), board->getIds().size()); - - // interpolate charuco corners - vector< Point2f > charucoCorners; - vector< int > charucoIds; - - if(iter % 2 == 0) { - aruco::interpolateCornersCharuco(corners, ids, img, board, charucoCorners, - charucoIds); - } else { - aruco::interpolateCornersCharuco(corners, ids, img, board, charucoCorners, - charucoIds, cameraMatrix, distCoeffs); - } - - if(charucoIds.size() == 0) continue; - - // estimate charuco pose - aruco::estimatePoseCharucoBoard(charucoCorners, charucoIds, board, cameraMatrix, - distCoeffs, rvec, tvec); - - - // check axes - const float offset = (board->getSquareLength() - board->getMarkerLength()) / 2.f; - vector axes = getAxis(cameraMatrix, distCoeffs, rvec, tvec, board->getSquareLength(), offset); - vector topLeft = getMarkerById(board->getIds()[0], corners, ids); - ASSERT_NEAR(topLeft[0].x, axes[1].x, 3.f); - ASSERT_NEAR(topLeft[0].y, axes[1].y, 3.f); - vector bottomLeft = getMarkerById(board->getIds()[2], corners, ids); - ASSERT_NEAR(bottomLeft[0].x, axes[2].x, 3.f); - ASSERT_NEAR(bottomLeft[0].y, axes[2].y, 3.f); - - // check estimate result - vector< Point2f > projectedCharucoCorners; - - projectPoints(board->chessboardCorners, rvec, tvec, cameraMatrix, distCoeffs, - projectedCharucoCorners); - - for(unsigned int i = 0; i < charucoIds.size(); i++) { - - int currentId = charucoIds[i]; - - if(currentId >= (int)board->chessboardCorners.size()) { - ts->printf(cvtest::TS::LOG, "Invalid Charuco corner id"); - ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); - return; - } - - double repError = cv::norm(charucoCorners[i] - projectedCharucoCorners[currentId]); // TODO cvtest - - - if(repError > 5.) { - ts->printf(cvtest::TS::LOG, "Charuco corner reprojection error too high"); - ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); - return; - } - } - } - } - } -} - - -/** - * @brief Check diamond detection - */ -class CV_CharucoDiamondDetection : public cvtest::BaseTest { - public: - CV_CharucoDiamondDetection(); - - protected: - void run(int); -}; - - -CV_CharucoDiamondDetection::CV_CharucoDiamondDetection() {} - - -void CV_CharucoDiamondDetection::run(int) { - - int iter = 0; - Mat cameraMatrix = Mat::eye(3, 3, CV_64FC1); - Size imgSize(500, 500); - Ptr params = aruco::DetectorParameters::create(); - params->minDistanceToBorder = 0; - aruco::ArucoDetector detector(aruco::getPredefinedDictionary(aruco::DICT_6X6_250), params); - float squareLength = 0.03f; - float markerLength = 0.015f; - Ptr board = - aruco::CharucoBoard::create(3, 3, squareLength, markerLength, detector.dictionary); - - cameraMatrix.at< double >(0, 0) = cameraMatrix.at< double >(1, 1) = 650; - cameraMatrix.at< double >(0, 2) = imgSize.width / 2; - cameraMatrix.at< double >(1, 2) = imgSize.height / 2; - - Mat distCoeffs(5, 1, CV_64FC1, Scalar::all(0)); - // for different perspectives - for(double distance = 0.2; distance <= 0.3; distance += 0.1) { - for(int yaw = -50; yaw <= 50; yaw += 25) { - for(int pitch = -50; pitch <= 50; pitch += 25) { - - int markerBorder = iter % 2 + 1; - vector idsTmp; - for(int i = 0; i < 4; i++) - idsTmp.push_back(4 * iter + i); - board->setIds(idsTmp); - iter++; - - // get synthetic image - Mat rvec, tvec; - Mat img = projectCharucoBoard(board, cameraMatrix, deg2rad(yaw), deg2rad(pitch), - distance, imgSize, markerBorder, rvec, tvec); - - // detect markers - vector< vector< Point2f > > corners; - vector< int > ids; - detector.params->markerBorderBits = markerBorder; - detector.detectMarkers(img, corners, ids); - - if(ids.size() != 4) { - ts->printf(cvtest::TS::LOG, "Not enough markers for diamond detection"); - ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); - return; - } - // detect diamonds - vector< vector< Point2f > > diamondCorners; - vector< Vec4i > diamondIds; - aruco::detectCharucoDiamond(img, corners, ids, squareLength / markerLength, diamondCorners, diamondIds, - cameraMatrix, distCoeffs, detector.dictionary); - - // check results - if(diamondIds.size() != 1) { - ts->printf(cvtest::TS::LOG, "Diamond not detected correctly"); - ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); - return; - } - - for(int i = 0; i < 4; i++) { - if(diamondIds[0][i] != board->getIds()[i]) { - ts->printf(cvtest::TS::LOG, "Incorrect diamond ids"); - ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); - return; - } - } - - - vector< Point2f > projectedDiamondCorners; - - // copy chessboardCorners - vector copyChessboardCorners = board->chessboardCorners; - // move copyChessboardCorners points - for (size_t i = 0; i < copyChessboardCorners.size(); i++) - copyChessboardCorners[i] -= board->getRightBottomBorder() / 2.f; - - projectPoints(copyChessboardCorners, rvec, tvec, cameraMatrix, distCoeffs, - projectedDiamondCorners); - - vector< Point2f > projectedDiamondCornersReorder(4); - projectedDiamondCornersReorder[0] = projectedDiamondCorners[0]; - projectedDiamondCornersReorder[1] = projectedDiamondCorners[1]; - projectedDiamondCornersReorder[2] = projectedDiamondCorners[3]; - projectedDiamondCornersReorder[3] = projectedDiamondCorners[2]; - - - for(unsigned int i = 0; i < 4; i++) { - - double repError = cv::norm(diamondCorners[0][i] - projectedDiamondCornersReorder[i]); // TODO cvtest - - if(repError > 5.) { - ts->printf(cvtest::TS::LOG, "Diamond corner reprojection error too high"); - ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); - return; - } - } - - Ptr estimateParameters = aruco::EstimateParameters::create(); - estimateParameters->pattern = aruco::ARUCO_CW_TOP_LEFT_CORNER; - // estimate diamond pose - vector< Vec3d > estimatedRvec, estimatedTvec; - aruco::estimatePoseSingleMarkers(diamondCorners, squareLength, cameraMatrix, distCoeffs, estimatedRvec, - estimatedTvec, noArray(), estimateParameters); - - // check result - vector< Point2f > projectedDiamondCornersPose; - vector< Vec3f > diamondObjPoints(4); - diamondObjPoints[0] = Vec3f(0.f, 0.f, 0); - diamondObjPoints[1] = Vec3f(squareLength, 0.f, 0); - diamondObjPoints[2] = Vec3f(squareLength, squareLength, 0); - diamondObjPoints[3] = Vec3f(0.f, squareLength, 0); - projectPoints(diamondObjPoints, estimatedRvec[0], estimatedTvec[0], cameraMatrix, - distCoeffs, projectedDiamondCornersPose); - - for(unsigned int i = 0; i < 4; i++) { - double repError = cv::norm(projectedDiamondCornersReorder[i] - projectedDiamondCornersPose[i]); // TODO cvtest - - if(repError > 5.) { - ts->printf(cvtest::TS::LOG, "Charuco pose error too high"); - ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); - return; - } - } - } - } - } -} - -/** -* @brief Check charuco board creation -*/ -class CV_CharucoBoardCreation : public cvtest::BaseTest { -public: - CV_CharucoBoardCreation(); - -protected: - void run(int); -}; - -CV_CharucoBoardCreation::CV_CharucoBoardCreation() {} - -void CV_CharucoBoardCreation::run(int) -{ - Ptr dictionary = aruco::getPredefinedDictionary(aruco::DICT_5X5_250); - int n = 6; - - float markerSizeFactor = 0.5f; - - for (float squareSize_mm = 5.0f; squareSize_mm < 35.0f; squareSize_mm += 0.1f) - { - Ptr board_meters = aruco::CharucoBoard::create( - n, n, squareSize_mm*1e-3f, squareSize_mm * markerSizeFactor * 1e-3f, dictionary); - - Ptr board_millimeters = aruco::CharucoBoard::create( - n, n, squareSize_mm, squareSize_mm * markerSizeFactor, dictionary); - - for (size_t i = 0; i < board_meters->nearestMarkerIdx.size(); i++) - { - if (board_meters->nearestMarkerIdx[i].size() != board_millimeters->nearestMarkerIdx[i].size() || - board_meters->nearestMarkerIdx[i][0] != board_millimeters->nearestMarkerIdx[i][0]) - { - ts->printf(cvtest::TS::LOG, - cv::format("Charuco board topology is sensitive to scale with squareSize=%.1f\n", - squareSize_mm).c_str()); - ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT); - break; - } - } - } -} - - -TEST(CV_CharucoDetection, accuracy) { - CV_CharucoDetection test; - test.safe_run(); -} - -TEST(CV_CharucoPoseEstimation, accuracy) { - CV_CharucoPoseEstimation test; - test.safe_run(); -} - -TEST(CV_CharucoDiamondDetection, accuracy) { - CV_CharucoDiamondDetection test; - test.safe_run(); -} - -TEST(CV_CharucoBoardCreation, accuracy) { - CV_CharucoBoardCreation test; - test.safe_run(); -} - -TEST(Charuco, testCharucoCornersCollinear_true) -{ - int squaresX = 13; - int squaresY = 28; - float squareLength = 300; - float markerLength = 150; - int dictionaryId = 11; - - - Ptr detectorParams = aruco::DetectorParameters::create(); - - Ptr dictionary = - aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId)); - - Ptr charucoBoard = - aruco::CharucoBoard::create(squaresX, squaresY, squareLength, markerLength, dictionary); - - // consistency with C++98 - const int arrLine[9] = {192, 204, 216, 228, 240, 252, 264, 276, 288}; - vector charucoIdsAxisLine(9, 0); - - for (int i = 0; i < 9; i++){ - charucoIdsAxisLine[i] = arrLine[i]; - } - - const int arrDiag[7] = {198, 209, 220, 231, 242, 253, 264}; - - vector charucoIdsDiagonalLine(7, 0); - - for (int i = 0; i < 7; i++){ - charucoIdsDiagonalLine[i] = arrDiag[i]; - } - - bool resultAxisLine = cv::aruco::testCharucoCornersCollinear(charucoBoard, charucoIdsAxisLine); - - bool resultDiagonalLine = cv::aruco::testCharucoCornersCollinear(charucoBoard, charucoIdsDiagonalLine); - - EXPECT_TRUE(resultAxisLine); - - EXPECT_TRUE(resultDiagonalLine); -} - -TEST(Charuco, testCharucoCornersCollinear_false) -{ - int squaresX = 13; - int squaresY = 28; - float squareLength = 300; - float markerLength = 150; - int dictionaryId = 11; - - - Ptr detectorParams = aruco::DetectorParameters::create(); - - Ptr dictionary = - aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId)); - - Ptr charucoBoard = - aruco::CharucoBoard::create(squaresX, squaresY, squareLength, markerLength, dictionary); - - // consistency with C++98 - const int arr[63] = {192, 193, 194, 195, 196, 197, 198, 204, 205, 206, 207, 208, - 209, 210, 216, 217, 218, 219, 220, 221, 222, 228, 229, 230, - 231, 232, 233, 234, 240, 241, 242, 243, 244, 245, 246, 252, - 253, 254, 255, 256, 257, 258, 264, 265, 266, 267, 268, 269, - 270, 276, 277, 278, 279, 280, 281, 282, 288, 289, 290, 291, - 292, 293, 294}; - - vector charucoIds(63, 0); - for (int i = 0; i < 63; i++){ - charucoIds[i] = arr[i]; - } - - - bool result = cv::aruco::testCharucoCornersCollinear(charucoBoard, charucoIds); - - EXPECT_FALSE(result); -} - -// test that ChArUco board detection is subpixel accurate -TEST(Charuco, testBoardSubpixelCoords) -{ - cv::Size res{500, 500}; - cv::Mat K = (cv::Mat_(3,3) << - 0.5*res.width, 0, 0.5*res.width, - 0, 0.5*res.height, 0.5*res.height, - 0, 0, 1); - - // set expected_corners values - cv::Mat expected_corners = (cv::Mat_(9,2) << - 200, 200, - 250, 200, - 300, 200, - 200, 250, - 250, 250, - 300, 250, - 200, 300, - 250, 300, - 300, 300 - ); - - cv::Mat gray; - - auto dict = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_APRILTAG_36h11); - auto board = cv::aruco::CharucoBoard::create(4, 4, 1.f, .8f, dict); - - // generate ChArUco board - board->draw(Size(res.width, res.height), gray, 150); - cv::GaussianBlur(gray, gray, Size(5, 5), 1.0); - - auto params = cv::aruco::DetectorParameters::create(); - params->cornerRefinementMethod = cv::aruco::CORNER_REFINE_APRILTAG; - - aruco::ArucoDetector detector(dict, params); - - std::vector ids; - std::vector> corners, rejected; - - detector.detectMarkers(gray, corners, ids, rejected); - - ASSERT_EQ(ids.size(), size_t(8)); - - cv::Mat c_ids, c_corners; - cv::aruco::interpolateCornersCharuco(corners, ids, gray, board, c_corners, c_ids, K); - - ASSERT_EQ(c_corners.rows, expected_corners.rows); - EXPECT_NEAR(0, cvtest::norm(expected_corners, c_corners.reshape(1), NORM_INF), 1e-1); - - c_ids = cv::Mat(); - c_corners = cv::Mat(); - cv::aruco::interpolateCornersCharuco(corners, ids, gray, board, c_corners, c_ids); - - ASSERT_EQ(c_corners.rows, expected_corners.rows); - EXPECT_NEAR(0, cvtest::norm(expected_corners, c_corners.reshape(1), NORM_INF), 1e-1); -} - -TEST(CV_ArucoTutorial, can_find_choriginal) -{ - string imgPath = cvtest::findDataFile("choriginal.jpg", false); - Mat image = imread(imgPath); - aruco::ArucoDetector detector(aruco::getPredefinedDictionary(aruco::DICT_6X6_250)); - - vector< int > ids; - vector< vector< Point2f > > corners, rejected; - const size_t N = 17ull; - // corners of aruco markers with indices goldCornersIds - const int goldCorners[N][8] = { {268,77, 290,80, 286,97, 263,94}, {360,90, 382,93, 379,111, 357,108}, - {211,106, 233,109, 228,127, 205,123}, {306,120, 328,124, 325,142, 302,138}, - {402,135, 425,139, 423,157, 400,154}, {247,152, 271,155, 267,174, 242,171}, - {347,167, 371,171, 369,191, 344,187}, {185,185, 209,189, 203,210, 178,206}, - {288,201, 313,206, 309,227, 284,223}, {393,218, 418,222, 416,245, 391,241}, - {223,240, 250,244, 244,268, 217,263}, {333,258, 359,262, 356,286, 329,282}, - {152,281, 179,285, 171,312, 143,307}, {267,300, 294,305, 289,331, 261,327}, - {383,319, 410,324, 408,351, 380,347}, {194,347, 223,352, 216,382, 186,377}, - {315,368, 345,373, 341,403, 310,398} }; - map mapGoldCorners; - for (int i = 0; i < static_cast(N); i++) - mapGoldCorners[i] = goldCorners[i]; - - detector.detectMarkers(image, corners, ids, rejected); - - ASSERT_EQ(N, ids.size()); - for (size_t i = 0; i < N; i++) - { - int arucoId = ids[i]; - ASSERT_EQ(4ull, corners[i].size()); - ASSERT_TRUE(mapGoldCorners.find(arucoId) != mapGoldCorners.end()); - for (int j = 0; j < 4; j++) - { - EXPECT_NEAR(static_cast(mapGoldCorners[arucoId][j * 2]), corners[i][j].x, 1.f); - EXPECT_NEAR(static_cast(mapGoldCorners[arucoId][j * 2 + 1]), corners[i][j].y, 1.f); - } - } -} - -TEST(CV_ArucoTutorial, can_find_chocclusion) -{ - string imgPath = cvtest::findDataFile("chocclusion_original.jpg", false); - Mat image = imread(imgPath); - aruco::ArucoDetector detector(aruco::getPredefinedDictionary(aruco::DICT_6X6_250)); - - vector< int > ids; - vector< vector< Point2f > > corners, rejected; - const size_t N = 13ull; - // corners of aruco markers with indices goldCornersIds - const int goldCorners[N][8] = { {301,57, 322,62, 317,79, 295,73}, {391,80, 413,85, 408,103, 386,97}, - {242,79, 264,85, 256,102, 234,96}, {334,103, 357,109, 352,126, 329,121}, - {428,129, 451,134, 448,152, 425,146}, {274,128, 296,134, 290,153, 266,147}, - {371,154, 394,160, 390,180, 366,174}, {208,155, 232,161, 223,181, 199,175}, - {309,182, 333,188, 327,209, 302,203}, {411,210, 436,216, 432,238, 407,231}, - {241,212, 267,219, 258,242, 232,235}, {167,244, 194,252, 183,277, 156,269}, - {202,314, 230,322, 220,349, 191,341} }; - map mapGoldCorners; - const int goldCornersIds[N] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 15}; - for (int i = 0; i < static_cast(N); i++) - mapGoldCorners[goldCornersIds[i]] = goldCorners[i]; - - detector.detectMarkers(image, corners, ids, rejected); - - ASSERT_EQ(N, ids.size()); - for (size_t i = 0; i < N; i++) - { - int arucoId = ids[i]; - ASSERT_EQ(4ull, corners[i].size()); - ASSERT_TRUE(mapGoldCorners.find(arucoId) != mapGoldCorners.end()); - for (int j = 0; j < 4; j++) - { - EXPECT_NEAR(static_cast(mapGoldCorners[arucoId][j * 2]), corners[i][j].x, 1.f); - EXPECT_NEAR(static_cast(mapGoldCorners[arucoId][j * 2 + 1]), corners[i][j].y, 1.f); - } - } -} - -TEST(CV_ArucoTutorial, can_find_diamondmarkers) -{ - string imgPath = cvtest::findDataFile("diamondmarkers.png", false); - Mat image = imread(imgPath); - - string dictPath = cvtest::findDataFile("tutorial_dict.yml", false); - Ptr dictionary = makePtr(); - FileStorage fs(dictPath, FileStorage::READ); - dictionary->aruco::Dictionary::readDictionary(fs.root()); // set marker from tutorial_dict.yml - - string detectorPath = cvtest::findDataFile("detector_params.yml", false); - fs = FileStorage(detectorPath, FileStorage::READ); - Ptr detectorParams = aruco::DetectorParameters::create(); - detectorParams->readDetectorParameters(fs.root()); - detectorParams->cornerRefinementMethod = 3; - - aruco::ArucoDetector detector(dictionary, detectorParams); - - vector< int > ids; - vector< vector< Point2f > > corners, rejected; - const size_t N = 12ull; - // corner indices of ArUco markers - const int goldCornersIds[N] = { 4, 12, 11, 3, 12, 10, 12, 10, 10, 11, 2, 11 }; - map counterGoldCornersIds; - for (int i = 0; i < static_cast(N); i++) - counterGoldCornersIds[goldCornersIds[i]]++; - - detector.detectMarkers(image, corners, ids, rejected); - map counterRes; - for (size_t i = 0; i < N; i++) - { - int arucoId = ids[i]; - counterRes[arucoId]++; - } - - ASSERT_EQ(N, ids.size()); - EXPECT_EQ(counterGoldCornersIds, counterRes); // check the number of ArUco markers -} - -TEST(Charuco, issue_14014) -{ - string imgPath = cvtest::findDataFile("aruco/recover.png"); - Mat img = imread(imgPath); - - Ptr detectorParams = aruco::DetectorParameters::create(); - detectorParams->cornerRefinementMethod = aruco::CORNER_REFINE_SUBPIX; - detectorParams->cornerRefinementMinAccuracy = 0.01; - aruco::ArucoDetector detector(aruco::getPredefinedDictionary(aruco::DICT_7X7_250), detectorParams); - Ptr board = aruco::CharucoBoard::create(8, 5, 0.03455f, 0.02164f, detector.dictionary); - - vector corners, rejectedPoints; - vector ids; - - detector.detectMarkers(img, corners, ids, rejectedPoints); - - ASSERT_EQ(corners.size(), 19ull); - EXPECT_EQ(Size(4, 1), corners[0].size()); // check dimension of detected corners - - size_t numRejPoints = rejectedPoints.size(); - ASSERT_EQ(rejectedPoints.size(), 26ull); // optional check to track regressions - EXPECT_EQ(Size(4, 1), rejectedPoints[0].size()); // check dimension of detected corners - - detector.refineDetectedMarkers(img, board, corners, ids, rejectedPoints); - - ASSERT_EQ(corners.size(), 20ull); - EXPECT_EQ(Size(4, 1), corners[0].size()); // check dimension of rejected corners after successfully refine - - ASSERT_EQ(rejectedPoints.size() + 1, numRejPoints); - EXPECT_EQ(Size(4, 1), rejectedPoints[0].size()); // check dimension of rejected corners after successfully refine -} - -}} // namespace diff --git a/modules/aruco/test/test_misc.cpp b/modules/aruco/test/test_misc.cpp deleted file mode 100644 index 2224fc574ac..00000000000 --- a/modules/aruco/test/test_misc.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. - -#include "test_precomp.hpp" - -namespace opencv_test { namespace { - -TEST(CV_ArucoDrawMarker, regression_1226) -{ - int squares_x = 7; - int squares_y = 5; - int bwidth = 1600; - int bheight = 1200; - - cv::Ptr dict = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_4X4_50); - cv::Ptr board = cv::aruco::CharucoBoard::create(squares_x, squares_y, 1.0, 0.75, dict); - cv::Size sz(bwidth, bheight); - cv::Mat mat; - - ASSERT_NO_THROW( - { - board->draw(sz, mat, 0, 1); - }); -} - -}} // namespace diff --git a/modules/aruco/test/test_precomp.hpp b/modules/aruco/test/test_precomp.hpp index c130b27ef31..d57315babde 100644 --- a/modules/aruco/test/test_precomp.hpp +++ b/modules/aruco/test/test_precomp.hpp @@ -7,6 +7,6 @@ #include "opencv2/ts.hpp" #include "opencv2/imgproc.hpp" #include "opencv2/3d.hpp" -#include +#include #endif diff --git a/modules/aruco/tutorials/aruco_board_detection/aruco_board_detection.markdown b/modules/aruco/tutorials/aruco_board_detection/aruco_board_detection.markdown index 6ce8603ecf2..25979d9c09c 100644 --- a/modules/aruco/tutorials/aruco_board_detection/aruco_board_detection.markdown +++ b/modules/aruco/tutorials/aruco_board_detection/aruco_board_detection.markdown @@ -27,61 +27,57 @@ Thus, the pose can be calculated even in the presence of occlusions or partial v - The obtained pose is usually more accurate since a higher amount of point correspondences (marker corners) are employed. -The aruco module allows the use of Boards. The main class is the ```cv::aruco::Board``` class which defines the Board layout: - -@code{.cpp} - class Board { - public: - std::vector > objPoints; - cv::Ptr dictionary; - std::vector ids; - }; -@endcode - -A object of type ```Board``` has three parameters: -- The ```objPoints``` structure is the list of corner positions in the 3d Board reference system, i.e. its layout. -For each marker, its four corners are stored in the standard order, i.e. in clockwise order and starting -with the top left corner. -- The ```dictionary``` parameter indicates to which marker dictionary the Board markers belong to. -- Finally, the ```ids``` structure indicates the identifiers of each of the markers in ```objPoints``` respect to the specified ```dictionary```. - - Board Detection ----- A Board detection is similar to the standard marker detection. The only difference is in the pose estimation step. In fact, to use marker boards, a standard marker detection should be done before estimating the Board pose. -The aruco module provides a specific function, ```estimatePoseBoard()```, to perform pose estimation for boards: +To perform pose estimation for boards, you should use ```#cv::solvePnP``` function, as shown below: @code{.cpp} - cv::Mat inputImage; - // camera parameters are read from somewhere - cv::Mat cameraMatrix, distCoeffs; - // You can read camera parameters from tutorial_camera_params.yml - readCameraParameters(filename, cameraMatrix, distCoeffs); // This function is located in detect_board.cpp - // assume we have a function to create the board object - cv::Ptr board = cv::aruco::Board::create(); - ... - std::vector markerIds; - std::vector> markerCorners; - cv::aruco::detectMarkers(inputImage, board.dictionary, markerCorners, markerIds); - // if at least one marker detected - if(markerIds.size() > 0) { - cv::Vec3d rvec, tvec; - int valid = cv::aruco::estimatePoseBoard(markerCorners, markerIds, board, cameraMatrix, distCoeffs, rvec, tvec); - } +cv::Mat inputImage; + +// Camera parameters are read from somewhere +cv::Mat cameraMatrix, distCoeffs; + +// You can read camera parameters from tutorial_camera_params.yml +readCameraParameters(filename, cameraMatrix, distCoeffs); // This function is implemented in aruco_samples_utility.hpp + +// Assume we have a function to create the board object +cv::Ptr board = cv::aruco::Board::create(); + +... + +std::vector markerIds; +std::vector> markerCorners; + +cv::aruco::DetectorParameters detectorParams = cv::aruco::DetectorParameters(); +cv::aruco::ArucoDetector detector(board.dictionary, detectorParams); + +detector.detectMarkers(inputImage, markerCorners, markerIds); + +cv::Vec3d rvec, tvec; + +// If at least one marker detected +if(markerIds.size() > 0) { + // Get object and image points for the solvePnP function + cv::Mat objPoints, imgPoints; + board->matchImagePoints(markerCorners, markerIds, objPoints, imgPoints); + + // Find pose + cv::solvePnP(objPoints, imgPoints, cameraMatrix, distCoeffs, rvec, tvec); +} + @endcode -The parameters of estimatePoseBoard are: +The parameters are: -- ```markerCorners``` and ```markerIds```: structures of detected markers from ```detectMarkers()``` function. +- ```objPoints```, ```imgPoints```: object and image points, matched with ```matchImagePoints```, which, in turn, takes as input ```markerCorners``` and ```markerIds```: structures of detected markers from ```detectMarkers()``` function). - ```board```: the ```Board``` object that defines the board layout and its ids - ```cameraMatrix``` and ```distCoeffs```: camera calibration parameters necessary for pose estimation. - ```rvec``` and ```tvec```: estimated pose of the Board. If not empty then treated as initial guess. -- The function returns the total number of markers employed for estimating the board pose. Note that not all the - markers provided in ```markerCorners``` and ```markerIds``` should be used, since only the markers whose ids are -listed in the ```Board::ids``` structure are considered. +- The function returns the total number of markers employed for estimating the board pose. The ```drawFrameAxes()``` function can be used to check the obtained pose. For instance: @@ -135,16 +131,15 @@ in any unit, having in mind that the estimated pose for this board will be measu - Finally, the dictionary of the markers is provided. So, this board will be composed by 5x7=35 markers. The ids of each of the markers are assigned, by default, in ascending -order starting on 0, so they will be 0, 1, 2, ..., 34. This can be easily customized by accessing to the ids vector -through ```board.ids```, like in the ```Board``` parent class. +order starting on 0, so they will be 0, 1, 2, ..., 34. After creating a Grid Board, we probably want to print it and use it. A function to generate the image -of a ```GridBoard``` is provided in ```cv::aruco::GridBoard::draw()```. For example: +of a ```GridBoard``` is provided in ```cv::aruco::GridBoard::generateImage()```. For example: @code{.cpp} cv::Ptr board = cv::aruco::GridBoard::create(5, 7, 0.04, 0.01, dictionary); cv::Mat boardImage; - board->draw( cv::Size(600, 500), boardImage, 10, 1 ); + board->generateImage( cv::Size(600, 500), boardImage, 10, 1 ); @endcode - The first parameter is the size of the output image in pixels. In this case 600x500 pixels. If this is not proportional @@ -152,7 +147,7 @@ to the board dimensions, it will be centered on the image. - ```boardImage```: the output image with the board. - The third parameter is the (optional) margin in pixels, so none of the markers are touching the image border. In this case the margin is 10. -- Finally, the size of the marker border, similarly to ```drawMarker()``` function. The default value is 1. +- Finally, the size of the marker border, similarly to ```generateImageMarker()``` function. The default value is 1. The output image will be something like this: @@ -173,13 +168,17 @@ Finally, a full example of board detection: cv::Mat cameraMatrix, distCoeffs; // You can read camera parameters from tutorial_camera_params.yml - readCameraParameters(filename, cameraMatrix, distCoeffs); // This function is located in detect_board.cpp + readCameraParameters(filename, cameraMatrix, distCoeffs); // This function is implemented in aruco_samples_utility.hpp - cv::Ptr dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); - // To use tutorial sample, you need read custome dictionaty from tutorial_dict.yml - readDictionary(filename, dictionary); // This function is located in detect_board.cpp + cv::aruco::Dictionary dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); + + // To use tutorial sample, you need read custom dictionaty from tutorial_dict.yml + readDictionary(filename, dictionary); // This function is implemented in opencv/modules/objdetect/src/aruco/aruco_dictionary.cpp cv::Ptr board = cv::aruco::GridBoard::create(5, 7, 0.04, 0.01, dictionary); + cv::aruco::DetectorParameters detectorParams = cv::aruco::DetectorParameters(); + cv::aruco::ArucoDetector detector(dictionary, detectorParams); + while (inputVideo.grab()) { cv::Mat image, imageCopy; inputVideo.retrieve(image); @@ -187,17 +186,26 @@ Finally, a full example of board detection: std::vector ids; std::vector > corners; - cv::aruco::detectMarkers(image, dictionary, corners, ids); - // if at least one marker detected + // Detect markers + detector.detectMarkers(image, corners, ids); + + // If at least one marker detected if (ids.size() > 0) { cv::aruco::drawDetectedMarkers(imageCopy, corners, ids); cv::Vec3d rvec, tvec; - int valid = estimatePoseBoard(corners, ids, board, cameraMatrix, distCoeffs, rvec, tvec); - // if at least one board marker detected - if(valid > 0) + // Get object and image points for the solvePnP function + cv::Mat objPoints, imgPoints; + board->matchImagePoints(corners, ids, objPoints, imgPoints); + + // Find pose + cv::solvePnP(objPoints, imgPoints, cameraMatrix, distCoeffs, rvec, tvec); + + // If at least one board marker detected + markersOfBoardDetected = (int)objPoints.total() / 4; + if(markersOfBoardDetected > 0) cv::drawFrameAxes(imageCopy, cameraMatrix, distCoeffs, rvec, tvec, 0.1); } @@ -269,13 +277,17 @@ internal bits are not analyzed at all and only the corner distances are evaluate This is an example of using the ```refineDetectedMarkers()``` function: @code{.cpp} - cv::Ptr dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); + + cv::aruco::Dictionary dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); cv::Ptr board = cv::aruco::GridBoard::create(5, 7, 0.04, 0.01, dictionary); + cv::aruco::DetectorParameters detectorParams = cv::aruco::DetectorParameters(); + cv::aruco::ArucoDetector detector(dictionary, detectorParams); + std::vector markerIds; std::vector> markerCorners, rejectedCandidates; - cv::aruco::detectMarkers(inputImage, dictionary, markerCorners, markerIds, cv::aruco::DetectorParameters(), rejectedCandidates); + detector.detectMarkers(inputImage, markerCorners, markerIds, rejectedCandidates); - cv::aruco::refineDetectedMarkersinputImage, board, markerCorners, markerIds, rejectedCandidates); + detector.refineDetectedMarkers(inputImage, board, markerCorners, markerIds, rejectedCandidates); // After calling this function, if any new marker has been detected it will be removed from rejectedCandidates and included // at the end of markerCorners and markerIds @endcode diff --git a/modules/aruco/tutorials/aruco_detection/aruco_detection.markdown b/modules/aruco/tutorials/aruco_detection/aruco_detection.markdown index 2e81d09b1f9..b2096d3a0bc 100644 --- a/modules/aruco/tutorials/aruco_detection/aruco_detection.markdown +++ b/modules/aruco/tutorials/aruco_detection/aruco_detection.markdown @@ -14,11 +14,7 @@ to obtain the camera pose. Also, the inner binary codification makes them specia the possibility of applying error detection and correction techniques. The aruco module is based on the [ArUco library](http://www.uco.es/investiga/grupos/ava/node/26), -a popular library for detection of square fiducial markers developed by Rafael Muñoz and Sergio Garrido: - -> S. Garrido-Jurado, R. Muñoz-Salinas, F. J. Madrid-Cuevas, and M. J. Marín-Jiménez. 2014. -> "Automatic generation and detection of highly reliable fiducial markers under occlusion". -> Pattern Recogn. 47, 6 (June 2014), 2280-2292. DOI=10.1016/j.patcog.2014.01.005 +a popular library for detection of square fiducial markers developed by Rafael Muñoz and Sergio Garrido @cite Aruco2014. The aruco functionalities are included in: @code{.cpp} @@ -67,24 +63,24 @@ Marker Creation ------ Before their detection, markers need to be printed in order to be placed in the environment. -Marker images can be generated using the `drawMarker()` function. +Marker images can be generated using the `generateImageMarker()` function. For example, lets analyze the following call: @code{.cpp} cv::Mat markerImage; -cv::Ptr dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); -cv::aruco::drawMarker(dictionary, 23, 200, markerImage, 1); +cv::aruco::Dictionary dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); +cv::aruco::generateImageMarker(dictionary, 23, 200, markerImage, 1); cv::imwrite("marker23.png", markerImage); @endcode First, the `Dictionary` object is created by choosing one of the predefined dictionaries in the aruco module. -Concretely, this dictionary is composed of 250 markers and a marker size of 6x6 bits (`DICT_6X6_250`). +Concretely, this dictionary is composed of 250 markers and a marker size of 6x6 bits (`#cv::aruco::DICT_6X6_250`). -The parameters of `drawMarker` are: +The parameters of `generateImageMarker` are: - The first parameter is the `Dictionary` object previously created. -- The second parameter is the marker id, in this case the marker 23 of the dictionary `DICT_6X6_250`. +- The second parameter is the marker id, in this case the marker 23 of the dictionary `#cv::aruco::DICT_6X6_250`. Note that each dictionary is composed of a different number of markers. In this case, the valid ids go from 0 to 249. Any specific id out of the valid range will produce an exception. - The third parameter, 200, is the size of the output marker image. In this case, the output image @@ -167,22 +163,25 @@ cv::Mat inputImage; ... std::vector markerIds; std::vector> markerCorners, rejectedCandidates; -cv::Ptr parameters = cv::aruco::DetectorParameters::create(); -cv::Ptr dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); -cv::aruco::detectMarkers(inputImage, dictionary, markerCorners, markerIds, parameters, rejectedCandidates); +cv::aruco::DetectorParameters detectorParams = cv::aruco::DetectorParameters(); +cv::aruco::Dictionary dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); +cv::aruco::ArucoDetector detector(dictionary, detectorParams); +detector.detectMarkers(inputImage, markerCorners, markerIds, rejectedCandidates); @endcode +When you create an `#cv::aruco::ArucoDetector` object, you need to pass the following parameters to the constructor: + +- A dictionary object, in this case one of the predefined dictionaries (`#cv::aruco::DICT_6X6_250`). +- Object of type `#cv::aruco::DetectorParameters`. This object includes all parameters that can be customized during the detection process. These parameters will be explained in the next section. + The parameters of `detectMarkers` are: - The first parameter is the image containing the markers to be detected. -- The second parameter is the dictionary object, in this case one of the predefined dictionaries (`DICT_6X6_250`). - The detected markers are stored in the `markerCorners` and `markerIds` structures: - `markerCorners` is the list of corners of the detected markers. For each marker, its four corners are returned in their original order (which is clockwise starting with top left). So, the first corner is the top left corner, followed by the top right, bottom right and bottom left. - `markerIds` is the list of ids of each of the detected markers in `markerCorners`. Note that the returned `markerCorners` and `markerIds` vectors have the same size. -- The fourth parameter is the object of type `DetectionParameters`. This object includes all the -parameters that can be customized during the detection process. These parameters are explained in the next section. - The final parameter, `rejectedCandidates`, is a returned list of marker candidates, i.e. shapes that were found and considered but did not contain a valid marker. Each candidate is also defined by its four corners, and its format is the same as the `markerCorners` parameter. This @@ -211,15 +210,19 @@ camera: @code{.cpp} cv::VideoCapture inputVideo; inputVideo.open(0); -cv::Ptr dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); + +cv::aruco::DetectorParameters detectorParams = cv::aruco::DetectorParameters(); +cv::aruco::Dictionary dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); +cv::aruco::ArucoDetector detector(dictionary, detectorParams); + while (inputVideo.grab()) { cv::Mat image, imageCopy; inputVideo.retrieve(image); image.copyTo(imageCopy); std::vector ids; - std::vector > corners; - cv::aruco::detectMarkers(image, dictionary, corners, ids); + std::vector> corners, rejected; + detector.detectMarkers(image, corners, ids, rejected); // if at least one marker detected if (ids.size() > 0) @@ -248,15 +251,15 @@ Parameters for `detect_markers.cpp`: Pose Estimation ------ -The next thing you probably want to do after detecting the markers is to obtain the camera pose from them. +The next thing you'll probably want to do after detecting the markers is to use them to get the camera pose. -To perform camera pose estimation you need to know the calibration parameters of your camera. These are +To perform camera pose estimation, you need to know your camera's calibration parameters. These are the camera matrix and distortion coefficients. If you do not know how to calibrate your camera, you can take a look at the `calibrateCamera()` function and the Calibration tutorial of OpenCV. You can also calibrate your camera using the aruco module as explained in the **Calibration with ArUco and ChArUco** tutorial. Note that this only needs to be done once unless the camera optics are modified (for instance changing its focus). -In the end, what you get after the calibration is the camera matrix: a matrix of 3x3 elements with the +As a result of the calibration, you get a camera matrix: a matrix of 3x3 elements with the focal distances and the camera center coordinates (a.k.a intrinsic parameters), and the distortion coefficients: a vector of 5 or more elements that models the distortion produced by your camera. @@ -264,19 +267,25 @@ When you estimate the pose with ArUco markers, you can estimate the pose of each If you want to estimate one pose from a set of markers, use ArUco Boards (see the **Detection of ArUco Boards** tutorial). Using ArUco boards instead of single markers allows some markers to be occluded. -The camera pose with respect to a marker is the 3d transformation from the marker coordinate system to the -camera coordinate system. It is specified by rotation and translation vectors (see `solvePnP()` function for more +The camera pose relative to the marker is a 3d transformation from the marker coordinate system to the +camera coordinate system. It is specified by rotation and translation vectors (see `#cv::solvePnP()` function for more information). -The aruco module provides a function to estimate the poses of all the detected markers: - @code{.cpp} cv::Mat cameraMatrix, distCoeffs; // You can read camera parameters from tutorial_camera_params.yml -readCameraParameters(filename, cameraMatrix, distCoeffs); // This function is located in detect_markers.cpp +readCameraParameters(cameraParamsFilename, cameraMatrix, distCoeffs); // This function is implemented in aruco_samples_utility.hpp std::vector rvecs, tvecs; -cv::aruco::estimatePoseSingleMarkers(markerCorners, 0.05, cameraMatrix, distCoeffs, rvecs, tvecs); + +// Set coordinate system +cv::Mat objPoints(4, 1, CV_32FC3); +... + +// Calculate pose for each marker +for (int i = 0; i < nMarkers; i++) { + solvePnP(objPoints, corners.at(i), cameraMatrix, distCoeffs, rvecs.at(i), tvecs.at(i)); +} @endcode - The `markerCorners` parameter is the vector of marker corners returned by the `detectMarkers()` function. @@ -316,10 +325,21 @@ cv::VideoCapture inputVideo; inputVideo.open(0); cv::Mat cameraMatrix, distCoeffs; +float markerLength = 0.05; + // You can read camera parameters from tutorial_camera_params.yml -readCameraParameters(filename, cameraMatrix, distCoeffs); // This function is located in detect_markers.cpp +readCameraParameters(cameraParamsFilename, cameraMatrix, distCoeffs); // This function is implemented in aruco_samples_utility.hpp + +// Set coordinate system +cv::Mat objPoints(4, 1, CV_32FC3); +objPoints.ptr(0)[0] = cv::Vec3f(-markerLength/2.f, markerLength/2.f, 0); +objPoints.ptr(0)[1] = cv::Vec3f(markerLength/2.f, markerLength/2.f, 0); +objPoints.ptr(0)[2] = cv::Vec3f(markerLength/2.f, -markerLength/2.f, 0); +objPoints.ptr(0)[3] = cv::Vec3f(-markerLength/2.f, -markerLength/2.f, 0); -cv::Ptr dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); +cv::aruco::DetectorParameters detectorParams = cv::aruco::DetectorParameters(); +cv::aruco::Dictionary dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); +aruco::ArucoDetector detector(dictionary, detectorParams); while (inputVideo.grab()) { cv::Mat image, imageCopy; @@ -328,19 +348,27 @@ while (inputVideo.grab()) { std::vector ids; std::vector> corners; - cv::aruco::detectMarkers(image, dictionary, corners, ids); + detector.detectMarkers(image, corners, ids); - // if at least one marker detected + // If at least one marker detected if (ids.size() > 0) { cv::aruco::drawDetectedMarkers(imageCopy, corners, ids); - std::vector rvecs, tvecs; - cv::aruco::estimatePoseSingleMarkers(corners, 0.05, cameraMatrix, distCoeffs, rvecs, tvecs); - // draw axis for each marker - for(int i=0; i rvecs(nMarkers), tvecs(nMarkers); + + // Calculate pose for each marker + for (int i = 0; i < nMarkers; i++) { + solvePnP(objPoints, corners.at(i), cameraMatrix, distCoeffs, rvecs.at(i), tvecs.at(i)); + } + + // Draw axis for each marker + for(unsigned int i = 0; i < ids.size(); i++) { cv::drawFrameAxes(imageCopy, cameraMatrix, distCoeffs, rvecs[i], tvecs[i], 0.1); + } } + // Show resulting image and close window cv::imshow("out", imageCopy); char key = (char) cv::waitKey(waitTime); if (key == 27) @@ -363,8 +391,9 @@ Note: The samples now take input from the command line using cv::CommandLinePars @endcode Parameters for `detect_markers.cpp`: @snippet samples/detect_markers.cpp aruco_detect_markers_keys + @note To work with examples from the tutorial, you can use camera parameters from `tutorial_camera_params.yml`. -An example of use in `detect.cpp`. +An example of use in `detect_markers.cpp`. @@ -373,12 +402,12 @@ Selecting a dictionary The aruco module provides the `Dictionary` class to represent a dictionary of markers. -In addition to the marker size and the number of markers in the dictionary, there is another important dictionary -parameter, the inter-marker distance. The inter-marker distance is the minimum distance among its markers -and it determines the error detection and correction capabilities of the dictionary. +In addition to the marker size and the number of markers in the dictionary, there is another important parameter of the dictionary - +the inter-marker distance. The inter-marker distance is the minimum distance between dictionary markers +that determines the dictionary's ability to detect and correct errors. -In general, lower dictionary sizes and higher marker sizes increase the inter-marker distance and -vice-versa. However, the detection of markers with higher sizes is more complex, due to the higher +In general, smaller dictionary sizes and larger marker sizes increase the inter-marker distance and +vice versa. However, the detection of markers with larger sizes is more difficult due to the higher number of bits that need to be extracted from the image. For instance, if you need only 10 markers in your application, it is better to use a dictionary composed only of those 10 markers than using a dictionary composed of 1000 markers. The reason is that @@ -390,29 +419,28 @@ you can increase your system robustness: ### Predefined dictionaries -This is the easiest way to select a dictionary. The aruco module includes a set of predefined dictionaries - in a variety of marker sizes and number of markers. For instance: +This is the easiest way to select a dictionary. The aruco module includes a set of predefined +dictionaries in a variety of marker sizes and number of markers. For instance: @code{.cpp} - cv::Ptr dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); +cv::aruco::Dictionary dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); @endcode -`DICT_6X6_250` is an example of predefined dictionary of markers with 6x6 bits and a total of 250 +`#cv::aruco::DICT_6X6_250` is an example of predefined dictionary of markers with 6x6 bits and a total of 250 markers. From all the provided dictionaries, it is recommended to choose the smallest one that fits your application. -For instance, if you need 200 markers of 6x6 bits, it is better to use `DICT_6X6_250` than `DICT_6X6_1000`. +For instance, if you need 200 markers of 6x6 bits, it is better to use `#cv::aruco::DICT_6X6_250` than `cv::aruco::DICT_6X6_1000`. The smaller the dictionary, the higher the inter-marker distance. -The list of available predefined dictionaries can be found in the documentation for the `PREDEFINED_DICTIONARY_NAME` enum. +The list of available predefined dictionaries can be found in the documentation for the `PredefinedDictionaryType` enum. ### Automatic dictionary generation -The dictionary can be generated automatically to adjust to the desired number of markers and bits, so that -the inter-marker distance is optimized: +A dictionary can be generated automatically to adjust the desired number of markers and bits to optimize the inter-marker distance: @code{.cpp} - cv::Ptr dictionary = cv::aruco::generateCustomDictionary(36, 5); +cv::aruco::Dictiojary dictionary = cv::aruco::extendDictionary(36, 5); @endcode This will generate a customized dictionary composed of 36 markers of 5x5 bits. The process can take several @@ -420,20 +448,19 @@ seconds, depending on the parameters (it is slower for larger dictionaries and h ### Manual dictionary generation -Finally, the dictionary can be configured manually, so that any codification can be employed. To do that, +Finally, the dictionary can be configured manually, so that any encoding can be used. To do that, the `Dictionary` object parameters need to be assigned manually. It must be noted that, unless you have - a special reason to do this manually, it is preferable to use one of the previous alternatives. +a special reason to do this manually, it is preferable to use one of the previous alternatives. The `Dictionary` parameters are: - @code{.cpp} class Dictionary { public: - Mat bytesList; - int markerSize; - int maxCorrectionBits; // maximum number of bits that can be corrected + cv::Mat bytesList; // marker code information + int markerSize; // number of bits per dimension + int maxCorrectionBits; // maximum number of bits that can be corrected ... @@ -454,19 +481,22 @@ For example: @code{.cpp} cv::aruco::Dictionary dictionary; - // markers of 6x6 bits + + // Markers of 6x6 bits dictionary.markerSize = 6; - // maximum number of bit corrections + + // Maximum number of bit corrections dictionary.maxCorrectionBits = 3; - // lets create a dictionary of 100 markers - for(int i=0; i<100; i++) + // Let's create a dictionary of 100 markers + for(int i = 0; i < 100; i++) { - // assume generateMarkerBits() generates a new marker in binary format, so that + // Assume generateMarkerBits() generates a new marker in binary format, so that // markerBits is a 6x6 matrix of CV_8UC1 type, only containing 0s and 1s cv::Mat markerBits = generateMarkerBits(); cv::Mat markerCompressed = cv::aruco::Dictionary::getByteListFromBits(markerBits); - // add the marker as a new row + + // Add the marker as a new row dictionary.bytesList.push_back(markerCompressed); } @endcode @@ -477,7 +507,7 @@ For example: Detector Parameters ------ -One of the parameters of `detectMarkers()` function is a `DetectorParameters` object. This object +One of the parameters of `ArucoDetector` is a `DetectorParameters` object. This object includes all the options that can be customized during the marker detection process. This section describes each detector parameter. The parameters can be classified depending on @@ -485,7 +515,7 @@ the process in which they’re involved: ### Thresholding -One of the first steps of the marker detection process is an adaptive thresholding of the input image. +One of the first steps in the marker detection process is adaptive thresholding of the input image. For instance, the thresholded image for the sample image used above is: @@ -506,12 +536,12 @@ For instance, for the values `adaptiveThreshWinSizeMin` = 5 and `adaptiveThreshW `adaptiveThreshWinSizeStep` = 4, there will be 5 thresholding steps with window sizes 5, 9, 13, 17 and 21. On each thresholding image, marker candidates will be extracted. -Low values of window size can ‘break’ the marker border if the marker size is too large, causing it to not be detected, as in the following image: +Low values of window size can "break" the marker border if the marker size is too large, causing it to not be detected, as in the following image: ![Broken marker image](images/singlemarkersbrokenthresh.png) -On the other hand, values that are too high can produce the same effect if the markers are too small, and it can also -reduce the performance. Moreover the process would tend to a global thresholding, losing the adaptive benefits. +On the other hand, too large values can produce the same effect if the markers are too small, and can also +reduce the performance. Moreover the process will tend to global thresholding, resulting in a loss of adaptive benefits. The simplest case is using the same value for `adaptiveThreshWinSizeMin` and `adaptiveThreshWinSizeMax`, which produces a single thresholding step. However, it is usually better to use a @@ -556,8 +586,8 @@ For instance, a image with size 640x480 and a minimum relative marker perimeter to a minimum marker perimeter of 640x0.05 = 32 pixels, since 640 is the maximum dimension of the image. The same applies for the `maxMarkerPerimeterRate` parameter. -If the `minMarkerPerimeterRate` is too low, it can penalize considerably the detection performance since -many more contours would be considered for future stages. +If the `minMarkerPerimeterRate` is too low, detection performance can be significantly reduced, +as many more contours will be considered for future stages. This penalization is not so noticeable for the `maxMarkerPerimeterRate` parameter, since there are usually many more small contours than big contours. A `minMarkerPerimeterRate` value of 0 and a `maxMarkerPerimeterRate` value of 4 (or more) will be @@ -623,8 +653,8 @@ Default value: After candidate detection, the bits of each candidate are analyzed in order to determine if they are markers or not. -Before analyzing the binary code itself, the bits need to be extracted. To do so, the perspective -distortion is removed and the resulting image is thresholded using Otsu threshold to separate +Before analyzing the binary code itself, the bits need to be extracted. To do this, perspective +distortion is corrected and the resulting image is thresholded using Otsu threshold to separate black and white pixels. This is an example of the image obtained after removing the perspective distortion of a marker: @@ -644,7 +674,7 @@ This parameter indicates the width of the marker border. It is relative to the s value of 2 indicates the border has the width of two internal bits. This parameter needs to coincide with the border size of the markers you are using. The border size -can be configured in the marker drawing functions such as `drawMarker()`. +can be configured in the marker drawing functions such as `generateImageMarker()`. Default value: @@ -663,7 +693,7 @@ Default value: #### perspectiveRemovePixelPerCell -This parameter determines the number of pixels (per cell) in the obtained image after removing perspective +This parameter determines the number of pixels (per cell) in the obtained image after correcting perspective distortion (including the border). This is the size of the red squares in the image above. For instance, let’s assume we are dealing with markers of 5x5 bits and border size of 1 bit @@ -687,7 +717,7 @@ not recommended to consider all the cell pixels. Instead it is better to ignore margins of the cells. The reason for this is that, after removing the perspective distortion, the cells’ colors are, in general, not -perfectly separated and white cells can invade some pixels of black cells (and vice-versa). Thus, it is +perfectly separated and white cells can invade some pixels of black cells (and vice versa). Thus, it is better to ignore some pixels just to avoid counting erroneous pixels. For instance, in the following image: @@ -748,8 +778,9 @@ be accurate, for instance for pose estimation. It is usually a time-consuming st #### cornerRefinementMethod -This parameter determines whether the corner subpixel process is performed or not and which method to use if it is being performed. It can be disabled -if accurate corners are not necessary. Possible values are `CORNER_REFINE_NONE`, `CORNER_REFINE_SUBPIX`, `CORNER_REFINE_CONTOUR`, and `CORNER_REFINE_APRILTAG`. +This parameter determines whether the corner subpixel process is performed or not and which method to use +if it is being performed. It can be disabled if accurate corners are not necessary. Possible values are +`CORNER_REFINE_NONE`, `CORNER_REFINE_SUBPIX`, `CORNER_REFINE_CONTOUR`, and `CORNER_REFINE_APRILTAG`. Default value: @@ -759,9 +790,8 @@ Default value: This parameter determines the window size of the subpixel refinement process. -High values can produce the effect that close image corners are included in the window region, so that the -marker corner moves to a different and wrong location during the process. Furthermore -it can affect performance. +High values can cause close corners of the image to be included in the window area, so that the corner +of the marker moves to a different and incorrect location during the process. Also, it may affect performance. Default value: @@ -773,8 +803,8 @@ These two parameters determine the stop criteria of the subpixel refinement proc `cornerRefinementMaxIterations` indicates the maximum number of iterations and `cornerRefinementMinAccuracy` the minimum error value before stopping the process. -If the number of iterations is too high, it can affect the performance. On the other hand, if it is -too low, it can produce a poor subpixel refinement. +If the number of iterations is too high, it may affect the performance. On the other hand, if it is +too low, it can result in poor subpixel refinement. Default values: diff --git a/modules/aruco/tutorials/charuco_detection/charuco_detection.markdown b/modules/aruco/tutorials/charuco_detection/charuco_detection.markdown index ddcd5e91beb..5d47ce59269 100644 --- a/modules/aruco/tutorials/charuco_detection/charuco_detection.markdown +++ b/modules/aruco/tutorials/charuco_detection/charuco_detection.markdown @@ -75,7 +75,7 @@ The ids of each of the markers are assigned by default in ascending order and st This can be easily customized by accessing to the ids vector through ```board.ids```, like in the ```Board``` parent class. Once we have our ```CharucoBoard``` object, we can create an image to print it. This can be done with the -CharucoBoard::draw() method: +CharucoBoard::generateImage() method: @snippet samples/tutorial_charuco_create_detect.cpp createBoard @@ -84,7 +84,7 @@ to the board dimensions, it will be centered on the image. - ```boardImage```: the output image with the board. - The third parameter is the (optional) margin in pixels, so none of the markers are touching the image border. In this case the margin is 10. -- Finally, the size of the marker border, similarly to ```drawMarker()``` function. The default value is 1. +- Finally, the size of the marker border, similarly to ```generateImageMarker()``` function. The default value is 1. The output image will be something like this: diff --git a/modules/barcode/src/detector/bardetect.cpp b/modules/barcode/src/detector/bardetect.cpp index 72990b3cc8a..ec0806970c0 100644 --- a/modules/barcode/src/detector/bardetect.cpp +++ b/modules/barcode/src/detector/bardetect.cpp @@ -86,6 +86,9 @@ void Detect::localization() for (const float scale:SCALE_LIST) { window_size = cvRound(min_side * scale); + if(window_size == 0) { + window_size = 1; + } calCoherence(window_size); barcodeErode(); regionGrowing(window_size); diff --git a/modules/cudaarithm/src/arithm.cpp b/modules/cudaarithm/src/arithm.cpp index 381580cff43..30cf225e154 100644 --- a/modules/cudaarithm/src/arithm.cpp +++ b/modules/cudaarithm/src/arithm.cpp @@ -439,7 +439,8 @@ namespace class ConvolutionImpl : public Convolution { public: - explicit ConvolutionImpl(Size user_block_size_) : user_block_size(user_block_size_) {} + explicit ConvolutionImpl(Size user_block_size_) : user_block_size(user_block_size_), planR2C(0), planC2R(0) {} + ~ConvolutionImpl(); void convolve(InputArray image, InputArray templ, OutputArray result, bool ccorr = false, Stream& stream = Stream::Null()); @@ -452,6 +453,9 @@ namespace Size user_block_size; Size dft_size; + cufftHandle planR2C, planC2R; + Size plan_size; + GpuMat image_spect, templ_spect, result_spect; GpuMat image_block, templ_block, result_data; }; @@ -491,6 +495,27 @@ namespace // Use maximum result matrix block size for the estimated DFT block size block_size.width = std::min(dft_size.width - templ_size.width + 1, result_size.width); block_size.height = std::min(dft_size.height - templ_size.height + 1, result_size.height); + + if (dft_size != plan_size) + { + if (planR2C != 0) + cufftSafeCall( cufftDestroy(planR2C) ); + if (planC2R != 0) + cufftSafeCall( cufftDestroy(planC2R) ); + + cufftSafeCall( cufftPlan2d(&planC2R, dft_size.height, dft_size.width, CUFFT_C2R) ); + cufftSafeCall( cufftPlan2d(&planR2C, dft_size.height, dft_size.width, CUFFT_R2C) ); + + plan_size = dft_size; + } + } + + ConvolutionImpl::~ConvolutionImpl() + { + if (planR2C != 0) + cufftSafeCall( cufftDestroy(planR2C) ); + if (planC2R != 0) + cufftSafeCall( cufftDestroy(planC2R) ); } Size ConvolutionImpl::estimateBlockSize(Size result_size) @@ -516,10 +541,6 @@ namespace cudaStream_t stream = StreamAccessor::getStream(_stream); - cufftHandle planR2C, planC2R; - cufftSafeCall( cufftPlan2d(&planC2R, dft_size.height, dft_size.width, CUFFT_C2R) ); - cufftSafeCall( cufftPlan2d(&planR2C, dft_size.height, dft_size.width, CUFFT_R2C) ); - cufftSafeCall( cufftSetStream(planR2C, stream) ); cufftSafeCall( cufftSetStream(planC2R, stream) ); @@ -559,9 +580,6 @@ namespace } } - cufftSafeCall( cufftDestroy(planR2C) ); - cufftSafeCall( cufftDestroy(planC2R) ); - syncOutput(result, _result, _stream); } } diff --git a/modules/cudaarithm/src/cuda/lut.cu b/modules/cudaarithm/src/cuda/lut.cu index 336f9b28859..26e69db9a96 100644 --- a/modules/cudaarithm/src/cuda/lut.cu +++ b/modules/cudaarithm/src/cuda/lut.cu @@ -53,6 +53,7 @@ #include "opencv2/cudaarithm.hpp" #include "opencv2/cudev.hpp" #include "opencv2/core/private.cuda.hpp" +#include using namespace cv; using namespace cv::cuda; @@ -60,8 +61,6 @@ using namespace cv::cudev; namespace cv { namespace cuda { - texture texLutTable; - LookUpTableImpl::LookUpTableImpl(InputArray _lut) { if (_lut.kind() == _InputArray::CUDA_GPU_MAT) @@ -73,83 +72,28 @@ namespace cv { namespace cuda { Mat h_lut = _lut.getMat(); d_lut.upload(Mat(1, 256, h_lut.type(), h_lut.data)); } - CV_Assert( d_lut.depth() == CV_8U ); CV_Assert( d_lut.rows == 1 && d_lut.cols == 256 ); - - cc30 = deviceSupports(FEATURE_SET_COMPUTE_30); - - if (cc30) - { - // Use the texture object - cudaResourceDesc texRes; - std::memset(&texRes, 0, sizeof(texRes)); - texRes.resType = cudaResourceTypeLinear; - texRes.res.linear.devPtr = d_lut.data; - texRes.res.linear.desc = cudaCreateChannelDesc(); - texRes.res.linear.sizeInBytes = 256 * d_lut.channels() * sizeof(uchar); - - cudaTextureDesc texDescr; - std::memset(&texDescr, 0, sizeof(texDescr)); - - CV_CUDEV_SAFE_CALL( cudaCreateTextureObject(&texLutTableObj, &texRes, &texDescr, 0) ); - } - else - { - // Use the texture reference - cudaChannelFormatDesc desc = cudaCreateChannelDesc(); - CV_CUDEV_SAFE_CALL( cudaBindTexture(0, &texLutTable, d_lut.data, &desc) ); - } - } - - LookUpTableImpl::~LookUpTableImpl() - { - if (cc30) - { - // Use the texture object - cudaDestroyTextureObject(texLutTableObj); - } - else - { - // Use the texture reference - cudaUnbindTexture(texLutTable); - } + szInBytes = 256 * d_lut.channels() * sizeof(uchar); } struct LutTablePtrC1 { typedef uchar value_type; typedef uchar index_type; - - cudaTextureObject_t texLutTableObj; - - __device__ __forceinline__ uchar operator ()(uchar, uchar x) const - { - #if CV_CUDEV_ARCH < 300 - // Use the texture reference - return tex1Dfetch(texLutTable, x); - #else - // Use the texture object - return tex1Dfetch(texLutTableObj, x); - #endif + cv::cudev::TexturePtr tex; + __device__ __forceinline__ uchar operator ()(uchar, uchar x) const { + return tex(x); } }; + struct LutTablePtrC3 { typedef uchar3 value_type; typedef uchar3 index_type; - - cudaTextureObject_t texLutTableObj; - - __device__ __forceinline__ uchar3 operator ()(const uchar3&, const uchar3& x) const - { - #if CV_CUDEV_ARCH < 300 - // Use the texture reference - return make_uchar3(tex1Dfetch(texLutTable, x.x * 3), tex1Dfetch(texLutTable, x.y * 3 + 1), tex1Dfetch(texLutTable, x.z * 3 + 2)); - #else - // Use the texture object - return make_uchar3(tex1Dfetch(texLutTableObj, x.x * 3), tex1Dfetch(texLutTableObj, x.y * 3 + 1), tex1Dfetch(texLutTableObj, x.z * 3 + 2)); - #endif + cv::cudev::TexturePtr tex; + __device__ __forceinline__ uchar3 operator ()(const uchar3&, const uchar3& x) const { + return make_uchar3(tex(x.x * 3), tex(x.y * 3 + 1), tex(x.z * 3 + 2)); } }; @@ -169,20 +113,18 @@ namespace cv { namespace cuda { { GpuMat_ src1(src.reshape(1)); GpuMat_ dst1(dst.reshape(1)); - + cv::cudev::Texture tex(szInBytes, reinterpret_cast(d_lut.data)); LutTablePtrC1 tbl; - tbl.texLutTableObj = texLutTableObj; - + tbl.tex = TexturePtr(tex); dst1.assign(lut_(src1, tbl), stream); } else if (lut_cn == 3) { GpuMat_& src3 = (GpuMat_&) src; GpuMat_& dst3 = (GpuMat_&) dst; - + cv::cudev::Texture tex(szInBytes, reinterpret_cast(d_lut.data)); LutTablePtrC3 tbl; - tbl.texLutTableObj = texLutTableObj; - + tbl.tex = TexturePtr(tex); dst3.assign(lut_(src3, tbl), stream); } diff --git a/modules/cudaarithm/src/lut.hpp b/modules/cudaarithm/src/lut.hpp index 2c63e9acdfc..d28b1a9e9a8 100644 --- a/modules/cudaarithm/src/lut.hpp +++ b/modules/cudaarithm/src/lut.hpp @@ -15,14 +15,10 @@ class LookUpTableImpl : public LookUpTable { public: LookUpTableImpl(InputArray lut); - ~LookUpTableImpl(); - void transform(InputArray src, OutputArray dst, Stream& stream = Stream::Null()) CV_OVERRIDE; - private: GpuMat d_lut; - cudaTextureObject_t texLutTableObj; - bool cc30; + size_t szInBytes = 0; }; } } diff --git a/modules/cudacodec/CMakeLists.txt b/modules/cudacodec/CMakeLists.txt index 071404ecc76..6ff9f1ae9d7 100644 --- a/modules/cudacodec/CMakeLists.txt +++ b/modules/cudacodec/CMakeLists.txt @@ -6,24 +6,33 @@ set(the_description "CUDA-accelerated Video Encoding/Decoding") ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4127 /wd4324 /wd4512 -Wundef -Wshadow) -ocv_add_module(cudacodec opencv_core opencv_videoio OPTIONAL opencv_cudev WRAP python) +set(required_dependencies opencv_core opencv_videoio opencv_cudaarithm opencv_cudawarping) +if(HAVE_NVCUVENC) + list(APPEND required_dependencies opencv_cudaimgproc) +endif() + +ocv_add_module(cudacodec ${required_dependencies} OPTIONAL opencv_cudev WRAP python) ocv_module_include_directories() ocv_glob_module_sources() set(extra_libs "") -if(HAVE_NVCUVID) - list(APPEND extra_libs ${CUDA_CUDA_LIBRARY} ${CUDA_nvcuvid_LIBRARY}) -endif() - -if(HAVE_NVCUVENC) - if(WIN32) - list(APPEND extra_libs ${CUDA_nvcuvenc_LIBRARY}) +if(HAVE_NVCUVID OR HAVE_NVCUVENC) + list(APPEND extra_libs ${CUDA_CUDA_LIBRARY}) + if(HAVE_NVCUVID) + list(APPEND extra_libs ${CUDA_nvcuvid_LIBRARY}) + endif() + if(HAVE_NVCUVENC) + if(WIN32) + list(APPEND extra_libs ${CUDA_nvencodeapi_LIBRARY}) + else() + list(APPEND extra_libs ${CUDA_nvidia-encode_LIBRARY}) + endif() endif() endif() ocv_create_module(${extra_libs}) ocv_add_accuracy_tests() -ocv_add_perf_tests() +ocv_add_perf_tests() \ No newline at end of file diff --git a/modules/cudacodec/include/opencv2/cudacodec.hpp b/modules/cudacodec/include/opencv2/cudacodec.hpp index 54ec5bed0a8..d61673cd71f 100644 --- a/modules/cudacodec/include/opencv2/cudacodec.hpp +++ b/modules/cudacodec/include/opencv2/cudacodec.hpp @@ -66,114 +66,170 @@ using namespace cuda; // Stream ////////////////////////////////// Video Encoding ////////////////////////////////// -// Works only under Windows. -// Supports only H264 video codec and AVI files. - -enum SurfaceFormat +/** @brief Video codecs supported by cudacodec::VideoReader and cudacodec::VideoWriter. +@note + - Support will depend on your hardware, refer to the Nvidia Video Codec SDK Video Encode and Decode GPU Support Matrix for details. + */ +enum Codec { - SF_UYVY = 0, - SF_YUY2, - SF_YV12, - SF_NV12, - SF_IYUV, - SF_BGR, - SF_GRAY = SF_BGR + MPEG1 = 0, + MPEG2, + MPEG4, + VC1, + H264, + JPEG, + H264_SVC, + H264_MVC, + HEVC, + VP8, + VP9, + AV1, + NumCodecs, + + Uncompressed_YUV420 = (('I' << 24) | ('Y' << 16) | ('U' << 8) | ('V')), //!< Y,U,V (4:2:0) + Uncompressed_YV12 = (('Y' << 24) | ('V' << 16) | ('1' << 8) | ('2')), //!< Y,V,U (4:2:0) + Uncompressed_NV12 = (('N' << 24) | ('V' << 16) | ('1' << 8) | ('2')), //!< Y,UV (4:2:0) + Uncompressed_YUYV = (('Y' << 24) | ('U' << 16) | ('Y' << 8) | ('V')), //!< YUYV/YUY2 (4:2:2) + Uncompressed_UYVY = (('U' << 24) | ('Y' << 16) | ('V' << 8) | ('Y')) //!< UYVY (4:2:2) }; -/** @brief Different parameters for CUDA video encoder. - */ -struct CV_EXPORTS_W EncoderParams +/** @brief ColorFormat for the frame returned by VideoReader::nextFrame() and VideoReader::retrieve() or used to initialize a VideoWriter. +*/ +enum class ColorFormat { + UNDEFINED = 0, + BGRA = 1, //!< OpenCV color format, can be used with both VideoReader and VideoWriter. + BGR = 2, //!< OpenCV color format, can be used with both VideoReader and VideoWriter. + GRAY = 3, //!< OpenCV color format, can be used with both VideoReader and VideoWriter. + NV_NV12 = 4, //!< Nvidia color format - equivalent to YUV - Semi-Planar YUV [Y plane followed by interleaved UV plane], can be used with both VideoReader and VideoWriter. + + RGB = 5, //!< OpenCV color format, can only be used with VideoWriter. + RGBA = 6, //!< OpenCV color format, can only be used with VideoWriter. + NV_YV12 = 8, //!< Nvidia Buffer Format - Planar YUV [Y plane followed by V and U planes], use with VideoReader, can only be used with VideoWriter. + NV_IYUV = 9, //!< Nvidia Buffer Format - Planar YUV [Y plane followed by U and V planes], use with VideoReader, can only be used with VideoWriter. + NV_YUV444 = 10, //!< Nvidia Buffer Format - Planar YUV [Y plane followed by U and V planes], use with VideoReader, can only be used with VideoWriter. + NV_AYUV = 11, //!< Nvidia Buffer Format - 8 bit Packed A8Y8U8V8. This is a word-ordered format where a pixel is represented by a 32-bit word with V in the lowest 8 bits, U in the next 8 bits, Y in the 8 bits after that and A in the highest 8 bits, can only be used with VideoWriter. +#ifndef CV_DOXYGEN + PROP_NOT_SUPPORTED +#endif +}; + +/** @brief Rate Control Modes. +*/ +enum EncodeParamsRcMode { + ENC_PARAMS_RC_CONSTQP = 0x0, //!< Constant QP mode. + ENC_PARAMS_RC_VBR = 0x1, //!< Variable bitrate mode. + ENC_PARAMS_RC_CBR = 0x2 //!< Constant bitrate mode. +}; + +/** @brief Multi Pass Encoding. +*/ +enum EncodeMultiPass { - int P_Interval; //!< NVVE_P_INTERVAL, - int IDR_Period; //!< NVVE_IDR_PERIOD, - int DynamicGOP; //!< NVVE_DYNAMIC_GOP, - int RCType; //!< NVVE_RC_TYPE, - int AvgBitrate; //!< NVVE_AVG_BITRATE, - int PeakBitrate; //!< NVVE_PEAK_BITRATE, - int QP_Level_Intra; //!< NVVE_QP_LEVEL_INTRA, - int QP_Level_InterP; //!< NVVE_QP_LEVEL_INTER_P, - int QP_Level_InterB; //!< NVVE_QP_LEVEL_INTER_B, - int DeblockMode; //!< NVVE_DEBLOCK_MODE, - int ProfileLevel; //!< NVVE_PROFILE_LEVEL, - int ForceIntra; //!< NVVE_FORCE_INTRA, - int ForceIDR; //!< NVVE_FORCE_IDR, - int ClearStat; //!< NVVE_CLEAR_STAT, - int DIMode; //!< NVVE_SET_DEINTERLACE, - int Presets; //!< NVVE_PRESETS, - int DisableCabac; //!< NVVE_DISABLE_CABAC, - int NaluFramingType; //!< NVVE_CONFIGURE_NALU_FRAMING_TYPE - int DisableSPSPPS; //!< NVVE_DISABLE_SPS_PPS - - EncoderParams(); - /** @brief Constructors. - - @param configFile Config file name. - - Creates default parameters or reads parameters from config file. - */ - explicit EncoderParams(const String& configFile); + ENC_MULTI_PASS_DISABLED = 0x0, //!< Single Pass. + ENC_TWO_PASS_QUARTER_RESOLUTION = 0x1, //!< Two Pass encoding is enabled where first Pass is quarter resolution. + ENC_TWO_PASS_FULL_RESOLUTION = 0x2, //!< Two Pass encoding is enabled where first Pass is full resolution. +}; - /** @brief Reads parameters from config file. - @param configFile Config file name. - */ - void load(const String& configFile); - /** @brief Saves parameters to config file. +/** @brief Supported Encoder Profiles. +*/ +enum EncodeProfile { + ENC_CODEC_PROFILE_AUTOSELECT = 0, + ENC_H264_PROFILE_BASELINE = 1, + ENC_H264_PROFILE_MAIN = 2, + ENC_H264_PROFILE_HIGH = 3, + ENC_H264_PROFILE_HIGH_444 = 4, + ENC_H264_PROFILE_STEREO = 5, + ENC_H264_PROFILE_PROGRESSIVE_HIGH = 6, + ENC_H264_PROFILE_CONSTRAINED_HIGH = 7, + ENC_HEVC_PROFILE_MAIN = 8, + ENC_HEVC_PROFILE_MAIN10 = 9, + ENC_HEVC_PROFILE_FREXT = 10 +}; - @param configFile Config file name. - */ - void save(const String& configFile) const; +/** @brief Nvidia Encoding Presets. Performance degrades and quality improves as we move from P1 to P7. +*/ +enum EncodePreset { + ENC_PRESET_P1 = 1, + ENC_PRESET_P2 = 2, + ENC_PRESET_P3 = 3, + ENC_PRESET_P4 = 4, + ENC_PRESET_P5 = 5, + ENC_PRESET_P6 = 6, + ENC_PRESET_P7 = 7 }; -/** @brief Callbacks for CUDA video encoder. - */ -class CV_EXPORTS_W EncoderCallBack +/** @brief Tuning information. +*/ +enum EncodeTuningInfo { + ENC_TUNING_INFO_UNDEFINED = 0, //!< Undefined tuningInfo. Invalid value for encoding. + ENC_TUNING_INFO_HIGH_QUALITY = 1, //!< Tune presets for latency tolerant encoding. + ENC_TUNING_INFO_LOW_LATENCY = 2, //!< Tune presets for low latency streaming. + ENC_TUNING_INFO_ULTRA_LOW_LATENCY = 3, //!< Tune presets for ultra low latency streaming. + ENC_TUNING_INFO_LOSSLESS = 4, //!< Tune presets for lossless encoding. + ENC_TUNING_INFO_COUNT +}; + +/** Quantization Parameter for each type of frame when using ENC_PARAMS_RC_MODE::ENC_PARAMS_RC_CONSTQP. +*/ +struct CV_EXPORTS_W_SIMPLE EncodeQp { -public: - enum PicType - { - IFRAME = 1, - PFRAME = 2, - BFRAME = 3 - }; + CV_PROP_RW uint32_t qpInterP; //!< Specifies QP value for P-frame. + CV_PROP_RW uint32_t qpInterB; //!< Specifies QP value for B-frame. + CV_PROP_RW uint32_t qpIntra; //!< Specifies QP value for Intra Frame. +}; - virtual ~EncoderCallBack() {} +/** @brief Different parameters for CUDA video encoder. +*/ +struct CV_EXPORTS_W_SIMPLE EncoderParams +{ +public: + CV_WRAP EncoderParams() : nvPreset(ENC_PRESET_P3), tuningInfo(ENC_TUNING_INFO_HIGH_QUALITY), encodingProfile(ENC_CODEC_PROFILE_AUTOSELECT), + rateControlMode(ENC_PARAMS_RC_VBR), multiPassEncoding(ENC_MULTI_PASS_DISABLED), constQp({ 0,0,0 }), averageBitRate(0), maxBitRate(0), + targetQuality(30), gopLength(0) {}; + + CV_PROP_RW EncodePreset nvPreset; + CV_PROP_RW EncodeTuningInfo tuningInfo; + CV_PROP_RW EncodeProfile encodingProfile; + CV_PROP_RW EncodeParamsRcMode rateControlMode; + CV_PROP_RW EncodeMultiPass multiPassEncoding; + CV_PROP_RW EncodeQp constQp; //!< QP's for ENC_PARAMS_RC_CONSTQP. + CV_PROP_RW int averageBitRate; //!< target bitrate for ENC_PARAMS_RC_VBR and ENC_PARAMS_RC_CBR. + CV_PROP_RW int maxBitRate; //!< upper bound on bitrate for ENC_PARAMS_RC_VBR and ENC_PARAMS_RC_CONSTQP. + CV_PROP_RW uint8_t targetQuality; //!< value 0 - 51 where video quality decreases as targetQuality increases, used with ENC_PARAMS_RC_VBR. + CV_PROP_RW int gopLength; +}; +CV_EXPORTS bool operator==(const EncoderParams& lhs, const EncoderParams& rhs); - /** @brief Callback function to signal the start of bitstream that is to be encoded. +/** @brief Interface for encoder callbacks. - Callback must allocate buffer for CUDA encoder and return pointer to it and it's size. - */ - virtual uchar* acquireBitStream(int* bufferSize) = 0; +User can implement own multiplexing by implementing this interface. +*/ +class CV_EXPORTS_W EncoderCallback { +public: + /** @brief Callback function to signal that the encoded bitstream for one or more frames is ready. - /** @brief Callback function to signal that the encoded bitstream is ready to be written to file. + @param vPacket The raw bitstream for one or more frames. */ - virtual void releaseBitStream(unsigned char* data, int size) = 0; - - /** @brief Callback function to signal that the encoding operation on the frame has started. - - @param frameNumber - @param picType Specify frame type (I-Frame, P-Frame or B-Frame). - */ - CV_WRAP virtual void onBeginFrame(int frameNumber, EncoderCallBack::PicType picType) = 0; + virtual void onEncoded(std::vector> vPacket) = 0; - /** @brief Callback function signals that the encoding operation on the frame has finished. + /** @brief Callback function to that the encoding has finished. + * */ + virtual void onEncodingFinished() = 0; - @param frameNumber - @param picType Specify frame type (I-Frame, P-Frame or B-Frame). - */ - CV_WRAP virtual void onEndFrame(int frameNumber, EncoderCallBack::PicType picType) = 0; + virtual ~EncoderCallback() {} }; /** @brief Video writer interface. -The implementation uses H264 video codec. +Available when built with WITH_NVCUVENC=ON while Nvidia's Video Codec SDK is installed. -@note Currently only Windows platform is supported. +Encoding support is dependent on the GPU, refer to the Nvidia Video Codec SDK Video Encode and Decode GPU Support Matrix for details. @note - An example on how to use the videoWriter class can be found at opencv_source_code/samples/gpu/video_writer.cpp - */ +*/ class CV_EXPORTS_W VideoWriter { public: @@ -181,90 +237,51 @@ class CV_EXPORTS_W VideoWriter /** @brief Writes the next video frame. - @param frame The written frame. - @param lastFrame Indicates that it is end of stream. The parameter can be ignored. + @param frame The framet to be written. - The method write the specified image to video file. The image must have the same size and the same + The method encodes the specified image to a video stream. The image must have the same size and the same surface format as has been specified when opening the video writer. - */ - CV_WRAP virtual void write(InputArray frame, bool lastFrame = false) = 0; + */ + CV_WRAP virtual void write(InputArray frame) = 0; + /** @brief Retrieve the encoding parameters. + */ CV_WRAP virtual EncoderParams getEncoderParams() const = 0; + + /** @brief Waits until the encoding process has finished before calling EncoderCallback::onEncodingFinished(). + */ + CV_WRAP virtual void release() = 0; }; /** @brief Creates video writer. -@param fileName Name of the output video file. Only AVI file format is supported. -@param frameSize Size of the input video frames. -@param fps Framerate of the created video stream. -@param format Surface format of input frames ( SF_UYVY , SF_YUY2 , SF_YV12 , SF_NV12 , -SF_IYUV , SF_BGR or SF_GRAY). BGR or gray frames will be converted to YV12 format before -encoding, frames with other formats will be used as is. - -The constructors initialize video writer. FFMPEG is used to write videos. User can implement own -multiplexing with cudacodec::EncoderCallBack . - */ -CV_EXPORTS_W Ptr createVideoWriter(const String& fileName, Size frameSize, double fps, SurfaceFormat format = SF_BGR); -/** @overload -@param fileName Name of the output video file. Only AVI file format is supported. +@param fileName Name of the output video file. Only raw h264 or hevc files are supported. @param frameSize Size of the input video frames. +@param codec Codec. @param fps Framerate of the created video stream. -@param params Encoder parameters. See cudacodec::EncoderParams . -@param format Surface format of input frames ( SF_UYVY , SF_YUY2 , SF_YV12 , SF_NV12 , -SF_IYUV , SF_BGR or SF_GRAY). BGR or gray frames will be converted to YV12 format before -encoding, frames with other formats will be used as is. +@param colorFormat OpenCv color format of the frames to be encoded. +@param encoderCallback Callbacks for video encoder. See cudacodec::EncoderCallback. Required for working with the encoded video stream. +@param stream Stream for frame pre-processing. */ -CV_EXPORTS_W Ptr createVideoWriter(const String& fileName, Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format = SF_BGR); +CV_EXPORTS_W Ptr createVideoWriter(const String& fileName, const Size frameSize, const Codec codec = Codec::H264, const double fps = 25.0, + const ColorFormat colorFormat = ColorFormat::BGR, Ptr encoderCallback = 0, const Stream& stream = Stream::Null()); -/** @overload -@param encoderCallback Callbacks for video encoder. See cudacodec::EncoderCallBack . Use it if you -want to work with raw video stream. -@param frameSize Size of the input video frames. -@param fps Framerate of the created video stream. -@param format Surface format of input frames ( SF_UYVY , SF_YUY2 , SF_YV12 , SF_NV12 , -SF_IYUV , SF_BGR or SF_GRAY). BGR or gray frames will be converted to YV12 format before -encoding, frames with other formats will be used as is. -*/ -CV_EXPORTS_W Ptr createVideoWriter(const Ptr& encoderCallback, Size frameSize, double fps, SurfaceFormat format = SF_BGR); -/** @overload -@param encoderCallback Callbacks for video encoder. See cudacodec::EncoderCallBack . Use it if you -want to work with raw video stream. +/** @brief Creates video writer. + +@param fileName Name of the output video file. Only raw h264 or hevc files are supported. @param frameSize Size of the input video frames. +@param codec Codec. @param fps Framerate of the created video stream. -@param params Encoder parameters. See cudacodec::EncoderParams. -@param format Surface format of input frames ( SF_UYVY , SF_YUY2 , SF_YV12 , SF_NV12 , -SF_IYUV , SF_BGR or SF_GRAY). BGR or gray frames will be converted to YV12 format before -encoding, frames with other formats will be used as is. +@param colorFormat OpenCv color format of the frames to be encoded. +@param params Additional encoding parameters. +@param encoderCallback Callbacks for video encoder. See cudacodec::EncoderCallback. Required for working with the encoded video stream. +@param stream Stream for frame pre-processing. */ -CV_EXPORTS_W Ptr createVideoWriter(const Ptr& encoderCallback, Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format = SF_BGR); +CV_EXPORTS_W Ptr createVideoWriter(const String& fileName, const Size frameSize, const Codec codec, const double fps, const ColorFormat colorFormat, + const EncoderParams& params, Ptr encoderCallback = 0, const Stream& stream = Stream::Null()); ////////////////////////////////// Video Decoding ////////////////////////////////////////// -/** @brief Video codecs supported by cudacodec::VideoReader . - */ -enum Codec -{ - MPEG1 = 0, - MPEG2, - MPEG4, - VC1, - H264, - JPEG, - H264_SVC, - H264_MVC, - HEVC, - VP8, - VP9, - AV1, - NumCodecs, - - Uncompressed_YUV420 = (('I'<<24)|('Y'<<16)|('U'<<8)|('V')), //!< Y,U,V (4:2:0) - Uncompressed_YV12 = (('Y'<<24)|('V'<<16)|('1'<<8)|('2')), //!< Y,V,U (4:2:0) - Uncompressed_NV12 = (('N'<<24)|('V'<<16)|('1'<<8)|('2')), //!< Y,UV (4:2:0) - Uncompressed_YUYV = (('Y'<<24)|('U'<<16)|('Y'<<8)|('V')), //!< YUYV/YUY2 (4:2:2) - Uncompressed_UYVY = (('U'<<24)|('Y'<<16)|('V'<<8)|('Y')) //!< UYVY (4:2:2) -}; - /** @brief Chroma formats supported by cudacodec::VideoReader. */ enum ChromaFormat @@ -309,6 +326,9 @@ struct CV_EXPORTS_W_SIMPLE FormatInfo CV_PROP_RW double fps; CV_PROP_RW int ulNumDecodeSurfaces;//!< Maximum number of internal decode surfaces. CV_PROP_RW DeinterlaceMode deinterlaceMode; + CV_PROP_RW cv::Size targetSz;//!< Post-processed size of the output frame. + CV_PROP_RW cv::Rect srcRoi;//!< Region of interest decoded from video source. + CV_PROP_RW cv::Rect targetRoi;//!< Region of interest in the output frame containing the decoded frame. }; /** @brief cv::cudacodec::VideoReader generic properties identifier. @@ -328,20 +348,12 @@ enum class VideoReaderProps { #endif }; -/** @brief ColorFormat for the frame returned by nextFrame()/retrieve(). -*/ -enum class ColorFormat { - BGRA = 1, - BGR = 2, - GRAY = 3, - YUV = 4, -#ifndef CV_DOXYGEN - PROP_NOT_SUPPORTED -#endif -}; - /** @brief Video reader interface. +Available when built with WITH_NVCUVID=ON while Nvidia's Video Codec SDK is installed. + +Decoding support is dependent on the GPU, refer to the Nvidia Video Codec SDK Video Encode and Decode GPU Support Matrix for details. + @note - An example on how to use the videoReader class can be found at opencv_source_code/samples/gpu/video_reader.cpp @@ -435,8 +447,9 @@ class CV_EXPORTS_W VideoReader /** @brief Set the desired ColorFormat for the frame returned by nextFrame()/retrieve(). @param colorFormat Value of the ColorFormat. + @return `true` unless the colorFormat is not supported. */ - CV_WRAP virtual void set(const ColorFormat colorFormat) = 0; + CV_WRAP virtual bool set(const ColorFormat colorFormat) = 0; /** @brief Returns the specified VideoReader property @@ -516,6 +529,10 @@ surfaces it requires for correct functionality and optimal video memory usage bu overall application. The optimal number of decode surfaces (in terms of performance and memory utilization) should be decided by experimentation for each application, but it cannot go below the number determined by NVDEC. @param rawMode Allow the raw encoded data which has been read up until the last call to grab() to be retrieved by calling retrieve(rawData,RAW_DATA_IDX). +@param targetSz Post-processed size (width/height should be multiples of 2) of the output frame, defaults to the size of the encoded video source. +@param srcRoi Region of interest (x/width should be multiples of 4 and y/height multiples of 2) decoded from video source, defaults to the full frame. +@param targetRoi Region of interest (x/width should be multiples of 4 and y/height multiples of 2) within the output frame to copy and resize the decoded frame to, +defaults to the full frame. */ struct CV_EXPORTS_W_SIMPLE VideoReaderInitParams { CV_WRAP VideoReaderInitParams() : udpSource(false), allowFrameDrop(false), minNumDecodeSurfaces(0), rawMode(0) {}; @@ -523,6 +540,9 @@ struct CV_EXPORTS_W_SIMPLE VideoReaderInitParams { CV_PROP_RW bool allowFrameDrop; CV_PROP_RW int minNumDecodeSurfaces; CV_PROP_RW bool rawMode; + CV_PROP_RW cv::Size targetSz; + CV_PROP_RW cv::Rect srcRoi; + CV_PROP_RW cv::Rect targetRoi; }; /** @brief Creates video reader. diff --git a/modules/cudacodec/misc/python/pyopencv_cudacodec.hpp b/modules/cudacodec/misc/python/pyopencv_cudacodec.hpp deleted file mode 100644 index 15fd43de427..00000000000 --- a/modules/cudacodec/misc/python/pyopencv_cudacodec.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#ifdef HAVE_OPENCV_CUDACODEC - -#include "opencv2/cudacodec.hpp" - -typedef cudacodec::EncoderCallBack::PicType EncoderCallBack_PicType; - -CV_PY_TO_CLASS(cudacodec::EncoderParams); -CV_PY_FROM_CLASS(cudacodec::EncoderParams); - -#endif diff --git a/modules/cudacodec/misc/python/test/test_cudacodec.py b/modules/cudacodec/misc/python/test/test_cudacodec.py index dc9f7a40aae..3f41c3bbede 100644 --- a/modules/cudacodec/misc/python/test/test_cudacodec.py +++ b/modules/cudacodec/misc/python/test/test_cudacodec.py @@ -2,7 +2,7 @@ import os import cv2 as cv import numpy as np - +import tempfile from tests_common import NewOpenCVTests, unittest class cudacodec_test(NewOpenCVTests): @@ -79,12 +79,28 @@ def test_writer_existence(self): #Test at least the existence of wrapped functions for now try: - _writer = cv.cudacodec.createVideoWriter("tmp", (128, 128), 30) + fd, fname = tempfile.mkstemp(suffix=".h264") + os.close(fd) + encoder_params_in = cv.cudacodec.EncoderParams() + encoder_params_in.gopLength = 10 + stream = cv.cuda.Stream() + sz = (1920,1080) + writer = cv.cudacodec.createVideoWriter(fname, sz, cv.cudacodec.H264, 30, cv.cudacodec.ColorFormat_BGR, + encoder_params_in, stream=stream) + blankFrameIn = cv.cuda.GpuMat(sz,cv.CV_8UC3) + writer.write(blankFrameIn) + writer.release() + encoder_params_out = writer.getEncoderParams() + self.assert_true(encoder_params_in.gopLength == encoder_params_out.gopLength) + cap = cv.VideoCapture(fname,cv.CAP_FFMPEG) + self.assert_true(cap.isOpened()) + ret, blankFrameOut = cap.read() + self.assert_true(ret and blankFrameOut.shape == blankFrameIn.download().shape) except cv.error as e: self.assertEqual(e.code, cv.Error.StsNotImplemented) - self.skipTest("NVCUVENC is not installed") + self.skipTest("Either NVCUVENC or a GPU hardware encoder is missing or the encoding profile is not supported.") - self.assertTrue(True) #It is sufficient that no exceptions have been there + os.remove(fname) if __name__ == '__main__': NewOpenCVTests.bootstrap() \ No newline at end of file diff --git a/modules/cudacodec/perf/perf_video.cpp b/modules/cudacodec/perf/perf_video.cpp index af7b2f67c90..bb4e9a4a775 100644 --- a/modules/cudacodec/perf/perf_video.cpp +++ b/modules/cudacodec/perf/perf_video.cpp @@ -45,7 +45,7 @@ namespace opencv_test { namespace { -#if defined(HAVE_NVCUVID) +#if defined(HAVE_NVCUVID) || defined(HAVE_NVCUVENC) #if defined(HAVE_FFMPEG_WRAPPER) // should this be set in preprocessor or in cvconfig.h #define VIDEO_SRC Values("cv/video/768x576.avi", "cv/video/1920x1080.avi") @@ -54,6 +54,8 @@ namespace opencv_test { namespace { #define VIDEO_SRC Values( "cv/video/1920x1080.avi") #endif +#if defined(HAVE_NVCUVID) + DEF_PARAM_TEST_1(FileName, string); ////////////////////////////////////////////////////// @@ -93,63 +95,97 @@ PERF_TEST_P(FileName, VideoReader, VIDEO_SRC) ////////////////////////////////////////////////////// // VideoWriter -#if defined(HAVE_NVCUVID) && defined(_WIN32) +#if defined(HAVE_NVCUVENC) -PERF_TEST_P(FileName, VideoWriter, VIDEO_SRC) -{ - declare.time(30); - - const string inputFile = perf::TestBase::getDataPath(GetParam()); - const string outputFile = cv::tempfile(".avi"); +DEF_PARAM_TEST(WriteToFile, string, cv::cudacodec::ColorFormat, cv::cudacodec::Codec); - const double FPS = 25.0; +#define COLOR_FORMAT Values(cv::cudacodec::ColorFormat::BGR, cv::cudacodec::ColorFormat::RGB, cv::cudacodec::ColorFormat::BGRA, \ +cv::cudacodec::ColorFormat::RGBA, cv::cudacodec::ColorFormat::GRAY) +#define CODEC Values(cv::cudacodec::Codec::H264, cv::cudacodec::Codec::HEVC) +PERF_TEST_P(WriteToFile, VideoWriter, Combine(VIDEO_SRC, COLOR_FORMAT, CODEC)) +{ + declare.time(30); + const string inputFile = perf::TestBase::getDataPath(GET_PARAM(0)); + const cv::cudacodec::ColorFormat surfaceFormat = GET_PARAM(1); + const cudacodec::Codec codec = GET_PARAM(2); + const double fps = 25; + const int nFrames = 20; cv::VideoCapture reader(inputFile); - ASSERT_TRUE( reader.isOpened() ); - - cv::Mat frame; - - if (PERF_RUN_CUDA()) - { - cv::Ptr d_writer; - - cv::cuda::GpuMat d_frame; - - for (int i = 0; i < 10; ++i) - { - reader >> frame; - ASSERT_FALSE(frame.empty()); - - d_frame.upload(frame); - - if (d_writer.empty()) - d_writer = cv::cudacodec::createVideoWriter(outputFile, frame.size(), FPS); - - startTimer(); next(); - d_writer->write(d_frame); + ASSERT_TRUE(reader.isOpened()); + Mat frameBgr; + if (PERF_RUN_CUDA()) { + const std::string ext = codec == cudacodec::Codec::H264 ? ".h264" : ".hevc"; + const string outputFile = cv::tempfile(ext.c_str()); + std::vector frames; + cv::Mat frameNewSf; + cuda::Stream stream; + ColorConversionCodes conversionCode = COLOR_COLORCVT_MAX; + switch (surfaceFormat) { + case cudacodec::ColorFormat::RGB: + conversionCode = COLOR_BGR2RGB; + break; + case cudacodec::ColorFormat::BGRA: + conversionCode = COLOR_BGR2BGRA; + break; + case cudacodec::ColorFormat::RGBA: + conversionCode = COLOR_BGR2RGBA; + break; + case cudacodec::ColorFormat::GRAY: + conversionCode = COLOR_BGR2GRAY; + default: + break; + } + for (int i = 0; i < nFrames; i++) { + reader >> frameBgr; + ASSERT_FALSE(frameBgr.empty()); + if (conversionCode == COLOR_COLORCVT_MAX) + frameNewSf = frameBgr; + else + cv::cvtColor(frameBgr, frameNewSf, conversionCode); + GpuMat frame; frame.upload(frameNewSf, stream); + frames.push_back(frame); + } + stream.waitForCompletion(); + cv::Ptr d_writer = cv::cudacodec::createVideoWriter(outputFile, frameBgr.size(), codec, fps, surfaceFormat, 0, stream); + for (int i = 0; i < nFrames - 1; ++i) { + startTimer(); + d_writer->write(frames[i]); stopTimer(); } + startTimer(); + d_writer->write(frames[nFrames - 1]); + d_writer->release(); + stopTimer(); + + ASSERT_EQ(0, remove(outputFile.c_str())); } - else - { + else { + if (surfaceFormat != cv::cudacodec::ColorFormat::BGR || codec != cv::cudacodec::Codec::H264) + throw PerfSkipTestException(); cv::VideoWriter writer; - - for (int i = 0; i < 10; ++i) - { - reader >> frame; - ASSERT_FALSE(frame.empty()); - + const string outputFile = cv::tempfile(".avi"); + for (int i = 0; i < nFrames-1; ++i) { + reader >> frameBgr; + ASSERT_FALSE(frameBgr.empty()); if (!writer.isOpened()) - writer.open(outputFile, VideoWriter::fourcc('X', 'V', 'I', 'D'), FPS, frame.size()); - - startTimer(); next(); - writer.write(frame); + writer.open(outputFile, VideoWriter::fourcc('X', 'V', 'I', 'D'), fps, frameBgr.size()); + startTimer(); + writer.write(frameBgr); stopTimer(); } + reader >> frameBgr; + ASSERT_FALSE(frameBgr.empty()); + startTimer(); + writer.write(frameBgr); + writer.release(); + stopTimer(); + + ASSERT_EQ(0, remove(outputFile.c_str())); } - - SANITY_CHECK(frame); + SANITY_CHECK(frameBgr); } +#endif #endif }} // namespace diff --git a/modules/cudacodec/src/NvEncoder.cpp b/modules/cudacodec/src/NvEncoder.cpp new file mode 100644 index 00000000000..249f6f1c61e --- /dev/null +++ b/modules/cudacodec/src/NvEncoder.cpp @@ -0,0 +1,785 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +#include "precomp.hpp" + +#if defined(HAVE_NVCUVENC) +#include "NvEncoder.h" + +namespace cv { namespace cudacodec { +#ifndef _WIN32 +#include +static inline bool operator==(const GUID& guid1, const GUID& guid2) { + return !memcmp(&guid1, &guid2, sizeof(GUID)); +} + +static inline bool operator!=(const GUID& guid1, const GUID& guid2) { + return !(guid1 == guid2); +} +#endif + +NvEncoder::NvEncoder(NV_ENC_DEVICE_TYPE eDeviceType, void* pDevice, uint32_t nWidth, uint32_t nHeight, NV_ENC_BUFFER_FORMAT eBufferFormat, + uint32_t nExtraOutputDelay) : + m_hEncoder(nullptr), + m_pDevice(pDevice), + m_eDeviceType(eDeviceType), + m_nWidth(nWidth), + m_nHeight(nHeight), + m_nMaxEncodeWidth(nWidth), + m_nMaxEncodeHeight(nHeight), + m_eBufferFormat(eBufferFormat), + m_nExtraOutputDelay(nExtraOutputDelay) +{ + LoadNvEncApi(); + + if (!m_nvenc.nvEncOpenEncodeSession) + { + m_nEncoderBuffer = 0; + NVENC_THROW_ERROR("EncodeAPI not found", NV_ENC_ERR_NO_ENCODE_DEVICE); + } + + NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS encodeSessionExParams = {}; + encodeSessionExParams.version = NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER; + encodeSessionExParams.device = m_pDevice; + encodeSessionExParams.deviceType = m_eDeviceType; + encodeSessionExParams.apiVersion = NVENCAPI_VERSION; + void* hEncoder = NULL; + NVENC_API_CALL(m_nvenc.nvEncOpenEncodeSessionEx(&encodeSessionExParams, &hEncoder)); + m_hEncoder = hEncoder; +} + +void NvEncoder::LoadNvEncApi() +{ + + uint32_t version = 0; + uint32_t currentVersion = (NVENCAPI_MAJOR_VERSION << 4) | NVENCAPI_MINOR_VERSION; + NVENC_API_CALL(NvEncodeAPIGetMaxSupportedVersion(&version)); + if (currentVersion > version) + { + NVENC_THROW_ERROR("Current Driver Version does not support this NvEncodeAPI version, please upgrade driver", NV_ENC_ERR_INVALID_VERSION); + } + + m_nvenc = {}; + m_nvenc.version = NV_ENCODE_API_FUNCTION_LIST_VER; + NVENC_API_CALL(NvEncodeAPICreateInstance(&m_nvenc)); +} + +NvEncoder::~NvEncoder() +{ + DestroyHWEncoder(); +} + +void NvEncoder::CreateDefaultEncoderParams(NV_ENC_INITIALIZE_PARAMS* pIntializeParams, GUID codecGuid, GUID presetGuid, NV_ENC_TUNING_INFO tuningInfo) +{ + if (!m_hEncoder) + { + NVENC_THROW_ERROR("Encoder Initialization failed", NV_ENC_ERR_NO_ENCODE_DEVICE); + return; + } + + if (pIntializeParams == nullptr || pIntializeParams->encodeConfig == nullptr) + { + NVENC_THROW_ERROR("pInitializeParams and pInitializeParams->encodeConfig can't be NULL", NV_ENC_ERR_INVALID_PTR); + } + + memset(pIntializeParams->encodeConfig, 0, sizeof(NV_ENC_CONFIG)); + auto pEncodeConfig = pIntializeParams->encodeConfig; + memset(pIntializeParams, 0, sizeof(NV_ENC_INITIALIZE_PARAMS)); + pIntializeParams->encodeConfig = pEncodeConfig; + + + pIntializeParams->encodeConfig->version = NV_ENC_CONFIG_VER; + pIntializeParams->version = NV_ENC_INITIALIZE_PARAMS_VER; + + pIntializeParams->encodeGUID = codecGuid; + pIntializeParams->presetGUID = presetGuid; + pIntializeParams->encodeWidth = m_nWidth; + pIntializeParams->encodeHeight = m_nHeight; + pIntializeParams->darWidth = m_nWidth; + pIntializeParams->darHeight = m_nHeight; + pIntializeParams->frameRateNum = 30; + pIntializeParams->frameRateDen = 1; + pIntializeParams->enablePTD = 1; + pIntializeParams->reportSliceOffsets = 0; + pIntializeParams->enableSubFrameWrite = 0; + pIntializeParams->maxEncodeWidth = m_nWidth; + pIntializeParams->maxEncodeHeight = m_nHeight; + pIntializeParams->enableMEOnlyMode = false; + pIntializeParams->enableOutputInVidmem = false; +#if defined(_WIN32) + pIntializeParams->enableEncodeAsync = GetCapabilityValue(codecGuid, NV_ENC_CAPS_ASYNC_ENCODE_SUPPORT); +#endif + pIntializeParams->tuningInfo = tuningInfo; + NV_ENC_PRESET_CONFIG presetConfig = {}; + presetConfig.version = NV_ENC_PRESET_CONFIG_VER; + presetConfig.presetCfg.version = NV_ENC_CONFIG_VER; + m_nvenc.nvEncGetEncodePresetConfigEx(m_hEncoder, codecGuid, presetGuid, tuningInfo, &presetConfig); + memcpy(pIntializeParams->encodeConfig, &presetConfig.presetCfg, sizeof(NV_ENC_CONFIG)); + + if (pIntializeParams->encodeGUID == NV_ENC_CODEC_H264_GUID) + { + if (m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444 || m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444_10BIT) + { + pIntializeParams->encodeConfig->encodeCodecConfig.h264Config.chromaFormatIDC = 3; + } + pIntializeParams->encodeConfig->encodeCodecConfig.h264Config.idrPeriod = pIntializeParams->encodeConfig->gopLength; + } + else if (pIntializeParams->encodeGUID == NV_ENC_CODEC_HEVC_GUID) + { + pIntializeParams->encodeConfig->encodeCodecConfig.hevcConfig.pixelBitDepthMinus8 = + (m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV420_10BIT || m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444_10BIT) ? 2 : 0; + if (m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444 || m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444_10BIT) + { + pIntializeParams->encodeConfig->encodeCodecConfig.hevcConfig.chromaFormatIDC = 3; + } + pIntializeParams->encodeConfig->encodeCodecConfig.hevcConfig.idrPeriod = pIntializeParams->encodeConfig->gopLength; + } + + return; +} + +void NvEncoder::CreateEncoder(const NV_ENC_INITIALIZE_PARAMS* pEncoderParams) +{ + if (!m_hEncoder) + { + NVENC_THROW_ERROR("Encoder Initialization failed", NV_ENC_ERR_NO_ENCODE_DEVICE); + } + + if (!pEncoderParams) + { + NVENC_THROW_ERROR("Invalid NV_ENC_INITIALIZE_PARAMS ptr", NV_ENC_ERR_INVALID_PTR); + } + + if (pEncoderParams->encodeWidth == 0 || pEncoderParams->encodeHeight == 0) + { + NVENC_THROW_ERROR("Invalid encoder width and height", NV_ENC_ERR_INVALID_PARAM); + } + + if (pEncoderParams->encodeGUID != NV_ENC_CODEC_H264_GUID && pEncoderParams->encodeGUID != NV_ENC_CODEC_HEVC_GUID) + { + NVENC_THROW_ERROR("Invalid codec guid", NV_ENC_ERR_INVALID_PARAM); + } + + if (pEncoderParams->encodeGUID == NV_ENC_CODEC_H264_GUID) + { + if (m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV420_10BIT || m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444_10BIT) + { + NVENC_THROW_ERROR("10-bit format isn't supported by H264 encoder", NV_ENC_ERR_INVALID_PARAM); + } + } + + // set other necessary params if not set yet + if (pEncoderParams->encodeGUID == NV_ENC_CODEC_H264_GUID) + { + if ((m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444) && + (pEncoderParams->encodeConfig->encodeCodecConfig.h264Config.chromaFormatIDC != 3)) + { + NVENC_THROW_ERROR("Invalid ChromaFormatIDC", NV_ENC_ERR_INVALID_PARAM); + } + } + + if (pEncoderParams->encodeGUID == NV_ENC_CODEC_HEVC_GUID) + { + bool yuv10BitFormat = (m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV420_10BIT || m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444_10BIT) ? true : false; + if (yuv10BitFormat && pEncoderParams->encodeConfig->encodeCodecConfig.hevcConfig.pixelBitDepthMinus8 != 2) + { + NVENC_THROW_ERROR("Invalid PixelBitdepth", NV_ENC_ERR_INVALID_PARAM); + } + + if ((m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444 || m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444_10BIT) && + (pEncoderParams->encodeConfig->encodeCodecConfig.hevcConfig.chromaFormatIDC != 3)) + { + NVENC_THROW_ERROR("Invalid ChromaFormatIDC", NV_ENC_ERR_INVALID_PARAM); + } + } + + memcpy(&m_initializeParams, pEncoderParams, sizeof(m_initializeParams)); + m_initializeParams.version = NV_ENC_INITIALIZE_PARAMS_VER; + + if (pEncoderParams->encodeConfig) + { + memcpy(&m_encodeConfig, pEncoderParams->encodeConfig, sizeof(m_encodeConfig)); + m_encodeConfig.version = NV_ENC_CONFIG_VER; + } + else + { + NV_ENC_PRESET_CONFIG presetConfig = {}; + presetConfig.version = NV_ENC_PRESET_CONFIG_VER; + presetConfig.presetCfg.version = NV_ENC_CONFIG_VER; + m_nvenc.nvEncGetEncodePresetConfigEx(m_hEncoder, pEncoderParams->encodeGUID, pEncoderParams->presetGUID, pEncoderParams->tuningInfo, &presetConfig); + memcpy(&m_encodeConfig, &presetConfig.presetCfg, sizeof(NV_ENC_CONFIG)); + } + m_initializeParams.encodeConfig = &m_encodeConfig; + NVENC_API_CALL(m_nvenc.nvEncInitializeEncoder(m_hEncoder, &m_initializeParams)); + m_bEncoderInitialized = true; + m_nWidth = m_initializeParams.encodeWidth; + m_nHeight = m_initializeParams.encodeHeight; + m_nMaxEncodeWidth = m_initializeParams.maxEncodeWidth; + m_nMaxEncodeHeight = m_initializeParams.maxEncodeHeight; + + m_nEncoderBuffer = m_encodeConfig.frameIntervalP + m_encodeConfig.rcParams.lookaheadDepth + m_nExtraOutputDelay; + m_nOutputDelay = m_nEncoderBuffer - 1; + + m_vpCompletionEvent.resize(m_nEncoderBuffer, nullptr); + +#if defined(_WIN32) + for (uint32_t i = 0; i < m_vpCompletionEvent.size(); i++) + { + m_vpCompletionEvent[i] = CreateEvent(NULL, FALSE, FALSE, NULL); + NV_ENC_EVENT_PARAMS eventParams = { NV_ENC_EVENT_PARAMS_VER }; + eventParams.completionEvent = m_vpCompletionEvent[i]; + m_nvenc.nvEncRegisterAsyncEvent(m_hEncoder, &eventParams); + } +#endif + + m_vMappedInputBuffers.resize(m_nEncoderBuffer, nullptr); + m_vBitstreamOutputBuffer.resize(m_nEncoderBuffer, nullptr); + InitializeBitstreamBuffer(); + AllocateInputBuffers(m_nEncoderBuffer); +} + +void NvEncoder::DestroyEncoder() +{ + if (!m_hEncoder) + { + return; + } + + ReleaseInputBuffers(); + + DestroyHWEncoder(); +} + +void NvEncoder::DestroyHWEncoder() +{ + if (!m_hEncoder) + { + return; + } + +#if defined(_WIN32) + for (uint32_t i = 0; i < m_vpCompletionEvent.size(); i++) + { + if (m_vpCompletionEvent[i]) + { + NV_ENC_EVENT_PARAMS eventParams = { NV_ENC_EVENT_PARAMS_VER }; + eventParams.completionEvent = m_vpCompletionEvent[i]; + m_nvenc.nvEncUnregisterAsyncEvent(m_hEncoder, &eventParams); + CloseHandle(m_vpCompletionEvent[i]); + } + } + m_vpCompletionEvent.clear(); +#endif + + DestroyBitstreamBuffer(); + + m_nvenc.nvEncDestroyEncoder(m_hEncoder); + + m_hEncoder = nullptr; + + m_bEncoderInitialized = false; +} + +const NvEncInputFrame* NvEncoder::GetNextInputFrame() +{ + int i = m_iToSend % m_nEncoderBuffer; + return &m_vInputFrames[i]; +} + +void NvEncoder::MapResources(uint32_t bfrIdx) +{ + NV_ENC_MAP_INPUT_RESOURCE mapInputResource = {}; + mapInputResource.version = NV_ENC_MAP_INPUT_RESOURCE_VER; + mapInputResource.registeredResource = m_vRegisteredResources[bfrIdx]; + NVENC_API_CALL(m_nvenc.nvEncMapInputResource(m_hEncoder, &mapInputResource)); + m_vMappedInputBuffers[bfrIdx] = mapInputResource.mappedResource; +} + +void NvEncoder::EncodeFrame(std::vector>& vPacket, NV_ENC_PIC_PARAMS* pPicParams) +{ + vPacket.clear(); + if (!IsHWEncoderInitialized()) + { + NVENC_THROW_ERROR("Encoder device not found", NV_ENC_ERR_NO_ENCODE_DEVICE); + } + + int bfrIdx = m_iToSend % m_nEncoderBuffer; + + MapResources(bfrIdx); + + NVENCSTATUS nvStatus = DoEncode(m_vMappedInputBuffers[bfrIdx], m_vBitstreamOutputBuffer[bfrIdx], pPicParams); + + if (nvStatus == NV_ENC_SUCCESS || nvStatus == NV_ENC_ERR_NEED_MORE_INPUT) + { + m_iToSend++; + GetEncodedPacket(m_vBitstreamOutputBuffer, vPacket, true); + } + else + { + NVENC_THROW_ERROR("nvEncEncodePicture API failed", nvStatus); + } +} + +void NvEncoder::GetSequenceParams(std::vector& seqParams) +{ + uint8_t spsppsData[1024]; // Assume maximum spspps data is 1KB or less + memset(spsppsData, 0, sizeof(spsppsData)); + NV_ENC_SEQUENCE_PARAM_PAYLOAD payload = {}; + payload.version = NV_ENC_SEQUENCE_PARAM_PAYLOAD_VER; + uint32_t spsppsSize = 0; + + payload.spsppsBuffer = spsppsData; + payload.inBufferSize = sizeof(spsppsData); + payload.outSPSPPSPayloadSize = &spsppsSize; + NVENC_API_CALL(m_nvenc.nvEncGetSequenceParams(m_hEncoder, &payload)); + seqParams.clear(); + seqParams.insert(seqParams.end(), &spsppsData[0], &spsppsData[spsppsSize]); +} + +NVENCSTATUS NvEncoder::DoEncode(NV_ENC_INPUT_PTR inputBuffer, NV_ENC_OUTPUT_PTR outputBuffer, NV_ENC_PIC_PARAMS* pPicParams) +{ + NV_ENC_PIC_PARAMS picParams = {}; + if (pPicParams) + { + picParams = *pPicParams; + } + picParams.version = NV_ENC_PIC_PARAMS_VER; + picParams.pictureStruct = NV_ENC_PIC_STRUCT_FRAME; + picParams.inputBuffer = inputBuffer; + picParams.bufferFmt = GetPixelFormat(); + picParams.inputWidth = GetEncodeWidth(); + picParams.inputHeight = GetEncodeHeight(); + picParams.outputBitstream = outputBuffer; + picParams.completionEvent = GetCompletionEvent(m_iToSend % m_nEncoderBuffer); + NVENCSTATUS nvStatus = m_nvenc.nvEncEncodePicture(m_hEncoder, &picParams); + + return nvStatus; +} + +void NvEncoder::SendEOS() +{ + NV_ENC_PIC_PARAMS picParams = {}; + picParams.version = NV_ENC_PIC_PARAMS_VER; + + picParams.encodePicFlags = NV_ENC_PIC_FLAG_EOS; + picParams.completionEvent = GetCompletionEvent(m_iToSend % m_nEncoderBuffer); + NVENC_API_CALL(m_nvenc.nvEncEncodePicture(m_hEncoder, &picParams)); +} + +void NvEncoder::EndEncode(std::vector>& vPacket) +{ + vPacket.clear(); + if (!IsHWEncoderInitialized()) + { + NVENC_THROW_ERROR("Encoder device not initialized", NV_ENC_ERR_ENCODER_NOT_INITIALIZED); + } + + SendEOS(); + + GetEncodedPacket(m_vBitstreamOutputBuffer, vPacket, false); +} + +void NvEncoder::GetEncodedPacket(std::vector& vOutputBuffer, std::vector>& vPacket, bool bOutputDelay) +{ + unsigned i = 0; + int iEnd = bOutputDelay ? m_iToSend - m_nOutputDelay : m_iToSend; + for (; m_iGot < iEnd; m_iGot++) + { + WaitForCompletionEvent(m_iGot % m_nEncoderBuffer); + NV_ENC_LOCK_BITSTREAM lockBitstreamData = {}; + lockBitstreamData.version = NV_ENC_LOCK_BITSTREAM_VER; + lockBitstreamData.outputBitstream = vOutputBuffer[m_iGot % m_nEncoderBuffer]; + lockBitstreamData.doNotWait = false; + NVENC_API_CALL(m_nvenc.nvEncLockBitstream(m_hEncoder, &lockBitstreamData)); + + uint8_t* pData = (uint8_t*)lockBitstreamData.bitstreamBufferPtr; + if (vPacket.size() < i + 1) + { + vPacket.push_back(std::vector()); + } + vPacket[i].clear(); + vPacket[i].insert(vPacket[i].end(), &pData[0], &pData[lockBitstreamData.bitstreamSizeInBytes]); + i++; + + NVENC_API_CALL(m_nvenc.nvEncUnlockBitstream(m_hEncoder, lockBitstreamData.outputBitstream)); + + if (m_vMappedInputBuffers[m_iGot % m_nEncoderBuffer]) + { + NVENC_API_CALL(m_nvenc.nvEncUnmapInputResource(m_hEncoder, m_vMappedInputBuffers[m_iGot % m_nEncoderBuffer])); + m_vMappedInputBuffers[m_iGot % m_nEncoderBuffer] = nullptr; + } + } +} + +bool NvEncoder::Reconfigure(const NV_ENC_RECONFIGURE_PARAMS* pReconfigureParams) +{ + NVENC_API_CALL(m_nvenc.nvEncReconfigureEncoder(m_hEncoder, const_cast(pReconfigureParams))); + + memcpy(&m_initializeParams, &(pReconfigureParams->reInitEncodeParams), sizeof(m_initializeParams)); + if (pReconfigureParams->reInitEncodeParams.encodeConfig) + { + memcpy(&m_encodeConfig, pReconfigureParams->reInitEncodeParams.encodeConfig, sizeof(m_encodeConfig)); + } + + m_nWidth = m_initializeParams.encodeWidth; + m_nHeight = m_initializeParams.encodeHeight; + m_nMaxEncodeWidth = m_initializeParams.maxEncodeWidth; + m_nMaxEncodeHeight = m_initializeParams.maxEncodeHeight; + + return true; +} + +NV_ENC_REGISTERED_PTR NvEncoder::RegisterResource(void* pBuffer, NV_ENC_INPUT_RESOURCE_TYPE eResourceType, + int width, int height, int pitch, NV_ENC_BUFFER_FORMAT bufferFormat, NV_ENC_BUFFER_USAGE bufferUsage, + NV_ENC_FENCE_POINT_D3D12* pInputFencePoint) +{ + NV_ENC_REGISTER_RESOURCE registerResource = {}; + registerResource.version = NV_ENC_REGISTER_RESOURCE_VER; + registerResource.resourceType = eResourceType; + registerResource.resourceToRegister = pBuffer; + registerResource.width = width; + registerResource.height = height; + registerResource.pitch = pitch; + registerResource.bufferFormat = bufferFormat; + registerResource.bufferUsage = bufferUsage; + registerResource.pInputFencePoint = pInputFencePoint; + NVENC_API_CALL(m_nvenc.nvEncRegisterResource(m_hEncoder, ®isterResource)); + + return registerResource.registeredResource; +} + +void NvEncoder::RegisterInputResources(std::vector inputframes, NV_ENC_INPUT_RESOURCE_TYPE eResourceType, + int width, int height, int pitch, NV_ENC_BUFFER_FORMAT bufferFormat, bool bReferenceFrame) +{ + for (uint32_t i = 0; i < inputframes.size(); ++i) + { + NV_ENC_REGISTERED_PTR registeredPtr = RegisterResource(inputframes[i], eResourceType, width, height, pitch, bufferFormat, NV_ENC_INPUT_IMAGE); + + std::vector _chromaOffsets; + NvEncoder::GetChromaSubPlaneOffsets(bufferFormat, pitch, height, _chromaOffsets); + NvEncInputFrame inputframe = {}; + inputframe.inputPtr = (void*)inputframes[i]; + inputframe.chromaOffsets[0] = 0; + inputframe.chromaOffsets[1] = 0; + for (uint32_t ch = 0; ch < _chromaOffsets.size(); ch++) + { + inputframe.chromaOffsets[ch] = _chromaOffsets[ch]; + } + inputframe.numChromaPlanes = NvEncoder::GetNumChromaPlanes(bufferFormat); + inputframe.pitch = pitch; + inputframe.chromaPitch = NvEncoder::GetChromaPitch(bufferFormat, pitch); + inputframe.bufferFormat = bufferFormat; + inputframe.resourceType = eResourceType; + + if (bReferenceFrame) + { + m_vRegisteredResourcesForReference.push_back(registeredPtr); + m_vReferenceFrames.push_back(inputframe); + } + else + { + m_vRegisteredResources.push_back(registeredPtr); + m_vInputFrames.push_back(inputframe); + } + } +} + +void NvEncoder::FlushEncoder() +{ + try + { + std::vector> vPacket; + EndEncode(vPacket); + } + catch (...) + { + + } +} + +void NvEncoder::UnregisterInputResources() +{ + FlushEncoder(); + + m_vMappedRefBuffers.clear(); + + for (uint32_t i = 0; i < m_vMappedInputBuffers.size(); ++i) + { + if (m_vMappedInputBuffers[i]) + { + m_nvenc.nvEncUnmapInputResource(m_hEncoder, m_vMappedInputBuffers[i]); + } + } + m_vMappedInputBuffers.clear(); + + for (uint32_t i = 0; i < m_vRegisteredResources.size(); ++i) + { + if (m_vRegisteredResources[i]) + { + m_nvenc.nvEncUnregisterResource(m_hEncoder, m_vRegisteredResources[i]); + } + } + m_vRegisteredResources.clear(); + + + for (uint32_t i = 0; i < m_vRegisteredResourcesForReference.size(); ++i) + { + if (m_vRegisteredResourcesForReference[i]) + { + m_nvenc.nvEncUnregisterResource(m_hEncoder, m_vRegisteredResourcesForReference[i]); + } + } + m_vRegisteredResourcesForReference.clear(); + +} + + +void NvEncoder::WaitForCompletionEvent(int iEvent) +{ +#if defined(_WIN32) + // Check if we are in async mode. If not, don't wait for event; + NV_ENC_CONFIG sEncodeConfig = { 0 }; + NV_ENC_INITIALIZE_PARAMS sInitializeParams = { 0 }; + sInitializeParams.encodeConfig = &sEncodeConfig; + GetInitializeParams(&sInitializeParams); + + if (0U == sInitializeParams.enableEncodeAsync) + { + return; + } +#ifdef DEBUG + WaitForSingleObject(m_vpCompletionEvent[iEvent], INFINITE); +#else + // wait for 20s which is infinite on terms of gpu time + if (WaitForSingleObject(m_vpCompletionEvent[iEvent], 20000) == WAIT_FAILED) + { + NVENC_THROW_ERROR("Failed to encode frame", NV_ENC_ERR_GENERIC); + } +#endif +#endif +} + +uint32_t NvEncoder::GetWidthInBytes(const NV_ENC_BUFFER_FORMAT bufferFormat, const uint32_t width) +{ + switch (bufferFormat) { + case NV_ENC_BUFFER_FORMAT_NV12: + case NV_ENC_BUFFER_FORMAT_YV12: + case NV_ENC_BUFFER_FORMAT_IYUV: + case NV_ENC_BUFFER_FORMAT_YUV444: + return width; + case NV_ENC_BUFFER_FORMAT_YUV420_10BIT: + case NV_ENC_BUFFER_FORMAT_YUV444_10BIT: + return width * 2; + case NV_ENC_BUFFER_FORMAT_ARGB: + case NV_ENC_BUFFER_FORMAT_ARGB10: + case NV_ENC_BUFFER_FORMAT_AYUV: + case NV_ENC_BUFFER_FORMAT_ABGR: + case NV_ENC_BUFFER_FORMAT_ABGR10: + return width * 4; + default: + NVENC_THROW_ERROR("Invalid Buffer format", NV_ENC_ERR_INVALID_PARAM); + } +} + +uint32_t NvEncoder::GetNumChromaPlanes(const NV_ENC_BUFFER_FORMAT bufferFormat) +{ + switch (bufferFormat) + { + case NV_ENC_BUFFER_FORMAT_NV12: + case NV_ENC_BUFFER_FORMAT_YUV420_10BIT: + return 1; + case NV_ENC_BUFFER_FORMAT_YV12: + case NV_ENC_BUFFER_FORMAT_IYUV: + case NV_ENC_BUFFER_FORMAT_YUV444: + case NV_ENC_BUFFER_FORMAT_YUV444_10BIT: + return 2; + case NV_ENC_BUFFER_FORMAT_ARGB: + case NV_ENC_BUFFER_FORMAT_ARGB10: + case NV_ENC_BUFFER_FORMAT_AYUV: + case NV_ENC_BUFFER_FORMAT_ABGR: + case NV_ENC_BUFFER_FORMAT_ABGR10: + return 0; + default: + NVENC_THROW_ERROR("Invalid Buffer format", NV_ENC_ERR_INVALID_PARAM); + } +} + +uint32_t NvEncoder::GetChromaPitch(const NV_ENC_BUFFER_FORMAT bufferFormat, const uint32_t lumaPitch) +{ + switch (bufferFormat) + { + case NV_ENC_BUFFER_FORMAT_NV12: + case NV_ENC_BUFFER_FORMAT_YUV420_10BIT: + case NV_ENC_BUFFER_FORMAT_YUV444: + case NV_ENC_BUFFER_FORMAT_YUV444_10BIT: + return lumaPitch; + case NV_ENC_BUFFER_FORMAT_YV12: + case NV_ENC_BUFFER_FORMAT_IYUV: + return (lumaPitch + 1) / 2; + case NV_ENC_BUFFER_FORMAT_ARGB: + case NV_ENC_BUFFER_FORMAT_ARGB10: + case NV_ENC_BUFFER_FORMAT_AYUV: + case NV_ENC_BUFFER_FORMAT_ABGR: + case NV_ENC_BUFFER_FORMAT_ABGR10: + return 0; + default: + NVENC_THROW_ERROR("Invalid Buffer format", NV_ENC_ERR_INVALID_PARAM); + } +} + +void NvEncoder::GetChromaSubPlaneOffsets(const NV_ENC_BUFFER_FORMAT bufferFormat, const uint32_t pitch, const uint32_t height, std::vector& chromaOffsets) +{ + chromaOffsets.clear(); + switch (bufferFormat) + { + case NV_ENC_BUFFER_FORMAT_NV12: + case NV_ENC_BUFFER_FORMAT_YUV420_10BIT: + chromaOffsets.push_back(pitch * height); + return; + case NV_ENC_BUFFER_FORMAT_YV12: + case NV_ENC_BUFFER_FORMAT_IYUV: + chromaOffsets.push_back(pitch * height); + chromaOffsets.push_back(chromaOffsets[0] + (NvEncoder::GetChromaPitch(bufferFormat, pitch) * GetChromaHeight(bufferFormat, height))); + return; + case NV_ENC_BUFFER_FORMAT_YUV444: + case NV_ENC_BUFFER_FORMAT_YUV444_10BIT: + chromaOffsets.push_back(pitch * height); + chromaOffsets.push_back(chromaOffsets[0] + (pitch * height)); + return; + case NV_ENC_BUFFER_FORMAT_ARGB: + case NV_ENC_BUFFER_FORMAT_ARGB10: + case NV_ENC_BUFFER_FORMAT_AYUV: + case NV_ENC_BUFFER_FORMAT_ABGR: + case NV_ENC_BUFFER_FORMAT_ABGR10: + return; + default: + NVENC_THROW_ERROR("Invalid Buffer format", NV_ENC_ERR_INVALID_PARAM); + } +} + +uint32_t NvEncoder::GetChromaHeight(const NV_ENC_BUFFER_FORMAT bufferFormat, const uint32_t lumaHeight) +{ + switch (bufferFormat) + { + case NV_ENC_BUFFER_FORMAT_YV12: + case NV_ENC_BUFFER_FORMAT_IYUV: + case NV_ENC_BUFFER_FORMAT_NV12: + case NV_ENC_BUFFER_FORMAT_YUV420_10BIT: + return (lumaHeight + 1) / 2; + case NV_ENC_BUFFER_FORMAT_YUV444: + case NV_ENC_BUFFER_FORMAT_YUV444_10BIT: + return lumaHeight; + case NV_ENC_BUFFER_FORMAT_ARGB: + case NV_ENC_BUFFER_FORMAT_ARGB10: + case NV_ENC_BUFFER_FORMAT_AYUV: + case NV_ENC_BUFFER_FORMAT_ABGR: + case NV_ENC_BUFFER_FORMAT_ABGR10: + return 0; + default: + NVENC_THROW_ERROR("Invalid Buffer format", NV_ENC_ERR_INVALID_PARAM); + } +} + +uint32_t NvEncoder::GetChromaWidthInBytes(const NV_ENC_BUFFER_FORMAT bufferFormat, const uint32_t lumaWidth) +{ + switch (bufferFormat) + { + case NV_ENC_BUFFER_FORMAT_YV12: + case NV_ENC_BUFFER_FORMAT_IYUV: + return (lumaWidth + 1) / 2; + case NV_ENC_BUFFER_FORMAT_NV12: + return lumaWidth; + case NV_ENC_BUFFER_FORMAT_YUV420_10BIT: + return 2 * lumaWidth; + case NV_ENC_BUFFER_FORMAT_YUV444: + return lumaWidth; + case NV_ENC_BUFFER_FORMAT_YUV444_10BIT: + return 2 * lumaWidth; + case NV_ENC_BUFFER_FORMAT_ARGB: + case NV_ENC_BUFFER_FORMAT_ARGB10: + case NV_ENC_BUFFER_FORMAT_AYUV: + case NV_ENC_BUFFER_FORMAT_ABGR: + case NV_ENC_BUFFER_FORMAT_ABGR10: + return 0; + default: + NVENC_THROW_ERROR("Invalid Buffer format", NV_ENC_ERR_INVALID_PARAM); + } +} + + +int NvEncoder::GetCapabilityValue(GUID guidCodec, NV_ENC_CAPS capsToQuery) +{ + if (!m_hEncoder) + { + return 0; + } + NV_ENC_CAPS_PARAM capsParam = {}; + capsParam.version = NV_ENC_CAPS_PARAM_VER; + capsParam.capsToQuery = capsToQuery; + int v; + m_nvenc.nvEncGetEncodeCaps(m_hEncoder, guidCodec, &capsParam, &v); + return v; +} + +int NvEncoder::GetFrameSize() const +{ + switch (GetPixelFormat()) + { + case NV_ENC_BUFFER_FORMAT_YV12: + case NV_ENC_BUFFER_FORMAT_IYUV: + case NV_ENC_BUFFER_FORMAT_NV12: + return GetEncodeWidth() * (GetEncodeHeight() + (GetEncodeHeight() + 1) / 2); + case NV_ENC_BUFFER_FORMAT_YUV420_10BIT: + return 2 * GetEncodeWidth() * (GetEncodeHeight() + (GetEncodeHeight() + 1) / 2); + case NV_ENC_BUFFER_FORMAT_YUV444: + return GetEncodeWidth() * GetEncodeHeight() * 3; + case NV_ENC_BUFFER_FORMAT_YUV444_10BIT: + return 2 * GetEncodeWidth() * GetEncodeHeight() * 3; + case NV_ENC_BUFFER_FORMAT_ARGB: + case NV_ENC_BUFFER_FORMAT_ARGB10: + case NV_ENC_BUFFER_FORMAT_AYUV: + case NV_ENC_BUFFER_FORMAT_ABGR: + case NV_ENC_BUFFER_FORMAT_ABGR10: + return 4 * GetEncodeWidth() * GetEncodeHeight(); + default: + NVENC_THROW_ERROR("Invalid Buffer format", NV_ENC_ERR_INVALID_PARAM); + } +} + +void NvEncoder::GetInitializeParams(NV_ENC_INITIALIZE_PARAMS* pInitializeParams) +{ + if (!pInitializeParams || !pInitializeParams->encodeConfig) + { + NVENC_THROW_ERROR("Both pInitializeParams and pInitializeParams->encodeConfig can't be NULL", NV_ENC_ERR_INVALID_PTR); + } + NV_ENC_CONFIG* pEncodeConfig = pInitializeParams->encodeConfig; + *pEncodeConfig = m_encodeConfig; + *pInitializeParams = m_initializeParams; + pInitializeParams->encodeConfig = pEncodeConfig; +} + +void NvEncoder::InitializeBitstreamBuffer() +{ + for (int i = 0; i < m_nEncoderBuffer; i++) + { + NV_ENC_CREATE_BITSTREAM_BUFFER createBitstreamBuffer = {}; + createBitstreamBuffer.version = NV_ENC_CREATE_BITSTREAM_BUFFER_VER; + NVENC_API_CALL(m_nvenc.nvEncCreateBitstreamBuffer(m_hEncoder, &createBitstreamBuffer)); + m_vBitstreamOutputBuffer[i] = createBitstreamBuffer.bitstreamBuffer; + } +} + +void NvEncoder::DestroyBitstreamBuffer() +{ + for (uint32_t i = 0; i < m_vBitstreamOutputBuffer.size(); i++) + { + if (m_vBitstreamOutputBuffer[i]) + { + m_nvenc.nvEncDestroyBitstreamBuffer(m_hEncoder, m_vBitstreamOutputBuffer[i]); + } + } + + m_vBitstreamOutputBuffer.clear(); +} +}} +#endif \ No newline at end of file diff --git a/modules/cudacodec/src/NvEncoder.h b/modules/cudacodec/src/NvEncoder.h new file mode 100644 index 00000000000..dd13d2c1501 --- /dev/null +++ b/modules/cudacodec/src/NvEncoder.h @@ -0,0 +1,377 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_NVENCODER_HPP +#define OPENCV_NVENCODER_HPP +#include +#include "nvEncodeAPI.h" +#include +#include +#include +#include +#include +#include + +namespace cv { namespace cudacodec { + +#define NVENC_THROW_ERROR( errorStr, errorCode ) \ +do \ +{ \ +cv::String msg = cv::format("%s [Code = %d]", errorStr, errorCode); \ +cv::error(cv::Error::GpuApiCallError, msg, __FUNCTION__, __FILE__, __LINE__); \ +} while (0) + + +#define NVENC_API_CALL( nvencAPI ) \ +do \ +{ \ +NVENCSTATUS errorCode = nvencAPI; \ +if( errorCode != NV_ENC_SUCCESS) \ +{ \ +cv::String msg = cv::format("NVENC returned error [Code = %d]", errorCode); \ +cv::error(cv::Error::GpuApiCallError, msg, __FUNCTION__, __FILE__, __LINE__); \ +} \ +} while (0) + +struct NvEncInputFrame +{ + void* inputPtr = nullptr; + uint32_t chromaOffsets[2]; + uint32_t numChromaPlanes; + uint32_t pitch; + uint32_t chromaPitch; + NV_ENC_BUFFER_FORMAT bufferFormat; + NV_ENC_INPUT_RESOURCE_TYPE resourceType; +}; + +/** +* @brief Shared base class for different encoder interfaces. +*/ +class NvEncoder +{ +public: + /** + * @brief This function is used to initialize the encoder session. + * Application must call this function to initialize the encoder, before + * starting to encode any frames. + */ + virtual void CreateEncoder(const NV_ENC_INITIALIZE_PARAMS* pEncodeParams); + + /** + * @brief This function is used to destroy the encoder session. + * Application must call this function to destroy the encoder session and + * clean up any allocated resources. The application must call EndEncode() + * function to get any queued encoded frames before calling DestroyEncoder(). + */ + virtual void DestroyEncoder(); + + /** + * @brief This function is used to reconfigure an existing encoder session. + * Application can use this function to dynamically change the bitrate, + * resolution and other QOS parameters. If the application changes the + * resolution, it must set NV_ENC_RECONFIGURE_PARAMS::forceIDR. + */ + bool Reconfigure(const NV_ENC_RECONFIGURE_PARAMS* pReconfigureParams); + + /** + * @brief This function is used to get the next available input buffer. + * Applications must call this function to obtain a pointer to the next + * input buffer. The application must copy the uncompressed data to the + * input buffer and then call EncodeFrame() function to encode it. + */ + const NvEncInputFrame* GetNextInputFrame(); + + + /** + * @brief This function is used to encode a frame. + * Applications must call EncodeFrame() function to encode the uncompressed + * data, which has been copied to an input buffer obtained from the + * GetNextInputFrame() function. + */ + virtual void EncodeFrame(std::vector>& vPacket, NV_ENC_PIC_PARAMS* pPicParams = nullptr); + + /** + * @brief This function to flush the encoder queue. + * The encoder might be queuing frames for B picture encoding or lookahead; + * the application must call EndEncode() to get all the queued encoded frames + * from the encoder. The application must call this function before destroying + * an encoder session. + */ + virtual void EndEncode(std::vector>& vPacket); + + /** + * @brief This function is used to query hardware encoder capabilities. + * Applications can call this function to query capabilities like maximum encode + * dimensions, support for lookahead or the ME-only mode etc. + */ + int GetCapabilityValue(GUID guidCodec, NV_ENC_CAPS capsToQuery); + + /** + * @brief This function is used to get the current device on which encoder is running. + */ + void* GetDevice() const { return m_pDevice; } + + /** + * @brief This function is used to get the current device type which encoder is running. + */ + NV_ENC_DEVICE_TYPE GetDeviceType() const { return m_eDeviceType; } + + /** + * @brief This function is used to get the current encode width. + * The encode width can be modified by Reconfigure() function. + */ + int GetEncodeWidth() const { return m_nWidth; } + + /** + * @brief This function is used to get the current encode height. + * The encode height can be modified by Reconfigure() function. + */ + int GetEncodeHeight() const { return m_nHeight; } + + /** + * @brief This function is used to get the current frame size based on pixel format. + */ + int GetFrameSize() const; + + /** + * @brief This function is used to initialize config parameters based on + * given codec and preset guids. + * The application can call this function to get the default configuration + * for a certain preset. The application can either use these parameters + * directly or override them with application-specific settings before + * using them in CreateEncoder() function. + */ + void CreateDefaultEncoderParams(NV_ENC_INITIALIZE_PARAMS* pIntializeParams, GUID codecGuid, GUID presetGuid, NV_ENC_TUNING_INFO tuningInfo = NV_ENC_TUNING_INFO_UNDEFINED); + + /** + * @brief This function is used to get the current initialization parameters, + * which had been used to configure the encoder session. + * The initialization parameters are modified if the application calls + * Reconfigure() function. + */ + void GetInitializeParams(NV_ENC_INITIALIZE_PARAMS* pInitializeParams); + + /** + * @brief This function is used to get sequence and picture parameter headers. + * Application can call this function after encoder is initialized to get SPS and PPS + * nalus for the current encoder instance. The sequence header data might change when + * application calls Reconfigure() function. + */ + void GetSequenceParams(std::vector& seqParams); + + /** + * @brief NvEncoder class virtual destructor. + */ + virtual ~NvEncoder(); + +public: + /** + * @brief This a static function to get chroma offsets for YUV planar formats. + */ + static void GetChromaSubPlaneOffsets(const NV_ENC_BUFFER_FORMAT bufferFormat, const uint32_t pitch, + const uint32_t height, std::vector& chromaOffsets); + /** + * @brief This a static function to get the chroma plane pitch for YUV planar formats. + */ + static uint32_t GetChromaPitch(const NV_ENC_BUFFER_FORMAT bufferFormat, const uint32_t lumaPitch); + + /** + * @brief This a static function to get the number of chroma planes for YUV planar formats. + */ + static uint32_t GetNumChromaPlanes(const NV_ENC_BUFFER_FORMAT bufferFormat); + + /** + * @brief This a static function to get the chroma plane width in bytes for YUV planar formats. + */ + static uint32_t GetChromaWidthInBytes(const NV_ENC_BUFFER_FORMAT bufferFormat, const uint32_t lumaWidth); + + /** + * @brief This a static function to get the chroma planes height in bytes for YUV planar formats. + */ + static uint32_t GetChromaHeight(const NV_ENC_BUFFER_FORMAT bufferFormat, const uint32_t lumaHeight); + + + /** + * @brief This a static function to get the width in bytes for the frame. + * For YUV planar format this is the width in bytes of the luma plane. + */ + static uint32_t GetWidthInBytes(const NV_ENC_BUFFER_FORMAT bufferFormat, const uint32_t width); + + /** + * @brief This function returns the number of allocated buffers. + */ + uint32_t GetEncoderBufferCount() const { return m_nEncoderBuffer; } +protected: + + /** + * @brief NvEncoder class constructor. + * NvEncoder class constructor cannot be called directly by the application. + */ + NvEncoder(NV_ENC_DEVICE_TYPE eDeviceType, void* pDevice, uint32_t nWidth, uint32_t nHeight, + NV_ENC_BUFFER_FORMAT eBufferFormat, uint32_t nOutputDelay); + + /** + * @brief This function is used to check if hardware encoder is properly initialized. + */ + bool IsHWEncoderInitialized() const { return m_hEncoder != NULL && m_bEncoderInitialized; } + + /** + * @brief This function is used to register CUDA, D3D or OpenGL input buffers with NvEncodeAPI. + * This is non public function and is called by derived class for allocating + * and registering input buffers. + */ + void RegisterInputResources(std::vector inputframes, NV_ENC_INPUT_RESOURCE_TYPE eResourceType, + int width, int height, int pitch, NV_ENC_BUFFER_FORMAT bufferFormat, bool bReferenceFrame = false); + + /** + * @brief This function is used to unregister resources which had been previously registered for encoding + * using RegisterInputResources() function. + */ + void UnregisterInputResources(); + + /** + * @brief This function is used to register CUDA, D3D or OpenGL input or output buffers with NvEncodeAPI. + */ + NV_ENC_REGISTERED_PTR RegisterResource(void* pBuffer, NV_ENC_INPUT_RESOURCE_TYPE eResourceType, + int width, int height, int pitch, NV_ENC_BUFFER_FORMAT bufferFormat, NV_ENC_BUFFER_USAGE bufferUsage = NV_ENC_INPUT_IMAGE, + NV_ENC_FENCE_POINT_D3D12* pInputFencePoint = NULL); + + /** + * @brief This function returns maximum width used to open the encoder session. + * All encode input buffers are allocated using maximum dimensions. + */ + uint32_t GetMaxEncodeWidth() const { return m_nMaxEncodeWidth; } + + /** + * @brief This function returns maximum height used to open the encoder session. + * All encode input buffers are allocated using maximum dimensions. + */ + uint32_t GetMaxEncodeHeight() const { return m_nMaxEncodeHeight; } + + /** + * @brief This function returns the completion event. + */ + void* GetCompletionEvent(uint32_t eventIdx) { return (m_vpCompletionEvent.size() == m_nEncoderBuffer) ? m_vpCompletionEvent[eventIdx] : nullptr; } + + /** + * @brief This function returns the current pixel format. + */ + NV_ENC_BUFFER_FORMAT GetPixelFormat() const { return m_eBufferFormat; } + + /** + * @brief This function is used to submit the encode commands to the + * NVENC hardware. + */ + NVENCSTATUS DoEncode(NV_ENC_INPUT_PTR inputBuffer, NV_ENC_OUTPUT_PTR outputBuffer, NV_ENC_PIC_PARAMS* pPicParams); + + /** + * @brief This function is used to submit the encode commands to the + * NVENC hardware for ME only mode. + */ + //NVENCSTATUS DoMotionEstimation(NV_ENC_INPUT_PTR inputBuffer, NV_ENC_INPUT_PTR inputBufferForReference, NV_ENC_OUTPUT_PTR outputBuffer); + + /** + * @brief This function is used to map the input buffers to NvEncodeAPI. + */ + void MapResources(uint32_t bfrIdx); + + /** + * @brief This function is used to wait for completion of encode command. + */ + void WaitForCompletionEvent(int iEvent); + + /** + * @brief This function is used to send EOS to HW encoder. + */ + void SendEOS(); + +private: + /** + * @brief This is a private function which is used to check if there is any + buffering done by encoder. + * The encoder generally buffers data to encode B frames or for lookahead + * or pipelining. + */ + bool IsZeroDelay() { return m_nOutputDelay == 0; } + + /** + * @brief This is a private function which is used to load the encode api shared library. + */ + void LoadNvEncApi(); + + /** + * @brief This is a private function which is used to get the output packets + * from the encoder HW. + * This is called by DoEncode() function. If there is buffering enabled, + * this may return without any output data. + */ + void GetEncodedPacket(std::vector& vOutputBuffer, std::vector>& vPacket, bool bOutputDelay); + + /** + * @brief This is a private function which is used to initialize the bitstream buffers. + * This is only used in the encoding mode. + */ + void InitializeBitstreamBuffer(); + + /** + * @brief This is a private function which is used to destroy the bitstream buffers. + * This is only used in the encoding mode. + */ + void DestroyBitstreamBuffer(); + + /** + * @brief This is a private function which is used to destroy HW encoder. + */ + void DestroyHWEncoder(); + + /** + * @brief This function is used to flush the encoder queue. + */ + void FlushEncoder(); + +private: + /** + * @brief This is a pure virtual function which is used to allocate input buffers. + * The derived classes must implement this function. + */ + virtual void AllocateInputBuffers(int32_t numInputBuffers) = 0; + + /** + * @brief This is a pure virtual function which is used to destroy input buffers. + * The derived classes must implement this function. + */ + virtual void ReleaseInputBuffers() = 0; + +protected: + void* m_hEncoder = nullptr; + NV_ENCODE_API_FUNCTION_LIST m_nvenc; + std::vector m_vInputFrames; + std::vector m_vRegisteredResources; + std::vector m_vReferenceFrames; + std::vector m_vRegisteredResourcesForReference; + std::vector m_vMappedInputBuffers; + std::vector m_vMappedRefBuffers; + std::vector m_vpCompletionEvent; + + int32_t m_iToSend = 0; + int32_t m_iGot = 0; + int32_t m_nEncoderBuffer = 0; + int32_t m_nOutputDelay = 0; + +private: + void* m_pDevice; + NV_ENC_DEVICE_TYPE m_eDeviceType; + uint32_t m_nWidth; + uint32_t m_nHeight; + uint32_t m_nMaxEncodeWidth = 0; + uint32_t m_nMaxEncodeHeight = 0; + NV_ENC_BUFFER_FORMAT m_eBufferFormat; + NV_ENC_INITIALIZE_PARAMS m_initializeParams = {}; + NV_ENC_CONFIG m_encodeConfig = {}; + bool m_bEncoderInitialized = false; + uint32_t m_nExtraOutputDelay = 3; // To ensure encode and graphics can work in parallel, m_nExtraOutputDelay should be set to at least 1 + std::vector m_vBitstreamOutputBuffer; +}; +}} +#endif \ No newline at end of file diff --git a/modules/cudacodec/src/NvEncoderCuda.cpp b/modules/cudacodec/src/NvEncoderCuda.cpp new file mode 100644 index 00000000000..9aae90c2729 --- /dev/null +++ b/modules/cudacodec/src/NvEncoderCuda.cpp @@ -0,0 +1,196 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +#include "precomp.hpp" + +#if defined(HAVE_NVCUVENC) +#include "NvEncoderCuda.h" + +namespace cv { namespace cudacodec { +NvEncoderCuda::NvEncoderCuda(CUcontext cuContext, uint32_t nWidth, uint32_t nHeight, NV_ENC_BUFFER_FORMAT eBufferFormat, + uint32_t nExtraOutputDelay) : + NvEncoder(NV_ENC_DEVICE_TYPE_CUDA, cuContext, nWidth, nHeight, eBufferFormat, nExtraOutputDelay), + m_cuContext(cuContext) +{ + if (!m_hEncoder) + { + NVENC_THROW_ERROR("Encoder Initialization failed", NV_ENC_ERR_INVALID_DEVICE); + } + + if (!m_cuContext) + { + NVENC_THROW_ERROR("Invalid Cuda Context", NV_ENC_ERR_INVALID_DEVICE); + } +} + +NvEncoderCuda::~NvEncoderCuda() +{ + ReleaseCudaResources(); +} + +void NvEncoderCuda::AllocateInputBuffers(int32_t numInputBuffers) +{ + if (!IsHWEncoderInitialized()) + { + NVENC_THROW_ERROR("Encoder intialization failed", NV_ENC_ERR_ENCODER_NOT_INITIALIZED); + } + + cuSafeCall(cuCtxPushCurrent(m_cuContext)); + std::vector inputFrames; + for (int i = 0; i < numInputBuffers; i++) + { + CUdeviceptr pDeviceFrame; + uint32_t chromaHeight = GetNumChromaPlanes(GetPixelFormat()) * GetChromaHeight(GetPixelFormat(), GetMaxEncodeHeight()); + if (GetPixelFormat() == NV_ENC_BUFFER_FORMAT_YV12 || GetPixelFormat() == NV_ENC_BUFFER_FORMAT_IYUV) + chromaHeight = GetChromaHeight(GetPixelFormat(), GetMaxEncodeHeight()); + cuSafeCall(cuMemAllocPitch((CUdeviceptr*)&pDeviceFrame, + &m_cudaPitch, + GetWidthInBytes(GetPixelFormat(), GetMaxEncodeWidth()), + GetMaxEncodeHeight() + chromaHeight, 16)); + inputFrames.push_back((void*)pDeviceFrame); + } + cuSafeCall(cuCtxPopCurrent(NULL)); + + RegisterInputResources(inputFrames, + NV_ENC_INPUT_RESOURCE_TYPE_CUDADEVICEPTR, + GetMaxEncodeWidth(), + GetMaxEncodeHeight(), + (int)m_cudaPitch, + GetPixelFormat(), + false); +} + +void NvEncoderCuda::SetIOCudaStreams(NV_ENC_CUSTREAM_PTR inputStream, NV_ENC_CUSTREAM_PTR outputStream) +{ + NVENC_API_CALL(m_nvenc.nvEncSetIOCudaStreams(m_hEncoder, inputStream, outputStream)); +} + +void NvEncoderCuda::ReleaseInputBuffers() +{ + ReleaseCudaResources(); +} + +void NvEncoderCuda::ReleaseCudaResources() +{ + if (!m_hEncoder) + { + return; + } + + if (!m_cuContext) + { + return; + } + + UnregisterInputResources(); + + cuCtxPushCurrent(m_cuContext); + + for (uint32_t i = 0; i < m_vInputFrames.size(); ++i) + { + if (m_vInputFrames[i].inputPtr) + { + cuMemFree(reinterpret_cast(m_vInputFrames[i].inputPtr)); + } + } + m_vInputFrames.clear(); + + for (uint32_t i = 0; i < m_vReferenceFrames.size(); ++i) + { + if (m_vReferenceFrames[i].inputPtr) + { + cuMemFree(reinterpret_cast(m_vReferenceFrames[i].inputPtr)); + } + } + m_vReferenceFrames.clear(); + + cuCtxPopCurrent(NULL); + m_cuContext = nullptr; +} + +void NvEncoderCuda::CopyToDeviceFrame(CUcontext device, + void* pSrcFrame, + uint32_t nSrcPitch, + CUdeviceptr pDstFrame, + uint32_t dstPitch, + int width, + int height, + CUmemorytype srcMemoryType, + NV_ENC_BUFFER_FORMAT pixelFormat, + const uint32_t dstChromaOffsets[], + uint32_t numChromaPlanes, + bool bUnAlignedDeviceCopy, + CUstream stream) +{ + if (srcMemoryType != CU_MEMORYTYPE_HOST && srcMemoryType != CU_MEMORYTYPE_DEVICE) + { + NVENC_THROW_ERROR("Invalid source memory type for copy", NV_ENC_ERR_INVALID_PARAM); + } + + cuSafeCall(cuCtxPushCurrent(device)); + + uint32_t srcPitch = nSrcPitch ? nSrcPitch : NvEncoder::GetWidthInBytes(pixelFormat, width); + CUDA_MEMCPY2D m = {}; + m.srcMemoryType = srcMemoryType; + if (srcMemoryType == CU_MEMORYTYPE_HOST) + { + m.srcHost = pSrcFrame; + } + else + { + m.srcDevice = (CUdeviceptr)pSrcFrame; + } + m.srcPitch = srcPitch; + m.dstMemoryType = CU_MEMORYTYPE_DEVICE; + m.dstDevice = pDstFrame; + m.dstPitch = dstPitch; + m.WidthInBytes = NvEncoder::GetWidthInBytes(pixelFormat, width); + m.Height = height; + if (bUnAlignedDeviceCopy && srcMemoryType == CU_MEMORYTYPE_DEVICE) + { + cuSafeCall(cuMemcpy2DUnaligned(&m)); + } + else + { + cuSafeCall(stream == NULL ? cuMemcpy2D(&m) : cuMemcpy2DAsync(&m, stream)); + } + + std::vector srcChromaOffsets; + NvEncoder::GetChromaSubPlaneOffsets(pixelFormat, srcPitch, height, srcChromaOffsets); + uint32_t chromaHeight = NvEncoder::GetChromaHeight(pixelFormat, height); + uint32_t destChromaPitch = NvEncoder::GetChromaPitch(pixelFormat, dstPitch); + uint32_t srcChromaPitch = NvEncoder::GetChromaPitch(pixelFormat, srcPitch); + uint32_t chromaWidthInBytes = NvEncoder::GetChromaWidthInBytes(pixelFormat, width); + + for (uint32_t i = 0; i < numChromaPlanes; ++i) + { + if (chromaHeight) + { + if (srcMemoryType == CU_MEMORYTYPE_HOST) + { + m.srcHost = ((uint8_t*)pSrcFrame + srcChromaOffsets[i]); + } + else + { + m.srcDevice = (CUdeviceptr)((uint8_t*)pSrcFrame + srcChromaOffsets[i]); + } + m.srcPitch = srcChromaPitch; + + m.dstDevice = (CUdeviceptr)((uint8_t*)pDstFrame + dstChromaOffsets[i]); + m.dstPitch = destChromaPitch; + m.WidthInBytes = chromaWidthInBytes; + m.Height = chromaHeight; + if (bUnAlignedDeviceCopy && srcMemoryType == CU_MEMORYTYPE_DEVICE) + { + cuSafeCall(cuMemcpy2DUnaligned(&m)); + } + else + { + cuSafeCall(stream == NULL ? cuMemcpy2D(&m) : cuMemcpy2DAsync(&m, stream)); + } + } + } + cuSafeCall(cuCtxPopCurrent(NULL)); +} +}} +#endif \ No newline at end of file diff --git a/modules/cudacodec/src/NvEncoderCuda.h b/modules/cudacodec/src/NvEncoderCuda.h new file mode 100644 index 00000000000..55788dc7f96 --- /dev/null +++ b/modules/cudacodec/src/NvEncoderCuda.h @@ -0,0 +1,75 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_NVENCODERCUDA_HPP +#define OPENCV_NVENCODERCUDA_HPP +#include +#include +#include +#include +#include "NvEncoder.h" + +namespace cv { namespace cudacodec { + +/** +* @brief Encoder for CUDA device memory. +*/ +class NvEncoderCuda : public NvEncoder +{ +public: + NvEncoderCuda(CUcontext cuContext, uint32_t nWidth, uint32_t nHeight, NV_ENC_BUFFER_FORMAT eBufferFormat, + uint32_t nExtraOutputDelay = 3); + virtual ~NvEncoderCuda(); + + /** + * @brief This is a static function to copy input data from host memory to device memory. + * This function assumes YUV plane is a single contiguous memory segment. + */ + static void CopyToDeviceFrame(CUcontext device, + void* pSrcFrame, + uint32_t nSrcPitch, + CUdeviceptr pDstFrame, + uint32_t dstPitch, + int width, + int height, + CUmemorytype srcMemoryType, + NV_ENC_BUFFER_FORMAT pixelFormat, + const uint32_t dstChromaOffsets[], + uint32_t numChromaPlanes, + bool bUnAlignedDeviceCopy = false, + CUstream stream = NULL); + + /** + * @brief This function sets input and output CUDA streams + */ + void SetIOCudaStreams(NV_ENC_CUSTREAM_PTR inputStream, NV_ENC_CUSTREAM_PTR outputStream); + +protected: + /** + * @brief This function is used to release the input buffers allocated for encoding. + * This function is an override of virtual function NvEncoder::ReleaseInputBuffers(). + */ + virtual void ReleaseInputBuffers() override; + +private: + /** + * @brief This function is used to allocate input buffers for encoding. + * This function is an override of virtual function NvEncoder::AllocateInputBuffers(). + */ + virtual void AllocateInputBuffers(int32_t numInputBuffers) override; + +private: + /** + * @brief This is a private function to release CUDA device memory used for encoding. + */ + void ReleaseCudaResources(); + +protected: + CUcontext m_cuContext; + +private: + size_t m_cudaPitch = 0; +}; +}} +#endif \ No newline at end of file diff --git a/modules/cudacodec/src/ffmpeg_video_source.cpp b/modules/cudacodec/src/ffmpeg_video_source.cpp index 436a18eb395..815e5c8ce66 100644 --- a/modules/cudacodec/src/ffmpeg_video_source.cpp +++ b/modules/cudacodec/src/ffmpeg_video_source.cpp @@ -72,7 +72,9 @@ Codec FourccToCodec(int codec) switch (codec) { case CV_FOURCC_MACRO('m', 'p', 'e', 'g'): // fallthru + case CV_FOURCC_MACRO('m', 'p', 'g', '1'): // fallthru case CV_FOURCC_MACRO('M', 'P', 'G', '1'): return MPEG1; + case CV_FOURCC_MACRO('m', 'p', 'g', '2'): // fallthru case CV_FOURCC_MACRO('M', 'P', 'G', '2'): return MPEG2; case CV_FOURCC_MACRO('X', 'V', 'I', 'D'): // fallthru case CV_FOURCC_MACRO('m', 'p', '4', 'v'): // fallthru @@ -85,8 +87,18 @@ Codec FourccToCodec(int codec) case CV_FOURCC_MACRO('h', '2', '6', '5'): // fallthru case CV_FOURCC_MACRO('h', 'e', 'v', 'c'): return HEVC; case CV_FOURCC_MACRO('M', 'J', 'P', 'G'): return JPEG; - case CV_FOURCC_MACRO('V', 'P', '8', '0'): return VP8; - case CV_FOURCC_MACRO('V', 'P', '9', '0'): return VP9; + case CV_FOURCC_MACRO('v', 'p', '8', '0'): // fallthru + case CV_FOURCC_MACRO('V', 'P', '8', '0'): // fallthru + case CV_FOURCC_MACRO('v', 'p', '0', '8'): // fallthru + case CV_FOURCC_MACRO('V', 'P', '0', '8'): return VP8; + case CV_FOURCC_MACRO('v', 'p', '9', '0'): // fallthru + case CV_FOURCC_MACRO('V', 'P', '9', '0'): // fallthru + case CV_FOURCC_MACRO('V', 'P', '0', '9'): // fallthru + case CV_FOURCC_MACRO('v', 'p', '0', '9'): return VP9; + case CV_FOURCC_MACRO('a', 'v', '1', '0'): // fallthru + case CV_FOURCC_MACRO('A', 'V', '1', '0'): // fallthru + case CV_FOURCC_MACRO('a', 'v', '0', '1'): // fallthru + case CV_FOURCC_MACRO('A', 'V', '0', '1'): return AV1; default: break; } diff --git a/modules/cudacodec/src/frame_queue.cpp b/modules/cudacodec/src/frame_queue.cpp index 6fecff6b8cf..d73e04eb180 100644 --- a/modules/cudacodec/src/frame_queue.cpp +++ b/modules/cudacodec/src/frame_queue.cpp @@ -45,10 +45,8 @@ #ifdef HAVE_NVCUVID -RawPacket::RawPacket(const unsigned char* _data, const size_t _size, const bool _containsKeyFrame) : size(_size), containsKeyFrame(_containsKeyFrame) { - data = cv::makePtr(new unsigned char[size]); - memcpy(*data, _data, size); -}; +RawPacket::RawPacket(const unsigned char* data_, const size_t size, const bool containsKeyFrame_) : + data(data_,data_ + size), containsKeyFrame(containsKeyFrame_) {}; cv::cudacodec::detail::FrameQueue::~FrameQueue() { if (isFrameInUse_) diff --git a/modules/cudacodec/src/frame_queue.hpp b/modules/cudacodec/src/frame_queue.hpp index b6e0b06bccf..840b23c5dde 100644 --- a/modules/cudacodec/src/frame_queue.hpp +++ b/modules/cudacodec/src/frame_queue.hpp @@ -50,11 +50,12 @@ class RawPacket { public: RawPacket(const unsigned char* _data, const size_t _size = 0, const bool _containsKeyFrame = false); - unsigned char* Data() const { return *data; } - size_t size; - bool containsKeyFrame; + const unsigned char* Data() const noexcept { return data.data(); } + size_t Size() const noexcept { return data.size(); } + bool ContainsKeyFrame() const noexcept { return containsKeyFrame; } private: - cv::Ptr data = 0; + std::vector data; + bool containsKeyFrame = false; }; namespace cv { namespace cudacodec { namespace detail { diff --git a/modules/cudacodec/src/precomp.hpp b/modules/cudacodec/src/precomp.hpp index ca3c68958da..99a788a0128 100644 --- a/modules/cudacodec/src/precomp.hpp +++ b/modules/cudacodec/src/precomp.hpp @@ -57,32 +57,38 @@ #include "opencv2/core/private.cuda.hpp" #include -#ifdef HAVE_NVCUVID - #if defined(HAVE_DYNLINK_NVCUVID_HEADER) - #include - #elif defined(HAVE_NVCUVID_HEADER) - #include - #endif - - #ifdef _WIN32 +#if defined(HAVE_NVCUVID) || defined(HAVE_NVCUVENC) + #if _WIN32 #define NOMINMAX - #include - #ifdef HAVE_NVCUVENC - #include - #endif - #else - #include - #include #endif + #if defined(HAVE_NVCUVID) + #if defined(HAVE_DYNLINK_NVCUVID_HEADER) + #include + #elif defined(HAVE_NVCUVID_HEADER) + #include + #endif - #include "thread.hpp" - #include "video_source.hpp" - #include "ffmpeg_video_source.hpp" - #include "cuvid_video_source.hpp" - #include "frame_queue.hpp" - #include "video_decoder.hpp" - #include "video_parser.hpp" + #ifdef _WIN32 + #include + #else + #include + #include + #endif + #include "thread.hpp" + #include "video_source.hpp" + #include "ffmpeg_video_source.hpp" + #include "cuvid_video_source.hpp" + #include "frame_queue.hpp" + #include "video_decoder.hpp" + #include "video_parser.hpp" + #endif + #if defined(HAVE_NVCUVENC) + #include + #include + #include "NvEncoderCuda.h" + #include + #endif #endif #endif /* OPENCV_PRECOMP_H */ diff --git a/modules/cudacodec/src/video_decoder.cpp b/modules/cudacodec/src/video_decoder.cpp index 69845a7a0b9..f828b08c158 100644 --- a/modules/cudacodec/src/video_decoder.cpp +++ b/modules/cudacodec/src/video_decoder.cpp @@ -148,6 +148,14 @@ void cv::cudacodec::detail::VideoDecoder::create(const FormatInfo& videoFormat) createInfo_.ulTargetHeight = videoFormat.height; createInfo_.ulMaxWidth = videoFormat.ulMaxWidth; createInfo_.ulMaxHeight = videoFormat.ulMaxHeight; + createInfo_.display_area.left = videoFormat.displayArea.x; + createInfo_.display_area.right = videoFormat.displayArea.x + videoFormat.displayArea.width; + createInfo_.display_area.top = videoFormat.displayArea.y; + createInfo_.display_area.bottom = videoFormat.displayArea.y + videoFormat.displayArea.height; + createInfo_.target_rect.left = videoFormat.targetRoi.x; + createInfo_.target_rect.right = videoFormat.targetRoi.x + videoFormat.targetRoi.width; + createInfo_.target_rect.top = videoFormat.targetRoi.y; + createInfo_.target_rect.bottom = videoFormat.targetRoi.y + videoFormat.targetRoi.height; createInfo_.ulNumOutputSurfaces = 2; createInfo_.ulCreationFlags = videoCreateFlags; createInfo_.vidLock = lock_; diff --git a/modules/cudacodec/src/video_decoder.hpp b/modules/cudacodec/src/video_decoder.hpp index 98d8e652542..76d731f2078 100644 --- a/modules/cudacodec/src/video_decoder.hpp +++ b/modules/cudacodec/src/video_decoder.hpp @@ -49,10 +49,17 @@ namespace cv { namespace cudacodec { namespace detail { class VideoDecoder { public: - VideoDecoder(const Codec& codec, const int minNumDecodeSurfaces, CUcontext ctx, CUvideoctxlock lock) : ctx_(ctx), lock_(lock), decoder_(0) + VideoDecoder(const Codec& codec, const int minNumDecodeSurfaces, cv::Size targetSz, cv::Rect srcRoi, cv::Rect targetRoi, CUcontext ctx, CUvideoctxlock lock) : + ctx_(ctx), lock_(lock), decoder_(0) { videoFormat_.codec = codec; videoFormat_.ulNumDecodeSurfaces = minNumDecodeSurfaces; + // alignment enforced by nvcuvid, likely due to chroma subsampling + videoFormat_.targetSz.width = targetSz.width - targetSz.width % 2; videoFormat_.targetSz.height = targetSz.height - targetSz.height % 2; + videoFormat_.srcRoi.x = srcRoi.x - srcRoi.x % 4; videoFormat_.srcRoi.width = srcRoi.width - srcRoi.width % 4; + videoFormat_.srcRoi.y = srcRoi.y - srcRoi.y % 2; videoFormat_.srcRoi.height = srcRoi.height - srcRoi.height % 2; + videoFormat_.targetRoi.x = targetRoi.x - targetRoi.x % 4; videoFormat_.targetRoi.width = targetRoi.width - targetRoi.width % 4; + videoFormat_.targetRoi.y = targetRoi.y - targetRoi.y % 2; videoFormat_.targetRoi.height = targetRoi.height - targetRoi.height % 2; } ~VideoDecoder() @@ -66,6 +73,9 @@ class VideoDecoder // Get the code-type currently used. cudaVideoCodec codec() const { return static_cast(videoFormat_.codec); } int nDecodeSurfaces() const { return videoFormat_.ulNumDecodeSurfaces; } + cv::Size getTargetSz() const { return videoFormat_.targetSz; } + cv::Rect getSrcRoi() const { return videoFormat_.srcRoi; } + cv::Rect getTargetRoi() const { return videoFormat_.targetRoi; } unsigned long frameWidth() const { return videoFormat_.ulWidth; } unsigned long frameHeight() const { return videoFormat_.ulHeight; } @@ -89,7 +99,7 @@ class VideoDecoder cuSafeCall( cuvidMapVideoFrame(decoder_, picIdx, &ptr, &pitch, &videoProcParams) ); - return cuda::GpuMat(frameHeight() * 3 / 2, frameWidth(), CV_8UC1, (void*) ptr, pitch); + return cuda::GpuMat(targetHeight() * 3 / 2, targetWidth(), CV_8UC1, (void*) ptr, pitch); } void unmapFrame(cuda::GpuMat& frame) diff --git a/modules/cudacodec/src/video_parser.cpp b/modules/cudacodec/src/video_parser.cpp index feda982c5b8..8bccd065a8d 100644 --- a/modules/cudacodec/src/video_parser.cpp +++ b/modules/cudacodec/src/video_parser.cpp @@ -120,10 +120,19 @@ int CUDAAPI cv::cudacodec::detail::VideoParser::HandleVideoSequence(void* userDa newFormat.nBitDepthMinus8 = format->bit_depth_luma_minus8; newFormat.ulWidth = format->coded_width; newFormat.ulHeight = format->coded_height; - newFormat.width = format->coded_width; - newFormat.height = format->coded_height; - newFormat.displayArea = Rect(Point(format->display_area.left, format->display_area.top), Point(format->display_area.right, format->display_area.bottom)); newFormat.fps = format->frame_rate.numerator / static_cast(format->frame_rate.denominator); + newFormat.targetSz = thiz->videoDecoder_->getTargetSz(); + newFormat.width = newFormat.targetSz.width ? newFormat.targetSz.width : format->coded_width; + newFormat.height = newFormat.targetSz.height ? newFormat.targetSz.height : format->coded_height; + newFormat.srcRoi = thiz->videoDecoder_->getSrcRoi(); + if (newFormat.srcRoi.empty()) { + format->display_area.right = format->coded_width; + format->display_area.bottom = format->coded_height; + newFormat.displayArea = Rect(Point(format->display_area.left, format->display_area.top), Point(format->display_area.right, format->display_area.bottom)); + } + else + newFormat.displayArea = newFormat.srcRoi; + newFormat.targetRoi = thiz->videoDecoder_->getTargetRoi(); newFormat.ulNumDecodeSurfaces = min(!thiz->allowFrameDrop_ ? max(thiz->videoDecoder_->nDecodeSurfaces(), static_cast(format->min_num_decode_surfaces)) : format->min_num_decode_surfaces * 2, 32); if (format->progressive_sequence) diff --git a/modules/cudacodec/src/video_reader.cpp b/modules/cudacodec/src/video_reader.cpp index 903defaf379..a566bd4de71 100644 --- a/modules/cudacodec/src/video_reader.cpp +++ b/modules/cudacodec/src/video_reader.cpp @@ -54,6 +54,7 @@ Ptr cv::cudacodec::createVideoReader(const Ptr&, co #else // HAVE_NVCUVID void nv12ToBgra(const GpuMat& decodedFrame, GpuMat& outFrame, int width, int height, cudaStream_t stream); +bool ValidColorFormat(const ColorFormat colorFormat); void videoDecPostProcessFrame(const GpuMat& decodedFrame, GpuMat& outFrame, int width, int height, const ColorFormat colorFormat, Stream stream) @@ -74,7 +75,7 @@ void videoDecPostProcessFrame(const GpuMat& decodedFrame, GpuMat& outFrame, int outFrame.create(height, width, CV_8UC1); cudaMemcpy2DAsync(outFrame.ptr(), outFrame.step, decodedFrame.ptr(), decodedFrame.step, width, height, cudaMemcpyDeviceToDevice, StreamAccessor::getStream(stream)); } - else if (colorFormat == ColorFormat::YUV) { + else if (colorFormat == ColorFormat::NV_NV12) { decodedFrame.copyTo(outFrame, stream); } } @@ -86,7 +87,8 @@ namespace class VideoReaderImpl : public VideoReader { public: - explicit VideoReaderImpl(const Ptr& source, const int minNumDecodeSurfaces, const bool allowFrameDrop = false , const bool udpSource = false); + explicit VideoReaderImpl(const Ptr& source, const int minNumDecodeSurfaces, const bool allowFrameDrop = false , const bool udpSource = false, + const Size targetSz = Size(), const Rect srcRoi = Rect(), const Rect targetRoi = Rect()); ~VideoReaderImpl(); bool nextFrame(GpuMat& frame, Stream& stream) CV_OVERRIDE; @@ -99,7 +101,7 @@ namespace bool set(const VideoReaderProps propertyId, const double propertyVal) CV_OVERRIDE; - void set(const ColorFormat _colorFormat) CV_OVERRIDE; + bool set(const ColorFormat colorFormat_) CV_OVERRIDE; bool get(const VideoReaderProps propertyId, double& propertyVal) const CV_OVERRIDE; bool getVideoReaderProps(const VideoReaderProps propertyId, double& propertyValOut, double propertyValIn) const CV_OVERRIDE; @@ -131,7 +133,8 @@ namespace return videoSource_->format(); } - VideoReaderImpl::VideoReaderImpl(const Ptr& source, const int minNumDecodeSurfaces, const bool allowFrameDrop, const bool udpSource) : + VideoReaderImpl::VideoReaderImpl(const Ptr& source, const int minNumDecodeSurfaces, const bool allowFrameDrop, const bool udpSource, + const Size targetSz, const Rect srcRoi, const Rect targetRoi) : videoSource_(source), lock_(0) { @@ -143,7 +146,7 @@ namespace cuSafeCall( cuCtxGetCurrent(&ctx) ); cuSafeCall( cuvidCtxLockCreate(&lock_, ctx) ); frameQueue_.reset(new FrameQueue()); - videoDecoder_.reset(new VideoDecoder(videoSource_->format().codec, minNumDecodeSurfaces, ctx, lock_)); + videoDecoder_.reset(new VideoDecoder(videoSource_->format().codec, minNumDecodeSurfaces, targetSz, srcRoi, targetRoi, ctx, lock_)); videoParser_.reset(new VideoParser(videoDecoder_, frameQueue_, allowFrameDrop, udpSource)); videoSource_->setVideoParser(videoParser_); videoSource_->start(); @@ -254,7 +257,8 @@ namespace if (idx >= rawPacketsBaseIdx && idx < rawPacketsBaseIdx + rawPackets.size()) { if (!frame.isMat()) CV_Error(Error::StsUnsupportedFormat, "Raw data is stored on the host and must be retrieved using a cv::Mat"); - Mat tmp(1, rawPackets.at(idx - rawPacketsBaseIdx).size, CV_8UC1, rawPackets.at(idx - rawPacketsBaseIdx).Data(), rawPackets.at(idx - rawPacketsBaseIdx).size); + const size_t i = idx - rawPacketsBaseIdx; + Mat tmp(1, rawPackets.at(i).Size(), CV_8UC1, const_cast(rawPackets.at(i).Data()), rawPackets.at(i).Size()); frame.getMatRef() = tmp; } } @@ -270,8 +274,16 @@ namespace return false; } - void VideoReaderImpl::set(const ColorFormat _colorFormat) { - colorFormat = _colorFormat; + bool ValidColorFormat(const ColorFormat colorFormat) { + if (colorFormat == ColorFormat::BGRA || colorFormat == ColorFormat::BGR || colorFormat == ColorFormat::GRAY || colorFormat == ColorFormat::NV_NV12) + return true; + return false; + } + + bool VideoReaderImpl::set(const ColorFormat colorFormat_) { + if (!ValidColorFormat(colorFormat_)) return false; + colorFormat = colorFormat_; + return true; } bool VideoReaderImpl::get(const VideoReaderProps propertyId, double& propertyVal) const { @@ -299,7 +311,7 @@ namespace case VideoReaderProps::PROP_LRF_HAS_KEY_FRAME: { const int iPacket = propertyVal - rawPacketsBaseIdx; if (videoSource_->RawModeEnabled() && iPacket >= 0 && iPacket < rawPackets.size()) { - propertyVal = rawPackets.at(iPacket).containsKeyFrame; + propertyVal = rawPackets.at(iPacket).ContainsKeyFrame(); return true; } else @@ -357,13 +369,15 @@ Ptr cv::cudacodec::createVideoReader(const String& filename, const videoSource.reset(new CuvidVideoSource(filename)); } - return makePtr(videoSource, params.minNumDecodeSurfaces, params.allowFrameDrop, params.udpSource); + return makePtr(videoSource, params.minNumDecodeSurfaces, params.allowFrameDrop, params.udpSource, params.targetSz, + params.srcRoi, params.targetRoi); } Ptr cv::cudacodec::createVideoReader(const Ptr& source, const VideoReaderInitParams params) { Ptr videoSource(new RawVideoSourceWrapper(source, params.rawMode)); - return makePtr(videoSource, params.minNumDecodeSurfaces); + return makePtr(videoSource, params.minNumDecodeSurfaces, params.allowFrameDrop, params.udpSource, params.targetSz, + params.srcRoi, params.targetRoi); } #endif // HAVE_NVCUVID diff --git a/modules/cudacodec/src/video_writer.cpp b/modules/cudacodec/src/video_writer.cpp index ce3b68fb2a8..db3e2e36306 100644 --- a/modules/cudacodec/src/video_writer.cpp +++ b/modules/cudacodec/src/video_writer.cpp @@ -43,874 +43,345 @@ #include "precomp.hpp" -using namespace cv; +namespace cv { namespace cudacodec { using namespace cv::cuda; -using namespace cv::cudacodec; -#if !defined(HAVE_NVCUVENC) || !defined(_WIN32) +#if !defined(HAVE_NVCUVENC) -cv::cudacodec::EncoderParams::EncoderParams() { throw_no_cuda(); } -cv::cudacodec::EncoderParams::EncoderParams(const String&) { throw_no_cuda(); } -void cv::cudacodec::EncoderParams::load(const String&) { throw_no_cuda(); } -void cv::cudacodec::EncoderParams::save(const String&) const { throw_no_cuda(); } +Ptr createVideoWriter(const String&, const Size, const Codec, const double, const ColorFormat, const Ptr, const cv::cuda::Stream&) { throw_no_cuda(); return Ptr(); } +Ptr createVideoWriter(const String&, const Size, const Codec, const double, const ColorFormat, const EncoderParams&, const Ptr, const cv::cuda::Stream&) { throw_no_cuda(); return Ptr(); } -Ptr cv::cudacodec::createVideoWriter(const String&, Size, double, SurfaceFormat) { throw_no_cuda(); return Ptr(); } -Ptr cv::cudacodec::createVideoWriter(const String&, Size, double, const EncoderParams&, SurfaceFormat) { throw_no_cuda(); return Ptr(); } +#else // !defined HAVE_NVCUVENC -Ptr cv::cudacodec::createVideoWriter(const Ptr&, Size, double, SurfaceFormat) { throw_no_cuda(); return Ptr(); } -Ptr cv::cudacodec::createVideoWriter(const Ptr&, Size, double, const EncoderParams&, SurfaceFormat) { throw_no_cuda(); return Ptr(); } +NV_ENC_BUFFER_FORMAT EncBufferFormat(const ColorFormat colorFormat); +int NChannels(const ColorFormat colorFormat); +GUID CodecGuid(const Codec codec); +void FrameRate(const double fps, uint32_t& frameRateNum, uint32_t& frameRateDen); +GUID EncodingProfileGuid(const EncodeProfile encodingProfile); +GUID EncodingPresetGuid(const EncodePreset nvPreset); +bool Equal(const GUID& g1, const GUID& g2); -#else // !defined HAVE_NVCUVENC || !defined _WIN32 - -void RGB_to_YV12(const GpuMat& src, GpuMat& dst); - -/////////////////////////////////////////////////////////////////////////// -// VideoWriterImpl - -namespace +bool operator==(const EncoderParams& lhs, const EncoderParams& rhs) { - class NVEncoderWrapper - { - public: - NVEncoderWrapper() : encoder_(0) - { - int err; - - err = NVGetHWEncodeCaps(); - if (err) - CV_Error(Error::GpuNotSupported, "No CUDA capability present"); - - // Create the Encoder API Interface - err = NVCreateEncoder(&encoder_); - CV_Assert( err == 0 ); - } - - ~NVEncoderWrapper() - { - if (encoder_) - NVDestroyEncoder(encoder_); - } - - operator NVEncoder() const - { - return encoder_; - } - - private: - NVEncoder encoder_; - }; - - enum CodecType - { - MPEG1, // not supported yet - MPEG2, // not supported yet - MPEG4, // not supported yet - H264 - }; - - class VideoWriterImpl : public VideoWriter - { - public: - VideoWriterImpl(const Ptr& callback, Size frameSize, double fps, SurfaceFormat format, CodecType codec = H264); - VideoWriterImpl(const Ptr& callback, Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format, CodecType codec = H264); - - void write(InputArray frame, bool lastFrame = false); - - EncoderParams getEncoderParams() const; - - private: - void initEncoder(double fps); - void setEncodeParams(const EncoderParams& params); - void initGpuMemory(); - void initCallBacks(); - void createHWEncoder(); - - Ptr callback_; - Size frameSize_; - - CodecType codec_; - SurfaceFormat inputFormat_; - NVVE_SurfaceFormat surfaceFormat_; - - NVEncoderWrapper encoder_; - - GpuMat videoFrame_; - CUvideoctxlock cuCtxLock_; + return std::tie(lhs.nvPreset, lhs.tuningInfo, lhs.encodingProfile, lhs.rateControlMode, lhs.multiPassEncoding, lhs.constQp.qpInterB, lhs.constQp.qpInterP, lhs.constQp.qpIntra, + lhs.averageBitRate, lhs.maxBitRate, lhs.targetQuality, lhs.gopLength) == std::tie(rhs.nvPreset, rhs.tuningInfo, rhs.encodingProfile, rhs.rateControlMode, rhs.multiPassEncoding, rhs.constQp.qpInterB, rhs.constQp.qpInterP, rhs.constQp.qpIntra, + rhs.averageBitRate, rhs.maxBitRate, rhs.targetQuality, rhs.gopLength); +}; - // CallBacks - - static unsigned char* NVENCAPI HandleAcquireBitStream(int* pBufferSize, void* pUserdata); - static void NVENCAPI HandleReleaseBitStream(int nBytesInBuffer, unsigned char* cb, void* pUserdata); - static void NVENCAPI HandleOnBeginFrame(const NVVE_BeginFrameInfo* pbfi, void* pUserdata); - static void NVENCAPI HandleOnEndFrame(const NVVE_EndFrameInfo* pefi, void* pUserdata); - }; - - VideoWriterImpl::VideoWriterImpl(const Ptr& callback, Size frameSize, double fps, SurfaceFormat format, CodecType codec) : - callback_(callback), - frameSize_(frameSize), - codec_(codec), - inputFormat_(format), - cuCtxLock_(0) - { - surfaceFormat_ = (inputFormat_ == SF_BGR ? YV12 : static_cast(inputFormat_)); +class RawVideoWriter : public EncoderCallback +{ +public: + RawVideoWriter(String fileName); + ~RawVideoWriter(); + void onEncoded(std::vector> vPacket); + void onEncodingFinished(); +private: + std::ofstream fpOut; +}; + +RawVideoWriter::RawVideoWriter(String fileName) { + fpOut = std::ofstream(fileName, std::ios::out | std::ios::binary); + if (!fpOut) + CV_Error(Error::StsError, "Failed to open video file " + fileName + " for writing!"); +} - initEncoder(fps); +void RawVideoWriter::onEncodingFinished() { + fpOut.close(); +} - initGpuMemory(); +RawVideoWriter::~RawVideoWriter() { + onEncodingFinished(); +} - initCallBacks(); +void RawVideoWriter::onEncoded(std::vector> vPacket) { + for (auto& packet : vPacket) + fpOut.write(reinterpret_cast(packet.data()), packet.size()); +} - createHWEncoder(); +class VideoWriterImpl : public VideoWriter +{ +public: + VideoWriterImpl(const Ptr& videoWriter, const Size frameSize, const Codec codec, const double fps, + const ColorFormat colorFormat, const Stream& stream = Stream::Null()); + VideoWriterImpl(const Ptr& videoWriter, const Size frameSize, const Codec codec, const double fps, + const ColorFormat colorFormat, const EncoderParams& encoderParams, const Stream& stream = Stream::Null()); + ~VideoWriterImpl(); + void write(InputArray frame); + EncoderParams getEncoderParams() const; + void release(); +private: + void Init(const Codec codec, const double fps, const Size frameSz); + void InitializeEncoder(const GUID codec, const double fps); + void CopyToNvSurface(const InputArray src); + + Ptr encoderCallback; + ColorFormat colorFormat = ColorFormat::UNDEFINED; + NV_ENC_BUFFER_FORMAT surfaceFormat = NV_ENC_BUFFER_FORMAT::NV_ENC_BUFFER_FORMAT_UNDEFINED; + EncoderParams encoderParams; + Stream stream = Stream::Null(); + Ptr pEnc; + std::vector> vPacket; + int nSrcChannels = 0; + CUcontext cuContext; +}; + +NV_ENC_BUFFER_FORMAT EncBufferFormat(const ColorFormat colorFormat) { + switch (colorFormat) { + case ColorFormat::BGR: return NV_ENC_BUFFER_FORMAT_ARGB; + case ColorFormat::RGB: return NV_ENC_BUFFER_FORMAT_ABGR; + case ColorFormat::BGRA: return NV_ENC_BUFFER_FORMAT_ARGB; + case ColorFormat::RGBA: return NV_ENC_BUFFER_FORMAT_ABGR; + case ColorFormat::GRAY: + case ColorFormat::NV_NV12: return NV_ENC_BUFFER_FORMAT_NV12; + case ColorFormat::NV_YV12: return NV_ENC_BUFFER_FORMAT_YV12; + case ColorFormat::NV_IYUV: return NV_ENC_BUFFER_FORMAT_IYUV; + case ColorFormat::NV_YUV444: return NV_ENC_BUFFER_FORMAT_YUV444; + case ColorFormat::NV_AYUV: return NV_ENC_BUFFER_FORMAT_AYUV; + default: return NV_ENC_BUFFER_FORMAT_UNDEFINED; } +} - VideoWriterImpl::VideoWriterImpl(const Ptr& callback, Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format, CodecType codec) : - callback_(callback), - frameSize_(frameSize), - codec_(codec), - inputFormat_(format), - cuCtxLock_(0) - { - surfaceFormat_ = (inputFormat_ == SF_BGR ? YV12 : static_cast(inputFormat_)); - - initEncoder(fps); - - setEncodeParams(params); - - initGpuMemory(); - - initCallBacks(); - - createHWEncoder(); +int NChannels(const ColorFormat colorFormat) { + switch (colorFormat) { + case ColorFormat::BGR: + case ColorFormat::RGB: + case ColorFormat::NV_IYUV: + case ColorFormat::NV_YUV444: return 3; + case ColorFormat::RGBA: + case ColorFormat::BGRA: + case ColorFormat::NV_AYUV: return 4; + case ColorFormat::GRAY: + case ColorFormat::NV_NV12: + case ColorFormat::NV_YV12: return 1; + default: return 0; } +} - void VideoWriterImpl::initEncoder(double fps) - { - int err; - - // Set codec - - static const unsigned long codecs_id[] = - { - NV_CODEC_TYPE_MPEG1, NV_CODEC_TYPE_MPEG2, NV_CODEC_TYPE_MPEG4, NV_CODEC_TYPE_H264, NV_CODEC_TYPE_VC1 - }; - err = NVSetCodec(encoder_, codecs_id[codec_]); - if (err) - CV_Error(Error::StsNotImplemented, "Codec format is not supported"); - - // Set default params - - err = NVSetDefaultParam(encoder_); - CV_Assert( err == 0 ); - - // Set some common params - - int inputSize[] = { frameSize_.width, frameSize_.height }; - err = NVSetParamValue(encoder_, NVVE_IN_SIZE, &inputSize); - CV_Assert( err == 0 ); - err = NVSetParamValue(encoder_, NVVE_OUT_SIZE, &inputSize); - CV_Assert( err == 0 ); - - int aspectRatio[] = { frameSize_.width, frameSize_.height, ASPECT_RATIO_DAR }; - err = NVSetParamValue(encoder_, NVVE_ASPECT_RATIO, &aspectRatio); - CV_Assert( err == 0 ); - - // FPS - - int frame_rate = static_cast(fps + 0.5); - int frame_rate_base = 1; - while (fabs(static_cast(frame_rate) / frame_rate_base) - fps > 0.001) - { - frame_rate_base *= 10; - frame_rate = static_cast(fps*frame_rate_base + 0.5); - } - int FrameRate[] = { frame_rate, frame_rate_base }; - err = NVSetParamValue(encoder_, NVVE_FRAME_RATE, &FrameRate); - CV_Assert( err == 0 ); - - // Select device for encoding - - int gpuID = getDevice(); - err = NVSetParamValue(encoder_, NVVE_FORCE_GPU_SELECTION, &gpuID); - CV_Assert( err == 0 ); +VideoWriterImpl::VideoWriterImpl(const Ptr& encoderCallBack_, const Size frameSz, const Codec codec, const double fps, + const ColorFormat colorFormat_, const EncoderParams& encoderParams_, const Stream& stream_) : + encoderCallback(encoderCallBack_), colorFormat(colorFormat_), encoderParams(encoderParams_), stream(stream_) +{ + CV_Assert(colorFormat != ColorFormat::UNDEFINED); + surfaceFormat = EncBufferFormat(colorFormat); + if (surfaceFormat == NV_ENC_BUFFER_FORMAT_UNDEFINED) { + String msg = cv::format("Unsupported input surface format: %i", colorFormat); + CV_LOG_WARNING(NULL, msg); + CV_Error(Error::StsUnsupportedFormat, msg); } + nSrcChannels = NChannels(colorFormat); + Init(codec, fps, frameSz); +} - void VideoWriterImpl::setEncodeParams(const EncoderParams& params) - { - int err; - - int P_Interval = params.P_Interval; - err = NVSetParamValue(encoder_, NVVE_P_INTERVAL, &P_Interval); - CV_Assert( err == 0 ); - - int IDR_Period = params.IDR_Period; - err = NVSetParamValue(encoder_, NVVE_IDR_PERIOD, &IDR_Period); - CV_Assert( err == 0 ); - - int DynamicGOP = params.DynamicGOP; - err = NVSetParamValue(encoder_, NVVE_DYNAMIC_GOP, &DynamicGOP); - CV_Assert( err == 0 ); - - NVVE_RateCtrlType RCType = static_cast(params.RCType); - err = NVSetParamValue(encoder_, NVVE_RC_TYPE, &RCType); - CV_Assert( err == 0 ); - - int AvgBitrate = params.AvgBitrate; - err = NVSetParamValue(encoder_, NVVE_AVG_BITRATE, &AvgBitrate); - CV_Assert( err == 0 ); - - int PeakBitrate = params.PeakBitrate; - err = NVSetParamValue(encoder_, NVVE_PEAK_BITRATE, &PeakBitrate); - CV_Assert( err == 0 ); - - int QP_Level_Intra = params.QP_Level_Intra; - err = NVSetParamValue(encoder_, NVVE_QP_LEVEL_INTRA, &QP_Level_Intra); - CV_Assert( err == 0 ); - - int QP_Level_InterP = params.QP_Level_InterP; - err = NVSetParamValue(encoder_, NVVE_QP_LEVEL_INTER_P, &QP_Level_InterP); - CV_Assert( err == 0 ); - - int QP_Level_InterB = params.QP_Level_InterB; - err = NVSetParamValue(encoder_, NVVE_QP_LEVEL_INTER_B, &QP_Level_InterB); - CV_Assert( err == 0 ); - - int DeblockMode = params.DeblockMode; - err = NVSetParamValue(encoder_, NVVE_DEBLOCK_MODE, &DeblockMode); - CV_Assert( err == 0 ); - - int ProfileLevel = params.ProfileLevel; - err = NVSetParamValue(encoder_, NVVE_PROFILE_LEVEL, &ProfileLevel); - CV_Assert( err == 0 ); - - int ForceIntra = params.ForceIntra; - err = NVSetParamValue(encoder_, NVVE_FORCE_INTRA, &ForceIntra); - CV_Assert( err == 0 ); - - int ForceIDR = params.ForceIDR; - err = NVSetParamValue(encoder_, NVVE_FORCE_IDR, &ForceIDR); - CV_Assert( err == 0 ); - - int ClearStat = params.ClearStat; - err = NVSetParamValue(encoder_, NVVE_CLEAR_STAT, &ClearStat); - CV_Assert( err == 0 ); - - NVVE_DI_MODE DIMode = static_cast(params.DIMode); - err = NVSetParamValue(encoder_, NVVE_SET_DEINTERLACE, &DIMode); - CV_Assert( err == 0 ); - - if (params.Presets != -1) - { - NVVE_PRESETS_TARGET Presets = static_cast(params.Presets); - err = NVSetParamValue(encoder_, NVVE_PRESETS, &Presets); - CV_Assert( err == 0 ); - } +VideoWriterImpl::VideoWriterImpl(const Ptr& encoderCallback, const Size frameSz, const Codec codec, const double fps, + const ColorFormat colorFormat, const Stream& stream) : + VideoWriterImpl(encoderCallback, frameSz, codec, fps, colorFormat, EncoderParams(), stream) +{ +} - int DisableCabac = params.DisableCabac; - err = NVSetParamValue(encoder_, NVVE_DISABLE_CABAC, &DisableCabac); - CV_Assert( err == 0 ); +void VideoWriterImpl::release() { + pEnc->EndEncode(vPacket); + encoderCallback->onEncoded(vPacket); + encoderCallback->onEncodingFinished(); +} - int NaluFramingType = params.NaluFramingType; - err = NVSetParamValue(encoder_, NVVE_CONFIGURE_NALU_FRAMING_TYPE, &NaluFramingType); - CV_Assert( err == 0 ); +VideoWriterImpl::~VideoWriterImpl() { + release(); +} - int DisableSPSPPS = params.DisableSPSPPS; - err = NVSetParamValue(encoder_, NVVE_DISABLE_SPS_PPS, &DisableSPSPPS); - CV_Assert( err == 0 ); +GUID CodecGuid(const Codec codec) { + switch (codec) { + case Codec::H264: return NV_ENC_CODEC_H264_GUID; + case Codec::HEVC: return NV_ENC_CODEC_HEVC_GUID; + default: break; } + std::string msg = "Unknown codec: cudacodec::VideoWriter only supports CODEC_VW::H264 and CODEC_VW::HEVC"; + CV_LOG_WARNING(NULL, msg); + CV_Error(Error::StsUnsupportedFormat, msg); +} - EncoderParams VideoWriterImpl::getEncoderParams() const - { - int err; - - EncoderParams params; - - int P_Interval; - err = NVGetParamValue(encoder_, NVVE_P_INTERVAL, &P_Interval); - CV_Assert( err == 0 ); - params.P_Interval = P_Interval; - - int IDR_Period; - err = NVGetParamValue(encoder_, NVVE_IDR_PERIOD, &IDR_Period); - CV_Assert( err == 0 ); - params.IDR_Period = IDR_Period; - - int DynamicGOP; - err = NVGetParamValue(encoder_, NVVE_DYNAMIC_GOP, &DynamicGOP); - CV_Assert( err == 0 ); - params.DynamicGOP = DynamicGOP; - - NVVE_RateCtrlType RCType; - err = NVGetParamValue(encoder_, NVVE_RC_TYPE, &RCType); - CV_Assert( err == 0 ); - params.RCType = RCType; - - int AvgBitrate; - err = NVGetParamValue(encoder_, NVVE_AVG_BITRATE, &AvgBitrate); - CV_Assert( err == 0 ); - params.AvgBitrate = AvgBitrate; - - int PeakBitrate; - err = NVGetParamValue(encoder_, NVVE_PEAK_BITRATE, &PeakBitrate); - CV_Assert( err == 0 ); - params.PeakBitrate = PeakBitrate; - - int QP_Level_Intra; - err = NVGetParamValue(encoder_, NVVE_QP_LEVEL_INTRA, &QP_Level_Intra); - CV_Assert( err == 0 ); - params.QP_Level_Intra = QP_Level_Intra; - - int QP_Level_InterP; - err = NVGetParamValue(encoder_, NVVE_QP_LEVEL_INTER_P, &QP_Level_InterP); - CV_Assert( err == 0 ); - params.QP_Level_InterP = QP_Level_InterP; - - int QP_Level_InterB; - err = NVGetParamValue(encoder_, NVVE_QP_LEVEL_INTER_B, &QP_Level_InterB); - CV_Assert( err == 0 ); - params.QP_Level_InterB = QP_Level_InterB; - - int DeblockMode; - err = NVGetParamValue(encoder_, NVVE_DEBLOCK_MODE, &DeblockMode); - CV_Assert( err == 0 ); - params.DeblockMode = DeblockMode; - - int ProfileLevel; - err = NVGetParamValue(encoder_, NVVE_PROFILE_LEVEL, &ProfileLevel); - CV_Assert( err == 0 ); - params.ProfileLevel = ProfileLevel; - - int ForceIntra; - err = NVGetParamValue(encoder_, NVVE_FORCE_INTRA, &ForceIntra); - CV_Assert( err == 0 ); - params.ForceIntra = ForceIntra; - - int ForceIDR; - err = NVGetParamValue(encoder_, NVVE_FORCE_IDR, &ForceIDR); - CV_Assert( err == 0 ); - params.ForceIDR = ForceIDR; - - int ClearStat; - err = NVGetParamValue(encoder_, NVVE_CLEAR_STAT, &ClearStat); - CV_Assert( err == 0 ); - params.ClearStat = ClearStat; - - NVVE_DI_MODE DIMode; - err = NVGetParamValue(encoder_, NVVE_SET_DEINTERLACE, &DIMode); - CV_Assert( err == 0 ); - params.DIMode = DIMode; - - params.Presets = -1; - - int DisableCabac; - err = NVGetParamValue(encoder_, NVVE_DISABLE_CABAC, &DisableCabac); - CV_Assert( err == 0 ); - params.DisableCabac = DisableCabac; - - int NaluFramingType; - err = NVGetParamValue(encoder_, NVVE_CONFIGURE_NALU_FRAMING_TYPE, &NaluFramingType); - CV_Assert( err == 0 ); - params.NaluFramingType = NaluFramingType; - - int DisableSPSPPS; - err = NVGetParamValue(encoder_, NVVE_DISABLE_SPS_PPS, &DisableSPSPPS); - CV_Assert( err == 0 ); - params.DisableSPSPPS = DisableSPSPPS; - - return params; +void VideoWriterImpl::Init(const Codec codec, const double fps, const Size frameSz) { + // init context + GpuMat temp(1, 1, CV_8UC1); + temp.release(); + cuSafeCall(cuCtxGetCurrent(&cuContext)); + CV_Assert(nSrcChannels != 0); + const GUID codecGuid = CodecGuid(codec); + try { + pEnc = new NvEncoderCuda(cuContext, frameSz.width, frameSz.height, surfaceFormat); + InitializeEncoder(codecGuid, fps); + const cudaStream_t cudaStream = cuda::StreamAccessor::getStream(stream); + pEnc->SetIOCudaStreams((NV_ENC_CUSTREAM_PTR)&cudaStream, (NV_ENC_CUSTREAM_PTR)&cudaStream); } - - void VideoWriterImpl::initGpuMemory() + catch (cv::Exception& e) { - int err; - - // initialize context - GpuMat temp(1, 1, CV_8U); - temp.release(); - - static const int bpp[] = - { - 16, // UYVY, 4:2:2 - 16, // YUY2, 4:2:2 - 12, // YV12, 4:2:0 - 12, // NV12, 4:2:0 - 12, // IYUV, 4:2:0 - }; - - CUcontext cuContext; - cuSafeCall( cuCtxGetCurrent(&cuContext) ); - - // Allocate the CUDA memory Pitched Surface - if (surfaceFormat_ == UYVY || surfaceFormat_ == YUY2) - videoFrame_.create(frameSize_.height, (frameSize_.width * bpp[surfaceFormat_]) / 8, CV_8UC1); - else - videoFrame_.create((frameSize_.height * bpp[surfaceFormat_]) / 8, frameSize_.width, CV_8UC1); - - // Create the Video Context Lock (used for synchronization) - cuSafeCall( cuvidCtxLockCreate(&cuCtxLock_, cuContext) ); - - // If we are using GPU Device Memory with NVCUVENC, it is necessary to create a - // CUDA Context with a Context Lock cuvidCtxLock. The Context Lock needs to be passed to NVCUVENC - - int iUseDeviceMem = 1; - err = NVSetParamValue(encoder_, NVVE_DEVICE_MEMORY_INPUT, &iUseDeviceMem); - CV_Assert( err == 0 ); - - err = NVSetParamValue(encoder_, NVVE_DEVICE_CTX_LOCK, &cuCtxLock_); - CV_Assert( err == 0 ); + String msg = String("Error initializing Nvidia Encoder. Refer to Nvidia's GPU Support Matrix to confirm your GPU supports hardware encoding, ") + + String("codec and surface format and check the encoder documentation to verify your choice of encoding paramaters are supported.") + + e.msg; + CV_Error(Error::GpuApiCallError, msg); } + const Size encoderFrameSz(pEnc->GetEncodeWidth(), pEnc->GetEncodeHeight()); + CV_Assert(frameSz == encoderFrameSz); +} - void VideoWriterImpl::initCallBacks() - { - NVVE_CallbackParams cb; - memset(&cb, 0, sizeof(NVVE_CallbackParams)); - - cb.pfnacquirebitstream = HandleAcquireBitStream; - cb.pfnonbeginframe = HandleOnBeginFrame; - cb.pfnonendframe = HandleOnEndFrame; - cb.pfnreleasebitstream = HandleReleaseBitStream; - - NVRegisterCB(encoder_, cb, this); +void FrameRate(const double fps, uint32_t& frameRateNum, uint32_t& frameRateDen) { + CV_Assert(fps >= 0); + int frame_rate = (int)(fps + 0.5); + int frame_rate_base = 1; + while (fabs(((double)frame_rate / frame_rate_base) - fps) > 0.001) { + frame_rate_base *= 10; + frame_rate = (int)(fps * frame_rate_base + 0.5); } + frameRateNum = frame_rate; + frameRateDen = frame_rate_base; +} - void VideoWriterImpl::createHWEncoder() - { - int err; - - // Create the NVIDIA HW resources for Encoding on NVIDIA hardware - err = NVCreateHWEncoder(encoder_); - CV_Assert( err == 0 ); +GUID EncodingProfileGuid(const EncodeProfile encodingProfile) { + switch (encodingProfile) { + case(ENC_CODEC_PROFILE_AUTOSELECT): return NV_ENC_CODEC_PROFILE_AUTOSELECT_GUID; + case(ENC_H264_PROFILE_BASELINE): return NV_ENC_H264_PROFILE_BASELINE_GUID; + case(ENC_H264_PROFILE_MAIN): return NV_ENC_H264_PROFILE_MAIN_GUID; + case(ENC_H264_PROFILE_HIGH): return NV_ENC_H264_PROFILE_HIGH_GUID; + case(ENC_H264_PROFILE_HIGH_444): return NV_ENC_H264_PROFILE_HIGH_444_GUID; + case(ENC_H264_PROFILE_STEREO): return NV_ENC_H264_PROFILE_STEREO_GUID; + case(ENC_H264_PROFILE_PROGRESSIVE_HIGH): return NV_ENC_H264_PROFILE_PROGRESSIVE_HIGH_GUID; + case(ENC_H264_PROFILE_CONSTRAINED_HIGH): return NV_ENC_H264_PROFILE_CONSTRAINED_HIGH_GUID; + case(ENC_HEVC_PROFILE_MAIN): return NV_ENC_HEVC_PROFILE_MAIN_GUID; + case(ENC_HEVC_PROFILE_MAIN10): return NV_ENC_HEVC_PROFILE_MAIN10_GUID; + case(ENC_HEVC_PROFILE_FREXT): return NV_ENC_HEVC_PROFILE_FREXT_GUID; + default: break; } + std::string msg = "Unknown Encoding Profile."; + CV_LOG_WARNING(NULL, msg); + CV_Error(Error::StsUnsupportedFormat, msg); +} - // UYVY/YUY2 are both 4:2:2 formats (16bpc) - // Luma, U, V are interleaved, chroma is subsampled (w/2,h) - void copyUYVYorYUY2Frame(Size frameSize, const GpuMat& src, GpuMat& dst) - { - // Source is YUVY/YUY2 4:2:2, the YUV data in a packed and interleaved - - // YUV Copy setup - CUDA_MEMCPY2D stCopyYUV422; - memset(&stCopyYUV422, 0, sizeof(CUDA_MEMCPY2D)); - - stCopyYUV422.srcXInBytes = 0; - stCopyYUV422.srcY = 0; - stCopyYUV422.srcMemoryType = CU_MEMORYTYPE_DEVICE; - stCopyYUV422.srcHost = 0; - stCopyYUV422.srcDevice = (CUdeviceptr) src.data; - stCopyYUV422.srcArray = 0; - stCopyYUV422.srcPitch = src.step; - - stCopyYUV422.dstXInBytes = 0; - stCopyYUV422.dstY = 0; - stCopyYUV422.dstMemoryType = CU_MEMORYTYPE_DEVICE; - stCopyYUV422.dstHost = 0; - stCopyYUV422.dstDevice = (CUdeviceptr) dst.data; - stCopyYUV422.dstArray = 0; - stCopyYUV422.dstPitch = dst.step; - - stCopyYUV422.WidthInBytes = frameSize.width * 2; - stCopyYUV422.Height = frameSize.height; - - // DMA Luma/Chroma - cuSafeCall( cuMemcpy2D(&stCopyYUV422) ); +GUID EncodingPresetGuid(const EncodePreset nvPreset) { + switch (nvPreset) { + case ENC_PRESET_P1: return NV_ENC_PRESET_P1_GUID; + case ENC_PRESET_P2: return NV_ENC_PRESET_P2_GUID; + case ENC_PRESET_P3: return NV_ENC_PRESET_P3_GUID; + case ENC_PRESET_P4: return NV_ENC_PRESET_P4_GUID; + case ENC_PRESET_P5: return NV_ENC_PRESET_P5_GUID; + case ENC_PRESET_P6: return NV_ENC_PRESET_P6_GUID; + case ENC_PRESET_P7: return NV_ENC_PRESET_P7_GUID; + default: break; } + std::string msg = "Unknown Nvidia Encoding Preset."; + CV_LOG_WARNING(NULL, msg); + CV_Error(Error::StsUnsupportedFormat, msg); +} - // YV12/IYUV are both 4:2:0 planar formats (12bpc) - // Luma, U, V chroma planar (12bpc), chroma is subsampled (w/2,h/2) - void copyYV12orIYUVFrame(Size frameSize, const GpuMat& src, GpuMat& dst) - { - // Source is YV12/IYUV, this native format is converted to NV12 format by the video encoder - - // (1) luma copy setup - CUDA_MEMCPY2D stCopyLuma; - memset(&stCopyLuma, 0, sizeof(CUDA_MEMCPY2D)); - - stCopyLuma.srcXInBytes = 0; - stCopyLuma.srcY = 0; - stCopyLuma.srcMemoryType = CU_MEMORYTYPE_DEVICE; - stCopyLuma.srcHost = 0; - stCopyLuma.srcDevice = (CUdeviceptr) src.data; - stCopyLuma.srcArray = 0; - stCopyLuma.srcPitch = src.step; - - stCopyLuma.dstXInBytes = 0; - stCopyLuma.dstY = 0; - stCopyLuma.dstMemoryType = CU_MEMORYTYPE_DEVICE; - stCopyLuma.dstHost = 0; - stCopyLuma.dstDevice = (CUdeviceptr) dst.data; - stCopyLuma.dstArray = 0; - stCopyLuma.dstPitch = dst.step; - - stCopyLuma.WidthInBytes = frameSize.width; - stCopyLuma.Height = frameSize.height; - - // (2) chroma copy setup, U/V can be done together - CUDA_MEMCPY2D stCopyChroma; - memset(&stCopyChroma, 0, sizeof(CUDA_MEMCPY2D)); - - stCopyChroma.srcXInBytes = 0; - stCopyChroma.srcY = frameSize.height << 1; // U/V chroma offset - stCopyChroma.srcMemoryType = CU_MEMORYTYPE_DEVICE; - stCopyChroma.srcHost = 0; - stCopyChroma.srcDevice = (CUdeviceptr) src.data; - stCopyChroma.srcArray = 0; - stCopyChroma.srcPitch = src.step >> 1; // chroma is subsampled by 2 (but it has U/V are next to each other) - - stCopyChroma.dstXInBytes = 0; - stCopyChroma.dstY = frameSize.height << 1; // chroma offset (srcY*srcPitch now points to the chroma planes) - stCopyChroma.dstMemoryType = CU_MEMORYTYPE_DEVICE; - stCopyChroma.dstHost = 0; - stCopyChroma.dstDevice = (CUdeviceptr) dst.data; - stCopyChroma.dstArray = 0; - stCopyChroma.dstPitch = dst.step >> 1; - - stCopyChroma.WidthInBytes = frameSize.width >> 1; - stCopyChroma.Height = frameSize.height; // U/V are sent together - - // DMA Luma - cuSafeCall( cuMemcpy2D(&stCopyLuma) ); - - // DMA Chroma channels (UV side by side) - cuSafeCall( cuMemcpy2D(&stCopyChroma) ); - } +bool Equal(const GUID& g1, const GUID& g2) { + if (std::tie(g1.Data1, g1.Data2, g1.Data3, g1.Data4) == std::tie(g2.Data1, g2.Data2, g2.Data3, g2.Data4)) + return true; + return false; +} - // NV12 is 4:2:0 format (12bpc) - // Luma followed by U/V chroma interleaved (12bpc), chroma is subsampled (w/2,h/2) - void copyNV12Frame(Size frameSize, const GpuMat& src, GpuMat& dst) - { - // Source is NV12 in pitch linear memory - // Because we are assume input is NV12 (if we take input in the native format), the encoder handles NV12 as a native format in pitch linear memory - - // Luma/Chroma can be done in a single transfer - CUDA_MEMCPY2D stCopyNV12; - memset(&stCopyNV12, 0, sizeof(CUDA_MEMCPY2D)); - - stCopyNV12.srcXInBytes = 0; - stCopyNV12.srcY = 0; - stCopyNV12.srcMemoryType = CU_MEMORYTYPE_DEVICE; - stCopyNV12.srcHost = 0; - stCopyNV12.srcDevice = (CUdeviceptr) src.data; - stCopyNV12.srcArray = 0; - stCopyNV12.srcPitch = src.step; - - stCopyNV12.dstXInBytes = 0; - stCopyNV12.dstY = 0; - stCopyNV12.dstMemoryType = CU_MEMORYTYPE_DEVICE; - stCopyNV12.dstHost = 0; - stCopyNV12.dstDevice = (CUdeviceptr) dst.data; - stCopyNV12.dstArray = 0; - stCopyNV12.dstPitch = dst.step; - - stCopyNV12.WidthInBytes = frameSize.width; - stCopyNV12.Height = (frameSize.height * 3) >> 1; - - // DMA Luma/Chroma - cuSafeCall( cuMemcpy2D(&stCopyNV12) ); - } +void VideoWriterImpl::InitializeEncoder(const GUID codec, const double fps) +{ + NV_ENC_INITIALIZE_PARAMS initializeParams = {}; + initializeParams.version = NV_ENC_INITIALIZE_PARAMS_VER; + NV_ENC_CONFIG encodeConfig = {}; + encodeConfig.version = NV_ENC_CONFIG_VER; + initializeParams.encodeConfig = &encodeConfig; + pEnc->CreateDefaultEncoderParams(&initializeParams, codec, EncodingPresetGuid(encoderParams.nvPreset), (NV_ENC_TUNING_INFO)encoderParams.tuningInfo); + FrameRate(fps, initializeParams.frameRateNum, initializeParams.frameRateDen); + initializeParams.encodeConfig->profileGUID = EncodingProfileGuid(encoderParams.encodingProfile); + initializeParams.encodeConfig->rcParams.rateControlMode = (NV_ENC_PARAMS_RC_MODE)(encoderParams.rateControlMode + encoderParams.multiPassEncoding); + initializeParams.encodeConfig->rcParams.constQP = { encoderParams.constQp.qpInterB, encoderParams.constQp.qpInterB,encoderParams.constQp.qpInterB }; + initializeParams.encodeConfig->rcParams.averageBitRate = encoderParams.averageBitRate; + initializeParams.encodeConfig->rcParams.maxBitRate = encoderParams.maxBitRate; + initializeParams.encodeConfig->rcParams.targetQuality = encoderParams.targetQuality; + initializeParams.encodeConfig->gopLength = encoderParams.gopLength; + if (Equal(codec, NV_ENC_CODEC_H264_GUID)) + initializeParams.encodeConfig->encodeCodecConfig.h264Config.idrPeriod = encoderParams.gopLength; + else if (Equal(codec, NV_ENC_CODEC_HEVC_GUID)) + initializeParams.encodeConfig->encodeCodecConfig.hevcConfig.idrPeriod = encoderParams.gopLength; + pEnc->CreateEncoder(&initializeParams); +} - void VideoWriterImpl::write(InputArray _frame, bool lastFrame) - { - GpuMat frame = _frame.getGpuMat(); +inline bool CvFormat(const ColorFormat cf) { + if (cf == ColorFormat::BGR || cf == ColorFormat::RGB || cf == ColorFormat::BGRA || cf == ColorFormat::RGBA || cf == ColorFormat::GRAY) + return true; + return false; +} - if (inputFormat_ == SF_BGR) - { - CV_Assert( frame.size() == frameSize_ ); - CV_Assert( frame.type() == CV_8UC1 || frame.type() == CV_8UC3 || frame.type() == CV_8UC4 ); - } - else - { - CV_Assert( frame.size() == videoFrame_.size() ); - CV_Assert( frame.type() == videoFrame_.type() ); +void VideoWriterImpl::CopyToNvSurface(const InputArray src) +{ + const NvEncInputFrame* encoderInputFrame = pEnc->GetNextInputFrame(); + CV_Assert(src.isGpuMat() || src.isMat()); + if (CvFormat(colorFormat)) + CV_Assert(src.size() == Size(pEnc->GetEncodeWidth(), pEnc->GetEncodeHeight())); + Npp8u* dst = (Npp8u*)encoderInputFrame->inputPtr; + if (colorFormat == ColorFormat::BGR || colorFormat == ColorFormat::RGB) { + GpuMat srcDevice; + if (src.isGpuMat()) + srcDevice = src.getGpuMat(); + else { + if (stream) + srcDevice.upload(src, stream); + else + srcDevice.upload(src); } - - NVVE_EncodeFrameParams efparams; - efparams.Width = frameSize_.width; - efparams.Height = frameSize_.height; - efparams.Pitch = static_cast(videoFrame_.step); - efparams.SurfFmt = surfaceFormat_; - efparams.PictureStruc = FRAME_PICTURE; - efparams.topfieldfirst = 0; - efparams.repeatFirstField = 0; - efparams.progressiveFrame = (surfaceFormat_ == NV12) ? 1 : 0; - efparams.bLast = lastFrame; - efparams.picBuf = 0; // Must be set to NULL in order to support device memory input - - // Don't forget we need to lock/unlock between memcopies - cuSafeCall( cuvidCtxLock(cuCtxLock_, 0) ); - - if (inputFormat_ == SF_BGR) - { - RGB_to_YV12(frame, videoFrame_); + if (colorFormat == ColorFormat::BGR) { + GpuMat dstGpuMat(pEnc->GetEncodeHeight(), pEnc->GetEncodeWidth(), CV_8UC4, dst, encoderInputFrame->pitch); + cuda::cvtColor(srcDevice, dstGpuMat, COLOR_BGR2BGRA, 0, stream); } - else - { - switch (surfaceFormat_) - { - case UYVY: // UYVY (4:2:2) - case YUY2: // YUY2 (4:2:2) - copyUYVYorYUY2Frame(frameSize_, frame, videoFrame_); - break; - - case YV12: // YV12 (4:2:0), Y V U - case IYUV: // IYUV (4:2:0), Y U V - copyYV12orIYUVFrame(frameSize_, frame, videoFrame_); - break; - - case NV12: // NV12 (4:2:0) - copyNV12Frame(frameSize_, frame, videoFrame_); - break; - } + else { + GpuMat dstGpuMat(pEnc->GetEncodeHeight(), pEnc->GetEncodeWidth(), CV_8UC4, dst, encoderInputFrame->pitch); + cuda::cvtColor(srcDevice, dstGpuMat, COLOR_RGB2RGBA, 0, stream); } - - cuSafeCall( cuvidCtxUnlock(cuCtxLock_, 0) ); - - int err = NVEncodeFrame(encoder_, &efparams, 0, videoFrame_.data); - CV_Assert( err == 0 ); - } - - unsigned char* NVENCAPI VideoWriterImpl::HandleAcquireBitStream(int* pBufferSize, void* pUserdata) - { - VideoWriterImpl* thiz = static_cast(pUserdata); - - return thiz->callback_->acquireBitStream(pBufferSize); - } - - void NVENCAPI VideoWriterImpl::HandleReleaseBitStream(int nBytesInBuffer, unsigned char* cb, void* pUserdata) - { - VideoWriterImpl* thiz = static_cast(pUserdata); - - thiz->callback_->releaseBitStream(cb, nBytesInBuffer); } - - void NVENCAPI VideoWriterImpl::HandleOnBeginFrame(const NVVE_BeginFrameInfo* pbfi, void* pUserdata) - { - VideoWriterImpl* thiz = static_cast(pUserdata); - - thiz->callback_->onBeginFrame(pbfi->nFrameNumber, static_cast(pbfi->nPicType)); - } - - void NVENCAPI VideoWriterImpl::HandleOnEndFrame(const NVVE_EndFrameInfo* pefi, void* pUserdata) - { - VideoWriterImpl* thiz = static_cast(pUserdata); - - thiz->callback_->onEndFrame(pefi->nFrameNumber, static_cast(pefi->nPicType)); - } - - /////////////////////////////////////////////////////////////////////////// - // FFMPEG - - class EncoderCallBackFFMPEG : public EncoderCallBack - { - public: - EncoderCallBackFFMPEG(const String& fileName, Size frameSize, double fps); - ~EncoderCallBackFFMPEG(); - - unsigned char* acquireBitStream(int* bufferSize); - void releaseBitStream(unsigned char* data, int size); - void onBeginFrame(int frameNumber, PicType picType); - void onEndFrame(int frameNumber, PicType picType); - - private: - static bool init_MediaStream_FFMPEG(); - - struct OutputMediaStream_FFMPEG* stream_; - std::vector buf_; - bool isKeyFrame_; - - static Create_OutputMediaStream_FFMPEG_Plugin create_OutputMediaStream_FFMPEG_p; - static Release_OutputMediaStream_FFMPEG_Plugin release_OutputMediaStream_FFMPEG_p; - static Write_OutputMediaStream_FFMPEG_Plugin write_OutputMediaStream_FFMPEG_p; - }; - - Create_OutputMediaStream_FFMPEG_Plugin EncoderCallBackFFMPEG::create_OutputMediaStream_FFMPEG_p = 0; - Release_OutputMediaStream_FFMPEG_Plugin EncoderCallBackFFMPEG::release_OutputMediaStream_FFMPEG_p = 0; - Write_OutputMediaStream_FFMPEG_Plugin EncoderCallBackFFMPEG::write_OutputMediaStream_FFMPEG_p = 0; - - bool EncoderCallBackFFMPEG::init_MediaStream_FFMPEG() - { - static bool initialized = false; - - if (!initialized) - { - #if defined(_WIN32) - const char* module_name = "opencv_ffmpeg" - CVAUX_STR(CV_VERSION_MAJOR) CVAUX_STR(CV_VERSION_MINOR) CVAUX_STR(CV_VERSION_REVISION) - #if (defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__) - "_64" - #endif - ".dll"; - - static HMODULE cvFFOpenCV = LoadLibrary(module_name); - - if (cvFFOpenCV) - { - create_OutputMediaStream_FFMPEG_p = - (Create_OutputMediaStream_FFMPEG_Plugin)GetProcAddress(cvFFOpenCV, "create_OutputMediaStream_FFMPEG"); - release_OutputMediaStream_FFMPEG_p = - (Release_OutputMediaStream_FFMPEG_Plugin)GetProcAddress(cvFFOpenCV, "release_OutputMediaStream_FFMPEG"); - write_OutputMediaStream_FFMPEG_p = - (Write_OutputMediaStream_FFMPEG_Plugin)GetProcAddress(cvFFOpenCV, "write_OutputMediaStream_FFMPEG"); - - initialized = create_OutputMediaStream_FFMPEG_p != 0 && release_OutputMediaStream_FFMPEG_p != 0 && write_OutputMediaStream_FFMPEG_p != 0; - } - #elif defined(HAVE_FFMPEG) - create_OutputMediaStream_FFMPEG_p = create_OutputMediaStream_FFMPEG; - release_OutputMediaStream_FFMPEG_p = release_OutputMediaStream_FFMPEG; - write_OutputMediaStream_FFMPEG_p = write_OutputMediaStream_FFMPEG; - - initialized = true; - #endif + else if (colorFormat == ColorFormat::GRAY) { + const cudaMemcpyKind memcpyKind = src.isGpuMat() ? cudaMemcpyDeviceToDevice : cudaMemcpyHostToDevice; + const void* srcPtr = src.isGpuMat() ? src.getGpuMat().data : src.getMat().data; + const size_t srcPitch = src.isGpuMat() ? src.getGpuMat().step : src.getMat().step; + const uint32_t chromaHeight = NvEncoder::GetChromaHeight(NV_ENC_BUFFER_FORMAT_NV12, pEnc->GetEncodeHeight()); + if (stream) { + cudaMemcpy2DAsync(dst, encoderInputFrame->pitch, srcPtr, srcPitch, pEnc->GetEncodeWidth(), pEnc->GetEncodeHeight(), memcpyKind, + cuda::StreamAccessor::getStream(stream)); + cudaMemset2DAsync(&dst[encoderInputFrame->pitch * pEnc->GetEncodeHeight()], encoderInputFrame->pitch, 128, pEnc->GetEncodeWidth(), chromaHeight, + cuda::StreamAccessor::getStream(stream)); + } + else { + cudaMemcpy2D(dst, encoderInputFrame->pitch, srcPtr, srcPitch, pEnc->GetEncodeWidth(), pEnc->GetEncodeHeight(), memcpyKind); + cudaMemset2D(&dst[encoderInputFrame->pitch * pEnc->GetEncodeHeight()], encoderInputFrame->pitch, 128, pEnc->GetEncodeWidth(), chromaHeight); } - - return initialized; - } - - EncoderCallBackFFMPEG::EncoderCallBackFFMPEG(const String& fileName, Size frameSize, double fps) : - stream_(0), isKeyFrame_(false) - { - int buf_size = std::max(frameSize.area() * 4, 1024 * 1024); - buf_.resize(buf_size); - - CV_Assert( init_MediaStream_FFMPEG() ); - - stream_ = create_OutputMediaStream_FFMPEG_p(fileName.c_str(), frameSize.width, frameSize.height, fps); - CV_Assert( stream_ != 0 ); - } - - EncoderCallBackFFMPEG::~EncoderCallBackFFMPEG() - { - release_OutputMediaStream_FFMPEG_p(stream_); - } - - unsigned char* EncoderCallBackFFMPEG::acquireBitStream(int* bufferSize) - { - *bufferSize = static_cast(buf_.size()); - return &buf_[0]; - } - - void EncoderCallBackFFMPEG::releaseBitStream(unsigned char* data, int size) - { - write_OutputMediaStream_FFMPEG_p(stream_, data, size, isKeyFrame_); - } - - void EncoderCallBackFFMPEG::onBeginFrame(int frameNumber, PicType picType) - { - CV_UNUSED(frameNumber); - isKeyFrame_ = (picType == IFRAME); } - - void EncoderCallBackFFMPEG::onEndFrame(int frameNumber, PicType picType) - { - CV_UNUSED(frameNumber); - CV_UNUSED(picType); + else { + void* srcPtr = src.isGpuMat() ? src.getGpuMat().data : src.getMat().data; + const CUmemorytype cuMemoryType = src.isGpuMat() ? CU_MEMORYTYPE_DEVICE : CU_MEMORYTYPE_HOST; + NvEncoderCuda::CopyToDeviceFrame(cuContext, srcPtr, static_cast(src.step()), (CUdeviceptr)encoderInputFrame->inputPtr, (int)encoderInputFrame->pitch, pEnc->GetEncodeWidth(), + pEnc->GetEncodeHeight(), cuMemoryType, encoderInputFrame->bufferFormat, encoderInputFrame->chromaOffsets, encoderInputFrame->numChromaPlanes, + false, cuda::StreamAccessor::getStream(stream)); } } -/////////////////////////////////////////////////////////////////////////// -// EncoderParams - -cv::cudacodec::EncoderParams::EncoderParams() -{ - P_Interval = 3; - IDR_Period = 15; - DynamicGOP = 0; - RCType = 1; - AvgBitrate = 4000000; - PeakBitrate = 10000000; - QP_Level_Intra = 25; - QP_Level_InterP = 28; - QP_Level_InterB = 31; - DeblockMode = 1; - ProfileLevel = 65357; - ForceIntra = 0; - ForceIDR = 0; - ClearStat = 0; - DIMode = 1; - Presets = 2; - DisableCabac = 0; - NaluFramingType = 0; - DisableSPSPPS = 0; -} - -cv::cudacodec::EncoderParams::EncoderParams(const String& configFile) -{ - load(configFile); -} - -void cv::cudacodec::EncoderParams::load(const String& configFile) -{ - FileStorage fs(configFile, FileStorage::READ); - CV_Assert( fs.isOpened() ); - - read(fs["P_Interval" ], P_Interval, 3); - read(fs["IDR_Period" ], IDR_Period, 15); - read(fs["DynamicGOP" ], DynamicGOP, 0); - read(fs["RCType" ], RCType, 1); - read(fs["AvgBitrate" ], AvgBitrate, 4000000); - read(fs["PeakBitrate" ], PeakBitrate, 10000000); - read(fs["QP_Level_Intra" ], QP_Level_Intra, 25); - read(fs["QP_Level_InterP"], QP_Level_InterP, 28); - read(fs["QP_Level_InterB"], QP_Level_InterB, 31); - read(fs["DeblockMode" ], DeblockMode, 1); - read(fs["ProfileLevel" ], ProfileLevel, 65357); - read(fs["ForceIntra" ], ForceIntra, 0); - read(fs["ForceIDR" ], ForceIDR, 0); - read(fs["ClearStat" ], ClearStat, 0); - read(fs["DIMode" ], DIMode, 1); - read(fs["Presets" ], Presets, 2); - read(fs["DisableCabac" ], DisableCabac, 0); - read(fs["NaluFramingType"], NaluFramingType, 0); - read(fs["DisableSPSPPS" ], DisableSPSPPS, 0); -} - -void cv::cudacodec::EncoderParams::save(const String& configFile) const -{ - FileStorage fs(configFile, FileStorage::WRITE); - CV_Assert( fs.isOpened() ); - - write(fs, "P_Interval" , P_Interval); - write(fs, "IDR_Period" , IDR_Period); - write(fs, "DynamicGOP" , DynamicGOP); - write(fs, "RCType" , RCType); - write(fs, "AvgBitrate" , AvgBitrate); - write(fs, "PeakBitrate" , PeakBitrate); - write(fs, "QP_Level_Intra" , QP_Level_Intra); - write(fs, "QP_Level_InterP", QP_Level_InterP); - write(fs, "QP_Level_InterB", QP_Level_InterB); - write(fs, "DeblockMode" , DeblockMode); - write(fs, "ProfileLevel" , ProfileLevel); - write(fs, "ForceIntra" , ForceIntra); - write(fs, "ForceIDR" , ForceIDR); - write(fs, "ClearStat" , ClearStat); - write(fs, "DIMode" , DIMode); - write(fs, "Presets" , Presets); - write(fs, "DisableCabac" , DisableCabac); - write(fs, "NaluFramingType", NaluFramingType); - write(fs, "DisableSPSPPS" , DisableSPSPPS); -} +void VideoWriterImpl::write(const InputArray frame) { + CV_Assert(frame.channels() == nSrcChannels); + CopyToNvSurface(frame); + pEnc->EncodeFrame(vPacket); + encoderCallback->onEncoded(vPacket); +}; -/////////////////////////////////////////////////////////////////////////// -// createVideoWriter +EncoderParams VideoWriterImpl::getEncoderParams() const { + return encoderParams; +}; -Ptr cv::cudacodec::createVideoWriter(const String& fileName, Size frameSize, double fps, SurfaceFormat format) +Ptr createVideoWriter(const String& fileName, const Size frameSize, const Codec codec, const double fps, const ColorFormat colorFormat, + Ptr encoderCallback, const Stream& stream) { - Ptr encoderCallback(new EncoderCallBackFFMPEG(fileName, frameSize, fps)); - return createVideoWriter(encoderCallback, frameSize, fps, format); + encoderCallback = encoderCallback ? encoderCallback : new RawVideoWriter(fileName); + return makePtr(encoderCallback, frameSize, codec, fps, colorFormat, stream); } -Ptr cv::cudacodec::createVideoWriter(const String& fileName, Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format) +Ptr createVideoWriter(const String& fileName, const Size frameSize, const Codec codec, const double fps, const ColorFormat colorFormat, + const EncoderParams& params, Ptr encoderCallback, const Stream& stream) { - Ptr encoderCallback(new EncoderCallBackFFMPEG(fileName, frameSize, fps)); - return createVideoWriter(encoderCallback, frameSize, fps, params, format); + encoderCallback = encoderCallback ? encoderCallback : new RawVideoWriter(fileName); + return makePtr(encoderCallback, frameSize, codec, fps, colorFormat, params, stream); } -Ptr cv::cudacodec::createVideoWriter(const Ptr& encoderCallback, Size frameSize, double fps, SurfaceFormat format) -{ - return makePtr(encoderCallback, frameSize, fps, format); -} - -Ptr cv::cudacodec::createVideoWriter(const Ptr& encoderCallback, Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format) -{ - return makePtr(encoderCallback, frameSize, fps, params, format); -} +#endif // !defined HAVE_NVCUVENC -#endif // !defined HAVE_NVCUVENC || !defined _WIN32 || defined HAVE_FFMPEG_WRAPPER +}} diff --git a/modules/cudacodec/test/test_precomp.hpp b/modules/cudacodec/test/test_precomp.hpp index dd584825213..7d38b1142f0 100644 --- a/modules/cudacodec/test/test_precomp.hpp +++ b/modules/cudacodec/test/test_precomp.hpp @@ -47,6 +47,8 @@ #include "opencv2/ts/cuda_test.hpp" #include "opencv2/cudacodec.hpp" +#include "opencv2/cudawarping.hpp" +#include "opencv2/cudaarithm.hpp" #include "cvconfig.h" diff --git a/modules/cudacodec/test/test_video.cpp b/modules/cudacodec/test/test_video.cpp index e37833ef8bd..b9b4e9f25c6 100644 --- a/modules/cudacodec/test/test_video.cpp +++ b/modules/cudacodec/test/test_video.cpp @@ -54,6 +54,10 @@ PARAM_TEST_CASE(CheckExtraData, cv::cuda::DeviceInfo, check_extra_data_params_t) { }; +PARAM_TEST_CASE(Scaling, cv::cuda::DeviceInfo, std::string, Size2f, Rect2f, Rect2f) +{ +}; + PARAM_TEST_CASE(Video, cv::cuda::DeviceInfo, std::string) { }; @@ -139,8 +143,8 @@ CUDA_TEST_P(CheckExtraData, Reader) ASSERT_EQ(extraDataIdx, 1 ); ASSERT_TRUE(reader->grab()); cv::Mat extraData; - const bool newData = reader->retrieve(extraData, extraDataIdx); - ASSERT_TRUE(newData && sz || !newData && !sz); + const bool newData = reader->retrieve(extraData, static_cast(extraDataIdx)); + ASSERT_TRUE((newData && sz) || (!newData && !sz)); ASSERT_EQ(extraData.total(), sz); } @@ -166,17 +170,59 @@ CUDA_TEST_P(CheckKeyFrame, Reader) ASSERT_TRUE(reader->grab()); double N = -1; ASSERT_TRUE(reader->get(cv::cudacodec::VideoReaderProps::PROP_NUMBER_OF_RAW_PACKAGES_SINCE_LAST_GRAB,N)); - for (int i = rawIdxBase; i < N + rawIdxBase; i++) { + for (int i = static_cast(rawIdxBase); i < static_cast(N + rawIdxBase); i++) { nPackages++; double containsKeyFrame = i; ASSERT_TRUE(reader->get(cv::cudacodec::VideoReaderProps::PROP_LRF_HAS_KEY_FRAME, containsKeyFrame)); - ASSERT_TRUE(nPackages == 1 && containsKeyFrame || nPackages == 2 && !containsKeyFrame) << "nPackage: " << i; + ASSERT_TRUE((nPackages == 1 && containsKeyFrame) || (nPackages == 2 && !containsKeyFrame)) << "nPackage: " << i; if (nPackages >= maxNPackagesToCheck) break; } } } +CUDA_TEST_P(Scaling, Reader) +{ + cv::cuda::setDevice(GET_PARAM(0).deviceID()); + std::string inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "../" + GET_PARAM(1); + const Size2f targetSzIn = GET_PARAM(2); + const Rect2f srcRoiIn = GET_PARAM(3); + const Rect2f targetRoiIn = GET_PARAM(4); + + GpuMat frameOr; + { + cv::Ptr readerGs = cv::cudacodec::createVideoReader(inputFile); + ASSERT_TRUE(readerGs->set(cudacodec::ColorFormat::GRAY)); + ASSERT_TRUE(readerGs->nextFrame(frameOr)); + } + + cudacodec::VideoReaderInitParams params; + params.targetSz = Size(static_cast(frameOr.cols * targetSzIn.width), static_cast(frameOr.rows * targetSzIn.height)); + params.srcRoi = Rect(static_cast(frameOr.cols * srcRoiIn.x), static_cast(frameOr.rows * srcRoiIn.y), static_cast(frameOr.cols * srcRoiIn.width), + static_cast(frameOr.rows * srcRoiIn.height)); + params.targetRoi = Rect(static_cast(params.targetSz.width * targetRoiIn.x), static_cast(params.targetSz.height * targetRoiIn.y), + static_cast(params.targetSz.width * targetRoiIn.width), static_cast(params.targetSz.height * targetRoiIn.height)); + cv::Ptr reader = cv::cudacodec::createVideoReader(inputFile, {}, params); + ASSERT_TRUE(reader->set(cudacodec::ColorFormat::GRAY)); + GpuMat frame; + ASSERT_TRUE(reader->nextFrame(frame)); + const cudacodec::FormatInfo format = reader->format(); + Size targetSzOut; + targetSzOut.width = params.targetSz.width - params.targetSz.width % 2; targetSzOut.height = params.targetSz.height - params.targetSz.height % 2; + Rect srcRoiOut, targetRoiOut; + srcRoiOut.x = params.srcRoi.x - params.srcRoi.x % 4; srcRoiOut.width = params.srcRoi.width - params.srcRoi.width % 4; + srcRoiOut.y = params.srcRoi.y - params.srcRoi.y % 2; srcRoiOut.height = params.srcRoi.height - params.srcRoi.height % 2; + targetRoiOut.x = params.targetRoi.x - params.targetRoi.x % 4; targetRoiOut.width = params.targetRoi.width - params.targetRoi.width % 4; + targetRoiOut.y = params.targetRoi.y - params.targetRoi.y % 2; targetRoiOut.height = params.targetRoi.height - params.targetRoi.height % 2; + ASSERT_TRUE(format.valid && format.targetSz == targetSzOut && format.srcRoi == srcRoiOut && format.targetRoi == targetRoiOut); + ASSERT_TRUE(frame.size() == targetSzOut); + GpuMat frameGs; + cv::cuda::resize(frameOr(srcRoiOut), frameGs, targetRoiOut.size(), 0, 0, INTER_AREA); + // assert on mean absolute error due to different resize algorithms + const double mae = cv::cuda::norm(frameGs, frame(targetRoiOut), NORM_L1)/frameGs.size().area(); + ASSERT_LT(mae, 2.35); +} + CUDA_TEST_P(Video, Reader) { cv::cuda::setDevice(GET_PARAM(0).deviceID()); @@ -185,28 +231,34 @@ CUDA_TEST_P(Video, Reader) if (GET_PARAM(1) == "cv/video/768x576.avi" && !videoio_registry::hasBackend(CAP_FFMPEG)) throw SkipTestException("FFmpeg backend not found"); +#ifdef _WIN32 // handle old FFmpeg backend + if (GET_PARAM(1) == "/cv/tracking/faceocc2/data/faceocc2.webm") + throw SkipTestException("Feature not yet supported by Windows FFmpeg shared library!"); +#endif + const std::vector> formatsToChannels = { {cudacodec::ColorFormat::GRAY,1}, {cudacodec::ColorFormat::BGR,3}, {cudacodec::ColorFormat::BGRA,4}, - {cudacodec::ColorFormat::YUV,1} + {cudacodec::ColorFormat::NV_NV12,1} }; std::string inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "../" + GET_PARAM(1); cv::Ptr reader = cv::cudacodec::createVideoReader(inputFile); + ASSERT_FALSE(reader->set(cudacodec::ColorFormat::RGB)); cv::cudacodec::FormatInfo fmt = reader->format(); cv::cuda::GpuMat frame; - for (int i = 0; i < 100; i++) + for (int i = 0; i < 10; i++) { // request a different colour format for each frame const std::pair< cudacodec::ColorFormat, int>& formatToChannels = formatsToChannels[i % formatsToChannels.size()]; - reader->set(formatToChannels.first); + ASSERT_TRUE(reader->set(formatToChannels.first)); double colorFormat; ASSERT_TRUE(reader->get(cudacodec::VideoReaderProps::PROP_COLOR_FORMAT, colorFormat) && static_cast(colorFormat) == formatToChannels.first); ASSERT_TRUE(reader->nextFrame(frame)); if(!fmt.valid) fmt = reader->format(); - const int height = formatToChannels.first == cudacodec::ColorFormat::YUV ? 1.5 * fmt.height : fmt.height; + const int height = formatToChannels.first == cudacodec::ColorFormat::NV_NV12 ? static_cast(1.5 * fmt.height) : fmt.height; ASSERT_TRUE(frame.cols == fmt.width && frame.rows == height); ASSERT_FALSE(frame.empty()); ASSERT_TRUE(frame.channels() == formatToChannels.second); @@ -241,9 +293,9 @@ CUDA_TEST_P(VideoReadRaw, Reader) double N = -1; ASSERT_TRUE(reader->get(cv::cudacodec::VideoReaderProps::PROP_NUMBER_OF_RAW_PACKAGES_SINCE_LAST_GRAB,N)); ASSERT_TRUE(N >= 0) << N << " < 0"; - for (int i = rawIdxBase; i <= N + rawIdxBase; i++) { + for (int j = static_cast(rawIdxBase); j <= static_cast(N + rawIdxBase); j++) { Mat rawPackets; - reader->retrieve(rawPackets, i); + reader->retrieve(rawPackets, j); file.write((char*)rawPackets.data, rawPackets.total()); } } @@ -265,7 +317,7 @@ CUDA_TEST_P(VideoReadRaw, Reader) { ASSERT_TRUE(readerReference->nextFrame(reference)); ASSERT_TRUE(readerActual->grab()); - ASSERT_TRUE(readerActual->retrieve(actual, decodedFrameIdx)); + ASSERT_TRUE(readerActual->retrieve(actual, static_cast(decodedFrameIdx))); actual.download(actualHost); reference.download(referenceHost); ASSERT_TRUE(cvtest::norm(actualHost, referenceHost, NORM_INF) == 0); @@ -373,61 +425,249 @@ CUDA_TEST_P(CheckInitParams, Reader) #endif // HAVE_NVCUVID -#if defined(_WIN32) && defined(HAVE_NVCUVENC) -////////////////////////////////////////////////////// -// VideoWriter +#if defined(HAVE_NVCUVID) && defined(HAVE_NVCUVENC) +struct TransCode : testing::TestWithParam +{ + cv::cuda::DeviceInfo devInfo; + virtual void SetUp() + { + devInfo = GetParam(); + cv::cuda::setDevice(devInfo.deviceID()); + } +}; -CUDA_TEST_P(Video, Writer) + +CUDA_TEST_P(TransCode, H264ToH265) { - cv::cuda::setDevice(GET_PARAM(0).deviceID()); + const std::string inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "../highgui/video/big_buck_bunny.h264"; + constexpr cv::cudacodec::ColorFormat colorFormat = cv::cudacodec::ColorFormat::NV_NV12; + constexpr double fps = 25; + const cudacodec::Codec codec = cudacodec::Codec::HEVC; + const std::string ext = ".h265"; + const std::string outputFile = cv::tempfile(ext.c_str()); + constexpr int nFrames = 5; + Size frameSz; + { + cv::Ptr reader = cv::cudacodec::createVideoReader(inputFile); + cv::cudacodec::FormatInfo fmt = reader->format(); + reader->set(cudacodec::ColorFormat::NV_NV12); + cv::Ptr writer; + cv::cuda::GpuMat frame; + cv::cuda::Stream stream; + for (int i = 0; i < nFrames; ++i) { + ASSERT_TRUE(reader->nextFrame(frame, stream)); + if (!fmt.valid) { + fmt = reader->format(); + ASSERT_TRUE(fmt.valid); + } + ASSERT_FALSE(frame.empty()); + Mat tst; frame.download(tst); + if (writer.empty()) { + frameSz = Size(fmt.width, fmt.height); + writer = cv::cudacodec::createVideoWriter(outputFile, frameSz, codec, fps, colorFormat, 0, stream); + } + writer->write(frame); + } + } + + { + cv::VideoCapture cap(outputFile); + ASSERT_TRUE(cap.isOpened()); + const int width = static_cast(cap.get(CAP_PROP_FRAME_WIDTH)); + const int height = static_cast(cap.get(CAP_PROP_FRAME_HEIGHT)); + ASSERT_EQ(frameSz, Size(width, height)); + ASSERT_EQ(fps, cap.get(CAP_PROP_FPS)); + Mat frame; + for (int i = 0; i < nFrames; ++i) { + cap >> frame; + ASSERT_FALSE(frame.empty()); + } + } + ASSERT_EQ(0, remove(outputFile.c_str())); +} - const std::string inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "video/" + GET_PARAM(1); +INSTANTIATE_TEST_CASE_P(CUDA_Codec, TransCode, ALL_DEVICES); +#endif - std::string outputFile = cv::tempfile(".avi"); - const double FPS = 25.0; +#if defined(HAVE_NVCUVENC) - cv::VideoCapture reader(inputFile); - ASSERT_TRUE(reader.isOpened()); +////////////////////////////////////////////////////// +// VideoWriter - cv::Ptr d_writer; +//========================================================================== - cv::Mat frame; - cv::cuda::GpuMat d_frame; +void CvtColor(const Mat& in, Mat& out, const cudacodec::ColorFormat surfaceFormatCv) { + switch (surfaceFormatCv) { + case(cudacodec::ColorFormat::RGB): + return cv::cvtColor(in, out, COLOR_BGR2RGB); + case(cudacodec::ColorFormat::BGRA): + return cv::cvtColor(in, out, COLOR_BGR2BGRA); + case(cudacodec::ColorFormat::RGBA): + return cv::cvtColor(in, out, COLOR_BGR2RGBA); + case(cudacodec::ColorFormat::GRAY): + return cv::cvtColor(in, out, COLOR_BGR2GRAY); + default: + in.copyTo(out); + } +} - for (int i = 0; i < 10; ++i) +PARAM_TEST_CASE(Write, cv::cuda::DeviceInfo, bool, cv::cudacodec::Codec, double, cv::cudacodec::ColorFormat) +{ +}; + +CUDA_TEST_P(Write, Writer) +{ + cv::cuda::setDevice(GET_PARAM(0).deviceID()); + const std::string inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "../highgui/video/big_buck_bunny.mp4"; + const bool deviceSrc = GET_PARAM(1); + const cudacodec::Codec codec = GET_PARAM(2); + const double fps = GET_PARAM(3); + const cv::cudacodec::ColorFormat colorFormat = GET_PARAM(4); + const std::string ext = codec == cudacodec::Codec::H264 ? ".h264" : ".hevc"; + const std::string outputFile = cv::tempfile(ext.c_str()); + constexpr int nFrames = 5; + Size frameSz; { - reader >> frame; - ASSERT_FALSE(frame.empty()); + cv::VideoCapture cap(inputFile); + ASSERT_TRUE(cap.isOpened()); + cv::Ptr writer; + cv::Mat frame, frameNewSf; + cv::cuda::GpuMat dFrame; + cv::cuda::Stream stream; + for (int i = 0; i < nFrames; ++i) { + cap >> frame; + ASSERT_FALSE(frame.empty()); + if (writer.empty()) { + frameSz = frame.size(); + writer = cv::cudacodec::createVideoWriter(outputFile, frameSz, codec, fps, colorFormat, 0, stream); + } + CvtColor(frame, frameNewSf, colorFormat); + if (deviceSrc) { + dFrame.upload(frameNewSf); + writer->write(dFrame); + } + else + writer->write(frameNewSf); + } + } - d_frame.upload(frame); + { + cv::VideoCapture cap(outputFile); + ASSERT_TRUE(cap.isOpened()); + const int width = static_cast(cap.get(CAP_PROP_FRAME_WIDTH)); + const int height = static_cast(cap.get(CAP_PROP_FRAME_HEIGHT)); + ASSERT_EQ(frameSz, Size(width, height)); + ASSERT_TRUE(abs(fps - cap.get(CAP_PROP_FPS)) < 0.5); + Mat frame; + for (int i = 0; i < nFrames; ++i) { + cap >> frame; + ASSERT_FALSE(frame.empty()); + } + } + ASSERT_EQ(0, remove(outputFile.c_str())); +} - if (d_writer.empty()) - d_writer = cv::cudacodec::createVideoWriter(outputFile, frame.size(), FPS); +#define DEVICE_SRC true, false +#define FPS 10, 29.7 +#define CODEC cv::cudacodec::Codec::H264, cv::cudacodec::Codec::HEVC +#define COLOR_FORMAT cv::cudacodec::ColorFormat::BGR, cv::cudacodec::ColorFormat::RGB, cv::cudacodec::ColorFormat::BGRA, \ +cv::cudacodec::ColorFormat::RGBA, cv::cudacodec::ColorFormat::GRAY +INSTANTIATE_TEST_CASE_P(CUDA_Codec, Write, testing::Combine(ALL_DEVICES, testing::Values(DEVICE_SRC), testing::Values(CODEC), testing::Values(FPS), + testing::Values(COLOR_FORMAT))); - d_writer->write(d_frame); + +struct EncoderParams : testing::TestWithParam +{ + cv::cuda::DeviceInfo devInfo; + cv::cudacodec::EncoderParams params; + virtual void SetUp() + { + devInfo = GetParam(); + cv::cuda::setDevice(devInfo.deviceID()); + // Fixed params for CBR test + params.nvPreset = cv::cudacodec::EncodePreset::ENC_PRESET_P7; + params.tuningInfo = cv::cudacodec::EncodeTuningInfo::ENC_TUNING_INFO_HIGH_QUALITY; + params.encodingProfile = cv::cudacodec::EncodeProfile::ENC_H264_PROFILE_MAIN; + params.rateControlMode = cv::cudacodec::EncodeParamsRcMode::ENC_PARAMS_RC_CBR; + params.multiPassEncoding = cv::cudacodec::EncodeMultiPass::ENC_TWO_PASS_FULL_RESOLUTION; + params.averageBitRate = 1000000; + params.maxBitRate = 0; + params.targetQuality = 0; + params.gopLength = 5; } +}; - reader.release(); - d_writer.release(); - reader.open(outputFile); - ASSERT_TRUE(reader.isOpened()); +CUDA_TEST_P(EncoderParams, Writer) +{ + const std::string inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "../highgui/video/big_buck_bunny.mp4"; + constexpr double fps = 25.0; + constexpr cudacodec::Codec codec = cudacodec::Codec::H264; + const std::string ext = ".h264"; + const std::string outputFile = cv::tempfile(ext.c_str()); + Size frameSz; + constexpr int nFrames = 5; + { + cv::VideoCapture reader(inputFile); + ASSERT_TRUE(reader.isOpened()); + const cv::cudacodec::ColorFormat colorFormat = cv::cudacodec::ColorFormat::BGR; + cv::Ptr writer; + cv::Mat frame; + cv::cuda::GpuMat dFrame; + cv::cuda::Stream stream; + for (int i = 0; i < nFrames; ++i) { + reader >> frame; + ASSERT_FALSE(frame.empty()); + dFrame.upload(frame); + if (writer.empty()) { + frameSz = frame.size(); + writer = cv::cudacodec::createVideoWriter(outputFile, frameSz, codec, fps, colorFormat, params, 0, stream); + cv::cudacodec::EncoderParams paramsOut = writer->getEncoderParams(); + ASSERT_EQ(params, paramsOut); + } + writer->write(dFrame); + } + } - for (int i = 0; i < 5; ++i) { - reader >> frame; - ASSERT_FALSE(frame.empty()); + cv::VideoCapture cap(outputFile); + ASSERT_TRUE(cap.isOpened()); + const int width = static_cast(cap.get(CAP_PROP_FRAME_WIDTH)); + const int height = static_cast(cap.get(CAP_PROP_FRAME_HEIGHT)); + ASSERT_EQ(frameSz, Size(width, height)); + ASSERT_EQ(fps, cap.get(CAP_PROP_FPS)); + const bool checkGop = videoio_registry::hasBackend(CAP_FFMPEG); + Mat frame; + for (int i = 0; i < nFrames; ++i) { + cap >> frame; + ASSERT_FALSE(frame.empty()); + if (checkGop && (cap.get(CAP_PROP_FRAME_TYPE) == 73)) { + ASSERT_TRUE(i % params.gopLength == 0); + } + } } + ASSERT_EQ(0, remove(outputFile.c_str())); } -#endif // _WIN32, HAVE_NVCUVENC +INSTANTIATE_TEST_CASE_P(CUDA_Codec, EncoderParams, ALL_DEVICES); + +#endif // HAVE_NVCUVENC INSTANTIATE_TEST_CASE_P(CUDA_Codec, CheckSet, testing::Combine( ALL_DEVICES, testing::Values("highgui/video/big_buck_bunny.mp4"))); +#define VIDEO_SRC_SCALING "highgui/video/big_buck_bunny.mp4" +#define TARGET_SZ Size2f(1,1), Size2f(0.8f,0.9f), Size2f(2.3f,1.8f) +#define SRC_ROI Rect2f(0,0,1,1), Rect2f(0.25f,0.25f,0.5f,0.5f) +#define TARGET_ROI Rect2f(0,0,1,1), Rect2f(0.2f,0.3f,0.6f,0.7f) +INSTANTIATE_TEST_CASE_P(CUDA_Codec, Scaling, testing::Combine( + ALL_DEVICES, testing::Values(VIDEO_SRC_SCALING), testing::Values(TARGET_SZ), testing::Values(SRC_ROI), testing::Values(TARGET_ROI))); + #define VIDEO_SRC_R "highgui/video/big_buck_bunny.mp4", "cv/video/768x576.avi", "cv/video/1920x1080.avi", "highgui/video/big_buck_bunny.avi", \ - "highgui/video/big_buck_bunny.h264", "highgui/video/big_buck_bunny.h265", "highgui/video/big_buck_bunny.mpg" + "highgui/video/big_buck_bunny.h264", "highgui/video/big_buck_bunny.h265", "highgui/video/big_buck_bunny.mpg", \ + "highgui/video/sample_322x242_15frames.yuv420p.libvpx-vp9.mp4", "highgui/video/sample_322x242_15frames.yuv420p.libaom-av1.mp4", \ + "cv/tracking/faceocc2/data/faceocc2.webm" INSTANTIATE_TEST_CASE_P(CUDA_Codec, Video, testing::Combine( ALL_DEVICES, testing::Values(VIDEO_SRC_R))); diff --git a/modules/cudaimgproc/src/cuda/canny.cu b/modules/cudaimgproc/src/cuda/canny.cu index 99a4f72a8fe..46b9624fb68 100644 --- a/modules/cudaimgproc/src/cuda/canny.cu +++ b/modules/cudaimgproc/src/cuda/canny.cu @@ -48,6 +48,7 @@ #include "opencv2/core/cuda/functional.hpp" #include "opencv2/core/cuda/utility.hpp" #include "opencv2/core/cuda.hpp" +#include using namespace cv::cuda; using namespace cv::cuda::device; @@ -90,47 +91,8 @@ namespace cv { namespace cuda { namespace device namespace canny { - struct SrcTex - { - virtual ~SrcTex() {} - - __host__ SrcTex(int _xoff, int _yoff) : xoff(_xoff), yoff(_yoff) {} - - __device__ __forceinline__ virtual int operator ()(int y, int x) const = 0; - - int xoff; - int yoff; - }; - - texture tex_src(false, cudaFilterModePoint, cudaAddressModeClamp); - struct SrcTexRef : SrcTex - { - __host__ SrcTexRef(int _xoff, int _yoff) : SrcTex(_xoff, _yoff) {} - - __device__ __forceinline__ int operator ()(int y, int x) const override - { - return tex2D(tex_src, x + xoff, y + yoff); - } - }; - - struct SrcTexObj : SrcTex - { - __host__ SrcTexObj(int _xoff, int _yoff, cudaTextureObject_t _tex_src_object) : SrcTex(_xoff, _yoff), tex_src_object(_tex_src_object) { } - - __device__ __forceinline__ int operator ()(int y, int x) const override - { - return tex2D(tex_src_object, x + xoff, y + yoff); - } - - cudaTextureObject_t tex_src_object; - }; - - template < - class T, - class Norm, - typename = typename std::enable_if::value>::type - > - __global__ void calcMagnitudeKernel(const T src, PtrStepi dx, PtrStepi dy, PtrStepSzf mag, const Norm norm) + template + __global__ void calcMagnitudeKernel(cv::cudev::TextureOffPtr texSrc, PtrStepi dx, PtrStepi dy, PtrStepSzf mag, const Norm norm) { const int x = blockIdx.x * blockDim.x + threadIdx.x; const int y = blockIdx.y * blockDim.y + threadIdx.y; @@ -138,8 +100,8 @@ namespace canny if (y >= mag.rows || x >= mag.cols) return; - int dxVal = (src(y - 1, x + 1) + 2 * src(y, x + 1) + src(y + 1, x + 1)) - (src(y - 1, x - 1) + 2 * src(y, x - 1) + src(y + 1, x - 1)); - int dyVal = (src(y + 1, x - 1) + 2 * src(y + 1, x) + src(y + 1, x + 1)) - (src(y - 1, x - 1) + 2 * src(y - 1, x) + src(y - 1, x + 1)); + int dxVal = (texSrc(y - 1, x + 1) + 2 * texSrc(y, x + 1) + texSrc(y + 1, x + 1)) - (texSrc(y - 1, x - 1) + 2 * texSrc(y, x - 1) + texSrc(y + 1, x - 1)); + int dyVal = (texSrc(y + 1, x - 1) + 2 * texSrc(y + 1, x) + texSrc(y + 1, x + 1)) - (texSrc(y - 1, x - 1) + 2 * texSrc(y - 1, x) + texSrc(y - 1, x + 1)); dx(y, x) = dxVal; dy(y, x) = dyVal; @@ -151,63 +113,20 @@ namespace canny { const dim3 block(16, 16); const dim3 grid(divUp(mag.cols, block.x), divUp(mag.rows, block.y)); - - bool cc30 = deviceSupports(FEATURE_SET_COMPUTE_30); - - if (cc30) + cv::cudev::TextureOff texSrc(srcWhole, yoff, xoff); + if (L2Grad) { - cudaTextureDesc texDesc; - memset(&texDesc, 0, sizeof(texDesc)); - texDesc.addressMode[0] = cudaAddressModeClamp; - texDesc.addressMode[1] = cudaAddressModeClamp; - texDesc.addressMode[2] = cudaAddressModeClamp; - - cudaTextureObject_t tex = 0; - createTextureObjectPitch2D(&tex, srcWhole, texDesc); - - SrcTexObj src(xoff, yoff, tex); - - if (L2Grad) - { - L2 norm; - calcMagnitudeKernel<<>>(src, dx, dy, mag, norm); - } - else - { - L1 norm; - calcMagnitudeKernel<<>>(src, dx, dy, mag, norm); - } - - cudaSafeCall( cudaGetLastError() ); - - if (stream == NULL) - cudaSafeCall( cudaDeviceSynchronize() ); - else - cudaSafeCall( cudaStreamSynchronize(stream) ); - - cudaSafeCall( cudaDestroyTextureObject(tex) ); + L2 norm; + calcMagnitudeKernel<<>>(texSrc, dx, dy, mag, norm); } else { - bindTexture(&tex_src, srcWhole); - SrcTexRef src(xoff, yoff); - - if (L2Grad) - { - L2 norm; - calcMagnitudeKernel<<>>(src, dx, dy, mag, norm); - } - else - { - L1 norm; - calcMagnitudeKernel<<>>(src, dx, dy, mag, norm); - } - - cudaSafeCall( cudaGetLastError() ); - - if (stream == NULL) - cudaSafeCall( cudaDeviceSynchronize() ); + L1 norm; + calcMagnitudeKernel<<>>(texSrc, dx, dy, mag, norm); } + + if (stream == NULL) + cudaSafeCall(cudaDeviceSynchronize()); } void calcMagnitude(PtrStepSzi dx, PtrStepSzi dy, PtrStepSzf mag, bool L2Grad, cudaStream_t stream) @@ -229,8 +148,7 @@ namespace canny namespace canny { - texture tex_mag(false, cudaFilterModePoint, cudaAddressModeClamp); - __global__ void calcMapKernel(const PtrStepSzi dx, const PtrStepi dy, PtrStepi map, const float low_thresh, const float high_thresh) + __global__ void calcMapKernel(cv::cudev::TexturePtr texMag, const PtrStepSzi dx, const PtrStepi dy, PtrStepi map, const float low_thresh, const float high_thresh) { const int CANNY_SHIFT = 15; const int TG22 = (int)(0.4142135623730950488016887242097*(1< tex2D(tex_mag, x - 1, y) && m >= tex2D(tex_mag, x + 1, y)) + if (m > texMag(y, x - 1) && m >= texMag(y, x + 1)) edge_type = 1 + (int)(m > high_thresh); } else if(dyVal > tg67x) { - if (m > tex2D(tex_mag, x, y - 1) && m >= tex2D(tex_mag, x, y + 1)) + if (m > texMag(y - 1, x) && m >= texMag(y + 1, x)) edge_type = 1 + (int)(m > high_thresh); } else { - if (m > tex2D(tex_mag, x - s, y - 1) && m >= tex2D(tex_mag, x + s, y + 1)) - edge_type = 1 + (int)(m > high_thresh); - } - } - - map(y, x) = edge_type; - } - - __global__ void calcMapKernel(const PtrStepSzi dx, const PtrStepi dy, PtrStepi map, const float low_thresh, const float high_thresh, cudaTextureObject_t tex_mag) - { - const int CANNY_SHIFT = 15; - const int TG22 = (int)(0.4142135623730950488016887242097*(1<= dx.cols - 1 || y == 0 || y >= dx.rows - 1) - return; - - int dxVal = dx(y, x); - int dyVal = dy(y, x); - - const int s = (dxVal ^ dyVal) < 0 ? -1 : 1; - const float m = tex2D(tex_mag, x, y); - - dxVal = ::abs(dxVal); - dyVal = ::abs(dyVal); - - // 0 - the pixel can not belong to an edge - // 1 - the pixel might belong to an edge - // 2 - the pixel does belong to an edge - int edge_type = 0; - - if (m > low_thresh) - { - const int tg22x = dxVal * TG22; - const int tg67x = tg22x + ((dxVal + dxVal) << CANNY_SHIFT); - - dyVal <<= CANNY_SHIFT; - - if (dyVal < tg22x) - { - if (m > tex2D(tex_mag, x - 1, y) && m >= tex2D(tex_mag, x + 1, y)) - edge_type = 1 + (int)(m > high_thresh); - } - else if(dyVal > tg67x) - { - if (m > tex2D(tex_mag, x, y - 1) && m >= tex2D(tex_mag, x, y + 1)) - edge_type = 1 + (int)(m > high_thresh); - } - else - { - if (m > tex2D(tex_mag, x - s, y - 1) && m >= tex2D(tex_mag, x + s, y + 1)) + if (m > texMag(y - 1, x - s) && m >= texMag(y + 1, x + s)) edge_type = 1 + (int)(m > high_thresh); } } @@ -338,47 +204,10 @@ namespace canny { const dim3 block(16, 16); const dim3 grid(divUp(dx.cols, block.x), divUp(dx.rows, block.y)); - - if (deviceSupports(FEATURE_SET_COMPUTE_30)) - { - // Use the texture object - cudaResourceDesc resDesc; - memset(&resDesc, 0, sizeof(resDesc)); - resDesc.resType = cudaResourceTypePitch2D; - resDesc.res.pitch2D.devPtr = mag.ptr(); - resDesc.res.pitch2D.height = mag.rows; - resDesc.res.pitch2D.width = mag.cols; - resDesc.res.pitch2D.pitchInBytes = mag.step; - resDesc.res.pitch2D.desc = cudaCreateChannelDesc(); - - cudaTextureDesc texDesc; - memset(&texDesc, 0, sizeof(texDesc)); - texDesc.addressMode[0] = cudaAddressModeClamp; - texDesc.addressMode[1] = cudaAddressModeClamp; - texDesc.addressMode[2] = cudaAddressModeClamp; - - cudaTextureObject_t tex=0; - cudaCreateTextureObject(&tex, &resDesc, &texDesc, NULL); - calcMapKernel<<>>(dx, dy, map, low_thresh, high_thresh, tex); - cudaSafeCall( cudaGetLastError() ); - - if (stream == NULL) - cudaSafeCall( cudaDeviceSynchronize() ); - else - cudaSafeCall( cudaStreamSynchronize(stream) ); - - cudaSafeCall( cudaDestroyTextureObject(tex) ); - } - else - { - // Use the texture reference - bindTexture(&tex_mag, mag); - calcMapKernel<<>>(dx, dy, map, low_thresh, high_thresh); - cudaSafeCall( cudaGetLastError() ); - - if (stream == NULL) - cudaSafeCall( cudaDeviceSynchronize() ); - } + cv::cudev::Texture texMag(mag); + calcMapKernel<<>>(texMag, dx, dy, map, low_thresh, high_thresh); + if (stream == NULL) + cudaSafeCall( cudaDeviceSynchronize() ); } } diff --git a/modules/cudaimgproc/src/cuda/corners.cu b/modules/cudaimgproc/src/cuda/corners.cu index 92a37e6fde1..2f3452648ca 100644 --- a/modules/cudaimgproc/src/cuda/corners.cu +++ b/modules/cudaimgproc/src/cuda/corners.cu @@ -47,6 +47,7 @@ #include "opencv2/core/cuda/vec_math.hpp" #include "opencv2/core/cuda/saturate_cast.hpp" #include "opencv2/core/cuda/border_interpolate.hpp" +#include #include "opencv2/opencv_modules.hpp" @@ -58,10 +59,7 @@ namespace cv { namespace cuda { namespace device { /////////////////////////////////////////// Corner Harris ///////////////////////////////////////////////// - texture harrisDxTex(0, cudaFilterModePoint, cudaAddressModeClamp); - texture harrisDyTex(0, cudaFilterModePoint, cudaAddressModeClamp); - - __global__ void cornerHarris_kernel(const int block_size, const float k, PtrStepSzf dst) + __global__ void cornerHarris_kernel(cv::cudev::TexturePtr texDx, cv::cudev::TexturePtr texDy, const int block_size, const float k, PtrStepSzf dst) { const int x = blockIdx.x * blockDim.x + threadIdx.x; const int y = blockIdx.y * blockDim.y + threadIdx.y; @@ -81,8 +79,8 @@ namespace cv { namespace cuda { namespace device { for (int j = jbegin; j < jend; ++j) { - float dx = tex2D(harrisDxTex, j, i); - float dy = tex2D(harrisDyTex, j, i); + float dx = texDx(i, j); + float dy = texDy(i, j); a += dx * dx; b += dx * dy; @@ -95,7 +93,7 @@ namespace cv { namespace cuda { namespace device } template - __global__ void cornerHarris_kernel(const int block_size, const float k, PtrStepSzf dst, const BR border_row, const BC border_col) + __global__ void cornerHarris_kernel(cv::cudev::TexturePtr texDx, cv::cudev::TexturePtr texDy, const int block_size, const float k, PtrStepSzf dst, const BR border_row, const BC border_col) { const int x = blockIdx.x * blockDim.x + threadIdx.x; const int y = blockIdx.y * blockDim.y + threadIdx.y; @@ -119,8 +117,8 @@ namespace cv { namespace cuda { namespace device { const int x = border_row.idx_col(j); - float dx = tex2D(harrisDxTex, x, y); - float dy = tex2D(harrisDyTex, x, y); + float dx = texDx(y, x); + float dy = texDy(y, x); a += dx * dx; b += dx * dy; @@ -136,22 +134,20 @@ namespace cv { namespace cuda { namespace device { dim3 block(32, 8); dim3 grid(divUp(Dx.cols, block.x), divUp(Dx.rows, block.y)); - - bindTexture(&harrisDxTex, Dx); - bindTexture(&harrisDyTex, Dy); - + cv::cudev::Texture texDx(Dx); + cv::cudev::Texture texDy(Dy); switch (border_type) { case BORDER_REFLECT101: - cornerHarris_kernel<<>>(block_size, k, dst, BrdRowReflect101(Dx.cols), BrdColReflect101(Dx.rows)); + cornerHarris_kernel<<>>(texDx, texDy, block_size, k, dst, BrdRowReflect101(Dx.cols), BrdColReflect101(Dx.rows)); break; case BORDER_REFLECT: - cornerHarris_kernel<<>>(block_size, k, dst, BrdRowReflect(Dx.cols), BrdColReflect(Dx.rows)); + cornerHarris_kernel<<>>(texDx, texDy, block_size, k, dst, BrdRowReflect(Dx.cols), BrdColReflect(Dx.rows)); break; case BORDER_REPLICATE: - cornerHarris_kernel<<>>(block_size, k, dst); + cornerHarris_kernel<<>>(texDx, texDy, block_size, k, dst); break; } @@ -163,10 +159,7 @@ namespace cv { namespace cuda { namespace device /////////////////////////////////////////// Corner Min Eigen Val ///////////////////////////////////////////////// - texture minEigenValDxTex(0, cudaFilterModePoint, cudaAddressModeClamp); - texture minEigenValDyTex(0, cudaFilterModePoint, cudaAddressModeClamp); - - __global__ void cornerMinEigenVal_kernel(const int block_size, PtrStepSzf dst) + __global__ void cornerMinEigenVal_kernel(cv::cudev::TexturePtr texMinEigenValDx, cv::cudev::TexturePtr texMinEigenValDy, const int block_size, PtrStepSzf dst) { const int x = blockIdx.x * blockDim.x + threadIdx.x; const int y = blockIdx.y * blockDim.y + threadIdx.y; @@ -186,8 +179,8 @@ namespace cv { namespace cuda { namespace device { for (int j = jbegin; j < jend; ++j) { - float dx = tex2D(minEigenValDxTex, j, i); - float dy = tex2D(minEigenValDyTex, j, i); + float dx = texMinEigenValDx(i, j); + float dy = texMinEigenValDy(i, j); a += dx * dx; b += dx * dy; @@ -204,7 +197,7 @@ namespace cv { namespace cuda { namespace device template - __global__ void cornerMinEigenVal_kernel(const int block_size, PtrStepSzf dst, const BR border_row, const BC border_col) + __global__ void cornerMinEigenVal_kernel(cv::cudev::TexturePtr texMinEigenValDx, cv::cudev::TexturePtr texMinEigenValDy, const int block_size, PtrStepSzf dst, const BR border_row, const BC border_col) { const int x = blockIdx.x * blockDim.x + threadIdx.x; const int y = blockIdx.y * blockDim.y + threadIdx.y; @@ -228,8 +221,8 @@ namespace cv { namespace cuda { namespace device { int x = border_row.idx_col(j); - float dx = tex2D(minEigenValDxTex, x, y); - float dy = tex2D(minEigenValDyTex, x, y); + float dx = texMinEigenValDx(y, x); + float dy = texMinEigenValDy(y, x); a += dx * dx; b += dx * dy; @@ -248,22 +241,20 @@ namespace cv { namespace cuda { namespace device { dim3 block(32, 8); dim3 grid(divUp(Dx.cols, block.x), divUp(Dx.rows, block.y)); - - bindTexture(&minEigenValDxTex, Dx); - bindTexture(&minEigenValDyTex, Dy); - + cv::cudev::Texture texMinEigenValDx(Dx); + cv::cudev::Texture texMinEigenValDy(Dy); switch (border_type) { case BORDER_REFLECT101: - cornerMinEigenVal_kernel<<>>(block_size, dst, BrdRowReflect101(Dx.cols), BrdColReflect101(Dx.rows)); + cornerMinEigenVal_kernel<<>>(texMinEigenValDx, texMinEigenValDy, block_size, dst, BrdRowReflect101(Dx.cols), BrdColReflect101(Dx.rows)); break; case BORDER_REFLECT: - cornerMinEigenVal_kernel<<>>(block_size, dst, BrdRowReflect(Dx.cols), BrdColReflect(Dx.rows)); + cornerMinEigenVal_kernel<<>>(texMinEigenValDx, texMinEigenValDy, block_size, dst, BrdRowReflect(Dx.cols), BrdColReflect(Dx.rows)); break; case BORDER_REPLICATE: - cornerMinEigenVal_kernel<<>>(block_size, dst); + cornerMinEigenVal_kernel<<>>(texMinEigenValDx, texMinEigenValDy, block_size, dst); break; } diff --git a/modules/cudaimgproc/src/cuda/debayer.cu b/modules/cudaimgproc/src/cuda/debayer.cu index 0da78139807..bfe4b6f5ea8 100644 --- a/modules/cudaimgproc/src/cuda/debayer.cu +++ b/modules/cudaimgproc/src/cuda/debayer.cu @@ -48,6 +48,7 @@ #include "opencv2/core/cuda/limits.hpp" #include "opencv2/core/cuda/color.hpp" #include "opencv2/core/cuda/saturate_cast.hpp" +#include "opencv2/cudev/ptr2d/texture.hpp" namespace cv { namespace cuda { namespace device { @@ -389,10 +390,8 @@ namespace cv { namespace cuda { namespace device // // ported to CUDA - texture sourceTex(false, cudaFilterModePoint, cudaAddressModeClamp); - - template - __global__ void MHCdemosaic(PtrStepSz dst, const int2 sourceOffset, const int2 firstRed) + template + __global__ void MHCdemosaic(PtrStepSz dst, Ptr2D src, const int2 firstRed) { const float kAx = -1.0f / 8.0f, kAy = -1.5f / 8.0f, kAz = 0.5f / 8.0f /*kAw = -1.0f / 8.0f*/; const float kBx = 2.0f / 8.0f, /*kBy = 0.0f / 8.0f,*/ /*kBz = 0.0f / 8.0f,*/ kBw = 4.0f / 8.0f ; @@ -408,8 +407,8 @@ namespace cv { namespace cuda { namespace device return; int2 center; - center.x = x + sourceOffset.x; - center.y = y + sourceOffset.y; + center.x = x; + center.y = y; int4 xCoord; xCoord.x = center.x - 2; @@ -423,25 +422,26 @@ namespace cv { namespace cuda { namespace device yCoord.z = center.y + 1; yCoord.w = center.y + 2; - float C = tex2D(sourceTex, center.x, center.y); // ( 0, 0) + float C = src(center.y, center.x); // ( 0, 0) float4 Dvec; - Dvec.x = tex2D(sourceTex, xCoord.y, yCoord.y); // (-1,-1) - Dvec.y = tex2D(sourceTex, xCoord.y, yCoord.z); // (-1, 1) - Dvec.z = tex2D(sourceTex, xCoord.z, yCoord.y); // ( 1,-1) - Dvec.w = tex2D(sourceTex, xCoord.z, yCoord.z); // ( 1, 1) + Dvec.x = src(yCoord.y, xCoord.y); // (-1,-1) + Dvec.y = src(yCoord.z, xCoord.y); // (-1, 1) + Dvec.z = src(yCoord.y, xCoord.z); // ( 1,-1) + Dvec.w = src(yCoord.z, xCoord.z); // ( 1, 1) + float4 value; - value.x = tex2D(sourceTex, center.x, yCoord.x); // ( 0,-2) A0 - value.y = tex2D(sourceTex, center.x, yCoord.y); // ( 0,-1) B0 - value.z = tex2D(sourceTex, xCoord.x, center.y); // (-2, 0) E0 - value.w = tex2D(sourceTex, xCoord.y, center.y); // (-1, 0) F0 + value.x = src(yCoord.x, center.x); // ( 0,-2) A0 + value.y = src(yCoord.y, center.x); // ( 0,-1) B0 + value.z = src(center.y, xCoord.x); // (-2, 0) E0 + value.w = src(center.y, xCoord.y); // (-1, 0) F0 // (A0 + A1), (B0 + B1), (E0 + E1), (F0 + F1) - value.x += tex2D(sourceTex, center.x, yCoord.w); // ( 0, 2) A1 - value.y += tex2D(sourceTex, center.x, yCoord.z); // ( 0, 1) B1 - value.z += tex2D(sourceTex, xCoord.w, center.y); // ( 2, 0) E1 - value.w += tex2D(sourceTex, xCoord.z, center.y); // ( 1, 0) F1 + value.x += src(yCoord.w, center.x); // ( 0, 2) A1 + value.y += src(yCoord.z, center.x); // ( 0, 1) B1 + value.z += src(center.y, xCoord.w); // ( 2, 0) E1 + value.w += src(center.y, xCoord.z); // ( 1, 0) F1 float4 PATTERN; PATTERN.x = kCx * C; @@ -527,9 +527,15 @@ namespace cv { namespace cuda { namespace device const dim3 block(32, 8); const dim3 grid(divUp(src.cols, block.x), divUp(src.rows, block.y)); - bindTexture(&sourceTex, src); + if (sourceOffset.x || sourceOffset.y) { + cv::cudev::TextureOff texSrc(src, sourceOffset.y, sourceOffset.x); + MHCdemosaic><<>>((PtrStepSz)dst, texSrc, firstRed); + } + else { + cv::cudev::Texture texSrc(src); + MHCdemosaic><<>>((PtrStepSz)dst, texSrc, firstRed); + } - MHCdemosaic<<>>((PtrStepSz)dst, sourceOffset, firstRed); cudaSafeCall( cudaGetLastError() ); if (stream == 0) diff --git a/modules/cudaimgproc/src/cuda/gftt.cu b/modules/cudaimgproc/src/cuda/gftt.cu index b5655611005..81785319902 100644 --- a/modules/cudaimgproc/src/cuda/gftt.cu +++ b/modules/cudaimgproc/src/cuda/gftt.cu @@ -45,36 +45,36 @@ #include #include -#include "opencv2/core/cuda/common.hpp" #include "opencv2/core/cuda/utility.hpp" +#include #include namespace cv { namespace cuda { namespace device { namespace gfft { - template __global__ void findCorners(float threshold, const Mask mask, float2* corners, int max_count, int rows, int cols, cudaTextureObject_t eigTex, int *g_counter) + template __global__ void findCorners(cv::cudev::TexturePtr tex, float threshold, const Mask mask, float2* corners, int max_count, int rows, int cols, int *g_counter) { const int j = blockIdx.x * blockDim.x + threadIdx.x; const int i = blockIdx.y * blockDim.y + threadIdx.y; if (i > 0 && i < rows - 1 && j > 0 && j < cols - 1 && mask(i, j)) { - float val = tex2D(eigTex, j, i); + float val = tex(i, j); if (val > threshold) { float maxVal = val; - maxVal = ::fmax(tex2D(eigTex, j - 1, i - 1), maxVal); - maxVal = ::fmax(tex2D(eigTex, j , i - 1), maxVal); - maxVal = ::fmax(tex2D(eigTex, j + 1, i - 1), maxVal); + maxVal = ::fmax(tex(i - 1, j - 1), maxVal); + maxVal = ::fmax(tex(i - 1, j), maxVal); + maxVal = ::fmax(tex(i - 1, j + 1), maxVal); - maxVal = ::fmax(tex2D(eigTex, j - 1, i), maxVal); - maxVal = ::fmax(tex2D(eigTex, j + 1, i), maxVal); + maxVal = ::fmax(tex(i, j - 1), maxVal); + maxVal = ::fmax(tex(i, j + 1), maxVal); - maxVal = ::fmax(tex2D(eigTex, j - 1, i + 1), maxVal); - maxVal = ::fmax(tex2D(eigTex, j , i + 1), maxVal); - maxVal = ::fmax(tex2D(eigTex, j + 1, i + 1), maxVal); + maxVal = ::fmax(tex(i + 1, j - 1), maxVal); + maxVal = ::fmax(tex(i + 1, j), maxVal); + maxVal = ::fmax(tex(i + 1, j + 1), maxVal); if (val == maxVal) { @@ -87,17 +87,18 @@ namespace cv { namespace cuda { namespace device } } - int findCorners_gpu(const cudaTextureObject_t &eigTex, const int &rows, const int &cols, float threshold, PtrStepSzb mask, float2* corners, int max_count, int* counterPtr, cudaStream_t stream) + int findCorners_gpu(const PtrStepSzf eig, float threshold, PtrStepSzb mask, float2* corners, int max_count, int* counterPtr, cudaStream_t stream) { cudaSafeCall( cudaMemsetAsync(counterPtr, 0, sizeof(int), stream) ); + cv::cudev::Texture tex(eig); dim3 block(16, 16); - dim3 grid(divUp(cols, block.x), divUp(rows, block.y)); + dim3 grid(divUp(eig.cols, block.x), divUp(eig.rows, block.y)); if (mask.data) - findCorners<<>>(threshold, SingleMask(mask), corners, max_count, rows, cols, eigTex, counterPtr); + findCorners<<>>(tex, threshold, SingleMask(mask), corners, max_count, eig.rows, eig.cols, counterPtr); else - findCorners<<>>(threshold, WithOutMask(), corners, max_count, rows, cols, eigTex, counterPtr); + findCorners<<>>(tex, threshold, WithOutMask(), corners, max_count, eig.rows, eig.cols, counterPtr); cudaSafeCall( cudaGetLastError() ); @@ -113,27 +114,24 @@ namespace cv { namespace cuda { namespace device class EigGreater { public: - EigGreater(const cudaTextureObject_t &eigTex_) : eigTex(eigTex_) - { - } - __device__ __forceinline__ bool operator()(float2 a, float2 b) const - { - return tex2D(eigTex, a.x, a.y) > tex2D(eigTex, b.x, b.y); + EigGreater(cv::cudev::TexturePtr tex_) : tex(tex_) {} + __device__ __forceinline__ bool operator()(float2 a, float2 b) const{ + return tex(a.y, a.x) > tex(b.y, b.x); } - - cudaTextureObject_t eigTex; + cv::cudev::TexturePtr tex; }; - void sortCorners_gpu(const cudaTextureObject_t &eigTex, float2* corners, int count, cudaStream_t stream) + void sortCorners_gpu(const PtrStepSzf eig, float2* corners, int count, cudaStream_t stream) { + cv::cudev::Texture tex(eig); thrust::device_ptr ptr(corners); #if THRUST_VERSION >= 100802 if (stream) - thrust::sort(thrust::cuda::par(ThrustAllocator::getAllocator()).on(stream), ptr, ptr + count, EigGreater(eigTex)); + thrust::sort(thrust::cuda::par(ThrustAllocator::getAllocator()).on(stream), ptr, ptr + count, EigGreater(tex)); else - thrust::sort(thrust::cuda::par(ThrustAllocator::getAllocator()), ptr, ptr + count, EigGreater(eigTex)); + thrust::sort(thrust::cuda::par(ThrustAllocator::getAllocator()), ptr, ptr + count, EigGreater(tex)); #else - thrust::sort(ptr, ptr + count, EigGreater(eigTex)); + thrust::sort(ptr, ptr + count, EigGreater(tex)); #endif } } // namespace optical_flow diff --git a/modules/cudaimgproc/src/cuda/hough_segments.cu b/modules/cudaimgproc/src/cuda/hough_segments.cu index 59eb78f6996..3f4c3aff870 100644 --- a/modules/cudaimgproc/src/cuda/hough_segments.cu +++ b/modules/cudaimgproc/src/cuda/hough_segments.cu @@ -50,7 +50,8 @@ namespace cv { namespace cuda { namespace device { namespace hough_segments { - __global__ void houghLinesProbabilistic(cv::cudev::Texture src, const PtrStepSzi accum, + template + __global__ void houghLinesProbabilistic(Ptr2D src, const PtrStepSzi accum, int4* out, const int maxSize, const float rho, const float theta, const int lineGap, const int lineLength, @@ -219,15 +220,18 @@ namespace cv { namespace cuda { namespace device const dim3 block(32, 8); const dim3 grid(divUp(accum.cols - 2, block.x), divUp(accum.rows - 2, block.y)); - cv::cudev::GpuMat_ src_(mask); - cv::cudev::Texture tex(src_, false, cudaFilterModePoint, cudaAddressModeClamp); - - houghLinesProbabilistic<<>>(tex, accum, - out, maxSize, - rho, theta, - lineGap, lineLength, - mask.rows, mask.cols, - counterPtr); + Size wholeSize; + Point ofs; + mask.locateROI(wholeSize, ofs); + if (ofs.x || ofs.y) { + cv::cudev::TextureOff texMask(wholeSize.height, wholeSize.width, mask.datastart, mask.step, ofs.y, ofs.x); + houghLinesProbabilistic><<>>(texMask, accum, out, maxSize, rho, theta, lineGap, lineLength, mask.rows, mask.cols, counterPtr); + } + else { + cv::cudev::Texture texMask(mask); + houghLinesProbabilistic><<>>(texMask, accum, out, maxSize, rho, theta, lineGap, lineLength, mask.rows, mask.cols, counterPtr); + } + cudaSafeCall( cudaGetLastError() ); int totalCount; @@ -236,7 +240,6 @@ namespace cv { namespace cuda { namespace device cudaSafeCall( cudaStreamSynchronize(stream) ); totalCount = ::min(totalCount, maxSize); - return totalCount; } } diff --git a/modules/cudaimgproc/src/cuda/mean_shift.cu b/modules/cudaimgproc/src/cuda/mean_shift.cu index 3b3b93f94e4..ef7497be5c8 100644 --- a/modules/cudaimgproc/src/cuda/mean_shift.cu +++ b/modules/cudaimgproc/src/cuda/mean_shift.cu @@ -47,19 +47,16 @@ #include "opencv2/core/cuda/vec_math.hpp" #include "opencv2/core/cuda/saturate_cast.hpp" #include "opencv2/core/cuda/border_interpolate.hpp" +#include namespace cv { namespace cuda { namespace device { namespace imgproc { - texture tex_meanshift; - - __device__ short2 do_mean_shift(int x0, int y0, unsigned char* out, - size_t out_step, int cols, int rows, - int sp, int sr, int maxIter, float eps) + __device__ short2 do_mean_shift(cv::cudev::TexturePtr tex, int x0, int y0, unsigned char* out,size_t out_step, int cols, int rows, int sp, int sr, int maxIter, float eps) { int isr2 = sr*sr; - uchar4 c = tex2D(tex_meanshift, x0, y0 ); + uchar4 c = tex(y0, x0); // iterate meanshift procedure for( int iter = 0; iter < maxIter; iter++ ) @@ -79,7 +76,7 @@ namespace cv { namespace cuda { namespace device int rowCount = 0; for( int x = minx; x <= maxx; x++ ) { - uchar4 t = tex2D( tex_meanshift, x, y ); + uchar4 t = tex(y, x); int norm2 = (t.x - c.x) * (t.x - c.x) + (t.y - c.y) * (t.y - c.y) + (t.z - c.z) * (t.z - c.z); if( norm2 <= isr2 ) @@ -119,13 +116,13 @@ namespace cv { namespace cuda { namespace device return make_short2((short)x0, (short)y0); } - __global__ void meanshift_kernel(unsigned char* out, size_t out_step, int cols, int rows, int sp, int sr, int maxIter, float eps ) + __global__ void meanshift_kernel(cv::cudev::TexturePtr tex, unsigned char* out, size_t out_step, int cols, int rows, int sp, int sr, int maxIter, float eps ) { int x0 = blockIdx.x * blockDim.x + threadIdx.x; int y0 = blockIdx.y * blockDim.y + threadIdx.y; if( x0 < cols && y0 < rows ) - do_mean_shift(x0, y0, out, out_step, cols, rows, sp, sr, maxIter, eps); + do_mean_shift(tex, x0, y0, out, out_step, cols, rows, sp, sr, maxIter, eps); } void meanShiftFiltering_gpu(const PtrStepSzb& src, PtrStepSzb dst, int sp, int sr, int maxIter, float eps, cudaStream_t stream) @@ -134,21 +131,15 @@ namespace cv { namespace cuda { namespace device dim3 threads(32, 8, 1); grid.x = divUp(src.cols, threads.x); grid.y = divUp(src.rows, threads.y); - - cudaChannelFormatDesc desc = cudaCreateChannelDesc(); - cudaSafeCall( cudaBindTexture2D( 0, tex_meanshift, src.data, desc, src.cols, src.rows, src.step ) ); - - meanshift_kernel<<< grid, threads, 0, stream >>>( dst.data, dst.step, dst.cols, dst.rows, sp, sr, maxIter, eps ); + cv::cudev::Texture tex(src.rows, src.cols, (uchar4*)src.data, src.step); + meanshift_kernel<<< grid, threads, 0, stream >>>( tex, dst.data, dst.step, dst.cols, dst.rows, sp, sr, maxIter, eps ); cudaSafeCall( cudaGetLastError() ); - if (stream == 0) cudaSafeCall( cudaDeviceSynchronize() ); } - __global__ void meanshiftproc_kernel(unsigned char* outr, size_t outrstep, - unsigned char* outsp, size_t outspstep, - int cols, int rows, - int sp, int sr, int maxIter, float eps) + __global__ void meanshiftproc_kernel(cv::cudev::TexturePtr tex, unsigned char* outr, size_t outrstep, unsigned char* outsp, size_t outspstep, + int cols, int rows,int sp, int sr, int maxIter, float eps) { int x0 = blockIdx.x * blockDim.x + threadIdx.x; int y0 = blockIdx.y * blockDim.y + threadIdx.y; @@ -156,7 +147,7 @@ namespace cv { namespace cuda { namespace device if( x0 < cols && y0 < rows ) { int basesp = (blockIdx.y * blockDim.y + threadIdx.y) * outspstep + (blockIdx.x * blockDim.x + threadIdx.x) * 2 * sizeof(short); - *(short2*)(outsp + basesp) = do_mean_shift(x0, y0, outr, outrstep, cols, rows, sp, sr, maxIter, eps); + *(short2*)(outsp + basesp) = do_mean_shift(tex, x0, y0, outr, outrstep, cols, rows, sp, sr, maxIter, eps); } } @@ -166,13 +157,9 @@ namespace cv { namespace cuda { namespace device dim3 threads(32, 8, 1); grid.x = divUp(src.cols, threads.x); grid.y = divUp(src.rows, threads.y); - - cudaChannelFormatDesc desc = cudaCreateChannelDesc(); - cudaSafeCall( cudaBindTexture2D( 0, tex_meanshift, src.data, desc, src.cols, src.rows, src.step ) ); - - meanshiftproc_kernel<<< grid, threads, 0, stream >>>( dstr.data, dstr.step, dstsp.data, dstsp.step, dstr.cols, dstr.rows, sp, sr, maxIter, eps ); + cv::cudev::Texture tex(src.rows, src.cols, (uchar4*)src.data, src.step); + meanshiftproc_kernel<<< grid, threads, 0, stream >>>( tex, dstr.data, dstr.step, dstsp.data, dstsp.step, dstr.cols, dstr.rows, sp, sr, maxIter, eps ); cudaSafeCall( cudaGetLastError() ); - if (stream == 0) cudaSafeCall( cudaDeviceSynchronize() ); } diff --git a/modules/cudaimgproc/src/gftt.cpp b/modules/cudaimgproc/src/gftt.cpp index ae19087aac1..540534a87ab 100644 --- a/modules/cudaimgproc/src/gftt.cpp +++ b/modules/cudaimgproc/src/gftt.cpp @@ -55,8 +55,8 @@ namespace cv { namespace cuda { namespace device { namespace gfft { - int findCorners_gpu(const cudaTextureObject_t &eigTex_, const int &rows, const int &cols, float threshold, PtrStepSzb mask, float2* corners, int max_count, int* counterPtr, cudaStream_t stream); - void sortCorners_gpu(const cudaTextureObject_t &eigTex_, float2* corners, int count, cudaStream_t stream); + int findCorners_gpu(const PtrStepSzf eig, float threshold, PtrStepSzb mask, float2* corners, int max_count, int* counterPtr, cudaStream_t stream); + void sortCorners_gpu(const PtrStepSzf eig, float2* corners, int count, cudaStream_t stream); } }}} @@ -120,31 +120,15 @@ namespace cudaStream_t stream_ = StreamAccessor::getStream(stream); ensureSizeIsEnough(1, std::max(1000, static_cast(image.size().area() * 0.05)), CV_32FC2, tmpCorners_); - //create texture object for findCorners_gpu and sortCorners_gpu - cudaTextureDesc texDesc; - memset(&texDesc, 0, sizeof(texDesc)); - texDesc.readMode = cudaReadModeElementType; - texDesc.filterMode = cudaFilterModePoint; - texDesc.addressMode[0] = cudaAddressModeClamp; - texDesc.addressMode[1] = cudaAddressModeClamp; - texDesc.addressMode[2] = cudaAddressModeClamp; - - cudaTextureObject_t eigTex_; - PtrStepSzf eig = eig_; - cv::cuda::device::createTextureObjectPitch2D(&eigTex_, eig, texDesc); - - int total = findCorners_gpu(eigTex_, eig_.rows, eig_.cols, static_cast(maxVal * qualityLevel_), mask, tmpCorners_.ptr(), tmpCorners_.cols, counterPtr_, stream_); + int total = findCorners_gpu(eig_, static_cast(maxVal * qualityLevel_), mask, tmpCorners_.ptr(), tmpCorners_.cols, counterPtr_, stream_); if (total == 0) { _corners.release(); - cudaSafeCall( cudaDestroyTextureObject(eigTex_) ); return; } - sortCorners_gpu(eigTex_, tmpCorners_.ptr(), total, stream_); - - cudaSafeCall( cudaDestroyTextureObject(eigTex_) ); + sortCorners_gpu(eig_, tmpCorners_.ptr(), total, stream_); if (minDistance_ < 1) { diff --git a/modules/cudaimgproc/test/test_color.cpp b/modules/cudaimgproc/test/test_color.cpp index 97be36a1210..e88bc8a1db6 100644 --- a/modules/cudaimgproc/test/test_color.cpp +++ b/modules/cudaimgproc/test/test_color.cpp @@ -2294,14 +2294,15 @@ INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, CvtColor, testing::Combine( /////////////////////////////////////////////////////////////////////////////////////////////////////// // Demosaicing -struct Demosaicing : testing::TestWithParam +struct Demosaicing : testing::TestWithParam> { cv::cuda::DeviceInfo devInfo; + bool useRoi; virtual void SetUp() { - devInfo = GetParam(); - + devInfo = GET_PARAM(0); + useRoi = GET_PARAM(1); cv::cuda::setDevice(devInfo.deviceID()); } @@ -2419,7 +2420,7 @@ CUDA_TEST_P(Demosaicing, BayerBG2BGR_MHT) mosaic(img, src, cv::Point(1, 1)); cv::cuda::GpuMat dst; - cv::cuda::demosaicing(loadMat(src), dst, cv::cuda::COLOR_BayerBG2BGR_MHT); + cv::cuda::demosaicing(loadMat(src, useRoi), dst, cv::cuda::COLOR_BayerBG2BGR_MHT); EXPECT_MAT_SIMILAR(img, dst, 5e-3); } @@ -2433,7 +2434,7 @@ CUDA_TEST_P(Demosaicing, BayerGB2BGR_MHT) mosaic(img, src, cv::Point(0, 1)); cv::cuda::GpuMat dst; - cv::cuda::demosaicing(loadMat(src), dst, cv::cuda::COLOR_BayerGB2BGR_MHT); + cv::cuda::demosaicing(loadMat(src, useRoi), dst, cv::cuda::COLOR_BayerGB2BGR_MHT); EXPECT_MAT_SIMILAR(img, dst, 5e-3); } @@ -2447,7 +2448,7 @@ CUDA_TEST_P(Demosaicing, BayerRG2BGR_MHT) mosaic(img, src, cv::Point(0, 0)); cv::cuda::GpuMat dst; - cv::cuda::demosaicing(loadMat(src), dst, cv::cuda::COLOR_BayerRG2BGR_MHT); + cv::cuda::demosaicing(loadMat(src, useRoi), dst, cv::cuda::COLOR_BayerRG2BGR_MHT); EXPECT_MAT_SIMILAR(img, dst, 5e-3); } @@ -2461,12 +2462,11 @@ CUDA_TEST_P(Demosaicing, BayerGR2BGR_MHT) mosaic(img, src, cv::Point(1, 0)); cv::cuda::GpuMat dst; - cv::cuda::demosaicing(loadMat(src), dst, cv::cuda::COLOR_BayerGR2BGR_MHT); - + cv::cuda::demosaicing(loadMat(src, useRoi), dst, cv::cuda::COLOR_BayerGR2BGR_MHT); EXPECT_MAT_SIMILAR(img, dst, 5e-3); } -INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, Demosaicing, ALL_DEVICES); +INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, Demosaicing, testing::Combine(ALL_DEVICES, WHOLE_SUBMAT)); /////////////////////////////////////////////////////////////////////////////////////////////////////// // swapChannels diff --git a/modules/cudaimgproc/test/test_hough.cpp b/modules/cudaimgproc/test/test_hough.cpp index e6a05f578f6..023e1c50c7d 100644 --- a/modules/cudaimgproc/test/test_hough.cpp +++ b/modules/cudaimgproc/test/test_hough.cpp @@ -115,8 +115,20 @@ INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, HoughLines, testing::Combine( /////////////////////////////////////////////////////////////////////////////////////////////////////// // HoughLines Probabilistic -PARAM_TEST_CASE(HoughLinesProbabilistic, cv::cuda::DeviceInfo, cv::Size, UseRoi) +PARAM_TEST_CASE(HoughLinesProbabilistic, DeviceInfo, Size, UseRoi) { + cv::cuda::DeviceInfo devInfo; + bool useRoi; + Size size; + + virtual void SetUp() + { + devInfo = GET_PARAM(0); + size = GET_PARAM(1); + useRoi = GET_PARAM(2); + cv::cuda::setDevice(devInfo.deviceID()); + } + static void generateLines(cv::Mat& img) { img.setTo(cv::Scalar::all(0)); @@ -140,11 +152,6 @@ PARAM_TEST_CASE(HoughLinesProbabilistic, cv::cuda::DeviceInfo, cv::Size, UseRoi) CUDA_TEST_P(HoughLinesProbabilistic, Accuracy) { - const cv::cuda::DeviceInfo devInfo = GET_PARAM(0); - cv::cuda::setDevice(devInfo.deviceID()); - const cv::Size size = GET_PARAM(1); - const bool useRoi = GET_PARAM(2); - const float rho = 1.0f; const float theta = (float) (1.0 * CV_PI / 180.0); const int minLineLength = 15; @@ -169,12 +176,55 @@ CUDA_TEST_P(HoughLinesProbabilistic, Accuracy) } +void HoughLinesProbabilisticThread(const Ptr detector, const GpuMat& imgIn, const std::vector& linesOut, Stream& stream) { + for (auto& lines : linesOut) + detector->detect(imgIn, lines, stream); + stream.waitForCompletion(); +} + +CUDA_TEST_P(HoughLinesProbabilistic, Async) +{ + constexpr int nThreads = 5; + constexpr int nIters = 5; + vector streams(nThreads); // async test only + vector imgsIn; + vector> detectors; + vector> linesOut(nThreads); + const float rho = 1.0f; + const float theta = (float)(1.0 * CV_PI / 180.0); + const int minLineLength = 15; + const int maxLineGap = 8; + + cv::Mat src(size, CV_8UC1); + generateLines(src); + + for (int i = 0; i < nThreads; i++) { + imgsIn.push_back(loadMat(src, useRoi)); + detectors.push_back(createHoughSegmentDetector(rho, theta, minLineLength, maxLineGap)); + linesOut.push_back(vector(nIters)); + } + + vector thread(nThreads); + for (int i = 0; i < nThreads; i++) thread.at(i) = std::thread(HoughLinesProbabilisticThread, detectors.at(i), std::ref(imgsIn.at(i)), std::ref(linesOut.at(i)), std::ref(streams.at(i))); + for (int i = 0; i < nThreads; i++) thread.at(i).join(); + + for (int i = 0; i < nThreads; i++) { + std::vector linesSegment; + std::vector lines; + for (const auto& line : linesOut.at(i)) { + line.download(linesSegment); + cv::Mat dst(size, CV_8UC1); + drawLines(dst, linesSegment); + ASSERT_MAT_NEAR(src, dst, 0.0); + } + } +} + INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, HoughLinesProbabilistic, testing::Combine( ALL_DEVICES, DIFFERENT_SIZES, WHOLE_SUBMAT)); - /////////////////////////////////////////////////////////////////////////////////////////////////////// // HoughCircles diff --git a/modules/cudaimgproc/test/test_precomp.hpp b/modules/cudaimgproc/test/test_precomp.hpp index dd94f6f2856..e388fbdaa8a 100644 --- a/modules/cudaimgproc/test/test_precomp.hpp +++ b/modules/cudaimgproc/test/test_precomp.hpp @@ -49,4 +49,6 @@ #include "cvconfig.h" +#include + #endif diff --git a/modules/cudalegacy/include/opencv2/cudalegacy/NCV.hpp b/modules/cudalegacy/include/opencv2/cudalegacy/NCV.hpp index d0ec6a42d6e..f03410dfbd0 100644 --- a/modules/cudalegacy/include/opencv2/cudalegacy/NCV.hpp +++ b/modules/cudalegacy/include/opencv2/cudalegacy/NCV.hpp @@ -119,9 +119,9 @@ typedef bool NcvBool; typedef long long Ncv64s; #if defined(__APPLE__) && !defined(__CUDACC__) - typedef uint64_t Ncv64u; + typedef uint64 Ncv64u; #else - typedef unsigned long long Ncv64u; + typedef uint64 Ncv64u; #endif typedef int Ncv32s; diff --git a/modules/cudalegacy/include/opencv2/cudalegacy/NPP_staging.hpp b/modules/cudalegacy/include/opencv2/cudalegacy/NPP_staging.hpp index 89e7f7cdea3..d9189eb20bb 100644 --- a/modules/cudalegacy/include/opencv2/cudalegacy/NPP_staging.hpp +++ b/modules/cudalegacy/include/opencv2/cudalegacy/NPP_staging.hpp @@ -174,7 +174,7 @@ NCVStatus nppiStInterpolateFrames(const NppStInterpolationState *pState); * \return NCV status code */ CV_EXPORTS -NCVStatus nppiStFilterRowBorder_32f_C1R(const Ncv32f *pSrc, +NCVStatus nppiStFilterRowBorder_32f_C1R(Ncv32f *pSrc, NcvSize32u srcSize, Ncv32u nSrcStep, Ncv32f *pDst, @@ -182,7 +182,7 @@ NCVStatus nppiStFilterRowBorder_32f_C1R(const Ncv32f *pSrc, Ncv32u nDstStep, NcvRect32u oROI, NppStBorderType borderType, - const Ncv32f *pKernel, + Ncv32f *pKernel, Ncv32s nKernelSize, Ncv32s nAnchor, Ncv32f multiplier); @@ -208,7 +208,7 @@ NCVStatus nppiStFilterRowBorder_32f_C1R(const Ncv32f *pSrc, * \return NCV status code */ CV_EXPORTS -NCVStatus nppiStFilterColumnBorder_32f_C1R(const Ncv32f *pSrc, +NCVStatus nppiStFilterColumnBorder_32f_C1R(Ncv32f *pSrc, NcvSize32u srcSize, Ncv32u nSrcStep, Ncv32f *pDst, @@ -216,7 +216,7 @@ NCVStatus nppiStFilterColumnBorder_32f_C1R(const Ncv32f *pSrc, Ncv32u nDstStep, NcvRect32u oROI, NppStBorderType borderType, - const Ncv32f *pKernel, + Ncv32f *pKernel, Ncv32s nKernelSize, Ncv32s nAnchor, Ncv32f multiplier); @@ -319,7 +319,7 @@ NCVStatus nppiStVectorWarp_PSF2x2_32f_C1(const Ncv32f *pSrc, * \return NCV status code */ CV_EXPORTS -NCVStatus nppiStResize_32f_C1R(const Ncv32f *pSrc, +NCVStatus nppiStResize_32f_C1R(Ncv32f *pSrc, NcvSize32u srcSize, Ncv32u nSrcStep, NcvRect32u srcROI, diff --git a/modules/cudalegacy/src/cuda/NCVBroxOpticalFlow.cu b/modules/cudalegacy/src/cuda/NCVBroxOpticalFlow.cu index 01914880248..a7f83c715d0 100644 --- a/modules/cudalegacy/src/cuda/NCVBroxOpticalFlow.cu +++ b/modules/cudalegacy/src/cuda/NCVBroxOpticalFlow.cu @@ -65,9 +65,12 @@ #include "opencv2/cudalegacy/NPP_staging.hpp" #include "opencv2/cudalegacy/NCVBroxOpticalFlow.hpp" +#include typedef NCVVectorAlloc FloatVector; +typedef cv::cudev::TexturePtr Ptr2D; +typedef cv::cudev::Texture Texture; ///////////////////////////////////////////////////////////////////////////////////////// // Implementation specific constants @@ -84,39 +87,6 @@ inline int iDivUp(int a, int b) return (a + b - 1)/b; } -///////////////////////////////////////////////////////////////////////////////////////// -// Texture references -///////////////////////////////////////////////////////////////////////////////////////// - -texture tex_coarse; -texture tex_fine; - -texture tex_I1; -texture tex_I0; - -texture tex_Ix; -texture tex_Ixx; -texture tex_Ix0; - -texture tex_Iy; -texture tex_Iyy; -texture tex_Iy0; - -texture tex_Ixy; - -texture tex_u; -texture tex_v; -texture tex_du; -texture tex_dv; -texture tex_numerator_dudv; -texture tex_numerator_u; -texture tex_numerator_v; -texture tex_inv_denominator_u; -texture tex_inv_denominator_v; -texture tex_diffusivity_x; -texture tex_diffusivity_y; - - ///////////////////////////////////////////////////////////////////////////////////////// // SUPPLEMENTARY FUNCTIONS ///////////////////////////////////////////////////////////////////////////////////////// @@ -265,8 +235,7 @@ __forceinline__ __device__ void diffusivity_along_y(float *s, int pos, const flo ///\param h number of rows in global memory array ///\param p global memory array pitch in floats /////////////////////////////////////////////////////////////////////////////// -template -__forceinline__ __device__ void load_array_element(float *smem, int is, int js, int i, int j, int w, int h, int p) +__forceinline__ __device__ void load_array_element(Ptr2D texSrc, float *smem, int is, int js, int i, int j, int w, int h, int p) { //position within shared memory array const int ijs = js * PSOR_PITCH + is; @@ -276,20 +245,7 @@ __forceinline__ __device__ void load_array_element(float *smem, int is, int js, j = max(j, -j-1); j = min(j, h-j+h-1); const int pos = j * p + i; - switch(tex_id){ - case 0: - smem[ijs] = tex1Dfetch(tex_u, pos); - break; - case 1: - smem[ijs] = tex1Dfetch(tex_v, pos); - break; - case 2: - smem[ijs] = tex1Dfetch(tex_du, pos); - break; - case 3: - smem[ijs] = tex1Dfetch(tex_dv, pos); - break; - } + smem[ijs] = texSrc(pos); } /////////////////////////////////////////////////////////////////////////////// @@ -301,49 +257,48 @@ __forceinline__ __device__ void load_array_element(float *smem, int is, int js, ///\param h number of rows in global memory array ///\param p global memory array pitch in floats /////////////////////////////////////////////////////////////////////////////// -template -__forceinline__ __device__ void load_array(float *smem, int ig, int jg, int w, int h, int p) +__forceinline__ __device__ void load_array(Ptr2D texSrc, float *smem, int ig, int jg, int w, int h, int p) { const int i = threadIdx.x + 2; const int j = threadIdx.y + 2; - load_array_element(smem, i, j, ig, jg, w, h, p);//load current pixel + load_array_element(texSrc, smem, i, j, ig, jg, w, h, p);//load current pixel __syncthreads(); if(threadIdx.y < 2) { //load bottom shadow elements - load_array_element(smem, i, j-2, ig, jg-2, w, h, p); + load_array_element(texSrc, smem, i, j-2, ig, jg-2, w, h, p); if(threadIdx.x < 2) { //load bottom right shadow elements - load_array_element(smem, i+PSOR_TILE_WIDTH, j-2, ig+PSOR_TILE_WIDTH, jg-2, w, h, p); + load_array_element(texSrc, smem, i+PSOR_TILE_WIDTH, j-2, ig+PSOR_TILE_WIDTH, jg-2, w, h, p); //load middle right shadow elements - load_array_element(smem, i+PSOR_TILE_WIDTH, j, ig+PSOR_TILE_WIDTH, jg, w, h, p); + load_array_element(texSrc, smem, i+PSOR_TILE_WIDTH, j, ig+PSOR_TILE_WIDTH, jg, w, h, p); } else if(threadIdx.x >= PSOR_TILE_WIDTH-2) { //load bottom left shadow elements - load_array_element(smem, i-PSOR_TILE_WIDTH, j-2, ig-PSOR_TILE_WIDTH, jg-2, w, h, p); + load_array_element(texSrc, smem, i-PSOR_TILE_WIDTH, j-2, ig-PSOR_TILE_WIDTH, jg-2, w, h, p); //load middle left shadow elements - load_array_element(smem, i-PSOR_TILE_WIDTH, j, ig-PSOR_TILE_WIDTH, jg, w, h, p); + load_array_element(texSrc, smem, i-PSOR_TILE_WIDTH, j, ig-PSOR_TILE_WIDTH, jg, w, h, p); } } else if(threadIdx.y >= PSOR_TILE_HEIGHT-2) { //load upper shadow elements - load_array_element(smem, i, j+2, ig, jg+2, w, h, p); + load_array_element(texSrc, smem, i, j+2, ig, jg+2, w, h, p); if(threadIdx.x < 2) { //load upper right shadow elements - load_array_element(smem, i+PSOR_TILE_WIDTH, j+2, ig+PSOR_TILE_WIDTH, jg+2, w, h, p); + load_array_element(texSrc, smem, i+PSOR_TILE_WIDTH, j+2, ig+PSOR_TILE_WIDTH, jg+2, w, h, p); //load middle right shadow elements - load_array_element(smem, i+PSOR_TILE_WIDTH, j, ig+PSOR_TILE_WIDTH, jg, w, h, p); + load_array_element(texSrc, smem, i+PSOR_TILE_WIDTH, j, ig+PSOR_TILE_WIDTH, jg, w, h, p); } else if(threadIdx.x >= PSOR_TILE_WIDTH-2) { //load upper left shadow elements - load_array_element(smem, i-PSOR_TILE_WIDTH, j+2, ig-PSOR_TILE_WIDTH, jg+2, w, h, p); + load_array_element(texSrc, smem, i-PSOR_TILE_WIDTH, j+2, ig-PSOR_TILE_WIDTH, jg+2, w, h, p); //load middle left shadow elements - load_array_element(smem, i-PSOR_TILE_WIDTH, j, ig-PSOR_TILE_WIDTH, jg, w, h, p); + load_array_element(texSrc, smem, i-PSOR_TILE_WIDTH, j, ig-PSOR_TILE_WIDTH, jg, w, h, p); } } else @@ -352,12 +307,12 @@ __forceinline__ __device__ void load_array(float *smem, int ig, int jg, int w, i if(threadIdx.x < 2) { //load middle right shadow elements - load_array_element(smem, i+PSOR_TILE_WIDTH, j, ig+PSOR_TILE_WIDTH, jg, w, h, p); + load_array_element(texSrc, smem, i+PSOR_TILE_WIDTH, j, ig+PSOR_TILE_WIDTH, jg, w, h, p); } else if(threadIdx.x >= PSOR_TILE_WIDTH-2) { //load middle left shadow elements - load_array_element(smem, i-PSOR_TILE_WIDTH, j, ig-PSOR_TILE_WIDTH, jg, w, h, p); + load_array_element(texSrc, smem, i-PSOR_TILE_WIDTH, j, ig-PSOR_TILE_WIDTH, jg, w, h, p); } } __syncthreads(); @@ -382,13 +337,9 @@ __forceinline__ __device__ void load_array(float *smem, int ig, int jg, int w, i /// \param alpha (in) alpha in Brox model (flow smoothness) /// \param gamma (in) gamma in Brox model (edge importance) /////////////////////////////////////////////////////////////////////////////// - -__global__ void prepare_sor_stage_1_tex(float *diffusivity_x, float *diffusivity_y, - float *denominator_u, float *denominator_v, - float *numerator_dudv, - float *numerator_u, float *numerator_v, - int w, int h, int s, - float alpha, float gamma) +__global__ void prepare_sor_stage_1_tex(Ptr2D texU, Ptr2D texV, Ptr2D texDu, Ptr2D texDv, Ptr2D texI0, Ptr2D texI1, Ptr2D texIx, Ptr2D texIxx, Ptr2D texIx0, Ptr2D texIy, Ptr2D texIyy, + Ptr2D texIy0, Ptr2D texIxy, float *diffusivity_x, float *diffusivity_y, float *denominator_u, float *denominator_v, float *numerator_dudv, float *numerator_u, float *numerator_v, + int w, int h, int s, float alpha, float gamma) { __shared__ float u[PSOR_PITCH * PSOR_HEIGHT]; __shared__ float v[PSOR_PITCH * PSOR_HEIGHT]; @@ -408,24 +359,24 @@ __global__ void prepare_sor_stage_1_tex(float *diffusivity_x, float *diffusivity float x = (float)ig + 0.5f; float y = (float)jg + 0.5f; //load u and v to smem - load_array<0>(u, ig, jg, w, h, s); - load_array<1>(v, ig, jg, w, h, s); - load_array<2>(du, ig, jg, w, h, s); - load_array<3>(dv, ig, jg, w, h, s); + load_array(texU, u, ig, jg, w, h, s); + load_array(texV, v, ig, jg, w, h, s); + load_array(texDu, du, ig, jg, w, h, s); + load_array(texDv, dv, ig, jg, w, h, s); //warped position float wx = (x + u[ijs])/(float)w; float wy = (y + v[ijs])/(float)h; x /= (float)w; y /= (float)h; //compute image derivatives - const float Iz = tex2D(tex_I1, wx, wy) - tex2D(tex_I0, x, y); - const float Ix = tex2D(tex_Ix, wx, wy); - const float Ixz = Ix - tex2D(tex_Ix0, x, y); - const float Ixy = tex2D(tex_Ixy, wx, wy); - const float Ixx = tex2D(tex_Ixx, wx, wy); - const float Iy = tex2D(tex_Iy, wx, wy); - const float Iyz = Iy - tex2D(tex_Iy0, x, y); - const float Iyy = tex2D(tex_Iyy, wx, wy); + const float Iz = texI1(wy, wx) - texI0(y,x); + const float Ix = texIx(wy, wx); + const float Ixz = Ix - texIx0(y, x); + const float Ixy = texIxy(wy, wx); + const float Ixx = texIxx(wy, wx); + const float Iy = texIy(wy, wx); + const float Iyz = Iy - texIy0(y, x); + const float Iyy = texIyy(wy, wx); //compute data term float q0, q1, q2; q0 = Iz + Ix * du[ijs] + Iy * dv[ijs]; @@ -462,8 +413,7 @@ __global__ void prepare_sor_stage_1_tex(float *diffusivity_x, float *diffusivity ///\param h ///\param s /////////////////////////////////////////////////////////////////////////////// -__global__ void prepare_sor_stage_2(float *inv_denominator_u, float *inv_denominator_v, - int w, int h, int s) +__global__ void prepare_sor_stage_2(Ptr2D texDiffX, Ptr2D texDiffY, float *inv_denominator_u, float *inv_denominator_v, int w, int h, int s) { __shared__ float sx[(PSOR_TILE_WIDTH+1) * (PSOR_TILE_HEIGHT+1)]; __shared__ float sy[(PSOR_TILE_WIDTH+1) * (PSOR_TILE_HEIGHT+1)]; @@ -486,8 +436,8 @@ __global__ void prepare_sor_stage_2(float *inv_denominator_u, float *inv_denomin } if(inside) { - sx[ijs] = tex1Dfetch(tex_diffusivity_x, ijg); - sy[ijs] = tex1Dfetch(tex_diffusivity_y, ijg); + sx[ijs] = texDiffX(ijg); + sy[ijs] = texDiffY(ijg); } else { @@ -498,25 +448,17 @@ __global__ void prepare_sor_stage_2(float *inv_denominator_u, float *inv_denomin if(j == PSOR_TILE_HEIGHT-1) { if(jg < h-1 && inside) - { - sy[up] = tex1Dfetch(tex_diffusivity_y, ijg + s); - } + sy[up] = texDiffY(ijg + s); else - { sy[up] = 0.0f; - } } int right = ijs + 1; if(threadIdx.x == PSOR_TILE_WIDTH-1) { if(ig < w-1 && inside) - { - sx[right] = tex1Dfetch(tex_diffusivity_x, ijg + 1); - } + sx[right] = texDiffX(ijg + 1); else - { sx[right] = 0.0f; - } } __syncthreads(); float diffusivity_sum; @@ -534,17 +476,8 @@ __global__ void prepare_sor_stage_2(float *inv_denominator_u, float *inv_denomin // Red-Black SOR ///////////////////////////////////////////////////////////////////////////////////////// -template __global__ void sor_pass(float *new_du, - float *new_dv, - const float *g_inv_denominator_u, - const float *g_inv_denominator_v, - const float *g_numerator_u, - const float *g_numerator_v, - const float *g_numerator_dudv, - float omega, - int width, - int height, - int stride) +template __global__ void sor_pass(Ptr2D texU, Ptr2D texV, Ptr2D texDu, Ptr2D texDv, Ptr2D texDiffX, Ptr2D texDiffY, float *new_du, float *new_dv, const float *g_inv_denominator_u, + const float *g_inv_denominator_v, const float *g_numerator_u, const float *g_numerator_v, const float *g_numerator_dudv, float omega, int width, int height, int stride) { int i = blockIdx.x * blockDim.x + threadIdx.x; int j = blockIdx.y * blockDim.y + threadIdx.y; @@ -560,14 +493,14 @@ template __global__ void sor_pass(float *new_du, //load smooth term float s_up, s_left, s_right, s_down; - s_left = tex1Dfetch(tex_diffusivity_x, pos); - s_down = tex1Dfetch(tex_diffusivity_y, pos); + s_left = texDiffX(pos); + s_down = texDiffY(pos); if(i < width-1) - s_right = tex1Dfetch(tex_diffusivity_x, pos_r); + s_right = texDiffX(pos_r); else s_right = 0.0f; //Neumann BC if(j < height-1) - s_up = tex1Dfetch(tex_diffusivity_y, pos_u); + s_up = texDiffY(pos_u); else s_up = 0.0f; //Neumann BC @@ -577,30 +510,29 @@ template __global__ void sor_pass(float *new_du, float du_up, du_left, du_right, du_down, du; float dv_up, dv_left, dv_right, dv_down, dv; - u_left = tex1Dfetch(tex_u, pos_l); - u_right = tex1Dfetch(tex_u, pos_r); - u_down = tex1Dfetch(tex_u, pos_d); - u_up = tex1Dfetch(tex_u, pos_u); - u = tex1Dfetch(tex_u, pos); - - v_left = tex1Dfetch(tex_v, pos_l); - v_right = tex1Dfetch(tex_v, pos_r); - v_down = tex1Dfetch(tex_v, pos_d); - v = tex1Dfetch(tex_v, pos); - v_up = tex1Dfetch(tex_v, pos_u); - - du = tex1Dfetch(tex_du, pos); - du_left = tex1Dfetch(tex_du, pos_l); - du_right = tex1Dfetch(tex_du, pos_r); - du_down = tex1Dfetch(tex_du, pos_d); - du_up = tex1Dfetch(tex_du, pos_u); - - dv = tex1Dfetch(tex_dv, pos); - dv_left = tex1Dfetch(tex_dv, pos_l); - dv_right = tex1Dfetch(tex_dv, pos_r); - dv_down = tex1Dfetch(tex_dv, pos_d); - dv_up = tex1Dfetch(tex_dv, pos_u); - + u_left = texU(pos_l); + u_right = texU(pos_r); + u_down = texU(pos_d); + u_up = texU(pos_u); + u = texU(pos); + + v_left = texV(pos_l); + v_right = texV(pos_r); + v_down = texV(pos_d); + v = texV(pos); + v_up = texV(pos_u); + + du = texDu(pos); + du_left = texDu(pos_l); + du_right = texDu(pos_r); + du_down = texDu(pos_d); + du_up = texDu(pos_u); + + dv = texDv(pos); + dv_left = texDv(pos_l); + dv_right = texDv(pos_r); + dv_down = texDv(pos_d); + dv_up = texDv(pos_u); float numerator_dudv = g_numerator_dudv[pos]; if((i+j)%2 == isBlack) @@ -624,52 +556,6 @@ template __global__ void sor_pass(float *new_du, /////////////////////////////////////////////////////////////////////////////// // utility functions /////////////////////////////////////////////////////////////////////////////// - -void initTexture1D(texture &tex) -{ - tex.addressMode[0] = cudaAddressModeClamp; - tex.filterMode = cudaFilterModePoint; - tex.normalized = false; -} - -void initTexture2D(texture &tex) -{ - tex.addressMode[0] = cudaAddressModeMirror; - tex.addressMode[1] = cudaAddressModeMirror; - tex.filterMode = cudaFilterModeLinear; - tex.normalized = true; -} - -void InitTextures() -{ - initTexture2D(tex_I0); - initTexture2D(tex_I1); - initTexture2D(tex_fine); // for downsampling - initTexture2D(tex_coarse); // for prolongation - - initTexture2D(tex_Ix); - initTexture2D(tex_Ixx); - initTexture2D(tex_Ix0); - - initTexture2D(tex_Iy); - initTexture2D(tex_Iyy); - initTexture2D(tex_Iy0); - - initTexture2D(tex_Ixy); - - initTexture1D(tex_u); - initTexture1D(tex_v); - initTexture1D(tex_du); - initTexture1D(tex_dv); - initTexture1D(tex_diffusivity_x); - initTexture1D(tex_diffusivity_y); - initTexture1D(tex_inv_denominator_u); - initTexture1D(tex_inv_denominator_v); - initTexture1D(tex_numerator_dudv); - initTexture1D(tex_numerator_u); - initTexture1D(tex_numerator_v); -} - namespace { struct ImagePyramid @@ -804,8 +690,6 @@ NCVStatus NCVBroxOpticalFlow(const NCVBroxOpticalFlowDescriptor desc, ncvAssertCUDAReturn(cudaMemcpy(derivativeFilter.ptr(), derivativeFilterHost, sizeof(float) * kDFilterSize, cudaMemcpyHostToDevice), NCV_CUDA_ERROR); - - InitTextures(); } //prepare image pyramid @@ -909,9 +793,6 @@ NCVStatus NCVBroxOpticalFlow(const NCVBroxOpticalFlowDescriptor desc, ncvAssertCUDAReturn(cudaMemsetAsync(v.ptr(), 0, kSizeInPixelsAligned * sizeof(float), stream), NCV_CUDA_ERROR); //select images with lowest resolution - size_t pitch = alignUp(pyr.w.back(), kStrideAlignmentFloat) * sizeof(float); - ncvAssertCUDAReturn(cudaBindTexture2D(0, tex_I0, pyr.img0.back()->ptr(), channel_desc, pyr.w.back(), pyr.h.back(), pitch), NCV_CUDA_ERROR); - ncvAssertCUDAReturn(cudaBindTexture2D(0, tex_I1, pyr.img1.back()->ptr(), channel_desc, pyr.w.back(), pyr.h.back(), pitch), NCV_CUDA_ERROR); ncvAssertCUDAReturn(cudaStreamSynchronize(stream), NCV_CUDA_ERROR); FloatVector* ptrU = &u; @@ -941,17 +822,14 @@ NCVStatus NCVBroxOpticalFlow(const NCVBroxOpticalFlowDescriptor desc, ncvAssertCUDAReturn(cudaMemsetAsync(du.ptr(), 0, kLevelSizeInBytes, stream), NCV_CUDA_ERROR); ncvAssertCUDAReturn(cudaMemsetAsync(dv.ptr(), 0, kLevelSizeInBytes, stream), NCV_CUDA_ERROR); - //texture format descriptor - cudaChannelFormatDesc ch_desc = cudaCreateChannelDesc(); - I0 = *img0Iter; I1 = *img1Iter; ++img0Iter; ++img1Iter; - ncvAssertCUDAReturn(cudaBindTexture2D(0, tex_I0, I0->ptr(), ch_desc, kLevelWidth, kLevelHeight, kLevelStride*sizeof(float)), NCV_CUDA_ERROR); - ncvAssertCUDAReturn(cudaBindTexture2D(0, tex_I1, I1->ptr(), ch_desc, kLevelWidth, kLevelHeight, kLevelStride*sizeof(float)), NCV_CUDA_ERROR); + Texture texI0(kLevelHeight, kLevelWidth, I0->ptr(), kLevelStride * sizeof(float), true, cudaFilterModeLinear, cudaAddressModeMirror); + Texture texI1(kLevelHeight, kLevelWidth, I1->ptr(), kLevelStride * sizeof(float), true, cudaFilterModeLinear, cudaAddressModeMirror); //compute derivatives dim3 dBlocks(iDivUp(kLevelWidth, 32), iDivUp(kLevelHeight, 6)); @@ -991,20 +869,24 @@ NCVStatus NCVBroxOpticalFlow(const NCVBroxOpticalFlowDescriptor desc, ncvAssertReturnNcvStat( nppiStFilterRowBorder_32f_C1R (Iy.ptr(), srcSize, nSrcStep, Ixy.ptr(), srcSize, nSrcStep, oROI, nppStBorderMirror, derivativeFilter.ptr(), kDFilterSize, kDFilterSize/2, 1.0f/12.0f) ); - ncvAssertCUDAReturn(cudaBindTexture2D(0, tex_Ix, Ix.ptr(), ch_desc, kLevelWidth, kLevelHeight, kPitchTex), NCV_CUDA_ERROR); - ncvAssertCUDAReturn(cudaBindTexture2D(0, tex_Ixx, Ixx.ptr(), ch_desc, kLevelWidth, kLevelHeight, kPitchTex), NCV_CUDA_ERROR); - ncvAssertCUDAReturn(cudaBindTexture2D(0, tex_Ix0, Ix0.ptr(), ch_desc, kLevelWidth, kLevelHeight, kPitchTex), NCV_CUDA_ERROR); - ncvAssertCUDAReturn(cudaBindTexture2D(0, tex_Iy, Iy.ptr(), ch_desc, kLevelWidth, kLevelHeight, kPitchTex), NCV_CUDA_ERROR); - ncvAssertCUDAReturn(cudaBindTexture2D(0, tex_Iyy, Iyy.ptr(), ch_desc, kLevelWidth, kLevelHeight, kPitchTex), NCV_CUDA_ERROR); - ncvAssertCUDAReturn(cudaBindTexture2D(0, tex_Iy0, Iy0.ptr(), ch_desc, kLevelWidth, kLevelHeight, kPitchTex), NCV_CUDA_ERROR); - ncvAssertCUDAReturn(cudaBindTexture2D(0, tex_Ixy, Ixy.ptr(), ch_desc, kLevelWidth, kLevelHeight, kPitchTex), NCV_CUDA_ERROR); + Texture texIx(kLevelHeight, kLevelWidth, Ix.ptr(), kPitchTex, true, cudaFilterModeLinear, cudaAddressModeMirror); + Texture texIxx(kLevelHeight, kLevelWidth, Ixx.ptr(), kPitchTex, true, cudaFilterModeLinear, cudaAddressModeMirror); + Texture texIx0(kLevelHeight, kLevelWidth, Ix0.ptr(), kPitchTex, true, cudaFilterModeLinear, cudaAddressModeMirror); + Texture texIy(kLevelHeight, kLevelWidth, Iy.ptr(), kPitchTex, true, cudaFilterModeLinear, cudaAddressModeMirror); + Texture texIyy(kLevelHeight, kLevelWidth, Iyy.ptr(), kPitchTex, true, cudaFilterModeLinear, cudaAddressModeMirror); + Texture texIy0(kLevelHeight, kLevelWidth, Iy0.ptr(), kPitchTex, true, cudaFilterModeLinear, cudaAddressModeMirror); + Texture texIxy(kLevelHeight, kLevelWidth, Ixy.ptr(), kPitchTex, true, cudaFilterModeLinear, cudaAddressModeMirror); + Texture texDiffX(1, kLevelSizeInBytes / sizeof(float), diffusivity_x.ptr(), kLevelSizeInBytes); + Texture texDiffY(1, kLevelSizeInBytes / sizeof(float), diffusivity_y.ptr(), kLevelSizeInBytes); // flow - ncvAssertCUDAReturn(cudaBindTexture(0, tex_u, ptrU->ptr(), ch_desc, kLevelSizeInBytes), NCV_CUDA_ERROR); - ncvAssertCUDAReturn(cudaBindTexture(0, tex_v, ptrV->ptr(), ch_desc, kLevelSizeInBytes), NCV_CUDA_ERROR); + Texture texU(1, kLevelSizeInBytes / sizeof(float), ptrU->ptr(), kLevelSizeInBytes); + Texture texV(1, kLevelSizeInBytes / sizeof(float), ptrV->ptr(), kLevelSizeInBytes); // flow increments - ncvAssertCUDAReturn(cudaBindTexture(0, tex_du, du.ptr(), ch_desc, kLevelSizeInBytes), NCV_CUDA_ERROR); - ncvAssertCUDAReturn(cudaBindTexture(0, tex_dv, dv.ptr(), ch_desc, kLevelSizeInBytes), NCV_CUDA_ERROR); + Texture texDu(1, kLevelSizeInBytes / sizeof(float), du.ptr(), kLevelSizeInBytes); + Texture texDv(1, kLevelSizeInBytes / sizeof(float), dv.ptr(), kLevelSizeInBytes); + Texture texDuNew(1, kLevelSizeInBytes / sizeof(float), du_new.ptr(), kLevelSizeInBytes); + Texture texDvNew(1, kLevelSizeInBytes / sizeof(float), dv_new.ptr(), kLevelSizeInBytes); dim3 psor_blocks(iDivUp(kLevelWidth, PSOR_TILE_WIDTH), iDivUp(kLevelHeight, PSOR_TILE_HEIGHT)); dim3 psor_threads(PSOR_TILE_WIDTH, PSOR_TILE_HEIGHT); @@ -1018,89 +900,30 @@ NCVStatus NCVBroxOpticalFlow(const NCVBroxOpticalFlowDescriptor desc, for (Ncv32u current_inner_iteration = 0; current_inner_iteration < desc.number_of_inner_iterations; ++current_inner_iteration) { //compute coefficients - prepare_sor_stage_1_tex<<>> - (diffusivity_x.ptr(), - diffusivity_y.ptr(), - denom_u.ptr(), - denom_v.ptr(), - num_dudv.ptr(), - num_u.ptr(), - num_v.ptr(), - kLevelWidth, - kLevelHeight, - kLevelStride, - alpha, - gamma); + prepare_sor_stage_1_tex<<>> (texU, texV, texDu, texDv, texI0, texI1, texIx, texIxx, texIx0, texIy, texIyy, texIy0, texIxy, + diffusivity_x.ptr(), diffusivity_y.ptr(), denom_u.ptr(), denom_v.ptr(), num_dudv.ptr(), num_u.ptr(), num_v.ptr(), kLevelWidth, kLevelHeight, kLevelStride, alpha, gamma); ncvAssertCUDALastErrorReturn(NCV_CUDA_ERROR); - ncvAssertCUDAReturn(cudaBindTexture(0, tex_diffusivity_x, diffusivity_x.ptr(), ch_desc, kLevelSizeInBytes), NCV_CUDA_ERROR); - ncvAssertCUDAReturn(cudaBindTexture(0, tex_diffusivity_y, diffusivity_y.ptr(), ch_desc, kLevelSizeInBytes), NCV_CUDA_ERROR); - - ncvAssertCUDAReturn(cudaBindTexture(0, tex_numerator_dudv, num_dudv.ptr(), ch_desc, kLevelSizeInBytes), NCV_CUDA_ERROR); - - ncvAssertCUDAReturn(cudaBindTexture(0, tex_numerator_u, num_u.ptr(), ch_desc, kLevelSizeInBytes), NCV_CUDA_ERROR); - ncvAssertCUDAReturn(cudaBindTexture(0, tex_numerator_v, num_v.ptr(), ch_desc, kLevelSizeInBytes), NCV_CUDA_ERROR); - - prepare_sor_stage_2<<>>(denom_u.ptr(), denom_v.ptr(), kLevelWidth, kLevelHeight, kLevelStride); + prepare_sor_stage_2<<>>(texDiffX, texDiffY, denom_u.ptr(), denom_v.ptr(), kLevelWidth, kLevelHeight, kLevelStride); ncvAssertCUDALastErrorReturn(NCV_CUDA_ERROR); - // linear system coefficients - ncvAssertCUDAReturn(cudaBindTexture(0, tex_diffusivity_x, diffusivity_x.ptr(), ch_desc, kLevelSizeInBytes), NCV_CUDA_ERROR); - ncvAssertCUDAReturn(cudaBindTexture(0, tex_diffusivity_y, diffusivity_y.ptr(), ch_desc, kLevelSizeInBytes), NCV_CUDA_ERROR); - - ncvAssertCUDAReturn(cudaBindTexture(0, tex_numerator_dudv, num_dudv.ptr(), ch_desc, kLevelSizeInBytes), NCV_CUDA_ERROR); - - ncvAssertCUDAReturn(cudaBindTexture(0, tex_numerator_u, num_u.ptr(), ch_desc, kLevelSizeInBytes), NCV_CUDA_ERROR); - ncvAssertCUDAReturn(cudaBindTexture(0, tex_numerator_v, num_v.ptr(), ch_desc, kLevelSizeInBytes), NCV_CUDA_ERROR); - - ncvAssertCUDAReturn(cudaBindTexture(0, tex_inv_denominator_u, denom_u.ptr(), ch_desc, kLevelSizeInBytes), NCV_CUDA_ERROR); - ncvAssertCUDAReturn(cudaBindTexture(0, tex_inv_denominator_v, denom_v.ptr(), ch_desc, kLevelSizeInBytes), NCV_CUDA_ERROR); //solve linear system for (Ncv32u solver_iteration = 0; solver_iteration < desc.number_of_solver_iterations; ++solver_iteration) { float omega = 1.99f; - - ncvAssertCUDAReturn(cudaBindTexture(0, tex_du, du.ptr(), ch_desc, kLevelSizeInBytes), NCV_CUDA_ERROR); - ncvAssertCUDAReturn(cudaBindTexture(0, tex_dv, dv.ptr(), ch_desc, kLevelSizeInBytes), NCV_CUDA_ERROR); - - sor_pass<0><<>> - (du_new.ptr(), - dv_new.ptr(), - denom_u.ptr(), - denom_v.ptr(), - num_u.ptr(), - num_v.ptr(), - num_dudv.ptr(), - omega, - kLevelWidth, - kLevelHeight, - kLevelStride); + sor_pass<0><<>>(texU, texV, texDu, texDv, texDiffX, texDiffY, du_new.ptr(), dv_new.ptr(), denom_u.ptr(), denom_v.ptr(), + num_u.ptr(), num_v.ptr(), num_dudv.ptr(), omega, kLevelWidth, kLevelHeight, kLevelStride); ncvAssertCUDALastErrorReturn(NCV_CUDA_ERROR); - ncvAssertCUDAReturn(cudaBindTexture(0, tex_du, du_new.ptr(), ch_desc, kLevelSizeInBytes), NCV_CUDA_ERROR); - ncvAssertCUDAReturn(cudaBindTexture(0, tex_dv, dv_new.ptr(), ch_desc, kLevelSizeInBytes), NCV_CUDA_ERROR); - - sor_pass<1><<>> - (du.ptr(), - dv.ptr(), - denom_u.ptr(), - denom_v.ptr(), - num_u.ptr(), - num_v.ptr(), - num_dudv.ptr(), - omega, - kLevelWidth, - kLevelHeight, - kLevelStride); - ncvAssertCUDALastErrorReturn(NCV_CUDA_ERROR); + sor_pass<1><<>>(texU, texV, texDuNew, texDvNew, texDiffX, texDiffY, du.ptr(), dv.ptr(), denom_u.ptr(), denom_v.ptr(), num_u.ptr(), + num_v.ptr(),num_dudv.ptr(), omega, kLevelWidth, kLevelHeight, kLevelStride); - ncvAssertCUDAReturn(cudaBindTexture(0, tex_du, du.ptr(), ch_desc, kLevelSizeInBytes), NCV_CUDA_ERROR); - ncvAssertCUDAReturn(cudaBindTexture(0, tex_dv, dv.ptr(), ch_desc, kLevelSizeInBytes), NCV_CUDA_ERROR); + ncvAssertCUDALastErrorReturn(NCV_CUDA_ERROR); }//end of solver loop }// end of inner loop diff --git a/modules/cudalegacy/src/cuda/NCVHaarObjectDetection.cu b/modules/cudalegacy/src/cuda/NCVHaarObjectDetection.cu index 57506173f50..9760bcee523 100644 --- a/modules/cudalegacy/src/cuda/NCVHaarObjectDetection.cu +++ b/modules/cudalegacy/src/cuda/NCVHaarObjectDetection.cu @@ -72,6 +72,7 @@ #include "opencv2/cudalegacy/NCV.hpp" #include "opencv2/cudalegacy/NPP_staging.hpp" #include "opencv2/cudalegacy/NCVHaarObjectDetection.hpp" +#include #include "NCVRuntimeTemplates.hpp" #include "NCVAlg.hpp" @@ -94,24 +95,6 @@ const Ncv32u NUM_THREADS_ANCHORSPARALLEL = 64; #define NUM_THREADS_CLASSIFIERPARALLEL (1 << NUM_THREADS_CLASSIFIERPARALLEL_LOG2) -/** \internal -* Haar features solid array. -*/ -texture texHaarFeatures; - - -/** \internal -* Haar classifiers flattened trees container. -* Two parts: first contains root nodes, second - nodes that are referred by root nodes. -* Drawback: breaks tree locality (might cause more cache misses -* Advantage: No need to introduce additional 32-bit field to index root nodes offsets -*/ -texture texHaarClassifierNodes; - - -texture texIImage; - - __device__ HaarStage64 getStage(Ncv32u iStage, HaarStage64 *d_Stages) { return d_Stages[iStage]; @@ -119,51 +102,37 @@ __device__ HaarStage64 getStage(Ncv32u iStage, HaarStage64 *d_Stages) template -__device__ HaarClassifierNode128 getClassifierNode(Ncv32u iNode, HaarClassifierNode128 *d_ClassifierNodes) +__device__ HaarClassifierNode128 getClassifierNode(cv::cudev::TexturePtr texHaarClassifierNodes, Ncv32u iNode, HaarClassifierNode128 *d_ClassifierNodes) { HaarClassifierNode128 tmpNode; if (tbCacheTextureCascade) - { - tmpNode._ui4 = tex1Dfetch(texHaarClassifierNodes, iNode); - } + tmpNode._ui4 = texHaarClassifierNodes(iNode); else - { tmpNode = d_ClassifierNodes[iNode]; - } return tmpNode; } template -__device__ void getFeature(Ncv32u iFeature, HaarFeature64 *d_Features, - Ncv32f *weight, - Ncv32u *rectX, Ncv32u *rectY, Ncv32u *rectWidth, Ncv32u *rectHeight) +__device__ void getFeature(cv::cudev::TexturePtr texHaarFeatures, Ncv32u iFeature, HaarFeature64* d_Features, Ncv32f* weight, Ncv32u* rectX, Ncv32u* rectY, Ncv32u* rectWidth, Ncv32u* rectHeight) { HaarFeature64 feature; if (tbCacheTextureCascade) - { - feature._ui2 = tex1Dfetch(texHaarFeatures, iFeature); - } + feature._ui2 = texHaarFeatures(iFeature); else - { feature = d_Features[iFeature]; - } feature.getRect(rectX, rectY, rectWidth, rectHeight); *weight = feature.getWeight(); } template -__device__ Ncv32u getElemIImg(Ncv32u x, Ncv32u *d_IImg) +__device__ Ncv32u getElemIImg(cv::cudev::TexturePtr texImg, Ncv32u x, Ncv32u *d_IImg) { if (tbCacheTextureIImg) - { - return tex1Dfetch(texIImage, x); - } + return texImg(x); else - { return d_IImg[x]; - } } @@ -203,17 +172,10 @@ __device__ void compactBlockWriteOutAnchorParallel(Ncv32u threadPassFlag, Ncv32u } -template -__global__ void applyHaarClassifierAnchorParallel(Ncv32u *d_IImg, Ncv32u IImgStride, - Ncv32f *d_weights, Ncv32u weightsStride, - HaarFeature64 *d_Features, HaarClassifierNode128 *d_ClassifierNodes, HaarStage64 *d_Stages, - Ncv32u *d_inMask, Ncv32u *d_outMask, - Ncv32u mask1Dlen, Ncv32u mask2Dstride, - NcvSize32u anchorsRoi, Ncv32u startStageInc, Ncv32u endStageExc, Ncv32f scaleArea) +template +__global__ void applyHaarClassifierAnchorParallel(cv::cudev::TexturePtr texImg, cv::cudev::TexturePtr texHaarFeatures, cv::cudev::TexturePtr texHaarClassifierNodes, + Ncv32u *d_IImg, Ncv32u IImgStride, Ncv32f *d_weights, Ncv32u weightsStride, HaarFeature64 *d_Features, HaarClassifierNode128 *d_ClassifierNodes, HaarStage64 *d_Stages, Ncv32u *d_inMask, + Ncv32u *d_outMask, Ncv32u mask1Dlen, Ncv32u mask2Dstride, NcvSize32u anchorsRoi, Ncv32u startStageInc, Ncv32u endStageExc, Ncv32f scaleArea) { Ncv32u y_offs; Ncv32u x_offs; @@ -299,7 +261,7 @@ __global__ void applyHaarClassifierAnchorParallel(Ncv32u *d_IImg, Ncv32u IImgStr { while (bMoreNodesToTraverse) { - HaarClassifierNode128 curNode = getClassifierNode(iNode, d_ClassifierNodes); + HaarClassifierNode128 curNode = getClassifierNode(texHaarClassifierNodes, iNode, d_ClassifierNodes); HaarFeatureDescriptor32 featuresDesc = curNode.getFeatureDesc(); Ncv32u curNodeFeaturesNum = featuresDesc.getNumFeatures(); Ncv32u iFeature = featuresDesc.getFeaturesOffset(); @@ -310,19 +272,17 @@ __global__ void applyHaarClassifierAnchorParallel(Ncv32u *d_IImg, Ncv32u IImgStr { Ncv32f rectWeight; Ncv32u rectX, rectY, rectWidth, rectHeight; - getFeature - (iFeature + iRect, d_Features, - &rectWeight, &rectX, &rectY, &rectWidth, &rectHeight); + getFeature (texHaarFeatures, iFeature + iRect, d_Features, &rectWeight, &rectX, &rectY, &rectWidth, &rectHeight); Ncv32u iioffsTL = (y_offs + rectY) * IImgStride + (x_offs + rectX); Ncv32u iioffsTR = iioffsTL + rectWidth; Ncv32u iioffsBL = iioffsTL + rectHeight * IImgStride; Ncv32u iioffsBR = iioffsBL + rectWidth; - Ncv32u rectSum = getElemIImg(iioffsBR, d_IImg) - - getElemIImg(iioffsBL, d_IImg) + - getElemIImg(iioffsTL, d_IImg) - - getElemIImg(iioffsTR, d_IImg); + Ncv32u rectSum = getElemIImg(texImg, iioffsBR, d_IImg) - + getElemIImg(texImg, iioffsBL, d_IImg) + + getElemIImg(texImg, iioffsTL, d_IImg) - + getElemIImg(texImg, iioffsTR, d_IImg); #if defined CPU_FP_COMPLIANCE || defined DISABLE_MAD_SELECTIVELY curNodeVal += __fmul_rn((Ncv32f)rectSum, rectWeight); @@ -393,15 +353,10 @@ __global__ void applyHaarClassifierAnchorParallel(Ncv32u *d_IImg, Ncv32u IImgStr } -template -__global__ void applyHaarClassifierClassifierParallel(Ncv32u *d_IImg, Ncv32u IImgStride, - Ncv32f *d_weights, Ncv32u weightsStride, - HaarFeature64 *d_Features, HaarClassifierNode128 *d_ClassifierNodes, HaarStage64 *d_Stages, - Ncv32u *d_inMask, Ncv32u *d_outMask, - Ncv32u mask1Dlen, Ncv32u mask2Dstride, - NcvSize32u anchorsRoi, Ncv32u startStageInc, Ncv32u endStageExc, Ncv32f scaleArea) +template +__global__ void applyHaarClassifierClassifierParallel(cv::cudev::TexturePtr texImg, cv::cudev::TexturePtr texHaarFeatures, cv::cudev::TexturePtr texHaarClassifierNodes, Ncv32u *d_IImg, + Ncv32u IImgStride, Ncv32f *d_weights, Ncv32u weightsStride, HaarFeature64 *d_Features, HaarClassifierNode128 *d_ClassifierNodes, HaarStage64 *d_Stages, Ncv32u *d_inMask, Ncv32u *d_outMask, + Ncv32u mask1Dlen, Ncv32u mask2Dstride, NcvSize32u anchorsRoi, Ncv32u startStageInc, Ncv32u endStageExc, Ncv32f scaleArea) { Ncv32u maskOffset = MAX_GRID_DIM * blockIdx.y + blockIdx.x; @@ -439,7 +394,7 @@ __global__ void applyHaarClassifierClassifierParallel(Ncv32u *d_IImg, Ncv32u IIm while (bMoreNodesToTraverse) { - HaarClassifierNode128 curNode = getClassifierNode(iNode, d_ClassifierNodes); + HaarClassifierNode128 curNode = getClassifierNode(texHaarClassifierNodes, iNode, d_ClassifierNodes); HaarFeatureDescriptor32 featuresDesc = curNode.getFeatureDesc(); Ncv32u curNodeFeaturesNum = featuresDesc.getNumFeatures(); Ncv32u iFeature = featuresDesc.getFeaturesOffset(); @@ -450,19 +405,17 @@ __global__ void applyHaarClassifierClassifierParallel(Ncv32u *d_IImg, Ncv32u IIm { Ncv32f rectWeight; Ncv32u rectX, rectY, rectWidth, rectHeight; - getFeature - (iFeature + iRect, d_Features, - &rectWeight, &rectX, &rectY, &rectWidth, &rectHeight); + getFeature (texHaarFeatures, iFeature + iRect, d_Features, &rectWeight, &rectX, &rectY, &rectWidth, &rectHeight); Ncv32u iioffsTL = (y_offs + rectY) * IImgStride + (x_offs + rectX); Ncv32u iioffsTR = iioffsTL + rectWidth; Ncv32u iioffsBL = iioffsTL + rectHeight * IImgStride; Ncv32u iioffsBR = iioffsBL + rectWidth; - Ncv32u rectSum = getElemIImg(iioffsBR, d_IImg) - - getElemIImg(iioffsBL, d_IImg) + - getElemIImg(iioffsTL, d_IImg) - - getElemIImg(iioffsTR, d_IImg); + Ncv32u rectSum = getElemIImg(texImg, iioffsBR, d_IImg) - + getElemIImg(texImg, iioffsBL, d_IImg) + + getElemIImg(texImg, iioffsTL, d_IImg) - + getElemIImg(texImg, iioffsTR, d_IImg); #if defined CPU_FP_COMPLIANCE || defined DISABLE_MAD_SELECTIVELY curNodeVal += __fmul_rn((Ncv32f)rectSum, rectWeight); @@ -578,8 +531,9 @@ struct applyHaarClassifierAnchorParallelFunctor { dim3 gridConf, blockConf; cudaStream_t cuStream; - - //Kernel arguments are stored as members; + cv::cudev::TexturePtr texImg; + cv::cudev::TexturePtr texHaarFeatures; + cv::cudev::TexturePtr texHaarClassifierNodes; Ncv32u *d_IImg; Ncv32u IImgStride; Ncv32f *d_weights; @@ -597,32 +551,12 @@ struct applyHaarClassifierAnchorParallelFunctor Ncv32f scaleArea; //Arguments are passed through the constructor - applyHaarClassifierAnchorParallelFunctor(dim3 _gridConf, dim3 _blockConf, cudaStream_t _cuStream, - Ncv32u *_d_IImg, Ncv32u _IImgStride, - Ncv32f *_d_weights, Ncv32u _weightsStride, - HaarFeature64 *_d_Features, HaarClassifierNode128 *_d_ClassifierNodes, HaarStage64 *_d_Stages, - Ncv32u *_d_inMask, Ncv32u *_d_outMask, - Ncv32u _mask1Dlen, Ncv32u _mask2Dstride, - NcvSize32u _anchorsRoi, Ncv32u _startStageInc, - Ncv32u _endStageExc, Ncv32f _scaleArea) : - gridConf(_gridConf), - blockConf(_blockConf), - cuStream(_cuStream), - d_IImg(_d_IImg), - IImgStride(_IImgStride), - d_weights(_d_weights), - weightsStride(_weightsStride), - d_Features(_d_Features), - d_ClassifierNodes(_d_ClassifierNodes), - d_Stages(_d_Stages), - d_inMask(_d_inMask), - d_outMask(_d_outMask), - mask1Dlen(_mask1Dlen), - mask2Dstride(_mask2Dstride), - anchorsRoi(_anchorsRoi), - startStageInc(_startStageInc), - endStageExc(_endStageExc), - scaleArea(_scaleArea) + applyHaarClassifierAnchorParallelFunctor(cv::cudev::TexturePtr texImg_, cv::cudev::TexturePtr texHaarFeatures_, cv::cudev::TexturePtr texHaarClassifierNodes_, dim3 _gridConf, + dim3 _blockConf, cudaStream_t _cuStream, Ncv32u *_d_IImg, Ncv32u _IImgStride, Ncv32f *_d_weights, Ncv32u _weightsStride, HaarFeature64 *_d_Features, HaarClassifierNode128 *_d_ClassifierNodes, + HaarStage64 *_d_Stages, Ncv32u *_d_inMask, Ncv32u *_d_outMask, Ncv32u _mask1Dlen, Ncv32u _mask2Dstride, NcvSize32u _anchorsRoi, Ncv32u _startStageInc, Ncv32u _endStageExc, Ncv32f _scaleArea) : + gridConf(_gridConf), blockConf(_blockConf), cuStream(_cuStream), texImg(texImg_), texHaarFeatures(texHaarFeatures_), texHaarClassifierNodes(texHaarClassifierNodes_), d_IImg(_d_IImg), IImgStride(_IImgStride), + d_weights(_d_weights), weightsStride(_weightsStride), d_Features(_d_Features), d_ClassifierNodes(_d_ClassifierNodes), d_Stages(_d_Stages), d_inMask(_d_inMask), d_outMask(_d_outMask), mask1Dlen(_mask1Dlen), + mask2Dstride(_mask2Dstride), anchorsRoi(_anchorsRoi), startStageInc(_startStageInc), endStageExc(_endStageExc), scaleArea(_scaleArea) {} template @@ -635,43 +569,19 @@ struct applyHaarClassifierAnchorParallelFunctor Loki::TL::TypeAt::Result::value, Loki::TL::TypeAt::Result::value, Loki::TL::TypeAt::Result::value > - <<>> - (d_IImg, IImgStride, - d_weights, weightsStride, - d_Features, d_ClassifierNodes, d_Stages, - d_inMask, d_outMask, - mask1Dlen, mask2Dstride, - anchorsRoi, startStageInc, - endStageExc, scaleArea); + <<>> (texImg, texHaarFeatures, texHaarClassifierNodes, d_IImg, IImgStride, d_weights, weightsStride, d_Features, d_ClassifierNodes, d_Stages, d_inMask, + d_outMask, mask1Dlen, mask2Dstride, anchorsRoi, startStageInc, endStageExc, scaleArea); } }; -void applyHaarClassifierAnchorParallelDynTemplate(NcvBool tbInitMaskPositively, - NcvBool tbCacheTextureIImg, - NcvBool tbCacheTextureCascade, - NcvBool tbReadPixelIndexFromVector, - NcvBool tbDoAtomicCompaction, - - dim3 gridConf, dim3 blockConf, cudaStream_t cuStream, - - Ncv32u *d_IImg, Ncv32u IImgStride, - Ncv32f *d_weights, Ncv32u weightsStride, - HaarFeature64 *d_Features, HaarClassifierNode128 *d_ClassifierNodes, HaarStage64 *d_Stages, - Ncv32u *d_inMask, Ncv32u *d_outMask, - Ncv32u mask1Dlen, Ncv32u mask2Dstride, - NcvSize32u anchorsRoi, Ncv32u startStageInc, - Ncv32u endStageExc, Ncv32f scaleArea) +void applyHaarClassifierAnchorParallelDynTemplate(NcvBool tbInitMaskPositively, NcvBool tbCacheTextureIImg, NcvBool tbCacheTextureCascade, NcvBool tbReadPixelIndexFromVector, NcvBool tbDoAtomicCompaction, + dim3 gridConf, dim3 blockConf, cudaStream_t cuStream, cv::cudev::TexturePtr texImg, cv::cudev::TexturePtr texHaarFeatures, cv::cudev::TexturePtr texHaarClassifierNodes, Ncv32u *d_IImg, + Ncv32u IImgStride, Ncv32f *d_weights, Ncv32u weightsStride, HaarFeature64 *d_Features, HaarClassifierNode128 *d_ClassifierNodes, HaarStage64 *d_Stages, Ncv32u *d_inMask, Ncv32u *d_outMask, + Ncv32u mask1Dlen, Ncv32u mask2Dstride, NcvSize32u anchorsRoi, Ncv32u startStageInc, Ncv32u endStageExc, Ncv32f scaleArea) { - - applyHaarClassifierAnchorParallelFunctor functor(gridConf, blockConf, cuStream, - d_IImg, IImgStride, - d_weights, weightsStride, - d_Features, d_ClassifierNodes, d_Stages, - d_inMask, d_outMask, - mask1Dlen, mask2Dstride, - anchorsRoi, startStageInc, - endStageExc, scaleArea); + applyHaarClassifierAnchorParallelFunctor functor(texImg, texHaarFeatures, texHaarClassifierNodes, gridConf, blockConf, cuStream, d_IImg, IImgStride, d_weights, weightsStride, d_Features, d_ClassifierNodes, d_Stages, + d_inMask, d_outMask, mask1Dlen, mask2Dstride, anchorsRoi, startStageInc, endStageExc, scaleArea); //Second parameter is the number of "dynamic" template parameters NCVRuntimeTemplateBool::KernelCaller @@ -688,8 +598,9 @@ struct applyHaarClassifierClassifierParallelFunctor { dim3 gridConf, blockConf; cudaStream_t cuStream; - - //Kernel arguments are stored as members; + cv::cudev::TexturePtr texImg; + cv::cudev::TexturePtr texHaarFeatures; + cv::cudev::TexturePtr texHaarClassifierNodes; Ncv32u *d_IImg; Ncv32u IImgStride; Ncv32f *d_weights; @@ -707,32 +618,13 @@ struct applyHaarClassifierClassifierParallelFunctor Ncv32f scaleArea; //Arguments are passed through the constructor - applyHaarClassifierClassifierParallelFunctor(dim3 _gridConf, dim3 _blockConf, cudaStream_t _cuStream, - Ncv32u *_d_IImg, Ncv32u _IImgStride, - Ncv32f *_d_weights, Ncv32u _weightsStride, - HaarFeature64 *_d_Features, HaarClassifierNode128 *_d_ClassifierNodes, HaarStage64 *_d_Stages, - Ncv32u *_d_inMask, Ncv32u *_d_outMask, - Ncv32u _mask1Dlen, Ncv32u _mask2Dstride, - NcvSize32u _anchorsRoi, Ncv32u _startStageInc, - Ncv32u _endStageExc, Ncv32f _scaleArea) : - gridConf(_gridConf), - blockConf(_blockConf), - cuStream(_cuStream), - d_IImg(_d_IImg), - IImgStride(_IImgStride), - d_weights(_d_weights), - weightsStride(_weightsStride), - d_Features(_d_Features), - d_ClassifierNodes(_d_ClassifierNodes), - d_Stages(_d_Stages), - d_inMask(_d_inMask), - d_outMask(_d_outMask), - mask1Dlen(_mask1Dlen), - mask2Dstride(_mask2Dstride), - anchorsRoi(_anchorsRoi), - startStageInc(_startStageInc), - endStageExc(_endStageExc), - scaleArea(_scaleArea) + applyHaarClassifierClassifierParallelFunctor(dim3 _gridConf, dim3 _blockConf, cudaStream_t _cuStream, cv::cudev::TexturePtr texImg_, cv::cudev::TexturePtr texHaarFeatures_, + cv::cudev::TexturePtr texHaarClassifierNodes_, Ncv32u *_d_IImg, Ncv32u _IImgStride, Ncv32f *_d_weights, Ncv32u _weightsStride, HaarFeature64 *_d_Features, + HaarClassifierNode128 *_d_ClassifierNodes, HaarStage64 *_d_Stages, Ncv32u *_d_inMask, Ncv32u *_d_outMask, Ncv32u _mask1Dlen, Ncv32u _mask2Dstride, NcvSize32u _anchorsRoi, + Ncv32u _startStageInc, Ncv32u _endStageExc, Ncv32f _scaleArea) : gridConf(_gridConf), blockConf(_blockConf), cuStream(_cuStream), texImg(texImg_), texHaarFeatures(texHaarFeatures_), + texHaarClassifierNodes(texHaarClassifierNodes_), d_IImg(_d_IImg), IImgStride(_IImgStride), d_weights(_d_weights), weightsStride(_weightsStride), d_Features(_d_Features), + d_ClassifierNodes(_d_ClassifierNodes), d_Stages(_d_Stages), d_inMask(_d_inMask), d_outMask(_d_outMask), mask1Dlen(_mask1Dlen), mask2Dstride(_mask2Dstride), anchorsRoi(_anchorsRoi), + startStageInc(_startStageInc), endStageExc(_endStageExc), scaleArea(_scaleArea) {} template @@ -743,40 +635,19 @@ struct applyHaarClassifierClassifierParallelFunctor Loki::TL::TypeAt::Result::value, Loki::TL::TypeAt::Result::value, Loki::TL::TypeAt::Result::value > - <<>> - (d_IImg, IImgStride, - d_weights, weightsStride, - d_Features, d_ClassifierNodes, d_Stages, - d_inMask, d_outMask, - mask1Dlen, mask2Dstride, - anchorsRoi, startStageInc, - endStageExc, scaleArea); + <<>> (texImg, texHaarFeatures, texHaarClassifierNodes, d_IImg, IImgStride, d_weights, weightsStride, d_Features, d_ClassifierNodes, d_Stages, d_inMask, + d_outMask, mask1Dlen, mask2Dstride, anchorsRoi, startStageInc, endStageExc, scaleArea); } }; -void applyHaarClassifierClassifierParallelDynTemplate(NcvBool tbCacheTextureIImg, - NcvBool tbCacheTextureCascade, - NcvBool tbDoAtomicCompaction, - - dim3 gridConf, dim3 blockConf, cudaStream_t cuStream, - - Ncv32u *d_IImg, Ncv32u IImgStride, - Ncv32f *d_weights, Ncv32u weightsStride, - HaarFeature64 *d_Features, HaarClassifierNode128 *d_ClassifierNodes, HaarStage64 *d_Stages, - Ncv32u *d_inMask, Ncv32u *d_outMask, - Ncv32u mask1Dlen, Ncv32u mask2Dstride, - NcvSize32u anchorsRoi, Ncv32u startStageInc, - Ncv32u endStageExc, Ncv32f scaleArea) +void applyHaarClassifierClassifierParallelDynTemplate(NcvBool tbCacheTextureIImg, NcvBool tbCacheTextureCascade, NcvBool tbDoAtomicCompaction, dim3 gridConf, dim3 blockConf, cudaStream_t cuStream, + cv::cudev::TexturePtr texImg, cv::cudev::TexturePtr texHaarFeatures, cv::cudev::TexturePtr texHaarClassifierNodes, Ncv32u *d_IImg, Ncv32u IImgStride, Ncv32f *d_weights, + Ncv32u weightsStride, HaarFeature64 *d_Features, HaarClassifierNode128 *d_ClassifierNodes, HaarStage64 *d_Stages, Ncv32u *d_inMask, Ncv32u *d_outMask, Ncv32u mask1Dlen, Ncv32u mask2Dstride, + NcvSize32u anchorsRoi, Ncv32u startStageInc, Ncv32u endStageExc, Ncv32f scaleArea) { - applyHaarClassifierClassifierParallelFunctor functor(gridConf, blockConf, cuStream, - d_IImg, IImgStride, - d_weights, weightsStride, - d_Features, d_ClassifierNodes, d_Stages, - d_inMask, d_outMask, - mask1Dlen, mask2Dstride, - anchorsRoi, startStageInc, - endStageExc, scaleArea); + applyHaarClassifierClassifierParallelFunctor functor(gridConf, blockConf, cuStream, texImg, texHaarFeatures, texHaarClassifierNodes, d_IImg, IImgStride, d_weights, weightsStride, d_Features, + d_ClassifierNodes, d_Stages, d_inMask, d_outMask, mask1Dlen, mask2Dstride, anchorsRoi, startStageInc, endStageExc, scaleArea); //Second parameter is the number of "dynamic" template parameters NCVRuntimeTemplateBool::KernelCaller @@ -1015,31 +886,15 @@ NCVStatus ncvApplyHaarClassifierCascade_device(NCVMatrix &integral, NCV_SKIP_COND_BEGIN + cv::cudev::Texture texImg; if (bTexCacheIImg) - { - cudaChannelFormatDesc cfdTexIImage; - cfdTexIImage = cudaCreateChannelDesc(); + texImg = cv::cudev::Texture((anchorsRoi.height + haar.ClassifierSize.height) * integral.pitch(), integral.ptr()); - size_t alignmentOffset; - ncvAssertCUDAReturn(cudaBindTexture(&alignmentOffset, texIImage, integral.ptr(), cfdTexIImage, - (anchorsRoi.height + haar.ClassifierSize.height) * integral.pitch()), NCV_CUDA_ERROR); - ncvAssertReturn(alignmentOffset==0, NCV_TEXTURE_BIND_ERROR); - } - - if (bTexCacheCascade) - { - cudaChannelFormatDesc cfdTexHaarFeatures; - cudaChannelFormatDesc cfdTexHaarClassifierNodes; - cfdTexHaarFeatures = cudaCreateChannelDesc(); - cfdTexHaarClassifierNodes = cudaCreateChannelDesc(); - - size_t alignmentOffset; - ncvAssertCUDAReturn(cudaBindTexture(&alignmentOffset, texHaarFeatures, - d_HaarFeatures.ptr(), cfdTexHaarFeatures,sizeof(HaarFeature64) * haar.NumFeatures), NCV_CUDA_ERROR); - ncvAssertReturn(alignmentOffset==0, NCV_TEXTURE_BIND_ERROR); - ncvAssertCUDAReturn(cudaBindTexture(&alignmentOffset, texHaarClassifierNodes, - d_HaarNodes.ptr(), cfdTexHaarClassifierNodes, sizeof(HaarClassifierNode128) * haar.NumClassifierTotalNodes), NCV_CUDA_ERROR); - ncvAssertReturn(alignmentOffset==0, NCV_TEXTURE_BIND_ERROR); + cv::cudev::Texture texHaarFeatures; + cv::cudev::Texture texHaarClassifierNodes; + if (bTexCacheCascade) { + texHaarFeatures = cv::cudev::Texture(sizeof(HaarFeature64) * haar.NumFeatures, reinterpret_cast(d_HaarFeatures.ptr())); + texHaarClassifierNodes = cv::cudev::Texture(sizeof(HaarClassifierNode128) * haar.NumClassifierTotalNodes, reinterpret_cast(d_HaarNodes.ptr())); } Ncv32u stageStartAnchorParallel = 0; @@ -1130,26 +985,10 @@ NCVStatus ncvApplyHaarClassifierCascade_device(NCVMatrix &integral, dim3 grid1(((d_pixelMask.stride() + NUM_THREADS_ANCHORSPARALLEL - 1) / NUM_THREADS_ANCHORSPARALLEL), anchorsRoi.height); dim3 block1(NUM_THREADS_ANCHORSPARALLEL); - applyHaarClassifierAnchorParallelDynTemplate( - true, //tbInitMaskPositively - bTexCacheIImg, //tbCacheTextureIImg - bTexCacheCascade, //tbCacheTextureCascade - pixParallelStageStops[pixParallelStageStopsIndex] != 0,//tbReadPixelIndexFromVector - bDoAtomicCompaction, //tbDoAtomicCompaction - grid1, - block1, - cuStream, - integral.ptr(), integral.stride(), - d_weights.ptr(), d_weights.stride(), - d_HaarFeatures.ptr(), d_HaarNodes.ptr(), d_HaarStages.ptr(), - d_ptrNowData->ptr(), - bDoAtomicCompaction ? d_ptrNowTmp->ptr() : d_ptrNowData->ptr(), - 0, - d_pixelMask.stride(), - anchorsRoi, - pixParallelStageStops[pixParallelStageStopsIndex], - pixParallelStageStops[pixParallelStageStopsIndex+1], - scaleAreaPixels); + applyHaarClassifierAnchorParallelDynTemplate( true, bTexCacheIImg, bTexCacheCascade, pixParallelStageStops[pixParallelStageStopsIndex] != 0, bDoAtomicCompaction, grid1, block1, cuStream, + texImg, texHaarFeatures, texHaarClassifierNodes, integral.ptr(), integral.stride(), d_weights.ptr(), d_weights.stride(), d_HaarFeatures.ptr(), d_HaarNodes.ptr(), d_HaarStages.ptr(), + d_ptrNowData->ptr(), bDoAtomicCompaction ? d_ptrNowTmp->ptr() : d_ptrNowData->ptr(), 0, d_pixelMask.stride(), anchorsRoi, pixParallelStageStops[pixParallelStageStopsIndex], + pixParallelStageStops[pixParallelStageStopsIndex+1], scaleAreaPixels); ncvAssertCUDAReturn(cudaGetLastError(), NCV_CUDA_ERROR); if (bDoAtomicCompaction) @@ -1200,26 +1039,10 @@ NCVStatus ncvApplyHaarClassifierCascade_device(NCVMatrix &integral, } dim3 block2(NUM_THREADS_ANCHORSPARALLEL); - applyHaarClassifierAnchorParallelDynTemplate( - false, //tbInitMaskPositively - bTexCacheIImg, //tbCacheTextureIImg - bTexCacheCascade, //tbCacheTextureCascade - pixParallelStageStops[pixParallelStageStopsIndex] != 0 || pixelStep != 1 || bMaskElements,//tbReadPixelIndexFromVector - bDoAtomicCompaction, //tbDoAtomicCompaction - grid2, - block2, - cuStream, - integral.ptr(), integral.stride(), - d_weights.ptr(), d_weights.stride(), - d_HaarFeatures.ptr(), d_HaarNodes.ptr(), d_HaarStages.ptr(), - d_ptrNowData->ptr(), - bDoAtomicCompaction ? d_ptrNowTmp->ptr() : d_ptrNowData->ptr(), - numDetections, - d_pixelMask.stride(), - anchorsRoi, - pixParallelStageStops[pixParallelStageStopsIndex], - pixParallelStageStops[pixParallelStageStopsIndex+1], - scaleAreaPixels); + applyHaarClassifierAnchorParallelDynTemplate( false, bTexCacheIImg, bTexCacheCascade, pixParallelStageStops[pixParallelStageStopsIndex] != 0 || pixelStep != 1 || bMaskElements, bDoAtomicCompaction, + grid2, block2, cuStream, texImg, texHaarFeatures, texHaarClassifierNodes, integral.ptr(), integral.stride(), d_weights.ptr(), d_weights.stride(), d_HaarFeatures.ptr(), d_HaarNodes.ptr(), + d_HaarStages.ptr(), d_ptrNowData->ptr(), bDoAtomicCompaction ? d_ptrNowTmp->ptr() : d_ptrNowData->ptr(), numDetections, d_pixelMask.stride(), anchorsRoi, + pixParallelStageStops[pixParallelStageStopsIndex], pixParallelStageStops[pixParallelStageStopsIndex+1], scaleAreaPixels); ncvAssertCUDAReturn(cudaGetLastError(), NCV_CUDA_ERROR); if (bDoAtomicCompaction) @@ -1263,24 +1086,9 @@ NCVStatus ncvApplyHaarClassifierCascade_device(NCVMatrix &integral, } dim3 block3(NUM_THREADS_CLASSIFIERPARALLEL); - applyHaarClassifierClassifierParallelDynTemplate( - bTexCacheIImg, //tbCacheTextureIImg - bTexCacheCascade, //tbCacheTextureCascade - bDoAtomicCompaction, //tbDoAtomicCompaction - grid3, - block3, - cuStream, - integral.ptr(), integral.stride(), - d_weights.ptr(), d_weights.stride(), - d_HaarFeatures.ptr(), d_HaarNodes.ptr(), d_HaarStages.ptr(), - d_ptrNowData->ptr(), - bDoAtomicCompaction ? d_ptrNowTmp->ptr() : d_ptrNowData->ptr(), - numDetections, - d_pixelMask.stride(), - anchorsRoi, - stageMiddleSwitch, - stageEndClassifierParallel, - scaleAreaPixels); + applyHaarClassifierClassifierParallelDynTemplate(bTexCacheIImg, bTexCacheCascade, bDoAtomicCompaction, grid3, block3, cuStream, texImg, texHaarFeatures, texHaarClassifierNodes, integral.ptr(), integral.stride(), + d_weights.ptr(), d_weights.stride(), d_HaarFeatures.ptr(), d_HaarNodes.ptr(), d_HaarStages.ptr(), d_ptrNowData->ptr(), bDoAtomicCompaction ? d_ptrNowTmp->ptr() : d_ptrNowData->ptr(), numDetections, + d_pixelMask.stride(), anchorsRoi, stageMiddleSwitch, stageEndClassifierParallel, scaleAreaPixels); ncvAssertCUDAReturn(cudaGetLastError(), NCV_CUDA_ERROR); if (bDoAtomicCompaction) diff --git a/modules/cudalegacy/src/cuda/NPP_staging.cu b/modules/cudalegacy/src/cuda/NPP_staging.cu index 90880d56cc5..b7a24ee0360 100644 --- a/modules/cudalegacy/src/cuda/NPP_staging.cu +++ b/modules/cudalegacy/src/cuda/NPP_staging.cu @@ -48,12 +48,7 @@ #include "opencv2/cudev.hpp" #include "opencv2/cudalegacy/NPP_staging.hpp" - - -texture tex8u; -texture tex32u; -texture tex64u; - +#include //============================================================================== // @@ -71,7 +66,6 @@ cudaStream_t nppStGetActiveCUDAstream(void) } - cudaStream_t nppStSetActiveCUDAstream(cudaStream_t cudaStream) { cudaStream_t tmp = nppStream; @@ -117,25 +111,25 @@ private: template -inline __device__ T readElem(T *d_src, Ncv32u texOffs, Ncv32u srcStride, Ncv32u curElemOffs); +inline __device__ T readElem(cv::cudev::TexturePtr tex8u, T *d_src, Ncv32u texOffs, Ncv32u srcStride, Ncv32u curElemOffs); template<> -inline __device__ Ncv8u readElem(Ncv8u *d_src, Ncv32u texOffs, Ncv32u srcStride, Ncv32u curElemOffs) +inline __device__ Ncv8u readElem(cv::cudev::TexturePtr tex8u, Ncv8u* d_src, Ncv32u texOffs, Ncv32u srcStride, Ncv32u curElemOffs) { - return tex1Dfetch(tex8u, texOffs + srcStride * blockIdx.x + curElemOffs); + return tex8u(texOffs + srcStride * blockIdx.x + curElemOffs); } template<> -inline __device__ Ncv32u readElem(Ncv32u *d_src, Ncv32u texOffs, Ncv32u srcStride, Ncv32u curElemOffs) +inline __device__ Ncv32u readElem(cv::cudev::TexturePtr tex8u, Ncv32u *d_src, Ncv32u texOffs, Ncv32u srcStride, Ncv32u curElemOffs) { return d_src[curElemOffs]; } template<> -inline __device__ Ncv32f readElem(Ncv32f *d_src, Ncv32u texOffs, Ncv32u srcStride, Ncv32u curElemOffs) +inline __device__ Ncv32f readElem(cv::cudev::TexturePtr tex8u, Ncv32f *d_src, Ncv32u texOffs, Ncv32u srcStride, Ncv32u curElemOffs) { return d_src[curElemOffs]; } @@ -160,8 +154,7 @@ inline __device__ Ncv32f readElem(Ncv32f *d_src, Ncv32u texOffs, Ncv32u * \return None */ template -__global__ void scanRows(T_in *d_src, Ncv32u texOffs, Ncv32u srcWidth, Ncv32u srcStride, - T_out *d_II, Ncv32u IIstride) +__global__ void scanRows(cv::cudev::TexturePtr tex8u, T_in *d_src, Ncv32u texOffs, Ncv32u srcWidth, Ncv32u srcStride, T_out *d_II, Ncv32u IIstride) { //advance pointers to the current line if (sizeof(T_in) != 1) @@ -190,7 +183,7 @@ __global__ void scanRows(T_in *d_src, Ncv32u texOffs, Ncv32u srcWidth, Ncv32u sr if (curElemOffs < srcWidth) { //load elements - curElem = readElem(d_src, texOffs, srcStride, curElemOffs); + curElem = readElem(tex8u, d_src, texOffs, srcStride, curElemOffs); } curElemMod = _scanElemOp::scanElemOp(curElem); @@ -224,25 +217,9 @@ template NCVStatus scanRowsWrapperDevice(T_in *d_src, Ncv32u srcStride, T_out *d_dst, Ncv32u dstStride, NcvSize32u roi) { - cudaChannelFormatDesc cfdTex; - size_t alignmentOffset = 0; - if (sizeof(T_in) == 1) - { - cfdTex = cudaCreateChannelDesc(); - ncvAssertCUDAReturn(cudaBindTexture(&alignmentOffset, tex8u, d_src, cfdTex, roi.height * srcStride), NPPST_TEXTURE_BIND_ERROR); - if (alignmentOffset > 0) - { - ncvAssertCUDAReturn(cudaUnbindTexture(tex8u), NCV_CUDA_ERROR); - ncvAssertCUDAReturn(cudaBindTexture(&alignmentOffset, tex8u, d_src, cfdTex, alignmentOffset + roi.height * srcStride), NPPST_TEXTURE_BIND_ERROR); - } - } - scanRows - - <<>> - (d_src, (Ncv32u)alignmentOffset, roi.width, srcStride, d_dst, dstStride); - + cv::cudev::Texture tex8u(static_cast(roi.height * srcStride), (Ncv8u*)d_src); + scanRows <<>> (tex8u, d_src, 0, roi.width, srcStride, d_dst, dstStride); ncvAssertCUDALastErrorReturn(NPPST_CUDA_KERNEL_EXECUTION_ERROR); - return NPPST_SUCCESS; } @@ -585,59 +562,25 @@ NCVStatus nppiStSqrIntegral_8u64u_C1R_host(Ncv8u *h_src, Ncv32u srcStep, const Ncv32u NUM_DOWNSAMPLE_NEAREST_THREADS_X = 32; const Ncv32u NUM_DOWNSAMPLE_NEAREST_THREADS_Y = 8; - -template -__device__ T getElem_Decimate(Ncv32u x, T *d_src); - - -template<> -__device__ Ncv32u getElem_Decimate(Ncv32u x, Ncv32u *d_src) -{ - return tex1Dfetch(tex32u, x); -} - - -template<> -__device__ Ncv32u getElem_Decimate(Ncv32u x, Ncv32u *d_src) -{ - return d_src[x]; -} - - -template<> -__device__ Ncv64u getElem_Decimate(Ncv32u x, Ncv64u *d_src) -{ - uint2 tmp = tex1Dfetch(tex64u, x); - Ncv64u res = (Ncv64u)tmp.y; - res <<= 32; - res |= tmp.x; - return res; -} - - -template<> -__device__ Ncv64u getElem_Decimate(Ncv32u x, Ncv64u *d_src) +template +__global__ void decimate_C1R(T* d_src, Ncv32u srcStep, T* d_dst, Ncv32u dstStep, NcvSize32u dstRoi, Ncv32u scale) { - return d_src[x]; + int curX = blockIdx.x * blockDim.x + threadIdx.x; + int curY = blockIdx.y * blockDim.y + threadIdx.y; + if (curX >= dstRoi.width || curY >= dstRoi.height) return; + d_dst[curY * dstStep + curX] = d_src[(curY * srcStep + curX) * scale]; } - -template -__global__ void decimate_C1R(T *d_src, Ncv32u srcStep, T *d_dst, Ncv32u dstStep, - NcvSize32u dstRoi, Ncv32u scale) +template +__global__ void decimate_C1R(cv::cudev::TexturePtr texSrc, Ncv32u srcStep, T* d_dst, Ncv32u dstStep, + NcvSize32u dstRoi, Ncv32u scale) { int curX = blockIdx.x * blockDim.x + threadIdx.x; int curY = blockIdx.y * blockDim.y + threadIdx.y; - - if (curX >= dstRoi.width || curY >= dstRoi.height) - { - return; - } - - d_dst[curY * dstStep + curX] = getElem_Decimate((curY * srcStep + curX) * scale, d_src); + if (curX >= dstRoi.width || curY >= dstRoi.height) return; + d_dst[curY * dstStep + curX] = texSrc((curY * srcStep + curX) * scale); } - template static NCVStatus decimateWrapperDevice(T *d_src, Ncv32u srcStep, T *d_dst, Ncv32u dstStep, @@ -659,39 +602,12 @@ static NCVStatus decimateWrapperDevice(T *d_src, Ncv32u srcStep, dim3 grid((dstRoi.width + NUM_DOWNSAMPLE_NEAREST_THREADS_X - 1) / NUM_DOWNSAMPLE_NEAREST_THREADS_X, (dstRoi.height + NUM_DOWNSAMPLE_NEAREST_THREADS_Y - 1) / NUM_DOWNSAMPLE_NEAREST_THREADS_Y); dim3 block(NUM_DOWNSAMPLE_NEAREST_THREADS_X, NUM_DOWNSAMPLE_NEAREST_THREADS_Y); - - if (!readThruTexture) - { - decimate_C1R - - <<>> - (d_src, srcStep, d_dst, dstStep, dstRoi, scale); + if (!readThruTexture) { + decimate_C1R<<>>(d_src, srcStep, d_dst, dstStep, dstRoi, scale); } - else - { - cudaChannelFormatDesc cfdTexSrc; - - if (sizeof(T) == sizeof(Ncv32u)) - { - cfdTexSrc = cudaCreateChannelDesc(); - - size_t alignmentOffset; - ncvAssertCUDAReturn(cudaBindTexture(&alignmentOffset, tex32u, d_src, cfdTexSrc, srcRoi.height * srcStep * sizeof(T)), NPPST_TEXTURE_BIND_ERROR); - ncvAssertReturn(alignmentOffset==0, NPPST_TEXTURE_BIND_ERROR); - } - else - { - cfdTexSrc = cudaCreateChannelDesc(); - - size_t alignmentOffset; - ncvAssertCUDAReturn(cudaBindTexture(&alignmentOffset, tex64u, d_src, cfdTexSrc, srcRoi.height * srcStep * sizeof(T)), NPPST_TEXTURE_BIND_ERROR); - ncvAssertReturn(alignmentOffset==0, NPPST_TEXTURE_BIND_ERROR); - } - - decimate_C1R - - <<>> - (d_src, srcStep, d_dst, dstStep, dstRoi, scale); + else { + cv::cudev::Texture texSrc(srcRoi.height * srcStep * sizeof(T), d_src); + decimate_C1R<<>>(texSrc, srcStep, d_dst, dstStep, dstRoi, scale); } ncvAssertCUDALastErrorReturn(NPPST_CUDA_KERNEL_EXECUTION_ERROR); @@ -753,11 +669,7 @@ static NCVStatus decimateWrapperHost(T *h_src, Ncv32u srcStep, implementNppDecimate(32, u) -implementNppDecimate(32, s) -implementNppDecimate(32, f) implementNppDecimate(64, u) -implementNppDecimate(64, s) -implementNppDecimate(64, f) implementNppDecimateHost(32, u) implementNppDecimateHost(32, s) implementNppDecimateHost(32, f) @@ -776,43 +688,29 @@ implementNppDecimateHost(64, f) const Ncv32u NUM_RECTSTDDEV_THREADS = 128; -template -__device__ Ncv32u getElemSum(Ncv32u x, Ncv32u *d_sum) +template +__device__ Ncv32u getElemSum(Ptr2D tex, Ncv32u x, Ncv32u *d_sum) { if (tbCacheTexture) - { - return tex1Dfetch(tex32u, x); - } + return tex(x); else - { return d_sum[x]; - } } -template -__device__ Ncv64u getElemSqSum(Ncv32u x, Ncv64u *d_sqsum) +template +__device__ Ncv64u getElemSqSum(Ptr2D tex, Ncv32u x, Ncv64u *d_sqsum) { if (tbCacheTexture) - { - uint2 tmp = tex1Dfetch(tex64u, x); - Ncv64u res = (Ncv64u)tmp.y; - res <<= 32; - res |= tmp.x; - return res; - } + return tex(x); else - { return d_sqsum[x]; - } } template -__global__ void rectStdDev_32f_C1R(Ncv32u *d_sum, Ncv32u sumStep, - Ncv64u *d_sqsum, Ncv32u sqsumStep, - Ncv32f *d_norm, Ncv32u normStep, - NcvSize32u roi, NcvRect32u rect, Ncv32f invRectArea) +__global__ void rectStdDev_32f_C1R(cv::cudev::TexturePtr texSum, cv::cudev::TexturePtr texSumSq, Ncv32u *d_sum, Ncv32u sumStep, Ncv64u *d_sqsum, Ncv32u sqsumStep, + Ncv32f *d_norm, Ncv32u normStep, NcvSize32u roi, NcvRect32u rect, Ncv32f invRectArea) { Ncv32u x_offs = blockIdx.x * NUM_RECTSTDDEV_THREADS + threadIdx.x; if (x_offs >= roi.width) @@ -824,17 +722,17 @@ __global__ void rectStdDev_32f_C1R(Ncv32u *d_sum, Ncv32u sumStep, Ncv32u sqsum_offset = blockIdx.y * sqsumStep + x_offs; //OPT: try swapping order (could change cache hit/miss ratio) - Ncv32u sum_tl = getElemSum(sum_offset + rect.y * sumStep + rect.x, d_sum); - Ncv32u sum_bl = getElemSum(sum_offset + (rect.y + rect.height) * sumStep + rect.x, d_sum); - Ncv32u sum_tr = getElemSum(sum_offset + rect.y * sumStep + rect.x + rect.width, d_sum); - Ncv32u sum_br = getElemSum(sum_offset + (rect.y + rect.height) * sumStep + rect.x + rect.width, d_sum); + Ncv32u sum_tl = getElemSum(texSum, sum_offset + rect.y * sumStep + rect.x, d_sum); + Ncv32u sum_bl = getElemSum(texSum, sum_offset + (rect.y + rect.height) * sumStep + rect.x, d_sum); + Ncv32u sum_tr = getElemSum(texSum, sum_offset + rect.y * sumStep + rect.x + rect.width, d_sum); + Ncv32u sum_br = getElemSum(texSum, sum_offset + (rect.y + rect.height) * sumStep + rect.x + rect.width, d_sum); Ncv32u sum_val = sum_br + sum_tl - sum_tr - sum_bl; Ncv64u sqsum_tl, sqsum_bl, sqsum_tr, sqsum_br; - sqsum_tl = getElemSqSum(sqsum_offset + rect.y * sqsumStep + rect.x, d_sqsum); - sqsum_bl = getElemSqSum(sqsum_offset + (rect.y + rect.height) * sqsumStep + rect.x, d_sqsum); - sqsum_tr = getElemSqSum(sqsum_offset + rect.y * sqsumStep + rect.x + rect.width, d_sqsum); - sqsum_br = getElemSqSum(sqsum_offset + (rect.y + rect.height) * sqsumStep + rect.x + rect.width, d_sqsum); + sqsum_tl = getElemSqSum(texSumSq, sqsum_offset + rect.y * sqsumStep + rect.x, d_sqsum); + sqsum_bl = getElemSqSum(texSumSq, sqsum_offset + (rect.y + rect.height) * sqsumStep + rect.x, d_sqsum); + sqsum_tr = getElemSqSum(texSumSq, sqsum_offset + rect.y * sqsumStep + rect.x + rect.width, d_sqsum); + sqsum_br = getElemSqSum(texSumSq, sqsum_offset + (rect.y + rect.height) * sqsumStep + rect.x + rect.width, d_sqsum); Ncv64u sqsum_val = sqsum_br + sqsum_tl - sqsum_tr - sqsum_bl; Ncv32f mean = sum_val * invRectArea; @@ -897,31 +795,12 @@ NCVStatus nppiStRectStdDev_32f_C1R(Ncv32u *d_sum, Ncv32u sumStep, dim3 grid(((roi.width + NUM_RECTSTDDEV_THREADS - 1) / NUM_RECTSTDDEV_THREADS), roi.height); dim3 block(NUM_RECTSTDDEV_THREADS); + cv::cudev::Texture texSum((roi.height + rect.y + rect.height) * sumStep * sizeof(Ncv32u), d_sum); + cv::cudev::Texture texSumSq((roi.height + rect.y + rect.height) * sqsumStep * sizeof(Ncv64u), d_sqsum); if (!readThruTexture) - { - rectStdDev_32f_C1R - - <<>> - (d_sum, sumStep, d_sqsum, sqsumStep, d_norm, normStep, roi, rect, invRectArea); - } + rectStdDev_32f_C1R<<>>(texSum, texSumSq, d_sum, sumStep, d_sqsum, sqsumStep, d_norm, normStep, roi, rect, invRectArea); else - { - cudaChannelFormatDesc cfdTexSrc; - cudaChannelFormatDesc cfdTexSqr; - cfdTexSrc = cudaCreateChannelDesc(); - cfdTexSqr = cudaCreateChannelDesc(); - - size_t alignmentOffset; - ncvAssertCUDAReturn(cudaBindTexture(&alignmentOffset, tex32u, d_sum, cfdTexSrc, (roi.height + rect.y + rect.height) * sumStep * sizeof(Ncv32u)), NPPST_TEXTURE_BIND_ERROR); - ncvAssertReturn(alignmentOffset==0, NPPST_TEXTURE_BIND_ERROR); - ncvAssertCUDAReturn(cudaBindTexture(&alignmentOffset, tex64u, d_sqsum, cfdTexSqr, (roi.height + rect.y + rect.height) * sqsumStep * sizeof(Ncv64u)), NPPST_TEXTURE_BIND_ERROR); - ncvAssertReturn(alignmentOffset==0, NPPST_TEXTURE_BIND_ERROR); - - rectStdDev_32f_C1R - - <<>> - (NULL, sumStep, NULL, sqsumStep, d_norm, normStep, roi, rect, invRectArea); - } + rectStdDev_32f_C1R<<>>(texSum, texSumSq, NULL, sumStep, NULL, sqsumStep, d_norm, normStep, roi, rect, invRectArea); ncvAssertCUDALastErrorReturn(NPPST_CUDA_KERNEL_EXECUTION_ERROR); @@ -1553,40 +1432,24 @@ NCVStatus nppsStCompact_32f_host(Ncv32f *h_src, Ncv32u srcLen, // //============================================================================== - -texture texSrc; -texture texKernel; - - -__forceinline__ __device__ float getValueMirrorRow(const int rowOffset, - int i, - int w) +__forceinline__ __device__ float getValueMirrorRow(cv::cudev::TexturePtr< Ncv32f> tex, const int rowOffset, int i, int w) { if (i < 0) i = 1 - i; if (i >= w) i = w + w - i - 1; - return tex1Dfetch (texSrc, rowOffset + i); + return tex(rowOffset + i); } -__forceinline__ __device__ float getValueMirrorColumn(const int offset, - const int rowStep, - int j, - int h) +__forceinline__ __device__ float getValueMirrorColumn(cv::cudev::TexturePtr< Ncv32f> tex, const int offset, const int rowStep, int j, int h) { if (j < 0) j = 1 - j; if (j >= h) j = h + h - j - 1; - return tex1Dfetch (texSrc, offset + j * rowStep); + return tex(offset + j * rowStep); } -__global__ void FilterRowBorderMirror_32f_C1R(Ncv32u srcStep, - Ncv32f *pDst, - NcvSize32u dstSize, - Ncv32u dstStep, - NcvRect32u roi, - Ncv32s nKernelSize, - Ncv32s nAnchor, - Ncv32f multiplier) +__global__ void FilterRowBorderMirror_32f_C1R(cv::cudev::TexturePtr texSrc, cv::cudev::TexturePtr texKernel1, Ncv32u srcStep, Ncv32f *pDst, NcvSize32u dstSize, Ncv32u dstStep, + NcvRect32u roi, Ncv32s nKernelSize, Ncv32s nAnchor, Ncv32f multiplier) { // position within ROI const int ix = blockDim.x * blockIdx.x + threadIdx.x; @@ -1606,22 +1469,16 @@ __global__ void FilterRowBorderMirror_32f_C1R(Ncv32u srcStep, float sum = 0.0f; for (int m = 0; m < nKernelSize; ++m) { - sum += getValueMirrorRow (rowOffset, ix + m - p, roi.width) - * tex1Dfetch (texKernel, m); + sum += getValueMirrorRow(texSrc, rowOffset, ix + m - p, roi.width) + * texKernel1(m); } pDst[iy * dstStep + ix] = sum * multiplier; } -__global__ void FilterColumnBorderMirror_32f_C1R(Ncv32u srcStep, - Ncv32f *pDst, - NcvSize32u dstSize, - Ncv32u dstStep, - NcvRect32u roi, - Ncv32s nKernelSize, - Ncv32s nAnchor, - Ncv32f multiplier) +__global__ void FilterColumnBorderMirror_32f_C1R(cv::cudev::TexturePtr texSrc, cv::cudev::TexturePtr texKernel, Ncv32u srcStep, Ncv32f *pDst, NcvSize32u dstSize, Ncv32u dstStep, + NcvRect32u roi, Ncv32s nKernelSize, Ncv32s nAnchor, Ncv32f multiplier) { const int ix = blockDim.x * blockIdx.x + threadIdx.x; const int iy = blockDim.y * blockIdx.y + threadIdx.y; @@ -1638,15 +1495,15 @@ __global__ void FilterColumnBorderMirror_32f_C1R(Ncv32u srcStep, float sum = 0.0f; for (int m = 0; m < nKernelSize; ++m) { - sum += getValueMirrorColumn (offset, srcStep, iy + m - p, roi.height) - * tex1Dfetch (texKernel, m); + sum += getValueMirrorColumn(texSrc, offset, srcStep, iy + m - p, roi.height) + * texKernel(m); } pDst[ix + iy * dstStep] = sum * multiplier; } -NCVStatus nppiStFilterRowBorder_32f_C1R(const Ncv32f *pSrc, +NCVStatus nppiStFilterRowBorder_32f_C1R(Ncv32f *pSrc, NcvSize32u srcSize, Ncv32u nSrcStep, Ncv32f *pDst, @@ -1654,7 +1511,7 @@ NCVStatus nppiStFilterRowBorder_32f_C1R(const Ncv32f *pSrc, Ncv32u nDstStep, NcvRect32u oROI, NppStBorderType borderType, - const Ncv32f *pKernel, + Ncv32f *pKernel, Ncv32s nKernelSize, Ncv32s nAnchor, Ncv32f multiplier) @@ -1686,12 +1543,8 @@ NCVStatus nppiStFilterRowBorder_32f_C1R(const Ncv32f *pSrc, oROI.height = srcSize.height - oROI.y; } - cudaChannelFormatDesc floatChannel = cudaCreateChannelDesc (); - texSrc.normalized = false; - texKernel.normalized = false; - - cudaBindTexture (0, texSrc, pSrc, floatChannel, srcSize.height * nSrcStep); - cudaBindTexture (0, texKernel, pKernel, floatChannel, nKernelSize * sizeof (Ncv32f)); + cv::cudev::Texture texSrc(srcSize.height * nSrcStep, pSrc); + cv::cudev::Texture texKernel(nKernelSize * sizeof(Ncv32f), pKernel); dim3 ctaSize (32, 6); dim3 gridSize ((oROI.width + ctaSize.x - 1) / ctaSize.x, @@ -1706,8 +1559,7 @@ NCVStatus nppiStFilterRowBorder_32f_C1R(const Ncv32f *pSrc, case nppStBorderWrap: return NPPST_ERROR; case nppStBorderMirror: - FilterRowBorderMirror_32f_C1R <<>> - (srcStep, pDst, dstSize, dstStep, oROI, nKernelSize, nAnchor, multiplier); + FilterRowBorderMirror_32f_C1R <<>>(texSrc, texKernel, srcStep, pDst, dstSize, dstStep, oROI, nKernelSize, nAnchor, multiplier); ncvAssertCUDALastErrorReturn(NPPST_CUDA_KERNEL_EXECUTION_ERROR); break; default: @@ -1718,7 +1570,7 @@ NCVStatus nppiStFilterRowBorder_32f_C1R(const Ncv32f *pSrc, } -NCVStatus nppiStFilterColumnBorder_32f_C1R(const Ncv32f *pSrc, +NCVStatus nppiStFilterColumnBorder_32f_C1R(Ncv32f *pSrc, NcvSize32u srcSize, Ncv32u nSrcStep, Ncv32f *pDst, @@ -1726,7 +1578,7 @@ NCVStatus nppiStFilterColumnBorder_32f_C1R(const Ncv32f *pSrc, Ncv32u nDstStep, NcvRect32u oROI, NppStBorderType borderType, - const Ncv32f *pKernel, + Ncv32f *pKernel, Ncv32s nKernelSize, Ncv32s nAnchor, Ncv32f multiplier) @@ -1758,12 +1610,8 @@ NCVStatus nppiStFilterColumnBorder_32f_C1R(const Ncv32f *pSrc, oROI.height = srcSize.height - oROI.y; } - cudaChannelFormatDesc floatChannel = cudaCreateChannelDesc (); - texSrc.normalized = false; - texKernel.normalized = false; - - cudaBindTexture (0, texSrc, pSrc, floatChannel, srcSize.height * nSrcStep); - cudaBindTexture (0, texKernel, pKernel, floatChannel, nKernelSize * sizeof (Ncv32f)); + cv::cudev::Texture texSrc(srcSize.height * nSrcStep, pSrc); + cv::cudev::Texture texKernel(nKernelSize * sizeof(Ncv32f), pKernel); dim3 ctaSize (32, 6); dim3 gridSize ((oROI.width + ctaSize.x - 1) / ctaSize.x, @@ -1776,8 +1624,7 @@ NCVStatus nppiStFilterColumnBorder_32f_C1R(const Ncv32f *pSrc, case nppStBorderWrap: return NPPST_ERROR; case nppStBorderMirror: - FilterColumnBorderMirror_32f_C1R <<>> - (srcStep, pDst, dstSize, dstStep, oROI, nKernelSize, nAnchor, multiplier); + FilterColumnBorderMirror_32f_C1R <<>>(texSrc, texKernel, srcStep, pDst, dstSize, dstStep, oROI, nKernelSize, nAnchor, multiplier); ncvAssertCUDALastErrorReturn(NPPST_CUDA_KERNEL_EXECUTION_ERROR); break; default: @@ -1800,16 +1647,11 @@ inline Ncv32u iDivUp(Ncv32u num, Ncv32u denom) return (num + denom - 1)/denom; } - -texture tex_src1; -texture tex_src0; - - -__global__ void BlendFramesKernel(const float *u, const float *v, // forward flow - const float *ur, const float *vr, // backward flow - const float *o0, const float *o1, // coverage masks - int w, int h, int s, - float theta, float *out) +__global__ void BlendFramesKernel(cv::cudev::TexturePtr texSrc0, cv::cudev::TexturePtr texSrc1, + const float *u, const float *v, // forward flow + const float *ur, const float *vr, // backward flow + const float *o0, const float *o1, // coverage masks + int w, int h, int s, float theta, float *out) { const int ix = threadIdx.x + blockDim.x * blockIdx.x; const int iy = threadIdx.y + blockDim.y * blockIdx.y; @@ -1829,27 +1671,17 @@ __global__ void BlendFramesKernel(const float *u, const float *v, // forward f bool b0 = o0[pos] > 1e-4f; bool b1 = o1[pos] > 1e-4f; - if (b0 && b1) - { - // pixel is visible on both frames - out[pos] = tex2D(tex_src0, x - _u * theta, y - _v * theta) * (1.0f - theta) + - tex2D(tex_src1, x + _u * (1.0f - theta), y + _v * (1.0f - theta)) * theta; - } - else if (b0) - { - // visible on the first frame only - out[pos] = tex2D(tex_src0, x - _u * theta, y - _v * theta); - } - else - { - // visible on the second frame only - out[pos] = tex2D(tex_src1, x - _ur * (1.0f - theta), y - _vr * (1.0f - theta)); - } + if (b0 && b1) // pixel is visible on both frames + out[pos] = texSrc0(y - _v * theta, x - _u * theta)* (1.0f - theta) + texSrc0(y + _v * (1.0f - theta), x + _u * (1.0f - theta)) * theta; + else if (b0) // visible on the first frame only + out[pos] = texSrc0(y - _v * theta, x - _u * theta); + else // visible on the second frame only + out[pos] = texSrc1(y - _vr * (1.0f - theta), x - _ur * (1.0f - theta)); } -NCVStatus BlendFrames(const Ncv32f *src0, - const Ncv32f *src1, +NCVStatus BlendFrames(Ncv32f *src0, + Ncv32f *src1, const Ncv32f *ufi, const Ncv32f *vfi, const Ncv32f *ubi, @@ -1862,29 +1694,13 @@ NCVStatus BlendFrames(const Ncv32f *src0, Ncv32f theta, Ncv32f *out) { - tex_src1.addressMode[0] = cudaAddressModeClamp; - tex_src1.addressMode[1] = cudaAddressModeClamp; - tex_src1.filterMode = cudaFilterModeLinear; - tex_src1.normalized = false; - - tex_src0.addressMode[0] = cudaAddressModeClamp; - tex_src0.addressMode[1] = cudaAddressModeClamp; - tex_src0.filterMode = cudaFilterModeLinear; - tex_src0.normalized = false; - - cudaChannelFormatDesc desc = cudaCreateChannelDesc (); const Ncv32u pitch = stride * sizeof (float); - ncvAssertCUDAReturn (cudaBindTexture2D (0, tex_src1, src1, desc, width, height, pitch), NPPST_TEXTURE_BIND_ERROR); - ncvAssertCUDAReturn (cudaBindTexture2D (0, tex_src0, src0, desc, width, height, pitch), NPPST_TEXTURE_BIND_ERROR); - + cv::cudev::Texture texSrc0(height, width, src0, pitch, false, cudaFilterModeLinear); + cv::cudev::Texture texSrc1(height, width, src1, pitch, false, cudaFilterModeLinear); dim3 threads (32, 4); dim3 blocks (iDivUp (width, threads.x), iDivUp (height, threads.y)); - - BlendFramesKernel<<>> - (ufi, vfi, ubi, vbi, o1, o2, width, height, stride, theta, out); - + BlendFramesKernel<<>>(texSrc0, texSrc1, ufi, vfi, ubi, vbi, o1, o2, width, height, stride, theta, out); ncvAssertCUDALastErrorReturn(NPPST_CUDA_KERNEL_EXECUTION_ERROR); - return NPPST_SUCCESS; } @@ -2255,44 +2071,27 @@ NCVStatus nppiStVectorWarp_PSF2x2_32f_C1(const Ncv32f *pSrc, // //============================================================================== - -texture texSrc2D; - - __forceinline__ -__device__ float processLine(int spos, - float xmin, - float xmax, - int ixmin, - int ixmax, - float fxmin, - float cxmax) +__device__ float processLine(cv::cudev::TexturePtr tex, int spos, float xmin, float xmax, int ixmin, int ixmax, float fxmin, float cxmax) { // first element float wsum = 1.0f - xmin + fxmin; - float sum = tex1Dfetch(texSrc, spos) * (1.0f - xmin + fxmin); + float sum = tex( spos) * (1.0f - xmin + fxmin); spos++; for (int ix = ixmin + 1; ix < ixmax; ++ix) { - sum += tex1Dfetch(texSrc, spos); + sum += tex(spos); spos++; wsum += 1.0f; } - sum += tex1Dfetch(texSrc, spos) * (cxmax - xmax); + sum += tex(spos) * (cxmax - xmax); wsum += cxmax - xmax; return sum / wsum; } -__global__ void resizeSuperSample_32f(NcvSize32u srcSize, - Ncv32u srcStep, - NcvRect32u srcROI, - Ncv32f *dst, - NcvSize32u dstSize, - Ncv32u dstStep, - NcvRect32u dstROI, - Ncv32f scaleX, - Ncv32f scaleY) +__global__ void resizeSuperSample_32f(cv::cudev::TexturePtr texSrc, NcvSize32u srcSize, Ncv32u srcStep, NcvRect32u srcROI, Ncv32f *dst, NcvSize32u dstSize, Ncv32u dstStep, + NcvRect32u dstROI, Ncv32f scaleX, Ncv32f scaleY) { // position within dst ROI const int ix = blockIdx.x * blockDim.x + threadIdx.x; @@ -2332,18 +2131,18 @@ __global__ void resizeSuperSample_32f(NcvSize32u srcSize, float wsum = 1.0f - yBegin + floorYBegin; - float sum = processLine (pos, xBegin, xEnd, iXBegin, iXEnd, floorXBegin, + float sum = processLine (texSrc, pos, xBegin, xEnd, iXBegin, iXEnd, floorXBegin, ceilXEnd) * (1.0f - yBegin + floorYBegin); pos += srcStep; for (int iy = iYBegin + 1; iy < iYEnd; ++iy) { - sum += processLine (pos, xBegin, xEnd, iXBegin, iXEnd, floorXBegin, + sum += processLine (texSrc, pos, xBegin, xEnd, iXBegin, iXEnd, floorXBegin, ceilXEnd); pos += srcStep; wsum += 1.0f; } - sum += processLine (pos, xBegin, xEnd, iXBegin, iXEnd, floorXBegin, + sum += processLine (texSrc, pos, xBegin, xEnd, iXBegin, iXEnd, floorXBegin, ceilXEnd) * (ceilYEnd - yEnd); wsum += ceilYEnd - yEnd; sum /= wsum; @@ -2372,14 +2171,7 @@ __device__ float bicubicCoeff(float x_) } -__global__ void resizeBicubic(NcvSize32u srcSize, - NcvRect32u srcROI, - NcvSize32u dstSize, - Ncv32u dstStep, - Ncv32f *dst, - NcvRect32u dstROI, - Ncv32f scaleX, - Ncv32f scaleY) +__global__ void resizeBicubic(cv::cudev::TexturePtr texSrc, NcvSize32u srcSize, NcvRect32u srcROI, NcvSize32u dstSize, Ncv32u dstStep, Ncv32f *dst, NcvRect32u dstROI, Ncv32f scaleX, Ncv32f scaleY) { const int ix = blockIdx.x * blockDim.x + threadIdx.x; const int iy = blockIdx.y * blockDim.y + threadIdx.y; @@ -2433,7 +2225,7 @@ __global__ void resizeBicubic(NcvSize32u srcSize, float wx = bicubicCoeff (xDist); float wy = bicubicCoeff (yDist); wx *= wy; - sum += wx * tex2D (texSrc2D, cx * dx, cy * dy); + sum += wx * texSrc(cy * dy, cx * dx); wsum += wx; } } @@ -2441,7 +2233,7 @@ __global__ void resizeBicubic(NcvSize32u srcSize, } -NCVStatus nppiStResize_32f_C1R(const Ncv32f *pSrc, +NCVStatus nppiStResize_32f_C1R(Ncv32f *pSrc, NcvSize32u srcSize, Ncv32u nSrcStep, NcvRect32u srcROI, @@ -2469,33 +2261,17 @@ NCVStatus nppiStResize_32f_C1R(const Ncv32f *pSrc, if (interpolation == nppStSupersample) { - // bind texture - cudaBindTexture (0, texSrc, pSrc, srcSize.height * nSrcStep); - // invoke kernel + cv::cudev::Texture texSrc(srcSize.height * nSrcStep, pSrc); dim3 ctaSize (32, 6); - dim3 gridSize ((dstROI.width + ctaSize.x - 1) / ctaSize.x, - (dstROI.height + ctaSize.y - 1) / ctaSize.y); - - resizeSuperSample_32f <<>> - (srcSize, srcStep, srcROI, pDst, dstSize, dstStep, dstROI, 1.0f / xFactor, 1.0f / yFactor); + dim3 gridSize ((dstROI.width + ctaSize.x - 1) / ctaSize.x,(dstROI.height + ctaSize.y - 1) / ctaSize.y); + resizeSuperSample_32f <<>> (texSrc, srcSize, srcStep, srcROI, pDst, dstSize, dstStep, dstROI, 1.0f / xFactor, 1.0f / yFactor); } else if (interpolation == nppStBicubic) { - texSrc2D.addressMode[0] = cudaAddressModeMirror; - texSrc2D.addressMode[1] = cudaAddressModeMirror; - texSrc2D.normalized = true; - - cudaChannelFormatDesc desc = cudaCreateChannelDesc (); - - cudaBindTexture2D (0, texSrc2D, pSrc, desc, srcSize.width, srcSize.height, - nSrcStep); - + cv::cudev::Texture texSrc(srcSize.height, srcSize.width, pSrc, nSrcStep, true, cudaFilterModePoint, cudaAddressModeMirror); dim3 ctaSize (32, 6); - dim3 gridSize ((dstSize.width + ctaSize.x - 1) / ctaSize.x, - (dstSize.height + ctaSize.y - 1) / ctaSize.y); - - resizeBicubic <<>> - (srcSize, srcROI, dstSize, dstStep, pDst, dstROI, 1.0f / xFactor, 1.0f / yFactor); + dim3 gridSize ((dstSize.width + ctaSize.x - 1) / ctaSize.x, (dstSize.height + ctaSize.y - 1) / ctaSize.y); + resizeBicubic <<>> (texSrc, srcSize, srcROI, dstSize, dstStep, pDst, dstROI, 1.0f / xFactor, 1.0f / yFactor); } else { diff --git a/modules/cudalegacy/src/cuda/bm.cu b/modules/cudalegacy/src/cuda/bm.cu index 1307a8e3275..546f0903b05 100644 --- a/modules/cudalegacy/src/cuda/bm.cu +++ b/modules/cudalegacy/src/cuda/bm.cu @@ -46,29 +46,27 @@ #include "opencv2/core/cuda/limits.hpp" #include "opencv2/core/cuda/functional.hpp" #include "opencv2/core/cuda/reduce.hpp" +#include using namespace cv::cuda; using namespace cv::cuda::device; namespace optflowbm { - texture tex_prev(false, cudaFilterModePoint, cudaAddressModeClamp); - texture tex_curr(false, cudaFilterModePoint, cudaAddressModeClamp); - - __device__ int cmpBlocks(int X1, int Y1, int X2, int Y2, int2 blockSize) + __device__ int cmpBlocks(cv::cudev::TexturePtr texCurr, cv::cudev::TexturePtr texPrev, int X1, int Y1, int X2, int Y2, int2 blockSize) { int s = 0; for (int y = 0; y < blockSize.y; ++y) { for (int x = 0; x < blockSize.x; ++x) - s += ::abs(tex2D(tex_prev, X1 + x, Y1 + y) - tex2D(tex_curr, X2 + x, Y2 + y)); + s += ::abs(texPrev(Y1 + y, X1 + x) -texCurr(Y2 + y, X2 + x)); } return s; } - __global__ void calcOptFlowBM(PtrStepSzf velx, PtrStepf vely, const int2 blockSize, const int2 shiftSize, const bool usePrevious, + __global__ void calcOptFlowBM(cv::cudev::TexturePtr texPrev, cv::cudev::TexturePtr texCurr, PtrStepSzf velx, PtrStepf vely, const int2 blockSize, const int2 shiftSize, const bool usePrevious, const int maxX, const int maxY, const int acceptLevel, const int escapeLevel, const short2* ss, const int ssCount) { @@ -90,7 +88,7 @@ namespace optflowbm int dist = numeric_limits::max(); if (0 <= X2 && X2 <= maxX && 0 <= Y2 && Y2 <= maxY) - dist = cmpBlocks(X1, Y1, X2, Y2, blockSize); + dist = cmpBlocks(texPrev, texCurr, X1, Y1, X2, Y2, blockSize); int countMin = 1; int sumx = offX; @@ -111,7 +109,7 @@ namespace optflowbm if (0 <= X2 && X2 <= maxX && 0 <= Y2 && Y2 <= maxY) { - const int tmpDist = cmpBlocks(X1, Y1, X2, Y2, blockSize); + const int tmpDist = cmpBlocks(texPrev, texCurr, X1, Y1, X2, Y2, blockSize); if (tmpDist < acceptLevel) { sumx = dx; @@ -151,16 +149,12 @@ namespace optflowbm void calc(PtrStepSzb prev, PtrStepSzb curr, PtrStepSzf velx, PtrStepSzf vely, int2 blockSize, int2 shiftSize, bool usePrevious, int maxX, int maxY, int acceptLevel, int escapeLevel, const short2* ss, int ssCount, cudaStream_t stream) { - bindTexture(&tex_prev, prev); - bindTexture(&tex_curr, curr); - + cv::cudev::Texture texPrev(prev); + cv::cudev::Texture texCurr(curr); const dim3 block(32, 8); const dim3 grid(divUp(velx.cols, block.x), divUp(vely.rows, block.y)); - - calcOptFlowBM<<>>(velx, vely, blockSize, shiftSize, usePrevious, - maxX, maxY, acceptLevel, escapeLevel, ss, ssCount); + calcOptFlowBM<<>>(texPrev, texCurr, velx, vely, blockSize, shiftSize, usePrevious, maxX, maxY, acceptLevel, escapeLevel, ss, ssCount); cudaSafeCall( cudaGetLastError() ); - if (stream == 0) cudaSafeCall( cudaDeviceSynchronize() ); } diff --git a/modules/cudalegacy/test/TestHypothesesGrow.cpp b/modules/cudalegacy/test/TestHypothesesGrow.cpp index e7fe4d939df..ad4c3c9df3c 100644 --- a/modules/cudalegacy/test/TestHypothesesGrow.cpp +++ b/modules/cudalegacy/test/TestHypothesesGrow.cpp @@ -100,7 +100,8 @@ bool TestHypothesesGrow::process() NCV_SKIP_COND_BEGIN ncvAssertReturn(this->src.fill(h_vecSrc), false); - memset(h_vecDst.ptr(), 0, h_vecDst.length() * sizeof(NcvRect32u)); + + *h_vecDst.ptr() = {}; NCVVectorReuse h_vecDst_as32u(h_vecDst.getSegment(), lenDst * sizeof(NcvRect32u) / sizeof(Ncv32u)); ncvAssertReturn(h_vecDst_as32u.isMemReused(), false); ncvAssertReturn(this->src.fill(h_vecDst_as32u), false); diff --git a/modules/cudaobjdetect/src/cuda/hog.cu b/modules/cudaobjdetect/src/cuda/hog.cu index 5c12860620a..2e0b880365c 100644 --- a/modules/cudaobjdetect/src/cuda/hog.cu +++ b/modules/cudaobjdetect/src/cuda/hog.cu @@ -46,6 +46,7 @@ #include "opencv2/core/cuda/reduce.hpp" #include "opencv2/core/cuda/functional.hpp" #include "opencv2/core/cuda/warp_shuffle.hpp" +#include namespace cv { namespace cuda { namespace device { @@ -825,64 +826,57 @@ namespace cv { namespace cuda { namespace device //------------------------------------------------------------------- // Resize - texture resize8UC4_tex; - texture resize8UC1_tex; - - __global__ void resize_for_hog_kernel(float sx, float sy, PtrStepSz dst, int colOfs) + __global__ void resize_for_hog_kernel(cv::cudev::TexturePtr src, float sx, float sy, PtrStepSz dst) { unsigned int x = blockIdx.x * blockDim.x + threadIdx.x; unsigned int y = blockIdx.y * blockDim.y + threadIdx.y; if (x < dst.cols && y < dst.rows) - dst.ptr(y)[x] = tex2D(resize8UC1_tex, x * sx + colOfs, y * sy) * 255; + dst.ptr(y)[x] = src(y * sy, x * sx) * 255; } - __global__ void resize_for_hog_kernel(float sx, float sy, PtrStepSz dst, int colOfs) + __global__ void resize_for_hog_kernel(cv::cudev::TexturePtr src, float sx, float sy, PtrStepSz dst) { unsigned int x = blockIdx.x * blockDim.x + threadIdx.x; unsigned int y = blockIdx.y * blockDim.y + threadIdx.y; if (x < dst.cols && y < dst.rows) { - float4 val = tex2D(resize8UC4_tex, x * sx + colOfs, y * sy); + float4 val = src(y * sy, x * sx); dst.ptr(y)[x] = make_uchar4(val.x * 255, val.y * 255, val.z * 255, val.w * 255); } } - template - static void resize_for_hog(const PtrStepSzb& src, PtrStepSzb dst, TEX& tex) + static void resize_for_hog_8UC1(const PtrStepSzb& src, PtrStepSzb dst) { - tex.filterMode = cudaFilterModeLinear; - - size_t texOfs = 0; - int colOfs = 0; - - cudaChannelFormatDesc desc = cudaCreateChannelDesc(); - cudaSafeCall( cudaBindTexture2D(&texOfs, tex, src.data, desc, src.cols, src.rows, src.step) ); - - if (texOfs != 0) - { - colOfs = static_cast( texOfs/sizeof(T) ); - cudaSafeCall( cudaUnbindTexture(tex) ); - cudaSafeCall( cudaBindTexture2D(&texOfs, tex, src.data, desc, src.cols, src.rows, src.step) ); - } - + cv::cudev::Texture tex(src.rows, src.cols, src.data, src.step, false, cudaFilterModeLinear, cudaAddressModeClamp, cudaReadModeNormalizedFloat); dim3 threads(32, 8); dim3 grid(divUp(dst.cols, threads.x), divUp(dst.rows, threads.y)); float sx = static_cast(src.cols) / dst.cols; float sy = static_cast(src.rows) / dst.rows; - resize_for_hog_kernel<<>>(sx, sy, (PtrStepSz)dst, colOfs); + resize_for_hog_kernel<<>>(tex, sx, sy, (PtrStepSz)dst); cudaSafeCall( cudaGetLastError() ); - cudaSafeCall( cudaDeviceSynchronize() ); + } + + static void resize_for_hog_8UC4(const PtrStepSzb& src, PtrStepSzb dst) + { + cv::cudev::Texture tex(src.rows, src.cols, reinterpret_cast(src.data), src.step, false, cudaFilterModeLinear, cudaAddressModeClamp, cudaReadModeNormalizedFloat); + dim3 threads(32, 8); + dim3 grid(divUp(dst.cols, threads.x), divUp(dst.rows, threads.y)); + + float sx = static_cast(src.cols) / dst.cols; + float sy = static_cast(src.rows) / dst.rows; - cudaSafeCall( cudaUnbindTexture(tex) ); + resize_for_hog_kernel<<>>(tex, sx, sy, (PtrStepSz)dst); + cudaSafeCall(cudaGetLastError()); + cudaSafeCall(cudaDeviceSynchronize()); } - void resize_8UC1(const PtrStepSzb& src, PtrStepSzb dst) { resize_for_hog (src, dst, resize8UC1_tex); } - void resize_8UC4(const PtrStepSzb& src, PtrStepSzb dst) { resize_for_hog(src, dst, resize8UC4_tex); } + void resize_8UC1(const PtrStepSzb& src, PtrStepSzb dst) { resize_for_hog_8UC1(src, dst); } + void resize_8UC4(const PtrStepSzb& src, PtrStepSzb dst) { resize_for_hog_8UC4(src, dst); } } // namespace hog }}} // namespace cv { namespace cuda { namespace cudev diff --git a/modules/cudaobjdetect/test/test_objdetect.cpp b/modules/cudaobjdetect/test/test_objdetect.cpp index 4843cc483ef..5fff18041ea 100644 --- a/modules/cudaobjdetect/test/test_objdetect.cpp +++ b/modules/cudaobjdetect/test/test_objdetect.cpp @@ -222,7 +222,7 @@ INSTANTIATE_TEST_CASE_P(CUDA_ObjDetect, HOG, ALL_DEVICES); */ //============== caltech hog tests =====================// -struct CalTech : public ::testing::TestWithParam > +struct CalTech : public ::testing::TestWithParam> { cv::cuda::DeviceInfo devInfo; cv::Mat img; @@ -232,7 +232,13 @@ struct CalTech : public ::testing::TestWithParam("caltech/image_00000009_0.png", "caltech/image_00000032_0.png", "caltech/image_00000165_0.png", "caltech/image_00000261_0.png", "caltech/image_00000469_0.png", - "caltech/image_00000527_0.png", "caltech/image_00000574_0.png"))); + "caltech/image_00000527_0.png", "caltech/image_00000574_0.png"), testing::Values(GREYSCALE))); //------------------------variable GPU HOG Tests------------------------// diff --git a/modules/cudaoptflow/src/cuda/pyrlk.cu b/modules/cudaoptflow/src/cuda/pyrlk.cu index ca9759c2e53..76a9f3f7977 100644 --- a/modules/cudaoptflow/src/cuda/pyrlk.cu +++ b/modules/cudaoptflow/src/cuda/pyrlk.cu @@ -50,8 +50,7 @@ #include "opencv2/core/cuda/reduce.hpp" #include "opencv2/core/cuda/filters.hpp" #include "opencv2/core/cuda/border_interpolate.hpp" - -#include +#include using namespace cv::cuda; using namespace cv::cuda::device; @@ -64,224 +63,6 @@ namespace pyrlk __constant__ int c_halfWin_y; __constant__ int c_iters; - texture tex_I8U(false, cudaFilterModeLinear, cudaAddressModeClamp); - texture tex_I8UC4(false, cudaFilterModeLinear, cudaAddressModeClamp); - - texture tex_I16UC4(false, cudaFilterModeLinear, cudaAddressModeClamp); - - - texture tex_If(false, cudaFilterModeLinear, cudaAddressModeClamp); - texture tex_If4(false, cudaFilterModeLinear, cudaAddressModeClamp); - - texture tex_Ib(false, cudaFilterModePoint, cudaAddressModeClamp); - - texture tex_J8U(false, cudaFilterModeLinear, cudaAddressModeClamp); - texture tex_J8UC4(false, cudaFilterModeLinear, cudaAddressModeClamp); - - texture tex_J16UC4(false, cudaFilterModeLinear, cudaAddressModeClamp); - - - texture tex_Jf(false, cudaFilterModeLinear, cudaAddressModeClamp); - texture tex_Jf4(false, cudaFilterModeLinear, cudaAddressModeClamp); - - - template struct Tex_I - { - static __host__ __forceinline__ void bindTexture_(PtrStepSz::vec_type> I) - { - CV_UNUSED(I); - } - }; - - template <> struct Tex_I<1, uchar> - { - static __device__ __forceinline__ float read(float x, float y) - { - return tex2D(tex_I8U, x, y); - } - static __host__ __forceinline__ void bindTexture_(PtrStepSz& I) - { - bindTexture(&tex_I8U, I); - } - }; - template <> struct Tex_I<1, ushort> - { - static __device__ __forceinline__ float read(float x, float y) - { - return 0.0; - } - static __host__ __forceinline__ void bindTexture_(PtrStepSz& I) - { - CV_UNUSED(I); - } - }; - template <> struct Tex_I<1, int> - { - static __device__ __forceinline__ float read(float x, float y) - { - return 0.0; - } - static __host__ __forceinline__ void bindTexture_(PtrStepSz& I) - { - CV_UNUSED(I); - } - }; - template <> struct Tex_I<1, float> - { - static __device__ __forceinline__ float read(float x, float y) - { - return tex2D(tex_If, x, y); - } - static __host__ __forceinline__ void bindTexture_(PtrStepSz& I) - { - bindTexture(&tex_If, I); - } - }; - // ****************** 3 channel specializations ************************ - template <> struct Tex_I<3, uchar> - { - static __device__ __forceinline__ float3 read(float x, float y) - { - return make_float3(0,0,0); - } - static __host__ __forceinline__ void bindTexture_(PtrStepSz I) - { - CV_UNUSED(I); - } - }; - template <> struct Tex_I<3, ushort> - { - static __device__ __forceinline__ float3 read(float x, float y) - { - return make_float3(0, 0, 0); - } - static __host__ __forceinline__ void bindTexture_(PtrStepSz I) - { - CV_UNUSED(I); - } - }; - template <> struct Tex_I<3, int> - { - static __device__ __forceinline__ float3 read(float x, float y) - { - return make_float3(0, 0, 0); - } - static __host__ __forceinline__ void bindTexture_(PtrStepSz I) - { - CV_UNUSED(I); - } - }; - template <> struct Tex_I<3, float> - { - static __device__ __forceinline__ float3 read(float x, float y) - { - return make_float3(0, 0, 0); - } - static __host__ __forceinline__ void bindTexture_(PtrStepSz I) - { - CV_UNUSED(I); - } - }; - // ****************** 4 channel specializations ************************ - - template <> struct Tex_I<4, uchar> - { - static __device__ __forceinline__ float4 read(float x, float y) - { - return tex2D(tex_I8UC4, x, y); - } - static __host__ __forceinline__ void bindTexture_(PtrStepSz& I) - { - bindTexture(&tex_I8UC4, I); - } - }; - template <> struct Tex_I<4, ushort> - { - static __device__ __forceinline__ float4 read(float x, float y) - { - return tex2D(tex_I16UC4, x, y); - } - static __host__ __forceinline__ void bindTexture_(PtrStepSz& I) - { - bindTexture(&tex_I16UC4, I); - } - }; - template <> struct Tex_I<4, float> - { - static __device__ __forceinline__ float4 read(float x, float y) - { - return tex2D(tex_If4, x, y); - } - static __host__ __forceinline__ void bindTexture_(PtrStepSz& I) - { - bindTexture(&tex_If4, I); - } - }; - // ************* J *************** - template struct Tex_J - { - static __host__ __forceinline__ void bindTexture_(PtrStepSz::vec_type>& J) - { - CV_UNUSED(J); - } - }; - template <> struct Tex_J<1, uchar> - { - static __device__ __forceinline__ float read(float x, float y) - { - return tex2D(tex_J8U, x, y); - } - static __host__ __forceinline__ void bindTexture_(PtrStepSz& J) - { - bindTexture(&tex_J8U, J); - } - }; - template <> struct Tex_J<1, float> - { - static __device__ __forceinline__ float read(float x, float y) - { - return tex2D(tex_Jf, x, y); - } - static __host__ __forceinline__ void bindTexture_(PtrStepSz& J) - { - bindTexture(&tex_Jf, J); - } - }; - // ************* 4 channel specializations *************** - template <> struct Tex_J<4, uchar> - { - static __device__ __forceinline__ float4 read(float x, float y) - { - return tex2D(tex_J8UC4, x, y); - } - static __host__ __forceinline__ void bindTexture_(PtrStepSz& J) - { - bindTexture(&tex_J8UC4, J); - } - }; - template <> struct Tex_J<4, ushort> - { - static __device__ __forceinline__ float4 read(float x, float y) - { - return tex2D(tex_J16UC4, x, y); - } - static __host__ __forceinline__ void bindTexture_(PtrStepSz& J) - { - bindTexture(&tex_J16UC4, J); - } - }; - template <> struct Tex_J<4, float> - { - static __device__ __forceinline__ float4 read(float x, float y) - { - return tex2D(tex_Jf4, x, y); - } - static __host__ __forceinline__ void bindTexture_(PtrStepSz& J) - { - bindTexture(&tex_Jf4, J); - } - }; - __device__ __forceinline__ void accum(float& dst, const float& val) { dst += val; @@ -364,8 +145,8 @@ namespace pyrlk } }; - template - __global__ void sparseKernel(const float2* prevPts, float2* nextPts, uchar* status, float* err, const int level, const int rows, const int cols) + template + __global__ void sparseKernel(const Ptr2D texI, const Ptr2D texJ, const float2* prevPts, float2* nextPts, uchar* status, float* err, const int level, const int rows, const int cols) { #if __CUDA_ARCH__ <= 110 const int BLOCK_SIZE = 128; @@ -413,15 +194,14 @@ namespace pyrlk float x = prevPt.x + xBase + 0.5f; float y = prevPt.y + yBase + 0.5f; - I_patch[i][j] = Tex_I::read(x, y); + I_patch[i][j] = texI(y, x); // Scharr Deriv + work_type dIdx = 3.0f * texI(y - 1, x + 1) + 10.0f * texI(y, x + 1) + 3.0f * texI(y + 1, x + 1) - + (3.0f * texI(y - 1, x - 1) + 10.0f * texI(y, x - 1) + 3.0f * texI(y + 1, x - 1)); - work_type dIdx = 3.0f * Tex_I::read(x+1, y-1) + 10.0f * Tex_I::read(x+1, y) + 3.0f * Tex_I::read(x+1, y+1) - - (3.0f * Tex_I::read(x-1, y-1) + 10.0f * Tex_I::read(x-1, y) + 3.0f * Tex_I::read(x-1, y+1)); - - work_type dIdy = 3.0f * Tex_I::read(x-1, y+1) + 10.0f * Tex_I::read(x, y+1) + 3.0f * Tex_I::read(x+1, y+1) - - (3.0f * Tex_I::read(x-1, y-1) + 10.0f * Tex_I::read(x, y-1) + 3.0f * Tex_I::read(x+1, y-1)); + work_type dIdy = 3.0f * texI(y + 1, x - 1) + 10.0f * texI(y + 1, x) + 3.0f * texI(y + 1, x + 1) - + (3.0f * texI(y - 1, x - 1) + 10.0f * texI(y - 1, x) + 3.0f * texI(y - 1, x + 1)); dIdx_patch[i][j] = dIdx; dIdy_patch[i][j] = dIdy; @@ -490,7 +270,8 @@ namespace pyrlk for (int x = threadIdx.x, j = 0; x < c_winSize_x; x += blockDim.x, ++j) { work_type I_val = I_patch[i][j]; - work_type J_val = Tex_J::read(nextPt.x + x + 0.5f, nextPt.y + y + 0.5f); + + work_type J_val = texJ(nextPt.y + y + 0.5f, nextPt.x + x + 0.5f); work_type diff = (J_val - I_val) * 32.0f; @@ -533,7 +314,8 @@ namespace pyrlk for (int x = threadIdx.x, j = 0; x < c_winSize_x; x += blockDim.x, ++j) { work_type I_val = I_patch[i][j]; - work_type J_val = Tex_J::read(nextPt.x + x + 0.5f, nextPt.y + y + 0.5f); + + work_type J_val = texJ(nextPt.y + y + 0.5f, nextPt.x + x + 0.5f); work_type diff = J_val - I_val; @@ -749,6 +531,27 @@ namespace pyrlk } } // __global__ void sparseKernel_ + // Specialization for non float data, cudaFilterModeLinear only compatible with cudaReadModeNormalizedFloat. + template class TextureLinear : public cv::cudev::Texture::vec_type, typename TypeVec::vec_type> { + public: + typedef typename TypeVec::vec_type elem_type; + typedef typename TypeVec::vec_type ret_type; + __host__ TextureLinear(PtrStepSz src, const bool normalizedCoords = false, const cudaTextureAddressMode addressMode = cudaAddressModeClamp) : + cv::cudev::Texture(src, normalizedCoords, cudaFilterModeLinear, addressMode, cudaReadModeNormalizedFloat) + { + } + }; + + // Specialization for float data, cudaReadModeNormalizedFloat only compatible with cudaReadModeElementType. + template class TextureLinear : public cv::cudev::Texture::vec_type, typename TypeVec::vec_type> + { + public: + typedef typename TypeVec::vec_type float_type; + __host__ TextureLinear(PtrStepSz src, const bool normalizedCoords = false, const cudaTextureAddressMode addressMode = cudaAddressModeClamp) : + cv::cudev::Texture (src, normalizedCoords, cudaFilterModeLinear, addressMode, cudaReadModeElementType) + { + } + }; template class sparse_caller { @@ -756,16 +559,16 @@ namespace pyrlk static void call(PtrStepSz::vec_type> I, PtrStepSz::vec_type> J, int rows, int cols, const float2* prevPts, float2* nextPts, uchar* status, float* err, int ptcount, int level, dim3 block, cudaStream_t stream) { + typedef typename TypeVec::vec_type dType; + typedef typename TypeVec::vec_type rType; + TextureLinear texI(I); + TextureLinear texJ(J); dim3 grid(ptcount); - CV_UNUSED(I); - CV_UNUSED(J); if (level == 0 && err) - sparseKernel <<>>(prevPts, nextPts, status, err, level, rows, cols); + sparseKernel><<>>(texI, texJ, prevPts, nextPts, status, err, level, rows, cols); else - sparseKernel <<>>(prevPts, nextPts, status, err, level, rows, cols); - + sparseKernel><<>>(texI, texJ, prevPts, nextPts, status, err, level, rows, cols); cudaSafeCall(cudaGetLastError()); - if (stream == 0) cudaSafeCall(cudaDeviceSynchronize()); } @@ -903,8 +706,8 @@ namespace pyrlk }; - template - __global__ void denseKernel(PtrStepf u, PtrStepf v, const PtrStepf prevU, const PtrStepf prevV, PtrStepf err, const int rows, const int cols) + template + __global__ void denseKernel(const Ptr2D texI, const Ptr2D texJ, PtrStepf u, PtrStepf v, const PtrStepf prevU, const PtrStepf prevV, PtrStepf err, const int rows, const int cols) { extern __shared__ int smem[]; @@ -925,15 +728,15 @@ namespace pyrlk float x = xBase - c_halfWin_x + j + 0.5f; float y = yBase - c_halfWin_y + i + 0.5f; - I_patch[i * patchWidth + j] = tex2D(tex_If, x, y); + I_patch[i * patchWidth + j] = texI(y, x); // Scharr Deriv - dIdx_patch[i * patchWidth + j] = 3 * tex2D(tex_If, x+1, y-1) + 10 * tex2D(tex_If, x+1, y) + 3 * tex2D(tex_If, x+1, y+1) - - (3 * tex2D(tex_If, x-1, y-1) + 10 * tex2D(tex_If, x-1, y) + 3 * tex2D(tex_If, x-1, y+1)); + dIdx_patch[i * patchWidth + j] = 3 * texI(y - 1, x + 1) + 10 * texI(y, x + 1) + 3 * texI(y + 1, x + 1) - + (3 * texI(y - 1, x - 1) + 10 * texI(y, x - 1) + 3 * texI(y + 1, x - 1)); - dIdy_patch[i * patchWidth + j] = 3 * tex2D(tex_If, x-1, y+1) + 10 * tex2D(tex_If, x, y+1) + 3 * tex2D(tex_If, x+1, y+1) - - (3 * tex2D(tex_If, x-1, y-1) + 10 * tex2D(tex_If, x, y-1) + 3 * tex2D(tex_If, x+1, y-1)); + dIdy_patch[i * patchWidth + j] = 3 * texI(y + 1, x - 1) + 10 * texI(y + 1,x) + 3 * texI(y+ 1, x + 1) - + (3 * texI(y - 1, x - 1) + 10 * texI(y - 1,x) + 3 * texI(y - 1, x + 1)); } } @@ -1004,7 +807,7 @@ namespace pyrlk for (int j = 0; j < c_winSize_x; ++j) { int I = I_patch[(threadIdx.y + i) * patchWidth + threadIdx.x + j]; - int J = tex2D(tex_Jf, nextPt.x - c_halfWin_x + j + 0.5f, nextPt.y - c_halfWin_y + i + 0.5f); + int J = texJ(nextPt.y - c_halfWin_y + i + 0.5f, nextPt.x - c_halfWin_x + j + 0.5f); int diff = (J - I) * 32; @@ -1040,7 +843,8 @@ namespace pyrlk for (int j = 0; j < c_winSize_x; ++j) { int I = I_patch[(threadIdx.y + i) * patchWidth + threadIdx.x + j]; - int J = tex2D(tex_Jf, nextPt.x - c_halfWin_x + j + 0.5f, nextPt.y - c_halfWin_y + i + 0.5f); + + int J = texJ(nextPt.y - c_halfWin_y + i + 0.5f, nextPt.x - c_halfWin_x + j + 0.5f); errval += ::abs(J - I); } @@ -1109,9 +913,6 @@ namespace pyrlk { sparse_caller::call, sparse_caller::call, sparse_caller::call, sparse_caller::call, sparse_caller::call } }; - Tex_I::bindTexture_(I); - Tex_J::bindTexture_(J); - funcs[patch.y - 1][patch.x - 1](I, J, I.rows, I.cols, prevPts, nextPts, status, err, ptcount, level, block, stream); } @@ -1119,9 +920,8 @@ namespace pyrlk { dim3 block(16, 16); dim3 grid(divUp(I.cols, block.x), divUp(I.rows, block.y)); - Tex_I<1, T>::bindTexture_(I); - Tex_J<1, T>::bindTexture_(J); - + TextureLinear<1, T> texI(I); + TextureLinear<1, T> texJ(J); int2 halfWin = make_int2((winSize.x - 1) / 2, (winSize.y - 1) / 2); const int patchWidth = block.x + 2 * halfWin.x; const int patchHeight = block.y + 2 * halfWin.y; @@ -1129,12 +929,12 @@ namespace pyrlk if (err.data) { - denseKernel << > >(u, v, prevU, prevV, err, I.rows, I.cols); + denseKernel><<>>(texI, texJ, u, v, prevU, prevV, err, I.rows, I.cols); cudaSafeCall(cudaGetLastError()); } else { - denseKernel << > >(u, v, prevU, prevV, PtrStepf(), I.rows, I.cols); + denseKernel><<>>(texI, texJ, u, v, prevU, prevV, PtrStepf(), I.rows, I.cols); cudaSafeCall(cudaGetLastError()); } diff --git a/modules/cudaoptflow/src/cuda/tvl1flow.cu b/modules/cudaoptflow/src/cuda/tvl1flow.cu index 7ee7b36e096..4044ec2a08a 100644 --- a/modules/cudaoptflow/src/cuda/tvl1flow.cu +++ b/modules/cudaoptflow/src/cuda/tvl1flow.cu @@ -46,6 +46,7 @@ #include "opencv2/core/cuda/border_interpolate.hpp" #include "opencv2/core/cuda/limits.hpp" #include "opencv2/core/cuda.hpp" +#include using namespace cv::cuda; using namespace cv::cuda::device; @@ -102,63 +103,8 @@ namespace tvl1flow } } - struct SrcTex - { - virtual ~SrcTex() {} - - __device__ __forceinline__ virtual float I1(float x, float y) const = 0; - __device__ __forceinline__ virtual float I1x(float x, float y) const = 0; - __device__ __forceinline__ virtual float I1y(float x, float y) const = 0; - }; - - texture tex_I1 (false, cudaFilterModePoint, cudaAddressModeClamp); - texture tex_I1x(false, cudaFilterModePoint, cudaAddressModeClamp); - texture tex_I1y(false, cudaFilterModePoint, cudaAddressModeClamp); - struct SrcTexRef : SrcTex - { - __device__ __forceinline__ float I1(float x, float y) const CV_OVERRIDE - { - return tex2D(tex_I1, x, y); - } - __device__ __forceinline__ float I1x(float x, float y) const CV_OVERRIDE - { - return tex2D(tex_I1x, x, y); - } - __device__ __forceinline__ float I1y(float x, float y) const CV_OVERRIDE - { - return tex2D(tex_I1y, x, y); - } - }; - - struct SrcTexObj : SrcTex - { - __host__ SrcTexObj(cudaTextureObject_t tex_obj_I1_, cudaTextureObject_t tex_obj_I1x_, cudaTextureObject_t tex_obj_I1y_) - : tex_obj_I1(tex_obj_I1_), tex_obj_I1x(tex_obj_I1x_), tex_obj_I1y(tex_obj_I1y_) {} - - __device__ __forceinline__ float I1(float x, float y) const CV_OVERRIDE - { - return tex2D(tex_obj_I1, x, y); - } - __device__ __forceinline__ float I1x(float x, float y) const CV_OVERRIDE - { - return tex2D(tex_obj_I1x, x, y); - } - __device__ __forceinline__ float I1y(float x, float y) const CV_OVERRIDE - { - return tex2D(tex_obj_I1y, x, y); - } - - cudaTextureObject_t tex_obj_I1; - cudaTextureObject_t tex_obj_I1x; - cudaTextureObject_t tex_obj_I1y; - }; - - template < - typename T, - typename = typename std::enable_if::value>::type - > __global__ void warpBackwardKernel( - const PtrStepSzf I0, const T src, const PtrStepf u1, const PtrStepf u2, + const PtrStepSzf I0, const cv::cudev::TexturePtr I1, const cv::cudev::TexturePtr I1x, const cv::cudev::TexturePtr I1y, const PtrStepf u1, const PtrStepf u2, PtrStepf I1w, PtrStepf I1wx, PtrStepf I1wy, PtrStepf grad, PtrStepf rho) { const int x = blockIdx.x * blockDim.x + threadIdx.x; @@ -189,11 +135,9 @@ namespace tvl1flow for (int cx = xmin; cx <= xmax; ++cx) { const float w = bicubicCoeff(wx - cx) * bicubicCoeff(wy - cy); - - sum += w * src.I1(cx, cy); - sumx += w * src.I1x(cx, cy); - sumy += w * src.I1y(cx, cy); - + sum += w * I1(cy, cx); + sumx += w * I1x(cy, cx); + sumy += w * I1y(cy, cx); wsum += w; } } @@ -224,49 +168,14 @@ namespace tvl1flow PtrStepSzf I1wy, PtrStepSzf grad, PtrStepSzf rho, cudaStream_t stream) { + cv::cudev::Texture texI1(I1); + cv::cudev::Texture texI1x(I1x); + cv::cudev::Texture texI1y(I1y); const dim3 block(32, 8); const dim3 grid(divUp(I0.cols, block.x), divUp(I0.rows, block.y)); - - bool cc30 = deviceSupports(FEATURE_SET_COMPUTE_30); - - if (cc30) - { - cudaTextureDesc texDesc; - memset(&texDesc, 0, sizeof(texDesc)); - texDesc.addressMode[0] = cudaAddressModeClamp; - texDesc.addressMode[1] = cudaAddressModeClamp; - texDesc.addressMode[2] = cudaAddressModeClamp; - - cudaTextureObject_t texObj_I1 = 0, texObj_I1x = 0, texObj_I1y = 0; - - createTextureObjectPitch2D(&texObj_I1, I1, texDesc); - createTextureObjectPitch2D(&texObj_I1x, I1x, texDesc); - createTextureObjectPitch2D(&texObj_I1y, I1y, texDesc); - - warpBackwardKernel << > > (I0, SrcTexObj(texObj_I1, texObj_I1x, texObj_I1y), u1, u2, I1w, I1wx, I1wy, grad, rho); - cudaSafeCall(cudaGetLastError()); - - if (!stream) - cudaSafeCall(cudaDeviceSynchronize()); - else - cudaSafeCall(cudaStreamSynchronize(stream)); - - cudaSafeCall(cudaDestroyTextureObject(texObj_I1)); - cudaSafeCall(cudaDestroyTextureObject(texObj_I1x)); - cudaSafeCall(cudaDestroyTextureObject(texObj_I1y)); - } - else - { - bindTexture(&tex_I1, I1); - bindTexture(&tex_I1x, I1x); - bindTexture(&tex_I1y, I1y); - - warpBackwardKernel << > > (I0, SrcTexRef(), u1, u2, I1w, I1wx, I1wy, grad, rho); - cudaSafeCall(cudaGetLastError()); - - if (!stream) - cudaSafeCall(cudaDeviceSynchronize()); - } + warpBackwardKernel<<>>(I0, texI1, texI1x, texI1y , u1, u2, I1w, I1wx, I1wy, grad, rho); + if (!stream) + cudaSafeCall(cudaDeviceSynchronize()); } } diff --git a/modules/cudastereo/src/cuda/stereobm.cu b/modules/cudastereo/src/cuda/stereobm.cu index 348556060d1..73df35ff63d 100644 --- a/modules/cudastereo/src/cuda/stereobm.cu +++ b/modules/cudastereo/src/cuda/stereobm.cu @@ -43,8 +43,10 @@ #if !defined CUDA_DISABLER #include "opencv2/core/cuda/common.hpp" +#include #include + namespace cv { namespace cuda { namespace device { namespace stereobm @@ -601,13 +603,12 @@ namespace cv { namespace cuda { namespace device /////////////////////////////////// Textureness filtering //////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// - texture texForTF; - - __device__ __forceinline__ float sobel(int x, int y) + __device__ __forceinline__ float sobel(cv::cudev::TexturePtr texSrc, int x, int y) { - float conv = tex2D(texForTF, x - 1, y - 1) * (-1) + tex2D(texForTF, x + 1, y - 1) * (1) + - tex2D(texForTF, x - 1, y ) * (-2) + tex2D(texForTF, x + 1, y ) * (2) + - tex2D(texForTF, x - 1, y + 1) * (-1) + tex2D(texForTF, x + 1, y + 1) * (1); + float conv = texSrc(y - 1, x - 1) * (-1) + texSrc(y - 1, x + 1) * (1) + + texSrc(y, x - 1) * (-2) + texSrc(y, x + 1) * (2) + + texSrc(y + 1, x - 1) * (-1) + texSrc(y + 1, x + 1) * (1); + return fabs(conv); } @@ -635,7 +636,7 @@ namespace cv { namespace cuda { namespace device #define RpT (2 * ROWSperTHREAD) // got experimentally - __global__ void textureness_kernel(PtrStepSzb disp, int winsz, float threshold) + __global__ void textureness_kernel(cv::cudev::TexturePtr texSrc, PtrStepSzb disp, int winsz, float threshold) { int winsz2 = winsz/2; int n_dirty_pixels = (winsz2) * 2; @@ -657,9 +658,9 @@ namespace cv { namespace cuda { namespace device for(int i = y - winsz2; i <= y + winsz2; ++i) { - sum += sobel(x - winsz2, i); + sum += sobel(texSrc, x - winsz2, i); if (cols_extra) - sum_extra += sobel(x + blockDim.x - winsz2, i); + sum_extra += sobel(texSrc, x + blockDim.x - winsz2, i); } *cols = sum; if (cols_extra) @@ -675,12 +676,12 @@ namespace cv { namespace cuda { namespace device for(int y = beg_row + 1; y < end_row; ++y) { - sum = sum - sobel(x - winsz2, y - winsz2 - 1) + sobel(x - winsz2, y + winsz2); + sum = sum - sobel(texSrc, x - winsz2, y - winsz2 - 1) + sobel(texSrc, x - winsz2, y + winsz2); *cols = sum; if (cols_extra) { - sum_extra = sum_extra - sobel(x + blockDim.x - winsz2, y - winsz2 - 1) + sobel(x + blockDim.x - winsz2, y + winsz2); + sum_extra = sum_extra - sobel(texSrc, x + blockDim.x - winsz2, y - winsz2 - 1) + sobel(texSrc, x + blockDim.x - winsz2, y + winsz2); *cols_extra = sum_extra; } @@ -697,28 +698,16 @@ namespace cv { namespace cuda { namespace device void postfilter_textureness(const PtrStepSzb& input, int winsz, float avgTexturenessThreshold, const PtrStepSzb& disp, cudaStream_t & stream) { avgTexturenessThreshold *= winsz * winsz; - - texForTF.filterMode = cudaFilterModeLinear; - texForTF.addressMode[0] = cudaAddressModeWrap; - texForTF.addressMode[1] = cudaAddressModeWrap; - - cudaChannelFormatDesc desc = cudaCreateChannelDesc(); - cudaSafeCall( cudaBindTexture2D( 0, texForTF, input.data, desc, input.cols, input.rows, input.step ) ); - + cv::cudev::Texture tex(input, false, cudaFilterModeLinear, cudaAddressModeWrap, cudaReadModeNormalizedFloat); dim3 threads(128, 1, 1); dim3 grid(1, 1, 1); - grid.x = divUp(input.cols, threads.x); grid.y = divUp(input.rows, RpT); - size_t smem_size = (threads.x + threads.x + (winsz/2) * 2 ) * sizeof(float); - textureness_kernel<<>>(disp, winsz, avgTexturenessThreshold); + textureness_kernel<<>>(tex, disp, winsz, avgTexturenessThreshold); cudaSafeCall( cudaGetLastError() ); - if (stream == 0) cudaSafeCall( cudaDeviceSynchronize() ); - - cudaSafeCall( cudaUnbindTexture (texForTF) ); } } // namespace stereobm }}} // namespace cv { namespace cuda { namespace cudev diff --git a/modules/cudawarping/src/cuda/remap.cu b/modules/cudawarping/src/cuda/remap.cu index 79f155ddfb9..38edf19ae24 100644 --- a/modules/cudawarping/src/cuda/remap.cu +++ b/modules/cudawarping/src/cuda/remap.cu @@ -48,6 +48,7 @@ #include "opencv2/core/cuda/vec_math.hpp" #include "opencv2/core/cuda/saturate_cast.hpp" #include "opencv2/core/cuda/filters.hpp" +#include namespace cv { namespace cuda { namespace device { @@ -77,8 +78,8 @@ namespace cv { namespace cuda { namespace device dim3 grid(divUp(dst.cols, block.x), divUp(dst.rows, block.y)); B brd(src.rows, src.cols, VecTraits::make(borderValue)); - BorderReader< PtrStep, B > brdSrc(src, brd); - Filter< BorderReader< PtrStep, B > > filter_src(brdSrc); + BorderReader, B> brdSrc(src, brd); + Filter, B>> filter_src(brdSrc); remap<<>>(filter_src, mapx, mapy, dst); cudaSafeCall( cudaGetLastError() ); @@ -98,8 +99,8 @@ namespace cv { namespace cuda { namespace device dim3 grid(divUp(dst.cols, block.x), divUp(dst.rows, block.y)); B brd(src.rows, src.cols, VecTraits::make(borderValue)); - BorderReader< PtrStep, B > brdSrc(src, brd); - Filter< BorderReader< PtrStep, B > > filter_src(brdSrc); + BorderReader, B> brdSrc(src, brd); + Filter, B>> filter_src(brdSrc); remap<<>>(filter_src, mapx, mapy, dst); cudaSafeCall( cudaGetLastError() ); @@ -108,88 +109,96 @@ namespace cv { namespace cuda { namespace device } }; - #define OPENCV_CUDA_IMPLEMENT_REMAP_TEX(type) \ - texture< type , cudaTextureType2D> tex_remap_ ## type (0, cudaFilterModePoint, cudaAddressModeClamp); \ - struct tex_remap_ ## type ## _reader \ - { \ - typedef type elem_type; \ - typedef int index_type; \ - int xoff, yoff; \ - tex_remap_ ## type ## _reader (int xoff_, int yoff_) : xoff(xoff_), yoff(yoff_) {} \ - __device__ __forceinline__ elem_type operator ()(index_type y, index_type x) const \ - { \ - return tex2D(tex_remap_ ## type , x + xoff, y + yoff); \ - } \ - }; \ - template