<commit_before>/*Naam: Sanne Berendschot
Studentnummer: 10269290
Minor Programmeren, Programmeerproject*/

// make global variables for the data
var map;
var dataColorsFrom  = {};
var dataColorsTo = {};
var dataOriginAsylum;
var toFrom;
var newCountry = "SYR";
var nameCountry = "Syria";
var dataCountry = [];
var dataCountryAmount;
var maxDataCountryAmount;
var minDataCountryAmount;
var dataOrigin;
var dataAsylum;
var minY;
var maxY;
var maxDataYear;
var minDataYear;
var svgChangeTimeline;
var yearSlider;
var color;
var countryStar = "SSD";
var countryStarName = "South Sudan";

var dataBarchart;
var newDataBarchart;
var chart;
var svgChangeChart;
var amountOfRefugees;

// parse the date
var parseTime = d3.time.format("%Y").parse;

// set outlines for graphs
var margin = {top: 50, right: 40, bottom: 120, left: 150},
    width = 800 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

// set the ranges for graph
var xG = d3.time.scale()
    .rangeRound([0, width]);

var yG = d3.scale.linear()
    .rangeRound([height, 0]);

// make array for the years as a string and in time
var yearsTime = []
var yearsString = []
j = 0
for (i = 1990; i < 2016; i++) {
    yearsTime[j] = parseTime(i.toString())
    yearsString[j] = i.toString();
    j++
};

// make function to draw the line for graph
var lineCountry = d3.svg.line()
    .x(function(d) { return xG(d.year); })
    .y(function(d) { return yG(d.amount); });

// initialize x axis for graph
var xAxisG = d3.svg.axis()
    .scale(xG)
    .orient("bottom");

// initialize y axis for graph
var yAxisG = d3.svg.axis()
    .scale(yG)
    .orient("left");

// make scale for barchart
var xB = d3.scale.ordinal()
    .rangeRoundBands([0, width], .4);

var yB = d3.scale.linear()
    .range([height, 0]);

// initialize x axis for barchart
var xAxisB = d3.svg.axis()
    .scale(xB)
    .orient("bottom");

// initialize y axis for barchart
var yAxisB = d3.svg.axis()
    .scale(yB)
    .orient("left");

// load data
queue()
    .defer(d3.tsv, "Dataset Origin goed.tsv")
    .defer(d3.tsv, "Dataset Asylum goed.tsv")
    .defer(d3.json, "dataBarchart.json")
    .await(makeVisualisations)

// make the two data visualisations
function makeVisualisations(error, datasetOrigin, datasetAsylum, datasetBarchart) {

    // check for error
    if (error) throw error;

    // save the data
    dataOrigin = datasetOrigin;
    dataAsylum = datasetAsylum;
    dataBarchart = datasetBarchart;

    // make world map

    // find min and max of data in specific year for legend
    var dataYear = dataOrigin.map(function(obj){ return obj[2015]; });
    maxDataYear = Math.max.apply(null, dataYear);
    minDataYear = Math.min.apply(null, dataYear);

    // make function to scale values to a color for map
    color = d3.scale.linear()
        .domain([minDataYear,maxDataYear])
        .range(["#FFB266","brown"]);

    // put data in dataset in correct format
    dataOrigin.forEach(function(d){
        var country = d.Country,
            value = +d[2015];
            //value = Math.log(value)
        dataColorsFrom[country] = { amount: value, fillColor: color(value) };
    });

    dataAsylum.forEach(function(d){
        var country = d.Country,
            value = +d[2015];
        dataColorsTo[country] = { amount: value, fillColor: color(value) };
    });

    // set default datasets
    dataset = dataColorsFrom
    dataOriginAsylum = dataOrigin
    toFrom = "from"

    // make the map
    makeMap();

    // make slider
    makeSlider();

    // make legend for world map
    makeLegendMap();

    // make graph for refugees over time

    // initialize svg
    var svgGraph = d3.select("#container2").append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .attr("id", "graph")
        .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    // save data in correct format
    correctDataFormatTimeline();

    // set y-axis for default settings
    setYaxisTimeline();

    // make title
    svgGraph.append("g")
        .attr("transform", "translate(0," + height + ")")
        .append("text")
            .attr("class", "graphTitle")
            .attr("x", width / 2)
            .attr("y", - height - margin.top / 2)
            .style("text-anchor", "middle")
            .text("Amount of refugees " + toFrom + " " + nameCountry + " per year");

    // make x axis
    svgGraph.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxisG)
        .append("text")
            .attr("class", "axisTitle")
            .attr("x", width)
            .attr("y", 50)
            .style("text-anchor", "end")
            .text("Time");

    // make y axis
    svgGraph.append("g")
        .attr("class", "y axis")
        .call(yAxisG)
        .append("text")
            .attr("class", "axisTitle")
            .attr("transform", "rotate(-90)")
            .attr("y", - 90)
            .attr("dy", ".71em")
            .style("text-anchor", "end")
            .text("Amount of refugees");

    // add line
    svgGraph.append("path")
        .attr("class", "line")
        .datum(dataCountry)
        .attr("fill", "none")
        .attr("stroke", "brown")
        .attr("stroke-linejoin", "round")
        .attr("stroke-linecap", "round")
        .attr("stroke-width", 1.5)
        .attr("d", lineCountry);

    // add comment
    svgGraph.append("g")
        .attr("transform", "translate(0," + height + ")")
        .append("text")
            .attr("x", 0)
            .attr("y", margin.bottom)
            .style("text-anchor", "begin")
            .text("Hover over the line for exact data");

    // define tooltip for showing the data
    var div = d3.select("#container2").append("div")
        .attr("class", "tooltip")
        .style("opacity", 0);

    // initialize mouseover
    var mouseOver = svgGraph.append("g")
      .attr("transform", "translate(" + 0 + "," + 0 + ")");

    // define area over which to move
    mouseOver.append("svg:rect")
        .attr("width", width)
        .attr("height", height)
        .attr("fill", "none")
        .attr("pointer-events", "all");

    // add tooltip
    mouseOver.on('mousemove', function() {

        // select correct section and data
        var svgScatter = svgGraph.selectAll("dot")
            .data(dataCountry)

            // make scatterplot
            .enter().append("circle")
                .attr("r", 3)
                .attr("id", "circle")
                .style("fill", "brown")
                .attr("cx", function(d) { return xG(d.year); })
                .attr("cy", function(d) { return yG(d.amount); })

                // show information when on line
                .on("mouseover", function(d) {
                    div.transition()
                        .duration(200)
                        .style("opacity", .9);
                    div .html("Year: " + d.yearx +
                            "
Vluchtelingen: "
                            + d.amount)
                        .style("left", (d3.event.pageX - 700) + "px")
                        .style("top", (d3.event.pageY - 220) + "px");
                    })

                // remove information when not on line
                .on("mouseout", function(d) {
                    div.transition()
                        .duration(500)
                        .style("opacity", 0);
                });

            // remove scatterplot when not on line
            svgScatter.transition().style("opacity", 0);
    });

    // make barchart
    makeBarchart();
};

// save data in correct format for timeline
function correctDataFormatTimeline() {
    dataOriginAsylum.forEach(function(d) {
        if (d.Country == newCountry) {
            for (i = 0; i < 26; i++) {
                object = {amount : d[yearsString[i]], year: yearsTime[i], yearx: yearsString[i]}
                dataCountry[i] = object;
            }
        }
    });
};

// set y-axis of timeline
function setYaxisTimeline() {

    // define min and max for y-axis
    dataCountryAmount = dataCountry.map(function(obj){ return obj.amount; });
    maxDataCountryAmount = Math.max.apply(null, dataCountryAmount);
    minDataCountryAmount = Math.min.apply(null, dataCountryAmount);
    minY = Math.floor(minDataCountryAmount /100) * 100;
    maxY = Math.ceil(maxDataCountryAmount / 100) * 100;

    // set domain for timeline
    xG.domain(d3.extent(yearsTime));
    yG.domain([minY, maxY]);
};

// change the graph of the timeline
function changeGraphTimeline() {

    // select the section for applying changes
    svgChangeTimeline = d3.select("#container2").transition();

    // change the title
    svgChangeTimeline.select(".graphTitle")
        .text("Amount of refugees " + toFrom + " " + nameCountry + " per year");

    // change the line
    svgChangeTimeline.select(".line")
        .duration(750)
        .attr("d", lineCountry(dataCountry));

    // change the y axis
    svgChangeTimeline.select(".y.axis")
        .duration(750)
        .call(yAxisG);
};

// make slider for world map
function makeSlider() {

    // update map when slider is used
    d3.select("#YearSlider").on("input", function() {
        update(+this.value);
    });

    // initialize with year 2015
    update(2015);

    // update when slider is used
    function update(year) {

        // put data in dataset in correct format
        dataOriginAsylum.forEach(function(d){
            var country = d.Country,
                value = +d[year];
                //value = Math.log(value)
            if (toFrom == "from") {
                dataColorsFrom[country] = { amount: value, fillColor: color(value) };
                dataset = dataColorsFrom;
            } else if (toFrom == "to") {
                dataColorsTo[country] = { amount: value, fillColor: color(value) };
                dataset = dataColorsTo;
            } else {
                console.log('No To or From was given')
            }
        });

        // update colors of world map
        map.updateChoropleth(dataset)

        // adjust the text on the range slider
        d3.select("#YearSlider-value").text(year);
        d3.select("#YearSlider").property("value", year);
    };
};

// make legend for world map
function makeLegendMap() {
    // select the correct section
    var svgMap = d3.select(".datamap")

    // make horizontal gradient
    var linearGradient = svgMap.append("defs").append("linearGradient")
        .attr("id", "linear-gradient")
        .attr("x1", "0%")
        .attr("y1", "0%")
        .attr("x2", "100%")
        .attr("y2", "0%");

    // set brightest color
    linearGradient.append("stop")
        .attr("offset", "0%")
        .attr("stop-color", "#FFB266");

    // set the darkest color
    linearGradient.append("stop")
        .attr("offset", "100%")
        .attr("stop-color", "brown");

    // set width, height and place for legend
    legendWidth = 240
    legendHeight = 10
    xCo = 20
    yCo = 460

    // append a title
    svgMap.append("text")
        .attr("id", "legendTitle")
        .attr("x", xCo)
        .attr("y", yCo - 10)
        .text("Amount of refugees (in millions)");

    // draw the rectangle and fill with gradient
    svgMap.append("rect")
        .attr("width", legendWidth)
        .attr("height", legendHeight)
        .style("fill", "url(#linear-gradient)")
        .style("x", xCo)
        .style("y", yCo);

    // make legend in millions
    maxDataYearMillion = maxDataYear / 1000000

    // set scale for x-axis
    var xScale = d3.scale.linear()
        .range([0, legendWidth])
        .domain([minDataYear,maxDataYearMillion]);

    // define x axis
    var xAxisLegend = d3.svg.axis()
          .orient("bottom")
          .ticks(10)
          .scale(xScale);

    // place x axis
    svgMap.append("g")
        .attr("transform", "translate(" + xCo + "," + (yCo + legendHeight) + ")")
        .attr("id", "legendX")
        .call(xAxisLegend);
};

// update the data when origin or asylumm is clicked
function updateDataToFrom(ToOrFrom) {

    // use correct data
    if (ToOrFrom == 0) {
        dataset = dataColorsFrom;
        dataOriginAsylum = dataOrigin;
        map.options.data = dataColorsFrom;
        toFrom = "from";
    } else if (ToOrFrom == 1) {
        dataset = dataColorsTo;
        dataOriginAsylum = dataAsylum;
        map.options.data = dataColorsTo;
        toFrom = "to";
    } else {
        console.log("You didn't define ToOrFrom")
    }

    // update colors in map
    map.updateChoropleth(dataset)

    // save new data
    correctDataFormatTimeline();

    // set y-axis again
    setYaxisTimeline();

    // change the graph of the timeline
    changeGraphTimeline();
};

// make the map
function makeMap() {
    map = new Datamap({
        element: document.getElementById("container1"),
        scope: "world",

        // zoom in on South-America
        setProjection: function(element) {
            var projection = d3.geo.equirectangular()
                .center([0, 0])
                .rotate([0, 0])
                .scale(100)
                .translate([element.offsetWidth / 2, element.offsetHeight / 2]);
            var path = d3.geo.path()
                .projection(projection);

        return {path: path, projection: projection};
        },

        // set default settings
        fills: { defaultFill: "#F5F5F5" },
        data: dataset,
        geographyConfig: {
            borderColor: "#331900",

            // settings for mouse hover
            highlightBorderWidth: 2,
            highlightFillColor: function(geo) {
                return geo["fillColor"] || "#F5F5F5";
            },
            highlightBorderColor: "black",

            // make tooltip
            popupTemplate: function(geo, data) {

                // only show information when data is present
                if (!dataset) { return ; }

                // show country and life expectancy in information box
                return ["
",
                    "", geo.properties.name, "",
                    "
Amount of refugees: ", Math.round(dataset[geo.id].amount * 10) / 10, "",
                    "
"].join('');
            }
        },

        // when country clicked, graph below changes
        done: function(datamap) {
            datamap.svg.selectAll(".datamaps-subunit").on("click", function(geo) {

                // save the selected country
                newCountry = geo.id;
                nameCountry = geo.properties.name

                // define new dataset for new country
                correctDataFormatTimeline();

                // set y-axis again
                setYaxisTimeline();

                // change the graph of the timeline
                changeGraphTimeline();

                // change barchart if one of 5 countries is clicked
                if (newCountry == "SYR" || newCountry == "SOM" || newCountry == "SSD" || newCountry == "CAF" || newCountry == "COD") {
                    countryStar = geo.id;
                    countryStarName = geo.properties.name

                    // put data in correct format
                    correctDataFormatBarchart();

                    setAmountOfRefugeesCorrect();

                    // set domain
                    setDomainBarchart();

                    changeBarchart();
                };

            });
        }
    });
};

// make the barchart
function makeBarchart() {

    console.log(dataBarchart)

    // initialize svg
    chart = d3.select("#container3").append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    // make title
    chart.append("g")
        .attr("transform", "translate(0," + height + ")")
        .append("text")
            .attr("class", "graphTitle")
            .attr("x", width / 2)
            .attr("y", - height - margin.top / 2)
            .style("text-anchor", "end")
            .text("Refugees from " + countryStarName);

    // put data in correct format
    correctDataFormatBarchart();

    setAmountOfRefugeesCorrect();

    // set domain
    setDomainBarchart();

    var tooltip = d3.select("body")
        .append("div")
        .style("position", "absolute")
        .style("z-index", "10")
        .style("visibility", "hidden")
        .text("a simple tooltip");

    // make x axis
    chart.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxisB)
        .selectAll("text")
            .style("text-anchor", "end")
            .attr("dx", "-.8em")
            .attr("dy", ".15em")
            .attr("transform", "rotate(-25)");
    chart.append("text")
        .attr("class", "axisTitle")
        .attr("x", width/2)
        .attr("y", height + 60)
        .attr("dy", ".71em")
        .style("text-anchor", "end")
        .text("Country");

    // make y axis
    chart.append("g")
        .attr("class", "y axis")
        .call(yAxisB);
    chart.append("text")
        .attr("class", "axisTitle")
        .attr("transform", "rotate(-90)")
        .attr("y", - 90)
        .attr("dy", ".71em")
        .style("text-anchor", "end")
        .text("Amount of refugees");

    // make bars
    chart.selectAll(".bar")
        .data(newDataBarchart)
        .enter().append("rect")
        .attr("class", "bar")
        .attr("x", function(d) { return xB(d.country); })
        .attr("y", function(d) { return yB(d.amount); })
        .attr("height", function(d) { return height - yB(d.amount); })
        .attr("width", xB.rangeBand())
        .on("mouseover", function(){return tooltip.style("visibility", "visible");})
        .on("mousemove", function(){return tooltip.style("top", (event.pageY-10)+"px").style("left",(event.pageX+10)+"px");})
        .on("mouseout", function(){return tooltip.style("visibility", "hidden");});

    // add comment
    chart.append("g")
        .attr("transform", "translate(0," + height + ")")
        .append("text")
            .attr("class", "comment")
            .attr("x", width - 5*margin.right)
            .attr("y", - height - 10)
            .style("text-anchor", "begin")
            .text("Amount of refugees: " + amountOfRefugees);
};

// make correct data format for barchart
function correctDataFormatBarchart() {
    newDataBarchart = []
    j = 0
    dataBarchart.forEach(function(d){
        if (d.origin == countryStarName && d.origin != d.country) {
            newDataBarchart[j] = {"country": d.country, "amount": d.amount};
            j++;
        };
    });
};

function setAmountOfRefugeesCorrect() {
    dataBarchart.forEach(function(d){
        if (d.origin == countryStarName && d.origin == d.country) {
            amountOfRefugees = d.amount;
        };
    });
};

function setDomainBarchart() {
    xB.domain(newDataBarchart.map(function(d) { return d.country; }));
    yB.domain([0, Math.ceil(d3.max(newDataBarchart, function(d) { return d.amount; })/1000000)*1000000]);
};

function changeBarchart() {
    // select the section for applying changes
    svgChangeChart = d3.select("#container3").transition();

    // change the title
    svgChangeChart.select(".graphTitle")
        .text("Refugees from " + countryStarName);

    svgChangeChart.select(".comment")
        .text("Amount of refugees: " + amountOfRefugees);

    var bars = chart.selectAll(".bar").data(newDataBarchart, function(d) { return d.country; }) // (data) is an array/iterable thing, second argument is an ID generator function

    bars.exit()
    .transition()
        .duration(300)
    .attr("y", yB(0))
    .attr("height", height - yB(0))
    .style('fill-opacity', 1e-6)
    .remove();

    // data that needs DOM = enter() (a set/selection, not an event!)
    bars.enter().append("rect")
        .attr("class", "bar")
        .attr("y", yB(0))
        .attr("height", height - yB(0));

    // the "UPDATE" set:
    bars.transition().duration(300).attr("x", function(d) { return xB(d.country); }) // (d) is one item from the data array, x is the scale object from above
        .attr("width", xB.rangeBand()) // constant, so no callback function(d) here
        .attr("y", function(d) { return yB(d.amount); })
        .attr("height", function(d) { return height - yB(d.amount); }); // flip the height, because y's domain is bottom up, but SVG renders top down

    // change the y axis
    svgChangeChart.select(".x.axis")
        .duration(750)
        .call(xAxisB)
            .selectAll("text")
            .style("text-anchor", "end")
            .attr("dx", "-.8em")
            .attr("dy", ".15em")
            .attr("transform", "rotate(-25)");

    // change the y axis
    svgChangeChart.select(".y.axis")
        .duration(750)
        .call(yAxisB);
}<commit_msg>Delete refugees.js<commit_after><|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import { EditSession, UndoManager } from 'ace';
import classnames from 'classnames';

import Editor from '../Editor';
import Icon from '../Icon';
import Terminal from '../ide/Terminal';
import MatplotlibPanel from '../ide/panels/MatplotlibPanel';
import TurtlePanel from '../ide/panels/TurtlePanel';
import CodeBlock from './CodeBlock';

import { EmbedTypes, RunModeDefaults } from '../../constants/Embed';

import { createEmbedObject } from '../../util/embedUtils';

import SourceboxProject from '../../models/project/sourceboxProject';
import SkulptProject from '../../models/project/skulptProject';
import {Severity} from "../../models/severity";

import Debug from 'debug';
const debug = Debug('webbox:CodeCellView');

/**
 * The Notebook-Component renders the different cells with a component according to its cell_type.
 */
export default class CodeCellView extends React.PureComponent {
  constructor(props) {
    super(props);

    this.onStartStopExecution = this.onStartStopExecution.bind(this);
    this.onSwitchMode = this.onSwitchMode.bind(this);
    this.onCloseTerminal = this.onCloseTerminal.bind(this);
    this.onUndoChanges = this.onUndoChanges.bind(this);
    this.onOpenInExternalWindow = this.onOpenInExternalWindow.bind(this);
    this.onProjectStateChange = this.onProjectStateChange.bind(this);
    this.onKeyDown = this.onKeyDown.bind(this);

    this.state = { editMode: false, showTerminal: false };
  }

  componentWillUnmount() {
    // Dispose listeners to avoid leaks
    if (this.state.project != null) {
      this.state.project.tabManager.removeListener('change', this.onProjectStateChange);
      this.state.project.on('change', this.onProjectStateChange);
    }
  }

  onKeyDown(e) {
    // Shift + Enter -> Execute Code
    if ((e.metaKey || (e.shiftKey && !e.altKey && !e.ctrlKey)) && e.key === "Enter") {
      this.startStopExecution();
      e.preventDefault();
    }

    // Escape -> ReadMode
    if (!e.metaKey && !e.shiftKey && !e.altKey && !e.ctrlKey && e.key === "Escape" && this.state.editMode) {
      this.switchMode();
      e.preventDefault();
    }

  }

  onOpenInExternalWindow() {
    /**
     * Running an unnamed example:
     *  - Get the current code
     *  - Get the set language (we need to know how to run the code)
     *  - Either use the set id for statistics or generate a new one
     *  - Current course/chapter (for statistics)
     */
    const code = this.session != null ? this.session.getValue() : this.props.code;
    let notebookLanguageInformation = this.props.cell.getIn(['metadata', 'executionLanguage'], this.props.executionLanguage.executionLanguage);
    let notebookEmbedType = this.props.embedType || EmbedTypes.Sourcebox;
    const embedType = this.props.cell.getIn(['metadata', 'embedType'], notebookEmbedType);

    // Experimental
    const id = this.props.cell.getIn(['metadata', 'runid'], RunModeDefaults.id);

    const url = `${window.location.protocol}//${window.location.host}/run?language=${encodeURIComponent(notebookLanguageInformation)}&id=${encodeURIComponent(id)}&embedType=${encodeURIComponent(embedType)}&code=${encodeURIComponent(code)}`;
    const strWindowFeatures = "menubar=yes,location=yes,resizable=yes,scrollbars=yes,status=yes";

    window.open(url, "Beispiel Ausführen", strWindowFeatures);
  }

  onCloseTerminal() {
    this.setState({
      showTerminal: false
    });
  }

  onUndoChanges() {
    this.session.setValue(this.props.code);
    this.setState({
      change: true
    });
  }

  onSwitchMode() {
    if (this.state.editMode) {
      this.setState({ editMode: false });
    } else {
      this.setState( { editMode: true } );
    }
  }

  onStartStopExecution() {
    // Lazy creation of the project and binding of listeners
    if (this.state.project == null) {
      this.initialize().then(success => {
        console.info("after init in onStartStopExecution", success);
        // Only retry the start of the execution if the project has been successfully created
        if (success) {
          this.onStartStopExecution();
        }
      });

      return;
    }

    let code = this.session != null ? this.session.getValue() : this.props.code;
    let project = this.state.project;

    this.state.project.tabManager.closeTabByType("matplotlib");

    if (project.isRunning()) {
      project.stop();
    } else {
      project.getFiles()[0].setValue(code);
      this.setState({
        showTerminal: true,
        project: project,
        tabs: this.state.project.tabManager.getTabs()
      });
      project.run();      // execute the code
    }
  }

  onProjectStateChange() {
    this.setState({
      tabs: this.state.project.tabManager.getTabs()
    }, this.forceUpdate());  // To force a Rerender
  }

  /**
   * Helper to determine the height of the rendered markdown to set the ace editor size accordingly
   * @returns {Number} ace editor wrappers height or minimum
   */
  getWrapperHeightOrMin() {
    if (this.wrapperNode) {
      return Math.max(this.wrapperNode.offsetHeight,  this.wrapperNode.scrollHeight,  this.wrapperNode.clientHeight, this.props.minHeight);
    } else {
      return this.props.minHeight;
    }
  }

  initialize() {
    return this.createEmptyProject().then(project => {
      project.tabManager.on('change', this.onProjectStateChange);
      project.on('change', this.onProjectStateChange);
      this.setState({
        project: project,
        tabs: project.tabManager.getTabs()
      });

      return true;
    }).catch(err => {
      this.context.messageList.showMessage(Severity.Warning, err);
      debug("Failed to create empty project", err);
      return false;
    });
  }

  createEmptyProject() {
    // Step 1: Get all relevant information, language, embed type and code
    let language = this.props.cell.getIn(['metadata', 'executionLanguage'], this.props.executionLanguage.executionLanguage);
    let notebookEmbedType = this.props.embedType || EmbedTypes.Sourcebox;
    const id = this.props.cell.getIn(['metadata', 'runid'], RunModeDefaults.id);
    const embedType = this.props.cell.getIn(['metadata', 'embedType'], notebookEmbedType);

    let projectData = {
      embed: createEmbedObject('', language, embedType, id),
      user: window.__USER_DATA__,
      messageList: this.context.messageList,
      remoteDispatcher: this.context.remoteDispatcher,
    };

    // Defer project creation to the point where all resources are available
    const promise = new Promise((resolve, reject) => {
      if (embedType === EmbedTypes.Sourcebox) {
        // Check if user is authenticated and/or show error
        if (window.__SOURCEBOX__.authToken == null || window.__SOURCEBOX__.authToken === "") {
          reject(new Error("Sie müssen zum Verwenden dieser Funktion angemeldet sein."));
        } else {
          resolve(new SourceboxProject(projectData, {
            auth: window.__SOURCEBOX__.authToken,
            server: window.__SOURCEBOX__.server,
            transports: window.__SOURCEBOX__.transports || ['websocket']
          }));
        }
      } else if (embedType === EmbedTypes.Skulpt) {
        // Check if skulpt is available, otherwise load the libs
        if (typeof Sk === "undefined") {
          require.ensure([], require => {
            require('exports-loader?Sk!../../../public/skulpt/skulpt.min.js');
            require('exports-loader?Sk!../../../public/skulpt/skulpt-stdlib.js');
            resolve(new SkulptProject(projectData));
          });
        } else {
          resolve(new SkulptProject(projectData));
        }
      } else {
        reject(new Error("Ungültiger oder nicht unterstützter 'embedType' wurde eingestellt. Wenden Sie sich zur Lösung an den Autor!"));
      }
    });

    return promise;
  }

  handleAdditionalPanels(tabs) {
    let additionalPanel = false;
    return tabs.map(({active, item, type}, index) => {
      let PanelType;
      switch (type) {
        case "turtle":
          PanelType = TurtlePanel;
          break;
        case "matplotlib":
          PanelType = MatplotlibPanel;
          break;
        default:
      }

      if (PanelType && !additionalPanel) {
        additionalPanel = true;
        return <PanelType className="second-panel" key={index} active={active} item={item}/>;
      } else if (PanelType && additionalPanel) {
        this.context.messageList.showMessage(Severity.Warning, new Error("Anzeige mehrere Turtle- bzw. Matplotlib-Graphen wird nicht unterstützt!"));
      }
    });
  }

  renderEditMode() {
    let minHeight = 100;
    let source = this.session != null ? this.session.getValue() : this.props.code;
    let languageName = this.props.notebookLanguage || 'python';
    let mode = this.props.cell.getIn(['metadata', 'mode'], languageName);

    // Reuse existing session if possible
    if (this.session) {
      this.session.setValue(source);
      this.session.setMode('ace/mode/' + mode);
    } else {
      this.session = new EditSession(source, 'ace/mode/' + mode);
      this.session.setUndoManager(new UndoManager);

      // Register change listener on the editor to know when to update
      this.session.on('change', () => {
        this.setState({
          change: true
        });
      });
    }

    return (

        <Editor fontSize="14px" minHeight={minHeight} maxLines={100} session={this.session} ref={editor => this.editor = editor} />

    );
  }

  renderReadMode() {
    let code = this.session != null ? this.session.getValue() : this.props.code;
    let executionLanguage = this.props.cell.getIn(['metadata', 'executionLanguage'], this.props.executionLanguage.executionLanguage);
    let mode = this.props.cell.getIn(['metadata', 'mode'], (this.props.notebookLanguage || 'python'));

    // Render the read mode depending on the given viewComponent
    return <this.props.viewComponent code={code} executionLanguage={executionLanguage} mode={mode}/>;
  }

  render() {
    const { code, className} = this.props;
    const { editMode, showTerminal, project, tabs } = this.state;
    const classes = classnames(`code-cell col-xs-12 row ${className}`);
    const externalIcon = <Icon name="external-link" className="icon-control hidden-print" onClick={this.onOpenInExternalWindow} title="IDE in neuem Fenster öffnen" />;
    const editIcon = <Icon name="edit" className="icon-control hidden-print" onClick={this.onSwitchMode} title="Zum Editiermodus wechseln" />;
    const readIcon = <Icon name="book" className="icon-control hidden-print" onClick={this.onSwitchMode} title="Zum Lesemodus wechseln (Escape)" />;
    const playIcon = <Icon name="play" className="success icon-control hidden-print" onClick={this.onStartStopExecution} title="Code ausführen (Shift + Enter)" />;
    const stopIcon = <Icon name="stop" className="danger icon-control hidden-print" onClick={this.onStartStopExecution} title="Code stoppen" />;
    const undoIcon = <Icon name="undo" className="danger icon-control hidden-print" onClick={this.onUndoChanges} title="Änderungen rückgängig machen" />;
    const closeTerminalIcon = <Icon name="close" className="close-btn icon-control hidden-print" onClick={this.onCloseTerminal} title="Terminal schliessen" />;
    let additionalPanels = showTerminal ? this.handleAdditionalPanels(tabs, project, code) : null;
    //const missingEmbed =
Ungültiger embedType. Wenden Sie sich an den Autor!
;

    const ideArea =

      { showTerminal ? closeTerminalIcon : null }
      { (project && project.runner) ? <Terminal process={project.runner}/> : null}
      { additionalPanels }

;

    return (

          { /*!project ? missingEmbed : null*/}

            { externalIcon }
            { editMode ? readIcon : editIcon}
            { project ? (project.isRunning() ? stopIcon : playIcon) : playIcon}
            { this.session ? (this.session.getUndoManager().hasUndo() ? null : undoIcon) : null }

          { editMode ? this.renderEditMode() : this.renderReadMode() }
          { showTerminal ? ideArea : null }

    );
  }
}

CodeCellView.propTypes = {
  viewComponent: PropTypes.oneOfType([
    PropTypes.func,
    PropTypes.element
  ]), /* use this instead of markdown-it */
  code: PropTypes.string.isRequired,
  cell: PropTypes.object.isRequired,
  executionLanguage: PropTypes.object.isRequired,
  notebookLanguage: PropTypes.string.isRequired,
  embedType: PropTypes.string.isRequired,
  className: PropTypes.string,
  minHeight: PropTypes.number
};

CodeCellView.defaultProps = {
  viewComponent: CodeBlock,
  className: "",
  minHeight: 100
};

CodeCellView.contextTypes = {
  messageList: PropTypes.object,
  remoteDispatcher: PropTypes.object
};<commit_msg>Use options mananger for codecell view editor<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import { EditSession, UndoManager } from 'ace';
import classnames from 'classnames';

import Editor from '../Editor';
import optionManager from '../../models/options';
import Icon from '../Icon';
import Terminal from '../ide/Terminal';
import MatplotlibPanel from '../ide/panels/MatplotlibPanel';
import TurtlePanel from '../ide/panels/TurtlePanel';
import CodeBlock from './CodeBlock';

import { EmbedTypes, RunModeDefaults } from '../../constants/Embed';

import { createEmbedObject } from '../../util/embedUtils';

import SourceboxProject from '../../models/project/sourceboxProject';
import SkulptProject from '../../models/project/skulptProject';
import {Severity} from '../../models/severity';

import Debug from 'debug';
const debug = Debug('webbox:CodeCellView');

/**
 * The Notebook-Component renders the different cells with a component according to its cell_type.
 */
export default class CodeCellView extends React.PureComponent {
  constructor(props) {
    super(props);

    this.onStartStopExecution = this.onStartStopExecution.bind(this);
    this.onSwitchMode = this.onSwitchMode.bind(this);
    this.onCloseTerminal = this.onCloseTerminal.bind(this);
    this.onUndoChanges = this.onUndoChanges.bind(this);
    this.onOpenInExternalWindow = this.onOpenInExternalWindow.bind(this);
    this.onProjectStateChange = this.onProjectStateChange.bind(this);
    this.onKeyDown = this.onKeyDown.bind(this);
    this.onChangeOption = this.onChangeOption.bind(this);

    this.state = {
      editMode: false,
      showTerminal: false,
      options: optionManager.getOptions()
    };
  }

  componentWillMount() {
    optionManager.on('change', this.onChangeOption);
  }

  componentWillUnmount() {
    // Dispose listeners to avoid leaks
    if (this.state.project != null) {
      this.state.project.tabManager.removeListener('change', this.onProjectStateChange);
      this.state.project.on('change', this.onProjectStateChange);
    }

    optionManager.removeListener('change', this.onChangeOption);
  }

  onChangeOption() {
    this.setState({
      options: optionManager.getOptions()
    });
  }

  onKeyDown(e) {
    // Shift + Enter -> Execute Code
    if ((e.metaKey || (e.shiftKey && !e.altKey && !e.ctrlKey)) && e.key === 'Enter') {
      this.startStopExecution();
      e.preventDefault();
    }

    // Escape -> ReadMode
    if (!e.metaKey && !e.shiftKey && !e.altKey && !e.ctrlKey && e.key === 'Escape' && this.state.editMode) {
      this.switchMode();
      e.preventDefault();
    }

  }

  onOpenInExternalWindow() {
    /**
     * Running an unnamed example:
     *  - Get the current code
     *  - Get the set language (we need to know how to run the code)
     *  - Either use the set id for statistics or generate a new one
     *  - Current course/chapter (for statistics)
     */
    const code = this.session != null ? this.session.getValue() : this.props.code;
    const notebookLanguageInformation = this.props.cell.getIn(['metadata', 'executionLanguage'], this.props.executionLanguage.executionLanguage);
    const notebookEmbedType = this.props.embedType || EmbedTypes.Sourcebox;
    const embedType = this.props.cell.getIn(['metadata', 'embedType'], notebookEmbedType);

    // Experimental
    const id = this.props.cell.getIn(['metadata', 'runid'], RunModeDefaults.id);

    const url = `${window.location.protocol}//${window.location.host}/run?language=${encodeURIComponent(notebookLanguageInformation)}&id=${encodeURIComponent(id)}&embedType=${encodeURIComponent(embedType)}&code=${encodeURIComponent(code)}`;
    const strWindowFeatures = 'menubar=yes,location=yes,resizable=yes,scrollbars=yes,status=yes';

    window.open(url, 'Beispiel Ausführen', strWindowFeatures);
  }

  onCloseTerminal() {
    this.setState({
      showTerminal: false
    });
  }

  onUndoChanges() {
    this.session.setValue(this.props.code);
    this.setState({
      change: true
    });
  }

  onSwitchMode() {
    if (this.state.editMode) {
      this.setState({ editMode: false });
    } else {
      this.setState( { editMode: true } );
    }
  }

  onStartStopExecution() {
    // Lazy creation of the project and binding of listeners
    if (this.state.project == null) {
      this.initialize().then(success => {
        debug('after init in onStartStopExecution', success);
        // Only retry the start of the execution if the project has been successfully created
        if (success) {
          this.onStartStopExecution();
        }
      });

      return;
    }

    const code = this.session != null ? this.session.getValue() : this.props.code;
    const project = this.state.project;

    this.state.project.tabManager.closeTabByType('matplotlib');

    if (project.isRunning()) {
      project.stop();
    } else {
      project.getFiles()[0].setValue(code);
      this.setState({
        showTerminal: true,
        project: project,
        tabs: this.state.project.tabManager.getTabs()
      });
      project.run();      // execute the code
    }
  }

  onProjectStateChange() {
    this.setState({
      tabs: this.state.project.tabManager.getTabs()
    }, this.forceUpdate());  // To force a Rerender
  }

  /**
   * Helper to determine the height of the rendered markdown to set the ace editor size accordingly
   * @returns {Number} ace editor wrappers height or minimum
   */
  getWrapperHeightOrMin() {
    if (this.wrapperNode) {
      return Math.max(this.wrapperNode.offsetHeight, this.wrapperNode.scrollHeight, this.wrapperNode.clientHeight, this.props.minHeight);
    } else {
      return this.props.minHeight;
    }
  }

  initialize() {
    return this.createEmptyProject().then(project => {
      project.tabManager.on('change', this.onProjectStateChange);
      project.on('change', this.onProjectStateChange);
      this.setState({
        project: project,
        tabs: project.tabManager.getTabs()
      });

      return true;
    }).catch(err => {
      this.context.messageList.showMessage(Severity.Warning, err);
      debug('Failed to create empty project', err);
      return false;
    });
  }

  createEmptyProject() {
    // Step 1: Get all relevant information, language, embed type and code
    const language = this.props.cell.getIn(['metadata', 'executionLanguage'], this.props.executionLanguage.executionLanguage);
    const notebookEmbedType = this.props.embedType || EmbedTypes.Sourcebox;
    const id = this.props.cell.getIn(['metadata', 'runid'], RunModeDefaults.id);
    const embedType = this.props.cell.getIn(['metadata', 'embedType'], notebookEmbedType);

    const projectData = {
      embed: createEmbedObject('', language, embedType, id),
      user: window.__USER_DATA__,
      messageList: this.context.messageList,
      remoteDispatcher: this.context.remoteDispatcher,
    };

    // Defer project creation to the point where all resources are available
    const promise = new Promise((resolve, reject) => {
      if (embedType === EmbedTypes.Sourcebox) {
        // Check if user is authenticated and/or show error
        if (window.__SOURCEBOX__.authToken == null || window.__SOURCEBOX__.authToken === '') {
          reject(new Error('Sie müssen zum Verwenden dieser Funktion angemeldet sein.'));
        } else {
          resolve(new SourceboxProject(projectData, {
            auth: window.__SOURCEBOX__.authToken,
            server: window.__SOURCEBOX__.server,
            transports: window.__SOURCEBOX__.transports || ['websocket']
          }));
        }
      } else if (embedType === EmbedTypes.Skulpt) {
        // Check if skulpt is available, otherwise load the libs
        if (typeof Sk === 'undefined') {
          require.ensure([], require => {
            require('exports-loader?Sk!../../../public/skulpt/skulpt.min.js');
            require('exports-loader?Sk!../../../public/skulpt/skulpt-stdlib.js');
            resolve(new SkulptProject(projectData));
          });
        } else {
          resolve(new SkulptProject(projectData));
        }
      } else {
        reject(new Error("Ungültiger oder nicht unterstützter 'embedType' wurde eingestellt. Wenden Sie sich zur Lösung an den Autor!"));
      }
    });

    return promise;
  }

  handleAdditionalPanels(tabs) {
    let additionalPanel = false;
    return tabs.map(({active, item, type}, index) => {
      let PanelType;
      switch (type) {
        case 'turtle':
          PanelType = TurtlePanel;
          break;
        case 'matplotlib':
          PanelType = MatplotlibPanel;
          break;
        default:
      }

      if (PanelType && !additionalPanel) {
        additionalPanel = true;
        return <PanelType className="second-panel" key={index} active={active} item={item}/>;
      } else if (PanelType && additionalPanel) {
        this.context.messageList.showMessage(Severity.Warning, new Error('Anzeige mehrere Turtle- bzw. Matplotlib-Graphen wird nicht unterstützt!'));
      }
    });
  }

  renderEditMode() {
    const minHeight = 100;
    const source = this.session != null ? this.session.getValue() : this.props.code;
    const languageName = this.props.notebookLanguage || 'python';
    const mode = this.props.cell.getIn(['metadata', 'mode'], languageName);
    const {font, fontSize, ace: aceOptions} = this.state.options;

    // Reuse existing session if possible
    if (this.session) {
      this.session.setValue(source);
      this.session.setMode('ace/mode/' + mode);
    } else {
      this.session = new EditSession(source, 'ace/mode/' + mode);
      this.session.setUndoManager(new UndoManager);

      // Register change listener on the editor to know when to update
      this.session.on('change', () => {
        this.setState({
          change: true
        });
      });
    }

    return (

        <Editor
          fontFamily={`${font}, monospace`}
          fontSize={`${fontSize}pt`}
          {...aceOptions}
          minHeight={minHeight}
          maxLines={100}
          session={this.session}
          ref={editor => { this.editor = editor; }} />

    );
  }

  renderReadMode() {
    const code = this.session != null ? this.session.getValue() : this.props.code;
    const executionLanguage = this.props.cell.getIn(['metadata', 'executionLanguage'], this.props.executionLanguage.executionLanguage);
    const mode = this.props.cell.getIn(['metadata', 'mode'], (this.props.notebookLanguage || 'python'));

    // Render the read mode depending on the given viewComponent
    return <this.props.viewComponent code={code} executionLanguage={executionLanguage} mode={mode}/>;
  }

  render() {
    const { code, className} = this.props;
    const { editMode, showTerminal, project, tabs } = this.state;
    const classes = classnames(`code-cell col-xs-12 row ${className}`);
    const externalIcon = <Icon name="external-link" className="icon-control hidden-print" onClick={this.onOpenInExternalWindow} title="IDE in neuem Fenster öffnen" />;
    const editIcon = <Icon name="edit" className="icon-control hidden-print" onClick={this.onSwitchMode} title="Zum Editiermodus wechseln" />;
    const readIcon = <Icon name="book" className="icon-control hidden-print" onClick={this.onSwitchMode} title="Zum Lesemodus wechseln (Escape)" />;
    const playIcon = <Icon name="play" className="success icon-control hidden-print" onClick={this.onStartStopExecution} title="Code ausführen (Shift + Enter)" />;
    const stopIcon = <Icon name="stop" className="danger icon-control hidden-print" onClick={this.onStartStopExecution} title="Code stoppen" />;
    const undoIcon = <Icon name="undo" className="danger icon-control hidden-print" onClick={this.onUndoChanges} title="Änderungen rückgängig machen" />;
    const closeTerminalIcon = <Icon name="close" className="close-btn icon-control hidden-print" onClick={this.onCloseTerminal} title="Terminal schliessen" />;
    const additionalPanels = showTerminal ? this.handleAdditionalPanels(tabs, project, code) : null;
    //const missingEmbed =
Ungültiger embedType. Wenden Sie sich an den Autor!
;

    const ideArea =

      { showTerminal ? closeTerminalIcon : null }
      { (project && project.runner) ? <Terminal process={project.runner}/> : null}
      { additionalPanels }

;

    return (

          { /*!project ? missingEmbed : null*/}

            { externalIcon }
            { editMode ? readIcon : editIcon}
            { project ? (project.isRunning() ? stopIcon : playIcon) : playIcon}
            { this.session ? (this.session.getUndoManager().hasUndo() ? null : undoIcon) : null }

          { editMode ? this.renderEditMode() : this.renderReadMode() }
          { showTerminal ? ideArea : null }

    );
  }
}

CodeCellView.propTypes = {
  viewComponent: PropTypes.oneOfType([
    PropTypes.func,
    PropTypes.element
  ]), /* use this instead of markdown-it */
  code: PropTypes.string.isRequired,
  cell: PropTypes.object.isRequired,
  executionLanguage: PropTypes.object.isRequired,
  notebookLanguage: PropTypes.string.isRequired,
  embedType: PropTypes.string.isRequired,
  className: PropTypes.string,
  minHeight: PropTypes.number
};

CodeCellView.defaultProps = {
  viewComponent: CodeBlock,
  className: '',
  minHeight: 100
};

CodeCellView.contextTypes = {
  messageList: PropTypes.object,
  remoteDispatcher: PropTypes.object
};<|endoftext|>


<commit_before>var express = require('express');
var request = require('request');
var cheerio = require('cheerio');
var moment = require('moment');
var router = express.Router();

/* GET kickstarter project info. */
router.get('/kickstarter/:userId/:projectName', function(req, res) {
  var url = [
    'http://kickstarter.com/projects',
    req.params.userId,
    req.params.projectName
  ].join('/');

  request(url, function(error, response, html){
    if(!error){
      var $ = cheerio.load(html);
      var projectTitle = $('#project-header .title h2').text();
      if(!projectTitle) {
        res.status(404);
        res.render('error', {
            message: 'Shoot, we can\'t find a project called ' + req.params.projectName,
            error: 'Not Found'
        });
        return;
      }

      var json = {
        project: {},
        perks: []
      };

      function trimString (str) {
        return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
      }
      // Set up all the project info
      json.project.title = trimString(projectTitle);
      json.project.url = url;
      json.project.video = [
        url,
        'widget/video.html'
      ].join('/');
      json.project.videoEmbed = [
        ''
      ].join('');
      json.project.backers = $('*[data-backers-count]').data('backers-count');
      json.project.raised = '$' + Math.ceil($('.NS_projects__ecom #pledged').data('pledged'));
      json.project.goal = '$' + Math.ceil($('.NS_projects__ecom #pledged').data('goal'));
      json.project.percentRaised = parseInt($('.NS_projects__ecom #pledged').data('percent-raised') * 100) + '%';
      json.project.ends = moment(trimString($('.NS_projects__ecom #stats div h5').data('end_time'))).fromNow();

      // Loop thru all the perks and poplute the perks object
      $('.NS-projects-rightcol-rewards .NS-projects-reward').each(function( index ) {
        data = $(this);

        // If the campaign is still active, set the pledge url
        // Otherwise, just link to the project
        if (data.find('.pledge').attr('href')) {
          var pledgeUrl = 'http://www.kickstarter.com' + data.find('.pledge').attr('href');
        } else {
          var pledgeUrl = url;
        }

        // Check if is is a limited perk
        var amountAvailable = data.find('.limited-number').text().replace(/[^\w\s]/gi, '');
        var re = /(.*\ \s+)(.*)(\s+i\).*)/;
        var newtext = amountAvailable.replace(re, "$2");

        // Set up the perks objects
        var perk = {
          title: trimString(data.find('.mb1').text()),
          amount: '$' + trimString(data.find('.mb1').text()).replace(/\D/g,''),
          url: pledgeUrl,
          description: data.find('.desc p').text(),
          deliveryDate: data.find('.delivery-date time').text(),
          claimed: parseInt(data.find('.num-backers').text()),
          available: parseInt(amountAvailable.substring(amountAvailable.lastIndexOf(" ")+1)) || 'Unlimited'
        };
        json.perks.push(perk);
      });

      // Send the data
      res.json(json);
    } else {
      // Show the error page
      res.status(err.status || 404);
      res.render('error', {
          message: err.message,
          error: err
      });
    }
  })
});

module.exports = router;
<commit_msg>repaired broken embed link<commit_after>var express = require('express');
var request = require('request');
var cheerio = require('cheerio');
var moment = require('moment');
var router = express.Router();

/* GET kickstarter project info. */
router.get('/kickstarter/:userId/:projectName', function(req, res) {
  var url = [
    'http://kickstarter.com/projects',
    req.params.userId,
    req.params.projectName
  ].join('/');

  request(url, function(error, response, html){
    if(!error){
      var $ = cheerio.load(html);
      var projectTitle = $('#project-header .title h2').text();
      if(!projectTitle) {
        res.status(404);
        res.render('error', {
            message: 'Shoot, we can\'t find a project called ' + req.params.projectName,
            error: 'Not Found'
        });
        return;
      }

      var json = {
        project: {},
        perks: []
      };

      function trimString (str) {
        return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
      }
      // Set up all the project info
      json.project.title = trimString(projectTitle);
      json.project.url = url;
      json.project.video = [
        url,
        'widget/video.html'
      ].join('/');
      json.project.videoEmbed = [
        '',
        ''
        '',
      ].join('');
      json.project.backers = $('*[data-backers-count]').data('backers-count');
      json.project.raised = '$' + Math.ceil($('.NS_projects__ecom #pledged').data('pledged'));
      json.project.goal = '$' + Math.ceil($('.NS_projects__ecom #pledged').data('goal'));
      json.project.percentRaised = parseInt($('.NS_projects__ecom #pledged').data('percent-raised') * 100) + '%';
      json.project.ends = moment(trimString($('.NS_projects__ecom #stats div h5').data('end_time'))).fromNow();

      // Loop thru all the perks and poplute the perks object
      $('.NS-projects-rightcol-rewards .NS-projects-reward').each(function( index ) {
        data = $(this);

        // If the campaign is still active, set the pledge url
        // Otherwise, just link to the project
        if (data.find('.pledge').attr('href')) {
          var pledgeUrl = 'http://www.kickstarter.com' + data.find('.pledge').attr('href');
        } else {
          var pledgeUrl = url;
        }

        // Check if is is a limited perk
        var amountAvailable = data.find('.limited-number').text().replace(/[^\w\s]/gi, '');
        var re = /(.*\ \s+)(.*)(\s+i\).*)/;
        var newtext = amountAvailable.replace(re, "$2");

        // Set up the perks objects
        var perk = {
          title: trimString(data.find('.mb1').text()),
          amount: '$' + trimString(data.find('.mb1').text()).replace(/\D/g,''),
          url: pledgeUrl,
          description: data.find('.desc p').text(),
          deliveryDate: data.find('.delivery-date time').text(),
          claimed: parseInt(data.find('.num-backers').text()),
          available: parseInt(amountAvailable.substring(amountAvailable.lastIndexOf(" ")+1)) || 'Unlimited'
        };
        json.perks.push(perk);
      });

      // Send the data
      res.json(json);
    } else {
      // Show the error page
      res.status(err.status || 404);
      res.render('error', {
          message: err.message,
          error: err
      });
    }
  })
});

module.exports = router;
<|endoftext|>


<commit_before>'use strict';

var express      = require('express');
var configs      = require('../configs/global.configs');
var Article      = require('../models/Article');
var User         = require('../models/User');
var Category     = require('../models/Category');
var _            = require('lodash');
var moment       = require('moment');
var path         = require('path');
var fs           = require('fs');
var cheerio      = require('cheerio');
var sanitizeHtml = require('sanitize-html');

var router = express.Router();

Article.belongsTo(User, {foreignKey:'user_id', as:'User'});
Article.belongsTo(Category, {foreignKey:'category_id', as:'Category'});

module.exports = function(validator){

	router.get('/articles/new', function(req, res, next){ //create placeholder for new article
		var result = validator(req, res);

		if(result.success){

			let now = moment();

			Article.create({
				title: 'new article',
				valid: 1,
				start_time: now.format('YYYY-MM-DD HH:mm:ss'),
				approved: 0,
				at_top: 0,
				user_id: result.user_id
			})
			.then(function(article){
				article.category_id = null;
				res.json({
					success: true,
					message: 'Article created',
					record: article
				});
			})
			.catch(function(error){
				res.json({
					success: false,
					error: error,
					message: 'Unable to create article'
				});
			});

		} else {
			res.json(result);
		}
	});

	router.get('/articles/:id', function(req, res, next) {
		var result = validator(req, res);

		if(result.success){

			var id = req.params.id;

			if(!id){
				throw new Error('Invalid article ID');
			}

			Article.findOne({where: {id: id}, valid: 1}).then(function(result){

				if(!result){
					throw new Error('Invalid article');
				}

				res.json({
					success: true,
					record: result
				});

			}).catch(function(error){
				console.error(error);

				res.json({
					success: false,
					error: error
				});
			});

		} else {
			res.json(result);
		}
	});

	router.get('/articles', function(req, res, next) {

		var result = validator(req, res);

		if(result.success){

			var pageIndex  = parseInt(req.query.pageIndex);
			var pageSize   = parseInt(req.query.pageSize);
			var sortField  = _.trim(_.escape(req.query.sortField));
			var sortOrder  = _.trim(_.escape(req.query.sortOrder));

			var conditions          = { valid: 1 };
			var category_conditions = { valid: 1 };
			var user_conditions     = { valid: 1 };
			var order               = 'id desc';
			var filter              = '';

			for(filter in req.query){
				if(_.indexOf(['pageIndex','pageSize', 'sortField', 'sortOrder'], filter) === -1){

					var f_value = _.trim(_.escape(req.query[filter]));

					if(f_value){

						if(filter === 'category_name'){
							category_conditions['title'] = { '$like': '%' + f_value + '%' }
						} else if(filter === 'author'){
							user_conditions['username'] = { '$like': '%' + f_value + '%' }
						} else {
							conditions[filter] = { '$like': '%' + f_value + '%' };
						}
					}
				}
			}

			if(sortField){
				if(sortField === 'category_name'){
					sortField = '`Category`.`title`';
				}

				if(sortField === 'author'){
					sortField = '`User`.`username`';
				}
				order = sortField + ' ' + sortOrder;
			}

			pageIndex = !isNaN(pageIndex) ? pageIndex - 1 : 0;
			pageSize  = !isNaN(pageSize) ? pageSize : 20;

			Article.findAndCountAll({
				where:   conditions,
				order:   order,
				offset:  (pageIndex * pageSize),
				limit:   pageSize,
				attributes:['title', 'id', 'abstract', 'created', 'modified', 'thumbnail', 'video_url', 'at_top'],
				include: [
					{ model:Category, as:'Category', required: true, where: category_conditions, attributes:['title', 'id'] },
					{ model:User, as:'User', required: true, where: user_conditions, attributes:['username', 'id'] }
				]
			}).then(function(result){

				res.json({
					success:    true,
					data:       result.rows,
					itemsCount: result.count
				});

			}).catch(function(error){

				console.error(error);

				res.json({
					success: false,
					error: error
				});
			});

		} else {
			res.json(result);
		}
	});

	router.put('/articles', function(req, res, next) {
		var result = validator(req, res);

		if(result.success){

			var record = req.body;
			var id     = record.id;

			Article.find({where:{id:id}})
			.then(function(article){

				//find the first image in the content
				var $document = cheerio.load(record.content);
				var first_img = $document('img').first();

				if(first_img){
					record.thumbnail = first_img.attr('src');
				}

				record.content = sanitizeHtml(record.content, {
					allowedTags: [
					  'h1','h2','h3', 'h4', 'h5', 'h6', 'blockquote', 'p', 'a', 'ul', 'ol',
					  'nl', 'li', 'b', 'i', 'strong', 'em', 'strike', 'hr', 'br', 'div', 'img',
					  'table', 'thead', 'caption', 'tbody', 'tr', 'th', 'td', 'pre'
					],
					allowedAttributes: {
					  a: [ 'href', 'name', 'target', 'title'],
					  img: [ 'src' ]
					},
					// Lots of these won't come up by default because we don't allow them
					selfClosing: [ 'img', 'br', 'hr', 'area', 'base', 'basefont', 'input', 'link', 'meta' ],
					// URL schemes we permit
					allowedSchemes: [ 'http', 'https', 'mailto' ],
					allowProtocolRelative: true
				});

				article.updateAttributes(record).then(function(article){

					//clear the cache if any
					var cache_file_name = path.join(__dirname, '../public/articles/read', id + '.html');

					if(fs.existsSync(cache_file_name)){
						fs.unlink(cache_file_name);
					}

					res.json({
						success: true,
						record: article
					});
				})

				.catch(function(error){

					console.info('error @ /articles PUT:', error);

					res.json({
						success: false,
						error: error
					});
				});
			})
			.catch(function(error){

				console.info('error @ /articles PUT:', error);

				res.json({
					success: false,
					error: error
				});
			});

		}else {
			res.json(result);
		}
	});

	router.delete('/articles', function(req, res, next) {
		var result = validator(req, res);

		if(result.success){

			var record = req.body;
			var id     = record.id;

			Article.find({where:{id:id}})
			.then(function(article){

				article.updateAttributes({valid:0})
				.then(function(article){
					res.json(article);
				})
				.catch(function(error){
					console.info('Error @article delete:', error);
					res.json({
						success: false,
						error: error
					});
				});
			})
			.catch(function(error){
				console.info('Error @article delete:', error);
				res.json({
					success: false,
					error: error
				});
			});

		}else {
			res.json(result);
		}
	});

	return router;
}<commit_msg>Added HTML sanitization<commit_after>'use strict';

var express      = require('express');
var configs      = require('../configs/global.configs');
var Article      = require('../models/Article');
var User         = require('../models/User');
var Category     = require('../models/Category');
var _            = require('lodash');
var moment       = require('moment');
var path         = require('path');
var fs           = require('fs');
var cheerio      = require('cheerio');
var sanitizeHtml = require('sanitize-html');

var router = express.Router();

Article.belongsTo(User, {foreignKey:'user_id', as:'User'});
Article.belongsTo(Category, {foreignKey:'category_id', as:'Category'});

module.exports = function(validator){

	router.get('/articles/new', function(req, res, next){ //create placeholder for new article
		var result = validator(req, res);

		if(result.success){

			let now = moment();

			Article.create({
				title: 'new article',
				valid: 1,
				start_time: now.format('YYYY-MM-DD HH:mm:ss'),
				approved: 0,
				at_top: 0,
				user_id: result.user_id
			})
			.then(function(article){
				article.category_id = null;
				res.json({
					success: true,
					message: 'Article created',
					record: article
				});
			})
			.catch(function(error){
				res.json({
					success: false,
					error: error,
					message: 'Unable to create article'
				});
			});

		} else {
			res.json(result);
		}
	});

	router.get('/articles/:id', function(req, res, next) {
		var result = validator(req, res);

		if(result.success){

			var id = req.params.id;

			if(!id){
				throw new Error('Invalid article ID');
			}

			Article.findOne({where: {id: id}, valid: 1}).then(function(result){

				if(!result){
					throw new Error('Invalid article');
				}

				res.json({
					success: true,
					record: result
				});

			}).catch(function(error){
				console.error(error);

				res.json({
					success: false,
					error: error
				});
			});

		} else {
			res.json(result);
		}
	});

	router.get('/articles', function(req, res, next) {

		var result = validator(req, res);

		if(result.success){

			var pageIndex  = parseInt(req.query.pageIndex);
			var pageSize   = parseInt(req.query.pageSize);
			var sortField  = _.trim(_.escape(req.query.sortField));
			var sortOrder  = _.trim(_.escape(req.query.sortOrder));

			var conditions          = { valid: 1 };
			var category_conditions = { valid: 1 };
			var user_conditions     = { valid: 1 };
			var order               = 'id desc';
			var filter              = '';

			for(filter in req.query){
				if(_.indexOf(['pageIndex','pageSize', 'sortField', 'sortOrder'], filter) === -1){

					var f_value = _.trim(_.escape(req.query[filter]));

					if(f_value){

						if(filter === 'category_name'){
							category_conditions['title'] = { '$like': '%' + f_value + '%' }
						} else if(filter === 'author'){
							user_conditions['username'] = { '$like': '%' + f_value + '%' }
						} else {
							conditions[filter] = { '$like': '%' + f_value + '%' };
						}
					}
				}
			}

			if(sortField){
				if(sortField === 'category_name'){
					sortField = '`Category`.`title`';
				}

				if(sortField === 'author'){
					sortField = '`User`.`username`';
				}
				order = sortField + ' ' + sortOrder;
			}

			pageIndex = !isNaN(pageIndex) ? pageIndex - 1 : 0;
			pageSize  = !isNaN(pageSize) ? pageSize : 20;

			Article.findAndCountAll({
				where:   conditions,
				order:   order,
				offset:  (pageIndex * pageSize),
				limit:   pageSize,
				attributes:['title', 'id', 'abstract', 'created', 'modified', 'thumbnail', 'video_url', 'at_top'],
				include: [
					{ model:Category, as:'Category', required: true, where: category_conditions, attributes:['title', 'id'] },
					{ model:User, as:'User', required: true, where: user_conditions, attributes:['username', 'id'] }
				]
			}).then(function(result){

				res.json({
					success:    true,
					data:       result.rows,
					itemsCount: result.count
				});

			}).catch(function(error){

				console.error(error);

				res.json({
					success: false,
					error: error
				});
			});

		} else {
			res.json(result);
		}
	});

	router.put('/articles', function(req, res, next) {
		var result = validator(req, res);

		if(result.success){

			var record = req.body;
			var id     = record.id;

			Article.find({where:{id:id}})
			.then(function(article){

				//find the first image in the content
				var $document = cheerio.load(record.content);
				var first_img = $document('img').first();

				if(first_img){
					record.thumbnail = first_img.attr('src');
				}

				record.content = sanitizeHtml(record.content, {
					allowedTags: [
					  'h1','h2','h3', 'h4', 'h5', 'h6', 'blockquote', 'p', 'a', 'ul', 'ol',
					  'nl', 'li', 'b', 'i', 'strong', 'em', 'strike', 'hr', 'br', 'div', 'img',
					  'table', 'thead', 'caption', 'tbody', 'tr', 'th', 'td', 'pre', 'iframe'
					],
					allowedAttributes: {
					  a: [ 'href', 'name', 'target', 'title'],
					  img: [ 'src' ]
					},
					// Lots of these won't come up by default because we don't allow them
					selfClosing: [ 'img', 'br', 'hr', 'area', 'base', 'basefont', 'input', 'link', 'meta' ],
					// URL schemes we permit
					allowedSchemes: [ 'http', 'https', 'mailto' ],
					allowProtocolRelative: true
				});

				article.updateAttributes(record).then(function(article){

					//clear the cache if any
					var cache_file_name = path.join(__dirname, '../public/articles/read', id + '.html');

					if(fs.existsSync(cache_file_name)){
						fs.unlink(cache_file_name);
					}

					res.json({
						success: true,
						record: article
					});
				})

				.catch(function(error){

					console.info('error @ /articles PUT:', error);

					res.json({
						success: false,
						error: error
					});
				});
			})
			.catch(function(error){

				console.info('error @ /articles PUT:', error);

				res.json({
					success: false,
					error: error
				});
			});

		}else {
			res.json(result);
		}
	});

	router.delete('/articles', function(req, res, next) {
		var result = validator(req, res);

		if(result.success){

			var record = req.body;
			var id     = record.id;

			Article.find({where:{id:id}})
			.then(function(article){

				article.updateAttributes({valid:0})
				.then(function(article){
					res.json(article);
				})
				.catch(function(error){
					console.info('Error @article delete:', error);
					res.json({
						success: false,
						error: error
					});
				});
			})
			.catch(function(error){
				console.info('Error @article delete:', error);
				res.json({
					success: false,
					error: error
				});
			});

		}else {
			res.json(result);
		}
	});

	return router;
}<|endoftext|>


<commit_before>/**
 * Created by King Lee on 14-10-21.
 */
var redis_fly_flow_wrapper = require('./nosql/redis_fly_flow_wrapper');
var log4js = require('log4js');
var log_json = require('../config/log.json');
log4js.configure(log_json);
var http_logger = log4js.getLogger('http-logger');

exports.on_pay_result_verify = function(req,res){
    var orderid = req.body['orderid'];
    redis_fly_flow_wrapper.get(orderid,function(reply){
        var order_info = JSON.parse(reply);
        http_logger.debug(order_info);
        res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
        var code = "200";
        res.end(JSON.stringify({"code":code,"ret":order_info?order_info.ret:0,"amount":order_info?order_info.amount:0}));
    });
};
<commit_msg>add fly_flow_verify log<commit_after>/**
 * Created by King Lee on 14-10-21.
 */
var redis_fly_flow_wrapper = require('./nosql/redis_fly_flow_wrapper');
var log4js = require('log4js');
var log_json = require('../config/log.json');
log4js.configure(log_json);
var http_logger = log4js.getLogger('http-logger');

exports.on_pay_result_verify = function(req,res){
    var orderid = req.body['orderid'];
    http_logger.debug(orderid);
    redis_fly_flow_wrapper.get(orderid,function(reply){
        var order_info = JSON.parse(reply);
        http_logger.debug(order_info);
        res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
        var code = "200";
        res.end(JSON.stringify({"code":code,"ret":order_info?order_info.ret:0,"amount":order_info?order_info.amount:0}));
    });
};
<|endoftext|>


<commit_before>var express = require('express');
var path = require('path');
var ejs = require('ejs');
var fs = require('fs');
var router = express.Router();
var filter = require('../passport.js');
var Project = require('../../db/project');
var Page = require('../../db/page');
var Btncom = require('../../db/btncom');
var Imgcom = require('../../db/imgcom');
var Textcom = require('../../db/textcom');
var View = require('../../db/view');
var previewPath = path.resolve(__dirname, '../../public/preview');
var previewTPL = path.resolve(__dirname, 'preview.html');

/* GET home page. */
router.get('/', function (req, res, next) {
    filter.authorize(req, res, function (req, res) {
        var projectId = req.query.projectId;
        var allPage = [];
        Page.getPageList(projectId, function (err, pageList) {

            if (err) {
                return;
            }

            if (pageList) {
                pageList.forEach(function (o) {
                    var onePage = o;
                    //Btncom
                    Btncom.getBtncomListByPageId(o._id, function (err, btncomList) {

                        if (err) {

                            return;
                        }
                        if (btncomList) {
                            onePage.btncomtList = btncomList;
                        }

                        //Imgcom
                        Imgcom.getImgcomListByPageId(o._id, function (err, imgcomList) {
                            if (err) {

                                return;
                            }
                            if (imgcomList) {
                                onePage.imgcomList = imgcomList;
                            }
                            //Textcom
                            Textcom.getTextcomListByPageId(o._id, function (err, textcomList) {
                                if (err) {

                                    return;
                                }
                                if (textcomList) {
                                    onePage.textcomList = textcomList;
                                }

                                allPage.push(onePage);
                                if (allPage.length === pageList.length) {
                                    Project.getProject(projectId, function (err, projectEntity) {
                                        if (err) {
                                            return;
                                        }

                                        if (projectEntity) {
                                            createHTML(projectEntity.updatetime.getTime(), projectId, allPage, res);
                                        }
                                    });
                                }
                            });
                            //Textcom End
                        });
                        //Imgcom End

                    });
                    //Btncom End

                });
            }

        });

    })
});

function createHTML(uid, projectId, allPage, res) {
    var str = fs.readFileSync(previewTPL, {encoding: 'UTF-8'});

    allPage.sort(function (a, b) {
        if (a.sortindex > b.sortindex) {
            return 1;
        } else {
            return -1;
        }
    });
    var html = ejs.render(str, {allPage: allPage});
    var isExists = fs.existsSync(previewPath);
    var previewSrc = '';

    if (!isExists) {
        fs.mkdirSync(previewPath);
    }

    View.getView(uid, function (err, view) {
        if (err) {
            return;
        }

        if (view) {
            previewSrc = view.url;
            if (view.uid != uid) {
                previewSrc = writeHTML();
            }
        } else {
            previewSrc = writeHTML();
        }
        res.render('preview', {previewSrc: previewSrc})
    });

    function writeHTML() {
        var newPreviewPath = path.join(previewPath, projectId + '');
        if (!fs.existsSync(newPreviewPath)) {
            fs.mkdirSync(newPreviewPath);
        }
        fs.writeFileSync(path.join(newPreviewPath, 'index.html'), html);
        var view = new View({
            url: path.join(path.sep, 'preview', projectId + '', 'index.html'),
            uid: uid,
            project: projectId
        });
        view.save();
        return path.join(path.sep, 'preview', projectId + '', 'index.html');
    }

}

module.exports = router;<commit_msg>增加jsonp接口<commit_after>var express = require('express');
var path = require('path');
var ejs = require('ejs');
var fs = require('fs');
var router = express.Router();
var filter = require('../passport.js');
var Project = require('../../db/project');
var Page = require('../../db/page');
var Btncom = require('../../db/btncom');
var Imgcom = require('../../db/imgcom');
var Textcom = require('../../db/textcom');
var View = require('../../db/view');
var previewPath = path.resolve(__dirname, '../../public/preview');
var previewTPL = path.resolve(__dirname, 'preview.html');

/* GET home page. */
router.get('/', function (req, res, next) {
    filter.authorize(req, res, function (req, res) {
        var projectId = req.query.projectId;
        var allPage = [];
        Page.getPageList(projectId, function (err, pageList) {

            if (err) {
                return;
            }

            if (pageList) {
                pageList.forEach(function (o) {
                    var onePage = o;
                    //Btncom
                    Btncom.getBtncomListByPageId(o._id, function (err, btncomList) {

                        if (err) {

                            return;
                        }
                        if (btncomList) {
                            onePage.btncomtList = btncomList;
                        }

                        //Imgcom
                        Imgcom.getImgcomListByPageId(o._id, function (err, imgcomList) {
                            if (err) {

                                return;
                            }
                            if (imgcomList) {
                                onePage.imgcomList = imgcomList;
                            }
                            //Textcom
                            Textcom.getTextcomListByPageId(o._id, function (err, textcomList) {
                                if (err) {

                                    return;
                                }
                                if (textcomList) {
                                    onePage.textcomList = textcomList;
                                }

                                allPage.push(onePage);
                                if (allPage.length === pageList.length) {
                                    Project.getProject(projectId, function (err, projectEntity) {
                                        if (err) {
                                            return;
                                        }

                                        if (projectEntity) {
                                            createHTML(projectEntity.updatetime.getTime(), projectId, allPage, res);
                                        }
                                    });
                                }
                            });
                            //Textcom End
                        });
                        //Imgcom End

                    });
                    //Btncom End

                });
            }

        });

    })
});

function createHTML(uid, projectId, allPage, res) {
    var str = fs.readFileSync(previewTPL, {encoding: 'UTF-8'});

    allPage.sort(function (a, b) {
        if (a.sortindex > b.sortindex) {
            return 1;
        } else {
            return -1;
        }
    });
    var html = ejs.render(str, {allPage: allPage});
    var isExists = fs.existsSync(previewPath);
    var previewSrc = '';

    if (!isExists) {
        fs.mkdirSync(previewPath);
    }

    View.getView(uid, function (err, view) {
        if (err) {
            return;
        }

        if (view) {
            previewSrc = view.url;
            if (view.uid != uid) {
                previewSrc = writeHTML();
            }
        } else {
            previewSrc = writeHTML();
        }
        res.render('preview', {previewSrc: previewSrc})
    });

    function writeHTML() {
        var newPreviewPath = path.join(previewPath, projectId + '');
        if (!fs.existsSync(newPreviewPath)) {
            fs.mkdirSync(newPreviewPath);
        }
        fs.writeFileSync(path.join(newPreviewPath, 'index.html'), html);
        var view = new View({
            url: path.join(path.sep, 'preview', projectId + '', 'index.html'),
            uid: uid,
            project: projectId
        });
        view.save();
        return path.join(path.sep, 'preview', projectId + '', 'index.html');
    }

}

/* GET home page. */
router.get('/jsonp', function (req, res, next) {
    var projectId = req.query.projectId;
    var allPage = [];
    Page.getPageList(projectId, function (err, pageList) {
        if (err || !pageList.length) {
            res.status('404');
            res.send({
                success: false, // 标记失败
                model: {
                    error: '系统错误'
                }
            });
            return;
        }

        if (pageList) {
            pageList.forEach(function (o) {
                var onePage = o;
                //Btncom
                Btncom.getBtncomListByPageId(o._id, function (err, btncomList) {

                    if (err || !btncomList.length) {
                        res.status('404');
                        res.send({
                            success: false, // 标记失败
                            model: {
                                error: '系统错误'
                            }
                        });
                        return;
                    }
                    if (btncomList) {
                        onePage.btncomtList = btncomList;
                    }

                    //Imgcom
                    Imgcom.getImgcomListByPageId(o._id, function (err, imgcomList) {
                        if (err || !imgcomList.length) {
                            res.status('404');
                            res.send({
                                success: false, // 标记失败
                                model: {
                                    error: '系统错误'
                                }
                            });
                            return;
                        }
                        if (imgcomList) {
                            onePage.imgcomList = imgcomList;
                        }
                        //Textcom
                        Textcom.getTextcomListByPageId(o._id, function (err, textcomList) {
                            if (err || !textcomList.length) {
                                res.status('404');
                                res.send({
                                    success: false, // 标记失败
                                    model: {
                                        error: '系统错误'
                                    }
                                });
                                return;
                            }
                            if (textcomList) {
                                onePage.textcomList = textcomList;
                            }

                            allPage.push(onePage);
                            if (allPage.length === pageList.length) {
                                res.status('200');
                                res.jsonp(allPage);
                            }
                        });
                        //Textcom End
                    });
                    //Imgcom End

                });
                //Btncom End

            });
        }

    });

});

module.exports = router;<|endoftext|>


<commit_before>var keystone 	= require('keystone'),
	async		= require('async'),
	_			= require('underscore'),
	moment		= require('moment'),
	Event		= keystone.list('Event'),
	Utils		= require('../middleware/utilities'),
	pageService	= require('../middleware/service_page');

exports = module.exports = function(req, res) {
	'use strict';

	var view		= new keystone.View(req, res),
		locals		= res.locals,
		userType	= req.user ? req.user.userType : '', // Knowing the type of user visiting the page will allow us to display extra relevant information
		eventType, 		// Used to map the url to the stored event for determining which subset of events to show
		targetGroup;	// Used to map to the different attendee groups to simplify searching for whether the user is attending

	switch(userType) {
		case 'admin'			: targetGroup = 'staffAttendees'; break;
		case 'family'			: targetGroup = 'familyAttendees'; break;
		case 'social worker'	: targetGroup = 'socialWorkerAttendees'; break;
		case 'site visitor'		: targetGroup = 'siteVisitorAttendees'; break;
		default					: targetGroup = '';
	}

	// Use the URL stored in the request object to determine what event type we need to list out
	var targetList = req.originalUrl.replace('/events/', '');

	switch(targetList) {
		case 'adoption-parties/'		: eventType = 'MARE adoption parties & information events'; locals.showAdoptionParties = true; break;
		case 'mapp-trainings/'			: eventType = 'MAPP trainings'; locals.showMAPPTrainings = true; break;
		case 'fundraising-events/'		: eventType = 'fundraising events'; locals.showFundraisingEvents = true; break;
		case 'agency-info-meetings/'	: eventType = 'agency information meetings'; locals.showAgencyInfoMeetings = true; break;
		case 'other-trainings/'			: eventType = 'other opportunities & trainings'; locals.showOtherTrainings = true; break;
		default							: eventType = '';
	}

	async.parallel([
		function(done) { // TODO: Pull this into the Event service
			Event.model.find()
				.where('type', eventType) // Grab only the events matching the target category
				.where('isActive', true) // We don't want to show inactive events
				.populate(targetGroup)
				.populate('address.state')
				.exec()
				.then(function (events) {
					req.user = req.user || {};
					// determine if the user is a social worker.  We want to allow them to create events if they are
					locals.isSocialWorker = req.user && req.user.userType === 'social worker' ? true : false;
					// If there are no events to display, we need to capture that information for rendering
					locals.noEvents = events.length > 0 ? false : true;
					// An array to hold all events for use during templating
					locals.events = [];
					// A set of options to define how truncation will be handled
					var truncateOptions = {
						targetLength: 400
					}

					// Loop through all events
					_.each(events, function(event) {
						// The list page needs truncated details information to keep the cards they're displayed on small
						event.shortContent = Utils.truncateText(event.description, truncateOptions);
						// Determine whether or not address information exists for the event, which is helpful during rendering
						// street1 is required, so this is enough to tell us if the address has been populated
						event.hasAddress = event.address && event.address.street1 ? true : false;

						_.each(event[targetGroup], function(attendee) {
							// Without converting to strings, these were both evaluating to Object which didn't allow for a clean comparison
							var attendeeID	= attendee._id.toString(),
								userID		= req.user._id.toString();

							// Determine whether the user has already attended the event
							event.attended = attendeeID === userID ? true : false;

							// Pull the date and time into a string for easier templating
							event.dateString = moment(event.date).format('dddd MMMM Do, YYYY');
						});

						// Store all events in an array on locals to expose them during templating
						locals.events.push(event);
					});

					done();

				});
		},
		function(done) { pageService.populateSidebar(req, res, done); },
		function(done) { pageService.getSectionHeader(req, res, done, 'Events'); }
	], function() {
		// Set the layout to render with the right sidebar
		locals['render-with-sidebar'] = true;
		// Render the view once all the data has been retrieved
		view.render('eventList');
	});
};
<commit_msg>#111 | fix dates not showing up for anonymous users in events lists<commit_after>var keystone 	= require('keystone'),
	async		= require('async'),
	_			= require('underscore'),
	moment		= require('moment'),
	Event		= keystone.list('Event'),
	Utils		= require('../middleware/utilities'),
	pageService	= require('../middleware/service_page');

exports = module.exports = function(req, res) {
	'use strict';

	var view		= new keystone.View(req, res),
		locals		= res.locals,
		userType	= req.user ? req.user.userType : '', // Knowing the type of user visiting the page will allow us to display extra relevant information
		eventType, 		// Used to map the url to the stored event for determining which subset of events to show
		targetGroup;	// Used to map to the different attendee groups to simplify searching for whether the user is attending

	switch(userType) {
		case 'admin'			: targetGroup = 'staffAttendees'; break;
		case 'family'			: targetGroup = 'familyAttendees'; break;
		case 'social worker'	: targetGroup = 'socialWorkerAttendees'; break;
		case 'site visitor'		: targetGroup = 'siteVisitorAttendees'; break;
		default					: targetGroup = '';
	}

	// Use the URL stored in the request object to determine what event type we need to list out
	var targetList = req.originalUrl.replace('/events/', '');

	switch(targetList) {
		case 'adoption-parties/'		: eventType = 'MARE adoption parties & information events'; locals.showAdoptionParties = true; break;
		case 'mapp-trainings/'			: eventType = 'MAPP trainings'; locals.showMAPPTrainings = true; break;
		case 'fundraising-events/'		: eventType = 'fundraising events'; locals.showFundraisingEvents = true; break;
		case 'agency-info-meetings/'	: eventType = 'agency information meetings'; locals.showAgencyInfoMeetings = true; break;
		case 'other-trainings/'			: eventType = 'other opportunities & trainings'; locals.showOtherTrainings = true; break;
		default							: eventType = '';
	}

	async.parallel([
		function(done) { // TODO: Pull this into the Event service
			Event.model.find()
				.where('type', eventType) // Grab only the events matching the target category
				.where('isActive', true) // We don't want to show inactive events
				.populate(targetGroup)
				.populate('address.state')
				.exec()
				.then(function (events) {
					req.user = req.user || {};
					// determine if the user is a social worker.  We want to allow them to create events if they are
					locals.isSocialWorker = req.user && req.user.userType === 'social worker' ? true : false;
					// If there are no events to display, we need to capture that information for rendering
					locals.noEvents = events.length > 0 ? false : true;
					// An array to hold all events for use during templating
					locals.events = [];
					// A set of options to define how truncation will be handled
					var truncateOptions = {
						targetLength: 400
					}

					// Loop through all events
					_.each(events, function(event) {
						// The list page needs truncated details information to keep the cards they're displayed on small
						event.shortContent = Utils.truncateText(event.description, truncateOptions);
						// Determine whether or not address information exists for the event, which is helpful during rendering
						// street1 is required, so this is enough to tell us if the address has been populated
						event.hasAddress = event.address && event.address.street1 ? true : false;

						_.each(event[targetGroup], function(attendee) {
							// Without converting to strings, these were both evaluating to Object which didn't allow for a clean comparison
							var attendeeID	= attendee._id.toString(),
								userID		= req.user._id.toString();

							// Determine whether the user has already attended the event
							event.attended = attendeeID === userID ? true : false;
						});
						// Pull the date and time into a string for easier templating
						event.dateString = moment(event.date).format('dddd MMMM Do, YYYY');
						// Store all events in an array on locals to expose them during templating
						locals.events.push(event);
					});

					done();

				});
		},
		function(done) { pageService.populateSidebar(req, res, done); },
		function(done) { pageService.getSectionHeader(req, res, done, 'Events'); }
	], function() {
		// Set the layout to render with the right sidebar
		locals['render-with-sidebar'] = true;
		// Render the view once all the data has been retrieved
		view.render('eventList');
	});
};
<|endoftext|>


<commit_before>import express from 'express';
import bodyParser from 'body-parser';
import { makeExecutableSchema } from 'graphql-tools';
import { apolloExpress } from 'apollo-server';
import proxyMiddleware from 'http-proxy-middleware';
import { graphiqlExpress } from 'graphql-server-express';
import { GraphQLSchema } from 'graphql';
import { maskErrors } from 'graphql-errors';
import { formatError } from 'apollo-errors';
import cors from 'cors';

// graphql resources
import RootQuery from '/imports/graphql/queries/rootQuery';
import RootMutation from '/imports/graphql/mutations/rootMutation';
import RootSubscription from '/imports/graphql/subscriptions/rootSubscription';

/**
 * Root schema
 * @type {GraphQLSchema}
 */

const getGraphglContext = req => {
	return {token: req.headers.authorization};
};

const RootSchema = new GraphQLSchema({
	query: RootQuery,
	mutation: RootMutation,
	subscription: RootSubscription,
});

// mask error messages
maskErrors(RootSchema);

const GRAPHQL_PORT = 4000;

const graphQLServer = express();

const whitelist = [
	'http://localhost:3000',
	'http://admin.localhost.dev:3000'
];
const corsOptions = {
	origin: (origin, callback) => {
		const originIsWhitelisted = whitelist.indexOf(origin) !== -1;
		callback(null, originIsWhitelisted);
	},
	credentials: true
};
graphQLServer.use(cors(corsOptions));

graphQLServer.use('/graphql', bodyParser.json(), apolloExpress(req => ({
	schema: RootSchema,
	formatError,
	context: getGraphglContext(req),
})));
graphQLServer.use('/graphiql', graphiqlExpress({ endpointURL: '/graphql' }));

graphQLServer.listen(GRAPHQL_PORT);
WebApp.rawConnectHandlers.use(proxyMiddleware(`http://localhost:${GRAPHQL_PORT}/graphql`));
<commit_msg>update cors settings for local, dev, and prod environments<commit_after>import express from 'express';
import bodyParser from 'body-parser';
import { makeExecutableSchema } from 'graphql-tools';
import { apolloExpress } from 'apollo-server';
import proxyMiddleware from 'http-proxy-middleware';
import { graphiqlExpress } from 'graphql-server-express';
import { GraphQLSchema } from 'graphql';
import { maskErrors } from 'graphql-errors';
import { formatError } from 'apollo-errors';
import cors from 'cors';

// graphql resources
import RootQuery from '/imports/graphql/queries/rootQuery';
import RootMutation from '/imports/graphql/mutations/rootMutation';
import RootSubscription from '/imports/graphql/subscriptions/rootSubscription';

/**
 * Root schema
 * @type {GraphQLSchema}
 */

const getGraphglContext = req => {
	return {token: req.headers.authorization};
};

const RootSchema = new GraphQLSchema({
	query: RootQuery,
	mutation: RootMutation,
	subscription: RootSubscription,
});

// mask error messages
maskErrors(RootSchema);

const GRAPHQL_PORT = 4000;

const graphQLServer = express();

const whitelist = [
	/\.chs\.local$/,
	/\.orphe\.us$/,
	/\.chs\.harvard\.edu$/,
];

const corsOptions = {
	origin: whitelist,
	credentials: true,
};
graphQLServer.use(cors(corsOptions));

graphQLServer.use('/graphql', bodyParser.json(), apolloExpress(req => ({
	schema: RootSchema,
	formatError,
	context: getGraphglContext(req),
})));
graphQLServer.use('/graphiql', graphiqlExpress({ endpointURL: '/graphql' }));

graphQLServer.listen(GRAPHQL_PORT);
WebApp.rawConnectHandlers.use(proxyMiddleware(`http://localhost:${GRAPHQL_PORT}/graphql`));
<|endoftext|>


<commit_before>var Hal = function () {
    this.knowledge = {'what is the answer to life the universe and everything?': '42'};
    this.currentQuestion = '';
    this.name = 'HAL BOT';
    console.log(this.name + ' AWAKEN');
};

Hal.prototype.eavesdrop = function (message) {
    if (message.endsWith('?')) {
        if (message in this.knowledge) {
            return {
                    author: this.name,
                    msg: this.knowledge[message],
                    human: false
                };
        } else {
            this.currentQuestion = message;
        }
    } else {
        if (this.currentQuestion) {
            console.log('KNOWLEDGE GAINED: ' + this.currentQuestion + ' -> ' + message);
            this.knowledge[this.currentQuestion] = message;
            this.currentQuestion = '';
        }
    }

    return '';
};

module.exports = Hal;

<commit_msg>adding case insensitve AI<commit_after>var Hal = function () {
    this.knowledge = {'what is the answer to life the universe and everything?': '42'};
    this.currentQuestion = '';
    this.name = 'HAL BOT';
    console.log(this.name + ' AWAKEN');
};

Hal.prototype.eavesdrop = function (message) {
    message = message.toLowerCase();
    if (message.endsWith('?')) {
        if (message in this.knowledge) {
            return {
                    author: this.name,
                    msg: this.knowledge[message],
                    human: false
                };
        } else {
            this.currentQuestion = message;
        }
    } else {
        if (this.currentQuestion) {
            console.log('KNOWLEDGE GAINED: ' + this.currentQuestion + ' -> ' + message);
            this.knowledge[this.currentQuestion] = message;
            this.currentQuestion = '';
        }
    }

    return '';
};

module.exports = Hal;

<|endoftext|>


<commit_before>var crypto = require('crypto');
var defaults = require('lodash.defaults');
var fs = require('fs');
var mustache = require('mustache');
var path = require('path');

var config = require('./config');

/**
 * Constructor
 */
function Handler (route) {
    // Route definition
    defaults(route, config);

    // Render template
    var location = path.resolve(__dirname, './template.html');
    var template = fs.readFileSync(location, 'utf8');
    var output = mustache.render(template, route);
    var checksum = crypto.createHash('md5').update(output).digest('hex');

    return function (req, res) {
        res.set({
            'Content-Type': 'text/html',
            'Cache-Control': 'public, max-age=31536000',
            'Etag': 'W/"' + checksum + '"'
        });
        res.send(output);
    };
}

/**
 * Export a new instance
 */
module.exports = function (route) {
    return new Handler(route);
};
<commit_msg>Make template caching strong<commit_after>var crypto = require('crypto');
var defaults = require('lodash.defaults');
var fs = require('fs');
var mustache = require('mustache');
var path = require('path');

var config = require('./config');

/**
 * Constructor
 */
function Handler (route) {
    // Route definition
    defaults(route, config);

    // Render template
    var location = path.resolve(__dirname, './template.html');
    var template = fs.readFileSync(location, 'utf8');
    var output = mustache.render(template, route);
    var checksum = crypto.createHash('md5').update(output).digest('hex');

    return function (req, res) {
        res.set({
            'Content-Type': 'text/html',
            'Cache-Control': 'public, max-age=31536000',
            'Etag': '"' + checksum + '"'
        });
        res.send(output);
    };
}

/**
 * Export a new instance
 */
module.exports = function (route) {
    return new Handler(route);
};
<|endoftext|>