Skip to content
Snippets Groups Projects
Select Git revision
  • cb131082e8712209e69b15e5e05c6ad3da0c7a3f
  • master default protected
  • 67-multithreading-is-plattform-dependent
  • cmake_windows
  • v0.8.4
  • v0.8.3
  • v0.8.2
  • v0.8
  • v0.7
  • v0.6
  • v0.5-alpha
  • v0.4
12 results

FrameElement.cpp

Blame
  • create-evaluation-files.py 36.31 KiB
    #!/usr/bin/python3
    # Create HTML files with Selection evaluation results for each participant
    #    in current directory. Creates evaluation.html and reviews/
    #
    # cd Selection
    # usage: python ../create-evaluation-files.py \
    #    ../RegistrantsList.csv ../evaluation-results.csv
    #
    # Some --- columns needs to be renamed in evaluation-results.csv
    # First column --- to -o-
    # Column --- for each preference stating Does not meet requirements needs to be renamed to -n-
    #
    import sys
    import csv
    import os
    import re
    import string
    from posix import unlink
    from datetime import datetime
    from collections import Counter
    import glob
    
    #
    # Basic skeleton of html file (header, footer and content in the middle (parameter 3)
    # Also include place holders for file title (0) and date (1)
    skeleton = """
    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <meta http-equiv="CACHE-CONTROL" content="NO-CACHE">
        <meta http-equiv="EXPIRES" content="0">
        <title>{{TITLE}}</title>
        <script type="text/javascript">
            function goto_project(){
                var myselect = document.getElementById("project_id_list");
                window.location.href = '#project_'+myselect.options[myselect.selectedIndex].value;
            }
        </script>
    <style>
      body {background-color:white}
      .size {
      background-color: white;
      margin:0 auto;
      font-family: arial;
      font-size: 12px;
      }
      div.title { font-size: 16px; font-weight: bold;}
      div {margin-bottom: 2px;}
      table.list {
          width: 100%;
          padding: 0px;
          margin: 0px;
          -webkit-border-vertical-spacing: 0px;
      }
      table.list tr:nth-child(even) {
        background-color: #EFEFEF;
      }
      table.list tr.head, table.list tr.foot {
          background-color: #BBBBBB;
      }
          table.list tr.head th {
              border-bottom: 1px solid #aaaaaa;
          }
          table.list tr.foot th {
              border-top: 1px solid #aaaaaa;
          }
    
      table.list tr td.id {
          text-align: right;
          padding-right: 5px;
          border-left: 0px;
      }
      table.list tr:hover {
        background-color: LightGreen;
      }
      td.dataCaptionTD {
          width: 150px;
      }
      td.dataSubCaptionTD {
          width: 150px;
      }
      th.overall_comment, td.overall_comment {
          width: 15%;
          vertical-align: top;
      }
      table.list tr table.no_bg_coloring tr {
          background-color: transparent;
      }
      table.list tr.registrant_selected {
          text-decoration: line-through;
          background-color: #00EFEF;
          font-style: italic;
          color: #999999;
      }
          table.list tr.registrant_selected a {
              color: #999999;
          }
    </style>
    </head>
    <body>
    <div class=size>
    <br>
    <br>
    <div style="font-size: 16px; text-align: center; font-weight: bold;">Summer of HPC project evaluation results</div>
    <br><br>
    <div ><span style="float:right;"><b>Date</b>: {{DATE}}</span></div> 
    {{CONTENT}}
    </body>
    </html>
    """
    
    #
    # Main content of index.html file. It holds list of projects and particiants (sorted by score)
    #
    index_data = """
    <br>
    <a name="projects"></a>
    Content: [<a href="#projects">Project list</a>]&nbsp;&nbsp;[<a href="#registrants">Registrant list</a>]
    <br>
    <br>
    <h2>PROJECT LIST WITH REGISTRANTS</h2>
    
    <table>
    <tr valign="top">
        <td>
            Projects and selected registrants (students):
            <table class="list" style="width: auto;">
            <tr class="head">
                <td>Project: ID- - name</td>
                <td>Selected registrant (link to application)</td>
                <td>Country</td>
                <td>Gender</td>
                <td>Age</td>
            <td>E-mail</td>
                <td colspan="2">Evaluation<br>details</td>
            </tr>
            {{PROJECT_LIST_AND_SELECTED_PARTICIPANTS}}
            </table>
        </td>
        <td width="10%">&nbsp;</td>
        <td>
            Countries - all and selected.
            <table class="list">
            <tr class="head">
                <th>&nbsp;</th>
                <th colspan="3">Registrants</th>
            </tr>
            <tr class="head">
                <th>Country</th>
                <th width="60px">All</th>
                <th width="60px">Selected</th>
                <th width="60px">[%]</th>
            </tr>
            {{COUNTRY_PARTICIPANTS_LIST}}
            </table>
        </td>
    </tr>
    </table>
    <hr>
    {{CONTENT_PROJECTS}}
    
    <br>
    <br>
    <br>
    <hr>
    <br>
    <a name="registrants"></a>
    Content: [<a href="#projects">Project list</a>]&nbsp;&nbsp;[<a href="#registrants">Registrant list</a>]
    <br>
    <br>
    <h2>REGISTRANTS EVALUATIONS</h2>
    {{CONTENT_REGISTRANTS}}
    """
    
    # layout of project in TOC
    project_selected_participant_row = """
        <tr>
            <td><a href="#project_{{PROJECT_ID}}">{{PROJECT_ID}} - {{PROJECT_NAME}}</td>
            <td>{{PARTICIPANTS_LIST}}</td>
        </tr>
    """
    
    # layout of list of participants; value is added to "skeleton"
    project_html_data = """
    <br>
    <a name="project_{{PROJECT_ID}}"></a>
    <h3>{{PROJECT_ID}} - {{PROJECT_NAME}}</h3>
    On mouseover (put mouse cursor above mark) and additional explanation will be displayed. <div style="float: right;"><a href="#projects">[to top]</a></div>
    <table class="list">
    <head>
        <tr class="head">
            <th>&nbsp;</th>
            <th>&nbsp;</th>
            <th>&nbsp;</th>
            <th>&nbsp;</th>
            <th>&nbsp;</th>
            <th>&nbsp;</th>
            <th colspan="2">Comment</th>
            <th colspan="2">Pref.1</th>
            <th colspan="2">Pref.2</th>
            <th colspan="2">Pref.3</th>
            <th colspan="3">Motivation</th>
            <th colspan="3">Ambasador</th>
            <th colspan="3">Technical</th>
            <th>&nbsp;</th>
        </tr>
        <tr class="head">
            <th>No.</th>
            <th>Name (ID)</th>
            <th>Country</th>
            <th>Gender</th>
            <th>Age</th>
            <th>Choice</th>
            <th class="overall_comment">P1</th>
            <th class="overall_comment">P2</th>
            <th title="[X] = Student meet compulsory preferences.\n[  ] = Student DOES NOT meet compulsory preferences.">(?)</th>
            <th title="[X] = Student meet desirable prerequisites.\n[  ] = Student DOES NOT meet desirable preferences.">(?)</th>
            <th title="[X] = Student meet compulsory preferences.\n[  ] = Student DOES NOT meet compulsory preferences.">(?)</th>
            <th title="[X] = Student meet desirable prerequisites.\n[  ] = Student DOES NOT meet desirable preferences.">(?)</th>
            <th title="[X] = Student meet compulsory preferences.\n[  ] = Student DOES NOT meet compulsory preferences.">(?)</th>
            <th title="[X] = Student meet desirable prerequisites.\n[  ] = Student DOES NOT meet desirable preferences.">(?)</th>
            <th>P1</th>
            <th>P2</th>
            <th>Avg</th>
            <th>P1</th>
            <th>P2</th>
            <th>Avg</th>
            <th>P1</th>
            <th>P2</th>
            <th>Avg</th>
            <th>Average</th>
        </tr>
    </thead>
    <tbody>
    {{REGISTRANT_DATA}}
    </tbody>
    </table>
    """
    
    # row for 
    project_user_row = """
    <tr class="{{REGISTRANT_SELECTED}}">
        <td class="id">{{I}}</td>
        <td><a href="{{HTML_FILENAME}}">{{NAME}} ({{ID}})</a> <a href='{{EVALUATION_HTML_LINK_1}}'>[eval1]</a> <a href='{{EVALUATION_HTML_LINK_2}}'>[eval2]</a></td>
        <td>{{COUNTRY}}</td>
        <td align="center">{{GENDER}}</td>
        <td align="center">{{AGE}}</td>
        <td class="{{CHOICE}}" align="center">{{CHOICE}}</td>
        <td align="left" class="overall_comment"><i>{{REVIEWER_1}}:</i><br>{{OVERALL_COMMENT_1}}</td>
        <td align="left" class="overall_comment"><i>{{REVIEWER_2}}:</i><br>{{OVERALL_COMMENT_2}}</td>
        <td align="center" title="{{PREFERENCE_1_COMPULSORY}}">{{PREFERENCE_1_SHORT_COMPULSORY}}</td>
        <td align="center" title="{{PREFERENCE_1_DESIRABLE}}">{{PREFERENCE_1_SHORT_DESIRABLE}}</td>
        <td align="center" title="{{PREFERENCE_2_COMPULSORY}}">{{PREFERENCE_2_SHORT_COMPULSORY}}</td>
        <td align="center" title="{{PREFERENCE_2_DESIRABLE}}">{{PREFERENCE_2_SHORT_DESIRABLE}}</td>
        <td align="center" title="{{PREFERENCE_3_COMPULSORY}}">{{PREFERENCE_3_SHORT_COMPULSORY}}</td>
        <td align="center" title="{{PREFERENCE_3_DESIRABLE}}">{{PREFERENCE_3_SHORT_DESIRABLE}}</td>
        <td align="center" title="{{REVIEWER_1}}: {{MOTIVATION_COMMENT_P1}}">{{MOTIVATION_P1}}</td>
        <td align="center" title="{{REVIEWER_2}}: {{MOTIVATION_COMMENT_P2}}">{{MOTIVATION_P2}}</td>
        <td align="center">{{MOTIVATION_AVG}}</td>
        <td align="center" title="{{REVIEWER_1}}: {{AMBASADOR_COMMENT_P1}}">{{AMBASADOR_P1}}</td>
        <td align="center" title="{{REVIEWER_2}}: {{AMBASADOR_COMMENT_P2}}">{{AMBASADOR_P2}}</td>
        <td align="center">{{AMBASADOR_AVG}}</td>
        <td align="center" title="{{REVIEWER_1}}: {{TECHNICAL_COMMENT_P1}}">{{TECHNICAL_P1}}</td>
        <td align="center" title="{{REVIEWER_2}}: {{TECHNICAL_COMMENT_P2}}">{{TECHNICAL_P2}}</td>
        <td align="center">{{TECHNICAL_AVG}}</td>
        <td align="center">{{AVERAGE_P}}</td>
    </tr>
    """
    
    # layout of single row for each participant; content is added to "person_data"
    registrant_list = """
    On mouseover (put mouse cursor above mark) and additional explanation will be displayed. 
    <table class="list">
    <tr class="head">
        <th>&nbsp;</th>
        <th>&nbsp;</th>
        <th colspan="2">Comment</th>
        <th colspan="2">Pref.1</th>
        <th colspan="2">Pref.2</th>
        <th colspan="2">Pref.3</th>
        <th colspan="3">Motivation</th>
        <th colspan="3">Ambasador</th>
        <th colspan="3">Technical</th>
        <th>&nbsp;</th>
    </tr>
    <tr class="head">
        <th>No.</th>
        <th>Registrant</th>
        <th class="overall_comment">P1</th>
        <th class="overall_comment">P2</th>
        <th title="[X] = Student meet compulsory preferences.\n[  ] = Student DOES NOT meet compulsory preferences.">(?)</th>
        <th title="[X] = Student meet desirable prerequisites.\n[  ] = Student DOES NOT meet desirable preferences.">(?)</th>
        <th title="[X] = Student meet compulsory preferences.\n[  ] = Student DOES NOT meet compulsory preferences.">(?)</th>
        <th title="[X] = Student meet desirable prerequisites.\n[  ] = Student DOES NOT meet desirable preferences.">(?)</th>
        <th title="[X] = Student meet compulsory preferences.\n[  ] = Student DOES NOT meet compulsory preferences.">(?)</th>
        <th title="[X] = Student meet desirable prerequisites.\n[  ] = Student DOES NOT meet desirable preferences.">(?)</th>
        <th>P1</th>
        <th>P2</th>
        <th>Avg</th>
        <th>P1</th>
        <th>P2</th>
        <th>Avg</th>
        <th>P1</th>
        <th>P2</th>
        <th>Avg</th>
        <th>Average</th>
    </tr>
    {0}
    <tr class="foot">
        <th>No</th>
        <th>Registrant</th>
        <th colspan="2">Comment</th>
        <th colspan="2">Pref.1</th>
        <th colspan="2">Pref.2</th>
        <th colspan="2">Pref.3</th>
        <th colspan="3">Motivation</th>
        <th colspan="3">Ambasador</th>
        <th colspan="3">Technical</th>
        <th>Average</th>
    </tr>
    </table>
    """
    
    # layout of registrant daata + scores of evaluation + average scores
    person_row = """
    <tr class="{{REGISTRANT_SELECTED}}">
        <td class="id">{{I}}</td>
        <td><a href="{{HTML_FILENAME}}">{{REGISTRANT_NAME}}; {{COUNTRY}}, {{GENDER}}, {{AGE}} years (ID: {{REGISTRANT_ID}})</a><br>Preferred projects: {{PROJECT_ID_LIST}}</td>
        <td align="left" class="overall_comment"><i>{{REVIEWER_1}}:</i><br>{{OVERALL_COMMENT_1}}</td>
        <td align="left" class="overall_comment"><i>{{REVIEWER_2}}:</i><br>{{OVERALL_COMMENT_2}}</td>
        <td align="center" title="{{PREFERENCE_1_COMPULSORY}}">{{PREFERENCE_1_SHORT_COMPULSORY}}</td>
        <td align="center" title="{{PREFERENCE_1_DESIRABLE}}">{{PREFERENCE_1_SHORT_DESIRABLE}}</td>
        <td align="center" title="{{PREFERENCE_2_COMPULSORY}}">{{PREFERENCE_2_SHORT_COMPULSORY}}</td>
        <td align="center" title="{{PREFERENCE_2_DESIRABLE}}">{{PREFERENCE_2_SHORT_DESIRABLE}}</td>
        <td align="center" title="{{PREFERENCE_3_COMPULSORY}}">{{PREFERENCE_3_SHORT_COMPULSORY}}</td>
        <td align="center" title="{{PREFERENCE_3_DESIRABLE}}">{{PREFERENCE_3_SHORT_DESIRABLE}}</td>
        <td align="center" title="{{REVIEWER_1}}: {{MOTIVATION_COMMENT_P1}}">{{MOTIVATION_P1}}</td>
        <td align="center" title="{{REVIEWER_2}}: {{MOTIVATION_COMMENT_P2}}">{{MOTIVATION_P2}}</td>
        <td align="center">{{MOTIVATION_AVG}}</td>
        <td align="center" title="{{REVIEWER_1}}: {{AMBASADOR_COMMENT_P1}}">{{AMBASADOR_P1}}</td>
        <td align="center" title="{{REVIEWER_2}}: {{AMBASADOR_COMMENT_P2}}">{{AMBASADOR_P2}}</td>
        <td align="center">{{AMBASADOR_AVG}}</td>
        <td align="center" title="{{REVIEWER_1}}: {{TECHNICAL_COMMENT_P1}}">{{TECHNICAL_P1}}</td>
        <td align="center" title="{{REVIEWER_2}}: {{TECHNICAL_COMMENT_P2}}">{{TECHNICAL_P2}}</td>
        <td align="center">{{TECHNICAL_AVG}}</td>
        <td align="center">{{AVERAGE_P}}</td>
    </tr>
    """
    
    #
    # Save given title/date/content into given file
    #
    def save_content(filename, skeleton, title, date, content):
        skeleton = skeleton.replace("{{TITLE}}", title)
        skeleton = skeleton.replace("{{DATE}}",  date)
        skeleton = skeleton.replace("{{CONTENT}}", content)
        # open file and write content
        f = open(filename, "w")
        f.write(skeleton)
        f.close()
    
        return
    
    
    #
    # Read file and return header and data rows
    #
    def read_csv_file(filename):
        # Open the CSV file for reading -- evaluation data
        reader = csv.reader(open(filename))
        header_org = next(reader)
        header = []
        # correct names of fields (columns); remove all non-printable chars and "
        include = set(string.printable)
        
        for key in header_org:
            # check all header names/columns
            name = "".join(ch for ch in key if ch in include)
            name = name.replace('"', "")
            header.append(name)
        
        #print(header)
        # get header len = number of fields/columns
        header_len = len(header)
        
        data_rows = []
        # Read a single row from the CSV file
        for row in reader:
            if len(row) == 0:
                continue
            if len(row) != header_len:
                print("BAD DATA ROW ", ", ".join(row))
                continue
            data_rows.append(row)
    
        return { "header": header, "rows": data_rows } 
    
    #
    # Return number of points (score) for given evaluation part
    # 0 if not defined. Values are written as %d Points.
    #
    def get_points_from_evaluation(value):
        point = 0;
        
        if value:
            # check 
            #print(value)
            tmp_point = value.split(" ")[0].strip();
            
            if tmp_point:
                point = int(tmp_point)
        
        return point;
    
    
    #===========================================================
    #== MAIN 
    #===========================================================
    
    # read both files
    tmp_user_data = read_csv_file(sys.argv[1])
    eval_data = read_csv_file(sys.argv[2])
    
    #
    # create user_data dictionary with id as key and other data as dictionay 
    # for each row, keys are field names 
    user_data = {}
    
    for row in tmp_user_data['rows']:
        # process all rows
        dic=dict(zip(tmp_user_data['header'], row))
        #[print(key) for key in dic.keys()]
        if dic['ID'] == '':
            dic['ID'] = 0;
        
        id = int(dic['ID']);
        link = glob.glob('../Application_Form/*_%d' % id)
        if len(link) == 0:
            print('Missing Application form for id %d' % id)
        link = link[0]
        dic.update({'link_application': "%s/index.html" % link});
        user_data.update({id:dic})
    
    
    #print(user_data)
    
    if not os.path.exists("reviews"):
        # if does not exist, create cubdir for storing HTML files
        os.makedirs("reviews")
        
    #get_file("cookies.txt", "54-0.pdf", "https://events.prace-ri.eu/event/367/manage/registration/users/54/attachments/0.pdf")
    print("Creating HTML files: ")
    
    # read registrant content template
    f = open("../evaluation-detail-format.html", "r");
    evaluation_content = f.read()
    f.close()
    
    n = datetime.now()
    generation_date = "{0}. {1}. {2} @ {3}:{4}".format(n.day, n.month, n.year, n.hour, n.minute)
    
    # data about projects and registrants sorted with project first, then all rgistrant data and scores...
    project_data = {};
    student_data = {};
    country_data = {};
    
    for id in user_data:
        # prepare array for student evaluation data
        student_data.update({id: {'motivation': {'p': ['', ''], 'comment': ['',''], 'avg': 0.}, 
                                  'ambasador': {'p': ['', ''], 'comment': ['',''], 'avg': 0.}, 
                                  'technical': {'p': ['', ''], 'comment': ['',''], 'avg': 0.}, 
                                  'average': 0.,
                                  'num_reviewers_done': 0,
                                  'evaluation_detail_file': ['',''],
                                  'reviewer': ['', ''], 
                                  'overall_comment': ['', ''],
                                  'preference': [[['',''], ['',''], ['','']], [['',''], ['',''], ['','']]]}
                             });           
    
        # store countries into separate array
        ctryName = user_data[id]['Country']
        
        if not ctryName in country_data:
            # add country to array
            country_data.update({ctryName : {'all': 0, 'selected': 0, 'percent': 0.0 }});
            
        # add another student
        country_data[ctryName]['all'] += 1;
    
    #print(student_data)
    #print(eval_data)
    for row in eval_data['rows']:
        # loop over all evaluations
        done_keys = {}
        dic=dict(zip(eval_data['header'], row))
    
    #    print(dic)
        userID=int(dic["Applicant number"]);
        reviewerName=dic["Signature"].replace(" ","_");
        filename = "reviews/{0:03}_{1}.html".format(userID,reviewerName)
    
        #print("{0}: {1}".format(userID, user_data[userID]['Name']))
    #    print(" - evaluation defined")
    
        # store points form evaluation
        sum = 0;
        numReviewer = student_data[userID]['num_reviewers_done'];
        
        if numReviewer < 2:
            student_data[userID]['evaluation_detail_file'][numReviewer] = filename;
            student_data[userID]['reviewer'][numReviewer] = dic["Signature"];
            student_data[userID]['overall_comment'][numReviewer] = dic["Overall recommendation and comment"];
            
        else:
            print("{0}: {1}".format(userID, user_data[userID]['Name']))
            print("   -->> ERROR: too many reviewers!! -- {0}; only first 2 reviewers used.".format(numReviewer+1))
            continue;
        
        # 2019 remapping
        remap = {
        'motivation': 'Motivation & Enthusiasm',
        'ambasador': 'Ambassador Potential',
        'technical': 'Technical ability'
        }
        for part in ['motivation', 'ambasador', 'technical']:
            # parse all fields, store the points and compute the average
    
            point = get_points_from_evaluation(dic[remap[part]]);
            #print("    - {0}: {1} -> {2} (reviever num: {3})".format(part, dic[remap[part]], point, numReviewer))
            #print(dic[remap[part] + " comment"])
    
            if numReviewer < 2:
                student_data[userID][part]['p'][numReviewer] = point;
                student_data[userID][part]['comment'][numReviewer] = dic[remap[part] + " comment"];
                
            if numReviewer == 0:
                # average is current values 
                student_data[userID][part]['avg'] = student_data[userID][part]['p'][0];
                sum += student_data[userID][part]['avg'];
                
            else:
                # compute average from both marks
                student_data[userID][part]['avg'] = 0.5*(student_data[userID][part]['p'][0]+student_data[userID][part]['p'][1]);
                sum += student_data[userID][part]['avg'];
    
        # compute the average
        student_data[userID]['average'] = sum/3.;
        student_data[userID]['num_reviewers_done'] += 1;
    
     #   print("    - avg: {0:.2f}".format(student_data[userID]['average']);)
        #
        # generate registrant presentation HTML
        #
        content = evaluation_content
        # current preference
        currentPreference = '';
    
        for i in range(0,len(eval_data['header'])):
            # loop over header to preserve key order
            key = eval_data['header'][i]
            value = row[i].strip()
            #print(key, "|" + value + "|")
            # replace value for all keys in row
            html_fld = key.replace(" ", "_").upper();
            
            #print("key: {0}".format(html_fld))
            
            if html_fld in done_keys:
                # current key was already used in current row; add number at the end
                #print("found: {0}".format(html_fld))
                done_keys[html_fld] += 1
                html_fld = "{0}__{1}".format(html_fld, done_keys[html_fld])
            else:
                # key not used; add it to array for checking later
                done_keys.update({html_fld: 1})
            
    #        print("key: " + key + ", html: " + html_fld + ", value=|" + value  + "|")
            #print(done_keys)
    
            content = content.replace("{{" + html_fld + "}}", value)
            
            if key == "Applicant number":
                # replace also add/replace participant full name and formated UID {0:03}
                userID = int(value)
                tmp_title = user_data[userID]['Name']
                formUID = value.strip().zfill(3)
                content = content.replace("{{REGISTRANT_NAME}}", tmp_title)
                content = content.replace("{{FORMATED_UID}}", formUID)
     
            elif key == "Submission Date":
                # 2019 format 
                # 2019-03-26 00:33:44.289498+00:00
                # display date + time in more nicer format
                #print(html_fld)
                if value != '':
                    # n = datetime.strptime(value, '%y-%m-%d %H:%M:%S.%f+%z')
                    # dateTime = "{0}. {1}. {2} @ {3}:{4}".format(n.day, n.month, n.year, n.hour, n.minute)
                    content = content.replace("{{" + html_fld +"_DISP}}", value)
                else:
                    content = content.replace("{{" + html_fld +"_DISP}}", "")
    
            elif key == 'Motivation & Enthusiasm':
                content = content.replace("{{%s}}" % "MOTIVATION", value)
    
            elif key == 'Motivation & Enthusiasm comment':
                content = content.replace("{{%s}}" % "MOTIVATION-COMMENT", value)
    
            elif key == 'Ambassador Potential':
                content = content.replace("{{%s}}" % "AMBASADOR", value)
    
            elif key == 'Ambassador Potential comment':
                content = content.replace("{{%s}}" % "AMBASADOR-COMMENT", value)
    
            elif key == 'Technical ability':
                content = content.replace("{{%s}}" % "TECHNICAL", value)
    
            elif key == 'Technical ability comment':
                content = content.replace("{{%s}}" % "TECHNICAL-COMMENT", value)
    
            elif key == 'Overall recommendation and comment':
                content = content.replace("{{%s}}" % "OVERALL", value)
    
            elif key.startswith("Project preference"):
                # process preference
                currentPreference = key[-1]
                #print('Current preference = ', currentPreference)
                currPrefIndex = int(currentPreference)-1
                # The string is in form:
                # Student meet compulsory preferences.; Student meet desirable prerequisites
                if 'meet compulsory' in value:
                    student_data[userID]['preference'][numReviewer][currPrefIndex][0] = "[X]"
                else:
                    student_data[userID]['preference'][numReviewer][currPrefIndex][0] = "[&nbsp;&nbsp;]"
    
                if 'meet desirable' in value:
                    student_data[userID]['preference'][numReviewer][currPrefIndex][1] = "[X]"
                else:
                    student_data[userID]['preference'][numReviewer][currPrefIndex][1] = "[&nbsp;&nbsp;]"
    
                if "not fit" in value:
                    #student_data[userID]['preference'][numReviewer][currPrefIndex][2] = "[X]"
                    content = content.replace("{{PREFERENCE_" + currentPreference +"_DOESNOTFIT}}", "[X]")
                else:
                    # student_data[userID]['preference'][numReviewer][currPrefIndex][2] = "[&nbsp;&nbsp;]";
                    content = content.replace("{{PREFERENCE_" + currentPreference +"_DOESNOTFIT}}", "[&nbsp;&nbsp;]")
    
                content = content.replace("{{PREFERENCE_" + currentPreference +"_COMPULSORY}}", student_data[userID]['preference'][numReviewer][currPrefIndex][0])
                content = content.replace("{{PREFERENCE_" + currentPreference +"_DESIRABLE}}", student_data[userID]['preference'][numReviewer][currPrefIndex][1])
                
        # add content into skeleton and write to file
        save_content(filename, skeleton, "Summer of HPC 2019 - Registrant data", generation_date, content)
    
    # for fldName in ['First Choice', 'Second Choice', 'Third Choice']:
    #for fldName in ['1', '2', '3']:
    for fldName in ['Choice 1', 'Choice 2', 'Choice 3']:
        # get all three projects and first add all user's first choise, then second and then third choice
        for id in user_data:
            # loop over all users and extract projects and prepare arrays
            if user_data[id][fldName].strip():
                # project is defined
                proj = user_data[id][fldName].split(" ", 1);
    #            print(proj)
                projID = int(proj[0].strip());
                projName = proj[1].strip();
            
                if not projID in project_data:
                    # project does not exist; add an empty array for later addinf the data
                    initData = {'name': projName, 'students': [], 'selected_student': []};
                    project_data.update({projID: initData})
    
                project_data[projID]['students'].append({'id': id, 'choice': fldName.split(" ")[1]});
    
    
    for id in user_data:
        # loop over usr data and save selected students/registrants for each projct
        if user_data[id]['selected'].strip():
            projID = int(user_data[id]['selected'].strip());
            project_data[projID]['selected_student'].append(id);
            # get student country and change country stat data
            ctryName = user_data[id]['Country'];
            country_data[ctryName]['selected'] += 1;
            
    
    # now display project and student data into evaluation.html file
    content_projects = "";
    content_registrants = registrant_list;
    
    # sort projects by projectID
    project_ids = sorted(project_data);
    
    #
    # layout project data + registrants for each project
    proj_rows = "";
    proj_select = "";
    
    for projID in project_ids:
        # loop over all projets
        proj_row = project_html_data;
        proj_row = proj_row.replace("{{PROJECT_NAME}}", project_data[projID]['name']);
        proj_row = proj_row.replace("{{PROJECT_ID}}", "{0}".format(projID));
        
        tmp_row = project_selected_participant_row.replace("{{PROJECT_ID}}", "{0}".format(projID));
        tmp_row = tmp_row.replace("{{PROJECT_NAME}}", project_data[projID]['name']);
    
        if project_data[projID]['selected_student']:
            tmp_row = tmp_row.replace("{{PARTICIPANTS_LIST}}",
                                      "<br>".join("<a href='{0}'>{1}</a> ({7})</td><td>{2}</td><td>{3}</td><td>{4}</td><td align='center'><a href='{5}'>[1]</a></td><td align='center'><a href='{6}'>[2]</a></td><td>{8}</td>"
                                                  .format(user_data[x]['link_application'], user_data[x]['Name'],
                                                          user_data[x]['Country'], user_data[x]['Gender'],
                                                          user_data[x]['Age (years)'],
                                                          student_data[x]['evaluation_detail_file'][0],
                                                          student_data[x]['evaluation_detail_file'][1],
                                                          user_data[x]['ID'],
                                user_data[x]['Email'])
                                                  for x in project_data[projID]['selected_student']));
        else:
            tmp_row = tmp_row.replace("{{PARTICIPANTS_LIST}}", "");
    
        proj_select += tmp_row
        
    #    proj_select += project_toc_row.format(projID, projID, project_data[projID]['name']);
        user_rows = "";
        no = 1;
        
        for student_row in sorted(project_data[projID]['students'], key=lambda student_row: (student_row['choice'], -student_data[student_row['id']]['average'], student_row['id'])):
            # create list of students in current project
            id = student_row['id'];
            row = project_user_row;
            row = row.replace("{{I}}", "{0}".format(no));
            row = row.replace("{{NAME}}", user_data[id]['Name']);
            row = row.replace("{{ID}}", user_data[id]['ID']);
            row = row.replace("{{COUNTRY}}", user_data[id]['Country']);
            row = row.replace("{{GENDER}}", user_data[id]['Gender']);
            row = row.replace("{{AGE}}", user_data[id]['Age (years)']);
            row = row.replace("{{CHOICE}}", student_row['choice']);
            row = row.replace("{{OVERALL}}", student_row['choice']);
            row = row.replace("{{HTML_FILENAME}}", user_data[id]['link_application']);
            row = row.replace("{{EVALUATION_HTML_LINK_1}}", student_data[id]['evaluation_detail_file'][0]);
            row = row.replace("{{EVALUATION_HTML_LINK_2}}", student_data[id]['evaluation_detail_file'][1]);
            row = row.replace("{{REVIEWER_1}}", student_data[id]['reviewer'][0]);
            row = row.replace("{{REVIEWER_2}}", student_data[id]['reviewer'][1]);
            row = row.replace("{{OVERALL_COMMENT_1}}", student_data[id]['overall_comment'][0]);
            row = row.replace("{{OVERALL_COMMENT_2}}", student_data[id]['overall_comment'][1]);
    
            if user_data[id]['selected']:
                # current student is selected for project; display it in special way
                row =  row.replace("{{REGISTRANT_SELECTED}}", "registrant_selected");
            else:
                # ordinary row
                row = row.replace("{{REGISTRANT_SELECTED}}", "");
    
            for part in ['motivation','ambasador','technical']:
                # add all parts
                html_fld = part.upper();
                #print(student_data[id].keys())
                #print(part in student_data[id])
                row = row.replace("{{"+ html_fld +"_P1}}", "{0}".format(student_data[id][part]['p'][0]));
                row = row.replace("{{"+ html_fld +"_P2}}", "{0}".format(student_data[id][part]['p'][1]));
                row = row.replace("{{"+ html_fld +"_COMMENT_P1}}", "{0}".format(student_data[id][part]['comment'][0]));
                row = row.replace("{{"+ html_fld +"_COMMENT_P2}}", "{0}".format(student_data[id][part]['comment'][1]));
        
                if student_data[id][part]['avg'] > 0:
                    row = row.replace("{{"+ html_fld +"_AVG}}", "{0:.2f}".format(student_data[id][part]['avg']));
                else:
                    row = row.replace("{{"+ html_fld +"_AVG}}", "");
                
            if student_data[id]['average'] > 0:
                row = row.replace("{{AVERAGE_P}}", "{0:.2f}".format(student_data[id]['average']));
            else:
                row = row.replace("{{AVERAGE_P}}", "");
    
            for prefNo in range(1,4):
                # display all preferences
                row = row.replace("{{PREFERENCE_" + "{0}".format(prefNo) +"_SHORT_COMPULSORY}}", 
                                  "{0}<br>{1}".format(student_data[id]['preference'][0][prefNo-1][0], student_data[id]['preference'][1][prefNo-1][0]));
                row = row.replace("{{PREFERENCE_" + "{0}".format(prefNo) +"_SHORT_DESIRABLE}}", 
                                  "{0}<br>{1}".format(student_data[id]['preference'][0][prefNo-1][1], student_data[id]['preference'][1][prefNo-1][1]));
                row = row.replace("{{PREFERENCE_" + "{0}".format(prefNo) +"_COMPULSORY}}", 
                                  "{0}: {1}\n{2}: {3}".format(student_data[id]['reviewer'][0], student_data[id]['preference'][0][prefNo-1][0], 
                                                                student_data[id]['reviewer'][1], student_data[id]['preference'][1][prefNo-1][0]));
                row = row.replace("{{PREFERENCE_" + "{0}".format(prefNo) +"_DESIRABLE}}", 
                                  "{0}: {1}\n{2}: {3}".format(student_data[id]['reviewer'][0], student_data[id]['preference'][0][prefNo-1][1], 
                                                                student_data[id]['reviewer'][1], student_data[id]['preference'][1][prefNo-1][1]));
    
            user_rows += row;
            no += 1;
    
        proj_row = proj_row.replace("{{REGISTRANT_DATA}}", user_rows);
        proj_rows += proj_row;
        
    #print(proj_select)
    
    index_data = index_data.replace("{{PROJECT_LIST_AND_SELECTED_PARTICIPANTS}}", proj_select)
    content_projects = proj_rows
    
    
    #
    # display country statistics: all + selected registrants + percents
    country_rows = ""
    country_list_sorted = sorted(country_data)
    
    for ctryName in country_list_sorted:
        # loop over all countries
        row = ""
        perc = 100 * country_data[ctryName]['selected'] * 1.0 / country_data[ctryName]['all']
        country_rows += "<tr><td>{0}</td><td class='id'>{1}</td><td class='id'>{2}</td><td class='id'>{3:.1f}</td></tr>".format(
                                ctryName, country_data[ctryName]['all'], country_data[ctryName]['selected'], perc)
    
    index_data = index_data.replace("{{COUNTRY_PARTICIPANTS_LIST}}", country_rows);
    
    # layout of registrant data + scores of evaluation + average scores
    user_avg = {};
    
    for id in user_data:
        # loop over usr data and create {key: avg} for sorting
        user_avg.update({id: student_data[id]['average']});
        
    # now sort it
    user_sorted = Counter(user_avg)
    
    rows = ""
    no = 1;
    for cell in user_sorted.most_common():
        # loop over usr data and create registrant data
        id = cell[0];
        row = person_row;
        row = row.replace("{{I}}", "{0}".format(no));
        row = row.replace("{{REGISTRANT_NAME}}", user_data[id]['Name']);
        row = row.replace("{{COUNTRY}}", user_data[id]['Country']);
        row = row.replace("{{GENDER}}", user_data[id]['Gender']);
        row = row.replace("{{AGE}}", user_data[id]['Age (years)']);
        row = row.replace("{{REGISTRANT_ID}}", user_data[id]['ID']);
        row = row.replace("{{HTML_FILENAME}}", user_data[id]['link_application']);
        row = row.replace("{{REVIEWER_1}}", student_data[id]['reviewer'][0]);
        row = row.replace("{{REVIEWER_2}}", student_data[id]['reviewer'][1]);
        row = row.replace("{{OVERALL_COMMENT_1}}", student_data[id]['overall_comment'][0]);
        row = row.replace("{{OVERALL_COMMENT_2}}", student_data[id]['overall_comment'][1]);
        project_list_tmp = "";
        sep = "";
        
        if user_data[id]['selected']:
            # current student is selected for project; display it in special way
            row = row.replace("{{REGISTRANT_SELECTED}}", "registrant_selected");
        else:
            # ordinary row
            row = row.replace("{{REGISTRANT_SELECTED}}", "");
    
    #    for fldName in ['1', '2', '3']:
        for fldName in ['Choice 1', 'Choice 2', 'Choice 3']:        
            # get all three projects and first add all user's first choise, then second and then third choice
            if user_data[id][fldName].strip():
                # project is defined
                proj = user_data[id][fldName].split(" ", 1);
                projID = int(proj[0].strip());
                project_list_tmp += "{0} <a href='#project_{1}'>{2}</a>".format(sep,projID,projID)
                sep = ", "
    
        row = row.replace("{{PROJECT_ID_LIST}}", project_list_tmp);
    
        for part in ['motivation','ambasador','technical']:
            # add all parts
            html_fld = part.upper();
            row = row.replace("{{"+ html_fld +"_P1}}", "{0}".format(student_data[id][part]['p'][0]));
            row = row.replace("{{"+ html_fld +"_P2}}", "{0}".format(student_data[id][part]['p'][1]));
            row = row.replace("{{"+ html_fld +"_COMMENT_P1}}", "{0}".format(student_data[id][part]['comment'][0]));
            row = row.replace("{{"+ html_fld +"_COMMENT_P2}}", "{0}".format(student_data[id][part]['comment'][1]));
    
            if student_data[id][part]['avg'] > 0:
                row = row.replace("{{"+ html_fld +"_AVG}}", "{0:.2f}".format(student_data[id][part]['avg']));
            else:
                row = row.replace("{{"+ html_fld +"_AVG}}", "");
            
        if student_data[id]['average'] > 0:
            row = row.replace("{{AVERAGE_P}}", "{0:.2f}".format(student_data[id]['average']));
        else:
            row = row.replace("{{AVERAGE_P}}", "");
    
        for prefNo in range(1,4):
            # display all preferences
            row = row.replace("{{PREFERENCE_" + "{0}".format(prefNo) +"_SHORT_COMPULSORY}}", 
                              "{0}<br>{1}".format(student_data[id]['preference'][0][prefNo-1][0], student_data[id]['preference'][1][prefNo-1][0]));
            row = row.replace("{{PREFERENCE_" + "{0}".format(prefNo) +"_SHORT_DESIRABLE}}", 
                              "{0}<br>{1}".format(student_data[id]['preference'][0][prefNo-1][1], student_data[id]['preference'][1][prefNo-1][1]));
            row = row.replace("{{PREFERENCE_" + "{0}".format(prefNo) +"_COMPULSORY}}", 
                              "{0}: {1}\n{2}: {3}".format(student_data[id]['reviewer'][0], student_data[id]['preference'][0][prefNo-1][0], 
                                                            student_data[id]['reviewer'][1], student_data[id]['preference'][1][prefNo-1][0]));
            row = row.replace("{{PREFERENCE_" + "{0}".format(prefNo) +"_DESIRABLE}}", 
                              "{0}: {1}\n{2}: {3}".format(student_data[id]['reviewer'][0], student_data[id]['preference'][0][prefNo-1][1], 
                                                            student_data[id]['reviewer'][1], student_data[id]['preference'][1][prefNo-1][1]));
    
        rows += row;
        no += 1;
        
        
    content_registrants = registrant_list.format(rows);
    
    # add persons list into "index" file content
    content = index_data
    content = content.replace("{{CONTENT_PROJECTS}}", content_projects)
    content = content.replace("{{CONTENT_REGISTRANTS}}", content_registrants)
    save_content("evaluation.html", skeleton, "Summer of HPC 2018 - Project evaluation results", generation_date, content)
    
    print("All done!")