1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  package org.kuali.common.util.spring;
17  
18  import java.io.File;
19  import java.util.ArrayList;
20  import java.util.Arrays;
21  import java.util.Collections;
22  import java.util.Comparator;
23  import java.util.Iterator;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Properties;
27  
28  import org.codehaus.plexus.util.StringUtils;
29  import org.kuali.common.util.Assert;
30  import org.kuali.common.util.CollectionUtils;
31  import org.kuali.common.util.FormatUtils;
32  import org.kuali.common.util.LocationUtils;
33  import org.kuali.common.util.LoggerLevel;
34  import org.kuali.common.util.LoggerUtils;
35  import org.kuali.common.util.Project;
36  import org.kuali.common.util.ProjectContext;
37  import org.kuali.common.util.ProjectUtils;
38  import org.kuali.common.util.PropertyUtils;
39  import org.kuali.common.util.ReflectionUtils;
40  import org.kuali.common.util.Str;
41  import org.kuali.common.util.execute.Executable;
42  import org.kuali.common.util.execute.SpringExecutable;
43  import org.kuali.common.util.nullify.NullUtils;
44  import org.kuali.common.util.property.Constants;
45  import org.kuali.common.util.property.ProjectProperties;
46  import org.kuali.common.util.service.DefaultSpringService;
47  import org.kuali.common.util.service.PropertySourceContext;
48  import org.kuali.common.util.service.SpringContext;
49  import org.kuali.common.util.service.SpringService;
50  import org.slf4j.Logger;
51  import org.slf4j.LoggerFactory;
52  import org.springframework.beans.factory.BeanFactoryUtils;
53  import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
54  import org.springframework.context.ApplicationContext;
55  import org.springframework.context.ConfigurableApplicationContext;
56  import org.springframework.context.annotation.AnnotationConfigApplicationContext;
57  import org.springframework.context.support.ClassPathXmlApplicationContext;
58  import org.springframework.context.support.GenericXmlApplicationContext;
59  import org.springframework.core.env.ConfigurableEnvironment;
60  import org.springframework.core.env.EnumerablePropertySource;
61  import org.springframework.core.env.Environment;
62  import org.springframework.core.env.MutablePropertySources;
63  import org.springframework.core.env.PropertiesPropertySource;
64  import org.springframework.core.env.PropertySource;
65  
66  public class SpringUtils {
67  
68  	private static final Logger logger = LoggerFactory.getLogger(SpringUtils.class);
69  
70  	private static final String GLOBAL_SPRING_PROPERTY_SOURCE_NAME = "springPropertySource";
71  
72  	public static SpringContext getSpringContext(List<Class<?>> annotatedClasses, ProjectContext project, List<ProjectContext> others) {
73  		
74  		
75  		
76  		
77  		PropertySource<?> source = getGlobalPropertySource(project, others);
78  
79  		
80  		
81  		PropertySourceContext psc = new PropertySourceContext(source, true);
82  
83  		
84  		SpringContext context = new SpringContext();
85  
86  		
87  		context.setPropertySourceContext(psc);
88  
89  		
90  		context.setAnnotatedClasses(annotatedClasses);
91  
92  		
93  		return context;
94  	}
95  
96  	public static SpringContext getSpringContext(Class<?> annotatedClass, ProjectContext project, List<ProjectContext> others) {
97  		return getSpringContext(CollectionUtils.asList(annotatedClass), project, others);
98  	}
99  
100 	
101 
102 
103 
104 	public static PropertySource<?> getGlobalPropertySource(ProjectContext project, ProjectContext other) {
105 		return getGlobalPropertySource(project, Arrays.asList(other));
106 	}
107 
108 	
109 
110 
111 
112 	public static PropertySource<?> getGlobalPropertySource(ProjectContext project, List<ProjectContext> others) {
113 		return getGlobalPropertySource(project, others, null);
114 	}
115 
116 	
117 
118 
119 
120 	public static PropertySource<?> getGlobalPropertySource(ProjectContext project, List<ProjectContext> others, Properties properties) {
121 
122 		ProjectProperties projectProperties = ProjectUtils.loadProjectProperties(project);
123 
124 		Properties existing = projectProperties.getPropertiesContext().getProperties();
125 		Properties combined = PropertyUtils.combine(existing, properties);
126 		projectProperties.getPropertiesContext().setProperties(combined);
127 
128 		List<ProjectProperties> otherProjectProperties = new ArrayList<ProjectProperties>();
129 		for (ProjectContext other : CollectionUtils.toEmptyList(others)) {
130 			ProjectProperties opp = ProjectUtils.loadProjectProperties(other);
131 			otherProjectProperties.add(opp);
132 		}
133 
134 		
135 		return getGlobalPropertySource(projectProperties, otherProjectProperties);
136 	}
137 
138 	
139 
140 
141 
142 	public static PropertySource<?> getGlobalPropertySource(ProjectProperties project, List<ProjectProperties> others) {
143 		
144 		List<ProjectProperties> list = new ArrayList<ProjectProperties>();
145 
146 		
147 		list.add(project);
148 
149 		
150 		list.addAll(others);
151 
152 		
153 		list.add(project);
154 
155 		
156 		return getGlobalPropertySource(GLOBAL_SPRING_PROPERTY_SOURCE_NAME, list);
157 	}
158 
159 	public static List<String> getIncludes(Environment env, String key, String defaultValue) {
160 		String includes = SpringUtils.getProperty(env, key, defaultValue);
161 		if (NullUtils.isNull(includes) || StringUtils.equals(includes, Constants.WILDCARD)) {
162 			return new ArrayList<String>();
163 		} else {
164 			return CollectionUtils.getTrimmedListFromCSV(includes);
165 		}
166 	}
167 
168 	public static List<String> getIncludes(Environment env, String key) {
169 		return getIncludes(env, key, null);
170 	}
171 
172 	public static List<String> getExcludes(Environment env, String key, String defaultValue) {
173 		String excludes = SpringUtils.getProperty(env, key, defaultValue);
174 		if (NullUtils.isNullOrNone(excludes)) {
175 			return new ArrayList<String>();
176 		} else {
177 			return CollectionUtils.getTrimmedListFromCSV(excludes);
178 		}
179 	}
180 
181 	public static List<String> getExcludes(Environment env, String key) {
182 		return getExcludes(env, key, null);
183 	}
184 
185 	
186 
187 
188 	public static <T> T getInstance(Environment env, String key, Class<T> defaultValue) {
189 		String className = getProperty(env, key, defaultValue.getCanonicalName());
190 		return ReflectionUtils.newInstance(className);
191 	}
192 
193 	
194 
195 
196 	public static <T> T getInstance(Environment env, String key) {
197 		String className = getProperty(env, key, null);
198 		return ReflectionUtils.newInstance(className);
199 	}
200 
201 	public static List<String> getListFromCSV(Environment env, String key, String defaultValue) {
202 		String csv = SpringUtils.getProperty(env, key, defaultValue);
203 		return CollectionUtils.getTrimmedListFromCSV(csv);
204 	}
205 
206 	@Deprecated
207 	public static List<PropertySource<?>> getPropertySources(SpringService service, Class<?> annotatedClass, String mavenPropertiesBeanName, Properties mavenProperties) {
208 		return getPropertySources(annotatedClass, mavenPropertiesBeanName, mavenProperties);
209 	}
210 
211 	public static List<PropertySource<?>> getPropertySources(Class<?> annotatedClass, String mavenPropertiesBeanName, Properties mavenProperties) {
212 		ConfigurableApplicationContext parent = null;
213 		if (mavenProperties == null) {
214 			parent = getConfigurableApplicationContext();
215 		} else {
216 			parent = getContextWithPreRegisteredBean(mavenPropertiesBeanName, mavenProperties);
217 		}
218 		AnnotationConfigApplicationContext child = new AnnotationConfigApplicationContext();
219 		child.setParent(parent);
220 		child.register(annotatedClass);
221 		child.refresh();
222 		return SpringUtils.getPropertySources(child);
223 	}
224 
225 	@Deprecated
226 	public static List<PropertySource<?>> getPropertySources(SpringService service, String location, String mavenPropertiesBeanName, Properties mavenProperties) {
227 		return getPropertySources(location, mavenPropertiesBeanName, mavenProperties);
228 	}
229 
230 	public static List<PropertySource<?>> getPropertySources(String location, String mavenPropertiesBeanName, Properties mavenProperties) {
231 		String[] locationsArray = { location };
232 		ConfigurableApplicationContext parent = getContextWithPreRegisteredBean(mavenPropertiesBeanName, mavenProperties);
233 		ConfigurableApplicationContext child = new ClassPathXmlApplicationContext(locationsArray, parent);
234 		return SpringUtils.getPropertySources(child);
235 	}
236 
237 	public static Executable getSpringExecutable(Environment env, boolean skip, PropertySource<?> ps, List<Class<?>> annotatedClasses) {
238 		
239 
240 
241 
242 		PropertySourceContext psc = new PropertySourceContext(ps, true);
243 
244 		
245 		SpringContext context = new SpringContext();
246 		context.setAnnotatedClasses(annotatedClasses);
247 		context.setPropertySourceContext(psc);
248 
249 		
250 		SpringExecutable se = new SpringExecutable();
251 		se.setService(new DefaultSpringService());
252 		se.setContext(context);
253 		se.setSkip(skip);
254 		return se;
255 	}
256 
257 	public static int getInteger(Environment env, String key) {
258 		String value = getProperty(env, key);
259 		return Integer.parseInt(value);
260 	}
261 
262 	public static int getInteger(Environment env, String key, int defaultValue) {
263 		String value = getProperty(env, key, Integer.toString(defaultValue));
264 		return Integer.parseInt(value);
265 	}
266 
267 	public static long getLong(Environment env, String key) {
268 		String value = getProperty(env, key);
269 		return Long.parseLong(value);
270 	}
271 
272 	public static long getLong(Environment env, String key, long defaultValue) {
273 		String value = getProperty(env, key, Long.toString(defaultValue));
274 		return Long.parseLong(value);
275 	}
276 
277 	public static double getDouble(Environment env, String key) {
278 		String value = getProperty(env, key);
279 		return Double.parseDouble(value);
280 	}
281 
282 	public static double getDouble(Environment env, String key, double defaultValue) {
283 		String value = getProperty(env, key, Double.toString(defaultValue));
284 		return Double.parseDouble(value);
285 	}
286 
287 	
288 
289 
290 
291 
292 	public static long getMillis(Environment env, String key, String defaultValue) {
293 		String value = getProperty(env, key, defaultValue);
294 		return FormatUtils.getMillis(value);
295 	}
296 
297 	
298 
299 
300 
301 
302 	public static long getBytes(Environment env, String key, String defaultValue) {
303 		String value = getProperty(env, key, defaultValue);
304 		return FormatUtils.getBytes(value);
305 	}
306 
307 	
308 
309 
310 
311 
312 	public static long getBytes(Environment env, String key) {
313 		String value = getProperty(env, key);
314 		return FormatUtils.getBytes(value);
315 	}
316 
317 	public static File getFile(Environment env, String key) {
318 		String value = getProperty(env, key);
319 		return new File(value);
320 	}
321 
322 	public static boolean getBoolean(Environment env, String key, boolean defaultValue) {
323 		String value = getProperty(env, key, Boolean.toString(defaultValue));
324 		return Boolean.parseBoolean(value);
325 	}
326 
327 	public static boolean getBoolean(Environment env, String key) {
328 		String value = getProperty(env, key);
329 		return Boolean.parseBoolean(value);
330 	}
331 
332 	public static PropertySource<?> getGlobalPropertySource(String name, List<ProjectProperties> pps) {
333 		
334 		Properties source = PropertyUtils.load(pps);
335 
336 		
337 		Properties globalSource = PropertyUtils.getGlobalProperties(source);
338 
339 		
340 		PropertyUtils.prepareContextProperties(globalSource);
341 
342 		
343 
344 		
345 		return new PropertiesPropertySource(name, globalSource);
346 	}
347 
348 	public static PropertySource<?> getPropertySource(String name, List<ProjectProperties> pps) {
349 		
350 		Properties source = PropertyUtils.load(pps);
351 
352 		
353 		PropertyUtils.prepareContextProperties(source);
354 
355 		
356 		return new PropertiesPropertySource(name, source);
357 	}
358 
359 	
360 
361 
362 
363 
364 
365 
366 	public static String getDefaultPropertyContextLocation(String gav) {
367 		Assert.hasText(gav, "gav has no text");
368 		Project p = ProjectUtils.getProject(gav);
369 		return "classpath:" + Str.getPath(p.getGroupId()) + "/" + p.getArtifactId() + "-properties-context.xml";
370 	}
371 
372 	
373 
374 
375 	public static void validateExists(List<String> locations) {
376 		StringBuilder sb = new StringBuilder();
377 		for (String location : locations) {
378 			if (!LocationUtils.exists(location)) {
379 				sb.append("Location [" + location + "] does not exist\n");
380 			}
381 		}
382 		if (sb.length() > 0) {
383 			throw new IllegalArgumentException(sb.toString());
384 		}
385 	}
386 
387 	public static ConfigurableApplicationContext getContextWithPreRegisteredBeans(String id, String displayName, List<String> beanNames, List<Object> beans) {
388 		Assert.isTrue(beanNames.size() == beans.size());
389 		GenericXmlApplicationContext appContext = new GenericXmlApplicationContext();
390 		if (!StringUtils.isBlank(id)) {
391 			appContext.setId(id);
392 		}
393 		if (!StringUtils.isBlank(displayName)) {
394 			appContext.setDisplayName(displayName);
395 		}
396 		appContext.refresh();
397 		ConfigurableListableBeanFactory factory = appContext.getBeanFactory();
398 		for (int i = 0; i < beanNames.size(); i++) {
399 			String beanName = beanNames.get(i);
400 			Object bean = beans.get(i);
401 			logger.debug("Registering bean - [{}] -> [{}]", beanName, bean.getClass().getName());
402 			factory.registerSingleton(beanName, bean);
403 		}
404 		return appContext;
405 	}
406 
407 	public static ConfigurableApplicationContext getConfigurableApplicationContext() {
408 		return new GenericXmlApplicationContext();
409 	}
410 
411 	public static ConfigurableApplicationContext getContextWithPreRegisteredBeans(List<String> beanNames, List<Object> beans) {
412 		return getContextWithPreRegisteredBeans(null, null, beanNames, beans);
413 	}
414 
415 	
416 
417 
418 	public static void refreshQuietly(ConfigurableApplicationContext context) {
419 		if (context != null) {
420 			context.refresh();
421 		}
422 	}
423 
424 	
425 
426 
427 	public static void closeQuietly(ConfigurableApplicationContext context) {
428 		if (context != null) {
429 			context.close();
430 		}
431 	}
432 
433 	public static ConfigurableApplicationContext getContextWithPreRegisteredBean(String beanName, Object bean) {
434 		return getContextWithPreRegisteredBeans(Arrays.asList(beanName), Arrays.asList(bean));
435 	}
436 
437 	public static List<PropertySource<?>> getPropertySourcesFromAnnotatedClass(String annotatedClassName) {
438 		Class<?> annotatedClass = ReflectionUtils.getClass(annotatedClassName);
439 		return getPropertySources(annotatedClass);
440 	}
441 
442 	public static List<PropertySource<?>> getPropertySources(Class<?> annotatedClass) {
443 		ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(annotatedClass);
444 		return extractPropertySourcesAndClose(context);
445 	}
446 
447 	public static List<PropertySource<?>> extractPropertySourcesAndClose(ConfigurableApplicationContext context) {
448 		
449 		List<PropertySource<?>> sources = getPropertySources(context);
450 
451 		
452 		closeQuietly(context);
453 
454 		
455 		return sources;
456 	}
457 
458 	
459 
460 
461 	public static List<PropertySource<?>> getPropertySources(String location) {
462 		ConfigurableApplicationContext context = new GenericXmlApplicationContext(location);
463 		return extractPropertySourcesAndClose(context);
464 	}
465 
466 	
467 
468 
469 	public static List<PropertySource<?>> getPropertySources(ConfigurableApplicationContext context) {
470 		
471 		return getPropertySources(context, new PropertySourceNameComparator());
472 	}
473 
474 	public static <T> Map<String, T> getAllBeans(List<String> locations, Class<T> type) {
475 		String[] locationsArray = locations.toArray(new String[locations.size()]);
476 		ConfigurableApplicationContext ctx = new GenericXmlApplicationContext(locationsArray);
477 		Map<String, T> map = BeanFactoryUtils.beansOfTypeIncludingAncestors(ctx, type);
478 		ctx.close();
479 		return map;
480 	}
481 
482 	public static <T> Map<String, T> getAllBeans(String location, Class<T> type) {
483 		ConfigurableApplicationContext ctx = new GenericXmlApplicationContext(location);
484 		Map<String, T> map = BeanFactoryUtils.beansOfTypeIncludingAncestors(ctx, type);
485 		ctx.close();
486 		return map;
487 	}
488 
489 	public static <T> Map<String, T> getAllBeans(ConfigurableApplicationContext ctx, Class<T> type) {
490 		return BeanFactoryUtils.beansOfTypeIncludingAncestors(ctx, type);
491 	}
492 
493 	
494 
495 
496 	public static List<PropertySource<?>> getPropertySources(ConfigurableApplicationContext context, Comparator<PropertySource<?>> comparator) {
497 		
498 		@SuppressWarnings("rawtypes")
499 		Map<String, PropertySource> map = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, PropertySource.class);
500 
501 		
502 		List<PropertySource<?>> list = new ArrayList<PropertySource<?>>();
503 		for (PropertySource<?> source : map.values()) {
504 			list.add(source);
505 		}
506 
507 		
508 		Collections.sort(list, comparator);
509 
510 		
511 		return list;
512 	}
513 
514 	
515 
516 
517 	public static List<PropertySource<?>> asList(PropertySource<?>... sources) {
518 		List<PropertySource<?>> list = new ArrayList<PropertySource<?>>();
519 		if (sources == null) {
520 			return list;
521 		}
522 		for (PropertySource<?> element : sources) {
523 			if (element != null) {
524 				list.add(element);
525 			}
526 		}
527 		return list;
528 	}
529 
530 	public static void debug(ApplicationContext ctx) {
531 		logger.debug("------------------------ Spring Context ------------------------------");
532 		logger.debug("Id: [{}]", ctx.getId());
533 		logger.debug("Display Name: [{}]", ctx.getDisplayName());
534 		logger.debug("Application Name: [{}]", ctx.getApplicationName());
535 		logger.debug("----------------------------------------------------------------------");
536 		List<String> names = Arrays.asList(BeanFactoryUtils.beanNamesIncludingAncestors(ctx));
537 		List<String> columns = Arrays.asList("Name", "Type", "Hashcode");
538 		List<Object[]> rows = new ArrayList<Object[]>();
539 		Collections.sort(names);
540 		for (String name : names) {
541 			Object bean = ctx.getBean(name);
542 			String instance = (bean == null) ? Constants.NULL : bean.getClass().getSimpleName();
543 			String hashcode = (bean == null) ? Constants.NULL : Integer.toHexString(bean.hashCode());
544 			Object[] row = { name, instance, hashcode };
545 			rows.add(row);
546 		}
547 		LoggerUtils.logTable(columns, rows, LoggerLevel.DEBUG, logger, true);
548 		logger.debug("----------------------------------------------------------------------");
549 	}
550 
551 	public static void showPropertySources(List<PropertySource<?>> propertySources) {
552 		List<String> columns = Arrays.asList("Name", "Impl", "Source");
553 		List<Object[]> rows = new ArrayList<Object[]>();
554 		for (PropertySource<?> propertySource : propertySources) {
555 			String name = propertySource.getName();
556 			String impl = propertySource.getClass().getName();
557 			String source = propertySource.getSource().getClass().getName();
558 			Object[] row = { name, impl, source };
559 			rows.add(row);
560 		}
561 		LoggerUtils.logTable(columns, rows, LoggerLevel.INFO, logger, true);
562 	}
563 
564 	public static void showPropertySources(ConfigurableEnvironment env) {
565 		showPropertySources(getPropertySources(env));
566 	}
567 
568 	
569 
570 
571 	public static String getProperty(Environment env, String key) {
572 		String value = env.getRequiredProperty(key);
573 		return env.resolveRequiredPlaceholders(value);
574 	}
575 
576 	
577 
578 
579 	public static boolean exists(Environment env, String key) {
580 		return env.getProperty(key) != null;
581 	}
582 
583 	
584 
585 
586 
587 	public static String getProperty(Environment env, String key, String defaultValue) {
588 		if (defaultValue == null) {
589 			
590 			return getProperty(env, key);
591 		} else {
592 			
593 			String value = env.getProperty(key);
594 			if (value == null) {
595 				
596 				return env.resolveRequiredPlaceholders(defaultValue);
597 			} else {
598 				
599 				return env.resolveRequiredPlaceholders(value);
600 			}
601 		}
602 	}
603 
604 	
605 
606 
607 
608 	public static Properties getAllEnumerableProperties(ConfigurableEnvironment env) {
609 
610 		
611 		List<PropertySource<?>> sources = getPropertySources(env);
612 
613 		
614 		
615 		Collections.reverse(sources);
616 
617 		
618 		PropertySourceConversionResult result = convertEnumerablePropertySources(sources);
619 
620 		
621 		return PropertyUtils.combine(result.getPropertiesList());
622 	}
623 
624 	
625 
626 
627 	public static void reconfigurePropertySources(ConfigurableEnvironment env, String name, Properties properties) {
628 		
629 		removeAllPropertySources(env);
630 
631 		
632 		MutablePropertySources mps = env.getPropertySources();
633 
634 		
635 		Assert.isTrue(mps.size() == 0);
636 
637 		
638 		PropertiesPropertySource pps = new PropertiesPropertySource(name, properties);
639 
640 		
641 		mps.addFirst(pps);
642 	}
643 
644 	
645 
646 
647 	public static void removeAllPropertySources(ConfigurableEnvironment env) {
648 		MutablePropertySources mps = env.getPropertySources();
649 		List<PropertySource<?>> sources = getPropertySources(env);
650 		for (PropertySource<?> source : sources) {
651 			String name = source.getName();
652 			mps.remove(name);
653 		}
654 	}
655 
656 	
657 
658 
659 	public static List<PropertySource<?>> getPropertySources(ConfigurableEnvironment env) {
660 		MutablePropertySources mps = env.getPropertySources();
661 		List<PropertySource<?>> sources = new ArrayList<PropertySource<?>>();
662 		Iterator<PropertySource<?>> itr = mps.iterator();
663 		while (itr.hasNext()) {
664 			PropertySource<?> source = itr.next();
665 			sources.add(source);
666 		}
667 		return sources;
668 	}
669 
670 	
671 
672 
673 	public static PropertySourceConversionResult convertEnumerablePropertySources(List<PropertySource<?>> sources) {
674 		PropertySourceConversionResult result = new PropertySourceConversionResult();
675 		List<Properties> list = new ArrayList<Properties>();
676 		List<PropertySource<?>> converted = new ArrayList<PropertySource<?>>();
677 		List<PropertySource<?>> skipped = new ArrayList<PropertySource<?>>();
678 		
679 		for (PropertySource<?> source : sources) {
680 			logger.debug("Adding [{}]", source.getName());
681 			if (source instanceof EnumerablePropertySource) {
682 				EnumerablePropertySource<?> eps = (EnumerablePropertySource<?>) source;
683 				Properties sourceProperties = convert(eps);
684 				list.add(sourceProperties);
685 				converted.add(source);
686 			} else {
687 				logger.debug("Unable to obtain properties from property source [{}] -> [{}]", source.getName(), source.getClass().getName());
688 				skipped.add(source);
689 			}
690 		}
691 		result.setConverted(converted);
692 		result.setSkipped(skipped);
693 		result.setPropertiesList(list);
694 		return result;
695 	}
696 
697 	
698 
699 
700 	public static Properties convert(EnumerablePropertySource<?> source) {
701 		Properties properties = new Properties();
702 		String[] names = source.getPropertyNames();
703 		for (String name : names) {
704 			Object object = source.getProperty(name);
705 			if (object != null) {
706 				String value = object.toString();
707 				properties.setProperty(name, value);
708 			} else {
709 				logger.warn("Property [{}] is null", name);
710 			}
711 		}
712 		return properties;
713 	}
714 
715 	
716 
717 
718 	public static boolean isTrue(Environment env, String property) {
719 		String value = env.getProperty(property);
720 		if (StringUtils.isBlank(value)) {
721 			return false;
722 		} else {
723 			return new Boolean(value);
724 		}
725 	}
726 
727 }