Skip to content

Commit

Permalink
Demo and tutorial are working.
Browse files Browse the repository at this point in the history
  • Loading branch information
Zaur Nasibov committed Aug 27, 2012
1 parent 1d6958b commit c22dd2f
Show file tree
Hide file tree
Showing 15 changed files with 234 additions and 151 deletions.
2 changes: 0 additions & 2 deletions demo/demo_config.py
Expand Up @@ -45,5 +45,3 @@
}

APPLICATIONS = [app_hash_cracker_1]
#APPLICATIONS = [app_mc_pi_1, ]
#APPLICATIONS = [app_mc_pi_1, app_hash_cracker_1]
29 changes: 29 additions & 0 deletions doc/_static/Makefile
@@ -0,0 +1,29 @@
PROJECT_NAME = monte_carlo_pi
LIB = $(PROJECT_NAME).js
# location of coffee file and to-be-compiled js files.
LIBDIR = js

# js target
TARGETS = $(LIBDIR)/$(LIB)
CLEAN_TARGETS =

# if make has been called recursively, add remote targets
ifeq ($(origin PJ_RES_DIR), environment)
TARGETS += remote
CLEAN_TARGETS += clean_remote
endif

all: $(TARGETS)

$(LIBDIR)/$(LIB): $(LIBDIR)/$(PROJECT_NAME).coffee
coffee --bare -c $(LIBDIR)/$(PROJECT_NAME).coffee

remote:
mkdir -p $(PJ_RES_DIR)/$(PROJECT_NAME)
cp $(LIBDIR)/*.js $(PJ_RES_DIR)/$(PROJECT_NAME)

clean: $(CLEAN_TARGETS)
rm -f $(LIBDIR)/$(PROJECT_NAME).js

clean_remote:
rm -rf $(PJ_RES_DIR)/$(PROJECT_NAME)
27 changes: 26 additions & 1 deletion doc/_static/alea.js
@@ -1,4 +1,29 @@
// From http://baagoe.com/en/RandomMusings/javascript/
// Copyright (C) 2010 by Johannes Baagøe <baagoe@baagoe.org
// Aleas is licensed under the MIT license.
// http://baagoe.org/en/wiki/Alea
function Mash() {
var n = 0xefc8249d;

var mash = function(data) {
data = data.toString();
for (var i = 0; i < data.length; i++) {
n += data.charCodeAt(i);
var h = 0.02519603282416938 * n;
n = h >>> 0;
h -= n;
h *= n;
n = h >>> 0;
h -= n;
n += h * 0x100000000; // 2^32
}
return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
};

mash.version = 'Mash 0.9';
return mash;
}


function Alea() {
return (function(args) {
// Johannes Baagøe <baagoe@baagoe.com>, 2010
Expand Down
6 changes: 3 additions & 3 deletions doc/auto_filters.rst
Expand Up @@ -70,7 +70,7 @@ class::
'__next__' : [depleted_guard, ],
'normalize' : [ignore_null_result, ],
'store_result' : [ignore_null_result, ],
}
}

Here, :ref:`auto_filter <api_auto_filter>` is a binary-flag attribute
which defines the auto-decorating process behaviour.
Expand All @@ -85,7 +85,7 @@ the ``auto_filter`` attribute with desired value, e.g.::
auto_filter = CONFIG_FILTERS

The :ref:`auto_filters <api_auto_filters>` attribute defines the filters
bound to the methods of the class. In the example above the
both :meth:`Project.normalize` and :meth:`Project.store_result` methods
bound to the methods of the class. In the example above both
:meth:`Project.normalize` and :meth:`Project.store_result` methods
are decorated by the :func:`ignore_null_result
<kaylee.project.ignore_null_result>` filter.
1 change: 1 addition & 0 deletions doc/clientapi.rst
Expand Up @@ -308,6 +308,7 @@ AJAX
:param error: callback invoked in of request failure.



.. [1] http://en.wikipedia.org/wiki/Web_worker
.. [2] http://www.w3schools.com/html5/html5_webworkers.asp
10 changes: 4 additions & 6 deletions doc/tutorial/client_side.rst
Expand Up @@ -6,10 +6,8 @@ Step 3: Client-Side Code
As you may already know, the client-side of Kaylee is written in
`CoffeeScript <http://coffeescript.org/>`_. But there is nothing
that prevents you from writing the project in pure JavaScript!
Yet, for simplicity and clarity we are going to use CoffeeScript.
Mastering the basics of CoffeeScript takes less than 10 minutes
and even without that, the project code should be simple and clear to
everybody.
Mastering the basics of CoffeeScript takes less than 30 minutes
and that is the language used in the tutorial application.

The client-side code of Kaylee projects basically consists of two callbacks
in ``pj`` namespace: :js:func:`pj.init(kl_config, app_config) <pj.init>` and
Expand Down Expand Up @@ -46,8 +44,8 @@ Here, we implement the Monte-Carlo PI algorithm and return the result via
the :js:func:`task_completed() <klw.task_completed>` function from
:ref:`Kaylee Worker API <client_workerapi>`.

If you are comfortable with the code above, just copy-paste it to
``js/monte_carlo_pi.coffee``.
If you are comfortable with the code above, copy-paste it to
``monte_carlo_pi/js/monte_carlo_pi.coffee``.


Continue with :ref:`tutorial-server-side`.
63 changes: 63 additions & 0 deletions doc/tutorial/compiling.rst
@@ -0,0 +1,63 @@
.. _tutorial-compiling:

Step 6: Compiling the Application
=================================

Makefile
--------

The Makefile builds ``monte_carlo_pi.js`` locally and (if built by the
master demo Makefile) copies the fields to to the ``build`` directory:

.. code-block:: makefile
PROJECT_NAME = monte_carlo_pi
LIB = $(PROJECT_NAME).js
# location of coffee file and to-be-compiled js files.
LIBDIR = js
# js target
TARGETS = $(LIBDIR)/$(LIB)
CLEAN_TARGETS =
# if make has been called recursively, add remote targets
ifeq ($(origin PJ_RES_DIR), environment)
TARGETS += remote
CLEAN_TARGETS += clean_remote
endif
all: $(TARGETS)
$(LIBDIR)/$(LIB): $(LIBDIR)/$(PROJECT_NAME).coffee
coffee --bare -c $(LIBDIR)/$(PROJECT_NAME).coffee
remote:
mkdir -p $(PJ_RES_DIR)/$(PROJECT_NAME)
cp $(LIBDIR)/*.js $(PJ_RES_DIR)/$(PROJECT_NAME)
clean: $(CLEAN_TARGETS)
rm -f $(LIBDIR)/$(PROJECT_NAME).js
clean_remote:
rm -rf $(PJ_RES_DIR)/$(PROJECT_NAME)
Do **NOT** copy-paste the code above to because Makefiles syntax is based
on tab characters. `Download <../_static/Makefile>`_ the Makefile
and save it to ``monte_carlo_pi/Makefile``.

It is also necessary to modify the master demo Makefile in order for the
build process find the project:

.. code-block:: makefile
# demo/Makefile
PROJECTS = monte_carlo_pi # you can comment out the rest of the applications
Run ``make`` in demo directory to build the projects and collect the files
to the ``build`` directory.


Continue with :ref:`tutorial-running`.
54 changes: 28 additions & 26 deletions doc/tutorial/configuration.rst
Expand Up @@ -6,10 +6,13 @@ Step 5: Configuring the Application
Kaylee has numerous ways of loading the configuration. One of the
convenient ways is to load it from a ``.py`` file. The
``demo/demo_config.py`` file used for demo configuration can be as well used
to configure our application.
to configure the tutorial application.
The applications are defined in a Python dictionary-like or JSON-like
manner. First of all, the application needs a unique name and a description:
::

.. code-block:: python
# demo/demo_config.py
app_mc_pi_1 = {
'name' : 'mc_pi.1',
Expand All @@ -18,8 +21,10 @@ manner. First of all, the application needs a unique name and a description:
...
}
Now, lets add the project configuration. Note, that it is still an entry in
``app_mc_pi_1`` dict::
Now, let's write the project configuration. Note, that we are still filling
the ``app_mc_pi_1`` dict:

.. code-block:: python
'project' : {
'name' : 'MonteCarloPiProject',
Expand All @@ -28,28 +33,29 @@ Now, lets add the project configuration. Note, that it is still an entry in
'alea_script' : '/static/js/projects/monte_carlo_pi/alea.js',
'random_points' : 1000000,
'tasks_count' : 10
},
},
'storage' : {
'name' : 'MemoryPermanentStorage',
}
},
}
},
.. module:: kaylee

The ``name`` entry indicated the Python class (Kaylee Project subclass) used
in this application (``MonteCarloPiProject``).
The ``config`` contains the keyword arguments passed to
``Project.__init__()``. The ``storage`` entry defines the
:py:class:`permanent storage <PermanentStorage>` to which the results are
saved. The :py:class:`MemoryPermanentStorage
<kaylee.contrib.MemoryPermanentStorage>`
is a simple in-memory storage from :ref:`kaylee.contrib <contrib>`.

The final piece of the configuration is the controller and its temporal results
storage. To keep things simple, lets use :py:class:`SimpleController
<kaylee.contrib.SimpleController>` from ``kaylee.contrib``.
Note that this is also the part of the application configuration and recides
inside the ``app_mc_pi_1`` dictionary.::
The ``name`` entry indicates the Python class (:py:class:`kaylee.Project`
subclass) used in the application. The ``config`` contains the keyword
arguments passed to ``Project.__init__()``. The ``storage`` entry defines
the :py:class:`permanent storage <PermanentStorage>` to which the results
are saved. Here, :py:class:`MemoryPermanentStorage
<kaylee.contrib.MemoryPermanentStorage>` is a simple in-memory storage from
:ref:`kaylee.contrib <contrib>` package.

The final piece of the configuration is the controller. To keep things
simple, let's use :py:class:`SimpleController
<kaylee.contrib.SimpleController>` from ``kaylee.contrib``. Note that this
is also the part of the application configuration and recides
inside the ``app_mc_pi_1`` dictionary:

.. code-block:: python
'controller' : {
'name' : 'SimpleController',
Expand All @@ -63,8 +69,4 @@ picks up the first available application).

APPLICATIONS = [app_mc_pi_1 ]

That's it! You are now ready to launch the application to compute PI via
distributed calculations.


Continue with :ref:`tutorial-running`.
Continue with :ref:`tutorial-compiling`.
3 changes: 2 additions & 1 deletion doc/tutorial/index.rst
Expand Up @@ -17,9 +17,10 @@ http://github.com/BasicWolf/kaylee-tutorial-app
:maxdepth: 1

introduction
structure
requirements
structure
client_side
server_side
configuration
compiling
running
2 changes: 1 addition & 1 deletion doc/tutorial/introduction.rst
Expand Up @@ -61,4 +61,4 @@ Of course that can be done on your own computer! But this is just a small
problem enough to learn building Kaylee apps :)


Continue with :ref:`tutorial-project-structure`.
Continue with :ref:`tutorial-requirements`.
56 changes: 32 additions & 24 deletions doc/tutorial/requirements.rst
@@ -1,13 +1,13 @@
.. _tutorial-requirements:

Step 2: Project Requirements
Step 1: Project Requirements
============================


Pseudo-Random Generator
-----------------------
As we discussed before, the random numbers are what makes Monte Carlo method
possible. Unfortunately it is not that easy to quickly generate truly random
As we discussed before, the Monte Carlo method is based on random numbers'
sequences. Unfortunately it is not that easy to quickly generate truly random
numbers on a computer. Instead the ``pseudo-random`` generators are used for
this purpose. The problem with the javascript's standard ``Math.random()`` is
that there is no official way to start a random numbers sequence from a certain
Expand All @@ -16,48 +16,56 @@ verify the results.
However there are great javascript libraries for pseudo-random numbers
generation. One of them is the `alea.js`_ library which we are going to use.

So before continuing, please `download <../_static/alea.js>`_
and include ``alea.js`` in project's ``js`` directory.


.. _tutorial-requirements-configuration:

Configuration
-------------
The client-side application configuration is a JSON object passed from the
server to the client when an application is initialized on the client side.
It contains shared and application-specific information required for the
project initialization.
What kind of configuration do we need to pass to the client?
server to the client during the application initialization process.
What kind of configuration does the tutorial app client requires?
First of all, a Node should know the number of random points to be generated.
Second, the project requires the ``alea.js`` library and should be able to load
it. Luckily the standard ``importScripts()`` function is available in HTML5
Web Workers in order to load javascript code. All we have to do is to pass the
URL of the library. Considering these requirements, the desired configuration
is similar to::
Second, the project requires the ``alea.js`` library. Fortunately the standard
``importScripts()`` function is available in HTML5 Web Workers, which loads
javascript code on the fly. Considering these requirements, the desired
client-side configuration would be similar to::

{
'alea_script' : '/static/projects/monte_carlo_pi/alea.js',
'random_points' : 100000,
}

On server-side, the project needs to know the amount of completed *tasks*
that would be enough for the overall calculations.
The server-side part of the application should be aware of the amount of
completed tasks that would be enough to announce the computing process
to be `completed`::

{
'tasks_count' : 10
}


Tasks and Solutions Data
------------------------
Every random numbers sequence needs a seed to start with. And such unique seed
already exists in every task: it is unique task's ``id`` provided by the project.
For our purpose, even a numerical incremental id is enough to server as a seed.
The returned solution is simpy the calculated value of PI.
Every random numbers sequence needs a seed to start with. Fortunately,
that kind of seed already exists in every task: it is unique task's ``id``
provided by the project. Even a numerical auto-incremental id is enough
to serve as a seed::

{
'id' : 1
}

The returned solution is simpy the calculated value of PI::

{
'pi' : 3.14212
}


The Algorithm
-------------

The algorithm of calculating PI is based on the theory explained in
:ref:`introduction <tutorial-introduction>`::
:ref:`tutorial-introduction`::

let points_counter = 0
repeat random_points times:
Expand All @@ -71,6 +79,6 @@ On server-side the results are collected and the mean value is calculated::

pi = sum(pi_1, pi_2, ... pi_amount_of_tasks) / amount_of_tasks

Continue with :ref:`tutorial-client-side`.
Continue with :ref:`tutorial-project-structure`.

.. _alea.js: http://baagoe.org/en/w/index.php/Better_random_numbers_for_javascript

0 comments on commit c22dd2f

Please sign in to comment.