Tutorial UObject pour Urbi 1.0

(book compiled from )

Matthieu Nottale

Traduction d l'anglais Antoine (Zelig) HUE

This document is released under the Attribution-NonCommercial-NoDerivs 2.0 Creative Commons licence (http://creativecommons.org/licenses/by-nc-nd/2.0/deed.en).


Table of Contents

1. Introduction
Les concepts de base
2. L'API UObject
Créer une classe, lier les variables et fonctions
Créer de nouvelles instances
Notification de modification ou d'accès à une variable
Les timers
Le cas particulier des variables capteurs/actionneurs
Utiliser des variables URBI
Utiliser les types binaires
Utiliser les hubs pour grouper des objets
Envoyer du code URBI
3. CAS D'UTILISATION
Ecrire un périphérique servomoteur
Mise en cache
Utiliser des timers
Utiliser les hubs pour grouper les objets
Autre application
Ecrire un périphérique caméra
Optimisation en mode plugin
Ecrire un périphérique haut-parleur ou microphone
Ecrire un périphérique virtuel : ball detection
A. Copyright

Chapter 1. Introduction

Table of Contents

Les concepts de base

Ce document vous guide à travers les différentes étapes pour écrire un composant URBI C++, en utilisant l'API UObject. Cette API peut être utilisée pour ajouter de nouveaux objets écrit en C++ pour le langage URBI, et pour interagir depuis C++ avec les objets qui sont déjà définis. Nous traitons les cas usuels de contrôle de périphériques physiques(servomotor, speaker, camera...), et nous interfaçons les composants de niveaux plus hauts (voice recognition, object detection,...) avec URBI.

Les concepts de base

L'API définit la classe UObject. Chaque instance d'une classe dérivée de votre code C++ correspondra à un objet URBI partageant certaines de ses méthodes et de ses attributs. L'API fournit des méthodes pour déclarer quels éléments de votre objet seront partagés. Pour partager une variable avec URBI,Vous devez lui donner le type UVar. Ce type est un container qui fournis des opérateurs de tous les types connus à URBI: double, string et char*, et la structure de gestion des binaires UBinary, USound et UImage. Ce type peut aussi lire et écrire dans la classe liburbi UValue. L'API fournie des méthodes pour initialiser les retours de fonctions qui seront notifiés quand une variable sera modifiée ou lue par du code URBI. Les méthode d'instance de tout prototype peuvent être rendu accessible à partir d'Urbi, fournissant tous les types de paramètres et le type en retour peut être converti vers/à partir de UValue.

Le prochain chapitre couvre tous les aspects de l'API UObject, et le reste du document décrit plusieurs cas d'utilisation en détail.

Chapter 2. L'API UObject

Créer une classe, lier les variables et fonctions

Illustrons ces concepts en définissant un objet simple: adder. Cet objet a une variable v, et une méthode add qui retourne la somme de cette variable et de son paramètre.

En premier le include requis et le namespace.

#include <uobject.hh>
using namespace urbi;

puis nous déclarons notre classe adder:

class adder : public UObject //doit hériter de UObject
     {
     public:
     //la classe doit avoir un seul constructeur avec un paramètre string
        adder(string);

        UVar v; //notre variable

        double add(double ); //notre méthode
     };

Enfin l'implantation du constructeur et notre méthode add

//le constructeur défini ce qui est disponible venant d'Urbi
     adder::adder(string s): UObject(s) { //requis

        UBindVar(adder,v); //macro utilisée pour lier les variables
        UBindFunction(adder, add); //macro utilisée pour lier les méthodes
     }

     double adder::add(double secondValue) {
        return v+secondValue;
     }

     //register your class to the URBI kernel
     UStart(adder); //this line registers your class to URBI

Pour résumer:

  • Déclarez votre classe d'objet comme héritant d'UOject

  • Déclarez un constructeur unique avec un paramètre string et passer ce paramètre string au constructeur d'UObject.

  • Déclarez de type UVar les variables que vous voulez partager avec Urbi.

  • Dans le constructeur, appellez UBindVar(classname, varname) pour chaque UVar que vous voulez comme une variable d'instance, et UBindFunction(classname, functionname) pour chaque fonction que vous voulez lier.

  • N'oubliez pas d'appeler la macro UStart pour chaque objet

Créer de nouvelles instances

Quand vous lancez un serveur URBI, un objet de chaque classe enregistrée avec UStart est créé avec le même nom que la classe. De nouvelles instances peuvent être créées d'Urbi en utilisant la commande new. Pour chaque instance créée dans URBI, l'instance correspondante de l'objet C++ est créée. Vous pouvez obtenir les paramètres passés au constructeur en définissant et liant une méthode nommée init avec les paramètres appropriés.

Notification de modification ou d'accès à une variable

Vous pouvez enregistrer une fonction qui serra appelée à chaque accès ou modification d'une variable (uniquement pour les composants locaux) en appelant UNotifyChange et UNotifyAccess, en passant aussi bien une UVar ou un nom de variable name comme premier paramètre, et une fonction membre de votre UObject comme second paramètre. Cette fonction peut avoir zéro ou un paramètre: une UVar & pointant vers la UVar qui est accédée ou modifiée. Le retour de la fonction notifyChange est appelé après que la valeur de la variable est changée, Attendu que le retour de notifyAccess est appelé avant que la variable soit accédée, vous donne la possibilité de mettre à jour sa valeur.

Les timers

L'API vous donne deux méthodes pour appeler une fonction périodiquement:

  • Appeler USetUpdate(int period) dans votre objet initialise un timer qui appel la méthode de l'UObject virtuel update() avec la période spécifiée (en millisecondes)

  • Appeler USetTimer en lui passant la période en millisecondes et un pointeur vers une méthode dans votre UObject appellera cette méthode à la période spécifiée.

Le cas particulier des variables capteurs/actionneurs

Dans URBI, une variable peut avoir différents sens dépendant de si on est en lecture ou en écriture: vous pouvez utiliser la même variable pour représenter la valeur cible d'un actionneur et la valeur courante mesurée par un capteur associé. Ce mode spécial est activé par le UObject définissant la variable en appelant USensor après avoir appelé UBindVar. Cet appel à l'effet suivant

  • Quand du code URBI ou du code venant d'autre modules lit la variable , ils lisent la valeur courante. Quand du code URBI ou du code venant d'autre modules écrivent dans la variable, Ils fixent la valeur de la cible.

  • Quand le module qui a appelé USensor lit la variable, il lit la valeur de la cible. Quand il écrit dans la variable, il écrit la valeur courante.

Si USensor n'est pas appelée, alors la variable a seulement une valeur associée qui est écrite et lue par tous les modules et code URBI.

Utiliser des variables URBI

Vous pouvez lire ou écrire chaque variable URBI en créant une UVar et en passant son nom au constructeur. La valeur est changée en écrivant n'importe quel type compatible à la UVar, et accéder à sa valeur en recopiant l'uvar dans n'importe quel type compatible. Toutefois, des précautions doivent être prisent en mode remote: les changements sur les variables venant de code Urbi ou d'autres modules sont visibles seulement si vous avez appelé UNotifyChange pour cette variable. Autrement l'UVar n'est pas synchronisée. Sinon, en mode remote, vous pouvez obtenir la valeur sur demande en appelant UNotifyOnRequest(variable,fonction). Puis pour obtenir une valeur mise à jour, appelez la méthode requestValue pour la UVar, et votre fonction callback sera appelée dés que la valeur sera disponible. Vous pouvez lire et écrire toutes les propriétés URBI d'une UVar en lisant et écrivant l'objet UProp approprié dans l'UVar.

Utiliser les types binaires

URBI peut stocker des objets binaires de tous types dans un container générique, et fournir des structures spécifiques pour les sons et les images. Le container générique est appelé UBinary et est défini dans l'en-tête uobject.h. Il contient un champ enum qui donne le type du binaire(UNKNOWN(inconnu), SOUND(son) ou IMAGE(image)), et l'union d'une stucture USound et UImage contenant un pointeur vers les données, la taille des données et les méta-informations spécifiques à ce type. Lire un UBinary à partir d'une UVar, et écrire un UBinary dans une UVar exécute un deep-copy des données. En mode plugin, vous pouvez accéder directement au buffer utilisé par le kernel en dupliquant l'UVar dans une UImage ou une USound. Vous pouvez enfin écrire dans le buffer, mais vous ne pouvez changer aucune autre information.

Utiliser les hubs pour grouper des objets

Parfois, vous avez besoin d'exécuter des actions sur un groupe d'UObjects, pour des périphériques d'instances qui ont besoin d'être mis à jour ensemble. L'API fournis la classe UObjectHub pour cet usage. Pour créer un hub, déclarez simplement une sousclasse de UObjectHub, et enregistrez la en appelant une fois la macro UStartHub(classname). Une seule instance de cette classe sera créée à chaque démarrage du serveur. Les instances UObject peuvent être enregistrées dans ce hub en appelant instances URegister(hubclassname). Des Timers peuvent être liés à UObjectHub de la même façon que pour UObject (voir la section timers plus haut). Le kernel appelera la méthode update() de tout UObject avant d'appeler la méthode update() du hub. Une instance hub peut être récupérée en appelant getUObjectHub(string classname). le hub contient aussi la liste des UObject enregistrés dans ses attributs de membre.

Envoyer du code URBI

Si vous avez besoin d'envoyer du code URBI au serveur, la macro URBI() est disponible, aussi bien que la fonction unarmorAndSend(). Vous pouvez aussi bien lui passer une string, ou directement du code URBI code à l'intérieur d'une paire de parenthèses:

unarmorAndSend("tag:1+1;");
URBI((
      at (someevent(x))
      {
        sometag:echo x;
      };
    ));

Chapter 3. CAS D'UTILISATION

Ecrire un périphérique servomoteur

Ecrivons un UObject pour un périphérique servomoteur dont l'API de sous-couche est:

  • bool initialize(int id); //initialise le servomoteur avec un ID donné

  • double getPosition(int id); //lire un servomoteur avec une position id donnée

  • void setPosition(int id, double pos); //envoyer une commande au servomoteur

  • void setPID(int id, int p, int i, int d); //initialiser les paramètres PID

Notre en-tête vient en premier. Notre périphérique servo fournit un attribut nommé val, le nom standard URBI, et deux façon de régler le gain PID: une méthode, et trois variables.

class servo : public UObject //doit hériter du UObject
     {
     public:
     //La classe doit avoir un constructeur unique prenant une string
        servo(string);

        UVar val; //notre variable de position
        UVar P; //P gain
        UVar I; //I gain
        UVar D; //D gain

        int valueChanged(UVar &v); //rappel de changement de val
        int valueAccessed(UVar &v); //rappel pour l'accès à val
        int pidChanged(UVar &v); // rappel pour le changement de PID
        void setPID(int p, int i, int d);
        int init(int id); //constructeur URBI

        int id;
     };

Le constructeur enregistre uniquement l'init, afin que notre instance par défaut ne fasse rien, et puisse seulement être utilisée pour créer de nouvelles instances.

//Le constructeur enregistre uniquement l'init
     servo::servo(string s): UObject(s) { //required
        UBindFunction(servo, init); //register init
     }

La fonction init, est appelée dans une nouvelle instance chaque fois qu'une nouvelle instance URBI est créée, enregistre les trois variables (val, P, I and D), et initialise les fonctions de retour.

int servo::init(int id) { //constructeur URBI
        this->id=id;
        if (!initialize(id)) return 1;
        UBindVar(servo,val);
        USensor(val); //val est à la fois un capteur et un actionneur
        val.blend = UMIX; //règle le mode du blend sur mix
        UBindVar(servo,P);
        UBindVar(servo,I);
        UBindVar(servo,D);
        UBindFunction(servo, setPID);
        UNotifyChange(val, &servo::valueChanged);
        UNotifyAccess(val, &servo::valueAccessed);
        UNotifyChange(P, &servo::pidChanged);
        UNotifyChange(I, &servo::pidChanged);
        UNotifyChange(D, &servo::pidChanged);
        return 0;
     }

Puis nous définissons notre méthode de retour. servo::valueChanged sera appelé chaque fois que la variable val est modifiée, juste après que la valeur est changée: nous utilisons cette méthode pour envoyer notre commande au servo. servo::valueAccessed est appelée juste avant que la valeur soit lue. Dans cette fonction nous demandons au servo la valeur courante, et nous réglons val en conséquence.

//appelée chaque fois que la valeur est écrite
     int servo::valueChanged(UVar & v) { //v is a ref. to val
        setPosition(id, (double)val);
        return 0;

     //appelée chaque fois que la valeur est lue
     int servo::valueAccessed(UVar & v) { //v is a ref. to val
        val = getPosition(id);
        return 0;
     }

servo::pidChanged appelée chaque fois que l'une des variables PID est écrite. La fonction servo::setPID peut être appelée directement à partir d'Urbi.

int servo::pidChanged(UVar &v) {
        setPID(id, (int)P, (int)I, (int)D);
        return 1;
     }
     void servo::setPID(int p, int i, int d) {
        setPID(id, p, i, d);
        P=p;I=i;D=d;
     }
      //enregistre la classe servo dans le kernel d'Urbi
       UStart(servo);

Ca y ai, c'est fini, compilez ce module, et vous pouvez l'utiliser dans URBI:

//crée une nouvelle instance et appelle init(1)
    headPan = new servo(1);
    headPan.setPID(8,2,1); //calls setPID()
    headPan.val=13; //calls valueChanged()
    headPan.val*12; //calls valueAccessed()
    //periodically calls valueChanged()
    headPan.val = 0 sin:1s ampli:20,
    //periodically calls valueAccessed()
    at (headPan.val < 0) echo "left";

Le code d'exemple au dessus présente un problème: valueAccessed et valueChanged sont appelées chaque fois que la valeur est lue ou écrite depuis Urbi, ce qui peut arriver souvent. C'est un problème si l'envoi de la commande actuelle (setPosition dans notre exemple) prends du temps pour s'exécuter. Il y a deux solutions à cette question:

Mise en cache

Une solution est de se rappeler la dernière fois que la valeur a été lue/écrite, et de ne pas utiliser la nouvelle commande avant un temps fixé. Notez que le kernel le fait automatiquement pour les variables USensor()'d qui sont en mode blend autre que normal. Aussi la solution la plus simple au problème ci-dessus est de régler la variable en mode de blend mix. L'inévitable inconvénient est que les commandes ne sont pas appliquées immédiatement, mais seulement après un léger retard.

Utiliser des timers

Au lieu de mettre à jour/récupérer la valeur à la demande, vous pouvez choisir de le faire périodiquement à l'aide d'un timer. Une petite différence entre les deux méthodes d'API est pratique dans ce cas: la méthode de l'update() virtuel appelée périodiquement après avoir été initialisée par USetUpdate(interval) est appelée juste après la première exécution du code Urbi, tandis que l'initialisation des timers par USetTimer sont appelés juste avant la première exécution du code Urbi. Aussi la solution idéale est de lire vos capteurs lors du second retour, et d'écrire dans vos actionneurs dans le premier. Notre exemple précédent (sans le support du PID, pour être clair) peut être réécrit comme cela: l'en-tête devient.

class servo : public UObject //hérite de UObject
     {
     public:
     //La classe doit avoir un constructeur unique prenant une string
        servo(string);

        UVar val; //notre variable de position

        virtual int update(); //appelée périodiquement
        int getVal(); //appelée périodiquement
        int init(int id); //constructeur URBI

        int id;
     };

le constructeur est inchangé, l'initialisation devient:

int servo::init(int id) { //constructeur urbi
        this->id=id;
        if (!initialize(id)) return 0;
        UBindVar(servo,val);
        USensor(val); //val est à la fois un capteur et un actionneur
        USetUpdate(1); //appellera update() périodiquement
        USetTimer(1, &servo::getVal); //idem pour getVal()
        return 0;
     }

valueChanged devient update et valueAccessed devient getVal. Au lieu d'être appelées sur demande, elles sont maintenant appelées périodiquement. La période d'appel ne peut être inférieur à la période du serveur (qui a été choisie au démarrage du robot, ou fixée par l'architecture en sous-couche), aussi vous pouvez la fixer à 0 pour signifier aussi rapidement qu'il est utile.

Utiliser les hubs pour grouper les objets

maintenant, supposons que, pour notre exemple précédent, nous pourrions accélérer les choses en envoyant toutes les commandes du servomoteur en même temps, en utilisant la méthode setPositions(int count, int *ids, double * positions) qui prends deux champs pour ids et positions. Le hub est le meilleur moyen de remplir cette tâche. L'en-tête UObject reste la même. Nous ajoutons une déclaration de hub:

class servohub : public UObjectHub
     {
     public:
     //La classe doit avoir un constructeur unique prenant une string
        servohub(string s);

        virtual int update(); //appelée périodiquement
        void addValue(int id, double val); //appelée par le servo
        int * ids; double * vals; int size; int count;
     };

servo::update devient un appel à la méthode addValue du hub:

int servo::update() {
     ((servohub*)getUObjectHub("servohub"))->addValue(id,
     (double)val);
     };

La ligne suivante peut être ajoutée à la méthode d'initialisation du servo, toutefois elle n'a pas d'utilité dans notre exemple:

URegister(servohub);

Finalement, l'implantation de notre méthode de hub est:

servohub::servohub(string s)
        :UObjectHub(s), ids(0),vals(0),size(0), count(0) {
        USetUpdate(1); //initialisation du timer
     }

     int servohub::update() { //appelée périodiquement
        setPositions(count, ids, vals);
        count=0; //reset le compteur de position
        return 0;
     }

     void servohub::addValue(int id, double val) {
        if (count+1<size) { //allocate more memory
            ids=(int *)realloc(ids, (count+1)*sizeof(int);
            vals=(double*)realloc(vals, (count+1)*sizeof(double);
            size = count+1;
        }
        ids[count]=id; vals[count++]=val;
     }
     UStartHub(servohub); //n'oubliez pas cette ligne

Périodiquement, la méthode update est appelée pour chaque instance de servo, qui ajoute des commandes au champs hub, puis la méthode update du hub est appelée, envoyant actuellement la commande et initialisant le champ.

Autre application

Sinon, pour démontrer l'utilisation de la variable de membre du hub, nous pouvons enlever complètement la méthode d'update de la classe servo (et l'appel USetUpdate() dans l'init), et réécrire la méthode update du hub de la façon suivante:

int servohub::update() { //appelée périodiquement
        for (UObjectList::iterator it=members.begin();
            it!=members.end();it++) {
            addValue(((servo*)*it)->id, (double)((servo*)*it)->val);
        }
        setPositions(count, ids, vals);
        count=0; //reset le compteur de position
        return 0;
     }

Ecrire un périphérique caméra

Un périphérique caméra est un uobject dont le champ val est un objet binaire. Le kernel urbi lui-même ne différencie pas entre tout les formats binaire possibles et les types de données, mais l'API fournit des structures spécifiques aux images par commodité. Vous devez être prudent avec la gestion de la mémoire. La structure UBinary gère sa propre mémoire: les copies sont des deep copy, et le destructeur libère le buffer associé. Les structures UImages et Usound ne le font pas.

Supposons que nous ayons une API caméra en sous-couche avec les fonctions suivantes :

  • bool initialize(int id); //initialise la caméra avec une ID donnée

  • int getWidth(int id); //lit la largeur d'image

  • int getHeight(int id); //lit la hauteur d'image

  • char * getImage(int id); //obtient le buffer d'image au format RGB24. Le retour du buffer est toujours le même et ne doit pas être libéré.

Le code de notre périphérique peut être écrit comme suit:

class Camera : public UObject //hérite de UObject
     {
     public:
     //la classe doit avoir un constructeur unique prenant une string
        Camera(string);

        UVar val; //notre variable image
        UVar width,height; //taille de l'image

        int getVal(UVar &); //appelée sur accès
        virtual int update(); //appelée périodiquement
        int init(int id); //constructeur URBI

        int frame; //compteur de frame de catching
        int accessFrame; //numéro de la frame du dernier accès
        int id; //caméra id
        UBinary bin;
     };

Initialisation des registres du constructeur:

//Initialisation des registres du constructeur
     Camera::Camera(string s): UObject(s),frame(0) { //required
        UBindFunction(Camera, init); //register init
     }

La fonction init lit la variable, une fonction appelée sur accès, et met en route un chronomètre sur update. elle initialise également la structure de UBinary.

int Camera::init(int id) { //constructeur urbi
        this->id=id;
        frame=0; accessFrame = 0;
        if (!initialize(id)) return 0;
        UBindVar(Camera,val);
        UBindVar(Camera,width);
        UBindVar(Camera,height);
        width = getWidth(id); height = getHeight(id);
        USetUpdate(1); //appellera update() periodiquement
        UNotifyAccess(val, &Camera::getVal);
        bin.type=BINARY_IMAGE;
        bin.image.width = width;
        bin.image.height=height;
        bin.image.imageFormat = IMAGE_RGB;
        bin.image.size = width*height*3;
        return 0;
     }

La fonction update met simplement à jour le compteur de frames

int Camera::update() {
        frame++;
        return 0;
     }

getVal met à jour la valeur de la caméra, seulement si elle n'a jamais été appelée par cette frame, qui prévoit un simple mécanisme de mise en cache afin d'éviter trop souvent l'exécution d'une potentiellement longue opération d'acquisition d'une image.

int Camera::getVal(UVar & ) {
      if (frame==accessFrame) return 1;
      bin.image.data = getImage(id);
      val = bin; //assign image to bin
     }
UStart(Camera);

Les données de l'image sont copiées dans le kernel quand on procède de cette façon.

Soyez prudent, supposons que nous ayons créé la structure UBinary dans la méthode getVal, notre buffer aura été libéré à la fin de la fonction. pour éviter cela, réglez le à 0 après avoir assignée la UBinary à la UVar.

Optimisation en mode plugin

En mode plugin, il est possible d'accéder au buffer utilisé par le kernel en la recopiant dans une UImage. Vous pouvez modifier le contenu du buffer du kernel, mais aucun autre paramètre.

Ecrire un périphérique haut-parleur ou microphone

La manipulation des sons est similaire à celle des images, la structure USoundest est fournies pour cette utilisation. La meilleur façon d'implémenter un microphone est de remplir la variable val du UObject avec les données du son correspondant à une période du kernel. Si vous faites ainsi, le code Urbi loop tag:micro.val produira le résultat escompté.

Ecrire un périphérique virtuel : ball detection

Les algorithmes qui nécessite une grosse puissance de calcul peuvent être écrit en C++ mais sont toujours utilisable dans Urbi: Ils récupèrent leurs données en utilisant les variables des autres modules référencés par UVar, et exporte leurs résultats dans d'autres UVar. Considérons le cas d'un périphérique de détection de balle qui reçoit une image en entrée, et envoie en sortie les coordonnées de la balle, si il y en a une de détectée.

L'en-tête est définie ainsi:

class BallTracker : public UObject //hérite de l'UObject
     {
     public:
     //la classe doit avoir un constructeur unique prenant une string
        BallTracker(string);

        UVar visible; //la balle est elle visible?
        UVar x,y; //coordonnées de la balle

        int init(string varname); //constructeur Urbi
     };

initialise seulement les registres du constructeur:

//initialise seulement les registres du constructeur
     BallTracker::BallTracker(string s): UObject(s) { //requis
        UBindFunction(BallTracker, init); //initialisation des registres
     }

La fonction d'initialisation lie les variables et un callback sur la mise à jour de la variable de l'image passée en paramètre.

int BallTracker::init(string cameraval) { //constructeur urbi
        UBindVar(BallTracker,visible);
        UBindVar(BallTracker,x);
        UBindVar(BallTracker,y);
        UNotifyChange(cameraval, &BallTracker::newImage);
        visible = 0;
        return 0;
     }

La fonction newImage fait tourner l'algorithme de détection sur l'image qui est dans ses paramètres, et met à jour les variables.

int BallTracker::newImage(UVar &v) {
        UImage i = v; //recopie dans UImage
        int px,py;
        bool found = detectBall(i.data, i.width, i.height, &px,
     &py);
        if (found) {
            visible = 1;
            x = px/i.width;
            y = py/i.height;
        } else {
            visible = 0;
        }
        return 0;
     }

Appendix A. Copyright


THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE
TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR
"LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE
LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE
OR COPYRIGHT LAW IS PROHIBITED.

BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND
AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS
YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF
SUCH TERMS AND CONDITIONS.

1. Definitions

   1. "Collective Work" means a work, such as a periodical issue,
   anthology or encyclopedia, in which the Work in its entirety in
   unmodified form, along with a number of other contributions,
   constituting separate and independent works in themselves, are
   assembled into a collective whole. A work that constitutes a
   Collective Work will not be considered a Derivative Work (as
   defined below) for the purposes of this License.  2. "Derivative
   Work" means a work based upon the Work or upon the Work and other
   pre-existing works, such as a translation, musical arrangement,
   dramatization, fictionalization, motion picture version, sound
   recording, art reproduction, abridgment, condensation, or any other
   form in which the Work may be recast, transformed, or adapted,
   except that a work that constitutes a Collective Work will not be
   considered a Derivative Work for the purpose of this License. For
   the avoidance of doubt, where the Work is a musical composition or
   sound recording, the synchronization of the Work in timed-relation
   with a moving image ("synching") will be considered a Derivative
   Work for the purpose of this License.  3. "Licensor" means the
   individual or entity that offers the Work under the terms of this
   License.  4. "Original Author" means the individual or entity who
   created the Work.  5. "Work" means the copyrightable work of
   authorship offered under the terms of this License.  6. "You" means
   an individual or entity exercising rights under this License who
   has not previously violated the terms of this License with respect
   to the Work, or who has received express permission from the
   Licensor to exercise rights under this License despite a previous
   violation.

2. Fair Use Rights. Nothing in this license is intended to reduce,
limit, or restrict any rights arising from fair use, first sale or
other limitations on the exclusive rights of the copyright owner under
copyright law or other applicable laws.

3. License Grant. Subject to the terms and conditions of this License,
Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
perpetual (for the duration of the applicable copyright) license to
exercise the rights in the Work as stated below:

   1. to reproduce the Work, to incorporate the Work into one or more
   Collective Works, and to reproduce the Work as incorporated in the
   Collective Works; 2. to distribute copies or phonorecords of,
   display publicly, perform publicly, and perform publicly by means
   of a digital audio transmission the Work including as incorporated
   in Collective Works;

The above rights may be exercised in all media and formats whether now
known or hereafter devised. The above rights include the right to make
such modifications as are technically necessary to exercise the rights
in other media and formats, but otherwise you have no rights to make
Derivative Works. All rights not expressly granted by Licensor are
hereby reserved, including but not limited to the rights set forth in
Sections 4(d) and 4(e).

4. Restrictions.The license granted in Section 3 above is expressly
made subject to and limited by the following restrictions:

   1. You may distribute, publicly display, publicly perform, or
   publicly digitally perform the Work only under the terms of this
   License, and You must include a copy of, or the Uniform Resource
   Identifier for, this License with every copy or phonorecord of the
   Work You distribute, publicly display, publicly perform, or
   publicly digitally perform. You may not offer or impose any terms
   on the Work that alter or restrict the terms of this License or the
   recipients' exercise of the rights granted hereunder. You may not
   sublicense the Work. You must keep intact all notices that refer to
   this License and to the disclaimer of warranties. You may not
   distribute, publicly display, publicly perform, or publicly
   digitally perform the Work with any technological measures that
   control access or use of the Work in a manner inconsistent with the
   terms of this License Agreement. The above applies to the Work as
   incorporated in a Collective Work, but this does not require the
   Collective Work apart from the Work itself to be made subject to
   the terms of this License. If You create a Collective Work, upon
   notice from any Licensor You must, to the extent practicable,
   remove from the Collective Work any reference to such Licensor or
   the Original Author, as requested.  2. You may not exercise any of
   the rights granted to You in Section 3 above in any manner that is
   primarily intended for or directed toward commercial advantage or
   private monetary compensation. The exchange of the Work for other
   copyrighted works by means of digital file-sharing or otherwise
   shall not be considered to be intended for or directed toward
   commercial advantage or private monetary compensation, provided
   there is no payment of any monetary compensation in connection with
   the exchange of copyrighted works.  3. If you distribute, publicly
   display, publicly perform, or publicly digitally perform the Work,
   You must keep intact all copyright notices for the Work and give
   the Original Author credit reasonable to the medium or means You
   are utilizing by conveying the name (or pseudonym if applicable) of
   the Original Author if supplied; the title of the Work if supplied;
   and to the extent reasonably practicable, the Uniform Resource
   Identifier, if any, that Licensor specifies to be associated with
   the Work, unless such URI does not refer to the copyright notice or
   licensing information for the Work. Such credit may be implemented
   in any reasonable manner; provided, however, that in the case of a
   Collective Work, at a minimum such credit will appear where any
   other comparable authorship credit appears and in a manner at least
   as prominent as such other comparable authorship credit.  4.

      For the avoidance of doubt, where the Work is a musical
         composition: 1. Performance Royalties Under Blanket
         Licenses. Licensor reserves the exclusive right to collect,
         whether individually or via a performance rights society
         (e.g. ASCAP, BMI, SESAC), royalties for the public
         performance or public digital performance (e.g. webcast) of
         the Work if that performance is primarily intended for or
         directed toward commercial advantage or private monetary
         compensation.  2. Mechanical Rights and Statutory
         Royalties. Licensor reserves the exclusive right to collect,
         whether individually or via a music rights agency or
         designated agent (e.g. Harry Fox Agency), royalties for any
         phonorecord You create from the Work ("cover version") and
         distribute, subject to the compulsory license created by 17
         USC Section 115 of the US Copyright Act (or the equivalent in
         other jurisdictions), if Your distribution of such cover
         version is primarily intended for or directed toward
         commercial advantage or private monetary compensation.
         5. Webcasting Rights and Statutory Royalties. For the
         avoidance of doubt, where the Work is a sound recording,
         Licensor reserves the exclusive right to collect, whether
         individually or via a performance-rights society
         (e.g. SoundExchange), royalties for the public digital
         performance (e.g. webcast) of the Work, subject to the
         compulsory license created by 17 USC Section 114 of the US
         Copyright Act (or the equivalent in other jurisdictions), if
         Your public digital performance is primarily intended for or
         directed toward commercial advantage or private monetary
         compensation.

5. Representations, Warranties and Disclaimer

UNLESS OTHERWISE MUTUALLY AGREED BY THE PARTIES IN WRITING, LICENSOR
OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR
OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE,
MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR
THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF
ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO
NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY
NOT APPLY TO YOU.

6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY
APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY
LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR
EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK,
EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. Termination

   1. This License and the rights granted hereunder will terminate
   automatically upon any breach by You of the terms of this
   License. Individuals or entities who have received Collective Works
   from You under this License, however, will not have their licenses
   terminated provided such individuals or entities remain in full
   compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will
   survive any termination of this License.  2. Subject to the above
   terms and conditions, the license granted here is perpetual (for
   the duration of the applicable copyright in the
   Work). Notwithstanding the above, Licensor reserves the right to
   release the Work under different license terms or to stop
   distributing the Work at any time; provided, however that any such
   election will not serve to withdraw this License (or any other
   license that has been, or is required to be, granted under the
   terms of this License), and this License will continue in full
   force and effect unless terminated as stated above.

8. Miscellaneous

   1. Each time You distribute or publicly digitally perform the Work
   or a Collective Work, the Licensor offers to the recipient a
   license to the Work on the same terms and conditions as the license
   granted to You under this License.  2. If any provision of this
   License is invalid or unenforceable under applicable law, it shall
   not affect the validity or enforceability of the remainder of the
   terms of this License, and without further action by the parties to
   this agreement, such provision shall be reformed to the minimum
   extent necessary to make such provision valid and enforceable.
   3. No term or provision of this License shall be deemed waived and
   no breach consented to unless such waiver or consent shall be in
   writing and signed by the party to be charged with such waiver or
   consent.  4. This License constitutes the entire agreement between
   the parties with respect to the Work licensed here. There are no
   understandings, agreements or representations with respect to the
   Work not specified here. Licensor shall not be bound by any
   additional provisions that may appear in any communication from
   You. This License may not be modified without the mutual written
   agreement of the Licensor and You.