Index: /js/human_3d_alignment/package.json
===================================================================
--- /js/human_3d_alignment/package.json	(revision 910)
+++ /js/human_3d_alignment/package.json	(revision 911)
@@ -25,6 +25,6 @@
   "contributors": [
     "Maciej Komosinski <maciej.komosinski@cs.put.poznan.pl>",
-    "Grzegorz Latosiński",
     "Agnieszka Mensfelt <agnieszka.mensfelt@cs.put.poznan.pl>",
+    "Artur Olejnik",
     "Szymon Ulatowski"
   ],
@@ -48,8 +48,14 @@
     "react-grid-layout": "^0.16.6",
     "react-icons": "^2.2.7",
+    "react-input-slider": "^5.1.4",
+    "react-select": "^3.0.8",
     "react-treebeard": "^2.1.0",
     "strip-comment": "^1.1.3",
     "three": "^0.88.0",
-    "three-orbit-controls": "^82.1.0"
+    "three-css3drenderer": "^1.0.1",
+    "three-orbit-controls": "^82.1.0",
+    "three-trackballcontrols": "0.0.8",
+    "three-transform-controls": "^1.0.4",
+    "tween": "^0.9.0"
   },
   "devDependencies": {
Index: /js/human_3d_alignment/src/index.jsx
===================================================================
--- /js/human_3d_alignment/src/index.jsx	(revision 910)
+++ /js/human_3d_alignment/src/index.jsx	(revision 911)
@@ -1,8 +1,17 @@
 /*global Module*/
 "use strict";
+import http from 'http';
 import React from 'react';
+import Genotypes from './utils/genotypes';
 import TitlePanel from './viewskeleton/titlepanel';
 import WidgetsContainer from './viewskeleton/widgetscontainer';
+import TextViewer from './widgets/textviewer';
+import ParmViewer from './widgets/parmviewer';
 import SimilViewer from './widgets/similviewer';
+import FitViewer from './widgets/fitviewer';
+import SliderViewer from './widgets/sliderviewer';
+import EndViewer from './widgets/endviewer';
+
+const ROUNDS = 15;
 
 const styles = {
@@ -28,5 +37,4 @@
 };
 
-//const mql = window.matchMedia('(min-width: 800px)');
 
 /**
@@ -44,5 +52,9 @@
         window.genetics = new Module.PreconfiguredGenetics();
         this.layout = [
-            {name:'0,similviewer', x: 0, y: 0, w: 12, h: 4}
+            {name:'0,textviewer', x: 0, y: 0, w: 9, h: 1},
+            {name:'2,similviewer', x: 0, y: 1, w: 6, h: 4},
+            {name:'3,fitviewer', x: 6, y: 1, w: 6, h: 2},
+            {name:'4,sliderviewer', x: 6, y: 3, w: 6, h: 2},
+            {name:'1,parmviewer', x: 9, y: 0, w: 3, h: 1}
         ];
 
@@ -50,6 +62,64 @@
 
         this.state = {
-            parametersmodal: false
+            genotypes: 0,
+            round: 0,
+            genotype1: '',
+            genotype2: '',
+            pairs: [],
+            id1: 0,
+            id2: 0,
+            parts1: 0,
+            parts2: 0,
+            selected1: [],
+            selected2: [],
+            position1: [0, 0, 0],
+            position2: [0, 0, 0],
+            rotation1: [0, 0, 0],
+            rotation2: [0, 0, 0],
+            userId: 0,
+            userIp: 'localhost',
+            timeStart: 0,
+            selectedGender: {value: "empty", label: " "},
+            selectedYear: {value: "empty", label: " "},
+            percent: 0,
+            sliderUpdated: true,
+            isDisable: true,
+            isFinished: false,
+            fitHeight: 2,
+            fitWidth: 6,
+            controlMode: 'translate',
+            blockView: true,
+            result: ''
         };
+
+        this.start = this.start.bind(this);
+        this.getIp = this.getIp.bind(this);
+        this.nextRound = this.nextRound.bind(this);
+        this.saveRound = this.saveRound.bind(this);
+        this.saveFit = this.saveFit.bind(this);
+        this.refresh = this.refresh.bind(this);
+        this.sendToServer = this.sendToServer.bind(this);
+        this.finishApp = this.finishApp.bind(this);
+        this.isReady = this.isReady.bind(this);
+        this.isFitted = this.isFitted.bind(this);
+        this.browserData = this.browserData.bind(this);
+        this.loadNewGenotypes = this.loadNewGenotypes.bind(this);
+        this.handleChangeStartTime = this.handleChangeStartTime.bind(this);
+        this.handleChangeId = this.handleChangeId.bind(this);
+        this.handleChangeIp = this.handleChangeIp.bind(this);
+        this.handleChangeGender =  this.handleChangeGender.bind(this);
+        this.handleChangeYear = this.handleChangeYear.bind(this);
+        this.handleChangePercent = this.handleChangePercent.bind(this);
+        this.handleChangeStartTime = this.handleChangeStartTime.bind(this);
+        this.handleChangeFitHeight = this.handleChangeFitHeight.bind(this);
+        this.handleChangeFitWidth = this.handleChangeFitWidth.bind(this);
+        this.handleChangeControlMode = this.handleChangeControlMode.bind(this);
+        this.handleChangePosition1 = this.handleChangePosition1.bind(this);
+        this.handleChangePosition2 = this.handleChangePosition2.bind(this);
+        this.handleChangeRotation1 = this.handleChangeRotation1.bind(this);
+        this.handleChangeRotation2 = this.handleChangeRotation2.bind(this);
+        this.handleChangeBlockView = this.handleChangeBlockView.bind(this);
+        this.onClickNext = this.onClickNext.bind(this);
+        this.onClickFinish = this.onClickFinish.bind(this);
     }
 
@@ -58,5 +128,21 @@
     */
     componentDidMount() {
-        this.useLayout(this.layout);
+        window.addEventListener( 'keydown', ( event ) => {
+            switch ( event.keyCode ) {
+                case 84: // T
+                    this.handleChangeControlMode( "translate" );
+                    break;
+                case 82: // R
+                    this.handleChangeControlMode( "rotate" );
+                    break;
+            }
+        } );
+        let timeStart = new Date();
+        this.handleChangeStartTime(timeStart); //set time start
+        this.handleChangeId(  Math.round(timeStart.getTime() / 1000).toString() +  (Math.floor(Math.random() * (9999999 - 1000000 + 1) ) + 1000000).toString() + this.browserData().toString() ); //set user id = time + random + browserData_hash
+        this.getIp();   //set user ip
+        this.genotypes = new Genotypes(this, "https://raw.githubusercontent.com/arturolejnik95/human_3d_alignment/master/walking.gen");   //load text from file to this.genotypes
+        let head = "'User ID'|'User IP'|'Gender'|'Year of born'|'Start time'|'Stop time'|'Position of 1st'|'Position of 2nd'|'Rotation of 1st'|'Rotation of 2nd'|'ID 1st'|'ID 2nd'|'Fit'|'Result'\n"
+        this.handleChangeResult(head);
     }
 
@@ -65,5 +151,471 @@
     */
     componentDidUpdate() {
-        window.dispatchEvent(new Event('resize'));
+        //window.dispatchEvent(new Event('resize'));
+        if (this.state.genotype1 != '' && this.state.genotype2 != '') {
+            this.useLayout(this.layout);
+        }
+    }
+
+
+    /**
+     * Start questionnaire if genotypes are loaded
+     */
+    start() {
+        this.setState({ genotypes: this.genotypes.id.length }, function() {
+            console.log(`Genotypes: `, this.state.genotypes);
+        });
+
+        this.loadNewGenotypes();
+        this.handleChangeBlockView(false);
+        this.useLayout(this.layout);
+    }
+
+    getIp() {
+        http.get({'host': 'api.ipify.org', 'port': 80, 'path': '/'}, (resp) => {
+            resp.on('data', ip => {
+                this.handleChangeIp(ip)
+            });
+        });
+    }
+
+    /**
+     * Save data about this round
+     */
+    saveRound() {
+        this.setState({ sliderUpdated: false }, function() {
+            console.log('Slider Updated: ' + this.state.sliderUpdated);
+        });
+        this.isReady();
+    }
+
+    /**
+     * Preset result as:
+     * user ID - IP - gender - year of born - start : end - position of 1. : position of 2.
+     * - rotation of 1. : rotation of 2. - id of 1. : id of second - pairs (1. mesh : 2. mesh) - fit result (0 - 100) ;
+     */
+    saveFit() {
+        let min = Math.min(this.state.parts1, this.state.parts2);
+        let timeStop = new Date();
+        let start = this.state.timeStart;
+        let stop = timeStop;
+        start = ("0" + start.getDate()).slice(-2) + '.' + ("0" + (start.getMonth() + 1)).slice(-2) + '.' + start.getFullYear() + ' ' + String(start.getHours()).padStart(2, '0') + ':' + String(start.getMinutes()).padStart(2, '0') + ':' + String(start.getSeconds()).padStart(2, '0');
+        stop = ("0" + stop.getDate()).slice(-2) + '.' + ("0" + (stop.getMonth() + 1)).slice(-2) + '.' + stop.getFullYear() + ' ' + String(stop.getHours()).padStart(2, '0') + ':' + String(stop.getMinutes()).padStart(2, '0') + ':' + String(stop.getSeconds()).padStart(2, '0');
+
+        let fit =   this.state.userId + '|' +
+                    this.state.userIp + '|' +
+                    this.state.selectedGender.value + '|' +
+                    this.state.selectedYear.value + '|' +
+                    start + '|' +
+                    stop + '|' +
+                    '(' + this.state.position1[0] + ',' + this.state.position1[1] + ',' + this.state.position1[2] + ')|' +  
+                    '(' + this.state.position2[0] + ',' + this.state.position2[1] + ',' + this.state.position2[2] + ')|' +  
+                    '(' + this.state.rotation1[0] + ',' + this.state.rotation1[1] + ',' + this.state.rotation1[2] + ')|' +  
+                    '(' + this.state.rotation2[0] + ',' + this.state.rotation2[1] + ',' + this.state.rotation2[2] + ')|';  
+                    
+        
+        let pair = this.state.pairs[this.state.pairs.length - 1];
+        fit = fit + this.genotypes.id[pair[0]] + '|' + this.genotypes.id[pair[1]] + '|';
+
+        for (let i = 0; i < min; i++) {
+            fit = fit + this.state.selected1[i] + ':' + (this.state.selected2[i].charCodeAt(0) - 65 + 1);
+            if (i < min - 1) {
+                fit = fit + ';';
+            }
+        }
+        fit = fit + '|' + this.state.percent + '\n';
+
+        this.sendToServer(fit);
+
+        this.handleChangeResult(this.state.result + fit);
+        this.handleChangeStartTime(timeStop);
+    }
+
+
+
+    sendToServer(fit) {
+        let rawFile = new XMLHttpRequest();
+        rawFile.addEventListener('load', () => {
+            console.log(rawFile.responseText);
+        });
+        rawFile.addEventListener('error', () => {
+            console.log('Błąd wysyłania na serwer');
+        });
+        
+        rawFile.open("POST", 'https://ptsv2.com/t/b7nhq-1578108725/post');
+        rawFile.setRequestHeader("Content-type", 'text/plain');
+        rawFile.send(fit);
+    }
+
+    /**
+     * Load next pair of genotypes
+     */
+    nextRound() {
+        this.loadNewGenotypes();
+        this.handleChangeBlockView(false);
+    }
+
+    /**
+     * Refresh used default layout
+     */
+    refresh() {
+        this.useLayout(this.layout);
+    }
+
+    /**
+     * Load new genotypes to simulator viewer 
+     */
+    loadNewGenotypes() {
+        //Firstly it chooses pair of genotypes that user doesnt used before
+        let rand1, rand2, amount1, amount2, gen1, gen2;
+
+        do {
+            rand1 = 0, rand2 = 0;
+            do  {
+                while (rand1 == rand2) {
+                    rand1 = Math.floor(Math.random() * this.state.genotypes);
+                    rand2 = Math.floor(Math.random() * this.state.genotypes);
+                }
+            } while (this.state.pairs.includes([rand1, rand2]) || this.state.pairs.includes([rand2, rand1]));
+
+            //This part load genotypes to the state
+            gen1 = this.genotypes.genotype[rand1];
+            gen2 = this.genotypes.genotype[rand2];
+            amount1 = gen1.split('').filter(function(sign){return sign === 'X'}).length;
+            amount2 = gen2.split('').filter(function(sign){return sign === 'X'}).length;
+            if (amount1 > 0) {
+                amount1++;
+            }
+            if (amount2 > 0) {
+                amount2++
+            }
+        } while (amount1 > 52 || amount2 > 52);
+
+        let newpairs = this.state.pairs;
+        if (amount1 <= amount2) {
+            newpairs.push([rand1, rand2]);
+            this.setState({ genotype1: gen1, genotype2: gen2 }, function() {
+                console.log(`Genotypes: `, this.state.genotype1, this.state.genotype2);
+            });
+            this.setState({parts1: amount1, parts2: amount2}, function() {
+                console.log(this.state.parts1 + ' ' + this.state.parts2);
+            });
+        } else {
+            newpairs.push([rand2, rand1]);
+            this.setState({ genotype1: gen2, genotype2: gen1 }, function() {
+                console.log(`Genotypes: `, this.state.genotype1, this.state.genotype2);
+            });
+            this.setState({parts1: amount2, parts2: amount1}, function() {
+                console.log(this.state.parts1 + ' ' + this.state.parts2);
+            });
+        }
+        this.setState({ pairs: newpairs }, function() {
+            console.log(`Pairs: `, this.state.pairs);
+        });
+
+        //Load tables of selected parts in fitviewer
+        let min = Math.min(amount1, amount2);
+        let s1 = [];
+        let s2 = [];
+        for (let i = 0; i < min; i++) {
+            s1.push((i+1).toString());
+            s2.push(' ');
+        }
+
+        //Start new round and load to state tables of selected and round
+        let r = this.state.round + 1;
+        this.setState({ round: r, selected1: s1, selected2: s2}, function() {
+            console.log(`Round and state `, this.state.round + '. ' + this.state.selected1 + ' ' + this.state.selected2);
+        });
+    }
+
+    /**
+     * Check is user ready to go to the next question by checking choosed gender, birth year and percent of similarity
+     */
+    isReady() {
+        if (this.state.selectedGender.value != 'empty' && this.state.selectedYear.value != 'empty' && this.state.sliderUpdated) {
+            this.setState({isDisable: false}, function() {
+                console.log(this.state.isDisable);
+            });
+        } else {
+            if (!this.state.isDisable) {
+                this.setState({isDisable: true}, function() {
+                    console.log(this.state.isDisable);
+                });
+            }
+        }
+    }
+
+    /**
+     * Check is user matched all needed sticks
+     */
+    isFitted() {
+        let index1 = this.state.selected1.indexOf(' ');
+        let index2 = this.state.selected2.indexOf(' ');
+
+        if (index1 < 0 && index2 < 0 && this.state.sliderUpdated) {
+            this.setState({sliderUpdated: false}, function() {
+                console.log(this.state.sliderUpdated);
+                this.isReady();
+            });
+        }
+    }
+
+    /**
+     * Return hash data of browser
+     */
+    browserData() {
+        let data = navigator.userAgent;
+        let hash = 0;
+        for (let i = 0; i < data.length; i++) {
+            let character = data.charCodeAt(i);
+            hash = ((hash<<5)-hash)+character;
+            hash = hash & hash; // Convert to 32bit integer
+        }
+        return hash;
+    }
+
+    /**
+     * Performed at the end of the survey
+     */
+    finishApp() {
+        this.layout = [
+            {name:'5,endviewer', x: 0, y: 0, w: 12, h: 4}
+        ];
+        this.useLayout(this.layout);
+    }
+
+    /**
+     * Allow to change gender in state
+     * @param {string} gen choosed gender by user in listbox 
+     */
+    handleChangeGender(gen) {
+        this.setState({ selectedGender: gen }, function() {
+            console.log(`Gender selected:`, this.state.selectedGender);
+            console.log(this.genotypes.id.length)
+            this.isReady();
+        });
+    };
+    
+    /**
+     * Allow to change IP
+     * @param {number} ip user IP
+     */
+    handleChangeIp(ip) {
+        this.setState({ userIp: ip }, function() {
+            console.log(`IP:`, this.state.userIp);
+        });
+    }
+    
+    /**
+     * Allow to change user ID
+     * @param {number} id user ID
+     */
+    handleChangeId(id) {
+        this.setState({ userId: id }, function() {
+            console.log(`ID:`, this.state.userId);
+        });
+    }
+    
+    /**
+     * Allow to change start time
+     * @param {number} time time of begging fitting framsticks
+     */
+    handleChangeStartTime(time) {
+        this.setState({ timeStart: time }, function() {
+            console.log(`Start time:`, this.state.timeStart);
+        });
+    }
+
+    /**
+     * Allow to change birth year in state
+     * @param {number} year choosed birth year by user in listbox
+     */
+    handleChangeYear(year) {
+        this.setState({ selectedYear: year }, function() {
+            console.log(`Birth year selected:`, this.state.selectedYear);
+            this.isReady();
+        });
+    }
+
+    /**
+     * Allow to change percent in state and mark this in state.sliderUpdated
+     * @param {Integer} per choosed similarity of framsticks by user in percentage
+     */
+    handleChangePercent(per) {
+        this.setState({ percent: per, sliderUpdated: true }, function() {
+            console.log('Percent selected: ' + this.state.percent + ' ' + this.state.sliderUpdated);
+            this.isReady();
+        });
+    }
+
+    /**
+     * 
+     * @param {number} nr framstick id
+     * @param {number} pos position on the match map
+     * @param {*} val id of choosed stick
+     */
+    handleChangeSelected(nr, pos, val) {
+        if (nr == 1) {
+            this.setState(state => {
+                const selected1 = state.selected1.map((item, i) => {
+                    if (pos === i) {
+                        return val;
+                    } else {
+                        return item;
+                    }
+                });
+
+                return {
+                    selected1,
+                };
+            },  function() {
+                console.log(this.state.selected1);
+                this.isFitted();
+            });
+        } else {
+            this.setState(state => {
+                const selected2 = state.selected2.map((item, i) => {
+                    if (pos === i) {
+                        let v = val.charCodeAt(0);
+                        if (v > 90) {
+                            v = v - 6;
+                        }
+                        let res = String.fromCharCode(v);
+                        return res;
+                    } else {
+                        return item;
+                    }
+                });
+
+                return {
+                    selected2,
+                };
+            }, function() {
+                console.log(this.state.selected2);
+                this.isFitted();
+            });
+        }
+    }
+    
+    /**
+     * Function to inform fitviewer about change of height to update scrollbar (for firefox)
+     * @param {number} h height
+     */
+    handleChangeFitHeight(h) {
+        this.setState({ fitHeight: h }, function() {
+            console.log(`Fit Height:`, this.state.fitHeight);
+        });
+    }
+    
+    /**
+     * Function to inform fitviewer about change of width to update scrollbar (for firefox)
+     * @param {number} w width
+     */
+    handleChangeFitWidth(w) {
+        this.setState({ fitWidth: w }, function() {
+            console.log(`Fit Width:`, this.state.fitWidth);
+        });
+    }
+
+    /**
+     * Allow to change transform controler mode
+     * @param {number} mode translate or rotation
+     */
+    handleChangeControlMode(mode) {
+        this.setState({ controlMode: mode }, function() {
+            console.log(`Control mode:`, this.state.controlMode);
+        });
+    }
+
+    /**
+     * Allow to save actural position of first genotype
+     * @param {Array} pos position [x, y, z] of first genotype
+     */
+    handleChangePosition1(pos) {
+        this.setState({ position1: pos}, function() {
+            console.log('Position1: ', this.state.position1);
+        });
+    }
+
+    /**
+     * Allow to save actural position of second genotype
+     * @param {Array} pos position [x, y, z] of second genotype
+     */
+    handleChangePosition2(pos) {
+        this.setState({ position2: pos}, function() {
+            console.log('Position2: ', this.state.position2);
+        });
+    }
+
+    /**
+     * Allow to save actural rotation of first genotype
+     * @param {Array} rot rotation [x, y, z] of first genotype
+     */
+    handleChangeRotation1(rot) {
+        this.setState({ rotation1: rot}, function() {
+            console.log('Rotation1: ', this.state.rotation1);
+        });
+    }
+
+    /**
+     * Allow to save actural rotation of second genotype
+     * @param {Array} rot rotation [x, y, z] of second genotype
+     */
+    handleChangeRotation2(rot) {
+        this.setState({ rotation2: rot}, function() {
+            console.log('Rotation2: ', this.state.rotation2);
+        });
+    }
+
+    /**
+     * Allow to block view in simviewer
+     * @param {Array} rot rotation [x, y, z] of second genotype
+     */
+    handleChangeBlockView(bool) {
+        this.setState({ blockView: bool}, function() {
+            console.log('Block View: ', this.state.blockView);
+        });
+    }
+
+    /**
+     * Allow to change finish result that will be save in the file at the end
+     * @param {string} res text to be save in file
+     */
+    handleChangeResult(res) {
+        this.setState({ result: res }, function() {
+            console.log('Result: ', this.state.result);
+        });
+    }
+
+    /**
+     * Next button function
+     */
+    onClickNext() {
+        this.handleChangeBlockView(true);
+        this.saveFit();
+        if (this.state.round == ROUNDS) {
+            this.setState({ isFinished: true }, function() {
+                console.log('Finish state: ' + this.state.isFinished);
+    
+                if (this.state.isFinished) {
+                    this.finishApp();
+                }
+            });
+        } else {
+            this.nextRound();
+        }
+    }
+
+    /**
+     * Close button function
+     */
+    onClickFinish() {
+        this.setState({ isFinished: true }, function() {
+            console.log('Finish state: ' + this.state.isFinished);
+
+            if (this.state.isFinished) {
+                this.finishApp();
+            }
+        });
     }
 
@@ -76,4 +628,8 @@
         for (let i = 0; i < layout.length; i++) {
             newlayout.push({name: layout[i].i, x: layout[i].x, y: layout[i].y, w: layout[i].w, h: layout[i].h});
+            if (newlayout[i].name == '2fitviewer') {
+                this.handleChangeFitHeight(newlayout[i].h);
+                this.handleChangeFitWidth(newlayout[i].w);
+            }
         }
     }
@@ -87,6 +643,62 @@
             let name = layout[i].name.split(',')[1];
             switch (name) {
+                case 'textviewer':
+                    items.push({content: <TextViewer/>, i: "" + i + 'textviewer',
+                        x: layout[i].x, y: layout[i].y, w: layout[i].w, h: layout[i].h});
+                    break;
                 case 'similviewer':
-                    items.push({content: <SimilViewer/>, i: "" + i + 'similviewer',
+                    items.push({content: <SimilViewer
+                            genotype1 = {this.state.genotype1}
+                            genotype2 = {this.state.genotype2}
+                            selected1 = {this.state.selected1}
+                            selected2 = {this.state.selected2}
+                            blockView = {this.state.blockView}
+                            handleChangePosition1 = {(pos) => this.handleChangePosition1(pos)}
+                            handleChangePosition2 = {(pos) => this.handleChangePosition2(pos)}
+                            handleChangeRotation1 = {(rot) => this.handleChangeRotation1(rot)}
+                            handleChangeRotation2 = {(rot) => this.handleChangeRotation2(rot)}
+                            controlMode = {this.state.controlMode}
+                            round = {this.state.round}/>, 
+                        i: "" + i + 'similviewer',
+                        x: layout[i].x, y: layout[i].y, w: layout[i].w, h: layout[i].h});
+                    break;
+                case 'parmviewer':
+                    items.push({content: <ParmViewer 
+                            handleChangeYear = {(year) => {this.handleChangeYear(year)}} 
+                            handleChangeGender = {(gen) => {this.handleChangeGender(gen)}}
+                        />, 
+                        i: "" + i + 'parmviewer',
+                        x: layout[i].x, y: layout[i].y, w: layout[i].w, h: layout[i].h});
+                    break;
+                case 'fitviewer':
+                    items.push({content: <FitViewer 
+                            selected1 = {this.state.selected1} 
+                            selected2 = {this.state.selected2} 
+                            parts1 = {this.state.parts1} 
+                            parts2 = {this.state.parts2}
+                            fitHeight = {this.state.fitHeight}
+                            fitWidth = {this.state.fitWidth}
+                            handleChangeSelected = {(nr, pos, val) => {this.handleChangeSelected(nr, pos, val)}}/>,
+                        i: "" + i + 'fitviewer',
+                        x: layout[i].x, y: layout[i].y, w: layout[i].w, h: layout[i].h});
+                    break;
+                case 'sliderviewer':
+                    items.push({content: <SliderViewer 
+                            isDisable = {this.state.isDisable}
+                            parts1 = {this.state.parts1}
+                            parts2 = {this.state.parts2}
+                            selected1 = {this.state.selected1}
+                            selected2 = {this.state.selected2}
+                            onClickNext = {() => {this.onClickNext()}}
+                            onClickFinish = {() => {this.onClickFinish()}}
+                            handleChangePercent = {(per) => {this.handleChangePercent(per)}}/>,
+                        i: "" + i + 'sliderviewer',
+                        x: layout[i].x, y: layout[i].y, w: layout[i].w, h: layout[i].h});
+                    break;
+                case 'endviewer':
+                    items.push({content: <EndViewer 
+                            userId = {this.state.userId}
+                            result = {this.state.result}/>,
+                        i: "" + i + 'endviewer',
                         x: layout[i].x, y: layout[i].y, w: layout[i].w, h: layout[i].h});
                     break;
@@ -104,14 +716,18 @@
         const contentHeader = (
             <span>   
-                <span style={{marginLeft: '20px'}}>Matching in 3D</span> 
+                <span style={{marginLeft: '20px', fontFamily: "'Fira Mono', Monaco, 'Andale Mono', 'Lucida Console', 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace"}}>
+                    Ankieta
+                </span> 
             </span>
         );
-        
+
         return (
-                <TitlePanel title={contentHeader}>
-                    <div style={styles.content}>
-                        {this.container}
-                    </div>
-                </TitlePanel>
+            <TitlePanel 
+                title={contentHeader}
+            >
+                <div style={styles.content}>
+                    {this.container}
+                </div>
+            </TitlePanel>
         );
     }
Index: /js/human_3d_alignment/src/utils/genotypes.js
===================================================================
--- /js/human_3d_alignment/src/utils/genotypes.js	(revision 911)
+++ /js/human_3d_alignment/src/utils/genotypes.js	(revision 911)
@@ -0,0 +1,95 @@
+/*global Module*/
+"use strict";
+
+/**
+ * Class to keep genotypes data
+ */
+class Genotypes {
+
+    /**
+     * Default constructor for genotypes object
+     * @param {string} path path to .gen file with genotypes
+     */
+    constructor(obj, path) {
+        this.parent = obj;
+        this.loaded = false;
+        this.id = [];
+        this.name = [];
+        this.genotype = [];
+        this.readGenotypesFromFile(path);
+        
+    }
+
+    /**
+     * Read genotypes from genotypes.gen file.
+     * @param {string} file path to genotypes.gen
+     */
+    readGenotypesFromFile(file) {
+        let rawFile = new XMLHttpRequest();
+        rawFile.open("GET", file, true);
+        rawFile.onload = (e) => {
+            if (rawFile.readyState === 4) {
+                if (rawFile.status === 200) {
+                    this.readGenotypesFromText(rawFile.responseText);
+                } else {
+                    console.error(rawFile.statusText);
+                }
+            }
+        };
+        rawFile.onerror = (e) => {
+            console.error(rawFile.statusText);
+        };
+        rawFile.send(null);
+    }
+
+    /**
+     * Read genotypes from text read from genotypes.gen. TODO mk> This function should be removed; use SDK functionality instead for reliable parsing.
+     * @param {string} text 
+     */
+    readGenotypesFromText(text) {
+        let textTable = text.split('org:\n');
+        let i = 1;
+        while (i < textTable.length) {
+            let lines = textTable[i].split('\n');
+            if (lines[0].includes('name:')) {
+                let j = 0;
+                let gen = '';
+                let name = '';
+                let id = '';
+                while (j < lines.length) {
+                    if (lines[j].includes('name:')) {
+                        name += lines[j].split(':')[1];
+                    } else if (lines[j].includes('genotype:')) {
+                        gen += lines[j].replace('genotype:', '');
+                        let k = j + 1;
+                        while (!lines[k].includes('info_timestamp:')) {
+                            if (lines[k] != '\n') {
+                                gen += ' ' + lines[k];
+                            } else {
+                                gen += ' '
+                            }
+                            k++;
+                        }
+                        gen = gen.split('~').join('');
+                    } else if (lines[j].includes('num:')) {
+                        id += lines[j].split(':')[1];
+                    }
+                    j++;
+                }
+                if (!gen.includes('//0')) {
+                    this.name.push(name);
+                    this.genotype.push(gen);
+                    this.id.push(id);
+                }
+            }
+
+            i++;
+        }
+        this.loaded = true;
+        this.parent.start();
+    }
+
+}
+
+
+export default Genotypes;
Index: /js/human_3d_alignment/src/viewskeleton/widgetscontainer.jsx
===================================================================
--- /js/human_3d_alignment/src/viewskeleton/widgetscontainer.jsx	(revision 910)
+++ /js/human_3d_alignment/src/viewskeleton/widgetscontainer.jsx	(revision 911)
@@ -52,5 +52,5 @@
      */
     createElement(el) {
-        const removeStyle = {
+        const headerStyle = {
             right: "2px",
             marginRight: "10px",
@@ -70,8 +70,7 @@
                 <div style={{display: 'table-row', textAlign: 'right'}}>
                 <span
-                    className="remove"
-                    style={removeStyle}
-                    onClick={this.onRemoveItem.bind(this,el.i)}
-                >&#10006;</span>
+                    className="header"
+                    style={headerStyle}
+                > </span>
                 </div>
                 <div style={{display: 'table-row', height: '100%'}}>
@@ -164,4 +163,5 @@
                     onBreakpointChange={this.onBreakpointChange}
                     cols={{ lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }}
+                    rowHeight={150}
                     className="layout"
                     {...this.props}
Index: /js/human_3d_alignment/src/visualization/camera.js
===================================================================
--- /js/human_3d_alignment/src/visualization/camera.js	(revision 910)
+++ /js/human_3d_alignment/src/visualization/camera.js	(revision 911)
@@ -87,4 +87,7 @@
         let modelSphere = modelBox.getBoundingSphere();
 
+        this.targetPosition = modelSphere.center.clone();
+        this.cameraPosition = modelSphere.center.clone().addScalar(modelSphere.radius);
+
         return {
             target: {
Index: /js/human_3d_alignment/src/visualization/framstick.js
===================================================================
--- /js/human_3d_alignment/src/visualization/framstick.js	(revision 911)
+++ /js/human_3d_alignment/src/visualization/framstick.js	(revision 911)
@@ -0,0 +1,226 @@
+/*global Module*/
+"use strict";
+
+import * as THREE from 'three';
+import PartMeshFactory from './partmeshfactory';
+import JointMeshFactory from './jointmeshfactory';
+import GenotypeParser from '../utils/genotypeparser';
+import { geometry } from './transformations';
+
+
+/**
+ * @file Framstick Object
+ * @author Patryk Gliszczynski
+ * @version 1.2
+ */
+class Framstick {
+
+  /**
+   * 
+   * @param {Genotype} genotype genotype of creating framstick
+   */
+  constructor(genotype, viewer) {
+    this.viewer = viewer;
+    this.genotype = genotype;
+    this.parts = [];
+    this.joints = [];
+    this.meshes = [];
+    
+    this.positions = [];
+    this.color = 'white';
+    this.avgPosition = new THREE.Vector3(0, 0, 0);
+
+    this.partfactory = new PartMeshFactory(geometry.part);
+    this.jointfactory = new JointMeshFactory(geometry.joint);
+
+    this.mesh = new THREE.Group();
+    this.loadFromGenotype();
+
+    for (let i = 0; i < this.mesh.children.length; i++) {
+      this.avgPosition.add(this.mesh.children[i].position.clone());
+    }
+
+    this.avgPosition.divideScalar(this.mesh.children.length);
+
+    for (let i = 0; i < this.mesh.children.length; i++) {
+      this.mesh.children[i].position.sub(this.avgPosition);
+    }
+
+    this.viewer.scene.add(this.mesh);
+
+  }
+
+  /**
+   * Change Framstick's color on click
+   */
+  setColor(color) { 
+    if (this.color != color) {
+      let colorTemp = this.color;
+      this.color = color;
+
+      let position = this.mesh.position.clone();
+      let rotation = this.mesh.rotation.clone();
+      this.viewer.scene.remove(this.mesh);
+
+      this.loadFromGenotype();
+
+      this.mesh.position.set( position.x, position.y, position.z );
+      this.mesh.rotation.set(rotation.x, rotation.y, rotation.z, rotation.order );
+
+
+      if (this.color == 'red' || colorTemp == 'red') {
+        for (let i = 0; i < this.meshes.length; i++) {
+          this.viewer.meshes.shift();
+        }
+        for (let i = 0; i < this.parts.length; i++) {
+          this.viewer.parts.shift();
+        }
+        for (let i = this.meshes.length - 1; i >= 0; i--) {
+          this.viewer.meshes.unshift(this.meshes[i]);
+        }
+        for (let i = this.parts.length - 1; i >= 0; i--) {
+          this.viewer.parts.unshift(this.parts[i]);
+        }
+      } else {
+        for (let i = 0; i < this.meshes.length; i++) {
+          this.viewer.meshes.pop();
+        }
+        for (let i = 0; i < this.parts.length; i++) {
+          this.viewer.parts.pop();
+        }
+        for (let i = 0; i < this.meshes.length; i++) {
+          this.viewer.meshes.push(this.meshes[i]);
+        }
+        for (let i = 0; i < this.parts.length; i++) {
+          this.viewer.parts.push(this.parts[i]);
+        }
+      }
+
+      this.viewer.scene.add(this.mesh);
+    }
+  }
+
+  addText(nr) {
+    for (let i = 0; i < this.positions.length; i++) {
+      let div = document.createElement("div");
+      div.className = "label";
+      div.style.position = 'absolute';
+      div.style.color = 'white';
+      div.style.textAlign = 'center';
+      div.style.display = '';
+      div.style.fontFamily = "'Fira Mono', Monaco, 'Andale Mono', 'Lucida Console', 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace";
+      //div.style.margin = '-5px 0 0 15px';
+      div.style.pointerEvents = 'none';
+      div.style.webkitUserSelect = 'none';
+      div.style.mozUserSelect = 'none';
+      div.style.msUserSelect = 'none';
+      div.style.userSelect = 'none';
+
+      if (nr == 1) {
+        div.textContent = (i+1).toString();
+      } else {
+        let label = '';
+        if (i + 1 + 64 > 90) {
+          label = String.fromCharCode(i + 1 + 70);
+        } else {
+          label = String.fromCharCode(i + 1 + 64);
+        }    
+        div.textContent = label;
+      }
+      
+      let pos = new THREE.Vector3().copy(this.positions[i]).applyEuler(this.mesh.rotation).add(this.mesh.position);
+      let dis = pos.distanceTo(this.viewer.camera.perspectiveCamera.position);
+      pos.project(this.viewer.camera.perspectiveCamera);
+
+      this.viewer.raycaster.setFromCamera(pos, this.viewer.camera.perspectiveCamera);
+
+      let intersectedObjects = this.viewer.raycaster.intersectObjects(this.viewer.parts);
+      let show = intersectedObjects.length && this.parts[i] === intersectedObjects[0].object;
+
+
+      if (Math.abs(pos.z) > 1 || pos.x < -0.96 || pos.y < -0.96 || pos.x > 0.96 || pos.y > 0.96)  {
+        div.style.display = 'none';
+      } else {
+        div.style.fontSize = (150.0 / dis).toString() + 'px';
+        div.style.display = '';
+
+        if ((150.0 / dis)/(2*this.viewer.container.clientHeight) + pos.y > 1.0 || 
+            pos.y - (150.0 / dis)/(2*this.viewer.container.clientHeight) < -1.0 || 
+            (150.0 / dis)/(2*this.viewer.container.clientWidth) + pos.x > 1.0 || 
+            pos.x - (150.0 / dis)/(2*this.viewer.container.clientWidth) < -1.0) {
+          div.style.display = 'none';
+        }
+        div.style.zIndex = (-pos.z * .5 + .5) * 100000 | 0;
+
+        if (!show) {
+          //div.style.margin = '-5px 0 0 15px';
+          div.style.display = 'none';
+        }
+        
+        let x = (pos.x *  .5 + .5) * this.viewer.container.clientWidth;
+        let y = (pos.y * -.5 + .5) * this.viewer.container.clientHeight;
+        div.style.transform = `translate(-50%, -50%) translate(${x}px,${y}px)`;
+        this.viewer.container.appendChild(div);
+      }
+
+    }
+  }
+
+  /**
+   * Return framstick position in the world
+   */
+  setPositions() {
+    this.positions = [];
+    let tempV = new THREE.Vector3();
+
+    for (let i = 0; i < this.parts.length; i++) {
+      let mesh = this.parts[i];
+
+      this.viewer.camera.perspectiveCamera.updateMatrixWorld(true, false);
+      mesh.getWorldPosition(tempV);
+      this.positions.push(tempV.clone());
+    }
+  }
+
+  /**
+  * Code below was taken from: http://fugue.synology.me:30000/grzegorzlatosinski/framsticks-js
+  * @author Grzegorz Latosiński
+  * @pull_date 22.01.2018
+  */
+  loadFromGenotype() {
+    this.mesh = new THREE.Group();
+
+    let model = GenotypeParser.getModelFromGenotype(this.genotype);
+
+    if (typeof model !== 'undefined') {
+      let partsforjoints = [];
+      this.meshes = [];
+      this.parts = [];
+      this.joints = [];
+
+      for (let i = 0; i < model.getPartCount(); i++) {
+        let m = this.partfactory.create(model.getPart(i), this.color);
+        partsforjoints.push(m.userData);
+        this.mesh.add(m)
+        this.parts.push(m);
+        this.meshes.push(m);
+      }
+
+      for (let i = 0; i < model.getJointCount(); i++) {
+        let m = this.jointfactory.create(model.getJoint(i), this.color, partsforjoints);
+        
+        this.mesh.add(m);
+        this.joints.push(m);
+        this.meshes.push(m);
+      }
+
+      new THREE.Box3().setFromObject(this.mesh).getCenter(this.mesh.position).multiplyScalar(-1);
+
+      for (let i = 0; i < this.mesh.children.length; i++) {
+        this.mesh.children[i].position.sub(this.avgPosition);
+      }
+    }
+  }
+}
+
+export default Framstick;
Index: /js/human_3d_alignment/src/visualization/jointmeshfactory.js
===================================================================
--- /js/human_3d_alignment/src/visualization/jointmeshfactory.js	(revision 910)
+++ /js/human_3d_alignment/src/visualization/jointmeshfactory.js	(revision 911)
@@ -33,5 +33,5 @@
      * @returns {Mesh}  Mesh for a given joint
      */
-    getNewJointMesh(joint, shapeConfig) {
+    getNewJointMesh(joint, color, shapeConfig) {
         let firstPartPosVec = new THREE.Vector3(
             joint.get_part1().get_p().get_x(), 
@@ -42,24 +42,11 @@
             joint.get_part2().get_p().get_y(), 
             joint.get_part2().get_p().get_z());
-        //let line = new THREE.LineCurve3(firstPartPosVec, secondPartPosVec);
-        //let geometry = new THREE.TubeGeometry(line, numsegmentstube, shapeConfig.radius, 
-        //    shapeConfig.radiusSegments, false);
 
         let direction = new THREE.Vector3().subVectors(secondPartPosVec, firstPartPosVec);
-        let orientation = new THREE.Matrix4();
-
-        let geometry = new THREE.CylinderGeometry(shapeConfig.radius, shapeConfig.radius, direction.length(), shapeConfig.radiusSegments);
-        
-
-        let material = this.transformations.getNewMaterial(
-            joint.get_vcolor().get_x(), 
-            joint.get_vcolor().get_y(), 
-            joint.get_vcolor().get_z());
-        material.transparent = shapeConfig.isTransparent;
-        material.opacity = shapeConfig.opacity;
-        //let mesh = new THREE.Mesh(geometry, material);
-        
+        let geometry = new THREE.CylinderGeometry(shapeConfig.radius, shapeConfig.radius, direction.length() - 2 * 0.18, shapeConfig.radiusSegments);     
+        let material = this.transformations.getNewMaterial(color);   
         let mesh = new THREE.Mesh( geometry, material ); //new Physijs.CylinderMesh( geometry, Physijs.createMaterial(material) ); //new THREE.Mesh( geometry, material );
 
+        let orientation = new THREE.Matrix4();
         orientation.lookAt(firstPartPosVec, secondPartPosVec, new THREE.Object3D().up);
         orientation.multiply(new THREE.Matrix4().set(
@@ -82,5 +69,5 @@
             mesh: mesh, 
             connectedParts: [], 
-            showTransparent: shapeConfig.isTransparent 
+            showTransparent: true 
         };
         return mesh;
@@ -115,12 +102,12 @@
      * @returns {JointMesh} new joint mesh, for properties of Object look at addConnectionInfo jointMesh param documentation
      */
-    create(joint, partMeshes) {
+    create(joint, color, partMeshes) {
         let result;
         let shape = joint.get_shape();
 
         if (this.jointShapes['SHAPE_FIXED'].value == shape) {
-            result = this.getNewJointMesh(joint, this.config.linkShape);
+            result = this.getNewJointMesh(joint, color, this.config.linkShape);
         } else {
-            result = this.getNewJointMesh(joint, this.config.cylinderShape);
+            result = this.getNewJointMesh(joint, color, this.config.cylinderShape);
         }
 
Index: /js/human_3d_alignment/src/visualization/partmeshfactory.js
===================================================================
--- /js/human_3d_alignment/src/visualization/partmeshfactory.js	(revision 910)
+++ /js/human_3d_alignment/src/visualization/partmeshfactory.js	(revision 911)
@@ -36,10 +36,7 @@
      * @returns {PartMesh} info about part mesh
      */
-    getNewSphereMesh(part, sphereRadius, segments, applyScale) {
+    getNewSphereMesh(part, color, sphereRadius, segments, applyScale) {
         let geometry = new THREE.SphereGeometry(sphereRadius, segments, segments);
-        let material = this.transformations.getNewMaterial(
-            part.get_vcolor().get_x(), 
-            part.get_vcolor().get_y(), 
-            part.get_vcolor().get_z());
+        let material = this.transformations.getNewMaterial(color);
         let mesh = null;
         if (applyScale) {
@@ -94,5 +91,5 @@
      * @returns {PartMesh} info about part mesh
      */
-    getNewBoxMesh(part) {
+    getNewBoxMesh(part, color) {
         let geometry = new THREE.BoxGeometry(2, 2, 2);
         geometry.scale(
@@ -101,8 +98,5 @@
             part.get_scale().get_z());
 
-        let material = this.transformations.getNewMaterial(
-            part.get_vcolor().get_x(), 
-            part.get_vcolor().get_y(), 
-            part.get_vcolor().get_z());
+        let material = this.transformations.getNewMaterial(color);
         let mesh = new THREE.Mesh(geometry, material);
         mesh.position.set(
@@ -133,10 +127,7 @@
      * @returns {PartMesh} info about part mesh
      */
-    getNewCylinderMesh(part) {
+    getNewCylinderMesh(part, color) {
         let geometry = new THREE.CylinderGeometry(1, 1, 2, 32);
-        let material = this.transformations.getNewMaterial(
-            part.get_vcolor().get_x(), 
-            part.get_vcolor().get_y(), 
-            part.get_vcolor().get_z());
+        let material = this.transformations.getNewMaterial(color);
 
         geometry.scale(
@@ -181,5 +172,5 @@
      * @returns {PartMesh} info about part mesh
      */
-    create(part) {
+    create(part, color) {
 
         let shape = part.get_shape();
@@ -187,15 +178,17 @@
             return this.getNewSphereMesh(
                 part, 
+                color,
                 this.config.ellipsoidShape.radius, 
                 this.config.ellipsoidShape.segments, true);
         }
         else if (this.partShapes['SHAPE_CUBOID'].value == shape) {
-            return this.getNewBoxMesh(part);
+            return this.getNewBoxMesh(part, color);
         }
         else if (this.partShapes['SHAPE_CYLINDER'].value == shape) {
-            return this.getNewCylinderMesh(part);
+            return this.getNewCylinderMesh(part, color);
         }
         return this.getNewSphereMesh(
             part, 
+            color,
             this.config.defaultShape.radius, 
             this.config.defaultShape.segments, 
Index: /js/human_3d_alignment/src/visualization/sviewer.js
===================================================================
--- /js/human_3d_alignment/src/visualization/sviewer.js	(revision 910)
+++ /js/human_3d_alignment/src/visualization/sviewer.js	(revision 911)
@@ -3,10 +3,8 @@
 
 import * as THREE from 'three';
-import TrackballControls from 'three-trackballcontrols';
-import PartMeshFactory from './partmeshfactory';
-import JointMeshFactory from './jointmeshfactory';
+import Framstick from './framstick';
 import Scene from './scene';
 import Camera from './camera';
-import { geometry } from './transformations';
+const TransformControls = require('three-transform-controls')(THREE);
 
 /** Camera class configuration for Viewer */
@@ -66,14 +64,14 @@
      */
     constructor(width, height, canvasdom) {
+        this.container = document.getElementById("simcontainer");
+
+        this.meshes = [];
         this.parts = [];
-        this.joints = [];
-        this.meshes = [];
-        this.parts2 = [];
-        this.joints2 = [];
-        this.meshes2 = [];
-        this.creature1 = new THREE.Group();
-        this.creature2 = new THREE.Group();
-        this.partfactory = new PartMeshFactory(geometry.part);
-        this.jointfactory = new JointMeshFactory(geometry.joint);
+        this.lines = [];
+        this.framstick1 = null;
+        this.framstick2 = null;
+        this.selected1 = [];
+        this.selected2 = [];
+
         this.renderer = new THREE.WebGLRenderer({
             antialias: true,
@@ -85,5 +83,15 @@
         this.scene = new Scene();
         this.camera = new Camera(cameraconfig, this.renderer.domElement, false);
-        //console.log(this.camera);
+        this.control = new TransformControls(this.camera.getPerspectiveCamera(), this.renderer.domElement);
+        this.control.addEventListener( 'change', (e) => {
+            this.addLines(this.selected1, this.selected2);
+            this.addText();
+        });
+        this.control.addEventListener( 'dragging-changed', function(e) {
+            this.camera.getCameraControl().enable = ! e.value;
+        });
+        this.scene.add(this.control);
+        this.control.setMode( "translate" );
+
         let ambientLight = new THREE.AmbientLight(lightconfig.ambient.color);
         this.scene.add(ambientLight);
@@ -100,45 +108,126 @@
         bottomDirectionalLight.position.set(0, 0, lightconfig.directional.bottom.positionZ);
         this.scene.add(bottomDirectionalLight);
+
         this.renderer.setClearColor('gray');
-        this.rezoom = true;
+        this.rezoom = false;
+        this.autorotate = false;
         this.renderScene = this.renderScene.bind(this);
         this.selectedelements = [];
 
         this.mouse = new THREE.Vector2();
-        this.offset = new THREE.Vector3();
-        this.INTERSECTED = null;
         this.SELECTED = null;
-
-        this.plane = new THREE.Mesh( new THREE.PlaneGeometry(500, 500, 8, 8 ), new THREE.MeshBasicMaterial( { color: 0x000000, opacity: 0.25, transparent: true, wireframe: true } ) );
-        this.plane.visible = true;
-        this.scene.add( this.plane ); 
-
-        this.controls = new TrackballControls( this.camera.getPerspectiveCamera() );
-        this.projector = new THREE.Projector();
-        this.controls.target = new THREE.Vector3(0, 0, 0);
-        this.controls.maxDistance = 150;
-        this.controls2 = null;
-    }
-
-    addMesh(meshes, parts, joints, model, creature)
-    {
-        let partsforjoints = [];
-        meshes = [];
-        parts = [];
-        joints = [];
-        for (let i = 0; i < model.getPartCount(); i++) {
-            let mesh = this.partfactory.create(model.getPart(i));
-            partsforjoints.push(mesh.userData);
-            meshes.push(mesh);
-            parts.push(mesh);
-            creature.add(mesh);
-        }
-
-        for (let i = 0; i < model.getJointCount(); i++) {
-            let mesh = this.jointfactory.create(model.getJoint(i), partsforjoints);
-            meshes.push(mesh);
-            joints.push(mesh);
-            creature.add(mesh);
-        }
+        this.CLICKED = false;
+
+
+        this.lineMaterial = new THREE.LineBasicMaterial({
+            color: 0xffff00,
+            transparent: true,
+            opacity: 0.5
+        });
+
+        this.textLabels = [];
+        this.container = document.getElementById("simcontainer");
+    }
+
+    /**
+     * Allow to clear view and add new pair of genotypes
+     * @param {string} genotype1 Genotype of first framstick
+     * @param {string} genotype2 Genotype of second framstick
+     */
+    add2Genotypes(genotype1, genotype2) {
+        this.clearView();
+
+        this.framstick1 = new Framstick(genotype1, this);
+        this.framstick2 = new Framstick(genotype2, this);
+
+        this.meshes = [];
+        this.parts = [];
+
+        for (let i = 0; i < this.framstick1.mesh.children.length; i++) {
+            this.meshes.push(this.framstick1.mesh.children[i]);
+        }
+
+        for (let i = 0; i < this.framstick2.mesh.children.length; i++) {
+            this.meshes.push(this.framstick2.mesh.children[i]);
+        }
+
+        for (let i = 0; i < this.framstick1.parts.length; i++) {
+            this.parts.push(this.framstick1.parts[i]);
+        }
+
+        for (let i = 0; i < this.framstick2.parts.length; i++) {
+            this.parts.push(this.framstick2.parts[i]);
+        }
+
+        this.framstick1.mesh.position.set( 0, -2, 0 );
+        this.framstick2.mesh.position.set( 0, 2, 0 );
+
+        this.framstick1.setPositions();
+        this.framstick2.setPositions();
+
+        this.framstick1.setColor('red');
+        this.framstick2.setColor('blue');
+
+        this.camera.zoomAll(this.meshes);
+        this.addText();
+    }
+
+    /**
+     * Draw lines between selected parts of both framsticks
+     * @param {Array} selected1 array of values that user selected in fitview for first genotype
+     * @param {Array} selected2 array of values that user selected in fitview for second genotype
+     */
+    addLines(selected1, selected2) {
+        for (let i = 0; i < this.lines.length; i++) {
+            this.scene.remove(this.lines[i]);
+        }
+
+        this.lines = [];
+
+        let pairs = (selected1.length + selected2.length) / 2;
+
+        for (let i = 0; i < pairs; i++) {
+            if (selected1[i] != ' ' && selected2[i] != ' ') {
+                let index1 = parseInt(selected1[i]) - 1;
+                let index2 = selected2[i].charCodeAt(0) - 65;
+
+                let tempV1 = new THREE.Vector3().copy(this.framstick1.positions[index1]).applyEuler(this.framstick1.mesh.rotation).add(this.framstick1.mesh.position);
+                let tempV2 = new THREE.Vector3().copy(this.framstick2.positions[index2]).applyEuler(this.framstick2.mesh.rotation).add(this.framstick2.mesh.position);
+
+                let geometry = new THREE.Geometry();
+                geometry.vertices.push( tempV1 );
+                geometry.vertices.push( tempV2 );
+
+                let line = new THREE.Line( geometry, this.lineMaterial );
+                this.lines.push(line);
+            }
+        }
+
+        for (let i = 0; i < this.lines.length; i++) {
+            this.scene.add(this.lines[i]);
+        }
+    }
+
+    addText() {
+
+        while (this.container.children.length > 3){
+            this.container.removeChild(this.container.lastChild)
+        }
+
+        this.textLabels = [];
+
+        if (this.framstick1 != null && this.framstick2 != null) {
+            this.framstick1.addText(1);
+            this.framstick2.addText(2);
+        }
+
+    }
+
+    /**
+     * Allow to change mode of TransformControls
+     * @param {string} mode Selected mode of transformcontrols
+     */
+    setMode(mode) {
+        this.control.setMode(mode);
     }
 
@@ -150,74 +239,55 @@
      */
     handleMouseDown(position) {
-      this.raycaster.setFromCamera( position, this.camera.getPerspectiveCamera() );  
-      let intersectsC1 = this.raycaster.intersectObjects( this.creature1.children );
-            let intersectsC2 = this.raycaster.intersectObjects( this.creature2.children );
-
-				if ( intersectsC1.length > 0 || intersectsC2.length > 0 ) {
-                    
-					this.controls.enabled = false;
-                    let obj = intersectsC1.length > 0 ? this.creature1 : this.creature2;
-					this.SELECTED = obj;
-					let intersects = this.raycaster.intersectObject( this.plane );
-					this.offset.copy( intersects[ 0 ].point ).sub( this.plane.position );
-				}
+        this.raycaster.setFromCamera( position, this.camera.getPerspectiveCamera() );  
+        let intersectsC1 = this.raycaster.intersectObjects( this.framstick1.mesh.children );
+        let intersectsC2 = this.raycaster.intersectObjects( this.framstick2.mesh.children );
+
+        if ( intersectsC1.length > 0 || intersectsC2.length > 0 ) {
+            
+            let obj = intersectsC1.length > 0 ? this.framstick1 : this.framstick2;
+
+            if ( this.SELECTED ) {
+                if (this.SELECTED == obj) {
+                    if (this.SELECTED == this.framstick1) {
+                        obj.setColor('red');
+                    } else {
+                        obj.setColor('blue');
+                    }
+                    this.control.detach();
+                    this.SELECTED = null;
+                } else {
+                    if (this.SELECTED == this.framstick1) {
+                        this.SELECTED.setColor('red');
+                    } else {
+                        this.SELECTED.setColor('blue');
+                    }
+                    this.control.detach();
+                    obj.setColor('white');   
+                    this.SELECTED = obj;      
+                    this.control.attach( obj.mesh );     
+                }
+            } else {
+                this.control.detach();
+                obj.setColor('white');
+                this.SELECTED = obj;  
+                this.control.attach( obj.mesh );
+            }
+        } else {
+            if (this.SELECTED) {
+                if (this.SELECTED == this.framstick1) {
+                    this.SELECTED.setColor('red');
+                } else {
+                    this.SELECTED.setColor('blue');
+                }
+                this.control.detach();
+                this.SELECTED = null;
+            }
+        }
     }
 
     handleMouseUp() {
-        this.controls.enabled = true;
-        this.SELECTED = null;
-
-        if (this.INTERSECTED)
-        {
-            this.plane.position.copy(this.INTERSECTED.position);
-            this.SELECTED = null;
-        }
     }
 
     handleMouseMove(position) {
-        this.raycaster.setFromCamera( position, this.camera.getPerspectiveCamera() );
-        if ( this.SELECTED ) {
-            let intersects = this.raycaster.intersectObject( this.plane );
-            if (intersects[ 0 ])
-                {this.SELECTED.position.copy( intersects[ 0 ].point.sub( this.offset ) );}
-            return;
-        }
-
-            let intersectsC1 = this.raycaster.intersectObjects(this.creature1.children);
-            let intersectsC2 = this.raycaster.intersectObjects(this.creature2.children);
-            if (intersectsC1.length > 0 || intersectsC2.length > 0)
-            {
-                let obj = intersectsC1.length > 0 ? this.creature1 : this.creature2;
-                this.INTERSECTED = obj;
-                this.plane.position.copy( obj.position );
-                this.plane.lookAt( this.camera.getPerspectiveCamera().position );
-            }
-            else
-            {
-                this.INTERSECTED = null;
-            }
-        
-    }
-
-    /**
-     * Method uses ready Model to create and add meshes to the scene. If model is 
-     * undefined, an empty scene will be rendered.
-     * @param {Module.Model} model input model 1
-     * @param {Module.Model} model input model 2
-     */
-    loadMeshesFromModel(model, model2) {
-        this.clearView();
-        if (typeof model !== 'undefined') {
-
-            this.addMesh(this.meshes, this.parts, this.joints, model, this.creature1);
-            this.addMesh(this.meshes2, this.parts2, this.joints2, model2, this.creature2);
-            this.creature2.position.set( 0, 0, 0 );
-            this.creature2.position.set( 0, -1, 0 );
-            this.scene.add(this.creature1);
-            this.scene.add(this.creature2);
-            if (this.rezoom) {
-                this.camera.zoomAll(this.meshes);
-            }
-        }
     }
 
@@ -251,5 +321,4 @@
         this.camera.getPerspectiveCamera().updateProjectionMatrix();
         this.renderer.setSize(width, height);
-        //console.log(this.renderer.getSize());
         this.renderer.setPixelRatio(window.devicePixelRatio || 1);
     }
@@ -262,5 +331,7 @@
     setRezoom(rezoom) {
         this.rezoom = rezoom;
-        this.camera.zoomAll(this.meshes);
+        if (this.rezoom) {
+            this.camera.zoomAll(this.meshes);
+        }
     }
 
@@ -277,5 +348,14 @@
      */
     clearView() {
-        this.scene.clear();
+        if (this.framstick1 != null && this.framstick2 != null) {
+            this.scene.remove(this.framstick1.mesh);
+            this.scene.remove(this.framstick2.mesh);
+        }
+        this.control.detach();
+        while (this.container.children.length > 3) {
+            this.container.removeChild(this.container.lastChild)
+        }
+
+        this.SELECTED = null;
     }
 
Index: /js/human_3d_alignment/src/visualization/transformations.js
===================================================================
--- /js/human_3d_alignment/src/visualization/transformations.js	(revision 910)
+++ /js/human_3d_alignment/src/visualization/transformations.js	(revision 911)
@@ -45,13 +45,9 @@
         cylinderShape: {
             radius: 0.1,
-            radiusSegments: 10,
-            isTransparent: false,
-            opacity: 1
+            radiusSegments: 10
         },
         linkShape: {
             radius: 0.04,
-            radiusSegments: 10,
-            isTransparent: true,
-            opacity: 0.2
+            radiusSegments: 10
         }
     }
@@ -186,10 +182,12 @@
      * @returns {MeshPhongMaterial} new material for Mesh
      */
-    getNewMaterial(r, g, b) {
-        let color = new THREE.Color(
-            this.calcColorComponent(r), 
-            this.calcColorComponent(g), 
-            this.calcColorComponent(b));
-        return new THREE.MeshPhongMaterial({ color: color });
+    getNewMaterial(color) {
+        return new THREE.MeshPhongMaterial({
+            color: color,
+            transparent: true,
+            opacity: 0.6,
+            reflectivity: 0.2,
+            shininess: 600
+        });
     }
 
Index: /js/human_3d_alignment/src/widgets/endviewer.jsx
===================================================================
--- /js/human_3d_alignment/src/widgets/endviewer.jsx	(revision 911)
+++ /js/human_3d_alignment/src/widgets/endviewer.jsx	(revision 911)
@@ -0,0 +1,66 @@
+/*global Module*/
+"use strict";
+import React from 'react';
+
+const styles = {
+    content: {
+        position: 'absolute',
+        height: '100%',
+        width: '100%',
+        top: '50%',
+        textAlign: 'center',
+        fontSize: '30px'
+    },
+    text: {
+        fontFamily: "'Fira Mono', Monaco, 'Andale Mono', 'Lucida Console', 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace"
+    }
+}
+
+/**
+ * Component for assesing genotypes matching.
+ */
+class EndViewer extends React.Component {
+    /**
+     * Basic constructor.
+     * @param {any} props properties of Component
+     */
+    constructor(props) {
+        super(props);
+        this.props = props;
+        
+        this.download = this.download.bind(this);
+    }
+
+    download(type) {
+        let file = new Blob([this.props.result], {type: type});
+        let filename = this.props.userId + '.csv';
+        if (window.navigator.msSaveOrOpenBlob) // IE10+
+            window.navigator.msSaveOrOpenBlob(file, filename);
+        else { // Others
+            let a = document.createElement("a"),
+                    url = URL.createObjectURL(file);
+            a.href = url;
+            a.download = filename;
+            document.body.appendChild(a);
+            a.click();
+            setTimeout(function() {
+                document.body.removeChild(a);
+                window.URL.revokeObjectURL(url);  
+            }, 1500); 
+        }
+    }    
+     
+    render() {
+
+        return (
+            <div id = 'end' style={styles.content}>
+                <div style={styles.text}>Dziękujemy za udział w badaniu!</div>
+                <div>
+                    <button styles={styles.text} onClick={() => {this.download('text/plain')}}>Pobierz wyniki</button>
+                </div>
+            </div>
+        );
+    }
+}                          
+
+export default EndViewer;
Index: /js/human_3d_alignment/src/widgets/fitviewer.jsx
===================================================================
--- /js/human_3d_alignment/src/widgets/fitviewer.jsx	(revision 911)
+++ /js/human_3d_alignment/src/widgets/fitviewer.jsx	(revision 911)
@@ -0,0 +1,482 @@
+/*global Module*/
+"use strict";
+
+import React from 'react';
+
+
+const styles = {
+    header: {
+        textAlign: 'center',
+        letterSpacing: '5px',
+        fontFamily: "'Fira Mono', Monaco, 'Andale Mono', 'Lucida Console', 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace", 
+        webkitUserSelect : 'none', 
+        mozUserSelect: 'none', 
+        msUserSelect: 'none', 
+        userSelect: 'none'
+    },
+    creatureText: {
+        margin: '0',
+        position: 'absolute',
+        top: '50%',
+        left: '50%',
+        marginRight: '-50%',
+        transform: 'translate(-50%, -50%)',
+        webkitUserSelect : 'none',
+        mozUserSelect: 'none',
+        msUserSelect: 'none',
+        userSelect: 'none',
+        fontFamily: "'Fira Mono', Monaco, 'Andale Mono', 'Lucida Console', 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace"
+    },
+    creatureBench: { 
+        position: 'relative', 
+        border: '2px solid black', 
+        color: 'white', 
+        backgroundColor: 'gray',
+        width: '50px', 
+        height: '50px', 
+        fontSize: '30px',
+        pointerEvent: 'none',
+        fontFamily: "'Fira Mono', Monaco, 'Andale Mono', 'Lucida Console', 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace",
+    },
+    creatureBench1: { 
+        position: 'relative', 
+        border: '2px solid black', 
+        color: 'white', 
+        backgroundColor: 'red',
+        width: '50px', 
+        height: '50px', 
+        fontSize: '30px',
+        pointerEvents: 'none',
+        fontFamily: "'Fira Mono', Monaco, 'Andale Mono', 'Lucida Console', 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace",
+    },
+    creatureBench2: { 
+        position: 'relative', 
+        border: '2px solid black', 
+        color: 'white', 
+        backgroundColor: 'blue',
+        width: '50px', 
+        height: '50px', 
+        fontSize: '30px',
+        pointerEvents: 'none',
+        fontFamily: "'Fira Mono', Monaco, 'Andale Mono', 'Lucida Console', 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace",
+    },
+    middleField:{
+        position: 'relative', 
+        color: 'gray', 
+        backgroundColor: 'gray',
+        width: '54px',
+        height: '54px',
+        webkitUserSelect: 'none',
+        mozUserSelect: 'none',
+        msUserSelect: 'none',
+        userSelect: 'none'
+    },
+    emptyField: {
+        display: 'table', 
+        width: '100%', 
+        height: '20px'
+    },
+    field: {
+        display: 'flex'
+    },
+    empty: {
+        webkitUserSelect : 'none',
+        mozUserSelect: 'none',
+        msUserSelect: 'none',
+        userSelect: 'none'
+    },
+    cell: {
+        display: 'table-cell'
+    },
+    row: {
+        display: 'table-row',
+    }
+};
+
+/**
+ * Component for assesing genotypes matching.
+ */
+class FitViewer extends React.Component {
+    /**
+     * Basic constructor.
+     * @param {any} props properties of Component
+     */
+    constructor(props) {
+        super(props);
+        this.props = props;
+
+        this.state = {
+            height: 2,
+            choosed: ' ',
+            initialX: 0,
+            initialY: 0
+        }
+        
+        this.createSecondRow = this.createSecondRow.bind(this);
+        this.createThirdRow = this.createThirdRow.bind(this);
+        this.createFourthRow = this.createFourthRow.bind(this);
+        this.select = this.select.bind(this);
+    }
+
+    select(e) {
+        let item = null;
+        let index;
+
+        for (let i = 0; i < this.props.parts1; i++) {
+            let index2 = (i+1).toString();
+            let itemD = document.querySelector('#creature' + index2);
+            let itemP = document.querySelector('#p' + index2);
+            if (e.target === itemD || e.target === itemP) {
+                item = null;
+                index = index2;
+                item = document.querySelector('#creature' + index);
+            }
+        }
+
+        for (let i = 0; i < this.props.parts2; i++) {
+            let index2 = '';
+            if (i + 1 + 64 > 90) {
+                index2 = String.fromCharCode(i + 1 + 70);
+            } else {
+                index2 = String.fromCharCode(i + 1 + 64);
+            }     
+            let itemD = document.querySelector('#creature' + index2);
+            let itemP = document.querySelector('#p' + index2);
+            if (e.target === itemD || e.target === itemP) {
+                item = null;
+                index = index2;
+                item = document.querySelector('#creature' + index);
+            }
+        }
+
+        if (this.state.choosed != ' ') {
+            if (!item) {
+                if (!isNaN(this.state.choosed)) {
+                    for (let i = 0; i < Math.min(this.props.parts1, this.props.parts2); i++) {
+                        let index2 = (i+1).toString();
+                        let itemD =  document.querySelector('#field1-' + index2);
+
+                        
+                        if (e.target === itemD) {
+                            let index3 = this.props.selected1.indexOf(this.state.choosed);
+
+                            if (index3 > -1) {
+                                this.props.handleChangeSelected(1, index3, ' ');
+                            }
+                            this.props.handleChangeSelected(1, i, this.state.choosed);
+                        }
+                    }
+                } else {
+                    for (let i = 0; i < Math.min(this.props.parts1, this.props.parts2); i++) {
+                        let index2 = (i+1).toString();
+                        let itemD =  document.querySelector('#field2-' + index2);
+
+                        
+                        if (e.target === itemD) {
+
+                            let temp = this.state.choosed;
+                            if (this.state.choosed.charCodeAt(0) > 90) {
+                                temp = String.fromCharCode(temp.charCodeAt(0) - 6);
+                            }
+
+                            let index3 = this.props.selected2.indexOf(temp);
+
+                            if (index3 > -1) {
+                                this.props.handleChangeSelected(2, index3, ' ');
+                            }
+                            this.props.handleChangeSelected(2, i, this.state.choosed);
+                        }
+                    }
+                }
+                this.setState({ choosed: ' ' }, function() {
+                    console.log(this.state.choosed);
+                });
+
+            } else {
+                let item2 = document.querySelector('#creature' + this.state.choosed);
+                if ((item.parentNode.parentNode.parentNode.className == 'rowField' || item.parentNode.parentNode.parentNode.className == 'rowBench') &&
+                    (item2.parentNode.parentNode.parentNode.className == 'rowField' || item2.parentNode.parentNode.parentNode.className == 'rowBench')) {
+                    let nr = 0;
+                    let index1 = 0;
+                    let index2 = 0;
+                    let temp = this.state.choosed;
+                    if (this.state.choosed.charCodeAt(0) > 90) {
+                        temp = String.fromCharCode(temp.charCodeAt(0) - 6);
+                    }
+                    if (!isNaN(this.state.choosed)) {
+                        nr = 1;
+                        index1 = this.props.selected1.indexOf(this.state.choosed);
+                        index2 = this.props.selected1.indexOf(index);
+                    } else {
+                        nr = 2;
+                        let temp1 = this.state.choosed;
+                        let temp2 = index;
+                        if (this.state.choosed.charCodeAt(0) > 90) {
+                            temp1 = String.fromCharCode(temp1.charCodeAt(0) - 6);
+                        }
+                        if (index.charCodeAt(0) > 90) {
+                            temp2 = String.fromCharCode(temp2.charCodeAt(0) - 6);
+                        }
+
+                        index1 = this.props.selected2.indexOf(temp);
+                        index2 = this.props.selected2.indexOf(temp2);
+                    }
+                    this.props.handleChangeSelected(nr, index1, index);
+                    this.props.handleChangeSelected(nr, index2, this.state.choosed);
+
+                    this.setState({ choosed: ' ' }, function() {
+                        console.log(this.state.choosed);
+                    });
+                } else {
+                    if (item.parentNode.parentNode.parentNode.parentNode === item2.parentNode.parentNode.parentNode || 
+                        item.parentNode.parentNode.parentNode === item2.parentNode.parentNode.parentNode.parentNode) {
+                        let nr = 0;
+                        let index1 = 0;
+                        let index2 = 0;
+                        if (!isNaN(this.state.choosed)) {
+                            nr = 1;
+                            index1 = this.props.selected1.indexOf(this.state.choosed);
+                            index2 = this.props.selected1.indexOf(index);
+                        } else {
+                            nr = 2;
+                            let temp = this.state.choosed;
+                            let temp2 = index;
+                            if (this.state.choosed.charCodeAt(0) > 90) {
+                                temp = String.fromCharCode(temp.charCodeAt(0) - 6);
+                            }
+                            if (index.charCodeAt(0) > 90) {
+                                temp2 = String.fromCharCode(temp2.charCodeAt(0) - 6);
+                            }
+                            index1 = this.props.selected2.indexOf(temp);
+                            index2 = this.props.selected2.indexOf(temp2);
+                        }
+                        this.props.handleChangeSelected(nr, index1, index);
+                        this.props.handleChangeSelected(nr, index2, this.state.choosed);
+                        this.setState({ choosed: ' ' }, function() {
+                            console.log(this.state.choosed);
+                        });
+                    } else {
+                        this.setState({ choosed: index }, function() {
+                            console.log(this.state.choosed);
+                        });
+                    }
+                }
+            }
+        } else {
+            if (item != null) {
+                this.setState({ choosed: index }, function() {
+                    console.log(this.state.choosed);
+                });
+            }
+        }
+    }
+
+    createSecondRow() {
+        let row = []
+        let len = Math.min(this.props.parts1, this.props.parts2);
+        for (let i = 0; i < len; i++) {        
+            if (this.props.selected1[i] != ' ') {
+                if (this.props.selected1[i] && this.state.choosed == this.props.selected1[i]) {   
+                    row.push(
+                        <div id={'cell'+(i+1).toString()} className='cell' style={styles.cell}>
+                            <div id={'field1-'+(i+1).toString()} 
+                                className='field'
+                                style={styles.middleField}>
+                                <div id={'creature' + this.props.selected1[i]} 
+                                    className='creature1' 
+                                    onMouseDown={this.select}
+                                    style={styles.creatureBench1}>
+                                    <p id={'p' + this.props.selected1[i]} style={styles.creatureText}>
+                                        {this.props.selected1[i]}
+                                    </p>
+                                </div>
+                            </div>
+                        </div>
+                    );
+                } else {
+                    row.push(
+                        <div id={'cell'+(i+1).toString()} className='cell' style={styles.cell}>
+                            <div id={'field1-'+(i+1).toString()} 
+                                className='field'
+                                style={styles.middleField}>
+                                <div id={'creature' + this.props.selected1[i]} 
+                                    className='creature1' 
+                                    onMouseDown={this.select}
+                                    style={styles.creatureBench}>
+                                    <p id={'p' + this.props.selected1[i]} style={styles.creatureText}>
+                                        {this.props.selected1[i]}
+                                    </p>
+                                </div>
+                            </div>
+                        </div>
+                    );
+                }
+            } else {
+                row.push(
+                    <div id='cellnull' className='cell' style={styles.cell}>
+                        <div id={'field1-'+(i+1).toString()} 
+                            onMouseDown = {this.select}
+                            className='field'
+                            style={styles.middleField}>
+                            &nbsp;
+                        </div>
+                    </div>
+                );
+            }    
+        }
+        if (row.length == 0) {
+            row.push(
+                <div style={styles.empty}>&nbsp;</div>
+            );
+        }
+        return row;
+    }
+
+    createThirdRow() {
+        let row = [];
+        let len = Math.min(this.props.parts1, this.props.parts2);
+        for (let i = 0; i < len; i++) {  
+            if (this.props.selected2[i] && this.props.selected2[i] != ' ') { 
+                let value = this.props.selected2[i];
+                let char = value.charCodeAt(0);
+                if (char > 90) {
+                    char += 6;
+                    value = String.fromCharCode(char);
+                }
+                if (this.state.choosed == value) {    
+                    row.push(
+                        <div id={'cell'+(i+1).toString()} className='cell' style={styles.cell}>
+                            <div id={'field2-'+(i+1).toString()}
+                                className='field'
+                                style={styles.middleField}>
+                                <div id={'creature' + value}
+                                    className='creature2' 
+                                    onMouseDown={this.select}
+                                    style={styles.creatureBench2}>
+                                    <p id={'p' + value} style={styles.creatureText}>
+                                        {value}
+                                    </p>
+                                </div>
+                            </div>
+                        </div>
+                    );
+                } else {
+                    row.push(
+                        <div id={'cell'+(i+1).toString()} className='cell' style={styles.cell}>
+                            <div id={'field2-'+(i+1).toString()}
+                                className='field'
+                                style={styles.middleField}>
+                                <div id={'creature' + value} 
+                                    className='creature2' 
+                                    onMouseDown={this.select}
+                                    style={styles.creatureBench}>
+                                    <p id={'p' + value} style={styles.creatureText}>
+                                        {value}
+                                    </p>
+                                </div>
+                            </div>
+                        </div>
+                    );
+                }
+            } else {
+                row.push(
+                    <div id='cellnull' className='cell' style={styles.cell}>
+                        <div id={'field2-'+(i+1).toString()} 
+                            onMouseDown = {this.select}
+                            className='field'
+                            style={styles.middleField}>
+                        </div>
+                    </div>
+                );
+            }
+        }
+        if (row.length == 0) {
+            row.push(
+                <div style={styles.empty}>&nbsp;</div>
+            );
+        }
+        return row;
+    }
+
+    createFourthRow() {
+        let row = [];
+        for (let i = 0; i < this.props.parts2; i++) {
+            let idtext = '';
+            let idtext1 = String.fromCharCode(i + 1 + 64);
+            if (i + 1 + 64 >= 91) {
+                idtext = String.fromCharCode(i  + 1 + 70);
+            } else {
+                idtext = idtext1;
+            }
+
+            if (this.props.selected2.indexOf(idtext1) < 0) {
+                if (this.state.choosed == idtext) {
+                    row.push(
+                        <div id={'cell'+idtext} className='cell' style={styles.cell}>
+                            <div id={'creature' + idtext} 
+                                className='creature2' 
+                                onMouseDown={this.select}
+                                style={styles.creatureBench2}>
+                                <p id={'p' + idtext} style={styles.creatureText}>
+                                    {idtext}
+                                </p>
+                            </div>
+                        </div>
+                    );
+                } else {
+                    row.push(
+                        <div id={'cell'+idtext} className='cell' style={styles.cell}>
+                            <div id={'creature' + idtext}
+                                className='creature2' 
+                                onMouseDown={this.select}
+                                style={styles.creatureBench}>
+                                <p id={'p' + idtext} style={styles.creatureText}>
+                                    {idtext}
+                                </p>
+                            </div>
+                        </div>
+                    );
+                }
+            }
+        }
+        if (row.length == 0) {
+            row.push(
+                <div id='cellnull' className='cell' style={styles.cell}>
+                    <div style={styles.empty}>&nbsp;</div>
+                </div>
+            );
+        }
+        return row;
+    }
+     
+    render() {     
+        let h = ((this.props.fitHeight * 150 - 16) + 8 * (this.props.fitHeight - 1)).toString() + 'px';
+        let w = ((this.props.fitWidth * 150 - 16) + 8 * (this.props.fitWidth - 1)).toString() + 'px';
+
+        return (
+            <div id='fit' className='fit' onMouseDown={ev => {if (ev) ev.stopPropagation();}} onTouchStart={ev => {if (ev) ev.stopPropagation();}} style={{position: 'relative', width: w, height: h, whiteSpace: 'no-wrap', overflow: 'auto'}}>
+                <h2 className='title' style={styles.header}>
+                    DOPASOWANIE
+                </h2>
+
+                <div key='rowsFields' onMouseDown = {this.select} className="rows" style={{display: 'table', borderCollapse: 'separate', borderSpacing: '15px'}}>
+                    <div id='rowCreature1' onMouseDown = {this.select}>
+                        <div id='rowField1' className='rowField' onMouseDown = {this.select} style={styles.row}>
+                            {this.createSecondRow()}
+                        </div>
+                    </div>
+                    <div id='rowCreature2'>
+                        <div id='rowField2' className='rowField' onMouseDown = {this.select} style={styles.row}>
+                            {this.createThirdRow()}
+                        </div>
+                        <div id='rowBench2' className='rowBench' onMouseDown = {this.select} style={styles.row}>
+                            {this.createFourthRow()}
+                        </div>
+                    </div>
+                </div>
+            </div>
+        );
+    }
+}
+
+export default FitViewer;
Index: /js/human_3d_alignment/src/widgets/parmviewer.jsx
===================================================================
--- /js/human_3d_alignment/src/widgets/parmviewer.jsx	(revision 911)
+++ /js/human_3d_alignment/src/widgets/parmviewer.jsx	(revision 911)
@@ -0,0 +1,105 @@
+/*global Module*/
+"use strict";
+
+import React from 'react';
+import Select from 'react-select';
+
+const genders = [
+    { value: 'empty', label: ' ' },
+    { value: 'man', label: 'Mężczyzna' },
+    { value: 'woman', label: 'Kobieta' }
+];
+
+const currentYear = new Date().getFullYear();
+
+const years = [];
+years.push({value: 'empty', label: ' '})
+    
+for (let i = 0; i < 120; i += 1) {
+    years.push({ value: currentYear - i, label: currentYear - i });
+}
+
+const styles = {
+    header: {
+        display: 'table',
+        width: '100%',
+        height: '20px'
+    },
+    row: {
+        display: 'table',
+        width: '100%',
+        tableLayout: 'fixed'
+    },
+    desc: {
+        display: 'table-cell',
+        textAlign: 'right',
+        fontFamily: "'Fira Mono', Monaco, 'Andale Mono', 'Lucida Console', 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace", 
+        webkitUserSelect : 'none', 
+        mozUserSelect: 'none', 
+        msUserSelect: 'none', 
+        userSelect: 'none'
+    },
+    ind: {
+        display: 'table-cell',
+        width: '20px',
+        webkitUserSelect : 'none', 
+        mozUserSelect: 'none', 
+        msUserSelect: 'none', 
+        userSelect: 'none'
+    },
+    select: {
+        fontFamily: "'Fira Mono', Monaco, 'Andale Mono', 'Lucida Console', 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace"
+    }
+}
+
+/**
+ * Component for adding user parameters
+ */
+class ParmViewer extends React.Component {
+    /**
+     * Basic constructor.
+     * @param {any} props properties of Component
+     */
+    constructor(props) {
+        super(props);
+        this.props = props;
+        this.state = {};
+    }
+     
+    render() {
+        
+        return (
+            <div>
+                <div style={styles.header}/>
+                <div className='age' style={styles.row}>
+                    <span htmlFor="age" style={styles.desc}>Wiek</span>
+                    <Select 
+                        options={years}
+                        onChange={this.props.handleChangeYear}
+                        placeholder={'Wybierz rok urodzenia'}
+                        display={'table-cell'}
+                        height={'20px'} 
+                        styles={styles.select}
+                        noValidate
+                    />
+                    <div style={styles.ind}/>
+                </div>
+                <div className='gender' style={styles.row}>
+                    <span htmlFor="gender" style={styles.desc}>Płeć</span>
+                    <Select
+                        options={genders}
+                        onChange={this.props.handleChangeGender}
+                        placeholder='Wybierz płeć'
+                        display={'table-cell'}
+                        height={'20px'}
+                        styles={styles.select}
+                        noValidate
+                    />
+                    <div style={styles.ind}/>
+                </div>
+            </div>
+        );
+    }
+}                   
+
+export default ParmViewer;
Index: /js/human_3d_alignment/src/widgets/similviewer.jsx
===================================================================
--- /js/human_3d_alignment/src/widgets/similviewer.jsx	(revision 910)
+++ /js/human_3d_alignment/src/widgets/similviewer.jsx	(revision 911)
@@ -3,9 +3,7 @@
 import React from 'react';
 import ReactDOM from 'react-dom';
+import * as THREE from 'three';
 import Sviewer from '../visualization/sviewer';
 import { Md3dRotation, MdYoutubeSearchedFor } from 'react-icons/lib/md';
-import GenotypeParser from '../utils/genotypeparser';
-import _ from 'lodash';
-import * as THREE from 'three';
 
 /**
@@ -24,5 +22,7 @@
             rezoom: true,
             valid: true,
-            clicked: false
+            clicked: false,
+            controlMode: 'translate',
+            round: 0
         };
         this.start = this.start.bind(this);
@@ -38,13 +38,7 @@
         let temp2 = ReactDOM.findDOMNode(this.mount).parentNode;
         this.viewer = new Sviewer(temp2.clientWidth, temp2.clientHeight, temp);
-        if (this.model) {
-            //Module.destroy(this.model);
-        }
-        this.model = GenotypeParser.getModelFromGenotype("X(X,X)");
-        this.model2 = GenotypeParser.getModelFromGenotype("XX");
-        this.viewer.loadMeshesFromModel(this.model, this.model2);
         this.viewer.setAutoRotate(this.state.autorotate);
         this.viewer.setRezoom(this.state.rezoom);
-        //this.elementspicker = new ElementsPicker(this.viewer.scene, this.viewer.camera.getPerspectiveCamera());
+
         this.renderScene = this.viewer.renderScene.bind(this.viewer);
         this.lastw = temp2.clientWidth;
@@ -94,4 +88,35 @@
             this.viewer.renderer, 
             this.viewer.camera.getPerspectiveCamera());
+            
+        if (!this.props.blockView) {
+
+            if (this.props.round != this.state.round) {
+                this.setState({ round: this.props.round }, function() {
+                    console.log(`Round in sim: `, this.state.round);
+                });
+                this.viewer.add2Genotypes(this.props.genotype1, this.props.genotype2);
+                this.viewer.addLines(this.props.selected1, this.props.selected2);
+            }
+            if (this.props.controlMode != this.state.controlMode) {
+                this.setState({ controlMode: this.props.controlMode }, function() {
+                    console.log('Control mode: ', this.state.controlMode);
+                    this.viewer.setMode(this.state.controlMode);
+                })
+            }
+            if (this.viewer.selected1 != this.props.selected1) {
+                this.viewer.selected1 = [];
+                this.viewer.selected1 = this.props.selected1;
+            }
+            if (this.viewer.selected2 != this.props.selected2) {
+                this.viewer.selected2 = [];
+                this.viewer.selected2 = this.props.selected2;
+            }
+            if (this.props.round == this.state.round) {
+                this.viewer.addText();
+                this.viewer.addLines(this.props.selected1, this.props.selected2);
+            } else {
+                this.viewer.clearView();
+            }
+        }
     }
 
@@ -107,6 +132,7 @@
      */
     switchRezoom() {
-        this.setState({rezoom: !this.state.rezoom});
-        this.viewer.setRezoom(!this.state.rezoom);
+        this.setState({rezoom: !this.state.rezoom}, function() {
+            this.viewer.setRezoom(this.state.rezoom);
+        });
     }
 
@@ -115,6 +141,11 @@
      */
     switchAutorotate() {
-        this.setState({autorotate: !this.state.autorotate});
-        this.viewer.setAutoRotate(!this.state.autorotate);
+        if (this.state.rezoom) {
+            this.switchRezoom();
+        }
+        this.setState({autorotate: !this.state.autorotate}, function() {
+            console.log(this.state.autorotate);
+            this.viewer.setAutoRotate(this.state.autorotate);
+        });
     }
 
@@ -127,5 +158,4 @@
         mousePosition.x = ((evt.clientX - bound.left) / bound.width) * 2 - 1;
         mousePosition.y = -((evt.clientY - bound.top) / bound.height) * 2 + 1;
-        //let vector = new THREE.Vector3(mousePosition.x, mousePosition.y, 0.5);
         let vector = new THREE.Vector2(mousePosition.x, mousePosition.y);
         return vector;
@@ -137,4 +167,12 @@
      */
     handleMouseDown(evt) {
+        if (this.state.rezoom) {
+            this.switchRezoom();
+        }
+
+        if (this.state.autorotate) {
+            this.switchAutorotate();
+        }
+
         evt.preventDefault();
         let mousePosition = this.getMousePosition(evt);
@@ -147,4 +185,19 @@
      */
     handleMouseUp(evt) {
+
+        let position1 = [];
+        let position2 = [];
+        let rotation1 = [];
+        let rotation2 = [];
+        this.viewer.framstick1.mesh.position.toArray(position1);
+        this.viewer.framstick2.mesh.position.toArray(position2);
+        this.viewer.framstick1.mesh.rotation.toArray(rotation1);
+        this.viewer.framstick2.mesh.rotation.toArray(rotation2);
+
+        this.props.handleChangePosition1(position1);
+        this.props.handleChangePosition2(position2);
+        this.props.handleChangeRotation1(rotation1);
+        this.props.handleChangeRotation2(rotation2);
+
         evt.preventDefault();
         let mousePosition = this.getMousePosition(evt);
@@ -160,7 +213,5 @@
         let mousePosition = this.getMousePosition(evt);
         this.viewer.handleMouseMove(mousePosition);
-    }
-
-    
+    }    
      
     render() {
@@ -170,5 +221,5 @@
                     <tr onMouseDown={ev => {if (ev) ev.stopPropagation();}}>
                         <td rowSpan={2} style={{position:'relative', verticalAlign: 'top', alignContent: 'left'}}>
-                            <div style={{height: '100%', width: '100%', position: 'absolute', transform: 'translateZ(0)'}} onMouseDown={ev => {if (ev) ev.stopPropagation();}} onTouchStart={ev => {if (ev) ev.stopPropagation();}}>
+                            <div id="simcontainer" style={{height: '100%', width: '100%', position: 'absolute', transform: 'translateZ(0)'}} onMouseDown={ev => {if (ev) ev.stopPropagation();}} onTouchStart={ev => {if (ev) ev.stopPropagation();}}>
                                 <canvas ref={(mount) => {this.mount = mount;}} onMouseDown={(evt) => this.handleMouseDown(evt)} onMouseUp={(evt) => this.handleMouseUp(evt)} onMouseMove={(evt) => this.handleMouseMove(evt)} style={{position: 'absolute', zIndex: 1}}></canvas>
                                 <Md3dRotation onClick={() => this.switchAutorotate()}  style={{zIndex: 2, position: 'absolute', left: '5%', bottom: 0, width: '20%', height: '20%', maxWidth: '40px', maxHeight: '40px', minWidth: '15px', minHeight: '15px', color: this.state.autorotate ? 'green' : 'black'}} />
Index: /js/human_3d_alignment/src/widgets/sliderviewer.jsx
===================================================================
--- /js/human_3d_alignment/src/widgets/sliderviewer.jsx	(revision 911)
+++ /js/human_3d_alignment/src/widgets/sliderviewer.jsx	(revision 911)
@@ -0,0 +1,160 @@
+/*global Module*/
+"use strict";
+
+import React from 'react';
+import Slider from 'react-input-slider';
+
+const styles = {
+    header: {
+        textAlign: 'center',
+        letterSpacing: '5px',
+        fontFamily: "'Fira Mono', Monaco, 'Andale Mono', 'Lucida Console', 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace", 
+        webkitUserSelect : 'none', 
+        mozUserSelect: 'none', 
+        msUserSelect: 'none', 
+        userSelect: 'none'
+    },
+    interval: {
+        display: 'table',
+        width: '100%',
+        height: '20px'
+    },
+    small_interval: {
+        display: 'table',
+        width: '100%',
+        height: '5px'
+    },
+    slider_position: {
+        textAlign: 'center',
+        width: '100%'
+    },
+    nextButton_position: {
+        display: 'table',
+        width: '100%',
+        textAlign: 'center'
+    },
+    finishButton_position: {
+        display: 'table',
+        width: '90%',
+        textAlign: 'right'
+    },
+    slider: {
+        width: '80%'
+    },
+    nextButton: {
+        width: '250px',
+        height: '50px',
+        fontSize: '28px'
+    },
+    finishButton: {
+        width: '200px',
+        height: '40px',
+        backgroundColor: 'red',
+        color: 'white',
+        fontSize: '16px'
+    },
+    percent: {
+        textAlign: 'center', 
+        fontFamily: "'Fira Mono', Monaco, 'Andale Mono', 'Lucida Console', 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace", 
+        webkitUserSelect : 'none', 
+        mozUserSelect: 'none', 
+        msUserSelect: 'none', 
+        userSelect: 'none'
+    }
+}
+
+/**
+ * Component for adding user parameters
+ */
+class SliderViewer extends React.Component {
+    /**
+     * Basic constructor.
+     * @param {any} props properties of Component
+     */
+    constructor(props) {
+        super(props);
+        this.props = props;
+        this.state = { 
+            percent: 50
+        }
+
+        this.handleChangePercent = this.handleChangePercent.bind(this);
+        this.onClickNext = this.onClickNext.bind(this);
+    }
+    
+    /**
+     * Allow to change percent in state of sliderViewer and set it also in props
+     * @param {number} per choosed similarity of framsticks by user in percentage
+     */
+    handleChangePercent(per) {
+		this.setState({ percent: per.x }, function() {
+            console.log(this.state.percent);
+            this.props.handleChangePercent(this.state.percent);
+        });
+    }
+
+    onClickNext() {
+        let index1 = this.props.selected1.indexOf(' ');
+        let index2 = this.props.selected2.indexOf(' ');
+
+        if (index1 < 0 && index2 < 0) {
+            this.props.onClickNext();
+            this.setState({ percent: 50 }, function() {
+                console.log(this.state.percent);
+                this.props.handleChangePercent(this.state.percent);
+            });
+        } else {
+            let min = '';
+            let max = '';
+            if (this.props.parts1 <= this.props.parts2) {
+                min = 'pierwszego';
+                max = 'drugiego';
+            } else {
+                min = 'drugiego';
+                max = 'pierwszego';
+            }
+            alert('Należy dopasować wszystkie wierzchołki z '+min+' modelu z wierzchołkami '+max+' modelu.');
+        }
+        
+    }
+
+    render() {
+        return (
+            <div onMouseDown={ev => {if (ev) ev.stopPropagation();}} onTouchStart={ev => {if (ev) ev.stopPropagation();}}>
+                <h2 className='title' style={styles.header}>
+                    PODOBIEŃSTWO
+                </h2>
+                <div style={styles.interval}/>
+                <div className='slider' style={styles.slider_position}>
+                    <Slider 
+                        min={0}
+                        max={100}
+                        x = {this.state.percent}
+                        percent = {this.state.percent}
+                        style={styles.slider}
+                        onChange={this.handleChangePercent}
+                    />
+                </div> 
+                <div style={styles.small_interval}/>
+                <div className='percent' style={styles.percent}>
+                    {this.state.percent} %
+                </div>
+                <div style={styles.interval}/>
+                <div style={styles.nextButton_position}>
+                    <button type='button' onClick={this.onClickNext} disabled={this.props.isDisable} style={styles.nextButton}>
+                        Następny
+                    </button>
+                </div>
+                <div style={styles.small_interval}/>
+                <div style={styles.finishButton_position}>
+                    <button type='button' onClick={this.props.onClickFinish} style={styles.finishButton}>
+                        Zamknij
+                    </button>
+                </div>
+                
+            </div>
+        );
+    }
+}
+
+export default SliderViewer;
Index: /js/human_3d_alignment/src/widgets/textviewer.jsx
===================================================================
--- /js/human_3d_alignment/src/widgets/textviewer.jsx	(revision 911)
+++ /js/human_3d_alignment/src/widgets/textviewer.jsx	(revision 911)
@@ -0,0 +1,42 @@
+/*global Module*/
+"use strict";
+import React from 'react';
+
+const styles = {
+    content: {
+        position: 'absolute',
+        margin: '10px 10px 10px 10px',
+        height: '100%',
+        verticalAlign: 'sub',
+        textAlign: 'justify', 
+        fontFamily: "'Fira Mono', Monaco, 'Andale Mono', 'Lucida Console', 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace", 
+        webkitUserSelect : 'none', 
+        mozUserSelect: 'none', 
+        msUserSelect: 'none', 
+        userSelect: 'none'
+    }
+}
+
+/**
+ * Component for assessing genotype matching.
+ */
+class TextViewer extends React.Component {
+    /**
+     * Basic constructor.
+     * @param {any} props properties of Component
+     */
+    constructor(props) {
+        super(props);
+        this.props = props;
+    }
+     
+    render() {
+        return (
+            <div style={styles.content}>
+                Dopasuj (nałóż na siebie) oba modele jak najlepiej, wedle własnej opinii, przesuwając je i obracając za pomocą myszy. Potem po prawej stronie okienka przypisz każdy wierzchołek jednego modelu (cyferki) najlepiej odpowiadającemu (wedle własnej opinii) wierzchołkowi drugiego modelu (literki).
+            </div>
+        );
+    }
+}                          
+
+export default TextViewer;
