/* Minification failed. Returning unminified contents.
(7412,13-16): run-time error JS1300: Strict-mode does not allow assignment to undefined variables: pos
 */
(function () {
    'use strict';
    var app = angular.module('app', [
        'ngAnimate',
        'ngCookies',
        'ipCookie',
        'flow',
        'timer',//<timer>
        // Mark's modules for new timeline testing
        'battlesnake.schedule',
        'battlesnake.err'
        //for toaster support include the script from common/toaster.js, also add ref to css <link href="~/Content/toastrng/toaster.css" rel="stylesheet" /> and <div data-toaster-container></div> to layout
        //then just inject 'toaster'
        //,'toaster'
    ]);
        //.config(function ($compileProvider) {
        //$compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|tel):/);
        //})

    app.filter('reverse', function () {
        return function (items) {
            return items.slice().reverse();
        };
    });
})();
;
(function() {
    angular.module('app').factory('filterStabilize', [
            function() {
                var cache = {};
                var service = function(filterName, filterFn) {
                    var filter = function() {
                        var args = [];
                        for (var i = 0; i < arguments.length; ++i) {
                            args.push(arguments[i]);
                        }
                        var input = args[0];
                        if (!input) {
                            return input;
                        }
                        cache[filterName] = cache[filterName] || {};
                        var key = JSON.stringify(args);
                        var fromCache = cache[filterName][key];
                        if (fromCache) {
                            return fromCache;
                        }
                        args[0] = angular.copy(input);
                        var filtered = filterFn.apply(this, args) || args[0];
                        cache[filterName][key] = filtered;
                        return filtered;
                    };
                    return filter;
                };
                return service;
            }
        ]);
})();;
(function () {
    angular.module('app').filter('partition', ['filterStabilize',
    function (stabilize) {
      var filter = stabilize('partition', function (arr, size) {
          var newArr = [];
          for (var i = 0; i < arr.length; i += size) {
              newArr.push(arr.slice(i, i + size));
          }
          return newArr;
      });
      return filter;
  }
]);
})();;
(function () {
    'use strict';
    var fid = 'listingrelativeurls';
    angular.module('app').filter(fid, [relativeUrls]);
    function relativeUrls() {
        return function (absoluteUrl) {
            var pathBeginIndex = absoluteUrl.indexOf('/v/');
            if (pathBeginIndex < 8) {
                return absoluteUrl;
            }
            return window.location.protocol + "//" + window.location.host + absoluteUrl.substring(pathBeginIndex);
        };
    }
})();;
(function () {
    angular.module('app').filter('slice', function () {
        return function (arr, start, end) {
            if (arr == undefined) return [];
            return arr.slice(start, end);
        };
    });
})();;
(function () {
    angular.module('app').filter('moment', function () {
        return function (date, format) {
            var d = moment(date);
            console.log(d.format("DD.MM.YY"));
            return d.format("DD.MM.YY");
        };
    });
})();;
(function () {
    'use strict';
    var fid = 'substringtwo';
    angular.module('app').filter(fid, [substringoftwo]);
    function substringoftwo() {
        return function (str) {
            return str.substring(0, 2) + ":" + str.substring(2, 4) + ":" + str.substring(4, 6);
        };
    }
})();;
(function () {
    'use strict';
    var fid = 'listingtype';
    angular.module('app').filter(fid, [listingtype]);
    function listingtype() {
        return function (listItem) {
            var sortedList = [];
            if (listItem != undefined) {
                for (var i = 0; i < listItem.length; i++) {
                    if (listItem[i].Type != 1) {
                        sortedList.push(listItem[i]);
                    }
                }
            }
            return sortedList;
        };
    }
})();;
(function () {
    'use strict';
    var fid = 'onlyaudios';
    angular.module('app').filter(fid, [onlyaudios]);
    function onlyaudios() {
        return function (listItem) {
            var sortedList = [];
            if (listItem != undefined) {
                for (var i = 0; i < listItem.length; i++) {
                    if (listItem[i].Type == 16) {
                        sortedList.push(listItem[i]);
                    }
                }
            }
            return sortedList;
        };
    }
})();;
(function () {
    'use strict';
    var fid = 'datecompare';
    angular.module('app').filter(fid, [datecompare]);
    function datecompare() {
        return function (listItem) {
            var sortedList = [];
            if (listItem.length != 0) {
                for (var i = 0; i < listItem.length; i++) {
                    if (moment(listItem[i].Published)._d < new Date()) {
                        sortedList.push(listItem[i]);
                    }
                }
            }
            return sortedList;
        };
    }
})();;
(function () {
    'use strict';
    var fid = 'dateformat';
    angular.module('app').filter(fid, ['$filter', function ($filter) {
        return function (date, resource) {
            var now = moment().startOf('day');
            var comp = moment(date);
            if (comp.isBefore(now, "day")) {
            if (now.diff(comp, 'days') > 0) {
                return 0;
                        } else {
                return 1;
                        }
                    } else {
                        return 2;
                    }
            
        };
    }])
})();


// 0 - mitte eile ja mitte täna, kauge minevik
// 1 - eile
// 2 - täna;
(function () {
    'use strict';
    var fid = 'sentenceCut';
    angular.module('ng').filter(fid, ['$filter',  function ($filter) {
    return function (value, wordwise, max, tail) {
        if (!value) return '';

        max = parseInt(max, 10);
        if (!max) return value;
        if (value.length <= max) return value;

        value = value.substr(0, max);
        if (wordwise) {
            var lastspace = value.lastIndexOf(' ');
            if (lastspace != -1) {
                value = value.substr(0, lastspace);
            }
        }

        return value + (tail || ' …');
    };
    }])
})();
;
(function () {
    'use strict';
    var fid = 'itemswithmusic';
    angular.module('app').filter(fid, [itemswithmusicfilter]);
    function itemswithmusicfilter() {
        return function (playlists) {

            if (!playlists) return [];

            return playlists.filter(function(playlist) {
                return playlist && playlist.Musics && playlist.Musics.length > 0;
            });
        };
    }
})();;
(function () {
    'use strict';
    var controllerId = 'search3Ctrl';
    angular.module('app').controller(controllerId, ['$scope', '$attrs', 'search3Service', '$location', '$timeout', '$sce', '$q', search3Ctrl]);

    function search3Ctrl($scope, $attrs, search3Service, $location, $timeout, $sce, $q) {
        $scope.pt = 0;
        $scope.columns = 4;
        $scope.bscol = "span" + Math.floor(12 / $scope.columns);
        var langs = ['et', 'en-GB', 'ru'];
        var paginationStep = 10;
        $scope.strictF = function (exp, act) { return exp == act; }
        var culture = parseInt($attrs.culture);
        $scope.so = $scope.$eval($attrs.so);
        $scope.cripa = ($attrs.cripa.toLowerCase()) == "true";
        $scope.scm = ($attrs.scm.toLowerCase()) == "true";
        $scope.portaltype = parseInt($attrs.portaltype);
        $scope.lastQueryFromAll = false;
        var languagepack = $scope.$eval($attrs.languagepack);
        $scope.categorylinkdisplay = languagepack[culture]['linkdisplays'][$scope.portaltype];

        $scope.options = [
            { name: "10", value: 10 },
            { name: "25", value: 25 },
            { name: "50", value: 50 },
            { name: "200", value: 200 }
        ];

        $scope.radioPortals = [646, 668, 665, 666];
        $scope.portalNames = ["Raadio2", "Klassikaraadio", "Raadio4", "Vikerraadio"];
        $scope.portalName = "";
        $scope.rootid = parseInt($attrs.root);
        $scope.portalfillerid = $attrs.portalfillerid;
        $scope.portals = { all: [] };
        $scope.activeQuery = {};
        $scope.categories = {};
        $scope.filterOptions = {};
        $scope.showRadioQuickOptions = false;
        $scope.defaultPortalId = 0;

        $scope.trust = function (item) { return $sce.trustAsHtml(item); }
        $scope.activateTab = function (tabname) {
            $timeout(function () {
                angular.element('#' + tabname).tab('show');
            }, 0);
        }

        var contentLoadFunction = undefined;
        var programLoadFunction = undefined;
        var videoLoadFunction = undefined;

        $scope.nextPage = function (resultSet) {
            if (resultSet.paging.current >= resultSet.paging.sliceStop) {
                $scope.paginationNext(resultSet);
            }
            if (resultSet.paging.current < resultSet.paging.totalPages) {
                $scope.loadPage(resultSet, resultSet.paging.current + 1);
            }
        }
        $scope.prevPage = function (resultSet) {
            if (resultSet.paging.page == resultSet.paging.sliceStart) {
                $scope.paginationPrev(resultSet);
            }
            if (resultSet.paging.current > 1) {
                $scope.loadPage(resultSet, resultSet.paging.current - 1);
            }
        }
        if ($scope.radioPortals.indexOf($scope.rootid) == -1) {
            $scope.showRadioQuickOptions = false;
            $scope.defaultPortalId = 0;
        }
        else {
            $scope.showRadioQuickOptions = true;
            $scope.portalName = $scope.portalNames[$scope.radioPortals.indexOf($scope.rootid)];
            console.log($scope.rootid);
            $scope.defaultPortalId = $scope.rootid;
        }

        $scope.portaldefaults = {
            filteroption: 0,
            portalid: $scope.defaultPortalId
        };

        $scope.portalChangeHandler = function () {
            var portal = _.find($scope.portals.all, function (po) { return po.CategoryId == $scope.portals.selectedPortal; });
            $scope.activeQuery.portalid = portal.CategoryId || 0;
            $scope.pt = portal.PortalType || 0;
            search3Service.getDependantCategories($scope.activeQuery.portalid).then(setCategoriesDropDown).then(function () { $scope.filterOptions.all = $scope.so[$scope.pt]; });
        }

        $scope.categoryChangeHandler = function () { $scope.activeQuery.category = $scope.categories.selectedCategory; }

        $scope.sizeChangeHandler = function (resultSet) {
            if (resultSet.paging.totalPages > 0) {
                var prev = resultSet.paging.page * resultSet.paging.prevSize;
                resultSet.paging.prevSize = resultSet.paging.size;
                var newIndex = (prev / resultSet.paging.size) >> 0;
                resultSet.paging.page = newIndex;
                search3Service.setPageSizeForResultSet({ resultSetName: resultSet.name, size: resultSet.paging.size });
            }
            resultSet.load();
        }
        $scope.loadPage = function (resultSet, pageIndex) {
            resultSet.paging.page = (pageIndex - 1);
            resultSet.load();
            document.getElementById('search3').scrollIntoView();
        }

        $scope.paginationNext = function (resultSet) {
            var newSliceStop = Math.min((resultSet.paging.sliceStop + paginationStep), resultSet.paging.totalPages);
            if (newSliceStop != resultSet.paging.sliceStop && newSliceStop > resultSet.paging.sliceStop) {
                resultSet.paging.sliceStart += paginationStep;
                resultSet.paging.sliceStop = newSliceStop;
            }
        }

        $scope.paginationPrev = function (resultSet) {
            if (resultSet.paging.sliceStart - paginationStep >= 0) {
                resultSet.paging.sliceStart -= paginationStep;
                resultSet.paging.sliceStop = resultSet.paging.sliceStart + 10;
            }
        }

        $scope.next = function (resultSet) {
            if (resultSet.paging.current < resultSet.paging.totalPages) {
                resultSet.paging.page++;
                if (resultSet.paging.page == resultSet.paging.sliceStop) { $scope.paginationNext(resultSet); }
                resultSet.load();
            }
        }

        $scope.prev = function (resultSet) {
            if (resultSet.paging.current > 1) {
                resultSet.paging.page--;
                if (resultSet.paging.page < resultSet.paging.sliceStart) { $scope.paginationPrev(resultSet); }
                resultSet.load();
            }
        }

        function reset() {
            $scope.categoryLinkResults = { all: [], searching: false, items: getCategoryItems };
            $scope.contentResults = { name: "contentResults", load: contentLoadFunction, paging: { page: 0, size: search3Service.getPageSizeForResultSet({ resultSetName: "contentResults", defaultValue: 50 }), prevSize: 50, total: 0, totalPages: 0, sliceStart: 0, sliceStop: paginationStep }, all: [], searching: false };
            $scope.programResults = { name: "programResults", load: programLoadFunction, paging: { page: 0, size: search3Service.getPageSizeForResultSet({ resultSetName: "programResults", defaultValue: 50 }), prevSize: 50, total: 0, totalPages: 0, sliceStart: 0, sliceStop: paginationStep }, all: [], searching: false };
            $scope.videoResults = { name: "videoResults", load: videoLoadFunction, paging: { page: 0, size: search3Service.getPageSizeForResultSet({ resultSetName: "videoResults", defaultValue: 50 }), prevSize: 50, total: 0, totalPages: 0, sliceStart: 0, sliceStop: paginationStep }, all: [], searching: false };
        }

        $scope.doSearch = doSearch;
        $scope.filterOptionChangeHandler = filterOptionChangeHandler;

        init();

        function init() {
            $scope.activeQuery = search3Service.validateActiveQuery($location.search(), $scope.portaldefaults);
            contentLoadFunction = $scope.activeQuery.filteroption == 3 ? getMedia : getContents;
            programLoadFunction = $scope.activeQuery.filteroption == 5 ? getReviewAble : getPrograms;
            videoLoadFunction = getVideos;
            search3Service.getSearchableCategories($scope.portalfillerid).then(setPortalsDropDown).then(search3Service.getDependantCategories).then(setCategoriesDropDown).
                then(setOptions).then($scope.portalChangeHandler).finally(doSearch);
            $(".datepicker").datepicker($.extend({}, $.datepicker.regional[langs[culture]], { dateFormat: 'dd.mm.yy' }));
        }


        function setPortalsDropDown(data) {
            $scope.portals.all = data;
            var portalExists = _.find($scope.portals.all, function (p) { return p.CategoryId == $scope.activeQuery.portalid; });
            $scope.pt = portalExists.PortalType || 0;
            $scope.portals.selectedPortal = portalExists ? $scope.activeQuery.portalid : $scope.rootid;
            $scope.activeQuery.portalid = $scope.portals.selectedPortal;
            return $scope.activeQuery.portalid;
        }

        function filterOptionChangeHandler() {
            $scope.activeQuery.filteroption = $scope.filterOptions.selectedOption;
            contentLoadFunction = $scope.activeQuery.filteroption == 3 ? getMedia : getContents;
            programLoadFunction = $scope.activeQuery.filteroption == 5 ? getReviewAble : getPrograms;
        }

        function doSearch() {
            $scope.activeQuery.portalid = $scope.portals.selectedPortal;
            $location.search($scope.activeQuery);
            $scope.lastQueryFromAll = $scope.activeQuery.portalid == 0;
            reset();
            switch ($scope.activeQuery.filteroption) {
                case 1:
                    getCategories();
                    break;
                case 2:
                    getContents();
                    break;
                case 3:
                    getMedia();
                    break;
                case 4:
                    if ($scope.cripa) {
                        getPrograms().then(getCategories);
                    } else {
                        getPrograms();
                    }
                    break;
                case 5:
                    getReviewAble();
                    break;
                case 6:
                    getVideos();
                    break;
                default:
                    getPrograms();
                    getCategories();
                    getContents();
                    getVideos();
            }
        }
        function getVideos() {
            $scope.videoResults.paging.searching = true;
            search3Service.getVideos(getCopy($scope.videoResults)).then(setVideos);
        }
        function getCategories() {
            search3Service.getPortalType($scope.activeQuery.portalid).then(setLinkResultsDisplay);
            search3Service.getCategoryLinks($scope.activeQuery).then(setCategoryLinks);
        }
        function getMedia() {
            $scope.contentResults.paging.searching = true;
            search3Service.getMedia(getCopy($scope.contentResults)).then(setContents);
        }
        function getContents() {
            $scope.contentResults.paging.searching = true;
            var deep = getCopy($scope.contentResults);
            search3Service.getContents(deep).then(setContents);
        }
        function getPrograms() {
            var def = $q.defer();
            $scope.programResults.paging.searching = true;
            search3Service.getPrograms(getCopy($scope.programResults)).then(setPrograms).then(function () { def.resolve(); });
            return def.promise;
        }
        function getReviewAble() {
            $scope.programResults.paging.searching = true;
            var deep = getCopy($scope.programResults);
            deep.onlyreviewable = true;
            search3Service.getReViewable(deep).then(setPrograms);
        }
        function setLinkResultsDisplay(data) {
            $scope.categorylinkdisplay = $.inArray($scope.portals.selectedPortal, $scope.radioPortals) == 1 ? languagepack[culture]['linkdisplays'][2] : languagepack[culture]['linkdisplays'][data];
        }
        function getCopy(resultSet) {
            var deep = { size: resultSet.paging.size, page: resultSet.paging.page };
            return angular.extend(deep, $scope.activeQuery);
        }

        function genericSetter(data, resultSet) {
            resultSet.paging.total = data.TotalCount;
            resultSet.all = data.Results;
            resultSet.paging.totalPages = Math.ceil(resultSet.paging.total / resultSet.paging.size);
            var arr = [];
            for (var j = 1; j <= resultSet.paging.totalPages; j++) { arr.push(j); }
            resultSet.paging.allPages = arr;
            resultSet.paging.current = resultSet.paging.totalPages > 0 ? (resultSet.paging.page + 1) : 0;
        }

        function setContents(data) {
            genericSetter(data, $scope.contentResults);
            _($scope.contentResults.all).each(function (content) {
                content.Header = unescapeHTMLEntities(content.Header);
            });
            $scope.contentResults.paging.searching = false;
            $scope.activateTab('contenttab');

            function unescapeHTMLEntities(str) {
                /* Do not use with untrusted data */
                return $('<textarea/>').html(str).text();
            }
        }
        function setVideos(data) {
            genericSetter(data, $scope.videoResults);
            $scope.videoResults.paging.searching = false;
            if ($scope.activeQuery.filteroption != 0) $scope.activateTab('videotab');
        }
        function setPrograms(data) {
            genericSetter(data, $scope.programResults);
            $scope.programResults.paging.searching = false;
            if ($scope.activeQuery.filteroption != 0) $scope.activateTab('programtab');
        }
        function setCategoryLinks(links) {
            for (var j = 0; j < links.Mains.length; j++) {
                links.Mains[j].slices = [];
                var start = 0, stop = 0, step = 0;
                for (var k = 0; k < $scope.columns; k++) {
                    if (start == 0) {
                        step = Math.ceil(links.Mains[j].CategoryDisplays.length / $scope.columns);
                    }
                    stop += step;
                    stop = Math.min(stop, links.Mains[j].CategoryDisplays.length);
                    links.Mains[j].slices.push({ start: start, stop: stop });
                    start += step;
                }

            }
            $scope.categoryLinkResults.all = links;
            if ($scope.activeQuery.filteroption != 0 && $scope.activeQuery.filteroption != 4) $scope.activateTab('categorytab');
        }

        function getCategoryItems() {
            var ret = 0;
            if (!$scope.categoryLinkResults || !$scope.categoryLinkResults.all || !$scope.categoryLinkResults.all.Mains) return ret;
            for (var i = 0; i < $scope.categoryLinkResults.all.Mains.length; i++) {
                var d = $scope.categoryLinkResults.all.Mains[i];
                for (var j = 0; j < d.CategoryDisplays.length; j++) { ret++; }
            }
            return ret;
        }

        function setOptions() {
            $scope.filterOptions.all = $scope.so[$scope.pt];
            var optionExists = _.find($scope.filterOptions.all, function (opt) { return opt.id == $scope.activeQuery.filteroption; });
            $scope.filterOptions.selectedOption = optionExists ? $scope.activeQuery.filteroption : 0;
            $scope.activeQuery.filteroption = $scope.filterOptions.selectedOption;
        }

        function setCategoriesDropDown(data) {
            $scope.categories.all = data;
            var categoryExists = _.find($scope.categories.all, function (p) { return p.CategoryId == $scope.activeQuery.category; });
            $scope.categories.selectedCategory = categoryExists ? $scope.activeQuery.category : 0;
            $scope.activeQuery.category = $scope.categories.selectedCategory;
        }
    }
})();
;
(function () {
    'use strict';

    var controllerId = 'searchRouteCtrl';

    try {
        angular.module('app').controller(controllerId, ['$scope', '$attrs', searchRouteCtrl]);
    } catch (ex) {
        angular.module('errMuuda').controller(controllerId, ['$scope', '$attrs', searchRouteCtrl]);
    }

    function searchRouteCtrl($scope, $attrs) {

        $scope.route = {
            phrase: "",
            portalid: parseInt($attrs.portalid || 0)
        }

        $scope.doRoute = function () {
            var currentUrl = window.location.href;
            var redirectto = gethref() + "/search3#?phrase=" + $scope.route.phrase;
            //rus and news must by default only search intra portal
            if ($scope.route.portalid == 180 || $scope.route == 204) {
                redirectto += "&portalid=" + $scope.route.portalid;
            }
            window.location.assign(redirectto);
            if (currentUrl.indexOf("search3") > -1) {
                location.reload();
            }
        }

        function gethref() {
            var url = window.location.protocol + "//" + window.location.hostname;
            if (window.location.port.length > 0) {
                url += ":" + window.location.port;
            }
            return url;
        }

        $scope.keyUpEnter = function (e) {
            if (e.keyCode === 13) {
                $scope.doRoute();
            }
        }
    }
})();
;
(function () {
    'use strict';
    var serviceId = 'search3Service';
    angular.module('app').factory(serviceId, ['$http', '$q', '$cookieStore', search3Service]);

    function search3Service($http, $q, $cookieStore) {
        var service = {
            getVideos: getVideos,
            getPrograms: getPrograms,
            getContents: getContents,
            getSearchableCategories: getSearchableCategories,
            validateActiveQuery: validateActiveQuery,
            getOptions: getOptions,
            getCategoryLinks: getCategoryLinks,
            getDependantCategories: getDependantCategories,
            getMedia: getMedia,
            getReViewable: getReViewable,
            getPortalType: getPortalType,
            getPageSizeForResultSet: getPageSizeForResultSet,
            setPageSizeForResultSet: setPageSizeForResultSet
        };
        var allowedParams = ["to", "from", "phrase", "category", "filteroption", "portalid"];

        var serviceEndpoints = {
            clips: "/api/search/clips?",
            searchableCategories: "/api/search/searchportals",
            options: "/api/search/searchoptions",
            getCategoryLinksEP: function (portalid, categoryid, phrase) { return "/api/search/categorydisplays?portalid=" + portalid + "&categoryid=" + categoryid + "&phrase=" + phrase; },
            programs: '/api/search/programs?',
            getContentsEP: '/api/search/contents?',
            getMediaEP: '/api/search/media?',
            dependantEP: "/api/search/categoriesforportal?id=",
            portaltypeEP: function (categoryid) { return "/api/category/portaltypeforcategoryid?categoryid=" + categoryid; }
        };
        return service;

        function getPortalType(categoryid) {
            var def = $q.defer();
            $http({ method: "get", cache: true, url: serviceEndpoints.portaltypeEP(categoryid) }).success(function (data) { def.resolve(data); });
            return def.promise;
        }

        function getVideos(searchRequest) {
            var def = $q.defer();
            $http({ method: "get", url: serviceEndpoints.clips + $.param(searchRequest) }).success(function (data) {
                def.resolve(data);
            });
            return def.promise;
        }

        function getReViewable(searchRequest) {
            var url = serviceEndpoints.programs + $.param(searchRequest);
            var def = $q.defer();
            $http({ method: "get", url: url }).success(function (data) { def.resolve(data); });
            return def.promise;
        }

        function getMedia(searchRequest) {
            var url = serviceEndpoints.getMediaEP + $.param(searchRequest);
            var def = $q.defer();
            $http({ method: "get", url: url }).success(function (data) { def.resolve(data); });
            return def.promise;
        }

        function getDependantCategories(principalid) {
            var def = $q.defer();
            $http({ method: "get", cache: true, url: serviceEndpoints.dependantEP + principalid }).success(function (data) { def.resolve(data); });
            return def.promise;
        }
        function getPageSizeForResultSet(request) {
            var size = $cookieStore.get(request.resultSetName + "size") || request.defaultValue;
            return parseInt(size);
        }
        function setPageSizeForResultSet(request) {
            $cookieStore.put(request.resultSetName + "size", request.size);
        }
        function getPrograms(searchRequest) {
            var url = serviceEndpoints.programs + $.param(searchRequest);
            var def = $q.defer();
            $http({ method: "get", url: url }).success(function (data) { def.resolve(data); });
            return def.promise;
        }

        function getContents(searchRequest) {
            var url = serviceEndpoints.getContentsEP + $.param(searchRequest);
            var def = $q.defer();
            $http({ method: "get", url: url }).success(function(data) {def.resolve(data); });
            return def.promise;
        }
        function getOptions() {
            var def = $q.defer();
            $http({ method: "get", url: serviceEndpoints.options, cache: true }).success(function (data) { def.resolve(data); });
            return def.promise;
        }

        function getCategoryLinks(searchRequest) {
            var url = serviceEndpoints.getCategoryLinksEP(searchRequest.portalid, searchRequest.category, searchRequest.phrase);
            var def = $q.defer();
            $http({ method: "get", url: url, cache: true }).success(function (data) {
                def.resolve(data);
            });
            return def.promise;
        }

        function getSearchableCategories(id) {
            var defer = $q.defer();
            $http({ method: "get", url: serviceEndpoints.searchableCategories + id, cache: true }).success(function (data) { defer.resolve(data); });
            return defer.promise;
        }

        function validateActiveQuery(routeParams, portaldefaults) {
            var clean = {};
            for (var i = 0; i < allowedParams.length; i++) clean[allowedParams[i]] = routeParams[allowedParams[i]];
            return defaultQueryValues(clean, portaldefaults);
        }

        function defaultQueryValues(clean, portaldefaults) {
            //clean.from = clean.from || "01.01.2010";
            //clean.to = clean.to || $.datepicker.formatDate("dd.mm.yy", new Date());
            clean.from = "";
            clean.to = "";
            clean.phrase = clean.phrase || "";
            clean.category = clean.category ? parseInt(clean.category) : 0;
            clean.filteroption = clean.filteroption ? parseInt(clean.filteroption) : portaldefaults.filteroption;
            clean.portalid = clean.portalid ? parseInt(clean.portalid) : portaldefaults.portalid;
            return clean;
        }
    }
})();;
(function() {
    'use strict';
    angular.module('app').directive('searchdropdown', ['$window', searchdropdown]);
    
    function searchdropdown ($window) {
        var directive = {
            templateUrl: '/FrontUI/Templates/AngularTemplates/searchdropdown',
            replace: true,
            link: link,
            scope: {
                options: "=",
                rs: "=",
                changehandler: "="
            },
            restrict: 'AE'
        };
        return directive;

        function link(scope, element, attrs) {
            scope.change = function (newvalue) {
                if (newvalue != scope.rs.paging.size) {
                    scope.rs.paging.size = newvalue;
                    scope.changehandler(scope.rs);
                }
            }
        }
    }
})();;
(function() {
    'use strict';
    angular.module('app').directive('searchResultSet', ['$window', searchResultSet]);
    
    function searchResultSet ($window) {
        var directive = {
            templateUrl: '/FrontUI/Templates/AngularTemplates/searchresultset',
            link: link,
            restrict: 'AE',
            replace: true,
            scope: {
                rs: "=",
                changehandler: "=",
                options: "="
            }
        };
        return directive;

        function link(scope, element, attrs) {
            //console.group("searchResultSet directive:");
            //console.log("Linked");
            //console.log(scope.changehandler);
            //console.log(scope.rs);
            //console.groupEnd();
        }
    }
})();;
(function () {
    'use strict';

    var controllerId = 'saatekavaController';

    angular.module('app').controller(controllerId,
        ['$scope', '$attrs', 'saatekavaService', '$locale', '$sce', '$timeout', '$compile', saatekavaController]);

    function saatekavaController($scope, $attrs, saatekavaService, $locale, $sce, $timeout, $compile) {
        $scope.controllerName = 'saatekavaController';
        $scope.datepickerSelectHandler = datepickerSelectHandler;

        $scope.uid = $attrs.uid;
        $scope.debug = $attrs.debug == "True";
        $scope.mediaTypes = getMediaTypesSelect($attrs.language);
        $scope.daysSelect = getDaysSelect($attrs.language);
        $scope.playerHtml = $sce.trustAsHtml("init");
        $scope.selectedDays = $scope.daysSelect[0];
        $scope.selectedMediaType = $scope.mediaTypes[0];
        $scope.datepicker = angular.element('#' + $scope.uid + '-saatekavadatepicker');
        $scope.displayDaysChangeHandler = displayDaysChangeHandler;
        $scope.daysHolder = [];
        $scope.mediafilterexpression = {};
        $scope.idfilter = {};
        $scope.loadAndToggle = loadAndToggle;
        $scope.$watch('selectedMediaType', _mediaChangeHandler);
        $scope.$watch('onlyIds', _idfilterhandler);
        $scope.showJson = false;
        $scope.loading = false;
        $scope.toggleLoading = toggleLoading;
        $scope.markCurrentlyAiring = markCurrentlyAiring;
        $scope.showVideo = $attrs.showvideo == "True";
        $scope.defaultImg = $attrs.defaultimg;
        $scope.imgSize = "";
        $scope.activeElement = 0;
        $scope.pastDates = $attrs.pastdates == "True";
        $scope.loadPlaylist = loadPlaylist;
        $scope.playClip = playClip;
        $scope.videoPlayer = 
            	'    <div class="player">' +
                '        <div class="play-button" id="ajakavaplayer" ng-style="{\'background-image\': \'url({{mediaposter}})\'}"' +
                '             data-key="$514317695773130"' +
                '             data-swf="/Content/player/swf/flowplayer.swf"' +
                '             data-swf-hls="/Content/player/swf/flowplayerhls.swf"' +
                '             data-debug="true"' + 
                '             data-wmode="transparent"'+
                '             >' +
                '<img ng-if="mediaposter" ng-src="{{mediaposter}}"/>' +
                '        </div>' +
                '    </div>'
            ;
        var loadingPreCheck = false;

        function toggleLoading() {
            $scope.loading = !$scope.loading;
        }

        $scope.toggleJson = function () {
            $scope.showJson = !$scope.showJson;
        }

        $scope.startPlayer = startPlayer;
        $scope.changeMedia = changeMedia;

        $scope.playerError = false;
        $scope.playerObj = false;

        function startPlayer(mediaObj, imageSize) {

            $timeout(function () {
                $scope.mediaposter = mediaObj.image;



                
                if ($scope.playerObj === false) {

                    angular.element('#' + mediaObj.player).append($scope.videoPlayer);

                    var video = angular.element('#ajakavaplayer');
                    
                    $scope.$apply();
                    $compile(video)($scope);
                    $scope.playerObj = new meediaPlayer(video, {
                        live: mediaObj.live,
                        autoplay: true,
                        clip: {
                            sources: mediaObj.source
                        }
                    });
                    
                    if (typeof $scope.playerObj.getPlayer().on !== 'undefined')
                    {
                        $scope.playerObj.getPlayer().on('error', function () {
                            $scope.playerError = true;
                        })
                    }


                } else {

                    if ($scope.playerError === true)
                    {
                        $scope.playerObj.getPlayer().data('flowplayer').error = $scope.playerObj.getPlayer().data('flowplayer').loading = false;
                        $scope.playerObj.getPlayer().removeClass('is-error');
                        $scope.playerError = false;
                    }
                    $scope.playerObj.loadClip({
                        live: mediaObj.live,
                        autoplay: true,
                        sources: mediaObj.source
                    });
                    
                    
                }


            });
            //$scope.playerHtml = $sce.trustAsHtml($scope.videoPlayer);
        }

        function changeMedia(obj, index) {
            startPlayer(obj, $scope.imgSize);
            $scope.activeElement = index;
        }

        init();

        function defaultIframe(iframehtml, imageSize) {

            var elements = iframehtml.split(" ");
            for (var i = 0; i < elements.length; i++) {
                if (elements[i].indexOf('height') >= 0) {
                    if (elements[i].length > 15) {
                        var video = elements[i].split("&image")[0];
                        elements[i] = video + "&image=http://static.err.ee/gridfs/" + $scope.defaultImg + "?width=" + imageSize.width + "&height=100&mode=crop";
                    } else {
                        elements[i] = elements[i].substring(0, 7) + '"100"';
                    }
                }
            }
            elements[elements.length - 2] = elements[elements.length - 2] + '" style="height: 100px;"';
            return elements.join(' ');
        }

        function _idfilterhandler() {
            if ($scope.onlyIds) {
                $scope.idfilter = { Id: '!00000000-0000-0000-0000-000000000000' }
            } else {
                $scope.idfilter = {}
            }
        }

        function init() {
            $scope.frontUISettings = _getFrontUISettings();
            saatekavaService.setSettings($scope.frontUISettings);
            $scope.selectedDays = $scope.daysSelect[$scope.frontUISettings.days];
            $scope.selectedMediaType = $scope.mediaTypes[$scope.frontUISettings.mediafilter];

            var lang = "et";

            if ($scope.frontUISettings.language == 1) {
                lang = "en-GB";
            } else if ($scope.frontUISettings.language == 2) {
                lang = "ru";
            }

            $scope.datepicker.datepicker($.extend({}, $.datepicker.regional[lang], {
                dateFormat: 'dd.mm.yy',
                onSelect: $scope.datepickerSelectHandler,
            }));
            var today = new Date();
            var newDay = new Date();
            newDay.setDate(today.getDate() - $scope.frontUISettings.daydelta);
            $scope.datepicker.datepicker("setDate", newDay);


            activate();
        }

        function _getFrontUISettings() {
            var frontUISettings = {};
            frontUISettings.daydelta = parseInt($attrs.daydelta);
            frontUISettings.days = parseInt($attrs.days);
            frontUISettings.mediafilter = parseInt($attrs.mediafilter);
            frontUISettings.feedname = $attrs.feedname;
            frontUISettings.language = parseInt($attrs.language);
            frontUISettings.portaltype = $attrs.portaltype;
            frontUISettings.uid = $attrs.uid;
            frontUISettings.debug = $attrs.debug == "True";
            frontUISettings.cropVideo = $attrs.cropVideo == "True";
            frontUISettings.channel = $attrs.channel;
            return frontUISettings;
        }

        function displayDaysChangeHandler() {
            activate();
        }

        function datepickerSelectHandler() {
            $scope.frontUISettings.daydelta = 0;
            activate();
        }

        function clearActivePlayers() {
            $scope.playerObj = false;
            $(".flowplayer").each(function () {
                $(this).data("flowplayer").shutdown();
            });
                
            angular.element('#ajakavaplayer').parent().remove();
            
        }
        //refactor
        function loadAndToggle(saade, domElementString) {

            var isSlideIn = _getIsSlideIn(domElementString);
            var imageSize = _getImageSizeForDomElement(domElementString);

            //save this for future ref, when loading clips for example
            saade.imageSize = imageSize;
            $scope.imgSize = imageSize;
            clearActivePlayers();
            if (saade.Id !== undefined && saade.Id != '00000000-0000-0000-0000-000000000000') {
                if (saade.Image) {
                    if ($scope.showVideo) {
                        saade.resizedImageUrl = saatekavaService.getResizedImageUrl(saade.Image, imageSize, saade.ImageResizerOptions);
                    }
                }
                saatekavaService.getTimeLineContent(saade, imageSize).then(function (content) {
                    var wasCurrentlyAiring;
                    if (content) {
                        saade.clientdata = content;
                    }
                    if (!isSlideIn && (saade.hasMedia || saade.isCurrentlyAiring)) {
                        wasCurrentlyAiring = saade.isCurrentlyAiring;
                        
                        saade.isCurrentlyAiring = wasCurrentlyAiring;
                        saade.isActivePlayerHolder = true;

                        $scope.startPlayer(saade.mediaClip[0], imageSize);
                        if (saade.hasMedia) {
                            $scope.markCurrentlyAiring($scope.daysHolder);
                        }
                    }
                });
            } else if (saade.isCurrentlyAiring) {
                if (saade.Image) {
                    saade.resizedImageUrl = saatekavaService.getResizedImageUrl(saade.Image, imageSize, saade.ImageResizerOptions);
                }
 
                saade.isCurrentlyAiring = true;
                saade.isActivePlayerHolder = true;
                $scope.startPlayer(saade.mediaClip[0], imageSize);
            } else {
                if (saade.Image) {
                    saade.resizedImageUrl = saatekavaService.getResizedImageUrl(saade.Image, imageSize, saade.ImageResizerOptions);
                }
            }
            $timeout(function () {
                angular.element("#" + $scope.uid + "-saatekavaaccordion .in").collapse('hide');
                /* 50ms timeouts and nested timeout to workaround firefox bug relating to PORT114 */
                $timeout(function () {
                    angular.element('#' + domElementString).collapse('toggle');
                }, 50);
            }, 50);
        }

        function playClip(saade, index) {
            saatekavaService.initClips(saade);
            var wasCurrentlyAiring = saade.isCurrentlyAiring;
            //clearActivePlayers();
            saade.isCurrentlyAiring = wasCurrentlyAiring;
            saade.isActivePlayerHolder = true;
            $scope.startPlayer(saade.relatedClip[index], saade.imageSize);
            if (saade.hasMedia) {
                $scope.markCurrentlyAiring($scope.daysHolder);
            }

        }

        function loadPlaylist(saade) {
            if (!saade.playListLoaded) {
                var searchRequest = {
                    radioSeriesId: saade.RadioSeriesId,
                    channel: $scope.frontUISettings.channel,
                    date: saade.Published
                };
                saatekavaService.getShowPlayList(searchRequest).then(function (playlistData) {
                    saade.playlist = playlistData;
                });
                saade.playListLoaded = true;
            }
        }

        function _getIsSlideIn(domElementString) {
            var el = angular.element('#' + domElementString);
            return el.hasClass("in");
        }

        function activate() {
            var startdate = moment($scope.datepicker.val(), 'DD.MM.YYYY');
            saatekavaService.getTimeLineDays(startdate._d, $scope.selectedDays.value, $scope.pastDates).then(processPrograms);
            loadingPreCheck = true;
            $timeout(function () { $scope.loading = loadingPreCheck; }, 75);
        }

        function processPrograms(shows) {
            loadingPreCheck = false;
            $scope.loading = false;
            shows.sort(date_sort_asc);
            $scope.daysHolder = [];
            $scope.markCurrentlyAiring(shows);
            $scope.daysHolder = shows;
        }

        function markCurrentlyAiring(shows) {
            var today = new Date();
            var currentlyAiring;
            for (var i = 0; i < shows.length; i++) {
                var lastShowIndex = (shows[i].shows.length - 1);
                for (var j = 0; j < shows[i].shows.length; j++) {
                    var onAirStart = new Date(shows[i].shows[j].Published);
                    if (areSameDay(onAirStart, today) && onAirStart > today) {
                        var matchIndex = j > 0 ? (j - 1) : j;
                        currentlyAiring = shows[i].shows[matchIndex];
                        setCurrentlyAiringProperties(currentlyAiring);
                        return;
                    }

                    if (lastShowIndex == j && onAirStart <= today && areSameDay(today, onAirStart)) {
                        currentlyAiring = shows[i].shows[j];
                        setCurrentlyAiringProperties(currentlyAiring);
                        return;
                    }
                }
            }
        }

        function areSameDay(date1, date2) {
            if (typeof (date1) == "string") date1 = new Date(date1);
            if (typeof (date2) == "string") date2 = new Date(date2);
            return date1.getDate() == date2.getDate() && date1.getMonth() == date2.getMonth() && date1.getFullYear() == date2.getFullYear();
        }

        function setCurrentlyAiringProperties(saade) {
            if (saade) {
                saade.isCurrentlyAiring = true;
                saade.mediaClip = [];
                var imageSize = _getImageSizeForDomElement();
                saade.mediaClip[0] = saatekavaService.buildOtseIFrame(saade.Image, imageSize, saade.ImageResizerOptions);
            }
        }

        function date_sort_asc(o1, o2) {
            if (o1.date > o2.date) return 1;
            if (o1.date < o2.date) return -1;
            return 0;
        };

        function _mediaChangeHandler() {
            switch ($scope.selectedMediaType.value) {
                case 0:
                    $scope.mediafilterexpression = {};
                    break;
                case 1:
                    $scope.mediafilterexpression = function (item) {
                        return item.hasVideo || item.hasAudio;
                    }
                    break;
                default:
                    $scope.mediafilterexpression = {};
            }
        }

        function _getImageSizeForDomElement(domelementId) {
            var imageSize = {};
            var width = angular.element('#' + domelementId).width() || angular.element('#saatekavacollapse0-0').width();
            if (width == 0) width = null;
            var height = Math.ceil(width / 1.777777777778); //16:9
            imageSize.width = width;
            imageSize.height = height;
            return imageSize;
        }


        function getMediaTypesSelect(lang) {
            var language = parseInt(lang);

            var viewName = "Veebis vaadatavad";
            if ($attrs.portaltype == "radio") {
                viewName = "Veebis kuulatavad";
            }
            switch (language) {
                case 0:
                    return [{ name: "Kõik saated", value: 0 }, { name: viewName, value: 1 }];
                case 1:
                    return [{ name: "All", value: 0 }, { name: "Media", value: 1 }];
                case 2:
                    return [{ name: "Bсе", value: 0 }, { name: "Mедиa", value: 1 }];
                default:
                    return [{ name: "Kõik saated", value: 0 }, { name: "Audio", value: 1 }];
            }
        }

        function getDaysSelect(language) {
            var languageAsInt = parseInt(language);
            switch (languageAsInt) {
                case 0:
                    return [{ name: "1 päev", value: 1 }, { name: "2 päeva", value: 2 }, { name: "3 päeva", value: 3 }, { name: "4 päeva", value: 4 }, { name: "5 päeva", value: 5 }, { name: "6 päeva", value: 6 }, { name: "7 päeva", value: 7 }];
                case 1:
                    return [{ name: "1 day", value: 1 }, { name: "2 days", value: 2 }, { name: "3 days", value: 3 }, { name: "4 days", value: 4 }, { name: "5 days", value: 5 }, { name: "6 days", value: 6 }, { name: "7 days", value: 7 }];
                case 2:
                    return [{ name: "1 день", value: 1 }, { name: "2 дня", value: 2 }, { name: "3 дня", value: 3 }, { name: "4 дня", value: 4 }, { name: "5 дней", value: 5 }, { name: "6 дней", value: 6 }, { name: "7 дней", value: 7 }];
                default:
                    return [{ name: "1 päev", value: 1 }, { name: "2 päeva", value: 2 }, { name: "3 päeva", value: 3 }, { name: "4 päeva", value: 4 }, { name: "5 päeva", value: 5 }, { name: "6 päeva", value: 6 }, { name: "7 päeva", value: 7 }];
            }
        }

    }
})();
;
(function () {
    'use strict';
    var serviceId = 'saatekavaService';
    angular.module('app').service(serviceId, ['$http', '$q', '$sce', saatekavaService]);

    var frontUISettings = {};

    function saatekavaService($http, $q, $sce) {
        var serviceHost = "/api/loader/";
        var timeLineDay = "GetTimeLineDay/";
        var timeLineContent = "gettimelinecontent/";
        var showPlayList = "GetShowPlayList";
        var getcategorydisplay = "GetCategoryUrlForPrimaryCategory/?categoryid=";
        var service = {
            getTimeLineDays: getTimeLineDays,
            getTimeLineContent: getTimeLineContent,
            getResizedImageUrl: getResizedImageUrl,
            getShowPlayList: getShowPlayList,
            buildOtseIFrame: buildOtseIFrame,
            setSettings: setSettings,
            initClips: initClips
        };

        return service;

        function setSettings(mainSettings) {
            frontUISettings = mainSettings;
        }

        function getResizedImageUrl(imageFileName, imageSize, imageResizeOptions) {
            var imgUrl;

            if (imageResizeOptions != null && imageResizeOptions != "") {
                imgUrl = "http://static.err.ee/gridfs/" + imageFileName + imageResizeOptions;
            } else {
                imgUrl = "http://static.err.ee/gridfs/" + imageFileName + "?width=" + imageSize.width + "&height=" + imageSize.height + "&mode=crop";
            }


            return imgUrl;
        }

        function initClips(saade) {
            if (saade.relatedClip) return;
            saade.relatedClip = [];
            var imagefilename = saade.Image;
            if (saade.Image) {
                if (saade.Image.FileName) {
                    imagefilename = saade.Image.FileName;
                }
            }
            for (var j = 0; j < saade.ContentRelations.length; j++) {
                if (saade.ContentRelations[j].MediaSources && saade.ContentRelations[j].MediaSources.length > 0) {
                    saade.relatedClip.push(_buildMediaObj(saade.ContentRelations[j].MediaSources[0], saade.Id, imagefilename, saade.imageSize, saade.player));
                }
            }
        }

        function buildOtseIFrame(imageFileName, imageSize) {

            var url = "";
            var iframehtml;
            if (/Android/i.test(navigator.userAgent) || /IEMobile/i.test(navigator.userAgent) || /BlackBerry/i.test(navigator.userAgent)) {

                switch (frontUISettings.feedname.toUpperCase()) {
                    case 'RAADIO2':
                        url = 'rtsp://194.36.162.51:80/live/raadio2';
                        break;
                    case 'RAADIO4':
                        url = 'rtsp://194.36.162.51:80/live/raadio4';
                        break;
                    case 'RAADIOTALLINN':
                        url = 'rtsp://194.36.162.51:80/live/raadiotallinn';
                        break;
                    case 'VIKERRAADIO':
                        url = 'rtsp://194.36.162.228:80/live/vikerraadio';
                        break;
                    case 'ETV':
                        url = 'rtsp://wowza3.err.ee:80/live/etvm';
                        break;
                    case 'ETV2':
                        url = 'rtsp://wowza3.err.ee:80/live/etv2m';
                        break;
                }

                iframehtml = '<div class="flex-video widescreen" style="padding-top: 0;"><a style="width:100%;" href="' + url + '"><div class="media-icons">\
                                        <span aria-hidden="true" style="font-family: "icomoon";" class="media-icon icomoon-play"></span>\
                                        </div><img alt="Video" style="width:100%;" src="http://static.err.ee/gridfs/' + imageFileName + '?width=752&height=423&mode=crop' + '" id="image"></a></div>';
            } else if (/iPhone|iPad|iPod/i.test(navigator.userAgent)) {


                switch (frontUISettings.feedname.toUpperCase()) {
                    case 'RAADIO2':
                        url = 'http://194.36.162.51/live/raadio2madal/playlist.m3u8';
                        break;
                    case 'RAADIO4':
                        url = 'http://194.36.162.51/live/raadio4madal/playlist.m3u8';
                        break;
                    case 'RAADIOTALLINN':
                        url = 'http://194.36.162.51/live/raadiotallinnmadal/playlist.m3u8';
                        break;
                    case 'VIKERRAADIO':
                        url = 'http://194.36.162.51/live/vikerraadiomadal/playlist.m3u8';
                        break;
                    case 'ETV':
                        url = 'http://wowza3.err.ee/live/smil:etv.smil/playlist.m3u8';
                        break;
                    case 'ETV2':
                        url = 'http://wowza3.err.ee/live/smil:etv2.smil/playlist.m3u8';
                        break;
                }

                iframehtml = '<div class="flex-video widescreen" style="padding-top: 0;"><a style="width:100%;" href="' + url + '"><div class="media-icons">\
                                        <span aria-hidden="true" style="font-family: "icomoon";" class="media-icon icomoon-play"></span>\
                                        </div><img alt="Video" style="width:100%;" src="http://static.err.ee/gridfs/'+ imageFileName + '?width=752&height=423&mode=crop' + '" id="image"></a></div>';
            } else {
                if (frontUISettings.feedname.toLowerCase() == "klassika") {
                    frontUISettings.feedname = "klassikaraadio";
                }
                var mediaUrl = 'http://otse.err.ee/iframe2?' +
                    'channel=' + frontUISettings.feedname +
                    '&mediaspace=mediaframe' +
                    '&autoplay=false' +
                    '&mediamode=wowzalive' +
                    '&width=100' +
                    '&height=100' +
                    '&site=' + window.location.host;
                mediaUrl += '&image=http://static.err.ee/gridfs/' + imageFileName + '?width=' + imageSize.width;
                var playerHeight = frontUISettings.portaltype == "tv" ? imageSize.height : 25;
                iframehtml = '<iframe id="mediaframe" class="saatekavaiframe" frameborder="0" scrolling="no" width="100%" height="' + playerHeight + '" src="' + mediaUrl + '" border="0"></iframe>';
            }

            return iframehtml;
        }
        /*DEPRECATED*/
        function _buildMediaIFrameHtml(mediaSource, imageFileName, imageSize) {
            var mediatype = (mediaSource.Type == 128) ? "&mediamode=wowzavideo" : "&mediamode=wowzaaudio";
            var media = mediaSource.Content.replace('://', '').split('@');
            var mediaUrl = 'http://static.err.ee/media?' +
                'stream=' + media[0] +
                '&file=' + media[1] +
                '&mediaspace=mediaframe' +
                '&autoplay=false' +
                mediatype +
                '&site=' + window.location.host
                + '&image=http://static.err.ee/gridfs/' + imageFileName + '?width=' + imageSize.width + "&height=" + imageSize.height;

            var playerHeight = mediaSource.Type == 128 ? 423 : 25;
            //var iframeHtml = '<div class="flex-video widescreen"><iframe id="mediaframe" class="saatekavaiframe" frameborder="0" scrolling="no" width="100%" height="' + playerHeight + '" src="' + mediaUrl + '" border="0"></iframe></div>';
            //var iframeHtml = '<div class="flex-video widescreen"><iframe id="mediaframe" class="saatekavaiframe" frameborder="0" scrolling="no" width="100%" height="auto" src="' + mediaUrl + '" border="0"></iframe></div>';
            var iframeHtml = '<iframe id="mediaframe" class="saatekavaiframe" frameborder="0" scrolling="no" width="100%" height="' + playerHeight + '" src="' + mediaUrl + '" border="0"></iframe>';


            return iframeHtml;
        }
        function _buildMediaObj(mediaSource, id, imageFileName, imageSize, player) {
            var obj = {};


            obj = {
                source: mediaSource.Content,
                live: false,
                image: 'http://static.err.ee/gridfs/' + imageFileName + '?width=' + imageSize.width + "&height=" + imageSize.height,
                id: id,
                player: player
            };


            return obj;
        }
        function getTimeLineContent(saade, imageSize) {
            var defer = $q.defer();
            var url = serviceHost + timeLineContent + saade.Id;
            var getCategoryUrl = serviceHost + getcategorydisplay;
            $http({ method: "GET", url: url, cache: true }).success(function (data) {
                if (data.Texts != undefined && data.Texts != null) {
                    for (var i = 0; i < data.Texts.length; i++) {
                        if (data.Texts[i].Language != undefined && data.Texts[i].Language == frontUISettings.language) {
                            saade.safeBody = $sce.trustAsHtml(data.Texts[i].Body);
                            saade.safeLead = $sce.trustAsHtml(data.Texts[i].Lead);
                            break;
                        }
                    }
                }
                var imagefilename = saade.Image;
                if (data.Image) {
                    if (data.Image.FileName) {
                        imagefilename = data.Image.FileName;
                    }
                }
                if (!saade.isCurrentlyAiring) {
                    if (data.MediaSources.length > 0 && data.MediaSources[0] !== undefined) {

                        saade.mediaClip = [];
                        for (var j = 0; j < data.MediaSources.length; j++) {
                            saade.mediaClip.push(_buildMediaObj(data.MediaSources[j], saade.Id, imagefilename, imageSize, saade.player));
                        }
                        saade.hasMedia = true;
                    }
                }
                saade.resizedImageUrl = getResizedImageUrl(imagefilename, imageSize, saade.ImageResizerOptions);
                saade.contentHasBeenLoaded = true;
                $http({
                    method: "GET", url: getCategoryUrl + data.PrimaryCategoryId
                    , cache: true
                }).success(function (catdisplay) {
                    saade.categoryUrl = catdisplay;
                    defer.resolve(data);
                }).error(function () { defer.resolve(data); });
            }).error(function (status) { defer.reject(status); });
            return defer.promise;
        }

        function getTimeLineDays(startDate, howManyDays, pastdates) {
            var defer = $q.defer();
            var promises = [];
            var ret = [];
            var year;
            var day;
            var month;
            if (pastdates) {
                for (var i = howManyDays; i > 0; i--) {
                    year = startDate.getFullYear();
                    day = startDate.getDate();
                    month = startDate.getMonth();
                    month++;
                    var url = serviceHost + timeLineDay + "?day=" + day + "&month=" + month + "&year=" + year + "&returnPlaylist=true";
                    promises.push($http({
                        url: url,
                        method: "GET",
                        cache: true
                    }).success(handleDayData));
                    startDate.setDate(startDate.getDate() - 1);
                }
            } else {
                for (var j = 0; j < howManyDays; j++) {
                    year = startDate.getFullYear();
                    day = startDate.getDate();
                    month = startDate.getMonth();
                    month++;
                    var url = serviceHost + timeLineDay + "?day=" + day + "&month=" + month + "&year=" + year + "&returnPlaylist=true";
                    promises.push($http({
                        url: url,
                        method: "GET",
                        cache: true
                    }).success(handleDayData));
                    startDate.setDate(startDate.getDate() + 1);
                }
            }

            $q.all(promises).then(function () { defer.resolve(ret); });
            return defer.promise;

            function handleDayData(data, status, b, reqInfo) {
                if (typeof (data) === "object") {
                    for (var j = 0; j < data.length; j++) {
                        if (data[j].Lead) {
                            data[j].safeLead = $sce.trustAsHtml(data[j].Lead);
                        }
                        if (data[j].HeaderLong) {
                            data[j].safeHeader = $sce.trustAsHtml(data[j].HeaderLong);
                        } else {
                            data[j].safeHeader = $sce.trustAsHtml(data[j].Header);
                        }
                    }
                    ret.push({ date: _getDateFromQuery(reqInfo.url), shows: data });
                }
            }
        }
        function _getDateFromQuery(url) {
            var splitQuery = url.split('?')[1].split('&');
            var dateStrings = [];
            for (var i = 0; i < splitQuery.length; i++) {
                dateStrings.push(splitQuery[i].split('=')[1]);
            }
            var month = parseInt(dateStrings[1]);
            var dateString = month + "/" + dateStrings[0] + "/" + dateStrings[2];
            return new Date(dateString);
        }

        function getShowPlayList(searchRequest) {
            var defer = $q.defer();
            if (searchRequest.date != undefined) {
                var d = moment(searchRequest.date);
                var date = d.format("D.MM.YYYY H:mm:ss");
                var reqUrl = serviceHost + showPlayList + "?key=" + searchRequest.channel.toLowerCase() + "/" + searchRequest.radioSeriesId.toLowerCase() + "/" + date;
                $http({ method: "get", url: reqUrl }).success(function (data) { defer.resolve(data); }).error(function (data) { defer.reject("failed request"); });
                return defer.promise;
            }
            return null;
        }
    }
})();;
(function () {
    'use strict';
    var controllerId = 'mediapollCtrl';
    angular.module('app').controller(controllerId,
        ['$scope', '$attrs', 'mediapollService', '$cookies', '$cookieStore','$q', mediapollCtrl]);

    function mediapollCtrl($scope, $attrs, mediapollService, $cookies, $cookieStore, $q) {
        var votedCookieName = "mp_pv-" + $attrs.pollid;
        $scope.previousVotes = $cookieStore.get(votedCookieName) || [];
        $scope.voteLimit = getVoteTimeLimitObject($attrs.votelimit) || { hours: 0, minutes: 0, seconds: 0 };
        $scope.manyOptions = $attrs.manyoptions == "True";
        $scope.showVoteCount = $attrs.showvotecount == "True";
        $scope.showVoteResults = $attrs.showvotesresults == "True";
        $scope.allowMultiple = $attrs.allowmultiple === "True";
        $scope.vg = $attrs.vg == "True";
        $scope.language = $scope.$eval($attrs.language);
        $scope.pollOptions = $scope.$eval($attrs.pollinfo);
        $scope.totalVotes = 0;
        $scope.predicate = "-progressPercent";
        $scope.maxVotes = 0;
        var languageOptions = $scope.$eval($attrs.languageoptions);
        $scope.pollId = $attrs.pollid;
        $scope.options = [];
        $scope.activate = activate;
        $scope.setVote = setVote;
        $scope.vote = vote;
        $scope.launchResults = launchResults;
        $scope.selectedVotes = [];
        activate();
        function activate() {
            initVotes();
            fillOptions();
        }

        function launchResults() {
            $('#myModal').modal();
        }
        function getDefaultOption(index) {
            return {
                optionId: $scope.pollOptions[index].optionId,
                optionName: $scope.pollOptions[index].optionName,
                isSelected: false,
                displayText: languageOptions.selectMe,
                votes: $scope.pollOptions[index].votes
            };
        }

        function voteTimelimitNotExceeded(previousVoteDate) {
            var now = moment().subtract('seconds', $scope.voteLimit.seconds).subtract('hours', $scope.voteLimit.hours).subtract('minutes', $scope.voteLimit.minutes);
            var lastVotedDate = moment(previousVoteDate);
            return now.diff(lastVotedDate) <= 0;
        }
        function fillOptions() {
            for (var i = 0; i < $scope.pollOptions.length; i++) {
                var opt = getDefaultOption(i);
                var voted = _.find($scope.previousVotes, function (op) { return op.optionId == opt.optionId; });
                if (voted) {
                    if ($scope.allowMultiple) {
                        if (voteTimelimitNotExceeded(voted.lastVoted)) {
                            opt.votingBlocked = true;
                            $scope.showPollAnswered = true;
                        }
                    } else {
                        opt.votingBlocked = true;
                        $scope.votingBlocked = true;
                        $scope.showPollAnswered = true;
                    }
                }
                $scope.options.push(opt);
            }

            if (!$scope.manyOptions) {
                var t = _.find($scope.options, function (op) { return op.votingBlocked == true; });
                if (t) {
                    $scope.showPollAnswered = true;
                    $scope.options.forEach(function (item) {
                        item.radioChosen = item.votingBlocked ? false : true;
                    });
                }
                
            }
        }
        function initVotes() {
            $scope.pollOptions.forEach(function (item) {
                $scope.totalVotes += item.votes;
            });
            $scope.pollOptions.forEach(function (item) {
                item.progressPercent = $scope.totalVotes > 0 ? (item.votes / $scope.totalVotes) * 100 : 0;
                item.progressWidth = item.progressPercent + "%";
                if (item.votes > $scope.maxVotes) {
                    $scope.maxVotes = item.votes;
                }
            });

            $scope.pollOptions.forEach(function (item) {
                item.progressRelative = $scope.maxVotes > 0 ? (item.votes / $scope.maxVotes) * 100 : 0;
                item.progressRelativeWidth = item.progressRelative + "%";
            });
        }

        function setVotesAndUpdateCookie(option) {
            $scope.totalVotes++;
            option.votes++;
            option.votingBlocked = true;
            option.isSelected = false;
            var pv = $cookieStore.get(votedCookieName) || [];
            var filtered = _.filter(pv, function (op) { return op.optionId != option.optionId; });
            filtered.push({ optionId: option.optionId, lastVoted: new Date() });
            $cookieStore.put(votedCookieName, filtered);
            //toaster.pop("success", "Valik: " + option.optionName, languageOptions.voteSuccess);
            $scope.showPollAnswered = true;
        }

        function vote() {
            if (!$scope.selectedVotes.length > 0) return;
            var promises = [];
            for (var j = 0; j < $scope.selectedVotes.length; j++) {
                (function (realIndex) {
                    var option = _.find($scope.options, function (op) { return op.optionId == $scope.selectedVotes[realIndex]; });
                    promises.push(mediapollService.postVote($scope.pollId, $scope.selectedVotes[realIndex]).then(function(data) {
                        if (data.data == "\"FAIL\"") {
                            //toaster.pop("error", "Valik: " + getName(realIndex), languageOptions.voteFailed);
                        } else {
                            setVotesAndUpdateCookie(option);
                        }
                    }));
                })(j);
            }
            promisesHandler(promises);
        }

        function promisesHandler(promises) {
            $q.all(promises).then(function () {
                $scope.selectedVotes = [];
                if (!$scope.manyOptions) {
                    $scope.options.forEach(function (item) {
                        item.radioChosen = item.votingBlocked ? false : true;
                    });
                }
            });
        }

        function getName(index) {
            var id = $scope.selectedVotes[index];
            var obj = findOption(id);
            if (angular.isDefined(obj)) {
                return obj.optionName;
            }
            return "";
        }

        function findOption(id) {
            for (var j = 0; j < $scope.options.length; j++) {
                var ref = $scope.options[j];
                if (ref.optionId == id) {
                    return ref;
                }
            }
            return undefined;
        }

        function setVote(index) {
            var ref = $scope.options[index];
            if (ref.votingBlocked || ref.radioChosen) return;
            if ($scope.manyOptions) {
                if (ref.isSelected) {
                    _removeFromSelected(ref);
                } else {
                    _addToSelected(ref);
                }
            } else {
                if (ref.isSelected) {
                    _removeFromSelected(ref);
                } else {
                    _clearOptions();
                    _addToSelected(ref);
                }
            }
        }
        function _clearOptions() {
            for (var j = 0; j < $scope.options.length; j++) {
                _removeFromSelected($scope.options[j]);
            }
        }
        function _removeFromSelected(ref) {
            for (var j = 0; j < $scope.selectedVotes.length; j++) {
                if ($scope.selectedVotes[j] == ref.optionId) {
                    $scope.selectedVotes.splice(j, 1);
                    ref.displayText = languageOptions.selectMe;
                    ref.isSelected = false;
                    return;
                }
            }
        }

        function _addToSelected(ref) {
            $scope.selectedVotes.push(ref.optionId);
            ref.displayText = languageOptions.selected;
            ref.isSelected = true;
        }

        function getVoteTimeLimitObject(vl) {
            if (!vl) return vl;
            var splitted = vl.split(":");
            if (splitted.length != 3) throw new Error("unexpected length: votelimit");
            return { hours: parseInt(splitted[0]), minutes: parseInt(splitted[1]), seconds: parseInt(splitted[2]) };
        }
    }
})();
;
(function () {
    'use strict';
    var serviceId = 'mediapollService';
    angular.module('app').factory(serviceId, ['$http', mediapollService]);

    function mediapollService($http) {
        var service = {
            postVote: postVote
        };
        return service;

        function postVote(pollId, optionId) {
            var url = "/api/loader/postvote?pollPublicId=" + pollId + "&optionPublicId=" + optionId;
            return $http({ method: "POST", url: url }).success(function(data) {
            }).error(function(data) {
                console.log(data);
            });
        }
    }
})();;
(function () {
    'use strict';

    var controllerId = 'playlistCtrl';

    angular.module('app').controller(controllerId, ['$scope', '$attrs', '$timeout', 'playlistService', playlistCtrl]);

    function playlistCtrl($scope, $attrs, $timeout, playlistService) {
        $scope.settings = {};
        $scope.airInfo = { start: 0, end: 5 };
        $scope.programSelected = programSelected;
        $scope.playlist = {};
        $scope.dmy = "DD.MM.YYYY";
        $scope.firstload = true;
        var langs = ['et', 'en-GB', 'ru'];
        var culture = parseInt($attrs.culture);
        $scope.airTimesNextItems = airTimesNextItems;
        $scope.maxItemCount = maxItemCount;
        $scope.airData = {};
        $scope.currentYear = "";

        $scope.playlistSelected = function () {
            unSetSelected();
            $scope.firstload = false;
            $scope.dataLoaded = true;
            $scope.loadTimer = $timeout(callAtTimeout, 1000);
            $scope.airInfo.selectedValue.isSelected = true;
            var searchRequest = {
                radioSeriesId: $scope.programs.selectedProgram.RadioSeriesId,
                channel: $scope.settings.radioChannel,
                date: $scope.airInfo.selectedValue.AirDate
            };
            playlistService.getPlaylistForProgram(searchRequest).then(playListReceived);
        }
        function initSettings() {
            $scope.settings.radioChannel = $attrs.radiochannel;
            $scope.settings.selectedProgram = $attrs.selectedprogram;
            $scope.settings.airItemsDisplayAmount = parseInt($attrs.airitemsdisplayamount);
            $scope.settings.showAll = $attrs.showall;
            var date = new Date();
            $scope.numberOfYears = date.getFullYear() - 2013;
        }

        $scope.displaySettings = function () {
            console.log($scope.settings);
        }
        $scope.channelChanged = channelChanged;
        $scope.chooseYear = chooseYear;
        $scope.programs = {};

        function callAtTimeout() {
            $scope.dataLoaded = false;
        }

        function unSetSelected() {
            for (var i = 0; i < $scope.airInfo.airTimes.length; i++) {
                $scope.airInfo.airTimes[i].isSelected = false;
            }
        }

        function maxItemCount() {
            if ($scope.airInfo.airTimes != undefined) {
                var airInfoLength = $scope.airInfo.airTimes.length;
                if (airInfoLength % $attrs.airitemsdisplayamount == 0) {
                    return airInfoLength;
                } else {
                    return airInfoLength + ($attrs.airitemsdisplayamount - airInfoLength % $attrs.airitemsdisplayamount);
                }
            }
        }

        function programSelected() {
            $scope.programs.selectedProgram = _.find($scope.programs.values, function (p) { return p.CategoryId == $scope.programs.selectedValue; });

            $scope.playlist = {};
            if ($scope.programs.selectedProgram != undefined && $scope.programs.selectedProgram.RadioSeriesId != "unresolved") {
                playlistService.getAirTimeForProgram($scope.programs.selectedProgram.RadioSeriesId, $scope.settings.radioChannel, $scope.settings.showAll).then(airTimesReceived);
            }
            if ($scope.programs.selectedProgram != undefined && $scope.programs.selectedProgram.RadioSeriesId == "unresolved") {
                $scope.playlist = {
                    Header: "NO INFO",
                    Description: "this > saated category has no RADIOSERIESID specified"
                }
                $scope.airInfo.airTimes = [];
                console.log("PROGRAM IS IN LIST BUT HAS NO RADIOSERIESID SET IN ADMIN");
            }
        }

        function channelChanged() {
            playlistService.getProgramsForChannel($scope.settings.radioChannel).then(fillDependant);
        }

        init();

        function airTimesNextItems(forward) {
            var newstart;
            if (forward) {
                newstart = $scope.airInfo.start + $scope.settings.airItemsDisplayAmount;
                if (newstart < $scope.airInfo.airTimes.length) {
                    setAirInfo(newstart, ($scope.airInfo.end + $scope.settings.airItemsDisplayAmount));
                }
            } else {
                newstart = $scope.airInfo.start - $scope.settings.airItemsDisplayAmount;
                if (newstart >= 0) {
                    setAirInfo(newstart, ($scope.airInfo.end - $scope.settings.airItemsDisplayAmount));
                } else {
                    setAirInfo();
                }
            }
        }

        function init() {
            initSettings();
            setAirInfo();
            channelChanged();
        }
        function setAirInfo(start, end) {
            if (start == undefined && end == undefined) {
                $scope.airInfo.start = 0;
                $scope.airInfo.end = $scope.settings.airItemsDisplayAmount;
            } else {
                $scope.airInfo.start = start;
                $scope.airInfo.end = end;
            }
        }
        function fillDependant(data) {
            setAirInfo();
            $scope.programs.values = data;
            //if the dependant contains an entry specified in frontui it should get selected, otherwise selected the first item
            var selected = _.find($scope.programs.values, function (p) { return p.ParentId == $scope.settings.selectedProgram; });

            $scope.programs.selectedValue = (selected == undefined) ? $scope.programs.values[0].CategoryId : selected.CategoryId;
            programSelected();
        }

        function airTimesReceived(data) {
            $scope.airData = data;
            var date = new Date();
            $scope.chooseYear(date.getFullYear(), true);
        }

        function chooseYear(year, fromtoday) {
            var startDate = new Date(year, 0, 1);
            var endDate = new Date();
            if (!fromtoday) {
                endDate = new Date(year, 11, 31);
            }
            var data = chooseDates(startDate, endDate);

            if ($scope.settings.showAll == "True") {
                var futureDate = new Date();
                futureDate.setDate(futureDate.getDate() + 14);
                data = chooseDates(startDate, futureDate);
            }
            $scope.currentYear = year;
            $scope.airInfo.selectedValue = data[0];

            
            var today = new Date().toISOString().substr(0, 10).replace('T', ' ');
            var ShowOnToday = null;

            for (var i = 0; i < data.length; i++) {
                if (data[i].AirDate.substr(0,10) == today) {
                    $scope.airInfo.selectedValue = data[i];
                    ShowOnToday = true;
                    break;
                }
            }

            if (ShowOnToday == null) {
                for (var i = 0; i < data.length; i++) {
                    if (moment() > moment(data[i].AirDate)) {
                        $scope.airInfo.selectedValue = data[i];
                        break;
                    }
                }
            }
            $scope.airInfo.airTimes = data;
            setAirTimesItems();
        }

        function setAirTimesItems() {
            if ($scope.airInfo.airTimes.length > 0 && $scope.programs.selectedProgram != undefined) {
                var searchRequest = {
                    radioSeriesId: $scope.programs.selectedProgram.RadioSeriesId,
                    channel: $scope.settings.radioChannel,
                    date: $scope.airInfo.selectedValue.AirDate
                };
                playlistService.getPlaylistForProgram(searchRequest).then(playListReceived);
            }
        }

        function chooseDates(startDate, endDate) {
            var airData = $scope.airData;
            var chosenDates = [];
            for (var i = 0; i < airData.length; i++) {
                var nowDate = Date.parse(airData[i].AirDate);
                if (nowDate > startDate && nowDate < endDate) {
                    chosenDates.push(airData[i]);
                }
            }
            return chosenDates;
        }

        function playListReceived(results) {
            removeProgramNameFromPlaylist(results);
            setCorrectArtistAndSongName(results);
            $scope.playlists = results;

            $scope.dataLoaded = true;
            $timeout.cancel($scope.loadTimer);
        }

        function setCorrectArtistAndSongName(results) {
            if (results === undefined || results === null || results === "null") { return; }

            results.forEach(function(playlist) {
                if (playlist.Musics != undefined) {
                    for (var i = 0; i < playlist.Musics.length; i++) {
                        var meta = playlist.Musics[i].meta;
                        var info = playlist.Musics[i].Info;
                        var si = {
                            title: "", artist: ""
                        }
                        if (meta != undefined) {
                            si.title = meta.SONGNAME;
                            si.artist = meta.PERFORMER;
                            playlist.Musics[i].si = si;
                            continue;
                        }
                        if (info != undefined) {
                            si.title = info.ITEMNAME1;
                            si.artist = info.ITEMNAME2;
                            playlist.Musics[i].si = si;
                        }
                    }
                }
            });
        }

        function removeProgramNameFromPlaylist(results) {

            if (results === undefined || results === null || results === "null") {
                return;
            }

            results.forEach(function(playlist) {
                if (playlist.Musics.length > 0) {
                    if (playlist.Musics[0].Info.ITEMNAME1 == playlist.Header) {
                        playlist.Musics.splice(0, 1);
                    }
                }
            });
        }

        $scope.toggleVisibilityForSettings = function () {
            $scope.showSettingsJson = !$scope.showSettingsJson;
        }
        $scope.toggleVisibilityForAirInfo = function () {
            $scope.showAirInfoJson = !$scope.showAirInfoJson;
        }
        $scope.toggleVisibilityForPrograms = function () {
            $scope.showProgramsJson = !$scope.showProgramsJson;
        }

        $scope.getNumber = function (num) {
            return new Array(num);
        }
    }
})();
;
(function () {
    'use strict';

    var serviceId = 'playlistService';

    angular.module('app').factory(serviceId, ['$http', '$q', playlistService]);

    function playlistService($http, $q) {
        var service = {
            getProgramsForChannel: getProgramsForChannel,
            getAirTimeForProgram: getAirTimeForProgram,
            getPlaylistForProgram: getPlaylistForProgram
        };
        var serviceEndPoints = {
            playlists: "/api/loader/playlistcategories/",
            airTime: "/api/loader/airtimesforprogram/",
            playlist: "/api/loader/playlistforprogram/"
        }
        return service;

        function getAirTimeForProgram(radioseriesid, channel, showAll) {
            var defer = $q.defer();
            $http({ method: "get", cache: true, url: serviceEndPoints.airTime + radioseriesid + "?channel=" + channel + "&showAll=" + showAll }).success(function (data) {
                defer.resolve(data);
            });
            return defer.promise;
        }

        function getProgramsForChannel(channel) {
            var defer = $q.defer();
            $http({ method: "get", cache: true, url: serviceEndPoints.playlists + channel + "?forpublic=true" }).success(function (data) {
                defer.resolve(data);
            });
            return defer.promise;
        }
        function getPlaylistForProgram(searchRequest) {
            var defer = $q.defer();
            if (searchRequest.date != undefined) {
                var d = moment(searchRequest.date);
                angular.extend(searchRequest, { day: d.date(), month: (d.month() + 1), year: d.year() });
            }
            var reqUrl = serviceEndPoints.playlist + searchRequest.radioSeriesId + "?channel=" + searchRequest.channel + "&day=" + searchRequest.day + "&month=" + searchRequest.month + "&year=" + searchRequest.year;
            $http({ method: "get", url: reqUrl }).success(function (data) { defer.resolve(data); }).error(function (data) { defer.reject("failed request"); });
            return defer.promise;
        }
    }
})();;
(function () {
    'use strict';
    var controllerId = 'pollCtrl';

    angular.module('app').controller(controllerId,
    ['$scope', '$attrs', 'pollService', 'ipCookie', pollController]);

    function pollController($scope, $attrs, pollService, ipCookie) {
        $scope.title = 'pollCtrl';
        var votedCookieName = "po_pv-" + $attrs.pollid;
        $scope.previousVotes = ipCookie(votedCookieName) || [];
        $scope.voteLimit = { hours: 0, minutes: 0, seconds: 0 };
        $scope.vg = $attrs.vg == "True";
        $scope.showPollOptions = true;
        $scope.disabled = true;
        $scope.showResults = false;
        $scope.pollId = $attrs.pollid;
        $scope.resultPage = resultPage;
        $scope.vote = vote;
        $scope.multipleVotes = false;
        $scope.selectedVotes = [];
        $scope.multiselect = false;
        $scope.selectionOption = "radio";
        $scope.selected = selected;
        $scope.imagetype = $attrs.imagetype;
        $scope.postedVotes = [];
        $scope.pollData = {};

        getPollVotes();

        function checkCookie() {
            var latestVote = getLatestVote($scope.previousVotes);
            if ($scope.previousVotes != 0) {
                if (voteTimelimitNotExceeded(latestVote) || !$scope.multiplevotes) {
                    resultPage();
                    return true;
                }
            }
            return false;
        }

        function getPollVotes() {
            pollService.getPollData($scope.pollId, $scope.imagetype).then(getPollSuccessHandler);
        }

        function getPollSuccessHandler(data) {
            findVotePercent(data);
            $scope.pollData = data;
            $scope.multipleVotes = data.AllowMultipleVotes;
            $scope.voteLimit = getVoteTimeLimitObject(data.VoteTimeLimit);
            $scope.multiselect = data.MultipleOptions;
            $scope.multiplevotes = data.AllowMultipleVotes;
            var isCookieSet = checkCookie();
          
            if (!isCookieSet) {
                $scope.showPollOptions = true;
                $scope.disabled = true;
                $scope.showResults = false;
            }

            if (data.MultipleOptions == true) {
                $scope.selectionOption = "checkbox";
            }
        }

        function findVotePercent(data) {
            for (var i = 0; i < data.Options.length; i++) {
                data.Options[i].Percent = ((data.Options[i].VoteCount / data.TotalVotes) * 100).toFixed(2) + "%";
            }
        }

        function setCookie(pollId, posted) {
            var previous = $scope.previousVotes;
            var filtered = $scope.previousVotes;
            if (!$scope.multiselect) {
                filtered = [
                    { optionId: posted[0], lastVoted: new Date() }
                ];
            } else {
                for (var i = 0; i < posted.length; i++) {
                    if (previous.length != 0 && previous[i] != undefined) {

                        if (!containsObject(previous, posted[i])) {
                            filtered.push({ optionId: posted[i], lastVoted: new Date() });
                        } else {

                            var index = findObjectIndex(filtered, posted[i]);
                            if (index == -1) {
                                console.log("FAIL");
                            } else {
                                filtered[index] = { optionId: posted[i], lastVoted: new Date() };
                            }
                        }
                    } else {
                        filtered.push({ optionId: posted[i], lastVoted: new Date() });
                    }
                }
            }
            var cookieName = "po_pv-" + pollId;
            var expirationMin = expirationMinutes();
            if (!$scope.multiplevotes) {
                ipCookie(cookieName, filtered, { expires: 1, expirationUnit: 'years' });
            } else {
                ipCookie(cookieName, filtered, { expires: expirationMin, expirationUnit: 'minutes' });
            }
        }

        function expirationMinutes() {
            if ($scope.voteLimit != null) {
                var limit = $scope.voteLimit;
                return limit.hours * 60 + limit.minutes;
            }
            return 0;
        }

        function findObjectIndex(filtered, value) {
            for (var i = 0; i < filtered.length; i++) {
                if (filtered[i].optionId == value) {
                    return i;
                }
            }
            return -1;
        }

        function containsObject(previous, value) {
            for (var i = 0; i < previous.length; i++) {
                if (previous[i].optionId == value) {
                    return true;
                }
            }
            return false;
        }

        function containsSelected(previous, value) {
            for (var i = 0; i < previous.length; i++) {
                if (previous[i] == value) {
                    return true;
                }
            }
            return false;
        }

        function resultPage() {
            $scope.showPollOptions = false;
            $scope.disabled = true;
            $scope.showResults = true;
        };

        function vote() {
            if ($scope.disabled != true) {
                for (var i = 0; i < $scope.selectedVotes.length; i++) {
                    pollService.tryPostPoll($scope.pollId, $scope.selectedVotes[i].PublicId).then(tryPostSuccessHandler($scope.selectedVotes[i]), tryPostFailHandler);
                }
                setCookie($scope.pollId, $scope.postedVotes);
                $scope.selectedVotes = [];
                resultPage();
            }
        }

        function tryPostSuccessHandler(selectedVote) {
            var voteIndex = $scope.pollData.Options.indexOf(selectedVote);
            $scope.pollData.Options[voteIndex].VoteCount++;
            $scope.pollData.TotalVotes++;
            findVotePercent($scope.pollData);
        }
        function tryPostFailHandler() {
            $scope.showPollOptions = true;
            $scope.disabled = false;
            $scope.showResults = false;
        }

        function selected(option) {
            if (containsSelected($scope.selectedVotes, option)) {
                var index = $scope.selectedVotes.indexOf(option);
                $scope.selectedVotes.splice(index, 1);
            } else {
                if ($scope.multiselect) {
                    $scope.selectedVotes.push(option);
                } else {
                    $scope.selectedVotes[0] = option;
                }
            }

            if ($scope.selectedVotes.length != 0) {
                $scope.disabled = false;
            } else {
                $scope.disabled = true;
            }
        };

        function voteTimelimitNotExceeded(previousVoteDate) {
            var now = moment().subtract('seconds', $scope.voteLimit.seconds).subtract('hours', $scope.voteLimit.hours).subtract('minutes', $scope.voteLimit.minutes);
            var lastVotedDate = moment(previousVoteDate);
            return now.diff(lastVotedDate) <= 0;
        }

        function getLatestVote(pastVotes) {
            var earliestDate = "1970-11-27T08:48:14.964Z";

            if (pastVotes.length == 1) {

                earliestDate = pastVotes[0].lastVoted;
            } else {
                for (var i = 0; i < pastVotes.length; i++) {
                    if (pastVotes[i].lastVoted > earliestDate) {
                        earliestDate = pastVotes[i].lastVoted;
                    }
                }
            }
            return earliestDate;
        }

        function getVoteTimeLimitObject(vl) {
            if (!vl) return vl;
            var splitted = vl.split(":");
            if (splitted.length != 3) throw new Error("unexpected length: votelimit");
            return { hours: parseInt(splitted[0]), minutes: parseInt(splitted[1]), seconds: parseInt(splitted[2]) };
        }
    }
})();;
(function () {
    'use strict';
    var serviceId = 'pollService';
    angular.module('app').service(serviceId, ['$http', '$q', pollService]);

    function pollService($http, $q) {
        var serviceHost = "/api/loader/";
        var service = {
            tryPostPoll: tryPostPoll,
            getPollData: getPollData
        };

        return service;
        function tryPostPoll(pollId, optId) {
            var defer = $q.defer();
            $http({ method: "POST", url: serviceHost + "postvote?pollPublicId=" + pollId + "&optionPublicId=" + optId }).success(function (data) {
                defer.resolve(data);
            }).error(function (status) {
                defer.reject(status);
            });
            return defer.promise;
        }

        function getPollData(pollId, imagetype) {
            var defer = $q.defer();
            $http({ method: "get", cache: false, url: serviceHost + "GetPollResult?id=" + pollId + "&imagetype=" + imagetype }).success(function (data) {
                defer.resolve(data);
            });
            return defer.promise;
        }
    }
})();;
(function () {
    'use strict';
    var controllerId = 'articleCtrl';
    angular.module('app').controller(controllerId,
    ['$scope', '$sce', articleController]);
    function articleController($scope, $sce) {
        $scope.title = 'articleCtrl';
        $scope.video = "";
        $scope.setMedia = function (value) {
            $scope.video = $sce.trustAsHtml(value);
        };
    }
})();
;
(function () {
    'use strict';
    var controllerId = 'forumViewCtrl';
    angular.module('app').controller(controllerId,
        ['$scope', '$attrs', forumViewController]);

    function forumViewController($scope, $attrs) {
        $scope.parentComment = null;
        $scope.replyName = null;
        $scope.commentstoshow = $attrs.commentstoshow;
        $scope.replaceCommenting = replaceCommenting;

        function replaceCommenting(replyToName, commentToAddUiBlock) {
            if ($scope.commentDiv == undefined) {
                $scope.commentDiv = document.getElementById(('commenting'));
            }
            if (replyToName != "") {
                //If answering to a childcomment
                if (replyToName.indexOf("/") != -1) {
                    $scope.replyName = replyToName.split('/')[1];
                    replyToName = replyToName.split('/')[0];
                }
                angular.element(document.getElementById('answer_' + commentToAddUiBlock)).append($scope.commentDiv);
                angular.element(document.getElementById('answer_' + commentToAddUiBlock)).css("display", "initial");
            } else {
                angular.element(document.getElementById('newComment')).append($scope.commentDiv);
            }
            $scope.parentComment = replyToName;
        }
    }
})();;
(function () {
    'use strict';
    var serviceId = 'forumService';
    angular.module('app').service(serviceId, ['$http', '$q', forumService]);

    function forumService($http, $q) {
        var serviceHost = "/api/loader/";
        var service = {
            getContent: getContent,
            tryPostComment: tryPostComment
        };

        return service;
        function tryPostComment(postable) {
            var defer = $q.defer();
            $http({ method: "POST", url: serviceHost + "postcomment", data: postable }).success(function (data) {
                defer.resolve(data);
            }).error(function (status) {
                defer.reject(status);
            });
            return defer.promise;
        }
        function getContent(guid, numberofcomments, language) {
            if (numberofcomments==undefined) {
                numberofcomments = 50;
            }
            return $http({ method: "GET", url: serviceHost + "getcontent?id=" + guid + "&numberOfComments=" + numberofcomments + "&language=" + language });
        }
    }
})();;
(function () {
    'use strict';

    var serviceId = 'forumBll';
    angular.module('app').factory(serviceId, ['$http', '$sce', forumBll]);
    function forumBll($http, $sce) {
        var service = {
            handleGetContent: handleGetContent
        };
        return service;
        function handleGetContent(data, $scope) {
            for (var i = 0; i < data.Comments.length; i++) {
                data.Comments[i].Text = $sce.trustAsHtml(data.Comments[i].Text.replace(/\n/g, '<br/>'));
            }
            $scope.forumheader = data.Header;
            $scope.comments = data.Comments;
            $scope.comments.totalCount = data.TotalCount;
            $scope.comments.redirectUrl = data.RedirectUrl;
            $scope.lead = $sce.trustAsHtml(data.Lead.replace(/\n/g, '<br/>'));
            $scope.redirectUrl = data.RedirectUrl;
            $scope.commentTotal = data.TotalCount;
        }
    }
})();;
(function() {
    'use strict';

    angular.module('app').directive('forumComments', ['$window', forumComments]);
    
    function forumComments ($window) {
        var directive = {
            link: link,
            restrict: 'AE',
            scope: {
                comments: "=",
                lead: "=",
                showlead:"=",
                showheader: "=",
                forumheader: "=",
                commentstoshow: "="
            },
            templateUrl: "/FrontUI/Templates/AngularTemplates/forummain"
        };
        return directive;

        function link(scope, element, attrs) {
        }
    }

})();;
(function () {
    'use strict';
    try {
        angular.module('app').directive('radioRds', ['$window', 'radioService', '$interval', radioRds]);
    } catch (ex) {
        angular.module('errMuuda').directive('radioRds', ['$window', 'radioService', '$interval', radioRds]);
    }

    function radioRds($window, radioService, $interval) {
        var directive = {
            link: link,
            restrict: 'AE',
            scope: {
                type: "=",
            },
            templateUrl: "/FrontUI/Templates/AngularTemplates/radiords"
        };
        return directive;

        function link(scope, element, attrs) {
            scope.type = getChannel(scope.type);
            scope.previousSongs = [];
            if (scope.type != "") {
                getContent(scope.type);
            }

            function getContent(type) {
                radioService.getRadioContent(type).then(handleRadioData).finally(function () {
                    startTimer(type);
                });
            }

            function handleRadioData(data) {
                var airitem = data.data.toString();
                if (airitem.length < 5) {
                    scope.onAir = null;
                } else {
                    if ($.inArray(airitem, scope.previousSongs) == -1) {

                        scope.onAir = replaceAllBackSlash(airitem.substr(1, airitem.length - 2));
                        if (scope.previousSongs.length == 5) {
                            scope.previousSongs.pop();
                        }
                        scope.previousSongs.push(airitem);
                    }
                }
            }

            function replaceAllBackSlash(targetStr) {
                var index = targetStr.indexOf("\\");
                while (index >= 0) {
                    targetStr = targetStr.replace("\\", "");
                    index = targetStr.indexOf("\\");
                }
                return targetStr;
            }

            function getChannel(type) {
                switch (type) {
                    case "klassika":
                        return "klassikaraadio";
                    case "raadio2":
                        return "raadio2";
                    case "viker":
                        return "vikerraadio";
                    case "raadio4":
                        return "raadio4";
                    case "r-tallinn":
                        return "raadiotallinn";
                    default:
                        return "";
                }
            }

            function startTimer(type) {
                scope.timer = $interval(function () {
                    radioService.getRadioContent(type).then(handleRadioData);
                }, 3 * 10000);
            };
        }
    }
})();;
(function () {
    'use strict';
    var serviceId = 'errCaptchaService';
    angular.module('app').service(serviceId, ['$http', '$q', errCaptchaService]);

    function errCaptchaService($http, $q) {
        var serviceHost = "/api/errcaptcha/";
        var service = {
            getCaptchaContent: getCaptchaContent,
            verifyCaptcha: verifyCaptcha
        };

        return service;
        function verifyCaptcha(postable) {
            var defer = $q.defer();
            $http({ method: "POST", url: serviceHost + "verifycaptcha?captchaId=" + postable.captchaId + "&answerId=" + postable.answerId }).success(function (data) {
                defer.resolve(data);
            }).error(function (status) {
                defer.reject(status);
            });
            return defer.promise;
        }
        function getCaptchaContent() {          
            return $http({ method: "GET", url: serviceHost + "getcaptcha" });
        }
    }
})();;
(function () {
    'use strict';

    var serviceId = 'errCaptchaBll';
    angular.module('app').factory(serviceId, ['$http', '$sce', forumBll]);
    function forumBll() {
        var service = {
            handleGetContent: handleGetContent
        };
        return service;
        function handleGetContent(data, $scope) {
            $scope.captchaid = data.CaptchaId;
            $scope.question = data.Question;
            $scope.answers = data.Answers;
        }
    }
})();;
(function () {
    'use strict';
    angular.module('app').directive('errCaptcha', ['$window', 'errCaptchaService', 'errCaptchaBll', '$interval', errCaptcha]);

    function errCaptcha($window, errCaptchaService, errCaptchaBll, $interval) {
        var directive = {
            link: link,
            restrict: 'AE',
            scope: {},
            templateUrl: "/FrontUI/Templates/AngularTemplates/errcaptcha"
        };
        return directive;

        function link(scope, element, attrs) {
            errCaptchaService.getCaptchaContent().then(handleCaptchaData).finally(function () {
                scope.startTimer();
            });

            function handleCaptchaData(data) {
                errCaptchaBll.handleGetContent(data.data, scope);
            }

            scope.clicked = function (val) {
                if (val != undefined)
                    scope.selected = val;
            }

            scope.startTimer = $interval(function () {
                errCaptchaService.getCaptchaContent().then(handleCaptchaData);
            }, 300000);

            scope.cancelTimer = function () {
                $interval.cancel(scope.startTimer);
            }

            window.ErrCaptcha = {
                refresh: function () {
                    scope.selected = undefined;
                    scope.cancelTimer();
                    errCaptchaService.getCaptchaContent().then(handleCaptchaData).finally(function () {
                        scope.startTimer();
                    });
                }
            }
        }
    }
})();;

/*** This file is generated automatically, do not edit it as changes will not be preserved ***/


/*!** Module: language ***/


/*!** Source: src/language/module.js ***/

; (function (angular) {
    'use strict';

    /**
	 * @ngdoc module
	 * @name language
	 *
	 * @description
	 * Language selector
	 */
    angular.module('battlesnake.language', []);

})(window.angular);


/*!** Source: src/language/language-service.js ***/

; (function (angular, _) {
    'use strict';

    angular.module('battlesnake.language')
		.factory('languageService', languageService)
		.value('fallbackLanguages', ['en'])
		.factory('defaultLanguage', defaultLanguageGetter)
    ;

    function defaultLanguageGetter($locale) {
        return $locale.id;
    }
    defaultLanguageGetter.$inject = ["$locale"];

    function languageService(fallbackLanguages, defaultLanguage) {
        /* Wraps a strings object[lang][id] in a getter function */
        return function languageWrapper(strings) {
            /*
			 * Gets string 'id' in given 'locale'.  If not found or if locale is
			 * not specified, then falls back to 'fallbackLanguage'.  If not
			 * found or fallbackLanguage is not specified, then falls backt to
			 * un-camelCased version of 'id'.
			 */
            return function languageStringGetter(id, locale) {
                var langs = _(fallbackLanguages).clone();
                langs.unshift(defaultLanguage);
                langs.unshift(locale);
                if (window.languageOverride) {
                    langs.unshift(window.languageOverride);
                }
                var string;
                for (var i = 0; i < langs.length; i++) {
                    if (string = get(langs[i])) {
                        return string;
                    }
                }
                console.error('languageService: no translation found for ' + id);
                return id.replace(/[a-z][A-Z]/g, '$1 $2');

                function get(locale) {
                    if (!locale) {
                        return null;
                    }
                    /* Try locale */
                    var string = strings[locale] && strings[locale][id];
                    /* Try language */
                    if (!string && locale.length > 2) {
                        var lang = locale.substr(0, 2);
                        string = strings[lang] && strings[lang][id];
                    }
                    /* Warn if not found */
                    if (!string) {
                        console.warn('languageService: string "' + id + '" not found for locale/language "' + locale + '"');
                    }
                    return string;
                }
            }
        };
    }
    languageService.$inject = ["fallbackLanguages", "defaultLanguage"];

})(window.angular, window._);

/*** This file is generated automatically, do not edit it as changes will not be preserved ***/


/*!** Module: date-picker ***/


/*!** Source: src/date-picker/module.js ***/

; (function (angular) {
    'use strict';

    /**
	 * @ngdoc module
	 * @name date-picker
	 *
	 * @description
	 * Date-picker widget
	 */
    angular.module('battlesnake.date-picker', ['battlesnake.language']);

})(window.angular);


/*!** Source: src/date-picker/datepicker-locale.js ***/

; (function (angular) {
    'use strict';

    angular.module('battlesnake.date-picker')
		.service('datePickerLocale', datePickerLocale);

    function datePickerLocale() {
        this.en = {
            today: 'Today',
            clear: 'Clear',
            close: 'Close'
        };
        this.et = {
            today: 'Täna',
            clear: 'Eemalda',
            close: 'Sulge'
        };
        this.ru = {
            today: 'Сегодня',
            clear: null,
            close: null
        };
    }

})(window.angular);


/*!** Source: src/date-picker/datepicker-directive.js ***/

; (function (angular, $, moment, _) {
    'use strict';

    angular.module('battlesnake.date-picker')
		.directive('jquiDatePicker', jquiDatePickerDirective);

    function jquiDatePickerDirective() {
        $("<style>.kartulita.ui-datepicker .ui-datepicker-next:before,.kartulita.ui-datepicker .ui-datepicker-prev:before { content: ''; }</style>").appendTo($('head'));

        return {
            restrict: 'A',
            require: 'ngModel',
            scope: {
                datePickerSelect: '&',
                datePickerActive: '=',
                datePickerAlign: '@'
            },
            link: link
        };

        /* Too lazy to code a separate controller */
        function link(scope, element, attrs, ngModel) {
            var loc_id = (moment.locale() || 'et').substr(0, 2);
            var locales = $.datepicker.regional || {};
            var config = _({}).extend(locales[loc_id], {
                dateFormat: 'yy-mm-dd',
                onSelect: viewValueChanged,
                showOptions: { direction: 'down' }
            });
            var container = angular.element('<div></div>')
				.css({
				    position: 'absolute',
				    display: 'inline-block',
				    top: 0,
				    left: 0
				})
				.addClass('ui-datepicker ui-widget kartulita')
				.datepicker(config)
            ;

            scope.$watch('datePickerActive', setActive);

            container.appendTo(angular.element('body'));

            return;

            function setActive(value) {
                /* Don't use display:none as it stops getBoundingClientRect from working */
                if (value) {
                    var p = element[0].getBoundingClientRect();
                    var c = container[0].getBoundingClientRect();
                    var x = p.left, y = p.top;
                    var align = scope.datePickerAlign || 'top left';
                    if (align.match(/\btop\b/)) {
                        y = p.bottom;
                    } else if (align.match(/\bbottom\b/)) {
                        y = p.top - (c.bottom - c.top);
                    }
                    if (align.match(/\bleft\b/)) {
                        x = p.left;
                    } else if (align.match(/\bright\b/)) {
                        x = p.right - (c.right - c.left);
                    }
                    x += window.scrollX, y += window.scrollY;
                    container
						.css({
						    left: x + 'px',
						    top: y + 'px',
						    zIndex: 999999,
						    visibility: 'visible'
						})
						.datepicker('setDate', ngModel.$modelValue.toDate())
                } else {
                    container.css({
                        visibility: 'hidden',
                        top: 0,
                        left: 0
                    });
                }
            }

            function viewValueChanged(value) {
                var value = moment(Date.parse(value));
                scope.$apply(function () {
                    ngModel.$setViewValue(value);
                    scope.datePickerActive = false;
                });
                scope.$apply(function () {
                    scope.datePickerSelect({ value: value });
                });
            }
        }
    }

})(window.angular, window.$, window.moment, window._);

/*** This file is generated automatically, do not edit it as changes will not be preserved ***/


/*!** Module: now-playing ***/


/*!** Source: src/now-playing/module.js ***/

; (function (angular) {
    'use strict';

    /**
	 * @ngdoc module
	 * @name now-playing
	 *
	 * @description
	 * "Now Playing" component with smart polling
	 */
    angular.module('battlesnake.now-playing', []);

})(window.angular);


/*!** Template: src/now-playing/now-playing-template.html ***/

; (function (angular) {
    'use strict';

    var html =

		'<!-- Now playing -->' +
		'<div class="now-playing" ng-class="{ \'empty\': model.empty }">' +
		'<!-- Extra container provided for CSS marquee and other tricks -->' +
		'<span class="now-playing-text-container">' +
		'<i class="icomoon-play now-playing-play-icon"></i>' +
		'<a class="now-playing-text" ng-href="{{ model.data.url }}" target="_blank" ng-if="model.data.url">{{ model.caption }}</a>' +
		'<span class="now-playing-text" ng-if="!model.data.url">{{ model.caption }}</span>' +
		'</span>' +
		'</div>';

    if (angular.version.minor < 3) {
        html = html.replace(/{\s*::\s*/g, '{ ').replace(/"\s*::\s*/g, '"');
    }

    angular.module('battlesnake.now-playing')
		.run(["$templateCache", function ($templateCache) {
		    $templateCache.put('now-playing-template.html', html)
		}]);

})(window.angular);

/*!** Source: src/now-playing/now-playing-directive.js ***/

; (function (angular) {
    'use strict';

    angular.module('battlesnake.now-playing')
		.directive('nowPlaying', nowPlayingDirective);

    function nowPlayingDirective() {
        return {
            restrict: 'A',
            require: 'nowPlaying',
            scope: {
                adapter: '=nowPlaying',
                onOpenItem: '&nowPlayingOpenItem'
            },
            templateUrl: 'now-playing-template.html',
            controller: 'nowPlayingController',
            link: link
        };

        function link(scope, element, attrs, controller) {
            controller.init(element);
        }
    }

})(window.angular);


/*!** Source: src/now-playing/now-playing-controller.js ***/

; (function (angular) {
    'use strict';

    angular.module('battlesnake.now-playing')
		.controller('nowPlayingController', nowPlayingController);

    function nowPlayingController($scope, $timeout, $q) {
        var element;
        var scope = $scope;

        $scope.model = {
            data: null,
            caption: '',
            empty: true
        };

        $scope.methods = {
            openItem: openItem
        };

        var updateTimer;

        this.init = initController;
        return;

        function initController(element_) {
            element = element_;
            resetModel();
            scope.$watch('adapter', adapterChanged);
        }

        function adapterChanged() {
            resetModel();
            if (scope.adapter) {
                poll();
            }
        }

        function resetModel() {
            setEmpty();
            stopTimer();
        }

        function setEmpty() {
            $scope.model.data = null;
            $scope.model.caption = '';
            $scope.model.empty = true;
        }

        function setTimer(delay) {
            stopTimer();
            updateTimer = $timeout(poll, delay);
        }

        function stopTimer() {
            if (updateTimer) {
                $timeout.cancel(updateTimer);
                updateTimer = null;
            }
        }

        function poll() {
            return $q.when(scope.adapter.update())
				.then(updateData)
				.catch(pollFailed);
        }

        function updateData(data) {
            var old = scope.model.caption;
            var value = data.caption;
            scope.model.caption = data.empty ? '' : (value || '');
            scope.model.empty = data.hasOwnProperty('empty') ? data.empty : !scope.model.caption.length;
            scope.model.data = data || {};
            if (data.delay) {
                setTimer(data.delay);
            } else if (old === value) {
                setTimer(scope.adapter.delayNoUpdate || 5000);
            } else {
                setTimer(scope.adapter.delayUpdate || 60000);
            }
        }

        function openItem() {
            scope.onOpenItem({ data: scope.model.data });
        }

        function pollFailed() {
            setEmpty();
        }
    }
    nowPlayingController.$inject = ["$scope", "$timeout", "$q"];

})(window.angular);

/*** This file is generated automatically, do not edit it as changes will not be preserved ***/


/*!** Module: timeline ***/


/*!** Source: src/timeline/module.js ***/

; (function (angular) {
    'use strict';

    /**
	 * @ngdoc module
	 * @name timeline
	 *
	 * @description
	 * Timeline widget
	 *
	 * @example
	 * See demos/index.html
	 */
    angular.module('battlesnake.timeline', ['ngTouch', 'battlesnake.language', 'battlesnake.date-picker']);

})(window.angular);


/*!** Template: src/timeline/timeline-template.html ***/

; (function (angular) {
    'use strict';

    var html =

		'<!-- Timeline -->' +
		'<div class="timeline" ondragstart="return false;" ondrop="return false;">' +
		'<div class="timeline-goto" ng-class="{ open: view.datePicker.isOpening }" ' +
		'ng-click="view.datePicker.toggle()" ' +
		'ng-if="!noCalender" ' +
		'jqui-date-picker ' +
		'ng-model="view.datePicker.value" ' +
		'date-picker-active="view.datePicker.isOpen" ' +
		'date-picker-align="top right" ' +
		'date-picker-select="view.datePicker.select()">' +
		'<a href="javascript://" class="open-button"></a>' +
		'</div>' +
		'<!-- Scroll control\'s container -->' +
		'<div class="timeline-stream-container">' +
		'<a href="javascript://" class="timeline-nav prev"></a>' +
		'<a href="javascript://" class="timeline-nav next"></a>' +
		'<!-- Scroll control -->' +
		'<div timeline-groups class="timeline-groups">' +
		'<!-- group in model.groups -->' +
		'<div timeline-group class="timeline-group">' +
		'<div class="timeline-group-title">' +
		'<span class="timeline-group-title-dims">' +
		'{{ :: group.date | timelineGroupWhen:model.groupBy }} ' +
		'</span>' +
		'</div>' +
		'<!-- items <- getItems(group.date) -->' +
		'<div timeline-items items-per-row="2" class="timeline-items">' +
		'<!-- item in items -->' +
		'<div class="timeline-item-container" ' +
		'ng-class="{ current: isCurrent(item) }" ' +
		'ng-swipe-left="methods.prev()" ' +
		'ng-swipe-right="methods.next()">' +
		'<!-- Item (no directive needed for this) -->' +
		'<a timeline-item class="timeline-item" href="javascript://" ' +
		'ng-click="methods.openItem(item)">' +
		'<!-- Image URL -->' +
		'<img ng-if=":: !item._isSprite" ' +
		'ng-src="{{ (isCurrent(item) ? item.activeThumbnail : null) || item.thumbnail }}" ' +
		'alt="{{ :: item.title }}" ' +
		'class="timeline-item-thumbnail" ' +
		'ondragstart="return false;" ondrop="return false;">' +
		'<!-- Image is CSS sprite -->' +
		'<div ng-if=":: item._isSprite" ' +
		'class="timeline-item-thumbnail" ' +
		'ng-style="(isCurrent(item) ? item.activeThumbnail : null) || item.thumbnail">' +
		'</div>' +
		'<div class="media-icons timeline-item-states">' +
		'<!-- Playable -->' +
		'<div class="playable media-icon icomoon-play" ' +
		'ng-if="item.playable && !isCurrent(item)"></div>' +
		'<!-- Show is currently playing: show play button -->' +
		'<div class="current" ng-if="isCurrent(item)">' +
		'<span class="media-icon icomoon-play"></span>' +
		'{{ :: strings(\'playLive\') }} ' +
		'</div>' +
		'</div>' +
		'<!-- Hover-over info -->' +
		'<div class="timeline-item-header">' +
		'<div class="timeline-item-time">' +
		'{{ :: item.start | timelineItemWhen:model.groupBy }} ' +
		'</div>' +
		'<div class="timeline-item-title">' +
		'{{ :: item.title }} ' +
		'</div>' +
		'<div class="timeline-item-state-icon icomoon-play" ' +
		'ng-if="item.playable">' +
		'</div>' +
		'</div>' +
		'</a>' +
		'</div>' +
		'</div>' +
		'</div>' +
		'</div>' +
		'</div>' +
		'</div>';

    if (angular.version.minor < 3) {
        html = html.replace(/{\s*::\s*/g, '{ ').replace(/"\s*::\s*/g, '"');
    }

    angular.module('battlesnake.timeline')
		.run(["$templateCache", function ($templateCache) {
		    $templateCache.put('timeline-template.html', html)
		}]);

})(window.angular);

/*!** Source: src/timeline/items-controller.js ***/

; (function (angular) {
    'use strict';

    angular.module('battlesnake.timeline')
		.controller('timelineItemsController', timelineItemsController);

    /* Must also be configured in the LESS file */
    var rowCount = 2;

    function timelineItemsController($scope, $timeout) {
        var scope = $scope;
        var element;
        var transclude;

        var debouncer;

        this.init = initController;
        return;

        function initController(_element, _transclude) {
            element = _element;
            transclude = _transclude;

            rebuildList();
            scope.$on('currentChanged', debouncedRebuildList);
        }

        function debouncedRebuildList() {
            if (debouncer) {
                return;
            } else {
                rebuildList();
                debouncer = true;
                $timeout(function () { debouncer = null; }, 100);
            }
        }

        /* Rebuild the view */
        function rebuildList() {
            var items = scope.items;

            var columnElement;
            var rows;
            var currentIndex = getCurrentIndex();

            element.empty();
            newRow();
            prependPhantoms();
            addItems();
            appendPhantoms();

            return;

            /* Get index of currently playing item (or -1 if none found) */
            function getCurrentIndex() {
                for (var i = 0; i < items.length; i++) {
                    if (scope.isCurrent(items[i])) {
                        return i;
                    }
                }
                return -1;
            }

            /*
			 * Prepend a phantom if currently-active item is not a first-row
			 * item, so we don't have gaps next to the currently-active item
			 */
            function prependPhantoms() {
                var phantoms = currentIndex === -1 ? 0 : currentIndex % rowCount;
                while (phantoms--) {
                    addPhantom();
                }
            }

            /* Add items */
            function addItems() {
                for (var i = 0; i < items.length; i++) {
                    addItem(items[i], i === currentIndex);
                }
            }

            /* Fill last row with phantoms */
            function appendPhantoms() {
                while (rows !== 0) {
                    addPhantom();
                }
            }

            /* Low-level: start new column */
            function newRow() {
                rows = 0;
            }

            /* Low-level: Move to next row, wrap if needed */
            function nextRow() {
                if (++rows >= rowCount) {
                    newRow();
                }
            }

            /* Low-level: add to row, create new column element if needed */
            function addToRow(item) {
                if (rows === 0) {
                    columnElement = angular.element('<div/>')
						.addClass('timeline-items-column');
                    element.append(columnElement);
                }
                columnElement.append(item);
                nextRow();
            }

            /* Low-level: add item */
            function addItem(item) {
                var current = scope.isCurrent(item);
                if (current) {
                    newRow();
                }
                var itemScope = scope.$new();
                itemScope.item = item;
                item._isSprite = typeof item.thumbnail === 'object';
                transclude(itemScope, function (clone, scope) {
                    addToRow(clone);
                    if (current) {
                        scope.$emit('setCurrentItemElement', clone.find('*[timeline-item]'));
                    }
                });
                if (current) {
                    newRow();
                }
            }

            /* Low-level: add phantom */
            function addPhantom() {
                var item = angular.element('<div class="timeline-item-container phantom"/>');
                addToRow(item);
            }

        }

    }
    timelineItemsController.$inject = ["$scope", "$timeout"];

})(window.angular);


/*!** Source: src/timeline/group-directive.js ***/

; (function (angular, _) {
    'use strict';

    angular.module('battlesnake.timeline')
		.directive('timelineGroup', timelineGroupDirective);

    function timelineGroupDirective() {
        return {
            restrict: 'A',
            priority: 10,
            require: 'timelineGroup',
            controller: 'timelineGroupController',
            transclude: true,
            link: link
        };

        function link(scope, element, attrs, controller, transclude) {
            controller.init(element, transclude);
        }
    }

})(window.angular, window._);


/*!** Source: src/timeline/group-controller.js ***/

; (function (angular, _) {
    'use strict';

    angular.module('battlesnake.timeline')
		.controller('timelineGroupController', timelineGroupController);

    function timelineGroupController($scope, $q) {
        var scope = $scope;
        var element;
        var transclude;
        var itemsElement;

        this.init = initController;
        return;

        function initController(_element, _transclude) {
            element = _element;
            transclude = _transclude;
            loadGroup();
        }

        function loadGroup() {
            if (!scope.api) {
                return;
            }
            var group = scope.group;
            var date = group.date;
            /*
			 * We get adjacent groups and filter to ensure that group groups
			 * correspond to the local time-zone.  Since the front-end
			 * service caches group data, this won't result in redundant
			 * requests to the back-end, and also serves to pre-load
			 * adjacent groups if not already loaded.
			 */
            var groupsToGet = [
				date.clone().subtract(1, scope.model.groupBy),
				date,
				date.clone().add(1, scope.model.groupBy)
            ];
            /* Map groups to promises and process result */
            $q.when(null)
				.then(function () {
				    group.loading = true;
				    scope.$emit('groupLoading');
				})
				.then(function () {
				    return $q.all(groupsToGet.map(scope.api.getGroup));
				})
				.then(function (data) { return [].concat.apply([], data); })
				.then(filterData)
				.then(sortData)
				.then(createChildren)
				.then(function () { group.loaded = true; })
				.catch(function () {
				    group.failed = true;
				    scope.$emit('groupLoadFailed');
				    scope.$destroy();
				    element.remove();
				})
				.finally(function () {
				    group.loading = false;
				    scope.$emit('groupLoaded', element);
				})
            ;

            return;

            function filterData(data) {
                return _(data)
					.filter(isNow);

                function isNow(item) {
                    return date.isSame(item.start, scope.model.groupBy);
                }
            }

            function sortData(data) {
                return _(data)
					.sort(momentComparator);

                function momentComparator(a, b) {
                    return a.start.diff(b.start);
                }
            }

            function createChildren(data) {
                /*
				 * If no data available, assume no data is available for
				 * this group and notify the controller
				 */
                if (!data.length) {
                    return $q.reject('No data');
                }
                /* Store data and create subelements if needed */
                scope.items = data;
                if (!itemsElement) {
                    transclude(scope, function (clone, scope) {
                        itemsElement = clone.appendTo(element);
                    });
                }

                return;
            }
        }

    }
    timelineGroupController.$inject = ["$scope", "$q"];

})(window.angular, window._);


/*!** Source: src/timeline/timeline-locale.js ***/

; (function (angular) {
    'use strict';

    angular.module('battlesnake.timeline')
		.factory('timelineLocale', timelineLocale);

    /*
	 * Declared once and outside the factory since the injector hack used by
	 * timeline-adapter would otherwise get a new instance of the translations
	 */
    var strings = {
        en: {
            playLive: 'Now playing',
            today: 'Today',
            groupWhenFormat: 'dddd DD.MM',
            itemWhenFormat: 'HH:mm',
        },
        et: {
            /* battlesnake.err:timeline-adapter modifies/decorates playLive for radio channels */
            playLive: 'Vaata otse',
            today: 'Täna',
            groupWhenFormat: 'dddd DD.MM',
            itemWhenFormat: 'HH:mm',
        },
        ru: {
            playLive: 'Прямой эфир',
            today: 'Сегодня',
            groupWhenFormat: 'dddd DD.MM',
            itemWhenFormat: 'HH:mm',
        }
    };

    function timelineLocale() {
        return strings;
    }

})(window.angular);


/*!** Source: src/timeline/groups-controller.js ***/

; (function (angular, _) {
    'use strict';

    angular.module('battlesnake.timeline')
		.controller('timelineGroupsController', timelineGroupsController);

    function timelineGroupsController($scope) {
        var scope = $scope;

        var element;
        var transclude;

        var groupCache = {};

        this.init = initController;
        return;

        function initController(_element, _transclude) {
            element = _element;
            transclude = _transclude;
            /* Event handlers */
            scope.$on('groupsChanged', updateGroups);
            scope.$on('modelReset', clearCache);
        }

        /* Create elements as needed */
        function updateGroups() {
            _(scope.model.groups).each(updateGroupElement);
        }

        /* Create element for a group if needed, does not delete/update */
        function updateGroupElement(group) {
            var date = group.date;
            var key = dateToKey(date);
            var cacheLine;
            if (_(groupCache).has(key)) {
                return;
            } else {
                cacheLine = {
                    serial: date.toDate().getTime(),
                    generation: scope.model.resetCount,
                    element: null,
                    scope: null
                };
                groupCache[key] = cacheLine;
            }
            var itemScope = scope.$new();
            itemScope.group = group;
            transclude(itemScope, function (clone, scope) {
                scope.key = key;
                cacheLine.element = clone;
                cacheLine.scope = scope;
                var position = findGroupElementPosition(date);
                if (position.prev) {
                    clone.insertAfter(position.prev.last());
                } else if (position.next) {
                    clone.insertBefore(position.next.first());
                } else {
                    clone.appendTo(element);
                }
            });
        }

        /* Create cache key for a date (must be chronologically sortable) */
        function dateToKey(date) {
            return date.format('YYYY-MM-DD HH:mm');
        }

        /* Find the elements that a group should be inserted between */
        function findGroupElementPosition(date) {
            var ticks = date.toDate().getTime();
            var res = _(groupCache)
				.reduce(function (memo, cacheLine) {
				    var serial = cacheLine.serial;
				    var prev = memo.prev;
				    var next = memo.next;
				    if (serial < ticks && (!prev || serial > prev.serial)) {
				        memo.prev = cacheLine;
				    }
				    if (serial > ticks && (!next || serial < next.serial)) {
				        memo.next = cacheLine;
				    }
				    return memo;
				}, { prev: null, next: null });
            if (res.prev) {
                res.prev = res.prev.element;
            }
            if (res.next) {
                res.next = res.next.element;
            }
            return res;
        }

        /* Empty the cache */
        function clearCache() {
            _(groupCache).each(function (line, key) {
                delete groupCache[key];
                line.element.remove();
                line.scope.$destroy();
            });
        }

    }
    timelineGroupsController.$inject = ["$scope"];

})(window.angular, window._);


/*!** Source: src/timeline/timeline-directive.js ***/

; (function (angular) {
    'use strict';

    angular.module('battlesnake.timeline')
		.directive('timeline', timelineDirective);

    function timelineDirective() {
        return {
            restrict: 'A',
            require: 'timeline',
            controller: 'timelineController',
            scope: {
                adapter: '=timeline',
                onOpenItem: '&timelineOpenItem',
                initialDate: '@timelineInitialDate',
                groupBy: '@timelineGroupBy',
                noCalendar: '@timelineNoCalendar'

            },
            templateUrl: 'timeline-template.html',
            link: link
        };

        function link(scope, element, attrs, controller) {
            controller.init(element);
        }
    }

})(window.angular);


/*!** Source: src/timeline/items-directive.js ***/

; (function (angular) {
    'use strict';

    angular.module('battlesnake.timeline')
		.directive('timelineItems', timelineItemsDirective);

    function timelineItemsDirective() {
        return {
            restrict: 'A',
            priority: 10,
            require: 'timelineItems',
            controller: 'timelineItemsController',
            transclude: true,
            link: link
        };

        function link(scope, element, attrs, controller, transclude) {
            controller.init(element, transclude);
        }
    }

})(window.angular);


/*!** Source: src/timeline/groups-directive.js ***/

; (function (angular, _) {
    'use strict';

    angular.module('battlesnake.timeline')
		.directive('timelineGroups', timelineGroupsDirective);

    function timelineGroupsDirective() {
        return {
            restrict: 'A',
            priority: 10,
            require: 'timelineGroups',
            controller: 'timelineGroupsController',
            transclude: true,
            link: link
        };

        function link(scope, element, attrs, controller, transclude) {
            controller.init(element, transclude);
        }
    }

})(window.angular, window._);


/*!** Source: src/timeline/timeline-filters.js ***/

; (function (angular, moment) {
    'use strict';

    angular.module('battlesnake.timeline')
		.filter('timelineGroupWhen', timelineGroupWhenFilter)
		.filter('timelineItemWhen', timelineItemWhenFilter)
    ;

    function timelineGroupWhenFilter(languageService, timelineLocale) {
        var lang = languageService(timelineLocale);
        return function (when, groupBy) {
            return when.isSame(moment(), groupBy) ?
				lang('today') :
				when.format(lang('groupWhenFormat')).replace(/^[a-z]/, function (c) { return c.toUpperCase(); });
        };
    }
    timelineGroupWhenFilter.$inject = ["languageService", "timelineLocale"];

    function timelineItemWhenFilter(languageService, timelineLocale) {
        var lang = languageService(timelineLocale);
        return function (when) {
            return when.format(lang('itemWhenFormat'));
        };
    }
    timelineItemWhenFilter.$inject = ["languageService", "timelineLocale"];

})(window.angular, window.moment);


/*!** Source: src/timeline/timeline-service.js ***/

; (function (angular, _, moment) {
    'use strict';

    angular.module('battlesnake.timeline')
		.factory('timelineService', timelineService);

    /*
	 * Use the "timeline" attribute directive to specify the source to use
	 */
    function timelineService() {

        return {
            connect: connect
        };

        function connect(adapter) {
            var source = {
                adapter: adapter,
                cache: {},
                loading: {}
            };
            var cache = source.cache;
            var loading = source.loading;

            _(adapter.preloaded).each(function (datum) {
                cacheData(getKey(datum.date), datum.data);
            });

            return {
                getGroup: getGroup,
                getCurrent: getCurrent
            };

            function getGroup(date) {
                date = moment(date);
                var key = getKey(date);
                /* Check cache */
                if ((adapter.canCache && adapter.canCache(key)) && _(cache).has(key)) {
                    return cache[key];
                }
                /* See if data is loading already */
                if (_(loading).has(key)) {
                    return loading[key];
                }
                /* Get from backend */
                return loading[key] = adapter.getGroup(date)
					.then(dataLoaded)
					.then(function (data) { return cacheData(key, data); })
					.catch(function () { return cacheData(key, []); });

                function dataLoaded(data) {
                    delete loading[key];
                    return data;
                }
            }

            function getKey(date) {
                return moment(date).format('YYYY-MM-DD HH:mm:ss');
            }

            function cacheData(key, data) {
                cache[key] = data;
                return data;
            }

            function getCurrent() {
                var now = moment();
                return _.find(
					[].concat.apply([], _(cache).values())
						.sort(function (a, b) {
						    return b.start.unix() - a.start.unix();
						}),
					function (item) {
					    return item.start.isBefore(now);
					}
				);
            }
        }
    }

})(window.angular, window._, window.moment);


/*!** Source: src/timeline/timeline-controller.js ***/

; (function (angular, moment, _, $, window) {
    'use strict';

    angular.module('battlesnake.timeline')
		.controller('timelineController', timelineController);

    /*
	 * We REALLY need to move the scroll logic out to a completely separate
	 * component (virtual-list).  This controller would be so much cleaner and
	 * the virtual-list component would be handy to have in other places too.
	 */

    function timelineController($scope, $timeout, $interval, $window, $swipe, languageService, timelineLocale, timelineService, timelineAnimatorFactory) {
        var scope = $scope;

        var defaultGroupBy = 'day';

        /* l10n */
        scope.strings = languageService(timelineLocale);

        /* Public viewmodel - this object is also used by child directives */
        scope.model = {
            reset: resetModel,
            /* Grouping */
            groupBy: null,
            /* Currently playing item */
            current: null,
            /* Initial date (now / @initial-date / date chosen in date-picker) */
            initialDate: null
        };

        /* High-level methods for manipulating the view state */
        scope.methods = {
            /* Simple navigation */
            prev: prevScreen,
            next: nextScreen,
            changeScreen: changeScreen,
            /* Mousewheel */
            wheel: wheelHandler,
            /* Precise movement */
            scrollBy: scrollBy,
            scrollTo: scrollTo,
            /* User activated a timeline-item */
            openItem: openItem
        };

        /* Helper function to detect if a timeline-item is currently airing */
        scope.isCurrent = isCurrent;

        /* View stuff */
        /* (TODO: Move scrollbox logic to separate directive) */
        scope.view = {
            reset: resetView,
            /* Animator for scroll position */
            position: timelineAnimatorFactory.create(scrollChanged, scrollEvent),
            /* User has nagivated (either scrolled or used date-picker) */
            userHasNavigated: false,
            /* X-coordinate of first item (the reference position for scrolling) */
            getOrigin: getOrigin,
            /* When origin is changed, this is updated to provide a delta */
            originOffset: 0,
            /* Reference element */
            reference: null,
            /* Center reference element (for position = zero) */
            referenceCentered: false,
            /* Main container for timeline */
            mainContainer: null,
            /* Element to scroll */
            scrollContainer: null,
            /* Element corresponding to currently playing item */
            currentItemElement: null,
            /* Date picker */
            datePicker: {
                reset: resetDatePicker,
                isOpen: false,
                value: null,
                select: datePickerSelect,
                toggle: toggleDatePicker
            },
            /* Touch events */
            touch: {
                start: touchStart,
                move: touchMove,
                end: touchEnd,
                cancel: touchCancel,
                memo: null
            },
            /*  Touch events on nav buttons */
            navTouch: {
                start: navTouchStart,
                end: navTouchEnd,
                cancel: navTouchCancel,
                memo: {
                    direction: 0,
                    timer: null,
                    start: null
                }
            }
        };

        /* How far to scroll on wheel notch */
        var screensPerWheelDelta = 0.2;
        /* Used for "currently playing" checker */
        var currentInterval;
        /* Current item */
        var current = null;

        /*
		 * Try to detect failed backend connection so we avoid spamming with
		 * doomed requests
		 */
        var earlyFailCount = 0;
        var disableLoading = false;

        this.init = initController;
        return;

        /* Util */

        function $immediate(fn) {
            $timeout(fn, 0);
        }

        function $delay(fn, delay) {
            var timer = null;
            return function () {
                if (timer) {
                    return;
                } else {
                    timer = $timeout(function () {
                        timer = null;
                        fn();
                    }, delay);
                }
            };
        }

        function $debounce(fn, delay) {
            var timer = null;
            return function () {
                if (timer) {
                    return;
                } else {
                    fn();
                    timer = $timeout(function () {
                        timer = null;
                    }, delay);
                }
            };
        }

        /* Initialiser */

        function initController(element) {
            scope.initController = null;
            scope.view.mainContainer = element;
            scope.view.scrollContainer = scope.view.mainContainer.find('.timeline-groups');
            scope.$watch('adapter', adapterChanged);
            scope.$watch('groupBy', scope.model.reset);
            /* Touch events */
            $swipe.bind(scope.view.mainContainer, scope.view.touch, ['touch', 'mouse']);
            $swipe.bind(element.find('.timeline-nav'), scope.view.navTouch, ['touch', 'mouse']);
            /* Scope observers */
            scope.$on('groupLoaded', groupLoaded);
            scope.$on('groupLoadFailed', groupLoadFailed);
            scope.$on('setCurrentItemElement', setCurrentItemElement);
            $(window).bind('resize', $debounce(windowResized, /WebKit/i.test(window.navigator.userAgent) ? 1000 / 60 : 1000 / 10));
        }

        function windowResized() {
            /* Update scroll (in case reference element is centered) */
            updateScrollOffset();
        }

        /* Adapter */
        function adapterChanged() {
            if (scope.adapter) {
                scope.api = timelineService.connect(scope.adapter);
            } else {
                scope.api = null;
            }
            scope.model.reset();
            scope.$broadcast('adapterChanged');
        }

        /*
		 * Emergency bailout, prevents us spamming requests if backend is broken
		 */
        function groupLoadFailed() {
            if (scope.model.groups.length < 5 && ++earlyFailCount >= 5) {
                disableLoading = true;
                scope.model.groups.length = 0;
            }
        }

        /* Geometry */

        function getPageWidth() {
            return scope.view.mainContainer.innerWidth();
        }

        function getViewWidth() {
            return scope.view.scrollContainer.outerWidth(true);
        }

        /* Model */

        function ItemGroup(date) {
            this.date = date;
            this.loading = false;
            this.loaded = false;
            this.failed = false;
            if (Object.seal) {
                Object.seal(this);
            }
        }

        function resetModel(initialDate) {
            /* Grouping */
            scope.model.groupBy = scope.groupBy || defaultGroupBy;
            /* Notify children */
            scope.$broadcast('modelReset');
            /* Re-zero the view */
            scope.view.reset();
            /* Set initial date */
            scope.model.initialDate = initialDate || null;
            setInitialGroup();
        }

        /*
		 * Resets view to just show the initial group, which will trigger the
		 * loading of adjacent groups as needed to fill the view
		 */
        function setInitialGroup() {
            /*
			 * Stylesheet load check:
			 * Shouldn't be needed, but the shitty .NET system occasionally
			 * fails to provide stylesheets, preventing the groups from stacking
			 * horizontally, and thus resulting in the backend being spammed
			 * with requests for more group data
			 */
            if (scope.view.scrollContainer.outerWidth() === 0) {
                $timeout(setInitialGroup, 50);
                return;
            }
            /* Get initial group to show */
            var date = moment(scope.model.initialDate || scope.initialDate || moment())
				.clone().local().startOf(scope.model.groupBy);
            scope.model.initialDate = date;
            /* Store reference date */
            scope.model.refDate = date;
            /* Array of dates of groups to display */
            scope.model.groups = [new ItemGroup(date)];
            /* Reset current item */
            setCurrent(null);
            /* Notify child scopes of changes */
            groupsChanged();
            /* Reset early fail count for error bailout */
            earlyFailCount = 0;
            disableLoading = false;
        }

        function gotoDate(value) {
            if (!value) {
                return;
            }
            scope.model.reset(moment(value));
            scope.view.userHasNavigated = true;
        }

        /* Number of groups that are loading */
        function groupsLoading() {
            var groups = _(scope.model.groups).where({ loading: true });
            return groups ? groups.length : 0;
        }

        /* Number of groups that have loaded */
        function groupsLoaded() {
            var groups = _(scope.model.groups).where({ loaded: true });
            return groups ? groups.length : 0;
        }

        function groupLoaded(event, element) {
            /* Set group as reference if none has been acquired yet */
            if (!scope.view.reference) {
                setOriginElement(element, false, false);
            }
            /* Update currently-airing */
            updateCurrent();
            /* Update scroll position */
            updateScrollOffset();
        }

        /* Periodically check which show is currently playing and update view */
        function updateCurrent() {
            if (!currentInterval) {
                currentInterval = $interval(updateCurrent, 5000);
                scope.$on('$destroy', function () {
                    $interval.cancel(currentInterval);
                    currentInterval = null;
                });
            }
            setCurrent(scope.api.getCurrent());
        }

        function setCurrent(value) {
            var old = current;
            if (old === value) {
                return;
            }
            current = value;
            scope.view.currentItemElement = null;
            if (isCurrent(old)) {
                return;
            }
            scope.$broadcast('currentChanged');
            if (!scope.view.userHasNavigated) {
                scrollToCurrentItem(false);
            }
        }

        /* Fuzzy comparison to see if item is currently showing */
        function isCurrent(item) {
            return sameItemFuzzy(item, current);
        }

        /* Do not depend on reference equality */
        function sameItemFuzzy(a, b) {
            return a === b || (a && b &&
				a.start.unix() === b.start.unix() &&
				a.id == b.id);
        }

        function scrollToCurrentItem(immediate) {
            var el = scope.view.currentItemElement;
            if (!el) {
                $timeout(function () { scrollToCurrentItem(immediate); }, 50);
                return;
            }
            setOriginElement(el, true, true);
        }

        /* Observers */

        function groupsChanged() {
            scope.$broadcast('groupsChanged');
        }

        function setCurrentItemElement(event, element) {
            var isInitial = !scope.view.currentItemElement;
            scope.view.currentItemElement = element;
            /* Let reflow happen first */
            $immediate(function () {
                if (!scope.view.userHasNavigated) {
                    scrollToCurrentItem(isInitial);
                }
            });
        }

        /* Load more data */

        function loadPastGroup() {
            var groups = scope.model.groups;
            if (disableLoading || groups.length && groups[0].failed) {
                return;
            }
            groups.unshift(new ItemGroup(groups[0].date.clone().subtract(1, scope.model.groupBy)));
            groupsChanged();
        }

        function loadFutureGroup() {
            var groups = scope.model.groups;
            if (disableLoading || groups.length && groups[groups.length - 1].failed) {
                return;
            }
            groups.push(new ItemGroup(groups[groups.length - 1].date.clone().add(1, scope.model.groupBy)));
            groupsChanged();
        }

        /* Event handler to open an item when tapped/clicked */
        function openItem(item) {
            scope.onOpenItem({ item: item });
        }

        /* Date picker */

        function datePickerSelect() {
            gotoDate(scope.view.datePicker.value);
        }

        function resetDatePicker() {
            scope.view.datePicker.isOpen = false;
            scope.view.datePicker.value = moment();
        }

        function toggleDatePicker() {
            var dp = scope.view.datePicker;
            if (dp.isOpen) {
                dp.isOpen = false;
            } else {
                /* Should we set the value here? (note: there is a watcher on the value */
                dp.isOpen = true;
            }
        }

        /* Called by the animator: updates view and triggers loading of more groups if needed */

        function scrollChanged(current, target) {
            if (!arguments.length) {
                if (!scope.view.position.value) {
                    scrollToCurrentItem(true);
                    return;
                }
                current = scope.view.position.value.current || 0;
                target = scope.view.position.value.target || 0;
            }
            var pageWidth = getPageWidth();
            var viewWidth = getViewWidth();
            var origin = scope.view.getOrigin();
            /* Bounds checking */
            var min = -origin, max = viewWidth - pageWidth - origin;
            if (target > max) {
                target = max;
            }
            if (target < min) {
                target = min;
            }
            var position = {
                current: current,
                target: target
            };
            /* Store and update position */
            updateScrollOffset(position);
            /* Return valid */
            return target;
        }

        /* Gets the absolute scroll offset */
        function getScrollOffset() {
            var current = scope.view.position.value ? scope.view.position.value.current : 0;
            var offset = current + scope.view.getOrigin() + scope.view.originOffset;
            return offset;
        }

        /* Update scroll offset in view, set and store position if specified */
        function updateScrollOffset(position) {
            /*
			 * We don't use angular binding/interpolation for this as it would
			 * murder animation performance due to $digest loops running in each
			 * frame.  Also, some bindings aren't updated during touch events
			 * (e.g. ngStyle).
			 */
            if (position) {
                /* Store position */
                scope.view.position.value = position;
            }
            var offset = getScrollOffset();
            /* Ensure at least one group title is wholly visible in the view */
            keepAtLeastOneGroupTitleInView();
            /* Set position in view */
            scope.view.scrollContainer.css({
                transform: 'translateX(%px)'.replace('%', -offset)
            });
            /* Load more groups if needed  */
            ensureViewIsFilled();
        }

        /* Ensures that we have enough data in the view to fill it */
        function ensureViewIsFilled() {
            var pageWidth = getPageWidth();
            var viewWidth = getViewWidth();
            if (!scope.view.position.value) {
                return;
            }
            var offset = scope.view.position.value.target + scope.view.originOffset + scope.view.getOrigin();
            var loadNextThreshold = pageWidth + 300;
            /* Some limits to prevent us from flooding the backend */
            if (scope.view.reference && groupsLoading() <= 2 && groupsLoaded() > 0) {
                /* Force $apply for these */
                if (offset < loadNextThreshold) {
                    trackDeferred(loadPastGroup);
                }
                if (offset > (viewWidth - loadNextThreshold)) {
                    trackDeferred(loadFutureGroup);
                }
            }
            return;

            /* Prevents mass calling of the same function due to the same causes */
            function trackDeferred(fn) {
                if (fn.$deferredPending) {
                    return;
                }
                fn.$deferredPending = true;
                $immediate(function () {
                    try {
                        fn();
                    } finally {
                        fn.$deferredPending = false;
                    }
                });
            }
        }

        function keepAtLeastOneGroupTitleInView() {
            var offset = getScrollOffset();
            var width = getPageWidth();
            var groupElements = scope.view.mainContainer.find('.timeline-group');
            groupElements.each(function () {
                updateTitlePosition(angular.element(this), offset, width);
            });
            return;

            function updateTitlePosition(element, offset, width) {
                var e_l = element.position().left - offset;
                var e_w = element.innerWidth();
                var e_r = e_l + e_w;
                var title = element.find('.timeline-group-title');
                var t_w = title.find(':first-child').outerWidth(true);

                /*     OFF-LEFT | IN VIEW | OFF-RIGHT */
                /* 1.        <--|title--> |           */
                /* 2.    <-----t|tle>     |           */
                /* 3.           | <title--|-->        */
                /* 3.           |     <tit|e----->    */
                /* 3.           |         | <title... */
                /* 4. ...title> |         |           */
                if (e_l <= 0 && e_r >= t_w) {
                    /* Case 1 */
                    title.css({ transform: 'translateX(' + (-e_l) + 'px)' });
                } else if (e_l < 0 && e_r > 0) {
                    /* Case 2 */
                    title.css({ transform: 'translateX(' + (e_w - t_w) + 'px)' });
                } else if (e_l > 0) {
                    /* Case 3 */
                    title.css({ transform: 'translateX(0)' });
                } else {
                    /* Case 4 */
                    title.css({ transform: 'translateX(' + (e_w - t_w) + 'px)' });
                }
            }
        }

        function scrollEvent(event) {
            /* Run outside angular-land */
        }

        /* High-level scroll methods */

        function resetView() {
            scope.view.referenceCentered = false;
            scope.view.reference = null;
            scope.view.originOffset = 0;
            scope.view.userHasNavigated = false;
            scope.view.position.reset();
            scope.view.datePicker.reset();
        }

        function prevScreen(event) {
            if (event) {
                event.preventDefault();
            }
            changeScreen(-1);
        }

        function nextScreen(event) {
            if (event) {
                event.preventDefault();
            }
            changeScreen(+1);
        }

        function wheelHandler(event, delta) {
            changeScreen(-delta * screensPerWheelDelta);
            event.stopPropagation();
            event.preventDefault();
        }

        /*
		 * Sets the origin element.  If one was previously set, originOffset is
		 * adjusted so that the scroll offset (calculated in updateScrollOffset)
		 * remains the same.  Hence we can change the origin and anchor without
		 * affecting the final scroll offset.
		 */
        function setOriginElement(element, centered, rezeroOffset) {
            /*
			 * If an origin element is already assigned, then update the delta-
			 * offset (originOffset) with the position difference between the
			 * old origin and the new one.
			 */
            var translate = !!scope.view.reference && !rezeroOffset;
            var oldOrigin, newOrigin;
            if (translate) {
                oldOrigin = getOrigin(true);
            }
            scope.view.reference = element;
            scope.view.referenceCentered = centered;
            if (rezeroOffset) {
                scope.view.originOffset = 0;
            }
            if (!element) {
                return;
            }
            if (translate) {
                newOrigin = getOrigin(true);
                scope.view.originOffset += (oldOrigin - newOrigin);
            }
            updateScrollOffset();
        }

        function getOrigin(absolute) {
            /*
			 * Could use string and el[posFn], but this should be a little
			 * faster
			 */
            var posFn = absolute ? function (el) { return el.offset(); } :
				function (el) { return el.position(); };
            var element = scope.view.reference;
            var centered = scope.view.referenceCentered;
            if (!element) {
                return 0;
            } else {
                var left = posFn(element).left;
                if (!centered) {
                    return left;
                } else {
                    var pageWidth = getPageWidth();
                    var width = element.outerWidth();
                    return left - (pageWidth - width) / 2;
                }
            }
        }

        /* Touch-and-hold support for navigation buttons */

        function navTouchStart(r, event) {
            if (scope.view.navTouch.memo) {
                navTouchEnd();
            }
            scope.view.navTouch.memo = {
                direction: angular.element(event.target).hasClass('prev') ? -1 : +1,
                timer: setInterval(navTouchUpdate, 100),
                start: new Date().getTime()
            };
            navTouchUpdate();
            if (event) {
                event.preventDefault();
            }
        }

        function navTouchEnd(r, event) {
            var memo = scope.view.navTouch.memo;
            if (!memo.timer) {
                return;
            }
            clearInterval(memo.timer);
            memo.timer = null;
            var dt = new Date().getTime() - memo.start;
            if (dt > 400) {
                changeScreen(0, true);
            }
            if (event) {
                event.preventDefault();
            }
            scope.view.navTouch.memo = null;
        }

        function navTouchCancel(r, event) {
            navTouchEnd(r, event);
        }

        function navTouchUpdate() {
            changeScreen(scope.view.navTouch.memo.direction, true);
        }

        /* Touch events for swipe/drag in the main area */

        function touchStart(r) {
            scope.view.touch.memo = {
                start: {
                    x: r.x,
                    time: seconds()
                },
                last: {
                    x: r.x
                }
            };
        }

        function touchMove(r) {
            if (!scope.view.touch.memo) {
                return;
            }
            var dx = scope.view.touch.memo.last.x - r.x;
            scope.view.touch.memo.last = {
                x: r.x
            };
            scope.methods.scrollBy(dx, true);
            scope.view.userHasNavigated = true;
        }

        function touchEnd(r) {
            touchStop(r, false);
        }

        function touchCancel(r) {
            touchStop(r, true);
        }

        function touchStop(r, cancel) {
            if (!scope.view.touch.memo) {
                return;
            }
            if (!cancel) {
                /* Swipe detection */
                var dx = -(r.x - scope.view.touch.memo.start.x);
                var dt = seconds() - scope.view.touch.memo.start.time;
                var ax = Math.abs(dx);
                var v = ax / dt;
                /* Distance+velocity threshold and time limit for swipe */
                if (dt > 0 && dt < 0.3 && v > 1100 && ax > 50) {
                    $timeout(function () {
                        scope.methods.changeScreen(dx / ax);
                    }, 30);
                } else if (ax > 0) {
                    touchMove(r);
                }
            }
            scope.view.touch.memo = null;
        }

        /* Scroll by arbitrary blocks (positive direction = right) */
        function changeScreen(blocks, rel) {
            var pageWidth = getPageWidth();
            var scrollQuantum = pageWidth * 2 / 3;
            scrollBy(blocks * scrollQuantum, false, rel);
            scope.view.userHasNavigated = true;
        }

        /* Scroll by pixels (positive direction = right) */
        function scrollBy(delta, immediate, rel) {
            if (rel) {
                scope.view.position.increl(delta);
            } else {
                scope.view.position.inc(delta, immediate);
            }
        }

        /* Scroll to the specified offset target */
        function scrollTo(target, immediate) {
            scope.view.position.set(target, immediate);
        }

        function seconds() {
            return new Date().getTime() / 1000;
        }

    }
    timelineController.$inject = ["$scope", "$timeout", "$interval", "$window", "$swipe", "languageService", "timelineLocale", "timelineService", "timelineAnimatorFactory"];

})(window.angular, window.moment, window._, window.$, window);


/*!** Source: src/timeline/timeline-animator.js ***/

; (function (angular, requestAnimationFrame) {
    'use strict';

    angular.module('battlesnake.timeline')
		.factory('timelineAnimatorFactory', timelineAnimatorFactory);

    function timelineAnimatorFactory() {
        return {
            create: function (onValidate, onEvent) {
                return new TimelineAnimator(onValidate, onEvent);
            }
        };
    }

    function TimelineAnimator(onValidate, onEvent) {
        /* Constants */
        /* dx/dt = clamp(Dx * moveRate, minSpeed, maxSpeed), note: moveRate has unit /s */
        var moveRate = 5;
        /* Speed limits (pixels/s) */
        var minSpeed = 150, maxSpeed = 1200;
        /* How close we have to be to the target for scrolling to stop */
        var stopThreshold = 1;

        /* Variables */
        var current = 0;
        var target = 0;
        var animating = false;
        var t_last = 0;
        var t_start, t_start_perf;

        return {
            reset: reset,
            get: get,
            set: set,
            inc: inc,
            increl: increl,
            revalidate: revalidate
        };

        function reset() {
            set(0, true);
        }

        function get(immediate) {
            return immediate ? current : target;
        }

        function set(value, immediate) {
            if (immediate === 'animating') {
                current = value;
                startAnimation();
            } else if (immediate) {
                current = value;
                target = value;
                stopAnimation();
            } else {
                target = value;
                startAnimation();
            }
            revalidate();
            onEvent('changed', current, target);
        }

        function revalidate() {
            var val = onValidate(current, target);
            if (typeof val === 'number' && target !== val) {
                target = val;
                startAnimation();
            }
        }

        function inc(delta, immediate) {
            set(get(immediate) + delta, immediate);
        }

        /* Increase relative to view position, not target position */
        function increl(delta) {
            set(get(true) + delta, false);
        }

        function requestFrame() {
            if (requestAnimationFrame) {
                /* Workaround for iPad Safari not supporting window.performance.now() */
                var nextFrame = function (t_abs) {
                    var t = t_abs - t_start_perf;
                    var dt = t - t_last;
                    t_last = t;
                    animateFrame(dt / 1000);
                };
                requestAnimationFrame(function (t_start) {
                    if (t_start_perf) {
                        nextFrame(t_start);
                    } else {
                        t_start_perf = t_start;
                        requestAnimationFrame(nextFrame);
                    }
                });
            } else {
                setTimeout(function () {
                    var t_abs = new Date().getTime();
                    var t = t_abs - t_start;
                    var dt = t - t_last;
                    t_last = t;
                    animateFrame(dt / 1000);
                }, 1000 / 60);
            }
        }

        function startAnimation() {
            if (!animating) {
                animating = true;
                onEvent('start');
                t_start = new Date().getTime();
                t_start_perf = null;
                t_last = 0;
                requestFrame();
            }
        }

        function stopAnimation() {
            if (animating) {
                animating = false;
                onEvent('stop');
            }
        }

        function animateFrame(dt) {
            if (!animating) {
                return;
            }
            /* Geometry */
            var direction = target === current ? 0 : target > current ? +1 : -1;
            var delta = (target - current) * moveRate;
            /* Enforce minimum speed */
            var absDelta = Math.abs(delta);
            if (absDelta === 0) {
                stopAnimation();
                return;
            }
            if (absDelta < minSpeed) {
                delta *= minSpeed / absDelta;
            }
            if (absDelta > maxSpeed) {
                delta *= maxSpeed / absDelta;
            }
            /* Apply change */
            var next = current + dt * delta;
            /* We passed or reached the target */
            var remaining = target - next;
            if (remaining * direction <= 0 || Math.abs(remaining) < stopThreshold) {
                set(target, true);
            } else {
                set(next, 'animating');
                requestFrame();
            }
        }
    }

})(window.angular, window.requestAnimationFrame);


/*** This file is generated automatically, do not edit it as changes will not be preserved ***/


/*!** Module: show-viewer ***/


/*!** Source: src/show-viewer/module.js ***/

; (function (angular) {
    'use strict';

    /**
	 * @ngdoc module
	 * @name show-viewer
	 *
	 * @description
	 * Displays information about shows and allows viewing/streaming
	 */
    angular.module('battlesnake.show-viewer', ['battlesnake.language']);

})(window.angular);


/*!** Template: src/show-viewer/show-viewer-template.html ***/

; (function (angular) {
    'use strict';

    var html =

		'<div class="show-viewer row">' +
		'<!-- Show image/media viewer -->' +
		'<div class="span6 media-column" ng-if="show.media || show.image">' +
		'<div class="show-media">' +
		'<img ng-if="show.image && !activeSource" class="show-media-image" ng-src="{{ show.image }}" width="100%">' +
		'<div class="show-media-live-container" ng-if="activeSource">' +
		'    <div class="player">' +
        '    </div>' +
		'</div>' +
		'<div class="show-media-sources" ng-if="show.media.sources.length > 1">' +
		'<a ng-repeat="source in show.media.sources" class="show-media-source" ng-class="{ selected: (activeSource === source) }" ng-click="selectSource(source, null)" href="javascript://">' +
		'{{ source.name || (\'#\' + ($index + 1)) }} ' +
		'</a>' +
		'</div>' +
		'<div class="show-media-active-title" ng-if="activeSourceTitle">' +
		'{{ activeSourceTitle }} ' +
		'</div>' +
		'</div>' +
		'</div>' +
		'<!-- Show info -->' +
		'<div class="span6 info-column">' +
		'<div class="show-info">' +
		'<!-- Title -->' +
		'<a class="show-target-link" ng-href="{{ show.targetUrl }}">' +
		'<h3 class="show-title">' +
		'{{ show.title }} ' +
		'</h3>' +
		'</a>' +
		'<!-- Start time -->' +
		'<div class="meta">' +
		'<div class="show-timestamp timestamp">' +
		'{{ show.start | showViewerDateTime }} ' +
		'</div>' +
		'</div>' +
		'<!-- Show description -->' +
		'<div class="show-description lead" ng-bind-html="show.description"></div>' +
		'<!-- Links menu -->' +
		'<div class="show-links-menu dropdown" ng-if="show.links && show.links.menu" dropdown>' +
		'<button type="button" class="btn dropdown-toggle" dropdown-toggle>' +
		'{{ show.links.menuTitle }} ' +
		'</button>' +
		'<ul class="dropdown-menu show-links-menu-items">' +
		'<li ng-repeat="link in show.links.menu" class="show-link" ng-class="link.class">' +
		'<a ng-href="{{ link.url }}" class="link-heading" title="{{ link.title }}" target="_blank">' +
		'<i ng-class="link.iconClass" ng-if="link.iconClass"></i>' +
		'{{ link.title }} ' +
		'</a>' +
		'<span class="btn" class="show-link-action" ng-repeat="action in link.actions" ng-href="{{ action.url }}" ng-class="action.class">' +
		'{{ action.title }} ' +
		'</span>' +
		'</li>' +
		'</ul>' +
		'</div>' +
		'<!-- Links list -->' +
		'<div class="show-links-list" ng-if="show.links && show.links.list">' +
		'<div class="show-link" ng-repeat="link in show.links.list" ng-class="link.class">' +
		'<a href="javascript://" ng-click="selectSource(link.obj, link.title)" class="link-heading" title="{{ link.title }}" ng-class="{ active: (activeSource === link.url) }">' +
		'<i ng-class="link.iconClass" ng-if="link.iconClass"></i>' +
		'{{ link.title }} ' +
		'</a>' +
		'<span ng-if="link.actions && link.actions.length">' +
		'&nbsp;&mdash;&nbsp; ' +
		'</span>' +
		'<a ng-repeat="action in link.actions" ng-href="{{ action.url }}" class="show-link-action" ng-class="action.class">' +
		'{{ action.title }} ' +
		'</a>' +
		'</div>' +
		'</div>' +
		'<!-- Programme homepage -->' +
		'<div class="show-category-link" ng-if="show.categoryUrl">' +
		'<a ng-href="{{ show.categoryUrl }}" class="marker-more">' +
		'{{ strings(\'programmeHomepage\') }} ' +
		'</a>' +
		'</div>' +
		'<!-- Open channel in new window -->' +
		'<div class="show-channel-link" ng-if="show.channelUrl && show.media.getIsPlaying()">' +
		'<a ng-href="{{ show.channelUrl }}" target="_blank">' +
		'{{ strings(\'openInNewWindow\') }} ' +
		'</a>' +
		'</div>' +
		'</div>' +
		'<!-- Playlist viewer -->' +
		'<div class="playlist-container" ' +
		'ng-if="show.playlist && (!canShowPlaylist || canShowPlaylist(show, playlist))">' +
		'<label class="btn">' +
		'<!-- Apologies for the inline CSS, but this button should never need to be shown, and my stylesheet seems to be overridden by a site-specific one at ERR -->' +
		'<input type="checkbox" class="playlist-toggle" ng-model="view.showPlaylist" style="display:none">' +
		'{{ strings(\'showPlaylist\') }} ' +
		'</label>' +
		'<div ng-if="view.showPlaylist" class="playlist">' +
		'<div class="playlist-item" ng-repeat="item in show.playlist.items">' +
		'<span class="playlist-field time timestamp-no-overflow-base bold" ng-if="item.time && showTimesInPlaylist">' +
		'{{ item.time }} ' +
		'</span>' +
		'<span class="playlist-field title">' +
		'{{ item.title }} ' +
		'</span>' +
		'</div>' +
		'</div>' +
		'</div>' +
		'<!-- Alternative media formats -->' +
		'<div class="media-formats" ng-if="show.media.formats">' +
		'<div class="category">' +
		'{{ strings(\'alternativeListening\') }} ' +
		'</div>' +
		'<a class="format btn" ng-repeat="format in show.media.formats" ng-href="{{ format.url }}" target="_blank">' +
		'{{ format.codec }} {{ format.bitrate }}K ' +
		'</a>' +
		'</div>' +
		'</div>' +
		'</div>';

    if (angular.version.minor < 3) {
        html = html.replace(/{\s*::\s*/g, '{ ').replace(/"\s*::\s*/g, '"');
    }


    angular.module('battlesnake.show-viewer')
		.run(["$templateCache", function ($templateCache) {
		    $templateCache.put('show-viewer-template.html', html)
		}]);

})(window.angular);

/*!** Source: src/show-viewer/show-viewer-locale.js ***/

; (function (angular) {
    'use strict';

    angular.module('battlesnake.show-viewer')
		.service('showViewerLocale', showViewerLocale);

    /*
	 * Declared once and outside the factory since the injector hack used by
	 * show-viewer-adapter would otherwise get a new instance of the translations
	 */
    var strings = {
        en: {
            openInNewWindow: 'Open in new window',
            programmeHomepage: 'Programme page',
            alternativeListening: 'Alternative listening options',
            showPlaylist: 'Show playlist',
            download: 'Download'
        },
        et: {
            openInNewWindow: 'Ava uues aknas',
            programmeHomepage: 'Saatesarja kodulehele',
            alternativeListening: 'Alternatiivsed kuulamise variandid',
            showPlaylist: 'Näita lugusid',
            download: 'Lae alla'
        },
        ru: {
            openInNewWindow: 'Открыть в новом окне',
            programmeHomepage: 'На страницу передачи',
            alternativeListening: null,
            showPlaylist: null,
            download: null
        }
    };

    function showViewerLocale() {
        return strings;
    }

})(window.angular);


/*!** Source: src/show-viewer/show-viewer-controller.js ***/

; (function (angular) {
    'use strict';

    angular.module('battlesnake.show-viewer')
		.controller('showViewerController', showViewerController);


    function showViewerController($scope, $timeout, languageService, showViewerLocale, $compile) {
        var scope = $scope;
        scope.videoplayer = false;
        scope.playerEl = '        <div class="play-button" ng-class="{\'force-image\': show.isRadio, hideimg: !show.isRadio}" ng-style="{\'background-image\': \'url({{show.image}})\'}" id="timelinePlayer"' +
'             data-key="$514317695773130"' +
'             data-swf="/Content/player/swf/flowplayer.swf"' +
'             data-swf-hls="/Content/player/swf/flowplayerhls.swf"' +
'             data-debug="true"' +
'             data-wmode="transparent"' +
'             >' +
                '<img ng-if="show.image" ng-src="{{show.image}}"/>' +
'        </div>';
        
        scope.strings = languageService(showViewerLocale);

        scope.view = {
            showPlaylist: false
        };

        scope.selectSource = selectSource;

        this.init = initController;

        return;

        function initController() {
            scope.$watch('show', showChanged);
        }

        function showChanged() {

            var show = scope.show;
            if (show && show.media.sources && show.media.sources.length) {
                if (/iPhone/.test(navigator.userAgent) && scope.videoplayer) {
                    scope.videoplayer.getPlayer().data('flowplayer').shutdown();
                    scope.videoplayer.getPlayer().remove();
                    scope.videoplayer = false;
                }
                selectSource(show.media.sources[0], null);
            } else {
                scope.activeSource = null;
            }
        }

        function selectSource(source, title) {
            scope.activeSource = source;
            scope.activeSourceTitle = title;
            initPlayer(source);

        }
        function initPlayer(source) {

            var live = false;
            var emorPath = "";
            var clip = false;
            if (source.name == "-")
            {
                live = true;
            }
            if (source.emorpath)
            {
                emorPath = source.emorpath;
            }

            if (source.Content && source.Content.indexOf("://") === 0) {
                clip = {
                    sources: source.Content,
                    live: live,
                    autoplay: true,
                }
            }
            else if (source.ContentHls) {
                clip = {
                    live: live,
                    autoplay: true,
                    sources: [
                       { type: 'video/flash', src: source.ContentFlash},
                       { type: 'application/x-mpegurl', src: source.ContentHls },
                       { type: 'video/rtsp', src: source.ContentRtsp },
                    ]
                }
                //dashUrl = "http://" + streamUrl + dir + dashUrl + file.replace(".mp4", "") + "/manifest.mpd";
            }
            $timeout(function () {
                if (scope.videoplayer === false) {
                    
                    angular.element('.player').append(scope.playerEl);
                    var nPlayer = angular.element('#timelinePlayer');
                    $scope.$apply();
                    $compile(nPlayer)(scope);

                    scope.videoplayer = new meediaPlayer(nPlayer, {
                        emorpath: emorPath,
                        clip: clip
                    });
                } else {
                    if (scope.videoplayer.getPlayer().data('flowplayer'))
                    {
                        scope.videoplayer.getPlayer().data('flowplayer').conf.emorpath = emorPath;
                    }
                    
                    scope.videoplayer.loadClip(clip);
                    if (scope.videoplayer && /iPhone/i.test(navigator.userAgent)) {
                        //scope.videoplayer.getPlayer().data('flowplayer').unload();

                    }
                }
            });
        }
    }
    showViewerController.$inject = ["$scope", "$timeout", "languageService", "showViewerLocale", "$compile"];

})(window.angular);


/*!** Source: src/show-viewer/show-viewer-filters.js ***/

; (function (angular) {
    'use strict';

    angular.module('battlesnake.show-viewer')
		.filter('showViewerDateTime', showViewerDateTimeFilter)
    ;

    function showViewerDateTimeFilter() {
        return function (when) {
            if (!when) {
                return '';
            }
            return when.local().format('DD.MM.YYYY HH:mm');
        };
    }

})(window.angular);


/*!** Source: src/show-viewer/show-viewer-directive.js ***/

; (function (angular) {
    'use strict';

    angular.module('battlesnake.show-viewer')
		.directive('showViewer', showViewerDirective);

    function showViewerDirective() {

        return {
            restrict: 'A',
            require: 'showViewer',
            controller: 'showViewerController',
            scope: {
                show: '=showViewer',
                canShowPlaylist: '=',
                showTimesInPlaylist: '='
            },
            templateUrl: 'show-viewer-template.html',
            link: link
        };

        function link(scope, element, attrs, controller) {
            controller.init();
        }
    }

})(window.angular);



/*!** Source: src/schedule/module.js ***/

; (function (angular) {
    'use strict';

    /**
	 * @ngdoc module
	 * @name schedule
	 * @requires timeline
	 * @requires show-viewer
	 * @requires now-playing
	 *
	 * @description
	 * Combines timeline and show-viewer widgets
	 */
    angular.module('battlesnake.schedule', ['battlesnake.timeline', 'battlesnake.show-viewer', 'battlesnake.now-playing']);

})(window.angular);


/*!** Template: src/schedule/schedule-template.html ***/

; (function (angular) {
    'use strict';

    var html =

		'<div class="schedule container" ng-class="{ \'full-width\': fullWidth === \'true\' }">' +
		'<div ng-class="{ \'full-width\': fullWidth === \'true\' }">' +
		'<div now-playing="adapter.nowPlaying" ' +
		'ng-if="adapter.nowPlaying" ' +
		'class="full-width" ' +
		'ng-class="nowPlayingClass">' +
		'</div>' +
		'<div timeline="adapter.timeline" ' +
		'ng-if="adapter.timeline" ' +
		'class="full-width" ' +
		'ng-class="timelineClass" ' +
		'timeline-open-item="methods.openItem(item.itemData)" ' +
		'timeline-group-by="{{ groupBy }}">' +
		'</div>' +
		'<div class="toggle-arrow-container">' +
		'<div class="toggle-arrow" ' +
		'ng-show="!!model.details" ' +
		'ng-click="methods.toggleViewer()">' +
		'</div>' +
		'</div>' +
		'</div>' +
		'<div show-viewer="model.details" ' +
		'class="container" ' +
		'ng-class="showViewerClass" ' +
		'ng-if="adapter.showViewer && !!model.details && expanded" ' +
		'can-show-playlist="adapter.showViewer.canShowPlaylist" ' +
		'show-times-in-playlist="adapter.showViewer.showTimesInPlaylist">' +
		'</div>' +
		'</div>';

    if (angular.version.minor < 3) {
        html = html.replace(/{\s*::\s*/g, '{ ').replace(/"\s*::\s*/g, '"');
    }

    angular.module('battlesnake.schedule')
		.run(["$templateCache", function ($templateCache) {
		    $templateCache.put('schedule-template.html', html)
		}]);

})(window.angular);

/*!** Source: src/schedule/schedule-directive.js ***/

; (function (angular) {
    'use strict';

    angular.module('battlesnake.schedule')
		.directive('schedule', scheduleDirective);

    function scheduleDirective() {
        return {
            restrict: 'A',
            require: 'schedule',
            scope: {
                adapter: '=schedule',
                nowPlayingClass: '@',
                timelineClass: '@',
                showViewerClass: '@',
                expanded: '=?',
                selectedItem: '=?',
                fullWidth: '@',
                groupBy: '@'
            },
            templateUrl: 'schedule-template.html',
            controller: 'scheduleController'
        };
    }

})(window.angular);


/*!** Source: src/schedule/schedule-controller.js ***/

; (function (angular) {
    'use strict';

    angular.module('battlesnake.schedule')
		.controller('scheduleController', scheduleController);

    function scheduleController($scope) {
        $scope.model = {
            details: null
        };

        $scope.methods = {
            openItem: openItem,
            toggleViewer: toggleViewer
        };

        //$scope.$watch('selectedItem', selectionChanged);
        $scope.$watch('adapter', adapterChanged);
        return;

        function adapterChanged() {
            $scope.model.details = null;
            $scope.expanded = false;
        }

        //function selectionChanged() {
        //    openItem($scope.selectedItem, true);
        //}

        function openItem(item, forceOpen) {
            if ($scope.selectedItem === item && !forceOpen) {
                toggleViewer();
                return;
            }
            $scope.selectedItem = item;
            if (!item) {
                return;
            }

            return $scope.adapter.showViewer.getDetails(item)
				.then(function (details) {
				    $scope.expanded = true;
				    $scope.model.details = details;
				});
        }

        function toggleViewer() {
            $scope.expanded = !$scope.expanded;
        }
    }
    scheduleController.$inject = ["$scope"];

})(window.angular);

/*** This file is generated automatically, do not edit it as changes will not be preserved ***/


/*!** Module: err ***/


/*!** Source: src/err/module.js ***/

; (function (angular) {
    'use strict';

    /**
	 * @ngdoc module
	 * @name err
	 *
	 * @description
	 * ERR adapters to connect the ERR backend to the Battlesnake/Kartulita modules.
	 */
    angular.module('battlesnake.err', ['battlesnake.language'])
		.config(whitelistRtsp)
    ;

    function whitelistRtsp($compileProvider) {
        ($compileProvider.aHrefSanitizationWhitelist || $compileProvider.urlSanitizationWhitelist)(/^\s*(https?|ftp|mailto|rtsp):/);
    }
    whitelistRtsp.$inject = ["$compileProvider"];

})(window.angular);


/*!** Source: src/err/show-viewer-adapter.js ***/

; (function (angular, _, moment, location) {
    'use strict';

    angular.module('battlesnake.err')
		.factory('showViewerAdapterFactory', showViewerAdapterFactory);

    function showViewerAdapterFactory($http, $sce, $q, $timeout, playlistAdapterFactory, languageService, errLocale) {

        var strings = languageService(errLocale);

        return getAdapter;

        function getAdapter(api, languageIndex) {

            var result = {
                endpoint: api.baseUrl + '/loader/GetTimelineContent',
                playlistAdapter: playlistAdapterFactory(api),
                getDetails: getDetails,
                canShowPlaylist: canShowPlaylist
            };

            var showViewerLocale, showPlaylist;

            return result;

            function localeHack() {
                /* Override showPlaylist for Klassika */
                if (!showViewerLocale) {
                    showViewerLocale = angular.injector(['ng', 'battlesnake.show-viewer']).get('showViewerLocale');
                    showPlaylist = showViewerLocale.et.showPlaylist;
                }
                var isKlassika = api.channel === 'klassikaraadio';
                showViewerLocale.et.showPlaylist = isKlassika ? 'Muusika nimekiri' : showPlaylist;
            }

            function canShowPlaylist(show, playlist) {
                return api.showAllPlaylists || moment().isAfter(show.finish);
            }

            function getMediaUrl(content, image, autoplay) {
                var parts = content.replace('://', '').split('@');
                var host = location.host || location.hostname;
                var hostAuto = api.baseUrl.match(/[\w\.]*\.err\.ee/);
                if (!host.match(/\.err\.ee/) && hostAuto) {
                    host = hostAuto[0];
                }
                return $sce.trustAsResourceUrl(
					'http://static.err.ee/media?' +
					[
						'stream=' + parts[0].toLowerCase(),
						'file=' + parts[1],
						'mediaspace=mediaframe',
						'autoplay=true',
						'mediamode=wowzavideo',
						'width=100',
						'site=' + host,
						'image=' + image
					].join('&'));
            }

            function getMediaSources(show, sources) {
                return _(sources).chain()
					.filter(function (source) {
					    return source.Content && source.Content.trim().length;
					})
					//.map(mapSource)
					.unique()
					.value();
            }

            function getMediaStream(source) {
                return [$sce.trustAsResourceUrl(source)];
            }

            function getLiveStream(channel, image) {
                var params = {
                    channel: channel,
                    mediaspace: 'mediaframe',
                    forcestart: true,
                    mediamode: 'wowzalive',
                    width: 100,
                    site: window.location.host,
                    /*
                     * God only knows why the image URL must be unescaped...
                                            image: image
                     */
                };
                var mediaUrl = 'http://otse.err.ee/iframe2?' +
                    _(params).map(function (val, key) {
                        return encodeURIComponent(key) + '=' + encodeURIComponent(val);
                    })
                    .join('&') +
                    '&image=' + image;
                return getMediaStream(mediaUrl);
            }

            /* Map show item (backend format) to show-viewer format */
            function getDetails(item) {
                if (item.Id.match(/^[0\-]+$/)) {
                    return $q.when(getShowData(item));
                } else {
                    return $http.get(result.endpoint + '/' + item.Id)
						.then(function (response) {
						    return getShowData(item, response.data);
						});
                }
            }

            /* Class representing data about a show */
            function getShowData(baseData, contentData) {
                localeHack();
                contentData = contentData || {};
                var show = {};
                show.baseData = baseData;
                show.contentData = contentData;
                show.title = getText(contentData.Texts, baseData.HeaderLong || baseData.Header, 'Header');
                show.image = getImage(contentData.Image || baseData.Image);
                show.description = $sce.trustAsHtml(baseData.ContentLead || getText(contentData.Texts, baseData.Lead, 'Lead'));
                show.start = moment(baseData.Published || contentData.Published || contentData.Created);
                show.finish = moment(baseData.Updated);
                show.categoryUrl = '';
                show.playlist = null;
                /* GetCategoryUrlForPrimaryCategory (async) */
                if (baseData.PrimaryCategoryId) {
                    getCategoryUrl(baseData.PrimaryCategoryId)
						.then(function (url) {
						    if (/^[^\/]*(\/\/[^\/]*)?\/?$|^$/.test(url)) {
						        return $q.reject('No category URL');
						    }
						    show.categoryUrl = url;
						})
						/* Playlist */
						.then(function () {
						    var feedId = show.categoryUrl.split('/').pop();
						    return result.playlistAdapter.getPlaylist(feedId, baseData.Published);
						})
						.then(function (playlist) {
						    show.playlist = playlist;
						})
						.catch(function () { });
                }
                show.channelUrl = null;
                /*
				 * Disabled as requested by Margus (open in new window link)
				 * show.channelUrl = 'http://otse.err.ee/' + api.channel;
				 */
                show.targetUrl = contentData.Url;
                show.media = {};
                show.isRadio = !!api.channel.match(/raadio/i);

                if (!contentData.disableLive && (!api.ignoreFutureMedia || show.start.isBefore(moment()))) {
                    /* Media sources provided */
                    var sources = _(contentData.MediaSources || []).chain()
						.filter(function (source) { return !!source; })
						.map(JSON.stringify.bind(JSON))
						.uniq()
						.map(JSON.parse.bind(JSON))
						.value();
                    show.media.sources = sources.length ? sources :
						(baseData.ContentRelations || []).length ? getMediaSources(show, baseData.ContentRelations[0].MediaSources) :
						null;
                }
                _(show.media.sources).each(function (source, index)
                {
                    source.name = 'TUND' + (index + 1); //# -> TUND
                });
                /* Is show currently playing */
                show.getIsPlaying = function () { return isPlaying(show); };
                if (show.getIsPlaying()) {
                    if (api.live) {
                        var liveMedia = [{ ContentHls: api.live.http, ContentRtsp: api.live.rtsp, ContentRtmp: api.live.rtmp, ContentFlash: api.live.flash }];//TODO: dash
                        /*if (/Android|IEMobile|Blackberry/i.test(navigator.userAgent)) {
                            liveMedia = getMediaStream(api.live.rtsp);
                        } else if (/iPhone|iPad|iPod/i.test(navigator.userAgent)) {
                            liveMedia = getMediaStream(api.live.http);
                        } else {
                            liveMedia = getLiveStream(api.channel, show.image);
                        }*/
                        if (!show.media.sources && liveMedia.length) {
                            show.media.sources = [];
                        }
                        while (liveMedia.length) {
                            show.media.sources.unshift(liveMedia.pop());
                            show.media.sources[0].name = '-';
                            show.media.sources[0].emorpath = api.channel+'/otse';
                        }

                    }
                    /* Alternative bitrates/formats for live show */
                    if (api.live.alternatives) {
                        show.media.formats = api.live.alternatives;
                    }
                }
                /* Links */
                show.links = {
                    list: null,
                    menu: null,
                    menuTitle: strings('download')
                };
                if (baseData.ContentRelations && baseData.ContentRelations.length) {
                    show.links.list = _(baseData.ContentRelations).map(mapSourceToListItem.bind(show));
                }
                /* Downloadable sources */
                if (baseData.HasPodcast) {
                    show.links.menu = _(contentData.MediaSources).map(mapPodcastMenuItem);
                }

                return show;
            }

            function mapPodcastMenuItem(source) {
                var link = {
                    url: source.PodcastUrl,
                    title: source.MediaMetadata[0].Caption,
                    actions: []
                };
                return link;
            }

            function mapSourceToListItem(data) {
                var source = data.MediaSources[0];
                if (!source) {
                    return '';
                }
                var meta = source.MediaMetadata[0];
                var link = {
                    obj: source,
                    title: meta && meta.Caption || data.Texts[0].Header || '',
                    actions: [],
                    iconClass: [(source.Type & 64) ? 'fa fa-microphone' : ' ', (source.Type & 128) ? 'fa fa-play-circle-o' : ' '].join(' ')
                };
                if (meta && meta.PodcastUrl) {
                    link.actions.push({
                        url: meta.PodcastUrl,
                        title: strings('download')
                    });
                }
                return link;
            }

            function getCategoryUrl(categoryId) {
                var request = {
                    method: 'GET',
                    url: api.baseUrl + '/loader/GetCategoryUrlForPrimaryCategory/',
                    params: { categoryid: categoryId }
                };
                return $http(request)
					.then(function (res) {
					    return res.data && res.data.Url || $q.reject(null);
					});
            }

            function isPlaying(data) {
                var now = moment();
                return now.isAfter(data.start) && now.isBefore(data.finish);
            }

            function getImage(image) {
                if (typeof image === 'string') {
                    if (/^https?:\/\//.test(image)) {
                        return resize(image);
                    } else {
                        return resize('http://static.err.ee/gridfs/' + image);
                    }
                } else if (typeof image === 'object') {
                    return resize('http://static.err.ee/gridfs/' + image.FileName + (image.ImageResizerOptions || ''));
                } else {
                    return null;
                }

                function resize(url) {
                    return (
							url.replace(/&?(height|width)=[^&]*&?/gi, '&') +
							(url.indexOf('?') === -1 ? '?' : '&') +
							'width=752&mode=crop'
						).replace(/&{2,}/g, '&');
                }
            }

            function getText(texts, fallback, key) {
                var text;
                if (texts && texts.length) {
                    text = _(texts).findWhere({ Language: languageIndex });
                    if (!text) {
                        text = texts[0];
                    }
                    return text[key];
                } else {
                    return fallback;
                }
            }
        }
    }
    showViewerAdapterFactory.$inject = ["$http", "$sce", "$q", "$timeout", "playlistAdapterFactory", "languageService", "errLocale"];

})(window.angular, window._, window.moment, window.location);


/*!** Source: src/err/timeline-adapter.js ***/

; (function (angular, moment, _) {
    'use strict';

    angular.module('battlesnake.err')
		.constant('timelineTileImageSpec', { size: 144, activeSize: 304, quality: 85 })
		.factory('timelineAdapterFactory', timelineAdapterFactory)
    ;

    function timelineAdapterFactory($http, timelineTileImageSpec) {

        return getAdapter;

        function getAdapter(api, preloaded) {
            var result = {
                /* URL to get timeline items per group */
                endpoint: api.baseUrl + '/loader/GetTimelineDay',
                /* Get contents of a group */
                getGroup: getGroup,
                /* Can the given item be cached? */
                canCache: canCache,
                /* Preloaded data */
                preloaded: null
            };

            if (preloaded) {
                if (preloaded.alreadyMapped) {
                    result.preloaded = preloaded;
                } else {
                    result.preloaded = _(preloaded)
						.map(function (line) {
						    var data = _(line.data).map(mapItem);
						    fillBlackHoles(data);
						    return {
						        date: moment(line.date),
						        data: data
						    };
						});
                }
            }

            var timelineLocale, playLive;

            return result;

            function timelineLocaleHack(isRadio) {
                /* Hack for Kuula<==>Vaata for TV/Raadio */
                if (!timelineLocale) {
                    timelineLocale = angular.injector(['ng', 'battlesnake.timeline']).get('timelineLocale');
                    playLive = timelineLocale.et.playLive;
                }
                timelineLocale.et.playLive = isRadio ? 'Kuula otse' : playLive;
            }

            function canCache(yyyymmdd) {
                /* Hack to change "Play Live" Estonian translation for radio/TV */
                timelineLocaleHack(!!api.channel.match(/raadio/i));
                return true;
            }

            function getGroup(group) {
                var request = {
                    method: 'GET',
                    url: result.endpoint,
                    params: {
                        year: group.format('YYYY'),
                        month: group.format('MM'),
                        day: group.format('DD')
                    }
                };
                return $http(request)
					.then(transformData);

                /*
				 * Correct time black-holes by adjusting the end time of the
				 * show before the black-hole
				 */
                function transformData(res) {
                    var data = _(res.data).map(mapItem);
                    fillBlackHoles(data);
                    return data;
                }
            }

            function fillBlackHoles(data) {
                for (var i = 0; i < data.length - 1; i++) {
                    var item = data[i], next = data[i + 1];
                    var diff = moment.duration(next.start.diff(item.finish)).asMinutes();
                    /* Upper limit removed, we have serious black holes >1hour */
                    if (diff > 0 /*&& diff <= 10*/) {
                        item.finish = next.start;
                        item.itemData.Updated = item.finish.format();
                    }
                }
            }

            function mapItem(item) {
                var start = moment(item.Published).local();
                return {
                    /* Unique ID of item */
                    id: item.Id,
                    /* Title of item */
                    title: item.Header,
                    /* Start time */
                    start: correctTZ(start).local(),
                    /* Finish time */
                    finish: correctTZ(moment(item.Updated)).local(),
                    /* Address of image to display in timeline */
                    /* Return an object of CSS key-valye pairs in order to use CSS sprites */
                    /* See http://stackoverflow.com/questions/18500801/resizing-background-sprite-image-to-fit-div */
                    thumbnail: getImageUrl(item, timelineTileImageSpec.size),
                    /* Address of image to use for active tile */
                    activeThumbnail: getImageUrl(item, timelineTileImageSpec.activeSize),
                    /* Store original item data for viewer */
                    itemData: item,
                    /* Item can be played */
                    playable: (item.hasAudio || item.hasVideo) && (!api.ignoreFutureMedia || start.isBefore(moment()))
                };

                /* Backend sometimes stores datetimes in Estonian winter time zone, but marks them as UTC with Z suffix */
                function correctTZ(t) {
                    return t; //t.add(2, 'hours');
                }

                function getImageUrl(item, size) {
                    return 'http://static.err.ee/gridfs/' + item.Image +
						'?width=' + size + '&height=' + size + '&mode=crop&quality=' + timelineTileImageSpec.quality;
                }

            }

        }
    }
    timelineAdapterFactory.$inject = ["$http", "timelineTileImageSpec"];

})(window.angular, window.moment, window._);


/*!** Source: src/err/playlist-adapter.js ***/

; (function (angular, _, moment) {
    'use strict';

    angular.module('battlesnake.err')
		.factory('playlistAdapterFactory', playlistAdapterFactory);

    function playlistAdapterFactory($http) {

        return getAdapter;

        function getAdapter(api) {

            var result = {
                endpoint: api.baseUrl + '/loader/playlistforprogram',
                getPlaylist: getPlaylist
            };
            return result;

            function getPlaylist(feedId, date) {
                var request = oldGetEndpoint(feedId, date);

                return $http(request)
					.then(transformData);

                function oldGetEndpoint(feedId, date) {
                    date = moment(date);
                    return {
                        method: 'GET',
                        url: result.endpoint,
                        params: {
                            id: feedId,
                            channel: api.alternateChannel || api.channel,
                            year: date.format('YYYY'),
                            month: date.format('MM'),
                            day: date.format('DD')
                        }
                    };
                }

                function newGetEndpoint(feedId, date) {
                    date = moment(date);
                    var feedName = api.alternateChannel || api.channel;
                    var categoryName = ''; /* Knowing this would break encapsulation */
                    var dateUrl = date.format('D.MM.YYYY H:mm:ss'); /* Why can't we just use UNIX timestamps */
                    return {
                        method: 'GET',
                        url: '/api/loader/GetShowPlayList',
                        params: {
                            key: [feedName, categoryName, dateUrl].join('/'),
                        }
                    };
                }

            }

            function transformData(res) {
                var data = res.data;
                if (!data || !data.Musics || !data.Musics.length) {
                    return null;
                }
                return {
                    items: _(data.Musics).map(mapItem)
                };
            }

            function mapItem(item) {
                var title;
                if (api.playlistUseAuthor) {
                    var performer = (item.meta.PERFORMER || '').trim();
                    if (performer) {
                        performer = ' (' + performer + ')';
                    }
                    title = item.meta.AUTHOR1 + ' - ' + item.meta.SONGNAME + performer;
                } else {
                    title = item.meta.PERFORMER + ' - ' + item.meta.SONGNAME;
                }
                return {
                    __debug: { item: item },
                    time: moment(item.Info.STARTTIME, 'hhmmss').format('hh:mm:ss'),
                    title: title
                };
            }

        }

    }
    playlistAdapterFactory.$inject = ["$http"];

})(window.angular, window._, window.moment);


/*!** Source: src/err/locale.js ***/

; (function (angular, moment) {
    'use strict';

    angular.module('battlesnake.err')
		.service('errLocale', errLocale)
		.config(setLanguage)
    ;

    function errLocale() {
        this.en = {
            download: 'Download'
        };
        this.et = {
            download: 'Lae alla'
        };
        this.ru = {
            download: null
        };
    }

    var locale = location.search.match(/[\?\&]test-lang=([a-z]+)/);
    if (locale) {
        locale = locale[1];
        console.info('Language override via test-lang URL parameter: ' + locale);
    } else {
        locale = location.hostname.match(/\br(aadio)?4\b/) ? 'ru' : 'et';
    }

    moment.locale(locale);

    /* Set default language used by language-service (previous default is browser language */
    function setLanguage($provide) {
        $provide.decorator('defaultLanguage', ["$delegate", function ($delegate) { return locale; }]);
    }
    setLanguage.$inject = ["$provide"];

})(window.angular, window.moment);


/*!** Source: src/err/now-playing-adapter.js ***/

; (function (angular) {
    'use strict';

    angular.module('battlesnake.err')
		.service('nowPlayingAdapterFactory', nowPlayingAdapterFactory);

    function nowPlayingAdapterFactory($http) {
        return getAdapter;

        function getAdapter(api) {

            var result = {
                /* URL to get now playing item */
                endpoint: api.baseUrl + '/radio/GetContent?type=' + encodeURIComponent(api.channel),
                /* Polling delay if caption didn't change */
                delayNoUpdate: 5000,
                /* Polling delay if caption changed */
                delayUpdate: 60000,
                /* Called when polling for new value */
                update: update
            };

            return result;

            /* Returns a promise which resolves to an object */
            function update() {
                return $http.get(result.endpoint)
					.then(parseResult);
            }

            /* Parses API response to produce object for now-playing component */
            function parseResult(res) {
                var data = res.data;
                if (data && data !== 'null' && data !== 'undefined' && data !== '""' && data !== "''") {
                    if (data.match(/^".*"$/)) {
                        try {
                            var parsed = JSON.parse(data);
                            data = parsed;
                        } catch (e) {
                        }
                    }
                    return {
                        caption: data.replace(/^\s*|\s*$/g, ''),
                        url: 'http://otse.err.ee/' + api.channel
                    };
                } else {
                    return {
                        empty: true,
                        delay: 10000
                    }
                }
            }
        }
    }
    nowPlayingAdapterFactory.$inject = ["$http"];

})(window.angular);


/*!** Source: src/err/apis.js ***/

; (function (angular) {
    'use strict';

    angular.module('battlesnake.err')
		.factory('scheduleApi', scheduleApi);

    function scheduleApi() {
        return {
            etv: {
                baseUrl: 'http://etv.err.ee/api',
                channel: 'etv',
                live: {
                    rtsp: 'rtsp://striimid.err.ee:80/live/etvm',
                    http: 'http://striimid.err.ee/live/smil:etv.smil/playlist.m3u8',
                    flash: 'rtmp://striimid.err.ee:80/live/etv',
                    rtmp: 'rtmp://striimid.err.ee:80/live',
                }
            },
            etv2: {
                baseUrl: 'http://etv2.err.ee/api',
                channel: 'etv2',
                live: {
                    rtsp: 'rtsp://wowza3.err.ee/live/etv2m',
                    http: 'http://wowza3.err.ee/live/smil:etv2.smil/playlist.m3u8',
                    flash: 'rtmp://wowza3.err.ee/live/etv2',
                    rtmp: 'rtmp://wowza3.err.ee/live/',
                }
            },
            raadio2: {
                baseUrl: 'http://r2.err.ee/api',
                channel: 'raadio2',
                live: {
                    rtsp: 'rtsp://194.36.162.51/live/raadio2',
                    http: 'http://194.36.162.51/live/raadio2/playlist.m3u8',
                    flash: 'rtmp://194.36.162.51:80/live/raadio2',
                    rtmp: 'rtmp://194.36.162.51:80/live/',
                    alternatives: getAlternatives('raadio2', 'vana.r2')
                }
            },
            raadio4: {
                baseUrl: 'http://r4.err.ee/api',
                channel: 'raadio4',
                live: {
                    rtsp: 'rtsp://194.36.162.51/live/raadio4',
                    http: 'http://194.36.162.51/live/raadio4/playlist.m3u8',
                    flash: 'rtmp:/194.36.162.51/live/raadio4',
                    rtmp: 'rtmp://194.36.162.51/live/',
                    alternatives: getAlternatives('raadio4', 'vana.r4')
                }
            },
            raadioTallinn: {
                baseUrl: 'http://raadiotallinn.err.ee/api',
                channel: 'raadiotallinn',
                live: {
                    rtsp: 'rtsp://194.36.162.51/live/raadiotallinn',
                    http: 'http://194.36.162.51/live/raadiotallinn/playlist.m3u8',
                    rtmp: 'rtmp://194.36.162.51/live/',
                    flash: 'rtmp://194.36.162.51/live/raadiotallinn',
                    alternatives: getAlternatives('raadiotallinn', 'vana.raadiotallinn')
                }
            },
            vikerRaadio: {
                baseUrl: 'http://vikerraadio.err.ee/api',
                channel: 'vikerraadio',
                alternateChannel: 'viker',
                live: {
                    rtsp: 'rtsp://striimid.err.ee/live/vikerraadio',
                    http: 'http://striimid.err.ee/live/vikerraadio/playlist.m3u8',
                    rtmp: 'rtmp://striimid.err.ee/live',
                    flash: 'rtmp://striimid.err.ee/live/vikerraadio',
                    alternatives: getAlternatives('vikerraadio', 'vikerraadio')
                },
                ignoreFutureMedia: true
            },
            klassikaRaadio: {
                baseUrl: 'http://klassikaraadio.err.ee/api',
                channel: 'klassikaraadio',
                alternateChannel: 'klassika',
                live: {
                    rtsp: 'rtsp://194.36.162.51/live/klassikaraadio',
                    http: 'http://194.36.162.51/live/klassikaraadio/playlist.m3u8',
                    rtmp: 'rtmp://194.36.162.51/live/',
                    flash: 'rtmp://194.36.162.51/live/klassikaraadio',
                    alternatives: getAlternatives('klassikaraadio', 'vana.klassikaraadio')
                },
                playlistUseAuthor: true,
                showAllPlaylists: true,
            }
        };
    }

    function getAlternatives(channel, subdomain) {
        return [
			{
			    codec: 'aac',
			    bitrate: 128,
			    url: 'rtsp://193.40.133.138:80/live/' + channel
			},
			{
			    codec: 'aac',
			    bitrate: 64,
			    url: 'rtsp://193.40.133.138:80/live/' + channel + 'madal'
			},
			{
			    codec: 'mp3',
			    bitrate: 128,
			    url: 'http://' + subdomain + '.err.ee/gfx/' + channel + '128.m3u'
			},
			{
			    codec: 'mp3',
			    bitrate: 64,
			    url: 'http://' + subdomain + '.err.ee/gfx/' + channel + '64.m3u'
			}
        ];
    }

})(window.angular);
;
(function (angular, errTimelineApi_, errTimelinePreloadedData_) {
    'use strict';

    angular.module('app')
		.constant('errTimelineApi', errTimelineApi_)
		.constant('errTimelinePreloadedData', errTimelinePreloadedData_)
        .controller('errTimelineController', errTimelineController)
    ;

    /* Can't we just add ngAnnotate to the build chain? */
    errTimelineController.$inject = '$scope,$q,$timeout,$window,showViewerAdapterFactory,timelineAdapterFactory,nowPlayingAdapterFactory,errTimelineApi,scheduleApi,errTimelinePreloadedData'.split(',');
    function errTimelineController($scope, $q, $timeout, $window, showViewerAdapterFactory, timelineAdapterFactory, nowPlayingAdapterFactory, errTimelineApi, scheduleApi, errTimelinePreloadedData) {

        var apiName = errTimelineApi;
        if (!scheduleApi[apiName]) {
            throw new Error('Schedule API not found: ' + apiName);
        }
        var apiConfig = scheduleApi[apiName];
        apiConfig.baseUrl = window.location.protocol + "//" + window.location.host + "/api";

        $scope.model = {
            title: 'Show viewer demo with timeline binding',
            nowPlaying: null,
            expanded: false,
            item: null,
            adapter: {
                showViewer: showViewerAdapterFactory(apiConfig),
                timeline: timelineAdapterFactory(apiConfig, errTimelinePreloadedData),
                nowPlaying: nowPlayingAdapterFactory(apiConfig)
            }
        };
        /* "Now playing" poller */
        var nowPlayingTimer = null;
        updateNowPlaying();
        /* Start playing automatically? */
        if (/[\&\?]showlive(\&|$)/i.test($window.location.search)) {
            showCurrent();
        }
        return;

        function updateNowPlaying() {
            /* RDS disabled as requested */
            return;
            /* */
            if (!$scope.model.adapter.nowPlaying) {
                return;
            }
            $scope.model.adapter.nowPlaying()
				.then(function (res) {
				    var data = res.data || '""';
				    try {
				        data = JSON.parse(data);
				    } catch (e) {
				        /* Trololol */
				    }
				    return data.replace(/^\s+|\s+$/g, '').replace(/^null$/, '');
				}, function () {
				    return '';
				})
				.then(showNowPlaying);
            return;

            function showNowPlaying(value) {
                var changed = $scope.model.nowPlaying !== value;
                $scope.model.nowPlaying = value;
                nowPlayingTimer = $timeout(updateNowPlaying, changed ? 30000 : 5000);
            }
        }

        function showCurrent() {
            $scope.model.adapter.timeline.getDay(moment())
                .then(getCurrent)
                .then(function selectShow(show) {
                    $scope.model.item = show.itemData;
                    $scope.model.expanded = true;
                });

            function getCurrent(data) {
                return _(data).chain()
                    .sort(showReverseComparator)
                    .find(hasStartedPredicate)
                    .value();

                function showReverseComparator(a, b) {
                    return -a.start.diff(b.start);
                }

                function hasStartedPredicate(show) {
                    return show.start.isBefore(moment());
                }
            }
        }
    }

})(window.angular, window.errTimelineApi, window.errTimelinePreloadedData);;
(function () {
    'use strict';
    var controllerId = 'radioCtrl';

    try {
        angular.module('app').controller(controllerId, ['$scope', '$attrs', radioController]);
    } catch (ex) {
        angular.module('errMuuda').controller(controllerId, ['$scope', '$attrs', radioController]);
    }

    function radioController($scope, $attrs) {
        $scope.title = 'radioCtrl';
        $scope.type = $attrs.type || "";
    }
})();;
(function () {
    'use strict';
    var serviceId = 'radioService';
    try {
        angular.module('app').service(serviceId, ['$http', radioService]);
    } catch (ex) {
        angular.module('errMuuda').service(serviceId, ['$http', radioService]);
    }

    function radioService($http) {
        var serviceHost = "/api/Radio/";
        var service = {
            getRadioContent: getRadioContent
        };

        return service;

        function getRadioContent(name) {
            return $http({ method: "GET", url: serviceHost + "getcontent?type=" + name });
        }
    }
})();;
(function () {
    'use strict';
    var controllerId = 'radiolistCtrl';

    try {
        angular.module('app').controller(controllerId, ['$scope', '$attrs', 'radiolistService', radiolistController]);
    } catch (ex) {
        angular.module('errMuuda').controller(controllerId, ['$scope', '$attrs', 'radiolistService', radiolistController]);
    }

    function radiolistController($scope, $attrs, radiolistService) {
        $scope.title = 'radiolistCtrl';
        //data properties
        $scope.setitems = setItems;
        $scope.getitems = getitems;
        //paging
        $scope.setPage = setPage;
        $scope.setCurrentPage = setCurrentPage;
        $scope.setFirstLast = setFirstLast;
        //other properties
        $scope.showModal = showModal;
        $scope.type = $attrs.type;
        $scope.numitems = $attrs.numitems;
        $scope.numdays = $attrs.numdays;
        $scope.usepaging = $attrs.usepaging;
        $scope.numpageitems = $attrs.numpageitems;
        $scope.keywords = $attrs.keywords;
        $scope.displayItems = [];
        $scope.pages = 0;
        $scope.currentPage = 1;
        $scope.pager = [-2,-1,0,1,2,3,4];
        $scope.pageCount;
        $scope.prevIsActive = false;
        $scope.nextIsActive = true;
        //get data
        getitems();

        function getitems() {
            radiolistService.getRadioContent($scope.type, $scope.numdays, $scope.numitems, $scope.keywords).then(setItems);
        }
        //JSON to items
        function setItems(data) {
            
            var items = data.length;
            var counter = 0;
            for (var i = 0; i < data.length; i++) {
                var link = data[i].Content.split('@');
                var description = "";
                if (data[i].Description != undefined) {
                    description = data[i].Description.replace(/��/g, "р");
                }
                var displayItem = {
                    id: data[i].Id,
                    created: $.datepicker.formatDate('dd.mm.yy', new Date(data[i].AirDate)),
                    channel: link[0],
                    mediasource: link[1],
                    header: data[i].Caption.replace(/��/g, "р"),
                    description: description
                }
                $scope.displayItems.push(displayItem);
                if (counter == $scope.numpageitems) {
                    $scope.pages++;
                    counter = 0;
                }
                counter++;
            }
            setRadioItems();
            setPageCount(items)
        }

        function setRadioItems() {
            if ($scope.usepaging == "True") {
                var start = ($scope.currentPage -1) * $scope.numpageitems;
                var end = ($scope.currentPage -1) * $scope.numpageitems + parseInt($scope.numpageitems);
                $scope.radioitems = $scope.displayItems.slice(start, end);
            } else {
                $scope.radioitems = $scope.displayItems;
            }
        }

        function setPageCount(items) {
            $scope.pageCount = Math.ceil(items / $scope.numpageitems);
        }

        function setCurrentPage(pageNum) {
            $scope.currentPage = $scope.pager[pageNum];            
        }

        function setPage(count) {
            if((count == -1 && $scope.currentPage == 1) || (count ==  1 && $scope.currentPage == $scope.pageCount)) {                
            } else {                
            $scope.prevIsActive = true;
            $scope.nextIsActive = true;
            $scope.currentPage += count;
            if ($scope.currentPage == 1) {
                $scope.prevIsActive = false;
            }
            if ($scope.currentPage == $scope.pageCount) {
                $scope.nextIsActive = false;
            }
            if (($scope.currentPage <= $scope.pageCount)) {
                $scope.pager = [];
                $scope.pager[0] = $scope.currentPage - 3;
                $scope.pager[1] = $scope.currentPage - 2;
                $scope.pager[2] = $scope.currentPage - 1;
                $scope.pager[3] = $scope.currentPage;
                $scope.pager[4] = $scope.currentPage + 1;
                $scope.pager[5] = $scope.currentPage + 2;
                $scope.pager[6] = $scope.currentPage + 3;
            } 
            setRadioItems();
            }
        }

        function setFirstLast(num) {
            $scope.currentPage = num;
            setPage(0);
        }

        //show modal
        function showModal(displayItem) {
            var url = "http://ext.err.ee/iframevideo.aspx?autoplay=true&mediaspace=mediaframe&stream=media.err.ee/" + displayItem.channel + "/&file=" + displayItem.mediasource + "&width=504&nohide=true";
            $("#radioHead").text(displayItem.header);
            $("#radioBody").html("");
            $("#radioBody").append('<iframe id="mediaframe" class="errflxmedia" width="504" height="50" scrolling="no" src="' + url + '" frameborder="0"></iframe>');
            $('#myRadioModal').modal('show');
        }
    }
})();;
(function () {
    'use strict';
    var serviceId = 'radiolistService';
    try {
        angular.module('app').service(serviceId, ['$http', '$q', radiolistService]);
    } catch (ex) {
        angular.module('errMuuda').service(serviceId, ['$http', '$q', radiolistService]);
    }

    function radiolistService($http, $q) {
        var serviceHost = "/api/Radio/";
        var service = {
            getRadioContent: getRadioContent
        };

        return service;

        function getRadioContent(type, numdays, numitems, keywords) {
            var defer = $q.defer();
            $http({ method: "get", cache: false, url: serviceHost + "getradiolistcontent?type=" + type + "&numofdays=" + numdays + "&itemsnum=" + numitems + "&keywords=" + keywords }).success(function (data) {
                defer.resolve(data);
            });
            return defer.promise;
        }
    }
})();;
(function () {
    'use strict';
    var serviceId = 'allVideosService';
    try {
        angular.module('app').service(serviceId, ['$http', '$q', allVideosService]);
    } catch (ex) {
        angular.module('errMuuda').service(serviceId, ['$http', '$q', allVideosService]);
    }

    function allVideosService($http, $q) {
        var serviceHost = "/api/Loader/GetAllMedia?type=";
        var service = {
            loadFirstContent: loadFirstContent,
            loadContent: loadContent
        };

        return service;

        function loadFirstContent(mediaType) {
            var defer = $q.defer();
            serviceHost += mediaType;
            if (mediaType == 0) serviceHost = "/api/Loader/GetAllGalleries";
            $http({ method: "get", cache: false, url: serviceHost }).success(function (data) {
                defer.resolve(data);
            });
            
            return defer.promise;
        }

        function loadContent(mediaType, page) {
            var defer = $q.defer();
            serviceHost = "/api/Loader/GetAllMedia?type=" + mediaType + "&page=" + page;
            if (mediaType == 0) serviceHost = "/api/Loader/GetAllGalleries/?page=" + page;
            $http({method : "get", cahce: false, url: serviceHost}).success(function (data) {
            defer.resolve(data);
            });
            return defer.promise;
        }

        
    }
})();;
(function () {
    'use strict';
    var controllerId = 'videosCtrl';

    try {
        angular.module('app').controller(controllerId, ['$scope', '$attrs', 'allVideosService', videosController]);
    } catch (ex) {
        angular.module('errMuuda').controller(controllerId, ['$scope', '$attrs', 'allVideosService', videosController]);
    }

    function videosController($scope, $attrs, videosService) {

        $scope.title = 'videosCtrl';
        $scope.resources;
        $scope.setitems = setItems;
        $scope.getitems = getitems;
        $scope.videoItems = [];
        $scope.loadMore = loadMore;
        $scope.page;
        $scope.setPage = setPage;
        getitems();
        $scope.cutterStyle = "height: 525px";
        $scope.height = 525;
        $scope.pageId = $attrs.pageid;
        $scope.setMediaType = setMediaType;
        $scope.mediaType;

        function getitems() {
            setMediaType();
            videosService.loadFirstContent($scope.mediaType).then(setItems);
        }
        var row = { items: [] }, counter = 0;
        function setItems(data) {
            
            data.forEach(function (videoItem) {
                
                   var Item = {
                        Header: videoItem.Header,
                        Published: videoItem.Published,
                        Updated: videoItem.Updated,
                        Image: "http://static.err.ee/gridfs/" + videoItem.Image,
                        ImageResizerOptions: ((videoItem.ImageResizerOptions == "" || videoItem.ImageResizerOptions == null || videoItem.ImageResizerOptions === undefined) ? "?width=272&height=153&mode=crop&anchor=middlecenter" : videoItem.ImageResizerOptions),
                        Url: videoItem.Url
                    }
                   row.items.push(Item);
                    
                
                counter++;
                if (counter == 4) {
                    $scope.videoItems.push(row);
                    row = { items: [] };
                    counter = 0;
                }
                
            });

        }

        function loadMore() {
            setPage();
            $scope.height = 2 * $scope.height
            videosService.loadContent($scope.mediaType, $scope.page).then(setItems);
            $scope.cutterStyle = "height: " + $scope.height + "px";


        }

        function setPage() {
            $scope.page = $scope.videoItems.length / 3;
        }

        
        function setMediaType() {
            if ($attrs.pageid == "videos") $scope.mediaType = 128;
            if ($attrs.pageid == "audios") $scope.mediaType = 64;
            if ($attrs.pageid == "galleries") $scope.mediaType = 0;
        }
        
        
    }


})();;
(function () {
    'use strict';
    var controllerId = "newsCtrl";

    try {
        angular.module('app').controller(controllerId, ['$scope', '$attrs', 'allNewsService', '$sce', '$timeout', newsController]);
    } catch (ex) {
        angular.module('errMuuda').controller(controllerId, ['$scope', '$attrs', 'allNewsService', '$sce', '$timeout',newsController]);
    }

    function newsController($scope, $attrs, allNewsService, $sce, $timeout) {

        $scope.title = 'newsCtrl';
        $scope.newsData = [];
        $scope.getItems = getItems;
        $scope.setItems = setItems;
        $scope.date = new Date();
        $scope.dateToday = new Date();
        $scope.isActive = false;
        $scope.isActive2 = true;
        $scope.changePages = changePages;
        $scope.pager = [];
        $scope.setPager = setPager;
        $scope.prevDate = "";
        $scope.selectedDate;
        $scope.model = {
            datee : ""
        };
        $scope.datepick = angular.element('#datepick');
        $scope.selectDate = selectDate;
        $scope.checkDate = checkDate;
        $scope.language = $attrs.language;

        setPager();
        getItems();

        function getItems() {
            allNewsService.loadContent($scope.date).then(setItems);
        }
        
        function setItems(data) {
            $scope.newsData = [];
            var row = { items: [] }, counter = 0;
            data.forEach(function (newsItem) {
                if ((moment($scope.prevDate).date() != moment(newsItem.Updated).date() && counter != 0 && $scope.prevDate != "")) {
                    $scope.newsData.push(row);
                    row = { items: [] };
                    counter = 0;
                }
                var Item = {
                    Header: newsItem.Header,
                    NumberOfComments: newsItem.NumberOfComments,
                    Published: newsItem.Published,
                    Updated: newsItem.Updated,
                    Url: newsItem.Url

                }
                row.items.push(Item);
                counter = 1;                
                $scope.prevDate = newsItem.Updated;
                
            });
            $scope.newsData.push(row);
        }

        function changePages(i) {
            $scope.date = moment($scope.date).add(i, "days")._d;
            $scope.model.datee = moment($scope.date).format('DD.MM.YYYY');
            getItems();
            checkDate();
            setPager();
            

        }

        function setPager() {
            $scope.pager = [];
            $scope.pager.push(moment($scope.date).subtract(2, "days").format('DD.MM'));
            $scope.pager.push(moment($scope.date).subtract(1, "days").format('DD.MM'));
            $scope.pager.push(moment($scope.date).format('DD.MM'));
            $scope.pager.push(moment($scope.date).add(1, "days").format('DD.MM'));
            $scope.pager.push(moment($scope.date).add(2, "days").format('DD.MM'));
        }
        


        if ($scope.language == "en") $scope.language = "en-GB";
        $scope.datepick.datepicker($.extend({}, $.datepicker.regional[$scope.language], {
           dateFormat: "mm-dd-yy",
           onSelect: $scope.selectDate
        }));

        function selectDate(date) {
            $scope.model.datee = date;
            $scope.model.datee = moment(date).toDate();

            if (moment(date).toDate() <= $scope.dateToday)              
                $scope.date = $scope.model.datee;

            $scope.model.datee = moment($scope.model.datee).format('DD.MM.YYYY');
            getItems();
            checkDate();
            setPager();


            
               
        }


        function checkDate() {
            if (moment($scope.date).date() == moment($scope.dateToday).date()) {
                $scope.isActive = false;
            }
            else $scope.isActive = true;
            if (moment($scope.dateToday).subtract(1, "days").date() == moment($scope.date).date()) $scope.isActive2 = false;
            else $scope.isActive2 = true;

        }



        


    }


})();


;
(function () {
    'use strict';
    var serviceId = "allNewsService";
    try {
        angular.module('app').service(serviceId, ['$http', '$q', allNewsService]);
    } catch (ex) {
        angular.module('errMuuda').service(serviceId, ['$http', '$q', allNewsService]);
    }

    function allNewsService($http, $q) {
        var serviceHost = "/api/loader/GetAllNews/?year=";
        var service = {
            loadContent: loadContent
        };

        return service;

        function loadContent(date) {
            var defer = $q.defer();
            $http({method : "get", cache: false, url: serviceHost + 
                + moment(date).format("YYYY") + "&month="
                + moment(date).format("MM") + "&day="
                + moment(date).format("DD")}).success(function (data) {
                    defer.resolve(data);
                });
            
            return defer.promise;
            }
        }
    




})();

            ;
angular.module('app')
    .controller('HostSelection', ['$scope', '$timeout', function($scope, $timeout) {

        // Define controller model
        $scope.model = {

            // Define placeholder for game hosts
            hosts : [
                { id : 1, firstname : 'Andres', lastname : 'Kuusk', img : '/Content/images/events/saatejuhtidevahetus2014/saatejuhid/andres.jpg', denied: 'foorum' },
                { id : 2, firstname : 'Grete', lastname : 'Lõbu', img : '/Content/images/events/saatejuhtidevahetus2014/saatejuhid/grete.jpg', denied: 'ringvaade', denied2: 'ringvaade2' },
                { id : 3, firstname : 'Katrin', lastname : 'Viirpalu', img : '/Content/images/events/saatejuhtidevahetus2014/saatejuhid/katrin.jpg', denied: 'terevisioon', denied2: 'terevisioon2' },
                { id : 4, firstname : 'Lembitu', lastname : 'Kuuse', img : '/Content/images/events/saatejuhtidevahetus2014/saatejuhid/lembitu.jpg', denied: 'spordiuudised' },
                { id : 5, firstname : 'Maire', lastname : 'Aunaste', img : '/Content/images/events/saatejuhtidevahetus2014/saatejuhid/maire.jpg', denied: 'tousejasara' },
                { id : 6, firstname : 'Marko', lastname : 'Reikop', img : '/Content/images/events/saatejuhtidevahetus2014/saatejuhid/marko.jpg', denied: 'ringvaade', denied2: 'ringvaade2' },
                { id : 7, firstname : 'Mihkel', lastname : 'Kärmas', img : '/Content/images/events/saatejuhtidevahetus2014/saatejuhid/mihkel.jpg', denied: 'pealtnagija' },
                { id : 8, firstname : 'Monika', lastname : 'Tamla', img : '/Content/images/events/saatejuhtidevahetus2014/saatejuhid/monika.jpg', denied: 'ak' },
                { id : 9, firstname : 'Reet', lastname : 'Linna', img : '/Content/images/events/saatejuhtidevahetus2014/saatejuhid/reet.jpg', denied: 'prillitoos' },
                { id : 10, firstname : 'Vladislav', lastname : 'Koržets', img : '/Content/images/events/saatejuhtidevahetus2014/saatejuhid/vladislav.jpg', denied: 'osoon' },
                { id : 11, firstname : 'Urmas', lastname : 'Vaino', img : '/Content/images/events/saatejuhtidevahetus2014/saatejuhid/urmas.jpg', denied: 'terevisioon', denied2: 'terevisioon2' }
            ],

            // Define placeholder for game shows
            ak : {}, foorum : {}, osoon : {}, pealtnagija : {}, prillitoos : {}, ringvaade : {}, ringvaade2 : {}, spordiuudised : {}, terevisioon : {}, terevisioon2 : {}, tousejasara : {},
            
            // Define placeholder for condition,
            // which will define, if hash was set
            hashset: false,

            // Define placeholder for previously
            // answered game fetched by hash
            results: {}
        };

        // Define controller methods
        $scope.methods = {
            
            /**
             * Set all values
             */
            setAll: function () {
                $scope.model.results = [];
                $scope.model.tousejasara = {id : 1, firstname : 'Andres', lastname : 'Kuusk', img : '/Content/images/events/saatejuhtidevahetus2014/saatejuhid/andres.jpg' };
                $scope.model.terevisioon2 = { id : 2, firstname : 'Grete', lastname : 'Lõbu', img : '/Content/images/events/saatejuhtidevahetus2014/saatejuhid/grete.jpg' };
                $scope.model.spordiuudised = { id : 3, firstname : 'Katrin', lastname : 'Viirpalu', img : '/Content/images/events/saatejuhtidevahetus2014/saatejuhid/katrin.jpg' };
                $scope.model.ringvaade2 = { id : 4, firstname : 'Lembitu', lastname : 'Kuuse', img : '/Content/images/events/saatejuhtidevahetus2014/saatejuhid/lembitu.jpg' };
                $scope.model.foorum = { id : 5, firstname : 'Maire', lastname : 'Aunaste', img : '/Content/images/events/saatejuhtidevahetus2014/saatejuhid/maire.jpg' };
                $scope.model.prillitoos = { id : 6, firstname : 'Marko', lastname : 'Reikop', img : '/Content/images/events/saatejuhtidevahetus2014/saatejuhid/marko.jpg' };
                $scope.model.terevisioon = { id : 7, firstname : 'Mihkel', lastname : 'Kärmas', img : '/Content/images/events/saatejuhtidevahetus2014/saatejuhid/mihkel.jpg' };
                $scope.model.ringvaade = { id : 8, firstname : 'Monika', lastname : 'Tamla', img : '/Content/images/events/saatejuhtidevahetus2014/saatejuhid/monika.jpg' };
                $scope.model.osoon = { id: 9, firstname: 'Reet', lastname: 'Linna', img: '/Content/images/events/saatejuhtidevahetus2014/saatejuhid/reet.jpg' };
                $scope.model.ak = { id : 10, firstname : 'Vladislav', lastname : 'Koržets', img : '/Content/images/events/saatejuhtidevahetus2014/saatejuhid/vladislav.jpg' };
                $scope.model.pealtnagija = { id : 11, firstname : 'Urmas', lastname : 'Vaino', img : '/Content/images/events/saatejuhtidevahetus2014/saatejuhid/urmas.jpg' };
            },

            /**
             * Initialize game environment
             */
            init: function () {

                // Set hash for display purposes
                $scope.model.hashset = true;

                $timeout(function() {

                    // Check if url parameter has been set
                    if($.urlParam('checksum'))
                    {
                        // Get previous results by hash
                        $.getJSON('/api/loader/GetHostMixUpVotesByChecksum?checksum=' + $.urlParam('checksum'), function(data) {

                            // Set results
                            $scope.model.results = data;

                            // Define scope
                            $scope.$apply(function() {
                                $.each(data.Votes, function(id, value) {

                                    // Get host name
                                    var name = value.VotedHost.split(' ');

                                    // Fetch host by it's first and last name
                                    var host = $.grep($scope.model.hosts, function(e) {
                                        return e.firstname == name[0] && e.lastname == name[1];
                                    })[0];

                                    // Hide the selection
                                    $('div[data-id=' + host.id + ']').hide();

                                    // Set show values
                                    switch(value.Show) {
                                        case 'Aktuaalne Kaamera': $scope.model.ak = host; break;
                                        case 'Foorum': $scope.model.foorum = host; break;
                                        case 'Osoon': $scope.model.osoon = host; break;
                                        case 'Pealtnägija': $scope.model.pealtnagija = host; break;
                                        case 'Prillitoos': $scope.model.prillitoos = host; break;
                                        case 'Ringvaade': if($scope.model.ringvaade.id !== undefined) $scope.model.ringvaade2 = host; else $scope.model.ringvaade = host; break;
                                        case 'Spordiuudised': $scope.model.spordiuudised = host; break;
                                        case 'Terevisioon': if($scope.model.terevisioon.id !== undefined) $scope.model.terevisioon2 = host; else $scope.model.terevisioon = host; break;
                                        case 'Tõuse ja sära': $scope.model.tousejasara = host; break;
                                    }
                                });
                            });
                        });
                    }
                    else
                        $scope.methods.setAll();
                }, 500);
            }
        };

    }]);

$.urlParam = function (name) { var results = new RegExp('[\\?&amp;]' + name + '=([^&amp;#]*)').exec(window.location.href); if (results === null) return 0; else return results[1] || 0;};
(function () {
    'use strict';

    var controllerId = 'musiclistCtrl';

    angular.module('app').controller(controllerId, ['$scope', '$attrs', 'musiclistService', musiclistCtrl]);

    function musiclistCtrl($scope, $attrs, musiclistService) {
        $scope.categoryId = $attrs.categoryid;
        $scope.channel = $attrs.channel;
        $scope.date = $attrs.date;
        $scope.musics = [];
        init();

        function init() {
            if ($scope.channel != "") {
                musiclistService.getCategoryRadioSeriesId($scope.categoryId).then(categorySuccessHandler);
            }
        }
        function loadData(radioSeriesId) {
            var searchRequest = {
                radioSeriesId: radioSeriesId,
                channel: $scope.channel,
                date: $scope.date
            };
            musiclistService.getPlaylistForProgram(searchRequest).then(successHandler);
        }
        function successHandler(data) {
            $scope.musics = data[0].Musics;
        }
        function categorySuccessHandler(radioSeriesId) {
            radioSeriesId = radioSeriesId.replace(/"/g, '');
            loadData(radioSeriesId);
        }
    }
})();
;
(function () {
    'use strict';
    var serviceId = 'musiclistService';
    angular.module('app').service(serviceId, ['$http', '$q', musiclistService]);

    function musiclistService($http, $q) {
        var service = {
            getPlaylistForProgram: getPlaylistForProgram,
            getCategoryRadioSeriesId: getCategoryRadioSeriesId
        };
        var serviceEndPoints = {
            playlist: "/api/loader/playlistforprogram/",
            radioseriesid: "/api/category/getcategoryradioseriesid"
        }
        return service;

        function getPlaylistForProgram(searchRequest) {

            var defer = $q.defer();
            if (searchRequest.date != undefined) {
                var date = searchRequest.date.replace(" ", "T");
                date = date.replace(".", "-");
                date = date.replace(".", "-");
                searchRequest.date = new Date(date);
                var d = moment(searchRequest.date);
                angular.extend(searchRequest, { day: d.date(), month: (d.month() + 1), year: d.year() });
            }
            var reqUrl = serviceEndPoints.playlist + searchRequest.radioSeriesId + "?channel=" + searchRequest.channel + "&day=" + searchRequest.day + "&month=" + searchRequest.month + "&year=" + searchRequest.year;
            $http({ method: "get", url: reqUrl }).success(function (data) { defer.resolve(data); }).error(function (data) { defer.reject("failed request"); });
            return defer.promise;
        }
        function getCategoryRadioSeriesId(categoryId) {
            var defer = $q.defer();
            var reqUrl = serviceEndPoints.radioseriesid + "?categoryid=" + categoryId;
            $http({ method: "get", url: reqUrl }).success(function (data) { defer.resolve(data); }).error(function (data) { defer.reject("failed request"); });
            return defer.promise;
        }
    }
})();;
(function () {
    'use strict';
    var controllerName = "listingCtrl";

    var c_dm = "_listingdisplaytype";

    angular.module('app').controller(controllerName, ['$scope', '$attrs', 'listingService', '$location', 'common', listingCtrl]);

    function listingCtrl($scope, $attrs, listingService, $location, common) {

        $scope.nothumbs = $attrs.nothumbs == "true";
        $scope.allResults = false;
        $scope.displaymode = listingService.getDisplayMode(c_dm, $attrs.displaymode);

        //radio portals cant use thumbnailgrid list
        if ($scope.nothumbs) $scope.displaymode = 'List';

        listingService.setDisplayMode(c_dm, $scope.displaymode);
        $scope.setDisplayType = setDisplayType;

        $scope.columns = $attrs.columns || 5;
        $scope.pagerstep = $attrs.paginationSize || 10;

        $scope.userDoFind = userDoFind;

        $scope.defimage = $attrs.defimage;
        $scope.bscol = "span" + Math.floor(12 / $scope.columns + 1); /**/

        $scope.path = $attrs.path;
        var culture = $attrs.culture;
        var langs = ['et', 'en-GB', 'ru'];
        $(".datepicker").datepicker($.extend({}, $.datepicker.regional[langs[culture]], { dateFormat: 'dd.mm.yy' }));
        $scope.activeQuery = listingService.getCurrentOrDefaultQueryParams($location.search());
        $scope.doFind = doFind;

        $scope.pagination = {
            page: $scope.activeQuery.page,
            pagesize: $scope.activeQuery.pagesize,
            totalResults: 0,
            parentreset: true
        };

        doFind();

        function setDisplayType(type) {
            $scope.displaymode = type;
            listingService.setDisplayMode(c_dm, type);
        }

        function doFind() {
            if ($scope.allResults) {
                $scope.pagination.page = 1;
                $scope.pagination.pagesize = $scope.pagination.totalResults;
            }
            var query = angular.extend($scope.activeQuery, { path: $scope.path, page: $scope.pagination.page, pagesize: $scope.pagination.pagesize, showAll: $scope.allResults });
            listingService.getPageByPath(query).then(handleResults);
            $location.search(query);
        }

        function userDoFind() {
            $scope.pagination.parentreset = !$scope.pagination.parentreset;
            $scope.pagination.page = 1;
            $scope.doFind();
        }
        function handleResults(data) {
            $scope.pagination.totalResults = parseInt(data.Total);
            data.ListItemsPartitioned = common.partition(data.ListItems, $scope.columns);
            $scope.resultSet = data;
            document.getElementById('listingview_input').scrollIntoView();
        }
    }
})();
(function () {
    'use strict';
    var sid = "listingService";

    angular.module('app').service(sid, ['$http', '$q', '$cookieStore', listingService]);

    function listingService($http, $q, $cookieStore) {

        var endPoints = {
            byPath: function (query) { return "/api/listing/bypath?path=" + query.path + "&page=" + query.page + "&pagesize=" + query.pagesize + "&phrase=" + query.phrase + "&from=" + query.from + "&to=" + query.to + "&showAll=" + query.showAll; }
        }

        var services = {
            getPageByPath: getPageByPath,
            getCurrentOrDefaultQueryParams: getCurrentOrDefaultQueryParams,
            getDisplayMode: getDisplayMode,
            setDisplayMode: setDisplayMode
        };
        return services;

        function getDisplayMode(cookieName, defaultValue) {
            var storedValue = $cookieStore.get(cookieName);
            if (storedValue !== null && storedValue != undefined && typeof storedValue === "string" && storedValue.length > 0) {
                return storedValue;
            }
            return defaultValue;
        }

        function setDisplayMode(cookieName, value) {
            $cookieStore.put(cookieName, value);
        }

        function getPageByPath(query) {
            var def = $q.defer();
            $http({ method: "get", url: endPoints.byPath(query) }).success(function (data) { def.resolve(data); });
            return def.promise;
        }
        function getCurrentOrDefaultQueryParams(params) {
            var defaultO = {
                page: !isNaN(params.page) ? parseInt(params.page) : 1
                , pagesize: !isNaN(params.pagesize) ? parseInt(params.pagesize) : 20
                , phrase: params.phrase || ""
                , from: params.from || ""
                , to: params.to || ""
                //$.datepicker.formatDate("dd.mm.yy", new Date())
            };
            if (defaultO.pagesize > 200) defaultO.pagesize = 200;
            return defaultO;
        }
    }
})();
//depends on the slice filter for the view part.
(function () {
    'use strict';
    //renamed this to from 'pagination' to errpagination because a directive named 'pagination' is already getting added from somewhere, is someone adding some 3rd party angular directives that clash with this?
    var directiveId = "errpagination";

    angular.module('app').directive(directiveId, [pagination]);

    function pagination() {
        var directive = {
            templateUrl: '/FrontUI/Templates/AngularTemplates/pagination',
            replace: true,
            link: link,
            scope: {
                paginationinfo: "=",
                parentloadfunc: "&",
                pagerstep: "="
            },
            restrict: 'A'
        };
        return directive;

        function link(scope) {

            scope.paginginner = {
                totalPages: [],
                sliceStart: 0,
                sliceStop: scope.pagerstep,
            }

            scope.setTotalPages = function () {
                var totalPages = Math.ceil(scope.paginationinfo.totalResults / scope.paginationinfo.pagesize);
                scope.paginginner.totalPages = [];
                for (var i = 1; i <= totalPages; i++) { scope.paginginner.totalPages.push(i); }
            }


            scope.$watch('paginationinfo.totalResults', scope.setTotalPages);

            //paginationinfo.parentreset is a signaling object.
            scope.$watch('paginationinfo.parentreset', function () {
                scope.paginginner = {
                    totalPages: [],
                    sliceStart: 0,
                    sliceStop: scope.pagerstep,
                };
                scope.setTotalPages();
            });

            scope.next = function () {
                if (scope.paginationinfo.page < scope.paginginner.totalPages.length) {
                    scope.paginationinfo.page++;
                    if (scope.paginationinfo.page > scope.paginginner.sliceStop) { scope.paginationNext(); }
                    scope.parentloadfunc();
                }
            }

            scope.paginationNext = function () {
                var newSliceStop = Math.min((scope.paginginner.sliceStop + scope.pagerstep), scope.paginginner.totalPages.length);
                if (newSliceStop != scope.paginginner.sliceStop && newSliceStop > scope.paginginner.sliceStop) {
                    scope.paginginner.sliceStart += scope.pagerstep;
                    scope.paginginner.sliceStop = newSliceStop;
                }
            }
            scope.prev = function () {
                if (scope.paginationinfo.page > 0) {
                    scope.paginationinfo.page--;
                    if (scope.paginationinfo.page == scope.paginginner.sliceStart) { scope.paginationPrev(); }
                    scope.parentloadfunc();
                }
            }

            scope.paginationPrev = function () {
                if (scope.paginginner.sliceStart - scope.pagerstep >= 0 && scope.paginationinfo.page > 0) {
                    scope.paginginner.sliceStart -= scope.pagerstep;
                    scope.paginginner.sliceStop = scope.paginginner.sliceStart + scope.pagerstep;
                }
            }

            scope.loadPage = function (pageNumber) {
                scope.paginationinfo.page = pageNumber;
                scope.parentloadfunc();
            }
            //todo: pagesize change logic (stay on same newsitem + cookies) 
        }
    }

})();;
(function () {
    'use strict';

    angular
        .module('app')
        .directive('listitemdisplaylist', listitemdisplaylist);

    listitemdisplaylist.$inject = ['$window'];

    function listitemdisplaylist($window) {
        var directive = {
            templateUrl: '/FrontUI/Templates/AngularTemplates/listitemdisplaylist',
            replace: true,
            link: link,
            restrict: 'A',
            scope: { item: "=" }
        };
        return directive;

        function link(scope, element, attrs) {

        }
    }

})();;
(function () {
    'use strict';

    angular
        .module('app')
        .directive('listitemdesktopdisplaylist', listitemdesktopdisplaylist);

    listitemdesktopdisplaylist.$inject = ['$window'];

    function listitemdesktopdisplaylist($window) {
        var directive = {
            templateUrl: '/FrontUI/Templates/AngularTemplates/listitemdesktopdisplaylist',
            replace: true,
            link: link,
            restrict: 'A',
            scope : { item: "=" }
        };
        return directive;

        function link(scope, element, attrs) {

        }
    }

})();;
(function () {
    'use strict';
    var resourceEndpoint = "http://static.err.ee/gridfs/";

    angular.module('app').directive('listitemdisplaythumbnail', ['$window', 'common', listItemDisplay]);


    function listItemDisplay($window, common) {
        var directive = {
            replace: true,
            link: link,
            restrict: 'EA',
            templateUrl: '/FrontUI/Templates/AngularTemplates/listitemdisplaythumbnail',
            scope: {
                item: "=",
                defimage: "=",
                imageurl: "=",
                resizeoptions: "="
            }
        };
        return directive;

        function link(scope, element, attrs) {
            scope.resizedImg = function () {

                element.children('.multirow-ellipsis').dotdotdot({
                    height: 120
                });

                var img = element.children('img');

                img.bind('error', function () {
                    img.unbind('error');
                    img.attr('src', resourceEndpoint + scope.defimage + "?width=" + element.width());
                });

                var imageUrl = scope.imageurl;
                var resizeOptions = scope.resizeoptions;

                var elementWidth = parseInt(element.width());
                var maxHeight = parseInt((elementWidth / 16) * 9);
                var defaulted = false;
                
                if (imageUrl === undefined || imageUrl === null || imageUrl === "") { imageUrl = scope.defimage; }

                if (resizeOptions === undefined || resizeOptions === null || resizeOptions === "") {
                    resizeOptions = "?width=" + elementWidth + "&maxheight=" + maxHeight;
                    defaulted = true;
                }

                var imgUrl = imageUrl + resizeOptions;
                if (!defaulted) {
                    imgUrl = common.addOrUpdateQueryParam(imgUrl, 'maxheight', maxHeight);
                    imgUrl = common.addOrUpdateQueryParam(imgUrl, 'width', elementWidth);
                    imgUrl = common.addOrUpdateQueryParam(imgUrl, 'quality', 90);
                }
                return resourceEndpoint + imgUrl;
            }
        }
    }
})();;
(function() {

    'use strict';
    var fid = 'unsafe';
    angular.module('app').filter(fid, ['$sce', trustasfilter]);
    function trustasfilter($sce) { return $sce.trustAsHtml; }

})();;
(function () {
    'use strict';

    var serviceId = 'common';

    angular.module('app').service(serviceId, [common]);

    function common() {
        
        var service = {
            partition: partition,
            addOrUpdateQueryParam: addOrUpdateQueryParam
        };

        return service;

        function addOrUpdateQueryParam(url, param, value) {
            var regex = new RegExp('(' + param + '=)[^\&#]+', 'i');

            if (regex.test(url)) return url.replace(regex, '$1' + value);

            var split = url.split('#');

            var delim = split[0].indexOf('?') > -1 ? "&" : "?";

            var added = delim + param + "=" + value;

            split[0] += added;

            return split.join("#");
        }

        function partition(arr, size) {
            if (!arr) return [];
            var newArr = [];
            for (var i = 0; i < arr.length; i += size) { newArr.push(arr.slice(i, i + size)); }
            return newArr;
        }
    }
})();;
(function () {
    'use strict';

    var controllerId = 'uploadController';

    angular.module('app').controller(controllerId,
        ['$scope', uploadController]);

    function uploadController($scope) {
        $scope.progress = '1%';
        $scope.fileUpload = false;
        $scope.showError = false;
        $scope.files = "";
        $scope.agreedWithConditions = false;

        $scope.fileUploadSuccess = function (message) {
            var statusMessage = JSON.parse(message);
            if (statusMessage.StatusCode == 500) {
                $scope.showError = true;
                $scope.progress = '0%';
            } else {
                var data = encodeURIComponent(statusMessage.Data);
                if ($scope.files == "") {
                    $scope.files = data;
                } else {
                    $scope.files.concat(data);
                }
                $scope.fileUpload = true;
            }
        };

        $scope.setProgress = function (progress) {
            if (!$scope.showError) {
                $scope.progress = progress * 100 + '%';
            }
        }

        $scope.fileUploadError = function (message) {
            $scope.showError = true;
        }

        $scope.agreementNecessary = function (nec) {
            $scope.greedWithConditions = !nec;
        }
    }
})();;
/*! ng-flow 2.6.1 */
!function (a, b, c) { "use strict"; function d(b) { if (this.support = !("undefined" == typeof File || "undefined" == typeof Blob || "undefined" == typeof FileList || !Blob.prototype.slice && !Blob.prototype.webkitSlice && !Blob.prototype.mozSlice), this.support) { this.supportDirectory = /WebKit/.test(a.navigator.userAgent), this.files = [], this.defaults = { chunkSize: 1048576, forceChunkSize: !1, simultaneousUploads: 3, singleFile: !1, fileParameterName: "file", progressCallbacksInterval: 500, speedSmoothingFactor: .1, query: {}, headers: {}, withCredentials: !1, preprocess: null, method: "multipart", testMethod: "GET", uploadMethod: "POST", prioritizeFirstAndLastChunk: !1, target: "/", testChunks: !0, generateUniqueIdentifier: null, maxChunkRetries: 0, chunkRetryInterval: null, permanentErrors: [404, 415, 500, 501], successStatuses: [200, 201, 202], onDropStopPropagation: !1 }, this.opts = {}, this.events = {}; var c = this; this.onDrop = function (a) { c.opts.onDropStopPropagation && a.stopPropagation(), a.preventDefault(); var b = a.dataTransfer; b.items && b.items[0] && b.items[0].webkitGetAsEntry ? c.webkitReadDataTransfer(a) : c.addFiles(b.files, a) }, this.preventEvent = function (a) { a.preventDefault() }, this.opts = d.extend({}, this.defaults, b || {}) } } function e(a, b) { this.flowObj = a, this.file = b, this.name = b.fileName || b.name, this.size = b.size, this.relativePath = b.relativePath || b.webkitRelativePath || this.name, this.uniqueIdentifier = a.generateUniqueIdentifier(b), this.chunks = [], this.paused = !1, this.error = !1, this.averageSpeed = 0, this.currentSpeed = 0, this._lastProgressCallback = Date.now(), this._prevUploadedSize = 0, this._prevProgress = 0, this.bootstrap() } function f(a, b, c) { this.flowObj = a, this.fileObj = b, this.fileObjSize = b.size, this.offset = c, this.tested = !1, this.retries = 0, this.pendingRetry = !1, this.preprocessState = 0, this.loaded = 0, this.total = 0; var d = this.flowObj.opts.chunkSize; this.startByte = this.offset * d, this.endByte = Math.min(this.fileObjSize, (this.offset + 1) * d), this.xhr = null, this.fileObjSize - this.endByte < d && !this.flowObj.opts.forceChunkSize && (this.endByte = this.fileObjSize); var e = this; this.event = function (a, b) { b = Array.prototype.slice.call(arguments), b.unshift(e), e.fileObj.chunkEvent.apply(e.fileObj, b) }, this.progressHandler = function (a) { a.lengthComputable && (e.loaded = a.loaded, e.total = a.total), e.event("progress", a) }, this.testHandler = function () { var a = e.status(!0); "error" === a ? (e.event(a, e.message()), e.flowObj.uploadNextChunk()) : "success" === a ? (e.tested = !0, e.event(a, e.message()), e.flowObj.uploadNextChunk()) : e.fileObj.paused || (e.tested = !0, e.send()) }, this.doneHandler = function () { var a = e.status(); if ("success" === a || "error" === a) e.event(a, e.message()), e.flowObj.uploadNextChunk(); else { e.event("retry", e.message()), e.pendingRetry = !0, e.abort(), e.retries++; var b = e.flowObj.opts.chunkRetryInterval; null !== b ? setTimeout(function () { e.send() }, b) : e.send() } } } function g(a, b) { var c = a.indexOf(b); c > -1 && a.splice(c, 1) } function h(a, b) { return "function" == typeof a && (b = Array.prototype.slice.call(arguments), a = a.apply(null, b.slice(1))), a } function i(a, b) { setTimeout(a.bind(b), 0) } function j(a) { return k(arguments, function (b) { b !== a && k(b, function (b, c) { a[c] = b }) }), a } function k(a, b, c) { if (a) { var d; if ("undefined" != typeof a.length) { for (d = 0; d < a.length; d++) if (b.call(c, a[d], d) === !1) return } else for (d in a) if (a.hasOwnProperty(d) && b.call(c, a[d], d) === !1) return } } var l = a.navigator.msPointerEnabled; d.prototype = { on: function (a, b) { a = a.toLowerCase(), this.events.hasOwnProperty(a) || (this.events[a] = []), this.events[a].push(b) }, off: function (a, b) { a !== c ? (a = a.toLowerCase(), b !== c ? this.events.hasOwnProperty(a) && g(this.events[a], b) : delete this.events[a]) : this.events = {} }, fire: function (a, b) { b = Array.prototype.slice.call(arguments), a = a.toLowerCase(); var c = !1; return this.events.hasOwnProperty(a) && k(this.events[a], function (a) { c = a.apply(this, b.slice(1)) === !1 || c }, this), "catchall" != a && (b.unshift("catchAll"), c = this.fire.apply(this, b) === !1 || c), !c }, webkitReadDataTransfer: function (a) { function b(a) { g += a.length, k(a, function (a) { if (a.isFile) { var e = a.fullPath; a.file(function (a) { c(a, e) }, d) } else a.isDirectory && a.createReader().readEntries(b, d) }), e() } function c(a, b) { a.relativePath = b.substring(1), h.push(a), e() } function d(a) { throw a } function e() { 0 == --g && f.addFiles(h, a) } var f = this, g = a.dataTransfer.items.length, h = []; k(a.dataTransfer.items, function (a) { var f = a.webkitGetAsEntry(); return f ? void (f.isFile ? c(a.getAsFile(), f.fullPath) : f.createReader().readEntries(b, d)) : void e() }) }, generateUniqueIdentifier: function (a) { var b = this.opts.generateUniqueIdentifier; if ("function" == typeof b) return b(a); var c = a.relativePath || a.webkitRelativePath || a.fileName || a.name; return a.size + "-" + c.replace(/[^0-9a-zA-Z_-]/gim, "") }, uploadNextChunk: function (a) { var b = !1; if (this.opts.prioritizeFirstAndLastChunk && (k(this.files, function (a) { return !a.paused && a.chunks.length && "pending" === a.chunks[0].status() && 0 === a.chunks[0].preprocessState ? (a.chunks[0].send(), b = !0, !1) : !a.paused && a.chunks.length > 1 && "pending" === a.chunks[a.chunks.length - 1].status() && 0 === a.chunks[0].preprocessState ? (a.chunks[a.chunks.length - 1].send(), b = !0, !1) : void 0 }), b)) return b; if (k(this.files, function (a) { return a.paused || k(a.chunks, function (a) { return "pending" === a.status() && 0 === a.preprocessState ? (a.send(), b = !0, !1) : void 0 }), b ? !1 : void 0 }), b) return !0; var c = !1; return k(this.files, function (a) { return a.isComplete() ? void 0 : (c = !0, !1) }), c || a || i(function () { this.fire("complete") }, this), !1 }, assignBrowse: function (a, c, d, e) { "undefined" == typeof a.length && (a = [a]), k(a, function (a) { var f; "INPUT" === a.tagName && "file" === a.type ? f = a : (f = b.createElement("input"), f.setAttribute("type", "file"), j(f.style, { visibility: "hidden", position: "absolute" }), a.appendChild(f), a.addEventListener("click", function () { f.click() }, !1)), this.opts.singleFile || d || f.setAttribute("multiple", "multiple"), c && f.setAttribute("webkitdirectory", "webkitdirectory"), k(e, function (a, b) { f.setAttribute(b, a) }); var g = this; f.addEventListener("change", function (a) { g.addFiles(a.target.files, a), a.target.value = "" }, !1) }, this) }, assignDrop: function (a) { "undefined" == typeof a.length && (a = [a]), k(a, function (a) { a.addEventListener("dragover", this.preventEvent, !1), a.addEventListener("dragenter", this.preventEvent, !1), a.addEventListener("drop", this.onDrop, !1) }, this) }, unAssignDrop: function (a) { "undefined" == typeof a.length && (a = [a]), k(a, function (a) { a.removeEventListener("dragover", this.preventEvent), a.removeEventListener("dragenter", this.preventEvent), a.removeEventListener("drop", this.onDrop) }, this) }, isUploading: function () { var a = !1; return k(this.files, function (b) { return b.isUploading() ? (a = !0, !1) : void 0 }), a }, _shouldUploadNext: function () { var a = 0, b = !0, c = this.opts.simultaneousUploads; return k(this.files, function (d) { k(d.chunks, function (d) { return "uploading" === d.status() && (a++, a >= c) ? (b = !1, !1) : void 0 }) }), b && a }, upload: function () { var a = this._shouldUploadNext(); if (a !== !1) { this.fire("uploadStart"); for (var b = !1, c = 1; c <= this.opts.simultaneousUploads - a; c++) b = this.uploadNextChunk(!0) || b; b || i(function () { this.fire("complete") }, this) } }, resume: function () { k(this.files, function (a) { a.resume() }) }, pause: function () { k(this.files, function (a) { a.pause() }) }, cancel: function () { for (var a = this.files.length - 1; a >= 0; a--) this.files[a].cancel() }, progress: function () { var a = 0, b = 0; return k(this.files, function (c) { a += c.progress() * c.size, b += c.size }), b > 0 ? a / b : 0 }, addFile: function (a, b) { this.addFiles([a], b) }, addFiles: function (a, b) { var c = []; k(a, function (a) { if ((!l || l && a.size > 0) && (a.size % 4096 !== 0 || "." !== a.name && "." !== a.fileName) && !this.getFromUniqueIdentifier(this.generateUniqueIdentifier(a))) { var d = new e(this, a); this.fire("fileAdded", d, b) && c.push(d) } }, this), this.fire("filesAdded", c, b) && k(c, function (a) { this.opts.singleFile && this.files.length > 0 && this.removeFile(this.files[0]), this.files.push(a) }, this), this.fire("filesSubmitted", c, b) }, removeFile: function (a) { for (var b = this.files.length - 1; b >= 0; b--) this.files[b] === a && (this.files.splice(b, 1), a.abort()) }, getFromUniqueIdentifier: function (a) { var b = !1; return k(this.files, function (c) { c.uniqueIdentifier === a && (b = c) }), b }, getSize: function () { var a = 0; return k(this.files, function (b) { a += b.size }), a }, sizeUploaded: function () { var a = 0; return k(this.files, function (b) { a += b.sizeUploaded() }), a }, timeRemaining: function () { var a = 0, b = 0; return k(this.files, function (c) { c.paused || c.error || (a += c.size - c.sizeUploaded(), b += c.averageSpeed) }), a && !b ? Number.POSITIVE_INFINITY : a || b ? Math.floor(a / b) : 0 } }, e.prototype = { measureSpeed: function () { var a = Date.now() - this._lastProgressCallback; if (a) { var b = this.flowObj.opts.speedSmoothingFactor, c = this.sizeUploaded(); this.currentSpeed = Math.max((c - this._prevUploadedSize) / a * 1e3, 0), this.averageSpeed = b * this.currentSpeed + (1 - b) * this.averageSpeed, this._prevUploadedSize = c } }, chunkEvent: function (a, b, c) { switch (b) { case "progress": if (Date.now() - this._lastProgressCallback < this.flowObj.opts.progressCallbacksInterval) break; this.measureSpeed(), this.flowObj.fire("fileProgress", this, a), this.flowObj.fire("progress"), this._lastProgressCallback = Date.now(); break; case "error": this.error = !0, this.abort(!0), this.flowObj.fire("fileError", this, c, a), this.flowObj.fire("error", c, this, a); break; case "success": if (this.error) return; this.measureSpeed(), this.flowObj.fire("fileProgress", this, a), this.flowObj.fire("progress"), this._lastProgressCallback = Date.now(), this.isComplete() && (this.currentSpeed = 0, this.averageSpeed = 0, this.flowObj.fire("fileSuccess", this, c, a)); break; case "retry": this.flowObj.fire("fileRetry", this, a) } }, pause: function () { this.paused = !0, this.abort() }, resume: function () { this.paused = !1, this.flowObj.upload() }, abort: function (a) { this.currentSpeed = 0, this.averageSpeed = 0; var b = this.chunks; a && (this.chunks = []), k(b, function (a) { "uploading" === a.status() && (a.abort(), this.flowObj.uploadNextChunk()) }, this) }, cancel: function () { this.flowObj.removeFile(this) }, retry: function () { this.bootstrap(), this.flowObj.upload() }, bootstrap: function () { this.abort(!0), this.error = !1, this._prevProgress = 0; for (var a = this.flowObj.opts.forceChunkSize ? Math.ceil : Math.floor, b = Math.max(a(this.file.size / this.flowObj.opts.chunkSize), 1), c = 0; b > c; c++) this.chunks.push(new f(this.flowObj, this, c)) }, progress: function () { if (this.error) return 1; if (1 === this.chunks.length) return this._prevProgress = Math.max(this._prevProgress, this.chunks[0].progress()), this._prevProgress; var a = 0; k(this.chunks, function (b) { a += b.progress() * (b.endByte - b.startByte) }); var b = a / this.size; return this._prevProgress = Math.max(this._prevProgress, b > .9999 ? 1 : b), this._prevProgress }, isUploading: function () { var a = !1; return k(this.chunks, function (b) { return "uploading" === b.status() ? (a = !0, !1) : void 0 }), a }, isComplete: function () { var a = !1; return k(this.chunks, function (b) { var c = b.status(); return "pending" === c || "uploading" === c || 1 === b.preprocessState ? (a = !0, !1) : void 0 }), !a }, sizeUploaded: function () { var a = 0; return k(this.chunks, function (b) { a += b.sizeUploaded() }), a }, timeRemaining: function () { if (this.paused || this.error) return 0; var a = this.size - this.sizeUploaded(); return a && !this.averageSpeed ? Number.POSITIVE_INFINITY : a || this.averageSpeed ? Math.floor(a / this.averageSpeed) : 0 }, getType: function () { return this.file.type && this.file.type.split("/")[1] }, getExtension: function () { return this.name.substr((~-this.name.lastIndexOf(".") >>> 0) + 2).toLowerCase() } }, f.prototype = { getParams: function () { return { flowChunkNumber: this.offset + 1, flowChunkSize: this.flowObj.opts.chunkSize, flowCurrentChunkSize: this.endByte - this.startByte, flowTotalSize: this.fileObjSize, flowIdentifier: this.fileObj.uniqueIdentifier, flowFilename: this.fileObj.name, flowRelativePath: this.fileObj.relativePath, flowTotalChunks: this.fileObj.chunks.length } }, getTarget: function (a, b) { return a += a.indexOf("?") < 0 ? "?" : "&", a + b.join("&") }, test: function () { this.xhr = new XMLHttpRequest, this.xhr.addEventListener("load", this.testHandler, !1), this.xhr.addEventListener("error", this.testHandler, !1); var a = h(this.flowObj.opts.testMethod, this.fileObj, this), b = this.prepareXhrRequest(a, !0); this.xhr.send(b) }, preprocessFinished: function () { this.preprocessState = 2, this.send() }, send: function () { var a = this.flowObj.opts.preprocess; if ("function" == typeof a) switch (this.preprocessState) { case 0: return this.preprocessState = 1, void a(this); case 1: return } if (this.flowObj.opts.testChunks && !this.tested) return void this.test(); this.loaded = 0, this.total = 0, this.pendingRetry = !1; var b = this.fileObj.file.slice ? "slice" : this.fileObj.file.mozSlice ? "mozSlice" : this.fileObj.file.webkitSlice ? "webkitSlice" : "slice", c = this.fileObj.file[b](this.startByte, this.endByte, this.fileObj.file.type); this.xhr = new XMLHttpRequest, this.xhr.upload.addEventListener("progress", this.progressHandler, !1), this.xhr.addEventListener("load", this.doneHandler, !1), this.xhr.addEventListener("error", this.doneHandler, !1); var d = h(this.flowObj.opts.uploadMethod, this.fileObj, this), e = this.prepareXhrRequest(d, !1, this.flowObj.opts.method, c); this.xhr.send(e) }, abort: function () { var a = this.xhr; this.xhr = null, a && a.abort() }, status: function (a) { return this.pendingRetry || 1 === this.preprocessState ? "uploading" : this.xhr ? this.xhr.readyState < 4 ? "uploading" : this.flowObj.opts.successStatuses.indexOf(this.xhr.status) > -1 ? "success" : this.flowObj.opts.permanentErrors.indexOf(this.xhr.status) > -1 || !a && this.retries >= this.flowObj.opts.maxChunkRetries ? "error" : (this.abort(), "pending") : "pending" }, message: function () { return this.xhr ? this.xhr.responseText : "" }, progress: function () { if (this.pendingRetry) return 0; var a = this.status(); return "success" === a || "error" === a ? 1 : "pending" === a ? 0 : this.total > 0 ? this.loaded / this.total : 0 }, sizeUploaded: function () { var a = this.endByte - this.startByte; return "success" !== this.status() && (a = this.progress() * a), a }, prepareXhrRequest: function (a, b, c, d) { var e = h(this.flowObj.opts.query, this.fileObj, this, b); e = j(this.getParams(), e); var f = h(this.flowObj.opts.target, this.fileObj, this, b), g = null; if ("GET" === a || "octet" === c) { var i = []; k(e, function (a, b) { i.push([encodeURIComponent(b), encodeURIComponent(a)].join("=")) }), f = this.getTarget(f, i), g = d || null } else g = new FormData, k(e, function (a, b) { g.append(b, a) }), g.append(this.flowObj.opts.fileParameterName, d, this.fileObj.file.name); return this.xhr.open(a, f, !0), this.xhr.withCredentials = this.flowObj.opts.withCredentials, k(h(this.flowObj.opts.headers, this.fileObj, this, b), function (a, b) { this.xhr.setRequestHeader(b, a) }, this), g } }, d.evalOpts = h, d.extend = j, d.each = k, d.FlowFile = e, d.FlowChunk = f, d.version = "2.9.0", "object" == typeof module && module && "object" == typeof module.exports ? module.exports = d : (a.Flow = d, "function" == typeof define && define.amd && define("flow", [], function () { return d })) }(window, document), angular.module("flow.provider", []).provider("flowFactory", function () { "use strict"; this.defaults = {}, this.factory = function (a) { return new Flow(a) }, this.events = [], this.on = function (a, b) { this.events.push([a, b]) }, this.$get = function () { var a = this.factory, b = this.defaults, c = this.events; return { create: function (d) { var e = a(angular.extend({}, b, d)); return angular.forEach(c, function (a) { e.on(a[0], a[1]) }), e } } } }), angular.module("flow.init", ["flow.provider"]).controller("flowCtrl", ["$scope", "$attrs", "$parse", "flowFactory", function (a, b, c, d) { var e = angular.extend({}, a.$eval(b.flowInit)), f = a.$eval(b.flowObject) || d.create(e), g = function (b) { var c = Array.prototype.slice.call(arguments); c.shift(); var d = a.$broadcast.apply(a, ["flow::" + b, f].concat(c)); return { progress: 1, filesSubmitted: 1, fileSuccess: 1, fileError: 1, complete: 1 }[b] && a.$apply(), d.defaultPrevented ? !1 : void 0 }; f.on("catchAll", g), a.$on("$destroy", function () { f.off("catchAll", g) }), a.$flow = f, b.hasOwnProperty("flowName") && (c(b.flowName).assign(a, f), a.$on("$destroy", function () { c(b.flowName).assign(a) })) }]).directive("flowInit", [function () { return { scope: !0, controller: "flowCtrl" } }]), angular.module("flow.btn", ["flow.init"]).directive("flowBtn", [function () { return { restrict: "EA", scope: !1, require: "^flowInit", link: function (a, b, c) { var d = c.hasOwnProperty("flowDirectory"), e = c.hasOwnProperty("flowSingleFile"), f = c.hasOwnProperty("flowAttrs") && a.$eval(c.flowAttrs); a.$flow.assignBrowse(b, d, e, f) } } }]), angular.module("flow.dragEvents", ["flow.init"]).directive("flowPreventDrop", function () { return { scope: !1, link: function (a, b) { b.bind("drop dragover", function (a) { a.preventDefault() }) } } }).directive("flowDragEnter", ["$timeout", function (a) { return { scope: !1, link: function (b, c, d) { function e(a) { var b = !1, c = a.dataTransfer || a.originalEvent.dataTransfer; return angular.forEach(c && c.types, function (a) { "Files" === a && (b = !0) }), b } var f, g = !1; c.bind("dragover", function (c) { e(c) && (g || (b.$apply(d.flowDragEnter), g = !0), a.cancel(f), c.preventDefault()) }), c.bind("dragleave drop", function () { a.cancel(f), f = a(function () { b.$eval(d.flowDragLeave), f = null, g = !1 }, 100) }) } } }]), angular.module("flow.drop", ["flow.init"]).directive("flowDrop", function () { return { scope: !1, require: "^flowInit", link: function (a, b, c) { function d() { a.$flow.assignDrop(b) } function e() { a.$flow.unAssignDrop(b) } c.flowDropEnabled ? a.$watch(c.flowDropEnabled, function (a) { a ? d() : e() }) : d() } } }), !function (a) { "use strict"; function b(a) { return a.charAt(0).toUpperCase() + a.slice(1) } var c = a.module("flow.events", ["flow.init"]), d = { fileSuccess: ["$file", "$message"], fileProgress: ["$file"], fileAdded: ["$file", "$event"], filesAdded: ["$files", "$event"], filesSubmitted: ["$files", "$event"], fileRetry: ["$file"], fileError: ["$file", "$message"], uploadStart: [], complete: [], progress: [], error: ["$message", "$file"] }; a.forEach(d, function (d, e) { var f = "flow" + b(e); "flowUploadStart" == f && (f = "flowUploadStarted"), c.directive(f, [function () { return { require: "^flowInit", controller: ["$scope", "$attrs", function (b, c) { b.$on("flow::" + e, function () { var e = Array.prototype.slice.call(arguments), g = e.shift(); if (b.$flow === e.shift()) { var h = {}; a.forEach(d, function (a, b) { h[a] = e[b] }), b.$eval(c[f], h) === !1 && g.preventDefault() } }) }] } }]) }) }(angular), angular.module("flow.img", ["flow.init"]).directive("flowImg", [function () { return { scope: !1, require: "^flowInit", link: function (a, b, c) { var d = c.flowImg; a.$watch(d, function (b) { if (b) { var d = new FileReader; d.readAsDataURL(b.file), d.onload = function (b) { a.$apply(function () { c.$set("src", b.target.result) }) } } }) } } }]), angular.module("flow.transfers", ["flow.init"]).directive("flowTransfers", [function () { return { scope: !0, require: "^flowInit", link: function (a) { a.transfers = a.$flow.files } } }]), angular.module("flow", ["flow.provider", "flow.init", "flow.events", "flow.btn", "flow.drop", "flow.transfers", "flow.img", "flow.dragEvents"]);;
(function () {
    'use strict';

    angular.module('app').directive('mediaPlayer', ['$sce', '$compile', '$timeout', '$http', '$templateCache', mediaPlayer]);

    function mediaPlayer($sce, $compile, $timeout, $http, $templateCache) {
        var directive = {
            compile: compile,
            restrict: 'AE',
            scope: {
                media: "="
            }

        };
        return directive;

        function compile(elem, attrs) {
            return function (scope, element, attrs) {
                var template = "";

                var reuse = false;
                var videoHeight = 0;
                var timerCancel = false;
                var showEndscreen = true;
                scope.videoplayer = false;
                scope.playerError = false;
                scope.$watch("media", function (newV, oldV) {
                    init();
                }, true);

                scope.trustSrc = function (filePath) {
                    return $sce.trustAsResourceUrl(filePath);
                };
                scope.cancelNew = function () {
                    timerCancel = true;
                    scope.$broadcast('timer-stop');
                };
                scope.toNext = function () {//Lõik või saade

                    timerCancel = true;
                    scope.$broadcast('timer-stop');

                    if (scope.nextMehod == 1 && scope.media.NextPartCode) {
                        $timeout(function () {
                            angular.element(scope.media.NextPartCode).trigger("click");
                        });

                    }
                    else if (nextUrl) {
                        $timeout(function () {
                            document.location = nextUrl + "#autoplay";
                        });
                    }
                };

                scope.$on('timer-stopped', function () {
                    if (timerCancel === true)
                        return;
                    scope.toNext();
                });

                function init() {

                    if (!$templateCache.get(attrs.template)) {
                        loadTemplate();
                    }
                    else {
                        parseMedia(scope.media);

                        if (!scope.player.reuse) {
                            var video = $compile(template)(scope);

                            element.html('').append(video);

                        }
                        $timeout(function () {

                            if (scope.videoplayer === false || !scope.player.reuse) {

                                scope.videoplayer = new meediaPlayer(angular.element('#' + scope.player.playerId), { clip: scope.player.clip });
                                if (typeof scope.videoplayer.getPlayer().on !== 'undefined') {
                                    scope.videoplayer.getPlayer().on('error', function () {
                                        scope.playerError = true;
                                    })
                                }
                            }
                            else {
                                if (scope.playerError === true) {
                                    scope.videoplayer.getPlayer().data('flowplayer').error = scope.videoplayer.getPlayer().data('flowplayer').loading = false;
                                    scope.videoplayer.getPlayer().removeClass('is-error');
                                    scope.playerError = false;
                                }
                                scope.player.clip.autoPlay = true;
                              
                                scope.videoplayer.loadClip(scope.player.clip);
                                scope.videoplayer.getPlayer().removeClass("is-finished");
                            }

                            var videoHeight = scope.videoplayer.getPlayer().height();

                            prepareEnd(videoHeight);
                            if (scope.videoplayer.getPlayer().data('flowplayer'))
                            {
                                scope.videoplayer.getPlayer().data('flowplayer').on("finish", function (e, api) {
                                    if (!showEndscreen) {
                                        scope.videoplayer.getPlayer().removeClass("is-finished");
                                        return;
                                    }
                                    timerCancel = false;
                                    scope.$broadcast('timer-start');


                                });
                            }
                            
                        });
                    }


                }

                function loadTemplate() {
                    var templateLoader = $http.get(attrs.template, { cache: $templateCache });
                    var promise = templateLoader.success(function (html) {
                        template = html;
                        init();
                    })
                }
                function parseMedia(media) {
                    scope.obj = false;

                    var emorPath = media.EmorPath;

                    if (media.Source.indexOf('object') != -1 || media.Source.indexOf('iframe') != -1) {
                        scope.obj = true;
                        return;
                    }
                    var player = {
                        playerId: media.PlayerId,
                        emorPath: emorPath,
                        nextTitle: "",
                        live: (media.Live ? "true" : "false"),
                        imageUrl: "http://static.err.ee/gridfs/" + media.ImageUrl + "&emorPath=" + encodeURIComponent(emorPath),
                        autoPlay: (window.location.hash.indexOf("autoplay") > -1 ? "true" : ""),
                        reuse: (typeof media.Reuse !== "undefined" && media.Reuse == 1 ? true : false)
                    };


                    var dir = "";
                    var file = "";

                    var imgHost = "http://static.err.ee/gridfs/";

                    var streamUrl = "media.err.ee";
                    var clip = {};
                    var mp3 = false;
                    if (media.Source.indexOf("://") === 0) {
                        clip.sources = media.Source;
                        
                    }
                    else if (media.Source.indexOf("heli.er") !== -1) {
                        clip.sources = [
                               { type: "audio/mpeg", src: media.Source }
                        ];
                    }
                    player.clip = clip;

                    scope.player = player;
                }
                function prepareEnd(playerHeight) {
                    showEndscreen = true;
                    var innerHeight = angular.element(".endscreen-inner").height();
                    scope.player.innerMargin = (playerHeight - innerHeight) / 2 + "px";


                    if (pos == (am - 1)) {
                        if (nextTitle == "") {
                            showEndscreen = false;
                            return;
                        }

                        scope.player.nextTitle = nextTitle;
                        scope.nextMehod = 2;
                    }
                    else if (pos < (am - 1)) {

                        scope.player.nextTitle = scope.media.NextPartName;
                        scope.nextMehod = 1;
                    }
                    else {
                        showEndscreen = false;
                    }

                }
            }
        }
    }

})();;
(function () {
    'use strict';
    var controllerId = 'mediaPlayerController';
    angular.module('app').controller(controllerId,
        ['$scope', mediaPlayerController]);

    function mediaPlayerController($scope) {
        $scope.media = {};
        $scope.setMedia = function (curpos, autoPlay, reuse) {
            curpos = parseInt(curpos);
            pos = curpos;
            var media = localList[pos];
            media.AutoPlay = autoPlay;
            media.Reuse = reuse;
            $scope.media = media;
        }
    }
})();;
window.twttr = (function (d, s, id) { var js, fjs = d.getElementsByTagName(s)[0], t = window.twttr || {}; if (d.getElementById(id)) return; js = d.createElement(s); js.id = id; js.src = "https://platform.twitter.com/widgets.js"; fjs.parentNode.insertBefore(js, fjs); t._e = []; t.ready = function (f) { t._e.push(f); }; return t; }(document, "script", "twitter-wjs"));;
(function () {
    'use strict';
    var controllerId = 'forumCtrl';
    angular.module('app').controller(controllerId,
        ['$scope', '$attrs', 'forumService', 'forumBll', '$interval', '$timeout', forumController]);

    function forumController($scope, $attrs, forumService, forumBll, $interval, $timeout) {

        $scope.title = 'forumCtrl';
        $scope.language = $attrs.language;
        $scope.activate = activate;
        $scope.lead = "";
        $scope.forumheader = "";
        $scope.comments = [];
        $scope.settings = {};
        $scope.commmentUrl = "http://" + window.location.host + "/k/" + $attrs.contentid;
        $scope.sendComment = sendComment;
        $scope.postedMessage = false;
        $scope.captchaError = false;
        $scope.captchaRequired = false;
        $scope.enterCaptcha = $attrs.enterfrompicture;
        $scope.noresize = $attrs.noresize == "true";
        var resizer;
        activate();

        function activate() {
            loadSettings();
            loadData();
        }
        function loadSettings() {
            $scope.settings.contentId = $attrs.contentid;
            resizer = $interval(function () {
                if (!$scope.noresize) {
                    var comments = $("#fwcomments");
                    var captcha = $("#fwcaptcha");
                    var captchaHeight = captcha.height();
                    var commentsHeight = comments.height();
                    if (captchaHeight != null) {
                        if (captchaHeight < commentsHeight) {
                            comments.height(captchaHeight);
                        }
                        if (captcha.height() <= comments.height()) {
                            $interval.cancel(resizer);
                        }
                    }
                }
                if (document.getElementsByName('recaptcha_response_field').length == 1) {
                    document.getElementsByName('recaptcha_response_field')[0].placeholder = $scope.enterCaptcha;
                }
            }, 200);
            $timeout(function () { stopResize(); }, 10000);
        }
        function stopResize() {
            if (angular.isDefined(resizer)) {
                $interval.cancel(resizer);
            }
        }
        function loadData() {
            if ($scope.settings.contentId && $scope.settings.contentId !== "00000000-0000-0000-0000-000000000000") {
                forumService.getContent($scope.settings.contentId, $scope.commentstoshow, $scope.language).then(handleLoadData);
            }
        }
        function sendComment() {
            var response = Recaptcha.get_response();
            if (response == null || response == undefined || !response.length > 0) {
                $scope.captchaRequired = true;
                $scope.captchaError = false;
                return;
            }
            var challenge = Recaptcha.get_challenge();
            var postable = {
                challenge: challenge,
                response: response,
                userName: $scope.userName,
                userComment: $scope.userComment,
                contentid: $scope.settings.contentId
            }
            forumService.tryPostComment(postable).then(tryPostSuccessHandler, tryPostFailHandler).finally(reloadCaptcha);
        }
        function tryPostSuccessHandler() {
            $scope.userName = "";
            $scope.userComment = "";
            $scope.commentForm.$setPristine(true);
            loadData();
            $scope.postedMessage = true;
            $scope.captchaError = false;
            $scope.catchaRequired = false;
        }
        function tryPostFailHandler() {
            $scope.captchaRequired = false;
            $scope.captchaError = true;
        }
        function reloadCaptcha() {
            Recaptcha.reload();
        }
        function handleLoadData(data) {
            forumBll.handleGetContent(data.data, $scope);
        }
    }
})();
;
/*
 AngularJS v1.3.14
 (c) 2010-2014 Google, Inc. http://angularjs.org
 License: MIT
*/
(function(y,u,z){'use strict';function s(h,k,p){n.directive(h,["$parse","$swipe",function(d,e){return function(l,m,f){function g(a){if(!c)return!1;var b=Math.abs(a.y-c.y);a=(a.x-c.x)*k;return q&&75>b&&0<a&&30<a&&.3>b/a}var b=d(f[h]),c,q,a=["touch"];u.isDefined(f.ngSwipeDisableMouse)||a.push("mouse");e.bind(m,{start:function(a,b){c=a;q=!0},cancel:function(a){q=!1},end:function(a,c){g(a)&&l.$apply(function(){m.triggerHandler(p);b(l,{$event:c})})}},a)}}])}var n=u.module("ngTouch",[]);n.factory("$swipe",
[function(){function h(d){var e=d.touches&&d.touches.length?d.touches:[d];d=d.changedTouches&&d.changedTouches[0]||d.originalEvent&&d.originalEvent.changedTouches&&d.originalEvent.changedTouches[0]||e[0].originalEvent||e[0];return{x:d.clientX,y:d.clientY}}function k(d,e){var l=[];u.forEach(d,function(d){(d=p[d][e])&&l.push(d)});return l.join(" ")}var p={mouse:{start:"mousedown",move:"mousemove",end:"mouseup"},touch:{start:"touchstart",move:"touchmove",end:"touchend",cancel:"touchcancel"}};return{bind:function(d,
e,l){var m,f,g,b,c=!1;l=l||["mouse","touch"];d.on(k(l,"start"),function(a){g=h(a);c=!0;f=m=0;b=g;e.start&&e.start(g,a)});var q=k(l,"cancel");if(q)d.on(q,function(a){c=!1;e.cancel&&e.cancel(a)});d.on(k(l,"move"),function(a){if(c&&g){var d=h(a);m+=Math.abs(d.x-b.x);f+=Math.abs(d.y-b.y);b=d;10>m&&10>f||(f>m?(c=!1,e.cancel&&e.cancel(a)):(a.preventDefault(),e.move&&e.move(d,a)))}});d.on(k(l,"end"),function(a){c&&(c=!1,e.end&&e.end(h(a),a))})}}}]);n.config(["$provide",function(h){h.decorator("ngClickDirective",
["$delegate",function(k){k.shift();return k}])}]);n.directive("ngClick",["$parse","$timeout","$rootElement",function(h,k,p){function d(b,c,d){for(var a=0;a<b.length;a+=2){var e=b[a+1],f=d;if(25>Math.abs(b[a]-c)&&25>Math.abs(e-f))return b.splice(a,a+2),!0}return!1}function e(b){if(!(2500<Date.now()-m)){var c=b.touches&&b.touches.length?b.touches:[b],e=c[0].clientX,c=c[0].clientY;1>e&&1>c||g&&g[0]===e&&g[1]===c||(g&&(g=null),"label"===b.target.tagName.toLowerCase()&&(g=[e,c]),d(f,e,c)||(b.stopPropagation(),
b.preventDefault(),b.target&&b.target.blur()))}}function l(b){b=b.touches&&b.touches.length?b.touches:[b];var c=b[0].clientX,d=b[0].clientY;f.push(c,d);k(function(){for(var a=0;a<f.length;a+=2)if(f[a]==c&&f[a+1]==d){f.splice(a,a+2);break}},2500,!1)}var m,f,g;return function(b,c,g){function a(){n=!1;c.removeClass("ng-click-active")}var k=h(g.ngClick),n=!1,r,s,v,w;c.on("touchstart",function(a){n=!0;r=a.target?a.target:a.srcElement;3==r.nodeType&&(r=r.parentNode);c.addClass("ng-click-active");s=Date.now();
a=a.touches&&a.touches.length?a.touches:[a];a=a[0].originalEvent||a[0];v=a.clientX;w=a.clientY});c.on("touchmove",function(c){a()});c.on("touchcancel",function(c){a()});c.on("touchend",function(b){var k=Date.now()-s,h=b.changedTouches&&b.changedTouches.length?b.changedTouches:b.touches&&b.touches.length?b.touches:[b],t=h[0].originalEvent||h[0],h=t.clientX,t=t.clientY,x=Math.sqrt(Math.pow(h-v,2)+Math.pow(t-w,2));n&&750>k&&12>x&&(f||(p[0].addEventListener("click",e,!0),p[0].addEventListener("touchstart",
l,!0),f=[]),m=Date.now(),d(f,h,t),r&&r.blur(),u.isDefined(g.disabled)&&!1!==g.disabled||c.triggerHandler("click",[b]));a()});c.onclick=function(a){};c.on("click",function(a,c){b.$apply(function(){k(b,{$event:c||a})})});c.on("mousedown",function(a){c.addClass("ng-click-active")});c.on("mousemove mouseup",function(a){c.removeClass("ng-click-active")})}}]);s("ngSwipeLeft",-1,"swipeleft");s("ngSwipeRight",1,"swiperight")})(window,window.angular);
;
