redis - HSCAN MATCH only "first level" - redis

I'm using Redis with hashes to index real paths from file system, e.g.:
HSET example "/dir" "some value"
HSET example "/dir/sub-dir" "some value"
HSET example "/dir/sub-dir-2" "some value"
HSET example "/dir/sub-dir/sub-sub-dir" "some value"
HSET example "/dir/sub-dir/another-sub-sub-dir" "some value"
Now I need to get "directory's content". I have tried to use HSCAN:
HSCAN example 0 MATCH "/dir/*"
but with this I'm getting every path in this directory but I should get only:
/dir/sub-dir
/dir/sub-dir-2
Is it possible to get this via match pattern?

AFAIK, no, Redis' pattern matching is glob-like which doesn't allow this.
You could use a server-side Redis Lua script for this purpose though, perhaps something like this:
local key = KEYS[1]
local cur = ARGV[1]
local path = ARGV[2]
local pattern = path .. '*'
local plen = string.len(pattern)
local r = redis.call('HSCAN', key, cur, 'MATCH', pattern)
local rlen = #r[2]
while rlen > 0 do
local f = r[2][rlen-1]
if string.find(f, '/', plen) then
-- Remove field and value
for i = 0,1 do
table.remove(r[2], rlen)
rlen = rlen - 1
end
else
rlen = rlen - 2
end
end
return r
~/work/redis-io master* 15:59:55
❯ redis-cli --eval /tmp/hscanfirstlv.lua example , 0 "/dir/"
1) "0"
2) 1) "/dir/sub-dir"
2) "some value"
3) "/dir/sub-dir-2"
4) "some value"
Execution example:
$ cat myscript.lua | redis-cli SCRIPT LOAD -x
"4a95e1a03bfeeb1cb9e433862dce47b63981fbdc"
$ redis-cli EVALSHA "4a95e1a03bfeeb1cb9e433862dce47b63981fbdc" 1 example 0 "/dir/"
1) "0"
2) 1) "/dir/sub-dir"
2) "some value"
3) "/dir/sub-dir-2"
4) "some value"

Related

VB.NET - Get second hyperlink from string and set as LinkLabel text property

I have a tool that takes in an email and sorts the data into the appropriate fields. In the email, there are normally two hyperlinks that launch the ticket editor in IBM notes. One is a local link and one is a server link. The following code is able to get the local link as it is the first hyperlink that contains 'notes://' but I need to get the one for the server as well, which also starts with 'notes://".
For i = 0 To lines.Count + 1
If lines(i).StartsWith("notes://") Then
StartLine = i
Exit For
End If
Next
link_OpenRequestUsingNotes.Text = lines(StartLine)
I thought of writing some code to check the line about it to see if it matches a specific string, maybe with Regex?
For the local link it needs to look for:
"using a Notes client (local replica)"
For the server link it needs to look for:
"using a Notes client (Server):"
The hyperlink is below this text so it would need to look for those and then get the text on the next line.
These links are then set as the text for two link labels that the users can press and go to that link.
If someone could please help me find a way to get the server link, it would be greatly appreciated.
You can use this code:
link_OpenRequestUsingNotes_Local.Text = "" 'fields for local link
link_OpenRequestUsingNotes_Server.Text = "" 'field for server link
For i = 0 To lines.Count - 1
If lines(i).StartsWith("using a Notes client (local replica)") Then
link_OpenRequestUsingNotes_Local.Text = lines(i + 1)
ElseIf lines(i).StartsWith("using a Notes client (Server)")
link_OpenRequestUsingNotes_Server.Text = lines(i + 1)
End If
If link_OpenRequestUsingNotes_Local.Text <> "" AndAlso link_OpenRequestUsingNotes_Server.Text <> "" Then
Exit For
End If
Next i
You could use code like this to find the first two links:
Dim notes = Function(x) x.StartsWith("notes://")
Dim index As Integer = lines.FindIndex(notes)
If index <> -1 AndAlso index < (lines.Count - 1) Then
Dim firstLink As String = lines(index + 1)
' ... do something with "firstLink"...
Debug.Print(firstLink)
index = lines.FindIndex(index + 2, notes)
If index <> -1 AndAlso index < (lines.Count - 1) Then
Dim secondLink As String = lines(index + 1)
' ... do something with "secondLink"...
Debug.Print(secondLink)
End If
End If
I managed to fix it myself
Just add 1 to i (StartLine = i + 1) to go to the line below!
'Notes Server Link
For i = 0 To lines.Count - 1
If lines(i).StartsWith("Click here to open the request using a Notes client (Server):") Then
StartLine = i + 1
Exit For
End If
Next
link_OpenServerLink.Text = lines(StartLine)

Can elements from a System.Collection.Arraylist be compared to see if any of the elements are the same?

Basically what the title of the question asks. If I prompt a user their name, then ask the user to enter any 5 numbers, finally storing the responses into an arraylist.
Wscript.StdOut.WriteLine "What is your name"
name = Wscript.StdIn.ReadLine
Wscript.StdOut.WriteLine "Enter any number"
att1 = CInt(WScript.StdIn.ReadLine)
Wscript.StdOut.WriteLine "Enter any number"
att2 = Cint(Wscript.StdIn.ReadLine)
Wscript.StdOut.WriteLine "Enter any number: "
att3 = CInt(Wscript.StdIn.ReadLine)
Wscript.StdOut.WriteLine "Enter any number: "
att4 = CInt(Wscript.StdIn.ReadLine)
Wscript.StdOut.WriteLine "Enter any number: "
att5 = CInt(Wscript.StdIn.ReadLine)
set myNumArray = CreateObject("System.Collections.Arraylist")
myNumArray.Add att1
myNumArray.Add att2
myNumArray.Add att3
myNumArray.Add att4
myNumArray.Add att5
How could I discover if any of the numbers the user returned are the same.
for example, The user enters 5 numbers: 1, 2, 2, 4, 5. How can i tell if the user entered the 2 twice?
Use a dictionary (but properly):
Option Explicit
Dim alInp : Set alInp = CreateObject("System.Collections.ArrayList")
alInp.Add 1
alInp.Add 2
alInp.Add 2
alInp.Add 4
alInp.Add 5
Dim dicInp : Set dicInp = CreateObject("Scripting.Dictionary")
Dim elm
For Each elm In alInp
dicInp(elm) = dicInp(elm) + 1
Next
Dim key
For Each key In dicInp
If dicInp(key) > 1 Then WScript.Echo "found", key, dicInp(key), "times"
Next
ouput:
cscript 34890229.vbs
found 2 2 times
Or - look at the current content of the ArrayList by using it .Contains method:
Option Explicit
Dim alInp : Set alInp = CreateObject("System.Collections.ArrayList")
Dim elm
For Each elm In Array(1, 2, 2, 4, 5)
If alInp.Contains(elm) Then
WScript.Echo "not again:", elm
Else
alInp.Add elm
End If
Next
WScript.Echo Join(alInp.ToArray())
output:
cscript 34890229-2.vbs
not again: 2
1 2 4 5
Use a dictionary
Set Arg = WScript.Arguments
set WshShell = createObject("Wscript.Shell")
Set Inp = WScript.Stdin
Set Outp = Wscript.Stdout
Set Dict = CreateObject("Scripting.Dictionary")
Do Until Inp.AtEndOfStream
On Error Resume Next
Line=Inp.readline
Dict.Add Line, ""
If Err.Number <> 0 then
If LCase(Arg(1)) = "l" then
Dict.Remove Line
Dict.Add Line, ""
End If
End If
Loop
For Each thing in Dict.Keys()
Outp.writeline thing
Next
DeDup
filter dedup {f|l}
filter dup {f|l}
Removes duplicate lines in a file keeping either the first or last occurence
f - keeps the first occuring duplicate line
c - keeps the last occuring duplicate line
Example
filter dedup f < "%systemroot%\win.ini"
Filter reads and writes standard in and standard out only. These are only available in a command prompt.
filter <inputfile >outputfile
filter <inputfile | other_command
other_command | filter >outputfile
other_command | filter | other_command

Facter ignoring variables at runtime

I have a Facter custom fact for use in Puppet that should generate a list of specific information, but it doesn't always work correctly, even on servers running the exact same versions of ruby, facter, puppet, and mysql. The code is below:
#backends.rb
puts "Backends retrieval"
if Facter.value('demainversion') == '2'
dbasename = Facter.value('dbasename')
if dbasename == ''
dbasename = 'database'
end
mysqlcmd = "mysql -uUser -pPassword #{dbasename} --skip_column_names -e "
if Facter.value('clustered')
dbasename = Facter.value('dbasename')
mysqlcmd = "mysql -uUser -pPassword -hclustered-host #{dbasename} --skip_column_names -e "
end
puts mysqlcmd
clients = Facter.value('databases').split(', ')
if clients != ''
clients.each do |client|
count = 0
client_id =
res =
backends = ""
facter_name = "#{client.gsub(' ','_')}_backends"
Facter.add("#{facter_name}") do
setcode do
puts "#{client} listing"
client_id = %x[#{mysqlcmd}"SELECT id FROM UserGroup WHERE groupName='#{client.strip}'"].strip
puts "#{client_id} listing"
puts backends
res = %x[#{mysqlcmd}"SELECT sourceMachine,sourceUser FROM GrabberJob WHERE clientGroup_id=#{client_id.strip}"].strip
res.each do |row|
machine = row.split(' ')[0]
login = row.split(' ')[1]
val = login.gsub('admin','')
if count == 0
backends << machine.strip << "(" << val << ")"
else
backends << ", " << machine.strip << "(" << val << ")"
end
count += 1
end
backends.strip
end
end
end
end
end
When puppet (or irb) runs this it may (or may not) return ...
ERROR 1046 (3D000) at line 1: No database selected
... but if the server throws the error it will continue to exhibit the problem. I know that the dbasename variable is set correctly, courtesy of the puts statements used for debugging, but the variable is ignored when the mysql commands are actually run.
I have also tried adding a USE #{dbasename}; statement to the client_id and res commands to no avail. Any suggestions on what I could do to make it work consistently would be most appreciated.

combine values of a parameter in reporting services 2008

Hi I have a parameter called 'SiteOfClinic' which lists down few site
OHH YAC
DHH Paeds
QHH YAC
TRP Paeds
MJH Paeds
It works fine so far, but now i want to combine the top two (option 1 and 2) together, so i created another label 'OHH YAC/DHH Paeds' but I dont know what to put in the expression to combain the two.
i have tried the following but unsuccessfull
=SPLIT(JOIN(Parameters!HospitalSite.Value,"'OHH YAC,DHH Paeds"),"'OHH YAC,DHH Paeds")
and
=JOIN(Parameters!HospitalSite.Value,"OHH YAC,DHH Paeds")
please help, many thanks.
>> ' Assuming "SiteOfClinic" (aka "Parameters!HospitalSite.Value")
>> ' is an array containing 3 string values:
>> SiteOfClinic = Array("A 0", "B 1", "C 2")
>> ' and you want an array holding the first two items, you have to create a copy:
>> Copy = SiteOfClinic
>> ' and keep just the first two items
>> ReDim Preserve Copy(1)
>> ' Use Join(array, separator) to build a string from Copy
>> s = Join(Copy, "<>")
>> WScript.Echo s
>> or Split(string, separator) to get an array from s
>> a = Split(s, "<>")
>> WScript.Echo CStr(UBound(Copy)=UBound(a)), CStr(a(0)=Copy(0))
>>
A 0<>B 1
True True

Scripting.Dictionary Lookup-add-if-not-present with only one key search?

I am looking up keys in a Scripting.Dictionary to make sure I add them (and their items) only once to the dictionary:
If MyDict.Exists (Key) Then ' first internal key-value lookup
Set Entry=MyDict.Item (Key) ' Second internal key->value lookup
else
Set Entry=New ItemType
MyDict.Add Key,Entry
End If
' Now I work on Entry...
Exists looks up the key in the dictionary, and Item () does it, too. So i get two key lookups for one logical lookup operation. Isn't there a better way?
The dox for the Item property say
"If key is not found when attempting to return an existing item, a new
key is created and its corresponding item is left empty."
(MSDN)
This is true, i.e. looking up a non-existant key obviously makes this key part of the dictionary, probably with associated item = empty.
But what is that good for? How could I use this to boil it down to one lookup operation? How can I set the empty item after creating the key during the Item () property call?
This code and output:
>> Set d = CreateObject("Scripting.Dictionary")
>> WScript.Echo 0, d.Count
>> If d.Exists("soon to come") Then : WScript.Echo 1, d.Count : End If
>> WScript.Echo 2, d.Count
>> d("soon to come") = d("soon to come") + 1
>> WScript.Echo 3, d.Count, d("soon to come")
>>
0 0
2 0
3 1 1
shows:
Looking up a non existing key with .Exists does not add the key to the dictionary (.Count is still 0 at #2)
Accessing a non existing key via .Item or () - as on the right hand side of the assignment in my sample code - adds a key/Empty pair to the dictionary; for some task (e.g. frequency counting) this 'works', because Empty is treated as 0 in addition or "" in string concatenation. This small scale autovivification can't be used for objects (no decent way to map Empty to whatever object the programmer thinks off and no default magic as in Python or Ruby in VBScript)
If you have to maintain a dictionary of named objects and can access the name and its object at the same time, you can just write Set d(name) = object - d(name) will create the key slot "name" if necessary and the Set assignment will put the object into the corresponding value (overwriting Empty or the 'old' object ('pointer')).
If you append some details about what you really want to achieve, I'm willing to add to this answer.
Added:
If you (logically) work on a list of keys with duplicates and must add new
objects to the dictionary on the fly, you can't avoid the double lookup, because
you need to check for existence (1.0) and assign (2.0) the (perhaps newly
created and assigned(1.5)) object to your work variable (see /m:a or /m:b in my
sample code). Other languages with statements that deliver a value may allow
something like
if ! (oBJ = dicX( key )) {
oBJ = dicX( key ) = new ItemType()
}
oBJ.doSomething()
and without VBScript's Set vs. Let abomination something like
oBJ = dicX( key )
If IsEmpty( oBJ ) Then
dicX( key ) = New ItemType
oBJ = dicX( key )
End If
would do the extra work for new elements only, but all that is a pipe dream.
If those double lookups really matter (which I doubt - can you give an argument
or evidence?), then the overall design of your program does matter. For example:
If you can unique-fy your work list, everything becomes simple (see /m:c in my
sample). Admittedly, I still have no idea, whether such changes are possible
for your specific task.
Code to experiment with:
Dim dicX : Set dicX = CreateObject( "Scripting.Dictionary" )
Dim aKeys : aKeys = Split( "1 2 3 4 4 3 2 1 5" )
Dim sMode : sMode = "a"
Dim oWAN : Set OWAN = WScript.Arguments.Named
If oWAN.Exists( "m" ) Then sMode = oWAN( "m" )
Dim sKey, oBJ
Select Case sMode
Case "a"
For Each sKey In aKeys
If Not dicX.Exists( sKey ) Then
Set dicX( sKey ) = New cItemType.init( sKey )
End If
Set oBJ = dicX( sKey )
WScript.Echo oBJ.m_sInfo
Next
Case "b"
For Each sKey In aKeys
If IsEmpty( dicX( sKey ) ) Then
Set dicX( sKey ) = New cItemType.init( sKey )
End If
Set oBJ = dicX( sKey )
WScript.Echo oBJ.m_sInfo
Next
Case "c"
aKeys = uniqueList( aKeys )
For Each sKey In aKeys
Set dicX( sKey ) = New cItemType.init( sKey )
Set oBJ = dicX( sKey )
WScript.Echo oBJ.m_sInfo
Next
Case Else
WScript.Echo "Unknown /m:" & sMode & ", pick one of a, b, c."
End Select
WScript.Echo "----------"
For Each sKey In dicX.Keys
WScript.Echo dicX( sKey ).m_sInfo
Next
Dim g_ITCnt : g_ITCnt = 0
Class cItemType
Public m_sInfo
Public Function init( sKey )
Set init = Me
g_ITCnt = g_ITCnt + 1
m_sInfo = "Obj for " & sKey & " (" & g_ITCnt & ")"
End Function
End Class ' cItemType
Function uniqueList( aX )
Dim dicU : Set dicU = CreateObject( "Scripting.Dictionary" )
Dim vX
For Each vX in aX
dicU( vX ) = Empty
Next
uniqueList = dicU.Keys
End Function
sample output:
/m:a
Obj for 1 (1)
Obj for 2 (2)
Obj for 3 (3)
Obj for 4 (4)
Obj for 4 (4)
Obj for 3 (3)
Obj for 2 (2)
Obj for 1 (1)
Obj for 5 (5)
----------
Obj for 1 (1)
Obj for 2 (2)
Obj for 3 (3)
Obj for 4 (4)
Obj for 5 (5)
==================================================
xpl.vbs: Erfolgreich beendet. (0) [0.07031 secs]
/m:c
Obj for 1 (1)
Obj for 2 (2)
Obj for 3 (3)
Obj for 4 (4)
Obj for 5 (5)
----------
Obj for 1 (1)
Obj for 2 (2)
Obj for 3 (3)
Obj for 4 (4)
Obj for 5 (5)
================================================
xpl.vbs: Erfolgreich beendet. (0) [0.03906 secs]
The timing difference is probably caused by the reduced output of the /m:c
mode, but it emphasizes the importance of not doing something more often
then necessary.
The key problem to me is the fact that VBScript forces us to use Set with objects, and Empty is not an object. One trick that I've used in the past to get around this is to use the Array function to create a temporary placeholder for the value. Then I can check the array to see if the value is an object or not. Applied to your example:
tempArr = Array(dict.Item(key))
If IsEmpty(tempArr(0)) Then
' new entry
Set entry = New MyClass
' can't use Add because the key has already been implicitly created
Set dict.Item(key) = entry
Else
' existing entry
Set entry = tempArr(0)
End If
In this case, though, you haven't eliminated the double lookup, but moved it from the "existing entry" case to the "new entry" case.