source: sans/Dev/trunk/NCNR_User_Procedures/Common/Packages/PlotManager/PlotUtilsMacro_v40.ipf @ 662

Last change on this file since 662 was 662, checked in by srkline, 13 years ago

Modified installer to copy folders, rather than move them. This allows the installer to be re-run without downloading or unzipping a fresh copy.

Added a "refresh" button to the PlotManager?. Streamlined the filtering out of non-plottable data.

Made XML the default (set the global to 1 in Wrapper, Initialize, and Main_USANS).

File size: 37.0 KB
Line 
1#pragma rtGlobals=1             // Use modern global access method.
2#pragma version=4.00
3#pragma IgorVersion=6.1
4
5// This is to be used with the Analysis packages ONLY
6// there are a number of utility procedures here for loading
7// data and generating valid lists of data files that are
8// directly copied from the Reduction package
9// -- There WILL be name conflicts if you mix the two...
10//
11// 16 DEC 05 SRK
12// prepended function names with A_ to tag them for the
13// "A"nalysis parckage, though nearly all are duplicate procedures
14// so there will be no overlap with the reduction package
15//
16//
17// these extra procedures are used by:
18// Linearized fits (duplicated in Reduction - will need to handle gently)
19// Invariant (no overlap with reduction)
20//
21// SRK MAR 2005
22
23// create a KW=string; of model=coef correspondence as the models are plotted, rather than
24// some other hard-wired solution
25Function AddModelToStrings(funcStr,coefStr,paramStr,suffix)
26        String funcStr,coefStr,paramStr,suffix
27       
28        if(exists("root:Packages:NIST:paramKWStr")==0)
29//              String/G root:Packages:NIST:coefKWStr=""
30                String/G root:Packages:NIST:paramKWStr=""
31//              String/G root:Packages:NIST:suffixKWStr=""
32        endif
33        SVAR coefKWStr = root:Packages:NIST:coefKWStr
34        SVAR paramKWStr = root:Packages:NIST:paramKWStr
35        SVAR suffixKWStr = root:Packages:NIST:suffixKWStr
36        coefKWStr += funcStr+"="+coefStr+";"
37        paramKWStr += funcStr+"="+paramStr+";"
38        suffixKWStr += funcStr+"="+suffix+";"
39end
40
41// loads a 1-d (ascii) datafile and plots the data
42// will overwrite existing data if user is OK with this
43// - multiple datasets can be automatically plotted on the same graph
44//
45//substantially easier to write this as a Proc rather than a function...
46
47//
48Proc A_LoadOneDData()
49        A_LoadOneDDataWithName("",1)            //will prompt for file and plot data
50End
51
52// load the data specified by fileStr (a full path:name)
53// and plots if doPlot==1
54// if fileStr is null, a dialog is presented to select the file
55//
56// 3 cases (if)
57// - 3 columns = QIS, no resolution
58// - 6 columns = QSIG, SANS w/resolution
59// - 5 columns = old-style desmeared USANS data (from VAX)
60//
61// This loader replaces the A_LoadOneDData() which was almost completely duplicated code
62//
63//new version, 19JUN07 that loads each data set into a separate data folder
64// the data folder is given the "base name" of the data file as it's loaded
65//
66
67Proc A_LoadOneDDataWithName(fileStr,doPlot)
68        String fileStr
69        Variable doPlot
70       
71        A_LoadOneDDataToName(fileStr,"",doPlot,0)
72
73End
74
75
76///Function that takes output name as well as input
77Proc A_LoadOneDDataToName(fileStr,outStr,doPlot,forceOverwrite)
78        String fileStr, outstr
79        Variable doPlot,forceOverwrite
80       
81        Variable rr,gg,bb,refnum,dQv
82        String w0,w1,w2,n0,n1,n2
83        String w3,w4,w5,n3,n4,n5                        //3 extra waves to load
84        SetDataFolder root:             //build sub-folders for each data set under root
85
86// I can't see that we need to find dQv here.   
87//      if (exists("root:Packages:NIST:USANS:Globals:MainPanel:gDQv"))
88//              //Running from USANS reduction
89//              Variable dQv = root:Packages:NIST:USANS:Globals:MainPanel:gDQv
90//      endif
91//      if(exists("root:Packages:NIST:USANS_dQv"))
92//              //Running from SANS Analysis
93//              Variable dQv = root:Packages:NIST:USANS_dQv
94//      else
95//              //running from somewhere else, probably SANS Reduction, which uses common loaders
96//              Variable/G root:Packages:NIST:USANS_dQv = 0.117
97//      endif
98               
99        // if no fileStr passed in, display dialog now
100        if (cmpStr(fileStr,"") == 0)
101                fileStr = DoOpenFileDialog("Select a data file to load")
102                if (cmpstr(fileStr,"") == 0)
103                        return          //get out if no file selected
104                endif
105        endif
106
107        if (isXML(fileStr) == 1)
108                LoadNISTXMLData(fileStr,outstr,doPlot,forceOverwrite)
109        else           
110                //Load the waves, using default waveX names
111                //if no path or file is specified for LoadWave, the default Mac open dialog will appear
112                LoadWave/G/D/A/Q fileStr
113                String fileNamePath = S_Path+S_fileName
114//              String basestr = ParseFilePath(3,ParseFilePath(5,fileNamePath,":",0,0),":",0,0)
115
116                String basestr
117                if (!cmpstr(outstr, ""))                //Outstr = "", cmpstr returns 0
118//                      enforce a short enough name here to keep Igor objects < 31 chars
119                        baseStr = ShortFileNameString(CleanupName(S_fileName,0))
120                        baseStr = CleanupName(baseStr,0)                //in case the user added odd characters
121                        //baseStr = CleanupName(S_fileName,0)
122                else
123                        baseStr = outstr                        //for output, hopefully correct length as passed in
124                endif
125       
126//              print "basestr :"+basestr
127                String fileName =  ParseFilePath(0,ParseFilePath(5,filestr,":",0,0),":",1,0)
128//              print "filename :"+filename
129                Variable numCols = V_flag
130               
131                //changes JIL to allow 2-column data to be read in, "faking" a 3rd column of errors
132                if(numCols==2) //no errors
133                        n1 = StringFromList(1, S_waveNames ,";" )
134                        Duplicate/O $("root:"+n1), errorTmp
135                        errorTmp = 0.01*(errorTmp)+ 0.03*sqrt(errorTmp)
136                        S_waveNames+="errorTmp;"
137                        numCols=3
138                endif
139               
140                if(numCols==3)          //simple 3-column data with no resolution information
141                       
142                        // put the names of the three loaded waves into local names
143                        n0 = StringFromList(0, S_waveNames ,";" )
144                        n1 = StringFromList(1, S_waveNames ,";" )
145                        n2 = StringFromList(2, S_waveNames ,";" )
146                       
147                        //remove the semicolon AND period from files from the VAX
148                        w0 = CleanupName((basestr + "_q"),0)
149                        w1 = CleanupName((basestr + "_i"),0)
150                        w2 = CleanupName((basestr + "_s"),0)
151                       
152                        //String baseStr=w1[0,strlen(w1)-3]
153                        if(DataFolderExists("root:"+baseStr))
154                                if (!forceOverwrite)
155                                        DoAlert 1,"The file "+S_filename+" has already been loaded. Do you want to load the new data file, overwriting the data in memory?"
156                                        if(V_flag==2)   //user selected No, don't load the data
157                                                SetDataFolder root:
158                                                KillWaves $n0,$n1,$n2           // kill the default waveX that were loaded
159                                                if(DataFolderExists("root:Packages:NIST"))
160                                                        String/G root:Packages:NIST:gLastFileName = filename
161                                                endif
162                                                return  //quits the macro
163                                        endif
164                                endif
165                                SetDataFolder $("root:"+baseStr)
166                        else
167                                NewDataFolder/S $("root:"+baseStr)
168                        endif
169
170                       
171                        ////overwrite the existing data, if it exists
172                        Duplicate/O $("root:"+n0), $w0
173                        Duplicate/O $("root:"+n1), $w1
174                        Duplicate/O $("root:"+n2), $w2
175       
176                        // no resolution matrix to make
177       
178                        SetScale d,0,0,"1/A",$w0
179                        SetScale d,0,0,"1/cm",$w1
180                       
181                endif           //3-col data
182               
183                if(numCols == 6)                //6-column SANS or USANS data that has resolution information
184                       
185                        // put the names of the (default named) loaded waves into local names
186                        n0 = StringFromList(0, S_waveNames ,";" )
187                        n1 = StringFromList(1, S_waveNames ,";" )
188                        n2 = StringFromList(2, S_waveNames ,";" )
189                        n3 = StringFromList(3, S_waveNames ,";" )
190                        n4 = StringFromList(4, S_waveNames ,";" )
191                        n5 = StringFromList(5, S_waveNames ,";" )
192                       
193                        //remove the semicolon AND period from files from the VAX
194                        w0 = CleanupName((basestr + "_q"),0)
195                        w1 = CleanupName((basestr + "_i"),0)
196                        w2 = CleanupName((basestr + "_s"),0)
197                        w3 = CleanupName((basestr + "sq"),0)
198                        w4 = CleanupName((basestr + "qb"),0)
199                        w5 = CleanupName((basestr + "fs"),0)
200                       
201                        //String baseStr=w1[0,strlen(w1)-3]
202                        if(DataFolderExists("root:"+baseStr))
203                                if(!forceOverwrite)
204                                        DoAlert 1,"The file "+S_filename+" has already been loaded. Do you want to load the new data file, overwriting the data in memory?"
205                                        if(V_flag==2)   //user selected No, don't load the data
206                                                SetDataFolder root:
207                                                KillWaves $n0,$n1,$n2,$n3,$n4,$n5               // kill the default waveX that were loaded
208                                                if(DataFolderExists("root:Packages:NIST"))
209                                                        String/G root:Packages:NIST:gLastFileName = filename
210                                                endif
211                                                return          //quits the macro
212                                        endif
213                                endif
214                                SetDataFolder $("root:"+baseStr)
215                        else
216                                NewDataFolder/S $("root:"+baseStr)
217                        endif
218
219
220
221       
222        ////overwrite the existing data, if it exists
223                        Duplicate/O $("root:"+n0), $w0
224                        Duplicate/O $("root:"+n1), $w1
225                        Duplicate/O $("root:"+n2), $w2
226                        Duplicate/O $("root:"+n3), $w3
227                        Duplicate/O $("root:"+n4), $w4
228                        Duplicate/O $("root:"+n5), $w5
229       
230                        // need to switch based on SANS/USANS
231                        if (isSANSResolution($w3[0]))           //checks to see if the first point of the wave is <0]
232                                // make a resolution matrix for SANS data
233                                Variable np=numpnts($w0)
234                                Make/D/O/N=(np,4) $(baseStr+"_res")
235                               
236                                $(baseStr+"_res")[][0] = $w3[p]         //sigQ
237                                $(baseStr+"_res")[][1] = $w4[p]         //qBar
238                                $(baseStr+"_res")[][2] = $w5[p]         //fShad
239                                $(baseStr+"_res")[][3] = $w0[p]         //Qvalues
240                        else
241                                //the data is USANS data
242                                // marix calculation here, but for now, just copy the waves
243                                //$(baseStr+"_res")[][0] = $w3[p]               //sigQ
244                                //$(baseStr+"_res")[][1] = $w4[p]               //qBar
245                                //$(baseStr+"_res")[][2] = $w5[p]               //fShad
246                                //$(baseStr+"_res")[][3] = $w0[p]               //Qvalues
247                                dQv = -$w3[0]
248                               
249                                USANS_CalcWeights(baseStr,dQv)
250                               
251                        endif
252                        Killwaves/Z $w3,$w4,$w5                 //get rid of the resolution waves that are in the matrix
253       
254                        SetScale d,0,0,"1/A",$w0
255                        SetScale d,0,0,"1/cm",$w1
256               
257                endif   //6-col data
258       
259                // Load ORNL data from Heller program
260                if(numCols == 4)                //4-column SANS or USANS data that has resolution information
261                       
262                        // put the names of the (default named) loaded waves into local names
263                        n0 = StringFromList(0, S_waveNames ,";" )
264                        n1 = StringFromList(1, S_waveNames ,";" )
265                        n2 = StringFromList(2, S_waveNames ,";" )
266                        n3 = StringFromList(3, S_waveNames ,";" )
267                       
268                        //remove the semicolon AND period from files from the VAX
269                        w0 = CleanupName((basestr + "_q"),0)
270                        w1 = CleanupName((basestr + "_i"),0)
271                        w2 = CleanupName((basestr + "_s"),0)
272                        w3 = CleanupName((basestr + "sq"),0)
273                        w4 = CleanupName((basestr + "qb"),0)
274                        w5 = CleanupName((basestr + "fs"),0)
275       
276                       
277                        //String baseStr=w1[0,strlen(w1)-3]
278                        if(DataFolderExists("root:"+baseStr))
279                                if(!forceOverwrite)
280                                        DoAlert 1,"The file "+S_filename+" has already been loaded. Do you want to load the new data file, overwriting the data in memory?"
281                                        if(V_flag==2)   //user selected No, don't load the data
282                                                SetDataFolder root:
283                                                KillWaves $n0,$n1,$n2,$n3               // kill the default waveX that were loaded
284                                                if(DataFolderExists("root:Packages:NIST"))
285                                                        String/G root:Packages:NIST:gLastFileName = filename
286                                                endif
287                                                return          //quits the macro
288                                        endif
289                                endif
290                                SetDataFolder $("root:"+baseStr)
291                        else
292                                NewDataFolder/S $("root:"+baseStr)
293                        endif
294       
295
296
297       
298        ////overwrite the existing data, if it exists
299                        Duplicate/O $("root:"+n0), $w0
300                        Duplicate/O $("root:"+n1), $w1
301                        Duplicate/O $("root:"+n2), $w2
302                        Duplicate/O $("root:"+n3), $w3
303                        Duplicate/O $("root:"+n0), $w0 // Set qb wave to nominal measured Q values
304                        Duplicate/O $("root:"+n0), $w5 // Make wave of appropriate length
305                        $w5 = 1                                           //  Set all shadowfactor to 1
306       
307                        // need to switch based on SANS/USANS
308                        if (isSANSResolution($w3[0]))           //checks to see if the first point of the wave is <0]
309                                // make a resolution matrix for SANS data
310                                Variable np=numpnts($w0)
311                                Make/D/O/N=(np,4) $(baseStr+"_res")
312                               
313                                $(baseStr+"_res")[][0] = $w3[p]         //sigQ
314                                $(baseStr+"_res")[][1] = $w4[p]         //qBar
315                                $(baseStr+"_res")[][2] = $w5[p]         //fShad
316                                $(baseStr+"_res")[][3] = $w0[p]         //Qvalues
317                        else
318                                //the data is USANS data
319                                // marix calculation here, but for now, just copy the waves
320                                //$(baseStr+"_res")[][0] = $w3[p]               //sigQ
321                                //$(baseStr+"_res")[][1] = $w4[p]               //qBar
322                                //$(baseStr+"_res")[][2] = $w5[p]               //fShad
323                                //$(baseStr+"_res")[][3] = $w0[p]               //Qvalues
324                                dQv = -$w3[0]
325                               
326                                USANS_CalcWeights(baseStr,dQv)
327                               
328                        endif
329                        Killwaves/Z $w3,$w4,$w5                 //get rid of the resolution waves that are in the matrix
330       
331                        SetScale d,0,0,"1/A",$w0
332                        SetScale d,0,0,"1/cm",$w1
333               
334                endif   //4-col data
335       
336       
337                if(numCols==5)          //this is the "old-style" VAX desmeared data format
338                       
339                        // put the names of the three loaded waves into local names
340                        n0 = StringFromList(0, S_waveNames ,";" )
341                        n1 = StringFromList(1, S_waveNames ,";" )
342                        n2 = StringFromList(2, S_waveNames ,";" )
343                        n3 = StringFromList(3, S_waveNames ,";" )
344                        n4 = StringFromList(4, S_waveNames ,";" )
345                       
346                       
347                        //remove the semicolon AND period from files from the VAX
348                        w0 = CleanupName((basestr+"_q"),0)
349                        w1 = CleanupName((basestr+"_i"),0)
350                        w2 = CleanupName((basestr+"_s"),0)
351                        w3 = CleanupName((basestr+"_ism"),0)
352                        w4 = CleanupName((basestr+"_fit_ism"),0)
353                       
354                        //String baseStr=w1[0,strlen(w1)-3]
355                        if(DataFolderExists("root:"+baseStr))
356                                if(!forceOverwrite)
357                                        DoAlert 1,"The file "+S_filename+" has already been loaded. Do you want to load the new data file, overwriting the data in memory?"
358                                        if(V_flag==2)   //user selected No, don't load the data
359                                                KillWaves $n0,$n1,$n2,$n3,$n4,$n5               // kill the default waveX that were loaded
360                                                if(DataFolderExists("root:Packages:NIST"))
361                                                        String/G root:Packages:NIST:gLastFileName = filename
362                                                endif           //set the last file loaded to the one NOT loaded
363                                                return          //quits the macro
364                                        endif
365                                endif
366                                SetDataFolder $("root:"+baseStr)
367                        else
368                                NewDataFolder/S $("root:"+baseStr)
369                        endif
370                       
371                        ////overwrite the existing data, if it exists   
372                        Duplicate/O $("root:"+n0), $w0
373                        Duplicate/O $("root:"+n1), $w1
374                        Duplicate/O $("root:"+n2), $w2
375                        Duplicate/O $("root:"+n3), $w3
376                        Duplicate/O $("root:"+n4), $w4
377                       
378                        // no resolution matrix
379                endif           //5-col data
380
381                //////
382                if(DataFolderExists("root:Packages:NIST"))
383                        String/G root:Packages:NIST:gLastFileName = filename
384                endif
385       
386               
387                //plot if desired
388                if(doPlot)
389                        Print GetDataFolder(1)
390                       
391                        // assign colors randomly
392                        rr = abs(trunc(enoise(65535)))
393                        gg = abs(trunc(enoise(65535)))
394                        bb = abs(trunc(enoise(65535)))
395                       
396                        // if target window is a graph, and user wants to append, do so
397                   DoWindow/B Plot_Manager
398                        if(WinType("") == 1)
399                                DoAlert 1,"Do you want to append this data to the current graph?"
400                               
401                               
402                                if(V_Flag == 1)
403                                        AppendToGraph $w1 vs $w0
404                                        ModifyGraph mode($w1)=3,marker($w1)=19,msize($w1)=2,rgb($w1) =(rr,gg,bb),tickUnit=1
405                                        ErrorBars/T=0 $w1 Y,wave=($w2,$w2)
406                                        ModifyGraph tickUnit(left)=1
407                                else
408                                //new graph
409                                        SetDataFolder $("root:"+baseStr)                //sometimes I end up back in root: here, and I can't figure out why!
410                                        Display $w1 vs $w0
411                                        ModifyGraph log=1,mode($w1)=3,marker($w1)=19,msize($w1)=2,rgb($w1)=(rr,gg,bb),tickUnit=1
412                                        ModifyGraph grid=1,mirror=2,standoff=0
413                                        ErrorBars/T=0 $w1 Y,wave=($w2,$w2)
414                                        ModifyGraph tickUnit(left)=1
415                                        Label left "I(q)"
416                                        Label bottom "q (A\\S-1\\M)"
417                                        Legend
418                                endif
419                        else
420                        // graph window was not target, make new one
421                                Display $w1 vs $w0
422                                ModifyGraph log=1,mode($w1)=3,marker($w1)=19,msize($w1)=2,rgb($w1)=(rr,gg,bb),tickUnit=1
423                                ModifyGraph grid=1,mirror=2,standoff=0
424                                ErrorBars/T=0 $w1 Y,wave=($w2,$w2)
425                                ModifyGraph tickUnit(left)=1
426                                Label left "I(q)"
427                                Label bottom "q (A\\S-1\\M)"
428                                Legend
429                        endif
430                endif
431                       
432                //go back to the root folder and clean up before leaving
433                SetDataFolder root:
434                KillWaves/Z $n0,$n1,$n2,$n3,$n4,$n5
435               
436        endif
437End
438
439
440//procedure for loading NSE data in the format (4-columns)
441// qvals - time - I(q,t) - dI(q,t)
442//
443//
444// this does NOT load the data into separate folders...
445//
446Proc A_LoadNSEData()
447        A_LoadNSEDataWithName("",1)
448End
449
450Proc A_LoadNSEDataWithName(fileStr,doPlot)
451
452        //Load the waves, using default waveX names
453        //if no path or file is specified for LoadWave, the default Mac open dialog will appear
454        LoadWave/G/D/A  fileStr
455        String filename = S_fileName
456       
457        String w0,w1,w2,n0,n1,n2,wt,w3,n3
458        Variable rr,gg,bb
459       
460        // put the names of the three loaded waves into local names
461        n0 = StringFromList(0, S_waveNames ,";" )
462        n1 = StringFromList(1, S_waveNames ,";" )
463        n2 = StringFromList(2, S_waveNames ,";" )
464        n3 = StringFromList(3, S_waveNames ,";" )
465       
466       
467        //remove the semicolon AND period from files from the VAX
468        w0 = CleanupName(("qvals_"+S_fileName),0)
469        w1 = CleanupName(("time_"+S_fileName),0)
470        w2 = CleanupName(("iqt_"+S_fileName),0)
471        w3 = CleanupName(("iqterr_"+S_fileName),0)
472       
473        if(exists(w0) !=0)
474                DoAlert 0,"This file has already been loaded. Use Append to Graph..."
475                KillWaves $n0,$n1,$n2           // kill the default waveX that were loaded
476                return
477        endif
478       
479        // Rename to give nice names
480        Rename $n0, $w0
481        Rename $n1, $w1
482        Rename $n2, $w2
483        Rename $n3, $w3
484               
485        if(doPlot)
486                // assign colors randomly
487                rr = abs(trunc(enoise(65535)))
488                gg = abs(trunc(enoise(65535)))
489                bb = abs(trunc(enoise(65535)))
490               
491                // if target window is a graph, and user wants to append, do so
492                if(WinType("") == 1)
493                        DoAlert 1,"Do you want to append this data to the current graph?"
494                        if(V_Flag == 1)
495                                AppendToGraph $w2 vs $w1
496                                ModifyGraph mode($w2)=3,marker($w2)=29,msize($w2)=2,rgb($w2) =(rr,gg,bb),grid=1,mirror=2,tickUnit=1
497                                ErrorBars/T=0 $w2 Y,wave=($w3,$w3)
498                        else
499                        //new graph
500                                Display $w2 vs $w1
501                                ModifyGraph standoff=0,mode($w2)=3,marker($w2)=29,msize($w2)=2,rgb($w2)=(rr,gg,bb),grid=1,mirror=2,tickUnit=1
502                                ErrorBars/T=0 $w2 Y,wave=($w3,$w3)
503                                Legend
504                        endif
505                else
506                // graph window was not target, make new one
507                        Display $w2 vs $w1
508                        ModifyGraph standoff=0,mode($w2)=3,marker($w2)=29,msize($w2)=2,rgb($w2)=(rr,gg,bb),grid=1,mirror=2,tickUnit=1
509                        ErrorBars/T=0 $w2 Y,wave=($w3,$w3)
510                        Legend
511                endif
512        endif //doPlot         
513
514End
515
516//procedure for loading desmeared USANS data in the format (5-columns)
517// qvals - I(q) - sig I - Ism(q) - fitted Ism(q)
518//no weighting wave is created (not needed in IGOR 4)
519//
520// not really ever used...
521//
522Proc A_LoadUSANSData()
523
524        //Load the waves, using default waveX names
525        //if no path or file is specified for LoadWave, the default Mac open dialog will appear
526        LoadWave/G/D/A
527   String filename = S_fileName
528       
529        String w0,w1,w2,n0,n1,n2,w3,n3,w4,n4
530        Variable rr,gg,bb
531       
532        // put the names of the three loaded waves into local names
533        n0 = StringFromList(0, S_waveNames ,";" )
534        n1 = StringFromList(1, S_waveNames ,";" )
535        n2 = StringFromList(2, S_waveNames ,";" )
536        n3 = StringFromList(3, S_waveNames ,";" )
537        n4 = StringFromList(4, S_waveNames ,";" )
538       
539       
540        //remove the semicolon AND period from files from the VAX
541        w0 = CleanupName((S_fileName+"_q"),0)
542        w1 = CleanupName((S_fileName+"_i"),0)
543        w2 = CleanupName((S_fileName+"_s"),0)
544        w3 = CleanupName((S_fileName+"_ism"),0)
545        w4 = CleanupName((S_fileName+"_fit_ism"),0)
546       
547        if(exists(w0) !=0)              //the wave already exists
548                DoAlert 1,"This file "+S_filename+" has already been loaded. Do you want to load the new data file, overwriting the data in memory?"
549                if(V_flag==2)   //user selected No
550                        KillWaves $n0,$n1,$n2,$n3,$n4           // kill the default waveX that were loaded
551                        if(DataFolderExists("root:Packages:NIST"))
552                                String/G root:Packages:NIST:gLastFileName = filename
553                        endif           //set the last file loaded to the one NOT loaded
554                        return          //quits the macro
555                endif
556        endif
557       
558        ////overwrite the existing data, if it exists
559        Duplicate/O $n0, $w0
560        Duplicate/O $n1, $w1
561        Duplicate/O $n2, $w2
562        Duplicate/O $n3, $w3
563        Duplicate/O $n4, $w4
564        KillWaves $n0,$n1,$n2,$n3,$n4
565       
566        if(DataFolderExists("root:Packages:NIST"))
567                String/G root:Packages:NIST:gLastFileName = filename
568        endif
569               
570        // assign colors randomly
571        rr = abs(trunc(enoise(65535)))
572        gg = abs(trunc(enoise(65535)))
573        bb = abs(trunc(enoise(65535)))
574       
575                // if target window is a graph, and user wants to append, do so
576        if(WinType("") == 1)
577                DoAlert 1,"Do you want to append this data to the current graph?"
578                if(V_Flag == 1)
579                        AppendToGraph $w1 vs $w0
580                        ModifyGraph mode=3,marker=29,msize=2,rgb ($w1) =(rr,gg,bb),tickUnit=1,grid=1,mirror=2
581                        ErrorBars/T=0 $w1 Y,wave=($w2,$w2)
582                else
583                //new graph
584                        Display $w1 vs $w0
585                        ModifyGraph log=1,mode=3,marker=29,msize=2,rgb=(rr,gg,bb),tickUnit=1,grid=1,mirror=2
586                        ErrorBars/T=0 $w1 Y,wave=($w2,$w2)
587                        Legend
588                endif
589        else
590        // graph window was not target, make new one
591                Display $w1 vs $w0
592                ModifyGraph log=1,mode=3,marker=29,msize=2,rgb=(rr,gg,bb),tickUnit=1,grid=1,mirror=2
593                ErrorBars/T=0 $w1 Y,wave=($w2,$w2)
594                Legend
595        endif
596               
597End
598
599
600//// Extra "Utility Procedures"
601// to pick path, get a list of data files, and make sure that a valid filename
602// is passed to LoadOneDDataWithName()
603//
604
605//prompts user to choose the local folder that contains the SANS Data
606//only one folder can be used, and its path is catPathName (and is a NAME, not a string)
607//this will overwrite the path selection
608//returns 1 if no path selected as error condition
609Function A_PickPath()
610       
611        //set the global string to the selected pathname
612        NewPath/O/M="pick the SANS data folder" catPathName
613        PathInfo/S catPathName
614        String dum = S_path
615        String alertStr = ""
616        alertStr = "You must set the path to Charlotte through a Mapped Network Drive, not through the Network Neighborhood"
617        //alertStr += "  Please see the manual for details."
618        if (V_flag == 0)
619                //path does not exist - no folder selected
620                String/G root:Packages:NIST:gCatPathStr = "no folder selected"
621                return(1)
622        else
623                //set the global to the path (as a string)
624                // need 4 \ since it is the escape character
625                if(cmpstr("\\\\",dum[0,1])==0)  //Windoze user going through network neighborhood
626                        DoAlert 0,alertStr
627                        KillPath catPathName
628                        return(1)
629                endif
630                String/G root:Packages:NIST:gCatPathStr = dum
631                return(0)               //no error
632        endif
633End
634
635//Function attempts to find valid filename from partial name that has been stripped of
636//the VAX version number. The partial name is tried first
637//*** the PATH is hard-wired to catPathName (which is assumed to exist)
638//version numers up to ;10 are tried
639//only the "name;vers" is returned. the path is not prepended, hence the return string
640//is not a complete specification of the file
641//
642// added 11/99 - uppercase and lowercase versions of the file are tried, if necessary
643// since from marquee, the filename field (textread[0]) must be used, and can be a mix of
644// upper/lowercase letters, while the filename on the server (should) be all caps
645// now makes repeated calls to ValidFileString()
646//
647Function/S A_FindValidFilename(partialName)
648        String PartialName
649       
650        String retStr=""
651       
652        //try name with no changes - to allow for ABS files that have spaces in the names 12APR04
653        retStr = A_ValidFileString(partialName)
654        if(cmpstr(retStr,"") !=0)
655                //non-null return
656                return(retStr)
657        Endif
658       
659        //if the partial name is derived from the file header, there can be spaces at the beginning
660        //or in the middle of the filename - depending on the prefix and initials used
661        //
662        //remove any leading spaces from the name before starting
663        partialName = A_RemoveAllSpaces(partialName)
664       
665        //try name with no spaces
666        retStr = A_ValidFileString(partialName)
667        if(cmpstr(retStr,"") !=0)
668                //non-null return
669                return(retStr)
670        Endif
671       
672        //try all UPPERCASE
673        partialName = UpperStr(partialName)
674        retStr = A_ValidFileString(partialName)
675        if(cmpstr(retStr,"") !=0)
676                //non-null return
677                return(retStr)
678        Endif
679       
680        //try all lowercase (ret null if failure)
681        partialName = LowerStr(partialName)
682        retStr = A_ValidFileString(partialName)
683        if(cmpstr(retStr,"") !=0)
684                //non-null return
685                return(retStr)
686        else
687                return(retStr)
688        Endif
689End
690
691//function to test a binary file to see if it is a RAW binary SANS file
692//first checks the total bytes in the file (which for raw data is 33316 bytes)
693//**note that the "DIV" file will also show up as a raw file by the run field
694//should be listed in CAT/SHORT and in patch windows
695//
696//Function then checks the file fname (full path:file) for "RAW" run.type field
697//if not found, the data is not raw data and zero is returned
698Function A_CheckIfRawData(fname)
699        String fname
700       
701        Variable refnum,totalBytes
702        String testStr=""
703       
704        Open/R/T="????TEXT" refNum as fname
705        //get the total number of bytes in the file, to avoid moving past EOF
706        FStatus refNum
707        totalBytes = V_logEOF
708        //Print totalBytes
709        if(totalBytes!=33316)
710                //can't possibly be a raw data file
711                Close refnum
712                return(0)               //not a raw SANS file
713        Endif
714        FSetPos refNum,75
715        FReadLine/N=3 refNum,testStr
716        Close refNum
717       
718        if(cmpstr(testStr,"RAW")==0)
719                //true, is raw data file
720                Return(1)
721        else
722                //some other file
723                Return(0)
724        Endif
725End
726
727//list (input) is a list, typically returned from IndexedFile()
728//which is semicolon-delimited, and may contain filesnames from the VAX
729//that contain version numbers, where the version number appears as a separate list item
730//(and also as a non-existent file)
731//these numbers must be purged from the list, especially for display in a popup
732//or list processing of filenames
733//the function returns the list, cleaned of version numbers (up to 11)
734//raw data files will typically never have a version number other than 1.
735Function/S A_RemoveVersNumsFromList(list)
736        String list
737       
738        //get rid of version numbers first (up to 11)
739        Variable ii,num
740        String item
741        num = ItemsInList(list,";")
742        ii=1
743        do
744                item = num2str(ii)
745                list = RemoveFromList(item, list ,";" )
746                ii+=1
747        while(ii<12)
748       
749        return (list)
750End
751
752//Function attempts to find valid filename from partial name that has been stripped of
753//the VAX version number. The partial name is tried first
754//*** the PATH is hard-wired to catPathName (which is assumed to exist)
755//version numers up to ;10 are tried
756//only the "name;vers" is returned. the path is not prepended, hence the return string
757//is not a complete specification of the file
758//
759Function/S A_ValidFileString(partialName)
760        String partialName
761       
762        String tempName = "",msg=""
763        Variable ii,refnum
764       
765        ii=0
766        do
767                if(ii==0)
768                        //first pass, try the partialName
769                        tempName = partialName
770                        Open/Z/R/T="????TEXT"/P=catPathName refnum tempName     //Does open file (/Z flag)
771                        if(V_flag == 0)
772                                //file exists
773                                Close refnum            //YES needed,
774                                break
775                        endif
776                else
777                        tempName = partialName + ";" + num2str(ii)
778                        Open/Z/R/T="????TEXT"/P=catPathName refnum tempName
779                        if(V_flag == 0)
780                                //file exists
781                                Close refnum
782                                break
783                        endif
784                Endif
785                ii+=1
786                //print "ii=",ii
787        while(ii<11)
788        //go get the selected bits of information, using tempName, which exists
789        if(ii>=11)
790                //msg = partialName + " not found. is version number > 11?"
791                //DoAlert 0, msg
792                //PathInfo catPathName
793                //Print S_Path
794                Return ("")             //use null string as error condition
795        Endif
796       
797        Return (tempName)
798End
799
800//function to remove all spaces from names when searching for filenames
801//the filename (as saved) will never have interior spaces (TTTTTnnn_AB _Bnnn)
802//but the text field in the header WILL, if less than 3 characters were used for the
803//user's initials, and can have leading spaces if prefix was less than 5 characters
804//
805//returns a string identical to the original string, except with the interior spaces removed
806//
807Function/S A_RemoveAllSpaces(str)
808        String str
809       
810        String tempstr = str
811        Variable ii,spc,len             //should never be more than 2 or 3 trailing spaces in a filename
812        ii=0
813        do
814                len = strlen(tempStr)
815                spc = strsearch(tempStr," ",0)          //is the last character a space?
816                if (spc == -1)
817                        break           //no more spaces found, get out
818                endif
819                str = tempstr
820                tempStr = str[0,(spc-1)] + str[(spc+1),(len-1)] //remove the space from the string
821        While(1)        //should never be more than 2 or 3
822       
823        If(strlen(tempStr) < 1)
824                tempStr = ""            //be sure to return a null string if problem found
825        Endif
826       
827        //Print strlen(tempstr)
828       
829        Return(tempStr)
830               
831End
832
833//AJJ Oct 2008
834//Moved from GaussUtils - makes more sense to have it here
835
836// utility used in the "PlotSmeared...() macros to get a list of data folders
837//
838//1:    Waves.
839//2:    Numeric variables.
840//3:    String variables.
841//4:    Data folders.
842Function/S GetAList(type)
843        Variable type
844       
845        SetDataFolder root:
846       
847        String objName,str=""
848        Variable index = 0
849        do
850                objName = GetIndexedObjName(":", type, index)
851                if (strlen(objName) == 0)
852                        break
853                endif
854                //Print objName
855                str += objName + ";"
856                index += 1
857        while(1)
858       
859        // remove myGlobals, Packages, etc. from the folder list
860        if(type==4)
861                str = RemoveFromList("myGlobals", str , ";" )
862                str = RemoveFromList("Packages", str, ";")
863                str = RemoveFromList("AutoFit", str, ";")
864                str = RemoveFromList("TISANE", str, ";")
865                str = RemoveFromList("HayPenMSA", str, ";")
866                str = RemoveFromList("SAS", str, ";")                   //from Irena
867                str = RemoveFromList("USAXS", str, ";")
868        endif
869       
870        return(str)
871End
872
873
874//returns the path to the file, or null if cancel
875Function/S DoOpenFileDialog(msg)
876        String msg
877       
878        Variable refNum
879//      String message = "Select a file"
880        String outputPath
881       
882        Open/D/R/T="????"/M=msg refNum
883        outputPath = S_fileName
884       
885        return outputPath
886End
887
888// returns the path to the file, or null if the user cancelled
889// fancy use of optional parameters
890//
891// enforce short file names (25 characters)
892Function/S DoSaveFileDialog(msg,[fname,suffix])
893        String msg,fname,suffix
894        Variable refNum
895//      String message = "Save the file as"
896
897        if(ParamIsDefault(fname))
898//              Print "fname not supplied"
899                fname = ""
900        endif
901        if(ParamIsDefault(suffix))
902//              Print "suffix not supplied"
903                suffix = ""
904        endif
905       
906        String outputPath,tmpName,testStr
907        Variable badLength=0,maxLength=25,l1,l2
908       
909       
910        tmpName = fname + suffix
911       
912        do
913                badLength=0
914                Open/D/M=msg/T="????" refNum as tmpName         //OS will allow 255 characters, but then I can't read it back in!
915                outputPath = S_fileName
916               
917                testStr = ParseFilePath(0, outputPath, ":", 1, 0)               //just the filename
918                if(strlen(testStr)==0)
919                        break           //cancel, allow exit
920                endif
921                if(strlen(testStr) > maxLength)
922                        badlength = 1
923                        DoAlert 2,"File name is too long. Is\r"+testStr[0,maxLength-1]+"\rOK?"
924                        if(V_flag==3)
925                                outputPath = ""
926                                break
927                        endif
928                        if(V_flag==1)                   //my suggested name is OK, so trim the output
929                                badlength=0
930                                l1 = strlen(testStr)            //too long length
931                                l1 = l1-maxLength               //number to trim
932                                //Print outputPath
933                                l2=strlen(outputPath)
934                                outputPath = outputPath[0,l2-1-l1]
935                                //Print "modified  ",outputPath
936                        endif
937                        //if(V_flag==2)  do nothing, let it go around again
938                endif
939               
940        while(badLength)
941       
942        return outputPath
943End
944
945// returns a shortened file name (26 characters max) so that the loader
946// won't try to create Igor objects that have names that are longer than 31
947//
948Function/S ShortFileNameString(inStr)
949        String inStr
950
951        String outStr=""
952        Variable maxLength=25
953        Variable nameTooLong=0
954       
955        if(strlen(inStr) <= maxLength)
956                return (inStr)          //length OK
957        else
958                do
959                        nameTooLong = 0
960                       
961                        DoAlert 1,"File name is too long. Is\r"+inStr[0,maxLength-1]+"\rOK?"
962                        if(V_flag==1)                   //my suggested name is OK, so trim the output
963                                outStr = inStr[0,maxLength-1]
964                                //Print "modified  ",outStr
965                                return(outStr)
966                        endif
967       
968       
969                        if(V_flag == 2)         //not OK, do something about it
970                                String/G root:myGlobals:gShortNameStr = inStr[0,maxLength-1]
971                                SVAR newStr = root:myGlobals:gShortNameStr
972                               
973                                DoWindow/F ShorterNameInput             //it really shouldn't exist...
974                                if(V_flag==0)
975                                        NewPanel /W=(570,152,915,280) as "Enter a Shorter Name"
976                                        DoWindow/C ShorterNameInput
977                                        SetDrawLayer UserBack
978                                        TitleBox title0,pos={35,8},size={261,20},title=" Enter a shorter file name. It must be 25 characters or less "
979                                        TitleBox title0,fStyle=1
980                                        SetVariable setvar0,pos={21,52},size={300,15},title="New name",value= _STR:newStr
981                                        SetVariable setvar0,proc=ShorterNameSetVarProc
982                                        SetVariable setvar0 valueBackColor=(65535,49151,49151)
983                                        Button button0,pos={259,87},size={60,20},title="Done"
984                                        Button button0,proc=ShorterNameDoneButtonProc
985                                endif
986                               
987                                PauseForUser ShorterNameInput
988                               
989                                // this really should force a good name, but there could be errors that I'm not catching
990                                Print newStr, strlen(newStr)
991                                nameTooLong = 0
992                        endif
993               
994                while (nameTooLong)
995               
996                return(newStr)
997               
998        endif
999               
1000End
1001
1002
1003// for the ShortFileNameString() - PauseForUser to get a shorter file name
1004Function ShorterNameSetVarProc(sva) : SetVariableControl
1005        STRUCT WMSetVariableAction &sva
1006               
1007        switch( sva.eventCode )
1008                case 1: // mouse up
1009                case 2: // Enter key
1010                case 3: // Live update
1011                                String sv = sva.sval
1012                                if( strlen(sv) > 25 )
1013                                        sv= sv[0,24]
1014                                        SetVariable  $(sva.ctrlName),win=$(sva.win),value=_STR:sv
1015                                        SetVariable setvar0 valueBackColor=(65535,49151,49151)
1016                                        Beep
1017                                else
1018                                        SetVariable setvar0 valueBackColor=(65535,65535,65535)
1019                                endif
1020                                break
1021                endswitch
1022        return 0
1023End
1024
1025// for the ShortFileNameString() - PauseForUser to get a shorter file name
1026Function ShorterNameDoneButtonProc(ba) : ButtonControl
1027        STRUCT WMButtonAction &ba
1028       
1029        String win = ba.win
1030
1031        switch (ba.eventCode)
1032                case 2:
1033                        SVAR newStr = root:myGlobals:gShortNameStr
1034                        ControlInfo setvar0
1035                        newStr = S_value
1036                        DoWindow/K ShorterNameInput
1037                       
1038                        break
1039        endswitch
1040
1041        return 0
1042End
1043
1044
1045// a function common to many panels, so put the basic version here that simply
1046// returns null string if no functions are present. Calling procedures can
1047// add to the list to customize as needed.
1048// show the available models
1049// not the f*(cw,xw) point calculations
1050// not the *X(cw,xw) XOPS
1051//
1052// KIND:10 should show only user-defined curve fitting functions
1053// - not XOPs
1054// - not other user-defined functions
1055Function/S User_FunctionPopupList()
1056        String list,tmp
1057        list = FunctionList("*",";","KIND:10")          //get every user defined curve fit function
1058
1059        //now start to remove everything the user doesn't need to see...
1060
1061        tmp = FunctionList("*_proto",";","KIND:10")             //prototypes
1062        list = RemoveFromList(tmp, list  ,";")
1063       
1064        //prototypes that show up if GF is loaded
1065        list = RemoveFromList("GFFitFuncTemplate", list)
1066        list = RemoveFromList("GFFitAllAtOnceTemplate", list)
1067        list = RemoveFromList("NewGlblFitFunc", list)
1068        list = RemoveFromList("NewGlblFitFuncAllAtOnce", list)
1069        list = RemoveFromList("GlobalFitFunc", list)
1070        list = RemoveFromList("GlobalFitAllAtOnce", list)
1071        list = RemoveFromList("GFFitAAOStructTemplate", list)
1072        list = RemoveFromList("NewGF_SetXWaveInList", list)
1073        list = RemoveFromList("NewGlblFitFuncAAOStruct", list)
1074       
1075        // more to remove as a result of 2D/Gizmo
1076        list = RemoveFromList("A_WMRunLessThanDelta", list)
1077        list = RemoveFromList("WMFindNaNValue", list)
1078        list = RemoveFromList("WM_Make3DBarChartParametricWave", list)
1079        list = RemoveFromList("UpdateQxQy2Mat", list)
1080        list = RemoveFromList("MakeBSMask", list)
1081       
1082        // MOTOFIT/GenFit bits
1083        tmp = "GEN_allatoncefitfunc;GEN_fitfunc;GetCheckBoxesState;MOTO_GFFitAllAtOnceTemplate;MOTO_GFFitFuncTemplate;MOTO_NewGF_SetXWaveInList;MOTO_NewGlblFitFunc;MOTO_NewGlblFitFuncAllAtOnce;GeneticFit_UnSmearedModel;GeneticFit_SmearedModel;"
1084        list = RemoveFromList(tmp, list  ,";")
1085
1086        // SANS Reduction bits
1087        tmp = "ASStandardFunction;Ann_1D_Graph;Avg_1D_Graph;BStandardFunction;CStandardFunction;Draw_Plot1D;MyMat2XYZ;NewDirection;SANSModelAAO_MCproto;Monte_SANS_Threaded;Monte_SANS_NotThreaded;Monte_SANS_W1;Monte_SANS_W2;Monte_SANS_W3;Monte_SANS_W4;Monte_SANS;FractionReachingDetector;"
1088        list = RemoveFromList(tmp, list  ,";")
1089
1090        // USANS Reduction bits
1091        tmp = "DSM_Guinier_Fit;RemoveMaskedPoints;"
1092        list = RemoveFromList(tmp, list  ,";")
1093
1094        //more functions from analysis models (2008)
1095        tmp = "Barbell_Inner;Barbell_Outer;Barbell_integrand;BCC_Integrand;Integrand_BCC_Inner;Integrand_BCC_Outer;"
1096        list = RemoveFromList(tmp, list  ,";")
1097        tmp = "CapCyl;CapCyl_Inner;CapCyl_Outer;ConvLens;ConvLens_Inner;ConvLens_Outer;"
1098        list = RemoveFromList(tmp, list  ,";")
1099        tmp = "Dumb;Dumb_Inner;Dumb_Outer;FCC_Integrand;Integrand_FCC_Inner;Integrand_FCC_Outer;"
1100        list = RemoveFromList(tmp, list  ,";")
1101        tmp = "Integrand_SC_Inner;Integrand_SC_Outer;SC_Integrand;SphCyl;SphCyl_Inner;SphCyl_Outer;"
1102        list = RemoveFromList(tmp, list  ,";")
1103        tmp = "CSPP_Outer;CSPP_Inner;PP_Outer;PP_Inner;"
1104        list = RemoveFromList(tmp, list  ,";")
1105        tmp = "Guinier_Fit;"
1106        list = RemoveFromList(tmp, list  ,";")
1107
1108        tmp = FunctionList("f*",";","NPARAMS:2")                //point calculations
1109        list = RemoveFromList(tmp, list  ,";")
1110       
1111        tmp = FunctionList("fSmear*",";","NPARAMS:3")           //smeared dependency calculations
1112        list = RemoveFromList(tmp, list  ,";")
1113       
1114        // anything that might be included in Irena
1115        tmp = FunctionList("GEN_*",";","KIND:10")
1116        list = RemoveFromList(tmp, list  ,";")
1117        tmp = FunctionList("IN2G_*",";","KIND:10")
1118        list = RemoveFromList(tmp, list  ,";")
1119        tmp = FunctionList("IR1A_*",";","KIND:10")
1120        list = RemoveFromList(tmp, list  ,";")
1121        tmp = FunctionList("IR1B_*",";","KIND:10")
1122        list = RemoveFromList(tmp, list  ,";")
1123        tmp = FunctionList("IR1U_*",";","KIND:10")
1124        list = RemoveFromList(tmp, list  ,";")
1125        tmp = FunctionList("IR1V_*",";","KIND:10")
1126        list = RemoveFromList(tmp, list  ,";")
1127        tmp = FunctionList("IR1_*",";","KIND:10")
1128        list = RemoveFromList(tmp, list  ,";")
1129        tmp = FunctionList("IR2D_*",";","KIND:10")
1130        list = RemoveFromList(tmp, list  ,";")
1131
1132        tmp = FunctionList("IR2D_*",";","KIND:10")
1133        list = RemoveFromList(tmp, list  ,";")
1134        tmp = FunctionList("IR2H_*",";","KIND:10")
1135        list = RemoveFromList(tmp, list  ,";") 
1136        tmp = FunctionList("IR2L_*",";","KIND:10")
1137        list = RemoveFromList(tmp, list  ,";")
1138        tmp = FunctionList("IR2Pr_*",";","KIND:10")
1139        list = RemoveFromList(tmp, list  ,";")
1140        tmp = FunctionList("IR2R_*",";","KIND:10")
1141        list = RemoveFromList(tmp, list  ,";")
1142        tmp = FunctionList("IR2S_*",";","KIND:10")
1143        list = RemoveFromList(tmp, list  ,";")
1144        tmp = FunctionList("IR2_*",";","KIND:10")
1145        list = RemoveFromList(tmp, list  ,";")
1146        tmp = FunctionList("*LogLog",";","KIND:10")
1147        list = RemoveFromList(tmp, list  ,";")
1148       
1149        //functions included in Nika
1150        tmp = FunctionList("NI1*",";","KIND:10")
1151        list = RemoveFromList(tmp, list  ,";")
1152        tmp = FunctionList("TransAx_*",";","KIND:10")
1153        list = RemoveFromList(tmp, list  ,";")
1154        tmp = FunctionList("TransformAxis*",";","KIND:10")
1155        list = RemoveFromList(tmp, list  ,";")
1156        tmp = FunctionList("erfForNormal*",";","KIND:10")
1157        list = RemoveFromList(tmp, list  ,";")
1158
1159        // functions in Indra (USAXS)
1160        tmp = FunctionList("IN2Q_*",";","KIND:10")
1161        list = RemoveFromList(tmp, list  ,";")
1162        tmp = FunctionList("IN3_*",";","KIND:10")
1163        list = RemoveFromList(tmp, list  ,";")
1164       
1165//      tmp = FunctionList("*X",";","KIND:4")           //XOPs, but these shouldn't show up if KIND:10 is used initially
1166//      Print "X* = ",tmp
1167//      print " "
1168//      list = RemoveFromList(tmp, list  ,";")
1169       
1170        //non-fit functions that I can't seem to filter out
1171        list = RemoveFromList("BinaryHS_PSF11;BinaryHS_PSF12;BinaryHS_PSF22;EllipCyl_Integrand;PP_Inner;PP_Outer;Phi_EC;TaE_Inner;TaE_Outer;",list,";")
1172
1173        list = SortList(list)
1174        return(list)
1175End
Note: See TracBrowser for help on using the repository browser.