SendGrid Handle bars variable in json not show up when used a second time - handlebars.js

I have this handle bars statement in SendGrid. When using the variable taskCount the value is only used in the greaterThan block. The other 2 times it is used it appears to be null.
Here is the json data
{
"Username":"ChampCbg",
"JoinedAt":"12/1/2020",
"DaysSinceJoined":"20",
"taskCount":5
}
here is statement with handlebars
{{#greaterThan taskCount 0}}
Congrats on starting {{insert taskCount "default=1"}} task{{#greaterThan taskCount 1}} (s){{/greaterThan}} and taking the first small step.
{{else}}
You have not started a task yet. What are you waiting for? It has been {{DaysSinceJoined}} days since you joined on {{JoinedAt}}.
You have missed {{DaysSinceJoined}} days where you could been making Small Steps towards the dreams of you better tomorrow.
{{/greaterThan}}
Here is the end result
Hello ChampCbg!
Congrats on starting 1 task and taking the first small step.
Don't let another day pass you by. Start designing you vision board
today.
As the results show the greaterThan block selects the correct statement, but then next times taskCount is used the default value and null value are chosen.
What is the cause of this?

Twilio SendGrid developer evangelist here.
Honestly, I thought your template would work as you wrote it. But I tried it out and it did not (not that I didn't believe you, I just had to do that to work out what to do!).
So, the way to deal with this is to refer to the variables in your data using the #root object within the greaterThan conditional (or other conditionals).
Try this as your template:
{{#greaterThan taskCount 0}}
Congrats on starting {{insert #root.taskCount "default=1"}} task{{#greaterThan #root.taskCount 1}} (s){{/greaterThan}} and taking the first small step.
{{else}}
You have not started a task yet. What are you waiting for? It has been {{#root.DaysSinceJoined}} days since you joined on {{#root.JoinedAt}}.
You have missed {{#root.DaysSinceJoined}} days where you could been making Small Steps towards the dreams of you better tomorrow.
{{/greaterThan}}

Related

Moment misunderstanding utcOffset

I'm working with moment and moment-timezone and I don't get it. Can anyone explain me why this happens?
THIS (which is what I want):
moment('2018-11-28T00:00:00.000-02:00').toISOString()
Prints 2018-11-28T02:00:00.000Z
BUT:
moment('2018-11-28T00:00:00.000').zone('-02:00').toISOString()
moment('2018-11-28T00:00:00.000').utcOffset('-02:00').toISOString()
Both print 2018-11-27T23:00:00.000Z
PD: My zone is GMT+1.
Why are different? it is not supposed to be equals?
How do I set the offset (not in the constructor but with a method after I have de moment object)?
Thanks! BR
As I can see, you want to keep the existing time of day when using utcOffset method. It accepts a second parameter, which is a boolean. As the documentation says:
Passing true will keep the same local time, but at the expense of choosing a different point in Universal Time.
// "2018-11-28T02:00:00.000Z"
moment('2018-11-28T00:00:00.000').utcOffset('-02:00', true).toISOString();
For more information check the documentation

After Effects Expressions - controling comps from main comp using an "Expressions Layer"

THE GOAL I WANT TO ACHEIVE:
Control AE timelines using ONE EXPRESSION LAYER (much like using Actionscript) to trigger frequently used comps such as blinking, walking, flying etc... for cartoon animation.
I want animate a the blinking of a cartoon character. (and other actions, explained below) Rather than "re posting" the comp or key frames movements every time I want a blink or a particular action, I want to create a script where I can trigger the Blink comp to play. Is this possible? (Sidenote: A random blink through entire movie would be nice) but I still want to know how to do this for the reasons below.
Ideally: I would like to create an "Expressions layer" in the main comp to TRIGGER other comps to play. At certain points I would like to add triggers to call frequently used comps that contain actions like.. Blinking, Walking, Flying, Look Left and Right etc...
IT WOULD BE AMAZING IF somehow we could trigger other comps to begin, repeat, stop, maybe reverse, and do this all from one Main Comp using an expression layer.
WHY DO IT THIS WAY?
Why not just paste a comp in the spot you want it to play every time you want such action? Well in after effects if you wanted a "blink comp" to play 40 times in two minutes you would have to create 40 layers, or pate the key frames on that comp 40 times. Wouldn't it be awesome to trigger or call it from one one layer when you wanted it from one expressions layer?
We do something like this in Flash using Actionscript all the time. It would be awesome if there was a method out there to achieve this effect. This would be an OUTSTANDING tutorial and I believe it would be very popular if someone did it. It could be used for a MULTITUDE of amazing effects and could save a ton of time for everyone. Heck, help me figure this out and perhaps I will make a tutorial.
Thank you all ye "overflowing Stackers" who contribute! :)
I found the answer and that is...
IT'S NOT POSSIBLE.
After Effects expressions can not control other timelines. Unfortunately you have to put an expression on each layer you want to affect.
The next best solution, and to achieve something close to what I was asking can be found on this link: motionscript.com/design-guide/marker-sync.html
We can only hope that Adobe will someday give the power to expressions like they did with action-script.
HOPEFULLY SOON! Anyone reading this who works for Adobe please plead our case. Thanks
Part 1: Reference other layers in pre-Comps
Simply replace "thisComp" with "comp("ComName")"
To reference Effect-Controllers between compositions, follow the below formula:
comp("ComName").layer("LayerWithExpression").effect("EffectControlerName")("EffectControllerType")
More In-depth Answer: Adobe's Docs - Skip to the Layer Sub-objects part
As I understand the Adobe documentation, only Layers can be accessed,
not footage. What this means is that you will need to create your
expression link utilizing a pre-Comp. Footage can not access this so
that also means no nulls, adjustment layers, etc.
As an added bonus, if you use the essential graphics panel, you can put all the controllers in one pre-comp, but have the controls available no matter which comp you are in. Just select it in the Essential-Graphics dropdown.
Part 2: Start/End based on other layers within pre-comps:
Regarding the next part where you want the expressions to activate based on other compositions, I recommend using the in-out Point expression.
inPoint | Return type: Number. Returns the In point of the layer, in seconds.
outPoint | Return type: Number. Returns the Out point of the layer, in seconds.
If you utilize the start time overrides you can pull this from:
startTime | Return type: Number. Returns the start time of the layer, in seconds.
Alternate Option:
I would recommend avoiding this as the keyframes are basically referenced as an index, so things can get messed up if you add one ahead of a keyframe you were already using - def incorporate some error handling.
Refer to the Key attributes and methods (expression reference) Here
Part 3: Interpolation & Time Reversal
You can time reverse the layer in the rightclick->time, otherwise this is all interpolation expressions like loop out etc - you can loopOut("FOO") a pre-comp if you not only cut it correctly, but also enable time remapping.
then use this to loop those keyframes;
try{ timeStart = thisProperty.key(1).time; duration = thisProperty.key(thisProperty.numKeys).time-timeStart; pingPong =
false; //change to true value if you want to loop animationn back &
forth quant=Math.floor((time-timeStart)/duration);
if(quant<0) quant = 0
if(quant%2 == 1 && pingPong == true){
t = 2*timeStart+ (quant+1)*duration - time;
}
else{
t = time-quant*duration;
}
}
catch(err){
t = time;
}
thisProperty.valueAtTime(t)

Applying more than one sort on a Tridion broker query

I have a broker query where I need to sort by 2 different fields (using JSP and 2011 SP1)
The API has the method "addSorting" which I am applying.
It appears, however, that the second addSorting call is overwriting the first addSorting call - rather than adding the second sort:
// Sort by Date
CustomMetaKeyColumn customMetaKeyColumnDate = new CustomMetaKeyColumn("date", MetadataType.DATE);
query.addSorting(new SortParameter(customMetaKeyColumnDate, SortParameter.DESCENDING));
// Sort by Owner
CustomMetaKeyColumn customMetaKeyColumnOwner = new CustomMetaKeyColumn("owner", MetadataType.STRING);
query.addSorting(new SortParameter(customMetaKeyColumnOwner, SortParameter.ASCENDING));
They sorts work fine individually.
Is this expected? Is addSorting really a setSorting - where only 1 sort can be specified or am I missing a way to combine 2 sorts?
The addSorting method works just fine. However, it simply does not work for CustomMeta columns!!! There is already a confirmed defect regarding this subject with the following summary: "SortParameter does not work with two metadata fields". This is still an open defect for 2011SP1 and is scheduled to be fixed only for the next release.
Cheers,
Daniel.

How do I use states in jmock?

I'm writing an integration test that simulates a sequence of actions coming from the front end. I'm setting up my expectations like this:
context.checking(new Expectations() {{
States state = states("service");
allowing(service).getPendingTxn();
will(returnValue(null));
when(state.isNot("has-pending-txn"));
one(service).createPendingTxn();
will(returnValue(txnId));
then(state.is("has-pending-txn"));
allowing(service).getPendingTxn();
will(returnValue(transaction));
when(state.is("has-pending-txn"));
}});
The code under test then makes the calls in that order.
This isn't working for me. It looks like service.getPendingTxn() is returning a jMock null object, rather than the supplied values. I think I'm doing something wrong when I write both will(...) and when(...) after an expectation, but I'm not sure.
Is there something I'm missing here?
Per Duncan's suggestion, the answer is that that's exactly how you use states. I had another problem in the test that I incorrectly attributed to being related to states.

BidSystem, online auction, problem with timing

guys!
I'm developing an online auction with time limit.
The ending time period is only for one opened auction.
After logging into the site I show the time left for the open auction. The time is calculated in this way:
EndDateTime = Date and Time of end of auction;
DateTime.Now() = current Date and Time
timeLeft= (EndDateTime - DateTime.Now()).Seconds().
In javascript, I update the time left by:
timeLeft=timeLeft-1
The problem is that when I login from different browsers at the same time the browsers show a different count down.
Help me, please!
I guess there will always be differences of a few seconds because of the server processing time and the time needed to download the page.
The best way would be to actually send the end time to the browser and calculate the time remaining in javascript. That way the times should be the same (on the same machine of course).
Roman,
I had a little look at eBay (they know a thing or two about this stuff :)) and noticed that once the item is inside the last 90 seconds, a GET request gets fired every 2 seconds to update the variables in the javascript via a json response. you can look at this inside firebug/fiddler to see what it does.
here is an example of the json it pulls down:
{
"ViewItemLiteResponse":{
"Item":[
{
"IsRefreshPage":false,
"ViewerItemRelation":"NONE",
"EndDate":{
"Time":"12:38:48 BST",
"Date":"01 Oct, 2010"
},
"LastModifiedDate":1285932821000,
"CurrentPrice":{
"CleanAmount":"23.00",
"Amount":23,
"MoneyStandard":"£23.00",
"CurrencyCode":"GBP"
},
"IsEnded":false,
"AccessedDate":1285933031000,
"BidCount":4,
"MinimumToBid":{
"CleanAmount":"24.00",
"Amount":24,
"MoneyStandard":"£24.00",
"CurrencyCode":"GBP"
},
"TimeLeft":{
"SecondsLeft":37,
"MinutesLeft":1,
"HoursLeft":0,
"DaysLeft":0
},
"Id":160485015499,
"IsFinalized":false,
"ViewerItemRelationId":0,
"IsAutoRefreshEnabled":true
}
]
}
}
You could do something similar inside your code.
[edit] - on further looking at the eBay code, altho it only runs the intensive GET requests in the last 90 seconds, the same json as above is added when the page is initially loaded as well. Then, at 3 mins or so, the GET request is run every 10 seconds. therefore i assume the same javascript is run against that structure whether it be >90 seconds or not.
This may be a problem with javascript loading at different speeds,
or the setInterval will trigger at slightly different times depending on the loop
i would look into those two

Resources