Browse Source

Merge remote-tracking branch 'origin/master' into upgrade-clojure-frameworks

Zane Kansil 10 years ago
parent
commit
af73e4e62a
100 changed files with 2499 additions and 323 deletions
  1. 4 0
      .travis.yml
  2. 1 0
      config/php.ini
  3. 46 14
      frameworks/CSharp/README.md
  4. 51 31
      frameworks/CSharp/nancy/README.md
  5. 4 0
      frameworks/Elixir/phoenix/.gitignore
  6. 8 0
      frameworks/Elixir/phoenix/README.md
  7. 24 0
      frameworks/Elixir/phoenix/benchmark_config.json
  8. 23 0
      frameworks/Elixir/phoenix/config/config.exs
  9. 13 0
      frameworks/Elixir/phoenix/config/dev.exs
  10. 3 0
      frameworks/Elixir/phoenix/config/locales/en.exs
  11. 38 0
      frameworks/Elixir/phoenix/config/prod.exs
  12. 7 0
      frameworks/Elixir/phoenix/config/test.exs
  13. 3 0
      frameworks/Elixir/phoenix/install.sh
  14. 29 0
      frameworks/Elixir/phoenix/lib/hello.ex
  15. 30 0
      frameworks/Elixir/phoenix/lib/hello/endpoint.ex
  16. 30 0
      frameworks/Elixir/phoenix/mix.exs
  17. 6 0
      frameworks/Elixir/phoenix/priv/static/css/phoenix.css
  18. BIN
      frameworks/Elixir/phoenix/priv/static/images/phoenix.png
  19. 565 0
      frameworks/Elixir/phoenix/priv/static/js/phoenix.js
  20. 15 0
      frameworks/Elixir/phoenix/setup.sh
  21. 7 0
      frameworks/Elixir/phoenix/test/hello_test.exs
  22. 1 0
      frameworks/Elixir/phoenix/test/test_helper.exs
  23. 40 0
      frameworks/Elixir/phoenix/web/controllers/page_controller.ex
  24. 11 0
      frameworks/Elixir/phoenix/web/models/repo.exs
  25. 7 0
      frameworks/Elixir/phoenix/web/models/world.exs
  26. 31 0
      frameworks/Elixir/phoenix/web/router.ex
  27. 31 0
      frameworks/Elixir/phoenix/web/templates/layout/application.html.eex
  28. 1 0
      frameworks/Elixir/phoenix/web/templates/page/error.html.eex
  29. 34 0
      frameworks/Elixir/phoenix/web/templates/page/index.html.eex
  30. 1 0
      frameworks/Elixir/phoenix/web/templates/page/not_found.html.eex
  31. 17 0
      frameworks/Elixir/phoenix/web/view.ex
  32. 16 0
      frameworks/Elixir/phoenix/web/views/error_view.ex
  33. 3 0
      frameworks/Elixir/phoenix/web/views/layout_view.ex
  34. 3 0
      frameworks/Elixir/phoenix/web/views/page_view.ex
  35. 1 2
      frameworks/Erlang/cowboy/.gitignore
  36. 1 1
      frameworks/Erlang/cowboy/benchmark_config.json
  37. 5 3
      frameworks/Erlang/cowboy/setup.sh
  38. 1 2
      frameworks/Erlang/elli/.gitignore
  39. 1 1
      frameworks/Erlang/elli/benchmark_config.json
  40. 2 2
      frameworks/Erlang/elli/rebar.config
  41. 5 3
      frameworks/Erlang/elli/setup.sh
  42. 11 5
      frameworks/Haskell/wai/bench/wai.hs
  43. 1 0
      frameworks/Haskell/wai/benchmark_config.json
  44. 2 0
      frameworks/Haskell/yesod/bench/bench.cabal
  45. 119 37
      frameworks/Haskell/yesod/bench/src/yesod.hs
  46. 3 0
      frameworks/Haskell/yesod/benchmark_config.json
  47. 32 6
      frameworks/Java/README.md
  48. 1 1
      frameworks/JavaScript/express/app.js
  49. 12 14
      frameworks/JavaScript/express/setup.sh
  50. 1 1
      frameworks/JavaScript/hapi/app.js
  51. 11 14
      frameworks/JavaScript/hapi/setup.sh
  52. 0 0
      frameworks/JavaScript/koa/README.md
  53. 128 0
      frameworks/JavaScript/koa/app.js
  54. 28 0
      frameworks/JavaScript/koa/benchmark_config.json
  55. 3 0
      frameworks/JavaScript/koa/install.sh
  56. 17 0
      frameworks/JavaScript/koa/package.json
  57. 17 0
      frameworks/JavaScript/koa/setup.sh
  58. 0 0
      frameworks/JavaScript/koa/source_code
  59. 21 0
      frameworks/JavaScript/koa/views/fortunes.hbs
  60. 1 3
      frameworks/JavaScript/nodejs/hello.js
  61. 11 15
      frameworks/JavaScript/nodejs/setup.sh
  62. 30 8
      frameworks/PHP/README.md
  63. 1 4
      frameworks/PHP/hhvm/once.php.inc
  64. 2 0
      frameworks/PHP/limonade/.gitignore
  65. 26 0
      frameworks/PHP/limonade/benchmark_config.json
  66. 7 0
      frameworks/PHP/limonade/composer.json
  67. 46 0
      frameworks/PHP/limonade/deploy/nginx.conf
  68. 105 0
      frameworks/PHP/limonade/index.php
  69. 11 0
      frameworks/PHP/limonade/install.sh
  70. 5 0
      frameworks/PHP/limonade/models/Fortune.php
  71. 5 0
      frameworks/PHP/limonade/models/World.php
  72. 12 0
      frameworks/PHP/limonade/setup.sh
  73. 19 0
      frameworks/PHP/limonade/views/fortune.php
  74. 1 0
      frameworks/PHP/php-phalcon/app/views/layouts/mongobench.volt
  75. 30 43
      frameworks/PHP/symfony2/README.md
  76. 30 0
      frameworks/Python/API-Hour/README.md
  77. 21 3
      frameworks/Python/README.md
  78. 25 21
      frameworks/Python/bottle/README.md
  79. 20 20
      frameworks/Python/django/README.md
  80. 27 9
      frameworks/Python/falcon/README.md
  81. 11 3
      frameworks/Python/flask/README.md
  82. 20 19
      frameworks/Python/pyramid/README.md
  83. 29 11
      frameworks/Python/tornado/README.md
  84. 40 0
      frameworks/Python/turbogears/README.md
  85. 93 0
      frameworks/Python/turbogears/app.py
  86. 27 0
      frameworks/Python/turbogears/benchmark_config.json
  87. 25 0
      frameworks/Python/turbogears/gunicorn_conf.py
  88. 19 0
      frameworks/Python/turbogears/install.sh
  89. 17 0
      frameworks/Python/turbogears/models/Fortune.py
  90. 17 0
      frameworks/Python/turbogears/models/World.py
  91. 0 0
      frameworks/Python/turbogears/models/__init__.py
  92. 11 0
      frameworks/Python/turbogears/requirements.txt
  93. 7 0
      frameworks/Python/turbogears/setup.sh
  94. 20 0
      frameworks/Python/turbogears/templates/fortunes.html
  95. 29 0
      frameworks/Python/uwsgi/README.md
  96. 20 10
      frameworks/Python/wsgi/README.md
  97. 52 7
      frameworks/Ruby/README.md
  98. 32 2
      frameworks/Ruby/grape/README.md
  99. 23 8
      frameworks/Ruby/ngx_mruby/README.md
  100. 46 0
      frameworks/Ruby/padrino/README.md

+ 4 - 0
.travis.yml

@@ -38,6 +38,7 @@ env:
     - "TESTDIR=Dart/dart-redstone"
     - "TESTDIR=Dart/dart-start"
     - "TESTDIR=Dart/dart-stream"
+    - "TESTDIR=Elixir/phoenix"
     - "TESTDIR=Erlang/cowboy"
     - "TESTDIR=Erlang/elli"
     - "TESTDIR=Go/beego"
@@ -81,6 +82,7 @@ env:
     - "TESTDIR=Java/wildfly-ee7"
     - "TESTDIR=JavaScript/express"
     - "TESTDIR=JavaScript/hapi"
+    - "TESTDIR=JavaScript/koa"
     - "TESTDIR=JavaScript/nodejs"
     - "TESTDIR=JavaScript/ringojs"
     - "TESTDIR=JavaScript/ringojs-convenient"
@@ -101,6 +103,7 @@ env:
     - "TESTDIR=PHP/fuel"
     - "TESTDIR=PHP/kohana"
     - "TESTDIR=PHP/php-laravel"
+    - "TESTDIR=PHP/limonade"
     - "TESTDIR=PHP/lithium"
     - "TESTDIR=PHP/php-micromvc"
     - "TESTDIR=PHP/php-phalcon"
@@ -125,6 +128,7 @@ env:
     - "TESTDIR=Python/flask"
     - "TESTDIR=Python/pyramid"
     - "TESTDIR=Python/tornado"
+    - "TESTDIR=Python/turbogears"
     - "TESTDIR=Python/uwsgi"
     - "TESTDIR=Python/web2py"
     - "TESTDIR=Python/wheezyweb"

+ 1 - 0
config/php.ini

@@ -870,6 +870,7 @@ zend_extension=opcache.so
 extension=redis.so
 extension=phalcon.so
 extension=yaf.so
+extension=mongo.so
 ;extension=php_bz2.dll
 ;extension=php_curl.dll
 ;extension=php_fileinfo.dll

+ 46 - 14
frameworks/CSharp/README.md

@@ -1,26 +1,30 @@
-# Limited Travis-CI Verification 
+# C# (CSharp) Frameworks
 
-Because the verification system uses the linux-only Travis-CI
-service, verifying Windows-only tests has to be done manually
-and is very time consuming. 
+The information below contains information specific to C#. 
+For further guidance, review the 
+[documentation](http://frameworkbenchmarks.readthedocs.org/en/latest/).
 
-Consider including an additional test, likely based on Mono and 
-FastCGI (e.g. xsp), that can run on Linux when submitting a new
-framework. This will drastically speed up our ability to merge
-in your pull request. 
+## Infrastructure Software Versions
 
-# Different Mono Versions
+* [Mono C# compiler latest version](http://www.mono-project.com/docs/about-mono/languages/csharp/)
+
+## Adding a New C# Framework
+
+### Different Mono Versions
 
 While we have not currently run into the need to have multiple 
 simultaneous Mono installations, it is [possible](http://www.mono-project.com/docs/compiling-mono/parallel-mono-environments/)
 
-# Debugging Mono + NuGet
+### Debugging Mono + NuGet
 
-Mono understands an environment variable `MONO_LOG_LEVEL=debug` that is helpful for checking that 
+Mono understands an environment variable `MONO_LOG_LEVEL=debug` 
+that is helpful for checking that 
 mono is properly working e.g. loading necessary DLL's. 
 
-Most NuGet commands understand a `-Verbosity` flag, which is great because the error messages can be completely
-mystifying when working with Mono too. Use this would enable all the debugging you can: 
+Most NuGet commands understand a `-Verbosity` flag, which is 
+great because the error messages can be completely
+mystifying when working with Mono too. Use this would enable 
+all the debugging you can: 
 
     $ MONO_LOG_LEVEL=debug mono NuGet2.exe update -Verbosity "detailed" -self
 
@@ -28,10 +32,38 @@ For example, aspnet was constantly failing with this message:
     
     Could not connect to the feed specified at 'https://www.nuget.org/api/v2/'. Please verify that the package source (located in the Package Manager Settings) is valid and ensure your network connectivity.`. 
 
-Using `-Verbosity "detailed"` shows that the real error is actually a Mono library problem, as so: 
+Using `-Verbosity "detailed"` shows that the real error is 
+actually a Mono library problem, as so: 
 
     System.InvalidOperationException: Could not connect to the feed specified at 'https://www.nuget.org/api/v2/'. Please verify that the package source (located in the Package Manager Settings) is valid and ensure your network connectivity. ---> System.Net.WebException: libMonoPosixHelper.so ---> System.DllNotFoundException: libMonoPosixHelper.so
       at (wrapper managed-to-native) System.IO.Compression.DeflateStreamNative:CreateZStream (System.IO.Compression.CompressionMode,bool,System.IO.Compression.DeflateStreamNative/UnmanagedReadOrWrite,intptr)
       <snip>
 
 More helpful info is [here](http://www.mono-project.com/docs/advanced/pinvoke/dllnotfoundexception/), [here](http://docs.nuget.org/docs/reference/command-line-reference)
+
+### Limited Travis-CI Verification 
+
+Because the verification system uses the linux-only Travis-CI
+service, verifying Windows-only tests has to be done manually
+and is very time consuming. 
+
+Consider including an additional test, likely based on Mono and 
+FastCGI (e.g. xsp), that can run on Linux when submitting a new
+framework. This will drastically speed up our ability to merge
+in your pull request. 
+
+## Get Help
+
+### C# Experts
+
+_There aren't any C# experts listed, yet. If you're an expert, add yourself!_
+
+### C# Community
+
+_We don't have any community links added. Add some to help further guide 
+future contirbutors._
+
+### Resources
+
+_If you stumble upon some helpful links or discussions, add them 
+for easy reference for future contributors._

+ 51 - 31
frameworks/CSharp/nancy/README.md

@@ -1,21 +1,54 @@
-# Nancy on Mono and Windows
+# Nancy on Mono and Windows Benchmarking Test
 
-## Tests
+The information below contains information specific to Nancy on Mono and Windows. 
+For further guidance, review the 
+[documentation](http://frameworkbenchmarks.readthedocs.org/en/latest/). 
+Also note the additional information provided in the [CSharp README](../).
 
-### JSON
+This is the Nancy on Mono and Windows portion of a [benchmarking test suite](../../) 
+comparing a variety of web platforms.
 
-* `http://localhost:8080/json`
+## Infrastructure Software Versions
 
----
+**Language**
+
+* C# 5.0
+
+**Platforms**
+
+* .NET Framework 4.5 (Windows)
+* Mono 3.0.X (Linux)
+
+**Web Servers**
+
+* IIS 8 (Windows)
+* nginx 1.4.0 & XSP FastCGI (Linux)
+
+**Web Stack**
+
+* ASP.NET 4.5
+* Nancy 0.17.1 (custom build to address this issue: https://github.com/NancyFx/Nancy/pull/1100)
+
+**Databases**
+
+* MySQL Connector/Net
+
+**Developer Tools**
+
+* Visual Studio 2012
+
+## Paths & Source for Tests
+
+* [JSON Serialization](NancyModules/JsonModule.cs): "/json"
 
 ### Nancy - Dapper (ORM)
 
-**MySQL**
+* [Single Database Query](NancyModules/DbModule.cs): "/db"
+* [Multiple Database Queries](NancyModules/DbModule.cs): "/db/10"
 
-* `http://localhost:8080/db`
-* `http://localhost:8080/db/10`
+## Add a New Test for Nancy
 
-## Mono Installation
+### Mono Installation
 
     sudo apt-get install build-essential autoconf automake libtool zlib1g-dev git
 
@@ -36,31 +69,18 @@
     make
     sudo make install
 
-## Versions
-
-**Language**
-
-* C# 5.0
-
-**Platforms**
-
-* .NET Framework 4.5 (Windows)
-* Mono 3.0.X (Linux)
-
-**Web Servers**
-
-* IIS 8 (Windows)
-* nginx 1.4.0 & XSP FastCGI (Linux)
+## Get Help
 
-**Web Stack**
+### Experts
 
-* ASP.NET 4.5
-* Nancy 0.17.1 (custom build to address this issue: https://github.com/NancyFx/Nancy/pull/1100)
+_There aren't any experts listed, yet. If you're an expert, add yourself!_
 
-**Databases**
+### Community
 
-* MySQL Connector/Net
+* Chat in the [#NancyFX](https://jabbr.net/account/login?ReturnUrl=%2F#/rooms/nancyfx) room on JabbR.
+* #NancyFx on Twitter.
 
-**Developer Tools**
+### Resources
 
-* Visual Studio 2012
+* [Source Code](https://github.com/NancyFx/Nancy)
+* [Issue #877 - Discussion regarding Event2.dll and Global.asax thread configuration](https://github.com/TechEmpower/FrameworkBenchmarks/issues/877)

+ 4 - 0
frameworks/Elixir/phoenix/.gitignore

@@ -0,0 +1,4 @@
+/_build
+/deps
+erl_crash.dump
+*.ez

+ 8 - 0
frameworks/Elixir/phoenix/README.md

@@ -0,0 +1,8 @@
+# Hello
+
+To start your new Phoenix application:
+
+1. Install dependencies with `mix deps.get`
+2. Start Phoenix endpoint with `mix phoenix.server`
+
+Now you can visit `localhost:8080` from your browser.

+ 24 - 0
frameworks/Elixir/phoenix/benchmark_config.json

@@ -0,0 +1,24 @@
+{
+    "framework": "phoenix",
+    "tests": [{
+        "default": {
+            "setup_file": "setup",
+            "json_url": "/json",
+            "plaintext_url": "/plaintext",
+            "port": 8080,
+            "approach": "Realistic",
+            "classification": "Framework",
+            "database": "Postgres",
+            "framework": "Phoenix",
+            "language": "elixir",
+            "orm": "etco",
+            "platform": "Erlang/OTP",
+            "webserver": "cowboy",
+            "os": "Linux",
+            "database_os": "Linux",
+            "display_name": "phoenix",
+            "notes": "",
+            "versus": ""
+        }
+    }]
+}

+ 23 - 0
frameworks/Elixir/phoenix/config/config.exs

@@ -0,0 +1,23 @@
+# This file is responsible for configuring your application
+# and its dependencies with the aid of the Mix.Config module.
+#
+# This configuration file is loaded before any dependency and
+# is restricted to this project.
+use Mix.Config
+
+# Configures the endpoint
+config :hello, Hello.Endpoint,
+  url: [host: "localhost"],
+  secret_key_base: "Z18ZjzZslFpKd8HB41IljqMavPiOKVF9y1DIQ+S2Ytg7Op0EIauwJgd7mtRStssx",
+  debug_errors: false,
+  pubsub: [adapter: Phoenix.PubSub.PG2]
+
+
+# Configures Elixir's Logger
+config :logger, :console,
+  format: "$time $metadata[$level] $message\n",
+  metadata: [:request_id]
+
+# Import environment specific config. This must remain at the bottom
+# of this file so it overrides the configuration defined above.
+import_config "#{Mix.env}.exs"

+ 13 - 0
frameworks/Elixir/phoenix/config/dev.exs

@@ -0,0 +1,13 @@
+use Mix.Config
+
+config :hello, Hello.Endpoint,
+  url: [host: "localhost", port: 8080],
+  http: [port: System.get_env("PORT") || 8080],
+  debug_errors: true,
+  cache_static_lookup: false
+
+# Enables code reloading for development
+config :phoenix, :code_reloader, true
+
+# Do not include metadata nor timestamps in development logs
+config :logger, :console, format: "[$level] $message\n"

+ 3 - 0
frameworks/Elixir/phoenix/config/locales/en.exs

@@ -0,0 +1,3 @@
+[
+  hello: "Hello"
+]

+ 38 - 0
frameworks/Elixir/phoenix/config/prod.exs

@@ -0,0 +1,38 @@
+use Mix.Config
+
+config :hello, Hello.Endpoint,
+  url: [host: "localhost", port: 8080],
+  http: [port: 8080],
+  secret_key_base: "Z18ZjzZslFpKd8HB41IljqMavPiOKVF9y1DIQ+S2Ytg7Op0EIauwJgd7mtRStssx",
+  cache_static_lookup: false
+
+# ## SSL Support
+#
+# To get SSL working, you will need to add the `https` key
+# to the previous section:
+#
+#  config:hello, Hello.Endpoint,
+#    ...
+#    https: [port: 443,
+#            keyfile: System.get_env("SOME_APP_SSL_KEY_PATH"),
+#            certfile: System.get_env("SOME_APP_SSL_CERT_PATH")]
+#
+# Where those two env variables point to a file on
+# disk for the key and cert.
+
+
+# Do not pring debug messages in production
+config :logger, level: :info
+
+# ## Using releases
+#
+# If you are doing OTP releases, you need to instruct Phoenix
+# to start the server for all endpoints:
+#
+#    config :phoenix, :serve_endpoints, true
+#
+# Alternatively, you can configure exactly which server to
+# start per endpoint:
+#
+#     config :hello, Hello.Endpoint, server: true
+#

+ 7 - 0
frameworks/Elixir/phoenix/config/test.exs

@@ -0,0 +1,7 @@
+use Mix.Config
+
+config :hello, Hello.Endpoint,
+  http: [port: System.get_env("PORT") || 4001]
+
+# Print only warnings and errors during test
+config :logger, level: :warn

+ 3 - 0
frameworks/Elixir/phoenix/install.sh

@@ -0,0 +1,3 @@
+#!/bin/bash
+
+fw_depends elixir

+ 29 - 0
frameworks/Elixir/phoenix/lib/hello.ex

@@ -0,0 +1,29 @@
+defmodule Hello do
+  use Application
+
+  # See http://elixir-lang.org/docs/stable/elixir/Application.html
+  # for more information on OTP Applications
+  def start(_type, _args) do
+    import Supervisor.Spec, warn: false
+
+    children = [
+      # Start the endpoint when the application starts
+      supervisor(Hello.Endpoint, []),
+      # Here you could define other workers and supervisors as children
+      # worker(Hello.Worker, [arg1, arg2, arg3]),
+      # worker(Hello.Repo, [])
+    ]
+
+    # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
+    # for other strategies and supported options
+    opts = [strategy: :one_for_one, name: Hello.Supervisor]
+    Supervisor.start_link(children, opts)
+  end
+
+  # Tell Phoenix to update the endpoint configuration
+  # whenever the application is updated.
+  def config_change(changed, _new, removed) do
+    Hello.Endpoint.config_change(changed, removed)
+    :ok
+  end
+end

+ 30 - 0
frameworks/Elixir/phoenix/lib/hello/endpoint.ex

@@ -0,0 +1,30 @@
+defmodule Hello.Endpoint do
+  use Phoenix.Endpoint, otp_app: :hello
+
+  # Serve at "/" the given assets from "priv/static" directory
+  plug Plug.Static,
+    at: "/", from: :hello,
+    only: ~w(css images js favicon.ico robots.txt)
+
+  plug Plug.Logger
+
+  # Code reloading will only work if the :code_reloader key of
+  # the :phoenix application is set to true in your config file.
+  plug Phoenix.CodeReloader
+
+  plug Plug.Parsers,
+    parsers: [:urlencoded, :multipart, :json],
+    pass: ["*/*"],
+    json_decoder: Poison
+
+  plug Plug.MethodOverride
+  plug Plug.Head
+
+  plug Plug.Session,
+    store: :cookie,
+    key: "_hello_key",
+    signing_salt: "DNlAnJ2o",
+    encryption_salt: "AOXxaZRq"
+
+  plug :router, Hello.Router
+end

+ 30 - 0
frameworks/Elixir/phoenix/mix.exs

@@ -0,0 +1,30 @@
+defmodule Hello.Mixfile do
+  use Mix.Project
+
+  def project do
+    [app: :hello,
+     version: "0.0.1",
+     elixir: "~> 1.0",
+     elixirc_paths: ["lib", "web"],
+     compilers: [:phoenix] ++ Mix.compilers,
+     deps: deps]
+  end
+
+  # Configuration for the OTP application
+  #
+  # Type `mix help compile.app` for more information
+  def application do
+    [mod: {Hello, []},
+     applications: [:phoenix, :cowboy, :logger, :postgrex, :ecto]]
+  end
+
+  # Specifies your project dependencies
+  #
+  # Type `mix help deps` for examples and options
+  defp deps do
+    [{:phoenix, "~> 0.9.0"},
+     {:cowboy, "~> 1.0"},
+     {:postgrex, "~> 0.6.0"},
+     {:ecto, "~> 0.2.5"}]
+  end
+end

File diff suppressed because it is too large
+ 6 - 0
frameworks/Elixir/phoenix/priv/static/css/phoenix.css


BIN
frameworks/Elixir/phoenix/priv/static/images/phoenix.png


+ 565 - 0
frameworks/Elixir/phoenix/priv/static/js/phoenix.js

@@ -0,0 +1,565 @@
+"use strict";
+
+var _prototypeProperties = function (child, staticProps, instanceProps) { if (staticProps) Object.defineProperties(child, staticProps); if (instanceProps) Object.defineProperties(child.prototype, instanceProps); };
+
+var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } };
+
+(function (root, factory) {
+  if (typeof define === "function" && define.amd) {
+    return define(["phoenix"], factory);
+  } else if (typeof exports === "object") {
+    return factory(exports);
+  } else {
+    root.Phoenix = {};
+    return factory.call(root, root.Phoenix);
+  }
+})(Function("return this")(), function (exports) {
+  var root = this;
+  var SOCKET_STATES = { connecting: 0, open: 1, closing: 2, closed: 3 };
+
+  exports.Channel = (function () {
+    function Channel(topic, message, callback, socket) {
+      _classCallCheck(this, Channel);
+
+      this.topic = topic;
+      this.message = message;
+      this.callback = callback;
+      this.socket = socket;
+      this.bindings = null;
+
+      this.reset();
+    }
+
+    _prototypeProperties(Channel, null, {
+      reset: {
+        value: function reset() {
+          this.bindings = [];
+        },
+        writable: true,
+        configurable: true
+      },
+      on: {
+        value: function on(event, callback) {
+          this.bindings.push({ event: event, callback: callback });
+        },
+        writable: true,
+        configurable: true
+      },
+      isMember: {
+        value: function isMember(topic) {
+          return this.topic === topic;
+        },
+        writable: true,
+        configurable: true
+      },
+      off: {
+        value: function off(event) {
+          this.bindings = this.bindings.filter(function (bind) {
+            return bind.event !== event;
+          });
+        },
+        writable: true,
+        configurable: true
+      },
+      trigger: {
+        value: function trigger(triggerEvent, msg) {
+          this.bindings.filter(function (bind) {
+            return bind.event === triggerEvent;
+          }).map(function (bind) {
+            return bind.callback(msg);
+          });
+        },
+        writable: true,
+        configurable: true
+      },
+      send: {
+        value: function send(event, payload) {
+          this.socket.send({ topic: this.topic, event: event, payload: payload });
+        },
+        writable: true,
+        configurable: true
+      },
+      leave: {
+        value: function leave() {
+          var message = arguments[0] === undefined ? {} : arguments[0];
+          this.socket.leave(this.topic, message);
+          this.reset();
+        },
+        writable: true,
+        configurable: true
+      }
+    });
+
+    return Channel;
+  })();
+
+
+  exports.Socket = (function () {
+    // Initializes the Socket
+    //
+    // endPoint - The string WebSocket endpoint, ie, "ws://example.com/ws",
+    //                                               "wss://example.com"
+    //                                               "/ws" (inherited host & protocol)
+    // opts - Optional configuration
+    //   transport - The Websocket Transport, ie WebSocket, Phoenix.LongPoller.
+    //               Defaults to WebSocket with automatic LongPoller fallback.
+    //   heartbeatIntervalMs - The millisecond interval to send a heartbeat message
+    //   logger - The optional function for specialized logging, ie:
+    //            `logger: (msg) -> console.log(msg)`
+    //
+    function Socket(endPoint) {
+      var opts = arguments[1] === undefined ? {} : arguments[1];
+      _classCallCheck(this, Socket);
+
+      this.states = SOCKET_STATES;
+      this.stateChangeCallbacks = { open: [], close: [], error: [], message: [] };
+      this.flushEveryMs = 50;
+      this.reconnectTimer = null;
+      this.reconnectAfterMs = 5000;
+      this.heartbeatIntervalMs = 30000;
+      this.channels = [];
+      this.sendBuffer = [];
+
+      this.transport = opts.transport || root.WebSocket || exports.LongPoller;
+      this.heartbeatIntervalMs = opts.heartbeatIntervalMs || this.heartbeatIntervalMs;
+      this.logger = opts.logger || function () {}; // noop
+      this.endPoint = this.expandEndpoint(endPoint);
+      this.resetBufferTimer();
+      this.reconnect();
+    }
+
+    _prototypeProperties(Socket, null, {
+      protocol: {
+        value: function protocol() {
+          return location.protocol.match(/^https/) ? "wss" : "ws";
+        },
+        writable: true,
+        configurable: true
+      },
+      expandEndpoint: {
+        value: function expandEndpoint(endPoint) {
+          if (endPoint.charAt(0) !== "/") {
+            return endPoint;
+          }
+          if (endPoint.charAt(1) === "/") {
+            return "" + this.protocol() + ":" + endPoint;
+          }
+
+          return "" + this.protocol() + "://" + location.host + "" + endPoint;
+        },
+        writable: true,
+        configurable: true
+      },
+      close: {
+        value: function close(callback, code, reason) {
+          if (this.conn) {
+            this.conn.onclose = function () {}; // noop
+            if (code) {
+              this.conn.close(code, reason || "");
+            } else {
+              this.conn.close();
+            }
+            this.conn = null;
+          }
+          callback && callback();
+        },
+        writable: true,
+        configurable: true
+      },
+      reconnect: {
+        value: function reconnect() {
+          var _this = this;
+          this.close(function () {
+            _this.conn = new _this.transport(_this.endPoint);
+            _this.conn.onopen = function () {
+              return _this.onConnOpen();
+            };
+            _this.conn.onerror = function (error) {
+              return _this.onConnError(error);
+            };
+            _this.conn.onmessage = function (event) {
+              return _this.onConnMessage(event);
+            };
+            _this.conn.onclose = function (event) {
+              return _this.onConnClose(event);
+            };
+          });
+        },
+        writable: true,
+        configurable: true
+      },
+      resetBufferTimer: {
+        value: function resetBufferTimer() {
+          var _this = this;
+          clearTimeout(this.sendBufferTimer);
+          this.sendBufferTimer = setTimeout(function () {
+            return _this.flushSendBuffer();
+          }, this.flushEveryMs);
+        },
+        writable: true,
+        configurable: true
+      },
+      log: {
+
+        // Logs the message. Override `this.logger` for specialized logging. noops by default
+        value: function log(msg) {
+          this.logger(msg);
+        },
+        writable: true,
+        configurable: true
+      },
+      onOpen: {
+
+        // Registers callbacks for connection state change events
+        //
+        // Examples
+        //
+        //    socket.onError (error) -> alert("An error occurred")
+        //
+        value: function onOpen(callback) {
+          this.stateChangeCallbacks.open.push(callback);
+        },
+        writable: true,
+        configurable: true
+      },
+      onClose: {
+        value: function onClose(callback) {
+          this.stateChangeCallbacks.close.push(callback);
+        },
+        writable: true,
+        configurable: true
+      },
+      onError: {
+        value: function onError(callback) {
+          this.stateChangeCallbacks.error.push(callback);
+        },
+        writable: true,
+        configurable: true
+      },
+      onMessage: {
+        value: function onMessage(callback) {
+          this.stateChangeCallbacks.message.push(callback);
+        },
+        writable: true,
+        configurable: true
+      },
+      onConnOpen: {
+        value: function onConnOpen() {
+          var _this = this;
+          clearInterval(this.reconnectTimer);
+          if (!this.transport.skipHeartbeat) {
+            this.heartbeatTimer = setInterval(function () {
+              return _this.sendHeartbeat();
+            }, this.heartbeatIntervalMs);
+          }
+          this.rejoinAll();
+          this.stateChangeCallbacks.open.forEach(function (callback) {
+            return callback();
+          });
+        },
+        writable: true,
+        configurable: true
+      },
+      onConnClose: {
+        value: function onConnClose(event) {
+          var _this = this;
+          this.log("WS close:");
+          this.log(event);
+          clearInterval(this.reconnectTimer);
+          clearInterval(this.heartbeatTimer);
+          this.reconnectTimer = setInterval(function () {
+            return _this.reconnect();
+          }, this.reconnectAfterMs);
+          this.stateChangeCallbacks.close.forEach(function (callback) {
+            return callback(event);
+          });
+        },
+        writable: true,
+        configurable: true
+      },
+      onConnError: {
+        value: function onConnError(error) {
+          this.log("WS error:");
+          this.log(error);
+          this.stateChangeCallbacks.error.forEach(function (callback) {
+            return callback(error);
+          });
+        },
+        writable: true,
+        configurable: true
+      },
+      connectionState: {
+        value: function connectionState() {
+          switch (this.conn && this.conn.readyState) {
+            case this.states.connecting:
+              return "connecting";
+            case this.states.open:
+              return "open";
+            case this.states.closing:
+              return "closing";
+            default:
+              return "closed";
+          }
+        },
+        writable: true,
+        configurable: true
+      },
+      isConnected: {
+        value: function isConnected() {
+          return this.connectionState() === "open";
+        },
+        writable: true,
+        configurable: true
+      },
+      rejoinAll: {
+        value: function rejoinAll() {
+          var _this = this;
+          this.channels.forEach(function (chan) {
+            return _this.rejoin(chan);
+          });
+        },
+        writable: true,
+        configurable: true
+      },
+      rejoin: {
+        value: function rejoin(chan) {
+          chan.reset();
+          this.send({ topic: chan.topic, event: "join", payload: chan.message });
+          chan.callback(chan);
+        },
+        writable: true,
+        configurable: true
+      },
+      join: {
+        value: function join(topic, message, callback) {
+          var chan = new exports.Channel(topic, message, callback, this);
+          this.channels.push(chan);
+          if (this.isConnected()) {
+            this.rejoin(chan);
+          }
+        },
+        writable: true,
+        configurable: true
+      },
+      leave: {
+        value: function leave(topic) {
+          var message = arguments[1] === undefined ? {} : arguments[1];
+          this.send({ topic: topic, event: "leave", payload: message });
+          this.channels = this.channels.filter(function (c) {
+            return !c.isMember(topic);
+          });
+        },
+        writable: true,
+        configurable: true
+      },
+      send: {
+        value: function send(data) {
+          var _this = this;
+          var callback = function () {
+            return _this.conn.send(root.JSON.stringify(data));
+          };
+          if (this.isConnected()) {
+            callback();
+          } else {
+            this.sendBuffer.push(callback);
+          }
+        },
+        writable: true,
+        configurable: true
+      },
+      sendHeartbeat: {
+        value: function sendHeartbeat() {
+          this.send({ topic: "phoenix", event: "heartbeat", payload: {} });
+        },
+        writable: true,
+        configurable: true
+      },
+      flushSendBuffer: {
+        value: function flushSendBuffer() {
+          if (this.isConnected() && this.sendBuffer.length > 0) {
+            this.sendBuffer.forEach(function (callback) {
+              return callback();
+            });
+            this.sendBuffer = [];
+          }
+          this.resetBufferTimer();
+        },
+        writable: true,
+        configurable: true
+      },
+      onConnMessage: {
+        value: function onConnMessage(rawMessage) {
+          this.log("message received:");
+          this.log(rawMessage);
+          var _root$JSON$parse = root.JSON.parse(rawMessage.data);
+
+          var topic = _root$JSON$parse.topic;
+          var event = _root$JSON$parse.event;
+          var payload = _root$JSON$parse.payload;
+          this.channels.filter(function (chan) {
+            return chan.isMember(topic);
+          }).forEach(function (chan) {
+            return chan.trigger(event, payload);
+          });
+          this.stateChangeCallbacks.message.forEach(function (callback) {
+            callback(topic, event, payload);
+          });
+        },
+        writable: true,
+        configurable: true
+      }
+    });
+
+    return Socket;
+  })();
+
+
+  exports.LongPoller = (function () {
+    function LongPoller(endPoint) {
+      _classCallCheck(this, LongPoller);
+
+      this.retryInMs = 5000;
+      this.endPoint = null;
+      this.token = null;
+      this.sig = null;
+      this.skipHeartbeat = true;
+      this.onopen = function () {}; // noop
+      this.onerror = function () {}; // noop
+      this.onmessage = function () {}; // noop
+      this.onclose = function () {}; // noop
+      this.states = SOCKET_STATES;
+      this.upgradeEndpoint = this.normalizeEndpoint(endPoint);
+      this.pollEndpoint = this.upgradeEndpoint + (/\/$/.test(endPoint) ? "poll" : "/poll");
+      this.readyState = this.states.connecting;
+
+      this.poll();
+    }
+
+    _prototypeProperties(LongPoller, null, {
+      normalizeEndpoint: {
+        value: function normalizeEndpoint(endPoint) {
+          return endPoint.replace("ws://", "http://").replace("wss://", "https://");
+        },
+        writable: true,
+        configurable: true
+      },
+      endpointURL: {
+        value: function endpointURL() {
+          return this.pollEndpoint + ("?token=" + encodeURIComponent(this.token) + "&sig=" + encodeURIComponent(this.sig));
+        },
+        writable: true,
+        configurable: true
+      },
+      closeAndRetry: {
+        value: function closeAndRetry() {
+          this.close();
+          this.readyState = this.states.connecting;
+        },
+        writable: true,
+        configurable: true
+      },
+      ontimeout: {
+        value: function ontimeout() {
+          this.onerror("timeout");
+          this.closeAndRetry();
+        },
+        writable: true,
+        configurable: true
+      },
+      poll: {
+        value: function poll() {
+          var _this = this;
+          if (!(this.readyState === this.states.open || this.readyState === this.states.connecting)) {
+            return;
+          }
+
+          exports.Ajax.request("GET", this.endpointURL(), "application/json", null, this.ontimeout.bind(this), function (status, resp) {
+            if (resp && resp !== "") {
+              var _root$JSON$parse = root.JSON.parse(resp);
+
+              var token = _root$JSON$parse.token;
+              var sig = _root$JSON$parse.sig;
+              var messages = _root$JSON$parse.messages;
+              _this.token = token;
+              _this.sig = sig;
+            }
+            switch (status) {
+              case 200:
+                messages.forEach(function (msg) {
+                  return _this.onmessage({ data: root.JSON.stringify(msg) });
+                });
+                _this.poll();
+                break;
+              case 204:
+                _this.poll();
+                break;
+              case 410:
+                _this.readyState = _this.states.open;
+                _this.onopen();
+                _this.poll();
+                break;
+              case 0:
+              case 500:
+                _this.onerror();
+                _this.closeAndRetry();
+                break;
+              default:
+                throw "unhandled poll status " + status;
+            }
+          });
+        },
+        writable: true,
+        configurable: true
+      },
+      send: {
+        value: function send(body) {
+          var _this = this;
+          exports.Ajax.request("POST", this.endpointURL(), "application/json", body, this.onerror.bind(this, "timeout"), function (status, resp) {
+            if (status !== 200) {
+              _this.onerror(status);
+            }
+          });
+        },
+        writable: true,
+        configurable: true
+      },
+      close: {
+        value: function close(code, reason) {
+          this.readyState = this.states.closed;
+          this.onclose();
+        },
+        writable: true,
+        configurable: true
+      }
+    });
+
+    return LongPoller;
+  })();
+
+
+  exports.Ajax = {
+
+    states: { complete: 4 },
+
+    request: function (method, endPoint, accept, body, ontimeout, callback) {
+      var _this = this;
+      var req = root.XMLHttpRequest ? new root.XMLHttpRequest() : // IE7+, Firefox, Chrome, Opera, Safari
+      new root.ActiveXObject("Microsoft.XMLHTTP"); // IE6, IE5
+      req.open(method, endPoint, true);
+      req.setRequestHeader("Content-type", accept);
+      req.onerror = function () {
+        callback && callback(500, null);
+      };
+      req.onreadystatechange = function () {
+        if (req.readyState === _this.states.complete && callback) {
+          callback(req.status, req.responseText);
+        }
+      };
+      if (ontimeout) {
+        req.ontimeout = ontimeout;
+      }
+
+      req.send(body);
+    }
+  };
+});

+ 15 - 0
frameworks/Elixir/phoenix/setup.sh

@@ -0,0 +1,15 @@
+#!/bin/bash
+
+source $IROOT/elixir.installed
+
+sed -i 's|db_host: "localhost",|db_host: "${DBHOST}",|g' config/config.exs
+
+rm -rf _build deps
+
+mix local.hex --force
+mix local.rebar --force
+mix deps.get --force
+
+MIX_ENV=prod mix compile.protocols --force
+MIX_ENV=prod elixir --detached -pa _build/$MIX_ENV/consolidated -S mix phoenix.server
+

+ 7 - 0
frameworks/Elixir/phoenix/test/hello_test.exs

@@ -0,0 +1,7 @@
+defmodule HelloTest do
+  use ExUnit.Case
+
+  test "the truth" do
+    assert 1 + 1 == 2
+  end
+end

+ 1 - 0
frameworks/Elixir/phoenix/test/test_helper.exs

@@ -0,0 +1 @@
+ExUnit.start

+ 40 - 0
frameworks/Elixir/phoenix/web/controllers/page_controller.ex

@@ -0,0 +1,40 @@
+defmodule Hello.PageController do
+  use Phoenix.Controller
+
+  plug :action
+
+  def index(conn, _params) do
+    json conn, %{
+      "TE Benchmarks\n" => "Started",
+      "DBHOST" => System.get_env("DBHOST"),
+      "DBPORT" => System.get_env("DBPORT"),
+    }
+  end
+
+  # avoid namespace collision
+  def _json(conn, _params) do
+    json conn, %{message: "Hello, world!"}
+  end
+
+  def db(conn, _params) do
+    :random.seed(:erlang.now)
+    id = :random.uniform(10000)
+    text conn, "TE Benchmarks\n"
+  end
+
+  def queries(conn, _params) do
+    text conn, "TE Benchmarks\n"
+  end
+
+  def fortunes(conn, _params) do
+    text conn, "TE Benchmarks\n"
+  end
+
+  def updates(conn, _params) do
+    text conn, "TE Benchmarks\n"
+  end
+
+  def plaintext(conn, _params) do
+    text conn, "Hello, world!"
+  end
+end

+ 11 - 0
frameworks/Elixir/phoenix/web/models/repo.exs

@@ -0,0 +1,11 @@
+defmodule Hello.Repo do
+  use Ecto.Repo, adapter: Ecto.Adapters.Postgres
+
+  def conf do
+    parse_url "ecto://username:password@host/database_name"
+  end
+
+  def priv do
+    app_dir(:hello, "priv/repo")
+  end
+end

+ 7 - 0
frameworks/Elixir/phoenix/web/models/world.exs

@@ -0,0 +1,7 @@
+defmodule Hello.User do
+  use Ecto.Model
+
+  schema "world" do
+    field :randomNumber, :integer
+  end
+end

+ 31 - 0
frameworks/Elixir/phoenix/web/router.ex

@@ -0,0 +1,31 @@
+defmodule Hello.Router do
+  use Phoenix.Router
+
+  pipeline :browser do
+    plug :accepts, ~w(html)
+    plug :fetch_session
+    plug :fetch_flash
+    plug :protect_from_forgery
+  end
+
+  pipeline :api do
+    plug :accepts, ~w(json)
+  end
+
+  scope "/", Hello do
+    pipe_through :browser # Use the default browser stack
+
+    get "/json", PageController, :_json
+    get "/db", PageController, :db
+    get "/queries", PageController, :queries
+    get "/fortunes", PageController, :fortunes
+    get "/updates", PageController, :updates
+    get "/plaintext", PageController, :plaintext
+    get "/", PageController, :index
+  end
+
+  # Other scopes may use custom stacks.
+  # scope "/api", Hello do
+  #   pipe_through :api
+  # end
+end

+ 31 - 0
frameworks/Elixir/phoenix/web/templates/layout/application.html.eex

@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <meta name="description" content="">
+    <meta name="author" content="">
+
+    <title>Hello Phoenix!</title>
+    <link rel="stylesheet" href="/css/phoenix.css">
+  </head>
+
+  <body>
+    <div class="container">
+      <div class="header">
+        <ul class="nav nav-pills pull-right">
+          <li><a href="http://www.phoenixframework.org/docs">Get Started</a></li>
+        </ul>
+        <span class="logo"></span>
+      </div>
+
+      <%= @inner %>
+
+      <div class="footer">
+        <p><a href="http://phoenixframework.org">phoenixframework.org</a></p>
+      </div>
+
+    </div> <!-- /container -->
+  </body>
+</html>

+ 1 - 0
frameworks/Elixir/phoenix/web/templates/page/error.html.eex

@@ -0,0 +1 @@
+Something went wrong

+ 34 - 0
frameworks/Elixir/phoenix/web/templates/page/index.html.eex

@@ -0,0 +1,34 @@
+<div class="jumbotron">
+  <h2>Welcome to Phoenix!</h2>
+  <p class="lead">Phoenix is an Elixir Web Framework targeting full-featured, fault tolerant applications with realtime functionality.</p>
+</div>
+
+<div class="row marketing">
+  <div class="col-lg-6">
+    <h4>Resources</h4>
+    <ul>
+      <li>
+        <a href="http://hexdocs.pm/phoenix">Docs</a>
+      </li>
+      <li>
+        <a href="https://github.com/phoenixframework/phoenix">Source</a>
+      </li>
+    </ul>
+  </div>
+
+  <div class="col-lg-6">
+    <h4>Help</h4>
+    <ul>
+      <li>
+        <a href="https://github.com/phoenixframework/phoenix/issues?state=open">Issues</a>
+      </li>
+      <li>
+        <a href="irc://irc.freenode.net/elixir-lang">#elixir-lang on freenode IRC</a>
+      </li>
+      <li>
+        <a href="https://twitter.com/chris_mccord">@chris_mccord</a>
+      </li>
+    </ul>
+  </div>
+</div>
+

+ 1 - 0
frameworks/Elixir/phoenix/web/templates/page/not_found.html.eex

@@ -0,0 +1 @@
+The page you are looking for does not exist

+ 17 - 0
frameworks/Elixir/phoenix/web/view.ex

@@ -0,0 +1,17 @@
+defmodule Hello.View do
+  use Phoenix.View, root: "web/templates"
+
+  # The quoted expression returned by this block is applied
+  # to this module and all other views that use this module.
+  using do
+    quote do
+      # Import common functionality
+      import Hello.Router.Helpers
+
+      # Use Phoenix.HTML to import all HTML functions (forms, tags, etc)
+      use Phoenix.HTML
+    end
+  end
+
+  # Functions defined here are available to all other views/templates
+end

+ 16 - 0
frameworks/Elixir/phoenix/web/views/error_view.ex

@@ -0,0 +1,16 @@
+defmodule Hello.ErrorView do
+  use Hello.View
+
+  def render("404.html", _assigns) do
+    "Page not found - 404"
+  end
+
+  def render("500.html", _assigns) do
+    "Server internal error - 500"
+  end
+
+  # Render all other templates as 500
+  def render(_, assigns) do
+    render "500.html", assigns
+  end
+end

+ 3 - 0
frameworks/Elixir/phoenix/web/views/layout_view.ex

@@ -0,0 +1,3 @@
+defmodule Hello.LayoutView do
+  use Hello.View
+end

+ 3 - 0
frameworks/Elixir/phoenix/web/views/page_view.ex

@@ -0,0 +1,3 @@
+defmodule Hello.PageView do
+  use Hello.View
+end

+ 1 - 2
frameworks/Erlang/cowboy/.gitignore

@@ -1,5 +1,4 @@
 erl_crash.dump
-__init__.py
 deps
 ebin
-*.deb
+.rebar

+ 1 - 1
frameworks/Erlang/cowboy/benchmark_config.json

@@ -2,7 +2,7 @@
   "framework": "cowboy",
   "tests": [{
     "default": {
-      "setup_file": "setup_erlang",
+      "setup_file": "setup",
       "json_url": "/json",
       "db_url": "/db",
       "query_url": "/query?queries=",

+ 5 - 3
frameworks/Erlang/cowboy/setup_erlang.sh → frameworks/Erlang/cowboy/setup.sh

@@ -1,9 +1,11 @@
 #!/bin/bash
-export REBAR_HOME=$IROOT/rebar
+
+source $IROOT/erlang.installed
+source $IROOT/rebar.installed
 
 sed -i 's|"benchmarkdbpass", ".*", 3306|"benchmarkdbpass", "'"${DBHOST}"'", 3306|g' src/hello_world_app.erl
 
-rm -rf deps/*
+rm -rf deps/* ebin/*
 $REBAR_HOME/rebar get-deps
 $REBAR_HOME/rebar compile
-erl -pa ebin deps/*/ebin +sbwt very_long +swt very_low -s hello_world -noshell -detached
+erl -pa ebin deps/*/ebin +sbwt very_long +swt very_low -s hello_world -noshell -detached

+ 1 - 2
frameworks/Erlang/elli/.gitignore

@@ -1,5 +1,4 @@
 erl_crash.dump
-__init__.py
 deps
 ebin
-*.deb
+.rebar

+ 1 - 1
frameworks/Erlang/elli/benchmark_config.json

@@ -2,7 +2,7 @@
   "framework": "elli",
   "tests": [{
     "default": {
-      "setup_file": "setup_erlang",
+      "setup_file": "setup",
       "json_url": "/json",
       "db_url": "/db",
       "query_url": "/query?queries=",

+ 2 - 2
frameworks/Erlang/elli/rebar.config

@@ -1,6 +1,6 @@
 {deps,
  [
-  {jiffy, ".*", {git, "https://github.com/davisp/jiffy.git", {tag, "0.8.5"}}},
+  {jiffy, ".*", {git, "https://github.com/davisp/jiffy.git", {tag, "0.13.3"}}},
   {emysql, ".*", {git, "https://github.com/Eonblast/Emysql.git"}},
-  {elli, "", {git, "git://github.com/knutin/elli.git"}}
+  {elli, "", {git, "git://github.com/knutin/elli.git", {tag, "v1.0.3"}}}
  ]}.

+ 5 - 3
frameworks/Erlang/elli/setup_erlang.sh → frameworks/Erlang/elli/setup.sh

@@ -1,9 +1,11 @@
 #!/bin/bash
-export REBAR_HOME=$IROOT/rebar
+
+source $IROOT/erlang.installed
+source $IROOT/rebar.installed
 
 sed -i 's|"benchmarkdbpass", ".*", 3306|"benchmarkdbpass", "'"${DBHOST}"'", 3306|g' src/elli_bench_sup.erl
 
-rm -rf deps/*
+rm -rf deps/* ebin/*
 $REBAR_HOME/rebar get-deps
 $REBAR_HOME/rebar compile
-erl -pa ebin deps/*/ebin +sbwt very_long +swt very_low -s elli_bench -noshell -detached
+erl -pa ebin deps/*/ebin +sbwt very_long +swt very_low -s elli_bench -noshell -detached

+ 11 - 5
frameworks/Haskell/wai/bench/wai.hs

@@ -5,8 +5,8 @@ import Control.Concurrent (runInUnboundThread)
 import Data.Aeson ((.=), object, encode)
 import qualified Data.ByteString.Lazy as L
 import Data.Text (Text)
-import Network.HTTP.Types (status200)
-import Network.Wai (responseBuilder)
+import Network.HTTP.Types (status200, status404)
+import Network.Wai (responseBuilder, rawPathInfo)
 import qualified Network.Wai.Handler.Warp as W
 
 main :: IO ()
@@ -15,10 +15,16 @@ main =
   where
     settings = W.setPort 8000
              $ W.setOnException (\_ _ -> return ()) W.defaultSettings
-    app _ respond = respond response
-    !response = responseBuilder status200 ct json
-    ct = [("Content-Type", "application/json")]
+    app request respond = case rawPathInfo request of
+        "/json" -> respond responseJson
+        "/plaintext" -> respond responsePlaintext
+        _ -> respond $ responseBuilder status404 [] ""
+    !responseJson = responseBuilder status200 ctJson json
+    ctJson = [("Content-Type", "application/json")]
     !json = copyByteString
           $ L.toStrict
           $ encode
           $ object ["message" .= ("Hello, World!" :: Text)]
+    !responsePlaintext = responseBuilder status200 ctPlaintext plaintext
+    ctPlaintext = [("Content-type", "text/plain")]
+    plaintext = "Hello, World!"

+ 1 - 0
frameworks/Haskell/wai/benchmark_config.json

@@ -4,6 +4,7 @@
     "default": {
       "setup_file": "setup",
       "json_url": "/json",
+      "plaintext_url": "/plaintext",
       "port": 8000,
       "approach": "Realistic",
       "classification": "Platform",

+ 2 - 0
frameworks/Haskell/yesod/bench/bench.cabal

@@ -37,6 +37,8 @@ executable         bench
                  , http-types
                  , aeson
                  , blaze-builder
+                 , blaze-html
                  , bytestring                    >= 0.10
                  , resource-pool
                  , resourcet
+                 , shakespeare

+ 119 - 37
frameworks/Haskell/yesod/bench/src/yesod.hs

@@ -14,34 +14,39 @@
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 module Main (main, resourcesApp, Widget, WorldId) where
 import           Blaze.ByteString.Builder
-import           Control.Concurrent           (runInUnboundThread)
-import           Control.Monad                (replicateM)
-import           Control.Monad.Logger         (runNoLoggingT)
-import           Control.Monad.Primitive      (PrimState)
-import           Control.Monad.Reader         (ReaderT)
-import           Control.Monad.Trans.Resource (InternalState)
-import           Data.Aeson                   (encode)
-import qualified Data.ByteString.Lazy         as L
-import           Data.Conduit.Pool            (Pool, createPool)
-import           Data.Int                     (Int64)
-import           Data.IORef                   (newIORef)
-import           Data.Pool                    (withResource)
-import           Data.Text                    (Text)
-import           Database.MongoDB             (Field ((:=)), (=:))
-import qualified Database.MongoDB             as Mongo
-import           Database.Persist             (Key, PersistEntity,
-                                               PersistEntityBackend,
-                                               PersistStore, get)
-import qualified Database.Persist.MySQL       as My
-import           Database.Persist.TH          (mkPersist, mpsGeneric,
-                                               persistLowerCase, sqlSettings)
-import           Network                      (PortID (PortNumber))
+import           Control.Applicative           (liftA2)
+import           Control.Concurrent            (runInUnboundThread)
+import           Control.Monad                 (replicateM)
+import           Control.Monad.Logger          (runNoLoggingT)
+import           Control.Monad.Primitive       (PrimState)
+import           Control.Monad.Reader          (ReaderT)
+import           Control.Monad.Trans.Resource  (InternalState)
+import           Data.Aeson                    (encode)
+import qualified Data.ByteString.Lazy          as L
+import           Data.Conduit.Pool             (Pool, createPool)
+import           Data.Int                      (Int64)
+import           Data.IORef                    (newIORef)
+import           Data.Function                 (on)
+import           Data.List                     (sortBy)
+import           Data.Pool                     (withResource)
+import           Data.Text                     (Text)
+import           Database.MongoDB              (Field ((:=)), (=:))
+import qualified Database.MongoDB              as Mongo
+import           Database.Persist              (Key, PersistEntity,
+                                                PersistEntityBackend,
+                                                PersistStore, get, update,
+                                                (=.))
+import qualified Database.Persist.MySQL        as My
+import           Database.Persist.TH           (mkPersist, mpsGeneric,
+                                                persistLowerCase, sqlSettings)
+import           Network                       (PortID (PortNumber))
 import           Network.HTTP.Types
 import           Network.Wai
-import qualified Network.Wai.Handler.Warp     as Warp
-import           System.Environment           (getArgs)
-import           System.IO.Unsafe             (unsafePerformIO)
-import qualified System.Random.MWC            as R
+import qualified Network.Wai.Handler.Warp      as Warp
+import           System.Environment            (getArgs)
+import           System.IO.Unsafe              (unsafePerformIO)
+import qualified System.Random.MWC             as R
+import           Text.Blaze.Html.Renderer.Utf8 (renderHtmlBuilder)
 import           Yesod.Core
 
 mkPersist sqlSettings { mpsGeneric = True } [persistLowerCase|
@@ -49,6 +54,11 @@ World sql=World
     randomNumber Int sql=randomNumber
 |]
 
+mkPersist sqlSettings { mpsGeneric = True } [persistLowerCase|
+Fortune sql=Fortune
+    message Text sql=message
+|]
+
 data App = App
     { appGen      :: !(R.Gen (PrimState IO))
     , mySqlPool   :: !(Pool My.SqlBackend)
@@ -62,11 +72,18 @@ mkYesod "App" [parseRoutes|
 
 /db                 DbR       GET
 /dbs/#Int           DbsR      GET
-!/dbs/#Text         DbsRdefault  GET
+!/dbs/#Text         DbsDefaultR  GET
 
 /mongo/raw/db       MongoRawDbR  GET
 /mongo/raw/dbs/#Int MongoRawDbsR GET
-!/mongo/raw/dbs/#Text MongoRawDbsRdefault GET
+!/mongo/raw/dbs/#Text MongoRawDbsDefaultR GET
+
+/updates/#Int       UpdatesR     GET
+!/updates/#Text     UpdatesDefaultR GET
+
+/fortunes           FortunesR    GET
+
+/plaintext          PlaintextR   GET
 |]
 
 fakeInternalState :: InternalState
@@ -107,28 +124,42 @@ getMongoRawDbR = getDb rawMongoIntQuery
 getDbsR :: Int -> Handler Value
 getDbsR cnt = do
     App {..} <- getYesod
-    multiRandomHandler (intQuery runMySQL My.toSqlKey) cnt'
+    multiRandomHandler randomNumber (intQuery runMySQL My.toSqlKey) cnt'
   where
     cnt' | cnt < 1 = 1
          | cnt > 500 = 500
          | otherwise = cnt
 
-getDbsRdefault :: Text -> Handler Value
-getDbsRdefault _ = getDbsR 1
+getDbsDefaultR :: Text -> Handler Value
+getDbsDefaultR _ = getDbsR 1
 
 getMongoRawDbsR :: Int -> Handler Value
-getMongoRawDbsR cnt = multiRandomHandler rawMongoIntQuery cnt'
+getMongoRawDbsR cnt = multiRandomHandler randomNumber rawMongoIntQuery cnt'
   where
     cnt' | cnt < 1 = 1
          | cnt > 500 = 500
          | otherwise = cnt
 
-getMongoRawDbsRdefault :: Text -> Handler Value
-getMongoRawDbsRdefault _ = getMongoRawDbsR 1
+getMongoRawDbsDefaultR :: Text -> Handler Value
+getMongoRawDbsDefaultR _ = getMongoRawDbsR 1
+
+getUpdatesR :: Int -> Handler Value
+getUpdatesR cnt = multiRandomHandler randomPair go cnt'
+  where
+    cnt' | cnt < 1 = 1
+         | cnt > 500 = 500
+         | otherwise = cnt
+    go = uncurry (intUpdate runMySQL My.toSqlKey)
+
+getUpdatesDefaultR :: Text -> Handler Value
+getUpdatesDefaultR _ = getUpdatesR 1
 
 randomNumber :: R.Gen (PrimState IO) -> IO Int64
 randomNumber appGen = R.uniformR (1, 10000) appGen
 
+randomPair :: R.Gen (PrimState IO) -> IO (Int64, Int64)
+randomPair appGen = liftA2 (,) (randomNumber appGen) (randomNumber appGen)
+
 getDb :: (Int64 -> Handler Value) -> Handler Value
 getDb query = do
     app <- getYesod
@@ -172,13 +203,28 @@ rawMongoIntQuery i = do
     Just x <- runMongoDB $ Mongo.findOne (Mongo.select ["id" =: i] "World")
     return $ documentToJson x
 
+intUpdate :: (Functor m, Monad m, MonadIO m
+             , PersistStore backend) =>
+             (ReaderT backend m (Maybe (WorldGeneric backend))
+                -> m (Maybe (WorldGeneric backend)))
+             -> (Int64 -> Key (WorldGeneric backend))
+             -> Int64 -> Int64 -> m Value
+intUpdate db toKey i v = do
+    Just x <- db $ get k
+    _ <- db $ fmap (const Nothing) $
+             update k [WorldRandomNumber =. fromIntegral v]
+    return $ object ["id" .= i, "randomNumber" .= v]
+  where
+    k = toKey i
+
 multiRandomHandler :: ToJSON a
-                   => (Int64 -> Handler a)
+                   => (R.Gen (PrimState IO) -> IO b)
+                   -> (b -> Handler a)
                    -> Int
                    -> Handler Value
-multiRandomHandler operation cnt = do
+multiRandomHandler rand operation cnt = do
     App {..} <- getYesod
-    nums <- liftIO $ replicateM cnt (randomNumber appGen)
+    nums <- liftIO $ replicateM cnt (rand appGen)
     return . array =<< mapM operation nums
 
 documentToJson :: [Field] -> Value
@@ -195,6 +241,42 @@ instance ToJSON Mongo.Value where
   toJSON (Mongo.Doc d)   = documentToJson d
   toJSON s = error $ "no convert for: " ++ show s
 
+getFortunesR :: Handler ()
+getFortunesR = do
+    es <- runMySQL $ My.selectList [] []
+    sendWaiResponse
+        $ responseBuilder status200 [("Content-type", typeHtml)]
+        $ fortuneTemplate (messages es)
+  where
+    messages es = sortBy (compare `on` snd)
+        ((0, "Additional fortune added at request time.") : map stripEntity es)
+    stripEntity e =
+        (My.fromSqlKey (My.entityKey e), fortuneMessage . My.entityVal $ e)
+
+getPlaintextR :: Handler ()
+getPlaintextR = sendWaiResponse
+              $ responseBuilder
+                status200
+                [("Content-Type", typePlain)]
+              $ copyByteString "Hello, World!"
+
+fortuneTemplate :: [(Int64, Text)] -> Builder
+fortuneTemplate messages = renderHtmlBuilder $ [shamlet|
+$doctype 5
+<html>
+    <head>
+        <title>Fortunes
+    <body>
+        <table>
+            <tr>
+                <th>id
+                <th>message
+            $forall message <- messages
+                <tr>
+                    <td>#{fst message}
+                    <td>#{snd message}
+|]
+
 
 
 main :: IO ()

+ 3 - 0
frameworks/Haskell/yesod/benchmark_config.json

@@ -6,6 +6,9 @@
       "json_url": "/json",
       "db_url": "/db",
       "query_url": "/dbs/",
+      "update_url": "/updates/",
+      "fortune_url": "/fortunes",
+      "plaintext_url": "/plaintext",
       "port": 8000,
       "approach": "Realistic",
       "classification": "Fullstack",

+ 32 - 6
frameworks/Java/README.md

@@ -1,7 +1,20 @@
-# Installation and Bash Configuration
+# Java Frameworks
 
-In order to declare that your framework requires Java, you should have an `install.sh`
-that contains at least
+The information below contains information specific to Java. 
+For further guidance, review the 
+[documentation](http://frameworkbenchmarks.readthedocs.org/en/latest/).
+
+## Infrastructure Software Versions
+
+* Java 7
+* Java 8
+
+## Adding a New Java Framework
+
+### Installation and Bash Configuration
+
+In order to declare that your framework requires Java, you 
+should have an `install.sh` that contains at least
 
     #!/bin/bash
 
@@ -9,7 +22,20 @@ that contains at least
 
 This installs the OpenJDK 7 JVM.
 
-Frameworks can also choose to install Oracle Java 8 JVM by declaring a dependency on "java8"
-instead of java. In order to use Java 8 JVM frameworks need to add the following line in their "setup.sh" file:
+Frameworks can also choose to install Oracle Java 8 JVM by 
+declaring a dependency on "java8" instead of java. In order 
+to use Java 8 JVM frameworks need to add the following line 
+in their "setup.sh" file:
+
+    export JAVA_HOME=/opt/java8
+
+## Get Help
+
+### Java Experts
+
+_There aren't any experts listed, yet. If you're an expert, 
+add yourself!_
+
+### Interesting Links
 
-export JAVA_HOME=/opt/java8
+* [Surprise! Java is fastest for server-side Web apps](http://www.infoworld.com/article/2609675/java/surprise--java-is-fastest-for-server-side-web-apps.html)

+ 1 - 1
frameworks/JavaScript/express/app.js

@@ -1,3 +1,3 @@
 #!/bin/bash
 
-fw_depends nodejs
+fw_depends nvm

+ 12 - 14
frameworks/JavaScript/express/setup.sh

@@ -1,20 +1,18 @@
 #!/bin/bash
-export NODE_HOME=${IROOT}/node-v0.10.8-linux-x64
-
 sed -i 's|mongodb://.*/hello_world|mongodb://'"${DBHOST}"'/hello_world|g' app.js
 sed -i 's|localhost|'"${DBHOST}"'|g' app.js
 
-export NODE_HOME=${IROOT}/node-v0.10.8-linux-x64
-export PATH=$PATH:$NODE_HOME/bin
+export NODE_ENV=production
+export NVM_HOME=${IROOT}/nvm
+# Used to avoid nvm's return 2 error.
+# Sourcing this functions if 0 is returned.
+source $NVM_HOME/nvm.sh || 0
+nvm install 0.10.8
+nvm use 0.10.8
 
-${NODE_HOME}/bin/npm install
-${NODE_HOME}/bin/node app &
+# update npm before app init
+npm install -g npm
 
-# !DO NOT REMOVE!
-#
-# It takes `node app` a few seconds to turn on and 
-# then fork. If you remove this sleep, the parent shell 
-# executing this script will be terminated before the 
-# application has time to awaken and be forked, and 
-# express will fail to be started
-sleep 5
+# run app
+npm install
+node app &

+ 1 - 1
frameworks/JavaScript/hapi/app.js

@@ -1,3 +1,3 @@
 #!/bin/bash
 
-fw_depends nodejs
+fw_depends nvm

+ 11 - 14
frameworks/JavaScript/hapi/setup.sh

@@ -1,20 +1,17 @@
 #!/bin/bash
-export NODE_HOME=${IROOT}/node-v0.10.8-linux-x64
-
 sed -i 's|localhost|'"${DBHOST}"'|g' app.js
 
 export NODE_ENV=production
-export NODE_HOME=${IROOT}/node-v0.10.8-linux-x64
-export PATH=$PATH:$NODE_HOME/bin
+export NVM_HOME=${IROOT}/nvm
+# Used to avoid nvm's return 2 error.
+# Sourcing this functions if 0 is returned.
+source $NVM_HOME/nvm.sh || 0
+nvm install 0.10.8
+nvm use 0.10.8
 
-${NODE_HOME}/bin/npm install
-${NODE_HOME}/bin/node app &
+# update npm before app init
+npm install -g npm
 
-# !DO NOT REMOVE!
-#
-# It takes `node app` a few seconds to turn on and 
-# then fork. If you remove this sleep, the parent shell 
-# executing this script will be terminated before the 
-# application has time to awaken and be forked, and 
-# express will fail to be started
-sleep 5
+# run app
+npm install
+node app &

+ 0 - 0
frameworks/JavaScript/koa/README.md


+ 128 - 0
frameworks/JavaScript/koa/app.js

@@ -0,0 +1,128 @@
+var cluster = require('cluster')
+  , numCPUs = require('os').cpus().length;
+
+// Koa Deps
+var koa = require('koa')
+  , route = require('koa-route')
+  , handlebars = require('koa-handlebars')
+  , bodyParser = require('koa-bodyparser')
+  , override = require('koa-override');
+
+// Monk MongoDB Driver Deps
+var monk = require('monk')
+  , wrap = require('co-monk')
+  , db = monk('mongodb://localhost/hello_world')
+  , worlds = wrap(db.get('world'))
+  , fortunes = wrap(db.get('fortune'));
+
+if (cluster.isMaster) {
+  // Fork workers.
+  for (var i = 0; i < numCPUs; i++) {
+    cluster.fork();
+  }
+
+  cluster.on('exit', function(worker, code, signal) {
+    console.log('worker ' + worker.process.pid + ' died');
+  });
+} else {
+  var app = module.exports = koa();
+  app.use(bodyParser());
+  app.use(override());
+  app.use(handlebars({
+    // needed, otherwise missing dir err
+    partialsDir: "views"
+  }));
+
+  // routes
+  app.use(route.get('/json', jsonHandler));
+  app.use(route.get('/db', dbHandler));
+  app.use(route.get('/queries', queriesHandler));
+  app.use(route.get('/fortunes', fortuneHandler));
+  app.use(route.get('/updates', updateHandler));
+  app.use(route.get('/plaintext', textHandler));
+
+  // Helpers
+  function getRandomNumber() {
+    return Math.floor(Math.random()*10000) + 1;
+  };
+
+  function validateParam(param) {
+    var numOfQueries = isNaN(param) ? 1 : param;
+    if (numOfQueries > 500) {
+      numOfQueries = 500;
+    } else if (numOfQueries < 1) {
+      numOfQueries = 1;
+    }
+    return numOfQueries;
+  }
+
+  // Query Helpers
+  function *worldUpdateQuery() {
+    var randomId = getRandomNumber();
+    var randomNumber = getRandomNumber();
+    var result = yield worlds.update(
+      {id: randomId}, 
+      {$set: {randomNumber: randomNumber}}
+    );
+    return {
+      id: randomId,
+      randomNumber: randomNumber
+    }
+  }
+
+  function *worldQuery() {
+    return yield worlds.findOne({id: getRandomNumber()}, '-_id');
+  }
+
+  function *fortunesQuery() {
+    return yield fortunes.find({}, '-_id');
+  }
+
+  // Route handlers
+  function *jsonHandler() {
+    this.body = {
+      message: "Hello, world!"
+    }
+  }
+
+  function *dbHandler() {
+    this.body = yield worldQuery;
+  }
+
+  function *queriesHandler() {
+    var numOfQueries = validateParam(this.query.queries);
+    var queries = [];
+    for (var i = 0; i < numOfQueries; i++) {
+      queries.push(worldQuery);
+    }
+    this.body = yield queries;
+  }
+
+  function *fortuneHandler() {
+    this.set('Server', 'Koa');
+    var fortunes = yield fortunesQuery;
+    fortunes.push({
+      id: 0,
+      message: 'Additional fortune added at request time.'
+    });
+    fortunes.sort(function(a, b) {
+      return a.message < b.message ? -1 : 1;
+    });
+    yield this.render("fortunes", {fortunes: fortunes});
+  }
+
+  function *updateHandler() {
+    var numOfUpdates = validateParam(this.query.queries);
+    var queries = [];
+    for (var i = 0; i < numOfUpdates; i++) {
+      queries.push(worldUpdateQuery);
+    }
+    this.body = yield queries;
+  }
+
+  function *textHandler() {
+    this.body = 'Hello, world!';
+  }
+
+  app.listen(8080);
+}

+ 28 - 0
frameworks/JavaScript/koa/benchmark_config.json

@@ -0,0 +1,28 @@
+{
+  "framework": "koa",
+  "tests": [{
+    "default": {
+      "setup_file": "setup",
+      "json_url": "/json",
+      "db_url": "/db",
+      "query_url": "/queries?queries=",
+      "fortune_url": "/fortunes",
+      "update_url": "/updates?queries=",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Micro",
+      "database": "MongoDB",
+      "framework": "koa",
+      "language": "JavaScript",
+      "orm": "Raw",
+      "platform": "nodejs",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "koa",
+      "notes": "",
+      "versus": "node"
+    }
+  }]
+}

+ 3 - 0
frameworks/JavaScript/koa/install.sh

@@ -0,0 +1,3 @@
+#!/bin/bash
+
+fw_depends nvm

+ 17 - 0
frameworks/JavaScript/koa/package.json

@@ -0,0 +1,17 @@
+{
+  "name": "koa-tfb",
+  "version": "0.0.1",
+  "description": "Koa tests for TechEmpower Framework Benchmarks.",
+  "main": "app.js",
+  "private": true,
+  "dependencies": {
+    "co-monk": "1.0.0",
+    "koa": "0.18.1",
+    "koa-bodyparser": "1.4.1",
+    "koa-handlebars": "0.5.2",
+    "koa-mongo": "0.3.0",
+    "koa-override": "1.0.0",
+    "koa-route": "2.4.0",
+    "monk": "1.0.1"
+  }
+}

+ 17 - 0
frameworks/JavaScript/koa/setup.sh

@@ -0,0 +1,17 @@
+#!/bin/bash
+
+sed -i 's|mongodb://.*/hello_world|mongodb://'"${DBHOST}"'/hello_world|g' app.js
+
+export NVM_HOME=${IROOT}/nvm
+# Used to avoid nvm's return 2 error.
+# Sourcing this functions if 0 is returned.
+source $NVM_HOME/nvm.sh || 0
+nvm install 0.11.16
+nvm use 0.11.16
+
+# update npm before app init
+npm install -g npm
+
+# run app
+npm install
+node --harmony app &

+ 0 - 0
frameworks/JavaScript/koa/source_code


+ 21 - 0
frameworks/JavaScript/koa/views/fortunes.hbs

@@ -0,0 +1,21 @@
+<!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>

+ 1 - 3
frameworks/JavaScript/nodejs/hello.js

@@ -1,5 +1,3 @@
 #!/bin/bash
 
-export NODE_HOME=${IROOT}/node-v0.10.8-linux-x64
-
-fw_depends nodejs
+fw_depends nvm

+ 11 - 15
frameworks/JavaScript/nodejs/setup.sh

@@ -1,21 +1,17 @@
 #!/bin/bash
-export NODE_HOME=${IROOT}/node-v0.10.8-linux-x64
-
 sed -i 's|localhost|'"${DBHOST}"'|g' hello.js
-sed -i 's|mongodb//.*/hello_world|mongodb//'"${DBHOST}"'/hello_world|g' hello.js
+sed -i 's|mongodb://.*/hello_world|mongodb://'"${DBHOST}"'/hello_world|g' hello.js
 
 export NODE_ENV=production
-export NODE_HOME=${IROOT}/node-v0.10.8-linux-x64
-export PATH=$PATH:$NODE_HOME/bin
+export NVM_HOME=${IROOT}/nvm
+# Used to avoid nvm's return 2 error.
+# Sourcing this functions if 0 is returned.
+source $NVM_HOME/nvm.sh || 0
+nvm install 0.10.8
+nvm use 0.10.8
 
-${NODE_HOME}/bin/npm install
-${NODE_HOME}/bin/node hello.js &
+# update npm before app init
+npm install -g npm
 
-# !DO NOT REMOVE!
-#
-# It takes `node app` a few seconds to turn on and 
-# then fork. If you remove this sleep, the parent shell 
-# executing this script will be terminated before the 
-# application has time to awaken and be forked, and 
-# express will fail to be started
-sleep 5
+npm install
+node hello.js &

+ 30 - 8
frameworks/PHP/README.md

@@ -1,10 +1,20 @@
-# PHP Version
+# PHP Frameworks
+
+The information below contains information specific to PHP. 
+For further guidance, review the 
+[documentation](http://frameworkbenchmarks.readthedocs.org/en/latest/).
+
+## Infrastructre Software Versions
+
+### PHP Version
 
 [Currently this toolset runs PHP 5.5.17](https://github.com/TechEmpower/FrameworkBenchmarks/blob/master/toolset/setup/linux/languages/php.sh). At the moment all PHP-based frameworks use the 
 same PHP version, but we are open to receiving a pull request
 that enables supporting multiple versions. 
 
-# PHP Acceleration and Caching
+## Adding New PHP-based Frameworks
+
+### PHP Acceleration and Caching
 
 Caching the output of the PHP bytecode compiler is expressly 
 allowed by this benchmark. As we use PHP 5.5, which comes 
@@ -43,7 +53,7 @@ easier to use systems such as APCu.
 
 Ask if you are not certain.
 
-# Adding New PHP-based Frameworks
+## Install.sh and Setup.sh Files
 
 Most PHP frameworks use `fw_depends php nginx composer` in their `install.sh` file, 
 which installs PHP, Nginx, and Composer automatically. They then create a `setup.sh`
@@ -75,7 +85,7 @@ When using `php`, `php-fpm`, or other binaries, always use the full path
 to the binary, e.g. instead of `php <command>`, 
 use `/home/foo/FrameworkBenchmarks/installs/php-5.5.17/bin/php <your command>`. 
 
-# Dependency Management Using Composer
+### Dependency Management Using Composer
 
 Many PHP apps use [Composer](https://getcomposer.org/) for dependency management, 
 which greatly simplifies downloading the framework, loading the framework, and 
@@ -90,7 +100,7 @@ The lock file is a fully-defined file generated by composer 1) reading your JSON
 dependencies 3) downloading a lot of data from Github. Without this lock file, composer takes 2-3x 
 longer to run, and it can even halt and require user input
 
-## Setting up Composer
+#### Setting up Composer
 
 Add a `composer.json` file to your framework's root folder, e.g. `php-fuel/composer.json`. 
 Ensure your `install.sh` lists composer as a dependency, and uses `composer.phar` to 
@@ -109,7 +119,7 @@ e.g. `php-fuel/vendor` that contains all dependencies. Update your PHP scripts
 to either directly reference files inside of vendor, or use the `vendor/autoload.php`
 file. 
 
-## Generating composer.lock file
+#### Generating composer.lock file
 
 Composer uses Github *a lot*, enough so that it is common for it to exceed the 
 API limit and cause infinite hangs or installation failures. To avoid this, it 
@@ -145,7 +155,7 @@ queries as they are shown. Use these steps
     # Add the lock file to this repository
     git add -f composer.lock
 
-## Updating Composer setup
+#### Updating Composer setup
 
 If you update `composer.json`, you need to regenerate the lock
 file. If you forget to do this, you will see this error message 
@@ -153,8 +163,20 @@ when running:
 
     Warning: The lock file is not up to date with the latest changes in composer.json. You may be getting outdated dependencies. Run update to update them.
 
-# Debugging PHP Frameworks
+### Debugging PHP Frameworks
 
 The first stop for HTTP 500 errors is to enable stack traces. 
 Update `config/php-fpm.conf` to include `php_flag[display_errors] = on`. 
 If you don't use php-fpm, update the `config/php.ini`
+
+## Get Help
+
+### PHP Experts
+
+_There aren't any PHP experts listed, yet. If you're an expert, 
+add yourself!_
+
+### Resources & Interesting Links
+
+_If you find some interesting links related to the PHP tests, 
+add them here._

+ 1 - 4
frameworks/PHP/hhvm/once.php.inc

@@ -5,7 +5,7 @@ class Benchmark {
 
     public function setup_db($need_utf8 = true)
     {
-        $attrs     = array(PDO::ATTR_PERSISTENT => true);
+        $attrs     = array(PDO::ATTR_PERSISTENT => false);
         // hhvm doesn't support charset=utf8 in the DSN yet
         // See https://github.com/facebook/hhvm/issues/1309
         if ($need_utf8) {
@@ -30,8 +30,6 @@ class Benchmark {
     {
         $this->setup_db();
 
-        // Create an array with the response string.
-        $arr = array();
         $id = mt_rand(1, 10000);
 
         // Define query
@@ -41,7 +39,6 @@ class Benchmark {
 
         // Store result in array.
         $arr = array('id' => $id, 'randomNumber' => $statement->fetchColumn());
-        $id = mt_rand(1, 10000);
 
         // Send the required parameters
         header('Content-Type: application/json');

+ 2 - 0
frameworks/PHP/limonade/.gitignore

@@ -0,0 +1,2 @@
+vendor
+deploy/php-fpm.pid

+ 26 - 0
frameworks/PHP/limonade/benchmark_config.json

@@ -0,0 +1,26 @@
+{
+  "framework": "limonade",
+  "tests": [{
+    "default": {
+      "setup_file": "setup",
+      "json_url": "/json",
+      "plaintext_url": "/plaintext",
+      "db_url": "/db",
+      "query_url": "/queries/",
+      "fortune_url": "/fortune",
+      "update_url": "/updates/",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Micro",
+      "database": "MySQL",
+      "framework": "Limonade",
+      "language": "PHP",
+      "orm": "Full",
+      "platform": "PHP-FPM",
+      "webserver": "nginx",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "Limonade"
+    }
+  }]
+}

+ 7 - 0
frameworks/PHP/limonade/composer.json

@@ -0,0 +1,7 @@
+{
+   "require": {
+   	"sofadesign/limonade" : "dev-master",
+   	"php-activerecord/php-activerecord" : "1.1.2"
+   }
+}
+

+ 46 - 0
frameworks/PHP/limonade/deploy/nginx.conf

@@ -0,0 +1,46 @@
+worker_processes  8;
+
+error_log stderr error;
+
+events {
+    worker_connections  1024;
+}
+
+http {
+    include       /usr/local/nginx/conf/mime.types;
+    default_type  application/octet-stream;
+    access_log off;
+    sendfile        on;
+    keepalive_timeout  65;
+
+    upstream fastcgi_backend {
+        server 127.0.0.1:9001;
+        keepalive 32;
+    }
+
+    server {
+        listen       8080;
+        server_name  localhost;
+
+        root /home/ubuntu/FrameworkBenchmarks/limonade/;
+        index  index.php;
+
+        location / {
+            try_files $uri $uri/ @rewrite;
+        }
+
+        location @rewrite {
+            rewrite ^/(.*)$ /index.php?u=$1&$args;
+        }
+
+        location ~ \.php$ {
+            try_files $uri =404;
+            fastcgi_pass   fastcgi_backend;
+            fastcgi_keep_conn on;
+            fastcgi_index  index.php;
+            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
+            include        /usr/local/nginx/conf/fastcgi_params;
+        }
+
+    }
+}

+ 105 - 0
frameworks/PHP/limonade/index.php

@@ -0,0 +1,105 @@
+<?php
+require_once "vendor/sofadesign/limonade/lib/limonade.php";
+require_once "vendor/php-activerecord/php-activerecord/ActiveRecord.php";
+
+function configure() {
+	$cfg = ActiveRecord\Config::instance();
+	$cfg->set_model_directory("models");
+	$cfg->set_connections(array(
+		"development" => "mysql://benchmarkdbuser:benchmarkdbpass@localhost/hello_world?charset=utf8"));
+
+option("bas_url", "/");
+}
+
+dispatch("/plaintext", "plaintext");
+function plaintext() {
+	header('Content-Type: text/plain; charset=utf-8');
+	return txt("Hello, World!");
+}
+
+dispatch("/json", "jsonHandler");
+function jsonHandler() {
+	header('Content-Type: application/json; charset=utf-8');
+	$arr = array("message" => "Hello, World!");
+	return json($arr);
+}
+
+dispatch("/db", "db");
+function db() {
+	$id = mt_rand(1, 10000);
+	$test = World::find($id);
+	return json($test->to_array());
+}
+
+dispatch("/queries/:queries", "queries");
+function queries() {
+	header('Content-Type: application/json; charset=utf-8');
+	$query_count = params("queries");
+	if ($query_count < 1) {
+		$query_count = 1;
+	}
+	if ($query_count > 500) {
+		$query_count = 500;
+	}
+	
+	$worlds = array();
+
+	for ($i = 0; $i < $query_count; $i++) {
+		$id = mt_rand(1, 10000);
+		$world = World::find($id);
+		$worlds[] = $world->to_array();
+	}
+
+	return json($worlds);
+
+}
+
+function update_world(&$world, $key) {
+	$world["randomnumber"] = mt_rand(1, 10000);
+}
+
+dispatch("/updates/:queries", "updates");
+function updates() {
+	header('Content-Type: application/json; charset=utf-8');
+	$query_count = params("queries");
+	if ($query_count < 1) {
+		$query_count = 1;
+	}
+	if ($query_count > 500) {
+		$query_count = 500;
+	}
+
+	$worlds = array();
+
+	for ($i = 0; $i < $query_count; $i++) {
+		$id = mt_rand(1, 10000);
+		$world = World::find($id);
+		$worlds[] = $world->to_array();
+	}
+
+	array_walk($worlds, "update_world");
+
+	return json($worlds);
+}
+
+function fortune_to_array(&$fortune, $key) {
+	$fortune->message = htmlspecialchars($fortune->message);
+	$fortune = $fortune->to_array();
+}
+
+function compare_fortunes($f1, $f2) {
+	return strcmp($f1["message"], $f2["message"]);
+}
+
+dispatch("/fortune", "fortune");
+function fortune() {
+	header('Content-Type: text/html; charset=utf-8');
+	$fortunes = Fortune::all();
+	array_walk($fortunes, "fortune_to_array");
+	$fortunes[] = array("id"=>0, "message"=> "Additional fortune added at request time.");
+	usort($fortunes, "compare_fortunes");
+	return render("fortune.php", null, array("fortunes" => $fortunes));
+}
+
+run();
+?>

+ 11 - 0
frameworks/PHP/limonade/install.sh

@@ -0,0 +1,11 @@
+#!/bin/bash
+export PHP_HOME=${IROOT}/php-5.5.17
+export COMPOSER_HOME=${IROOT}/php-composer
+export PHP_FPM=$PHP_HOME/sbin/php-fpm
+export NGINX_HOME=${IROOT}/nginx
+
+fw_depends php nginx composer
+
+${PHP_HOME}/bin/php ${COMPOSER_HOME}/composer.phar install \
+  --no-interaction --working-dir $TROOT \
+  --no-progress --optimize-autoloader 

+ 5 - 0
frameworks/PHP/limonade/models/Fortune.php

@@ -0,0 +1,5 @@
+<?php
+class Fortune extends ActiveRecord\Model {
+	static $table_name = "Fortune";
+}
+?>

+ 5 - 0
frameworks/PHP/limonade/models/World.php

@@ -0,0 +1,5 @@
+<?php
+class World extends ActiveRecord\Model {
+	static $table_name = "World";
+}
+?>

+ 12 - 0
frameworks/PHP/limonade/setup.sh

@@ -0,0 +1,12 @@
+#!/bin/bash
+export PHP_HOME=${IROOT}/php-5.5.17
+export COMPOSER_HOME=${IROOT}/php-composer
+export PHP_FPM=${PHP_HOME}/sbin/php-fpm
+export NGINX_HOME=${IROOT}/nginx
+
+sed -i 's|localhost|'"${DBHOST}"'|g' index.php
+sed -i 's|root .*/FrameworkBenchmarks/limonade|root '"${TROOT}"'|g' deploy/nginx.conf
+sed -i 's|/usr/local/nginx/|'"${IROOT}"'/nginx/|g' deploy/nginx.conf
+
+$PHP_FPM --fpm-config $FWROOT/config/php-fpm.conf -g $TROOT/deploy/php-fpm.pid
+$NGINX_HOME/sbin/nginx -c $TROOT/deploy/nginx.conf

+ 19 - 0
frameworks/PHP/limonade/views/fortune.php

@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Fortunes</title>
+</head>
+<body>
+<table>
+<tr>
+<th>id</th>
+<th>message</th>
+</tr>
+<?php
+foreach($fortunes as $f) {
+	echo ("<tr><td>" . $f["id"] . "</td><td>" . $f["message"] . "</td></tr>");
+}
+?>
+</table>
+</body>
+</html>

+ 1 - 0
frameworks/PHP/php-phalcon/app/views/layouts/mongobench.volt

@@ -0,0 +1 @@
+<!DOCTYPE html><html><head><title>Fortunes</title></head><body>{{ content() }}</body></html>

+ 30 - 43
frameworks/PHP/symfony2/README.md

@@ -1,36 +1,14 @@
 # Symfony 2 Benchmarking Test
 
-This is the Symfony 2 PHP portion of a benchmarking test suite comparing a variety of web development platforms.
+The information below contains information specific to Symfony2. 
+For further guidance, review the 
+[documentation](http://frameworkbenchmarks.readthedocs.org/en/latest/). 
+Also note the additional information provided in the [PHP README](../).
 
-This implementation is the direct result of installing the 
-[Standard Edition of Symfony 2](https://github.com/symfony/symfony-standard) using [Composer](https://getcomposer.org/), and making 
-the minimum modifications necessary to support 
-running the benchmark. Specifically, unnecessary bundles 
-have *not* been removed from the kernel to properly 
-reflect "out of the box" performance. If you're interested
-in tuned performance, see the symfony-stripped test, which
-removes and unnecessary components. 
-
-Note: `app/bootstrap.php.cache` is generated by Composer
-when you first run `composer.phar install`
-
-### JSON Encoding Test
-Uses the PHP standard [JSON encoder](http://www.php.net/manual/en/function.json-encode.php).
-
-* [JSON test controller](src/Skamander/BenchmarkBundle/Controller/BenchController.php)
-
-### Data-Store/Database Mapping Test
-Uses the Symfony 2/Doctrine 2 Entity functionality.
-
-* [DB test controller](src/Skamander/BenchmarkBundle/Controller/BenchController.php)
-* [DB test model](src/Skamander/BenchmarkBundle/Entity/World.php)
-
-### Template Test
-Uses Symfony's template engine 'Twig'
-
-* [Template test controller](src/Skamander/BenchmarkBundle/Controller/BenchController.php)
+This is the Symfony 2 PHP portion of a [benchmarking test suite](../../) comparing a variety of web development platforms.
 
 ## Infrastructure Software Versions
+
 The tests were run with:
 
 * [Symfony Version 2.2.1](http://symfony.com/)
@@ -38,25 +16,34 @@ The tests were run with:
 * [nginx 1.4.0](http://nginx.org/)
 * [MySQL 5.5.29](https://dev.mysql.com/)
 
-## Test URLs
-### JSON Encoding Test
-
-http://localhost/json
-
-### Data-Store/Database Mapping Test
+## Paths & Source for Tests
 
-http://localhost/db
+* [JSON Serialization](src/Skamander/BenchmarkBundle/Controller/BenchController.php)
+: "/json" _Note: Uses the PHP standard 
+[JSON encoder](http://www.php.net/manual/en/function.json-encode.php)._
+* [Single Database Query](src/Skamander/BenchmarkBundle/Controller/BenchController.php) ([Model](src/Skamander/BenchmarkBundle/Entity/World.php))
+: "/db" _Note: Uses the Symfony 2/Doctrine 2 Entity functionality._
+* [Multiple Database Queries](src/Skamander/BenchmarkBundle/Controller/BenchController.php) ([Model](src/Skamander/BenchmarkBundle/Entity/World.php))
+: "/db?queries=" _Note: Uses the Symfony 2/Doctrine 2 Entity functionality._
+* [Fortunes Template Test](src/Skamander/BenchmarkBundle/Controller/BenchController.php)
+: "/fortunes" _Note: Uses Symfony's template engine 'Twig'_
 
-### Variable Query Test
-    
-http://localhost/db?queries=2
+## Advice for Adding Symfony2 Tests
 
-### Templating Test
+This implementation is the direct result of installing the 
+[Standard Edition of Symfony 2](https://github.com/symfony/symfony-standard) using [Composer](https://getcomposer.org/), and making 
+the minimum modifications necessary to support 
+running the benchmark. Specifically, unnecessary bundles 
+have *not* been removed from the kernel to properly 
+reflect "out of the box" performance. If you're interested
+in tuned performance, see the symfony-stripped test, which
+removes and unnecessary components. 
 
-http://localhost/fortunes
+Note: `app/bootstrap.php.cache` is generated by Composer
+when you first run `composer.phar install`
 
 # Interesting Links
 
-[Discussion on APC vs Zend Optimizer, PHP 5.4](http://www.ricardclau.com/2013/03/apc-vs-zend-optimizer-benchmarks-with-symfony2/)
-
-[Symphony2 Performance Tuning](http://symfony.com/doc/current/book/performance.html)
+* [Discussion on APC vs Zend Optimizer, PHP 5.4](http://www.ricardclau.com/2013/03/apc-vs-zend-optimizer-benchmarks-with-symfony2/)
+* [Symfony2 Performance Tuning](http://symfony.com/doc/current/book/performance.html)
+* [Why is Symfony2 performing so bad in benchmarks and does it matter?](http://stackoverflow.com/questions/16696763/why-is-symfony2-performing-so-bad-in-benchmarks-and-does-it-matter)

+ 30 - 0
frameworks/Python/API-Hour/README.md

@@ -0,0 +1,30 @@
+# API-Hour Benchmark Test
+
+This is the API-Hour portion of a [benchmarking tests suite](../../) 
+comparing a variety of web development platforms.
+
+The information below is specific to API-Hour. For further guidance, 
+review the [documentation](http://frameworkbenchmarks.readthedocs.org/en/latest/). 
+Also note that there is additional information provided in 
+the [Python README](../).
+
+## Test Paths & Sources
+
+* [JSON Serialization](hello/endpoints/world.py): "/json"
+* [Single Database Query](hello/services/world.py): "/db"
+* [Multiple Database Queries](hello/services/world.py): "/queries?queries=#"*
+* [Fortunes](hello/services/world.py): "/fortunes"
+* [Database Updates](hello/services/world.py): "/updates?queries=#"*
+* [Plaintext](hello/endpoints/world.py): "/plaintext"
+
+*Replace # with an actual number.
+
+## Get Help
+
+### Community
+
+* [API-Hour Google Group](https://groups.google.com/forum/#!forum/api-hour)
+
+### Resources
+
+* [API-Hour Source Code](https://github.com/Eyepea/API-Hour)

+ 21 - 3
frameworks/Python/README.md

@@ -1,9 +1,26 @@
 # Python frameworks
 
-## Experts
+The information below contains information specific to Python. 
+For further guidance, review the 
+[documentation](http://frameworkbenchmarks.readthedocs.org/en/latest/).
+
+## Infrastructure Software Versions
+
+* [python2 2.7.9](https://www.python.org/)
+* [python3 3.4.2](https://www.python.org/)
+* [pypy 2.4.0](http://pypy.org/)
+* [nginx 1.4.1](http://nginx.org/)
+
+## Get Help
+
+### Python Experts
 
 * INADA Naoki (@methane) -- Expert of Python and Python's MySQL driver.
 
+### [Python Community](https://www.python.org/community/)
+
+* `#python` IRC Channel ([irc.freenode.net](http://freenode.net/))
+* `#python-dev` IRC Channel ([irc.freenode.net](http://freenode.net/))
 
 ## Python interpreters
 
@@ -27,7 +44,6 @@ PyPy is the fastest Python implementation with JIT.
 There is PyPy's Python 3 implementation (PyPy3), but it is not so tuned like PyPy2.
 So we don't use it for now.
 
-
 ## WSGI Servers
 
 ### Nginx + uWSGI
@@ -99,8 +115,10 @@ You can see Flask's files to know how to write new test.
 virtualenv is installed on Python 2 and PyPy.  Use `$IROOT/py3/bin/python3 -m venv $TROOT/py3`
 for Python 3.
 
+You can set environment variables within `install.sh` or within `setup.sh`.
+
 `bechmark_config` is json file to define test.
-See [here](https://github.com/TechEmpower/FrameworkBenchmarks#the-benchmark_configjson-file)
+See [here](http://frameworkbenchmarks.readthedocs.org/en/latest/Codebase/Framework-Files/#benchmark-config-file).
 
 `setup_py2.sh` is used to run test on Python 2.  `gunicorn_conf.py` is configuration for gunicorn.
 `setup_py2.sh` and `gunicorn_conf.py` are written as generic as possible.

+ 25 - 21
frameworks/Python/bottle/README.md

@@ -1,34 +1,38 @@
-# Bottle Benchmark Test
+# [Bottle](http://bottlepy.org/docs/dev/index.html) Benchmark Test
 
-Single file test, [app.py](app.py)
+This is the Python Bottle portion of a [benchmarking tests suite](../../) 
+comparing a variety of frameworks.
 
+The information below is specific to Bottle. For further guidance, 
+review the [documentation](http://frameworkbenchmarks.readthedocs.org/en/latest/). 
+Also note that there is additional information that's provided in 
+the [Python README](../).
 
-## Test URLs
-### JSON Encoding 
+## Test Paths and Sources
 
-http://localhost:8080/json
-
-### Single Row Random Query
+All tests are implemented in a single file ([app.py](app.py)).
 
 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
+* [JSON Serialization](app.py): "/json"
+* [Single Database Query](app.py): "/dbs"
+* [Multiple Database Queries](app.py): "/db?queries=#"*
+* [Fortunes](app.py): "/fortunes"
+* [Database Updates](app.py): "/updates?queries=#"*
+* [Plaintext](app.py): "/plaintext"
 
 Without ORM (raw):
-    http://localhost:8080/dbraw?queries=2
 
-### Fortune Test
+* [Single Database Query](app.py): "/raw-db"
+* [Multiple Database Queries](app.py): "/raw-queries?=#"*
+* [Fortune](app.py): "/raw-fortune"
+* [Database Updates](app.py): "/raw-updates?queries=#"*
 
-With ORM:
-    http://localhost:8080/fortune
+*Replace # with an actual number.
 
-Without ORM (raw):
-    http://localhost:8080/fortuneraw
+## Get Help
+
+### Community
 
+* [bottlepy Google Group](https://groups.google.com/forum/#!forum/bottlepy)
+* `#bottlepy` IRC Channel ([irc.freenode.net](https://freenode.net/))

+ 20 - 20
frameworks/Python/django/README.md

@@ -1,30 +1,30 @@
-# Django Benchmarking Test
+# [Django](https://www.djangoproject.com/) Benchmarking Test
 
-This is the Django portion of a benchmarking test suite comparing a variety of web development platforms.
+This is the Django portion of a [benchmarking tests suite](../../) 
+comparing a variety of web development platforms.
 
-### JSON Encoding Test
+The information below is specific to Django. For further guidance, 
+review the [documentation](http://frameworkbenchmarks.readthedocs.org/en/latest/). 
+Also note that there is additional information provided in 
+the [Python README](../).
 
-* [JSON test source](hello/world/views.py)
+## Test Paths & Sources
 
+* [JSON Serialization](hello/world/views.py): "/json"
+* [Single Database Query](hello/world/views.py): "/db", [World Model](hello/world/models.py)
+* [Multiple Database Queries](hello/world/views.py): "/dbs?queries=#"*, [World Model](hello/world/models.py)
+* [Fortunes](hello/world/views.py): "/fortunes", [Fortune Model](hello/world/models.py)
+* [Database Updates](hello/world/views.py): "/update?queries=#"*, [World Model](hello/world/models.py)
+* _Plaintext: N/A_
 
-### Data-Store/Database Mapping Test
+*Replace # with an actual number.
 
-* [DB test controller](hello/world/views.py)
-* [DB test model](hello/world/models.py)
+## Get Help
 
+### [Community](https://www.djangoproject.com/community/)
 
-## Resources
-* https://docs.djangoproject.com/en/dev/intro/tutorial01/
+* `#django` IRC Channel ([irc.freenode.net](https://freenode.net/))
 
-## Test URLs
-### JSON Encoding Test
+### Resources
 
-http://localhost:8080/json
-
-### Data-Store/Database Mapping Test
-
-http://localhost:8080/db
-
-### Variable Query Test
-
-http://localhost:8080/db?queries=2
+* [Writing your first Django app](https://docs.djangoproject.com/en/dev/intro/tutorial01/)

+ 27 - 9
frameworks/Python/falcon/README.md

@@ -1,25 +1,43 @@
 # Falcon Benchmark Test (ported from Flask example)
 
-Single file test, [app.py](app.py)
+This is the Falcon portion of a [benchmarking tests suite](../../) 
+comparing a variety of web development platforms.
+
+The information below is specific to Falcon. For further guidance, 
+review the [documentation](http://frameworkbenchmarks.readthedocs.org/en/latest/). 
+Also note that there is additional information provided in 
+the [Python README](../).
 
 ## Description
 
 Falcon API framework (http://falconframework.org)
 
-### Database
-
-(none at the moment)
+## Infrastructure Software
 
 ### Server
 
 * gunicorn+meinheld on CPython
 * Tornado on PyPy
 
-## Test URLs
-### JSON Encoding
+## Test Paths & Sources
+
+All of the test implementations are located within a single file ([app.py](app.py)).
+
+* [JSON Serialization](app.py): "/json"
+* _Single Database Query: N/A_
+* _Multiple Database Queries: N/A_
+* _Fortunes: N/A_
+* _Database Updates: N/A_
+* [Plaintext](app.py): "/plaintext"
+
+## Get Help
+
+### Resources
 
-http://localhost:8080/json
+* [Falcon Source Code](https://github.com/falconry/falcon)
 
-### Plaintext
+### [Community](http://falcon.readthedocs.org/en/0.2.0/community/index.html)
 
-http://localhost:8080/plaintext
+* `#falconframework` IRC Channel ([irc.freenode.net](https://freenode.net/))
+* Subscribe to email list by emailing falcon[at]librelist.com and 
+following the instructions in the reply.

+ 11 - 3
frameworks/Python/flask/README.md

@@ -1,6 +1,15 @@
-# Flask Benchmark Test
+# [Flask](http://flask.pocoo.org/) Benchmark Test
 
-Single file test, [app.py](app.py)
+The information below is specific to Flask. For further guidance, 
+review the [documentation](http://frameworkbenchmarks.readthedocs.org/en/latest/). 
+Also note that there is additional information that's provided in 
+the [Python README](../).
+
+This is the Python Flask portion of a [benchmarking tests suite](../../) 
+comparing a variety of frameworks.
+
+All test implementations are located within a single file 
+([app.py](app.py)).
 
 ## Description
 
@@ -20,7 +29,6 @@ MySQL (MySQL-python on CPython, PyMySQL on PyPy)
 * gunicorn+meinheld on CPython
 * Tornado on PyPy
 
-
 ## Test URLs
 ### JSON Encoding 
 

+ 20 - 19
frameworks/Python/pyramid/README.md

@@ -1,31 +1,32 @@
 # Pyramid benchmark test
 
+This is the Python Pyramid portion of a [benchmarking tests suite](../../) 
+comparing a variety of frameworks.
+
+The information below is specific to Pyramid. For further guidance, 
+review the [documentation](http://frameworkbenchmarks.readthedocs.org/en/latest/). 
+Also note that there is additional information that's provided in 
+the [Python README](../).
+
 [Pyramid](http://www.pylonsproject.org/) is a flexible Python 2/3 framework.
 This test uses [SQLAlchemy](http://www.sqlalchemy.org/) as its ORM, the default
 [Chameleon](http://www.pylonsproject.org/) for its templating, and
 [Gunicorn](https://github.com/benoitc/gunicorn) for the application server.
 
-## Test URLs
-
-### JSON Encoding
-
-http://localhost:6543/json
-
-### Single Row Random Query
-
-http://localhost:6543/db
-
-### Variable Row Query Test
-
-http://localhost:6543/queries?queries=10
+## Test Paths & Source
 
-### Fortune Test
+* [JSON Serialization](frameworkbenchmarks/tests.py): "/json"
+* [Single Database Query](frameworkbenchmarks/tests.py): "/db", [World Model](frameworkbenchmarks/models.py)
+* [Multiple Database Queries](frameworkbenchmarks/tests.py): "queries?queries=#"*, [World Model](frameworkbenchmarks/models.py)
+* [Fortunes](frameworkbenchmarks/tests.py): "/fortunes", [Fortune Model](frameworkbenchmarks/models.py)
+* [Database Updates](frameworkbenchmarks/tests.py): "updates?queries=#"*, [World Model](frameworkbenchmarks/models.py)
+* [Plaintext](frameworkbenchmarks/tests.py): "/plaintext"
 
-http://localhost:6543/fortunes
+*Replace # with an actual number.
 
-### Updates
-http://localhost:6543/updates?queries=10
+## Get Help
 
-### Plaintext
+### Community
 
-http://localhost:6543/plaintext
+* `#pyramid` IRC Channel ([irc.freenode.net](https://freenode.net/))
+* [Pyramid (pylons-discuss) Google Group](https://groups.google.com/forum/#!forum/pylons-discuss)

+ 29 - 11
frameworks/Python/tornado/README.md

@@ -1,16 +1,12 @@
 # Tornado Benchmarking Test
 
-This is the Tornado portion of a benchmarking test suite comparing a variety of web development platforms.
-
-### JSON Encoding Test
-
-* [JSON test source](server.py)
-
-
-### Data-Store/Database Mapping Test
-
-* [Database teste source Raw](server.py)
+This is the Tornado portion of a [benchmarking tests suite](../../) 
+comparing a variety of web development platforms.
 
+The information below is specific to Tornado. For further guidance, 
+review the [documentation](http://frameworkbenchmarks.readthedocs.org/en/latest/). 
+Also note that there is additional information that's provided in 
+the [Python README](../).
 
 ## Infrastructure Software
 
@@ -19,6 +15,28 @@ This is the Tornado portion of a benchmarking test suite comparing a variety of
 * [Mongodb](https://www.mongodb.org/) with [motor](http://motor.readthedocs.org/en/stable/)
 * [PostgreSQL](http://www.postgresql.org/) with [momoko](http://momoko.61924.nl/en/latest/)
 
+## Test Paths & Sources
+
+### Raw Database Tests
+
+* [Single Database Query](server.py): "/dbraw"
+* [Multiple Database Queries](server.py): "/queriesraw?queries=#"*
+
+### Tests
+
+* [JSON Serialization](server.py): "/json"
+* [Single Database Query](server.py): "/db"
+* [Multiple Database Queries](server.py): "/queries?queries=#"*
+* [Plaintext](server.py): "/plaintext"
+
+*Replace # with an actual number.
+
+## Get Help
+
+### Community
+
+* [python-tornado Google Group](https://groups.google.com/forum/#!forum/python-tornado)
+
+### Resources
 
-## Resources
 * http://www.tornadoweb.org/en/stable/documentation.html

+ 40 - 0
frameworks/Python/turbogears/README.md

@@ -0,0 +1,40 @@
+# TurboGears Benchmark Test 
+
+Single file test, [app.py](app.py)
+
+## Description
+
+TurboGears framework (http://turbogears.org)
+
+### Database
+
+MySQL
+
+### Server
+
+* Gunicorn + Meinheld
+
+## Test URLs
+### JSON Encoding
+
+http://localhost:8080/json
+
+### Plaintext
+
+http://localhost:8080/plaintext
+
+### DB
+
+http://localhost:8080/db
+
+### Query
+
+http://localhost:8080/queries?queries=2
+
+### Update
+
+http://localhost:8080/updates?queries=2
+
+### Fortune
+
+http://localhost:8080/fortune

+ 93 - 0
frameworks/Python/turbogears/app.py

@@ -0,0 +1,93 @@
+import os
+import sys
+import json
+from functools import partial
+from operator import attrgetter
+from random import randint
+
+import bleach
+
+from tg import expose, TGController, AppConfig
+
+from jinja2 import Environment, PackageLoader
+
+from sqlalchemy.orm import scoped_session, sessionmaker
+from sqlalchemy import create_engine
+
+from models.Fortune import Fortune
+from models.World import World
+
+DBDRIVER = 'mysql'
+DBHOSTNAME = os.environ.get('DBHOST', 'localhost')
+DATABASE_URI = '%s://benchmarkdbuser:benchmarkdbpass@%s:3306/hello_world?charset=utf8' % (DBDRIVER, DBHOSTNAME)
+
+db_engine = create_engine(DATABASE_URI)
+Session = sessionmaker(bind=db_engine)
+db_session = Session()
+
+env = Environment(loader=PackageLoader("app", "templates"))
+
+def getQueryNum(queryString):
+    try:
+        num_queries = int(queryString)
+        if num_queries < 1:
+            return 1
+        if num_queries > 500:
+            return 500
+        return num_queries
+    except ValueError:
+         return 1
+
+class RootController(TGController):
+
+    @expose(content_type="text/plain")
+    def plaintext(self):
+        return "Hello, World!"
+
+    @expose("json")
+    def json(self):
+        return {"message": "Hello, World!"}
+
+    @expose("json")
+    def db(self):
+        wid = randint(1, 10000)
+        world = db_session.query(World).get(wid).serialize()
+        return world
+
+    @expose("json")
+    def updates(self, queries=1):
+        num_queries = getQueryNum(queries)
+        worlds = []
+        rp = partial(randint, 1, 10000)
+        ids = [rp() for _ in xrange(num_queries)]
+        ids.sort()
+        for id in ids:
+            world = db_session.query(World).get(id)
+            world.randomNumber = rp()
+            worlds.append(world.serialize())
+        return json.dumps(worlds)
+
+    @expose("json")
+    def queries(self, queries=1):
+        num_queries = getQueryNum(queries)
+        rp = partial(randint, 1, 10000)
+        get = db_session.query(World).get
+        worlds = [get(rp()).serialize() for _ in xrange(num_queries)]
+        return json.dumps(worlds)
+
+
+    @expose()
+    def fortune(self):
+        fortunes = db_session.query(Fortune).all()
+        fortunes.append(Fortune(id=0, message="Additional fortune added at request time."))
+        fortunes.sort(key=attrgetter("message"))
+        for f in fortunes:
+            f.message = bleach.clean(f.message)
+            template = env.get_template("fortunes.html")
+        return template.render(fortunes=fortunes)
+
+config = AppConfig(minimal=True, root_controller=RootController())
+config.renderers.append("jinja")
+
+app = config.make_wsgi_app()
+

+ 27 - 0
frameworks/Python/turbogears/benchmark_config.json

@@ -0,0 +1,27 @@
+{
+  "framework": "turbogears",
+  "tests": [{
+    "default": {
+      "setup_file": "setup",
+      "json_url": "/json",
+      "db_url": "/db",
+      "query_url": "/queries?queries=",
+      "fortune_url": "/fortune",
+      "update_url": "/updates?queries=",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Micro",
+      "database": "MySQL",
+      "framework": "TurboGears",
+      "language": "Python",
+      "orm": "Full",
+      "platform": "Meinheld",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "TurboGears",
+      "notes": "CPython 2.7"
+    }
+  }]
+}

+ 25 - 0
frameworks/Python/turbogears/gunicorn_conf.py

@@ -0,0 +1,25 @@
+import multiprocessing
+import os
+import sys
+
+_is_pypy = hasattr(sys, 'pypy_version_info')
+_is_travis = os.environ.get('TRAVIS') == 'true'
+
+workers = multiprocessing.cpu_count() * 3
+if _is_travis:
+    workers = 2
+
+bind = "0.0.0.0:8080"
+keepalive = 120
+errorlog = '-'
+pidfile = 'gunicorn.pid'
+
+if _is_pypy:
+    worker_class = "tornado"
+else:
+    worker_class = "meinheld.gmeinheld.MeinheldWorker"
+
+    def post_fork(server, worker):
+        # Disalbe access log
+        import meinheld.server
+        meinheld.server.set_access_logger(None)

+ 19 - 0
frameworks/Python/turbogears/install.sh

@@ -0,0 +1,19 @@
+#!/bin/bash
+
+export PY2_ROOT=$IROOT/py2
+export PY2=$PY2_ROOT/bin/python
+export PY2_PIP=$PY2_ROOT/bin/pip
+
+export PY3_ROOT=$IROOT/py3
+export PY3=$PY3_ROOT/bin/python3
+export PY3_PIP=$PY3_ROOT/bin/pip3
+
+mkdir -p $IROOT/.pip_cache
+export PIP_DOWNLOAD_CACHE=$IROOT/.pip_cache
+
+fw_depends python2 python3
+
+$PY2_PIP install --install-option="--prefix=${PY2_ROOT}" -r $TROOT/requirements.txt
+
+$PY3_PIP install --install-option="--prefix=${PY3_ROOT}" -r $TROOT/requirements.txt
+

+ 17 - 0
frameworks/Python/turbogears/models/Fortune.py

@@ -0,0 +1,17 @@
+from sqlalchemy.ext.declarative import declarative_base
+from sqlalchemy import Column
+from sqlalchemy.types import String, Integer
+
+Base = declarative_base()
+
+class Fortune(Base):
+    __tablename__ = "fortune"
+
+    id = Column(Integer, primary_key = True)
+    message = Column(String)
+
+    def serialize(self):
+        return {
+            'id' : int(self.id),
+            'message' : self.message
+        }

+ 17 - 0
frameworks/Python/turbogears/models/World.py

@@ -0,0 +1,17 @@
+from sqlalchemy.ext.declarative import declarative_base
+from sqlalchemy import Column
+from sqlalchemy.types import String, Integer
+
+Base = declarative_base()
+
+class World(Base):
+    __tablename__ = "world"
+
+    id = Column(Integer, primary_key = True)
+    randomNumber = Column(Integer)
+
+    def serialize(self):
+        return {
+            'id' : int(self.id),
+            'randomNumber' : int(self.randomNumber)
+        }

+ 0 - 0
frameworks/Python/turbogears/models/__init__.py


+ 11 - 0
frameworks/Python/turbogears/requirements.txt

@@ -0,0 +1,11 @@
+tg.devtools==2.3.4
+
+bleach==1.4.1
+
+SQLAlchemy==0.9.9
+zope.sqlalchemy==0.7.6
+mysqlclient==1.3.6
+jinja2==2.7.3
+
+gunicorn==19.3.0
+meinheld==0.5.7

+ 7 - 0
frameworks/Python/turbogears/setup.sh

@@ -0,0 +1,7 @@
+#!/bin/bash
+
+export PY2_ROOT=$IROOT/py2
+export PY2=$PY2_ROOT/bin/python
+export PY2_GUNICORN=$PY2_ROOT/bin/gunicorn
+
+$PY2_GUNICORN app:app -c gunicorn_conf.py &

+ 20 - 0
frameworks/Python/turbogears/templates/fortunes.html

@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Fortunes</title>
+    </head>
+    <body>
+        <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>
+    </body>
+</html>

+ 29 - 0
frameworks/Python/uwsgi/README.md

@@ -0,0 +1,29 @@
+# UWSGI Benchmarking Test
+
+This is the UWSGI portion of a [benchmarking tests suite](../../) 
+comparing a variety of web development platforms.
+
+The information below is specific to UWSGI. For further guidance, 
+review the [documentation](http://frameworkbenchmarks.readthedocs.org/en/latest/). 
+Also note that there is additional information provided in 
+the [Python README](../).
+
+## Test Paths & Sources
+
+* [JSON Serialization](hello.py): "/json"
+* _Single Database Query: N/A_
+* _Multiple Database Queries: N/A_
+* _Fortunes: N/A_
+* _Database Updates: N/A_
+* _Plaintext: N/A_
+
+## Get Help
+
+### Community
+
+* `#uwsgi` IRC Channel ([irc.freenode.net](https://freenode.net/))
+
+### References
+
+* [UWSGI Source Code](https://github.com/unbit/uwsgi)
+* [UWSGI Docs](https://uwsgi-docs.readthedocs.org/en/latest/)

+ 20 - 10
frameworks/Python/wsgi/README.md

@@ -1,22 +1,32 @@
 # WSGI Benchmarking Test
 
-This is the WSGI portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
+This is the WSGI portion of a [benchmarking tests suite](../../) 
+comparing a variety of web development platforms.
 
-### JSON Encoding Test
-
-
-* [JSON test controller/view](hello.py)
+The information below is specific to WSGI. For further guidance, 
+review the [documentation](http://frameworkbenchmarks.readthedocs.org/en/latest/). 
+Also note that there is additional information provided in 
+the [Python README](../).
 
 ## Infrastructure Software Versions
+
 The tests were run with:
+
 * [Python 2.7.3](http://www.python.org/)
 * [Gunicorn 0.17.2](http://gunicorn.org/)
 
+## Test Paths & Sources
+
+* [JSON Serialization](hello.py): "/json"
+* Single Database Query: N/A_
+* Multiple Database Queries: N/A_
+* Fortunes: N/A_
+* Database Updates: N/A_
+* [Plaintext](hello.py): "/plaintext"
 
-## References
-http://docs.gunicorn.org/en/latest/run.html
+## Get Help
 
-## Test URLs
-### JSON Encoding Test
+### References
 
-http://localhost:8080/json
+* [WSGI Docs](http://wsgi.readthedocs.org/en/latest/)
+* [Gunicorn Docs](http://docs.gunicorn.org/en/latest/run.html)

+ 52 - 7
frameworks/Ruby/README.md

@@ -1,24 +1,69 @@
-# Using RVM to setup your environment
+# Ruby Frameworks
+
+The information below contains information specific to Ruby. 
+For further guidance, review the 
+[documentation](http://frameworkbenchmarks.readthedocs.org/en/latest/).
+
+## Infrastructure Software Versions
+
+* [RVM 2.2.1](https://rvm.io/) (Unless tests are run in Travis-CI)
+
+## Adding a New Ruby Framework
+
+### Installation
 
 TFB uses rvm wherever possible to help ruby-based or
 jruby-based frameworks setup their environment. 
-In your framework's `install.sh`, put this prior to other statements: 
+
+When verifying the tests in Travis-CI we rely on Travis-CI's 
+RVM installation (and $HOME isn't /home/travis while running 
+Travis-CI), so we have certain specific caveats to keep 
+Travis-CI happy.
+
+#### Install RVM
+
+Most install.sh files will at least have this:
 
     #!/bin/bash
-    
+
+    fw_depends rvm # This installs RVM
+
+    if [ "$TRAVIS" = "true" ]
+    then
+      rvmsudo rvm install ruby-2.0.0-p0
+    else
+      rvm install ruby-2.0.0-p0
+    fi
+
+### Set Up with RVM
+
+At the top of your framework's `setup.sh`, put this (if 
+you're using RVM): 
+
+    #!/bin/bash
+
     # Assume single-user installation
-    source $HOME/.rvm/scripts/rvm
+    if [ "$TRAVIS" = "true" ]
+    then
+      source /home/travis/.rvm/scripts/rvm
+    else
+      source $HOME/.rvm/scripts/rvm
+    fi
 
 Because TFB uses Python's `subprocess` module, which runs 
 all shell processes in a non-login mode, you must source the 
-`rvm` script before using `rvm` anywhere. Placing the `source`
-call in your `install.sh` before other commands ensures that it 
-will be called before installation and before running `setup.py`
+`rvm` script before using `rvm` anywhere. 
 
 For compatibility with how the framework rounds are executed, 
 you must use a single-user installation if you wish to run 
 ruby-based TFB tests.
 
+## Get Help
+
+### Ruby Experts
 
+_No experts listed, yet. If you're an expert, add yourself!_
 
+### [Ruby Community](https://www.ruby-lang.org/en/community/)
 
+* `#ruby-lang` on IRC ([irc.freenode.net](https://freenode.net/))

+ 32 - 2
frameworks/Ruby/grape/README.md

@@ -1,15 +1,45 @@
-# Ruby Grape Benchmarking Test
+# Grape Micro-Framework
 
-This is the Ruby Grape portion of a [benchmarking test suite](../) comparing a variety of web servers along with JRuby/MRI.
+The information below contains information specific to Grape. 
+For further guidance, review the 
+[documentation](http://frameworkbenchmarks.readthedocs.org/en/latest/). 
+Also note the additional information provided in the [Ruby README](../).
+
+This is the Ruby Grape portion of a [benchmarking test suite](../../) 
+comparing a variety of web servers along with JRuby/MRI.
 
 ## Infrastructure Software Versions
 The tests were run with:
 
 * [Ruby 2.0.0-p0](http://www.ruby-lang.org/)
 * [JRuby 1.7.8](http://jruby.org/)
+* [Rubinius 2.2.10](http://rubini.us/)
 * [Grape 0.8.0](http://intridea.github.io/grape/)
 * [Rack 1.5.2](http://rack.github.com/)
 * [Unicorn 4.8.3](http://unicorn.bogomips.org/)
 * [TorqBox 0.1.7](http://torquebox.org/torqbox/)
 * [Puma 2.9.0](http://puma.io/)
 * [Thin 1.6.2](http://code.macournoyer.com/thin/)
+
+## Paths & Source for Tests
+
+* [JSON Serialization](config.ru): "/json"
+* [Single Database Query](config.ru): "/db"
+* [Multiple Database Queries](config.ru): "/query?queries={#}"
+* _Fortunes: N/A_
+* [Database Updates](config.ru): "/updates?queries={#}"
+* [Plaintext](config.ru): "/plaintext"
+
+## Get Help
+
+### Experts
+
+_No experts listed, yet. If you're an expert, add yourself!_
+
+### Community
+
+* [Grape Google Group](https://groups.google.com/forum/?fromgroups#!forum/ruby-grape)
+
+### Resources
+
+* [Grape Micro-framework Source Code](https://github.com/intridea/grape)

+ 23 - 8
frameworks/Ruby/ngx_mruby/README.md

@@ -1,21 +1,36 @@
 # [nginx + mruby](https://github.com/matsumoto-r/ngx_mruby) Benchmark Test
 
+The information below contains information specific to nginx + mruby. 
+For further guidance, review the 
+[documentation](http://frameworkbenchmarks.readthedocs.org/en/latest/). 
+Also note the additional information provided in the [Ruby README](../).
+
+This is the nginx + mruby portion of a [benchmarking test suite](../../) 
+comparing a variety of web platforms.
+
+---
+
 The nginx app is distributes across a few files. most of it is in [nginx.conf](nginx.conf)
 The nginx conf is inside [nginx.conf](nginx.conf)
 Requires a nginx compiled with ngx_mruby module. It has been called nginx_mruby for lack of a better name
 
+## Infrastructure Software Versions
 
-## Test URLs
-### JSON Encoding
+The tests were run with:
 
-http://localhost:8080/json
+* [Ruby 2.0.0-p0](http://www.ruby-lang.org/)
 
-### Single Row Random Query
+## Paths & Source for Tests
 
-http://localhost:8080/db
+* [JSON Serialization](nginx.conf): "/json"
+* [Single Database Query](db.rb): "/db"
+* [Multiple Database Query](queries.rb): "/queries?queries={#}"
+* _Fortunes: N/A_
+* _Database Updates: N/A_
+* [Plaintext](nginx.conf): "/plaintext"
 
-### Variable Row Query Test
+## Get Help
 
-http://localhost:8080/db?queries=2
+### Experts
 
-Based upon the [openresty](../../Lua/openresty/) implementation.
+_No experts listed, yet. If you're an expert, add yourself!_

+ 46 - 0
frameworks/Ruby/padrino/README.md

@@ -0,0 +1,46 @@
+# Padrino Framework
+
+The information below contains information specific to Padrino. 
+For further guidance, review the 
+[documentation](http://frameworkbenchmarks.readthedocs.org/en/latest/). 
+Also note the additional information provided in the [Ruby README](../).
+
+This is the Ruby Padrino portion of a [benchmarking test suite](../../) 
+comparing a variety of web servers.
+
+## Infrastructure Software Versions
+The tests were run with:
+
+* [Ruby 2.0.0-p0](http://www.ruby-lang.org/)
+* [JRuby 1.7.8](http://jruby.org/)
+* [Rubinius 2.2.10](http://rubini.us/)
+* [Padrino 0.12.3](http://www.padrinorb.com/)
+* [Rack 1.5.2](http://rack.github.com/)
+* [Unicorn 4.8.3](http://unicorn.bogomips.org/)
+* [TorqBox 0.1.7](http://torquebox.org/torqbox/)
+* [Puma 2.9.0](http://puma.io/)
+* [Thin 1.6.2](http://code.macournoyer.com/thin/)
+
+## Paths & Source for Tests
+
+* [JSON Serialization](app/controllers.rb): "/json"
+* [Single Database Query](app/controllers.rb): "/db", [World Model](models/world.rb)
+* [Multiple Database Queries](app/controllers.rb): "/query?queries={#}", [World Model](models/world.rb)
+* [Fortunes](app/controllers.rb): "/fortunes", [Fortunes Model](models/fortune.rb)
+* [Database Updates](app/controllers.rb): "/updates?queries={#}", [World Model](models/world.rb)
+* [Plaintext](app/controllers.rb): "/plaintext"
+
+## Get Help
+
+### Experts
+
+_No experts listed, yet. If you're an expert, add yourself!_
+
+### [Community](http://www.padrinorb.com/pages/contribute)
+
+* [Padrino Google Group](https://groups.google.com/forum/#!forum/padrino)
+* `#padrino` IRC Channel([irc.freenode.net](http://freenode.net/))
+
+### Resources
+
+* [Padrino framework Source Code](https://github.com/padrino/padrino-framework)

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