Added new module 'akka-docs' as the basis for the new Sphinx/reST based docs. Also added the first draft of the new Getting Started Guide
49
akka-docs/Makefile
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
BUILDDIR = _build
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
.PHONY: help clean html singlehtml latex pdf
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " singlehtml to make a single large HTML file"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " pdf to make LaTeX files and run them through pdflatex"
|
||||
|
||||
clean:
|
||||
-rm -rf $(BUILDDIR)/*
|
||||
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
singlehtml:
|
||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||
"(use \`make latexpdf' here to do that automatically)."
|
||||
|
||||
pdf:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through pdflatex..."
|
||||
make -C $(BUILDDIR)/latex all-pdf
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
BIN
akka-docs/_static/akka.png
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
BIN
akka-docs/_static/logo.png
Normal file
|
After Width: | Height: | Size: 7.9 KiB |
65
akka-docs/conf.py
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Akka documentation build configuration file.
|
||||
#
|
||||
|
||||
import sys, os
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
extensions = ['sphinx.ext.todo']
|
||||
|
||||
templates_path = ['_templates']
|
||||
source_suffix = '.rst'
|
||||
master_doc = 'index'
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
project = u'Akka'
|
||||
copyright = u'2009-2011, Scalable Solutions AB'
|
||||
version = '1.0'
|
||||
release = '1.0'
|
||||
|
||||
pygments_style = 'akka'
|
||||
highlight_language = 'scala'
|
||||
|
||||
# -- Options for HTML output ---------------------------------------------------
|
||||
|
||||
html_theme = 'akka'
|
||||
html_theme_options = {
|
||||
'full_logo': 'true'
|
||||
}
|
||||
html_theme_path = ['themes']
|
||||
|
||||
html_title = 'Akka Documentation'
|
||||
html_logo = '_static/logo.png'
|
||||
#html_favicon = None
|
||||
|
||||
html_static_path = ['_static']
|
||||
|
||||
html_last_updated_fmt = '%b %d, %Y'
|
||||
#html_sidebars = {}
|
||||
#html_additional_pages = {}
|
||||
html_domain_indices = False
|
||||
html_use_index = False
|
||||
html_show_sourcelink = False
|
||||
html_show_sphinx = False
|
||||
html_show_copyright = True
|
||||
htmlhelp_basename = 'Akkadoc'
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
|
||||
latex_paper_size = 'a4'
|
||||
latex_font_size = '10pt'
|
||||
|
||||
latex_documents = [
|
||||
('index', 'Akka.tex', u' Akka Documentation',
|
||||
u'Scalable Solutions AB', 'manual'),
|
||||
]
|
||||
|
||||
latex_elements = {
|
||||
'classoptions': ',oneside,openany',
|
||||
'babel': '\\usepackage[english]{babel}',
|
||||
'preamble': '\\definecolor{VerbatimColor}{rgb}{0.935,0.935,0.935}'
|
||||
}
|
||||
|
||||
# latex_logo = '_static/akka.png'
|
||||
14
akka-docs/index.rst
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
Contents
|
||||
========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
manual/getting-started-first
|
||||
|
||||
|
||||
Links
|
||||
=====
|
||||
|
||||
* `Akka Documentation <http://doc.akka.io>`_
|
||||
* `Support <http://scalablesolutions.se>`_
|
||||
347
akka-docs/manual/getting-started-first.rst
Executable file
|
|
@ -0,0 +1,347 @@
|
|||
Getting Started Tutorial: First Chapter
|
||||
=======================================
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Welcome to the first tutorial on how to get started with Akka and Scala. We assume that you already know what Akka and Scala is and will now focus on the steps necessary to start your first project.
|
||||
|
||||
There are two variations of this first tutorial:
|
||||
|
||||
- creating a standalone project and run it from the command line
|
||||
- creating a SBT (Simple Build Tool) project and running it from within SBT
|
||||
|
||||
Since they are so similar we will present them both in this tutorial. The sample application that we will create is using actors to calculate the value of Pi. Is using an algorithm that is easily parallelizable and therefore suits the actor model very well, but is generic enough to suit as a starting point for all kinds of Master/Worker style problems.
|
||||
|
||||
http://www.earldouglas.com/system/files/pi-series.png
|
||||
|
||||
In this particular algorithm the master splits the series into chunks which are sent out to each worker actor to be processed, when each worker has processed its chunk it sends a result back to the master which aggregates to total result.
|
||||
|
||||
Downloading and installing Akka
|
||||
-------------------------------
|
||||
|
||||
The first thing we need to do is to download Akka. Let's get the 1.1 distribution from `http://akka.io/downloads <http://akka.io/downloads/>`_. Once you have downloaded the distribution unzip it in the folder you would like to have Akka installed in, in my case I choose to install it in ``/Users/jboner/tools/``, simply by unzipping it to this directory.
|
||||
|
||||
You need to do one more thing in order to install Akka properly and that is to set the ``AKKA_HOME`` environment variable to the root of the distribution. In my case I'm opening up a shell and navigating down to the distribution and setting the ``AKKA_HOME`` variable::
|
||||
|
||||
$ cd /Users/jboner/tools/akka-1.1
|
||||
$ export AKKA_HOME=`pwd`
|
||||
$ echo $AKKA_HOME
|
||||
/Users/jboner/tools/akka-1.1
|
||||
|
||||
If we now take a look at what we have in this distribution, looks like this::
|
||||
|
||||
$ ls -l
|
||||
total 16944
|
||||
drwxr-xr-x 7 jboner staff 238 Apr 6 11:15 .
|
||||
drwxr-xr-x 28 jboner staff 952 Apr 6 11:16 ..
|
||||
drwxr-xr-x 17 jboner staff 578 Apr 6 11:16 deploy
|
||||
drwxr-xr-x 26 jboner staff 884 Apr 6 11:16 dist
|
||||
drwxr-xr-x 3 jboner staff 102 Apr 6 11:15 lib_managed
|
||||
-rwxr-xr-x 1 jboner staff 8674105 Apr 6 11:15 scala-library.jar
|
||||
drwxr-xr-x 4 jboner staff 136 Apr 6 11:16 scripts
|
||||
|
||||
- In the ``dist`` directory we have all the Akka JARs, including sources and docs.
|
||||
- In the ``lib_managed/compile`` directory we have all the Akka's dependency JARs.
|
||||
- In the ``deploy`` directory we have all the sample JARs.
|
||||
- In the ``scripts`` directory we have scripts for running Akka.
|
||||
- Finallly the ``scala-library.jar`` is the JAR for the latest Scala distribution that Akka depends on.
|
||||
|
||||
Creating the messages
|
||||
---------------------
|
||||
|
||||
First we need to create the messages is that we want to have flowing in the system. Let's create three different messages:
|
||||
|
||||
- ``Calculate`` -- starts the calculation
|
||||
- ``Work`` -- contains the work assignment
|
||||
- ``Result`` -- contains the result from the worker's calculation
|
||||
|
||||
Messages sent to actors should always be immutable to avoid sharing mutable state. In scala we have 'case classes' which make excellent messages. So let's start by creating three messages as case classes. We also create a common base trait for our messages (that we define as being ``sealed`` in order to prevent creating messages outside our control)::
|
||||
|
||||
sealed trait PiMessage
|
||||
|
||||
case object Calculate extends PiMessage
|
||||
|
||||
case class Work(arg: Int, nrOfElements: Int) extends PiMessage
|
||||
|
||||
case class Result(value: Double) extends PiMessage
|
||||
|
||||
Creating the worker
|
||||
-------------------
|
||||
|
||||
Now we can create the worker actor. This is done by mixing in the ``Actor`` trait and defining the ``receive`` method. The ``receive`` method defines our message handler. We expect it to be able to handle the ``Work`` message so we need to add a handler for this message::
|
||||
|
||||
class Worker extends Actor {
|
||||
def receive = {
|
||||
case Work(arg, nrOfElements) =>
|
||||
self reply Result(calculatePiFor(arg, nrOfElements)) // perform the work
|
||||
}
|
||||
}
|
||||
|
||||
As you can see we have now created an ``Actor`` with a ``receive`` method that as a handler for the ``Work`` message. In this handler we invoke the ``calculatePiFor(..)`` method, wraps the result in a ``Result`` message and sends it back to the original sender using ``self.reply``. In Akka the sender reference is implicitly passed along with the message so that the receiver can always reply or store away the sender reference use.
|
||||
|
||||
The only thing missing in our ``Worker`` actor is the implementation on the ````calculatePiFor(..)`` method. There are many ways we can implement this algorithm in Scala, now let's try to balance functional programming with efficiency and use a tail recursive function::
|
||||
|
||||
def calculatePiFor(arg: Int, nrOfElements: Int): Double = {
|
||||
val end = (arg + 1) * nrOfElements - 1
|
||||
|
||||
@tailrec def doCalculatePiFor(cursor: Int, acc: Double): Double = {
|
||||
if (end == cursor) acc
|
||||
else doCalculatePiFor(cursor + 1, acc + (4 * math.pow(-1, cursor) / (2 * cursor + 1)))
|
||||
}
|
||||
|
||||
doCalculatePiFor(arg * nrOfElements, 0.0D)
|
||||
}
|
||||
|
||||
Here we use the classic trick with a local nested method to make sure that the compiler can perform a tail call optimization. We can ensure that the compiler will be able to do that by annotate tail recursive function with ``@tailrec``, with this annotation the compiler will emit an error if it can optimize it. With this implementation the calculation is really fast.
|
||||
|
||||
Creating the master
|
||||
-------------------
|
||||
|
||||
The master actor is a little bit more involved. In its constructor we need to create the workers (the ``Worker`` actors) and start them. We will also wrap them in a load-balancing router to make it easier to spread out the work evenly between the workers. Let's do that first::
|
||||
|
||||
// create the workers
|
||||
val workers = Vector.fill(nrOfWorkers)(actorOf[Worker].start)
|
||||
|
||||
// wrap them with a load-balancing router
|
||||
val router = Routing.loadBalancerActor(CyclicIterator(workers)).start
|
||||
|
||||
As you can see we are using the ``actorOf`` factory method to create actors, this method returns as an ``ActorRef`` which is a reference to our newly created actor. This method is available in the ``Actor`` object but is usually imported::
|
||||
|
||||
import akka.actor.Actor._
|
||||
|
||||
Now we have a routes are representing all our workers in a single abstraction. If you paid attention to the code above to see that we were using the ``nrOfWorkers`` variable. This variable and others we have to pass to the ``Master`` actor in its constructor. So now let's create the master actor. We had to pass in three integer variables needed:
|
||||
|
||||
- ``nrOfWorkers`` -- defining how many workers we should start up
|
||||
- ``nrOfMessages`` -- defining how many numebr chunks should send out to the workers
|
||||
- ``nrOfElements`` -- defining how big the number chunks sent to each worker should be
|
||||
|
||||
Let's not write the master actor::
|
||||
|
||||
class Master(nrOfWorkers: Int, nrOfMessages: Int, nrOfElements: Int, latch: CountDownLatch)
|
||||
extends Actor {
|
||||
|
||||
var pi: Double = _
|
||||
var nrOfResults: Int = _
|
||||
var start: Long = _
|
||||
|
||||
// create the workers
|
||||
val workers = Vector.fill(nrOfWorkers)(actorOf[Worker].start)
|
||||
|
||||
// wrap them with a load-balancing router
|
||||
val router = Routing.loadBalancerActor(CyclicIterator(workers)).start
|
||||
|
||||
def receive = { ... }
|
||||
|
||||
override def preStart = start = now
|
||||
|
||||
override def postStop = {
|
||||
// tell the world that the calculation is complete
|
||||
println(
|
||||
"\n\tPi estimate: \t\t%s\n\tCalculation time: \t%s millis"
|
||||
.format(pi, (now - start)))
|
||||
latch.countDown
|
||||
}
|
||||
}
|
||||
|
||||
Couple of things are worth explaining further.
|
||||
|
||||
First, we are passing in a ``java.util.concurrent.CountDownLatch`` to the ``Master`` actor. This latch is only used for plumbing, to have a simple way letting the outside world knowing when the master can deliver the result and shut down. In more idiomatic Akka code, as we will see in part two of this tutorial series, we would not use a latch.
|
||||
|
||||
Second, we are adding a couple of lifecycle callback methods; ``preStart`` and ``postStop``. In the ``preStart`` callback we are recording the time when the actor is started and in the ``postStop`` callback we are printing out the result (the approximation of Pi) and the time it took to calculate it. In this call but we also invoke ``latch.countDown`` to tell the outside world that we are done.
|
||||
|
||||
But we are not done yet. We are missing the message handler for the ``Master`` actor. This message handler needs to be able to react to two different messages:
|
||||
|
||||
- ``Calculate`` -- which should start the calculation
|
||||
- ``Result`` -- which should aggregate the different results
|
||||
|
||||
The ``Calculate`` handler is sending out work to all the ``Worker`` actors and after doing that also sends a ``Broadcast(PoisonPill)`` message to the router, this will make the route or send out the ``PoisonPill`` message to all the actors in this representing (in our case all the ``Worker`` actors). The ``PoisonPill`` is a special kind of message that tells the receiver to shut himself down using the normal shutdown; ``self.stop``. Then we also send a ``PoisonPill`` to the router itself (since it's also an actor that we want to shut down).
|
||||
|
||||
The ``Result`` handler is simpler, here we just get the value from the ``Result`` message and aggregate it to our ``pi`` member variable. We also keep track of how many results we have received back and if it matches the number of tasks sent out the ``Master`` actor considers itself done and shuts himself down.
|
||||
|
||||
Now, let's capture this in code::
|
||||
|
||||
// message handler
|
||||
def receive = {
|
||||
case Calculate =>
|
||||
// schedule work
|
||||
for (arg <- 0 until nrOfMessages) router ! Work(arg, nrOfElements)
|
||||
|
||||
// send a PoisonPill to all workers telling them to shut down themselves
|
||||
router ! Broadcast(PoisonPill)
|
||||
|
||||
// send a PoisonPill to the router, telling him to shut himself down
|
||||
router ! PoisonPill
|
||||
|
||||
case Result(value) =>
|
||||
// handle result from the worker
|
||||
pi += value
|
||||
nrOfResults += 1
|
||||
if (nrOfResults == nrOfMessages) self.stop
|
||||
}
|
||||
|
||||
Bootstrap the calculation
|
||||
-------------------------
|
||||
|
||||
Now the only thing that is left to implement his the runner that should bootstrap and run his calculation for us. We do that by creating an object that we call ``Pi``, here we can extend the ``App`` trait in Scala which means that we will be able to run this as an application directly from the command line. The ``Pi`` object is a perfect container module for our actors and messages, so let's put them all there. We also create a method ``calculate`` in which we start up the ``Master`` actor and waits for it to finish::
|
||||
|
||||
object Pi extends App {
|
||||
|
||||
calculate(nrOfWorkers = 4, nrOfElements = 10000, nrOfMessages = 10000)
|
||||
|
||||
... // actors and messages
|
||||
|
||||
def calculate(nrOfWorkers: Int, nrOfElements: Int, nrOfMessages: Int) {
|
||||
|
||||
// this latch is only plumbing to know when the calculation is completed
|
||||
val latch = new CountDownLatch(1)
|
||||
|
||||
// create the master
|
||||
val master = actorOf(new Master(nrOfWorkers, nrOfMessages, nrOfElements, latch)).start
|
||||
|
||||
// start the calculation
|
||||
master ! Calculate
|
||||
|
||||
// wait for master to shut down
|
||||
latch.await
|
||||
}
|
||||
}
|
||||
|
||||
That's it. Now we are done.
|
||||
|
||||
But before we package it up and run it, let's take a look at the full code now, with package declaration, imports and all of::
|
||||
|
||||
package akka.tutorial.scala.first
|
||||
|
||||
import akka.actor.{Actor, ActorRef, PoisonPill}
|
||||
import Actor._
|
||||
import akka.routing.{Routing, CyclicIterator}
|
||||
import Routing._
|
||||
import akka.dispatch.Dispatchers
|
||||
|
||||
import System.{currentTimeMillis => now}
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
import scala.annotation.tailrec
|
||||
|
||||
object Pi extends App {
|
||||
|
||||
calculate(nrOfWorkers = 4, nrOfElements = 10000, nrOfMessages = 10000)
|
||||
|
||||
// ====================
|
||||
// ===== Messages =====
|
||||
// ====================
|
||||
sealed trait PiMessage
|
||||
case object Calculate extends PiMessage
|
||||
case class Work(arg: Int, nrOfElements: Int) extends PiMessage
|
||||
case class Result(value: Double) extends PiMessage
|
||||
|
||||
// ==================
|
||||
// ===== Worker =====
|
||||
// ==================
|
||||
class Worker extends Actor {
|
||||
|
||||
// define the work
|
||||
def calculatePiFor(arg: Int, nrOfElements: Int): Double = {
|
||||
val end = (arg + 1) * nrOfElements - 1
|
||||
@tailrec def doCalculatePiFor(cursor: Int, acc: Double): Double = {
|
||||
if (end == cursor) acc
|
||||
else doCalculatePiFor(cursor + 1, acc + (4 * math.pow(-1, cursor) / (2 * cursor + 1)))
|
||||
}
|
||||
doCalculatePiFor(arg * nrOfElements, 0.0D)
|
||||
}
|
||||
|
||||
def receive = {
|
||||
case Work(arg, nrOfElements) =>
|
||||
self reply Result(calculatePiFor(arg, nrOfElements)) // perform the work
|
||||
}
|
||||
}
|
||||
|
||||
// ==================
|
||||
// ===== Master =====
|
||||
// ==================
|
||||
class Master(nrOfWorkers: Int, nrOfMessages: Int, nrOfElements: Int, latch: CountDownLatch)
|
||||
extends Actor {
|
||||
|
||||
var pi: Double = _
|
||||
var nrOfResults: Int = _
|
||||
var start: Long = _
|
||||
|
||||
// create the workers
|
||||
val workers = Vector.fill(nrOfWorkers)(actorOf[Worker].start)
|
||||
|
||||
// wrap them with a load-balancing router
|
||||
val router = Routing.loadBalancerActor(CyclicIterator(workers)).start
|
||||
|
||||
// message handler
|
||||
def receive = {
|
||||
case Calculate =>
|
||||
// schedule work
|
||||
for (arg <- 0 until nrOfMessages) router ! Work(arg, nrOfElements)
|
||||
|
||||
// send a PoisonPill to all workers telling them to shut down themselves
|
||||
router ! Broadcast(PoisonPill)
|
||||
|
||||
// send a PoisonPill to the router, telling him to shut himself down
|
||||
router ! PoisonPill
|
||||
|
||||
case Result(value) =>
|
||||
// handle result from the worker
|
||||
pi += value
|
||||
nrOfResults += 1
|
||||
if (nrOfResults == nrOfMessages) self.stop
|
||||
}
|
||||
|
||||
override def preStart = start = now
|
||||
|
||||
override def postStop = {
|
||||
// tell the world that the calculation is complete
|
||||
println(
|
||||
"\n\tPi estimate: \t\t%s\n\tCalculation time: \t%s millis"
|
||||
.format(pi, (now - start)))
|
||||
latch.countDown
|
||||
}
|
||||
}
|
||||
|
||||
// ==================
|
||||
// ===== Run it =====
|
||||
// ==================
|
||||
def calculate(nrOfWorkers: Int, nrOfElements: Int, nrOfMessages: Int) {
|
||||
|
||||
// this latch is only plumbing to know when the calculation is completed
|
||||
val latch = new CountDownLatch(1)
|
||||
|
||||
// create the master
|
||||
val master = actorOf(new Master(nrOfWorkers, nrOfMessages, nrOfElements, latch)).start
|
||||
|
||||
// start the calculation
|
||||
master ! Calculate
|
||||
|
||||
// wait for master to shut down
|
||||
latch.await
|
||||
}
|
||||
}
|
||||
|
||||
Run it as a command line application
|
||||
------------------------------------
|
||||
|
||||
In order to run it as a stand-alone application you first need to copy the full code snippet above and put it into a file ``Pi.scala`` which you save in, for example, the ``$AKKA_HOME/tutorial`` directory (create the ``tutorial`` folder if it doesn't exist)::
|
||||
|
||||
$ cd akka-1.1
|
||||
$ export AKKA_HOME=`pwd`
|
||||
$ scalac -cp dist/akka-actor-1.1.jar tutorial/Pi.scala
|
||||
$ java -cp dist/akka-actor-1.1.jar:scala-library.jar:tutorial akka.tutorial.scala.first.Pi
|
||||
$ ...
|
||||
|
||||
Run it inside SBT
|
||||
-----------------
|
||||
|
||||
Run::
|
||||
|
||||
$ sbt
|
||||
> update
|
||||
> console
|
||||
> akka.tutorial.scala.first.Pi.calculate(nrOfWorkers = 4, nrOfElements = 10000, nrOfMessages = 10000)
|
||||
> ...
|
||||
> :quit
|
||||
|
||||
BIN
akka-docs/manual/more.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
64
akka-docs/themes/akka/layout.html
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
{#
|
||||
akka/layout.html
|
||||
~~~~~~~~~~~~~~~~~
|
||||
#}
|
||||
|
||||
{% extends "basic/layout.html" %}
|
||||
{% set script_files = script_files + ['_static/theme_extras.js'] %}
|
||||
{% set css_files = css_files + ['_static/print.css'] %}
|
||||
|
||||
{# do not display relbars #}
|
||||
{% block relbar1 %}{% endblock %}
|
||||
{% block relbar2 %}{% endblock %}
|
||||
|
||||
{% macro nav() %}
|
||||
<p>
|
||||
{%- block akkarel1 %}
|
||||
{%- endblock %}
|
||||
{%- if prev %}
|
||||
«  <a href="{{ prev.link|e }}">{{ prev.title }}</a>
|
||||
  ::  
|
||||
{%- endif %}
|
||||
<a class="uplink" href="{{ pathto(master_doc) }}">{{ _('Contents') }}</a>
|
||||
{%- if next %}
|
||||
  ::  
|
||||
<a href="{{ next.link|e }}">{{ next.title }}</a>  »
|
||||
{%- endif %}
|
||||
{%- block akkarel2 %}
|
||||
{%- endblock %}
|
||||
</p>
|
||||
{% endmacro %}
|
||||
|
||||
{% block content %}
|
||||
<div class="header">
|
||||
{%- block akkaheader %}
|
||||
{%- if theme_full_logo != "false" %}
|
||||
<a href="{{ pathto('index') }}">
|
||||
<img class="logo" src="{{ pathto('_static/' + logo, 1) }}" alt="Logo"/>
|
||||
</a>
|
||||
{%- else %}
|
||||
{%- if logo -%}
|
||||
<img class="rightlogo" src="{{ pathto('_static/' + logo, 1) }}" alt="Logo"/>
|
||||
{%- endif -%}
|
||||
<h1 class="heading"><a href="{{ pathto('index') }}">
|
||||
<span>{{ shorttitle|e }}</span></a></h1>
|
||||
<h2 class="heading"><span>{{ title|striptags|e }}</span></h2>
|
||||
{%- endif %}
|
||||
{%- endblock %}
|
||||
</div>
|
||||
<div class="topnav">
|
||||
{{ nav() }}
|
||||
</div>
|
||||
<div class="content">
|
||||
{#{%- if display_toc %}
|
||||
<div id="toc">
|
||||
<h3>Table Of Contents</h3>
|
||||
{{ toc }}
|
||||
</div>
|
||||
{%- endif %}#}
|
||||
{% block body %}{% endblock %}
|
||||
</div>
|
||||
<div class="bottomnav">
|
||||
{{ nav() }}
|
||||
</div>
|
||||
{% endblock %}
|
||||
58
akka-docs/themes/akka/pygments/akka.py
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
pygments.styles.akka
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Akka style for Scala highlighting.
|
||||
"""
|
||||
|
||||
from pygments.style import Style
|
||||
from pygments.token import Keyword, Name, Comment, String, Error, \
|
||||
Number, Operator, Generic, Whitespace
|
||||
|
||||
|
||||
class AkkaStyle(Style):
|
||||
"""
|
||||
Akka style for Scala highlighting.
|
||||
"""
|
||||
|
||||
background_color = "#f0f0f0"
|
||||
default_style = ""
|
||||
|
||||
styles = {
|
||||
Whitespace: "#f0f0f0",
|
||||
Comment: "#777766",
|
||||
Comment.Preproc: "",
|
||||
Comment.Special: "",
|
||||
|
||||
Keyword: "#000080",
|
||||
Keyword.Pseudo: "",
|
||||
Keyword.Type: "",
|
||||
|
||||
Operator: "#000000",
|
||||
Operator.Word: "",
|
||||
|
||||
Name.Builtin: "#000000",
|
||||
Name.Function: "#000000",
|
||||
Name.Class: "#000000",
|
||||
Name.Namespace: "#000000",
|
||||
Name.Exception: "#000000",
|
||||
Name.Variable: "#000000",
|
||||
Name.Constant: "bold #000000",
|
||||
Name.Label: "#000000",
|
||||
Name.Entity: "#000000",
|
||||
Name.Attribute: "#000000",
|
||||
Name.Tag: "#000000",
|
||||
Name.Decorator: "#000000",
|
||||
|
||||
String: "#008000",
|
||||
String.Doc: "",
|
||||
String.Interpol: "",
|
||||
String.Escape: "",
|
||||
String.Regex: "",
|
||||
String.Symbol: "",
|
||||
String.Other: "",
|
||||
Number: "#008000",
|
||||
|
||||
Error: "border:#FF0000"
|
||||
}
|
||||
352
akka-docs/themes/akka/static/akka.css_t
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
/*
|
||||
* akka.css_t
|
||||
*/
|
||||
|
||||
@import url("basic.css");
|
||||
|
||||
html {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
background: #FFF url(bg-page.png) top left repeat-x;
|
||||
}
|
||||
|
||||
body {
|
||||
line-height: 1.5;
|
||||
margin: auto;
|
||||
padding: 0px;
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
min-width: 59em;
|
||||
max-width: 70em;
|
||||
color: {{ theme_textcolor }};
|
||||
}
|
||||
|
||||
div.footer {
|
||||
padding: 8px;
|
||||
font-size: 11px;
|
||||
text-align: center;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
/* link colors and text decoration */
|
||||
|
||||
a:link {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: {{ theme_linkcolor }};
|
||||
}
|
||||
|
||||
a:visited {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: {{ theme_visitedlinkcolor }};
|
||||
}
|
||||
|
||||
a:hover, a:active {
|
||||
text-decoration: underline;
|
||||
color: {{ theme_hoverlinkcolor }};
|
||||
}
|
||||
|
||||
/* Some headers act as anchors, don't give them a hover effect */
|
||||
|
||||
h1 a:hover, a:active {
|
||||
text-decoration: none;
|
||||
color: {{ theme_headingcolor }};
|
||||
}
|
||||
|
||||
h2 a:hover, a:active {
|
||||
text-decoration: none;
|
||||
color: {{ theme_headingcolor }};
|
||||
}
|
||||
|
||||
h3 a:hover, a:active {
|
||||
text-decoration: none;
|
||||
color: {{ theme_headingcolor }};
|
||||
}
|
||||
|
||||
h4 a:hover, a:active {
|
||||
text-decoration: none;
|
||||
color: {{ theme_headingcolor }};
|
||||
}
|
||||
|
||||
a.headerlink {
|
||||
color: #a7ce38;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
a.headerlink:hover {
|
||||
color: #a7ce38;
|
||||
}
|
||||
|
||||
/* basic text elements */
|
||||
|
||||
div.content {
|
||||
margin-top: 20px;
|
||||
margin-left: 40px;
|
||||
margin-right: 40px;
|
||||
margin-bottom: 50px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
/* heading and navigation */
|
||||
|
||||
div.header {
|
||||
position: relative;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
height: 85px;
|
||||
/* background: #eeeeee; */
|
||||
padding: 0 40px;
|
||||
}
|
||||
div.header h1 {
|
||||
font-size: 1.6em;
|
||||
font-weight: normal;
|
||||
letter-spacing: 1px;
|
||||
color: {{ theme_headingcolor }};
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding-top: 15px;
|
||||
}
|
||||
div.header h1 a {
|
||||
font-weight: normal;
|
||||
color: {{ theme_headingcolor }};
|
||||
}
|
||||
div.header h2 {
|
||||
font-size: 1.3em;
|
||||
font-weight: normal;
|
||||
letter-spacing: 1px;
|
||||
text-transform: uppercase;
|
||||
color: #aaa;
|
||||
border: 0;
|
||||
margin-top: -3px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.header img.rightlogo {
|
||||
float: right;
|
||||
}
|
||||
|
||||
|
||||
div.title {
|
||||
font-size: 1.3em;
|
||||
font-weight: bold;
|
||||
color: {{ theme_headingcolor }};
|
||||
border-bottom: dotted thin #e0e0e0;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
div.topnav {
|
||||
/* background: #e0e0e0; */
|
||||
}
|
||||
div.topnav p {
|
||||
margin-top: 0;
|
||||
margin-left: 40px;
|
||||
margin-right: 40px;
|
||||
margin-bottom: 0px;
|
||||
text-align: right;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
div.bottomnav {
|
||||
background: #eeeeee;
|
||||
}
|
||||
div.bottomnav p {
|
||||
margin-right: 40px;
|
||||
text-align: right;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
a.uplink {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
|
||||
/* contents box */
|
||||
|
||||
table.index {
|
||||
margin: 0px 0px 30px 30px;
|
||||
padding: 1px;
|
||||
border-width: 1px;
|
||||
border-style: dotted;
|
||||
border-color: #e0e0e0;
|
||||
}
|
||||
table.index tr.heading {
|
||||
background-color: #e0e0e0;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
table.index tr.index {
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
table.index td {
|
||||
padding: 5px 20px;
|
||||
}
|
||||
|
||||
table.index a:link, table.index a:visited {
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
color: {{ theme_linkcolor }};
|
||||
}
|
||||
table.index a:hover, table.index a:active {
|
||||
text-decoration: underline;
|
||||
color: {{ theme_hoverlinkcolor }};
|
||||
}
|
||||
|
||||
|
||||
/* Akka Cloud Manual styles and layout */
|
||||
|
||||
/* Rounded corner boxes */
|
||||
/* Common declarations */
|
||||
div.admonition {
|
||||
-webkit-border-radius: 10px;
|
||||
-khtml-border-radius: 10px;
|
||||
-moz-border-radius: 10px;
|
||||
border-radius: 10px;
|
||||
border-style: dotted;
|
||||
border-width: thin;
|
||||
border-color: #dcdcdc;
|
||||
padding: 10px 15px 10px 15px;
|
||||
margin-bottom: 15px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
div.note {
|
||||
padding: 10px 15px 10px 80px;
|
||||
background: #e4ffde url(alert_info_32.png) 15px 15px no-repeat;
|
||||
min-height: 42px;
|
||||
}
|
||||
div.warning {
|
||||
padding: 10px 15px 10px 80px;
|
||||
background: #fffbc6 url(alert_warning_32.png) 15px 15px no-repeat;
|
||||
min-height: 42px;
|
||||
}
|
||||
div.seealso {
|
||||
background: #e4ffde;
|
||||
}
|
||||
|
||||
/* More layout and styles */
|
||||
h1 {
|
||||
font-size: 1.3em;
|
||||
font-weight: bold;
|
||||
color: {{ theme_headingcolor }};
|
||||
border-bottom: dotted thin #e0e0e0;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.2em;
|
||||
font-weight: normal;
|
||||
color: {{ theme_headingcolor }};
|
||||
border-bottom: dotted thin #e0e0e0;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.1em;
|
||||
font-weight: normal;
|
||||
color: {{ theme_headingcolor }};
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1.0em;
|
||||
font-weight: normal;
|
||||
color: {{ theme_headingcolor }};
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
p {
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
p.last {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
ol {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding-left: 5px;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
li {
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
div.content ul > li {
|
||||
-moz-background-clip:border;
|
||||
-moz-background-inline-policy:continuous;
|
||||
-moz-background-origin:padding;
|
||||
background: transparent url(bullet_orange.png) no-repeat scroll left 0.45em;
|
||||
list-style-image: none;
|
||||
list-style-type: none;
|
||||
padding: 0 0 0 1.666em;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
tt {
|
||||
background-color: #e2e2e2;
|
||||
font-size: 1.0em;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
pre {
|
||||
border-color: #0c3762;
|
||||
border-style: dotted;
|
||||
border-width: thin;
|
||||
margin: 0 0 12px 0;
|
||||
padding: 0.8em;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
hr {
|
||||
border-top: 1px solid #ccc;
|
||||
border-bottom: 0;
|
||||
border-right: 0;
|
||||
border-left: 0;
|
||||
margin-bottom: 10px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
/* printer only pretty stuff */
|
||||
@media print {
|
||||
.noprint {
|
||||
display: none;
|
||||
}
|
||||
/* for acronyms we want their definitions inlined at print time */
|
||||
acronym[title]:after {
|
||||
font-size: small;
|
||||
content: " (" attr(title) ")";
|
||||
font-style: italic;
|
||||
}
|
||||
/* and not have mozilla dotted underline */
|
||||
acronym {
|
||||
border: none;
|
||||
}
|
||||
div.topnav, div.bottomnav, div.header, table.index {
|
||||
display: none;
|
||||
}
|
||||
div.content {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
html {
|
||||
background: #FFF;
|
||||
}
|
||||
}
|
||||
|
||||
.viewcode-back {
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
div.viewcode-block:target {
|
||||
background-color: #f4debf;
|
||||
border-top: 1px solid #ac9;
|
||||
border-bottom: 1px solid #ac9;
|
||||
margin: -1px -12px;
|
||||
padding: 0 12px;
|
||||
}
|
||||
BIN
akka-docs/themes/akka/static/alert_info_32.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
akka-docs/themes/akka/static/alert_warning_32.png
Normal file
|
After Width: | Height: | Size: 1 KiB |
BIN
akka-docs/themes/akka/static/bg-page.png
Normal file
|
After Width: | Height: | Size: 164 B |
BIN
akka-docs/themes/akka/static/bullet_orange.png
Normal file
|
After Width: | Height: | Size: 365 B |
12
akka-docs/themes/akka/theme.conf
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
[theme]
|
||||
inherit = basic
|
||||
stylesheet = akka.css
|
||||
pygments_style = friendly
|
||||
|
||||
[options]
|
||||
full_logo = false
|
||||
textcolor = #333333
|
||||
headingcolor = #0c3762
|
||||
linkcolor = #dc3c01
|
||||
visitedlinkcolor = #892601
|
||||
hoverlinkcolor = #ff4500
|
||||