<commit_before>var trivia = {
  tagline: null,
  index: [],
  randomTrivia: [
    "The word \"trivia\" comes from the Latin word \"trivium\", meaning a meeting of three roads.",
    "In the Middle Ages the \"trivium\" meant the curriculum of study comprising grammar, logic, and rhetoric.",
    "Oedipus killed his father at a trivium, a meeting of three roads. He later defeated the Sphinx in a trivia contest and saved the city of Thebes! Then he married his mother.",
    "The planet Jupiter is full of hot gas. So is your mom.",
    "Dueling is legal in Paraguay as long as both parties are registered blood donors.",
    "An ostrich\'s eye is bigger than its brain. Its brain is bigger than yours.",
    "The microwave oven was invented by mistake when an engineer testing a magnetron tube noticed that the radiation from it melted the chocolate bar he had in his pocket. He cried like a baby over the chocolate until he realized the commercial potential.",
    "Armadillos can be housebroken. Houses can\'t be armadillobroken.",
    "Recycling one glass jar saves enough energy to watch TV for 3 hours, but you should still read a book instead.",
    "Chewing gum while peeling onions will keep you from crying, unless you\'re thinking about your dead childhood puppy.",
    "In a survey, married men revealed that they change their underwear twice as often as single men: so, about once a week.",
    "\"Stewardesses\" is the longest word that is typed with only the left hand, even though it\'s sexist.",
    "The ancient Code of Hammurabi decreed that bartenders who watered down beer would be executed; bartenders responded by inventing the fruity cocktail.",
    "The American Psychiatric Asocial classifies careen withdrawal as a mental disorder, because obviously anyone who stops drinking coffee is nuts.",
    "The muppet Elmo is the only non-human to have testified before Congress. He was forced to admit under oath that he is insufferably annoying.",
    "The most shoplifted food item in the U.S. is candy; in Europe, it\'s cheese. Consequently European prisoners have better teeth but worse breath.",
    "Your cat does not really love you. He\'s just using you.",
    "Alaska is 75 times larger than New Jersey, yet has only 1/75 as many jerks.",
    "Trivia is about trivialities, while the trivium is about the most essential things. All the boring stuff goes in the quadrivium.",
    "British aphorist Logan Pearsall Smith published a book called \"Trivialities, bits of information of little consequence\". This appears to be the origin of the modern sense of \"trivia\".",
    "Famous expert in the trivium of liberal arts, Charles Van Doren, was involved in a major cheating scandal over his success on a television trivia quiz show.",
    "In English the days of the week are named after Norse gods, except for Saturday and Sunday. The first eight months are named after Roman gods, including two emperors; the rest are just numbers.",
    "Nobody likes clowns",
    "Mark Twain was born and died under two successive appearances of Halley\’s Comet. He once said \"Get your facts first, then you can distort them as you please\", which is the motto of this trivia feature!",
    "Most fortune cookies contain bromides and truisms, not fortunes.",
    "Many sayings are falsely attributed to Confucius. \"Never eat yellow snow\" is genuine, however.",
    "The difference between an aphorism and an apothegm is that you\'ve heard of one and not the other.",
    "There are no stupid questions, only stupid people.",
    "Back when people respected learning, trivia was called lore.",
    "Most people agree that the greatest sporting event of all time was when Rocky Balboa defeated Apollo Creed. Those people can\'t distinguish between fiction and reality.",
    "The first marathon was run by Pheidippides, a messenger bringing to Athens the news of the Battle of Marathon. When he had announced the Greek victory, he collapsed and died.",
    "The wheel was invented by Ughg, a caveman famous for dinosaur-riding. He also invented fire and Cheez-Its.",
    "Elephant seals can hold their breath for 100 minutes, and are not really elephants.",
    "The average adult human brain has about 100 billion brain cells, with 100 trillion connections between them, but most people only use four or five.",
    "According to Google CEO Eric Shmidt, every two days humanity now creates as much information as we did from the dawn of civilization until 2003. On an unrelated note, Sturgeon\'s Law states that 90% of everything is crap.",
    "Dogs were promoted to Man\'s Best Friend after the previous best friend caused that unfortunate incident in Vegas. You know the one."
    ];

  buildIndex: function () {
    for (var i = 1; i < trivia.randomTrivia.length; i++) {
      trivia.index.push(i);
    }
    trivia.shuffle(trivia.index);
    trivia.index.push('0');
  },

  shuffle: function (array) {
    var m = array.length, t, i;
    while (m) {
      i = Math.floor(Math.random() * m--);
      // console.log('i = ' + i);
      t = array[m];
      array[m] = array[i];
      array[i] = t;
    }
    return array;
  },

  setStoredIndex: function() {
    localStorage.index = JSON.stringify(trivia.index);
  },

  getStoredIndex: function() {
    if (localStorage.shuffledIndex) {
      trivia.index = JSON.parse(localStorage.index);
    } else {
      trivia.buildIndex();
    }
  },

  randomFact: function () {
    if (localStorage.index) {
      trivia.index = JSON.parse(localStorage.index);
    }
    if (trivia.index.length === 0) {
      trivia.buildIndex();
    }
    trivia.tagline = document.getElementById("tagline");
    trivia.tagline.textContent = trivia.randomTrivia[trivia.index.pop()];
    localStorage.index = JSON.stringify(trivia.index);
  },
}

trivia.randomFact();

<commit_msg>Fixed an errant semicolon that came in with the merge.<commit_after>var trivia = {
  tagline: null,
  index: [],
  randomTrivia: [
    "The word \"trivia\" comes from the Latin word \"trivium\", meaning a meeting of three roads.",
    "In the Middle Ages the \"trivium\" meant the curriculum of study comprising grammar, logic, and rhetoric.",
    "Oedipus killed his father at a trivium, a meeting of three roads. He later defeated the Sphinx in a trivia contest and saved the city of Thebes! Then he married his mother.",
    "The planet Jupiter is full of hot gas. So is your mom.",
    "Dueling is legal in Paraguay as long as both parties are registered blood donors.",
    "An ostrich\'s eye is bigger than its brain. Its brain is bigger than yours.",
    "The microwave oven was invented by mistake when an engineer testing a magnetron tube noticed that the radiation from it melted the chocolate bar he had in his pocket. He cried like a baby over the chocolate until he realized the commercial potential.",
    "Armadillos can be housebroken. Houses can\'t be armadillobroken.",
    "Recycling one glass jar saves enough energy to watch TV for 3 hours, but you should still read a book instead.",
    "Chewing gum while peeling onions will keep you from crying, unless you\'re thinking about your dead childhood puppy.",
    "In a survey, married men revealed that they change their underwear twice as often as single men: so, about once a week.",
    "\"Stewardesses\" is the longest word that is typed with only the left hand, even though it\'s sexist.",
    "The ancient Code of Hammurabi decreed that bartenders who watered down beer would be executed; bartenders responded by inventing the fruity cocktail.",
    "The American Psychiatric Asocial classifies careen withdrawal as a mental disorder, because obviously anyone who stops drinking coffee is nuts.",
    "The muppet Elmo is the only non-human to have testified before Congress. He was forced to admit under oath that he is insufferably annoying.",
    "The most shoplifted food item in the U.S. is candy; in Europe, it\'s cheese. Consequently European prisoners have better teeth but worse breath.",
    "Your cat does not really love you. He\'s just using you.",
    "Alaska is 75 times larger than New Jersey, yet has only 1/75 as many jerks.",
    "Trivia is about trivialities, while the trivium is about the most essential things. All the boring stuff goes in the quadrivium.",
    "British aphorist Logan Pearsall Smith published a book called \"Trivialities, bits of information of little consequence\". This appears to be the origin of the modern sense of \"trivia\".",
    "Famous expert in the trivium of liberal arts, Charles Van Doren, was involved in a major cheating scandal over his success on a television trivia quiz show.",
    "In English the days of the week are named after Norse gods, except for Saturday and Sunday. The first eight months are named after Roman gods, including two emperors; the rest are just numbers.",
    "Nobody likes clowns",
    "Mark Twain was born and died under two successive appearances of Halley\’s Comet. He once said \"Get your facts first, then you can distort them as you please\", which is the motto of this trivia feature!",
    "Most fortune cookies contain bromides and truisms, not fortunes.",
    "Many sayings are falsely attributed to Confucius. \"Never eat yellow snow\" is genuine, however.",
    "The difference between an aphorism and an apothegm is that you\'ve heard of one and not the other.",
    "There are no stupid questions, only stupid people.",
    "Back when people respected learning, trivia was called lore.",
    "Most people agree that the greatest sporting event of all time was when Rocky Balboa defeated Apollo Creed. Those people can\'t distinguish between fiction and reality.",
    "The first marathon was run by Pheidippides, a messenger bringing to Athens the news of the Battle of Marathon. When he had announced the Greek victory, he collapsed and died.",
    "The wheel was invented by Ughg, a caveman famous for dinosaur-riding. He also invented fire and Cheez-Its.",
    "Elephant seals can hold their breath for 100 minutes, and are not really elephants.",
    "The average adult human brain has about 100 billion brain cells, with 100 trillion connections between them, but most people only use four or five.",
    "According to Google CEO Eric Shmidt, every two days humanity now creates as much information as we did from the dawn of civilization until 2003. On an unrelated note, Sturgeon\'s Law states that 90% of everything is crap.",
    "Dogs were promoted to Man\'s Best Friend after the previous best friend caused that unfortunate incident in Vegas. You know the one."
    ],

  buildIndex: function () {
    for (var i = 1; i < trivia.randomTrivia.length; i++) {
      trivia.index.push(i);
    }
    trivia.shuffle(trivia.index);
    trivia.index.push('0');
  },

  shuffle: function (array) {
    var m = array.length, t, i;
    while (m) {
      i = Math.floor(Math.random() * m--);
      // console.log('i = ' + i);
      t = array[m];
      array[m] = array[i];
      array[i] = t;
    }
    return array;
  },

  setStoredIndex: function() {
    localStorage.index = JSON.stringify(trivia.index);
  },

  getStoredIndex: function() {
    if (localStorage.shuffledIndex) {
      trivia.index = JSON.parse(localStorage.index);
    } else {
      trivia.buildIndex();
    }
  },

  randomFact: function () {
    if (localStorage.index) {
      trivia.index = JSON.parse(localStorage.index);
    }
    if (trivia.index.length === 0) {
      trivia.buildIndex();
    }
    trivia.tagline = document.getElementById("tagline");
    trivia.tagline.textContent = trivia.randomTrivia[trivia.index.pop()];
    localStorage.index = JSON.stringify(trivia.index);
  },
}

trivia.randomFact();

<|endoftext|>


<commit_before>import canUseDOM from '../util/inDOM'

export default (function(){
  var root = canUseDOM && document.documentElement

  return (root && root.contains)
    ? function(context, node){ return context.contains(node); }
    : (root && root.compareDocumentPosition)
        ? function(context, node){
            return context === node || !!(context.compareDocumentPosition(node) & 16);
          }
        : function(context, node){
            if (node) do {
              if (node === context) return true;
            } while ((node = node.parentNode));

            return false;
          }
})()
<commit_msg>Support contains on SVG elements in IE<commit_after>import canUseDOM from '../util/inDOM'

export default (function(){
  // HTML DOM and SVG DOM may have different support levels,
  // so we need to check on context instead of a document root element.
  return canUseDOM
    ? function(context, node){
        if (context.contains) {
          return context.contains(node);
        } else if (context.compareDocumentPosition){
          return context === node || !!(context.compareDocumentPosition(node) & 16);
        } else {
          return fallback(context, node);
        }
      }
    : fallback;
})()

function fallback(context, node) {
  if (node) do {
    if (node === context) return true;
  } while ((node = node.parentNode));

  return false;
}
<|endoftext|>


<commit_before>var $zoom,
    $timelapse,
    $handle,
    $time,
    timerWidth,
    $tooltip,
    $city,
    $cityname,
    windowHeight,
    windowWidth;

var initSliders = function() {
    // creates the time slider
    $timelapse.slider({
    	range: "min",
    	min: MINVALUE,
    	max: MAXVALUE,
    	step: 1
    });

    // creates the zoom slider
    $zoom.slider({
    	min: 0,
    	max: 3,
    	step: 1
    });
};

// sets negative margins to the modal popup in order to center it on screen
var initPopup = function() {
    $('#sign-in-window').css( {
      'marginLeft' : -(($('#sign-in-window').width() + 52)/2),
      'marginTop' : -(($('#sign-in-window').height() + 42)/2)
    });
};

// sets the dimensions of the mask
var initMask = function() {
    windowHeight = $(document).height();
    windowWidth = $(window).width();

    $('#mask').css({'width' : windowWidth, 'height' : windowHeight});
};

var showYourSharesInfo = function() {
    $('#your-shares-info').show();
    toggleFocus();
};

var hideYourSharesInfo = function() {
    $('#your-shares-info').hide();
    toggleFocus();
};

var toggleFocusInfo = function(focus) {
    if(focus != -1) {
        $('#focus-info').show();
    } else {
        $('#focus-info').hide();
    }
};

var toggleFocus = function() {
    var list = document.getElementById("cities-list");

    list.value = -1;
    toggleFocusInfo(list.value);
    if(list.disabled) {
        list.disabled = false;
    } else {
        list.disabled = true;
    }
};

var initUI = function() {
    $zoom = $('#zoom');
    $timelapse = $('#time-wrapper');
    $handle = $('#time-wrapper a');
    $time = $('#current-time');
    timerWidth = $('#time-wrapper').width();
    $tooltip = $('#tooltip');
    $city = $('svg text');
    $cityname = $('#tooltip span');

    // increases the value of the zoom slider
    $('#zoom-in').click(function() {

        updateCurrentScale();
        $zoom.slider("value", (currentScale + 1));
    });

    // decreases the value of the zoom slider
    $('#zoom-out').click(function() {

        updateCurrentScale();
        $zoom.slider("value", (currentScale - 1));
    });

    $zoom.bind('slidechange', function(event, ui) {
       if(ui.value <= 3 && ui.value > 0) {
           $('#visualization').addClass('pannable');
       } else {
           if($('#visualization').hasClass('pannable')) {
               $('#visualization').removeClass('pannable');
           }
       }
    });

    // displays the sign-in modal popup
    $('#sign-in').click(function() {
        $('#mask').fadeIn(200);
        $('#sign-in-window').fadeIn(200);
    });

    // toggles hightlight on magnifiers icons depending on the current value
    $('#zoom').bind("slidechange", function () {

        updateCurrentScale();

        if(currentScale > 0) {
            $('#zoom-out').removeClass('off');
        } else {
            $('#zoom-out').addClass('off');
        }

        if(currentScale > 2) {
            $('#zoom-in').addClass('off');
        } else {
            $('#zoom-in').removeClass('off');
        }
    });

    // hides the sign-in modal popup
    $('#mask').click(function() {
        $(this).fadeOut(200);
        $('#sign-in-window').fadeOut(200);
    });

    // triggers the play/pause and toggles the corresponding strings
    $('#play-pause').click(function() {
        togglePlay();
    });

    // Resizes the mask when the window is resized to avoird scrollbars
    $(window).resize(function() {
        initMask();
    });

    var updateTimeLabel = function(currentTime) {
        $time.css('left', (currentTime / MAXVALUE) * timerWidth);
        updateDelta(x, currentTime);
    };

    // stops playing when the slider is manually changed
    $timelapse.mousedown(function() {
        if(isPlaying) {
            togglePlay();
            $('body').mouseup(function() {
                togglePlay();
                $('body').unbind('mouseup');
            });
        };
    });

    $timelapse.bind('slide', function(event, ui) {
        fastForward(ui.value);
        updateTimeLabel(ui.value);
    });

    // resumes playing when slider is released, but only if this happens after interrupting replay
    $('body').mouseup(function() {
        $(window).unbind('mousemove');
    });

    // updates the position of the tooltip
    $(document).mousemove(function(e){
        var w = $tooltip.width();

       $tooltip.css({
           'left' : e.pageX - ((w / 2) + 15),
           'top' : e.pageY + 27
        });
    });

    // shows the popup
    $('#boundingBox').hover(function() {
        $tooltip.show();
    }, function() {
        $tooltip.hide();
    });

    $('#viewport1 g').hover(function() {
        $tooltip.show();
    }, function() {
        $tooltip.hide();
    })

    // writes the name of the city in the tooltip
    $city.mouseenter(function() {
       var content = $(this).text();
       $cityname.text(content);
    });

    // makes the current time label move with the slider handle
    $timelapse.bind('slidechange', function(event, ui) {
        updateTimeLabel(ui.value);
    });

    //Make spacebar play/pause
    $(document).bind('keydown', function(e) {
        var code = (e.keyCode ? e.keyCode : e.which);
        if(code === 32) {
            togglePlay();
        }
    });

    $(document).bind('keypress', function(e) {
        var code = (e.keyCode ? e.keyCode : e.which);
        if(code === 32) {
            return false;
        }
    });

    $('#show-everyone').click(function() {
        shareHistory = globalHistory;
        resetToCurrentTime();
        $(this).toggle();
        $('#show-your-shares').toggle();
        hideYourSharesInfo();
    });

    $('#show-your-shares').click(function() {
        shareHistory = userHistory;
        resetToCurrentTime();
        $(this).toggle();
        $('#show-everyone').toggle();
        showYourSharesInfo();
    });

    $("#cities-list").change(function () {
        $("select option:selected").each(function () {
            focusedCity = parseInt($(this).val());
            $('#focus-info').text($(this).text());
        });
        resetToCurrentTime();
        toggleFocusInfo(focusedCity);
    });

    $('#show-everyone').hide();

    initPopup();
    initMask();
    initSliders();
};

// increments the value of the time slider
var updateTimelapse = function() {
    $timelapse.slider('value', currentTime + 1)
};

var resetTimelapse = function() {
    $timelapse.slider('value', 0);
};

var showPlayButton = function() {
    $('#play').show();
    $('#pause').hide();
};

var showPauseButton = function() {
    $('#play').hide();
    $('#pause').show();
};

var disableSlider = function() {
    $timelapse.slider('disable');
    sliderEnabled = false;
};<commit_msg>Minor fix to my last commit<commit_after>var $zoom,
    $timelapse,
    $handle,
    $time,
    timerWidth,
    $tooltip,
    $city,
    $cityname,
    windowHeight,
    windowWidth;

var initSliders = function() {
    // creates the time slider
    $timelapse.slider({
    	range: "min",
    	min: MINVALUE,
    	max: MAXVALUE,
    	step: 1
    });

    // creates the zoom slider
    $zoom.slider({
    	min: 0,
    	max: 3,
    	step: 1
    });
};

// sets negative margins to the modal popup in order to center it on screen
var initPopup = function() {
    $('#sign-in-window').css( {
      'marginLeft' : -(($('#sign-in-window').width() + 52)/2),
      'marginTop' : -(($('#sign-in-window').height() + 42)/2)
    });
};

// sets the dimensions of the mask
var initMask = function() {
    windowHeight = $(document).height();
    windowWidth = $(window).width();

    $('#mask').css({'width' : windowWidth, 'height' : windowHeight});
};

var showYourSharesInfo = function() {
    $('#your-shares-info').show();
    toggleFocus();
};

var hideYourSharesInfo = function() {
    $('#your-shares-info').hide();
    toggleFocus();
};

var toggleFocusInfo = function(focus) {
    if(focus != -1) {
        $('#focus-info').show();
    } else {
        $('#focus-info').hide();
    }
};

var toggleFocus = function() {
    var list = document.getElementById("cities-list");

    list.value = -1;
    toggleFocusInfo(list.value);
    if(list.disabled) {
        list.disabled = false;
    } else {
        list.disabled = true;
    }
};

var initUI = function() {
    $zoom = $('#zoom');
    $timelapse = $('#time-wrapper');
    $handle = $('#time-wrapper a');
    $time = $('#current-time');
    timerWidth = $('#time-wrapper').width();
    $tooltip = $('#tooltip');
    $city = $('svg text');
    $cityname = $('#tooltip span');

    // increases the value of the zoom slider
    $('#zoom-in').click(function() {

        updateCurrentScale();
        $zoom.slider("value", (currentScale + 1));
    });

    // decreases the value of the zoom slider
    $('#zoom-out').click(function() {

        updateCurrentScale();
        $zoom.slider("value", (currentScale - 1));
    });

    $zoom.bind('slidechange', function(event, ui) {
       if(ui.value <= 3 && ui.value > 0) {
           $('#visualization').addClass('pannable');
       } else {
           if($('#visualization').hasClass('pannable')) {
               $('#visualization').removeClass('pannable');
           }
       }
    });

    // displays the sign-in modal popup
    $('#sign-in').click(function() {
        $('#mask').fadeIn(200);
        $('#sign-in-window').fadeIn(200);
    });

    // toggles hightlight on magnifiers icons depending on the current value
    $('#zoom').bind("slidechange", function () {

        updateCurrentScale();

        if(currentScale > 0) {
            $('#zoom-out').removeClass('off');
        } else {
            $('#zoom-out').addClass('off');
        }

        if(currentScale > 2) {
            $('#zoom-in').addClass('off');
        } else {
            $('#zoom-in').removeClass('off');
        }
    });

    // hides the sign-in modal popup
    $('#mask').click(function() {
        $(this).fadeOut(200);
        $('#sign-in-window').fadeOut(200);
    });

    // triggers the play/pause and toggles the corresponding strings
    $('#play-pause').click(function() {
        togglePlay();
    });

    // Resizes the mask when the window is resized to avoird scrollbars
    $(window).resize(function() {
        initMask();
    });

    var updateTimeLabel = function(currentTime) {
        $time.css('left', (currentTime / MAXVALUE) * timerWidth);
        updateDelta(x, currentTime);
    };

    // stops playing when the slider is manually changed
    $timelapse.mousedown(function() {
        if(isPlaying) {
            togglePlay();
            $('body').mouseup(function() {
                togglePlay();
                $('body').unbind('mouseup');
            });
        };
    });

    $timelapse.bind('slide', function(event, ui) {
        fastForward(ui.value);
        updateTimeLabel(ui.value);
    });

    // resumes playing when slider is released, but only if this happens after interrupting replay
    $('body').mouseup(function() {
        $(window).unbind('mousemove');
    });

    // updates the position of the tooltip
    $(document).mousemove(function(e){
        var w = $tooltip.width();

       $tooltip.css({
           'left' : e.pageX - ((w / 2) + 15),
           'top' : e.pageY + 27
        });
    });

    // shows the popup
    $('#boundingBox').hover(function() {
        $tooltip.show();
    }, function() {
        $tooltip.hide();
    });

    $('#viewport1 g').hover(function() {
        $tooltip.show();
    }, function() {
        $tooltip.hide();
    })

    // writes the name of the city in the tooltip
    $city.mouseenter(function() {
       var content = $(this).text();
       $cityname.text(content);
    });

    // makes the current time label move with the slider handle
    $timelapse.bind('slidechange', function(event, ui) {
        updateTimeLabel(ui.value);
    });

    //Make spacebar play/pause
    $(document).bind('keydown', function(e) {
        var code = (e.keyCode ? e.keyCode : e.which);
        if(code === 32) {
            togglePlay();
        }
    });

    $(document).bind('keypress', function(e) {
        var code = (e.keyCode ? e.keyCode : e.which);
        if(code === 32) {
            return false;
        }
    });

    $('#show-everyone').click(function() {
        shareHistory = globalHistory;
        resetToCurrentTime();
        $(this).toggle();
        $('#show-your-shares').toggle();
        hideYourSharesInfo();
    });

    $('#show-your-shares').click(function() {
        shareHistory = userHistory;
        resetToCurrentTime();
        $(this).toggle();
        $('#show-everyone').toggle();
        showYourSharesInfo();
    });

    $("#cities-list").change(function () {
        $("select option:selected").each(function () {
            focusedCity = parseInt($(this).val());
            $('#focus-info').text($(this).text());
        });
        resetToCurrentTime();
        toggleFocusInfo(focusedCity);
    });

    $('#show-everyone').hide();

    initPopup();
    initMask();
    initSliders();
};

// increments the value of the time slider
var updateTimelapse = function() {
    $timelapse.slider('value', currentTime + 1)
};

var resetTimelapse = function() {
    $timelapse.slider('value', 0);
};

var showPlayButton = function() {
    $('#play').show();
    $('#pause').hide();
};

var showPauseButton = function() {
    $('#play').hide();
    $('#pause').show();
};

var disableSlider = function() {
    $timelapse.slider('disable');
    sliderEnabled = false;
};<|endoftext|>


<commit_before>'use strict'

const xtend = require('xtend')
const unified = require('unified')
const parse = require('remark-parse')
const PropTypes = require('prop-types')
const defaultRenderers = require('./renderers')
const getDefinitions = require('./get-definitions')
const astToReact = require('./ast-to-react')
const wrapTableRows = require('./wrap-table-rows')
const disallowNode = require('./plugins/disallow-node')
const naiveHtml = require('./plugins/naive-html')

const allTypes = Object.keys(defaultRenderers)

const ReactMarkdown = function ReactMarkdown(props) {
  const src = props.source || props.children || ''

  if (props.allowedTypes && props.disallowedTypes) {
    throw new Error('Only one of `allowedTypes` and `disallowedTypes` should be defined')
  }

  const renderers = xtend(defaultRenderers, props.renderers)

  const rawAst = unified()
    .use(parse)
    .parse(src)

  const plugins = determinePlugins(props)
  const ast = plugins.reduce((node, plugin) => plugin(node), rawAst)
  const renderProps = xtend(props, {
    renderers: renderers,
    definitions: getDefinitions(ast)
  })

  return astToReact(ast, renderProps)
}

function determinePlugins(props) {
  const plugins = [wrapTableRows]

  let disallowedTypes = props.disallowedTypes
  if (props.allowedTypes) {
    disallowedTypes = allTypes.filter(
      type => type !== 'root' && props.allowedTypes.indexOf(type) === -1
    )
  }

  const removalMethod = props.unwrapDisallowed ? 'unwrap' : 'remove'
  if (disallowedTypes && disallowedTypes.length > 0) {
    plugins.push(disallowNode.ofType(disallowedTypes, removalMethod))
  }

  if (props.allowNode) {
    plugins.push(disallowNode.ifNotMatch(props.allowNode, removalMethod))
  }

  const renderHtml = !props.escapeHtml && !props.skipHtml
  if (renderHtml) {
    plugins.push(naiveHtml)
  }

  return plugins
}

ReactMarkdown.defaultProps = {
  renderers: {},
  escapeHtml: true,
  skipHtml: false
}

ReactMarkdown.propTypes = {
  className: PropTypes.string,
  source: PropTypes.string,
  children: PropTypes.string,
  sourcePos: PropTypes.bool,
  escapeHtml: PropTypes.bool,
  skipHtml: PropTypes.bool,
  softBreak: PropTypes.string,
  allowNode: PropTypes.func,
  allowedTypes: PropTypes.arrayOf(PropTypes.oneOf(allTypes)),
  disallowedTypes: PropTypes.arrayOf(PropTypes.oneOf(allTypes)),
  transformLinkUri: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]),
  transformImageUri: PropTypes.func,
  unwrapDisallowed: PropTypes.bool,
  renderers: PropTypes.object
}

module.exports = ReactMarkdown
<commit_msg>Add support for AST-plugins<commit_after>'use strict'

const xtend = require('xtend')
const unified = require('unified')
const parse = require('remark-parse')
const PropTypes = require('prop-types')
const defaultRenderers = require('./renderers')
const getDefinitions = require('./get-definitions')
const astToReact = require('./ast-to-react')
const wrapTableRows = require('./wrap-table-rows')
const disallowNode = require('./plugins/disallow-node')
const naiveHtml = require('./plugins/naive-html')

const allTypes = Object.keys(defaultRenderers)

const ReactMarkdown = function ReactMarkdown(props) {
  const src = props.source || props.children || ''

  if (props.allowedTypes && props.disallowedTypes) {
    throw new Error('Only one of `allowedTypes` and `disallowedTypes` should be defined')
  }

  const renderers = xtend(defaultRenderers, props.renderers)

  const rawAst = unified()
    .use(parse)
    .parse(src)

  const plugins = determinePlugins(props)
  const ast = plugins.reduce((node, plugin) => plugin(node), rawAst)
  const renderProps = xtend(props, {
    renderers: renderers,
    definitions: getDefinitions(ast)
  })

  return astToReact(ast, renderProps)
}

function determinePlugins(props) {
  const plugins = [wrapTableRows]

  let disallowedTypes = props.disallowedTypes
  if (props.allowedTypes) {
    disallowedTypes = allTypes.filter(
      type => type !== 'root' && props.allowedTypes.indexOf(type) === -1
    )
  }

  const removalMethod = props.unwrapDisallowed ? 'unwrap' : 'remove'
  if (disallowedTypes && disallowedTypes.length > 0) {
    plugins.push(disallowNode.ofType(disallowedTypes, removalMethod))
  }

  if (props.allowNode) {
    plugins.push(disallowNode.ifNotMatch(props.allowNode, removalMethod))
  }

  const renderHtml = !props.escapeHtml && !props.skipHtml
  if (renderHtml) {
    plugins.push(naiveHtml)
  }

  return props.astPlugins ? plugins.concat(props.astPlugins) : plugins
}

ReactMarkdown.defaultProps = {
  renderers: {},
  escapeHtml: true,
  skipHtml: false
}

ReactMarkdown.propTypes = {
  className: PropTypes.string,
  source: PropTypes.string,
  children: PropTypes.string,
  sourcePos: PropTypes.bool,
  escapeHtml: PropTypes.bool,
  skipHtml: PropTypes.bool,
  allowNode: PropTypes.func,
  allowedTypes: PropTypes.arrayOf(PropTypes.oneOf(allTypes)),
  disallowedTypes: PropTypes.arrayOf(PropTypes.oneOf(allTypes)),
  transformLinkUri: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]),
  transformImageUri: PropTypes.func,
  astPlugins: PropTypes.arrayOf(PropTypes.func),
  unwrapDisallowed: PropTypes.bool,
  renderers: PropTypes.object
}

module.exports = ReactMarkdown
<|endoftext|>


<commit_before>import { CARDS_SHUFFLE, CARDS_MOVE_CARD, CARDS_SHOW_FACE, CARDS_CLICK } from '../constants';

const shuffle = (arr) => {
  let unshuffled = arr.slice();
  let shuffled = [];
  while(unshuffled.length > 0){
    let randomIndex = Math.floor( Math.random()*unshuffled.length );
    let randomItem = shuffled.push( unshuffled[randomIndex] );
    unshuffled = [
      ...unshuffled.slice(0,randomIndex),
      ...unshuffled.slice(randomIndex+1)
    ];
  }
  return shuffled;
}

const updateLast = (arr, updateWith) => {
  return arr.map( (item, index) => (
    index === arr.length-1 ? Object.assign({}, item, updateWith) : item
  ) );
}

const cardClickHandlers = {
  hand: (state, key, index) => {
    console.log("cardClickHandlers hand", key, index);

    return {
      ...state,
      hand: [
        ...state.hand.slice(0,index),
        Object.assign( {}, state.hand[index], { selected: !state.hand[index].selected } ),
        ...state.hand.slice(index+1),
      ],
    }
  }
}

const cardTypes = {
  resources: {
    wood: {
      name: "Wood",
      graphics: "http://preview.turbosquid.com/Preview/2014/05/20__17_27_37/wooden_beams_c_0000.jpgb887479b-935a-4f6e-b722-970544f474a0Original.jpg",
      type: "resource"
    },
    stone: {
      name: "Stone",
      graphics: "https://cdn1.artstation.com/p/assets/images/images/001/848/817/large/gavin-bartlett-gavinbartlett-rock-03-2016-render-01.jpg?1453684542",
      type: "resource"
    },
    iron: {
      name: "Iron",
      graphics: "http://media-dominaria.cursecdn.com/attachments/143/922/635769989532453054.jpg",
      type: "resource"
    },
    serf: {
      name: "Serf",
      graphics: "http://tes.riotpixels.com/skyrim/artwork/concept-a/large/NCostumeMF01.jpg",
      type: "resource"
    },
    gold: {
      name: "Gold",
      graphics: "http://www.blirk.net/wallpapers/1600x1200/gold-wallpaper-4.jpg",
      type: "resource"
    }
  },
  lands: {
    forest: {
      name: "Forest",
      graphics: "https://s-media-cache-ak0.pinimg.com/736x/79/ff/22/79ff227b71cb7392013b50bb5eb77fa7.jpg",
      type: "land"
    },
    plains: {
      name: "Plains",
      graphics: "https://s-media-cache-ak0.pinimg.com/736x/08/b3/3a/08b33ae668059df7fcfe14aa5dd1c57a.jpg",
      type: "land"
    },
    hills: {
      name: "Hills",
      graphics: "http://orig02.deviantart.net/0c14/f/2010/309/8/9/rocky_terrain_stock_3_by_mirandarose_stock-d328drk.jpg",
      type: "land"
    },
    mountains: {
      name: "Mountains",
      graphics: "http://www.movingmountainsministries.com/wp-content/uploads/2014/03/green-abstract-mountains-artwork-337347-21.jpg",
      type: "land"
    }
  },
  buildings: {
    "tower": {
      name: "Tower",
      type: "building",
      graphics: "http://preview.turbosquid.com/Preview/2014/05/24__15_49_12/windowtower.jpge4dd1d20-d37b-495d-b178-d7b7ed020190HD.jpg",
      cost: { wood: 0, iron: 0, stone: 0 },
      tokenSlots: [],
      labels: []
    },
    "wall": {
      name: "Wall",
      type: "building",
      graphics: "http://preview.turbosquid.com/Preview/2015/03/30__21_06_04/S1.jpgdab93f66-4f4c-47a6-9c64-bb2c83c4da0cOriginal.jpg",
      cost: { wood: 0, iron: 0, stone: 0 },
      tokenSlots: [],
      labels: []
    },
    // "gate": {
    //   name: "Gate",
    //   type: "building",
    //   cost: { wood: 0, iron: 0, stone: 0 },
    //   tokenSlots: [],
    //   labels: []
    // },
    "living quarters": {
      name: "Living Quarters",
      type: "building",
      graphics: "https://s-media-cache-ak0.pinimg.com/736x/45/32/41/453241e1d38ffdfcbcb439946775a40e.jpg",
      cost: { wood: 0, iron: 0, stone: 0 },
      tokenSlots: [],
      labels: []
    },
    "armory": {
      name: "Armory",
      type: "building",
      graphics: "http://orig13.deviantart.net/c8db/f/2015/002/c/a/armory_by_hfesbra-d8ca2pf.jpg",
      cost: { wood: 0, iron: 0, stone: 0 },
      tokenSlots: [],
      labels: []
    },
    "barracks": {
      name: "Barracks",
      type: "building",
      graphics: "http://www.florian-bruecher.de/portfolio/grafiken/props_wehrhaus02.jpg",
      cost: { wood: 0, iron: 0, stone: 0 },
      tokenSlots: [],
      labels: []
    },
    "hall": {
      name: "Hall",
      type: "building",
      graphics: "http://squarefaction.ru/files/game/744/gallery/fa1a798345789195acf615d5d9dc5329.jpg",
      cost: { wood: 0, iron: 0, stone: 0 },
      tokenSlots: [],
      labels: []
    },
    "blacksmith": {
      name: "Blacksmith",
      type: "building",
      graphics: "https://img-new.cgtrader.com/items/220210/large_medieval_village_blacksmith_3d_model_3ds_fbx_obj_blend_X__ms3d_b3d_3f114f8d-673b-4735-b9da-e0217b42198c.jpg",
      cost: { wood: 0, iron: 0, stone: 0 },
      tokenSlots: [],
      labels: []
    },
    "stables": {
      name: "Stables",
      type: "building",
      cost: { wood: 0, iron: 0, stone: 0 },
      tokenSlots: [],
      labels: []
    },
    "mine": {
      name: "Mine",
      type: "building",
      cost: { wood: 0, iron: 0, stone: 0 },
      tokenSlots: [],
      labels: []
    },
    "chapel": {
      name: "Chapel",
      type: "building",
      cost: { wood: 0, iron: 0, stone: 0 },
      tokenSlots: [],
      labels: []
    },
    "sawmill": {
      name: "Sawmill",
      type: "building",
      cost: { wood: 0, iron: 0, stone: 0 },
      tokenSlots: [],
      labels: []
    },
    "quary": {
      name: "Quary",
      type: "building",
      cost: { wood: 0, iron: 0, stone: 0 },
      tokenSlots: [],
      labels: []
    },
    "marketplace": {
      name: "Marketplace",
      type: "building",
      cost: { wood: 0, iron: 0, stone: 0 },
      tokenSlots: [],
      labels: []

    },
  },
  units: {
    guards: {
      name: "Guards",
      type: "unit",
      cost: { wood: 0, iron: 0, stone: 0 }
    },
    marksmen: {
      name: "Marksmen",
      type: "unit",
      cost: { wood: 0, iron: 0, stone: 0 }
    },
    horsemen: {
      name: "Horsemen",
      type: "unit",
      cost: { wood: 0, iron: 0, stone: 0 }
    },
    bandits: {
      name: "Bandits",
      type: "unit",
      cost: { wood: 0, iron: 0, stone: 0 }
    },
    footman: {
      name: "Footman",
      type: "unit",
      cost: { wood: 0, iron: 0, stone: 0 }
    }
  }
};

const cardDecks = {
  "supply": [
    ...Object.keys(cardTypes.buildings).map( (key) => ( { card: cardTypes.buildings[key], amount: 10, stack: true } ) ),
    ...Object.keys(cardTypes.units).map( (key) => ( { card: cardTypes.units[key], amount: 10, stack: true } ) )
  ],
  "board": Object.keys(cardTypes.lands).map( (key) => ( { card: cardTypes.lands[key], amount: 3 } ) ),
  "resources": Object.keys(cardTypes.resources).map( (key) => ( { card: cardTypes.resources[key], amount: 20 } ) ),
  "hand": Object.keys(cardTypes.resources).map( (key) => ( { card: cardTypes.resources[key], amount: 2, extendBy: { hover: true } } ) ),
};

const deckFactory = () => (
  Object.keys(cardDecks).reduce( (prev, key) => (
    Object.assign({}, prev,
      { // deck key
        [key]: cardDecks[key].reduce( (prev, item) => {
          let cards = [];
          for (var i = 0 ; i < item.amount ; i++) {
            cards.push( Object.assign({}, item.card, item.extendBy));
          }
          return item.stack ? [
            ...prev,
            cards
          ] : [
            ...prev,
            ...cards
          ]
        }, [] )
      }
    )
  ) , {})
);

const decks = deckFactory();

decks.board = shuffle(decks.board);
decks.supply = decks.supply.map( (item, index) => (
  updateLast( item, { hover: true } )
) );

// console.log("decks", decks.supply);

export default function cards(state = decks, action) {
  switch (action.type) {
    case CARDS_CLICK:
    let key = action.payload.key;
      console.log(CARDS_CLICK, action.payload);
      return key in cardClickHandlers ? cardClickHandlers[key](state, key, action.payload.index) : state;

    case CARDS_SHUFFLE:
      return {
        ...state,
        [action.payload]: shuffle( state[action.payload] ),
      };

    case CARDS_MOVE_CARD:
      return {
        ...state,
        [action.payload.from]: [
          ...state[action.payload.from].slice(0, action.payload.index),
          ...state[action.payload.from].slice(action.payload.index+1)
        ],
        [action.payload.to]: [
          ...state[action.payload.to],
          state[action.payload.from][action.payload.index]
        ],
      };

    case CARDS_SHOW_FACE:
      let index = action.payload.key;
      return {
        ...state,
        [action.payload.key]: state[action.payload.key].map( (item) => ( {
          ...item,
          faceUp: action.payload.faceUp
        } ) ),
      };

    default:
      return state;
  }
}<commit_msg>building graphics<commit_after>import { CARDS_SHUFFLE, CARDS_MOVE_CARD, CARDS_SHOW_FACE, CARDS_CLICK } from '../constants';

const shuffle = (arr) => {
  let unshuffled = arr.slice();
  let shuffled = [];
  while(unshuffled.length > 0){
    let randomIndex = Math.floor( Math.random()*unshuffled.length );
    let randomItem = shuffled.push( unshuffled[randomIndex] );
    unshuffled = [
      ...unshuffled.slice(0,randomIndex),
      ...unshuffled.slice(randomIndex+1)
    ];
  }
  return shuffled;
}

const updateLast = (arr, updateWith) => {
  return arr.map( (item, index) => (
    index === arr.length-1 ? Object.assign({}, item, updateWith) : item
  ) );
}

const cardClickHandlers = {
  hand: (state, key, index) => {
    console.log("cardClickHandlers hand", key, index);

    return {
      ...state,
      hand: [
        ...state.hand.slice(0,index),
        Object.assign( {}, state.hand[index], { selected: !state.hand[index].selected } ),
        ...state.hand.slice(index+1),
      ],
    }
  }
}

const cardTypes = {
  resources: {
    wood: {
      name: "Wood",
      graphics: "http://preview.turbosquid.com/Preview/2014/05/20__17_27_37/wooden_beams_c_0000.jpgb887479b-935a-4f6e-b722-970544f474a0Original.jpg",
      type: "resource"
    },
    stone: {
      name: "Stone",
      graphics: "https://cdn1.artstation.com/p/assets/images/images/001/848/817/large/gavin-bartlett-gavinbartlett-rock-03-2016-render-01.jpg?1453684542",
      type: "resource"
    },
    iron: {
      name: "Iron",
      graphics: "http://media-dominaria.cursecdn.com/attachments/143/922/635769989532453054.jpg",
      type: "resource"
    },
    serf: {
      name: "Serf",
      graphics: "http://tes.riotpixels.com/skyrim/artwork/concept-a/large/NCostumeMF01.jpg",
      type: "resource"
    },
    gold: {
      name: "Gold",
      graphics: "http://www.blirk.net/wallpapers/1600x1200/gold-wallpaper-4.jpg",
      type: "resource"
    }
  },
  lands: {
    forest: {
      name: "Forest",
      graphics: "https://s-media-cache-ak0.pinimg.com/736x/79/ff/22/79ff227b71cb7392013b50bb5eb77fa7.jpg",
      type: "land"
    },
    plains: {
      name: "Plains",
      graphics: "https://s-media-cache-ak0.pinimg.com/736x/08/b3/3a/08b33ae668059df7fcfe14aa5dd1c57a.jpg",
      type: "land"
    },
    hills: {
      name: "Hills",
      graphics: "http://orig02.deviantart.net/0c14/f/2010/309/8/9/rocky_terrain_stock_3_by_mirandarose_stock-d328drk.jpg",
      type: "land"
    },
    mountains: {
      name: "Mountains",
      graphics: "http://www.movingmountainsministries.com/wp-content/uploads/2014/03/green-abstract-mountains-artwork-337347-21.jpg",
      type: "land"
    }
  },
  buildings: {
    "tower": {
      name: "Tower",
      type: "building",
      graphics: "http://preview.turbosquid.com/Preview/2014/05/24__15_49_12/windowtower.jpge4dd1d20-d37b-495d-b178-d7b7ed020190HD.jpg",
      cost: { wood: 0, iron: 0, stone: 0 },
      tokenSlots: [],
      labels: []
    },
    "wall": {
      name: "Wall",
      type: "building",
      graphics: "http://preview.turbosquid.com/Preview/2015/03/30__21_06_04/S1.jpgdab93f66-4f4c-47a6-9c64-bb2c83c4da0cOriginal.jpg",
      cost: { wood: 0, iron: 0, stone: 0 },
      tokenSlots: [],
      labels: []
    },
    // "gate": {
    //   name: "Gate",
    //   type: "building",
    //   cost: { wood: 0, iron: 0, stone: 0 },
    //   tokenSlots: [],
    //   labels: []
    // },
    "living quarters": {
      name: "Living Quarters",
      type: "building",
      graphics: "https://s-media-cache-ak0.pinimg.com/736x/45/32/41/453241e1d38ffdfcbcb439946775a40e.jpg",
      cost: { wood: 0, iron: 0, stone: 0 },
      tokenSlots: [],
      labels: []
    },
    "armory": {
      name: "Armory",
      type: "building",
      graphics: "http://orig13.deviantart.net/c8db/f/2015/002/c/a/armory_by_hfesbra-d8ca2pf.jpg",
      cost: { wood: 0, iron: 0, stone: 0 },
      tokenSlots: [],
      labels: []
    },
    "barracks": {
      name: "Barracks",
      type: "building",
      graphics: "http://www.florian-bruecher.de/portfolio/grafiken/props_wehrhaus02.jpg",
      cost: { wood: 0, iron: 0, stone: 0 },
      tokenSlots: [],
      labels: []
    },
    "hall": {
      name: "Hall",
      type: "building",
      graphics: "http://squarefaction.ru/files/game/744/gallery/fa1a798345789195acf615d5d9dc5329.jpg",
      cost: { wood: 0, iron: 0, stone: 0 },
      tokenSlots: [],
      labels: []
    },
    "blacksmith": {
      name: "Blacksmith",
      type: "building",
      graphics: "https://img-new.cgtrader.com/items/220210/large_medieval_village_blacksmith_3d_model_3ds_fbx_obj_blend_X__ms3d_b3d_3f114f8d-673b-4735-b9da-e0217b42198c.jpg",
      cost: { wood: 0, iron: 0, stone: 0 },
      tokenSlots: [],
      labels: []
    },
    "stables": {
      name: "Stables",
      type: "building",
      graphics: "http://www.3d-puzzlewelt.com/images_shop/product/mittelalter-pferdestall_umbum_4627081552141_1388_1.jpg",
      cost: { wood: 0, iron: 0, stone: 0 },
      tokenSlots: [],
      labels: []
    },
    "mine": {
      name: "Mine",
      type: "building",
      graphics: "https://enchantedamerica.files.wordpress.com/2014/09/florida-disneyland-seven-dwarfs-mine-train-rails.jpg",
      cost: { wood: 0, iron: 0, stone: 0 },
      tokenSlots: [],
      labels: []
    },
    "chapel": {
      name: "Chapel",
      type: "building",
      graphics: "https://s-media-cache-ak0.pinimg.com/736x/06/17/3b/06173b7f2a158d87011c16a7b5cd8130.jpg",
      cost: { wood: 0, iron: 0, stone: 0 },
      tokenSlots: [],
      labels: []
    },
    "sawmill": {
      name: "Sawmill",
      type: "building",
      graphics: "http://img13.deviantart.net/7364/i/2012/056/2/5/old_sawmill_by_erebus74-d4qx60h.jpg",
      cost: { wood: 0, iron: 0, stone: 0 },
      tokenSlots: [],
      labels: []
    },
    "quarry": {
      name: "Quarry",
      type: "building",
      graphics: "https://s-media-cache-ak0.pinimg.com/736x/eb/66/d1/eb66d13d533b94a7bc02bbbd6f18e494.jpg",
      cost: { wood: 0, iron: 0, stone: 0 },
      tokenSlots: [],
      labels: []
    },
    "marketplace": {
      name: "Marketplace",
      type: "building",
      graphics: "http://orig07.deviantart.net/a882/f/2012/235/b/4/medieval_market_by_minnhagen-d5c4fb5.jpg",
      cost: { wood: 0, iron: 0, stone: 0 },
      tokenSlots: [],
      labels: []

    },
  },
  units: {
    guards: {
      name: "Guards",
      type: "unit",
      cost: { wood: 0, iron: 0, stone: 0 }
    },
    marksmen: {
      name: "Marksmen",
      type: "unit",
      cost: { wood: 0, iron: 0, stone: 0 }
    },
    horsemen: {
      name: "Horsemen",
      type: "unit",
      cost: { wood: 0, iron: 0, stone: 0 }
    },
    bandits: {
      name: "Bandits",
      type: "unit",
      cost: { wood: 0, iron: 0, stone: 0 }
    },
    footman: {
      name: "Footman",
      type: "unit",
      cost: { wood: 0, iron: 0, stone: 0 }
    }
  }
};

const cardDecks = {
  "supply": [
    ...Object.keys(cardTypes.buildings).map( (key) => ( { card: cardTypes.buildings[key], amount: 10, stack: true } ) ),
    ...Object.keys(cardTypes.units).map( (key) => ( { card: cardTypes.units[key], amount: 10, stack: true } ) )
  ],
  "board": Object.keys(cardTypes.lands).map( (key) => ( { card: cardTypes.lands[key], amount: 3 } ) ),
  "resources": Object.keys(cardTypes.resources).map( (key) => ( { card: cardTypes.resources[key], amount: 20 } ) ),
  "hand": Object.keys(cardTypes.resources).map( (key) => ( { card: cardTypes.resources[key], amount: 2, extendBy: { hover: true } } ) ),
};

const deckFactory = () => (
  Object.keys(cardDecks).reduce( (prev, key) => (
    Object.assign({}, prev,
      { // deck key
        [key]: cardDecks[key].reduce( (prev, item) => {
          let cards = [];
          for (var i = 0 ; i < item.amount ; i++) {
            cards.push( Object.assign({}, item.card, item.extendBy));
          }
          return item.stack ? [
            ...prev,
            cards
          ] : [
            ...prev,
            ...cards
          ]
        }, [] )
      }
    )
  ) , {})
);

const decks = deckFactory();

decks.board = shuffle(decks.board);
decks.supply = decks.supply.map( (item, index) => (
  updateLast( item, { hover: true } )
) );

// console.log("decks", decks.supply);

export default function cards(state = decks, action) {
  switch (action.type) {
    case CARDS_CLICK:
    let key = action.payload.key;
      console.log(CARDS_CLICK, action.payload);
      return key in cardClickHandlers ? cardClickHandlers[key](state, key, action.payload.index) : state;

    case CARDS_SHUFFLE:
      return {
        ...state,
        [action.payload]: shuffle( state[action.payload] ),
      };

    case CARDS_MOVE_CARD:
      return {
        ...state,
        [action.payload.from]: [
          ...state[action.payload.from].slice(0, action.payload.index),
          ...state[action.payload.from].slice(action.payload.index+1)
        ],
        [action.payload.to]: [
          ...state[action.payload.to],
          state[action.payload.from][action.payload.index]
        ],
      };

    case CARDS_SHOW_FACE:
      let index = action.payload.key;
      return {
        ...state,
        [action.payload.key]: state[action.payload.key].map( (item) => ( {
          ...item,
          faceUp: action.payload.faceUp
        } ) ),
      };

    default:
      return state;
  }
}<|endoftext|>


<commit_before>import * as c from '../constants/index'

const initialState = {
  app: `readable`,
  categories: [],
  comments: [],
  posts: [],
  updates: {},
  newComment: {
    show: false,
    parentId: '',
  },
  newPost: {
    show: false,
    complete: false,
  },
  sort: {
    by: `date`,
    descending: true
  },
  filter: ``
}

const updatePost = ({ state, post, update }) => ({
  ...state,
  posts: {
    ...state.posts,
    [post.id]: post
  },
  updates: {
    ...state.updates,
    [post.id]: update
  }
})

const updateComment = ({ state, comment, update }) => ({
  ...state,
  comments: {
    ...state.comments,
    [comment.id]: comment
  },
  updates: {
    ...state.updates,
    [comment.id]: update
  }
})

const deletePost = ({ state, id }) => ({
  ...state,
  posts: {
    ...state.posts,
    [id]: {
      ...state.posts[id],
      deleted: true
    }
  },
  updates: {
    ...state.updates,
    [id]: {
      type: c.DELETE,
      status: c.SUCCESS
    }
  }
})

const deleteComment = ({ state, id }) => ({
  ...state,
  comments: {
    ...state.comments,
    [id]: {
      ...state.comments[id],
      deleted: true
    }
  },
  updates: {
    ...state.updates,
    [id]: {
      type: c.DELETE,
      status: c.SUCCESS
    }
  }
})

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case c.FETCH_INITIAL_DATA_SUCCESS:
      return {...state, ...action.value}

    case c.EDIT_POST_BEGIN:
      return {
        ...state,
        updates: {
          ...state.updates,
          [action.id]: {
            type: c.EDIT,
            status: c.EDIT_MODE
          }
        }
      }
    case c.EDIT_POST_END:
      return {
        ...state,
        updates: {
          ...state.updates,
          [action.id]: {
            type: c.EDIT,
            status: c.CANCEL
          }
        }
      }
    case c.EDIT_POST_REQUEST:
      return {
        ...state,
        updates: {
          ...state.updates,
          [action.id]: {
            type: c.EDIT,
            status: c.REQUEST
          }
        }
      }
    case c.EDIT_POST_SUCCESS:
      return updatePost({
        state,
        post: action.post,
        update: { type: c.EDIT, status: c.SUCCESS }
      })

    case c.EDIT_COMMENT_BEGIN:
      return {
        ...state,
        updates: {
          ...state.updates,
          [action.id]: {
            type: c.EDIT,
            status: c.EDIT_MODE
          }
        }
      }
    case c.EDIT_COMMENT_END:
      return {
        ...state,
        updates: {
          ...state.updates,
          [action.id]: {
            type: c.EDIT,
            status: c.CANCEL
          }
        }
      }
    case c.EDIT_COMMENT_REQUEST:
      return {
        ...state,
        updates: {
          ...state.updates,
          [action.id]: {
            type: c.EDIT,
            status: c.REQUEST
          }
        }
      }
    case c.EDIT_COMMENT_SUCCESS:
      return {
        ...state,
        comments: {
          ...state.comments,
          [action.comment.id]: action.comment
        },
        updates: {
          ...state.updates,
          [action.comment.id]: {
            type: c.EDIT,
            status: c.SUCCESS
          }
        }
      }
    case c.VOTE_POST_SUCCESS:
      return updatePost({
        state,
        post: action.post,
        update: { type: c.VOTE, status: c.SUCCESS }
      })

    case c.VOTE_COMMENT_SUCCESS:
      return updateComment({
        state,
        comment: action.comment,
        update: { type: c.DELETE, status: c.SUCCESS }
      })

    case c.DELETE_POST_SUCCESS:
      return deletePost({
        state,
        id: action.id
      })

    case c.DELETE_COMMENT_SUCCESS:
      return deleteComment({
        state,
        id: action.id
      })

    case c.CREATE_COMMENT_SUCCESS:
      return {
        ...state,
        comments: {
          ...state.comments,
          [action.comment.id]: action.comment
        },
        newComment: {
          ...state.newComment,
          show: false
        }
      }

    case c.CREATE_POST_REQUEST:
      return {
        ...state,
        newPost: {
          ...state.newPost,
          [action.post.id]: c.CREATE_POST_REQUEST
        }
      }

    case c.CREATE_POST_SUCCESS:
      return {
        ...state,
        posts: {
          ...state.posts,
          [action.post.id]: action.post
        },
        newPost: {
          ...state.newPost,
          [action.post.id]: c.CREATE_POST_SUCCESS
        }
      }

    case c.CREATE_POST_ERROR:
      return {
        ...state,
        newPost: {
          ...state.newPost,
          [action.post.id]: c.CREATE_POST_ERROR
        }
      }

    case c.NEW_COMMENT_SHOW:
      return {
        ...state,
        newComment: {
          show: true,
          parentId: action.parentId
        }
      }

    case c.NEW_COMMENT_HIDE:
      return {
        ...state,
        newComment: {
          show: false,
          parentId: ''
        }
      }

    case c.NEW_POST_SHOW:
      return {
        ...state,
        newPost: {
          show: true
        }
      }

    case c.NEW_POST_HIDE:
      return {
        ...state,
        newPost: {
          show: false
        }
      }

    case c.SORT_BY_DATE:
      return {
        ...state,
        sort: {
          by: 'date',
          descending: action.descending
        }
      }

    case c.SORT_BY_VOTES:
      return {
        ...state,
        sort: {
          by: 'votes',
          descending: action.descending
        }
      }

    case c.FILTER_BY_CATEGORY:
      return {
        ...state,
        filter: action.category
      }

    default:
      return state
  }
}

export default reducer
<commit_msg>feat: sort by votes descending as default<commit_after>import * as c from '../constants/index'

const initialState = {
  app: `readable`,
  categories: [],
  comments: [],
  posts: [],
  updates: {},
  newComment: {
    show: false,
    parentId: '',
  },
  newPost: {
    show: false,
    complete: false,
  },
  sort: {
    by: `votes`,
    descending: true
  },
  filter: ``
}

const updatePost = ({ state, post, update }) => ({
  ...state,
  posts: {
    ...state.posts,
    [post.id]: post
  },
  updates: {
    ...state.updates,
    [post.id]: update
  }
})

const updateComment = ({ state, comment, update }) => ({
  ...state,
  comments: {
    ...state.comments,
    [comment.id]: comment
  },
  updates: {
    ...state.updates,
    [comment.id]: update
  }
})

const deletePost = ({ state, id }) => ({
  ...state,
  posts: {
    ...state.posts,
    [id]: {
      ...state.posts[id],
      deleted: true
    }
  },
  updates: {
    ...state.updates,
    [id]: {
      type: c.DELETE,
      status: c.SUCCESS
    }
  }
})

const deleteComment = ({ state, id }) => ({
  ...state,
  comments: {
    ...state.comments,
    [id]: {
      ...state.comments[id],
      deleted: true
    }
  },
  updates: {
    ...state.updates,
    [id]: {
      type: c.DELETE,
      status: c.SUCCESS
    }
  }
})

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case c.FETCH_INITIAL_DATA_SUCCESS:
      return {...state, ...action.value}

    case c.EDIT_POST_BEGIN:
      return {
        ...state,
        updates: {
          ...state.updates,
          [action.id]: {
            type: c.EDIT,
            status: c.EDIT_MODE
          }
        }
      }
    case c.EDIT_POST_END:
      return {
        ...state,
        updates: {
          ...state.updates,
          [action.id]: {
            type: c.EDIT,
            status: c.CANCEL
          }
        }
      }
    case c.EDIT_POST_REQUEST:
      return {
        ...state,
        updates: {
          ...state.updates,
          [action.id]: {
            type: c.EDIT,
            status: c.REQUEST
          }
        }
      }
    case c.EDIT_POST_SUCCESS:
      return updatePost({
        state,
        post: action.post,
        update: { type: c.EDIT, status: c.SUCCESS }
      })

    case c.EDIT_COMMENT_BEGIN:
      return {
        ...state,
        updates: {
          ...state.updates,
          [action.id]: {
            type: c.EDIT,
            status: c.EDIT_MODE
          }
        }
      }
    case c.EDIT_COMMENT_END:
      return {
        ...state,
        updates: {
          ...state.updates,
          [action.id]: {
            type: c.EDIT,
            status: c.CANCEL
          }
        }
      }
    case c.EDIT_COMMENT_REQUEST:
      return {
        ...state,
        updates: {
          ...state.updates,
          [action.id]: {
            type: c.EDIT,
            status: c.REQUEST
          }
        }
      }
    case c.EDIT_COMMENT_SUCCESS:
      return {
        ...state,
        comments: {
          ...state.comments,
          [action.comment.id]: action.comment
        },
        updates: {
          ...state.updates,
          [action.comment.id]: {
            type: c.EDIT,
            status: c.SUCCESS
          }
        }
      }
    case c.VOTE_POST_SUCCESS:
      return updatePost({
        state,
        post: action.post,
        update: { type: c.VOTE, status: c.SUCCESS }
      })

    case c.VOTE_COMMENT_SUCCESS:
      return updateComment({
        state,
        comment: action.comment,
        update: { type: c.DELETE, status: c.SUCCESS }
      })

    case c.DELETE_POST_SUCCESS:
      return deletePost({
        state,
        id: action.id
      })

    case c.DELETE_COMMENT_SUCCESS:
      return deleteComment({
        state,
        id: action.id
      })

    case c.CREATE_COMMENT_SUCCESS:
      return {
        ...state,
        comments: {
          ...state.comments,
          [action.comment.id]: action.comment
        },
        newComment: {
          ...state.newComment,
          show: false
        }
      }

    case c.CREATE_POST_REQUEST:
      return {
        ...state,
        newPost: {
          ...state.newPost,
          [action.post.id]: c.CREATE_POST_REQUEST
        }
      }

    case c.CREATE_POST_SUCCESS:
      return {
        ...state,
        posts: {
          ...state.posts,
          [action.post.id]: action.post
        },
        newPost: {
          ...state.newPost,
          [action.post.id]: c.CREATE_POST_SUCCESS
        }
      }

    case c.CREATE_POST_ERROR:
      return {
        ...state,
        newPost: {
          ...state.newPost,
          [action.post.id]: c.CREATE_POST_ERROR
        }
      }

    case c.NEW_COMMENT_SHOW:
      return {
        ...state,
        newComment: {
          show: true,
          parentId: action.parentId
        }
      }

    case c.NEW_COMMENT_HIDE:
      return {
        ...state,
        newComment: {
          show: false,
          parentId: ''
        }
      }

    case c.NEW_POST_SHOW:
      return {
        ...state,
        newPost: {
          show: true
        }
      }

    case c.NEW_POST_HIDE:
      return {
        ...state,
        newPost: {
          show: false
        }
      }

    case c.SORT_BY_DATE:
      return {
        ...state,
        sort: {
          by: 'date',
          descending: action.descending
        }
      }

    case c.SORT_BY_VOTES:
      return {
        ...state,
        sort: {
          by: 'votes',
          descending: action.descending
        }
      }

    case c.FILTER_BY_CATEGORY:
      return {
        ...state,
        filter: action.category
      }

    default:
      return state
  }
}

export default reducer
<|endoftext|>


<commit_before>import { applyFunctionMerging, setFuncNames } from '../symbolication';
import { defaultThreadOrder } from '../profile-data';

function profileViewReducer(state, action) {
  switch (action.type) {
    case 'START_SYMBOLICATING':
      return Object.assign({}, state, { symbolicationStatus: 'SYMBOLICATING' });
    case 'DONE_SYMBOLICATING':
      let newState = Object.assign({}, state, { symbolicationStatus: 'DONE' });
      delete newState.waitingForLibs;
      return newState;
    case 'REQUESTING_SYMBOL_TABLE': {
      let newWaitingForLibs = new Set(state.waitingForLibs || []);
      newWaitingForLibs.add(action.requestedLib);
      return Object.assign({}, state, { waitingForLibs: newWaitingForLibs });
    }
    case 'RECEIVED_SYMBOL_TABLE_REPLY': {
      let newWaitingForLibs = new Set(state.waitingForLibs || []);
      newWaitingForLibs.delete(action.requestedLib);
      return Object.assign({}, state, { waitingForLibs: newWaitingForLibs });
    }
    case 'COALESCED_FUNCTIONS_UPDATE': {
      const { functionsUpdatePerThread } = action;
      const threads = state.profile.threads.map((thread, threadIndex) => {
        if (!functionsUpdatePerThread[threadIndex])
          return thread;
        const { oldFuncToNewFuncMap, funcIndices, funcNames } = functionsUpdatePerThread[threadIndex];
        thread = applyFunctionMerging(thread, oldFuncToNewFuncMap);
        thread = setFuncNames(thread, funcIndices, funcNames);
        return thread;
      });
      const profile = Object.assign({}, state.profile, { threads });
      const vothreads = state.viewOptions.threads.map((thread, threadIndex) => {
        if (!functionsUpdatePerThread[threadIndex]) {
          return thread;
        }
        const { oldFuncToNewFuncMap } = functionsUpdatePerThread[threadIndex];
        const selectedFuncStack = thread.selectedFuncStack.map(oldFunc => {
          const newFunc = oldFuncToNewFuncMap.get(oldFunc);
          return newFunc === undefined ? oldFunc : newFunc;
        });
        const expandedFuncStacks = thread.expandedFuncStacks.map(oldFuncArray => {
          return oldFuncArray.map(oldFunc => {
            const newFunc = oldFuncToNewFuncMap.get(oldFunc);
            return newFunc === undefined ? oldFunc : newFunc;
          });
        });
        return Object.assign({}, thread, { selectedFuncStack, expandedFuncStacks });
      });
      const viewOptions = Object.assign({}, state.viewOptions, { threads: vothreads });
      return Object.assign({}, state, { profile, viewOptions });
    }
    case 'CHANGE_SELECTED_FUNC_STACK': {
      const { selectedFuncStack, threadIndex } = action;
      const threads = state.viewOptions.threads.map((thread, ti) => {
        if (ti !== threadIndex) {
          return thread;
        }
        return Object.assign({}, thread, { selectedFuncStack });
      });
      const viewOptions = Object.assign({}, state.viewOptions, { threads });
      return Object.assign({}, state, { viewOptions });
    }
    case 'CHANGE_SELECTED_THREAD': {
      const { selectedThread } = action;
      const viewOptions = Object.assign({}, state.viewOptions, { selectedThread });
      return Object.assign({}, state, { viewOptions });
    }
    case 'CHANGE_EXPANDED_FUNC_STACKS': {
      const { threadIndex, expandedFuncStacks } = action;
      const threads = state.viewOptions.threads.map((thread, ti) => {
        if (ti !== threadIndex) {
          return thread;
        }
        return Object.assign({}, thread, { expandedFuncStacks });
      });
      const viewOptions = Object.assign({}, state.viewOptions, { threads });
      return Object.assign({}, state, { viewOptions });
    }
    default:
      return state;
  }
}

export default function reducer(state = {}, action) {
  switch (action.type) {
    case 'WAITING_FOR_PROFILE_FROM_ADDON':
      return { status: 'WAITING_FOR_PROFILE' };
    case 'RECEIVE_PROFILE_FROM_ADDON':
      const threadOrder = defaultThreadOrder(action.profile.threads);
      return {
        status: 'DONE',
        view: 'PROFILE',
        profileView: {
          viewOptions: {
            threadOrder: threadOrder,
            selectedThread: threadOrder[0],
            threads: action.profile.threads.map(thread => ({
              selectedFuncStack: [],
              expandedFuncStacks: [],
            })),
            symbolicationStatus: null,
          },
          profile: action.profile
        },
      };
    default:
      if ('profileView' in state) {
        const profileView = profileViewReducer(state.profileView, action);
        if (profileView !== state.profileView) {
          return Object.assign({}, state, { profileView });
        }
        return state;
      }
      return state;
  }
}
<commit_msg>Use combineReducers.<commit_after>import { combineReducers } from 'redux';
import { applyFunctionMerging, setFuncNames } from '../symbolication';
import { defaultThreadOrder } from '../profile-data';

function status(state = 'INITIALIZING', action) {
  switch (action.type) {
    case 'WAITING_FOR_PROFILE_FROM_ADDON':
      return 'WAITING_FOR_PROFILE';
    case 'RECEIVE_PROFILE_FROM_ADDON':
      return 'DONE';
    default:
      return state;
  }
}

function view(state = 'INITIALIZING', action) {
  switch (action.type) {
    case 'RECEIVE_PROFILE_FROM_ADDON':
      return 'PROFILE';
    default:
      return state;
  }
}

function threadOrder(state = [], action) {
  switch (action.type) {
    case 'RECEIVE_PROFILE_FROM_ADDON':
      return defaultThreadOrder(action.profile.threads);
    default:
      return state;
  }
}

function selectedThread(state = 0, action) {
  switch (action.type) {
    case 'RECEIVE_PROFILE_FROM_ADDON':
      return defaultThreadOrder(action.profile.threads)[0];
    case 'CHANGE_SELECTED_THREAD':
      return action.selectedThread;
    default:
      return state;
  }
}

function viewOptionsThreads(state = [], action) {
  switch (action.type) {
    case 'RECEIVE_PROFILE_FROM_ADDON':
      return action.profile.threads.map(thread => ({
        selectedFuncStack: [],
        expandedFuncStacks: [],
      }));
    case 'COALESCED_FUNCTIONS_UPDATE': {
      const { functionsUpdatePerThread } = action;
      return state.map((thread, threadIndex) => {
        if (!functionsUpdatePerThread[threadIndex]) {
          return thread;
        }
        const { oldFuncToNewFuncMap } = functionsUpdatePerThread[threadIndex];
        const selectedFuncStack = thread.selectedFuncStack.map(oldFunc => {
          const newFunc = oldFuncToNewFuncMap.get(oldFunc);
          return newFunc === undefined ? oldFunc : newFunc;
        });
        const expandedFuncStacks = thread.expandedFuncStacks.map(oldFuncArray => {
          return oldFuncArray.map(oldFunc => {
            const newFunc = oldFuncToNewFuncMap.get(oldFunc);
            return newFunc === undefined ? oldFunc : newFunc;
          });
        });
        return { selectedFuncStack, expandedFuncStacks };
      });
    }
    case 'CHANGE_SELECTED_FUNC_STACK': {
      const { selectedFuncStack, threadIndex } = action;
      return state.map((thread, ti) => {
        if (ti !== threadIndex) {
          return thread;
        }
        return Object.assign({}, thread, { selectedFuncStack });
      });
    }
    case 'CHANGE_EXPANDED_FUNC_STACKS': {
      const { threadIndex, expandedFuncStacks } = action;
      return state.map((thread, ti) => {
        if (ti !== threadIndex) {
          return thread;
        }
        return Object.assign({}, thread, { expandedFuncStacks });
      });
    }
    default:
      return state;
  }
}

function symbolicationStatus(state = 'DONE', action) {
  switch (action.type) {
    case 'START_SYMBOLICATING':
      return 'SYMBOLICATING';
    case 'DONE_SYMBOLICATING':
      return 'DONE';
    default:
      return state;
  }
}

function waitingForLibs(state = new Set(), action) {
  switch (action.type) {
    case 'REQUESTING_SYMBOL_TABLE': {
      const newState = new Set(state);
      newState.add(action.requestedLib);
      return newState;
    }
    case 'RECEIVED_SYMBOL_TABLE_REPLY': {
      const newState = new Set(state);
      newState.delete(action.requestedLib);
      return newState;
    }
    default:
      return state;
  }
}

function profile(state = {}, action) {
  switch (action.type) {
    case 'RECEIVE_PROFILE_FROM_ADDON':
      return action.profile;
    case 'COALESCED_FUNCTIONS_UPDATE': {
      const { functionsUpdatePerThread } = action;
      const threads = state.threads.map((thread, threadIndex) => {
        if (!functionsUpdatePerThread[threadIndex])
          return thread;
        const { oldFuncToNewFuncMap, funcIndices, funcNames } = functionsUpdatePerThread[threadIndex];
        thread = applyFunctionMerging(thread, oldFuncToNewFuncMap);
        thread = setFuncNames(thread, funcIndices, funcNames);
        return thread;
      });
      return Object.assign({}, state, { threads });
    }
    default:
      return state;
  }
}

const viewOptions = combineReducers({ threadOrder, selectedThread, threads: viewOptionsThreads, symbolicationStatus, waitingForLibs });
const profileView = combineReducers({ viewOptions, profile });

export default combineReducers({ status, view, profileView });
<|endoftext|>


<commit_before>// @flow
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import { createSelector } from "reselect";
import { prefs } from "../utils/prefs";

import constants from "../constants";
import type { Action } from "../actions/types";

type PauseState = {
  pause: ?any,
  isWaitingOnBreak: boolean,
  frames: ?(any[]),
  selectedFrameId: ?string,
  loadedObjects: Object,
  shouldPauseOnExceptions: boolean,
  shouldIgnoreCaughtExceptions: boolean,
  debuggeeUrl: string
};

export const State = (): PauseState => ({
  pause: undefined,
  isWaitingOnBreak: false,
  frames: undefined,
  selectedFrameId: undefined,
  loadedObjects: {},
  shouldPauseOnExceptions: prefs.pauseOnExceptions,
  shouldIgnoreCaughtExceptions: prefs.ignoreCaughtExceptions,
  debuggeeUrl: ""
});

function update(state: PauseState = State(), action: Action): PauseState {
  switch (action.type) {
    case constants.PAUSED: {
      const { selectedFrameId, frames, loadedObjects, pauseInfo } = action;
      pauseInfo.isInterrupted = pauseInfo.why.type === "interrupted";

      // turn this into an object keyed by object id
      let objectMap = {};
      loadedObjects.forEach(obj => {
        objectMap[obj.value.objectId] = obj;
      });

      return Object.assign({}, state, {
        isWaitingOnBreak: false,
        pause: pauseInfo,
        selectedFrameId,
        frames,
        loadedObjects: objectMap
      });
    }

    case constants.RESUME:
      return Object.assign({}, state, {
        pause: null,
        frames: null,
        selectedFrameId: null,
        loadedObjects: {}
      });

    case constants.TOGGLE_PRETTY_PRINT:
      if (action.status == "done") {
        const frames = action.value.frames;
        let pause = frames[0];

        return Object.assign({}, state, { pause, frames });
      }

      break;
    case constants.BREAK_ON_NEXT:
      return Object.assign({}, state, { isWaitingOnBreak: true });

    case constants.SELECT_FRAME:
      return Object.assign({}, state, { selectedFrameId: action.frame.id });

    case constants.LOAD_OBJECT_PROPERTIES:
      if (action.status === "start") {
        state.loadedObjects[action.objectId] = {};
        return state;
      }

      if (action.status === "done") {
        if (!action.value) {
          return Object.assign({}, state);
        }

        const ownProperties = action.value.ownProperties;
        const ownSymbols = action.value.ownSymbols || [];
        const prototype = action.value.prototype;

        const obj = { ownProperties, prototype, ownSymbols };
        state.loadedObjects[action.objectId] = obj;
        return state;
      }
      break;

    case constants.NAVIGATE:
      return Object.assign({}, State(), { debuggeeUrl: action.url });

    case constants.PAUSE_ON_EXCEPTIONS:
      const { shouldPauseOnExceptions, shouldIgnoreCaughtExceptions } = action;

      prefs.pauseOnExceptions = shouldPauseOnExceptions;
      prefs.ignoreCaughtExceptions = shouldIgnoreCaughtExceptions;

      return Object.assign({}, state, {
        shouldPauseOnExceptions,
        shouldIgnoreCaughtExceptions
      });
  }

  return state;
}

// Selectors

// Unfortunately, it's really hard to make these functions accept just
// the state that we care about and still type it with Flow. The
// problem is that we want to re-export all selectors from a single
// module for the UI, and all of those selectors should take the
// top-level app state, so we'd have to "wrap" them to automatically
// pick off the piece of state we're interested in. It's impossible
// (right now) to type those wrapped functions.
type OuterState = { pause: PauseState };

const getPauseState = state => state.pause;

export const getPause = createSelector(
  getPauseState,
  pauseWrapper => pauseWrapper.pause
);

/*export const getLoadedObjects = createSelector(getPauseState, pauseWrapper =>
  pauseWrapper.loadedObjects
);*/

export function getLoadedObjects(state: OuterState) {
  return state.pause.loadedObjects;
}

export function getLoadedObject(state: OuterState, objectId: string) {
  return getLoadedObjects(state)[objectId];
}

export function getObjectProperties(state: OuterState, parentId: string) {
  return getLoadedObjects(state).filter(obj => obj.parentId == parentId);
}

export function getIsWaitingOnBreak(state: OuterState) {
  return state.pause.isWaitingOnBreak;
}

export function getShouldPauseOnExceptions(state: OuterState) {
  return state.pause.shouldPauseOnExceptions;
}

export function getShouldIgnoreCaughtExceptions(state: OuterState) {
  return state.pause.shouldIgnoreCaughtExceptions;
}

export function getFrames(state: OuterState) {
  return state.pause.frames;
}

const getSelectedFrameId = createSelector(getPauseState, pauseWrapper => {
  return pauseWrapper.selectedFrameId;
});

export const getSelectedFrame = createSelector(
  getSelectedFrameId,
  getFrames,
  (selectedFrameId, frames) => {
    if (!frames) {
      return null;
    }
    return frames.find(frame => frame.id == selectedFrameId);
  }
);

export function getDebuggeeUrl(state: OuterState) {
  return state.pause.debuggeeUrl;
}

// NOTE: currently only used for chrome
export function getChromeScopes(state: OuterState) {
  const frame = getSelectedFrame(state);
  return frame ? frame.scopeChain : undefined;
}

export default update;
<commit_msg>fix lint issues<commit_after>// @flow
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import { createSelector } from "reselect";
import { prefs } from "../utils/prefs";

import constants from "../constants";
import type { Action } from "../actions/types";

type PauseState = {
  pause: ?any,
  isWaitingOnBreak: boolean,
  frames: ?(any[]),
  selectedFrameId: ?string,
  loadedObjects: Object,
  shouldPauseOnExceptions: boolean,
  shouldIgnoreCaughtExceptions: boolean,
  debuggeeUrl: string
};

export const State = (): PauseState => ({
  pause: undefined,
  isWaitingOnBreak: false,
  frames: undefined,
  selectedFrameId: undefined,
  loadedObjects: {},
  shouldPauseOnExceptions: prefs.pauseOnExceptions,
  shouldIgnoreCaughtExceptions: prefs.ignoreCaughtExceptions,
  debuggeeUrl: ""
});

function update(state: PauseState = State(), action: Action): PauseState {
  switch (action.type) {
    case constants.PAUSED: {
      const { selectedFrameId, frames, loadedObjects, pauseInfo } = action;
      pauseInfo.isInterrupted = pauseInfo.why.type === "interrupted";

      // turn this into an object keyed by object id
      let objectMap = {};
      loadedObjects.forEach(obj => {
        objectMap[obj.value.objectId] = obj;
      });

      return Object.assign({}, state, {
        isWaitingOnBreak: false,
        pause: pauseInfo,
        selectedFrameId,
        frames,
        loadedObjects: objectMap
      });
    }

    case constants.RESUME:
      return Object.assign({}, state, {
        pause: null,
        frames: null,
        selectedFrameId: null,
        loadedObjects: {}
      });

    case constants.TOGGLE_PRETTY_PRINT:
      if (action.status == "done") {
        const frames = action.value.frames;
        let pause = frames[0];

        return Object.assign({}, state, { pause, frames });
      }

      break;
    case constants.BREAK_ON_NEXT:
      return Object.assign({}, state, { isWaitingOnBreak: true });

    case constants.SELECT_FRAME:
      return Object.assign({}, state, { selectedFrameId: action.frame.id });

    case constants.LOAD_OBJECT_PROPERTIES:
      if (action.status === "start") {
        state.loadedObjects[action.objectId] = {};
        return state;
      }

      if (action.status === "done") {
        if (!action.value) {
          return Object.assign({}, state);
        }

        const ownProperties = action.value.ownProperties;
        const ownSymbols = action.value.ownSymbols || [];
        const prototype = action.value.prototype;

        const obj = { ownProperties, prototype, ownSymbols };
        state.loadedObjects[action.objectId] = obj;
        return state;
      }
      break;

    case constants.NAVIGATE:
      return Object.assign({}, State(), { debuggeeUrl: action.url });

    case constants.PAUSE_ON_EXCEPTIONS:
      const { shouldPauseOnExceptions, shouldIgnoreCaughtExceptions } = action;

      prefs.pauseOnExceptions = shouldPauseOnExceptions;
      prefs.ignoreCaughtExceptions = shouldIgnoreCaughtExceptions;

      return Object.assign({}, state, {
        shouldPauseOnExceptions,
        shouldIgnoreCaughtExceptions
      });
  }

  return state;
}

// Selectors

// Unfortunately, it's really hard to make these functions accept just
// the state that we care about and still type it with Flow. The
// problem is that we want to re-export all selectors from a single
// module for the UI, and all of those selectors should take the
// top-level app state, so we'd have to "wrap" them to automatically
// pick off the piece of state we're interested in. It's impossible
// (right now) to type those wrapped functions.
type OuterState = { pause: PauseState };

const getPauseState = state => state.pause;

export const getPause = createSelector(
  getPauseState,
  pauseWrapper => pauseWrapper.pause
);

export const getLoadedObjects = createSelector(
  getPauseState,
  pauseWrapper => pauseWrapper.loadedObjects
);

export function getLoadedObject(state: OuterState, objectId: string) {
  return getLoadedObjects(state)[objectId];
}

export function getObjectProperties(state: OuterState, parentId: string) {
  return getLoadedObjects(state).filter(obj => obj.parentId == parentId);
}

export function getIsWaitingOnBreak(state: OuterState) {
  return state.pause.isWaitingOnBreak;
}

export function getShouldPauseOnExceptions(state: OuterState) {
  return state.pause.shouldPauseOnExceptions;
}

export function getShouldIgnoreCaughtExceptions(state: OuterState) {
  return state.pause.shouldIgnoreCaughtExceptions;
}

export function getFrames(state: OuterState) {
  return state.pause.frames;
}

const getSelectedFrameId = createSelector(getPauseState, pauseWrapper => {
  return pauseWrapper.selectedFrameId;
});

export const getSelectedFrame = createSelector(
  getSelectedFrameId,
  getFrames,
  (selectedFrameId, frames) => {
    if (!frames) {
      return null;
    }
    return frames.find(frame => frame.id == selectedFrameId);
  }
);

export function getDebuggeeUrl(state: OuterState) {
  return state.pause.debuggeeUrl;
}

// NOTE: currently only used for chrome
export function getChromeScopes(state: OuterState) {
  const frame = getSelectedFrame(state);
  return frame ? frame.scopeChain : undefined;
}

export default update;
<|endoftext|>


<commit_before>import {
  CHANGE_EVENT_RESPONSE_PENDING,
  CREATE_COMMENT,
  CREATE_POST,
  FETCH_POST,
  FETCH_POSTS,
  FOLLOW_POST,
  REMOVE_POST,
  UPDATE_POST,
  VOTE_ON_POST,
  VOTE_ON_POST_PENDING
} from '../actions'
import { omit, find, without } from 'lodash'
import { cloneSet, mergeList } from './util'
import { same } from '../models'

const normalize = post => ({
  ...post,
  communities: post.communities.map(c => c.id)
})

const normalizeUpdate = (post, params) => {
  return {
    ...post,
    ...omit(params, 'imageUrl', 'imageRemoved', 'docs', 'removedDocs')
  }
}

const changeEventResponse = (post, response, user) => {
  if (!user) return

  var meInResponders = find(post.responders, {id: user.id})
  var responders = without(post.responders, meInResponders)

  if (!meInResponders || meInResponders.response !== response) {
    responders.push({id: user.id, name: user.name, avatar_url: user.avatar_url, response: response})
  }
  return {...post, ...{ responders }}
}

export default function (state = {}, action) {
  let { error, type, payload, meta } = action
  if (error) {
    switch (type) {
      case VOTE_ON_POST:
        return {
          ...state,
          [meta.id]: {...state[meta.id], ...meta.prevProps}
        }
      default:
        return state
    }
  }

  let id
  switch (type) {
    case FETCH_POSTS:
      return mergeList(state, payload.posts.map(normalize), 'id')
    case CREATE_POST:
    case FETCH_POST:
      return {...state, [payload.id]: normalize(payload)}
    case UPDATE_POST:
      id = meta.id
      let post = state[id]
      return {...state, [id]: normalizeUpdate(post, meta.params)}
    case CHANGE_EVENT_RESPONSE_PENDING:
      id = meta.id
      post = state[id]
      var { response, user } = meta
      return {...state, [id]: changeEventResponse(post, response, user)}
    case VOTE_ON_POST_PENDING:
      id = meta.id
      post = state[id]
      var newPost
      if (post.myVote) {
        newPost = {...post, myVote: false, votes: post.votes - 1}
      } else {
        newPost = {...post, myVote: true, votes: post.votes + 1}
      }
      return {...state, [id]: newPost}
    case REMOVE_POST:
      id = meta.id
      return {...state, [id]: null}
    case FOLLOW_POST:
      id = meta.id
      post = state[id]
      let person = meta.person
      let follower = find(post.followers, same('id', person))
      let newFollowers = follower
        ? without(post.followers, follower)
        : (post.followers || []).concat(person)
      return cloneSet(state, `${id}.followers`, newFollowers)
  }
  return state
}
<commit_msg>add follower when creating a comment<commit_after>import {
  CHANGE_EVENT_RESPONSE_PENDING,
  CREATE_COMMENT,
  CREATE_POST,
  FETCH_POST,
  FETCH_POSTS,
  FOLLOW_POST,
  REMOVE_POST,
  UPDATE_POST,
  VOTE_ON_POST,
  VOTE_ON_POST_PENDING
} from '../actions'
import { omit, find, without } from 'lodash'
import { cloneSet, mergeList } from './util'
import { same } from '../models'

const normalize = post => ({
  ...post,
  communities: post.communities.map(c => c.id)
})

const normalizeUpdate = (post, params) => {
  return {
    ...post,
    ...omit(params, 'imageUrl', 'imageRemoved', 'docs', 'removedDocs')
  }
}

const changeEventResponse = (post, response, user) => {
  if (!user) return

  var meInResponders = find(post.responders, {id: user.id})
  var responders = without(post.responders, meInResponders)

  if (!meInResponders || meInResponders.response !== response) {
    responders.push({id: user.id, name: user.name, avatar_url: user.avatar_url, response: response})
  }
  return {...post, ...{ responders }}
}

const addOrRemoveFollower = (state, id, person) => {
  let post = state[id]
  let follower = find(post.followers, same('id', person))
  let newFollowers = follower
    ? without(post.followers, follower)
    : (post.followers || []).concat(person)
  return cloneSet(state, `${id}.followers`, newFollowers)
}

const addFollower = (state, id, person) => {
  let post = state[id]
  let follower = find(post.followers, same('id', person))
  return follower
    ? state
    : cloneSet(state, `${id}.followers`, (post.followers || []).concat(person))
}

export default function (state = {}, action) {
  let { error, type, payload, meta } = action
  if (error) {
    switch (type) {
      case VOTE_ON_POST:
        return {
          ...state,
          [meta.id]: {...state[meta.id], ...meta.prevProps}
        }
      default:
        return state
    }
  }

  let { id } = meta || {}

  switch (type) {
    case FETCH_POSTS:
      return mergeList(state, payload.posts.map(normalize), 'id')
    case CREATE_POST:
    case FETCH_POST:
      return {...state, [payload.id]: normalize(payload)}
    case UPDATE_POST:
      let post = state[id]
      return {...state, [id]: normalizeUpdate(post, meta.params)}
    case CHANGE_EVENT_RESPONSE_PENDING:
      post = state[id]
      var { response, user } = meta
      return {...state, [id]: changeEventResponse(post, response, user)}
    case VOTE_ON_POST_PENDING:
      post = state[id]
      var newPost
      if (post.myVote) {
        newPost = {...post, myVote: false, votes: post.votes - 1}
      } else {
        newPost = {...post, myVote: true, votes: post.votes + 1}
      }
      return {...state, [id]: newPost}
    case REMOVE_POST:
      return {...state, [id]: null}
    case FOLLOW_POST:
      return addOrRemoveFollower(state, id, meta.person)
    case CREATE_COMMENT:
      return addFollower(state, id, payload.user)
  }
  return state
}
<|endoftext|>


<commit_before>import { createLogger } from 'redux-logger';
import appReducer from 'redux/reducers/app';
import availabilityReducer from 'redux/reducers/availability';
import contentReducer from 'redux/reducers/content';
import {
  claimsReducer,
  costInfoReducer,
  fileInfoReducer,
  searchReducer,
  walletReducer,
  notificationsReducer,
  blacklistReducer,
} from 'lbry-redux';
import navigationReducer from 'redux/reducers/navigation';
import settingsReducer from 'redux/reducers/settings';
import { userReducer, rewardsReducer } from 'lbryinc';
import shapeShiftReducer from 'redux/reducers/shape_shift';
import subscriptionsReducer from 'redux/reducers/subscriptions';
import publishReducer from 'redux/reducers/publish';
import { persistStore, autoRehydrate } from 'redux-persist';
import createCompressor from 'redux-persist-transform-compress';
import createFilter from 'redux-persist-transform-filter';
import localForage from 'localforage';
import { createStore, applyMiddleware, compose, combineReducers } from 'redux';
import thunk from 'redux-thunk';

function isFunction(object) {
  return typeof object === 'function';
}

function isNotFunction(object) {
  return !isFunction(object);
}

function createBulkThunkMiddleware() {
  return ({ dispatch, getState }) => next => action => {
    if (action.type === 'BATCH_ACTIONS') {
      action.actions.filter(isFunction).map(actionFn => actionFn(dispatch, getState));
    }
    return next(action);
  };
}

function enableBatching(reducer) {
  return function batchingReducer(state, action) {
    switch (action.type) {
      case 'BATCH_ACTIONS':
        return action.actions.filter(isNotFunction).reduce(batchingReducer, state);
      default:
        return reducer(state, action);
    }
  };
}

const reducers = combineReducers({
  app: appReducer,
  navigation: navigationReducer,
  availability: availabilityReducer,
  claims: claimsReducer,
  fileInfo: fileInfoReducer,
  content: contentReducer,
  costInfo: costInfoReducer,
  rewards: rewardsReducer,
  search: searchReducer,
  settings: settingsReducer,
  wallet: walletReducer,
  user: userReducer,
  shapeShift: shapeShiftReducer,
  subscriptions: subscriptionsReducer,
  publish: publishReducer,
  notifications: notificationsReducer,
  blacklist: blacklistReducer,
});

const bulkThunk = createBulkThunkMiddleware();
const middleware = [thunk, bulkThunk];

if (app.env === 'development') {
  const logger = createLogger({
    collapsed: true,
  });
  middleware.push(logger);
}

// eslint-disable-next-line no-underscore-dangle
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const store = createStore(
  enableBatching(reducers),
  {}, // initial state
  composeEnhancers(
    autoRehydrate({
      log: app.env === 'development',
    }),
    applyMiddleware(...middleware)
  )
);

const compressor = createCompressor();
// Removing claims from redux-persist to see if it solves https://github.com/lbryio/lbry-desktop/issues/1983
// We were caching so much data the app was locking up
// We can't add this back until we can perform this in a non-blocking way
// const saveClaimsFilter = createFilter('claims', ['byId', 'claimsByUri']);
const subscriptionsFilter = createFilter('subscriptions', ['subscriptions', 'unread', 'viewMode']);
const contentFilter = createFilter('content', ['positions', 'history']);

// We only need to persist the receiveAddress for the wallet
const walletFilter = createFilter('wallet', ['receiveAddress']);

const persistOptions = {
  whitelist: ['subscriptions', 'publish', 'wallet', 'content'],
  // Order is important. Needs to be compressed last or other transforms can't
  // read the data
  transforms: [subscriptionsFilter, walletFilter, contentFilter, compressor],
  debounce: 10000,
  storage: localForage,
};

window.cacheStore = persistStore(store, persistOptions, err => {
  if (err) {
    console.error('Unable to load saved settings'); // eslint-disable-line no-console
  }
});

export default store;
<commit_msg>persist fileSort options when the app is closed<commit_after>import { createLogger } from 'redux-logger';
import appReducer from 'redux/reducers/app';
import availabilityReducer from 'redux/reducers/availability';
import contentReducer from 'redux/reducers/content';
import {
  claimsReducer,
  costInfoReducer,
  fileInfoReducer,
  searchReducer,
  walletReducer,
  notificationsReducer,
  blacklistReducer,
} from 'lbry-redux';
import navigationReducer from 'redux/reducers/navigation';
import settingsReducer from 'redux/reducers/settings';
import { userReducer, rewardsReducer } from 'lbryinc';
import shapeShiftReducer from 'redux/reducers/shape_shift';
import subscriptionsReducer from 'redux/reducers/subscriptions';
import publishReducer from 'redux/reducers/publish';
import { persistStore, autoRehydrate } from 'redux-persist';
import createCompressor from 'redux-persist-transform-compress';
import createFilter from 'redux-persist-transform-filter';
import localForage from 'localforage';
import { createStore, applyMiddleware, compose, combineReducers } from 'redux';
import thunk from 'redux-thunk';

function isFunction(object) {
  return typeof object === 'function';
}

function isNotFunction(object) {
  return !isFunction(object);
}

function createBulkThunkMiddleware() {
  return ({ dispatch, getState }) => next => action => {
    if (action.type === 'BATCH_ACTIONS') {
      action.actions.filter(isFunction).map(actionFn => actionFn(dispatch, getState));
    }
    return next(action);
  };
}

function enableBatching(reducer) {
  return function batchingReducer(state, action) {
    switch (action.type) {
      case 'BATCH_ACTIONS':
        return action.actions.filter(isNotFunction).reduce(batchingReducer, state);
      default:
        return reducer(state, action);
    }
  };
}

const reducers = combineReducers({
  app: appReducer,
  navigation: navigationReducer,
  availability: availabilityReducer,
  claims: claimsReducer,
  fileInfo: fileInfoReducer,
  content: contentReducer,
  costInfo: costInfoReducer,
  rewards: rewardsReducer,
  search: searchReducer,
  settings: settingsReducer,
  wallet: walletReducer,
  user: userReducer,
  shapeShift: shapeShiftReducer,
  subscriptions: subscriptionsReducer,
  publish: publishReducer,
  notifications: notificationsReducer,
  blacklist: blacklistReducer,
});

const bulkThunk = createBulkThunkMiddleware();
const middleware = [thunk, bulkThunk];

if (app.env === 'development') {
  const logger = createLogger({
    collapsed: true,
  });
  middleware.push(logger);
}

// eslint-disable-next-line no-underscore-dangle
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const store = createStore(
  enableBatching(reducers),
  {}, // initial state
  composeEnhancers(
    autoRehydrate({
      log: app.env === 'development',
    }),
    applyMiddleware(...middleware)
  )
);

const compressor = createCompressor();
// Removing claims from redux-persist to see if it solves https://github.com/lbryio/lbry-desktop/issues/1983
// We were caching so much data the app was locking up
// We can't add this back until we can perform this in a non-blocking way
// const saveClaimsFilter = createFilter('claims', ['byId', 'claimsByUri']);
const subscriptionsFilter = createFilter('subscriptions', ['subscriptions', 'unread', 'viewMode']);
const contentFilter = createFilter('content', ['positions', 'history']);
const fileInfoFilter = createFilter('fileInfo', [
  'fileListPublishedSort',
  'fileListDownloadedSort',
  'fileListSubscriptionSort',
]);
// We only need to persist the receiveAddress for the wallet
const walletFilter = createFilter('wallet', ['receiveAddress']);

const persistOptions = {
  whitelist: ['subscriptions', 'publish', 'wallet', 'content', 'fileInfo'],
  // Order is important. Needs to be compressed last or other transforms can't
  // read the data
  transforms: [subscriptionsFilter, walletFilter, contentFilter, fileInfoFilter, compressor],
  debounce: 10000,
  storage: localForage,
};

window.cacheStore = persistStore(store, persistOptions, err => {
  if (err) {
    console.error('Unable to load saved settings'); // eslint-disable-line no-console
  }
});

export default store;
<|endoftext|>