<commit_before>/*
 * == BSD2 LICENSE ==
 * Copyright (c) 2014, Tidepool Project
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the associated License, which is identical to the BSD 2-Clause
 * License as published by the Open Source Initiative at opensource.org.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the License for more details.
 *
 * You should have received a copy of the License along with this program; if
 * not, you can obtain one from Tidepool Project at tidepool.org.
 * == BSD2 LICENSE ==
 */

var i18next = require('i18next');
var t = i18next.t.bind(i18next);

var d3 = require('d3');
var _ = require('lodash');

var log = require('bows')('Shapes');

var legend = {
  SHAPE_MARGIN: 3,
  SHAPE_WIDTH: 15.5,
  basal: [
    {
      create: function(opts) {
        opts.widths.push(opts.SHAPE_WIDTH);
        return opts.selection.append('rect')
          .attr({
            'class': 'd3-basal d3-rect-basal d3-legend'
          });
      },
      type: 'rect'
    },
    {
      create: function(opts) {
        return opts.selection.append('text')
          .attr({
            'class': 'd3-pool-legend'
          })
          .text(t('delivered'))
          .each(function() {
            opts.widths.push(this.getBoundingClientRect().width);
            opts.textHeight = this.getBoundingClientRect().height;
          });
      },
      type: 'text'
    },
    {
      create: function(opts) {
        opts.widths.push(opts.SHAPE_WIDTH);
        return opts.selection.append('rect')
          .attr({
            'class': 'd3-basal d3-rect-basal-undelivered'
          });
      },
      type: 'rect'
    },
    {
      create: function(opts) {
        return opts.selection.append('text')
          .attr({
            'class': 'd3-pool-legend'
          })
          .text(t('scheduled'))
          .each(function() {
            opts.widths.push(this.getBoundingClientRect().width);
          });
      },
      type: 'text'
    }
  ],
  bg: [
    {
      create: function(opts) {
        return opts.selection.append('text')
          .attr({
            'class': 'd3-pool-legend'
          })
          .text(t('high'))
          .each(function() {
            opts.widths.push(this.getBoundingClientRect().width);
            opts.textHeight = this.getBoundingClientRect().height;
          });
      },
      type: 'text'
    },
    {
      create: function(opts) {
        opts.widths.push(opts.SHAPE_WIDTH);
        return opts.selection.append('circle')
          .attr({
            'class': 'd3-smbg d3-circle-smbg d3-bg-high'
          });
      },
      type: 'circle'
    },
    {
      create: function(opts) {
        opts.widths.push(opts.SHAPE_WIDTH);
        return opts.selection.append('circle')
          .attr({
            'class': 'd3-smbg d3-circle-smbg d3-bg-high d3-circle-open'
          });
      },
      type: 'circle'
    },
    {
      create: function(opts) {
        opts.widths.push(opts.SHAPE_WIDTH);
        return opts.selection.append('circle')
          .attr({
            'class': 'd3-smbg d3-circle-smbg d3-bg-target'
          });
      },
      type: 'circle'
    },
    {
      create: function(opts) {
        opts.widths.push(opts.SHAPE_WIDTH);
        return opts.selection.append('circle')
          .attr({
            'class': 'd3-smbg d3-circle-smbg d3-bg-low d3-circle-open'
          });
      },
      type: 'circle'
    },
    {
      create: function(opts) {
        opts.widths.push(opts.SHAPE_WIDTH);
        return opts.selection.append('circle')
          .attr({
            'class': 'd3-smbg d3-circle-smbg d3-bg-low'
          });
      },
      type: 'circle'
    },
    {
      create: function(opts) {
        return opts.selection.append('text')
          .attr({
            'class': 'd3-pool-legend'
          })
          .text(t('low'))
          .each(function() {
            opts.widths.push(this.getBoundingClientRect().width);
          });
      },
      type: 'text'
    },
  ],
  bolus: [
    {
      create: function(opts) {
        opts.widths.push(opts.SHAPE_WIDTH);
        return opts.selection.append('rect')
          .attr({
            'class': 'd3-bolus d3-rect-bolus-legend'
          });
      },
      type: 'rect'
    },
    {
      create: function(opts) {
        return opts.selection.append('text')
          .attr({
            'class': 'd3-pool-legend'
          })
          .text(t('delivered'))
          .each(function() {
            opts.widths.push(this.getBoundingClientRect().width);
            opts.textHeight = this.getBoundingClientRect().height;
          });
      },
      type: 'text'
    },
    {
      create: function(opts) {
        opts.widths.push(opts.SHAPE_WIDTH);
        return opts.selection.append('rect')
          .attr({
            'class': 'd3-bolus d3-rect-recommended-legend'
          });
      },
      type: 'rect'
    },
    {
      create: function(opts) {
        return opts.selection.append('text')
          .attr({
            'class': 'd3-pool-legend'
          })
          .text(t('undelivered'))
          .each(function() {
            opts.widths.push(this.getBoundingClientRect().width);
            opts.textHeight = this.getBoundingClientRect().height;
          });
      },
      type: 'text'
    }
  ],
  carbs: [
    {
      create: function(opts) {
        opts.widths.push(opts.SHAPE_WIDTH);
        return opts.selection.append('rect')
          .attr({
            'class': 'd3-rect-carbs-legend'
          });
      },
      type: 'rect'
    },
    {
      create: function(opts) {
        return opts.selection.append('text')
          .attr({
            'class': 'd3-pool-legend'
          })
          .text(t('carbs'))
          .each(function() {
            opts.widths.push(this.getBoundingClientRect().width);
            opts.textHeight = this.getBoundingClientRect().height;
          });
      },
      type: 'text'
    }
  ],
  cumWidth: function(a, i) {
    var b = a.slice();
    b.splice(i);
    return _.reduce(b, function(sum, num) { return sum + num; });
  },
  draw: function(selection, type) {
    var opts = {
      selection: selection,
      widths: [],
      SHAPE_WIDTH: this.SHAPE_WIDTH
    };
    var typeFns = this[type];
    _.each(typeFns, _.bind(function(fn, i) {
      var created = fn.create(opts), w;
      if (fn.type === 'text') {
        if (opts.widths[i - 1]) {
          w = this.cumWidth(opts.widths, i);
          if ((i === typeFns.length - 1) && (i !== 1)) {
            var s = this.SHAPE_WIDTH - this.SHAPE_MARGIN*2;
            created.attr('transform', 'translate(' + (-(w + s/2)) + ',0)');
          }
          else {
            created.attr('transform', 'translate(' + (-w) + ',0)');
          }
        }
      }
      else if (fn.type === 'circle') {
        if (opts.widths[i - 1]) {
          w = this.cumWidth(opts.widths, i);
          var r = (this.SHAPE_WIDTH - this.SHAPE_MARGIN*2)/2;
          created.attr({
            'cx': -(w + 2*r),
            'cy': -opts.textHeight/4,
            'r': r
          });
        }
      }
      else if (fn.type === 'rect') {
        var side = this.SHAPE_WIDTH - this.SHAPE_MARGIN*2;
        created.attr({
          'width': side,
          'height': side
        });
        if (opts.widths[i - 1]) {
          w = this.cumWidth(opts.widths, i);
          created.attr({
            'x': -w - this.SHAPE_WIDTH
          });
        }
        else {
          created.attr({
            'x': -side - 1.5
          });
        }
      }
    }, this));
    if (type !== 'bg') {
      // a y-attribute of 0 would put the top of the rects *at* the text baseline
      // so an upward (negative) shift of half the shape width works well
      var baselineShift = -(this.SHAPE_WIDTH/2 + this.SHAPE_MARGIN);
      selection.selectAll('rect')
        .attr('y', baselineShift);
    }
    var w;
    selection.each(function() { w = this.getBoundingClientRect(); });
    return w;
  }
};

module.exports = legend;
<commit_msg>Use 5-way bg colors for daily legend<commit_after>/*
 * == BSD2 LICENSE ==
 * Copyright (c) 2014, Tidepool Project
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the associated License, which is identical to the BSD 2-Clause
 * License as published by the Open Source Initiative at opensource.org.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the License for more details.
 *
 * You should have received a copy of the License along with this program; if
 * not, you can obtain one from Tidepool Project at tidepool.org.
 * == BSD2 LICENSE ==
 */

var i18next = require('i18next');
var t = i18next.t.bind(i18next);

var d3 = require('d3');
var _ = require('lodash');

var log = require('bows')('Shapes');

var legend = {
  SHAPE_MARGIN: 3,
  SHAPE_WIDTH: 15.5,
  basal: [
    {
      create: function(opts) {
        opts.widths.push(opts.SHAPE_WIDTH);
        return opts.selection.append('rect')
          .attr({
            'class': 'd3-basal d3-rect-basal d3-legend'
          });
      },
      type: 'rect'
    },
    {
      create: function(opts) {
        return opts.selection.append('text')
          .attr({
            'class': 'd3-pool-legend'
          })
          .text(t('delivered'))
          .each(function() {
            opts.widths.push(this.getBoundingClientRect().width);
            opts.textHeight = this.getBoundingClientRect().height;
          });
      },
      type: 'text'
    },
    {
      create: function(opts) {
        opts.widths.push(opts.SHAPE_WIDTH);
        return opts.selection.append('rect')
          .attr({
            'class': 'd3-basal d3-rect-basal-undelivered'
          });
      },
      type: 'rect'
    },
    {
      create: function(opts) {
        return opts.selection.append('text')
          .attr({
            'class': 'd3-pool-legend'
          })
          .text(t('scheduled'))
          .each(function() {
            opts.widths.push(this.getBoundingClientRect().width);
          });
      },
      type: 'text'
    }
  ],
  bg: [
    {
      create: function(opts) {
        return opts.selection.append('text')
          .attr({
            'class': 'd3-pool-legend'
          })
          .text(t('high'))
          .each(function() {
            opts.widths.push(this.getBoundingClientRect().width);
            opts.textHeight = this.getBoundingClientRect().height;
          });
      },
      type: 'text'
    },
    {
      create: function(opts) {
        opts.widths.push(opts.SHAPE_WIDTH);
        return opts.selection.append('circle')
          .attr({
            'class': 'd3-smbg d3-circle-smbg d3-bg-very-high'
          });
      },
      type: 'circle'
    },
    {
      create: function(opts) {
        opts.widths.push(opts.SHAPE_WIDTH);
        return opts.selection.append('circle')
          .attr({
            'class': 'd3-smbg d3-circle-smbg d3-bg-high'
          });
      },
      type: 'circle'
    },
    {
      create: function(opts) {
        opts.widths.push(opts.SHAPE_WIDTH);
        return opts.selection.append('circle')
          .attr({
            'class': 'd3-smbg d3-circle-smbg d3-bg-target'
          });
      },
      type: 'circle'
    },
    {
      create: function(opts) {
        opts.widths.push(opts.SHAPE_WIDTH);
        return opts.selection.append('circle')
          .attr({
            'class': 'd3-smbg d3-circle-smbg d3-bg-low'
          });
      },
      type: 'circle'
    },
    {
      create: function(opts) {
        opts.widths.push(opts.SHAPE_WIDTH);
        return opts.selection.append('circle')
          .attr({
            'class': 'd3-smbg d3-circle-smbg d3-bg-very-low'
          });
      },
      type: 'circle'
    },
    {
      create: function(opts) {
        return opts.selection.append('text')
          .attr({
            'class': 'd3-pool-legend'
          })
          .text(t('low'))
          .each(function() {
            opts.widths.push(this.getBoundingClientRect().width);
          });
      },
      type: 'text'
    },
  ],
  bolus: [
    {
      create: function(opts) {
        opts.widths.push(opts.SHAPE_WIDTH);
        return opts.selection.append('rect')
          .attr({
            'class': 'd3-bolus d3-rect-bolus-legend'
          });
      },
      type: 'rect'
    },
    {
      create: function(opts) {
        return opts.selection.append('text')
          .attr({
            'class': 'd3-pool-legend'
          })
          .text(t('delivered'))
          .each(function() {
            opts.widths.push(this.getBoundingClientRect().width);
            opts.textHeight = this.getBoundingClientRect().height;
          });
      },
      type: 'text'
    },
    {
      create: function(opts) {
        opts.widths.push(opts.SHAPE_WIDTH);
        return opts.selection.append('rect')
          .attr({
            'class': 'd3-bolus d3-rect-recommended-legend'
          });
      },
      type: 'rect'
    },
    {
      create: function(opts) {
        return opts.selection.append('text')
          .attr({
            'class': 'd3-pool-legend'
          })
          .text(t('undelivered'))
          .each(function() {
            opts.widths.push(this.getBoundingClientRect().width);
            opts.textHeight = this.getBoundingClientRect().height;
          });
      },
      type: 'text'
    }
  ],
  carbs: [
    {
      create: function(opts) {
        opts.widths.push(opts.SHAPE_WIDTH);
        return opts.selection.append('rect')
          .attr({
            'class': 'd3-rect-carbs-legend'
          });
      },
      type: 'rect'
    },
    {
      create: function(opts) {
        return opts.selection.append('text')
          .attr({
            'class': 'd3-pool-legend'
          })
          .text(t('carbs'))
          .each(function() {
            opts.widths.push(this.getBoundingClientRect().width);
            opts.textHeight = this.getBoundingClientRect().height;
          });
      },
      type: 'text'
    }
  ],
  cumWidth: function(a, i) {
    var b = a.slice();
    b.splice(i);
    return _.reduce(b, function(sum, num) { return sum + num; });
  },
  draw: function(selection, type) {
    var opts = {
      selection: selection,
      widths: [],
      SHAPE_WIDTH: this.SHAPE_WIDTH
    };
    var typeFns = this[type];
    _.each(typeFns, _.bind(function(fn, i) {
      var created = fn.create(opts), w;
      if (fn.type === 'text') {
        if (opts.widths[i - 1]) {
          w = this.cumWidth(opts.widths, i);
          if ((i === typeFns.length - 1) && (i !== 1)) {
            var s = this.SHAPE_WIDTH - this.SHAPE_MARGIN*2;
            created.attr('transform', 'translate(' + (-(w + s/2)) + ',0)');
          }
          else {
            created.attr('transform', 'translate(' + (-w) + ',0)');
          }
        }
      }
      else if (fn.type === 'circle') {
        if (opts.widths[i - 1]) {
          w = this.cumWidth(opts.widths, i);
          var r = (this.SHAPE_WIDTH - this.SHAPE_MARGIN*2)/2;
          created.attr({
            'cx': -(w + 2*r),
            'cy': -opts.textHeight/4,
            'r': r
          });
        }
      }
      else if (fn.type === 'rect') {
        var side = this.SHAPE_WIDTH - this.SHAPE_MARGIN*2;
        created.attr({
          'width': side,
          'height': side
        });
        if (opts.widths[i - 1]) {
          w = this.cumWidth(opts.widths, i);
          created.attr({
            'x': -w - this.SHAPE_WIDTH
          });
        }
        else {
          created.attr({
            'x': -side - 1.5
          });
        }
      }
    }, this));
    if (type !== 'bg') {
      // a y-attribute of 0 would put the top of the rects *at* the text baseline
      // so an upward (negative) shift of half the shape width works well
      var baselineShift = -(this.SHAPE_WIDTH/2 + this.SHAPE_MARGIN);
      selection.selectAll('rect')
        .attr('y', baselineShift);
    }
    var w;
    selection.each(function() { w = this.getBoundingClientRect(); });
    return w;
  }
};

module.exports = legend;
<|endoftext|>


<commit_before>function renderVoteData(vote) {
    var skript = $('#skript-' + vote.id);
    skript.find('.vote-number').html(vote.votes);
    skript.find('.vote-bar').animate( { width: '' + (vote.votePercentage * 100) + '%'}, 300);
    if (vote.channel) {
      skript
        .find('span.channel')
        .find('span').html('#' + vote.channel).end()
        .removeClass('choose').addClass('fixed');
    } else {
      skript
        .find('span.channel')
        .removeClass('fixed').addClass('choose');
    };
}

function renderSkript(skript) {
    $('#templates .skript').
        clone().
        attr('id', 'skript-' + skript.id).
        find('.title').html(skript.title).end().
        find('.author').html(skript.author).end().
        find('.vote').click(function() {
            castVote(skript.id);
        }).end().
        appendTo('#skript-list');

    renderVoteData(skript);
}

function loadSkripts(skripts) {
    $.each(skripts, function(id, skript) {
        renderSkript(skript);
    });
}

function castVote(id) {
    $.post('/api/vote/' + id, { channel: $('#skript-' + id + ' .channel input').val() }, function(res) {
        highlightVote(id);
    });
}

function highlightVote(id) {
    $('#skript-' + id).addClass('voted-for');
}

function handleShowTimes(data) {
    handleCurrentShow(data.current);
    handleNextShow(data.next);
}

function handleCurrentShow(data) {
    console.log("current show: " + data);
    var currentShow = JSON.parse(data);

    if (currentShow.status == 'running') {
      $('.current-show')
        .find('.name').html(currentShow.skript.title).end()
        .removeClass('stopped').addClass('running');
    } else {
      $('.current-show').removeClass('running').addClass('stopped');
    }
}

function handleNextShow(time) {
    // TODO implement
    time = new Date(time);
    console.log("Next show: ", time);
    $('#next-show').
        find('.time').html(time.toLocaleString()).end().
        find('.countdown').countdown({'until': time});
}

var openLightBox = function(openId){
    var box = $(openId);
    box.fadeIn();
    box.css({
        'margin-top' : -(box.height() + 80) / 2,
        'margin-left' : -(box.width() + 80) / 2
    });
    $('#lightbox-background').css({'filter' : 'alpha(opacity=80)'}).fadeIn();
    var closeLightBox = function(){
        $("body").css({"overflow": "auto"});
        $('#lightbox-background, .lightbox').fadeOut();
    };
    $('#lightbox-background').live('click', closeLightBox);
    $('.lightbox a.close').live('click', closeLightBox);
    $("body").css({"overflow": "hidden"});
};

$(document).ready(function() {
    $(".open-lightbox").click(function(e){
        openLightBox($(this).attr("href"));
    });
    $.getJSON('/api/skripts', function(skripts) {
      loadSkripts(skripts);
    });

    document.socket = io.connect('/');
    document.socket.on('show times', handleShowTimes);
    document.socket.on('votes', function(votes) {
        $.each(votes, function(id, vote) {
            renderVoteData(vote);
        });
    });
    document.socket.on('my vote', function(id) {
        console.log('my vote is ', id);
        highlightVote(id);
    });
});
<commit_msg>reset countdown properly<commit_after>function renderVoteData(vote) {
    var skript = $('#skript-' + vote.id);
    skript.find('.vote-number').html(vote.votes);
    skript.find('.vote-bar').animate( { width: '' + (vote.votePercentage * 100) + '%'}, 300);
    if (vote.channel) {
      skript
        .find('span.channel')
        .find('span').html('#' + vote.channel).end()
        .removeClass('choose').addClass('fixed');
    } else {
      skript
        .find('span.channel')
        .removeClass('fixed').addClass('choose');
    };
}

function renderSkript(skript) {
    $('#templates .skript').
        clone().
        attr('id', 'skript-' + skript.id).
        find('.title').html(skript.title).end().
        find('.author').html(skript.author).end().
        find('.vote').click(function() {
            castVote(skript.id);
        }).end().
        appendTo('#skript-list');

    renderVoteData(skript);
}

function loadSkripts(skripts) {
    $.each(skripts, function(id, skript) {
        renderSkript(skript);
    });
}

function castVote(id) {
    $.post('/api/vote/' + id, { channel: $('#skript-' + id + ' .channel input').val() }, function(res) {
        highlightVote(id);
    });
}

function highlightVote(id) {
    $('#skript-' + id).addClass('voted-for');
}

function handleShowTimes(data) {
    handleCurrentShow(data.current);
    handleNextShow(data.next);
}

function handleCurrentShow(data) {
    console.log("current show: " + data);
    var currentShow = JSON.parse(data);

    if (currentShow.status == 'running') {
      $('.current-show')
        .find('.name').html(currentShow.skript.title).end()
        .removeClass('stopped').addClass('running');
    } else {
      $('.current-show').removeClass('running').addClass('stopped');
    }
}

function handleNextShow(time) {
    // TODO implement
    time = new Date(time);
    console.log("Next show: ", time);
    $('#next-show').
        find('.time').html(time.toLocaleString()).end().
        find('.countdown').removeClass('hasCountdown').html('').end().
        find('.countdown').countdown({'until': time});
}

var openLightBox = function(openId){
    var box = $(openId);
    box.fadeIn();
    box.css({
        'margin-top' : -(box.height() + 80) / 2,
        'margin-left' : -(box.width() + 80) / 2
    });
    $('#lightbox-background').css({'filter' : 'alpha(opacity=80)'}).fadeIn();
    var closeLightBox = function(){
        $("body").css({"overflow": "auto"});
        $('#lightbox-background, .lightbox').fadeOut();
    };
    $('#lightbox-background').live('click', closeLightBox);
    $('.lightbox a.close').live('click', closeLightBox);
    $("body").css({"overflow": "hidden"});
};

$(document).ready(function() {
    $(".open-lightbox").click(function(e){
        openLightBox($(this).attr("href"));
    });
    $.getJSON('/api/skripts', function(skripts) {
      loadSkripts(skripts);
    });

    document.socket = io.connect('/');
    document.socket.on('show times', handleShowTimes);
    document.socket.on('votes', function(votes) {
        $.each(votes, function(id, vote) {
            renderVoteData(vote);
        });
    });
    document.socket.on('my vote', function(id) {
        console.log('my vote is ', id);
        highlightVote(id);
    });
});
<|endoftext|>


<commit_before>/**
 * Competence class
 */
function Competence(viewmodel, id, code, name, weight, locked, subcompetences) {
    return {
        id: ko.observable(id),
        code: ko.observable(code),
        name: ko.observable(name),
        weight: ko.observable(weight),
        locked: false,
        subcompetences: ko.observableArray(subcompetences),

        addSubCompetence: function() {
            this.subcompetences.push(new SubCompetence(this));
            automatedWeightCalculation(this.subcompetences());
            /*var total = 100;
            alert(total);
            console.log(this.subcompetences);
            for(var sub in this.subcompetences){
                alert(sub);
                sub.calculateWeight(100);
                total -= sub.weight;
                alert(total);
            }*/
        },

        removeThis: function() {
            viewmodel.removeCompetence(this);
        },

        toggleLock: function(data, event){
            if(this.locked == true)
            {
                $(event.target).addClass("icon-unlock").removeClass("icon-lock");
                this.locked = false;
            }
            else
            {
                $(event.target).addClass("icon-lock").removeClass("icon-unlock");
                this.locked = true;
            }
        },

        removeSubCompetence: function(subCompetence) {
            this.subcompetences.remove(subCompetence);
            automatedWeightCalculation(this.subcompetences());
        }
    };

}

/**
 * SubCompetence class
 */
function SubCompetence(parent, id, code, name, weight, locked, indicators) {
    return {
        id: ko.observable(id),
        code: ko.observable(code),
        name: ko.observable(name),
        weight: ko.observable(weight),
        locked: false,
        indicators: ko.observableArray(indicators),

        addIndicator: function() {
            this.indicators.push(new Indicator(this));
            automatedWeightCalculation(this.indicators());
        },

        /*calculateWeight: function(total){
            this.weight = total;
        },*/

        removeThis: function() {
            parent.removeSubCompetence(this);

        },

        toggleLock: function(data, event){
            if(this.locked == true)
            {
                $(event.target).addClass("icon-unlock").removeClass("icon-lock");
                this.locked = false;
            }
            else
            {
                $(event.target).addClass("icon-lock").removeClass("icon-unlock");
                this.locked = true;
            }
        },

        removeIndicator: function(indicator) {
            this.indicators.remove(indicator);
            automatedWeightCalculation(this.indicators());
        }

    };
}

/**
 * Indicator class
 */
function Indicator(parent, id, name, weight, locked, description) {
    return {
        id: ko.observable(id),
        name: ko.observable(name),
        weight: ko.observable(weight),
        locked: false,
        description : ko.observable(description),

        removeThis: function() {
            parent.removeIndicator(this);
        },

        toggleLock: function(data, event){
            if(this.locked == true)
            {
                $(event.target).addClass("icon-unlock").removeClass("icon-lock");
                this.locked = false;
            }
            else
            {
                $(event.target).addClass("icon-lock").removeClass("icon-unlock");
                this.locked = true;
            }
        }
    };
}

// View model for the courses page
function pageViewModel(gvm) {
    // projecttitle
    gvm.projecttitle = ko.observable("");
    //gvm.competences = 0;
    gvm.subcomp = 0;

    // Page specific i18n bindings
    gvm.title = ko.computed(function (){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("ProjectTitle") + ": " + gvm.projecttitle();}, gvm);
    gvm.pageHeader = ko.observable("Project");
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);

    gvm.addCompetenceBtn = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("AddCompetence");}, gvm);
    gvm.savePage = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("SaveBtn");}, gvm);

    gvm.competences = ko.observableArray([]);

    gvm.addCompetence = function() {
        gvm.competences.push(new Competence(this));
        automatedWeightCalculation(this.competences());

        // Update automated weight calculation
        ko.utils.arrayForEach(gvm.competences, function(competence){
            console.log(competence.weight);
            competence.weight(percent);
        });
    };

    gvm.removeCompetence = function(competence) {
        gvm.competences.remove(competence);
        automatedWeightCalculation(this.competences());
    }

    gvm.updateCompetence = function(id, code, description, max, weight) {
        var comp = new Competence(this, id, code, description, weight);
        gvm.competences.push(comp);
        return comp;
    }

    gvm.clearStructure = function() {
        gvm.competences.destroyAll();
    }
}

/**
 * Push the current project state to the database
 * @returns {undefined}
 */
function saveProjectStructure() {
    $.ajax({
       type: "POST",
       url: "/api/projectstructure/" + projectid,
       data: ko.toJSON(viewModel.competences),
       success: function(){
           // TODO make multilangual and with modals
           alert("Saved projectstructure to server");

           fetchProjectStructure();
       }
    });
}

function fetchProjectStructure() {
    viewModel.clearStructure();

    $.getJSON("/api/projectstructure/" + projectid, function(data){
        $.each(data, function(i, item){
            var competence = viewModel.updateCompetence(item.id, item.code, item.description, item.max, item.weight);

            $.each(item.subcompetences, function(i, subcomp){
               var subcompetence = new SubCompetence(competence, subcomp.id, subcomp.code, subcomp.description, subcomp.weight);
               competence.subcompetences.push(subcompetence);

               $.each(subcomp.indicators, function(i, indic){
                  subcompetence.indicators.push(new Indicator(subcompetence, indic.id, indic.name, indic.description));
               });
            });
        })
    });
}

function initPage() {
    fetchProjectStructure();

    $(".addCompetenceBtn").click(function() {
        viewModel.addCompetence();
    });

    $(".savePageBtn").click(function(){
        if(totalPercentCheck()) {
            saveProjectStructure();
            console.log("Saved");
        }
        else
        {
            console.log("Not saved");
        }
    });
}

function totalPercentCheck()
{
    var totalPercentCompetences = 0;
    var totalPercentSubcompetences = new Array();
    var totalPercentIndicators = new Array();
    var nrOfSubcompetences = 0;
    var nrOfIndicators = 0;

    var checkSubcompetences = true;
    var checkIndicators = true;

    for(var indexCompetences =0; indexCompetences < viewModel.competences().length; indexCompetences++)
    {
        totalPercentCompetences = totalPercentCompetences + parseInt(viewModel.competences()[indexCompetences].weight());
        totalPercentSubcompetences.push(0);
        for(var indexSubcompetence = 0; indexSubcompetence < viewModel.competences()[indexCompetences].subcompetences().length; indexSubcompetence++)
        {
            totalPercentSubcompetences[nrOfSubcompetences] = totalPercentSubcompetences[nrOfSubcompetences] + parseInt(viewModel.competences()[indexCompetences].subcompetences()[indexSubcompetence].weight());
            for(var indexIndicators = 0; indexIndicators < viewModel.competences()[indexCompetences].subcompetences()[indexSubcompetence].indicators().length; indexIndicators++)
            {
                totalPercentIndicators[nrOfIndicators] = totalPercentIndicators[nrOfIndicators] + parseInt(viewModel.competences()[indexCompetences].subcompetences()[indexSubcompetence].indicators()[indexIndicators].weight());
            }
            nrOfIndicators++;
        }
        nrOfSubcompetences++;
    }

    for(var i = 0; i < nrOfIndicators; i++)
    {
        if(totalPercentSubcompetences[i] != 100)
        {
            checkSubcompetences = false;
        }
    }

    for(var index = 0; index < nrOfIndicators; index++)
    {
        if(totalPercentIndicators[index] != 100)
        {
            checkIndicators = false;
        }
    }

    if(totalPercentCompetences == 100 && checkSubcompetences && checkIndicators )
    {
        return true;
    }
    else
    {
        return false;
    }
}

function automatedWeightCalculation(data)
{
    var lockedPercent = 0;
    var nrOfUnlocked = 0;

    for(var index = 0; index < data.length; index++)
    {
        if(data[index].locked == true)
        {
            lockedPercent = lockedPercent + parseInt(data[index].weight());
        }
        else
        {
            nrOfUnlocked++;
        }
    }

    var remainingPercent = 100 - lockedPercent;

    var percentPerCompetence = remainingPercent / nrOfUnlocked;

    percentPerCompetence = percentPerCompetence.toFixed(2);

    for(var index = 0; index < data.length; index++)
    {
        if(data[index].locked == false)
        {
            data[index].weight(percentPerCompetence);
        }
    }
}
<commit_msg>total percent check<commit_after>/**
 * Competence class
 */
function Competence(viewmodel, id, code, name, weight, locked, subcompetences) {
    return {
        id: ko.observable(id),
        code: ko.observable(code),
        name: ko.observable(name),
        weight: ko.observable(weight),
        locked: false,
        subcompetences: ko.observableArray(subcompetences),

        addSubCompetence: function() {
            this.subcompetences.push(new SubCompetence(this));
            automatedWeightCalculation(this.subcompetences());
            /*var total = 100;
            alert(total);
            console.log(this.subcompetences);
            for(var sub in this.subcompetences){
                alert(sub);
                sub.calculateWeight(100);
                total -= sub.weight;
                alert(total);
            }*/
        },

        removeThis: function() {
            viewmodel.removeCompetence(this);
        },

        toggleLock: function(data, event){
            if(this.locked == true)
            {
                $(event.target).addClass("icon-unlock").removeClass("icon-lock");
                this.locked = false;
            }
            else
            {
                $(event.target).addClass("icon-lock").removeClass("icon-unlock");
                this.locked = true;
            }
        },

        removeSubCompetence: function(subCompetence) {
            this.subcompetences.remove(subCompetence);
            automatedWeightCalculation(this.subcompetences());
        }
    };

}

/**
 * SubCompetence class
 */
function SubCompetence(parent, id, code, name, weight, locked, indicators) {
    return {
        id: ko.observable(id),
        code: ko.observable(code),
        name: ko.observable(name),
        weight: ko.observable(weight),
        locked: false,
        indicators: ko.observableArray(indicators),

        addIndicator: function() {
            this.indicators.push(new Indicator(this));
            automatedWeightCalculation(this.indicators());
        },

        /*calculateWeight: function(total){
            this.weight = total;
        },*/

        removeThis: function() {
            parent.removeSubCompetence(this);

        },

        toggleLock: function(data, event){
            if(this.locked == true)
            {
                $(event.target).addClass("icon-unlock").removeClass("icon-lock");
                this.locked = false;
            }
            else
            {
                $(event.target).addClass("icon-lock").removeClass("icon-unlock");
                this.locked = true;
            }
        },

        removeIndicator: function(indicator) {
            this.indicators.remove(indicator);
            automatedWeightCalculation(this.indicators());
        }

    };
}

/**
 * Indicator class
 */
function Indicator(parent, id, name, weight, locked, description) {
    return {
        id: ko.observable(id),
        name: ko.observable(name),
        weight: ko.observable(weight),
        locked: false,
        description : ko.observable(description),

        removeThis: function() {
            parent.removeIndicator(this);
        },

        toggleLock: function(data, event){
            if(this.locked == true)
            {
                $(event.target).addClass("icon-unlock").removeClass("icon-lock");
                this.locked = false;
            }
            else
            {
                $(event.target).addClass("icon-lock").removeClass("icon-unlock");
                this.locked = true;
            }
        }
    };
}

// View model for the courses page
function pageViewModel(gvm) {
    // projecttitle
    gvm.projecttitle = ko.observable("");
    //gvm.competences = 0;
    gvm.subcomp = 0;

    // Page specific i18n bindings
    gvm.title = ko.computed(function (){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("ProjectTitle") + ": " + gvm.projecttitle();}, gvm);
    gvm.pageHeader = ko.observable("Project");
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);

    gvm.addCompetenceBtn = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("AddCompetence");}, gvm);
    gvm.savePage = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("SaveBtn");}, gvm);

    gvm.competences = ko.observableArray([]);

    gvm.addCompetence = function() {
        gvm.competences.push(new Competence(this));
        automatedWeightCalculation(this.competences());

        // Update automated weight calculation
        ko.utils.arrayForEach(gvm.competences, function(competence){
            console.log(competence.weight);
            competence.weight(percent);
        });
    };

    gvm.removeCompetence = function(competence) {
        gvm.competences.remove(competence);
        automatedWeightCalculation(this.competences());
    }

    gvm.updateCompetence = function(id, code, description, max, weight) {
        var comp = new Competence(this, id, code, description, weight);
        gvm.competences.push(comp);
        return comp;
    }

    gvm.clearStructure = function() {
        gvm.competences.destroyAll();
    }
}

/**
 * Push the current project state to the database
 * @returns {undefined}
 */
function saveProjectStructure() {
    $.ajax({
       type: "POST",
       url: "/api/projectstructure/" + projectid,
       data: ko.toJSON(viewModel.competences),
       success: function(){
           // TODO make multilangual and with modals
           alert("Saved projectstructure to server");

           fetchProjectStructure();
       }
    });
}

function fetchProjectStructure() {
    viewModel.clearStructure();

    $.getJSON("/api/projectstructure/" + projectid, function(data){
        $.each(data, function(i, item){
            var competence = viewModel.updateCompetence(item.id, item.code, item.description, item.max, item.weight);

            $.each(item.subcompetences, function(i, subcomp){
               var subcompetence = new SubCompetence(competence, subcomp.id, subcomp.code, subcomp.description, subcomp.weight);
               competence.subcompetences.push(subcompetence);

               $.each(subcomp.indicators, function(i, indic){
                  subcompetence.indicators.push(new Indicator(subcompetence, indic.id, indic.name, indic.description));
               });
            });
        })
    });
}

function initPage() {
    fetchProjectStructure();

    $(".addCompetenceBtn").click(function() {
        viewModel.addCompetence();
    });

    $(".savePageBtn").click(function(){
        if(totalPercentCheck()) {
            saveProjectStructure();
            console.log("Saved");
        }
        else
        {
            console.log("Not saved");
        }
    });
}

function totalPercentCheck()
{
    var totalPercentCompetences = 0;
    var totalPercentSubcompetences = new Array();
    var totalPercentIndicators = new Array();
    var nrOfSubcompetences = 0;
    var nrOfIndicators = 0;

    var checkSubcompetences = true;
    var checkIndicators = true;

    for(var indexCompetences =0; indexCompetences < viewModel.competences().length; indexCompetences++)
    {
        totalPercentCompetences = totalPercentCompetences + parseInt(viewModel.competences()[indexCompetences].weight());
        totalPercentSubcompetences.push(0);
        for(var indexSubcompetence = 0; indexSubcompetence < viewModel.competences()[indexCompetences].subcompetences().length; indexSubcompetence++)
        {
            totalPercentSubcompetences[nrOfSubcompetences] = totalPercentSubcompetences[nrOfSubcompetences] + parseInt(viewModel.competences()[indexCompetences].subcompetences()[indexSubcompetence].weight());
            for(var indexIndicators = 0; indexIndicators < viewModel.competences()[indexCompetences].subcompetences()[indexSubcompetence].indicators().length; indexIndicators++)
            {
                totalPercentIndicators[nrOfIndicators] = totalPercentIndicators[nrOfIndicators] + parseInt(viewModel.competences()[indexCompetences].subcompetences()[indexSubcompetence].indicators()[indexIndicators].weight());
            }
            nrOfIndicators++;
        }
        nrOfSubcompetences++;
    }

    for(var i = 0; i < nrOfSubcompetences - 1; i++)
    {
        if(totalPercentSubcompetences[i] != 100)
        {
            checkSubcompetences = false;
        }
    }

    for(var index = 0; index < nrOfIndicators - 1; index++)
    {
        if(totalPercentIndicators[index] != 100)
        {
            checkIndicators = false;
        }
    }

    if(totalPercentCompetences == 100 && checkSubcompetences && checkIndicators )
    {
        return true;
    }
    else
    {
        return false;
    }
}

function automatedWeightCalculation(data)
{
    var lockedPercent = 0;
    var nrOfUnlocked = 0;

    for(var index = 0; index < data.length; index++)
    {
        if(data[index].locked == true)
        {
            lockedPercent = lockedPercent + parseInt(data[index].weight());
        }
        else
        {
            nrOfUnlocked++;
        }
    }

    var remainingPercent = 100 - lockedPercent;

    var percentPerCompetence = remainingPercent / nrOfUnlocked;

    percentPerCompetence = percentPerCompetence.toFixed(2);

    for(var index = 0; index < data.length; index++)
    {
        if(data[index].locked == false)
        {
            data[index].weight(percentPerCompetence);
        }
    }
}
<|endoftext|>


<commit_before>(function($, window, document, undefined) {

  if (!$.Rapido) {
    $.Rapido = {};
  }

  $.Rapido.Animation = function(el, options) {
    var base = this;

    base.$el = $(el);
    base.el = el;

    base.$el.data('Rapido.Animation', base);

    base.init = function() {
      base.options = $.extend({},$.Rapido.Animation.defaultOptions, options);

      addClass();
    };

    function addClass() {
      var animation, offset, scrollbar, container, added = false;

      animation = base.$el.data('animation');

      if (base.options.offsetMenu) {
        container = '.offcanvas__content';
        offset = base.$el.position();
      } else {
        container = window;
        offset = base.$el.offset();
      }

      offset = offset.top - base.options.offset;
      offset = parseInt(offset);

      //console.log(offset);

      $(container).scroll(function(e) {

        if (base.options.offsetMenu) {
          scrollbar = $('.offcanvas__content').scrollTop();
        } else {
          scrollbar = $(document).scrollTop();
        }

        //console.log(scrollbar);

        if (offset <= scrollbar && !added) {
          base.$el.addClass(animation);
          added = true;
        }

      });
    }

    base.init();
  };

  $.Rapido.Animation.defaultOptions = {
    offset: 500,
    offsetMenu: false
  };

  $.fn.rapido_Animation = function(options) {
    return this.each(function() {
      (new $.Rapido.Animation(this, options));
    });
  };

})(jQuery, window, document);
<commit_msg>Cleaned offset Added isOffsetLayout with new rapido_Utilities.elemExist function<commit_after>(function($, window, document, undefined) {

  if (!$.Rapido) {
    $.Rapido = {};
  }

  $.Rapido.Animation = function(el, options) {
    var base = this;

    base.$el = $(el);
    base.el = el;

    base.$el.data('Rapido.Animation', base);

    base.init = function() {
      base.options = $.extend({},$.Rapido.Animation.defaultOptions, options);

      addClass();
    };

    function addClass() {
      var animation, offset, scrollbar, container, isOffsetLayout, added = false;

      // Get the animation to apply
      animation = base.$el.data('animation');

      // Check if is using the offset layout
      isOffsetLayout = $.rapido_Utilities.elemExist(base.options.offsetClass);

      // Set corrent container of the content
      if (isOffsetLayout) {
        container = base.options.offsetClass;
      } else {
        container = window;
      }

      // Get offset of element to animate
      offset = base.$el.position();
      offset = offset.top - base.options.offset;

      $(container).scroll(function(e) {

        // On scroll udate scroll value fro comparison
        if (isOffsetLayout) {
          scrollbar = $(base.options.offsetClass).scrollTop();
        } else {
          scrollbar = $(document).scrollTop();
        }

        // Check if current container offset is less or equal the
        // element's offset and it's not animated already
        if (offset <= scrollbar && !added) {
          base.$el.addClass(animation);
          added = true;
        }

      });
    }

    base.init();
  };

  $.Rapido.Animation.defaultOptions = {
    offset: 500,
    offsetClass: '.offcanvas__content'
  };

  $.fn.rapido_Animation = function(options) {
    return this.each(function() {
      (new $.Rapido.Animation(this, options));
    });
  };

})(jQuery, window, document);
<|endoftext|>


<commit_before>
game.SpendExp = me.ScreenObject.extend({
	/**
	 *  action to perform on state change
	 */
	onResetEvent: function() {
		me.game.world.addChild(new me.Sprite(0, 0, me.loader.getImage('exp-screen')), -10); // TODO

                me.game.world.addChild(new (me.Renderable.extend({
                    init:function(){
                        this._super(me.Renderable,'init', [10,10,300,50]);
                        this.font= new me.Font("Arial", 46, "white");

                    },
                    draw:function(renderer){

                        this.font.draw(renderer.getContext(), "F1-F4 press F5 to skip", this.pos.x , this.pos.y);
                        this.font.draw(renderer.getContext(), "Current Exp: " + game.data.exp.toString() , this.pos.x + 50 , this.pos.y + 100);
                        this.font.draw(renderer.getContext(), "F1: INCREASE GOLD PRODUCTION " + game.data.exp.toString() , this.pos.x + 50 , this.pos.y + 150);
                        this.font.draw(renderer.getContext(), "F2: ADD STARTING GOLD " + game.data.exp.toString() , this.pos.x + 50 , this.pos.y + 200);
                        this.font.draw(renderer.getContext(), "F3: INCREASE ATTACK DAMAGE " + game.data.exp.toString() , this.pos.x + 50 , this.pos.y + 250);
                        this.font.draw(renderer.getContext(), "F4: INCREASE STARTING HEALTH " + game.data.exp.toString() , this.pos.x + 50 , this.pos.y + 300);
                    }
                })));
            },

	/**
	 *  action to perform when leaving this screen (state change)
	 */
	onDestroyEvent: function() {

            }
});
<commit_msg>finished 44<commit_after>
game.SpendExp = me.ScreenObject.extend({
	/**
	 *  action to perform on state change
	 */
	onResetEvent: function() {
		me.game.world.addChild(new me.Sprite(0, 0, me.loader.getImage('exp-screen')), -10); // TODO
                me.input.bindKey(me.input.KEY.F1, "F1");
                me.input.bindKey(me.input.KEY.F2, "F2");
                me.input.bindKey(me.input.KEY.F3, "F3");
                me.input.bindKey(me.input.KEY.F4, "F4");
                me.input.bindKey(me.input.KEY.F5, "F5");
                me.game.world.addChild(new (me.Renderable.extend({
                    init:function(){
                        this._super(me.Renderable,'init', [10,10,300,50]);
                        this.font= new me.Font("Arial", 46, "white");

                    },
                    draw:function(renderer){

                        this.font.draw(renderer.getContext(), "F1-F4 press F5 to skip", this.pos.x , this.pos.y);
                        this.font.draw(renderer.getContext(), "Current Exp: " + game.data.exp.toString() , this.pos.x + 50 , this.pos.y + 100);
                        this.font.draw(renderer.getContext(), "F1: INCREASE GOLD PRODUCTION CURRENT LEVL: " + game.data.exp1.toString() + " COST: " + ((game.data.exp1 + 1)*10), this.pos.x + 50 , this.pos.y + 150);
                        this.font.draw(renderer.getContext(), "F2: ADD STARTING GOLD " +  game.data.exp.toString() , this.pos.x + 50 , this.pos.y + 200);
                        this.font.draw(renderer.getContext(), "F3: INCREASE ATTACK DAMAGE " + game.data.exp.toString() , this.pos.x + 50 , this.pos.y + 250);
                        this.font.draw(renderer.getContext(), "F4: INCREASE STARTING HEALTH " + game.data.exp.toString() , this.pos.x + 50 , this.pos.y + 300);
                    }
                })));

             this.handler = me.event.subscribe(me.event.KEYDOWN, function(action, keyCode, edge){
                 if (action === "F1"){

                 }else if (action==="F2"){

                 }else if (action==="F3"){

                 }else if (action==="F4"){

                 }else if (action==="F5"){
                    me.state.change(me.state.PLAY);
                 }
             });
         },
	/**
	 *  action to perform when leaving this screen (state change)
	 */
	onDestroyEvent: function() {
		me.input.unbindKey(me.input.KEY.F1, "F1");
                me.input.unbindKey(me.input.KEY.F2, "F2");
                me.input.unbindKey(me.input.KEY.F3, "F3");
                me.input.unbindKey(me.input.KEY.F4, "F4");
                me.input.unbindKey(me.input.KEY.F5, "F5");
                me.event.unsubscribe(this.handler);
            }
});
<|endoftext|>


<commit_before>const blacklist = {
    "encyclopedia-es": [
        "Abuso sexual",
        "Abuso y maltrato infantil",
        "Actores pornográficos de Alemania",
        "Actores pornográficos de Brasil",
        "Actores pornográficos de Canadá",
        "Actores pornográficos de Colombia",
        "Actores pornográficos de España",
        "Actores pornográficos de Estados Unidos",
        "Actores pornográficos de Francia",
        "Actores pornográficos de Hungría",
        "Actores pornográficos de Italia",
        "Actores pornográficos de Japón",
        "Actores pornográficos de México",
        "Actores pornográficos de Rumania",
        "Actores pornográficos del Reino Unido",
        "Actores pornográficos de la República Checa",
        "Altporn",
        "Anime y manga hentai",
        "Anime y manga lolicon",
        "Ano humano",
        "Aparato reproductor femenino",
        "Aparato reproductor masculino",
        "BDSM",
        "Cine pornográfico",
        "Erotismo anal",
        "Erotismo oral",
        "Estudios pornográficos",
        "Fetichismo sexual",
        "Géneros pornográficos",
        "Incesto",
        "Industria del sexo",
        "Jerga sexual",
        "Juguetes sexuales",
        "Leyendas urbanas sexuales",
        "Mama",
        "Masturbación",
        "Métodos de ejecución",
        "Modelos eróticas de Estados Unidos",
        "Novelas eróticas",
        "Nudismo",
        "Orgasmo",
        "Parafilias",
        "Pederastia",
        "Pene",
        "Penthouse Pets",
        "Piercing en los genitales",
        "Piercing en los genitales masculinos",
        "Pirsins",
        "Playboy",
        "Pornografía",
        "Prácticas sexuales",
        "Prostitución",
        "Relaciones íntimas",
        "Revistas para adultos",
        "Revolución sexual",
        "Sexo grupal",
        "Sexo ocasional",
        "Sitios web pornográficos",
        "Testículo",
        "Tortura"
    ],
    "encyclopedia-pt": [
        "Anatomia sexual",
        "BDSM",
        "Estrelas pornográficas da Alemanha",
        "Estrelas pornográficas da Colômbia",
        "Estrelas pornográficas da Espanha",
        "Estrelas pornográficas da França",
        "Estrelas pornográficas da Hungria",
        "Estrelas pornográficas da Itália",
        "Estrelas pornográficas da Romênia",
        "Estrelas pornográficas da República Checa",
        "Estrelas pornográficas do Brasil",
        "Estrelas pornográficas do Canadá",
        "Estrelas pornográficas do Japão",
        "Estrelas pornográficas do México",
        "Estrelas pornográficas do Reino Unido",
        "Estrelas pornográficas dos Estados Unidos",
        "Fetichismo",
        "Hentai",
        "Indústria do sexo",
        "Mama",
        "Masturbação",
        "Métodos de execução",
        "Modificação corporal",
        "Nudez",
        "Objetos usados para estimulação sexual",
        "Orgasmo",
        "Parafilias",
        "Pederastia",
        "Pénis",
        "Playboy",
        "Pornografia",
        "Produtoras de filmes pornográficos",
        "Prostituição",
        "Relacionamentos íntimos",
        "Revistas de conteúdo adulto",
        "Sexo",
        "Sexualidade",
        "Sistema reprodutor",
        "Sistema reprodutor feminino",
        "Sistema reprodutor masculino",
        "Sites adultos",
        "Termos sexuais do Japão",
        "Tortura"
    ],
    "encyclopedia-en": [
        "Alt porn",
        "American female adult models",
        "American pornographic actors",
        "Anal eroticism",
        "BDSM",
        "BDSM terminology",
        "Body piercing",
        "Brazilian pornographic film actors",
        "Breast",
        "British pornographic film actors",
        "Canadian pornographic film actors",
        "Casual sex",
        "Child abuse",
        "Clitoris",
        "Colombian pornographic film actors",
        "Czech pornographic film actors",
        "Erotica",
        "Erotica and pornography websites",
        "Execution methods",
        "Fellatio",
        "Female genital piercings",
        "French pornographic film actors",
        "Genital piercings",
        "German pornographic film actors",
        "Group sex",
        "Hentai",
        "Human female reproductive system",
        "Human male reproductive system",
        "Hungarian pornographic film actors",
        "Incest",
        "Intimate relationships",
        "Italian pornographic film actors",
        "Japanese pornographic film actors",
        "Japanese sex terms",
        "Male genital piercings",
        "Mammal female reproductive system",
        "Mammal male reproductive system",
        "Masturbation",
        "Mexican pornographic film actors",
        "Nudity",
        "Oral eroticism",
        "Orgasm",
        "Paraphilias",
        "Pederasty",
        "Penis",
        "Penthouse Pets",
        "Playboy",
        "Pornographic animation",
        "Pornographic film studios",
        "Pornographic magazines",
        "Pornography",
        "Pornography by genre",
        "Pornography portal",
        "Pornography terms",
        "Prostitution",
        "Romanian pornographic film actors",
        "Sex industry",
        "Sex positions",
        "Sex toys",
        "Sexual acts",
        "Sexual anatomy",
        "Sexual arousal",
        "Sexual fetishism",
        "Sexual revolution",
        "Sexual slang",
        "Sexual urban legends",
        "Spanish pornographic film actors",
        "Testicle",
        "Torture",
        "Vagina"
    ],
    "encyclopedia-fr": [
        "Accessoire BDSM",
        "Acteur allemand de films pornographiques",
        "Acteur américain de films pornographiques",
        "Acteur brésilien de films pornographiques",
        "Acteur canadien de films pornographiques",
        "Acteur colombien de films pornographiques",
        "Acteur français de films pornographiques",
        "Acteur hongrois de films pornographiques",
        "Acteur italien de films pornographiques",
        "Acteur japonais de films pornographiques",
        "Acteur tchèque de films pornographiques",
        "Actrice espagnole de films pornographiques",
        "Actrice roumaine de films pornographiques",
        "Anatomie de l'appareil reproducteur masculin",
        "Anatomie sexuelle",
        "Appareil reproducteur féminin",
        "Appareil reproductif masculin",
        "Art érotique",
        "BDSM",
        "Cinéma pornographique",
        "Clitoris",
        "Érection",
        "Érotisme",
        "Érotisme anal",
        "Fétichisme sexuel",
        "Hentai manga",
        "Inceste",
        "Industrie du sexe",
        "Intimité",
        "Jouet sexuel",
        "Masturbation",
        "Méthode d'exécution",
        "Nudité",
        "Orgasme",
        "Paraphilie",
        "Pédérastie",
        "Pénis",
        "Penthouse Pets",
        "Piercing",
        "Playboy",
        "Pornographie",
        "Pornographie LGBT",
        "Position sexuelle",
        "Pratique sexuelle",
        "Pratique sexuelle en groupe",
        "Presse pornographique",
        "Prostitution",
        "Révolution sexuelle",
        "Sein",
        "Sexualité humaine",
        "Sexualité libre",
        "Site web érotique ou pornographique",
        "Société de production de films pornographiques",
        "Torture"
    ],
    "encyclopedia-ar": [
        "العنف ضد الأطفال",
        "ممثلو أفلام إباحية ألمان",
        "ممثلو أفلام إباحية كنديون",
        "ممثلو أفلام إباحية أسبانيون",
        "ممثلو أفلام إباحية أمريكيون",
        "ممثلو أفلام إباحية فرنسيون",
        "ممثلو أفلام إباحية هنغاريون",
        "ممثلو أفلام إباحية إيطاليون",
        "ممثلو أفلام إباحية يابانيون",
        "جهاز تناسلي ذكري",
        "فتيشية",
        "صناعة الجنس",
        "ألعاب جنسية",
        "ثدي",
        "عري",
        "شذوذ جنسي",
        "قضيب",
        "بلاي بوي",
        "إباحة",
        "دعارة",
        "علاقات أليفة",
        "مواقع وب إباحية",
        "خصية",
        "طرق إعدام",
        "أوضاع جنسية",
        "تعذيب"
    ]
};
<commit_msg>Add Erotic video games category to blacklist<commit_after>const blacklist = {
    "encyclopedia-es": [
        "Abuso sexual",
        "Abuso y maltrato infantil",
        "Actores pornográficos de Alemania",
        "Actores pornográficos de Brasil",
        "Actores pornográficos de Canadá",
        "Actores pornográficos de Colombia",
        "Actores pornográficos de España",
        "Actores pornográficos de Estados Unidos",
        "Actores pornográficos de Francia",
        "Actores pornográficos de Hungría",
        "Actores pornográficos de Italia",
        "Actores pornográficos de Japón",
        "Actores pornográficos de México",
        "Actores pornográficos de Rumania",
        "Actores pornográficos del Reino Unido",
        "Actores pornográficos de la República Checa",
        "Altporn",
        "Anime y manga hentai",
        "Anime y manga lolicon",
        "Ano humano",
        "Aparato reproductor femenino",
        "Aparato reproductor masculino",
        "BDSM",
        "Cine pornográfico",
        "Erotismo anal",
        "Erotismo oral",
        "Estudios pornográficos",
        "Fetichismo sexual",
        "Géneros pornográficos",
        "Incesto",
        "Industria del sexo",
        "Jerga sexual",
        "Juguetes sexuales",
        "Leyendas urbanas sexuales",
        "Mama",
        "Masturbación",
        "Métodos de ejecución",
        "Modelos eróticas de Estados Unidos",
        "Novelas eróticas",
        "Nudismo",
        "Orgasmo",
        "Parafilias",
        "Pederastia",
        "Pene",
        "Penthouse Pets",
        "Piercing en los genitales",
        "Piercing en los genitales masculinos",
        "Pirsins",
        "Playboy",
        "Pornografía",
        "Prácticas sexuales",
        "Prostitución",
        "Relaciones íntimas",
        "Revistas para adultos",
        "Revolución sexual",
        "Sexo grupal",
        "Sexo ocasional",
        "Sitios web pornográficos",
        "Testículo",
        "Tortura"
    ],
    "encyclopedia-pt": [
        "Anatomia sexual",
        "BDSM",
        "Estrelas pornográficas da Alemanha",
        "Estrelas pornográficas da Colômbia",
        "Estrelas pornográficas da Espanha",
        "Estrelas pornográficas da França",
        "Estrelas pornográficas da Hungria",
        "Estrelas pornográficas da Itália",
        "Estrelas pornográficas da Romênia",
        "Estrelas pornográficas da República Checa",
        "Estrelas pornográficas do Brasil",
        "Estrelas pornográficas do Canadá",
        "Estrelas pornográficas do Japão",
        "Estrelas pornográficas do México",
        "Estrelas pornográficas do Reino Unido",
        "Estrelas pornográficas dos Estados Unidos",
        "Fetichismo",
        "Hentai",
        "Indústria do sexo",
        "Mama",
        "Masturbação",
        "Métodos de execução",
        "Modificação corporal",
        "Nudez",
        "Objetos usados para estimulação sexual",
        "Orgasmo",
        "Parafilias",
        "Pederastia",
        "Pénis",
        "Playboy",
        "Pornografia",
        "Produtoras de filmes pornográficos",
        "Prostituição",
        "Relacionamentos íntimos",
        "Revistas de conteúdo adulto",
        "Sexo",
        "Sexualidade",
        "Sistema reprodutor",
        "Sistema reprodutor feminino",
        "Sistema reprodutor masculino",
        "Sites adultos",
        "Termos sexuais do Japão",
        "Tortura"
    ],
    "encyclopedia-en": [
        "Alt porn",
        "American female adult models",
        "American pornographic actors",
        "Anal eroticism",
        "BDSM",
        "BDSM terminology",
        "Body piercing",
        "Brazilian pornographic film actors",
        "Breast",
        "British pornographic film actors",
        "Canadian pornographic film actors",
        "Casual sex",
        "Child abuse",
        "Clitoris",
        "Colombian pornographic film actors",
        "Czech pornographic film actors",
        "Erotic video games",
        "Erotica",
        "Erotica and pornography websites",
        "Execution methods",
        "Fellatio",
        "Female genital piercings",
        "French pornographic film actors",
        "Genital piercings",
        "German pornographic film actors",
        "Group sex",
        "Hentai",
        "Human female reproductive system",
        "Human male reproductive system",
        "Hungarian pornographic film actors",
        "Incest",
        "Intimate relationships",
        "Italian pornographic film actors",
        "Japanese pornographic film actors",
        "Japanese sex terms",
        "Male genital piercings",
        "Mammal female reproductive system",
        "Mammal male reproductive system",
        "Masturbation",
        "Mexican pornographic film actors",
        "Nudity",
        "Oral eroticism",
        "Orgasm",
        "Paraphilias",
        "Pederasty",
        "Penis",
        "Penthouse Pets",
        "Playboy",
        "Pornographic animation",
        "Pornographic film studios",
        "Pornographic magazines",
        "Pornography",
        "Pornography by genre",
        "Pornography portal",
        "Pornography terms",
        "Prostitution",
        "Romanian pornographic film actors",
        "Sex industry",
        "Sex positions",
        "Sex toys",
        "Sexual acts",
        "Sexual anatomy",
        "Sexual arousal",
        "Sexual fetishism",
        "Sexual revolution",
        "Sexual slang",
        "Sexual urban legends",
        "Spanish pornographic film actors",
        "Testicle",
        "Torture",
        "Vagina"
    ],
    "encyclopedia-fr": [
        "Accessoire BDSM",
        "Acteur allemand de films pornographiques",
        "Acteur américain de films pornographiques",
        "Acteur brésilien de films pornographiques",
        "Acteur canadien de films pornographiques",
        "Acteur colombien de films pornographiques",
        "Acteur français de films pornographiques",
        "Acteur hongrois de films pornographiques",
        "Acteur italien de films pornographiques",
        "Acteur japonais de films pornographiques",
        "Acteur tchèque de films pornographiques",
        "Actrice espagnole de films pornographiques",
        "Actrice roumaine de films pornographiques",
        "Anatomie de l'appareil reproducteur masculin",
        "Anatomie sexuelle",
        "Appareil reproducteur féminin",
        "Appareil reproductif masculin",
        "Art érotique",
        "BDSM",
        "Cinéma pornographique",
        "Clitoris",
        "Érection",
        "Érotisme",
        "Érotisme anal",
        "Fétichisme sexuel",
        "Hentai manga",
        "Inceste",
        "Industrie du sexe",
        "Intimité",
        "Jouet sexuel",
        "Masturbation",
        "Méthode d'exécution",
        "Nudité",
        "Orgasme",
        "Paraphilie",
        "Pédérastie",
        "Pénis",
        "Penthouse Pets",
        "Piercing",
        "Playboy",
        "Pornographie",
        "Pornographie LGBT",
        "Position sexuelle",
        "Pratique sexuelle",
        "Pratique sexuelle en groupe",
        "Presse pornographique",
        "Prostitution",
        "Révolution sexuelle",
        "Sein",
        "Sexualité humaine",
        "Sexualité libre",
        "Site web érotique ou pornographique",
        "Société de production de films pornographiques",
        "Torture"
    ],
    "encyclopedia-ar": [
        "العنف ضد الأطفال",
        "ممثلو أفلام إباحية ألمان",
        "ممثلو أفلام إباحية كنديون",
        "ممثلو أفلام إباحية أسبانيون",
        "ممثلو أفلام إباحية أمريكيون",
        "ممثلو أفلام إباحية فرنسيون",
        "ممثلو أفلام إباحية هنغاريون",
        "ممثلو أفلام إباحية إيطاليون",
        "ممثلو أفلام إباحية يابانيون",
        "جهاز تناسلي ذكري",
        "فتيشية",
        "صناعة الجنس",
        "ألعاب جنسية",
        "ثدي",
        "عري",
        "شذوذ جنسي",
        "قضيب",
        "بلاي بوي",
        "إباحة",
        "دعارة",
        "علاقات أليفة",
        "مواقع وب إباحية",
        "خصية",
        "طرق إعدام",
        "أوضاع جنسية",
        "تعذيب"
    ]
};
<|endoftext|>


<commit_before>import React from "react";
import PropTypes from "prop-types";
import { graphql } from "gatsby";
import styled from "styled-components";
import MDXRenderer from "gatsby-mdx/mdx-renderer";
import { Chip } from "@material-ui/core";

import { Cover, Layout, Wrapper, SEO, Flex, PrevNext } from "../components";
import source from "../assets/source-code.png";
import demo from "../assets/demo.png";

const Title = styled.h1`
  margin-bottom: 1rem;
`;

const ProjectContent = styled.div`
  margin-top: 4rem;
`;

const Content = styled.div`
  grid-column: 2;
  box-shadow: 0 4px 120px rgba(0, 0, 0, 0.1);
  max-width: 1000px;
  border-radius: 1rem;
  padding: 3rem 6rem;
  background-color: ${props => props.theme.colors.bg};
  z-index: 9000;
  margin-top: -3rem;
  @media (max-width: ${props => props.theme.breakpoints.tablet}) {
    padding: 3rem 2rem;
  }
  @media (max-width: ${props => props.theme.breakpoints.phone}) {
    padding: 2rem 1.5rem;
  }
`;
const Icon = styled.img`
  width: 40px;
`;

const Project = ({
  pageContext: { slug, prev, next },
  data: { mdx: projectNode, file: publicURL }
}) => {
  const project = projectNode.frontmatter;
  return (
    <Layout customSEO>
      <Cover condensed />
      <Wrapper>
        <SEO postPath={slug} postNode={projectNode} article />
        <Content>
          <Flex>

              <Title>{project.title}</Title>

{project.slogan}

          </Flex>

            Source Code: <Icon src={source} alt="source" />

            Demo: <Icon src={demo} alt="demo" />

            Tech:{" "}
            {project.techs.map(tech => (
              <Chip label={tech} key={tech} />
            ))}

            Tags:{" "}
            {project.tags.map(tag => (
              <Chip label={tag} key={tag} />
            ))}

          <ProjectContent>
            <MDXRenderer>{projectNode.code.body}</MDXRenderer>
          </ProjectContent>
          <PrevNext prefix={`/projects`} prev={prev} next={next} />
        </Content>
      </Wrapper>
    </Layout>
  );
};

export default Project;

Project.propTypes = {
  pageContext: PropTypes.shape({
    slug: PropTypes.string.isRequired,
    next: PropTypes.object,
    prev: PropTypes.object
  }),
  data: PropTypes.shape({
    mdx: PropTypes.object.isRequired
  }).isRequired
};

Project.defaultProps = {
  pageContext: PropTypes.shape({
    next: null,
    prev: null
  })
};

export const projectQuery = graphql`
  query projectBySlug($slug: String!) {
    file(relativeDirectory: { glob: "recall" }, name: { in: "logo" }) {
      publicURL
    }
    mdx(
      fields: { slug: { eq: $slug } }
      fileAbsolutePath: { regex: "/projects/" }
    ) {
      code {
        body
      }
      frontmatter {
        title
        slogan
        date(formatString: "MM/DD/YYYY")
        source
        demo
        techs
        tags
      }
      parent {
        ... on File {
          mtime
          birthtime
        }
      }
    }
  }
`;
<commit_msg>got logo query working for project detail page<commit_after>import React from "react";
import PropTypes from "prop-types";
import { Link, graphql } from "gatsby";
import styled from "styled-components";
import MDXRenderer from "gatsby-mdx/mdx-renderer";
import { Chip } from "@material-ui/core";

import { Cover, Layout, Wrapper, SEO, Flex, PrevNext } from "../components";
import source from "../assets/source-code.png";
import demo from "../assets/demo.png";

const Title = styled.h1`
  margin-bottom: 1rem;
`;

const ProjectContent = styled.div`
  margin-top: 4rem;
`;

const Content = styled.div`
  grid-column: 2;
  box-shadow: 0 4px 120px rgba(0, 0, 0, 0.1);
  max-width: 1000px;
  border-radius: 1rem;
  padding: 3rem 6rem;
  background-color: ${props => props.theme.colors.bg};
  z-index: 9000;
  margin-top: -3rem;
  @media (max-width: ${props => props.theme.breakpoints.tablet}) {
    padding: 3rem 2rem;
  }
  @media (max-width: ${props => props.theme.breakpoints.phone}) {
    padding: 2rem 1.5rem;
  }
`;
const Icon = styled.img`
  width: 40px;
`;

const Project = ({
  pageContext: { slug, prev, next },
  data: { mdx: projectNode, file: publicURL }
}) => {
  const project = projectNode.frontmatter;
  return (
    <Layout customSEO>
      <Cover condensed />
      <Wrapper>
        <SEO postPath={slug} postNode={projectNode} article />
        <Content>
          <Flex>

              <Title>{project.title}</Title>

{project.slogan}

          </Flex>

            Source Code: <Icon src={source} alt="source" />

            Demo: <Icon src={demo} alt="demo" />

            Tech:{" "}
            {project.techs.map(tech => (
              <Link to={`/techs/${tech}`}>
                <Chip label={tech} key={tech} />
              </Link>
            ))}

            Tags:{" "}
            {project.tags.map(tag => (
              <Link to={`/tags/${tag}`}>
                <Chip label={tag} key={tag} />
              </Link>
            ))}

          <ProjectContent>
            <MDXRenderer>{projectNode.code.body}</MDXRenderer>
          </ProjectContent>
          <PrevNext prefix={`/projects`} prev={prev} next={next} />
        </Content>
      </Wrapper>
    </Layout>
  );
};

export default Project;

Project.propTypes = {
  pageContext: PropTypes.shape({
    slug: PropTypes.string.isRequired,
    next: PropTypes.object,
    prev: PropTypes.object
  }),
  data: PropTypes.shape({
    mdx: PropTypes.object.isRequired
  }).isRequired
};

Project.defaultProps = {
  pageContext: PropTypes.shape({
    next: null,
    prev: null
  })
};

export const projectQuery = graphql`
  query projectBySlug($slug: String!, $dir: String!) {
    file(relativeDirectory: { eq: $dir }, name: { in: "logo" }) {
      publicURL
    }
    mdx(
      fields: { slug: { eq: $slug } }
      fileAbsolutePath: { regex: "/projects/" }
    ) {
      code {
        body
      }
      frontmatter {
        title
        slogan
        date(formatString: "MM/DD/YYYY")
        source
        demo
        techs
        tags
      }
      parent {
        ... on File {
          mtime
          birthtime
        }
      }
    }
  }
`;
<|endoftext|>


<commit_before>import React from 'react'
import Helmet from '../components/helmet'
import Link from 'gatsby-link'
import styled from 'emotion/react'

import { createPanes, PageContainer } from '../layouts/containers'
import { sansfont, Header1, breakpoint1 } from '../layouts/emotion-base'
import ProjectDescription from '../components/ProjectDescription'
import ProjectDesigners from '../components/ProjectDesigners'
import ImageList from '../components/ImageList'
import HiddenSelector from '../components/HiddenSelector'
import WorkSummary from '../components/WorkSummary'
import Video from '../components/Video'
import {
  imageInfo,
  projectLink,
  workImageTexts,
  workLink,
  SHOW_SELECTORS,
} from '../util'

const { LeftPane, RightPane } = createPanes()

const ProjectHeader = styled.div`
  composes: ${sansfont};
  margin-bottom: 40px;
`

const ProjectWhen = styled.div`
  composes: ${sansfont};
  margin-top: 20px;
  font-size: 20px;
  font-weight: 100;
`

const ProjectTemplate = ({ data, pathContext }) => {
  const { project, allProjectsYaml, allDesignersYaml } = data

  const projects = allProjectsYaml.edges.map(edge => edge.node)
  const designers = allDesignersYaml
    ? allDesignersYaml.edges.map(edge => edge.node)
    : []

  const projectImages = (project.hydratedImages || [])
    .filter(i => !!i)
    .map(image =>
      Object.assign(imageInfo(image), {
        texts: image.caption ? { title: image.caption } : null,
      })
    )

  const workImages = []
  designers.forEach(designer => {
    const works = (designer.works || []).filter(
      work =>
        work.projects &&
        work.projects.map(project => project.slug).includes(project.slug) &&
        work.hydratedImages &&
        work.hydratedImages.length > 0 &&
        work.hydratedImages[0]
    )

    works.forEach(work => {
      workImages.push(
        Object.assign(imageInfo(work.hydratedImages[0]), {
          work,
          designer,
          texts: workImageTexts({
            work,
            designer,
            smallText: (
              <Link to={workLink(designer.slug, work.slug)}>
                {work.title}, {work.when}
              </Link>
            ),
          }),
        })
      )
    })
  })

  const imageSets = [
    { images: projectImages, title: null },
    { images: workImages, title: 'Included Works' },
  ].filter(item => item.images.length > 0)

  const typeTitle = `${project.type}s`
  const currentTypeProjects = projects.filter(p => p.type === project.type)

  const projectsByYear = Array.from(
    new Set(currentTypeProjects.map(p => p.date))
  )
    .sort((a, b) => Date.parse(b) - Date.parse(a)) // sort reverse-chronologically
    .map(date => {
      const dateYear = function(date) {
        return new Date(date).getFullYear()
      }
      const year = dateYear(date)
      return {
        year,
        projects: currentTypeProjects.filter(p => dateYear(p.date) === year),
      }
    })

  const selectorSections = projectsByYear.map(({ year, projects }) => ({
    title: year,
    items: projects.map(project => ({
      title: project.title,
      link: projectLink(project),
    })),
  }))

  const hoverImageRenderer = hoverImage =>
    hoverImage.work && hoverImage.designer ? (
      <WorkSummary work={hoverImage.work} designer={hoverImage.designer} />
    ) : null

  return (
    <PageContainer>
      <Helmet
        title={`${project.title} - Salon 94 Design`}
        description={project.description}
      />
      <LeftPane>
        {project.video && <Video video={project.video} />}
        <ImageList
          imageSets={imageSets}
          hoverImageRenderer={hoverImageRenderer}
        />
      </LeftPane>
      <RightPane>
        <ProjectHeader>
          <Header1>
            {project.title}

              <ProjectDesigners project={project} designers={designers} />
              <ProjectWhen>{project.when}</ProjectWhen>

          </Header1>
          <ProjectDescription project={project} />
        </ProjectHeader>

        {SHOW_SELECTORS &&
          currentTypeProjects.length > 1 && (
            <HiddenSelector
              title={`All ${typeTitle}`}
              sections={selectorSections}
              currentItemLink={projectLink(project)}
            />
          )}
      </RightPane>
    </PageContainer>
  )
}

export default ProjectTemplate

export const pageQuery = graphql`
  query ProjectsTemplateQuery($slug: String!, $designersRegex: String!) {
    project: projectsYaml(slug: { eq: $slug }) {
      ...fullProjectFields
    }
    allProjectsYaml(sort: { order: ASC, fields: [title] }) {
      ...linkProjectEdges
    }
    allDesignersYaml(filter: { slug: { regex: $designersRegex } }) {
      edges {
        node {
          slug
          title
          ...fullWorkFields
        }
      }
    }
  }
`
<commit_msg>ui: add 'Exhibition view' header<commit_after>import React from 'react'
import Helmet from '../components/helmet'
import Link from 'gatsby-link'
import styled from 'emotion/react'

import { createPanes, PageContainer } from '../layouts/containers'
import { sansfont, Header1, breakpoint1 } from '../layouts/emotion-base'
import ProjectDescription from '../components/ProjectDescription'
import ProjectDesigners from '../components/ProjectDesigners'
import ImageList from '../components/ImageList'
import HiddenSelector from '../components/HiddenSelector'
import WorkSummary from '../components/WorkSummary'
import Video from '../components/Video'
import {
  imageInfo,
  projectLink,
  workImageTexts,
  workLink,
  SHOW_SELECTORS,
} from '../util'

const { LeftPane, RightPane } = createPanes()

const ProjectHeader = styled.div`
  composes: ${sansfont};
  margin-bottom: 40px;
`

const ProjectWhen = styled.div`
  composes: ${sansfont};
  margin-top: 20px;
  font-size: 20px;
  font-weight: 100;
`

const ProjectTemplate = ({ data, pathContext }) => {
  const { project, allProjectsYaml, allDesignersYaml } = data

  const projects = allProjectsYaml.edges.map(edge => edge.node)
  const designers = allDesignersYaml
    ? allDesignersYaml.edges.map(edge => edge.node)
    : []

  const projectImages = (project.hydratedImages || [])
    .filter(i => !!i)
    .map(image =>
      Object.assign(imageInfo(image), {
        texts: image.caption ? { title: image.caption } : null,
      })
    )

  const workImages = []
  designers.forEach(designer => {
    const works = (designer.works || []).filter(
      work =>
        work.projects &&
        work.projects.map(project => project.slug).includes(project.slug) &&
        work.hydratedImages &&
        work.hydratedImages.length > 0 &&
        work.hydratedImages[0]
    )

    works.forEach(work => {
      workImages.push(
        Object.assign(imageInfo(work.hydratedImages[0]), {
          work,
          designer,
          texts: workImageTexts({
            work,
            designer,
            smallText: (
              <Link to={workLink(designer.slug, work.slug)}>
                {work.title}, {work.when}
              </Link>
            ),
          }),
        })
      )
    })
  })

  const imageSets = [
    { images: projectImages, title: !project.video.vimeoId ? 'Exhibition View' : null },
    { images: workImages, title: 'Included Works' },
  ].filter(item => item.images.length > 0)

  const typeTitle = `${project.type}s`
  const currentTypeProjects = projects.filter(p => p.type === project.type)

  const projectsByYear = Array.from(
    new Set(currentTypeProjects.map(p => p.date))
  )
    .sort((a, b) => Date.parse(b) - Date.parse(a)) // sort reverse-chronologically
    .map(date => {
      const dateYear = function(date) {
        return new Date(date).getFullYear()
      }
      const year = dateYear(date)
      return {
        year,
        projects: currentTypeProjects.filter(p => dateYear(p.date) === year),
      }
    })

  const selectorSections = projectsByYear.map(({ year, projects }) => ({
    title: year,
    items: projects.map(project => ({
      title: project.title,
      link: projectLink(project),
    })),
  }))

  const hoverImageRenderer = hoverImage =>
    hoverImage.work && hoverImage.designer ? (
      <WorkSummary work={hoverImage.work} designer={hoverImage.designer} />
    ) : null

  return (
    <PageContainer>
      <Helmet
        title={`${project.title} - Salon 94 Design`}
        description={project.description}
      />
      <LeftPane>
        {project.video.vimeoId && <Video video={project.video} />}
        <ImageList
          imageSets={imageSets}
          hoverImageRenderer={hoverImageRenderer}
        />
      </LeftPane>
      <RightPane>
        <ProjectHeader>
          <Header1>
            {project.title}

              <ProjectDesigners project={project} designers={designers} />
              <ProjectWhen>{project.when}</ProjectWhen>

          </Header1>
          <ProjectDescription project={project} />
        </ProjectHeader>

        {SHOW_SELECTORS &&
          currentTypeProjects.length > 1 && (
            <HiddenSelector
              title={`All ${typeTitle}`}
              sections={selectorSections}
              currentItemLink={projectLink(project)}
            />
          )}
      </RightPane>
    </PageContainer>
  )
}

export default ProjectTemplate

export const pageQuery = graphql`
  query ProjectsTemplateQuery($slug: String!, $designersRegex: String!) {
    project: projectsYaml(slug: { eq: $slug }) {
      ...fullProjectFields
    }
    allProjectsYaml(sort: { order: ASC, fields: [title] }) {
      ...linkProjectEdges
    }
    allDesignersYaml(filter: { slug: { regex: $designersRegex } }) {
      edges {
        node {
          slug
          title
          ...fullWorkFields
        }
      }
    }
  }
`
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2016-2017 The Regents of the University of California
 * Author: Jim Robinson
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/**
 * Created by dat on 4/18/17.
 */

var igv = (function (igv) {

    igv.IGVModalTable = function (config) {

        var self = this,
            $modal;

        this.initialized = false;

        this.config = config;

        $modal = config.$modal;

        this.dataSource = config.dataSource;

        this.$modalTable = $('

');

        config.$modalBody.append(this.$modalTable);

        this.$spinner = $('
');
        this.$modalTable.append(this.$spinner);

        this.$spinner.append($(''));
        this.$spinner.hide();

        $modal.on('show.bs.modal', function (e) {

            if (undefined === config.browserRetrievalFunction) {
                igv.presentAlert('ERROR: must provide browser retrieval function');
            }

        });

        $modal.on('shown.bs.modal', function (e) {

            if (undefined === config.browserRetrievalFunction) {
                $modal.modal('hide');
            } else if (true !== self.initialized) {
                self.initialized = true;
                self.$spinner.show();
                self.dataSource.retrieveData(function () {
                    self.createTableWithDataSource(self.dataSource);
                    self.$spinner.hide();
                });
            }

        });

        config.$modalTopCloseButton.on('click', function () {
            $('tr.selected').removeClass('selected');
        });

        config.$modalBottomCloseButton.on('click', function () {
            $('tr.selected').removeClass('selected');
        });

        config.$modalGoButton.on('click', function () {

            var dt,
                $selectedTableRows,
                result,
                browser;

            $selectedTableRows = self.$dataTables.$('tr.selected');

            if (undefined === config.browserRetrievalFunction) {
                igv.presentAlert('ERROR: must provide browser retrieval function');
            } else if ($selectedTableRows.length > 0) {

                $selectedTableRows.removeClass('selected');

                dt = self.$modalTable.DataTable();
                result = [];
                $selectedTableRows.each(function() {
                    result.push( self.dataSource.dataAtRowIndex( dt.row(this).index() ) );
                });

                browser = config.browserRetrievalFunction();
                browser[ config.browserLoadFunction ](result);
            }

        });

    };

    igv.IGVModalTable.prototype.genomeID = function () {
        return this.dataSource.config.genomeID;
    };

    igv.IGVModalTable.teardown = function () {

        var list;

        list =
            [
                this.$modalTable.find('tbody'),
                this.config.$modal,
                this.config.$modalTopCloseButton,
                this.config.$modalBottomCloseButton,
                this.config.$modalGoButton
            ];

        _.each(list, function ($e) {
            $e.unbind();
        });

        this.config.$modalBody.empty();
    };

    igv.IGVModalTable.prototype.unbindAllMouseHandlers = function () {
        var list;

        list =
            [
                this.$modalTable.find('tbody'),
                this.config.$modal,
                this.config.$modalTopCloseButton,
                this.config.$modalBottomCloseButton,
                this.config.$modalGoButton
            ];

        _.each(list, function ($e) {
            $e.unbind();
        });

    };

    /**
     * @param dataSource source of data fed to the table (see for example EncodeDataSource)
     */
    igv.IGVModalTable.prototype.createTableWithDataSource = function (dataSource) {

        this.$spinner.hide();

        this.$dataTables = this.$modalTable.dataTable({
            data: dataSource.tableData(),
            paging: true,
            scrollX: false,
            scrollY: '400px',
            scrollCollapse: false,
            scroller: true,
            fixedColumns: true,
            columns: dataSource.tableColumns()
        });

        this.$modalTable.find('tbody').on('click', 'tr', function () {

            if ($(this).hasClass('selected')) {
                $(this).removeClass('selected');
            } else {
                $(this).addClass('selected');
            }

        });

    };

    return igv;

})(igv || {});
<commit_msg>remove dead code<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2016-2017 The Regents of the University of California
 * Author: Jim Robinson
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/**
 * Created by dat on 4/18/17.
 */

var igv = (function (igv) {

    igv.IGVModalTable = function (config) {

        var self = this,
            $modal;

        this.initialized = false;

        this.config = config;

        $modal = config.$modal;

        this.dataSource = config.dataSource;

        this.$modalTable = $('

');

        config.$modalBody.append(this.$modalTable);

        this.$spinner = $('
');
        this.$modalTable.append(this.$spinner);

        this.$spinner.append($(''));
        this.$spinner.hide();

        $modal.on('show.bs.modal', function (e) {

            if (undefined === config.browserRetrievalFunction) {
                igv.presentAlert('ERROR: must provide browser retrieval function');
            }

        });

        $modal.on('shown.bs.modal', function (e) {

            if (undefined === config.browserRetrievalFunction) {
                $modal.modal('hide');
            } else if (true !== self.initialized) {
                self.initialized = true;
                self.$spinner.show();
                self.dataSource.retrieveData(function () {
                    self.createTableWithDataSource(self.dataSource);
                    self.$spinner.hide();
                });
            }

        });

        config.$modalTopCloseButton.on('click', function () {
            $('tr.selected').removeClass('selected');
        });

        config.$modalBottomCloseButton.on('click', function () {
            $('tr.selected').removeClass('selected');
        });

        config.$modalGoButton.on('click', function () {

            var dt,
                $selectedTableRows,
                result,
                browser;

            $selectedTableRows = self.$dataTables.$('tr.selected');

            if (undefined === config.browserRetrievalFunction) {
                igv.presentAlert('ERROR: must provide browser retrieval function');
            } else if ($selectedTableRows.length > 0) {

                $selectedTableRows.removeClass('selected');

                dt = self.$modalTable.DataTable();
                result = [];
                $selectedTableRows.each(function() {
                    result.push( self.dataSource.dataAtRowIndex( dt.row(this).index() ) );
                });

                browser = config.browserRetrievalFunction();
                browser[ config.browserLoadFunction ](result);
            }

        });

    };

    igv.IGVModalTable.prototype.genomeID = function () {
        return this.dataSource.config.genomeID;
    };

    igv.IGVModalTable.teardown = function () {

        var list;

        list =
            [
                this.$modalTable.find('tbody'),
                this.config.$modal,
                this.config.$modalTopCloseButton,
                this.config.$modalBottomCloseButton,
                this.config.$modalGoButton
            ];

        _.each(list, function ($e) {
            $e.unbind();
        });

        this.config.$modalBody.empty();
    };

    /**
     * @param dataSource source of data fed to the table (see for example EncodeDataSource)
     */
    igv.IGVModalTable.prototype.createTableWithDataSource = function (dataSource) {

        this.$spinner.hide();

        this.$dataTables = this.$modalTable.dataTable({
            data: dataSource.tableData(),
            paging: true,
            scrollX: false,
            scrollY: '400px',
            scrollCollapse: false,
            scroller: true,
            fixedColumns: true,
            columns: dataSource.tableColumns()
        });

        this.$modalTable.find('tbody').on('click', 'tr', function () {

            if ($(this).hasClass('selected')) {
                $(this).removeClass('selected');
            } else {
                $(this).addClass('selected');
            }

        });

    };

    return igv;

})(igv || {});
<|endoftext|>


<commit_before>/*
 * == BSD2 LICENSE ==
 * Copyright (c) 2014, Tidepool Project
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the associated License, which is identical to the BSD 2-Clause
 * License as published by the Open Source Initiative at opensource.org.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the License for more details.
 *
 * You should have received a copy of the License along with this program; if
 * not, you can obtain one from Tidepool Project at tidepool.org.
 * == BSD2 LICENSE ==
 */

var common = require('./common.js');
var schema = require('./validator/schematron.js');

var basalCommon = {
  deliveryType: schema().in(['scheduled', 'suspend', 'temp']),
  deviceTime: schema().ifExists().isDeviceTime(),
  duration: schema().ifExists().number().min(0),
  normalEnd: schema().isISODateTime(),
  rate: schema().number().min(0)
};

module.exports = schema(
  common,
  schema(basalCommon),
  {
    suppressed: schema().ifExists().object(basalCommon)
  }
);
<commit_msg>Allow 'automated' deliveryType in basal validation<commit_after>/*
 * == BSD2 LICENSE ==
 * Copyright (c) 2014, Tidepool Project
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the associated License, which is identical to the BSD 2-Clause
 * License as published by the Open Source Initiative at opensource.org.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the License for more details.
 *
 * You should have received a copy of the License along with this program; if
 * not, you can obtain one from Tidepool Project at tidepool.org.
 * == BSD2 LICENSE ==
 */

var common = require('./common.js');
var schema = require('./validator/schematron.js');

var basalCommon = {
  deliveryType: schema().in(['scheduled', 'suspend', 'temp', 'automated']),
  deviceTime: schema().ifExists().isDeviceTime(),
  duration: schema().ifExists().number().min(0),
  normalEnd: schema().isISODateTime(),
  rate: schema().number().min(0)
};

module.exports = schema(
  common,
  schema(basalCommon),
  {
    suppressed: schema().ifExists().object(basalCommon)
  }
);
<|endoftext|>