<commit_before>//get Master firefox version
function getFirefoxMasterVersion(userAgent) {
    var version = 0;
    var ua = userAgent || navigator.userAgent;

    var matches = /Firefox\/([0-9]+).[0-9]+(?:.[0-9]+)?/.exec(
        ua
    );

    if (matches !== null && matches.length > 0) {
        version = parseInt(matches[1], 10);
    }

    return version;
}

function isFirefox(userAgent) {
    var ua = userAgent || navigator.userAgent;
    // camino UA string contains 'like Firefox'
    return (
        (/\sFirefox/).test(ua) &&
        !(/like Firefox/i).test(ua) &&
        !(/SeaMonkey/i).test(ua)
    );
}

function isAustralis() {
    // Check if the visitor is using Firefox and it's v29+
    if (isFirefox()) {
        var fx_version = getFirefoxMasterVersion();
        var minimumAustralisVersion = 29;
        return (fx_version >= minimumAustralisVersion);
    } else {
        return false;
    }
}

var _currentDataTimestamp = 0;

// TODO: make this better and less hacky
// should not be in global scope, nor should
// most of this file.
window.setInterval(function(){
    // bump forward 1 minute
    if (_currentDataTimestamp) {
        // only move forward if it's been set
        _currentDataTimestamp += 60;
    }
}, 60000);  // 60s

function getDevTimestamp() {
    // TODO REMOVE ME
    // confirmed manually that this is equal to
    // smithers.utils.get_epoch_minute()
    var unixtime = (new Date()).getTime() / 1000  // seconds since epoch
    return Math.floor(unixtime / 60) * 60  // round down to minute
}

function getJsonDataUrl() {
    var $body = $('body');
    var staticDataUrl = $body.data('staticDataUrl');

    if (!_currentDataTimestamp) {
        // NOTE: will be 0 when redis is off or returns nothing
        var latestTimestamp = $body.data('timestamp'); // an int

        if (!latestTimestamp) {
            // TODO REMOVE ME
            // guess at the latest timestamp (for dev)
            console.log('USING DEV TIMESTAMP!');
            // take off 3 extra minutes for fewer 404s
            latestTimestamp = getDevTimestamp() - 180;
        }

        // two minutes ago
        _currentDataTimestamp = latestTimestamp - 120;
    }
    console.log('Current timestamp', _currentDataTimestamp);
    var url = staticDataUrl + 'stats_' + _currentDataTimestamp + '.json';
    console.log(url);
    return url;
}

var $stats_panel_tab_title = $('.stats-panel-tab .title');
var stats_panel_opened_title = $stats_panel_tab_title.data('open-title');
var stats_panel_closed_title = $stats_panel_tab_title.text();

function openStatsPanel() {
    // hide glows on stats panel open
    if (showing_glows) {
        hideGlows();
    } else {
        showGlows();
    }

    showing_glows = !showing_glows;

    // update tab title
    if ($('body').hasClass('stats-panel-open')) {
        $stats_panel_tab_title.text(stats_panel_opened_title);
    } else {
        $stats_panel_tab_title.text(stats_panel_closed_title);
    }
}

$(document).ready(function () {

    var hasMediaQueries = ('matchMedia' in window);
    var mode = 'mobile';

    function checkMode() {
        var current_mode = getMode();
        if (mode !== current_mode) {
            mode = current_mode;
            setMode(mode);
        }
    }

    function getMode() {
        if (hasMediaQueries && matchMedia('(min-width: 768px)').matches) {
            return 'desktop';
        }
        return 'mobile';
    }

    function setMode(mode) {
        console.log('setting mode to ', mode);
    }

    if (hasMediaQueries) {
        checkMode();
        $(window).on('resize', function () {
            checkMode();
        });
    }

    var $choice_modal = $('.choice-modal');
    var $choices = $('.choices .btn');
    var events = 'transitionend';

    var events = (function() {
        var el = document.createElement('div');
        var transitions = {
            'transition': 'transitionend',
            'OTransition': 'oTransitionEnd',
            'MSTransition': 'msTransitionEnd',
            'MozTransition': 'transitionend',
            'WebkitTransition': 'webkitTransitionEnd'
        }

        for (var selector in transitions){
            if (el.style[selector] !== undefined) {
                return transitions[selector];
            }
        }

        return null;
    })();

    $('.choice-footer-container').on(
        events,
        function (event) {
            if (event.target === event.currentTarget) {
                var state = $(this).data('state');
                if (state === 'opening-height') {
                    $(this).data('state', '');
                    $('.choice-footnotes').css('display', 'block');
                    $('.choice-footer-content, .choice-footnotes')
                        .data('state', 'opening-opacity')
                        .css('opacity', 1);
                }
            }
        }
    );

    $('.choice-footnotes').on(
        events,
        function (event) {
            if (event.target === event.currentTarget) {
                var state = $(this).data('state');
                if (state === 'closing-opacity') {
                    $(this).data('state', '').css('display', 'none');
                }
            }
        }
    );

    $('.choice-footer-content').on(
        events,
        function (event) {
            if (event.target === event.currentTarget) {
                var state = $(this).data('state');
                if (state === 'closing-opacity') {
                    $('.choice-footer-container')
                        .data('state', 'closing-height')
                        .css('height', 0);
                }
            }
        }
    );

    $choice_modal.find('.choice-body-container').on(
        events,
        function (event) {
            var $body = $(this);
            if (event.target === event.currentTarget) {
                var state = $body.data('state');
                if (state === 'opening-opacity-out') {
                    $('.choices').removeClass('in-progress');
                    $choices.each(function(i) {
                        $(this).removeClass('selected');
                    });

                    var from_height = $body.height();

                    // We need to ignore this transition for Safari. Otherwise
                    // it will animate from height 0 to from_height.
                    var transition = $body.css('transition');
                    $body
                        .css('transition', 'none')
                        .css('height', from_height);

                    $choice_modal.addClass('choice-modal-interstitial');

                    var to_height = $body.find('.modal-body').outerHeight();

                    // Hack for Safari 7. If this is not added, the CSS
                    // transitions on the $body do not run.
                    $choice_modal.find('.modal-dialog').css('transform', 'translate(0, 1px)');

                    // Yield to allow the browser to draw at from_height
                    setTimeout(function() {
                        // Re-enable transitions. Yield to allow the browser
                        // to register the transitions.
                        $body.css('transition', transition);
                        setTimeout(function() {
                            $body
                                .data('state', 'opening-height')
                                .css('height', to_height);

                            // Hack for Safari 7. If this is not added, the CSS
                            // transitions on the $body do not run.
                            $choice_modal.find('.modal-dialog').css('transform', 'translate(0, 0)');
                        }, 0);
                    }, 0);
                } else if (state === 'opening-height') {
                    $body.data('state', 'opening-opacity-in').css('opacity', 1);
                } else if (state === 'opening-opacity-in') {
                    $body.data('state', '');
                }
            }
        }
    );

    function showShareButtons() {
        var height = $('.choice-footer-container .modal-footer').outerHeight();
        $('.choice-footer-container').data('state', 'opening-height').height(height);
    }

    function hideShareButtons() {
        $('.choice-footnotes, .choice-footer-content')
            .data('state', 'closing-opacity')
            .css('opacity', 0);
    }

    function openInterstitialModal(choice) {
        hideShareButtons();

        $choice_modal.find('.choice-body-container')
            .data('state', 'opening-opacity-out')
            .css('opacity', 0);

        $choices.each(function(i) {
            $choice_modal.removeClass('interstitial-modal-' + $(this).data('choice'));
        });

        if (choice) {
            $choice_modal.addClass('interstitial-modal-' + choice);
        }
    }

    function handleChoiceModalOpen() {
        var $choice_modal = $(this);

        // remove any selection
        $choices.each(function(i) {
            $choice_modal.removeClass('interstitial-modal-' + $(this).data('choice'));
        });

        // make sure we're on the first page
        $choice_modal.removeClass('choice-modal-interstitial')
        $choice_modal.find('.choice-body-container').css('height', 'auto');

        // center it vertically
        $choice_modal.css('display', 'block');
        var $dialog = $choice_modal.find('.modal-dialog');

        setTimeout(function() {
            var offset = Math.max(
                // 150 pixels to approximately account for share buttons
                ($(window).height() - $dialog.height() - 150) / 2,
                20
            );
            $dialog.css('margin-top', offset);
        }, 20);
    }

    $choice_modal.on('show.bs.modal', handleChoiceModalOpen);

    var hash = window.location.hash;

    if (isAustralis()) {
        // if the browser is Australis, add a class to HTML tag
        // and show the primary choice modal
        var $html = $(document.documentElement);
        $('html').addClass('australis');

        // if we're on australis and there's no hash tag, show the choice modal
        if (hash.indexOf("#") === -1) {
            $choice_modal.modal();
        }
    } else {
        $('html').addClass('non-australis');
    }

    if (hash.indexOf("choice") != -1) {
        // if #choice is in the URL, show the choice modal
        $choice_modal.modal();
    } else if (hash.indexOf("video") != -1) {
        // if #video is in the URL, show the video modal
        $( '#video-modal' ).modal();
        insertVideo();
    } else if (hash.indexOf("number") != -1) {
        // if #number is in the URL, show the number modal
        $( '#number-modal' ).modal();
    } else if (hash.indexOf("stats") != -1) {
        // if #number is in the URL, show the number modal
        $( 'body' ).addClass('stats-panel-open');
        openStatsPanel();
    }

    $( '.stats-panel-tab' ).click(function() {
        $( 'body' ).toggleClass( "stats-panel-open" );
        openStatsPanel();
    });

    // turn on fading for choice modal after initial load so it fades
    // on subsequent open/closes, but not the first time
    $choice_modal.addClass('fade');

    // "Share the map" popopver
    $('.popover-markup > .trigger').popover({
        html : true,
        title: function() {
          return $(this).parent().find('.head').html();
        },
        content: function() {
          return $(this).parent().find('.content').html();
        },
        container: 'body'
    });

    // Close popover on click outside of popover
    $('body').on('click', function (e) {
        $('[data-toggle="popover"]').each(function () {
            //the 'is' for buttons that trigger popups
            //the 'has' for icons within a button that triggers a popup
            if (!$(this).is(e.target) &&
                $(this).has(e.target).length === 0 &&
                $('.popover').has(e.target).length === 0) {
                $(this).popover('hide');
            }
        });
    });

    $choices.click(function() {
        $choices.removeClass('selected');
        $(this).addClass('selected');
        $('.choices').addClass('in-progress');
        showShareButtons();
    });

    function openShareWindow(href) {
        $('.popover-markup  .trigger').popover('hide');
        window.open(href, '_blank', "height=420,width=550");
    }

    function shareChoice(choice) {
        var url = $choice_modal.data('share-url');
        if (url) {
            $.post(url, { 'issue': choice });
        }
    }

    // Open .share-window links in a new window, and close any popovers
    $(document).on('click', '.share-window', function(event) {
        event.preventDefault();
        openShareWindow(this.href);
    });

    $('.modal-footer .share-twitter').click(function(e) {
        var $selected = $('.choices .selected');
        if ($selected.length) {
            openShareWindow($selected.data('twitter'));
            openInterstitialModal($selected.data('choice'));
            shareChoice($selected.data('choice'));
        }
    });

    $('.modal-footer .share-facebook').click(function(e) {
        var $selected = $('.choices .selected');
        if ($selected.length) {
            openShareWindow($selected.data('facebook'));
            openInterstitialModal($selected.data('choice'));
            shareChoice($selected.data('choice'));
        }
    });

    $('.choice-footnotes .share-local').click(function(e) {
        var $selected = $('.choices .selected');
        if ($selected.length) {
            openInterstitialModal($selected.data('choice'));
            shareChoice($selected.data('choice'));
        }
    });

    // Insert YouTube video into #video modal
    function insertVideo(autoplay) {
        if (autoplay) {
            autoplay = '1';
        } else {
            autoplay = '0';
        }
        var width = 853;
        var height = 480;
        var id = 'WB98kYqQt9c';
        $('#video-modal .modal-body').html('<iframe width="' + width + '" height="' +
            height + '" src="//www.youtube-nocookie.com/embed/' +
            id + '?autoplay=' + autoplay + '&' +
            '" frameborder="0" allowfullscreen></iframe>')
    }

    $('#video-modal').on('show.bs.modal', function (e) {
        // Insert YouTube player when video modal is opened
        insertVideo(true);
    });

    $('#video-modal').on('hidden.bs.modal', function (e) {
        // Stop YouTube player when video modal is closed
        $('#video-modal .modal-body').html('');
    });

});
<commit_msg>Move choice buttons to/from mobile layout.<commit_after>//get Master firefox version
function getFirefoxMasterVersion(userAgent) {
    var version = 0;
    var ua = userAgent || navigator.userAgent;

    var matches = /Firefox\/([0-9]+).[0-9]+(?:.[0-9]+)?/.exec(
        ua
    );

    if (matches !== null && matches.length > 0) {
        version = parseInt(matches[1], 10);
    }

    return version;
}

function isFirefox(userAgent) {
    var ua = userAgent || navigator.userAgent;
    // camino UA string contains 'like Firefox'
    return (
        (/\sFirefox/).test(ua) &&
        !(/like Firefox/i).test(ua) &&
        !(/SeaMonkey/i).test(ua)
    );
}

function isAustralis() {
    // Check if the visitor is using Firefox and it's v29+
    if (isFirefox()) {
        var fx_version = getFirefoxMasterVersion();
        var minimumAustralisVersion = 29;
        return (fx_version >= minimumAustralisVersion);
    } else {
        return false;
    }
}

var _currentDataTimestamp = 0;

// TODO: make this better and less hacky
// should not be in global scope, nor should
// most of this file.
window.setInterval(function(){
    // bump forward 1 minute
    if (_currentDataTimestamp) {
        // only move forward if it's been set
        _currentDataTimestamp += 60;
    }
}, 60000);  // 60s

function getDevTimestamp() {
    // TODO REMOVE ME
    // confirmed manually that this is equal to
    // smithers.utils.get_epoch_minute()
    var unixtime = (new Date()).getTime() / 1000  // seconds since epoch
    return Math.floor(unixtime / 60) * 60  // round down to minute
}

function getJsonDataUrl() {
    var $body = $('body');
    var staticDataUrl = $body.data('staticDataUrl');

    if (!_currentDataTimestamp) {
        // NOTE: will be 0 when redis is off or returns nothing
        var latestTimestamp = $body.data('timestamp'); // an int

        if (!latestTimestamp) {
            // TODO REMOVE ME
            // guess at the latest timestamp (for dev)
            console.log('USING DEV TIMESTAMP!');
            // take off 3 extra minutes for fewer 404s
            latestTimestamp = getDevTimestamp() - 180;
        }

        // two minutes ago
        _currentDataTimestamp = latestTimestamp - 120;
    }
    console.log('Current timestamp', _currentDataTimestamp);
    var url = staticDataUrl + 'stats_' + _currentDataTimestamp + '.json';
    console.log(url);
    return url;
}

var $stats_panel_tab_title = $('.stats-panel-tab .title');
var stats_panel_opened_title = $stats_panel_tab_title.data('open-title');
var stats_panel_closed_title = $stats_panel_tab_title.text();

function openStatsPanel() {
    // hide glows on stats panel open
    if (showing_glows) {
        hideGlows();
    } else {
        showGlows();
    }

    showing_glows = !showing_glows;

    // update tab title
    if ($('body').hasClass('stats-panel-open')) {
        $stats_panel_tab_title.text(stats_panel_opened_title);
    } else {
        $stats_panel_tab_title.text(stats_panel_closed_title);
    }
}

$(document).ready(function () {

    var hasMediaQueries = ('matchMedia' in window);
    var mode = 'mobile';

    function checkMode() {
        var current_mode = getMode();
        if (mode !== current_mode) {
            mode = current_mode;
            setMode(mode);
        }
    }

    function getMode() {
        if (hasMediaQueries && matchMedia('(min-width: 768px)').matches) {
            return 'desktop';
        }
        return 'mobile';
    }

    function setMode(mode) {
        console.log('setting mode to ', mode);
        if (mode === 'desktop') {
            $('.choices-module')
                .appendTo($('#choice-modal-choice-page'))
                .removeClass('visible-xs');
        } else {
            $('.choices-module')
                .prependTo($('.wrapper'))
                .addClass('visible-xs');
        }
    }

    if (hasMediaQueries) {
        checkMode();
        $(window).on('resize', function () {
            checkMode();
        });
    }

    var $choice_modal = $('.choice-modal');
    var $choices = $('.choices .btn');
    var events = 'transitionend';

    var events = (function() {
        var el = document.createElement('div');
        var transitions = {
            'transition': 'transitionend',
            'OTransition': 'oTransitionEnd',
            'MSTransition': 'msTransitionEnd',
            'MozTransition': 'transitionend',
            'WebkitTransition': 'webkitTransitionEnd'
        }

        for (var selector in transitions){
            if (el.style[selector] !== undefined) {
                return transitions[selector];
            }
        }

        return null;
    })();

    $('.choice-footer-container').on(
        events,
        function (event) {
            if (event.target === event.currentTarget) {
                var state = $(this).data('state');
                if (state === 'opening-height') {
                    $(this).data('state', '');
                    $('.choice-footnotes').css('display', 'block');
                    $('.choice-footer-content, .choice-footnotes')
                        .data('state', 'opening-opacity')
                        .css('opacity', 1);
                }
            }
        }
    );

    $('.choice-footnotes').on(
        events,
        function (event) {
            if (event.target === event.currentTarget) {
                var state = $(this).data('state');
                if (state === 'closing-opacity') {
                    $(this).data('state', '').css('display', 'none');
                }
            }
        }
    );

    $('.choice-footer-content').on(
        events,
        function (event) {
            if (event.target === event.currentTarget) {
                var state = $(this).data('state');
                if (state === 'closing-opacity') {
                    $('.choice-footer-container')
                        .data('state', 'closing-height')
                        .css('height', 0);
                }
            }
        }
    );

    $choice_modal.find('.choice-body-container').on(
        events,
        function (event) {
            var $body = $(this);
            if (event.target === event.currentTarget) {
                var state = $body.data('state');
                if (state === 'opening-opacity-out') {
                    $('.choices').removeClass('in-progress');
                    $choices.each(function(i) {
                        $(this).removeClass('selected');
                    });

                    var from_height = $body.height();

                    // We need to ignore this transition for Safari. Otherwise
                    // it will animate from height 0 to from_height.
                    var transition = $body.css('transition');
                    $body
                        .css('transition', 'none')
                        .css('height', from_height);

                    $choice_modal.addClass('choice-modal-interstitial');

                    var to_height = $body.find('.modal-body').outerHeight();

                    // Hack for Safari 7. If this is not added, the CSS
                    // transitions on the $body do not run.
                    $choice_modal.find('.modal-dialog').css('transform', 'translate(0, 1px)');

                    // Yield to allow the browser to draw at from_height
                    setTimeout(function() {
                        // Re-enable transitions. Yield to allow the browser
                        // to register the transitions.
                        $body.css('transition', transition);
                        setTimeout(function() {
                            $body
                                .data('state', 'opening-height')
                                .css('height', to_height);

                            // Hack for Safari 7. If this is not added, the CSS
                            // transitions on the $body do not run.
                            $choice_modal.find('.modal-dialog').css('transform', 'translate(0, 0)');
                        }, 0);
                    }, 0);
                } else if (state === 'opening-height') {
                    $body.data('state', 'opening-opacity-in').css('opacity', 1);
                } else if (state === 'opening-opacity-in') {
                    $body.data('state', '');
                }
            }
        }
    );

    function showShareButtons() {
        var height = $('.choice-footer-container .modal-footer').outerHeight();
        $('.choice-footer-container').data('state', 'opening-height').height(height);
    }

    function hideShareButtons() {
        $('.choice-footnotes, .choice-footer-content')
            .data('state', 'closing-opacity')
            .css('opacity', 0);
    }

    function openInterstitialModal(choice) {
        hideShareButtons();

        $choice_modal.find('.choice-body-container')
            .data('state', 'opening-opacity-out')
            .css('opacity', 0);

        $choices.each(function(i) {
            $choice_modal.removeClass('interstitial-modal-' + $(this).data('choice'));
        });

        if (choice) {
            $choice_modal.addClass('interstitial-modal-' + choice);
        }
    }

    function handleChoiceModalOpen() {
        var $choice_modal = $(this);

        // remove any selection
        $choices.each(function(i) {
            $choice_modal.removeClass('interstitial-modal-' + $(this).data('choice'));
        });

        // make sure we're on the first page
        $choice_modal.removeClass('choice-modal-interstitial')
        $choice_modal.find('.choice-body-container').css('height', 'auto');

        // center it vertically
        $choice_modal.css('display', 'block');
        var $dialog = $choice_modal.find('.modal-dialog');

        setTimeout(function() {
            var offset = Math.max(
                // 150 pixels to approximately account for share buttons
                ($(window).height() - $dialog.height() - 150) / 2,
                20
            );
            $dialog.css('margin-top', offset);
        }, 20);
    }

    $choice_modal.on('show.bs.modal', handleChoiceModalOpen);

    var hash = window.location.hash;

    if (isAustralis()) {
        // if the browser is Australis, add a class to HTML tag
        // and show the primary choice modal
        var $html = $(document.documentElement);
        $('html').addClass('australis');

        // if we're on australis and there's no hash tag, show the choice modal
        if (hash.indexOf("#") === -1) {
            $choice_modal.modal();
        }
    } else {
        $('html').addClass('non-australis');
    }

    if (hash.indexOf("choice") != -1) {
        // if #choice is in the URL, show the choice modal
        $choice_modal.modal();
    } else if (hash.indexOf("video") != -1) {
        // if #video is in the URL, show the video modal
        $( '#video-modal' ).modal();
        insertVideo();
    } else if (hash.indexOf("number") != -1) {
        // if #number is in the URL, show the number modal
        $( '#number-modal' ).modal();
    } else if (hash.indexOf("stats") != -1) {
        // if #number is in the URL, show the number modal
        $( 'body' ).addClass('stats-panel-open');
        openStatsPanel();
    }

    $( '.stats-panel-tab' ).click(function() {
        $( 'body' ).toggleClass( "stats-panel-open" );
        openStatsPanel();
    });

    // turn on fading for choice modal after initial load so it fades
    // on subsequent open/closes, but not the first time
    $choice_modal.addClass('fade');

    // "Share the map" popopver
    $('.popover-markup > .trigger').popover({
        html : true,
        title: function() {
          return $(this).parent().find('.head').html();
        },
        content: function() {
          return $(this).parent().find('.content').html();
        },
        container: 'body'
    });

    // Close popover on click outside of popover
    $('body').on('click', function (e) {
        $('[data-toggle="popover"]').each(function () {
            //the 'is' for buttons that trigger popups
            //the 'has' for icons within a button that triggers a popup
            if (!$(this).is(e.target) &&
                $(this).has(e.target).length === 0 &&
                $('.popover').has(e.target).length === 0) {
                $(this).popover('hide');
            }
        });
    });

    $choices.click(function() {
        $choices.removeClass('selected');
        $(this).addClass('selected');
        $('.choices').addClass('in-progress');
        showShareButtons();
    });

    function openShareWindow(href) {
        $('.popover-markup  .trigger').popover('hide');
        window.open(href, '_blank', "height=420,width=550");
    }

    function shareChoice(choice) {
        var url = $choice_modal.data('share-url');
        if (url) {
            $.post(url, { 'issue': choice });
        }
    }

    // Open .share-window links in a new window, and close any popovers
    $(document).on('click', '.share-window', function(event) {
        event.preventDefault();
        openShareWindow(this.href);
    });

    $('.modal-footer .share-twitter').click(function(e) {
        var $selected = $('.choices .selected');
        if ($selected.length) {
            openShareWindow($selected.data('twitter'));
            openInterstitialModal($selected.data('choice'));
            shareChoice($selected.data('choice'));
        }
    });

    $('.modal-footer .share-facebook').click(function(e) {
        var $selected = $('.choices .selected');
        if ($selected.length) {
            openShareWindow($selected.data('facebook'));
            openInterstitialModal($selected.data('choice'));
            shareChoice($selected.data('choice'));
        }
    });

    $('.choice-footnotes .share-local').click(function(e) {
        var $selected = $('.choices .selected');
        if ($selected.length) {
            openInterstitialModal($selected.data('choice'));
            shareChoice($selected.data('choice'));
        }
    });

    // Insert YouTube video into #video modal
    function insertVideo(autoplay) {
        if (autoplay) {
            autoplay = '1';
        } else {
            autoplay = '0';
        }
        var width = 853;
        var height = 480;
        var id = 'WB98kYqQt9c';
        $('#video-modal .modal-body').html('<iframe width="' + width + '" height="' +
            height + '" src="//www.youtube-nocookie.com/embed/' +
            id + '?autoplay=' + autoplay + '&' +
            '" frameborder="0" allowfullscreen></iframe>')
    }

    $('#video-modal').on('show.bs.modal', function (e) {
        // Insert YouTube player when video modal is opened
        insertVideo(true);
    });

    $('#video-modal').on('hidden.bs.modal', function (e) {
        // Stop YouTube player when video modal is closed
        $('#video-modal .modal-body').html('');
    });

});
<|endoftext|>


<commit_before>/**
 * @file ScrollableTable component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component, createRef} from 'react';
import PropTypes from 'prop-types';

// Statics
import TableFragment from '../_statics/TableFragment';

// Vendors
import isEmpty from 'lodash/isEmpty';
import Util from '../_vendors/Util';

class ScrollableTable extends Component {

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.wrapper = createRef();

        this.state = {
            wrapperEl: null
        };

    }

    componentDidMount() {
        this.setState({
            wrapperEl: this.wrapper && this.wrapper.current
        });
    }

    getChildren = () => {

        const {children} = this.props,
            {wrapperEl} = this.state;

        return (typeof children === 'function' ? children(wrapperEl) : children) || null;

    };

    render() {

        const {

                scroll, useDynamicRender,

                // not passing down these props
                children: c, fragment, scrollHeight, rowHeight, scrollBuffer,

                ...restProps

            } = this.props,
            children = this.getChildren();

        return useDynamicRender || !isEmpty(scroll) ?
            <div {...restProps}
                 ref={this.wrapper}>
                {children}
            </div>
            :
            children;

    }
}

ScrollableTable.propTypes = {

    children: PropTypes.any,

    className: PropTypes.string,
    style: PropTypes.object,

    /**
     * scroll
     */
    scroll: PropTypes.shape({
        width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
        height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
        maxHeight: PropTypes.oneOfType([PropTypes.number, PropTypes.string])
    }),

    fragment: PropTypes.oneOf(Util.enumerateValue(TableFragment)),

    /**
     * Dynamic Render
     */
    useDynamicRender: PropTypes.bool,
    scrollHeight: PropTypes.number,
    rowHeight: PropTypes.number,
    scrollBuffer: PropTypes.number

};

ScrollableTable.defaultProps = {

    /**
     * Dynamic Render
     */
    useDynamicRender: false,
    scrollHeight: 500,
    rowHeight: 50,
    scrollBuffer: 8

};

export default ScrollableTable;
<commit_msg>update ScrollableTable<commit_after>/**
 * @file ScrollableTable component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component, createRef} from 'react';
import PropTypes from 'prop-types';

// Statics
import TableFragment from '../_statics/TableFragment';

// Vendors
import isEmpty from 'lodash/isEmpty';
import Util from '../_vendors/Util';

class ScrollableTable extends Component {

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.wrapper = createRef();

        this.state = {
            wrapperEl: null
        };

    }

    componentDidMount() {
        this.setState({
            wrapperEl: this.wrapper && this.wrapper.current
        });
    }

    getChildren = () => {

        const {children} = this.props,
            {wrapperEl} = this.state;

        return (typeof children === 'function' ? children(wrapperEl) : children) || null;

    };

    render() {

        const {

                scroll, useDynamicRender,

                // not passing down these props
                children: c, fragment, scrollHeight, rowHeight, scrollBuffer,

                ...restProps

            } = this.props,
            children = this.getChildren();

        return useDynamicRender || !isEmpty(scroll) ?
            <div {...restProps}
                 ref={this.wrapper}>
                {children}
            </div>
            :
            children;

    }
}

ScrollableTable.propTypes = {

    children: PropTypes.any,

    className: PropTypes.string,
    style: PropTypes.object,

    /**
     * scroll
     */
    scroll: PropTypes.shape({
        width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
        height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
        maxHeight: PropTypes.oneOfType([PropTypes.number, PropTypes.string])
    }),

    fragment: PropTypes.oneOf(Util.enumerateValue(TableFragment)),

    /**
     * Dynamic Render
     */
    useDynamicRender: PropTypes.bool,
    scrollHeight: PropTypes.number,
    rowHeight: PropTypes.number,
    scrollBuffer: PropTypes.number,

    onScroll: PropTypes.func

};

ScrollableTable.defaultProps = {

    /**
     * Dynamic Render
     */
    useDynamicRender: false,
    scrollHeight: 500,
    rowHeight: 50,
    scrollBuffer: 8

};

export default ScrollableTable;
<|endoftext|>


<commit_before>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

var gulp = require('gulp');
var filter = require('gulp-filter');
var es = require('event-stream');
var path = require('path');

var all = [
	'*',
	'build/**/*',
	'extensions/**/*',
	'scripts/**/*',
	'src/**/*',
	'test/**/*'
];

var eolFilter = [
	'**',
	'!ThirdPartyNotices.txt',
	'!LICENSE.txt',
	'!extensions/**/out/**',
	'!**/node_modules/**',
	'!**/fixtures/**',
	'!**/*.{svg,exe,png,scpt,bat,cur,ttf,woff,eot}',
];

var indentationFilter = [
	'**',
	'!ThirdPartyNotices.txt',
	'!**/*.md',
	'!**/*.yml',
	'!**/lib/**',
	'!**/*.d.ts',
	'!extensions/typescript/server/**',
	'!test/assert.js',
	'!**/package.json',
	'!**/npm-shrinkwrap.json',
	'!**/octicons/**',
	'!**/vs/languages/sass/test/common/example.scss',
	'!**/vs/languages/less/common/parser/less.grammar.txt',
	'!**/vs/languages/css/common/buildscripts/css-schema.xml',
	'!**/vs/languages/markdown/common/raw.marked.js',
	'!**/vs/base/common/winjs.base.raw.js',
	'!**/vs/base/node/terminateProcess.sh',
	'!**/vs/base/node/terminateProcess.sh',
	'!**/vs/text.js',
	'!**/vs/nls.js',
	'!**/vs/css.js',
	'!**/vs/loader.js',
	'!extensions/**/snippets/**',
	'!extensions/**/syntaxes/**',
	'!extensions/**/themes/**',
];

var copyrightFilterList = [
	'**',
	'!**/*.json',
	'!**/*.html',
	'!**/test/**',
	'!**/*.md',
	'!**/*.sh',
	'!**/*.txt',
	'!src/vs/editor/standalone-languages/swift.ts',
];

var copyrightHeader = [
	'/*---------------------------------------------------------------------------------------------',
	' *  Copyright (c) Microsoft Corporation. All rights reserved.',
	' *  Licensed under the MIT License. See License.txt in the project root for license information.',
	' *--------------------------------------------------------------------------------------------*/'
].join('\n');

var hygiene = exports.hygiene = function (some) {
	var errorCount = 0;

	var eol = es.through(function (file) {
		if (/\r\n?/g.test(file.contents.toString('utf8'))) {
			console.error(file.relative + ': Bad EOL found');
			errorCount++;
		}

		this.emit('data', file);
	});

	var indentation = es.through(function (file) {
		file.contents
			.toString('utf8')
			.split(/\r\n|\r|\n/)
			.forEach(function(line, i) {
				if (/^\s*$/.test(line)) {
					// empty or whitespace lines are OK
				} else if (/^[\t]*[^\s]/.test(line)) {
					// good indent
				} else if (/^[\t]* \*/.test(line)) {
					// block comment using an extra space
				} else {
					console.error(file.relative + '(' + (i + 1) + ',1): Bad whitespace indentation');
					errorCount++;
				}
			});

		this.emit('data', file);
	});

	var copyrights = es.through(function (file) {
		if (file.contents.toString('utf8').indexOf(copyrightHeader) !== 0) {
			console.error(file.relative + ': Missing or bad copyright statement');
			errorCount++;
		}

		this.emit('data', file);
	});

	return gulp.src(some || all, { base: '.' })
		.pipe(filter(function (f) { return !f.stat.isDirectory(); }))
		.pipe(filter(eolFilter))
		.pipe(eol)
		.pipe(filter(indentationFilter))
		.pipe(indentation)
		.pipe(filter(copyrightFilterList))
		.pipe(copyrights)
		.pipe(es.through(null, function () {
			if (errorCount > 0) {
				this.emit('error', 'Hygiene failed with ' + errorCount + ' errors. Check \'build/gulpfile.hygiene.js\'.');
			} else {
				this.emit('end');
			}
		}));
};

gulp.task('hygiene', function () {
	return hygiene();
});

// this allows us to run this as a git pre-commit hook
if (require.main === module) {
	var cp = require('child_process');
	cp.exec('git diff --cached --name-only', function (err, out) {
		if (err) {
			console.error();
			console.error(err);
			process.exit(1);
		}

		var some = out
			.split(/\r?\n/)
			.filter(function (l) { return !!l; });

		hygiene(some).on('error', function (err) {
			console.error();
			console.error(err);
			process.exit(1);
		});
	});
}
<commit_msg>update hygiene script to ignore cmd and bat<commit_after>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

var gulp = require('gulp');
var filter = require('gulp-filter');
var es = require('event-stream');
var path = require('path');

var all = [
	'*',
	'build/**/*',
	'extensions/**/*',
	'scripts/**/*',
	'src/**/*',
	'test/**/*'
];

var eolFilter = [
	'**',
	'!ThirdPartyNotices.txt',
	'!LICENSE.txt',
	'!extensions/**/out/**',
	'!**/node_modules/**',
	'!**/fixtures/**',
	'!**/*.{svg,exe,png,scpt,bat,cmd,cur,ttf,woff,eot}',
];

var indentationFilter = [
	'**',
	'!ThirdPartyNotices.txt',
	'!**/*.md',
	'!**/*.yml',
	'!**/lib/**',
	'!**/*.d.ts',
	'!extensions/typescript/server/**',
	'!test/assert.js',
	'!**/package.json',
	'!**/npm-shrinkwrap.json',
	'!**/octicons/**',
	'!**/vs/languages/sass/test/common/example.scss',
	'!**/vs/languages/less/common/parser/less.grammar.txt',
	'!**/vs/languages/css/common/buildscripts/css-schema.xml',
	'!**/vs/languages/markdown/common/raw.marked.js',
	'!**/vs/base/common/winjs.base.raw.js',
	'!**/vs/base/node/terminateProcess.sh',
	'!**/vs/base/node/terminateProcess.sh',
	'!**/vs/text.js',
	'!**/vs/nls.js',
	'!**/vs/css.js',
	'!**/vs/loader.js',
	'!extensions/**/snippets/**',
	'!extensions/**/syntaxes/**',
	'!extensions/**/themes/**',
];

var copyrightFilterList = [
	'**',
	'!**/*.json',
	'!**/*.html',
	'!**/test/**',
	'!**/*.md',
	'!**/*.bat',
	'!**/*.cmd',
	'!**/*.sh',
	'!**/*.txt',
	'!src/vs/editor/standalone-languages/swift.ts',
];

var copyrightHeader = [
	'/*---------------------------------------------------------------------------------------------',
	' *  Copyright (c) Microsoft Corporation. All rights reserved.',
	' *  Licensed under the MIT License. See License.txt in the project root for license information.',
	' *--------------------------------------------------------------------------------------------*/'
].join('\n');

var hygiene = exports.hygiene = function (some) {
	var errorCount = 0;

	var eol = es.through(function (file) {
		if (/\r\n?/g.test(file.contents.toString('utf8'))) {
			console.error(file.relative + ': Bad EOL found');
			errorCount++;
		}

		this.emit('data', file);
	});

	var indentation = es.through(function (file) {
		file.contents
			.toString('utf8')
			.split(/\r\n|\r|\n/)
			.forEach(function(line, i) {
				if (/^\s*$/.test(line)) {
					// empty or whitespace lines are OK
				} else if (/^[\t]*[^\s]/.test(line)) {
					// good indent
				} else if (/^[\t]* \*/.test(line)) {
					// block comment using an extra space
				} else {
					console.error(file.relative + '(' + (i + 1) + ',1): Bad whitespace indentation');
					errorCount++;
				}
			});

		this.emit('data', file);
	});

	var copyrights = es.through(function (file) {
		if (file.contents.toString('utf8').indexOf(copyrightHeader) !== 0) {
			console.error(file.relative + ': Missing or bad copyright statement');
			errorCount++;
		}

		this.emit('data', file);
	});

	return gulp.src(some || all, { base: '.' })
		.pipe(filter(function (f) { return !f.stat.isDirectory(); }))
		.pipe(filter(eolFilter))
		.pipe(eol)
		.pipe(filter(indentationFilter))
		.pipe(indentation)
		.pipe(filter(copyrightFilterList))
		.pipe(copyrights)
		.pipe(es.through(null, function () {
			if (errorCount > 0) {
				this.emit('error', 'Hygiene failed with ' + errorCount + ' errors. Check \'build/gulpfile.hygiene.js\'.');
			} else {
				this.emit('end');
			}
		}));
};

gulp.task('hygiene', function () {
	return hygiene();
});

// this allows us to run this as a git pre-commit hook
if (require.main === module) {
	var cp = require('child_process');
	cp.exec('git diff --cached --name-only', function (err, out) {
		if (err) {
			console.error();
			console.error(err);
			process.exit(1);
		}

		var some = out
			.split(/\r?\n/)
			.filter(function (l) { return !!l; });

		hygiene(some).on('error', function (err) {
			console.error();
			console.error(err);
			process.exit(1);
		});
	});
}
<|endoftext|>


<commit_before>var command = {
  command: 'test',
  description: 'Run JavaScript and Solidity tests',
  builder: {},
  run: function (options, done) {
    var OS = require("os");
    var dir = require("node-dir");
    var temp = require("temp");
    var Config = require("truffle-config");
    var Artifactor = require("truffle-artifactor");
    var Develop = require("../develop");
    var Test = require("../test");
    var fs = require("fs");
    var copy = require("../copy");
    var Environment = require("../environment");

    var config = Config.detect(options);

    // if "development" exists, default to using that for testing
    if (!config.network && config.networks.development) {
      config.network = "development";
    }

    if (!config.network) {
      config.network = "test";
    }

    var ipcDisconnect;

    var files = [];

    if (options.file) {
      files = [options.file];
    } else if (options._.length > 0) {
      Array.prototype.push.apply(files, options._);
    }

    function getFiles(callback) {
      if (files.length != 0) {
        return callback(null, files);
      }

      dir.files(config.test_directory, callback);
    };

    getFiles(function(err, files) {
      if (err) return done(err);

      files = files.filter(function(file) {
        return file.match(config.test_file_extension_regexp) != null;
      });

      temp.mkdir('test-', function(err, temporaryDirectory) {
        if (err) return done(err);

        function cleanup() {
          var args = arguments;
          // Ensure directory cleanup.
          temp.cleanup(function(err) {
            // Ignore cleanup errors.
            done.apply(null, args);
            if (ipcDisconnect) {
              ipcDisconnect();
            }
          });
        };

        function run() {
          // Set a new artifactor; don't rely on the one created by Environments.
          // TODO: Make the test artifactor configurable.
          config.artifactor = new Artifactor(temporaryDirectory);

          Test.run(config.with({
            test_files: files,
            contracts_build_directory: temporaryDirectory
          }), cleanup);
        };

        var environmentCallback = function(err) {
          if (err) return done(err);
          // Copy all the built files over to a temporary directory, because we
          // don't want to save any tests artifacts. Only do this if the build directory
          // exists.
          fs.stat(config.contracts_build_directory, function(err, stat) {
            if (err) return run();

            copy(config.contracts_build_directory, temporaryDirectory, function(err) {
              if (err) return done(err);

              config.logger.log("Using network '" + config.network + "'." + OS.EOL);

              run();
            });
          });
        }

        if (config.networks[config.network]) {
          Environment.detect(config, environmentCallback);
        } else {
          var ipcOptions = {
            network: "test"
          };

          var testrpcOptions = {
            host: "127.0.0.1",
            port: 7545,
            network_id: 4447,
            mnemonic: "candy maple cake sugar pudding cream honey rich smooth crumble sweet treat",
            gasLimit: config.gas
          };

          Develop.connectOrStart(ipcOptions, testrpcOptions, function(started, disconnect) {
            ipcDisconnect = disconnect;
            Environment.develop(config, testrpcOptions, environmentCallback);
          });
        }
      });
    });
  }
}

module.exports = command;
<commit_msg>Add --show-events flag to test command<commit_after>var command = {
  command: 'test',
  description: 'Run JavaScript and Solidity tests',
  builder: {
    "show-events": {
      describe: "Show all test logs",
      type: "boolean",
      default: false
    },
  },
  run: function (options, done) {
    var OS = require("os");
    var dir = require("node-dir");
    var temp = require("temp");
    var Config = require("truffle-config");
    var Artifactor = require("truffle-artifactor");
    var Develop = require("../develop");
    var Test = require("../test");
    var fs = require("fs");
    var copy = require("../copy");
    var Environment = require("../environment");

    var config = Config.detect(options);

    // if "development" exists, default to using that for testing
    if (!config.network && config.networks.development) {
      config.network = "development";
    }

    if (!config.network) {
      config.network = "test";
    }

    var ipcDisconnect;

    var files = [];

    if (options.file) {
      files = [options.file];
    } else if (options._.length > 0) {
      Array.prototype.push.apply(files, options._);
    }

    function getFiles(callback) {
      if (files.length != 0) {
        return callback(null, files);
      }

      dir.files(config.test_directory, callback);
    };

    getFiles(function(err, files) {
      if (err) return done(err);

      files = files.filter(function(file) {
        return file.match(config.test_file_extension_regexp) != null;
      });

      temp.mkdir('test-', function(err, temporaryDirectory) {
        if (err) return done(err);

        function cleanup() {
          var args = arguments;
          // Ensure directory cleanup.
          temp.cleanup(function(err) {
            // Ignore cleanup errors.
            done.apply(null, args);
            if (ipcDisconnect) {
              ipcDisconnect();
            }
          });
        };

        function run() {
          // Set a new artifactor; don't rely on the one created by Environments.
          // TODO: Make the test artifactor configurable.
          config.artifactor = new Artifactor(temporaryDirectory);

          Test.run(config.with({
            test_files: files,
            contracts_build_directory: temporaryDirectory
          }), cleanup);
        };

        var environmentCallback = function(err) {
          if (err) return done(err);
          // Copy all the built files over to a temporary directory, because we
          // don't want to save any tests artifacts. Only do this if the build directory
          // exists.
          fs.stat(config.contracts_build_directory, function(err, stat) {
            if (err) return run();

            copy(config.contracts_build_directory, temporaryDirectory, function(err) {
              if (err) return done(err);

              config.logger.log("Using network '" + config.network + "'." + OS.EOL);

              run();
            });
          });
        }

        if (config.networks[config.network]) {
          Environment.detect(config, environmentCallback);
        } else {
          var ipcOptions = {
            network: "test"
          };

          var testrpcOptions = {
            host: "127.0.0.1",
            port: 7545,
            network_id: 4447,
            mnemonic: "candy maple cake sugar pudding cream honey rich smooth crumble sweet treat",
            gasLimit: config.gas
          };

          Develop.connectOrStart(ipcOptions, testrpcOptions, function(started, disconnect) {
            ipcDisconnect = disconnect;
            Environment.develop(config, testrpcOptions, environmentCallback);
          });
        }
      });
    });
  }
}

module.exports = command;
<|endoftext|>


<commit_before>var fs = require("fs"),
	express = require("express"),
	app = express(),
	marked = require("marked"),
	mustache = require("./mustache.js"),
	template = fs.readFileSync("./themes/basic/main.html", { "encoding": "utf-8" }),
	archives,
	drafts,
	object_factory = function () {
		var obj = {
			"author": "Guy Pursey",
			"title": "Coughing & Chopping",
			"blog_title": "A testing blog.",
			"posts": [],
			"base_url": "http://scriptogr.am/guypursey",
			"css": "<link href=\"/themes/basic/style.css\" rel=\"stylesheet\" type=\"text/css\" />",
			"profile_image": "http://www.gravatar.com/avatar/97e4c3c79d57e4e9df2f78aaa5c39361?d=mm&s=128",
			"cover_image": "",
			"accent_color": "",
			"theme": "basic",
			"pages": [
				{
					"permalink": "",
					"title": ""
				}
			],
			"page": "",
			"is_archive": false,
			"pagination": ""
		};
		return obj;
	},
	context;

// By inserting a space in each triplet of braces, this prevents an error with the CSS and Mustache template.
template = template.replace(/\}\}\}/g, "}} }");

app.use("/themes", express.static('themes'));

app.use(function (req, res, next) {
	fs.readdir("../content/archives/", function (err, files) {
		if (err) {
			res.sendStatus(500); // equivalent to res.status(500).send('Internal Server Error')
		} else {
			archives = files.filter(function (e, i, a) {
				return (e.match(/^\d{12}/));
			});
			context = object_factory();
			archives.forEach(function(v, i, a) {
				var current_post = {},
					post_file = fs.readFileSync("../content/archives/" + v  + "/" + v + ".md", { "encoding": "utf-8" }),
					tags_file = fs.readFileSync("../content/archives/" + v  + "/" + "tags.txt", { "encoding": "utf-8" });

				current_post["title"] = "Test post";
				current_post["content"] = marked(post_file);
				current_post["tags"] = [{ "name": "test" }];

				context.posts.push(current_post);
			});

			// TODO: sort out synchronicity
			next();
		}
	});
});

app.use("/draft", function (req, res, next) {
	fs.readdir("../content/drafts/", function (err, files) {
		if (err) {
			res.sendStatus(500); // equivalent to res.status(500).send('Internal Server Error')
		} else {
			drafts = files.filter(function (e, i, a) {
				return true;
			});
			next();
		}
	});
});

app.get("/", function (req, res, next) {
	res.writeHead(200, "text/html");
	res.write(JSON.stringify(archives, null, "\t"));
	next();
});

app.use("/preview", function (req, res, next) {
	res.writeHead(200, "text/html");
	res.write(mustache.render(template, context));
	next();
});

app.get("/draft", function (req, res, next) {
	res.writeHead(200, "text/html");
	res.write(JSON.stringify(archives, null, "\t"));
	res.write(JSON.stringify(drafts, null, "\t") || " ");
	next();
});

app.use(function (req, res, next) {
	res.end();
});

app.listen(1337);<commit_msg>Added code which will allow proper HTML rendering.<commit_after>var fs = require("fs"),
	express = require("express"),
	app = express(),
	marked = require("marked"),
	mustache = require("./mustache.js"),
	template = fs.readFileSync("./themes/basic/main.html", { "encoding": "utf-8" }),
	archives,
	drafts,
	object_factory = function () {
		var obj = {
			"author": "Guy Pursey",
			"title": "Coughing & Chopping",
			"blog_title": "A testing blog.",
			"posts": [],
			"base_url": "http://scriptogr.am/guypursey",
			"css": "<link href=\"/themes/basic/style.css\" rel=\"stylesheet\" type=\"text/css\" />",
			"profile_image": "http://www.gravatar.com/avatar/97e4c3c79d57e4e9df2f78aaa5c39361?d=mm&s=128",
			"cover_image": "",
			"accent_color": "",
			"theme": "basic",
			"pages": [
				{
					"permalink": "",
					"title": ""
				}
			],
			"page": "",
			"is_archive": false,
			"pagination": ""
		};
		return obj;
	},
	tripled_variables = ["css", "content", "profile_image"],
	context;

// By inserting a space in each triplet of braces, this prevents an error with the CSS and Mustache template.
template = template.replace(/\}\}\}/g, "}} }");

// Because Scriptogram only ever uses double-braced variables, replace these with triple-braced.
tripled_variables.forEach(function (v, i, a) {
	template = template.replace(new RegExp("\{\{(" + v + ")\}\}", "g"), "{{{$1}}}");
});

app.use("/themes", express.static('themes'));

app.use(function (req, res, next) {
	fs.readdir("../content/archives/", function (err, files) {
		if (err) {
			res.sendStatus(500); // equivalent to res.status(500).send('Internal Server Error')
		} else {
			archives = files.filter(function (e, i, a) {
				return (e.match(/^\d{12}/));
			});
			context = object_factory();
			archives.forEach(function(v, i, a) {
				var current_post = {},
					post_file = fs.readFileSync("../content/archives/" + v  + "/" + v + ".md", { "encoding": "utf-8" }),
					tags_file = fs.readFileSync("../content/archives/" + v  + "/" + "tags.txt", { "encoding": "utf-8" });

				current_post["title"] = "Test post";
				current_post["content"] = marked(post_file);
				current_post["tags"] = [{ "name": "test" }];

				context.posts.push(current_post);
			});

			// TODO: sort out synchronicity
			next();
		}
	});
});

app.use("/draft", function (req, res, next) {
	fs.readdir("../content/drafts/", function (err, files) {
		if (err) {
			res.sendStatus(500); // equivalent to res.status(500).send('Internal Server Error')
		} else {
			drafts = files.filter(function (e, i, a) {
				return true;
			});
			next();
		}
	});
});

app.get("/", function (req, res, next) {
	res.writeHead(200, "text/html");
	res.write(JSON.stringify(archives, null, "\t"));
	next();
});

app.use("/preview", function (req, res, next) {
	res.writeHead(200, "text/html");
	res.write(mustache.render(template, context));
	next();
});

app.get("/draft", function (req, res, next) {
	res.writeHead(200, "text/html");
	res.write(JSON.stringify(archives, null, "\t"));
	res.write(JSON.stringify(drafts, null, "\t") || " ");
	next();
});

app.use(function (req, res, next) {
	res.end();
});

app.listen(1337);<|endoftext|>


<commit_before>const queue = require('../../workers/queue');
const models = require("../../../models");
const i18n = require('../../utils/i18n');
const async = require('async');
const moment = require('moment');
const log = require('../../utils/logger');
const _ = require('lodash');

const domainIncludes = (domainId) => {
  return [
    {
      model: models.Group,
      required: true,
      attributes: ['id','configuration','name'],
      include: [
        {
          model: models.Community,
          required: true,
          attributes: ['id','configuration','name'],
          include: [
            {
              model: models.Domain,
              attributes: ['id','configuration','name'],
              where: {
                id: domainId
              },
              required: true
            }
          ]
        }
      ]
    }
  ];
};

const communityIncludes = (communityId) => {
  return [
    {
      model: models.Group,
      required: true,
      attributes: ['id','configuration','name'],
      include: [
        {
          model: models.Community,
          required: true,
          attributes: ['id','configuration','name'],
          where: {
            id: communityId
          }
        }
      ]
    }
  ];
};

const groupIncludes = (groupId) => {
  return [
    {
      model: models.Group,
      required: true,
      attributes: ['id','configuration','name'],
      where: {
        id: groupId
      }
    }
  ];
};

const userIncludes = (userId) => {
  return [
    {
      model: models.User,
      attributes: models.User.defaultAttributesWithSocialMediaPublicAndEmail,
      required: true,
      where: {
        id: userId
      }
    }
  ];
};

const _toPercent = number => {
  if (number) {
    return Math.round(number*100)+'%';
  }
};

const getPushItem = (type, model) => {
  let source, toxicityScore, toxicityScoreRaw, latestContent = null,
      severeToxicityScore, content,
      lastReportedAtDate = null, firstReportedDate = null,
      lastReportedByEmail;

  if (model.data && model.data.moderation) {
    const moderation = model.data.moderation;

    if (moderation.toxicityScore) {
      toxicityScore = _toPercent(moderation.toxicityScore);
      toxicityScoreRaw = moderation.toxicityScore;
    }

    if (moderation.severeToxicityScore) {
      severeToxicityScore = _toPercent(moderation.severeToxicityScore);
    }
    if (moderation.lastReportedBy &&
      moderation.lastReportedBy.length > 0) {
      source = moderation.lastReportedBy[0].source;
      firstReportedDate = moderation.lastReportedBy[moderation.lastReportedBy.length-1].date;
      lastReportedAtDate = moderation.lastReportedBy[0].date;
      lastReportedByEmail = moderation.lastReportedBy[0].userEmail;
    }
  }

  if (!firstReportedDate)
    firstReportedDate = model.created_at;

  if (!lastReportedAtDate)
    lastReportedAtDate = model.created_at;

  if (!lastReportedByEmail)
    lastReportedByEmail = "Unknown";

  let pointTextContent, postTextContent, postTranscriptContent, postNameContent;

  if (type==='point') {
    pointTextContent = model.PointRevisions[model.PointRevisions.length-1].content;
    latestContent = model.PointRevisions[model.PointRevisions.length-1].content;
  } else if (type==='post') {
    postTextContent = model.description;
    postNameContent = model.name;
    if (model.PostVideos && model.PostVideos.length>0 && model.PostVideos[model.PostVideos.length-1].meta && model.PostVideos[0].meta.text) {
      postTranscriptContent = model.PostVideos[model.PostVideos.length-1].meta.text;
    } else if (model.PostAudios && model.PostAudios.length>0 &&
      model.PostAudios[model.PostAudios.length-1].meta && model.PostAudios[model.PostAudios.length-1].meta.text) {
      postTranscriptContent = model.PostAudios[model.PostAudios.length-1].meta.text;
    }
  }

  let groupName;
  groupName = model.Group ? model.Group.name : null;
  if (groupName==='hidden_public_group_for_domain_level_points') {
    groupName = "";
  }

  return {
    id: model.id,
    created_at: model.created_at,
    formatted_date: moment(model.created_at).format("DD/MM/YY HH:mm"),
    type: type,
    lastReportedByEmail: lastReportedByEmail,
    counter_flags: model.counter_flags,
    status: model.status,
    public_data: model.public_data,
    user_id: model.user_id,
    toxicityScore: toxicityScore,
    toxicityScoreRaw: toxicityScoreRaw,
    severeToxicityScore: severeToxicityScore,
    source: source,
    lastReportedAtDate: lastReportedAtDate,
    firstReportedDate: firstReportedDate,
    lastReportedAtDateFormatted: lastReportedAtDate ? moment(lastReportedAtDate).format("DD/MM/YY HH:mm") : null,
    firstReportedDateFormatted:  firstReportedDate ? moment(firstReportedDate).format("DD/MM/YY HH:mm") : null,
    user_email: model.User.email,
    cover_media_type: model.cover_media_type,
    is_post: type==='post',
    is_point: type==='point',
    title: model.name,
    post_id: model.post_id,
    groupName: groupName,
    language: model.language,
    name: model.name,
    description: model.description,
    moderation_data: { moderation: model.data ? model.data.moderation : null },
    postTextContent,
    content: type==='post' ? (model.name + ' ' + model.description) : pointTextContent,
    pointTextContent,
    postTranscriptContent,
    postNameContent: postNameContent,
    name_content: type==='post' ? model.name : "",
    transcriptContent: postTranscriptContent,
    Group: model.Group,
    PostVideos: model.PostVideos,
    PostAudios: model.PostAudios,
    PostHeaderImages: model.PostHeaderImages,
    PointVideos: model.PointVideos,
    PointAudios: model.PointAudios,
    PointRevisions: model.PointRevisions,
    latestContent: latestContent
  };
};

const getItems = (posts, points, options) => {
  let items = [];
  _.forEach(posts, post => {
    items.push(getPushItem('post', post));
  });

  // Free memory
  posts = null;

  _.forEach(points, point => {
    items.push(getPushItem('point', point));
  });

  // Free memory
  points = null;

  if (options.allContent) {
    items = _.orderBy(items,['created_at'], ['desc']);
  } else {
    items = _.orderBy(items,['status', 'counter_flags', 'created_at'], ['asc','desc','desc']);
  }

  return items;
};

const getModelModeration = (options, callback) => {
  options.model.unscoped().findAll({
    where: {
      deleted: false,
      $or: [
        {
          counter_flags: {
            $gt: options.allContent ? -1 : 0
          },
        },
        {
          status: "in_moderation_queue"
        }
      ],
    },
    order: options.order,
    include: options.includes,
    attributes: options.attributes
  }).then(items => {
    callback(null, items);
  }).catch(error => {
    callback(error);
  })
};

const getAllModeratedItemsByMaster = (options, callback) => {
  let posts, points;

  const postBaseIncludes = _.cloneDeep(options.includes);
  const pointBaseIncludes = _.cloneDeep(options.includes);

  async.series([
    parallelCallback => {
      let postIncludes = postBaseIncludes.concat([
        {
          model: models.Image,
          required: false,
          as: 'PostHeaderImages',
          attributes:["formats",'updated_at']
        },
        {
          model: models.Video,
          required: false,
          attributes: ['id','formats','updated_at','viewable','public_meta','meta'],
          as: 'PostVideos',
          include: [
            {
              model: models.Image,
              as: 'VideoImages',
              attributes:["formats",'updated_at'],
              required: false
            },
          ]
        },
        {
          model: models.Audio,
          required: false,
          attributes: ['id','formats','updated_at','listenable','public_meta','meta'],
          as: 'PostAudios',
        }
      ]);

      if (!options.userId) {
        postIncludes = postIncludes.concat([ { model: models.User, attributes: models.User.defaultAttributesWithSocialMediaPublicAndEmail }]);
      } else {
        postIncludes = postIncludes.concat([ { model: models.Group, attributes: ['id','name','configuration'] }]);
      }

      const order = [
        [ { model: models.Image, as: 'PostHeaderImages' } ,'updated_at', 'asc' ],
        [ { model: models.Video, as: "PostVideos" }, 'updated_at', 'desc' ],
        [ { model: models.Audio, as: "PostAudios" }, 'updated_at', 'desc' ],
        [ { model: models.Video, as: "PostVideos" }, { model: models.Image, as: 'VideoImages' } ,'updated_at', 'asc' ]
      ];

      const attributes = ['id','created_at','counter_flags','language','data','name','cover_media_type','description','status','public_data','user_id'];

      getModelModeration(_.merge(_.cloneDeep(options), {model: models.Post, includes: postIncludes, order, attributes }), (error, postsIn) => {
        parallelCallback(error);
        posts = postsIn;
      })
    },
    parallelCallback => {
      let pointIncludes = pointBaseIncludes.concat([
        {
          model: models.Video,
          required: false,
          attributes: ['id','formats','updated_at','viewable','public_meta','meta'],
          as: 'PointVideos',
          include: [
            {
              model: models.Image,
              as: 'VideoImages',
              attributes:["formats",'updated_at'],
              required: false
            },
          ]
        },
        {
          model: models.Audio,
          required: false,
          attributes: ['id','formats','updated_at','listenable','public_meta','meta'],
          as: 'PointAudios'
        },
        {
          model: models.PointRevision,
          attributes: ['id','content'],
          required: false
        }
      ]);

      if (!options.userId) {
        pointIncludes = pointIncludes.concat([ { model: models.User, attributes: models.User.defaultAttributesWithSocialMediaPublicAndEmail }]);
      } else {
        pointIncludes = pointIncludes.concat([ { model: models.Group, required: false, attributes: ['id','name','configuration'] }]);
      }

      const order = [
        [ { model: models.Video, as: "PointVideos" }, 'updated_at', 'desc' ],
        [ { model: models.Audio, as: "PointAudios" }, 'updated_at', 'desc' ],
        [ models.PointRevision, 'created_at', 'asc' ],
        [ { model: models.Video, as: "PointVideos" }, { model: models.Image, as: 'VideoImages' } ,'updated_at', 'asc' ]
      ];

      const attributes = ['id','created_at','counter_flags','name','language','data','post_id','status','public_data','user_id'];

      getModelModeration(_.merge(_.cloneDeep(options), {model: models.Point, attributes, includes: pointIncludes, order }), (error, pointsIn) => {
        points = pointsIn;
        parallelCallback(error);
      })
    }
  ], error => {
    callback(error, getItems(posts, points, options));
  });
};

const getAllModeratedItemsByDomain = (options, callback) => {
  getAllModeratedItemsByMaster(_.merge(options, {includes: domainIncludes(options.domainId) }), callback);
};

const getAllModeratedItemsByCommunity = (options, callback) => {
  getAllModeratedItemsByMaster(_.merge(options, {includes: communityIncludes(options.communityId) }), callback);
};

const getAllModeratedItemsByGroup = (options, callback) => {
  getAllModeratedItemsByMaster(_.merge(options, {includes: groupIncludes(options.groupId) }), callback);
};

const getAllModeratedItemsByUser = (options, callback) => {
  getAllModeratedItemsByMaster(_.merge(options, {includes: userIncludes(options.userId) }), callback);
};

module.exports = {
  domainIncludes,
  communityIncludes,
  groupIncludes,
  userIncludes,
  getAllModeratedItemsByDomain,
  getAllModeratedItemsByUser,
  getAllModeratedItemsByCommunity,
  getAllModeratedItemsByGroup
};<commit_msg>Try to free memory for heroku limits<commit_after>const queue = require('../../workers/queue');
const models = require("../../../models");
const i18n = require('../../utils/i18n');
const async = require('async');
const moment = require('moment');
const log = require('../../utils/logger');
const _ = require('lodash');

const domainIncludes = (domainId) => {
  return [
    {
      model: models.Group,
      required: true,
      attributes: ['id','configuration','name'],
      include: [
        {
          model: models.Community,
          required: true,
          attributes: ['id','configuration','name'],
          include: [
            {
              model: models.Domain,
              attributes: ['id','configuration','name'],
              where: {
                id: domainId
              },
              required: true
            }
          ]
        }
      ]
    }
  ];
};

const communityIncludes = (communityId) => {
  return [
    {
      model: models.Group,
      required: true,
      attributes: ['id','configuration','name'],
      include: [
        {
          model: models.Community,
          required: true,
          attributes: ['id','configuration','name'],
          where: {
            id: communityId
          }
        }
      ]
    }
  ];
};

const groupIncludes = (groupId) => {
  return [
    {
      model: models.Group,
      required: true,
      attributes: ['id','configuration','name'],
      where: {
        id: groupId
      }
    }
  ];
};

const userIncludes = (userId) => {
  return [
    {
      model: models.User,
      attributes: models.User.defaultAttributesWithSocialMediaPublicAndEmail,
      required: true,
      where: {
        id: userId
      }
    }
  ];
};

const _toPercent = number => {
  if (number) {
    return Math.round(number*100)+'%';
  }
};

const getPushItem = (type, model) => {
  let source, toxicityScore, toxicityScoreRaw, latestContent = null,
      severeToxicityScore, content,
      lastReportedAtDate = null, firstReportedDate = null,
      lastReportedByEmail;

  if (model.data && model.data.moderation) {
    const moderation = model.data.moderation;

    if (moderation.toxicityScore) {
      toxicityScore = _toPercent(moderation.toxicityScore);
      toxicityScoreRaw = moderation.toxicityScore;
    }

    if (moderation.severeToxicityScore) {
      severeToxicityScore = _toPercent(moderation.severeToxicityScore);
    }
    if (moderation.lastReportedBy &&
      moderation.lastReportedBy.length > 0) {
      source = moderation.lastReportedBy[0].source;
      firstReportedDate = moderation.lastReportedBy[moderation.lastReportedBy.length-1].date;
      lastReportedAtDate = moderation.lastReportedBy[0].date;
      lastReportedByEmail = moderation.lastReportedBy[0].userEmail;
    }
  }

  if (!firstReportedDate)
    firstReportedDate = model.created_at;

  if (!lastReportedAtDate)
    lastReportedAtDate = model.created_at;

  if (!lastReportedByEmail)
    lastReportedByEmail = "Unknown";

  let pointTextContent, postTextContent, postTranscriptContent, postNameContent;

  if (type==='point') {
    pointTextContent = model.PointRevisions[model.PointRevisions.length-1].content;
    latestContent = model.PointRevisions[model.PointRevisions.length-1].content;
  } else if (type==='post') {
    postTextContent = model.description;
    postNameContent = model.name;
    if (model.PostVideos && model.PostVideos.length>0 && model.PostVideos[model.PostVideos.length-1].meta && model.PostVideos[0].meta.text) {
      postTranscriptContent = model.PostVideos[model.PostVideos.length-1].meta.text;
    } else if (model.PostAudios && model.PostAudios.length>0 &&
      model.PostAudios[model.PostAudios.length-1].meta && model.PostAudios[model.PostAudios.length-1].meta.text) {
      postTranscriptContent = model.PostAudios[model.PostAudios.length-1].meta.text;
    }
  }

  let groupName;
  groupName = model.Group ? model.Group.name : null;
  if (groupName==='hidden_public_group_for_domain_level_points') {
    groupName = "";
  }

  return {
    id: model.id,
    created_at: model.created_at,
    formatted_date: moment(model.created_at).format("DD/MM/YY HH:mm"),
    type: type,
    lastReportedByEmail: lastReportedByEmail,
    counter_flags: model.counter_flags,
    status: model.status,
    public_data: model.public_data,
    user_id: model.user_id,
    toxicityScore: toxicityScore,
    toxicityScoreRaw: toxicityScoreRaw,
    severeToxicityScore: severeToxicityScore,
    source: source,
    lastReportedAtDate: lastReportedAtDate,
    firstReportedDate: firstReportedDate,
    lastReportedAtDateFormatted: lastReportedAtDate ? moment(lastReportedAtDate).format("DD/MM/YY HH:mm") : null,
    firstReportedDateFormatted:  firstReportedDate ? moment(firstReportedDate).format("DD/MM/YY HH:mm") : null,
    user_email: model.User.email,
    cover_media_type: model.cover_media_type,
    is_post: type==='post',
    is_point: type==='point',
    title: model.name,
    post_id: model.post_id,
    groupName: groupName,
    language: model.language,
    name: model.name,
    description: model.description,
    moderation_data: { moderation: model.data ? model.data.moderation : null },
    postTextContent,
    content: type==='post' ? (model.name + ' ' + model.description) : pointTextContent,
    pointTextContent,
    postTranscriptContent,
    postNameContent: postNameContent,
    name_content: type==='post' ? model.name : "",
    transcriptContent: postTranscriptContent,
    Group: model.Group,
    PostVideos: model.PostVideos,
    PostAudios: model.PostAudios,
    PostHeaderImages: model.PostHeaderImages,
    PointVideos: model.PointVideos,
    PointAudios: model.PointAudios,
    PointRevisions: model.PointRevisions,
    latestContent: latestContent
  };
};

const getItems = (posts, points, options) => {
  log.info("get_moderation_items getItems 1");
  let items = [];
  _.forEach(posts, post => {
    items.push(getPushItem('post', post));
  });

  // Free memory
  posts = null;

  log.info("get_moderation_items getItems 2");
  _.forEach(points, point => {
    items.push(getPushItem('point', point));
  });

  // Free memory
  points = null;

  log.info("get_moderation_items getItems 3");
  if (options.allContent) {
    items = _.orderBy(items,['created_at'], ['desc']);
  } else {
    items = _.orderBy(items,['status', 'counter_flags', 'created_at'], ['asc','desc','desc']);
  }

  return items;
};

const getModelModeration = (options, callback) => {
  log.info("get_moderation_items getModelModeration X");
  options.model.unscoped().findAll({
    where: {
      deleted: false,
      $or: [
        {
          counter_flags: {
            $gt: options.allContent ? -1 : 0
          },
        },
        {
          status: "in_moderation_queue"
        }
      ],
    },
    order: options.order,
    include: options.includes,
    attributes: options.attributes
  }).then(items => {
    callback(null, items);
  }).catch(error => {
    callback(error);
  })
};

const getAllModeratedItemsByMaster = (options, callback) => {
  let posts, points;

  const postBaseIncludes = _.cloneDeep(options.includes);
  const pointBaseIncludes = _.cloneDeep(options.includes);

  async.series([
    parallelCallback => {
      let postIncludes = postBaseIncludes.concat([
        {
          model: models.Image,
          required: false,
          as: 'PostHeaderImages',
          attributes:["formats",'updated_at']
        },
        {
          model: models.Video,
          required: false,
          attributes: ['id','formats','updated_at','viewable','public_meta','meta'],
          as: 'PostVideos',
          include: [
            {
              model: models.Image,
              as: 'VideoImages',
              attributes:["formats",'updated_at'],
              required: false
            },
          ]
        },
        {
          model: models.Audio,
          required: false,
          attributes: ['id','formats','updated_at','listenable','public_meta','meta'],
          as: 'PostAudios',
        }
      ]);

      if (!options.userId) {
        postIncludes = postIncludes.concat([ { model: models.User, attributes: models.User.defaultAttributesWithSocialMediaPublicAndEmail }]);
      } else {
        postIncludes = postIncludes.concat([ { model: models.Group, attributes: ['id','name','configuration'] }]);
      }

      const order = [
        [ { model: models.Image, as: 'PostHeaderImages' } ,'updated_at', 'asc' ],
        [ { model: models.Video, as: "PostVideos" }, 'updated_at', 'desc' ],
        [ { model: models.Audio, as: "PostAudios" }, 'updated_at', 'desc' ],
        [ { model: models.Video, as: "PostVideos" }, { model: models.Image, as: 'VideoImages' } ,'updated_at', 'asc' ]
      ];

      const attributes = ['id','created_at','counter_flags','language','data','name','cover_media_type','description','status','public_data','user_id'];

      getModelModeration(_.merge(_.cloneDeep(options), {model: models.Post, includes: postIncludes, order, attributes }), (error, postsIn) => {
        parallelCallback(error);
        posts = postsIn;
      })
    },
    parallelCallback => {
      let pointIncludes = pointBaseIncludes.concat([
        {
          model: models.Video,
          required: false,
          attributes: ['id','formats','updated_at','viewable','public_meta','meta'],
          as: 'PointVideos',
          include: [
            {
              model: models.Image,
              as: 'VideoImages',
              attributes:["formats",'updated_at'],
              required: false
            },
          ]
        },
        {
          model: models.Audio,
          required: false,
          attributes: ['id','formats','updated_at','listenable','public_meta','meta'],
          as: 'PointAudios'
        },
        {
          model: models.PointRevision,
          attributes: ['id','content'],
          required: false
        }
      ]);

      if (!options.userId) {
        pointIncludes = pointIncludes.concat([ { model: models.User, attributes: models.User.defaultAttributesWithSocialMediaPublicAndEmail }]);
      } else {
        pointIncludes = pointIncludes.concat([ { model: models.Group, required: false, attributes: ['id','name','configuration'] }]);
      }

      const order = [
        [ { model: models.Video, as: "PointVideos" }, 'updated_at', 'desc' ],
        [ { model: models.Audio, as: "PointAudios" }, 'updated_at', 'desc' ],
        [ models.PointRevision, 'created_at', 'asc' ],
        [ { model: models.Video, as: "PointVideos" }, { model: models.Image, as: 'VideoImages' } ,'updated_at', 'asc' ]
      ];

      const attributes = ['id','created_at','counter_flags','name','language','data','post_id','status','public_data','user_id'];

      getModelModeration(_.merge(_.cloneDeep(options), {model: models.Point, attributes, includes: pointIncludes, order }), (error, pointsIn) => {
        points = pointsIn;
        parallelCallback(error);
      })
    }
  ], error => {
    log.info("get_moderation_items got items from database");
    callback(error, getItems(posts, points, options));
  });
};

const getAllModeratedItemsByDomain = (options, callback) => {
  getAllModeratedItemsByMaster(_.merge(options, {includes: domainIncludes(options.domainId) }), callback);
};

const getAllModeratedItemsByCommunity = (options, callback) => {
  getAllModeratedItemsByMaster(_.merge(options, {includes: communityIncludes(options.communityId) }), callback);
};

const getAllModeratedItemsByGroup = (options, callback) => {
  getAllModeratedItemsByMaster(_.merge(options, {includes: groupIncludes(options.groupId) }), callback);
};

const getAllModeratedItemsByUser = (options, callback) => {
  getAllModeratedItemsByMaster(_.merge(options, {includes: userIncludes(options.userId) }), callback);
};

module.exports = {
  domainIncludes,
  communityIncludes,
  groupIncludes,
  userIncludes,
  getAllModeratedItemsByDomain,
  getAllModeratedItemsByUser,
  getAllModeratedItemsByCommunity,
  getAllModeratedItemsByGroup
};<|endoftext|>


<commit_before>var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World!\n');
}).listen(1337);
console.log('Server running at Port 1337');

<commit_msg>Nodejs server port default to 9000<commit_after>var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World!\n');
}).listen(9000);
console.log('Server running at Port 9000');

<|endoftext|>