Please rate this module in the marketplace and spread the word if you find it useful :)
Click here to see version and release notes
[TOC]
Titanium Mobile Module for Parse.com iOS and Android APIs. Uses native iOS & Android API code from parse.com. Does not use their simple REST API. You have access to Objects, Queries, Users, Files, Push Notifications and anything else Parse can imagine.
Please go to www.parse.com and sign up for an account!
IMPORTANT: This module is unofficial and is not maintained by parse.com
If you need more information, please visit the Parse API iOS guide here: Parse API iOS Documentation or the Parse API Android Documentation
If you need more clarification on using the library, please look at the Parse iOS documentation and then find the function you're looking for here to use it in Javascript. This module follows the naming conventions of the iOS documentation.
The accompanying example included with the module ( located in the ./example
directory ) shows working code for all of the following examples. You just need to provide it with your own Parse API Application ID and Client Key and you should be able to test out every example for yourself. Also if you want to use the Facebook Functions on iOS, you must provide your Facebook API key as well. Just make sure you can see what the console is printing out because most messages are printed using Ti.API.info()
.
I would suggest using proper namespacing for your application. You can only use require("com.forge42.parseapi")
once inside your application or else you'll run into problems. I suggest doing this at the start of your program along with the parse init function. An example for namespacing would be to put your application variables in a global variable. Remember all variables declared outside of any function scope will be global and available to your entire application due to the way javascript works.
Example:
var myapp_globals = {};
myapp_globals.parseapi = require("com.forge42.parseapi");
myapp_globals.parseapi.parseInit( // init here );
///// then in another file whenever you need to use the parseapi variable you can do the following to access the parseapi object:
myapp_globals.parseapi.somefunctionhere() /// any function here.
Just make sure to use a unique name for myapp_globals
. That's how namespacing works. If you want some more information please see: http://developer.appcelerator.com/question/127559/are-titanium-modules-singletons-when-using-require and for javascript namespacing: http://javascriptweblog.wordpress.com/2010/12/07/namespacing-in-javascript/
Another way to namespace your application is using the CommonJS standard. You can read more about that in the namespacing links above.
To access this module from JavaScript, you would do the following:
var parseapi = require('com.forge42.parseapi');
parseapi.initParse( {
applicationId: "put your parse api APPLICATION ID here",
clientKey: "put your parse api CLIENT KEY here"
});
The parseapi variable is a reference to the Module object. From this variable you can create PFObject, PFQuery, PFUser and access other functions from the Parse API.
To save an object to the Parse API database, you need to create a PFObject using the parseapi.createPFObject()
function of the module. Once it's created you can initialize it with a class name. In this example we use the TestObject class. You can save all types of data by using the pfObject.setObject( data, key )
function from the PFObject you created. You can store the following types null, Boolean, Number, String, or Object. You can basically save anything that can be JSON encoded.
There are two ways to save a PFObject.
Synchronously:
// New PFObject
var pfObject = parseapi.PFObjectCreateObjectWithClassName("TestObject");
// Text, numbers
pfObject.setObject("Cereal Box", "product");
pfObject.setObject(1500, "quantity");
// Can pass an object that will get stored using JSON
pfObject.setObject({ name:"upc", upcData: 123214353 }, "productData");
// Save Synchronously.
// returns (boolean)succeeded, (integer or null)errorCode, (string or null)error
var result = pfObject.save();
if( result.succeeded ) {
Ti.API.info("Successfully saved object!");
Ti.API.info("Created Object ID: " + pfObject.objectId);
} else {
Ti.API.info("Could not save object. ErrorCode: " + result.errorCode + " Error: " + result.error);
}
Asynchronously: (In The Background with Callbacks)
// New PFObject
var pfObject = parseapi.PFObjectCreateObjectWithClassName("TestObject");
// Text, numbers
pfObject.setObject("Cereal Box", "product");
pfObject.setObject(1500, "quantity");
// Can pass an object that will get stored using JSON
pfObject.setObject({ name:"upc", upcData: 123214353 }, "productData");
// Save Asynchronously.
pfObject.saveInBackground( {
success: function(e) {
// event: nothing
Ti.API.info("Success!");
Ti.API.info("Created Object ID: " + pfObject.objectId);
},
error: function(e) {
// event: (integer or null)errorCode, (string or null)error
Ti.API.info("Error: " + JSON.stringify(e));
}
});
Synchronous:
var pfObject = null;
var objectArray = new Array();
for( var i = 1; i < 5; i++ )
{
// New PFObject
pfObject = parseapi.PFObjectCreateObjectWithClassName("TestObject");
// Text, numbers
pfObject.setObject("Candy Bars", "product");
pfObject.setObject(i*10, "quantity");
objectArray.push( pfObject );
}
// Save Synchronously.
// returns (boolean)succeeded, (integer or null)errorCode, (string or null)error
var result = parseapi.PFObjectSaveAll( objectArray );
if( result.succeeded ) {
Ti.API.info("Successfully saved all " + objectArray.length + " objects!");
} else {
Ti.API.info("Could not save all objects. ErrorCode: " + result.errorCode + " Error: " + result.error);
}
Asynchronous:
var pfObject = null;
var objectArray = new Array();
for( var i = 1; i < 5; i++ )
{
// New PFObject
pfObject = parseapi.PFObjectCreateObjectWithClassName("TestObject");
// Text, numbers
pfObject.setObject("Candy Bars", "product");
pfObject.setObject(i*10, "quantity");
objectArray.push( pfObject );
}
// Save Asynchronously.
// does not return or have any callbacks
parseapi.PFObjectSaveAllInBackground( {
objects: objectArray
});
You can retrieve data from the Parse database using a PFQuery. There are a couple of ways to do this. One way is to retrieve an object by it's id. Every PFObject that gets saved to the Parse database automatically obtains an pfObject.objectId
string, a pfObject.createdAt
timestamp, and a pfObject.updatedAt
timestamp. To retrieve an object using a PFQuery by it's id, we use the pfQuery.getObjectWithId( id )
function.
Aside from the pfObject.objectId
, pfObject.createdAt
, and pfObject.updatedAt
, you can retrieve other data from the PFObject by using the pfObject.objectForKey( key )
function.
Here is an example:
Synchronous:
var pfQuery = parseapi.PFQueryCreateQueryWithClassName("TestObject");
var result = pfQuery.getObjectWithId("yaEuC5qrkF");
// Synchronous.
// returns (boolean)succeeded, (PFObject or null)object, (integer or null)errorCode, (string or null)error
if( result.succeeded ) {
Ti.API.info("Successfully queried object!");
var pfObject = result.object;
Ti.API.info("Start Query Result:");
Ti.API.info(" objectId: " + pfObject.objectId );
Ti.API.info(" updatedAt: " + pfObject.updatedAt );
Ti.API.info(" createdAt: " + pfObject.createdAt );
Ti.API.info(" product: " + pfObject.objectForKey("product") );
Ti.API.info(" quantity: " + pfObject.objectForKey("quantity") );
Ti.API.info(" productData: " + JSON.stringify( pfObject.objectForKey("productData") ) );
Ti.API.info("End Query Result");
} else {
Ti.API.info("Could not query object. ErrorCode: " + result.errorCode + " Error: " + result.error);
}
Asynchronous:
var pfQuery = parseapi.PFQueryCreateQueryWithClassName("TestObject");
pfQuery.getObjectInBackgroundWithId({
id: "yaEuC5qrkF",
success: function(e) {
// event: (PFObject)object
Ti.API.info("Success!");
var pfObject = e.object;
Ti.API.info("Start Query Result:");
Ti.API.info(" objectId: " + pfObject.objectId );
Ti.API.info(" updatedAt: " + pfObject.updatedAt );
Ti.API.info(" createdAt: " + pfObject.createdAt );
Ti.API.info(" product: " + pfObject.objectForKey("product") );
Ti.API.info(" quantity: " + pfObject.objectForKey("quantity") );
Ti.API.info(" productData: " + JSON.stringify( pfObject.objectForKey("productData") ) );
Ti.API.info("End Query Result");
},
error: function(e) {
// event: (integer or null)errorCode, (string or null)error
Ti.API.info("Error: " + JSON.stringify(e));
}
});
The output from the above example would be:
[INFO] Successfully queried object!
[INFO] Start Query Result:
[INFO] objectId: yaEuC5qrkF
[INFO] updatedAt: Wed Oct 12 2011 18:19:11 GMT-0400 (EDT)
[INFO] createdAt: Wed Oct 12 2011 18:19:11 GMT-0400 (EDT)
[INFO] product: Cereal Box
[INFO] quantity: 1500
[INFO] productData: {"name":"upc","upcData":123214353}
[INFO] End Query Result
Another way to retrieve data is to build a query. Similar to performing a query on a database, you can build up the query using the pfQuery.whereKey( { key: , query_type: } )
where query_type is one of the following: equalTo, greaterThan, greaterThanOrEqualTo, lessThan, lessThanOrEqualTo, notEqualTo. You can call this function more than once to build more complicated queries. You can also limit, skip and order the results.
Here's an example:
Synchronous:
var pfQuery = parseapi.PFQueryCreateQueryWithClassName("TestObject");
pfQuery.whereKey( {
key: "product",
equalTo: "Cereal Box" // can be equalTo, greaterThan, greaterThanOrEqualTo, lessThan, lessThanOrEqualTo, notEqualTo
});
pfQuery.skip = 2; // skip the first two matching items
pfQuery.limit = 5; // set the limit
pfQuery.orderByDescending("createdAt"); // can also be orderByAscending (takes a key as an argument)
// Synchronous.
// returns (boolean)succeeded, (Array or null)objects, (integer or null)errorCode, (string or null)error
var result = pfQuery.findObjects();
if( result.succeeded ) {
Ti.API.info("Successfully queried objects!");
var pfObjects = result.objects;
Ti.API.info("Query returned " + pfObjects.length + " PFObjects");
Ti.API.info("Start Query Result -------------------------------- ");
for( var i = 0; i < pfObjects.length; i++ )
{
var pfObject = pfObjects[i];
Ti.API.info(" PFObject " + i);
Ti.API.info(" objectId: " + pfObject.objectId );
Ti.API.info(" updatedAt: " + pfObject.updatedAt );
Ti.API.info(" createdAt: " + pfObject.createdAt );
Ti.API.info(" product: " + pfObject.objectForKey("product") );
Ti.API.info(" End PFObject");
Ti.API.info("");
}
Ti.API.info("End Query Result -------------------------------- ");
} else {
Ti.API.info("Could not query objects. ErrorCode: " + result.errorCode + " Error: " + result.error);
}
Asynchronous:
var pfQuery = parseapi.PFQueryCreateQueryWithClassName("TestObject");
pfQuery.whereKey( {
key: "product",
equalTo: "Cereal Box" // can be equalTo, greaterThan, greaterThanOrEqualTo, lessThan, lessThanOrEqualTo, notEqualTo
});
pfQuery.skip = 2; // skip the first two matching items
pfQuery.limit = 5; // set the limit
pfQuery.orderByDescending("createdAt"); // can also be orderByAscending (takes a key as an argument)
// Asynchronous
pfQuery.findObjectsInBackground({
success: function(e) {
// event: (PFObject)object
Ti.API.info("Success!");
var pfObjects = e.objects;
Ti.API.info("Query returned " + pfObjects.length + " PFObjects");
Ti.API.info("Start Query Result -------------------------------- ");
for( var i = 0; i < pfObjects.length; i++ )
{
var pfObject = pfObjects[i];
Ti.API.info(" PFObject " + i);
Ti.API.info(" objectId: " + pfObject.objectId );
Ti.API.info(" updatedAt: " + pfObject.updatedAt );
Ti.API.info(" createdAt: " + pfObject.createdAt );
Ti.API.info(" product: " + pfObject.objectForKey("product") );
//Ti.API.info(" quantity: " + pfObject.objectForKey("quantity") );
//Ti.API.info(" productData: " + JSON.stringify( pfObject.objectForKey("productData") ) );
Ti.API.info(" End PFObject");
Ti.API.info("");
}
Ti.API.info("End Query Result -------------------------------- ");
},
error: function(e) {
// event: (integer or null)errorCode, (string or null)error
Ti.API.info("Error: " + JSON.stringify(e));
}
});
The output from the above example would be:
[INFO] Successfully queried objects!
[INFO] Query returned 4 PFObjects
[INFO] Start Query Result --------------------------------
[INFO] PFObject 0
[INFO] objectId: yaEuC5qrkF
[INFO] updatedAt: Wed Oct 12 2011 18:19:11 GMT-0400 (EDT)
[INFO] createdAt: Wed Oct 12 2011 18:19:11 GMT-0400 (EDT)
[INFO] product: Cereal Box
[INFO] End PFObject
[INFO]
[INFO] PFObject 1
[INFO] objectId: EtmRlGx4bC
[INFO] updatedAt: Wed Oct 12 2011 18:18:20 GMT-0400 (EDT)
[INFO] createdAt: Wed Oct 12 2011 18:18:20 GMT-0400 (EDT)
[INFO] product: Cereal Box
[INFO] End PFObject
[INFO]
[INFO] PFObject 2
[INFO] objectId: ZYIMJazOEP
[INFO] updatedAt: Wed Oct 12 2011 18:18:19 GMT-0400 (EDT)
[INFO] createdAt: Wed Oct 12 2011 18:18:19 GMT-0400 (EDT)
[INFO] product: Cereal Box
[INFO] End PFObject
[INFO]
[INFO] PFObject 3
[INFO] objectId: XKJLnCDhfo
[INFO] updatedAt: Wed Oct 12 2011 18:17:36 GMT-0400 (EDT)
[INFO] createdAt: Wed Oct 12 2011 18:17:36 GMT-0400 (EDT)
[INFO] product: Cereal Box
[INFO] End PFObject
[INFO]
[INFO] End Query Result --------------------------------
You can get more information on how to use some more advanced query functions in this Parse.com Blog Article.
They will teach you how to use pfQuery.whereContainedIn
and more.
Remember that there is a one to one correspondence with this module and the API so just look in the module reference files and you can find any function you're looking for.
You can use the same procedure that you use with findObjects
to get an object count for a query you have built.
Here's an example:
Synchronous:
var pfQuery = parseapi.PFQueryCreateQueryWithClassName("TestObject");
pfQuery.whereKey( {
key: "product",
equalTo: "Cereal Box" // can be equalTo, greaterThan, greaterThanOrEqualTo, lessThan, lessThanOrEqualTo, notEqualTo
});
// Synchronous.
// returns (boolean)succeeded, (Number or null)count, (integer or null)errorCode, (string or null)error
var result = pfQuery.countObjects();
if( result.succeeded ) {
Ti.API.info("Successfully counted " + result.count + " objects!");
} else {
Ti.API.info("Could not count objects. ErrorCode: " + result.errorCode + " Error: " + result.error);
}
Asynchronous:
var pfQuery = parseapi.PFQueryCreateQueryWithClassName("TestObject");
pfQuery.whereKey( {
key: "product",
equalTo: "Cereal Box" // can be equalTo, greaterThan, greaterThanOrEqualTo, lessThan, lessThanOrEqualTo, notEqualTo
});
// Asynchronous
pfQuery.countObjectsInBackground({
success: function(e) {
// event: (Number)count
Ti.API.info("Successfully counted " + e.count + " objects!");
},
error: function(e) {
// event: (integer or null)errorCode, (string or null)error
Ti.API.info("Error: " + JSON.stringify(e));
}
});
Instead of using a PFQuery to get and object from the database, you can just call the parseapi.PFQueryCreateObjectOfClassAndId
function.
Example:
var result = parseapi.PFQueryCreateObjectOfClassAndId( {
objectClass: "TestObject",
objectId: "reWZuh9q9o"
});
if( result.succeeded ) {
Ti.API.info("Successfully got object!");
var pfObject = result.object;
//do something with the object. Print an example.
Ti.API.info( "Quantity: " + pfObject.objectForKey("quantity") );
} else {
Ti.API.info("Could not get object. ErrorCode: " + result.errorCode + " Error: " + result.error);
}
To build another query without having to create a new pfQuery object, you can just call the pfQuery.resetQuery()
function and you can begin building another query.
To use the caching capabilities of PFQuery. You just have to set the cachePolicy
for the PFQuery you're using. More information can be found at parse's website here: Parse.com Caching
All the caching constants can be found in the Parse Module Reference
Example:
var pfQuery = parseapi.PFQueryCreateQueryWithClassName("TestObject");
pfQuery.whereKey( {
key: "product",
equalTo: "Cereal Box" // can be equalTo, greaterThan, greaterThanOrEqualTo, lessThan, lessThanOrEqualTo, notEqualTo
});
pfQuery.cachePolicy = kParseCachePolicyNetworkElseCache;
// Synchronous.
// returns (boolean)succeeded, (Array or null)objects, (integer or null)errorCode, (string or null)error
var result = pfQuery.findObjects();
if( result.succeeded ) {
Ti.API.info("Successfully queried objects!");
} else {
Ti.API.info("Could not query objects. ErrorCode: " + result.errorCode + " Error: " + result.error);
}
IMPORTANT: You can only use the Asynchronous pfQuery.findObjectsInBackground
when using the kParseCachePolicyCacheThenNetwork
constant because it calls the success callback twice, first with the cached results, then with the network results.
Example:
var pfQuery = parseapi.PFQueryCreateQueryWithClassName("TestObject");
pfQuery.whereKey( {
key: "product",
equalTo: "Cereal Box" // can be equalTo, greaterThan, greaterThanOrEqualTo, lessThan, lessThanOrEqualTo, notEqualTo
});
pfQuery.cachePolicy = kParseCachePolicyCacheThenNetwork;
// Asynchronous
pfQuery.findObjectsInBackground({
success: function(e) {
// event: (PFObject)object
Ti.API.info("Success!");
// gets called twice, first with the cached results, then with the network results.
},
error: function(e) {
// event: (integer or null)errorCode, (string or null)error
Ti.API.info("Error: " + JSON.stringify(e));
}
});
You can remove data easily by first retrieving a PFObject then calling its pfObject.deleteObject()
function. Once you delete a PFObject using this function, object on the Parse database will be deleted but your copy of the PFObject will still be valid until you null out the variable.
The following example assumes you already queried the Parse database and retrieved a PFObject.
Synchronous:
var pfObject = //Retrieve a PFObject using PFQuery as in the example above
// delete object synchronously
var result = pfObject.deleteObject();
if( result.succeeded )
{
Ti.API.info("Successfully deleted object with ID: " + pfObject.objectId);
}
else
{
Ti.API.info("Could not delete object with ID: " + pfObject.objectId + " ErrorCode: " + result.errorCode + " Error: " + result.error);
}
Asynchronous:
var pfObject = //Retrieve a PFObject using PFQuery as in the example above
// delete object Asynchronously
pfObject.deleteObjectInBackground({
success: function(e) {
// event: nothing
Ti.API.info("Successfully deleted object with ID: " + pfObject.objectId);
},
error: function(e) {
// event: (integer or null)errorCode, (string or null)error
Ti.API.info("Could not delete object with ID: " + pfObject.objectId + " ErrorCode: " + e.errorCode + " Error: " + e.error);
}
});
To update the data stored in a PFObject or PFUser, just set/change the object fields using pfObject.setObject()
or pfUser.setObject()
and save them again with the new data. It's that simple.
Update a User's password using the pfUser.setPassword()
method.
Update a User's username or email using the pfUser.setObject(newEmail, "email")
or pfUser.setObject(newUsername, "username")
.
Remember to call save
or saveInBackground
when you're done modifying the object's content so it can synchronize with Parse's servers.
PFFile's can't be updated.
Users are handled in a special way using the PFUser object. PFUser inherits all the functions from PFObject but also includes some extra functions to sign up and login/logout users.
IMPORTANT: The username, email, password
when logging in or during sign up are now all CASE-SENSITIVE!! IT IS YOUR RESPONSIBILITY to convert the username and password to lowercase if you want to prevent the autocorrect on most phones that capitalize the first letter in a text field from messing up the signup and login process.
To signup a new user you need to first initialize the sign up process using the pfUser.signUp( {} )
function with a username, password, and email argument. The email
field is optional or you can pass null
but the username and password are mandatory. After it's initialized you can add any other data just like a PFObject. In the example, we add that the user lives in "New York" under the "city" key using the setObject( data, key )
function. After you're done adding data, you run the pfUser.finishSignUp()
function to create the user in the database.
After a new user is created, they will automatically be logged in.
Example:
Synchronous:
var email =<EMAIL_ADDRESS>var password = "test";
// PFUser objects inherit all the methods of PFObject
var pfUser = parseapi.createPFUser(); // first create a pfUser object
// initialize the signup process with credentials
pfUser.initSignUp( {
username: email,
password: password,
email: email //the email field is optional
});
// you can set objects just like PFObject before finishing the sign up process
pfUser.setObject("New York", "city");
// Synchronous sign up function, logs you in after it finishes
// returns (boolean)succeeded, (integer or null)errorCode, (string or null)error
var result = pfUser.finishSignUp();
if( result.succeeded ) {
Ti.API.info("Successfully created a new user with id: " + pfUser.objectId);
var user = parseapi.PFUserCurrentUser();
Ti.API.info( "Logged In as: " + user.objectForKey("username") ); // show the logged in user
} else {
Ti.API.info("Could not create new user. ErrorCode: " + result.errorCode + " Error: " + result.error);
}
Asynchronous:
var email =<EMAIL_ADDRESS>var password = "test";
// PFUser objects inherit all the methods of PFObject
var pfUser = parseapi.createPFUser(); // first create a pfUser object
// initialize the signup process with credentials
pfUser.initSignUp( {
username: email,
password: password,
email: email
});
// you can set objects just like PFObject before finishing the sign up process
pfUser.setObject("New York", "city");
// Asynchronous sign up function
// returns (boolean)succeeded, (integer or null)errorCode, (string or null)error
pfUser.finishSignUpInBackground({
success: function(e) {
// event: nothing
Ti.API.info("Successfully created a new user with id: " + pfUser.objectId);
var user = parseapi.PFUserCurrentUser();
Ti.API.info( "Logged In as: " + user.objectForKey("username") ); // show the logged in user
},
error: function(e) {
// event: (integer or null)errorCode, (string or null)error
Ti.API.info("Could not create new user. ErrorCode: " + e.errorCode + " Error: " + e.error);
}
});
To login a user you make a call to the parseapi.PFUserLogin( { username: password: } )
function.
To logout a user call the parseapi.PFUserLogout()
function.
The current user will be kept in the application's cache when you exit your application. This way you don't have to have the user login/out every time they open your app. But REMEMBER when you resume your application, the PFUser you obtain from parseapi.PFUserCurrentUser()
is a cached version. So make sure to refresh it by calling pfUser.refresh()
or pfUser.refreshInBackground()
.
Example:
Synchronous:
var user =<EMAIL_ADDRESS>var pass = "test";
//Synchronous User Login
// returns (boolean)succeeded, (integer or null)errorCode, (string or null)error, (PFUser or nil) user
var result = parseapi.PFUserLogin( {
username: user,
password: pass
});
if( result.succeeded ) {
Ti.API.info("Successfully logged in!");
var user = result.user;
Ti.API.info( "Logged In as: " + user.objectForKey("username") ); // show the logged in user
} else {
Ti.API.info("Could not login with credentials. ErrorCode: " + result.errorCode + " Error: " + result.error);
}
Asynchronous:
var user =<EMAIL_ADDRESS>var pass = "test";
//Asynchronous User Login
parseapi.PFUserLoginInBackground( {
username: user,
password: pass,
success: function(e) {
// event: (PFObject) user
Ti.API.info("Successfully logged in!");
var user = e.user;
Ti.API.info( "Logged In as: " + user.objectForKey("username") ); // show the logged in user
},
error: function(e) {
Ti.API.info("Could not login with credentials. ErrorCode: " + e.errorCode + " Error: " + e.error);
}
});
To check if a user is logged in or to obtain the current PFUser object, make a call to the parseapi.PFUserCurrentUser()
function.
If this function returns null, it means there's no user logged in.
Example:
var user = parseapi.PFUserCurrentUser();
if( user != null )
{
Ti.API.info( "Current Logged In User: \n" + user.objectForKey("username") );
} else {
Ti.API.info( "No user logged in" );
}
The current user will be kept in the application's cache when you exit your application. This way you don't have to have the user login/out every time they open your app. But REMEMBER when you resume your application, the PFUser you obtain from parseapi.PFUserCurrentUser()
is a cached version. So make sure to refresh it by calling pfUser.refresh()
or pfUser.refreshInBackground()
.
Example:
if (Titanium.Platform.name == 'android') {
// Refresh the Current User on Resume on Android
Ti.Android.currentActivity.addEventListener('resume', function(e) {
Ti.API.info("Resumed Android App");
var user = parseapi.PFUserCurrentUser();
if( user != null ) {
user.refresh();
}
});
} else {
// Refresh the Current User on Resume on iPhone
Ti.App.addEventListener('resume', function(){
Ti.API.info("Resumed iPhone App");
var user = parseapi.PFUserCurrentUser();
if( user != null ) {
user.refresh();
}
});
}
IMPORTANT: Remember to refresh the current user before saving or changing data. Just in case to prevent you from overwriting any data you might have saved using the REST API somewhere else.
Since the PFUser object inherits all the functions from PFObject, you can treat it like updating any PFObject.
Example:
//get the current user
var currentUser = parseapi.PFUserCurrentUser();
if( currentUser != null )
{
// Set the new data or change old data
currentUser.setObject("Dave", "firstName"); // change my name from David to Dave
currentUser.setObject("programmerdave", "nickname"); // add a nickname
// Then Save.
// Synchronous Save
// returns (boolean)succeeded, (integer or null)errorCode, (string or null)error
var result = currentUser.save();
if( result.succeeded ) {
Ti.API.info("Successfully saved data!");
} else {
Ti.API.info("Could not save data. ErrorCode: " + result.errorCode + " Error: " + result.error);
}
}
If you want to update data for a user that's currently not logged in, you can't. The parse api will let you read but not update a user that hasn't been authenticated by a login method. I'll let parse tell you more Parse PFUser Security
The PFUser class provides a layer of security that prevents altering objects that haven't been authenticated on the device.
The policy is that you are not able to invoke any of the save or delete type methods unless the object was obtained using an authenticated method, like logIn or signUp.
This ensures that only the device that has authenticated the user via a username and password has the ability to alter that user.
You can however read other user's data by using a PFUser Query but the save and delete methods will not work. You can check if a user is authenticated on the device (meaning that you can save or delete it) by checking the pfUser.isAuthenticated
property.
IMPORTANT: You can't save or delete any updates to a user that has not been authenticated on the device. See the Updating Other User's Data
section of this guide.
To query for users, you need to use the special user query, parseapi.PFQueryCreateQueryForUser()
that returns a query that can search for users. The objects returned from the query are PFObjects.
var userQuery = parseapi.PFQueryCreateQueryForUser();
if( userQuery != null )
{
// now it works just like a normal query
userQuery.whereKey( {
key: "city",
equalTo: "New York" // can be equalTo, greaterThan, greaterThanOrEqualTo, lessThan, lessThanOrEqualTo, notEqualTo
});
// Synchronous.
// returns (boolean)succeeded, (Array or null)objects, (integer or null)errorCode, (string or null)error
var result = userQuery.findObjects();
if( result.succeeded ) {
Ti.API.info("Successfully queried objects!");
// remember you can only read these user objects
var pfObjectUsers = result.objects;
if( pfObjectUsers.length > 0 )
{
// The users here are PFObjects
var firstUser = pfObjectUsers[0];
// print username
Ti.API.info( "Username: " + firstUser.objectForKey("username") );
}
} else {
Ti.API.info("Could not query user objects. ErrorCode: " + result.errorCode + " Error: " + result.error);
}
}
If you want to retrieve PFUser instead of PFObject, you can do so by calling parseapi.PFQueryCreateUserObjectWithId( id )
.
Example:
var result = parseapi.PFQueryCreateUserObjectWithId( "x1y2z345" );
if( result.succeeded ) {
Ti.API.info("Successfully got user object!");
// remember you can only read these user objects
var pfUser = result.user;
//do something with the user. Print the username
Ti.API.info( "Username: " + pfUser.objectForKey("username") );
} else {
Ti.API.info("Could not get user. ErrorCode: " + result.errorCode + " Error: " + result.error);
}
REMEMBER: These PFObjects and PFUsers are read only.
If the user forgets their password, you can call parseapi.PFUserRequestPasswordResetForEmail( email )
or parseapi.PFUserRequestPasswordResetForEmailInBackground
. More information for this is available here Parse Resetting Passwords
Synchronous:
var email =<EMAIL_ADDRESS>//Synchronous Password Reset
// returns (boolean)succeeded, (integer or null)errorCode, (string or null)error, (PFUser or null) user
var result = parseapi.PFUserRequestPasswordResetForEmail( email );
if( result.succeeded ) {
Ti.API.info("Successfully Requested Password Reset. Check your email.");
} else {
Ti.API.info("Could not request password reset. ErrorCode: " + result.errorCode + " Error: " + result.error);
}
Asynchronous:
var email =<EMAIL_ADDRESS>//Asynchronous Password Reset
parseapi.PFUserRequestPasswordResetForEmailInBackground( {
email: email,
success: function(e) {
// event: null
Ti.API.info("Successfully Requested Password Reset. Check your email.");
},
error: function(e) {
// event: (integer or null)errorCode, (string or null)error
Ti.API.info("Could not request password reset. ErrorCode: " + result.errorCode + " Error: " + result.error);
}
});
If a user wants to change their password, first set the new password by calling pfUser.setPassword
and then save the pfUser.
var currentUser = parseapi.PFUserCurrentUser();
// First set the new password
currentUser.setPassword( newpassword );
// Then Save.
// returns (boolean)succeeded, (integer or null)errorCode, (string or null)error
var result = currentUser.save();
if( result.succeeded ) {
Ti.API.info("Successfully changed password!");
} else {
Ti.API.info("Could not save new password. ErrorCode: " + result.errorCode + " Error: " + result.error);
}
More information about Parse's integration with the Facebook API can be found here Facebook Users.
This module also has functions to access the Facebook API dialog and request functions. This is very similar to using the original facebook functions found in the Titanium SDK Facebook Module.
If you use this library for your Facebook API there is no need to use Titanium's Facebook Module.
More information about setting up your application to use the Facebook API can be found here Facebook iOS Tutorial
IMPORTANT: Facebook Integration is currently only available on iOS.
From the Facebook Developer Pages, put your facebook application id in the facebookApplicationId
property when calling parseapi.initParse
.
Example:
var parseapi = require('com.forge42.parseapi');
parseapi.initParse( {
applicationId: "put your parse api APPLICATION ID here",
clientKey: "put your parse api CLIENT KEY here",
facebookApplicationId: "put your facebook application APP ID here"
});
VERY IMPORTANT: You have to setup a custom URL Scheme for your iOS App for this module to work.
You might want to check if your application has registered a Facebook application id. This is an easy way to determine if your Facebook functions should run or not so you can easily disable and enable your Facebook implementation. This is useful for Android devices as the Parse API doesn't support Facebook on Android yet. So when it does support Android, you can just add the Facebook Application Id to your initParse method and you'll be set!
Example:
// when we initialize, check if we are using Android or iOS
var parseapi = require('com.forge42.parseapi');
if (Titanium.Platform.name == 'android')
{
// Parse doesn't support the Facebook API on Android yet.
parseapi.initParse( {
applicationId: "Place your Application Id Here",
clientKey: "Place your Client Key Here"
});
} else {
// Parse Supports Facebook API on iOS
parseapi.initParse( {
applicationId: "Place your Application Id Here",
clientKey: "Place your Client Key Here",
facebookApplicationId: "Place your Facebook Application Id Here"
});
}
Then when in your code, you can check if the Facebook application id was setup with the following property.
Example:
if( parseapi.ParseHasFacebookApplicationId ) {
// Do something with facebook here
}
All the examples in the included app.js use this
Follow these steps to add your custom url scheme for your facebook integration:
Step 1) Setup this Parse Module and Run your application once in the iphone simulator.
Step 2) Go into the newly created folder (YOUR PROJECT DIRECTORY)/build/iphone
and copy your Info.plist
file into your root project directory (YOUR PROJECT DIRECTORY)
. This will let Titanium know you're using a custom Info.plist
file. (Don't worry about updating the file. Titanium will do it's best to change what it needs in your custom.plist file without overwriting your changes.)
Step 3) Now open up Info.plist in a text editor of your choice.
Step 4) Do a search for the CFBundleURLSchemes
key. Now do either of the following steps.
I have the CFBundleURLSchemes key
fb
. Then go to step 6. Example: <string>fb1234567890</string>
I don't have the CFBundleURLSchemes key
Step 5) Add the following lines in the Info.plist
. Remember to replace com.mycompany.myapplication
with your own. Then go to step 6. (Hint: Add these lines inside the <dict></dict>
after <plist version="1.0">
)
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>com.mycompany.myapplication</string>
<key>CFBundleURLSchemes</key>
<array>
<string>fb1234567890</string>
</array>
</dict>
</array>
Step 6) Save the file. Make sure it's in your Project Root Directory. This process makes titanium use a custom Info.plist file. Titanium will do it's best to try and update your keys but if you run into any problems, delete the custom Info.plist file, clean and build your project, and repeat these steps.
To login or sign up a user you can only call the Asynchronous function parseapi.PFUserLogInWithFacebookInBackground
. It takes a permissions array of strings. These permissions can be found here: Facebook API Permissions
The user will be presented with a Facebook Login or Sign Up Screen to authorize your application.
The current user will be kept in the application's cache when you exit your application. This way you don't have to have the user login/out every time they open your app. But REMEMBER when you resume your application, the PFUser you obtain from parseapi.PFUserCurrentUser()
is a cached version. So make sure to refresh it by calling pfUser.refresh()
or pfUser.refreshInBackground()
.
Also the only way you can find out if the user is new is by checking the pfUser.isNew
property like it shows in the example, otherwise the user isn't new and just logged in.
Example:
var permissions = new Array("");
// Asynchronous facebook sign up/login function
parseapi.PFUserLogInWithFacebookInBackground({
permissions: permissions,
success: function(e) {
// event: (PFUser)user
var pfUser = e.user;
if( pfUser.isNew )
{
Ti.API.info("Successfully created a new user with facebook id: " + pfUser.facebookId);
}
else
{
Ti.API.info("Logged in with facebook id: " + pfUser.facebookId);
}
test_button_array[9].title = "PFUser Logout";
},
error: function(e) {
// event: (integer or null)errorCode, (string or null)error
if( e.errorCode == parseapi.kParseErrorFacebookLoginCancelled ) {
Ti.API.info(e.error); // user cancelled error message
}
else {
Ti.API.info("Could not create new user. ErrorCode: " + e.errorCode + " Error: " + e.error);
}
}
});
To link a Facebook Account with an existing PFUser you can only call the Asynchronous function pfUser.linkToFacebookInBackground
.
It takes a permissions array of strings. These permissions can be found here: Facebook API Permissions
The user will be presented with a Facebook Login or Sign Up Screen to authorize your application and after it succeeds, the user can now use his Facebook account with the account he registered manually beforehand. The user can also now login through his Facebook account as well for the same user account.
var permissions = new Array("");
var user = parseapi.PFUserCurrentUser();
if( user == null )
{
Ti.API.info("No User Currently Logged In");
return;
}
if( user.hasFacebook )
{
Ti.API.info("User already has a linked facebook account");
return;
}
// Only Asynchronous
user.linkToFacebookInBackground({
permissions: permissions,
success: function(e) {
// event: null
var pfUser = parseapi.PFUserCurrentUser();
Ti.API.info("Successfully Linked Account! User Facebook Id: " + pfUser.facebookId);
},
error: function(e) {
// event: (integer or null)errorCode, (string or null)error
if( e.errorCode == parseapi.kParseErrorFacebookLoginCancelled ) {
Ti.API.info(e.error);
}
else {
Ti.API.info("Could not link with Facebook Account!  ErrorCode: " + e.errorCode + " Error: " + e.error);
}
});
Synchronous:
// Synchronous Unlink
var result = user.unlinkFromFacebook();
// Synchronous.
// returns (boolean)succeeded, (integer or null)errorCode, (string or null)error
if( result.succeeded ) {
Ti.API.info("Success: The user is no longer associated with their Facebook account.");
} else {
Ti.API.info("Could not unlink account! ErrorCode: " + e.errorCode + " Error: " + e.error);
}
There is a finite time before the facebook session expires so you have to check if the facebook session expired before running any facebook calls. Also if you close your app and come back in later, you might still be logged in with a PFUser but the facebook session might have expired or not be valid. You can use the parseapi.FacebookSessionIsValid
property to check if the session is expired. If it is expired, you can make the user login again through facebook or log the user out. When the facebook session expires, you will still be able to see the current logged in user when calling PFUserCurrentUser
so checking if the user is logged in is not enough. So make sure to check if the session is valid.
A way around this is to use the offline_access
permission in parseapi.PFUserLogInWithFacebookInBackground
. This will give you an infinite expiry time and you won't have to authorize the user again. You can read more about this in the Facebook Authentication Page or the Facebook Permissions Page
Functions are available to access the Facebook Graph API or the deprecated Facebook REST API. More information available here Facebook Request iOS Documentation
There are also functions for using Facebook Dialogs.
The following functions are extremely similar to the Titanium Facebook functions so you should be familiar with them if you've used the Facebook API. Also you should be able to port your existing code without a problem. (The following are examples used by the Facebook Titanium Examples with some slight modifications to be used with the parseapi).
IMPORTANT: These functions assume that you're logged in, otherwise they will fail and return an error. Sorry but these functions do not return an errorCode. Since these functions do not return an error code, make sure to check if you're logged in with the parseapi.PFUserCurrentUser()
and check that the user's Facebook session is still valid by checking parseapi.FacebookSessionIsValid
before calling any of the following facebook functions. If the user is not logged in or the facebook session is not valid, you'll have to make the user login again by calling the parseapi.PFUserLoginWithFacebookInBackground()
.
Examples:
parseapi.FacebookRequestWithGraphPath('me', {}, 'GET', function(e) {
if (e.success) {
Ti.API.info(e.result);
} else if (e.error) {
Ti.API.info(e.error);
} else {
Ti.API.info('Unknown response');
}
});
(More Facebook Info on Events)
// First make sure this permission exists
var permissions = new Array("create_event");
parseapi.PFUserLogInWithFacebookInBackground({
permissions: permissions,
success: function(e) {},
error: function(e) {}
};
// ...
// ...
// Now create the event after you've confirmed authorize() was successful.
var starttime = new Date(2012, 4, 31, 17, 0);
var endtime = new Date(2012, 4, 31, 19, 0);
var title = "Parse Module for Titanium Testing";
var description = "What a great module!";
var data = {
start_time: JSON.stringify(starttime), // API expects a JSON stringified date
end_time: JSON.stringify(endtime),
description: description,
name: title
};
parseapi.FacebookRequestWithGraphPath('me/events', data, 'POST', function(e) {
if (e.success) {
Ti.API.info("Success! Returned from FB: " + e.result);
} else {
if (e.error) {
Ti.API.info(e.error);
} else {
Ti.API.info("Unknown result");
}
}
});
(More Facebook Info on User Status Message)
// First make sure this permission exists
var permissions = new Array("publish_stream");
parseapi.PFUserLogInWithFacebookInBackground({
permissions: permissions,
success: function(e) {},
error: function(e) {}
};
// ...
// ...
parseapi.FacebookRequestWithGraphPath('me/feed', {message: "Trying out FB Graph API and it's fun!"}, "POST", function(e) {
if (e.success) {
Ti.API.info("Success! From FB: " + e.result);
} else {
if (e.error) {
Ti.API.info(e.error);
} else {
Ti.API.info("Unkown result");
}
}
});
(More Facebook Info on Uploading Photos)
// First make sure this permission exists
var permissions = new Array("publish_stream");
parseapi.PFUserLogInWithFacebookInBackground({
permissions: permissions,
success: function(e) {},
error: function(e) {}
};
// ...
// ...
var f = Ti.Filesystem.getFile('pumpkin.jpg');
var blob = f.read();
var data = {
message: 'This is a pumpkin',
picture: blob
};
parseapi.FacebookRequestWithGraphPath('me/photos', data, 'POST', function(e){
if (e.success) {
Ti.API.info("Success! From FB: " + e.result);
} else {
if (e.error) {
Ti.API.info(e.error);
} else {
Ti.API.info("Unkown result");
}
}
});
(More Facebook Info on Uploading Photos)
// First make sure this permission exists
var permissions = new Array("publish_stream");
parseapi.PFUserLogInWithFacebookInBackground({
permissions: permissions,
success: function(e) {},
error: function(e) {}
};
// ...
// ...
var f = Ti.Filesystem.getFile('pumpkin.jpg');
var blob = f.read();
var data = {
caption: 'This is a pumpkin',
picture: blob
};
parseapi.FacebookRequest('photos.upload', data, function(e){
if (e.success) {
Ti.API.info("Success! From FB: " + e.result);
} else {
if (e.error) {
Ti.API.info(e.error);
} else {
Ti.API.info("Unkown result");
}
}
});
(More Facebook Info on the Feed Dialog)
var data = {
link: "http://www.appcelerator.com",
name: "Appcelerator Titanium Mobile",
message: "Checkout this cool open source project for creating mobile apps",
caption: "Appcelerator Titanium Mobile",
picture: "http://developer.appcelerator.com/assets/img/DEV_titmobile_image.png",
description: "You've got the ideas, now you've got the power. Titanium translates your hard won web skills into native applications..."
};
parseapi.FacebookDialog("feed", data, function(e) {
if (e.success) {
Ti.API.info("Success! From FB: " + e.result);
} else {
if (e.error) {
Ti.API.info(e.error);
} else if (e.cancelled) {
Ti.API.info('Cancelled');
} else {
Ti.API.info("Unkown result");
}
}
});
PFFile lets you store application files in the cloud that would otherwise be too large or cumbersome to fit into a regular PFObject. The most common use case is storing images but you can also use it for documents, videos, music, and any other binary data.
You can find more information about PFFiles here in the Parse.com iOS PFFiles Section
You can only store Titanium Blobs in a PFFile.
You don't need to worry about filename collisions. Each upload gets a unique identifier so there's no problem with uploading multiple files named resume.txt.
It's important that you give a name to the file that has a file extension. This lets Parse figure out the file type and handle it accordingly. So, if you're storing PNG images, make sure your filename ends with .png.
Synchronous:
// Load a file and convert it to a blob
var file = Ti.Filesystem.getFile('resume.txt');
var blob = file.read(); // you can also use f.toBlob();
// New PFFile with name and data
var pfFile = parseapi.PFFileCreateFileWithNameAndData( {
name: "resume.txt",
data: blob
});
// Save File Synchronously.
// returns (boolean)succeeded, (integer or null)errorCode, (string or null)error
var result = pfFile.save();
if( result.succeeded ) {
Ti.API.info("Successfully saved file: " + pfFile.name );
Ti.API.info("Created Object URL: " + pfFile.url);
} else {
Ti.API.info("Could not save object. ErrorCode: " + result.errorCode + " Error: " + result.error);
}
// Now save this file in a PFObject
// New PFObject
var pfObject = parseapi.PFObjectCreateObjectWithClassName("TestObjectWithFile");
pfObject.setObject("resume.txt", "name");
pfObject.setObject(pfFile, "savedFile");
// save pfObject
result = pfObject.save();
if( result.succeeded ) {
Ti.API.info("Successfully saved object!");
} else {
Ti.API.info("Could not save object. ErrorCode: " + result.errorCode + " Error: " + result.error);
}
Asynchronous:
// Load a file and convert it to a blob
var file = Ti.Filesystem.getFile('resume.txt');
var blob = file.read(); // you can also use f.toBlob();
// New PFFile with name and data
var pfFile = parseapi.PFFileCreateFileWithNameAndData( {
name: "resume.txt",
data: blob
});
// Save File Asynchronously.
pfFile.saveInBackground( {
success: function(e) {
// event: nothing
Ti.API.info("Successfully saved file: " + pfFile.name );
Ti.API.info("Created Object URL: " + pfFile.url);
// New PFObject
var pfObject = parseapi.PFObjectCreateObjectWithClassName("TestObjectWithFile");
// Text, numbers
pfObject.setObject("resume.txt", "name");
pfObject.setObject(pfFile, "savedFile");
// save pfObject
result = pfObject.save();
if( result.succeeded ) {
Ti.API.info("Successfully saved object!");
} else {
Ti.API.info("Could not save object. ErrorCode: " + result.errorCode + " Error: " + result.error);
}
},
error: function(e) {
// event: (integer or null)errorCode, (string or null)error
Ti.API.info("Error: " + JSON.stringify(e));
}
});
Storing images is basically the same as storing files except that there are some minor issues outlined in the next section below. You can find an example of storing images in the example/app.js
file in this module.
There is a slight issue with the way Titanium stores it's TiBlob data type for images. On iOS, if an image is stored to a TiBlob, it will always return a JPEG representation of the image, even if the image was a png file. On Android, it will always return a PNG representation. This only affects us when we try to store an image to a Parse PFFile object. If the user chooses an image from the gallery or the camera, these limitations are imposed by the current release of the Titanium Mobile SDK.
Therefore, to provide you with more choices, I have implemented the parseapi.setDefaultTiBlobImageRepresentation( parseapi.kTiBlobImageDefaultPNG )
global function. Where you can either pass parseapi.kTiBlobImageDefaultPNG
or parseapi.kTiBlobImageDefaultJPEG
as the argument to set the default way images are stored in a PFFile if the TiBlob was not loaded directly from a TiFile. The default global setting for storing TiBlob Images in all PFFiles is parseapi.kTiBlobImageDefaultPNG
, so just make sure you know this when uploading images that you didn't directly load from a TiFile.
REMEMBER: This isn't a problem if you use a TiFile and convert it to a TiBlob data type by using myfile.toBlob()
or myFile.read()
in your javascript. In this case, the data for your image will be stored correctly in whatever format the file is stored in.
IMPORTANT: If you're not sure that a TiBlob image you're using will be saved with parseapi.setDefaultTiBlobImageRepresentation()
, I have implemented the parseapi.willTiBlobBeSavedWithDefaultImageRepresentation( TiBlob )
function which checks your TiBlob and returns a boolean value. You can also use parseapi.getDefaultTiBlobImageRepresentation()
which will return either parseapi.kTiBlobImageDefaultPNG
or parseapi.kTiBlobImageDefaultJPEG
.
IMPORTANT: If you try to save a TiFile, you will get the following error: TiFile is not a supported data type. Please use myfile.toBlob() to provide a TiBlob data type. Storing as empty data.
and the PFFile will be saved as an empty file. So remember to use myfile.toBlob()
or myFile.read()
in your javascript before saving the data in a PFFile. We only accept the TiBlob datatype.
To retrieve a file, you can query the object you saved the file in and then call pfFile.getData()
or pfFile.getDataInBackground()
which will download the file from the server and return a TiBlob.
Example:
// Get a specific object with a query
var result = parseapi.PFQueryCreateObjectOfClassAndId( {
objectClass: "TestObjectWithFile",
objectId: "0123456789"
});
if( result.succeeded )
{
var pfObject = result.object;
var pfFile = pfObject.objectForKey("savedFile");
if( pfFile != null )
{
var result = pfFile.getData();
if( result.succeeded ) {
Ti.API.info("Got data for file: " + pfFile.name);
}
else {
Ti.API.info("Could not get data for File. ErrorCode: " + result.errorCode + " Error: " + result.error);
}
}
else
{
Ti.API.info("Object has no saved file");
}
} else {
Ti.API.info("Could not find object");
}
This module supports all the associations shown in the Parse.com Relational Data Section and Parse.com User Associations Section of their iOS Guide.
//PFObject Associations example
var post = parseapi.PFObjectCreateObjectWithClassName("Post");
post.setObject("This Parse Module is Great!", "name");
var result = post.save(); // save the post, then change the title and let the comment save both of these objects
var comment = parseapi.PFObjectCreateObjectWithClassName("Comment");
comment.setObject("awesome!", "comment");
comment.setObject(post, "post");
post.setObject("I have comments now!", "name");
post.setObject("I have content too!", "content");
//asynchronous
comment.saveInBackground( {
success: function(e) {
Ti.API.info("Success: " + JSON.stringify(e));
},
error: function(e) {
Ti.API.info("Error: " + JSON.stringify(e));
}
});
var user = parseapi.PFUserCurrentUser();
if( user == null ) {
alert("No User Logged In!");
return;
}
//User Associations example
var post = parseapi.PFObjectCreateObjectWithClassName("Post");
post.setObject("How are you " + user.objectForKey("username") + "!", "name");
post.setObject(user, "user");
//synchronous
var result = post.save();
if( result.succeeded ) {
Ti.API.info("Successfully saved object!");
} else {
Ti.API.info("Could not save object. ErrorCode: " + result.errorCode + " Error: " + result.error);
}
You can apply this same idea to retrieving PFObjects.
var user = parseapi.PFUserCurrentUser();
if( user == null ) {
alert("No User Logged In!");
return;
}
// Find all posts by the current user
var pfQuery = parseapi.PFQueryCreateQueryWithClassName("Post");
pfQuery.whereKey( {
key: "user",
equalTo: user
});
// Synchronous.
// returns (boolean)succeeded, (Array or null)objects, (integer or null)errorCode, (string or null)error
var result = pfQuery.findObjects();
if( result.succeeded ) {
Ti.API.info("Successfully queried objects!");
var pfObjects = result.objects;
Ti.API.info("Query returned " + pfObjects.length + " PFObjects");
} else {
Ti.API.info("Could not query objects. ErrorCode: " + result.errorCode + " Error: " + result.error);
}
REMEMBER: Receiving push notifications for iOS doesn't work in the simulator! But you can send push notifications in the simulator :)
Please visit the Parse iOS Guide for Push Notifications to find out how to set this up.
After you setup your iOS Certificates, Keys, and Provisioning Profile, you can add the following lines of code to your application to register for push notifications:
// iOS Push Notifications
Ti.Network.registerForPushNotifications({
types:[
Ti.Network.NOTIFICATION_TYPE_BADGE,
Ti.Network.NOTIFICATION_TYPE_ALERT,
Ti.Network.NOTIFICATION_TYPE_SOUND
],
success: function(e) {
var token = e.deviceToken;
// register the parse api to receive notifications
parseapi.ParseiOSPushStoreDeviceToken( token );
// Synchronous
// subscribe to global channel
var result = parseapi.ParseiOSPushSubscribeToChannel("");
if( result.succeeded == false )
{
alert("Could not subscribe to global push notifications channel");
}
},
error: function(e) {
alert("iOS Register For Push Notifications Error: " + e.error);
},
callback: function(e) {
var data = e.data;
// Let parse handle the in app push notifications
// this function will show the user an alert dialog and make an alert sound
parseapi.ParseiOSPushHandlePush(data);
}
});
This module wraps the function calls that the Parse API makes available through it's SDK. So by looking at this Parse Module Reference and Parse's Documentation on Parse.com iOS Push Notifications, you should be able to use their documentation to do anything with push notifications. There are other methods such as subscribing, unsubscribing, retrieving different channels which you can find the the Parse Module Reference.
Here is a simple example where a device sends a message to the global push notification channel synchronously. It shouldn't be hard to use this example and the coding patterns in this guide to write other Push Notification code.
Example:
// Synchronous
// Send Push Message to Global Channel
// returns (boolean)succeeded, (integer or null)errorCode, (string or null)error
var result = parseapi.ParseiOSPushSendPushMessageToChannel( {
channel: "", // global channel
message: "Client Sent Everyone this Message!"
});
if( result.succeeded ) {
alert("Successfully sent Push Notification message.");
} else {
alert("Could not send Push Notification message. ErrorCode: " + result.errorCode + " Error: " + result.error);
}
Here's another example of how to send data. You can send the following properties alert, badge, and sound which are described in Apple's documentation but you can also send custom properties.
var myData = {
alert: "Hello everyone!",
badge: 3,
sound: "default",
customFlag: true
};
// Synchronous
// Send Push Data to Global Channel
// returns (boolean)succeeded, (integer or null)errorCode, (string or null)error
var result = parseapi.ParseiOSPushSendPushDataToChannel( {
channel: "", // global channel
data: myData
});
if( result.succeeded ) {
alert("Successfully sent Push Notification message.");
} else {
alert("Could not send Push Notification message. ErrorCode: " + result.errorCode + " Error: " + result.error);
}
You can retrieve these messages in the Ti.Network.registerForPushNotifications
callback function or just let Parse Handle it with parseapi.ParseiOSPushHandlePush(data);
Example:
Ti.Network.registerForPushNotifications({
//....other callbacks .... etc....
callback: function(e) {
var data = e.data;
if( data.customFlag == true )
{
alert("You set the custom flag!!!!");
}
else
{
alert(data.alert);
}
// Or Let parse handle the in app push notifications
// this function will show the user an alert dialog and make an alert sound
//parseapi.ParseiOSPushHandlePush(data);
}
});
In all the examples above, if a function fails, it returns an errorCode
and an error
string. You can check the error code by comparing it against the error codes listed in the Error Code Properties of the Parse Module Reference page of this documentation.
Example:
//Asynchronous User Login
parseapi.PFUserLoginInBackground( {
username: user,
password: pass,
success: function(e) {
},
error: function(e) {
// An error occured
// Used the wrong credentials to login a user
if( e.errorCode == parseapi.kParseErrorUserWrongCredentials )
{
Ti.API.info("Please try to login again! Error: " + e.error);
}
}
});
Important: All debugging info is turned off by default
You can call the parseapi.enableParseModuleDebugLog( boolean )
function to show more debugging information from the Parse API Module. You can test this for yourself in the examples. All messages from this will be prefixed with [PARSE MODULE]
.
This guide contains examples and everything you need to know to start using the parse api module.
The following reference files list all the functions, arguments, and return values for the Parse Module.
Click here to see version and release notes
Programmer: David E. Rodriguez
Company: Forge42
Website: www.forge42.com
Blog<EMAIL_ADDRESS>Twitter: @programmerdave
If you find any bugs, please let me know.
Also when reporting a bug or problem, please send me your iOS build.log
file in your e-mail if using the iOS version of the module.
Please direct questions, feedback, and concerns about this module to<EMAIL_ADDRESS>Please include Parse API Module iOS Support
or Parse API Module Android Support in the subject line.
I will get back to you in a timely manner.
Please if you want a new feature in Parse, Tell them! The more requests they get, the faster they implement certain features. Send them an email at<EMAIL_ADDRESS>IMPORTANT: This module is unofficial and is not maintained by parse.com
Copyright(c) 2011 by Forge42.
Please see the LICENSE file included in the distribution for further details.


Vagrant test project works
You can find source codes on the vagrant machine at /vagrant/projects/test/index.html


Back Control From HalfGuard
Frame up with left arm, grab ops right hand with your right hand, get the underhook, grab the belt, move opponent forward to assist with getting out
from under their right arm (use left knee to assist in moving them if required) left arm loops around to grab lapel of opponent, head and chest are getting
in tight to ops right shoulder, use a straight left leg and the lapel to generate momentum and move opponent and yourself 180 deg, so the floors on your back and
opponent is ontop of you, if you can't get the other hook in, figure 4 your legs and deadlift to open opponent up, get the hook in.


Jaime Latre, who rowed with Messi, to ref Leganes v Barca
The Catalans have been handed the list of officials for the coming weekend
by German BonaThe RFEF have published their refereeing appointments for the weekend - week 14 of La Liga - the first after the international break.
Santiago Jaime Latre is taking charge of Barcelona's trip to face Leganes at Butarque on Saturday, 1pm. The VAR ref will be Mario Melero López.
Latre has reffed Barca 10 times, they have won eight and drawn two. However he fell out with Lionel Messi last time out, in a 1-1 draw against Athletic at Camp Nou. The cameras captured Messi saying "you're threatening me, you're threatening me, always the same with you, always the same," to the official.
Messi came on off the bench in that game and criticised the officials for their leniency towards Athletic players and for a corner not given.
That wasn't the first time Messi had problems with Latre. In 16-17, a 2-1 win at Sevilla, Messi was booked for tying his shoelace on the pitch, in a surreal incident that the referee deemed timewasting. Barca appealed the card.


Please read the documentation at docs.aspose.com/display/wordsnet/LINQ+Reporting+Engine+API
For quick testing, please create a new Table in the document and add the data according to the following table.
ProductName Price Description Laptop 1200.00 MSI GP Series GP63 Leopard-428 15.6in Keyboard 25.00 Logitech K400 Plus Wireless Touch Keyboard Mouse 15.00 Logitech M325 RF Wireless Optical 1000 LED Monitor 300.00 LG 34UB67-B Black 34in 21:9 Ultra wide
Save this file as Data.docx and upload it as data source.
Set Table Index: 0
Set Data Source Name: products


BLOG INDEX PAGE
| 26 | |
| OCT | |
| 2014 | Website Rework |
|
This is my second pass at designing this site. The changes I made this time were mostly cosmetic. I think it looks more polished now. I'm happy with the color scheme and the background image on the index page. read more... |
| 24 | |
| OCT | |
| 2014 | Learning how to ask Technical Questions |
|
In this week's post, I'll address the art of asking technical questions. The first step in finding the answer to a question is figuring out if you even have to ask the question at all. Has it already been answered? Use Google to look for reference material, blog posts, or forum posts that might address your question. If you're getting an error message, Google the error message itself. read more... |
| 16 | |
| OCT | |
| 2014 | Dealing with Conflict |
|
When I was living in France, I lived in an apartment that was not in very good shape, even by French standards. The bathroom was particularly bad. The toilet would wobble every time we sat down on it (because we were fat, according to our landlady), and some previous tenant had sealed off gaps between the wall and the pipes but stuffing socks into them. In the 3.5 years that we lived in Paris, we were never in a position to move. My landlady, while not fundamentally a bad person, was very busy, and was out of the city most of the time. She also seemed to have a blind spot as far as the state of the apartment was concerned. read more... |
| 16 | |
| OCT | |
| 2014 | An Overview of Regular Expressions |
|
This week we're being asked to write about one of the technical topics that we haven't covered in Phase 0. One of the suggestions was Regular Expressions, and since it's been on my list of things I want to learn about for some time now, that's the topic I'll cover in this week's technical blog. read more... |
| 08 | |
| OCT | |
| 2014 | Personal Values and Stereotype Threat |
|
It's hard to select just one or two values from the list we were given. I consider will-power an important value, especially right now as I prepare to start the on-site part of DBC. Will-power is the means by which I force myself to do things that are unappealing in the moment but that are ultimately beneficial to me or to the people I care about. read more... |
| 08 | |
| OCT | |
| 2014 | A Comparison Between SQL and noSQL Databases |
|
This week we're being asked to write an overview of the differences between SQL and noSQL databases, as well as to examine the advantages and disadvantages of each model. read more... |
| 03 | |
| OCT | |
| 2014 | Stereotype Threat |
|
This week, we're being asked to write about stereotype threat. My first reaction when I started researching this topic was that it was going to be really hard to time box the assignment to an hour, and my second reaction was that it would be really difficult to write about it at all. read more... |
| 03 | |
| OCT | |
| 2014 | Blocks and Procs and Lambdas - Oh My! |
|
This week I'll provide a quick but hopefully informational overview about Blocs, Procs, and Lambdas, and how they are useful in Ruby. All three of these are ways of grouping code together to use as a unit. Another name for this is Closures. read more... |
| 28 | |
| SEP | |
| 2014 | Pairing and Feedback at DBC |
|
At the beginning of DBC, the combination of my lack of confidence in my technical ability and my feeling of social awkwardness made me dread pairing. Over the past five weeks, it has mostly become a good experience. I don't know if I will ever totally be in my comfort zone while pairing, especially remotely. However, it has gotten a lot easier with practice. read more... |
| 28 | |
| SEP | |
| 2014 | Working with Classes in Ruby |
|
For this post, I'll use technical design for apparel as my the real world example of building a class in Ruby. Of course, this is a very simplified example. Let's say that I want to have a shirt produced in a factory. I have to provide exact instructions to the machine operator. It is not his or her job to make judgement calls about what the shirt looks like or how it should be constructed. read more... |
| 18 | |
| SEP | |
| 2014 | Technology Industry Problem: Worker Shortage and Training |
|
One of the biggest problems facing the technology industry today is the lack of skilled workers. At the same time, a large segment of the workforce is still unemployed or underemployed due to obsolete skill sets. read more... |
| 18 | |
| SEP | |
| 2014 | Using the Inject Method |
|
The inject method in Ruby is commonly used as a way to accumulate a collection of objects. Given a set of objects, it will iterate over each one, executing whatever code is specified, and return a result. Inject is useful for dealing with collections of objects, such as strings, arrays, and hashes. Let's have a look at the format, and then I will go over some possible use cases. read more... |
| 14 | |
| SEP | |
| 2014 | An Exploration of my Gregorc Learning Style |
|
My thinking style is Concrete Sequential. For better and for worse, I think that the CS description is an accurate reflection of the way I currently think and learn. As a concrete thinker, I take in information based on direct observation – what I see in front of me. I am also a linear thinker, which means that I learn better when I have an outline or plan to work from. read more... |
| 14 | |
| SEP | |
| 2014 | All About JavaScript |
|
Javascript's popularity stems from the fact that is able to be interpreted by most browsers without any action on the part of the user. From the perspective of a web developer, JavaScript is lightweight and easy to use. The code can be written in any text editor, and it is immediately ready to be tested and deployed without having to be compiled. read more... |
| 07 | |
| SEP | |
| 2014 | Working with Margin, Border, and Padding in CSS |
|
Margins, borders, and padding are all ways to create white space and create visual boundaries between elements on a web page. It's important to remember that all three of these all take up space on the page. When you're trying to determine the width of the various elements on your page, you must take this into account and adjust the widths of the parent elements accordingly. read more... |
| 31 | |
| AUG | |
| 2014 | Software Development is a Team Sport |
|
Before watching the chat, I did not realize how large a role collaboration would play in the experience. Now, I'm realizing that learning to work technically with other people is going to be a big part of DBC. I'm looking forward to it, but also apprehensive. Learning not to feel insecure and compare myself to other people will be a challenge. What Shereef said about imposter syndrome definitely holds true for me. read more... |
| 31 | |
| AUG | |
| 2014 | Technical Blog 1 - Website Comparison |
|
I have been using this site every day for several months, because I'm sick of my music collection on iTunes, and to expose myself to different types of music. I splurged and got the subscription service, which is worth it to me since I have it on constantly. The focal point of the site is the area where the track information is displayed. The name of the track and the album art take up most of the real estate in the center of the page, which I would expect since I go there to listen to tracks. Visually, I'd describe the site as minimalist, utilitarian, modular, neutral, and boxy. It isn't badly designed but it's very simple and focused; there isn't a lot of extraneous content visible at the top level. read more... |


Jashlabs is a digital agency built in Ontario, Canada. We are a small team of passionalte people who love the web.
We offer a wide range of services ranging from website design to hybrid mobile app development which can help you go from a startup idea to a market ready product within a few weeks.
Got an idea that’s worth bringing to life? We can help you translate your vision into a digital experience.
We love creating reliable, self documenting and scalable codebases that run fast. We use the latest techonolgies and frameworks
We can create hybrid mobile applications that can run on both android and iOS phones
We've had the priviledge of working with wonderful clients. Here are some of the things we've built for them.
Brian and Paul worked with us yet again for a product that helps thousands of drivers to ace their DMV written tests. We created a website and mobile apps for both Android and iOS.
“We worked with Jashlabs to help build our backend services for DirtyDish. They took the time to really understand our business goals and customer journeys, which helped guide architectural decisions that would deliver optimal user experiences. The end product was nothing short of remarkable. You have a trusted partner in Jashlabs.”


FROZEN (Jidu hanleng) (director/writer: Wang Xiaoshuai; screenwriter: Ming Pang; cinematographer: Yang Shu; editor: Qing Qing; cast: Jia Hongshen (Qi Lei), Ma Xiaoqing (Shao Yun), Bai Yu (Sister), Li Geng (Sister's Husband), Bai Yefu (Bald Guy), Wei Ye (Longhaired Guy), Zhang Yongning (Lau Ling), 1996-China)
Reviewed by Dennis Schwartz
Frozen is an independently produced Chinese film, made during 1994, and it reflects the pessimism the artist community of the post-Tiananmen Square generation felt about the materialistic Communist regime and how the regime stifles free expression. It is a call for artistic freedom, but interestingly enough, this political film shies away from offering any significant political commentary. The director, Wang Xiaoshuai, clashed with the Chinese authorities over the film, since filmmakers in China must go through official channels. He finally took the film secretly to Amsterdam to get it released and took the pseudonym Wu Ming, meaning `No Name.'There is a coldness about this film that prevents it from being a true emotional experience rather than an intellectual response to what the students and avant-garde community in Beijing were feeling at the time.
The story is told in flashback style, of a laconic, stoic, young depressed student, Qi Lei (Jia Hongshen), who is a performance artist and decides that at the beginning of each of the four seasons, to perform a symbolical death ritual, which will culminate in his actual suicide. He starts with a self-burial in the autumn, a water burial for the winter, a burning for the spring, and for the summer, he plans to go through with his actual death, in the form of an ice burial.
It is very difficult to feel anything but regret for his plan of a slow suicide, a martyrdom for the cause, to show how repressive the Communist system is and how tired he is of living. His plan is to use himself as a concept for others to rally around his cause.  Only Qi Leng's mentor, the art critic Lau Ling (Zhang Yongning) -- Shao Yun's ex-lover -- seems to approve of what Qi is doing.
The film opens at a posthumous exhibition of Qi Lei's art work, where the attendance is good for the first day, but interest in his death soon wanes. He will be shown communicating with the other students and performance artists, who either do not act favorably to his plan or remain quiet. A performance artist eats a bar of soap with a knife and fork and is revolted by what he eats, almost as much as the audience is revolted by seeing him go through that routine. A fortune teller mysteriously mentions that he will be reborn, that one life leads to another. His friend, Longhair Guy, thinks he might be having mental problems and brings him to a mental-health clinic so he can be dissuaded from committing suicide, but a mistake in identity occurs and the doctor takes him for the patient, Qi Lei. This was a hard scene to swallow as not being a contrived one and a very forced metaphor on the political situation, though it provided some much needed levity rather than any particular increase in political insights.
The last 20 minutes of the film offers a surprise twist to the story and thereby saves it somewhat from the doldrums it was in. It results in a film that gets its message across that freedom is frozen in China, that things are still far from democratic. It was a though-provoking film, but in a very manipulative way, that was none too pleasing to view despite its good intentions.
REVIEWED ON 5/30/2000 GRADE: C-
Dennis Schwartz: "Ozus' World Movie Reviews"
http://www.sover.net/~ozus
<EMAIL_ADDRESS>© ALL RIGHTS RESERVED DENNIS SCHWARTZ
The review above was posted to the
rec.arts.movies.reviews newsgroup (de.rec.film.kritiken for German reviews).
The Internet Movie Database accepts no responsibility for the contents of the
review and has no editorial control. Unless stated otherwise, the copyright
belongs to the author.
Please direct comments/criticisms of the review to relevant newsgroups.
Broken URLs inthe reviews are the responsibility of the author.
The formatting of the review is likely to differ from the original due
to ASCII to HTML conversion.
Related links: index of all rec.arts.movies.reviews reviews


I study Computer Engineering at the University of Waterloo. I'm passionate about bringing innovative and fun ideas to life and driven to keep challenging myself. My interests are Distributed Computing, Trading, Painting, Squash and Travel.
 A simple life.


About: Astriarch - Ruler of the Stars
Astriarch - Ruler of the Stars is a Turn-based, Single Player Space Strategy Game. Build planetary improvements and star ships to capture planets and defeat your enemies. Your ultimate goal is to become the master of the known universe, and earn the title of Astriarch!
Developed in 2010 by Mastered Software, Astriarch combines aspects of other classic space strategy games such as Master of Orion 2 (MOO2), Stellar Conflict (1987 Amiga), and Star Control.
Astriarch is a free casual web game. The game will continue to be improved to increase playability and maximize fun while still staying simple and easy to learn.
The name Astriarch comes from the Ancient Greek words for star (ástron) and ruler (arkhos).
Astriarch - Ruler of the Stars, space strategy game designed and developed by Mastered Software, music by Resonant. Astriarch uses Stratiscape JavaScript Canvas Library and the jQuery Listbox plugin.
Astriarch source code has been released on GitHub. The open source code is intended to provide an example of how to create a turn-based strategy game in using HTML5, JavaScript and NodeJS.


{{ 'workflow_from_template' | translate}}
{{workflow.from_template}}
Your workflow was not generated from a template.
A workflow template allows you to quickly create then update a workflow and its components.
You can init a new template from current workflow.
Your workflow was not imported from your code.
Manage your workflow as code from your repository to automatically update it with changes on your branches.


STM expression mechanical boundary meristem Figure signal auxin pSTM::CFP-N stress shoot gene pBOUND>>GFP signals induction ablation Plant meristems plants observed organ arabidopsis cell tissue using activity folding apical curvature line stm-dgh Traas control correlation formation boundaries growth induced Biology Scale development genes Heisler performed supplement {border-style —figure Cell KNOX cells pSTM::STM-Venus pattern promoter role level plant presence px;} response #ffffff;} Arabidopsis DII-Venus Hamant NPA boundary. described Development Note PIN grown intensity Aida CFP Vernoux domain generated http://dx.doi.org/./eLife.. lines Nature increase meristem, surface Gaussian Representative ablations fusion local measured shown size time Current compression expressing mutant perturbations previously site strong transport CUC GFP Uyttewaal boundary, cytokinin data depletion different growing impact new pin- regulation sections test used Laufs Mechanical SAM Video area biochemical bot- function involved isoxaben jasmonate meristem. morphogenesis overnight shape treatment water (e.g. Interestingly, SAM. analyzed angle cm. compared consistent correlated data, help induce organs protein proteins representative required separation showing work µm. ./dev. ./j.cub... Boudaoud Contributed DII-Venus-N KNAT associated bar, bars, crease detected does expressed forces http://dx.doi.org/./ identity increased nucleus px; remains stresses suggests transcriptional unpublished vitro {font-family ./j.-X...x B). Brunoud Developmental FM- Grandjean Landrein PID Physiology Research Sciences Wang act analysis axillary conditions conditions, contribution early embryo essential ethanol font-size generate higher independent line, marker mechanotransduction medium meristems. microtubule molecular obtained parallel regulatory stem suggesting Analysis Godin Hay Lyon Meyerowitz Morin PINOID Reuille [], amiRNA apex application class confirm detect dissected distribution double; eLife expression. following homeobox investigated lapse leaf leaves levels meristems, middle network organogenesis pPID>>GFP particular, pathway pathways patterns perturbations. phenotype polarity presented promotes region results robustness scenario signaling similar transcription translational treatments upstream > (ATG) (relates ./nature A). ANR--BLAN- Agence Based Council European ImageJ Isoxaben Jan Kwiatkowska Long Nationale Olivier Recherche Reinhardt Rozier STMamiRNA Science Student Tasaka background border-color border-width boundaries, called check contrast correlates cytokinins delay differential drosophila enhanced ethylene evidence experiments extent functions high initiation instance, interpretation largely lateral leading leads lines, long meristematic mesh method mount naked negative old orthogonal pJAZ::GUS pSTM::STMamiRNA points polar question reagents. reduction related relatively revealed signalling situ solid; stained stm successive suggest supplemented tension thaliana treatment, uncoupled {font-style {font-weight μm. (upper ,-D ./pp.. ./tpc.. Acquisition Belles-Boix Besnard Brunet Conversely, Experimental First, France Furthermore, Furutani However, Imaging Jaalouk Janmey K). Kim Landsberg MERISTEMLESS Material Mirabet Molecular Nakayama Orr PIN-FORMED SHOOT STM-Venus Sassi Time Tsiantis University ablations, absence allele background, bar biological bold bot-: cause central contribute controls cotyledon courier; das design, development. developmental diluted direction effect elements em; embryos emergence expression, factors flowers form gibberellin gibberellins homeodomain hormone hypothesis, identified imaging immersion incubation independently inflorescence inhibitor involve laser line. lines. longitudinal mRNA maximal mediated optical pCUC::CFP pCUC::CUC-GFP pPID::CFP-N panel) partly patterning pin plants, play possibility primer primordium promote protocol provide pt;} recovering red reduced regulates regulator relation reporter responses root signals, signals. software solution stages stress. sufficient table test. this, transduction transferred trigger well-known words, wound zone


16 found sealed in trailer on ferry bound for Ireland
DUBLIN, Nov 21 — Sixteen people have been found sealed inside a trailer on a ferry bound for the Irish port of Rosslare, shipping operator Stena Line said today.
The discovery draws renewed attention to the issue of illegal immigration and human trafficking in western Europe, after 39 Vietnamese were found dead in a trailer in Britain last month.
And on Tuesday, the crew of a cargo ferry run by DFDS Seaways found 25 migrants in a refrigerated container on a boat sailing to Britain and forced the vessel to return to port.
The 16 individuals in the latest discovery were found aboard a night sailing of the Stena Horizon ship from Cherbourg in northern France yesterday.
“One of our employees during a routine inspection discovered 16 people in a sealed trailer on the vehicle deck,” Stena Line chief communications officer Ian Hampton said in a statement.
“All the individuals are reported to be in good health and have been moved to a private passenger lounge on the ship.”
The ship was due to arrive in port mid-afternoon today, according to the firm, and immigration and security officials have been alerted to meet them.
There was no immediate comment from Irish police or indications of the people’s nationalities.
Meanwhile in Dublin, a man being held for alleged participation in the British case involving the 39 Vietnamese victims appeared in court for an extradition hearing.
Eamon Harrison is alleged to have delivered the trailer in which the 39 victims were found dead to Zeebrugge in Belgium before it travelled on to a port in south-east England.
He faces 39 charges of manslaughter, one count of conspiracy to commit human trafficking and one count of conspiracy to assist in unlawful immigration.
The case was adjourned until another hearing on December 12. — AFP


Please type the first and last name of the person you are looking for.
Please type the first and last name of the person whose descendants you are looking for.
Please type the first and last name of the person you are looking for.
Please type the first and last name of the person you are looking for.
Enter the characteristics of the person you want to search for.


[t]Dear {$customerName|escape},[/t]
[uts:_logo]
[t]The vacancy with id #{$vid} has been published by {$name}.[/t]


The overall goal of the assignment is to:
The functional goal of the assignment is to:
Note that this assignment was written so that you can implement it in parts after each lecture. If you are performing the assignment in between lectures, stop at the next lecture boundary in the technical requirements section and resume once you have completed the lecture. You are free to experiment with other forms of the queries presented, but the grading will only be targeted at the specific requirements listed.
Start your MongoDB server using mongod
Download and extract the starter set of files. The root directory of this starter set will be referred to as the root directory of your solution.
--- student-start
|-- assignment.rb
|-- race_results.json
|-- .rspec (important hidden file)
`-- spec
|-- lecture1_spec.rb
|-- lecture2_spec.rb
|-- lecture3_spec.rb
|-- lecture4_spec.rb
|-- lecture5_spec.rb
`-- spec_helper.rb
Install the following gems. You may already have them installed.
$ gem install rspec
$ gem install rspec-its
$ gem install mongo -v 2.1.2
Run the rspec command from the project root directory (i.e., student-start
directory) to execute the unit tests within the spec directory. This should result in several failures until you complete your solution in assignment.rb
.
$ rspec
(N) examples, (N) failures, (N) pending
...
Implement the Ruby technical requirements in assignment.rb
within the provided class Solution
. Helper methods have been provided to get a connection to Mongo and to set the database and collection names. You can override these values using environment variables if you are not using the defaults. Since you are not turning in this assignment -- you may also simply edit the defaults used within the source file. However, the defaults used are as follows:
MONGO_URL='mongodb://localhost:27017'
MONGO_DATABASE='test'
RACE_COLLECTION='race1'
You can load the assignment.rb
script into the irb
shell and take advantage of the helper methods of the Solution
class to try out commands in the shell before adding them to the assignment solution.
$ irb
> require './assignment.rb'
=> true
> racers=Solution.collection
=> #<Mongo::Collection:0x8262360 namespace=test.race1>
> racers.find.count
=> 1000
Implement all methods relative to the @coll
instance variable setup to reference the collection.
As you implement each requirement, the following is provided to help familiarize you with the schema associated with a race document:
{"_id"=>BSON::ObjectId('564c01c886c12c3d3d0003ca'),
"number"=>970,
"first_name"=>"LONNIE",
"last_name"=>"FITZGERALD",
"gender"=>"F",
"group"=>"14 and under",
"secs"=>2258}
In this section we will use delete_many
, insert_many
, and insert_one
to implement and test different create metthods.
clear_collection
that:
delete_many
)You can demonstrate your method using the irb
shell.
> Solution.collection.insert_one({})
=> #<Mongo::Operation::Result:22500120 documents=[{"ok"=>1, "n"=>1}]>
> s=Solution.new
> r=s.clear_collection
=> #<Mongo::Operation::Result:22249400 documents=[{"ok"=>1, "n"=>1}]>
> r.ok?
=> true
> r.deleted_count
=> 1
$rspec spec/lecture1_spec.rb -e rq01
load_collection
that:
load_hash()
method provided in the bootstrap assignment.rb
for this.insert_many
)You can demonstrate your method using the irb
shell.
> r=s.load_collection('./race_results.json')
> r.inserted_count
=> 1000
> r.inserted_ids.slice(0,2)
=> [BSON::ObjectId('5663a565e301d093ac0003eb'), BSON::ObjectId('5663a565e301d093ac0003ec')]
$rspec spec/lecture1_spec.rb -e rq02
insert
that:
insert_one
)You can demonstrate your method using the irb
shell.
> r=s.insert({:foo=>"bar"})
=> #<Mongo::Operation::Result:18276240 documents=[{"ok"=>1, "n"=>1}]>
> r.inserted_ids
=> [BSON::ObjectId('5663a66fe301d093ac0007d3')]
2.2.2 :052 > r.returned_count
=> 1
$rspec spec/lecture1_spec.rb -e rq03
In this section we will locate documents in a collection based on the AND'ing of extact-matching parameters acting as prototype
documents. We will also begin to shape the returned document(s) with the use of projection
.
all
that:
find
)You can demonstrate your method using the irb
shell.
> s.all(:first_name=>"MARY").first
=> {"_id"=>BSON::ObjectId('5663a755e301d099140003d0'), "number"=>975, "first_name"=>"MARY",
"last_name"=>"RODGERS", "gender"=>"M", "group"=>"30 to 39", "secs"=>3025}
$rspec spec/lecture2_spec.rb -e rq01
find_by_name
that:
find
)first_name
, last_name
, and number
properties (hint: projection
You can demonstrate your method using the irb
shell.
> s.find_by_name("MARY", "RODGERS").first
=> {"number"=>975, "first_name"=>"MARY", "last_name"=>"RODGERS"}
$rspec spec/lecture2_spec.rb -e rq02
In this section we will get some practice bounding method results based on sorting and paging commands.
find_group_results
that
group
name, offset
value, and limit
valuegroup
group
and _id
fields from the results (hint: projection
)secs
), accending (hint: sort
)offset
documents in the ordered result (hint: skip
)limit
documents (hint: limit
)You can demonstrate your method using the irb
shell.
> r=s.find_group_results("30 to 39", 1, 2)
> r.to_a.count
=> 2
> r.to_a
=> [{"number"=>248, "first_name"=>"MARTIN", "last_name"=>"RAMOS", "gender"=>"M", "secs"=>1263},
{"number"=>320, "first_name"=>"TWILA", "last_name"=>"TUCKER", "gender"=>"F", "secs"=>1270}]
> r.selector
=> {:group=>"30 to 39"}
> r.count
=> 129
$rspec spec/lecture3_spec.rb
In this section we will find documents based on a comparison that does not involve equality.
Hint: Review the Mongo Query and Projection Operators
find_between
that
min
and max
valuesecs
) that is between min
and max
(exclusive).You can demonstrate your method using the irb
shell.
> r=s.find_between(1600,1615)
> r.to_a.count
=> 2
> r.to_a
=> [{..."first_name"=>"MEGAN", "last_name"=>"ANDERSON"... "secs"=>1605},
{..."first_name"=>"KELI", "last_name"=>"SIMPSON"... "secs"=>1606}]
$rspec spec/lecture4_spec.rb -e rq01
find_by_letter
that
letter
, offset
, and limit
letter
provided using a regular expression. You only need to treat letter
as a string and do not have to enforce as a character. However, you should convert this value to upper case. The following REGEX "^S.+"
will locate all names starting with the letter S
.last_name
, ascendingoffset
documentslimit
documentsYou can demonstrate your method using the irb
shell.
r=s.find_by_letter("sal",0,1).first
=> {..."first_name"=>"LOURIE", "last_name"=>"SALAZAR"...}
$rspec spec/lecture4_spec.rb -e rq02
In this section we will modify the database.
update_racer
that
_id
property in the input hashreplace_one
)You can demonstrate your method using the irb
shell.
> r1=s.all.first
=> {"_id"=>..., "number"=>0, "first_name"=>"SHAUN", "last_name"=>"JOHNSON" ...
> r1[:first_name]="foo"; r1[:last_name]="bar"
> r1
=> {"_id"=>..., "number"=>0, "first_name"=>"foo", "last_name"=>"bar" ...
> r=s.update_racer(r1)
=> #<Mongo::Operation::Result:28472340 documents=[{"ok"=>1, "nModified"=>1, "n"=>1}]>
> r.modified_count
=> 1
$rspec spec/lecture5_spec.rb -e rq01
add_time
that
:$inc
)You can demonstrate your method using the irb
shell.
r1=s.all.to_a.sample
=> {"_id"=>BSON::ObjectId('5663a754e301d09914000054'), "number"=>83, ... "secs"=>3146}
> r=s.add_time(r1[:number], 1000)
=> #<Mongo::Operation::Result:23028380 documents=[{"ok"=>1, "nModified"=>1, "n"=>1}]>
> s.all(:number=>r1[:number]).first[:secs]
=> 4146
$rspec spec/lecture5_spec.rb -e rq02
Unit tests have been provided in the bootstrap files that can be used to evaluate your solution. They must be run from the same directory as your solution.
$ rspec
........
(N) examples, 0 failures
There is no submission required for this assignment but the skills learned will be part of a follow-on assignment so please complete this to the requirements of the unit test.


Growing up in the small town of Colville Washington, there was never a ton of opportunities to pursue art. I always loved creating things, but it was not until later on in high school, and in college, that I really got involved with design. I love coming up with ideas for projects, and working with my hands. In the future I hope to explore more with photography and video. Other than art I enjoy dancing, hiking, mountain biking, camping, swimming, and skiing.
| Education | Expirience | Skill Set | Software |
|---|---|---|---|
| Colville High School | Hills Resort Server | Image Composition | Photoshop |
| EWU | Evergreen Apartments | Logo Design | Illustrator |
| Colville Sign Co | Editing | Indesign | |
| Layout | Github | ||
| Painting | Codepen |


PODS¶
PODS (Parallel Optimization with Dynamic coordinate search using Surrogates) is a parallel surrogate-based algorithm for optimization of HEB (High-dimensional, Expensive, and Black-box) problems. PODS is an expansion of serial DYCORS and incorporated the Surrogate-Distance Metric for selecting of multiple evaluation points in each iteration, which is required to implement an algorithm in parallel.
The synchronous parallelization with multiprocessing python model is implementited in PODS.
| [1] | D. Eriksson, D. Bindel, and C. Shoemaker. Surrogate Optimization Toolbox (pySOT). github.com/dme65/pySOT, 2015 . |
| [2] | Rommel G Regis and Christine A Shoemaker. Combining radial basis function surrogates and dynamic coordinate search in high-dimensional expensive black-box optimization. Engineering Optimization, 45(5): 529–555, 2013. |
| [3] | Rommel G Regis and Christine A Shoemaker. Parallel stochastic global optimization using radial basis functions. INFORMS Journal on Computing, 21(3):411–426, 2009. |


self._eval_aux_ops()
self.cleanup_parameterized_circuits()
return self._ret
// This is the objective function to be passed to the optimizer that is used for evaluation
def _energy_evaluation(self, parameters):
Raises:
AquaError: wrong setting of operator and backend.
if self.operator is None:
raise AquaError("Operator was never provided")
if self.quantum_instance is None:
raise AquaError("Quantum Instance was never provided")
self._operator = self.operator


Event details
Medication Name
Dosage
Time
Notification Type
Vibrate
Silent
Sound
Vibrate and Sound
Days per week
Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Reminders
minutes before
hours before
days before
weeks before
Color
Create Medication Reminder
Cancel


{% extends 'shop/base.html' %} {% block content %}
You put {{product.quantity }} of our {{ product.name }} which costs {{ product.price }} in your basket.
The total for all of this fun is: {{ total}}
Buy one for yourself