xref: /AOO41X/main/qadevOOo/runner/util/RegistryTools.java (revision ef39d40d3f5e66cf3f035b3e93783012b340500d)
1*ef39d40dSAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*ef39d40dSAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*ef39d40dSAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*ef39d40dSAndrew Rist  * distributed with this work for additional information
6*ef39d40dSAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*ef39d40dSAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*ef39d40dSAndrew Rist  * "License"); you may not use this file except in compliance
9*ef39d40dSAndrew Rist  * with the License.  You may obtain a copy of the License at
10cdf0e10cSrcweir  *
11*ef39d40dSAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir  *
13*ef39d40dSAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*ef39d40dSAndrew Rist  * software distributed under the License is distributed on an
15*ef39d40dSAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*ef39d40dSAndrew Rist  * KIND, either express or implied.  See the License for the
17*ef39d40dSAndrew Rist  * specific language governing permissions and limitations
18*ef39d40dSAndrew Rist  * under the License.
19cdf0e10cSrcweir  *
20*ef39d40dSAndrew Rist  *************************************************************/
21*ef39d40dSAndrew Rist 
22*ef39d40dSAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir package util;
25cdf0e10cSrcweir 
26cdf0e10cSrcweir // access the implementations via names
27cdf0e10cSrcweir import com.sun.star.uno.UnoRuntime;
28cdf0e10cSrcweir import java.io.PrintWriter ;
29cdf0e10cSrcweir 
30cdf0e10cSrcweir import com.sun.star.registry.XRegistryKey ;
31cdf0e10cSrcweir import com.sun.star.registry.XSimpleRegistry ;
32cdf0e10cSrcweir import com.sun.star.registry.RegistryKeyType ;
33cdf0e10cSrcweir import com.sun.star.registry.RegistryValueType ;
34cdf0e10cSrcweir import com.sun.star.registry.InvalidRegistryException ;
35cdf0e10cSrcweir import com.sun.star.lang.XMultiServiceFactory ;
36cdf0e10cSrcweir import com.sun.star.uno.Exception;
37cdf0e10cSrcweir 
38cdf0e10cSrcweir public class RegistryTools {
39cdf0e10cSrcweir 
40cdf0e10cSrcweir 	/**
41cdf0e10cSrcweir 	* Creates 'com.sun.star.registry.SimpleRegistry'
42cdf0e10cSrcweir 	* service.
43cdf0e10cSrcweir 	* @param xMSF Multiservice factory.
44cdf0e10cSrcweir 	* @return Service created.
45cdf0e10cSrcweir 	*/
createRegistryService(XMultiServiceFactory xMSF)46cdf0e10cSrcweir 	public static XSimpleRegistry createRegistryService
47cdf0e10cSrcweir 		(XMultiServiceFactory xMSF) throws com.sun.star.uno.Exception {
48cdf0e10cSrcweir 
49cdf0e10cSrcweir         Object oInterface = xMSF.createInstance
50cdf0e10cSrcweir         	("com.sun.star.registry.SimpleRegistry");
51cdf0e10cSrcweir         return (XSimpleRegistry) UnoRuntime.queryInterface (
52cdf0e10cSrcweir         	XSimpleRegistry.class, oInterface) ;
53cdf0e10cSrcweir     }
54cdf0e10cSrcweir 
55cdf0e10cSrcweir 	/**
56cdf0e10cSrcweir 	* Opens registry file for reading/writing. If file doesn't
57cdf0e10cSrcweir 	* exist a new one created.
58cdf0e10cSrcweir 	* @param file Registry file name.
59cdf0e10cSrcweir 	* @param xMSF Multiservice factory.
60cdf0e10cSrcweir 	* @return Opened registry.
61cdf0e10cSrcweir 	*/
openRegistry(String file, XMultiServiceFactory xMSF)62cdf0e10cSrcweir     public static XSimpleRegistry openRegistry
63cdf0e10cSrcweir     	(String file, XMultiServiceFactory xMSF)
64cdf0e10cSrcweir     	throws com.sun.star.uno.Exception {
65cdf0e10cSrcweir 
66cdf0e10cSrcweir     	XSimpleRegistry reg = createRegistryService(xMSF) ;
67cdf0e10cSrcweir 
68cdf0e10cSrcweir     	reg.open(file, false, true) ;
69cdf0e10cSrcweir 
70cdf0e10cSrcweir     	return reg ;
71cdf0e10cSrcweir     }
72cdf0e10cSrcweir 
73cdf0e10cSrcweir 	/**
74cdf0e10cSrcweir 	* Compares two registry keys, their names, value
75cdf0e10cSrcweir 	* types and values.
76cdf0e10cSrcweir 	* return <code>true</code> if key names, value types
77cdf0e10cSrcweir 	* and values are equal, else returns <code>false</code>.
78cdf0e10cSrcweir 	*/
compareKeys(XRegistryKey key1, XRegistryKey key2)79cdf0e10cSrcweir 	public static boolean compareKeys
80cdf0e10cSrcweir 		(XRegistryKey key1, XRegistryKey key2) {
81cdf0e10cSrcweir 
82cdf0e10cSrcweir 		if (key1 == null || key2 == null ||
83cdf0e10cSrcweir 			!key1.isValid() || !key2.isValid())
84cdf0e10cSrcweir 
85cdf0e10cSrcweir 			return false ;
86cdf0e10cSrcweir 
87cdf0e10cSrcweir 		String keyName1 = getShortKeyName(key1.getKeyName()) ;
88cdf0e10cSrcweir 		String keyName2 = getShortKeyName(key2.getKeyName()) ;
89cdf0e10cSrcweir 
90cdf0e10cSrcweir 		if (!keyName1.equals(keyName2)) return false ;
91cdf0e10cSrcweir 
92cdf0e10cSrcweir 		try {
93cdf0e10cSrcweir 			if (key1.getValueType() != key2.getValueType()) return false ;
94cdf0e10cSrcweir 		} catch (InvalidRegistryException e) {
95cdf0e10cSrcweir 			return false ;
96cdf0e10cSrcweir 		}
97cdf0e10cSrcweir 
98cdf0e10cSrcweir 		RegistryValueType type ;
99cdf0e10cSrcweir 		try {
100cdf0e10cSrcweir 			type = key1.getValueType() ;
101cdf0e10cSrcweir 
102cdf0e10cSrcweir 			if (type.equals(RegistryValueType.ASCII)) {
103cdf0e10cSrcweir 				if (!key1.getAsciiValue().equals(key2.getAsciiValue()))
104cdf0e10cSrcweir 					return false ;
105cdf0e10cSrcweir 			} else
106cdf0e10cSrcweir 			if (type.equals(RegistryValueType.STRING)) {
107cdf0e10cSrcweir 				if (!key1.getStringValue().equals(key2.getStringValue()))
108cdf0e10cSrcweir 					return false ;
109cdf0e10cSrcweir 			} else
110cdf0e10cSrcweir 			if (type.equals(RegistryValueType.LONG)) {
111cdf0e10cSrcweir 				if (key1.getLongValue() != key2.getLongValue())
112cdf0e10cSrcweir 					return false ;
113cdf0e10cSrcweir 			} else
114cdf0e10cSrcweir 			if (type.equals(RegistryValueType.BINARY)) {
115cdf0e10cSrcweir 				byte[] bin1 = key1.getBinaryValue() ;
116cdf0e10cSrcweir 				byte[] bin2 = key2.getBinaryValue() ;
117cdf0e10cSrcweir 				if (bin1.length != bin2.length)
118cdf0e10cSrcweir 					return false ;
119cdf0e10cSrcweir 				for (int i = 0; i < bin1.length; i++)
120cdf0e10cSrcweir 					if (bin1[i] != bin2[i]) return false ;
121cdf0e10cSrcweir 			} else
122cdf0e10cSrcweir 			if (type.equals(RegistryValueType.ASCIILIST)) {
123cdf0e10cSrcweir 				String[] list1 = key1.getAsciiListValue() ;
124cdf0e10cSrcweir 				String[] list2 = key2.getAsciiListValue() ;
125cdf0e10cSrcweir 				if (list1.length != list2.length)
126cdf0e10cSrcweir 					return false ;
127cdf0e10cSrcweir 				for (int i = 0; i < list1.length; i++)
128cdf0e10cSrcweir 					if (!list1[i].equals(list2[i])) return false ;
129cdf0e10cSrcweir 			} else
130cdf0e10cSrcweir 			if (type.equals(RegistryValueType.STRINGLIST)) {
131cdf0e10cSrcweir 				String[] list1 = key1.getStringListValue() ;
132cdf0e10cSrcweir 				String[] list2 = key2.getStringListValue() ;
133cdf0e10cSrcweir 				if (list1.length != list2.length)
134cdf0e10cSrcweir 					return false ;
135cdf0e10cSrcweir 				for (int i = 0; i < list1.length; i++)
136cdf0e10cSrcweir 					if (!list1[i].equals(list2[i])) return false ;
137cdf0e10cSrcweir 			} else
138cdf0e10cSrcweir 			if (type.equals(RegistryValueType.LONGLIST)) {
139cdf0e10cSrcweir 				int[] list1 = key1.getLongListValue() ;
140cdf0e10cSrcweir 				int[] list2 = key2.getLongListValue() ;
141cdf0e10cSrcweir 				if (list1.length != list2.length)
142cdf0e10cSrcweir 					return false ;
143cdf0e10cSrcweir 				for (int i = 0; i < list1.length; i++)
144cdf0e10cSrcweir 					if (list1[i] != list2[i]) return false ;
145cdf0e10cSrcweir 			}
146cdf0e10cSrcweir 		} catch (Exception e) {
147cdf0e10cSrcweir 			return false ;
148cdf0e10cSrcweir 		}
149cdf0e10cSrcweir 
150cdf0e10cSrcweir 		return true ;
151cdf0e10cSrcweir 	}
152cdf0e10cSrcweir 
153cdf0e10cSrcweir 	/**
154cdf0e10cSrcweir 	* Gets name of the key relative to its parent.
155cdf0e10cSrcweir 	* For example if full name of key is '/key1/subkey'
156cdf0e10cSrcweir 	* short key name is 'subkey'
157cdf0e10cSrcweir 	* @param keyName Full key name.
158cdf0e10cSrcweir 	* @return Short key name.
159cdf0e10cSrcweir 	*/
getShortKeyName(String keyName)160cdf0e10cSrcweir 	public static String getShortKeyName(String keyName) {
161cdf0e10cSrcweir 		if (keyName == null) return null ;
162cdf0e10cSrcweir 		int idx = keyName.lastIndexOf("/") ;
163cdf0e10cSrcweir 		if (idx < 0) return keyName ;
164cdf0e10cSrcweir 		else return keyName.substring(idx + 1) ;
165cdf0e10cSrcweir 	}
166cdf0e10cSrcweir 
167cdf0e10cSrcweir 	/**
168cdf0e10cSrcweir 	* Compare all child keys.
169cdf0e10cSrcweir 	* @param compareRoot If <code>true</code> method also
170cdf0e10cSrcweir 	* compare root keys, if <code>false</code> it begins recursive
171cdf0e10cSrcweir 	* comparing from children of root keys.
172cdf0e10cSrcweir 	* @return <code>true</code> if keys and their sub keys are equal.
173cdf0e10cSrcweir 	*/
compareKeyTrees(XRegistryKey tree1, XRegistryKey tree2, boolean compareRoot)174cdf0e10cSrcweir 	protected static boolean compareKeyTrees
175cdf0e10cSrcweir 		(XRegistryKey tree1, XRegistryKey tree2, boolean compareRoot) {
176cdf0e10cSrcweir 
177cdf0e10cSrcweir 		if (compareRoot && !compareKeys(tree1, tree2)) return false ;
178cdf0e10cSrcweir 
179cdf0e10cSrcweir 		try {
180cdf0e10cSrcweir 			String[] keyNames1 = tree1.getKeyNames() ;
181cdf0e10cSrcweir 			String[] keyNames2 = tree2.getKeyNames() ;
182cdf0e10cSrcweir 
183cdf0e10cSrcweir 			if (keyNames1 == null && keyNames2 == null) return true ;
184cdf0e10cSrcweir 
185cdf0e10cSrcweir 			if (keyNames1 == null || keyNames2 == null ||
186cdf0e10cSrcweir 				keyNames2.length != keyNames1.length)
187cdf0e10cSrcweir 				return false ;
188cdf0e10cSrcweir 
189cdf0e10cSrcweir 			for (int i = 0; i < keyNames1.length; i++) {
190cdf0e10cSrcweir 
191cdf0e10cSrcweir 				String keyName = getShortKeyName(keyNames1[i]) ;
192cdf0e10cSrcweir 				XRegistryKey key2 = tree2.openKey(keyName) ;
193cdf0e10cSrcweir 
194cdf0e10cSrcweir 				if (key2 == null)
195cdf0e10cSrcweir 				// key with the same name doesn't exist in the second tree
196cdf0e10cSrcweir 					return false ;
197cdf0e10cSrcweir 
198cdf0e10cSrcweir 				if (!tree1.getKeyType(keyName).equals(
199cdf0e10cSrcweir 					 tree2.getKeyType(keyName)))
200cdf0e10cSrcweir 					return false ;
201cdf0e10cSrcweir 
202cdf0e10cSrcweir 				if (tree1.getKeyType(keyName).equals(
203cdf0e10cSrcweir 					RegistryKeyType.LINK)) {
204cdf0e10cSrcweir 
205cdf0e10cSrcweir 					if (!getShortKeyName(tree1.getLinkTarget(keyName)).equals(
206cdf0e10cSrcweir 						getShortKeyName(tree2.getLinkTarget(keyName))))
207cdf0e10cSrcweir 
208cdf0e10cSrcweir 						return false ;
209cdf0e10cSrcweir 				} else {
210cdf0e10cSrcweir 
211cdf0e10cSrcweir 					if (compareKeyTrees(tree1.openKey(keyName),
212cdf0e10cSrcweir 						  tree2.openKey(keyName), true) == false) return false ;
213cdf0e10cSrcweir 				}
214cdf0e10cSrcweir 			}
215cdf0e10cSrcweir 		} catch (InvalidRegistryException e) {
216cdf0e10cSrcweir 			return false ;
217cdf0e10cSrcweir 		}
218cdf0e10cSrcweir 
219cdf0e10cSrcweir 		return true ;
220cdf0e10cSrcweir 	}
221cdf0e10cSrcweir 
222cdf0e10cSrcweir 	/**
223cdf0e10cSrcweir 	* Compare keys specified and all their child keys.
224cdf0e10cSrcweir 	* @return <code>true</code> if keys and their sub keys are equal.
225cdf0e10cSrcweir 	*/
compareKeyTrees(XRegistryKey tree1, XRegistryKey tree2)226cdf0e10cSrcweir 	public static boolean compareKeyTrees
227cdf0e10cSrcweir 		(XRegistryKey tree1, XRegistryKey tree2) {
228cdf0e10cSrcweir 
229cdf0e10cSrcweir 		return compareKeyTrees(tree1, tree2, false) ;
230cdf0e10cSrcweir 	}
231cdf0e10cSrcweir 
232cdf0e10cSrcweir 	/**
233cdf0e10cSrcweir 	* Prints to a specified output about all keys and subkeys information
234cdf0e10cSrcweir 	* (key name, type, value, link target, attributes) recursively.
235cdf0e10cSrcweir 	* @param reg Registry for which information is needed.
236cdf0e10cSrcweir 	* @param out Output stream.
237cdf0e10cSrcweir 	*/
printRegistryInfo(XSimpleRegistry reg, PrintWriter out)238cdf0e10cSrcweir 	public static void printRegistryInfo(XSimpleRegistry reg, PrintWriter out) {
239cdf0e10cSrcweir 		try {
240cdf0e10cSrcweir 			printRegistryInfo(reg.getRootKey(), out) ;
241cdf0e10cSrcweir 		} catch (com.sun.star.registry.InvalidRegistryException e) {
242cdf0e10cSrcweir 			out.println("!!! Can't open root registry key for info printing") ;
243cdf0e10cSrcweir 		}
244cdf0e10cSrcweir 	}
245cdf0e10cSrcweir 
246cdf0e10cSrcweir 	/**
247cdf0e10cSrcweir 	* Prints to a specified output about all keys and subkeys information
248cdf0e10cSrcweir 	* (key name, type, value, link target, attributes) recursively.
249cdf0e10cSrcweir 	* @param root Key for which subkeys (and further) information is required.
250cdf0e10cSrcweir 	* @param out Output stream.
251cdf0e10cSrcweir 	*/
printRegistryInfo(XRegistryKey root, PrintWriter out)252cdf0e10cSrcweir 	public static void printRegistryInfo(XRegistryKey root, PrintWriter out) {
253cdf0e10cSrcweir 		if (root == null) {
254cdf0e10cSrcweir 			out.println("/(null)") ;
255cdf0e10cSrcweir 			return ;
256cdf0e10cSrcweir 		}
257cdf0e10cSrcweir 
258cdf0e10cSrcweir 		out.println("/") ;
259cdf0e10cSrcweir 		try {
260cdf0e10cSrcweir 			printTreeInfo(root, out, "  ") ;
261cdf0e10cSrcweir 		} catch (com.sun.star.registry.InvalidRegistryException e) {
262cdf0e10cSrcweir 			out.println("Exception accessing registry :") ;
263cdf0e10cSrcweir 			e.printStackTrace(out) ;
264cdf0e10cSrcweir 		}
265cdf0e10cSrcweir 	}
266cdf0e10cSrcweir 
printTreeInfo(XRegistryKey key, PrintWriter out, String margin)267cdf0e10cSrcweir 	private static void printTreeInfo(XRegistryKey key,
268cdf0e10cSrcweir 		PrintWriter out, String margin)
269cdf0e10cSrcweir 		throws com.sun.star.registry.InvalidRegistryException {
270cdf0e10cSrcweir 
271cdf0e10cSrcweir 		String[] subKeys = key.getKeyNames() ;
272cdf0e10cSrcweir 
273cdf0e10cSrcweir 		if (subKeys == null || subKeys.length == 0) return ;
274cdf0e10cSrcweir 
275cdf0e10cSrcweir 		for (int i = 0; i < subKeys.length; i++) {
276cdf0e10cSrcweir 			printKeyInfo(key, subKeys[i], out, margin) ;
277cdf0e10cSrcweir 			XRegistryKey subKey = key.openKey
278cdf0e10cSrcweir 				(getShortKeyName(subKeys[i])) ;
279cdf0e10cSrcweir 			printTreeInfo(subKey, out, margin + "  ") ;
280cdf0e10cSrcweir 			subKey.closeKey() ;
281cdf0e10cSrcweir 		}
282cdf0e10cSrcweir 	}
283cdf0e10cSrcweir 
printKeyInfo(XRegistryKey parentKey, String keyName, PrintWriter out, String margin)284cdf0e10cSrcweir 	private static void printKeyInfo(XRegistryKey parentKey,
285cdf0e10cSrcweir 		String keyName, PrintWriter out, String margin)
286cdf0e10cSrcweir 		throws com.sun.star.registry.InvalidRegistryException {
287cdf0e10cSrcweir 
288cdf0e10cSrcweir 		out.print(margin) ;
289cdf0e10cSrcweir 		keyName = getShortKeyName(keyName) ;
290cdf0e10cSrcweir 		XRegistryKey key = parentKey.openKey(keyName) ;
291cdf0e10cSrcweir 		if (key != null)
292cdf0e10cSrcweir 			out.print("/" + getShortKeyName(key.getKeyName()) + " ") ;
293cdf0e10cSrcweir 		else {
294cdf0e10cSrcweir 			out.println("(null)") ;
295cdf0e10cSrcweir 			return ;
296cdf0e10cSrcweir 		}
297cdf0e10cSrcweir 
298cdf0e10cSrcweir 		if (!key.isValid()) {
299cdf0e10cSrcweir 			out.println("(not valid)") ;
300cdf0e10cSrcweir 			return ;
301cdf0e10cSrcweir 		}
302cdf0e10cSrcweir 
303cdf0e10cSrcweir 		if (key.isReadOnly()) {
304cdf0e10cSrcweir 			out.print("(read only) ") ;
305cdf0e10cSrcweir 		}
306cdf0e10cSrcweir 
307cdf0e10cSrcweir 		if (parentKey.getKeyType(keyName) == RegistryKeyType.LINK) {
308cdf0e10cSrcweir 			out.println("(link to " + parentKey.getLinkTarget(keyName) + ")") ;
309cdf0e10cSrcweir 			return ;
310cdf0e10cSrcweir 		}
311cdf0e10cSrcweir 
312cdf0e10cSrcweir 		RegistryValueType type ;
313cdf0e10cSrcweir 		try {
314cdf0e10cSrcweir 			type = key.getValueType() ;
315cdf0e10cSrcweir 
316cdf0e10cSrcweir 			if (type.equals(RegistryValueType.ASCII)) {
317cdf0e10cSrcweir 				out.println("[ASCII] = '" + key.getAsciiValue() + "'") ;
318cdf0e10cSrcweir 			} else
319cdf0e10cSrcweir 			if (type.equals(RegistryValueType.STRING)) {
320cdf0e10cSrcweir 				out.println("[STRING] = '" + key.getStringValue() + "'") ;
321cdf0e10cSrcweir 			} else
322cdf0e10cSrcweir 			if (type.equals(RegistryValueType.LONG)) {
323cdf0e10cSrcweir 				out.println("[LONG] = " + key.getLongValue()) ;
324cdf0e10cSrcweir 			} else
325cdf0e10cSrcweir 			if (type.equals(RegistryValueType.BINARY)) {
326cdf0e10cSrcweir 				out.print("[BINARY] = {") ;
327cdf0e10cSrcweir 				byte[] bin = key.getBinaryValue() ;
328cdf0e10cSrcweir 				for (int i = 0; i < bin.length; i++)
329cdf0e10cSrcweir 					out.print("" + bin[i] + ",") ;
330cdf0e10cSrcweir 				out.println("}") ;
331cdf0e10cSrcweir 			} else
332cdf0e10cSrcweir 			if (type.equals(RegistryValueType.ASCIILIST)) {
333cdf0e10cSrcweir 				out.print("[ASCIILIST] = {") ;
334cdf0e10cSrcweir 				String[] list = key.getAsciiListValue() ;
335cdf0e10cSrcweir 				for (int i = 0; i < list.length; i++)
336cdf0e10cSrcweir 					out.print("'" + list[i] + "',") ;
337cdf0e10cSrcweir 				out.println("}") ;
338cdf0e10cSrcweir 			} else
339cdf0e10cSrcweir 			if (type.equals(RegistryValueType.STRINGLIST)) {
340cdf0e10cSrcweir 				out.print("[STRINGLIST] = {") ;
341cdf0e10cSrcweir 				String[] list = key.getStringListValue() ;
342cdf0e10cSrcweir 				for (int i = 0; i < list.length; i++)
343cdf0e10cSrcweir 					out.print("'" + list[i] + "',") ;
344cdf0e10cSrcweir 				out.println("}") ;
345cdf0e10cSrcweir 			} else
346cdf0e10cSrcweir 			if (type.equals(RegistryValueType.LONGLIST)) {
347cdf0e10cSrcweir 				out.print("[LONGLIST] = {") ;
348cdf0e10cSrcweir 				int[] list = key.getLongListValue() ;
349cdf0e10cSrcweir 				for (int i = 0; i < list.length; i++)
350cdf0e10cSrcweir 					out.print("" + list[i] + ",") ;
351cdf0e10cSrcweir 				out.println("}") ;
352cdf0e10cSrcweir 			} else {
353cdf0e10cSrcweir 				out.println("") ;
354cdf0e10cSrcweir 			}
355cdf0e10cSrcweir 		} catch (com.sun.star.uno.Exception e) {
356cdf0e10cSrcweir 			out.println("Exception occured : ") ;
357cdf0e10cSrcweir 			e.printStackTrace(out) ;
358cdf0e10cSrcweir 		} finally {
359cdf0e10cSrcweir 			key.closeKey() ;
360cdf0e10cSrcweir 		}
361cdf0e10cSrcweir 	}
362cdf0e10cSrcweir 
363cdf0e10cSrcweir 
364cdf0e10cSrcweir //	public static void compareKeyTrees
365cdf0e10cSrcweir 
366cdf0e10cSrcweir }
367