How do I configure the perform upkeep to know which function to call in chainlink keepers? - chainlink

I want the Chainlink Keeper to call a function based on some paramters, so my checkUpkeep function is as follows:
function checkUpkeep(
bytes calldata checkData
) external view override returns (
bool upkeepNeeded, bytes memory performData
) {
if (getPrice() == roundMoonPrice[coinRound]) {
upkeepNeeded = true;
return (true, performData) ;`//should perform upkeep for the setTime() function`
} if (roundWinningIndex[coinRound].length != 0) {
upkeepNeeded = true;
return (true, performData);`//should perform upkep for the a withdrawal function
}
How do I configure the perform upkeep to know which function to call? How do I make sure it calls the correct function?

There are a number of ways you can have the keepers call the correct function. One way would be to add information in your performData designating which function to call.
The performUpkeep looks like this:
function performUpkeep(bytes calldata performData) external override {
// conditional to call one function
// conditional to call a different function
}
1. The Better way
When the Chainlink keepers call checkUpkeep they pass the returned information of performData to the input of performUpkeep. You can encode just about anything to pass as inputs to the performUpkeep function.
For example, you could pass a number to performUpkeep that corresponds with which function to call:
function checkUpkeep(
bytes calldata checkData
) external view override returns (
bool upkeepNeeded, bytes memory performData
) {
if (getPrice() == roundMoonPrice[coinRound]) {
upkeepNeeded = true;
performData = abi.encodePacked(uint256(0); // This is the new line
return (true, performData) ;
} if (roundWinningIndex[coinRound].length != 0) {
upkeepNeeded = true;
performData = abi.encodePacked(uint256(1); // This is the new line
return (true, performData);
}
Then, in your performUpkeep:
function performUpkeep(bytes calldata performData) external override {
uint256 decodedValue = abi.decode(performData, (uint256));
if(decodedValue == 0){
setTime();
}
if(decodedValue == 1){
withdraw();
}
}
We encode and decode our performData object. In fact, we can use multiple parameters as well using more clever encoding per the solidity docs.
2. The not as good, but easier to understand way
Otherwise, you could do something with storage variables if the encoding is too tricky. This isn't ideal, because multiple calls of performUpkeep will fight for the storage variable.
For example:
uint256 public functionToCall = 0;
function checkUpkeep(
bytes calldata checkData
) external view override returns (
bool upkeepNeeded, bytes memory performData
) {
if (getPrice() == roundMoonPrice[coinRound]) {
upkeepNeeded = true;
functionToCall = 0;
return (true, performData) ;
} if (roundWinningIndex[coinRound].length != 0) {
upkeepNeeded = true;
functionToCall = 1;
return (true, performData);
}
Then:
function performUpkeep(bytes calldata performData) external override {
if(functionToCall == 0){
setTime();
}
if(functionToCall == 1){
withdraw();
}
}

Related

abort object3d.traverse in three.js

How can I abort the traverse when I traverse a three.js object?
scene.traverse(x => {
if (x.userData)
// stop traversing here
});
return and break do not work
Object3D.traverse code (r134)
You would need to modify the traverse function to bail based on output from your callback function.
Something like this (untested):
// three.js/src/core/Object3D.js
traverse( callback ) {
let bailedOut = callback( this );
if( !bailedOut ) {
const children = this.children;
for ( let i = 0, l = children.length; i < l && !bailedOut; i ++ ) {
bailedOut = children[ i ].traverse( callback );
}
}
return bailedOut;
}
And then call it like:
function doTheThing( node ) {
let bailOut = false;
if( node.userData ) {
bailOut = true;
}
else {
// do the thing
}
return bailOut;
}
scene.traverse( doTheThing );
The processing basically continues until your callback returns true, at which point it triggers a cascade back up the traverse recursion chain until it exits the original call.

Compare most recent values from multiple BehaviorSubjects

Say I have this:
isMatchedCountLessThanTotalCountMessage(){
// I want to implement this
// "returns" a string asynchronously
}
getMatchedEventsCount() {
return this.dcs.matchCount.asObservable();
}
getTotalEventsCount() {
return this.dcs.totalCount.asObservable();
}
matchedCount and totalCount are like so:
public matchCount = new BehaviorSubject<number>(0);
public totalCount = new BehaviorSubject<number>(0);
these Observables fire integers as values change. Anytime a value is fired from either one, I want to compare the two most recent values from both, how do I do that?
What I want to do is return a boolean from the method
so I can display in the HTML:
<div>{{(isMatchedCountLessThanTotalCountMessage() | async)}}</div>
I think Observable.zip might do the trick:
isMatchedCountLessThanTotalCountMessage(){
return Observable.zip(
this.getMatchedEventsCount(),
this.getTotalEventsCount()
)
.subscribe(function(v){
const intA = v[0];
const intB = v[1];
if(intA > intB)
// but I don't know how to send a message the HTML from here
});
}
You can easily use .map() function to transform the data you want:
isMatchedCountLessThanTotalCountMessage() {
return Observable.combineLatest(
this.getMatchedEventsCount(),
this.getTotalEventsCount(),
)
.map(([intA, intB]) => {
return intA > intB ? '(results ARE filtered)' : '(results are not filtered)'
})
}
This works, although we might be able to use something other than Observable.zip.
isMatchedCountLessThanTotalCount() {
return Observable.create(obs => {
return Observable.zip(
this.getMatchedEventsCount(),
this.getTotalEventsCount()
)
.subscribe(v => {
if ((v[1] - v[0]) > 0) {
obs.next('(results ARE filtered)')
}
else {
obs.next('(results are not filtered)');
}
});
});
}
and there is actually a simpler way to do that using what's called a "projection function":
isMatchedCountLessThanTotalCount() {
return Observable.combineLatest(
this.getMatchedEventsCount(),
this.getTotalEventsCount(),
function (one, two) {
if ((two - one) > 0) {
return '(results ARE filtered)'
}
return '(results are not filtered)';
}
)
}
Observable.combineLatest() is similar to Observable.zip() but will fire upon the first new value, it doesn't wait for new values to come from all observables.

IInternetProtocolRoot::Start is never called

I am working on Asynchronous Pluggable Protocol Handler according to
https://msdn.microsoft.com/en-us/library/aa767916(v=vs.85).aspx#Creating_an_Asynchro
but step 3 is not happens. Urlmon.dll is supposed to call QueryInterface on my pluggable protocol handler for its IInternetProtocol interface and it does not. I am missing something and I can not figure it out. Does anybody know what the problem?
On step 2, ParseUrl is called twice:
if( ParseAction == PARSEACTION::PARSE_SECURITY_URL ) {
if( cchResult < _countof(L"http://localhost/") ) {
return S_FALSE;
}
memcpy(pwzResult, L"http://localhost/", sizeof(L"http://localhost/"));
*pcchResult = _countof(L"http://localhost/") - 1;
return S_OK;
}
if( ParseAction == PARSEACTION::PARSE_DOMAIN ) {
if( cchResult < _countof(L"localhost") ) {
return S_FALSE;
}
memcpy(pwzResult, L"localhost", sizeof(L"localhost"));
*pcchResult = _countof(L"localhost") - 1;
return S_OK;
}
return INET_E_DEFAULT_ACTION;

LINQ ToList() causes all records to be the last one off a coroutine

I seem to have an misunderstanding because the following code works correctly if I don't append the ToList() command:
IEnumerable<ProcessorInfo> query = (
from n in InfoGet(EMachineInfoDepth.LogicalProcessor)
select n
)
.ToList();
InfoGet looks like this:
internal static IEnumerable<ProcessorInfo> InfoGet(EMachineInfoDepth depth)
{
ProcessorInfo result = new ProcessorInfo();
// loop through all workgroups
foreach (Workgroup wg in workgroups_S)
{
result.Workgroup = wg;
if (depth >= EMachineInfoDepth.NUMANode)
{
// loop through all NUMANodes
foreach (NUMANode node in wg.NUMANodes)
{
result.NUMANode = node;
if (depth >= EMachineInfoDepth.CPU)
{
// loop through all CPUs
foreach (CPU cpu in node.CPUs)
{
result.CPU = cpu;
if (depth >= EMachineInfoDepth.Core)
{
// loop through all Cores
foreach (Core core in cpu.Cores)
{
result.Core = core;
if (depth >= EMachineInfoDepth.LogicalProcessor)
{
// loop through all LogicalProcessors
foreach (LogicalProcessor lp in core.LogicalProcessors)
{
result.LogicalProc = lp;
yield return result;
}
}
else
{
yield return result;
}
}
}
else
{
yield return result;
}
}
}
else
{
yield return result;
}
}
}
else
{
yield return result;
}
}
}
With ToList() I get the correct count, but all records equal the final element in the sequence. While I get that this could be a variable scope error in my complex coroutine, as in all iterations see the final value, why does the code work without ToList()?
My question is: what am I misunderstanding?
Problem is, you're returning reference to the same variable all the time:
ProcessorInfo result = new ProcessorInfo();
That's the only place you're actually creating new ProcessorInfo object. You only change it's properties values later, but return still the same object.
You should consider adding copy constructor into your ProcessorInfo() class, and replace every yield return result; call with yield return new ProcessorInfo(result);. That would be the easiest way to make it work.
Update
It could look like it works e.g. when you've saved some variable state somewhere during loop:
foreach(var item in query)
{
itemsList.Add(item);
propertyList.Add(item.IntProperty);
}
After that call itemsList will contain incorrect data, while propertyList will be just fine.

Axapta Validation Override Always Executes Twice

In most cases, validation methods I've overridden execute twice each time the parent field is changed. Everything still works, but the InfoLog displays double messages every time.
Is there any way to prevent this?
Thanks
public boolean validate()
{
boolean ret;
int exlowValue;
int lowValue;
int highValue;
int exhighValue;
str errorMessage;
;
ret = super();
//Make sure a numeric value was entered
if (ABC_RegExValidator::validateMe("integer", int2str (ABC_Checks_checkExtremeLow.value())))
{
//get the form values
exlowValue = ABC_Checks_checkExtremeLow.value();
lowValue = str2int(ABC_Checks_checkLow.valueStr());
highValue = str2int(ABC_Checks_checkHigh.valueStr());
exhighValue = str2int(ABC_Checks_checkExtremeHigh.valueStr());
//Extreme Low must be 0 or less than all others
if (exlowValue != 0)
{
//A non-zero value was entered; it must be less than all other fields
if ((exlowValue >= lowValue && lowValue > 0) || (exlowValue >= highValue && highValue > 0) || (exlowValue >= exhighValue && exhighValue > 0))
{
//Return an error
ret = checkfailed(strFmt("#ABC197", int2str(exlowValue)));
}
else
{
//Not greater than any other value
//Success!
ret = true;
} //Greater than all others?
}
else
{
//No errors
ret = true;
} // 0?
}
else
{
//Regular expression failed
//Return an error
ret = checkfailed("#ABC192");
} //Regular expression
return ret;
}
Your description of the problem is not really clear. One can override the valite method on a form control, the validate method on a form datasource and the validatefield method on the table. That's my knowledge of version 3.0.
And how do you mean the "parent field"? I presume the table field?
If I put info messages in each of these methods they only execute once when I modify a value. That's the case in 3.0. I don't know which version you're using.
Maybe you could be more precise about which validation method you're testing?

Resources