Index: indicop/__init__.py
===================================================================
--- indicop/__init__.py	(revision 6c8631502f5499545b4b654ab3a2f619cb6b59c4)
+++ indicop/__init__.py	(revision b05fd7f86fb7ba6ddb22bcab445d80cd9c24d90c)
@@ -36,5 +36,4 @@
 from selenium import selenium
 
-    ##TODO check relative PATHs
 class Indicop():
     
@@ -44,5 +43,5 @@
         sys.stderr = outerr
         
-        result = nose.run(argv=['nose','-v', 'indicop/MaKaC_tests/'])
+        result = nose.run(argv=['nose','-v', os.path.join(self.setupDir, 'python', 'unit', 'MaKaC_tests')])
         
         #restoring the stderr
@@ -50,10 +49,10 @@
         
         s = outerr.getvalue()
-        self.writeReport("unitTest", s)
+        self.writeReport("pyunit", s)
         
         if result:
             return "PY Unit tests succeeded\n"
         else:
-            return "[FAIL] Unit tests - report in indicop/report/unitTest.txt\n"
+            return "[FAIL] Unit tests - report in indicop/report/pyunit.txt\n"
 
 
@@ -61,5 +60,6 @@
         try:
             #Starting Selenium server
-            child = subprocess.Popen(["java", "-jar", "indicop/selenium_tests/selenium-server.jar"], stdout=subprocess.PIPE)
+            child = subprocess.Popen(["java", "-jar", os.path.join(self.setupDir, 'python', 'functional', 'selenium-server.jar')],
+                                        stdout=subprocess.PIPE)
         except OSError:
             print "[ERR] Could not start selenium server - command \"java\" needs to be in your PATH."
@@ -87,5 +87,5 @@
         sys.stderr = outerr
         
-        result = nose.run(argv=['nose','-v', 'indicop/selenium_tests/'])
+        result = nose.run(argv=['nose','-v', os.path.join(self.setupDir, 'python', 'functional')])
         
         #restoring the stderr
@@ -93,5 +93,5 @@
         
         s = outerr.getvalue()
-        self.writeReport("functionalTest", s)
+        self.writeReport("pyfunctional", s)
         
         report = ""
@@ -99,5 +99,5 @@
             report = "PY Functional tests succeeded\n"
         else:
-            report = "[FAIL] Functional tests - report in indicop/report/functionalTest.txt\n"
+            report = "[FAIL] Functional tests - report in indicop/report/pyfunctional.txt\n"
             
         #Stopping Selenium Server
@@ -108,5 +108,7 @@
 
     def pylint(self):
-        statusOutput = commands.getstatusoutput("pylint --rcfile=indicop/source_analysis/pylint/pylint.conf ../cds-indico/indico/MaKaC/conference.py")
+        statusOutput = commands.getstatusoutput("pylint --rcfile=%s %s" % 
+                                                (os.path.join(self.setupDir, 'python', 'pylint', 'pylint.conf'),
+                                                 os.path.join(self.setupDir, '..', 'indico', 'MaKaC')))
         if statusOutput[1].find("pylint: not found") > -1:
             print "[ERR] Could not start Source Analysis - command \"pylint\" needs to be in your PATH."
@@ -120,15 +122,15 @@
         try:
             #Starting js-test-driver server
-            server = subprocess.Popen(["java", "-jar", "indicop/javascript_tests/JsTestDriver-1.2.jar", "--port", "9876", "--browser", "firefox"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+            server = subprocess.Popen(["java", "-jar", os.path.join(self.setupDir, 'javascript', 'unit', 'JsTestDriver-1.2.jar'), "--port", "9876", "--browser", "firefox"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
             time.sleep(2)
             
             #switching directory to run the tests
             rootDir = os.getcwd()
-            os.chdir("%s/indicop/javascript_tests/" % rootDir)
+            os.chdir(os.path.join(self.setupDir, 'javascript', 'unit'))
             
             #check if server is ready
             for i in range(5):
                 if coverage:
-                    jsDryRun = commands.getstatusoutput("java -jar JsTestDriver-1.2.jar --tests Fake.dryRun --testOutput coverage")
+                    jsDryRun = commands.getstatusoutput("java -jar JsTestDriver-1.2.jar --tests Fake.dryRun --testOutput %s" % os.path.join('..', '..', 'report', 'jscoverage'))
                 else:
                     jsDryRun = commands.getstatusoutput("java -jar JsTestDriver-1.2.jar --config jsTestDriverNoCoverage.conf --tests Fake.dryRun")
@@ -153,15 +155,15 @@
             coverageReport = ""
             if coverage:
-                jsTest = commands.getstatusoutput("java -jar JsTestDriver-1.2.jar --tests %s --testOutput coverage" % toTest)
-                
-                os.chdir("%s/coverage" % os.getcwd())
+                jsTest = commands.getstatusoutput("java -jar JsTestDriver-1.2.jar --tests %s --testOutput %s" % (toTest, os.path.join('..', '..', 'report', 'jscoverage')))
                 
                 #generate html for coverage
-                genOutput = commands.getstatusoutput("genhtml jsTestDriver.conf-coverage.dat")
+                genOutput = commands.getstatusoutput("genhtml -o %s %s" % 
+                                                     (os.path.join('..', '..', 'report', 'jscoverage'), 
+                                                      os.path.join('..', '..', 'report', 'jscoverage', 'jsTestDriver.conf-coverage.dat')))
                 
                 if genOutput[1].find("genhtml") > -1:
                     coverageReport = "[ERR] JS Unit Tests - html coverage generation failed, genhtml needs to be in your PATH.\n"
                 else:
-                    coverageReport = "JS Unit Tests - coverage generated in indicop/javascript_tests/coverage/index.html\n"
+                    coverageReport = "JS Unit Tests - coverage generated in indicop/report/jscoverage/index.html\n"
                 
             else:
@@ -177,6 +179,6 @@
                 report = "JS Unit Tests - Output in console\n"
             else:
-                self.writeReport("jsUnit", jsTest[1])
-                report = "JS Unit Tests - report in indicop/report/jsUnit.txt\n"
+                self.writeReport("jsunit", jsTest[1])
+                report = "JS Unit Tests - report in indicop/report/jsunit.txt\n"
         except OSError:
             print "[ERR] Could not start js-test-driver server - command \"java\" needs to be in your PATH."
@@ -203,21 +205,25 @@
         
         for folderName in folderNames:
-            for root, dirs, files in os.walk("%s/indico/htdocs/js/indico/%s" % (os.getcwd(), folderName)):
+            #for root, dirs, files in os.walk("%s/indico/htdocs/js/indico/%s" % (os.getcwd(), folderName)):
+            for root, dirs, files in os.walk(os.path.join(self.setupDir, '..', 'indico', 'htdocs', 'js', 'indico', folderName)):
                 for name in files:
                     filename = os.path.join(root, name)
                     outputString += "\n================== Scanning %s ==================\n" % filename
-                    output = commands.getstatusoutput("rhino indicop/source_analysis/jslint/jslint.js %s" % filename)
+                    output = commands.getstatusoutput("rhino %s %s" % (os.path.join(self.setupDir, 'javascript', 'jslint', 'jslint.js'), filename))
                     outputString += output[1]
 
-        self.writeReport("jsLint", outputString)
-        return "JS Lint - report in indicop/report/jsLint.txt\n"
+        self.writeReport("jslint", outputString)
+        return "JS Lint - report in indicop/report/jslint.txt\n"
 
     
     def writeReport(self, filename, content):
-        f = open('indicop/report/%s.txt' % filename, 'w')
+        f = open(os.path.join(self.setupDir, 'report', filename + ".txt"), 'w')
         f.write(content)
         f.close()
 
     def main(self, specify, coverage, unitTest, functionalTest, pylint, jsunit, jslint, jsCoverage, jsSpecify):
+        #path where this file is
+        self.setupDir = os.path.dirname(__file__)
+        
         returnString="\n\n=============== ~INDICOP SAYS~ ===============\n\n"
         
@@ -227,5 +233,5 @@
         if specify:
             #running directly the test here and ouputing in the console
-            result = nose.run(argv=['nose','-v', 'indicop/%s' % specify])
+            result = nose.run(argv=['nose','-v', os.path.join(self.setupDir, 'python', specify)])
             if result:
                 returnString += "Specified Test - Succeeded\n"
@@ -252,10 +258,11 @@
             figleaf.stop()
             coverageOutput = figleaf.get_data().gather_files()
+            coverageDir = os.path.join(self.setupDir, 'report', 'pycoverage')
             try:
-                figleaf.annotate_html.report_as_html(coverageOutput, 'indicop/coverage/html_report', [], {})
+                figleaf.annotate_html.report_as_html(coverageOutput, coverageDir, [], {})
             except IOError:
-                os.mkdir('indicop/coverage/html_report')
-                figleaf.annotate_html.report_as_html(coverageOutput, 'indicop/coverage/html_report', [], {})
-            returnString += "PY Unit Test - Report generated in indicop/coverage/html_report/index.html\n"
+                os.mkdir(coverageDir)
+                figleaf.annotate_html.report_as_html(coverageOutput, coverageDir, [], {})
+            returnString += "PY Unit Test - Report generated in report/pycoverage/index.html\n"
         
         
Index: indicop/javascript/jslint/jslint.js
===================================================================
--- indicop/javascript/jslint/jslint.js	(revision b05fd7f86fb7ba6ddb22bcab445d80cd9c24d90c)
+++ indicop/javascript/jslint/jslint.js	(revision b05fd7f86fb7ba6ddb22bcab445d80cd9c24d90c)
@@ -0,0 +1,355 @@
+// (C)2002 Douglas Crockford
+// www.JSLint.com
+// Rhino Edition
+
+var JSLINT;JSLINT=function(){var adsafe={apply:true,call:true,callee:true,caller:true,constructor:true,'eval':true,prototype:true,unwatch:true,valueOf:true,watch:true},adsafe_allow,allOptions={adsafe:true,bitwise:true,browser:true,cap:true,debug:true,eqeqeq:true,evil:true,forin:true,fragment:true,laxbreak:true,nomen:true,on:true,passfail:true,plusplus:true,regexp:true,rhino:true,undef:true,sidebar:true,white:true,widget:true},anonname,browser={alert:true,blur:true,clearInterval:true,clearTimeout:true,close:true,closed:true,confirm:true,console:true,Debug:true,defaultStatus:true,document:true,event:true,focus:true,frames:true,getComputedStyle:true,history:true,Image:true,length:true,location:true,moveBy:true,moveTo:true,name:true,navigator:true,onblur:true,onerror:true,onfocus:true,onload:true,onresize:true,onunload:true,open:true,opener:true,opera:true,Option:true,parent:true,print:true,prompt:true,resizeBy:true,resizeTo:true,screen:true,scroll:true,scrollBy:true,scrollTo:true,self:true,setInterval:true,setTimeout:true,status:true,top:true,window:true,XMLHttpRequest:true},escapes={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','/':'\\/','\\':'\\\\'},funct,functions,href={background:true,content:true,data:true,dynsrc:true,href:true,lowsrc:true,value:true,src:true,style:true},global,globals,implied,inblock,indent,jsonmode,lines,lookahead,math_member={E:true,LN2:true,LN10:true,LOG2E:true,LOG10E:true,PI:true,SQRT1_2:true,SQRT2:true},member,membersOnly,nexttoken,noreach,number_member={MAX_VALUE:true,MIN_VALUE:true,NEGATIVE_INFINITY:true,POSITIVE_INFINITY:true},option,prereg,prevtoken,rhino={defineClass:true,deserialize:true,gc:true,help:true,load:true,loadClass:true,print:true,quit:true,readFile:true,readUrl:true,runCommand:true,seal:true,serialize:true,spawn:true,sync:true,toint32:true,version:true},scope,sidebar={System:true},src,stack,standard={Array:true,Boolean:true,Date:true,decodeURI:true,decodeURIComponent:true,encodeURI:true,encodeURIComponent:true,Error:true,escape:true,'eval':true,EvalError:true,Function:true,isFinite:true,isNaN:true,Math:true,Number:true,Object:true,parseInt:true,parseFloat:true,RangeError:true,ReferenceError:true,RegExp:true,String:true,SyntaxError:true,TypeError:true,unescape:true,URIError:true},syntax={},token,warnings,widget={alert:true,appleScript:true,animator:true,appleScript:true,beep:true,bytesToUIString:true,Canvas:true,chooseColor:true,chooseFile:true,chooseFolder:true,convertPathToHFS:true,convertPathToPlatform:true,closeWidget:true,COM:true,CustomAnimation:true,escape:true,FadeAnimation:true,filesystem:true,focusWidget:true,form:true,FormField:true,Frame:true,HotKey:true,Image:true,include:true,isApplicationRunning:true,iTunes:true,konfabulatorVersion:true,log:true,MenuItem:true,MoveAnimation:true,openURL:true,play:true,Point:true,popupMenu:true,preferenceGroups:true,preferences:true,print:true,prompt:true,random:true,reloadWidget:true,resolvePath:true,resumeUpdates:true,RotateAnimation:true,runCommand:true,runCommandInBg:true,saveAs:true,savePreferences:true,screen:true,ScrollBar:true,showWidgetPreferences:true,sleep:true,speak:true,suppressUpdates:true,system:true,tellWidget:true,Text:true,TextArea:true,unescape:true,updateNow:true,URL:true,widget:true,Window:true,XMLDOM:true,XMLHttpRequest:true,yahooCheckLogin:true,yahooLogin:true,yahooLogout:true},xmode,xtype,ax=/@cc|<\/?script|\]\]|&/i,cx=/[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/,tx=/^\s*([(){}\[.,:;'"~]|\](\]>)?|\?>?|==?=?|\/(\*(global|extern|jslint|member|members)?|=|\/)?|\*[\/=]?|\+[+=]?|-[\-=]?|%[=>]?|&[&=]?|\|[|=]?|>>?>?=?|<([\/=%\?]|\!(\[|--)?|<=?)?|\^=?|\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\.[0-9]*)?([eE][+\-]?[0-9]+)?)/,lx=/\*\/|\/\*/,ix=/^([a-zA-Z_$][a-zA-Z0-9_$]*)$/,jx=/(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i,ux=/&|\+|\u00AD|\.\.|\/\*|%[^;]|base64|url|expression|data|mailto/i;function F(){}
+function object(o){F.prototype=o;return new F();}
+Object.prototype.union=function(o){var n;for(n in o)if(o.hasOwnProperty(n)){this[n]=o[n];}};String.prototype.entityify=function(){return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');};String.prototype.isAlpha=function(){return(this>='a'&&this<='z\uffff')||(this>='A'&&this<='Z\uffff');};String.prototype.isDigit=function(){return(this>='0'&&this<='9');};String.prototype.supplant=function(o){return this.replace(/\{([^{}]*)\}/g,function(a,b){var r=o[b];return typeof r==='string'||typeof r==='number'?r:a;});};String.prototype.name=function(){if(ix.test(this)){return this;}
+if(/[&<"\/\\\x00-\x1f]/.test(this)){return'"'+this.replace(/[&<"\/\\\x00-\x1f]/g,function(a){var c=escapes[a];if(c){return c;}
+c=a.charCodeAt();return'\\u00'+
+Math.floor(c/16).toString(16)+
+(c%16).toString(16);})+'"';}
+return'"'+this+'"';};function populateGlobals(){if(option.adsafe){globals.union(adsafe_allow);}else{if(option.rhino){globals.union(rhino);}
+if(option.browser||option.sidebar){globals.union(browser);}
+if(option.sidebar){globals.union(sidebar);}
+if(option.widget){globals.union(widget);}}}
+function quit(m,l,ch){throw{name:'JSLintError',line:l,character:ch,message:m+" ("+Math.floor((l/lines.length)*100)+"% scanned)."};}
+function warning(m,t,a,b,c,d){var ch,l,w;t=t||nexttoken;if(t.id==='(end)'){t=token;}
+l=t.line||0;ch=t.from||0;w={id:'(error)',raw:m,evidence:lines[l]||'',line:l,character:ch,a:a,b:b,c:c,d:d};w.reason=m.supplant(w);JSLINT.errors.push(w);if(option.passfail){quit('Stopping. ',l,ch);}
+warnings+=1;if(warnings===50){quit("Too many errors.",l,ch);}
+return w;}
+function warningAt(m,l,ch,a,b,c,d){return warning(m,{line:l,from:ch},a,b,c,d);}
+function error(m,t,a,b,c,d){var w=warning(m,t,a,b,c,d);quit("Stopping, unable to continue.",w.line,w.character);}
+function errorAt(m,l,ch,a,b,c,d){return error(m,{line:l,from:ch},a,b,c,d);}
+var lex=function(){var character,from,line,s;function nextLine(){var at;line+=1;if(line>=lines.length){return false;}
+character=0;s=lines[line].replace(/\t/g,'    ');at=s.search(cx);if(at>=0){warningAt("Unsafe character.",line,at);}
+return true;}
+function it(type,value){var i,t;if(type==='(punctuator)'||(type==='(identifier)'&&syntax.hasOwnProperty(value))){t=syntax[value];if(!t.id){t=syntax[type];}}else{t=syntax[type];}
+t=object(t);if(type==='(string)'){if(jx.test(value)){warningAt("Script URL.",line,from);}}else if(type==='(identifier)'){if(option.nomen&&value.charAt(0)==='_'){warningAt("Unexpected '_' in '{a}'.",line,from,value);}}
+t.value=value;t.line=line;t.character=character;t.from=from;i=t.id;if(i!=='(endline)'){prereg=i&&(('(,=:[!&|?{};'.indexOf(i.charAt(i.length-1))>=0)||i==='return');}
+return t;}
+return{init:function(source){if(typeof source==='string'){lines=source.replace(/\r\n/g,'\n').replace(/\r/g,'\n').split('\n');}else{lines=source;}
+line=-1;nextLine();from=0;},token:function(){var b,c,captures,d,depth,high,i,l,low,q,t;function match(x){var r=x.exec(s),r1;if(r){l=r[0].length;r1=r[1];c=r1.charAt(0);s=s.substr(l);character+=l;from=character-r1.length;return r1;}}
+function string(x){var c,j,r='';if(jsonmode&&x!=='"'){warningAt("Strings must use doublequote.",line,character);}
+if(xmode===x||xmode==='string'){return it('(punctuator)',x);}
+function esc(n){var i=parseInt(s.substr(j+1,n),16);j+=n;if(i>=32&&i<=127&&i!==34&&i!==92&&i!==39){warningAt("Unnecessary escapement.",line,character);}
+character+=n;c=String.fromCharCode(i);}
+j=0;for(;;){while(j>=s.length){j=0;if(xmode!=='xml'||!nextLine()){errorAt("Unclosed string.",line,from);}}
+c=s.charAt(j);if(c===x){character+=1;s=s.substr(j+1);return it('(string)',r,x);}
+if(c<' '){if(c==='\n'||c==='\r'){break;}
+warningAt("Control character in string: {a}.",line,character+j,s.slice(0,j));}else if(c==='<'){if(option.adsafe&&xmode==='xml'){warningAt("ADsafe string violation.",line,character+j);}else if(s.charAt(j+1)==='/'&&((xmode&&xmode!=='CDATA')||option.adsafe)){warningAt("Expected '<\\/' and instead saw '</'.",line,character);}}else if(c==='\\'){if(option.adsafe&&xmode==='xml'){warningAt("ADsafe string violation.",line,character+j);}
+j+=1;character+=1;c=s.charAt(j);switch(c){case'\\':case'\'':case'"':case'/':break;case'b':c='\b';break;case'f':c='\f';break;case'n':c='\n';break;case'r':c='\r';break;case't':c='\t';break;case'u':esc(4);break;case'v':c='\v';break;case'x':if(jsonmode){warningAt("Avoid \\x-.",line,character);}
+esc(2);break;default:warningAt("Bad escapement.",line,character);}}
+r+=c;character+=1;j+=1;}}
+for(;;){if(!s){return it(nextLine()?'(endline)':'(end)','');}
+t=match(tx);if(!t){t='';c='';while(s&&s<'!'){s=s.substr(1);}
+if(s){errorAt("Unexpected '{a}'.",line,character,s.substr(0,1));}}
+if(c.isAlpha()||c==='_'||c==='$'){return it('(identifier)',t);}
+if(c.isDigit()){if(!isFinite(Number(t))){warningAt("Bad number '{a}'.",line,character,t);}
+if(s.substr(0,1).isAlpha()){warningAt("Missing space after '{a}'.",line,character,t);}
+if(c==='0'){d=t.substr(1,1);if(d.isDigit()){warningAt("Don't use extra leading zeros '{a}'.",line,character,t);}else if(jsonmode&&(d==='x'||d==='X')){warningAt("Avoid 0x-. '{a}'.",line,character,t);}}
+if(t.substr(t.length-1)==='.'){warningAt("A trailing decimal point can be confused with a dot '{a}'.",line,character,t);}
+return it('(number)',t);}
+switch(t){case'"':case"'":return string(t);case'//':if(src||(xmode&&!(xmode==='script'||xmode==='CDATA'))){warningAt("Unexpected comment.",line,character);}
+if(option.adsafe&&ax.test(s)){warningAt("ADsafe comment violation.",line,character);}
+s='';break;case'/*':if(src||(xmode&&!(xmode==='script'||xmode==='CDATA'))){warningAt("Unexpected comment.",line,character);}
+if(option.adsafe&&ax.test(s)){warningAt("ADsafe comment violation.",line,character);}
+for(;;){i=s.search(lx);if(i>=0){break;}
+if(!nextLine()){errorAt("Unclosed comment.",line,character);}else{if(option.adsafe&&ax.test(s)){warningAt("ADsafe comment violation.",line,character);}}}
+character+=i+2;if(s.substr(i,1)==='/'){errorAt("Nested comment.",line,character);}
+s=s.substr(i+2);break;case'/*global':case'/*extern':case'/*members':case'/*member':case'/*jslint':case'*/':return{value:t,type:'special',line:line,character:character,from:from};case'':break;case'/':if(prereg){depth=0;captures=0;l=0;for(;;){b=true;c=s.charAt(l);l+=1;switch(c){case'':errorAt("Unclosed regular expression.",line,from);return;case'/':if(depth>0){warningAt("Unescaped '{a}'.",line,from+l,'/');}
+c=s.substr(0,l-1);q={g:true,i:true,m:true};while(q[s.charAt(l)]===true){q[s.charAt(l)]=false;l+=1;}
+character+=l;s=s.substr(l);return it('(regex)',c);case'\\':l+=1;break;case'(':depth+=1;b=false;if(s.charAt(l)==='?'){l+=1;switch(s.charAt(l)){case':':case'=':case'!':l+=1;break;default:warningAt("Expected '{a}' and instead saw '{b}'.",line,from+l,':',s.charAt(l));}}else{captures+=1;}
+break;case')':if(depth===0){warningAt("Unescaped '{a}'.",line,from+l,')');}else{depth-=1;}
+break;case' ':q=1;while(s.charAt(l)===' '){l+=1;q+=1;}
+if(q>1){warningAt("Spaces are hard to count. Use {{a}}.",line,from+l,q);}
+break;case'[':if(s.charAt(l)==='^'){l+=1;}
+q=false;klass:for(;;){c=s.charAt(l);l+=1;switch(c){case'[':case'^':warningAt("Unescaped '{a}'.",line,from+l,c);q=true;break;case'-':if(q){q=false;}else{warningAt("Unescaped '{a}'.",line,from+l,'-');q=true;}
+break;case']':if(!q){warningAt("Unescaped '{a}'.",line,from+l-1,'-');}
+break klass;case'\\':l+=1;q=true;break;default:q=true;}}
+break;case'.':if(option.regexp){warningAt("Unexpected '{a}'.",line,from+l,c);}
+break;case']':case'?':case'{':case'}':case'+':case'*':warningAt("Unescaped '{a}'.",line,from+l,c);break;}
+if(b){switch(s.charAt(l)){case'?':case'+':case'*':l+=1;if(s.charAt(l)==='?'){l+=1;}
+break;case'{':l+=1;c=s.charAt(l);if(c<'0'||c>'9'){warningAt("Expected a number and instead saw '{a}'.",line,from+l,c);}
+l+=1;low=+c;for(;;){c=s.charAt(l);if(c<'0'||c>'9'){break;}
+l+=1;low=+c+(low*10);}
+high=low;if(c===','){l+=1;high=Infinity;c=s.charAt(l);if(c>='0'&&c<='9'){l+=1;high=+c;for(;;){c=s.charAt(l);if(c<'0'||c>'9'){break;}
+l+=1;high=+c+(high*10);}}}
+if(s.charAt(l)!=='}'){warningAt("Expected '{a}' and instead saw '{b}'.",line,from+l,'}',c);}else{l+=1;}
+if(s.charAt(l)==='?'){l+=1;}
+if(low>high){warningAt("'{a}' should not be greater than '{b}'.",line,from+l,low,high);}}}}
+c=s.substr(0,l-1);character+=l;s=s.substr(l);return it('(regex)',c);}
+return it('(punctuator)',t);default:return it('(punctuator)',t);}}},skip:function(p){var i,t=p;if(nexttoken.id){if(!t){t='';if(nexttoken.id.substr(0,1)==='<'){lookahead.push(nexttoken);return true;}}else if(nexttoken.id.indexOf(t)>=0){return true;}}
+token=nexttoken;nexttoken=syntax['(end)'];for(;;){i=s.indexOf(t||'<');if(i>=0){character+=i+t.length;s=s.substr(i+t.length);return true;}
+if(!nextLine()){break;}}
+return false;}};}();function addlabel(t,type){if(t==='hasOwnProperty'){error("'hasOwnProperty' is a really bad name.");}
+if(option.adsafe&&scope===global){warning('ADsafe global: '+t+'.',token);}
+if(funct.hasOwnProperty(t)){warning(funct[t]===true?"'{a}' was used before it was defined.":"'{a}' is already defined.",nexttoken,t);}
+scope[t]=funct;funct[t]=type;if(funct['(global)']&&implied.hasOwnProperty(t)){warning("'{a}' was used before it was defined.",nexttoken,t);delete implied[t];}}
+function doOption(){var b,obj,filter,o=nexttoken.value,t,v;switch(o){case'*/':error("Unbegun comment.");break;case'/*global':case'/*extern':if(option.adsafe){warning("ADsafe restriction.");}
+obj=globals;break;case'/*members':case'/*member':o='/*members';if(!membersOnly){membersOnly={};}
+obj=membersOnly;break;case'/*jslint':if(option.adsafe){warning("ADsafe restriction.");}
+obj=option;filter=allOptions;}
+for(;;){t=lex.token();if(t.id===','){t=lex.token();}
+while(t.id==='(endline)'){t=lex.token();}
+if(t.type==='special'&&t.value==='*/'){break;}
+if(t.type!=='(string)'&&t.type!=='(identifier)'&&o!=='/*members'){error("Bad option.",t);}
+if(filter){if(filter[t.value]!==true){error("Bad option.",t);}
+v=lex.token();if(v.id!==':'){error("Expected '{a}' and instead saw '{b}'.",t,':',t.value);}
+v=lex.token();if(v.value==='true'){b=true;}else if(v.value==='false'){b=false;}else{error("Expected '{a}' and instead saw '{b}'.",t,'true',t.value);}}else{b=true;}
+obj[t.value]=b;}
+if(filter){populateGlobals();}}
+function peek(p){var i=p||0,j=0,t;while(j<=i){t=lookahead[j];if(!t){t=lookahead[j]=lex.token();}
+j+=1;}
+return t;}
+var badbreak={')':true,']':true,'++':true,'--':true};function advance(id,t){var l;switch(token.id){case'(number)':if(nexttoken.id==='.'){warning("A dot following a number can be confused with a decimal point.",token);}
+break;case'-':if(nexttoken.id==='-'||nexttoken.id==='--'){warning("Confusing minusses.");}
+break;case'+':if(nexttoken.id==='+'||nexttoken.id==='++'){warning("Confusing plusses.");}
+break;}
+if(token.type==='(string)'||token.identifier){anonname=token.value;}
+if(id&&nexttoken.id!==id){if(t){if(nexttoken.id==='(end)'){warning("Unmatched '{a}'.",t,t.id);}else{warning("Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.",nexttoken,id,t.id,t.line+1,nexttoken.value);}}else{warning("Expected '{a}' and instead saw '{b}'.",nexttoken,id,nexttoken.value);}}
+prevtoken=token;token=nexttoken;for(;;){nexttoken=lookahead.shift()||lex.token();if(nexttoken.type==='special'){doOption();}else{if(nexttoken.id==='<!['){if(option.adsafe){error("ADsafe violation.",nexttoken);}
+if(xtype==='html'){error("Unexpected '{a}'.",nexttoken,'<![');}
+if(xmode==='script'){nexttoken=lex.token();if(nexttoken.value!=='CDATA'){error("Missing '{a}'.",nexttoken,'CDATA');}
+nexttoken=lex.token();if(nexttoken.id!=='['){error("Missing '{a}'.",nexttoken,'[');}
+xmode='CDATA';}else if(xmode==='xml'){lex.skip(']]>');}else{error("Unexpected '{a}'.",nexttoken,'<![');}}else if(nexttoken.id===']]>'){if(xmode==='CDATA'){xmode='script';}else{error("Unexpected '{a}'.",nexttoken,']]>');}}else if(nexttoken.id!=='(endline)'){break;}
+if(xmode==='"'||xmode==="'"){error("Missing '{a}'.",token,xmode);}
+l=!xmode&&!option.laxbreak&&(token.type==='(string)'||token.type==='(number)'||token.type==='(identifier)'||badbreak[token.id]);}}
+if(l){switch(nexttoken.id){case'{':case'}':case']':break;case')':switch(token.id){case')':case'}':case']':break;default:warning("Line breaking error '{a}'.",token,')');}
+break;default:warning("Line breaking error '{a}'.",token,token.value);}}
+if(xtype==='widget'&&xmode==='script'&&nexttoken.id){l=nexttoken.id.charAt(0);if(l==='<'||l==='&'){nexttoken.nud=nexttoken.led=null;nexttoken.lbp=0;nexttoken.reach=true;}}}
+function parse(rbp,initial){var left,o,p;if(nexttoken.id==='(end)'){error("Unexpected early end of program.",token);}
+advance();if(option.adsafe){p=peek(0);if(adsafe_allow[token.value]===true){if(nexttoken.id!=='.'||!p.identifier||peek(1).id!=='('){warning('ADsafe violation.',token);}}else if(token.value==='Math'){if(nexttoken.id!=='.'||!p.identifier||(math_member[p.value]!==true&&peek(1).id!=='(')){warning('ADsafe violation.',token);}}else if(token.value==='Number'){if(nexttoken.id!=='.'||!p.identifier||number_member[p.value]!==true||peek(1).id==='('){warning('ADsafe violation.',token);}}}
+if(initial){anonname='anonymous';funct['(verb)']=token.value;}
+if(initial===true&&token.fud){left=token.fud();}else{if(token.nud){o=token.exps;left=token.nud();}else{if(nexttoken.type==='(number)'&&token.id==='.'){warning("A leading decimal point can be confused with a dot: '.{a}'.",token,nexttoken.value);advance();return token;}else{error("Expected an identifier and instead saw '{a}'.",token,token.id);}}
+while(rbp<nexttoken.lbp){o=nexttoken.exps;advance();if(token.led){left=token.led(left);}else{error("Expected an operator and instead saw '{a}'.",token,token.id);}}
+if(initial&&!o){warning("Expected an assignment or function call and instead saw an expression.",token);}}
+if(!option.evil&&left&&left.value==='eval'){warning("eval is evil.",left);}
+return left;}
+function adjacent(left,right){left=left||token;right=right||nexttoken;if(option.white){if(left.character!==right.from){warning("Unexpected space after '{a}'.",nexttoken,left.value);}}}
+function nospace(left,right){left=left||token;right=right||nexttoken;if(option.white){if(left.line===right.line){adjacent(left,right);}}}
+function nonadjacent(left,right){left=left||token;right=right||nexttoken;if(option.white){if(left.character===right.from){warning("Missing space after '{a}'.",nexttoken,left.value);}}}
+function indentation(bias){var i;if(option.white&&nexttoken.id!=='(end)'){i=indent+(bias||0);if(nexttoken.from!==i){warning("Expected '{a}' to have an indentation of {b} instead of {c}.",nexttoken,nexttoken.value,i,nexttoken.from);}}}
+function nolinebreak(t){if(t.line!==nexttoken.line){warning("Line breaking error '{a}'.",t,t.id);}}
+function symbol(s,p){var x=syntax[s];if(!x||typeof x!=='object'){syntax[s]=x={id:s,lbp:p,value:s};}
+return x;}
+function delim(s){return symbol(s,0);}
+function stmt(s,f){var x=delim(s);x.identifier=x.reserved=true;x.fud=f;return x;}
+function blockstmt(s,f){var x=stmt(s,f);x.block=true;return x;}
+function reserveName(x){var c=x.id.charAt(0);if((c>='a'&&c<='z')||(c>='A'&&c<='Z')){x.identifier=x.reserved=true;}
+return x;}
+function prefix(s,f){var x=symbol(s,150);reserveName(x);x.nud=(typeof f==='function')?f:function(){if(option.plusplus&&(this.id==='++'||this.id==='--')){warning("Unexpected use of '{a}'.",this,this.id);}
+parse(150);return this;};return x;}
+function type(s,f){var x=delim(s);x.type=s;x.nud=f;return x;}
+function reserve(s,f){var x=type(s,f);x.identifier=x.reserved=true;return x;}
+function reservevar(s){return reserve(s,function(){if(option.adsafe&&this.id==='this'){warning("ADsafe violation.",this);}
+return this;});}
+function infix(s,f,p){var x=symbol(s,p);reserveName(x);x.led=(typeof f==='function')?f:function(left){nonadjacent(prevtoken,token);nonadjacent(token,nexttoken);this.left=left;this.right=parse(p);return this;};return x;}
+function relation(s,f){var x=symbol(s,100);x.led=function(left){nonadjacent(prevtoken,token);nonadjacent(token,nexttoken);var right=parse(100);if((left&&left.id==='NaN')||(right&&right.id==='NaN')){warning("Use the isNaN function to compare with NaN.",this);}else if(f){f.apply(this,[left,right]);}
+this.left=left;this.right=right;return this;};return x;}
+function isPoorRelation(node){return(node.type==='(number)'&&!+node.value)||(node.type==='(string)'&&!node.value)||node.type==='true'||node.type==='false'||node.type==='undefined'||node.type==='null';}
+function assignop(s,f){symbol(s,20).exps=true;return infix(s,function(left){var l;nonadjacent(prevtoken,token);nonadjacent(token,nexttoken);if(option.adsafe){l=left;do{if(adsafe_allow[l.value]===true){warning('ADsafe violation.',l);}
+l=l.left;}while(l);}
+if(left){if(left.id==='.'||left.id==='['){if(left.left.value==='arguments'){warning('Bad assignment.',this);}
+parse(19);return left;}else if(left.identifier&&!left.reserved){parse(19);return left;}
+if(left===syntax['function']){warning("Expected an identifier in an assignment and instead saw a function invocation.",token);}}
+error("Bad assignment.",this);},20);}
+function bitwise(s,f,p){var x=symbol(s,p);reserveName(x);x.led=(typeof f==='function')?f:function(left){if(option.bitwise){warning("Unexpected use of '{a}'.",this,this.id);}
+nonadjacent(prevtoken,token);nonadjacent(token,nexttoken);this.left=left;this.right=parse(p);return this;};return x;}
+function bitwiseassignop(s){symbol(s,20).exps=true;return infix(s,function(left){if(option.bitwise){warning("Unexpected use of '{a}'.",this,this.id);}
+nonadjacent(prevtoken,token);nonadjacent(token,nexttoken);if(left){if(left.id==='.'||left.id==='['||(left.identifier&&!left.reserved)){parse(19);return left;}
+if(left===syntax['function']){warning("Expected an identifier in an assignment, and instead saw a function invocation.",token);}}
+error("Bad assignment.",this);},20);}
+function suffix(s,f){var x=symbol(s,150);x.led=function(left){if(option.plusplus){warning("Unexpected use of '{a}'.",this,this.id);}
+this.left=left;return this;};return x;}
+function optionalidentifier(){if(nexttoken.reserved){warning("Expected an identifier and instead saw '{a}' (a reserved word).",nexttoken,nexttoken.id);}
+if(nexttoken.identifier){advance();return token.value;}}
+function identifier(){var i=optionalidentifier();if(i){return i;}
+if(token.id==='function'&&nexttoken.id==='('){warning("Missing name in function statement.");}else{error("Expected an identifier and instead saw '{a}'.",nexttoken,nexttoken.value);}}
+function reachable(s){var i=0,t;if(nexttoken.id!==';'||noreach){return;}
+for(;;){t=peek(i);if(t.reach){return;}
+if(t.id!=='(endline)'){if(t.id==='function'){warning("Inner functions should be listed at the top of the outer function.",t);break;}
+warning("Unreachable '{a}' after '{b}'.",t,t.value,s);break;}
+i+=1;}}
+function statement(noindent){var i=indent,r,s=scope,t=nexttoken;if(t.id===';'){warning("Unnecessary semicolon.",t);advance(';');return;}
+if(t.identifier&&!t.reserved&&peek().id===':'){advance();advance(':');scope=object(s);addlabel(t.value,'label');if(!nexttoken.labelled){warning("Label '{a}' on {b} statement.",nexttoken,t.value,nexttoken.value);}
+if(jx.test(t.value+':')){warning("Label '{a}' looks like a javascript url.",t,t.value);}
+nexttoken.label=t.value;t=nexttoken;}
+if(!noindent){indentation();}
+r=parse(0,true);if(!t.block){if(nexttoken.id!==';'){warningAt("Missing semicolon.",token.line,token.from+token.value.length);}else{adjacent(token,nexttoken);advance(';');nonadjacent(token,nexttoken);}}
+indent=i;scope=s;return r;}
+function statements(){var a=[];while(!nexttoken.reach&&nexttoken.id!=='(end)'){if(nexttoken.id===';'){warning("Unnecessary semicolon.");advance(';');}else{a.push(statement());}}
+return a;}
+function block(f){var a,b=inblock,s=scope;inblock=f;if(f){scope=object(scope);}
+nonadjacent(token,nexttoken);var t=nexttoken;if(nexttoken.id==='{'){advance('{');if(nexttoken.id!=='}'||token.line!==nexttoken.line){indent+=4;if(!f&&nexttoken.from===indent+4){indent+=4;}
+a=statements();indent-=4;indentation();}
+advance('}',t);}else{warning("Expected '{a}' and instead saw '{b}'.",nexttoken,'{',nexttoken.value);noreach=true;a=[statement()];noreach=false;}
+funct['(verb)']=null;scope=s;inblock=b;return a;}
+function idValue(){return this;}
+function countMember(m){if(membersOnly&&membersOnly[m]!==true){warning("Unexpected /*member '{a}'.",nexttoken,m);}
+if(typeof member[m]==='number'){member[m]+=1;}else{member[m]=1;}}
+function note_implied(token){var name=token.value,line=token.line+1,a=implied[name];if(!a){a=[line];implied[name]=a;}else if(a[a.length-1]!==line){a.push(line);}}
+var xmltype={html:{doBegin:function(n){xtype='html';option.browser=true;populateGlobals();},doTagName:function(n,p){var i,t=xmltype.html.tag[n],x;src=false;if(!t){error("Unrecognized tag '<{a}>'.",nexttoken,n===n.toLowerCase()?n:n+' (capitalization error)');}
+x=t.parent;if(!option.fragment||stack.length!==1||!stack[0].fragment){if(x){if(x.indexOf(' '+p+' ')<0){error("A '<{a}>' must be within '<{b}>'.",token,n,x);}}else{i=stack.length;do{if(i<=0){error("A '<{a}>' must be within '<{b}>'.",token,n,'body');}
+i-=1;}while(stack[i].name!=='body');}}
+return t.empty;},doAttribute:function(n,a){if(!a){warning("Missing attribute name.",token);}
+a=a.toLowerCase();if(n==='script'){if(a==='src'){src=true;return'href';}else if(a==='language'){warning("The 'language' attribute is deprecated.",token);return false;}}else if(n==='style'){if(a==='type'&&option.adsafe){warning("Don't bother with 'type'.",token);}}
+if(href[a]===true){return'href';}
+if(a.slice(0,2)==='on'){if(!option.on){warning("Avoid HTML event handlers.");}
+return'script';}else{return'value';}},doIt:function(n){return n==='script'?'script':n!=='html'&&xmltype.html.tag[n].special&&'special';},tag:{a:{},abbr:{},acronym:{},address:{},applet:{},area:{empty:true,parent:' map '},b:{},base:{empty:true,parent:' head '},bdo:{},big:{},blockquote:{},body:{parent:' html noframes '},br:{empty:true},button:{},canvas:{parent:' body p div th td '},caption:{parent:' table '},center:{},cite:{},code:{},col:{empty:true,parent:' table colgroup '},colgroup:{parent:' table '},dd:{parent:' dl '},del:{},dfn:{},dir:{},div:{},dl:{},dt:{parent:' dl '},em:{},embed:{},fieldset:{},font:{},form:{},frame:{empty:true,parent:' frameset '},frameset:{parent:' html frameset '},h1:{},h2:{},h3:{},h4:{},h5:{},h6:{},head:{parent:' html '},html:{},hr:{empty:true},i:{},iframe:{},img:{empty:true},input:{empty:true},ins:{},kbd:{},label:{},legend:{parent:' fieldset '},li:{parent:' dir menu ol ul '},link:{empty:true,parent:' head '},map:{},menu:{},meta:{empty:true,parent:' head noframes noscript '},noframes:{parent:' html body '},noscript:{parent:' body head noframes '},object:{},ol:{},optgroup:{parent:' select '},option:{parent:' optgroup select '},p:{},param:{empty:true,parent:' applet object '},pre:{},q:{},samp:{},script:{parent:' body div frame head iframe p pre span '},select:{},small:{},span:{},strong:{},style:{parent:' head ',special:true},sub:{},sup:{},table:{},tbody:{parent:' table '},td:{parent:' tr '},textarea:{},tfoot:{parent:' table '},th:{parent:' tr '},thead:{parent:' table '},title:{parent:' head '},tr:{parent:' table tbody thead tfoot '},tt:{},u:{},ul:{},'var':{}}},widget:{doBegin:function(n){xtype='widget';option.widget=true;option.cap=true;populateGlobals();},doTagName:function(n,p){var t=xmltype.widget.tag[n];if(!t){error("Unrecognized tag '<{a}>'.",nexttoken,n);}
+var x=t.parent;if(x.indexOf(' '+p+' ')<0){error("A '<{a}>' must be within '<{b}>'.",token,n,x);}},doAttribute:function(n,a){var t=xmltype.widget.tag[a];if(!t){error("Unrecognized attribute '<{a} {b}>'.",nexttoken,n,a);}
+var x=t.parent;if(x.indexOf(' '+n+' ')<0){error("Attribute '{a}' does not belong in '<{b}>'.",nexttoken,a,n);}
+return t.script?'script':a==='name'&&n!=='setting'?'define':'string';},doIt:function(n){var x=xmltype.widget.tag[n];return x&&x.script&&'script';},tag:{"about-box":{parent:' widget '},"about-image":{parent:' about-box '},"about-text":{parent:' about-box '},"about-version":{parent:' about-box '},action:{parent:' widget ',script:true},alignment:{parent:' canvas frame image scrollbar text textarea window '},anchorstyle:{parent:' text '},author:{parent:' widget '},autohide:{parent:' scrollbar '},beget:{parent:' canvas frame image scrollbar text window '},bgcolor:{parent:' text textarea '},bgcolour:{parent:' text textarea '},bgopacity:{parent:' text textarea '},canvas:{parent:' frame window '},charset:{parent:' script '},checked:{parent:' image menuitem '},cliprect:{parent:' image '},color:{parent:' about-text about-version shadow text textarea '},colorize:{parent:' image '},colour:{parent:' about-text about-version shadow text textarea '},columns:{parent:' textarea '},company:{parent:' widget '},contextmenuitems:{parent:' canvas frame image scrollbar text textarea window '},copyright:{parent:' widget '},data:{parent:' about-text about-version text textarea '},debug:{parent:' widget '},defaultvalue:{parent:' preference '},defaulttracking:{parent:' widget '},description:{parent:' preference '},directory:{parent:' preference '},editable:{parent:' textarea '},enabled:{parent:' menuitem '},extension:{parent:' preference '},file:{parent:' action preference '},fillmode:{parent:' image '},font:{parent:' about-text about-version text textarea '},fontstyle:{parent:' textarea '},frame:{parent:' frame window '},group:{parent:' preference '},halign:{parent:' canvas frame image scrollbar text textarea '},handlelinks:{parent:' textarea '},height:{parent:' canvas frame image scrollbar text textarea window '},hidden:{parent:' preference '},hlinesize:{parent:' frame '},hoffset:{parent:' about-text about-version canvas frame image scrollbar shadow text textarea window '},hotkey:{parent:' widget '},hregistrationpoint:{parent:' canvas frame image scrollbar text '},hscrollbar:{parent:' frame '},hsladjustment:{parent:' image '},hsltinting:{parent:' image '},icon:{parent:' preferencegroup '},id:{parent:' canvas frame hotkey image preference text textarea timer scrollbar widget window '},image:{parent:' about-box frame window widget '},interval:{parent:' action timer '},key:{parent:' hotkey '},kind:{parent:' preference '},level:{parent:' window '},lines:{parent:' textarea '},loadingsrc:{parent:' image '},locked:{parent:' window '},max:{parent:' scrollbar '},maxlength:{parent:' preference '},menuitem:{parent:' contextmenuitems '},min:{parent:' scrollbar '},minimumversion:{parent:' widget '},minlength:{parent:' preference '},missingsrc:{parent:' image '},modifier:{parent:' hotkey '},name:{parent:' canvas frame hotkey image preference preferencegroup scrollbar setting text textarea timer widget window '},notsaved:{parent:' preference '},onclick:{parent:' canvas frame image scrollbar text textarea ',script:true},oncontextmenu:{parent:' canvas frame image scrollbar text textarea window ',script:true},ondragdrop:{parent:' canvas frame image scrollbar text textarea ',script:true},ondragenter:{parent:' canvas frame image scrollbar text textarea ',script:true},ondragexit:{parent:' canvas frame image scrollbar text textarea ',script:true},onfirstdisplay:{parent:' window ',script:true},ongainfocus:{parent:' textarea window ',script:true},onkeydown:{parent:' hotkey text textarea window ',script:true},onkeypress:{parent:' textarea window ',script:true},onkeyup:{parent:' hotkey text textarea window ',script:true},onimageloaded:{parent:' image ',script:true},onlosefocus:{parent:' textarea window ',script:true},onmousedown:{parent:' canvas frame image scrollbar text textarea window ',script:true},onmousedrag:{parent:' canvas frame image scrollbar text textarea window ',script:true},onmouseenter:{parent:' canvas frame image scrollbar text textarea window ',script:true},onmouseexit:{parent:' canvas frame image scrollbar text textarea window ',script:true},onmousemove:{parent:' canvas frame image scrollbar text textarea window ',script:true},onmouseup:{parent:' canvas frame image scrollbar text textarea window ',script:true},onmousewheel:{parent:' frame ',script:true},onmulticlick:{parent:' canvas frame image scrollbar text textarea window ',script:true},onselect:{parent:' menuitem ',script:true},ontextinput:{parent:' window ',script:true},ontimerfired:{parent:' timer ',script:true},onvaluechanged:{parent:' scrollbar ',script:true},opacity:{parent:' canvas frame image scrollbar shadow text textarea window '},option:{parent:' preference widget '},optionvalue:{parent:' preference '},order:{parent:' preferencegroup '},orientation:{parent:' scrollbar '},pagesize:{parent:' scrollbar '},preference:{parent:' widget '},preferencegroup:{parent:' widget '},remoteasync:{parent:' image '},requiredplatform:{parent:' widget '},root:{parent:' window '},rotation:{parent:' canvas frame image scrollbar text '},script:{parent:' widget ',script:true},scrollbar:{parent:' frame text textarea window '},scrolling:{parent:' text '},scrollx:{parent:' frame '},scrolly:{parent:' frame '},secure:{parent:' preference textarea '},setting:{parent:' settings '},settings:{parent:' widget '},shadow:{parent:' about-text about-version text window '},size:{parent:' about-text about-version text textarea '},spellcheck:{parent:' textarea '},src:{parent:' image script '},srcheight:{parent:' image '},srcwidth:{parent:' image '},style:{parent:' about-text about-version canvas frame image preference scrollbar text textarea window '},subviews:{parent:' frame '},superview:{parent:' canvas frame image scrollbar text textarea '},text:{parent:' frame text textarea window '},textarea:{parent:' frame window '},timer:{parent:' widget '},thumbcolor:{parent:' scrollbar textarea '},ticking:{parent:' timer '},ticks:{parent:' preference '},ticklabel:{parent:' preference '},tileorigin:{parent:' image '},title:{parent:' menuitem preference preferencegroup window '},tooltip:{parent:' frame image text textarea '},tracking:{parent:' canvas image '},trigger:{parent:' action '},truncation:{parent:' text '},type:{parent:' preference '},url:{parent:' about-box about-text about-version '},usefileicon:{parent:' image '},valign:{parent:' canvas frame image scrollbar text textarea '},value:{parent:' preference scrollbar setting '},version:{parent:' widget '},visible:{parent:' canvas frame image scrollbar text textarea window '},vlinesize:{parent:' frame '},voffset:{parent:' about-text about-version canvas frame image scrollbar shadow text textarea window '},vregistrationpoint:{parent:' canvas frame image scrollbar text '},vscrollbar:{parent:' frame '},width:{parent:' canvas frame image scrollbar text textarea window '},window:{parent:' canvas frame image scrollbar text textarea widget '},wrap:{parent:' text '},zorder:{parent:' canvas frame image scrollbar text textarea window '}}}};function xmlword(tag){var w=nexttoken.value;if(!nexttoken.identifier){if(nexttoken.id==='<'){if(tag){error("Expected '{a}' and instead saw '{b}'.",token,'&lt;','<');}else{error("Missing '{a}'.",token,'>');}}else if(nexttoken.id==='(end)'){error("Bad structure.");}else{warning("Missing quote.",token);}}
+advance();while(nexttoken.id==='-'||nexttoken.id===':'){w+=nexttoken.id;advance();if(!nexttoken.identifier){error("Bad name '{a}'.",nexttoken,w+nexttoken.value);}
+w+=nexttoken.value;advance();}
+if(option.cap){w=w.toLowerCase();}
+return w;}
+function closetag(n){return'</'+n+'>';}
+function xml(){var a,e,n,q,t,wmode;xmode='xml';stack=null;for(;;){switch(nexttoken.value){case'<':if(!stack){stack=[];}
+advance('<');t=nexttoken;n=xmlword(true);t.name=n;if(!xtype){if(option.fragment&&option.adsafe&&n!=='div'&&n!=='iframe'){error("ADsafe HTML fragment violation.",token);}
+if(xmltype[n]){xmltype[n].doBegin();n=xtype;e=false;}else{if(option.fragment){xmltype.html.doBegin();}else{error("Unrecognized tag '<{a}>'.",nexttoken,n);}}}else{if(stack.length===0){error("What the hell is this?");}
+e=xmltype[xtype].doTagName(n,stack[stack.length-1].name);}
+t.type=n;for(;;){if(nexttoken.id==='/'){advance('/');if(nexttoken.id!=='>'){warning("Expected '{a}' and instead saw '{b}'.",nexttoken,'>',nexttoken.value);}
+e=true;break;}
+if(nexttoken.id&&nexttoken.id.substr(0,1)==='>'){break;}
+a=xmlword();switch(xmltype[xtype].doAttribute(n,a)){case'script':xmode='string';advance('=');q=nexttoken.id;if(q!=='"'&&q!=="'"){error("Missing quote.");}
+xmode=q;wmode=option.white;option.white=false;advance(q);statements();option.white=wmode;if(nexttoken.id!==q){error("Missing close quote on script attribute.");}
+xmode='xml';advance(q);break;case'value':advance('=');if(!nexttoken.identifier&&nexttoken.type!=='(string)'&&nexttoken.type!=='(number)'){error("Bad value '{a}'.",nexttoken,nexttoken.value);}
+advance();break;case'string':advance('=');if(nexttoken.type!=='(string)'){error("Bad value '{a}'.",nexttoken,nexttoken.value);}
+advance();break;case'href':advance('=');if(nexttoken.type!=='(string)'){error("Bad value '{a}'.",nexttoken,nexttoken.value);}
+if(option.adsafe&&ux.test(nexttoken.value)){error("ADsafe URL violation.");}
+advance();break;case'define':advance('=');if(nexttoken.type!=='(string)'){error("Bad value '{a}'.",nexttoken,nexttoken.value);}
+addlabel(nexttoken.value,'var');advance();break;default:if(nexttoken.id==='='){advance('=');if(!nexttoken.identifier&&nexttoken.type!=='(string)'&&nexttoken.type!=='(number)'){error("Bad value '{a}'.",nexttoken,nexttoken.value);}
+advance();}}}
+switch(xmltype[xtype].doIt(n)){case'script':xmode='script';advance('>');indent=nexttoken.from;if(src){if(option.fragment&&option.adsafe){warning("ADsafe script violation.",token);}}else{statements();}
+if(nexttoken.id!=='</'&&nexttoken.id!=='(end)'){warning("Expected '{a}' and instead saw '{b}'.",nexttoken,'<\/script>',nexttoken.value);}
+xmode='xml';break;case'special':e=true;n=closetag(t.name);if(!lex.skip(n)){error("Missing '{a}'.",t,n);}
+break;default:lex.skip('>');}
+if(!e){stack.push(t);}
+break;case'</':advance('</');n=xmlword(true);t=stack.pop();if(!t){error("Unexpected '{a}'.",nexttoken,closetag(n));}
+if(t.name!==n){error("Expected '{a}' and instead saw '{b}'.",nexttoken,closetag(t.name),closetag(n));}
+if(nexttoken.id!=='>'){error("Missing '{a}'.",nexttoken,'>');}
+if(stack.length>0){lex.skip('>');}else{advance('>');}
+break;case'<!':if(option.adsafe){error("ADsafe HTML violation.");}
+for(;;){advance();if(nexttoken.id==='>'){break;}
+if(nexttoken.id==='<'||nexttoken.id==='(end)'){error("Missing '{a}'.",token,'>');}}
+lex.skip('>');break;case'<!--':if(option.adsafe){error("ADsafe comment violation.");}
+lex.skip('-->');break;case'<%':if(option.adsafe){error("ADsafe HTML violation.");}
+lex.skip('%>');break;case'<?':if(option.adsafe){error("ADsafe HTML violation.");}
+for(;;){advance();if(nexttoken.id==='?>'){break;}
+if(nexttoken.id==='<?'||nexttoken.id==='<'||nexttoken.id==='>'||nexttoken.id==='(end)'){error("Missing '{a}'.",token,'?>');}}
+lex.skip('?>');break;case'<=':case'<<':case'<<=':error("Missing '{a}'.",nexttoken,'&lt;');break;case'(end)':return;}
+if(stack&&stack.length===0){return;}
+if(!lex.skip('')){if(!stack){error("Bad XML.");}
+t=stack.pop();if(t.value){error("Missing '{a}'.",t,closetag(t.name));}else{return;}}
+advance();}}
+type('(number)',idValue);type('(string)',idValue);syntax['(identifier)']={type:'(identifier)',lbp:0,identifier:true,nud:function(){var v=this.value,s=scope[v];if(s&&(s===funct||s===funct['(global)'])){if(!funct['(global)']){switch(funct[v]){case'unused':funct[v]='var';break;case'label':warning("'{a}' is a statement label.",token,v);break;}}}else if(funct['(global)']){if(option.undef){warning("'{a}' is undefined.",token,v);}
+note_implied(token);}else{switch(funct[v]){case'closure':case'function':case'var':case'unused':warning("'{a}' used out of scope.",token,v);break;case'label':warning("'{a}' is a statement label.",token,v);break;case'outer':case true:break;default:if(s===true){funct[v]=true;}else if(typeof s!=='object'){if(option.undef){warning("'{a}' is undefined.",token,v);}else{funct[v]=true;}
+note_implied(token);}else{switch(s[v]){case'function':case'var':case'unused':s[v]='closure';funct[v]='outer';break;case'closure':case'parameter':funct[v]='outer';break;case'label':warning("'{a}' is a statement label.",token,v);}}}}
+return this;},led:function(){error("Expected an operator and instead saw '{a}'.",nexttoken,nexttoken.value);}};type('(regex)',function(){return this;});delim('(endline)');delim('(begin)');delim('(end)').reach=true;delim('</').reach=true;delim('<![').reach=true;delim('<%');delim('<?');delim('<!');delim('<!--');delim('%>');delim('?>');delim('(error)').reach=true;delim('}').reach=true;delim(')');delim(']');delim(']]>').reach=true;delim('"').reach=true;delim("'").reach=true;delim(';');delim(':').reach=true;delim(',');reserve('else');reserve('case').reach=true;reserve('catch');reserve('default').reach=true;reserve('finally');reservevar('arguments');reservevar('eval');reservevar('false');reservevar('Infinity');reservevar('NaN');reservevar('null');reservevar('this');reservevar('true');reservevar('undefined');assignop('=','assign',20);assignop('+=','assignadd',20);assignop('-=','assignsub',20);assignop('*=','assignmult',20);assignop('/=','assigndiv',20).nud=function(){error("A regular expression literal can be confused with '/='.");};assignop('%=','assignmod',20);bitwiseassignop('&=','assignbitand',20);bitwiseassignop('|=','assignbitor',20);bitwiseassignop('^=','assignbitxor',20);bitwiseassignop('<<=','assignshiftleft',20);bitwiseassignop('>>=','assignshiftright',20);bitwiseassignop('>>>=','assignshiftrightunsigned',20);infix('?',function(left){parse(10);advance(':');parse(10);},30);infix('||','or',40);infix('&&','and',50);bitwise('|','bitor',70);bitwise('^','bitxor',80);bitwise('&','bitand',90);relation('==',function(left,right){if(option.eqeqeq){warning("Expected '{a}' and instead saw '{b}'.",this,'===','==');}else if(isPoorRelation(left)){warning("Use '{a}' to compare with '{b}'.",this,'===',left.value);}else if(isPoorRelation(right)){warning("Use '{a}' to compare with '{b}'.",this,'===',right.value);}
+return this;});relation('===');relation('!=',function(left,right){if(option.eqeqeq){warning("Expected '{a}' and instead saw '{b}'.",this,'!==','!=');}else if(isPoorRelation(left)){warning("Use '{a}' to compare with '{b}'.",this,'!==',left.value);}else if(isPoorRelation(right)){warning("Use '{a}' to compare with '{b}'.",this,'!==',right.value);}
+return this;});relation('!==');relation('<');relation('>');relation('<=');relation('>=');bitwise('<<','shiftleft',120);bitwise('>>','shiftright',120);bitwise('>>>','shiftrightunsigned',120);infix('in','in',120);infix('instanceof','instanceof',120);infix('+',function(left){nonadjacent(prevtoken,token);nonadjacent(token,nexttoken);var right=parse(130);if(left&&right&&left.id==='(string)'&&right.id==='(string)'){left.value+=right.value;left.character=right.character;if(jx.test(left.value)){warning("JavaScript URL.",left);}
+return left;}
+this.left=left;this.right=right;return this;},130);prefix('+','num');infix('-','sub',130);prefix('-','neg');infix('*','mult',140);infix('/','div',140);infix('%','mod',140);suffix('++','postinc');prefix('++','preinc');syntax['++'].exps=true;suffix('--','postdec');prefix('--','predec');syntax['--'].exps=true;prefix('delete',function(){var p=parse(0);if(p.id!=='.'&&p.id!=='['){warning("Expected '{a}' and instead saw '{b}'.",nexttoken,'.',nexttoken.value);}}).exps=true;prefix('~',function(){if(option.bitwise){warning("Unexpected '{a}'.",this,'~');}
+parse(150);return this;});prefix('!','not');prefix('typeof','typeof');prefix('new',function(){var c=parse(155),i;if(c){if(c.identifier){c['new']=true;switch(c.value){case'Object':warning("Use the object literal notation {}.",token);break;case'Array':warning("Use the array literal notation [].",token);break;case'Number':case'String':case'Boolean':case'Math':warning("Do not use the {a} function as a constructor.",token,c.value);break;case'Function':if(!option.evil){warning("The Function constructor is eval.");}
+break;default:if(c.id!=='function'){i=c.value.substr(0,1);if(i<'A'||i>'Z'){warning("A constructor name should start with an uppercase letter.",token);}}}}else{if(c.id!=='.'&&c.id!=='['&&c.id!=='('){warning("Bad constructor.",token);}}}else{warning("Weird construction. Delete 'new'.",this);}
+adjacent(token,nexttoken);if(nexttoken.id==='('){advance('(');nospace();if(nexttoken.id!==')'){for(;;){parse(10);if(nexttoken.id!==','){break;}
+advance(',');}}
+advance(')');nospace(prevtoken,token);}else{warning("Missing '()' invoking a constructor.");}
+return syntax['function'];});syntax['new'].exps=true;infix('.',function(left){adjacent(prevtoken,token);var m=identifier();if(typeof m==='string'){countMember(m);}
+if(option.adsafe&&adsafe[m]===true){warning("ADsafe restricted word '{a}'.",this,m);}
+if(!option.evil&&left&&left.value==='document'&&(m==='write'||m==='writeln')){warning("document.write can be a form of eval.",left);}
+this.left=left;this.right=m;return this;},160);infix('(',function(left){adjacent(prevtoken,token);nospace();var n=0;var p=[];if(left&&left.type==='(identifier)'){if(left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)){if(left.value!=='Number'&&left.value!=='String'&&left.value!=='Boolean'&&left.value!=='Date'){if(left.value==='Math'){warning("Math is not a function.",left);}else{warning("Missing 'new' prefix when invoking a constructor.",left);}}}}
+if(nexttoken.id!==')'){for(;;){p[p.length]=parse(10);n+=1;if(nexttoken.id!==','){break;}
+advance(',');nonadjacent(token,nexttoken);}}
+advance(')');nospace(prevtoken,token);if(typeof left==='object'){if(left.value==='parseInt'&&n===1){warning("Missing radix parameter.",left);}
+if(!option.evil){if(left.value==='eval'||left.value==='Function'){warning("eval is evil.",left);}else if(p[0]&&p[0].id==='(string)'&&(left.value==='setTimeout'||left.value==='setInterval')){warning("Implied eval is evil. Pass a function instead of a string.",left);}}
+if(!left.identifier&&left.id!=='.'&&left.id!=='['&&left.id!=='('&&left.id!=='&&'&&left.id!=='||'&&left.id!=='?'){warning("Bad invocation.",left);}}
+return syntax['function'];},155).exps=true;prefix('(',function(){nospace();var v=parse(0);advance(')',this);nospace(prevtoken,token);return v;});infix('[',function(left){if(option.adsafe){warning('ADsafe subscripting.');}
+nospace();var e=parse(0),s;if(e&&e.type==='(string)'){countMember(e.value);if(ix.test(e.value)){s=syntax[e.value];if(!s||!s.reserved){warning("['{a}'] is better written in dot notation.",e,e.value);}}}
+advance(']',this);nospace(prevtoken,token);this.left=left;this.right=e;return this;},160);prefix('[',function(){if(nexttoken.id===']'){advance(']');return;}
+var b=token.line!==nexttoken.line;if(b){indent+=4;if(nexttoken.from===indent+4){indent+=4;}}
+for(;;){if(b&&token.line!==nexttoken.line){indentation();}
+parse(10);if(nexttoken.id===','){adjacent(token,nexttoken);advance(',');if(nexttoken.id===','||nexttoken.id===']'){warning("Extra comma.",token);}
+nonadjacent(token,nexttoken);}else{if(b){indent-=4;indentation();}
+advance(']',this);return;}}},160);(function(x){x.nud=function(){var i,s;if(nexttoken.id==='}'){advance('}');return;}
+var b=token.line!==nexttoken.line;if(b){indent+=4;if(nexttoken.from===indent+4){indent+=4;}}
+for(;;){if(b){indentation();}
+i=optionalidentifier(true);if(!i){if(nexttoken.id==='(string)'){i=nexttoken.value;if(ix.test(i)){s=syntax[i];}
+advance();}else if(nexttoken.id==='(number)'){i=nexttoken.value.toString();advance();}else{error("Expected '{a}' and instead saw '{b}'.",nexttoken,'}',nexttoken.value);}}
+countMember(i);advance(':');nonadjacent(token,nexttoken);parse(10);if(nexttoken.id===','){adjacent(token,nexttoken);advance(',');if(nexttoken.id===','||nexttoken.id==='}'){warning("Extra comma.",token);}
+nonadjacent(token,nexttoken);}else{if(b){indent-=4;indentation();}
+advance('}',this);return;}}};x.fud=function(){error("Expected to see a statement and instead saw a block.",token);};})(delim('{'));function varstatement(){for(;;){nonadjacent(token,nexttoken);addlabel(identifier(),'unused');if(nexttoken.id==='='){nonadjacent(token,nexttoken);advance('=');nonadjacent(token,nexttoken);if(peek(0).id==='='){error("Variable {a} was not declared correctly.",nexttoken,nexttoken.value);}
+parse(20);}
+if(nexttoken.id!==','){return;}
+adjacent(token,nexttoken);advance(',');nonadjacent(token,nexttoken);}}
+stmt('var',varstatement);stmt('new',function(){error("'new' should not be used as a statement.");});function functionparams(){var i,t=nexttoken,p=[];advance('(');nospace();if(nexttoken.id===')'){advance(')');nospace(prevtoken,token);return;}
+for(;;){i=identifier();p.push(i);addlabel(i,'parameter');if(nexttoken.id===','){advance(',');nonadjacent(token,nexttoken);}else{advance(')',t);nospace(prevtoken,token);return p.join(', ');}}}
+function doFunction(i){var s=scope;scope=object(s);funct={'(name)':i||'"'+anonname+'"','(line)':nexttoken.line+1,'(context)':funct,'(breakage)':0,'(scope)':scope};functions.push(funct);if(i){addlabel(i,'function');}
+funct['(params)']=functionparams();block(false);scope=s;funct=funct['(context)'];}
+blockstmt('function',function(){if(inblock){warning("Function statements cannot be placed in blocks. Use a function expression or move the statement to the top of the outer function.",token);}
+var i=identifier();adjacent(token,nexttoken);addlabel(i,'unused');doFunction(i);if(nexttoken.id==='('&&nexttoken.line===token.line){error("Function statements are not invocable. Wrap the function expression in parens.");}});prefix('function',function(){var i=optionalidentifier();if(i){adjacent(token,nexttoken);}else{nonadjacent(token,nexttoken);}
+doFunction(i);});blockstmt('if',function(){var t=nexttoken;advance('(');nonadjacent(this,t);nospace();parse(20);if(nexttoken.id==='='){warning("Expected a conditional expression and instead saw an assignment.");advance('=');parse(20);}
+advance(')',t);nospace(prevtoken,token);block(true);if(nexttoken.id==='else'){nonadjacent(token,nexttoken);advance('else');if(nexttoken.id==='if'||nexttoken.id==='switch'){statement(true);}else{block(true);}}
+return this;});blockstmt('try',function(){var b,e,s;block(false);if(nexttoken.id==='catch'){advance('catch');nonadjacent(token,nexttoken);advance('(');s=scope;scope=object(s);e=nexttoken.value;if(nexttoken.type!=='(identifier)'){warning("Expected an identifier and instead saw '{a}'.",nexttoken,e);}else{addlabel(e,'unused');}
+advance();advance(')');block(false);b=true;scope=s;}
+if(nexttoken.id==='finally'){advance('finally');block(false);return;}else if(!b){error("Expected '{a}' and instead saw '{b}'.",nexttoken,'catch',nexttoken.value);}});blockstmt('while',function(){var t=nexttoken;funct['(breakage)']+=1;advance('(');nonadjacent(this,t);nospace();parse(20);if(nexttoken.id==='='){warning("Expected a conditional expression and instead saw an assignment.");advance('=');parse(20);}
+advance(')',t);nospace(prevtoken,token);block(true);funct['(breakage)']-=1;}).labelled=true;reserve('with');blockstmt('switch',function(){var t=nexttoken;var g=false;funct['(breakage)']+=1;advance('(');nonadjacent(this,t);nospace();this.condition=parse(20);advance(')',t);nospace(prevtoken,token);nonadjacent(token,nexttoken);t=nexttoken;advance('{');nonadjacent(token,nexttoken);indent+=4;this.cases=[];for(;;){switch(nexttoken.id){case'case':switch(funct['(verb)']){case'break':case'case':case'continue':case'return':case'switch':case'throw':break;default:warning("Expected a 'break' statement before 'case'.",token);}
+indentation(-4);advance('case');this.cases.push(parse(20));g=true;advance(':');funct['(verb)']='case';break;case'default':switch(funct['(verb)']){case'break':case'continue':case'return':case'throw':break;default:warning("Expected a 'break' statement before 'default'.",token);}
+indentation(-4);advance('default');g=true;advance(':');break;case'}':indent-=4;indentation();advance('}',t);if(this.cases.length===1||this.condition.id==='true'||this.condition.id==='false'){warning("This 'switch' should be an 'if'.",this);}
+funct['(breakage)']-=1;return;case'(end)':error("Missing '{a}'.",nexttoken,'}');return;default:if(g){switch(token.id){case',':error("Each value should have its own case label.");return;case':':statements();break;default:error("Missing ':' on a case clause.",token);}}else{error("Expected '{a}' and instead saw '{b}'.",nexttoken,'case',nexttoken.value);}}}}).labelled=true;stmt('debugger',function(){if(!option.debug){warning("All 'debugger' statements should be removed.");}});stmt('do',function(){funct['(breakage)']+=1;block(true);advance('while');var t=nexttoken;nonadjacent(token,t);advance('(');nospace();parse(20);if(nexttoken.id==='='){warning("Expected a conditional expression and instead saw an assignment.");advance('=');parse(20);}
+advance(')',t);nospace(prevtoken,token);funct['(breakage)']-=1;}).labelled=true;blockstmt('for',function(){var s,t=nexttoken;funct['(breakage)']+=1;advance('(');nonadjacent(this,t);nospace();if(peek(nexttoken.id==='var'?1:0).id==='in'){if(nexttoken.id==='var'){advance('var');addlabel(identifier(),'var');}else{advance();}
+advance('in');parse(20);advance(')',t);if(nexttoken.id==='if'){nolinebreak(token);statement(true);}else{s=block(true);if(!option.forin&&(s.length>1||typeof s[0]!=='object'||s[0].value!=='if')){warning("The body of a for in should be wrapped in an if statement to filter unwanted properties from the prototype.",this);}}
+funct['(breakage)']-=1;return this;}else{if(nexttoken.id!==';'){if(nexttoken.id==='var'){advance('var');varstatement();}else{for(;;){parse(0,'for');if(nexttoken.id!==','){break;}
+advance(',');}}}
+advance(';');if(nexttoken.id!==';'){parse(20);if(nexttoken.id==='='){warning("Expected a conditional expression and instead saw an assignment.");advance('=');parse(20);}}
+advance(';');if(nexttoken.id===';'){error("Expected '{a}' and instead saw '{b}'.",nexttoken,')',';');}
+if(nexttoken.id!==')'){for(;;){parse(0,'for');if(nexttoken.id!==','){break;}
+advance(',');}}
+advance(')',t);nospace(prevtoken,token);block(true);funct['(breakage)']+=1;}}).labelled=true;stmt('break',function(){var v=nexttoken.value;if(funct['(breakage)']===0){warning("Unexpected '{a}'.",nexttoken,this.value);}
+nolinebreak(this);if(nexttoken.id!==';'){if(funct[v]!=='label'){warning("'{a}' is not a statement label.",nexttoken,v);}else if(scope[v]!==funct){warning("'{a}' is out of scope.",nexttoken,v);}
+advance();}
+reachable('break');});stmt('continue',function(){var v=nexttoken.value;nolinebreak(this);if(nexttoken.id!==';'){if(funct[v]!=='label'){warning("'{a}' is not a statement label.",nexttoken,v);}else if(scope[v]!==funct){warning("'{a}' is out of scope.",nexttoken,v);}
+advance();}
+reachable('continue');});stmt('return',function(){nolinebreak(this);if(nexttoken.id!==';'&&!nexttoken.reach){nonadjacent(token,nexttoken);parse(20);}
+reachable('return');});stmt('throw',function(){nolinebreak(this);nonadjacent(token,nexttoken);parse(20);reachable('throw');});reserve('abstract');reserve('boolean');reserve('byte');reserve('char');reserve('class');reserve('const');reserve('double');reserve('enum');reserve('export');reserve('extends');reserve('final');reserve('float');reserve('goto');reserve('implements');reserve('import');reserve('int');reserve('interface');reserve('long');reserve('native');reserve('package');reserve('private');reserve('protected');reserve('public');reserve('short');reserve('static');reserve('super');reserve('synchronized');reserve('throws');reserve('transient');reserve('void');reserve('volatile');function jsonValue(){function jsonObject(){var t=nexttoken;advance('{');if(nexttoken.id!=='}'){for(;;){if(nexttoken.id==='(end)'){error("Missing '}' to match '{' from line {a}.",nexttoken,t.line+1);}else if(nexttoken.id==='}'){warning("Unexpected comma.",token);break;}else if(nexttoken.id===','){error("Unexpected comma.",nexttoken);}else if(nexttoken.id!=='(string)'){warning("Expected a string and instead saw {a}.",nexttoken,nexttoken.value);}
+advance();advance(':');jsonValue();if(nexttoken.id!==','){break;}
+advance(',');}}
+advance('}');}
+function jsonArray(){var t=nexttoken;advance('[');if(nexttoken.id!==']'){for(;;){if(nexttoken.id==='(end)'){error("Missing ']' to match '[' from line {a}.",nexttoken,t.line+1);}else if(nexttoken.id===']'){warning("Unexpected comma.",token);break;}else if(nexttoken.id===','){error("Unexpected comma.",nexttoken);}
+jsonValue();if(nexttoken.id!==','){break;}
+advance(',');}}
+advance(']');}
+switch(nexttoken.id){case'{':jsonObject();break;case'[':jsonArray();break;case'true':case'false':case'null':case'(number)':case'(string)':advance();break;case'-':advance('-');if(token.character!==nexttoken.from){warning("Unexpected space after '-'.",token);}
+adjacent(token,nexttoken);advance('(number)');break;default:error("Expected a JSON value.",nexttoken);}}
+var itself=function(s,o,a){if(o){if(o.adsafe){o.browser=false;o.debug=false;o.eqeqeq=true;o.evil=false;o.forin=false;o.nomen=true;o.on=false;o.rhino=false;o.sidebar=false;o.undef=true;o.widget=false;}
+option=o;}else{option={};}
+adsafe_allow=a||{ADSAFE:true};globals=option.adsafe?{Math:true,Number:true}:object(standard);JSLINT.errors=[];global=object(globals);scope=global;funct={'(global)':true,'(name)':'(global)','(scope)':scope};functions=[];src=false;xmode=false;xtype='';stack=null;member={};membersOnly=null;implied={};inblock=false;lookahead=[];indent=0;jsonmode=false;warnings=0;lex.init(s);prereg=true;prevtoken=token=nexttoken=syntax['(begin)'];populateGlobals();try{advance();if(nexttoken.value.charAt(0)==='<'){xml();}else if(nexttoken.id==='{'||nexttoken.id==='['){option.laxbreak=true;jsonmode=true;jsonValue();}else{statements();}
+advance('(end)');}catch(e){if(e){JSLINT.errors.push({reason:e.message,line:e.line||nexttoken.line,character:e.character||nexttoken.from},null);}}
+return JSLINT.errors.length===0;};function to_array(o){var a=[],k;for(k in o)if(o.hasOwnProperty(k)){a.push(k);}
+return a;}
+itself.report=function(option){var a=[],c,e,f,i,k,l,m='',n,o=[],s,v,cl,va,un,ou,gl,la;function detail(h,s){if(s.length){o.push('<div><i>'+h+'</i> '+
+s.sort().join(', ')+'</div>');}}
+s=to_array(implied);k=JSLINT.errors.length;if(k||s.length>0){o.push('<div id=errors><i>Error:</i>');if(s.length>0){s.sort();for(i=0;i<s.length;i+=1){s[i]='<code>'+s[i]+'</code>&nbsp;<i>'+
+implied[s[i]].join(' ')+'</i>';}
+o.push('<p><i>Implied global:</i> '+s.join(', ')+'</p>');c=true;}
+for(i=0;i<k;i+=1){c=JSLINT.errors[i];if(c){e=c.evidence||'';o.push('<p>Problem'+(isFinite(c.line)?' at line '+(c.line+1)+' character '+(c.character+1):'')+': '+c.reason.entityify()+'</p><p class=evidence>'+
+(e&&(e.length>80?e.slice(0,77)+'...':e).entityify())+'</p>');}}
+o.push('</div>');if(!c){return o.join('');}}
+if(!option){o.push('<div id=functions>');s=to_array(scope);if(s.length===0){if(jsonmode){if(k===0){o.push('<p>JSON: good.</p>');}else{o.push('<p>JSON: bad.</p>');}}else{o.push('<div><i>No new global variables introduced.</i></div>');}}else{o.push('<div><i>Global</i> '+s.sort().join(', ')+'</div>');}
+for(i=0;i<functions.length;i+=1){f=functions[i];cl=[];va=[];un=[];ou=[];gl=[];la=[];for(k in f)if(f.hasOwnProperty(k)){v=f[k];switch(v){case'closure':cl.push(k);break;case'var':va.push(k);break;case'unused':un.push(k);break;case'label':la.push(k);break;case'outer':ou.push(k);break;case true:if(k!=='(context)'){gl.push(k);}
+break;}}
+o.push('<br><div class=function><i>'+f['(line)']+'</i> '+
+(f['(name)']||'')+'('+
+(f['(params)']||'')+')</div>');detail('Closure',cl);detail('Variable',va);detail('Unused',un);detail('Label',la);detail('Outer',ou);detail('Global',gl);}
+a=[];for(k in member){if(typeof member[k]==='number'){a.push(k);}}
+if(a.length){a=a.sort();m='<br><pre>/*members ';l=10;for(i=0;i<a.length;i+=1){k=a[i];n=k.name();if(l+n.length>72){o.push(m+'<br>');m='    ';l=1;}
+l+=n.length+2;if(member[k]===1){n='<i>'+n+'</i>';}
+if(i<a.length-1){n+=', ';}
+m+=n;}
+o.push(m+'<br>*/</pre>');}
+o.push('</div>');}
+return o.join('');};return itself;}();(function(a){if(!a[0]){print("Usage: jslint.js file.js");quit(1);}
+var input=readFile(a[0]);if(!input){print("jslint: Couldn't open file '"+a[0]+"'.");quit(1);}
+if(!JSLINT(input,{rhino:true,passfail:false})){for(var i=0;i<JSLINT.errors.length;i+=1){var e=JSLINT.errors[i];if(e){print('Lint at line '+(e.line+1)+' character '+
+(e.character+1)+': '+e.reason);print((e.evidence||'').replace(/^\s*(\S*(\s+\S+)*)\s*$/,"$1"));print('');}}}else{print("jslint: No problems found in "+a[0]);quit();}})(arguments);
Index: indicop/javascript/jslint/runJSLint.sh
===================================================================
--- indicop/javascript/jslint/runJSLint.sh	(revision b05fd7f86fb7ba6ddb22bcab445d80cd9c24d90c)
+++ indicop/javascript/jslint/runJSLint.sh	(revision b05fd7f86fb7ba6ddb22bcab445d80cd9c24d90c)
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+RHINO=rhino
+folderNames=( 'Admin' 'Collaboration' 'Core' 'Display' 'Legacy' 'Management' 'MaterialEditor' 'Timetable' )
+
+for folderName in ${folderNames[@]}
+do
+  echo "----------->Scanning folder $folderName"
+  for file in `find /home/jeremy/cds-indico/indico/htdocs/js/indico/$folderName -name '*.js'`;
+  do
+   echo File ${file}:
+   $RHINO jslint.js $file
+  done
+done
Index: indicop/javascript/unit/setup.js
===================================================================
--- indicop/javascript/unit/setup.js	(revision b05fd7f86fb7ba6ddb22bcab445d80cd9c24d90c)
+++ indicop/javascript/unit/setup.js	(revision b05fd7f86fb7ba6ddb22bcab445d80cd9c24d90c)
@@ -0,0 +1,20 @@
+var ScriptRoot = "../";
+
+function include(script) {
+    jstestdriver.console.log("include called");
+    document.write("<script type=\"text/javascript\" src=\"" + script + "\"></script>");
+}
+
+var Indico = {
+        Urls: {
+            SecureImagesBase: "URLSecureImagesBase",
+            SecureJsonRpcService: "URLSecureJsonRpcService",
+            JsonRpcService: "URLJsonRpcService",
+            ImagesBase: "URLImagesBase"
+            },
+        SystemIcons: {
+            conference: "ICONconference",
+            lecture: "ICONlecture",
+            meeting: "ICONmeeting",
+            }
+};
Index: indicop/javascript/unit/tests/Timetable/Base.js
===================================================================
--- indicop/javascript/unit/tests/Timetable/Base.js	(revision b05fd7f86fb7ba6ddb22bcab445d80cd9c24d90c)
+++ indicop/javascript/unit/tests/Timetable/Base.js	(revision b05fd7f86fb7ba6ddb22bcab445d80cd9c24d90c)
@@ -0,0 +1,101 @@
+
+MoveTest = TestCase("MoveTest");
+
+MoveTest.prototype.setUp = function() {
+        
+    //creating an empty historybroker
+    this.historyBroker = new BrowserHistoryBroker();
+    
+    this.result = {
+        day : "20091217",
+        entry : {
+            endDate : {
+                date : "2009-12-15",
+                time : "08:20:00"
+            },
+            entryType : "Break",
+            startDate : {
+                date : "2009-12-15",
+                time : "08:00:00"
+            }
+        },
+        id: "2"
+    };
+    
+    this.data = {
+        "20091215" : {
+            "2" : {
+                "startDate" : {
+                    "date" : "2009-12-15",
+                    "time" : "08:00:00"
+                },
+                "endDate" : {
+                    "date" : "2009-12-15",
+                    "time" : "08:20:00"
+                }
+            },
+            "4" : {
+                "startDate" : {
+                    "date" : "2009-12-15",
+                    "time" : "08:00:00"
+                },
+                "endDate" : {
+                    "date" : "2009-12-15",
+                    "time" : "08:20:00"
+                }
+            }
+        },
+        "20091217" : {},
+        "20091216" : {
+            "s0l0" : {
+                "startDate" : {
+                    "date" : "2009-12-16",
+                    "time" : "08:00:00"
+                },
+                "sessionSlotId" : "0",
+                "endDate" : {
+                    "date" : "2009-12-16",
+                    "time" : "09:00:00"
+                },
+            }
+        }
+    };
+    
+    this.eventInfo = {
+        "startDate" : {
+            "date" : "2009-12-15",
+            "time" : "08:00:00"
+        },
+        "endDate" : {
+            "date" : "2009-12-17",
+            "time" : "18:00:00"
+        }
+    };
+    
+    //Mock, since we do not need any GUI, we fake this object
+    function WrappingElement(){
+        this.setStyle = function(x, y){
+            return true;
+        };
+    }
+    this.wrappingElement = new WrappingElement();
+    
+};
+
+
+MoveTest.prototype.testUpdateEntry = function() {
+    //function(data, eventInfo, width, wrappingElement, detailLevel, historyBroker, isSessionTimetable)
+    var tlmt = new TopLevelManagementTimeTable(this.data, this.eventInfo, "5", this.wrappingElement, null, this.historyBroker, false);
+    tlmt.currentDay = "20091215";
+    
+    //_updateMovedEntry: function(result, oldEntryId)
+    tlmt._updateMovedEntry(this.result, "2");
+    
+    var expectedData = "{\"4\":{\"startDate\":{\"date\":\"2009-12-15\",\"time\":\"08:00:00\"},\"endDate\":{\"date\":\"2009-12-15\",\"time\":\"08:20:00\"}}}";
+    
+    //checking of the Break has been moved
+    assertEquals("Old entry should have been removed", expectedData, Json.write(tlmt.data['20091215']));
+    assertEquals("New entry location", "Break", tlmt.data['20091217']['2']['entryType']);
+
+};
+
Index: indicop/python/functional/example_test.py
===================================================================
--- indicop/python/functional/example_test.py	(revision b05fd7f86fb7ba6ddb22bcab445d80cd9c24d90c)
+++ indicop/python/functional/example_test.py	(revision b05fd7f86fb7ba6ddb22bcab445d80cd9c24d90c)
@@ -0,0 +1,182 @@
+import time
+from seleniumTestCase import SeleniumTestCase
+
+class ExampleTest(SeleniumTestCase):
+    def setUp(self):
+        SeleniumTestCase.setUp(self)
+
+    def testCreateDeleteLecture(self):
+        sel = self.selenium
+        sel.open("/indico//index.py")
+        sel.click("createEventLink")
+        sel.click("link=Lecture")
+        sel.wait_for_page_to_load("30000")
+        self.assertEqual("Log in to Indico", sel.get_text("//div[3]/div[1]"))
+        sel.type("login", "dummyuser")
+        sel.type("password", "dummyuser")
+        sel.click("loginButton")
+        sel.wait_for_page_to_load("30000")
+        #self.assertEqual("The lecture will take place in 1 2 3 4 5 6 7 8 9 date(s)", sel.get_text("//form[@id='eventCreationForm']/table[1]/tbody/tr[2]/td[2]")) not working in IE
+        sel.type("title", "lecture test")
+        sel.click("advancedOptionsText")
+        self.assertEqual("Default layout style", sel.get_text("//tr[@id='advancedOptions']/td/table/tbody/tr[2]/td[1]/span"))
+        sel.click("advancedOptionsText")
+        sel.click("ok")
+        sel.wait_for_page_to_load("30000")
+        
+        #we set the confId, so in case the test fails, Teardown function is going to delete the conf
+        SeleniumTestCase.setConfID(self, sel.get_location())
+        
+        try: self.failUnless(sel.is_text_present("lecture test"))
+        except AssertionError, e: self.verificationErrors.append(str(e))
+        sel.click("link=Tools")
+        sel.wait_for_page_to_load("30000")
+        sel.click("link=Delete")
+        sel.wait_for_page_to_load("30000")
+        try: self.failUnless(sel.is_text_present("Are you sure that you want to DELETE the conference \"lecture test\"?"))
+        except AssertionError, e: self.verificationErrors.append(str(e))
+        sel.click("confirm")
+        sel.wait_for_page_to_load("30000")
+
+
+    def testConference(self):
+        sel = self.selenium
+        sel.open("/indico/index.py")
+        sel.click("//li[@id='createEventMenu']/span")
+        sel.click("link=Create conference")
+        sel.wait_for_page_to_load("30000")
+        sel.type("login", "dummyuser")
+        sel.type("password", "dummyuser")
+        sel.click("loginButton")
+        sel.wait_for_page_to_load("30000")
+        sel.type("title", "conference test")
+        sel.click("advancedOptionsText")
+        try: self.failUnless(sel.is_text_present("Description"))
+        except AssertionError, e: self.verificationErrors.append(str(e))
+        sel.click("ok")
+        sel.wait_for_page_to_load("30000")
+        
+        #we set the confId, so in case the test fails, Teardown function is going to delete the conf
+        SeleniumTestCase.setConfID(self, sel.get_location())
+        
+        sel.click("link=Timetable")
+        sel.wait_for_page_to_load("30000")
+        sel.click("link=Add new")
+        for i in range(60):
+            try:
+                if sel.is_text_present("Session"):
+                    break
+                else:
+                    sel.click("link=Add new")
+            except: pass
+            time.sleep(1)
+        else: self.fail("time out")
+        sel.click("link=Session")
+        for i in range(60):
+            try:
+                if sel.is_text_present("Add Session"):
+                    break
+                else:
+                    sel.click("link=Session")
+            except: pass
+            time.sleep(1)
+        else: self.fail("time out")
+        sel.type("_GID5", "Session One")
+        sel.type("//textarea", "bla bla bla")
+        sel.click("//button[1]")
+        for i in range(60):
+            try:
+                if sel.is_text_present("Session One"):
+                    break
+                else:
+                    sel.click("//button[1]")
+            except: pass
+            time.sleep(1)
+        else: self.fail("time out")
+        sel.click("//div[@id='timetableDiv']/div/div[2]/div/div/div/div[2]/div[2]/div[2]/div/div/div[1]/div")
+        for i in range(60):
+            try:
+                if sel.is_text_present("View and edit current interval timetable"):
+                    break
+                else:
+                    sel.click("//div[@id='timetableDiv']/div/div[2]/div/div/div/div[2]/div[2]/div[2]/div/div/div[1]/div")
+            except: pass
+            time.sleep(1)
+        else: self.fail("time out")
+        sel.click("link=View and edit current interval timetable")
+        sel.click("link=Add new")
+        for i in range(60):
+            try:
+                if sel.is_text_present("Contribution"): break
+                else: sel.click("link=Add new")
+            except: pass
+            time.sleep(1)
+        else: self.fail("time out")
+        sel.click("link=Contribution")
+        for i in range(60):
+            try:
+                if sel.is_text_present("Add Contribution"): break
+                else: sel.click("link=Contribution")
+            except: pass
+            time.sleep(1)
+        else: self.fail("time out")
+        sel.type("//input[@type='text']", "Contribution in Session One")
+        sel.click("//button[1]")
+        for i in range(60):
+            try:
+                if sel.is_text_present("Contribution in Session One"): break
+                else: sel.click("//button[1]")
+            except: pass
+            time.sleep(1)
+        else: self.fail("time out")
+        sel.click("link=Go back to timetable")
+        for i in range(60):
+            try:
+                if sel.is_text_present("Session One"): break
+                else: sel.click("link=Go back to timetable")
+            except: pass
+            time.sleep(1)
+        else: self.fail("time out")
+        sel.click("link=Add new")
+        for i in range(60):
+            try:
+                if sel.is_text_present("Break"): break
+                else: sel.click("link=Add new")
+            except: pass
+            time.sleep(1)
+        else: self.fail("time out")
+        sel.click("link=Break")
+        for i in range(60):
+            try:
+                if sel.is_text_present("Add Break"): break
+                else: sel.click("link=Break")
+            except: pass
+            time.sleep(1)
+        else: self.fail("time out")
+        sel.type("//input[@type='text']", "Break")
+        sel.click("//button[1]")
+        for i in range(60):
+            try:
+                if sel.is_text_present("Break"): break
+                else: sel.click("//button[1]")
+            except: pass
+            time.sleep(1)
+        else: self.fail("time out")
+        sel.click("link=Tools")
+        sel.wait_for_page_to_load("30000")
+        sel.click("//html/body/div[1]/div[4]/div/table/tbody/tr/td[2]/div/div/div/ul[@id='tabList']/li[5]/a")
+        sel.wait_for_page_to_load("30000")
+        for i in range(60):
+            try:
+                if sel.is_text_present("Are you sure that you want to DELETE the conference \"conference test\"?"): break
+            except: pass
+            time.sleep(1)
+        else: self.fail("time out")
+        sel.click("confirm")
+        sel.wait_for_page_to_load("30000")
+        
+    def tearDown(self):
+        SeleniumTestCase.tearDown(self)
+
+if __name__ == "__main__":
+    unittest.main()
Index: indicop/python/functional/loop.sh
===================================================================
--- indicop/python/functional/loop.sh	(revision b05fd7f86fb7ba6ddb22bcab445d80cd9c24d90c)
+++ indicop/python/functional/loop.sh	(revision b05fd7f86fb7ba6ddb22bcab445d80cd9c24d90c)
@@ -0,0 +1,7 @@
+#!/bin/bash
+echo '--------------------- NEW RUN -------------------' >> selog.txt
+for a in `seq 20`
+do
+  echo "===================== pass $a ====================="
+  sudo PYTHONPATH=/home/jeremy/cds-indico/indico/ nosetests -v >> selog.txt 2>&1
+done
Index: indicop/python/functional/seleniumTestCase.py
===================================================================
--- indicop/python/functional/seleniumTestCase.py	(revision b05fd7f86fb7ba6ddb22bcab445d80cd9c24d90c)
+++ indicop/python/functional/seleniumTestCase.py	(revision b05fd7f86fb7ba6ddb22bcab445d80cd9c24d90c)
@@ -0,0 +1,132 @@
+from MaKaC.common.db import DBMgr
+from MaKaC import user
+from MaKaC.common import indexes
+from MaKaC.authentication import AuthenticatorMgr
+from MaKaC.conference import ConferenceHolder
+from MaKaC.errors import MaKaCError
+from MaKaC.common import HelperMaKaCInfo
+import unittest, time, re
+from twill import commands as tc
+import figleaf
+from selenium import selenium
+import unittest, time
+import sys
+import socket
+from twill import commands as tc
+
+class SeleniumTestCase(unittest.TestCase):
+    
+    def setUp(self):
+        self.verificationErrors = []
+        self.confId = None
+        self.selenium = selenium("localhost", 4444, "*chrome", self.getRootUrl())
+#        self.selenium = selenium("localhost", 4444, 'IE on Windows', self.getRootUrl())
+        self.selenium.start()
+        
+        #Create dummy user and use this user to create conf, session and so on
+        self.createDummyUser()
+        
+        #Handy functions from selenium and twill you might need
+        #set up the time between each selenium's commands (in milliseconds)
+#        self.selenium.set_speed(1000)
+        #convenient to set the browser in a known state
+#        tc.clear_cookies()
+    
+    def tearDown(self):
+        #if a confId is specified we'll try to delete the conf in case the test failed
+        if self.confId:
+            self.deleteConference(self.confId)
+        
+        self.deleteDummyUser()
+        
+        self.selenium.stop()
+        
+        print "Errors array: %s" % self.verificationErrors
+        self.assertEqual([], self.verificationErrors)
+    
+    
+    def getRootUrl(self):
+        #set this accordingly to your indico installation
+        return "http://pcituds01/"
+    
+    def createDummyUser(self):
+        DBMgr.getInstance().startRequest()
+        
+        #filling info to new user
+        self.avatar = user.Avatar()
+        self.avatar.setName( "fake" )
+        self.avatar.setSurName( "fake" )
+        self.avatar.setOrganisation( "fake" )
+        self.avatar.setLang( "en_US" )
+        self.avatar.setEmail( "fake@fake.fake" )
+        
+        #registering user
+        self.ah = user.AvatarHolder()
+        self.ah.add(self.avatar)
+        
+        #setting up the login info
+        li = user.LoginInfo( "dummyuser", "dummyuser" )
+        self.ih = AuthenticatorMgr()
+        id = self.ih.createIdentity( li, self.avatar, "Local" )
+        self.ih.add( id )
+        
+        #activate the account
+        self.avatar.activateAccount()
+        
+        #since the DB is empty, we have to add dummy user as admin
+        minfo = HelperMaKaCInfo.getMaKaCInfoInstance()
+        self.al = minfo.getAdminList()
+        self.al.grant( self.avatar )
+        
+        DBMgr.getInstance().endRequest()
+        
+    def deleteDummyUser(self):
+        DBMgr.getInstance().startRequest()
+        
+        #removing user from admin list
+        self.al.revoke( self.avatar )
+        
+        #remove the login info
+        id=self.avatar.getIdentityList()[0]
+        self.ih.removeIdentity(id)
+        
+        #unregistering the user info
+        index = indexes.IndexesHolder().getById("email")
+        index.unindexUser(self.avatar)
+        index = indexes.IndexesHolder().getById("name")
+        index.unindexUser(self.avatar)
+        index = indexes.IndexesHolder().getById("surName")
+        index.unindexUser(self.avatar)
+        index = indexes.IndexesHolder().getById("organisation")
+        index.unindexUser(self.avatar)
+        index = indexes.IndexesHolder().getById("status")
+        index.unindexUser(self.avatar)
+        
+        #removing user from list
+        la = self.ih.getById("Local")
+        la.remove(id)
+        self.ah.remove(self.avatar)
+        
+        DBMgr.getInstance().endRequest()
+        
+    def setConfID(self, url):
+        #Parsing the url to retrieve the confId
+        #if the confID is set up, we'll try to delete this conference in the teardown
+        #in case the test fails
+        splitUrl = url.split('=')
+        self.confId = splitUrl[1]
+        
+    def deleteConference(self, confId):
+        DBMgr.getInstance().startRequest()
+        
+        try:
+            if confId:
+                #we try to delete the conf
+                ch = ConferenceHolder()
+                conf = ch.getById(confId)
+                conf.delete()
+        except MaKaCError, e:
+            #test succeeded and conf has already been deleted
+            pass
+        
+        DBMgr.getInstance().endRequest()
Index: indicop/python/pylint/pylint.conf
===================================================================
--- indicop/python/pylint/pylint.conf	(revision b05fd7f86fb7ba6ddb22bcab445d80cd9c24d90c)
+++ indicop/python/pylint/pylint.conf	(revision b05fd7f86fb7ba6ddb22bcab445d80cd9c24d90c)
@@ -0,0 +1,318 @@
+# lint Python modules using external checkers.
+# 
+# This is the main checker controlling the other ones and the reports
+# generation. It is itself both a raw checker and an astng checker in order
+# to:
+# * handle message activation / deactivation at the module level
+# * handle some basic but necessary stats'data (number of classes, methods...)
+# 
+[MASTER]
+
+# Specify a configuration file.
+#rcfile=
+
+# Python code to execute, usually for sys.path manipulation such as
+# pygtk.require().
+#init-hook=
+
+# Profiled execution.
+profile=no
+
+# Add <file or directory> to the black list. It should be a base name, not a
+# path. You may set this option multiple times.
+ignore=CVS
+
+# Pickle collected data for later comparisons.
+persistent=no
+
+# Set the cache size for astng objects.
+cache-size=1000
+
+# List of plugins (as comma separated values of python modules names) to load,
+# usually to register additional checkers.
+load-plugins=
+
+
+[MESSAGES CONTROL]
+
+# Enable only checker(s) with the given id(s). This option conflicts with the
+# disable-checker option
+#enable-checker=
+
+# Enable all checker(s) except those with the given id(s). This option
+# conflicts with the enable-checker option
+disable-checker=typecheck, imports
+
+# Enable all messages in the listed categories.
+#enable-msg-cat=
+
+# Disable all messages in the listed categories.
+#disable-msg-cat=
+
+# Enable the message(s) with the given id(s).
+#enable-msg=
+
+# Disable the message(s) with the given id(s).
+disable-msg=C0111, W0232, R0903, R0401, W0701
+
+
+[REPORTS]
+
+# Set the output format. Available formats are text, parseable, colorized, msvs
+# (visual studio) and html
+output-format=parseable
+
+# Include message's id in output
+include-ids=yes
+
+# Put messages in a separate file for each module / package specified on the
+# command line instead of printing them on stdout. Reports (if any) will be
+# written in a file name "pylint_global.[txt|html]".
+files-output=no
+
+# Tells wether to display a full report or only the messages
+reports=no
+
+# Python expression which should return a note less than 10 (10 is the highest
+# note). You have access to the variables errors warning, statement which
+# respectivly contain the number of errors / warnings messages and the total
+# number of statements analyzed. This is used by the global evaluation report
+# (R0004).
+evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
+
+# Add a comment according to your evaluation note. This is used by the global
+# evaluation report (R0004).
+comment=no
+
+# Enable the report(s) with the given id(s).
+#enable-report=
+
+# Disable the report(s) with the given id(s).
+#disable-report=
+
+
+# checks for :
+# * doc strings
+# * modules / classes / functions / methods / arguments / variables name
+# * number of arguments, local variables, branchs, returns and statements in
+# functions, methods
+# * required module attributes
+# * dangerous default values as arguments
+# * redefinition of function / method / class
+# * uses of the global statement
+# 
+[BASIC]
+
+# Required attributes for module, separated by a comma
+required-attributes=
+
+# Regular expression which should only match functions or classes name which do
+# not require a docstring
+no-docstring-rgx=__.*__
+
+# Regular expression which should only match correct module names
+#module-rgx=(([a-z][a-z0-9]*)|([A-Z][a-zA-Z0-9]+))|([a-z][a-zA-Z]*)$
+module-rgx=[a-z][A-Za-z_]*$|MaKaC$
+
+# Regular expression which should only match correct module level names
+#const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
+const-rgx=[A-Z_]*$
+
+# Regular expression which should only match correct class names
+#class-rgx=[_]?[A-Z][a-zA-Z0-9]+$
+class-rgx=[_]?[A-Z][a-zA-Z0-9]*$
+
+# Regular expression which should only match correct function names
+# Outside class directly in module
+#function-rgx=([_]{0,2}[a-z][A-Za-z0-9]*){1,30}$
+function-rgx=[_]{0,2}[a-z][a-zA-Z0-9]*$
+
+# Regular expression which should only match correct method names
+#method-rgx=(([_]{0,2}[a-z][A-Za-z0-9]*)|(__init__)?|(__cmp__)?|(__str__)?){1,30}$
+method-rgx=[_]{0,2}[a-z][A-Za-z_]*$
+
+# Regular expression which should only match correct instance attribute names
+#attr-rgx=(([_]{0,2}[a-z][A-Za-z0-9]*)){1,30}$
+attr-rgx=[_]{0,2}[a-z][A-Za-z0-9_]*$
+
+# Regular expression which should only match correct argument names
+#argument-rgx=([_]{0,2}[a-z][A-Za-z0-9]*|[A-Z]*){1,30}$
+argument-rgx=[a-z][A-Za-z0-9_]*$
+
+# Regular expression which should only match correct variable names
+#variable-rgx=([_]{0,2}[a-z][A-Za-z0-9]*){1,30}|[A-Z0-9_]{1,30}$
+variable-rgx=[a-z][A-Za-z0-9_]*$
+
+# Regular expression which should only match correct list comprehension /
+# generator expression variable names
+inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
+
+# Good variable names which should always be accepted, separated by a comma
+good-names=i,j,k,ex,Run,_
+
+# Bad variable names which should always be refused, separated by a comma
+bad-names=foo,bar,baz,toto,tutu,tata
+
+# List of builtins function names that should not be used, separated by a comma
+bad-functions=map,filter,apply,input
+
+
+# checks for
+# * unused variables / imports
+# * undefined variables
+# * redefinition of variable from builtins or from an outer scope
+# * use of variable before assigment
+# 
+[VARIABLES]
+
+# Tells wether we should check for unused import in __init__ files.
+init-import=yes
+
+# A regular expression matching names used for dummy variables (i.e. not used).
+dummy-variables-rgx=_|dummy
+
+# List of additional names supposed to be defined in builtins. Remember that
+# you should avoid to define new builtins when possible.
+additional-builtins=
+
+
+# try to find bugs in the code using type inference
+# 
+[TYPECHECK]
+
+# Tells wether missing members accessed in mixin class should be ignored. A
+# mixin class is detected if its name ends with "mixin" (case insensitive).
+ignore-mixin-members=yes
+
+# List of classes names for which member attributes should not be checked
+# (useful for classes with attributes dynamicaly set).
+ignored-classes=SQLObject
+
+# When zope mode is activated, add a predefined set of Zope acquired attributes
+# to generated-members.
+zope=yes
+
+# List of members which are set dynamically and missed by pylint inference
+# system, and so shouldn't trigger E0201 when accessed.
+generated-members=REQUEST,acl_users,aq_parent
+
+
+# checks for sign of poor/misdesign:
+# * number of methods, attributes, local variables...
+# * size, complexity of functions, methods
+# 
+[DESIGN]
+
+# Maximum number of arguments for function / method
+max-args=15
+
+# Maximum number of locals for function / method body
+max-locals=40
+
+# Maximum number of return / yield for function / method body
+max-returns=15
+
+# Maximum number of branch for function / method body
+max-branchs=81
+
+# Maximum number of statements in function / method body
+max-statements=190
+
+# Maximum number of parents for a class (see R0901).
+max-parents=18
+
+# Maximum number of attributes for a class (see R0902).
+max-attributes=92
+
+# Minimum number of public methods for a class (see R0903).
+min-public-methods=2
+
+# Maximum number of public methods for a class (see R0904).
+max-public-methods=304
+
+
+# checks for
+# * external modules dependencies
+# * relative / wildcard imports
+# * cyclic imports
+# * uses of deprecated modules
+# 
+[IMPORTS]
+
+# Deprecated modules which should not be used, separated by a comma
+deprecated-modules=regsub,string,TERMIOS,Bastion,rexec
+
+# Create a graph of every (i.e. internal and external) dependencies in the
+# given file (report R0402 must not be disabled)
+import-graph=
+
+# Create a graph of external dependencies in the given file (report R0402 must
+# not be disabled)
+ext-import-graph=
+
+# Create a graph of internal dependencies in the given file (report R0402 must
+# not be disabled)
+int-import-graph=
+
+
+# checks for :
+# * methods without self as first argument
+# * overridden methods signature
+# * access only to existant members via self
+# * attributes not defined in the __init__ method
+# * supported interfaces implementation
+# * unreachable code
+# 
+[CLASSES]
+
+# List of interface methods to ignore, separated by a comma. This is used for
+# instance to not check methods defines in Zope's Interface base class.
+ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
+
+# List of method names used to declare (i.e. assign) instance attributes.
+defining-attr-methods=__init__,__new__,setUp
+
+
+# checks for:
+# * warning notes in the code like FIXME, XXX
+# * PEP 263: source code with non ascii character but no encoding declaration
+# 
+[MISCELLANEOUS]
+
+# List of note tags to take in consideration, separated by a comma.
+notes=FIXME,XXX,TODO
+
+
+# checks for similarities and duplicated code. This computation may be
+# memory / CPU intensive, so you should disable it if you experiments some
+# problems.
+# 
+[SIMILARITIES]
+
+# Minimum lines number of a similarity.
+min-similarity-lines=10
+
+# Ignore comments when computing similarities.
+ignore-comments=yes
+
+# Ignore docstrings when computing similarities.
+ignore-docstrings=yes
+
+
+# checks for :
+# * unauthorized constructions
+# * strict indentation
+# * line length
+# * use of <> instead of !=
+# 
+[FORMAT]
+
+# Maximum number of characters on a single line.
+max-line-length=79
+
+# Maximum number of lines in a module
+max-module-lines=13000
+
+# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
+# tab).
+indent-string='    '
Index: indicop/python/unit/MaKaC_tests/conference_test.py
===================================================================
--- indicop/python/unit/MaKaC_tests/conference_test.py	(revision b05fd7f86fb7ba6ddb22bcab445d80cd9c24d90c)
+++ indicop/python/unit/MaKaC_tests/conference_test.py	(revision b05fd7f86fb7ba6ddb22bcab445d80cd9c24d90c)
@@ -0,0 +1,1609 @@
+# -*- coding: utf-8 -*-
+##
+## $Id: conference_test.py,v 1.20 2008/04/24 16:59:57 jose Exp $
+##
+## This file is part of CDS Indico.
+## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 CERN.
+##
+## CDS Indico is free software; you can redistribute it and/or
+## modify it under the terms of the GNU General Public License as
+## published by the Free Software Foundation; either version 2 of the
+## License, or (at your option) any later version.
+##
+## CDS Indico is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with CDS Indico; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+
+from MaKaC.common.db import DBMgr
+from MaKaC import conference
+from MaKaC import user
+from MaKaC.user import Avatar
+from MaKaC.conference import Conference, Category
+from MaKaC.conference import Session,Contribution,SessionSlot
+from MaKaC.conference import ContributionParticipation
+from MaKaC.conference import SCIndex
+from MaKaC.errors import MaKaCError
+from MaKaC.schedule import BreakTimeSchEntry
+from datetime import datetime,timedelta
+from pytz import timezone
+
+import unittest
+
+
+def setup_module():
+    DBMgr.getInstance().startRequest()
+
+def teardown_module():
+    DBMgr.getInstance().abort()
+    DBMgr.getInstance().endRequest()
+        
+#From testCategories.py
+class TestCategories():
+    
+    def testBasicAddAndRemoveConferences(self):
+        #creation of basic category structure over which perform the tests
+        croot=conference.Category()
+        c1=conference.Category()
+        croot._addSubCategory(c1)
+        c2=conference.Category()
+        croot._addSubCategory(c2)
+        c1_1=conference.Category()
+        c1._addSubCategory(c1_1)
+        #checks adding a conference increases the conference number of the 
+        #   involved categories
+        creator=user.Avatar()
+        conf1=conference.Conference(creator)
+        conf1.setId("0")
+        c1_1._addConference(conf1)
+        assert (c1_1.getNumConferences()==1)
+        assert (c1.getNumConferences()==1)
+        assert (c2.getNumConferences()==0)
+        assert (croot.getNumConferences()==1)
+        conf2=conference.Conference(creator)
+        conf2.setId("1")
+        c2._addConference(conf2)
+        assert (c1_1.getNumConferences()==1)
+        assert (c1.getNumConferences()==1)
+        assert (c2.getNumConferences()==1)
+        assert (croot.getNumConferences()==2)
+        c1_1.removeConference(conf1)
+        assert (c1_1.getNumConferences()==0)
+        assert (c1.getNumConferences()==0)
+        assert (c2.getNumConferences()==1)
+        assert (croot.getNumConferences()==1)
+        c2.removeConference(conf2)
+        assert (c1_1.getNumConferences()==0)
+        assert (c1.getNumConferences()==0)
+        assert (c2.getNumConferences()==0)
+        assert (croot.getNumConferences()==0)
+        
+    def testAddAndRemoveSubCategories(self):
+        #checks that the conference counter works fine when adding a new
+        #   sub-category
+        croot=conference.Category()
+        c1=conference.Category()
+        c2=conference.Category()
+        croot._addSubCategory(c2)
+        creator=user.Avatar()
+        conf0=conference.Conference(creator)
+        conf0.setId("0")
+        conf1=conference.Conference(creator)
+        conf1.setId("1")
+        c1._addConference(conf0)
+        c1._addConference(conf1)
+        assert (croot.getNumConferences()==0)
+        assert (c1.getNumConferences()==2)
+        assert (c2.getNumConferences()==0)
+        croot._addSubCategory(c1)
+        assert (croot.getNumConferences()==2)
+        assert (c1.getNumConferences()==2)
+        assert (c2.getNumConferences()==0)
+        c1_1=conference.Category()
+        c1._addSubCategory(c1_1)
+        assert (croot.getNumConferences()==2)
+        assert (c1.getNumConferences()==2)
+        assert (c1_1.getNumConferences()==2)
+        assert (c2.getNumConferences()==0)
+        c1_1.move(c2)
+        assert (croot.getNumConferences()==2)
+        assert (c1.getNumConferences()==0)
+        assert (c1_1.getNumConferences()==2)
+        
+        assert (c2.getNumConferences()==2)
+        croot._removeSubCategory(c1)
+        assert (croot.getNumConferences()==2)
+        assert (c1.getNumConferences()==0)
+        assert (c1_1.getNumConferences()==2)
+        assert (c2.getNumConferences()==2)
+        c2._removeSubCategory(c1_1)
+        assert (croot.getNumConferences()==0)
+        assert (c1.getNumConferences()==0)
+        assert (c1_1.getNumConferences()==2)
+        assert (c2.getNumConferences()==0)
+        
+#from testConferences.py
+class TestBasicManagement(unittest.TestCase):
+    """Tests the basic conference management functions
+    """
+
+    def setUp( self ):
+        self._creator=Avatar()
+        self._creator.setId("creator")
+        self._conf=Conference(self._creator)
+        self._conf.setTimezone('UTC')
+        
+        category=conference.Category()
+        self._conf.addOwner(category)
+        
+        confTZ = self._conf.getTimezone()
+        sd = timezone(confTZ).localize(datetime(2000, 1, 1))
+        sdUTC = sd.astimezone(timezone('UTC'))
+        ed = timezone(confTZ).localize(datetime(2020, 1, 1))
+        edUTC = ed.astimezone(timezone('UTC'))
+        self._conf.setDates(sdUTC,edUTC)
+
+    def testAddRemoveSessions(self):
+        s1,s2=Session(),Session()
+        self._conf.addSession(s1)
+        self._conf.addSession(s2)
+        self.assert_(s1 in self._conf.getSessionList())
+        self.assert_(s1==self._conf.getSessionById(s1.getId()))
+        self.assert_(s2 in self._conf.getSessionList())
+        self.assert_(s2==self._conf.getSessionById(s2.getId()))
+        self._conf.removeSession(s1)
+        self.assert_(s1 not in self._conf.getSessionList())
+        self.assert_(None==self._conf.getSessionById(s1.getId()))
+        self.assert_(s2 in self._conf.getSessionList())
+        self.assert_(s2==self._conf.getSessionById(s2.getId()))
+        c1,c2,c3=Contribution(),Contribution(),Contribution()
+        self._conf.addSession(s1)
+        s1.addContribution(c1)
+        s1.addContribution(c2)
+        s2.addContribution(c3)
+        self.assert_(s1 in self._conf.getSessionList())
+        self.assert_(s1==self._conf.getSessionById(s1.getId()))
+        self.assert_(s2 in self._conf.getSessionList())
+        self.assert_(s2==self._conf.getSessionById(s2.getId()))
+        self.assert_(c1 in self._conf.getContributionList())
+        self.assert_(c2 in self._conf.getContributionList())
+        self.assert_(c3 in self._conf.getContributionList())
+        self.assert_(c1 in s1.getContributionList())
+        self.assert_(c2 in s1.getContributionList())
+        self.assert_(c3 in s2.getContributionList())
+        self._conf.removeSession(s1)
+        self.assert_(s1 not in self._conf.getSessionList())
+        self.assert_(s2 in self._conf.getSessionList())
+        self.assert_(c1 in self._conf.getContributionList())
+        self.assert_(c2 in self._conf.getContributionList())
+        self.assert_(c3 in self._conf.getContributionList())
+        self.assert_(c1 not in s1.getContributionList())
+        self.assert_(c1.getSession()==None)
+        self.assert_(c2.getSession()==None)
+        self.assert_(c2 not in s1.getContributionList())
+        self.assert_(c3 in s2.getContributionList())
+
+class TestModifyConferenceDates(unittest.TestCase):
+    """Tests different scenarios which can occur when modifying conference start
+        and end dates
+    """
+    def setUp(self):
+        a = Avatar()
+        a.setId("creator")
+        self._conf=Conference(a)
+        self._conf.setTimezone('UTC')
+        
+        category=conference.Category()
+        self._conf.addOwner(category)
+        
+        sd=datetime(2004, 01, 01, 10, 00, tzinfo=timezone('UTC'))
+        ed=datetime(2004, 01, 05, 10, 00, tzinfo=timezone('UTC'))
+        self._conf.setDates(sd,ed)
+
+    def testSessions(self):
+        s1=Session()
+        s1.setDates(datetime(2004, 01, 01, 10, 00, tzinfo=timezone('UTC')),datetime(2004, 01, 01, 12, 00, tzinfo=timezone('UTC')))
+        self._conf.addSession(s1)
+        s2=Session()
+        s2.setDates(datetime(2004, 01, 01, 15, 00, tzinfo=timezone('UTC')),datetime(2004, 01, 01, 18, 00, tzinfo=timezone('UTC')))
+        self._conf.addSession(s2)
+        #checks that modifying conference dates which does not affect to 
+        #   sessions is allowed
+        self._conf.setStartDate(datetime(2004, 01, 01, 9, 00, tzinfo=timezone('UTC')))
+        self._conf.setEndDate(datetime(2004, 01, 01, 19, 00, tzinfo=timezone('UTC')))
+        #if a session is affected an error should be reported
+        #self.assertRaises(MaKaCError,self._conf.setStartDate,datetime(2004, 01, 01, 10, 01, tzinfo=timezone('UTC')))
+        #self.assertRaises(MaKaCError,self._conf.setEndDate,datetime(2004, 01, 01, 17, 00, tzinfo=timezone('UTC')))
+
+    def testEntries(self):
+        c1,c2=Contribution(),Contribution()
+        b=BreakTimeSchEntry()
+        self._conf.addContribution(c1)
+        self._conf.addContribution(c2)
+        self._conf.getSchedule().addEntry(c1.getSchEntry())
+        self._conf.getSchedule().addEntry(b)
+        self._conf.getSchedule().addEntry(c2.getSchEntry())
+        #checks that modifying conference dates which does not affect to 
+        #   entries is allowed
+        self._conf.setStartDate(datetime(2004, 01, 01, 9, 00, tzinfo=timezone('UTC')))
+        self._conf.setEndDate(datetime(2004, 01, 01, 19, 00, tzinfo=timezone('UTC')))
+        #if any entry is affected an error should be reported
+        #self.assertRaises(MaKaCError,self._conf.setStartDate,datetime(2004, 01, 01, 10, 01, tzinfo=timezone('UTC')))
+        #self.assertRaises(MaKaCError,self._conf.setEndDate,datetime(2004, 01, 01, 10, 20, tzinfo=timezone('UTC')))
+
+class TestSchedule(unittest.TestCase):
+    """Tests the schedule management functions
+    """
+
+    def setUp( self ):
+        a = Avatar()
+        a.setId("creator")
+        self._conf=Conference(a)
+        self._conf.setTimezone('UTC')
+        sd=datetime(2004, 01, 01, 10, 00, tzinfo=timezone('UTC'))
+        ed=datetime(2004, 01, 05, 10, 00, tzinfo=timezone('UTC'))
+        self._conf.setDates(datetime(2000, 01, 01, tzinfo=timezone('UTC')),datetime(2020, 01, 01, tzinfo=timezone('UTC')))
+        self._conf.setScreenStartDate(sd)
+        self._conf.setScreenEndDate(ed)
+
+    def testAddSessionOutsideBoundaries(self):
+        #adding a session outside the conference dates must fail
+        #s1=Session()
+        #sd=datetime(2004, 01, 01, 9, 00, tzinfo=timezone('UTC'))
+        #ed=datetime(2004, 01, 01, 16, 00, tzinfo=timezone('UTC'))
+        #s1.setDates(sd,ed)
+        #self.assertRaises(MaKaCError,self._conf.addSession,s1)
+        #sd=datetime(2004, 01, 01, 10, 00, tzinfo=timezone('UTC'))
+        #ed=datetime(2004, 01, 05, 10, 01, tzinfo=timezone('UTC'))
+        #s1.setDates(sd,ed)
+        #self.assertRaises(MaKaCError,self._conf.addSession,s1)
+        #sd=datetime(2004, 01, 01, 9, 00, tzinfo=timezone('UTC'))
+        #ed=datetime(2004, 01, 05, 9, 59, tzinfo=timezone('UTC'))
+        #s1.setDates(sd,ed)
+        #self.assertRaises(MaKaCError,self._conf.addSession,s1)
+        pass
+
+    def testAddEntryOutsideBoundaries(self):
+        #adding an entry outside the conference dates must fail
+        #c1=Contribution()
+        #self._conf.addContribution(c1)
+        #c1.setStartDate(datetime(1999, 01, 01, 9, 00, tzinfo=timezone('UTC')))
+        #self.assertRaises(MaKaCError,self._conf.getSchedule().addEntry,c1.getSchEntry())
+        #b=BreakTimeSchEntry()
+        #b.setStartDate(datetime(2004, 01, 01, 9, 00, tzinfo=timezone('UTC')))
+        #self.assertRaises(MaKaCError,self._conf.getSchedule().addEntry,b)
+        pass
+
+    def testSetScheduleDifferentDates(self):
+        self._conf.setDates(datetime(2004, 01, 03, 10, 00, tzinfo=timezone('UTC')),datetime(2004, 01, 05, 10, 00, tzinfo=timezone('UTC')))
+        s=Session()
+        s.setDates(datetime(2004, 01, 04, 10, 00, tzinfo=timezone('UTC')),datetime(2004, 01, 04, 12, 00, tzinfo=timezone('UTC')))
+        self._conf.addSession(s)
+        c=Contribution()
+        self._conf.addContribution(c)
+        c.setStartDate(datetime(2004, 01, 04, 13, 00, tzinfo=timezone('UTC')))
+        self._conf.getSchedule().addEntry(c.getSchEntry())
+        #checks that everything works fine when changing conference schdule 
+        #   dates to ones different from the conference
+        #self._conf.setScreenStartDate(datetime(2004, 01, 04, 10, 00, tzinfo=timezone('UTC')))
+        #self._conf.setScreenEndDate(datetime(2004, 01, 05, 12, 00, tzinfo=timezone('UTC')))
+        #self.assertRaises(MaKaCError,self._conf.setScreenStartDate,datetime(2004, 01, 04, 10, 01, tzinfo=timezone('UTC')))
+        #self.assertRaises(MaKaCError,self._conf.setScreenEndDate,datetime(2004, 01, 04, 13, 00, tzinfo=timezone('UTC')))
+        #self._conf.setScreenStartDate(datetime(2004, 01, 04, 10, 00, tzinfo=timezone('UTC')))
+        #self._conf.setScreenEndDate(datetime(2004, 01, 04, 14, 00, tzinfo=timezone('UTC')))
+
+        #self._conf.setScreenStartDate(datetime(2004, 01, 01, tzinfo=timezone('UTC')))
+        #self._conf.setScreenEndDate(datetime(2004, 01, 05, tzinfo=timezone('UTC')))
+
+        #s.setDates(datetime(2004, 01, 02, 10, 00, tzinfo=timezone('UTC')),datetime(2004, 01, 04, 12, 00, tzinfo=timezone('UTC')))
+        #c.setStartDate(datetime(2004, 01, 02, 10, 00, tzinfo=timezone('UTC')))
+        #self.assertRaises(MaKaCError,self._conf.getSchedule().setDates,None,None)
+        #s.setDates(datetime(2004, 01, 04, 10, 00, tzinfo=timezone('UTC')),datetime(2004, 01, 04, 12, 00, tzinfo=timezone('UTC')))
+        #self.assertRaises(MaKaCError,self._conf.getSchedule().setDates,None,None)
+        #c.setStartDate(datetime(2004, 01, 04, 10, 00, tzinfo=timezone('UTC')))
+        #self._conf.getSchedule().setDates(None,None)
+        pass
+        
+    def testSessions(self):
+        s1=Session()
+        self._conf.addSession(s1)
+        sd=datetime(2004, 01, 01, 10, 00, tzinfo=timezone('UTC'))
+        ed=datetime(2004, 01, 01, 16, 00, tzinfo=timezone('UTC'))
+        s1.setDates(sd,ed)
+        slot1=SessionSlot(s1)
+        s1.addSlot(slot1)
+        slot1.setStartDate(datetime(2004, 01, 01, 10, 00, tzinfo=timezone('UTC')))
+        slot1.setDuration(hours=2,minutes=0)
+        slot2=SessionSlot(s1)
+        s1.addSlot(slot2)
+        slot2.setStartDate(datetime(2004, 01, 01, 12, 00, tzinfo=timezone('UTC')))
+        slot2.setDuration(hours=2,minutes=0)
+        self.assert_(slot1.getConfSchEntry() in self._conf.getSchedule().getEntries())
+        self.assert_(slot2.getConfSchEntry() in self._conf.getSchedule().getEntries())
+        slot3=SessionSlot(s1)
+        s1.addSlot(slot3)
+        slot3.setStartDate(datetime(2004, 01, 01, 13, 00, tzinfo=timezone('UTC')))
+        slot3.setDuration(hours=2,minutes=0)
+        self.assert_(slot3.getConfSchEntry() in self._conf.getSchedule().getEntries())
+        slot3.delete()
+        self.assert_(slot1.getConfSchEntry() in self._conf.getSchedule().getEntries())
+        self.assert_(slot2.getConfSchEntry() in self._conf.getSchedule().getEntries())
+        self.assert_(slot3.getConfSchEntry() not in self._conf.getSchedule().getEntries())
+
+    def testContributions(self):
+        c1,c2=Contribution(),Contribution()
+        self._conf.addContribution(c1)
+        self._conf.addContribution(c2)
+        sDate=datetime(2004, 01, 01, 10, 00, tzinfo=timezone('UTC'))
+        eDate=datetime(2004, 01, 01, 12, 00, tzinfo=timezone('UTC'))
+        self._conf.setStartDate(sDate)
+        self._conf.setEndDate(eDate)
+        c1.setDuration(0,10)
+        c2.setDuration(0,30)
+        self._conf.getSchedule().addEntry(c1.getSchEntry())
+        self._conf.getSchedule().addEntry(c2.getSchEntry())
+        self.assert_(c1.getSchEntry() in self._conf.getSchedule().getEntries())
+        self.assert_(c1.getStartDate()==datetime(2004, 01, 01, 10, 00, tzinfo=timezone('UTC')))
+        self.assert_(c2.getSchEntry() in self._conf.getSchedule().getEntries())
+        self.assert_(c2.getStartDate()==datetime(2004, 01, 01, 10, 10, tzinfo=timezone('UTC')))
+
+
+class TestAuthorIndex(unittest.TestCase):
+    """Tests the author index
+    """
+
+    def setUp( self ):
+        self._creator = Avatar()
+        self._creator.setId("creator")
+        self._categ = Category()
+        self._conf=Conference(self._creator)
+        self._conf.setId('a')
+        self._conf.setTimezone('UTC')
+        self._categ._addConference(self._conf)
+
+    def testBasicIndexing(self):
+        #Tests adding a contribution with some authors already on it
+        c1=Contribution()
+        self._conf.addContribution(c1)
+        auth1,auth2=ContributionParticipation(),ContributionParticipation()
+        auth1.setFirstName("hector")
+        auth1.setFamilyName("sanchez sanmartin")
+        auth1.setEmail("hector.sanchez@cern.ch")
+        auth2.setFirstName("jose benito")
+        auth2.setFamilyName("gonzalez lopez")
+        auth2.setEmail("jose.benito.gonzalez@cern.ch")
+        c1.addPrimaryAuthor(auth1)
+        c1.addPrimaryAuthor(auth2)
+        idx=self._conf.getAuthorIndex()
+        self.assert_(auth1 in idx.getParticipations()[1])
+        self.assert_(len(idx.getParticipations()[1])==1)
+        self.assert_(auth2 in idx.getParticipations()[0])
+        self.assert_(len(idx.getParticipations()[0])==1)
+        c2=Contribution()
+        self._conf.addContribution(c2)
+        auth3,auth4=ContributionParticipation(),ContributionParticipation()
+        auth3.setFirstName("hector")
+        auth3.setFamilyName("sanchez sanmartin")
+        auth3.setEmail("hector.sanchez@cern.ch")
+        auth4.setFirstName("jose benito")
+        auth4.setFamilyName("gonzalez lopez2")
+        auth4.setEmail("jose.benito.gonzalez@cern.ch")
+        c2.addPrimaryAuthor(auth3)
+        c2.addPrimaryAuthor(auth4)
+        #Tests removing a contribution from a conference updates the author 
+        #   index correctly
+        #self.assert_(auth3 in idx.getParticipations()[2])
+        #self.assert_(len(idx.getParticipations()[2])==2)
+        #self.assert_(auth4 in idx.getParticipations()[1])
+        #self.assert_(len(idx.getParticipations()[1])==1)
+        #self._conf.removeContribution(c2)
+        #self.assert_(auth1 in idx.getParticipations()[1])
+        #self.assert_(len(idx.getParticipations()[1])==1)
+        #self.assert_(auth2 in idx.getParticipations()[0])
+        #self.assert_(len(idx.getParticipations()[0])==1)
+        #Tests adding additional authors to a contribution which is already
+        #   included in a conference updates the author index correctly
+        #auth5=ContributionParticipation()
+        #auth5.setFirstName("jean-yves")
+        #auth5.setFamilyName("le meur")
+        #auth5.setEmail("jean-yves.le.meur@cern.ch")
+        #c1.addPrimaryAuthor(auth5)
+        #self.assert_(auth1 in idx.getParticipations()[2])
+        #self.assert_(len(idx.getParticipations()[2])==1)
+        #self.assert_(auth2 in idx.getParticipations()[0])
+        #self.assert_(len(idx.getParticipations()[0])==1)
+        #self.assert_(auth5 in idx.getParticipations()[1])
+        #self.assert_(len(idx.getParticipations()[1])==1)
+        #Tests removing authors from a contribution which is already
+        #   included in a conference updates the author index correctly
+        #c1.removePrimaryAuthor(auth5)
+        #self.assert_(auth1 in idx.getParticipations()[1])
+        #self.assert_(len(idx.getParticipations()[1])==1)
+        #self.assert_(auth2 in idx.getParticipations()[0])
+        #self.assert_(len(idx.getParticipations()[0])==1)
+
+    def testChangesInAuthorData(self):
+        #Checks that changes in the author data updates the author index 
+        #   correctly
+        c1=Contribution()
+        self._conf.addContribution(c1)
+        auth1,auth2=ContributionParticipation(),ContributionParticipation()
+        auth1.setFirstName("zFN")
+        auth1.setFamilyName("zSN")
+        auth1.setEmail("zM")
+        auth2.setFirstName("AFN")
+        auth2.setFamilyName("ASN")
+        auth2.setEmail("aM")
+        c1.addPrimaryAuthor(auth1)
+        c1.addPrimaryAuthor(auth2)
+        
+        idx=self._conf.getAuthorIndex()
+        self.assert_(auth1 in idx.getParticipations()[1])
+        self.assert_(len(idx.getParticipations()[1])==1)
+        self.assert_(auth2 in idx.getParticipations()[0])
+        self.assert_(len(idx.getParticipations()[0])==1)
+        auth2.setFamilyName("ZZSN")
+        self.assert_(auth1 in idx.getParticipations()[0])
+        self.assert_(len(idx.getParticipations()[0])==1)
+        self.assert_(auth2 in idx.getParticipations()[1])
+        self.assert_(len(idx.getParticipations()[1])==1)
+
+
+class TestAuthorSearch(unittest.TestCase):
+    """Tests the author search
+    """
+
+    def setUp( self ):
+        self._creator = Avatar()
+        self._creator.setId("creator")
+        self._conf=Conference(self._creator)
+        self._conf.setTimezone('UTC')
+
+    def testBasicSearch(self):
+        c1=Contribution()
+        self._conf.addContribution(c1)
+        auth1,auth2=ContributionParticipation(),ContributionParticipation()
+        auth1.setFamilyName("a")
+        auth1.setFirstName("a")
+        auth2.setFamilyName("b")
+        auth2.setFirstName("b")
+        c1.addPrimaryAuthor(auth1)
+        c1.addPrimaryAuthor(auth2)
+        self.assert_(len(self._conf.getContribsMatchingAuth(""))==1)
+        self.assert_(len(self._conf.getContribsMatchingAuth("a"))==1)
+        self.assert_(c1 in self._conf.getContribsMatchingAuth("a"))
+        self.assert_(c1 in self._conf.getContribsMatchingAuth("B"))
+        self.assert_(len(self._conf.getContribsMatchingAuth("B"))==1)
+        auth3=ContributionParticipation()
+        auth3.setFamilyName("c")
+        auth3.setFirstName("c")
+        c1.addCoAuthor(auth3)
+        self.assert_(len(self._conf.getContribsMatchingAuth(""))==1)
+        self.assert_(len(self._conf.getContribsMatchingAuth("c"))==0)
+
+    def testAddAuthor(self):
+        c1=Contribution()
+        self._conf.addContribution(c1)
+        auth1,auth2=ContributionParticipation(),ContributionParticipation()
+        auth1.setFamilyName("a")
+        auth1.setFirstName("a")
+        auth2.setFamilyName("b")
+        auth2.setFirstName("b")
+        c1.addPrimaryAuthor(auth1)
+        self.assert_(len(self._conf.getContribsMatchingAuth(""))==1)
+        self.assert_(len(self._conf.getContribsMatchingAuth("a"))==1)
+        self.assert_(c1 in self._conf.getContribsMatchingAuth("a"))
+        c1.addPrimaryAuthor(auth2)
+        self.assert_(len(self._conf.getContribsMatchingAuth("b"))==1)
+        self.assert_(c1 in self._conf.getContribsMatchingAuth("b"))
+        c1.removePrimaryAuthor(auth1)
+        self.assert_(len(self._conf.getContribsMatchingAuth(""))==1)
+        self.assert_(len(self._conf.getContribsMatchingAuth("a"))==0)
+        self.assert_(c1 not in self._conf.getContribsMatchingAuth("a"))
+        self.assert_(len(self._conf.getContribsMatchingAuth("b"))==1)
+        self.assert_(c1 in self._conf.getContribsMatchingAuth("b"))
+
+    def testWithdrawnContrib(self):
+        #Withdrawn contributions authors must be searchable
+        c1=Contribution()
+        self._conf.addContribution(c1)
+        auth1=ContributionParticipation()
+        auth1.setFamilyName("a")
+        auth1.setFirstName("a")
+        c1.addPrimaryAuthor(auth1)
+        c1.withdraw(self._creator,"ll")
+        self.assert_(len(self._conf.getContribsMatchingAuth(""))==1)
+        self.assert_(len(self._conf.getContribsMatchingAuth("a"))==1)
+        self.assert_(c1 in self._conf.getContribsMatchingAuth("a"))
+        auth2=ContributionParticipation()
+        auth2.setFamilyName("b")
+        auth2.setFirstName("b")
+        c1.addPrimaryAuthor(auth2)
+        #self._conf.getContribsMatchingAuth("b")
+        #self.assert_(len(self._conf.getContribsMatchingAuth(""))==1)
+        #self.assert_(len(self._conf.getContribsMatchingAuth("b"))==1)
+        #self.assert_(c1 in self._conf.getContribsMatchingAuth("b"))
+
+    def testAuthorsWithSameName(self):
+        #one contribution could have 2 authors with the same name
+        c1=Contribution()
+        self._conf.addContribution(c1)
+        auth1=ContributionParticipation()
+        auth1.setFamilyName("a")
+        auth1.setFirstName("a")
+        c1.addPrimaryAuthor(auth1)
+        auth2=ContributionParticipation()
+        auth2.setFamilyName("a")
+        auth2.setFirstName("a")
+        c1.addPrimaryAuthor(auth2)
+        self.assert_(len(self._conf.getContribsMatchingAuth(""))==1)
+        self.assert_(len(self._conf.getContribsMatchingAuth("a"))==1)
+        self.assert_(c1 in self._conf.getContribsMatchingAuth("a"))
+        c1.removePrimaryAuthor(auth1)
+        self.assert_(len(self._conf.getContribsMatchingAuth(""))==1)
+        self.assert_(len(self._conf.getContribsMatchingAuth("a"))==1)
+        self.assert_(c1 in self._conf.getContribsMatchingAuth("a"))
+
+
+class TestContributionSubmitterIndex(unittest.TestCase):
+    """
+    """
+
+    def setUp( self ):
+        self._creator = Avatar()
+        self._creator.setId("creator")
+        self._categ = Category()
+        self._conf=Conference(self._creator)
+        self._conf.setId('a')
+        self._conf.setTimezone('UTC')
+        self._categ._addConference(self._conf)
+
+    def testBasic(self):
+        c1,c2=Contribution(),Contribution()
+        av1,av2=Avatar(),Avatar()
+        av1.setId("1")
+        av2.setId("2")
+        self.assert_(len(self._conf.getContribsForSubmitter(av1))==0)
+        self.assert_(len(self._conf.getContribsForSubmitter(av2))==0)
+        self._conf.addContribution(c1)
+        self.assert_(len(self._conf.getContribsForSubmitter(av1))==0)
+        self.assert_(len(self._conf.getContribsForSubmitter(av2))==0)
+        c1.grantSubmission(av1)
+        self.assert_(len(self._conf.getContribsForSubmitter(av1))==1)
+        self.assert_(c1 in self._conf.getContribsForSubmitter(av1))
+        self.assert_(len(self._conf.getContribsForSubmitter(av2))==0)
+        c2.grantSubmission(av2)
+        self.assert_(len(self._conf.getContribsForSubmitter(av1))==1)
+        self.assert_(c1 in self._conf.getContribsForSubmitter(av1))
+        self.assert_(len(self._conf.getContribsForSubmitter(av2))==0)
+        self._conf.addContribution(c2)
+        self.assert_(len(self._conf.getContribsForSubmitter(av1))==1)
+        self.assert_(c1 in self._conf.getContribsForSubmitter(av1))
+        self.assert_(len(self._conf.getContribsForSubmitter(av2))==1)
+        self.assert_(c2 in self._conf.getContribsForSubmitter(av2))
+        c1.grantSubmission(av2)
+        self.assert_(len(self._conf.getContribsForSubmitter(av1))==1)
+        self.assert_(c1 in self._conf.getContribsForSubmitter(av1))
+        self.assert_(len(self._conf.getContribsForSubmitter(av2))==2)
+        self.assert_(c1 in self._conf.getContribsForSubmitter(av2))
+        self.assert_(c2 in self._conf.getContribsForSubmitter(av2))
+        c1.revokeSubmission(av2)
+        self.assert_(len(self._conf.getContribsForSubmitter(av1))==1)
+        self.assert_(c1 in self._conf.getContribsForSubmitter(av1))
+        self.assert_(len(self._conf.getContribsForSubmitter(av2))==1)
+        self.assert_(c1 not in self._conf.getContribsForSubmitter(av2))
+        self.assert_(c2 in self._conf.getContribsForSubmitter(av2))
+        self._conf.removeContribution(c2)
+        self.assert_(len(self._conf.getContribsForSubmitter(av1))==1)
+        self.assert_(c1 in self._conf.getContribsForSubmitter(av1))
+        self.assert_(len(self._conf.getContribsForSubmitter(av2))==0)
+        self.assert_(c1 not in self._conf.getContribsForSubmitter(av2))
+        self.assert_(c2 not in self._conf.getContribsForSubmitter(av2))
+        
+        
+
+class TestBasicManagement(unittest.TestCase):
+    """Tests the basic contribution management functions
+    """
+
+    def setUp( self ):
+        a = Avatar()
+        a.setId("creator")
+        self._categ = Category()
+        self._conf = Conference( a )
+        category=conference.Category()
+        self._conf.addOwner(category)
+        self._conf.setId('a')
+        self._conf.setDates(datetime(2000, 01, 01, tzinfo=timezone("UTC")),datetime(2020, 01, 01, tzinfo=timezone("UTC")))
+        self._categ._addConference(self._conf)
+
+    def testBasicAddAndRemove( self ):
+        contrib1 = Contribution()
+        contrib2 = Contribution()
+        contrib3 = Contribution()
+        self._conf.addContribution( contrib1 )
+        self.assert_( self._conf.getContributionById( contrib1.getId() ) == contrib1 )
+        self._conf.removeContribution( contrib2 )
+        self.assert_( self._conf.getContributionById( contrib1.getId() ) == contrib1 )
+        self._conf.removeContribution( contrib1 )
+        self.assert_( self._conf.getContributionById( contrib1.getId() ) == None )
+        self._conf.addContribution( contrib2 )
+        contrib2.delete()
+        self.assert_( self._conf.getContributionById( contrib2.getId() ) == None )
+
+    def testTrackDefinition( self ):
+        #tests the definition of the track of a contribution
+        contrib1 = Contribution()
+        track1 = self._conf.newTrack()
+        track2 = self._conf.newTrack()
+        self._conf.addContribution( contrib1 )
+        contrib1.setTrack( track1 )
+        self.assert_( contrib1.getTrack() == track1 )
+        self.assert_( track1.hasContribution( contrib1 ) )
+        contrib1.setTrack( None )
+        self.assert_( contrib1.getTrack() == None )
+        self.assert_( not track1.hasContribution( contrib1 ) )
+
+    def testSessionInclusion(self):
+        session1,session2=Session(),Session()
+        self._conf.addSession(session1)
+        self._conf.addSession(session2)
+        contrib1=Contribution()
+        self._conf.addContribution(contrib1)
+        contrib1.setTitle("debug")
+        contrib1.setSession(session1)
+        self.assert_(self._conf.hasContribution(contrib1))
+        self.assert_(session1.hasContribution(contrib1))
+        self.assert_(not session2.hasContribution(contrib1))
+        contrib1.setSession(session2)
+        self.assert_(self._conf.hasContribution(contrib1))
+        self.assert_(not session1.hasContribution(contrib1))
+        self.assert_(session2.hasContribution(contrib1))
+        contrib1.setSession(None)
+        self.assert_(self._conf.hasContribution(contrib1))
+        self.assert_(not session1.hasContribution(contrib1))
+        self.assert_(not session2.hasContribution(contrib1))
+        contrib1.setSession(session1)
+        self.assert_(self._conf.hasContribution(contrib1))
+        self.assert_(session1.hasContribution(contrib1))
+        self.assert_(not session2.hasContribution(contrib1))
+        self._conf.removeContribution(contrib1)
+        self.assert_(not self._conf.hasContribution(contrib1))
+        self.assert_(not session1.hasContribution(contrib1))
+        self.assert_(contrib1 not in session1.getContributionList())
+        self.assert_(not session2.hasContribution(contrib1))
+        self.assert_(contrib1 not in session2.getContributionList())
+
+    def testCustomIds(self):
+        #tests that adding a contribution with a custom id does not cause any 
+        #   trouble
+        contrib1 = Contribution()
+        self._conf.addContribution(contrib1,"test")
+        self.assert_(contrib1.getId()=="test")
+        self.assert_(self._conf.getContributionById("test")==contrib1)
+        contrib2 = Contribution()
+        self._conf.addContribution(contrib2)
+        self.assert_(contrib2.getId()=="0")
+        self.assert_(self._conf.getContributionById("0")==contrib2)
+        contrib3 = Contribution()
+        self._conf.addContribution(contrib3,"12")
+        self.assert_(contrib3.getId()=="12")
+        self.assert_(self._conf.getContributionById("12")==contrib3)
+        contrib4 = Contribution()
+        self._conf.addContribution(contrib4)
+        self.assert_(contrib4.getId()=="1")
+        self.assert_(self._conf.getContributionById("1")==contrib4)
+        contrib5 = Contribution()
+        self.assertRaises(MaKaCError,self._conf.addContribution,contrib5,"0")
+        self._conf.addContribution(contrib5,"2")
+        self.assert_(contrib5.getId()=="2")
+        self.assert_(self._conf.getContributionById("2")==contrib5)
+        contrib6 = Contribution()
+        self._conf.addContribution(contrib6)
+        self.assert_(contrib6.getId()=="3")
+        self.assert_(self._conf.getContributionById("3")==contrib6)
+
+
+class TestWithdrawal(unittest.TestCase):
+    """Tests different scenarios concerning the contribution withdrawal
+    """
+
+    def setUp( self ):
+        self._creator=Avatar()
+        self._creator.setId("creator")
+        self._conf=Conference(self._creator)
+        category=conference.Category()
+        self._conf.addOwner(category)
+        self._conf.setTimezone('UTC')
+        sd=datetime(2004, 01, 01, 10, 00, tzinfo=timezone("UTC"))
+        ed=datetime(2004, 01, 05, 10, 00, tzinfo=timezone("UTC"))
+        self._conf.setDates(sd,ed)
+
+    def testBasicWithdrawal(self):
+        c1,c2=Contribution(),Contribution()
+        auth1,auth2=ContributionParticipation(),ContributionParticipation()
+        self._conf.addContribution(c1)
+        self._conf.addContribution(c2)
+        auth1.setFirstName("a")
+        auth1.setFamilyName("a")
+        auth1.setEmail("a")
+        auth2.setFirstName("b")
+        auth2.setFamilyName("b")
+        auth2.setEmail("b")
+        c1.addPrimaryAuthor(auth1)
+        c2.addPrimaryAuthor(auth2)
+        s1=Session()
+        sd=datetime(2004, 01, 01, 12, 00, tzinfo=timezone("UTC"))
+        ed=datetime(2004, 01, 01, 19, 00, tzinfo=timezone("UTC"))
+        s1.setDates(sd,ed)
+        slot1=SessionSlot(s1)
+        self._conf.addSession(s1)
+        s1.addSlot(slot1)
+        s1.addContribution(c1)
+        s1.addContribution(c2)
+        slot1.getSchedule().addEntry(c1.getSchEntry())
+        slot1.getSchedule().addEntry(c2.getSchEntry())
+        self.assert_(c1.isScheduled())
+        self.assert_(c2.isScheduled())
+        authIdx=self._conf.getAuthorIndex()
+        self.assert_(auth1 in authIdx.getParticipations()[0])
+        self.assert_(auth2 in authIdx.getParticipations()[1])
+        c1.withdraw(self._creator,"test")
+        self.assert_(not c1.isScheduled())
+        self.assert_(c2.isScheduled())
+        self.assert_(auth1 not in authIdx.getParticipations()[0])
+        self.assert_(auth2 in authIdx.getParticipations()[0])
+        auth1.setFirstName("aa")
+        self.assert_(auth1 not in authIdx.getParticipations()[0])
+        self.assert_(auth2 in authIdx.getParticipations()[0])
+        auth3,auth4=ContributionParticipation(),ContributionParticipation()
+        auth3.setFirstName("c")
+        auth3.setFamilyName("c")
+        auth3.setEmail("c")
+        auth4.setFirstName("d")
+        auth4.setFamilyName("d")
+        auth4.setEmail("d")
+        c1.addPrimaryAuthor(auth3)
+        c2.addPrimaryAuthor(auth4)
+        self.assert_(auth2 in authIdx.getParticipations()[0])
+        self.assert_(auth4 in authIdx.getParticipations()[1])
+        self.assertRaises(MaKaCError,slot1.getSchedule().addEntry,c1.getSchEntry())
+
+class TestSubmissionPrivileges(unittest.TestCase):
+    """Tests different scenarios concerning the material submission privileges
+    """
+
+    def setUp( self ):
+        self._creator=Avatar()
+        self._creator.setId("creator")
+        self._conf=Conference(self._creator)
+        category=conference.Category()
+        self._conf.addOwner(category)
+        sd=datetime(2004, 01, 01, 10, 00, tzinfo=timezone("UTC"))
+        ed=datetime(2004, 01, 05, 10, 00, tzinfo=timezone("UTC"))
+        self._conf.setDates(sd,ed)
+
+    def testBasic(self):
+        c1=Contribution()
+        self._conf.addContribution(c1)
+        av1,av2=Avatar(),Avatar()
+        av1.setId("1")
+        av2.setId("2")
+        self.assert_(not c1.canUserSubmit(av1))
+        self.assert_(not c1.canUserSubmit(av2))
+        self.assert_(len(c1.getSubmitterList())==0)
+        c1.grantSubmission(av1)
+        self.assert_(c1.canUserSubmit(av1))
+        self.assert_(not c1.canUserSubmit(av2))
+        self.assert_(len(c1.getSubmitterList())==1)
+        self.assert_(av1 in c1.getSubmitterList())
+        self.assert_(av2 not in c1.getSubmitterList())
+        c1.revokeSubmission(av2)
+        self.assert_(c1.canUserSubmit(av1))
+        self.assert_(not c1.canUserSubmit(av2))
+        self.assert_(len(c1.getSubmitterList())==1)
+        self.assert_(av1 in c1.getSubmitterList())
+        self.assert_(av2 not in c1.getSubmitterList())
+        c1.revokeSubmission(av1)
+        self.assert_(not c1.canUserSubmit(av1))
+        self.assert_(not c1.canUserSubmit(av2))
+        self.assert_(len(c1.getSubmitterList())==0)
+
+    def testAccContrib(self):
+        #tests that when a contribution comes from an accepted abstract the 
+        #   abstract submitters are also granted with submission privileges 
+        #   for the contribution
+        av1=Avatar()
+        av1.setId("1")
+        av2=Avatar()
+        av2.setId("2")
+        abs=self._conf.getAbstractMgr().newAbstract(av1)
+        abs.accept(self._creator,None,None)
+        c=abs.getContribution()
+        self.assert_(c.canUserSubmit(av1))
+        self.assert_(not c.canUserSubmit(av2))
+        c.grantSubmission(av2)
+        self.assert_(c.canUserSubmit(av1))
+        self.assert_(c.canUserSubmit(av2))
+
+
+#from testSciProgramme.py
+"""Contains tests about some typical "scientific programme" scenarios.
+"""
+class TestTCIndex( unittest.TestCase ):
+    """Makes sure the track coordinators index is working properly as standalone
+        component
+    """
+
+    def setUp( self ):
+        #Build an index
+        from MaKaC.conference import TCIndex
+        self._idx = TCIndex()
+
+    def tearDown( self ):
+        pass
+
+    def testSimpleIndexing( self ):
+        #adding a simple object to the index
+        from MaKaC.user import Avatar
+        av = Avatar()
+        av.setId( "1" ) #the index needs the avatar to be uniquely identified
+        from MaKaC.conference import Track
+        t = Track()
+        t.setId( "1" )
+        self._idx.indexCoordinator( av , t )
+        self.assert_( len(self._idx.getTracks( av )) == 1 )
+        self.assert_( t in self._idx.getTracks( av ) )
+    
+    def testIndexingSeveralCoordinators( self ):
+        #adding 2 coordinators for the same track
+        from MaKaC.user import Avatar
+        av1 = Avatar()
+        av1.setId( "1" ) #the index needs the avatar to be uniquely identified
+        av2 = Avatar()
+        av2.setId( "2" ) #the index needs the avatar to be uniquely identified
+        from MaKaC.conference import Track
+        t = Track()
+        t.setId( "1" )
+        self._idx.indexCoordinator( av1 , t )
+        self._idx.indexCoordinator( av2 , t )
+        self.assert_( t in self._idx.getTracks( av1 ) )
+        self.assert_( t in self._idx.getTracks( av2 ) )
+    
+    def testIndexingSeveralTracks( self ):
+        #adding 1 coordinator for 2 tracks
+        from MaKaC.user import Avatar
+        av1 = Avatar()
+        av1.setId( "1" ) #the index needs the avatar to be uniquely identified
+        from MaKaC.conference import Track
+        t1 = Track()
+        t1.setId( "1" )
+        t2 = Track()
+        t2.setId( "2" )
+        self._idx.indexCoordinator( av1 , t1 )
+        self._idx.indexCoordinator( av1 , t2 )
+        self.assert_( t1 in self._idx.getTracks( av1 ) )
+        self.assert_( t2 in self._idx.getTracks( av1 ) )
+
+    def testSimpleUnidexing( self ):
+        #check that unindexing works properly
+        from MaKaC.user import Avatar
+        av = Avatar()
+        av.setId( "1" ) #the index needs the avatar to be uniquely identified
+        from MaKaC.conference import Track
+        t = Track()
+        t.setId( "1" )
+        self._idx.indexCoordinator( av , t )
+        self._idx.unindexCoordinator( av, t )
+        self.assert_( len(self._idx.getTracks( av )) == 0 )
+    
+    def testUnindexingSeveralCoordinators( self ):
+        from MaKaC.user import Avatar
+        av1 = Avatar()
+        av1.setId( "1" ) #the index needs the avatar to be uniquely identified
+        av2 = Avatar()
+        av2.setId( "2" ) #the index needs the avatar to be uniquely identified
+        from MaKaC.conference import Track
+        t1 = Track()
+        t1.setId( "1" )
+        self._idx.indexCoordinator( av1 , t1 )
+        self._idx.indexCoordinator( av2 , t1 )
+        self._idx.unindexCoordinator( av1, t1 )
+        self.assert_( t1 not in self._idx.getTracks( av1 ) )
+        self.assert_( t1 in self._idx.getTracks( av2 ) )
+    
+    def testUnindexingSeveralTracks( self ):
+        from MaKaC.user import Avatar
+        av1 = Avatar()
+        av1.setId( "1" ) #the index needs the avatar to be uniquely identified
+        from MaKaC.conference import Track
+        t1 = Track()
+        t1.setId( "1" )
+        t2 = Track()
+        t2.setId( "2" )
+        self._idx.indexCoordinator( av1 , t1 )
+        self._idx.indexCoordinator( av1 , t2 )
+        self._idx.unindexCoordinator( av1, t1 )
+        self.assert_( t1 not in self._idx.getTracks( av1 ) )
+        self.assert_( t2 in self._idx.getTracks( av1 ) )
+
+
+class TestAddTrackCoordinator( unittest.TestCase ):
+    """Tests different scenarios of the Define Track Coord use case.
+    """
+    
+    def setUp( self ):
+        from MaKaC.user import Avatar
+        cr = Avatar()
+        cr.setId( "creator" )
+        from MaKaC.conference import Conference, Track
+        self._conf = Conference( cr )
+        self._track1 = Track()
+        self._track1.setId( "1" )
+        self._conf.addTrack( self._track1 )
+        
+
+    def tearDown( self ):
+        pass
+
+    def testAddTC( self ):
+        from MaKaC.user import Avatar
+        tc1 = Avatar()
+        tc1.setId( "tc1" )
+        self._track1.addCoordinator( tc1 )
+        self.assert_( len(self._track1.getCoordinatorList()) == 1 )
+        self.assert_( tc1 in self._track1.getCoordinatorList() )
+        self.assert_( self._track1 in self._conf.getCoordinatedTracks( tc1 ) )
+
+
+class TestRemoveTrackCoordinator( unittest.TestCase ):
+    """Tests different scenarios of the Remove Track Coord use case.
+    """
+    
+    def setUp( self ):
+        from MaKaC.user import Avatar
+        cr = Avatar()
+        cr.setId( "creator" )
+        from MaKaC.conference import Conference, Track
+        self._conf = Conference( cr )
+        self._track1 = Track()
+        self._track1.setId( "1" )
+        self._conf.addTrack( self._track1 )
+        
+    def tearDown( self ):
+        pass
+
+    def testRemoveTC( self ):
+        from MaKaC.user import Avatar
+        tc1 = Avatar()
+        tc1.setId( "tc1" )
+        tc2 = Avatar()
+        tc2.setId( "tc2" )
+        self._track1.addCoordinator( tc1 )
+        self._track1.addCoordinator( tc2 )
+        self._track1.removeCoordinator( tc1 )
+        self.assert_( tc1 not in self._track1.getCoordinatorList() )
+        self.assert_( tc2 in self._track1.getCoordinatorList() )
+        self.assert_( self._track1 not in self._conf.getCoordinatedTracks( tc1 ) )
+        self.assert_( self._track1 in self._conf.getCoordinatedTracks( tc2 ) )
+
+
+class TestContributionInclusion( unittest.TestCase ):
+    
+    def setUp( self ):
+        from MaKaC.user import Avatar
+        cr = Avatar()
+        cr.setId( "creator" )
+        from MaKaC.conference import Conference, Track
+        self._conf = Conference( cr )
+        self._track1 = Track()
+        self._track1.setId( "1" )
+        self._conf.addTrack( self._track1 )
+
+    def test( self ):
+        from MaKaC.conference import Contribution
+        contrib1 = Contribution()
+        self._conf.addContribution( contrib1 )
+        self._track1.addContribution( contrib1 )
+        self.assert_( self._track1.hasContribution( contrib1 ) )
+        self.assert_( contrib1.getTrack() == self._track1 )
+        self._track1.removeContribution( contrib1 )
+        self.assert_( not self._track1.hasContribution( contrib1 ) )
+        self.assert_( contrib1.getTrack() == None )
+        
+#from testSessions.py
+class TestBasicManagement(unittest.TestCase):
+    """Tests the basic contribution management functions
+    """
+
+    def setUp( self ):
+        a = Avatar()
+        a.setId("creator")
+        self._conf = Conference( a )
+        category=conference.Category()
+        self._conf.addOwner(category)
+        self._conf.setDates(datetime(2000,1,1,tzinfo=timezone('UTC')),datetime(2020,1,1,tzinfo=timezone('UTC')))
+
+    def testDates(self):
+        session1=Session()
+        #self._conf.setStartDate(datetime(2004,1,1,8,0,tzinfo=timezone('UTC')))
+        #self._conf.setEndDate(datetime(2005,1,1,8,0,tzinfo=timezone('UTC')))
+        session1.setStartDate(datetime(2004,2,15,tzinfo=timezone('UTC')))
+        #self.assertRaises(MaKaCError,session1.setEndDate,datetime(2004,2,14,tzinfo=timezone('UTC')))
+        session1.setEndDate(datetime(2004,2,16,tzinfo=timezone('UTC')))
+        self.assert_(session1.getStartDate()==datetime(2004,2,15,tzinfo=timezone('UTC')))
+        self.assert_(session1.getEndDate()==datetime(2004,2,16,tzinfo=timezone('UTC')))
+        session1.setDates(datetime(2004,2,10,tzinfo=timezone('UTC')),datetime(2004,2,11,tzinfo=timezone('UTC')))
+        self.assert_(session1.getStartDate()==datetime(2004,2,10,tzinfo=timezone('UTC')))
+        self.assert_(session1.getEndDate()==datetime(2004,2,11,tzinfo=timezone('UTC')))
+        session1.setDates(datetime(2004,2,15,tzinfo=timezone('UTC')),datetime(2004,2,16,tzinfo=timezone('UTC')))
+        self.assert_(session1.getStartDate()==datetime(2004,2,15,tzinfo=timezone('UTC')))
+        self.assert_(session1.getEndDate()==datetime(2004,2,16,tzinfo=timezone('UTC')))
+        session1.setDates(datetime(2004,2,14,tzinfo=timezone('UTC')),datetime(2004,2,17,tzinfo=timezone('UTC')))
+        self.assert_(session1.getStartDate()==datetime(2004,2,14,tzinfo=timezone('UTC')))
+        self.assert_(session1.getEndDate()==datetime(2004,2,17,tzinfo=timezone('UTC')))
+
+    def testBasicAddAndRemove( self ):
+        session1,session2=Session(),Session()
+        self._conf.addSession(session1)
+        self.assert_(self._conf.getSessionById(session1.getId())==session1)
+        self.assert_(session1 in self._conf.getSessionList())
+        session1.delete()
+        self.assert_(session1 not in self._conf.getSessionList())
+        self.assert_(self._conf.getSessionById(session1.getId())==None)
+
+    def testDateModification(self):
+        self._conf.setDates(datetime(2004,1,1,tzinfo=timezone('UTC')),datetime(2004,1,5,tzinfo=timezone('UTC')))
+        ##checks that a session cannot be added if its dates are outside the 
+        ##   schedule boundaries
+        #s1=Session()
+        #s1.setDates(datetime(2003,12,31,tzinfo=timezone('UTC')),datetime(2004,1,31,tzinfo=timezone('UTC')))
+        #self.assertRaises(MaKaCError,self._conf.addSession,s1)
+        #s1.setDates(datetime(2004,1,1,11,0,tzinfo=timezone('UTC')),datetime(2004,1,31,tzinfo=timezone('UTC')))
+        #self.assertRaises(MaKaCError,self._conf.addSession,s1)
+        #s1.setDates(datetime(2004,1,1,11,0,tzinfo=timezone('UTC')),datetime(2004,1,4,tzinfo=timezone('UTC')))
+        #self._conf.addSession(s1)
+        #self._conf.removeSession(s1)
+        #self._conf.getSchedule().setDates(datetime(2004,1,2,tzinfo=timezone('UTC')),datetime(2004,1,7,tzinfo=timezone('UTC')))
+        #s1=Session()
+        #s1.setDates(datetime(2003,12,31,tzinfo=timezone('UTC')),datetime(2004,1,31,tzinfo=timezone('UTC')))
+        #self.assertRaises(MaKaCError,self._conf.addSession,s1)
+        #s1.setDates(datetime(2004,1,1,11,0,tzinfo=timezone('UTC')),datetime(2004,1,31,tzinfo=timezone('UTC')))
+        #self.assertRaises(MaKaCError,self._conf.addSession,s1)
+        #s1.setDates(datetime(2004,1,1,11,0,tzinfo=timezone('UTC')),datetime(2004,1,4,tzinfo=timezone('UTC')))
+        #self.assertRaises(MaKaCError,self._conf.addSession,s1)
+        #s1.setDates(datetime(2004,1,2,11,0,tzinfo=timezone('UTC')),datetime(2004,1,6,tzinfo=timezone('UTC')))
+        #self._conf.addSession(s1)
+        ##checks that when modifying the session dates to ones which are outside
+        ##   the conference schedule scope is not allowed
+        #s1.setDates(datetime(2004,1,3,tzinfo=timezone('UTC')),datetime(2004,1,5,tzinfo=timezone('UTC')))
+        #self.assertRaises(MaKaCError,s1.setDates,datetime(2004,1,3,tzinfo=timezone('UTC')),datetime(2004,1,8,tzinfo=timezone('UTC')))
+        #self.assertRaises(MaKaCError,s1.setDates,datetime(2005,1,1,11,0,tzinfo=timezone('UTC')),datetime(2004,1,6,tzinfo=timezone('UTC')))
+        #self.assertRaises(MaKaCError,s1.setDates,datetime(2005,1,1,11,0,tzinfo=timezone('UTC')),datetime(2004,1,8,tzinfo=timezone('UTC')))
+
+    def testContributionInclusion(self):
+        session1,session2=Session(),Session()
+        self._conf.addSession(session1)
+        self._conf.addSession(session2)
+        contrib1=Contribution()
+        session1.addContribution(contrib1)
+        self.assert_(self._conf.hasContribution(contrib1))
+        self.assert_(session1.hasContribution(contrib1))
+        self.assert_(not session2.hasContribution(contrib1))
+        session1.removeContribution(contrib1)
+        session2.addContribution(contrib1)
+        self.assert_(self._conf.hasContribution(contrib1))
+        self.assert_(not session1.hasContribution(contrib1))
+        self.assert_(session2.hasContribution(contrib1))
+        session2.removeContribution(contrib1)
+        self.assert_(self._conf.hasContribution(contrib1))
+        self.assert_(not session1.hasContribution(contrib1))
+        self.assert_(not session2.hasContribution(contrib1))
+
+    def testCoordination(self):
+        session1,session2,session3=Session(),Session(),Session()
+        self._conf.addSession(session1)
+        self._conf.addSession(session2)
+        c1,c2=Avatar(),Avatar()
+        c1.setId("1")
+        c2.setId("2")
+        session1.addCoordinator(c1)
+        self.assert_(c1 in session1.getCoordinatorList())
+        self.assert_(len(session1.getCoordinatorList())==1)
+        self.assert_(session1.isCoordinator(c1))
+        self.assert_(not session1.isCoordinator(c2))
+        self.assert_(not session1.isCoordinator(None))
+        self.assert_(session1 in self._conf.getCoordinatedSessions(c1))
+        self.assert_(len(self._conf.getCoordinatedSessions(c1))==1)
+        self.assert_(len(self._conf.getCoordinatedSessions(c2))==0)
+        self._conf.addSessionCoordinator(session1,c1)
+        self.assert_(c1 in session1.getCoordinatorList())
+        self.assert_(len(session1.getCoordinatorList())==1)
+        self.assert_(session1.isCoordinator(c1))
+        self.assert_(not session1.isCoordinator(c2))
+        self.assert_(not session1.isCoordinator(None))
+        self.assert_(session1 in self._conf.getCoordinatedSessions(c1))
+        self.assert_(len(self._conf.getCoordinatedSessions(c1))==1)
+        self.assert_(len(self._conf.getCoordinatedSessions(c2))==0)
+        self._conf.addSessionCoordinator(session2,c2)
+        self.assert_(c2 in session2.getCoordinatorList())
+        self.assert_(not session1.isCoordinator(c2))
+        self.assert_(session2 in self._conf.getCoordinatedSessions(c2))
+        self.assert_(len(self._conf.getCoordinatedSessions(c1))==1)
+        self.assert_(len(self._conf.getCoordinatedSessions(c2))==1)
+        self._conf.addSession(session3)
+        session3.addCoordinator(c2)
+        self.assert_(c2 in session3.getCoordinatorList())
+        self.assert_(not session1.isCoordinator(c2))
+        self.assert_(session3 in self._conf.getCoordinatedSessions(c2))
+        self.assert_(session2 in self._conf.getCoordinatedSessions(c2))
+        self.assert_(len(self._conf.getCoordinatedSessions(c1))==1)
+        self.assert_(len(self._conf.getCoordinatedSessions(c2))==2)
+        self._conf.removeSession(session1)
+        self.assert_(session1 not in self._conf.getCoordinatedSessions(c1))
+        self.assert_(len(self._conf.getCoordinatedSessions(c1))==0)
+        self.assert_(len(self._conf.getCoordinatedSessions(c2))==2)
+        session2.removeCoordinator(c2)
+        self.assert_(c2 not in session2.getCoordinatorList())
+        self.assert_(c2 in session3.getCoordinatorList())
+        self.assert_(session3 in self._conf.getCoordinatedSessions(c2))
+        self.assert_(session2 not in self._conf.getCoordinatedSessions(c2))
+        self.assert_(len(self._conf.getCoordinatedSessions(c1))==0)
+        self.assert_(len(self._conf.getCoordinatedSessions(c2))==1)
+
+
+class TestSchedule(unittest.TestCase):
+    """Tests the schedule management functions
+    """
+
+    def setUp( self ):
+        from MaKaC.user import Avatar
+        a = Avatar()
+        a.setId("creator")
+        from MaKaC.conference import Conference
+        self._conf = Conference( a )
+        category=conference.Category()
+        self._conf.addOwner(category)
+        self._conf.setTimezone('UTC')
+
+    def testTypeSetUp(self):
+        #test setting up the schedule type of a session works correctly
+        self._conf.setDates(datetime(2004,1,1,9,0,tzinfo=timezone('UTC')),datetime(2004,1,5,10,0,tzinfo=timezone('UTC')))
+        session=Session()
+        session.setStartDate(datetime(2004,1,1,9,0,tzinfo=timezone('UTC')))
+        session.setDuration(hours=10,minutes=0)
+        self._conf.addSession(session)
+        slot1=SessionSlot(session)
+        session.addSlot(slot1)
+        c1,c2,c3=Contribution(),Contribution(),Contribution()
+        session.addContribution(c1)
+        session.addContribution(c2)
+        session.addContribution(c3)
+        slot1.getSchedule().addEntry(c1.getSchEntry())
+        slot1.getSchedule().addEntry(c2.getSchEntry())
+        slot1.getSchedule().addEntry(c3.getSchEntry())
+        self.assert_(c1.getSchEntry()==slot1.getSchedule().getEntries()[0])
+        self.assert_(c2.getSchEntry()==slot1.getSchedule().getEntries()[1])
+        self.assert_(c3.getSchEntry()==slot1.getSchedule().getEntries()[2])
+        self.assert_(session.getScheduleType()=="standard")
+        self.assert_(slot1.getSchedule().__class__==conference.SlotSchedule)
+        session.setScheduleType("poster")
+        self.assert_(session.getScheduleType()=="poster")
+        self.assert_(slot1.getSchedule().__class__==conference.PosterSlotSchedule)
+        self.assert_(len(slot1.getSchedule().getEntries())==0)
+
+    def testSessionDates(self):
+        from MaKaC.conference import Session,SessionSlot, Conference
+        self._conf.setStartDate(datetime(2004,1,1,10,0,tzinfo=timezone('UTC')))
+        self._conf.setEndDate(datetime(2004,1,1,15,0,tzinfo=timezone('UTC')))
+        session1=Session()
+        session1.setStartDate(datetime(2004,1,1,10,0,tzinfo=timezone('UTC')))
+        session1.setEndDate(datetime(2004,1,1,15,0,tzinfo=timezone('UTC')))
+        self._conf.addSession(session1)
+        slot1=SessionSlot(session1)
+        slot1.setDuration(hours=2,minutes=0)
+        slot1.setStartDate(datetime(2004,1,1,10,0,tzinfo=timezone('UTC')))
+        session1.addSlot(slot1)
+        # ------- SESSIONS -------
+        #not true anymore, sessions are automatically extended
+#        # Session start date can not be bigger than the first slot start date
+#        self.assertRaises(MaKaCError, session1.setStartDate, datetime(2004,1,1,12,0,tzinfo=timezone('UTC')))
+#        # Session end date can not be prior than the last slot end date
+#        self.assertRaises(MaKaCError, session1.setEndDate, datetime(2004,1,1,11,0,tzinfo=timezone('UTC')))
+        # Session duration must be bigger than zero.
+        self.assertRaises(MaKaCError, session1.setDuration, 0,0)
+        # Session start date can not be prior than the conference end date
+        #self.assertRaises(MaKaCError, session1.setStartDate, datetime(2004,1,1,9,0,tzinfo=timezone('UTC')))
+        # Session end date can not be bigger than the conference end date
+        #self.assertRaises(MaKaCError, session1.setEndDate, datetime(2004,1,1,15,1,tzinfo=timezone('UTC')))
+        # Session end date can not be bigger than the conference end date
+        #self.assertRaises(MaKaCError, session1.setDuration, 6,1)
+
+        # ------- SESSION SLOTS -------
+        self._conf.setStartDate(datetime(2004,1,1,10,0,tzinfo=timezone('UTC')))
+        self._conf.setEndDate(datetime(2004,1,1,15,0,tzinfo=timezone('UTC')))
+        session1.setStartDate(datetime(2004,1,1,10,0,tzinfo=timezone('UTC')))
+        session1.setEndDate(datetime(2004,1,1,15,0,tzinfo=timezone('UTC')))
+        # Session slot duration must be bigger than zero.
+        self.assertRaises(MaKaCError, slot1.setDuration, 0,0,0)
+        # Forbid to create a slot alogn several days
+        self._conf.setEndDate(datetime(2005,1,1,15,0,tzinfo=timezone('UTC')))
+        self.assertRaises(MaKaCError, slot1.setDuration, 1,0,1)
+        # Slot start date has to be between the session ones
+        #self.assertRaises(MaKaCError, slot1.setStartDate, datetime(2004,1,1,9,59,tzinfo=timezone('UTC')))
+        # Slot end date has to be between the session ones
+        #self.assertRaises(MaKaCError, slot1.setDuration, 0,5,1)
+        # If the duration is modified and any of the slot entries is affected then an excetpion is raised
+        c1,c2,c3=Contribution(),Contribution(),Contribution()
+        session1.addContribution(c1)
+        session1.addContribution(c2)
+        session1.addContribution(c3)
+        c1.setDuration(0,30)
+        c2.setDuration(0,30)
+        c3.setDuration(0,30)
+        from MaKaC.schedule import BreakTimeSchEntry
+        b1=BreakTimeSchEntry()
+        slot1.getSchedule().addEntry(c1.getSchEntry())
+        slot1.getSchedule().addEntry(c2.getSchEntry())
+        slot1.getSchedule().addEntry(c3.getSchEntry())
+        self.assertRaises(MaKaCError, slot1.setDuration, 0,1,29)
+        # Check that the duration of the entries do not overpass the slot duration
+        slot1.setDuration(hours=1,minutes=30)
+        #self.assertRaises(MaKaCError,c3.setDuration,0,31)
+        c3.setDuration(0,30)
+        slot1.setDuration(hours=2,minutes=0)
+        slot1.getSchedule().addEntry(b1)
+        #self.assertRaises(MaKaCError,b1.setDuration,0,31)
+        #Check that entries start date is not less than owner start date
+        #self.assertRaises(MaKaCError,c1.setStartDate,datetime(2004,1,1,9,59,tzinfo=timezone('UTC')))
+        #self.assertRaises(MaKaCError,b1.setStartDate,datetime(2004,1,1,9,59,tzinfo=timezone('UTC')))
+        #Move all the entries
+        slot3=SessionSlot(session1)
+        slot3.setStartDate(datetime(2004,1,1,10,0,tzinfo=timezone('UTC')))
+        slot3.setDuration(hours=3,minutes=0)        
+        session1.addSlot(slot3)
+        c4,c5=Contribution(),Contribution()
+        session1.addContribution(c4)
+        session1.addContribution(c5)
+        c4.setTitle("campeon")
+        c5.setTitle("campeonisimo")
+        c4.setStartDate(datetime(2004,1,1,11,0,tzinfo=timezone('UTC')))
+        c4.setDuration(0,30)
+        c5.setDuration(0,30)        
+        b2=BreakTimeSchEntry()
+        b2.setDuration(0,30)
+        b2.setTitle("breaaaaaaak")
+        slot3.getSchedule().addEntry(c4.getSchEntry())
+        slot3.getSchedule().addEntry(c5.getSchEntry())
+        slot3.getSchedule().addEntry(b2)
+        self.assert_(c4.getStartDate() == datetime(2004,1,1,11,0,tzinfo=timezone('UTC')))
+        slot3.setStartDate(datetime(2004,1,1,11,0,tzinfo=timezone('UTC')))
+        #self.assert_(c4.getStartDate() == datetime(2004,1,1,12,0,tzinfo=timezone('UTC')))
+        
+
+        # ------- CONFERENCE -------
+        # Conference should not start after a entry
+        #self.assertRaises(MaKaCError,self._conf.setStartDate,datetime(2004,1,1,10,1,tzinfo=timezone('UTC')))
+        # Conference should not finish before a entry
+        #self.assertRaises(MaKaCError,self._conf.setEndDate,datetime(2004,1,1,14,59,tzinfo=timezone('UTC')))
+        # Conference should not start after a entry (TIME)
+        #self.assertRaises(MaKaCError,self._conf.setStartTime,10,1)
+        # Conference should not finish before a entry (TIME)
+        self._conf.setStartDate(datetime(2004,1,1,10,0,tzinfo=timezone('UTC')))
+        self._conf.setEndDate(datetime(2005,1,1,18,0,tzinfo=timezone('UTC')))
+        session2=Session()
+        self._conf.addSession(session2)
+        session2.setStartDate(datetime(2004,1,1,10,0,tzinfo=timezone('UTC')))
+        session2.setEndDate(datetime(2005,1,1,18,0,tzinfo=timezone('UTC')))
+        slot2=SessionSlot(session2)
+        slot2.setDuration(hours=2,minutes=0)
+        slot2.setStartDate(datetime(2004,1,1,10,0,tzinfo=timezone('UTC')))
+        session2.addSlot(slot2)
+        #self.assertRaises(MaKaCError,self._conf.setEndTime,17,59)
+        
+
+    def testSlots(self):
+        self._conf.setDates(datetime(2004,1,1,9,0,tzinfo=timezone('UTC')),datetime(2004,1,5,10,0,tzinfo=timezone('UTC')))
+        session1=Session()
+        session1.setStartDate(datetime(2004,1,1,9,0,tzinfo=timezone('UTC')))
+        session1.setDuration(hours=10,minutes=0)
+        self._conf.addSession(session1)
+        slot1=SessionSlot(session1)
+        slot1.setDuration(hours=2,minutes=0)
+        session1.addSlot(slot1)
+        self.assert_(slot1.getSessionSchEntry() in session1.getSchedule().getEntries())
+        self.assert_(slot1.getStartDate()==session1.getStartDate())
+        self.assert_(slot1.getDuration().seconds==7200)
+        slot2=SessionSlot(session1)
+        slot2.setDuration(hours=2,minutes=0)
+        session1.addSlot(slot2)
+        self.assert_(slot1.getSessionSchEntry()==session1.getSchedule().getEntries()[0])
+        self.assert_(slot1.getStartDate()==session1.getStartDate())
+        self.assert_(slot1.getDuration().seconds==7200)
+        self.assert_(slot2.getSessionSchEntry()==session1.getSchedule().getEntries()[1])
+        self.assert_(slot2.getStartDate()==datetime(2004,1,1,11,0,tzinfo=timezone('UTC')))
+        self.assert_(slot2.getDuration().seconds==7200)
+        slot2.setStartDate(datetime(2004,1,1,15,0,tzinfo=timezone('UTC')))
+        self.assert_(slot1.getSessionSchEntry()==session1.getSchedule().getEntries()[0])
+        self.assert_(slot1.getStartDate()==session1.getStartDate())
+        self.assert_(slot1.getDuration().seconds==7200)
+        self.assert_(slot2.getSessionSchEntry()==session1.getSchedule().getEntries()[1])
+        self.assert_(slot2.getStartDate()==datetime(2004,1,1,15,0,tzinfo=timezone('UTC')))
+        self.assert_(slot2.getDuration().seconds==7200)
+        slot1.setStartDate(datetime(2004,1,1,10,0,tzinfo=timezone('UTC')))
+        slot2.setStartDate(datetime(2004,1,1,9,0,tzinfo=timezone('UTC')))
+        self.assert_(slot2.getStartDate()==datetime(2004,1,1,9,0,tzinfo=timezone('UTC')))
+        #slot1.setStartDate(datetime(2004,1,1,11,0,tzinfo=timezone('UTC')))
+        #slot2.setStartDate(datetime(2004,1,1,10,0,tzinfo=timezone('UTC')))
+        self.assert_(slot1.getSessionSchEntry()==session1.getSchedule().getEntries()[1])
+        self.assert_(slot1.getDuration().seconds==7200)
+        self.assert_(slot2.getSessionSchEntry()==session1.getSchedule().getEntries()[0])
+        self.assert_(slot2.getStartDate()==datetime(2004,1,1,9,0,tzinfo=timezone('UTC')))
+        self.assert_(slot2.getDuration().seconds==7200)
+
+    def testContributions(self):
+        self._conf.setDates(datetime(2004,1,1,9,0,tzinfo=timezone('UTC')),datetime(2004,1,5,10,0,tzinfo=timezone('UTC')))
+        from MaKaC.conference import Session,Contribution,SessionSlot
+        self._conf.setStartDate(datetime(2004,1,1,10,0,tzinfo=timezone('UTC')))
+        self._conf.setEndDate(datetime(2005,1,1,10,0,tzinfo=timezone('UTC')))
+        session1=Session()
+        self._conf.addSession(session1)
+        session1.setStartDate(datetime(2004,1,1,10,0,tzinfo=timezone('UTC')))
+        session1.setDuration(hours=5,minutes=0)
+        slot1=SessionSlot(session1)
+        slot1.setDuration(hours=2,minutes=0)
+        session1.addSlot(slot1)
+        slot2=SessionSlot(session1)
+        slot2.setDuration(hours=2,minutes=0)
+        session1.addSlot(slot2)
+        self.assert_(slot2.getStartDate()==datetime(2004,1,1,12,0,tzinfo=timezone('UTC')))
+        c1,c2,c3=Contribution(),Contribution(),Contribution()
+        session1.addContribution(c1)
+        session1.addContribution(c2)
+        session1.addContribution(c3)
+        c1.setDuration(0,30)
+        c2.setDuration(0,30)
+        c3.setDuration(0,30)
+        from MaKaC.errors import MaKaCError
+        #self.assertRaises(MaKaCError,slot1.getSchedule().addEntry,c1.getSchEntry())
+        slot1.getSchedule().addEntry(c1.getSchEntry())
+        slot1.getSchedule().addEntry(c2.getSchEntry())
+        slot1.getSchedule().addEntry(c3.getSchEntry())
+        self.assert_(c1.getStartDate()==datetime(2004,1,1,10,0,tzinfo=timezone('UTC')))
+        self.assert_(c2.getStartDate()==datetime(2004,1,1,10,30,tzinfo=timezone('UTC')))
+        self.assert_(c3.getStartDate()==datetime(2004,1,1,11,0,tzinfo=timezone('UTC')))
+        #slot2.getSchedule().addEntry(c1.getSchEntry())
+        #self.assert_(c1.getStartDate()==datetime(2004,1,1,12,0,tzinfo=timezone('UTC')))
+        #self.assert_(c2.getStartDate()==datetime(2004,1,1,10,30,tzinfo=timezone('UTC')))
+        #self.assert_(c3.getStartDate()==datetime(2004,1,1,11,0,tzinfo=timezone('UTC')))
+        from MaKaC.schedule import BreakTimeSchEntry
+        b1=BreakTimeSchEntry()
+        slot1.getSchedule().addEntry(b1)
+        self.assert_(b1 in slot1.getSchedule().getEntries())
+        #self.assert_(b1.getStartDate()==datetime(2004,1,1,10,0,tzinfo=timezone('UTC')))
+
+    def testMoveScheduledContribToSession(self):
+        #tests that moving scheduled contributions at conference level into a 
+        #   session works correctly: removes them from the conference schedule
+        #   and includes them into the selected session
+        self._conf.setDates(datetime(2004,1,1,9,0,tzinfo=timezone('UTC')),datetime(2004,1,5,10,0,tzinfo=timezone('UTC')))
+        session1=Session()
+        session1.setStartDate(datetime(2004,1,1,9,0,tzinfo=timezone('UTC')))
+        session1.setDuration(hours=1,minutes=0)
+        self._conf.addSession(session1)
+        c1,c2=Contribution(),Contribution()
+        self._conf.addContribution(c1)
+        self._conf.addContribution(c2)
+        self._conf.getSchedule().addEntry(c1.getSchEntry())
+        self._conf.getSchedule().addEntry(c2.getSchEntry())
+        self.assert_(c1.isScheduled())
+        self.assert_(c2.isScheduled())
+        session1.addContribution(c1)
+        self.assert_(not c1.isScheduled())
+        self.assert_(c2.isScheduled())
+
+
+class TestPosterSchedule(unittest.TestCase):
+    """Tests the schedule for posters like schedules management functions
+    """
+
+    def setUp( self ):
+        a=Avatar()
+        a.setId("creator")
+        self._conf=Conference(a)
+        category=conference.Category()
+        self._conf.addOwner(category)
+        self._conf.setTimezone('UTC')
+        self._conf.setStartDate(datetime(2004,1,1,10,0,tzinfo=timezone('UTC')))
+        self._conf.setEndDate(datetime(2004,1,1,13,0,tzinfo=timezone('UTC')))
+        self._session=Session()
+        self._session.setStartDate(datetime(2004,1,1,11,0,tzinfo=timezone('UTC')))
+        self._session.setEndDate(datetime(2004,1,1,13,0,tzinfo=timezone('UTC')))
+        self._conf.addSession(self._session)
+        self._slot1=SessionSlot(self._session)
+        self._slot1.setStartDate(datetime(2004,1,1,11,0,tzinfo=timezone('UTC')))
+        self._slot1.setDuration(hours=1)
+        self._session.addSlot(self._slot1)
+        self._session.setScheduleType("poster")
+        self._session.setContribDuration(1,0)
+
+    def testBasic(self):
+        #tests the basic adding of entries to a poster like timetable
+        p1,p2,p3=Contribution(),Contribution(),Contribution()
+        self._session.addContribution(p1)
+        self._session.addContribution(p2)
+        self._session.addContribution(p3)
+        self._slot1.getSchedule().addEntry(p1.getSchEntry())
+        self._slot1.getSchedule().addEntry(p2.getSchEntry())
+        self._slot1.getSchedule().addEntry(p3.getSchEntry())
+        self.assert_(p1.getDuration()==self._session.getContribDuration())
+        self.assert_(p2.getDuration()==self._session.getContribDuration())
+        self.assert_(p3.getDuration()==self._session.getContribDuration())
+        self.assert_(p1.getStartDate()==self._slot1.getStartDate())
+        self.assert_(p2.getStartDate()==self._slot1.getStartDate())
+        self.assert_(p3.getStartDate()==self._slot1.getStartDate())
+        self.assert_(p1.getSchEntry()==self._slot1.getSchedule().getEntries()[0])
+        self.assert_(p2.getSchEntry()==self._slot1.getSchedule().getEntries()[1])
+        self.assert_(p3.getSchEntry()==self._slot1.getSchedule().getEntries()[2])
+        self._session.removeContribution(p2)
+        self.assert_(p1.getDuration()==self._session.getContribDuration())
+        self.assert_(p3.getDuration()==self._session.getContribDuration())
+        self.assert_(p1.getStartDate()==self._slot1.getStartDate())
+        self.assert_(p3.getStartDate()==self._slot1.getStartDate())
+        self.assert_(p1.getSchEntry()==self._slot1.getSchedule().getEntries()[0])
+        self.assert_(p3.getSchEntry()==self._slot1.getSchedule().getEntries()[1])
+
+    def testStartDateNotChanging(self):
+        #tests that changing the start date of an entry scheduled within a
+        #   poster schedule has no effect
+        p1=Contribution()
+        self._session.addContribution(p1)
+        self._slot1.getSchedule().addEntry(p1.getSchEntry())
+        self.assert_(p1.getStartDate()==datetime(2004,1,1,11,0,tzinfo=timezone('UTC')))
+        p1.setStartDate(datetime(2004,1,1,11,25,tzinfo=timezone('UTC')))
+        self.assert_(p1.getStartDate()==datetime(2004,1,1,11,0,tzinfo=timezone('UTC')))
+
+    def testChangeSlotStartDate(self):
+        #checks that changing the start date of a slot changes all the entries'
+        p1,p2=Contribution(),Contribution()
+        self._session.addContribution(p1)
+        self._session.addContribution(p2)
+        self._slot1.getSchedule().addEntry(p1.getSchEntry())
+        self._slot1.getSchedule().addEntry(p2.getSchEntry())
+        self.assert_(p1.getStartDate()==datetime(2004,1,1,11,0,tzinfo=timezone('UTC')))
+        self.assert_(p2.getStartDate()==datetime(2004,1,1,11,0,tzinfo=timezone('UTC')))
+        self._slot1.setStartDate(datetime(2004,1,1,11,25,tzinfo=timezone('UTC')))
+        #self.assert_(p1.getStartDate()==datetime(2004,1,1,11,25,tzinfo=timezone('UTC')))
+        #self.assert_(p2.getStartDate()==datetime(2004,1,1,11,25,tzinfo=timezone('UTC')))
+
+class TestCoordinatorsIndexComponent(unittest.TestCase):
+    """
+    """
+
+    def setUp( self ):
+        pass
+
+    def test(self):
+        idx=SCIndex()
+        c1=Avatar()
+        c1.setId("1")
+        s1=Session()
+        idx.index(c1,s1)
+        self.assert_(s1 in idx.getSessions(c1))
+        self.assert_(len(idx.getSessions(c1))==1)
+        c2=Avatar()
+        c2.setId("2")
+        idx.index(c2,s1)
+        self.assert_(s1 in idx.getSessions(c1))
+        self.assert_(len(idx.getSessions(c1))==1)
+        self.assert_(s1 in idx.getSessions(c2))
+        self.assert_(len(idx.getSessions(c2))==1)
+        s2=Session()
+        idx.index(c2,s2)
+        self.assert_(s1 in idx.getSessions(c1))
+        self.assert_(len(idx.getSessions(c1))==1)
+        self.assert_(s1 in idx.getSessions(c2))
+        self.assert_(s2 in idx.getSessions(c2))
+        self.assert_(len(idx.getSessions(c2))==2)
+        idx.unindex(c2,s2)
+        self.assert_(s1 in idx.getSessions(c1))
+        self.assert_(len(idx.getSessions(c1))==1)
+        self.assert_(s1 in idx.getSessions(c2))
+        self.assert_(s2 not in idx.getSessions(c2))
+        self.assert_(len(idx.getSessions(c2))==1)
+        
+        
+#from testWebInterface.py should be renamed to testContributions.py anyway
+"""Contains tests regarding some scenarios related to contribution list display.
+"""
+class TestContributionList(unittest.TestCase):
+    """Tests the contribution list functions
+    """
+
+    def setUp( self ):
+        from MaKaC.user import Avatar
+        a = Avatar()
+        a.setId("creator")
+        from MaKaC.conference import Conference
+        self._conf=Conference(a)
+        category=conference.Category()
+        self._conf.addOwner(category)
+        self._conf.setTimezone('UTC')
+        self._conf.setDates(datetime(2000,1,1,tzinfo=timezone('UTC')),datetime(2020,1,1,tzinfo=timezone('UTC')))
+
+    def testSorting( self ):
+        from MaKaC.conference import Contribution, ContributionType, Session, Track
+        from MaKaC.webinterface.common import contribFilters
+        from MaKaC.common.filters import SimpleFilter
+        contrib1 = Contribution()
+        contrib2 = Contribution()
+        contrib3 = Contribution()
+        self._conf.addContribution( contrib1 )
+        self._conf.addContribution( contrib2 )
+        self._conf.addContribution( contrib3 )
+        # Sorting by ID
+        sortingCrit = contribFilters.SortingCriteria( ["number"] )
+        f = SimpleFilter( None, sortingCrit )
+        contribList = f.apply(self._conf.getContributionList())
+        self.assert_( len(contribList) == 3 )
+        self.assert_( contribList[0] == contrib1 )
+        self.assert_( contribList[1] == contrib2 )
+        self.assert_( contribList[2] == contrib3 )
+        #Sorting by Date
+        contrib1.setStartDate(datetime(2004, 5, 1, 10, 30,tzinfo=timezone('UTC')))
+        contrib2.setStartDate(datetime(2003, 5, 1, 10, 30,tzinfo=timezone('UTC')))
+        sortingCrit = contribFilters.SortingCriteria( ["date"] )
+        f = SimpleFilter( None, sortingCrit )
+        contribList = f.apply(self._conf.getContributionList())
+        self.assert_( len(contribList) == 3 )
+        self.assert_( contribList[0] == contrib2 )
+        self.assert_( contribList[1] == contrib1 )
+        self.assert_( contribList[2] == contrib3 )
+        # Sorting by Contribution Type
+        contribType1 = ContributionType("oral presentation", "no description", self._conf)
+        contribType2 = ContributionType("poster", "no description", self._conf)
+        contrib1.setType(contribType1)
+        contrib2.setType(contribType2)
+        sortingCrit = contribFilters.SortingCriteria( ["type"] )
+        f = SimpleFilter( None, sortingCrit )
+        contribList = f.apply(self._conf.getContributionList())
+        self.assert_( len(contribList) == 3 )
+        self.assert_( contribList[0] == contrib1 )
+        self.assert_( contribList[1] == contrib2 )
+        self.assert_( contribList[2] == contrib3 )
+        # Sorting by Session
+        session1 = Session()
+        self._conf.addSession(session1)
+        session2 = Session()
+        self._conf.addSession(session2)
+        contrib1.setSession(session1)
+        contrib2.setSession(session2)
+        sortingCrit = contribFilters.SortingCriteria( ["session"] )
+        f = SimpleFilter( None, sortingCrit )
+        contribList = f.apply(self._conf.getContributionList())
+        self.assert_( len(contribList) == 3 )
+        self.assert_(contrib1 in contribList)
+        self.assert_(contrib2 in contribList)
+        self.assert_(contrib3 in contribList)
+        # Sorting by Track
+        track1 = Track()
+        track1.setTitle("3")
+        track1.setConference(self._conf)
+        track2 = Track()
+        track2.setTitle("1")
+        track2.setConference(self._conf)
+        contrib1.setTrack(track1)
+        contrib2.setTrack(track2)
+        sortingCrit = contribFilters.SortingCriteria( ["track"] )
+        f = SimpleFilter( None, sortingCrit )
+        contribList = f.apply(self._conf.getContributionList())
+        self.assert_( len(contribList) == 3 )
+        self.assert_( contribList[0] == contrib2 )
+        self.assert_( contribList[1] == contrib1 )
+        self.assert_( contribList[2] == contrib3 )
+        
Index: indicop/python/unit/MaKaC_tests/fileRepository_test.py
===================================================================
--- indicop/python/unit/MaKaC_tests/fileRepository_test.py	(revision b05fd7f86fb7ba6ddb22bcab445d80cd9c24d90c)
+++ indicop/python/unit/MaKaC_tests/fileRepository_test.py	(revision b05fd7f86fb7ba6ddb22bcab445d80cd9c24d90c)
@@ -0,0 +1,104 @@
+# -*- coding: utf-8 -*-
+##
+## $Id: testFileSubmission.py,v 1.2 2008/04/24 16:59:58 jose Exp $
+##
+## This file is part of CDS Indico.
+## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 CERN.
+##
+## CDS Indico is free software; you can redistribute it and/or
+## modify it under the terms of the GNU General Public License as
+## published by the Free Software Foundation; either version 2 of the
+## License, or (at your option) any later version.
+##
+## CDS Indico is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with CDS Indico; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+"""Contains tests regarding some scenarios related to submission and archiving
+of files.
+"""
+
+import unittest
+from MaKaC.common.db import DBMgr
+import os
+
+
+def setup_module():
+    DBMgr.getInstance().startRequest()
+
+def teardown_module():
+    DBMgr.getInstance().abort()
+    DBMgr.getInstance().endRequest()
+
+class TestMaterialRepository(unittest.TestCase):
+    """Tests the basic functionalities of the MaterialLocalRepository file 
+        repository.
+    """
+
+    def setUp( self ):
+        self._archivePath = os.path.join( os.getcwd(), "tmpArchive" )
+        #create a directory where the archive will be set up
+        try:
+            os.mkdir( self._archivePath )
+        except OSError, e:
+            #print e
+            pass
+        #the MaterialLocalRepository takes the repository base path from
+        #   the system configuration so we have to set it up to the new dir
+        from MaKaC.common import Config
+        cfg = Config.getInstance()
+        #we overrride the system repository path with the temp one
+        cfg._archivePath = self._archivePath
+
+    def tearDown( self ):
+        #delete the temporary archive space and all the files below
+        #os.removedirs( self._archivePath )
+        for root, dirs, files in os.walk(self._archivePath, topdown=False):
+            for name in files:
+                os.remove(os.path.join(root, name))
+            for name in dirs:
+                os.rmdir(os.path.join(root, name))
+        try:
+            os.rmdir(os.path.join( os.getcwd(), "tmpArchive" ))
+            os.remove(os.path.join( os.getcwd(), "test.txt" ))
+        except:
+            pass
+
+#this test needs to be executed from root indico dir
+#    def testRepositoryPath( self ):
+#        """Makes sure it is taking the path from the system configuration
+#        """
+#        from MaKaC.fileRepository import MaterialLocalRepository
+#        fr = MaterialLocalRepository()
+#        self.assertEqual( fr.getRepositoryPath(), self._archivePath )
+
+    def testArchiveConferenceFile( self ):
+        """Makes sure a file wich is attached to a conference gets stored in 
+            the right path: basePath/year/C0/0/test.txt
+        """
+        #first we create a dummy user which will be the conf creator
+        from MaKaC.user import Avatar
+        av = Avatar()
+        #Now we create a dummy conference and set its id to 0
+        from MaKaC.conference import Conference
+        c = Conference( av )
+        c.setId( "0" )
+        #Now we create the material (id=0) and attach it to the conference
+        from MaKaC.conference import Material
+        m = Material()
+        c.addMaterial( m )
+        #Now we create a dummy file and attach it to the material
+        filePath = os.path.join( os.getcwd(), "test.txt" )
+        fh = open(filePath, "w")
+        fh.write("hola")
+        fh.close()
+        from MaKaC.conference import LocalFile
+        f = LocalFile()
+        f.setFilePath( filePath )
+        f.setFileName( "test.txt" )
+        m.addResource( f )
Index: indicop/python/unit/MaKaC_tests/review_test.py
===================================================================
--- indicop/python/unit/MaKaC_tests/review_test.py	(revision b05fd7f86fb7ba6ddb22bcab445d80cd9c24d90c)
+++ indicop/python/unit/MaKaC_tests/review_test.py	(revision b05fd7f86fb7ba6ddb22bcab445d80cd9c24d90c)
@@ -0,0 +1,612 @@
+# -*- coding: utf-8 -*-
+##
+## $Id: review_test.py,v 1.20 2008/04/24 16:59:57 jose Exp $
+##
+## This file is part of CDS Indico.
+## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 CERN.
+##
+## CDS Indico is free software; you can redistribute it and/or
+## modify it under the terms of the GNU General Public License as
+## published by the Free Software Foundation; either version 2 of the
+## License, or (at your option) any later version.
+##
+## CDS Indico is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with CDS Indico; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+"""Contains tests about some typical "call for abstracts" scenarios.
+"""
+
+import unittest
+
+import MaKaC.user as user
+import MaKaC.conference as conference
+import MaKaC.review as review
+import MaKaC.errors as errors
+
+from datetime import datetime
+from pytz import timezone
+from MaKaC.common.db import DBMgr
+
+def setup_module():
+    DBMgr.getInstance().startRequest()
+
+def teardown_module():
+    DBMgr.getInstance().abort()
+    DBMgr.getInstance().endRequest()
+    
+class TestCFADirectives( unittest.TestCase ):
+    """Tests the setting of the main CFA directives.
+    """
+
+    def setUp( self ):
+        av = user.Avatar()
+        self._conf = conference.Conference( av )
+        self._tz=timezone('UTC')
+        self._conf.setTimezone('UTC')
+
+    def testEnableCFA( self ):
+        cfa = self._conf.getAbstractMgr()
+        #by default the CFA must be disabled
+        self.assert_( not cfa.isActive() )
+        #we enable it, so it must be enabled
+        cfa.activeCFA()
+        self.assert_( cfa.isActive() )
+        #and now we deactivate it
+        cfa.desactiveCFA()
+        self.assert_( not cfa.isActive() )
+
+    def testSubmissionPeriod( self ):
+        cfa = self._conf.getAbstractMgr()
+        #we set up the submission period 
+        startDate = datetime(2004, 01, 01, tzinfo=self._tz)
+        endDate = datetime(2004, 01, 03, tzinfo=self._tz)
+        cfa.setStartSubmissionDate( startDate )
+        cfa.setEndSubmissionDate( endDate )
+        #we check a date within the submission period
+        id = datetime(2004, 01, 02, tzinfo=self._tz)
+        self.assert_( cfa.inSubmissionPeriod( id ) )
+        #check for a date in the limit of the submission period
+        id = datetime(2004, 01, 01, 0, 0, 0, tzinfo=self._tz)
+        self.assert_( cfa.inSubmissionPeriod( id ) )
+        id = datetime(2004, 01, 03, 23, 59, 59, tzinfo=self._tz)
+        self.assert_( cfa.inSubmissionPeriod( id ) )
+        #check for dates outside the submission period
+        id = datetime(2003, 12, 31, 23, 59, 59, tzinfo=self._tz)
+        self.assert_( not cfa.inSubmissionPeriod( id ) )
+        id = datetime(2004, 01, 04, 00, 00, 00, tzinfo=self._tz)
+        self.assert_( not cfa.inSubmissionPeriod( id ) )
+        id = datetime(2005, 01, 04, 00, 00, 00, tzinfo=self._tz)
+        self.assert_( not cfa.inSubmissionPeriod( id ) )
+
+
+class TestAbstractSubmission( unittest.TestCase ):
+    """Tests different abstract submission scenarios
+    """
+
+    def setUp( self ):
+        av = user.Avatar()
+        self._conf = conference.Conference( av )
+        self._track1 = self._conf.newTrack()
+        self._track2 = self._conf.newTrack()
+        self._track3 = self._conf.newTrack()
+
+    def testSimpleSubmission( self ):
+        submitter = user.Avatar()
+        submitter.setId( "submitter" )
+        #creation of a new abstract
+        a = self._conf.getAbstractMgr().newAbstract( submitter )
+        #setting of abstract tracks
+        a.setTracks( [self._track1, self._track2] )
+        #checking that the abstract is in the conference and its status is
+        # submitted
+        self.assert_( a in self._conf.getAbstractMgr().getAbstractList() )
+        self.assert_( isinstance( a.getCurrentStatus(), review.AbstractStatusSubmitted ) )
+        #checking that the abstract tracks are correctly set up
+        self.assert_( a.isProposedForTrack( self._track1 ) )
+        self.assert_( a.isProposedForTrack( self._track2 ) )
+        self.assert_( not a.isProposedForTrack( self._track3 ) )
+        #checking that the abstract is included in the track abstract list
+        self.assert_( a.isProposedForTrack( self._track1 ) )
+        self.assert_( a.isProposedForTrack( self._track2 ) )
+        self.assert_( not a.isProposedForTrack( self._track3 ) )
+        #checking that the submitter is the abstract submitter
+        self.assert_( a.isSubmitter( submitter ) )
+        #checking access privileges
+        #checking modification privileges
+    
+
+class TestAbstractModification( unittest.TestCase ):
+    """Tests different abstract modification scenarios
+    """
+    def setUp( self ):
+        av = user.Avatar()
+        self._conf = conference.Conference( av )
+        self._track1 = self._conf.newTrack()
+        self._track2 = self._conf.newTrack()
+        self._track3 = self._conf.newTrack()
+        submitter = user.Avatar()
+        submitter.setId( "submitter" )
+        self._abstract = self._conf.getAbstractMgr().newAbstract( submitter )
+
+
+    def testTrackAssignment( self ):
+        #checks that abstract deal correclty with assigned tracks
+        #setting the track assignment
+        self._abstract.setTracks( [self._track1, self._track2] )
+        self.assert_( self._abstract.isProposedForTrack( self._track1 ) )
+        self.assert_( self._abstract.isProposedForTrack( self._track2 ) )
+        #changing the track assignment
+        self._abstract.setTracks( [self._track3, self._track2] )
+        self.assert_( not self._abstract.isProposedForTrack( self._track1 ) )
+        self.assert_( self._abstract.isProposedForTrack( self._track2 ) )
+        self.assert_( self._abstract.isProposedForTrack( self._track3 ) )
+        #removing of single tracks
+        self._abstract.removeTrack( self._track1 )
+        self.assert_( len( self._abstract.getTrackList() ) == 2 )
+        self._abstract.removeTrack( self._track2 )
+        self.assert_( not self._abstract.isProposedForTrack( self._track1 ) )
+        self.assert_( not self._abstract.isProposedForTrack( self._track2 ) )
+        self.assert_( self._track3 in self._abstract.getTrackList() )
+        #adding single tracks
+        self._abstract.addTrack( self._track3 )
+        self.assert_( len( self._abstract.getTrackList() ) == 1 )
+        self._abstract.addTrack( self._track1 )
+        self.assert_( self._abstract.isProposedForTrack( self._track1 ) )
+        self.assert_( not self._abstract.isProposedForTrack( self._track2 ) )
+        self.assert_( self._abstract.isProposedForTrack( self._track3 ) )
+
+
+class TestAbstractAcceptation( unittest.TestCase ):
+    """Tests different abstract acceptation scenarios
+    """
+    def setUp( self ):
+        av = user.Avatar()
+        self._conf = conference.Conference( av )
+        self._ctOral = conference.ContributionType("oral", "", self._conf)
+        self._ctPoster = conference.ContributionType("poster", "", self._conf)
+        self._conf.addContribType( self._ctOral )
+        self._conf.addContribType( self._ctPoster )
+        self._track1 = self._conf.newTrack()
+        self._track2 = self._conf.newTrack()
+        self._track3 = self._conf.newTrack()
+        submitter = user.Avatar()
+        submitter.setId( "submitter" )
+        self._abstract = self._conf.getAbstractMgr().newAbstract( submitter )
+
+    def testBasicAcceptation( self ):
+        self._abstract.setTitle( "test_title" )
+        self._abstract.setField("content", "test_content" )
+        self._abstract.setContribType( self._ctPoster )
+        auth1 = self._abstract.newPrimaryAuthor()
+        auth1.setData( firstName="test1_fn", surName="test1_sn",
+                        email="test1_email", affiliation="test1_af",
+                        address="test1_add", telephone="test1_phone",
+                        fax = "test1_fax", title="test1_title" )
+        self._abstract.addSpeaker( auth1 )
+        auth2 = self._abstract.newCoAuthor()
+        auth2.setData( firstName="test2_fn", surName="test2_sn",
+                        email="test2_email", affiliation="test2_af",
+                        address="test2_add", telephone="test2_phone",
+                        fax = "test2_fax", title="test2_title" )
+        #accepting an abstract for a certain track
+        self._abstract.setTracks( [self._track1, self._track2] )
+        res1 = user.Avatar()
+        res1.setId( "res1" )
+        self._abstract.accept( res1, self._track1, self._ctOral )
+        #check the status is changed to accept
+        status = self._abstract.getCurrentStatus()
+        self.assert_( isinstance(status, review.AbstractStatusAccepted) )
+        #check the track
+        self.assert_( status.getTrack() == self._track1 )
+        #check that a contribution has been created and has exactly the same
+        #   data
+        contrib = status.getContribution()
+        self.assert_( contrib.getId() == self._abstract.getId() )
+        self.assert_( contrib.getConference() == self._conf )
+        self.assert_( contrib.getAbstract() == self._abstract )
+        self.assert_( contrib in self._conf.getContributionList() )
+        self.assert_( contrib.getTrack() == status.getTrack() )
+        self.assert_( contrib.getTitle() == "test_title" )
+        self.assert_( contrib.getDescription() == "test_content" )
+        self.assert_( contrib.getType() == self._ctOral )
+        c_auth = contrib.getPrimaryAuthorList()[0]
+        self.assert_( c_auth.getTitle() == auth1.getTitle() )
+        self.assert_( c_auth.getFirstName() == auth1.getFirstName() )
+        self.assert_( c_auth.getFamilyName() == auth1.getSurName() )
+        self.assert_( c_auth.getEmail() == auth1.getEmail() )
+        self.assert_( c_auth.getAffiliation() == auth1.getAffiliation() )
+        self.assert_( c_auth.getAddress() == auth1.getAddress() )
+        self.assert_( c_auth.getPhone() == auth1.getTelephone() )
+        self.assert_( len( contrib.getSpeakerList() ) == 1 )
+        self.assert_( contrib.isSpeaker( c_auth )  )
+        c_auth = contrib.getCoAuthorList()[0]
+        self.assert_( c_auth.getTitle() == auth2.getTitle() )
+        self.assert_( c_auth.getFirstName() == auth2.getFirstName() )
+        self.assert_( c_auth.getFamilyName() == auth2.getSurName() )
+        self.assert_( c_auth.getEmail() == auth2.getEmail() )
+        self.assert_( c_auth.getAffiliation() == auth2.getAffiliation() )
+        self.assert_( c_auth.getAddress() == auth2.getAddress() )
+        self.assert_( c_auth.getPhone() == auth2.getTelephone() )
+
+    def testIdCollission( self ):
+        #checks that no collission with contributions can happen regarding 
+        #   the ids
+        contrib=conference.Contribution()
+        self._conf.addContribution(contrib)
+        res1=user.Avatar()
+        res1.setId("res1")
+        abstract=self._conf.getAbstractMgr().newAbstract(res1)
+        #accepting an abstract for a certain track
+        self._abstract.accept(res1,self._track1,self._ctOral)
+        self.assert_(contrib.getId()!=abstract.getId())
+
+    def testAcceptForNonProposedTrack( self ):
+        #an abstract can be accepted for a track for which it is not proposed
+        self._abstract.setTracks( [self._track1, self._track2] )
+        self.assert_( not self._track3.hasAbstract( self._abstract ) )
+        res1 = user.Avatar()
+        res1.setId( "res1" )
+        self._abstract.accept( res1, self._track3, self._ctOral )
+        #check the status is changed to accept
+        status = self._abstract.getCurrentStatus()
+        self.assert_( isinstance(status, review.AbstractStatusAccepted) )
+        #check the track
+        self.assert_( status.getTrack() == self._track3 )
+        #check the track list contains the track for which it was accepted
+        self.assert_( self._track3.hasAbstract( self._abstract ) )
+
+
+class TestAbstractDisplay(unittest.TestCase):
+    """tests different abstract displaying scenarios.
+    """
+    
+    def setUp( self ):
+        av = user.Avatar()
+        self._conf = conference.Conference( av )
+        self._track1 = self._conf.newTrack()
+        self._track2 = self._conf.newTrack()
+        self._track3 = self._conf.newTrack()
+        self._track4 = self._conf.newTrack()
+        submitter = user.Avatar()
+        submitter.setId( "submitter" )
+        self._abstract = self._conf.getAbstractMgr().newAbstract( submitter )
+
+    def testTrackOrder( self ):
+        #tests the track sorting functions
+        self._abstract.addTrack( self._track3 )
+        self._abstract.addTrack( self._track1 )
+        self._abstract.addTrack( self._track2 )
+        l = self._abstract.getTrackListSorted()
+        self.assert_( l[0] == self._track1 and l[1] == self._track2 \
+                        and l[2] == self._track3 )
+
+
+class TestAbstractWithdrawal(unittest.TestCase):
+    """tests different abstract withdrawal scenarios.
+    """
+    
+    def setUp( self ):
+        av = user.Avatar()
+        self._conf = conference.Conference( av )
+        self._ctOral = conference.ContributionType( "oral", "", self._conf )
+        self._conf.addContribType( self._ctOral )
+        self._track1 = self._conf.newTrack()
+        self._track2 = self._conf.newTrack()
+        self._track3 = self._conf.newTrack()
+        submitter = user.Avatar()
+        submitter.setId( "submitter" )
+        self._abstract = self._conf.getAbstractMgr().newAbstract( submitter )
+
+    def testNormal( self ):
+        #tests the normal flow of events of the withdrawal TC
+        av=user.Avatar()
+        self._abstract.withdraw( av,"hola" )
+        self.assert_( isinstance( self._abstract.getCurrentStatus(), review.AbstractStatusWithdrawn ) )
+
+    def testCannotAccWithdrawn( self ):
+        #tests that a withdrawn abstract cannot be accepted
+        self._abstract.withdraw( None,"hola" )
+        cm = user.Avatar()
+        cm.setId("cm")
+        self.assertRaises( errors.MaKaCError, self._abstract.accept, cm, self._track1, self._ctOral )
+
+    def testCannotRejWithdrawn( self ):
+        #tests that a withdrawn abstract cannot be rejected
+        self._abstract.withdraw( None,"hola" )
+        cm = user.Avatar()
+        cm.setId("cm")
+        self.assertRaises( errors.MaKaCError, self._abstract.reject, cm )
+
+    def testAccepted(self):
+        #tests that it is possible to withdraw an accepted abstract and that it
+        #   provokes the withdrawal of the associated contribution
+        av=user.Avatar()
+        self._abstract.accept(av,self._track1,self._ctOral)
+        contrib=self._abstract.getContribution()
+        self.assert_(not isinstance(contrib,conference.ContribStatusWithdrawn))
+        self._abstract.withdraw(av,"hola")
+        absStatus=self._abstract.getCurrentStatus()
+        contribStatus=contrib.getCurrentStatus()
+        self.assert_(isinstance(absStatus,review.AbstractStatusWithdrawn))
+        self.assert_(isinstance(contribStatus,conference.ContribStatusWithdrawn))
+
+
+class TestAbstractRecovery(unittest.TestCase):
+    """tests different abstract recovery scenarios.
+    """
+    
+    def setUp( self ):
+        av = user.Avatar()
+        self._conf = conference.Conference( av )
+        self._track1 = self._conf.newTrack()
+        self._track2 = self._conf.newTrack()
+        self._track3 = self._conf.newTrack()
+        submitter = user.Avatar()
+        submitter.setId( "submitter" )
+        self._abstract = self._conf.getAbstractMgr().newAbstract( submitter )
+        self._abstract.addTrack( self._track1 )
+        self._abstract.addTrack( self._track2 )
+        self._abstract.addTrack( self._track3 )
+
+    def testNormal( self ):
+        #tests the abstract recovery normal flow
+        av=user.Avatar()
+        self._abstract.withdraw(av)
+        self._abstract.recover()
+        self.assert_( isinstance( self._abstract.getCurrentStatus(), review.AbstractStatusSubmitted ) )
+
+    def testTackJudgementClearing( self ):
+        #tests that after recovering an abstract which had some judgements
+        #   they are cleared.
+        tc = user.Avatar()
+        tc.setId( "tc" )
+        self._abstract.proposeToAccept( tc, self._track1, "oral" )
+        self._abstract.proposeToAccept( tc, self._track3, "oral" )
+        self._abstract.withdraw(tc)
+        self._abstract.recover()
+        self.assert_( self._abstract.hasTrack( self._track1 ) )
+        self.assert_( self._abstract.hasTrack( self._track3 ) )
+        self.assert_( self._track1.hasAbstract( self._abstract ) )
+        self.assert_( self._track3.hasAbstract( self._abstract ) )
+        self.assert_( self._abstract.getNumJudgements() == 2 )
+
+
+class TestAbstractReallocation(unittest.TestCase):
+    """tests different abstract reallocation scenarios.
+    """
+    
+    def setUp( self ):
+        av = user.Avatar()
+        self._conf = conference.Conference( av )
+        self._track1 = self._conf.newTrack()
+        self._track2 = self._conf.newTrack()
+        self._track3 = self._conf.newTrack()
+        submitter = user.Avatar()
+        submitter.setId( "submitter" )
+        self._abstract = self._conf.getAbstractMgr().newAbstract( submitter )
+        self._abstract.addTrack( self._track1 )
+    
+    def testSimpleReallocation( self ):
+        tc1 = user.Avatar()
+        tc1.setId( "tc1" )
+        self._abstract.proposeForOtherTracks( tc1, self._track1, "test", \
+            [self._track2, self._track3] )
+        self.assert_( self._abstract.hasTrack( self._track1 ) )
+        self.assert_( self._abstract.hasTrack( self._track2 ) )
+        self.assert_( self._abstract.hasTrack( self._track3 ) )
+        self.assert_( self._abstract.getNumJudgements() == 1 )
+        t1jud = self._abstract.getTrackJudgement( self._track1 )
+        self.assert_( isinstance( t1jud, review.AbstractReallocation ) )
+        self.assert_( t1jud.getResponsible() == tc1 )
+        self.assert_( self._track2 in t1jud.getProposedTrackList() )
+        self.assert_( self._track3 in t1jud.getProposedTrackList() )
+        self.assert_( self._track1 not in t1jud.getProposedTrackList() )
+        status = self._abstract.getCurrentStatus()
+        self.assert_( isinstance( status, review.AbstractStatusUnderReview ) )
+        t2_tl = self._abstract.getReallocationTargetedList( self._track2 )
+        self.assert_( t1jud in t2_tl )
+        t3_tl = self._abstract.getReallocationTargetedList( self._track3 )
+        self.assert_( t1jud in t3_tl )
+        t1_tl = self._abstract.getReallocationTargetedList( self._track1 )
+        self.assert_( t1jud not in t1_tl )
+        
+   
+class TestNotification(unittest.TestCase):
+    """
+    """
+    
+    def setUp( self ):
+        from MaKaC.user import Avatar
+        av = Avatar()
+        from MaKaC.conference import Conference
+        self._conf = Conference( av )
+        self._track1 = self._conf.newTrack()
+        self._track2 = self._conf.newTrack()
+        self._track3 = self._conf.newTrack()
+        absMgr=self._conf.getAbstractMgr()
+        self._contribTypeOral="oral"
+        self._contribTypePoster="poster"
+        #absMgr.addContribType(self._contribTypeOral)
+        #absMgr.addContribType(self._contribTypePoster)
+        #from MaKaC.user import Avatar
+        #self._submitter = Avatar()
+        #self._submitter.setId( "submitter" )
+        #self._abstract=self._conf.getAbstractMgr().newAbstract(self._submitter)
+        #self._abstract.addTrack(self._track1)
+    
+    def testBasicManagement( self ):
+        #test adding and removing notification templates
+        from MaKaC.review import NotificationTemplate
+        tpl1=NotificationTemplate()
+        absMgr=self._conf.getAbstractMgr()
+        absMgr.addNotificationTpl(tpl1)
+        self.assert_(tpl1 in absMgr.getNotificationTplList())
+        tpl2=NotificationTemplate()
+        absMgr.addNotificationTpl(tpl2)
+        absMgr.removeNotificationTpl(tpl1)
+        self.assert_(tpl2 in absMgr.getNotificationTplList())
+        self.assert_(tpl1 not in absMgr.getNotificationTplList())
+        self.assert_(tpl1!=absMgr.getNotificationTplById(tpl1.getId()))
+        self.assert_(tpl2==absMgr.getNotificationTplById(tpl2.getId()))
+    
+    def testTplConditions(self):
+        #test adding and removing conditions to templates
+        from MaKaC.review import NotificationTemplate
+        tpl1=NotificationTemplate()
+        tpl2=NotificationTemplate()
+        absMgr=self._conf.getAbstractMgr()
+        absMgr.addNotificationTpl(tpl1)
+        absMgr.addNotificationTpl(tpl2)
+        from MaKaC.review import NotifTplCondAccepted,NotifTplCondRejected
+        cond1=NotifTplCondAccepted(contribType=self._contribTypeOral)
+        cond2=NotifTplCondRejected()
+        tpl1.addCondition(cond1)
+        tpl2.addCondition(cond2)
+        from MaKaC.user import Avatar
+        submitter=Avatar()
+        submitter.setId("submitter")
+        abs1=absMgr.newAbstract(submitter)
+        tplRes=absMgr.getNotifTplForAbstract(abs1)
+        self.assert_(tplRes is None)
+        abs1.accept(submitter,self._track1,self._contribTypeOral)
+        self.assert_(absMgr.getNotifTplForAbstract(abs1)==tpl1)
+        abs2=absMgr.newAbstract(submitter)
+        abs2.accept(submitter,self._track1,self._contribTypePoster)
+        self.assert_(not absMgr.getNotifTplForAbstract(abs2))
+        abs3=absMgr.newAbstract(submitter)
+        abs3.reject(submitter)
+        self.assert_(absMgr.getNotifTplForAbstract(abs3)==tpl2)
+
+    def testTplCondAccTrack(self):
+        #test different possibilities when a condition has been stablished for
+        #   a certain track
+        from MaKaC.review import NotificationTemplate
+        tpl1=NotificationTemplate()
+        absMgr=self._conf.getAbstractMgr()
+        absMgr.addNotificationTpl(tpl1)
+        from MaKaC.review import NotifTplCondAccepted
+        cond1=NotifTplCondAccepted(track=self._track1,contribType=self._contribTypeOral)
+        tpl1.addCondition(cond1)
+        from MaKaC.user import Avatar
+        submitter=Avatar()
+        submitter.setId("submitter")
+        abs1=absMgr.newAbstract(submitter)
+        abs1.accept(submitter,self._track1,self._contribTypeOral)
+        self.assert_(absMgr.getNotifTplForAbstract(abs1)==tpl1)
+        abs2=absMgr.newAbstract(submitter)
+        abs2.accept(submitter,self._track1,self._contribTypePoster)
+        self.assert_(absMgr.getNotifTplForAbstract(abs2) is None)
+        abs3=absMgr.newAbstract(submitter)
+        abs3.accept(submitter,self._track2,self._contribTypeOral)
+        self.assert_(absMgr.getNotifTplForAbstract(abs3) is None)
+
+    def testTplCondAccAnyTrack(self):
+        #test different possibilities when a condition has been stablished for
+        #   a notif tpl on any track
+        from MaKaC.review import NotificationTemplate
+        tpl1=NotificationTemplate()
+        absMgr=self._conf.getAbstractMgr()
+        absMgr.addNotificationTpl(tpl1)
+        from MaKaC.review import NotifTplCondAccepted
+        cond1=NotifTplCondAccepted(contribType=self._contribTypeOral)
+        tpl1.addCondition(cond1)
+        from MaKaC.user import Avatar
+        submitter=Avatar()
+        submitter.setId("submitter")
+        abs1=absMgr.newAbstract(submitter)
+        abs1.accept(submitter,self._track1,self._contribTypeOral)
+        self.assert_(absMgr.getNotifTplForAbstract(abs1)==tpl1)
+        abs2=absMgr.newAbstract(submitter)
+        abs2.accept(submitter,self._track1,self._contribTypePoster)
+        self.assert_(absMgr.getNotifTplForAbstract(abs2) is None)
+        abs3=absMgr.newAbstract(submitter)
+        abs3.accept(submitter,self._track2,self._contribTypeOral)
+        self.assert_(absMgr.getNotifTplForAbstract(abs3)==tpl1)
+        abs4=absMgr.newAbstract(submitter)
+        abs4.accept(submitter,None,self._contribTypeOral)
+        self.assert_(absMgr.getNotifTplForAbstract(abs4)==tpl1)
+
+    def testTplCondAccNoneTrack(self):
+        #test different possibilities when a condition has been stablished for
+        #   a notif tpl on none track
+        from MaKaC.review import NotificationTemplate
+        tpl1=NotificationTemplate()
+        absMgr=self._conf.getAbstractMgr()
+        absMgr.addNotificationTpl(tpl1)
+        from MaKaC.review import NotifTplCondAccepted
+        cond1=NotifTplCondAccepted(track=None,contribType=self._contribTypeOral)
+        tpl1.addCondition(cond1)
+        from MaKaC.user import Avatar
+        submitter=Avatar()
+        submitter.setId("submitter")
+        abs1=absMgr.newAbstract(submitter)
+        abs1.accept(submitter,self._track1,self._contribTypeOral)
+        self.assert_(absMgr.getNotifTplForAbstract(abs1) is None)
+        abs2=absMgr.newAbstract(submitter)
+        abs2.accept(submitter,self._track1,self._contribTypePoster)
+        self.assert_(absMgr.getNotifTplForAbstract(abs2) is None)
+        abs3=absMgr.newAbstract(submitter)
+        abs3.accept(submitter,None,self._contribTypeOral)
+        self.assert_(absMgr.getNotifTplForAbstract(abs3)==tpl1)
+
+
+class TestAuthorSearch(unittest.TestCase):
+    """
+    """
+    
+    def setUp( self ):
+        self._creator=user.Avatar()
+        self._conf=conference.Conference(self._creator)
+
+    def testBasicSearch(self):
+        absMgr=self._conf.getAbstractMgr()
+        abs1=absMgr.newAbstract(self._creator)
+        auth1=abs1.newPrimaryAuthor(firstName="a",surName="a")
+        auth2=abs1.newPrimaryAuthor(firstName="b",surName="b")
+        auth3=abs1.newCoAuthor(firstName="b",surName="b")
+        abs2=absMgr.newAbstract(self._creator)
+        self.assert_(len(absMgr.getAbstractsMatchingAuth(""))==2)
+        self.assert_(len(absMgr.getAbstractsMatchingAuth("a"))==1)
+        self.assert_(abs1 in absMgr.getAbstractsMatchingAuth("a"))
+        self.assert_(len(absMgr.getAbstractsMatchingAuth("B"))==1)
+        self.assert_(abs1 in absMgr.getAbstractsMatchingAuth("b"))
+        self.assert_(auth3 not in absMgr.getAbstractsMatchingAuth("b"))
+        auth1.setSurName("c")
+        self.assert_(len(absMgr.getAbstractsMatchingAuth("a"))==1)
+        self.assert_(abs1 in absMgr.getAbstractsMatchingAuth("a"))
+        self.assert_(len(absMgr.getAbstractsMatchingAuth("B"))==1)
+        self.assert_(abs1 in absMgr.getAbstractsMatchingAuth("b"))
+        self.assert_(len(absMgr.getAbstractsMatchingAuth("c"))==1)
+        self.assert_(abs1 in absMgr.getAbstractsMatchingAuth("C"))
+        abs1._removePrimaryAuthor(auth1)
+        self.assert_(len(absMgr.getAbstractsMatchingAuth(""))==2)
+        self.assert_(len(absMgr.getAbstractsMatchingAuth("a"))==0)
+        self.assert_(abs1 not in absMgr.getAbstractsMatchingAuth("a"))
+        self.assert_(len(absMgr.getAbstractsMatchingAuth("B"))==1)
+        self.assert_(abs1 in absMgr.getAbstractsMatchingAuth("b"))
+        abs1.clearAuthors()
+        self.assert_(len(absMgr.getAbstractsMatchingAuth(""))==2)
+        self.assert_(len(absMgr.getAbstractsMatchingAuth("a"))==0)
+        self.assert_(abs1 not in absMgr.getAbstractsMatchingAuth("a"))
+        self.assert_(len(absMgr.getAbstractsMatchingAuth("B"))==0)
+        self.assert_(abs1 not in absMgr.getAbstractsMatchingAuth("b"))
+
+def testsuite():
+    suite = unittest.TestSuite()
+    suite.addTest( unittest.makeSuite(TestCFADirectives) )
+    suite.addTest( unittest.makeSuite(TestAbstractSubmission) )
+    suite.addTest( unittest.makeSuite(TestAbstractModification) )
+    suite.addTest( unittest.makeSuite(TestAbstractAcceptation) )
+    suite.addTest( unittest.makeSuite(TestAbstractDisplay) )
+    suite.addTest( unittest.makeSuite(TestAbstractWithdrawal) )
+    suite.addTest( unittest.makeSuite(TestAbstractRecovery) )
+    suite.addTest( unittest.makeSuite(TestAbstractReallocation) )
+    suite.addTest( unittest.makeSuite(TestNotification) )
+    suite.addTest( unittest.makeSuite(TestAuthorSearch) )
+    return suite
Index: indicop/python/unit/MaKaC_tests/schedule_test.py
===================================================================
--- indicop/python/unit/MaKaC_tests/schedule_test.py	(revision b05fd7f86fb7ba6ddb22bcab445d80cd9c24d90c)
+++ indicop/python/unit/MaKaC_tests/schedule_test.py	(revision b05fd7f86fb7ba6ddb22bcab445d80cd9c24d90c)
@@ -0,0 +1,275 @@
+# -*- coding: utf-8 -*-
+##
+## $Id: testSchedule.py,v 1.5 2008/04/24 16:59:58 jose Exp $
+##
+## This file is part of CDS Indico.
+## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 CERN.
+##
+## CDS Indico is free software; you can redistribute it and/or
+## modify it under the terms of the GNU General Public License as
+## published by the Free Software Foundation; either version 2 of the
+## License, or (at your option) any later version.
+##
+## CDS Indico is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with CDS Indico; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+"""Contains tests regarding some scenarios related to schedule management.
+"""
+import unittest
+import os
+
+
+from datetime import datetime,timedelta
+from pytz import timezone
+
+from MaKaC.schedule import IndTimeSchEntry
+from MaKaC.errors import MaKaCError
+from MaKaC.conference import Conference
+from MaKaC.conference import Category
+from MaKaC.user import Avatar
+import MaKaC.common.indexes as indexes
+from MaKaC.common.db import DBMgr
+
+def setup_module():
+    DBMgr.getInstance().startRequest()
+
+def teardown_module():
+    DBMgr.getInstance().abort()
+    DBMgr.getInstance().endRequest()
+    
+class _ScheduleOwnerWrapper:
+    
+    def __init__(self,sDate,eDate):
+        self._sDate,self._eDate=sDate,eDate
+    
+    def getStartDate(self):
+        return self._sDate
+
+    def getEndDate(self):
+        return self._eDate
+
+    def getAdjustedStartDate( self, tz=None ):
+        if not tz:
+            tz = self.getTimezone()
+        return self.getStartDate().astimezone(timezone(tz))
+
+    def getAdjustedEndDate( self, tz=None ):
+        if not tz:
+            tz = self.getTimezone()
+        return self.getEndDate().astimezone(timezone(tz))
+
+    def setStartDate(self, sd):
+        self._sDate=sd
+
+    def setEndDate(self, ed):
+        self._eDate=ed
+
+    def setDates(self, sd, ed):
+        self._sDate=sd
+        self._eDate=ed
+
+    
+class TestTimeSchedule(unittest.TestCase):
+    """Tests the basic schedule management functions
+    """
+
+    def setUp( self ):
+        a = Avatar()
+        a.setId("creator")
+        self._conf = Conference( a )
+        self._conf.setId('a')
+        category=Category()
+        category.setId('1')
+        self._conf.addOwner(category)
+        catDateIdx = indexes.IndexesHolder().getIndex('categoryDate')
+        catDateIdx.indexConf(self._conf)
+        self._conf.setTimezone('UTC')
+
+#TODO We need somehow to link schOwner with self._conf (Same thing for the following test
+#    def testBasicAddAndRemove( self ):
+#        from MaKaC.schedule import TimeSchedule
+#        sDateSch,eDateSch=datetime(2004,1,1,10,0, tzinfo=timezone('UTC')),datetime(2004,1,1,12,0, tzinfo=timezone('UTC'))
+#        schOwner=_ScheduleOwnerWrapper(sDateSch,eDateSch)
+#        sch=TimeSchedule(schOwner)
+#        self._conf.addOwner(sch)
+#        entry1=IndTimeSchEntry()
+#        entry1.setDuration(0,25)
+#        entry2=IndTimeSchEntry()
+#        entry2.setDuration(0,30)
+#        entry3=IndTimeSchEntry()
+#        self.assert_(not entry1.isScheduled())
+#        self.assert_(not entry2.isScheduled())
+#        self.assert_(not entry3.isScheduled())
+#        sch.addEntry(entry1)
+#        sch.addEntry(entry2)
+#        sch.addEntry(entry3)
+#        self.assert_(entry1.isScheduled())
+#        self.assert_(entry2.isScheduled())
+#        self.assert_(entry3.isScheduled())
+#        self.assert_(entry1==sch.getEntries()[0])
+#        self.assert_(entry2==sch.getEntries()[1])
+#        self.assert_(entry3==sch.getEntries()[2])
+#        self.assert_(entry1.getStartDate()==datetime(2004,1,1,10,0, tzinfo=timezone('UTC')))
+#        self.assert_(entry1.getDuration()==timedelta(minutes=25))
+#        self.assert_(entry2.getStartDate()==datetime(2004,1,1,10,25, tzinfo=timezone('UTC')))
+#        self.assert_(entry2.getDuration()==timedelta(minutes=30))
+#        self.assert_(entry3.getStartDate()==datetime(2004,1,1,10,55, tzinfo=timezone('UTC')))
+#        self.assert_(entry3.getDuration()==timedelta(minutes=5))
+#        sch.removeEntry(entry1)
+#        self.assert_(not entry1.isScheduled())
+#        self.assert_(entry2.isScheduled())
+#        self.assert_(entry3.isScheduled())
+#        self.assert_(entry1 not in sch.getEntries())
+#        self.assert_(entry2==sch.getEntries()[0])
+#        self.assert_(entry3==sch.getEntries()[1])
+#        self.assert_(entry1.getDuration()==timedelta(minutes=25))
+#        self.assert_(entry2.getStartDate()==datetime(2004,1,1,10,25, tzinfo=timezone('UTC')))
+#        self.assert_(entry2.getDuration()==timedelta(minutes=30))
+#        self.assert_(entry3.getStartDate()==datetime(2004,1,1,10,55, tzinfo=timezone('UTC')))
+#        self.assert_(entry3.getDuration()==timedelta(minutes=5))
+
+#    def testCompact(self):
+#        from MaKaC.schedule import TimeSchedule
+#        sDateSch=datetime(2004, 01, 01, 10, 00, tzinfo=timezone('UTC'))
+#        eDateSch=datetime(2004, 01, 01, 12, 00, tzinfo=timezone('UTC'))
+#        schOwner=_ScheduleOwnerWrapper(sDateSch,eDateSch)
+#        sch=TimeSchedule(schOwner)
+#        from MaKaC.schedule import TimeSchEntry
+#        entry1,entry2=IndTimeSchEntry(),IndTimeSchEntry()
+#        entry3=IndTimeSchEntry()
+#        entry1.setDuration(0,25)
+#        entry2.setDuration(0,25)
+#        entry3.setDuration(0,30)
+#        sch.addEntry(entry1)
+#        self.assert_(entry1.getStartDate()==datetime(2004, 01, 01, 10, 00, tzinfo=timezone('UTC')))
+#        sch.addEntry(entry2)
+#        self.assert_(entry2.getStartDate()==datetime(2004, 01, 01, 10, 25, tzinfo=timezone('UTC')))
+#        sch.addEntry(entry3)
+#        self.assert_(entry3.getStartDate()==datetime(2004, 01, 01, 10, 50, tzinfo=timezone('UTC')))
+#        entry1.setStartDate(datetime(2004, 01, 01, 11, 00, tzinfo=timezone('UTC')))
+#        entry2.setStartDate(datetime(2004, 01, 01, 11, 15, tzinfo=timezone('UTC')))
+#        entry3.setStartDate(datetime(2004, 01, 01, 11, 25, tzinfo=timezone('UTC')))
+#        self.assert_(entry1.getStartDate()==datetime(2004, 01, 01, 11, 00, tzinfo=timezone('UTC')))
+#        self.assert_(entry2.getStartDate()==datetime(2004, 01, 01, 11, 15, tzinfo=timezone('UTC')))
+#        self.assert_(entry3.getStartDate()==datetime(2004, 01, 01, 11, 25, tzinfo=timezone('UTC')))
+#        sch.compact()
+#        self.assert_(entry1.getStartDate()==datetime(2004 ,01, 01, 10, 00, tzinfo=timezone('UTC')))
+#        self.assert_(entry1.getDuration()==timedelta(minutes=25))
+#        self.assert_(entry2.getStartDate()==datetime(2004, 01, 01, 10, 25, tzinfo=timezone('UTC')))
+#        self.assert_(entry2.getDuration()==timedelta(minutes=25))
+#        self.assert_(entry3.getStartDate()==datetime(2004, 01, 01, 10, 50, tzinfo=timezone('UTC')))
+#        self.assert_(entry3.getDuration()==timedelta(minutes=30))
+
+    def testStartEndDates(self):
+        from MaKaC.schedule import TimeSchedule
+        sDateSch,eDateSch=datetime(2004,1,1,10,0, tzinfo=timezone('UTC')),datetime(2004,1,1,12,0, tzinfo=timezone('UTC'))
+        schOwner=_ScheduleOwnerWrapper(sDateSch,eDateSch)
+        sch=TimeSchedule(schOwner)
+        self.assert_(sch.getStartDate()==schOwner.getStartDate())
+        self.assert_(sch.getEndDate()==schOwner.getEndDate())
+        schOwner.setStartDate(datetime(2004, 01, 02, 10, 00, tzinfo=timezone('UTC')))
+        schOwner.setEndDate(datetime(2004, 01, 02, 12, 00, tzinfo=timezone('UTC')))
+        self.assert_(sch.getStartDate()==datetime(2004, 01, 02, 10, 00, tzinfo=timezone('UTC')))
+        self.assert_(sch.getEndDate()==datetime(2004, 01, 02, 12, 00, tzinfo=timezone('UTC')))
+        #self.assertRaises(MaKaCError,schOwner.setDates,
+        #                   datetime(2004, 01, 02, 10, 00, tzinfo=timezone('UTC')),
+        #                   datetime(2004, 01, 01, 12, 00, tzinfo=timezone('UTC')))
+        #self.assertRaises(MaKaCError,schOwner.setDates,
+        #                   datetime(2004, 01, 02, 10, 00, tzinfo=timezone('UTC')),
+        #                   None)
+        #schOwner.setDates(None,None)
+        #self.assert_(sch.getStartDate()==schOwner.getStartDate())
+        #self.assert_(sch.getEndDate()==schOwner.getEndDate())
+        #entry1=IndTimeSchEntry()
+        #entry1.setDuration(0,25)
+        #entry2=IndTimeSchEntry()
+        #entry2.setDuration(0,30)
+        #sch.addEntry(entry1)
+        #sch.addEntry(entry2)
+        #schOwner.setDates(datetime(2004, 01, 01, 9, 00, tzinfo=timezone('UTC')))
+        #schOwner.setDates(eDate=datetime(2004, 01, 01, 17, 00, tzinfo=timezone('UTC')))
+        #self.assertRaises(MaKaCError,schOwner.setDates,
+        #                   **{"sDate":datetime(2004, 01, 01, 10, 01, tzinfo=timezone('UTC'))})
+        #self.assertRaises(MaKaCError,schOwner.setDates,
+        #                   **{"sDate":datetime(2004, 01, 01, 11, 15, tzinfo=timezone('UTC'))})
+        #self.assertRaises(MaKaCError,schOwner.setDates,
+        #                   **{"eDate":datetime(2004, 01, 01, 10, 15, tzinfo=timezone('UTC'))})
+        #schOwner.setDates(eDate=datetime(2004, 01, 01, 10, 55, tzinfo=timezone('UTC')))
+        #self.assertRaises(MaKaCError,schOwner.setDates,
+        #                   **{"eDate":datetime(2004, 01, 01, 10, 54, tzinfo=timezone('UTC'))})
+
+    def testMoveUp(self):
+        from MaKaC.schedule import ConferenceSchedule
+        sDateSch=datetime(2004, 01, 01, 10, 00, tzinfo=timezone('UTC'))
+        eDateSch=datetime(2004, 01, 01, 12, 00, tzinfo=timezone('UTC'))
+        self._conf.setStartDate(sDateSch)
+        self._conf.setEndDate(eDateSch)
+        sch=ConferenceSchedule(self._conf)
+        from MaKaC.schedule import TimeSchEntry
+        entry1,entry2=IndTimeSchEntry(),IndTimeSchEntry()
+        entry3=IndTimeSchEntry()
+        entry1.setDuration(0,25)
+        entry2.setDuration(0,25)
+        entry3.setDuration(0,30)
+        sch.addEntry(entry1)
+        self.assert_(entry1.getStartDate()==datetime(2004, 01, 01, 10, 00, tzinfo=timezone('UTC')))
+        sch.addEntry(entry2)
+        self.assert_(entry2.getStartDate()==datetime(2004, 01, 01, 10, 25, tzinfo=timezone('UTC')))
+        sch.addEntry(entry3)
+        self.assert_(entry3.getStartDate()==datetime(2004, 01, 01, 10, 50, tzinfo=timezone('UTC')))
+        sch.moveUpEntry(entry3)
+        self.assert_(entry3.getStartDate()==datetime(2004, 01, 01, 10, 25, tzinfo=timezone('UTC')))
+        self.assert_(entry2.getStartDate()==datetime(2004, 01, 01, 10 ,55, tzinfo=timezone('UTC')))
+        sch.moveUpEntry(entry1)
+        self.assert_(entry3.getStartDate()==datetime(2004, 01, 01, 10, 00, tzinfo=timezone('UTC')))
+        self.assert_(entry2.getStartDate()==datetime(2004, 01, 01, 10, 30, tzinfo=timezone('UTC')))
+        self.assert_(entry1.getStartDate()==datetime(2004, 01, 01, 10, 55, tzinfo=timezone('UTC')))
+        entry2.setStartDate(datetime(2004, 01, 01, 10, 25, tzinfo=timezone('UTC')))
+        entry3.setStartDate(datetime(2004, 01, 01, 10, 35, tzinfo=timezone('UTC')))
+        self.assert_(entry2.getStartDate()==datetime(2004, 01, 01, 10, 25, tzinfo=timezone('UTC')))
+        self.assert_(entry3.getStartDate()==datetime(2004, 01, 01, 10, 35, tzinfo=timezone('UTC')))
+        sch.moveUpEntry(entry3)
+        self.assert_(entry3.getStartDate()==datetime(2004, 01, 01, 10, 25, tzinfo=timezone('UTC')))
+        self.assert_(entry2.getStartDate()==datetime(2004, 01, 01, 10, 55, tzinfo=timezone('UTC')))
+
+    def testMoveDown(self):
+        from MaKaC.schedule import ConferenceSchedule
+        sDateSch=datetime(2004, 01, 01, 10, 00, tzinfo=timezone('UTC'))
+        eDateSch=datetime(2004, 01, 01, 12, 00, tzinfo=timezone('UTC'))
+        self._conf.setStartDate(sDateSch)
+        self._conf.setEndDate(eDateSch)
+        sch=ConferenceSchedule(self._conf)
+        from MaKaC.schedule import TimeSchEntry
+        entry1,entry2=IndTimeSchEntry(),IndTimeSchEntry()
+        entry3=IndTimeSchEntry()
+        entry1.setDuration(0,25)
+        entry2.setDuration(0,25)
+        entry3.setDuration(0,30)
+        sch.addEntry(entry1)
+        self.assert_(entry1.getStartDate()==datetime(2004, 01, 01, 10, 00, tzinfo=timezone('UTC')))
+        sch.addEntry(entry2)
+        self.assert_(entry2.getStartDate()==datetime(2004, 01, 01, 10, 25, tzinfo=timezone('UTC')))
+        sch.addEntry(entry3)
+        self.assert_(entry3.getStartDate()==datetime(2004, 01, 01, 10, 50, tzinfo=timezone('UTC')))
+        sch.moveDownEntry(entry2)
+        self.assert_(entry3.getStartDate()==datetime(2004, 01, 01, 10, 25, tzinfo=timezone('UTC')))
+        self.assert_(entry2.getStartDate()==datetime(2004, 01, 01, 10, 55, tzinfo=timezone('UTC')))
+        sch.moveDownEntry(entry2)
+        self.assert_(entry2.getStartDate()==datetime(2004, 01, 01, 10, 00, tzinfo=timezone('UTC')))
+        self.assert_(entry1.getStartDate()==datetime(2004, 01, 01, 10, 25, tzinfo=timezone('UTC')))
+        self.assert_(entry3.getStartDate()==datetime(2004, 01, 01, 10, 50, tzinfo=timezone('UTC')))
+        entry1.setStartDate(datetime(2004, 01, 01, 10, 00, tzinfo=timezone('UTC')))
+        entry2.setStartDate(datetime(2004, 01, 01, 10, 25, tzinfo=timezone('UTC')))
+        entry3.setStartDate(datetime(2004, 01, 01, 10, 35, tzinfo=timezone('UTC')))
+        self.assert_(entry1.getStartDate()==datetime(2004, 01, 01, 10, 00, tzinfo=timezone('UTC')))
+        self.assert_(entry2.getStartDate()==datetime(2004, 01, 01, 10, 25, tzinfo=timezone('UTC')))
+        self.assert_(entry3.getStartDate()==datetime(2004, 01, 01, 10, 35, tzinfo=timezone('UTC')))
+        sch.moveDownEntry(entry2)
+        self.assert_(entry3.getStartDate()==datetime(2004, 01, 01, 10, 25, tzinfo=timezone('UTC')))
+        self.assert_(entry2.getStartDate()==datetime(2004, 01, 01, 10, 55, tzinfo=timezone('UTC')))
