The errors of neo4j-manual-milestone.pdf - neo4j

These codes are in neo4j-manual-milestone.pdf( version: 1.8M05):
TraversalDescription t = new TraversalDescription();
t.setOrder( TraversalDescription.DEPTH_FIRST );
t.setUniqueness( TraversalDescription.NODE );
t.setMaxDepth( 10 );
t.setReturnFilter( TraversalDescription.ALL );
t.setRelationships( new Relationship( "singer", Relationship.OUT ) );
// END SNIPPET: traversalDesc
// START SNIPPET: traverse
URI traverserUri = new URI( startNode.toString() + "/traverse/node" );
WebResource resource = Client.create()
.resource( traverserUri );
String jsonTraverserPayload = t.toJson();
ClientResponse response = resource.accept( MediaType.APPLICATION_JSON )
.type( MediaType.APPLICATION_JSON )
.entity( jsonTraverserPayload )
.post( ClientResponse.class );
System.out.println( String.format(
"POST [%s] to [%s], status code [%d], returned data: "
+ System.getProperty( "line.separator" ) + "%s",
jsonTraverserPayload, traverserUri, response.getStatus(),
response.getEntity( String.class ) ) );
response.close();
When I use them, the errors display.

If you go to the online version of the manual, at http://docs.neo4j.org/chunked/1.8.M05/tutorial-traversal-java-api.html at the bottom of the page there is a link to the full source, which is executed and tested together with the main neo4j build.
HTH

Related

Verifying user is authenticated using AWS IOS SDK

I created a lamdba function which does the following:
var param =
{
IdentityPoolId: "us-east-1:the-full-identity-id",
Logins: {} // To have provider name in a variable
};
param.Logins["com.test.website.login"] = userIdICreatedAndStoredInDynamoDB;
cognitoidentity.getOpenIdTokenForDeveloperIdentity(param,
function(err, data)
{
if (err) return fn(err); // an error occurred
else fn(null, data.IdentityId, data.Token); // successful response
});
It returns the identityId and token for that user. Everything is setup with IAM roles and AWS Cognito Identity and appears to be authenticating in the console.
I have two questions:
How do I test in the app that the user is authenticated? I save the identityId and token in the app device.
How long does the authentication last? I want the user to remain logged in. This is how most apps I use work and stays logged in until they hit logout.
Thanks.
To answer the first question:
How do I test in the app that the user is authenticated? I save the identityId and token in the app device.
You test the authentication by making a "Custom Authorizer"
The AWS example function you can find in the Lambda Example Functions when you go to make a new function
(if you filter to NodeJS 4.3 functions, it's towards the back)
Or you can take a look at THIS which is the same thing, just on GitHub instead.
I made a sorta modified version here:
"use strict";
const
codes = {
100: "Continue", 101: "Switching Protocols", 102: "Processing",
200: "OK", 201: "Created", 202: "Accepted", 203: "Non-Authoritative Information", 204: "No Content", 205: "Reset Content", 206: "Partial Content", 207: "Multi-Status", 208: "Already Reported", 226: "IM Used",
300: "Multiple Choices", 301: "Moved Permanently", 302: "Found", 303: "See Other", 304: "Not Modified", 305: "Use Proxy", 307: "Temporary Redirect", 308: "Permanent Redirect",
400: "Bad Request", 401: "Unauthorized", 402: "Payment Required", 403: "Forbidden", 404: "Not Found", 405: "Method Not Allowed", 406: "Not Acceptable", 407: "Proxy Authentication Required", 408: "Request Timeout", 409: "Conflict", 410: "Gone", 411: "Length Required", 412: "Precondition Failed", 413: "Payload Too Large", 414: "URI Too Long",
415: "Unsupported Media Type", 416: "Range Not Satisfiable", 417: "Expectation Failed", 418: "I'm a teapot", 421: "Misdirected Request", 422: "Unprocessable Entity", 423: "Locked", 424: "Failed Dependency", 425: "Unordered Collection", 426: "Upgrade Required", 428: "Precondition Required", 429: "Too Many Requests", 431: "Request Header Fields Too Large", 451: "Unavailable For Legal Reasons",
500: "Internal Server Error", 501: "Not Implemented", 502: "Bad Gateway", 503: "Service Unavailable", 504: "Gateway Timeout", 505: "HTTP Version Not Supported", 506: "Variant Also Negotiates", 507: "Insufficient Storage", 508: "Loop Detected", 509: "Bandwidth Limit Exceeded", 510: "Not Extended", 511: "Network Authentication Required"
},
resp = ( statusCode, data ) => ( { statusCode, message: codes[ statusCode ], data } ),
AWS = require( "aws-sdk" ),
crypto = require( "crypto" ),
COG = new AWS.CognitoIdentity(),
token = {
algorithm: "aes-256-ctr",
encrypt: item => {
item = JSON.stringify( item );
let cipher = crypto.createCipher( token.algorithm, process.env.PoolId ),
crypted = cipher.update( item, 'utf8', 'base64' );
crypted += cipher.final( 'base64' );
return crypted;
},
decrypt: item => {
let decipher = crypto.createDecipher( token.algorithm, process.env.PoolId ),
dec = decipher.update( item, 'base64', 'utf8' );
dec += decipher.final( 'utf8' );
return dec;
}
};
function AuthPolicy( principal, awsAccountId, apiOptions ) {
this.awsAccountId = awsAccountId;
this.principalId = principal;
this.version = '2012-10-17';
this.pathRegex = new RegExp( '^[/.a-zA-Z0-9-\*]+$' );
this.allowMethods = [];
this.denyMethods = [];
if( !apiOptions || !apiOptions.restApiId ) this.restApiId = '*';
else this.restApiId = apiOptions.restApiId;
if( !apiOptions || !apiOptions.region ) this.region = '*';
else this.region = apiOptions.region;
if( !apiOptions || !apiOptions.stage ) this.stage = '*';
else this.stage = apiOptions.stage;
}
AuthPolicy.HttpVerb = {
GET: 'GET',
POST: 'POST',
PUT: 'PUT',
PATCH: 'PATCH',
HEAD: 'HEAD',
DELETE: 'DELETE',
OPTIONS: 'OPTIONS',
ALL: '*',
};
AuthPolicy.prototype = ( function AuthPolicyClass() {
function addMethod( effect, verb, resource, conditions ) {
if( verb !== '*' && !Object.prototype.hasOwnProperty.call( AuthPolicy.HttpVerb, verb ) ) {
throw new Error( `Invalid HTTP verb ${verb}. Allowed verbs in AuthPolicy.HttpVerb` );
}
if( !this.pathRegex.test( resource ) )
throw new Error( `Invalid resource path: ${resource}. Path should match ${this.pathRegex}` );
let cleanedResource = resource;
if( resource.substring( 0, 1 ) === '/' )
cleanedResource = resource.substring( 1, resource.length );
const resourceArn = `arn:aws:execute-api:${this.region}:${this.awsAccountId}:${this.restApiId}/${this.stage}/${verb}/${cleanedResource}`;
if( effect.toLowerCase() === 'allow' )
this.allowMethods.push( {
resourceArn,
conditions,
} );
else if( effect.toLowerCase() === 'deny' )
this.denyMethods.push( {
resourceArn,
conditions,
} );
}
function getEmptyStatement( effect ) {
const statement = {};
statement.Action = 'execute-api:Invoke';
statement.Effect = effect.substring( 0, 1 ).toUpperCase() + effect.substring( 1, effect.length ).toLowerCase();
statement.Resource = [];
return statement;
}
function getStatementsForEffect( effect, methods ) {
const statements = [];
if( methods.length > 0 ) {
const statement = getEmptyStatement( effect );
for( let i = 0; i < methods.length; i++ ) {
const curMethod = methods[ i ];
if( curMethod.conditions === null || curMethod.conditions.length === 0 )
statement.Resource.push( curMethod.resourceArn );
else {
const conditionalStatement = getEmptyStatement( effect );
conditionalStatement.Resource.push( curMethod.resourceArn );
conditionalStatement.Condition = curMethod.conditions;
statements.push( conditionalStatement );
}
}
if( statement.Resource !== null && statement.Resource.length > 0 )
statements.push( statement );
}
return statements;
}
return {
constructor: AuthPolicy,
allowAllMethods() {
addMethod.call( this, 'allow', '*', '*', null );
},
denyAllMethods() {
addMethod.call( this, 'deny', '*', '*', null );
},
allowMethod( verb, resource ) {
addMethod.call( this, 'allow', verb, resource, null );
},
denyMethod( verb, resource ) {
addMethod.call( this, 'deny', verb, resource, null );
},
allowMethodWithConditions( verb, resource, conditions ) {
addMethod.call( this, 'allow', verb, resource, conditions );
},
denyMethodWithConditions( verb, resource, conditions ) {
addMethod.call( this, 'deny', verb, resource, conditions );
},
build() {
if( ( !this.allowMethods || this.allowMethods.length === 0 ) &&
( !this.denyMethods || this.denyMethods.length === 0 ) )
throw new Error( 'No statements defined for the policy' );
const policy = {}, doc = {};
policy.principalId = this.principalId;
doc.Version = this.version;
doc.Statement = [];
doc.Statement = doc.Statement.concat( getStatementsForEffect.call( this, 'Allow', this.allowMethods ) );
doc.Statement = doc.Statement.concat( getStatementsForEffect.call( this, 'Deny', this.denyMethods ) );
policy.policyDocument = doc;
return policy;
},
};
} () );
exports.handler = ( event, context, cb ) => {
const
principalId = process.env.principalId,
tmp = event.methodArn.split( ':' ),
apiGatewayArnTmp = tmp[ 5 ].split( '/' ),
awsAccountId = tmp[ 4 ],
apiOptions = {
region: tmp[ 3 ],
restApiId: apiGatewayArnTmp[ 0 ],
stage: apiGatewayArnTmp[ 1 ]
},
policy = new AuthPolicy( principalId, awsAccountId, apiOptions );
let response;
if( !event.authorizationToken || typeof event.authorizationToken !== "string" )
response = resp( 401 );
let item = token.decrypt( event.authorizationToken );
try { item = resp( 100, JSON.parse( item ) ); }
catch( e ) { item = resp( 401 ); }
if( item.statusCode !== 100 )
response = resp( 401 );
else if( item.data.Expiration <= new Date().getTime() )
response = resp( 407 );
else
response = resp( 100 );
if( response.statusCode >= 400 ) {
policy.denyAllMethods();
const authResponse = policy.build();
authResponse.context = response;
cb( null, authResponse );
} else {
COG.getCredentialsForIdentity( {
IdentityId: item.data.IdentityId,
Logins: {
'cognito-identity.amazonaws.com': item.data.Token
}
}, ( e, d ) => {
if( e ) {
policy.denyAllMethods();
response = resp( 401 );
} else {
policy.allowMethod( AuthPolicy.HttpVerb.GET, "/user" );
policy.allowMethod( AuthPolicy.HttpVerb.DELETE, "/user" );
response = resp( 202 );
}
const authResponse = policy.build();
authResponse.context = response;
cb( null, authResponse );
} );
}
};
Above is the full example... But let me break this down and explain why the one they provide is not as helpful.
Here are the steps to setting this up so you can see why it has to be something like this.
Go to Lambda and make a function called Auth_isValid or something like that
Put your PoolId and principalId into the Environment Variables so it's easy to change later
Head over to API Gateway and lets link this up
Under API Options on the left side, hit Authorizers
Click Create -> Custom Authorizer
Fill in your Lambda Region, function name (should auto-fill), Authorizer name, Identity Token Source (keep it simple with method.request.header.Authorization for now, and TTL can be 300. Lets not mess with Execution role or token validation expression yet.
Save/Update it and head back to Lambda - we'll hook up a function with this authorizer later.
Ok so when you look at my function, you'll see that I do this weird encrypt/decrypt thing at the very top:
token = {
algorithm: "aes-256-ctr",
encrypt: item => {
item = JSON.stringify( item );
let cipher = crypto.createCipher( token.algorithm, process.env.PoolId ),
crypted = cipher.update( item, 'utf8', 'base64' );
crypted += cipher.final( 'base64' );
return crypted;
},
decrypt: item => {
let decipher = crypto.createDecipher( token.algorithm, process.env.PoolId ),
dec = decipher.update( item, 'base64', 'utf8' );
dec += decipher.final( 'utf8' );
return dec;
}
};
Basically, I wrap some items I want inside an encrypted key simple so I can pass all my information around easy-peasy.
(I pass in the Identity Pool as a hash to make it cool and simple and as long as you never send the Identity Pool ID to the front end, we're good!)
The Custom Authorizer requires one single token, not a JSON block of what you'll say is a "token" or something (which you could do but it looks dumb)
So we have one unified token that gets passed in and I call the decrypt function for this to unwrap (I'll show the encrypt example in a second.
Now some people may say "oh well that's not actually encryption it could easily be figured out" - my answer to this is: "ya well it would have been unencrypted, raw text anyway, why not make it easy."
Ok now that you see that part, head down to the bottom of the function.
let response;
if( !event.authorizationToken || typeof event.authorizationToken !== "string" )
response = resp( 401 );
let item = token.decrypt( event.authorizationToken );
try { item = resp( 100, JSON.parse( item ) ); }
catch( e ) { item = resp( 401 ); }
if( item.statusCode !== 100 )
response = resp( 401 );
else if( item.data.Expiration <= new Date().getTime() )
response = resp( 407 );
else
response = resp( 100 );
if( response.statusCode >= 400 ) {
policy.denyAllMethods();
const authResponse = policy.build();
authResponse.context = response;
cb( null, authResponse );
} else {
COG.getCredentialsForIdentity( {
IdentityId: item.data.IdentityId,
Logins: {
'cognito-identity.amazonaws.com': item.data.Token
}
}, ( e, d ) => {
if( e ) {
policy.denyAllMethods();
response = resp( 401 );
} else {
policy.allowMethod( AuthPolicy.HttpVerb.GET, "/user" );
policy.allowMethod( AuthPolicy.HttpVerb.DELETE, "/user" );
response = resp( 202 );
}
const authResponse = policy.build();
authResponse.context = response;
cb( null, authResponse );
} );
}
Update:
Our incoming data from API Gateway is:
{
"type":"TOKEN",
"authorizationToken":"<session_token>",
"methodArn":"arn:aws:execute-api:<region>:<Account_ID>:<API_ID>/<Stage>/<Method>/<Resource_Path>"
}
Our outgoing data from Lambda should be something like:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "execute-api:Invoke",
"Effect": "Deny",
"Resource": [
"arn:aws:execute-api:<region>:<Account_ID>:<API_ID>/<Stage>/*/*"
]
}
]
}
Depending on how our authorization goes.
So in my first if check, I make sure the authorizationToken is there and that it's a string, if it's not, we say it's Unauthorized (everyone should know and use their status codes)
Second, I decrypt the token and make sure that went well with a try-catch attempt. If it didn't go well, they're Unauthorized. if it did, we can Continue.
You'll see in the token, I put a variable Expiration, this is how I check if the key was once accepted and correct and is simply expired now. For this, I say Proxy Authentication Required. Which tells my front end, go call login again and give me new creds. Don't forget, the purpose of this function has to be only to check IF we're authorized. Not to do fancy things like refresh tokens.
Next, I check if everything is good and call denyAllMethods and put the response code in the context of the response. API Gateway is very picky and only wants simply IAM formatted policies passed around - no other information or format or whatever may be in there if it's not specified HERE or HERE
If everything is OK, I call getCredentialsForIdentity - using the IdentityId and Token, make sure that token is, in fact valid as well, and then I allow the functions needed at the time. These are very important and will validate the token to only those functions - in other words. If your IAM role in IAM says it can access everything, this will say no, you can only access GET on /user and DELETE on /user. So don't let it fool you. This is a custom authorizer after all.
Next, I need to show you how I put all this in from the Login part. I have the same token = { part but in my login function I added a getToken function:
token.getToken = obj => {
return new Promise( ( res, rej ) => {
COG.getOpenIdTokenForDeveloperIdentity( {
IdentityPoolId: process.env.PoolId,
Logins: {
"com.whatever.developerIdthing": obj.email
},
TokenDuration: duration
}, ( e, r ) => {
r.Expiration = new Date().getTime() + ( duration * 1000 );
if( e ) rej( e );
else res( token.encrypt( r ) );
} );
} );
};
Notice above, the:
duration
Part.
This is the answer to your second question:
How long does the authentication last? I want the user to remain logged in. This is how most apps I use work and stays logged in until they hit logout.
You create an OpenIdToken using their email or whatever you want to identify them and TokenDuration is in seconds. I would recommend making this a week or two but if you wanted a year long or something, 31536000 would be it. Another way of doing this is to make a function that only gives you authorized credentials, and instead of calling denyAll in the authorizer when a 407 scenario comes up, make the only method they can call allowMethod( POST, /updateCreds ); or something like that. This way you can refresh their stuff every once in a while.
The pseudo for that is:
Remove:
if( response.statusCode >= 400 )
else
And do:
if( statusCode >= 400 )
denyAll
else if( statusCode === 407 )
allow refresh function
else
allow everything else
Hope this helps!
To test if they're logged in you need to set up a service that'll check the token against Cognito. Quick and dirty way is to set up a basic lambda, expose it through API Gateway with an authorizer pointed at your User Identity Pool. All the lambda needs to do is return HTTP 200, since what you're really checking is the authorizer. Then have your app get/post/etc to that API URL w/ a header of "Authorization":$ACCESS_TOKEN. either it'll kick back a 200 on success or it'll return an Unauthorized message.
Your Cognito token is only good for an hour, but you can refresh the token to keep a person logged in. When your user authenticated they got three tokens: ID, Access, and Refresh token. You can use the latter to request a new access token.
It is documented at : http://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html

Drools mode stream and containers

HI this is my code.
public static KieContainer createKieContainerForProject() {
KieServices ks = KieServices.Factory.get();
// Create a module model
KieModuleModel kieModuleModel = ks.newKieModuleModel();
// Base Model from the module model
KieBaseModel kieBaseModel = kieModuleModel.newKieBaseModel( "KBase" )
.setDefault( true )
.setEqualsBehavior( EqualityBehaviorOption.EQUALITY)
.setEventProcessingMode( EventProcessingOption.STREAM );
// Create session model for the Base Model
KieSessionModel ksessionModel = kieBaseModel.newKieSessionModel( "KSession" )
.setDefault( true )
.setType( KieSessionModel.KieSessionType.STATEFUL )
.setClockType( ClockTypeOption.get("realtime") );
// Create File System services
KieFileSystem kFileSystem = ks.newKieFileSystem();
File file = new File("src/main/resources/rules/Sample.drl");
Resource resource = ks.getResources().newFileSystemResource(file).setResourceType(ResourceType.DRL);
kFileSystem.write( resource );
KieBuilder kbuilder = ks.newKieBuilder( kFileSystem );
// kieModule is automatically deployed to KieRepository if successfully built.
kbuilder.buildAll();
if (kbuilder.getResults().hasMessages(org.kie.api.builder.Message.Level.ERROR)) {
throw new RuntimeException("Build time Errors: " + kbuilder.getResults().toString());
}
KieContainer kContainer = ks.newKieContainer(ks.getRepository().getDefaultReleaseId());
return kContainer;
}
}
it's dont work when I call the fucntion, and my rules no work too.
my rule is
rule "Sound the alarm in case temperature rises above threshold"
when
TemperatureThreshold( $max : max )
Number( doubleValue > $max ) from accumulate(
SensorReading( $temp : temperature ) over window:time( 10m ),
average( $temp ) )
then
// sound the alarm
end
when I run the program, He says it has error, mode not stream and the code dont work.
how do I put a program in stream mode?
REduce your code, and add -KieBase and KieSession creation:
KieServices ks = KieServices.Factory.get();
KieFileSystem kFileSystem = ks.newKieFileSystem();
FileInputStream fis = new FileInputStream( "...drl" );
kFileSystem.write("src/main/resources/somename.drl",
ks.getResources().newInputStreamResource( fis ) ); //XXX
KieBuilder kbuilder = ks.newKieBuilder( kFileSystem );
kbuilder.buildAll();
if (kbuilder.getResults().hasMessages(org.kie.api.builder.Message.Level.ERROR)) {
throw new RuntimeException("Build time Errors: " + kbuilder.getResults().toString());
}
KieContainer kContainer = ks.newKieContainer(ks.getRepository().getDefaultReleaseId());
KieBaseConfiguration config = ks.newKieBaseConfiguration();
config.setOption(EventProcessingOption.STREAM);
KieBase kieBase = kContainer.newKieBase( config );
KieSession kieSession = kieBase.newKieSession();
This should give you a session that's capable of running your rule. (
According to the docs, it's as follows:
KieBaseConfiguration config = KieServices.Factory.get().newKieBaseConfiguration();
config.setOption( EventProcessingOption.STREAM );
But it's probably worth taking a look at this Drools test for a working example.

Jquery mobile, How to use changePage to update changeHash and Parameters

options.dataUrl = urlObj.href;
$.mobile.changePage( $page, options );
dataUrl contains the complete url with parameters
http://example.com/#sales?p=page
but the above code only updates the url with hash only, after the new page loads... the url changes to
http://example.com/#sales
and does not apply ?p=page.
Here is the complete function, check the last few lines....
function getSPList( urlObj, options ){
var pageName = urlObj.hash.replace( /.*p=/, "" ),
pageSelector = urlObj.hash.replace( /\?.*$/, "" );
$.ajax({
url:"getSPList.php",
dataType: 'json',
data: {p: pageName},
success:function(result){
if ( result ) {
var $page = $( pageSelector ),
$header = $page.children( ":jqmData(role=header)" ),
$content = $page.children( ":jqmData(role=content)" ),
markup = "<ul data-role='listview' data-filter='true' data-filter-placeholder='Search Salesperson...'>";
for ( var i = 0; i < result.sp.length; i++ ) {
markup += "<li><a href='#addClient?p="+ result.sp[i].id +"' data-transition='slide'>" + result.sp[i].name + "</a></li>";
}
markup += "</ul>";
$content.html( markup );
$page.page();
$content.find( ":jqmData(role=listview)" ).listview();
options.dataUrl = urlObj.href;
options.changeHash = true;
$.mobile.changePage( $page, options );
}
}
});
return
}
I have experienced the same problem and here is what I've found as of version 1.3.2:
Inside $.mobile.changePage(toPage, options) options.dataUrl is passed through path.convertUrlToDataUrl() before being stored and used.
Inside path.convertUrlToDataUrl() everything before and including the '#' as well as everything after and including the '?' is stripped.
Further down inside of $.mobile.changePage() before the url is passed to $.mobile.navigate() I see this:
// rebuilding the hash here since we loose it earlier on
// TODO preserve the originally passed in path
if( !path.isPath( url ) && url.indexOf( "#" ) < 0 ) {
url = "#" + url;
}
So it seems to be a bug in jQm. For my app I'm adding this inside the bottom of the previously mentioned if statement:
var query_index = (settings.dataUrl || '').indexOf('?');
if (query_index > -1) {
url += settings.dataUrl.substring(query_index);
}
This solves the initial problem but I'm unsure about potential negative side effects or if there is a better workaround out there.

Tabris 0.11 iOS EXC_BAD_ACCESS Geolocation

First of all: Thanks that I got such a good and fast feedback from you guys a few days ago.
I'm still playing around in Tabris 0.11 and tried to implement a Geolocation like you guys did in the demo project.
Everything is working great on Android, but under iOS (IPhone 5) I get the error
EXC_BAD_ACCESS (code=1, address=0xbbadbeef)
Here is how my code looks like
public void create( Composite parent, UIContext context ) {
// creation of the layout types
createLayouts();
parent.setLayout( GridLayoutFactory.fillDefaults().margins( 0, 0 ).spacing( 0, 0 ).create() );
createContainer( parent );
createBrowser();
}
private void createLayouts() {
layoutGrid = new GridLayout();
layoutGrid.numColumns = 1;
layoutGridData = new GridData();
layoutGridData.horizontalAlignment = GridData.FILL;
}
private void createContainer( Composite parent ) {
[...]
containerBrowser = new Composite( parent, SWT.NONE );
containerBrowser.setLayout( layoutGrid );
containerBrowser.setLayoutData( new GridData( SWT.FILL, SWT.FILL, true, true ) );
[...]
}
private void createBrowser() {
browser = new Browser( containerBrowser, SWT.NONE );
browser.setLayoutData( new GridData( SWT.FILL, SWT.FILL, true, true ) );
lastLat = 48.775418;
lastLon = 9.181759;
setBrowserUrl( lastLat, lastLon);
}
private void setBrowserUrl( double lat, double lon) {
StringBuilder builder = new StringBuilder();
builder.append( "http://open.mapquestapi.com/staticmap/v4/getmap" );
builder.append( "?size=" + 200 + "," + 200 );
builder.append( "&zoom=16" );
lastLat = lat;
lastLon = lon;
builder.append( "&center=" + lat + "," + lon );
builder.append( "&imageType=png" );
if( lastLabel != null ) {
builder.append( "&pois=" + lastLabel + "," + lat + "," + lon + ",0,0" );
}
browser.setUrl( builder.toString() );
}
I'm not really experienced in iOS, I hope this information helps you guys.
Thanks in advance, Toby
With the example you've provided, I could not reproduce the problem. Maybe what you are seeing is an issue in the pre-release Tabris 0.11 client. The issue might be already fixed in the final Tabris 1.0 release.
I suggest you download Tabris 1.0 ( http://developer.eclipsesource.com/tabris/downloads/ ) and try again.
If you still have a problem, send my your "Device Log" of the crashed App using the "Xcode Organizer".

How can I set and read session data in RingoJS?

Good day,
I have recently started playing with RingoJS along with Stick middleware and I am now stuck with sessions. I can't make it work.
main.js
var {Application} = require( "./_lib_/stick" ),
app = exports.app = Application();
app.configure( "mount" );
app.mount( "/", require( "./actions" ) );
if ( require.main === module ) {
require( "ringo/httpserver" ).main( module.directory );
}
actions.js
var {Application, helpers} = require( "./_lib_/stick" ),
Response = require( "ringo/jsgi/response" );
export( "app" );
var app = Application();
app.configure( "route", "render", "session" );
app.render.base = module.resolve( "templates" );
app.render.master = "page.html";
app.get("/session.htm", function( request ) {
//request.session.data.foo = "bar";
request.session.data.put("foo", "bar");
return Response.redirect( "session2.htm" );
});
app.get("/session2.htm", function( request ) {
var value = request.session;
return Response.html( "Session: " + value );
});
I've tested many combinaison but none of them worked as espected.
Most errors I get is about reading the data from the session. For example:
TypeError: Cannot read property "data" from undefined
Any tips?
"session" needs to come before "mount" in app.configure.
On the fourth line of main.js:
app.configure( "session", "mount" );
Then, remove "session" from the later call to app.configure since there's no point in running the middleware twice.

Resources