1# - try to find VRJuggler 3.0-related packages (main finder)
2#  VRJUGGLER30_LIBRARY_DIRS, library search paths
3#  VRJUGGLER30_INCLUDE_DIRS, include search paths
4#  VRJUGGLER30_LIBRARIES, the libraries to link against
5#  VRJUGGLER30_ENVIRONMENT
6#  VRJUGGLER30_RUNTIME_LIBRARY_DIRS
7#  VRJUGGLER30_CXX_FLAGS
8#  VRJUGGLER30_DEFINITIONS
9#  VRJUGGLER30_FOUND, If false, do not try to use VR Juggler 3.0.
10#
11# Components available to search for (uses "VRJOGL30" by default):
12#  VRJOGL30
13#  VRJ30
14#  Gadgeteer20
15#  JCCL14
16#  VPR22
17#  Sonix14
18#  Tweek14
19#
20# Additionally, a full setup requires these packages and their Find_.cmake scripts
21#  CPPDOM
22#  GMTL
23#
24# Optionally uses Flagpoll (and FindFlagpoll.cmake)
25#
26# Notes on components:
27#  - All components automatically include their dependencies.
28#  - You can search for the name above with or without the version suffix.
29#  - If you do not specify a component, VRJOGL30(the OpenGL view manager)
30#    will be used by default.
31#  - Capitalization of component names does not matter, but it's best to
32#    pretend it does and use the above capitalization.
33#  - Since this script calls find_package for your requested components and
34#    their dependencies, you can use any of the variables specified in those
35#    files in addition to the "summary" ones listed here, for more finely
36#    controlled building and linking.
37#
38# This CMake script requires all of the Find*.cmake scripts for the
39# components listed above, as it is only a "meta-script" designed to make
40# using those scripts more developer-friendly.
41#
42# Useful configuration variables you might want to add to your cache:
43#  (CAPS COMPONENT NAME)_ROOT_DIR - A directory prefix to search
44#                         (a path that contains include/ as a subdirectory)
45#
46# The VJ_BASE_DIR environment variable is also searched (preferentially)
47# when seeking any of the above components, as well as Flagpoll, CPPDOM,
48# and Boost (from within VPR22), so most sane build environments should
49# "just work."
50#
51# IMPORTANT: Note that you need to manually re-run CMake if you change
52# this environment variable, because it cannot auto-detect this change
53# and trigger an automatic re-run.
54#
55# Original Author:
56# 2009-2011 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
57# http://academic.cleardefinition.com
58# Iowa State University HCI Graduate Program/VRAC
59# Updated for VR Juggler 3.0 by:
60# Brandon Newendorp <brandon@newendorp.com> and Ryan Pavlik
61#
62# Copyright Iowa State University 2009-2011.
63# Distributed under the Boost Software License, Version 1.0.
64# (See accompanying file LICENSE_1_0.txt or copy at
65# http://www.boost.org/LICENSE_1_0.txt)
66
67include(CleanLibraryList)
68include(CleanDirectoryList)
69include(FindPackageMessage)
70
71set(VRJUGGLER30_ROOT_DIR
72	"${VRJUGGLER30_ROOT_DIR}"
73	CACHE
74	PATH
75	"Additional root directory to search for VR Juggler and its dependencies.")
76if(NOT VRJUGGLER30_ROOT_DIR)
77	file(TO_CMAKE_PATH "$ENV{VJ_BASE_DIR}" VRJUGGLER30_ROOT_DIR)
78endif()
79
80# Default required components
81if(NOT VRJuggler30_FIND_COMPONENTS)
82	set(VRJuggler30_FIND_COMPONENTS vrjogl30)
83endif()
84
85if(VRJuggler30_FIND_QUIETLY)
86	set(_FIND_FLAGS "QUIET")
87else()
88	set(_FIND_FLAGS "")
89endif()
90
91set(VRJUGGLER30_SUBMODULES
92	VRJ30
93	VRJOGL30
94	Gadgeteer20
95	JCCL14
96	VPR22
97	Sonix14
98	Tweek14)
99string(TOUPPER "${VRJUGGLER30_SUBMODULES}" VRJUGGLER30_SUBMODULES_UC)
100string(TOUPPER
101	"${VRJuggler30_FIND_COMPONENTS}"
102	VRJUGGLER30_FIND_COMPONENTS_UC)
103
104# Turn a potentially messy components list into a nice one with versions.
105set(VRJUGGLER30_REQUESTED_COMPONENTS)
106foreach(VRJUGGLER30_LONG_NAME ${VRJUGGLER30_SUBMODULES_UC})
107	# Look at requested components
108	foreach(VRJUGGLER30_REQUEST ${VRJUGGLER30_FIND_COMPONENTS_UC})
109		string(REGEX
110			MATCH
111			"${VRJUGGLER30_REQUEST}"
112			VRJUGGLER30_MATCHING
113			"${VRJUGGLER30_LONG_NAME}")
114		if(VRJUGGLER30_MATCHING)
115			list(APPEND
116				VRJUGGLER30_REQUESTED_COMPONENTS
117				${VRJUGGLER30_LONG_NAME})
118			list(APPEND
119				VRJUGGLER30_COMPONENTS_FOUND
120				${VRJUGGLER30_LONG_NAME}_FOUND)
121		endif()
122	endforeach()
123endforeach()
124
125if(VRJUGGLER30_REQUESTED_COMPONENTS)
126	list(REMOVE_DUPLICATES VRJUGGLER30_REQUESTED_COMPONENTS)
127endif()
128
129if(VRJUGGLER30_COMPONENTS_FOUND)
130	list(REMOVE_DUPLICATES VRJUGGLER30_COMPONENTS_FOUND)
131endif()
132
133if(CMAKE_SIZEOF_VOID_P MATCHES "8")
134	set(_VRJ_LIBSUFFIXES lib64 lib)
135	set(_VRJ_LIBDSUFFIXES
136		debug
137		lib64/x86_64/debug
138		lib64/debug
139		lib64
140		lib/x86_64/debug
141		lib/debug
142		lib)
143	set(_VRJ_LIBDSUFFIXES_ONLY
144		debug
145		lib64/x86_64/debug
146		lib64/debug
147		lib/x86_64/debug
148		lib/debug)
149else()
150	set(_VRJ_LIBSUFFIXES lib)
151	set(_VRJ_LIBDSUFFIXES debug lib/i686/debug lib/debug lib)
152	set(_VRJ_LIBDSUFFIXES_ONLY debug lib/i686/debug lib/debug)
153endif()
154
155if(NOT VRJUGGLER30_FIND_QUIETLY
156	AND NOT VRJUGGLER30_FOUND
157	AND NOT "${_VRJUGGLER30_SEARCH_COMPONENTS}"	STREQUAL "${VRJUGGLER30_REQUESTED_COMPONENTS}")
158	message(STATUS
159		"Searching for these requested VR Juggler 3.0 components and their dependencies: ${VRJUGGLER30_REQUESTED_COMPONENTS}")
160endif()
161
162# Find components
163if("${VRJUGGLER30_REQUESTED_COMPONENTS}" MATCHES "VRJOGL30" AND NOT VRJOGL30_FOUND)
164	find_package(VRJOGL30 ${_FIND_FLAGS})
165endif()
166
167if("${VRJUGGLER30_REQUESTED_COMPONENTS}" MATCHES "VRJ30" AND NOT VRJ30_FOUND)
168	find_package(VRJ30 ${_FIND_FLAGS})
169endif()
170
171if("${VRJUGGLER30_REQUESTED_COMPONENTS}" MATCHES "JCCL14" AND NOT JCCL14_FOUND)
172	find_package(JCCL14 ${_FIND_FLAGS})
173endif()
174
175if("${VRJUGGLER30_REQUESTED_COMPONENTS}" MATCHES "GADGETEER20" AND NOT GADGETEER20_FOUND)
176	find_package(Gadgeteer20 ${_FIND_FLAGS})
177endif()
178
179if("${VRJUGGLER30_REQUESTED_COMPONENTS}" MATCHES "SONIX14" AND NOT SONIX14_FOUND)
180	find_package(Sonix14 ${_FIND_FLAGS})
181endif()
182
183if("${VRJUGGLER30_REQUESTED_COMPONENTS}" MATCHES "TWEEK14" AND NOT TWEEK14_FOUND)
184	find_package(Tweek14 ${_FIND_FLAGS})
185endif()
186
187if("${VRJUGGLER30_REQUESTED_COMPONENTS}" MATCHES "VPR22" AND NOT VPR22_FOUND)
188	find_package(VPR22 ${_FIND_FLAGS})
189endif()
190
191# handle the QUIETLY and REQUIRED arguments and set xxx_FOUND to TRUE if
192# all listed variables are TRUE
193include(FindPackageHandleStandardArgs)
194find_package_handle_standard_args(VRJuggler30
195	DEFAULT_MSG
196	${VRJUGGLER30_COMPONENTS_FOUND})
197
198if(VRJUGGLER30_FOUND)
199	foreach(VRJUGGLER30_REQUEST ${VRJUGGLER30_REQUESTED_COMPONENTS})
200		list(APPEND VRJUGGLER30_LIBRARIES ${${VRJUGGLER30_REQUEST}_LIBRARIES})
201		list(APPEND
202			VRJUGGLER30_INCLUDE_DIRS
203			${${VRJUGGLER30_REQUEST}_INCLUDE_DIRS})
204	endforeach()
205
206	clean_library_list(VRJUGGLER30_LIBRARIES)
207
208	clean_directory_list(VRJUGGLER30_INCLUDE_DIRS)
209
210	set(_vjbase)
211	set(_vjbaseclean)
212	foreach(_component VPR22 VRJ30 VRJOGL30 JCCL14 GADGETEER20)
213
214		# Find the common parent directory of the include dir and the library dir
215		get_filename_component(_absincpath "${${_component}_INCLUDE_DIR}" PATH)
216		if(${_component}_INCLUDE_DIR)
217			get_filename_component(_curpath "${${_component}_LIBRARY_RELEASE}" PATH)
218			get_filename_component(_nextpath "${_curpath}/.." ABSOLUTE)
219			while(NOT _curpath STREQUAL _nextpath)
220				set(_curpath "${_nextpath}")
221				string(LENGTH "${_curpath}" _pathlen)
222				if("${_absincpath}" MATCHES "^${_curpath}.*")
223					list(APPEND _vjbase "${_curpath}")
224					break()
225				endif()
226				get_filename_component(_nextpath "${_curpath}/.." ABSOLUTE)
227			endwhile()
228		endif()
229	endforeach()
230
231	clean_directory_list(_vjbase)
232
233	set(_vrj30_have_base_dir NO)
234	list(LENGTH _vjbase _vjbaselen)
235	if("${_vjbaselen}" EQUAL 1 AND NOT VRJUGGLER30_VJ_BASE_DIR)
236		list(GET _vjbase 0 VRJUGGLER30_VJ_BASE_DIR)
237		mark_as_advanced(VRJUGGLER30_VJ_BASE_DIR)
238		if(NOT VRJUGGLER30_VJ_BASE_DIR STREQUAL _vrj30_base_dir)
239			unset(VRJUGGLER30_VJ_CFG_DIR)
240		endif()
241		set(_vrj30_have_base_dir YES)
242	else()
243		list(GET _vjbase 0 _calculated_base_dir)
244		if(NOT
245			"${_calculated_base_dir}"
246			STREQUAL
247			"${VRJUGGLER30_VJ_BASE_DIR}")
248			message("It looks like you might be mixing VR Juggler versions... ${_vjbaselen} ${_vjbase}")
249			message("If you are, fix your libraries then remove the VRJUGGLER30_VJ_BASE_DIR variable in CMake, then configure again")
250			message("If you aren't, set the VRJUGGLER30_VJ_BASE_DIR variable to the desired VJ_BASE_DIR to use when running")
251		else()
252			if(NOT VRJUGGLER30_VJ_BASE_DIR STREQUAL _vrj30_base_dir)
253				unset(VRJUGGLER30_VJ_CFG_DIR)
254			endif()
255			set(_vrj30_have_base_dir YES)
256		endif()
257	endif()
258
259	set(_vrj30_base_dir "${VRJUGGLER30_VJ_BASE_DIR}")
260	set(_vrj30_base_dir "${_vrj30_base_dir}" CACHE INTERNAL "" FORCE)
261
262	if(_vrj30_have_base_dir)
263		find_path(VRJUGGLER30_VJ_CFG_DIR
264			standalone.jconf
265			PATHS
266			${VRJUGGLER30_VJ_BASE_DIR}/share/vrjuggler-3.0/data/configFiles
267			${VRJUGGLER30_VJ_BASE_DIR}/share/vrjuggler/data/configFiles
268			NO_DEFAULT_PATH)
269		mark_as_advanced(VRJUGGLER30_VJ_CFG_DIR)
270	endif()
271
272	set(VRJUGGLER30_VJ_BASE_DIR
273		"${VRJUGGLER30_VJ_BASE_DIR}"
274		CACHE
275		PATH
276		"Base directory to use as VJ_BASE_DIR when running your app."
277		FORCE)
278	set(VRJUGGLER30_ENVIRONMENT
279		"VJ_BASE_DIR=${VRJUGGLER30_VJ_BASE_DIR}"
280		"JCCL_BASE_DIR=${VRJUGGLER30_VJ_BASE_DIR}"
281		"SONIX_BASE_DIR=${VRJUGGLER30_VJ_BASE_DIR}"
282		"TWEEK_BASE_DIR=${VRJUGGLER30_VJ_BASE_DIR}"
283		"VJ_CFG_DIR=${VRJUGGLER30_VJ_CFG_DIR}")
284
285	include(GetDirectoryList)
286
287	get_directory_list(VRJUGGLER30_RUNTIME_LIBRARY_DIRS
288		${VRJUGGLER30_LIBRARIES})
289	if(WIN32)
290		foreach(dir ${VRJUGGLER30_RUNTIME_LIBRARY_DIRS})
291			list(APPEND VRJUGGLER30_RUNTIME_LIBRARY_DIRS "${dir}/../bin")
292		endforeach()
293	endif()
294
295	if(MSVC)
296		# BOOST_ALL_DYN_LINK
297		set(VRJUGGLER30_DEFINITIONS
298			"-DBOOST_ALL_DYN_LINK"
299			"-DCPPDOM_DYN_LINK"
300			"-DCPPDOM_AUTO_LINK")
301
302		# Disable these annoying warnings
303		# 4275: non dll-interface class used as base for dll-interface class
304		# 4251: needs to have dll-interface to be used by clients of class
305		# 4100: unused parameter
306		# 4512: assignment operator could not be generated
307		# 4127: (Not currently disabled) conditional expression in loop evaluates to constant
308
309		set(VRJUGGLER30_CXX_FLAGS "/wd4275 /wd4251 /wd4100 /wd4512")
310	elseif(CMAKE_COMPILER_IS_GNUCXX)
311		# Silence annoying warnings about deprecated hash_map.
312		set(VRJUGGLER30_CXX_FLAGS "-Wno-deprecated")
313
314		set(VRJUGGLER30_DEFINITIONS "")
315	endif()
316	set(VRJUGGLER30_CXX_FLAGS
317		"${VRJUGGLER30_CXX_FLAGS} ${CPPDOM_CXX_FLAGS}")
318
319	set(_VRJUGGLER30_SEARCH_COMPONENTS
320		"${VRJUGGLER30_REQUESTED_COMPONENTS}"
321		CACHE
322		INTERNAL
323		"Requested components, used as a flag.")
324
325
326
327	set(_plugin_dirs)
328	foreach(_libdir ${VRJUGGLER30_RUNTIME_LIBRARY_DIRS})
329		# Find directories of Gadgeteer plugins and drivers
330		if(EXISTS "${_libdir}/gadgeteer")
331			list(APPEND
332				_plugin_dirs
333				"${_libdir}/gadgeteer/drivers"
334				"${_libdir}/gadgeteer/plugins")
335		elseif(EXISTS "${_libdir}/gadgeteer-1.4")
336			list(APPEND
337				_plugin_dirs
338				"${_libdir}/gadgeteer-1.4/drivers"
339				"${_libdir}/gadgeteer-1.4/plugins")
340		endif()
341
342		# Find directories of Sonix plugins
343		if(EXISTS "${_libdir}/sonix")
344			list(APPEND _plugin_dirs "${_libdir}/sonix/plugins/dbg")
345			list(APPEND _plugin_dirs "${_libdir}/sonix/plugins/opt")
346		elseif(EXISTS "${_libdir}/sonix-1.4")
347			list(APPEND _plugin_dirs "${_libdir}/sonix-1.4/plugins/dbg")
348			list(APPEND _plugin_dirs "${_libdir}/sonix-1.4/plugins/opt")
349		endif()
350
351		# Find directories of JCCL plugins
352		if(EXISTS "${_libdir}/jccl/plugins")
353			list(APPEND _plugin_dirs "${_libdir}/jccl/plugins")
354		elseif(EXISTS "${_libdir}/jccl-1.4/plugins")
355			list(APPEND _plugin_dirs "${_libdir}/jccl-1.4/plugins")
356		endif()
357
358		# Find directories of VR Juggler plugins
359		if(EXISTS "${_libdir}/vrjuggler/plugins")
360			list(APPEND _plugin_dirs "${_libdir}/vrjuggler/plugins")
361		elseif(EXISTS "${_libdir}/vrjuggler-3.0/plugins")
362			list(APPEND _plugin_dirs "${_libdir}/vrjuggler-3.0/plugins")
363		endif()
364	endforeach()
365
366	# Grab the actual plugins
367	foreach(_libdir ${_plugin_dirs})
368		if(EXISTS "${_libdir}")
369			list(APPEND VRJUGGLER30_RUNTIME_LIBRARY_DIRS "${_libdir}")
370			file(GLOB _plugins "${_libdir}/*${CMAKE_SHARED_LIBRARY_SUFFIX}")
371			foreach(_plugin ${_plugins})
372				if("${_plugin}" MATCHES "_d${CMAKE_SHARED_LIBRARY_SUFFIX}")
373					list(APPEND VRJUGGLER30_BUNDLE_PLUGINS_DEBUG ${_plugin})
374				else()
375					list(APPEND VRJUGGLER30_BUNDLE_PLUGINS ${_plugin})
376				endif()
377			endforeach()
378		endif()
379	endforeach()
380
381	mark_as_advanced(VRJUGGLER30_ROOT_DIR)
382endif()
383
384mark_as_advanced(VRJUGGLER30_DEFINITIONS)
385
386function(install_vrjuggler30_data_files prefix)
387	set(base "${VRJUGGLER30_VJ_CFG_DIR}/..")
388	get_filename_component(base "${base}" ABSOLUTE)
389	file(RELATIVE_PATH reldest "${VRJUGGLER30_VJ_BASE_DIR}" "${base}")
390	if(prefix STREQUAL "" OR prefix STREQUAL "." OR prefix STREQUAL "./")
391		set(DEST "${reldest}")
392	else()
393		set(DEST "${prefix}/${reldest}")
394	endif()
395
396	# configFiles *.jconf
397	file(GLOB
398		_vj_config_files
399		"${base}/configFiles/*.jconf")
400	install(FILES ${_vj_config_files} DESTINATION "${DEST}/configFiles/")
401
402	# definitions *.jdef
403	file(GLOB
404		_vj_defs_files
405		"${base}/definitions/*.jdef")
406	install(FILES ${_vj_defs_files} DESTINATION "${DEST}/definitions/")
407
408	# models *.flt
409	file(GLOB
410		_vj_model_files
411		"${base}/models/*.flt")
412	install(FILES ${_vj_model_files} DESTINATION "${DEST}/models/")
413
414	# sounds *.wav
415	file(GLOB
416		_vj_sound_files
417		"${base}/sounds/*.wav")
418	install(FILES ${_vj_sound_files} DESTINATION "${DEST}/sounds/")
419endfunction()
420
421macro(_vrjuggler30_plugin_install _VAR)
422	foreach(plugin ${${_VAR}})
423		get_filename_component(full "${plugin}" ABSOLUTE)
424		file(RELATIVE_PATH relloc "${VRJUGGLER30_VJ_BASE_DIR}" "${full}")
425		set(filedest "${DEST}/${relloc}")
426		get_filename_component(path "${filedest}" PATH)
427		list(APPEND out "${filedest}")
428		install(FILES "${full}" DESTINATION "${path}" ${ARGN})
429	endforeach()
430endmacro()
431
432function(install_vrjuggler30_plugins prefix varForFilenames)
433	set(DEST "${prefix}")
434
435	set(out)
436	_vrjuggler30_plugin_install(VRJUGGLER30_BUNDLE_PLUGINS)
437	_vrjuggler30_plugin_install(VRJUGGLER30_BUNDLE_PLUGINS_DEBUG CONFIGURATIONS DEBUG)
438	set(${varForFilenames} ${out} PARENT_SCOPE)
439
440endfunction()
441
442function(get_vrjuggler_bundle_sources _target_sources)
443	if(APPLE)
444		set(_bundledir "${VRJUGGLER30_VJ_CFG_DIR}/../bundle")
445		get_filename_component(_bundledir "${_bundledir}" ABSOLUTE)
446
447		set(_vj_base_dir .)
448		set(_vj_data_dir ${vj_base_dir}/share/vrjuggler-3.0)
449
450		# Append Mac-specific sources to source list
451		set(_vj_bundle_src
452			${_bundledir}/vrjuggler.icns
453			${_bundledir}/vrjuggler.plist
454			${_bundledir}/en.lproj/MainMenu.nib/classes.nib
455			${_bundledir}/MainMenu.nib/info.nib
456			${_bundledir}/MainMenu.nib/keyedobjects.nib)
457
458		message(STATUS "vjbundlesrc: ${_vj_bundle_src}")
459		set(${_target_sources}
460			${${_target_sources}}
461			${_vj_bundle_src}
462			PARENT_SCOPE)
463
464		# Set destination of nib files
465		set_source_files_properties(${_bundledir}/MainMenu.nib/classes.nib
466			${_bundledir}/MainMenu.nib/info.nib
467			${_bundledir}/MainMenu.nib/keyedobjects.nib
468			PROPERTIES
469			MACOSX_PACKAGE_LOCATION
470			Resources/en.lproj/MainMenu.nib/)
471
472		# Set destination of Resources
473		set_source_files_properties(${_bundledir}/vrjuggler.icns
474			${_bundledir}/vrjuggler.plist
475			PROPERTIES
476			MACOSX_PACKAGE_LOCATION
477			Resources/)
478	endif()
479endfunction()
480
481get_filename_component(_vrjuggler30moddir
482	${CMAKE_CURRENT_LIST_FILE}
483	PATH)
484function(fixup_vrjuggler_app_bundle
485	_target
486	_targetInstallDest
487	_extralibs
488	_libdirs)
489
490	if(NOT VRJUGGLER30_FOUND)
491		return()
492	endif()
493
494
495	set(PACKAGE_DIR ${_vrjuggler30moddir}/package)
496	set(MACOSX_PACKAGE_DIR ${PACKAGE_DIR}/macosx)
497
498	set(TARGET_LOCATION
499		"${_targetInstallDest}/${_target}${CMAKE_EXECUTABLE_SUFFIX}")
500	if(APPLE)
501		set(TARGET_LOCATION "${TARGET_LOCATION}.app")
502	endif()
503
504	set_target_properties(${_target}
505		PROPERTIES
506		MACOSX_BUNDLE_INFO_PLIST
507		${MACOSX_PACKAGE_DIR}/VRJuggler30BundleInfo.plist.in
508		MACOSX_BUNDLE_ICON_FILE
509		vrjuggler.icns
510		MACOSX_BUNDLE_INFO_STRING
511		"${PROJECT_NAME} (VR Juggler Application) version ${CPACK_PACKAGE_VERSION}, created by ${CPACK_PACKAGE_VENDOR}"
512		MACOSX_BUNDLE_GUI_IDENTIFIER
513		org.vrjuggler.${PROJECT_NAME}
514		MACOSX_BUNDLE_SHORT_VERSION_STRING
515		${CPACK_PACKAGE_VERSION}
516		MACOSX_BUNDLE_BUNDLE_VERSION
517		${CPACK_PACKAGE_VERSION})
518
519	if(WIN32)
520		list(APPEND _libdirs "${VRJUGGLER30_VJ_BASE_DIR}/bin")
521	endif()
522
523	set(BUNDLE_LIBS ${_extralibs})
524	set(BUNDLE_LIB_DIRS "${VRJUGGLER30_VJ_BASE_DIR}" ${_libdirs})
525
526	configure_file(${PACKAGE_DIR}/fixupbundle.cmake.in
527		${CMAKE_CURRENT_BINARY_DIR}/${_target}-fixupbundle-juggler.cmake
528		@ONLY)
529	install(SCRIPT
530		"${CMAKE_CURRENT_BINARY_DIR}/${_target}-fixupbundle-juggler.cmake")
531endfunction()
532