<commit_before>'use strict';
$(document).ready(function() {
    $("#filters ." + location.pathname.split("/")[5]+" input").attr("checked", "checked").parent().attr("style", "font-weight: bold !important;");
    $("#items .validate a").each(function(){
        $(this).click(validate_item_onclick);
    });
    $("#workflow_add_item a").click(modal_onclick);
    $(".workflow_add_category").click(modal_onclick);
    $("a[data-target='pop-up']").click(popupShow);
    $(".pop-up .close").click(popupClose);
    $(".take_untake_item a").click(takeItem);
    $(".take_untake_item a.close").click(untakeItem);
    $("table #sortable").each(function(){
        $(this).sortable({
            items: '.item_list',
            stop: onDragStop,
        }).disableSelection();
    });
    $(".tooltip").tooltip({
        position: { my: "left+15 center", at: "right center" }
    });
    $("#modal_background").click(modal_hide);

});

function popupData(popup){
    var $popup = $(popup),
        $ul = $popup.find('dl');

    $ul.empty();
    $.getJSON($popup.data('url'), function(data){
        var re = new RegExp("((((http|https):\/\/)?(www\.)?)?([a-zA-Z0-9;/?:@&=+$-])*(\.(fr|com|eu|org|net|edu|gouv|co|paris)){1}(\/[a-zA-Z0-9;/?:@&=+$-_!~*'()]+)?)");
        $.each(data, function(key, val){
            var words = val.text.split(' ');
            for(var i in words){
                var word = String(words[i]);
                if(word.match(re)){
                    if(!word.startsWith('http')){
                        word = 'http://' + word;
                        words[i] = word;
                    }
                }
            }
            val.text = words.join(' ');
            var text = val.text.replace(re, '$&');
            $ul.append('
'+ val.username + ' ' + $.datepicker.formatDate('dd/mm', new Date(val.date))  + '
')
               .append('
'+ text + '
');
        });
    });
}

function popupShow(){
    var $element = $($(this).next());
    $element.addClass('active').draggable();
    popupData($element);
}

function popupClose(){
    $(this).closest('.pop-up').removeClass('active');
    return false;
}

function onDragStop(event, ui){
    var item = $(ui.item).data("itemPk");
    var related = $(ui.item).next().data("itemPk");
    setItemPosition(related, item);
}

function setItemPosition(afterId, taskId){
    if(afterId){
        var url = "/workflow/drag-item/" + taskId + "/" + afterId + "/";
    }else{
        var url = "/workflow/drag-item/" + taskId + "/";
    }
    var dfd = $.post(url);
    dfd.fail(function(jqXHR, textStatus){
        console.log(textStatus);
    });
}

function send_request($elem){
    var dfd = $.get($elem.attr("href"));
    dfd.fail(function(jqXHR){
            alert(jqXHR.responseText);
    });
    return dfd;
}

function sendPutRequest(url, data){
    var dfd = $.ajax({
        url: url,
        type: 'PUT',
        data: data,
    });
    dfd.fail(function(jqXHR){
        console.log(jqXHR.responseText);
    });
    return dfd;
}

function updateProgressBar(){
    var $bar = $('.progress'),
        successBar = $bar.find('.progress-bar-success'),
        untestedBar = $bar.find('.progress-bar-untested'),
        failedBar = $bar.find('.progress-bar-danger');

    var counts = {
        0: 0, // Untested items
        1: 0, // Success items
        2: 0 // Failed items
    },
    total = 0;

    var $trs = $('.item_list');
    $trs.each(function() {
        counts[this.getAttribute('data-status')] += 1;
    });
    total = $trs.length;
    successPercent = (counts[1] * 100 )/ total;
    untestedPercent = (counts[0] * 100 )/ total;
    failedPercent = (counts[2] * 100 )/ total;

    successBar.css('width', successPercent + '%').text(Math.round(successPercent) + '%');
    untestedBar.css('width', untestedPercent + '%').text(Math.round(untestedPercent) + '%');
    failedBar.css('width', failedPercent + '%').text(Math.round(failedPercent) + '%');
    updateCounters(counts);
}

function updateCounters(counts){
    $('.square.success .number').text(counts[1]);
    $('.square.untested .number').text(counts[0]);
    $('.square.failed .number').text(counts[2]);
    $('#filters .success .number').text(counts[1]);
    $('#filters .failed .number').text(counts[2]);
}

function takeItem(){
    var elem = $(this);
    var username = elem.closest('table').data('username');
    var item_pk = elem.closest('.item_list').data('item-pk');
    if(elem.hasClass('not-take')){
        var dfd = sendPutRequest(
            "/api/item/" + item_pk + "/take/" + username + "/",
            {username: username, item_pk: item_pk}
        );
        dfd.done(function(){
            elem.removeClass('not-take');
            var link = $('');
            elem.closest('.take_untake_item').html(username + link[0].outerHTML);
            $('.untake').click(untakeItem);
        });
    }
}

function untakeItem(){
    var elem = $(this);
    var item_pk = elem.closest('.item_list').data('item-pk');
    if(!elem.hasClass('not-take')){
        var dfd = sendPutRequest(
            "/api/item/" + item_pk + "/untake/",
            {item_pk: item_pk}
        );
        dfd.done(function(){
            var link = $('Take');
            elem.closest('.take_untake_item').html(link);
            link.click(takeItem);
        });
    }

}

function validate_item_onclick() {
    var elem = $(this);
    var url = $(elem).data('url');
    $.get(url)
        .done(function(data){
            var status_old = data.status_old;
            var status_new = data.validation;
            $(elem).closest('tr').attr('data-status', status_new);
            $(elem).closest('td').find('span.validated').removeClass('validated');
            $(elem).find('span').addClass('validated');
            $(elem).closest('td').find('span.last_modification').text(moment(data.updated_at).format('D/MM/YYYY HH:mm'));

            updateProgressBar();
        })
        .fail(function(jqXHR){
            alert(jqXHR.responseText);
        });
    return false;
}

function modal_onclick() {
    $elem = $(this)
    send_request($elem)
        .done(function(data){
            modal_callback($elem, data);
        });
    return false;
}

function modal_callback($elem, data) {
    var $content = $($.trim(data)).filter("#content");
    $content.find("form").attr("action", $elem.attr("href")); // set the correct target url

    $("body #modal_content").html($content.html()+'×');
    $("#modal_content form :submit").click(modal_form_submit_onclick);

    // callback to close the modal
    $("#modal_background").click(modal_hide);
    $("#modal_content .close_modal").click(modal_hide);

    modal_show();
}

function modal_show() {
    $("#modal_content").css("top", window.scrollY);
    $("#modal_background").show();
    $("#modal_content").show();
    return false;
}

function modal_hide() {
    $("#modal_background").hide();
    $("#modal_content").hide();
    return false;
}

function modal_form_submit_onclick() {
    var f = $("#modal_content form");
    $.post(f.attr("action"), f.serialize())
        .done(function(data, textStatus, jqXHR){
            if (jqXHR.getResponseHeader("Content-Type") === "text/html; charset=utf-8") {
                /* post failed, show the form again */
                modal_callback($("#modal_content form").attr("action"), data);
            }
            else {
                /* post successfull (this is supposed to be an empty json response) */

                modal_hide();

                var cat_id = f.find("select :selected").attr("value");

                if (typeof cat_id === "undefined") {
                    /* new category, we must reload the whole page to show it */
                    location.reload();
                }
                else {
                    /* category already exist, just refresh it */
                    counters["all"] += 1;
                    counters["untaken"] += 1;
                    counters["untested"] += 1;
                    $("#take_untake_category_"+cat_id + "_show a").click();
                }
            }
        })
        .fail(function(jqXHR){
            console.log(jqXHR.responseText);
        });
    return false;
}
<commit_msg>fix var declaration<commit_after>'use strict';
$(document).ready(function() {
    $("#filters ." + location.pathname.split("/")[5]+" input").attr("checked", "checked").parent().attr("style", "font-weight: bold !important;");
    $("#items .validate a").each(function(){
        $(this).click(validate_item_onclick);
    });
    $("#workflow_add_item a").click(modal_onclick);
    $(".workflow_add_category").click(modal_onclick);
    $("a[data-target='pop-up']").click(popupShow);
    $(".pop-up .close").click(popupClose);
    $(".take_untake_item a").click(takeItem);
    $(".take_untake_item a.close").click(untakeItem);
    $("table #sortable").each(function(){
        $(this).sortable({
            items: '.item_list',
            stop: onDragStop,
        }).disableSelection();
    });
    $(".tooltip").tooltip({
        position: { my: "left+15 center", at: "right center" }
    });
    $("#modal_background").click(modal_hide);

});

function popupData(popup){
    var $popup = $(popup),
        $ul = $popup.find('dl');

    $ul.empty();
    $.getJSON($popup.data('url'), function(data){
        var re = new RegExp("((((http|https):\/\/)?(www\.)?)?([a-zA-Z0-9;/?:@&=+$-])*(\.(fr|com|eu|org|net|edu|gouv|co|paris)){1}(\/[a-zA-Z0-9;/?:@&=+$-_!~*'()]+)?)");
        $.each(data, function(key, val){
            var words = val.text.split(' ');
            for(var i in words){
                var word = String(words[i]);
                if(word.match(re)){
                    if(!word.startsWith('http')){
                        word = 'http://' + word;
                        words[i] = word;
                    }
                }
            }
            val.text = words.join(' ');
            var text = val.text.replace(re, '$&');
            $ul.append('
'+ val.username + ' ' + $.datepicker.formatDate('dd/mm', new Date(val.date))  + '
')
               .append('
'+ text + '
');
        });
    });
}

function popupShow(){
    var $element = $($(this).next());
    $element.addClass('active').draggable();
    popupData($element);
}

function popupClose(){
    $(this).closest('.pop-up').removeClass('active');
    return false;
}

function onDragStop(event, ui){
    var item = $(ui.item).data("itemPk");
    var related = $(ui.item).next().data("itemPk");
    setItemPosition(related, item);
}

function setItemPosition(afterId, taskId){
    if(afterId){
        var url = "/workflow/drag-item/" + taskId + "/" + afterId + "/";
    }else{
        var url = "/workflow/drag-item/" + taskId + "/";
    }
    var dfd = $.post(url);
    dfd.fail(function(jqXHR, textStatus){
        console.log(textStatus);
    });
}

function send_request($elem){
    var dfd = $.get($elem.attr("href"));
    dfd.fail(function(jqXHR){
            alert(jqXHR.responseText);
    });
    return dfd;
}

function sendPutRequest(url, data){
    var dfd = $.ajax({
        url: url,
        type: 'PUT',
        data: data,
    });
    dfd.fail(function(jqXHR){
        console.log(jqXHR.responseText);
    });
    return dfd;
}

function updateProgressBar(){
    var $bar = $('.progress'),
        successBar = $bar.find('.progress-bar-success'),
        untestedBar = $bar.find('.progress-bar-untested'),
        failedBar = $bar.find('.progress-bar-danger');

    var counts = {
        0: 0, // Untested items
        1: 0, // Success items
        2: 0 // Failed items
    },
    total = 0;

    var $trs = $('.item_list');
    $trs.each(function() {
        counts[this.getAttribute('data-status')] += 1;
    });
    total = $trs.length;
    var successPercent = (counts[1] * 100 )/ total,
        untestedPercent = (counts[0] * 100 )/ total,
        failedPercent = (counts[2] * 100 )/ total;

    successBar.css('width', successPercent + '%').text(Math.round(successPercent) + '%');
    untestedBar.css('width', untestedPercent + '%').text(Math.round(untestedPercent) + '%');
    failedBar.css('width', failedPercent + '%').text(Math.round(failedPercent) + '%');
    updateCounters(counts);
}

function updateCounters(counts){
    $('.square.success .number').text(counts[1]);
    $('.square.untested .number').text(counts[0]);
    $('.square.failed .number').text(counts[2]);
    $('#filters .success .number').text(counts[1]);
    $('#filters .failed .number').text(counts[2]);
}

function takeItem(){
    var elem = $(this);
    var username = elem.closest('table').data('username');
    var item_pk = elem.closest('.item_list').data('item-pk');
    if(elem.hasClass('not-take')){
        var dfd = sendPutRequest(
            "/api/item/" + item_pk + "/take/" + username + "/",
            {username: username, item_pk: item_pk}
        );
        dfd.done(function(){
            elem.removeClass('not-take');
            var link = $('');
            elem.closest('.take_untake_item').html(username + link[0].outerHTML);
            $('.untake').click(untakeItem);
        });
    }
}

function untakeItem(){
    var elem = $(this);
    var item_pk = elem.closest('.item_list').data('item-pk');
    if(!elem.hasClass('not-take')){
        var dfd = sendPutRequest(
            "/api/item/" + item_pk + "/untake/",
            {item_pk: item_pk}
        );
        dfd.done(function(){
            var link = $('Take');
            elem.closest('.take_untake_item').html(link);
            link.click(takeItem);
        });
    }

}

function validate_item_onclick() {
    var elem = $(this);
    var url = $(elem).data('url');
    $.get(url)
        .done(function(data){
            var status_old = data.status_old;
            var status_new = data.validation;
            $(elem).closest('tr').attr('data-status', status_new);
            $(elem).closest('td').find('span.validated').removeClass('validated');
            $(elem).find('span').addClass('validated');
            $(elem).closest('td').find('span.last_modification').text(moment(data.updated_at).format('D/MM/YYYY HH:mm'));

            updateProgressBar();
        })
        .fail(function(jqXHR){
            alert(jqXHR.responseText);
        });
    return false;
}

function modal_onclick() {
    $elem = $(this)
    send_request($elem)
        .done(function(data){
            modal_callback($elem, data);
        });
    return false;
}

function modal_callback($elem, data) {
    var $content = $($.trim(data)).filter("#content");
    $content.find("form").attr("action", $elem.attr("href")); // set the correct target url

    $("body #modal_content").html($content.html()+'×');
    $("#modal_content form :submit").click(modal_form_submit_onclick);

    // callback to close the modal
    $("#modal_background").click(modal_hide);
    $("#modal_content .close_modal").click(modal_hide);

    modal_show();
}

function modal_show() {
    $("#modal_content").css("top", window.scrollY);
    $("#modal_background").show();
    $("#modal_content").show();
    return false;
}

function modal_hide() {
    $("#modal_background").hide();
    $("#modal_content").hide();
    return false;
}

function modal_form_submit_onclick() {
    var f = $("#modal_content form");
    $.post(f.attr("action"), f.serialize())
        .done(function(data, textStatus, jqXHR){
            if (jqXHR.getResponseHeader("Content-Type") === "text/html; charset=utf-8") {
                /* post failed, show the form again */
                modal_callback($("#modal_content form").attr("action"), data);
            }
            else {
                /* post successfull (this is supposed to be an empty json response) */

                modal_hide();

                var cat_id = f.find("select :selected").attr("value");

                if (typeof cat_id === "undefined") {
                    /* new category, we must reload the whole page to show it */
                    location.reload();
                }
                else {
                    /* category already exist, just refresh it */
                    counters["all"] += 1;
                    counters["untaken"] += 1;
                    counters["untested"] += 1;
                    $("#take_untake_category_"+cat_id + "_show a").click();
                }
            }
        })
        .fail(function(jqXHR){
            console.log(jqXHR.responseText);
        });
    return false;
}
<|endoftext|>


<commit_before>export default [
  {id: 'vale_guardian', raid: 'Forsaken Thicket', wing: 'Spirit Vale', name: 'Vale Guardian', type: 'Boss'},
  {id: 'spirit_woods', raid: 'Forsaken Thicket', wing: 'Spirit Vale', name: 'Spirit Woods', type: 'Checkpoint'},
  {id: 'gorseval', raid: 'Forsaken Thicket', wing: 'Spirit Vale', name: 'Gorseval', type: 'Boss'},
  {id: 'sabetha', raid: 'Forsaken Thicket', wing: 'Spirit Vale', name: 'Sabetha', type: 'Boss'},
  {id: 'slothasor', raid: 'Forsaken Thicket', wing: 'Salvation Pass', name: 'Slothasor', type: 'Boss'},
  {id: 'bandit_trio', raid: 'Forsaken Thicket', wing: 'Salvation Pass', name: 'Bandit Trio', type: 'Boss'},
  {id: 'matthias', raid: 'Forsaken Thicket', wing: 'Salvation Pass', name: 'Matthias', type: 'Boss'},
  {id: 'escort', raid: 'Forsaken Thicket', wing: 'Stronghold of the Faithful', name: 'Escort', type: 'Boss'},
  {id: 'keep_construct', raid: 'Forsaken Thicket', wing: 'Stronghold of the Faithful', name: 'Keep Construct', type: 'Boss'},
  {id: 'twisted_castle', raid: 'Forsaken Thicket', wing: 'Stronghold of the Faithful', name: 'Twisted Castle', type: 'Checkpoint'},
  {id: 'xera', raid: 'Forsaken Thicket', wing: 'Stronghold of the Faithful', name: 'Xera', type: 'Boss'},
  {id: 'cairn', raid: 'Forsaken Thicket', wing: 'Bastion of the Penitent', name: 'Cairn', type: 'Boss'},
  {id: 'mursaat_overseer', raid: 'Forsaken Thicket', wing: 'Bastion of the Penitent', name: 'Mursaat Overseer', type: 'Boss'},
  {id: 'samarog', raid: 'Forsaken Thicket', wing: 'Bastion of the Penitent', name: 'Samarog', type: 'Boss'},
  {id: 'deimos', raid: 'Forsaken Thicket', wing: 'Bastion of the Penitent', name: 'Deimos', type: 'Boss'}
]
<commit_msg>Fix raid name for Bastion of the Penitent<commit_after>export default [
  {id: 'vale_guardian', raid: 'Forsaken Thicket', wing: 'Spirit Vale', name: 'Vale Guardian', type: 'Boss'},
  {id: 'spirit_woods', raid: 'Forsaken Thicket', wing: 'Spirit Vale', name: 'Spirit Woods', type: 'Checkpoint'},
  {id: 'gorseval', raid: 'Forsaken Thicket', wing: 'Spirit Vale', name: 'Gorseval', type: 'Boss'},
  {id: 'sabetha', raid: 'Forsaken Thicket', wing: 'Spirit Vale', name: 'Sabetha', type: 'Boss'},
  {id: 'slothasor', raid: 'Forsaken Thicket', wing: 'Salvation Pass', name: 'Slothasor', type: 'Boss'},
  {id: 'bandit_trio', raid: 'Forsaken Thicket', wing: 'Salvation Pass', name: 'Bandit Trio', type: 'Boss'},
  {id: 'matthias', raid: 'Forsaken Thicket', wing: 'Salvation Pass', name: 'Matthias', type: 'Boss'},
  {id: 'escort', raid: 'Forsaken Thicket', wing: 'Stronghold of the Faithful', name: 'Escort', type: 'Boss'},
  {id: 'keep_construct', raid: 'Forsaken Thicket', wing: 'Stronghold of the Faithful', name: 'Keep Construct', type: 'Boss'},
  {id: 'twisted_castle', raid: 'Forsaken Thicket', wing: 'Stronghold of the Faithful', name: 'Twisted Castle', type: 'Checkpoint'},
  {id: 'xera', raid: 'Forsaken Thicket', wing: 'Stronghold of the Faithful', name: 'Xera', type: 'Boss'},
  {id: 'cairn', raid: 'Bastion of the Penitent', wing: 'Bastion of the Penitent', name: 'Cairn', type: 'Boss'},
  {id: 'mursaat_overseer', raid: 'Bastion of the Penitent', wing: 'Bastion of the Penitent', name: 'Mursaat Overseer', type: 'Boss'},
  {id: 'samarog', raid: 'Bastion of the Penitent', wing: 'Bastion of the Penitent', name: 'Samarog', type: 'Boss'},
  {id: 'deimos', raid: 'Bastion of the Penitent', wing: 'Bastion of the Penitent', name: 'Deimos', type: 'Boss'}
]
<|endoftext|>


<commit_before>import { hot } from "react-hot-loader";
import { Meteor } from "meteor/meteor";
import React, { Component, Fragment } from "react";
import { Router, Route, Redirect } from "react-router-dom";
import history from "../utils/history";
import qs from "query-string";

// DOCUSS
import "./style.scss";
import { dcs } from "/imports/client/utils/dcs-master";
const discourseUrl = "https://discuss.focallocal.org/";
//const discourseUrl = 'http://vps465971.ovh.net:3000'

// Includes
import MainMenu from "./includes/MainMenu";

// Pages
import Home from "./pages/Home";
import Whitepaper from "./pages/WhitePaper";
import Team from "./pages/TeamMembers";
import Faq from "./pages/Faq";
import Partners from "./pages/Partners";
import About from "./pages/About";
import Authentication from "./pages/Authentication";
import Map_ from "./pages/Map";
import NewEventLoadable from "./pages/NewEvent/loadable";
import CongratsModal from "./pages/NewEvent/CongratsModal";
import Page from "./pages/Page";

// Components
import ScrollToTop from "./components/ScrollToTop";
import Admin from "./pages/Admin/index"

class App extends Component {
  constructor() {
    super();
    // DOCUSS
    this.state = {
      showRightPanel: false,
      balloonId: false,
      dcsTags: null,
      leftRightTransition: false
    };
  }

  componentDidMount() {
    // Add the touch-screen flag to the  tag
    const touchScreen =
      !!("ontouchstart" in window) || window.navigator.msMaxTouchPoints > 0;
    if (touchScreen) {
      document.documentElement.classList.add("touch-screen");
    }

    setTimeout(() => {
      document.querySelector("#root").classList.toggle("show");
    }, 100); // add a fading effect on the inital loading

    // Hide the ghost when transition is over
    const dcsGhost = document.getElementById("dcs-ghost");
    dcsGhost.addEventListener("transitionend", () => {
      this.setState({ leftRightTransition: false });
    });

    // Connect to the plugin in Discourse
    dcs
      .connect({
        discourseWindow: document.getElementById("dcs-right").contentWindow,
        discourseOrigin: new URL(discourseUrl).origin,
        timeout: 15000
      })
      .catch(err => {
        // Timeout error
        console.log(err);
      });

    // Set up callbacks to handle Discourse route changes (when the user
    // clicks on something (ex: his profile) in Discourse)
    dcs.onHome(() => {
      this.triggeredByDiscourse = true;
      changeHistory({
        params: { r: "1", b: null, t: null, d: null },
        push: false
      });
    });
    dcs.onPath(path => {
      this.triggeredByDiscourse = true;
      changeHistory({
        params: { r: undefined, b: null, t: null, d: path },
        push: false
      });
    });
    dcs.onTagOrTopic((tag, topicId) => {
      Meteor.call("Events.getEventId", { discourseTag: tag }, (err, res) => {
        if (err) {
          console.log("Events.getEventId Error:", err);
        } else {
          this.triggeredByDiscourse = true;
          changeHistory({
            pathname: "/page/" + res,
            params: { r: "1", b: tag.substring(17), t: topicId || null },
            push: false
          });
        }
      });
    });

    // Setup callbacks to handle other Discourse events
    dcs.onUserChange(user => {
      //user && console.log('Unread notifications: ', user.unreadNotifications)
    });
    dcs.onDcsTags(dcsTags => {
      this.setState({ dcsTags });
    });

    // Update the Discourse route. DON'T DO THIS IMMEDIATELY, otherwise
    // transitions won't trigger between the two states
    setTimeout(() => {
      this.dcsUpdateFromUrl();
    }, 0);
    history.listen(() => {
      this.dcsUpdateFromUrl();
    });
  }

  dcsUpdateFromUrl() {
    const { r, b, t, d } = qs.parse(window.location.search);
    if (!this.triggeredByDiscourse) {
      // Required to no changing the route again
      if (t) {
        dcs.gotoTopic(t);
      } else if (b) {
        const prefix = "/page/";
        if (window.location.pathname.startsWith(prefix)) {
          const pageId = window.location.pathname.substring(prefix.length);
          const tag = "dcs-" + pageId.substring(0, 12).toLowerCase() + "-" + b;
          dcs.gotoTag(tag);
        } else if (window.location.pathname.startsWith('/')) {
          const pathname = window.location.pathname
          const endIndex = pathname.search('\\?') > -1 ? pathname.search('\\?') : pathname.length
          const tagLocation = pathname.slice(pathname.search('/') + 1, endIndex)
          const tag = "dcs-" + tagLocation + "-" + b
          dcs.gotoTag(tag)
        }
      } else if (d) {
        dcs.gotoPath(d);
      } else {
        dcs.gotoHome();
      }
    }
    this.triggeredByDiscourse = false;
    // Don't set leftRightTransition if you're not sure this will trigger a transition!
    const layoutChange =
      r !== this.state.showRightPanel || !!b !== !!this.state.balloonId;
    if (layoutChange) {
      this.setState({
        showRightPanel: r,
        balloonId: b,
        leftRightTransition: true
      });
    }
  }

  render() {
    let dcsClass = "";
    if (this.state.showRightPanel) {
      dcsClass += "dcs-show-right ";
    }
    if (this.state.balloonId) {
      dcsClass += "dcs-sel ";
    }

    const dcsProps = {
      dcsTags: this.state.dcsTags,
      dcsClick: this.dcsClick.bind(this)
    };

    return (

          <Router history={history}>
            <Fragment>
              <MainMenu />

              <ScrollToTop>
                <Route exact path="/(home)?" component={Home} />
                <Route exact path="/team" render={props => <Team {...props} {...dcsProps} />} />
                <Route exact path="/partners" render={props => <Partners {...props} {...dcsProps} />} />
                <Route exact path="/whitepaper" render={props => <Whitepaper {...props} {...dcsProps} />} />
                <Route exact path="/faq" render={props => <Faq {...props} {...dcsProps} />}/>
                <Route exact path="/about" render={props => <About {...props} {...dcsProps} />}/>
                <Route path="/map" component={Map_} />
                <Route exact path="/admin" render={props => <Admin {...props}/>} />
                <Route path="*" render={this.renderNewEvent} />
                <Route exact path="/thank-you" component={CongratsModal} />
                <Route exact path="/page/:id" render={props => <Page {...props} {...dcsProps} />}
                />

                <Authentication />
              </ScrollToTop>
            </Fragment>
          </Router>

>

    );
  }

  onDcsSplitbarClick = () => {
    const showRightPanel = !this.state.showRightPanel;
    changeHistory({ params: { r: showRightPanel ? "1" : null }, push: true });
  };

  dcsClick(balloonId) {
    if (balloonId) {
      if (balloonId.length > 3 || balloonId.toLowerCase() !== balloonId) {
        throw new Error(`Invalid balloonId "${balloonId}"`);
      }
      changeHistory({
        params: { r: "1", b: balloonId, t: null, d: null },
        push: true
      });
    } else {
      changeHistory({
        params: { r: null, b: null, t: null, d: null },
        push: true
      });
    }
  }

  renderNewEvent = ({ location, history }) => {
    const { new: new_, edit } = qs.parse(location.search);
    const isOpen = Boolean(new_ === "1" || (edit === "1" && window.__editData));

    if (isOpen && !Meteor.userId()) {
      sessionStorage.setItem("redirect", "/?new=1");
      return <Redirect to="/sign-in" />;
    }
    /*
    else if(!isOpen){
      return <Redirect to='/home' />
    }
    */

    return (
      <NewEventLoadable isOpen={isOpen} location={location} history={history} />
    );
  };
}

export default hot(module)(App);

// A falsy pathname means the pathname won't be changed
// An undefined query params means the query param won't be changed
// A null query params means the query param will be removed
function changeHistory({ pathname = null, params, push }) {
  const p = Object.assign(params);
  Object.keys(p).forEach(key => p[key] === undefined && delete p[key]);
  const s = qs.parse(window.location.search);
  Object.assign(s, p);
  Object.keys(s).forEach(key => s[key] === null && delete s[key]);
  const search = qs.stringify(s);
  //############################################################################
  // TERRIBLE WORKAROUND FOR ISSUE https://github.com/focallocal/fl-maps/issues/742
  if (pathname && pathname !== location.pathname) {
    console.log("##########", pathname + "?" + search);
    location.href = pathname + "?" + search;
    return;
  }
  //############################################################################
  pathname = pathname || window.location.pathname;
  if (push) {
    history.push({ pathname, search });
  } else {
    history.replace({ pathname, search });
  }
}
<commit_msg>implement routing from discourse to whitepaper<commit_after>import { hot } from "react-hot-loader";
import { Meteor } from "meteor/meteor";
import React, { Component, Fragment } from "react";
import { Router, Route, Redirect } from "react-router-dom";
import history from "../utils/history";
import qs from "query-string";

// DOCUSS
import "./style.scss";
import { dcs } from "/imports/client/utils/dcs-master";
const discourseUrl = "https://discuss.focallocal.org/";
//const discourseUrl = 'http://vps465971.ovh.net:3000'

// Includes
import MainMenu from "./includes/MainMenu";

// Pages
import Home from "./pages/Home";
import Whitepaper from "./pages/WhitePaper";
import Team from "./pages/TeamMembers";
import Faq from "./pages/Faq";
import Partners from "./pages/Partners";
import About from "./pages/About";
import Authentication from "./pages/Authentication";
import Map_ from "./pages/Map";
import NewEventLoadable from "./pages/NewEvent/loadable";
import CongratsModal from "./pages/NewEvent/CongratsModal";
import Page from "./pages/Page";

// Components
import ScrollToTop from "./components/ScrollToTop";
import Admin from "./pages/Admin/index"

class App extends Component {
  constructor() {
    super();
    // DOCUSS
    this.state = {
      showRightPanel: false,
      balloonId: false,
      dcsTags: null,
      leftRightTransition: false
    };
  }

  componentDidMount() {
    // Add the touch-screen flag to the  tag
    const touchScreen =
      !!("ontouchstart" in window) || window.navigator.msMaxTouchPoints > 0;
    if (touchScreen) {
      document.documentElement.classList.add("touch-screen");
    }

    setTimeout(() => {
      document.querySelector("#root").classList.toggle("show");
    }, 100); // add a fading effect on the inital loading

    // Hide the ghost when transition is over
    const dcsGhost = document.getElementById("dcs-ghost");
    dcsGhost.addEventListener("transitionend", () => {
      this.setState({ leftRightTransition: false });
    });

    // Connect to the plugin in Discourse
    dcs
      .connect({
        discourseWindow: document.getElementById("dcs-right").contentWindow,
        discourseOrigin: new URL(discourseUrl).origin,
        timeout: 15000
      })
      .catch(err => {
        // Timeout error
        console.log(err);
      });

    // Set up callbacks to handle Discourse route changes (when the user
    // clicks on something (ex: his profile) in Discourse)
    dcs.onHome(() => {
      this.triggeredByDiscourse = true;
      changeHistory({
        params: { r: "1", b: null, t: null, d: null },
        push: false
      });
    });
    dcs.onPath(path => {
      this.triggeredByDiscourse = true;
      changeHistory({
        params: { r: undefined, b: null, t: null, d: path },
        push: false
      });
    });
    dcs.onTagOrTopic((tag, topicId) => {
      if (tag.includes('whitepaper')) {
        changeHistory({
          pathname: "/whitepaper",
          params: { r: "1", b: tag.substring(17), t: topicId || null },
          push: false
        });
      } else {
        Meteor.call("Events.getEventId", { discourseTag: tag }, (err, res) => {
          if (err) {
            console.log("Events.getEventId Error:", err);
          } else {
            this.triggeredByDiscourse = true;
            changeHistory({
              pathname: "/page/" + res,
              params: { r: "1", b: tag.substring(17), t: topicId || null },
              push: false
            });
          }
        });
      }
    });

  //   dcs.onTagOrTopic((tag, topicId) => {
  //     if (isFromTheWhitepaperPage(tag)) { // Function to be designed
  //       changeHistory({
  //         pathname: "/whitepaper",
  //         params: { r: "1", b: tag.substring(...), t: topicId || null },
  //         push: false
  //       });
  // else {
  //         Meteor.call("Events.getEventId", { discourseTag: tag }, (err, res) => {
  //           if (err) {
  //             console.log("Events.getEventId Error:", err);
  //           } else {
  //             this.triggeredByDiscourse = true;
  //             changeHistory({
  //               pathname: "/page/" + res,
  //               params: { r: "1", b: tag.substring(...), t: topicId || null },
  //               push: false
  //             });
  //           }
  //         });
  //       }
  //     });

    // Setup callbacks to handle other Discourse events
    dcs.onUserChange(user => {
      //user && console.log('Unread notifications: ', user.unreadNotifications)
    });
    dcs.onDcsTags(dcsTags => {
      this.setState({ dcsTags });
    });

    // Update the Discourse route. DON'T DO THIS IMMEDIATELY, otherwise
    // transitions won't trigger between the two states
    setTimeout(() => {
      this.dcsUpdateFromUrl();
    }, 0);
    history.listen(() => {
      this.dcsUpdateFromUrl();
    });
  }

  dcsUpdateFromUrl() {
    const { r, b, t, d } = qs.parse(window.location.search);
    if (!this.triggeredByDiscourse) {
      // Required to no changing the route again
      if (t) {
        dcs.gotoTopic(t);
      } else if (b) {
        const prefix = "/page/";
        if (window.location.pathname.startsWith(prefix)) {
          const pageId = window.location.pathname.substring(prefix.length);
          const tag = "dcs-" + pageId.substring(0, 12).toLowerCase() + "-" + b;
          dcs.gotoTag(tag);
        } else if (window.location.pathname.startsWith('/')) {
          const pathname = window.location.pathname
          const endIndex = pathname.search('\\?') > -1 ? pathname.search('\\?') : pathname.length
          const tagLocation = pathname.slice(pathname.search('/') + 1, endIndex)
          const tag = "dcs-" + tagLocation + "-" + b
          dcs.gotoTag(tag)
        }
      } else if (d) {
        dcs.gotoPath(d);
      } else {
        dcs.gotoHome();
      }
    }
    this.triggeredByDiscourse = false;
    // Don't set leftRightTransition if you're not sure this will trigger a transition!
    const layoutChange =
      r !== this.state.showRightPanel || !!b !== !!this.state.balloonId;
    if (layoutChange) {
      this.setState({
        showRightPanel: r,
        balloonId: b,
        leftRightTransition: true
      });
    }
  }

  render() {
    let dcsClass = "";
    if (this.state.showRightPanel) {
      dcsClass += "dcs-show-right ";
    }
    if (this.state.balloonId) {
      dcsClass += "dcs-sel ";
    }

    const dcsProps = {
      dcsTags: this.state.dcsTags,
      dcsClick: this.dcsClick.bind(this)
    };

    return (

          <Router history={history}>
            <Fragment>
              <MainMenu />

              <ScrollToTop>
                <Route exact path="/(home)?" component={Home} />
                <Route exact path="/team" render={props => <Team {...props} {...dcsProps} />} />
                <Route exact path="/partners" render={props => <Partners {...props} {...dcsProps} />} />
                <Route exact path="/whitepaper" render={props => <Whitepaper {...props} {...dcsProps} />} />
                <Route exact path="/faq" render={props => <Faq {...props} {...dcsProps} />}/>
                <Route exact path="/about" render={props => <About {...props} {...dcsProps} />}/>
                <Route path="/map" component={Map_} />
                <Route exact path="/admin" render={props => <Admin {...props}/>} />
                <Route path="*" render={this.renderNewEvent} />
                <Route exact path="/thank-you" component={CongratsModal} />
                <Route exact path="/page/:id" render={props => <Page {...props} {...dcsProps} />}
                />

                <Authentication />
              </ScrollToTop>
            </Fragment>
          </Router>

>

    );
  }

  onDcsSplitbarClick = () => {
    const showRightPanel = !this.state.showRightPanel;
    changeHistory({ params: { r: showRightPanel ? "1" : null }, push: true });
  };

  dcsClick(balloonId) {
    if (balloonId) {
      if (balloonId.length > 3 || balloonId.toLowerCase() !== balloonId) {
        throw new Error(`Invalid balloonId "${balloonId}"`);
      }
      changeHistory({
        params: { r: "1", b: balloonId, t: null, d: null },
        push: true
      });
    } else {
      changeHistory({
        params: { r: null, b: null, t: null, d: null },
        push: true
      });
    }
  }

  renderNewEvent = ({ location, history }) => {
    const { new: new_, edit } = qs.parse(location.search);
    const isOpen = Boolean(new_ === "1" || (edit === "1" && window.__editData));

    if (isOpen && !Meteor.userId()) {
      sessionStorage.setItem("redirect", "/?new=1");
      return <Redirect to="/sign-in" />;
    }
    /*
    else if(!isOpen){
      return <Redirect to='/home' />
    }
    */

    return (
      <NewEventLoadable isOpen={isOpen} location={location} history={history} />
    );
  };
}

export default hot(module)(App);

// A falsy pathname means the pathname won't be changed
// An undefined query params means the query param won't be changed
// A null query params means the query param will be removed
function changeHistory({ pathname = null, params, push }) {
  const p = Object.assign(params);
  Object.keys(p).forEach(key => p[key] === undefined && delete p[key]);
  const s = qs.parse(window.location.search);
  Object.assign(s, p);
  Object.keys(s).forEach(key => s[key] === null && delete s[key]);
  const search = qs.stringify(s);
  //############################################################################
  // TERRIBLE WORKAROUND FOR ISSUE https://github.com/focallocal/fl-maps/issues/742
  if (pathname && pathname !== location.pathname) {
    console.log("##########", pathname + "?" + search);
    location.href = pathname + "?" + search;
    return;
  }
  //############################################################################
  pathname = pathname || window.location.pathname;
  if (push) {
    history.push({ pathname, search });
  } else {
    history.replace({ pathname, search });
  }
}
<|endoftext|>


<commit_before>// NPM Libraries
import { hot } from "react-hot-loader";
import { Meteor } from "meteor/meteor";
import React, { Component, Fragment } from "react";
import { Router, Route, Redirect } from "react-router-dom";
import history from "../utils/history";
import qs from "query-string";

// Includes/Fragments
import MainMenu from "./includes/MainMenu";

// Pages
import Home from "./pages/Home";
import Whitepaper from "./pages/WhitePaper";
import Team from "./pages/TeamMembers";
import Faq from "./pages/Faq";
import Partners from "./pages/Partners";
import About from "./pages/About";
import Map_ from "./pages/Map";
import NewEventLoadable from "./pages/NewEvent/loadable";
import CongratsModal from "./pages/NewEvent/CongratsModal";
import Page from "./pages/Page";
import { Error404 } from "./pages/Errors";

import WPIntro from "./pages/WhitePaper/Intro";
import WPWhy from "./pages/WhitePaper/Why";
import WPFAQs from "./pages/WhitePaper/faqs";

// Components
import ScrollToTop from "./components/ScrollToTop";
import Admin from "./pages/Admin/index"

// Docuss
import { comToPlugin, inIFrame } from 'dcs-client'
import { SimpleRouteMatcher } from 'meteor/sylque:dcs-simple-route-matcher'
import { runReactRouterSync } from 'dcs-react-router-sync'
import websiteJSON from '../../../public/dcs-website.json'

// Styles and Other
import './styles.scss'

//------------------------------------------------------------------------------

class App extends Component {
  componentDidMount() {
    // Add the touch-screen flag to the <html> tag
    const touchScreen =
      !!("ontouchstart" in window) || window.navigator.msMaxTouchPoints > 0;
    if (touchScreen) {
      document.documentElement.classList.add("touch-screen");
    }

    setTimeout(() => {
      document.querySelector("#root").classList.toggle("show");
    }, 100); // add a fading effect on the inital loading
  }

  render() {

    const routePaths = {
      root: "/",
      home: "/home",
      team: "/team",
      partners: "/partners",
      whitepaper: "/whitepaper",
      faq: "/faq",
      about: "/about",
      map: "/map",
      admin: "/admin",
      thankyou: "/thank-you",
      page: "/page",
      signin: "/sign-in",
      signup: "/sign-up",
      change_password: "/change-password",
      forgot_password: "/forgot-password",
      sso_auth: "/sso_auth",

      whitepaper_intro: "/whitepaper/intro",
      whitepaper_why: "/whitepaper/why",
      whitepaper_faqs: "/whitepaper/faqs"
    }
    const standaloneMode = !inIFrame()

    return (
      <Router history={history}>
        <Fragment>
          {standaloneMode && <MainMenu />}
          <ScrollToTop>
            <Route exact path={routePaths.root} component={Home} />
            <Route exact path={routePaths.home} component={Home} />
            <Route exact path={routePaths.team} component={Team} />
            <Route exact path={routePaths.partners} component={Partners} />
            <Route exact path={routePaths.whitepaper} component={Whitepaper} />
            <Route exact path={routePaths.faq} component={Faq} />
            <Route exact path={routePaths.about} component={About} />
            <Route path={routePaths.map} component={Map_} />
            <Route exact path={routePaths.admin} render={props => <Admin {...props} />} />
            <Route exact path={routePaths.thankyou} component={CongratsModal} />
            <Route exact path={`${routePaths.page}/:id`} component={Page} />

            <Route exact path={routePaths.whitepaper_intro} component={WPIntro} />
            <Route exact path={routePaths.whitepaper_why} render={WPWhy} />
            <Route exact path={routePaths.whitepaper_faqs} render={WPFAQs} />

            <Route path="*" render={() => this.check404Route(Object.values(routePaths))} />
          </ScrollToTop>
        </Fragment>
      </Router>
    );
  }

  renderNewEvent = ({ location, history }) => {
    const { new: new_, edit } = qs.parse(location.search);
    const isOpen = Boolean(new_ === "1" || (edit === "1" && window.__editData));

    if (isOpen && !Meteor.userId()) {
      /*
      sessionStorage.setItem("redirect", "/?new=1");
      return <Redirect to="/sign-in" />;
      */
      alert('You need to login before you can create an event')
      return null
    }
    /*
    else if(!isOpen){
      return <Redirect to='/home' />
    }
    */
    console.log('passed in loc:\n', location)
    console.log('passed in hist:\n', history)
    return (
      <NewEventLoadable isOpen={isOpen} location={location} history={history} />
    );
  };

  /**
   * This function manages the 'catch-all' route, serving two purposes.
   * (1) open a model to create/edit event when there is the appropriate search string in the URL
   * (2) for all other routes not specified, it will redirect to a 404 page
   * Ideally we should be using React-router Switch to create a fallback 404 page...
   * But this would require opening the new event modal without using the URL as a hook
   * And this may break interactions with Docus (e.g. editing an event directly from the forum)
   */
  check404Route = (routes) => {
    if (window.location.search === '?new=1' || window.location.search === '?edit=1') {
      return this.renderNewEvent({ location: window.location, history })
    }
    if (!routes.some(e => e === window.location.pathname)
      && !window.location.pathname.includes('/page/')
      && !window.location.pathname.includes('reset-password')) {
        return <Error404 />
    }
    return null
  }
}

export default hot(module)(App);

//------------------------------------------------------------------------------

// Docuss

if (inIFrame()) {
  comToPlugin.connect({
    discourseOrigin: '*',
    timeout: 10000,
    onTimeout: () => console.log('Could not connect to the Docuss plugin')
  })

  // Set Docuss-generated topic to have pre-populated category
  comToPlugin.onDiscourseRoutePushed(({ route }) => {
    const topicCategory =
      route.pageName === 'm_about'? 'The About Page Discussion' :
      route.pageName === 'whitepaper'? 'Public Happiness Token' :
      route.pageName === 'wp_why'? 'Public Happiness Token' :
      route.pageName === 'wp_intro'? 'Public Happiness Token' :
      route.pageName === 'wp_faqs'? 'Public Happiness Token' :
      route.pageName === 'm_gather'? 'Hidden' :
      'General Discussion'
    comToPlugin.postSetRouteProps({ category: topicCategory })
  })

}

const routeMatcher = new SimpleRouteMatcher({
  maxPageNameLength: websiteJSON.dcsTag.maxPageNameLength,
  forceLowercase: websiteJSON.dcsTag.forceLowercase,
  predefinedPageNames: websiteJSON.pages.map(p => ({
    pageName: p.name,
    pathname: p.url // This works because we know our urls are all relative urls, i.e. pathname = url
  })),
  otherPagesPrefix: websiteJSON.webApp.otherPagesPrefix
})

runReactRouterSync({ browserHistory: history, routeMatcher })

//------------------------------------------------------------------------------
<commit_msg>added happier world economies category<commit_after>// NPM Libraries
import { hot } from "react-hot-loader";
import { Meteor } from "meteor/meteor";
import React, { Component, Fragment } from "react";
import { Router, Route, Redirect } from "react-router-dom";
import history from "../utils/history";
import qs from "query-string";

// Includes/Fragments
import MainMenu from "./includes/MainMenu";

// Pages
import Home from "./pages/Home";
import Whitepaper from "./pages/WhitePaper";
import Team from "./pages/TeamMembers";
import Faq from "./pages/Faq";
import Partners from "./pages/Partners";
import About from "./pages/About";
import Map_ from "./pages/Map";
import NewEventLoadable from "./pages/NewEvent/loadable";
import CongratsModal from "./pages/NewEvent/CongratsModal";
import Page from "./pages/Page";
import { Error404 } from "./pages/Errors";

import WPIntro from "./pages/WhitePaper/Intro";
import WPWhy from "./pages/WhitePaper/Why";
import WPFAQs from "./pages/WhitePaper/faqs";

// Components
import ScrollToTop from "./components/ScrollToTop";
import Admin from "./pages/Admin/index"

// Docuss
import { comToPlugin, inIFrame } from 'dcs-client'
import { SimpleRouteMatcher } from 'meteor/sylque:dcs-simple-route-matcher'
import { runReactRouterSync } from 'dcs-react-router-sync'
import websiteJSON from '../../../public/dcs-website.json'

// Styles and Other
import './styles.scss'

//------------------------------------------------------------------------------

class App extends Component {
  componentDidMount() {
    // Add the touch-screen flag to the <html> tag
    const touchScreen =
      !!("ontouchstart" in window) || window.navigator.msMaxTouchPoints > 0;
    if (touchScreen) {
      document.documentElement.classList.add("touch-screen");
    }

    setTimeout(() => {
      document.querySelector("#root").classList.toggle("show");
    }, 100); // add a fading effect on the inital loading
  }

  render() {

    const routePaths = {
      root: "/",
      home: "/home",
      team: "/team",
      partners: "/partners",
      whitepaper: "/whitepaper",
      faq: "/faq",
      about: "/about",
      map: "/map",
      admin: "/admin",
      thankyou: "/thank-you",
      page: "/page",
      signin: "/sign-in",
      signup: "/sign-up",
      change_password: "/change-password",
      forgot_password: "/forgot-password",
      sso_auth: "/sso_auth",

      whitepaper_intro: "/whitepaper/intro",
      whitepaper_why: "/whitepaper/why",
      whitepaper_faqs: "/whitepaper/faqs"
    }
    const standaloneMode = !inIFrame()

    return (
      <Router history={history}>
        <Fragment>
          {standaloneMode && <MainMenu />}
          <ScrollToTop>
            <Route exact path={routePaths.root} component={Home} />
            <Route exact path={routePaths.home} component={Home} />
            <Route exact path={routePaths.team} component={Team} />
            <Route exact path={routePaths.partners} component={Partners} />
            <Route exact path={routePaths.whitepaper} component={Whitepaper} />
            <Route exact path={routePaths.faq} component={Faq} />
            <Route exact path={routePaths.about} component={About} />
            <Route path={routePaths.map} component={Map_} />
            <Route exact path={routePaths.admin} render={props => <Admin {...props} />} />
            <Route exact path={routePaths.thankyou} component={CongratsModal} />
            <Route exact path={`${routePaths.page}/:id`} component={Page} />

            <Route exact path={routePaths.whitepaper_intro} component={WPIntro} />
            <Route exact path={routePaths.whitepaper_why} render={WPWhy} />
            <Route exact path={routePaths.whitepaper_faqs} render={WPFAQs} />

            <Route path="*" render={() => this.check404Route(Object.values(routePaths))} />
          </ScrollToTop>
        </Fragment>
      </Router>
    );
  }

  renderNewEvent = ({ location, history }) => {
    const { new: new_, edit } = qs.parse(location.search);
    const isOpen = Boolean(new_ === "1" || (edit === "1" && window.__editData));

    if (isOpen && !Meteor.userId()) {
      /*
      sessionStorage.setItem("redirect", "/?new=1");
      return <Redirect to="/sign-in" />;
      */
      alert('You need to login before you can create an event')
      return null
    }
    /*
    else if(!isOpen){
      return <Redirect to='/home' />
    }
    */
    console.log('passed in loc:\n', location)
    console.log('passed in hist:\n', history)
    return (
      <NewEventLoadable isOpen={isOpen} location={location} history={history} />
    );
  };

  /**
   * This function manages the 'catch-all' route, serving two purposes.
   * (1) open a model to create/edit event when there is the appropriate search string in the URL
   * (2) for all other routes not specified, it will redirect to a 404 page
   * Ideally we should be using React-router Switch to create a fallback 404 page...
   * But this would require opening the new event modal without using the URL as a hook
   * And this may break interactions with Docus (e.g. editing an event directly from the forum)
   */
  check404Route = (routes) => {
    if (window.location.search === '?new=1' || window.location.search === '?edit=1') {
      return this.renderNewEvent({ location: window.location, history })
    }
    if (!routes.some(e => e === window.location.pathname)
      && !window.location.pathname.includes('/page/')
      && !window.location.pathname.includes('reset-password')) {
        return <Error404 />
    }
    return null
  }
}

export default hot(module)(App);

//------------------------------------------------------------------------------

// Docuss

if (inIFrame()) {
  comToPlugin.connect({
    discourseOrigin: '*',
    timeout: 10000,
    onTimeout: () => console.log('Could not connect to the Docuss plugin')
  })

  // Set Docuss-generated topic to have pre-populated category
  comToPlugin.onDiscourseRoutePushed(({ route }) => {
    const topicCategory =
      route.pageName === 'm_about'? 'The About Page Discussion' :
      route.pageName === 'whitepaper'? 'Public Happiness Token' :
      route.pageName === 'wp_why'? 'Public Happiness Token' :
      route.pageName === 'wp_intro'? 'Public Happiness Token' :
      route.pageName === 'wp_faqs'? 'Public Happiness Token' :
      route.pageName === 'm_gather'? 'Hidden' :
      route.pageName === 'summit'? 'Projects: The Happier World Economies Summit' :
      'General Discussion'
    comToPlugin.postSetRouteProps({ category: topicCategory })
  })

}

const routeMatcher = new SimpleRouteMatcher({
  maxPageNameLength: websiteJSON.dcsTag.maxPageNameLength,
  forceLowercase: websiteJSON.dcsTag.forceLowercase,
  predefinedPageNames: websiteJSON.pages.map(p => ({
    pageName: p.name,
    pathname: p.url // This works because we know our urls are all relative urls, i.e. pathname = url
  })),
  otherPagesPrefix: websiteJSON.webApp.otherPagesPrefix
})

runReactRouterSync({ browserHistory: history, routeMatcher })

//------------------------------------------------------------------------------
<|endoftext|>


<commit_before>import BlackSail from './ship/black-sail-part';
import Back from './ship/back-part';
import Cannon from './ship/cannon-part';
import Front from './ship/front-part';
import Ship from './ship';

export default class PirateShip extends Ship {
    constructor(state) {
        super(state);
        this.parts = [
            new Front(state, {x: 4, y: 4}, {x: 3, y: 4}, {x: 5, y: 4}),
            new BlackSail(state, {x: 5, y: 4}, {x: 4, y: 4}, {x: 6, y: 4}),
            new Back(state, {x: 6, y: 4}, {x: 5, y: 4}, {x: 7, y: 4})
        ];
        this.direction = {x: -1, y: 0};
    }

    update() {
        if (!this.alive) {
            return;
        }

        this.animationStep = (this.animationStep + 1) % 16;
        if (this.animationStep !== 0) {
            return;
        }

        const collectedDebris = this.state.debris.find((debris) => {
            if (debris.position.x == this.parts[0].position.x && debris.position.y == this.parts[0].position.y) {
                debris.alive = false;
                return true;
            }
            return false;
        });

        this.move(!!collectedDebris);

        if (this.state.isOutOfBounds(this.parts[0].position)) {
            this.alive = false;
            return;
        }

        if (collectedDebris) {
            const newPart = this.parts.length == 3 || Math.random() < .5 ? Cannon : BlackSail;
            this.parts.splice(1, 0, new newPart(this.state, collectedDebris.position, this.parts[0].position, null));
        }

        this.parts.forEach((part) => {
            part.update();
        });
    }

    addOccupied(occupied) {
        for (const part of this.parts) {
            if (part.previous) {
                occupied.push(part.previous);
            }
        }
    }
}
<commit_msg>reduce likelyhood for spawning cannons<commit_after>import BlackSail from './ship/black-sail-part';
import Back from './ship/back-part';
import Cannon from './ship/cannon-part';
import Front from './ship/front-part';
import Ship from './ship';

export default class PirateShip extends Ship {
    constructor(state) {
        super(state);
        this.parts = [
            new Front(state, {x: 4, y: 4}, {x: 3, y: 4}, {x: 5, y: 4}),
            new BlackSail(state, {x: 5, y: 4}, {x: 4, y: 4}, {x: 6, y: 4}),
            new Back(state, {x: 6, y: 4}, {x: 5, y: 4}, {x: 7, y: 4})
        ];
        this.direction = {x: -1, y: 0};
    }

    update() {
        if (!this.alive) {
            return;
        }

        this.animationStep = (this.animationStep + 1) % 16;
        if (this.animationStep !== 0) {
            return;
        }

        const collectedDebris = this.state.debris.find((debris) => {
            if (debris.position.x == this.parts[0].position.x && debris.position.y == this.parts[0].position.y) {
                debris.alive = false;
                return true;
            }
            return false;
        });

        this.move(!!collectedDebris);

        if (this.state.isOutOfBounds(this.parts[0].position)) {
            this.alive = false;
            return;
        }

        if (collectedDebris) {
            const newPart = this.parts.length == 3 || Math.random() < .3 ? Cannon : BlackSail;
            this.parts.splice(1, 0, new newPart(this.state, collectedDebris.position, this.parts[0].position, null));
        }

        this.parts.forEach((part) => {
            part.update();
        });
    }

    addOccupied(occupied) {
        for (const part of this.parts) {
            if (part.previous) {
                occupied.push(part.previous);
            }
        }
    }
}
<|endoftext|>


<commit_before>
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Actions, ActionConst } from 'react-native-router-flux';
import { Container, Header, Title, Content, Button, Footer, FooterTab, Text, Body, Left, Right, Icon, Item, Input, Grid, Row, Col } from 'native-base';

import { View } from 'react-native';

import Menu, {
  MenuContext,
  MenuTrigger,
  MenuOptions,
  MenuOption,
  renderers
} from 'react-native-popup-menu';

import { openDrawer } from '../../actions/drawer';
import { loadUserGroups, clearGroupsInCache, loadBookmarks, resetBookmarks } from 'PLActions';
import styles from './styles';

// Tab Scenes
import Newsfeed from './newsfeed/'

const { SlideInMenu } = renderers;

class Home extends Component {

  static propTypes = {
    openDrawer: React.PropTypes.func,
  }

  constructor(props) {
    super(props);
    this.state = {
      tab1: true,
      tab2: false,
      tab3: false,
      tab4: false,
      group: 'all',
    };
  }

  // Newsfeed
  async onNewsfeedTab() {
    const { props: { token, bookmarksPage, dispatch, items } } = this;
    this.toggleTab1();
    try {
      if (bookmarksPage === 0) {
        await Promise.race([
          dispatch(loadBookmarks(token)),
          timeout(15000),
        ]);
      }
    } catch (e) {
      const message = e.message || e;
      if (message !== 'Timed out') {
        alert(message);
      }
      else {
        alert('Timed out. Please check internet connection');
      }
      dispatch(resetBookmarks());
      return;
    } finally {
      if (items.length === 0) {
        alert('No newsfeed yet');
      }
    }
  }

  toggleTab1() {
    this.setState({
      tab1: true,
      tab2: false,
      tab3: false,
      tab4: false,
    });
  }

  toggleTab2() {
    this.setState({
      tab1: false,
      tab2: true,
      tab3: false,
      tab4: false,
    });
  }

  toggleTab3() {
    this.setState({
      tab1: false,
      tab2: false,
      tab3: true,
      tab4: false,
    });
  }

  toggleTab4() {
    this.setState({
      tab1: false,
      tab2: false,
      tab3: false,
      tab4: true,
    });
  }

  selectGroup(group) {
    this.setState({ group: group });
  }

  selectNewItem(value) {
    this.bottomMenu.close();
  }

  onRef = r => {
    this.bottomMenu = r;
  }

  goToGroupSelector() {
    this.props.dispatch(clearGroupsInCache());
    Actions.groupSelector();
  }

  renderSelectedTab() {
    if (this.state.tab1 === true) {
      return (<Newsfeed />);
    } else {
      return null;
    }
  }

  render() {
    return (
      <MenuContext customStyles={menuContextStyles}>
        <Container>
          <Header searchBar rounded style={styles.header}>
            <Left style={{ flex: 0.1 }}>
              <Button transparent onPress={this.props.openDrawer}>
                <Icon active name="menu" style={{ color: 'white' }} />
              </Button>
            </Left>
            <Item style={styles.searchBar}>
              <Input style={styles.searchInput} placeholder="Search groups, people, topics" />
              <Icon active name="search" />
            </Item>
          </Header>
          <View style={styles.container}>
            <Grid style={styles.groupSelector}>
              <Row>
                <Col style={styles.col}>
                  <Button style={this.state.group == 'all' ? styles.iconActiveButton : styles.iconButton} onPress={() => this.selectGroup('all')}>
                    <Icon active name="walk" style={styles.icon} />
                  </Button>
                  <Text style={styles.iconText} onPress={() => this.selectGroup('all')}>All</Text>
                </Col>
                <Col style={styles.col}>
                  <Button style={this.state.group == 'town' ? styles.iconActiveButton : styles.iconButton} onPress={() => this.selectGroup('town')}>
                    <Icon active name="pin" style={styles.icon} />
                  </Button>
                  <Text style={styles.iconText} onPress={() => this.selectGroup('town')}>Town</Text>
                </Col>
                <Col style={styles.col}>
                  <Button style={this.state.group == 'state' ? styles.iconActiveButton : styles.iconButton} onPress={() => this.selectGroup('state')}>
                    <Icon active name="pin" style={styles.icon} />
                  </Button>
                  <Text style={styles.iconText} onPress={() => this.selectGroup('state')}>State</Text>
                </Col>
                <Col style={styles.col}>
                  <Button style={this.state.group == 'country' ? styles.iconActiveButton : styles.iconButton} onPress={() => this.selectGroup('country')}>
                    <Icon active name="pin" style={styles.icon} />
                  </Button>
                  <Text style={styles.iconText} onPress={() => this.selectGroup('country')}>Country</Text>
                </Col>
                <Col style={styles.col}>
                  <Button style={styles.iconButton} onPress={() => this.goToGroupSelector()}>
                    <Icon active name="more" style={styles.icon} />
                  </Button>
                  <Text style={styles.iconText} onPress={() => this.goToGroupSelector()}>More</Text>
                </Col>
              </Row>
            </Grid>
            {this.renderSelectedTab()}
          </View>

          <Footer style={styles.footer}>
            <FooterTab>
              <Button active={this.state.tab1} onPress={() => this.onNewsfeedTab()} >
                <Icon active={this.state.tab1} name="ios-flash" />
                <Text>Newsfeed</Text>
              </Button>
              <Button active={this.state.tab2} onPress={() => this.toggleTab2()} >
                <Icon active={this.state.tab2} name="md-people" />
                <Text>Friends</Text>
              </Button>
              <Button>
                <Menu name="create_item" renderer={SlideInMenu} onSelect={value => this.selectNewItem(value)} ref={this.onRef}>
                  <MenuTrigger>
                    <Icon name="ios-add-circle" style={{ fontSize: 36, color: '#030366' }} />
                  </MenuTrigger>
                  <MenuOptions customStyles={optionsStyles}>
                    <MenuOption value={'group_announcement'}>
                      <Button iconLeft transparent dark onPress={() => this.selectNewItem('group_announcement')}>
                        <Icon name="volume-up" style={styles.menuIcon} />
                        <Text style={styles.menuText}>Create New Group Announcement</Text>
                      </Button>
                    </MenuOption>
                    <MenuOption value={'group_fundraiser'}>
                      <Button iconLeft transparent dark onPress={() => this.selectNewItem('group_fundraiser')}>
                        <Icon name="cash" style={styles.menuIcon} />
                        <Text style={styles.menuText}>Create New Group Fundraiser</Text>
                      </Button>
                    </MenuOption>
                    <MenuOption value={'group_event'}>
                      <Button iconLeft transparent dark onPress={() => this.selectNewItem('group_event')}>
                        <Icon name="calendar" style={styles.menuIcon} />
                        <Text style={styles.menuText}>Create New Group Event</Text>
                      </Button>
                    </MenuOption>
                    <MenuOption value={'group_petition'}>
                      <Button iconLeft transparent dark onPress={() => this.selectNewItem('group_petition')}>
                        <Icon name="create" style={styles.menuIcon} />
                        <Text style={styles.menuText}>Create New Group Petition</Text>
                      </Button>
                    </MenuOption>
                    <MenuOption value={'group_discussion'}>
                      <Button iconLeft transparent dark onPress={() => this.selectNewItem('group_discussion')}>
                        <Icon name="chatbubbles" style={styles.menuIcon} />
                        <Text style={styles.menuText}>Create New Group Discussion</Text>
                      </Button>
                    </MenuOption>
                    <MenuOption value={'group_poll'}>
                      <Button iconLeft transparent dark onPress={() => this.selectNewItem('group_poll')}>
                        <Icon name="stats" style={styles.menuIcon} />
                        <Text style={styles.menuText}>Create New Group Poll</Text>
                      </Button>
                    </MenuOption>
                    <MenuOption value={'petition'}>
                      <Button iconLeft transparent dark onPress={() => this.selectNewItem('petition')}>
                        <Icon name="create" style={styles.menuIcon} />
                        <Text style={styles.menuText}>Create New Petition</Text>
                      </Button>
                    </MenuOption>
                    <MenuOption value={'post'}>
                      <Button iconLeft transparent dark onPress={() => this.selectNewItem('post')}>
                        <Icon name="flag" style={styles.menuIcon} />
                        <Text style={styles.menuText}>Create New Post</Text>
                      </Button>
                    </MenuOption>
                  </MenuOptions>
                </Menu>
              </Button>
              <Button active={this.state.tab3} onPress={() => this.toggleTab3()} >
                <Icon active={this.state.tab3} name="md-mail" />
                <Text>Messages</Text>
              </Button>
              <Button active={this.state.tab4} onPress={() => this.toggleTab4()} >
                <Icon active={this.state.tab4} name="md-notifications" />
                <Text>Notifications</Text>
              </Button>
            </FooterTab>
          </Footer>
        </Container>
      </MenuContext >
    );
  }
}

const optionsStyles = {
  optionsContainer: {
    backgroundColor: '#fafafa',
    paddingLeft: 5,
  },
};

const menuContextStyles = {
  menuContextWrapper: styles.container,
  backdrop: styles.backdrop,
};

function bindAction(dispatch) {
  return {
    openDrawer: () => dispatch(openDrawer()),
  };
}

async function timeout(ms: number): Promise {
  return new Promise((resolve, reject) => {
    setTimeout(() => reject(new Error('Timed out')), ms);
  });
}

const mapStateToProps = state => ({
  token: state.user.token,
  bookmarksPage: state.bookmarks.page,
});

export default connect(mapStateToProps, bindAction)(Home);
<commit_msg>issue #13 - update home component  * just open newsfeed tab without pre-loading<commit_after>
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Actions, ActionConst } from 'react-native-router-flux';
import { Container, Header, Title, Content, Button, Footer, FooterTab, Text, Body, Left, Right, Icon, Item, Input, Grid, Row, Col } from 'native-base';

import { View } from 'react-native';

import Menu, {
  MenuContext,
  MenuTrigger,
  MenuOptions,
  MenuOption,
  renderers
} from 'react-native-popup-menu';

import { openDrawer } from '../../actions/drawer';
import { loadUserGroups, clearGroupsInCache, loadBookmarks, resetBookmarks } from 'PLActions';
import styles from './styles';

// Tab Scenes
import Newsfeed from './newsfeed/'

const { SlideInMenu } = renderers;

class Home extends Component {

  static propTypes = {
    openDrawer: React.PropTypes.func,
  }

  constructor(props) {
    super(props);
    this.state = {
      tab1: true,
      tab2: false,
      tab3: false,
      tab4: false,
      group: 'all',
    };
  }

  // Newsfeed Tab
  toggleTab1() {
    this.setState({
      tab1: true,
      tab2: false,
      tab3: false,
      tab4: false,
    });
  }

  // Friends Tab
  toggleTab2() {
    this.setState({
      tab1: false,
      tab2: true,
      tab3: false,
      tab4: false,
    });
  }

  // Messages Tab
  toggleTab3() {
    this.setState({
      tab1: false,
      tab2: false,
      tab3: true,
      tab4: false,
    });
  }

  // Notifications Tab
  toggleTab4() {
    this.setState({
      tab1: false,
      tab2: false,
      tab3: false,
      tab4: true,
    });
  }

  selectGroup(group) {
    this.setState({ group: group });
  }

  selectNewItem(value) {
    this.bottomMenu.close();
  }

  onRef = r => {
    this.bottomMenu = r;
  }

  goToGroupSelector() {
    Actions.groupSelector();
  }

  renderSelectedTab() {
    if (this.state.tab1 === true) {
      return (<Newsfeed />);
    } else {
      return null;
    }
  }

  render() {
    return (
      <MenuContext customStyles={menuContextStyles}>
        <Container>
          <Header searchBar rounded style={styles.header}>
            <Left style={{ flex: 0.1 }}>
              <Button transparent onPress={this.props.openDrawer}>
                <Icon active name="menu" style={{ color: 'white' }} />
              </Button>
            </Left>
            <Item style={styles.searchBar}>
              <Input style={styles.searchInput} placeholder="Search groups, people, topics" />
              <Icon active name="search" />
            </Item>
          </Header>
          <View style={styles.container}>
            <Grid style={styles.groupSelector}>
              <Row>
                <Col style={styles.col}>
                  <Button style={this.state.group == 'all' ? styles.iconActiveButton : styles.iconButton} onPress={() => this.selectGroup('all')}>
                    <Icon active name="walk" style={styles.icon} />
                  </Button>
                  <Text style={styles.iconText} onPress={() => this.selectGroup('all')}>All</Text>
                </Col>
                <Col style={styles.col}>
                  <Button style={this.state.group == 'town' ? styles.iconActiveButton : styles.iconButton} onPress={() => this.selectGroup('town')}>
                    <Icon active name="pin" style={styles.icon} />
                  </Button>
                  <Text style={styles.iconText} onPress={() => this.selectGroup('town')}>Town</Text>
                </Col>
                <Col style={styles.col}>
                  <Button style={this.state.group == 'state' ? styles.iconActiveButton : styles.iconButton} onPress={() => this.selectGroup('state')}>
                    <Icon active name="pin" style={styles.icon} />
                  </Button>
                  <Text style={styles.iconText} onPress={() => this.selectGroup('state')}>State</Text>
                </Col>
                <Col style={styles.col}>
                  <Button style={this.state.group == 'country' ? styles.iconActiveButton : styles.iconButton} onPress={() => this.selectGroup('country')}>
                    <Icon active name="pin" style={styles.icon} />
                  </Button>
                  <Text style={styles.iconText} onPress={() => this.selectGroup('country')}>Country</Text>
                </Col>
                <Col style={styles.col}>
                  <Button style={styles.iconButton} onPress={() => this.goToGroupSelector()}>
                    <Icon active name="more" style={styles.icon} />
                  </Button>
                  <Text style={styles.iconText} onPress={() => this.goToGroupSelector()}>More</Text>
                </Col>
              </Row>
            </Grid>
            {this.renderSelectedTab()}
          </View>

          <Footer style={styles.footer}>
            <FooterTab>
              <Button active={this.state.tab1} onPress={() => this.toggleTab1()} >
                <Icon active={this.state.tab1} name="ios-flash" />
                <Text>Newsfeed</Text>
              </Button>
              <Button active={this.state.tab2} onPress={() => this.toggleTab2()} >
                <Icon active={this.state.tab2} name="md-people" />
                <Text>Friends</Text>
              </Button>
              <Button>
                <Menu name="create_item" renderer={SlideInMenu} onSelect={value => this.selectNewItem(value)} ref={this.onRef}>
                  <MenuTrigger>
                    <Icon name="ios-add-circle" style={{ fontSize: 36, color: '#030366' }} />
                  </MenuTrigger>
                  <MenuOptions customStyles={optionsStyles}>
                    <MenuOption value={'group_announcement'}>
                      <Button iconLeft transparent dark onPress={() => this.selectNewItem('group_announcement')}>
                        <Icon name="volume-up" style={styles.menuIcon} />
                        <Text style={styles.menuText}>Create New Group Announcement</Text>
                      </Button>
                    </MenuOption>
                    <MenuOption value={'group_fundraiser'}>
                      <Button iconLeft transparent dark onPress={() => this.selectNewItem('group_fundraiser')}>
                        <Icon name="cash" style={styles.menuIcon} />
                        <Text style={styles.menuText}>Create New Group Fundraiser</Text>
                      </Button>
                    </MenuOption>
                    <MenuOption value={'group_event'}>
                      <Button iconLeft transparent dark onPress={() => this.selectNewItem('group_event')}>
                        <Icon name="calendar" style={styles.menuIcon} />
                        <Text style={styles.menuText}>Create New Group Event</Text>
                      </Button>
                    </MenuOption>
                    <MenuOption value={'group_petition'}>
                      <Button iconLeft transparent dark onPress={() => this.selectNewItem('group_petition')}>
                        <Icon name="create" style={styles.menuIcon} />
                        <Text style={styles.menuText}>Create New Group Petition</Text>
                      </Button>
                    </MenuOption>
                    <MenuOption value={'group_discussion'}>
                      <Button iconLeft transparent dark onPress={() => this.selectNewItem('group_discussion')}>
                        <Icon name="chatbubbles" style={styles.menuIcon} />
                        <Text style={styles.menuText}>Create New Group Discussion</Text>
                      </Button>
                    </MenuOption>
                    <MenuOption value={'group_poll'}>
                      <Button iconLeft transparent dark onPress={() => this.selectNewItem('group_poll')}>
                        <Icon name="stats" style={styles.menuIcon} />
                        <Text style={styles.menuText}>Create New Group Poll</Text>
                      </Button>
                    </MenuOption>
                    <MenuOption value={'petition'}>
                      <Button iconLeft transparent dark onPress={() => this.selectNewItem('petition')}>
                        <Icon name="create" style={styles.menuIcon} />
                        <Text style={styles.menuText}>Create New Petition</Text>
                      </Button>
                    </MenuOption>
                    <MenuOption value={'post'}>
                      <Button iconLeft transparent dark onPress={() => this.selectNewItem('post')}>
                        <Icon name="flag" style={styles.menuIcon} />
                        <Text style={styles.menuText}>Create New Post</Text>
                      </Button>
                    </MenuOption>
                  </MenuOptions>
                </Menu>
              </Button>
              <Button active={this.state.tab3} onPress={() => this.toggleTab3()} >
                <Icon active={this.state.tab3} name="md-mail" />
                <Text>Messages</Text>
              </Button>
              <Button active={this.state.tab4} onPress={() => this.toggleTab4()} >
                <Icon active={this.state.tab4} name="md-notifications" />
                <Text>Notifications</Text>
              </Button>
            </FooterTab>
          </Footer>
        </Container>
      </MenuContext >
    );
  }
}

const optionsStyles = {
  optionsContainer: {
    backgroundColor: '#fafafa',
    paddingLeft: 5,
  },
};

const menuContextStyles = {
  menuContextWrapper: styles.container,
  backdrop: styles.backdrop,
};

function bindAction(dispatch) {
  return {
    openDrawer: () => dispatch(openDrawer()),
  };
}

async function timeout(ms: number): Promise {
  return new Promise((resolve, reject) => {
    setTimeout(() => reject(new Error('Timed out')), ms);
  });
}

const mapStateToProps = state => ({
  token: state.user.token,
  bookmarksPage: state.bookmarks.page,
});

export default connect(mapStateToProps, bindAction)(Home);
<|endoftext|>


<commit_before>(function (Module, NodeBB) {
    'use strict';

    Module.exports = {
        adminSockets : NodeBB.require('./src/socket.io/admin').plugins,
        cache        : NodeBB.require('./src/posts/cache'),
        db           : NodeBB.require('./src/database'),
        emitter      : NodeBB.require('./src/emitter'),
        groups       : NodeBB.require('./src/groups'),
        meta         : NodeBB.require('./src/meta'),
        pluginSockets: NodeBB.require('./src/socket.io/plugins'),
        postTools    : NodeBB.require('./src/posts/tools'),
        serverSockets: NodeBB.require('./src/socket.io').server.sockets,
        settings     : NodeBB.require('./src/settings'),
        socketIndex  : NodeBB.require('./src/socket.io/index'),
        topics       : NodeBB.require('./src/topics'),
        user         : NodeBB.require('./src/user'),

        utils  : NodeBB.require('./public/src/utils'),
        helpers: NodeBB.require('./src/controllers/helpers'),

        /**
         * List is incomplete
         *
         * base_dir: '/path/to/NodeBB',
         * themes_path: '/path/to/NodeBB/node_modules',
         * views_dir: '/path/to/NodeBB/public/templates',
         * version: 'NodeBB Version',
         * url: 'http://localhost:4567',
         * core_templates_path: '/path/to/NodeBB/src/views',
         * base_templates_path: '/path/to/NodeBB/node_modules/nodebb-theme-vanilla/templates',
         * upload_path: '/public/uploads',
         * relative_path: '',
         * port: '4567',
         * upload_url: '/uploads/',
         * theme_templates_path: '/path/to/NodeBB/node_modules/nodebb-theme-lavender/templates',
         * theme_config: '/path/to/NodeBB/node_modules/nodebb-theme-lavender/theme.json',
         * NODE_ENV: 'development'
         */
        nconf   : NodeBB.require('nconf'),
        passport: NodeBB.require('passport'),
        express : NodeBB.require('express')
    };
})(module, require.main);<commit_msg>remove emitter<commit_after>(function (Module, NodeBB) {
    'use strict';

    Module.exports = {
        adminSockets : NodeBB.require('./src/socket.io/admin').plugins,
        cache        : NodeBB.require('./src/posts/cache'),
        db           : NodeBB.require('./src/database'),
        groups       : NodeBB.require('./src/groups'),
        meta         : NodeBB.require('./src/meta'),
        pluginSockets: NodeBB.require('./src/socket.io/plugins'),
        postTools    : NodeBB.require('./src/posts/tools'),
        serverSockets: NodeBB.require('./src/socket.io').server.sockets,
        settings     : NodeBB.require('./src/settings'),
        socketIndex  : NodeBB.require('./src/socket.io/index'),
        topics       : NodeBB.require('./src/topics'),
        user         : NodeBB.require('./src/user'),

        utils  : NodeBB.require('./public/src/utils'),
        helpers: NodeBB.require('./src/controllers/helpers'),

        /**
         * List is incomplete
         *
         * base_dir: '/path/to/NodeBB',
         * themes_path: '/path/to/NodeBB/node_modules',
         * views_dir: '/path/to/NodeBB/public/templates',
         * version: 'NodeBB Version',
         * url: 'http://localhost:4567',
         * core_templates_path: '/path/to/NodeBB/src/views',
         * base_templates_path: '/path/to/NodeBB/node_modules/nodebb-theme-vanilla/templates',
         * upload_path: '/public/uploads',
         * relative_path: '',
         * port: '4567',
         * upload_url: '/uploads/',
         * theme_templates_path: '/path/to/NodeBB/node_modules/nodebb-theme-lavender/templates',
         * theme_config: '/path/to/NodeBB/node_modules/nodebb-theme-lavender/theme.json',
         * NODE_ENV: 'development'
         */
        nconf   : NodeBB.require('nconf'),
        passport: NodeBB.require('passport'),
        express : NodeBB.require('express')
    };
})(module, require.main);
<|endoftext|>


<commit_before>"use strict";

const assert = require("assert");
let namespace;
let ibsPropertyName = "isBlockScoped";
let types;
let cache;

function tryScopedLibDirect() {
  namespace = require("@babel/types/lib/validators/isBlockScoped");

  // If the above import succeeded, then we should replace the .default
  // property of the isBlockScoped module, instead of .isBlockScoped.
  ibsPropertyName = "default";

  types = types || require("@babel/types");
  cache = cache || require("@babel/traverse").default.cache;
}

function tryScoped() {
  namespace = require("@babel/types");
  types = types || require("@babel/types");
  cache = cache || require("@babel/traverse").default.cache;
}

function tryScopedLib() {
  namespace = require("@babel/types/lib/validators");
  types = types || require("@babel/types");
  cache = cache || require("@babel/traverse").default.cache;
}

function tryUnscoped() {
  namespace = require("babel-types/lib/validators");
  types = types || require("babel-types");
  cache = cache || require("babel-traverse").default.cache;
}

[tryScopedLibDirect,
 tryScoped,
 tryScopedLib,
 tryUnscoped
].some(function (fn) {
  try {
    fn();
  } catch (e) {
    return false;
  }

  const wrapped = namespace[ibsPropertyName];
  assert.strictEqual(typeof wrapped, "function")

  // Allow types.isBlockScoped to return true for import-related nodes.
  const wrapper = namespace[ibsPropertyName] = function (node) {
    return node &&
      types.isImportDeclaration(node) ||
      wrapped.apply(this, arguments);
  };

  // The wrapping can fail if namespace[ibsPropertyName] is a non-writable
  // property (such as a getter function).
  if (namespace[ibsPropertyName] !== wrapper) {
    throw new Error(
      "Unable to patch @babel/types isBlockScoped function"
    );
  }

  return true;
});

module.exports = function (context) {
  const compiler = require("../lib/compiler.js");
  const transformOptions = {
    parse: require("../lib/parsers/babel.js").parse
  };

  function transform(node) {
    const result = compiler.transform(node, transformOptions);
    if (! result.identical) {
      // If the Reify compiler made any changes, invalidate all existing
      // Scope objects, so that any variable binding changes made by
      // compiler.transform will be reflected accurately.
      cache.clearScope();
    }
    return result;
  }

  return {
    visitor: {
      Program: {
        enter(path) {
          const code = path.hub.file.code;
          if (typeof code === "string") {
            transformOptions.moduleAlias =
              compiler.makeUniqueId("module", code);
          }
          Object.assign(transformOptions, this.opts);
          transform(path.node);
        },

        exit(path) {
          const ast = transform(path.node).ast;
          assert.strictEqual(ast.type, "Program");

          ast.body = [
            types.callExpression(
              types.memberExpression(
                types.parenthesizedExpression(
                  types.functionExpression(
                    null,
                    [types.identifier(transformOptions.moduleAlias)],
                    types.blockStatement(ast.body)
                  )
                ),
                types.identifier("call")
              ),
              [
                types.thisExpression(),
                types.identifier("module"),
              ]
            )
          ];
        }
      }
    }
  };
};
<commit_msg>Wrap module body with IIFE only if options.moduleAlias !== "module".<commit_after>"use strict";

const assert = require("assert");
let namespace;
let ibsPropertyName = "isBlockScoped";
let types;
let cache;

function tryScopedLibDirect() {
  namespace = require("@babel/types/lib/validators/isBlockScoped");

  // If the above import succeeded, then we should replace the .default
  // property of the isBlockScoped module, instead of .isBlockScoped.
  ibsPropertyName = "default";

  types = types || require("@babel/types");
  cache = cache || require("@babel/traverse").default.cache;
}

function tryScoped() {
  namespace = require("@babel/types");
  types = types || require("@babel/types");
  cache = cache || require("@babel/traverse").default.cache;
}

function tryScopedLib() {
  namespace = require("@babel/types/lib/validators");
  types = types || require("@babel/types");
  cache = cache || require("@babel/traverse").default.cache;
}

function tryUnscoped() {
  namespace = require("babel-types/lib/validators");
  types = types || require("babel-types");
  cache = cache || require("babel-traverse").default.cache;
}

[tryScopedLibDirect,
 tryScoped,
 tryScopedLib,
 tryUnscoped
].some(function (fn) {
  try {
    fn();
  } catch (e) {
    return false;
  }

  const wrapped = namespace[ibsPropertyName];
  assert.strictEqual(typeof wrapped, "function")

  // Allow types.isBlockScoped to return true for import-related nodes.
  const wrapper = namespace[ibsPropertyName] = function (node) {
    return node &&
      types.isImportDeclaration(node) ||
      wrapped.apply(this, arguments);
  };

  // The wrapping can fail if namespace[ibsPropertyName] is a non-writable
  // property (such as a getter function).
  if (namespace[ibsPropertyName] !== wrapper) {
    throw new Error(
      "Unable to patch @babel/types isBlockScoped function"
    );
  }

  return true;
});

module.exports = function (context) {
  const compiler = require("../lib/compiler.js");
  const transformOptions = {
    parse: require("../lib/parsers/babel.js").parse
  };

  let madeChanges = false;
  function transform(node) {
    const result = compiler.transform(node, transformOptions);
    if (! result.identical) {
      madeChanges = true;
      // If the Reify compiler made any changes, invalidate all existing
      // Scope objects, so that any variable binding changes made by
      // compiler.transform will be reflected accurately.
      cache.clearScope();
    }
    return result;
  }

  return {
    visitor: {
      Program: {
        enter(path) {
          const code = path.hub.file.code;
          if (typeof code === "string") {
            transformOptions.moduleAlias =
              compiler.makeUniqueId("module", code);
          }
          Object.assign(transformOptions, this.opts);
          transform(path.node);
        },

        exit(path) {
          const ast = transform(path.node).ast;
          assert.strictEqual(ast.type, "Program");

          if (! madeChanges || transformOptions.moduleAlias === "module") {
            return;
          }

          // If we need to rename the module identifier to the value of
          // transformOptions.moduleAlias, we wrap the module body with an
          // immediately invoked function expression.
          ast.body = [
            types.callExpression(
              types.memberExpression(
                types.parenthesizedExpression(
                  types.functionExpression(
                    null,
                    [types.identifier(transformOptions.moduleAlias)],
                    types.blockStatement(ast.body)
                  )
                ),
                types.identifier("call")
              ),
              [
                types.thisExpression(),
                types.identifier("module"),
              ]
            )
          ];
        }
      }
    }
  };
};
<|endoftext|>


<commit_before>var hoverZoomPlugins = hoverZoomPlugins || [];
hoverZoomPlugins.push({
    name:'Pixiv',
    prepareImgLinks:function (callback) {
        var res = [],
            filter = 'a img[src*="pixiv.net/img"]',
            search = [/_(\d+(ms)?|\d+x\d+)\./, '/mobile/'];
        hoverZoom.urlReplace(res, filter, search, ['_m.', '/']);
        if (options.showHighRes) {
            hoverZoom.urlReplace(res, filter, search, ['.', '/']);
        }
        hoverZoom.urlReplace(res, 'a img[src*="pixiv.net/profile/"]', search, ['.', '/']);
        callback($(res));

        $('a[href*="member_illust.php"]').on('mouseover', function() {
            var link = $(this);
            if (link.data().hoverZoomSrc) return;
            $.get(link.attr('href'), function (data) {
                if (link.data().hoverZoomSrc) return;
                try {
                    // extract JSON data from embedded script
                    let idx = data.indexOf('{"illustId"');
                    if (idx < 0) return;
                    let idx2 = data.indexOf('},user:', idx);
                    if (idx2 < 0) return;
                    let json = JSON.parse(data.slice(idx, idx2));
                    let src;
                    if (options.showHighRes)
                        src = json.urls.original;
                    else
                        src = json.urls.regular;
                    hoverZoom.prepareLink(link, src);
                } catch (e) {
                    cLog('Pixiv has probably changed JSON format.');
                }
            });
        });
    }
});
<commit_msg>Gallery support pixiv<commit_after>var hoverZoomPlugins = hoverZoomPlugins || [];
hoverZoomPlugins.push({
    name: 'Pixiv',
    prepareImgLinks: function (callback) {
        var res = [],
            filter = 'a img[src*="pixiv.net/img"]',
            search = [/_(\d+(ms)?|\d+x\d+)\./, '/mobile/'];
        hoverZoom.urlReplace(res, filter, search, ['_m.', '/']);
        if (options.showHighRes) {
            hoverZoom.urlReplace(res, filter, search, ['.', '/']);
        }
        hoverZoom.urlReplace(res, 'a img[src*="pixiv.net/profile/"]', search, ['.', '/']);
        callback($(res));

        $('a[href*="member_illust.php"]').on('mouseover', function () {
            var link = $(this);
            if (link.data().hoverZoomSrc) return;
            $.get(link.attr('href'), function (data) {
                if (link.data().hoverZoomSrc) return;
                try {
                    // extract JSON data from embedded script
                    let idx = data.indexOf('{"illustId"');
                    if (idx < 0) return;
                    let idx2 = data.indexOf('},user:', idx);
                    if (idx2 < 0) return;
                    let json = JSON.parse(data.slice(idx, idx2));
                    let imgCount = json.pageCount;
                    if (imgCount != 1)
                        galleryView(link, link.attr('href').replace("=medium", "=manga"), imgCount);
                    else {
                        if (options.showHighRes)
                            src = json.urls.original;
                        else
                            src = json.urls.regular;
                        hoverZoom.prepareLink(link, src);
                    }
                } catch (e) {
                    cLog('Pixiv has probably changed JSON format.');
                }
            });
        });

        function galleryView(link, href, imgCount) {
            let linkData = link.data();
            linkData.hoverZoomGallerySrc = [];
            linkData.hoverZoomGalleryCaption = [];
            $.get(href, function (data) {
                if (link.data().hoverZoomSrc) return;
                try {
                    for (let i = 0; i < imgCount; i++) {
                        let idxStartStrign = 'pixiv.context.images[' + i + '] = "';
                        let idx = data.indexOf(idxStartStrign) + idxStartStrign.length;
                        let idx2 = data.indexOf('";pixiv.context.thumbnailImages[' + i + ']');
                        let url = data.slice(idx, idx2).replace(/\\/g, '');
                        let urls = [url], caption = '';
                        linkData.hoverZoomGalleryCaption.push(i);
                        linkData.hoverZoomGallerySrc.push(urls);
                        linkData.hoverZoomSrc = undefined;
                    }
                } catch (e) {
                    cLog('Pixiv has probably changed HTML code for where galleries are');
                }
                callback($([link]));
            });
        }
    }
});<|endoftext|>