1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_toolkit.hxx"
26 
27 #ifndef _TOOLKIT_ROADMAP_CONTROL_HXX
28 #include <toolkit/controls/roadmapcontrol.hxx>
29 #endif
30 #include <toolkit/helper/unopropertyarrayhelper.hxx>
31 #include <toolkit/helper/property.hxx>
32 #include <com/sun/star/awt/XVclWindowPeer.hpp>
33 #include <comphelper/processfactory.hxx>
34 #include <osl/diagnose.h>
35 
36 //........................................................................
37 namespace toolkit
38 {
39 //........................................................................
40 
41 	using namespace ::com::sun::star::uno;
42 	using namespace ::com::sun::star::awt;
43 	using namespace ::com::sun::star::lang;
44 	using namespace ::com::sun::star::beans;
45     using namespace ::com::sun::star::container;
46 
47 //	----------------------------------------------------
48 //  helper
49 //	----------------------------------------------------
50 
lcl_throwIllegalArgumentException()51 static void lcl_throwIllegalArgumentException( )
52 {	// throwing is expensive (in terms of code size), thus we hope the compiler does not inline this ....
53 	throw IllegalArgumentException();
54 }
55 
lcl_throwIndexOutOfBoundsException()56 static void lcl_throwIndexOutOfBoundsException( )
57 {	// throwing is expensive (in terms of code size), thus we hope the compiler does not inline this ....
58 	throw IndexOutOfBoundsException();
59 }
60 
61 	// ===================================================================
62 	// = UnoControlRoadmapModel
63 	// ===================================================================
64 	// -------------------------------------------------------------------
UnoControlRoadmapModel(const Reference<XMultiServiceFactory> & i_factory)65 	UnoControlRoadmapModel::UnoControlRoadmapModel( const Reference< XMultiServiceFactory >& i_factory )
66         :UnoControlRoadmapModel_Base( i_factory )
67         ,maContainerListeners( *this )
68 	{
69 		ImplRegisterProperty( BASEPROPERTY_BACKGROUNDCOLOR );
70 		ImplRegisterProperty( BASEPROPERTY_BORDER );
71 		ImplRegisterProperty( BASEPROPERTY_BORDERCOLOR );
72 		ImplRegisterProperty( BASEPROPERTY_DEFAULTCONTROL );
73 		ImplRegisterProperty( BASEPROPERTY_FONTDESCRIPTOR );
74 		ImplRegisterProperty( BASEPROPERTY_HELPTEXT );
75 		ImplRegisterProperty( BASEPROPERTY_HELPURL );
76 		ImplRegisterProperty( BASEPROPERTY_IMAGEURL );
77 		ImplRegisterProperty( BASEPROPERTY_GRAPHIC );
78         ImplRegisterProperty( BASEPROPERTY_PRINTABLE );
79 		ImplRegisterProperty( BASEPROPERTY_COMPLETE );
80 		ImplRegisterProperty( BASEPROPERTY_ACTIVATED );
81 		ImplRegisterProperty( BASEPROPERTY_CURRENTITEMID );
82         ImplRegisterProperty( BASEPROPERTY_TABSTOP );
83         ImplRegisterProperty( BASEPROPERTY_TEXT );
84 	}
85 
86 	// -------------------------------------------------------------------
getServiceName()87 	::rtl::OUString UnoControlRoadmapModel::getServiceName() throw(RuntimeException)
88 	{
89 		return ::rtl::OUString::createFromAscii( szServiceName_UnoControlRoadmapModel );
90 	}
91 
92 
93 	// -------------------------------------------------------------------
ImplGetDefaultValue(sal_uInt16 nPropId) const94 	Any UnoControlRoadmapModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const
95 	{
96 		Any aReturn;
97 		switch (nPropId)
98 		{
99                 case BASEPROPERTY_COMPLETE:
100                     aReturn <<= (sal_Bool) sal_True;
101                     break;
102                 case BASEPROPERTY_ACTIVATED:
103                     aReturn <<= (sal_Bool) sal_True;
104                     break;
105                 case BASEPROPERTY_CURRENTITEMID:
106                     aReturn <<= (sal_Int16) -1;
107                     break;
108                 case BASEPROPERTY_TEXT:
109                    break;
110                 case BASEPROPERTY_BORDER:
111                     aReturn <<= (sal_Int16) 2;              // No Border
112                     break;
113 			    case BASEPROPERTY_DEFAULTCONTROL:
114                     aReturn <<= ::rtl::OUString( ::rtl::OUString::createFromAscii( szServiceName_UnoControlRoadmap ) );
115                     break;
116 			default : aReturn = UnoControlRoadmapModel_Base::ImplGetDefaultValue( nPropId ); break;
117 		}
118 
119 		return aReturn;
120 	}
121 
122 
createInstance()123     Reference< XInterface > SAL_CALL UnoControlRoadmapModel::createInstance(  ) throw (Exception, ::com::sun::star::uno::RuntimeException)
124     {
125 		ORoadmapEntry* pRoadmapItem = new ORoadmapEntry();
126 	    Reference< XInterface > xNewRoadmapItem = (::cppu::OWeakObject*)pRoadmapItem;
127 	    return xNewRoadmapItem;
128     }
129 
130 
createInstanceWithArguments(const Sequence<Any> &)131     Reference< XInterface > SAL_CALL UnoControlRoadmapModel::createInstanceWithArguments( const Sequence< Any >& /*aArguments*/ ) throw (Exception, RuntimeException)
132     {
133         // Todo: implementation of the arguments handling
134 		ORoadmapEntry* pRoadmapItem = new ORoadmapEntry();
135 	    Reference< XInterface > xNewRoadmapItem = (::cppu::OWeakObject*)pRoadmapItem;
136 	    return xNewRoadmapItem;
137     }
138 
139 
IMPLEMENT_FORWARD_XTYPEPROVIDER2(UnoControlRoadmapModel,UnoControlRoadmapModel_Base,UnoControlRoadmapModel_IBase)140  IMPLEMENT_FORWARD_XTYPEPROVIDER2( UnoControlRoadmapModel, UnoControlRoadmapModel_Base, UnoControlRoadmapModel_IBase )
141 
142 
143 	// -------------------------------------------------------------------
144     ::com::sun::star::uno::Any	SAL_CALL UnoControlRoadmapModel::queryAggregation( const ::com::sun::star::uno::Type & rType ) throw(::com::sun::star::uno::RuntimeException)
145     {
146         Any aRet = UnoControlRoadmapModel_Base::queryAggregation( rType );
147         if ( !aRet.hasValue() )
148             aRet = UnoControlRoadmapModel_IBase::queryInterface( rType );
149  	    return aRet;
150     }
151 
152 
153 	// -------------------------------------------------------------------
getInfoHelper()154 	::cppu::IPropertyArrayHelper& UnoControlRoadmapModel::getInfoHelper()
155 	{
156 		static UnoPropertyArrayHelper* pHelper = NULL;
157 		if ( !pHelper )
158 		{
159 			Sequence<sal_Int32>	aIDs = ImplGetPropertyIds();
160 			pHelper = new UnoPropertyArrayHelper( aIDs );
161 		}
162 		return *pHelper;
163 	}
164 
165 
166 	// beans::XMultiPropertySet
167 	// -------------------------------------------------------------------
getPropertySetInfo()168 	Reference< XPropertySetInfo > UnoControlRoadmapModel::getPropertySetInfo(  ) throw(RuntimeException)
169 	{
170 		static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
171 		return xInfo;
172 	}
173 
174 
getCount()175     sal_Int32 SAL_CALL UnoControlRoadmapModel::getCount() throw(RuntimeException)
176     {
177         return maRoadmapItems.size();
178     }
179 
getByIndex(sal_Int32 Index)180     Any SAL_CALL UnoControlRoadmapModel::getByIndex( sal_Int32 Index ) throw (IndexOutOfBoundsException, WrappedTargetException, RuntimeException )
181     {
182         if (( Index >= (sal_Int32)maRoadmapItems.size()) || (Index < 0))
183             lcl_throwIndexOutOfBoundsException( );
184         Any aAny;
185         aAny = makeAny( maRoadmapItems.at( Index ));
186         return aAny;
187     }
188 
189 
190 
MakeRMItemValidation(sal_Int32 Index,Reference<XInterface> xRoadmapItem)191     void UnoControlRoadmapModel::MakeRMItemValidation( sal_Int32 Index, Reference< XInterface > xRoadmapItem )
192     {
193         if ((Index > (sal_Int32)maRoadmapItems.size()) || ( Index < 0 ) )
194             lcl_throwIndexOutOfBoundsException( );
195         if ( !xRoadmapItem.is() )
196 		    lcl_throwIllegalArgumentException();
197         Reference< XServiceInfo > xServiceInfo( xRoadmapItem, UNO_QUERY );
198         sal_Bool bIsRoadmapItem = xServiceInfo->supportsService( ::rtl::OUString::createFromAscii( "com.sun.star.awt.RoadmapItem" ) );
199         if ( !bIsRoadmapItem )
200     	    lcl_throwIllegalArgumentException();
201     }
202 
203 
SetRMItemDefaultProperties(const sal_Int32,Reference<XInterface> xRoadmapItem)204     void UnoControlRoadmapModel::SetRMItemDefaultProperties( const sal_Int32 , Reference< XInterface > xRoadmapItem)
205     {
206 		Any	aAny;
207         Reference< XPropertySet > xPropertySet( xRoadmapItem, UNO_QUERY );
208         Reference< XPropertySet > xProps( xRoadmapItem, UNO_QUERY );
209 	    if ( xProps.is() )
210         {
211             sal_Int32 LocID = 0;
212             Any aValue = xPropertySet->getPropertyValue( ::rtl::OUString::createFromAscii( "ID" ) );
213             aValue >>= LocID;
214             if (LocID < 0)              // index may not be smaller than zero
215             {
216                 aAny <<= GetUniqueID();
217                 xPropertySet->setPropertyValue( ::rtl::OUString::createFromAscii( "ID" ), aAny );
218             }
219         }
220     }
221 
222 
223 // The performance of this method could certainly be improved.
224 // As long as only vectors with up to 10 elements are
225 // involved it should be sufficient
GetUniqueID()226        sal_Int32 UnoControlRoadmapModel::GetUniqueID()
227       {
228           Any aAny;
229           sal_Bool bIncrement = sal_True;
230           sal_Int32 CurID = 0;
231           sal_Int32 n_CurItemID = 0;
232           Reference< XInterface > CurRoadmapItem;
233           while ( bIncrement )
234           {
235  	      bIncrement = sal_False;
236               for ( RoadmapItemHolderList::iterator i = maRoadmapItems.begin(); i < maRoadmapItems.end(); i++ )
237               {
238                 CurRoadmapItem = *i;
239                 Reference< XPropertySet > xPropertySet( CurRoadmapItem, UNO_QUERY );
240                 aAny = xPropertySet->getPropertyValue( ::rtl::OUString::createFromAscii( "ID" ) );
241                 aAny >>= n_CurItemID;
242                 if (n_CurItemID == CurID)
243                 {
244                     bIncrement = sal_True;
245                     CurID++;
246                     break;
247                 }
248             }
249         }
250         return CurID;
251     }
252 
253 
GetContainerEvent(sal_Int32 Index,Reference<XInterface> xRoadmapItem)254     ContainerEvent UnoControlRoadmapModel::GetContainerEvent(sal_Int32 Index, Reference< XInterface > xRoadmapItem)
255     {
256 	    ContainerEvent aEvent;
257 	    aEvent.Source = *this;
258 	    aEvent.Element <<= xRoadmapItem;
259         aEvent.Accessor = makeAny(Index);
260         return aEvent;
261     }
262 
263 
GetCurrentItemID(Reference<XPropertySet> xPropertySet)264     sal_Int16 UnoControlRoadmapModel::GetCurrentItemID( Reference< XPropertySet > xPropertySet )
265     {
266         Any aAny = xPropertySet->getPropertyValue( GetPropertyName( BASEPROPERTY_CURRENTITEMID ) );
267         sal_Int16 n_CurrentItemID = 0;
268         aAny >>= n_CurrentItemID;
269         return n_CurrentItemID;
270     }
271 
272 
insertByIndex(const sal_Int32 Index,const Any & _Element)273     void SAL_CALL UnoControlRoadmapModel::insertByIndex( const sal_Int32 Index, const Any& _Element)
274                                     throw (IllegalArgumentException, IndexOutOfBoundsException, WrappedTargetException, RuntimeException )
275     {
276         if ( ( Index >= ( (sal_Int32)maRoadmapItems.size() + 1 ) ) || (Index < 0))
277             lcl_throwIndexOutOfBoundsException( );
278         Reference< XInterface > xRoadmapItem;
279         _Element >>= xRoadmapItem;
280         MakeRMItemValidation( Index, xRoadmapItem);
281         SetRMItemDefaultProperties( Index, xRoadmapItem );
282         maRoadmapItems.insert( maRoadmapItems.begin() + Index, xRoadmapItem);
283 	    ContainerEvent aEvent = GetContainerEvent(Index, xRoadmapItem);
284 	    maContainerListeners.elementInserted( aEvent );
285         Reference< XPropertySet > xPropertySet( (XAggregation*) (::cppu::OWeakAggObject*)this, UNO_QUERY );
286         sal_Int16 n_CurrentItemID = GetCurrentItemID( xPropertySet );
287         if ( Index <= n_CurrentItemID )
288         {
289             Any aAny;
290             aAny <<= ( sal_Int16 ) ( n_CurrentItemID + 1 );
291             xPropertySet->setPropertyValue( GetPropertyName( BASEPROPERTY_CURRENTITEMID ), aAny );
292         }
293     }
294 
295 
296 
removeByIndex(sal_Int32 Index)297     void SAL_CALL UnoControlRoadmapModel::removeByIndex( sal_Int32 Index)
298                                                 throw	 (IndexOutOfBoundsException, WrappedTargetException, RuntimeException )
299     {
300         if (( Index > (sal_Int32)maRoadmapItems.size()) || (Index < 0))
301             lcl_throwIndexOutOfBoundsException( );
302         Reference< XInterface > xRoadmapItem;
303         maRoadmapItems.erase( maRoadmapItems.begin() + Index );
304 	    ContainerEvent aEvent = GetContainerEvent(Index, xRoadmapItem);
305 	    maContainerListeners.elementRemoved( aEvent );
306         Reference< XPropertySet > xPropertySet( (XAggregation*) (::cppu::OWeakAggObject*)this, UNO_QUERY );
307         sal_Int16 n_CurrentItemID = GetCurrentItemID( xPropertySet );
308         Any aAny;
309         if ( Index <= n_CurrentItemID )
310         {
311             if ( n_CurrentItemID >= (sal_Int32)maRoadmapItems.size() )
312             {
313                 n_CurrentItemID = sal::static_int_cast< sal_Int16 >(
314                     maRoadmapItems.size()-1);
315                 if ( n_CurrentItemID < 0 )
316                     return;
317                 aAny <<= n_CurrentItemID;
318             }
319             else if (Index == n_CurrentItemID)
320                 aAny <<= ( sal_Int16 ) -1;
321             else if( Index < n_CurrentItemID)
322                 aAny <<= ( sal_Int16 ) ( n_CurrentItemID - 1 );
323             xPropertySet->setPropertyValue( GetPropertyName( BASEPROPERTY_CURRENTITEMID ), aAny );
324         }
325     }
326 
327 
replaceByIndex(const sal_Int32 Index,const Any & _Element)328 	void SAL_CALL UnoControlRoadmapModel::replaceByIndex( const sal_Int32 Index, const Any& _Element)
329                                 throw (IllegalArgumentException, IndexOutOfBoundsException, WrappedTargetException, RuntimeException )
330     {
331         Reference< XInterface > xRoadmapItem;
332         _Element >>= xRoadmapItem;
333         MakeRMItemValidation( Index, xRoadmapItem);
334         SetRMItemDefaultProperties( Index, xRoadmapItem );
335         maRoadmapItems.erase( maRoadmapItems.begin() + Index );
336         maRoadmapItems.insert( maRoadmapItems.begin() + Index, xRoadmapItem);        //push_back( xRoadmapItem );
337 	    ContainerEvent aEvent = GetContainerEvent(Index, xRoadmapItem);
338 	    maContainerListeners.elementReplaced( aEvent );
339     }
340 
341 
getElementType()342 	Type SAL_CALL UnoControlRoadmapModel::getElementType() throw(RuntimeException)
343     {
344 	    Type aType = getCppuType( ( Reference< XPropertySet>* ) NULL );
345 	    return aType;
346     }
347 
348 
hasElements()349     sal_Bool SAL_CALL UnoControlRoadmapModel::hasElements() throw(RuntimeException)
350     {
351         return !maRoadmapItems.empty();
352     }
353 
354 
addContainerListener(const::com::sun::star::uno::Reference<::com::sun::star::container::XContainerListener> & xListener)355     void SAL_CALL UnoControlRoadmapModel::addContainerListener( const ::com::sun::star::uno::Reference< ::com::sun::star::container::XContainerListener >& xListener ) throw (::com::sun::star::uno::RuntimeException)
356     {
357 	    maContainerListeners.addInterface( xListener );
358     }
359 
removeContainerListener(const::com::sun::star::uno::Reference<::com::sun::star::container::XContainerListener> & xListener)360     void SAL_CALL UnoControlRoadmapModel::removeContainerListener( const ::com::sun::star::uno::Reference< ::com::sun::star::container::XContainerListener >& xListener ) throw (::com::sun::star::uno::RuntimeException)
361     {
362 	    maContainerListeners.removeInterface( xListener );
363     }
364 
365     // ===================================================================
366 	// = UnoRoadmapControl
367 	// ===================================================================
368 	// -------------------------------------------------------------------
UnoRoadmapControl(const Reference<XMultiServiceFactory> & i_factory)369     UnoRoadmapControl::UnoRoadmapControl( const Reference< XMultiServiceFactory >& i_factory )
370         :UnoControlRoadmap_Base( i_factory )
371         ,maItemListeners( *this )
372 	{
373 	}
374 
IMPLEMENT_FORWARD_XTYPEPROVIDER2(UnoRoadmapControl,UnoControlRoadmap_Base,UnoControlRoadmap_IBase)375 IMPLEMENT_FORWARD_XTYPEPROVIDER2( UnoRoadmapControl, UnoControlRoadmap_Base, UnoControlRoadmap_IBase )
376 IMPLEMENT_FORWARD_XINTERFACE2( UnoRoadmapControl, UnoControlRoadmap_Base, UnoControlRoadmap_IBase )
377 
378 
379 sal_Bool SAL_CALL UnoRoadmapControl::setModel(const Reference< XControlModel >& _rModel) throw ( RuntimeException )
380     {
381 
382 
383    	    Reference< XContainer > xC( getModel(), UNO_QUERY );
384 	    if ( xC.is() )
385 		    xC->removeContainerListener( this );
386 
387         sal_Bool bReturn = UnoControlBase::setModel( _rModel );
388 
389 	    xC = xC.query( getModel());
390 	    if ( xC.is() )
391 		    xC->addContainerListener( this );
392 
393         return bReturn;
394     }
395 
396 
397 	// -------------------------------------------------------------------
GetComponentServiceName()398 	::rtl::OUString UnoRoadmapControl::GetComponentServiceName()
399 	{
400 		return ::rtl::OUString::createFromAscii( "Roadmap" );
401 	}
402 
403 
404 
dispose()405     void UnoRoadmapControl::dispose() throw(RuntimeException)
406     {
407 	    EventObject aEvt;
408 	    aEvt.Source = (::cppu::OWeakObject*)this;
409 	    maItemListeners.disposeAndClear( aEvt );
410 	    UnoControl::dispose();
411     }
412 
413 
414 
elementInserted(const ContainerEvent & rEvent)415 void UnoRoadmapControl::elementInserted( const ContainerEvent& rEvent )throw(RuntimeException)
416 {
417     Reference< XInterface > xRoadmapItem;
418     rEvent.Element >>= xRoadmapItem;
419     Reference< XPropertySet > xRoadmapPropertySet( xRoadmapItem, UNO_QUERY );
420 	if ( xRoadmapPropertySet.is() )
421         xRoadmapPropertySet->addPropertyChangeListener( rtl::OUString(), this );
422 
423     Reference< XContainerListener >  xPeer(getPeer(), UNO_QUERY);
424     if ( xPeer.is() )
425     {
426         xPeer->elementInserted( rEvent );
427 		Reference < XPropertySet > xPropertySet( xPeer, UNO_QUERY );
428         if ( xPropertySet.is() )
429 		    xPropertySet->addPropertyChangeListener( rtl::OUString(), this );
430     }
431 }
432 
433 
elementRemoved(const ContainerEvent & rEvent)434 void UnoRoadmapControl::elementRemoved( const ContainerEvent& rEvent )throw(RuntimeException)
435 {
436     Reference< XContainerListener >  xPeer(getPeer(), UNO_QUERY);
437     if ( xPeer.is() )
438         xPeer->elementRemoved( rEvent );
439     Reference< XInterface > xRoadmapItem;
440     rEvent.Element >>= xRoadmapItem;
441     Reference< XPropertySet > xPropertySet( xRoadmapItem, UNO_QUERY );
442 	if ( xPropertySet.is() )
443         xPropertySet->removePropertyChangeListener( rtl::OUString(), this );
444 }
445 
446 
elementReplaced(const ContainerEvent & rEvent)447 void UnoRoadmapControl::elementReplaced( const ContainerEvent& rEvent )throw(RuntimeException)
448 {
449     Reference< XContainerListener >  xPeer(getPeer(), UNO_QUERY);
450     if ( xPeer.is() )
451         xPeer->elementReplaced( rEvent );
452 }
453 
454 
itemStateChanged(const ItemEvent & rEvent)455 void SAL_CALL UnoRoadmapControl::itemStateChanged( const ItemEvent& rEvent ) throw (RuntimeException)
456 {
457     sal_Int16 CurItemIndex = sal::static_int_cast< sal_Int16 >(rEvent.ItemId);
458     Any aAny;
459     aAny <<= CurItemIndex;
460     Reference< XControlModel > xModel( getModel( ), UNO_QUERY );
461     Reference< XPropertySet > xPropertySet( xModel, UNO_QUERY );
462     xPropertySet->setPropertyValue( GetPropertyName( BASEPROPERTY_CURRENTITEMID ), aAny );
463     if ( maItemListeners.getLength() )
464 		maItemListeners.itemStateChanged( rEvent );
465 }
466 
467 
addItemListener(const Reference<XItemListener> & l)468 void SAL_CALL UnoRoadmapControl::addItemListener( const Reference< XItemListener >& l ) throw (RuntimeException)
469 {
470     maItemListeners.addInterface( l );
471 	if( getPeer().is() && maItemListeners.getLength() == 1 )
472 	{
473 		Reference < XItemEventBroadcaster > xRoadmap( getPeer(), UNO_QUERY );
474 		xRoadmap->addItemListener( this );
475 	}
476 }
477 
478 
removeItemListener(const Reference<XItemListener> & l)479 void SAL_CALL UnoRoadmapControl::removeItemListener( const Reference< XItemListener >& l ) throw (RuntimeException)
480 {
481 	if( getPeer().is() && maItemListeners.getLength() == 1 )
482 	{
483 		Reference < XItemEventBroadcaster >  xRoadmap( getPeer(), UNO_QUERY );
484 		xRoadmap->removeItemListener( this );
485 	}
486 
487     maItemListeners.removeInterface( l );
488 }
489 
490 
propertyChange(const PropertyChangeEvent & evt)491 void SAL_CALL UnoRoadmapControl::propertyChange( const PropertyChangeEvent& evt ) throw (RuntimeException)
492 {
493     Reference< XPropertyChangeListener >  xPeer(getPeer(), UNO_QUERY);
494     if ( xPeer.is() )
495         xPeer->propertyChange( evt );
496 }
497 
498 }
499 
500