Propchange: incubator/shindig/trunk/php/js/People.js
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/shindig/trunk/php/js/ShindigContainer.js
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/js/ShindigContainer.js?rev=606463&view=auto
==============================================================================
--- incubator/shindig/trunk/php/js/ShindigContainer.js (added)
+++ incubator/shindig/trunk/php/js/ShindigContainer.js Sat Dec 22 08:11:57 2007
@@ -0,0 +1,589 @@
+/**
+* @constructor
+*/
+opensocial.ShindigContainer = function() {
+       opensocial.Container.call(this);
+};
+opensocial.ShindigContainer.inherits(opensocial.Container);
+
+Array.prototype.each = function(fun) {
+       for (var cnt=0; cnt<this.length; cnt++) {
+               fun(this[cnt]);
+       };
+};
+/**
+* Initialize the container with the specified state.
+*
+* @param {Object} viewer Person object that corresponds to the viewer.
+* @param {Object} opt_owner Person object that corresponds to the owner.
+* @param {Map<String, String>} opt_friends A map of friends of the viewer,
+* keyed by their Id.
+* @param {Array<Object>} opt_activities An array of activity objects.
+* @param  {Map<String, String>} opt_nonFriends A map of contacts who are
+* not friends.
+*/
+opensocial.ShindigContainer.prototype.init = function(appName) {
+       /*
+       if (appName = '/46/o') {
+       this.appName = hashAppName;
+       }
+       else {
+       this.appName = appName;
+       }
+       */
+       if (this.containerInitialized) {
+               return;
+       }
+       this.containerInitialized = true;
+
+
+
+       this.appName = hashAppName;
+
+
+       this.viewerFriends = {};
+       this.viewerActivities = {};
+       this.ownerActivities = {};
+       this.ownerFriends ={};
+
+       //the framework calls this function passing a URL from which to load 
the data?
+       //looks like the   google.opensocial.Container.get().init("/46/o");    
call ends up passing the /46/o as viewer...
+       //interesting -- for us the person that embedded the object is hard to 
ascertain, while for social networks profile pages
+       //are a first-class concept... it's going to be tricky to map this in a 
non-fragile way
+       //each widget will have to track who inserted it
+       this.owner = xnGetOwner();
+       //TODO load the profile that owns the gadget I'm looking at...
+       this.viewer = xnGetViewer();
+
+       if (xnGetViewerFriends().contacts && 
xnGetViewerFriends().contacts.values) {
+               var contactsArr = xnGetViewerFriends().contacts.values;
+               var resultArr = new Array();
+               for (var i = 0; i < contactsArr.length; i++) {
+                       fObj = contactsArr[i];
+                       //todo load the app data
+                       resultArr[resultArr.length] = new 
opensocial.ShindigPerson(fObj.id, fObj.name, '', fObj.photoUrl, '', new 
Array(),'');
+               }
+               this.viewerFriends = resultArr;
+               //console.log('viewerFriends ' + resultArr.length);
+               //console.log('viewerFriendsx ' + contactsArr);
+       }
+       if (xnGetOwnerFriends().contacts && 
xnGetOwnerFriends().contacts.values) {
+               var contacts2Arr = xnGetOwnerFriends().contacts.values;
+               var result2Arr = new Array();
+               for (var i = 0; i < contacts2Arr.length; i++) {
+                       fObj = contacts2Arr[i];
+                       //todo load the app data
+                       result2Arr[result2Arr.length] = new 
opensocial.ShindigPerson(fObj.id, fObj.name, '', fObj.photoUrl, '', new 
Array(),'');
+               }
+               this.ownerFriends = result2Arr;
+       }
+       this.containerInitialized = true;
+       this.globalAppData = {};
+       this.instanceAppData = {};
+
+       this.owner.appData = preloadedUserData;
+       this.viewer.appData = preloadedViewerData;
+
+       this.activities = new Array();
+
+
+};
+opensocial.ShindigContainer.prototype.getAppName = function() {
+       return this.appName;
+};
+
+opensocial.ShindigContainer.prototype.isContainerInitialized = function() {
+       return this.containerInitialized;
+}
+opensocial.ShindigContainer.prototype.internalLoadAppData = function(person, 
callback) {
+       if (person) {
+               onSuccess = function(evaldObj) {
+                       //this.appData = evaldObj;//console.log('success!');
+                       //console.log('obj=');
+                       //console.log(evaldObj);
+                       //console.log('nummsg=' + evaldObj["numMessages"]);
+                       person.appData = evaldObj;
+                       //console.log(person.getAppField("numMessages"));
+                       person.isAppDataLoaded = true;
+                       callback();
+               };
+               onError = function(context, msg) {
+                       console.log('error = ' + msg);
+               };
+               var handlers = {
+                       success: onSuccess,
+                       failure: onError
+               };
+               //var form = new Array();
+               content = {'user':  person.id, 'op':'get-app-data', 'app': 
this.appName, 'xark': Shindig._.os.xark, 'origin': Shindig._.os.origin};
+               Shindig.api.post("/gadgets/index/api", content, handlers);
+       }
+};
+
+/**
+* Deprecated.
+*/
+opensocial.ShindigContainer.prototype.requestInstallApp = function(appUrl,
+opt_onSuccess, opt_onFailure) {
+       opt_onSuccess();
+};
+
+/**
+* Deprecated.
+*/
+opensocial.ShindigContainer.prototype.requestUninstallApp = function(appUrl,
+opt_onSuccess, opt_onFailure) {
+       opt_onSuccess();
+};
+
+/**
+* Make the specified person as friend by moving them from the nonFriends
+* list to the friends list.
+*
+* @param {String} id The id associated with the person to be made a friend.
+* @param {Function} opt_onSuccess The callback method on successful completion.
+* @param {Function} opt_onFailure The callback method on failure.
+*/
+opensocial.ShindigContainer.prototype.requestMakePersonAFriend = function(id,
+onSuccess, onError) {
+       if (!Shindig.CurrentProfile) {
+               alert("signin", "You must sign in to make someone your 
friend.");
+               return false;
+       }
+       if (Shindig.CurrentProfile.id.toLowerCase() == friendId.toLowerCase()) {
+               alert("You can't be your own friend!");
+               return false;
+       }
+       onSuccess = onSuccess || function() {
+               alert("Friend request sent!");
+       };
+       onError = onError || function(msg) {
+               if (msg == "Sorry, that person has blocked you") {
+                       // hide blocking from user
+                       onSuccess();
+               }
+               else {
+                       alert("make person friend error: " + msg);
+               }
+       };
+       Shindig.social.sendFriendRequest(friendId, {
+               success: onSuccess,
+               error: onError
+       });
+       return false;
+};
+
+opensocial.ShindigContainer.prototype.requestCreateActivity = 
function(activity,
+priority, opt_callback) {
+       // TODO(doll): We need to include simulating opeShindig a user dialog 
if the
+       // stream does not exist. The templates should also be translated at 
this
+       // point.
+       this.activities.push(activity);
+       if (opt_callback) {
+               opt_callback();
+       }
+};
+
+/**
+* Make the specified person as nonfriend by moving them from the friends
+* list to the nonFriends list.
+*
+* @param {String} id The id associated with the person to be removed
+* as a friend.
+* @param {Function} opt_onSuccess The callback method on successful completion.
+* @param {Function} opt_onFailure The callback method on failure.
+*/
+opensocial.ShindigContainer.prototype.requestMakePersonNotAFriend = 
function(id, opt_onSuccess, opt_onFailure) {
+
+       var url =  
dojo.string.substituteParams("/xn/rest/1.0/profile:%{id}/contact?xn_method=PUT",
 {
+               id: Shindig.CurrentProfile.id
+       });
+
+       var handlers = {
+               success: opt_onSuccess,
+               failure: opt_onFailure
+       };
+
+       context = null;
+       var post_data = {
+               contact_relationship: "not-friend",
+               contact_id: profileId
+       };
+
+       Shindig.api.post(url, post_data, handlers, context);
+
+};
+
+/**
+* This method returns the data requested about the viewer and his/her friends.
+* Since this is an in memory container, it is merely returShindig the member
+* variables. In a real world container, this would involve making an ajax
+* request to fetch the values from the server.
+*
+* @param {Object} dataRequest The object that specifies the data requested.
+* @param {Function} callback The callback method on completion.
+*/
+opensocial.ShindigContainer.prototype.requestData = function(dataRequest, 
callback) {
+
+       var myself = this;
+       /*
+       if (!this.owner.isDataLoaded()) {
+       console.log('calling load data for owner');
+       this.internalLoadAppData(this.owner, function() 
{myself.requestData(dataRequest, callback);} );
+       return;
+       }
+       if (!this.viewer.isDataLoaded()) {
+       console.log('calling load data for current profile');
+       this.internalLoadAppData(this.viewer, function() 
{myself.requestData(dataRequest, callback);} );
+       return;
+       }
+       */
+
+       //TODO the requests right now include "BogusAppname" clearly a 
placeholder... wouldn't it be better to specify
+       //the appID/name in the init() like I'm doing?
+
+       var requestObjects = dataRequest.getRequestObjects();
+       //var appName = dataRequest['AppName'];
+       var dataResponseValues = {};
+       //TODO for lists of friends requests we handle everything in-memory and 
return that data in this loop...
+       //the expected behavior for multiple requests simultaneously is a bit 
unclear.
+       for (var i = 0; i < requestObjects.length; i++) {
+               var request = requestObjects[i].request;
+               var responseName = requestObjects[i].key;
+               var requestedValue;
+               console.log('request type: ' + request.type);
+               console.log('request response name: ' + responseName);
+
+               switch(request.type) {
+                       case 
opensocial.DataRequest.RequestType.FETCH_GLOBAL_DATA :
+                       console.log('FETCH_GLOBAL_DATA');
+                       // TODO(doll): Filter by key
+                       requestedValue = this.globalAppData;
+                       break;
+
+                       case 
opensocial.DataRequest.RequestType.FETCH_INSTANCE_DATA :
+                       console.log('FETCH_INSTANCE_DATA');
+                       // TODO(doll): Filter by key
+                       requestedValue = this.instanceAppData;
+                       break;
+
+                       case 
opensocial.DataRequest.RequestType.UPDATE_INSTANCE_DATA :
+                       console.log('UPDATE_INSTANCE_DATA');
+                       this.instanceAppData[request.parameters.key] = 
request.parameters.value;
+                       break;
+
+                       case opensocial.DataRequest.RequestType.FETCH_PEOPLE :
+                       console.log('FETCH_PEOPLE');
+                       console.log(request);
+                       var groupId = request.parameters.idSpec;
+                       if (groupId == 
opensocial.DataRequest.Group.VIEWER_FRIENDS && this.viewer.getId() != 
'xn_anonymous') {
+                               console.log('FETCH_PEOPLE: viewerFriends');
+                               console.log(this.viewerFriends);
+                               //requestedValue = new 
s2.data.ArrayWrapper(this.viewerFriends);
+                               requestedValue = this.viewerFriends;
+                       }
+                       else if (groupId == 
opensocial.DataRequest.Group.OWNER_FRIENDS) {
+                               console.log('FETCH_PEOPLE: ownerFriends');
+                               //requestedValue = new 
s2.data.ArrayWrapper(this.ownerFriends);
+                               requestedValue = this.ownerFriends;
+                       }
+
+                       break;
+
+                       case opensocial.DataRequest.RequestType.FETCH_PERSON :
+
+                       //opensocial.Container.PersonId.VIEWER returns person: 
viewer -- not clear in the docs
+                       var personId = request.parameters.id;
+                       if (personId == opensocial.DataRequest.PersonId.VIEWER) 
{
+                               console.log('FETCH_PERSON: viewer');
+                               console.log(this.viewer);
+                               requestedValue  = this.viewer;
+                       }
+                       else if (personId == 
opensocial.DataRequest.PersonId.OWNER) {
+                               console.log('FETCH_PERSON: owner');
+                               requestedValue  = this.owner;
+                       } else {
+                               console.log('FETCH_PERSON: specific friend');
+                               requestedValue = 
this.viewerFriends.get(personId)
+                               || this.ownerFriends.get(personId);
+                       }
+
+
+                       //todo -- add waiting in case they request data from 
another profile
+                       break;
+
+                       case 
opensocial.DataRequest.RequestType.FETCH_ACTIVITIES :
+                       console.log('FETCH_ACTIVITIES');
+                       
//http://gadgets.Shindig.com/activity/log/list?fmt=json&screenName=diego
+
+                       onSuccess = function(evaldObj) {
+                               friendCount = evaldObj.total;
+                               //              
console.log('count='+friendCount);
+                               //              
console.log('intct='+evaldObj.contacts.values.length);
+                               var activitiesArr = evaldObj.values;
+                               var resultArr = {};
+                               if (responseName == "viewer" || 
request.responseName == "activities") {
+                                       this.viewerActivities = new Array();
+                                       resultArr = this.viewerActivities;
+                               }
+                               if (responseName == "owner") {
+                                       this.ownerActivities = new Array();
+                                       resultArr = this.ownerActivities;
+                               }
+
+/*
+    for(var i = 0;i < activityResponse.length;i++) {
+      var activity = activityResponse[i];
+      activities.push(new opensocial.Person.Activity(activity.ApplicationId, 
activity.Body, activity.Title, activity.Url, activity.Summary, 
activity.FolderId))
+    }
+    opensocial.DataRequest.ActivityRequestFields = {APP_ID:"appId", 
FOLDER_ID:"folderId"};
+    opensocial.DataRequest.prototype.newFetchActivitiesRequest = 
function(idSpec, opt_params) {
+  opt_params = opt_params || {};
+  var fields = opensocial.DataRequest.ActivityRequestFields, requestParams = 
{idSpec:idSpec, appId:opt_params[fields.APP_ID], 
folderId:opt_params[fields.FOLDER_ID]};
+  return new 
opensocial.DataRequest.BaseDataRequest(opensocial.DataRequest.RequestType.FETCH_ACTIVITIES,
 requestParams)
+  opensocial.Activity = function(stream, title, opt_params) {
+};
+opensocial.Activity.Field = {ID:"id", EXTERNAL_ID:"externalId", 
STREAM:"stream", TITLE:"title", SUMMARY:"summary", BODY:"body", URL:"url", 
MEDIA_ITEMS:"mediaItems", POSTED_TIME:"postedTime", 
CUSTOM_VALUES:"customValues"};
+
+*/
+                               for (var i = 0; i < activitiesArr.length; i++) {
+                                       fObj = activitiesArr[i];
+                                       resultArr[resultArr.length] = new 
opensocial.Person.Activity(fObj.id, fObj.description, fObj.title, fObj.link);
+                               }
+
+                               dataResponseValues[responseName] = new 
opensocial.ResponseItem(request, resultArr);
+                               callback(new 
opensocial.DataResponse(dataRequest, dataResponseValues));
+                       };
+                       onError = function(context, msg) {
+
+                       };
+                       var handlers = {
+                               success: onSuccess,
+                               failure: onError
+                       };
+                       if (this.viewer.getName() == 'xn_anonymous') {
+                               
Shindig.api.get("/activity/log/list?fmt=json&screenName=" + 
this.viewer.getId(), handlers);
+                       }
+                       else {
+                               console.log('not logged in');
+                       }
+                       return;
+
+                       case 
opensocial.DataRequest.RequestType.FETCH_PERSON_DATA:
+                       // TODO(doll): Filter by person and key
+                       console.log('FETCH_PERSON_DATA: ' + 
request.parameters.idSpec);
+                       var personId = request.parameters.idSpec || 
request.parameters.id;//request.parameters.id;
+                       if (personId == opensocial.DataRequest.PersonId.VIEWER) 
{
+                               requestedValue = this.viewer.getAppData();
+                       }
+                       else if (personId == 
opensocial.DataRequest.PersonId.OWNER) {
+                               requestedValue = this.owner.getAppData();
+                       }
+                       break;
+
+                       case 
opensocial.DataRequest.RequestType.UPDATE_PERSON_DATA :
+                       console.log('FETCH_PERSON_DATA: ' + 
request.parameters.person.id);
+                       var key = request.parameters.field;
+                       if (request.parameters.person.appData[key] != 
request.parameters.value) {
+                               request.parameters.person.appData[key] = 
request.parameters.value;
+                               if (this.viewer) {
+                                       onSuccess = function(evaldObj) {
+                                               console.log('success!');
+                                               
dataResponseValues[responseName] = new opensocial.ResponseItem(request, 
requestedValue);
+                                               callback(new 
opensocial.DataResponse(dataRequest, dataResponseValues));
+                                       };
+                                       onError = function(context, msg) {
+                                               console.log('error = ' + msg);
+                                       };
+                                       var handlers = {
+                                               success: onSuccess,
+                                               failure: onError
+                                       };
+                                       var userid = 
request.parameters.person.id;
+                                       var value = request.parameters.value;
+                                       //var form = new Array();
+                                       content = {'user':  userid, 
'op':'update-app-data', 'app': this.appName, 'key': key, 'value': value, 
'xark': Shindig._.os.xark, 'origin': Shindig._.os.origin};
+                                       Shindig.api.post("/gadgets/index/api", 
content, handlers);
+                               }
+                               else {
+                                       console.log('not logged in');
+                               }
+                       }
+                       return;
+
+                       case opensocial.DataRequest.RequestType.POST_ACTIVITY :
+                       console.log('POST_ACTIVITY');
+                       console.log(request);
+                       console.log('end POST_ACTIVITY');
+                       
+                               if (this.viewer) {
+                                       onSuccess = function(evaldObj) {
+                                               console.log('success!');
+                                               
dataResponseValues[responseName] = new opensocial.ResponseItem(request, 
requestedValue);
+                                               callback(new 
opensocial.DataResponse(dataRequest, dataResponseValues));
+                                       };
+                                       onError = function(context, msg) {
+                                               console.log('error = ' + msg);
+                                       };
+                                       var handlers = {
+                                               success: onSuccess,
+                                               failure: onError
+                                       };
+                                       var userid = 
request.parameters.person.id;
+                                       var value = request.parameters.value;
+                                       //var form = new Array();
+                                       content = {'user':  userid, 
'op':'insert-activity', 'app': this.appName, 'description': 
request.parameters.body, 'title': request.parameters.title, 'link': 
request.parameters.url, 'xark': Shindig._.os.xark, 'origin': 
Shindig._.os.origin};
+                                       Shindig.api.post("/gadgets/index/api", 
content, handlers);
+                               }
+                               else {
+                                       console.log('not logged in');
+                               }
+                       
+                       /*
+                       this.activities.push(new opensocial.Person.Activity(
+                       request.parameters.appId, request.parameters.body,
+                       request.parameters.title, request.parameters.url));
+                       */
+                       return;
+               }
+               console.log('setting response to '+responseName);
+               dataResponseValues[responseName] = new 
opensocial.ResponseItem(request, requestedValue);
+       }
+
+               console.log('viewer  ==========')
+       //console.log(dataResponseValues.get('viewer'))
+               console.log('end viewer ========== ')
+       
+       callback(new opensocial.DataResponse(dataResponseValues));
+};
+
+
+
+/**
+* Create a person.
+*
+* @param {String} id The id of the person
+* @param {String} name The name of the person
+* @param {String} email The email of the person
+* @param {String} pictureUrl The url of the person's photo
+* @param {Array<String>} installedApps An array of strings representing which
+*     apps are installed
+* @param {Map<String, String>} appData A map from app fields to app values
+* @param {Boolean} isViewerObject If true, this person is the currently logged
+*   in user.
+* @constructor
+*/
+opensocial.ShindigPerson = function(id, opt_name, opt_email, opt_pictureUrl, 
opt_installedApps, opt_appData, opt_isViewerObject) {
+       this.id = id;
+       this.name = opt_name;
+       this.email = opt_email;
+
+       this.pictureUrl = opt_pictureUrl;
+       if (this.pictureUrl.indexOf('?') == -1) {
+               this.pictureUrl += '?';
+       }
+       else {
+               this.pictureUrl += '&';
+       }
+       // this.pictureUrl += 'width=32&height=32'; // Ning specific
+       this.installedApps = opt_installedApps;
+       this.appData = opt_appData;
+       this.isViewerObject = opt_isViewerObject;
+       this.isAppDataLoaded = false;
+       this.isAppDataLoading = false;
+};
+
+
+opensocial.ShindigPerson.prototype.getField = function(key) {
+       if (key == opensocial.Person.Field.ID) {
+               return this.id;
+       }
+       if (key == opensocial.Person.Field.NAME) {
+               return this.name;
+       }
+       if (key == opensocial.Person.Field.EMAIL) {
+               return this.email;
+       }
+       return null;
+       //return this.fields[key];
+};
+
+opensocial.ShindigPerson.prototype.isDataLoaded = function() {
+       return this.isAppDataLoaded;
+};
+
+
+opensocial.ShindigPerson.prototype.isViewer = function() {
+       return this.isViewerObject;
+};
+
+
+opensocial.ShindigPerson.prototype.getId = function() {
+       return this.id;
+};
+
+
+opensocial.ShindigPerson.prototype.getName = function() {
+       return this.name;
+};
+
+
+opensocial.ShindigPerson.prototype.getEmail = function() {
+       return this.email;
+};
+
+/**
+* If the display name field is set, then return it. If not try to do
+* something meaShindigful using the email address.
+*/
+opensocial.ShindigPerson.prototype.getDisplayName = function() {
+       if (this.getName()) {
+               return this.getName();
+       } else  {
+               var email = this.getEmail();
+               if (email && email.indexOf('@') > 0) {
+                       return email.substring(0, email.indexOf('@'));
+               }
+       }
+       return '';
+};
+
+
+opensocial.ShindigPerson.prototype.getPicture = function() {
+       return this.pictureUrl;
+};
+
+
+opensocial.ShindigPerson.prototype.hasApp = function(appName) {
+       for (var i = 0; i < this.installedApps.length; i++) {
+               if (this.installedApps[i] == appName) {
+                       return true;
+               }
+       }
+
+       return false;
+};
+
+
+
+opensocial.ShindigPerson.prototype.getAppData = function(field) {
+       return this.appData;
+}
+opensocial.ShindigPerson.prototype.getAppField = function(field) {
+       if (typeof(this.appData[field]) == "undefined") {
+               return '';
+       }
+       return this.appData[field];
+};
+
+if(window.magic_orkut) {
+       opensocial.Container.setContainer(new opensocial.OrkutContainer)
+}
+else if(window.magic_shindig) {
+       opensocial.Container.setContainer(new opensocial.ShindigContainer)
+}
+else {
+       opensocial.Container.setContainer(new opensocial.IGoogleContainer)
+};
+
+

Propchange: incubator/shindig/trunk/php/js/ShindigContainer.js
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/shindig/trunk/php/js/hash.js
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/js/hash.js?rev=606463&view=auto
==============================================================================
--- incubator/shindig/trunk/php/js/hash.js (added)
+++ incubator/shindig/trunk/php/js/hash.js Sat Dec 22 08:11:57 2007
@@ -0,0 +1,257 @@
+/*
+ * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
+ * Digest Algorithm, as defined in RFC 1321.
+ * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
+ * Distributed under the BSD License
+ * See http://pajhome.org.uk/crypt/md5 for more info.
+ */
+
+/*
+ * Configurable variables. You may need to tweak these to be compatible with
+ * the server-side, but the defaults work in most cases.
+ */
+var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase        */
+var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */
+var chrsz   = 8;  /* bits per input character. 8 - ASCII; 16 - Unicode      */
+
+/*
+ * These are the functions you'll usually want to call
+ * They take string arguments and return either hex or base-64 encoded strings
+ */
+function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
+function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}
+function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}
+function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }
+function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }
+function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }
+
+/*
+ * Perform a simple self-test to see if the VM is working
+ */
+function md5_vm_test()
+{
+  return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
+}
+
+/*
+ * Calculate the MD5 of an array of little-endian words, and a bit length
+ */
+function core_md5(x, len)
+{
+  /* append padding */
+  x[len >> 5] |= 0x80 << ((len) % 32);
+  x[(((len + 64) >>> 9) << 4) + 14] = len;
+
+  var a =  1732584193;
+  var b = -271733879;
+  var c = -1732584194;
+  var d =  271733878;
+
+  for(var i = 0; i < x.length; i += 16)
+  {
+    var olda = a;
+    var oldb = b;
+    var oldc = c;
+    var oldd = d;
+
+    a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
+    d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
+    c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
+    b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
+    a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
+    d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
+    c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
+    b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
+    a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
+    d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
+    c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
+    b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
+    a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
+    d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
+    c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
+    b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);
+
+    a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
+    d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
+    c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);
+    b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
+    a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
+    d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
+    c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
+    b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
+    a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
+    d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
+    c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
+    b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
+    a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
+    d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
+    c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
+    b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
+
+    a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
+    d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
+    c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
+    b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
+    a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
+    d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
+    c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
+    b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
+    a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
+    d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
+    c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
+    b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
+    a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
+    d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
+    c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);
+    b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
+
+    a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
+    d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
+    c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
+    b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
+    a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
+    d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
+    c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
+    b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
+    a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
+    d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
+    c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
+    b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
+    a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
+    d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
+    c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
+    b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
+
+    a = safe_add(a, olda);
+    b = safe_add(b, oldb);
+    c = safe_add(c, oldc);
+    d = safe_add(d, oldd);
+  }
+  return Array(a, b, c, d);
+
+}
+
+/*
+ * These functions implement the four basic operations the algorithm uses.
+ */
+function md5_cmn(q, a, b, x, s, t)
+{
+  return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
+}
+function md5_ff(a, b, c, d, x, s, t)
+{
+  return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
+}
+function md5_gg(a, b, c, d, x, s, t)
+{
+  return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
+}
+function md5_hh(a, b, c, d, x, s, t)
+{
+  return md5_cmn(b ^ c ^ d, a, b, x, s, t);
+}
+function md5_ii(a, b, c, d, x, s, t)
+{
+  return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
+}
+
+/*
+ * Calculate the HMAC-MD5, of a key and some data
+ */
+function core_hmac_md5(key, data)
+{
+  var bkey = str2binl(key);
+  if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);
+
+  var ipad = Array(16), opad = Array(16);
+  for(var i = 0; i < 16; i++)
+  {
+    ipad[i] = bkey[i] ^ 0x36363636;
+    opad[i] = bkey[i] ^ 0x5C5C5C5C;
+  }
+
+  var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
+  return core_md5(opad.concat(hash), 512 + 128);
+}
+
+/*
+ * Add integers, wrapping at 2^32. This uses 16-bit operations internally
+ * to work around bugs in some JS interpreters.
+ */
+function safe_add(x, y)
+{
+  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
+  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
+  return (msw << 16) | (lsw & 0xFFFF);
+}
+
+/*
+ * Bitwise rotate a 32-bit number to the left.
+ */
+function bit_rol(num, cnt)
+{
+  return (num << cnt) | (num >>> (32 - cnt));
+}
+
+/*
+ * Convert a string to an array of little-endian words
+ * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
+ */
+function str2binl(str)
+{
+  var bin = Array();
+  var mask = (1 << chrsz) - 1;
+  for(var i = 0; i < str.length * chrsz; i += chrsz)
+    bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
+  return bin;
+}
+
+/*
+ * Convert an array of little-endian words to a string
+ */
+function binl2str(bin)
+{
+  var str = "";
+  var mask = (1 << chrsz) - 1;
+  for(var i = 0; i < bin.length * 32; i += chrsz)
+    str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
+  return str;
+}
+
+/*
+ * Convert an array of little-endian words to a hex string.
+ */
+function binl2hex(binarray)
+{
+  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
+  var str = "";
+  for(var i = 0; i < binarray.length * 4; i++)
+  {
+    str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
+           hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
+  }
+  return str;
+}
+
+/*
+ * Convert an array of little-endian words to a base-64 string
+ */
+function binl2b64(binarray)
+{
+  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+  var str = "";
+  for(var i = 0; i < binarray.length * 4; i += 3)
+  {
+    var triplet = (((binarray[i   >> 2] >> 8 * ( i   %4)) & 0xFF) << 16)
+                | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
+                |  ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
+    for(var j = 0; j < 4; j++)
+    {
+      if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
+      else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
+    }
+  }
+  return str;
+}
+


Reply via email to