Toshihiro Shimizu 890ddd
#include <sstream> /* std::ostringstream */</sstream>
Toshihiro Shimizu 890ddd
/* Not use boost at toonz-6.1 */
Toshihiro Shimizu 890ddd
// #include <boost shared_array.hpp=""> /* boost::shared_array<> */</boost>
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
//------------------------------------------------------------
Shinya Kitaoka 120a6e
class ino_channel_selector : public TStandardRasterFx {
Shinya Kitaoka 120a6e
  FX_PLUGIN_DECLARATION(ino_channel_selector)
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRasterFxPort m_source1;
Shinya Kitaoka 120a6e
  TRasterFxPort m_source2;
Shinya Kitaoka 120a6e
  TRasterFxPort m_source3;
Shinya Kitaoka 120a6e
  TRasterFxPort m_source4;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TIntParamP m_red_source;
Shinya Kitaoka 120a6e
  TIntParamP m_gre_source;
Shinya Kitaoka 120a6e
  TIntParamP m_blu_source;
Shinya Kitaoka 120a6e
  TIntParamP m_alp_source;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TIntEnumParamP m_red_channel;
Shinya Kitaoka 120a6e
  TIntEnumParamP m_gre_channel;
Shinya Kitaoka 120a6e
  TIntEnumParamP m_blu_channel;
Shinya Kitaoka 120a6e
  TIntEnumParamP m_alp_channel;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  ino_channel_selector()
Shinya Kitaoka 120a6e
      : m_red_source(1)
Shinya Kitaoka 120a6e
      , m_gre_source(1)
Shinya Kitaoka 120a6e
      , m_blu_source(1)
Shinya Kitaoka 120a6e
      , m_alp_source(1)
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      , m_red_channel(new TIntEnumParam(0, "Red"))
Shinya Kitaoka 120a6e
      , m_gre_channel(new TIntEnumParam(1, "Green"))
Shinya Kitaoka 120a6e
      , m_blu_channel(new TIntEnumParam(2, "Blue"))
Shinya Kitaoka 120a6e
      , m_alp_channel(new TIntEnumParam(3, "Alpha")) {
Shinya Kitaoka 120a6e
    addInputPort("Source1", this->m_source1);
Shinya Kitaoka 120a6e
    addInputPort("Source2", this->m_source2);
Shinya Kitaoka 120a6e
    addInputPort("Source3", this->m_source3);
Shinya Kitaoka 120a6e
    addInputPort("Source4", this->m_source4);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    bindParam(this, "red_source", this->m_red_source);
Shinya Kitaoka 120a6e
    bindParam(this, "green_source", this->m_gre_source);
Shinya Kitaoka 120a6e
    bindParam(this, "blue_source", this->m_blu_source);
Shinya Kitaoka 120a6e
    bindParam(this, "alpha_source", this->m_alp_source);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    bindParam(this, "red_channel", this->m_red_channel);
Shinya Kitaoka 120a6e
    bindParam(this, "green_channel", this->m_gre_channel);
Shinya Kitaoka 120a6e
    bindParam(this, "blue_channel", this->m_blu_channel);
Shinya Kitaoka 120a6e
    bindParam(this, "alpha_channel", this->m_alp_channel);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    this->m_red_channel->addItem(1, "Green");
Shinya Kitaoka 120a6e
    this->m_red_channel->addItem(2, "Blue");
Shinya Kitaoka 120a6e
    this->m_red_channel->addItem(3, "Alpha");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    this->m_gre_channel->addItem(0, "Red");
Shinya Kitaoka 120a6e
    this->m_gre_channel->addItem(2, "Blue");
Shinya Kitaoka 120a6e
    this->m_gre_channel->addItem(3, "Alpha");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    this->m_blu_channel->addItem(0, "Red");
Shinya Kitaoka 120a6e
    this->m_blu_channel->addItem(1, "Green");
Shinya Kitaoka 120a6e
    this->m_blu_channel->addItem(3, "Alpha");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    this->m_alp_channel->addItem(0, "Red");
Shinya Kitaoka 120a6e
    this->m_alp_channel->addItem(1, "Green");
Shinya Kitaoka 120a6e
    this->m_alp_channel->addItem(2, "Blue");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 473e70
  bool doGetBBox(double frame, TRectD &bBox, const TRenderSettings &info) override {
Shinya Kitaoka 120a6e
    for (int ii = 0; ii < this->getInputPortCount(); ++ii) {
Shinya Kitaoka 120a6e
      std::string nm          = this->getInputPortName(ii);
Shinya Kitaoka 120a6e
      TRasterFxPort *tmp_port = (TRasterFxPort *)this->getInputPort(nm);
Shinya Kitaoka 120a6e
      if (tmp_port->isConnected()) {
Shinya Kitaoka 120a6e
        return (*tmp_port)->doGetBBox(frame, bBox, info);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    bBox = TRectD();
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 473e70
  bool canHandle(const TRenderSettings &info, double frame) override { return true; }
Shinya Kitaoka 473e70
  void doCompute(TTile &tile, double frame, const TRenderSettings &ri) override;
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
FX_PLUGIN_IDENTIFIER(ino_channel_selector, "inoChannelSelectorFx");
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------
Toshihiro Shimizu 890ddd
// #include "igs_channel_selector.h"
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
template <typename in_pixel,="" out_pixel="" typename=""></typename>
Shinya Kitaoka 120a6e
void fx_template(const TRasterPT<in_pixel> in_ras, const int in_sel,</in_pixel>
Shinya Kitaoka 120a6e
                 const TRasterPT<out_pixel> out_ras, const int out_sel) {</out_pixel>
Shinya Kitaoka 120a6e
  for (int yy = 0; yy < out_ras->getLy(); ++yy) {
Shinya Kitaoka 120a6e
    IN_PIXEL *sl_in   = in_ras->pixels(yy);
Shinya Kitaoka 120a6e
    OUT_PIXEL *sl_out = out_ras->pixels(yy);
Shinya Kitaoka 120a6e
    for (int xx = 0; xx < out_ras->getLx(); ++xx, ++sl_in, ++sl_out) {
Shinya Kitaoka 120a6e
      int val = 0;
Shinya Kitaoka 120a6e
      switch (in_sel) {
Shinya Kitaoka 120a6e
      case 0:
Shinya Kitaoka 120a6e
        val = sl_in->r;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      case 1:
Shinya Kitaoka 120a6e
        val = sl_in->g;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      case 2:
Shinya Kitaoka 120a6e
        val = sl_in->b;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      case 3:
Shinya Kitaoka 120a6e
        val = sl_in->m;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      switch (out_sel) {
Shinya Kitaoka 120a6e
      case 0:
Shinya Kitaoka 120a6e
        sl_out->r = val;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      case 1:
Shinya Kitaoka 120a6e
        sl_out->g = val;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      case 2:
Shinya Kitaoka 120a6e
        sl_out->b = val;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      case 3:
Shinya Kitaoka 120a6e
        sl_out->m = val;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Shinya Kitaoka 120a6e
void fx_(const TRasterP in_ras, const int in_sel, TRasterP out_ras,
Shinya Kitaoka 120a6e
         const int out_sel) {
Shinya Kitaoka 120a6e
  if ((TRaster32P)in_ras && (TRaster32P)out_ras) {
Shinya Kitaoka 120a6e
    fx_template<tpixel32, tpixel32="">(in_ras, in_sel, out_ras, out_sel);</tpixel32,>
Shinya Kitaoka 120a6e
  } else if ((TRaster64P)in_ras && (TRaster64P)out_ras) {
Shinya Kitaoka 120a6e
    fx_template<tpixel64, tpixel64="">(in_ras, in_sel, out_ras, out_sel);</tpixel64,>
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Shinya Kitaoka 120a6e
void ino_channel_selector::doCompute(TTile &tile, double frame,
Shinya Kitaoka 120a6e
                                     const TRenderSettings &ri) {
Shinya Kitaoka 120a6e
  /* ------ サポートしていないPixelタイプはエラーを投げる --- */
Shinya Kitaoka 120a6e
  if (!((TRaster32P)tile.getRaster()) && !((TRaster64P)tile.getRaster())) {
Shinya Kitaoka 120a6e
    throw TRopException("unsupported input pixel type");
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  /* ------ 動作パラメータを得る ---------------------------- */
Shinya Kitaoka 120a6e
  const int red_source  = this->m_red_source->getValue() - 1;
Shinya Kitaoka 120a6e
  const int gre_source  = this->m_gre_source->getValue() - 1;
Shinya Kitaoka 120a6e
  const int blu_source  = this->m_blu_source->getValue() - 1;
Shinya Kitaoka 120a6e
  const int alp_source  = this->m_alp_source->getValue() - 1;
Shinya Kitaoka 120a6e
  const int red_channel = this->m_red_channel->getValue();
Shinya Kitaoka 120a6e
  const int gre_channel = this->m_gre_channel->getValue();
Shinya Kitaoka 120a6e
  const int blu_channel = this->m_blu_channel->getValue();
Shinya Kitaoka 120a6e
  const int alp_channel = this->m_alp_channel->getValue();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  /* ------ 画像位置とサイズ -------------------------------- */
Shinya Kitaoka 120a6e
  /***const TRectD rect = TRectD( tile.m_pos, TDimensionD(
Shinya Kitaoka 120a6e
            tile.getRaster()->getLx()
Shinya Kitaoka 120a6e
          , tile.getRaster()->getLy()
Shinya Kitaoka 120a6e
  ));
Shinya Kitaoka 120a6e
  const TPointD poin = TPointD(rect.getP00());
Shinya Kitaoka 120a6e
  const TDimension dime = TDimension(
Shinya Kitaoka 120a6e
           (int)(rect.getLx()+0.5)
Shinya Kitaoka 120a6e
          ,(int)(rect.getLy()+0.5)
Shinya Kitaoka 120a6e
  );***/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  /* ------ 塗りつぶしクリア -------------------------------- */
Shinya Kitaoka 120a6e
  tile.getRaster()->clear();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  /* ------ 入力画像を接続していなければ処理しない ---------- */
Shinya Kitaoka 120a6e
  if (this->getInputPortCount() <= 0) {
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  /* ------ 入力画像の参照を確保 ---------------------------- */
Shinya Kitaoka 120a6e
  // TTile *source_tiles = new TTile[this->getInputPortCount()];
Shinya Kitaoka 120a6e
  // int   *source_sw    = new int[this->getInputPortCount()];
Shinya Kitaoka 120a6e
  // TRasterP *ras_a     = new TRasterP[this->getInputPortCount()];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  /* Not use boost at toonz-6.1 */
Shinya Kitaoka 120a6e
  /******
Shinya Kitaoka 120a6e
  boost::shared_array<ttile></ttile>
Shinya Kitaoka 120a6e
          source_tiles(new TTile[this->getInputPortCount()]);
Shinya Kitaoka 120a6e
  boost::shared_array<int></int>
Shinya Kitaoka 120a6e
          source_sw(new int[this->getInputPortCount()]);
Shinya Kitaoka 120a6e
  boost::shared_array<trasterp></trasterp>
Shinya Kitaoka 120a6e
          ras_a(new TRasterP[this->getInputPortCount()]);
Toshihiro Shimizu 890ddd
******/
Shinya Kitaoka 120a6e
  /* Array item(TRasterFxPort) number is 4(fix) in this code */
Shinya Kitaoka 120a6e
  TTile source_tiles[4];
Shinya Kitaoka 120a6e
  int source_sw[4];
Shinya Kitaoka 120a6e
  TRasterP ras_a[4];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int ras_s = 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  /* ------ 画像生成 ---------------------------------------- */
Shinya Kitaoka 120a6e
  for (int ii = 0; ii < this->getInputPortCount(); ++ii) {
Shinya Kitaoka 120a6e
    std::string nm          = this->getInputPortName(ii);
Shinya Kitaoka 120a6e
    TRasterFxPort *tmp_port = (TRasterFxPort *)this->getInputPort(nm);
Shinya Kitaoka 120a6e
    if (tmp_port->isConnected() && ((ii == red_source) || (ii == gre_source) ||
Shinya Kitaoka 120a6e
                                    (ii == blu_source) || (ii == alp_source))) {
Shinya Kitaoka 120a6e
      (*tmp_port)->allocateAndCompute(
Shinya Kitaoka 120a6e
          source_tiles[ii]
Shinya Kitaoka 120a6e
          //,poin,dime
Shinya Kitaoka 120a6e
          ,
Shinya Kitaoka 120a6e
          tile.m_pos /* 位置 */
Shinya Kitaoka 120a6e
          ,
Shinya Kitaoka 120a6e
          TDimension(/* サイズ */
Shinya Kitaoka 120a6e
                     tile.getRaster()->getLx(), tile.getRaster()->getLy()),
Shinya Kitaoka 120a6e
          tile.getRaster() /* sampling */
Shinya Kitaoka 120a6e
          ,
Shinya Kitaoka 120a6e
          frame, ri);
Shinya Kitaoka 120a6e
      source_sw[ii]  = 1;
Shinya Kitaoka 120a6e
      ras_a[ras_s++] = source_tiles[ii].getRaster();
Shinya Kitaoka 120a6e
    } else
Shinya Kitaoka 120a6e
      source_sw[ii] = 0;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRasterP red_ras = 0;
Shinya Kitaoka 120a6e
  TRasterP gre_ras = 0;
Shinya Kitaoka 120a6e
  TRasterP blu_ras = 0;
Shinya Kitaoka 120a6e
  TRasterP alp_ras = 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if ((0 <= red_source) && (red_source < this->getInputPortCount()) &&
Shinya Kitaoka 120a6e
      source_sw[red_source]) {
Shinya Kitaoka 120a6e
    red_ras = source_tiles[red_source].getRaster();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if ((0 <= gre_source) && (gre_source < this->getInputPortCount()) &&
Shinya Kitaoka 120a6e
      source_sw[gre_source]) {
Shinya Kitaoka 120a6e
    gre_ras = source_tiles[gre_source].getRaster();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if ((0 <= blu_source) && (blu_source < this->getInputPortCount()) &&
Shinya Kitaoka 120a6e
      source_sw[blu_source]) {
Shinya Kitaoka 120a6e
    blu_ras = source_tiles[blu_source].getRaster();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if ((0 <= alp_source) && (alp_source < this->getInputPortCount()) &&
Shinya Kitaoka 120a6e
      source_sw[alp_source]) {
Shinya Kitaoka 120a6e
    alp_ras = source_tiles[alp_source].getRaster();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  /* ------ (app_begin)log記憶 ------------------------------ */
Shinya Kitaoka 120a6e
  const bool log_sw = ino::log_enable_sw();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (log_sw) {
Shinya Kitaoka 120a6e
    std::ostringstream os;
Shinya Kitaoka 120a6e
    os << "red"
Shinya Kitaoka 120a6e
       << "  s " << red_source << "  c " << red_channel << "   green"
Shinya Kitaoka 120a6e
       << "  s " << gre_source << "  c " << gre_channel << "   blue"
Shinya Kitaoka 120a6e
       << "  s " << blu_source << "  c " << blu_channel << "   alpha"
Shinya Kitaoka 120a6e
       << "  s " << alp_source << "  c " << alp_channel << "   tile w "
Shinya Kitaoka 120a6e
       << tile.getRaster()->getLx() << "  h " << tile.getRaster()->getLy()
Shinya Kitaoka 120a6e
       << "  b " << ino::pixel_bits(tile.getRaster());
Shinya Kitaoka 120a6e
    os << "   s_count " << this->getInputPortCount();
Shinya Kitaoka 120a6e
    for (int ii = 0; ii < this->getInputPortCount(); ++ii) {
Shinya Kitaoka 120a6e
      if (source_sw[ii]) {
Shinya Kitaoka 120a6e
        os << "   tile" << ii << "  w " << source_tiles[ii].getRaster()->getLx()
Shinya Kitaoka 120a6e
           << "  h " << source_tiles[ii].getRaster()->getLy() << "  b "
Shinya Kitaoka 120a6e
           << ino::pixel_bits(source_tiles[ii].getRaster());
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    os << "   frame " << frame;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  /* ------ 入力画像の参照開放 ------------------------------ */
Shinya Kitaoka 120a6e
  // delete [] source_sw;
Shinya Kitaoka 120a6e
  // delete [] source_tiles;
Shinya Kitaoka 120a6e
  /* ------ fx処理 ------------------------------------------ */
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    tile.getRaster()->lock();
Shinya Kitaoka 120a6e
    for (int ii = 0; ii < ras_s; ++ii) {
Shinya Kitaoka 120a6e
      ras_a[ii]->lock();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (red_ras) {
Shinya Kitaoka 120a6e
      fx_(red_ras, red_channel, tile.getRaster(), 0);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (gre_ras) {
Shinya Kitaoka 120a6e
      fx_(gre_ras, gre_channel, tile.getRaster(), 1);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (blu_ras) {
Shinya Kitaoka 120a6e
      fx_(blu_ras, blu_channel, tile.getRaster(), 2);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (alp_ras) {
Shinya Kitaoka 120a6e
      fx_(alp_ras, alp_channel, tile.getRaster(), 3);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    for (int ii = ras_s - 1; 0 <= ii; --ii) {
Shinya Kitaoka 120a6e
      ras_a[ii]->unlock();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    tile.getRaster()->unlock();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  /* ------ error処理 --------------------------------------- */
Shinya Kitaoka 120a6e
  catch (std::bad_alloc &e) {
Shinya Kitaoka 120a6e
    for (int ii = ras_s - 1; 0 <= ii; --ii) {
Shinya Kitaoka 120a6e
      ras_a[ii]->unlock();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    tile.getRaster()->unlock();
Shinya Kitaoka 120a6e
    if (log_sw) {
Shinya Kitaoka 120a6e
      std::string str("std::bad_alloc <");
Shinya Kitaoka 120a6e
      str += e.what();
Shinya Kitaoka 120a6e
      str += '>';
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    // delete [] ras_a;
Shinya Kitaoka 120a6e
    throw;
Shinya Kitaoka 120a6e
  } catch (std::exception &e) {
Shinya Kitaoka 120a6e
    for (int ii = ras_s - 1; 0 <= ii; --ii) {
Shinya Kitaoka 120a6e
      ras_a[ii]->unlock();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    tile.getRaster()->unlock();
Shinya Kitaoka 120a6e
    if (log_sw) {
Shinya Kitaoka 120a6e
      std::string str("exception <");
Shinya Kitaoka 120a6e
      str += e.what();
Shinya Kitaoka 120a6e
      str += '>';
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    // delete [] ras_a;
Shinya Kitaoka 120a6e
    throw;
Shinya Kitaoka 120a6e
  } catch (...) {
Shinya Kitaoka 120a6e
    for (int ii = ras_s - 1; 0 <= ii; --ii) {
Shinya Kitaoka 120a6e
      ras_a[ii]->unlock();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    tile.getRaster()->unlock();
Shinya Kitaoka 120a6e
    if (log_sw) {
Shinya Kitaoka 120a6e
      std::string str("other exception");
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    // delete [] ras_a;
Shinya Kitaoka 120a6e
    throw;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  // delete [] ras_a;
Toshihiro Shimizu 890ddd
}