/**
   * One-time setup in response to Application InitSignal.
   */
  void Create( Application& application )
  {
    Stage stage = Stage::GetCurrent();

    stage.KeyEventSignal().Connect(this, &TextLabelMultiLanguageExample::OnKeyEvent);
    stage.SetBackgroundColor( Color::WHITE );

    mTableView = Toolkit::TableView::New( NUMBER_OF_LANGUAGES, 1 );
    mTableView.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
    mTableView.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
    mTableView.SetParentOrigin( ParentOrigin::TOP_LEFT );
    mTableView.SetAnchorPoint( AnchorPoint::TOP_LEFT );
    mTableView.TouchSignal().Connect( this, &TextLabelMultiLanguageExample::OnTouch );
    stage.Add( mTableView );

    for( unsigned int index = 0u; index < NUMBER_OF_LANGUAGES; ++index )
    {
      const Language& language = LANGUAGES[index];

      TextLabel label = TextLabel::New();
      label.SetProperty( TextLabel::Property::MULTI_LINE, true );

      const std::string text = language.languageName + " " + language.languageRomanName + " " + language.text;
      label.SetProperty( TextLabel::Property::TEXT, text );

      mTableView.SetFitHeight( index );
      mTableView.AddChild( label, Toolkit::TableView::CellPosition( index, 0 ) );
    }
  }
Example #2
0
  // The Init signal is received once (only) during the Application lifetime
  void Create( Application& application )
  {
    Stage stage = Stage::GetCurrent();
    stage.SetBackgroundColor( Color::WHITE );
    stage.KeyEventSignal().Connect(this, &EmojiExample::OnKeyEvent);

    mTableView = Toolkit::TableView::New( NUMBER_OF_EMOJIS, 1 );
    mTableView.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
    mTableView.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
    mTableView.SetParentOrigin( ParentOrigin::TOP_LEFT );
    mTableView.SetAnchorPoint( AnchorPoint::TOP_LEFT );
    mTableView.TouchedSignal().Connect( this, &EmojiExample::OnTouchEvent );
    stage.Add( mTableView );

    for( unsigned int index = 0u; index < NUMBER_OF_EMOJIS; ++index )
    {
      const Emoji& emoji = EMOJIS[index];
      const std::string text = emoji.mUTF8 + " " + emoji.mDescription;

      TextLabel label = TextLabel::New( text );
      label.SetParentOrigin( ParentOrigin::TOP_CENTER );
      label.SetAnchorPoint( AnchorPoint::TOP_CENTER );
      label.SetProperty( TextLabel::Property::MULTI_LINE, true );

      mTableView.SetFitHeight( index );
      mTableView.AddChild( label, Toolkit::TableView::CellPosition( index, 0 ) );
    }
  }
Example #3
0
  void OnInit( Application& application )
  {
    // Create a ScrollView instance
    ScrollView scrollView = ScrollView::New();
    scrollView.SetParentOrigin( ParentOrigin::CENTER );
    Stage stage = Stage::GetCurrent();
    stage.Add(scrollView);

    // Set the size of scrollView; it covers the entire stage
    Size size = stage.GetSize();
    scrollView.SetSize(size);

    // Add actors to the ScrollView
    for( int i = 0; i < NUM_IMAGES; ++i )
    {
      AddImage( scrollView, size, i );
    }

    // The ScrollView contents are now draggable
    // To enforce horizontal-only scrolling, the Y axis ruler can be disabled
    RulerPtr rulerY = new DefaultRuler();
    rulerY->Disable();
    scrollView.SetRulerY( rulerY );

    // A domain can be applied to rulers to prevent scrolling beyond this boundary
    // In this case, to 4 times the width of the stage, allowing for 4 pages to be scrolled
    RulerPtr rulerX2 = new FixedRuler( size.width );
    rulerX2->SetDomain( RulerDomain( 0.0f, size.width*NUM_IMAGES ) );
    scrollView.SetRulerX( rulerX2 );

    // Connect key event signal
    stage.KeyEventSignal().Connect( this, &ScrollViewSample::OnKeyEvent );
  }
Example #4
0
  /**
   * One-time setup in response to Application InitSignal.
   */
  void Create( Application& application )
  {
    Stage stage = Stage::GetCurrent();
    Vector2 stageSize = stage.GetSize();

    stage.KeyEventSignal().Connect(this, &TextFontsExample::OnKeyEvent);

    CreateFolderButton ( mButton );
    mButton.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
    mButton.ClickedSignal().Connect( this, &TextFontsExample::OnButtonClicked );
    stage.Add( mButton );

    mLayoutSize = Vector2( stageSize.width*0.5f, stageSize.height*0.10f );
    CreateContainer ( mContainer , mLayoutSize);
    CreateContainer ( mContainer2 , mLayoutSize );
    CreateContainer ( mContainer3 , mLayoutSize );

    // Info about Text Label and if font should be fixed or free to change with system
    CreateContainer ( mContainerInfo , mLayoutSize );
    CreateContainer ( mContainer2Info , mLayoutSize );
    CreateContainer ( mContainer3Info , mLayoutSize );
    mContainerInfo.SetParentOrigin( ParentOrigin::TOP_RIGHT );
    mContainer2Info.SetParentOrigin( ParentOrigin::TOP_RIGHT );
    mContainer3Info.SetParentOrigin( ParentOrigin::TOP_RIGHT );
    mContainer.Add( mContainerInfo );
    mContainer2.Add( mContainer2Info );
    mContainer3.Add( mContainer3Info );
    CreateTextLabel ( mLabelInfo, "system free", Color::BLACK, true  );
    CreateTextLabel ( mLabel2Info, "json fixed", Color::BLACK, true  );
    CreateTextLabel ( mLabel3Info, "SetProp fixed", Color::BLACK, true  );
    mContainerInfo.Add( mLabelInfo );
    mContainer2Info.Add( mLabel2Info );
    mContainer3Info.Add( mLabel3Info );

    stage.Add( mContainer );
    stage.Add( mContainer2 );
    stage.Add( mContainer3 );

    CreateTextLabel ( mLabel, LABEL_TEXT, Color::WHITE  );

    CreateTextLabel ( mLabel2, LABEL_TEXT, Color::WHITE  );
    mLabel2.SetStyleName("textlabel-Rosemary");

    CreateTextLabel ( mLabel3, LABEL_TEXT, Color::WHITE  );
    mLabel3.SetProperty( TextLabel::Property::FONT_FAMILY, "SamsungOneUI" );

    mContainer.SetPosition( 0, 0 );
    mContainer2.SetPosition( 0, stageSize.height*0.25f );
    mContainer3.SetPosition( 0, stageSize.height*0.25f*2 );

    mContainer.Add( mLabel );
    mContainer2.Add( mLabel2 );
    mContainer3.Add( mLabel3 );
  }
Example #5
0
int UtcDaliStageSignalKeyEventP(void)
{
  TestApplication application;
  Stage stage = Stage::GetCurrent();

  KeyEventSignalData data;
  KeyEventReceivedFunctor functor( data );
  stage.KeyEventSignal().Connect( &application, functor );

  Integration::KeyEvent event( "i", "i", 0, 0, 0, Integration::KeyEvent::Down );
  application.ProcessEvent( event );

  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
  DALI_TEST_CHECK( event.keyModifier == data.receivedKeyEvent.keyModifier );
  DALI_TEST_CHECK( event.keyName == data.receivedKeyEvent.keyPressedName );
  DALI_TEST_CHECK( event.keyString == data.receivedKeyEvent.keyPressed );
  DALI_TEST_CHECK( event.state == static_cast<Integration::KeyEvent::State>( data.receivedKeyEvent.state ) );

  data.Reset();

  Integration::KeyEvent event2( "i", "i", 0, 0, 0, Integration::KeyEvent::Up );
  application.ProcessEvent( event2 );

  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
  DALI_TEST_CHECK( event2.keyModifier == data.receivedKeyEvent.keyModifier );
  DALI_TEST_CHECK( event2.keyName == data.receivedKeyEvent.keyPressedName );
  DALI_TEST_CHECK( event2.keyString == data.receivedKeyEvent.keyPressed );
  DALI_TEST_CHECK( event2.state == static_cast<Integration::KeyEvent::State>( data.receivedKeyEvent.state ) );

  data.Reset();

  Integration::KeyEvent event3( "a", "a", 0, 0, 0, Integration::KeyEvent::Down );
  application.ProcessEvent( event3 );

  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
  DALI_TEST_CHECK( event3.keyModifier == data.receivedKeyEvent.keyModifier );
  DALI_TEST_CHECK( event3.keyName == data.receivedKeyEvent.keyPressedName );
  DALI_TEST_CHECK( event3.keyString == data.receivedKeyEvent.keyPressed );
  DALI_TEST_CHECK( event3.state == static_cast<Integration::KeyEvent::State>( data.receivedKeyEvent.state ) );

  data.Reset();

  Integration::KeyEvent event4( "a", "a", 0, 0, 0, Integration::KeyEvent::Up );
  application.ProcessEvent( event4 );

  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
  DALI_TEST_CHECK( event4.keyModifier == data.receivedKeyEvent.keyModifier );
  DALI_TEST_CHECK( event4.keyName == data.receivedKeyEvent.keyPressedName );
  DALI_TEST_CHECK( event4.keyString == data.receivedKeyEvent.keyPressed );
  DALI_TEST_CHECK( event4.state == static_cast<Integration::KeyEvent::State>( data.receivedKeyEvent.state ) );
  END_TEST;
}
Example #6
0
int UtcDaliStageSignalKeyEventN(void)
{
  TestApplication application;
  Stage stage = Stage::GetCurrent();

  KeyEventSignalData data;
  KeyEventReceivedFunctor functor( data );
  stage.KeyEventSignal().Connect( &application, functor );

  // Check that a non-pressed key events data is not modified.
  DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION );

  END_TEST;
}
void EffectsViewApp::OnAppInitialize( Application& application )
{
  // The Init signal is received once (only) during the Application lifetime

  Stage stage = Stage::GetCurrent();
  stage.KeyEventSignal().Connect(this, &EffectsViewApp::OnKeyEvent);
  stage.SetBackgroundColor( Color::WHITE );

  mStageSize = stage.GetSize();

  // Creates a default view with a default tool bar.
  // The view is added to the stage.
  mContents = DemoHelper::CreateView( application, mView, mToolBar, "", TOOLBAR_IMAGE, "" );

  // Creates view change button.
  Toolkit::PushButton viewButton = Toolkit::PushButton::New();
  viewButton.SetUnselectedImage( VIEW_SWAP_IMAGE );
  viewButton.SetSelectedImage( VIEW_SWAP_SELECTED_IMAGE );
  // Connects the view change button clicked signal to the OnView method.
  viewButton.ClickedSignal().Connect( this, &EffectsViewApp::ChangeEffectSize );
  mToolBar.AddControl( viewButton, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HorizontalRight, DemoHelper::DEFAULT_MODE_SWITCH_PADDING  );

  Vector2 effectsViewSize( mStageSize.width, mStageSize.height * 0.25f );
  mDropShadowView = CreateEffectsView( EffectsView::DROP_SHADOW, effectsViewSize, mEffectSize );
  mDropShadowView.SetParentOrigin( ParentOrigin::CENTER );
  mDropShadowView.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
  mDropShadowView.SetZ( -mStageSize.height * 0.1f );
  mContents.Add( mDropShadowView );

  mEmbossView = CreateEffectsView( EffectsView::EMBOSS, effectsViewSize, mEffectSize );
  mEmbossView.SetParentOrigin( ParentOrigin::CENTER );
  mEmbossView.SetAnchorPoint( AnchorPoint::TOP_CENTER );
  mEmbossView.SetZ( mStageSize.height * 0.1f );
  mContents.Add( mEmbossView );

  SetTitle( mEffectSize );
}
  /**
   * @brief This is the main scene setup method for this demo.
   * This is called via the Init signal which is received once (only) during the Application lifetime.
   * @param[in] application The DALi application object
   */
  void Create( Application& application )
  {
    Stage stage = Stage::GetCurrent();

    // Creates a default view with a default tool-bar.
    // The view is added to the stage.
    Toolkit::ToolBar toolBar;
    Layer toolBarLayer = DemoHelper::CreateView( application, mView, toolBar, BACKGROUND_IMAGE, TOOLBAR_IMAGE, APPLICATION_TITLE );
    stage.Add( toolBarLayer );

    // Layer to hold the 3D scene.
    Layer layer = Layer::New();
    layer.SetAnchorPoint( AnchorPoint::CENTER );
    // Set the parent origin to a small percentage below the center (so the demo will scale for different resolutions).
    layer.SetParentOrigin( Vector3( 0.5f, 0.58f, 0.5f ) );
    layer.SetBehavior( Layer::LAYER_2D );
    layer.SetDepthTestDisabled( false );
    stage.Add( layer );

    // Main cube:
    // Make the demo scalable with different resolutions by basing
    // the cube size on a percentage of the stage size.
    float scaleSize( std::min( stage.GetSize().width, stage.GetSize().height ) );
    float cubeWidth( scaleSize * CUBE_WIDTH_SCALE );
    Vector3 cubeSize( cubeWidth, cubeWidth, cubeWidth );
    // Create the geometry for the cube, and the texture.
    Geometry cubeGeometry = CreateCubeVertices( Vector3::ONE, false );
    TextureSet cubeTextureSet = CreateTextureSet( CUBE_TEXTURE );
    // Create the cube object and add it.
    // Note: The cube is anchored around its base for animation purposes, so the position can be zero.
    mCubes[ MAIN_CUBE ] = CreateMainCubeObject( cubeGeometry, cubeSize, cubeTextureSet );
    layer.Add( mCubes[ MAIN_CUBE ] );

    // Floor:
    float floorWidth( scaleSize * FLOOR_DIMENSION_SCALE.x );
    Vector3 floorSize( floorWidth, scaleSize * FLOOR_DIMENSION_SCALE.y, floorWidth );
    // Create the floor object using the cube geometry with a new size, and add it.
    Actor floorObject( CreateFloorObject( cubeGeometry, floorSize ) );
    layer.Add( floorObject );

    // Stencil:
    Vector3 planeSize( floorWidth, floorWidth, 0.0f );
    // Create the stencil plane object, and add it.
    Actor stencilPlaneObject( CreateStencilPlaneObject( planeSize ) );
    layer.Add( stencilPlaneObject );

    // Reflection cube:
    // Create the reflection cube object and add it.
    // Note: The cube is anchored around its base for animation purposes, so the position can be zero.
    mCubes[ REFLECTION_CUBE ] = CreateReflectionCubeObject( cubeSize, cubeTextureSet );
    layer.Add( mCubes[ REFLECTION_CUBE ] );

    // Rotate the layer so we can see some of the top of the cube for a more 3D effect.
    layer.SetProperty( Actor::Property::ORIENTATION, Quaternion( Degree( -24.0f ), Degree( 0.0f ), Degree( 0.0f ) ) );

    // Set up the rotation on the Y axis.
    mRotationAnimation = Animation::New( ANIMATION_ROTATION_DURATION );
    float fullRotation = 360.0f;
    mRotationAnimation.AnimateBy( Property( mCubes[ MAIN_CUBE ], Actor::Property::ORIENTATION ),
                                 Quaternion( Degree( 0.0f ), Degree( fullRotation ), Degree( 0.0f ) ) );
    mRotationAnimation.AnimateBy( Property( floorObject, Actor::Property::ORIENTATION ),
                                 Quaternion( Degree( 0.0f ), Degree( fullRotation ), Degree( 0.0f ) ) );
    // Note the stencil is pre-rotated by 90 degrees on X, so we rotate relatively on its Z axis for an equivalent Y rotation.
    mRotationAnimation.AnimateBy( Property( stencilPlaneObject, Actor::Property::ORIENTATION ),
                                 Quaternion( Degree( 0.0f ), Degree( 0.0f ), Degree( fullRotation ) ) );
    mRotationAnimation.AnimateBy( Property( mCubes[ REFLECTION_CUBE ], Actor::Property::ORIENTATION ),
                                 Quaternion( Degree( 0.0f ), Degree( fullRotation ), Degree( 0.0f ) ) );
    mRotationAnimation.SetLooping( true );

    // Set up the cube bouncing animation.
    float totalTime = ANIMATION_BOUNCE_TOTAL_TIME;
    float deformationTime = ANIMATION_BOUNCE_DEFORMATION_TIME;
    // Percentage based amounts allows the bounce and deformation to scale for different resolution screens.
    float deformationAmount = ANIMATION_BOUNCE_DEFORMATION_PERCENT / 100.0f;
    float heightChange = ( cubeSize.y * ANIMATION_BOUNCE_HEIGHT_PERCENT ) / 100.0f;

    // Animation pre-calculations:
    float halfTime = totalTime / 2.0f;
    float halfDeformationTime = deformationTime / 2.0f;

    // First position the cubes at the top of the animation cycle.
    mCubes[ MAIN_CUBE ].SetProperty(       Actor::Property::POSITION_Y, -heightChange );
    mCubes[ REFLECTION_CUBE ].SetProperty( Actor::Property::POSITION_Y,  heightChange );

    mBounceAnimation = Animation::New( totalTime );

    // The animations for the main and reflected cubes are almost identical, so we combine the code to do both.
    for( int cube = 0; cube < 2; ++cube )
    {
      // If iterating on the reflection cube, adjust the heightChange variable so the below code can be reused.
      if( cube == 1 )
      {
        heightChange = -heightChange;
      }

      // 1st TimePeriod: Start moving down with increasing speed, until it is time to distort the cube due to impact.
      mBounceAnimation.AnimateBy( Property( mCubes[ cube ], Actor::Property::POSITION_Y ),  heightChange, AlphaFunction::EASE_IN_SQUARE, TimePeriod( 0.0f, halfTime - halfDeformationTime ) );

      // 2nd TimePeriod: The cube is touching the floor, start deforming it - then un-deform it again.
      mBounceAnimation.AnimateBy( Property( mCubes[ cube ], Actor::Property::SCALE_X ),  deformationAmount, AlphaFunction::BOUNCE, TimePeriod( halfTime - halfDeformationTime, deformationTime ) );
      mBounceAnimation.AnimateBy( Property( mCubes[ cube ], Actor::Property::SCALE_Z ),  deformationAmount, AlphaFunction::BOUNCE, TimePeriod( halfTime - halfDeformationTime, deformationTime ) );
      mBounceAnimation.AnimateBy( Property( mCubes[ cube ], Actor::Property::SCALE_Y ), -deformationAmount, AlphaFunction::BOUNCE, TimePeriod( halfTime - halfDeformationTime, deformationTime ) );

      // 3rd TimePeriod: Start moving up with decreasing speed, until at the apex of the animation.
      mBounceAnimation.AnimateBy( Property( mCubes[ cube ], Actor::Property::POSITION_Y ), -heightChange, AlphaFunction::EASE_OUT_SQUARE, TimePeriod( halfTime + halfDeformationTime, halfTime - halfDeformationTime ) );
    }

    mBounceAnimation.SetLooping( true );

    // Start the animations.
    mRotationAnimation.Play();
    mBounceAnimation.Play();

    // Respond to a click anywhere on the stage
    stage.GetRootLayer().TouchSignal().Connect( this, &RendererStencilExample::OnTouch );
    // Connect signals to allow Back and Escape to exit.
    stage.KeyEventSignal().Connect( this, &RendererStencilExample::OnKeyEvent );
  }
Example #9
0
  void Create( Application& application )
  {
    // Get a handle to the stage
    Stage stage = Stage::GetCurrent();
    stage.SetBackgroundColor(Color::YELLOW);

    // Respond to a click anywhere on the stage
    stage.KeyEventSignal().Connect(this, &AtlasController::OnKeyEvent);

    mApplication.GetWindow().ShowIndicator( Dali::Window::INVISIBLE );

    mContentLayer = DemoHelper::CreateView( mApplication,
        mView,
        mToolBar,
        BACKGROUND_IMAGE,
        TOOLBAR_IMAGE,
        "Atlas" );

    mLoseContextButton = Toolkit::PushButton::New();
    mLoseContextButton.SetUnselectedImage( LOSE_CONTEXT_IMAGE );
    mLoseContextButton.SetSelectedImage( LOSE_CONTEXT_IMAGE_SELECTED );
    mLoseContextButton.ClickedSignal().Connect( this, &AtlasController::OnLoseContextButtonClicked );
    mToolBar.AddControl( mLoseContextButton, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HorizontalRight, DemoHelper::DEFAULT_MODE_SWITCH_PADDING );

    mAtlas = Atlas::New( 400,300, Pixel::RGBA8888);
    mAtlas.Clear(Vector4(0.f,0.5f,0.5f,0.5f));
    mAtlas.Upload( DALI_IMAGE_DIR "icon-change.png", 50, 30 );
    mAtlas.Upload( DALI_IMAGE_DIR "icon-cluster-carousel.png", 100, 30 );
    mAtlas.Upload( DALI_IMAGE_DIR "icon-effects-on.png", 150, 30 );
    mAtlas.Upload( DALI_IMAGE_DIR "icon-effect-cross.png", 100, 80 );
    mAtlas.Upload( DALI_IMAGE_DIR "icon-effect-fold.png", 150, 80 );
    mAtlas.Upload( DALI_IMAGE_DIR "icon-effect-wave.png", 200, 80 );
    mAtlas.Upload( DALI_IMAGE_DIR "icon-item-view-layout-depth.png", 150, 130 );
    mAtlas.Upload( DALI_IMAGE_DIR "icon-item-view-layout-grid.png", 200, 130 );
    mAtlas.Upload( DALI_IMAGE_DIR "icon-item-view-layout-spiral.png", 250, 130 );
    UploadBufferImages();

    Toolkit::ImageView imageActor1 = Toolkit::ImageView::New( mAtlas );
    imageActor1.SetY(-170.f);
    imageActor1.SetParentOrigin(ParentOrigin::CENTER);
    mContentLayer.Add( imageActor1 );

    Atlas atlas2 = Atlas::New( 400,400, Pixel::RGB888);
    atlas2.Clear( Color::RED );
    atlas2.Upload( DALI_IMAGE_DIR "gallery-small-1.jpg", 4, 4 );
    atlas2.Clear( Color::BLUE );
    atlas2.Upload( DALI_IMAGE_DIR "gallery-small-2.jpg", 136, 4 );
    atlas2.Upload( DALI_IMAGE_DIR "gallery-small-3.jpg", 268, 4 );
    atlas2.Upload( DALI_IMAGE_DIR "gallery-small-4.jpg", 4, 136 );
    atlas2.Upload( DALI_IMAGE_DIR "gallery-small-5.jpg", 136, 136 );
    atlas2.Upload( DALI_IMAGE_DIR "gallery-small-6.jpg", 268, 135 );
    atlas2.Upload( DALI_IMAGE_DIR "gallery-small-7.jpg", 4, 268 );
    atlas2.Upload( DALI_IMAGE_DIR "gallery-small-7.jpg", 136, 268 );
    atlas2.Upload( DALI_IMAGE_DIR "gallery-small-7.jpg", 268, 268 );


    Toolkit::ImageView imageView = Toolkit::ImageView::New( DALI_IMAGE_DIR "gallery-small-1.jpg" );

    imageView.SetY(200.f);
    imageView.SetZ(-1.f);
    imageView.SetParentOrigin(ParentOrigin::CENTER);
    mContentLayer.Add( imageView );

    mPanGestureDetector = PanGestureDetector::New();
    mPanGestureDetector.DetectedSignal().Connect( this, &AtlasController::OnPanGesture );
    mPanGestureDetector.Attach( imageActor1 );
    mPanGestureDetector.Attach( imageView );

    stage.ContextLostSignal().Connect( this, &AtlasController::OnContextLost );
    stage.ContextRegainedSignal().Connect( this, &AtlasController::OnContextRegained );
  }