I have this block of actionscript code which is executed when a login is appempted. I an trying to reload a set of roles for a the user. I've added a result handler to the hasRole() method
[Observer("loginAttempted")]
public function loginAttempted():void {
identity.isLoggedIn(isLoggedInResult);
trace(identity.loggedIn+" "+identity.username);
var perms:Array = Permission.constants;
var i:int
trace("Load permissions");
for(i=0;i<perms.length;i++)
{
var p:Permission = perms[i];
var res = identity.hasRole(p.name,permissionResult);
if(res == true)
{
p.allowed = res;
}
trace(i+" "+p.name +" "+p.allowed+" "+res);
}
}
private function permissionResult(event:TideResultEvent):void {
trace("permissionResult "+event.result);
}
but i keep getting this error. Based on the graniteds docs the function should only take a single argument.
[Fault] exception, information=ArgumentError: Error #1063:
Argument count mismatch on Main/permissionResult(). Expected 1, got 2.
at TideRoleResponder/result()[C:\workspace\graniteds\as3\framework\org\granite\tide\ejb\Identity.as:201]
at org.granite.tide::Tide/result()[C:\workspace\graniteds\as3\framework\org\granite\tide\Tide.as:1831]
at org.granite.tide.rpc::ComponentResponder/result()[C:\workspace\graniteds\as3\framework\org\granite\tide\rpc\ComponentResponder.as:65]
at mx.rpc::AsyncToken/http://www.adobe.com/2006/flex/mx/internal::applyResult()[C:\autobuild\3.5.0\frameworks\projects\rpc\src\mx\rpc\AsyncToken.as:199]
at mx.rpc.events::ResultEvent/http://www.adobe.com/2006/flex/mx/internal::callTokenResponders()[C:\autobuild\3.5.0\frameworks\projects\rpc\src\mx\rpc\events\ResultEvent.as:172]
at mx.rpc::AbstractOperation/http://www.adobe.com/2006/flex/mx/internal::dispatchRpcEvent()[C:\autobuild\3.5.0\frameworks\projects\rpc\src\mx\rpc\AbstractOperation.as:199]
at org.granite.tide.rpc::TideOperation/http://www.adobe.com/2006/flex/mx/internal::dispatchRpcEvent()[C:\workspace\graniteds\as3\framework\org\granite\tide\rpc\TideOperation.as:73]
at mx.rpc::AbstractInvoker/http://www.adobe.com/2006/flex/mx/internal::resultHandler()[C:\autobuild\3.5.0\frameworks\projects\rpc\src\mx\rpc\AbstractInvoker.as:263]
at mx.rpc::Responder/result()[C:\autobuild\3.5.0\frameworks\projects\rpc\src\mx\rpc\Responder.as:46]
at mx.rpc::AsyncRequest/acknowledge()[C:\autobuild\3.5.0\frameworks\projects\rpc\src\mx\rpc\AsyncRequest.as:74]
at NetConnectionMessageResponder/resultHandler()[C:\autobuild\3.5.0\frameworks\projects\rpc\src\mx\messaging\channels\NetConnectionChannel.as:524]
at mx.messaging::MessageResponder/result()[C:\autobuild\3.5.0\frameworks\projects\rpc\src\mx\messaging\MessageResponder.as:199]
We are using the ifAnyGranted function on the identity to do something similar, and our result handler has 2 arguments: the TideResultEvent, and a String containing the role. Try changing the signature of the permissionResult function to:
private function permissionResult(event:TideResultEvent, role:String):void
Related
Based on https://www.plivo.com/blog/Send-templatized-SMS-from-a-Google-spreadsheet-using-Plivo-SMS-API/ I have the following code:
data = {
"SOURCE" : "+1234567890",
"DESTINATION" : "+2345678901",
"FIRST_NAME" : "Jane",
"LAST_NAME" : "Doe",
"COUPON" : "DUMMY20",
"STORE" : "PLIVO",
"DISCOUNT" : "20",
}
template_data = "Hi FIRST_NAME , your coupon code for discount of % purchase at is "
function createMessage(data,template_data){
Logger.log(data);
for (var key in data) {
Logger.log(key);
if (data.hasOwnProperty(key)) {
template_data = template_data.replace(new RegExp('+key+', 'gi'), data[key]);
}
}
Logger.log(template_data);
return template_data;
}
When I run createMessage and check the logs I see:
[18-10-02 13:19:03:139 EDT] undefined
[18-10-02 13:19:03:139 EDT] undefined
This suggests to me that the parameters are not being passed into the function. What am I doing wrong?
Running a function in the Script Editor does not pass arguments to the function. Currently, you have 3 user objects in your project's global namespace (among others from Google):
createMessage (a function object)
template_data (a string)
data (an object).
The line function createMessage(data, template_data) declares the object createMessage to be a function object, and indicates that the first two arguments passed to the function are known within the function's scope as data and template_data, respectively. These function-scope argument declarations shadow any more-distant declarations (i.e. from global scope or an enclosing function scope).
The solution is then to either write a "driver function" that you actually execute, in which you define the input parameters to your called functions, or to remove the parameters from the function call:
var data = {...}; // global var
var template_data = {...}; // global var
function driver() {
createMessage(data, template_data); // uses the globally scoped `data` & `template_data` objects
var otherdata = 1,
otherTemplate = 2;
createMessage(otherdata, otherTemplate); // uses the function-scoped `otherdata` and `template_data` objects
}
function createMessage(someData, someTemplate) {
Logger.log(someData);
Logger.log(arguments[0]); // equivalent to the above line.
// ...
}
Avoiding reference shadowing:
function createMessage() { // removed `arguments` reference binding
Logger.log(data); // accesses global-scope `data` object because there is no `data` reference in the nearest scope
To help with this scenario - preventing manual execution via the Script editor of functions needing parameters - I will generally make the functions private by adding a trailing _ to the name: function cantBeRunManually_(arg1, arg2, arg3) { ... }
References:
Arguments
Private Functions
Name conflicts / shadowing
I am building a bot in Gupshup with Api.ai integration. I have an agent in Api.ai with several intents and each of them linked through contexts(input & output contexts). When I use the following code to call Api.ai, the first intent is called and I get the reply. However when the second message is given, the bot takes it as a completely new message, without identifying its relation with first.
How can I solve this issue? Kindly help
function MessageHandler(context, event) {
// var nlpToken = "xxxxxxxxxxxxxxxxxxxxxxx";//Your API.ai token
// context.sendResponse(JSON.stringify(event));
sendMessageToApiAi({
message : event.message,
sessionId : new Date().getTime() +'api',
nlpToken : "3626fe2d46b64cf8a9c0d3bee99a9sb3",
callback : function(res){
//Sample response from apiai here.
context.sendResponse(JSON.parse(res).result.fulfillment.speech);
}
},context)
}
function sendMessageToApiAi(options,botcontext) {
var message = options.message; // Mandatory
var sessionId = options.sessionId || ""; // optinal
var callback = options.callback;
if (!(callback && typeof callback == 'function')) {
return botcontext.sendResponse("ERROR : type of options.callback should be function and its Mandatory");
}
var nlpToken = options.nlpToken;
if (!nlpToken) {
if (!botcontext.simpledb.botleveldata.config || !botcontext.simpledb.botleveldata.config.nlpToken) {
return botcontext.sendResponse("ERROR : token not set. Please set Api.ai Token to options.nlpToken or context.simpledb.botleveldata.config.nlpToken");
} else {
nlpToken = botcontext.simpledb.botleveldata.config.nlpToken;
}
}
var query = '?v=20150910&query='+ encodeURIComponent(message) +'&sessionId='+sessionId+'&timezone=Asia/Calcutta&lang=en '
var apiurl = "https://api.api.ai/api/query"+query;
var headers = { "Authorization": "Bearer " + nlpToken};
botcontext.simplehttp.makeGet(apiurl, headers, function(context, event) {
if (event.getresp) {
callback(event.getresp);
} else {
callback({})
}
});
}
/** Functions declared below are required **/
function EventHandler(context, event) {
if (!context.simpledb.botleveldata.numinstance)
context.simpledb.botleveldata.numinstance = 0;
numinstances = parseInt(context.simpledb.botleveldata.numinstance) + 1;
context.simpledb.botleveldata.numinstance = numinstances;
context.sendResponse("Thanks for adding me. You are:" + numinstances);
}
function HttpResponseHandler(context, event) {
// if(event.geturl === "http://ip-api.com/json")
context.sendResponse(event.getresp);
}
function DbGetHandler(context, event) {
context.sendResponse("testdbput keyword was last get by:" + event.dbval);
}
function DbPutHandler(context, event) {
context.sendResponse("testdbput keyword was last put by:" + event.dbval);
}
The sessionId has to be fixed for a user. There are two ways you can do this in the Gupshup bot code -
Use the unique userID which is sent to the bot for every user.
To get this value you can use -
event.senderobj.channelid
But this value is dependent on how different messaging channels provides it and api.ai has a limit of 36 characters.
Sample code -
function MessageHandler(context, event) {
sendMessageToApiAi({
message : event.message,
sessionId : event.senderobj.channelid,
nlpToken : "3626fe2d46b64cf8a9c0d3bee99a9sb3",
callback : function(res){
//Sample response from apiai here.
context.sendResponse(JSON.parse(res).result.fulfillment.speech);
}
},context)
}
Generate a unique sessionId for each user and store it in the database to utilise it. In the below sample , I am storing the sessionId at roomleveldata which is the default persistance provided by Gupshup, to know more check this guide.
Sample code -
function MessageHandler(context, event) {
sendMessageToApiAi({
message : event.message,
sessionId : sessionId(context),
nlpToken : "84c813598fb34dc5b1f3e1c695e49811",
callback : function(res){
//Sample response from apiai here.
context.sendResponse(JSON.stringify(res));
}
},context)
}
function sessionId(context){
var userSession = context.simpledb.roomleveldata.sessionID;
if(!userSession){
userSession = new Date().getTime() +'api';
context.simpledb.roomleveldata.sessionID = userSession;
return userSession;
}else{
return userSession;
}
}
Remember that sessionId should not exceed 36 characters.
Suresh,
It seems you generate new session id for every request:
new Date().getTime() +'api'
But if you want to make contexts work it must be one fixed value for all requests belonging to one user. For example, you could use some global variable for it.
I currently have some code from here (https://github.com/jmhnilbog/Nilbog-Lib-AS2/blob/master/mx/mx/remoting/NetServiceProxy.as) which converts a function into a function. This code is shown below:
private var _allowRes:Boolean= false;
function __resolve( methodName:String ):Function {
if( _allowRes ) {
var f = function() :Object {
// did the user give a default client when he created this NetServiceProxy?
if (this.client != null) {
// Yes. Let's create a responder object.
arguments.unshift(new NetServiceProxyResponder(this, methodName));
}
else {
if (typeof(arguments[0].onResult) != "function") {
mx.remoting.NetServices.trace("NetServices", "warning", 3, "There is no defaultResponder, and no responder was given in call to " + methodName);
arguments.unshift(new NetServiceProxyResponder(this, methodName));
}
}
if(typeof(this.serviceName) == "function")
this.serviceName = this.servicename;
arguments.unshift(this.serviceName + "." + methodName);
return( this.nc.call.apply(this.nc, arguments));
};
return f;
}
else {
return null;
}
}
Basically what the code is designed to do is return a new function (returned as f) which performs the correct server operates. However, if I try and use this syntax in AS3, I get the following two errors:
Error: Syntax error: expecting semicolon before colon.
Error: Syntax error: else is unexpected.
How would I go about doing this? I know this is someone else's code, but I am trying to get the old AS1/2 mx.remoting functionality working in AS3. Cheers.
Hopefully you can see a bit from the code what I'm trying to do here, basically I need to check if a record exists in a database, so I call a function to do so, but I'm using the sqlrunner class wherein the result of a query is called as an event response and I don't know how to get that value out of the resulting function back to the parent.
I feel like I must be doing things backwards or something..
public function dbmatch(datetime:String, typecode:String):Boolean {
var q:String = "SELECT DateTime FROM Event WHERE DateTime='"+datetime+"' AND EventTypeCode='"+typecode+"'"
SQLService.getInstance().execute(q,null,matchresult);
function matchresult(result:SQLResult):Boolean{
var match:String = result.data[0];
if (match == null){return false} else {return true}
}
return matchresult();
}
elsewhere:
var recordexists:Boolean = dbmatch(datetime, "Gb");
if (!recordexists){...}
Basically the problem is that the SQLService class can't immediatly return a result for your query. That is why it uses a callback listener function (matchresult in your example) to inform your program at a later time that it has finished the search.
A basic way of handling this would be to call the query, then wait for the Query to "callback" to your listening funciton, that can then continue execution.
public function dbmatch(datetime:String, typecode:String, callbackListener:Function):void {
var q:String = "SELECT DateTime FROM Event WHERE DateTime='"+datetime+"' AND EventTypeCode='"+typecode+"'"
SQLService.getInstance().execute(q, null, callbackListener);
}
Elsewhere:
// Start the query, but can't react to it immediatly
dbmatch(datetime, "Gb", onSQLQueryResult);
// Your callback function
public function onSQLQueryResult(result:SQLResult):void {
var match:String = result.data[0];
if (match == null) {
// Do stuff you were going to do at (!recordexists)
}
}
Why do you think the code below does not work?
What would you change/add to make it work?
Any help is appreciated..
function TraceIt(message:String, num:int)
{
trace(message, num);
}
function aa(f:Function, ...args):void
{
bb(f, args);
}
aa(TraceIt, "test", 1);
var func:Function = null;
var argum:Array = null;
function bb(f:Function, ...args):void
{
func = f;
argum = args;
exec();
}
function exec()
{
func.apply(null, argum);
}
I get an ArgumentError (Error #1063):
Argument count mismatch on test_fla::MainTimeline/TraceIt(). Expected 2, got 1.
..so, the passed parameter (argum) fails to provide all passed arguments..
..Please keep the function structure (traffic) intact.. I need a solution using the same functions in the same order.. I have to pass the args to a variable and use them in the exec() method above..
regards
Ok, here is the solution.. after breaking my head : )
function TraceIt(message:String, num:int)
{
trace(message, num);
}
function aa(f:Function=null, ...args):void
{
var newArgs:Array = args as Array;
newArgs.unshift(f);
bb.apply(null, newArgs);
}
aa(TraceIt, "test", 1);
var func:Function = null;
var argum:*;
function bb(f:Function=null, ...args):void
{
func = f;
argum = args as Array;
exec();
}
function exec():void
{
if (func == null) { return; }
func.apply(this, argum);
}
This way, you can pass arguments as variables to a different function and execute them..
Thanks to everyone taking the time to help...
When TraceIt() eventually gets called, it's being called with 1 Array parameter, not a String and int parameters.
You could change TraceIt() to:
function TraceIt(args:Array)
{
trace(args[0], args[1]);
}
Or you could change exec() to:
function exec()
{
func.apply(null, argum[0].toString().split(","));
}
...as it appears when you pass "test", 1, you end up with array whose first value is "test,1". This solution doesn't work beyond the trivial case, though.
Change your bb function to look like this:
function bb(f:Function, args:Array):void
{
func = f;
argum = args;
exec();
}
As you have it now, it accepts a variable number of arguments, but you are passing in an array(of the arguments) from aa.