TuttleOFX  1
HistogramKeyerPluginFactory.cpp
Go to the documentation of this file.
00001 #include "HistogramKeyerPluginFactory.hpp"
00002 #include "HistogramKeyerPlugin.hpp"
00003 #include "HistogramKeyerDefinitions.hpp"
00004 #include "HistogramKeyerOverlay.hpp"
00005 
00006 #include <limits>
00007 
00008 namespace tuttle {
00009 namespace plugin {
00010 namespace histogramKeyer {
00011 
00012 static const bool kSupportTiles = true;
00013 
00014 
00015 /**
00016  * @brief Function called to describe the plugin main features.
00017  * @param[in, out] desc Effect descriptor
00018  */
00019 void HistogramKeyerPluginFactory::describe( OFX::ImageEffectDescriptor& desc )
00020 {
00021         // describe the plugin
00022         desc.setLabels( "TuttleHistogramKeyer", "HistogramKeyer",
00023                             "HistogramKeyer" );
00024         desc.setPluginGrouping( "tuttle/image/process/color" );
00025 
00026         desc.setDescription(
00027                 "HistogramKeyer\n"
00028                 "This histogram keyer plugin allows user to create an alpha mask using HSL & RGB curves. Output can be in gray scale or directly in alpha channel (RGBA)."
00029                 "There are some selection parameters which could help you to refine your maniplulation (control points unders histograms and quantity)."
00030                 "A reverse output mask is also implemented.\n"
00031                 "\n"
00032         );
00033 
00034         // add the supported contexts, only filter at the moment
00035         desc.addSupportedContext( OFX::eContextFilter );
00036         desc.addSupportedContext( OFX::eContextGeneral );
00037 
00038         // add supported pixel depths
00039         desc.addSupportedBitDepth( OFX::eBitDepthUByte );
00040         desc.addSupportedBitDepth( OFX::eBitDepthUShort );
00041         desc.addSupportedBitDepth( OFX::eBitDepthFloat );
00042 
00043         // plugin flags
00044         desc.setSupportsTiles( kSupportTiles );
00045         desc.setRenderThreadSafety( OFX::eRenderFullySafe );
00046 
00047         desc.setOverlayInteractDescriptor( new OFX::DefaultEffectOverlayWrap<HistogramKeyerOverlayDescriptor>() );
00048 
00049         if( ! OFX::getImageEffectHostDescription()->supportsParametricParameter )
00050         {
00051                 BOOST_THROW_EXCEPTION( exception::MissingHostFeature( "Parametric parameter" ) );
00052         }
00053 }
00054 
00055 /**
00056  * @brief Function called to describe the plugin controls and features.
00057  * @param[in, out]   desc       Effect descriptor
00058  * @param[in]        context    Application context
00059  */
00060 void HistogramKeyerPluginFactory::describeInContext( OFX::ImageEffectDescriptor& desc,OFX::EContext context )
00061 {
00062         
00063         OFX::ClipDescriptor* srcClip = desc.defineClip( kOfxImageEffectSimpleSourceClipName );
00064         srcClip->addSupportedComponent( OFX::ePixelComponentRGBA );
00065         srcClip->addSupportedComponent( OFX::ePixelComponentRGB );
00066         srcClip->addSupportedComponent( OFX::ePixelComponentAlpha );
00067         srcClip->setSupportsTiles( kSupportTiles );
00068 
00069         OFX::ClipDescriptor* dstClip = desc.defineClip( kOfxImageEffectOutputClipName );
00070         dstClip->addSupportedComponent( OFX::ePixelComponentRGBA );
00071         dstClip->addSupportedComponent( OFX::ePixelComponentRGB );
00072         dstClip->addSupportedComponent( OFX::ePixelComponentAlpha );
00073         dstClip->setSupportsTiles( kSupportTiles );
00074 
00075         //global display
00076         OFX::BooleanParamDescriptor* boolGLOBAL = desc.defineBooleanParam(kGlobalDisplay);
00077         boolGLOBAL->setHint("Display global overlay on screen.");
00078         boolGLOBAL->setDefault(true);
00079                 
00080     // if parametric parameters are supported
00081         if( OFX::getImageEffectHostDescription()->supportsParametricParameter )
00082         {
00083                 OFX::ParametricParamDescriptor* curvesRGB = desc.defineParametricParam( kParamRGBColorSelection );
00084                 OFX::ParametricParamDescriptor* curvesHSL = desc.defineParametricParam( kParamHSLColorSelection );
00085                 
00086                 //Group Param (RGB & HSL)
00087                 OFX::GroupParamDescriptor *groupRGB = desc.defineGroupParam(kGroupRGB);
00088                 groupRGB->setLabel(kGroupRGBLabel);
00089                 OFX::GroupParamDescriptor *groupHSL = desc.defineGroupParam(kGroupHSL);
00090                 groupHSL->setLabel(kGroupHSLLabel);
00091 
00092                 //define the graphic aspect
00093                 curvesRGB->setRange( 0.0, 1.0 );                //set range on RGB curve
00094                 curvesHSL->setRange( 0.0, 1.0 );                //set range on HSL curve
00095                 curvesRGB->setDimension(nbCurvesRGB);   //3 curves on RGB
00096                 curvesHSL->setDimension(nbCurvesHSL);   //3 curves on HSL
00097 
00098                 //Add curves RGB
00099                 curvesRGB->setDimensionLabel( kParamColorSelectionRed, 0 );                     // 0 on RGB is red
00100                 curvesRGB->setDimensionLabel( kParamColorSelectionGreen, 1 );           // 1 on RGB is green
00101                 curvesRGB->setDimensionLabel( kParamColorSelectionBlue, 2 );            // 2 on RGB is blue
00102                 //Add curves HSL
00103                 curvesHSL->setDimensionLabel( kParamColorSelectionHue, 0 );                     // 0 on HSL is hue
00104                 curvesHSL->setDimensionLabel( kParamColorSelectionSaturation, 1 );      // 1 on HSL is saturation
00105                 curvesHSL->setDimensionLabel( kParamColorSelectionLightness, 2 );       // 2 on HSK is lightness
00106                 //define curves color RGB 
00107                 curvesRGB->setHint( "Color selection" );                
00108                 static const OfxRGBColourD red   = {1,0,0};             //set red color to red curve
00109                 static const OfxRGBColourD green = {0,1,0};             //set green color to green curve
00110                 static const OfxRGBColourD blue  = {0,0,1};             //set blue color to blue curve
00111                 curvesRGB->setUIColour( 0, red );
00112                 curvesRGB->setUIColour( 1, green );
00113                 curvesRGB->setUIColour( 2, blue );
00114                 //define curves color HSL 
00115                 curvesHSL->setHint( "Color selection" );
00116                 curvesHSL->setUIColour( 0, red );               //set red color on hue curve
00117                 curvesHSL->setUIColour( 1, green );             //set green color on saturation curve
00118                 curvesHSL->setUIColour( 2, blue );              //set lightness color on saturation curve
00119                 
00120                 curvesRGB->setInteractDescriptor( new OFX::DefaultParamInteractWrap<RGBParamOverlayDescriptor>() );     //attach parametric curve to RGBOverlay
00121                 curvesHSL->setInteractDescriptor( new OFX::DefaultParamInteractWrap<HSLParamOverlayDescriptor>() );     //attach parametric curve to HSLOverlay
00122                 
00123                 //add curves to their groups
00124                 curvesRGB->setParent(groupRGB); //add RGB curves to RGB group
00125                 curvesHSL->setParent(groupHSL); //add HSL curves to HSL group 
00126                 
00127                 //Set each curves to initial value
00128                 curvesRGB->setIdentity();
00129                 curvesHSL->setIdentity();
00130                 //add 2 control points (0,1) and (1,1) for each channel
00131                 for(unsigned int i=0; i< nbCurvesRGB; ++i)
00132                 {
00133                         //curvesRGB->addControlPoint( i, 0.0, 0.0, 1.0, false );
00134                         curvesRGB->addControlPoint( i, 0.0, 1.0, 1.0, false );
00135                 }
00136                 for(unsigned int i=0; i< nbCurvesHSL; ++i)
00137                 {
00138                         //curvesHSL->addControlPoint( i, 0.0, 0.0, 1.0, false );
00139                         curvesHSL->addControlPoint( i, 0.0, 1.0, 1.0, false );
00140                 }
00141                 
00142                 //Channels checkboxes (RGB)
00143                 OFX::BooleanParamDescriptor* boolR = desc.defineBooleanParam(kBoolRed);
00144                 boolR->setDefault(false);                                                       //red channel is not selected by default
00145                 boolR->setHint("Activate Red channel");
00146                 boolR->setLayoutHint( OFX::eLayoutHintNoNewLine ); //line is not finished
00147                 boolR->setParent(groupRGB);
00148                 //red multiplier
00149                 OFX::DoubleParamDescriptor* redMultiplier = desc.defineDoubleParam(kMultiplierRed);
00150                 redMultiplier->setLabel(kMultiplierLabel);
00151                 redMultiplier->setHint("Determinate curve from selection precision.");
00152                 redMultiplier->setRange(1, 1000);
00153                 redMultiplier->setDisplayRange(0,5);
00154                 redMultiplier->setDefault(1);
00155                 redMultiplier->setParent(groupRGB);
00156                 
00157                 
00158                 OFX::BooleanParamDescriptor* boolG = desc.defineBooleanParam(kBoolGreen);
00159                 boolG->setDefault(false);                                               //green channel is not selected by default
00160                 boolG->setHint("Activate Green channel");
00161                 boolG->setLayoutHint( OFX::eLayoutHintNoNewLine ); //line is not finished
00162                 boolG->setParent(groupRGB);
00163                 //green multiplier
00164                 OFX::DoubleParamDescriptor* greenMultiplier = desc.defineDoubleParam(kMultiplierGreen);
00165                 greenMultiplier->setLabel(kMultiplierLabel);
00166                 greenMultiplier->setHint("Determinate curve from selection precision.");
00167                 greenMultiplier->setRange(1, 1000);
00168                 greenMultiplier->setDisplayRange(0,5);
00169                 greenMultiplier->setDefault(1);
00170                 greenMultiplier->setParent(groupRGB);
00171                 
00172                 
00173                 OFX::BooleanParamDescriptor* boolB = desc.defineBooleanParam(kBoolBlue);
00174                 boolB->setHint("Activate Blue channel");
00175                 boolB->setLayoutHint( OFX::eLayoutHintNoNewLine ); //line is not finished
00176                 boolB->setDefault(false);                                                  //blue channel is not selected by default
00177                 boolB->setParent(groupRGB);
00178                 //blue multiplier
00179                 OFX::DoubleParamDescriptor* blueMultiplier = desc.defineDoubleParam(kMultiplierBlue);
00180                 blueMultiplier->setLabel(kMultiplierLabel);
00181                 blueMultiplier->setHint("Determinate curve from selection precision.");
00182                 blueMultiplier->setRange(1, 1000);
00183                 blueMultiplier->setDisplayRange(0,5);
00184                 blueMultiplier->setDefault(1);
00185                 blueMultiplier->setParent(groupRGB);
00186                 
00187                 
00188                 
00189                 //Channels check box (HSL)
00190                 OFX::BooleanParamDescriptor* boolH = desc.defineBooleanParam(kBoolHue);
00191                 boolH->setDefault(false);
00192                 boolH->setHint("Activate Hue channel");
00193                 boolH->setLayoutHint( OFX::eLayoutHintNoNewLine ); //line is not finished
00194                 boolH->setParent(groupHSL);
00195                 //Hue multiplier
00196                 OFX::DoubleParamDescriptor* hueMultiplier = desc.defineDoubleParam(kMultiplierHue);
00197                 hueMultiplier->setLabel(kMultiplierLabel);
00198                 hueMultiplier->setHint("Determinate curve from selection precision.");
00199                 hueMultiplier->setRange(1, 1000);
00200                 hueMultiplier->setDisplayRange(0,5);
00201                 hueMultiplier->setDefault(1);
00202                 hueMultiplier->setParent(groupHSL);
00203                 
00204                 
00205                 OFX::BooleanParamDescriptor* boolS = desc.defineBooleanParam(kBoolSaturation);
00206                 boolS->setDefault(false);
00207                 boolS->setHint("Activate Saturation channel");
00208                 boolS->setLayoutHint( OFX::eLayoutHintNoNewLine ); //line is not finished
00209                 boolS->setParent(groupHSL);
00210                 //Saturation multiplier
00211                 OFX::DoubleParamDescriptor* saturationMultiplier = desc.defineDoubleParam(kMultiplierSaturation);
00212                 saturationMultiplier->setLabel(kMultiplierLabel);
00213                 saturationMultiplier->setHint("Determinate curve from selection precision.");
00214                 saturationMultiplier->setRange(1, 1000);
00215                 saturationMultiplier->setDisplayRange(0,5);
00216                 saturationMultiplier->setDefault(1);
00217                 saturationMultiplier->setParent(groupHSL);
00218                 
00219                 OFX::BooleanParamDescriptor* boolL = desc.defineBooleanParam(kBoolLightness);
00220                 boolL->setHint("Activate Lightness channel");
00221                 boolL->setLayoutHint( OFX::eLayoutHintNoNewLine ); //line is not finished
00222                 boolL->setDefault(false);
00223                 boolL->setParent(groupHSL);
00224                 //Lightness multiplier
00225                 OFX::DoubleParamDescriptor* lightnessMultiplier = desc.defineDoubleParam(kMultiplierLightness);
00226                 lightnessMultiplier->setLabel(kMultiplierLabel);
00227                 lightnessMultiplier->setHint("Determinate curve from selection precision.");
00228                 lightnessMultiplier->setRange(1, 1000);
00229                 lightnessMultiplier->setDisplayRange(0,5);
00230                 lightnessMultiplier->setDefault(1);
00231                 lightnessMultiplier->setParent(groupHSL);
00232                 
00233                 //Clean Button (RGB)
00234                 OFX::PushButtonParamDescriptor* resetButtonRGB = desc.definePushButtonParam(kButtonResetRGB);
00235                 resetButtonRGB->setLabel(kButtonResetRGBLabel);
00236                 resetButtonRGB->setLayoutHint( OFX::eLayoutHintNoNewLine ); //line is not finished
00237                 resetButtonRGB->setHint("Reset the selected RGB curves. \n Warning : the curves may not be refreshed click on overlay to refresh.");
00238                 resetButtonRGB->setParent(groupRGB);
00239                 
00240                 //Selection To Curves Button (RGB)
00241                 OFX::PushButtonParamDescriptor* selectionToCurveButtonRGB = desc.definePushButtonParam(kButtonSelectionToCurveRGB);
00242                 selectionToCurveButtonRGB->setLabel(kButtonSelectionToCurveRGBLabel);
00243                 selectionToCurveButtonRGB->setHint("Load selected RGB curves with selection data. \n Warning : the curves may not be refreshed click on overlay to refresh.");
00244                 selectionToCurveButtonRGB->setParent(groupRGB);
00245                 
00246                 //Append selection to curves button (RGB)
00247                 OFX::PushButtonParamDescriptor* appendSelectionToCurveRGB = desc.definePushButtonParam(kButtonAppendSelectionToCurveRGB);
00248                 appendSelectionToCurveRGB->setLabel(kButtonAppendSelectionToCurveRGBLabel);                             //add label
00249                 appendSelectionToCurveRGB->setHint("Append current selection to selected RGB channels");//help
00250                 appendSelectionToCurveRGB->setParent(groupRGB);                                                                                 //add to RGB group
00251                 
00252                 //Clean Button (HSL)
00253                 OFX::PushButtonParamDescriptor* resetButtonHSL = desc.definePushButtonParam(kButtonResetHSL);
00254                 resetButtonHSL->setLabel(kButtonResetHSLLabel);
00255                 resetButtonHSL->setLayoutHint( OFX::eLayoutHintNoNewLine ); //line is not finished
00256                 resetButtonHSL->setHint("Reset the selected HSL curves \n Warning : the curves may not be refreshed click on overlay to refresh.");
00257                 resetButtonHSL->setParent(groupHSL);
00258                 
00259                 //Selection To Curves Button (HSL)
00260                 OFX::PushButtonParamDescriptor* selectionToCurveButtonHSL = desc.definePushButtonParam(kButtonSelectionToCurveHSL);
00261                 selectionToCurveButtonHSL->setLabel(kButtonSelectionToCurveHSLLabel);
00262                 selectionToCurveButtonHSL->setHint("Load selected HSL curves with selection data. \n Warning : the curves may not be refreshed click on overlay to refresh.");
00263                 selectionToCurveButtonHSL->setParent(groupHSL);
00264                 
00265                 //Append selection to curves button (HSL)
00266                 OFX::PushButtonParamDescriptor* appendSelectionToCurveHSL = desc.definePushButtonParam(kButtonAppendSelectionToCurveHSL);
00267                 appendSelectionToCurveHSL->setLabel(kButtonAppendSelectionToCurveHSLLabel);                             //add label
00268                 appendSelectionToCurveHSL->setHint("Append current selection to selected HSL channels");//help
00269                 appendSelectionToCurveHSL->setParent(groupHSL);                                                                                 //add to HSL group
00270                 
00271                 
00272                 //Close RGB group (group states by default on screen)
00273                 groupRGB->setOpen(false);
00274                 groupHSL->setOpen(true);
00275         }
00276         
00277         //Selection group
00278         {
00279                 OFX::GroupParamDescriptor *groupSelection = desc.defineGroupParam(kGroupSelection);
00280                 groupSelection->setLabel(kGroupSelectionLabel);
00281                 groupSelection->setOpen(false);
00282                 groupSelection->setAsTab();
00283                 //display selection
00284                 OFX::BooleanParamDescriptor* boolDisplaySelection = desc.defineBooleanParam(kBoolSelection);
00285                 boolDisplaySelection->setDefault(true);
00286                 boolDisplaySelection->setEvaluateOnChange(false);// don't need to recompute on change
00287                 boolDisplaySelection->setHint("Display the selected zone on screen.");
00288                 boolDisplaySelection->setParent(groupSelection);
00289                 //clear selection
00290                 OFX::PushButtonParamDescriptor* resetSelectionButton = desc.definePushButtonParam(kButtonResetSelection);
00291                 resetSelectionButton->setLabel(kButtonResetSelectionLabel);
00292                 resetSelectionButton->setHint("Reset user's selection.");
00293                 resetSelectionButton->setParent(groupSelection);
00294                 //selection mode
00295                 OFX::ChoiceParamDescriptor* selectionMode = desc.defineChoiceParam(kSelectionModeListParamLabel);
00296                 selectionMode->setLabel(kSelectionModeListParamLabel);
00297                 selectionMode->setHint( "Selection mode \n - unique : reset past selection before selection \n - additive : add pixels to current selection \n -subtractive : remote pixel from current selection");
00298                 selectionMode->appendOption(kSelectionModeListParamOpt2);
00299                 selectionMode->appendOption(kSelectionModeListParamOpt1);
00300                 selectionMode->appendOption(kSelectionModeListParamOpt3);
00301                 selectionMode->setParent(groupSelection);
00302                 //Precision of selection to curve
00303                 OFX::IntParamDescriptor* precisionSelectionToCurve = desc.defineIntParam(kprecisionCurveFromSelection);
00304                 precisionSelectionToCurve->setLabel(kprecisionCurveFromSelectionLabel);
00305                 precisionSelectionToCurve->setHint("Determinate curve from selection precision.");
00306                 precisionSelectionToCurve->setRange(1, 1000);
00307                 precisionSelectionToCurve->setDisplayRange(1, 300.0 );
00308                 precisionSelectionToCurve->setDefault(curveFromSelection);
00309                 precisionSelectionToCurve->setEvaluateOnChange(false); // don't need to recompute on change
00310                 precisionSelectionToCurve->setParent(groupSelection);
00311         }
00312         
00313         //Histogram overlay group
00314         {
00315                 OFX::GroupParamDescriptor *groupHistogramOverlay = desc.defineGroupParam(kGroupHistogramOverlay);
00316                 groupHistogramOverlay->setLabel(kGroupHistogramOverlayLabel);
00317                 groupHistogramOverlay->setOpen(true);
00318                 groupHistogramOverlay->setAsTab();
00319 
00320                 //Histogram display settings
00321                 OFX::ChoiceParamDescriptor* gammaType = desc.defineChoiceParam(kHistoDisplayListParamLabel);
00322                 gammaType->setLabel(kHistoDisplayListParamLabel);
00323                 gammaType->setEvaluateOnChange(false); // don't need to recompute on change
00324                 gammaType->setHint("Histogram display \n -global : normalize all of channels \n -by channel : keep proportions between channels");
00325                 gammaType->appendOption(kHistoDisplayListParamOpt2);
00326                 gammaType->appendOption(kHistoDisplayListParamOpt1);
00327                 gammaType->setParent(groupHistogramOverlay);    
00328 
00329                 //Clean all Button
00330                 OFX::PushButtonParamDescriptor* resetButtonAll = desc.definePushButtonParam(kButtonResetAll);
00331                 resetButtonAll->setLabel(kButtonResetAllLabel);
00332                 resetButtonAll->setHint("Reset all curves. \n Waring : the curves may not be refreshed click on overlay to refresh.");
00333                 resetButtonAll->setParent(groupHistogramOverlay);
00334         }
00335         
00336         ///Advanced group
00337         {
00338                 OFX::GroupParamDescriptor *groupAdvanced = desc.defineGroupParam(kGroupAdvanced);
00339                 groupAdvanced->setLabel(kGroupAdvancedLabel);
00340                 groupAdvanced->setOpen(false);
00341                 groupAdvanced->setAsTab();
00342                 
00343                 //nbOfstep (advanced group)
00344                 OFX::IntParamDescriptor* nbStepRange = desc.defineIntParam(knbStepRange);
00345                 nbStepRange->setLabel(knbStepRangeLabel);
00346                 nbStepRange->setHint("Determinate histogram overlay precision.");
00347                 nbStepRange->setRange(1, 1000);
00348                 nbStepRange->setDisplayRange(1, 600.0 );
00349                 nbStepRange->setDefault(255);
00350                 nbStepRange->setEvaluateOnChange(false); // don't need to recompute on change
00351                 nbStepRange->setParent(groupAdvanced);
00352                 //selection multiplier (advanced group)
00353                 OFX::DoubleParamDescriptor* selectionMultiplier = desc.defineDoubleParam(kselectionMultiplier);
00354                 selectionMultiplier->setLabel(kselectionMultiplierLabel);
00355                 selectionMultiplier->setHint("With high values, small selection are more visible.");
00356                 selectionMultiplier->setRange(0.001,1000.0);
00357                 selectionMultiplier->setDisplayRange(0.0, 100.0 );
00358                 selectionMultiplier->setDefault(2.0);
00359                 selectionMultiplier->setEvaluateOnChange(false); // don't need to recompute on change
00360                 selectionMultiplier->setParent(groupAdvanced);
00361 
00362                 //Refresh histograms overlay Button
00363                 OFX::PushButtonParamDescriptor* refreshOverlayButton = desc.definePushButtonParam(kButtonRefreshOverlay);
00364                 refreshOverlayButton->setLabel(kButtonRefreshOverlayLabel);
00365                 refreshOverlayButton->setHint("Refresh histogram overlay.");
00366                 refreshOverlayButton->setParent(groupAdvanced);
00367                 
00368                 //clamp values to 0 and 1
00369                 OFX::BooleanParamDescriptor* clampCurveValues = desc.defineBooleanParam(kBoolClampValues);
00370                 clampCurveValues->setHint("Clamp curve value : values superior to 1 or inferior to 0 will be clamp in process.");
00371                 clampCurveValues->setDefault(true);
00372                 clampCurveValues->setParent(groupAdvanced);
00373         }
00374         //Output settings
00375         OFX::ChoiceParamDescriptor* outputType = desc.defineChoiceParam(kOutputListParamLabel);
00376         outputType->setLabel(kOutputListParamLabel);
00377         outputType->setHint( "Output type \n Alpha channel or Black and White");
00378         outputType->appendOption(kOutputListParamOpt1);
00379         outputType->appendOption(kOutputListParamOpt2);
00380         outputType->setLayoutHint( OFX::eLayoutHintNoNewLine ); //line is not finished
00381 
00382         //Reverse mask
00383         OFX::BooleanParamDescriptor* boolReverseMask = desc.defineBooleanParam(kBoolReverseMask);
00384         boolReverseMask->setDefault(false);
00385         boolReverseMask->setHint("Revert alpha mask");
00386 }
00387 
00388 /**
00389  * @brief Function called to create a plugin effect instance
00390  * @param[in] handle  Effect handle
00391  * @param[in] context Application context
00392  * @return  plugin instance
00393  */
00394 OFX::ImageEffect* HistogramKeyerPluginFactory::createInstance( OfxImageEffectHandle handle,OFX::EContext context )
00395 {
00396         return new HistogramKeyerPlugin( handle );
00397 }
00398 
00399 }
00400 }
00401 }
00402