Toshihiro Shimizu 890ddd
#include <sstream> /* std::ostringstream */</sstream>
Toshihiro Shimizu 890ddd
#include "tfxparam.h"
Toshihiro Shimizu 890ddd
#include "stdfx.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "ino_common.h"
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
class ino_hsv_noise : public TStandardRasterFx
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	FX_PLUGIN_DECLARATION(ino_hsv_noise)
Toshihiro Shimizu 890ddd
	TRasterFxPort m_input;
Toshihiro Shimizu 890ddd
	TRasterFxPort m_refer;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TDoubleParamP m_hue;
Toshihiro Shimizu 890ddd
	TDoubleParamP m_sat;
Toshihiro Shimizu 890ddd
	TDoubleParamP m_val;
Toshihiro Shimizu 890ddd
	TDoubleParamP m_mat;
Toshihiro Shimizu 890ddd
	TDoubleParamP m_random_seed;
Toshihiro Shimizu 890ddd
	TDoubleParamP m_near_blur;
Toshihiro Shimizu 890ddd
	TDoubleParamP m_term_effective;
Toshihiro Shimizu 890ddd
	TDoubleParamP m_term_center;
Toshihiro Shimizu 890ddd
	TIntEnumParamP m_term_type;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TBoolParamP m_anti_alias;
Toshihiro Shimizu 890ddd
	TIntEnumParamP m_ref_mode;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	ino_hsv_noise()
Toshihiro Shimizu 890ddd
		: m_hue(0.025 * ino::param_range()), m_sat(0.0 * ino::param_range()), m_val(0.035 * ino::param_range()), m_mat(0.0 * ino::param_range()), m_random_seed(1), m_near_blur(1.0 * ino::param_range()), m_term_effective(0.0 * ino::param_range()), m_term_center(ino::param_range() / 2.0), m_term_type(new TIntEnumParam(0, "Keep Noise"))
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		  ,
Toshihiro Shimizu 890ddd
		  m_anti_alias(true), m_ref_mode(new TIntEnumParam(0, "Red"))
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		addInputPort("Source", this->m_input);
Toshihiro Shimizu 890ddd
		addInputPort("Reference", this->m_refer);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		bindParam(this, "hue", this->m_hue);
Toshihiro Shimizu 890ddd
		bindParam(this, "saturation", this->m_sat);
Toshihiro Shimizu 890ddd
		bindParam(this, "value", this->m_val);
Toshihiro Shimizu 890ddd
		bindParam(this, "alpha", this->m_mat);
Toshihiro Shimizu 890ddd
		bindParam(this, "seed", this->m_random_seed);
Toshihiro Shimizu 890ddd
		bindParam(this, "nblur", this->m_near_blur);
Toshihiro Shimizu 890ddd
		bindParam(this, "effective", this->m_term_effective);
Toshihiro Shimizu 890ddd
		bindParam(this, "center", this->m_term_center);
Toshihiro Shimizu 890ddd
		bindParam(this, "type", this->m_term_type);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		bindParam(this, "anti_alias", this->m_anti_alias);
Toshihiro Shimizu 890ddd
		bindParam(this, "reference", this->m_ref_mode);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		this->m_hue->setValueRange(
Toshihiro Shimizu 890ddd
			0.0 * ino::param_range(), 1.0 * ino::param_range());
Toshihiro Shimizu 890ddd
		this->m_sat->setValueRange(
Toshihiro Shimizu 890ddd
			0.0 * ino::param_range(), 1.0 * ino::param_range());
Toshihiro Shimizu 890ddd
		this->m_val->setValueRange(
Toshihiro Shimizu 890ddd
			0.0 * ino::param_range(), 1.0 * ino::param_range());
Toshihiro Shimizu 890ddd
		this->m_mat->setValueRange(
Toshihiro Shimizu 890ddd
			0.0 * ino::param_range(), 1.0 * ino::param_range());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		this->m_random_seed->setValueRange(
Toshihiro Shimizu 890ddd
			0, std::numeric_limits<unsigned long="">::max());</unsigned>
Toshihiro Shimizu 890ddd
		this->m_near_blur->setValueRange(
Toshihiro Shimizu 890ddd
			0.0 * ino::param_range(), 1.0 * ino::param_range());
Toshihiro Shimizu 890ddd
		this->m_term_effective->setValueRange(
Toshihiro Shimizu 890ddd
			0.0 * ino::param_range(), 1.0 * ino::param_range());
Toshihiro Shimizu 890ddd
		this->m_term_center->setValueRange(
Toshihiro Shimizu 890ddd
			0.0 * ino::param_range(), 1.0 * ino::param_range());
Toshihiro Shimizu 890ddd
		this->m_term_type->addItem(1, "Keep Contrast");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		this->m_ref_mode->addItem(1, "Green");
Toshihiro Shimizu 890ddd
		this->m_ref_mode->addItem(2, "Blue");
Toshihiro Shimizu 890ddd
		this->m_ref_mode->addItem(3, "Alpha");
Toshihiro Shimizu 890ddd
		this->m_ref_mode->addItem(4, "Luminance");
Toshihiro Shimizu 890ddd
		this->m_ref_mode->addItem(-1, "Nothing");
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	bool doGetBBox(
Toshihiro Shimizu 890ddd
		double frame, TRectD &bBox, const TRenderSettings &info)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		if (this->m_input.isConnected()) {
Toshihiro Shimizu 890ddd
			return this->m_input->doGetBBox(frame, bBox, info);
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			bBox = TRectD();
Toshihiro Shimizu 890ddd
			return false;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	bool canHandle(const TRenderSettings &info, double frame)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		//return true;
Toshihiro Shimizu 890ddd
		/* trueだと素材がスライドして現れるときノイズパターンが
Toshihiro Shimizu 890ddd
		変わってしまう 2013-4-5からtoonz上で変更した */
Toshihiro Shimizu 890ddd
		/* でなく、
Toshihiro Shimizu 890ddd
		ここでの指定にかかわらず、
Toshihiro Shimizu 890ddd
		素材をカメラ範囲で切り取ってるため、
Toshihiro Shimizu 890ddd
		スライドで現れるときのノイズパターンは変わってしまう。
Toshihiro Shimizu 890ddd
		だたし、移動以外のGeometryがなく、
Toshihiro Shimizu 890ddd
		連番の絵でなく一枚の絵を移動するだけのときは、
Toshihiro Shimizu 890ddd
		Cashのため(?)ノイズパターンは変化しない。
Toshihiro Shimizu 890ddd
		回転にノイズがついてくる。
Toshihiro Shimizu 890ddd
		防ぐ方法はtileに素材の位置と大きさ情報があれば...
Toshihiro Shimizu 890ddd
		2013-11-08 */
Toshihiro Shimizu 890ddd
		return false;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	void doCompute(
Toshihiro Shimizu 890ddd
		TTile &tile, double frame, const TRenderSettings &rend_sets);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
FX_PLUGIN_IDENTIFIER(ino_hsv_noise, "inohsvNoiseFx");
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
#include "igs_hsv_noise.h"
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
void fx_(
Toshihiro Shimizu 890ddd
	TRasterP in_ras, const TRasterP refer_ras, const int ref_mode
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	,
Toshihiro Shimizu 890ddd
	double hue_range, double sat_range, double val_range, double alp_range, unsigned long random_seed, double near_blur, double effective, double center, int type, const int camera_x, const int camera_y, const int camera_w, const int camera_h, const bool anti_alias_sw)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TRasterGR8P in_gr8(
Toshihiro Shimizu 890ddd
		in_ras->getLy(), in_ras->getLx() * ino::channels() *
Toshihiro Shimizu 890ddd
							 ((TRaster64P)in_ras ? sizeof(unsigned short) : sizeof(unsigned char)));
Toshihiro Shimizu 890ddd
	in_gr8->lock();
Toshihiro Shimizu 890ddd
	ino::ras_to_arr(in_ras, ino::channels(), in_gr8->getRawData());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	/* igs::hsv_noise::change(-)は今後つかわない2011-07-15 */
Toshihiro Shimizu 890ddd
	igs::hsv_noise::change(
Toshihiro Shimizu 890ddd
		// in_ras->getRawData() // BGRA
Toshihiro Shimizu 890ddd
		in_gr8->getRawData()
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			,
Toshihiro Shimizu 890ddd
		in_ras->getLy(), in_ras->getLx() // Must Not use in_ras->getWrap()
Toshihiro Shimizu 890ddd
		,
Toshihiro Shimizu 890ddd
		ino::channels(), ino::bits(in_ras)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
							 ,
Toshihiro Shimizu 890ddd
		(((0 <= ref_mode) && (0 != refer_ras)) ? refer_ras->getRawData() : 0) //BGRA
Toshihiro Shimizu 890ddd
		,
Toshihiro Shimizu 890ddd
		(((0 <= ref_mode) && (0 != refer_ras)) ? ino::bits(refer_ras) : 0), ref_mode
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		,
Toshihiro Shimizu 890ddd
		camera_x, camera_y, camera_w, camera_h
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		,
Toshihiro Shimizu 890ddd
		hue_range, sat_range, val_range, alp_range, random_seed, near_blur, effective, center, type, effective, center, type, effective, center, type, anti_alias_sw);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	ino::arr_to_ras(in_gr8->getRawData(), ino::channels(), in_ras, 0);
Toshihiro Shimizu 890ddd
	in_gr8->unlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
void ino_hsv_noise::doCompute(
Toshihiro Shimizu 890ddd
	TTile &tile, double frame, const TRenderSettings &rend_sets)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	/* ------ 接続していなければ処理しない -------------------- */
Toshihiro Shimizu 890ddd
	if (!this->m_input.isConnected()) {
Toshihiro Shimizu 890ddd
		tile.getRaster()->clear(); /* 塗りつぶしクリア */
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	/* ------ サポートしていないPixelタイプはエラーを投げる --- */
Toshihiro Shimizu 890ddd
	if (!((TRaster32P)tile.getRaster()) &&
Toshihiro Shimizu 890ddd
		!((TRaster64P)tile.getRaster())) {
Toshihiro Shimizu 890ddd
		throw TRopException("unsupported input pixel type");
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	/* ------ 動作パラメータを得る ---------------------------- */
Toshihiro Shimizu 890ddd
	const double hue_range = this->m_hue->getValue(frame) /
Toshihiro Shimizu 890ddd
							 ino::param_range();
Toshihiro Shimizu 890ddd
	const double sat_range = this->m_sat->getValue(frame) /
Toshihiro Shimizu 890ddd
							 ino::param_range();
Toshihiro Shimizu 890ddd
	const double val_range = this->m_val->getValue(frame) /
Toshihiro Shimizu 890ddd
							 ino::param_range();
Toshihiro Shimizu 890ddd
	const double mat_range = this->m_mat->getValue(frame) /
Toshihiro Shimizu 890ddd
							 ino::param_range();
Toshihiro Shimizu 890ddd
	const unsigned long random_seed = static_cast<unsigned long="">(</unsigned>
Toshihiro Shimizu 890ddd
		this->m_random_seed->getValue(frame));
Toshihiro Shimizu 890ddd
	const double near_blur = this->m_near_blur->getValue(frame) /
Toshihiro Shimizu 890ddd
							 ino::param_range() / 2.0;
Toshihiro Shimizu 890ddd
	int term_type = -1;
Toshihiro Shimizu 890ddd
	switch (this->m_term_type->getValue()) {
Toshihiro Shimizu 890ddd
	case 0:
Toshihiro Shimizu 890ddd
		term_type = 0;
Toshihiro Shimizu 890ddd
		break;
Toshihiro Shimizu 890ddd
	case 1:
Toshihiro Shimizu 890ddd
		term_type = 3;
Toshihiro Shimizu 890ddd
		break;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	const double term_center = this->m_term_center->getValue(frame) /
Toshihiro Shimizu 890ddd
							   ino::param_range();
Toshihiro Shimizu 890ddd
	const double term_effective =
Toshihiro Shimizu 890ddd
		this->m_term_effective->getValue(frame) /
Toshihiro Shimizu 890ddd
		ino::param_range();
Toshihiro Shimizu 890ddd
	const bool anti_alias_sw = this->m_anti_alias->getValue();
Toshihiro Shimizu 890ddd
	const int ref_mode = this->m_ref_mode->getValue();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	/* ------ 画像生成 ---------------------------------------- */
Toshihiro Shimizu 890ddd
	this->m_input->compute(tile, frame, rend_sets);
Toshihiro Shimizu 890ddd
	/*--- カメラの範囲をノイズを掛ける範囲としておく(余白含ず) -*/
Toshihiro Shimizu 890ddd
	int camera_x = 0;
Toshihiro Shimizu 890ddd
	int camera_y = 0;
Toshihiro Shimizu 890ddd
	int camera_w = static_cast<int>(rend_sets.m_cameraBox.getLx() + 0.5);</int>
Toshihiro Shimizu 890ddd
	int camera_h = static_cast<int>(rend_sets.m_cameraBox.getLy() + 0.5);</int>
Toshihiro Shimizu 890ddd
	/*--- カメラ範囲外へのmargin付き(たぶん)はノイズ範囲から外す -*/
Toshihiro Shimizu 890ddd
	const int margin_w = tile.getRaster()->getLx() - camera_w;
Toshihiro Shimizu 890ddd
	const int margin_h = tile.getRaster()->getLy() - camera_h;
Toshihiro Shimizu 890ddd
	if ((0 <= margin_h && 0 < margin_w)	/* 横方向のみ余白あり */
Toshihiro Shimizu 890ddd
		|| (0 < margin_h && 0 <= margin_w) /* 縦方向のみ余白あり */
Toshihiro Shimizu 890ddd
		|| (0 < margin_h && 0 < margin_w)  /* 縦横両方に余白あり */
Toshihiro Shimizu 890ddd
		) {
Toshihiro Shimizu 890ddd
		/*camera_x = static_cast<int>(ceil((double)margin_w / 2.));</int>
Toshihiro Shimizu 890ddd
		camera_y = static_cast<int>(ceil((double)margin_h / 2.));*/</int>
Toshihiro Shimizu 890ddd
		camera_x = margin_w / 2;
Toshihiro Shimizu 890ddd
		camera_y = margin_h / 2;
Toshihiro Shimizu 890ddd
		camera_w = rend_sets.m_cameraBox.getLx();
Toshihiro Shimizu 890ddd
		camera_h = rend_sets.m_cameraBox.getLy();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	/*--- 入力画像がカメラより一部でも小さい
Toshihiro Shimizu 890ddd
		(ノイズ範囲指定対応できない-->懸案事項) ------------*/
Toshihiro Shimizu 890ddd
	else {
Toshihiro Shimizu 890ddd
		camera_w = tile.getRaster()->getLx();
Toshihiro Shimizu 890ddd
		camera_h = tile.getRaster()->getLy();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	/*------ 参照画像生成 --------------------------------------*/
Toshihiro Shimizu 890ddd
	TTile reference_tile;
Toshihiro Shimizu 890ddd
	bool reference_sw = false;
Toshihiro Shimizu 890ddd
	if (this->m_refer.isConnected()) {
Toshihiro Shimizu 890ddd
		reference_sw = true;
Toshihiro Shimizu 890ddd
		this->m_refer->allocateAndCompute(
Toshihiro Shimizu 890ddd
			reference_tile, tile.m_pos, TDimensionI(/* Pixel単位 */
Toshihiro Shimizu 890ddd
													tile.getRaster()->getLx(), tile.getRaster()->getLy()),
Toshihiro Shimizu 890ddd
			tile.getRaster(), frame, rend_sets);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	/* ------ (app_begin)log記憶 ------------------------------ */
Toshihiro Shimizu 890ddd
	const bool log_sw = ino::log_enable_sw();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (log_sw) {
Toshihiro Shimizu 890ddd
		std::ostringstream os;
Toshihiro Shimizu 890ddd
		os << "params"
Toshihiro Shimizu 890ddd
		   << "  h " << hue_range
Toshihiro Shimizu 890ddd
		   << "  s " << sat_range
Toshihiro Shimizu 890ddd
		   << "  v " << val_range
Toshihiro Shimizu 890ddd
		   << "  a " << mat_range
Toshihiro Shimizu 890ddd
		   << "  seed " << random_seed
Toshihiro Shimizu 890ddd
		   << "  nblur " << near_blur
Toshihiro Shimizu 890ddd
		   << "  effective " << term_effective
Toshihiro Shimizu 890ddd
		   << "  center " << term_center
Toshihiro Shimizu 890ddd
		   << "  type " << term_type
Toshihiro Shimizu 890ddd
		   << "  frame " << frame
Toshihiro Shimizu 890ddd
		   << "  anti_alias " << anti_alias_sw
Toshihiro Shimizu 890ddd
		   << "  reference " << ref_mode
Toshihiro Shimizu 890ddd
		   << "  pixbits " << ino::pixel_bits(tile.getRaster())
Toshihiro Shimizu 890ddd
		   << "  tile.m_pos " << tile.m_pos
Toshihiro Shimizu 890ddd
		   << "  tile_getLx " << tile.getRaster()->getLx()
Toshihiro Shimizu 890ddd
		   << "  y " << tile.getRaster()->getLy()
Toshihiro Shimizu 890ddd
		   << "  rend_sets.m_cameraBox " << rend_sets.m_cameraBox
Toshihiro Shimizu 890ddd
		   << "  rend_sets.m_affine " << rend_sets.m_affine
Toshihiro Shimizu 890ddd
		   << "  camera x " << camera_x
Toshihiro Shimizu 890ddd
		   << "  y " << camera_y
Toshihiro Shimizu 890ddd
		   << "  w " << camera_w
Toshihiro Shimizu 890ddd
		   << "  h " << camera_h;
Toshihiro Shimizu 890ddd
		if (reference_sw) {
Toshihiro Shimizu 890ddd
			os
Toshihiro Shimizu 890ddd
				<< "  reference_tile.m_pos " << reference_tile.m_pos
Toshihiro Shimizu 890ddd
				<< "  reference_tile_getLx " << reference_tile.getRaster()->getLx()
Toshihiro Shimizu 890ddd
				<< "  y " << reference_tile.getRaster()->getLy();
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	/* ------ fx処理 ------------------------------------------ */
Toshihiro Shimizu 890ddd
	try {
Toshihiro Shimizu 890ddd
		tile.getRaster()->lock();
Toshihiro Shimizu 890ddd
		reference_tile.getRaster()->lock();
Toshihiro Shimizu 890ddd
		fx_(
Toshihiro Shimizu 890ddd
			tile.getRaster(), reference_tile.getRaster(), ref_mode
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			,
Toshihiro Shimizu 890ddd
			hue_range, sat_range, val_range, mat_range, random_seed, near_blur, term_effective, term_center, term_type, camera_x, camera_y, camera_w, camera_h, anti_alias_sw // --> add_blend_sw, default is true
Toshihiro Shimizu 890ddd
			);
Toshihiro Shimizu 890ddd
		reference_tile.getRaster()->unlock();
Toshihiro Shimizu 890ddd
		tile.getRaster()->unlock();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	/* ------ error処理 --------------------------------------- */
Toshihiro Shimizu 890ddd
	catch (std::bad_alloc &e) {
Toshihiro Shimizu 890ddd
		reference_tile.getRaster()->unlock();
Toshihiro Shimizu 890ddd
		tile.getRaster()->unlock();
Toshihiro Shimizu 890ddd
		if (log_sw) {
Toshihiro Shimizu 890ddd
			std::string str("std::bad_alloc <");
Toshihiro Shimizu 890ddd
			str += e.what();
Toshihiro Shimizu 890ddd
			str += '>';
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		throw;
Toshihiro Shimizu 890ddd
	} catch (std::exception &e) {
Toshihiro Shimizu 890ddd
		reference_tile.getRaster()->unlock();
Toshihiro Shimizu 890ddd
		tile.getRaster()->unlock();
Toshihiro Shimizu 890ddd
		if (log_sw) {
Toshihiro Shimizu 890ddd
			std::string str("exception <");
Toshihiro Shimizu 890ddd
			str += e.what();
Toshihiro Shimizu 890ddd
			str += '>';
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		throw;
Toshihiro Shimizu 890ddd
	} catch (...) {
Toshihiro Shimizu 890ddd
		reference_tile.getRaster()->unlock();
Toshihiro Shimizu 890ddd
		tile.getRaster()->unlock();
Toshihiro Shimizu 890ddd
		if (log_sw) {
Toshihiro Shimizu 890ddd
			std::string str("other exception");
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		throw;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}