<commit_before>;(function($$){ 'use strict';

  var CanvasRenderer = $$('renderer', 'canvas');

  // Draw edge text
  CanvasRenderer.prototype.drawEdgeText = function(context, edge) {
    var text = edge._private.style['content'].strValue;

    if( !text || text.match(/^\s+$/) ){
      return;
    }

    if( this.hideEdgesOnViewport && (this.dragData.didDrag || this.pinching || this.hoverData.dragging || this.data.wheel || this.swipePanning) ){ return; } // save cycles on pinching

    var computedSize = edge._private.style['font-size'].pxValue * edge.cy().zoom();
    var minSize = edge._private.style['min-zoomed-font-size'].pxValue;

    if( computedSize < minSize ){
      return;
    }

    // Calculate text draw position

    context.textAlign = 'center';
    context.textBaseline = 'middle';

    // this.recalculateEdgeLabelProjection( edge );

    var rs = edge._private.rscratch;
    if( !$$.is.number( rs.labelX ) || !$$.is.number( rs.labelY ) ){ return; } // no pos => label can't be rendered

    var style = edge._private.style;
    var autorotate = style['edge-text-rotation'].strValue === 'autorotate';
    var theta, dx, dy;

    if( autorotate ){
      switch( rs.edgeType ){
        case 'haystack':
          dx = rs.haystackPts[2] - rs.haystackPts[0];
          dy = rs.haystackPts[3] - rs.haystackPts[1];
          break;
        default:
          dx = rs.endX - rs.startX;
          dy = rs.endY - rs.startY;
      }

      theta = Math.atan( dy / dx );

      context.translate(rs.labelX, rs.labelY);
      context.rotate(theta);

      this.drawText(context, edge, 0, -4); // make label offset from the edge a bit

      context.rotate(-theta);
      context.translate(-rs.labelX, -rs.labelY);
    } else {
      this.drawText(context, edge, rs.labelX, rs.labelY);
    }

  };

  // Draw node text
  CanvasRenderer.prototype.drawNodeText = function(context, node) {
    var text = node._private.style['content'].strValue;

    if ( !text || text.match(/^\s+$/) ) {
      return;
    }

    var computedSize = node._private.style['font-size'].pxValue * node.cy().zoom();
    var minSize = node._private.style['min-zoomed-font-size'].pxValue;

    if( computedSize < minSize ){
      return;
    }

    // this.recalculateNodeLabelProjection( node );

    var textHalign = node._private.style['text-halign'].strValue;
    var textValign = node._private.style['text-valign'].strValue;
    var rs = node._private.rscratch;
    if( !$$.is.number( rs.labelX ) || !$$.is.number( rs.labelY ) ){ return; } // no pos => label can't be rendered

    switch( textHalign ){
      case 'left':
        context.textAlign = 'right';
        break;

      case 'right':
        context.textAlign = 'left';
        break;

      default: // e.g. center
        context.textAlign = 'center';
    }

    switch( textValign ){
      case 'top':
        context.textBaseline = 'bottom';
        break;

      case 'bottom':
        context.textBaseline = 'top';
        break;

      default: // e.g. center
        context.textBaseline = 'middle';
    }

    this.drawText(context, node, rs.labelX, rs.labelY);
  };

  CanvasRenderer.prototype.getFontCache = function(context){
    var cache;

    this.fontCaches = this.fontCaches || [];

    for( var i = 0; i < this.fontCaches.length; i++ ){
      cache = this.fontCaches[i];

      if( cache.context === context ){
        return cache;
      }
    }

    cache = {
      context: context
    };
    this.fontCaches.push(cache);

    return cache;
  };

  // set up canvas context with font
  // returns transformed text string
  CanvasRenderer.prototype.setupTextStyle = function( context, element ){
    // Font style
    var parentOpacity = element.effectiveOpacity();
    var style = element._private.style;
    var labelStyle = style['font-style'].strValue;
    var labelSize = style['font-size'].pxValue + 'px';
    var labelFamily = style['font-family'].strValue;
    var labelWeight = style['font-weight'].strValue;
    var opacity = style['text-opacity'].value * style['opacity'].value * parentOpacity;
    var outlineOpacity = style['text-outline-opacity'].value * opacity;
    var color = style['color'].value;
    var outlineColor = style['text-outline-color'].value;
    var shadowBlur = style['text-shadow-blur'].pxValue;
    var shadowOpacity = style['text-shadow-opacity'].value;
    var shadowColor = style['text-shadow-color'].value;
    var shadowOffsetX = style['text-shadow-offset-x'].pxValue;
    var shadowOffsetY = style['text-shadow-offset-y'].pxValue;

    var fontCacheKey = element._private.fontKey;
    var cache = this.getFontCache(context);

    if( cache.key !== fontCacheKey ){
      context.font = labelStyle + ' ' + labelWeight + ' ' + labelSize + ' ' + labelFamily;

      cache.key = fontCacheKey;
    }

    var text = String(style['content'].value);
    var textTransform = style['text-transform'].value;

    if (textTransform == 'none') {
    } else if (textTransform == 'uppercase') {
      text = text.toUpperCase();
    } else if (textTransform == 'lowercase') {
      text = text.toLowerCase();
    }

    // Calculate text draw position based on text alignment

    // so text outlines aren't jagged
    context.lineJoin = 'round';

    this.fillStyle(context, color[0], color[1], color[2], opacity);

    this.strokeStyle(context, outlineColor[0], outlineColor[1], outlineColor[2], outlineOpacity);

    this.shadowStyle(context, shadowColor, shadowOpacity, shadowBlur, shadowOffsetX, shadowOffsetY);

    return text;
  };

  function roundRect(ctx, x, y, width, height, radius) {
    var radius = radius || 5;
    ctx.beginPath();
    ctx.moveTo(x + radius, y);
    ctx.lineTo(x + width - radius, y);
    ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
    ctx.lineTo(x + width, y + height - radius);
    ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
    ctx.lineTo(x + radius, y + height);
    ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
    ctx.lineTo(x, y + radius);
    ctx.quadraticCurveTo(x, y, x + radius, y);
    ctx.closePath();
    ctx.fill();
  }

  // Draw text
  CanvasRenderer.prototype.drawText = function(context, element, textX, textY) {
    var style = element._private.style;
    var rstyle = element._private.rstyle;
    var parentOpacity = element.effectiveOpacity();
    if( parentOpacity === 0 || style["text-opacity"].value === 0){ return; }

    var text = this.setupTextStyle( context, element );

    if ( text != null && !isNaN(textX) && !isNaN(textY)) {
      var backgroundOpacity = style["text-background-opacity"].value;
      if ((style["text-background-color"] && style["text-background-color"].value != "none" || style["text-border-width"].pxValue > 0) && backgroundOpacity > 0) {
        var textBorderWidth = style["text-border-width"].pxValue;
        var margin = 4 + textBorderWidth/2;
        var halign = style["text-halign"].value;
        var valign = valign;

        if (element.isNode()) {
          //Move textX, textY to include the background margins
          if (valign == "top") {
            textY -=margin;
          } else if (valign == "bottom") {
            textY +=margin;
          }
          if (halign == "left") {
            textX -=margin;
          } else if (halign == "right") {
            textX +=margin;
          }
        }

        var bgWidth = rstyle.labelWidth;
        var bgHeight = style['font-size'].pxValue;
        var bgX = textX;

        if (halign) {
          if (halign == "center") {
            bgX = bgX - bgWidth / 2;
          } else if (halign == "left") {
            bgX = bgX- bgWidth;
          }
        }

        var bgY = textY;

        if (element.isNode()) {
          if (valign == "top") {
             bgY = bgY - bgHeight;
          } else if (valign == "center") {
            bgY = bgY- bgHeight / 2;
          }
        } else {
          bgY = bgY - bgHeight / 2;
        }

        if (style['edge-text-rotation'].strValue === 'autorotate') {
          textY = 0;
          bgWidth += 4;
          bgX = textX - bgWidth / 2;
          bgY = textY - bgHeight / 2;
        } else {
          // Adjust with border width & margin
          bgX -= margin;
          bgY -= margin;
          bgHeight += margin*2;
          bgWidth += margin*2;
        }

        if (style["text-background-color"]) {
          var textFill = context.fillStyle;
          var textBackgroundColor = style["text-background-color"].value;

          context.fillStyle = "rgba(" + textBackgroundColor[0] + "," + textBackgroundColor[1] + "," + textBackgroundColor[2] + "," + backgroundOpacity * parentOpacity + ")";
          roundRect(context, bgX, bgY, bgWidth, bgHeight, 2);
          context.fillStyle = textFill;
        }

        if (textBorderWidth > 0) {
          var textStroke = context.strokeStyle;
          var textLineWidth = context.lineWidth;
          var textBorderColor = style["text-border-color"].value;
          var textBorderStyle = style['text-border-style'].value;

          context.strokeStyle = "rgba(" + textBorderColor[0] + "," + textBorderColor[1] + "," + textBorderColor[2] + "," + backgroundOpacity * parentOpacity + ")";
          context.lineWidth = textBorderWidth;

          if( context.setLineDash ){ // for very outofdate browsers
            switch( textBorderStyle ){
              case 'dotted':
                context.setLineDash([ 1, 1 ]);
                break;
              case 'dashed':
                context.setLineDash([ 4, 2 ]);
                break;
              case 'double':
                context.lineWidth = textBorderWidth/4; // 50% reserved for white between the two borders
              case 'solid':
                context.setLineDash([ ]);
                break;
            }
          }

          context.strokeRect(bgX,bgY,bgWidth,bgHeight);

          if( textBorderStyle === 'double' ){
            var whiteWidth = textBorderWidth/2;

            context.strokeRect(bgX+whiteWidth,bgY+whiteWidth,bgWidth-whiteWidth*2,bgHeight-whiteWidth*2);
          }

          if( context.setLineDash ){ // for very outofdate browsers
            context.setLineDash([ ]);
          }
          context.lineWidth = textLineWidth;
          context.strokeStyle = textStroke;
        }

      }

      var lineWidth = 2  * style['text-outline-width'].value; // *2 b/c the stroke is drawn centred on the middle

      if (lineWidth > 0) {
        context.lineWidth = lineWidth;
        context.strokeText(text, textX, textY);
      }

      context.fillText(text, textX, textY);

      this.shadowStyle(context, 'transparent', 0); // reset for next guy
    }
  };

})( cytoscape );<commit_msg>always centred edge labels w/ autorotate re #849 and #838<commit_after>;(function($$){ 'use strict';

  var CanvasRenderer = $$('renderer', 'canvas');

  // Draw edge text
  CanvasRenderer.prototype.drawEdgeText = function(context, edge) {
    var text = edge._private.style['content'].strValue;

    if( !text || text.match(/^\s+$/) ){
      return;
    }

    if( this.hideEdgesOnViewport && (this.dragData.didDrag || this.pinching || this.hoverData.dragging || this.data.wheel || this.swipePanning) ){ return; } // save cycles on pinching

    var computedSize = edge._private.style['font-size'].pxValue * edge.cy().zoom();
    var minSize = edge._private.style['min-zoomed-font-size'].pxValue;

    if( computedSize < minSize ){
      return;
    }

    // Calculate text draw position

    context.textAlign = 'center';
    context.textBaseline = 'middle';

    // this.recalculateEdgeLabelProjection( edge );

    var rs = edge._private.rscratch;
    if( !$$.is.number( rs.labelX ) || !$$.is.number( rs.labelY ) ){ return; } // no pos => label can't be rendered

    var style = edge._private.style;
    var autorotate = style['edge-text-rotation'].strValue === 'autorotate';
    var theta, dx, dy;

    if( autorotate ){
      switch( rs.edgeType ){
        case 'haystack':
          dx = rs.haystackPts[2] - rs.haystackPts[0];
          dy = rs.haystackPts[3] - rs.haystackPts[1];
          break;
        default:
          dx = rs.endX - rs.startX;
          dy = rs.endY - rs.startY;
      }

      theta = Math.atan( dy / dx );

      context.translate(rs.labelX, rs.labelY);
      context.rotate(theta);

      this.drawText(context, edge, 0, 0); // make label offset from the edge a bit

      context.rotate(-theta);
      context.translate(-rs.labelX, -rs.labelY);
    } else {
      this.drawText(context, edge, rs.labelX, rs.labelY);
    }

  };

  // Draw node text
  CanvasRenderer.prototype.drawNodeText = function(context, node) {
    var text = node._private.style['content'].strValue;

    if ( !text || text.match(/^\s+$/) ) {
      return;
    }

    var computedSize = node._private.style['font-size'].pxValue * node.cy().zoom();
    var minSize = node._private.style['min-zoomed-font-size'].pxValue;

    if( computedSize < minSize ){
      return;
    }

    // this.recalculateNodeLabelProjection( node );

    var textHalign = node._private.style['text-halign'].strValue;
    var textValign = node._private.style['text-valign'].strValue;
    var rs = node._private.rscratch;
    if( !$$.is.number( rs.labelX ) || !$$.is.number( rs.labelY ) ){ return; } // no pos => label can't be rendered

    switch( textHalign ){
      case 'left':
        context.textAlign = 'right';
        break;

      case 'right':
        context.textAlign = 'left';
        break;

      default: // e.g. center
        context.textAlign = 'center';
    }

    switch( textValign ){
      case 'top':
        context.textBaseline = 'bottom';
        break;

      case 'bottom':
        context.textBaseline = 'top';
        break;

      default: // e.g. center
        context.textBaseline = 'middle';
    }

    this.drawText(context, node, rs.labelX, rs.labelY);
  };

  CanvasRenderer.prototype.getFontCache = function(context){
    var cache;

    this.fontCaches = this.fontCaches || [];

    for( var i = 0; i < this.fontCaches.length; i++ ){
      cache = this.fontCaches[i];

      if( cache.context === context ){
        return cache;
      }
    }

    cache = {
      context: context
    };
    this.fontCaches.push(cache);

    return cache;
  };

  // set up canvas context with font
  // returns transformed text string
  CanvasRenderer.prototype.setupTextStyle = function( context, element ){
    // Font style
    var parentOpacity = element.effectiveOpacity();
    var style = element._private.style;
    var labelStyle = style['font-style'].strValue;
    var labelSize = style['font-size'].pxValue + 'px';
    var labelFamily = style['font-family'].strValue;
    var labelWeight = style['font-weight'].strValue;
    var opacity = style['text-opacity'].value * style['opacity'].value * parentOpacity;
    var outlineOpacity = style['text-outline-opacity'].value * opacity;
    var color = style['color'].value;
    var outlineColor = style['text-outline-color'].value;
    var shadowBlur = style['text-shadow-blur'].pxValue;
    var shadowOpacity = style['text-shadow-opacity'].value;
    var shadowColor = style['text-shadow-color'].value;
    var shadowOffsetX = style['text-shadow-offset-x'].pxValue;
    var shadowOffsetY = style['text-shadow-offset-y'].pxValue;

    var fontCacheKey = element._private.fontKey;
    var cache = this.getFontCache(context);

    if( cache.key !== fontCacheKey ){
      context.font = labelStyle + ' ' + labelWeight + ' ' + labelSize + ' ' + labelFamily;

      cache.key = fontCacheKey;
    }

    var text = String(style['content'].value);
    var textTransform = style['text-transform'].value;

    if (textTransform == 'none') {
    } else if (textTransform == 'uppercase') {
      text = text.toUpperCase();
    } else if (textTransform == 'lowercase') {
      text = text.toLowerCase();
    }

    // Calculate text draw position based on text alignment

    // so text outlines aren't jagged
    context.lineJoin = 'round';

    this.fillStyle(context, color[0], color[1], color[2], opacity);

    this.strokeStyle(context, outlineColor[0], outlineColor[1], outlineColor[2], outlineOpacity);

    this.shadowStyle(context, shadowColor, shadowOpacity, shadowBlur, shadowOffsetX, shadowOffsetY);

    return text;
  };

  function roundRect(ctx, x, y, width, height, radius) {
    var radius = radius || 5;
    ctx.beginPath();
    ctx.moveTo(x + radius, y);
    ctx.lineTo(x + width - radius, y);
    ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
    ctx.lineTo(x + width, y + height - radius);
    ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
    ctx.lineTo(x + radius, y + height);
    ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
    ctx.lineTo(x, y + radius);
    ctx.quadraticCurveTo(x, y, x + radius, y);
    ctx.closePath();
    ctx.fill();
  }

  // Draw text
  CanvasRenderer.prototype.drawText = function(context, element, textX, textY) {
    var style = element._private.style;
    var rstyle = element._private.rstyle;
    var parentOpacity = element.effectiveOpacity();
    if( parentOpacity === 0 || style["text-opacity"].value === 0){ return; }

    var text = this.setupTextStyle( context, element );

    if ( text != null && !isNaN(textX) && !isNaN(textY)) {
      var backgroundOpacity = style["text-background-opacity"].value;
      if ((style["text-background-color"] && style["text-background-color"].value != "none" || style["text-border-width"].pxValue > 0) && backgroundOpacity > 0) {
        var textBorderWidth = style["text-border-width"].pxValue;
        var margin = 4 + textBorderWidth/2;
        var halign = style["text-halign"].value;
        var valign = valign;

        if (element.isNode()) {
          //Move textX, textY to include the background margins
          if (valign == "top") {
            textY -=margin;
          } else if (valign == "bottom") {
            textY +=margin;
          }
          if (halign == "left") {
            textX -=margin;
          } else if (halign == "right") {
            textX +=margin;
          }
        }

        var bgWidth = rstyle.labelWidth;
        var bgHeight = style['font-size'].pxValue;
        var bgX = textX;

        if (halign) {
          if (halign == "center") {
            bgX = bgX - bgWidth / 2;
          } else if (halign == "left") {
            bgX = bgX- bgWidth;
          }
        }

        var bgY = textY;

        if (element.isNode()) {
          if (valign == "top") {
             bgY = bgY - bgHeight;
          } else if (valign == "center") {
            bgY = bgY- bgHeight / 2;
          }
        } else {
          bgY = bgY - bgHeight / 2;
        }

        if (style['edge-text-rotation'].strValue === 'autorotate') {
          textY = 0;
          bgWidth += 4;
          bgX = textX - bgWidth / 2;
          bgY = textY - bgHeight / 2;
        } else {
          // Adjust with border width & margin
          bgX -= margin;
          bgY -= margin;
          bgHeight += margin*2;
          bgWidth += margin*2;
        }

        if (style["text-background-color"]) {
          var textFill = context.fillStyle;
          var textBackgroundColor = style["text-background-color"].value;

          context.fillStyle = "rgba(" + textBackgroundColor[0] + "," + textBackgroundColor[1] + "," + textBackgroundColor[2] + "," + backgroundOpacity * parentOpacity + ")";
          roundRect(context, bgX, bgY, bgWidth, bgHeight, 2);
          context.fillStyle = textFill;
        }

        if (textBorderWidth > 0) {
          var textStroke = context.strokeStyle;
          var textLineWidth = context.lineWidth;
          var textBorderColor = style["text-border-color"].value;
          var textBorderStyle = style['text-border-style'].value;

          context.strokeStyle = "rgba(" + textBorderColor[0] + "," + textBorderColor[1] + "," + textBorderColor[2] + "," + backgroundOpacity * parentOpacity + ")";
          context.lineWidth = textBorderWidth;

          if( context.setLineDash ){ // for very outofdate browsers
            switch( textBorderStyle ){
              case 'dotted':
                context.setLineDash([ 1, 1 ]);
                break;
              case 'dashed':
                context.setLineDash([ 4, 2 ]);
                break;
              case 'double':
                context.lineWidth = textBorderWidth/4; // 50% reserved for white between the two borders
              case 'solid':
                context.setLineDash([ ]);
                break;
            }
          }

          context.strokeRect(bgX,bgY,bgWidth,bgHeight);

          if( textBorderStyle === 'double' ){
            var whiteWidth = textBorderWidth/2;

            context.strokeRect(bgX+whiteWidth,bgY+whiteWidth,bgWidth-whiteWidth*2,bgHeight-whiteWidth*2);
          }

          if( context.setLineDash ){ // for very outofdate browsers
            context.setLineDash([ ]);
          }
          context.lineWidth = textLineWidth;
          context.strokeStyle = textStroke;
        }

      }

      var lineWidth = 2  * style['text-outline-width'].value; // *2 b/c the stroke is drawn centred on the middle

      if (lineWidth > 0) {
        context.lineWidth = lineWidth;
        context.strokeText(text, textX, textY);
      }

      context.fillText(text, textX, textY);

      this.shadowStyle(context, 'transparent', 0); // reset for next guy
    }
  };

})( cytoscape );<|endoftext|>


<commit_before>import Velocity from 'velocity-animate'
import {
	PAGE_SCROLL_STARTED,
	PAGE_SCROLL_ENDED,
    SCROLL_HEADER
} from '../constants'

const scrollEndpoints = ["content", "settings"]  // "home" is immovable
const scrollDuration = 1000
const scrollEasing = "ease-in-out"

export function scrollPage(endpoint, up) {

    if ( !scrollEndpoints.includes(endpoint) )
        throw new Error("Invalid scroll endpoint supplied to action");

    const top = up ? 0 : window.innerHeight
    const $target = getTarget(endpoint)

    return (dispatch, getState) => {
        if (up && !shouldScroll(getState(), endpoint)) return;

        $target.velocity("stop");
        dispatch(startScroll(endpoint));

        return $target.velocity({top}, {
            duration: scrollDuration,
            easing: scrollEasing,
            complete: () => dispatch(endScroll(endpoint))
        });
    }
}

function shouldScroll({status}, target) {
    return status.currentPage !== target
}

function getTarget(endpoint) {
    const target = $('.page-'+endpoint) // will always be 1
    if (!target) {
        throw new Error(`No .page-${endpoint} found`);
    } else return target
}

function startScroll(currentPage) {
    return {
        type: PAGE_SCROLL_STARTED,
        payload: currentPage
    }
}

function endScroll(currentPage) {
    return {
        type: PAGE_SCROLL_ENDED,
        payload: currentPage
    }
}

export function scrollHeader(toVisible, delay) {
    const $header = $('#header'), duration=300;
    var
        delay = delay||0,
        easing='ease-in',
        top=`-${$header.height()}px`;

    if (toVisible) {
        top = 0
        easing = 'ease-out'
    }

    return (dispatch, getState) => {
        if (shouldScrollHeader(getState(), toVisible)){
            $header.velocity("stop");
            dispatch(headerScroll(toVisible))
            return $header.velocity(
                {top},
                {duration, easing, delay}
            )
        }
    }
}

function headerScroll(toVisible) {
    return {
        type: SCROLL_HEADER,
        payload: toVisible
    }
}

function shouldScrollHeader({status:{ isHeaderVisible }}, toVisible) {
    return isHeaderVisible !== toVisible
}

<commit_msg>Fix page scroll toggle<commit_after>import Velocity from 'velocity-animate'
import {
	PAGE_SCROLL_STARTED,
	PAGE_SCROLL_ENDED,
    SCROLL_HEADER
} from '../constants'

const scrollEndpoints = ["content", "settings"]  // "home" is immovable
const scrollDuration = 1000
const scrollEasing = "ease-in-out"
const scrollTargetPrev = "home"

export function scrollPage(endpoint, up) {

    if ( !scrollEndpoints.includes(endpoint) )
        throw new Error("Invalid scroll endpoint supplied to action");

    const top = up ? 0 : window.innerHeight
    const $target = getTarget(endpoint)

    return (dispatch, getState) => {
        if (up && !shouldScroll(getState(), endpoint)) return;

        $target.velocity("stop");

        if (!up) {
            // Fix scroll toggle. Change state when reverting
            endpoint = scrollTargetPrev
        }

        dispatch(startScroll(endpoint));

        return $target.velocity({top}, {
            duration: scrollDuration,
            easing: scrollEasing,
            complete: () => dispatch(endScroll(endpoint))
        });
    }
}

function shouldScroll({status}, target) {
    return status.currentPage !== target
}

function getTarget(endpoint) {
    const target = $('.page-'+endpoint) // will always be 1
    if (!target) {
        throw new Error(`No .page-${endpoint} found`);
    } else {
        return target
    }
}

function startScroll(currentPage) {
    return {
        type: PAGE_SCROLL_STARTED,
        payload: currentPage
    }
}

function endScroll(currentPage) {
    return {
        type: PAGE_SCROLL_ENDED,
        payload: currentPage
    }
}

export function scrollHeader(toVisible, delay) {
    const $header = $('#header'), duration=300;
    var
        delay = delay||0,
        easing='ease-in',
        top=`-${$header.height()}px`;

    if (toVisible) {
        top = 0
        easing = 'ease-out'
    }

    return (dispatch, getState) => {
        if (shouldScrollHeader(getState(), toVisible)){
            $header.velocity("stop");
            dispatch(headerScroll(toVisible))
            return $header.velocity(
                {top},
                {duration, easing, delay}
            )
        }
    }
}

function headerScroll(toVisible) {
    return {
        type: SCROLL_HEADER,
        payload: toVisible
    }
}

function shouldScrollHeader({status:{ isHeaderVisible }}, toVisible) {
    return isHeaderVisible !== toVisible
}

<|endoftext|>


<commit_before>import React from 'react';
import Container from 'components/container';
import { LineChart } from 'react-d3';

const lineData = [
  {
    name: "series1",
    values: [ { x: 0, y: 1.75 }, { x: 1, y: 1.783 },  { x: 2, y: 1.76 }, { x: 5, y: 1.81 } ]
  }
];

export default class Analytics extends React.Component {

  constructor(props, context){
    super(props, context);
    this.state = {
      tearoff: false
    };
  }

  tearOff(state){
    this.setState({
      tearoff: state
    });
  }

  render(){
    return <Container title='analytics' className='analytics-container animated slideInRight' onTearoff={(state) => this.tearOff(state)}
               tearoff={this.state.tearoff} width={400} height={400} options={{maximizable:true}}>

      <LineChart data={lineData}
                 legend={!true}
                 width={400}
                 height={400}
                 viewBoxObject={{
                    x: 0,
                    y: 0,
                    width: 600,
                    height: 400
                  }}
                  title="PNL - EURGBP"
                  gridHorizontal={true}/>
    </Container>;
  }
}
<commit_msg>size tweaks<commit_after>import React from 'react';
import Container from 'components/container';
import { LineChart } from 'react-d3';

const lineData = [
  {
    name: "series1",
    values: [ { x: 0, y: 1.75 }, { x: 1, y: 1.783 },  { x: 2, y: 1.76 }, { x: 5, y: 1.81 } ]
  }
];

export default class Analytics extends React.Component {

  constructor(props, context){
    super(props, context);
    this.state = {
      tearoff: false
    };
  }

  tearOff(state){
    this.setState({
      tearoff: state
    });
  }

  render(){
    return <Container title='analytics' className='analytics-container animated slideInRight' onTearoff={(state) => this.tearOff(state)}
               tearoff={this.state.tearoff} width={400} height={800} options={{maximizable:true}}>

      <LineChart data={lineData}
                 legend={!true}
                 width={380}
                 height={400}
                 viewBoxObject={{
                    x: 0,
                    y: 0,
                    width: 600,
                    height: 400
                  }}
                  title="PNL - EURGBP"
                  gridHorizontal={true}/>
    </Container>;
  }
}
<|endoftext|>


<commit_before>'use strict';

const { WSEvents } = require('../../../util/Constants');

const handlers = {};

for (const name of Object.keys(WSEvents)) {
  try {
    handlers[name] = require(`./${name}.js`);
  } catch {} // eslint-disable-line no-empty
}

module.exports = handlers;
<commit_msg>refactor: remove error-silencing try/catch on event handler imports (#5542)<commit_after>'use strict';

const { WSEvents } = require('../../../util/Constants');

const handlers = {};

for (const name of Object.keys(WSEvents)) {
  handlers[name] = require(`./${name}.js`);
}

module.exports = handlers;
<|endoftext|>


<commit_before>var logger = require('npmlog'),
    express = require('express'),
    Memcached = require('memcached'),
    Path = require('path'),
    fs = require('fs'),
    moment = require('moment-timezone');

var Settings = require('../shared/settings.js'),
    settings = new Settings(),
    Mongo = require('../shared/mongo'),
    PluginLoader = require('./plugins'),
    Parser = require('./parser');

if(settings.loggerLevel) {
    logger.level = settings.loggerLevel;
}

logger.info('web', 'Trying to load plugins...');
var pluginLoader = new PluginLoader(settings, logger),
    loadable = pluginLoader.listPlugins(),
    plugins = loadable
        .map((p) => pluginLoader.loadPlugin(p))
        .filter((p) => p)
        .sort((a, b) => a.constructor.priority - b.constructor.priority)
        .sort((a) => a.constructor.isUrlTransformer ? 0 : 1);

logger.verbose('web', 'Loaded plugins: ', plugins.map(p => p.constructor.name).join(', '));

var memcachedUrl = `${settings.memcachedHost}:${settings.memcachedPort}`,
    memcached = new Memcached(memcachedUrl),
    mongo = new Mongo(settings.mongoUrl, logger),
    app = express(),
    parser = new Parser(logger, settings, plugins, mongo, memcached);

logger.info('web', `Using memcached @ ${memcachedUrl}`);

app.use(express.static(Path.join(__dirname, '..', '..', 'www')));

app.get('/', (req, res) => {
    var index = Path.join(__dirname, '..', '..', 'www', 'index.html');
    res.send(fs.readFileSync(index), 'text/html');
});

app.get('/api/latest', (req, res) => {
    logger.verbose('web', 'Request for api/latest');
    var rawPresent = Date.now(),
        past = moment(rawPresent).subtract(settings.outputDayRange, 'days'),
        rawPast = past.toDate().valueOf();
    parser.itemsInRange(rawPresent, rawPast, (err, result) => {
        var response = {
            from: rawPast,
            until: rawPresent,
            items: result
        };
        if(err) {
            res.status(500).send('Error');
        } else {
            res.status(200).type('json').send(JSON.stringify(response));
        }
    });
});

var server = app.listen(process.env.PORT || 2708, () => {
  var host = server.address().address,
      port = server.address().port;

  logger.info(`WeeklyDigest Web Interface listening on http://${host}:${port}`);
});
<commit_msg>Add CORS support<commit_after>var logger = require('npmlog'),
    express = require('express'),
    Memcached = require('memcached'),
    Path = require('path'),
    fs = require('fs'),
    moment = require('moment-timezone');

var Settings = require('../shared/settings.js'),
    settings = new Settings(),
    Mongo = require('../shared/mongo'),
    PluginLoader = require('./plugins'),
    Parser = require('./parser');

if(settings.loggerLevel) {
    logger.level = settings.loggerLevel;
}

logger.info('web', 'Trying to load plugins...');
var pluginLoader = new PluginLoader(settings, logger),
    loadable = pluginLoader.listPlugins(),
    plugins = loadable
        .map((p) => pluginLoader.loadPlugin(p))
        .filter((p) => p)
        .sort((a, b) => a.constructor.priority - b.constructor.priority)
        .sort((a) => a.constructor.isUrlTransformer ? 0 : 1);

logger.verbose('web', 'Loaded plugins: ', plugins.map(p => p.constructor.name).join(', '));

var memcachedUrl = `${settings.memcachedHost}:${settings.memcachedPort}`,
    memcached = new Memcached(memcachedUrl),
    mongo = new Mongo(settings.mongoUrl, logger),
    app = express(),
    parser = new Parser(logger, settings, plugins, mongo, memcached);

logger.info('web', `Using memcached @ ${memcachedUrl}`);

app.use(function(req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
    next();
});

app.use(express.static(Path.join(__dirname, '..', '..', 'www')));

app.get('/', (req, res) => {
    var index = Path.join(__dirname, '..', '..', 'www', 'index.html');
    res.send(fs.readFileSync(index), 'text/html');
});

app.get('/api/latest', (req, res) => {
    logger.verbose('web', 'Request for api/latest');
    var rawPresent = Date.now(),
        past = moment(rawPresent).subtract(settings.outputDayRange, 'days'),
        rawPast = past.toDate().valueOf();
    parser.itemsInRange(rawPresent, rawPast, (err, result) => {
        var response = {
            from: rawPast,
            until: rawPresent,
            items: result
        };
        if(err) {
            res.status(500).send('Error');
        } else {
            res.status(200).type('json').send(JSON.stringify(response));
        }
    });
});

var server = app.listen(process.env.PORT || 2708, () => {
  var host = server.address().address,
      port = server.address().port;

  logger.info(`WeeklyDigest Web Interface listening on http://${host}:${port}`);
});
<|endoftext|>


<commit_before>    // Init and define default parameters
    vars.items_data = [];

    // Duplicates the whole dataset
    vars.evt.register('init', utils.duplicate_data);

    if(vars.init) {
      vars.evt.call('init');
    }
    // Each item needs coordinates
    // 1/ In case we use functions for X/Y variables
    // 2/ Adds default attributes __var_x and __var_y if no coordinate exist

    if(typeof vars.var_x !== "string" && typeof vars.var_x === "function") {

      vars.all_data.forEach(function(d, i) {
        d.__var_x = vars.var_x(d, i, vars);
      });

      vars.var_x = "__var_x";

    }

    if(typeof vars.var_x === "undefined") {
      vars.var_x = "__var_x";
    }

    if(typeof vars.var_y !== "string" && typeof vars.var_y === "function") {

      vars.all_data.forEach(function(d, i) {
        d.__var_y = vars.var_y(d, i, vars);
      });

      vars.var_y = "__var_y";

    }

    if(typeof vars.var_y === "undefined") {
      vars.var_y = "__var_y";
    }

    // In case the chart type is a function
    if(typeof vars.type !== "string" && typeof vars.type === "function") {
      vars.type = vars.type(vars);
    }

    if(typeof vars.type === 'undefined') {
      vars.type = 'none';
    };

    // In case the current_time is set dynamically
    if(typeof vars.time.current_time === "function") {
      vars.time.current_time = vars.time.current_time(vars.data);
    }

    // In case the current_time is set dynamically
    if(typeof vars.time.parse === "undefined") {
      vars.time.parse = function(d) { return d; }
    }

    // Calculate vars.new_data which should contain two things
    // 1/ The list of all items (e.g. countries, products)
    // 2/ The metadata for each items
    if(vars.init || vars.refresh) {

      // Duplicate data to prevent mutation
      vars.new_data = JSON.parse(JSON.stringify(vars.all_data));

      // Creates default ids `__id` and `__value` for dataset without any id
      if(typeof vars.var_id === 'undefined') {

        vars.new_data = vars.new_data.map(function(d, i) {

          if(typeof d !== 'object') {
            var e = {}
            e.__id = i;
            e.__value = d;
            d = e;
          }

          d.__id = i;
          return d;

        });

        vars.var_id = '__id';

        if(typeof vars.var_text === 'undefined') {
          vars.var_text = '__id';
        }

      }

      // If time filter parameter is set, then keep values for this time
      if(typeof vars.time.filter !== "undefined" && vars.time.filter.length > 0) {

        if(vars.dev) {
          console.log("[vars.time.filter]", vars.time.filter);
        }

        vars.new_data = vars.new_data.filter(function(d, i) {
          return vars.time.filter.indexOf(d[vars.time.var_time]) > -1;
        });

      }

      // If time filter interval is set, then keep values from this interval
      if(typeof vars.time.filter_interval != "undefined" && vars.time.filter_interval.length == 2) {

        if(vars.dev) {
          console.log("[vars.time.interval]", vars.time.filter_interval);
        }

        vars.new_data = vars.new_data.filter(function(d, i) {
          return (d[vars.time.var_time] >= vars.time.filter_interval[0]) && (d[vars.time.var_time] <= vars.time.filter_interval[1]);
        });

      }

      // Find unique values for various parameters
      vars.time.interval = d3.extent(vars.new_data, function(d) {
        return vars.time.parse(d[vars.time.var_time]);
      });

      // Note: none-parsed time values
      vars.time.points = vistk.utils.find_unique_values(vars.new_data, vars.time.var_time);

      // In case no temporal values, change the accessor
      if(vars.time.var_time === null || vars.type === 'treemap') {
        vars.accessor_data = function(d) { return d; }
      }

      var unique_data = [];

      var lookup_index = [];
      var lookup_size = 0;

      vars.lookup_index_time = [];
      var lookup_time_size = 0;

      vars.new_data.forEach(function(d, i) {

        var index = -1;

        // Creates items by grouping data
        if(typeof lookup_index[d[vars.var_id]] === 'undefined') {

          index = lookup_size;
          lookup_size++;

          lookup_index[d[vars.var_id]] = index;

          utils.init_item(d);

          if(vars.filter.indexOf(d[vars.var_group]) > -1) {
            d.__filtered = true;
          }
          if(vars.highlight.indexOf(d[vars.var_id]) > -1) {
            d.__highlighted = true;
          }
          if(vars.selection.indexOf(d[vars.var_id]) > -1) {
            d.__selected = true;
          }

          d.__redraw = true;

          d.__index = index;

          // Dup for metadata
          var dup = JSON.parse(JSON.stringify(d));
          dup.values = [];

          unique_data.push(dup);

        } else {

          index = lookup_index[d[vars.var_id]];

        }

        var v = {};
        v[vars.time.var_time] = d[vars.time.var_time];
        v[vars.var_y] = d[vars.var_y];
        v[vars.var_x] = d[vars.var_x];
        v[vars.var_color] = d[vars.var_color];
        v[vars.var_size] = d[vars.var_size];
        v[vars.var_text] = d[vars.var_text];
        v[vars.var_r] = d[vars.var_r];
        v[vars.var_share] = d[vars.var_share];
        v[vars.var_id] = d[vars.var_id];

        // TODO: make sure there is no existing value for this time
        unique_data[index].values[d[vars.time.var_time]] = v;

      });

      vars.new_data = unique_data;

    }

    // Filter data by attribute
    // TODO: not sure we should remove data, but add an attribute instead would better
    if(vars.filter.length > 0) {

      if(vars.dev) {
        console.log("[vars.filter]", vars.filter);
      }

      vars.new_data = vars.new_data.filter(function(d) {
        // We don't keep values that are not in the vars.filter array
        return vars.filter.indexOf(d[vars.var_group]+"") > -1;
      });

    }

    // Aggregate data
    if(typeof vars.set['__aggregated'] !== 'undefined' && vars.refresh) {

      if(vars.dev) {
        console.log("[vars.aggregate]", vars.aggregate);
      }

      // Do the nesting by var_group
      // Should make sure it works for a generc dataset
      // Also for time or none-time attributes
      nested_data = d3.nest()
        .key(function(d) {
          return d[vars.var_group];
        })
        .rollup(function(leaves) {

          // Generates a new dataset with aggregated data
          var aggregation = {};

          // Name and id values are
          aggregation[vars.var_id] = 'agg_' + leaves[0][vars.var_group];
          aggregation[vars.var_text] = leaves[0][vars.var_group];
          aggregation[vars.var_group] = leaves[0][vars.var_group];

          // Quick fix in case var_x is an ordinal scale
          if(vars.var_x !== vars.var_id && vars.var_x !== vars.time.var_time && vars.var_x !== vars.var_group) {
            aggregation[vars.var_x] = d3.mean(leaves, function(d) {
              return d[vars.var_x];
            });
          } else {
            aggregation[vars.var_x] = leaves[0][vars.var_x];
          }

          if(vars.var_y !== vars.var_id && vars.var_y !== vars.time.var_time) {
            aggregation[vars.var_y] = d3.mean(leaves, function(d) {
              return d[vars.var_y];
            });
          } else {
            aggregation[vars.var_y] = leaves[0][vars.var_y];
          }

          aggregation[vars.var_r] = d3.sum(leaves, function(d) {
            return d[vars.var_r];
          });

          aggregation[vars.var_share] = d3.sum(leaves, function(d) {
            return d[vars.var_share];
          });

          aggregation.values = [];

          // Assuming all the time values are present in all items
          vars.time.points.forEach(function(time, i) {

            var d = {};

           // if(vars.var_x === vars.time.var_time) {
           //   d[vars.var_x] = leaves[0].values[i][vars.var_x];
           // } else {
           //   d[vars.var_x] = 0;
           // }

            // Init values
            d[vars.var_x] = leaves[0].values[time][vars.var_x];
            d[vars.var_y] = leaves[0].values[time][vars.var_y];
            d[vars.var_r] = leaves[0].values[time][vars.var_r];

            d[vars.var_share] = leaves[0].values[time][vars.var_share];
            d[vars.var_color] = leaves[0].values[time][vars.var_color];
            d[vars.var_size] = leaves[0].values[time][vars.var_size];
            d[vars.var_text] = leaves[0].values[time][vars.var_text];

            // Time var
            d[vars.time.var_time] = leaves[0].values[time][vars.time.var_time];

            // Should stay at the bottom to make sure it's not overriden
            d[vars.var_id] = 'agg_' + leaves[0].values[time][vars.var_id];

            d.__index = 'agg_' + leaves[0].values[time].__index;

            aggregation.values[time] = d;

            //return d;
          });

          // Assuming we only aggregate var_x, var_y, var_r
          leaves.forEach(function(d, i) {

            vars.time.points.forEach(function(time, i) {

              if(vars.var_x !== vars.time.var_time) {
                aggregation.values[time][vars.var_x] += d.values[time][vars.var_x];
              }

              aggregation.values[time][vars.var_y] += d.values[time][vars.var_y];
              aggregation.values[time][vars.var_r] += d.values[time][vars.var_r];

            });
          });

          utils.init_item(aggregation);

          // Set internal attributes specific to aggregate + force redraw
          aggregation.__aggregated = true;
          aggregation.__redraw = true;

          vars.columns.forEach(function(c) {

            if(c === vars.var_text || c === vars.var_group) {
              return;
            }

            aggregation[c] = d3.mean(leaves, function(d) {
              return d[c];
            });
          });

          return aggregation;
        })
        .entries(vars.new_data);

      // Transform key/value into values tab only
      if(typeof vars.set['__aggregated'] !== 'undefined' && vars.set['__aggregated']) {

        vars.new_data = vars.new_data.concat(nested_data.map(function(d) {
          return d.values;
        }));

      } else {

        vars.new_data = nested_data.map(function(d) { return d.values; });

      }

    }

    // Sorting the dataset
    if(typeof vars.var_sort !== "undefined" && vars.refresh) {

      if(vars.dev) {
         console.log("[updating sort]", vars.var_sort, vars.var_sort_asc, vars.user_vars)
      }

      if(typeof vars.var_sort_asc !== "undefined" && !vars.var_sort_asc) {
        vars.new_data = vars.new_data.sort(function(a, b) {
          if(typeof vars.accessor_data(a) !== 'undefined' && typeof vars.accessor_data(b) !== 'undefined')
            return d3.ascending(vars.accessor_data(a)[vars.var_sort], vars.accessor_data(b)[vars.var_sort]);
        });
      } else {
        vars.new_data = vars.new_data.sort(function(a, b) {
          if(typeof vars.accessor_data(a) !== 'undefined' && typeof vars.accessor_data(b) !== 'undefined')
            return d3.descending(vars.accessor_data(a)[vars.var_sort], vars.accessor_data(b)[vars.var_sort]);
        });
      }
    }

    vars.new_data = vars.new_data.filter(function(d) {

      // Making sure we re-draw highlighted items
      if(vars.highlight.indexOf(d[vars.var_id]) > -1) {
        d.__highlighted = true;
        d.__redraw = true;
      } else if(d.__highlighted) {
        d.__highlighted = false;
        d.__redraw = true;
      }

      return typeof vars.accessor_data(d) !== 'undefined' && typeof vars.accessor_data(d)[vars.var_id] !== 'undefined';
    });

    if(vars.redraw_all) {
      vars.new_data.forEach(function(d) { d.__redraw = true; });
    }

    vars.redraw_all = false;
<commit_msg>Fixes for time values<commit_after>    // Init and define default parameters
    vars.items_data = [];

    // Duplicates the whole dataset
    vars.evt.register('init', utils.duplicate_data);

    if(vars.init) {
      vars.evt.call('init');
    }
    // Each item needs coordinates
    // 1/ In case we use functions for X/Y variables
    // 2/ Adds default attributes __var_x and __var_y if no coordinate exist

    if(typeof vars.var_x !== "string" && typeof vars.var_x === "function") {

      vars.all_data.forEach(function(d, i) {
        d.__var_x = vars.var_x(d, i, vars);
      });

      vars.var_x = "__var_x";

    }

    if(typeof vars.var_x === "undefined") {
      vars.var_x = "__var_x";
    }

    if(typeof vars.var_y !== "string" && typeof vars.var_y === "function") {

      vars.all_data.forEach(function(d, i) {
        d.__var_y = vars.var_y(d, i, vars);
      });

      vars.var_y = "__var_y";

    }

    if(typeof vars.var_y === "undefined") {
      vars.var_y = "__var_y";
    }

    // In case the chart type is a function
    if(typeof vars.type !== "string" && typeof vars.type === "function") {
      vars.type = vars.type(vars);
    }

    if(typeof vars.type === 'undefined') {
      vars.type = 'none';
    };

    // In case the current_time is set dynamically
    if(typeof vars.time.current_time === "function") {
      vars.time.current_time = vars.time.current_time(vars.data);
    }

    // In case the current_time is set dynamically
    if(typeof vars.time.parse === "undefined") {
      vars.time.parse = function(d) { return d; }
    }

    // Calculate vars.new_data which should contain two things
    // 1/ The list of all items (e.g. countries, products)
    // 2/ The metadata for each items
    if(vars.init || vars.refresh) {

      // Duplicate data to prevent mutation
      vars.new_data = JSON.parse(JSON.stringify(vars.all_data));

      // Creates default ids `__id` and `__value` for dataset without any id
      if(typeof vars.var_id === 'undefined' || typeof vars.all_data[0][vars.var_id] === 'undefined') {

        vars.new_data = vars.new_data.map(function(d, i) {

          if(typeof d !== 'object') {
            var e = {}
            e.__id = i;
            e.__value = d;
            d = e;
          }

          d.__id = i;
          return d;

        });

        vars.var_id = '__id';

        if(typeof vars.var_text === 'undefined') {
          vars.var_text = '__id';
        }

      }

      // If time filter parameter is set, then keep values for this time
      if(typeof vars.time.filter !== "undefined" && vars.time.filter.length > 0) {

        if(vars.dev) {
          console.log("[vars.time.filter]", vars.time.filter);
        }

        vars.new_data = vars.new_data.filter(function(d, i) {
          return vars.time.filter.indexOf(d[vars.time.var_time]) > -1;
        });

      }

      // If time filter interval is set, then keep values from this interval
      if(typeof vars.time.filter_interval != "undefined" && vars.time.filter_interval.length == 2) {

        if(vars.dev) {
          console.log("[vars.time.interval]", vars.time.filter_interval);
        }

        vars.new_data = vars.new_data.filter(function(d, i) {
          return (d[vars.time.var_time] >= vars.time.filter_interval[0]) && (d[vars.time.var_time] <= vars.time.filter_interval[1]);
        });

      }

      // Find unique values for various parameters
      vars.time.interval = d3.extent(vars.new_data, function(d) {
        return vars.time.parse(d[vars.time.var_time]);
      });

      // Note: none-parsed time values
      vars.time.points = vistk.utils.find_unique_values(vars.new_data, vars.time.var_time);

      // In case no temporal values, change the accessor
      if(vars.time.var_time === null || vars.type === 'treemap') {
        vars.accessor_data = function(d) { return d; }
      }

      var unique_data = [];

      var lookup_index = [];
      var lookup_size = 0;

      vars.lookup_index_time = [];
      var lookup_time_size = 0;

      vars.new_data.forEach(function(d, i) {

        var index = -1;

        // Creates items by grouping data
        if(typeof lookup_index[d[vars.var_id]] === 'undefined') {

          index = lookup_size;
          lookup_size++;

          lookup_index[d[vars.var_id]] = index;

          utils.init_item(d);

          if(vars.filter.indexOf(d[vars.var_group]) > -1) {
            d.__filtered = true;
          }

          if(vars.highlight.indexOf(d[vars.var_id]) > -1) {
            d.__highlighted = true;
          }

          if(vars.selection.indexOf(d[vars.var_id]) > -1) {
            d.__selected = true;
          }

          d.__redraw = true;

          d.__index = index;

          // Duplicate for metadata
          var dup = JSON.parse(JSON.stringify(d));
          dup.values = [];

          unique_data.push(dup);

        } else {

          index = lookup_index[d[vars.var_id]];

        }

        var v = {};
        v[vars.time.var_time] = d[vars.time.var_time];
        v[vars.var_y] = d[vars.var_y];
        v[vars.var_x] = d[vars.var_x];
        v[vars.var_color] = d[vars.var_color];
        v[vars.var_size] = d[vars.var_size];
        v[vars.var_text] = d[vars.var_text];
        v[vars.var_r] = d[vars.var_r];
        v[vars.var_share] = d[vars.var_share];
        v[vars.var_id] = d[vars.var_id];

        // If no time values then we should already all the data we need
       // if(vars.time.var_time !== null) {
          unique_data[index].values[d[vars.time.var_time]] = v;
       // }

      });

      vars.new_data = unique_data;

    }

    // Filter data by attribute
    // TODO: not sure we should remove data, but add an attribute instead would better
    if(vars.filter.length > 0) {

      if(vars.dev) {
        console.log("[vars.filter]", vars.filter);
      }

      vars.new_data = vars.new_data.filter(function(d) {
        // We don't keep values that are not in the vars.filter array
        return vars.filter.indexOf(d[vars.var_group]+"") > -1;
      });

    }

    // Aggregate data
    if(typeof vars.set['__aggregated'] !== 'undefined' && vars.refresh) {

      if(vars.dev) {
        console.log("[vars.aggregate]", vars.aggregate);
      }

      // Do the nesting by var_group
      // Should make sure it works for a generc dataset
      // Also for time or none-time attributes
      nested_data = d3.nest()
        .key(function(d) {
          return d[vars.var_group];
        })
        .rollup(function(leaves) {

          // Generates a new dataset with aggregated data
          var aggregation = {};

          // Name and id values are
          aggregation[vars.var_id] = 'agg_' + leaves[0][vars.var_group];
          aggregation[vars.var_text] = leaves[0][vars.var_group];
          aggregation[vars.var_group] = leaves[0][vars.var_group];

          // Quick fix in case var_x is an ordinal scale
          if(vars.var_x !== vars.var_id && vars.var_x !== vars.time.var_time && vars.var_x !== vars.var_group) {
            aggregation[vars.var_x] = d3.mean(leaves, function(d) {
              return d[vars.var_x];
            });
          } else {
            aggregation[vars.var_x] = leaves[0][vars.var_x];
          }

          if(vars.var_y !== vars.var_id && vars.var_y !== vars.time.var_time) {
            aggregation[vars.var_y] = d3.mean(leaves, function(d) {
              return d[vars.var_y];
            });
          } else {
            aggregation[vars.var_y] = leaves[0][vars.var_y];
          }

          aggregation[vars.var_r] = d3.sum(leaves, function(d) {
            return d[vars.var_r];
          });

          aggregation[vars.var_share] = d3.sum(leaves, function(d) {
            return d[vars.var_share];
          });

          aggregation.values = [];

          // Assuming all the time values are present in all items
          vars.time.points.forEach(function(time, i) {

            var d = {};

           // if(vars.var_x === vars.time.var_time) {
           //   d[vars.var_x] = leaves[0].values[i][vars.var_x];
           // } else {
           //   d[vars.var_x] = 0;
           // }

            // Init values
            d[vars.var_x] = leaves[0].values[time][vars.var_x];
            d[vars.var_y] = leaves[0].values[time][vars.var_y];
            d[vars.var_r] = leaves[0].values[time][vars.var_r];

            d[vars.var_share] = leaves[0].values[time][vars.var_share];
            d[vars.var_color] = leaves[0].values[time][vars.var_color];
            d[vars.var_size] = leaves[0].values[time][vars.var_size];
            d[vars.var_text] = leaves[0].values[time][vars.var_text];

            // Time var
            d[vars.time.var_time] = leaves[0].values[time][vars.time.var_time];

            // Should stay at the bottom to make sure it's not overriden
            d[vars.var_id] = 'agg_' + leaves[0].values[time][vars.var_id];

            d.__index = 'agg_' + leaves[0].values[time].__index;

            aggregation.values[time] = d;

            //return d;
          });

          // Assuming we only aggregate var_x, var_y, var_r
          leaves.forEach(function(d, i) {

            vars.time.points.forEach(function(time, i) {

              if(vars.var_x !== vars.time.var_time) {
                aggregation.values[time][vars.var_x] += d.values[time][vars.var_x];
              }

              aggregation.values[time][vars.var_y] += d.values[time][vars.var_y];
              aggregation.values[time][vars.var_r] += d.values[time][vars.var_r];

            });
          });

          utils.init_item(aggregation);

          // Set internal attributes specific to aggregate + force redraw
          aggregation.__aggregated = true;
          aggregation.__redraw = true;

          vars.columns.forEach(function(c) {

            if(c === vars.var_text || c === vars.var_group) {
              return;
            }

            aggregation[c] = d3.mean(leaves, function(d) {
              return d[c];
            });
          });

          return aggregation;
        })
        .entries(vars.new_data);

      // Transform key/value into values tab only
      if(typeof vars.set['__aggregated'] !== 'undefined' && vars.set['__aggregated']) {

        vars.new_data = vars.new_data.concat(nested_data.map(function(d) {
          return d.values;
        }));

      } else {

        vars.new_data = nested_data.map(function(d) { return d.values; });

      }

    }

    // Sorting the dataset
    if(typeof vars.var_sort !== "undefined" && vars.refresh) {

      if(vars.dev) {
         console.log("[updating sort]", vars.var_sort, vars.var_sort_asc, vars.user_vars)
      }

      if(typeof vars.var_sort_asc !== "undefined" && !vars.var_sort_asc) {
        vars.new_data = vars.new_data.sort(function(a, b) {
          if(typeof vars.accessor_data(a) !== 'undefined' && typeof vars.accessor_data(b) !== 'undefined')
            return d3.ascending(vars.accessor_data(a)[vars.var_sort], vars.accessor_data(b)[vars.var_sort]);
        });
      } else {
        vars.new_data = vars.new_data.sort(function(a, b) {
          if(typeof vars.accessor_data(a) !== 'undefined' && typeof vars.accessor_data(b) !== 'undefined')
            return d3.descending(vars.accessor_data(a)[vars.var_sort], vars.accessor_data(b)[vars.var_sort]);
        });
      }
    }

    vars.new_data = vars.new_data.filter(function(d) {

      // Making sure we re-draw highlighted items
      if(vars.highlight.indexOf(d[vars.var_id]) > -1) {
        d.__highlighted = true;
        d.__redraw = true;
      } else if(d.__highlighted) {
        d.__highlighted = false;
        d.__redraw = true;
      }

      return typeof vars.accessor_data(d) !== 'undefined' && typeof vars.accessor_data(d)[vars.var_id] !== 'undefined';
    });

    if(vars.redraw_all) {
      vars.new_data.forEach(function(d) { d.__redraw = true; });
    }

    vars.redraw_all = false;
<|endoftext|>


<commit_before>//todo
//  pageURL refURL protocol related functions
// forEachOnArray

var CONSTANTS = require("./constants.js");
var BID = require("./bid.js");
var bidManager = require("./bidManager.js");

var debugLogIsEnabled = false;
var typeArray = "Array";
var typeString = "String";
var typeFunction = "Function";
var typeNumber = "Number";
var toString = Object.prototype.toString;

function isA(object, testForType) {
	return toString.call(object) === "[object " + testForType + "]";
}

/* start-test-block */
exports.isA = isA;
/* end-test-block */

exports.isFunction = function (object) {
	return isA(object, typeFunction);
};

exports.isString = function (object) {
	return isA(object, typeString);
};

exports.isArray = function (object) {
	return isA(object, typeArray);
};

exports.isNumber = function(object) {
	return isA(object, typeNumber);
};

exports.isObject = function(object){
	return typeof object === "object" && object !== null;
};

exports.isOwnProperty = function(theObject, proertyName){
	if(theObject.hasOwnProperty){
		return theObject.hasOwnProperty(proertyName);
	}
	return false;
};

exports.isUndefined = function(object){
	return typeof object === "undefined";
};

exports.enableDebugLog = function(){
	debugLogIsEnabled = true;
};

//todo: move...
var constDebugInConsolePrependWith = "-------------------------";

exports.log = function(data){
	if( debugLogIsEnabled && console && this.isFunction(console.log) ){ // eslint-disable-line no-console
		if(this.isString(data)){
			console.log( (new Date()).getTime()+ " : " + constDebugInConsolePrependWith + data ); // eslint-disable-line no-console
		}else{
			console.log(data); // eslint-disable-line no-console
		}
	}
};

exports.getCurrentTimestampInMs = function(){
	var date = new Date();
	return date.getTime();
};

exports.getCurrentTimestamp = function(){
	var date = new Date();
	return Math.round( date.getTime()/1000 );
};

var utilGetIncrementalInteger = (function() {
	var count = 0;
	return function() {
		count++;
		return count;
	};
})();

exports.getUniqueIdentifierStr = function() {
	return utilGetIncrementalInteger() + Math.random().toString(16).substr(2);
};

exports.copyKeyValueObject = function(copyTo, copyFrom){
	if(this.isObject(copyTo) && this.isObject(copyFrom)){
		this.forEachOnObject(copyFrom, function(key, value){
			copyFrom[key] = this.isArray(value) ? value : [value];
			if(this.isOwnProperty(copyTo, key)){
				copyTo[key].push.apply(copyTo[key], value);
			}else{
				copyTo[key] = value;
			}
		});
	}
};

exports.protocol = "https://"; //todo need a set method
exports.pageURL = "http://abc.com/ljljl/abc"; //todo removed

exports.getIncrementalInteger = (function() {
	var count = 0;
	return function() {
		count++;
		return count;
	};
})();

exports.generateUUID = function(){
	var d = new Date().getTime(),
      // todo: this.pageURL ???
		url = decodeURIComponent(this.pageURL).toLowerCase().replace(/[^a-z,A-Z,0-9]/gi, ""),
		urlLength = url.length
		;

    //todo: uncomment it,  what abt performance
    //if(win.performance && this.isFunction(win.performance.now)){
    //    d += performance.now();
    //}

	var uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx-zzzzz".replace(/[xyz]/g, function(c) {
		var r = (d + Math.random()*16)%16 | 0;
		d = Math.floor(d/16);
		var op;
		switch(c){
		case "x":
			op = r;
			break;
		case "z":
			op = url[Math.floor(Math.random()*urlLength)];
			break;
		default:
			op = (r&0x3|0x8);
		}

		return op.toString(16);
	});

	return uuid;
};

var macroRegexFlag = macroRegexFlag;
var constCommonMacroForWidthRegExp = new RegExp(CONSTANTS.MACROS.WIDTH, macroRegexFlag);
var constCommonMacroForHeightRegExp = new RegExp(CONSTANTS.MACROS.HEIGHT, macroRegexFlag);
var constCommonMacroForAdUnitIDRegExp = new RegExp(CONSTANTS.MACROS.AD_UNIT_ID, macroRegexFlag);
var constCommonMacroForAdUnitIndexRegExp = new RegExp(CONSTANTS.MACROS.AD_UNIT_INDEX, macroRegexFlag);
var constCommonMacroForIntegerRegExp = new RegExp(CONSTANTS.MACROS.INTEGER, macroRegexFlag);
var constCommonMacroForDivRegExp = new RegExp(CONSTANTS.MACROS.DIV, macroRegexFlag);

exports.generateSlotNamesFromPattern = function(activeSlot, pattern){
	var slotNames = [],
		slotName,
		slotNamesObj = {},
		sizeArray,
		sizeArrayLength,
		i
		;

	if(this.isObject(activeSlot) && this.isFunction(activeSlot.getSizes)){
		sizeArray = activeSlot.getSizes();
		sizeArrayLength = sizeArray.length;
		if( sizeArrayLength > 0){
			for(i = 0; i < sizeArrayLength; i++){
				if(sizeArray[i][0] && sizeArray[i][1]){

					slotName = pattern;
					slotName = slotName.replace(constCommonMacroForAdUnitIDRegExp, activeSlot.getAdUnitID())
                    .replace(constCommonMacroForWidthRegExp, sizeArray[i][0])
                    .replace(constCommonMacroForHeightRegExp, sizeArray[i][1])
                    .replace(constCommonMacroForAdUnitIndexRegExp, activeSlot.getAdUnitIndex())
                    .replace(constCommonMacroForIntegerRegExp, this.getIncrementalInteger())
                    .replace(constCommonMacroForDivRegExp, activeSlot.getDivID());

					if(! this.isOwnProperty(slotNamesObj, slotName)){
						slotNamesObj[slotName] = "";
						slotNames.push(slotName);
					}
				}
			}
		}
	}

	return slotNames;
};

//todo: is it required ?
exports.checkMandatoryParams = function(object, keys, adapterID){
	var error = false,
		success = true
	;

	if(!object || !this.isObject(object) || this.isArray(object)){
		this.log(adapterID + "provided object is invalid.");
		return error;
	}

	if(!this.isArray(keys)){
		this.log(adapterID + "provided keys must be in an array.");
		return error;
	}

	var arrayLength = keys.length;
	if(arrayLength == 0){
		return success;
	}

	// can not change following for loop to this.forEachOnArray
	for(var i=0; i<arrayLength; i++){
		if(!this.isOwnProperty(object, keys[i])){
			this.log(adapterID + ": "+keys[i]+", mandatory parameter not present.");
			return error;
		}
	}

	return success;
};

exports.forEachGeneratedKey = function(adapterID, slotConfigMandatoryParams, activeSlots, keyGenerationPattern, keyLookupMap, handlerFunction, addZeroBids){
	var activeSlotsLength = activeSlots.length,
		i,
		j,
		generatedKeys,
		generatedKeysLength,
		kgpConsistsWidthAndHeight
		;

	if(activeSlotsLength > 0 && keyGenerationPattern.length > 3){
		kgpConsistsWidthAndHeight = keyGenerationPattern.indexOf(CONSTANTS.MACROS.WIDTH) >= 0 && keyGenerationPattern.indexOf(CONSTANTS.MACROS.HEIGHT) >= 0;
		for(i = 0; i < activeSlotsLength; i++){
			var activeSlot = activeSlots[i];
			generatedKeys = this.generateSlotNamesFromPattern( activeSlot, keyGenerationPattern );
			generatedKeysLength = generatedKeys.length;
			for(j = 0; j < generatedKeysLength; j++){
				var generatedKey = generatedKeys[j],
					keyConfig = null,
					callHandlerFunction = false,
					sizeArray = activeSlot.getSizes()
					;

				if(keyLookupMap == null){
					callHandlerFunction = true;
				}else{
					keyConfig = keyLookupMap[generatedKey];
					if(!keyConfig){
						this.log(adapterID+": "+generatedKey+CONSTANTS.MESSAGES.M8);
					}else if(!this.checkMandatoryParams(keyConfig, slotConfigMandatoryParams, adapterID)){
						this.log(adapterID+": "+generatedKey+CONSTANTS.MESSAGES.M9);
					}else{
						callHandlerFunction = true;
					}
				}

				if(callHandlerFunction){

					if(addZeroBids == true){
						var bid = BID.createBid(adapterID, generatedKey);
						bid.setDefaultBidStatus(1);
						bidManager.setBidFromBidder(activeSlot.getDivID(), bid);
					}

					handlerFunction(
						generatedKey,
						kgpConsistsWidthAndHeight,
						activeSlot,
						keyLookupMap ? keyLookupMap[generatedKey] : null,
						sizeArray[j][0],
						sizeArray[j][1]
					);
				}
			}
		}
	}
};

exports.resizeWindow = function(theDocument, width, height){
	if(height && width){
		try{
			var fr = theDocument.defaultView.frameElement;
			fr.width = width;
			fr.height = height;
		}catch(e){} // eslint-disable-line no-empty
	}
};

exports.writeIframe = function(theDocument, src, width, height, style){
	theDocument.write("<iframe"
    + " frameborder=\"0\" allowtransparency=\"true\" marginheight=\"0\" marginwidth=\"0\" scrolling=\"no\" width=\""
    + width  + "\" hspace=\"0\" vspace=\"0\" height=\""
    + height + "\""
    + (style ?  " style=\""+ style+"\"" : "" )
    + " src=\"" + src + "\""
    + "></ifr" + "ame>");
};

exports.displayCreative = function(theDocument, bid){
	this.resizeWindow(theDocument, bid.getWidth(), bid.getHeight());
	if(bid.getAdHtml()){
		theDocument.write(bid.getAdHtml());
	}else if(bid.getAdUrl()){
		this.writeIframe(theDocument, bid.getAdUrl(), bid.getWidth(), bid.getHeight(), "");
	}else{
		this.log("creative details are not found");
		this.log(bid);
	}
};

exports.getScreenWidth = function(win){
	var screenWidth = -1;
	win.innerHeight ? (screenWidth = win.innerWidth) : win.document && win.document.documentElement && win.document.documentElement.clientWidth ? (screenWidth = win.document.documentElement.clientWidth) : win.document.body && (screenWidth = win.document.body.clientWidth);
	return screenWidth;
};

exports.getScreenHeight = function(win){
	var screenHeight = -1;
	win.innerHeight ? (screenHeight = win.innerHeight) : win.document && win.document.documentElement && win.document.documentElement.clientHeight ? (screenHeight = win.document.documentElement.clientHeight) : win.document.body && (screenHeight = win.document.body.clientHeight);
	return screenHeight;
};

// todo: how about accepting array of arguments to be passed to callback function after key, value, arrayOfArguments
exports.forEachOnObject = function(theObject, callback){
	if(!this.isObject(theObject)){
		return;
	}

	if(!this.isFunction(callback)){
		return;
	}

	for(var key in theObject){
		if(this.isOwnProperty(theObject, key)){
			callback(key, theObject[key]);
		}
	}
};

exports.forEachOnArray = function(theArray, callback){
	if(!this.isArray(theArray)){
		return;
	}

	if(!this.isFunction(callback)){
		return;
	}

	for(var index=0, arrayLength= theArray.length; index<arrayLength; index++){
		callback(index, theArray[index]);
	}
};

exports.trim = function(s){
	if(!this.isString(s)){
		return s;
	}else{
		return s.replace(/^\s+/g,"").replace(/\s+$/g,"");
	}
};

exports.isIframe = function(theWindow){
	try{
		return theWindow.self !== theWindow.top;
	}catch(e){
		return false;
	}
};

exports.getProtocol = function(theWindow){
	if(theWindow.location.protocol ===  "https:"){
		return "https://";
	}
	return "http://";
};

exports.getPageURL = function(){ //theWindow (arg) // todo
	return "";
};

exports.findInString = function(theString, find){
	return theString.indexOf(find) >= 0;
};

exports.addHookOnFunction = function(theObject, useProto, functionName, newFunction){
	var callMethodOn = theObject;
	theObject = useProto ? theObject.__proto__ : theObject;
	if(this.isObject(theObject) && this.isFunction(theObject[functionName])){
		var originalFunction = theObject[functionName];
		theObject[functionName] = newFunction(callMethodOn, originalFunction);
	}else{
		this.log("in assignNewDefination: oldReference is not a function");
	}
};<commit_msg>a fix in util<commit_after>//todo
//  pageURL refURL protocol related functions
// forEachOnArray

var CONSTANTS = require("./constants.js");
var BID = require("./bid.js");
var bidManager = require("./bidManager.js");

var debugLogIsEnabled = false;
var typeArray = "Array";
var typeString = "String";
var typeFunction = "Function";
var typeNumber = "Number";
var toString = Object.prototype.toString;

function isA(object, testForType) {
	return toString.call(object) === "[object " + testForType + "]";
}

/* start-test-block */
exports.isA = isA;
/* end-test-block */

exports.isFunction = function (object) {
	return isA(object, typeFunction);
};

exports.isString = function (object) {
	return isA(object, typeString);
};

exports.isArray = function (object) {
	return isA(object, typeArray);
};

exports.isNumber = function(object) {
	return isA(object, typeNumber);
};

exports.isObject = function(object){
	return typeof object === "object" && object !== null;
};

exports.isOwnProperty = function(theObject, proertyName){
	if(theObject.hasOwnProperty){
		return theObject.hasOwnProperty(proertyName);
	}
	return false;
};

exports.isUndefined = function(object){
	return typeof object === "undefined";
};

exports.enableDebugLog = function(){
	debugLogIsEnabled = true;
};

//todo: move...
var constDebugInConsolePrependWith = "-------------------------";

exports.log = function(data){
	if( debugLogIsEnabled && console && this.isFunction(console.log) ){ // eslint-disable-line no-console
		if(this.isString(data)){
			console.log( (new Date()).getTime()+ " : " + constDebugInConsolePrependWith + data ); // eslint-disable-line no-console
		}else{
			console.log(data); // eslint-disable-line no-console
		}
	}
};

exports.getCurrentTimestampInMs = function(){
	var date = new Date();
	return date.getTime();
};

exports.getCurrentTimestamp = function(){
	var date = new Date();
	return Math.round( date.getTime()/1000 );
};

var utilGetIncrementalInteger = (function() {
	var count = 0;
	return function() {
		count++;
		return count;
	};
})();

exports.getUniqueIdentifierStr = function() {
	return utilGetIncrementalInteger() + Math.random().toString(16).substr(2);
};

exports.copyKeyValueObject = function(copyTo, copyFrom){
	if(this.isObject(copyTo) && this.isObject(copyFrom)){
		var utilRef = this;
		this.forEachOnObject(copyFrom, function(key, value){
			copyFrom[key] = utilRef.isArray(value) ? value : [value];
			if(utilRef.isOwnProperty(copyTo, key)){
				copyTo[key].push.apply(copyTo[key], value);
			}else{
				copyTo[key] = value;
			}
		});
	}
};

exports.protocol = "https://"; //todo need a set method
exports.pageURL = "http://abc.com/ljljl/abc"; //todo removed

exports.getIncrementalInteger = (function() {
	var count = 0;
	return function() {
		count++;
		return count;
	};
})();

exports.generateUUID = function(){
	var d = new Date().getTime(),
      // todo: this.pageURL ???
		url = decodeURIComponent(this.pageURL).toLowerCase().replace(/[^a-z,A-Z,0-9]/gi, ""),
		urlLength = url.length
		;

    //todo: uncomment it,  what abt performance
    //if(win.performance && this.isFunction(win.performance.now)){
    //    d += performance.now();
    //}

	var uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx-zzzzz".replace(/[xyz]/g, function(c) {
		var r = (d + Math.random()*16)%16 | 0;
		d = Math.floor(d/16);
		var op;
		switch(c){
		case "x":
			op = r;
			break;
		case "z":
			op = url[Math.floor(Math.random()*urlLength)];
			break;
		default:
			op = (r&0x3|0x8);
		}

		return op.toString(16);
	});

	return uuid;
};

var macroRegexFlag = macroRegexFlag;
var constCommonMacroForWidthRegExp = new RegExp(CONSTANTS.MACROS.WIDTH, macroRegexFlag);
var constCommonMacroForHeightRegExp = new RegExp(CONSTANTS.MACROS.HEIGHT, macroRegexFlag);
var constCommonMacroForAdUnitIDRegExp = new RegExp(CONSTANTS.MACROS.AD_UNIT_ID, macroRegexFlag);
var constCommonMacroForAdUnitIndexRegExp = new RegExp(CONSTANTS.MACROS.AD_UNIT_INDEX, macroRegexFlag);
var constCommonMacroForIntegerRegExp = new RegExp(CONSTANTS.MACROS.INTEGER, macroRegexFlag);
var constCommonMacroForDivRegExp = new RegExp(CONSTANTS.MACROS.DIV, macroRegexFlag);

exports.generateSlotNamesFromPattern = function(activeSlot, pattern){
	var slotNames = [],
		slotName,
		slotNamesObj = {},
		sizeArray,
		sizeArrayLength,
		i
		;

	if(this.isObject(activeSlot) && this.isFunction(activeSlot.getSizes)){
		sizeArray = activeSlot.getSizes();
		sizeArrayLength = sizeArray.length;
		if( sizeArrayLength > 0){
			for(i = 0; i < sizeArrayLength; i++){
				if(sizeArray[i][0] && sizeArray[i][1]){

					slotName = pattern;
					slotName = slotName.replace(constCommonMacroForAdUnitIDRegExp, activeSlot.getAdUnitID())
                    .replace(constCommonMacroForWidthRegExp, sizeArray[i][0])
                    .replace(constCommonMacroForHeightRegExp, sizeArray[i][1])
                    .replace(constCommonMacroForAdUnitIndexRegExp, activeSlot.getAdUnitIndex())
                    .replace(constCommonMacroForIntegerRegExp, this.getIncrementalInteger())
                    .replace(constCommonMacroForDivRegExp, activeSlot.getDivID());

					if(! this.isOwnProperty(slotNamesObj, slotName)){
						slotNamesObj[slotName] = "";
						slotNames.push(slotName);
					}
				}
			}
		}
	}

	return slotNames;
};

//todo: is it required ?
exports.checkMandatoryParams = function(object, keys, adapterID){
	var error = false,
		success = true
	;

	if(!object || !this.isObject(object) || this.isArray(object)){
		this.log(adapterID + "provided object is invalid.");
		return error;
	}

	if(!this.isArray(keys)){
		this.log(adapterID + "provided keys must be in an array.");
		return error;
	}

	var arrayLength = keys.length;
	if(arrayLength == 0){
		return success;
	}

	// can not change following for loop to this.forEachOnArray
	for(var i=0; i<arrayLength; i++){
		if(!this.isOwnProperty(object, keys[i])){
			this.log(adapterID + ": "+keys[i]+", mandatory parameter not present.");
			return error;
		}
	}

	return success;
};

exports.forEachGeneratedKey = function(adapterID, slotConfigMandatoryParams, activeSlots, keyGenerationPattern, keyLookupMap, handlerFunction, addZeroBids){
	var activeSlotsLength = activeSlots.length,
		i,
		j,
		generatedKeys,
		generatedKeysLength,
		kgpConsistsWidthAndHeight
		;

	if(activeSlotsLength > 0 && keyGenerationPattern.length > 3){
		kgpConsistsWidthAndHeight = keyGenerationPattern.indexOf(CONSTANTS.MACROS.WIDTH) >= 0 && keyGenerationPattern.indexOf(CONSTANTS.MACROS.HEIGHT) >= 0;
		for(i = 0; i < activeSlotsLength; i++){
			var activeSlot = activeSlots[i];
			generatedKeys = this.generateSlotNamesFromPattern( activeSlot, keyGenerationPattern );
			generatedKeysLength = generatedKeys.length;
			for(j = 0; j < generatedKeysLength; j++){
				var generatedKey = generatedKeys[j],
					keyConfig = null,
					callHandlerFunction = false,
					sizeArray = activeSlot.getSizes()
					;

				if(keyLookupMap == null){
					callHandlerFunction = true;
				}else{
					keyConfig = keyLookupMap[generatedKey];
					if(!keyConfig){
						this.log(adapterID+": "+generatedKey+CONSTANTS.MESSAGES.M8);
					}else if(!this.checkMandatoryParams(keyConfig, slotConfigMandatoryParams, adapterID)){
						this.log(adapterID+": "+generatedKey+CONSTANTS.MESSAGES.M9);
					}else{
						callHandlerFunction = true;
					}
				}

				if(callHandlerFunction){

					if(addZeroBids == true){
						var bid = BID.createBid(adapterID, generatedKey);
						bid.setDefaultBidStatus(1);
						bidManager.setBidFromBidder(activeSlot.getDivID(), bid);
					}

					handlerFunction(
						generatedKey,
						kgpConsistsWidthAndHeight,
						activeSlot,
						keyLookupMap ? keyLookupMap[generatedKey] : null,
						sizeArray[j][0],
						sizeArray[j][1]
					);
				}
			}
		}
	}
};

exports.resizeWindow = function(theDocument, width, height){
	if(height && width){
		try{
			var fr = theDocument.defaultView.frameElement;
			fr.width = width;
			fr.height = height;
		}catch(e){} // eslint-disable-line no-empty
	}
};

exports.writeIframe = function(theDocument, src, width, height, style){
	theDocument.write("<iframe"
    + " frameborder=\"0\" allowtransparency=\"true\" marginheight=\"0\" marginwidth=\"0\" scrolling=\"no\" width=\""
    + width  + "\" hspace=\"0\" vspace=\"0\" height=\""
    + height + "\""
    + (style ?  " style=\""+ style+"\"" : "" )
    + " src=\"" + src + "\""
    + "></ifr" + "ame>");
};

exports.displayCreative = function(theDocument, bid){
	this.resizeWindow(theDocument, bid.getWidth(), bid.getHeight());
	if(bid.getAdHtml()){
		theDocument.write(bid.getAdHtml());
	}else if(bid.getAdUrl()){
		this.writeIframe(theDocument, bid.getAdUrl(), bid.getWidth(), bid.getHeight(), "");
	}else{
		this.log("creative details are not found");
		this.log(bid);
	}
};

exports.getScreenWidth = function(win){
	var screenWidth = -1;
	win.innerHeight ? (screenWidth = win.innerWidth) : win.document && win.document.documentElement && win.document.documentElement.clientWidth ? (screenWidth = win.document.documentElement.clientWidth) : win.document.body && (screenWidth = win.document.body.clientWidth);
	return screenWidth;
};

exports.getScreenHeight = function(win){
	var screenHeight = -1;
	win.innerHeight ? (screenHeight = win.innerHeight) : win.document && win.document.documentElement && win.document.documentElement.clientHeight ? (screenHeight = win.document.documentElement.clientHeight) : win.document.body && (screenHeight = win.document.body.clientHeight);
	return screenHeight;
};

// todo: how about accepting array of arguments to be passed to callback function after key, value, arrayOfArguments
exports.forEachOnObject = function(theObject, callback){
	if(!this.isObject(theObject)){
		return;
	}

	if(!this.isFunction(callback)){
		return;
	}

	for(var key in theObject){
		if(this.isOwnProperty(theObject, key)){
			callback(key, theObject[key]);
		}
	}
};

exports.forEachOnArray = function(theArray, callback){
	if(!this.isArray(theArray)){
		return;
	}

	if(!this.isFunction(callback)){
		return;
	}

	for(var index=0, arrayLength= theArray.length; index<arrayLength; index++){
		callback(index, theArray[index]);
	}
};

exports.trim = function(s){
	if(!this.isString(s)){
		return s;
	}else{
		return s.replace(/^\s+/g,"").replace(/\s+$/g,"");
	}
};

exports.isIframe = function(theWindow){
	try{
		return theWindow.self !== theWindow.top;
	}catch(e){
		return false;
	}
};

exports.getProtocol = function(theWindow){
	if(theWindow.location.protocol ===  "https:"){
		return "https://";
	}
	return "http://";
};

exports.getPageURL = function(){ //theWindow (arg) // todo
	return "";
};

exports.findInString = function(theString, find){
	return theString.indexOf(find) >= 0;
};

exports.addHookOnFunction = function(theObject, useProto, functionName, newFunction){
	var callMethodOn = theObject;
	theObject = useProto ? theObject.__proto__ : theObject;
	if(this.isObject(theObject) && this.isFunction(theObject[functionName])){
		var originalFunction = theObject[functionName];
		theObject[functionName] = newFunction(callMethodOn, originalFunction);
	}else{
		this.log("in assignNewDefination: oldReference is not a function");
	}
};<|endoftext|>


<commit_before>const assert = require('assert');

const OtherProducts = arr => {
  let str = '';
  for (let i = 0; i < arr.length; i += 1) {
    let num = 1;
    for (let j = 0; j < arr.length; j += 1) {
      if (i !== j) {
        num *= arr[j];
      }
    }
    str += num;
    if (i !== arr.length - 1) {
      str += '-';
    }
  }
  return str;
};

const in1 = '1, 2, 3, 100'; // input
const expect1 = '600-300-200-6'; // output
const test1 = OtherProducts(in1);
assert(test1, expect1);
<commit_msg>prettier fix<commit_after>const assert = require('assert');

const OtherProducts = (arr) => {
  let str = '';
  for (let i = 0; i < arr.length; i += 1) {
    let num = 1;
    for (let j = 0; j < arr.length; j += 1) {
      if (i !== j) {
        num *= arr[j];
      }
    }
    str += num;
    if (i !== arr.length - 1) {
      str += '-';
    }
  }
  return str;
};

const in1 = '1, 2, 3, 100'; // input
const expect1 = '600-300-200-6'; // output
const test1 = OtherProducts(in1);
assert(test1, expect1);
<|endoftext|>


<commit_before>

var RJTK = (function(self,$){
	'use strict';
	self.dialog = {
		newDialog: function(options) {
			var $dlg = $("
",{'class': 'reveal-modal'}).appendTo('body');
			$dlg.html('×

');

			$dlg.on('rjtk:dialog:open',function(e){
				$dlg.reveal();
			});

			$dlg.on('rjtk:dialog:close',function(e){
				$dlg.trigger('reveal:close');
			});

			$dlg.on('reveal:closed.rjtk_dialog',function(e){
				$dlg.trigger('rjtk:dialog:closed');
			});

			$dlg.on('reveal:opened.rjtk_dialog', function(e) {
				$dlg.trigger('rjtk:dialog:opened');
			});

			$dlg.setContent = function(content) {
				$dlg.find('.reveal-modal-inner').html(content);
			};

			return $dlg;
		}
	};

	return self;
}(RJTK || {},jQuery));
<commit_msg>updated for foundation 4<commit_after>

var RJTK = (function(self,$){
	'use strict';
	self.dialog = {
		newDialog: function(options) {
			var $dlg = $("
",{'class': 'reveal-modal'}).appendTo('body');
			$dlg.html('×

');

			$dlg.on('rjtk:dialog:open',function(e){
				$dlg.foundation('reveal','open');
			});

			$dlg.on('rjtk:dialog:close',function(e){
				$dlg.trigger('reveal:close');
			});

			$dlg.on('reveal:closed.rjtk_dialog',function(e){
				$dlg.trigger('rjtk:dialog:closed');
			});

			$dlg.on('reveal:opened.rjtk_dialog', function(e) {
				$dlg.trigger('rjtk:dialog:opened');
			});

			$dlg.setContent = function(content) {
				$dlg.find('.reveal-modal-inner').html(content);
			};

			return $dlg;
		}
	};

	return self;
}(RJTK || {},jQuery));
<|endoftext|>


<commit_before>'use strict';

app.controller('party/profile', [
  '$scope', 'displayService', 'party', 'pageService','constantService',
  function ($scope, display, party, page, constants) {
    var getUsers = function(volumes){

      var users = {};

      users.sponsors = [];
      users.labGroupMembers = [];
      users.nonGroupAffiliates = [];
      users.otherCollaborators = [];

      _(volumes).pluck('access').flatten().uniq(function(i){
        return i.party.id;
      }).each(function(v){
        console.log("V: ", v);
        if(v.children > 0 ){
          users.sponsors.push(v);
        } else if(v.parents && v.parents.length) {
          users.labGroupMembers.push(v);
        } else if(v.parents && v.parents.length) {
          users.nonGroupAffiliates.push(v);
        } else {
          users.otherCollaborators.push(v);
        }

      }).value();
      // The "value()" call is to actually force the chain to work.

      console.log("Users: ", users);
      return users;
    };

    // This is a quick helper function to make sure that the isSelected
    // class is set to empty and to avoid repeating code.
    var unSetSelected = function(v){
      v.isSelected = '';
      if(v.v !== undefined){
        v.v = _.map(v.v, function(a){
          a.isSelected = '';
          return a;
        });
      }

      return v;
    };

    var unselectAll = function(){

      $scope.volumes.individual = _.map($scope.volumes.individual, unSetSelected);

      $scope.volumes.collaborator = _.map($scope.volumes.collaborator, unSetSelected);

      $scope.volumes.inherited = _.map($scope.volumes.inherited, unSetSelected);

      $scope.users.sponsors = _.map($scope.users.sponsors, unSetSelected);

      $scope.users.nonGroupAffiliates = _.map($scope.users.nonGroupAffiliates, unSetSelected);

      $scope.users.labGroupMembers = _.map($scope.users.labGroupMembers, unSetSelected);

      $scope.users.otherCollaborators = _.map($scope.users.otherCollaborators, unSetSelected);

    };

    $scope.clickVolume = function(volume) {

      unselectAll();
      volume.isSelected = 'volumeSelected';
      volume = _.flatten([volume.v || volume]);
      for(var k = 0; k < volume.length; k++){
        for(var i = 0; i < volume[k].access.length; i++){

          var j;

          for (j = 0; j < $scope.users.sponsors.length; j++){
            if($scope.users.sponsors[j].party.id === volume[k].access[i].party.id){
              $scope.users.sponsors[j].isSelected = 'userSelected';
            }
          }

          for (j = 0; j < $scope.users.labGroupMembers.length; j++) {
            if($scope.users.labGroupMembers[j].party.id === volume[k].access[i].party.id){
              $scope.users.labGroupMembers[j].isSelected = 'userSelected';
            }
          }

          for (j = 0; j < $scope.users.nonGroupAffiliates.length; j++) {
            if($scope.users.nonGroupAffiliates[j].party.id === volume[k].access[i].party.id){
              $scope.users.nonGroupAffiliates[j].isSelected = 'userSelected';
            }
          }

          for (j = 0; j < $scope.users.otherCollaborators.length; j++) {
            if($scope.users.otherCollaborators[j].party.id === volume[k].access[i].party.id){
              $scope.users.otherCollaborators[j].isSelected = 'userSelected';
            }
          }
        }
      }
    };

    // This should take in a user, then select volumes on each thing.
    $scope.clickUser = function(user){
      unselectAll();

      var i, j, k;

      for(i = 0; i < $scope.volumes.individual.length; i++){
        for(j = 0; j < $scope.volumes.individual[i].v.length; j++){
          for(k = 0; k < $scope.volumes.individual[i].v[j].access; k++){
            if($scope.volumes.individual[i].v[j].access[k].party.id == user.party.id){
              $scope.volumes.individual[i].v[j].isSelected = 'volumeSelected';
            }
          }
        }
      }

      for(i = 0; i < $scope.volumes.collaborator.length; i++){
        for(j = 0; j < $scope.volumes.collaborator[i].v.length; j++){
          for(k = 0; k < $scope.volumes.collaborator[i].v[j].access.length; k++){
            if($scope.volumes.collaborator[i].v[j].access[k].party.id == user.party.id) {
              $scope.volumes.collaborator[i].v[j].isSelected = 'volumeSelected';
            }
          }
        }
      }

      for(i = 0; i < $scope.volumes.inherited.length; i++){
        for(j = 0; j < $scope.volumes.inherited[i].v.length; j++){
          for(k = 0; k < $scope.volumes.inherited[i].v[j].access.length; k++){
            if($scope.volumes.inherited[i].v[j].access[k].party.id == user.party.id) {
              $scope.volumes.inherited[i].v[j].isSelected = 'volumeSelected';
            }
          }
        }
      }
    };

    var getParents = function(parents) {
      var tempParents = [];
      _.each(parents, function(p){
        if(p.member){
          var v = [];
          var tempThing = {
            p: p,
            v: v
          };
          tempParents.push(tempThing);
        }
      });
      return tempParents;
    };

    var getVolumes = function(volumes) {
      var tempVolumes = {};
      tempVolumes.individual = [];
      tempVolumes.collaborator = [];

      tempVolumes.inherited = getParents(party.parents);

      _.each(volumes, function(v){
        if(v.party && v.party.id && party.id){
          tempVolumes.individual.push({v: [v]});
        } else if(tempVolumes.isCollaborator){
          tempVolumes.collaborator.push({v: [v]});
        } else{
          for (var i=0;i<v.access.length;i++){
            for (var j=0;j<tempVolumes.inherited.length;j++){
              if (v.access[i].children && v.access[i].party.id === tempVolumes.inherited[j].p.party.id){
                tempVolumes.inherited[j].v.push(v);
                break;
              }
            }
          }
        }
      });
      return tempVolumes;
    };

    $scope.party = party;
    $scope.volumes = getVolumes(party.volumes);
    console.log("Volumes: ", $scope.volumes);
    $scope.users = getUsers(party.volumes);
    $scope.page = page;
    $scope.profile = page.$location.path() === '/profile';
    display.title = party.name;

    console.log($scope.volumes.inherited);
  }
]);
<commit_msg>Fix isSelected.<commit_after>'use strict';

app.controller('party/profile', [
  '$scope', 'displayService', 'party', 'pageService','constantService',
  function ($scope, display, party, page, constants) {
    var getUsers = function(volumes){

      var users = {};

      users.sponsors = [];
      users.labGroupMembers = [];
      users.nonGroupAffiliates = [];
      users.otherCollaborators = [];

      _(volumes).pluck('access').flatten().uniq(function(i){
        return i.party.id;
      }).each(function(v){
        console.log("V: ", v);
        if(v.children > 0 ){
          users.sponsors.push(v);
        } else if(v.parents && v.parents.length) {
          users.labGroupMembers.push(v);
        } else if(v.parents && v.parents.length) {
          users.nonGroupAffiliates.push(v);
        } else {
          users.otherCollaborators.push(v);
        }

      }).value();
      // The "value()" call is to actually force the chain to work.

      console.log("Users: ", users);
      return users;
    };

    // This is a quick helper function to make sure that the isSelected
    // class is set to empty and to avoid repeating code.
    var unSetSelected = function(v){
      v.isSelected = '';
      if(v.v !== undefined){
        v.v = _.map(v.v, function(a){
          a.isSelected = '';
          return a;
        });
      }

      return v;
    };

    var unselectAll = function(){

      $scope.volumes.individual = _.map($scope.volumes.individual, unSetSelected);

      $scope.volumes.collaborator = _.map($scope.volumes.collaborator, unSetSelected);

      $scope.volumes.inherited = _.map($scope.volumes.inherited, unSetSelected);

      $scope.users.sponsors = _.map($scope.users.sponsors, unSetSelected);

      $scope.users.nonGroupAffiliates = _.map($scope.users.nonGroupAffiliates, unSetSelected);

      $scope.users.labGroupMembers = _.map($scope.users.labGroupMembers, unSetSelected);

      $scope.users.otherCollaborators = _.map($scope.users.otherCollaborators, unSetSelected);

    };

    $scope.clickVolume = function(volume) {

      unselectAll();
      volume.isSelected = 'volumeSelected';
      volume = _.flatten([volume.v || volume]);
      for(var k = 0; k < volume.length; k++){
        for(var i = 0; i < volume[k].access.length; i++){

          var j;

          for (j = 0; j < $scope.users.sponsors.length; j++){
            if($scope.users.sponsors[j].party.id === volume[k].access[i].party.id){
              $scope.users.sponsors[j].isSelected = 'userSelected';
            }
          }

          for (j = 0; j < $scope.users.labGroupMembers.length; j++) {
            if($scope.users.labGroupMembers[j].party.id === volume[k].access[i].party.id){
              $scope.users.labGroupMembers[j].isSelected = 'userSelected';
            }
          }

          for (j = 0; j < $scope.users.nonGroupAffiliates.length; j++) {
            if($scope.users.nonGroupAffiliates[j].party.id === volume[k].access[i].party.id){
              $scope.users.nonGroupAffiliates[j].isSelected = 'userSelected';
            }
          }

          for (j = 0; j < $scope.users.otherCollaborators.length; j++) {
            if($scope.users.otherCollaborators[j].party.id === volume[k].access[i].party.id){
              $scope.users.otherCollaborators[j].isSelected = 'userSelected';
            }
          }
        }
      }
    };

    // This should take in a user, then select volumes on each thing.
    $scope.clickUser = function(user){
      unselectAll();

      var i, j, k;

      for(i = 0; i < $scope.volumes.individual.length; i++){
        for(j = 0; j < $scope.volumes.individual[i].v.length; j++){
          for(k = 0; k < $scope.volumes.individual[i].v[j].access.length; k++){
            if($scope.volumes.individual[i].v[j].access[k].party.id == user.party.id){
              $scope.volumes.individual[i].v[j].isSelected = 'volumeSelected';
              $scope.volumes.individual[i].isSelected = 'volumeSelected';
            }
          }
        }
      }

      for(i = 0; i < $scope.volumes.collaborator.length; i++){
        for(j = 0; j < $scope.volumes.collaborator[i].v.length; j++){
          for(k = 0; k < $scope.volumes.collaborator[i].v[j].access.length; k++){
            if($scope.volumes.collaborator[i].v[j].access[k].party.id == user.party.id) {
              $scope.volumes.collaborator[i].v[j].isSelected = 'volumeSelected';
              $scope.volumes.collaborator[i].isSelected = 'volumeSelected';
            }
          }
        }
      }

      for(i = 0; i < $scope.volumes.inherited.length; i++){
        for(j = 0; j < $scope.volumes.inherited[i].v.length; j++){
          for(k = 0; k < $scope.volumes.inherited[i].v[j].access.length; k++){
            if($scope.volumes.inherited[i].v[j].access[k].party.id == user.party.id) {
              $scope.volumes.inherited[i].v[j].isSelected = 'volumeSelected';
              $scope.volumes.inherited[i].isSelected = 'volumeSelected';
            }
          }
        }
      }
    };

    var getParents = function(parents) {
      var tempParents = [];
      _.each(parents, function(p){
        if(p.member){
          var v = [];
          var tempThing = {
            p: p,
            v: v
          };
          tempParents.push(tempThing);
        }
      });
      return tempParents;
    };

    var getVolumes = function(volumes) {
      var tempVolumes = {};
      tempVolumes.individual = [];
      tempVolumes.collaborator = [];

      tempVolumes.inherited = getParents(party.parents);

      _.each(volumes, function(v){
        if(!v.party){
          tempVolumes.individual.push({v: [v]});
        } else if(tempVolumes.isCollaborator){
          tempVolumes.collaborator.push({v: [v]});
        } else{
          for (var i=0;i<v.access.length;i++){
            for (var j=0;j<tempVolumes.inherited.length;j++){
              if (v.access[i].children && v.access[i].party.id === tempVolumes.inherited[j].p.party.id){
                tempVolumes.inherited[j].v.push(v);
                break;
              }
            }
          }
        }
      });
      return tempVolumes;
    };

    $scope.party = party;
    $scope.volumes = getVolumes(party.volumes);
    console.log("Volumes: ", $scope.volumes);
    $scope.users = getUsers(party.volumes);
    $scope.page = page;
    $scope.profile = page.$location.path() === '/profile';
    display.title = party.name;

    console.log($scope.volumes.inherited);
  }
]);
<|endoftext|>


<commit_before>function CanvasLayer (map) {
	var me = {};

	var minZoom = 4;
	var maxZoom = 20;

	var updateFunctions = [];

	var markers = [];

	me.setPoints = function (list) {
		markers = list;
		layoutLevels();
		redraw();
	}

	function redraw() {
		updateFunctions.forEach(function (func) { func() });
	}

	var canvasTiles = L.tileLayer.canvas();

	canvasTiles.drawTile = function (canvas, tilePoint, zoom) {
		var size = canvas.width;
		var ctx = canvas.getContext('2d');

		var zoomExp = Math.pow(2, zoom);
		var x0 = tilePoint.x*size;
		var y0 = tilePoint.y*size;
		var x1 = x0 + size;
		var y1 = y0 + size;

		var levelZoom = Math.min(maxZoom, Math.max(zoom, minZoom));

		var scale = Math.pow(2, zoom-levelZoom);
		var r = 3*scale;

		function drawTile () {
			markers.forEach(function (marker) {
				var point = marker.levelPosition[levelZoom];
				var x = point.x*scale;
				var y = point.y*scale;

				if (x + r < x0) return;
				if (x - r > x1) return;
				if (y + r < y0) return;
				if (y - r > y1) return;

				ctx.beginPath();
				ctx.arc(
					x - x0,
					y - y0,
					r, 0, Math.PI*2, false);
				ctx.fillStyle = marker.fillColor;
				ctx.fill();
				ctx.lineWidth = scale;
				ctx.strokeStyle = marker.strokeColor;
				ctx.stroke();
			})
		}

		drawTile();

		updateFunctions.push(drawTile);
	}

	function layoutLevels() {
		markers.forEach(function (marker) {
			marker.levelPosition = [];
		});

		markers.forEach(function (marker) {
			var p = map.project([marker.latitude, marker.longitude], maxZoom);
			marker.levelPosition[maxZoom] = { x0:p.x, y0:p.y, x:p.x, y:p.y }
		})

		layout(maxZoom);

		for (var zoom = maxZoom-1; zoom >= minZoom; zoom--) {
			markers.forEach(function (marker) {
				var p0 = map.project([marker.latitude, marker.longitude], zoom);
				var p = marker.levelPosition[zoom+1];
				marker.levelPosition[zoom] = {
					x0:p.x0/2,
					y0:p.y0/2,
					x: p0.x,
					y: p0.y
				};
			})
			layout(zoom);
		}

		function layout(zoom) {

		}
	}

	canvasTiles.addTo(map);

	return me;
}<commit_msg>public redraw function<commit_after>function CanvasLayer (map) {
	var me = {};

	var minZoom = 4;
	var maxZoom = 20;

	var updateFunctions = [];

	var markers = [];

	me.setPoints = function (list) {
		markers = list;
		layoutLevels();
		me.redraw();
	}

	me.redraw = function () {
		updateFunctions.forEach(function (func) { func() });
	}

	var canvasTiles = L.tileLayer.canvas();

	canvasTiles.drawTile = function (canvas, tilePoint, zoom) {
		var size = canvas.width;
		var ctx = canvas.getContext('2d');

		var zoomExp = Math.pow(2, zoom);
		var x0 = tilePoint.x*size;
		var y0 = tilePoint.y*size;
		var x1 = x0 + size;
		var y1 = y0 + size;

		var levelZoom = Math.min(maxZoom, Math.max(zoom, minZoom));

		var scale = Math.pow(2, zoom-levelZoom);
		var r = 3*scale;

		function drawTile () {
			markers.forEach(function (marker) {
				var point = marker.levelPosition[levelZoom];
				var x = point.x*scale;
				var y = point.y*scale;

				if (x + r < x0) return;
				if (x - r > x1) return;
				if (y + r < y0) return;
				if (y - r > y1) return;

				ctx.beginPath();
				ctx.arc(
					x - x0,
					y - y0,
					r, 0, Math.PI*2, false);
				ctx.fillStyle = marker.fillColor;
				ctx.fill();
				ctx.lineWidth = scale;
				ctx.strokeStyle = marker.strokeColor;
				ctx.stroke();
			})
		}

		drawTile();

		updateFunctions.push(drawTile);
	}

	function layoutLevels() {
		markers.forEach(function (marker) {
			marker.levelPosition = [];
		});

		markers.forEach(function (marker) {
			var p = map.project([marker.latitude, marker.longitude], maxZoom);
			marker.levelPosition[maxZoom] = { x0:p.x, y0:p.y, x:p.x, y:p.y }
		})

		layout(maxZoom);

		for (var zoom = maxZoom-1; zoom >= minZoom; zoom--) {
			markers.forEach(function (marker) {
				var p0 = map.project([marker.latitude, marker.longitude], zoom);
				var p = marker.levelPosition[zoom+1];
				marker.levelPosition[zoom] = {
					x0:p.x0/2,
					y0:p.y0/2,
					x: p0.x,
					y: p0.y
				};
			})
			layout(zoom);
		}

		function layout(zoom) {

		}
	}

	canvasTiles.addTo(map);

	return me;
}<|endoftext|>