Browse Source

Merge branch 'master' of github.com:TechEmpower/FrameworkBenchmarks into add-restexpress

Todd Fredrich 12 years ago
parent
commit
8ffc87dc2a
100 changed files with 1951 additions and 3534 deletions
  1. 3 0
      .gitignore
  2. 20 11
      README.md
  3. 27 7
      benchmarker.py
  4. 25 0
      bottle/README.md
  5. 0 0
      bottle/__init__.py
  6. 72 0
      bottle/app.py
  7. 20 0
      bottle/benchmark_config
  8. 23 0
      bottle/setup.py
  9. 1 1
      cake/README.md
  10. 2 2
      cake/setup.py
  11. 9 1
      compojure/benchmark_config
  12. 4 0
      compojure/hello/project.clj
  13. 104 6
      compojure/hello/src/hello/handler.clj
  14. 1 1
      compojure/setup.py
  15. 2 1
      config/benchmark_profile
  16. 5 1
      config/client_sftp_batch
  17. 6 0
      config/create-postgres-database.sql
  18. 29 0
      config/create-postgres.sql
  19. 18 1
      config/create.js
  20. 21 0
      config/create.sql
  21. 2 2
      config/my.cnf
  22. 100 0
      config/pg_hba.conf
  23. 1 1
      config/php-fpm.conf
  24. 4 1
      config/php.ini
  25. 556 0
      config/postgresql.conf
  26. 34 0
      cowboy/README.md
  27. 24 0
      dancer/README.md
  28. 0 0
      dancer/__init__.py
  29. 32 0
      dancer/app.pl
  30. 18 0
      dancer/benchmark_config
  31. 37 0
      dancer/nginx.conf
  32. 32 0
      dancer/setup.py
  33. 2 2
      django-stripped/hello/world/views.py
  34. 1 1
      django-stripped/setup.py
  35. 2 1
      django/benchmark_config
  36. 2 1
      django/hello/hello/settings.py
  37. 1 0
      django/hello/hello/urls.py
  38. 1 4
      django/hello/templates/base.html
  39. 16 0
      django/hello/templates/fortunes.html
  40. 6 2
      django/hello/world/models.py
  41. 13 3
      django/hello/world/views.py
  42. 5 1
      django/setup.py
  43. 0 0
      dropwizard/__init__.py
  44. 13 0
      dropwizard/benchmark_config
  45. 58 0
      dropwizard/hello-world.yml
  46. 88 0
      dropwizard/pom.xml
  47. 25 0
      dropwizard/setup.py
  48. 25 0
      dropwizard/src/main/java/com/example/helloworld/HelloWorldConfiguration.java
  49. 48 0
      dropwizard/src/main/java/com/example/helloworld/HelloWorldService.java
  50. 36 0
      dropwizard/src/main/java/com/example/helloworld/core/World.java
  51. 22 0
      dropwizard/src/main/java/com/example/helloworld/db/WorldDAO.java
  52. 28 0
      dropwizard/src/main/java/com/example/helloworld/resources/JsonResource.java
  53. 42 0
      dropwizard/src/main/java/com/example/helloworld/resources/WorldResource.java
  54. 33 0
      elli/README.md
  55. 23 1
      express/app.js
  56. 2 1
      express/benchmark_config
  57. 2 1
      express/package.json
  58. 20 0
      express/views/fortune.mustache
  59. 11 0
      express/views/fortunes/index.jade
  60. 6 0
      express/views/layout.jade
  61. 11 7
      finagle/src/main/scala/com/falmarri/finagle/Finagle.scala
  62. 11 3
      flask/README.md
  63. 29 0
      flask/app.py
  64. 9 2
      flask/benchmark_config
  65. 1 1
      flask/setup.py
  66. 90 6
      framework_test.py
  67. 3 1
      gemini/.classpath
  68. 1 1
      gemini/.project
  69. 0 15
      gemini/Docroot/WEB-INF/GeminiHello-Base.conf
  70. 0 7
      gemini/Docroot/WEB-INF/GeminiHello-Dev.conf
  71. 5 3
      gemini/Docroot/WEB-INF/GeminiHello-Inverness.conf
  72. 2 16
      gemini/Docroot/WEB-INF/GeminiHello-Prod.conf
  73. 1 16
      gemini/Docroot/WEB-INF/GeminiHello.conf
  74. 0 79
      gemini/Docroot/WEB-INF/access-error.jsp
  75. 0 49
      gemini/Docroot/WEB-INF/jsp/error-page.jsp
  76. 0 1
      gemini/Docroot/WEB-INF/jsp/include-page-end.jsp
  77. 0 5
      gemini/Docroot/WEB-INF/jsp/include-page-start.jsp
  78. 0 27
      gemini/Docroot/WEB-INF/jsp/include-variables.jsp
  79. 0 32
      gemini/Docroot/WEB-INF/jsp/template.jsp
  80. BIN
      gemini/Docroot/WEB-INF/lib/gemini-1.3.6.jar
  81. BIN
      gemini/Docroot/WEB-INF/lib/guava-13.0.1.jar
  82. BIN
      gemini/Docroot/WEB-INF/lib/guava-14.0.1.jar
  83. BIN
      gemini/Docroot/WEB-INF/lib/techempower.jar
  84. BIN
      gemini/Docroot/WEB-INF/lib/trove4j-3.0.3.jar
  85. 16 0
      gemini/Docroot/WEB-INF/mustache/fortunes.mustache
  86. 9 0
      gemini/Docroot/WEB-INF/mustache/layout.mustache
  87. 0 10
      gemini/Docroot/WEB-INF/web.xml
  88. 0 104
      gemini/Docroot/css/basicadmin-logmonitor.css
  89. 0 473
      gemini/Docroot/css/basicadmin.css
  90. 0 82
      gemini/Docroot/css/gh.css
  91. 0 291
      gemini/Docroot/html/admin-compact-performance-monitor.html
  92. BIN
      gemini/Docroot/images/alert.gif
  93. BIN
      gemini/Docroot/images/filler.gif
  94. BIN
      gemini/Docroot/images/monitor-graph.png
  95. 0 354
      gemini/Docroot/js/basicadmin-logmonitor.js
  96. 0 396
      gemini/Docroot/js/basicadmin.js
  97. 0 1427
      gemini/Docroot/js/excanvas.js
  98. 0 43
      gemini/Docroot/js/gh.forms.js
  99. 0 25
      gemini/Docroot/js/gh.js
  100. 0 4
      gemini/Docroot/js/html5.js

+ 3 - 0
.gitignore

@@ -12,3 +12,6 @@ mods/
 /.settings
 /.buildpath
 /.project
+*.iml
+.idea/
+.hsenv/

+ 20 - 11
README.md

@@ -1,8 +1,10 @@
-# Web Framework Benchmarking Tests
+# Web Framework Performance Comparison
 
-Guesses and anecdotes can dominate discussions about the performance of web application frameworks.  Here we attempt to provide some objective performance measures across a wide field of frameworks, covering several platforms: Go, Python, Java, Ruby, PHP, Clojure, Groovy, and JavaScript.  The tests exercise the frameworks' JSON seralization and object-relational model (ORM).  Future versions will exercise server-side template libraries and other computation.
+This project is an attempt to provide representative and objective performance measures across a wide field of web application frameworks. With much help from the community, we now have very broad coverage and are happy to broaden it further with contributions. The project presently includes frameworks on many languages including Go, Python, Java, Ruby, PHP, Clojure, Groovy, JavaScript, Erlang, Haskell, Scala, Lua, and C.  The current tests exercise the frameworks' JSON seralization and object-relational model (ORM).  Future tests will exercise server-side template libraries and other computation.
 
-See results data we've collected from Amazon EC2 instances and our physical hardware at our blog. http://www.techempower.com/blog/2013/03/28/framework-benchmarks/
+Read more and see the results of our tests on Amazon EC2 and physical hardware at http://www.techempower.com/benchmarks/
+
+Join in the conversation at our Google Group: https://groups.google.com/forum/?fromgroups=#!forum/framework-benchmarks
 
 ## Running the test suite
 
@@ -24,6 +26,8 @@ When propmted to create a security group for the instances, here are the ports t
 * 9000 (Play Framework)
 * 27017 (MongoDB)
 * 3000 (yesod)
+* 8000 (snap)
+
 
 #### 2. Setting up the servers
 
@@ -36,7 +40,7 @@ To coordinate the tests via scripting, the servers need to be able to work toget
 Now ssh into the server instance and clone the latest from this repository (the scripts we use to run the tests expect that you'll clone the repository into your home directory):
 
 	ssh -i path-to-pem-file ubuntu@server-instance-ip
-	sudo apt-get install git-core
+	yes | sudo apt-get install git-core
 	git clone https://github.com/TechEmpower/FrameworkBenchmarks.git
 	cd FrameworkBenchmarks
 
@@ -45,12 +49,15 @@ Next, we're going to setup the servers with all the necessary software:
 	./run-tests.py -s server-private-ip -c client-private-ip -i path-to-pem --install-software --list-tests
     source ~/.bash_profile
     # For your first time through the tests, set the ulimit for open files
-    ulimit -n 4096
+    ulimit -n 8192
     # Most software is installed autormatically by the script, but running the mongo command below from 
     # the install script was causing some errors. For now this needs to be run manually.
-    cd installs/jruby-rack && rvm jruby-1.7.3 do jruby -S bundle exec rake clean gem SKIP_SPECS=true"
+    cd installs/jruby-rack && rvm jruby-1.7.3 do jruby -S bundle exec rake clean gem SKIP_SPECS=true
     cd target && rvm jruby-1.7.3 do gem install jruby-rack-1.2.0.SNAPSHOT.gem
-    cd ../..
+    cd ../../..
+    cd installs && curl -sS https://getcomposer.org/installer | php -- --install-dir=bin
+    cd ..
+    sudo apt-get remove --purge openjdk-6-jre openjdk-6-jre-headless
 	  mongo --host client-private-ip < config/create.js
 
 Assuming the above finished without error, we're ready to start the test suite:
@@ -97,12 +104,14 @@ Next, we're going to setup the servers with all the necessary software:
 	./run-tests.py -s server-ip -c client-ip -i path-to-ssh-key --install-software --list-tests
     source ~/.bash_profile
     # For your first time through the tests, set the ulimit for open files
-    ulimit -n 4096
     # Most software is installed autormatically by the script, but running the mongo command below from
     # the install script was causing some errors. For now this needs to be run manually.
-    cd installs/jruby-rack && rvm jruby-1.7.3 do jruby -S bundle exec rake clean gem SKIP_SPECS=true"
+    cd installs/jruby-rack && rvm jruby-1.7.3 do jruby -S bundle exec rake clean gem SKIP_SPECS=true
     cd target && rvm jruby-1.7.3 do gem install jruby-rack-1.2.0.SNAPSHOT.gem
-    cd ../..
+    cd ../../..
+    cd installs && curl -sS https://getcomposer.org/installer | php -- --install-dir=bin
+    cd ..
+    sudo apt-get remove --purge openjdk-6-jre openjdk-6-jre-headless
     mongo --host client-ip < config/create.js
 
 Assuming this finished without error, we're ready to start the test suite:
@@ -236,7 +245,7 @@ The benchmark_config file is used by our run script to identify the available te
   * query_url (optional): The relative URL path to the variable query test. The URL must be set up so that an integer can be applied to the end of the url to specify the number of queries to run, i.e. /db?queries= or /db/
   * port: The port the server is listneing on
   * sort: The sort order. This is important for our own blog post which relies on consistent ordering of the frameworks. You can get the next available sort order by running:
-    ./run-test.py --next-sort
+    ./run-tests.py --next-sort
 
 ## Setup Files
 

+ 27 - 7
benchmarker.py

@@ -175,19 +175,24 @@ class Benchmarker:
   ############################################################
   # report_results
   ############################################################
-  def report_results(self, framework, test, results, latency, requests, total_time):
+  def report_results(self, framework, test, results, latency, requests, total_time, errors, total_requests):
     # Try to get the id in the result array if it exists.
     try:
       framework_id = str(self.results['frameworks'].index(framework.name))
     except ValueError:
       framework_id = str(framework.sort)
       
-    
+    if test not in self.results['rawData'].keys():
+      self.results['rawData'][test] = dict()
+      self.results['weighttpData'][test] = dict()
+
     self.results['rawData'][test][framework_id] = results
     self.results['weighttpData'][test][framework_id] = dict()
     self.results['weighttpData'][test][framework_id]['latency'] = latency
     self.results['weighttpData'][test][framework_id]['requests'] = requests
     self.results['weighttpData'][test][framework_id]['totalTime'] = total_time
+    self.results['weighttpData'][test][framework_id]['errors'] = errors
+    self.results['weighttpData'][test][framework_id]['totalRequests'] = total_requests
 
   ############################################################
   # End report_results
@@ -251,7 +256,7 @@ class Benchmarker:
   def __setup_server(self):
     try:
       subprocess.check_call("sudo sysctl -w net.core.somaxconn=1024".rsplit(" "))
-      subprocess.check_call("sudo -s ulimit -n 4096".rsplit(" "))
+      subprocess.check_call("sudo -s ulimit -n 8192".rsplit(" "))
       subprocess.check_call("sudo sysctl net.ipv4.tcp_tw_reuse=1".rsplit(" "))
       subprocess.check_call("sudo sysctl net.ipv4.tcp_tw_recycle=1".rsplit(" "))
       subprocess.check_call("sudo sysctl -w kernel.shmmax=134217728".rsplit(" "))
@@ -272,10 +277,10 @@ class Benchmarker:
     p = subprocess.Popen(self.ssh_string, stdin=subprocess.PIPE, shell=True)
     p.communicate("""
       sudo sysctl -w net.core.somaxconn=1024
-      sudo -s ulimit -n 4096
+      sudo -s ulimit -n 8192
       sudo sysctl net.ipv4.tcp_tw_reuse=1
       sudo sysctl net.ipv4.tcp_tw_recycle=1
-      sudo sysctl -w kernel.shmmax=134217728
+      sudo sysctl -w kernel.shmmax=2147483648
       sudo sysctl -w kernel.shmall=2097152
     """)
   ############################################################
@@ -299,7 +304,11 @@ class Benchmarker:
       # If the test is in the excludes list, we skip it
       if self.exclude != None and test.name in self.exclude:
         continue
-
+      
+      # If the test does not contain an implementation of the current test-type, skip it
+      if self.type != 'all' and not test.contains_type(self.type):
+        continue
+      
       print textwrap.dedent("""
       =====================================================
         Beginning {name}
@@ -419,6 +428,15 @@ class Benchmarker:
         framework = self.results['frameworks'][int(key)]
         writer.writerow([framework] + value)
 
+    # Fortune CSV
+    with open(os.path.join(self.full_results_directory(), "fortune.csv"), 'wb') as csvfile:
+      writer = csv.writer(csvfile)
+      writer.writerow(["Framework"] + self.query_intervals)
+      if 'fortune' in self.results['rawData'].keys():
+        for key, value in self.results['rawData']['fortune'].iteritems():
+          framework = self.results['frameworks'][int(key)]
+          writer.writerow([framework] + value)
+
   ############################################################
   # End __parse_results
   ############################################################
@@ -502,10 +520,12 @@ class Benchmarker:
       self.results['rawData']['json'] = dict()
       self.results['rawData']['db'] = dict()
       self.results['rawData']['query'] = dict()
+      self.results['rawData']['fortune'] = dict()
       self.results['weighttpData'] = dict()
       self.results['weighttpData']['json'] = dict()
       self.results['weighttpData']['db'] = dict()
       self.results['weighttpData']['query'] = dict()
+      self.results['weighttpData']['fortune'] = dict()
     else:
       for x in self.__gather_tests():
         if x.name not in self.results['frameworks']:
@@ -524,4 +544,4 @@ class Benchmarker:
   # End __init__
   ############################################################
   
-  
+  

+ 25 - 0
bottle/README.md

@@ -0,0 +1,25 @@
+# Bottle Benchmark Test
+
+Single file test, [app.py](app.py)
+
+
+## Test URLs
+### JSON Encoding 
+
+http://localhost:8080/json
+
+### Single Row Random Query
+
+With ORM:
+    http://localhost:8080/dbs
+
+Without ORM (raw):
+    http://localhost:8080/dbsraw
+
+### Variable Row Query Test 
+
+With ORM:
+    http://localhost:8080/db?queries=2
+
+Without ORM (raw):
+    http://localhost:8080/dbraw?queries=2

+ 0 - 0
bottle/__init__.py


+ 72 - 0
bottle/app.py

@@ -0,0 +1,72 @@
+from bottle import Bottle, route, request, run
+from bottle.ext import sqlalchemy 
+from sqlalchemy import create_engine, Column, Integer
+from sqlalchemy.ext.declarative import declarative_base
+from random import randint
+import ujson
+
+app = Bottle()
+app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://benchmarkdbuser:benchmarkdbpass@DBHOSTNAME:3306/hello_world'
+Base = declarative_base()
+db_engine = create_engine(app.config['SQLALCHEMY_DATABASE_URI'])
+plugin = sqlalchemy.Plugin(db_engine, keyword='db', )
+app.install(plugin)
+
+
+class World(Base):
+  __tablename__ = "World"
+  id = Column(Integer, primary_key=True)
+  randomNumber = Column(Integer)
+
+  # http://stackoverflow.com/questions/7102754/jsonify-a-sqlalchemy-result-set-in-flask
+  @property
+  def serialize(self):
+     """Return object data in easily serializeable format"""
+     return {
+         'id'         : self.id,
+         'randomNumber': self.randomNumber
+     }
+
[email protected]("/json")
+def hello():
+  resp = {"message": "Hello, World!"}
+  return ujson.dumps(resp)
+
[email protected]("/db")
+def get_random_world(db):
+  num_queries = request.query.queries or '1'
+  worlds = []
+  for i in range(int(num_queries)):
+    wid = randint(1, 10000)
+    worlds.append(db.query(World).get(wid).serialize)
+  return ujson.dumps(worlds)
+
[email protected]("/dbs")
+def get_random_world_single(db):
+  wid = randint(1, 10000)
+  worlds = [db.query(World).get(wid).serialize]
+  return ujson.dumps(worlds)
+  
[email protected]("/dbraw")
+def get_random_world_raw():
+  connection = db_engine.connect()
+  num_queries = request.query.queries or '1'
+  worlds = []
+  for i in range(int(num_queries)):
+    wid = randint(1, 10000)
+    result = connection.execute("SELECT * FROM world WHERE id = " + str(wid)).fetchone()
+    worlds.append({'id': result[0], 'randomNumber': result[1]})
+  connection.close()
+  return ujson.dumps(worlds)
+
[email protected]("/dbsraw")
+def get_random_world_single_raw():
+  connection = db_engine.connect()
+  wid = randint(1, 10000)
+  result = connection.execute("SELECT * FROM world WHERE id = " + str(wid)).fetchone()
+  worlds = [{'id': result[0], 'randomNumber': result[1]}]
+  connection.close()
+  return ujson.dumps(worlds)
+
+if __name__ == "__main__":
+    app.run()

+ 20 - 0
bottle/benchmark_config

@@ -0,0 +1,20 @@
+{
+  "framework": "bottle",
+  "tests": [{
+    "default": {
+      "setup_file": "setup",
+      "json_url": "/json",
+      "db_url": "/dbs",
+      "query_url": "/db?queries=",
+      "port": 8080,
+      "sort": 88
+    },
+    "mysql-raw": {
+      "setup_file": "setup",
+      "db_url": "/dbsraw",
+      "query_url": "/dbraw?queries=",
+      "port": 8080,
+      "sort": 89
+    }
+  }]
+}

+ 23 - 0
bottle/setup.py

@@ -0,0 +1,23 @@
+import subprocess
+import sys
+import setup_util
+import os
+
+def start(args):
+  setup_util.replace_text("bottle/app.py", "DBHOSTNAME", args.database_host)
+  subprocess.Popen("gunicorn app:app --worker-class=\"egg:meinheld#gunicorn_worker\" -b 0.0.0.0:8080 -w " + str((args.max_threads * 2)) + " --preload --log-level=critical", shell=True, cwd="bottle")
+  
+  return 0
+
+def stop():
+  p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
+  out, err = p.communicate()
+  for line in out.splitlines():
+    if 'gunicorn' in line:
+      try:
+        pid = int(line.split(None, 2)[1])
+        os.kill(pid, 9)
+      except OSError:
+        pass
+  
+  return 0

+ 1 - 1
cake/README.md

@@ -20,7 +20,7 @@ The tests were run with:
 
 * [Cake Version 2.3.0](http://cakephp.org/)
 * [PHP Version 5.4.13](http://www.php.net/) with FPM and APC
-* [nginx 1.2.7](http://nginx.org/)
+* [nginx 1.4.0](http://nginx.org/)
 * [MySQL 5.5.29](https://dev.mysql.com/)
 
 Cake Debug mode is set to 0 in [core.php](app/Config/core.php), as

+ 2 - 2
cake/setup.py

@@ -15,7 +15,7 @@ def start(args):
   try:
     #subprocess.check_call("sudo cp cake/deploy/cake /etc/apache2/sites-available/", shell=True)
     #subprocess.check_call("sudo a2ensite cake", shell=True)
-    #subprocess.check_call("sudo chown -R www-data:www-data cake", shell=True)
+    subprocess.check_call("sudo chown -R www-data:www-data cake", shell=True)
     #subprocess.check_call("sudo /etc/init.d/apache2 start", shell=True)
     subprocess.check_call("sudo php-fpm --fpm-config config/php-fpm.conf -g " + home + "/FrameworkBenchmarks/cake/deploy/php-fpm.pid", shell=True)
     subprocess.check_call("sudo /usr/local/nginx/sbin/nginx -c " + home + "/FrameworkBenchmarks/cake/deploy/nginx.conf", shell=True)
@@ -28,7 +28,7 @@ def stop():
     subprocess.call("sudo kill -QUIT $( cat cake/deploy/php-fpm.pid )", shell=True)
     #subprocess.check_call("sudo a2dissite cake", shell=True)
     #subprocess.check_call("sudo /etc/init.d/apache2 stop", shell=True)
-    #subprocess.check_call("sudo chown -R $USER:$USER cake", shell=True)
+    subprocess.check_call("sudo chown -R $USER:$USER cake", shell=True)
     return 0
   except subprocess.CalledProcessError:
     return 1

+ 9 - 1
compojure/benchmark_config

@@ -6,8 +6,16 @@
       "json_url": "/compojure/json",
       "db_url": "/compojure/db/1",
       "query_url": "/compojure/db/",
+      "fortune_url": "/compojure/fortune-hiccup",
       "port": 8080,
       "sort": 2
+    },
+    "raw": {
+      "setup_file": "setup",
+      "db_url": "/compojure/dbraw/1",
+      "query_url": "/compojure/dbraw/",
+      "port": 8080,
+      "sort": 85
     }
   }]
-}
+}

+ 4 - 0
compojure/hello/project.clj

@@ -7,6 +7,10 @@
                  [korma "0.3.0-RC5"]
                  [log4j "1.2.15" :exclusions [javax.mail/mail javax.jms/jms com.sun.jdmk/jmxtools com.sun.jmx/jmxri]]
                  [mysql/mysql-connector-java "5.1.6"]
+                 [org.clojure/java.jdbc "0.3.0-alpha1"]
+                 [c3p0/c3p0 "0.9.1.2"]
+                 [hiccup "1.0.3"]
+                 [enlive "1.1.1"]
                  ]
   :plugins [[lein-ring "0.8.2"]]
   :ring {:handler hello.handler/app}

+ 104 - 6
compojure/hello/src/hello/handler.clj

@@ -1,19 +1,23 @@
 (ns hello.handler
+  (:import com.mchange.v2.c3p0.ComboPooledDataSource)
   (:use compojure.core
         ring.middleware.json
         ring.util.response
         korma.db
-        korma.core)
+        korma.core
+        hiccup.core
+        hiccup.util)
   (:require [compojure.handler :as handler]
-            [compojure.route :as route]))
+            [compojure.route :as route]
+            [clojure.java.jdbc :as jdbc]
+            [clojure.java.jdbc.sql :as sql]
+            [net.cgrand.enlive-html :as html]))
 
 ; Database connection
-(defdb db (mysql {:db "hello_world"
+(defdb db (mysql {:subname "//localhost:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts&cacheRSMetadata=true"
                   :user "benchmarkdbuser"
                   :password "benchmarkdbpass"
                   ;;OPTIONAL KEYS
-                  :host "localhost"
-                  :port "3306"
                   :delimiters "" ;; remove delimiters
                   :maximum-pool-size 256
                   }))
@@ -40,11 +44,105 @@
      queries ; Number of queries to run
      (repeatedly get-world)))))
 
+; Database connection for java.jdbc "raw"
+; https://github.com/clojure/java.jdbc/blob/master/doc/clojure/java/jdbc/ConnectionPooling.md
+(def db-spec-mysql-raw
+  {:classname "com.mysql.jdbc.Driver"
+   :subprotocol "mysql"
+   :subname "//localhost:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts&cacheRSMetadata=true"
+   :user "benchmarkdbuser"
+   :password "benchmarkdbpass"})
+
+(defn pool
+  [spec]
+  (let [cpds (doto (ComboPooledDataSource.)
+               (.setDriverClass (:classname spec))
+               (.setJdbcUrl (str "jdbc:" (:subprotocol spec) ":" (:subname spec)))
+               (.setUser (:user spec))
+               (.setPassword (:password spec))
+               ;; expire excess connections after 30 minutes of inactivity:
+               (.setMaxIdleTimeExcessConnections (* 30 60))
+               ;; expire connections after 3 hours of inactivity:
+               (.setMaxIdleTime (* 3 60 60)))]
+    {:datasource cpds}))
+
+(def pooled-db (delay (pool db-spec-mysql-raw)))
+
+(defn db-raw [] @pooled-db)
+
+; Query a random World record from the database
+(defn get-world-raw []
+  (let [id (inc (rand-int 9999))] ; Num between 1 and 10,000
+    (jdbc/with-connection (db-raw)
+      (jdbc/with-query-results rs [(str "select * from world where id = ?") id]
+        (doall rs)))))
+
+; Run the specified number of queries, return the results
+(defn run-queries-raw [queries]
+  (vec ; Return as a vector
+   (flatten ; Make it a list of maps
+    (take
+     queries ; Number of queries to run
+     (repeatedly get-world-raw)))))
+
+(defn get-query-count [queries]
+  "Parse provided string value of query count, clamping values to between 1 and 500."
+  (let [q (try (Integer/parseInt queries)
+               (catch Exception e 1))] ; default to 1 on parse failure
+    (if (> q 500)
+      500 ; clamp to 500 max
+      (if (< q 1)
+        1 ; clamp to 1 min
+        q)))) ; otherwise use provided value
+
+
+; Set up entity World and the database representation
+(defentity fortune
+  (pk :id)
+  (table :fortune)
+  (entity-fields :id :message)
+  (database db))
+
+(defn get-all-fortunes []
+  "Query all Fortune records from the database."
+    (select fortune
+            (fields :id :message)))
+
+(defn get-fortunes []
+  "Fetch the full list of Fortunes from the database, sort them by the fortune
+message text, and then return the results."
+  (let [fortunes (conj (get-all-fortunes) {:id 0 :message "Additional fortune added at request time."} )]
+    (sort-by #(:message %) fortunes)))
+
+(defn fortunes-hiccup [fortunes]
+  "Render the given fortunes to simple HTML using Hiccup."
+  (html
+   [:head
+    [:title "Fortunes"]]
+   [:body
+    [:table
+     [:tr
+      [:th "id"]
+      [:th "message"]]
+     (for [x fortunes]
+       [:tr
+        [:td (:id x)]
+        [:td (escape-html (:message x))]])
+     ]]))
+
+(defn fortunes-enlive [fortunes]
+  "Render the given fortunes to simple HTML using Enlive."
+  "todo")
+
 ; Define route handlers
 (defroutes app-routes
   (GET "/" [] "Hello, World!")
   (GET "/json" [] (response {:message "Hello, World!"}))
-  (GET "/db/:queries" [queries] (response (run-queries (Integer/parseInt queries))))
+  (GET "/db/:queries" [queries] (response (run-queries (get-query-count queries))))
+  (GET "/dbraw/:queries" [queries] (response (run-queries-raw (get-query-count queries))))
+  (GET "/fortune" [] (response (get-fortunes)))
+  (GET "/fortune-hiccup" [] (fortunes-hiccup (get-fortunes)))
+  (GET "/fortune-enlive" [] (fortunes-enlive (get-fortunes)))
   (route/not-found "Not Found"))
 
 ; Format responses as JSON

+ 1 - 1
compojure/setup.py

@@ -4,7 +4,7 @@ import sys
 import setup_util
 
 def start(args):
-  setup_util.replace_text("compojure/hello/src/hello/handler.clj", ":host \".*\"", ":host \"" + args.database_host + "\"")
+  setup_util.replace_text("compojure/hello/src/hello/handler.clj", ":subname \"//.*:3306", ":subname \"//" + args.database_host + ":3306")
 
   try:
     subprocess.check_call("lein ring uberwar", shell=True, cwd="compojure/hello")

+ 2 - 1
config/benchmark_profile

@@ -7,7 +7,8 @@ export GOPATH=~/FrameworkBenchmarks/go:~/FrameworkBenchmarks/webgo:$GOROOT
 export TOMCAT_HOME=~/FrameworkBenchmarks/installs/apache-tomcat-7.0.35
 export NODE_HOME=~/FrameworkBenchmarks/installs/node-v0.10.2-linux-x64
 export PLAY_HOME=~/FrameworkBenchmarks/installs/play-2.1.1
-export PATH="$JAVA_HOME/bin:$GRAILS_HOME/bin:$PLAY_HOME:$VERTX_HOME/bin:$GOROOT/bin:$NODE_HOME/bin:$HOME/FrameworkBenchmarks/installs/bin:$PATH"
+export PLAY1_HOME=~/FrameworkBenchmarks/installs/play-1.2.5
+export PATH="$JAVA_HOME/bin:$GRAILS_HOME/bin:$PLAY_HOME:$PLAY1_HOME:$VERTX_HOME/bin:$GOROOT/bin:$NODE_HOME/bin:$HOME/FrameworkBenchmarks/installs/bin:$PATH"
 
 export LD_LIBRARY_PATH='$LD_LIBRARY_PATH:/usr/local/apr/lib'
 

+ 5 - 1
config/client_sftp_batch

@@ -2,4 +2,8 @@ put config/my.cnf
 put config/mongodb.conf
 put config/create.sql
 put config/create.js
-put config/10gen.list
+put config/10gen.list
+put config/create-postgres-database.sql
+put config/create-postgres.sql
+put config/postgresql.conf
+put config/pg_hba.conf

+ 6 - 0
config/create-postgres-database.sql

@@ -0,0 +1,6 @@
+CREATE USER benchmarkdbuser WITH PASSWORD 'benchmarkdbpass';
+
+DROP DATABASE IF EXISTS hello_world;
+CREATE DATABASE hello_world WITH ENCODING 'UTF8';
+
+GRANT ALL PRIVILEGES ON DATABASE hello_world to benchmarkdbuser;

+ 29 - 0
config/create-postgres.sql

@@ -0,0 +1,29 @@
+DROP TABLE IF EXISTS World;
+CREATE TABLE  World (
+  id integer NOT NULL,
+  randomNumber integer NOT NULL default 0,
+  PRIMARY KEY  (id)
+);
+
+INSERT INTO World (id, randomNumber)
+SELECT x.id, random() * 10000 + 1 FROM generate_series(1,10000) as x(id);
+
+DROP TABLE IF EXISTS Fortune;
+CREATE TABLE  Fortune (
+  id integer NOT NULL,
+  message varchar(2048) NOT NULL,
+  PRIMARY KEY  (id)
+);
+
+INSERT INTO fortune (id, message) VALUES (1, 'fortune: No such file or directory');
+INSERT INTO fortune (id, message) VALUES (2, 'A computer scientist is someone who fixes things that aren''t broken.');
+INSERT INTO fortune (id, message) VALUES (3, 'After enough decimal places, nobody gives a damn.');
+INSERT INTO fortune (id, message) VALUES (4, 'A bad random number generator: 1, 1, 1, 1, 1, 4.33e+67, 1, 1, 1');
+INSERT INTO fortune (id, message) VALUES (5, 'A computer program does what you tell it to do, not what you want it to do.');
+INSERT INTO fortune (id, message) VALUES (6, 'Emacs is a nice operating system, but I prefer UNIX. — Tom Christaensen');
+INSERT INTO fortune (id, message) VALUES (7, 'Any program that runs right is obsolete.');
+INSERT INTO fortune (id, message) VALUES (8, 'A list is only as strong as its weakest link. — Donald Knuth');
+INSERT INTO fortune (id, message) VALUES (9, 'Feature: A bug with seniority.');
+INSERT INTO fortune (id, message) VALUES (10, 'Computers make very fast, very accurate mistakes.');
+INSERT INTO fortune (id, message) VALUES (11, '<script>alert("This should not be displayed in a browser alert box.");</script>');
+INSERT INTO fortune (id, message) VALUES (12, 'フレームワークのベンチマーク');

+ 18 - 1
config/create.js

@@ -5,4 +5,21 @@ for (var i = 1; i <= 10000; i++) {
 }
 
 // http://docs.mongodb.org/manual/applications/optimization/
-db.world.ensureIndex({id: 1})
+db.world.ensureIndex({id: 1})
+
+db.fortune.drop()
+
+db.fortune.save( {id: 1, message: 'fortune: No such file or directory'} );
+db.fortune.save( {id: 2, message: "A computer scientist is someone who fixes things that aren't broken."} );
+db.fortune.save( {id: 3, message: 'After enough decimal places, nobody gives a damn.'} );
+db.fortune.save( {id: 4, message: 'A bad random number generator: 1, 1, 1, 1, 1, 4.33e+67, 1, 1, 1'} );
+db.fortune.save( {id: 5, message: 'A computer program does what you tell it to do, not what you want it to do.'} );
+db.fortune.save( {id: 6, message: 'Emacs is a nice operating system, but I prefer UNIX. — Tom Christaensen'} );
+db.fortune.save( {id: 7, message: 'Any program that runs right is obsolete.'} );
+db.fortune.save( {id: 8, message: 'A list is only as strong as its weakest link. — Donald Knuth'} );
+db.fortune.save( {id: 9, message: 'Feature: A bug with seniority.'} );
+db.fortune.save( {id: 10, message: 'Computers make very fast, very accurate mistakes.'} );
+db.fortune.save( {id: 11, message: '<script>alert("This should not be displayed in a browser alert box.");</script>'} );
+db.fortune.save( {id: 12, message: 'フレームワークのベンチマーク'} );
+
+db.fortune.ensureIndex({id: 1})

+ 21 - 0
config/create.sql

@@ -35,3 +35,24 @@ END #
 DELIMITER ;
 
 CALL load_data();
+
+DROP TABLE IF EXISTS Fortune;
+CREATE TABLE  Fortune (
+  id int(10) unsigned NOT NULL auto_increment,
+  message varchar(2048) CHARACTER SET 'utf8' NOT NULL,
+  PRIMARY KEY  (id)
+)
+ENGINE=INNODB;
+
+INSERT INTO fortune (message) VALUES ('fortune: No such file or directory');
+INSERT INTO fortune (message) VALUES ('A computer scientist is someone who fixes things that aren''t broken.');
+INSERT INTO fortune (message) VALUES ('After enough decimal places, nobody gives a damn.');
+INSERT INTO fortune (message) VALUES ('A bad random number generator: 1, 1, 1, 1, 1, 4.33e+67, 1, 1, 1');
+INSERT INTO fortune (message) VALUES ('A computer program does what you tell it to do, not what you want it to do.');
+INSERT INTO fortune (message) VALUES ('Emacs is a nice operating system, but I prefer UNIX. — Tom Christaensen');
+INSERT INTO fortune (message) VALUES ('Any program that runs right is obsolete.');
+INSERT INTO fortune (message) VALUES ('A list is only as strong as its weakest link. — Donald Knuth');
+INSERT INTO fortune (message) VALUES ('Feature: A bug with seniority.');
+INSERT INTO fortune (message) VALUES ('Computers make very fast, very accurate mistakes.');
+INSERT INTO fortune (message) VALUES ('<script>alert("This should not be displayed in a browser alert box.");</script>');
+INSERT INTO fortune (message) VALUES ('フレームワークのベンチマーク');

+ 2 - 2
config/my.cnf

@@ -53,8 +53,8 @@ key_buffer              = 16M
 max_allowed_packet      = 16M
 thread_stack            = 256K
 thread_cache_size       = 128
-max_connections         = 2000
-back_log                = 2000
+max_connections         = 5000
+back_log                = 5000
 table_open_cache        = 800
 table_definition_cache  = 800
 max_heap_table_size     = 128M

+ 100 - 0
config/pg_hba.conf

@@ -0,0 +1,100 @@
+# PostgreSQL Client Authentication Configuration File
+# ===================================================
+#
+# Refer to the "Client Authentication" section in the PostgreSQL
+# documentation for a complete description of this file.  A short
+# synopsis follows.
+#
+# This file controls: which hosts are allowed to connect, how clients
+# are authenticated, which PostgreSQL user names they can use, which
+# databases they can access.  Records take one of these forms:
+#
+# local      DATABASE  USER  METHOD  [OPTIONS]
+# host       DATABASE  USER  ADDRESS  METHOD  [OPTIONS]
+# hostssl    DATABASE  USER  ADDRESS  METHOD  [OPTIONS]
+# hostnossl  DATABASE  USER  ADDRESS  METHOD  [OPTIONS]
+#
+# (The uppercase items must be replaced by actual values.)
+#
+# The first field is the connection type: "local" is a Unix-domain
+# socket, "host" is either a plain or SSL-encrypted TCP/IP socket,
+# "hostssl" is an SSL-encrypted TCP/IP socket, and "hostnossl" is a
+# plain TCP/IP socket.
+#
+# DATABASE can be "all", "sameuser", "samerole", "replication", a
+# database name, or a comma-separated list thereof. The "all"
+# keyword does not match "replication". Access to replication
+# must be enabled in a separate record (see example below).
+#
+# USER can be "all", a user name, a group name prefixed with "+", or a
+# comma-separated list thereof.  In both the DATABASE and USER fields
+# you can also write a file name prefixed with "@" to include names
+# from a separate file.
+#
+# ADDRESS specifies the set of hosts the record matches.  It can be a
+# host name, or it is made up of an IP address and a CIDR mask that is
+# an integer (between 0 and 32 (IPv4) or 128 (IPv6) inclusive) that
+# specifies the number of significant bits in the mask.  A host name
+# that starts with a dot (.) matches a suffix of the actual host name.
+# Alternatively, you can write an IP address and netmask in separate
+# columns to specify the set of hosts.  Instead of a CIDR-address, you
+# can write "samehost" to match any of the server's own IP addresses,
+# or "samenet" to match any address in any subnet that the server is
+# directly connected to.
+#
+# METHOD can be "trust", "reject", "md5", "password", "gss", "sspi",
+# "krb5", "ident", "peer", "pam", "ldap", "radius" or "cert".  Note that
+# "password" sends passwords in clear text; "md5" is preferred since
+# it sends encrypted passwords.
+#
+# OPTIONS are a set of options for the authentication in the format
+# NAME=VALUE.  The available options depend on the different
+# authentication methods -- refer to the "Client Authentication"
+# section in the documentation for a list of which options are
+# available for which authentication methods.
+#
+# Database and user names containing spaces, commas, quotes and other
+# special characters must be quoted.  Quoting one of the keywords
+# "all", "sameuser", "samerole" or "replication" makes the name lose
+# its special character, and just match a database or username with
+# that name.
+#
+# This file is read on server startup and when the postmaster receives
+# a SIGHUP signal.  If you edit the file on a running system, you have
+# to SIGHUP the postmaster for the changes to take effect.  You can
+# use "pg_ctl reload" to do that.
+
+# Put your actual configuration here
+# ----------------------------------
+#
+# If you want to allow non-local connections, you need to add more
+# "host" records.  In that case you will also need to make PostgreSQL
+# listen on a non-local interface via the listen_addresses
+# configuration parameter, or via the -i or -h command line switches.
+
+
+
+
+# DO NOT DISABLE!
+# If you change this first entry you will need to make sure that the
+# database superuser can access the database using some other method.
+# Noninteractive access to all databases is required during automatic
+# maintenance (custom daily cronjobs, replication, and similar tasks).
+#
+# Database administrative login by Unix domain socket
+local   all             postgres                                peer
+
+# TYPE  DATABASE        USER            ADDRESS                 METHOD
+
+# "local" is for Unix domain socket connections only
+local   all             all                                     peer
+# IPv4 local connections:
+host    all             all             127.0.0.1/32            md5
+# IPv6 local connections:
+host    all             all             ::1/128                 md5
+# Allow replication connections from localhost, by a user with the
+# replication privilege.
+#local   replication     postgres                                peer
+#host    replication     postgres        127.0.0.1/32            md5
+#host    replication     postgres        ::1/128                 md5
+host	all		all		0.0.0.0/0		md5

+ 1 - 1
config/php-fpm.conf

@@ -224,7 +224,7 @@ pm.start_servers = 256
 ; The desired minimum number of idle server processes.
 ; Note: Used only when pm is set to 'dynamic'
 ; Note: Mandatory when pm is set to 'dynamic'
-pm.min_spare_servers = 256
+pm.min_spare_servers = 16
 
 ; The desired maximum number of idle server processes.
 ; Note: Used only when pm is set to 'dynamic'

+ 4 - 1
config/php.ini

@@ -867,6 +867,7 @@ default_socket_timeout = 60
 ; Be sure to appropriately set the extension_dir directive.
 ;
 extension=apc.so
+extension=phalcon.so
 ;extension=php_bz2.dll
 ;extension=php_curl.dll
 ;extension=php_fileinfo.dll
@@ -1860,4 +1861,6 @@ ldap.max_links = -1
 
 ; Local Variables:
 ; tab-width: 4
-; End:
+; End:
+[apc]
+apc.stat = 0

+ 556 - 0
config/postgresql.conf

@@ -0,0 +1,556 @@
+# -----------------------------
+# PostgreSQL configuration file
+# -----------------------------
+#
+# This file consists of lines of the form:
+#
+#   name = value
+#
+# (The "=" is optional.)  Whitespace may be used.  Comments are introduced with
+# "#" anywhere on a line.  The complete list of parameter names and allowed
+# values can be found in the PostgreSQL documentation.
+#
+# The commented-out settings shown in this file represent the default values.
+# Re-commenting a setting is NOT sufficient to revert it to the default value;
+# you need to reload the server.
+#
+# This file is read on server startup and when the server receives a SIGHUP
+# signal.  If you edit the file on a running system, you have to SIGHUP the
+# server for the changes to take effect, or use "pg_ctl reload".  Some
+# parameters, which are marked below, require a server shutdown and restart to
+# take effect.
+#
+# Any parameter can also be given as a command-line option to the server, e.g.,
+# "postgres -c log_connections=on".  Some parameters can be changed at run time
+# with the "SET" SQL command.
+#
+# Memory units:  kB = kilobytes        Time units:  ms  = milliseconds
+#                MB = megabytes                     s   = seconds
+#                GB = gigabytes                     min = minutes
+#                                                   h   = hours
+#                                                   d   = days
+
+
+#------------------------------------------------------------------------------
+# FILE LOCATIONS
+#------------------------------------------------------------------------------
+
+# The default values of these variables are driven from the -D command-line
+# option or PGDATA environment variable, represented here as ConfigDir.
+
+data_directory = '/var/lib/postgresql/9.1/main'		# use data in another directory
+					# (change requires restart)
+hba_file = '/etc/postgresql/9.1/main/pg_hba.conf'	# host-based authentication file
+					# (change requires restart)
+ident_file = '/etc/postgresql/9.1/main/pg_ident.conf'	# ident configuration file
+					# (change requires restart)
+
+# If external_pid_file is not explicitly set, no extra PID file is written.
+external_pid_file = '/var/run/postgresql/9.1-main.pid'		# write an extra PID file
+					# (change requires restart)
+
+
+#------------------------------------------------------------------------------
+# CONNECTIONS AND AUTHENTICATION
+#------------------------------------------------------------------------------
+
+# - Connection Settings -
+
+listen_addresses = '*'		# what IP address(es) to listen on;
+					# comma-separated list of addresses;
+					# defaults to 'localhost', '*' = all
+					# (change requires restart)
+port = 5432				# (change requires restart)
+max_connections = 512			# (change requires restart)
+# Note:  Increasing max_connections costs ~400 bytes of shared memory per
+# connection slot, plus lock space (see max_locks_per_transaction).
+#superuser_reserved_connections = 3	# (change requires restart)
+unix_socket_directory = '/var/run/postgresql'		# (change requires restart)
+#unix_socket_group = ''			# (change requires restart)
+#unix_socket_permissions = 0777		# begin with 0 to use octal notation
+					# (change requires restart)
+#bonjour = off				# advertise server via Bonjour
+					# (change requires restart)
+#bonjour_name = ''			# defaults to the computer name
+					# (change requires restart)
+
+# - Security and Authentication -
+
+#authentication_timeout = 1min		# 1s-600s
+ssl = true				# (change requires restart)
+#ssl_ciphers = 'ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH'	# allowed SSL ciphers
+					# (change requires restart)
+#ssl_renegotiation_limit = 512MB	# amount of data between renegotiations
+#password_encryption = on
+#db_user_namespace = off
+
+# Kerberos and GSSAPI
+#krb_server_keyfile = ''
+#krb_srvname = 'postgres'		# (Kerberos only)
+#krb_caseins_users = off
+
+# - TCP Keepalives -
+# see "man 7 tcp" for details
+
+#tcp_keepalives_idle = 0		# TCP_KEEPIDLE, in seconds;
+					# 0 selects the system default
+#tcp_keepalives_interval = 0		# TCP_KEEPINTVL, in seconds;
+					# 0 selects the system default
+#tcp_keepalives_count = 0		# TCP_KEEPCNT;
+					# 0 selects the system default
+
+
+#------------------------------------------------------------------------------
+# RESOURCE USAGE (except WAL)
+#------------------------------------------------------------------------------
+
+# - Memory -
+
+shared_buffers = 32MB			# min 128kB
+					# (change requires restart)
+#temp_buffers = 8MB			# min 800kB
+#max_prepared_transactions = 0		# zero disables the feature
+					# (change requires restart)
+# Note:  Increasing max_prepared_transactions costs ~600 bytes of shared memory
+# per transaction slot, plus lock space (see max_locks_per_transaction).
+# It is not advisable to set max_prepared_transactions nonzero unless you
+# actively intend to use prepared transactions.
+#work_mem = 1MB				# min 64kB
+#maintenance_work_mem = 16MB		# min 1MB
+#max_stack_depth = 2MB			# min 100kB
+
+# - Kernel Resource Usage -
+
+#max_files_per_process = 1000		# min 25
+					# (change requires restart)
+#shared_preload_libraries = ''		# (change requires restart)
+
+# - Cost-Based Vacuum Delay -
+
+#vacuum_cost_delay = 0ms		# 0-100 milliseconds
+#vacuum_cost_page_hit = 1		# 0-10000 credits
+#vacuum_cost_page_miss = 10		# 0-10000 credits
+#vacuum_cost_page_dirty = 20		# 0-10000 credits
+#vacuum_cost_limit = 200		# 1-10000 credits
+
+# - Background Writer -
+
+#bgwriter_delay = 200ms			# 10-10000ms between rounds
+#bgwriter_lru_maxpages = 100		# 0-1000 max buffers written/round
+#bgwriter_lru_multiplier = 2.0		# 0-10.0 multipler on buffers scanned/round
+
+# - Asynchronous Behavior -
+
+#effective_io_concurrency = 1		# 1-1000. 0 disables prefetching
+
+
+#------------------------------------------------------------------------------
+# WRITE AHEAD LOG
+#------------------------------------------------------------------------------
+
+# - Settings -
+
+#wal_level = minimal			# minimal, archive, or hot_standby
+					# (change requires restart)
+#fsync = on				# turns forced synchronization on or off
+#synchronous_commit = on		# synchronization level; on, off, or local
+#wal_sync_method = fsync		# the default is the first option
+					# supported by the operating system:
+					#   open_datasync
+					#   fdatasync (default on Linux)
+					#   fsync
+					#   fsync_writethrough
+					#   open_sync
+#full_page_writes = on			# recover from partial page writes
+#wal_buffers = -1			# min 32kB, -1 sets based on shared_buffers
+					# (change requires restart)
+#wal_writer_delay = 200ms		# 1-10000 milliseconds
+
+#commit_delay = 0			# range 0-100000, in microseconds
+#commit_siblings = 5			# range 1-1000
+
+# - Checkpoints -
+
+#checkpoint_segments = 3		# in logfile segments, min 1, 16MB each
+#checkpoint_timeout = 5min		# range 30s-1h
+#checkpoint_completion_target = 0.5	# checkpoint target duration, 0.0 - 1.0
+#checkpoint_warning = 30s		# 0 disables
+
+# - Archiving -
+
+#archive_mode = off		# allows archiving to be done
+				# (change requires restart)
+#archive_command = ''		# command to use to archive a logfile segment
+#archive_timeout = 0		# force a logfile segment switch after this
+				# number of seconds; 0 disables
+
+
+#------------------------------------------------------------------------------
+# REPLICATION
+#------------------------------------------------------------------------------
+
+# - Master Server -
+
+# These settings are ignored on a standby server
+
+#max_wal_senders = 0		# max number of walsender processes
+				# (change requires restart)
+#wal_sender_delay = 1s		# walsender cycle time, 1-10000 milliseconds
+#wal_keep_segments = 0		# in logfile segments, 16MB each; 0 disables
+#vacuum_defer_cleanup_age = 0	# number of xacts by which cleanup is delayed
+#replication_timeout = 60s	# in milliseconds; 0 disables
+#synchronous_standby_names = ''	# standby servers that provide sync rep
+				# comma-separated list of application_name
+				# from standby(s); '*' = all
+
+# - Standby Servers -
+
+# These settings are ignored on a master server
+
+#hot_standby = off			# "on" allows queries during recovery
+					# (change requires restart)
+#max_standby_archive_delay = 30s	# max delay before canceling queries
+					# when reading WAL from archive;
+					# -1 allows indefinite delay
+#max_standby_streaming_delay = 30s	# max delay before canceling queries
+					# when reading streaming WAL;
+					# -1 allows indefinite delay
+#wal_receiver_status_interval = 10s	# send replies at least this often
+					# 0 disables
+#hot_standby_feedback = off		# send info from standby to prevent
+					# query conflicts
+
+
+#------------------------------------------------------------------------------
+# QUERY TUNING
+#------------------------------------------------------------------------------
+
+# - Planner Method Configuration -
+
+#enable_bitmapscan = on
+#enable_hashagg = on
+#enable_hashjoin = on
+#enable_indexscan = on
+#enable_material = on
+#enable_mergejoin = on
+#enable_nestloop = on
+#enable_seqscan = on
+#enable_sort = on
+#enable_tidscan = on
+
+# - Planner Cost Constants -
+
+#seq_page_cost = 1.0			# measured on an arbitrary scale
+#random_page_cost = 4.0			# same scale as above
+#cpu_tuple_cost = 0.01			# same scale as above
+#cpu_index_tuple_cost = 0.005		# same scale as above
+#cpu_operator_cost = 0.0025		# same scale as above
+#effective_cache_size = 128MB
+
+# - Genetic Query Optimizer -
+
+#geqo = on
+#geqo_threshold = 12
+#geqo_effort = 5			# range 1-10
+#geqo_pool_size = 0			# selects default based on effort
+#geqo_generations = 0			# selects default based on effort
+#geqo_selection_bias = 2.0		# range 1.5-2.0
+#geqo_seed = 0.0			# range 0.0-1.0
+
+# - Other Planner Options -
+
+#default_statistics_target = 100	# range 1-10000
+#constraint_exclusion = partition	# on, off, or partition
+#cursor_tuple_fraction = 0.1		# range 0.0-1.0
+#from_collapse_limit = 8
+#join_collapse_limit = 8		# 1 disables collapsing of explicit
+					# JOIN clauses
+
+
+#------------------------------------------------------------------------------
+# ERROR REPORTING AND LOGGING
+#------------------------------------------------------------------------------
+
+# - Where to Log -
+
+#log_destination = 'stderr'		# Valid values are combinations of
+					# stderr, csvlog, syslog, and eventlog,
+					# depending on platform.  csvlog
+					# requires logging_collector to be on.
+
+# This is used when logging to stderr:
+#logging_collector = off		# Enable capturing of stderr and csvlog
+					# into log files. Required to be on for
+					# csvlogs.
+					# (change requires restart)
+
+# These are only used if logging_collector is on:
+#log_directory = 'pg_log'		# directory where log files are written,
+					# can be absolute or relative to PGDATA
+#log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'	# log file name pattern,
+					# can include strftime() escapes
+#log_file_mode = 0600			# creation mode for log files,
+					# begin with 0 to use octal notation
+#log_truncate_on_rotation = off		# If on, an existing log file with the
+					# same name as the new log file will be
+					# truncated rather than appended to.
+					# But such truncation only occurs on
+					# time-driven rotation, not on restarts
+					# or size-driven rotation.  Default is
+					# off, meaning append to existing files
+					# in all cases.
+#log_rotation_age = 1d			# Automatic rotation of logfiles will
+					# happen after that time.  0 disables.
+#log_rotation_size = 10MB		# Automatic rotation of logfiles will
+					# happen after that much log output.
+					# 0 disables.
+
+# These are relevant when logging to syslog:
+#syslog_facility = 'LOCAL0'
+#syslog_ident = 'postgres'
+
+#silent_mode = off			# Run server silently.
+					# DO NOT USE without syslog or
+					# logging_collector
+					# (change requires restart)
+
+
+# - When to Log -
+
+#client_min_messages = notice		# values in order of decreasing detail:
+					#   debug5
+					#   debug4
+					#   debug3
+					#   debug2
+					#   debug1
+					#   log
+					#   notice
+					#   warning
+					#   error
+
+#log_min_messages = warning		# values in order of decreasing detail:
+					#   debug5
+					#   debug4
+					#   debug3
+					#   debug2
+					#   debug1
+					#   info
+					#   notice
+					#   warning
+					#   error
+					#   log
+					#   fatal
+					#   panic
+
+#log_min_error_statement = error	# values in order of decreasing detail:
+				 	#   debug5
+					#   debug4
+					#   debug3
+					#   debug2
+					#   debug1
+				 	#   info
+					#   notice
+					#   warning
+					#   error
+					#   log
+					#   fatal
+					#   panic (effectively off)
+
+#log_min_duration_statement = -1	# -1 is disabled, 0 logs all statements
+					# and their durations, > 0 logs only
+					# statements running at least this number
+					# of milliseconds
+
+
+# - What to Log -
+
+#debug_print_parse = off
+#debug_print_rewritten = off
+#debug_print_plan = off
+#debug_pretty_print = on
+#log_checkpoints = off
+#log_connections = off
+#log_disconnections = off
+#log_duration = off
+#log_error_verbosity = default		# terse, default, or verbose messages
+#log_hostname = off
+log_line_prefix = '%t '			# special values:
+					#   %a = application name
+					#   %u = user name
+					#   %d = database name
+					#   %r = remote host and port
+					#   %h = remote host
+					#   %p = process ID
+					#   %t = timestamp without milliseconds
+					#   %m = timestamp with milliseconds
+					#   %i = command tag
+					#   %e = SQL state
+					#   %c = session ID
+					#   %l = session line number
+					#   %s = session start timestamp
+					#   %v = virtual transaction ID
+					#   %x = transaction ID (0 if none)
+					#   %q = stop here in non-session
+					#        processes
+					#   %% = '%'
+					# e.g. '<%u%%%d> '
+#log_lock_waits = off			# log lock waits >= deadlock_timeout
+#log_statement = 'none'			# none, ddl, mod, all
+#log_temp_files = -1			# log temporary files equal or larger
+					# than the specified size in kilobytes;
+					# -1 disables, 0 logs all temp files
+#log_timezone = '(defaults to server environment setting)'
+
+
+#------------------------------------------------------------------------------
+# RUNTIME STATISTICS
+#------------------------------------------------------------------------------
+
+# - Query/Index Statistics Collector -
+
+#track_activities = on
+#track_counts = on
+#track_functions = none			# none, pl, all
+#track_activity_query_size = 1024 	# (change requires restart)
+#update_process_title = on
+#stats_temp_directory = 'pg_stat_tmp'
+
+
+# - Statistics Monitoring -
+
+#log_parser_stats = off
+#log_planner_stats = off
+#log_executor_stats = off
+#log_statement_stats = off
+
+
+#------------------------------------------------------------------------------
+# AUTOVACUUM PARAMETERS
+#------------------------------------------------------------------------------
+
+#autovacuum = on			# Enable autovacuum subprocess?  'on'
+					# requires track_counts to also be on.
+#log_autovacuum_min_duration = -1	# -1 disables, 0 logs all actions and
+					# their durations, > 0 logs only
+					# actions running at least this number
+					# of milliseconds.
+#autovacuum_max_workers = 3		# max number of autovacuum subprocesses
+					# (change requires restart)
+#autovacuum_naptime = 1min		# time between autovacuum runs
+#autovacuum_vacuum_threshold = 50	# min number of row updates before
+					# vacuum
+#autovacuum_analyze_threshold = 50	# min number of row updates before
+					# analyze
+#autovacuum_vacuum_scale_factor = 0.2	# fraction of table size before vacuum
+#autovacuum_analyze_scale_factor = 0.1	# fraction of table size before analyze
+#autovacuum_freeze_max_age = 200000000	# maximum XID age before forced vacuum
+					# (change requires restart)
+#autovacuum_vacuum_cost_delay = 20ms	# default vacuum cost delay for
+					# autovacuum, in milliseconds;
+					# -1 means use vacuum_cost_delay
+#autovacuum_vacuum_cost_limit = -1	# default vacuum cost limit for
+					# autovacuum, -1 means use
+					# vacuum_cost_limit
+
+
+#------------------------------------------------------------------------------
+# CLIENT CONNECTION DEFAULTS
+#------------------------------------------------------------------------------
+
+# - Statement Behavior -
+
+#search_path = '"$user",public'		# schema names
+#default_tablespace = ''		# a tablespace name, '' uses the default
+#temp_tablespaces = ''			# a list of tablespace names, '' uses
+					# only default tablespace
+#check_function_bodies = on
+#default_transaction_isolation = 'read committed'
+#default_transaction_read_only = off
+#default_transaction_deferrable = off
+#session_replication_role = 'origin'
+#statement_timeout = 0			# in milliseconds, 0 is disabled
+#vacuum_freeze_min_age = 50000000
+#vacuum_freeze_table_age = 150000000
+#bytea_output = 'hex'			# hex, escape
+#xmlbinary = 'base64'
+#xmloption = 'content'
+
+# - Locale and Formatting -
+
+datestyle = 'iso, mdy'
+#intervalstyle = 'postgres'
+#timezone = '(defaults to server environment setting)'
+#timezone_abbreviations = 'Default'     # Select the set of available time zone
+					# abbreviations.  Currently, there are
+					#   Default
+					#   Australia
+					#   India
+					# You can create your own file in
+					# share/timezonesets/.
+#extra_float_digits = 0			# min -15, max 3
+#client_encoding = sql_ascii		# actually, defaults to database
+					# encoding
+
+# These settings are initialized by initdb, but they can be changed.
+lc_messages = 'en_US.UTF-8'			# locale for system error message
+					# strings
+lc_monetary = 'en_US.UTF-8'			# locale for monetary formatting
+lc_numeric = 'en_US.UTF-8'			# locale for number formatting
+lc_time = 'en_US.UTF-8'				# locale for time formatting
+
+# default configuration for text search
+default_text_search_config = 'pg_catalog.english'
+
+# - Other Defaults -
+
+#dynamic_library_path = '$libdir'
+#local_preload_libraries = ''
+
+
+#------------------------------------------------------------------------------
+# LOCK MANAGEMENT
+#------------------------------------------------------------------------------
+
+#deadlock_timeout = 1s
+#max_locks_per_transaction = 64		# min 10
+					# (change requires restart)
+# Note:  Each lock table slot uses ~270 bytes of shared memory, and there are
+# max_locks_per_transaction * (max_connections + max_prepared_transactions)
+# lock table slots.
+#max_pred_locks_per_transaction = 64	# min 10
+					# (change requires restart)
+
+#------------------------------------------------------------------------------
+# VERSION/PLATFORM COMPATIBILITY
+#------------------------------------------------------------------------------
+
+# - Previous PostgreSQL Versions -
+
+#array_nulls = on
+#backslash_quote = safe_encoding	# on, off, or safe_encoding
+#default_with_oids = off
+#escape_string_warning = on
+#lo_compat_privileges = off
+#quote_all_identifiers = off
+#sql_inheritance = on
+#standard_conforming_strings = on
+#synchronize_seqscans = on
+
+# - Other Platforms and Clients -
+
+#transform_null_equals = off
+
+
+#------------------------------------------------------------------------------
+# ERROR HANDLING
+#------------------------------------------------------------------------------
+
+#exit_on_error = off				# terminate session on any error?
+#restart_after_crash = on			# reinitialize after backend crash?
+
+
+#------------------------------------------------------------------------------
+# CUSTOMIZED OPTIONS
+#------------------------------------------------------------------------------
+
+#custom_variable_classes = ''		# list of custom variable class names

+ 34 - 0
cowboy/README.md

@@ -0,0 +1,34 @@
+# Cowboy Benchmarking Test
+
+This is the Cowboy portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
+
+### JSON Encoding Test
+
+* [JSON test controller](src/json_handler.erl)
+
+
+### Data-Store/Database Mapping Test
+Uses the db abstraction class from Kohana
+
+* [DB test controller](src/db_handler.erl)
+
+
+## Infrastructure Software Versions
+The tests were run with:
+
+* [Cowboy 0.8.3](https://github.com/extend/cowboy)
+* [Erlang R16B](http://www.erlang.org/)
+* [MySQL 5.5.29](https://dev.mysql.com/)
+
+## Test URLs
+### JSON Encoding Test
+
+http://localhost/json
+
+### Data-Store/Database Mapping Test
+
+http://localhost/db
+
+### Variable Query Test
+    
+http://localhost/db?queries=2

+ 24 - 0
dancer/README.md

@@ -0,0 +1,24 @@
+# Setup
+
+* Perl 5.16.3
+* MySQL 5.5
+* Wrk 2.0
+
+# Requirements
+
+* Dancer
+* Dancer::Plugin::Database
+* DBD::mysql
+* Starman (if using Starman as web server)
+* Plack (for plackup)
+* nginx (if you want to front Dancer with nginx, nginx.conf provided)
+
+# Deployment
+
+Something along the lines of
+
+    plackup -E production -s Starman --workers=2 -l /tmp/frameworks-benchmark.sock -a ./app.pl
+
+if you want to front it with nginx, otherwise
+
+    plackup -E production -s Starman --port=8080 --workers=2 -a ./app.pl

+ 0 - 0
dancer/__init__.py


+ 32 - 0
dancer/app.pl

@@ -0,0 +1,32 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+
+use Dancer ':syntax';
+use DBI;
+
+set serializer => 'JSON';
+
+my $dsn = "dbi:mysql:database=hello_world;host=localhost;port=3306";
+my $dbh = DBI->connect( $dsn, 'benchmarkdbuser', 'benchmarkdbpass', {} );
+my $sth = $dbh->prepare("SELECT * FROM World where id = ?");
+
+get '/json' => sub {
+    { message => 'Hello, World!' }
+};
+
+get '/db' => sub {
+    my $queries = params->{queries} || 1;
+    my @response;
+    for ( 1 .. $queries ) {
+        my $id = int rand 10000 + 1;
+        $sth->execute($id);
+        if ( my $row = $sth->fetchrow_hashref ) {
+            push @response,
+              { id => $id, randomNumber => $row->{randomNumber} };
+        }
+    }
+    return \@response;
+};
+
+Dancer->dance;

+ 18 - 0
dancer/benchmark_config

@@ -0,0 +1,18 @@
+{
+  "framework": "dancer",
+  "tests": [{
+    "default": {
+      "setup_file": "setup",
+      "json_url": "/json",
+      "port": 8080,
+      "sort": 76
+    },
+    "raw": {
+      "setup_file": "setup",
+      "db_url": "/db",
+      "query_url": "/db?queries=",
+      "port": 8080,
+      "sort": 77
+    }
+  }]
+}

+ 37 - 0
dancer/nginx.conf

@@ -0,0 +1,37 @@
+user USR;
+
+worker_processes 2;
+
+events {
+  worker_connections  1024;
+}
+
+http {
+  output_buffers   1 32k;
+  postpone_output  1460;
+
+  sendfile         on;
+  tcp_nopush       on;
+
+  tcp_nodelay      on;
+
+  upstream backendurl {
+    server unix:/home/ubuntu/FrameworkBenchmarks/dancer/frameworks-benchmark.sock;
+  }
+
+  server {
+    listen 8080;
+    server_name localhost;
+
+    location / {
+      try_files $uri @proxy;
+      access_log off;
+      expires max;
+    }
+
+    location @proxy {
+      proxy_set_header Host $http_host;
+      proxy_pass http://backendurl;
+    }
+  }
+}

+ 32 - 0
dancer/setup.py

@@ -0,0 +1,32 @@
+import subprocess
+import sys
+import setup_util
+from os.path import expanduser
+import os
+import getpass
+
+home = expanduser("~")
+
+def start(args):
+  setup_util.replace_text("dancer/app.pl", "localhost", ""+ args.database_host +"")
+  setup_util.replace_text("dancer/nginx.conf", "USR", getpass.getuser())
+  setup_util.replace_text("dancer/nginx.conf", "server unix:.*\/FrameworkBenchmarks", "server unix:" + home + "/FrameworkBenchmarks")
+
+  try:
+    subprocess.Popen("plackup -E production -s Starman --workers=" + str(args.max_threads) + " -l " + home + "/FrameworkBenchmarks/dancer/frameworks-benchmark.sock -a ./app.pl", shell=True, cwd="dancer")
+    subprocess.check_call("sudo /usr/local/nginx/sbin/nginx -c " + home + "/FrameworkBenchmarks/dancer/nginx.conf", shell=True)
+    return 0
+  except subprocess.CalledProcessError:
+    return 1
+def stop():
+  try:
+    subprocess.call("sudo /usr/local/nginx/sbin/nginx -s stop", shell=True)
+    p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
+    out, err = p.communicate()
+    for line in out.splitlines():
+      if 'starman' in line:
+        pid = int(line.split(None, 2)[1])
+        os.kill(pid, 9)
+    return 0
+  except subprocess.CalledProcessError:
+    return 1

+ 2 - 2
django-stripped/hello/world/views.py

@@ -4,14 +4,14 @@ from django.template import Context, loader
 from django.http import HttpResponse
 from django.core import serializers
 from world.models import World
-import simplejson
+import ujson
 import random
 
 def json(request):
   response = {
     "message": "Hello, World!"
   }
-  return HttpResponse(simplejson.dumps(response), mimetype="application/json")
+  return HttpResponse(ujson.dumps(response), mimetype="application/json")
 
 def db(request):
   queries = int(request.GET.get('queries', 1))

+ 1 - 1
django-stripped/setup.py

@@ -7,7 +7,7 @@ import os
 def start(args):
   setup_util.replace_text("django-stripped/hello/hello/settings.py", "HOST': '.*'", "HOST': '" + args.database_host + "'")
 
-  subprocess.Popen("gunicorn hello.wsgi:application -k gevent -b 0.0.0.0:8080 -w " + str((args.max_threads * 2)) + " --log-level=critical", shell=True, cwd="django-stripped/hello")
+  subprocess.Popen("gunicorn hello.wsgi:application --worker-class=\"egg:meinheld#gunicorn_worker\" -b 0.0.0.0:8080 -w " + str((args.max_threads * 2)) + " --log-level=critical", shell=True, cwd="django-stripped/hello")
   return 0
 def stop():
   p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)

+ 2 - 1
django/benchmark_config

@@ -6,8 +6,9 @@
       "json_url": "/json",
       "db_url": "/db",
       "query_url": "/db?queries=",
+      "fortune_url": "/fortunes",
       "port": 8080,
       "sort": 3
     }
   }]
-}
+}

+ 2 - 1
django/hello/hello/settings.py

@@ -11,12 +11,13 @@ MANAGERS = ADMINS
 
 DATABASES = {
     'default': {
-        'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
+        'ENGINE': 'django_psycopg2_pool.gevent', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
         'NAME': 'hello_world',                      # Or path to database file if using sqlite3.
         'USER': 'benchmarkdbuser',                      # Not used with sqlite3.
         'PASSWORD': 'benchmarkdbpass',                  # Not used with sqlite3.
         'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
         'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
+	'POOL_SIZE' : 32,
     }
 }
 

+ 1 - 0
django/hello/hello/urls.py

@@ -16,4 +16,5 @@ urlpatterns = patterns('',
     # url(r'^admin/', include(admin.site.urls)),
     url(r'^json$', 'world.views.json'),
     url(r'^db$', 'world.views.db'),
+    url(r'^fortunes$', 'world.views.fortunes'),
 )

+ 1 - 4
django/hello/templates/base.html

@@ -2,10 +2,7 @@
 <html>
 <head>
 </head>
-
 <body>
-  <div id="content">
-    {% block content %}{% endblock %}
-  </div>
+  {% block content %}{% endblock %}
 </body>
 </html>

+ 16 - 0
django/hello/templates/fortunes.html

@@ -0,0 +1,16 @@
+{% extends "base.html" %}
+
+{% block content %}
+<table>
+<tr>
+<th>id</th>
+<th>message</th>
+</tr>
+{% for fortune in fortunes %}
+<tr>
+<td>{{ fortune.id }}</td>
+<td>{{ fortune.message }}</td>
+</tr>
+{% endfor %}
+</table>
+{% endblock %}

+ 6 - 2
django/hello/world/models.py

@@ -3,7 +3,11 @@ from django.db import models
 # Create your models here.
 
 class World(models.Model):
-  randomNumber = models.IntegerField()
+  randomnumber = models.IntegerField()
   class Meta:
-    db_table = 'World'
+    db_table = 'world'
 
+class Fortune(models.Model):
+  message = models.CharField()
+  class Meta:
+    db_table = 'fortune'

+ 13 - 3
django/hello/world/views.py

@@ -3,15 +3,17 @@
 from django.template import Context, loader
 from django.http import HttpResponse
 from django.core import serializers
-from world.models import World
-import simplejson
+from world.models import World, Fortune
+from django.shortcuts import render
+import ujson
 import random
+from operator import attrgetter
 
 def json(request):
   response = {
     "message": "Hello, World!"
   }
-  return HttpResponse(simplejson.dumps(response), mimetype="application/json")
+  return HttpResponse(ujson.dumps(response), mimetype="application/json")
 
 def db(request):
   queries = int(request.GET.get('queries', 1))
@@ -23,3 +25,11 @@ def db(request):
 
   return HttpResponse(serializers.serialize("json", worlds), mimetype="application/json")
 
+def fortunes(request):
+  fortunes = list(Fortune.objects.all())
+  fortunes.append(Fortune(id=0, message="Additional message added at runtime."))
+
+  fortunes = sorted(fortunes, key=attrgetter('message'))
+
+  context = {'fortunes': fortunes}
+  return render(request, 'fortunes.html', context)

+ 5 - 1
django/setup.py

@@ -2,10 +2,14 @@ import subprocess
 import sys
 import setup_util
 import os
+from os.path import expanduser
+
+home = expanduser("~")
 
 def start(args):
   setup_util.replace_text("django/hello/hello/settings.py", "HOST': '.*'", "HOST': '" + args.database_host + "'")
-  subprocess.Popen("gunicorn hello.wsgi:application -k gevent  -b 0.0.0.0:8080 -w " + str((args.max_threads * 2)) + " --log-level=critical", shell=True, cwd="django/hello")
+  setup_util.replace_text("django/hello/hello/settings.py", "\/home\/ubuntu",  home)
+  subprocess.Popen("gunicorn hello.wsgi:application --worker-class=\"egg:meinheld#gunicorn_worker\"  -b 0.0.0.0:8080 -w " + str((args.max_threads * 2)) + " --log-level=critical", shell=True, cwd="django/hello")
   return 0
 def stop():
   p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)

+ 0 - 0
dropwizard/__init__.py


+ 13 - 0
dropwizard/benchmark_config

@@ -0,0 +1,13 @@
+{
+    "framework": "dropwizard",
+    "tests": [{
+        "default": {
+            "setup_file": "setup",
+            "json_url": "/json",
+            "db_url": "/db",
+            "query_url": "/db?queries=",
+            "port": 9000,
+            "sort": 69
+        }
+    }]
+}

+ 58 - 0
dropwizard/hello-world.yml

@@ -0,0 +1,58 @@
+http:
+  port: 9000
+
+  requestLog:
+
+    # Settings for logging to stdout.
+    console:
+      # If true, log requests to stdout.
+      enabled: false
+
+database:
+  # the name of your JDBC driver
+  driverClass: com.mysql.jdbc.Driver
+
+  # the username
+  user: benchmarkdbuser
+
+  # the password
+  password: benchmarkdbpass
+
+  # the JDBC URL
+  url: jdbc:mysql://localhost:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts&cacheRSMetadata=true
+
+  # any properties specific to your JDBC driver:
+  properties:
+    charSet: UTF-8
+
+  # the maximum amount of time to wait on an empty pool before throwing an exception
+  maxWaitForConnection: 1s
+
+  # the SQL query to run when validating a connection's liveness
+  validationQuery: "/* MyService Health Check */ SELECT 1"
+
+  # the minimum number of connections to keep open
+  minSize: 8
+
+  # the maximum number of connections to keep open
+  maxSize: 256
+
+  # whether or not idle connections should be validated
+  checkConnectionWhileIdle: false
+
+  # how long a connection must be held before it can be validated
+  checkConnectionHealthWhenIdleFor: 10s
+
+  # the maximum lifetime of an idle connection
+  closeConnectionIfIdleFor: 1 minute
+
+logging:
+
+  # The default level of all loggers. Can be OFF, ERROR, WARN, INFO, DEBUG, TRACE, or ALL.
+  level: OFF
+
+  console:
+
+    # If true, write log statements to stdout.
+    enabled: false
+

+ 88 - 0
dropwizard/pom.xml

@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.xekm</groupId>
+    <artifactId>hello-world</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.yammer.dropwizard</groupId>
+            <artifactId>dropwizard-core</artifactId>
+            <version>0.6.2</version>
+        </dependency>
+        <dependency>
+            <groupId>com.yammer.dropwizard</groupId>
+            <artifactId>dropwizard-hibernate</artifactId>
+            <version>0.6.2</version>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <version>5.1.6</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>2.3.2</version>
+                <configuration>
+                    <source>1.7</source>
+                    <target>1.7</target>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>2.3.2</version>
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
+                        </manifest>
+                    </archive>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <version>1.6</version>
+                <configuration>
+                    <createDependencyReducedPom>true</createDependencyReducedPom>
+                    <filters>
+                        <filter>
+                            <artifact>*:*</artifact>
+                            <excludes>
+                                <exclude>META-INF/*.SF</exclude>
+                                <exclude>META-INF/*.DSA</exclude>
+                                <exclude>META-INF/*.RSA</exclude>
+                            </excludes>
+                        </filter>
+                    </filters>
+                </configuration>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <configuration>
+                            <transformers>
+                                <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
+                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+                                    <mainClass>com.example.helloworld.HelloWorldService</mainClass>
+                                </transformer>
+                            </transformers>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 25 - 0
dropwizard/setup.py

@@ -0,0 +1,25 @@
+import subprocess
+import sys
+import setup_util
+from os.path import expanduser
+import os
+
+home = expanduser("~")
+
+def start(args):
+    setup_util.replace_text("dropwizard/hello-world.yml", "url: jdbc:mysql://.*/hello_world", "url: jdbc:mysql://" + args.database_host + ":3306/hello_world")
+
+    try:
+        subprocess.check_call("mvn clean package;", shell=True, cwd="dropwizard")
+        subprocess.Popen("java -jar target/hello-world-0.0.1-SNAPSHOT.jar server hello-world.yml", shell=True, cwd="dropwizard")
+        return 0
+    except subprocess.CalledProcessError:
+        return 1
+def stop():
+  p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
+  out, err = p.communicate()
+  for line in out.splitlines():
+    if 'hello-world' in line:
+      pid = int(line.split(None, 2)[1])
+      os.kill(pid, 9)
+  return 0

+ 25 - 0
dropwizard/src/main/java/com/example/helloworld/HelloWorldConfiguration.java

@@ -0,0 +1,25 @@
+
+package com.example.helloworld;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+
+import org.hibernate.validator.constraints.NotEmpty;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.yammer.dropwizard.config.Configuration;
+import com.yammer.dropwizard.db.DatabaseConfiguration;
+
+public class HelloWorldConfiguration
+    extends Configuration
+{
+  @Valid
+  @NotNull
+  @JsonProperty
+  private DatabaseConfiguration database    = new DatabaseConfiguration();
+
+  public DatabaseConfiguration getDatabaseConfiguration()
+  {
+    return database;
+  }
+}

+ 48 - 0
dropwizard/src/main/java/com/example/helloworld/HelloWorldService.java

@@ -0,0 +1,48 @@
+
+package com.example.helloworld;
+
+import com.example.helloworld.core.World;
+import com.example.helloworld.db.WorldDAO;
+import com.example.helloworld.resources.JsonResource;
+import com.example.helloworld.resources.WorldResource;
+import com.yammer.dropwizard.Service;
+import com.yammer.dropwizard.config.Bootstrap;
+import com.yammer.dropwizard.config.Environment;
+import com.yammer.dropwizard.db.DatabaseConfiguration;
+import com.yammer.dropwizard.hibernate.HibernateBundle;
+
+public class HelloWorldService
+    extends Service<HelloWorldConfiguration>
+{
+  private final HibernateBundle<HelloWorldConfiguration> hibernate = new HibernateBundle<HelloWorldConfiguration>(
+                                                                       World.class)
+                                                                   {
+                                                                     @Override
+                                                                     public DatabaseConfiguration getDatabaseConfiguration(
+                                                                         HelloWorldConfiguration configuration)
+                                                                     {
+                                                                       return configuration.getDatabaseConfiguration();
+                                                                     }
+                                                                   };
+
+  public static void main(String[] args) throws Exception
+  {
+    new HelloWorldService().run(args);
+  }
+
+  @Override
+  public void initialize(Bootstrap<HelloWorldConfiguration> bootstrap)
+  {
+    bootstrap.setName("hello-world");
+    bootstrap.addBundle(hibernate);
+  }
+
+  @Override
+  public void run(HelloWorldConfiguration config, Environment environment)
+  {
+    final WorldDAO dao = new WorldDAO(hibernate.getSessionFactory());
+    environment.addResource(new WorldResource(dao));
+    environment.addResource(new JsonResource());
+  }
+
+}

+ 36 - 0
dropwizard/src/main/java/com/example/helloworld/core/World.java

@@ -0,0 +1,36 @@
+
+package com.example.helloworld.core;
+
+import javax.persistence.*;
+
+@Entity
+@Table(name = "World")
+public class World
+{
+  @Id
+  @GeneratedValue(strategy = GenerationType.AUTO)
+  private long id;
+
+  @Column(name = "randomNumber", nullable = false)
+  private long randomNumber;
+
+  public long getId()
+  {
+    return id;
+  }
+
+  public void setId(long id)
+  {
+    this.id = id;
+  }
+
+  public long getRandomNumber()
+  {
+    return this.randomNumber;
+  }
+
+  public void setRandomNumber(long randomNumber)
+  {
+    this.randomNumber = randomNumber;
+  }
+}

+ 22 - 0
dropwizard/src/main/java/com/example/helloworld/db/WorldDAO.java

@@ -0,0 +1,22 @@
+
+package com.example.helloworld.db;
+
+import org.hibernate.SessionFactory;
+
+import com.example.helloworld.core.World;
+import com.google.common.base.Optional;
+import com.yammer.dropwizard.hibernate.AbstractDAO;
+
+public class WorldDAO
+    extends AbstractDAO<World>
+{
+  public WorldDAO(SessionFactory factory)
+  {
+    super(factory);
+  }
+
+  public Optional<World> findById(Long id)
+  {
+    return Optional.fromNullable(get(id));
+  }
+}

+ 28 - 0
dropwizard/src/main/java/com/example/helloworld/resources/JsonResource.java

@@ -0,0 +1,28 @@
+
+package com.example.helloworld.resources;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+@Path("/json")
+@Produces(MediaType.APPLICATION_JSON)
+public class JsonResource
+{
+  private final Map<String, String> MESSAGE = new HashMap<String, String>();
+
+  public JsonResource()
+  {
+    MESSAGE.put("message", "Hello, world!");
+  }
+
+  @GET
+  public Map<String, String> sayHello()
+  {
+    return MESSAGE;
+  }
+}

+ 42 - 0
dropwizard/src/main/java/com/example/helloworld/resources/WorldResource.java

@@ -0,0 +1,42 @@
+
+package com.example.helloworld.resources;
+
+import java.util.Random;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+
+import com.example.helloworld.core.World;
+import com.example.helloworld.db.WorldDAO;
+import com.google.common.base.Optional;
+import com.yammer.dropwizard.hibernate.UnitOfWork;
+
+@Path("/db")
+@Produces(MediaType.APPLICATION_JSON)
+public class WorldResource
+{
+  private WorldDAO worldDAO = null;
+
+  public WorldResource(WorldDAO worldDAO)
+  {
+    this.worldDAO = worldDAO;
+  }
+
+  @GET
+  @UnitOfWork
+  public World[] dbTest(@QueryParam("queries") Optional<Integer> queries)
+  {
+    final int totalQueries = queries.or(1);
+    final World[] worlds = new World[queries.or(1)];
+    final Random random = new Random(System.currentTimeMillis());
+
+    for (int i = 0; i < totalQueries; i++)
+    {
+      worlds[i] = this.worldDAO.findById((long)random.nextInt(10000)).orNull();
+    }
+    return worlds;
+  }
+}

+ 33 - 0
elli/README.md

@@ -0,0 +1,33 @@
+# Elli Benchmarking Test
+
+This is the Elli portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
+
+### JSON Encoding Test
+
+* [JSON test controller](src/elli_bench_cb.erl)
+
+
+### Data-Store/Database Mapping Test
+
+* [DB test controller](src/elli_bench_cb.erl)
+
+
+## Infrastructure Software Versions
+The tests were run with:
+
+* [Elli](git://github.com/knutin/elli)
+* [Erlang R16B](http://www.erlang.org/)
+* [MySQL 5.5.29](https://dev.mysql.com/)
+
+## Test URLs
+### JSON Encoding Test
+
+http://localhost/json
+
+### Data-Store/Database Mapping Test
+
+http://localhost/db
+
+### Variable Query Test
+    
+http://localhost/db?queries=2

+ 23 - 1
express/app.js

@@ -21,6 +21,11 @@ var cluster = require('cluster')
     randomNumber: Sequelize.INTEGER
   }, {
     freezeTableName: true
+  })
+  , Fortune      = sequelize.define('Fortune', {
+    message: Sequelize.STRING
+  }, {
+    freezeTableName: true
   });
 
 var Schema = mongoose.Schema
@@ -50,6 +55,9 @@ if (cluster.isMaster) {
     app.use(express.bodyParser());
     app.use(express.methodOverride());
     app.use(app.router);
+
+    app.set('view engine', 'jade');
+    app.set('views', __dirname + '/views');
   });
 
   app.configure('development', function() {
@@ -104,5 +112,19 @@ if (cluster.isMaster) {
     });
   });
 
+  app.get('/fortune', function(req, res) {
+    Fortune.findAll().success(function (fortunes) {
+      var newFortune = Fortune.build({message: "Additional fortune added at request time."});
+      fortunes.push(newFortune);
+      fortunes.sort(sortFortunes);
+
+      res.render('fortunes', {fortunes: fortunes});
+    });
+  });
+
+  function sortFortunes(a, b) {
+    return (a.message < b.message) ? -1 : (a.message > b.message) ? 1 : 0;
+  }
+
   app.listen(8080);
-}
+}

+ 2 - 1
express/benchmark_config

@@ -18,8 +18,9 @@
       "setup_file": "setup",
       "db_url": "/sequelize",
       "query_url": "/sequelize?queries=",
+      "fortune_url": "/fortune",
       "port": 8080,
       "sort": 6
     }
   }]
-}
+}

+ 2 - 1
express/package.json

@@ -8,5 +8,6 @@
     , "async": "0.2.5"
     , "sequelize": "1.6.0-beta4"
     , "mysql": "2.0.0-alpha7"
+    , "jade": "0.29.0"
   }
-}
+}

+ 20 - 0
express/views/fortune.mustache

@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Fortunes</title>
+</head>
+<body>
+<table>
+<tr>
+<th>id</th>
+<th>message</th>
+</tr>
+{{#fortunes}}
+<tr>
+<td>{{id}}</td>
+<td>{{message}}</td>
+</tr>
+{{/fortunes}}
+</table>
+</body>
+</html>

+ 11 - 0
express/views/fortunes/index.jade

@@ -0,0 +1,11 @@
+extends ../layout
+
+block content
+  table
+    tr
+      th id
+      th message
+    for fortune in fortunes
+      tr
+        td= fortune.id
+        td= fortune.message

+ 6 - 0
express/views/layout.jade

@@ -0,0 +1,6 @@
+!!! 5
+html
+  head
+    title Fortunes
+  body
+    block content

+ 11 - 7
finagle/src/main/scala/com/falmarri/finagle/Finagle.scala

@@ -12,7 +12,7 @@ import org.jboss.netty.handler.codec.http.HttpResponseStatus
 import com.fasterxml.jackson.databind.ObjectMapper
 import com.fasterxml.jackson.module.scala.DefaultScalaModule
 import scala.language.experimental.macros
-import scala.reflect.macros.Context
+//import scala.reflect.macros.Context
 import java.io.StringWriter
 import org.jboss.netty.util.CharsetUtil.UTF_8
 import scala.slick.driver.MySQLDriver.simple._
@@ -50,12 +50,12 @@ object FinagleBenchmark extends App {
     ds.setDriverClassName("com.mysql.jdbc.Driver")
     ds.setUsername("benchmarkdbuser")
     ds.setPassword("benchmarkdbpass")
-    ds.setMaxActive(20);
+    ds.setMaxActive(256);
     ds.setMaxIdle(10);
     ds.setInitialSize(20);
     //ds.setValidationQuery("SELECT 1 FROM INFORMATION_SCHEMA.SYSTEM_USERS")
     //new java.io.File("target").mkdirs // ensure that folder for database exists
-    ds.setUrl("jdbc:mysql://" + System.getProperty("db.host", "localhost") + ":3306/hello_world")
+    ds.setUrl("jdbc:mysql://" + System.getProperty("db.host", "localhost") + ":3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts&cacheRSMetadata=true")
     ds
   }
   
@@ -89,8 +89,10 @@ object FinagleBenchmark extends App {
       val resp = Response()
       database withSession {implicit session: Session =>
         val rand = new Random()
-        val q = Query(Worlds).where(_.id inSet( for (i <- 0 to n) yield rand.nextInt(10000)))
-        resp.setContent(copiedBuffer(serialize(if (n == 1) q.first else q.list), UTF_8))
+        val q = (0 until n).map { _ =>
+          Query(Worlds).where(_.id > rand.nextInt(10000)).first
+        }
+        resp.setContent(copiedBuffer(serialize(q), UTF_8))
         resp.setContentTypeJson
         Future.value(resp)
       }
@@ -104,8 +106,10 @@ object FinagleBenchmark extends App {
 	      val resp = Response()
 	      database withSession {implicit session: Session =>
 	        val rand = new Random()
-	        val q = Query(Worlds).where(_.id inSet( for (i <- 0 to n) yield rand.nextInt(10000)))
-	        resp.setContent(copiedBuffer(serialize(if (n == 1) q.first else q.list), UTF_8))
+                val q = (0 until n).map { _ =>
+                  Query(Worlds).where(_.id > rand.nextInt(10000)).first
+                }
+                resp.setContent(copiedBuffer(serialize(q), UTF_8))
 	        resp.setContentTypeJson
 	        resp
 	      	}

+ 11 - 3
flask/README.md

@@ -10,8 +10,16 @@ http://localhost:8080/json
 
 ### Single Row Random Query
 
-http://localhost:8080/db
+With ORM:
+    http://localhost:8080/dbs
 
-### Variable Row Query Test
+Without ORM (raw):
+    http://localhost:8080/dbsraw
 
-http://localhost:8080/db?queries=2
+### Variable Row Query Test 
+
+With ORM:
+    http://localhost:8080/db?queries=2
+
+Without ORM (raw):
+    http://localhost:8080/dbraw?queries=2

+ 29 - 0
flask/app.py

@@ -1,10 +1,12 @@
 from flask import Flask, jsonify, request
 from flask.ext.sqlalchemy import SQLAlchemy
+from sqlalchemy import create_engine
 from random import randint
 
 app = Flask(__name__)
 app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://benchmarkdbuser:benchmarkdbpass@DBHOSTNAME:3306/hello_world'
 db = SQLAlchemy(app)
+dbraw_engine = create_engine(app.config['SQLALCHEMY_DATABASE_URI'])
 
 class World(db.Model):
   __tablename__ = "World"
@@ -33,6 +35,33 @@ def get_random_world():
     wid = randint(1, 10000)
     worlds.append(World.query.get(wid).serialize)
   return jsonify(worlds=worlds)
+
[email protected]("/dbs")
+def get_random_world_single():
+  wid = randint(1, 10000)
+  worlds = [World.query.get(wid).serialize]
+  return jsonify(worlds=worlds)
   
[email protected]("/dbraw")
+def get_random_world_raw():
+  connection = dbraw_engine.connect()
+  num_queries = request.args.get("queries", 1)
+  worlds = []
+  for i in range(int(num_queries)):
+    wid = randint(1, 10000)
+    result = connection.execute("SELECT * FROM world WHERE id = " + str(wid)).fetchone()
+    worlds.append({'id': result[0], 'randomNumber': result[1]})
+  connection.close()
+  return jsonify(worlds=worlds)
+
[email protected]("/dbsraw")
+def get_random_world_single_raw():
+  connection = dbraw_engine.connect()
+  wid = randint(1, 10000)
+  result = connection.execute("SELECT * FROM world WHERE id = " + str(wid)).fetchone()
+  worlds = [{'id': result[0], 'randomNumber': result[1]}]
+  connection.close()
+  return jsonify(worlds=worlds)
+
 if __name__ == "__main__":
     app.run()

+ 9 - 2
flask/benchmark_config

@@ -4,10 +4,17 @@
     "default": {
       "setup_file": "setup",
       "json_url": "/json",
-      "db_url": "/db",
+      "db_url": "/dbs",
       "query_url": "/db?queries=",
       "port": 8080,
       "sort": 31
+    },
+    "mysql-raw": {
+      "setup_file": "setup",
+      "db_url": "/dbsraw",
+      "query_url": "/dbraw?queries=",
+      "port": 8080,
+      "sort": 84
     }
   }]
-}
+}

+ 1 - 1
flask/setup.py

@@ -5,7 +5,7 @@ import os
 
 def start(args):
   setup_util.replace_text("flask/app.py", "DBHOSTNAME", args.database_host)
-  subprocess.Popen("gunicorn app:app -k gevent -b 0.0.0.0:8080 -w " + str((args.max_threads * 2)) + " --preload --log-level=critical", shell=True, cwd="flask")
+  subprocess.Popen("gunicorn app:app --worker-class=\"egg:meinheld#gunicorn_worker\" -b 0.0.0.0:8080 -w " + str((args.max_threads * 2)) + " --preload --log-level=critical", shell=True, cwd="flask")
   
   return 0
 

+ 90 - 6
framework_test.py

@@ -141,10 +141,43 @@ class FrameworkTest:
       self.query_url_passed = True
     except (AttributeError, subprocess.CalledProcessError) as e:
       self.query_url_passed = False
+
+    # Fortune
+    try:
+      print "VERIFYING Fortune (" + self.fortune_url + ") ..."
+      url = self.benchmarker.generate_url(self.fortune_url, self.port)
+      subprocess.check_call(["curl", "-f", url])
+      print ""
+      self.fortune_url_passed = True
+    except (AttributeError, subprocess.CalledProcessError) as e:
+      self.fortune_url_passed = False
   ############################################################
   # End verify_urls
   ############################################################
 
+  ############################################################
+  # contains_type(type)
+  # true if this test contains an implementation of the given 
+  # test type (json, db, etc.)
+  ############################################################
+  def contains_type(self, type):
+    try:
+      if type == 'json' and self.json_url != None:
+        return True
+      if type == 'db' and self.db_url != None:
+        return True
+      if type == 'query' and self.query_url != None:
+        return True
+      if type == 'fortune' and self.fortune_url != None:
+        return True
+    except AttributeError:
+      pass
+      
+    return False
+  ############################################################
+  # End stop
+  ############################################################
+
   ############################################################
   # benchmark
   # Runs the benchmark for each type of test that it implements
@@ -159,7 +192,7 @@ class FrameworkTest:
         self.__run_benchmark(remote_script, self.benchmarker.output_file(self.name, 'json'))
         results = self.__parse_test('json')
         self.benchmarker.report_results(framework=self, test="json", requests=results['requests'], latency=results['latency'],
-          results=results['results'], total_time=results['total_time'])
+          results=results['results'], total_time=results['total_time'], errors=results['errors'], total_requests=results['totalRequests'])
 
         print "Complete"
     except AttributeError:
@@ -173,7 +206,7 @@ class FrameworkTest:
         self.__run_benchmark(remote_script, self.benchmarker.output_file(self.name, 'db'))
         results = self.__parse_test('db')
         self.benchmarker.report_results(framework=self, test="db", requests=results['requests'], latency=results['latency'],
-          results=results['results'], total_time=results['total_time'])
+          results=results['results'], total_time=results['total_time'], errors=results['errors'], total_requests=results['totalRequests'])
 
         print "Complete"
     except AttributeError:
@@ -187,7 +220,20 @@ class FrameworkTest:
         self.__run_benchmark(remote_script, self.benchmarker.output_file(self.name, 'query'))
         results = self.__parse_test('query')
         self.benchmarker.report_results(framework=self, test="query", requests=results['requests'], latency=results['latency'],
-          results=results['results'], total_time=results['total_time'])
+          results=results['results'], total_time=results['total_time'], errors=results['errors'], total_requests=results['totalRequests'])
+        print "Complete"
+    except AttributeError:
+      pass
+
+    # fortune
+    try:
+      if self.fortune_url_passed and (self.benchmarker.type == "all" or self.benchmarker.type == "fortune"):
+        sys.stdout.write("BENCHMARKING Fortune ... ") 
+        remote_script = self.__generate_concurrency_script(self.fortune_url, self.port)
+        self.__run_benchmark(remote_script, self.benchmarker.output_file(self.name, 'fortune'))
+        results = self.__parse_test('fortune')
+        self.benchmarker.report_results(framework=self, test="fortune", requests=results['requests'], latency=results['latency'],
+          results=results['results'], total_time=results['total_time'], errors=results['errors'], total_requests=results['totalRequests'])
         print "Complete"
     except AttributeError:
       pass
@@ -204,19 +250,25 @@ class FrameworkTest:
     if os.path.exists(self.benchmarker.output_file(self.name, 'json')):
       results = self.__parse_test('json')
       self.benchmarker.report_results(framework=self, test="json", requests=results['requests'], latency=results['latency'],
-        results=results['results'], total_time=results['total_time'])
+        results=results['results'], total_time=results['total_time'], errors=results['errors'], total_requests=results['totalRequests'])
     
     # DB
     if os.path.exists(self.benchmarker.output_file(self.name, 'db')):
       results = self.__parse_test('db')
       self.benchmarker.report_results(framework=self, test="db", requests=results['requests'], latency=results['latency'],
-        results=results['results'], total_time=results['total_time'])
+        results=results['results'], total_time=results['total_time'], errors=results['errors'], total_requests=results['totalRequests'])
     
     # Query
     if os.path.exists(self.benchmarker.output_file(self.name, 'query')):
       results = self.__parse_test('query')
       self.benchmarker.report_results(framework=self, test="query", requests=results['requests'], latency=results['latency'],
-        results=results['results'], total_time=results['total_time'])
+        results=results['results'], total_time=results['total_time'], errors=results['errors'], total_requests=results['totalRequests'])
+
+    # Query
+    if os.path.exists(self.benchmarker.output_file(self.name, 'fortune')):
+      results = self.__parse_test('fortune')
+      self.benchmarker.report_results(framework=self, test="fortune", requests=results['requests'], latency=results['latency'],
+        results=results['results'], total_time=results['total_time'], errors=results['errors'], total_requests=results['totalRequests'])
   ############################################################
   # End parse_all
   ############################################################
@@ -229,6 +281,7 @@ class FrameworkTest:
       results = dict()
       results['results'] = []
       results['total_time'] = 0
+      results['totalRequests'] = 0
       results['latency'] = dict()
       results['latency']['avg'] = 0
       results['latency']['stdev'] = 0
@@ -239,6 +292,12 @@ class FrameworkTest:
       results['requests']['stdev'] = 0
       results['requests']['max'] = 0
       results['requests']['stdevPercent'] = 0
+      results['errors'] = dict()
+      results['errors']['connect'] = 0
+      results['errors']['read'] = 0
+      results['errors']['write'] = 0
+      results['errors']['timeout'] = 0
+      results['errors']['5xx'] = 0
       with open(self.benchmarker.output_file(self.name, test_type)) as raw_data:
         is_warmup = False
         for line in raw_data:
@@ -285,6 +344,31 @@ class FrameworkTest:
                   results['total_time'] += float(raw_time[:len(raw_time)-1]) * 60.0
                 elif "h" in raw_time:
                   results['total_time'] += float(raw_time[:len(raw_time)-1]) * 3600.0
+           
+            if "requests in" in line:
+              m = re.search("([0-9]+) requests in", line)
+              if m != None: 
+                results['totalRequests'] += int(m.group(1))
+            
+            if "Socket errors" in line:
+              if "connect" in line:
+                m = re.search("connect ([0-9]+)", line)
+                results['errors']['connect'] += int(m.group(1))
+              if "read" in line:
+                m = re.search("read ([0-9]+)", line)
+                results['errors']['read'] += int(m.group(1))
+              if "write" in line:
+                m = re.search("write ([0-9]+)", line)
+                results['errors']['write'] += int(m.group(1))
+              if "timeout" in line:
+                m = re.search("timeout ([0-9]+)", line)
+                results['errors']['timeout'] += int(m.group(1))
+            
+            if "Non-2xx" in line:
+              m = re.search("Non-2xx or 3xx responses: ([0-9]+)", line)
+              if m != None: 
+                results['errors']['5xx'] += int(m.group(1))
+              
 
       return results
     except IOError:

+ 3 - 1
gemini/.classpath

@@ -5,9 +5,11 @@
 	<classpathentry kind="lib" path="Docroot/WEB-INF/lib/mail.jar"/>
 	<classpathentry kind="lib" path="Docroot/WEB-INF/lib/kryonet-1.04-all.jar"/>
 	<classpathentry kind="src" path="Source"/>
-	<classpathentry kind="lib" path="Docroot/WEB-INF/lib/techempower.jar"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
 	<classpathentry kind="var" path="Resin4Jee"/>
 	<classpathentry kind="lib" path="Docroot/WEB-INF/lib/mysql-connector-java-5.1.23-bin.jar"/>
+	<classpathentry kind="lib" path="Docroot/WEB-INF/lib/gemini-1.3.6.jar"/>
+	<classpathentry kind="lib" path="Docroot/WEB-INF/lib/guava-14.0.1.jar"/>
+	<classpathentry kind="lib" path="Docroot/WEB-INF/lib/trove4j-3.0.3.jar"/>
 	<classpathentry kind="output" path="Docroot/WEB-INF/classes"/>
 </classpath>

+ 1 - 1
gemini/.project

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <projectDescription>
-	<name>GeminiHello</name>
+	<name>FrameworkBenchmarks-Gemini</name>
 	<comment></comment>
 	<projects>
 		<project>TechEmpower</project>

+ 0 - 15
gemini/Docroot/WEB-INF/GeminiHello-Base.conf

@@ -414,21 +414,6 @@ MailServerCount = 1
 
 EmailerThreadsDaemon = yes
 
-# StartupMailAuthor
-#   Specifies the email address to use when sending out the startup
-#   email.  This just needs to be specified so that the mail server
-#   won't reject it due to anti-spam measures.
-
-StartupMailAuthor = [email protected]
-
-# StartupMailRecipients
-#   When this Gemini application starts, Gemini will send an e-mail notice
-#   to the provided comma-separated list of recipients.  This notice can
-#   be useful for tracking when the site has been restarted.  If set to
-#   empty string, this functionality is disabled.
-
-StartupMailRecipients =
-
 # Mail Server blocks (where 'X' is a sequential ID of the mail servers
 # used by the application).
 #

+ 0 - 7
gemini/Docroot/WEB-INF/GeminiHello-Dev.conf

@@ -10,9 +10,6 @@
 # Extend the baseline configuration.
 Extends = GeminiHello-Base.conf
 
-# TODO: Edit these settings according to the particulars of the
-# Development environments.
-
 DeploymentDescription = Development/${Servlet.MachineName}
 
 # Database connectivity for Development.
@@ -23,8 +20,4 @@ db.LoginPass = root
 # Disable outbound e-mail from the Development environment.
 OutboundMailEnabled = no
 
-# You may want to disable the last login update on Development.
-#BasicSecurity.UpdateLastLogin = no
-
-
 

+ 5 - 3
gemini/Docroot/WEB-INF/GeminiHello-Inverness.conf

@@ -9,7 +9,9 @@
 
 # Extend the development configuration, which in turn extends the
 # baseline configuration.
-Extends = GeminiHello-Dev.conf
+Extends = GeminiHello-Prod.conf
+
+DeploymentDescription = Production/${Servlet.MachineName}
 
 # Now set any attributes that are specific to this machine.
 
@@ -18,5 +20,5 @@ db.ConnectString = 172.16.98.98:3306/hello_world?jdbcCompliantTruncation=false&e
 Log.Console.On = yes
 Log.Console.LogDebugThreshold = 50
 
-#db.Driver.Pooling = 30
-#db.Driver.MaxPooling = 30
+db.Driver.Pooling = 30
+db.Driver.MaxPooling = 30

+ 2 - 16
gemini/Docroot/WEB-INF/GeminiHello-Prod.conf

@@ -10,9 +10,6 @@
 # Extend the baseline configuration.
 Extends = GeminiHello-Base.conf
 
-# TODO: Edit these settings according to the particulars of the
-# Production environment.
-
 DeploymentDescription = Production/${Servlet.MachineName}
 
 # Database connectivity for Production.
@@ -20,19 +17,8 @@ db.ConnectString = localhost:3306/gemini?jdbcCompliantTruncation=false&cachePrep
 db.LoginName = hello
 db.LoginPass = hello
 
-# Mail server definition for the production environment.  TODO: Most
-# likely you shouldn't be using the TechEmpower mail server in 
-# Production, so change this.
-MailServerCount = 1
-MailServer1.ServerAddress = mail.techempower.com
-MailServer1.SmtpPort = 25
-MailServer1.PopPort = 110
-MailServer1.Username = mhixson
-MailServer1.Password = password
-MailServer1.ServerRole = Outbound
-
-# In production, we'll want to have the email exception handler enabled.
-EmailExceptionHandler.Enabled = true
+# For this application, we are not sending any outbound e-mail.
+OutboundMailEnabled = no
 
 # In production, refer to all the static assets via URLs with version strings to
 # allow us to perform aggressive caching.

+ 1 - 16
gemini/Docroot/WEB-INF/GeminiHello.conf

@@ -76,7 +76,7 @@ ApplicationRoot = ${Servlet.ApplicationRoot}
 #   description is used to identify the installation in some system-
 #   generated messages such as exception report e-mails.
 
-DeploymentDescription = Unspecified
+DeploymentDescription = Production
 
 
 # -----------------------------------------------------------------------
@@ -413,21 +413,6 @@ MailServerCount = 1
 
 EmailerThreadsDaemon = yes
 
-# StartupMailAuthor
-#   Specifies the email address to use when sending out the startup
-#   email.  This just needs to be specified so that the mail server
-#   won't reject it due to anti-spam measures.
-
-StartupMailAuthor = [email protected]
-
-# StartupMailRecipients
-#   When this Gemini application starts, Gemini will send an e-mail notice
-#   to the provided comma-separated list of recipients.  This notice can
-#   be useful for tracking when the site has been restarted.  If set to
-#   empty string, this functionality is disabled.
-
-StartupMailRecipients =
-
 # Mail Server blocks (where 'X' is a sequential ID of the mail servers
 # used by the application).
 #

+ 0 - 79
gemini/Docroot/WEB-INF/access-error.jsp

@@ -1,79 +0,0 @@
-<%@ page import="com.techempower.gemini.*, com.techempower.gemini.filters.*" %><%
-
-Integer errorType = (Integer)request.getAttribute("ErrorType");
-
-int type = AccessFilter.ERROR_UNKNOWN;
-if (errorType != null)
-{
-  type = errorType.intValue();
-}
-
-%><html>
-<head>
-<title>Access Check Error</title>
-<style>
-body
-{
-  background-color: white;
-  color: black;
-  font-family: Tahoma, Verdana, Arial, Helvetica;
-  font-size: 12px;
-  margin: 20px 20px 20px 20px;
-}
-
-h2
-{
-  font-size: 16px;
-  border-bottom: 2px solid #405060;
-}
-
-.error
-{
-  border-left: 8px solid #B00810;
-  padding-left: 6px;
-  padding-top: 3px;
-  padding-bottom: 4px;
-  text-align: justify;
-}
-
-.narrow
-{
-  width: 450px;
-}
-
-.footer
-{
-  font-size: 10px;
-  border-top: 1px dotted #DFDFDF;
-  font-style: italic;
-}
-
-a, a:visited
-{
-  color: #800000;
-}
-
-</style>
-</head>
-<body>
-
-<div class="narrow">
-<h2>Access Check Error</h2>
-<p class="error"><% if (type == AccessFilter.ERROR_NO_ACCESS) { 
-%>
-You have requested content to which you do not have "read" privileges.
-Please contact a system administrator if you believe you are seeing this
-message in error.  You may return to the <a href="/">home page</a>.<%
-} else {
-%>The system was not able to determine your authorization level.  You cannot view the
-requested content at this time.  Please contact a system administrator for
-assistance.  You may return to the <a href="/">home page</a>.<% } %>
-</p>
-
-<p class="footer">
-Gemini (v<%= GeminiConstants.GEMINI_VERSION %>) Access Control Filter
-</p>
-</div>
-
-</body>
-</html>

+ 0 - 49
gemini/Docroot/WEB-INF/jsp/error-page.jsp

@@ -1,49 +0,0 @@
-<%@ page extends="hello.GhJsp" %><%@ include file="/WEB-INF/jsp/include-variables.jsp" %><%
-
-  // -----------------------------------------------------------------
-  // Error page
-  //
-  // author: mhixson
-  //
-  // The error page is rendered when the controller tier encounters
-  // an uncaught exception during its request processing.  The
-  // exception is delivered along with an optional description.
-  // -----------------------------------------------------------------
-
-  vars.title = "GeminiHello Error";
-  
-  Throwable exception = (Throwable)context.getDelivery("Exception");
-  String description = context.getStringDelivery("Description");
-  boolean reveal = context.getBooleanDelivery("RevealStackTrace");
-  
-  // If reveal is false, the stack trace will be rendered into an HTML
-  // comment.  Application authors should consider removing that entirely
-  // if they are worried about users being able to find the stack trace.
-
-%><%@ include file="/WEB-INF/jsp/include-page-start.jsp" %>
-
-<h2>Sorry, your request could not be processed due to an error</h2>
-
-<p>
-  The request you submitted resulted in an error.  Your request cannot be processed at this time.  Please notify the system administrator.
-</p>
-
-<%= reveal ? "<p><pre style=\"color: #508050\">" : "<!--" %>
-Exception:
-<%= ThrowableHelper.getStackTrace(exception) %>
-<%
-if (exception instanceof ServletException)
-{
-  ServletException servletException = (ServletException)exception;
-%>
-
-Root cause:
-<%= ThrowableHelper.getStackTrace(servletException) %><%
-} %>
-<%= reveal ? "</pre></p>" : "-->" %>
-
-<p>
-  <%= description %>
-</p>
-
-<%@ include file="/WEB-INF/jsp/include-page-end.jsp" %>

+ 0 - 1
gemini/Docroot/WEB-INF/jsp/include-page-end.jsp

@@ -1 +0,0 @@
-</div><%-- End of div ID #container --%>

+ 0 - 5
gemini/Docroot/WEB-INF/jsp/include-page-start.jsp

@@ -1,5 +0,0 @@
-<!DOCTYPE html>
-<head>
-</head>
-<body<% if (StringHelper.isNonEmpty(vars.onload)) { %> onload="<%= vars.onload %>"<% } %>>
-  <div id="container">

+ 0 - 27
gemini/Docroot/WEB-INF/jsp/include-variables.jsp

@@ -1,27 +0,0 @@
-<%@ page import="com.techempower.*,
-                 com.techempower.gemini.*,
-                 com.techempower.gemini.form.*,
-                 com.techempower.gemini.messaging.*,
-                 com.techempower.gemini.jsp.*,
-                 com.techempower.helper.*,
-                 hello.*,
-                 hello.accounts.entity.*,
-                 java.math.*,
-                 java.text.*,
-                 java.util.*" %><%@ page session="false" %><%
-
-  //
-  // Sets up variables for use on all JSP pages.
-  //
-
-  GhContext          context  = (GhContext)request.getAttribute("Context");
-  GhRequestVariables vars     = new GhRequestVariables(context);
-
-  // Note that default stylesheets and scripts that are to be included on
-  // -all- pages should be defined in GhInfrastructure's
-  // constructor.  Page-scope stylesheets and scripts should be defined by
-  // overloading the jspInit function to call sas.addScript and sas.addSheet.
-  // Request-scope scripts and sheets can be defined by using vars.sas.
-  // However, request-scope scripts and sheets are quite uncommon.
-
-%>

+ 0 - 32
gemini/Docroot/WEB-INF/jsp/template.jsp

@@ -1,32 +0,0 @@
-<%@ page extends="hello.GhJsp" %><%@ include file="/WEB-INF/jsp/include-variables.jsp" %><%
-
-  // -----------------------------------------------------------------
-  // Template page
-  //
-  // author: mhixson
-  //
-  // This is a template to use when creating new JSPs.  All JSPs 
-  // should have the same basic structure as this template.  
-  // Embedded <script> tags, if needed, should be placed after 
-  // "include-page-end".
-  // -----------------------------------------------------------------
-  
-  vars.title = "GeminiHello Template";
-  vars.stylesheets.add("foo.css");
-  vars.scripts.add("bar.js");
-  
-%><%@ include file="/WEB-INF/jsp/include-page-start.jsp" %>
-
-<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis sit 
-amet purus arcu, non luctus ligula. Nullam pharetra euismod vestibulum. 
-Vivamus convallis ullamcorper tellus mattis lobortis. Duis at purus 
-ullamcorper ipsum posuere bibendum. Quisque ut ligula eu velit varius 
-pellentesque et sit amet libero. Suspendisse varius ante dui. Donec 
-vulputate dictum dui, vitae varius tortor fermentum adipiscing. Donec 
-auctor varius ullamcorper. Aenean nunc nulla, laoreet nec auctor a, 
-tempor eget risus. Suspendisse interdum, est faucibus pharetra ultrices, 
-tortor libero pulvinar sem, a imperdiet lacus justo at dui. Etiam at 
-magna leo, ac laoreet lectus. Pellentesque fringilla mauris nec enim 
-porttitor in adipiscing lacus semper.</p>
-
-<%@ include file="/WEB-INF/jsp/include-page-end.jsp" %>

BIN
gemini/Docroot/WEB-INF/lib/gemini-1.3.6.jar


BIN
gemini/Docroot/WEB-INF/lib/guava-13.0.1.jar


BIN
gemini/Docroot/WEB-INF/lib/guava-14.0.1.jar


BIN
gemini/Docroot/WEB-INF/lib/techempower.jar


BIN
gemini/Docroot/WEB-INF/lib/trove4j-3.0.3.jar


+ 16 - 0
gemini/Docroot/WEB-INF/mustache/fortunes.mustache

@@ -0,0 +1,16 @@
+{{<layout}}
+{{$body}}
+<table>
+<tr>
+<th>id</th>
+<th>message</th>
+</tr>
+{{#.}}
+<tr>
+<td>{{id}}</td>
+<td>{{message}}</td>
+</tr>
+{{/.}}
+</table>
+{{/body}}
+{{/layout}}

+ 9 - 0
gemini/Docroot/WEB-INF/mustache/layout.mustache

@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Fortunes</title>
+</head>
+<body>
+{{$body}}{{/body}}
+</body>
+</html>

+ 0 - 10
gemini/Docroot/WEB-INF/web.xml

@@ -50,14 +50,4 @@
   <!-- Use UTF-8 for everything. -->
   <character-encoding>UTF-8</character-encoding>
 
-  <!-- Enable GZIP compression. -->
-  <!--
-  <filter filter-name="gzip" filter-class="com.caucho.filters.GzipFilter">
-    <init>
-      <use-vary>true</use-vary>
-    </init>
-  </filter>
-  <filter-mapping url-pattern='*' filter-name="gzip" />
-  -->
-
 </web-app>

+ 0 - 104
gemini/Docroot/css/basicadmin-logmonitor.css

@@ -1,104 +0,0 @@
-/* 
-Gemini Basic Administration
-CSS for live log monitoring
-*/
-
-body
-{
-  color: black;
-  background: white;
-  margin: 0px 0px 0px 0px;
-}
-div#banner
-{
-  color: black;
-  background: rgba(255,255,255,0.6);
-  font-family: Tahoma, Verdana, Arial, Helvetica, sansserif;
-  font-size: 12px;
-  position: fixed;
-  top: 0px;
-  right: 0px;
-  padding: 4px 8px 4px 8px;
-  font-weight: bold;
-  text-align: right;
-}
-div#log, div#log td
-{
-  font-family: Consolas, Courier, fixed;
-  font-size: 12px;
-}
-div#log table
-{
-  padding: 0px 0px 0px 0px;
-}
-div#log table td.linenumber
-{
-  text-align: right;
-  width: 55px;
-  padding-right: 10px;
-}
-div#log table td.content
-{
-}
-div#banner span#channel
-{
-  font-weight: normal;
-}
-div#banner span#stats
-{
-  font-weight: normal;
-}
-div#banner span#stats span#displayed,
-div#banner span#stats span#captured
-{
-  font-weight: bold;
-}
-div#banner span#levels,
-div#banner span#controls
-{
-  display: block;
-  padding: 8px 0px 4px 0px;
-}
-div#banner span#levels a,
-div#banner span#controls a
-{
-  color: black;
-  background-image: -moz-linear-gradient(top, rgb(255,255,255), rgb(230,230,235));
-  background-image: -webkit-gradient(linear, center top, center bottom, from(rgb(255,255,255)), to(rgb(230,230,235)));
-  border: 1px solid rgb(180,180,190);
-  padding: 2px 4px 2px 4px;
-  margin: 0px 2px 0px 2px;
-  font-size: 12px;
-  text-decoration: none;
-  -moz-border-radius: 3px;
-  -webkit-border-radius: 3px;
-  -moz-box-shadow: 1px 1px 2px rgba(0,0,0,0.2);
-  -webkit-box-shadow: 1px 1px 2px rgba(0,0,0,0.2);
-  text-shadow: none;
-}
-div#banner span#levels a:hover,
-div#banner span#controls a:hover
-{
-  color: rgb(60,170,200);
-  background-image: -moz-linear-gradient(top, rgb(255,255,255), rgb(190,210,245));
-  background-image: -webkit-gradient(linear, center top, center bottom, from(rgb(255,255,255)), to(rgb(190,210,245)));
-  text-shadow: 0px 0px 2px rgba(255,255,255,0.9), 0px 0px 4px rgba(255,255,255,0.8), 0px 0px 6px rgba(255,255,255,0.7), 0px 0px 10px rgba(255,255,255,0.6);
-  border: 1px solid rgb(130,130,140);
-}
-div#banner span#levels a.selected,
-div#banner span#controls a.selected
-{
-  color: rgb(200,70,20);
-  background-image: -moz-linear-gradient(top, rgb(255,255,255), rgb(245,210,190));
-  background-image: -webkit-gradient(linear, center top, center bottom, from(rgb(255,255,255)), to(rgb(245,210,190)));
-  text-shadow: 0px 0px 2px rgba(255,255,255,0.9), 0px 0px 4px rgba(255,255,255,0.8), 0px 0px 6px rgba(255,255,255,0.7), 0px 0px 10px rgba(255,255,255,0.6);
-  border: 1px solid rgb(230,80,50);
-}
-div#banner span#controls input#filter
-{
-  width: 100px;
-  border: 1px solid rgb(180,180,190);
-  background: rgba(255,255,255,0.6);
-  font-family: Tahoma, Verdana, Arial, Helvetica, sansserif;
-  font-size: 12px;
-}

+ 0 - 473
gemini/Docroot/css/basicadmin.css

@@ -1,473 +0,0 @@
-/* Standard style-sheet for the basic administration section. */
-
-/* Standard representation of the administration sub-navigation.  This can 
-   be replaced by a custom rendering of the sub-navigation.  See 
-   include-subnav.jsp for more detail. */
-nav#admnav
-{
-  background-color: #F8F8FF;
-  font-family: Tahoma, Verdana, Arial, Helvetica;
-  font-size: 13px;
-  line-height: 18px;
-}
-
-nav#admnav a
-{
-  background-color: #DDDDEE;
-  display: inline-block;
-  padding: 0px 10px 0px 10px;
-  margin: 0px 4px 0px 0px;
-  color: black;
-  text-decoration: none;
-}
-
-nav#admnav a:hover
-{
-  background-color: #777788;
-  color: white;
-}
-
-/* The main administrative content div. */
-div#admcontent
-{
-  font-family: Tahoma, Verdana, Arial, Helvetica;
-  font-size: 11px;
-  line-height: 1.2em;
-  min-height: 450px;
-}
-
-div#admcontent input,
-div#admcontent select,
-div#admcontent textarea
-{
-  border: 1px solid black;
-  font-family: Tahoma, Verdana, Arial, Helvetica;
-  font-size: 12px;
-}
-
-div#admcontent textarea.largedetails
-{
-  width: 100%;
-  height: 400px;
-  box-sizing: border-box;
-  -webkit-box-sizing: border-box;
-  -moz-box-sizing: border-box;
-  padding: 6px 0px 6px 6px;
-  border: none;
-  margin: 0px 0px;
-  font-family: monospace;
-  line-height: 1.2em;
-  font-size: 11px;
-}
-
-div.admmenusection
-{
-  position: relative;
-  padding-bottom: 25px;
-}
-
-div.admmenusection div.admbanner
-{
-  font-size: 14px;
-  color: #303040;
-  margin-bottom: 3px;
-}
-
-div.admmenusection div.admlabel
-{
-  z-index: 2;
-}
-
-div.admmenusection div.admaccent
-{
-  position: absolute;
-  font-family: Verdana, Tahoma, Arial, Helvetica;
-  font-size: 72px;
-  font-weight: bold;
-  color: #DDDDEE;
-  top: -10px;
-  z-index: 0;
-  right: 0px;
-}
-
-div.admmenusection:hover div.admaccent
-{
-  color: #D0D0E1;
-}
-
-div.admmenusection div.admoptions
-{
-  border-top: 1px solid #DDDDEE;
-  position: relative;
-  background-color: #F8F8FF;
-  z-index: 1;
-}
-
-div.admoptions td
-{
-  padding: 1px 2px 1px 2px;
-  vertical-align: center;
-}
-
-div.admoptions a,
-a.admbutton
-{
-  display: inline-block;
-  min-width: 100px;
-  border: 1px solid #DDDDEE;
-  background-color: #FCFCFF;
-  padding: 2px 4px 2px 4px;
-  text-decoration: none;
-  white-space: nowrap;
-  color: black;
-}
-
-div.admoptions a:hover,
-a.admbutton:hover
-{
-  color: white;
-  border: 1px solid #777788;
-  background-color: #777788;
-}
-
-tr.admheader td
-{
-  border-top: 1px solid #707080;
-  border-bottom: 1px solid #505060;
-  padding: 1px 4px 1px 4px;
-  background-color: #606070;
-  color: white;
-  font-weight: bold;
-}
-
-tr.admheader td.separator
-{
-  border-top: none;
-  border-bottom: none;
-  background: none;
-}
-
-tr.admsubheader td
-{
-  border-top: 9px solid white;
-  border-bottom: 1px solid #9090A0;
-  padding: 1px 4px 1px 4px;
-  background-color: #A0A0B0;
-  color: white;
-  font-weight: bold;
-}
-
-tr.admplainsubheader td
-{
-  border-top: 9px solid white;
-  border-bottom: 1px solid #A0A0B0;
-  font-weight: bold;
-}
-
-td.admconfitem
-{
-  vertical-align: top;
-  padding-right: 4px;
-  background-color: white;
-  border-top: 1px solid white;
-  border-bottom: 1px solid white;
-  margin: 1px 0px 1px 0px;
-}
-
-td.admconfvalue,
-td.admconfintvalue
-{
-  vertical-align: top;
-  background-color: #F8F8FF;
-  padding: 1px 4px 1px 4px;
-  border-top: 1px solid white;
-  border-bottom: 1px solid white;
-  margin: 1px 0px 1px 0px;
-}
-
-td.admnowrap
-{
-  text-wrap: avoid;
-  white-space: nowrap;
-}
-
-td.admconfintvalue
-{
-  text-align: right;
-}
-
-td.exceptional
-{
-  color: #C00000;
-  background-color: #FFF0F0;
-}
-
-td.inactive
-{
-  color: #9898A8;
-}
-
-div.admform
-{
-}
-
-div.admform label
-{
-  width: 150px;
-}
-
-div.admform label, 
-div.admform input,
-div.admform select,
-div.admform textarea
-{
-  display: block;
-  float: left;
-  margin-bottom: 10px;
-}
-
-div.admform br
-{
-  clear: left;
-}
-
-div.admformv
-{
-}
-
-div.admformv ol
-{
-  list-style: none;
-  padding-left: 0px;
-}
-
-div.admformv ol li
-{
-  float: left;
-  margin-right: 10px;
-}
-
-div.admformv label
-{
-  font-size: 10px;
-}
-
-div.admformv label, div.admformv input
-{
-  display: block;
-}
-
-div.admformv div.clear
-{
-  clear: both;
-}
-
-p.admformvend
-{
-  clear: both;
-}
-
-.admmessage
-{
-  padding: 2px 6px 2px 6px;
-  margin: 12px 0px 12px 0px;
-  border: 1px solid #669966;
-  background-color: #EEFFEE;
-  color: black;
-  font-family: Tahoma, Arial, Helvetica;
-  font-size: 14px;
-}
-
-.admconfirm0 #desc,
-.admconfirm5 #desc,
-.admconfirm10 #desc
-{
-  text-align: left;
-  padding: 5px 5px 5px 5px;
-}
-
-.admconfirm0 #link,
-.admconfirm5 #link,
-.admconfirm10 #link
-{
-  text-align: left;
-  padding: 5px 5px 10px 5px;
-}
-
-.admconfirm0 #auxmessage,
-.admconfirm5 #auxmessage,
-.admconfirm10 #auxmessage
-{
-  text-align: left;
-  font-weight: bold;
-  background-color: #F0F0F0;
-  padding: 4px 4px 4px 4px;
-  border: 3px solid red;
-  color: black;
-}
-
-.admconfirm10
-{
-  width: 400px;
-  border: 1px solid #EE6666;
-  background-color: #FFE8E8;
-  color: black;
-  font-family: Tahoma, Arial, Helvetica;
-  font-size: 12px;
-}
-
-.admconfirm10 #banner
-{
-  padding: 5px 5px 5px 5px;
-  text-align: center;
-  font-family: Verdana, Tahoma, Arial, Helvetica;
-  font-size: 18px;
-  font-weight: bold;
-  background-color: #EE6666;
-  color: white;
-}
-
-.admconfirm10 #action
-{
-  text-align: center;
-  font-weight: bold;
-  background-color: #EE6666;
-  padding-bottom: 4px;
-  color: white;
-}
-
-.admconfirm10 #link a
-{
-  border: 1px solid #EE6666;
-  padding: 2px 10px 2px 10px;
-  text-decoration: none;
-  color: black;
-  font-weight: bold;
-}
-
-.admconfirm10 #link a:hover
-{
-  color: white;
-  background-color: #EE6666;
-}
-
-.admconfirm5
-{
-  width: 400px;
-  border: 1px solid #669966;
-  background-color: #EEFFEE;
-  color: black;
-  font-family: Tahoma, Arial, Helvetica;
-  font-size: 12px;
-}
-
-.admconfirm5 #banner
-{
-  padding: 5px 5px 5px 5px;
-  text-align: center;
-  font-family: Verdana, Tahoma, Arial, Helvetica;
-  font-size: 18px;
-  font-weight: bold;
-  background-color: #669966;
-  color: white;
-}
-
-.admconfirm5 #action
-{
-  text-align: center;
-  font-weight: bold;
-  background-color: #669966;
-  padding-bottom: 4px;
-  color: white;
-}
-
-.admconfirm5 #link a
-{
-  border: 1px solid #669966;
-  padding: 2px 10px 2px 10px;
-  text-decoration: none;
-  color: black;
-  font-weight: bold;
-}
-
-.admconfirm5 #link a:hover
-{
-  color: white;
-  background-color: #669966;
-}
-
-.admconfirm0
-{
-  width: 400px;
-  border: 1px solid #226699;
-  background-color: #DDEEFF;
-  color: black;
-  font-family: Tahoma, Arial, Helvetica;
-  font-size: 12px;
-}
-
-.admconfirm0 #banner
-{
-  padding: 5px 5px 5px 5px;
-  text-align: center;
-  font-family: Verdana, Tahoma, Arial, Helvetica;
-  font-size: 18px;
-  font-weight: bold;
-  background-color: #226699;
-  color: white;
-}
-
-.admconfirm0 #action
-{
-  text-align: center;
-  font-weight: bold;
-  background-color: #226699;
-  padding-bottom: 4px;
-  color: white;
-}
-
-.admconfirm0 #link a
-{
-  border: 1px solid #226699;
-  padding: 2px 10px 2px 10px;
-  text-decoration: none;
-  color: black;
-  font-weight: bold;
-}
-
-.admconfirm0 #link a:hover
-{
-  color: white;
-  background-color: #226699;
-}
-
-div#admcontent table.threadlist .highpri
-{
-  background-color: #FFE8E8;
-}
-
-div#admcontent table.threadlist .lowpri
-{
-  background-color: #E0FFF0;
-}
-
-div#admcontent table.threadlist .medpri
-{
-  background-color: #E0F0FF;
-}
-
-div#admcontent table.threadlist .pausepending
-{
-  background-color: #C0B0B0;
-}
-
-div#admcontent table.threadlist .paused
-{
-  background-color: #706060;
-  color: white;
-}
-
-div#admcontent span.alert
-{
-  color: #FF0000;
-}

+ 0 - 82
gemini/Docroot/css/gh.css

@@ -1,82 +0,0 @@
-/* GeminiHello style-sheet. */
-
-body {
-  padding: 0px;
-  margin: 0px;
-  background-color: rgb(190,190,190);
-  color: #000000;
-}
-
-body, input, textarea, select {
-  font-family: Arial, Helvetica;
-  font-size: 14px;
-  line-height: 18px;
-}
-
-/* Corrects styling for new HTML semantic elements in older browsers. */
-article, aside, details, figcaption, figure,
-footer, header, hgroup, menu, nav, section { 
-  display: block;
-}
-
-/* When placed at the end of a block, clears the floating blocks above. 
-   When placed at the beginning of a block, avoids some issues caused 
-   by margin collapsing (especially in IE7). */
-.clear {
-  display: block;
-  clear: both;
-  height: 1px;
-  margin-bottom: -1px;
-}
-
-/* Standard fixed-width layout. */
-#container {
-  background-color: white;
-  width: 1000px;
-  margin: 0px auto;
-}
-
-#header,
-#content,
-#footer {
-}
-
-#header,
-#footer {
-  background-color: rgb(200,210,254);
-  padding: 4px 10px;
-}
-
-#content {
-  padding: 10px 10px;
-}
-
-#messages p {
-  padding: 13px;
-  border-width: 2px;
-  border-style: solid;
-}
-
-#messages .success {
-  border-color: #c6d880; 
-  background-color: #e6efc2; 
-  color: #264409; 
-}
-
-#messages .error {
-  background-color: #fbe3e4; 
-  color: #8a1f11;
-  border-color: #fbc2c4;
-}
-
-#messages .warning {
-  background-color: #fff6bf; 
-  color: #514721;
-  border-color: #ffd324;;
-}
-
-#messages .normal { 
-  background-color: #d5edf8; 
-  color: #205791; 
-  border-color: #92cae4;
-}

+ 0 - 291
gemini/Docroot/html/admin-compact-performance-monitor.html

@@ -1,291 +0,0 @@
-<html>
-<head>
-<title>Performance Monitoring</title>
-<link type="text/css" rel="stylesheet" href="../css/basicadmin.css" />
-<link rel="shortcut icon" href="../images/monitor-graph.png" />
-<style>
-
-body, td {
-  font-family: calibri, tahoma, verdana, arial, helvetica;
-  font-size: 10px;
-  margin: 0px 0px 0px 0px;
-}
-
-#countdown {
-  position: fixed;
-  right: 0px;
-  height: 100%;
-  width: 5px;
-  background-color: rgb(100,100,110);
-  background: -moz-linear-gradient(top, rgb(90,90,100), rgb(200,200,210));
-  -moz-box-shadow: 0px 0px 10px rgba(100,100,110,0.75);
-}
-
-#countdown.error {
-  background-color: rgb(190,10,10);
-  background: -moz-linear-gradient(top, rgb(160,0,0), rgb(230,20,20));
-  -moz-box-shadow: 0px 0px 10px rgba(190,10,10,0.75);
-}
-
-#lastupdate {
-  margin: 4px 4px 4px 30px;
-}
-
-#health {
-  height: 175px;
-  margin: 4px 4px 4px 0px;
-}
-
-#datatable {
-  margin: 4px 4px 4px 30px;
-}
-
-#uptime {
-  padding: 4px 4px 4px 30px;
-}
-
-#controls {
-  margin: 10px 4px 10px 30px;
-}
-
-#controls .enabled {
-  border: 2px solid rgb(100,100,110);
-  padding: 2px 4px 2px 4px;
-  margin-right: 6px;
-  -moz-box-shadow: 0px 0px 10px rgba(100,100,110,0.5);
-}
-
-#controls a {
-  border: 1px solid rgb(180,180,240);
-  padding: 3px 5px 3px 5px;
-  -moz-box-shadow: 0px 0px 10px rgba(100,100,190,0.25);
-  text-decoration: none;
-  margin-right: 6px;
-  color: rgb(40,40,130);
-}
-
-#controls a:hover {
-  border: 2px solid rgb(180,240,180);
-  padding: 2px 4px 2px 4px;
-  -moz-box-shadow: 0px 0px 10px rgba(100,190,100,0.5);
-  background-color: rgb(200,255,200);
-  color: black;
-}
-
-</style>
-<script type="text/javascript" src="../js/basicadmin.js"></script>
-<script type="text/javascript" src="../js/jquery.js"></script>
-<script type="text/javascript" src="../js/jquery.flot.js"></script>
-</head>
-
-<body>
-
-<div id='countdown'>&nbsp;</div>
-
-<div id="uptime">[Uptime]</div>
-
-<div id="health">[Health]</div>
-
-<table id='datatable' border="0" cellpadding="0" cellspacing="0">
-<tbody id='header'>
-</tbody>
-<tbody id='cmds'>
-</tbody>
-</table>
-
-<div id="controls"></div>
-
-<div id="lastupdate">[Last update]</div>
-<div id="message"></div>
-
-</body>
-
-<script>
-
-var mode = 0,
-     svUrl = '../',
-    detail = '',
-    exc = 5,
-    commands,
-    content = "",
-    concurrencyHighlight = 10,
-    titles = ["Performance Monitoring", "Error - Cannot fetch performance data"],
-    refreshInterval = 5,
-    nextRefresh = refreshInterval,
-    seconds = nextRefresh,
-    maximumRefresh = 60,
-    lastUpdate = 0;
-
-if (!Date.now) {
-  Date.now = function now() {
-    return +new Date();
-  };
-}
-
-function renderHeader() {
-  var content = '';
-
-  // Performance monitoring mode.
-  if (mode == 0) {
-    content =
-        '<tr class="admheader">'
-      + '<td rowspan="2" valign="bottom">Command</td>'
-      + '<td rowspan="2" valign="bottom"><abbr title="Current load">CL</abbr></td>'
-      + '<td rowspan="2" valign="bottom"><abbr title="Count since application start">Count</abbr></td>'
-      + '<td rowspan="2" valign="bottom"><abbr title="Count in last hour">LH</abbr></td>'
-      + '<td class="separator">&nbsp;</td>'
-      + '<td colspan="6" align="center">Average in last hour</td>'
-      + '<td class="separator">&nbsp;</td>'
-      + '<td colspan="5" align="center">Worst in last hour</td>'
-      + '</tr>'
-      + '<tr class="admheader">'
-      + '<td class="separator">&nbsp;</td>'
-      + '<td align="right"><abbr title="Queries">Qs</abbr></td>'
-      + '<td align="right"><abbr title="Query Time">QT</abbr></td>'
-      + '<td align="right"><abbr title="Logic Time">LT</abbr></td>'
-      + '<td align="right"><abbr title="Render Time">RT</abbr></td>'
-      + '<td align="right"><abbr title="CPU Time">CT</abbr></td>'
-      + '<td align="right">Total</td>'
-      + '<td class="separator">&nbsp;</td>'
-      + '<td align="right"><abbr title="Queries">Qs</abbr></td>'
-      + '<td align="right"><abbr title="Query Time">QT</abbr></td>'
-      + '<td align="right"><abbr title="Logic Time">LT</abbr></td>'
-      + '<td align="right"><abbr title="Render Time">RT</abbr></td>'
-      + '<td align="right"><abbr title="CPU Time">CT</abbr></td>'
-      + '<td class="separator">&nbsp;</td>'
-      + '</tr>';
-  }
-  // Current requests mode.
-  else if (mode == 1) {
-    content =
-        '<tr class="admheader">'
-      + '<td>Command</td>'
-      + '<td><abbr title="Request Number">Req</abbr></td>'
-      + '<td><abbr title="Thread ID">TID</abbr></td>'
-      + '<td><abbr title="Request start time">Time</abbr></td>'
-      + '<td class="separator">&nbsp;</td>'
-      + '<td align="right"><abbr title="Dispatches">Ds</abbr></td>'
-      + '<td align="right"><abbr title="Queries">Qs</abbr></td>'
-      + '<td align="right"><abbr title="Query Exceptions">QEs</abbr></td>'
-      + '<td align="right"><abbr title="Query Time">QT</abbr></td>'
-      + '<td align="right"><abbr title="Logic Time">LT</abbr></td>'
-      + '<td align="right"><abbr title="Render Time">RT</abbr></td>'
-      + '<td align="right"><abbr title="CPU Time">CT</abbr></td>'
-      + '<td align="right"><abbr title="Total time">Total</abbr></td>'
-      + '</tr>';
-  }
-  $("tbody#header").html(content);
-}
-
-function render(commands, uptime) {
-  if (mode == 0) {
-    $("tbody#cmds").html(gba.renderPerformanceMonitorList(commands, detail, exc, 2, concurrencyHighlight));
-  }
-  else if (mode == 1) {
-    $("tbody#cmds").html(gba.renderCurrentRequestList(commands, detail, 2));
-  }
-  lastUpdate = Date.now();
-  if (uptime != null) {
-    $("div#uptime").html("Application last reported " + uptime + ".");
-  }
-};
-
-function refresh() {
-  var urlSuffix = '?cmd=admin-monitor-list&mode=1'
-  if (mode == 1) {
-    urlSuffix = '?cmd=admin-monitor-current&mode=1';
-  }
-
-  $.ajax({
-    url: svUrl + urlSuffix,
-    dataType: 'json',
-    type: 'get',
-    data: {},
-    timeout: 4000,
-    success: function(data) {
-        if (data != null) {
-          document.title = titles[0];
-          $("div#countdown").removeClass("error");
-          nextRefresh = refreshInterval;
-          if (seconds > nextRefresh)
-            seconds = nextRefresh;
-          if (mode == 0)
-            render(data.commands, data.uptime);
-          else
-            render(data.requests, data.uptime);
-          gba.renderHealthMonitorFlot(data.health, data.tzshift, data.interval, "div#health");
-        }
-        else {
-          refreshError();
-        }
-      },
-    error: refreshError
-    });
-}
-
-function refreshError() {
-  document.title = titles[1];
-
-  $("div#countdown").addClass("error");
-
-  // Back off a bit.
-  var newRefresh = nextRefresh + refreshInterval;
-  if (newRefresh > maximumRefresh)
-    newRefresh = maximumRefresh;
-  seconds += (newRefresh - nextRefresh);
-  nextRefresh = newRefresh;
-}
-
-function countdown() {
-  seconds--;
-  if (seconds == 0) {
-    refresh();
-    seconds = nextRefresh;
-  }
-  if (seconds == nextRefresh) {
-    $("div#countdown").height("100%");
-  }
-  else {
-    $("div#countdown").height(seconds * (100 / nextRefresh) + "%");
-  }
-  refreshLastUpdate();
-}
-
-function refreshLastUpdate() {
-  if (lastUpdate > 0) {
-    var sec = Math.floor((Date.now() - lastUpdate) / 1000);
-    var content = "Last update at " + new Date(lastUpdate) + " (" + sec + " second" + (sec == 1 ? "" : "s") + " ago).";
-    $("div#lastupdate").html(content);
-  }
-}
-
-function renderControls() {
-  var content = '';
-
-  function item(label, index) {
-    if (mode != index)
-      return ' <a href="javascript:switchMode(' + index + ');">' + label + '</a>';
-    else
-      return ' <span class="enabled">' + label + '</span>';
-  }
-
-  content += item("Overall Performance", 0);
-  content += item("Current Requests", 1);
-
-  $("div#controls").html(content);
-}
-
-function switchMode(newMode) {
-  mode = newMode;
-  renderControls();
-  renderHeader();
-  refresh();
-}
-
-renderControls();
-renderHeader();
-refresh();
-window.setInterval(countdown, 1000);
-
-</script>
-</html>

BIN
gemini/Docroot/images/alert.gif


BIN
gemini/Docroot/images/filler.gif


BIN
gemini/Docroot/images/monitor-graph.png


+ 0 - 354
gemini/Docroot/js/basicadmin-logmonitor.js

@@ -1,354 +0,0 @@
-/**
- * Gemini Basic Administration
- * Script for real-time log monitoring
- * Attempts to use WebSockets and falls back to AJAX.
- */
-
-var logmonitor = (function() {
-
-  var uid = 0,
-      logBuffer = new Array(),
-      dispCurr = 0,
-      dispThreshold = 30,
-      containReq = "",
-      repaintTimeout = 0,
-      capture = true,
-      track = true,
-      ignored = 0,
-      $filter = $("#filter"),
-      maxLines,
-      channelID,
-      channel,
-      svUrl,
-      ajaxProcessor,
-      wsProcessor,
-      activeProcessor,
-      $logData = $("tbody#logdata"),
-      $body = $("body"),
-      $displayed = $("span#displayed"),
-      $captured = $("span#captured");
-
-  /** The WebSocket processor. */
-  wsProcessor = (function() {
-    function connect() {
-      try {
-        var url;
-
-        if (svUrl.startsWith("http://")) {
-          url = "ws://" + svUrl.substring(7);
-        }
-        else {
-          url = "wss://" + svUrl.substring(8);
-        }
-
-        url = url + "?cmd=admin-log-monitor&act=ws&ch=" + channelID;
-        var ws = new WebSocket(url, "logmonitor");
-      }
-      catch (failure) {
-        return false;
-      }
-
-      // Receive data as a WebSocket event and decode from JSON before
-      // calling the distributor.
-      ws.onmessage = function(event) {
-        process($.parseJSON(event.data));
-      }
-
-      // Send a keep-alive message to the server every 30 seconds.
-      setInterval(function() {
-        ws.send("keep-alive");
-      }, 30000);
-
-      return true;
-    }
-
-    function process(data) {
-      for (var i = 0; i < data.updates.length; i++) {
-        debug(data.updates[i].text, data.updates[i].level);
-      }
-    }
-
-    function pause() {
-    }
-
-    function resume() {
-    }
-    
-    return {
-      connect: connect,
-      pause: pause,
-      resume: resume
-    };
-
-  })();
-
-  /** The AJAX processor. */
-  ajaxProcessor = (function() {
-    var ajaxInterval = 0,
-        since = 0;
-
-    function processAjaxFetch(data) {
-      if (data.uid) {
-        since = data.uid;
-      }
-      if (data.items) {
-        for (var i = 0; i < data.items.length; i++) {
-          debug(data.items[i].text, data.items[i].level);
-        }
-      }
-    }
-
-    function fetchViaAjax() {
-      $.ajax({
-        url: svUrl + "?cmd=admin-log-monitor&act=ajax&ch=" + channelID + "&since=" + since,
-        dataType: 'json',
-        type: 'get',
-        data: {},
-        success: processAjaxFetch
-        });
-    }
-
-    function connect() {
-      resume();
-      return true;
-    }
-
-    function pause() {
-      window.clearInterval(ajaxInterval);
-    }
-
-    function resume() {
-      window.clearInterval(ajaxInterval);
-      ajaxInterval = window.setInterval(fetchViaAjax, 500);
-    }
-
-    return {
-      connect: connect,
-      pause: pause,
-      resume: resume
-    };
-
-  })();
-
-  /** Paint details; wire up the filter; and start fetching log items. */
-  function init(sv, cid, channels) {
-    svUrl = sv;
-    channelID = cid;
-    channel = channels[cid];
-    maxLines = channel.size;
-
-    createSeverityClasses();
-    debug("Attaching listener to log file at " + standardDateString(new Date()) + ".", 50);
-    displayChannelInfo();
-
-    // Capture keypresses on the filter box.
-    $filter.focus().keyup(function(event) {
-      var curVal = containReq;
-      containReq = this.value.toLowerCase();
-      if (curVal != containReq) {
-        if (repaintTimeout > 0) {
-          window.clearTimeout(repaintTimeout);
-        }
-        repaintTimeout = window.setTimeout(repaintLog, 100);
-      }
-    });
-
-    $("#togglecapture").click(toggleCapture);
-    $("#toggletrack").click(toggleTrack);
-    $("#levels").find(".level").each(function (idx, el) {
-      el = $(el);
-      el.click(function() {
-        setThreshold(el.attr("level"));
-      });
-    });
-
-    connect();
-  }
-
-  /** Connect to the server.  Try WebSockets first and then AJAX. */
-  function connect() {
-    var good;
-
-    good = wsProcessor.connect();
-    if (good) {
-      activeProcessor = wsProcessor;
-    }
-    else {
-      good = ajaxProcessor.connect();
-      activeProcessor = ajaxProcessor;
-    }
-  }
-
-  /** Render a summary of the current channel's filter settings. */
-  function displayChannelInfo() {
-    var toAdd;
-    if (channel) {
-      toAdd = channel.name
-        + " (levels " + channel.min
-        + " to " + channel.max
-        + (channel.contains ? (" containing \"" + channel.contains + "\"") : "")
-        + (channel .regex ? (" matching regex \"" + channel.regex + "\"") : "")
-        + ")";
-    }
-    else {
-      toAdd = "Unknown log channel";
-    }
-    $("span#channel").html(toAdd);
-  }
-
-  /** Toggle the pause/capture mode. */
-  function toggleCapture() {
-    if (capture) {
-      capture = false;
-      $("div#banner span#controls a#togglecapture").addClass("selected").blur();
-      activeProcessor.pause();
-    }
-    else {
-      repaintLog();
-      capture = true;
-      $("div#banner span#controls a#togglecapture").removeClass("selected").blur();
-      activeProcessor.resume();
-    }
-  }
-
-  /** Toggle the scroll tracking mode. */
-  function toggleTrack() {
-    if (track) {
-      track = false;
-      $("div#banner span#controls a#toggletrack").removeClass("selected").blur();
-    }
-    else {
-      jumpToBottom();
-      track = true;
-      $("div#banner span#controls a#toggletrack").addClass("selected").blur();
-    }
-  }
-
-  /** Capture a log item and display the item if it meets the client-side filters. */
-  function debug(text, level) {
-    var logItem = { 'uid': uid++, 'level': level, 'text': text };
-
-    // Remove top item from the buffer if at maximum length.
-    if (logBuffer.length >= maxLines) {
-      logBuffer.shift();
-      if (capture) {
-        var toRemove = uid - maxLines - 1;
-        $("tr#line" + toRemove).remove();
-      }
-    }
-
-    // Add the item to our buffer.
-    logBuffer.push(logItem);
-
-    if (meetsCriteria(logItem)) {
-      displaySingle(logItem);
-    }
-
-    showStats();
-  }
-
-  /** Turns a log item into HTML. */
-  function renderSingleAsHtml(logItem) {
-    return "<tr id='line" + logItem.uid + "'><td class='content l" + logItem.level + "'>" + logItem.text + "</td></tr>";
-  }
-
-  /** Add a log item into the view assuming we're capturing. */
-  function displaySingle(logItem) {
-    if (capture) {
-      var toAdd = renderSingleAsHtml(logItem);
-      dispCurr++;
-      $logData.append(toAdd);
-      jumpIfFollow();
-    }
-    else {
-      ignored++;
-    }
-  }
-
-  /** If we're following the log, scroll down. */
-  function jumpIfFollow() {
-    if (track) {
-      jumpToBottom();
-    }
-  }
-
-  /** Scroll to the bottom of the page. */
-  function jumpToBottom() {
-    $body.scrollTop(10000000);
-  }
-
-  /* Adjust the minimum threshold and repaint. */
-  function setThreshold(newThreshold) {
-    dispThreshold = newThreshold;
-    $("div#banner span#levels a").removeClass("selected").blur();
-    $("div#banner span#levels a#t" + dispThreshold).addClass("selected");
-    repaintLog();
-  }
-
-  /** Clear the view and re-render it entirely given current client-side settings. */
-  function repaintLog() {
-    dispCurr = 0;
-    var toAdd = "";
-    for (var i = 0; i < logBuffer.length; i++) {
-      if (meetsCriteria(logBuffer[i])) {
-        toAdd += renderSingleAsHtml(logBuffer[i]);
-        dispCurr++;
-      }
-    }
-
-    $logData.html(toAdd);
-
-    showStats();
-    jumpIfFollow();
-  }
-
-  /** Determines if a log item meets the current client-side criteria. */
-  function meetsCriteria(logItem) {
-    if (logItem.level >= dispThreshold) {
-      return (  (containReq == "")
-             || (logItem.text.toLowerCase().indexOf(containReq) >= 0)
-             );
-    }
-    return false;
-  }
-
-  /** Display how many lines are visible versus captured. */
-  function showStats() {
-    var displayed = $logData.children().length;
-    $displayed.text(displayed);
-    $captured.text(logBuffer.length);
-  }
-
-  /** Create a gradient of colors for log severity. */
-  function createSeverityClasses() {
-    var sr = 168, sg = 168, sb = 128, offset = 0,
-        toAdd = "";
-
-    function createGradient(dr, dg, db, num) {
-      var res = "";
-      for (i = 0; i < num; i++) {
-        res += ".l" + (offset++) + " { color: rgb(" + sr + "," + sg + "," + sb + "); } ";
-        sr += dr; if (sr > 255) sr = 255; if (sr < 0) sr = 0;
-        sg += dg; if (sg > 255) sg = 255; if (sg < 0) sg = 0;
-        sb += db; if (sb > 255) sb = 255; if (sb < 0) sb = 0;
-      }
-
-      return res;
-    }
-
-    toAdd += createGradient(-4, -4, 4, 15);  // Start with gray
-    toAdd += createGradient(-1, 4, -6, 20);  // Blend to blue
-    toAdd += createGradient(-6, -8, -4, 20); // Blend to green
-    toAdd += createGradient(-6, -6, -6, 5);  // Blend to black
-    toAdd += createGradient(12, 6, 0, 20);   // Blend to orange
-    toAdd += createGradient(1, -2, 0, 10);   // Blend to red
-    toAdd += createGradient(4, -10, 0, 11);  // Blend to bright red
-
-    $("head").append("<style>" + toAdd + "</style>");
-  }
-
-  return {
-    init: init
-  };
-
-})();

+ 0 - 396
gemini/Docroot/js/basicadmin.js

@@ -1,396 +0,0 @@
-/**
- * Gemini Basic Administration
- */
-
-var gba = (function() {
-
-  /** Pad a number to two digits. */
-  function pad(n) {
-    return (n < 10) ? '0' + n : n
-  }
-
-  /** Render a full date. */
-  function standardDateString(d) {
-    return d.getFullYear() + '-'
-      + pad(d.getMonth() + 1)+'-'
-      + pad(d.getDate()) + ' '
-      + pad(d.getHours()) + ':'
-      + pad(d.getMinutes()) + ':'
-      + pad(d.getSeconds());
-  }
-
-  /** Render a date object as time only. */
-  function standardTimeString(d) {
-    return pad(d.getHours()) + ':'
-      + pad(d.getMinutes()) + ':'
-      + pad(d.getSeconds());
-  }
-
-  /** Truncate and add an abbr tag. */
-  function abbrTruncate(inputText, desiredLength, abbrMaxLength) {
-    if (inputText.length > desiredLength) {
-      if (  (abbrMaxLength != undefined)
-         && (inputText.length > abbrMaxLength)
-         ) {
-        return '<abbr title="' + inputText.substring(0, abbrMaxLength - 3) + '...">' + inputText.substring(0, desiredLength - 3) + '...</abbr>';
-      } else {
-        return '<abbr title="' + inputText + '">' + inputText.substring(0, desiredLength - 3) + '...</abbr>';
-      }
-    }
-    else {
-      return inputText;
-    }
-  }
-
-  /** Render the list of monitored commands in the performance monitor. */
-  function renderPerformanceMonitorList(commands, detail, exceptionalCoefficient,
-    includeSpecialTime, concurrencyHighlight) {
-
-    var st = false,             // Special time
-        cp = false,             // Compact mode
-        avgw = 8,               // Width in columns
-        worw = 6,               // Width in columns
-        totalRequests = 0,
-        totalConcurrent = 0,
-        lastHourRequests = 0,
-        totalDispatches = 0,    // Rough totals for averages across all commands.
-        totalQueries = 0,
-        totalQueryErrors = 0,
-        totalQueryTime = 0,
-        totalLogicTime = 0,
-        totalRenderTime = 0,
-        totalSpecialTime = 0,
-        totalTotalTime = 0,
-        totalCpuTime = 0,
-        worstQueries = 0,       // Worsts across all commands.
-        worstQueryErrors = 0,
-        worstQueryTime = 0,
-        worstSpecialTime = 0,
-        worstLogicTime = 0,
-        worstRenderTime = 0,
-        worstCpuTime = 0,
-        content = '';           // The HTML to render.
-
-    if (includeSpecialTime == 1) {
-      // Standard mode, do include ST (special time).
-      st = true;
-      avgw = 9;
-      worw = 7;
-    }
-    else if (includeSpecialTime == 2) {
-      // Compact mode.
-      cp = true;
-      avgw = 6;
-      worw = 5;
-    }
-
-    for (var i = 0; i < commands.length; i++) {
-      content += '<tr><td class="admconfitem">'
-        + (!cp ? '<a href="' + detail + commands[i].command + '">' : '')
-        + abbrTruncate(commands[i].command, 30)
-        + (!cp ? '</a>' : '')
-        + '</td><td class="admconfintvalue'
-        + ((commands[i].currentload >= concurrencyHighlight) ? ' exceptional' : (commands[i].currentload == 0 ? ' inactive' : '')) + '">'
-        + commands[i].currentload + '</td>'
-        + '<td class="admconfintvalue">' + commands[i].count + '</td>'
-        + '<td class="admconfintvalue' + (commands[i].ci != null ? '">' + commands[i].ci.count : ' inactive">--') + '</td>'
-        + '<td></td>';
-  
-      totalRequests += commands[i].count;
-      totalConcurrent += commands[i].currentload;
-  
-      if (commands[i].ci != null) {
-        content += (!cp ? '<td class="admconfintvalue">' + commands[i].ci.avgdisp + '</td>' : '')
-          + '<td class="admconfintvalue">' + commands[i].ci.avgqr + '</td>'
-          + (!cp ? '<td class="admconfintvalue">' + commands[i].ci.avgqe + '</td>' : '')
-          + '<td class="admconfintvalue">' + commands[i].ci.avgqt + '</td>'
-          + (st ? '<td class="admconfintvalue">' + commands[i].ci.avgsp + '</td>' : '')
-          + '<td class="admconfintvalue">' + commands[i].ci.avglg + '</td>'
-          + '<td class="admconfintvalue">' + commands[i].ci.avgrn + '</td>'
-          + '<td class="admconfintvalue">' + commands[i].ci.avgcp + '</td>'
-          + '<td class="admconfintvalue">' + commands[i].ci.avgto + '</td>'
-          + '<td></td><td class="admconfintvalue'
-            + ((commands[i].ci.worqr > commands[i].ci.avgqr * exceptionalCoefficient) ? ' exceptional' : '') + '">' + commands[i].ci.worqr + '</td>'
-          + (!cp ? '<td class="admconfintvalue' : '')
-            + (!cp ? ((commands[i].ci.worqe > commands[i].ci.avgqe * exceptionalCoefficient) ? ' exceptional' : '') + '">' + commands[i].ci.worqe + '</td>' : '')
-          + '<td class="admconfintvalue'
-            + ((commands[i].ci.worqt > commands[i].ci.avgqt * exceptionalCoefficient) ? ' exceptional' : '') + '">' + commands[i].ci.worqt + '</td>'
-          + (st ? '<td class="admconfintvalue' : '')
-            + (st ? ((commands[i].ci.worsp > commands[i].ci.avgsp * exceptionalCoefficient) ? ' exceptional' : '') + '">' + commands[i].ci.worsp + '</td>' : '')
-          + '<td class="admconfintvalue'
-            + ((commands[i].ci.worlg > commands[i].ci.avglg * exceptionalCoefficient) ? ' exceptional' : '') + '">' + commands[i].ci.worlg + '</td>'
-          + '<td class="admconfintvalue'
-            + ((commands[i].ci.worrn > commands[i].ci.avgrn * exceptionalCoefficient) ? ' exceptional' : '') + '">' + commands[i].ci.worrn + '</td>'
-          + '<td class="admconfintvalue'
-            + ((commands[i].ci.worcp > commands[i].ci.avgcp * exceptionalCoefficient) ? ' exceptional' : '') + '">' + commands[i].ci.worcp + '</td>';
-  
-        lastHourRequests += commands[i].ci.count;
-        totalDispatches += (commands[i].ci.count * commands[i].ci.avgdisp);
-        totalQueries += (commands[i].ci.count * commands[i].ci.avgqr);
-        totalQueryErrors += (commands[i].ci.count * commands[i].ci.avgqe);
-        totalQueryTime += (commands[i].ci.count * commands[i].ci.avgqt);
-        if (st) {
-          totalSpecialTime += (commands[i].ci.count * commands[i].ci.avgsp);
-        }
-        totalLogicTime += (commands[i].ci.count * commands[i].ci.avglg);
-        totalRenderTime += (commands[i].ci.count * commands[i].ci.avgrn);
-        totalCpuTime += (commands[i].ci.count * commands[i].ci.avgcp);
-        totalTotalTime += (commands[i].ci.count * commands[i].ci.avgto);
-  
-        if (commands[i].ci.worqr > worstQueries) {
-          worstQueries = commands[i].ci.worqr;
-        }
-        if (commands[i].ci.worqe > worstQueryErrors) {
-          worstQueryErrors = commands[i].ci.worqe;
-        }
-        if (commands[i].ci.worqt > worstQueryTime) {
-          worstQueryTime = commands[i].ci.worqt;
-        }
-        if (commands[i].ci.worsp > worstSpecialTime) {
-          worstSpecialTime = commands[i].ci.worsp;
-        }
-        if (commands[i].ci.worlg > worstLogicTime) {
-          worstLogicTime = commands[i].ci.worlg;
-        }
-        if (commands[i].ci.worrn > worstRenderTime) {
-          worstRenderTime = commands[i].ci.worrn;
-        }
-        if (commands[i].ci.worcp > worstCpuTime) {
-          worstCpuTime = commands[i].ci.worcp;
-        }
-      }
-      else {
-        for (var k = 0; k < avgw; k++) {
-          content += '<td class="admconfintvalue inactive">--</td>';
-        }
-        content += '<td></td>';
-        for (var k = 0; k < worw; k++) {
-          content += '<td class="admconfintvalue inactive">--</td>';
-        }
-      }
-  
-      if (!cp) {
-        content += '<td></td><td class="admconfvalue">' + standardTimeString(new Date(commands[i].last.time)) + '</td>'
-          + '<td class="admconfintvalue">' + commands[i].last.disp + '</td>'
-          + '<td class="admconfintvalue">' + commands[i].last.queries + '</td>'
-          + '<td class="admconfintvalue">' + commands[i].last.queryexc + '</td>'
-          + '<td class="admconfintvalue">' + commands[i].last.querytime + '</td>'
-          + (includeSpecialTime == 1 ? '<td class="admconfintvalue">' + commands[i].last.special + '</td>' : '')
-          + '<td class="admconfintvalue">' + commands[i].last.logic + '</td>'
-          + '<td class="admconfintvalue">' + commands[i].last.render + '</td>'
-          + '<td class="admconfintvalue">' + commands[i].last.cpu + '</td>'
-          + '<td class="admconfintvalue">' + commands[i].last.total + '</td>'
-          + '</tr>';
-      }
-    }
-  
-    content += '<tr class="admplainsubheader"><td colspan="4">Totals</td><td></td>'
-      + '<td colspan="' + avgw + '">Averages across all commands</td><td></td>'
-      + '<td colspan="' + worw + '">Worst across all commands</td></tr>'
-      + '<tr><td class="admconfitem"><b>' + commands.length + ' command' + (commands.length == 1 ? '' : 's')
-      + '</b></td><td class="admconfintvalue">' + totalConcurrent + '</td>'
-      + '<td class="admconfintvalue">' + totalRequests + '</td>'
-      + '<td class="admconfintvalue">' + lastHourRequests + '</td>'
-      + '<td></td>';
-  
-    if (lastHourRequests > 0) {
-      content += (!cp ? '<td class="admconfintvalue">' + Math.floor(totalDispatches / lastHourRequests) + '</td>' : '')
-        + '<td class="admconfintvalue">' + Math.floor(totalQueries / lastHourRequests) + '</td>'
-        + (!cp ? '<td class="admconfintvalue">' + Math.floor(totalQueryErrors / lastHourRequests) + '</td>' : '')
-        + '<td class="admconfintvalue">' + Math.floor(totalQueryTime / lastHourRequests) + '</td>'
-        + (includeSpecialTime == 1 ? '<td class="admconfintvalue">' + Math.floor(totalSpecialTime / lastHourRequests) + '</td>' : '')
-        + '<td class="admconfintvalue">' + Math.floor(totalLogicTime / lastHourRequests) + '</td>'
-        + '<td class="admconfintvalue">' + Math.floor(totalRenderTime / lastHourRequests) + '</td>'
-        + '<td class="admconfintvalue">' + Math.floor(totalCpuTime / lastHourRequests) + '</td>'
-        + '<td class="admconfintvalue">' + Math.floor(totalTotalTime / lastHourRequests) + '</td>'
-        + '<td></td>'
-        + '<td class="admconfintvalue">' + worstQueries + '</td>'
-        + (!cp ? '<td class="admconfintvalue">' + worstQueryErrors + '</td>' : '')
-        + '<td class="admconfintvalue">' + worstQueryTime + '</td>'
-        + (includeSpecialTime == 1 ? '<td class="admconfintvalue">' + worstSpecialTime + '</td>' : '')
-        + '<td class="admconfintvalue">' + worstLogicTime + '</td>'
-        + '<td class="admconfintvalue">' + worstRenderTime + '</td>'
-        + '<td class="admconfintvalue">' + worstCpuTime + '</td>'
-        + '</tr>';
-    }
-    else {
-      for (var k = 0; k < avgw; k++) {
-        content += '<td class="admconfintvalue inactive">--</td>';
-      }
-      content += '<td></td>';
-      for (var k = 0; k < worw; k++) {
-        content += '<td class="admconfintvalue inactive">--</td>';
-      }
-    }
-  
-    return content;
-  }
-  
-  /** Render the current requests in the performance monitor. */
-  function renderCurrentRequestList(requests, detail, includeSpecialTime) {
-
-    var st = false,             // Standard mode.
-        cp = false,             // Compact mode.
-        cols = 8,               // Width in columns.
-        totalDispatches = 0,    // Rough totals for averages across all commands.
-        totalQueries = 0,
-        totalQueryErrors = 0,
-        totalQueryTime = 0,
-        totalLogicTime = 0,
-        totalRenderTime = 0,
-        totalSpecialTime = 0,
-        totalTotalTime = 0,
-        totalCpuTime = 0,
-        worstQueries = 0,       // Worsts across all commands.
-        worstQueryErrors = 0,
-        worstQueryTime = 0,
-        worstSpecialTime = 0,
-        worstLogicTime = 0,
-        worstRenderTime = 0,
-        worstCpuTime = 0,
-        content = '';           // The HTML to render.
-
-    if (includeSpecialTime == 1) {
-      // Standard mode, include ST.
-      st = true;
-      cols = 9;
-    }
-    else if (includeSpecialTime == 2) {
-      // Compact mode.
-      cp = true;
-    }
-
-    for (var i = 0; i < requests.length; i++) {
-      content += '<tr><td class="admconfitem">'
-        + (!cp ? '<a href="' + detail + requests[i].thread + '">' : '')
-        + abbrTruncate(requests[i].command, 30)
-        + (!cp ? '</a>' : '')
-        + '</td><td class="admconfintvalue">' + requests[i].reqnum + '</td>'
-        + '<td class="admconfintvalue">' + requests[i].thread + '</td>'
-        + '<td class="admconfvalue">' + standardTimeString(new Date(requests[i].time)) + '</td>'
-        + '<td></td>'
-        + '<td class="admconfintvalue">' + requests[i].disp + '</td>'
-        + '<td class="admconfintvalue">' + requests[i].queries + '</td>'
-        + '<td class="admconfintvalue">' + requests[i].queryexc + '</td>'
-        + '<td class="admconfintvalue">' + requests[i].querytime + ' ms</td>'
-        + (st ? '<td class="admconfintvalue">' + requests[i].special + ' ms</td>' : '')
-        + '<td class="admconfintvalue">' + requests[i].logic + ' ms</td>'
-        + '<td class="admconfintvalue">' + requests[i].render + ' ms</td>'
-        + '<td class="admconfintvalue">' + requests[i].cpu + ' ms</td>'
-        + '<td class="admconfintvalue">' + requests[i].total + ' ms</td>'
-        + '</tr>';
-
-      totalDispatches += requests[i].disp;
-      totalQueries += requests[i].queries;
-      totalQueryErrors += requests[i].queryexc;
-      totalQueryTime += requests[i].querytime;
-      totalLogicTime += requests[i].logic;
-      totalSpecialTime += requests[i].special;
-      totalRenderTime += requests[i].render;
-      totalCpuTime += requests[i].cpu;
-      totalTotalTime += requests[i].total;
-    }
-
-    content += '<tr class="admplainsubheader"><td colspan="4">Totals</td><td></td>'
-      + '<td colspan="' + cols + '">Total across all commands</td></tr>'
-      + '<tr><td colspan="4" class="admconfitem"><b>' + requests.length + ' command' + (requests.length == 1 ? '' : 's')
-      + '</b></td><td></td>';
-
-    content += '<td class="admconfintvalue">' + totalDispatches + '</td>'
-      + '<td class="admconfintvalue">' + totalQueries + '</td>'
-      + '<td class="admconfintvalue">' + totalQueryErrors + '</td>'
-      + '<td class="admconfintvalue">' + totalQueryTime + ' ms</td>'
-      + (st ? '<td class="admconfintvalue">' + totalSpecialTime + ' ms</td>' : '')
-      + '<td class="admconfintvalue">' + totalLogicTime + ' ms</td>'
-      + '<td class="admconfintvalue">' + totalRenderTime + ' ms</td>'
-      + '<td class="admconfintvalue">' + totalCpuTime + ' ms</td>'
-      + '<td class="admconfintvalue">' + totalTotalTime + ' ms</td>';
-      + '</tr>';
-
-    return content;
-  }
-
-  /** Use Flot to render a chart of health over time. */
-  function renderHealthMonitorFlot(h, timezoneShift, interval, targetElement) {
-    var disps = new Array(),
-        dispc = new Array(),
-        memto = new Array(),
-        memfr = new Array(),
-        memus = new Array(),
-        pages = new Array(),
-        pagec = new Array(),
-        quers = new Array(),
-        querc = new Array(),
-        threa = new Array(),
-        block = new Array(),
-        waits = new Array(),
-        blcwa = new Array(),
-        lastTime,
-        healthOptions,
-        healthData;
-
-    // Build the series arrays.
-    for (var i = 0; i < h.length; i++) {
-      if (h[i] != null) {
-        lastTime = h[i].start + timezoneShift;
-        disps[i] = [lastTime, h[i].disps];
-        dispc[i] = [lastTime, h[i].dispcon];
-        if (h[i].totalmem > 0) {
-          memto[i] = [lastTime, h[i].totalmem];
-          memfr[i] = [lastTime, h[i].freemem];
-          memus[i] = [lastTime, h[i].totalmem - h[i].freemem];
-        }
-        pages[i] = [lastTime, h[i].pages];
-        pagec[i] = [lastTime, h[i].pagecon];
-        quers[i] = [lastTime, h[i].queries];
-        querc[i] = [lastTime, h[i].querycon];
-        if (h[i].threads > 0) {
-          threa[i] = [lastTime, h[i].threads];
-          block[i] = [lastTime, h[i].blocked];
-          waits[i] = [lastTime, h[i].waiting];
-          blcwa[i] = [lastTime, h[i].waiting + h[i].blocked];
-        }
-      }
-    }
-  
-    // Flot rendering options.
-    healthOptions = {
-      xaxis: { mode: "time", timeformat: "%h:%M", minTickSize: [1, "minute"] },
-      legend: { position: "nw" },
-      yaxis: { labelWidth: 25, min: 0, minTickSize: 1, tickDecimals: 0 },
-      y2axis: { labelWidth: 50, min: 0, minTickSize: 1, tickDecimals: 0, tickFormatter: function(number) {
-          return Math.floor(number / 1024 / 1024) + " M";
-        } },
-      selection: { mode: "x" },
-      colors: [ "#5060F0" ],
-      grid: { hoverable: true, backgroundColor: { colors: ["#FFF", "#FFF", "#FFF", "#F0F4F8"] },
-      series: { stack: false } }
-    };
-
-    // Data for Flot to render.
-    healthData =
-      [
-       { label: 'Used heap &gt;', color: '#B88810', data: memus, yaxis: 2 },
-       { label: '&lt; Pages', color: '#90A0FF', data: pages },
-       { label: '&lt; Dispatches', color: '#0000E0', data: disps },
-       { label: '&lt; Queries', color: '#C00000', data: quers },
-       { label: '&lt; Blocked/Waiting', color: '#009000', data: blcwa },
-       { label: 'Total heap &gt;', color: '#C0C0C2', data: memto, yaxis: 2 }
-      ];
-  
-    $.plot($(targetElement), healthData, healthOptions);
-  }
-
-  return {
-    standardDateString: standardDateString,
-    standardTimeString: standardTimeString,
-    abbrTruncate: abbrTruncate,
-    renderPerformanceMonitorList: renderPerformanceMonitorList,
-    renderCurrentRequestList: renderCurrentRequestList,
-    renderHealthMonitorFlot: renderHealthMonitorFlot
-  };
-
-})();
-
-
-

+ 0 - 1427
gemini/Docroot/js/excanvas.js

@@ -1,1427 +0,0 @@
-// Copyright 2006 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-
-// Known Issues:
-//
-// * Patterns only support repeat.
-// * Radial gradient are not implemented. The VML version of these look very
-//   different from the canvas one.
-// * Clipping paths are not implemented.
-// * Coordsize. The width and height attribute have higher priority than the
-//   width and height style values which isn't correct.
-// * Painting mode isn't implemented.
-// * Canvas width/height should is using content-box by default. IE in
-//   Quirks mode will draw the canvas using border-box. Either change your
-//   doctype to HTML5
-//   (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
-//   or use Box Sizing Behavior from WebFX
-//   (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
-// * Non uniform scaling does not correctly scale strokes.
-// * Filling very large shapes (above 5000 points) is buggy.
-// * Optimize. There is always room for speed improvements.
-
-// Only add this code if we do not already have a canvas implementation
-if (!document.createElement('canvas').getContext) {
-
-(function() {
-
-  // alias some functions to make (compiled) code shorter
-  var m = Math;
-  var mr = m.round;
-  var ms = m.sin;
-  var mc = m.cos;
-  var abs = m.abs;
-  var sqrt = m.sqrt;
-
-  // this is used for sub pixel precision
-  var Z = 10;
-  var Z2 = Z / 2;
-
-  /**
-   * This funtion is assigned to the <canvas> elements as element.getContext().
-   * @this {HTMLElement}
-   * @return {CanvasRenderingContext2D_}
-   */
-  function getContext() {
-    return this.context_ ||
-        (this.context_ = new CanvasRenderingContext2D_(this));
-  }
-
-  var slice = Array.prototype.slice;
-
-  /**
-   * Binds a function to an object. The returned function will always use the
-   * passed in {@code obj} as {@code this}.
-   *
-   * Example:
-   *
-   *   g = bind(f, obj, a, b)
-   *   g(c, d) // will do f.call(obj, a, b, c, d)
-   *
-   * @param {Function} f The function to bind the object to
-   * @param {Object} obj The object that should act as this when the function
-   *     is called
-   * @param {*} var_args Rest arguments that will be used as the initial
-   *     arguments when the function is called
-   * @return {Function} A new function that has bound this
-   */
-  function bind(f, obj, var_args) {
-    var a = slice.call(arguments, 2);
-    return function() {
-      return f.apply(obj, a.concat(slice.call(arguments)));
-    };
-  }
-
-  function encodeHtmlAttribute(s) {
-    return String(s).replace(/&/g, '&amp;').replace(/"/g, '&quot;');
-  }
-
-  function addNamespacesAndStylesheet(doc) {
-    // create xmlns
-    if (!doc.namespaces['g_vml_']) {
-      doc.namespaces.add('g_vml_', 'urn:schemas-microsoft-com:vml',
-                         '#default#VML');
-
-    }
-    if (!doc.namespaces['g_o_']) {
-      doc.namespaces.add('g_o_', 'urn:schemas-microsoft-com:office:office',
-                         '#default#VML');
-    }
-
-    // Setup default CSS.  Only add one style sheet per document
-    if (!doc.styleSheets['ex_canvas_']) {
-      var ss = doc.createStyleSheet();
-      ss.owningElement.id = 'ex_canvas_';
-      ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
-          // default size is 300x150 in Gecko and Opera
-          'text-align:left;width:300px;height:150px}';
-    }
-  }
-
-  // Add namespaces and stylesheet at startup.
-  addNamespacesAndStylesheet(document);
-
-  var G_vmlCanvasManager_ = {
-    init: function(opt_doc) {
-      if (/MSIE/.test(navigator.userAgent) && !window.opera) {
-        var doc = opt_doc || document;
-        // Create a dummy element so that IE will allow canvas elements to be
-        // recognized.
-        doc.createElement('canvas');
-        doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
-      }
-    },
-
-    init_: function(doc) {
-      // find all canvas elements
-      var els = doc.getElementsByTagName('canvas');
-      for (var i = 0; i < els.length; i++) {
-        this.initElement(els[i]);
-      }
-    },
-
-    /**
-     * Public initializes a canvas element so that it can be used as canvas
-     * element from now on. This is called automatically before the page is
-     * loaded but if you are creating elements using createElement you need to
-     * make sure this is called on the element.
-     * @param {HTMLElement} el The canvas element to initialize.
-     * @return {HTMLElement} the element that was created.
-     */
-    initElement: function(el) {
-      if (!el.getContext) {
-        el.getContext = getContext;
-
-        // Add namespaces and stylesheet to document of the element.
-        addNamespacesAndStylesheet(el.ownerDocument);
-
-        // Remove fallback content. There is no way to hide text nodes so we
-        // just remove all childNodes. We could hide all elements and remove
-        // text nodes but who really cares about the fallback content.
-        el.innerHTML = '';
-
-        // do not use inline function because that will leak memory
-        el.attachEvent('onpropertychange', onPropertyChange);
-        el.attachEvent('onresize', onResize);
-
-        var attrs = el.attributes;
-        if (attrs.width && attrs.width.specified) {
-          // TODO: use runtimeStyle and coordsize
-          // el.getContext().setWidth_(attrs.width.nodeValue);
-          el.style.width = attrs.width.nodeValue + 'px';
-        } else {
-          el.width = el.clientWidth;
-        }
-        if (attrs.height && attrs.height.specified) {
-          // TODO: use runtimeStyle and coordsize
-          // el.getContext().setHeight_(attrs.height.nodeValue);
-          el.style.height = attrs.height.nodeValue + 'px';
-        } else {
-          el.height = el.clientHeight;
-        }
-        //el.getContext().setCoordsize_()
-      }
-      return el;
-    }
-  };
-
-  function onPropertyChange(e) {
-    var el = e.srcElement;
-
-    switch (e.propertyName) {
-      case 'width':
-        el.getContext().clearRect();
-        el.style.width = el.attributes.width.nodeValue + 'px';
-        // In IE8 this does not trigger onresize.
-        el.firstChild.style.width =  el.clientWidth + 'px';
-        break;
-      case 'height':
-        el.getContext().clearRect();
-        el.style.height = el.attributes.height.nodeValue + 'px';
-        el.firstChild.style.height = el.clientHeight + 'px';
-        break;
-    }
-  }
-
-  function onResize(e) {
-    var el = e.srcElement;
-    if (el.firstChild) {
-      el.firstChild.style.width =  el.clientWidth + 'px';
-      el.firstChild.style.height = el.clientHeight + 'px';
-    }
-  }
-
-  G_vmlCanvasManager_.init();
-
-  // precompute "00" to "FF"
-  var decToHex = [];
-  for (var i = 0; i < 16; i++) {
-    for (var j = 0; j < 16; j++) {
-      decToHex[i * 16 + j] = i.toString(16) + j.toString(16);
-    }
-  }
-
-  function createMatrixIdentity() {
-    return [
-      [1, 0, 0],
-      [0, 1, 0],
-      [0, 0, 1]
-    ];
-  }
-
-  function matrixMultiply(m1, m2) {
-    var result = createMatrixIdentity();
-
-    for (var x = 0; x < 3; x++) {
-      for (var y = 0; y < 3; y++) {
-        var sum = 0;
-
-        for (var z = 0; z < 3; z++) {
-          sum += m1[x][z] * m2[z][y];
-        }
-
-        result[x][y] = sum;
-      }
-    }
-    return result;
-  }
-
-  function copyState(o1, o2) {
-    o2.fillStyle     = o1.fillStyle;
-    o2.lineCap       = o1.lineCap;
-    o2.lineJoin      = o1.lineJoin;
-    o2.lineWidth     = o1.lineWidth;
-    o2.miterLimit    = o1.miterLimit;
-    o2.shadowBlur    = o1.shadowBlur;
-    o2.shadowColor   = o1.shadowColor;
-    o2.shadowOffsetX = o1.shadowOffsetX;
-    o2.shadowOffsetY = o1.shadowOffsetY;
-    o2.strokeStyle   = o1.strokeStyle;
-    o2.globalAlpha   = o1.globalAlpha;
-    o2.font          = o1.font;
-    o2.textAlign     = o1.textAlign;
-    o2.textBaseline  = o1.textBaseline;
-    o2.arcScaleX_    = o1.arcScaleX_;
-    o2.arcScaleY_    = o1.arcScaleY_;
-    o2.lineScale_    = o1.lineScale_;
-  }
-
-  var colorData = {
-    aliceblue: '#F0F8FF',
-    antiquewhite: '#FAEBD7',
-    aquamarine: '#7FFFD4',
-    azure: '#F0FFFF',
-    beige: '#F5F5DC',
-    bisque: '#FFE4C4',
-    black: '#000000',
-    blanchedalmond: '#FFEBCD',
-    blueviolet: '#8A2BE2',
-    brown: '#A52A2A',
-    burlywood: '#DEB887',
-    cadetblue: '#5F9EA0',
-    chartreuse: '#7FFF00',
-    chocolate: '#D2691E',
-    coral: '#FF7F50',
-    cornflowerblue: '#6495ED',
-    cornsilk: '#FFF8DC',
-    crimson: '#DC143C',
-    cyan: '#00FFFF',
-    darkblue: '#00008B',
-    darkcyan: '#008B8B',
-    darkgoldenrod: '#B8860B',
-    darkgray: '#A9A9A9',
-    darkgreen: '#006400',
-    darkgrey: '#A9A9A9',
-    darkkhaki: '#BDB76B',
-    darkmagenta: '#8B008B',
-    darkolivegreen: '#556B2F',
-    darkorange: '#FF8C00',
-    darkorchid: '#9932CC',
-    darkred: '#8B0000',
-    darksalmon: '#E9967A',
-    darkseagreen: '#8FBC8F',
-    darkslateblue: '#483D8B',
-    darkslategray: '#2F4F4F',
-    darkslategrey: '#2F4F4F',
-    darkturquoise: '#00CED1',
-    darkviolet: '#9400D3',
-    deeppink: '#FF1493',
-    deepskyblue: '#00BFFF',
-    dimgray: '#696969',
-    dimgrey: '#696969',
-    dodgerblue: '#1E90FF',
-    firebrick: '#B22222',
-    floralwhite: '#FFFAF0',
-    forestgreen: '#228B22',
-    gainsboro: '#DCDCDC',
-    ghostwhite: '#F8F8FF',
-    gold: '#FFD700',
-    goldenrod: '#DAA520',
-    grey: '#808080',
-    greenyellow: '#ADFF2F',
-    honeydew: '#F0FFF0',
-    hotpink: '#FF69B4',
-    indianred: '#CD5C5C',
-    indigo: '#4B0082',
-    ivory: '#FFFFF0',
-    khaki: '#F0E68C',
-    lavender: '#E6E6FA',
-    lavenderblush: '#FFF0F5',
-    lawngreen: '#7CFC00',
-    lemonchiffon: '#FFFACD',
-    lightblue: '#ADD8E6',
-    lightcoral: '#F08080',
-    lightcyan: '#E0FFFF',
-    lightgoldenrodyellow: '#FAFAD2',
-    lightgreen: '#90EE90',
-    lightgrey: '#D3D3D3',
-    lightpink: '#FFB6C1',
-    lightsalmon: '#FFA07A',
-    lightseagreen: '#20B2AA',
-    lightskyblue: '#87CEFA',
-    lightslategray: '#778899',
-    lightslategrey: '#778899',
-    lightsteelblue: '#B0C4DE',
-    lightyellow: '#FFFFE0',
-    limegreen: '#32CD32',
-    linen: '#FAF0E6',
-    magenta: '#FF00FF',
-    mediumaquamarine: '#66CDAA',
-    mediumblue: '#0000CD',
-    mediumorchid: '#BA55D3',
-    mediumpurple: '#9370DB',
-    mediumseagreen: '#3CB371',
-    mediumslateblue: '#7B68EE',
-    mediumspringgreen: '#00FA9A',
-    mediumturquoise: '#48D1CC',
-    mediumvioletred: '#C71585',
-    midnightblue: '#191970',
-    mintcream: '#F5FFFA',
-    mistyrose: '#FFE4E1',
-    moccasin: '#FFE4B5',
-    navajowhite: '#FFDEAD',
-    oldlace: '#FDF5E6',
-    olivedrab: '#6B8E23',
-    orange: '#FFA500',
-    orangered: '#FF4500',
-    orchid: '#DA70D6',
-    palegoldenrod: '#EEE8AA',
-    palegreen: '#98FB98',
-    paleturquoise: '#AFEEEE',
-    palevioletred: '#DB7093',
-    papayawhip: '#FFEFD5',
-    peachpuff: '#FFDAB9',
-    peru: '#CD853F',
-    pink: '#FFC0CB',
-    plum: '#DDA0DD',
-    powderblue: '#B0E0E6',
-    rosybrown: '#BC8F8F',
-    royalblue: '#4169E1',
-    saddlebrown: '#8B4513',
-    salmon: '#FA8072',
-    sandybrown: '#F4A460',
-    seagreen: '#2E8B57',
-    seashell: '#FFF5EE',
-    sienna: '#A0522D',
-    skyblue: '#87CEEB',
-    slateblue: '#6A5ACD',
-    slategray: '#708090',
-    slategrey: '#708090',
-    snow: '#FFFAFA',
-    springgreen: '#00FF7F',
-    steelblue: '#4682B4',
-    tan: '#D2B48C',
-    thistle: '#D8BFD8',
-    tomato: '#FF6347',
-    turquoise: '#40E0D0',
-    violet: '#EE82EE',
-    wheat: '#F5DEB3',
-    whitesmoke: '#F5F5F5',
-    yellowgreen: '#9ACD32'
-  };
-
-
-  function getRgbHslContent(styleString) {
-    var start = styleString.indexOf('(', 3);
-    var end = styleString.indexOf(')', start + 1);
-    var parts = styleString.substring(start + 1, end).split(',');
-    // add alpha if needed
-    if (parts.length == 4 && styleString.substr(3, 1) == 'a') {
-      alpha = Number(parts[3]);
-    } else {
-      parts[3] = 1;
-    }
-    return parts;
-  }
-
-  function percent(s) {
-    return parseFloat(s) / 100;
-  }
-
-  function clamp(v, min, max) {
-    return Math.min(max, Math.max(min, v));
-  }
-
-  function hslToRgb(parts){
-    var r, g, b;
-    h = parseFloat(parts[0]) / 360 % 360;
-    if (h < 0)
-      h++;
-    s = clamp(percent(parts[1]), 0, 1);
-    l = clamp(percent(parts[2]), 0, 1);
-    if (s == 0) {
-      r = g = b = l; // achromatic
-    } else {
-      var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
-      var p = 2 * l - q;
-      r = hueToRgb(p, q, h + 1 / 3);
-      g = hueToRgb(p, q, h);
-      b = hueToRgb(p, q, h - 1 / 3);
-    }
-
-    return '#' + decToHex[Math.floor(r * 255)] +
-        decToHex[Math.floor(g * 255)] +
-        decToHex[Math.floor(b * 255)];
-  }
-
-  function hueToRgb(m1, m2, h) {
-    if (h < 0)
-      h++;
-    if (h > 1)
-      h--;
-
-    if (6 * h < 1)
-      return m1 + (m2 - m1) * 6 * h;
-    else if (2 * h < 1)
-      return m2;
-    else if (3 * h < 2)
-      return m1 + (m2 - m1) * (2 / 3 - h) * 6;
-    else
-      return m1;
-  }
-
-  function processStyle(styleString) {
-    var str, alpha = 1;
-
-    styleString = String(styleString);
-    if (styleString.charAt(0) == '#') {
-      str = styleString;
-    } else if (/^rgb/.test(styleString)) {
-      var parts = getRgbHslContent(styleString);
-      var str = '#', n;
-      for (var i = 0; i < 3; i++) {
-        if (parts[i].indexOf('%') != -1) {
-          n = Math.floor(percent(parts[i]) * 255);
-        } else {
-          n = Number(parts[i]);
-        }
-        str += decToHex[clamp(n, 0, 255)];
-      }
-      alpha = parts[3];
-    } else if (/^hsl/.test(styleString)) {
-      var parts = getRgbHslContent(styleString);
-      str = hslToRgb(parts);
-      alpha = parts[3];
-    } else {
-      str = colorData[styleString] || styleString;
-    }
-    return {color: str, alpha: alpha};
-  }
-
-  var DEFAULT_STYLE = {
-    style: 'normal',
-    variant: 'normal',
-    weight: 'normal',
-    size: 10,
-    family: 'sans-serif'
-  };
-
-  // Internal text style cache
-  var fontStyleCache = {};
-
-  function processFontStyle(styleString) {
-    if (fontStyleCache[styleString]) {
-      return fontStyleCache[styleString];
-    }
-
-    var el = document.createElement('div');
-    var style = el.style;
-    try {
-      style.font = styleString;
-    } catch (ex) {
-      // Ignore failures to set to invalid font.
-    }
-
-    return fontStyleCache[styleString] = {
-      style: style.fontStyle || DEFAULT_STYLE.style,
-      variant: style.fontVariant || DEFAULT_STYLE.variant,
-      weight: style.fontWeight || DEFAULT_STYLE.weight,
-      size: style.fontSize || DEFAULT_STYLE.size,
-      family: style.fontFamily || DEFAULT_STYLE.family
-    };
-  }
-
-  function getComputedStyle(style, element) {
-    var computedStyle = {};
-
-    for (var p in style) {
-      computedStyle[p] = style[p];
-    }
-
-    // Compute the size
-    var canvasFontSize = parseFloat(element.currentStyle.fontSize),
-        fontSize = parseFloat(style.size);
-
-    if (typeof style.size == 'number') {
-      computedStyle.size = style.size;
-    } else if (style.size.indexOf('px') != -1) {
-      computedStyle.size = fontSize;
-    } else if (style.size.indexOf('em') != -1) {
-      computedStyle.size = canvasFontSize * fontSize;
-    } else if(style.size.indexOf('%') != -1) {
-      computedStyle.size = (canvasFontSize / 100) * fontSize;
-    } else if (style.size.indexOf('pt') != -1) {
-      computedStyle.size = fontSize / .75;
-    } else {
-      computedStyle.size = canvasFontSize;
-    }
-
-    // Different scaling between normal text and VML text. This was found using
-    // trial and error to get the same size as non VML text.
-    computedStyle.size *= 0.981;
-
-    return computedStyle;
-  }
-
-  function buildStyle(style) {
-    return style.style + ' ' + style.variant + ' ' + style.weight + ' ' +
-        style.size + 'px ' + style.family;
-  }
-
-  function processLineCap(lineCap) {
-    switch (lineCap) {
-      case 'butt':
-        return 'flat';
-      case 'round':
-        return 'round';
-      case 'square':
-      default:
-        return 'square';
-    }
-  }
-
-  /**
-   * This class implements CanvasRenderingContext2D interface as described by
-   * the WHATWG.
-   * @param {HTMLElement} surfaceElement The element that the 2D context should
-   * be associated with
-   */
-  function CanvasRenderingContext2D_(surfaceElement) {
-    this.m_ = createMatrixIdentity();
-
-    this.mStack_ = [];
-    this.aStack_ = [];
-    this.currentPath_ = [];
-
-    // Canvas context properties
-    this.strokeStyle = '#000';
-    this.fillStyle = '#000';
-
-    this.lineWidth = 1;
-    this.lineJoin = 'miter';
-    this.lineCap = 'butt';
-    this.miterLimit = Z * 1;
-    this.globalAlpha = 1;
-    this.font = '10px sans-serif';
-    this.textAlign = 'left';
-    this.textBaseline = 'alphabetic';
-    this.canvas = surfaceElement;
-
-    var el = surfaceElement.ownerDocument.createElement('div');
-    el.style.width =  surfaceElement.clientWidth + 'px';
-    el.style.height = surfaceElement.clientHeight + 'px';
-    el.style.overflow = 'hidden';
-    el.style.position = 'absolute';
-    surfaceElement.appendChild(el);
-
-    this.element_ = el;
-    this.arcScaleX_ = 1;
-    this.arcScaleY_ = 1;
-    this.lineScale_ = 1;
-  }
-
-  var contextPrototype = CanvasRenderingContext2D_.prototype;
-  contextPrototype.clearRect = function() {
-    if (this.textMeasureEl_) {
-      this.textMeasureEl_.removeNode(true);
-      this.textMeasureEl_ = null;
-    }
-    this.element_.innerHTML = '';
-  };
-
-  contextPrototype.beginPath = function() {
-    // TODO: Branch current matrix so that save/restore has no effect
-    //       as per safari docs.
-    this.currentPath_ = [];
-  };
-
-  contextPrototype.moveTo = function(aX, aY) {
-    var p = this.getCoords_(aX, aY);
-    this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
-    this.currentX_ = p.x;
-    this.currentY_ = p.y;
-  };
-
-  contextPrototype.lineTo = function(aX, aY) {
-    var p = this.getCoords_(aX, aY);
-    this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});
-
-    this.currentX_ = p.x;
-    this.currentY_ = p.y;
-  };
-
-  contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
-                                            aCP2x, aCP2y,
-                                            aX, aY) {
-    var p = this.getCoords_(aX, aY);
-    var cp1 = this.getCoords_(aCP1x, aCP1y);
-    var cp2 = this.getCoords_(aCP2x, aCP2y);
-    bezierCurveTo(this, cp1, cp2, p);
-  };
-
-  // Helper function that takes the already fixed cordinates.
-  function bezierCurveTo(self, cp1, cp2, p) {
-    self.currentPath_.push({
-      type: 'bezierCurveTo',
-      cp1x: cp1.x,
-      cp1y: cp1.y,
-      cp2x: cp2.x,
-      cp2y: cp2.y,
-      x: p.x,
-      y: p.y
-    });
-    self.currentX_ = p.x;
-    self.currentY_ = p.y;
-  }
-
-  contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
-    // the following is lifted almost directly from
-    // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes
-
-    var cp = this.getCoords_(aCPx, aCPy);
-    var p = this.getCoords_(aX, aY);
-
-    var cp1 = {
-      x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
-      y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
-    };
-    var cp2 = {
-      x: cp1.x + (p.x - this.currentX_) / 3.0,
-      y: cp1.y + (p.y - this.currentY_) / 3.0
-    };
-
-    bezierCurveTo(this, cp1, cp2, p);
-  };
-
-  contextPrototype.arc = function(aX, aY, aRadius,
-                                  aStartAngle, aEndAngle, aClockwise) {
-    aRadius *= Z;
-    var arcType = aClockwise ? 'at' : 'wa';
-
-    var xStart = aX + mc(aStartAngle) * aRadius - Z2;
-    var yStart = aY + ms(aStartAngle) * aRadius - Z2;
-
-    var xEnd = aX + mc(aEndAngle) * aRadius - Z2;
-    var yEnd = aY + ms(aEndAngle) * aRadius - Z2;
-
-    // IE won't render arches drawn counter clockwise if xStart == xEnd.
-    if (xStart == xEnd && !aClockwise) {
-      xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
-                       // that can be represented in binary
-    }
-
-    var p = this.getCoords_(aX, aY);
-    var pStart = this.getCoords_(xStart, yStart);
-    var pEnd = this.getCoords_(xEnd, yEnd);
-
-    this.currentPath_.push({type: arcType,
-                           x: p.x,
-                           y: p.y,
-                           radius: aRadius,
-                           xStart: pStart.x,
-                           yStart: pStart.y,
-                           xEnd: pEnd.x,
-                           yEnd: pEnd.y});
-
-  };
-
-  contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
-    this.moveTo(aX, aY);
-    this.lineTo(aX + aWidth, aY);
-    this.lineTo(aX + aWidth, aY + aHeight);
-    this.lineTo(aX, aY + aHeight);
-    this.closePath();
-  };
-
-  contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
-    var oldPath = this.currentPath_;
-    this.beginPath();
-
-    this.moveTo(aX, aY);
-    this.lineTo(aX + aWidth, aY);
-    this.lineTo(aX + aWidth, aY + aHeight);
-    this.lineTo(aX, aY + aHeight);
-    this.closePath();
-    this.stroke();
-
-    this.currentPath_ = oldPath;
-  };
-
-  contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
-    var oldPath = this.currentPath_;
-    this.beginPath();
-
-    this.moveTo(aX, aY);
-    this.lineTo(aX + aWidth, aY);
-    this.lineTo(aX + aWidth, aY + aHeight);
-    this.lineTo(aX, aY + aHeight);
-    this.closePath();
-    this.fill();
-
-    this.currentPath_ = oldPath;
-  };
-
-  contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
-    var gradient = new CanvasGradient_('gradient');
-    gradient.x0_ = aX0;
-    gradient.y0_ = aY0;
-    gradient.x1_ = aX1;
-    gradient.y1_ = aY1;
-    return gradient;
-  };
-
-  contextPrototype.createRadialGradient = function(aX0, aY0, aR0,
-                                                   aX1, aY1, aR1) {
-    var gradient = new CanvasGradient_('gradientradial');
-    gradient.x0_ = aX0;
-    gradient.y0_ = aY0;
-    gradient.r0_ = aR0;
-    gradient.x1_ = aX1;
-    gradient.y1_ = aY1;
-    gradient.r1_ = aR1;
-    return gradient;
-  };
-
-  contextPrototype.drawImage = function(image, var_args) {
-    var dx, dy, dw, dh, sx, sy, sw, sh;
-
-    // to find the original width we overide the width and height
-    var oldRuntimeWidth = image.runtimeStyle.width;
-    var oldRuntimeHeight = image.runtimeStyle.height;
-    image.runtimeStyle.width = 'auto';
-    image.runtimeStyle.height = 'auto';
-
-    // get the original size
-    var w = image.width;
-    var h = image.height;
-
-    // and remove overides
-    image.runtimeStyle.width = oldRuntimeWidth;
-    image.runtimeStyle.height = oldRuntimeHeight;
-
-    if (arguments.length == 3) {
-      dx = arguments[1];
-      dy = arguments[2];
-      sx = sy = 0;
-      sw = dw = w;
-      sh = dh = h;
-    } else if (arguments.length == 5) {
-      dx = arguments[1];
-      dy = arguments[2];
-      dw = arguments[3];
-      dh = arguments[4];
-      sx = sy = 0;
-      sw = w;
-      sh = h;
-    } else if (arguments.length == 9) {
-      sx = arguments[1];
-      sy = arguments[2];
-      sw = arguments[3];
-      sh = arguments[4];
-      dx = arguments[5];
-      dy = arguments[6];
-      dw = arguments[7];
-      dh = arguments[8];
-    } else {
-      throw Error('Invalid number of arguments');
-    }
-
-    var d = this.getCoords_(dx, dy);
-
-    var w2 = sw / 2;
-    var h2 = sh / 2;
-
-    var vmlStr = [];
-
-    var W = 10;
-    var H = 10;
-
-    // For some reason that I've now forgotten, using divs didn't work
-    vmlStr.push(' <g_vml_:group',
-                ' coordsize="', Z * W, ',', Z * H, '"',
-                ' coordorigin="0,0"' ,
-                ' style="width:', W, 'px;height:', H, 'px;position:absolute;');
-
-    // If filters are necessary (rotation exists), create them
-    // filters are bog-slow, so only create them if abbsolutely necessary
-    // The following check doesn't account for skews (which don't exist
-    // in the canvas spec (yet) anyway.
-
-    if (this.m_[0][0] != 1 || this.m_[0][1] ||
-        this.m_[1][1] != 1 || this.m_[1][0]) {
-      var filter = [];
-
-      // Note the 12/21 reversal
-      filter.push('M11=', this.m_[0][0], ',',
-                  'M12=', this.m_[1][0], ',',
-                  'M21=', this.m_[0][1], ',',
-                  'M22=', this.m_[1][1], ',',
-                  'Dx=', mr(d.x / Z), ',',
-                  'Dy=', mr(d.y / Z), '');
-
-      // Bounding box calculation (need to minimize displayed area so that
-      // filters don't waste time on unused pixels.
-      var max = d;
-      var c2 = this.getCoords_(dx + dw, dy);
-      var c3 = this.getCoords_(dx, dy + dh);
-      var c4 = this.getCoords_(dx + dw, dy + dh);
-
-      max.x = m.max(max.x, c2.x, c3.x, c4.x);
-      max.y = m.max(max.y, c2.y, c3.y, c4.y);
-
-      vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z),
-                  'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',
-                  filter.join(''), ", sizingmethod='clip');");
-
-    } else {
-      vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;');
-    }
-
-    vmlStr.push(' ">' ,
-                '<g_vml_:image src="', image.src, '"',
-                ' style="width:', Z * dw, 'px;',
-                ' height:', Z * dh, 'px"',
-                ' cropleft="', sx / w, '"',
-                ' croptop="', sy / h, '"',
-                ' cropright="', (w - sx - sw) / w, '"',
-                ' cropbottom="', (h - sy - sh) / h, '"',
-                ' />',
-                '</g_vml_:group>');
-
-    this.element_.insertAdjacentHTML('BeforeEnd', vmlStr.join(''));
-  };
-
-  contextPrototype.stroke = function(aFill) {
-    var W = 10;
-    var H = 10;
-    // Divide the shape into chunks if it's too long because IE has a limit
-    // somewhere for how long a VML shape can be. This simple division does
-    // not work with fills, only strokes, unfortunately.
-    var chunkSize = 5000;
-
-    var min = {x: null, y: null};
-    var max = {x: null, y: null};
-
-    for (var j = 0; j < this.currentPath_.length; j += chunkSize) {
-      var lineStr = [];
-      var lineOpen = false;
-
-      lineStr.push('<g_vml_:shape',
-                   ' filled="', !!aFill, '"',
-                   ' style="position:absolute;width:', W, 'px;height:', H, 'px;"',
-                   ' coordorigin="0,0"',
-                   ' coordsize="', Z * W, ',', Z * H, '"',
-                   ' stroked="', !aFill, '"',
-                   ' path="');
-
-      var newSeq = false;
-
-      for (var i = j; i < Math.min(j + chunkSize, this.currentPath_.length); i++) {
-        if (i % chunkSize == 0 && i > 0) { // move into position for next chunk
-          lineStr.push(' m ', mr(this.currentPath_[i-1].x), ',', mr(this.currentPath_[i-1].y));
-        }
-
-        var p = this.currentPath_[i];
-        var c;
-
-        switch (p.type) {
-          case 'moveTo':
-            c = p;
-            lineStr.push(' m ', mr(p.x), ',', mr(p.y));
-            break;
-          case 'lineTo':
-            lineStr.push(' l ', mr(p.x), ',', mr(p.y));
-            break;
-          case 'close':
-            lineStr.push(' x ');
-            p = null;
-            break;
-          case 'bezierCurveTo':
-            lineStr.push(' c ',
-                         mr(p.cp1x), ',', mr(p.cp1y), ',',
-                         mr(p.cp2x), ',', mr(p.cp2y), ',',
-                         mr(p.x), ',', mr(p.y));
-            break;
-          case 'at':
-          case 'wa':
-            lineStr.push(' ', p.type, ' ',
-                         mr(p.x - this.arcScaleX_ * p.radius), ',',
-                         mr(p.y - this.arcScaleY_ * p.radius), ' ',
-                         mr(p.x + this.arcScaleX_ * p.radius), ',',
-                         mr(p.y + this.arcScaleY_ * p.radius), ' ',
-                         mr(p.xStart), ',', mr(p.yStart), ' ',
-                         mr(p.xEnd), ',', mr(p.yEnd));
-            break;
-        }
-  
-  
-        // TODO: Following is broken for curves due to
-        //       move to proper paths.
-  
-        // Figure out dimensions so we can do gradient fills
-        // properly
-        if (p) {
-          if (min.x == null || p.x < min.x) {
-            min.x = p.x;
-          }
-          if (max.x == null || p.x > max.x) {
-            max.x = p.x;
-          }
-          if (min.y == null || p.y < min.y) {
-            min.y = p.y;
-          }
-          if (max.y == null || p.y > max.y) {
-            max.y = p.y;
-          }
-        }
-      }
-      lineStr.push(' ">');
-  
-      if (!aFill) {
-        appendStroke(this, lineStr);
-      } else {
-        appendFill(this, lineStr, min, max);
-      }
-  
-      lineStr.push('</g_vml_:shape>');
-  
-      this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
-    }
-  };
-
-  function appendStroke(ctx, lineStr) {
-    var a = processStyle(ctx.strokeStyle);
-    var color = a.color;
-    var opacity = a.alpha * ctx.globalAlpha;
-    var lineWidth = ctx.lineScale_ * ctx.lineWidth;
-
-    // VML cannot correctly render a line if the width is less than 1px.
-    // In that case, we dilute the color to make the line look thinner.
-    if (lineWidth < 1) {
-      opacity *= lineWidth;
-    }
-
-    lineStr.push(
-      '<g_vml_:stroke',
-      ' opacity="', opacity, '"',
-      ' joinstyle="', ctx.lineJoin, '"',
-      ' miterlimit="', ctx.miterLimit, '"',
-      ' endcap="', processLineCap(ctx.lineCap), '"',
-      ' weight="', lineWidth, 'px"',
-      ' color="', color, '" />'
-    );
-  }
-
-  function appendFill(ctx, lineStr, min, max) {
-    var fillStyle = ctx.fillStyle;
-    var arcScaleX = ctx.arcScaleX_;
-    var arcScaleY = ctx.arcScaleY_;
-    var width = max.x - min.x;
-    var height = max.y - min.y;
-    if (fillStyle instanceof CanvasGradient_) {
-      // TODO: Gradients transformed with the transformation matrix.
-      var angle = 0;
-      var focus = {x: 0, y: 0};
-
-      // additional offset
-      var shift = 0;
-      // scale factor for offset
-      var expansion = 1;
-
-      if (fillStyle.type_ == 'gradient') {
-        var x0 = fillStyle.x0_ / arcScaleX;
-        var y0 = fillStyle.y0_ / arcScaleY;
-        var x1 = fillStyle.x1_ / arcScaleX;
-        var y1 = fillStyle.y1_ / arcScaleY;
-        var p0 = ctx.getCoords_(x0, y0);
-        var p1 = ctx.getCoords_(x1, y1);
-        var dx = p1.x - p0.x;
-        var dy = p1.y - p0.y;
-        angle = Math.atan2(dx, dy) * 180 / Math.PI;
-
-        // The angle should be a non-negative number.
-        if (angle < 0) {
-          angle += 360;
-        }
-
-        // Very small angles produce an unexpected result because they are
-        // converted to a scientific notation string.
-        if (angle < 1e-6) {
-          angle = 0;
-        }
-      } else {
-        var p0 = ctx.getCoords_(fillStyle.x0_, fillStyle.y0_);
-        focus = {
-          x: (p0.x - min.x) / width,
-          y: (p0.y - min.y) / height
-        };
-
-        width  /= arcScaleX * Z;
-        height /= arcScaleY * Z;
-        var dimension = m.max(width, height);
-        shift = 2 * fillStyle.r0_ / dimension;
-        expansion = 2 * fillStyle.r1_ / dimension - shift;
-      }
-
-      // We need to sort the color stops in ascending order by offset,
-      // otherwise IE won't interpret it correctly.
-      var stops = fillStyle.colors_;
-      stops.sort(function(cs1, cs2) {
-        return cs1.offset - cs2.offset;
-      });
-
-      var length = stops.length;
-      var color1 = stops[0].color;
-      var color2 = stops[length - 1].color;
-      var opacity1 = stops[0].alpha * ctx.globalAlpha;
-      var opacity2 = stops[length - 1].alpha * ctx.globalAlpha;
-
-      var colors = [];
-      for (var i = 0; i < length; i++) {
-        var stop = stops[i];
-        colors.push(stop.offset * expansion + shift + ' ' + stop.color);
-      }
-
-      // When colors attribute is used, the meanings of opacity and o:opacity2
-      // are reversed.
-      lineStr.push('<g_vml_:fill type="', fillStyle.type_, '"',
-                   ' method="none" focus="100%"',
-                   ' color="', color1, '"',
-                   ' color2="', color2, '"',
-                   ' colors="', colors.join(','), '"',
-                   ' opacity="', opacity2, '"',
-                   ' g_o_:opacity2="', opacity1, '"',
-                   ' angle="', angle, '"',
-                   ' focusposition="', focus.x, ',', focus.y, '" />');
-    } else if (fillStyle instanceof CanvasPattern_) {
-      if (width && height) {
-        var deltaLeft = -min.x;
-        var deltaTop = -min.y;
-        lineStr.push('<g_vml_:fill',
-                     ' position="',
-                     deltaLeft / width * arcScaleX * arcScaleX, ',',
-                     deltaTop / height * arcScaleY * arcScaleY, '"',
-                     ' type="tile"',
-                     // TODO: Figure out the correct size to fit the scale.
-                     //' size="', w, 'px ', h, 'px"',
-                     ' src="', fillStyle.src_, '" />');
-       }
-    } else {
-      var a = processStyle(ctx.fillStyle);
-      var color = a.color;
-      var opacity = a.alpha * ctx.globalAlpha;
-      lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity,
-                   '" />');
-    }
-  }
-
-  contextPrototype.fill = function() {
-    this.stroke(true);
-  };
-
-  contextPrototype.closePath = function() {
-    this.currentPath_.push({type: 'close'});
-  };
-
-  /**
-   * @private
-   */
-  contextPrototype.getCoords_ = function(aX, aY) {
-    var m = this.m_;
-    return {
-      x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,
-      y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2
-    };
-  };
-
-  contextPrototype.save = function() {
-    var o = {};
-    copyState(this, o);
-    this.aStack_.push(o);
-    this.mStack_.push(this.m_);
-    this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);
-  };
-
-  contextPrototype.restore = function() {
-    if (this.aStack_.length) {
-      copyState(this.aStack_.pop(), this);
-      this.m_ = this.mStack_.pop();
-    }
-  };
-
-  function matrixIsFinite(m) {
-    return isFinite(m[0][0]) && isFinite(m[0][1]) &&
-        isFinite(m[1][0]) && isFinite(m[1][1]) &&
-        isFinite(m[2][0]) && isFinite(m[2][1]);
-  }
-
-  function setM(ctx, m, updateLineScale) {
-    if (!matrixIsFinite(m)) {
-      return;
-    }
-    ctx.m_ = m;
-
-    if (updateLineScale) {
-      // Get the line scale.
-      // Determinant of this.m_ means how much the area is enlarged by the
-      // transformation. So its square root can be used as a scale factor
-      // for width.
-      var det = m[0][0] * m[1][1] - m[0][1] * m[1][0];
-      ctx.lineScale_ = sqrt(abs(det));
-    }
-  }
-
-  contextPrototype.translate = function(aX, aY) {
-    var m1 = [
-      [1,  0,  0],
-      [0,  1,  0],
-      [aX, aY, 1]
-    ];
-
-    setM(this, matrixMultiply(m1, this.m_), false);
-  };
-
-  contextPrototype.rotate = function(aRot) {
-    var c = mc(aRot);
-    var s = ms(aRot);
-
-    var m1 = [
-      [c,  s, 0],
-      [-s, c, 0],
-      [0,  0, 1]
-    ];
-
-    setM(this, matrixMultiply(m1, this.m_), false);
-  };
-
-  contextPrototype.scale = function(aX, aY) {
-    this.arcScaleX_ *= aX;
-    this.arcScaleY_ *= aY;
-    var m1 = [
-      [aX, 0,  0],
-      [0,  aY, 0],
-      [0,  0,  1]
-    ];
-
-    setM(this, matrixMultiply(m1, this.m_), true);
-  };
-
-  contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) {
-    var m1 = [
-      [m11, m12, 0],
-      [m21, m22, 0],
-      [dx,  dy,  1]
-    ];
-
-    setM(this, matrixMultiply(m1, this.m_), true);
-  };
-
-  contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) {
-    var m = [
-      [m11, m12, 0],
-      [m21, m22, 0],
-      [dx,  dy,  1]
-    ];
-
-    setM(this, m, true);
-  };
-
-  /**
-   * The text drawing function.
-   * The maxWidth argument isn't taken in account, since no browser supports
-   * it yet.
-   */
-  contextPrototype.drawText_ = function(text, x, y, maxWidth, stroke) {
-    var m = this.m_,
-        delta = 1000,
-        left = 0,
-        right = delta,
-        offset = {x: 0, y: 0},
-        lineStr = [];
-
-    var fontStyle = getComputedStyle(processFontStyle(this.font),
-                                     this.element_);
-
-    var fontStyleString = buildStyle(fontStyle);
-
-    var elementStyle = this.element_.currentStyle;
-    var textAlign = this.textAlign.toLowerCase();
-    switch (textAlign) {
-      case 'left':
-      case 'center':
-      case 'right':
-        break;
-      case 'end':
-        textAlign = elementStyle.direction == 'ltr' ? 'right' : 'left';
-        break;
-      case 'start':
-        textAlign = elementStyle.direction == 'rtl' ? 'right' : 'left';
-        break;
-      default:
-        textAlign = 'left';
-    }
-
-    // 1.75 is an arbitrary number, as there is no info about the text baseline
-    switch (this.textBaseline) {
-      case 'hanging':
-      case 'top':
-        offset.y = fontStyle.size / 1.75;
-        break;
-      case 'middle':
-        break;
-      default:
-      case null:
-      case 'alphabetic':
-      case 'ideographic':
-      case 'bottom':
-        offset.y = -fontStyle.size / 2.25;
-        break;
-    }
-
-    switch(textAlign) {
-      case 'right':
-        left = delta;
-        right = 0.05;
-        break;
-      case 'center':
-        left = right = delta / 2;
-        break;
-    }
-
-    var d = this.getCoords_(x + offset.x, y + offset.y);
-
-    lineStr.push('<g_vml_:line from="', -left ,' 0" to="', right ,' 0.05" ',
-                 ' coordsize="100 100" coordorigin="0 0"',
-                 ' filled="', !stroke, '" stroked="', !!stroke,
-                 '" style="position:absolute;width:1px;height:1px;">');
-
-    if (stroke) {
-      appendStroke(this, lineStr);
-    } else {
-      // TODO: Fix the min and max params.
-      appendFill(this, lineStr, {x: -left, y: 0},
-                 {x: right, y: fontStyle.size});
-    }
-
-    var skewM = m[0][0].toFixed(3) + ',' + m[1][0].toFixed(3) + ',' +
-                m[0][1].toFixed(3) + ',' + m[1][1].toFixed(3) + ',0,0';
-
-    var skewOffset = mr(d.x / Z) + ',' + mr(d.y / Z);
-
-    lineStr.push('<g_vml_:skew on="t" matrix="', skewM ,'" ',
-                 ' offset="', skewOffset, '" origin="', left ,' 0" />',
-                 '<g_vml_:path textpathok="true" />',
-                 '<g_vml_:textpath on="true" string="',
-                 encodeHtmlAttribute(text),
-                 '" style="v-text-align:', textAlign,
-                 ';font:', encodeHtmlAttribute(fontStyleString),
-                 '" /></g_vml_:line>');
-
-    this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
-  };
-
-  contextPrototype.fillText = function(text, x, y, maxWidth) {
-    this.drawText_(text, x, y, maxWidth, false);
-  };
-
-  contextPrototype.strokeText = function(text, x, y, maxWidth) {
-    this.drawText_(text, x, y, maxWidth, true);
-  };
-
-  contextPrototype.measureText = function(text) {
-    if (!this.textMeasureEl_) {
-      var s = '<span style="position:absolute;' +
-          'top:-20000px;left:0;padding:0;margin:0;border:none;' +
-          'white-space:pre;"></span>';
-      this.element_.insertAdjacentHTML('beforeEnd', s);
-      this.textMeasureEl_ = this.element_.lastChild;
-    }
-    var doc = this.element_.ownerDocument;
-    this.textMeasureEl_.innerHTML = '';
-    this.textMeasureEl_.style.font = this.font;
-    // Don't use innerHTML or innerText because they allow markup/whitespace.
-    this.textMeasureEl_.appendChild(doc.createTextNode(text));
-    return {width: this.textMeasureEl_.offsetWidth};
-  };
-
-  /******** STUBS ********/
-  contextPrototype.clip = function() {
-    // TODO: Implement
-  };
-
-  contextPrototype.arcTo = function() {
-    // TODO: Implement
-  };
-
-  contextPrototype.createPattern = function(image, repetition) {
-    return new CanvasPattern_(image, repetition);
-  };
-
-  // Gradient / Pattern Stubs
-  function CanvasGradient_(aType) {
-    this.type_ = aType;
-    this.x0_ = 0;
-    this.y0_ = 0;
-    this.r0_ = 0;
-    this.x1_ = 0;
-    this.y1_ = 0;
-    this.r1_ = 0;
-    this.colors_ = [];
-  }
-
-  CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
-    aColor = processStyle(aColor);
-    this.colors_.push({offset: aOffset,
-                       color: aColor.color,
-                       alpha: aColor.alpha});
-  };
-
-  function CanvasPattern_(image, repetition) {
-    assertImageIsValid(image);
-    switch (repetition) {
-      case 'repeat':
-      case null:
-      case '':
-        this.repetition_ = 'repeat';
-        break
-      case 'repeat-x':
-      case 'repeat-y':
-      case 'no-repeat':
-        this.repetition_ = repetition;
-        break;
-      default:
-        throwException('SYNTAX_ERR');
-    }
-
-    this.src_ = image.src;
-    this.width_ = image.width;
-    this.height_ = image.height;
-  }
-
-  function throwException(s) {
-    throw new DOMException_(s);
-  }
-
-  function assertImageIsValid(img) {
-    if (!img || img.nodeType != 1 || img.tagName != 'IMG') {
-      throwException('TYPE_MISMATCH_ERR');
-    }
-    if (img.readyState != 'complete') {
-      throwException('INVALID_STATE_ERR');
-    }
-  }
-
-  function DOMException_(s) {
-    this.code = this[s];
-    this.message = s +': DOM Exception ' + this.code;
-  }
-  var p = DOMException_.prototype = new Error;
-  p.INDEX_SIZE_ERR = 1;
-  p.DOMSTRING_SIZE_ERR = 2;
-  p.HIERARCHY_REQUEST_ERR = 3;
-  p.WRONG_DOCUMENT_ERR = 4;
-  p.INVALID_CHARACTER_ERR = 5;
-  p.NO_DATA_ALLOWED_ERR = 6;
-  p.NO_MODIFICATION_ALLOWED_ERR = 7;
-  p.NOT_FOUND_ERR = 8;
-  p.NOT_SUPPORTED_ERR = 9;
-  p.INUSE_ATTRIBUTE_ERR = 10;
-  p.INVALID_STATE_ERR = 11;
-  p.SYNTAX_ERR = 12;
-  p.INVALID_MODIFICATION_ERR = 13;
-  p.NAMESPACE_ERR = 14;
-  p.INVALID_ACCESS_ERR = 15;
-  p.VALIDATION_ERR = 16;
-  p.TYPE_MISMATCH_ERR = 17;
-
-  // set up externs
-  G_vmlCanvasManager = G_vmlCanvasManager_;
-  CanvasRenderingContext2D = CanvasRenderingContext2D_;
-  CanvasGradient = CanvasGradient_;
-  CanvasPattern = CanvasPattern_;
-  DOMException = DOMException_;
-})();
-
-} // if

+ 0 - 43
gemini/Docroot/js/gh.forms.js

@@ -1,43 +0,0 @@
-gh.provide('gh.forms');
-
-/**
- * Focuses the first element in the given form.  If the form has been 
- * submitted and has invalid elements, the first invalid element is 
- * focused.  Invisible elements and submit buttons will not be focused.
- * 
- * @param formSelector A CSS selector for the form, e.g. '#LoginForm'.
- */
-gh.forms.autofocus = function(formSelector) {
-  
-  var form = $(formSelector);
-  var invalidElements = form.find('.invalid:visible:not([type="hidden"]):not([type="submit"])');
-  
-  if (invalidElements.length == 0) {
-    var allElements = form.find('input:visible:not([type="hidden"]):not([type="submit"]), textarea:visible, select:visible');
-    if (allElements.length > 0) {
-      $(allElements[0]).focus();
-    }
-  } else {
-    $(invalidElements[0]).focus();
-  }
-  
-};
-
-/**
- * Prevents the given form from being submitted more than once.  
- * 
- * @param formSelector A CSS selector for the form, e.g. '#LoginForm'.
- */
-gh.forms.disableOnSubmit = function(formSelector) {
-
-  var form = $(formSelector);
-  
-  form.submit(function(e) {
-    if (form.data('submitted')) {
-      e.preventDefault();
-    } else {
-      form.data('submitted', true);
-    }
-  });
-  
-};

+ 0 - 25
gemini/Docroot/js/gh.js

@@ -1,25 +0,0 @@
-var gh = gh || {};
-
-/**
- * Creates the given namespace if it does not already exist.  For example: 
- *   gh.provide('foo.bar.baz');
- *   
- * is equivalent to:
- *   foo = foo || {};
- *   foo.bar = foo.bar || {};
- *   foo.bar.baz = foo.bar.baz || {};
- * 
- * So the following code would execute safely:
- *   gh.provide('foo.bar.baz');
- *   foo.bar.baz.count = 0;
- * 
- * @param namespace The namespace to be created.
- */
-gh.provide = function(namespace) {
-  namespace = namespace.split('.');
-  var object = window;
-  for (var i = 0; i < namespace.length; i++) {
-    object[namespace[i]] = object[namespace[i]] || {};
-    object = object[namespace[i]];
-  }
-}

+ 0 - 4
gemini/Docroot/js/html5.js

@@ -1,4 +0,0 @@
-// iepp v2.1pre @jon_neal & @aFarkas github.com/aFarkas/iepp
-// html5shiv @rem remysharp.com/html5-enabling-script
-// Dual licensed under the MIT or GPL Version 2 licenses
-/*@cc_on(function(a,b){function r(a){var b=-1;while(++b<f)a.createElement(e[b])}if(!window.attachEvent||!b.createStyleSheet||!function(){var a=document.createElement("div");return a.innerHTML="<elem></elem>",a.childNodes.length!==1}())return;a.iepp=a.iepp||{};var c=a.iepp,d=c.html5elements||"abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|subline|summary|time|video",e=d.split("|"),f=e.length,g=new RegExp("(^|\\s)("+d+")","gi"),h=new RegExp("<(/*)("+d+")","gi"),i=/^\s*[\{\}]\s*$/,j=new RegExp("(^|[^\\n]*?\\s)("+d+")([^\\n]*)({[\\n\\w\\W]*?})","gi"),k=b.createDocumentFragment(),l=b.documentElement,m=b.getElementsByTagName("script")[0].parentNode,n=b.createElement("body"),o=b.createElement("style"),p=/print|all/,q;c.getCSS=function(a,b){try{if(a+""===undefined)return""}catch(d){return""}var e=-1,f=a.length,g,h=[];while(++e<f){g=a[e];if(g.disabled)continue;b=g.media||b,p.test(b)&&h.push(c.getCSS(g.imports,b),g.cssText),b="all"}return h.join("")},c.parseCSS=function(a){var b=[],c;while((c=j.exec(a))!=null)b.push(((i.exec(c[1])?"\n":c[1])+c[2]+c[3]).replace(g,"$1.iepp-$2")+c[4]);return b.join("\n")},c.writeHTML=function(){var a=-1;q=q||b.body;while(++a<f){var c=b.getElementsByTagName(e[a]),d=c.length,g=-1;while(++g<d)c[g].className.indexOf("iepp-")<0&&(c[g].className+=" iepp-"+e[a])}k.appendChild(q),l.appendChild(n),n.className=q.className,n.id=q.id,n.innerHTML=q.innerHTML.replace(h,"<$1font")},c._beforePrint=function(){if(c.disablePP)return;o.styleSheet.cssText=c.parseCSS(c.getCSS(b.styleSheets,"all")),c.writeHTML()},c.restoreHTML=function(){if(c.disablePP)return;n.swapNode(q)},c._afterPrint=function(){c.restoreHTML(),o.styleSheet.cssText=""},r(b),r(k);if(c.disablePP)return;m.insertBefore(o,m.firstChild),o.media="print",o.className="iepp-printshim",a.attachEvent("onbeforeprint",c._beforePrint),a.attachEvent("onafterprint",c._afterPrint)})(this,document)@*/

Some files were not shown because too many files changed in this diff