Jump to content

Loops making me loopy


Recommended Posts

Theoretically, I'm trying to achieve this:

For $i = 1 to $some_number
   [...script...]
   For $j = 1 to $some_other_number
      [...script...]
      For $k = 1 to $yet_another_number
         [...script...]
      Next
   Next
Next

Without knowing how many levels to go. I dont' even know how to explain it :P The above would continue past For $i, For $j, For $k up until some variable amount of levels. I just don't know how to structure the loop inside the loop. The [...script...] is the same at each level.

Aw man, I'm sorry... I don't even know how to intelligently word the question so you can help me. But if you think you get the gist of what I'm asking and can point me in the right direction it would be helpful. Thanks.

LD

Edited by LondonNDIB
Link to comment
Share on other sites

Theoretically, I'm trying to achieve this:

For $i = $some_number
   [...script...]
   For $j = $some_other_number
      [...script...]
      For $k = $yet_another_number
         [...script...]
      Next
   Next
Next

Without knowing how many levels to go. I dont' even know how to explain it :P The above would continue past For $i, For $j, For $k up until some variable amount of levels. I just don't know how to structure the loop inside the loop. The [...script...] is the same at each level.

Aw man, I'm sorry... I don't even know how to intelligently word the question so you can help me. But if you think you get the gist of what I'm asking and can point me in the right direction it would be helpful. Thanks.

LD

so you want to create nested loops dynamically? Whatever your end result is, you may be able to achieve it easier using recursion, like a function that calls itself repeatedly until a base case is reached, and then a value is returned back up through the chain...

it takes some practice to think recursively, but it can really simplify some problems... here's an example:

this script figures all possible permutations of the letters in a word that you enter. rather than using a bunch of nested loops, it uses a recursive approach....

#include<array.au3>
Global $count = 0;sets up a counter
Global $word = InputBox("word", "enter a word", "cat");takes user input to get the word
Global $size = StringLen($word);determines the size of the word to find the total number of possible permutations
                            ;number of possible = factorial of length or: possible = $size * ($size -1) * ($size -2) * ($size - 3)...
Global $broken = StringSplit($word,"");breaks the word into letters
_ArrayDelete($broken,0);removes the count element from the array created by the stringsplit() function
$tmp = "";creates a container to hold the final string to output
$start = TimerInit()
DoAnagram($size);begins the recursive function
ConsoleWrite(@lf & TimerDiff($start)& @lf)
If StringLen($tmp) Then
run("Notepad");runs notepad to display data
WinWait("Untitled - Notepad");waits for notepad to exist
ControlSetText("Untitled - Notepad","",15,$tmp);updates the edit control in notepad to contain all of the data returned
EndIf

Func DoAnagram($newsize);this is the function that calls itself repeatedly to achieve the result
    if $newsize <> 1 Then;this check ensures that when the base case is encountered, no further calls to this function happen
        For $j = 1 to $newsize;this has it call itself for every possible combination, as explained in the declaration of the $size variable
            DoAnagram($newsize -1);it calls itself after decrementing the parameter it was passed
            If $newsize = 2 Then displayword();when the base case is being called, the word is displayed
            rotate($newsize);this rotates the letters that are not the first letter
        Next
    EndIf
EndFunc

Func rotate($newsize2);this function takes the number of characters that it is passed
    $position = $size - $newsize2;determines the number of characters that need to be rotated
$temp = $broken[$position];grabs the element currently in the first position
For $iterator = $position + 1 to $size-1;cycles through entire portion of the word
    $broken[$iterator - 1] = $broken[$iterator];moves each character left
Next
$broken[$iterator -1] = $temp;and stacks the element that was left most onto the right side
EndFunc

Func displayword()
    if $count < 99 Then $tmp = $tmp & " "
    if $count < 9 Then $tmp = $tmp & " "
    $count = $count + 1
    $tmp = $tmp & $count & " "
    For $iterator2 = 0 to $size - 1
        $tmp = $tmp & $broken[$iterator2]
    Next
    $tmp = $tmp & "  "
    $tmp = $tmp & ""
    If not Mod($count,6) Then $tmp = $tmp & @CRLF
EndFunc
Link to comment
Share on other sites

Hmm... recursion. Sounds about exactly what I need :P

In fact, I'm not sure why I worded so vaguely... I'm sure this problem has been addressed before and it took the word "recursion" to figure out how to ask! Thanks!

All I'm looking to do is to "recurse" through the local computer's directory structure and run a bit of code for each folder found (and subfolder, etc).

End result really is I want to display a complete directory structure for the computer as a treeview.

I will study your code to see if I can come up with it myself. In the meantime, if someone has a way to do what I need it would be appreciated! Thanks!!

LD

Link to comment
Share on other sites

Hmm... recursion. Sounds about exactly what I need :P

In fact, I'm not sure why I worded so vaguely... I'm sure this problem has been addressed before and it took the word "recursion" to figure out how to ask! Thanks!

All I'm looking to do is to "recurse" through the local computer's directory structure and run a bit of code for each folder found (and subfolder, etc).

End result really is I want to display a complete directory structure for the computer as a treeview.

I will study your code to see if I can come up with it myself. In the meantime, if someone has a way to do what I need it would be appreciated! Thanks!!

LD

actually, look up recursive file search in the forum, there have been several written, any one would take minor modifications to do what you want.
Link to comment
Share on other sites

End result really is I want to display a complete directory structure for the computer as a treeview.

this should do the trick...

#Include <GUIConstants.au3>
Global $Tree
Global $SubTree
; Create GUI
GUICreate("BrowseDemo",430,325)
$TreeView = GUICtrlCreateTreeView(10,10,200,305)
GUICtrlSetImage(-1,"shell32.dll",3,4)
GUICtrlSetImage(-1,"shell32.dll",4,2)
$list = GUICtrlCreateList("",220,10,200,310)
FileDelete("Files.ini")
$test = FileOpen ("test.txt",2)
$HDDrives = DrivegetDrive("FIXED")
For $i = 1 To $HDDrives[0]
    FileWriteLine ($test,$HDDrives[$i] & "\")
    Search($HDDrives[$i] & "\","*.*")
        $var = IniReadSection("Files.ini", $HDDrives[$i] & "\")
    For $h = 1 To $var[0][0]
        $IniRead = IniRead("Files.ini",$HDDrives[$i] & "\",$h,"NotFound")
        _Next($IniRead,"*.*",$h)
    Next
Next
; Close the search handle
FileClose($test)
$test = FileOpen ("test.txt",0)
GUISetState()
$a = _Search4Files(FileReadLine ($test,GUICtrlRead ($treeview)-4))
AdlibEnable ("check")
While 1;Main Loop
    $msg = GUIGetmsg()
    If $msg = $GUI_EVENT_CLOSE Then Exit
WEnd    
Exit
;Functions
;///////////////////////////////////////////
Func Search($SearchPath,$FileType)
$Item1 = GUICtrlCreateTreeViewItem(StringUpper($SearchPath),$TreeView)
GUICtrlSetImage(-1,"shell32.dll",8)
$Search = FileFindFirstFile($SearchPath & $FileType)  
If $search = -1 Then
    MsgBox(0, "Error", "No files/directories matched the search pattern")
    Exit
EndIf

$Count = 1
DIM $Tree[99999]
While 1
    $File = FileFindNextFile($search) 
    If @error Then ExitLoop
    
    $Attrib = FileGetAttrib($SearchPath & $File)
    If StringInStr($Attrib,"D") Then
        $Tree[$Count] = GUICtrlCreateTreeViewItem($File,$Item1)
        FileWriteLine ($test,$SearchPath & $File & "\")
        IniWrite("Files.ini",$SearchPath,$Count,$SearchPath & $File & "\")
        $Count = $Count +1
    EndIf
WEnd
FileClose($Search)
EndFunc

Func _Next($SearchPath,$FileType,$Number)
$Search1 = FileFindFirstFile($SearchPath & $FileType)  
If $search1 = -1 Then
Else
    $Count = 1
    DIM $SubTree[99999]
    While 1
        $NextFile = FileFindNextFile($search1) 
        If @error Then ExitLoop
        
        $Attrib = FileGetAttrib($SearchPath & $NextFile)
        If $Attrib = "D" Then;StringInStr($Attrib,"D") Then
            If $NextFile = "." Or $NextFile = ".." Then 
            Else    
                $FBuffer = $SearchPath & $NextFile & "\"
                $SubTree[$Count] = GUICtrlCreateTreeViewItem($NextFile,$Tree[$Number])
                FileWriteLine ($test,$FBuffer)
                $Search2 = FileFindFirstFile($FBuffer & "*.*")
                If $search2 = -1 Then
                   ;msgbox(0,"","Ingen mapper")
                Else
                    $Count1 = 1
                    While 1
                        $NextFile2 = FileFindNextFile($search2) 
                        If @error Then ExitLoop
                        $Attrib = FileGetAttrib($FBuffer & $NextFile2)
                        If $Attrib = "D" Then;StringInStr($Attrib,"D") Then
                            If $NextFile2 = "." Or $NextFile2 = ".." Then 
                            Else    
                                GUICtrlCreateTreeViewItem($NextFile2,$SubTree[$Count])
                                FileWriteLine ($test,$FBuffer & $NextFile2& "\")
                                $Count1 = $Count1 +1
                            EndIf
                        EndIf
                    WEnd    
                FileClose($Search2)
                EndIf
          ;msgbox(0,"","Stop " & $Count)
                $Count = $Count +1
            EndIf
        EndIf
    WEnd    
    FileClose($Search1)
EndIf
EndFUnc

Func check()
    $b = GUICtrlRead ($treeview)
    If $a <> $b Then $a = _Search4Files(FileReadLine ($test,GUICtrlRead ($treeview)-4))
EndFunc
    
Func _Search4Files($path)
    GUICtrlSetData($list, "")
    $search4 = FileFindFirstFile($path & "*.*")  
    If $search4 <> -1 Then
        While 1
            $file = FileFindNextFile($search4) 
            If @error Then ExitLoop
            If $file = "." Then $file = FileFindNextFile($search4)
            If $file = ".." Then $file = FileFindNextFile($search4)
            If StringInStr(FileGetAttrib ($path & $file), "D") = 0 Then GUICtrlSetData($list, $file)
        WEnd
    EndIf
    Return GUICtrlRead ($treeview)
    FileClose($search4)
EndFunc

8)

NEWHeader1.png

Link to comment
Share on other sites

Thanks! That code you posted though... either it is designed to do something odd that I can't figure out, or it is buggy? When I run it, a LOT of folders and files are missing, and in any case it only seems to go 3 or 4 deep. Still, there are some that don't expand at all for some reason. I'm probably missing something but I don't see a pattern (like, "only show files with a D in it" or something similar). It definately does NOT show all folders and files, that's for sure. And in no case will it go more than 4 levels deep (on my system anyway).

Thanks for the help though! Given me a lot to study!

LD

Link to comment
Share on other sites

Wow! Ok, I looked into a bit more and I don't think my approach will work anyway. I never got it altered for my needs, but I found one of the available scripts that did list everything and it worked but takes like 15 minutes to finish! And that's *just* listing! I need it to do a little more than just that so I don't think this will work.

I don't know enough about the GUI controls, but I wonder if I can make it so it only grabs the subfolders for a folder when you hit the + in the Treeview.

Anyway, for now I doubt I'll even try... too complex for what I'm trying to do. I'll just get the user to select paths one at a time rather than using TreeView.

LD

Link to comment
Share on other sites

Wow! Ok, I looked into a bit more and I don't think my approach will work anyway. I never got it altered for my needs, but I found one of the available scripts that did list everything and it worked but takes like 15 minutes to finish! And that's *just* listing! I need it to do a little more than just that so I don't think this will work.

I don't know enough about the GUI controls, but I wonder if I can make it so it only grabs the subfolders for a folder when you hit the + in the Treeview.

Anyway, for now I doubt I'll even try... too complex for what I'm trying to do. I'll just get the user to select paths one at a time rather than using TreeView.

LD

the only way to guarantee failure is to give up...
Link to comment
Share on other sites

Welcome to the forums!

Depending on precisely what you want to do, it may be more efficient performance-wise to call DOS for a recursive file or directory listing, and then write some short AutoIt code to parse the result. Would that help you achieve what you need?

Link to comment
Share on other sites

the only way to guarantee failure is to give up...

ok, i decided to just make my own recursive file lister rather than searching for another to quote to you. this one took 13 seconds to list every file on the C drive of my work computer, and the file size. I have the output going to a text file, if this searches quickly enough for you, i'm sure you could whip up the code to read in the text file and make your list tree...

beta is required, running without beta will crash

$tosearch = "C:"
$output = FileOpen("c:\filelist.txt",2)
Global $deep = 0
$start = TimerInit()
RecFileSearch($tosearch)
FileClose($output)
MsgBox(0,"done","it only took " & int(TimerDiff($start)/1000) & " seconds")
Func RecFileSearch($current)
    $deep = $deep +1
    Local $search = FileFindFirstFile($current & "\*.*")
    While 1
    Dim $file = FileFindNextFile($search)
    If @error Or StringLen($file)<1 Then ExitLoop
    FileWriteLine($output,$current & "\" & $file & "     " & FileGetSize($file))
    If StringInStr(FileGetAttrib($current & "\" & $file),"D") And ( $file <> "." Or $file <> ".." ) Then RecFileSearch($current & "\" & $file)
    WEnd
    FileClose($search)
EndFunc
Link to comment
Share on other sites

CD - You're right... I gave up too easily.

LxP - it was the Dos method (yours I think? Name looked familiar) that I tried that took 15 minutes.

CD - You didn't have to do that!! But thanks!!! That is far less code than anything I've seen so far, so at the very least it helps me to grasp the concepts a lot better!!! However, either you have a much faster computer than I (P4 3.2 1GB Ram) or I just have far more files than you. I ran your code an it took 168.351 seconds... still, FAR faster than the other method!

I want to explore the idea of breaking this down and only running the function for a folder when they hit the + in the treeview... but I fear I'm right back into the loopy loops again! lol

Let me try to better explain exactly what I want done.

There's a gui... it includes a treeview list. To start with, it will show each of the drives. When you hit the + it shows the folders (no files - don't want files) in the next level. I got that far with this:

#include <GUIConstants.au3>
#Include <File.au3>


Dim $DriveLetters = DriveGetDrive ( "fixed" )
Dim $ShowDriveLetters[$DriveLetters[0]+1]
Dim $ShowFolders[9999]
GUICreate("My GUI with treeview", 500, 500)
$treeview = GUICtrlCreateTreeView(6, 6, 488, 488, -1)
For $i = 1 to $DriveLetters[0]
    $ShowDriveLetters[$i] = GUICtrlCreateTreeViewItem($DriveLetters[$i], $treeview)
    $ReadIn = _FileListToArray ( $DriveLetters[$i], "*", 2 );brings in all folders in the root level
    For $j = 1 to $ReadIn[0]
        $ShowFolders[$j] = GUICtrlCreateTreeViewItem($ReadIn[$j], $ShowDriveLetters[$i])
    Next
Next

GUISetState ()
While 1
    $msg = GUIGetMsg()
    Select
        Case $msg = $GUI_EVENT_CLOSE
        ExitLoop
    EndSelect
WEnd

GUIDelete()
Exit

So that's fine, but I need it to dive deeper into the 3rd, 4th, 5th... Nth levels. That's where I just have gotten lost. Everytime I think I'm onto something I realize I've logically screwed it up and I'm back to where I was.

Once I figure out this part of it... the next step is to have code so that when they click an individual folder (not the +) more gui controls will show to the right giving options for that folder.

But if it takes several minutes to generate the gui then its not worth the effort and I'm better off having the user simply pick the folders one at a time using the SelectFolder dialogue.

The purpose of all this is for the user to flag which folders they want archived (and depending on the options they select will determine how to archive it).

I'll keep chugging away! Thanks for the welcome, the encouragement, and the help!!!

LD

Link to comment
Share on other sites

CD - You're right... I gave up too easily.

LxP - it was the Dos method (yours I think? Name looked familiar) that I tried that took 15 minutes.

CD - You didn't have to do that!! But thanks!!! That is far less code than anything I've seen so far, so at the very least it helps me to grasp the concepts a lot better!!! However, either you have a much faster computer than I (P4 3.2 1GB Ram) or I just have far more files than you. I ran your code an it took 168.351 seconds... still, FAR faster than the other method!

I want to explore the idea of breaking this down and only running the function for a folder when they hit the + in the treeview... but I fear I'm right back into the loopy loops again! lol

Let me try to better explain exactly what I want done.

There's a gui... it includes a treeview list. To start with, it will show each of the drives. When you hit the + it shows the folders (no files - don't want files) in the next level. I got that far with this:

#include <GUIConstants.au3>
#Include <File.au3>
Dim $DriveLetters = DriveGetDrive ( "fixed" )
Dim $ShowDriveLetters[$DriveLetters[0]+1]
Dim $ShowFolders[9999]
GUICreate("My GUI with treeview", 500, 500)
$treeview = GUICtrlCreateTreeView(6, 6, 488, 488, -1)
For $i = 1 to $DriveLetters[0]
    $ShowDriveLetters[$i] = GUICtrlCreateTreeViewItem($DriveLetters[$i], $treeview)
    $ReadIn = _FileListToArray ( $DriveLetters[$i], "*", 2 );brings in all folders in the root level
    For $j = 1 to $ReadIn[0]
        $ShowFolders[$j] = GUICtrlCreateTreeViewItem($ReadIn[$j], $ShowDriveLetters[$i])
    Next
Next

GUISetState ()
While 1
    $msg = GUIGetMsg()
    Select
        Case $msg = $GUI_EVENT_CLOSE
        ExitLoop
    EndSelect
WEnd

GUIDelete()
Exit

So that's fine, but I need it to dive deeper into the 3rd, 4th, 5th... Nth levels. That's where I just have gotten lost. Everytime I think I'm onto something I realize I've logically screwed it up and I'm back to where I was.

Once I figure out this part of it... the next step is to have code so that when they click an individual folder (not the +) more gui controls will show to the right giving options for that folder.

But if it takes several minutes to generate the gui then its not worth the effort and I'm better off having the user simply pick the folders one at a time using the SelectFolder dialogue.

The purpose of all this is for the user to flag which folders they want archived (and depending on the options they select will determine how to archive it).

I'll keep chugging away! Thanks for the welcome, the encouragement, and the help!!!

LD

it would be very easy to modify my code to do what you want. i try to stay away from subjective terms like "easy" but i mean that you wouldn't have to make alot of changes. All you have to do is take my script, put it to it's own file, and include it into yours. the Func and output file are all you really need. then when the user clicks on a folder in your treelist, call my function, passing the full path of the folder they clicked on. it will recursively search from that point down the tree, and write the output file, which you could read in to create the sub-trees.

***edit*** as far as how long it took on your pc, my computer is slower, but probably has alot fewer files as it is a brand new work machine, with AutoIT and the tools i need for my job being the only additions to a clean install. You can look at the size of the output file to see the diff, mine is only 1,802 K

Edited by cameronsdad
Link to comment
Share on other sites

$tosearch = "C:"
$output = FileOpen("c:\filelist.txt",2)
Global $deep = 0
$start = TimerInit()
RecFileSearch($tosearch)
FileClose($output)
MsgBox(0,"done","it only took " & int(TimerDiff($start)/1000) & " seconds")
Func RecFileSearch($current)
    $deep = $deep +1
    Local $search = FileFindFirstFile($current & "\*.*")
    While 1
    Dim $file = FileFindNextFile($search)
    If @error Or StringLen($file)<1 Then ExitLoop
    FileWriteLine($output,$current & "\" & $file & "     " & FileGetSize($file))
    If StringInStr(FileGetAttrib($current & "\" & $file),"D") And ( $file <> "." Or $file <> ".." ) Then RecFileSearch($current & "\" & $file)
    WEnd
    FileClose($search)
EndFunc
Just a couple questions about your code above:

1) FileClose($search). What is this for? I don't see a filehandle "$search" ever being opened.

2) What purpose does $deep serve?

Please don't take that as me being critical... I just don't see any purpose for those lines and I want to be sure I'm not missing anything. I deleted them and it seemed to work so I presume you had some ideas for them and didn't bother to take them out??? is that right?

This is totally cool though! I honestly somehow missed the whole concept of calling a function from within itself! I had no idea you could do that! I think that was the key I was looking for.

Thanks!

Link to comment
Share on other sites

Just a couple questions about your code above:

1) FileClose($search). What is this for? I don't see a filehandle "$search" ever being opened.

2) What purpose does $deep serve?

Please don't take that as me being critical... I just don't see any purpose for those lines and I want to be sure I'm not missing anything. I deleted them and it seemed to work so I presume you had some ideas for them and didn't bother to take them out??? is that right?

This is totally cool though! I honestly somehow missed the whole concept of calling a function from within itself! I had no idea you could do that! I think that was the key I was looking for.

Thanks!

1) it's the handle assigned to the FileFindFirstFile() on the same line that it's declared Locally (2 lines under the func start)

2)that one was a slip on my part, i was using that during the debugging when i was writing it, then didn't take it out even after i took out the lines that used it... i'm bad about orphan code like that. I caught it later in the day and took it out of other examples, but it was still in this one. it doesn't affect the script, except for making it look a little sloppier... if you want a fully commented copy of the same script, i commented it later and attached it for the thread: File > Delete or something like that...

Link to comment
Share on other sites

Thanks. Didn't realize you needed to release the handle.

Alas, I've gone in circles again and can't figure out how to make it work in the GUI :P

I know you don't like the "giving up" bit... but really, there's a solution that is so much less work (i'm already 2 man-days behind on this) and will provide the user with a faster interface. Sacrifice usability for speed... I think its worth it here.

The obsessive compulsive in me wants to finish this... but I'm pretty convinced from preliminary results that the end product will be unacceptable... so the practical side of me doesn't want to waste more days just to prove it.

Am I wrong?

Getting the computer's folder structure has been proven hard enough (but thank you for getting that solved!)... now I have to take that information and create the GUI from it... THEN, I need each of the potentially tens of thousands of dynamically created gui controls to call functions individually. I don't think the scalability is there.

I'm pretty sure this is possible. I'm not sure its practical.

The alternative, which isn't so bad, is for the user to select the folders one at a time with the FileSelectFolder function. It doesn't offer the user the visual cues that the FileTree view would provide... but I'm thinking its "good enough" and has other advantages that makes it the way to go.

LD

Link to comment
Share on other sites

Thanks. Didn't realize you needed to release the handle.

Alas, I've gone in circles again and can't figure out how to make it work in the GUI :P

I know you don't like the "giving up" bit... but really, there's a solution that is so much less work (i'm already 2 man-days behind on this) and will provide the user with a faster interface. Sacrifice usability for speed... I think its worth it here.

The obsessive compulsive in me wants to finish this... but I'm pretty convinced from preliminary results that the end product will be unacceptable... so the practical side of me doesn't want to waste more days just to prove it.

Am I wrong?

Getting the computer's folder structure has been proven hard enough (but thank you for getting that solved!)... now I have to take that information and create the GUI from it... THEN, I need each of the potentially tens of thousands of dynamically created gui controls to call functions individually. I don't think the scalability is there.

I'm pretty sure this is possible. I'm not sure its practical.

The alternative, which isn't so bad, is for the user to select the folders one at a time with the FileSelectFolder function. It doesn't offer the user the visual cues that the FileTree view would provide... but I'm thinking its "good enough" and has other advantages that makes it the way to go.

LD

the end result is the most important part of any project. Personally i would say to work on it (off the clock) just so that you can say that you got it to work. I think that you're really over-thinking it, believe it or not. if you are already comfortable using a fileselectfolder, why not have them do that, then list the sub files and folders from there? I can't write more code for you because i don't know exactly what you want to do. if you're able to write a working script to accomplish the end result you want, post it, and i'll see if i can't convert it to work the way you want it to. But i can promise you from experience, if you let go of it for a little while, work on another project or something, and then come back and read this thread, you'll read it differently and be able to accomplish what you want without further help.
Link to comment
Share on other sites

hi,

There are a couple of other links that could help, though I can't find them on the forum right now!

ExploreAU3

Autoit3Explorer.au3

Just so we don't have to re-invent the wheel....

There was "going" to be a UDF....?

Randall

Link to comment
Share on other sites

hi,

There are a couple of other links that could help, though I can't find them on the forum right now!

ExploreAU3

Autoit3Explorer.au3

Just so we don't have to re-invent the wheel....

There was "going" to be a UDF....?

Randall

I'm going to try and figure out how to get the autoit3explorer.au3 to work with network shares :P

I'm trying to create a script to create folders and automatically copy files based on input in a full gui

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...