├── .project ├── README.md └── mobile ├── android ├── .classpath ├── .gitignore ├── .project ├── LICENSE ├── README.md ├── assets │ ├── README │ └── Resources │ │ └── com.obscure.couchdb_client.js ├── build.properties ├── build.xml ├── documentation │ └── index.md ├── example │ └── app.js ├── hooks │ ├── README │ ├── add.py │ ├── install.py │ ├── remove.py │ └── uninstall.py ├── manifest └── timodule.xml ├── ios ├── .gitignore ├── Classes │ ├── .gitignore │ ├── ComObscureCouchdb_clientModule.h │ ├── ComObscureCouchdb_clientModule.m │ ├── ComObscureCouchdb_clientModuleAssets.h │ └── ComObscureCouchdb_clientModuleAssets.m ├── ComObscureCouchdb_client_Prefix.pch ├── LICENSE ├── README ├── assets │ ├── README │ └── com.obscure.couchdb_client.js ├── build.py ├── couchdb_client.xcodeproj │ └── project.pbxproj ├── documentation │ └── index.md ├── example │ └── app.js ├── hooks │ ├── README │ ├── add.py │ ├── install.py │ ├── remove.py │ └── uninstall.py ├── manifest ├── module.xcconfig ├── timodule.xml └── titanium.xcconfig └── noarch └── com.obscure.couchdb_client.inc.js /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | couchdb_client 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CouchDb Client Library for Appcelerator Titanium Mobile 2 | ------------------------------------------------------- 3 | 4 | This project is a port of `jquery.couchdb.js` to use the `Titanium.Network.HTTPClient` 5 | API instead of jQuery. There are three versions of the library: 6 | 7 | ### `modules/ios` 8 | 9 | Native module for iOS devices. See the Github wiki for build and installation 10 | instructions. 11 | 12 | ### `modules/android` 13 | 14 | A work in progress. There are some issues with a native Javascript module on Android, 15 | so for that platform, I suggest that you use... 16 | 17 | ### `modules/noarch/com.obscure.couchdb_client.inc.js` 18 | 19 | The library as an includeable script. To use this version of the script, copy it to 20 | your `Resources` directory and include it in your app files as follows: 21 | 22 | Titanium.include('com.obscure.couchdb_client.inc.js'); 23 | 24 | This will create a variable named `couchdb_client` in the current context which can 25 | be used to communicate with the CouchDb server. 26 | 27 | 28 | 29 | Acknowledgements 30 | ---------------- 31 | 32 | This library is based on the work of the Apache CouchDb team and contributors. 33 | 34 | sha1.js 35 | Version 2.1a Copyright Paul Johnston 2000 - 2002. 36 | 37 | base64.js 38 | Copyright (C) 1999 Masanao Izumo -------------------------------------------------------------------------------- /mobile/android/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /mobile/android/.gitignore: -------------------------------------------------------------------------------- 1 | tmp 2 | bin 3 | build 4 | *.zip 5 | .apt_generated 6 | dist 7 | .settings 8 | -------------------------------------------------------------------------------- /mobile/android/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | titanium-couchdb_client 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /mobile/android/LICENSE: -------------------------------------------------------------------------------- 1 | TODO: place your license here and we'll include it in the module distribution 2 | -------------------------------------------------------------------------------- /mobile/android/README.md: -------------------------------------------------------------------------------- 1 | CouchDb Client Library for Android 2 | ---------------------------------- 3 | 4 | *IMPORTANT NOTE*: this library is not currently working due to problems with 5 | various parts of the Titanium API not being loaded in the module's Javascript 6 | context. See the following Q&A on the Appcelerator site for details: 7 | 8 | http://developer.appcelerator.com/question/119612/cant-create-javascript-native-module-for-android 9 | -------------------------------------------------------------------------------- /mobile/android/assets/README: -------------------------------------------------------------------------------- 1 | Place your assets like PNG files in this directory and they will be packaged with your module. 2 | 3 | If you create a file named com.obscure.couchdb_client.js in this directory, it will be 4 | compiled and used as your module. This allows you to run pure Javascript 5 | modules that are pre-compiled. 6 | 7 | -------------------------------------------------------------------------------- /mobile/android/assets/Resources/com.obscure.couchdb_client.js: -------------------------------------------------------------------------------- 1 | /** @module com.obscure.couchdb_client */ 2 | 3 | /** 4 | * @fileOverview 5 | * CouchDB client module for Appcelerator Titanium. All of the functions 6 | * in this module are asynchronous and use an options object for common 7 | * parameters. 8 | * @see options 9 | */ 10 | 11 | /** 12 | * @name options 13 | * @field 14 | * @property {Function} success called by the module when the CouchDB call completes 15 | * successfully. The parameter to this function is the response from CouchDB 16 | * as an object. 17 | * @property {Function} failure called by the module when the CouchDB call fails for 18 | * any reason. The parameter to this function is the XMLHttpRequest object used 19 | * in the call. You can extract the response code and error messages from that XHR. 20 | * @property {String} username the username to use during the call. Some CouchDB calls 21 | * require an admin user; depending on your security setup, other calls may also 22 | * require a valid user. 23 | * @property {String} password the password to use during the call. 24 | */ 25 | 26 | var couchdb_client = {}; 27 | 28 | (function(module) { 29 | 30 | /** @private */ 31 | function userDb(callback) { 32 | module.session({ 33 | success: function(resp) { 34 | var userDb = module.db(resp.info.authentication_db); 35 | callback(userDb); 36 | } 37 | }); 38 | } 39 | 40 | /** @private */ 41 | function prepareUserDoc(user_doc, new_password) { 42 | if (typeof hex_sha1 == "undefined") { 43 | Ti.API.error("creating a user doc requires sha1.js to be loaded in the page"); 44 | return; 45 | } 46 | var user_prefix = "org.couchdb.user:"; 47 | user_doc._id = user_doc._id || user_prefix + user_doc.name; 48 | if (new_password) { 49 | // handle the password crypto 50 | user_doc.salt = _newUUID(); 51 | user_doc.password_sha = hex_sha1(new_password + user_doc.salt); 52 | } 53 | user_doc.type = "user"; 54 | if (!user_doc.roles) { 55 | user_doc.roles = []; 56 | } 57 | return user_doc; 58 | } 59 | 60 | /** @private */ 61 | function encodeDocId(docID) { 62 | var parts = docID.split("/"); 63 | if (parts[0] == "_design") { 64 | parts.shift(); 65 | return "_design/" + encodeURIComponent(parts.join('/')); 66 | } 67 | return encodeURIComponent(docID); 68 | } 69 | 70 | /** @private */ 71 | var viewOptions = [ 72 | "key", "startkey", "startkey_docid", "endkey", "endkey_docid", "limit", 73 | "stale", "descending", "skip", "group", "group_level", "reduce", 74 | "include_docs", "inclusive_end" 75 | ]; 76 | 77 | /** @private */ 78 | function encodeViewOptions(obj) { 79 | // http://wiki.apache.org/couchdb/HTTP_view_API 80 | // note that "keys" is handled separately 81 | var buf = []; 82 | for (var key in obj) { 83 | if (inArray(key, viewOptions) > -1) { 84 | buf.push(encodeURIComponent(key) + "=" + encodeURIComponent(JSON.stringify(obj[key]))); 85 | } 86 | } 87 | return buf.join('&'); 88 | } 89 | 90 | 91 | /** 92 | * base URL of the CouchDB server, i.e. 'http://localhost:5984' 93 | */ 94 | module.urlPrefix = ''; 95 | 96 | // public functions 97 | 98 | /** 99 | * Fetch a list of all databases. 100 | * @param options request options 101 | */ 102 | module.allDbs = function(options) { 103 | ajax({ 104 | url: this.urlPrefix + "/_all_dbs" 105 | }, options); 106 | }; 107 | 108 | /** 109 | * Get information about the server or a database (add "dbname" field to the options object). 110 | * @param options request options 111 | */ 112 | module.info = function(options) { 113 | ajax({ 114 | url: this.urlPrefix + "/" + (options.dbname || "") 115 | }, options); 116 | }; 117 | 118 | module.config = function(options, section, key, value) { 119 | var req = { url: this.urlPrefix + "/_config/" }; 120 | if (section) { 121 | req.url += encodeURIComponent(section) + "/"; 122 | if (key) { 123 | req.url += encodeURIComponent(key); 124 | } 125 | } 126 | if (value === null) { 127 | req.method = "DELETE"; 128 | } 129 | else if (value !== undefined) { 130 | req.method = "PUT"; 131 | req.data = JSON.stringify(value); 132 | } 133 | ajax(req, options); 134 | }; 135 | 136 | module.login = function(options, username, password) { 137 | this.session(extend({ username:username, password:password}, options)); 138 | }; 139 | 140 | module.logout = function(options) { 141 | ajax({ 142 | method: "DELETE", 143 | url: this.urlPrefix + "/_session", 144 | username: "_", 145 | password: "_" 146 | }, options); 147 | }; 148 | 149 | module.session = function(options) { 150 | ajax({ 151 | url: this.urlPrefix + "/_session", 152 | headers: { "Accept": "application/json" } 153 | }, options); 154 | }; 155 | 156 | module.signup = function(user_doc, password, options) { 157 | options = options || {}; 158 | user_doc = prepareUserDoc(user_doc, password); 159 | userDb(function(db) { 160 | db.saveDoc(user_doc, options); 161 | }); 162 | }; 163 | 164 | module.db = function(name, db_opts) { 165 | db_opts = db_opts || {}; 166 | 167 | return { 168 | name: name, 169 | uri: this.urlPrefix + "/" + encodeURIComponent(name) + "/", 170 | 171 | /** 172 | * Request compaction of the specified database. 173 | * @param 174 | */ 175 | compact: function(options) { 176 | ajax({ 177 | method: "POST", 178 | url: this.uri + "_compact", 179 | successStatus: 202 180 | }, options); 181 | }, 182 | 183 | /** 184 | * Cleans up the cached view output on disk for a given view. 185 | */ 186 | viewCleanup: function(options) { 187 | ajax({ 188 | method: "POST", 189 | url: this.uri + "_view_cleanup", 190 | successStatus: 202 191 | }, options); 192 | }, 193 | 194 | /** 195 | * Compacts the view indexes associated with the specified design 196 | * document. You can use this in place of the full database compaction 197 | * if you know a specific set of view indexes have been affected by a 198 | * recent database change. 199 | */ 200 | compactView: function(groupname, options) { 201 | ajax({ 202 | method: "POST", 203 | url: this.uri + "_compact/" + groupname, 204 | successStatus: 202 205 | }, options); 206 | }, 207 | 208 | /** 209 | * Create a new database 210 | */ 211 | create: function(options) { 212 | ajax({ 213 | method: "PUT", 214 | url: this.uri, 215 | successStatus: 201 216 | }, options); 217 | }, 218 | 219 | /** 220 | * Deletes the specified database, and all the documents and 221 | * attachments contained within it. 222 | */ 223 | drop: function(options) { 224 | ajax({ 225 | method: "DELETE", 226 | url: this.uri 227 | }, options); 228 | }, 229 | 230 | /** 231 | * Gets information about the specified database. 232 | */ 233 | info: function(options) { 234 | ajax({ 235 | url: this.uri 236 | }, options); 237 | }, 238 | 239 | /** 240 | * @namespace 241 | * $.couch.db.changes provides an API for subscribing to the changes 242 | * feed 243 | *
var $changes = $.couch.db("mydatabase").changes();
 244 |        *$changes.onChange = function (data) {
 245 |        *    ... process data ...
 246 |        * }
 247 |        * $changes.stop();
 248 |        * 
249 | */ 250 | /* TODO TODO TODO 251 | changes: function(since, options) { 252 | 253 | options = options || {}; 254 | // set up the promise object within a closure for this handler 255 | var timeout = 100, db = this, active = true, 256 | listeners = [], 257 | promise = { 258 | onChange : function(fun) { 259 | listeners.push(fun); 260 | }, 261 | stop : function() { 262 | active = false; 263 | } 264 | }; 265 | // call each listener when there is a change 266 | function triggerListeners(resp) { 267 | $.each(listeners, function() { 268 | this(resp); 269 | }); 270 | }; 271 | // when there is a change, call any listeners, then check for 272 | // another change 273 | options.success = function(resp) { 274 | timeout = 100; 275 | if (active) { 276 | since = resp.last_seq; 277 | triggerListeners(resp); 278 | getChangesSince(); 279 | }; 280 | }; 281 | options.error = function() { 282 | if (active) { 283 | setTimeout(getChangesSince, timeout); 284 | timeout = timeout * 2; 285 | } 286 | }; 287 | // actually make the changes request 288 | function getChangesSince() { 289 | var opts = $.extend({heartbeat : 10 * 1000}, options, { 290 | feed : "longpoll", 291 | since : since 292 | }); 293 | ajax( 294 | {url: db.uri + "_changes"+encodeOptions(opts)}, 295 | options, 296 | "Error connecting to "+db.uri+"/_changes." 297 | ); 298 | } 299 | // start the first request 300 | if (since) { 301 | getChangesSince(); 302 | } else { 303 | db.info({ 304 | success : function(info) { 305 | since = info.update_seq; 306 | getChangesSince(); 307 | } 308 | }); 309 | } 310 | return promise; 311 | }, 312 | */ 313 | 314 | /** 315 | * Fetch all the docs in this db. You can specify an array of keys to 316 | * fetch by passing the keys field in the 317 | * options parameter. 318 | */ 319 | allDocs: function(options) { 320 | var method = "GET"; 321 | var data = null; 322 | if (options["keys"]) { 323 | method = "POST"; 324 | var keys = options["keys"]; 325 | delete options["keys"]; 326 | data = { "keys": keys }; 327 | } 328 | ajax({ 329 | method: method, 330 | data: data, 331 | url: this.uri + "_all_docs" 332 | }, options); 333 | }, 334 | 335 | /** 336 | * Fetch all the design docs in this db 337 | */ 338 | allDesignDocs: function(options) { 339 | this.allDocs(extend({ startkey:"_design", endkey:"_design0" }, options)); 340 | }, 341 | 342 | /** 343 | * Returns the specified doc from the db. 344 | */ 345 | openDoc: function(docId, options) { 346 | ajax({ 347 | url: this.uri + encodeDocId(docId) 348 | }, options); 349 | }, 350 | 351 | /** 352 | * Create a new document in the specified database, using the supplied 353 | * JSON document structure. If the JSON structure includes the _id 354 | * field, then the document will be created with the specified document 355 | * ID. If the _id field is not specified, a new unique ID will be 356 | * generated. 357 | */ 358 | saveDoc: function(doc, options) { 359 | options = options || {}; 360 | var db = this; 361 | if (doc._id === undefined) { 362 | var method = "POST"; 363 | var uri = this.uri; 364 | } 365 | else { 366 | var method = "PUT"; 367 | var uri = this.uri + encodeDocId(doc._id); 368 | } 369 | ajax({ 370 | method: method, 371 | url: uri, 372 | data: doc, 373 | successStatus: [200, 201, 202] 374 | }, options); 375 | }, 376 | 377 | /** 378 | * Save a list of documents 379 | */ 380 | bulkSave: function(docs, options) { 381 | ajax({ 382 | method: "POST", 383 | url: this.uri + "_bulk_docs", 384 | data: docs, 385 | }, options); 386 | }, 387 | 388 | /** 389 | * Deletes the specified document from the database. You must supply 390 | * the current (latest) revision and id of the document 391 | * to delete eg removeDoc({_id:"mydoc", _rev: "1-2345"}) 392 | */ 393 | removeDoc: function(doc, options) { 394 | ajax({ 395 | method: "DELETE", 396 | data: { rev: doc._rev }, 397 | url: this.uri + encodeDocId(doc._id) 398 | }, options); 399 | }, 400 | 401 | /** 402 | * Remove a set of documents 403 | */ 404 | bulkRemove: function(docs, options){ 405 | docs.docs = each(docs.docs, function(i, doc) { 406 | doc._deleted = true; 407 | }); 408 | ajax({ 409 | method: "POST", 410 | successStatus: 201, 411 | url: this.uri + "_bulk_docs", 412 | data: docs 413 | }, options); 414 | }, 415 | 416 | /** 417 | * Copy an existing document to a new or existing document. 418 | */ 419 | copyDoc: function(source, destination, options) { 420 | if (!destination) { 421 | // TODO get a UUID 422 | } 423 | ajax({ 424 | method: "COPY", 425 | url: this.uri + encodeDocId(source), 426 | successStatus: 201, 427 | headers: { "Destination": destination } 428 | }, options); 429 | }, 430 | 431 | /** 432 | * Creates and executes a temporary view. 433 | */ 434 | query: function(mapFun, reduceFun, language, options) { 435 | language = language || "javascript"; 436 | if (typeof(mapFun) !== "string") { 437 | mapFun = mapFun.toSource ? mapFun.toSource() : "(" + mapFun.toString() + ")"; 438 | } 439 | var body = {language: language, map: mapFun}; 440 | if (reduceFun != null) { 441 | if (typeof(reduceFun) !== "string") 442 | reduceFun = reduceFun.toSource ? reduceFun.toSource() 443 | : "(" + reduceFun.toString() + ")"; 444 | body.reduce = reduceFun; 445 | } 446 | ajax({ 447 | method: "POST", 448 | url: this.uri + "_temp_view", 449 | data: body, 450 | headers: { "Content-Type": "application/json" } 451 | }, 452 | options); 453 | }, 454 | 455 | 456 | /** 457 | * Fetch a _list view output. You can specify a list of 458 | * keys in the options object to receive only those keys. 459 | */ 460 | list: function(list, view, options) { 461 | var list = list.split('/'); 462 | var method = 'GET'; 463 | var data = null; 464 | if (options['keys']) { 465 | method = 'POST'; 466 | var keys = options['keys']; 467 | delete options['keys']; 468 | data = {'keys': keys }; 469 | } 470 | ajax({ 471 | method: method, 472 | data: data, 473 | url: this.uri + '_design/' + list[0] + '/_list/' + list[1] + '/' + view 474 | }, options); 475 | }, 476 | 477 | /** 478 | * Executes the specified view-name from the specified design-doc 479 | * design document. You can specify a list of keys 480 | * in the options object to recieve only those keys. 481 | */ 482 | view: function(name, options) { 483 | var name = name.split('/'); 484 | var method = "GET"; 485 | var data = null; 486 | if (options["keys"]) { 487 | method = "POST"; 488 | var keys = options["keys"]; 489 | delete options["keys"]; 490 | data = { "keys": keys }; 491 | } 492 | ajax({ 493 | method: method, 494 | data: data, 495 | url: this.uri + "_design/" + name[0] + "/_view/" + name[1] + '?' + encodeViewOptions(options) 496 | }, options); 497 | }, 498 | 499 | /** 500 | * Fetch an arbitrary CouchDB database property. As of 1.1, only the 501 | * _revs_limit property is available. 502 | */ 503 | getDbProperty: function(propName, options) { 504 | ajax({ 505 | url: this.uri + propName 506 | }, options); 507 | }, 508 | 509 | /** 510 | * Set an arbitrary CouchDB database property. As of 1.1, only the 511 | * _revs_limit property is available. 512 | */ 513 | setDbProperty: function(propName, propValue, options) { 514 | ajax({ 515 | method: "PUT", 516 | url: this.uri + propName, 517 | data : propValue 518 | }, options); 519 | } 520 | } 521 | }; 522 | 523 | 524 | /** 525 | * AJAX functions for CouchDB client 526 | */ 527 | 528 | function httpData(xhr, type) { 529 | var contentType = xhr.getResponseHeader("content-type") || ""; 530 | var isXml = type === "xml" || (!type && contentType.indexOf("xml") >= 0); 531 | var isJson = type === "json" || (!type && contentType.indexOf("json") >= 0); 532 | 533 | var data = isXml ? xhr.responseXML : xhr.responseText; 534 | if (typeof data === "string") { 535 | if (isJson) { 536 | data = JSON.parse(data); 537 | } 538 | // other types here? 539 | } 540 | return data; 541 | } 542 | 543 | function toQueryString(obj) { 544 | var buf = []; 545 | for (var name in obj) { 546 | var value = obj[name]; 547 | if (inArray(name, ["key", "startkey", "endkey"]) >= 0) { 548 | value = JSON.stringify(value); 549 | } 550 | buf.push(encodeURIComponent(name) + "=" + encodeURIComponent(value)); 551 | } 552 | return buf.length ? buf.join("&") : ""; 553 | } 554 | 555 | /** 556 | * 557 | * opts.method HTTP method to use 558 | * opts.successStatus default 200; set to 201 for document create 559 | * opts.data for HTTP GET, the query parameters; otherwise request body 560 | * opts.headers extra headers to send 561 | * opts.success function(data) called on success; data is the object returned in the response 562 | * opts.failure function(xhr) called on failure with XMLHttpRequest object 563 | */ 564 | function ajax(req, opts, xhrOpts) { 565 | opts = opts || {}; 566 | xhrOpts = xhrOpts || {}; 567 | 568 | //var request = extend(req, opts); 569 | var request = extend({ successStatus: [200], method: "GET" }, req); 570 | 571 | // encode request.data onto URL 572 | if (request.data && request.method !== "POST" && request.method !== "PUT") { 573 | request.url += (request.url.indexOf("?") > -1 ? "&" : "?") + toQueryString(request.data); 574 | delete request.data; 575 | } 576 | 577 | successStatus = isArray(request.successStatus) ? request.successStatus : Array(request.successStatus); 578 | 579 | var xhr = Ti.Network.createHTTPClient(extend({ 580 | onload: function(e) { 581 | var req = e.source; 582 | try { 583 | var resp = httpData(req, "json"); 584 | } 585 | catch (err) { 586 | Ti.API.error(err.name + ": " + err.message); 587 | if (opts.failure) { 588 | opts.failure(req); 589 | } 590 | else { 591 | Ti.API.error(err); 592 | } 593 | } 594 | 595 | if (inArray(req.status, successStatus) >= 0) { 596 | if (opts.success) { 597 | opts.success(resp); 598 | } 599 | } 600 | else if (opts.failure) { 601 | opts.failure(req); 602 | } 603 | else { 604 | Ti.API.error("bad response: " + req.status + " " + req.responseText); 605 | } 606 | }, 607 | onerror: function(e) { 608 | var req = e.source; 609 | if (opts.failure) { 610 | opts.failure(req); 611 | } 612 | else { 613 | Ti.API.error("AJAX error: " + JSON.stringify(e) + " " + req.status + " " + req.responseText); 614 | } 615 | } 616 | }, xhrOpts)); 617 | 618 | xhr.open(request.method, request.url); 619 | Ti.API.debug(request.method + " "+request.url); 620 | 621 | if (xhr.setMaxRedirects) { 622 | xhr.setMaxRedirects(0); 623 | } 624 | 625 | // basic auth 626 | if (opts.username) { 627 | xhr.setRequestHeader('Authorization', 'Basic ' + Ti.Utils.base64encode(opts.username+':'+opts.password)); 628 | } 629 | 630 | // generic Accept header, may be overwritten below 631 | xhr.setRequestHeader("Accept", "*/*"); 632 | 633 | if (request.method === "POST" || request.method === "PUT") { 634 | xhr.setRequestHeader("Content-Type", "application/json"); 635 | } 636 | 637 | // extra headers 638 | if (request.headers) { 639 | for (var header in request.headers) { 640 | xhr.setRequestHeader(header, request.headers[header]); 641 | } 642 | } 643 | 644 | xhr.send(isPlainObject(request.data) ? JSON.stringify(request.data) : request.data); 645 | } 646 | 647 | /* 648 | * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined 649 | * in FIPS PUB 180-1 650 | * Version 2.1a Copyright Paul Johnston 2000 - 2002. 651 | * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet 652 | * Distributed under the BSD License 653 | * See http://pajhome.org.uk/crypt/md5 for details. 654 | */ 655 | 656 | /* 657 | * Configurable variables. You may need to tweak these to be compatible with 658 | * the server-side, but the defaults work in most cases. 659 | */ 660 | var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ 661 | var b64pad = "="; /* base-64 pad character. "=" for strict RFC compliance */ 662 | var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ 663 | 664 | /* 665 | * These are the functions you'll usually want to call 666 | * They take string arguments and return either hex or base-64 encoded strings 667 | */ 668 | function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));} 669 | function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));} 670 | function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));} 671 | function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));} 672 | function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));} 673 | function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));} 674 | 675 | /* 676 | * Perform a simple self-test to see if the VM is working 677 | */ 678 | function sha1_vm_test() 679 | { 680 | return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d"; 681 | } 682 | 683 | /* 684 | * Calculate the SHA-1 of an array of big-endian words, and a bit length 685 | */ 686 | function core_sha1(x, len) 687 | { 688 | /* append padding */ 689 | x[len >> 5] |= 0x80 << (24 - len % 32); 690 | x[((len + 64 >> 9) << 4) + 15] = len; 691 | 692 | var w = Array(80); 693 | var a = 1732584193; 694 | var b = -271733879; 695 | var c = -1732584194; 696 | var d = 271733878; 697 | var e = -1009589776; 698 | 699 | for(var i = 0; i < x.length; i += 16) 700 | { 701 | var olda = a; 702 | var oldb = b; 703 | var oldc = c; 704 | var oldd = d; 705 | var olde = e; 706 | 707 | for(var j = 0; j < 80; j++) 708 | { 709 | if(j < 16) w[j] = x[i + j]; 710 | else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1); 711 | var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), 712 | safe_add(safe_add(e, w[j]), sha1_kt(j))); 713 | e = d; 714 | d = c; 715 | c = rol(b, 30); 716 | b = a; 717 | a = t; 718 | } 719 | 720 | a = safe_add(a, olda); 721 | b = safe_add(b, oldb); 722 | c = safe_add(c, oldc); 723 | d = safe_add(d, oldd); 724 | e = safe_add(e, olde); 725 | } 726 | return Array(a, b, c, d, e); 727 | 728 | } 729 | 730 | /* 731 | * Perform the appropriate triplet combination function for the current 732 | * iteration 733 | */ 734 | function sha1_ft(t, b, c, d) 735 | { 736 | if(t < 20) return (b & c) | ((~b) & d); 737 | if(t < 40) return b ^ c ^ d; 738 | if(t < 60) return (b & c) | (b & d) | (c & d); 739 | return b ^ c ^ d; 740 | } 741 | 742 | /* 743 | * Determine the appropriate additive constant for the current iteration 744 | */ 745 | function sha1_kt(t) 746 | { 747 | return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : 748 | (t < 60) ? -1894007588 : -899497514; 749 | } 750 | 751 | /* 752 | * Calculate the HMAC-SHA1 of a key and some data 753 | */ 754 | function core_hmac_sha1(key, data) 755 | { 756 | var bkey = str2binb(key); 757 | if(bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz); 758 | 759 | var ipad = Array(16), opad = Array(16); 760 | for(var i = 0; i < 16; i++) 761 | { 762 | ipad[i] = bkey[i] ^ 0x36363636; 763 | opad[i] = bkey[i] ^ 0x5C5C5C5C; 764 | } 765 | 766 | var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz); 767 | return core_sha1(opad.concat(hash), 512 + 160); 768 | } 769 | 770 | /* 771 | * Add integers, wrapping at 2^32. This uses 16-bit operations internally 772 | * to work around bugs in some JS interpreters. 773 | */ 774 | function safe_add(x, y) 775 | { 776 | var lsw = (x & 0xFFFF) + (y & 0xFFFF); 777 | var msw = (x >> 16) + (y >> 16) + (lsw >> 16); 778 | return (msw << 16) | (lsw & 0xFFFF); 779 | } 780 | 781 | /* 782 | * Bitwise rotate a 32-bit number to the left. 783 | */ 784 | function rol(num, cnt) 785 | { 786 | return (num << cnt) | (num >>> (32 - cnt)); 787 | } 788 | 789 | /* 790 | * Convert an 8-bit or 16-bit string to an array of big-endian words 791 | * In 8-bit function, characters >255 have their hi-byte silently ignored. 792 | */ 793 | function str2binb(str) 794 | { 795 | var bin = Array(); 796 | var mask = (1 << chrsz) - 1; 797 | for(var i = 0; i < str.length * chrsz; i += chrsz) 798 | bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32); 799 | return bin; 800 | } 801 | 802 | /* 803 | * Convert an array of big-endian words to a string 804 | */ 805 | function binb2str(bin) 806 | { 807 | var str = ""; 808 | var mask = (1 << chrsz) - 1; 809 | for(var i = 0; i < bin.length * 32; i += chrsz) 810 | str += String.fromCharCode((bin[i>>5] >>> (32 - chrsz - i%32)) & mask); 811 | return str; 812 | } 813 | 814 | /* 815 | * Convert an array of big-endian words to a hex string. 816 | */ 817 | function binb2hex(binarray) 818 | { 819 | var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; 820 | var str = ""; 821 | for(var i = 0; i < binarray.length * 4; i++) 822 | { 823 | str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) + 824 | hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF); 825 | } 826 | return str; 827 | } 828 | 829 | /* 830 | * Convert an array of big-endian words to a base-64 string 831 | */ 832 | function binb2b64(binarray) 833 | { 834 | var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 835 | var str = ""; 836 | for(var i = 0; i < binarray.length * 4; i += 3) 837 | { 838 | var triplet = (((binarray[i >> 2] >> 8 * (3 - i %4)) & 0xFF) << 16) 839 | | (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 ) 840 | | ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF); 841 | for(var j = 0; j < 4; j++) 842 | { 843 | if(i * 8 + j * 6 > binarray.length * 32) str += b64pad; 844 | else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); 845 | } 846 | } 847 | return str; 848 | } 849 | 850 | /* Copyright (C) 1999 Masanao Izumo 851 | * Version: 1.0 852 | * LastModified: Dec 25 1999 853 | * This library is free. You can redistribute it and/or modify it. 854 | */ 855 | /* Modified by Chris Anderson to not use CommonJS */ 856 | /* Modified by Dan Webb not to require Narwhal's binary library */ 857 | 858 | var Base64 = {}; 859 | (function(exports) { 860 | 861 | var encodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 862 | var decodeChars = [ 863 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 864 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 865 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 866 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, 867 | -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 868 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, 869 | -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 870 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 871 | ]; 872 | 873 | exports.encode = function (str) { 874 | var out, i, length; 875 | var c1, c2, c3; 876 | 877 | length = len(str); 878 | i = 0; 879 | out = []; 880 | while(i < length) { 881 | c1 = str.charCodeAt(i++) & 0xff; 882 | if(i == length) 883 | { 884 | out.push(encodeChars.charCodeAt(c1 >> 2)); 885 | out.push(encodeChars.charCodeAt((c1 & 0x3) << 4)); 886 | out.push("=".charCodeAt(0)); 887 | out.push("=".charCodeAt(0)); 888 | break; 889 | } 890 | c2 = str.charCodeAt(i++); 891 | if(i == length) 892 | { 893 | out.push(encodeChars.charCodeAt(c1 >> 2)); 894 | out.push(encodeChars.charCodeAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4))); 895 | out.push(encodeChars.charCodeAt((c2 & 0xF) << 2)); 896 | out.push("=".charCodeAt(0)); 897 | break; 898 | } 899 | c3 = str.charCodeAt(i++); 900 | out.push(encodeChars.charCodeAt(c1 >> 2)); 901 | out.push(encodeChars.charCodeAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4))); 902 | out.push(encodeChars.charCodeAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6))); 903 | out.push(encodeChars.charCodeAt(c3 & 0x3F)); 904 | } 905 | 906 | var str = ""; 907 | out.forEach(function(chr) { str += String.fromCharCode(chr) }); 908 | return str; 909 | }; 910 | 911 | exports.decode = function (str) { 912 | var c1, c2, c3, c4; 913 | var i, length, out; 914 | 915 | length = len(str); 916 | i = 0; 917 | out = []; 918 | while(i < length) { 919 | /* c1 */ 920 | do { 921 | c1 = decodeChars[str.charCodeAt(i++) & 0xff]; 922 | } while(i < length && c1 == -1); 923 | if(c1 == -1) 924 | break; 925 | 926 | /* c2 */ 927 | do { 928 | c2 = decodeChars[str.charCodeAt(i++) & 0xff]; 929 | } while(i < length && c2 == -1); 930 | if(c2 == -1) 931 | break; 932 | 933 | out.push(String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4))); 934 | 935 | /* c3 */ 936 | do { 937 | c3 = str.charCodeAt(i++) & 0xff; 938 | if(c3 == 61) 939 | return out.join(''); 940 | c3 = decodeChars[c3]; 941 | } while(i < length && c3 == -1); 942 | if(c3 == -1) 943 | break; 944 | 945 | out.push(String.fromCharCode(((c2 & 0xF) << 4) | ((c3 & 0x3C) >> 2))); 946 | 947 | /* c4 */ 948 | do { 949 | c4 = str.charCodeAt(i++) & 0xff; 950 | if(c4 == 61) 951 | return out.join(''); 952 | c4 = decodeChars[c4]; 953 | } while(i < length && c4 == -1); 954 | 955 | if(c4 == -1) 956 | break; 957 | 958 | out.push(String.fromCharCode(((c3 & 0x03) << 6) | c4)); 959 | } 960 | 961 | return out.join(''); 962 | }; 963 | 964 | var len = function (object) { 965 | if (object.length !== undefined) { 966 | return object.length; 967 | } else if (object.getLength !== undefined) { 968 | return object.getLength(); 969 | } else { 970 | return undefined; 971 | } 972 | }; 973 | })(Base64); 974 | 975 | 976 | var class2type = []; 977 | (function(o){ 978 | var types = ["Boolean","Number","String","Function","Array","Date","RegExp","Object"]; 979 | for (var i=0, length=types.length; i < length; i++) { 980 | var name = types[i]; 981 | var key = "[object " + name + "]"; 982 | o[key] = name.toLowerCase(); 983 | } 984 | }(class2type)); 985 | 986 | var hasOwn = Object.prototype.hasOwnProperty, 987 | toString = Object.prototype.toString; 988 | 989 | function type(obj) { 990 | return obj == null ? String(obj) : class2type[toString.call(obj)] || "object"; 991 | } 992 | 993 | function isPlainObject(obj) { 994 | if ( !obj || type(obj) !== "object") { 995 | return false; 996 | } 997 | 998 | // Not own constructor property must be Object 999 | if ( obj.constructor && 1000 | !hasOwn.call(obj, "constructor") && 1001 | !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { 1002 | return false; 1003 | } 1004 | 1005 | // Own properties are enumerated firstly, so to speed up, 1006 | // if last one is own, then all properties are own. 1007 | 1008 | var key; 1009 | for (key in obj) {} 1010 | 1011 | return key === undefined || hasOwn.call( obj, key ); 1012 | } 1013 | 1014 | function isEmptyObject(obj) { 1015 | for (var name in obj) { 1016 | return false; 1017 | } 1018 | return true; 1019 | } 1020 | 1021 | function isArray(obj) { 1022 | return type(obj) === "array"; 1023 | } 1024 | 1025 | function isFunction(obj) { 1026 | return type(obj) === "function"; 1027 | } 1028 | 1029 | function each(object, callback, args) { 1030 | var name, i = 0, 1031 | length = object.length, 1032 | isObj = length === undefined || isFunction( object ); 1033 | 1034 | if ( args ) { 1035 | if ( isObj ) { 1036 | for ( name in object ) { 1037 | if ( callback.apply( object[ name ], args ) === false ) { 1038 | break; 1039 | } 1040 | } 1041 | } else { 1042 | for ( ; i < length; ) { 1043 | if ( callback.apply( object[ i++ ], args ) === false ) { 1044 | break; 1045 | } 1046 | } 1047 | } 1048 | 1049 | // A special, fast, case for the most common use of each 1050 | } else { 1051 | if ( isObj ) { 1052 | for ( name in object ) { 1053 | if ( callback.call( object[ name ], name, object[ name ] ) === false ) { 1054 | break; 1055 | } 1056 | } 1057 | } else { 1058 | for ( ; i < length; ) { 1059 | if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { 1060 | break; 1061 | } 1062 | } 1063 | } 1064 | } 1065 | 1066 | return object; 1067 | } 1068 | 1069 | function extend() { 1070 | var options, name, src, copy, copyIsArray, clone, 1071 | target = arguments[0] || {}, 1072 | i = 1, 1073 | length = arguments.length, 1074 | deep = false; 1075 | 1076 | // Handle a deep copy situation 1077 | if ( typeof target === "boolean" ) { 1078 | deep = target; 1079 | target = arguments[1] || {}; 1080 | // skip the boolean and the target 1081 | i = 2; 1082 | } 1083 | 1084 | // Handle case when target is a string or something (possible in deep copy) 1085 | if ( typeof target !== "object" && !isFunction(target) ) { 1086 | target = {}; 1087 | } 1088 | 1089 | // extend jQuery itself if only one argument is passed 1090 | if ( length === i ) { 1091 | target = this; 1092 | --i; 1093 | } 1094 | 1095 | for ( ; i < length; i++ ) { 1096 | // Only deal with non-null/undefined values 1097 | if ( (options = arguments[ i ]) != null ) { 1098 | // Extend the base object 1099 | for ( name in options ) { 1100 | if (options.hasOwnProperty(name)) { 1101 | src = target[ name ]; 1102 | copy = options[ name ]; 1103 | 1104 | // Prevent never-ending loop 1105 | if ( target === copy ) { 1106 | continue; 1107 | } 1108 | 1109 | // Recurse if we're merging plain objects or arrays 1110 | if ( deep && copy && ( isPlainObject(copy) || (copyIsArray = isArray(copy)) ) ) { 1111 | if ( copyIsArray ) { 1112 | copyIsArray = false; 1113 | clone = src && isArray(src) ? src : []; 1114 | 1115 | } else { 1116 | clone = src && isPlainObject(src) ? src : {}; 1117 | } 1118 | 1119 | // Never move original objects, clone them 1120 | target[ name ] = extend( deep, clone, copy ); 1121 | 1122 | // Don't bring in undefined values 1123 | } else if ( copy !== undefined ) { 1124 | target[ name ] = copy; 1125 | } 1126 | } 1127 | } 1128 | } 1129 | } 1130 | 1131 | // Return the modified object 1132 | return target; 1133 | } 1134 | 1135 | function inArray(elem, array) { 1136 | if (Array.prototype.indexOf) { 1137 | return array.indexOf(elem); 1138 | } 1139 | 1140 | for (var i=0, length=array.length; i < length; i++) { 1141 | if (array[i] === elem) { 1142 | return i; 1143 | } 1144 | } 1145 | 1146 | return -1; 1147 | } 1148 | 1149 | }(couchdb_client)); 1150 | 1151 | -------------------------------------------------------------------------------- /mobile/android/build.properties: -------------------------------------------------------------------------------- 1 | titanium.platform=/Library/Application Support/Titanium/mobilesdk/osx/1.6.2/android 2 | android.platform=/opt/android-sdk/platforms/android-4 3 | google.apis=/opt/android-sdk/add-ons/addon_google_apis_google_inc_4 -------------------------------------------------------------------------------- /mobile/android/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Ant build script for Titanium Android module couchdb_client 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /mobile/android/documentation/index.md: -------------------------------------------------------------------------------- 1 | # couchdb_client Module 2 | 3 | ## Description 4 | 5 | TODO: Enter your module description here 6 | 7 | ## Accessing the couchdb_client Module 8 | 9 | To access this module from JavaScript, you would do the following: 10 | 11 | var couchdb_client = require("com.obscure.couchdb_client"); 12 | 13 | The couchdb_client variable is a reference to the Module object. 14 | 15 | ## Reference 16 | 17 | TODO: If your module has an API, you should document 18 | the reference here. 19 | 20 | ### ___PROJECTNAMEASIDENTIFIER__.function 21 | 22 | TODO: This is an example of a module function. 23 | 24 | ### ___PROJECTNAMEASIDENTIFIER__.property 25 | 26 | TODO: This is an example of a module property. 27 | 28 | ## Usage 29 | 30 | TODO: Enter your usage example here 31 | 32 | ## Author 33 | 34 | TODO: Enter your author name, email and other contact 35 | details you want to share here. 36 | 37 | ## License 38 | 39 | TODO: Enter your license/legal information here. 40 | -------------------------------------------------------------------------------- /mobile/android/example/app.js: -------------------------------------------------------------------------------- 1 | // This is a test harness for your module 2 | // You should do something interesting in this harness 3 | // to test out the module and to provide instructions 4 | // to users on how to use it by example. 5 | 6 | Ti.include("com.obscure.couchdb_client.js"); 7 | 8 | // open a single window 9 | var window = Ti.UI.createWindow({ 10 | backgroundColor:'white' 11 | }); 12 | var label = Ti.UI.createLabel({ 13 | text: "running tests" 14 | }); 15 | window.add(label); 16 | window.open(); 17 | 18 | couchdb_client.urlPrefix = "http://10.8.17.113:5984"; 19 | 20 | couchdb_client.allDbs({ 21 | success: function(data) { 22 | label.text = JSON.stringify(data); 23 | } 24 | }); 25 | -------------------------------------------------------------------------------- /mobile/android/hooks/README: -------------------------------------------------------------------------------- 1 | These files are not yet supported as of 1.4.0 but will be in a near future release. 2 | -------------------------------------------------------------------------------- /mobile/android/hooks/add.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # This is the module project add hook that will be 4 | # called when your module is added to a project 5 | # 6 | import os, sys 7 | 8 | def dequote(s): 9 | if s[0:1] == '"': 10 | return s[1:-1] 11 | return s 12 | 13 | def main(args,argc): 14 | # You will get the following command line arguments 15 | # in the following order: 16 | # 17 | # project_dir = the full path to the project root directory 18 | # project_type = the type of project (desktop, mobile, ipad) 19 | # project_name = the name of the project 20 | # 21 | project_dir = dequote(os.path.expanduser(args[1])) 22 | project_type = dequote(args[2]) 23 | project_name = dequote(args[3]) 24 | 25 | # TODO: write your add hook here (optional) 26 | 27 | 28 | # exit 29 | sys.exit(0) 30 | 31 | 32 | 33 | if __name__ == '__main__': 34 | main(sys.argv,len(sys.argv)) 35 | 36 | -------------------------------------------------------------------------------- /mobile/android/hooks/install.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # This is the module install hook that will be 4 | # called when your module is first installed 5 | # 6 | import os, sys 7 | 8 | def main(args,argc): 9 | 10 | # TODO: write your install hook here (optional) 11 | 12 | # exit 13 | sys.exit(0) 14 | 15 | 16 | 17 | if __name__ == '__main__': 18 | main(sys.argv,len(sys.argv)) 19 | 20 | -------------------------------------------------------------------------------- /mobile/android/hooks/remove.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # This is the module project remove hook that will be 4 | # called when your module is remove from a project 5 | # 6 | import os, sys 7 | 8 | def dequote(s): 9 | if s[0:1] == '"': 10 | return s[1:-1] 11 | return s 12 | 13 | def main(args,argc): 14 | # You will get the following command line arguments 15 | # in the following order: 16 | # 17 | # project_dir = the full path to the project root directory 18 | # project_type = the type of project (desktop, mobile, ipad) 19 | # project_name = the name of the project 20 | # 21 | project_dir = dequote(os.path.expanduser(args[1])) 22 | project_type = dequote(args[2]) 23 | project_name = dequote(args[3]) 24 | 25 | # TODO: write your remove hook here (optional) 26 | 27 | # exit 28 | sys.exit(0) 29 | 30 | 31 | 32 | if __name__ == '__main__': 33 | main(sys.argv,len(sys.argv)) 34 | 35 | -------------------------------------------------------------------------------- /mobile/android/hooks/uninstall.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # This is the module uninstall hook that will be 4 | # called when your module is uninstalled 5 | # 6 | import os, sys 7 | 8 | def main(args,argc): 9 | 10 | # TODO: write your uninstall hook here (optional) 11 | 12 | # exit 13 | sys.exit(0) 14 | 15 | 16 | if __name__ == '__main__': 17 | main(sys.argv,len(sys.argv)) 18 | 19 | -------------------------------------------------------------------------------- /mobile/android/manifest: -------------------------------------------------------------------------------- 1 | # 2 | # this is your module manifest and used by Titanium 3 | # during compilation, packaging, distribution, etc. 4 | # 5 | version: 1.0 6 | description: CouchDB Client Module 7 | author: Paul Mietz Egli 8 | license: Apache 2.0 9 | copyright: Copyright (c) 2011 Paul Mietz Egli 10 | 11 | 12 | 13 | # these should not be edited 14 | name: couchdb_client 15 | moduleid: com.obscure.couchdb_client 16 | guid: 8c0b158d-5d5e-46ad-a709-ca404cb046b1 17 | platform: android 18 | minsdk: 1.6.2 19 | -------------------------------------------------------------------------------- /mobile/android/timodule.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /mobile/ios/.gitignore: -------------------------------------------------------------------------------- 1 | tmp 2 | bin 3 | build 4 | *.zip 5 | .svn 6 | -------------------------------------------------------------------------------- /mobile/ios/Classes/.gitignore: -------------------------------------------------------------------------------- 1 | ComObscureCouchdb_client.h 2 | ComObscureCouchdb_client.m 3 | -------------------------------------------------------------------------------- /mobile/ios/Classes/ComObscureCouchdb_clientModule.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Your Copyright Here 3 | * 4 | * Appcelerator Titanium is Copyright (c) 2009-2010 by Appcelerator, Inc. 5 | * and licensed under the Apache Public License (version 2) 6 | */ 7 | #import "TiModule.h" 8 | 9 | @interface ComObscureCouchdb_clientModule : TiModule 10 | { 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /mobile/ios/Classes/ComObscureCouchdb_clientModule.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Your Copyright Here 3 | * 4 | * Appcelerator Titanium is Copyright (c) 2009-2010 by Appcelerator, Inc. 5 | * and licensed under the Apache Public License (version 2) 6 | */ 7 | #import "ComObscureCouchdb_clientModule.h" 8 | #import "TiBase.h" 9 | #import "TiHost.h" 10 | #import "TiUtils.h" 11 | 12 | @implementation ComObscureCouchdb_clientModule 13 | 14 | #pragma mark Internal 15 | 16 | // this is generated for your module, please do not change it 17 | -(id)moduleGUID 18 | { 19 | return @"6474234f-0415-4683-969e-aa0073c86620"; 20 | } 21 | 22 | // this is generated for your module, please do not change it 23 | -(NSString*)moduleId 24 | { 25 | return @"com.obscure.couchdb_client"; 26 | } 27 | 28 | #pragma mark Lifecycle 29 | 30 | -(void)startup 31 | { 32 | // this method is called when the module is first loaded 33 | // you *must* call the superclass 34 | [super startup]; 35 | 36 | NSLog(@"[INFO] %@ loaded",self); 37 | } 38 | 39 | -(void)shutdown:(id)sender 40 | { 41 | // this method is called when the module is being unloaded 42 | // typically this is during shutdown. make sure you don't do too 43 | // much processing here or the app will be quit forceably 44 | 45 | // you *must* call the superclass 46 | [super shutdown:sender]; 47 | } 48 | 49 | #pragma mark Cleanup 50 | 51 | -(void)dealloc 52 | { 53 | // release any resources that have been retained by the module 54 | [super dealloc]; 55 | } 56 | 57 | #pragma mark Internal Memory Management 58 | 59 | -(void)didReceiveMemoryWarning:(NSNotification*)notification 60 | { 61 | // optionally release any resources that can be dynamically 62 | // reloaded once memory is available - such as caches 63 | [super didReceiveMemoryWarning:notification]; 64 | } 65 | 66 | #pragma mark Listener Notifications 67 | 68 | -(void)_listenerAdded:(NSString *)type count:(int)count 69 | { 70 | if (count == 1 && [type isEqualToString:@"my_event"]) 71 | { 72 | // the first (of potentially many) listener is being added 73 | // for event named 'my_event' 74 | } 75 | } 76 | 77 | -(void)_listenerRemoved:(NSString *)type count:(int)count 78 | { 79 | if (count == 0 && [type isEqualToString:@"my_event"]) 80 | { 81 | // the last listener called for event named 'my_event' has 82 | // been removed, we can optionally clean up any resources 83 | // since no body is listening at this point for that event 84 | } 85 | } 86 | 87 | #pragma Public APIs 88 | 89 | -(id)example:(id)args 90 | { 91 | // example method 92 | return @"hello world"; 93 | } 94 | 95 | -(id)exampleProp 96 | { 97 | // example property getter 98 | return @"hello world"; 99 | } 100 | 101 | -(void)exampleProp:(id)value 102 | { 103 | // example property setter 104 | } 105 | 106 | @end 107 | -------------------------------------------------------------------------------- /mobile/ios/Classes/ComObscureCouchdb_clientModuleAssets.h: -------------------------------------------------------------------------------- 1 | /** 2 | * This is a generated file. Do not edit or your changes will be lost 3 | */ 4 | 5 | @interface ComObscureCouchdb_clientModuleAssets : NSObject 6 | { 7 | } 8 | - (NSData*) moduleAsset; 9 | @end 10 | -------------------------------------------------------------------------------- /mobile/ios/Classes/ComObscureCouchdb_clientModuleAssets.m: -------------------------------------------------------------------------------- 1 | /** 2 | * This is a generated file. Do not edit or your changes will be lost 3 | */ 4 | #import "ComObscureCouchdb_clientModuleAssets.h" 5 | 6 | extern NSData * dataWithHexString (NSString * hexString); 7 | 8 | @implementation ComObscureCouchdb_clientModuleAssets 9 | 10 | - (NSData*) moduleAsset 11 | { 12 | return dataWithHexString(@"2866756e6374696f6e286d6f64756c65297b66756e6374696f6e207573657244622863616c6c6261636b297b6d6f64756c652e73657373696f6e287b737563636573733a66756e6374696f6e2872657370297b766172207573657244623d6d6f64756c652e646228726573702e696e666f2e61757468656e7469636174696f6e5f6462293b63616c6c6261636b28757365724462293b7d7d293b7d0a66756e6374696f6e207072657061726555736572446f6328757365725f646f632c6e65775f70617373776f7264297b696628747970656f66206865785f736861313d3d22756e646566696e656422297b54692e4150492e6572726f7228226372656174696e672061207573657220646f6320726571756972657320736861312e6a7320746f206265206c6f6164656420696e20746865207061676522293b72657475726e3b7d0a76617220757365725f7072656669783d226f72672e636f75636864622e757365723a223b757365725f646f632e5f69643d757365725f646f632e5f69647c7c757365725f7072656669782b757365725f646f632e6e616d653b6966286e65775f70617373776f7264297b757365725f646f632e73616c743d5f6e65775555494428293b757365725f646f632e70617373776f72645f7368613d6865785f73686131286e65775f70617373776f72642b757365725f646f632e73616c74293b7d0a757365725f646f632e747970653d2275736572223b69662821757365725f646f632e726f6c6573297b757365725f646f632e726f6c65733d5b5d3b7d0a72657475726e20757365725f646f633b7d0a66756e6374696f6e20656e636f6465446f63496428646f634944297b7661722070617274733d646f6349442e73706c697428222f22293b69662870617274735b305d3d3d225f64657369676e22297b70617274732e736869667428293b72657475726e225f64657369676e2f222b656e636f6465555249436f6d706f6e656e742870617274732e6a6f696e28272f2729293b7d0a72657475726e20656e636f6465555249436f6d706f6e656e7428646f634944293b7d0a76617220766965774f7074696f6e733d5b226b6579222c2273746172746b6579222c2273746172746b65795f646f636964222c22656e646b6579222c22656e646b65795f646f636964222c226c696d6974222c227374616c65222c2264657363656e64696e67222c22736b6970222c2267726f7570222c2267726f75705f6c6576656c222c22726564756365222c22696e636c7564655f646f6373222c22696e636c75736976655f656e64225d3b66756e6374696f6e20656e636f6465566965774f7074696f6e73286f626a297b766172206275663d5b5d3b666f7228766172206b657920696e206f626a297b696628696e4172726179286b65792c766965774f7074696f6e73293e2d31297b6275662e7075736828656e636f6465555249436f6d706f6e656e74286b6579292b223d222b656e636f6465555249436f6d706f6e656e74284a534f4e2e737472696e67696679286f626a5b6b65795d2929293b7d7d0a72657475726e206275662e6a6f696e28272627293b7d0a6d6f64756c652e75726c5072656669783d27273b6d6f64756c652e616c6c4462733d66756e6374696f6e286f7074696f6e73297b616a6178287b75726c3a746869732e75726c5072656669782b222f5f616c6c5f646273227d2c6f7074696f6e73293b7d3b6d6f64756c652e696e666f3d66756e6374696f6e286f7074696f6e73297b616a6178287b75726c3a746869732e75726c5072656669782b222f222b286f7074696f6e732e64626e616d657c7c2222297d2c6f7074696f6e73293b7d3b6d6f64756c652e636f6e6669673d66756e6374696f6e286f7074696f6e732c73656374696f6e2c6b65792c76616c7565297b766172207265713d7b75726c3a746869732e75726c5072656669782b222f5f636f6e6669672f227d3b69662873656374696f6e297b7265712e75726c2b3d656e636f6465555249436f6d706f6e656e742873656374696f6e292b222f223b6966286b6579297b7265712e75726c2b3d656e636f6465555249436f6d706f6e656e74286b6579293b7d7d0a69662876616c75653d3d3d6e756c6c297b7265712e6d6574686f643d2244454c455445223b7d0a656c73652069662876616c7565213d3d756e646566696e6564297b7265712e6d6574686f643d22505554223b7265712e646174613d4a534f4e2e737472696e676966792876616c7565293b7d0a616a6178287265712c6f7074696f6e73293b7d3b6d6f64756c652e6c6f67696e3d66756e6374696f6e286f7074696f6e732c757365726e616d652c70617373776f7264297b746869732e73657373696f6e28657874656e64287b757365726e616d653a757365726e616d652c70617373776f72643a70617373776f72647d2c6f7074696f6e7329293b7d3b6d6f64756c652e6c6f676f75743d66756e6374696f6e286f7074696f6e73297b616a6178287b6d6574686f643a2244454c455445222c75726c3a746869732e75726c5072656669782b222f5f73657373696f6e222c757365726e616d653a225f222c70617373776f72643a225f227d2c6f7074696f6e73293b7d3b6d6f64756c652e73657373696f6e3d66756e6374696f6e286f7074696f6e73297b616a6178287b75726c3a746869732e75726c5072656669782b222f5f73657373696f6e222c686561646572733a7b22416363657074223a226170706c69636174696f6e2f6a736f6e227d7d2c6f7074696f6e73293b7d3b6d6f64756c652e7369676e75703d66756e6374696f6e28757365725f646f632c70617373776f72642c6f7074696f6e73297b6f7074696f6e733d6f7074696f6e737c7c7b7d3b757365725f646f633d7072657061726555736572446f6328757365725f646f632c70617373776f7264293b7573657244622866756e6374696f6e286462297b64622e73617665446f6328757365725f646f632c6f7074696f6e73293b7d293b7d3b6d6f64756c652e64623d66756e6374696f6e286e616d652c64625f6f707473297b64625f6f7074733d64625f6f7074737c7c7b7d3b72657475726e7b6e616d653a6e616d652c7572693a746869732e75726c5072656669782b222f222b656e636f6465555249436f6d706f6e656e74286e616d65292b222f222c636f6d706163743a66756e6374696f6e286f7074696f6e73297b616a6178287b6d6574686f643a22504f5354222c75726c3a746869732e7572692b225f636f6d70616374222c737563636573735374617475733a3230327d2c6f7074696f6e73293b7d2c76696577436c65616e75703a66756e6374696f6e286f7074696f6e73297b616a6178287b6d6574686f643a22504f5354222c75726c3a746869732e7572692b225f766965775f636c65616e7570222c737563636573735374617475733a3230327d2c6f7074696f6e73293b7d2c636f6d70616374566965773a66756e6374696f6e2867726f75706e616d652c6f7074696f6e73297b616a6178287b6d6574686f643a22504f5354222c75726c3a746869732e7572692b225f636f6d706163742f222b67726f75706e616d652c737563636573735374617475733a3230327d2c6f7074696f6e73293b7d2c6372656174653a66756e6374696f6e286f7074696f6e73297b616a6178287b6d6574686f643a22505554222c75726c3a746869732e7572692c737563636573735374617475733a3230317d2c6f7074696f6e73293b7d2c64726f703a66756e6374696f6e286f7074696f6e73297b616a6178287b6d6574686f643a2244454c455445222c75726c3a746869732e7572697d2c6f7074696f6e73293b7d2c696e666f3a66756e6374696f6e286f7074696f6e73297b616a6178287b75726c3a746869732e7572697d2c6f7074696f6e73293b7d2c616c6c446f63733a66756e6374696f6e286f7074696f6e73297b766172206d6574686f643d22474554223b76617220646174613d6e756c6c3b6966286f7074696f6e735b226b657973225d297b6d6574686f643d22504f5354223b766172206b6579733d6f7074696f6e735b226b657973225d3b64656c657465206f7074696f6e735b226b657973225d3b646174613d7b226b657973223a6b6579737d3b7d0a616a6178287b6d6574686f643a6d6574686f642c646174613a646174612c75726c3a746869732e7572692b225f616c6c5f646f6373227d2c6f7074696f6e73293b7d2c616c6c44657369676e446f63733a66756e6374696f6e286f7074696f6e73297b746869732e616c6c446f637328657874656e64287b73746172746b65793a225f64657369676e222c656e646b65793a225f64657369676e30227d2c6f7074696f6e7329293b7d2c6f70656e446f633a66756e6374696f6e28646f6349642c6f7074696f6e73297b616a6178287b75726c3a746869732e7572692b656e636f6465446f63496428646f634964297d2c6f7074696f6e73293b7d2c73617665446f633a66756e6374696f6e28646f632c6f7074696f6e73297b6f7074696f6e733d6f7074696f6e737c7c7b7d3b7661722064623d746869733b696628646f632e5f69643d3d3d756e646566696e6564297b766172206d6574686f643d22504f5354223b766172207572693d746869732e7572693b7d0a656c73657b766172206d6574686f643d22505554223b766172207572693d746869732e7572692b656e636f6465446f63496428646f632e5f6964293b7d0a616a6178287b6d6574686f643a6d6574686f642c75726c3a7572692c646174613a646f632c737563636573735374617475733a5b3230302c3230312c3230325d7d2c6f7074696f6e73293b7d2c62756c6b536176653a66756e6374696f6e28646f63732c6f7074696f6e73297b616a6178287b6d6574686f643a22504f5354222c75726c3a746869732e7572692b225f62756c6b5f646f6373222c646174613a646f63732c7d2c6f7074696f6e73293b7d2c72656d6f7665446f633a66756e6374696f6e28646f632c6f7074696f6e73297b616a6178287b6d6574686f643a2244454c455445222c646174613a7b7265763a646f632e5f7265767d2c75726c3a746869732e7572692b656e636f6465446f63496428646f632e5f6964297d2c6f7074696f6e73293b7d2c62756c6b52656d6f76653a66756e6374696f6e28646f63732c6f7074696f6e73297b646f63732e646f63733d6561636828646f63732e646f63732c66756e6374696f6e28692c646f63297b646f632e5f64656c657465643d747275653b7d293b616a6178287b6d6574686f643a22504f5354222c737563636573735374617475733a3230312c75726c3a746869732e7572692b225f62756c6b5f646f6373222c646174613a646f63737d2c6f7074696f6e73293b7d2c636f7079446f633a66756e6374696f6e28736f757263652c64657374696e6174696f6e2c6f7074696f6e73297b6966282164657374696e6174696f6e297b7d0a616a6178287b6d6574686f643a22434f5059222c75726c3a746869732e7572692b656e636f6465446f63496428736f75726365292c737563636573735374617475733a3230312c686561646572733a7b2244657374696e6174696f6e223a64657374696e6174696f6e7d7d2c6f7074696f6e73293b7d2c71756572793a66756e6374696f6e286d617046756e2c72656475636546756e2c6c616e67756167652c6f7074696f6e73297b6c616e67756167653d6c616e67756167657c7c226a617661736372697074223b696628747970656f66286d617046756e29213d3d22737472696e6722297b6d617046756e3d6d617046756e2e746f536f757263653f6d617046756e2e746f536f7572636528293a2228222b6d617046756e2e746f537472696e6728292b2229223b7d0a76617220626f64793d7b6c616e67756167653a6c616e67756167652c6d61703a6d617046756e7d3b69662872656475636546756e213d6e756c6c297b696628747970656f662872656475636546756e29213d3d22737472696e6722290a72656475636546756e3d72656475636546756e2e746f536f757263653f72656475636546756e2e746f536f7572636528293a2228222b72656475636546756e2e746f537472696e6728292b2229223b626f64792e7265647563653d72656475636546756e3b7d0a616a6178287b6d6574686f643a22504f5354222c75726c3a746869732e7572692b225f74656d705f76696577222c646174613a626f64792c686561646572733a7b22436f6e74656e742d54797065223a226170706c69636174696f6e2f6a736f6e227d7d2c6f7074696f6e73293b7d2c6c6973743a66756e6374696f6e286c6973742c766965772c6f7074696f6e73297b766172206c6973743d6c6973742e73706c697428272f27293b766172206d6574686f643d27474554273b76617220646174613d6e756c6c3b6966286f7074696f6e735b276b657973275d297b6d6574686f643d27504f5354273b766172206b6579733d6f7074696f6e735b276b657973275d3b64656c657465206f7074696f6e735b276b657973275d3b646174613d7b276b657973273a6b6579737d3b7d0a616a6178287b6d6574686f643a6d6574686f642c646174613a646174612c75726c3a746869732e7572692b275f64657369676e2f272b6c6973745b305d2b272f5f6c6973742f272b6c6973745b315d2b272f272b766965777d2c6f7074696f6e73293b7d2c766965773a66756e6374696f6e286e616d652c6f7074696f6e73297b766172206e616d653d6e616d652e73706c697428272f27293b766172206d6574686f643d22474554223b76617220646174613d6e756c6c3b6966286f7074696f6e735b226b657973225d297b6d6574686f643d22504f5354223b766172206b6579733d6f7074696f6e735b226b657973225d3b64656c657465206f7074696f6e735b226b657973225d3b646174613d7b226b657973223a6b6579737d3b7d0a616a6178287b6d6574686f643a6d6574686f642c646174613a646174612c75726c3a746869732e7572692b225f64657369676e2f222b6e616d655b305d2b222f5f766965772f222b6e616d655b315d2b273f272b656e636f6465566965774f7074696f6e73286f7074696f6e73297d2c6f7074696f6e73293b7d2c676574446250726f70657274793a66756e6374696f6e2870726f704e616d652c6f7074696f6e73297b616a6178287b75726c3a746869732e7572692b70726f704e616d657d2c6f7074696f6e73293b7d2c736574446250726f70657274793a66756e6374696f6e2870726f704e616d652c70726f7056616c75652c6f7074696f6e73297b616a6178287b6d6574686f643a22505554222c75726c3a746869732e7572692b70726f704e616d652c646174613a70726f7056616c75657d2c6f7074696f6e73293b7d7d7d3b7d286578706f72747329293b66756e6374696f6e206874747044617461287868722c74797065297b76617220636f6e74656e74547970653d7868722e676574526573706f6e73654865616465722822636f6e74656e742d7479706522297c7c22223b766172206973586d6c3d747970653d3d3d22786d6c227c7c2821747970652626636f6e74656e74547970652e696e6465784f662822786d6c22293e3d30293b7661722069734a736f6e3d747970653d3d3d226a736f6e227c7c2821747970652626636f6e74656e74547970652e696e6465784f6628226a736f6e22293e3d30293b76617220646174613d6973586d6c3f7868722e726573706f6e7365584d4c3a7868722e726573706f6e7365546578743b696628747970656f6620646174613d3d3d22737472696e6722297b69662869734a736f6e297b646174613d4a534f4e2e70617273652864617461293b7d7d0a72657475726e20646174613b7d0a66756e6374696f6e20746f5175657279537472696e67286f626a297b766172206275663d5b5d3b666f7228766172206e616d6520696e206f626a297b7661722076616c75653d6f626a5b6e616d655d3b696628696e4172726179286e616d652c5b226b6579222c2273746172746b6579222c22656e646b6579225d293e3d30297b76616c75653d4a534f4e2e737472696e676966792876616c7565293b7d0a6275662e7075736828656e636f6465555249436f6d706f6e656e74286e616d65292b223d222b656e636f6465555249436f6d706f6e656e742876616c756529293b7d0a72657475726e206275662e6c656e6774683f6275662e6a6f696e28222622293a22223b7d0a66756e6374696f6e20616a6178287265712c6f7074732c7868724f707473297b6f7074733d6f7074737c7c7b7d3b7868724f7074733d7868724f7074737c7c7b7d3b76617220726571756573743d657874656e64287b737563636573735374617475733a5b3230305d2c6d6574686f643a22474554227d2c726571293b696628726571756573742e646174612626726571756573742e6d6574686f64213d3d22504f5354222626726571756573742e6d6574686f64213d3d2250555422297b726571756573742e75726c2b3d28726571756573742e75726c2e696e6465784f6628223f22293e2d313f2226223a223f22292b746f5175657279537472696e6728726571756573742e64617461293b64656c65746520726571756573742e646174613b7d0a737563636573735374617475733d6973417272617928726571756573742e73756363657373537461747573293f726571756573742e737563636573735374617475733a417272617928726571756573742e73756363657373537461747573293b766172207868723d54692e4e6574776f726b2e63726561746548545450436c69656e7428657874656e64287b6f6e6c6f61643a66756e6374696f6e2865297b766172207265713d652e736f757263653b7472797b76617220726573703d6874747044617461287265712c226a736f6e22293b7d0a636174636828657272297b54692e4150492e6572726f72286572722e6e616d652b223a20222b6572722e6d657373616765293b6966286f7074732e6661696c757265297b6f7074732e6661696c75726528726571293b7d0a656c73657b54692e4150492e6572726f7228657272293b7d7d0a696628696e4172726179287265712e7374617475732c73756363657373537461747573293e3d30297b6966286f7074732e73756363657373297b6f7074732e737563636573732872657370293b7d7d0a656c7365206966286f7074732e6661696c757265297b6f7074732e6661696c75726528726571293b7d0a656c73657b54692e4150492e6572726f72282262616420726573706f6e73653a20222b7265712e7374617475732b2220222b7265712e726573706f6e736554657874293b7d7d2c6f6e6572726f723a66756e6374696f6e2865297b766172207265713d652e736f757263653b6966286f7074732e6661696c757265297b6f7074732e6661696c75726528726571293b7d0a656c73657b54692e4150492e6572726f722822414a4158206572726f723a20222b4a534f4e2e737472696e676966792865292b2220222b7265712e7374617475732b2220222b7265712e726573706f6e736554657874293b7d7d7d2c7868724f70747329293b7868722e6f70656e28726571756573742e6d6574686f642c726571756573742e75726c293b54692e4150492e646562756728726571756573742e6d6574686f642b2220222b726571756573742e75726c293b7868722e7365744d61785265646972656374732830293b6966286f7074732e757365726e616d65297b7868722e736574526571756573744865616465722827417574686f72697a6174696f6e272c27426173696320272b54692e5574696c732e626173653634656e636f6465286f7074732e757365726e616d652b273a272b6f7074732e70617373776f726429293b7d0a7868722e736574526571756573744865616465722822416363657074222c222a2f2a22293b696628726571756573742e6d6574686f643d3d3d22504f5354227c7c726571756573742e6d6574686f643d3d3d2250555422297b7868722e736574526571756573744865616465722822436f6e74656e742d54797065222c226170706c69636174696f6e2f6a736f6e22293b7d0a696628726571756573742e68656164657273297b666f72287661722068656164657220696e20726571756573742e68656164657273297b7868722e73657452657175657374486561646572286865616465722c726571756573742e686561646572735b6865616465725d293b7d7d0a7868722e73656e64286973506c61696e4f626a65637428726571756573742e64617461293f4a534f4e2e737472696e6769667928726571756573742e64617461293a726571756573742e64617461293b7d0a76617220686578636173653d303b766172206236347061643d223d223b76617220636872737a3d383b66756e6374696f6e206865785f736861312873297b72657475726e2062696e623268657828636f72655f73686131287374723262696e622873292c732e6c656e6774682a636872737a29293b7d0a66756e6374696f6e206236345f736861312873297b72657475726e2062696e623262363428636f72655f73686131287374723262696e622873292c732e6c656e6774682a636872737a29293b7d0a66756e6374696f6e207374725f736861312873297b72657475726e2062696e623273747228636f72655f73686131287374723262696e622873292c732e6c656e6774682a636872737a29293b7d0a66756e6374696f6e206865785f686d61635f73686131286b65792c64617461297b72657475726e2062696e623268657828636f72655f686d61635f73686131286b65792c6461746129293b7d0a66756e6374696f6e206236345f686d61635f73686131286b65792c64617461297b72657475726e2062696e623262363428636f72655f686d61635f73686131286b65792c6461746129293b7d0a66756e6374696f6e207374725f686d61635f73686131286b65792c64617461297b72657475726e2062696e623273747228636f72655f686d61635f73686131286b65792c6461746129293b7d0a66756e6374696f6e20736861315f766d5f7465737428290a7b72657475726e206865785f73686131282261626322293d3d2261393939336533363437303638313661626133653235373137383530633236633963643064383964223b7d0a66756e6374696f6e20636f72655f7368613128782c6c656e290a7b785b6c656e3e3e355d7c3d307838303c3c2832342d6c656e253332293b785b28286c656e2b36343e3e39293c3c34292b31355d3d6c656e3b76617220773d4172726179283830293b76617220613d313733323538343139333b76617220623d2d3237313733333837393b76617220633d2d313733323538343139343b76617220643d3237313733333837383b76617220653d2d313030393538393737363b666f722876617220693d303b693c782e6c656e6774683b692b3d3136290a7b766172206f6c64613d613b766172206f6c64623d623b766172206f6c64633d633b766172206f6c64643d643b766172206f6c64653d653b666f7228766172206a3d303b6a3c38303b6a2b2b290a7b6966286a3c313629775b6a5d3d785b692b6a5d3b656c736520775b6a5d3d726f6c28775b6a2d335d5e775b6a2d385d5e775b6a2d31345d5e775b6a2d31365d2c31293b76617220743d736166655f61646428736166655f61646428726f6c28612c35292c736861315f6674286a2c622c632c6429292c736166655f61646428736166655f61646428652c775b6a5d292c736861315f6b74286a2929293b653d643b643d633b633d726f6c28622c3330293b623d613b613d743b7d0a613d736166655f61646428612c6f6c6461293b623d736166655f61646428622c6f6c6462293b633d736166655f61646428632c6f6c6463293b643d736166655f61646428642c6f6c6464293b653d736166655f61646428652c6f6c6465293b7d0a72657475726e20417272617928612c622c632c642c65293b7d0a66756e6374696f6e20736861315f667428742c622c632c64290a7b696628743c32302972657475726e28622663297c28287e62292664293b696628743c34302972657475726e20625e635e643b696628743c36302972657475726e28622663297c28622664297c28632664293b72657475726e20625e635e643b7d0a66756e6374696f6e20736861315f6b742874290a7b72657475726e28743c3230293f313531383530303234393a28743c3430293f313835393737353339333a28743c3630293f2d313839343030373538383a2d3839393439373531343b7d0a66756e6374696f6e20636f72655f686d61635f73686131286b65792c64617461290a7b76617220626b65793d7374723262696e62286b6579293b696628626b65792e6c656e6774683e313629626b65793d636f72655f7368613128626b65792c6b65792e6c656e6774682a636872737a293b76617220697061643d4172726179283136292c6f7061643d4172726179283136293b666f722876617220693d303b693c31363b692b2b290a7b697061645b695d3d626b65795b695d5e307833363336333633363b6f7061645b695d3d626b65795b695d5e307835433543354335433b7d0a76617220686173683d636f72655f7368613128697061642e636f6e636174287374723262696e62286461746129292c3531322b646174612e6c656e6774682a636872737a293b72657475726e20636f72655f73686131286f7061642e636f6e6361742868617368292c3531322b313630293b7d0a66756e6374696f6e20736166655f61646428782c79290a7b766172206c73773d287826307846464646292b287926307846464646293b766172206d73773d28783e3e3136292b28793e3e3136292b286c73773e3e3136293b72657475726e286d73773c3c3136297c286c737726307846464646293b7d0a66756e6374696f6e20726f6c286e756d2c636e74290a7b72657475726e286e756d3c3c636e74297c286e756d3e3e3e2833322d636e7429293b7d0a66756e6374696f6e207374723262696e6228737472290a7b7661722062696e3d417272617928293b766172206d61736b3d28313c3c636872737a292d313b666f722876617220693d303b693c7374722e6c656e6774682a636872737a3b692b3d636872737a290a62696e5b693e3e355d7c3d287374722e63686172436f6465417428692f636872737a29266d61736b293c3c2833322d636872737a2d69253332293b72657475726e2062696e3b7d0a66756e6374696f6e2062696e62327374722862696e290a7b766172207374723d22223b766172206d61736b3d28313c3c636872737a292d313b666f722876617220693d303b693c62696e2e6c656e6774682a33323b692b3d636872737a290a7374722b3d537472696e672e66726f6d43686172436f6465282862696e5b693e3e355d3e3e3e2833322d636872737a2d692533322929266d61736b293b72657475726e207374723b7d0a66756e6374696f6e2062696e62326865782862696e6172726179290a7b766172206865785f7461623d686578636173653f2230313233343536373839414243444546223a2230313233343536373839616263646566223b766172207374723d22223b666f722876617220693d303b693c62696e61727261792e6c656e6774682a343b692b2b290a7b7374722b3d6865785f7461622e636861724174282862696e61727261795b693e3e325d3e3e2828332d692534292a382b34292926307846292b0a6865785f7461622e636861724174282862696e61727261795b693e3e325d3e3e2828332d692534292a38292926307846293b7d0a72657475726e207374723b7d0a66756e6374696f6e2062696e62326236342862696e6172726179290a7b766172207461623d224142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f223b766172207374723d22223b666f722876617220693d303b693c62696e61727261792e6c656e6774682a343b692b3d33290a7b76617220747269706c65743d28282862696e61727261795b693e3e325d3e3e382a28332d69253429292630784646293c3c3136297c28282862696e61727261795b692b313e3e325d3e3e382a28332d28692b3129253429292630784646293c3c38297c282862696e61727261795b692b323e3e325d3e3e382a28332d28692b3229253429292630784646293b666f7228766172206a3d303b6a3c343b6a2b2b290a7b696628692a382b6a2a363e62696e61727261792e6c656e6774682a3332297374722b3d6236347061643b656c7365207374722b3d7461622e6368617241742828747269706c65743e3e362a28332d6a29292630783346293b7d7d0a72657475726e207374723b7d0a766172204261736536343d7b7d3b2866756e6374696f6e286578706f727473297b76617220656e636f646543686172733d224142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f223b766172206465636f646543686172733d5b2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c36322c2d312c2d312c2d312c36332c35322c35332c35342c35352c35362c35372c35382c35392c36302c36312c2d312c2d312c2d312c2d312c2d312c2d312c2d312c302c312c322c332c342c352c362c372c382c392c31302c31312c31322c31332c31342c31352c31362c31372c31382c31392c32302c32312c32322c32332c32342c32352c2d312c2d312c2d312c2d312c2d312c2d312c32362c32372c32382c32392c33302c33312c33322c33332c33342c33352c33362c33372c33382c33392c34302c34312c34322c34332c34342c34352c34362c34372c34382c34392c35302c35312c2d312c2d312c2d312c2d312c2d315d3b6578706f7274732e656e636f64653d66756e6374696f6e28737472297b766172206f75742c692c6c656e6774683b7661722063312c63322c63333b6c656e6774683d6c656e28737472293b693d303b6f75743d5b5d3b7768696c6528693c6c656e677468297b63313d7374722e63686172436f6465417428692b2b2926307866663b696628693d3d6c656e677468290a7b6f75742e7075736828656e636f646543686172732e63686172436f646541742863313e3e3229293b6f75742e7075736828656e636f646543686172732e63686172436f646541742828633126307833293c3c3429293b6f75742e7075736828223d222e63686172436f64654174283029293b6f75742e7075736828223d222e63686172436f64654174283029293b627265616b3b7d0a63323d7374722e63686172436f6465417428692b2b293b696628693d3d6c656e677468290a7b6f75742e7075736828656e636f646543686172732e63686172436f646541742863313e3e3229293b6f75742e7075736828656e636f646543686172732e63686172436f64654174282828633126307833293c3c34297c282863322630784630293e3e342929293b6f75742e7075736828656e636f646543686172732e63686172436f646541742828633226307846293c3c3229293b6f75742e7075736828223d222e63686172436f64654174283029293b627265616b3b7d0a63333d7374722e63686172436f6465417428692b2b293b6f75742e7075736828656e636f646543686172732e63686172436f646541742863313e3e3229293b6f75742e7075736828656e636f646543686172732e63686172436f64654174282828633126307833293c3c34297c282863322630784630293e3e342929293b6f75742e7075736828656e636f646543686172732e63686172436f64654174282828633226307846293c3c32297c282863332630784330293e3e362929293b6f75742e7075736828656e636f646543686172732e63686172436f64654174286333263078334629293b7d0a766172207374723d22223b6f75742e666f72456163682866756e6374696f6e28636872297b7374722b3d537472696e672e66726f6d43686172436f646528636872297d293b72657475726e207374723b7d3b6578706f7274732e6465636f64653d66756e6374696f6e28737472297b7661722063312c63322c63332c63343b76617220692c6c656e6774682c6f75743b6c656e6774683d6c656e28737472293b693d303b6f75743d5b5d3b7768696c6528693c6c656e677468297b646f7b63313d6465636f646543686172735b7374722e63686172436f6465417428692b2b2926307866665d3b7d7768696c6528693c6c656e677468262663313d3d2d31293b69662863313d3d2d31290a627265616b3b646f7b63323d6465636f646543686172735b7374722e63686172436f6465417428692b2b2926307866665d3b7d7768696c6528693c6c656e677468262663323d3d2d31293b69662863323d3d2d31290a627265616b3b6f75742e7075736828537472696e672e66726f6d43686172436f6465282863313c3c32297c282863322630783330293e3e342929293b646f7b63333d7374722e63686172436f6465417428692b2b2926307866663b69662863333d3d3631290a72657475726e206f75742e6a6f696e282727293b63333d6465636f646543686172735b63335d3b7d7768696c6528693c6c656e677468262663333d3d2d31293b69662863333d3d2d31290a627265616b3b6f75742e7075736828537472696e672e66726f6d43686172436f6465282828633226307846293c3c34297c282863332630783343293e3e322929293b646f7b63343d7374722e63686172436f6465417428692b2b2926307866663b69662863343d3d3631290a72657475726e206f75742e6a6f696e282727293b63343d6465636f646543686172735b63345d3b7d7768696c6528693c6c656e677468262663343d3d2d31293b69662863343d3d2d31290a627265616b3b6f75742e7075736828537472696e672e66726f6d43686172436f646528282863332630783033293c3c36297c633429293b7d0a72657475726e206f75742e6a6f696e282727293b7d3b766172206c656e3d66756e6374696f6e286f626a656374297b6966286f626a6563742e6c656e677468213d3d756e646566696e6564297b72657475726e206f626a6563742e6c656e6774683b7d656c7365206966286f626a6563742e6765744c656e677468213d3d756e646566696e6564297b72657475726e206f626a6563742e6765744c656e67746828293b7d656c73657b72657475726e20756e646566696e65643b7d7d3b7d2928426173653634293b76617220636c61737332747970653d5b5d3b2866756e6374696f6e286f297b7661722074797065733d5b22426f6f6c65616e222c224e756d626572222c22537472696e67222c2246756e6374696f6e222c224172726179222c2244617465222c22526567457870222c224f626a656374225d3b666f722876617220693d302c6c656e6774683d74797065732e6c656e6774683b693c6c656e6774683b692b2b297b766172206e616d653d74797065735b695d3b766172206b65793d225b6f626a65637420222b6e616d652b225d223b6f5b6b65795d3d6e616d652e746f4c6f7765724361736528293b7d7d28636c617373327479706529293b766172206861734f776e3d4f626a6563742e70726f746f747970652e6861734f776e50726f70657274792c746f537472696e673d4f626a6563742e70726f746f747970652e746f537472696e673b66756e6374696f6e2074797065286f626a297b72657475726e206f626a3d3d6e756c6c3f537472696e67286f626a293a636c61737332747970655b746f537472696e672e63616c6c286f626a295d7c7c226f626a656374223b7d0a66756e6374696f6e206973506c61696e4f626a656374286f626a297b696628216f626a7c7c74797065286f626a29213d3d226f626a65637422297b72657475726e2066616c73653b7d0a6966286f626a2e636f6e7374727563746f722626216861734f776e2e63616c6c286f626a2c22636f6e7374727563746f7222292626216861734f776e2e63616c6c286f626a2e636f6e7374727563746f722e70726f746f747970652c22697350726f746f747970654f662229297b72657475726e2066616c73653b7d0a766172206b65793b666f72286b657920696e206f626a297b7d0a72657475726e206b65793d3d3d756e646566696e65647c7c6861734f776e2e63616c6c286f626a2c6b6579293b7d0a66756e6374696f6e206973456d7074794f626a656374286f626a297b666f7228766172206e616d6520696e206f626a297b72657475726e2066616c73653b7d0a72657475726e20747275653b7d0a66756e6374696f6e2069734172726179286f626a297b72657475726e2074797065286f626a293d3d3d226172726179223b7d0a66756e6374696f6e20697346756e6374696f6e286f626a297b72657475726e2074797065286f626a293d3d3d2266756e6374696f6e223b7d0a66756e6374696f6e2065616368286f626a6563742c63616c6c6261636b2c61726773297b766172206e616d652c693d302c6c656e6774683d6f626a6563742e6c656e6774682c69734f626a3d6c656e6774683d3d3d756e646566696e65647c7c697346756e6374696f6e286f626a656374293b69662861726773297b69662869734f626a297b666f72286e616d6520696e206f626a656374297b69662863616c6c6261636b2e6170706c79286f626a6563745b6e616d655d2c61726773293d3d3d66616c7365297b627265616b3b7d7d7d656c73657b666f72283b693c6c656e6774683b297b69662863616c6c6261636b2e6170706c79286f626a6563745b692b2b5d2c61726773293d3d3d66616c7365297b627265616b3b7d7d7d7d656c73657b69662869734f626a297b666f72286e616d6520696e206f626a656374297b69662863616c6c6261636b2e63616c6c286f626a6563745b6e616d655d2c6e616d652c6f626a6563745b6e616d655d293d3d3d66616c7365297b627265616b3b7d7d7d656c73657b666f72283b693c6c656e6774683b297b69662863616c6c6261636b2e63616c6c286f626a6563745b695d2c692c6f626a6563745b692b2b5d293d3d3d66616c7365297b627265616b3b7d7d7d7d0a72657475726e206f626a6563743b7d0a66756e6374696f6e20657874656e6428297b766172206f7074696f6e732c6e616d652c7372632c636f70792c636f7079497341727261792c636c6f6e652c7461726765743d617267756d656e74735b305d7c7c7b7d2c693d312c6c656e6774683d617267756d656e74732e6c656e6774682c646565703d66616c73653b696628747970656f66207461726765743d3d3d22626f6f6c65616e22297b646565703d7461726765743b7461726765743d617267756d656e74735b315d7c7c7b7d3b693d323b7d0a696628747970656f6620746172676574213d3d226f626a65637422262621697346756e6374696f6e2874617267657429297b7461726765743d7b7d3b7d0a6966286c656e6774683d3d3d69297b7461726765743d746869733b2d2d693b7d0a666f72283b693c6c656e6774683b692b2b297b696628286f7074696f6e733d617267756d656e74735b695d29213d6e756c6c297b666f72286e616d6520696e206f7074696f6e73297b6966286f7074696f6e732e6861734f776e50726f7065727479286e616d6529297b7372633d7461726765745b6e616d655d3b636f70793d6f7074696f6e735b6e616d655d3b6966287461726765743d3d3d636f7079297b636f6e74696e75653b7d0a696628646565702626636f70792626286973506c61696e4f626a65637428636f7079297c7c28636f7079497341727261793d6973417272617928636f7079292929297b696628636f707949734172726179297b636f7079497341727261793d66616c73653b636c6f6e653d73726326266973417272617928737263293f7372633a5b5d3b7d656c73657b636c6f6e653d73726326266973506c61696e4f626a65637428737263293f7372633a7b7d3b7d0a7461726765745b6e616d655d3d657874656e6428646565702c636c6f6e652c636f7079293b7d656c736520696628636f7079213d3d756e646566696e6564297b7461726765745b6e616d655d3d636f70793b7d7d7d7d7d0a72657475726e207461726765743b7d0a66756e6374696f6e20696e417272617928656c656d2c6172726179297b69662841727261792e70726f746f747970652e696e6465784f66297b72657475726e2061727261792e696e6465784f6628656c656d293b7d0a666f722876617220693d302c6c656e6774683d61727261792e6c656e6774683b693c6c656e6774683b692b2b297b69662861727261795b695d3d3d3d656c656d297b72657475726e20693b7d7d0a72657475726e2d313b7d"); 13 | } 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /mobile/ios/ComObscureCouchdb_client_Prefix.pch: -------------------------------------------------------------------------------- 1 | 2 | #ifdef __OBJC__ 3 | #import 4 | #endif 5 | -------------------------------------------------------------------------------- /mobile/ios/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2011 Paul Mietz Egli 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | 15 | ----- 16 | 17 | based on work by the CouchDB team released under the Apache licence 18 | 19 | sha1.js 20 | Version 2.1a Copyright Paul Johnston 2000 - 2002. 21 | 22 | base64.js 23 | Copyright (C) 1999 Masanao Izumo -------------------------------------------------------------------------------- /mobile/ios/README: -------------------------------------------------------------------------------- 1 | Appcelerator Titanium iPhone Module Project 2 | =========================================== 3 | 4 | This is a skeleton Titanium Mobile iPhone module project. Modules can be 5 | used to extend the functionality of Titanium by providing additional native 6 | code that is compiled into your application at build time and can expose certain 7 | APIs into JavaScript. 8 | 9 | MODULE NAMING 10 | -------------- 11 | 12 | Choose a unique module id for your module. This ID usually follows a namespace 13 | convention using DNS notation. For example, com.appcelerator.module.test. This 14 | ID can only be used once by all public modules in Titanium. 15 | 16 | 17 | COMPONENTS 18 | ----------- 19 | 20 | Components that are exposed by your module must follow a special naming convention. 21 | A component (widget, proxy, etc) must be named with the pattern: 22 | 23 | TiProxy 24 | 25 | For example, if you component was called Foo, your proxy would be named: 26 | 27 | TiMyfirstFooProxy 28 | 29 | For view proxies or widgets, you must create both a view proxy and a view implementation. 30 | If you widget was named proxy, you would create the following files: 31 | 32 | TiMyfirstFooProxy.h 33 | TiMyfirstFooProxy.m 34 | TiMyfirstFoo.h 35 | TiMyfirstFoo.m 36 | 37 | The view implementation is named the same except it does contain the suffix `Proxy`. 38 | 39 | View implementations extend the Titanium base class `TiUIView`. View Proxies extend the 40 | Titanium base class `TiUIViewProxy` or `TiUIWidgetProxy`. 41 | 42 | For proxies that are simply native objects that can be returned to JavaScript, you can 43 | simply extend `TiProxy` and no view implementation is required. 44 | 45 | 46 | GET STARTED 47 | ------------ 48 | 49 | 1. Edit manifest with the appropriate details about your module. 50 | 2. Edit LICENSE to add your license details. 51 | 3. Place any assets (such as PNG files) that are required in the assets folder. 52 | 4. Edit the titanium.xcconfig and make sure you're building for the right Titanium version. 53 | 5. Code and build. 54 | 55 | BUILD TIME COMPILER CONFIG 56 | -------------------------- 57 | 58 | You can edit the file `module.xcconfig` to include any build time settings that should be 59 | set during application compilation that your module requires. This file will automatically get `#include` in the main application project. 60 | 61 | For more information about this file, please see the Apple documentation at: 62 | 63 | 64 | 65 | 66 | DOCUMENTATION FOR YOUR MODULE 67 | ----------------------------- 68 | 69 | You should provide at least minimal documentation for your module in `documentation` folder using the Markdown syntax. 70 | 71 | For more information on the Markdown syntax, refer to this documentation at: 72 | 73 | 74 | 75 | 76 | TEST HARNESS EXAMPLE FOR YOUR MODULE 77 | ------------------------------------ 78 | 79 | The `example` directory contains a skeleton application test harness that can be 80 | used for testing and providing an example of usage to the users of your module. 81 | 82 | 83 | INSTALL YOUR MODULE 84 | -------------------- 85 | 86 | 1. Run `build.py` which creates your distribution 87 | 2. cd to `/Library/Application Support/Titanium` 88 | 3. copy this zip file into the folder of your Titanium SDK 89 | 90 | REGISTER YOUR MODULE 91 | --------------------- 92 | 93 | Register your module with your application by editing `tiapp.xml` and adding your module. 94 | Example: 95 | 96 | 97 | com.obscure.couchdb_client 98 | 99 | 100 | When you run your project, the compiler will know automatically compile in your module 101 | dependencies and copy appropriate image assets into the application. 102 | 103 | USING YOUR MODULE IN CODE 104 | ------------------------- 105 | 106 | To use your module in code, you will need to require it. 107 | 108 | For example, 109 | 110 | var my_module = require('com.obscure.couchdb_client'); 111 | my_module.foo(); 112 | 113 | WRITING PURE JS NATIVE MODULES 114 | ------------------------------ 115 | 116 | You can write a pure JavaScript "natively compiled" module. This is nice if you 117 | want to distribute a JS module pre-compiled. 118 | 119 | To create a module, create a file named com.obscure.couchdb_client.js under the assets folder. 120 | This file must be in the Common JS format. For example: 121 | 122 | exports.echo = function(s) 123 | { 124 | return s; 125 | }; 126 | 127 | Any functions and properties that are exported will be made available as part of your 128 | module. All other code inside your JS will be private to your module. 129 | 130 | For pure JS module, you don't need to modify any of the Objective-C module code. You 131 | can leave it as-is and build. 132 | 133 | TESTING YOUR MODULE 134 | ------------------- 135 | 136 | Run the `titanium.py` script to test your module or test from within XCode. 137 | To test with the script, execute: 138 | 139 | titanium run --dir=YOURMODULEDIR 140 | 141 | 142 | This will execute the app.js in the example folder as a Titanium application. 143 | 144 | 145 | DISTRIBUTING YOUR MODULE 146 | ------------------------- 147 | 148 | Currently, you will need to manually distribution your module distribution zip file directly. However, in the near future, we will make module distribution and sharing built-in to Titanium Developer and in the Titanium Marketplace! 149 | 150 | 151 | Cheers! 152 | -------------------------------------------------------------------------------- /mobile/ios/assets/README: -------------------------------------------------------------------------------- 1 | Place your assets like PNG files in this directory and they will be packaged with your module. 2 | 3 | If you create a file named com.obscure.couchdb_client.js in this directory, it will be 4 | compiled and used as your module. This allows you to run pure Javascript 5 | modules that are pre-compiled. 6 | 7 | -------------------------------------------------------------------------------- /mobile/ios/assets/com.obscure.couchdb_client.js: -------------------------------------------------------------------------------- 1 | /** @module com.obscure.couchdb_client */ 2 | 3 | /** 4 | * @fileOverview 5 | * CouchDB client module for Appcelerator Titanium. All of the functions 6 | * in this module are asynchronous and use an options object for common 7 | * parameters. 8 | * @see options 9 | */ 10 | 11 | /** 12 | * @name options 13 | * @field 14 | * @property {Function} success called by the module when the CouchDB call completes 15 | * successfully. The parameter to this function is the response from CouchDB 16 | * as an object. 17 | * @property {Function} failure called by the module when the CouchDB call fails for 18 | * any reason. The parameter to this function is the XMLHttpRequest object used 19 | * in the call. You can extract the response code and error messages from that XHR. 20 | * @property {String} username the username to use during the call. Some CouchDB calls 21 | * require an admin user; depending on your security setup, other calls may also 22 | * require a valid user. 23 | * @property {String} password the password to use during the call. 24 | */ 25 | 26 | (function(module) { 27 | 28 | /** @private */ 29 | function userDb(callback) { 30 | module.session({ 31 | success: function(resp) { 32 | var userDb = module.db(resp.info.authentication_db); 33 | callback(userDb); 34 | } 35 | }); 36 | } 37 | 38 | /** @private */ 39 | function prepareUserDoc(user_doc, new_password) { 40 | if (typeof hex_sha1 == "undefined") { 41 | Ti.API.error("creating a user doc requires sha1.js to be loaded in the page"); 42 | return; 43 | } 44 | var user_prefix = "org.couchdb.user:"; 45 | user_doc._id = user_doc._id || user_prefix + user_doc.name; 46 | if (new_password) { 47 | // handle the password crypto 48 | user_doc.salt = _newUUID(); 49 | user_doc.password_sha = hex_sha1(new_password + user_doc.salt); 50 | } 51 | user_doc.type = "user"; 52 | if (!user_doc.roles) { 53 | user_doc.roles = []; 54 | } 55 | return user_doc; 56 | } 57 | 58 | /** @private */ 59 | function encodeDocId(docID) { 60 | var parts = docID.split("/"); 61 | if (parts[0] == "_design") { 62 | parts.shift(); 63 | return "_design/" + encodeURIComponent(parts.join('/')); 64 | } 65 | return encodeURIComponent(docID); 66 | } 67 | 68 | /** @private */ 69 | var viewOptions = ["key", "startkey", "startkey_docid", "endkey", "endkey_docid", "limit", "stale", "descending", "skip", "group", "group_level", "reduce", "include_docs", "inclusive_end"]; 70 | 71 | /** @private */ 72 | function encodeViewOptions(obj) { 73 | // http://wiki.apache.org/couchdb/HTTP_view_API 74 | // note that "keys" is handled separately 75 | var buf = []; 76 | for (var key in obj) { 77 | if (inArray(key, viewOptions) > -1) { 78 | buf.push(encodeURIComponent(key) + "=" + encodeURIComponent(JSON.stringify(obj[key]))); 79 | } 80 | } 81 | return buf.join('&'); 82 | } 83 | 84 | /** 85 | * base URL of the CouchDB server, i.e. 'http://localhost:5984' 86 | */ 87 | module.urlPrefix = ''; 88 | 89 | // public functions 90 | 91 | /** 92 | * Obtain a list of active tasks. The result is a JSON array of the currently running tasks, with each task being described with a single object. 93 | * @param options request options 94 | */ 95 | module.activeTasks = function(options) { 96 | ajax({ 97 | url: this.urlPrefix + "_active_tasks" 98 | }, 99 | options); 100 | }; 101 | 102 | /** 103 | * Fetch a list of all databases. 104 | * @param options request options 105 | */ 106 | module.allDbs = function(options) { 107 | ajax({ 108 | url: this.urlPrefix + "/_all_dbs" 109 | }, 110 | options); 111 | }; 112 | 113 | /** 114 | * Get information about the server or a database (add "dbname" field to the options object). 115 | * @param options request options 116 | */ 117 | module.info = function(options) { 118 | ajax({ 119 | url: this.urlPrefix + "/" + (options.dbname || "") 120 | }, 121 | options); 122 | }; 123 | 124 | module.config = function(options, section, key, value) { 125 | var req = { 126 | url: this.urlPrefix + "/_config/" 127 | }; 128 | if (section) { 129 | req.url += encodeURIComponent(section) + "/"; 130 | if (key) { 131 | req.url += encodeURIComponent(key); 132 | } 133 | } 134 | if (value === null) { 135 | req.method = "DELETE"; 136 | } else if (value !== undefined) { 137 | req.method = "PUT"; 138 | req.data = JSON.stringify(value); 139 | } 140 | ajax(req, options); 141 | }; 142 | 143 | module.login = function(options, username, password) { 144 | this.session(extend({ 145 | username: username, 146 | password: password 147 | }, 148 | options)); 149 | }; 150 | 151 | module.logout = function(options) { 152 | ajax({ 153 | method: "DELETE", 154 | url: this.urlPrefix + "/_session", 155 | username: "_", 156 | password: "_" 157 | }, 158 | options); 159 | }; 160 | 161 | module.session = function(options) { 162 | ajax({ 163 | url: this.urlPrefix + "/_session", 164 | headers: { 165 | "Accept": "application/json" 166 | } 167 | }, 168 | options); 169 | }; 170 | 171 | module.signup = function(user_doc, password, options) { 172 | options = options || {}; 173 | user_doc = prepareUserDoc(user_doc, password); 174 | userDb(function(db) { 175 | db.saveDoc(user_doc, options); 176 | }); 177 | }; 178 | 179 | module.db = function(name, db_opts) { 180 | db_opts = db_opts || {}; 181 | 182 | return { 183 | name: name, 184 | uri: this.urlPrefix + "/" + encodeURIComponent(name) + "/", 185 | 186 | /** 187 | * Request compaction of the specified database. 188 | * @param 189 | */ 190 | compact: function(options) { 191 | ajax({ 192 | method: "POST", 193 | url: this.uri + "_compact", 194 | successStatus: 202 195 | }, 196 | options); 197 | }, 198 | 199 | /** 200 | * Cleans up the cached view output on disk for a given view. 201 | */ 202 | viewCleanup: function(options) { 203 | ajax({ 204 | method: "POST", 205 | url: this.uri + "_view_cleanup", 206 | successStatus: 202 207 | }, 208 | options); 209 | }, 210 | 211 | /** 212 | * Compacts the view indexes associated with the specified design 213 | * document. You can use this in place of the full database compaction 214 | * if you know a specific set of view indexes have been affected by a 215 | * recent database change. 216 | */ 217 | compactView: function(groupname, options) { 218 | ajax({ 219 | method: "POST", 220 | url: this.uri + "_compact/" + groupname, 221 | successStatus: 202 222 | }, 223 | options); 224 | }, 225 | 226 | /** 227 | * Create a new database 228 | */ 229 | create: function(options) { 230 | ajax({ 231 | method: "PUT", 232 | url: this.uri, 233 | successStatus: 201 234 | }, 235 | options); 236 | }, 237 | 238 | /** 239 | * Deletes the specified database, and all the documents and 240 | * attachments contained within it. 241 | */ 242 | drop: function(options) { 243 | ajax({ 244 | method: "DELETE", 245 | url: this.uri 246 | }, 247 | options); 248 | }, 249 | 250 | /** 251 | * Gets information about the specified database. 252 | */ 253 | info: function(options) { 254 | ajax({ 255 | url: this.uri 256 | }, 257 | options); 258 | }, 259 | 260 | /** 261 | * @namespace 262 | * $.couch.db.changes provides an API for subscribing to the changes 263 | * feed 264 | *
var $changes = $.couch.db("mydatabase").changes();
 265 |              *$changes.onChange = function (data) {
 266 |              *    ... process data ...
 267 |              * }
 268 |              * $changes.stop();
 269 |              * 
270 | */ 271 | 272 | changes: function(since, options) { 273 | 274 | options = options || {}; 275 | // set up the promise object within a closure for this handler 276 | var timeout = 100, 277 | db = this, 278 | active = true, 279 | listeners = [], 280 | promise = { 281 | onChange: function(fun) { 282 | listeners.push(fun); 283 | }, 284 | stop: function() { 285 | active = false; 286 | } 287 | }; 288 | // call each listener when there is a change 289 | function triggerListeners(resp) { 290 | each(listeners, function() { 291 | this(resp); 292 | }); 293 | } 294 | // when there is a change, call any listeners, then check for 295 | // another change 296 | options.success = function(resp) { 297 | timeout = 100; 298 | if (active) { 299 | since = resp.last_seq; 300 | triggerListeners(resp); 301 | getChangesSince(); 302 | } 303 | }; 304 | options.error = function() { 305 | if (active) { 306 | setTimeout(getChangesSince, timeout); 307 | timeout = timeout * 2; 308 | } 309 | }; 310 | // actually make the changes request 311 | function getChangesSince() { 312 | var opts = extend({ 313 | heartbeat: 10 * 1000 314 | }, 315 | options, { 316 | feed: "longpoll", 317 | since: since 318 | }); 319 | ajax({ 320 | url: db.uri + "_changes" + encodeOptions(opts) 321 | }, 322 | options); 323 | } 324 | // start the first request 325 | if (since) { 326 | getChangesSince(); 327 | } else { 328 | db.info({ 329 | success: function(info) { 330 | since = info.update_seq; 331 | getChangesSince(); 332 | } 333 | }); 334 | } 335 | return promise; 336 | }, 337 | 338 | /** 339 | * Fetch all the docs in this db. You can specify an array of keys to 340 | * fetch by passing the keys field in the 341 | * options parameter. 342 | */ 343 | allDocs: function(options) { 344 | var method = "GET"; 345 | var data = null; 346 | if (options.keys) { 347 | method = "POST"; 348 | var keys = options.keys; 349 | delete options.keys; 350 | data = { 351 | "keys": keys 352 | }; 353 | } 354 | ajax({ 355 | method: method, 356 | data: data, 357 | url: this.uri + "_all_docs" 358 | }, 359 | options); 360 | }, 361 | 362 | /** 363 | * Fetch all the design docs in this db 364 | */ 365 | allDesignDocs: function(options) { 366 | this.allDocs(extend({ 367 | startkey: "_design", 368 | endkey: "_design0" 369 | }, 370 | options)); 371 | }, 372 | 373 | /** 374 | * Returns the specified doc from the db. 375 | */ 376 | openDoc: function(docId, options) { 377 | ajax({ 378 | url: this.uri + encodeDocId(docId) 379 | }, 380 | options); 381 | }, 382 | 383 | /** 384 | * Create a new document in the specified database, using the supplied 385 | * JSON document structure. If the JSON structure includes the _id 386 | * field, then the document will be created with the specified document 387 | * ID. If the _id field is not specified, a new unique ID will be 388 | * generated. 389 | */ 390 | saveDoc: function(doc, options) { 391 | options = options || {}; 392 | var db = this, 393 | method, uri; 394 | if (doc._id === undefined) { 395 | method = "POST"; 396 | uri = this.uri; 397 | } else { 398 | method = "PUT"; 399 | uri = this.uri + encodeDocId(doc._id); 400 | } 401 | ajax({ 402 | method: method, 403 | url: uri, 404 | data: doc, 405 | successStatus: [200, 201, 202] 406 | }, 407 | options); 408 | }, 409 | 410 | /** 411 | * Save a list of documents 412 | */ 413 | bulkSave: function(docs, options) { 414 | ajax({ 415 | method: "POST", 416 | url: this.uri + "_bulk_docs", 417 | data: docs 418 | }, 419 | options); 420 | }, 421 | 422 | /** 423 | * Deletes the specified document from the database. You must supply 424 | * the current (latest) revision and id of the document 425 | * to delete eg removeDoc({_id:"mydoc", _rev: "1-2345"}) 426 | */ 427 | removeDoc: function(doc, options) { 428 | ajax({ 429 | method: "DELETE", 430 | data: { 431 | rev: doc._rev 432 | }, 433 | url: this.uri + encodeDocId(doc._id) 434 | }, 435 | options); 436 | }, 437 | 438 | /** 439 | * Remove a set of documents 440 | */ 441 | bulkRemove: function(docs, options) { 442 | docs.docs = each(docs.docs, function(i, doc) { 443 | doc._deleted = true; 444 | }); 445 | ajax({ 446 | method: "POST", 447 | successStatus: 201, 448 | url: this.uri + "_bulk_docs", 449 | data: docs 450 | }, 451 | options); 452 | }, 453 | 454 | /** 455 | * Copy an existing document to a new or existing document. 456 | */ 457 | copyDoc: function(source, destination, options) { 458 | if (!destination) { 459 | // TODO get a UUID 460 | } 461 | ajax({ 462 | method: "COPY", 463 | url: this.uri + encodeDocId(source), 464 | successStatus: 201, 465 | headers: { 466 | "Destination": destination 467 | } 468 | }, 469 | options); 470 | }, 471 | 472 | /** 473 | * Creates and executes a temporary view. 474 | */ 475 | query: function(mapFun, reduceFun, language, options) { 476 | language = language || "javascript"; 477 | if (typeof(mapFun) !== "string") { 478 | mapFun = mapFun.toSource ? mapFun.toSource() : "(" + mapFun.toString() + ")"; 479 | } 480 | var body = { 481 | language: language, 482 | map: mapFun 483 | }; 484 | if (reduceFun !== null) { 485 | if (typeof(reduceFun) !== "string") reduceFun = reduceFun.toSource ? reduceFun.toSource() : "(" + reduceFun.toString() + ")"; 486 | body.reduce = reduceFun; 487 | } 488 | ajax({ 489 | method: "POST", 490 | url: this.uri + "_temp_view", 491 | data: body, 492 | headers: { 493 | "Content-Type": "application/json" 494 | } 495 | }, 496 | options); 497 | }, 498 | 499 | /** 500 | * Fetch a _list view output. You can specify a list of 501 | * keys in the options object to receive only those keys. 502 | */ 503 | list: function(list, view, options) { 504 | list = list.split('/'); 505 | var method = 'GET'; 506 | var data = null; 507 | if (options.keys) { 508 | method = 'POST'; 509 | var keys = options.keys; 510 | delete options.keys; 511 | data = { 512 | 'keys': keys 513 | }; 514 | } 515 | ajax({ 516 | method: method, 517 | data: data, 518 | url: this.uri + '_design/' + list[0] + '/_list/' + list[1] + '/' + view 519 | }, 520 | options); 521 | }, 522 | 523 | /** 524 | * Executes the specified view-name from the specified design-doc 525 | * design document. You can specify a list of keys 526 | * in the options object to recieve only those keys. 527 | */ 528 | view: function(name, options) { 529 | name = name.split('/'); 530 | var method = "GET"; 531 | var data = null; 532 | if (options.keys) { 533 | method = "POST"; 534 | var keys = options.keys; 535 | delete options.keys; 536 | data = { 537 | "keys": keys 538 | }; 539 | } 540 | ajax({ 541 | method: method, 542 | data: data, 543 | url: this.uri + "_design/" + name[0] + "/_view/" + name[1] + '?' + encodeViewOptions(options) 544 | }, 545 | options); 546 | }, 547 | 548 | /** 549 | * Fetch an arbitrary CouchDB database property. As of 1.1, only the 550 | * _revs_limit property is available. 551 | */ 552 | getDbProperty: function(propName, options) { 553 | ajax({ 554 | url: this.uri + propName 555 | }, 556 | options); 557 | }, 558 | 559 | /** 560 | * Set an arbitrary CouchDB database property. As of 1.1, only the 561 | * _revs_limit property is available. 562 | */ 563 | setDbProperty: function(propName, propValue, options) { 564 | ajax({ 565 | method: "PUT", 566 | url: this.uri + propName, 567 | data: propValue 568 | }, 569 | options); 570 | } 571 | }; 572 | }; 573 | 574 | // Request, configure, or stop, a replication operation. 575 | module.replicate = function(source, target, options, repOpts) { 576 | repOpts = extend({ 577 | source : source, 578 | target : target 579 | }, repOpts); 580 | 581 | var ajaxOptions = { 582 | url : this.urlPrefix + "_replicate", 583 | method : "POST", 584 | data : repOpts, 585 | successStatus : [200, 202] 586 | }; 587 | 588 | ajax(ajaxOptions, options); 589 | }; 590 | } (exports)); 591 | 592 | /** 593 | * AJAX functions for CouchDB client 594 | */ 595 | 596 | function httpData(xhr, type) { 597 | var contentType = xhr.getResponseHeader("content-type") || ""; 598 | var isXml = type === "xml" || (!type && contentType.indexOf("xml") >= 0); 599 | var isJson = type === "json" || (!type && contentType.indexOf("json") >= 0); 600 | 601 | var data = isXml ? xhr.responseXML : xhr.responseText; 602 | if (typeof data === "string") { 603 | if (isJson) { 604 | data = JSON.parse(data); 605 | } 606 | // other types here? 607 | } 608 | return data; 609 | } 610 | 611 | 612 | 613 | function toQueryString(obj) { 614 | var buf = []; 615 | for (var name in obj) { 616 | var value = obj[name]; 617 | if (inArray(name, ["key", "startkey", "endkey"]) >= 0) { 618 | value = JSON.stringify(value); 619 | } 620 | buf.push(encodeURIComponent(name) + "=" + encodeURIComponent(value)); 621 | } 622 | return buf.length ? buf.join("&") : ""; 623 | } 624 | 625 | /** 626 | * 627 | * opts.method HTTP method to use 628 | * opts.successStatus default 200; set to 201 for document create 629 | * opts.data for HTTP GET, the query parameters; otherwise request body 630 | * opts.headers extra headers to send 631 | * opts.success function(data) called on success; data is the object returned in the response 632 | * opts.failure function(xhr) called on failure with XMLHttpRequest object 633 | */ 634 | function ajax(req, opts, xhrOpts) { 635 | opts = opts || {}; 636 | xhrOpts = xhrOpts || {}; 637 | 638 | //var request = extend(req, opts); 639 | var request = extend({ 640 | successStatus: [200], 641 | method: "GET" 642 | }, 643 | req); 644 | 645 | // encode request.data onto URL 646 | if (request.data && request.method !== "POST" && request.method !== "PUT") { 647 | request.url += (request.url.indexOf("?") > -1 ? "&" : "?") + toQueryString(request.data); 648 | delete request.data; 649 | } 650 | 651 | successStatus = isArray(request.successStatus) ? request.successStatus : Array(request.successStatus); 652 | 653 | // Ti.API.info(req); 654 | // Ti.API.info(opts); 655 | // Ti.API.info(xhrOpts); 656 | var xhr = Ti.Network.createHTTPClient(extend({ 657 | onload: function(e) { 658 | var req = e.source, 659 | resp; 660 | try { 661 | resp = httpData(req, "json"); 662 | } 663 | catch(err) { 664 | Ti.API.error(err.name + ": " + err.message); 665 | if (opts.failure) { 666 | opts.failure(req); 667 | } else { 668 | Ti.API.error(err); 669 | } 670 | } 671 | 672 | if (inArray(req.status, successStatus) >= 0) { 673 | if (opts.success) { 674 | opts.success(resp); 675 | } 676 | } else if (opts.failure) { 677 | opts.failure(req); 678 | } else { 679 | Ti.API.error("bad response: " + req.status + " " + req.responseText); 680 | } 681 | }, 682 | onerror: function(e) { 683 | var req = e.source; 684 | if (opts.failure) { 685 | opts.failure(req); 686 | } else { 687 | Ti.API.error("AJAX error: " + JSON.stringify(e) + " " + req.status + " " + req.responseText); 688 | } 689 | } 690 | }, 691 | xhrOpts)); 692 | 693 | xhr.open(request.method, request.url); 694 | Ti.API.debug(request.method + " " + request.url); 695 | 696 | xhr.setMaxRedirects(0); 697 | 698 | // basic auth 699 | if (opts.username) { 700 | xhr.setRequestHeader('Authorization', 'Basic ' + Ti.Utils.base64encode(opts.username + ':' + opts.password)); 701 | } 702 | 703 | // generic Accept header, may be overwritten below 704 | xhr.setRequestHeader("Accept", "*/*"); 705 | 706 | if (request.method === "POST" || request.method === "PUT") { 707 | xhr.setRequestHeader("Content-Type", "application/json"); 708 | } 709 | 710 | // extra headers 711 | if (request.headers) { 712 | for (var header in request.headers) { 713 | xhr.setRequestHeader(header, request.headers[header]); 714 | } 715 | } 716 | 717 | xhr.send(isPlainObject(request.data) ? JSON.stringify(request.data) : request.data); 718 | } 719 | 720 | /* 721 | * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined 722 | * in FIPS PUB 180-1 723 | * Version 2.1a Copyright Paul Johnston 2000 - 2002. 724 | * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet 725 | * Distributed under the BSD License 726 | * See http://pajhome.org.uk/crypt/md5 for details. 727 | */ 728 | 729 | /* 730 | * Configurable variables. You may need to tweak these to be compatible with 731 | * the server-side, but the defaults work in most cases. 732 | */ 733 | var hexcase = 0; 734 | /* hex output format. 0 - lowercase; 1 - uppercase */ 735 | var b64pad = "="; 736 | /* base-64 pad character. "=" for strict RFC compliance */ 737 | var chrsz = 8; 738 | /* bits per input character. 8 - ASCII; 16 - Unicode */ 739 | 740 | /* 741 | * These are the functions you'll usually want to call 742 | * They take string arguments and return either hex or base-64 encoded strings 743 | */ 744 | function hex_sha1(s) { 745 | return binb2hex(core_sha1(str2binb(s), s.length * chrsz)); 746 | } 747 | 748 | 749 | function b64_sha1(s) { 750 | return binb2b64(core_sha1(str2binb(s), s.length * chrsz)); 751 | } 752 | 753 | 754 | function str_sha1(s) { 755 | return binb2str(core_sha1(str2binb(s), s.length * chrsz)); 756 | } 757 | 758 | 759 | function hex_hmac_sha1(key, data) { 760 | return binb2hex(core_hmac_sha1(key, data)); 761 | } 762 | 763 | 764 | function b64_hmac_sha1(key, data) { 765 | return binb2b64(core_hmac_sha1(key, data)); 766 | } 767 | 768 | 769 | function str_hmac_sha1(key, data) { 770 | return binb2str(core_hmac_sha1(key, data)); 771 | } 772 | 773 | /* 774 | * Perform a simple self-test to see if the VM is working 775 | */ 776 | function sha1_vm_test() { 777 | return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d"; 778 | } 779 | 780 | /* 781 | * Calculate the SHA-1 of an array of big-endian words, and a bit length 782 | */ 783 | function core_sha1(x, len) { 784 | /* append padding */ 785 | x[len >> 5] |= 0x80 << (24 - len % 32); 786 | x[((len + 64 >> 9) << 4) + 15] = len; 787 | 788 | var w = Array(80); 789 | var a = 1732584193; 790 | var b = -271733879; 791 | var c = -1732584194; 792 | var d = 271733878; 793 | var e = -1009589776; 794 | 795 | for (var i = 0; i < x.length; i += 16) { 796 | var olda = a; 797 | var oldb = b; 798 | var oldc = c; 799 | var oldd = d; 800 | var olde = e; 801 | 802 | for (var j = 0; j < 80; j++) { 803 | if (j < 16) w[j] = x[i + j]; 804 | else w[j] = rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1); 805 | var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), safe_add(safe_add(e, w[j]), sha1_kt(j))); 806 | e = d; 807 | d = c; 808 | c = rol(b, 30); 809 | b = a; 810 | a = t; 811 | } 812 | 813 | a = safe_add(a, olda); 814 | b = safe_add(b, oldb); 815 | c = safe_add(c, oldc); 816 | d = safe_add(d, oldd); 817 | e = safe_add(e, olde); 818 | } 819 | return Array(a, b, c, d, e); 820 | 821 | } 822 | 823 | /* 824 | * Perform the appropriate triplet combination function for the current 825 | * iteration 826 | */ 827 | function sha1_ft(t, b, c, d) { 828 | if (t < 20) return (b & c) | ((~b) & d); 829 | if (t < 40) return b ^ c ^ d; 830 | if (t < 60) return (b & c) | (b & d) | (c & d); 831 | return b ^ c ^ d; 832 | } 833 | 834 | /* 835 | * Determine the appropriate additive constant for the current iteration 836 | */ 837 | function sha1_kt(t) { 838 | return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : (t < 60) ? -1894007588 : -899497514; 839 | } 840 | 841 | /* 842 | * Calculate the HMAC-SHA1 of a key and some data 843 | */ 844 | function core_hmac_sha1(key, data) { 845 | var bkey = str2binb(key); 846 | if (bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz); 847 | 848 | var ipad = Array(16), 849 | opad = Array(16); 850 | for (var i = 0; i < 16; i++) { 851 | ipad[i] = bkey[i] ^ 0x36363636; 852 | opad[i] = bkey[i] ^ 0x5C5C5C5C; 853 | } 854 | 855 | var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz); 856 | return core_sha1(opad.concat(hash), 512 + 160); 857 | } 858 | 859 | /* 860 | * Add integers, wrapping at 2^32. This uses 16-bit operations internally 861 | * to work around bugs in some JS interpreters. 862 | */ 863 | function safe_add(x, y) { 864 | var lsw = (x & 0xFFFF) + (y & 0xFFFF); 865 | var msw = (x >> 16) + (y >> 16) + (lsw >> 16); 866 | return (msw << 16) | (lsw & 0xFFFF); 867 | } 868 | 869 | /* 870 | * Bitwise rotate a 32-bit number to the left. 871 | */ 872 | function rol(num, cnt) { 873 | return (num << cnt) | (num >>> (32 - cnt)); 874 | } 875 | 876 | /* 877 | * Convert an 8-bit or 16-bit string to an array of big-endian words 878 | * In 8-bit function, characters >255 have their hi-byte silently ignored. 879 | */ 880 | function str2binb(str) { 881 | var bin = []; 882 | var mask = (1 << chrsz) - 1; 883 | for (var i = 0; i < str.length * chrsz; i += chrsz) 884 | bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i % 32); 885 | return bin; 886 | } 887 | 888 | /* 889 | * Convert an array of big-endian words to a string 890 | */ 891 | function binb2str(bin) { 892 | var str = ""; 893 | var mask = (1 << chrsz) - 1; 894 | for (var i = 0; i < bin.length * 32; i += chrsz) 895 | str += String.fromCharCode((bin[i >> 5] >>> (32 - chrsz - i % 32)) & mask); 896 | return str; 897 | } 898 | 899 | /* 900 | * Convert an array of big-endian words to a hex string. 901 | */ 902 | function binb2hex(binarray) { 903 | var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; 904 | var str = ""; 905 | for (var i = 0; i < binarray.length * 4; i++) { 906 | str += hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8 + 4)) & 0xF) + hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8)) & 0xF); 907 | } 908 | return str; 909 | } 910 | 911 | /* 912 | * Convert an array of big-endian words to a base-64 string 913 | */ 914 | function binb2b64(binarray) { 915 | var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 916 | var str = ""; 917 | for (var i = 0; i < binarray.length * 4; i += 3) { 918 | var triplet = (((binarray[i >> 2] >> 8 * (3 - i % 4)) & 0xFF) << 16) | (((binarray[i + 1 >> 2] >> 8 * (3 - (i + 1) % 4)) & 0xFF) << 8) | ((binarray[i + 2 >> 2] >> 8 * (3 - (i + 2) % 4)) & 0xFF); 919 | for (var j = 0; j < 4; j++) { 920 | if (i * 8 + j * 6 > binarray.length * 32) str += b64pad; 921 | else str += tab.charAt((triplet >> 6 * (3 - j)) & 0x3F); 922 | } 923 | } 924 | return str; 925 | } 926 | 927 | /* Copyright (C) 1999 Masanao Izumo 928 | * Version: 1.0 929 | * LastModified: Dec 25 1999 930 | * This library is free. You can redistribute it and/or modify it. 931 | */ 932 | /* Modified by Chris Anderson to not use CommonJS */ 933 | /* Modified by Dan Webb not to require Narwhal's binary library */ 934 | 935 | var Base64 = {}; 936 | (function(exports) { 937 | 938 | var encodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 939 | var decodeChars = [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1]; 940 | 941 | exports.encode = function(str) { 942 | var out, i, length; 943 | var c1, c2, c3; 944 | 945 | length = len(str); 946 | i = 0; 947 | out = []; 948 | while (i < length) { 949 | c1 = str.charCodeAt(i++) & 0xff; 950 | if (i == length) { 951 | out.push(encodeChars.charCodeAt(c1 >> 2)); 952 | out.push(encodeChars.charCodeAt((c1 & 0x3) << 4)); 953 | out.push("=".charCodeAt(0)); 954 | out.push("=".charCodeAt(0)); 955 | break; 956 | } 957 | c2 = str.charCodeAt(i++); 958 | if (i == length) { 959 | out.push(encodeChars.charCodeAt(c1 >> 2)); 960 | out.push(encodeChars.charCodeAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4))); 961 | out.push(encodeChars.charCodeAt((c2 & 0xF) << 2)); 962 | out.push("=".charCodeAt(0)); 963 | break; 964 | } 965 | c3 = str.charCodeAt(i++); 966 | out.push(encodeChars.charCodeAt(c1 >> 2)); 967 | out.push(encodeChars.charCodeAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4))); 968 | out.push(encodeChars.charCodeAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6))); 969 | out.push(encodeChars.charCodeAt(c3 & 0x3F)); 970 | } 971 | 972 | str = ""; 973 | out.forEach(function(chr) { 974 | str += String.fromCharCode(chr); 975 | }); 976 | return str; 977 | }; 978 | 979 | exports.decode = function(str) { 980 | var c1, c2, c3, c4; 981 | var i, length, out; 982 | 983 | length = len(str); 984 | i = 0; 985 | out = []; 986 | while (i < length) { 987 | /* c1 */ 988 | do { 989 | c1 = decodeChars[str.charCodeAt(i++) & 0xff]; 990 | } while (i < length && c1 == -1); 991 | if (c1 == -1) break; 992 | 993 | /* c2 */ 994 | do { 995 | c2 = decodeChars[str.charCodeAt(i++) & 0xff]; 996 | } while (i < length && c2 == -1); 997 | if (c2 == -1) break; 998 | 999 | out.push(String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4))); 1000 | 1001 | /* c3 */ 1002 | do { 1003 | c3 = str.charCodeAt(i++) & 0xff; 1004 | if (c3 == 61) return out.join(''); 1005 | c3 = decodeChars[c3]; 1006 | } while (i < length && c3 == -1); 1007 | if (c3 == -1) break; 1008 | 1009 | out.push(String.fromCharCode(((c2 & 0xF) << 4) | ((c3 & 0x3C) >> 2))); 1010 | 1011 | /* c4 */ 1012 | do { 1013 | c4 = str.charCodeAt(i++) & 0xff; 1014 | if (c4 == 61) return out.join(''); 1015 | c4 = decodeChars[c4]; 1016 | } while (i < length && c4 == -1); 1017 | 1018 | if (c4 == -1) break; 1019 | 1020 | out.push(String.fromCharCode(((c3 & 0x03) << 6) | c4)); 1021 | } 1022 | 1023 | return out.join(''); 1024 | }; 1025 | 1026 | var len = function(object) { 1027 | if (object.length !== undefined) { 1028 | return object.length; 1029 | } else if (object.getLength !== undefined) { 1030 | return object.getLength(); 1031 | } else { 1032 | return undefined; 1033 | } 1034 | }; 1035 | })(Base64); 1036 | 1037 | var class2type = []; 1038 | (function(o) { 1039 | var types = ["Boolean", "Number", "String", "Function", "Array", "Date", "RegExp", "Object"]; 1040 | for (var i = 0, length = types.length; i < length; i++) { 1041 | var name = types[i]; 1042 | var key = "[object " + name + "]"; 1043 | o[key] = name.toLowerCase(); 1044 | } 1045 | } (class2type)); 1046 | 1047 | var hasOwn = Object.prototype.hasOwnProperty, 1048 | toString = Object.prototype.toString; 1049 | 1050 | 1051 | 1052 | function type(obj) { 1053 | return obj === null ? String(obj) : class2type[toString.call(obj)] || "object"; 1054 | } 1055 | 1056 | 1057 | 1058 | function isPlainObject(obj) { 1059 | if (!obj || type(obj) !== "object") { 1060 | return false; 1061 | } 1062 | 1063 | // Not own constructor property must be Object 1064 | if (obj.constructor && !hasOwn.call(obj, "constructor") && !hasOwn.call(obj.constructor.prototype, "isPrototypeOf")) { 1065 | return false; 1066 | } 1067 | 1068 | // Own properties are enumerated firstly, so to speed up, 1069 | // if last one is own, then all properties are own. 1070 | var key; 1071 | for (key in obj) {} 1072 | 1073 | return key === undefined || hasOwn.call(obj, key); 1074 | } 1075 | 1076 | 1077 | 1078 | function isEmptyObject(obj) { 1079 | for (var name in obj) { 1080 | return false; 1081 | } 1082 | return true; 1083 | } 1084 | 1085 | 1086 | 1087 | function isArray(obj) { 1088 | return type(obj) === "array"; 1089 | } 1090 | 1091 | 1092 | 1093 | function isFunction(obj) { 1094 | return type(obj) === "function"; 1095 | } 1096 | 1097 | 1098 | 1099 | function each(object, callback, args) { 1100 | var name, i = 0, 1101 | length = object.length, 1102 | isObj = length === undefined || isFunction(object); 1103 | 1104 | if (args) { 1105 | if (isObj) { 1106 | for (name in object) { 1107 | if (callback.apply(object[name], args) === false) { 1108 | break; 1109 | } 1110 | } 1111 | } else { 1112 | for (; i < length;) { 1113 | if (callback.apply(object[i++], args) === false) { 1114 | break; 1115 | } 1116 | } 1117 | } 1118 | 1119 | // A special, fast, case for the most common use of each 1120 | } else { 1121 | if (isObj) { 1122 | for (name in object) { 1123 | if (callback.call(object[name], name, object[name]) === false) { 1124 | break; 1125 | } 1126 | } 1127 | } else { 1128 | for (; i < length;) { 1129 | if (callback.call(object[i], i, object[i++]) === false) { 1130 | break; 1131 | } 1132 | } 1133 | } 1134 | } 1135 | 1136 | return object; 1137 | } 1138 | 1139 | 1140 | 1141 | function extend() { 1142 | var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {}, 1143 | i = 1, 1144 | length = arguments.length, 1145 | deep = false; 1146 | 1147 | // Handle a deep copy situation 1148 | if (typeof target === "boolean") { 1149 | deep = target; 1150 | target = arguments[1] || {}; 1151 | // skip the boolean and the target 1152 | i = 2; 1153 | } 1154 | 1155 | // Handle case when target is a string or something (possible in deep copy) 1156 | if (typeof target !== "object" && !isFunction(target)) { 1157 | target = {}; 1158 | } 1159 | 1160 | // extend jQuery itself if only one argument is passed 1161 | if (length === i) { 1162 | target = this; 1163 | --i; 1164 | } 1165 | 1166 | for (; i < length; i++) { 1167 | // Only deal with non-null/undefined values 1168 | if ((options = arguments[i]) !== null) { 1169 | // Extend the base object 1170 | for (name in options) { 1171 | if (options.hasOwnProperty(name)) { 1172 | src = target[name]; 1173 | copy = options[name]; 1174 | 1175 | // Prevent never-ending loop 1176 | if (target === copy) { 1177 | continue; 1178 | } 1179 | 1180 | // Recurse if we're merging plain objects or arrays 1181 | if (deep && copy && (isPlainObject(copy) || (copyIsArray = isArray(copy)))) { 1182 | if (copyIsArray) { 1183 | copyIsArray = false; 1184 | clone = src && isArray(src) ? src : []; 1185 | 1186 | } else { 1187 | clone = src && isPlainObject(src) ? src : {}; 1188 | } 1189 | 1190 | // Never move original objects, clone them 1191 | target[name] = extend(deep, clone, copy); 1192 | 1193 | // Don't bring in undefined values 1194 | } else if (copy !== undefined) { 1195 | target[name] = copy; 1196 | } 1197 | } 1198 | } 1199 | } 1200 | } 1201 | 1202 | // Return the modified object 1203 | return target; 1204 | } 1205 | 1206 | 1207 | 1208 | function inArray(elem, array) { 1209 | if (Array.prototype.indexOf) { 1210 | return array.indexOf(elem); 1211 | } 1212 | 1213 | for (var i = 0, length = array.length; i < length; i++) { 1214 | if (array[i] === elem) { 1215 | return i; 1216 | } 1217 | } 1218 | 1219 | return -1; 1220 | } 1221 | 1222 | 1223 | 1224 | function toJSON(obj) { 1225 | return obj !== null ? JSON.stringify(obj) : null; 1226 | } 1227 | 1228 | // Convert a options object to an url query string. 1229 | // ex: {key:'value',key2:'value2'} becomes '?key="value"&key2="value2"' 1230 | function encodeOptions(options) { 1231 | var buf = []; 1232 | if (typeof(options) == "object" && options !== null) { 1233 | for (var name in options) { 1234 | if (name == "error" || name == "success") continue; 1235 | var value = options[name]; 1236 | if (name == "key" || name == "startkey" || name == "endkey") { 1237 | value = toJSON(value); 1238 | } 1239 | buf.push(encodeURIComponent(name) + "=" + encodeURIComponent(value)); 1240 | } 1241 | } 1242 | return buf.length ? "?" + buf.join("&") : ""; 1243 | } -------------------------------------------------------------------------------- /mobile/ios/build.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Appcelerator Titanium Module Packager 4 | # 5 | # 6 | import os, sys, glob, string 7 | import zipfile 8 | 9 | cwd = os.path.abspath(os.path.dirname(sys._getframe(0).f_code.co_filename)) 10 | os.chdir(cwd) 11 | required_module_keys = ['name','version','moduleid','description','copyright','license','copyright','platform','minsdk'] 12 | module_defaults = { 13 | 'description':'My module', 14 | 'author': 'Your Name', 15 | 'license' : 'Specify your license', 16 | 'copyright' : 'Copyright (c) 2010 by Your Company', 17 | } 18 | module_license_default = "TODO: place your license here and we'll include it in the module distribution" 19 | 20 | def replace_vars(config,token): 21 | idx = token.find('$(') 22 | while idx != -1: 23 | idx2 = token.find(')',idx+2) 24 | if idx2 == -1: break 25 | key = token[idx+2:idx2] 26 | if not config.has_key(key): break 27 | token = token.replace('$(%s)' % key, config[key]) 28 | idx = token.find('$(') 29 | return token 30 | 31 | 32 | def read_ti_xcconfig(): 33 | contents = open(os.path.join(cwd,'titanium.xcconfig')).read() 34 | config = {} 35 | for line in contents.splitlines(False): 36 | line = line.strip() 37 | if line[0:2]=='//': continue 38 | idx = line.find('=') 39 | if idx > 0: 40 | key = line[0:idx].strip() 41 | value = line[idx+1:].strip() 42 | config[key] = replace_vars(config,value) 43 | return config 44 | 45 | def generate_doc(config): 46 | docdir = os.path.join(cwd,'documentation') 47 | if not os.path.exists(docdir): 48 | print "Couldn't find documentation file at: %s" % docdir 49 | return None 50 | sdk = config['TITANIUM_SDK'] 51 | support_dir = os.path.join(sdk,'module','support') 52 | sys.path.append(support_dir) 53 | import markdown 54 | documentation = [] 55 | for file in os.listdir(docdir): 56 | if file[0]=='.': continue 57 | md = open(os.path.join(docdir,file)).read() 58 | html = markdown.markdown(md) 59 | documentation.append({file:html}); 60 | return documentation 61 | 62 | def compile_js(manifest,config): 63 | js_file = os.path.join(cwd,'assets','com.obscure.couchdb_client.js') 64 | if not os.path.exists(js_file): return 65 | 66 | sdk = config['TITANIUM_SDK'] 67 | iphone_dir = os.path.join(sdk,'iphone') 68 | sys.path.insert(0,iphone_dir) 69 | from compiler import Compiler 70 | 71 | path = os.path.basename(js_file) 72 | metadata = Compiler.make_function_from_file(path,js_file) 73 | method = metadata['method'] 74 | eq = path.replace('.','_') 75 | method = ' return %s;' % method 76 | 77 | f = os.path.join(cwd,'Classes','ComObscureCouchdb_clientModuleAssets.m') 78 | c = open(f).read() 79 | idx = c.find('return ') 80 | before = c[0:idx] 81 | after = """ 82 | } 83 | 84 | @end 85 | """ 86 | newc = before + method + after 87 | 88 | if newc!=c: 89 | x = open(f,'w') 90 | x.write(newc) 91 | x.close() 92 | 93 | def die(msg): 94 | print msg 95 | sys.exit(1) 96 | 97 | def warn(msg): 98 | print "[WARN] %s" % msg 99 | 100 | def validate_license(): 101 | c = open(os.path.join(cwd,'LICENSE')).read() 102 | if c.find(module_license_default)!=1: 103 | warn('please update the LICENSE file with your license text before distributing') 104 | 105 | def validate_manifest(): 106 | path = os.path.join(cwd,'manifest') 107 | f = open(path) 108 | if not os.path.exists(path): die("missing %s" % path) 109 | manifest = {} 110 | for line in f.readlines(): 111 | line = line.strip() 112 | if line[0:1]=='#': continue 113 | if line.find(':') < 0: continue 114 | key,value = line.split(':') 115 | manifest[key.strip()]=value.strip() 116 | for key in required_module_keys: 117 | if not manifest.has_key(key): die("missing required manifest key '%s'" % key) 118 | if module_defaults.has_key(key): 119 | defvalue = module_defaults[key] 120 | curvalue = manifest[key] 121 | if curvalue==defvalue: warn("please update the manifest key: '%s' to a non-default value" % key) 122 | return manifest,path 123 | 124 | ignoreFiles = ['.DS_Store','.gitignore','libTitanium.a','titanium.jar','README','com.obscure.couchdb_client.js'] 125 | ignoreDirs = ['.DS_Store','.svn','.git','CVSROOT'] 126 | 127 | def zip_dir(zf,dir,basepath,ignore=[]): 128 | for root, dirs, files in os.walk(dir): 129 | for name in ignoreDirs: 130 | if name in dirs: 131 | dirs.remove(name) # don't visit ignored directories 132 | for file in files: 133 | if file in ignoreFiles: continue 134 | e = os.path.splitext(file) 135 | if len(e)==2 and e[1]=='.pyc':continue 136 | from_ = os.path.join(root, file) 137 | to_ = from_.replace(dir, basepath, 1) 138 | zf.write(from_, to_) 139 | 140 | def glob_libfiles(): 141 | files = [] 142 | for libfile in glob.glob('build/**/*.a'): 143 | if libfile.find('Release-')!=-1: 144 | files.append(libfile) 145 | return files 146 | 147 | def build_module(manifest,config): 148 | rc = os.system("xcodebuild -sdk iphoneos -configuration Release") 149 | if rc != 0: 150 | die("xcodebuild failed") 151 | rc = os.system("xcodebuild -sdk iphonesimulator -configuration Release") 152 | if rc != 0: 153 | die("xcodebuild failed") 154 | # build the merged library using lipo 155 | moduleid = manifest['moduleid'] 156 | libpaths = '' 157 | for libfile in glob_libfiles(): 158 | libpaths+='%s ' % libfile 159 | 160 | os.system("lipo %s -create -output build/lib%s.a" %(libpaths,moduleid)) 161 | 162 | def package_module(manifest,mf,config): 163 | name = manifest['name'].lower() 164 | moduleid = manifest['moduleid'].lower() 165 | version = manifest['version'] 166 | modulezip = '%s-iphone-%s.zip' % (moduleid,version) 167 | if os.path.exists(modulezip): os.remove(modulezip) 168 | zf = zipfile.ZipFile(modulezip, 'w', zipfile.ZIP_DEFLATED) 169 | modulepath = 'modules/iphone/%s/%s' % (moduleid,version) 170 | zf.write(mf,'%s/manifest' % modulepath) 171 | libname = 'lib%s.a' % moduleid 172 | zf.write('build/%s' % libname, '%s/%s' % (modulepath,libname)) 173 | docs = generate_doc(config) 174 | if docs!=None: 175 | for doc in docs: 176 | for file, html in doc.iteritems(): 177 | filename = string.replace(file,'.md','.html') 178 | zf.writestr('%s/documentation/%s'%(modulepath,filename),html) 179 | for dn in ('assets','example'): 180 | if os.path.exists(dn): 181 | zip_dir(zf,dn,'%s/%s' % (modulepath,dn),['README']) 182 | zf.write('LICENSE','%s/LICENSE' % modulepath) 183 | zf.write('module.xcconfig','%s/module.xcconfig' % modulepath) 184 | zf.close() 185 | 186 | 187 | if __name__ == '__main__': 188 | manifest,mf = validate_manifest() 189 | validate_license() 190 | config = read_ti_xcconfig() 191 | compile_js(manifest,config) 192 | build_module(manifest,config) 193 | package_module(manifest,mf,config) 194 | sys.exit(0) 195 | 196 | -------------------------------------------------------------------------------- /mobile/ios/couchdb_client.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 45; 7 | objects = { 8 | 9 | /* Begin PBXAggregateTarget section */ 10 | 24416B8111C4CA220047AFDD /* Build & Test */ = { 11 | isa = PBXAggregateTarget; 12 | buildConfigurationList = 24416B8A11C4CA520047AFDD /* Build configuration list for PBXAggregateTarget "Build & Test" */; 13 | buildPhases = ( 14 | 24416B8011C4CA220047AFDD /* ShellScript */, 15 | ); 16 | dependencies = ( 17 | 24416B8511C4CA280047AFDD /* PBXTargetDependency */, 18 | ); 19 | name = "Build & Test"; 20 | productName = "Build & test"; 21 | }; 22 | /* End PBXAggregateTarget section */ 23 | 24 | /* Begin PBXBuildFile section */ 25 | 24DD6CF91134B3F500162E58 /* ComObscureCouchdb_clientModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 24DD6CF71134B3F500162E58 /* ComObscureCouchdb_clientModule.h */; }; 26 | 24DD6CFA1134B3F500162E58 /* ComObscureCouchdb_clientModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 24DD6CF81134B3F500162E58 /* ComObscureCouchdb_clientModule.m */; }; 27 | 24DE9E1111C5FE74003F90F6 /* ComObscureCouchdb_clientModuleAssets.h in Headers */ = {isa = PBXBuildFile; fileRef = 24DE9E0F11C5FE74003F90F6 /* ComObscureCouchdb_clientModuleAssets.h */; }; 28 | 24DE9E1211C5FE74003F90F6 /* ComObscureCouchdb_clientModuleAssets.m in Sources */ = {isa = PBXBuildFile; fileRef = 24DE9E1011C5FE74003F90F6 /* ComObscureCouchdb_clientModuleAssets.m */; }; 29 | AA747D9F0F9514B9006C5449 /* ComObscureCouchdb_client_Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = AA747D9E0F9514B9006C5449 /* ComObscureCouchdb_client_Prefix.pch */; }; 30 | AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AACBBE490F95108600F1A2B1 /* Foundation.framework */; }; 31 | /* End PBXBuildFile section */ 32 | 33 | /* Begin PBXContainerItemProxy section */ 34 | 24416B8411C4CA280047AFDD /* PBXContainerItemProxy */ = { 35 | isa = PBXContainerItemProxy; 36 | containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; 37 | proxyType = 1; 38 | remoteGlobalIDString = D2AAC07D0554694100DB518D; 39 | remoteInfo = "couchdb_client"; 40 | }; 41 | /* End PBXContainerItemProxy section */ 42 | 43 | /* Begin PBXFileReference section */ 44 | 24DD6CF71134B3F500162E58 /* ComObscureCouchdb_clientModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "ComObscureCouchdb_clientModule.h"; path = "Classes/ComObscureCouchdb_clientModule.h"; sourceTree = ""; }; 45 | 24DD6CF81134B3F500162E58 /* ComObscureCouchdb_clientModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "ComObscureCouchdb_clientModule.m"; path = "Classes/ComObscureCouchdb_clientModule.m"; sourceTree = ""; }; 46 | 24DD6D1B1134B66800162E58 /* titanium.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = titanium.xcconfig; sourceTree = ""; }; 47 | 24DE9E0F11C5FE74003F90F6 /* ComObscureCouchdb_clientModuleAssets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "ComObscureCouchdb_clientModuleAssets.h"; path = "Classes/ComObscureCouchdb_clientModuleAssets.h"; sourceTree = ""; }; 48 | 24DE9E1011C5FE74003F90F6 /* ComObscureCouchdb_clientModuleAssets.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "ComObscureCouchdb_clientModuleAssets.m"; path = "Classes/ComObscureCouchdb_clientModuleAssets.m"; sourceTree = ""; }; 49 | AA747D9E0F9514B9006C5449 /* ComObscureCouchdb_client_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ComObscureCouchdb_client_Prefix.pch"; sourceTree = SOURCE_ROOT; }; 50 | AACBBE490F95108600F1A2B1 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 51 | D2AAC07E0554694100DB518D /* libComObscureCouchdb_client.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libComObscureCouchdb_client.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 52 | /* End PBXFileReference section */ 53 | 54 | /* Begin PBXFrameworksBuildPhase section */ 55 | D2AAC07C0554694100DB518D /* Frameworks */ = { 56 | isa = PBXFrameworksBuildPhase; 57 | buildActionMask = 2147483647; 58 | files = ( 59 | AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */, 60 | ); 61 | runOnlyForDeploymentPostprocessing = 0; 62 | }; 63 | /* End PBXFrameworksBuildPhase section */ 64 | 65 | /* Begin PBXGroup section */ 66 | 034768DFFF38A50411DB9C8B /* Products */ = { 67 | isa = PBXGroup; 68 | children = ( 69 | D2AAC07E0554694100DB518D /* libComObscureCouchdb_client.a */, 70 | ); 71 | name = Products; 72 | sourceTree = ""; 73 | }; 74 | 0867D691FE84028FC02AAC07 /* couchdb_client */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | 08FB77AEFE84172EC02AAC07 /* Classes */, 78 | 32C88DFF0371C24200C91783 /* Other Sources */, 79 | 0867D69AFE84028FC02AAC07 /* Frameworks */, 80 | 034768DFFF38A50411DB9C8B /* Products */, 81 | ); 82 | name = "couchdb_client"; 83 | sourceTree = ""; 84 | }; 85 | 0867D69AFE84028FC02AAC07 /* Frameworks */ = { 86 | isa = PBXGroup; 87 | children = ( 88 | AACBBE490F95108600F1A2B1 /* Foundation.framework */, 89 | ); 90 | name = Frameworks; 91 | sourceTree = ""; 92 | }; 93 | 08FB77AEFE84172EC02AAC07 /* Classes */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | 24DE9E0F11C5FE74003F90F6 /* ComObscureCouchdb_clientModuleAssets.h */, 97 | 24DE9E1011C5FE74003F90F6 /* ComObscureCouchdb_clientModuleAssets.m */, 98 | 24DD6CF71134B3F500162E58 /* ComObscureCouchdb_clientModule.h */, 99 | 24DD6CF81134B3F500162E58 /* ComObscureCouchdb_clientModule.m */, 100 | ); 101 | name = Classes; 102 | sourceTree = ""; 103 | }; 104 | 32C88DFF0371C24200C91783 /* Other Sources */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | AA747D9E0F9514B9006C5449 /* ComObscureCouchdb_client_Prefix.pch */, 108 | 24DD6D1B1134B66800162E58 /* titanium.xcconfig */, 109 | ); 110 | name = "Other Sources"; 111 | sourceTree = ""; 112 | }; 113 | /* End PBXGroup section */ 114 | 115 | /* Begin PBXHeadersBuildPhase section */ 116 | D2AAC07A0554694100DB518D /* Headers */ = { 117 | isa = PBXHeadersBuildPhase; 118 | buildActionMask = 2147483647; 119 | files = ( 120 | AA747D9F0F9514B9006C5449 /* ComObscureCouchdb_client_Prefix.pch in Headers */, 121 | 24DD6CF91134B3F500162E58 /* ComObscureCouchdb_clientModule.h in Headers */, 122 | 24DE9E1111C5FE74003F90F6 /* ComObscureCouchdb_clientModuleAssets.h in Headers */, 123 | ); 124 | runOnlyForDeploymentPostprocessing = 0; 125 | }; 126 | /* End PBXHeadersBuildPhase section */ 127 | 128 | /* Begin PBXNativeTarget section */ 129 | D2AAC07D0554694100DB518D /* couchdb_client */ = { 130 | isa = PBXNativeTarget; 131 | buildConfigurationList = 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "couchdb_client" */; 132 | buildPhases = ( 133 | D2AAC07A0554694100DB518D /* Headers */, 134 | D2AAC07B0554694100DB518D /* Sources */, 135 | D2AAC07C0554694100DB518D /* Frameworks */, 136 | ); 137 | buildRules = ( 138 | ); 139 | dependencies = ( 140 | ); 141 | name = "couchdb_client"; 142 | productName = "couchdb_client"; 143 | productReference = D2AAC07E0554694100DB518D /* libComObscureCouchdb_client.a */; 144 | productType = "com.apple.product-type.library.static"; 145 | }; 146 | /* End PBXNativeTarget section */ 147 | 148 | /* Begin PBXProject section */ 149 | 0867D690FE84028FC02AAC07 /* Project object */ = { 150 | isa = PBXProject; 151 | buildConfigurationList = 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "couchdb_client" */; 152 | compatibilityVersion = "Xcode 3.1"; 153 | developmentRegion = English; 154 | hasScannedForEncodings = 1; 155 | knownRegions = ( 156 | English, 157 | Japanese, 158 | French, 159 | German, 160 | ); 161 | mainGroup = 0867D691FE84028FC02AAC07 /* couchdb_client */; 162 | productRefGroup = 034768DFFF38A50411DB9C8B /* Products */; 163 | projectDirPath = ""; 164 | projectRoot = ""; 165 | targets = ( 166 | D2AAC07D0554694100DB518D /* couchdb_client */, 167 | 24416B8111C4CA220047AFDD /* Build & Test */, 168 | ); 169 | }; 170 | /* End PBXProject section */ 171 | 172 | /* Begin PBXShellScriptBuildPhase section */ 173 | 24416B8011C4CA220047AFDD /* ShellScript */ = { 174 | isa = PBXShellScriptBuildPhase; 175 | buildActionMask = 2147483647; 176 | files = ( 177 | ); 178 | inputPaths = ( 179 | ); 180 | outputPaths = ( 181 | ); 182 | runOnlyForDeploymentPostprocessing = 0; 183 | shellPath = /bin/sh; 184 | shellScript = "# shell script goes here\n\npython \"${TITANIUM_SDK}/titanium.py\" run --dir=\"${PROJECT_DIR}\"\nexit $?\n"; 185 | }; 186 | /* End PBXShellScriptBuildPhase section */ 187 | 188 | /* Begin PBXSourcesBuildPhase section */ 189 | D2AAC07B0554694100DB518D /* Sources */ = { 190 | isa = PBXSourcesBuildPhase; 191 | buildActionMask = 2147483647; 192 | files = ( 193 | 24DD6CFA1134B3F500162E58 /* ComObscureCouchdb_clientModule.m in Sources */, 194 | 24DE9E1211C5FE74003F90F6 /* ComObscureCouchdb_clientModuleAssets.m in Sources */, 195 | ); 196 | runOnlyForDeploymentPostprocessing = 0; 197 | }; 198 | /* End PBXSourcesBuildPhase section */ 199 | 200 | /* Begin PBXTargetDependency section */ 201 | 24416B8511C4CA280047AFDD /* PBXTargetDependency */ = { 202 | isa = PBXTargetDependency; 203 | target = D2AAC07D0554694100DB518D /* couchdb_client */; 204 | targetProxy = 24416B8411C4CA280047AFDD /* PBXContainerItemProxy */; 205 | }; 206 | /* End PBXTargetDependency section */ 207 | 208 | /* Begin XCBuildConfiguration section */ 209 | 1DEB921F08733DC00010E9CD /* Debug */ = { 210 | isa = XCBuildConfiguration; 211 | baseConfigurationReference = 24DD6D1B1134B66800162E58 /* titanium.xcconfig */; 212 | buildSettings = { 213 | ALWAYS_SEARCH_USER_PATHS = NO; 214 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 215 | COPY_PHASE_STRIP = NO; 216 | DSTROOT = "/tmp/ComObscureCouchdb_client.dst"; 217 | GCC_DYNAMIC_NO_PIC = NO; 218 | GCC_ENABLE_FIX_AND_CONTINUE = YES; 219 | GCC_MODEL_TUNING = G5; 220 | GCC_OPTIMIZATION_LEVEL = 0; 221 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 222 | GCC_PREFIX_HEADER = "ComObscureCouchdb_client_Prefix.pch"; 223 | INSTALL_PATH = /usr/local/lib; 224 | PRODUCT_NAME = "ComObscureCouchdb_client"; 225 | }; 226 | name = Debug; 227 | }; 228 | 1DEB922008733DC00010E9CD /* Release */ = { 229 | isa = XCBuildConfiguration; 230 | baseConfigurationReference = 24DD6D1B1134B66800162E58 /* titanium.xcconfig */; 231 | buildSettings = { 232 | ALWAYS_SEARCH_USER_PATHS = NO; 233 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 234 | DSTROOT = "/tmp/ComObscureCouchdb_client.dst"; 235 | GCC_MODEL_TUNING = G5; 236 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 237 | GCC_PREFIX_HEADER = "ComObscureCouchdb_client_Prefix.pch"; 238 | INSTALL_PATH = /usr/local/lib; 239 | PRODUCT_NAME = "ComObscureCouchdb_client"; 240 | }; 241 | name = Release; 242 | }; 243 | 1DEB922308733DC00010E9CD /* Debug */ = { 244 | isa = XCBuildConfiguration; 245 | baseConfigurationReference = 24DD6D1B1134B66800162E58 /* titanium.xcconfig */; 246 | buildSettings = { 247 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 248 | GCC_C_LANGUAGE_STANDARD = c99; 249 | GCC_OPTIMIZATION_LEVEL = 0; 250 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 251 | GCC_WARN_UNUSED_VARIABLE = YES; 252 | OTHER_LDFLAGS = ""; 253 | PREBINDING = NO; 254 | SDKROOT = iphoneos4.0; 255 | }; 256 | name = Debug; 257 | }; 258 | 1DEB922408733DC00010E9CD /* Release */ = { 259 | isa = XCBuildConfiguration; 260 | baseConfigurationReference = 24DD6D1B1134B66800162E58 /* titanium.xcconfig */; 261 | buildSettings = { 262 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 263 | GCC_C_LANGUAGE_STANDARD = c99; 264 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 265 | GCC_WARN_UNUSED_VARIABLE = YES; 266 | OTHER_LDFLAGS = ""; 267 | PREBINDING = NO; 268 | SDKROOT = iphoneos4.0; 269 | }; 270 | name = Release; 271 | }; 272 | 24416B8211C4CA220047AFDD /* Debug */ = { 273 | isa = XCBuildConfiguration; 274 | baseConfigurationReference = 24DD6D1B1134B66800162E58 /* titanium.xcconfig */; 275 | buildSettings = { 276 | COPY_PHASE_STRIP = NO; 277 | GCC_DYNAMIC_NO_PIC = NO; 278 | GCC_OPTIMIZATION_LEVEL = 0; 279 | PRODUCT_NAME = "Build & test"; 280 | }; 281 | name = Debug; 282 | }; 283 | 24416B8311C4CA220047AFDD /* Release */ = { 284 | isa = XCBuildConfiguration; 285 | baseConfigurationReference = 24DD6D1B1134B66800162E58 /* titanium.xcconfig */; 286 | buildSettings = { 287 | COPY_PHASE_STRIP = YES; 288 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 289 | GCC_ENABLE_FIX_AND_CONTINUE = NO; 290 | PRODUCT_NAME = "Build & test"; 291 | ZERO_LINK = NO; 292 | }; 293 | name = Release; 294 | }; 295 | /* End XCBuildConfiguration section */ 296 | 297 | /* Begin XCConfigurationList section */ 298 | 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "couchdb_client" */ = { 299 | isa = XCConfigurationList; 300 | buildConfigurations = ( 301 | 1DEB921F08733DC00010E9CD /* Debug */, 302 | 1DEB922008733DC00010E9CD /* Release */, 303 | ); 304 | defaultConfigurationIsVisible = 0; 305 | defaultConfigurationName = Release; 306 | }; 307 | 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "couchdb_client" */ = { 308 | isa = XCConfigurationList; 309 | buildConfigurations = ( 310 | 1DEB922308733DC00010E9CD /* Debug */, 311 | 1DEB922408733DC00010E9CD /* Release */, 312 | ); 313 | defaultConfigurationIsVisible = 0; 314 | defaultConfigurationName = Release; 315 | }; 316 | 24416B8A11C4CA520047AFDD /* Build configuration list for PBXAggregateTarget "Build & Test" */ = { 317 | isa = XCConfigurationList; 318 | buildConfigurations = ( 319 | 24416B8211C4CA220047AFDD /* Debug */, 320 | 24416B8311C4CA220047AFDD /* Release */, 321 | ); 322 | defaultConfigurationIsVisible = 0; 323 | defaultConfigurationName = Release; 324 | }; 325 | /* End XCConfigurationList section */ 326 | }; 327 | rootObject = 0867D690FE84028FC02AAC07 /* Project object */; 328 | } 329 | -------------------------------------------------------------------------------- /mobile/ios/documentation/index.md: -------------------------------------------------------------------------------- 1 | # couchdb_client Module 2 | 3 | ## Description 4 | 5 | TODO: Enter your module description here 6 | 7 | ## Accessing the couchdb_client Module 8 | 9 | To access this module from JavaScript, you would do the following: 10 | 11 | var couchdb_client = require("com.obscure.couchdb_client"); 12 | 13 | The couchdb_client variable is a reference to the Module object. 14 | 15 | ## Reference 16 | 17 | TODO: If your module has an API, you should document 18 | the reference here. 19 | 20 | ### ___PROJECTNAMEASIDENTIFIER__.function 21 | 22 | TODO: This is an example of a module function. 23 | 24 | ### ___PROJECTNAMEASIDENTIFIER__.property 25 | 26 | TODO: This is an example of a module property. 27 | 28 | ## Usage 29 | 30 | TODO: Enter your usage example here 31 | 32 | ## Author 33 | 34 | TODO: Enter your author name, email and other contact 35 | details you want to share here. 36 | 37 | ## License 38 | 39 | TODO: Enter your license/legal information here. 40 | -------------------------------------------------------------------------------- /mobile/ios/example/app.js: -------------------------------------------------------------------------------- 1 | // This is a test harness for your module 2 | // You should do something interesting in this harness 3 | // to test out the module and to provide instructions 4 | // to users on how to use it by example. 5 | 6 | 7 | // open a single window 8 | var window = Ti.UI.createWindow({ 9 | backgroundColor:'white' 10 | }); 11 | var label = Ti.UI.createLabel({ 12 | text: "running tests" 13 | }); 14 | window.add(label); 15 | window.open(); 16 | 17 | // TODO: write your module tests here 18 | var couchdb = require('com.obscure.couchdb_client'); 19 | couchdb.urlPrefix = "http://localhost:5984"; 20 | 21 | couchdb.allDbs({ 22 | success: function(data) { 23 | label.text = JSON.stringify(data); 24 | var promise = couchdb.db("test").changes(); 25 | promise.onChange( function (data) { 26 | label.text = JSON.stringify(data); 27 | }); 28 | } 29 | }); 30 | 31 | 32 | -------------------------------------------------------------------------------- /mobile/ios/hooks/README: -------------------------------------------------------------------------------- 1 | These files are not yet supported as of 1.4.0 but will be in a near future release. 2 | -------------------------------------------------------------------------------- /mobile/ios/hooks/add.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # This is the module project add hook that will be 4 | # called when your module is added to a project 5 | # 6 | import os, sys 7 | 8 | def dequote(s): 9 | if s[0:1] == '"': 10 | return s[1:-1] 11 | return s 12 | 13 | def main(args,argc): 14 | # You will get the following command line arguments 15 | # in the following order: 16 | # 17 | # project_dir = the full path to the project root directory 18 | # project_type = the type of project (desktop, mobile, ipad) 19 | # project_name = the name of the project 20 | # 21 | project_dir = dequote(os.path.expanduser(args[1])) 22 | project_type = dequote(args[2]) 23 | project_name = dequote(args[3]) 24 | 25 | # TODO: write your add hook here (optional) 26 | 27 | 28 | # exit 29 | sys.exit(0) 30 | 31 | 32 | 33 | if __name__ == '__main__': 34 | main(sys.argv,len(sys.argv)) 35 | 36 | -------------------------------------------------------------------------------- /mobile/ios/hooks/install.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # This is the module install hook that will be 4 | # called when your module is first installed 5 | # 6 | import os, sys 7 | 8 | def main(args,argc): 9 | 10 | # TODO: write your install hook here (optional) 11 | 12 | # exit 13 | sys.exit(0) 14 | 15 | 16 | 17 | if __name__ == '__main__': 18 | main(sys.argv,len(sys.argv)) 19 | 20 | -------------------------------------------------------------------------------- /mobile/ios/hooks/remove.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # This is the module project remove hook that will be 4 | # called when your module is remove from a project 5 | # 6 | import os, sys 7 | 8 | def dequote(s): 9 | if s[0:1] == '"': 10 | return s[1:-1] 11 | return s 12 | 13 | def main(args,argc): 14 | # You will get the following command line arguments 15 | # in the following order: 16 | # 17 | # project_dir = the full path to the project root directory 18 | # project_type = the type of project (desktop, mobile, ipad) 19 | # project_name = the name of the project 20 | # 21 | project_dir = dequote(os.path.expanduser(args[1])) 22 | project_type = dequote(args[2]) 23 | project_name = dequote(args[3]) 24 | 25 | # TODO: write your remove hook here (optional) 26 | 27 | # exit 28 | sys.exit(0) 29 | 30 | 31 | 32 | if __name__ == '__main__': 33 | main(sys.argv,len(sys.argv)) 34 | 35 | -------------------------------------------------------------------------------- /mobile/ios/hooks/uninstall.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # This is the module uninstall hook that will be 4 | # called when your module is uninstalled 5 | # 6 | import os, sys 7 | 8 | def main(args,argc): 9 | 10 | # TODO: write your uninstall hook here (optional) 11 | 12 | # exit 13 | sys.exit(0) 14 | 15 | 16 | if __name__ == '__main__': 17 | main(sys.argv,len(sys.argv)) 18 | 19 | -------------------------------------------------------------------------------- /mobile/ios/manifest: -------------------------------------------------------------------------------- 1 | # 2 | # this is your module manifest and used by Titanium 3 | # during compilation, packaging, distribution, etc. 4 | # 5 | version: 1.0 6 | description: CouchDB Client Module 7 | author: Paul Mietz Egli 8 | license: Apache 2.0 9 | copyright: Copyright (c) 2011 Paul Mietz Egli 10 | 11 | 12 | # these should not be edited 13 | name: couchdb_client 14 | moduleid: com.obscure.couchdb_client 15 | guid: 6474234f-0415-4683-969e-aa0073c86620 16 | platform: iphone 17 | minsdk: 1.6.2 18 | -------------------------------------------------------------------------------- /mobile/ios/module.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // PLACE ANY BUILD DEFINITIONS IN THIS FILE AND THEY WILL BE 3 | // PICKED UP DURING THE APP BUILD FOR YOUR MODULE 4 | // 5 | // see the following webpage for instructions on the settings 6 | // for this file: 7 | // http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/XcodeBuildSystem/400-Build_Configurations/build_configs.html 8 | // 9 | 10 | // 11 | // How to add a Framework (example) 12 | // 13 | // OTHER_LDFLAGS=$(inherited) -framework Foo 14 | // 15 | // Adding a framework for a specific version(s) of iPhone: 16 | // 17 | // OTHER_LDFLAGS[sdk=iphoneos4*]=$(inherited) -framework Foo 18 | // OTHER_LDFLAGS[sdk=iphonesimulator4*]=$(inherited) -framework Foo 19 | // 20 | // 21 | // How to add a compiler define: 22 | // 23 | // OTHER_CFLAGS=$(inherited) -DFOO=1 24 | // 25 | // 26 | // IMPORTANT NOTE: always use $(inherited) in your overrides 27 | // 28 | -------------------------------------------------------------------------------- /mobile/ios/timodule.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /mobile/ios/titanium.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // CHANGE THESE VALUES TO REFLECT THE VERSION (AND LOCATION IF DIFFERENT) 4 | // OF YOUR TITANIUM SDK YOU'RE BUILDING FOR 5 | // 6 | // 7 | TITANIUM_SDK_VERSION = 1.7.1 8 | 9 | 10 | // 11 | // THESE SHOULD BE OK GENERALLY AS-IS 12 | // 13 | TITANIUM_SDK = /Library/Application Support/Titanium/mobilesdk/osx/$(TITANIUM_SDK_VERSION) 14 | TITANIUM_BASE_SDK = "$(TITANIUM_SDK)/iphone/include" 15 | TITANIUM_BASE_SDK2 = "$(TITANIUM_SDK)/iphone/include/TiCore" 16 | HEADER_SEARCH_PATHS= $(TITANIUM_BASE_SDK) $(TITANIUM_BASE_SDK2) 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /mobile/noarch/com.obscure.couchdb_client.inc.js: -------------------------------------------------------------------------------- 1 | /** @module com.obscure.couchdb_client */ 2 | 3 | /** 4 | * @fileOverview 5 | * CouchDB client module for Appcelerator Titanium. All of the functions 6 | * in this module are asynchronous and use an options object for common 7 | * parameters. 8 | * @see options 9 | */ 10 | 11 | /** 12 | * @name options 13 | * @field 14 | * @property {Function} success called by the module when the CouchDB call completes 15 | * successfully. The parameter to this function is the response from CouchDB 16 | * as an object. 17 | * @property {Function} failure called by the module when the CouchDB call fails for 18 | * any reason. The parameter to this function is the XMLHttpRequest object used 19 | * in the call. You can extract the response code and error messages from that XHR. 20 | * @property {String} username the username to use during the call. Some CouchDB calls 21 | * require an admin user; depending on your security setup, other calls may also 22 | * require a valid user. 23 | * @property {String} password the password to use during the call. 24 | */ 25 | 26 | var couchdb_client = {}; 27 | 28 | (function(module) { 29 | 30 | /** @private */ 31 | function userDb(callback) { 32 | module.session({ 33 | success: function(resp) { 34 | var userDb = module.db(resp.info.authentication_db); 35 | callback(userDb); 36 | } 37 | }); 38 | } 39 | 40 | /** @private */ 41 | function prepareUserDoc(user_doc, new_password) { 42 | if (typeof hex_sha1 == "undefined") { 43 | Ti.API.error("creating a user doc requires sha1.js to be loaded in the page"); 44 | return; 45 | } 46 | var user_prefix = "org.couchdb.user:"; 47 | user_doc._id = user_doc._id || user_prefix + user_doc.name; 48 | if (new_password) { 49 | // handle the password crypto 50 | user_doc.salt = _newUUID(); 51 | user_doc.password_sha = hex_sha1(new_password + user_doc.salt); 52 | } 53 | user_doc.type = "user"; 54 | if (!user_doc.roles) { 55 | user_doc.roles = []; 56 | } 57 | return user_doc; 58 | } 59 | 60 | /** @private */ 61 | function encodeDocId(docID) { 62 | var parts = docID.split("/"); 63 | if (parts[0] == "_design") { 64 | parts.shift(); 65 | return "_design/" + encodeURIComponent(parts.join('/')); 66 | } 67 | return encodeURIComponent(docID); 68 | } 69 | 70 | /** @private */ 71 | var viewOptions = [ 72 | "key", "startkey", "startkey_docid", "endkey", "endkey_docid", "limit", 73 | "stale", "descending", "skip", "group", "group_level", "reduce", 74 | "include_docs", "inclusive_end" 75 | ]; 76 | 77 | /** @private */ 78 | function encodeViewOptions(obj) { 79 | // http://wiki.apache.org/couchdb/HTTP_view_API 80 | // note that "keys" is handled separately 81 | var buf = []; 82 | for (var key in obj) { 83 | if (inArray(key, viewOptions) > -1) { 84 | buf.push(encodeURIComponent(key) + "=" + encodeURIComponent(JSON.stringify(obj[key]))); 85 | } 86 | } 87 | return buf.join('&'); 88 | } 89 | 90 | 91 | /** 92 | * base URL of the CouchDB server, i.e. 'http://localhost:5984' 93 | */ 94 | module.urlPrefix = ''; 95 | 96 | // public functions 97 | 98 | /** 99 | * Fetch a list of all databases. 100 | * @param options request options 101 | */ 102 | module.allDbs = function(options) { 103 | ajax({ 104 | url: this.urlPrefix + "/_all_dbs" 105 | }, options); 106 | }; 107 | 108 | /** 109 | * Get information about the server or a database (add "dbname" field to the options object). 110 | * @param options request options 111 | */ 112 | module.info = function(options) { 113 | ajax({ 114 | url: this.urlPrefix + "/" + (options.dbname || "") 115 | }, options); 116 | }; 117 | 118 | module.config = function(options, section, key, value) { 119 | var req = { url: this.urlPrefix + "/_config/" }; 120 | if (section) { 121 | req.url += encodeURIComponent(section) + "/"; 122 | if (key) { 123 | req.url += encodeURIComponent(key); 124 | } 125 | } 126 | if (value === null) { 127 | req.method = "DELETE"; 128 | } 129 | else if (value !== undefined) { 130 | req.method = "PUT"; 131 | req.data = JSON.stringify(value); 132 | } 133 | ajax(req, options); 134 | }; 135 | 136 | module.login = function(options, username, password) { 137 | this.session(extend({ username:username, password:password}, options)); 138 | }; 139 | 140 | module.logout = function(options) { 141 | ajax({ 142 | method: "DELETE", 143 | url: this.urlPrefix + "/_session", 144 | username: "_", 145 | password: "_" 146 | }, options); 147 | }; 148 | 149 | module.session = function(options) { 150 | ajax({ 151 | url: this.urlPrefix + "/_session", 152 | headers: { "Accept": "application/json" } 153 | }, options); 154 | }; 155 | 156 | module.signup = function(user_doc, password, options) { 157 | options = options || {}; 158 | user_doc = prepareUserDoc(user_doc, password); 159 | userDb(function(db) { 160 | db.saveDoc(user_doc, options); 161 | }); 162 | }; 163 | 164 | module.db = function(name, db_opts) { 165 | db_opts = db_opts || {}; 166 | 167 | return { 168 | name: name, 169 | uri: this.urlPrefix + "/" + encodeURIComponent(name) + "/", 170 | 171 | /** 172 | * Request compaction of the specified database. 173 | * @param 174 | */ 175 | compact: function(options) { 176 | ajax({ 177 | method: "POST", 178 | url: this.uri + "_compact", 179 | successStatus: 202 180 | }, options); 181 | }, 182 | 183 | /** 184 | * Cleans up the cached view output on disk for a given view. 185 | */ 186 | viewCleanup: function(options) { 187 | ajax({ 188 | method: "POST", 189 | url: this.uri + "_view_cleanup", 190 | successStatus: 202 191 | }, options); 192 | }, 193 | 194 | /** 195 | * Compacts the view indexes associated with the specified design 196 | * document. You can use this in place of the full database compaction 197 | * if you know a specific set of view indexes have been affected by a 198 | * recent database change. 199 | */ 200 | compactView: function(groupname, options) { 201 | ajax({ 202 | method: "POST", 203 | url: this.uri + "_compact/" + groupname, 204 | successStatus: 202 205 | }, options); 206 | }, 207 | 208 | /** 209 | * Create a new database 210 | */ 211 | create: function(options) { 212 | ajax({ 213 | method: "PUT", 214 | url: this.uri, 215 | successStatus: 201 216 | }, options); 217 | }, 218 | 219 | /** 220 | * Deletes the specified database, and all the documents and 221 | * attachments contained within it. 222 | */ 223 | drop: function(options) { 224 | ajax({ 225 | method: "DELETE", 226 | url: this.uri 227 | }, options); 228 | }, 229 | 230 | /** 231 | * Gets information about the specified database. 232 | */ 233 | info: function(options) { 234 | ajax({ 235 | url: this.uri 236 | }, options); 237 | }, 238 | 239 | /** 240 | * @namespace 241 | * $.couch.db.changes provides an API for subscribing to the changes 242 | * feed 243 | *
var $changes = $.couch.db("mydatabase").changes();
 244 |        *$changes.onChange = function (data) {
 245 |        *    ... process data ...
 246 |        * }
 247 |        * $changes.stop();
 248 |        * 
249 | */ 250 | /* TODO TODO TODO 251 | changes: function(since, options) { 252 | 253 | options = options || {}; 254 | // set up the promise object within a closure for this handler 255 | var timeout = 100, db = this, active = true, 256 | listeners = [], 257 | promise = { 258 | onChange : function(fun) { 259 | listeners.push(fun); 260 | }, 261 | stop : function() { 262 | active = false; 263 | } 264 | }; 265 | // call each listener when there is a change 266 | function triggerListeners(resp) { 267 | $.each(listeners, function() { 268 | this(resp); 269 | }); 270 | }; 271 | // when there is a change, call any listeners, then check for 272 | // another change 273 | options.success = function(resp) { 274 | timeout = 100; 275 | if (active) { 276 | since = resp.last_seq; 277 | triggerListeners(resp); 278 | getChangesSince(); 279 | }; 280 | }; 281 | options.error = function() { 282 | if (active) { 283 | setTimeout(getChangesSince, timeout); 284 | timeout = timeout * 2; 285 | } 286 | }; 287 | // actually make the changes request 288 | function getChangesSince() { 289 | var opts = $.extend({heartbeat : 10 * 1000}, options, { 290 | feed : "longpoll", 291 | since : since 292 | }); 293 | ajax( 294 | {url: db.uri + "_changes"+encodeOptions(opts)}, 295 | options, 296 | "Error connecting to "+db.uri+"/_changes." 297 | ); 298 | } 299 | // start the first request 300 | if (since) { 301 | getChangesSince(); 302 | } else { 303 | db.info({ 304 | success : function(info) { 305 | since = info.update_seq; 306 | getChangesSince(); 307 | } 308 | }); 309 | } 310 | return promise; 311 | }, 312 | */ 313 | 314 | /** 315 | * Fetch all the docs in this db. You can specify an array of keys to 316 | * fetch by passing the keys field in the 317 | * options parameter. 318 | */ 319 | allDocs: function(options) { 320 | var method = "GET"; 321 | var data = null; 322 | if (options["keys"]) { 323 | method = "POST"; 324 | var keys = options["keys"]; 325 | delete options["keys"]; 326 | data = { "keys": keys }; 327 | } 328 | ajax({ 329 | method: method, 330 | data: data, 331 | url: this.uri + "_all_docs" 332 | }, options); 333 | }, 334 | 335 | /** 336 | * Fetch all the design docs in this db 337 | */ 338 | allDesignDocs: function(options) { 339 | this.allDocs(extend({ startkey:"_design", endkey:"_design0" }, options)); 340 | }, 341 | 342 | /** 343 | * Returns the specified doc from the db. 344 | */ 345 | openDoc: function(docId, options) { 346 | ajax({ 347 | url: this.uri + encodeDocId(docId) 348 | }, options); 349 | }, 350 | 351 | /** 352 | * Create a new document in the specified database, using the supplied 353 | * JSON document structure. If the JSON structure includes the _id 354 | * field, then the document will be created with the specified document 355 | * ID. If the _id field is not specified, a new unique ID will be 356 | * generated. 357 | */ 358 | saveDoc: function(doc, options) { 359 | options = options || {}; 360 | var db = this; 361 | if (doc._id === undefined) { 362 | var method = "POST"; 363 | var uri = this.uri; 364 | } 365 | else { 366 | var method = "PUT"; 367 | var uri = this.uri + encodeDocId(doc._id); 368 | } 369 | ajax({ 370 | method: method, 371 | url: uri, 372 | data: doc, 373 | successStatus: [200, 201, 202] 374 | }, options); 375 | }, 376 | 377 | /** 378 | * Save a list of documents 379 | */ 380 | bulkSave: function(docs, options) { 381 | ajax({ 382 | method: "POST", 383 | url: this.uri + "_bulk_docs", 384 | data: docs, 385 | }, options); 386 | }, 387 | 388 | /** 389 | * Deletes the specified document from the database. You must supply 390 | * the current (latest) revision and id of the document 391 | * to delete eg removeDoc({_id:"mydoc", _rev: "1-2345"}) 392 | */ 393 | removeDoc: function(doc, options) { 394 | ajax({ 395 | method: "DELETE", 396 | data: { rev: doc._rev }, 397 | url: this.uri + encodeDocId(doc._id) 398 | }, options); 399 | }, 400 | 401 | /** 402 | * Remove a set of documents 403 | */ 404 | bulkRemove: function(docs, options){ 405 | docs.docs = each(docs.docs, function(i, doc) { 406 | doc._deleted = true; 407 | }); 408 | ajax({ 409 | method: "POST", 410 | successStatus: 201, 411 | url: this.uri + "_bulk_docs", 412 | data: docs 413 | }, options); 414 | }, 415 | 416 | /** 417 | * Copy an existing document to a new or existing document. 418 | */ 419 | copyDoc: function(source, destination, options) { 420 | if (!destination) { 421 | // TODO get a UUID 422 | } 423 | ajax({ 424 | method: "COPY", 425 | url: this.uri + encodeDocId(source), 426 | successStatus: 201, 427 | headers: { "Destination": destination } 428 | }, options); 429 | }, 430 | 431 | /** 432 | * Creates and executes a temporary view. 433 | */ 434 | query: function(mapFun, reduceFun, language, options) { 435 | language = language || "javascript"; 436 | if (typeof(mapFun) !== "string") { 437 | mapFun = mapFun.toSource ? mapFun.toSource() : "(" + mapFun.toString() + ")"; 438 | } 439 | var body = {language: language, map: mapFun}; 440 | if (reduceFun != null) { 441 | if (typeof(reduceFun) !== "string") 442 | reduceFun = reduceFun.toSource ? reduceFun.toSource() 443 | : "(" + reduceFun.toString() + ")"; 444 | body.reduce = reduceFun; 445 | } 446 | ajax({ 447 | method: "POST", 448 | url: this.uri + "_temp_view", 449 | data: body, 450 | headers: { "Content-Type": "application/json" } 451 | }, 452 | options); 453 | }, 454 | 455 | 456 | /** 457 | * Fetch a _list view output. You can specify a list of 458 | * keys in the options object to receive only those keys. 459 | */ 460 | list: function(list, view, options) { 461 | var list = list.split('/'); 462 | var method = 'GET'; 463 | var data = null; 464 | if (options['keys']) { 465 | method = 'POST'; 466 | var keys = options['keys']; 467 | delete options['keys']; 468 | data = {'keys': keys }; 469 | } 470 | ajax({ 471 | method: method, 472 | data: data, 473 | url: this.uri + '_design/' + list[0] + '/_list/' + list[1] + '/' + view 474 | }, options); 475 | }, 476 | 477 | /** 478 | * Executes the specified view-name from the specified design-doc 479 | * design document. You can specify a list of keys 480 | * in the options object to recieve only those keys. 481 | */ 482 | view: function(name, options) { 483 | var name = name.split('/'); 484 | var method = "GET"; 485 | var data = null; 486 | if (options["keys"]) { 487 | method = "POST"; 488 | var keys = options["keys"]; 489 | delete options["keys"]; 490 | data = { "keys": keys }; 491 | } 492 | ajax({ 493 | method: method, 494 | data: data, 495 | url: this.uri + "_design/" + name[0] + "/_view/" + name[1] + '?' + encodeViewOptions(options) 496 | }, options); 497 | }, 498 | 499 | /** 500 | * Fetch an arbitrary CouchDB database property. As of 1.1, only the 501 | * _revs_limit property is available. 502 | */ 503 | getDbProperty: function(propName, options) { 504 | ajax({ 505 | url: this.uri + propName 506 | }, options); 507 | }, 508 | 509 | /** 510 | * Set an arbitrary CouchDB database property. As of 1.1, only the 511 | * _revs_limit property is available. 512 | */ 513 | setDbProperty: function(propName, propValue, options) { 514 | ajax({ 515 | method: "PUT", 516 | url: this.uri + propName, 517 | data : propValue 518 | }, options); 519 | } 520 | } 521 | }; 522 | 523 | 524 | /** 525 | * AJAX functions for CouchDB client 526 | */ 527 | 528 | function httpData(xhr, type) { 529 | var contentType = xhr.getResponseHeader("content-type") || ""; 530 | var isXml = type === "xml" || (!type && contentType.indexOf("xml") >= 0); 531 | var isJson = type === "json" || (!type && contentType.indexOf("json") >= 0); 532 | 533 | var data = isXml ? xhr.responseXML : xhr.responseText; 534 | if (typeof data === "string") { 535 | if (isJson) { 536 | data = JSON.parse(data); 537 | } 538 | // other types here? 539 | } 540 | return data; 541 | } 542 | 543 | function toQueryString(obj) { 544 | var buf = []; 545 | for (var name in obj) { 546 | var value = obj[name]; 547 | if (inArray(name, ["key", "startkey", "endkey"]) >= 0) { 548 | value = JSON.stringify(value); 549 | } 550 | buf.push(encodeURIComponent(name) + "=" + encodeURIComponent(value)); 551 | } 552 | return buf.length ? buf.join("&") : ""; 553 | } 554 | 555 | /** 556 | * 557 | * opts.method HTTP method to use 558 | * opts.successStatus default 200; set to 201 for document create 559 | * opts.data for HTTP GET, the query parameters; otherwise request body 560 | * opts.headers extra headers to send 561 | * opts.success function(data) called on success; data is the object returned in the response 562 | * opts.failure function(xhr) called on failure with XMLHttpRequest object 563 | */ 564 | function ajax(req, opts, xhrOpts) { 565 | opts = opts || {}; 566 | xhrOpts = xhrOpts || {}; 567 | 568 | //var request = extend(req, opts); 569 | var request = extend({ successStatus: [200], method: "GET" }, req); 570 | 571 | // encode request.data onto URL 572 | if (request.data && request.method !== "POST" && request.method !== "PUT") { 573 | request.url += (request.url.indexOf("?") > -1 ? "&" : "?") + toQueryString(request.data); 574 | delete request.data; 575 | } 576 | 577 | successStatus = isArray(request.successStatus) ? request.successStatus : Array(request.successStatus); 578 | 579 | var xhr = Ti.Network.createHTTPClient(extend({ 580 | onload: function(e) { 581 | var req = e.source; 582 | try { 583 | var resp = httpData(req, "json"); 584 | } 585 | catch (err) { 586 | Ti.API.error(err.name + ": " + err.message); 587 | if (opts.failure) { 588 | opts.failure(req); 589 | } 590 | else { 591 | Ti.API.error(err); 592 | } 593 | } 594 | 595 | if (inArray(req.status, successStatus) >= 0) { 596 | if (opts.success) { 597 | opts.success(resp); 598 | } 599 | } 600 | else if (opts.failure) { 601 | opts.failure(req); 602 | } 603 | else { 604 | Ti.API.error("bad response: " + req.status + " " + req.responseText); 605 | } 606 | }, 607 | onerror: function(e) { 608 | var req = e.source; 609 | if (opts.failure) { 610 | opts.failure(req); 611 | } 612 | else { 613 | Ti.API.error("AJAX error: " + JSON.stringify(e) + " " + req.status + " " + req.responseText); 614 | } 615 | } 616 | }, xhrOpts)); 617 | 618 | xhr.open(request.method, request.url); 619 | Ti.API.debug(request.method + " "+request.url); 620 | 621 | if (xhr.setMaxRedirects) { 622 | xhr.setMaxRedirects(0); 623 | } 624 | 625 | // basic auth 626 | if (opts.username) { 627 | xhr.setRequestHeader('Authorization', 'Basic ' + Ti.Utils.base64encode(opts.username+':'+opts.password)); 628 | } 629 | 630 | // generic Accept header, may be overwritten below 631 | xhr.setRequestHeader("Accept", "*/*"); 632 | 633 | if (request.method === "POST" || request.method === "PUT") { 634 | xhr.setRequestHeader("Content-Type", "application/json"); 635 | } 636 | 637 | // extra headers 638 | if (request.headers) { 639 | for (var header in request.headers) { 640 | xhr.setRequestHeader(header, request.headers[header]); 641 | } 642 | } 643 | 644 | xhr.send(isPlainObject(request.data) ? JSON.stringify(request.data) : request.data); 645 | } 646 | 647 | /* 648 | * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined 649 | * in FIPS PUB 180-1 650 | * Version 2.1a Copyright Paul Johnston 2000 - 2002. 651 | * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet 652 | * Distributed under the BSD License 653 | * See http://pajhome.org.uk/crypt/md5 for details. 654 | */ 655 | 656 | /* 657 | * Configurable variables. You may need to tweak these to be compatible with 658 | * the server-side, but the defaults work in most cases. 659 | */ 660 | var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ 661 | var b64pad = "="; /* base-64 pad character. "=" for strict RFC compliance */ 662 | var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ 663 | 664 | /* 665 | * These are the functions you'll usually want to call 666 | * They take string arguments and return either hex or base-64 encoded strings 667 | */ 668 | function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));} 669 | function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));} 670 | function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));} 671 | function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));} 672 | function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));} 673 | function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));} 674 | 675 | /* 676 | * Perform a simple self-test to see if the VM is working 677 | */ 678 | function sha1_vm_test() 679 | { 680 | return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d"; 681 | } 682 | 683 | /* 684 | * Calculate the SHA-1 of an array of big-endian words, and a bit length 685 | */ 686 | function core_sha1(x, len) 687 | { 688 | /* append padding */ 689 | x[len >> 5] |= 0x80 << (24 - len % 32); 690 | x[((len + 64 >> 9) << 4) + 15] = len; 691 | 692 | var w = Array(80); 693 | var a = 1732584193; 694 | var b = -271733879; 695 | var c = -1732584194; 696 | var d = 271733878; 697 | var e = -1009589776; 698 | 699 | for(var i = 0; i < x.length; i += 16) 700 | { 701 | var olda = a; 702 | var oldb = b; 703 | var oldc = c; 704 | var oldd = d; 705 | var olde = e; 706 | 707 | for(var j = 0; j < 80; j++) 708 | { 709 | if(j < 16) w[j] = x[i + j]; 710 | else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1); 711 | var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), 712 | safe_add(safe_add(e, w[j]), sha1_kt(j))); 713 | e = d; 714 | d = c; 715 | c = rol(b, 30); 716 | b = a; 717 | a = t; 718 | } 719 | 720 | a = safe_add(a, olda); 721 | b = safe_add(b, oldb); 722 | c = safe_add(c, oldc); 723 | d = safe_add(d, oldd); 724 | e = safe_add(e, olde); 725 | } 726 | return Array(a, b, c, d, e); 727 | 728 | } 729 | 730 | /* 731 | * Perform the appropriate triplet combination function for the current 732 | * iteration 733 | */ 734 | function sha1_ft(t, b, c, d) 735 | { 736 | if(t < 20) return (b & c) | ((~b) & d); 737 | if(t < 40) return b ^ c ^ d; 738 | if(t < 60) return (b & c) | (b & d) | (c & d); 739 | return b ^ c ^ d; 740 | } 741 | 742 | /* 743 | * Determine the appropriate additive constant for the current iteration 744 | */ 745 | function sha1_kt(t) 746 | { 747 | return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : 748 | (t < 60) ? -1894007588 : -899497514; 749 | } 750 | 751 | /* 752 | * Calculate the HMAC-SHA1 of a key and some data 753 | */ 754 | function core_hmac_sha1(key, data) 755 | { 756 | var bkey = str2binb(key); 757 | if(bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz); 758 | 759 | var ipad = Array(16), opad = Array(16); 760 | for(var i = 0; i < 16; i++) 761 | { 762 | ipad[i] = bkey[i] ^ 0x36363636; 763 | opad[i] = bkey[i] ^ 0x5C5C5C5C; 764 | } 765 | 766 | var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz); 767 | return core_sha1(opad.concat(hash), 512 + 160); 768 | } 769 | 770 | /* 771 | * Add integers, wrapping at 2^32. This uses 16-bit operations internally 772 | * to work around bugs in some JS interpreters. 773 | */ 774 | function safe_add(x, y) 775 | { 776 | var lsw = (x & 0xFFFF) + (y & 0xFFFF); 777 | var msw = (x >> 16) + (y >> 16) + (lsw >> 16); 778 | return (msw << 16) | (lsw & 0xFFFF); 779 | } 780 | 781 | /* 782 | * Bitwise rotate a 32-bit number to the left. 783 | */ 784 | function rol(num, cnt) 785 | { 786 | return (num << cnt) | (num >>> (32 - cnt)); 787 | } 788 | 789 | /* 790 | * Convert an 8-bit or 16-bit string to an array of big-endian words 791 | * In 8-bit function, characters >255 have their hi-byte silently ignored. 792 | */ 793 | function str2binb(str) 794 | { 795 | var bin = Array(); 796 | var mask = (1 << chrsz) - 1; 797 | for(var i = 0; i < str.length * chrsz; i += chrsz) 798 | bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32); 799 | return bin; 800 | } 801 | 802 | /* 803 | * Convert an array of big-endian words to a string 804 | */ 805 | function binb2str(bin) 806 | { 807 | var str = ""; 808 | var mask = (1 << chrsz) - 1; 809 | for(var i = 0; i < bin.length * 32; i += chrsz) 810 | str += String.fromCharCode((bin[i>>5] >>> (32 - chrsz - i%32)) & mask); 811 | return str; 812 | } 813 | 814 | /* 815 | * Convert an array of big-endian words to a hex string. 816 | */ 817 | function binb2hex(binarray) 818 | { 819 | var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; 820 | var str = ""; 821 | for(var i = 0; i < binarray.length * 4; i++) 822 | { 823 | str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) + 824 | hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF); 825 | } 826 | return str; 827 | } 828 | 829 | /* 830 | * Convert an array of big-endian words to a base-64 string 831 | */ 832 | function binb2b64(binarray) 833 | { 834 | var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 835 | var str = ""; 836 | for(var i = 0; i < binarray.length * 4; i += 3) 837 | { 838 | var triplet = (((binarray[i >> 2] >> 8 * (3 - i %4)) & 0xFF) << 16) 839 | | (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 ) 840 | | ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF); 841 | for(var j = 0; j < 4; j++) 842 | { 843 | if(i * 8 + j * 6 > binarray.length * 32) str += b64pad; 844 | else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); 845 | } 846 | } 847 | return str; 848 | } 849 | 850 | /* Copyright (C) 1999 Masanao Izumo 851 | * Version: 1.0 852 | * LastModified: Dec 25 1999 853 | * This library is free. You can redistribute it and/or modify it. 854 | */ 855 | /* Modified by Chris Anderson to not use CommonJS */ 856 | /* Modified by Dan Webb not to require Narwhal's binary library */ 857 | 858 | var Base64 = {}; 859 | (function(exports) { 860 | 861 | var encodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 862 | var decodeChars = [ 863 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 864 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 865 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 866 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, 867 | -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 868 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, 869 | -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 870 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 871 | ]; 872 | 873 | exports.encode = function (str) { 874 | var out, i, length; 875 | var c1, c2, c3; 876 | 877 | length = len(str); 878 | i = 0; 879 | out = []; 880 | while(i < length) { 881 | c1 = str.charCodeAt(i++) & 0xff; 882 | if(i == length) 883 | { 884 | out.push(encodeChars.charCodeAt(c1 >> 2)); 885 | out.push(encodeChars.charCodeAt((c1 & 0x3) << 4)); 886 | out.push("=".charCodeAt(0)); 887 | out.push("=".charCodeAt(0)); 888 | break; 889 | } 890 | c2 = str.charCodeAt(i++); 891 | if(i == length) 892 | { 893 | out.push(encodeChars.charCodeAt(c1 >> 2)); 894 | out.push(encodeChars.charCodeAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4))); 895 | out.push(encodeChars.charCodeAt((c2 & 0xF) << 2)); 896 | out.push("=".charCodeAt(0)); 897 | break; 898 | } 899 | c3 = str.charCodeAt(i++); 900 | out.push(encodeChars.charCodeAt(c1 >> 2)); 901 | out.push(encodeChars.charCodeAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4))); 902 | out.push(encodeChars.charCodeAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6))); 903 | out.push(encodeChars.charCodeAt(c3 & 0x3F)); 904 | } 905 | 906 | var str = ""; 907 | out.forEach(function(chr) { str += String.fromCharCode(chr) }); 908 | return str; 909 | }; 910 | 911 | exports.decode = function (str) { 912 | var c1, c2, c3, c4; 913 | var i, length, out; 914 | 915 | length = len(str); 916 | i = 0; 917 | out = []; 918 | while(i < length) { 919 | /* c1 */ 920 | do { 921 | c1 = decodeChars[str.charCodeAt(i++) & 0xff]; 922 | } while(i < length && c1 == -1); 923 | if(c1 == -1) 924 | break; 925 | 926 | /* c2 */ 927 | do { 928 | c2 = decodeChars[str.charCodeAt(i++) & 0xff]; 929 | } while(i < length && c2 == -1); 930 | if(c2 == -1) 931 | break; 932 | 933 | out.push(String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4))); 934 | 935 | /* c3 */ 936 | do { 937 | c3 = str.charCodeAt(i++) & 0xff; 938 | if(c3 == 61) 939 | return out.join(''); 940 | c3 = decodeChars[c3]; 941 | } while(i < length && c3 == -1); 942 | if(c3 == -1) 943 | break; 944 | 945 | out.push(String.fromCharCode(((c2 & 0xF) << 4) | ((c3 & 0x3C) >> 2))); 946 | 947 | /* c4 */ 948 | do { 949 | c4 = str.charCodeAt(i++) & 0xff; 950 | if(c4 == 61) 951 | return out.join(''); 952 | c4 = decodeChars[c4]; 953 | } while(i < length && c4 == -1); 954 | 955 | if(c4 == -1) 956 | break; 957 | 958 | out.push(String.fromCharCode(((c3 & 0x03) << 6) | c4)); 959 | } 960 | 961 | return out.join(''); 962 | }; 963 | 964 | var len = function (object) { 965 | if (object.length !== undefined) { 966 | return object.length; 967 | } else if (object.getLength !== undefined) { 968 | return object.getLength(); 969 | } else { 970 | return undefined; 971 | } 972 | }; 973 | })(Base64); 974 | 975 | 976 | var class2type = []; 977 | (function(o){ 978 | var types = ["Boolean","Number","String","Function","Array","Date","RegExp","Object"]; 979 | for (var i=0, length=types.length; i < length; i++) { 980 | var name = types[i]; 981 | var key = "[object " + name + "]"; 982 | o[key] = name.toLowerCase(); 983 | } 984 | }(class2type)); 985 | 986 | var hasOwn = Object.prototype.hasOwnProperty, 987 | toString = Object.prototype.toString; 988 | 989 | function type(obj) { 990 | return obj == null ? String(obj) : class2type[toString.call(obj)] || "object"; 991 | } 992 | 993 | function isPlainObject(obj) { 994 | if ( !obj || type(obj) !== "object") { 995 | return false; 996 | } 997 | 998 | // Not own constructor property must be Object 999 | if ( obj.constructor && 1000 | !hasOwn.call(obj, "constructor") && 1001 | !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { 1002 | return false; 1003 | } 1004 | 1005 | // Own properties are enumerated firstly, so to speed up, 1006 | // if last one is own, then all properties are own. 1007 | 1008 | var key; 1009 | for (key in obj) {} 1010 | 1011 | return key === undefined || hasOwn.call( obj, key ); 1012 | } 1013 | 1014 | function isEmptyObject(obj) { 1015 | for (var name in obj) { 1016 | return false; 1017 | } 1018 | return true; 1019 | } 1020 | 1021 | function isArray(obj) { 1022 | return type(obj) === "array"; 1023 | } 1024 | 1025 | function isFunction(obj) { 1026 | return type(obj) === "function"; 1027 | } 1028 | 1029 | function each(object, callback, args) { 1030 | var name, i = 0, 1031 | length = object.length, 1032 | isObj = length === undefined || isFunction( object ); 1033 | 1034 | if ( args ) { 1035 | if ( isObj ) { 1036 | for ( name in object ) { 1037 | if ( callback.apply( object[ name ], args ) === false ) { 1038 | break; 1039 | } 1040 | } 1041 | } else { 1042 | for ( ; i < length; ) { 1043 | if ( callback.apply( object[ i++ ], args ) === false ) { 1044 | break; 1045 | } 1046 | } 1047 | } 1048 | 1049 | // A special, fast, case for the most common use of each 1050 | } else { 1051 | if ( isObj ) { 1052 | for ( name in object ) { 1053 | if ( callback.call( object[ name ], name, object[ name ] ) === false ) { 1054 | break; 1055 | } 1056 | } 1057 | } else { 1058 | for ( ; i < length; ) { 1059 | if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { 1060 | break; 1061 | } 1062 | } 1063 | } 1064 | } 1065 | 1066 | return object; 1067 | } 1068 | 1069 | function extend() { 1070 | var options, name, src, copy, copyIsArray, clone, 1071 | target = arguments[0] || {}, 1072 | i = 1, 1073 | length = arguments.length, 1074 | deep = false; 1075 | 1076 | // Handle a deep copy situation 1077 | if ( typeof target === "boolean" ) { 1078 | deep = target; 1079 | target = arguments[1] || {}; 1080 | // skip the boolean and the target 1081 | i = 2; 1082 | } 1083 | 1084 | // Handle case when target is a string or something (possible in deep copy) 1085 | if ( typeof target !== "object" && !isFunction(target) ) { 1086 | target = {}; 1087 | } 1088 | 1089 | // extend jQuery itself if only one argument is passed 1090 | if ( length === i ) { 1091 | target = this; 1092 | --i; 1093 | } 1094 | 1095 | for ( ; i < length; i++ ) { 1096 | // Only deal with non-null/undefined values 1097 | if ( (options = arguments[ i ]) != null ) { 1098 | // Extend the base object 1099 | for ( name in options ) { 1100 | if (options.hasOwnProperty(name)) { 1101 | src = target[ name ]; 1102 | copy = options[ name ]; 1103 | 1104 | // Prevent never-ending loop 1105 | if ( target === copy ) { 1106 | continue; 1107 | } 1108 | 1109 | // Recurse if we're merging plain objects or arrays 1110 | if ( deep && copy && ( isPlainObject(copy) || (copyIsArray = isArray(copy)) ) ) { 1111 | if ( copyIsArray ) { 1112 | copyIsArray = false; 1113 | clone = src && isArray(src) ? src : []; 1114 | 1115 | } else { 1116 | clone = src && isPlainObject(src) ? src : {}; 1117 | } 1118 | 1119 | // Never move original objects, clone them 1120 | target[ name ] = extend( deep, clone, copy ); 1121 | 1122 | // Don't bring in undefined values 1123 | } else if ( copy !== undefined ) { 1124 | target[ name ] = copy; 1125 | } 1126 | } 1127 | } 1128 | } 1129 | } 1130 | 1131 | // Return the modified object 1132 | return target; 1133 | } 1134 | 1135 | function inArray(elem, array) { 1136 | if (Array.prototype.indexOf) { 1137 | return array.indexOf(elem); 1138 | } 1139 | 1140 | for (var i=0, length=array.length; i < length; i++) { 1141 | if (array[i] === elem) { 1142 | return i; 1143 | } 1144 | } 1145 | 1146 | return -1; 1147 | } 1148 | 1149 | }(couchdb_client)); 1150 | 1151 | --------------------------------------------------------------------------------