<?xml version="1.0" encoding="UTF-8" standalone="no"?><addon xmlns="http://icplayer.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="TrueFalse" xsi:schemaLocation="http://icplayer.com ../../tools/addon.xsd">
	<model>
        <property displayName="Is not an activity" name="isNotActivity" nameLabel="TrueFalse_property_is_not_activity" type="boolean"/>
		<property name="Multi" nameLabel="TrueFalse_property_multi" type="boolean"/>
		<property isDefault="true" name="Questions" nameLabel="TrueFalse_property_questions" type="list">
			<property isLocalized="true" name="Question" nameLabel="TrueFalse_property_question" type="html"/>
			<property name="Answer" nameLabel="TrueFalse_property_answer" type="string"/>
		</property>
		<property name="Choices" nameLabel="TrueFalse_property_choices" type="list">
			<property isLocalized="true" name="Choice" nameLabel="TrueFalse_property_choice" type="html"/>
		</property>
		<property name="Lang attribute" nameLabel="TrueFalse_property_lang_attribute" type="string"/>
		<property name="Speech texts" nameLabel="TrueFalse_property_speech_texts" type="staticlist">
			<property displayName="selected" name="Selected" type="staticrow">
                <property name="selected" nameLabel="TrueFalse_property_selected" type="string"/>
            </property>
			<property displayName="deselected" name="Deselected" type="staticrow">
                <property name="deselected" nameLabel="TrueFalse_property_deselected" type="string"/>
            </property>
			<property displayName="correct" name="Correct" type="staticrow">
                <property name="correct" nameLabel="TrueFalse_property_correct" type="string"/>
            </property>
			<property displayName="incorrect" name="Incorrect" type="staticrow">
                <property name="incorrect" nameLabel="TrueFalse_property_incorrect" type="string"/>
            </property>
		</property>
		<property displayName="Is disabled" name="isDisabled" nameLabel="TrueFalse_property_is_disabled" type="boolean"/>
		<property name="printable" nameLabel="printable_name_label" type="{No, Don't randomize, Randomize}"/>
		<property name="isSplitInPrintBlocked" nameLabel="printable_block_split_label" type="boolean"/>
	</model>
<css>.ic_page{
    direction:ltr;
}

#container * {
    direction:inherit;
}

.tf_radio,
.tf_checkbox {
    margin:0 0 1em 0;
    width: 100%;
    height: 100%;
    text-align:left;
    position: absolute;
    left: 0;
    top: 0;
    border-spacing:0 5px;
}

.tf_radio_row,
.tf_checkbox_row {
}

.tf_radio_image,
.tf_checkbox_image {
    cursor:pointer;
    border-collapse: separate;
    width:70px;
    min-width:70px;
    height:26px;
    min-height:26px;
    border-bottom:1px solid #111;
    border-top:1px solid #111;

}

.tf_radio_image.last,
.tf_checkbox_image.last {
    border-radius: 0 10px 10px 0;
    -moz-border-radius: 0 10px 10px 0;
    border-right:1px solid #111;
}

.tf_radio_text,
.tf_checkbox_text {
    margin:5px 0 0 4px;
    width:70px;
    min-width:70px;
    height:26px;
    min-height:26px;
    text-align:center;
}

.tf_radio_question.first,
.tf_checkbox_question.first {
    border:0;
}

.tf_radio_question,
.tf_checkbox_question {
    margin-top:5px;
    border-bottom:1px solid #111;
    border-top:1px solid #111;
    border-left:1px solid #111;
    padding:10px;
    border-radius: 10px 0 0 10px;
    -moz-border-radius: 10px 0 0 10px;
}

.tf_radio_image.up div {
    background-image: url('resources/tf-radio-image-up.png');
}

.tf_radio_image.up.disabled div {
    background-image: url('resources/tf-radio-image-up-disabled.png');
}

.tf_radio_image.down div {
    background-image: url('resources/tf-radio-image-down.png');
}

.tf_radio_image.down.correct div,
.tf_radio_image.down.correct-answer div{
    background-image: url('resources/tf-radio-image-down-correct.png');
}

.tf_radio_image.down.wrong div {
    background-image: url('resources/tf-radio-image-down-wrong.png');
}

.tf_checkbox_image.up div {
    background-image: url('resources/tf-checkbox-image-up.png');
}

.tf_checkbox_image.up.disabled div {
    background-image: url('resources/tf-checkbox-image-up-disabled.png');
}

.tf_checkbox_image.down div {
    background-image: url('resources/tf-checkbox-image-down.png');
}

.tf_checkbox_image.down.correct div,
.tf_checkbox_image.down.correct-answer div{
    background-image: url('resources/tf-checkbox-image-down-correct.png');
}

.tf_checkbox_image.down.wrong div {
    background-image: url('resources/tf-checkbox-image-down-wrong.png');
}

.tf_checkbox_image div,
.tf_radio_image div {
    width: 100%;
    height: 100%;
    background: no-repeat left center;
}

.printable_addon_TrueFalse .radio-container,
.printable_addon_TrueFalse .checkbox-container {
    position: relative;
}

.printable_addon_TrueFalse .radio-container input,
.printable_addon_TrueFalse .checkbox-container input {
    position: absolute;
    visibility: hidden;
}

.printable_addon_TrueFalse .radio-container span {
    display: block;
    width: 0.8em;
    height: 0.8em;
    border: solid 1px;
    border-radius: 50%;
}

.printable_addon_TrueFalse .checkbox-container span {
    display: block;
    width: 0.8em;
    height: 0.8em;
    border: solid 1px;
    border-radius: 2px;
}

.printable_addon_TrueFalse .radio-container span:after,
.printable_addon_TrueFalse .checkbox-container span:after {
    display: none;
    content: "";
}

.printable_addon_TrueFalse .radio-container input:checked ~ span:after,
.printable_addon_TrueFalse .checkbox-container input:checked ~ span:after {
    display: block;
}

.printable_addon_TrueFalse .radio-container span:before {
    position: relative;
    top: 18.5%;
    left: 18.5%;
    width: 12%;
    height: 12%;
    border: solid black;
    border-radius: 50%;
}

.printable_addon_TrueFalse .checkbox-container span:before {
    position: relative;
    width: 0.5em;
    height: 0.5em;
    border: solid black;
}

.correctAnswerMark::after {
    content: "\2714";
}

.incorrectAnswerMark::after {
    content: "\2716";
}
</css><view/><preview/><presenter>function AddonTrueFalse_create() {

    function getTextVoiceObject (text, lang) { return {text: text, lang: lang}; }

    var presenter = function () {};

    presenter.type = "";
    presenter.lastEvent = null;
    presenter.isShowAnswersActive = false;
    presenter.isGradualShowAnswersActive = false;
    presenter.keyboardNavigationActive = false;
    presenter.keyboardNavigationCurrentElement = null;
    presenter.keyboardNavigationElements = [];
    presenter.keyboardNavigationElementsLen = 0;
    presenter.printableState = null;
    presenter.didUserRespond = false;

    var possibleChoices = [];
    var multi = false;
    var isNotActivity = false;
    var questions = [];
    var playerController;
    var printableController;
    var eventBus; // Modules communication
    var tts;
    var selectedSpeechText = "selected";
    var deselectedSpeechText = "deselected";
    var correctSpeechText = "correct";
    var incorrectSpeechText = "incorrect";

    var QUESTION_AND_CHOICES_REQUIRED = "At least 1 question and 2 choices are required.";
    var INDEX_OUT_OF_RANGE = "Index is out of range.";
    var isWCAGOn = false;

    presenter.textParser = null;

    presenter.isSelectionCorrect = function (question, selection) {
        var answers = question.Answer.split(',');

        for (var i = 0; i &lt; answers.length; i++) {
            if (parseInt(answers[i], 10) === selection) {
                return true;
            }
        }

        return false;
    };

    var score = function () {
        var score = { 'score': 0, 'maxScore': 0, 'errorCount': 0 };
        for (var i = 0; i &lt; questions.length + 1; i++) {
            var j = 0;
            var row = presenter.$view.find('#' + i);
            if (i &gt; 0) {
                var values = (questions[i - 1].Answer).split(',');
                score.maxScore += values.length;
                row.children().each(function () {
                    if (isCorrectAnswer($(this), values, j)) {
                        score.score += 1;
                    } else if (isWrongAnswer($(this), values, j)) {
                        score.errorCount += 1;
                    }
                    j++;
                });
            }
        }
        return score;
    };

    var workMode = function (reset) {
        presenter.$view.find(".tf_" + presenter.type + "_image").each(function () {
            var image = $(this);
            image.removeClass("disabled wrong correct correct-answer");
            if (reset) {
                image.removeClass("down").addClass("up");
            }
        });

        presenter.$view.find('.tf_radio_question').each(function() {
            $(this).removeClass('disabled');
        });
    };

    var markElements = function () {
        for (var i = 0; i &lt; questions.length + 1; i++) {
            var j = 0;
            var row = presenter.$view.find('#' + i);
            if (i &gt; 0) {
                var values = (questions[i - 1].Answer).split(',');
                row.children().each(function () {
                    if ($(this).hasClass("disabled") &amp;&amp; j &gt; 0) return;
                    $(this).addClass("disabled");
                    if (isCorrectAnswer($(this), values, j)) {
                        $(this).addClass("correct");
                    } else if (isWrongAnswer($(this), values, j)) {
                        $(this).addClass("wrong");
                    }
                    j++;
                });
            }
        }
    };

    presenter.setPreviewTextParser = function (getTextParser) {
        presenter.textParser = new TextParserProxy(getTextParser());
    };

    function whichQuestion(row, table) {
        var questionNumber = 0;

        $(table).find('tr').each(function (index) {
            if ($(this)[0] == $(row)[0]) {
                questionNumber = index;

                return false;
            }
        });

        return questionNumber;
    }

    function whichAnswer(element, row) {
        var answerNumber = 0;
        $(row).find('.tf_' + presenter.type + '_image').each(function (index) {
            if ($(this)[0] == $(element)[0]) {
                answerNumber = index + 1; // Answers are counted from 1 to n

                return false;
            }

            return true;
        });

        return answerNumber;
    }

    presenter.createEventData = function (item, wasSelected, isSelectionCorrect) {
        return {
            'source': presenter.addonID,
            'item': item,
            'value': wasSelected ? '0' : '1',
            'score': isSelectionCorrect ? '1' : '0'
        };
    };

    presenter.createAllOKEventData = function () {
        return {
            'source': presenter.addonID,
            'item': 'all',
            'value': '',
            'score': ''
        };
    };

    presenter.createRowOKEventData = function (row) {
        return {
            'source': presenter.addonID,
            'item': row + '-all',
            'value': '',
            'score': ''
        }
    };

    function clickLogic(element) {
        var sendEvent = true;
        var wasSelected = false;
        if (presenter.isDisabled) return;

        if (!$(element).hasClass("disabled")) {
            if (multi) {
                if ($(element).hasClass("down")) {
                    wasSelected = true;
                    $(element).removeClass("down").addClass("up");
                } else {
                    $(element).removeClass("up").addClass("down");
                }
            } else {
                sendEvent = !$(element).hasClass("down");

                $(element).parent().children(".tf_" + presenter.type + "_image").each(function () {
                    $(this).removeClass("down").addClass("up");
                });

                $(element).removeClass("up").addClass("down");
            }

            if (sendEvent) {
                var selectedQuestion = whichQuestion($(element).parent(), $(element).parent().parent());
                var selectedAnswer = whichAnswer($(element), $(element).parent());
                var itemStr = selectedQuestion.toString() + '-' + selectedAnswer.toString();
                var isSelectionCorrect = presenter.isSelectionCorrect(questions[selectedQuestion - 1], parseInt(selectedAnswer, 10));

                var eventData = presenter.createEventData(itemStr, wasSelected, isSelectionCorrect);
                eventBus.sendEvent('ValueChanged', eventData);

                if (multi &amp;&amp; presenter.isRowOK(selectedQuestion)) {
                    var rowOKEventData = presenter.createRowOKEventData(selectedQuestion);
                    eventBus.sendEvent('ValueChanged', rowOKEventData);

                }

                if (presenter.isAllOK()) {
                    var allOKEventData = presenter.createAllOKEventData();
                    eventBus.sendEvent('ValueChanged', allOKEventData);
                }
            }
        }
    }

    function handleClickActions(view) {
        if(presenter.isDisabled) return;


        var $elements = $(view).find(".tf_" + presenter.type + "_image");
        
        if (!MobileUtils.isMobileUserAgent(window.navigator.userAgent)){
            $elements.hover(function(){
                $(this).addClass('mouse-hover');
                }, function(){
                $(this).removeClass('mouse-hover');
            });
        }
        
        $elements.on('touchstart', function (e) {
            e.stopPropagation();
            e.preventDefault();

            presenter.lastEvent = e;
        });

        $elements.on('touchend', function (e) {
            e.stopPropagation();
            e.preventDefault();

            if (presenter.lastEvent.type != e.type) {
                clickLogic($(e.target).parent());
            }
        });

        $elements.click(function (e) {
            e.stopPropagation();
            clickLogic(this);
        });
    }

    presenter.addTabindex = function (element, value) {
        element.attr("tabindex", value);
    };

    function generatePossibleChoicesRow(row) {
        row.append('&lt;td class="tf_' + presenter.type + '_question first" role="gridcell"&gt;&amp;nbsp;&lt;/td&gt;');

        for (var k = 0; k &lt; possibleChoices.length; k++) {
            var td = $('&lt;td class="tf_' + presenter.type + '_text" role="gridcell"&gt;' + possibleChoices[k].Choice + '&lt;/td&gt;');

            if (presenter.isTabindexEnabled) {
                presenter.addTabindex(td, 0);
            }

            row.append(td);
        }
    }

    function generateQuestionElement(row, rowID) {
        const question = questions[rowID - 1].Question;
        const parsedQuestion = presenter.textParser.parse(question);
        const td = $('&lt;td class="tf_' + presenter.type + '_question" role="gridcell"&gt;' + parsedQuestion + '&lt;/td&gt;');

        if (presenter.isTabindexEnabled) {
            presenter.addTabindex(td, 0);
        }

        row.append(td);
    }

    function generateRowContent(row, rowID) {
        generateQuestionElement(row, rowID);

        for (var i = 0; i &lt; possibleChoices.length; i++) {
            if (i === (possibleChoices.length - 1)) {
                row.append('&lt;td class="tf_' + presenter.type + '_image up last"&gt;&lt;/td&gt;');
            } else {
                row.append('&lt;td class="tf_' + presenter.type + '_image up"&gt;&lt;/td&gt;');
            }
            var innerElement = document.createElement('div');
            $(innerElement).css('color','rgba(0,0,0,0.0)');
            $(innerElement).css('font-size','0px');
            var text = $("&lt;div&gt;" + possibleChoices[i].Choice + "&lt;/div&gt;").text();
            var altText = document.createTextNode(text);
            $(innerElement).append(altText);
            innerElement.setAttribute('role', 'gridcell');

            if (presenter.isTabindexEnabled) {
                presenter.addTabindex($(innerElement), 0);
            }

            $(row).find('td:last-child').append(innerElement);
        }
    }

    function rowIndexed () {
        var count = possibleChoices.length + 1;
        return questions.reduce(function (acc, q, index) {
            acc.push({
                start: (index * count),
                end: ((index + 1) * count) - 1
            });
            return acc;
        }, []);
    }

    presenter.generateTableContent = function AddonTrueFalse_generateTableContent(table, view) {
        table.setAttribute('role', 'table');
        for (var rowID = 0; rowID &lt; questions.length + 1; rowID++) {
            $(table).append('&lt;tr class="tf_' + presenter.type + '_row" id=' + rowID + ' role="row"&gt;&lt;/tr&gt;');
            var row = $(view).find('#' + rowID);

            if (rowID === 0) {
                generatePossibleChoicesRow(row);
            } else {
                var answers = (questions[rowID - 1].Answer).split(',');
                for (var m = 0; m &lt; answers.length; m++) {
                    var answer = parseInt(answers[m]);
                    if (answer &gt; possibleChoices.length || answer &lt;= 0) {
                        $(view).html(INDEX_OUT_OF_RANGE);

                        break;
                    }
                }

                generateRowContent(row, rowID);
            }
        }
    };

    function getSpeechTexts(model) {
        var speechTexts = model['Speech texts'];

        if (speechTexts['Selected']['selected'] !== '' &amp;&amp; speechTexts['Selected']['selected'] !== undefined) {
            selectedSpeechText = speechTexts['Selected']['selected'];
        }

        if (speechTexts['Deselected']['deselected'] !== '' &amp;&amp; speechTexts['Deselected']['deselected'] !== undefined) {
            deselectedSpeechText = speechTexts['Deselected']['deselected'];
        }

        if (speechTexts['Correct']['correct'] !== '' &amp;&amp; speechTexts['Correct']['correct'] !== undefined) {
            correctSpeechText = speechTexts['Correct']['correct'];
        }

        if (speechTexts['Incorrect']['incorrect'] !== '' &amp;&amp; speechTexts['Incorrect']['incorrect'] !== undefined) {
            incorrectSpeechText = speechTexts['Incorrect']['incorrect'];
        }
    }

    var makeView = function (view, model, isPreview) {
        possibleChoices = model['Choices'];
        questions = model['Questions'];
        presenter.langAttribute = model['Lang attribute'];
        presenter.isVisible = ModelValidationUtils.validateBoolean(model["Is Visible"]);
        presenter.isVisibleByDefault = ModelValidationUtils.validateBoolean(model["Is Visible"]);
        presenter.isDisabled = false; // At start addon is always enabled, so we need to reset flag and set correct value.
        presenter.isDisabledByDefault = ModelValidationUtils.validateBoolean(model["isDisabled"]);
        presenter.$view.attr('lang', presenter.langAttribute);

        getSpeechTexts(model);

        if (notAllRequiredParameters(questions, possibleChoices)) {
            return $(view).html(QUESTION_AND_CHOICES_REQUIRED);
        }

        multi = model['Multi'] === 'True';

        if (model['isNotActivity'] != undefined){
            isNotActivity = (model['isNotActivity'] === 'True');
        }
        else {
            isNotActivity = false;
        }

        presenter.type = multi ? "checkbox" : "radio";
        var table = document.createElement('table');

        $(table).addClass('tf_' + presenter.type);
        $(table).attr("cellspacing", 0).attr("cellpadding", 0);
        $(view).append(table);

        presenter.generateTableContent(table, view);

        if (!isPreview) {
            handleClickActions(view);
            presenter.setVisibility(presenter.isVisible);

            if (presenter.isDisabledByDefault) {
                presenter.disable();
            } else {
                presenter.enable();
            }
        }

        if (presenter.textParser !== null &amp;&amp; !isPreview) { // Actions performed only in Player mode
            presenter.textParser.connectLinks($(view));
        }

        if (!isPreview) {
            presenter.$view.find('.tf_' + presenter.type + '_image' + ',.tf_' + presenter.type + '_question:not(.first)').each(function(index, element){
                presenter.keyboardNavigationElements[index] = $(element);
            });

            presenter.keyboardNavigationElementsLen = presenter.keyboardNavigationElements.length;
        }
    };

    presenter.setPlayerController = function (controller) {
        playerController = controller;
    };

    presenter.setEventBus = function (wrappedEventBus) {
        eventBus = wrappedEventBus;
    };

    presenter.setVisibility = function (isVisible) {
        presenter.$view.css('visibility', isVisible ? 'visible' : 'hidden');
    };

    presenter.hide = function () {
        presenter.setVisibility(false);
        presenter.isVisible = false;
    };

    presenter.show = function () {
        presenter.setVisibility(true);
        presenter.isVisible = true;
    };

    presenter.upgradeModel = function (model) {
        if (model['Speech texts'] === undefined) {
            model['Speech texts'] = {
                'Selected': {
                    'selected': ''
                },

                'Deselected': {
                    'deselected': ''
                },

                'Correct': {
                    'correct': ''
                },

                'Incorrect': {
                    'incorrect': ''
                }
            }
        }

        return model;
    };

    presenter.validateModel = function(model) {
        presenter.isTabindexEnabled = ModelValidationUtils.validateBoolean(model['Is Tabindex Enabled']);
    };

    presenter.run = function (view, model) {
        model = presenter.upgradeModel(model);
        presenter.$view = $(view);
        presenter.textParser = new TextParserProxy(playerController.getTextParser());

        presenter.validateModel(model);

        presenter.addonID = model.ID;
        makeView(view, model, false);

        var events = ['ShowAnswers', 'HideAnswers', 'GradualShowAnswers', 'GradualHideAnswers'];

        if (!eventBus) { return; }

        for (var i = 0; i &lt; events.length; i++) {
            eventBus.addEventListener(events[i], this);
        }
    };

    function isCorrectAnswer(element, values, index) {
        return values.indexOf(index.toString()) &gt;= 0 &amp;&amp; element.hasClass("down");
    }

    function isWrongAnswer(element, values, index) {
        return values.indexOf(index.toString()) &lt; 0 &amp;&amp; element.hasClass("down");
    }

    function notAllRequiredParameters(questions, possibleChoices) {
        return !questions[0].Question || possibleChoices.length &lt; 2 || !possibleChoices[0].Choice || !possibleChoices[1].Choice;
    }

    function getSelectedElements() {
        var selectedElements = [];
        var i = 0;
        presenter.$view.find(".tf_" + presenter.type + "_image").each(function () {
            selectedElements[i] = $(this).hasClass("down");
            i++;
        });
        return selectedElements;
    }

    presenter.createPreview = function (view, model) {
        model = presenter.upgradeModel(model);
        presenter.$view = $(view);
        makeView(view, model, true);
    };

    presenter.getState = function () {
        function getStateBase(selectedElements) {
            return {
            selectedElements: selectedElements,
            isVisible: presenter.isVisible,
            isDisabled: presenter.isDisabled
            }
        }

        var state = {};
        if (presenter.isShowAnswers()) {
            state = getStateBase(presenter.currentState); // This is saved on ShowAnswers
        } else {
            state = getStateBase(getSelectedElements());
        }

        return JSON.stringify(state);
    };

    presenter.setState = function (state) {
        if (!state) {
            return;
        }

        var i = 0;
        var selectedElements;
        var parsedState = JSON.parse(state);
        if(typeof parsedState.isVisible !== "undefined"){
            selectedElements = parsedState.selectedElements;
            presenter.setVisibility(parsedState.isVisible);
            presenter.isVisible = parsedState.isVisible;
        }else{
            selectedElements = parsedState;
        }

        presenter.$view.find(".tf_" + presenter.type + "_image").each(function () {
            if (selectedElements[i] == true) {
                $(this).addClass("down");
                $(this).removeClass("up");
            }
            i++;
        });

        //  For backward compatibility in old lessons
        if (parsedState.isDisabled === undefined) {
            parsedState.isDisabled = false;
        }

        if(!presenter.isShowAnswersActive) {
            if (parsedState.isDisabled) {
                presenter.disable();
            } else {
                presenter.enable();
            }
        }
    };

    presenter.setPrintableState = function(state) {
        presenter.printableState = null;
        presenter.didUserRespond = false;

        if (state === null || ModelValidationUtils.isStringEmpty(state)) {
            return;
        }
        presenter.didUserRespond = true;
        presenter.printableState = JSON.parse(state);
    };

    presenter.setShowErrorsMode = function () {
        if (isNotActivity) {
            return;
        }

        presenter.isErrorMode = true;

        if (presenter.isShowAnswersActive) {
            presenter.hideAnswers();
        }

        markElements();
    };

    presenter.setWorkMode = function () {
        if (isNotActivity) {
            return;
        }

        presenter.isErrorMode = false;

        if (presenter.isShowAnswersActive) {
            presenter.hideAnswers();
        }

        workMode(false);
    };

    presenter.reset = function () {
        presenter.isErrorMode = false;
        presenter.isShowAnswersActive = false;
        presenter.isGradualShowAnswersActive = false;

        if (presenter.currentState) {
            delete presenter.currentState;
        }

        workMode(true);
        presenter.setVisibility(presenter.isVisibleByDefault);
        presenter.isVisible = presenter.isVisibleByDefault;

        if (presenter.isDisabledByDefault) {
            presenter.disable();
        } else {
            presenter.enable();
        }
    };

    presenter.getErrorCount = function () {
        if (isNotActivity) return 0;

        if (presenter.isShowAnswers()) {
            return presenter.currentScore.errorCount;
        }

        return score().errorCount;
    };

    presenter.getMaxScore = function () {
        if (isNotActivity) return 0;

        if (presenter.isShowAnswers()) {
            return presenter.currentScore.maxScore;
        }

        return score().maxScore;
    };

    presenter.getScore = function () {
        if (isNotActivity) return 0;

        if (presenter.isShowAnswers()) {
            return presenter.currentScore.score;
        }

        return score().score;
    };

    presenter.executeCommand = function (name, params) {
        if (presenter.isErrorMode) {
            return;
        }

        var commands = {
            'isAllOK': presenter.isAllOK,
            'isSelected': presenter.isSelectedCommand,
            'markAsCorrect': presenter.markAsCorrectCommand,
            'markAsWrong': presenter.markAsWrongCommand,
            'markAsEmpty': presenter.markAsEmptyCommand,
            'removeMark': presenter.removeMarkCommand,
            'isAttempted' : presenter.isAttemptedCommand,
            'show': presenter.show,
            'hide': presenter.hide,
            'reset' : presenter.reset,
            'showAnswers' : presenter.showAnswers,
            'hideAnswers' : presenter.hideAnswers,
            'enable' : presenter.enable,
            'disable' : presenter.disable
        };

        Commands.dispatch(commands, name, params, presenter);
    };

    presenter.isAllOK = function () {
        return presenter.getMaxScore() === presenter.getScore() &amp;&amp; presenter.getErrorCount() === 0;
    };

    presenter.isRowOK = function (selectedQuestion) {
        var correctAnswersLength = 0;
        var rowAnswers = questions[selectedQuestion - 1].Answer.split(',');
        var row = presenter.$view.find('#' + selectedQuestion);

        for (var i = 0; i &lt; row.children('.down').length; i++) {
            var selectedAnswer = $(row.children('.down')[i]).index();
            var isSelectionCorrect = presenter.isSelectionCorrect(questions[selectedQuestion - 1], parseInt(selectedAnswer, 10));
            if (isSelectionCorrect) {
                correctAnswersLength++;
            }
        }

        return rowAnswers.length === correctAnswersLength;
    };

    presenter.isSelected = function (rowIndex, answerIndex) {
        if (answerIndex &lt; 1) return false;

        if (presenter.isShowAnswersActive) {
            presenter.hideAnswers();
        }

        var row = presenter.$view.find('#' + rowIndex);
        var el = row.children()[answerIndex];
        return $(el).hasClass("down");
    };


    presenter.markAsCorrect = function (rowIndex, answerIndex) {
        if(presenter.isDisabled) return;

        if (presenter.isShowAnswersActive) {
            presenter.hideAnswers();
        }

        var row = presenter.$view.find('#' + rowIndex);
        if (rowIndex &gt; 0) {
            var el = row.children()[answerIndex];
            $(el).addClass("disabled");
            $(el).addClass("correct");
         }
    };

    presenter.markAsWrong = function (rowIndex, answerIndex) {
        if(presenter.isDisabled) return;

        if (presenter.isShowAnswersActive) {
            presenter.hideAnswers();
        }

        var row = presenter.$view.find('#' + rowIndex);
        if (rowIndex &gt; 0) {
            var el = row.children()[answerIndex];
            $(el).addClass("disabled");
            $(el).addClass("wrong");
        }
    };

    presenter.markAsEmpty = function (rowIndex, answerIndex) {
        if(presenter.isDisabled) return;

        if (presenter.isShowAnswersActive) {
            presenter.hideAnswers();
        }

        var row = presenter.$view.find('#' + rowIndex);
        if (rowIndex &gt; 0) {
            var el = row.children()[answerIndex];
            $(el).addClass("disabled");
        }
    };

    presenter.removeMark = function (rowIndex, answerIndex) {
        if(presenter.isDisabled) return;

        if (presenter.isShowAnswersActive) {
            presenter.hideAnswers();
        }

        var row = presenter.$view.find('#' + rowIndex);
        if (rowIndex &gt; 0) {
            var el = row.children()[answerIndex];
            $(el).removeClass("wrong").removeClass("correct");
        }
    };

    presenter.isAttempted = function () {
        if (isNotActivity) return true;

        if (presenter.isShowAnswersActive) {
            presenter.hideAnswers();
        }

        var isAttempted = false;
        for (var rowIndex = 0; rowIndex &lt; questions.length + 1; rowIndex++) {
            var answerIndex = 0;
            var row = presenter.$view.find('#' + rowIndex);
            if (rowIndex &gt; 0) {
                row.children().each(function () {
                    if (presenter.isSelected(rowIndex, answerIndex)) {
                        isAttempted = true;
                        return false; // break;
                    }
                    answerIndex++;
                    return true;
                });
            }
        }
        return isAttempted;
    };

    presenter.isSelectedCommand = function (params) {
        presenter.isSelected(parseInt(params[0], 10), parseInt(params[1], 10));
    };

    presenter.isAttemptedCommand = function () {
         return presenter.isAttempted();
    };

    presenter.markAsEmptyCommand = function (params) {
        presenter.markAsEmpty(parseInt(params[0], 10), parseInt(params[1], 10));
    };

    presenter.markAsWrongCommand = function (params) {
        presenter.markAsWrong(parseInt(params[0], 10), parseInt(params[1], 10));
    };

    presenter.removeMarkCommand = function (params) {
        presenter.removeMark(parseInt(params[0], 10), parseInt(params[1], 10));
    };

    presenter.markAsCorrectCommand = function (params) {
        presenter.markAsCorrect(parseInt(params[0], 10), parseInt(params[1], 10));
    };

    presenter.onEventReceived = function (eventName, data) {
        if (eventName === "ShowAnswers") {
            presenter.showAnswers();
        } else if (eventName === "HideAnswers") {
            presenter.hideAnswers();
        } else if (eventName === "GradualShowAnswers") {
            if (!presenter.isGradualShowAnswersActive) {
                presenter.currentScore = score();
                presenter.currentState = getSelectedElements();
                presenter.isGradualShowAnswersActive = true;
            }
            if (data.moduleID === presenter.addonID) {
                workMode(true);
                presenter.gradualShowAnswers(parseInt(data.item, 10));
            }
        } else if (eventName === "GradualHideAnswers") {
            presenter.gradualHideAnswers();
        }
    };

    presenter.gradualShowAnswers = function (itemIndex) {
        presenter.setCorrectAnswers(itemIndex + 1); // don't ask
    }

    presenter.gradualHideAnswers = function () {
        presenter.isGradualShowAnswersActive = false;
        workMode(true);

        var state = JSON.stringify({
            "selectedElements": presenter.currentState,
            "isVisible": presenter.isVisible
        });

        presenter.setState(state);

        delete presenter.currentState;
    }

    presenter.isShowAnswers = function () {
        return presenter.isShowAnswersActive || presenter.isGradualShowAnswersActive;
    }

    presenter.getActivitiesCount = function () {
        return questions.length;
    }

    presenter.disable = function() {
        if (presenter.isShowAnswersActive) {
            presenter.hideAnswers();
        }
        presenter.isDisabled = true;
        presenter.$view.addClass("disabled");
    };

    presenter.enable = function() {
        if (presenter.isShowAnswersActive) {
            presenter.hideAnswers();
        }
        presenter.isDisabled = false;
        presenter.$view.removeClass("disabled");
    };

    presenter.showAnswers = function () {
        if (isNotActivity || presenter.isShowAnswersActive) {
            return;
        }

        presenter.currentScore = score();
        presenter.isShowAnswersActive = true;
        presenter.currentState = getSelectedElements();
        presenter.isErrorMode = false;
        workMode(true);

        presenter.setCorrectAnswers(questions.length)
    };

    presenter.setCorrectAnswers = function (length) {
       for (var i = 1; i &lt; length + 1; i++) {
            var $row = presenter.$view.find('#' + i);
            var correctValues = (questions[i - 1].Answer).split(',');

            var trueFalseImages = $row.find(".tf_" + presenter.type + "_image");
            trueFalseImages.addClass('disabled');

            for (var j = 0; j &lt; correctValues.length; j++) {
                // empty string split by separator will return array with empty element
                if (correctValues[j].length &gt; 0) {
                    var index = parseInt(correctValues[j], 10) + 1;
                    var $element = $row.find(".tf_" + presenter.type + "_image:nth-child(" + index + ")");

                    $element.addClass('down correct-answer');
                    $element.removeClass('up');
                }
            }
        }
    }

    presenter.hideAnswers = function () {
        if (isNotActivity || !presenter.isShowAnswersActive) {
            return;
        }

        workMode(true);

        var state = JSON.stringify({
            "selectedElements": presenter.currentState,
            "isVisible": presenter.isVisible
        });

        presenter.setState(state);

        delete presenter.currentState;
        presenter.isShowAnswersActive = false;
    };

    function getTextToSpeech () {
        if (tts) {
            return tts;
        }

        tts = playerController.getModule('Text_To_Speech1');
        return tts;
    }

    function getActivatedElement () {
        return presenter.$view.find('.keyboard_navigation_active_element');
    }

    function getElementIndex(element) {
        var div = element.parent(),
            parent = div.parent(),
            list = parent.find('td');

        return $(list).index(div);
    }

    function getChoice(index) {
        var $topRowElement = presenter.$view.find('#0');
        var $choiceElement = $topRowElement.children().eq(index);
        return window.TTSUtils.getTextVoiceArrayFromElement($choiceElement,presenter.langAttribute);
    }

    function readOption(readSelection) {
        var tts = getTextToSpeech();
        if (tts) {
            var $active = getActivatedElement(),
                elementIndex = getElementIndex($active),
                choiceArray = getChoice(elementIndex);
            
            if ($active.hasClass('tf_' + presenter.type + '_question')) {
                speak(window.TTSUtils.getTextVoiceArrayFromElement($active,presenter.langAttribute));
                return;
            }

            if (!readSelection) {
                if ($active.parent().hasClass('down')) {
                    if (presenter.isErrorMode) {
                        if ($active.parent().hasClass('correct')) {
                            speak(choiceArray.concat([getTextVoiceObject(selectedSpeechText + " " + correctSpeechText, "")]))
                        }
                        if($active.parent().hasClass('wrong')) {
                            speak(choiceArray.concat([getTextVoiceObject(selectedSpeechText + " " + incorrectSpeechText, "")]))
                        }
                    } else {
                        speak(choiceArray.concat([getTextVoiceObject(selectedSpeechText, "")]))
                    }
                } else {
                    speak(choiceArray);
                }
            } else {
                if ($active.parent().hasClass('down')) {
                    speak([getTextVoiceObject(selectedSpeechText, "")]);
                } else {
                    speak([getTextVoiceObject(deselectedSpeechText, "")]);
                }
            }
        }
    }

    presenter.setWCAGStatus = function (isOn) {
        isWCAGOn = isOn;
    };

    function speak (data) {
        var tts = getTextToSpeech();
        if (tts &amp;&amp; isWCAGOn) {
            tts.speak(data);
        }
    }

    presenter.keyboardController = function(keycode, isShiftKeyDown, event) {
        event.preventDefault();
        presenter.shiftPressed = event.shiftKey;

        var keys = {
            ENTER: 13,
            ESCAPE: 27,
            SPACE: 32,
            ARROW_LEFT: 37,
            ARROW_UP: 38,
            ARROW_RIGHT: 39,
            ARROW_DOWN: 40,
            TAB: 9
        };

        function mark_current_element(new_position_index){
            if (presenter.keyboardNavigationCurrentElement) {
                if(presenter.keyboardNavigationCurrentElement.find('div').length &gt; 0) {
                    presenter.keyboardNavigationCurrentElement.find('div').removeClass('keyboard_navigation_active_element');
                } else {
                    presenter.keyboardNavigationCurrentElement.removeClass('keyboard_navigation_active_element');
                }
            }
            presenter.keyboardNavigationCurrentElementIndex = new_position_index;
            presenter.keyboardNavigationCurrentElement = presenter.keyboardNavigationElements[new_position_index];
            if(presenter.keyboardNavigationCurrentElement.find('div').length &gt; 0) {
                presenter.keyboardNavigationCurrentElement.find('div').addClass('keyboard_navigation_active_element');
            } else {
                presenter.keyboardNavigationCurrentElement.addClass('keyboard_navigation_active_element');
            }
        }

        var enter = function (){
            if (isShiftKeyDown) {
                if (presenter.keyboardNavigationActive){
                    escape();
                    presenter.isKeyboardOpened = false;
                }
                return;
            }

            if (!presenter.keyboardNavigationActive) {
                presenter.keyboardNavigationActive = true;
                mark_current_element(0);
                readOption(false);
            } else {
                readOption(false);
            }
        };

        function swicht_element(move, checkDirection){
            var rows = rowIndexed();

            var currentRow = rows.filter(function (row) {
                return row.start &lt;= presenter.keyboardNavigationCurrentElementIndex &amp;&amp; row.end &gt;= presenter.keyboardNavigationCurrentElementIndex;
            })[0];

            var new_position_index = presenter.keyboardNavigationCurrentElementIndex + move;

            if(checkDirection &amp;&amp; currentRow &amp;&amp; (new_position_index &lt; currentRow.start || new_position_index &gt; currentRow.end)) {
                return;
            }

            if (new_position_index &gt;= presenter.keyboardNavigationElementsLen) {
                new_position_index = new_position_index - move;
            } else if (new_position_index &lt; 0) {
                new_position_index = presenter.keyboardNavigationCurrentElementIndex;
            }
            mark_current_element(new_position_index);
        }

        var next_element = function (){
            swicht_element(1, true);
            readOption(false);
        };

        var previous_element = function (){
            swicht_element(-1, true);
            readOption(false);
        };

        var next_question = function () {
            swicht_element(possibleChoices.length + 1, false);
            readOption(false);
        };

        var previous_question = function () {
            swicht_element(-(possibleChoices.length + 1), false);
            readOption(false);
        };

        var mark = function (){
            if (presenter.isErrorMode) {
                return;
            }
            presenter.keyboardNavigationCurrentElement.click();
            readOption(true);
        };

        var escape = function (){
            if (!presenter.keyboardNavigationActive){
                return;
            }
            presenter.keyboardNavigationActive = false;
            presenter.keyboardNavigationCurrentElement.find('div').removeClass('keyboard_navigation_active_element');
            presenter.keyboardNavigationCurrentElement.removeClass('keyboard_navigation_active_element');
            presenter.keyboardNavigationCurrentElement = null;
        };

        function tabHandler() {
            swicht_element(isShiftKeyDown ? -1 : 1, true);
            readOption(false);
        }

        var mapping = {};
        mapping[keys.ENTER] = enter;
        mapping[keys.ESCAPE] = escape;
        mapping[keys.SPACE] = mark;
        mapping[keys.ARROW_LEFT] = previous_element;
        mapping[keys.ARROW_UP] = previous_question;
        mapping[keys.ARROW_RIGHT] = next_element;
        mapping[keys.ARROW_DOWN] = next_question;
        mapping[keys.TAB] = tabHandler;

        try {
            mapping[keycode]();
        } catch (er) {
        }

    };

    presenter.setPrintableController = function (controller) {
        printableController = controller;
        presenter.textParser = new TextParserProxy(printableController.getTextParser());
    };

    presenter.getPrintableHTML = function (model, showAnswers) {
        var model = presenter.upgradeModel(model);
        var isMulti = model.Multi === 'True';
        var userAnswers = getUserResponses();
        var choiceLength = model.Choices.length

        var $view = $("&lt;div&gt;&lt;/div&gt;");
        $view.attr('id', model.ID);
        $view.addClass('printable_addon_TrueFalse');
        $view.css("max-width", model["Width"]+"px");
        var $table = $("&lt;table&gt;&lt;/table&gt;");
        var $tbody = $("&lt;tbody&gt;&lt;/tbody&gt;");

        //Header row
        var $trHead = $("&lt;tr&gt;&lt;/tr&gt;");
        $trHead.append("&lt;td&gt;&lt;/td&gt;");
        for (var i = 0; i &lt; choiceLength; i++) {
            var choice = model.Choices[i];
            var $td = $("&lt;td&gt;&lt;/td&gt;");
            $td.html(choice.Choice);
            if (isMulti &amp;&amp; showAnswers &amp;&amp; presenter.didUserRespond) {
                $td.attr('colspan', '2');
            } else if (!isMulti &amp;&amp; showAnswers &amp;&amp; presenter.didUserRespond &amp;&amp; i === (choiceLength - 1)) {
                $td.attr('colspan', '2');
            }
            $trHead.append($td);
        }
        $tbody.append($trHead);

        //Question rows
        for (var i = 0; i &lt; model.Questions.length; i++) {
            var question = model.Questions[i];
            var $tr = $("&lt;tr&gt;&lt;/tr&gt;");

            var $questionCell = $("&lt;td&gt;&lt;/td&gt;");
            $questionCell.html(presenter.textParser.parse(question.Question));
            $tr.append($questionCell);

            var answers = [];
            if (showAnswers) answers = question.Answer.split(',');
            var boxType = isMulti ? "checkbox" : "radio";

            for (var j = 0; j &lt; choiceLength; j++) {
                var $td = $("&lt;td&gt;&lt;/td&gt;");

                $td.addClass(`${boxType}-container`);
                $td.addClass(`${boxType}-${i+1}-${j+1}`);
                var $inputDiv = $("&lt;div&gt;&lt;/div&gt;");
                $inputDiv.addClass("placeholder");
                $td.append($inputDiv);
                var $checkbox = $("&lt;input type=\"checkbox\"&gt;");
                var userAnswerIndex = i * choiceLength + j;
                var $checkboxSpan = $("&lt;span&gt;&lt;/span&gt;");

                if (presenter.didUserRespond &amp;&amp; userAnswers[userAnswerIndex]) {
                    $checkbox.attr("checked", "checked");
                    $checkboxSpan.css('background', 'black');
                } else if (showAnswers &amp;&amp; answers.indexOf((j+1).toString()) != -1 &amp;&amp; !presenter.didUserRespond) {
                    $checkbox.attr("checked", "checked");
                    $checkboxSpan.css('background', 'darkgray');
                }

                $td.append($checkbox);

                $td.append($checkboxSpan);
                $tr.append($td);

                if (showAnswers &amp;&amp; isMulti &amp;&amp; userAnswers[userAnswerIndex]) {
                    var $markCell = $("&lt;td&gt;&lt;/td&gt;");
                    var $markDiv = $("&lt;div&gt;&lt;/div&gt;");
                    isAnswerCorrect(answers, userAnswers, i, j, choiceLength) ? $markDiv.addClass("correctAnswerMark") : $markDiv.addClass("incorrectAnswerMark");
                    $markCell.append($markDiv);
                    $tr.append($markCell);
                } else if (showAnswers &amp;&amp; presenter.didUserRespond &amp;&amp; isMulti) {
                    addCell(answers, userAnswers, $tr, i, choiceLength);
                }
            }
            if (showAnswers &amp;&amp; !isMulti &amp;&amp; didUserRespondOnQuestion(userAnswers, i, choiceLength)) {
                addCell(answers, userAnswers, $tr, i, choiceLength, true);
            }
            $tbody.append($tr);
        }

        $table.append($tbody);
        $view.append($table);
        return $view[0].outerHTML;
    };

    presenter.getScoreWithMetadata = function() {
        var scores = [];
        var allAnswers = [];
        var selectedElements = getSelectedElements();
        for (var i = 0; i &lt; possibleChoices.length; i++) {
            allAnswers.push(possibleChoices[i].Choice.trim());
        }
        for (var i = 0; i &lt; questions.length; i++) {
            var score = {
                userAnswer: "",
                allAnswers: allAnswers,
                isCorrect: false,
            };
            var correctAnswers = questions[i].Answer.split(',');
            firstChoiceIndex = i * possibleChoices.length;
            for (var j = 0; j &lt; possibleChoices.length; j++) {
                if (selectedElements[firstChoiceIndex + j]) {
                    score.userAnswer = allAnswers[j];
                    if (correctAnswers.indexOf((j + 1) + "") != -1) {
                        score.isCorrect = true;
                    }
                }
            }
            scores.push(score);
        }
        return scores;
    }

    function getUserResponses() {
        if (presenter.printableState &amp;&amp; presenter.printableState.hasOwnProperty('selectedElements')) {
            return presenter.printableState['selectedElements']
        }
        return [];
    }

    function addCell(answers, userAnswers, $tableRow, i, choiceLength, shouldAddMark = false) {
        var $td = $("&lt;td&gt;&lt;/td&gt;");
        var $markDiv = $("&lt;div&gt;&lt;/div&gt;");
        if (shouldAddMark) {
            areAnswersCorrect(answers, userAnswers, i, choiceLength) ? $markDiv.addClass("correctAnswerMark")
                : $markDiv.addClass("incorrectAnswerMark");
        }
        $td.append($markDiv);
        $tableRow.append($td);
    }

    function didUserRespondOnQuestion(userAnswers, i, choiceLength) {
        return userAnswers.slice(i * choiceLength, (i + 1) * choiceLength).some(answer =&gt; answer);
    }

    function areAnswersCorrect(correctAnswer, userAnswer, i, choiceLength) {
        var areCorrect = false;
        correctAnswer.forEach(answer =&gt; {
            var index = +answer - 1;
            if (userAnswer[i * choiceLength + index]) {
                areCorrect = true;
            }
        });
        return areCorrect;
    }

    function isAnswerCorrect(correctAnswers, userAnswer, i, j, choiceLength) {
        return correctAnswers.indexOf((j + 1).toString()) !== -1 &amp;&amp; userAnswer[i * choiceLength + j];
    }

    return presenter;
}
</presenter></addon>