Copyright © 2005-2006 Gostai
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
Table of Contents
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.
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.
Table of Contents
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
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.
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.
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.
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.
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.
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.
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.
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;
};
));
Table of Contents
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:
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.
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.
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.
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;
}
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.
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é.
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;
}
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.