/3.2 (Extension.1 Name: "Simple random sampling (1.0)" FirstRootClassName: "List" Roots: 2 Roots: 3 Roots: 4 Roots: 12 Roots: 13 Roots: 14 Roots: 15 Roots: 16 Version: 32 About: "This extension adds an item to the View|Themes menu for creating simple random samples (points) for features in polygon themes. (c) 1999-2000 QD." InstallScript: 17 UninstallScript: 18 ExtVersion: 1 ) (List.2 ) (List.3 ) (List.4 Child: 5 ) (List.5 Child: 6 Child: 10 Child: 11 ) (List.6 Child: 7 Child: 8 Child: 9 ) (AVStr.7 S: "View" ) (AVStr.8 S: "Theme" ) (AVStr.9 S: "View.Sample" ) (Choice.10 Disabled: 1 Help: "Sample themes//Produce a simple random (point) sample of each selected theme. Output is a new point theme for each active polygon theme." Update: "View.Sample.Update" Label: "Sample.." Click: "View.Sample" Shortcut: "Keys.None" ) (Numb.11 N: 6.00000000000000 ) (List.12 ) (Script.13 Name: "Theme.Sample" SourceCode: "' Name: Theme.Sample\n'\n' Headline: Convert a poly theme into a point theme\n'\n' Self: {\n' Theme: Theme to process\n' N: Sample size\n' thePrj: A projection\n' bIntensity: True for intensity sampling\n' }\n'\n' Called by: View.Sample\n'\n' Returns: NIL upon failure or user cancellation;\n' The new theme upon success\n'\n' Description: Constructs a simple random sample of selected features of\n' the input theme. A new\n' theme is created to hold the output\n'\n' Topics: Themes; conversion, sampling, sample, simple, random\n'\n' Search Keys:\n'\n' Requires: Script \"Polygon.Sample\"\n'\n' History: \n' 10 Jul 00: AV 3.2\n'\n' Author: William A. Huber, whuber@quantdec.com\n'\n' Comments: \n'============================================================================='\nif (SELF = NIL) then\n theView = av.GetProject.FindDoc(\"View1 \")\n theTheme = theView.FindTheme(\"States.shp\")\n N = 2\n thePrj = theView.GetProjection\n bIntensity = false\nelse\n theTheme = SELF.Get(0)\n N = SELF.Get(1)\n thePrj = SELF.Get(2)\n bIntensity = SELF.Get(3)\nend\n'============================================================================='\nsTitle = \"Theme.Sample (\" + theTheme.GetName + \")\"\ntheProject = av.GetProject\nfnWorkDir = theProject.GetWorkDir\n'============================================================================='\n'\n' Specify the out put shapefile.\n'\nfnDefault = fnWorkDir.MakeTmp(\"theme\",\"shp\")\nfnOutput = FileDialog.Put(fnDefault,\"*.shp\", sTitle + \"--Output Shapefile\")\nif (fnOutput = Nil) then return NIL end\nfnOutput.SetExtension(\"shp\")\n'============================================================================='\n'\n' Create an appropriate FTab.\n'\nftbOut = FTab.MakeNew(fnOutput, Point)\nif (ftbOut = NIL) then\n MsgBox.Error(\"Unable to create an output shape file\", sTitle)\n return NIL\nend\n'============================================= ================================'\n'\n' Add a field to uniquely identify each point.\n'\nfldPtId = Field.Make(\"Id\", #FIELD_DECIMAL, 8, 0)\nfldPtId.SetAlias(\"Point #\")\nftbOut.AddFields({fldPtId})\n'============================================================================='\n'\n' Find the shape fields; these are processed specially.\n'\nftbIn = theTheme.GetFTab\nfldShapeIn = ftbIn.FindField(\"Shape\")\nfldShapeOut = ftbOut.FindField(\"Shape\")\n'=============================================================================' \n'\n' If there are no selected features, convert all,\n' otherwise just convert the selected features.\n'\nif (ftbIn.GetSelection.Count = 0) then\n theRecordsToSample = ftbIn\n nRecs = ftbIn.GetNumrecords\nelse\n theRecordsToSample = ftbIn.GetSelection\n nRecs = theRecordsToSample.Count\nend\n'============================================================================='\n'\n' Compute areas.\n'\nlAreas = {}\nxTotalArea = 0\nav.ShowMsg(\"Reading\" ++ theTheme.GetName ++ \"...\")\nav.ShowStopButton\nav.SetStatus(0)\ni = 0\nfor ea ch r in theRecordsToSample\n i = i+100\n if (av.SetStatus(i/nRecs).Not) then\n MsgBox.Info(\"Reading halted.\", sTitle)\n return NIL\n end\n \n plyIn = ftbIn.ReturnValue(fldShapeIn, r) ' A poly\n \n if (thePrj.IsNull.Not) then\n plyIn = plyIn.ReturnProjected(thePrj)\n end\n x = plyIn.ReturnArea\n xTotalArea = xTotalArea + x\n lAreas.Add(x)\nend\n\nif (xTotalArea = 0) then\n MsgBox.Error(\"The total area to sample evaluates to zero; sampling halted.\",\n sTitle)\n return NIL\nend\n'========================= ===================================================='\n'\n' Compute sample sizes.\n'\nnScale = 1000000000\nlnSize = {} ' Sample sizes\n\nif (bIntensity) then\n nRemaining = N ' Number of samples left\n xAreaRemaining = xTotalArea ' Area left\n for each x in lAreas\n '\n ' Compute the sample size for the current polygon.\n '\n i = (x * nRemaining)/xAreaRemaining ' Expected sample size\n iFraction = i - i.Floor\n nRandom = Number.MakeRandom(0, nScale)\n if (nRandom / nSc ale < iFraction) then\n i = i.Ceiling\n else\n i = i.Floor\n end\n lnSize.Add(i)\n nRemaining = nRemaining - i\n xAreaRemaining = xAreaRemaining - x\n end\n \nelse\n '\n ' Generate N URNs\n '\n lURN = {}\n for each i in 1..N\n lURN.Add(Number.MakeRandom(0, nScale))\n end\n lURN.Add(nScale * 2) ' Sentinel\n '\n ' Use these to allocate samples among the regions.\n '\n lURN.Sort(true) ' Sort ascending\n i = 0\n xPartialArea = 0\n for each x in lAreas\n xThreshold = (x + xPartialArea) * n Scale / xTotalArea\n k = 0\n while (lURN.Get(i) <= xThreshold)\n k = k+1\n i = i+1\n end\n lnSize.Add(k)\n xPartialArea = xPartialArea + x\n end\n lURN = NIL\nend\nlAreas = NIL\n'============================================================================='\n'\n' Perform the sampling.\n'\nav.ShowMsg(\"Sampling\" ++ theTheme.GetName ++ \"...\")\nav.ShowStopButton\nav.SetStatus(0)\ni = -1 ' Indexes lnSize\nnId = 0\nsWarning = \"\"\nfor each r in theRecordsToSample\n i = i+1\n nSampleSize = lnSize.Ge t(i)\n if (av.SetStatus(i*100/nRecs).Not) then\n MsgBox.Info(\"Sampling stopped. Only samples already created will be saved.\", sTitle)\n break\n end\n \n plyIn = ftbIn.ReturnValue(fldShapeIn, r) ' A poly\n if (thePrj.IsNull.Not) then\n plyIn = plyIn.ReturnProjected(thePrj)\n end\n '\n ' Obtain nSampleSize independent samples of plyIn.\n '\n lPts = av.Run(\"Polygon.Sample\", {plyIn, nSampleSize})\n if (lPts = NIL) then\n sWarning = sWarning + NL + \n \"Unable to sample the polygon at record\" ++ i. AsString \n continue\n end\n '\n ' Unproject them if necessary.\n '\n if (thePrj.IsNull.Not) then\n lPtUnproj = {}\n for each thePt in lPts\n lPtUnproj.Add(thePt.ReturnUnprojected(thePrj))\n end\n lpts = lPtUnproj\n end\n '\n ' Write the sample points and assign them consecutive ids.\n '\n for each ptSample in lPts\n rOut = ftbOut.AddRecord\n ftbOut.SetValue(fldShapeOut, rOut, ptSample)\n ftbOut.SetValue(fldPtId, rOut, nId)\n nId = nId + 1\n end \nend ' processing input features\nav.Set Status(100)\n\nif (sWarning <> \"\") then\n sWarning = \"Warnings (polygons too skinny):\" + sWarning\n system.Beep\n MsgBox.Report(sWarning, sTitle)\nend\n\nftbOut.Flush\nftbOut.Refresh\n'============================================================================='\n'\n' Create a theme to return to caller.\n'\nthmOut = FTheme.Make(ftbOut)\nreturn thmOut\n' End of script\n" ) (Script.14 Name: "Polygon.Sample" SourceCode: "' Name: Polygon.Sample\n'\n' Headline: Convert a polygon into points.\n'\n' Self: {\n' thePoly: Theme to process\n' N: Sample size\n' }\n'\n' Called by: Theme.Sample\n'\n' Returns: List of points\n'\n' Description: Constructs a simple random sample of the polygon.\n'\n' Topics: Polygon, sampling, sample, simple, random\n'\n' Search Keys:\n'\n' Requires: \n'\n' History: \n' 10 Jul 00: AV 3.2\n'\n' Author: William A . Huber, whuber@quantdec.com\n'\n' Comments: This script will return NIL whenever the polygon occupies too\n' little of its extent. The cutoff (for the proportion of area\n' occupied by the polygon) is xDensityThreshold. A good value \n' is between 1/5 and 1/100.\n'\n' The resolution of sampling is established by nScale, which\n' must be 1 or greater and is best set at a very large value\n' less than 2^30.\n'=========================== =================================================='\nthePoly = SELF.Get(0)\nN = SELF.Get(1)\nxDensityThreshold = 1/100\nnScale = 1000000000\n'\n' Determine whether this polygon can be efficiently sampled. \n' If not, return NIL.\n'\nrctBB = thePoly.ReturnExtent\nxDensity = (thePoly.ReturnArea) / (rctBB.ReturnArea)\nif (xDensity < xDensityThreshold and (N > 0)) then\n return NIL\nend\n'\n' Compute the values needed to sample the polygon's extent.\n'\nxWidth = rctBB.GetWidth / nScale\nyHeight = rctBB.GetHeight / nScale\nx0 = r ctBB.GetLeft\ny0 = rctBB.GetBottom\n'\n' Sample the polygon.\n' \n' (The business with nScale+2 and the \"-1\" terms is to move the low-frequency\n' values returned by MakeRandom outside the polygon's extent, so that \n' sampling is truly uniform. This will really matter only if nScale is about \n' 1000000 or less.)\n'\nlPts = {}\nnScale = nScale + 2\nwhile (lPts.Count < N)\n x = (Number.MakeRandom(0, nScale)-1) * xWidth + x0\n y = (Number.MakeRandom(0, nScale)-1) * yHeight + y0\n if (thePoly.Contains(x@y)) then\n lPt s.Add(x@y)\n end\nend\n\nreturn lPts\n' end of script\n " ) (Script.15 Name: "View.Sample.Update" SourceCode: "theView = av.GetActiveDoc\n\nisEnabled = false\ntheThemes = theView.GetActiveThemes\nif (theThemes <> NIL) then\n for each theTheme in theThemes\n if (theTheme.Is(FTheme)) then\n theFTab = theTheme.GetFTab\n theShapeName = theFTab.GetShapeClass.GetClassName\n if ((theShapeName = \"Polygon\")) then\n isEnabled = true\n break\n end\n end\n end\nend\nSELF.SetEnabled(isEnabled)\n' end of script" ) (Script.16 Name: "View.Sample" SourceCode: "' Name: View.Sample\n'\n' Headline: Convert polygon themes into point themes\n'\n' Self: NIL\n'\n' Called by: --\n'\n' Returns: --\n'\n' Description: Converts each selected polygon of the input themes into a \n' collection of points using a simple random sample. New\n' themes are created to hold the output.\n'\n' Topics: Themes; conversion, sample, sampling, random, simple\n'\n' Search Keys:\n'\n' Requires: Theme.PolyToPointByInterval\n'\n' History: \n' 10 July 2000: AV 3.2\n' 10 July 2000: Modified from \"Poly themes to point\".\n' 8/3/99: Interval of 0 is used to convert to vertices.\n' 1/26/99: Reports the units in the theme name.\n' Works in projected units.\n' AV 3.0a, 11/20/97, by WAH\n'\n' Comments: Just a driver for Theme.Sample.\n' To transfer attributes to the points, spatially join the\n' polygon theme to the output point theme.\n'============= ================================================================'\nsTitle = \"Simple Random Sample\"\ntheView = av.GetActiveDoc \n'============================================================================='\n'\n' Ask for sampling strategy.\n'\nwhile (true) ' Loop while user needs help\n lsOptions = {\"by number\", \"by intensity\", \"Help\"}\n sOption = MsgBox.ListAsString(lsOptions, \"Select a sampling strategy:\", sTitle)\n if (sOption = NIL) then return NIL end ' User cancellation\n if (sOption <> \"Help\") then brea k end\n \n sMsg = \"You may create a simple random sample of all selected polygons\" ++\n \"(or of all polygons, if none are selected) in two ways: by number\" ++\n \"and by intensity.\" + NL + NL +\n \"When sampling by number, the entire sampling region will be sampled\" ++\n \"the number of times you specify. However, the distribution of those samples throughout\" ++\n \"the polygons will be random--the number of samples within each polygon\" ++\n \"is not guaranteed to be ex actly proportional to the polygon's area.\" + NL + NL +\n \"When sampling by intensity, the\" ++\n \"samples will be allocated by polygon areas. (Fractional\" ++\n \"numbers of samples will be allocated randomly so that the *expected*\" ++\n \"sample size for each polygon will be exactly proportional to its\" ++\n \"relative area.)\"\n MsgBox.Report(sMsg, sTitle)\nend\nbIntensity = (sOption = \"by intensity\")\n'============================================================================ ='\n' \n' Create a list of active poly themes.\n' \nlThemes = theView.GetActiveThemes\n\nlPolyThemes = {}\nfor each theTheme in lThemes\n if (theTheme.Is(FTheme)) then\n theFTab = theTheme.GetFTab\n theClassName = theFTab.GetShapeClass.GetClassName\n if (theClassName.Left(7) = \"Polygon\") then\n lPolyThemes.Add(theTheme)\n end\n end\nend\n\nif (lPolyThemes.Count < 1) then\n MsgBox.Error(\"No polygon themes are available for sampling.\", sTitle)\n return NIL\nend\n'=================================== =========================================='\n'\n' Ask for the destination view.\n'\nlViews = {}\nfor each d in av.GetProject.GetDocs\n if (d.Is(View)) then\n lViews.Add( d )\n end\nend\n\nif (lViews.Count > 1) then\n vueDest = MsgBox.ListAsString(lViews, \"Select the destination view:\", sTitle)\nelse\n vueDest = lViews.Get(0)\nend\nif (vueDest = NIL) then return NIL end\n'============================================================================='\n'\n' Do the work.\n'\ntheArgs = {NIL, NIL, theView.GetProjection, bInten sity} ' Theme, sample size, projection, sampling type\ni = lPolyThemes.Count\nneedsRefreshing = false\nx = 30 ' A starting value\nwhile (i > 0) ' Process from bottom to top, so results are added to destination in the correct order\n i = i-1 \n theTheme = lPolyThemes.Get(i)\n '\n ' Ask for the number of points.\n ' If user cancels, stop the script. If user provides invalid input,\n ' just skip this theme.\n '\n strX = MsgBox.Input( \"How many points for [\" + theTheme.Getname + \"]?\", \n sTitle, x.AsString)\n i f (strX = NIL) then break end\n if ((strX.IsNumber.Not) or (strX.AsNumber <= 0)) then\n system.Beep\n continue\n end\n x = strX.AsNumber\n \n theArgs.Set(0, theTheme)\n theArgs.Set(1, x)\n theNewTheme = av.run(\"Theme.Sample\", theArgs)\n if (theNewTheme = NIL) then continue end\n '\n ' Make new theme attributes match the old ones.\n '\n theNewTheme.GetFTab.SetEditable(theTheme.GetFTab.IsEditable)\n theNewTheme.SetName(\"Sample of\" ++ theTheme.GetName)\n theNewTheme.SetPassword(theTheme.GetPassword)\n theN ewTheme.SetLocked(theTheme.IsLocked)\n theNewTheme.SetSuffixUsed(theTheme.IsSuffixUsed)\n theNewTheme.SetLegendVisible(theTheme.IsLegendVisible)\n theNewTheme.SetVisible(theTheme.IsVisible)\n if (theTheme.GetComments.Trim = \"\") then\n s = \"\"\n else\n s = theTheme.GetComments + NL\n end\n theNewTheme.SetComments(s + \"Sampled\" ++ sOption ++ \"from\" ++ theTheme.GetName ++ \n \"on\" ++ Date.Now.AsString ++ \"by\" ++ sTitle)\n theNewTheme.SetAOI(theTheme.ReturnAOI)\n theNewTheme.Invalidate( true)\n \n vueDest.AddTheme(theNewTheme)\n needsRefreshing = true\nend ' Processing active point themes\n\nif (needsRefreshing) then\n vueDest.GetWin.Invalidate\n vueDest.GetWin.Close\n vueDest.GetWin.Open\nend\n' End of script \n" ) (Script.17 Name: "My Extension Install" SourceCode: "'DO NOT EDIT!!!\n\nif (av.getproject=nil) then return(nil) end\n\n\ntheDocs = SELF.get(0)\ntheControlList = SELF.get(1)\ntheMenuList = SELF.get(2)\ntheToolMenuList=SELF.Get(3)\ntheProject=Av.getproject\n\n\n'Add the Docs\n'\nfor each adoc in theDocs\n theProject.addDoc(adoc)\nend\n\n'Add the Controls\n'\nfor each totalControl in theControlList\n 'The Control list\n acontrol=totalControl.get(0)\n \n 'The physical control\n theControl = totalControl.get(1)\n \n 'The control Index\n theCindex=totalControl.get(2)\n\n 'Find the DocGUI\n theControlDoc=av.getproject.findGUI(aControl.get(0))\n if (theControlDoc=NIL) then \n MsgBox.Warning(\"The GUI \"+aControl.get(0)+\" cannot be found in the current project.\",\"Script Eror\")\n return(nil)\n end\n \n 'This finds the control set \n thecommand=\"av.getproject.findGUI(\"\"\"+aControl.get(0)+\"\"\").Get\"+acontrol.get(1)\n thescript1=Script.Make(thecommand)\n thecontrolset=thescript1.doit(\"\")\n \n 'Add the control to the control set\n theControlSet.Add(theControl,theCindex -1)\nend\n\n\n'Add the menus\nfor each totalcontrol in theMenuList\n \n 'The Control list\n acontrol=totalControl.get(0)\n mDoc=acontrol.get(0)\n mMenu=acontrol.get(1)\n mMenuItem=acontrol.get(2)\n\n 'The physical control\n theControl = totalControl.get(1)\n \n 'The control Index\n theCindex=totalControl.get(2)\n\n 'Find the DocGUI\n theControlDoc=av.getproject.findGUI(aControl.get(0))\n if (theControlDoc=NIL) then \n MsgBox.Warning(\"The GUI \"+aControl.get(0)+\" cannot be found in the current project.\",\"Script Eror\")\n return(nil)\n end\n \n theMbar=av.getproject.findGUI(mDoc).GetMenuBar\n themenu=theMbar.findbylabel(mMenu)\n if (themenu=NiL) then\n themenu=menu.make\n themenu.setlabel(mMenu)\n theMbar.add(themenu,999)\n end\n \n themenu.add(thecontrol, theCindex)\nend\n \n \n'Add the Tool Menus\n\nfor each totalControl in theToolMenuList\n 'The Control list\n acontrol=totalControl.get(0)\n \n 'The physical control\n theControl = totalControl.get(1)\n \n 'The c ontrol Index\n theCindex=totalControl.get(2)\n\n 'Find the DocGUI\n theControlDoc=av.getproject.findGUI(aControl.get(0))\n if (theControlDoc=NIL) then \n MsgBox.Warning(\"The GUI \"+aControl.get(0)+\" cannot be found in the current project.\",\"Script Eror\")\n return(nil)\n end\n \n 'This finds the control set \n thecommand=\"av.getproject.findGUI(\"\"\"+aControl.get(0)+\"\"\").Get\"+acontrol.get(1)\n thescript1=Script.Make(thecommand)\n thecontrolset=av.getproject.findGUI(aControl.get(0)).GetTool Bar\n \n 'Add the control to the control set\n theControlSet.Add(theControl,theCindex)\nend\n\n\nMsgBox.Info(\"Simple Random Sample by Quantitative Decisions.\" + NL +\n \"(c) 1996-2000. All rights reserved.\" + NL + NL +\n \"Browse http://www.quantdec.com for a grid-sampling extension for AV 3.x.\", \"\")\n \nav.getproject.setmodified(true)\n\n\n'And the scripts add themselves\n" ) (Script.18 Name: "My Extension Uninstall" SourceCode: "'DO NOT EDIT!!!\n\n'The SELF is the Extension\n\ntheDocs = SELF.get(0)\ntheControlList = SELF.get(1)\ntheMenuList = SELF.get(2)\ntheToolMenuList=SELF.get(3)\ntheProject=Av.getproject\n\n\n'Add the Docs\n'\nfor each adoc in theDocs\n If (theProject.finddoc(adoc.getname)<>NIL) then \n theAnswer=msgbox.yesno(\"Remove the Document \"+adoc.getname+\"?\",\"Remove Document?\",TRUE)\n if (theAnswer=TRUE) then theProject.RemoveDoc(adoc) end\n end\nend\n\n'Removethe Controls\n'\nfor each totalControl in theControlList\n 'Get the control list from the Ext\n acontrol=totalControl.get(0)\n \n 'Get the physical Control\n theControl = totalControl.get(1)\n \n 'Get the Controls Index\n theCindex=totalControl.get(2)\n\n 'Find the DocGUI for the Control\n theControlDoc=av.getproject.findGUI(aControl.get(0))\n if (theControlDoc=NIL) then \n MsgBox.Warning(\"The GUI \"+aControl.get(0)+\" cannot be found in the current project.\",\"Script Eror\")\n return(nil)\n end\n \n 'This sequence finds the appropiate control set\n thecommand= \"av.getproject.findGUI(\"\"\"+aControl.get(0)+\"\"\").Get\"+acontrol.get(1)\n thescript1=Script.Make(thecommand)\n thecontrolset=thescript1.doit(\"\")\n\n 'See if the control is in the set , if so remove it\n if (theControlSet.GetControls.find(theControl)<>NIL) then\n theControlSet.remove(theControl)\n if (thecontrol = \"ToolBar\") then\n theControlSet.selectdefault\n end\n end\nend\n\n\n'Remove the Menus\n'\nfor each totalcontrol in theMenuList\n \n 'The Control list\n acontrol=totalControl.get(0 )\n mDoc=acontrol.get(0)\n mMenu=acontrol.get(1)\n mMenuItem=acontrol.get(2)\n\n 'The physical control\n theControl = totalControl.get(1)\n \n 'The control Index\n theCindex=totalControl.get(2)\n\n 'Find the DocGUI\n theControlDoc=av.getproject.findGUI(aControl.get(0))\n if (theControlDoc=NIL) then \n MsgBox.Warning(\"The GUI \"+aControl.get(0)+\" cannot be found in the current project.\",\"Script Eror\")\n return(nil)\n end\n \n theMbar=av.getproject.findGUI(mDoc).GetMenuBar\n themenu=theMbar.findbylabel(mMenu)\n if (themenu=NiL) then\n MsgBox.Warning(\"The menu named \"+mMenu+\" is not here.\",\"Script Eror\")\n 'return(nil)\n else\n \n thething=themenu.getcontrols.find(thecontrol)\n if (thething<>NIL) then \n themenu.remove(thecontrol) \n end\n 'msgbox.info(themenu.GetControls.count.asstring,\"\")\n if (themenu.GetControls.count<1) then\n theMbar.remove(themenu)\n end\n end\nend\n \nfor each totalControl in theToolMenuList\n 'Get the control list from the Ext\n acontrol=totalControl.get(0)\n \n 'Get the physical Control\n theControl = totalControl.get(1)\n \n 'Get the Controls Index\n theCindex=totalControl.get(2)\n\n 'Find the DocGUI for the Control\n theControlDoc=av.getproject.findGUI(aControl.get(0))\n if (theControlDoc=NIL) then \n MsgBox.Warning(\"The GUI \"+aControl.get(0)+\" cannot be found in the current project.\",\"Script Eror\")\n return(nil)\n end\n \n 'This sequence finds the appropiate control set\n thecontrolset=av.getp roject.findGUI(aControl.get(0)).GetToolBar\n\n \n 'See if the control is in the set , if so remove it\n if (theControlSet.GetControls.find(theControl)<>NIL) then\n \n theControlSet.remove(theControl)\n theControlSet.selectdefault\n end\n\nend\n \n\n'And the scripts delete themselves\n\n\nav.getproject.setmodified(true)\n" )