Commits

Sean Wilkinson committed 03db81e Merge

Merged latest from origin to continue the migration

Comments (0)

Files changed (14)

 
 #-  .travis.yml ~~
 #                                                       ~~ (c) SRW, 15 Jul 2013
-#                                                   ~~ last updated 09 Dec 2013
+#                                                   ~~ last updated 21 Mar 2014
 
 before_install:
     -   sudo apt-get update -qq
     -   sudo apt-get install -qq curl git imagemagick make
 
+language: node_js
+
 node_js:
     -   "0.10"
 
 #   Thanks for stopping by :-)
 #
 #                                                       ~~ (c) SRW, 06 Feb 2012
-#                                                   ~~ last updated 17 Dec 2013
+#                                                   ~~ last updated 16 Mar 2014
 
 PROJ_ROOT   :=  $(realpath $(dir $(firstword $(MAKEFILE_LIST))))
 
 TEST_DIR    :=  $(PROJ_ROOT)/tests
 
 LOCAL_ADDR  :=  http://localhost:8177
-MOTHERSHIP  :=  https://qmachine.herokuapp.com
 QM_API_LOC  :=  '{"sqlite":"qm.db"}'
-QM_API_URL  :=  $(MOTHERSHIP)
-QM_WWW_URL  :=  $(MOTHERSHIP)
+QM_API_URL  :=  https://api.qmachine.org
+QM_WWW_URL  :=  https://www.qmachine.org
 
 ifeq ("$(strip $(db))", "couch")
     QM_API_LOC  :=  '{"couch":"http://127.0.0.1:5984/db"}'
     $(addprefix $(BUILD_DIR)/browser-client/,                               \
         apple-touch-icon-57x57.png                                          \
         apple-touch-icon-72x72.png                                          \
+        apple-touch-icon-76x76.png                                          \
         apple-touch-icon-114x114.png                                        \
+        apple-touch-icon-120x120.png                                        \
         apple-touch-icon-144x144.png                                        \
+        apple-touch-icon-152x152.png                                        \
         cache.manifest                                                      \
         coffeescript.js                                                     \
         favicon.ico                                                         \
 
 local-sandbox:
 	@   $(MAKE)                                                         \
-                MOTHERSHIP="$(strip $(LOCAL_ADDR))"                         \
                 QM_API_STRING=$(strip $(QM_API_LOC))                        \
+                QM_API_URL='$(strip $(LOCAL_ADDR))'                         \
+                QM_WWW_URL='$(strip $(LOCAL_ADDR))'                         \
                     web-service                                         ;   \
             $(CD) $(BUILD_DIR)                                          ;   \
             if [ ! -d local-sandbox/ ]; then                                \
                     $(NPM) start
 
 rack-app: | $(BUILD_DIR)/rack-app/
-	@   $(MAKE) MOTHERSHIP="$(strip $(LOCAL_ADDR))" browser-client  ;   \
+	@   $(MAKE) \
+                QM_API_URL='$(strip $(LOCAL_ADDR))'                         \
+                QM_WWW_URL='$(strip $(LOCAL_ADDR))'                         \
+                    browser-client                                      ;   \
             $(CD) $(BUILD_DIR)                                          ;   \
             if [ ! -d rack-app/public/ ]; then                              \
                 $(CP) browser-client rack-app/public                    ;   \
     $(addprefix $(ICONS_DIR)/,                                              \
         apple-touch-icon-57x57.png                                          \
         apple-touch-icon-72x72.png                                          \
+        apple-touch-icon-76x76.png                                          \
         apple-touch-icon-114x114.png                                        \
+        apple-touch-icon-120x120.png                                        \
         apple-touch-icon-144x144.png                                        \
+        apple-touch-icon-152x152.png                                        \
         apple-touch-startup-image-320x460.png                               \
         apple-touch-startup-image-320x460.png                               \
         apple-touch-startup-image-640x920.png                               \
-# QMachine [![Build Status](https://travis-ci.org/wilkinson/qmachine.png)](https://travis-ci.org/wilkinson/qmachine) [![Build Status](https://drone.io/github.com/wilkinson/qmachine/status.png)](https://drone.io/github.com/wilkinson/qmachine/latest) [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/wilkinson/qmachine/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
+# QMachine [![Build Status](https://travis-ci.org/wilkinson/qmachine.png)](https://travis-ci.org/wilkinson/qmachine) [![Build Status](https://drone.io/github.com/wilkinson/qmachine/status.png)](https://drone.io/github.com/wilkinson/qmachine/latest)
 
 [QMachine](https://www.qmachine.org) (QM) is a web service that can incorporate
 ordinary web browsers into a World Wide Computer without installing anything.
 For more information, see
 [https://wiki.qmachine.org](https://wiki.qmachine.org) :-)
 
+<!-- vim:set syntax=markdown: -->

share/macros.make

 #   When I can test for regressions instantly, I will reconsider. UGH.
 #
 #                                                       ~~ (c) SRW, 27 Nov 2012
-#                                                   ~~ last updated 01 Dec 2013
+#                                                   ~~ last updated 16 Mar 2014
 
 SHELL   :=  sh
 ECHO    :=  echo -e
     else                                                                    \
         $(call aside, "Optimizing stylesheets: $(1) -> $(2)")           ;   \
     fi                                                                  ;   \
-    echo "/*! $(MOTHERSHIP)/$(notdir $(2)) */\n" > $(2)                 ;   \
+    echo "/*! $(QM_WWW_URL)/$(notdir $(2)) */\n" > $(2)                 ;   \
     $(CAT) $(1) > $(2)-temp.js                                          ;   \
     if [ "$(firstword $(YUICOMP))" != "echo" ]; then                        \
         $(YUICOMP) --type css $(2)-temp.js -o $(2)-temp.js              ;   \
 
 define minify-js
     if [ "$(strip $(MINIFY))" = "$(firstword $(CLOSURE))" ]; then           \
-        echo "// $(MOTHERSHIP)/$(notdir $(2))\n" > $(2)                 ;   \
+        echo "// $(QM_WWW_URL)/$(notdir $(2))\n" > $(2)                 ;   \
         $(CLOSURE) --compilation_level WHITESPACE_ONLY                      \
             $(1:%=--js %) >> $(2)                                       ;   \
     elif [ "$(strip $(MINIFY))" = "$(firstword $(YUICOMP))" ]; then         \
-        echo "// $(MOTHERSHIP)/$(notdir $(2))\n" > $(2)                 ;   \
+        echo "// $(QM_WWW_URL)/$(notdir $(2))\n" > $(2)                 ;   \
         $(YUICOMP) --nomunge --preserve-semi --disable-optimizations        \
             --type js $(1) >> $(2)                                      ;   \
     elif [ "$(strip $(MINIFY))" = "$(firstword $(JSMIN))" ]; then           \
-        $(CAT) $(1) | $(JSMIN) "$(MOTHERSHIP)/$(notdir $(2))" > $(2)    ;   \
+        $(CAT) $(1) | $(JSMIN) "$(QM_WWW_URL)/$(notdir $(2))" > $(2)    ;   \
     else                                                                    \
-        echo "// $(MOTHERSHIP)/$(notdir $(2))\n" > $(2)                 ;   \
+        echo "// $(QM_WWW_URL)/$(notdir $(2))\n" > $(2)                 ;   \
         $(CAT) $(1) >> $(2)                                             ;   \
     fi
 endef
 
 define replace-url-macros
     $(SED) \
-        -e 's|MOTHERSHIP|$(strip $(MOTHERSHIP))|g'  \
-        -e 's|QM_API_URL|$(strip $(QM_API_URL))|g'  \
         -e 's|LOCAL_ADDR|$(strip $(LOCAL_ADDR))|g'  \
+        -e 's|QM_API_URL|$(strip $(QM_API_URL))|g'  \
         -e 's|QM_WWW_URL|$(strip $(QM_WWW_URL))|g'  $(1) > $(2)
 endef
 

src/bower-package/bower.json

     "dependencies": {
         "bootstrap": "3.0.3",
         "coffee-script": "1.6.3",
-        "jquery": "1.10.2",
+        "jquery": "1.11.0",
         "quanah": "0.2.0"
     },
     "main": [
         "./src/browser-client/style.css"
     ],
     "name": "qm",
-    "version": "1.1.5"
+    "version": "1.1.7"
 }

src/browser-client/index.html

 <!--
     index.html ~~
                                                         ~~ (c) SRW, 20 Nov 2012
-                                                    ~~ last updated 09 Dec 2013
+                                                    ~~ last updated 03 Mar 2014
 -->
 <!--[if IE]><![endif]-->
 <html lang="en">
     <link rel="apple-touch-icon" sizes="72x72"
         href="apple-touch-icon-72x72.png">
 
+    <link rel="apple-touch-icon" sizes="76x76"
+        href="apple-touch-icon-76x76.png">
+
     <link rel="apple-touch-icon" sizes="114x114"
         href="apple-touch-icon-114x114.png">
 
+    <link rel="apple-touch-icon" sizes="120x120"
+        href="apple-touch-icon-120x120.png">
+
     <link rel="apple-touch-icon" sizes="144x144"
         href="apple-touch-icon-144x144.png">
 
+    <link rel="apple-touch-icon" sizes="152x152"
+        href="apple-touch-icon-152x152.png">
+
   <!--
     Chrome Web Store
   -->
       <div class="container text-center">
         <p>
           &copy;
-          <a href="http://seanwilkinson.info">Sean Wilkinson</a> 2010-2013<br>
+          <a href="http://seanwilkinson.info">Sean Wilkinson</a> 2010-2014<br>
           Division of Informatics, Department of Pathology<br>
           Department of Biomedical Engineering<br>
           University of Alabama at Birmingham<br>

src/browser-client/manifest.webapp

     "name": "QMachine",
     "permissions": {},
     "type": "web",
-    "version": "1.1.5"
+    "version": "1.1.7"
 }

src/browser-client/mapreduce.js

+//- JavaScript source code
+
+//- mapreduce.js ~~
+//
+//  This file is the beginning of a new browser-based MapReduce engine that
+//  will use QMachine's API without modification. I'm not sure yet whether this
+//  undertaking will become a bolt-on framework that consumes the current web
+//  browser client or whether this will become its own project, but the idea
+//  here is to create a full MapReduce engine in the style of Hadoop et al.
+//
+//                                                      ~~ (c) SRW, 04 Feb 2014
+//                                                  ~~ last updated 09 Feb 2014
+
+(function (global) {
+    'use strict';
+
+ // Pragmas
+
+    /*global */
+
+    /*jshint camelcase: true, maxparams: 3, quotmark: single, strict: true */
+
+    /*jslint indent: 4, maxlen: 80 */
+
+    /*properties
+        avar, constructor, exit, fail, hasOwnProperty, length, map, mapReduce,
+        prototype, Q, QUANAH, reduce, val
+    */
+
+ // Prerequisites
+
+    if (global.hasOwnProperty('QUANAH') === false) {
+        throw new Error('Quanah is missing.');
+    }
+
+ // Declarations
+
+    var AVar, isFunction;
+
+ // Definitions
+
+    AVar = global.QUANAH.avar().constructor;
+
+    isFunction = function (f) {
+     // This function returns `true` if and only if input argument `f` is a
+     // function. The second condition is necessary to avoid a false positive
+     // in a pre-ES5 environment when `f` is a regular expression.
+        return ((typeof f === 'function') && (f instanceof Function));
+    };
+
+ // Prototype definitions
+
+    AVar.prototype.mapReduce = function (mapFunc, reduceFunc, optionsObj) {
+     // This function's purpose should be obvious from its name. It must be
+     // _foolproof_, so we begin by checking types.
+        if ((this instanceof AVar) === false) {
+            throw new TypeError('The `mapReduce` method is not generic.');
+        }
+        var argc = arguments.length;
+        this.Q(function (evt) {
+         // Having established that `this` is an avar, we check the types of
+         // the original input arguments to `mapReduce` as well as the `val`
+         // property of the avar using Quanah to take advantage of error
+         // handling. The function will run locally because it closes over
+         // `argc`, `isFunction`, and the original input arguments.
+            var exps = 'The `mapReduce` method expects ';
+            if ((argc !== 2) && (argc !== 3)) {
+                return evt.fail(exps + 'either two or three input arguments.');
+            }
+            if (isFunction(mapFunc) === false) {
+                return evt.fail(exps + 'its first argument to be a function.');
+            }
+            if (isFunction(reduceFunc) === false) {
+                return evt.fail(exps + 'its second argument to be a function.');
+            }
+            if ((argc === 3) && ((optionsObj instanceof Object) === false)) {
+                return evt.fail(exps + 'its input argument to be an object.');
+            }
+            if ((this.val instanceof Array) === false) {
+                return evt.fail(exps + '`this.val` to be an array.');
+            }
+            return evt.exit();
+        });
+        // ...
+        return this;
+    };
+
+ // That's all, folks!
+
+    return;
+
+}(Function.prototype.call.call(function (that) {
+    'use strict';
+
+ // This strict anonymous closure encapsulates the logic for detecting which
+ // object in the environment should be treated as _the_ global object. It's
+ // not as easy as you may think -- strict mode disables the `call` method's
+ // default behavior of replacing `null` with the global object. Luckily, we
+ // can work around that by passing a reference to the enclosing scope as an
+ // argument at the same time and testing to see if strict mode has done its
+ // deed. This task is not hard in the usual browser context because we know
+ // that the global object is `window`, but CommonJS implementations such as
+ // RingoJS confound the issue by modifying the scope chain, running scripts
+ // in sandboxed contexts, and using identifiers like `global` carelessly ...
+
+    /*global global: false */
+    /*jslint indent: 4, maxlen: 80 */
+    /*properties global */
+
+    if (this === null) {
+
+     // Strict mode has captured us, but we already passed a reference :-)
+
+        return (typeof global === 'object') ? global : that;
+
+    }
+
+ // Strict mode isn't supported in this environment, but we need to make sure
+ // we don't get fooled by Rhino's `global` function.
+
+    return (typeof this.global === 'object') ? this.global : this;
+
+}, null, this)));
+
+//- vim:set syntax=javascript:

src/browser-client/qmachine.js

 
 //- qmachine.js ~~
 //                                                      ~~ (c) SRW, 15 Nov 2012
-//                                                  ~~ last updated 17 Dec 2013
+//                                                  ~~ last updated 02 Feb 2014
 
 (function (global, sandbox) {
     'use strict';
  // RingoJS confound the issue by modifying the scope chain, running scripts
  // in sandboxed contexts, and using identifiers like `global` carelessly ...
 
-    /*jslint indent: 4, maxlen: 80 */
     /*global global: false */
+    /*jslint indent: 4, maxlen: 80 */
     /*properties global */
 
     if (this === null) {

src/chrome-hosted-app/manifest.json

         "unlimitedStorage"
     ],
     "short_name": "QMachine",
-    "version": "1.1.5"
+    "version": "1.1.7"
 }

src/rack-app/config.ru

 #   I do plan to merge this program with the Ruby gem in the future, which is
 #   why the database schema matches the Node.js implementation's (which is not
 #   as straight-forward as it could be). For now, it serves its purpose, and it
-#   does so with just 98 lines of source code ;-)
+#   does so with just 95 lines of source code ;-)
 #
 #   NOTE: Using a "%" character incorrectly in a URL will cause you great
 #   anguish, and there isn't a good way for me to handle this problem "softly"
 #   of a 'box', 'key', or 'status' value.
 #
 #                                                       ~~ (c) SRW, 24 Apr 2013
-#                                                   ~~ last updated 26 Oct 2013
+#                                                   ~~ last updated 29 Mar 2014
 
 require 'rubygems'
 require 'bundler'
 helpers do
   # This block defines subfunctions for use inside the route definitions.
 
-    def query(sql)
+    def sqlite(query)
       # This helper method helps DRY out the code for database queries, and it
       # does so in an incredibly robust and inefficient way -- by creating the
       # table and evicting expired rows before every single query. A caveat, of
                 );
                 DELETE FROM avars WHERE (exp_date < #{now_plus(0)})
                 sql
-          # We have to execute the query code `sql` separately because the
+          # We have to execute the query code `query` separately because the
           # `db.execute_batch` function always returns `nil`, which prevents
           # us from being able to retrieve the results of the query.
-            x = db.execute(sql)
+            x = db.execute(query)
         rescue SQLite3::Exception => err
-            puts "Exception occured: #{err}"
+            puts "Exception occurred: #{err}"
         ensure
             db.close if db
         end
                 (@box.match(/^[\w\-]+$/)) and
                 ((@key.is_a?(String) and @key.match(/^[A-Za-z0-9]+$/)) or
                 (@status.is_a?(String) and @status.match(/^[A-Za-z0-9]+$/)))
-        cross_origin if (settings.enable_CORS == true)
+        cross_origin if settings.enable_CORS?
     end
 
     get '/:version/:box' do
       # This route responds to API calls that "read" from persistent storage,
       # such as when checking for new tasks to run or downloading results.
+        hang_up unless (@key.is_a?(String) ^ @status.is_a?(String))
         bk, bs = "#{@box}&#{@key}", "#{@box}&#{@status}"
-        if (@key.is_a?(String)) then
+        if @key.is_a?(String) then
           # This arm runs when a client requests the value of a specific avar.
-            x = query("SELECT body FROM avars WHERE box_key = '#{bk}'")
+            x = sqlite("SELECT body FROM avars WHERE box_key = '#{bk}'")
             y = (x.length == 0) ? '{}' : x[0][0]
         else
           # This arm runs when a client requests a task queue.
-            x = query("SELECT key FROM avars WHERE box_status = '#{bs}'")
+            x = sqlite("SELECT key FROM avars WHERE box_status = '#{bs}'")
             y = (x.length == 0) ? '[]' : (x.map {|row| row[0]}).to_json
         end
         return [200, {'Content-Type' => 'application/json'}, [y]]
     post '/:version/:box' do
       # This route responds to API calls that "write" to persistent storage,
       # such as when uploading results or submitting new tasks.
-        hang_up unless (@key.is_a?(String))
+        hang_up unless @key.is_a?(String) and not @status.is_a?(String)
         body, ed = request.body.read, now_plus(settings.avar_ttl)
         x = JSON.parse(body)
         hang_up unless (@box == x['box']) and (@key == x['key'])
         bk, bs = "#{@box}&#{@key}", "#{@box}&#{x['status']}"
-        if (x['status'].is_a?(String)) then
-          # This arm runs only when a client writes a task description.
-            hang_up if (x['status'].match(/^[A-Za-z0-9]+$/) == nil)
-            query <<-sql
-                INSERT OR REPLACE INTO avars
-                    (body, box_key, box_status, exp_date, key)
-                VALUES ('#{body}', '#{bk}', '#{bs}', #{ed}, '#{x['key']}')
-                sql
+        if x['status'].is_a?(String) then
+          # This arm runs only when a client writes an avar which represents a
+          # task description.
+            hang_up unless x['status'].match(/^[A-Za-z0-9]+$/)
+            sqlite("INSERT OR REPLACE INTO avars
+                        (body, box_key, box_status, exp_date, key)
+                    VALUES ('#{body}', '#{bk}', '#{bs}', #{ed}, '#{@key}')")
         else
           # This arm runs when a client is writing a "regular avar".
-            query <<-sql
-                INSERT OR REPLACE INTO avars (body, box_key, exp_date)
-                VALUES ('#{body}', '#{bk}', #{ed})
-                sql
+            sqlite("INSERT OR REPLACE INTO avars (body, box_key, exp_date)
+                    VALUES ('#{body}', '#{bk}', #{ed})")
         end
         return [201, {'Content-Type' => 'text/plain'}, ['']]
     end

src/web-service/custom.js

 
 //- custom.js ~~
 //                                                      ~~ (c) SRW, 09 Dec 2013
-//                                                  ~~ last updated 12 Dec 2013
+//                                                  ~~ last updated 01 Apr 2014
 
 (function () {
     'use strict';
         cf_connecting_ip, 'cf-connecting-ip', cf_ipcountry, 'cf-ipcountry',
         cf_ray, 'cf-ray', cf_visitor, 'cf-visitor', connection, content_length,
         'content-length', dnt, env, hasOwnProperty, headers, host, ip, log,
-        method, origin, parse, remoteAddress, replace, split, timestamp, url,
-        x_forwarded_for, 'x-forwarded-for', x_forwarded_port,
+        method, origin, parse, referer, remoteAddress, replace, split,
+        timestamp, url, x_forwarded_for, 'x-forwarded-for', x_forwarded_port,
         'x-forwarded-port', x_forwarded_proto, 'x-forwarded-proto',
         x_request_start, 'x-request-start', x_wap_profile, 'x-wap-profile'
     */
          // See http://goo.gl/BZldtx.
             y.origin = headers.origin;
         }
+        if (headers.hasOwnProperty('referer')) {
+         // See http://goo.gl/BCW8Vf.
+            y.referer = headers.referer;
+        }
         if (headers.hasOwnProperty('x-forwarded-for')) {
          // See http://goo.gl/ZtqLv1.
             y.ip = headers['x-forwarded-for'].split(',')[0];

src/web-service/package.json

         "email": "sean@mathbiol.org"
     },
     "dependencies": {
-        "qm": "1.1.5"
+        "qm": "1.1.7"
     },
     "engines": {
         "node": ">= 0.8.0",
     "name": "web-service",
     "private": true,
     "readme": "See https://wiki.qmachine.org for more information.",
-    "repository": [],
     "scripts": {},
-    "version": "1.1.5"
+    "version": "1.1.7"
 }
 //  NOTE: I need to rewrite this junk so it uses Quanah ...
 //
 //                                                      ~~ (c) SRW, 28 Nov 2012
-//                                                  ~~ last updated 28 Oct 2013
+//                                                  ~~ last updated 16 Mar 2014
 
 (function () {
     'use strict';
     };
 
     mothership = phantom.args[0]; // this is for compatibility with 1.4.0 ...
-    //mothership = require('system').env['MOTHERSHIP'];
+    //mothership = require('system').env['QM_API_URL'];
 
     queue = [];