I have this simplified scenario:
asset device identified by deviceID
{
o String deviceID
o Data reading
}
concept Data identified by readingID
{
o String ReadingID
o Double Lng
o Double Lat
}
Is it possible to avoid that different devices have the same reading associated, like a unique relationship? An example:
deviceID = 1111 --> readingID = aaaa
deviceID = 2222 --> readingID = aaaa
I am trying to avoid this situation. I tryied to use a relationship using:
asset device identified by deviceID
{
o String deviceID
--> Data reading
}
taking Data as an Asset, but I have the same problem.
firstly your model is:
asset device identified by deviceID
{
o String deviceID
o Data reading
}
concept Data
{
o String readingID
o Double Lng
o Double Lat
}
secondly, relationships in Composer are not used to 'enforce' uniqueness a la RDBMS (as it doesn't use an RDBMS it uses a key/value store).
The simplest way to check if your device asset tries to use a readingID (stored in a concept, stashed in an asset in the asset registry) that's already associated with an asset is to run a query on the registry and use a true or false in your transaction code. Unless you stored the already used IDs elsewhere as a registry, but adds more maintenance etc.
Related
In Stata, in a foreach loop, I am searching for values within string variables, using strmatch() and asterisk (*) wildcards. I need the asterisks because I'm searching for words that fall into any part of the string.
These string variables are nested into local macros. However using * in the foreach does not work with Stata IF it is part of a nested/descendant macro. Is this because:
A) wildcards within strings can never be used in foreach in Stata when using nested macros, or
B) it isn't the wildcard itself, but the * (asterisk) that is producing the error in foreach?
If B), is it possible to define a new character that means 'wildcard' instead of * so I can still use nested macros to organize my concepts before doing foreach?
Note: I'm working with a large dataset so the strmatch() function without the foreach loop is not a solution, unless there is an alternative to foreach.
Here's an example, for drug class Q (parent/ancestor macro), with individual drug lists (descendant macro):
*chem term list
local drug_list1 " "A*B" "B*A" "A" "
local drug_list2 " "C*D" "D" "
*search term list
local drugclassQ " "drug_list1" "drug_list2" "
*check macro data successfully stored
di `drugclassQ'
(successfully stored)
*Search all drug terms in descriptions
foreach searchterm in "drugclassQ" {
gen byte `searchterm' = 0
di "Making column called `searchterm'"
foreach chemterm in ``searchterm'' {
di "Checking individual search terms in: `chemterm'"
foreach indiv in ``chemterm'' {
di "Searching all columns for *`indiv'*"
foreach codeterm in lower(variable) {
di "`searchterm': Checking `codeterm' column for *`indiv'*"
replace `searchterm' = 1 if strmatch(`codeterm', "*`indiv'*")
}
}
}
}
gen keep_term = .
replace keep_term=1 if drugclassQ==1
keep if keep_term==1
Here's an example of what I would want the foreach loop for find, searching within the string variable chemical
For example searching on "A*B" within parent macro drugclassQ would find drugs with string values within the string variable chemical as the following:
Amg / Fmg /B A/B A/ B/R Amg/dose / Emg/dose / Bmg/dose
(note: mg = milligrams to illustrate my point about needing to define the variable as a string since the drugs are entered into the database in different ways)
Example Output to identify strings with A and B anywhere within values of 'Chemical':
Obs
Chemical (string variable)
drugclassQ
1
Amg / Fmg /B
1
2
A/B
1
3
A/ B/R
1
4
Amg/dose / Emg/dose / Bmg/dose
1
5
A
0
My code works when I don't use asterisks, but then that defeats the premise of how I'm using the foreach code, i.e. using the wildcard that is within nested macros.
Any solutions?
Basically, I have to go through all baselines of an object until I get the author who modified "_ReqStatus" attribute and copy that value in "_Ownr" attribute. Everything is working fine for the current baseline, but I cannot get through the older baselines of the module. I have to mention that I run the script for 2000 objects each one having at least 20 baselines.
My code looks like this:
//scriptul recunoaste obiectele cu "ReqStatus modifica"
pragma runLim, 0
Module m = current
History h
HistoryType ht
Object o
string attributName
string attributNameBaseline
string authorName
string newOwner
Baseline lBaseLine
noError()
for o in entire m do {
**for lBaseLine in module(o) do{ //These 2 code lines were my try to load all baselines
Module lBaseMod = load(module(o), false) //but with no results**
for h in o do
{
string owner = ""
attributName=""
attributName = h.attrName
authorName=""
owner = o."_Owner"
if isDeleted(o) then continue
if(attributName=="_ReqStatus")
{
authorName=h.author
//print authorName
//print "\n"
if(null owner)
{
print identifier(o)
print "\n"
newOwner = authorName
print newOwner"\n"
o."_Ownr" = newOwner
//print newOwner
break
}
}
}
}
}
ErrMess = lastError()
Thanks
Tony Goodman provides a script "Smart History Viewer" at http://www.smartdxl.com/content/?p=418, Michael Sutherland has one at https://www.ibm.com/mysupport/s/forumsquestion?id=0D50z00006HIGSUCA5, also, if you do a search on https://www.ibm.com/mysupport/s/forumshome for e.g. "dxl history" you might find some more code examples which should help you with this topic.
Your problem is the variable o. It is set only in the loop for o in entire m, it always refers to the o in the current version of m, never to the corresponding Object in a baseline. When you open the Module lBaseMod, o is not automatically reassigned.
So, use a new variable of type Object, set it to the Object in the baseline corresponding to o and browse through this new Object's history, see the linked scripts for reference.
Also, you should rework the flow of your script. With your approach, you open all the Baselines of m for each Object. In your case this means 2000 * 20 load and close. It will be much faster (though not necessarily less memory consuming) to open all the baselines of m in an outer loop, probably using a Skip list to collect the necessary information.
Also note that when you test your script, "print" becomes very slow after some time. It will be faster if you remember all the values that you want to print e.g. in a Buffer and print it at the end of your script, or write the output to a file.
I want to find specified text within a string in a given column, and count how many times that string is repeated throughout the entire column.
For example, Find "XX" within a string in a column and print to dialogue box the number of times that text was found.
Module m = current
Object o
string s
string x
int offset = null
int len = null
int c
for o in m do
{
string s = probeAttr_(o, "AttributeA")
x = o."Object Text" ""
if(findPlainText(s, "XX", offset, len, false)){
print "Success "
} else {
print "Failed to match"
}
}
I have tried to use command findPlainText but I am inadvertently passing every object as true.
As well I placed the output to print 'success' or 'Failed to match' so I can at least get a number count of what is being passed. Unfortunately it seems like everything is being passed!
My understanding is that 'probeAttr_(o, "AttributeA")' allows me to specify and enter what column to search. As well o."Object Text" "" now allows me to look within any object and search for any text contained. I also realize that variable x is not being used but assume it has some way of being used to solve this issue.
I only use DOORS at a surface level but having this ability will save other staff tons of time. I realize this may be accomplished using the DOORS advanced filtering capability but I'd be able to compound this code with other simple commands to save time.
Thank you in advance for your help!!
If you want to count every occurence of a specified string in a text in an attribute for all objects, I think Mike's proposal is the correct answer. If you are only interested, if the specified string occurs once in that object's attribute, I suggest using Regexp, as I find it very fast, quite powerful and nevertheless easy to use, e.g.:
Regexp reSearch = regexp2 "XX"
int iCounter = 0
string strOT = ""
for o in m do {
strOT = o."Object Text" ""
if (reSearch strOT) {
iCounter++
}
}
print "Counted: '" iCounter "'\n"
Most of this has been answered in (DXL/Doors) How to find and count a text in a string?
You can easily exchange the "print" with a counter.
I have created a DXL script that goes through every row of a couple modules. I am printing out certain rows and its information. I am doing this by having a for loop that goes through the rows and if it hits a row that I am interested in, I save the elements in the columns of this row to different string variables and print those string variables. The script does not take too long to run if the module does not have a lot of rows I am interested in but if I want to run multiple modules at the same time or if a module has a lot of rows I am interested in, the script can take hours. I can show the code that I have if this is not enough to come up with solutions. Any help would be appreciated!
I have tried using a skip list to store the print statements in that and then tried going through the skip list to print each value but that did not make the script run any faster.
string sep=","
for o in m do
{
string ver1= o."column1"
if (checkIf(o) && (!(isDeleted(o))))
{
string ver2= o."column2"
string onum=number(o)
""
string otext = o."Object Text"
print ver1 sep ver2 sep onum
}
}
Initial optimization:
for o in m do
{
if (checkIf(o) && (!(isDeleted(o)))) {
//This doesn't appear to be used?
//string otext = o."Object Text"
print o."column1" "," o."column2" "," number(o) "\n"
}
}
Reasoning: DOORS has a system in place called the string table that holds declared strings in memory- and doesn't necessarily do the best at clearing it out when appropriate. By constantly declaring strings in your loop, you might be bumping into the memory limits of that system.
Problem with this is that the results all end up in that 'DXL editor' little window, and then have to be copy and pasted somewhere else to actually use it.
Secondary optimization:
// Turn off runlimit for timing
pragma runLim , 0
// Set file location - CHANGE FOR YOUR COMPUTER
string csv_location = "C:/Users/Username/Desktop/Info_Collection.csv"
// Open stream
Stream out = append csv_location
// Set headers
out << "Module,Column 1,Column 2,Object Number" "\n"
// Define your loop constraints
Module m = current
Object o
// Run your loop
for o in m do
{
if (checkIf(o) && (!(isDeleted(o)))) {
//This doesn't appear to be used?
//string otext = o."Object Text"
out << fullName(m)","o."column1" "," o."column2" "," number(o) "\n"
}
}
close out
This will let you run the same script in different modules, all outputting to the same CSV file, which you can then load into Excel or your data manipulation engine of choice.
This keeps the data collection happening outside of DOORS, so if something goes awry, you can track down where it occurred.
My third optimization would be to use a list of modules in, say, excel as an input and do this analysis, but that might be going too far.
If this doesn't help, then we can start examining other issues.
Note- I still would like to know what 'checkIf' is/does.
If your objective is to speed up the execution of the script, since most of the objects are of no interest to you, the most effective way I know of is to filter out most of the objects that are not interesting, e.g., a filter which is obj."Object Text" != "" would filter out Headings, if you are just interested in requirements, obj."Object Text" contains "[Ss]hall" etc. Save as a view for later use.
for o in m do { respects the display set, so if you don't touch most of the objects it will speed it up a lot!
Hope this helps.
Don
Using regular expressions I have managed to extract all sender addresses from the emails located in my Inbox, However I've tried and failed many times to also extract the associated UIDs for those individual emails.
Here's what I have so far:
result, data = mail.search(None, 'ALL')
ids = data[0]
id_list = ids.split()
for i in id_list:
typ, data = mail.fetch(i,'(RFC822)')
for response_part in data:
if isinstance(response_part, tuple):
msg = email.message_from_bytes(response_part[1])
sender = msg['from'].split()[-1]
address = re.sub(r'[<>]','',sender)
# Ignore any occurences of own email address and add to list
if not re.search(r'' + re.escape(LOGIN),address) and not address in email_list:
email_list.append(address)
print address
The output is slow (I'm assuming because of regular expressions) but none the less it gets the job done.
Output:
no-reply#mail.instagram.com
no-reply#accounts.google.com
rhodesi926#icloud.com
wat#elevenyellow.com
pinbot#notifications.pinterest.com
support#autopin.co
pinbot#account.pinterest.com
info#shootbox.me
pinbot#explore.pinterest.com
bugra#boostfy.co
mail-noreply#google.com
pinbot#inspire.pinterest.com
mua#mikasabeauty.com
noreply#apple.com
privacy-noreply#policies.google.com
Part of the problem is I don't understand how the UIDs are connected to the sender and where the UIDs get stored in the IMAP structure.
Im assuming I could right a regular expression that could pull any 4 digit combination of numbers from the "UID:" Field, I then fear it will slow my script down to a crawl....
If anyone understands Imaplib and can help I would be eternally grateful. Thank You.