|
POST
|
I suppose I was a bit vague. I mean that the gp.JoinField() takes a long time because it is adding a field or fields and calculating the data over into them. I want to avoid python code blocks in field calculator which is why I want to use a update cursor. Can anyone speak to the function of the update cursor on joined tables in v10? You cannot do an update cursor on a joined table directly. However, if you can define a query expression that will perform your selection and are not just working on a random user SelectionSet, the code below should work about as efficiently as doing the calculation directly on the joined table (and much more efficiently if you were using python calculations and not VB Script). Public Sub GetLayerSelection2()
Dim pMxDoc As IMxDocument
Set pMxDoc = ThisDocument
Dim pFLayer As IFeatureLayer
Set pFLayer = pMxDoc.FocusMap.Layer(0) 'Get first layer
Dim pQueryFilter As IQueryFilter
Set pQueryFilter = New QueryFilter
pQueryFilter.WhereClasue = "ParentTableName.OBJECTID > 0" ' do some sort of selection on the joined table
If Not TypeOf pDisplayTable.DisplayTable Is IRelQueryTable Then
MsgBox "Feature Layer is not joined! Exiting Sub."
Exit Sub
End If
Dim pDisplayTable As IDisplayTable ' Variable for the joined features
Set pDisplayTable = pFLayer
Dim pFCursor As IFeatureCursor
set pFCursor = pDisplayTable.SearchDisplayTable(pQueryFilter, False)
Dim pFeature As IFeature
Set pFeature = pFCursor.NextFeature
Dim pFeatureClass as IFeatureClass ' Variable for the unjoiined features
Set pFeatureClass = pFLayer
pQueryFilter.WhereClasue = "OBJECTID > 0" ' do the same selection on the unjoined table
Dim pUpdateCursor As IFeatureCursor
Set pUpdateCursor = pFeatureClass.Update(pQueryFilter, False)
Dim pFeature2 As IFeature
Set pFeature2 = pUpdateCursor.NextFeature
Dim pJoinIndex As Long
pJoinIndex = pDisplayTable.DisplayTable.Fields.FindField("JoinTableName.JoinField") ' Substitute the actual Join Table and Field names
If pJoinIndex = -1 Then
MsgBox "JoinTableName.JoinField Field Not Found! Exiting Sub." ' Substitute the appropriate message.
Exit Sub
End If
Dim pFieldIndex As Long
pFieldIndex = pFeature.Fields.FindField("FieldName") ' Get an unjoined field of the parent FC to update
If pFeatureIndex = -1 Then
MsgBox "FieldName Field Not Found! Exiting Sub." ' Substitute the appropriate message
Exit Sub
End If
Do Until pFeature Is Nothing ' Feature and Feature2 used the same query and run in synch.
pFeature2.Value(pFieldIndex) & " = " & pFeature.Value(pJoinIndex) ' transfer value of join field to field
pUpdateCursor.UpdateFeature = pFeature2
Set pFeature2 = pUpdateCursor.NextFeature ' Get the next unjoined feature
Set pFeature = pFCursor.NextFeature ' Get the next matching joined feature
Loop
End Sub To work with a SelectionSet, you would have to translate the user selection to a whereclause expression so that you would match it on both the joined displaytable and the unjoined featureclass update cursor. If the query expression required the join to work, then the selection would have to be done on the displaytable and an equivalent whereclause using OID values would have to be built to get the same selectionset on the unjoined featureclass. The code only works efficiently and correctly if the same set of records are selected on the parent unjoined FC update cursor and the joined FC search cursor. I still think that VB Script expressions in the calculator are fine to use on joined data in most cases and would probably use the gp.JoinField() most of the time (VB Script expressions work within python scripts in the fieldcalculator as long as they do not require use of the code block). Most of the time I do not need to use python code blocks on joined tables. (This is VBA, but could be translated to VB.NET fairly easily. In any case, the underlying logic of running parallel cursors would have to be employed if this were translated to python as well. If you wanted python I chose to ignore that point, because I don't know python that well to translate it. But the principles of the code above should still apply to python. Without being able to create some kind of parallel cursors the data from the join would probably have to be loaded to a dictionary and then writen to an unjoined update cursor, but getting identical selection sets is still key to running any process that would improve on the speed of a VB Script field calculation).
... View more
10-07-2010
05:38 PM
|
0
|
0
|
1350
|
|
POST
|
Verified that (9.3.1 SP1) an updatecursor does NOT work with a featurelayer/table view created with the MakeQueryTable tool. I will submit a bug report to ESRI. The field calculator is disabled on the MakeQueryTable result as well. I believe this behavior is intentional, because the MakeQueryTable support 1:M and M:M relationships as well as 1:1 and M:1 relationships. Edits on one record of the in memory table could easily be overwritten with a totally different value by the same calculation through the next record processed. The value you would wind up with would be dependent on the record order, which would make the result effectively random. Only after the table is exported to a permanent file would all of the records be processed independently and all of the results of a calculation would be preserved without overwriting, which is what ESRI supports I do not, however, understand why standard joiins can use the field calculator and not an updatecursor.
... View more
10-06-2010
02:27 PM
|
0
|
0
|
1350
|
|
POST
|
I've tried using JoinField and then using CalculateField. But with a large data set, as small as 100,000 records,this method takes way to long to be practical. Did you do the calculation with a python expresssion or a VB Script expression? A python expresssion will take 7 to 20 times as long to process as an equivalent VB Script expression on a joined table. I do join calculations all the time in python scripts with 100,000 records and using VB Script expressions. They usually take about 2 minutes or less per calculation, which I do not consider to be excessive (but if I had used a python expression the same calculation can take anywhere from 14 to 45 minutes, which is excessive).
... View more
10-06-2010
02:14 PM
|
0
|
0
|
1350
|
|
POST
|
I think if you give nothing as the queryfilter to ISelectionSet.Search, it will return all the records as a cursor. Sean: You are correct, using Nothing with as SelectionSet.Search method returns whatever records are already currently selected (and not the entire set of features). That is how my code is set up to behave. However, I was hoping to use the Update method to return a cursor from the FeatureClass instead of a SelectionSet Search method. If I use a query filter of Nothing with that method, all of the features of the feature class are returned for the cursor and not just the features that were already selected in the SelectionSet. If there were an Update method for the SelectionSet that would be ideal, but such a method is not available. Since a SelectionSet can be purely a user selection that may not have any apparent query where clause logic beyond the list of OID values, the only way I know how to reliably translate a SelectionSet to a whereclause is to list every OID value using an IN statement. I could build such a where clause by reading the IEnumIDs object from the SelectionSet, but that effectively causes another read of the selected features and the where clause I build might potentially exceed the allowed length of a string object if a lot of features are selected. I was hoping there is another alternative, but if nothing else is possible, that would be my approach. That approach should still be worth the trouble, since I expect that building a where clasue to use Update Cursors would still be much faster than using the Store method in combination with a Search Cursor.
... View more
10-05-2010
01:29 PM
|
0
|
0
|
686
|
|
POST
|
My join table is a standalone SQL table in a non-SDE database. I've found that if I join to a table within an SDE database then I have to use fully qualified table/field names, but not if to a non-SDE table. What I've got is a tool (in .Net) that loops through selected points, creates a line from each point, and then takes some attributes from that point and writes it to the line. The join is on the point feature class, and I am wanting to take a value from the join table and put it on the line. Mike. I tried your code with a file geodatabase and it requried the fully qualified table name and field name, so the behavior is not limited to an SDE geodatabase. But whatever works. Since your line features are not part of the code you have written and all your code accesses currently is the point feature class, you do not need the emedded loops to read the joined table. You also will not need embedded loops if you are going to simply construct one line from the points, since you would then just be writing to one feature and you can access all of the fields you need including the shape field of the parent table from the ICursor object derived from the IDisplayTable. However, if you are going to construct more than one line from a set of points based on some attrribute you would then need a set of embedded loops to control the creation of each line feature and the writing of the point attribute. My latest code is writen with the intent of addressing the broader question that keeps coming up on the forum of how do you use an update cursor on a joined table. It is very close to doing that if the SelectionSet of the parent Feature Class could be translated to an update cursor instead of a search cursor. (It can be done by buiilding a where clause from the OID values, but that would entail an extra read of the data, which would be nice to avoid, as well as creation of a potentially very long clause if many features are selected).
... View more
10-05-2010
12:00 PM
|
0
|
0
|
1588
|
|
POST
|
Take a look at the IGeoFeatureLayer interface for another method to get at the values on joined fields (IGeoFeatureLayer.SearchDisplayFeatures). It might be an easier approach. Sean: I looked at that interface, but that method is available already on the IDisplayTable and the help for IGeoFeatureLayer suggest using the IDisplayTable interface since it is more generic (it works with joined featureclasses and standalone tables). The other disadvantage of the IGeoFeatureLayer is that it requires the construction of a queryfilter and has no direct access to the existing SelectionSet for the layer. The code as writen is using whatever is already selected and the IDisplayTable provides fairly direct access to the SelectionSet for both the unjoined parent featureclass (or StandaloneTable) and the joined table data. What would be most useful at this point is a suggestion for the most direct way to transfer the records of a SelectionSet over to an Update Cursor without constructing a potentially huge whereclause.
... View more
10-05-2010
10:29 AM
|
0
|
0
|
1588
|
|
POST
|
I have revised your code to make it more efficient. Your code is slow because it uses repeated queries inside of a loop (it also was repeatedly doing a Dim of the Row variable inside the loop as well, which is a big no no. Never do a Dim inside of a loop). I realized that since you are accessing the same SelectionSet for the same parent feature class through the same layer that you do not need to use a queryfilter in the loop to synchronize the reading of the parent feature class and the joined table. To prove that the cursors on the unjoined featureclass and the joined displaytable are running in synch, I substituted reading the parent table ObjectID feilds in the code below. You can revise this code back to replacing the fields with your original fields (again if all you want to do is just read the joined data, just use the display table SelectionSet together with either the ParentTableName.FieldName or JoinTableName.FieldName formats for the fields you want to read). Now ideally this code could be further modified to use an efficient method that would substitute an update cursor for reading through the SelectionSet of the parent feature class instead of using a search cursor. That way the code would allow reading of data from the joined displaytable and writing to the features of the parent FeatureClass in a single pass, with efficiency that is similar to using a FieldCalculator with a VBA or VB Script expression on a joined table. Public Sub GetLayerSelection2()
Dim pMxDoc As IMxDocument
Set pMxDoc = ThisDocument
Dim pFLayer As IFeatureLayer
Set pFLayer = pMxDoc.FocusMap.Layer(0) 'Get first layer
Dim pDisplayTable As IDisplayTable
Set pDisplayTable = pFLayer
If Not TypeOf pDisplayTable.DisplayTable Is IRelQueryTable Then
MsgBox "Feature Layer is not joined! Exiting Sub."
Exit Sub
End If
Dim pSelSet As ISelectionSet
Set pSelSet = pDisplayTable.DisplaySelectionSet
Dim pCount As Long ' Use Integer only if this is VB.Net and not VBA.
pCount = pSelSet.Count
If pCount > 5 Then
MsgBox "Too many features selected. Please select 5 or less." 'Was quite slow, but now probably no longer necessary
Exit Sub
End If
Dim pTableCursor As ICursor
pSelSet.Search Nothing, True, pTableCursor
Dim pRow As IRow
Set pRow = pTableCursor.NextRow
Dim pFSel As IFeatureSelection
Set pFSel = pFLayer
Dim pSelSet2 As ISelectionSet
Set pSelSet2 = pFSel.SelectionSet
Dim pFCursor As IFeatureCursor
pSelSet2.Search Nothing, True, pFCursor
Dim pFeature As IFeature
Set pFeature = pFCursor.NextFeature
Dim pTableIndex As Long
pTableIndex = pDisplayTable.DisplayTable.Fields.FindField("ParentTableName.OBJECTID") ' Substitute the actual ParentTableName or use JoinTableName.FieldName
If pTableIndex = -1 Then
MsgBox "ParentTableName.OBJECTID Field Not Found! Exiting Sub." ' Substitute the appropriate message.
Exit Sub
End If
Dim pFeatureIndex As Long
pFeatureIndex = pFeature.Fields.FindField("OBJECTID")
If pFeatureIndex = -1 Then
MsgBox "OBJECTID Field Not Found! Exiting Sub."
Exit Sub
End If
Do Until pFeature Is Nothing ' Keep your loop as tight as possible and do not do Dim statements inside of it.
Debug.Print pFeature.Value(pFeatureIndex) & " = " & pRow.Value(pTableIndex) ' report value of field in join table
Set pRow = pTableCursor.NextRow
Set pFeature = pFCursor.NextFeature
Loop
End Sub
... View more
10-05-2010
08:49 AM
|
0
|
0
|
1588
|
|
POST
|
I tried your code and don't understand why it works for you at all. When I used it on a joined feature layer I got errors when I tried to just use a field name in the join table. I had to use the fully qualified table name and field name to obtain the display table field index and a correctly formatted query where clause inside of the loop to access the joined field name. I could not just use an unqualified field name as you seem to be doing. I am assuming you intend to write data to the parent feature class and not just read the data of the joined table. Otherwise, if all you wanted to do was read data you should be able to just use the display table without having to use the parent feature class and a pair of embedded loops on the parent feature class and on the display table. To just read data you should bypass the FeatureSelection and just set the SelectionSet to the DisplaySelectionSet of the display table and loop through it to get your key and joined field together (using the fully qualified table name and field name of the joined table). So what is this code really supposed to end up doing for you? If you need to use it to write to the parent table (or you actually have a 1:M or M:M relationship), then the embedded loops are probably necessary.
... View more
10-04-2010
10:14 PM
|
0
|
0
|
1588
|
|
POST
|
You can tighten up the loop a little by taking out the field tests outside of the loops as follows: Dim pTableIndex As Long
pTableIndex = pTable.Fields.FindField("SERVSTAT") ' Field to be found in join table
If pTableIndex = -1 Then
msgbox "SERVSTAT field not found. Exiting Sub."
Exit Sub
End If
Dim pFeatureIndex As Long
pFeatureIndex = pFeature.Fields.FindField("COMPKEY")
If pFeatureIndex = -1 Then
msgbox "COMPKEY field not found. Exiting Sub."
Exit Sub
End If
Do Until pFeature Is Nothing
strQuery = "COMPKEY = " & pFeature.Value(pFeatureIndex) 'Use join field (COMPKEY) to find matching record in table
pQFilter.WhereClause = strQuery
Set pTableCursor = pTable.Search(pQFilter, False)
Dim pRow As IRow
Set pRow = pTableCursor.NextRow
Do Until pRow Is Nothing
Debug.Print pRow.Value(pTableIndex) ' report value of field in join table
Set pRow = pTableCursor.NextRow
Loop
Set pFeature = pFCursor.NextFeature
Loop
... View more
10-04-2010
09:23 PM
|
0
|
0
|
1588
|
|
POST
|
I have searched the old and new forums and not seen any code that inserts new records into a Linear Reference Event Feature Layer using VBA. After some experimenting I found it was not possible to insert the features directly into the LR Event Layer, but it was possible to insert them into the underlying event table. The code below is what I came up with. It duplicates selected LR Event Features by inserting copies into the underlying Event table (I use it to split LR line features when changes in my sidewalk network occur). The code also reselects the original and new duplicated features so that they will display in the LR Event Feature Layer's Tableview. I hope this helps. Sub AddLRRecord()
' Get a reference to the Event Layer through the map.
Dim pMxDoc As IMxDocument
Set pMxDoc = ThisDocument
Dim pMap As IMap
Set pMap = pMxDoc.FocusMap
Dim pLayer As ILayer
Dim i As Long
For i = 0 To pMap.LayerCount - 1
Set pLayer = pMap.Layer(i)
If pLayer.Name = "SIDEWALKS Events" Then
Exit For
End If
Next i
If pLayer Is Nothing Then
MsgBox "Layer Not Found"
Exit Sub
End If
Dim pFLayer As IFeatureLayer
Set pFLayer = pLayer
' Get the LR Event layer's Selection Set.
Dim pFSel As IFeatureSelection
Set pFSel = pFLayer
Dim pSelSet As ISelectionSet
Set pSelSet = pFSel.SelectionSet
' Create a where clause to select records from underlying event table using OID values.
Dim pEnumIDs As IEnumIDs
Set pEnumIDs = pSelSet.IDs
Dim strWhere As String
strWhere = """OBJECTID"" IN ("
Dim lID As Long
pEnumIDs.Reset
lID = pEnumIDs.Next
Do While lID <> -1
strWhere = strWhere & lID & ","
lID = pEnumIDs.Next
Loop
strWhere = Left(strWhere, Len(strWhere) - 1) & ")"
If strWhere = """OBJECTID"" IN )" Then ' Make sure something was selected
MsgBox "No Sidewalks selected"
Exit Sub
End If
' Select the records in the underlying event table.
Dim pQF As IQueryFilter
Set pQF = New QueryFilter
pQF.WhereClause = strWhere
Dim pRouteEventSource As IRouteEventSource ' This is the interface for getting the Event Table
Set pRouteEventSource = pFLayer.FeatureClass
Dim pTable As ITable
Set pTable = pRouteEventSource.EventTable
Dim pCursor As ICursor
Set pCursor = pTable.Search(pQF, False)
' Copy the records and prepare a new where clause to select original and new features in the LR Event layer.
Dim pICursor As ICursor ' Set up insert cursor for underlying event table.
Set pICursor = pTable.Insert(True)
Dim pRowB As IRowBuffer
Set pRowB = pCursor.NextRow
Dim lFIDC As Long
lFIDC = pRowB.Fields.FindField("FID_CENTERLINE")
Dim lRoadSide As Long
lRoadSide = pRowB.Fields.FindField("ROAD_SIDE")
strWhere = """FID_CENTERLINE"" IN (" ' Create a new query for selecting in LR Event layer.
Dim strWhere2 As String
strWhere2 = " AND ""ROAD_SIDE"" IN ("
Do While Not pRowB Is Nothing
pICursor.InsertRow pRowB ' This duplicates the record in the event table.
strWhere = strWhere & pRowB.Value(lFIDC) & "," ' Adding records to where clause.
strWhere2 = strWhere2 & "'" & pRowB.Value(lRoadSide) & "',"
Set pRowB = pCursor.NextRow
Loop
strWhere = Left(strWhere, Len(strWhere) - 1) & ")"
strWhere2 = Left(strWhere2, Len(strWhere2) - 1) & ")"
strWhere = strWhere & strWhere2
' Reselect original records and duplicated records in the event layer.
pQF.WhereClause = strWhere
pFSel.SelectFeatures pQF, esriSelectionResultNew, False
Set pSelSet = pFSel.SelectionSet ' A SelectionSet will show selection in user tableview.
End Sub
... View more
10-01-2010
12:24 PM
|
0
|
1
|
3114
|
|
POST
|
You did not say which version and licence level of ArcGIS you are using or if this is a one time process or something that needs to be run multiple times. However, I normally approach this type or problem in 3 steps. The first step is to get the data in order. If it is already ordered on your basiin field the objectID should provide your base sequencing values. If it is not in order and you are using ArcGIS 10 with an ArcInfo licence there is a built-in permanent sort records tool that will sort on your basin field. If you have ArcGIS 9.3 you can use the script and tool at this post: http://forums.arcgis.com/threads/12385-(Again-Sorry)-Serial-number-for-the-records-in-the-attribute-table?p=37288#post37288 You also could use ET Geowizard from http://www.ian-ko.com/. It has a permanent sort tool that is included in the subset of tools that are available for free with unlimited use. Based on your descriptionm, you may first want to develop a query where you get just the values that have no numeric portion to do your sort on. The query might work if it was something like: NOT("BASIN" Like '_0%' or "BASIN Like '__0%') Once the data is ordered, I perform a Summary on the basin field and get the Min ObjectID value. Getting the Min ObjectID value may involve creating a field and calculating the OID values into it, since for some reason the Summary field does not like using the ObjectID field itself as a summary input. (It may be possible just to type in the ObjectID field name and avoid that extra step, but I have not tried it). ONce you have the summary, you could also add another field to the summary table create your unique offset values for each basin value at this point. If this is a one time set up just do it manually. Now you perform a join and calculate the sequenctial field. Using pseudo VBA (for 9.3) the value you want will be: [OrigTable.Basin] & format([OrigTable.ObjectID] - [SumTable.MinObjectID] + [SumTable.Offset], "0000") If you have ArcGIS 10, do not use Python on the join calculation as it will run 20 to 50 times slower than VB Script. The VB Script expression would be: basinNum = [OrigTable.ObjectID] - [SumTable.MinObjectID] + [SumTable.Offset] If len(basinNum) < 4 Then [OrigTable.Basin] & left("0000", 4 - len(basinNum)) & basinNum Else [OrigTable.Basin] & basinNum End If Potentially this could also be done in ModelBuilder, but the unique starting number would have to be hard coded into a calculation. I hope this helps.
... View more
09-16-2010
05:38 PM
|
0
|
0
|
514
|
|
POST
|
I had that originally...tried changing it back just now, so script is currently import arcpy mxd = ("G:\search_zoom\search_zoom.mxd") df=arcpy.mapping.ListDataFrames(MXD, "Layers")[0] Layer = (mxd, "section", df)[0] df.zoomToSelectedFeatures(layer) df.scale = df.scale * 1.1 arcpy.RefreshActiveView() with error of: File "G:\kpw\arc_server\auto_assessment\search_zoom\zoom2selected2.py", line 3, in <module> df=arcpy.mapping.ListDataFrames(MXD, "Layers")[0] NameError: name 'MXD' is not defined I originally had the arcpy.mapping.... starting line 2 as well, but that gave me the same error, so I removed it and just went straight to a direct reference and then it read fine until the next arcpy.mapping.... What am I missing? Python is case sensitive and the error is indicating that you have changed the case of the mxd variable in the 3rd line, which rather than using the assignment of the variable in the second line is being interpreted as a new unassigned variable. You have the same problem with the variable called Layer/layer. Be consistent with your variable spelling cases. Change the code to: import arcpy
mxd = ("G:\search_zoom\search_zoom.mxd")
df=arcpy.mapping.ListDataFrames(mxd, "Layers")[0]
Layer = (mxd, "section", df)[0]
df.zoomToSelectedFeatures(Layer)
df.scale = df.scale * 1.1
arcpy.RefreshActiveView()
... View more
09-10-2010
10:23 AM
|
0
|
0
|
3300
|
|
POST
|
I do not yet have ArcGIS 10, but the help for the tool lists a set of specific requirements of the input polygon layer that put some pretty severe limits on what will work with the tool. http://help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#//007000000009000000.htm Are you sure that you have a polygon layer that matches all of the requirements? (I can see I will need to continue to update and use the custom coded MapBook application code I have developed, since there is no way I can make my map series conform to these limitations in any way.)
... View more
09-10-2010
08:48 AM
|
0
|
0
|
1565
|
|
POST
|
(Edited) I have deleted my original suggestion after rereading your code. I realized I had misread the code and that my suggestion about the class name capitalization could not be the source of the problem (and your revised code proves that). I just don't like the idea of using arcgis as a class name or variable, since it could be a word that ESRI may reserve at some time (or may have already reserved based on the fact that you seem to think that your code is generating a conflict with an existing resource). Try changing the arcgis variable name to something else and see if the same error is generated. If it is, something other than a conflicting resource is at work. I also just noticed your comment where your wrote "# Give the object any other name than 'arcgis' and it works..". This indicates that arcgis is a reserved name in some form. I have not looked for documentation on that being a reserved word, but based on your code's behavior it does seem like that is somehow at the root of the code failure. (I also agree that the namespaces should prevent the conflict normally, but if somehow namespace ambiguity arises then I guess odd behaviors are possible if the namespaces are not clarified. At least that is the case in .NET. Most likely the import of arcgisscripting introduces an arcgis object from that namespace and your code creates ambiguity with that object name.)
... View more
09-04-2010
07:45 AM
|
0
|
0
|
905
|
|
POST
|
Just a note to improve performance on a portion of the code Jeff provided. Make it a practice to get the index of any field outside of the loops you create and directly use the field index in the loop. The FindField operation does a schema search loop that really only needs to be done once outside of your loop. Repeating loops within loops drags down performance. Using the index value directly inside the loop acts like direct array access to the field and does not cause a secondary hidden loop to occur for every record your loop processes. (From best practices with cursors training at the ESRI conference). So the sample code should be revised as follows:
Dim pTableCursor As ICursor
Dim pRow As IRow
Set pTableCursor = pTable.Search(Nothing, True)
Set pRow = pTableCursor.NextRow
Dim fIndex as Long
fIndex = pTable.Fields.FindField("FeatureClass.FieldName") 'fully qualified field name from joined table
Do Until pRow Is Nothing
Debug.Print pRow.Value(fIndex) ' removes a hidden loop required to find the field
Set pRow = pTableCursor.NextRow
Loop Hope this helps.
... View more
09-02-2010
03:41 PM
|
0
|
0
|
1747
|
| Title | Kudos | Posted |
|---|---|---|
| 1 | 03-24-2026 08:01 PM | |
| 6 | 02-23-2026 08:34 AM | |
| 1 | 03-31-2025 03:25 PM | |
| 1 | 03-28-2025 06:54 PM | |
| 1 | 03-16-2025 09:49 PM |
| Online Status |
Offline
|
| Date Last Visited |
03-24-2026
07:54 PM
|