<?xml version="1.0" encoding="UTF-8" standalone="no"?><addon xmlns="http://icplayer.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="FlashCards" xsi:schemaLocation="http://icplayer.com ../../tools/addon.xsd">
    <model>
		<property displayName="Cards" name="Cards" nameLabel="FlashCards_property_Cards" type="list">
            <property displayName="Front" name="Front" nameLabel="FlashCards_property_Front" type="html"/>
            <property displayName="Back" name="Back" nameLabel="FlashCards_property_Back" type="html"/>
			<property displayName="Audio Front" name="AudioFront" nameLabel="FlashCards_property_Audio_Front" type="audio"/>
			<property displayName="Audio Back" name="AudioBack" nameLabel="FlashCards_property_Audio_Back" type="audio"/>
        </property>
        <property displayName="Disable Loop" name="NoLoop" nameLabel="FlashCards_property_Disable_Loop" type="boolean"/>
        <property displayName="Enable Favourites" name="Favourites" nameLabel="FlashCards_property_Enable_Favourites" type="boolean"/>
        <property displayName="Hide Previous and Next Buttons" name="HidePrevNext" nameLabel="FlashCards_property_Hide_Previous_and_Next_Buttons" type="boolean"/>
        <property displayName="Show Activity Buttons" name="ShowButtons" nameLabel="FlashCards_property_Show_Activity_Buttons" type="boolean"/>
        <property displayName="Is Activity" name="IsActivity" nameLabel="FlashCards_property_Is_Activity" type="boolean"/>
        <property displayName="Send event only on card changed" name="sendEventOnCardChanged" nameLabel="FlashCards_property_eventOnCardChanged" type="boolean"/>
        <property displayName="Lang attribute" name="langAttribute" nameLabel="FlashCards_property_lang_attribute" type="string"/>
        <property displayName="Speech texts" name="speechTexts" nameLabel="FlashCards_property_speech_texts" type="staticlist">

            <property name="card" nameLabel="FlashCards_property_card" type="staticrow">
                <property name="card" nameLabel="FlashCards_property_card" type="string"/>
            </property>

            <property name="outOf" nameLabel="FlashCards_property_outOf" type="staticrow">
                <property name="outOf" nameLabel="FlashCards_property_outOf" type="string"/>
            </property>

            <property name="favourite" nameLabel="FlashCards_property_favourite" type="staticrow">
                <property name="favourite" nameLabel="FlashCards_property_favourite" type="string"/>
            </property>

            <property name="audio" nameLabel="FlashCards_property_audio" type="staticrow">
                <property name="audio" nameLabel="FlashCards_property_audio" type="string"/>
            </property>

            <property name="correct" nameLabel="FlashCards_property_correct" type="staticrow">
                <property name="correct" nameLabel="FlashCards_property_correct" type="string"/>
            </property>

            <property name="wrong" nameLabel="FlashCards_property_wrong" type="staticrow">
                <property name="wrong" nameLabel="FlashCards_property_wrong" type="string"/>
            </property>

            <property name="reset" nameLabel="FlashCards_property_reset" type="staticrow">
                <property name="reset" nameLabel="FlashCards_property_reset" type="string"/>
            </property>

            <property name="selected" nameLabel="FlashCards_property_selected" type="staticrow">
                <property name="selected" nameLabel="FlashCards_property_selected" type="string"/>
            </property>

            <property name="deselected" nameLabel="FlashCards_property_deselected" type="staticrow">
                <property name="deselected" nameLabel="FlashCards_property_deselected" type="string"/>
            </property>

            <property name="cardHasBeenReset" nameLabel="FlashCards_property_cardHasBeenReset" type="staticrow">
                <property name="cardHasBeenReset" nameLabel="FlashCards_property_cardHasBeenReset" type="string"/>
            </property>

            <property name="turned" nameLabel="FlashCards_property_turned" type="staticrow">
                <property name="turned" nameLabel="FlashCards_property_turned" type="string"/>
            </property>

        </property>
        <property displayName="Randomize order" name="randomize" nameLabel="FlashCards_property_randomize" type="boolean"/>
    </model>
<css>.flashcards-wrapper {
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
}

.flashcards-main{
    display: flex;
    width: 100%;
    height: 100%;
    perspective: 1000px;
}

.flashcards-prev, .flashcards-next {
    display: block;
    width: 30px;
    height: 100%;
    background: #e8e8e8;
    cursor: pointer;
    border: none;
}
.flashcards-prev:disabled, .flashcards-next:disabled {
    opacity: 0.5;
    cursor: default;
}

.flashcards-card {
    position: relative;
    width: 100%;
    height: 100%;
}
.flashcards-card-audio-wrapper{
    display: none;
    position: absolute;
    width: 40px;
    height: 40px;
    top: 40px;
    left: 10px;
}
    .flashcards-card-audio-button{
        cursor: pointer;
        width: 40px;
        height: 40px;
        border-radius: 50%;
        background-color: #017aaf;
        background-image: url(/file/serve/5957429735063552);
        background-size: 30px 30px;
        background-repeat: no-repeat;
        background-position: center center;
    }
    .flashcards-card-audio-button.playing{
        background-image: url(/file/serve/6424961084424192);
    }
    .flashcards-card-audio-button.disabled{
        cursor: pointer;
        opacity: 0.5;    
    }

.flashcards-card.flashcards-card-reversed .flashcards-card-front{
    transform: rotateY(-180deg);
}
.flashcards-card.flashcards-card-reversed .flashcards-card-back {
    transform: rotateY(0deg);
}

.flashcards-card-front, .flashcards-card-back {
    position: absolute;
    top: 0;
    right: 0;
    left: 0;
    bottom: 0;
    backface-visibility: hidden;
    transition: transform 0.5s;
    transform-style: preserve-3d;
    -webkit-backface-visibility: hidden;
}
.flashcards-card-front {
    background: #eee;
    color: black;
}
.flashcards-card-back {
    background: #d3e3f3;
    color: #000;
    transform: rotateY(180deg);
}
    .flashcards-card-contents {
        padding: 10px;
        top: 0;
        left: 0;
        right: 0;
        bottom: 50px;
        position: absolute;
        overflow-y: auto;
        cursor: pointer;
    }
    .flashcards-card-contents img {
        max-width: 100%;
    }

.flashcards-button-favourite{
    position: absolute;
    width: 30px;
    height: 30px;
    top:0;
    right: 0;
    background: #999;
    cursor: pointer;
}
.flashcards-button-favourite.flashcards-button-selected {
    background: #83e1f7;
}

.flashcards-buttons{
    position: absolute;
    bottom: 0px;
    width: 100%;
    height: 50px;
    background: #ddd;
    display: flex;
    cursor: pointer;
}
    .flashcards-button {
        width: 33.3333%;
        text-align: center;
        line-height: 50px;
        color: #000;
    }
    .flashcards-button.flashcards-button-selected {
        background: #83e1f7;
    }

.flashcards-panel{
    height: 30px;
    width: 100%;
    background: #e8e8e8;
    text-align: center;
    color: #000;
    line-height: 30px;
}
</css><view>&lt;div class="flashcards-wrapper"&gt;
    &lt;div class="flashcards-main"&gt;
        &lt;div class="flashcards-prev-wrapper"&gt;
            &lt;button type="button" class="flashcards-prev"&gt;&lt;/button&gt;
        &lt;/div&gt;
        &lt;div class="flashcards-card"&gt;
            &lt;div class="flashcards-card-front"&gt;
                &lt;div class="flashcards-card-contents flashcards-card-contents-front"&gt;
                &lt;/div&gt;
                &lt;div class="flashcards-card-audio-wrapper flashcards-card-audio-wrapper-front"&gt;
                    &lt;audio class="flashcards-card-audio flashcards-card-audio-front"&gt;&lt;/audio&gt;
                    &lt;div class="flashcards-card-audio-button flashcards-card-audio-button-front disabled"&gt;&lt;/div&gt;
                &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class="flashcards-card-back"&gt;
                &lt;div class="flashcards-card-contents flashcards-card-contents-back"&gt;
                &lt;/div&gt;
                &lt;div class="flashcards-buttons"&gt;
                    &lt;div class="flashcards-button flashcards-button-wrong"&gt;
                        x
                    &lt;/div&gt;
                    &lt;div class="flashcards-button flashcards-button-reset"&gt;
                        o
                    &lt;/div&gt;
                    &lt;div class="flashcards-button flashcards-button-correct"&gt;
                        v
                    &lt;/div&gt;
                &lt;/div&gt;
                &lt;div class="flashcards-card-audio-wrapper flashcards-card-audio-wrapper-back"&gt;
                    &lt;audio class="flashcards-card-audio flashcards-card-audio-back"&gt;&lt;/audio&gt;
                    &lt;div class="flashcards-card-audio-button flashcards-card-audio-button-back disabled"&gt;&lt;/div&gt;
                &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class="flashcards-button-favourite"&gt;&lt;/div&gt;
            &lt;div class="flashcards-card-audio-wrapper flashcards-card-audio-wrapper-hidden"&gt;
                &lt;audio class="flashcards-card-audio flashcards-card-audio-hidden"&gt;&lt;/audio&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class="flashcards-prev-wrapper"&gt;
            &lt;button type="button" class="flashcards-next"&gt;&lt;/button&gt;
        &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="flashcards-panel"&gt;&lt;/div&gt;
&lt;/div&gt;
</view><preview>&lt;div class="flashcards-wrapper"&gt;
    &lt;div class="flashcards-main"&gt;
        &lt;div class="flashcards-prev-wrapper"&gt;
            &lt;button type="button" class="flashcards-prev"&gt;&lt;/button&gt;
        &lt;/div&gt;
        &lt;div class="flashcards-card"&gt;
            &lt;div class="flashcards-card-front"&gt;
                &lt;div class="flashcards-card-contents flashcards-card-contents-front"&gt;
                &lt;/div&gt;
                &lt;div class="flashcards-card-audio-wrapper flashcards-card-audio-wrapper-front"&gt;
                    &lt;audio class="flashcards-card-audio flashcards-card-audio-front"&gt;&lt;/audio&gt;
                    &lt;div class="flashcards-card-audio-button flashcards-card-audio-button-front disabled"&gt;&lt;/div&gt;
                &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class="flashcards-card-back"&gt;
                &lt;div class="flashcards-card-contents flashcards-card-contents-back"&gt;
                &lt;/div&gt;
                &lt;div class="flashcards-buttons"&gt;
                    &lt;div class="flashcards-button flashcards-button-wrong"&gt;
                        x
                    &lt;/div&gt;
                    &lt;div class="flashcards-button flashcards-button-reset"&gt;
                        o
                    &lt;/div&gt;
                    &lt;div class="flashcards-button flashcards-button-correct"&gt;
                        v
                    &lt;/div&gt;
                &lt;/div&gt;
                &lt;div class="flashcards-card-audio-wrapper flashcards-card-audio-wrapper-back"&gt;
                    &lt;audio class="flashcards-card-audio flashcards-card-audio-back"&gt;&lt;/audio&gt;
                    &lt;div class="flashcards-card-audio-button flashcards-card-audio-button-back disabled"&gt;&lt;/div&gt;
                &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class="flashcards-button-favourite"&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class="flashcards-prev-wrapper"&gt;
            &lt;button type="button" class="flashcards-next"&gt;&lt;/button&gt;
        &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="flashcards-panel"&gt;&lt;/div&gt;
&lt;/div&gt;
</preview><presenter>function AddonFlashCards_create(){

    var presenter = function () {}

    presenter.configuration = {
        isVisible: false,
        currentCard: 1,
        noLoop: false,
        IsActivity: false,
        Favourites: false
    };

    presenter.state = {
        isVisible: false,
        currentCard: 1,
        totalCards: 1,
        noLoop: false,
        IsActivity: false,
        Favourites: false,
        ShowOnlyFavourites: false,
        cardsScore: null,
        cardsFavourites: null
    };

    presenter.cardMap = [];

    presenter.isLoaded = false;
    presenter.isPreview = false;
    presenter.textParser = null;

    let isWCAGOn = false;
    presenter.speechTexts = {};
    let KEYBOARD_NAVIGATION_ACTIVE_ITEM_CLASS = "keyboard_navigation_active_element";

    let DEFAULT_TTS_PHRASES = {
        card: "Card",
        outOf: "out of",
        favourite: "Favourite",
        audio: "Audio",
        correct: "Correct",
        wrong: "Wrong",
        reset: "Reset",
        selected: "Selected",
        deselected: "Deselected",
        cardHasBeenReset: "Card has been reset",
        turned: "Turned"
    };

    presenter.lastHiddenAudio = {
        cardIndex: -1,
        reverse: false
    };

    presenter.setPlayerController = function (controller) {
        presenter.playerController = controller;
        presenter.eventBus = presenter.playerController.getEventBus();
        presenter.eventBus.addEventListener('ShowAnswers', this);
        presenter.eventBus.addEventListener('HideAnswers', this);

        presenter.textParser = new TextParserProxy(controller.getTextParser());
    };

    presenter.createEventData = function (item, value, score) {
        return {
            source : presenter.configuration.addonID,
            item: item,
            value: value,
            score: score
        };
    };

    presenter.triggerEvent = function (item, value, score) {
        var eventData = presenter.createEventData(item, value, score);
        presenter.eventBus.sendEvent('ValueChanged', eventData);
    };

    presenter.validateModel = function (model) {
        presenter.setSpeechTexts(model['speechTexts']);
        return {
            isValid: true,
            isVisible: ModelValidationUtils.validateBoolean(model["Is Visible"]),
            noLoop: ModelValidationUtils.validateBoolean(model['NoLoop']),
            Favourites: ModelValidationUtils.validateBoolean(model['Favourites']),
            HidePrevNext: ModelValidationUtils.validateBoolean(model['HidePrevNext']),
            ShowButtons: ModelValidationUtils.validateBoolean(model['ShowButtons']),
            IsActivity: ModelValidationUtils.validateBoolean(model["IsActivity"]),
            currentCard: presenter.configuration.currentCard,
            cardsScore: [],
            cardsFavourites: [],
            addonID: model['ID'],
            langTag: model['langAttribute'],
            randomizeOrder: ModelValidationUtils.validateBoolean(model['randomize']),
            sendEventOnCardChanged: ModelValidationUtils.validateBoolean(model["sendEventOnCardChanged"])
        };
    };

    presenter.upgradeModel = function (model) {
        var upgradedModel = presenter.upgradeAddTTS(model);
        upgradedModel = presenter.upgradeSendEventOnCardChanged(upgradedModel);

        return presenter.upgradeAddRandomize(upgradedModel);
    };

    presenter.upgradeAddTTS = function (model) {
        var upgradedModel = {};
        $.extend(true, upgradedModel, model);

        if (!upgradedModel["speechTexts"]) {
            upgradedModel["speechTexts"] = {};
            upgradedModel["speechTexts"]["card"] = {card: ""};
            upgradedModel["speechTexts"]["outOf"] = {outOf: ""};
            upgradedModel["speechTexts"]["favourite"] = {favourite: ""};
            upgradedModel["speechTexts"]["audio"] = {audio: ""};
            upgradedModel["speechTexts"]["correct"] = {correct: ""};
            upgradedModel["speechTexts"]["wrong"] = {wrong: ""};
            upgradedModel["speechTexts"]["reset"] = {reset: ""};
            upgradedModel["speechTexts"]["selected"] = {selected: ""};
            upgradedModel["speechTexts"]["deselected"] = {deselected: ""};
            upgradedModel["speechTexts"]["cardHasBeenReset"] = {cardHasBeenReset: ""};
            upgradedModel["speechTexts"]["turned"] = {turned: ""};
        }
        if (!upgradedModel["langAttribute"]) {
            upgradedModel["langAttribute"] = ""
        }
        return upgradedModel;
    };

    presenter.upgradeSendEventOnCardChanged = function (model) {
        var upgradedModel = {};
        $.extend(true, upgradedModel, model);

        if (!upgradedModel.hasOwnProperty('sendEventOnCardChanged')) {
            upgradedModel['sendEventOnCardChanged'] = 'False';
        }

        return upgradedModel;
    };

    presenter.upgradeAddRandomize = function (model) {
            var upgradedModel = {};
            $.extend(true, upgradedModel, model);

            if (!upgradedModel["randomize"]) {
                upgradedModel["randomize"] = "False"
            }
            return upgradedModel;
        };

    presenter.setSpeechTexts = function(speechTexts) {
        presenter.speechTexts = {
            card: DEFAULT_TTS_PHRASES.card,
            outOf: DEFAULT_TTS_PHRASES.outOf,
            favourite: DEFAULT_TTS_PHRASES.favourite,
            audio: DEFAULT_TTS_PHRASES.audio,
            correct: DEFAULT_TTS_PHRASES.correct,
            wrong: DEFAULT_TTS_PHRASES.wrong,
            reset: DEFAULT_TTS_PHRASES.reset,
            selected: DEFAULT_TTS_PHRASES.selected,
            deselected: DEFAULT_TTS_PHRASES.deselected,
            cardHasBeenReset: DEFAULT_TTS_PHRASES.cardHasBeenReset,
            turned: DEFAULT_TTS_PHRASES.turned
        };

        if (!speechTexts || $.isEmptyObject(speechTexts)) {
            return;
        }
        presenter.speechTexts = {
            card: window.TTSUtils.getSpeechTextProperty(
                speechTexts.card.card,
                presenter.speechTexts.card),
            outOf: window.TTSUtils.getSpeechTextProperty(
                speechTexts.outOf.outOf,
                presenter.speechTexts.outOf),
            favourite: window.TTSUtils.getSpeechTextProperty(
                speechTexts.favourite.favourite,
                presenter.speechTexts.favourite),
            audio: window.TTSUtils.getSpeechTextProperty(
                speechTexts.audio.audio,
                presenter.speechTexts.audio),
            correct: window.TTSUtils.getSpeechTextProperty(
                speechTexts.correct.correct,
                presenter.speechTexts.correct),
            wrong: window.TTSUtils.getSpeechTextProperty(
                speechTexts.wrong.wrong,
                presenter.speechTexts.wrong),
            reset: window.TTSUtils.getSpeechTextProperty(
                speechTexts.reset.reset,
                presenter.speechTexts.reset),
            selected: window.TTSUtils.getSpeechTextProperty(
                speechTexts.selected.selected,
                presenter.speechTexts.selected),
            deselected: window.TTSUtils.getSpeechTextProperty(
                speechTexts.deselected.deselected,
                presenter.speechTexts.deselected),
            cardHasBeenReset: window.TTSUtils.getSpeechTextProperty(
                speechTexts.cardHasBeenReset.cardHasBeenReset,
                presenter.speechTexts.cardHasBeenReset),
            turned: window.TTSUtils.getSpeechTextProperty(
                speechTexts.turned.turned,
                presenter.speechTexts.turned),
        };
    };

    presenter.init = function (view, model, isPreview) {
        model = presenter.upgradeModel(model);
        var validatedModel = presenter.validateModel(model);
        presenter.configuration = validatedModel;
        presenter.isErrorMode = false;
        presenter.isPreview = isPreview;
        presenter.Cards = model.Cards;
        presenter.generateCardMap();
        presenter.state.isVisible = presenter.configuration.isVisible;
        presenter.state.noLoop = presenter.configuration.noLoop;
        presenter.state.cardsScore = presenter.configuration.cardsScore;
        presenter.state.cardsFavourites = presenter.configuration.cardsFavourites;

        presenter.view = view;
        presenter.$view = $(view);
        presenter.flashcardsMain = $(presenter.$view.find(".flashcards-card").get(0));
        presenter.flashcardsPrev = presenter.$view.find(".flashcards-prev");
        presenter.flashcardsNext = presenter.$view.find(".flashcards-next");
        presenter.flashcardsButtonFavourite = presenter.$view.find(".flashcards-button-favourite");
        presenter.flashcardsButtonWrong = presenter.$view.find(".flashcards-button-wrong");
        presenter.flashcardsButtonCorrect = presenter.$view.find(".flashcards-button-correct");
        presenter.flashcardsButtonReset = presenter.$view.find(".flashcards-button-reset");
        presenter.flashcardsButton = presenter.$view.find(".flashcards-button");
        presenter.flashcardsCardAudioButtonFront = presenter.$view.find(".flashcards-card-audio-button-front");
        presenter.flashcardsCardAudioButtonBack = presenter.$view.find(".flashcards-card-audio-button-back");
        presenter.audioElementBack =  presenter.$view.find(".flashcards-card-audio-back").get(0);
        presenter.audioElementFront =  presenter.$view.find(".flashcards-card-audio-front").get(0);
        presenter.audioElementHidden =  presenter.$view.find(".flashcards-card-audio-hidden").get(0);
        
        presenter.model = model;
        presenter.$card = $(presenter.$view.find(".flashcards-card").get(0));

        $(presenter.Cards).each(function (key) {
            presenter.state.cardsScore[key] = 0;
            presenter.state.cardsFavourites[key] = false;
        });

        presenter.state.totalCards = presenter.Cards.length;

        if (presenter.configuration.HidePrevNext) {
            $(presenter.flashcardsPrev.get(0)).hide();
            $(presenter.flashcardsNext.get(0)).hide();
        }
        if (!presenter.configuration.ShowButtons) {
            $(presenter.$view.find(".flashcards-buttons").get(0)).hide();
        }
        if (presenter.configuration.Favourites == false) {
            $(presenter.flashcardsButtonFavourite.get(0)).hide();
        }        

        presenter.showCard(1);
        setTimeout(()=&gt; {
            presenter.addClickHandlers();
        }, 0);

        //audio
        presenter.isFrontPlaying = false;
        presenter.isBackPlaying = false;
        presenter.isHiddenPlaying = false;
        if (!presenter.isPreview) {
            presenter.addAudioEventHandlers();
            MutationObserverService.createDestroyObserver(presenter.configuration.addonID, presenter.destroy, presenter.view);
            MutationObserverService.setObserver();
        }

        presenter.isLoaded = true;
    };

    presenter.generateCardMap = function() {
        presenter.cardMap = [];
        for (var i = 0; i &lt; presenter.Cards.length; i++) presenter.cardMap.push(i);
        if (presenter.configuration.randomizeOrder) {
            for (var i = presenter.cardMap.length - 1; i &gt; 0; i--) {
                var j = Math.floor(Math.random() * (i + 1));
                var tmp = presenter.cardMap[i];
                presenter.cardMap[i] = presenter.cardMap[j];
                presenter.cardMap[j] = tmp;
            }
        }
    };

    presenter.getCard = function(index) {
        return presenter.Cards[presenter.cardMap[index]];
    }

    presenter.countFavourites = function () {
        var i = 0;
        $(presenter.Cards).each(function (k,v) {
            if (presenter.state.cardsFavourites[k] == true){i++};
        });
        return i;
    };

    presenter.countNonFavouritesBefore = function (k) {
        var i = 0;
        for(j = 0; j &lt; k; j++){
            if (presenter.state.cardsFavourites[presenter.cardMap[j]] == false){i++};
        }
        return i;
    };

    presenter.addClickHandlers = function () {
        //FLIP, PREV &amp; NEXT
        $(presenter.$view.find(".flashcards-card-contents")).click(function (e) {
            if (presenter.isErrorMode) return;
            e.preventDefault();
            presenter.revertCard();
        });
        $(presenter.flashcardsPrev).click(function (e) {
            if (presenter.isErrorMode) return;
            e.preventDefault();
            presenter.prevCard();
        });
        $(presenter.flashcardsNext).click(function (e) {
            if (presenter.isErrorMode) return;
            e.preventDefault();
            presenter.nextCard();
        });

        //SCORE BUTTONS
        $(presenter.flashcardsButtonWrong).click(function () {
            if (presenter.isErrorMode) return;
            presenter.state.cardsScore[presenter.cardMap[presenter.state.currentCard-1]+1] = -1;
            $(presenter.flashcardsButton).removeClass("flashcards-button-selected");
            $(this).addClass("flashcards-button-selected");
        });
        $(presenter.flashcardsButtonCorrect).click(function () {
            if (presenter.isErrorMode) return;
            presenter.state.cardsScore[presenter.cardMap[presenter.state.currentCard-1]+1] = 1;
            $(presenter.flashcardsButton).removeClass("flashcards-button-selected");
            $(this).addClass("flashcards-button-selected");
        });
        $(presenter.flashcardsButtonReset).click(function () {
            if (presenter.isErrorMode) return;
            presenter.state.cardsScore[presenter.cardMap[presenter.state.currentCard-1]+1] = 0;
            $(presenter.flashcardsButton).removeClass("flashcards-button-selected");
        });

        //FAVOURITE BUTTON
        $(presenter.flashcardsButtonFavourite).click(function () {
            if (presenter.isErrorMode) return;
            if (presenter.state.cardsFavourites[presenter.cardMap[presenter.state.currentCard - 1]] == false){
                presenter.state.cardsFavourites[presenter.cardMap[presenter.state.currentCard - 1]] = true;
                $(this).addClass("flashcards-button-selected");
                presenter.triggerEvent(presenter.state.currentCard,"favourite","");
            }else{
                presenter.state.cardsFavourites[presenter.cardMap[presenter.state.currentCard - 1]] = false;
                $(this).removeClass("flashcards-button-selected");
                presenter.triggerEvent(presenter.state.currentCard,"unfavourite","");
            }            
        });

        //AUDIO
        $(presenter.flashcardsCardAudioButtonFront).click(function () {
            if (presenter.isErrorMode) return;
            
            if (presenter.isFrontPlaying == false) {
                presenter.isFrontPlaying = true;
                presenter.resetHiddenAudio();
                presenter.audioElementFront.play();
                $(presenter.flashcardsCardAudioButtonFront).addClass("playing");
                $(presenter.flashcardsCardAudioButtonFront).removeClass("paused");
                presenter.sendPlayEvent();
            }else{
                presenter.isFrontPlaying = false;
                presenter.audioElementFront.pause();
                $(presenter.flashcardsCardAudioButtonFront).removeClass("playing");
                $(presenter.flashcardsCardAudioButtonFront).addClass("paused");
                presenter.sendPauseEvent();
            }
        });
        $(presenter.flashcardsCardAudioButtonBack).click(function () {
            if (presenter.isErrorMode) return;
            presenter.audioElementBack =  presenter.$view.find(".flashcards-card-audio-back").get(0);
            if (presenter.isBackPlaying == false) {
                presenter.isBackPlaying = true;
                presenter.resetHiddenAudio();
                presenter.audioElementBack.play();
                $(presenter.flashcardsCardAudioButtonBack).addClass("playing");
                $(presenter.flashcardsCardAudioButtonBack).removeClass("paused");
                presenter.sendPlayEvent();
            }else{
                presenter.isBackPlaying = false;
                presenter.audioElementBack.pause();
                $(presenter.flashcardsCardAudioButtonBack).removeClass("playing");
                $(presenter.flashcardsCardAudioButtonBack).addClass("paused");
                presenter.sendPauseEvent();
            }
        });  
    };

     presenter.addAudioEventHandlers = function () {
         presenter.audioElementFront.onended = function () {
             $(presenter.flashcardsCardAudioButtonFront).removeClass("playing");
             $(presenter.flashcardsCardAudioButtonFront).removeClass("paused");
             presenter.isFrontPlaying = false;
             presenter.sendEndedEvent();
         };

         presenter.audioElementBack.onended = function () {
             $(presenter.flashcardsCardAudioButtonBack).removeClass("playing");
             $(presenter.flashcardsCardAudioButtonBack).removeClass("paused");
             presenter.isBackPlaying = false;
             presenter.sendEndedEvent();
         };

        presenter.audioElementHidden.onended = function () {
            presenter.isHiddenPlaying = false;
            presenter.sendEndedEvent(presenter.lastHiddenAudio.cardIndex + 1);
        };
     };
    
    presenter.run = function (view, model) {
        presenter.init(view, model, false);
    };
    
    presenter.createPreview = function (view, model) {
        presenter.init(view, model, true);
    };

    presenter.revertCard = function () {
        if (presenter.isFrontPlaying || presenter.isBackPlaying) {
            presenter.sendPauseEvent();
            if (presenter.isFrontPlaying) {
                $(presenter.flashcardsCardAudioButtonFront).addClass("paused");
            } else {
                $(presenter.flashcardsCardAudioButtonBack).addClass("paused");
            }
        }
        presenter.isFrontPlaying = false;
        presenter.audioElementFront.pause();
        $(presenter.flashcardsCardAudioButtonFront).removeClass("playing");

        presenter.isBackPlaying = false;
        presenter.audioElementBack.pause();
        $(presenter.flashcardsCardAudioButtonBack).removeClass("playing");

        presenter.$card.find(".flashcards-card-back .flashcards-card-contents").css("visibility","visible");
        var $cardElement = $(presenter.$view.find(".flashcards-card").get(0));
        $cardElement.toggleClass("flashcards-card-reversed");
        if ($cardElement.is(".flashcards-card-reversed")) {
            presenter.sendCardReversedEvent(presenter.state.currentCard, true);
        } else {
            presenter.sendCardReversedEvent(presenter.state.currentCard, false);
        }

    };

    presenter.isFrontVisible = function() {
        return !$(presenter.$view.find(".flashcards-card").get(0)).hasClass("flashcards-card-reversed");
    }

    presenter.originalCard = 1;
    presenter.prevCard = function () {
        if ((presenter.isFrontPlaying || presenter.isBackPlaying) &amp;&amp; presenter.state.currentCard &gt; 1) {
            presenter.sendEndedEvent(presenter.originalCard);
        }
        presenter.removeActiveElementClass();
        if (presenter.state.currentCard&gt;1){
            presenter.state.currentCard -= 1;
        }else if (presenter.state.noLoop == false){
            presenter.state.currentCard = presenter.state.totalCards;
        }
        presenter.showCard(presenter.state.currentCard, true);
    };

    presenter.nextCard = function (disregardNoLoop) {
        presenter.removeActiveElementClass();
        if (presenter.state.currentCard &lt; presenter.state.totalCards){
            presenter.state.currentCard += 1;
        }else if (presenter.state.noLoop == false || disregardNoLoop){
            presenter.state.currentCard = 1;
        }
        if ((presenter.isFrontPlaying || presenter.isBackPlaying) &amp;&amp; presenter.state.currentCard != presenter.originalCard) {
            presenter.sendEndedEvent(presenter.originalCard);
        }
        presenter.showCard(presenter.state.currentCard, true);
    };

    presenter.showCard = function (cardNumber, sendEvent) {
        if (sendEvent == undefined) sendEvent = false;
        presenter.originalCard = presenter.state.currentCard;
        cardNumber = parseInt(cardNumber,10);
        if (presenter.state.ShowOnlyFavourites == true &amp;&amp; presenter.countFavourites() &gt; 0 ){
            if (presenter.state.cardsFavourites[presenter.cardMap[presenter.state.currentCard - 1]] == true){
                presenter.displayCard(cardNumber, sendEvent);
            }else{
                if (cardNumber &lt;= presenter.state.totalCards){
                    presenter.nextCard(true);
                }
            }
        }else{
            presenter.displayCard(cardNumber, sendEvent);
        }        
    };

    presenter.displayCard = function (cardNumber, sendEvent) {
        if (presenter.state.noLoop){
            $(presenter.flashcardsPrev.get(0)).attr("disabled", false);
            $(presenter.flashcardsNext.get(0)).attr("disabled", false);
            if (cardNumber == 1){
                $(presenter.flashcardsPrev.get(0)).attr("disabled", true);
            }else if (cardNumber == presenter.state.totalCards){
                $(presenter.flashcardsNext.get(0)).attr("disabled", true);
            }
        }

        var currentCardNumber = cardNumber;
        var totalCardsNuber = 0;
        if (presenter.state.ShowOnlyFavourites == true) {
            currentCardNumber = cardNumber - presenter.countNonFavouritesBefore(cardNumber);
            totalCardsNuber = presenter.countFavourites();
        }else{
            totalCardsNuber = presenter.state.totalCards;
        }
        presenter.$view.find(".flashcards-panel").get(0).innerHTML = currentCardNumber + "/" + totalCardsNuber;
        presenter.$card.find(".flashcards-card-back .flashcards-card-contents").css('visibility', 'hidden');
        presenter.$card.removeClass("flashcards-card-reversed");

        presenter.$view.find(".flashcards-card-contents-front").get(0).innerHTML = parseAltText(presenter.getCard(cardNumber - 1).Front);
        presenter.$view.find(".flashcards-card-contents-back").get(0).innerHTML = parseAltText(presenter.getCard(cardNumber - 1).Back);

        //SCORE BUTTONS
        $(presenter.flashcardsButton).removeClass("flashcards-button-selected");
        if (presenter.state.cardsScore[presenter.cardMap[presenter.state.currentCard-1]+1] == 1){
            $(presenter.flashcardsButtonCorrect).addClass("flashcards-button-selected");
        }
        if (presenter.state.cardsScore[presenter.cardMap[presenter.state.currentCard-1]+1] == -1){
            $(presenter.flashcardsButtonWrong).addClass("flashcards-button-selected");
        }

        //FAV BUTTON
        if (presenter.state.cardsFavourites[presenter.cardMap[presenter.state.currentCard - 1]] == true) {
            $(presenter.flashcardsButtonFavourite).addClass("flashcards-button-selected");
        }else{
            $(presenter.flashcardsButtonFavourite).removeClass("flashcards-button-selected");
        }

        //AUDIO - front
        presenter.isFrontPlaying = false;
        $(presenter.flashcardsCardAudioButtonFront).removeClass("playing");
        $(presenter.flashcardsCardAudioButtonFront).addClass("disabled");
        if (presenter.getCard(presenter.state.currentCard - 1).AudioFront != ""){
            $(presenter.$view.find(".flashcards-card-audio-wrapper-front")).show();
            if (presenter.audioElementFront.canPlayType("audio/mpeg")) {
                presenter.audioElementFront.setAttribute("src",presenter.getCard(presenter.state.currentCard - 1).AudioFront);
                presenter.audioElementFront.oncanplay = function () {
                    $(presenter.flashcardsCardAudioButtonFront).removeClass("disabled");
                };
            } 
        }else{
            presenter.audioElementFront.setAttribute("src","");
            $(presenter.$view.find(".flashcards-card-audio-wrapper-front")).hide();
        }
        //AUDIO - back
        presenter.isBackPlaying = false;
        $(presenter.flashcardsCardAudioButtonBack).removeClass("playing");
        $(presenter.flashcardsCardAudioButtonBack).addClass("disabled");
        if (presenter.getCard(presenter.state.currentCard - 1).AudioBack != ""){
            $(presenter.$view.find(".flashcards-card-audio-wrapper-back")).show();
            if (presenter.audioElementBack.canPlayType("audio/mpeg")) {
                presenter.audioElementBack.setAttribute("src",presenter.getCard(presenter.state.currentCard - 1).AudioBack);
                presenter.audioElementBack.oncanplay = function () {
                    $(presenter.flashcardsCardAudioButtonBack).removeClass("disabled");
                };
            } 
        }else{
            presenter.audioElementBack.setAttribute("src","");
            $(presenter.$view.find(".flashcards-card-audio-wrapper-back")).hide();
        }
        presenter.renderMathJax();
        if (sendEvent) {
            presenter.sendCardChangedEvent(cardNumber);
        }
    };

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

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

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

    presenter.updateVisibility = function () {
        (presenter.state.isVisible) ? presenter.show() : presenter.hide();
    };

    presenter.setShowErrorsMode = function () {
        presenter.isErrorMode = true;
    }; 

    presenter.setWorkMode = function () {
        presenter.isErrorMode = false;
    };

    presenter.onEventReceived = function (eventName) {
        if (eventName == "ShowAnswers") {
            presenter.showAnswers();
        }

        if (eventName == "HideAnswers") {
            presenter.hideAnswers();
        }
    };

    presenter.showAnswers = function () {
        presenter.isErrorMode = true;
    };

    presenter.hideAnswers = function () {
        presenter.isErrorMode = false;
    };

    presenter.ShowOnlyFavourites = function () {presenter.showOnlyFavourites();};

    presenter.showOnlyFavourites = function () {
        if (presenter.countFavourites() &gt; 0) {
            presenter.state.ShowOnlyFavourites = true;
            presenter.showCard(presenter.state.currentCard);
        }
    };

    presenter.ShowAllCards = function () {presenter.showAllCards();};

    presenter.showAllCards = function () {
        presenter.state.ShowOnlyFavourites = false;
        presenter.showCard(presenter.state.currentCard);
    };

    presenter.resetFavourites = function () {
        presenter.state.ShowOnlyFavourites = false;
        $(presenter.Cards).each(function (key) {
            presenter.state.cardsFavourites[key] = false;
        });
        $(presenter.flashcardsButtonFavourite).removeClass("flashcards-button-selected");
    };
    
    presenter.reset = function () {
        presenter.isErrorMode = false;
        presenter.state.ShowOnlyFavourites = false;
        presenter.state.currentCard = presenter.configuration.currentCard;

        presenter.state.isVisible = presenter.configuration.isVisible;
        presenter.updateVisibility();

        $(presenter.model.Cards).each(function (key) {
            presenter.state.cardsScore[key] = 0;
            presenter.state.cardsFavourites[key] = false;
        });

        presenter.showCard(presenter.state.currentCard);
    };
    
    presenter.getErrorCount = function () {
        var errors = null;
        if (presenter.configuration.IsActivity) {
            errors = 0;
            $(presenter.state.cardsScore).each(function (key) {
                if (presenter.state.cardsScore[key] == -1){
                    errors++;
                }
            });
        }
        return errors;
    };
    
    presenter.getMaxScore = function () {
        var maxScore = null;
        if (presenter.configuration.IsActivity) {
            maxScore = presenter.state.totalCards;
        }
        return maxScore;
    };
    
    presenter.getScore = function () {
        var score = null;
        if (presenter.configuration.IsActivity) {
            score = 0;
            $(presenter.state.cardsScore).each(function (key) {
                if (presenter.state.cardsScore[key] == 1){
                    score++;
                }
            });
        }
        return score;
    };

    presenter.executeCommand = function (name, params) {
        var commands = {
            'show': presenter.show,
            'hide': presenter.hide,
            'nextCard': presenter.nextCard,
            'prevCard': presenter.prevCard,
            'reset': presenter.reset,
            'resetFavourites': presenter.resetFavourites,
            'ShowOnlyFavourites': presenter.showOnlyFavourites,
            'showOnlyFavourites': presenter.showOnlyFavourites,
            'ShowAllCards': presenter.showAllCards,
            'showAllCards': presenter.showAllCards,
            'countFavourites': presenter.countFavourites,
            'play': presenter.play,
            'pause': presenter.pause,
            'stop': presenter.stop
        };
        Commands.dispatch(commands, name, params, presenter);
    };
    
    presenter.getState = function () {
        return JSON.stringify({
            state: presenter.state
        });
    };

    presenter.setState = function (stateString) {
        if (ModelValidationUtils.isStringEmpty(stateString)) return;
        var parsedState = JSON.parse(stateString);
        presenter.state = parsedState.state;

        presenter.updateVisibility();
        if (presenter.configuration.randomizeOrder) {
            presenter.state.currentCard = 1;
        }
        presenter.showCard(presenter.state.currentCard);
    };

    presenter.destroy = function () {
        $(presenter.$view.find(".flashcards-card-contents")).unbind();
        $(presenter.flashcardsButtonWrong).unbind();
        $(presenter.flashcardsButtonCorrect).unbind();
        $(presenter.flashcardsButtonReset).unbind();
        $(presenter.flashcardsButtonFavourite).unbind();
        $(presenter.flashcardsButtonFavourite).unbind();
        $(presenter.flashcardsNext).unbind();
        
    };

    presenter.playHiddenCardAudio = function (cardIndex, reverse) {
        if (typeof reverse == 'string') {
            reverse = reverse.toLowerCase() == 'reverse' || reverse.toLowerCase() == 'true';
        }
        reverse = !!reverse;
        var card = presenter.Cards[cardIndex];
        if (!card) return;
        if (presenter.isFrontPlaying) {
            presenter.audioElementFront.pause();
            presenter.audioElementFront.currentTime = 0;
            presenter.isFrontPlaying = false;
            presenter.sendEndedEvent();
        }
        if (presenter.isBackPlaying) {
            presenter.audioElementBack.pause();
            presenter.audioElementBack.currentTime = 0;
            presenter.isBackPlaying = false;
            presenter.sendEndedEvent();
        }
        if ((!reverse &amp;&amp; card.AudioFront != "") || (reverse &amp;&amp; card.AudioBack != "")){
            if (presenter.audioElementHidden.canPlayType("audio/mpeg")) {
                var audioSrc = reverse ? card.AudioBack : card.AudioFront;
                if (presenter.lastHiddenAudio.cardIndex != cardIndex || presenter.lastHiddenAudio.reverse != reverse) {
                    presenter.lastHiddenAudio.cardIndex = cardIndex;
                    presenter.lastHiddenAudio.reverse = reverse;
                    presenter.audioElementHidden.setAttribute("src", audioSrc);
                    presenter.audioElementHidden.oncanplay = function () {
                        presenter.audioElementHidden.play();
                        presenter.sendPlayEvent(cardIndex + 1);
                        presenter.isHiddenPlaying = true;
                        presenter.audioElementHidden.oncanplay = null;
                    };
                } else if (!presenter.isHiddenPlaying) {
                    presenter.audioElementHidden.play();
                    presenter.sendPlayEvent(cardIndex + 1);
                    presenter.isHiddenPlaying = true;
                }
            }
        }
    }

    presenter.resetHiddenAudio = function() {
        if (presenter.isHiddenPlaying) {
            presenter.isHiddenPlaying = false;
            presenter.audioElementHidden.pause();
            presenter.sendEndedEvent(presenter.lastHiddenAudio.cardIndex + 1);
        }
        presenter.audioElementHidden.currentTime = 0;
    }

    presenter.sendEvent = function(eventName, cardNumber) {
        var item = presenter.state.currentCard;
        if (cardNumber !== undefined) item = cardNumber;
        item = presenter.cardMap[item - 1] + 1;
        var eventData = {
            'source': presenter.configuration.addonID,
            'item': item,
            'value': eventName,
            'score': ''
        };

        presenter.eventBus.sendEvent('ValueChanged', eventData);
    };

    presenter.sendPlayEvent = function(cardNumber) {
        if (presenter.configuration.sendEventOnCardChanged) { return; }
        presenter.sendEvent("playing", cardNumber);};

    presenter.sendPauseEvent = function(cardNumber) {
        if (presenter.configuration.sendEventOnCardChanged) { return; }
        presenter.sendEvent("pause", cardNumber);};

    presenter.sendEndedEvent = function(cardNumber) {
        if (presenter.configuration.sendEventOnCardChanged) { return; }
        presenter.sendEvent("ended", cardNumber);
    };

    presenter.sendCardChangedEvent = function(cardNumber) {presenter.sendEvent("", cardNumber);};

    presenter.sendCardReversedEvent = function(cardNumber, isReversed) {
        if (presenter.configuration.sendEventOnCardChanged) { return; }
        var eventValue = isReversed ? "back" : "front";
        presenter.sendEvent(eventValue, cardNumber);
    };

    presenter.play = function(cardIndex = -1, reverse = false) {
        if (Array.isArray(cardIndex)) {
            if (cardIndex.length &gt; 0) {
                if (cardIndex.length &gt; 1) reverse = cardIndex[1];
                cardIndex = cardIndex[0];
            } else {
                cardIndex = -1;
            }
        }
        if (cardIndex != -1) {
            presenter.playHiddenCardAudio(cardIndex - 1, reverse);
        } else {
            presenter.audioCommand("play");
        }
    };

    presenter.pause = function() {
        presenter.audioCommand("pause");
    };

    presenter.stop = function() {
        presenter.audioCommand("stop");
    };

    presenter.audioCommand = function(command) {
        if (presenter.isErrorMode) return;
        if (presenter.isHiddenPlaying &amp;&amp; command != "play") {
            if (command == "stop" &amp;&amp; presenter.audioElementHidden.currentTime &gt; 0) {
                presenter.audioElementHidden.currentTime = 0;
                presenter.sendEndedEvent(presenter.lastHiddenAudio.cardIndex + 1);
            }
            presenter.audioElementHidden.pause();
            if (command == "pause") {
                presenter.sendPauseEvent(presenter.lastHiddenAudio.cardIndex + 1);
            }
            presenter.isHiddenPlaying = false;
            return;
        }

        var currentCard = presenter.getCard(presenter.state.currentCard - 1);
        if (presenter.isFrontVisible()) {
            if (currentCard.AudioFront != "") {
                if (command == "play") {
                    if (presenter.isFrontPlaying) return;
                    presenter.isFrontPlaying = true;
                    presenter.resetHiddenAudio();
                    presenter.audioElementFront.play();
                    $(presenter.flashcardsCardAudioButtonFront).addClass("playing");
                    $(presenter.flashcardsCardAudioButtonFront).removeClass("paused");
                    presenter.sendPlayEvent();
                }else{
                    if (command == "stop" &amp;&amp; presenter.audioElementFront.currentTime &gt; 0) {
                        presenter.audioElementFront.currentTime = 0;
                        presenter.sendEndedEvent();
                        $(presenter.flashcardsCardAudioButtonFront).removeClass("paused");
                    }
                    if (!presenter.isFrontPlaying) return;
                    presenter.isFrontPlaying = false;
                    presenter.audioElementFront.pause();
                    $(presenter.flashcardsCardAudioButtonFront).removeClass("playing");
                    if (command == "pause") {
                        $(presenter.flashcardsCardAudioButtonFront).addClass("paused");
                        presenter.sendPauseEvent();
                    }
                }
            }
        } else {
            if (currentCard.AudioBack != "") {
                presenter.audioElementBack =  presenter.$view.find(".flashcards-card-audio-back").get(0);
                if (command == "play") {
                    if (presenter.isBackPlaying == true) return;
                    presenter.isBackPlaying = true;
                    presenter.resetHiddenAudio();
                    presenter.audioElementBack.play();
                    $(presenter.flashcardsCardAudioButtonBack).addClass("playing");
                    $(presenter.flashcardsCardAudioButtonBack).removeClass("paused");
                    presenter.sendPlayEvent();
                }else{
                    if (command == "stop" &amp;&amp; presenter.audioElementBack.currentTime &gt; 0) {
                        presenter.audioElementBack.currentTime = 0;
                        presenter.sendEndedEvent();
                        $(presenter.flashcardsCardAudioButtonBack).removeClass("paused");
                    }
                    if (presenter.isBackPlaying == false) return;
                    presenter.isBackPlaying = false;
                    presenter.audioElementBack.pause();
                    $(presenter.flashcardsCardAudioButtonBack).removeClass("playing");
                    if (command == "pause") {
                        $(presenter.flashcardsCardAudioButtonBack).addClass("paused");
                        presenter.sendPauseEvent();
                    }
                }
            }
        }
    }

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

    presenter.removeActiveElementClass = function() {
        presenter.$view.find("."+KEYBOARD_NAVIGATION_ACTIVE_ITEM_CLASS).removeClass(KEYBOARD_NAVIGATION_ACTIVE_ITEM_CLASS);
    }

    presenter.nextKeyboardElement = function() {
        cycleKeyboardElement(true);
    }

    presenter.prevKeyboardElement = function() {
        cycleKeyboardElement(false);
    }

    function cycleKeyboardElement(forward) {
        let elementList = [presenter.flashcardsMain, presenter.flashcardsButtonFavourite];
        let currentElementIndex = 0;
        if (presenter.flashcardsMain.is('.flashcards-card-reversed')) {
            elementList.push(presenter.flashcardsCardAudioButtonBack);
            elementList.push(presenter.flashcardsButtonWrong);
            elementList.push(presenter.flashcardsButtonReset);
            elementList.push(presenter.flashcardsButtonCorrect);
        } else {
            elementList.push(presenter.flashcardsCardAudioButtonFront);
        }

        elementList = elementList.filter( function($el) {
            return $el != null &amp;&amp; $el.length &gt; 0 &amp;&amp; $el.is(":visible");
        });

        for (let i = 0; i &lt; elementList.length; i++) {
            if (elementList[i].is("."+KEYBOARD_NAVIGATION_ACTIVE_ITEM_CLASS)) {
                currentElementIndex = i;
                break;
            }
        }

        presenter.removeActiveElementClass();
        if (forward) {
            currentElementIndex += 1;
            if (currentElementIndex &gt;= elementList.length) currentElementIndex = elementList.length - 1;
        } else {
            currentElementIndex -= 1;
            if (currentElementIndex &lt; 0) currentElementIndex = 0;
        }
        elementList[currentElementIndex].addClass(KEYBOARD_NAVIGATION_ACTIVE_ITEM_CLASS);

    }

    presenter.onSpace = function() {
        let currentElement = presenter.$view.find("."+KEYBOARD_NAVIGATION_ACTIVE_ITEM_CLASS);
        if (currentElement.length === 0 || currentElement.hasClass("flashcards-card")) {
            presenter.removeActiveElementClass();
            presenter.revertCard();
            speak([window.TTSUtils.getTextVoiceObject(presenter.speechTexts.turned)]);
        } else {
            currentElement.click();
            if (currentElement.hasClass('flashcards-button-reset')) {
                speak([window.TTSUtils.getTextVoiceObject(presenter.speechTexts.cardHasBeenReset)]);
            } else if (currentElement.hasClass('flashcards-button-correct')
                || currentElement.hasClass('flashcards-button-wrong')) {
                speak([window.TTSUtils.getTextVoiceObject(presenter.speechTexts.selected)]);
            } else if (currentElement.hasClass('flashcards-button-favourite')) {
                if (currentElement.hasClass('flashcards-button-selected')) {
                    speak([window.TTSUtils.getTextVoiceObject(presenter.speechTexts.selected)]);
                } else {
                    speak([window.TTSUtils.getTextVoiceObject(presenter.speechTexts.deselected)]);
                }
            }
        }
    }

    presenter.readSelected = function() {
        let textVoices = [];
        let currentElement = presenter.$view.find("."+KEYBOARD_NAVIGATION_ACTIVE_ITEM_CLASS);
        if (currentElement.length === 0 || currentElement.hasClass("flashcards-card")) {
            presenter.readCard();
        } else {
            if (currentElement.hasClass('flashcards-button-favourite')) {
                textVoices.push(window.TTSUtils.getTextVoiceObject(presenter.speechTexts.favourite));
            } else if (currentElement.hasClass('flashcards-card-audio-button')) {
                textVoices.push(window.TTSUtils.getTextVoiceObject(presenter.speechTexts.audio));
            } else if (currentElement.hasClass('flashcards-button-wrong')) {
                textVoices.push(window.TTSUtils.getTextVoiceObject(presenter.speechTexts.wrong));
            } else if (currentElement.hasClass('flashcards-button-correct')) {
                textVoices.push(window.TTSUtils.getTextVoiceObject(presenter.speechTexts.correct));
            } else if (currentElement.hasClass('flashcards-button-reset')) {
                textVoices.push(window.TTSUtils.getTextVoiceObject(presenter.speechTexts.reset));
            }
            if (currentElement.hasClass('flashcards-button-selected')) {
                textVoices.push(window.TTSUtils.getTextVoiceObject(presenter.speechTexts.selected));
            }
            speak(textVoices);
        }
    }

    presenter.readCard = function() {
        let $content = null;
        if (presenter.flashcardsMain.is('.flashcards-card-reversed')) {
            $content = presenter.flashcardsMain.find('.flashcards-card-contents-back');
        } else {
            $content = presenter.flashcardsMain.find('.flashcards-card-contents-front');
        }

        let textVoices = window.TTSUtils.getTextVoiceArrayFromElement($content, presenter.configuration.langTag);
        speak(textVoices);
    }

    presenter.readCardNumber = function() {
        let textVoices = [];
        textVoices.push(window.TTSUtils.getTextVoiceObject(presenter.speechTexts.card));
        textVoices.push(window.TTSUtils.getTextVoiceObject(presenter.state.currentCard + ''));
        textVoices.push(window.TTSUtils.getTextVoiceObject(presenter.speechTexts.outOf));
        textVoices.push(window.TTSUtils.getTextVoiceObject(presenter.state.totalCards + ''));
        speak(textVoices);
    }

    presenter.keyboardController = function(keycode, isShift, event) {
        event.preventDefault();
        switch (keycode) {
            case 9: // TAB
                if (isShift) {
                    presenter.prevKeyboardElement();
                } else {
                    presenter.nextKeyboardElement();
                }
                presenter.readSelected();
                break;
            case 13: //ENTER
                if (isShift) {
                    presenter.removeActiveElementClass();
                } else {
                    presenter.readSelected();
                }
                break;
            case 32: // SPACE
                presenter.onSpace();
                break;
            case 38: // UP
                presenter.prevCard();
                presenter.readCardNumber();
                break;
            case 40: // DOWN
                presenter.nextCard();
                presenter.readCardNumber();
                break;
            case 37: // LEFT
                presenter.prevCard();
                presenter.readCardNumber();
                break;
            case 39: // RIGHT
                presenter.nextCard();
                presenter.readCardNumber();
                break;
            case 27: // ESC
                presenter.removeActiveElementClass();
                break;
        }
    }

    presenter.getTextToSpeechOrNull = function (playerController) {
        if (playerController) {
            return playerController.getModule('Text_To_Speech1');
        }

        return null;
    };

    function speak(data) {
        var tts = presenter.getTextToSpeechOrNull(presenter.playerController);

        if (tts &amp;&amp; isWCAGOn) {
            tts.speak(data);
        }
    }

    presenter.renderMathJax = function () {
        if (presenter.isLoaded) {
            reloadMathJax();
        }
    }

    function reloadMathJax () {
        const args = [];
        args.push("Typeset", MathJax.Hub, presenter.$view[0]);
        MathJax.Hub.Queue(args);
    }

    function parseAltText(text) {
        return presenter.isPreview ? window.TTSUtils.parsePreviewAltText(text) : presenter.textParser.parseAltTexts(text);
    }

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