<commit_before>import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'

let Org = require('./org/org');
let Parser = require('./org/org_parser');
let React = require('react-native');

let {
  Text,
  TouchableHighlight,
  View
} = React;

/***** Actions *****/

const TOGGLE_VISIBILITY = 'TOGGLE_VISIBLE'; // type + node

function toggleVisibility (node) {
  return {
    type: TOGGLE_VISIBILITY,
    node
  };
}

const defaultState = {
  doc: Parser.parse(
    "* 1\nsection 1\n** 1.1\n** 1.2\n*** 1.2.1\n*** 1.2.2\n** 1.3\n* 2\n** 2.1\n* 1\nsection 1\n** 1.1\n** 1.2\n*** 1.2.1\n*** 1.2.2\n** 1.3\n* 2\n** 2.1\n* 1\nsection 1\n** 1.1\n** 1.2\n*** 1.2.1\n*** 1.2.2\n** 1.3\n* 2\n** 2.1\n* 1\nsection 1\n** 1.1\n** 1.2\n*** 1.2.1\n*** 1.2.2\n** 1.3\n* 2\n** 2.1"
  )
};

/***** Reducers *****/

export function orgAction(state=defaultState, action) {
  switch (action.type) {
    case TOGGLE_VISIBILITY:
      let current = Org.getMeta(node, 'hidden');
      let updated = Org.setMeta(node, 'hidden', !current);
      return Org.getDoc(updated);
    default:
      return state;
  }
}

/***** Components *****/

function Node({node}) {

}

function renderChildren(node) {
  const nodes = [];
  node = Org.getChild(node, 0);
  let i = 0;
  while (node !== undefined) {
    nodes.push(renderNode(node, i));
    node = Org.nextSibling(node);
    i += 1;
  }
  return nodes;
}

function renderNode(node, i, onPress) {
  let children = null;
  if (Org.numChildren(node) > 0) {
    if (Org.getMeta(node, 'hidden') !== true) {
      children =
      (<View style={styles.children}>
         {renderChildren(node)}
      </View>);
    } else {
      children = (<Text>...</Text>);
    }
  }
  return (
    <View key={i}>
      <TouchableHighlight >
        <Text>
          {node.content}
        </Text>
      </TouchableHighlight>
      {children}
    </View>
  );
}

function mapDispatchToProps(dispatch) {
  return { onPress: (node) => dispatch(toggleVisibility(node)) };
}

//renderNode = connect(() => {}, mapDispatchToProps)(renderNode);

export function renderDoc(doc) {
  return (
      <View style={styles.tree}>
      <Text>Test</Text>
      {renderChildren(doc.doc)}
    </View>
  );
}

function mapStateToProps(state) {
  return {
    doc: state.doc
  };
}

renderDoc = connect(mapStateToProps)(renderDoc);

const styles = {
  tree: {
    padding: 10
  },
  rootnode: {
    paddingBottom: 10
  },
  node: {
    paddingTop: 10
  },
  item: {
    flexDirection: 'row'
  },
  children: {
    paddingLeft: 20
  },
  icon: {
    paddingRight: 10,
    color: '#333',
    alignSelf: 'center'
  },
  roottext: {
    fontSize: 18
  }
};
<commit_msg>Strange bug with connect and RenderNode<commit_after>import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'

let Org = require('./org/org');
let Parser = require('./org/org_parser');
let React = require('react-native');

let {
  Text,
  TouchableHighlight,
  View
} = React;

/***** Actions *****/

const TOGGLE_VISIBILITY = 'TOGGLE_VISIBLE'; // type + node

function toggleVisibility (node) {
  return {
    type: TOGGLE_VISIBILITY,
    node
  };
}

const defaultState = {
  doc: Parser.parse(
    "* 1\nsection 1\n** 1.1\n** 1.2\n*** 1.2.1\n*** 1.2.2\n** 1.3\n* 2\n** 2.1\n* 1\nsection 1\n** 1.1\n** 1.2\n*** 1.2.1\n*** 1.2.2\n** 1.3\n* 2\n** 2.1\n* 1\nsection 1\n** 1.1\n** 1.2\n*** 1.2.1\n*** 1.2.2\n** 1.3\n* 2\n** 2.1\n* 1\nsection 1\n** 1.1\n** 1.2\n*** 1.2.1\n*** 1.2.2\n** 1.3\n* 2\n** 2.1"
  )
};

/***** Reducers *****/

export function orgAction(state=defaultState, action) {
  switch (action.type) {
    case TOGGLE_VISIBILITY:
      let current = Org.getMeta(node, 'hidden');
      let updated = Org.setMeta(node, 'hidden', !current);
      return Org.getDoc(updated);
    default:
      return state;
  }
}

/***** Components *****/

function Node({node}) {

}

function Children({node}) {

}

function renderChildren(node) {
  const nodes = [];
  Org.pprint(node);
  node = Org.getChild(node, 0);
  Org.pprint(node);
  let i = 0;
  while (node !== undefined) {
    nodes.push(renderNode(node));
    //nodes.push(renderNode(node, i));
    node = Org.nextSibling(node);
    i += 1;
  }
  return nodes;
}

//export function renderNode(node, i) {
export function renderNode(doc) {
  return (<Text> a </Text>)
  // return null;
  // let children = null;
  // if (Org.numChildren(node) > 0) {
  //   if (Org.getMeta(node, 'hidden') !== true) {
  //     children =
  //     (<View style={styles.children}>
  //        {renderChildren(node)}
  //     </View>);
  //   } else {
  //     children = (<Text>...</Text>);
  //   }
  // }
  //return (
  //  <View key={i}>
  //    <TouchableHighlight >
  //      <Text>
  //        {node.content}
  //      </Text>
  //    </TouchableHighlight>
  //    {children}
  //  </View>
  //);
}

console.warn(renderNode)
//renderNode = connect(mapStateToProps)(renderNode);
console.warn(renderNode)

function rnDispatch(dispatch) {
  return { onPress: (node) => dispatch(toggleVisibility(node)) };
}

function rnState(state, ownprops) {
  return ownprops;
}

export function renderDoc(doc) {
  return (
      <View style={styles.tree}>
      <Text>Test</Text>
      {renderChildren(doc.doc)}
    </View>
  );
}

function mapStateToProps(state) {
  return {
    doc: state.doc
  };
}

renderDoc = connect(mapStateToProps)(renderDoc);

const styles = {
  tree: {
    padding: 10
  },
  rootnode: {
    paddingBottom: 10
  },
  node: {
    paddingTop: 10
  },
  item: {
    flexDirection: 'row'
  },
  children: {
    paddingLeft: 20
  },
  icon: {
    paddingRight: 10,
    color: '#333',
    alignSelf: 'center'
  },
  roottext: {
    fontSize: 18
  }
};
<|endoftext|>


<commit_before>var Oncoprint = function(wrapper, params) {
    var that = {};

    // constants
    var RECT_HEIGHT = 23;
    var LITTLE_RECT_HEIGHT = RECT_HEIGHT / 3;
//    var LABEL_PADDING = 130;

    var UPREGULATED = "UPREGULATED";
    var DOWNREGULATED = "DOWNREGULATED";

    // useful variables
    var data = params.data;
    var query = QueryGeneData(data);
    var genes_list = query.getGeneList();
    var gene_data = data.gene_data;
    var no_genes = gene_data.length;
    var samples_all = query.getSampleList()

    // useful functions
    var translate = function(x,y) {
        return "translate(" + x + "," + y + ")";
    };

    // todo: am i using this?  what happens when you submit MIR_##/##?
    var cleanHugo = function(hugo) {
        // can't have '/' in DOM id
        return hugo.replace("/", "_");
    };

    var LABEL_PADDING = (function() {
        var avg_char_width = 23;

        var list_char_no = genes_list.map(function(i) {
            return i.split("").length;
        });

        return d3.max(list_char_no) * avg_char_width;
    })();

    // global state of the oncoprint
    var state = {
        padding: true,
        width_scalar: 1,
        show_unaltered: true,
        memo_sort: false
    };

    // functions that get state

    var getVisualizedSamples = function() {
        // get state of samples
        var samples_copy = samples_all.map(function(i) { return i;});

        // todo: note that you must sort first!
        // MemoSort behaves differently when it has different lists, that is,
        // it does not deterministically deal with samples that are equal
        if (state.memo_sort) {
            samples_copy = MemoSort(data, samples_copy, genes_list).sort();
        }

        if (!state.show_unaltered) {
            samples_copy = samples_copy.filter(query.isSampleAltered);
        }

        return samples_copy;
    };

    var getRectWidth = function() {
        var unscaled = 5.5;
        return state.width_scalar * unscaled;
    };

    var getTriangleBase = function() {
        return getRectWidth() / 2;
    };

    var getTrianglePath = function(up) {
        var base = getTriangleBase();

        if (up) {
            return "M 0 " + LITTLE_RECT_HEIGHT + " l "  + base + " -" + LITTLE_RECT_HEIGHT
                + " l " + base + " " + LITTLE_RECT_HEIGHT + " l 0 0";
//                return "M 0 7 l 2.75 -7 l 2.75 7 l 0 0";
        }
//        return "M 0 16 l " + base + " 7 l " + base + " -7 l 0 0";
        return "M 0 15 l " + base + " " + LITTLE_RECT_HEIGHT + " l "
            + base + " -" + LITTLE_RECT_HEIGHT + " l 0 0";
//            return "M 0 16 l 2.75 7 l 2.75 -7 l 0 0";
    };

    var getRectPadding = function() {
        var unscaled = 3;
        return state.padding ? (state.width_scalar * unscaled) : 0;
    };

    var getXScale = function(no_samples) {
        return (getRectWidth() + getRectPadding()) * no_samples;
    };

    var getWidth = function(no_samples) {
        return getXScale(no_samples) + LABEL_PADDING + (2 * (getRectWidth() + getRectPadding()));
    };

    var getHeight = function() {
        return (RECT_HEIGHT + 7) * no_genes;
    };

    // scales
    var x = d3.scale.ordinal().rangeBands([0, getXScale(samples_all.length)], 0);

    var y = d3.scale.ordinal().rangeBands([0, getHeight()], 0)
        .domain(genes_list);

    d3.select(wrapper)
        .style('width', '1300px')
        .style('overflow-x', 'auto')
        .style('overflow-y', 'hidden');

    // functions that echo
    that.wrapper = wrapper;

    that.getData = function() {
        return params.data;
    };

    var redraw = function(samples_visualized, track, hugo) {
        var sample = track.selectAll('.sample')
            .data(samples_visualized, function(d) { return d;});

        // enter
        var sample_enter = sample.enter().append('g')
            .attr('class', 'sample')
            .attr('transform', function(d) {
                return translate(x(d), y(hugo));
            });

        var width = getRectWidth();

        var cna = sample_enter.append('rect')
            .attr('class', function(d) {
                var cna = query.data(d, hugo, 'cna');
                return 'cna ' + (cna === null ? 'none' : cna);
            })
            .attr('width', width)
            .attr('height', RECT_HEIGHT);

        var mrna = sample_enter.append('rect')
            .attr('class', function(d) {
                var mrna = query.data(d, hugo, 'mrna');
                return 'mrna ' + (mrna === null ? 'none' : mrna);
            })
            .attr('width', width)
            .attr('height', RECT_HEIGHT);

        // remove all the null mrna squares
        mrna.filter(function(d) {
            var mrna = query.data(d, hugo, 'mrna');
            return mrna === null;
        }).remove();

//        var mutation_width = width + 2;
        var mut = sample_enter.append('rect')
            .attr('class', function(d) {
                var mutation = query.data(d, hugo, 'mutation');
                return 'mutation ' + (mutation === null ? 'none' : 'mut');
            })
//            .attr('x', -1)
            .attr('y', LITTLE_RECT_HEIGHT)
            .attr('width', width)
//            .attr('width', mutation_width)
            .attr('height', LITTLE_RECT_HEIGHT);

        // remove all the null mutation squares
        mut.filter(function(d) {
            var mutation = query.data(d, hugo, 'mutation');
            return mutation === null;
        }).remove();

        var up_triangle = getTrianglePath(true);
        var down_triangle = getTrianglePath(false);

        var rppa = sample_enter.append('path')
            .attr('class', 'rppa')
            .attr('d', function(d) {
                var rppa = query.data(d, hugo, 'rppa');

                if (rppa === UPREGULATED) {
                    return up_triangle;
                }
                if (rppa === DOWNREGULATED) {
                    return down_triangle;
                }
                if (rppa === null) {
                    return 'M 0 0';
                }
            });

        rppa.filter(function(d) {
            var rppa = query.data(d, hugo, 'rppa');

            return rppa === null;
        }).remove();

        // exit
        var sample_exit = sample.exit()
//            .transition()
//            .duration(750)
//            .attr('transform', function(d) {
//                return translate(3000, y(hugo));
//            })
            .remove();
    };

    /*
     * For the given oncoprint reference, returns the SVG Dom as string
     * for the body canvas.
     *
     * oncoprint - opaque reference to oncoprint system
     *
     */
//    var svg;
//    function GetOncoPrintBodyXML(svg) {
//
//        // outta here
//        return (new XMLSerializer()).serializeToString(svg);
//    }
//
//    var doXml = function() {
//        console.log(this);
////        this.elements['xml'].value=GetOncoPrintBodyXML(svg);
//        return true;
//    };

    that.draw = function() {

        svg = d3.select(wrapper).append('svg')
//        svg = d3.select(wrapper).insert('svg', ":first-child")
            .attr('width', getWidth(samples_all.length))
            .attr('height', getHeight());

        that.getSvg = function() { return svg; };

//        var svg_ify = $('<form>', {
//            action: "oncoprint_converter.svg",
//            enctype: "multipart/form-data",
//            method: "POST",
//            onsubmit: doXml,
//            target: "blank"
//        }).append("Get OncoPrint<input type=\"submit\" value=\"SVG\"/>");
//        $(wrapper).append(svg_ify);

        $("#oncoprint_header").append(
            '
Case Set: ' + params.case_set_str + '

'
            + '
Altered in ' + query.altered_samples.length + ' (' + d3.format("%")(query.percent_altered) + ')'
                + ' of cases

');

        x.domain(samples_all);

        gene_data.forEach(function(gene_obj) {

            var hugo = gene_obj.hugo;
            var cleaned_hugo = cleanHugo(hugo);

            // N.B. there is no data bound to g,
            // is this bad form?
            var track = svg.append('g')
                .attr('transform', translate(LABEL_PADDING, 0))
                .attr('class', 'track');

            var label = track.append('text')
                .attr('position', 'static')
                .attr('left', 0)
                .attr('x', -LABEL_PADDING)
                .attr('y', y(hugo) + .75 * RECT_HEIGHT);

            label.append('tspan')
                .attr('text-anchor', 'start')
                .text(gene_obj.hugo);

            label.append('tspan')
                .attr('text-anchor', 'end')
                .attr('x', 0 - 5)
                .text(gene_obj.percent_altered);

            toggleKey();

            redraw(samples_all, track, hugo);

        });
    };

    var toggleKey = function() {
        // show/hide the keys for the relevant data types
        var data_types = query.data_types;

        d3.select('#oncoprint_key').style('padding-left', LABEL_PADDING + "px");

        $('#oncoprint_key').children().each(function(i, el) {
            if(data_types.indexOf($(el).attr('id')) === -1) {
                $(el).hide();
            } else {
                $(el).show();
            }
        });
    };

    var transition = function() {
        // helper function

        var samples_visualized = getVisualizedSamples();
        var no_samples = samples_visualized.length;

        x.domain(samples_visualized);
        x.rangeBands([0, getXScale(no_samples)]);

        svg.selectAll('.track')[0].forEach(function(val, i) {

            var hugo = genes_list[i];

            var transition = d3.select(val).transition();

            transition.selectAll('.sample')
                .transition()
                .duration(1000)
                .attr('transform', function(d) {
                    return translate(x(d), y(hugo));
                });

            var rect_width = getRectWidth();
            transition.selectAll('rect')
                .transition()
                .duration(1000)
                .attr('width', rect_width);

            var up_triangle = getTrianglePath(true);
            var down_triangle = getTrianglePath(false);
            transition.selectAll('.rppa')
                .transition()
                .duration(1000)
                .attr('d', function(d) {
                    var rppa = query.data(d, hugo, 'rppa');

                    if (rppa === UPREGULATED) {
                        return up_triangle;
                    }
                    if (rppa === DOWNREGULATED) {
                        return down_triangle;
                    }
                });
        });

        svg.transition().duration(1000).style('width', getWidth(no_samples));
    };

    that.memoSort = function() {

        if (state.memo_sort) {
            return;
        }

        state.memo_sort = true;

        transition();
    };

    that.defaultSort = function() {

        if (!state.memo_sort) {
            return;
        }

        state.memo_sort = false;

        transition();
    };

    that.toggleWhiteSpace = function() {
        state.padding = !state.padding;

        transition();
    };

    that.scaleWidth = function(scalar) {
        state.width_scalar = scalar;
        transition();
    };

    that.toggleUnaltered = function() {
        state.show_unaltered = !state.show_unaltered;

        var samples_visualized = getVisualizedSamples();

        gene_data.forEach(function(gene, i) {
            var track = d3.select(d3.select(wrapper).selectAll('.track')[0][i]);
            redraw(samples_visualized, track, gene.hugo);
            transition();
        });
    };

    return that;
};
<commit_msg>added qtips<commit_after>var Oncoprint = function(wrapper, params) {
    var that = {};

    // constants
    var RECT_HEIGHT = 23;
    var LITTLE_RECT_HEIGHT = RECT_HEIGHT / 3;
//    var LABEL_PADDING = 130;

    var UPREGULATED = "UPREGULATED";
    var DOWNREGULATED = "DOWNREGULATED";

    // useful variables
    var data = params.data;
    var query = QueryGeneData(data);
    var genes_list = query.getGeneList();
    var gene_data = data.gene_data;
    var no_genes = gene_data.length;
    var samples_all = query.getSampleList()

    // useful functions
    var translate = function(x,y) {
        return "translate(" + x + "," + y + ")";
    };

    // todo: am i using this?  what happens when you submit MIR_##/##?
    var cleanHugo = function(hugo) {
        // can't have '/' in DOM id
        return hugo.replace("/", "_");
    };

    var LABEL_PADDING = (function() {
        var avg_char_width = 23;

        var list_char_no = genes_list.map(function(i) {
            return i.split("").length;
        });

        return d3.max(list_char_no) * avg_char_width;
    })();

    // global state of the oncoprint
    var state = {
        padding: true,
        width_scalar: 1,
        show_unaltered: true,
        memo_sort: false
    };

    // functions that get state

    var getVisualizedSamples = function() {
        // get state of samples
        var samples_copy = samples_all.map(function(i) { return i;});

        // todo: note that you must sort first!
        // MemoSort behaves differently when it has different lists, that is,
        // it does not deterministically deal with samples that are equal
        if (state.memo_sort) {
            samples_copy = MemoSort(data, samples_copy, genes_list).sort();
        }

        if (!state.show_unaltered) {
            samples_copy = samples_copy.filter(query.isSampleAltered);
        }

        return samples_copy;
    };

    var getRectWidth = function() {
        var unscaled = 5.5;
        return state.width_scalar * unscaled;
    };

    var getTriangleBase = function() {
        return getRectWidth() / 2;
    };

    var getTrianglePath = function(up) {
        var base = getTriangleBase();

        if (up) {
            return "M 0 " + LITTLE_RECT_HEIGHT + " l "  + base + " -" + LITTLE_RECT_HEIGHT
                + " l " + base + " " + LITTLE_RECT_HEIGHT + " l 0 0";
//                return "M 0 7 l 2.75 -7 l 2.75 7 l 0 0";
        }
//        return "M 0 16 l " + base + " 7 l " + base + " -7 l 0 0";
        return "M 0 15 l " + base + " " + LITTLE_RECT_HEIGHT + " l "
            + base + " -" + LITTLE_RECT_HEIGHT + " l 0 0";
//            return "M 0 16 l 2.75 7 l 2.75 -7 l 0 0";
    };

    var getRectPadding = function() {
        var unscaled = 3;
        return state.padding ? (state.width_scalar * unscaled) : 0;
    };

    var getXScale = function(no_samples) {
        return (getRectWidth() + getRectPadding()) * no_samples;
    };

    var getWidth = function(no_samples) {
        return getXScale(no_samples) + LABEL_PADDING + (2 * (getRectWidth() + getRectPadding()));
    };

    var getHeight = function() {
        return (RECT_HEIGHT + 7) * no_genes;
    };

    // scales
    var x = d3.scale.ordinal().rangeBands([0, getXScale(samples_all.length)], 0);

    var y = d3.scale.ordinal().rangeBands([0, getHeight()], 0)
        .domain(genes_list);

    d3.select(wrapper)
        .style('width', '1300px')
        .style('overflow-x', 'auto')
        .style('overflow-y', 'hidden');

    // functions that echo
    that.wrapper = wrapper;

    that.getData = function() {
        return params.data;
    };

    var redraw = function(samples_visualized, track, hugo) {
        var join_with_hugo = samples_visualized.map(function(i) {
            return {
                sample: i,
                hugo: hugo
            };
        });

        var sample = track.selectAll('.sample')
            .data(join_with_hugo, function(d) { return d;});

        // enter
        var sample_enter = sample.enter().append('g')
            .attr('class', 'sample')
            .attr('transform', function(d) {
                return translate(x(d.sample), y(hugo));
            });

        var width = getRectWidth();

        var cna = sample_enter.append('rect')
            .attr('class', function(d) {
                var cna = query.data(d.sample, hugo, 'cna');
                return 'cna ' + (cna === null ? 'none' : cna);
            })
            .attr('width', width)
            .attr('height', RECT_HEIGHT);

        var mrna = sample_enter.append('rect')
            .attr('class', function(d) {
                var mrna = query.data(d.sample, hugo, 'mrna');
                return 'mrna ' + (mrna === null ? 'none' : mrna);
            })
            .attr('width', width)
            .attr('height', RECT_HEIGHT);

        // remove all the null mrna squares
        mrna.filter(function(d) {
            var mrna = query.data(d.sample, hugo, 'mrna');
            return mrna === null;
        }).remove();

//        var mutation_width = width + 2;
        var mut = sample_enter.append('rect')
            .attr('class', function(d) {
                var mutation = query.data(d.sample, hugo, 'mutation');
                return 'mutation ' + (mutation === null ? 'none' : 'mut');
            })
//            .attr('x', -1)
            .attr('y', LITTLE_RECT_HEIGHT)
            .attr('width', width)
//            .attr('width', mutation_width)
            .attr('height', LITTLE_RECT_HEIGHT);

        // remove all the null mutation squares
        mut.filter(function(d) {
            var mutation = query.data(d.sample, hugo, 'mutation');
            return mutation === null;
        }).remove();

        var up_triangle = getTrianglePath(true);
        var down_triangle = getTrianglePath(false);

        var rppa = sample_enter.append('path')
            .attr('class', 'rppa')
            .attr('d', function(d) {
                var rppa = query.data(d.sample, hugo, 'rppa');

                if (rppa === UPREGULATED) {
                    return up_triangle;
                }
                if (rppa === DOWNREGULATED) {
                    return down_triangle;
                }
                if (rppa === null) {
                    return 'M 0 0';
                }
            });

        rppa.filter(function(d) {
            var rppa = query.data(d.sample, hugo, 'rppa');

            return rppa === null;
        }).remove();

        // exit
        var sample_exit = sample.exit()
//            .transition()
//            .duration(750)
//            .attr('transform', function(d) {
//                return translate(3000, y(hugo));
//            })
            .remove();
    };

    /*
     * For the given oncoprint reference, returns the SVG Dom as string
     * for the body canvas.
     *
     * oncoprint - opaque reference to oncoprint system
     *
     */
//    var svg;
//    function GetOncoPrintBodyXML(svg) {
//
//        // outta here
//        return (new XMLSerializer()).serializeToString(svg);
//    }
//
//    var doXml = function() {
//        console.log(this);
////        this.elements['xml'].value=GetOncoPrintBodyXML(svg);
//        return true;
//    };

    that.draw = function() {

        svg = d3.select(wrapper).append('svg')
//        svg = d3.select(wrapper).insert('svg', ":first-child")
            .attr('width', getWidth(samples_all.length))
            .attr('height', getHeight());

        that.getSvg = function() { return svg; };

//        var svg_ify = $('<form>', {
//            action: "oncoprint_converter.svg",
//            enctype: "multipart/form-data",
//            method: "POST",
//            onsubmit: doXml,
//            target: "blank"
//        }).append("Get OncoPrint<input type=\"submit\" value=\"SVG\"/>");
//        $(wrapper).append(svg_ify);

        $("#oncoprint_header").append(
            '
Case Set: ' + params.case_set_str + '

'
            + '
Altered in ' + query.altered_samples.length + ' (' + d3.format("%")(query.percent_altered) + ')'
                + ' of cases

');

        x.domain(samples_all);

        gene_data.forEach(function(gene_obj) {

            var hugo = gene_obj.hugo;
            var cleaned_hugo = cleanHugo(hugo);

            // N.B. there is no data bound to g,
            // is this bad form?
            var track = svg.append('g')
                .attr('transform', translate(LABEL_PADDING, 0))
                .attr('class', 'track');

            var label = track.append('text')
                .attr('position', 'static')
                .attr('left', 0)
                .attr('x', -LABEL_PADDING)
                .attr('y', y(hugo) + .75 * RECT_HEIGHT);

            label.append('tspan')
                .attr('text-anchor', 'start')
                .text(gene_obj.hugo);

            label.append('tspan')
                .attr('text-anchor', 'end')
                .attr('x', 0 - 5)
                .text(gene_obj.percent_altered);

            toggleKey();

            redraw(samples_all, track, hugo);
        });

        // begin qtip
        var formatMutation = function(sample, hugo) {
            var mutation = query.data(sample, hugo, 'mutation');

            if (mutation !== null) {
                return "Mutation: " + mutation + "
";
            }
            return "";
        };

        var patientViewUrl = function(sample_id) {
            var href = "http://localhost:8080/public-portal/tumormap.do?case_id=" + sample_id
                + "&cancer_study_id=" + params.cancer_study_id;

            return "" + sample_id + "";
        };

        d3.selectAll('.sample').each(function(d, i) {
            $(this).qtip({
                content: {text: ''
                    + formatMutation(d.sample, d.hugo)
                    + patientViewUrl(d.sample)
                    + ''},

                hide: { fixed: true, delay: 100 },
                style: { classes: 'ui-tooltip-light ui-tooltip-rounded ui-tooltip-shadow ui-tooltip-lightyellow' },
                position: {my:'top center',at:'bottom center'}
            });
        });
        // end qtip
    };

    var toggleKey = function() {
        // show/hide the keys for the relevant data types
        var data_types = query.data_types;

        d3.select('#oncoprint_key').style('padding-left', LABEL_PADDING + "px");

        $('#oncoprint_key').children().each(function(i, el) {
            if(data_types.indexOf($(el).attr('id')) === -1) {
                $(el).hide();
            } else {
                $(el).show();
            }
        });
    };

    var transition = function() {
        // helper function

        var samples_visualized = getVisualizedSamples();
        var no_samples = samples_visualized.length;

        x.domain(samples_visualized);
        x.rangeBands([0, getXScale(no_samples)]);

        svg.selectAll('.track')[0].forEach(function(val, i) {

            var hugo = genes_list[i];

            var transition = d3.select(val).transition();

            transition.selectAll('.sample')
                .transition()
                .duration(1000)
                .attr('transform', function(d) {
                    return translate(x(d.sample), y(hugo));
                });

            var rect_width = getRectWidth();
            transition.selectAll('rect')
                .transition()
                .duration(1000)
                .attr('width', rect_width);

            var up_triangle = getTrianglePath(true);
            var down_triangle = getTrianglePath(false);
            transition.selectAll('.rppa')
                .transition()
                .duration(1000)
                .attr('d', function(d) {
                    var rppa = query.data(d.sample, hugo, 'rppa');

                    if (rppa === UPREGULATED) {
                        return up_triangle;
                    }
                    if (rppa === DOWNREGULATED) {
                        return down_triangle;
                    }
                });
        });

        svg.transition().duration(1000).style('width', getWidth(no_samples));
    };

    that.memoSort = function() {

        if (state.memo_sort) {
            return;
        }

        state.memo_sort = true;

        transition();
    };

    that.defaultSort = function() {

        if (!state.memo_sort) {
            return;
        }

        state.memo_sort = false;

        transition();
    };

    that.toggleWhiteSpace = function() {
        state.padding = !state.padding;

        transition();
    };

    that.scaleWidth = function(scalar) {
        state.width_scalar = scalar;
        transition();
    };

    that.toggleUnaltered = function() {
        state.show_unaltered = !state.show_unaltered;

        var samples_visualized = getVisualizedSamples();

        gene_data.forEach(function(gene, i) {
            var track = d3.select(d3.select(wrapper).selectAll('.track')[0][i]);
            redraw(samples_visualized, track, gene.hugo);
            transition();
        });
    };

    return that;
};
<|endoftext|>


<commit_before>{
    init: function(elevators, floors) {
        for (var e=0; e<elevators.length; e++){
            var elevator = elevators[e];
            setElevatorHandlers(elevator);
        }

        function setElevatorHandlers(elevator){
            elevator.on("idle", function() {
                setElevatorSignals(elevator);
                //if not at top go one up
                if (elevator.currentFloor() < floors.length-1){
                    elevator.goToFloor(elevator.currentFloor() + 1);
                }
                //if at top go to 0
                else {
                    elevator.goToFloor(0);
                }

                });

            elevator.on("floor_button_pressed", function(floorNum){
                console.log("Pressed floors: ",elevator.getPressedFloors());
                console.log("Destination Queue: ",elevator.destinationQueue);
                setElevatorSignals(elevator);
                elevator.goToFloor(floorNum);
                optimizeOrder(elevator);
            });
        }

        function setElevatorSignals(elevator){
            if (elevator.currentFloor() < elevator.destinationQueue[0]){
                    down = false;
                    up = true;
                }
            else if (elevator.currentFloor() > elevator.destinationQueue[0]){
                down = true;
                up = false;
            }
            else{
                down = true;
                up = true;
            }
            elevator.goingDownIndicator(down);
            elevator.goingUpIndicator(up);
        }

        function optimizeOrder(elevator){
            var pressed = elevator.getPressedFloors();
            var temp = elevator.getPressedFloors();
            var passed=elevator.destinationQueue;
            var index = 0;
            //up - permutes the queue to be in ascending order starting at current floor
            if (elevator.goingUpIndicator() && !elevator.goingDownIndicator()){
                for (var i; i<pressed.length; i++){
                    if (pressed[i] >= elevator.currentFloor()){
                        index = i;
                        break;
                    }
                }
            pressed.splice(0,i);
            temp.splice(i,temp.length);
            pressed.concat(temp);
            elevator.destinationQueue = pressed;
            console.log("Optimized UP: ", elevator.destinationQueue);
            }

        //down - permutes the queue to be in descending order starting at current floor
        if (elevator.goingDownIndicator() && !elevator.goingUpIndicator()){
                for (var i; i<pressed.length; i++){
                    if (pressed[i] <= elevator.currentFloor()){
                        index = i-1;
                        break;
                    }
                }
            pressed.splice(0,i);
            temp.splice(i,temp.length);
            var reverse=[];
            for (var j = pressed.length; j>pressed.length; j--){
                reverse.append(pressed[j]);
            }
            reverse.concat(temp);
            elevator.destinationQueue = reverse;
            // pressed.concat(temp);
            // elevator.destinationQueue = pressed;
            console.log("Optimized Down: ", elevator.destinationQueue);
        }
     }

},

    update: function(dt, elevators, floors) {
        // We normally don't need to do anything here
    }
}<commit_msg>Changed alot of stuff - probably for the worse<commit_after>{
    init: function(elevators, floors) {
        for (var e=0; e<elevators.length; e++){
            var elevator = elevators[e];
            setElevatorHandlers(elevator);
        }
        for (var f=0; f<floors.length; f++){
            var floor = floors[f];
            setFloorHandlers(floor);
        }

        function setFloorHandlers(floor){
            floor.on("up_button_pressed", function() {
            // Maybe tell an elevator to go to this floor?
        })
            floor.on("down_button_pressed", function() {
        // Maybe tell an elevator to go to this floor?
        })
        }

        function setElevatorHandlers(elevator){
            elevator.on("idle", function() {
                //console.log("idle start: ", elevator.destinationQueue);
                //if not at top go one up
                elevator.goToFloor(0)
                if (elevator.currentFloor() < floors.length-1){
                    elevator.goToFloor(elevator.currentFloor() + 1);
                }
                //if at top go to 0
                else {
                    elevator.goToFloor(0);
                }
                setElevatorSignals(elevator);
                //console.log("idle end: ", elevator.destinationQueue);
                });

            elevator.on("floor_button_pressed", function(floorNum){
                //console.log("floor_button_pressed start: ", elevator.destinationQueue);
                elevator.goToFloor(floorNum);
                //console.log("Pressed floors: ",elevator.getPressedFloors());
                //console.log("Destination Queue: ",elevator.destinationQueue);

                optimizeOrder(elevator);
                setElevatorSignals(elevator);
                //console.log("floor_button_pressed end: ", elevator.destinationQueue);
            });

            elevator.on("stopped_at_floor", function(floorNum) {
                //console.log("stopped_at_floor start: ", elevator.destinationQueue);
                optimizeOrder(elevator);
                setElevatorSignals(elevator);
                //console.log("stopped_at_floor end: ", elevator.destinationQueue);
            });
        }

        function setElevatorSignals(elevator){
            //console.log("setElevatorSignals start: ", elevator.destinationQueue);
            if (elevator.currentFloor() < elevator.destinationQueue[0]){
                    down = false;
                    up = true;
                }
            else if (elevator.currentFloor() > elevator.destinationQueue[0]){
                down = true;
                up = false;
            }
            else{
                down = true;
                up = true;
            }
            elevator.goingDownIndicator(down);
            elevator.goingUpIndicator(up);
            //console.log("setElevatorSignals end: ", elevator.destinationQueue);
        }

        // may be able to simplify this alot if people don't get on elevator going wrong way
        //need testing to determine their behavior
        function optimizeOrder(elevator){
            if (elevator.goingUpIndicator() && !elevator.goingDownIndicator()){
                //console.log("Optimize start: ", elevator.destinationQueue);
                elevator.destinationQueue = elevator.getPressedFloors();
                //console.log("Optimize up end: ", elevator.destinationQueue);
            }
            if (elevator.goingDownIndicator() && !elevator.goingUpIndicator()){
                //console.log("Optimize down start: ", elevator.destinationQueue);
                elevator.destinationQueue = elevator.getPressedFloors().reverse();
                //console.log("Optimize down end: ", elevator.destinationQueue);
            }
        //     var pressed = elevator.getPressedFloors();
        //     var temp = elevator.getPressedFloors();
        //     var passed=elevator.destinationQueue;
        //     var index = 0;
        //     //up - permutes the queue to be in ascending order starting at current floor
        //     if (elevator.goingUpIndicator() && !elevator.goingDownIndicator()){
        //         for (var i; i<pressed.length; i++){
        //             if (pressed[i] >= elevator.currentFloor()){
        //                 index = i;
        //                 break;
        //             }
        //         }
        //     pressed.splice(0,i);
        //     temp.splice(i,temp.length);
        //     pressed.concat(temp);
        //     elevator.destinationQueue = pressed;
        //     //console.log("Optimized Up: ", elevator.destinationQueue);
        //     }

        // //down - permutes the queue to be in descending order starting at current floor
        // if (elevator.goingDownIndicator()){
        //         for (var i=0; i<pressed.length; i++){
        //             if (pressed[i] >= elevator.currentFloor()){
        //                 index = i-1;
        //                 break;
        //             }
        //         }
        //     pressed.splice(0,i);
        //     temp.splice(i,temp.length);
        //     var reverse=[];
        //     for (var j = pressed.length; j>pressed.length; j--){
        //         reverse.append(pressed[j]);
        //     }
        //     reverse.concat(temp);
        //     elevator.destinationQueue = reverse;
        //     //console.log("Optimized Down: ", elevator.destinationQueue);

        // }
      }

},

    update: function(dt, elevators, floors) {
        // We normally don't need to do anything here
    }
}<|endoftext|>


<commit_before>/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, global-require */

// eslint-disable-next-line no-underscore-dangle
global.__fbDisableExceptionsManager = true;

const addons = require('@storybook/addons').default;
const ReactNative = require('react-native');

const DevSettings = ReactNative.NativeModules.DevSettings;
const ExceptionsManager = require('react-native/Libraries/Core/ExceptionsManager');
const ErrorUtils = require('react-native/Libraries/Core/ErrorUtils');
const {
  resetLoadingImages,
  awaitImagesLoaded,
} = require('./ready-state-manager');

const MESSAGE_PREFIX = 'loki:';

let customErrorHandler;

function genericErrorHandler(e, isFatal) {
  if (customErrorHandler) {
    customErrorHandler(e, isFatal);
  } else {
    try {
      ExceptionsManager.handleException(e, isFatal);
    } catch (ee) {
      // eslint-disable-next-line no-console
      console.log('Failed to print error: ', ee.message);
      throw e;
    }
  }
}

ErrorUtils.setGlobalHandler(genericErrorHandler);

async function getPrettyError(error) {
  if (ReactNative.NativeModules.ExceptionsManager) {
    const parseErrorStack = require('react-native/Libraries/Core/Devtools/parseErrorStack');
    const symbolicateStackTrace = require('react-native/Libraries/Core/Devtools/symbolicateStackTrace');
    const stack = parseErrorStack(error);
    const prettyStack = await symbolicateStackTrace(stack);
    return {
      message: error.message,
      stack: prettyStack,
    };
  }
  return {
    message: error.message,
  };
}

function getAddonsChannel() {
  return new Promise((resolve, reject) => {
    let tries = 0;
    const attemptChannel = () => {
      tries++;
      try {
        const channel = addons.getChannel();
        resolve(channel);
      } catch (error) {
        if (tries < 10) {
          setTimeout(attemptChannel, 100);
        } else {
          reject(
            new Error(`Failed getting addons channel after ${tries} tries`)
          );
        }
      }
    };
    attemptChannel();
  });
}

async function configureStorybook() {
  // Monkey patch `Image`
  Object.defineProperty(ReactNative, 'Image', {
    configurable: true,
    enumerable: true,
    get: () => require('./ready-state-emitting-image'),
  });

  const channel = await getAddonsChannel();
  const platform = ReactNative.Platform.OS;

  const on = (eventName, callback) =>
    channel.on(`${MESSAGE_PREFIX}${eventName}`, params => {
      if (params && params.platform === platform) {
        callback(params);
      }
    });

  const emit = (eventName, params = {}) =>
    channel.emit(
      `${MESSAGE_PREFIX}${eventName}`,
      Object.assign({ platform }, params)
    );

  const originalState = {
    statusBarHidden: false, // TODO: get actual value
    disableYellowBox: console.disableYellowBox, // eslint-disable-line no-console
  };

  const restore = () => {
    customErrorHandler = null;
    ReactNative.StatusBar.setHidden(originalState.statusBarHidden);
    // eslint-disable-next-line no-console
    console.disableYellowBox = originalState.disableYellowBox;
  };

  const prepare = () => {
    customErrorHandler = async (error, isFatal) => {
      if (isFatal) {
        emit('error', {
          error: await getPrettyError(error),
        });
        restore();
        setTimeout(() => {
          DevSettings.reload();
        }, 1000);
      }
    };
    DevSettings.setHotLoadingEnabled(false);
    ReactNative.StatusBar.setHidden(true, 'none');
    // eslint-disable-next-line no-console
    console.disableYellowBox = true;
  };

  on('prepare', () => {
    prepare();
    setTimeout(() => emit('didPrepare'), platform === 'android' ? 500 : 0);
  });

  on('restore', () => {
    restore();
    emit('didRestore');
  });

  channel.on('setCurrentStory', () => {
    awaitImagesLoaded().finally(count => {
      emit('imagesLoaded', { count });
    });
    resetLoadingImages();
  });
}

module.exports = configureStorybook;
<commit_msg>Use ErrorUtils global to support react-native 0.49<commit_after>/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, global-require */

const addons = require('@storybook/addons').default;
const ReactNative = require('react-native');

const DevSettings = ReactNative.NativeModules.DevSettings;
const ExceptionsManager = require('react-native/Libraries/Core/ExceptionsManager');
const {
  resetLoadingImages,
  awaitImagesLoaded,
} = require('./ready-state-manager');

const MESSAGE_PREFIX = 'loki:';

let customErrorHandler;

function injectLokiGlobalErrorHandler() {
  if (!global.ErrorUtils) {
    return;
  }

  function genericErrorHandler(e, isFatal) {
    if (customErrorHandler) {
      customErrorHandler(e, isFatal);
    }
    try {
      ExceptionsManager.handleException(e, isFatal);
    } catch (ee) {
      // eslint-disable-next-line no-console
      console.log('Failed to print error: ', ee.message);
      throw e;
    }
  }

  global.ErrorUtils.setGlobalHandler(genericErrorHandler);
}

async function getPrettyError(error) {
  const message = String(error.message).split('\n')[0];
  if (ReactNative.NativeModules.ExceptionsManager) {
    const parseErrorStack = require('react-native/Libraries/Core/Devtools/parseErrorStack');
    const symbolicateStackTrace = require('react-native/Libraries/Core/Devtools/symbolicateStackTrace');
    const stack = parseErrorStack(error);
    const prettyStack = await symbolicateStackTrace(stack);
    return {
      message,
      stack: prettyStack,
    };
  }
  return {
    message,
  };
}

function getAddonsChannel() {
  return new Promise((resolve, reject) => {
    let tries = 0;
    const attemptChannel = () => {
      tries++;
      try {
        const channel = addons.getChannel();
        resolve(channel);
      } catch (error) {
        if (tries < 10) {
          setTimeout(attemptChannel, 100);
        } else {
          reject(
            new Error(`Failed getting addons channel after ${tries} tries`)
          );
        }
      }
    };
    attemptChannel();
  });
}

async function configureStorybook() {
  injectLokiGlobalErrorHandler();

  // Monkey patch `Image`
  Object.defineProperty(ReactNative, 'Image', {
    configurable: true,
    enumerable: true,
    get: () => require('./ready-state-emitting-image'),
  });

  const channel = await getAddonsChannel();
  const platform = ReactNative.Platform.OS;

  const on = (eventName, callback) =>
    channel.on(`${MESSAGE_PREFIX}${eventName}`, params => {
      if (params && params.platform === platform) {
        callback(params);
      }
    });

  const emit = (eventName, params = {}) =>
    channel.emit(
      `${MESSAGE_PREFIX}${eventName}`,
      Object.assign({ platform }, params)
    );

  const originalState = {
    statusBarHidden: false, // TODO: get actual value
    disableYellowBox: console.disableYellowBox, // eslint-disable-line no-console
  };

  const restore = () => {
    customErrorHandler = null;
    ReactNative.StatusBar.setHidden(originalState.statusBarHidden);
    // eslint-disable-next-line no-console
    console.disableYellowBox = originalState.disableYellowBox;
  };

  const prepare = () => {
    customErrorHandler = async (error, isFatal) => {
      if (isFatal) {
        emit('error', {
          error: await getPrettyError(error),
        });
        restore();
        setTimeout(() => {
          DevSettings.reload();
        }, 1000);
      }
    };
    DevSettings.setHotLoadingEnabled(false);
    ReactNative.StatusBar.setHidden(true, 'none');
    // eslint-disable-next-line no-console
    console.disableYellowBox = true;
  };

  on('prepare', () => {
    prepare();
    setTimeout(() => emit('didPrepare'), platform === 'android' ? 500 : 0);
  });

  on('restore', () => {
    restore();
    emit('didRestore');
  });

  channel.on('setCurrentStory', () => {
    awaitImagesLoaded().finally(count => {
      emit('imagesLoaded', { count });
    });
    resetLoadingImages();
  });
}

module.exports = configureStorybook;
<|endoftext|>


<commit_before>import Promise from 'bluebird';
import moment from 'moment-timezone';
import _ from 'lodash';
import merge from 'merge-options';
import models, { Op } from '../../server/models';
import activities from '../../server/constants/activities';
import emailLib from '../../server/lib/email';
import expenseStatus from '../../server/constants/expense_status';
import { formatCurrency } from '../../server/lib/utils';
import showdown from 'showdown';
const markdownConverter = new showdown.Converter();

if (!process.env.MANUAL) {
  onlyExecuteInProdOnMondays();
}

const {
  Activity,
  Collective,
  Expense,
  PaymentMethod,
  Transaction,
} = models;

const createdLastWeek = getTimeFrame('createdAt', process.env.START_DATE);
const updatedLastWeek = getTimeFrame('updatedAt', process.env.START_DATE);

const weekBefore = moment(process.env.START_DATE).tz('America/New_York').startOf('isoWeek').subtract(1, 'week');
const title = `Weekly Platform Report`;
const subtitle = `Week ${weekBefore.week()} from ${weekBefore.format('YYYY-MM-DD')} till ${moment(process.env.START_DATE).format('YYYY-MM-DD')}`;
const createdWeekBefore = getTimeFrame('createdAt', weekBefore);
const updatedWeekBefore = getTimeFrame('updatedAt', weekBefore);
const donation = {
  where: {
    OrderId: {
      [Op.not]: null
    }
  }
};

const pendingExpense = { where: { status: expenseStatus.PENDING } };
const approvedExpense = { where: { status: expenseStatus.APPROVED } };
const rejectedExpense = { where: { status: expenseStatus.REJECTED } };
const paidExpense = { where : { status: expenseStatus.PAID } };

const credit = { where: {type: 'CREDIT'}};

const excludeOcTeam = { where: {
  CollectiveId: {
    [Op.not]: 1 // OpenCollective collective
  }
} };

const lastWeekDonations = merge({}, createdLastWeek, donation, excludeOcTeam, credit);
const lastWeekExpenses = merge({}, updatedLastWeek, excludeOcTeam);

const pendingLastWeekExpenses = merge({}, lastWeekExpenses, pendingExpense);
const approvedLastWeekExpenses = merge({}, lastWeekExpenses, approvedExpense);
const rejectedLastWeekExpenses = merge({}, lastWeekExpenses, rejectedExpense);
const paidLastWeekExpenses = merge({}, lastWeekExpenses, paidExpense);

const weekBeforeDonations = merge({}, createdWeekBefore, donation, excludeOcTeam, credit);
const paidWeekBeforeExpenses = merge({}, updatedWeekBefore, excludeOcTeam, paidExpense);

const collectiveByCurrency = (table) => {
  return {
    plain: false,
    group: [ `${table}.currency` ],
    attributes: ['currency'],
    order: ['currency']
  }
};

const onlyIncludeCollectiveType = {
  include: [{
    model: Collective,
    as: 'collective',
    where: {
      type: 'COLLECTIVE'
    }
  }]
};

const service = (service) => {
  return {
    include: [{
      attributes: [],
      model: PaymentMethod,
      required: true,
      where: {
        service,
      },
    }],
  };
};

const paypalReceived = { where: { type: activities.WEBHOOK_PAYPAL_RECEIVED } };

const distinct = {
  plain: false,
  distinct: true
};

export default function run() {
  return Promise.props({

    // Donation statistics

    stripeDonationCount: Transaction.count(merge({}, lastWeekDonations, service('stripe'))),

    priorStripeDonationCount: Transaction.count(merge({}, weekBeforeDonations, service('stripe'))),

    manualDonationCount: Transaction.count(merge({}, lastWeekDonations, service('opencollective'))),

    priorManualDonationCount: Transaction.count(merge({}, weekBeforeDonations, service('opencollective'))),

    paypalDonationCount: Transaction.count(merge({}, lastWeekDonations, service('paypal'))),

    priorPaypalDonationCount: Transaction.count(merge({}, weekBeforeDonations, service('paypal'))),

    stripeDonationAmount: Transaction
      .aggregate('amount', 'SUM', merge({}, lastWeekDonations, collectiveByCurrency('Transaction'))),

    priorStripeDonationAmount: Transaction
      .aggregate('amount', 'SUM', merge({}, weekBeforeDonations, collectiveByCurrency('Transaction'))),

    manualDonationAmount: Transaction
      .aggregate('amount', 'SUM', merge({}, lastWeekDonations, collectiveByCurrency('Transaction'), service('opencollective'))),

    priorManualDonationAmount: Transaction
      .sum('amount', merge({}, weekBeforeDonations, service('opencollective'))),

    paypalReceivedCount: Activity.count(merge({}, createdLastWeek, paypalReceived)),

    paypalDonationAmount: Transaction
      .sum('amount', merge({}, lastWeekDonations, service('paypal'))),

    priorPaypalDonationAmount: Transaction
      .sum('amount', merge({}, weekBeforeDonations, service('paypal'))),

    // Expense statistics

    pendingExpenseCount: Expense.count(pendingLastWeekExpenses),

    approvedExpenseCount: Expense.count(approvedLastWeekExpenses),

    rejectedExpenseCount: Expense.count(rejectedLastWeekExpenses),

    paidExpenseCount: Expense.count(paidLastWeekExpenses),

    priorPaidExpenseCount: Expense.count(paidWeekBeforeExpenses),

    pendingExpenseAmount: Expense
      .aggregate('amount', 'SUM', merge({}, pendingLastWeekExpenses, collectiveByCurrency('Expense')))
      .map(row => `${row.currency} ${formatCurrency(row.SUM, row.currency)}`),

    approvedExpenseAmount: Expense
      .aggregate('amount', 'SUM', merge({}, approvedLastWeekExpenses, collectiveByCurrency('Expense')))
      .map(row => `${row.currency} ${formatCurrency(row.SUM, row.currency)}`),

    rejectedExpenseAmount: Expense
      .aggregate('amount', 'SUM', merge({}, rejectedLastWeekExpenses, collectiveByCurrency('Expense')))
      .map(row => `${row.currency} ${formatCurrency(row.SUM, row.currency)}`),

    paidExpenseAmount: Expense
      .aggregate('amount', 'SUM', merge({}, paidLastWeekExpenses, collectiveByCurrency('Expense'))),

    priorPaidExpenseAmount: Expense
      .aggregate('amount', 'SUM', merge({}, paidWeekBeforeExpenses, collectiveByCurrency('Expense'))),

    // Collective statistics

    activeCollectivesWithTransactions: Transaction
      .findAll(merge({attributes: ['CollectiveId'] }, createdLastWeek, distinct, excludeOcTeam, onlyIncludeCollectiveType))
      .map(row => row.CollectiveId),

    priorActiveCollectivesWithTransactions: Transaction
      .findAll(merge({attributes: ['CollectiveId'] }, createdWeekBefore, distinct, excludeOcTeam, onlyIncludeCollectiveType))
      .map(row => row.CollectiveId),

    activeCollectivesWithExpenses: Expense
      .findAll(merge({attributes: ['CollectiveId'] }, updatedLastWeek, distinct, excludeOcTeam))
      .map(row => row.CollectiveId),

    priorActiveCollectivesWithExpenses: Expense
      .findAll(merge({attributes: ['CollectiveId'] }, updatedWeekBefore, distinct, excludeOcTeam))
      .map(row => row.CollectiveId),

    newCollectives: Collective
      .findAll(merge({}, { attributes: ['slug', 'name', 'tags'], where: { type: 'COLLECTIVE' } }, createdLastWeek))
      .map(collective => {
        const openSource = collective.dataValues.tags && collective.dataValues.tags.indexOf('open source') !== -1;
        return `[${collective.dataValues.name || collective.dataValues.slug}](https://opencollective.com/${collective.dataValues.slug}) (${openSource ? 'open source' : collective.dataValues.tags})`
      }),

    priorNewCollectivesCount: Collective.count(merge({}, { where: { type: 'COLLECTIVE' } }, createdWeekBefore)),

  }).then(results => {
    results.activeCollectiveCount = _.union(results.activeCollectivesWithTransactions, results.activeCollectivesWithExpenses).length;
    results.priorActiveCollectiveCount = _.union(results.priorActiveCollectivesWithTransactions, results.priorActiveCollectivesWithExpenses).length;
    const report = reportString(results);
    console.log(report);
    const html = markdownConverter.makeHtml(report);
    return emailLib.sendMessage('team@opencollective.com', title, html, { tag: 'platform-weekly-report' });
  }).then(() => {
    console.log('Weekly reporting done!');
    process.exit();
  }).catch(err => {
    console.log('err', err);
    process.exit();
  });
}

/**
 * Heroku scheduler only has daily or hourly cron jobs, we only want to run
 * this script once per week on Monday (1). If the day is not Monday on production
 * we won't execute the script
 */
function onlyExecuteInProdOnMondays() {
  const today = new Date();
  if (process.env.NODE_ENV === 'production' && today.getDay() !== 1) {
    console.log('NODE_ENV is production and day is not Monday, script aborted!');
    process.exit();
  }
}

function getTimeFrame(propName, startDate) {
  const thisWeekStartRaw = moment(startDate) // will default to now if START_DATE is not set
    .tz('America/New_York')
    .startOf('isoWeek')
    .add(9, 'hours');
  const thisWeekStart = thisWeekStartRaw.format();
  const lastWeekStart = thisWeekStartRaw.subtract(1, 'week').format();

  return {
    where: {
      [propName]: {
        [Op.gt]: lastWeekStart,
        [Op.lt]: thisWeekStart
      }
    }
  };
}

function reportString({
  activeCollectiveCount,
  approvedExpenseAmount,
  approvedExpenseCount,
  stripeDonationAmount,
  stripeDonationCount,
  manualDonationAmount,
  manualDonationCount,
  newCollectives,
  paidExpenseAmount,
  paidExpenseCount,
  paypalDonationAmount,
  paypalDonationCount,
  pendingExpenseAmount,
  pendingExpenseCount,
  priorActiveCollectiveCount,
  priorStripeDonationAmount,
  priorStripeDonationCount,
  priorManualDonationAmount,
  priorManualDonationCount,
  priorNewCollectivesCount,
  priorPaidExpenseAmount,
  priorPaypalDonationAmount,
  priorPaypalDonationCount,
  priorPaidExpenseCount,
  rejectedExpenseAmount,
  rejectedExpenseCount,
}) {
  return `# ${title}
${subtitle}

## Donations
  - STRIPE: ${stripeDonationCount} donations received (${compareNumbers(stripeDonationCount, priorStripeDonationCount)})
    ${stripeDonationAmount.map(({ SUM, currency }) => `* ${currency} ${formatCurrency(SUM, currency)} (${compareNumbers(SUM, getSum(priorStripeDonationAmount, currency), (n) => formatCurrency(n, currency))})`).join('\n    ')}
  - PAYPAL: ${paypalDonationCount} paypal donations received (${compareNumbers(paypalDonationCount, priorPaypalDonationCount)})
    * USD ${formatCurrency(paypalDonationAmount, 'USD')} (${compareNumbers(paypalDonationAmount, priorPaypalDonationAmount, (n) => formatCurrency(n, 'USD'))})
  - MANUAL: ${manualDonationCount} donations received (${compareNumbers(manualDonationCount, priorManualDonationCount)})
    ${manualDonationAmount.map(({ SUM, currency }) => `* ${currency} ${formatCurrency(SUM, currency)} (${compareNumbers(SUM, getSum(priorManualDonationAmount, currency), (n) => formatCurrency(n, currency))})`).join('\n    ')}

## Expenses
  - ${paidExpenseCount} paid expenses (${compareNumbers(paidExpenseCount, priorPaidExpenseCount)})
    ${paidExpenseAmount.map(({ SUM, currency }) => `* ${currency} ${formatCurrency(SUM, currency)}  (${compareNumbers(SUM, getSum(priorPaidExpenseAmount, currency), (n) => formatCurrency(n, currency))})`).join('\n    ')}
  - ${pendingExpenseCount} pending expenses${displayTotals(pendingExpenseAmount)}
  - ${approvedExpenseCount} approved expenses${displayTotals(approvedExpenseAmount)}
  - ${rejectedExpenseCount} rejected expenses${displayTotals(rejectedExpenseAmount)}

## Collectives
  - ${activeCollectiveCount} active collectives (${compareNumbers(activeCollectiveCount, priorActiveCollectiveCount)})
  - ${newCollectives.length} new collectives (${compareNumbers(newCollectives.length, priorNewCollectivesCount)})${displayCollectives(newCollectives)}

Note: this reports excludes activities on the [OC team collective](https://opencollective.com/opencollective-company)
`;
}

function displayTotals(totals) {
  if (totals.length > 0) {
    return `\n    * ${totals.join('\n    * ').trim()}`;
  }
  return "";
}

function displayCollectives(collectives) {
  if (collectives.length > 0) {
    return `:\n    * ${collectives.join('\n    * ').trim()}`;
  }
  return "";
}

function compareNumbers(recentNumber, priorNumber, formatter = (number) => number) {
  const diff = Math.round(recentNumber - priorNumber);
  return `${diff >= 0 ? '+' : ''}${formatter(diff)}`;
}

function getSum(collection, currency) {
  const record = _.find(collection, { currency });
  return record ? record.SUM : 0;
}

run();
<commit_msg>compare to same dates previous month, using UTC, added total revenue in USD<commit_after>import Promise from 'bluebird';
import moment from 'moment-timezone';
import _ from 'lodash';
import merge from 'merge-options';
import models, { Op } from '../../server/models';
import activities from '../../server/constants/activities';
import emailLib from '../../server/lib/email';
import expenseStatus from '../../server/constants/expense_status';
import { formatCurrency } from '../../server/lib/utils';
import showdown from 'showdown';
import { reduceArrayToCurrency } from '../../server/lib/currency';
const markdownConverter = new showdown.Converter();

if (!process.env.MANUAL) {
  onlyExecuteInProdOnMondays();
}

const {
  Activity,
  Collective,
  Expense,
  PaymentMethod,
  Transaction,
} = models;

/**
 * Note: we cannot simply compare last week with the same week in the previous month
 * because that wouldn't always include the first of the month (when all the recurring subscriptions are processed)
 * So instead, we compare last week with the same date of the previous month + 7 days
 * Eg. we compare the week of Monday July 30 2018 till Sunday August 5 2018 (technically till Monday August 6 not included)
 *     with the week of Wednesday June 30th till Tuesday July 5 (technically till Wednesday July 6 not included)
 */
const lastWeek = [
  moment(process.env.START_DATE).tz('UTC').startOf('isoWeek').subtract(1, 'week'),
  moment(process.env.START_DATE).tz('UTC').startOf('isoWeek')
];
const sameDatesLastMonth = [
  moment(lastWeek[0]).subtract(1, 'month'),
  moment(lastWeek[0]).subtract(1, 'month').add(7, 'days')
];

const createdLastWeek = getTimeFrame('createdAt', lastWeek);
const updatedLastWeek = getTimeFrame('updatedAt', lastWeek);
const createdSameWeekPreviousMonth = getTimeFrame('createdAt', sameDatesLastMonth);
const updatedSameWeekPreviousMonth = getTimeFrame('updatedAt', sameDatesLastMonth);

const title = `Weekly Platform Report`;
const subtitle = `Week ${lastWeek[0].week()} from ${lastWeek[0].format('YYYY-MM-DD')} till ${lastWeek[1].format('YYYY-MM-DD')} (compared to ${sameDatesLastMonth[0].format('YYYY-MM-DD')} till ${sameDatesLastMonth[1].format('YYYY-MM-DD')})`;

const donation = {
  where: {
    OrderId: {
      [Op.not]: null
    }
  }
};

const pendingExpense = { where: { status: expenseStatus.PENDING } };
const approvedExpense = { where: { status: expenseStatus.APPROVED } };
const rejectedExpense = { where: { status: expenseStatus.REJECTED } };
const paidExpense = { where : { status: expenseStatus.PAID } };

const credit = { where: { type: 'CREDIT' }};

const excludeOcTeam = { where: {
  CollectiveId: {
    [Op.not]: 1 // OpenCollective collective
  }
} };

const lastWeekDonations = merge({}, createdLastWeek, donation, excludeOcTeam, credit);
const lastWeekExpenses = merge({}, updatedLastWeek, excludeOcTeam);

const pendingLastWeekExpenses = merge({}, lastWeekExpenses, pendingExpense);
const approvedLastWeekExpenses = merge({}, lastWeekExpenses, approvedExpense);
const rejectedLastWeekExpenses = merge({}, lastWeekExpenses, rejectedExpense);
const paidLastWeekExpenses = merge({}, lastWeekExpenses, paidExpense);

const weekBeforeDonations = merge({}, createdSameWeekPreviousMonth, donation, excludeOcTeam, credit);
const paidWeekBeforeExpenses = merge({}, updatedSameWeekPreviousMonth, excludeOcTeam, paidExpense);

const groupAndOrderBy = (table, attribute = 'currency') => {
  return {
    plain: false,
    group: [ `${table}.${attribute}` ],
    attributes: [[attribute, 'currency']],
    order: [attribute]
  }
};

const onlyIncludeCollectiveType = {
  include: [{
    model: Collective,
    as: 'collective',
    where: {
      type: 'COLLECTIVE'
    }
  }]
};

const service = (service) => {
  return {
    include: [{
      attributes: [],
      model: PaymentMethod,
      required: true,
      where: {
        service,
      },
    }],
  };
};

const paypalReceived = { where: { type: activities.WEBHOOK_PAYPAL_RECEIVED } };

const distinct = {
  plain: false,
  distinct: true
};

export default function run() {
  return Promise.props({

    // Donation statistics

    stripeDonationCount: Transaction.count(merge({}, lastWeekDonations, service('stripe'))),

    priorStripeDonationCount: Transaction.count(merge({}, weekBeforeDonations, service('stripe'))),

    manualDonationCount: Transaction.count(merge({}, lastWeekDonations, service('opencollective'))),

    priorManualDonationCount: Transaction.count(merge({}, weekBeforeDonations, service('opencollective'))),

    paypalDonationCount: Transaction.count(merge({}, lastWeekDonations, service('paypal'))),

    priorPaypalDonationCount: Transaction.count(merge({}, weekBeforeDonations, service('paypal'))),

    revenue: Transaction
      .aggregate('platformFeeInHostCurrency', 'SUM', merge({}, lastWeekDonations, groupAndOrderBy('Transaction', 'hostCurrency'))),

    priorRevenue: Transaction
      .aggregate('platformFeeInHostCurrency', 'SUM', merge({}, weekBeforeDonations, groupAndOrderBy('Transaction', 'hostCurrency'))),

    stripeDonationAmount: Transaction
      .aggregate('amount', 'SUM', merge({}, lastWeekDonations, groupAndOrderBy('Transaction'))),

    priorStripeDonationAmount: Transaction
      .aggregate('amount', 'SUM', merge({}, weekBeforeDonations, groupAndOrderBy('Transaction'))),

    manualDonationAmount: Transaction
      .aggregate('amount', 'SUM', merge({}, lastWeekDonations, groupAndOrderBy('Transaction'), service('opencollective'))),

    priorManualDonationAmount: Transaction
      .aggregate('amount', 'SUM', merge({}, weekBeforeDonations, groupAndOrderBy('Transaction'), service('opencollective'))),

    paypalReceivedCount: Activity.count(merge({}, createdLastWeek, paypalReceived)),

    paypalDonationAmount: Transaction
      .sum('amount', merge({}, lastWeekDonations, service('paypal'))),

    priorPaypalDonationAmount: Transaction
      .sum('amount', merge({}, weekBeforeDonations, service('paypal'))),

    // Expense statistics

    pendingExpenseCount: Expense.count(pendingLastWeekExpenses),

    approvedExpenseCount: Expense.count(approvedLastWeekExpenses),

    rejectedExpenseCount: Expense.count(rejectedLastWeekExpenses),

    paidExpenseCount: Expense.count(paidLastWeekExpenses),

    priorPaidExpenseCount: Expense.count(paidWeekBeforeExpenses),

    pendingExpenseAmount: Expense
      .aggregate('amount', 'SUM', merge({}, pendingLastWeekExpenses, groupAndOrderBy('Expense')))
      .map(row => `${row.currency} ${formatCurrency(row.SUM, row.currency)}`),

    approvedExpenseAmount: Expense
      .aggregate('amount', 'SUM', merge({}, approvedLastWeekExpenses, groupAndOrderBy('Expense')))
      .map(row => `${row.currency} ${formatCurrency(row.SUM, row.currency)}`),

    rejectedExpenseAmount: Expense
      .aggregate('amount', 'SUM', merge({}, rejectedLastWeekExpenses, groupAndOrderBy('Expense')))
      .map(row => `${row.currency} ${formatCurrency(row.SUM, row.currency)}`),

    paidExpenseAmount: Expense
      .aggregate('amount', 'SUM', merge({}, paidLastWeekExpenses, groupAndOrderBy('Expense'))),

    priorPaidExpenseAmount: Expense
      .aggregate('amount', 'SUM', merge({}, paidWeekBeforeExpenses, groupAndOrderBy('Expense'))),

    // Collective statistics

    activeCollectivesWithTransactions: Transaction
      .findAll(merge({attributes: ['CollectiveId'] }, createdLastWeek, distinct, excludeOcTeam, onlyIncludeCollectiveType))
      .map(row => row.CollectiveId),

    priorActiveCollectivesWithTransactions: Transaction
      .findAll(merge({attributes: ['CollectiveId'] }, createdSameWeekPreviousMonth, distinct, excludeOcTeam, onlyIncludeCollectiveType))
      .map(row => row.CollectiveId),

    activeCollectivesWithExpenses: Expense
      .findAll(merge({attributes: ['CollectiveId'] }, updatedLastWeek, distinct, excludeOcTeam))
      .map(row => row.CollectiveId),

    priorActiveCollectivesWithExpenses: Expense
      .findAll(merge({attributes: ['CollectiveId'] }, updatedSameWeekPreviousMonth, distinct, excludeOcTeam))
      .map(row => row.CollectiveId),

    newCollectives: Collective
      .findAll(merge({}, { attributes: ['slug', 'name', 'tags'], where: { type: 'COLLECTIVE' } }, createdLastWeek))
      .map(collective => {
        const openSource = collective.dataValues.tags && collective.dataValues.tags.indexOf('open source') !== -1;
        return `[${collective.dataValues.name || collective.dataValues.slug}](https://opencollective.com/${collective.dataValues.slug}) (${openSource ? 'open source' : collective.dataValues.tags})`
      }),

    priorNewCollectivesCount: Collective.count(merge({}, { where: { type: 'COLLECTIVE' } }, createdSameWeekPreviousMonth)),

  }).then(async (results) => {
    results.revenueInUSD = - await reduceArrayToCurrency(results.revenue.map(({ SUM, currency }) => {
      return { amount: SUM, currency };
    }));
    results.priorRevenueInUSD = - await reduceArrayToCurrency(results.priorRevenue.map(({ SUM, currency }) => {
      return { amount: SUM, currency };
    }));
    results.activeCollectiveCount = _.union(results.activeCollectivesWithTransactions, results.activeCollectivesWithExpenses).length;
    results.priorActiveCollectiveCount = _.union(results.priorActiveCollectivesWithTransactions, results.priorActiveCollectivesWithExpenses).length;
    const report = reportString(results);
    console.log(report);
    const html = markdownConverter.makeHtml(report);
    return emailLib.sendMessage('team@opencollective.com', title, html, { tag: 'platform-weekly-report' });
  }).then(() => {
    console.log('Weekly reporting done!');
    process.exit();
  }).catch(err => {
    console.log('err', err);
    process.exit();
  });
}

/**
 * Heroku scheduler only has daily or hourly cron jobs, we only want to run
 * this script once per week on Monday (1). If the day is not Monday on production
 * we won't execute the script
 */
function onlyExecuteInProdOnMondays() {
  const today = new Date();
  if (process.env.NODE_ENV === 'production' && today.getDay() !== 1) {
    console.log('NODE_ENV is production and day is not Monday, script aborted!');
    process.exit();
  }
}

function getTimeFrame(propName, timeRange) {
  return {
    where: {
      [propName]: {
        [Op.gte]: timeRange[0],
        [Op.lt]: timeRange[1]
      }
    }
  };
}

function reportString({
  activeCollectiveCount,
  approvedExpenseAmount,
  approvedExpenseCount,
  stripeDonationAmount,
  stripeDonationCount,
  manualDonationAmount,
  manualDonationCount,
  newCollectives,
  paidExpenseAmount,
  paidExpenseCount,
  paypalDonationAmount,
  paypalDonationCount,
  pendingExpenseAmount,
  pendingExpenseCount,
  revenue,
  priorRevenue,
  revenueInUSD,
  priorRevenueInUSD,
  priorActiveCollectiveCount,
  priorStripeDonationAmount,
  priorStripeDonationCount,
  priorManualDonationAmount,
  priorManualDonationCount,
  priorNewCollectivesCount,
  priorPaidExpenseAmount,
  priorPaypalDonationAmount,
  priorPaypalDonationCount,
  priorPaidExpenseCount,
  rejectedExpenseAmount,
  rejectedExpenseCount,
}) {
  const growth = (revenueInUSD-priorRevenueInUSD)/priorRevenueInUSD;
  const growthPercent = `${Math.round(growth*100)}%`;
  return `# ${title}
${subtitle}

## Revenue ${formatCurrency(revenueInUSD, 'USD')} (${compareNumbers(revenueInUSD, priorRevenueInUSD, (n) => formatCurrency(n, 'USD'))}) (${growthPercent} growth)
  ${revenue.map(({ SUM, currency }) => `* ${currency} ${formatCurrency(-SUM, currency)} (${compareNumbers(-SUM, -getSum(priorRevenue, currency), (n) => formatCurrency(n, currency))})`).join('\n  ')}

## Donations
  - STRIPE: ${stripeDonationCount} donations received (${compareNumbers(stripeDonationCount, priorStripeDonationCount)})
    ${stripeDonationAmount.map(({ SUM, currency }) => `* ${currency} ${formatCurrency(SUM, currency)} (${compareNumbers(SUM, getSum(priorStripeDonationAmount, currency), (n) => formatCurrency(n, currency))})`).join('\n    ')}
  - PAYPAL: ${paypalDonationCount} paypal donations received (${compareNumbers(paypalDonationCount, priorPaypalDonationCount)})
    * USD ${formatCurrency(paypalDonationAmount, 'USD')} (${compareNumbers(paypalDonationAmount, priorPaypalDonationAmount, (n) => formatCurrency(n, 'USD'))})
  - MANUAL: ${manualDonationCount} donations received (${compareNumbers(manualDonationCount, priorManualDonationCount)})
    ${manualDonationAmount.map(({ SUM, currency }) => `* ${currency} ${formatCurrency(SUM, currency)} (${compareNumbers(SUM, getSum(priorManualDonationAmount, currency), (n) => formatCurrency(n, currency))})`).join('\n    ')}

## Expenses
  - ${paidExpenseCount} paid expenses (${compareNumbers(paidExpenseCount, priorPaidExpenseCount)})
    ${paidExpenseAmount.map(({ SUM, currency }) => `* ${currency} ${formatCurrency(SUM, currency)}  (${compareNumbers(SUM, getSum(priorPaidExpenseAmount, currency), (n) => formatCurrency(n, currency))})`).join('\n    ')}
  - ${pendingExpenseCount} pending expenses${displayTotals(pendingExpenseAmount)}
  - ${approvedExpenseCount} approved expenses${displayTotals(approvedExpenseAmount)}
  - ${rejectedExpenseCount} rejected expenses${displayTotals(rejectedExpenseAmount)}

## Collectives
  - ${activeCollectiveCount} active collectives (${compareNumbers(activeCollectiveCount, priorActiveCollectiveCount)})
  - ${newCollectives.length} new collectives (${compareNumbers(newCollectives.length, priorNewCollectivesCount)})${displayCollectives(newCollectives)}

Note: this reports excludes activities on the [OC team collective](https://opencollective.com/opencollective-company)
`;
}

function displayTotals(totals) {
  if (totals.length > 0) {
    return `\n    * ${totals.join('\n    * ').trim()}`;
  }
  return "";
}

function displayCollectives(collectives) {
  if (collectives.length > 0) {
    return `:\n    * ${collectives.join('\n    * ').trim()}`;
  }
  return "";
}

function compareNumbers(recentNumber, priorNumber, formatter = (number) => number) {
  const diff = Math.round(recentNumber - priorNumber);
  return `${diff >= 0 ? '+' : ''}${formatter(diff)}`;
}

function getSum(collection, currency) {
  const record = _.find(collection, { currency });
  return record ? record.SUM : 0;
}

run();
<|endoftext|>


<commit_before>const filters = {}

$(function() {
  setupEvents();
});

async function setupEvents() {
  toggleDropdown();
  // If want all events on discovery page
  if (!(window.location.href).includes('filtered=true')) {
    const allEvents = await getAllEvents();
    populateAllEvents(allEvents);
  } else {
    // Get filtered events only
    const filteredEvents = await getFilteredEventsOnly(window.location.href.split("labelParams=")[1]);
    populateAllEvents(filteredEvents);
  }
}

/**
 * Get all search events for the keyword entered and populate
 * the events in the display.
 */
async function getAllSearchEvents() {
  const eventContainer = document.getElementById('event-container');
  if (eventContainer != null) {
    eventContainer.remove();
  }

  const searchContainer = document.getElementById('search-container');
  searchContainer.innerHTML = '';

  const keyword = document.getElementById('keyword').value;
  const response = await fetch(`search-data?keyword=${keyword}`);
  const searchEvents = await response.json();
  for (const key in searchEvents) {
    if (searchEvents.hasOwnProperty(key)) {
      populateEventContainer(searchEvents[key], 'search-container', 4);
    }
  }
}

function toggleDropdown() {
  $(".dropdown-toggle").dropdown();
}

async function getAllEvents() {
  const allEvents = await fetch('/discovery-event-details');
  return allEvents.json();
}

function populateRankedEvents(eventLevels) {
  const transposedEventLevels = transposeEventLevels(eventLevels);
  for (let i = 0; i < 4; i++) {
    for (const eventMap of transposedEventLevels[i]) {
      populateEventContainer(eventMap['event'], `masonry-col-${i + 1}`, eventMap['lod']);
      getInterestFilters(eventMap['event']);
    }
  }
}

/**
 * Makes the masonry grid for events-feed ordered rougly from left to right
 * instead of top to bottom
 */
function transposeEventLevels(eventLevels) {
  const numberOfColumns = 4;
  let transposed = [[], [], [], []];
  for (let i = 0; i < eventLevels.length; i++) {
    transposed[i % numberOfColumns].push(eventLevels[i]);
  }
  return transposed;
}

/**
 * Gets events by specified filter
 * @constructor
 * @param {string} labelParams - label params as selected by user
 */
async function getFilteredEventsOnly(labelParams) {
  const response = await fetch('/filtered-events?' + new URLSearchParams({'labelParams': labelParams}));
  return response.json();
}

async function populateAllEvents(allEvents) {
  const rankedEvents = await getRankedEvents(allEvents);
  const eventLevels = getLodsFromEvents(rankedEvents);
  populateRankedEvents(eventLevels);
  populateFilters(filters);
}

// Fill filter dict with {labelName: count}
function getInterestFilters(event) {
  for (interest in event.labels) {
    if (!(event.labels[interest] in filters)) {
      filters[event.labels[interest]] = 1;
    } else {
      filters[event.labels[interest]] = filters[event.labels[interest]] + 1;
    }
  }
}

// Populate filter tab with label checkboxes
function populateFilters(filters) {
  for (const key in filters) {
    $('#filterCheckBoxes')
      .append(getCheckboxes(key, filters[key]))
    }
  $('#filterCheckBoxes').append(`<br>`)
}

// Gives HTML for checkboxes
function getCheckboxes(key, value) {
  return `<input type="checkbox" id=${key} name=${key} value=${key}>
     ${key} (${value})
`
}

// Gets checked checkboxes and refreshes page
async function getFilteredEvents() {
  const checks = $('input[type="checkbox"]:checked').map(function() {
    return $(this).val();
  }).get();
  labelParams = checks.join("-");
  // refresh page while passing checked boxes as params
  window.location.href = window.location.href.split('?')[0] + '?filtered=true' + `?labelParams=${labelParams}`;
}
<commit_msg>Fix typo with 'roughly'<commit_after>const filters = {}

$(function() {
  setupEvents();
});

async function setupEvents() {
  toggleDropdown();
  // If want all events on discovery page
  if (!(window.location.href).includes('filtered=true')) {
    const allEvents = await getAllEvents();
    populateAllEvents(allEvents);
  } else {
    // Get filtered events only
    const filteredEvents = await getFilteredEventsOnly(window.location.href.split("labelParams=")[1]);
    populateAllEvents(filteredEvents);
  }
}

/**
 * Get all search events for the keyword entered and populate
 * the events in the display.
 */
async function getAllSearchEvents() {
  const eventContainer = document.getElementById('event-container');
  if (eventContainer != null) {
    eventContainer.remove();
  }

  const searchContainer = document.getElementById('search-container');
  searchContainer.innerHTML = '';

  const keyword = document.getElementById('keyword').value;
  const response = await fetch(`search-data?keyword=${keyword}`);
  const searchEvents = await response.json();
  for (const key in searchEvents) {
    if (searchEvents.hasOwnProperty(key)) {
      populateEventContainer(searchEvents[key], 'search-container', 4);
    }
  }
}

function toggleDropdown() {
  $(".dropdown-toggle").dropdown();
}

async function getAllEvents() {
  const allEvents = await fetch('/discovery-event-details');
  return allEvents.json();
}

function populateRankedEvents(eventLevels) {
  const transposedEventLevels = transposeEventLevels(eventLevels);
  for (let i = 0; i < 4; i++) {
    for (const eventMap of transposedEventLevels[i]) {
      populateEventContainer(eventMap['event'], `masonry-col-${i + 1}`, eventMap['lod']);
      getInterestFilters(eventMap['event']);
    }
  }
}

/**
 * Makes the masonry grid for events-feed ordered roughly from left to right
 * instead of top to bottom
 */
function transposeEventLevels(eventLevels) {
  const numberOfColumns = 4;
  let transposed = [[], [], [], []];
  for (let i = 0; i < eventLevels.length; i++) {
    transposed[i % numberOfColumns].push(eventLevels[i]);
  }
  return transposed;
}

/**
 * Gets events by specified filter
 * @constructor
 * @param {string} labelParams - label params as selected by user
 */
async function getFilteredEventsOnly(labelParams) {
  const response = await fetch('/filtered-events?' + new URLSearchParams({'labelParams': labelParams}));
  return response.json();
}

async function populateAllEvents(allEvents) {
  const rankedEvents = await getRankedEvents(allEvents);
  const eventLevels = getLodsFromEvents(rankedEvents);
  populateRankedEvents(eventLevels);
  populateFilters(filters);
}

// Fill filter dict with {labelName: count}
function getInterestFilters(event) {
  for (interest in event.labels) {
    if (!(event.labels[interest] in filters)) {
      filters[event.labels[interest]] = 1;
    } else {
      filters[event.labels[interest]] = filters[event.labels[interest]] + 1;
    }
  }
}

// Populate filter tab with label checkboxes
function populateFilters(filters) {
  for (const key in filters) {
    $('#filterCheckBoxes')
      .append(getCheckboxes(key, filters[key]))
    }
  $('#filterCheckBoxes').append(`<br>`)
}

// Gives HTML for checkboxes
function getCheckboxes(key, value) {
  return `<input type="checkbox" id=${key} name=${key} value=${key}>
     ${key} (${value})
`
}

// Gets checked checkboxes and refreshes page
async function getFilteredEvents() {
  const checks = $('input[type="checkbox"]:checked').map(function() {
    return $(this).val();
  }).get();
  labelParams = checks.join("-");
  // refresh page while passing checked boxes as params
  window.location.href = window.location.href.split('?')[0] + '?filtered=true' + `?labelParams=${labelParams}`;
}
<|endoftext|>


<commit_before>test(
  'NavigationTest',

  [
    'ephox.boss.api.CommentGene',
    'ephox.boss.api.Gene',
    'ephox.boss.api.TestUniverse',
    'ephox.boss.api.TextGene',
    'ephox.phoenix.test.Finder',
    'ephox.phoenix.wrap.Navigation'
  ],

  function (CommentGene, Gene, TestUniverse, TextGene, Finder, Navigation) {

    var doc = TestUniverse(
      Gene('root', 'root', [
        Gene('1', 'div', [
          Gene('1.1', 'p', [
            Gene('1.1.1', 'img', []),
            TextGene('1.1.2', 'post-image text')
          ]),
          Gene('1.2', 'p', [
            TextGene('1.2.1', 'This is text'),
            Gene('1.2.2', 'span', [
              TextGene('1.2.2.1', 'inside a span')
            ]),
            TextGene('1.2.3', 'More text'),
            Gene('1.2.4', 'em', [
              TextGene('1.2.4.1', 'Inside em')
            ]),
            TextGene('1.2.5', 'Last piece of text')
          ])
        ])
      ])
    );

    var checkLast = function (expected, id) {
      var actual = Navigation.toLast(doc, Finder.get(doc, id));
      assert.eq(expected.element, actual.element().id);
      assert.eq(expected.offset, actual.offset());
    };

    var checkLower = function (expected, id) {
      var actual = Navigation.toLower(doc, Finder.get(doc, id));
      assert.eq(expected.element, actual.element().id);
      assert.eq(expected.offset, actual.offset());
    };

    var checkLeaf = function (expected, id, offset) {
      var actual = Navigation.toLeaf(doc, Finder.get(doc, id), offset);
      assert.eq(expected.element, actual.element().id);
      assert.eq(expected.offset, actual.offset());
    };

    checkLower({ element: '1', offset: 2 }, '1');
    checkLower({ element: '1.2.5', offset: 'Last piece of text'.length }, '1.2.5');

    checkLast({ element: '1.2.5', offset: 'Last piece of text'.length }, '1');
    checkLast({ element: '1.2.5', offset: 'Last piece of text'.length }, '1.2.5');

    checkLeaf({ element: '1.1.2', offset: 0 }, '1.1', 1);
    checkLeaf({ element: '1.1.2', offset: 'post-image text'.length }, '1.1', 2);
    checkLeaf({ element: '1.2.2.1', offset: 0 }, '1.2', 1);
    checkLeaf({ element: '1.2.5', offset: 'Last piece of text'.length }, '1.2', 5);

    var checkFreeFallLtr = function (expected, universe, elementId) {
      var element = Finder.get(doc, elementId);
      var actual = Navigation.freefallLtr(universe, element);
      assert.eq(element.id, elementId);
      assert.eq(expected.element, actual.element().id);
      assert.eq(expected.offset, actual.offset());
    };

    // Freefall without comment nodes
    checkFreeFallLtr({ element: '1.1.1', offset: 0 }, doc, 'root');
    checkFreeFallLtr({ element: '1.1.1', offset: 0 }, doc, '1');
    checkFreeFallLtr({ element: '1.1.1', offset: 0 }, doc, '1.1');
    checkFreeFallLtr({ element: '1.1.1', offset: 0 }, doc, '1.1.1');
    checkFreeFallLtr({ element: '1.1.2', offset: 0 }, doc, '1.1.2');
    checkFreeFallLtr({ element: '1.2.1', offset: 0 }, doc, '1.2');
    checkFreeFallLtr({ element: '1.2.1', offset: 0 }, doc, '1.2.1');
    checkFreeFallLtr({ element: '1.2.2.1', offset: 0 }, doc, '1.2.2');
    checkFreeFallLtr({ element: '1.2.3', offset: 0 }, doc, '1.2.3');
    checkFreeFallLtr({ element: '1.2.4.1', offset: 0 }, doc, '1.2.4');
    checkFreeFallLtr({ element: '1.2.4.1', offset: 0 }, doc, '1.2.4.1');
    checkFreeFallLtr({ element: '1.2.5', offset: 0 }, doc, '1.2.5');

    // Freefall with comment nodes: tbio-4938
    doc = TestUniverse(
      Gene('2-root', '2-root', [
        Gene('2-1', 'p', [
          TextGene('2-1.1', 'some text')
        ])
      ])
    );

    checkFreeFallLtr({ element: '2-1.1', offset: 0 }, doc, '2-root');
    checkFreeFallLtr({ element: '2-1.1', offset: 0 }, doc, '2-1');
    checkFreeFallLtr({ element: '2-1.1', offset: 0 }, doc, '2-1.1');

    doc = TestUniverse(
      Gene('3-root', '3-root', [
        Gene('3-1', 'p', [
          CommentGene('3-c0', 'some comment'),
          TextGene('3-1.1', 'some text')
        ])
      ])
    );

    checkFreeFallLtr({ element: '3-1.1', offset: 0 }, doc, '3-root');
    checkFreeFallLtr({ element: '3-1.1', offset: 0 }, doc, '3-1');
    checkFreeFallLtr({ element: '3-1.1', offset: 0 }, doc, '3-c0');
    checkFreeFallLtr({ element: '3-1.1', offset: 0 }, doc, '3-1.1');

    doc = TestUniverse(
      Gene('4-root', '4-root', [
        CommentGene('4-c0', 'some comment'),
        Gene('4-1', 'p', [
          CommentGene('4-c1', 'some comment'),
          TextGene('4-1.1', 'some text'),
          CommentGene('4-c2', 'some comment')
        ])
      ])
    );

    checkFreeFallLtr({ element: '4-1.1', offset: 0 }, doc, '4-root');
    checkFreeFallLtr({ element: '4-1.1', offset: 0 }, doc, '4-c0');
    checkFreeFallLtr({ element: '4-1.1', offset: 0 }, doc, '4-1');
    checkFreeFallLtr({ element: '4-1.1', offset: 0 }, doc, '4-c1');
    checkFreeFallLtr({ element: '4-1.1', offset: 0 }, doc, '4-1.1');
    checkFreeFallLtr({ element: '4-c2', offset: 0 }, doc, '4-c2');

  }
);
<commit_msg>TBIO-4938: test rtl<commit_after>test(
  'NavigationTest',

  [
    'ephox.boss.api.CommentGene',
    'ephox.boss.api.Gene',
    'ephox.boss.api.TestUniverse',
    'ephox.boss.api.TextGene',
    'ephox.phoenix.test.Finder',
    'ephox.phoenix.wrap.Navigation'
  ],

  function (CommentGene, Gene, TestUniverse, TextGene, Finder, Navigation) {

    var doc = TestUniverse(
      Gene('root', 'root', [
        Gene('1', 'div', [
          Gene('1.1', 'p', [
            Gene('1.1.1', 'img', []),
            TextGene('1.1.2', 'post-image text')
          ]),
          Gene('1.2', 'p', [
            TextGene('1.2.1', 'This is text'),
            Gene('1.2.2', 'span', [
              TextGene('1.2.2.1', 'inside a span')
            ]),
            TextGene('1.2.3', 'More text'),
            Gene('1.2.4', 'em', [
              TextGene('1.2.4.1', 'Inside em')
            ]),
            TextGene('1.2.5', 'Last piece of text')
          ])
        ])
      ])
    );

    var checkLast = function (expected, id) {
      var actual = Navigation.toLast(doc, Finder.get(doc, id));
      assert.eq(expected.element, actual.element().id);
      assert.eq(expected.offset, actual.offset());
    };

    var checkLower = function (expected, id) {
      var actual = Navigation.toLower(doc, Finder.get(doc, id));
      assert.eq(expected.element, actual.element().id);
      assert.eq(expected.offset, actual.offset());
    };

    var checkLeaf = function (expected, id, offset) {
      var actual = Navigation.toLeaf(doc, Finder.get(doc, id), offset);
      assert.eq(expected.element, actual.element().id);
      assert.eq(expected.offset, actual.offset());
    };

    checkLower({ element: '1', offset: 2 }, '1');
    checkLower({ element: '1.2.5', offset: 'Last piece of text'.length }, '1.2.5');

    checkLast({ element: '1.2.5', offset: 'Last piece of text'.length }, '1');
    checkLast({ element: '1.2.5', offset: 'Last piece of text'.length }, '1.2.5');

    checkLeaf({ element: '1.1.2', offset: 0 }, '1.1', 1);
    checkLeaf({ element: '1.1.2', offset: 'post-image text'.length }, '1.1', 2);
    checkLeaf({ element: '1.2.2.1', offset: 0 }, '1.2', 1);
    checkLeaf({ element: '1.2.5', offset: 'Last piece of text'.length }, '1.2', 5);

    var checkFreeFallLtr = function (expected, universe, elementId) {
      var element = Finder.get(doc, elementId);
      var actual = Navigation.freefallLtr(universe, element);
      assert.eq(element.id, elementId);
      assert.eq(expected.element, actual.element().id);
      assert.eq(expected.offset, actual.offset());
    };

    var checkFreeFallRtl = function (expected, universe, elementId) {
      var element = Finder.get(doc, elementId);
      var actual = Navigation.freefallRtl(universe, element);
      assert.eq(element.id, elementId);
      assert.eq(expected.element, actual.element().id);
      assert.eq(expected.offset, actual.offset());
    };

    // Freefall without comment nodes
    checkFreeFallLtr({ element: '1.1.1', offset: 0 }, doc, 'root');
    checkFreeFallLtr({ element: '1.1.1', offset: 0 }, doc, '1');
    checkFreeFallLtr({ element: '1.1.1', offset: 0 }, doc, '1.1');
    checkFreeFallLtr({ element: '1.1.1', offset: 0 }, doc, '1.1.1');
    checkFreeFallLtr({ element: '1.1.2', offset: 0 }, doc, '1.1.2');
    checkFreeFallLtr({ element: '1.2.1', offset: 0 }, doc, '1.2');
    checkFreeFallLtr({ element: '1.2.1', offset: 0 }, doc, '1.2.1');
    checkFreeFallLtr({ element: '1.2.2.1', offset: 0 }, doc, '1.2.2');
    checkFreeFallLtr({ element: '1.2.3', offset: 0 }, doc, '1.2.3');
    checkFreeFallLtr({ element: '1.2.4.1', offset: 0 }, doc, '1.2.4');
    checkFreeFallLtr({ element: '1.2.4.1', offset: 0 }, doc, '1.2.4.1');
    checkFreeFallLtr({ element: '1.2.5', offset: 0 }, doc, '1.2.5');

    checkFreeFallRtl({ element: '1.2.5', offset: 18 }, doc, 'root');
    checkFreeFallRtl({ element: '1.2.5', offset: 18 }, doc, '1');
    checkFreeFallRtl({ element: '1.1.2', offset: 15 }, doc, '1.1');
    checkFreeFallRtl({ element: '1.1.1', offset:  0 }, doc, '1.1.1');
    checkFreeFallRtl({ element: '1.1.2', offset: 15 }, doc, '1.1.2');
    checkFreeFallRtl({ element: '1.2.5', offset: 18 }, doc, '1.2');
    checkFreeFallRtl({ element: '1.2.1', offset: 12 }, doc, '1.2.1');
    checkFreeFallRtl({ element: '1.2.2.1', offset: 13 }, doc, '1.2.2');
    checkFreeFallRtl({ element: '1.2.3', offset: 9 }, doc, '1.2.3');
    checkFreeFallRtl({ element: '1.2.4.1', offset: 9 }, doc, '1.2.4');
    checkFreeFallRtl({ element: '1.2.4.1', offset: 9 }, doc, '1.2.4.1');
    checkFreeFallRtl({ element: '1.2.5', offset: 18 }, doc, '1.2.5');

    // Freefall with comment nodes: tbio-4938
    doc = TestUniverse(
      Gene('2-root', '2-root', [
        Gene('2-1', 'p', [
          TextGene('2-1.1', 'some text')
        ])
      ])
    );

    checkFreeFallLtr({ element: '2-1.1', offset: 0 }, doc, '2-root');
    checkFreeFallLtr({ element: '2-1.1', offset: 0 }, doc, '2-1');
    checkFreeFallLtr({ element: '2-1.1', offset: 0 }, doc, '2-1.1');

    checkFreeFallRtl({ element: '2-1.1', offset: 9 }, doc, '2-root');
    checkFreeFallRtl({ element: '2-1.1', offset: 9 }, doc, '2-1');
    checkFreeFallRtl({ element: '2-1.1', offset: 9 }, doc, '2-1.1');

    doc = TestUniverse(
      Gene('3-root', '3-root', [
        Gene('3-1', 'p', [
          CommentGene('3-c0', 'some comment'),
          TextGene('3-1.1', 'some text')
        ])
      ])
    );

    checkFreeFallLtr({ element: '3-1.1', offset: 0 }, doc, '3-root');
    checkFreeFallLtr({ element: '3-1.1', offset: 0 }, doc, '3-1');
    checkFreeFallLtr({ element: '3-1.1', offset: 0 }, doc, '3-c0');
    checkFreeFallLtr({ element: '3-1.1', offset: 0 }, doc, '3-1.1');

    checkFreeFallRtl({ element: '3-1.1', offset: 9 }, doc, '3-root');
    checkFreeFallRtl({ element: '3-1.1', offset: 9 }, doc, '3-1');
    checkFreeFallRtl({ element: '3-c0', offset:  0 }, doc, '3-c0');
    checkFreeFallRtl({ element: '3-1.1', offset: 9 }, doc, '3-1.1');

    doc = TestUniverse(
      Gene('4-root', '4-root', [
        CommentGene('4-c0', 'some comment'),
        Gene('4-1', 'p', [
          CommentGene('4-c1', 'some comment'),
          TextGene('4-1.1', 'some text'),
          CommentGene('4-c2', 'some comment')
        ])
      ])
    );

    checkFreeFallLtr({ element: '4-1.1', offset: 0 }, doc, '4-root');
    checkFreeFallLtr({ element: '4-1.1', offset: 0 }, doc, '4-c0');
    checkFreeFallLtr({ element: '4-1.1', offset: 0 }, doc, '4-1');
    checkFreeFallLtr({ element: '4-1.1', offset: 0 }, doc, '4-c1');
    checkFreeFallLtr({ element: '4-1.1', offset: 0 }, doc, '4-1.1');
    checkFreeFallLtr({ element: '4-c2', offset:  0 }, doc, '4-c2');

    checkFreeFallRtl({ element: '4-1.1', offset: 9 }, doc, '4-root');
    checkFreeFallRtl({ element: '4-c0', offset:  0 }, doc, '4-c0');
    checkFreeFallRtl({ element: '4-1.1', offset: 9 }, doc, '4-1');
    checkFreeFallRtl({ element: '4-c1', offset:  0 }, doc, '4-c1');
    checkFreeFallRtl({ element: '4-1.1', offset: 9 }, doc, '4-1.1');
    checkFreeFallRtl({ element: '4-1.1', offset: 9 }, doc, '4-c2');

  }
);
<|endoftext|>


<commit_before>import {resetSettingsUI} from "../UIActions";
import {connect} from "react-redux";
import React from "react";

class ErrorBoundary extends React.Component {
    state = {
    	hasError: false
    };

    componentDidCatch(error, info) {
    	// Display fallback UI
    	if (error !== "state is undefined") {
    		this.setState({
    			hasError: true,
    			message: `
            ${error.message}
            ${error.stack}
            at line ${error.lineNumber}
            `
    		});
    	}
    }

    resetButton() {
    	this.props.onResetButtonClick();
    	this.setState({
    		hasError: false
    	});
    }

    render() {
    	if (this.state.hasError) {
    		// You can render any custom fallback UI
    		return (

Error!

{this.state.message}

    					<button className="btn btn-danger" onClick={() => this.resetButton()}>
    						{browser.i18n.getMessage("defaultSettingsText")}
    					</button>

    		);
    	}
    	return this.props.children;
    }
}

const mapDispatchToProps = (dispatch) => ({
	onResetButtonClick() {
		dispatch(
			resetSettingsUI()
		);
	}
});

export default connect(null, mapDispatchToProps)(ErrorBoundary);
<commit_msg>Fix mixed tabs and spaces error<commit_after>import {resetSettingsUI} from "../UIActions";
import {connect} from "react-redux";
import React from "react";

class ErrorBoundary extends React.Component {
	state = {
		hasError: false
	};

	componentDidCatch(error, info) {
		// Display fallback UI
		if (error !== "state is undefined") {
			this.setState({
				hasError: true,
				message: `
            ${error.message}
            ${error.stack}
            at line ${error.lineNumber}
            `
			});
		}
	}

	resetButton() {
		this.props.onResetButtonClick();
		this.setState({
			hasError: false
		});
	}

	render() {
		if (this.state.hasError) {
			// You can render any custom fallback UI
			return (

Error!

{this.state.message}

						<button className="btn btn-danger" onClick={() => this.resetButton()}>
							{browser.i18n.getMessage("defaultSettingsText")}
						</button>

			);
		}
		return this.props.children;
	}
}

const mapDispatchToProps = (dispatch) => ({
	onResetButtonClick() {
		dispatch(
			resetSettingsUI()
		);
	}
});

export default connect(null, mapDispatchToProps)(ErrorBoundary);
<|endoftext|>