What does Get do in VB6? - vb6

I'm trying to modify a program someone wrote in VB6 in the sem-distant past, and have come across the line below, and many similar ones. My question is, syntactically, what does this "Get" line look like it does or might do?
Get #3, StartByte + Offset, StudentScrBytes
Within the program, it's ALWAYS followed by 3 comma-separated items, and with one exception, the first item is a number preceded by #. The second looks to always resolve to a number, and the third a single variable.
I'm fairly sure I've figured out the numbers preceded by # are a file reference - the first time Get appears, instead of #3 or #10 or #whatever, it has a variable "TempFile" instead, initialized as FreeFile().
TempFile = FreeFile()
Open "c:\folerName.dir" For Binary Shared As TempFile
The only stuff I've been able to find on Get in VB6, seems to relate to OOP and getters/setters. Maybe I'm wrong, but I really don't think that's what's going on here, and all I have are vague guesses as to what is.
Here's the function the line was taken from. Both arguments are integers.
Function StudentScr$(Record, Contest)
Dim StudentScrBytes As String * 4
StartByte = (Record - 1) * LengthOfStudentRecord
If Contest = 1 Then Offset = 77
If Contest = 2 Then Offset = 85
If Contest = 3 Then Offset = 94
If Contest = 4 Then Offset = 102
If Contest = 5 Then Offset = 110
If Contest = 6 Then Offset = 118
If Contest = 7 Then Offset = 126
If Contest = 8 Then Offset = 134
Get #3, StartByte + Offset, StudentScrBytes
StudentScr$ = StudentScrBytes
End Function
I would think Get would get something from the specified file, except I can't tell how (or if) a file is even specified at all.

Have a look at the original MS VB6 documentation:
https://msdn.microsoft.com/en-us/library/aa243376(v=vs.60).aspx
You may also be interested in its counterpart Put:
https://msdn.microsoft.com/en-us/library/aa266212(v=vs.60).aspx
Hint: when searching for legacy VB statements, include "vs.60" for Visual Studio 6.0 in your Google search, and restrict your search to the MS site. MS hast this term in the official link, so you can not miss it. This search:
vb6 vs.60 get put site:microsoft.com
does bring up both Get and Put as the two first Google answers on my machine.

Related

How do I properly parse the range information in a unified diff?

Basically, what I want to do is look at the range information of a unified diff and know exactly which lines of code I should pay attention to.
For instance, this:
## -1827,7 +1827,7 ##
This tells me that in total only 1 line has changed, because the diff shows 3 lines above and below the change (so 7 - 6 = 1), and it also points me to the line 1830 (i.e. 1827 + 3).
To be more pedantic, this particular range information actually tells me that at line 1830, a line was removed (-), and at line 1830 a line was added (+).
Or to make that more obvious consider this range information for another diff:
## -878,15 +878,13 ##
What this is telling me is that at line 881 (878 + 3) 9 lines were deleted (15 - 6), but at line 881 only 7 lines were added (13 - 6).
So the question is, using a regex or some other Ruby string method, how do I pull out the above information easily?
i.e. how do I easily pull out this info:
Both The line numbers (i.e. just the 1827 or 878), which I can then add + 3 to determine the actual inline number I care about. It has to be both because both lines may not always be identical.
The number of lines affected (aka the 7, 15 or 13 right after the , in the above examples)
While I do that, how do I make sure to track the operation (addition or deletion) for each of the operations.
I tried slicing the string and going directly for a character -- e.g. myString[3] which gives me -, but that's the only character it reliably works for because the line numbers can be 1, 10, 100, 1000, 10000, etc. So the only way is to just scan the string and then parse it.
Edit 1
To add some code to show what I have tried.
Assume I have the contents of a diff in a variable called #diff_lines:
#diff_lines.each do |diff_line|
if diff_line.start_with?("##")
del_line_num_start = diff_line.split(/## /).second.split.first.split(/-/).second.split(/,/).first.to_i + 3
num_deleted_lines = diff_line.split(/## /).second.split.first.split(/-/).second.split(/,/).second.to_i - 6
add_line_num_start = diff_line.split(/## /).second.split.second.split(/\+/).second.split(/,/).first.to_i + 3
num_added_lines = diff_line.split(/## /).second.split.second.split(/\+/).second.split(/,/).second.to_i - 6
As you can see, the above works....but it is quite horrendous to look at and is OBVIOUSLY not very DRY.
Ideally I would like to be able to achieve the same thing, but just cleaner.
The general idea is to write a regular expression that has capture groups in it ((...)) to pick apart that string into something useful. For example:
diff_line.match(/\A##\s+\-(\d+),(\d+)\s+\+(\d+),(\d+)\s+##/)
This yields a MatchData object on a successful match. You can then apply this to some variables like:
if (m = diff_line.match(...))
a_start, a_len, b_start, b_len = m[1..4].map(&:to_i)
end
Then you can do whatever computations you need to do with these numbers.
If you're ever having trouble visualizing what a regular expression does, try a tool like Rubular to better illustrate the internals.

I cannot understand mistake lmer

I tried to solve the problem reading other answers but did not get the solution.
I am performing a lmer model:
MODHET <- lmer(PERC ~ SITE + TREAT + HET + TREAT*HET + (1|PINE), data = PRESU).
Perc is the percentage of predation. Site is a categorical variable that I am using as blocking factor. It is site identity where I performed the experiement. TREAT is categorical variable of 2 levels. HET is a continuous variable. The number of observation is 56 divided in 7 sites
Maybe the problem is how I expressed the random factor. In every site I selected 8 pines among 15 to perform the experiment. I included the pine identity as categorical random factor. For instance in Site 1 pines are called a1,a3,a7 ecc, while in site 2 are called b1,b4,b12 ecc...
The output of the model is
Error: number of levels of each grouping factor must be < number of observations
I donĀ“t understand where is the mistake. Could it be how I called the pines?
I tried also
MODHET <- lmer(PERC ~ SITE + TREAT + HET + TREAT*HET + (1|SITE:PINE), data = PRESU)
but the output is the same.
I hope that I explained well my problems. I read on this forum similar questions about it but I still do not get the solution.
Thank you for your help
Use argument control = lmerControl(check.nobs.vs.nRE = "ignore") in your lmer-call to suppress this error. However, I guess this does not solve the actual problem. It seems to me that your grouping level contains no "groups", probably "SITE" is your random intercept?
If you consider PINES nested as "subjects" within SITES, then I would suggest following formula:
MODHET <- lmer(PERC ~ TREAT*HET + (1|SITE), data = PRESU)
or,
MODHET <- lmer(PERC ~ TREAT*HET + (1 | SITE / PINE), data = PRESU)
But my answer may be wrong, I'm not sure whether I have enough information to fully understand what you're aiming at.
edit:
Sorry, nesting was not correctly specified, I fixed it in the above formula. See also this answer .

Excel VBA - Any performance benefits between const string range or define names for ranges?

G'Day,
I have a question more towards helping me understand on more about how Excel VBA can effectively manage defined ranges that have been declared in one place in order to execute data well. Just wanting to work out which two options (I know so far) is better or not as preferred best practice before working more on this project.
The problem I'm solving is to make a small table containing a number of failures across a set of fictional suppliers, thus the table looks like this (sorry it is in raw form)
"Company Name" "No. of Failures"
"Be Cool Machine" 7
"Coolant Quarters" 5
"Little Water Coolants 3
"Air Movers Systems" 7
"Generals Coolant" 5
"Admire Coolants" 4
My first option (Const String) is this module/formula as follows.
Option Explicit
Public Const CountofFailures As String = "J7:J12"
Sub btnRandom()
' Declaration of variables
Dim c As Range
' Provide a random number for failures across Suppliers
For Each c In ActiveSheet.Range(CountofFailures)
c.Value = Random1to10
Next c
End Sub
Function Random1to10() As Integer
'Ensure we have a different value each time we run this macro
Randomize
' Provide a random number from 1 to 10 (Maximum number of Failures)
Random1to10 = Int(Rnd() * 10 + 1)
End Function
Second option (Defined Name) is this module/formula as follows.
Option Explicit
Sub btnRandom()
' Declaration of variables
Dim c As Range
Dim iLoop As Long
' Provide a random number for Suppliers with Defined Range
For Each c In ActiveWorkbook.Names("CountofFailures").RefersToRange
c.Value = Random1to10
Next c
End Sub
Function Random1to10() As Integer
'Ensure we have a different value each time we run this macro
Randomize
' Provide a random number from 1 to 10 (Maximum number of Failures)
Random1to10 = Int(Rnd() * 10 + 1)
End Function
Any suggestions - I would do a macro timer test later if this helps?
Would there be a third option if I fetch a range listed in a cell as value? I haven't seen a code that does this in practice?
I don't know the performance difference-I suspect const is faster. My general advice is 'don't worry about performance until you have a performance problem'. Otherwise you end up guessing what to spend your optimize time on and it may not be right.
As for named ranges, the benefit is that they move when you insert rows and columns. If you insert a new column at column I your first example needs to be edited and your second example will conitinue to work.
Both of your codes loop through ranges which will be the bottleneck. I suggest you
Use a range name to automatically "locate" your data - ie if you insert/delete rows and columns your reference remains intact. My experience though is that many range names in a file can end up obfuscating what the workbook is doing
Do a single write to this range
code
Sub QuickFill()
Randomize
Range("CountofFailures").Formula = "=Randbetween(1,10)"
Range("CountofFailures").Value = Range("CountofFailures").Value
End Sub
I have found that Named Ranges are slower (presumably because Excel has to do an internal lookup on the Name to find what it refers to), but you are very unlikely to be able to find a significant dofference except in very extreme cases (tens of thousands of names being referenced tens of thousands or hundreds of thousands times).
And as Dick says: the benefits far outweigh the insignificant speed loss.

renumbering ordered session variables when deleting one

I'm updating a classic ASP application, written in jScript, for a local pita restaurant. I've created a new mobile-specific version of their desktop site, which allows ordering for delivery and lots of customization of the final pita (imagine a website for Subway, which would allow you to add pickles, lettuce, etc.). Each pita is stored as a string of numbers in a session variable. The total number of pitas is also stored. The session might look like this:
PitaCount = 3
MyPita1 = "35,23,16,231,12"
MyPita2 = "24,23,111,52,12,23,93"
MyPita3 = "115,24"
I know there may be better ways to store the data, but for now, since the whole thing is written, working , and live (and the client is happy), I'd like to just solve the problem I have. Here's the problem...
I've got buttons on the order recap page which allow the customer to delete pitas from the cart. When I do this, I want to renumber the session variables. If the customer deletes MyPita1, I need to renumber MyPita2 to MyPita1, renumber MyPita3 to MyPita2, and then decrement the PitaCount.
The AJAX button sends an integer to an ASP file with the number of the pita to be deleted (DeleteID). My function looks at PitaCount and DeleteID. If they're both 1, it just abandons the session. If they're both the same, but greater than one, we're deleting the most recently added pita, so no renumbering is needed. However, if PitaCount is greater then DeleteID, we need to renumber the pitas. Here's the code I'm using to do that:
for (y=DeleteID;y<PitaCount;y++) {
Session("MyPita" + y) = String(Session.Contents("MyPita" + (y+1)));
};
Session.Contents.Remove("MyPita" + PitaCount);
PitaCount--;
Session.Contents("PitaCount") = PitaCount;
This works for every pita EXCEPT the one which replaces the deleted one, which returns 'undefined'. For example, if I have 6 pitas in my cart, and I delete MyPita2, I end up with 5 pitas in the cart. Number 1, 3, 4, and 5 are exactly what you'd expect, but MyPita2 returns undefined.
I also tried a WHILE loop instead:
while (DeleteID < PitaCount) {
Session("MyPita" + DeleteID) = String(Session.Contents("MyPita" + (DeleteID+1)));
DeleteID++;
};
Session.Contents.Remove("MyPita" + PitaCount);
PitaCount--;
Session.Contents("PitaCount") = PitaCount;
This also returns 'undefined', just like the one above.
Until I can get this working I'm simply writing the most recent pita into the spot vacated by the deleted pita, but this reorders the cart, and I consider that a usability problem because people expect the items they added to the cart to remain in the same order. (Yes, I could add some kind of timestamp to the sessions and order using that, but it would be quicker to fix the problem I'm having, I think).
I'm baffled. Why (using the 6 pita example above) would it work perfectly on the second, third, and fourth iteration through the loop, but not on the first?
I can't be sure, but I think your issue may be that the value of DeleteID is a string. This could happen you assign its value by doing something like:
var DeleteID = Session("DeleteID");
Assuming this is true, then in the first iteration of your loop (which writes to the deleted spot), y is a string, and the expression y+1 is interpreted as a string concatenation instead of a numeric addition. If, for example, you delete ID 1, you're actually copying the value from id 11 ("1" + 1) into the deleted spot, which probably doesn't exist in your tests. This can be tested by adding at least 11 items to your cart and then deleting the first one. On the next iteration, the increment operator ++ forces y to be a number, so the script works as expected from that point on.
The solution is to convert DeleteID to a number when initializing your loop:
for (y = +DeleteID; y < PitaCount; y++) {
There may be better ways to convert a string to a number, but the + is what I remember.

Ellipsizing a set of names

OK, I'm sure somebody, somewhere must have come up with an algorithm for this already, so I figured I'd ask before I go off to (re)invent it myself.
I have a list of arbitrary (user-entered) non-empty text strings. Each string can be any length (except 0), and they're all unique. I want to display them to the user, but I want to trim them to some fixed length that I decide, and replace part of them with an ellipsis (...). The catch is that I want all of the output strings to be unique.
For example, if I have the strings:
Microsoft Internet Explorer 6
Microsoft Internet Explorer 7
Microsoft Internet Explorer 8
Mozilla Firefox 3
Mozilla Firefox 4
Google Chrome 14
then I wouldn't want to trim the ends of the strings, because that's the unique part (don't want to display "Microsoft Internet ..." 3 times), but it's OK to cut out the middle part:
Microsoft...rer 6
Microsoft...rer 7
Microsoft...rer 8
Mozilla Firefox 3
Mozilla Firefox 4
Google Chrome 14
Other times, the middle part might be unique, and I'd want to trim the end:
Minutes of Company Meeting, 5/25/2010 -- Internal use only
Minutes of Company Meeting, 6/24/2010 -- Internal use only
Minutes of Company Meeting, 7/23/2010 -- Internal use only
could become:
Minutes of Company Meeting, 5/25/2010...
Minutes of Company Meeting, 6/24/2010...
Minutes of Company Meeting, 7/23/2010...
I guess it should probably never ellipsize the very beginning of the strings, even if that would otherwise be allowed, since that would look weird. And I guess it could ellipsize more than one place in the string, but within reason -- maybe 2 times would be OK, but 3 or more seems excessive. Or maybe the number of times isn't as important as the size of the chunks that remain: less than about 5 characters between ellipses would be rather pointless.
The inputs (both number and size) won't be terribly large, so performance is not a major concern (well, as long as the algorithm doesn't try something silly like enumerating all possible strings until it finds a set that works!).
I guess these requirements seem pretty specific, but I'm actually fairly lenient -- I'm just trying to describe what I have in mind.
Has something like this been done before? Is there some existing algorithm or library that does this? I've googled some but found nothing quite like this so far (but maybe I'm just bad at googling). I have to believe somebody somewhere has wanted to solve this problem already!
It sounds like an application of the longest common substring problem.
Replace the longest substring common to all strings with ellipsis. If the string is still too long and you are allowed to have another ellipsis, repeat.
You have to realize that you might not be able to "ellipsize" a given set of strings enough to meet length requirements.
Sort the strings. Keep the first X characters of each string. If this prefix is not unique to the string before and after, then advance until unique characters (compared to the string before and after) are found. (If no unique characters are found, the string has no unique part, see bottom of post) Add ellipses before and after those unique characters.
Note that this still might look funny:
Microsoft Office -> Micro...ffice
Microsoft Outlook -> Micro...utlook
I don't know what language you're looking to do this in, but here's a Python implementation.
def unique_index(before, current, after, size):
'''Returns the index of the first part of _current_ of length _size_ that is
unique to it, _before_, and _after_. If _current_ has no part unique to it,
_before_, and _after_, it returns the _size_ letters at the end of _current_'''
before_unique = False
after_unique = False
for i in range(len(current)-size):
#this will be incorrect in the case mentioned below
if i > len(before)-1 or before[i] != current[i]:
before_unique = True
if i > len(after)-1 or after[i] != current[i]:
after_unique = True
if before_unique and after_unique:
return i
return len(current)-size
def ellipsize(entries, prefix_size, max_string_length):
non_prefix_size = max_string_length - prefix_size #-len("...")? Post isn't clear about this.
#If you want to preserve order then make a copy and make a mapping from the copy to the original
entries.sort()
ellipsized = []
# you could probably remove all this indexing with something out of itertools
for i in range(len(entries)):
current = entries[i]
#entry is already short enough, don't need to truncate
if len(current) <= max_string_length:
ellipsized.append(current)
continue
#grab empty strings if there's no string before/after
if i == 0:
before = ''
else:
before = entries[i-1]
if i == len(entries)-1:
after = ''
else:
after = entries[i+1]
#Is the prefix unique? If so, we're done.
current_prefix = entries[i][:prefix_size]
if not before.startswith(current_prefix) and not after.startswith(current_prefix):
ellipsized.append(current[:max_string_length] + '...') #again, possibly -3
#Otherwise find the unique part after the prefix if it exists.
else:
index = prefix_size + unique_index(before[prefix_size:], current[prefix_size:], after[prefix_size:], non_prefix_size)
if index == prefix_size:
header = ''
else:
header = '...'
if index + non_prefix_size == len(current):
trailer = ''
else:
trailer = '...'
ellipsized.append(entries[i][:prefix_size] + header + entries[i][index:index+non_prefix_size] + trailer)
return ellipsized
Also, you mention the string themselves are unique, but do they all have unique parts? For example, "Microsoft" and "Microsoft Internet Explorer 7" are two different strings, but the first has no part that is unique from the second. If this is the case, then you'll have to add something to your spec as to what to do to make this case unambiguous. (If you add "Xicrosoft", "MXcrosoft", "MiXrosoft", etc. to the mix with these two strings, there is no unique string shorter than the original string to represent "Microsoft") (Another way to think about it: if you have all possible X letter strings you can't compress them all to X-1 or less strings. Just like no compression method can compress all inputs, as this is essentially a compression method.)
Results from original post:
>>> for entry in ellipsize(["Microsoft Internet Explorer 6", "Microsoft Internet Explorer 7", "Microsoft Internet Explorer 8", "Mozilla Firefox 3", "Mozilla Firefox 4", "Google Chrome 14"], 7, 20):
print entry
Google Chrome 14
Microso...et Explorer 6
Microso...et Explorer 7
Microso...et Explorer 8
Mozilla Firefox 3
Mozilla Firefox 4
>>> for entry in ellipsize(["Minutes of Company Meeting, 5/25/2010 -- Internal use only", "Minutes of Company Meeting, 6/24/2010 -- Internal use only", "Minutes of Company Meeting, 7/23/2010 -- Internal use only"], 15, 40):
print entry
Minutes of Comp...5/25/2010 -- Internal use...
Minutes of Comp...6/24/2010 -- Internal use...
Minutes of Comp...7/23/2010 -- Internal use...

Resources