UPDATE and READKEY at the same time? - progress-4gl

In my application I'm building, I'd like for the first screen to be an UPDATE to an integer, but I'd like to have an option to press F2 to access a different kind of functionality in the program.
When I try it the logical way, I get buzzed at since the UPDATE is expecting INTEGER only input, and I'm pressing F2.
Can you UPDATE and READKEY successfully at the same time?

You're trying to do it the old way with editing blocks - try reading up on event-driven programming, where the code describes events and what gets run when a certain event happens. The code would look something like this:
ON F2 of update-field
DO: /* something */
END.
UPDATE update-field.
Better yet, don't use "UPDATE", do a "WAIT-FOR" instead.

Related

Clear a field when state changes - Salesforce

I want to make it so that when you fill in a field (in case) X and go to a state, it is deleted (this field should be saved in the history, I think this is done by default). This is necessary so that the user does not have to be hitting the pencil and erasing the message that comes from another state.
As I saw with a Trigger it can be done, do you have any idea?
You don't need code for it, you could do it with config changes (workflow / flow / process builder). But if you're really after a trigger - something like that.
trigger CaseTrigger on Case(before update){
for(Case c : trigger.new){
Case old = trigger.oldMap.get(c.Id);
if(c.Status != old.Status){
c.Description = null; // whichever field you want to wipe
}
}
}
Edit about 0 code solutions
Look into workflows, flows and process builder. Actually if you're starting fresh maybe focus on flows, the other 2 are bit passe and SF recommends migrating away: https://admin.salesforce.com/blog/2021/go-with-the-flow-whats-happening-with-workflow-rules-and-process-builder
Have a look at these and if you're stuck: consider posting at dedicated https://salesforce.stackexchange.com. StackOverflow is really for code related stuff, you'll reach more admins over there.
https://trailhead.salesforce.com/content/learn/modules/flow-builder
https://trailhead.salesforce.com/en/content/learn/modules/platform-app-builder-certification-maintenance-winter-21/get-handson-with-flow-before-save-trigger-when-certain-record-changes-are-made
https://salesforce.stackexchange.com/questions/301451/trigger-flow-if-a-specific-field-on-the-updated-record-changed
https://help.salesforce.com/s/articleView?id=release-notes.rn_forcecom_flow_fbuilder_prior_values_flow.htm&type=5&release=230

Connecting FluidEnter/FluidExit at run-time

I am toying with the FluidEnter/FluidExit. So in a simple form, here is what I am trying to do:
I created in Main an empty population of agent called Terminal. For now, in Terminal, there is only a fluidEnter connected to a fluidExit (very simple)
enter image description here
Now, on startup, I want to fill this population and set up the proper connections (the terminals are ordered).
So, on startup, I call a function init(), whose body start with Terminal t = add_terminals(); (I have only one terminal for now, just toying with things)
In Main, obviously, I also have a fluidEnter and a fluidExit. I would like to connect the fluidExit of Main to the fluidEnter of the terminal t, and the fluidExit of the terminal t to the fluidEnter of Main, so code (still in init()) looks like
fluidExit.set_fluidEnter(t.fluidEnter);
t.fluidExit.set_fluidEnter(fluidEnter);
I get an exception so obviously, I am doing something wrong. Any idea?
I think the set_fluidEnter function is deprecated or just non-functional.
Instead, you should do:
fluidExit.connect(t.fluidEnter);
So just replace set_fluidEnter with connect... nothing else.
That should do the trick
I was going down the same path as you a couple of months ago. Yes... .connect() works great. It even works as a gate. If it is disconnected, then fluid stops at the exit. Once connected, fluid starts to flow again. It is very slick.

Run Two Action At The Same Time Inside ONE Sequence

I'm not sure if what I'm seeking is possible, but I'm just checking to make sure I'm not doing thing the hard way.
At the moment I have two sequences, which both run at the same time. Each sequence starts off by waiting 3 seconds and then one sequence scales a node, where the other adjusts that node's alpha. So the code looks something like this:
node.runAction(SKAction.sequence([animationWait, animationScale]))
node.runAction(SKAction.sequence([animationWait, animationAlpha]))
But is there a way of running both the animationScale and animationAlpha at the same time inside one sequence? So it will look something like this (this doesn't work, but I'm hoping you can see what I'm trying to do):
node.runAction(SKAction.sequence([animationWait, (animationScale, animationAlpha)]))
You can group actions together to a sequence:
var actions = Array<SKAction>()
actions.append(SKAction.sequence([animationWait, animationScale]))
actions.append(SKAction.sequence([animationWait, animationAlpha]))
let group = SKAction.group(actions)
node.runAction(group)
When the action executes, the actions that comprise the group all start immediately and run in parallel. The duration of the group action is the longest duration among the collection of actions. If an action in the group has a duration less than the group’s duration, the action completes, then idles until the group completes the remaining actions. This matters most when creating a repeating action that repeats a group.
I just tested something out, and it seemed to have worked. Instead of the below:
node.runAction(SKAction.sequence([animationWait, (animationScale, animationAlpha)]))
do:
node.runAction(SKAction.sequence([animationWait, [animationScale, animationAlpha]]))
I'm surprised it worked. I was going to delete the question, but someone might find this handy.
EDIT:
The below no longer works
node.runAction(SKAction.sequence([animationWait, [animationScale, animationAlpha]]))
As evilboxingdragonslayer suggested, you will need to use "group", see below:
node.runAction(SKAction.sequence([animationWait, group([animationScale, animationAlpha])]))

Getting Updated Value while using lock?

this is my first Procedure.
define frame LockFrame Customer.Name Customer.CreditLimit Customer.Balance.
pause.
DO TRANSACTION:
for each Customer exclusive-lock:
assign Customer.CreditLimit = Customer.CreditLimit + 5.
pause 1 no-message.
display Customer.Name Customer.CreditLimit Customer.Balance.
end.
end.
and thsi is my second Procedure.
define frame LockFrame Customer.Name Customer.CreditLimit Customer.Balance.
pause.
DO TRANSACTION:
for each Customer exclusive-lock:
assign Customer.Balance= Customer.Balance + 2.
pause 1 no-message.
display Customer.Name Customer.CreditLimit Customer.Balance.
end.
end.
When I run first Procedure and just after second procedure, I have to get the value Updated by first (here CrditLimit).(and vice versa)
But I am not able to run second since the record is locked by the first.It is showing an error message.
I think problem is with my locking.Please help on this.
This is exactly what you should expect.
The record is locked, exclusively for the benefit of the first procedure, until the transaction commits. The commit will occur at the 2nd END statement.
I'm not sure why you have PAUSE in there -- you should never block on IO inside a transaction block -- that will only lead to problems (like users locking each other while they get up and go get coffee...)
You almost NEVER really want to enclose an update of an entire table in a transaction (which is what your DO TRANSACTION block is doing). Even if you think that is what you want to do, or have been told that that is what you must do it is probably wrong. This is usually the result of confusing a "business transaction" with a "database transaction" -- they are not the same thing -- especially when large amounts of data are in play.
A better way to write your code (apply the same concept to both samples):
define buffer updCustomer for customer.
for each customer no-lock /* where whatever */:
/* maybe some no-lock logic... */
do for updCustomer transaction:
find updCustomer exclusive-lock where recid( updCustomer ) = recid( customer ).
assign
updCustomer.creditLimit = customer.creditLimit + 5.
.
display
updCustomer.name
updCustomer.creditLimit
updCustomer.balance
.
end.
pause 1 no-message.
end.
Using NO-LOCK on the FOR EACH allows selection logic or other logic to run without needing the lock. Using the update buffer and the DO FOR ... TRANSACTION block tightly scopes the record lock and the transaction to that single block. Placing the PAUSE outside the block prevents the "user goes to get coffee" problem.
I hesitate to comment on any answer that Tom has given, since I consider him authoritative. But I want to point out two small things.
First of all, the use of RECID might be better as ROWID. ROWID is recommended for use by Progress (see http://documentation.progress.com/output/OpenEdge102a/oe102ahtml/wwhelp/wwhimpl/common/html/wwhelp.htm?context=dvref&file=dvref-15-48.html) since RECID is "supported for backward compatibility. For most applications, use the ROWID function, instead."
But that's minor, really. What's also important in my opinion is what Tom did in his example for you - he defined a buffer ("define buffer updCustomer for customer.") that he used in the update. I want to encourage you to use buffers EVERY time you work with a record, especially if you get into using persistent or super procedures, or if you are using functions or internal procedures.
Why? Defining a buffer ensures that the scope of the buffer you are updating is limited to the place where you defined it. As an example, Progress will "leak" the default buffer into your super procedure if you aren't careful. Imagine this scenario...a program that finds a record, calls a function in a super procedure to do "some stuff" and then deletes the record.
FIND MyTable WHERE MyTable.fk = fkValue NO-LOCK NO-ERROR.
UpdateOtherStuff(MyTable.fkValue).
DeleteMyRecord(MyTable.fkValue).
But in "UpdateOtherStuff", it does some work including this...
FOR EACH MyTable:
If MyTable.Thing = 'ThingOne' THEN LEAVE.
/* other processing here... */
END.
You might be surprised when you find that the super procedure shares the default "MyTable" buffer with your program, and ends up repositioning the record somewhere you don't want...so that the call to "DeleteMyRecord()" has a different record than you expect.
The problem would be solved if "UpdateOtherStuff" had a "DEFINE BUFFER ... FOR MyTable" at the top, even if it was "DEFINE BUFFER MyTAble for MyTable" (strange as that looks...).
That's why Tom's example, including a DEFINE BUFFER..., should be a template for the work you do in the ABL.
This question was asked previously - see https://stackoverflow.com/a/5490130/1433147.

How to ignore some subroutine calls in NYTProf reporting

I'm trying to profile a Perl script, but CORE::sleep gobble all the space (and time) of my report.
How can i tell NYTProf to ignore sleep calls ?
Assuming we have the following script :
sub BrandNewSubroutine {
sleep 10;
print "Odelay\n";
}
BrandNewSubroutine();
I want to get rid of the following line of the report :
Exclusive Time;Inclusive Time;Subroutine
10.0s;10.0s;main::::CORE:sleepmain::CORE:sleep
(opcode)
Edit: Using DB::disable_profile() and DB::enable_profile() won't do the trick, as it add sleep time to BrandNewSubroutine Inclusive time.
Thanks in advance.
I'd suggest either wrapping the calls to sleep (possibly by use of method mentioned in perlsub) with DB::disable_profile() and DB::enable_profile() calls (RUN-TIME CONTROL OF PROFILING in NYTProf documentation), or post processing the report to remove the offending calls.
CORE::accept is already ignored in the way you'd like CORE::sleep to be, so the mechanism is already in place. See this code in NYTProf.xs:
/* XXX make configurable eg for wait(), and maybe even subs like FCGI::Accept
* so perhaps use $hide_sub_calls->{$package}{$subname} to make it general.
* Then the logic would have to move out of this block.
*/
if (OP_ACCEPT == op_type)
subr_entry->hide_subr_call_time = 1;
So with a little hacking (OP_SLEEP==op_type || OP_ACCEPT == op_type) you'd be able to ignore CORE::sleep in the same way.
I'd accept a patch to enable that as an option.