--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------