I set up a VBA routine in Word 2013 to create/display a calendar.
An array was set up for the weekdays, here's some of it:
Public arrDays As Variant
arrDays = Split("Mon,Tue,Wed,Thu,Fri,Sat,Sun,Mon,Tue,Wed,Thur,Fri,Sat,Sun", ",")
With .Rows(2)
.Cells.VerticalAlignment = wdAlignVerticalCenter
.Range.ParagraphFormat.Alignment = wdAlignParagraphCenter
.Range.Font.Name = "Calibri"
.Range.Font.Italic = True
.Range.Font.Size = 28
.Height = 24
For J = 1 To 7
.Cells(J).Range.Text = arrDays(J + lngFirstDay - 2)
Next J
End With
When I place the .Cells(J).Range.Text in the specified cell number it starts with "Sun";
The watch window shows:
arrDays(0) "Sun"; arrDays(1) "Mon"; arrDays(2) "Tue";....
Mo matter how I arrange the weekdays in the split, it is the same.
The calendar routine does work, it's just this Split thing
Info that should have been in the original post:
Start of Calendar selection
Watch list of arrDays
First day of workweek - Sunday
Second day of workweek
Complete Calendar
It is fixed.
I moved Public arrDays As Variant from CallCalForm to Declarations and moved
arrDays = Split("Mon,Tue,Wed,Thu,Fri,Sat,Sun,Mon,Tue,Wed,Thur,Fri,Sat,Sun", ",")
from beginning of CallCalForm to top Sub CommandButton1_Click().
I'm not sure if moving around made a difference, maybe I had a typo somewhere. If I change the order of arrDays the outcome corresponds to the change.
Related
I have seen examples on how to create an array of all the dates, or a date every month between a start date and end date here. However, I am trying to create an array of dates every 2 weeks specifically between a start and end date.
Ex. if startdate = 7/18/2021 and enddate = 12/28/2025, I want an array that is:
array = {7/18/2021, 8/1/2021, 8/15/2021, ..., 12/28/2025}
How exactly can I do this? I tried using a recorded macro but it only uses the xlFillDefault and doesn't actually specify the algorithm used.
Sub get2weekdates()
'
' get2weekdates Macro
'
'
ActiveCell.FormulaR1C1 = "7/18/2021"
Range("D6").Select
ActiveCell.FormulaR1C1 = "8/1/2021"
Range("D5:D6").Select
Selection.AutoFill Destination:=Range("D5:D121"), Type:=xlFillDefault
Range("D5:D121").Select
End Sub
The idea of the Function ArrayWithDates() is to take 2 parameters - the first day and the size as an optional one (in the example, 14 is 2 weeks, you may write 21 for 3 weeks or 20 for 2 weeks and 6 days).
Once it gets these, it enlarges the array based on the size with this line - ReDim result(size - 1). As the 0th element of the array is known, it is assigned outside the loop - result(0) = firstDay.
Then, in the loop, the other elements are assigned, and each one is the next day, using DateAdd():
Public Sub TestMe()
Dim i As Long
Dim myArray As Variant
myArray = ArrayWithDates(#7/18/2021#)
For i = LBound(myArray) To UBound(myArray)
Debug.Print i; myArray(i)
Next i
End Sub
Public Function ArrayWithDates(firstDay As Date, Optional size As Long = 14) As Variant
Dim i As Long
If size < 1 Then
ArrayWithDates = Array()
Exit Function
End If
ReDim result(size)
result(0) = firstDay
For i = 1 + LBound(result) To UBound(result)
result(i) = DateAdd("D", 1, result(i - 1))
Next i
ArrayWithDates = result
End Function
The result looks as expected:
Dates are just doubles that look like a date. we just need to loop and add 14 to the start till we hit the end date:
Sub get2weekdates()
With ActiveSheet
Dim strtdt As Double
strtdt = .Range("C1").Value2
Dim eddt As Double
eddt = .Range("c2").Value2
Dim nmDts As Long
nmDts = (eddt - strtdt) / 14 + 1
Dim otArray As Variant
ReDim otArray(1 To nmDts, 1 To 1)
Dim i As Long
For i = 1 To nmDts
otArray(i, 1) = strtdt + ((i - 1) * 14)
Next i
.Range("D5").Resize(nmDts, 1).Value = otArray
.Range("D5").Resize(nmDts, 1).NumberFormat = "mm/dd/yyyy"
End With
End Sub
But as stated by #pdtcaskey with Office 365 this can be a simple formula:
=SEQUENCE((C2 - C1)/14 + 1,, C1, 14)
Hopefully someone can help me? I have 2 list boxes RndAdd1 & RndEdit1. I want to be able to multi select items in RndAdd1 and then click Button1 and it loops through selected items and one at a time adds them to the new range (first blank cell) until all items added. Then remove all the values just added from the original range. (basically move from Column A to Column B for Monday, Column C to D for Tuesday and so on)
I also have another variable set (which day of the week) I have the following code I was going to place on the button then nest a series of if/Elseif statements.
The trouble I'm having currently is that it posts the first value in the first blank cell, then the 2nd value overwrites the first value and so on until only the final value is now visible in the new range. This is probably a simple fix and I'm just not thinking of it in the correct way!
Dim lItem As Long
For lItem = 0 To RndAdd1.ListCount - 1
If RndAdd1.Selected(lItem) = True Then
If ComboBox1.Value = "Monday" Then
Sheets("Setup").Range("B65536").End(xlUp)(0, 1) = RndAdd1.List(lItem)
RndAdd1.Selected(lItem) = False
End If
End If
Next
RndAdd1.Clear
RndEdit1.Clear
ComboBox1.Clear
ComboBox1.List = Array("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")
ComboBox1.Value = "Monday"
'Tuesday Repeat Code but with different range to take round numbers from
I'm on my phone so cannot post code buy maybe this can help you:
Dim TargetRange as range
Set TargetRange = thisworkbook.sheets(1).range("A1") 'or whereever you want it
Do until IsEmpty(TargetRange.value)
Set targetrange = targetrange.offset(1,0)
Loop
TargetRange.value = "your value here"
This loops down until it finds an empty cell
Hope it helps
substitute
Sheets("Setup").Range("B65536").End(xlUp)(0, 1) = RndAdd1.List(lItem)
with
With Sheets("Setup")
.Range(.Rows.Count, "B").End(xlUp).Offset(1) = RndAdd1.List(lItem)
End With
I have a macro that so far, adds 4 new table columns to an existing table ("Table1"). Now, I would like the macro to format the 3rd and 4th row as percentage. I would like to include this in the loop already listed in my code. I have tried several different ways to do this. I don't think I quite understand how the UBound function works, but hopefully you can understand what I am trying to do.
I also am unsure if I am allowed to continue to utilize the WITH statement in my nested For loop in regards to me 'lst' variable.
#Jeeped - I'm looking at you for this one again...thanks for basically walking me through this whole project lol
Sub attStatPivInsertTableColumns_2()
Dim lst As ListObject
Dim currentSht As Worksheet
Dim colNames As Variant, r1c1s As Variant
Dim h As Integer, i As Integer
Set currentSht = ActiveWorkbook.Sheets("Sheet1")
Set lst = ActiveSheet.ListObjects("Table1")
colNames = Array("AHT", "Target AHT", "Transfers", "Target Transfers")
r1c1s = Array("=([#[Inbound Talk Time (Seconds)]]+[#[Inbound Hold Time (Seconds)]]+[#[Inbound Wrap Time (Seconds)]])/[#[Calls Handled]]", "=350", "=[#[Call Transfers and/or Conferences]]/[#[Calls Handled]]", "=0.15")
With lst
For h = LBound(colNames) To UBound(r1c1s)
.ListColumns.Add
.ListColumns(.ListColumns.Count).Name = colNames(h)
.ListColumns(.ListColumns.Count).DataBodyRange.FormulaR1C1 = r1c1s(h)
If UBound(colNames(h)) = 2 or UBound(colNames(h)) = 3 Then
For i = UBound(colNames(h), 2) To UBound(colNames(h), 3)
.ListColumns(.ListColumns.Count).NumberFormat = "0%"
End if
Next i
Next h
End With
End Sub
You don't need to nest a second for loop. If you want to set the 3rd and 4th columns to a percentage, you only need to set that when the iteration of the loop (h) is 2 or 3 (remembering that arrays index from 0). You also shouldn't cross arrays for the main loop, and since LBound is in most cases 0 you might as well just use that anyway. Try this:
With lst
For h = 0 To UBound(r1c1s)
.ListColumns.Add
.ListColumns(.ListColumns.Count).Name = colNames(h)
.ListColumns(.ListColumns.Count).DataBodyRange.FormulaR1C1 = r1c1s(h)
If h = 2 or h = 3 Then
.ListColumns(.ListColumns.Count).NumberFormat = "0%"
End if
Next h
End With
To answer the other point in your question, UBound(array) just gives the index of the largest element (the Upper BOUNDary) in the given array. So where you have 50 elements in such an array, UBound(array) will return 49 (zero based as mentioned before). LBound just gives the other end of the array (the Lower BOUNDary), which is generally zero.
Good day!
I am currently having a slight issue with a command button, which, I would like to be able to do the following: format a specific row to a certain row height, add thick borders to a certain number of cells in this same row and counting and adding the number of rows thus produced to the initial number in the file. Basically, the button should enable the user of the spread sheet to add a new row with specific formatting into which the user will input data and keep track of the number of rows added.
My current code stands as is:
Option Explicit
Private Sub NewLineRedButton_Click()
Dim i As Long
Dim y As Long
For y = ThisWorkbook.Worksheets("Flags").Cells(16.3) To y + 1
ThisWorkbook.Worksheets("Flags").Cells(16, 3) = y + 1
For i = 20 To i + y Step 1
ThisWorkbook.Worksheets("Flags").Rows(i).RowHeight = 45
ThisWorkbook.Worksheets("Flags").Cells(i, 1).Borders.LineStyle = xlContinuous
ThisWorkbook.Worksheets("Flags").Cells(i, 1).Borders.Weight = xlMedium
Next
Next
End Sub
At the moment the code executes only for two rows below and stops. I am not quite sure, why...?
Writing a for loop like this
For y = ThisWorkbook.Worksheets("Flags").Cells(16.3) To y + 1
is the same as writing it like this
For y = ThisWorkbook.Worksheets("Flags").Cells(16.3) To 1
I'm guessing the value in the cell is zero so it will execute the loop for 0 and 1 - i.e. the two times you are seeing.
You need something like
lEndRow = lStartRow + (lRowCount - 1)
For y = lStartRow to lEndRow
I have this going fine now. Just can't get it to do all the columns with the right borders... I am not sure how to to call them while using the cells(#, #) notation and I can't see how to use the Range(''Z#,Z#'') notation with my i variable being a Long...
Anyways: here's the result so far:
Option Explicit
Private Sub NewLineRedButton_Click()
Dim i As Long
Dim y As Long
Dim RowEnd As Long
RowEnd = ThisWorkbook.Worksheets("Flags").Cells(Rows.Count, 1).End(xlUp).Row
For y = 19 To RowEnd
ThisWorkbook.Worksheets("Flags").Cells(16, 3) = y - 17 ' First row which is already on the sheet is on row 19, first row appearing by button clicking is on row 20 and the program is counting the header hence the y - 17 for the value of the number of rows.
For i = 19 To RowEnd + 1 Step 1
ThisWorkbook.Worksheets("Flags").Rows(i).RowHeight = 45
ThisWorkbook.Worksheets("Flags").Cells(i, 1).Borders.LineStyle = xlContinuous
ThisWorkbook.Worksheets("Flags").Cells(i, 1).Borders.Weight = xlMedium
Next
Next
End Sub
Thanks for the help and ideas, finally wiggled around and found other resources from the leads given here.
Imgur Album with screens of worksheets: http://imgur.com/a/6rFWF
Long story short, I am writing an Excel VBA utility that will assign two types of security shifts (called coverages and weekend duties) to security staff members. Basically, I have a worksheet with all of the staff members and their various availability information in it (the top image in the imgur album) and a worksheet with all of the coverage dates in it (the bottom image in the imgur album). Note that I don't have an image of the weekend duty dates as it looks similar to the coverage dates (but with the Friday and Saturday shifts).
The utility basically assigns a random staff member to each date, checking to make sure it doesn't violate any of their availability requirements. Unfortunately, I realize that I am creating a large chance for an infinite loop to occur. In my own testing, there has only been 1 attempt out of around 15-16 that did not enter an infinite loop near the end. So I'm looking for your help to account for this so the utility doesn't eat itself.
Here is the "pseudo-code" for the procedure in question.
'Loop for Column A in the Coverage Slips sheet (image 2 in imgur album)
Do Until (CoverageRowNumber = LastCoverageSlipRow + 1)
Get a Random Staff Member by RNG
If staff member still needs more shifts (see Requirements columns) Then
If staff member does not have an "X" under the day of the week Then
If staff member does not have a matching date conflict Then
Assign the coverage
Increase CoverageRowNumber
End If
End If
End If
Loop
'Loop for Column B in the coverage slips sheet (image 2 in imgur album)
Do Until...
Same as the loop above
Loop
Edit: Disregard that I have the dates in two columns for now. I'll be fixing that once I solve the problem of this post...it's an easy fix and will cut the code almost in half.
The problem is that as the utility gets near the end of the list of dates, it often runs into the scenario where the only staff members left cannot sit that specific shift (whether because of day of the week or specific date). In the event that it runs into this scenario, I can see a couple of acceptable options (though I don't know how I'd go about programming them):
Undo all of the work that the utility did and start over until it can get lucky and find a solution that works. This would save me some time doing manual placements for the last few shifts but might take a very long time. Additionally, I'd have to store all of the original values and then paste them back into the spreadsheet anytime it starts over.
Simply stop assigning shifts and just exit the procedure. I will be able to manually place the last few shifts by moving a few people around. I sure is a lot less work than manually assigning 200 shifts by hand like I've been doing it the past few years.
Do you guys have any thoughts that could be of help here? I'm not even sure how I could have the procedure check to see if there are any available options or not, but either way there's got to be a way to detect (and deter) this infinite loop before it crashes the program.
Sorry for the novel, and thanks in advance for any help!
Edit: In an effort to provide a little more clarity, I figured I'd copy and paste the actual code below:
'------------------------------------------------------------'
'Create ws variables for each worksheet
Dim wsConflicts As Worksheet
Dim wsCoverageSlips As Worksheet
Dim wsWDSlips As Worksheet
Dim wsCoverageOutput As Worksheet
Dim wsWDOutput As Worksheet
'------------------------------------------------------------'
Public Function SetSheets()
'Assign the worksheets to the ws variables
Set wsConflicts = Worksheets("Conflicts")
Set wsCoverageSlips = Worksheets("Coverage Slips")
Set wsWDSlips = Worksheets("WD Slips")
Set wsCoverageOutput = Worksheets("Coverage Output")
Set wsWDOutput = Worksheets("WD Output")
'Display a message (debugging)
'MsgBox "The sheets have been assigned successfully"
End Function
'------------------------------------------------------------'
Public Function ColumnLetter(ColumnNumber As Integer) As String
Dim n As Long
Dim c As Byte
Dim s As String
n = ColumnNumber
Do
c = ((n - 1) Mod 26)
s = Chr(c + 65) & s
n = (n - c) \ 26
Loop While n > 0
ColumnLetter = s
End Function
'------------------------------------------------------------'
Sub AssignCoverages()
'Fill the ws variables
Call SetSheets
'Set the first and last row numbers
Dim FirstStaffMemberRow As Integer
FirstStaffMemberRow = 3
Dim LastStaffMemberRow As Integer
LastStaffMemberRow = wsConflicts.UsedRange.Rows.Count
'Count the number of required coverages and weekend duties
Dim RequiredCoverages As Integer
Dim RequiredWDs As Integer
For i = FirstStaffMemberRow To LastStaffMemberRow
RequiredCoverages = RequiredCoverages + wsConflicts.Range("B" & i).Value
RequiredWDs = RequiredWDs + wsConflicts.Range("C" & i).Value
Next i
'Display a message (debugging)
MsgBox "You currently have " & RequiredCoverages & " required coverages and " & RequiredWDs & " required weekend duties."
'Count the number of coverage slips and weekend duty slips
Dim FirstCoverageSlipRow As Integer
FirstCoverageSlipRow = 1
Dim LastCoverageSlipRow As Integer
LastCoverageSlipRow = wsCoverageSlips.UsedRange.Rows.Count
Dim NumCoverageSlips As Integer
NumCoverageSlips = (LastCoverageSlipRow - FirstCoverageSlipRow + 1)
Dim FirstWDSlipRow As Integer
FirstWDSlipRow = 1
Dim LastWDSlipRow As Integer
LastWDSlipRow = wsWDSlips.UsedRange.Rows.Count
Dim NumWDSlips As Integer
NumWDSlips = (LastWDSlipRow - FirstWDSlipRow + 1)
'Check to make sure there are enough required shifts for slips
If RequiredCoverages <> NumCoverageSlips Then
MsgBox "The number of shifts you require (Columns B & C on Conflicts sheet) does not match the number of slips you've entered. You have " & RequiredCoverages & " required coverages and " & NumCoverageSlips & " coverage slips. You have " & RequiredWDs & " required weekend duties and " & NumWDSlips & " weekend duty slips. Please correct this error and retry."
Exit Sub
Else
'Debugging
'MsgBox "The number of shifts you require (Columns B & C on Conflicts sheet) matches the number of slips you've entered. You have " & RequiredCoverages & " required coverages and " & NumCoverageSlips & " coverage slips. You have " & RequiredWDs & " required weekend duties and " & NumWDSlips & " weekend duty slips."
End If
'Massive loop to assign coverages to random staff members
Dim NumRemainingCoverages As Integer
NumRemainingCoverages = NumCoverageSlips
Dim SlipRowNumber As Integer
SlipRowNumber = FirstCoverageSlipRow
'Loop for Column A
Do Until (SlipRowNumber = LastCoverageSlipRow + 1)
'Get a random staff member row
StaffMemberRow = GetRandomStaffMemberRow(FirstStaffMemberRow, LastStaffMemberRow)
'Check to make sure the staff member has remaining required coverages
If wsConflicts.Range("B" & StaffMemberRow).Value > 0 Then
'Check to make sure the staff member can sit the day of the week
Dim CurrentDate As Date
CurrentDate = wsCoverageSlips.Range("A" & SlipRowNumber).Value
Dim CurrentDay As Integer
CurrentDay = Weekday(CurrentDate)
Dim CurrentDayColumn As String
If CurrentDay = 1 Then CurrentDayColumn = "D"
If CurrentDay = 2 Then CurrentDayColumn = "E"
If CurrentDay = 3 Then CurrentDayColumn = "F"
If CurrentDay = 4 Then CurrentDayColumn = "G"
If CurrentDay = 5 Then CurrentDayColumn = "H"
If CurrentDay = 6 Then CurrentDayColumn = "I"
If CurrentDay = 7 Then CurrentDayColumn = "J"
If wsConflicts.Range(CurrentDayColumn & StaffMemberRow).Value = "" Then
'Check to make sure the staff member does not have a date conflict
Dim ColumnNumber As Integer
Dim ColumnLetterText As String
Dim CoverageDateConflicts As Integer
CoverageDateConflicts = 0
For ColumnNumber = 11 To 20
ColumnLetterText = ColumnLetter(ColumnNumber)
Dim CoverageSlipDate As Date
If IsDate(wsConflicts.Range(ColumnLetterText & StaffMemberRow).Value) = True Then
CoverageSlipDate = wsConflicts.Range(ColumnLetterText & StaffMemberRow).Value
Else
CoverageSlipDate = DateValue("01/01/1900")
End If
If CurrentDate = CoverageSlipDate Then
CoverageDateConflicts = CoverageDateConflicts + 1
End If
Next ColumnNumber
If CoverageDateConflicts = 0 Then
'Assign the coverage
Dim BlankCoverageOutputRow As Integer
BlankCoverageOutputRow = wsCoverageOutput.UsedRange.Rows.Count + 1
wsCoverageOutput.Range("A" & BlankCoverageOutputRow).Value = wsConflicts.Range("A" & StaffMemberRow).Value
wsCoverageOutput.Range("B" & BlankCoverageOutputRow).Value = CurrentDate
'Reduce the staff member's required coverages by 1
Dim CurrentRequirements As Integer
CurrentRequirements = wsConflicts.Range("B" & StaffMemberRow).Value
wsConflicts.Range("B" & StaffMemberRow).Value = CurrentRequirements - 1
'Reduce the number of remaning coverages by 1
NumRemainingCoverages = NumRemainingCoverages - 1
'Increase the slip row number by 1
SlipRowNumber = SlipRowNumber + 1
'Message box for debugging
'MsgBox "Coverage Date (" & CurrentDate & ") assigned to " & wsConflicts.Range("A" & StaffMemberRow).Value & "."
End If 'End date check
End If 'End day check
End If 'End requirements check
Loop 'End loop for column A
End Sub
'------------------------------------------------------------'
Public Function GetRandomStaffMemberRow(FirstStaffMemberRow As Integer, LastStaffMemberRow As Integer)
'Pick a random number between the first staff member row and the last
Call Randomize
GetRandomStaffMemberRow = Int((LastStaffMemberRow - FirstStaffMemberRow + 1) * Rnd + FirstStaffMemberRow)
End Function
The question is too open for a detailed answer, so I try with some guidelines. I hope it helps.
I would use a class Solution with the following members:
Solution.ReadInputFromSheet() reads the table from the sheet into the class members
Solution.GenerateRandom() creates a new random solution. Try to find a balance between smart (add some logic to avoid totally random solutions) and speed (don't get stuck, exit after trying 10 or 50 random numbers that don't work), but speed is more important
Solution.Quality() As Double calculates the quality of the solution. For example a solution that is not valid returns 0, if Joe has 10 consecutive shifts returns 20, if the shifts are better distributed returns 100.
Solution.WriteOnSheet() write the data from the class members into the sheet.
Solution.Clone() As Solution() creates a new Solution instance with the same data
Make a cycle that creates a solution, checks if its quality is better than the best quality solution found so far, if it is better keep it, otherwise go and calculate another solution.
Set BestS = New Solution
BestS.ReadInputFromSheet
BestS.GenerateRandom()
Set S = New Solution
S.ReadInputFromSheet
For I = 1 To 10000
S.GenerateRandom()
If S.Quality() > BestS.Quality() Then Set BestS = S.Clone()
Next I
BestS.WriteOnSheet
Instead of 10000 you can use Timer to run it for a finite number of seconds, or make a button to interrupt it when you come back from lunch break.
A faster solution generator function is better than risking of getting stuck with one difficult (or impossible) solution.
For a smarter solution generator function I need more details on the rules.
So I went ahead and developed my own solution to this problem--it's not perfect and it's probably not the best way to handle the scenario. But it works, and it solved my problem in a matter of minutes instead of hours learning other methods.
Basically, I created two new "counter" variables. The first is FailedAttempts. Every time the procedure tries a random staff member but runs into a conflict, it increments FailedAttempts by 1. Every time the random staff member is a successful match (no conflicts), it resets FailedAttempts to 0. If at any time FailedAttempts = 100, it immediately exits the loop and starts over. In other words, if it tries 100 random staff members in a row without finding a match, I assume it's not going to find a match and just cut my losses.
The second variable, Assignments, is incremented by 1 every time that the procedure makes a successful assignment. When this number equals the number of shifts that the procedure is supposed to assign, it immediately exits the loop.
To do this, I had to use a couple of forbidden 'GoTo' commands (I wasn't sure how else to exit the loop. You can exit a For loop with Exit For but I believe this is invalid for Do While loops. I ended up only needing two GoTo's, one for exiting the loop and one to go back to the beginning of the procedure. I also made sure that the cells in the worksheet that change during the procedure are reset to their original state before it retries the assignment procedure.
I'll save everyone the trouble of reading through the extended version of the code, but in 'pseudo-code' form it looks like this:
Retry: 'Label for GoTo command
Do Until (CoverageRowNumber = LastCoverageSlipRow + 1)
Get a Random Staff Member by RNG
If staff member still needs more shifts (see Requirements columns) Then
If staff member does not have an "X" under the day of the week Then
If staff member does not have a matching date conflict Then
'Assign the coverage
'Increase CoverageRowNumber
Assignments = Assignments + 1
Else
FailedAttempts = FailedAttempts + 1
End If
Else
FailedAttempts = FailedAttempts + 1
End If
Else
FailedAttempts = FailedAttempts + 1
End If
If FailedAttempts > 100 Then
GoTo ExitLoop
End If
Loop
ExitLoop: 'Label for GoTo command
If Assignments <> NumCoverageSlips Then
GoTo Retry
End If
'Do rest of procedure
Again, there may be (and certainly is) a more elegant and "correct" way of accomplishing the task at hand. This method worked for me with the given environment. Thanks to those who provided solutions--even though I ended up going a different direction they provided great food for thought and helped me learn a bunch of new methods (especially the class idea from #stenci).
Thanks all.