View Javadoc
1   /*
2    * Copyright (c) 2002-2023, City of Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.plugins.document.web.spaces;
35  
36  import fr.paris.lutece.plugins.document.business.Document;
37  import fr.paris.lutece.plugins.document.business.DocumentFilter;
38  import fr.paris.lutece.plugins.document.business.DocumentHome;
39  import fr.paris.lutece.plugins.document.business.DocumentTypeHome;
40  import fr.paris.lutece.plugins.document.business.spaces.DocumentSpace;
41  import fr.paris.lutece.plugins.document.business.spaces.DocumentSpaceHome;
42  import fr.paris.lutece.plugins.document.service.spaces.DocumentSpacesService;
43  import fr.paris.lutece.plugins.document.service.spaces.SpaceRemovalListenerService;
44  import fr.paris.lutece.plugins.document.service.spaces.SpaceResourceIdService;
45  import fr.paris.lutece.plugins.document.utils.IntegerUtils;
46  import fr.paris.lutece.plugins.document.web.DocumentJspBean;
47  import fr.paris.lutece.portal.business.user.AdminUser;
48  import fr.paris.lutece.portal.service.message.AdminMessage;
49  import fr.paris.lutece.portal.service.message.AdminMessageService;
50  import fr.paris.lutece.portal.service.rbac.RBACService;
51  import fr.paris.lutece.portal.service.template.AppTemplateService;
52  import fr.paris.lutece.portal.service.workgroup.AdminWorkgroupService;
53  import fr.paris.lutece.portal.web.admin.PluginAdminPageJspBean;
54  import fr.paris.lutece.portal.web.constants.Messages;
55  import fr.paris.lutece.util.ReferenceList;
56  import fr.paris.lutece.util.html.HtmlTemplate;
57  import fr.paris.lutece.util.url.UrlItem;
58  
59  import org.apache.commons.lang3.StringUtils;
60  
61  import java.util.ArrayList;
62  import java.util.Collection;
63  import java.util.HashMap;
64  import java.util.Locale;
65  import java.util.Map;
66  
67  import javax.servlet.http.HttpServletRequest;
68  
69  
70  /**
71   * JSP Bean for spaces management
72   */
73  public class DocumentSpaceJspBean extends PluginAdminPageJspBean
74  {
75      public static final String RIGHT_DOCUMENT_SPACE_MANAGEMENT = "DOCUMENT_MANAGEMENT";
76  
77      /**
78       * Generated serial version UID
79       */
80      private static final long serialVersionUID = 7800908795009344020L;
81      private static final String TEMPLATE_CREATE_SPACE = "/admin/plugins/document/spaces/create_space.html";
82      private static final String TEMPLATE_MODIFY_SPACE = "/admin/plugins/document/spaces/modify_space.html";
83      private static final String TEMPLATE_MOVE_SPACE = "/admin/plugins/document/spaces/move_space.html";
84      private static final String JSP_MANAGE_DOCUMENT = "ManageDocuments.jsp";
85      private static final String JSP_DELETE_SPACE = "DoDeleteSpace.jsp";
86      private static final String PATH_JSP = "jsp/admin/plugins/document/";
87      private static final String PARAMETER_SPACE_ID = "id_space";
88      private static final String PARAMETER_PARENT_SPACE_ID = "id_parent_space";
89      private static final String PARAMETER_NAME = "name";
90      private static final String PARAMETER_DESCRIPTION = "description";
91      private static final String PARAMETER_VIEW_TYPE = "view_type";
92      private static final String PARAMETER_ICON = "icon";
93      private static final String PARAMETER_DOCUMENT_TYPE = "document_type";
94      private static final String PARAMETER_ALLOW_CREATION = "allow_creation";
95      private static final String PARAMETER_WORKGROUP_KEY = "workgroup_key";
96      private static final String MARK_SPACE = "space";
97      private static final String MARK_PARENT_SPACE = "parent_space";
98      private static final String MARK_VIEW_TYPE = "view_type";
99      private static final String MARK_VIEW_TYPES_LIST = "view_types_list";
100     private static final String MARK_ICONS_LIST = "icons_list";
101     private static final String MARK_DOCUMENT_TYPES_LIST = "document_types_list";
102     private static final String MARK_SPACES_BROWSER = "spaces_browser";
103     private static final String MARK_USER_WORKGROUP_LIST = "user_workgroup_list";
104     private static final String MARK_WORKGROUP_SELECTED = "selected_workgroup";
105     private static final String MARK_SUBMIT_BUTTON_DISABLED = "submit_button_disabled";
106     private static final String MESSAGE_CANNOT_DELETE_HAS_CHILDS = "document.spaces.message.cannotDeleteHasChilds";
107     private static final String MESSAGE_CANNOT_DELETE_HAS_DOCS = "document.spaces.message.cannotDeleteHasDocs";
108     private static final String MESSAGE_CANNOT_DELETE = "document.spaces.message.cannotDelete";
109     private static final String MESSAGE_CONFIRM_DELETE = "document.spaces.message.confirmDeleteSpace";
110     private static final String DEFAULT_VIEW_TYPE = "1";
111     private static final String PROPERTY_CREATE_SPACE_PAGE_TITLE = "document.create_space.pageTitle";
112     private static final String PROPERTY_MODIFY_SPACE_PAGE_TITLE = "document.modify_space.pageTitle";
113     private static final String PROPERTY_MOVE_SPACE_PAGE_TITLE = "document.move_space.pageTitle";
114     private static final String MESSAGE_MOVING_SPACE_NOT_AUTHORIZED = "document.message.movingSpaceNotAuthorized";
115 
116     /**
117      * Gets the create space page
118      * @param request The HTTP request
119      * @return The create space page
120      */
121     public String getCreateSpace( HttpServletRequest request )
122     {
123         setPageTitleProperty( PROPERTY_CREATE_SPACE_PAGE_TITLE );
124 
125         String strParentId = request.getParameter( PARAMETER_SPACE_ID );
126         int nParentId = IntegerUtils.convert( strParentId );
127         AdminUser user = getUser(  );
128         ReferenceList refListWorkGroups = AdminWorkgroupService.getUserWorkgroups( user, getLocale(  ) );
129         DocumentSpace spaceParent = DocumentSpaceHome.findByPrimaryKey( nParentId );
130         Map<String, Object> model = new HashMap<String, Object>(  );
131 
132         if ( RBACService.isAuthorized( DocumentSpace.RESOURCE_TYPE, strParentId,
133                     SpaceResourceIdService.PERMISSION_CREATE, getUser(  ) ) &&
134                 DocumentSpacesService.getInstance(  ).isAuthorizedViewByWorkgroup( nParentId, getUser(  ) ) )
135         {
136             model.put( MARK_VIEW_TYPE, DEFAULT_VIEW_TYPE );
137             model.put( MARK_VIEW_TYPES_LIST, DocumentSpaceHome.getViewTypeList( getLocale(  ) ) );
138             model.put( MARK_ICONS_LIST, DocumentSpaceHome.getIconsList(  ) );
139             model.put( MARK_DOCUMENT_TYPES_LIST, DocumentTypeHome.getDocumentTypesList(  ) );
140             model.put( MARK_PARENT_SPACE, spaceParent );
141             model.put( MARK_USER_WORKGROUP_LIST, refListWorkGroups );
142 
143             //LUTECE-890 : the first workgroup will be selected by default
144             if ( !refListWorkGroups.isEmpty(  ) )
145             {
146                 model.put( MARK_WORKGROUP_SELECTED, refListWorkGroups.get( 0 ).getCode(  ) );
147             }
148         }
149 
150         HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_CREATE_SPACE, getLocale(  ), model );
151 
152         return getAdminPage( template.getHtml(  ) );
153     }
154 
155     /**
156      * Perform the space creation
157      * @param request The HTTP request
158      * @return The Feature Home Page
159      */
160     public String doCreateSpace( HttpServletRequest request )
161     {
162         DocumentSpaceocument/business/spaces/DocumentSpace.html#DocumentSpace">DocumentSpace space = new DocumentSpace(  );
163         String strParentId = request.getParameter( PARAMETER_PARENT_SPACE_ID );
164 
165         if ( !RBACService.isAuthorized( DocumentSpace.RESOURCE_TYPE, strParentId,
166                     SpaceResourceIdService.PERMISSION_CREATE, getUser(  ) ) ||
167                 !DocumentSpacesService.getInstance(  )
168                                           .isAuthorizedViewByWorkgroup( IntegerUtils.convert( strParentId ), getUser(  ) ) )
169         {
170             return AdminMessageService.getMessageUrl( request, Messages.USER_ACCESS_DENIED, AdminMessage.TYPE_STOP );
171         }
172 
173         String strErrorUrl = getRequestData( request, space );
174 
175         if ( strErrorUrl != null )
176         {
177             return strErrorUrl;
178         }
179 
180         DocumentSpaceHome.create( space );
181 
182         return JSP_MANAGE_DOCUMENT;
183     }
184 
185     /**
186      * Gets the modify space page
187      * @param request The HTTP request
188      * @return the modify space page
189      */
190     public String getModifySpace( HttpServletRequest request )
191     {
192         setPageTitleProperty( PROPERTY_MODIFY_SPACE_PAGE_TITLE );
193 
194         String strIdSpace = request.getParameter( PARAMETER_SPACE_ID );
195         int nIdSpace = IntegerUtils.convert( strIdSpace );
196         AdminUser user = getUser(  );
197         Map<String, Object> model = new HashMap<String, Object>(  );
198 
199         if ( RBACService.isAuthorized( DocumentSpace.RESOURCE_TYPE, strIdSpace,
200                     SpaceResourceIdService.PERMISSION_MODIFY, getUser(  ) ) &&
201                 DocumentSpacesService.getInstance(  ).isAuthorizedViewByWorkgroup( nIdSpace, getUser(  ) ) )
202         {
203             ReferenceList refListWorkGroups = AdminWorkgroupService.getUserWorkgroups( user, getLocale(  ) );
204             DocumentSpace space = DocumentSpaceHome.findByPrimaryKey( nIdSpace );
205             ReferenceList listDocumentTypes = DocumentTypeHome.getDocumentTypesList(  );
206             listDocumentTypes.checkItems( space.getAllowedDocumentTypes(  ) );
207 
208             model.put( MARK_SPACE, space );
209             model.put( MARK_VIEW_TYPE, DEFAULT_VIEW_TYPE );
210             model.put( MARK_VIEW_TYPES_LIST, DocumentSpaceHome.getViewTypeList( getLocale(  ) ) );
211             model.put( MARK_ICONS_LIST, DocumentSpaceHome.getIconsList(  ) );
212             model.put( MARK_DOCUMENT_TYPES_LIST, listDocumentTypes );
213             model.put( MARK_USER_WORKGROUP_LIST, refListWorkGroups );
214         }
215 
216         HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_MODIFY_SPACE, getLocale(  ), model );
217 
218         return getAdminPage( template.getHtml(  ) );
219     }
220 
221     /**
222      * Perform the space modification
223      * @param request The HTTP request
224      * @return The Feature Home Page
225      */
226     public String doModifySpace( HttpServletRequest request )
227     {
228         String strIdSpace = request.getParameter( PARAMETER_SPACE_ID );
229         int nIdSpace = IntegerUtils.convert( strIdSpace );
230 
231         // Check for user's rights
232         if ( !RBACService.isAuthorized( DocumentSpace.RESOURCE_TYPE, strIdSpace,
233                     SpaceResourceIdService.PERMISSION_MODIFY, getUser(  ) ) ||
234                 !DocumentSpacesService.getInstance(  ).isAuthorizedViewByWorkgroup( nIdSpace, getUser(  ) ) )
235         {
236             return AdminMessageService.getMessageUrl( request, Messages.USER_ACCESS_DENIED, AdminMessage.TYPE_STOP );
237         }
238 
239         DocumentSpace space = DocumentSpaceHome.findByPrimaryKey( nIdSpace );
240         String strErrorUrl = getRequestData( request, space );
241 
242         if ( strErrorUrl != null )
243         {
244             return strErrorUrl;
245         }
246 
247         DocumentSpaceHome.update( space );
248 
249         return JSP_MANAGE_DOCUMENT;
250     }
251 
252     private String getRequestData( HttpServletRequest request, DocumentSpace space )
253     {
254         String strErrorUrl = null;
255         String strParentId = request.getParameter( PARAMETER_PARENT_SPACE_ID );
256         String strName = request.getParameter( PARAMETER_NAME );
257         String strDescription = request.getParameter( PARAMETER_DESCRIPTION );
258         String strViewType = request.getParameter( PARAMETER_VIEW_TYPE );
259         String strIcon = request.getParameter( PARAMETER_ICON );
260         String[] strDocumentType = request.getParameterValues( PARAMETER_DOCUMENT_TYPE );
261         String strAllowCreation = request.getParameter( PARAMETER_ALLOW_CREATION );
262         String strWorkgroup = request.getParameter( PARAMETER_WORKGROUP_KEY );
263         boolean bAllowCreation = ( ( strAllowCreation != null ) && ( strAllowCreation.equals( "on" ) ) ) ? true : false;
264 
265         // Mandatory fields
266         if ( StringUtils.isBlank( strName ) || StringUtils.isBlank( strDescription ) )
267         {
268             return AdminMessageService.getMessageUrl( request, Messages.MANDATORY_FIELDS, AdminMessage.TYPE_STOP );
269         }
270 
271         space.setIdParent( IntegerUtils.convert( strParentId ) );
272         space.setName( strName );
273         space.setDescription( strDescription );
274         space.setViewType( strViewType );
275         space.setIdIcon( IntegerUtils.convert( strIcon ) );
276         space.resetAllowedDocumentTypesList(  );
277         space.setDocumentCreationAllowed( bAllowCreation );
278         space.setWorkgroup( strWorkgroup );
279 
280         if ( strDocumentType != null )
281         {
282             for ( int i = 0; i < strDocumentType.length; i++ )
283             {
284                 space.addAllowedDocumentType( strDocumentType[i] );
285             }
286         }
287 
288         return strErrorUrl;
289     }
290 
291     /**
292      * Confirm the deletion
293      * @param request The HTTP request
294      * @return The Url to go
295      */
296     public String deleteSpace( HttpServletRequest request )
297     {
298         String strSpaceId = request.getParameter( PARAMETER_SPACE_ID );
299         int nSpaceId = IntegerUtils.convert( strSpaceId );
300 
301         // Check if there is child spaces
302         Collection<DocumentSpace> childs = DocumentSpaceHome.findChilds( nSpaceId );
303 
304         if ( childs.size(  ) > 0 )
305         {
306             return AdminMessageService.getMessageUrl( request, MESSAGE_CANNOT_DELETE_HAS_CHILDS, AdminMessage.TYPE_STOP );
307         }
308 
309         // Check if documents are stored in this space
310         DocumentFilterument/business/DocumentFilter.html#DocumentFilter">DocumentFilter filter = new DocumentFilter(  );
311         filter.setIdSpace( nSpaceId );
312 
313         Collection<Document> docs = DocumentHome.findByFilter( filter, Locale.getDefault(  ) );
314 
315         if ( docs.size(  ) > 0 )
316         {
317             return AdminMessageService.getMessageUrl( request, MESSAGE_CANNOT_DELETE_HAS_DOCS, AdminMessage.TYPE_STOP );
318         }
319 
320         // Check for user's rights
321         if ( !RBACService.isAuthorized( DocumentSpace.RESOURCE_TYPE, strSpaceId,
322                     SpaceResourceIdService.PERMISSION_DELETE, getUser(  ) ) ||
323                 !DocumentSpacesService.getInstance(  ).isAuthorizedViewByWorkgroup( nSpaceId, getUser(  ) ) )
324         {
325             return AdminMessageService.getMessageUrl( request, Messages.USER_ACCESS_DENIED, AdminMessage.TYPE_STOP );
326         }
327 
328         ArrayList<String> listErrors = new ArrayList<String>(  );
329 
330         if ( !SpaceRemovalListenerService.getService(  )
331                                              .checkForRemoval( Integer.toString( nSpaceId ), listErrors, getLocale(  ) ) )
332         {
333             String strCause = AdminMessageService.getFormattedList( listErrors, getLocale(  ) );
334             Object[] args = { strCause };
335 
336             return AdminMessageService.getMessageUrl( request, MESSAGE_CANNOT_DELETE, args, AdminMessage.TYPE_STOP );
337         }
338 
339         DocumentSpace space = DocumentSpaceHome.findByPrimaryKey( nSpaceId );
340 
341         Object[] messageArgs = { space.getName(  ) };
342         UrlItem url = new UrlItem( PATH_JSP + JSP_DELETE_SPACE );
343         url.addParameter( PARAMETER_SPACE_ID, nSpaceId );
344 
345         return AdminMessageService.getMessageUrl( request, MESSAGE_CONFIRM_DELETE, messageArgs, url.getUrl(  ),
346             AdminMessage.TYPE_CONFIRMATION );
347     }
348 
349     /**
350      * Perform the deletion
351      * @param request The HTTP request
352      * @return The Feature Home Page
353      */
354     public String doDeleteSpace( HttpServletRequest request )
355     {
356         String strSpaceId = request.getParameter( PARAMETER_SPACE_ID );
357 
358         int nSpaceId = IntegerUtils.convert( strSpaceId );
359         DocumentSpace documentSpace = DocumentSpaceHome.findByPrimaryKey( nSpaceId );
360         int nParentSpaceId = documentSpace.getIdParent(  );
361         UrlItem url = new UrlItem( JSP_MANAGE_DOCUMENT );
362 
363         if ( ( nSpaceId != 0 ) &&
364                 RBACService.isAuthorized( DocumentSpace.RESOURCE_TYPE, strSpaceId,
365                     SpaceResourceIdService.PERMISSION_DELETE, getUser(  ) ) &&
366                 DocumentSpacesService.getInstance(  ).isAuthorizedViewByWorkgroup( nSpaceId, getUser(  ) ) ) //if space is not root space
367         {
368             DocumentSpaceHome.remove( nSpaceId );
369             url.addParameter( DocumentJspBean.PARAMETER_SPACE_ID_FILTER, nParentSpaceId );
370         }
371 
372         return url.getUrlWithEntity(  );
373     }
374 
375     /**
376      * Get the move space screen
377      * @param request The request
378      * @return The HTML content to display
379      */
380     public String getMoveSpace( HttpServletRequest request )
381     {
382         setPageTitleProperty( PROPERTY_MOVE_SPACE_PAGE_TITLE );
383 
384         String strSpaceToMoveId = request.getParameter( PARAMETER_SPACE_ID );
385         String strSpaceId = request.getParameter( DocumentSpacesService.PARAMETER_BROWSER_SELECTED_SPACE_ID );
386         boolean bSubmitButtonDisabled = Boolean.TRUE;
387         DocumentSpace spaceToMove = null;
388 
389         if ( strSpaceToMoveId != null )
390         {
391             spaceToMove = DocumentSpaceHome.findByPrimaryKey( IntegerUtils.convert( strSpaceToMoveId ) );
392         }
393         else
394         {
395             return AdminMessageService.getMessageUrl( request, Messages.MANDATORY_FIELDS, AdminMessage.TYPE_ERROR );
396         }
397 
398         if ( StringUtils.isNotBlank( strSpaceId ) )
399         {
400             bSubmitButtonDisabled = Boolean.FALSE;
401         }
402 
403         Map<String, Object> model = new HashMap<String, Object>(  );
404 
405         // Spaces browser
406         model.put( MARK_SPACE, spaceToMove );
407         model.put( MARK_SUBMIT_BUTTON_DISABLED, bSubmitButtonDisabled );
408         model.put( MARK_SPACES_BROWSER,
409             DocumentSpacesService.getInstance(  ).getSpacesBrowser( request, getUser(  ), getLocale(  ), true, true ) );
410 
411         HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_MOVE_SPACE, getLocale(  ), model );
412 
413         return getAdminPage( template.getHtml(  ) );
414     }
415 
416     /**
417      * Do move a space
418      * @param request The request
419      * @return The next URL to redirect to
420      */
421     public String doMoveSpace( HttpServletRequest request )
422     {
423         String strSpaceId = request.getParameter( DocumentSpacesService.PARAMETER_BROWSER_SELECTED_SPACE_ID );
424 
425         if ( strSpaceId == null )
426         {
427             return AdminMessageService.getMessageUrl( request, Messages.MANDATORY_FIELDS, AdminMessage.TYPE_STOP );
428         }
429 
430         int nSpaceId = IntegerUtils.convert( strSpaceId );
431         DocumentSpace space = DocumentSpaceHome.findByPrimaryKey( nSpaceId );
432         String strSpaceToMoveId = request.getParameter( PARAMETER_SPACE_ID );
433         DocumentSpace spaceToMove = DocumentSpaceHome.findByPrimaryKey( IntegerUtils.convert( strSpaceToMoveId ) );
434 
435         // Check if selected space isn't the space to move
436         if ( ( space == null ) || ( spaceToMove == null ) || ( space.getId(  ) == spaceToMove.getId(  ) ) )
437         {
438             return AdminMessageService.getMessageUrl( request, MESSAGE_MOVING_SPACE_NOT_AUTHORIZED,
439                 AdminMessage.TYPE_STOP );
440         }
441 
442         // Check if selected space isn't child from space to move
443         DocumentSpace tmpSpace = DocumentSpaceHome.findByPrimaryKey( space.getId(  ) );
444 
445         while ( tmpSpace != null )
446         {
447             if ( tmpSpace.getIdParent(  ) == spaceToMove.getId(  ) )
448             {
449                 return AdminMessageService.getMessageUrl( request, MESSAGE_MOVING_SPACE_NOT_AUTHORIZED,
450                     AdminMessage.TYPE_STOP );
451             }
452 
453             tmpSpace = DocumentSpaceHome.findByPrimaryKey( tmpSpace.getIdParent(  ) );
454         }
455 
456         // Check if user have rights to create a space into this space
457         if ( RBACService.isAuthorized( space, SpaceResourceIdService.PERMISSION_CREATE, getUser(  ) ) &&
458                 DocumentSpacesService.getInstance(  ).isAuthorizedViewByWorkgroup( spaceToMove.getId(  ), getUser(  ) ) &&
459                 DocumentSpacesService.getInstance(  ).isAuthorizedViewByWorkgroup( space.getId(  ), getUser(  ) ) )
460         {
461             spaceToMove.setIdParent( nSpaceId );
462             DocumentSpaceHome.update( spaceToMove );
463 
464             return getHomeUrl( request );
465         }
466         else
467         {
468             return AdminMessageService.getMessageUrl( request, MESSAGE_MOVING_SPACE_NOT_AUTHORIZED,
469                 AdminMessage.TYPE_STOP );
470         }
471     }
472 }