<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Dwarfsoft [GPA] &#187; Group Policy</title>
	<atom:link href="http://www.dwarfsoft.com/blog/tag/group-policy/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.dwarfsoft.com/blog</link>
	<description>Great Programming Artistry</description>
	<lastBuildDate>Tue, 06 Sep 2011 11:18:59 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Group Policy Editing &#8211; Findings</title>
		<link>http://www.dwarfsoft.com/blog/2010/06/15/group-policy-editing-findings/</link>
		<comments>http://www.dwarfsoft.com/blog/2010/06/15/group-policy-editing-findings/#comments</comments>
		<pubDate>Tue, 15 Jun 2010 03:16:01 +0000</pubDate>
		<dc:creator>dwarfsoft</dc:creator>
				<category><![CDATA[Novell]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Tweet]]></category>
		<category><![CDATA[Domain]]></category>
		<category><![CDATA[eDirectory]]></category>
		<category><![CDATA[Group Policy]]></category>
		<category><![CDATA[Migration]]></category>
		<category><![CDATA[Profile]]></category>
		<category><![CDATA[Script]]></category>
		<category><![CDATA[VBScript]]></category>

		<guid isPermaLink="false">http://www.dwarfsoft.com/blog/?p=309</guid>
		<description><![CDATA[I had started another post on Group Policy editing, and how the Policy files are structured, and how to use and improve on the existing Group Policy Editor tool. The post has been found to be far too epic, so I have decided to cover a smaller subset of recent finds. As everybody is probably [...]]]></description>
			<content:encoded><![CDATA[<p>I had started another post on Group Policy editing, and how the Policy files are structured, and how to use and improve on the existing Group Policy Editor tool. The post has been found to be far too epic, so I have decided to cover a smaller subset of recent finds. </p>
<p>As everybody is probably already aware, we use Novell ConsoleOne and Zenworks where I work. ConsoleOne has some interesting features that require that whenever a Group Policy is being edited it takes over as the policy on the machine that is editing it. Rather than have a useful tool like Microsofts Group Policy Management Console, Novell likes to replace the local Group Policy and then just run gpedit.msc. Which is where my first gripe about gpedit.msc comes in:</p>
<p>GPEdit.msc requires line by line entry of things like, for example, port exceptions and program exceptions for the Windows Firewall. This is usually not an issue except that, as I have discussed in previous posts, we have been moving towards a Windows Domain environment. Firewall Exception rules are configured within two places in Group Policy: Domain Profile and Standard Profile. I have found that there is a need to move our current Standard Profile settings across to the Domain Profile settings. After a bit of registry searching I found a neat trick for doing exactly that.</p>
<p><span id="more-309"></span></p>
<p>In Novell, when a GPO is opened in gpedit.msc the Group Policy Contents are loaded into the normal registry locations (as per a normal GPO being applied to user and machine) and the contents are also loaded under a specific pair of registry keys. The <strong>HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Group Policy Objects</strong> Key is created on loading gpedit.msc, and underneath a pair of Keys are created like <strong>{449E44B0-A4DC-4665-AE8F-68710E1BC1EC}Machine</strong> and <strong>{449E44B0-A4DC-4665-AE8F-68710E1BC1EC}User</strong>, where the GUID is randomly generated  (or at least seems to be random) each time gpedit.msc is run. Under these keys are the branch on which the Group Policy Settings are configured.</p>
<p>So therefore in order to duplicate StandardProfile Settings I need to duplicate all keys and values underneath <strong>HKCU\Software\Microsoft\Windows\CurrentVersion\Group Policy Objects\<em>{GUID}</em>Machine\Software\Policies\Microsoft\WindowsFirewall\StandardProfile\</strong>, where {GUID} is the randomly generated GUID for editing a Group Policy Object. So far from my research I have never seen more than one GUID appear underneath the <strong>Group Policy Objects</strong> key, though your mileage may vary. So the first step is to get the User and Machine keys from under the Group Policy Objects key.</p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;">Const HKEY_CURRENT_USER = &amp;H80000001
Const HKEY_LOCAL_MACHINE = &amp;H80000002
&nbsp;
Const REG_SZ = 1
Const REG_EXPAND_SZ = 2
Const REG_BINARY = 3
Const REG_DWORD = 4
Const REG_MULTI_SZ = 7
&nbsp;
strComputer = <span style="color: #800000;">&quot;.&quot;</span>
&nbsp;
<span style="color: #151B8D; font-weight: bold;">Set</span> objReg=<span style="color: #E56717; font-weight: bold;">GetObject</span>(<span style="color: #800000;">&quot;winmgmts:{impersonationLevel=impersonate}!\\&quot;</span> &amp; _
 strComputer &amp; <span style="color: #800000;">&quot;\root\default:StdRegProv&quot;</span>)
&nbsp;
strKeyPath = <span style="color: #800000;">&quot;Software\Microsoft\Windows\CurrentVersion\Group Policy Objects\&quot;</span>
strStandardPath = <span style="color: #800000;">&quot;\Software\Policies\Microsoft\WindowsFirewall\StandardProfile\&quot;</span>
strDomainPath = <span style="color: #800000;">&quot;\Software\Policies\Microsoft\WindowsFirewall\DomainProfile\&quot;</span>
&nbsp;
<span style="color: #8D38C9; font-weight: bold;">If</span> keyExists(HKEY_CURRENT_USER,strKeyPath) <span style="color: #8D38C9; font-weight: bold;">Then</span>
  subkeys = GetSubkeys(HKEY_CURRENT_USER,strKeyPath)
  <span style="color: #8D38C9; font-weight: bold;">If</span> <span style="color: #8D38C9; font-weight: bold;">Not</span> IsEmpty(subkeys) <span style="color: #8D38C9; font-weight: bold;">Then</span>
    GPOMachine = subkeys(<span style="color: #151B8D; font-weight: bold;">LBound</span>(subkeys)) 
    GPOUser    = subkeys(<span style="color: #151B8D; font-weight: bold;">UBound</span>(subkeys))
&nbsp;
    RegCopyTree HKEY_CURRENT_USER, strKeyPath &amp; GPOMachine &amp; strStandardPath, strKeyPath &amp; GPOMachine &amp; strDomainPath, <span style="color: #00C2FF; font-weight: bold;">False</span>
  <span style="color: #8D38C9; font-weight: bold;">Else</span>
    WScript.Echo <span style="color: #800000;">&quot;Policy not found, please try editing the policy manually&quot;</span>
  <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span>
<span style="color: #8D38C9; font-weight: bold;">Else</span>
  WScript.Echo <span style="color: #800000;">&quot;Please start editing the Group Policy before running this script&quot;</span>
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span></pre></div></div>

<p>The code here is the shell of the script. We need to flesh out the functions keyExists, GetSubkeys, RegCopyTree, and valueExists (which we can&#8217;t see just yet). So first we will have a look at keyExists:</p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;"><span style="color: #E56717; font-weight: bold;">Function</span> keyExists(Hive, Key)
  <span style="color: #151B8D; font-weight: bold;">On</span> <span style="color: #151B8D; font-weight: bold;">Error</span> <span style="color: #151B8D; font-weight: bold;">Resume</span> <span style="color: #8D38C9; font-weight: bold;">Next</span>
  Err.Clear
&nbsp;
  ret = objReg.EnumValues(Hive,Key,arrValues,arrValueTypes)
&nbsp;
  <span style="color: #8D38C9; font-weight: bold;">If</span> ret &lt;&gt; 0 <span style="color: #8D38C9; font-weight: bold;">Then</span>
    keyExists = <span style="color: #00C2FF; font-weight: bold;">False</span>
  <span style="color: #8D38C9; font-weight: bold;">Else</span>
    keyExists = <span style="color: #00C2FF; font-weight: bold;">True</span>
  <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span>
  Err.Clear
  <span style="color: #151B8D; font-weight: bold;">On</span> <span style="color: #151B8D; font-weight: bold;">Error</span> <span style="color: #8D38C9; font-weight: bold;">Goto</span> 0
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span></pre></div></div>

<p>Fairly straightforward, we try and enumerate the values of a key. If we succeed then the key does exist, otherwise it doesn&#8217;t. We will use the same principle for checking if a Value Exists.</p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;"><span style="color: #E56717; font-weight: bold;">Function</span> valueExists(Hive, Key, ValueName)
  <span style="color: #151B8D; font-weight: bold;">On</span> <span style="color: #151B8D; font-weight: bold;">Error</span> <span style="color: #151B8D; font-weight: bold;">Resume</span> <span style="color: #8D38C9; font-weight: bold;">Next</span>
  Err.Clear
&nbsp;
  valueExists = <span style="color: #00C2FF; font-weight: bold;">False</span>
  <span style="color: #8D38C9; font-weight: bold;">If</span> <span style="color: #8D38C9; font-weight: bold;">Not</span> keyExists(Hive, Key) <span style="color: #8D38C9; font-weight: bold;">Then</span>
    <span style="color: #E56717; font-weight: bold;">Exit</span> <span style="color: #E56717; font-weight: bold;">Function</span>
  <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span>
&nbsp;
  ret = objReg.EnumValues(Hive,Key,arrValues,arrValueTypes)
&nbsp;
  <span style="color: #8D38C9; font-weight: bold;">If</span> IsNull(arrValues) <span style="color: #8D38C9; font-weight: bold;">Then</span>
    <span style="color: #E56717; font-weight: bold;">Exit</span> <span style="color: #E56717; font-weight: bold;">Function</span>
  <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">IF</span>
&nbsp;
  <span style="color: #8D38C9; font-weight: bold;">For</span> i = <span style="color: #151B8D; font-weight: bold;">LBound</span>(arrValues) <span style="color: #8D38C9; font-weight: bold;">to</span> <span style="color: #151B8D; font-weight: bold;">UBound</span>(arrValues)
    <span style="color: #8D38C9; font-weight: bold;">If</span> LCase(CStr(arrValues(i))) = LCase(CStr(ValueName)) <span style="color: #8D38C9; font-weight: bold;">Then</span>
	  valueExists = <span style="color: #00C2FF; font-weight: bold;">True</span>
	  <span style="color: #E56717; font-weight: bold;">Exit</span> <span style="color: #E56717; font-weight: bold;">Function</span>
	<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span>
  <span style="color: #8D38C9; font-weight: bold;">Next</span>
&nbsp;
  valueExists = <span style="color: #00C2FF; font-weight: bold;">False</span>
&nbsp;
  Err.Clear
  <span style="color: #151B8D; font-weight: bold;">On</span> <span style="color: #151B8D; font-weight: bold;">Error</span> <span style="color: #8D38C9; font-weight: bold;">Goto</span> 0
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span></pre></div></div>

<p>Here, we take the Enumeration of the Keys Values a step further and actually step through them looking for a match with ValueName. I have opted for a Case Insensitive search due to registry being case insensitive with value names.</p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;"><span style="color: #E56717; font-weight: bold;">Function</span> GetSubkeys(Hive, Key)
  <span style="color: #151B8D; font-weight: bold;">On</span> <span style="color: #151B8D; font-weight: bold;">Error</span> <span style="color: #151B8D; font-weight: bold;">Resume</span> <span style="color: #8D38C9; font-weight: bold;">Next</span>
  Err.Clear
&nbsp;
  ret = objReg.EnumKey(Hive,Key,arrSubkeys)
&nbsp;
  GetSubkeys = arrSubkeys
&nbsp;
  Err.Clear
  <span style="color: #151B8D; font-weight: bold;">On</span> <span style="color: #151B8D; font-weight: bold;">Error</span> <span style="color: #8D38C9; font-weight: bold;">Goto</span> 0
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span></pre></div></div>

<p>Possibly the simplest of the functions, GetSubkeys just returns an array of Keys underneath the current Key. The most indepth function we require is the RegCopyTree:</p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;"><span style="color: #E56717; font-weight: bold;">Function</span> RegCopyTree(Hive, SrcKey, DestKey, Force)
  <span style="color: #151B8D; font-weight: bold;">On</span> <span style="color: #151B8D; font-weight: bold;">Error</span> <span style="color: #151B8D; font-weight: bold;">Resume</span> <span style="color: #8D38C9; font-weight: bold;">Next</span>
  Err.Clear
  strComputer = <span style="color: #800000;">&quot;.&quot;</span>
  <span style="color: #151B8D; font-weight: bold;">Set</span> StdOut = WScript.StdOut
  strValue = <span style="color: #800000;">&quot;&quot;</span>
  <span style="color: #8D38C9; font-weight: bold;">If</span> Force &lt;&gt; <span style="color: #00C2FF; font-weight: bold;">True</span> <span style="color: #8D38C9; font-weight: bold;">Then</span>
    Force = <span style="color: #00C2FF; font-weight: bold;">False</span>
  <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span>
&nbsp;
  <span style="color: #8D38C9; font-weight: bold;">if</span> Right(SrcKey,1) &lt;&gt; <span style="color: #800000;">&quot;\&quot;</span> <span style="color: #8D38C9; font-weight: bold;">Then</span> SrcKey = SrcKey &amp; <span style="color: #800000;">&quot;\&quot;</span>
  <span style="color: #8D38C9; font-weight: bold;">if</span> Right(DestKey,1) &lt;&gt; <span style="color: #800000;">&quot;\&quot;</span> <span style="color: #8D38C9; font-weight: bold;">Then</span> DestKey = DestKey &amp; <span style="color: #800000;">&quot;\&quot;</span>
&nbsp;
  ret = objReg.EnumValues(Hive,SrcKey,arrValueNames,arrValueTypes)
&nbsp;
  <span style="color: #8D38C9; font-weight: bold;">For</span> i= <span style="color: #151B8D; font-weight: bold;">LBound</span>(arrValueNames) <span style="color: #8D38C9; font-weight: bold;">To</span> <span style="color: #151B8D; font-weight: bold;">UBound</span>(arrValueNames)
    <span style="color: #008000;">'StdOut.WriteLine &quot;Value Name: &quot; &amp; arrValueNames(i) 
</span>	StdOut.WriteLine <span style="color: #800000;">&quot;Copying from: &quot;</span> &amp; SrcKey &amp; arrValueNames(i)
	StdOut.WriteLine <span style="color: #800000;">&quot;To          : &quot;</span> &amp; DestKey &amp; arrValueNames(i)
    StdOut.Write     <span style="color: #800000;">&quot;       Value: &quot;</span>
&nbsp;
	<span style="color: #8D38C9; font-weight: bold;">If</span> (<span style="color: #8D38C9; font-weight: bold;">Not</span> valueExists(Hive, DestKey, arrValueNames(i))) <span style="color: #8D38C9; font-weight: bold;">Or</span> Force <span style="color: #8D38C9; font-weight: bold;">Then</span>
	  <span style="color: #8D38C9; font-weight: bold;">Select</span> <span style="color: #8D38C9; font-weight: bold;">Case</span> arrValueTypes(i)
			<span style="color: #8D38C9; font-weight: bold;">Case</span> REG_SZ
				<span style="color: #008000;">'StdOut.WriteLine &quot;Data Type: String&quot;
</span>				<span style="color: #008000;">'StdOut.WriteBlankLines(1)
</span>				
				objReg.GetStringValue Hive, SrcKey, arrValueNames(i), strValue
				objReg.SetStringValue Hive, DestKey, arrValueNames(i), strValue
				StdOut.Write strValue
			<span style="color: #8D38C9; font-weight: bold;">Case</span> REG_EXPAND_SZ
				<span style="color: #008000;">'StdOut.WriteLine &quot;Data Type: Expanded String&quot;
</span>				<span style="color: #008000;">'StdOut.WriteBlankLines(1)
</span>				
				objReg.GetExpandedStringValue Hive, SrcKey, arrValueNames(i), strValue
				objReg.SetExpandedStringValue Hive, DestKey, arrValueNames(i), strValue
				StdOut.Write strValue
&nbsp;
			<span style="color: #8D38C9; font-weight: bold;">Case</span> REG_BINARY
				<span style="color: #008000;">'StdOut.WriteLine &quot;Data Type: Binary&quot;
</span>				<span style="color: #008000;">'StdOut.WriteBlankLines(1)
</span>				
				objReg.GetBinaryValue Hive, SrcKey, arrValueNames(i), strValue
				objReg.SetBinaryValue Hive, DestKey, arrValueNames(i), strValue
				<span style="color: #8D38C9; font-weight: bold;">For</span> <span style="color: #8D38C9; font-weight: bold;">Each</span> x <span style="color: #8D38C9; font-weight: bold;">in</span> strValue
		          StdOut.Write Hex(x) &amp; <span style="color: #800000;">&quot; &quot;</span>
		        <span style="color: #8D38C9; font-weight: bold;">Next</span>
&nbsp;
			<span style="color: #8D38C9; font-weight: bold;">Case</span> REG_DWORD
				<span style="color: #008000;">'StdOut.WriteLine &quot;Data Type: DWORD&quot;
</span>				<span style="color: #008000;">'StdOut.WriteBlankLines(1)
</span>				
				objReg.GetDWORDValue Hive, SrcKey, arrValueNames(i), strValue
				objReg.SetDWordValue Hive, DestKey, arrValueNames(i), strValue
&nbsp;
				StdOut.Write Hex(strValue)
			<span style="color: #8D38C9; font-weight: bold;">Case</span> REG_MULTI_SZ
				<span style="color: #008000;">'StdOut.WriteLine &quot;Data Type: Multi String&quot;
</span>				<span style="color: #008000;">'StdOut.WriteBlankLines(1)
</span>				
				objReg.GetMultiStringValue Hive, SrcKey, arrValueNames(i), strValue
				objReg.SetMultiStringValue Hive, DestKey, arrValueNames(i), strValue
				<span style="color: #8D38C9; font-weight: bold;">For</span> <span style="color: #8D38C9; font-weight: bold;">Each</span> x <span style="color: #8D38C9; font-weight: bold;">in</span> strValue
		          StdOut.Write x
		        <span style="color: #8D38C9; font-weight: bold;">Next</span>
		<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">Select</span> 
&nbsp;
		StdOut.WriteLine <span style="color: #800000;">&quot;&quot;</span>
    <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span> <span style="color: #008000;">'' Force
</span>  <span style="color: #8D38C9; font-weight: bold;">Next</span>
&nbsp;
  ret = objReg.EnumKey(Hive,SrcKey,arrSubkeys)
&nbsp;
  <span style="color: #8D38C9; font-weight: bold;">For</span> i = <span style="color: #151B8D; font-weight: bold;">LBound</span>(arrSubkeys) <span style="color: #8D38C9; font-weight: bold;">to</span> <span style="color: #151B8D; font-weight: bold;">UBound</span>(arrSubkeys)
    <span style="color: #8D38C9; font-weight: bold;">If</span> <span style="color: #8D38C9; font-weight: bold;">Not</span> keyExists(Hive,DestKey &amp; arrSubkeys(i)) <span style="color: #8D38C9; font-weight: bold;">Then</span>
	  objReg.CreateKey Hive,DestKey &amp; arrSubkeys(i)
	<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span>
	RegCopyTree Hive, SrcKey &amp; arrSubkeys(i), DestKey &amp; arrSubkeys(i), Force
  <span style="color: #8D38C9; font-weight: bold;">Next</span>
&nbsp;
  <span style="color: #151B8D; font-weight: bold;">On</span> <span style="color: #151B8D; font-weight: bold;">Error</span> <span style="color: #8D38C9; font-weight: bold;">Goto</span> 0
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span></pre></div></div>

<p>This function takes the Hive, Source Key, Destination Key, and a Boolean Value to determine whether to Force overwriting existing values. It first creates the Destination key if it doesn&#8217;t already exist, then enumerates all values in the Source path, and writes them to the Destination path, creating new values or overwriting only if Force is set. This function has a lot of StdOut.Write calls to show the progress of the duplication. Running the script via CScript gives the following results:</p>
<pre>Copying from: Software\Microsoft\Windows\CurrentVersion\Group Policy Objects\{678C8897-54AA-4FB9-AA72-6C227C287D12}Machine\Software\Policies\Microsoft\WindowsFirewall\StandardProfile\EnableFirewall
To          : Software\Microsoft\Windows\CurrentVersion\Group Policy Objects\{678C8897-54AA-4FB9-AA72-6C227C287D12}Machine\Software\Policies\Microsoft\WindowsFirewall\DomainProfile\EnableFirewall
       Value: 1
Copying from: Software\Microsoft\Windows\CurrentVersion\Group Policy Objects\{678C8897-54AA-4FB9-AA72-6C227C287D12}Machine\Software\Policies\Microsoft\WindowsFirewall\StandardProfile\AuthorizedApplications\Enabled
To          : Software\Microsoft\Windows\CurrentVersion\Group Policy Objects\{678C8897-54AA-4FB9-AA72-6C227C287D12}Machine\Software\Policies\Microsoft\WindowsFirewall\DomainProfile\AuthorizedApplications\Enabled
       Value: 1
...</pre>
<p>This should simplify the time taken for duplicating from Standard to Domain profile. For future reference this has also made it far easier to import/export port/program exceptions from policies I am editing. In future I may incorporate this into my Group Policy Firewall Exceptions Excel Spreadsheet in VBA to allow writing updated policies to the Policy.</p>
<p>After running this the settings will be seen to have changed in the Group Policy Editor Window immediately. I have tested this and checked that the Logging file is not replaced by &#8220;&#8230;\standard.log&#8221; where it should be &#8220;&#8230;\domain.log&#8221;.</p>
<p>Cheers, Chris.</p>
<p>Attached: <a href='http://www.dwarfsoft.com/blog/wp-content/uploads/2010/06/RegFirewallProfileDuplication.vbs_.txt'>RegFirewallProfileDuplication.vbs</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.dwarfsoft.com/blog/2010/06/15/group-policy-editing-findings/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

