<commit_before>import React, { Component, Fragment } from 'react'
import {
  ThemeProvider,
  Box,
  Button,
  Container,
  Flex,
  Heading,
  Link as A,
  Section
} from '@hackclub/design-system'
import Helmet from 'react-helmet'
import Link from 'gatsby-link'
import Nav from 'components/Nav'
import Footer from 'components/Footer'
import { camelCase, join, map, range } from 'lodash'

const Header = Section.extend`
  padding-top: 0 !important;
  background-image: url(//splattered.now.sh/${props => camelCase(props.name)});

  h1 {
    mix-blend-mode: screen;
    background-color: ${props => props.theme.colors.white};
    color: ${props => props.theme.colors.black};
    padding-left: ${props => props.theme.space[4]}px;
    padding-right: ${props => props.theme.space[4]}px;
    clip-path: polygon(4% 0%, 100% 0%, 96% 100%, 0% 100%);
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.16);
  }

  h2 {
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.16);
  }
`

const Body = Box.extend`
  color: ${props => props.theme.colors.black};
  font-size: ${props => props.theme.fontSizes[2]};

  a {
    color: ${props => props.theme.colors.info};
  }

  h1:first-child {
    display: none;
  }

  h1,
  h2 {
    padding-bottom: ${props => props.theme.space[2]}px;
    border-bottom: 1px solid ${props => props.theme.colors.smoke};
  }

  hr {
    border: 0;
    height: 4px;
    background-color: ${props => props.theme.colors.primary};
    max-width: ${props => props.theme.space[7]}px;
    margin: ${props => props.theme.space[4]}px auto;
    border-radius: 4px;
  }

  pre,
  code,
  kbd {
    font-family: ${props => props.theme.mono};
    background-color: ${props => props.theme.colors.smoke};
    color: ${props => props.theme.colors.black};
    font-size: inherit;
    br {
      display: none;
    }
  }
  del code {
    text-decoration: inherit;
  }

  code {
    border-radius: 2px;
    padding-left: ${props => props.theme.space[1]}px;
    padding-right: ${props => props.theme.space[1]}px;
  }

  pre {
    word-wrap: normal;
    padding: ${props => props.theme.space[3]}px;
    border-radius: ${props => props.theme.radius};
    > code {
      padding: 0;
      margin: 0;
      word-break: normal;
      white-space: pre;
      background: transparent;
      border: 0;
    }
  }

  .highlight {
    margin-bottom: ${props => props.theme.space[3]}px;

    pre {
      margin-bottom: 0;
      word-break: normal;
    }
  }

  .highlight pre,
  pre {
    overflow: auto;
    font-size: 85%;
    line-height: 1.45;
  }

  pre code,
  pre tt {
    display: inline;
    max-width: auto;
    padding: 0;
    margin: 0;
    overflow: visible;
    line-height: inherit;
    word-wrap: normal;
    background-color: transparent;
    border: 0;
  }

  ${props =>
    join(
      map(
        range(1, 6),
        level =>
          `h${level} { font-size: ${props.theme.fontSizes[6 - level]}px; }`
      ),
      ''
    )};
`

Button.home = Button.withComponent(Link)

export default ({
  data: { markdownRemark: { frontmatter: { name, description, group }, html } }
}) => {
  return (
    <ThemeProvider>
      <Helmet title={`${name} – Hack Club`} />
      <Header name={name}>
        <Nav />
        <Heading.h1 f={[5, 6]} mt={[3, 4]} mb={2} children={name} />
        <Heading.h2 f={[3, 4]} regular children={description} />
        <Button.home to="/workshops" mt={[3, 4]} mb={2} inverted>
          Get More Workshops
        </Button.home>
      </Header>
      <Container maxWidth={42} p={3}>
        <Body dangerouslySetInnerHTML={{ __html: html }} />
      </Container>
      <Footer />
    </ThemeProvider>
  )
}

export const pageQuery = graphql`
  query WorkshopBySlug($path: String!) {
    markdownRemark(fields: { slug: { eq: $path } }) {
      html
      frontmatter {
        name
        description
        group
      }
    }
  }
`
<commit_msg>Use OutlineButton on workshop page<commit_after>import React, { Component, Fragment } from 'react'
import {
  ThemeProvider,
  Box,
  OutlineButton,
  Container,
  Flex,
  Heading,
  Link as A,
  Section
} from '@hackclub/design-system'
import Helmet from 'react-helmet'
import Link from 'gatsby-link'
import Nav from 'components/Nav'
import Footer from 'components/Footer'
import { camelCase, join, map, range } from 'lodash'

const Header = Section.extend`
  padding-top: 0 !important;
  background-image: url(//splattered.now.sh/${props => camelCase(props.name)});

  h1 {
    mix-blend-mode: screen;
    background-color: ${props => props.theme.colors.white};
    color: ${props => props.theme.colors.black};
    padding-left: ${props => props.theme.space[4]}px;
    padding-right: ${props => props.theme.space[4]}px;
    clip-path: polygon(4% 0%, 100% 0%, 96% 100%, 0% 100%);
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.16);
  }

  h2 {
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.16);
  }
`

const Body = Box.extend`
  color: ${props => props.theme.colors.black};
  font-size: ${props => props.theme.fontSizes[2]};

  a {
    color: ${props => props.theme.colors.info};
  }

  h1:first-child {
    display: none;
  }

  h1,
  h2 {
    padding-bottom: ${props => props.theme.space[2]}px;
    border-bottom: 1px solid ${props => props.theme.colors.smoke};
  }

  hr {
    border: 0;
    height: 4px;
    background-color: ${props => props.theme.colors.primary};
    max-width: ${props => props.theme.space[7]}px;
    margin: ${props => props.theme.space[4]}px auto;
    border-radius: 4px;
  }

  pre,
  code,
  kbd {
    font-family: ${props => props.theme.mono};
    background-color: ${props => props.theme.colors.smoke};
    color: ${props => props.theme.colors.black};
    font-size: inherit;
    br {
      display: none;
    }
  }
  del code {
    text-decoration: inherit;
  }

  code {
    border-radius: 2px;
    padding-left: ${props => props.theme.space[1]}px;
    padding-right: ${props => props.theme.space[1]}px;
  }

  pre {
    word-wrap: normal;
    padding: ${props => props.theme.space[3]}px;
    border-radius: ${props => props.theme.radius};
    > code {
      padding: 0;
      margin: 0;
      word-break: normal;
      white-space: pre;
      background: transparent;
      border: 0;
    }
  }

  .highlight {
    margin-bottom: ${props => props.theme.space[3]}px;

    pre {
      margin-bottom: 0;
      word-break: normal;
    }
  }

  .highlight pre,
  pre {
    overflow: auto;
    font-size: 85%;
    line-height: 1.45;
  }

  pre code,
  pre tt {
    display: inline;
    max-width: auto;
    padding: 0;
    margin: 0;
    overflow: visible;
    line-height: inherit;
    word-wrap: normal;
    background-color: transparent;
    border: 0;
  }

  ${props =>
    join(
      map(
        range(1, 6),
        level =>
          `h${level} { font-size: ${props.theme.fontSizes[6 - level]}px; }`
      ),
      ''
    )};
`

OutlineButton.home = OutlineButton.withComponent(Link)

export default ({
  data: { markdownRemark: { frontmatter: { name, description, group }, html } }
}) => {
  return (
    <ThemeProvider>
      <Helmet title={`${name} – Hack Club`} />
      <Header name={name}>
        <Nav />
        <Heading.h1 f={[5, 6]} mt={[3, 4]} mb={2} children={name} />
        <Heading.h2 f={[3, 4]} regular children={description} />
        <OutlineButton.home to="/workshops" mt={[3, 4]} mb={2} color="white">
          Get More Workshops
        </OutlineButton.home>
      </Header>
      <Container maxWidth={42} p={3}>
        <Body dangerouslySetInnerHTML={{ __html: html }} />
      </Container>
      <Footer />
    </ThemeProvider>
  )
}

export const pageQuery = graphql`
  query WorkshopBySlug($path: String!) {
    markdownRemark(fields: { slug: { eq: $path } }) {
      html
      frontmatter {
        name
        description
        group
      }
    }
  }
`
<|endoftext|>


<commit_before>// auto-suggest docs:
// http://code.drewwilson.com/entry/autosuggest-jquery-plugin
// Changes to previous
// - prefill and ashtmlid in data-auto-suggest-config
define([
    "jquery",
    "../core/parser",
    "../registry",
    "jquery_autosuggest",
    "jquery_form"
], function($, Parser, registry) {
    var parser = new Parser("autosuggest");
    parser.add_argument("words", "");
    parser.add_argument("pre-fill");
    parser.add_argument("as-html-id");
    parser.add_argument("selected-value-prop", "name");
    parser.add_argument("search-obj-prop", "name");

    var _ = {
        name: "autosuggest",
        trigger: "input.pat-autosuggest",
        init: function($el, opts) {
            if ($el.length > 1)
                return $el.each(function() { _.init($(this), opts); });

            var cfg = _.parser.parse($el, opts);

            if ($el.attr("readonly"))
                cfg.startText = "";
            else
                cfg.startText = $el.attr("placeholder") || "Enter text";

            // jquery_autosuggest does not like the placeholder attr (yet)
            $el.attr("placeholder", "");

            if (cfg.preFill && (cfg.preFill.slice(0,1) === ","))
                cfg.preFill = cfg.preFill.slice(1);

            $el.on("keydown.pat-autosuggest", _.onKeyDown);

            var data = cfg.words.split(/\s*,\s*/).map(function(word) {
                return {value: word, name: word};
            });

            cfg.selectionAdded = function() {
                $el.next().trigger("change");
            };
            cfg.selectionRemoved = function(elem) {
                elem.remove();
                $el.next().trigger("change");
            };

            $el.on("change.pat-autosuggest", false);

            // XXX: See https://github.com/Patternslib/Patterns/issues/149
            if (cfg.asHtmlId !== undefined) {
                cfg.asHtmlID = cfg.asHtmlId;
            }
            $el.autoSuggest(data, cfg);

            return $el;
        },
        destroy: function($el) {
            $el.off(".pat-autosuggest");

            // XXX: destroy the jqueryPlugin, unfortunately it doesn't
            // support this as of now
        },

        parser: parser,

        onKeyDown: function(ev) {
            var $this = $(this);
            if (ev.which === 13) {
                var $results = $this.parents(".as-selections").next();
                ev.preventDefault();
                // skip ENTER->comma translation, if selection is active
                if (($results.is(":visible")) &&
                    ($results.find(".active").length > 0)) return;
                var newev = $.Event("keydown");
                newev.ctrlKey = false;
                newev.which = 188;
                newev.keyCode = 188;
                $this.trigger(newev);
            }
        }
    };
    registry.register(_);
    return _;
});

// jshint indent: 4, browser: true, jquery: true, quotmark: double
// vim: sw=4 expandtab
<commit_msg>Add a placeholder option that takes precedence over placeholder attr. #192<commit_after>// auto-suggest docs:
// http://code.drewwilson.com/entry/autosuggest-jquery-plugin
// Changes to previous
// - prefill and ashtmlid in data-auto-suggest-config
define([
    "jquery",
    "../core/parser",
    "../registry",
    "jquery_autosuggest",
    "jquery_form"
], function($, Parser, registry) {
    var parser = new Parser("autosuggest");
    parser.add_argument("words", "");
    parser.add_argument("pre-fill");
    parser.add_argument("as-html-id");
    parser.add_argument("selected-value-prop", "name");
    parser.add_argument("search-obj-prop", "name");
    parser.add_argument("placeholder", function($el) {
        var placeholder = $el.attr("placeholder") || "Enter text";
        // jquery_autosuggest does not like the placeholder attr (yet)
        $el.attr("placeholder", "");
        return placeholder;
    });

    var _ = {
        name: "autosuggest",
        trigger: "input.pat-autosuggest",
        init: function($el, opts) {
            if ($el.length > 1)
                return $el.each(function() { _.init($(this), opts); });

            var cfg = _.parser.parse($el, opts);

            if ($el.attr("readonly"))
                cfg.startText = "";
            else
                cfg.startText = cfg.placeholder;

            if (cfg.preFill && (cfg.preFill.slice(0,1) === ","))
                cfg.preFill = cfg.preFill.slice(1);

            $el.on("keydown.pat-autosuggest", _.onKeyDown);

            var data = cfg.words.split(/\s*,\s*/).map(function(word) {
                return {value: word, name: word};
            });

            cfg.selectionAdded = function() {
                $el.next().trigger("change");
            };
            cfg.selectionRemoved = function(elem) {
                elem.remove();
                $el.next().trigger("change");
            };

            $el.on("change.pat-autosuggest", false);

            // XXX: See https://github.com/Patternslib/Patterns/issues/149
            if (cfg.asHtmlId !== undefined) {
                cfg.asHtmlID = cfg.asHtmlId;
            }
            $el.autoSuggest(data, cfg);

            return $el;
        },
        destroy: function($el) {
            $el.off(".pat-autosuggest");

            // XXX: destroy the jqueryPlugin, unfortunately it doesn't
            // support this as of now
        },

        parser: parser,

        onKeyDown: function(ev) {
            var $this = $(this);
            if (ev.which === 13) {
                var $results = $this.parents(".as-selections").next();
                ev.preventDefault();
                // skip ENTER->comma translation, if selection is active
                if (($results.is(":visible")) &&
                    ($results.find(".active").length > 0)) return;
                var newev = $.Event("keydown");
                newev.ctrlKey = false;
                newev.which = 188;
                newev.keyCode = 188;
                $this.trigger(newev);
            }
        }
    };
    registry.register(_);
    return _;
});

// jshint indent: 4, browser: true, jquery: true, quotmark: double
// vim: sw=4 expandtab
<|endoftext|>


<commit_before>define([
    'require',
    '../lib/jquery',
    '../../lib/jquery.autoSuggest'
], function(require) {

    var init = function($el, opts) {
        // fetch words for auto-suggestion
        var $cfg = $el.parents('[data-auto-suggest-config]:first');
        var words = $cfg.data('auto-suggest-config').split(':')[1].split(/\s*,\s*/);
        var data = words.map(function(word) {
            return {value: word, name: word};
        });
        $el.autoSuggest(
            data,
            {
                selectedValueProp: "name",
                searchObjProp: "name"
            }
        );
    };

    var pattern = {
        markup_trigger: "input.auto-suggest",
        initialised_class: "auto-suggest",
        register_jquery_plugin: false,
        init: init
    };

    return pattern;
});
<commit_msg>deal with missing config<commit_after>define([
    'require',
    '../lib/jquery',
    '../../lib/jquery.autoSuggest'
], function(require) {

    var init = function($el, opts) {
        // fetch words for auto-suggestion
        var $cfg = $el.parents('[data-auto-suggest-config]:first');

        // XXX: do this properly
        var words = (($cfg.data('auto-suggest-config') || '')
                     .split(':')[1] || '').split(/\s*,\s*/);
        var data = words.map(function(word) {
            return {value: word, name: word};
        });
        $el.autoSuggest(
            data,
            {
                selectedValueProp: "name",
                searchObjProp: "name"
            }
        );
    };

    var pattern = {
        markup_trigger: "input.auto-suggest",
        initialised_class: "auto-suggest",
        register_jquery_plugin: false,
        init: init
    };

    return pattern;
});
<|endoftext|>


<commit_before>/**
 * @author Mat Groves http://matgroves.com/ @Doormat23
 */

/**
 * A Text Object will create a line(s) of text using bitmap font. To split a line you can use "\n", "\r" or "\r\n"
 * You can generate the fnt files using
 * http://www.angelcode.com/products/bmfont/ for windows or
 * http://www.bmglyph.com/ for mac.
 * @class BitmapText
 * @extends DisplayObjectContainer
 * @constructor
 * @param {String} text The copy that you would like the text to display
 * @param {Object} style The style parameters
 * @param {String} style.font The size (optional) and bitmap font id (required) eq "Arial" or "20px Arial" (must have loaded previously)
 * @param {String} [style.align="left"] An alignment of the multiline text ("left", "center" or "right")
 */
PIXI.BitmapText = function(text, style)
{
    PIXI.DisplayObjectContainer.call(this);

    this.setText(text);
    this.setStyle(style);
    this.updateText();
    this.dirty = false

};

// constructor
PIXI.BitmapText.constructor = PIXI.BitmapText;
PIXI.BitmapText.prototype = Object.create(PIXI.DisplayObjectContainer.prototype);

/**
 * Set the copy for the text object
 * @method setText
 * @param {String} text The copy that you would like the text to display
 */
PIXI.BitmapText.prototype.setText = function(text)
{
    this.text = text || " ";
    this.dirty = true;
};

/**
 * Set the style of the text
 * @method setStyle
 * @param {Object} style The style parameters
 * @param {String} style.font The size (optional) and bitmap font id (required) eq "Arial" or "20px Arial" (must have loaded previously)
 * @param {String} [style.align="left"] An alignment of the multiline text ("left", "center" or "right")
 */
PIXI.BitmapText.prototype.setStyle = function(style)
{
    style = style || {};
    style.align = style.align || "left";
    this.style = style;

    var font = style.font.split(" ");
    this.fontName = font[font.length - 1];
    this.fontSize = font.length >= 2 ? parseInt(font[font.length - 2], 10) : PIXI.BitmapText.fonts[this.fontName].size;

    this.dirty = true;
};

/**
 * Renders text
 * @private
 */
PIXI.BitmapText.prototype.updateText = function()
{
    var data = PIXI.BitmapText.fonts[this.fontName];
    var pos = new PIXI.Point();
    var prevCharCode = null;
    var chars = [];
    var maxLineWidth = 0;
    var lineWidths = [];
    var line = 0;
    var scale = this.fontSize / data.size;
    for(var i = 0; i < this.text.length; i++)
    {
        var charCode = this.text.charCodeAt(i);
        if(/(?:\r\n|\r|\n)/.test(this.text.charAt(i)))
        {
            lineWidths.push(pos.x);
            maxLineWidth = Math.max(maxLineWidth, pos.x);
            line++;

            pos.x = 0;
            pos.y += data.lineHeight;
            prevCharCode = null;
            continue;
        }

        var charData = data.chars[charCode];
        if(!charData) continue;

        if(prevCharCode && charData[prevCharCode])
        {
           pos.x += charData.kerning[prevCharCode];
        }
        chars.push({texture:charData.texture, line: line, charCode: charCode, position: new PIXI.Point(pos.x + charData.xOffset, pos.y + charData.yOffset)});
        pos.x += charData.xAdvance;

        prevCharCode = charCode;
    }

    lineWidths.push(pos.x);
    maxLineWidth = Math.max(maxLineWidth, pos.x);

    var lineAlignOffsets = [];
    for(i = 0; i <= line; i++)
    {
        var alignOffset = 0;
        if(this.style.align == "right")
        {
            alignOffset = maxLineWidth - lineWidths[i];
        }
        else if(this.style.align == "center")
        {
            alignOffset = (maxLineWidth - lineWidths[i]) / 2;
        }
        lineAlignOffsets.push(alignOffset);
    }

    for(i = 0; i < chars.length; i++)
    {
        var char = new PIXI.Sprite(chars[i].texture)//PIXI.Sprite.fromFrame(chars[i].charCode);
        char.position.x = (chars[i].position.x + lineAlignOffsets[chars[i].line]) * scale;
        char.position.y = chars[i].position.y * scale;
        char.scale.x = char.scale.y = scale;
        this.addChild(char);
    }

    this.width = pos.x * scale;
    this.height = (pos.y + data.lineHeight) * scale;
};

/**
 * @private
 */
PIXI.BitmapText.prototype.updateTransform = function()
{
	if(this.dirty)
	{
        while(this.children.length > 0)
        {
            this.removeChild(this.getChildAt(0));
        }
        this.updateText();

        this.dirty = false;
	}

	PIXI.DisplayObjectContainer.prototype.updateTransform.call(this);
};

PIXI.BitmapText.fonts = {};<commit_msg>use a different name than char, which is reserved. Fixes #177<commit_after>/**
 * @author Mat Groves http://matgroves.com/ @Doormat23
 */

/**
 * A Text Object will create a line(s) of text using bitmap font. To split a line you can use "\n", "\r" or "\r\n"
 * You can generate the fnt files using
 * http://www.angelcode.com/products/bmfont/ for windows or
 * http://www.bmglyph.com/ for mac.
 * @class BitmapText
 * @extends DisplayObjectContainer
 * @constructor
 * @param {String} text The copy that you would like the text to display
 * @param {Object} style The style parameters
 * @param {String} style.font The size (optional) and bitmap font id (required) eq "Arial" or "20px Arial" (must have loaded previously)
 * @param {String} [style.align="left"] An alignment of the multiline text ("left", "center" or "right")
 */
PIXI.BitmapText = function(text, style)
{
    PIXI.DisplayObjectContainer.call(this);

    this.setText(text);
    this.setStyle(style);
    this.updateText();
    this.dirty = false

};

// constructor
PIXI.BitmapText.constructor = PIXI.BitmapText;
PIXI.BitmapText.prototype = Object.create(PIXI.DisplayObjectContainer.prototype);

/**
 * Set the copy for the text object
 * @method setText
 * @param {String} text The copy that you would like the text to display
 */
PIXI.BitmapText.prototype.setText = function(text)
{
    this.text = text || " ";
    this.dirty = true;
};

/**
 * Set the style of the text
 * @method setStyle
 * @param {Object} style The style parameters
 * @param {String} style.font The size (optional) and bitmap font id (required) eq "Arial" or "20px Arial" (must have loaded previously)
 * @param {String} [style.align="left"] An alignment of the multiline text ("left", "center" or "right")
 */
PIXI.BitmapText.prototype.setStyle = function(style)
{
    style = style || {};
    style.align = style.align || "left";
    this.style = style;

    var font = style.font.split(" ");
    this.fontName = font[font.length - 1];
    this.fontSize = font.length >= 2 ? parseInt(font[font.length - 2], 10) : PIXI.BitmapText.fonts[this.fontName].size;

    this.dirty = true;
};

/**
 * Renders text
 * @private
 */
PIXI.BitmapText.prototype.updateText = function()
{
    var data = PIXI.BitmapText.fonts[this.fontName];
    var pos = new PIXI.Point();
    var prevCharCode = null;
    var chars = [];
    var maxLineWidth = 0;
    var lineWidths = [];
    var line = 0;
    var scale = this.fontSize / data.size;
    for(var i = 0; i < this.text.length; i++)
    {
        var charCode = this.text.charCodeAt(i);
        if(/(?:\r\n|\r|\n)/.test(this.text.charAt(i)))
        {
            lineWidths.push(pos.x);
            maxLineWidth = Math.max(maxLineWidth, pos.x);
            line++;

            pos.x = 0;
            pos.y += data.lineHeight;
            prevCharCode = null;
            continue;
        }

        var charData = data.chars[charCode];
        if(!charData) continue;

        if(prevCharCode && charData[prevCharCode])
        {
           pos.x += charData.kerning[prevCharCode];
        }
        chars.push({texture:charData.texture, line: line, charCode: charCode, position: new PIXI.Point(pos.x + charData.xOffset, pos.y + charData.yOffset)});
        pos.x += charData.xAdvance;

        prevCharCode = charCode;
    }

    lineWidths.push(pos.x);
    maxLineWidth = Math.max(maxLineWidth, pos.x);

    var lineAlignOffsets = [];
    for(i = 0; i <= line; i++)
    {
        var alignOffset = 0;
        if(this.style.align == "right")
        {
            alignOffset = maxLineWidth - lineWidths[i];
        }
        else if(this.style.align == "center")
        {
            alignOffset = (maxLineWidth - lineWidths[i]) / 2;
        }
        lineAlignOffsets.push(alignOffset);
    }

    for(i = 0; i < chars.length; i++)
    {
        var c = new PIXI.Sprite(chars[i].texture)//PIXI.Sprite.fromFrame(chars[i].charCode);
        c.position.x = (chars[i].position.x + lineAlignOffsets[chars[i].line]) * scale;
        c.position.y = chars[i].position.y * scale;
        c.scale.x = c.scale.y = scale;
        this.addChild(c);
    }

    this.width = pos.x * scale;
    this.height = (pos.y + data.lineHeight) * scale;
};

/**
 * @private
 */
PIXI.BitmapText.prototype.updateTransform = function()
{
	if(this.dirty)
	{
        while(this.children.length > 0)
        {
            this.removeChild(this.getChildAt(0));
        }
        this.updateText();

        this.dirty = false;
	}

	PIXI.DisplayObjectContainer.prototype.updateTransform.call(this);
};

PIXI.BitmapText.fonts = {};<|endoftext|>


<commit_before>/*
 *
 */
'use strict';
class Executor {
    constructor(block, entity, code) {
        this.scope = new Entry.Scope(block, this);
        this.isUpdateTime = 0;
        this.entity = entity;
        this.code = code;
        this._callStack = [];
        this.register = {};
        this.paused = false;
        this.parentExecutor = null;
        this.valueMap = {};
        this.valueState = {};
        this.id = Entry.Utils.generateId();
    }

    execute(isFromOrigin) {
        if (Entry.isTurbo && !this.isUpdateTime) {
            this.isUpdateTime = performance.now();
        }
        if (this.isEnd()) {
            return;
        }

        const executedBlocks = [];
        const promises = [];
        if (isFromOrigin) {
            Entry.callStackLength = 0;
        }

        const entity = this.entity;

        while (true) {
            let returnVal = null;
            executedBlocks.push(this.scope.block);

            try {
                const schema = this.scope.block.getSchema();
                if (schema && Entry.skeleton[schema.skeleton].executable) {
                    Entry.dispatchEvent('blockExecute', this.scope.block && this.scope.block.view);
                    returnVal = this.scope.run(entity);
                    this.scope.key = Entry.generateHash();
                }
            } catch (e) {
                if (e.name === 'AsyncError') {
                    returnVal = Entry.STATIC.BREAK;
                } else if (e.name === 'IncompatibleError') {
                    Entry.Utils.stopProjectWithToast(this.scope, 'IncompatibleError', e);
                } else if (this.isFuncExecutor) {
                    //function executor
                    throw e;
                } else {
                    Entry.Utils.stopProjectWithToast(this.scope, undefined, e);
                }
            }

            //executor can be ended after block function call
            if (this.isEnd()) {
                return executedBlocks;
            }

            if (returnVal instanceof Promise) {
                console.log('promise');
                promises.push(returnVal);
                this.paused = true;
                returnVal
                    .then((returnVal) => {
                        this.valueMap = {};
                        this.valueState = {};
                        this.paused = false;
                        if (returnVal === Entry.STATIC.CONTINUE) {
                            return;
                        }
                        if (this.scope.block && Entry.engine.isState('run')) {
                            this.scope = new Entry.Scope(this.scope.block.getNextBlock(), this);
                        }
                        if (this.scope.block === null && this._callStack.length) {
                            const oldScope = this.scope;
                            this.scope = this._callStack.pop();
                            if (this.scope.isLooped !== oldScope.isLooped) {
                                this.isLooped = true;
                            }
                        }
                    })
                    .catch((e) => {
                        this.paused = false;
                        if (e.name === 'AsyncError') {
                            returnVal = Entry.STATIC.BREAK;
                        } else if (e.name === 'IncompatibleError') {
                            Entry.Utils.stopProjectWithToast(this.scope, 'IncompatibleError', e);
                        } else if (this.isFuncExecutor) {
                            throw e;
                        } else {
                            Entry.Utils.stopProjectWithToast(this.scope, undefined, e);
                        }
                    });
                break;
            } else if (
                returnVal === undefined ||
                returnVal === null ||
                returnVal === Entry.STATIC.PASS
            ) {
                this.scope = new Entry.Scope(this.scope.block.getNextBlock(), this);
                this.valueMap = {};
                this.valueState = {};
                if (this.scope.block === null) {
                    if (this._callStack.length) {
                        const oldScope = this.scope;
                        this.scope = this._callStack.pop();
                        if (this.scope.isLooped !== oldScope.isLooped) {
                            this.isLooped = true;
                            break;
                        }
                    } else {
                        break;
                    }
                }
            } else if (returnVal === Entry.STATIC.CONTINUE) {
                this.valueMap = {};
                this.valueState = {};
            } else if (returnVal === this.scope) {
                this.valueMap = {};
                this.valueState = {};
                break;
            } else if (returnVal === Entry.STATIC.BREAK) {
                break;
            }
        }
        return { promises, blocks: executedBlocks };
    }

    checkExecutorError(error) {
        if (error.name === 'AsyncError') {
            return Entry.STATIC.BREAK;
        } else if (this.isFuncExecutor) {
            throw error;
        } else {
            Entry.Utils.stopProjectWithToast(this.scope, undefined, error);
        }
    }

    checkExecutorResult(returnVal) {
        if (returnVal === undefined || returnVal === null || returnVal === Entry.STATIC.PASS) {
            this.scope = new Entry.Scope(this.scope.block.getNextBlock(), this);
            this.valueMap = {};
            this.valueState = {};
            if (this.scope.block === null) {
                if (this._callStack.length) {
                    const oldScope = this.scope;
                    this.scope = this._callStack.pop();
                    if (this.scope.isLooped !== oldScope.isLooped) {
                        this.isLooped = true;
                        return true;
                    }
                } else {
                    return true;
                }
            }
        } else if (returnVal === Entry.STATIC.CONTINUE) {
            this.valueMap = {};
            this.valueState = {};
        } else if (returnVal === this.scope) {
            this.valueMap = {};
            this.valueState = {};
            return true;
        } else if (returnVal === Entry.STATIC.BREAK) {
            return true;
        }
    }

    stepInto(thread) {
        if (!(thread instanceof Entry.Thread)) {
            console.error('Must step in to thread');
        }

        const block = thread.getFirstBlock();
        if (!block) {
            return Entry.STATIC.BREAK;
        }

        this._callStack.push(this.scope);

        this.scope = new Entry.Scope(block, this);
        return Entry.STATIC.CONTINUE;
    }

    break() {
        if (this._callStack.length) {
            this.scope = this._callStack.pop();
        }
        return Entry.STATIC.PASS;
    }

    breakLoop() {
        if (this._callStack.length) {
            this.scope = this._callStack.pop();
        }
        while (this._callStack.length) {
            const schema = Entry.block[this.scope.block.type];
            if (schema.class === 'repeat') {
                break;
            }
            this.scope = this._callStack.pop();
        }
        return Entry.STATIC.PASS;
    }

    end() {
        Entry.dispatchEvent('blockExecuteEnd', this.scope.block && this.scope.block.view);
        this.scope.block = null;
    }

    isPause() {
        return this.paused;
    }

    isEnd() {
        return this.scope.block === null;
    }
}

Entry.Executor = Executor;
<commit_msg>remove console.log<commit_after>/*
 *
 */
'use strict';
class Executor {
    constructor(block, entity, code) {
        this.scope = new Entry.Scope(block, this);
        this.isUpdateTime = 0;
        this.entity = entity;
        this.code = code;
        this._callStack = [];
        this.register = {};
        this.paused = false;
        this.parentExecutor = null;
        this.valueMap = {};
        this.valueState = {};
        this.id = Entry.Utils.generateId();
    }

    execute(isFromOrigin) {
        if (Entry.isTurbo && !this.isUpdateTime) {
            this.isUpdateTime = performance.now();
        }
        if (this.isEnd()) {
            return;
        }

        const executedBlocks = [];
        const promises = [];
        if (isFromOrigin) {
            Entry.callStackLength = 0;
        }

        const entity = this.entity;

        while (true) {
            let returnVal = null;
            executedBlocks.push(this.scope.block);

            try {
                const schema = this.scope.block.getSchema();
                if (schema && Entry.skeleton[schema.skeleton].executable) {
                    Entry.dispatchEvent('blockExecute', this.scope.block && this.scope.block.view);
                    returnVal = this.scope.run(entity);
                    this.scope.key = Entry.generateHash();
                }
            } catch (e) {
                if (e.name === 'AsyncError') {
                    returnVal = Entry.STATIC.BREAK;
                } else if (e.name === 'IncompatibleError') {
                    Entry.Utils.stopProjectWithToast(this.scope, 'IncompatibleError', e);
                } else if (this.isFuncExecutor) {
                    //function executor
                    throw e;
                } else {
                    Entry.Utils.stopProjectWithToast(this.scope, undefined, e);
                }
            }

            //executor can be ended after block function call
            if (this.isEnd()) {
                return executedBlocks;
            }

            if (returnVal instanceof Promise) {
                promises.push(returnVal);
                this.paused = true;
                returnVal
                    .then((returnVal) => {
                        this.valueMap = {};
                        this.valueState = {};
                        this.paused = false;
                        if (returnVal === Entry.STATIC.CONTINUE) {
                            return;
                        }
                        if (this.scope.block && Entry.engine.isState('run')) {
                            this.scope = new Entry.Scope(this.scope.block.getNextBlock(), this);
                        }
                        if (this.scope.block === null && this._callStack.length) {
                            const oldScope = this.scope;
                            this.scope = this._callStack.pop();
                            if (this.scope.isLooped !== oldScope.isLooped) {
                                this.isLooped = true;
                            }
                        }
                    })
                    .catch((e) => {
                        this.paused = false;
                        if (e.name === 'AsyncError') {
                            returnVal = Entry.STATIC.BREAK;
                        } else if (e.name === 'IncompatibleError') {
                            Entry.Utils.stopProjectWithToast(this.scope, 'IncompatibleError', e);
                        } else if (this.isFuncExecutor) {
                            throw e;
                        } else {
                            Entry.Utils.stopProjectWithToast(this.scope, undefined, e);
                        }
                    });
                break;
            } else if (
                returnVal === undefined ||
                returnVal === null ||
                returnVal === Entry.STATIC.PASS
            ) {
                this.scope = new Entry.Scope(this.scope.block.getNextBlock(), this);
                this.valueMap = {};
                this.valueState = {};
                if (this.scope.block === null) {
                    if (this._callStack.length) {
                        const oldScope = this.scope;
                        this.scope = this._callStack.pop();
                        if (this.scope.isLooped !== oldScope.isLooped) {
                            this.isLooped = true;
                            break;
                        }
                    } else {
                        break;
                    }
                }
            } else if (returnVal === Entry.STATIC.CONTINUE) {
                this.valueMap = {};
                this.valueState = {};
            } else if (returnVal === this.scope) {
                this.valueMap = {};
                this.valueState = {};
                break;
            } else if (returnVal === Entry.STATIC.BREAK) {
                break;
            }
        }
        return { promises, blocks: executedBlocks };
    }

    checkExecutorError(error) {
        if (error.name === 'AsyncError') {
            return Entry.STATIC.BREAK;
        } else if (this.isFuncExecutor) {
            throw error;
        } else {
            Entry.Utils.stopProjectWithToast(this.scope, undefined, error);
        }
    }

    checkExecutorResult(returnVal) {
        if (returnVal === undefined || returnVal === null || returnVal === Entry.STATIC.PASS) {
            this.scope = new Entry.Scope(this.scope.block.getNextBlock(), this);
            this.valueMap = {};
            this.valueState = {};
            if (this.scope.block === null) {
                if (this._callStack.length) {
                    const oldScope = this.scope;
                    this.scope = this._callStack.pop();
                    if (this.scope.isLooped !== oldScope.isLooped) {
                        this.isLooped = true;
                        return true;
                    }
                } else {
                    return true;
                }
            }
        } else if (returnVal === Entry.STATIC.CONTINUE) {
            this.valueMap = {};
            this.valueState = {};
        } else if (returnVal === this.scope) {
            this.valueMap = {};
            this.valueState = {};
            return true;
        } else if (returnVal === Entry.STATIC.BREAK) {
            return true;
        }
    }

    stepInto(thread) {
        if (!(thread instanceof Entry.Thread)) {
            console.error('Must step in to thread');
        }

        const block = thread.getFirstBlock();
        if (!block) {
            return Entry.STATIC.BREAK;
        }

        this._callStack.push(this.scope);

        this.scope = new Entry.Scope(block, this);
        return Entry.STATIC.CONTINUE;
    }

    break() {
        if (this._callStack.length) {
            this.scope = this._callStack.pop();
        }
        return Entry.STATIC.PASS;
    }

    breakLoop() {
        if (this._callStack.length) {
            this.scope = this._callStack.pop();
        }
        while (this._callStack.length) {
            const schema = Entry.block[this.scope.block.type];
            if (schema.class === 'repeat') {
                break;
            }
            this.scope = this._callStack.pop();
        }
        return Entry.STATIC.PASS;
    }

    end() {
        Entry.dispatchEvent('blockExecuteEnd', this.scope.block && this.scope.block.view);
        this.scope.block = null;
    }

    isPause() {
        return this.paused;
    }

    isEnd() {
        return this.scope.block === null;
    }
}

Entry.Executor = Executor;
<|endoftext|>


<commit_before>/*global window*/
/*jshint -W015*/
/*jscs:disable validateIndentation*/
(function ($, geo, d3) {
  'use strict';

  var load = function () {

  // This requires jquery ui, which we don't want to make a
  // hard requirement, so bail out here if the widget factory
  // is not available and throw a helpful message when the
  // tries to use it.
  if (!$.widget) {
    $.fn.geojsMap = function () {
      throw new Error(
        'The geojs jquery plugin requires jquery ui to be available.'
      );
    };
    return;
  }

  // for multiple initialization detection
  var initialized = false;

  /**
   * Takes an option key and returns true if it should
   * return a color accessor.
   * @private
   */
  function isColorKey(key) {
    return key.slice(key.length - 5, key.length)
      .toLowerCase() === 'color';
  }

  /**
   * Take an array of data and an accessor for a color property
   * and return a wrapped accessor mapping to actual color
   * values.  This allows users to pass arbitrary strings
   * or numbers as any color property and this will wrap
   * a categorical scale or linear scale.
   *
   * Requires d3
   * @private
   * @param {Object[]} data A data array
   * @param {(string|number|function)} acc A color accessor
   * @return {function}
   */
  function makeColorScale(data, acc) {
    if (!d3) {
      console.warn('d3 is unavailable, cannot apply color scales.');
      return acc;
    }
    var domain;
    var cannotHandle = false;
    var doNotHandle = true;
    var categorical = false;
    var min = Number.POSITIVE_INFINITY;
    var max = Number.NEGATIVE_INFINITY;

    function wrap(func) {
      if (geo.util.isFunction(func)) {
        return function () {
          return func(acc.apply(this, arguments));
        };
      } else {
        return func(acc);
      }
    }

    if (geo.util.isFunction(acc)) {
      domain = d3.set(data.map(acc)).values();
    } else {
      domain = [acc];
    }
    domain.forEach(function (v) {
      if (!(typeof v === 'string' &&
            typeof geo.util.convertColor(v) === 'object')) {
        // This is to handle cases when values are css names or
        // hex strings.  We don't want to apply a categorical
        // scale.
        doNotHandle = false;
      }
      if (typeof v === 'string') {
        categorical = true;
      } else if (!isFinite(v)) {
        cannotHandle = true;
      } else if (+v > max) {
        max = +v;
      } else if (+v < min) {
        min = +v;
      }
    });
    if (cannotHandle) {
      console.warn('Unknown color value types.');
      return acc;
    }
    if (doNotHandle) {
      return acc;
    }
    if (categorical) {
      if (domain.length <= 10) {
        return wrap(d3.scale.category10().domain(domain));
      } else if (domain.length <= 20) {
        return wrap(d3.scale.category20().domain(domain));
      } else {
        // TODO: sort domain by most used and make an "other" category
        return wrap(d3.scale.category20().domain(domain));
      }
    }
    // http://colorbrewer2.org/?type=diverging&scheme=RdYlBu&n=3
    return wrap(d3.scale.linear()
      .range([
        'rgb(252,141,89)',
        'rgb(255,255,191)',
        'rgb(145,191,219)'
      ])
      .domain([
        min,
        (min + max) / 2,
        max
      ]));
  }

  /**
   * @class geojsMap
   * @memberOf $.fn
   *
   * @description Generates a geojs map inside an element.  Due to
   * current limitations in geojs, only a single map can be instantiated
   * on a page.  Trying to create a second map will throw an error
   * (see issue
   * #154).
   * @example
Create a map with the default options.

   * $("#map").geojsMap();
   * @example
Create a map with a given initial center and zoom

   * $("#map").geojsMap({
   *    longitude: -125,
   *    latitude: 35,
   *    zoom: 5
   * });
   * @example
Create a map with points

   * $("#map").geojsMap({
   *    zoom: 1,
   *    points: {
   *        data: data,
   *        radius: 5,
   *        fillColor: 'steelblue',
   *        position: function (d) {
   *            return {
   *                x: d.coordinates[0],
   *                y: d.coordinates[1]
   *            };
   *       }
   *    }
   * });
   */
  $.widget('geojs.geojsMap', /** @lends $.fn.geojsMap */{
    /**
     * A coordinate object as accepted by geojs to express positions in an
     * arbitrary coordinate system (geographic, screen, etc).  Coordinates returned by
     * geojs methods are always expressed with "x" and "y" properties, but
     * it will accept any of the aliased properties.
     * @typedef coordinate
     * @type {Object}
     * @property {number} longitude Alias: "x", "lng", or "lon"
     * @property {number} latitude Alias: "y" or "lat"
     * @property {number} [elevation=0] Alias: "z", "elev", or "height"
     */

    /**
     * A geojs renderer is one of the following:
     *

     *
"vglRenderer": Uses webGL

     *
"d3Renderer": Uses svg

     *

     * @typedef renderer
     * @type {string}
     */

    /**
     * Colors can be expressed in multiple ways:
     *

     *
css name ("steelblue")

     *
24 bit hex value (0xff0051)

     *
25 bit hex string ("#ff0051")

     *
rgb object (values from 0-1, {r: 1, g: 0.5, b: 0})

     *

     * @typedef color
     * @type {*}
     */

    /**
     * Point feature options object.  All styles can be
     * given as accessor functions or constants.  Accessor
     * functions are called with the following signature:
     *

     *     function func(d, i) {
     *         // d    - data object
     *         // i    - index of d in the data array
     *         // this - geo.pointFeature
     *     }
     *

     * Pass null to remove saved options from previous calls.
     * @typedef pointOptions
     * @type {Object}
     * @property {Object[]} data Data array
     * @property {coordinate} position Location of the point center
     * @property {number} radius
     *  Radius of the circle in pixels (ignored when size
     *  is present)
     * @property {number} size
     *   A numerical value mapped affinely to a radius in the range [5,20]
     * @property {boolean} fill Presence or absence of the fill
     * @property {color} fillColor Interior color
     * @property {float} fillOpacity Opacity of the interior [0,1]
     * @property {boolean} stroke Presence or absence of the stroke
     * @property {color} strokeColor Stroke color
     * @property {float} strokeOpacity Opacity of the stroke [0,1]
     */

    /**
     * @instance
     * @description
     * Map options (not fully implemented).
     * @example
Get the current map center

     * var center=$("#map").geojsMap("center");
     * @example
Pan the map to a new center

     * $("#map").geojsMap("center", {lat: 10, lng: -100});
     * @property {coordinate} [center={lat: 0, lng: 0}] The map center
     * @property {number} [zoom=0] The zoom level (floating point >= 0)
     * @property {(number|null)} [width=null]
     *   The width of the map in pixels or null for 100%
     * @property {(number|null)} [height=null]
     *   The height of the map in pixels or null for 100%
     * @property {renderer} [renderer="vglRenderer"]
     *   The renderer for map features (initialization only)
     * @property {boolean} [autoresize=true]
     *   Resize the map on window.resize (initialization only)
     * @property {pointOptions} [points={}]
     *   Set the points option property (initialization only)
     */
    options: {
      center: {latitude: 0, longitude: 0},
      zoom: 0,
      width: null,
      height: null,
      renderer: 'vglRenderer',
      points: {},

      // These options are for future use, but shouldn't
      // be changed at the moment, so they aren't documented.
      baseLayer: 'osm',
      baseRenderer: 'vglRenderer'
    },

    /**
     * Internal constructor
     * @instance
     * @protected
     */
    _create: function () {
      if (this._map || !this.element.length) {
        // when called multiple times on a single element, do nothing
        return;
      }
      if (initialized) {
        // when called multiple times on different elements, die
        throw new Error(
          'Only one map per page is allowed.'
        );
      }
      // set global initialization state
      initialized = true;

      // create the map
      this._map = geo.map({
        width: this.options.width,
        height: this.options.height,
        zoom: this.options.zoom,
        center: this.options.center,
        node: this.element.get(0)
      });

      // create the base layer
      this._baseLayer = this._map.createLayer(
        this.options.baseLayer,
        {
          renderer: this.options.baseRenderer
        }
      );

      // Trigger a resize to a valid size before adding
      // the feature layer to handle some of the bugs that
      // occur when initializing onto a node of size 0.
      this._resize({width: 800, height: 600});

      // store the renderer, because it can't be changed
      this._renderer = this.options.renderer;

      // create the feature layer
      this._featureLayer = this._map.createLayer('feature', {
        renderer: this._renderer
      });

      // create a point feature
      this._points = this._featureLayer.createFeature('point').data([]);

      // create a line feature
      this._lines = this._featureLayer.createFeature('line').data([]);

      // trigger an initial draw
      this.redraw();

      // add point options
      this.points(this.options.points);
    },

    /**
     * Resize the map canvas.
     * @instance
     * @protected
     * @param {object?} size Explicit size or use this.options.
     */
    _resize: function (size) {
      var width = this.options.width,
          height = this.options.height;
      if (size) {
        width = size.width;
        height = size.height;
      }
      if (!width) {
        width = this.element.width();
      }
      if (!height) {
        height = this.element.height();
      }
      this._map.resize(0, 0, width, height);
    },

    /**
     * Do a full redraw of the map.  In general, users shouldn't need to
     * call this method, but it could be useful when accessing lower
     * level features of the mapping api.
     * @instance
     */
    redraw: function () {
      this._resize();
    },

    /**
     * Set point feature data and styles.  Only the properties provided
     * will be applied to the map.  For example, if options.data is
     * undefined, then the data previously given will be used.
     * @instance
     * @param {object} options Point options (see {@link pointOptions})
     * @example
Initializing point attributes

     * $("#map").geojsMap('points', {
     *     position: function (d) {
     *          return {x: d.geometry.lon, y: d.geometry.lat}
     *     },
     *     radius: function (d) { return d.size; },
     *     fillColor: "red",
     *     strokeColor: "#010a10"
     * });
     * @example
Updating the point data

     * $("#map").geojsMap('points', {
     *     data: data
     * });
     */
    points: function (options) {
      var pt = this._points, key, data, scl, that = this;
      options = options || {};

      if (options.data) {
        pt.data(options.data);
      }
      data = pt.data();

      if (options.position) {
        pt.position(function () {
          // could use some optimization
          var f = geo.util.ensureFunction(options.position);
          var d = f.apply(this, arguments);
          return geo.util.normalizeCoordinates(d);
        });
      }

      if (options.data && options.data.length) {
        // force recompute the color scales with new data
        options.fillColor = options.fillColor || pt.style().fillColor;
        options.strokeColor = options.strokeColor || pt.style().strokeColor;
      }

      if (options.size) {
        // save the size function to update the radius
        // scale when new data is given
        this._size = options.size;
      } else if (options.size === null) {
        delete this._size;
      }

      if (data.length && this._size) {
        scl = d3.scale.linear()
          .domain(
            d3.extent(data, this._size)
          )
          .range([5, 20]);
        options.radius = function () {
          return scl(that._size.apply(this, arguments));
        };
        delete options.size;
      }

      // apply color scales if necessary
      for (key in options) {
        if (options.hasOwnProperty(key) &&
            isColorKey(key)) {
          options[key] = makeColorScale(data, options[key]);
        }
      }
      pt.style(options).draw();

      // handle vglRenderer bug where feature.draw() doesn't cause a redraw
      if (this._renderer === 'vglRenderer') {
        this._map.draw();
      }
    }
  });
  };

  $(load);
})($ || window.$, geo || window.geo, d3 || window.d3);
<commit_msg>Fix default handling of colors<commit_after>/*global window*/
/*jshint -W015*/
/*jscs:disable validateIndentation*/
(function ($, geo, d3) {
  'use strict';

  var load = function () {

  // This requires jquery ui, which we don't want to make a
  // hard requirement, so bail out here if the widget factory
  // is not available and throw a helpful message when the
  // tries to use it.
  if (!$.widget) {
    $.fn.geojsMap = function () {
      throw new Error(
        'The geojs jquery plugin requires jquery ui to be available.'
      );
    };
    return;
  }

  // for multiple initialization detection
  var initialized = false;

  /**
   * Takes an option key and returns true if it should
   * return a color accessor.
   * @private
   */
  function isColorKey(key) {
    return key.slice(key.length - 5, key.length)
      .toLowerCase() === 'color';
  }

  /**
   * Take an array of data and an accessor for a color property
   * and return a wrapped accessor mapping to actual color
   * values.  This allows users to pass arbitrary strings
   * or numbers as any color property and this will wrap
   * a categorical scale or linear scale.
   *
   * Requires d3
   * @private
   * @param {Object[]} data A data array
   * @param {(string|number|function)} acc A color accessor
   * @return {function}
   */
  function makeColorScale(data, acc) {
    if (!d3) {
      console.warn('d3 is unavailable, cannot apply color scales.');
      return acc;
    }
    var domain;
    var cannotHandle = false;
    var doNotHandle = true;
    var categorical = false;
    var min = Number.POSITIVE_INFINITY;
    var max = Number.NEGATIVE_INFINITY;

    function wrap(func) {
      if (geo.util.isFunction(func)) {
        return function () {
          return func(acc.apply(this, arguments));
        };
      } else {
        return func(acc);
      }
    }

    if (geo.util.isFunction(acc)) {
      domain = d3.set(data.map(acc)).values();
    } else {
      domain = [acc];
    }
    domain.forEach(function (v) {
      if (!(typeof v === 'string' &&
            typeof geo.util.convertColor(v) === 'object')) {
        // This is to handle cases when values are css names or
        // hex strings.  We don't want to apply a categorical
        // scale.
        doNotHandle = false;
      }
      if (typeof v === 'string') {
        categorical = true;
      } else if (!isFinite(v)) {
        cannotHandle = true;
      } else if (+v > max) {
        max = +v;
      } else if (+v < min) {
        min = +v;
      }
    });
    if (cannotHandle) {
      // At least one value is not a string or a numeric value.
      // Pass the bare accessor back to geojs to handle it.
      return acc;
    }
    if (doNotHandle) {
      return acc;
    }
    if (categorical) {
      if (domain.length <= 10) {
        return wrap(d3.scale.category10().domain(domain));
      } else if (domain.length <= 20) {
        return wrap(d3.scale.category20().domain(domain));
      } else {
        // TODO: sort domain by most used and make an "other" category
        return wrap(d3.scale.category20().domain(domain));
      }
    }
    // http://colorbrewer2.org/?type=diverging&scheme=RdYlBu&n=3
    return wrap(d3.scale.linear()
      .range([
        'rgb(252,141,89)',
        'rgb(255,255,191)',
        'rgb(145,191,219)'
      ])
      .domain([
        min,
        (min + max) / 2,
        max
      ]));
  }

  /**
   * @class geojsMap
   * @memberOf $.fn
   *
   * @description Generates a geojs map inside an element.  Due to
   * current limitations in geojs, only a single map can be instantiated
   * on a page.  Trying to create a second map will throw an error
   * (see issue
   * #154).
   * @example
Create a map with the default options.

   * $("#map").geojsMap();
   * @example
Create a map with a given initial center and zoom

   * $("#map").geojsMap({
   *    longitude: -125,
   *    latitude: 35,
   *    zoom: 5
   * });
   * @example
Create a map with points

   * $("#map").geojsMap({
   *    zoom: 1,
   *    points: {
   *        data: data,
   *        radius: 5,
   *        fillColor: 'steelblue',
   *        position: function (d) {
   *            return {
   *                x: d.coordinates[0],
   *                y: d.coordinates[1]
   *            };
   *       }
   *    }
   * });
   */
  $.widget('geojs.geojsMap', /** @lends $.fn.geojsMap */{
    /**
     * A coordinate object as accepted by geojs to express positions in an
     * arbitrary coordinate system (geographic, screen, etc).  Coordinates returned by
     * geojs methods are always expressed with "x" and "y" properties, but
     * it will accept any of the aliased properties.
     * @typedef coordinate
     * @type {Object}
     * @property {number} longitude Alias: "x", "lng", or "lon"
     * @property {number} latitude Alias: "y" or "lat"
     * @property {number} [elevation=0] Alias: "z", "elev", or "height"
     */

    /**
     * A geojs renderer is one of the following:
     *

     *
"vglRenderer": Uses webGL

     *
"d3Renderer": Uses svg

     *

     * @typedef renderer
     * @type {string}
     */

    /**
     * Colors can be expressed in multiple ways:
     *

     *
css name ("steelblue")

     *
24 bit hex value (0xff0051)

     *
25 bit hex string ("#ff0051")

     *
rgb object (values from 0-1, {r: 1, g: 0.5, b: 0})

     *

     * @typedef color
     * @type {*}
     */

    /**
     * Point feature options object.  All styles can be
     * given as accessor functions or constants.  Accessor
     * functions are called with the following signature:
     *

     *     function func(d, i) {
     *         // d    - data object
     *         // i    - index of d in the data array
     *         // this - geo.pointFeature
     *     }
     *

     * Pass null to remove saved options from previous calls.
     * @typedef pointOptions
     * @type {Object}
     * @property {Object[]} data Data array
     * @property {coordinate} position Location of the point center
     * @property {number} radius
     *  Radius of the circle in pixels (ignored when size
     *  is present)
     * @property {number} size
     *   A numerical value mapped affinely to a radius in the range [5,20]
     * @property {boolean} fill Presence or absence of the fill
     * @property {color} fillColor Interior color
     * @property {float} fillOpacity Opacity of the interior [0,1]
     * @property {boolean} stroke Presence or absence of the stroke
     * @property {color} strokeColor Stroke color
     * @property {float} strokeOpacity Opacity of the stroke [0,1]
     */

    /**
     * @instance
     * @description
     * Map options (not fully implemented).
     * @example
Get the current map center

     * var center=$("#map").geojsMap("center");
     * @example
Pan the map to a new center

     * $("#map").geojsMap("center", {lat: 10, lng: -100});
     * @property {coordinate} [center={lat: 0, lng: 0}] The map center
     * @property {number} [zoom=0] The zoom level (floating point >= 0)
     * @property {(number|null)} [width=null]
     *   The width of the map in pixels or null for 100%
     * @property {(number|null)} [height=null]
     *   The height of the map in pixels or null for 100%
     * @property {renderer} [renderer="vglRenderer"]
     *   The renderer for map features (initialization only)
     * @property {boolean} [autoresize=true]
     *   Resize the map on window.resize (initialization only)
     * @property {pointOptions} [points={}]
     *   Set the points option property (initialization only)
     */
    options: {
      center: {latitude: 0, longitude: 0},
      zoom: 0,
      width: null,
      height: null,
      renderer: 'vglRenderer',
      points: {
        stroke: false,
        strokeColor: 'black'
      },

      // These options are for future use, but shouldn't
      // be changed at the moment, so they aren't documented.
      baseLayer: 'osm',
      baseRenderer: 'vglRenderer'
    },

    /**
     * Internal constructor
     * @instance
     * @protected
     */
    _create: function () {
      if (this._map || !this.element.length) {
        // when called multiple times on a single element, do nothing
        return;
      }
      if (initialized) {
        // when called multiple times on different elements, die
        throw new Error(
          'Only one map per page is allowed.'
        );
      }
      // set global initialization state
      initialized = true;

      // create the map
      this._map = geo.map({
        width: this.options.width,
        height: this.options.height,
        zoom: this.options.zoom,
        center: this.options.center,
        node: this.element.get(0)
      });

      // create the base layer
      this._baseLayer = this._map.createLayer(
        this.options.baseLayer,
        {
          renderer: this.options.baseRenderer
        }
      );

      // Trigger a resize to a valid size before adding
      // the feature layer to handle some of the bugs that
      // occur when initializing onto a node of size 0.
      this._resize({width: 800, height: 600});

      // store the renderer, because it can't be changed
      this._renderer = this.options.renderer;

      // create the feature layer
      this._featureLayer = this._map.createLayer('feature', {
        renderer: this._renderer
      });

      // create a point feature
      this._points = this._featureLayer.createFeature('point').data([]);

      // create a line feature
      this._lines = this._featureLayer.createFeature('line').data([]);

      // trigger an initial draw
      this.redraw();

      // add point options
      this.points(this.options.points);
    },

    /**
     * Resize the map canvas.
     * @instance
     * @protected
     * @param {object?} size Explicit size or use this.options.
     */
    _resize: function (size) {
      var width = this.options.width,
          height = this.options.height;
      if (size) {
        width = size.width;
        height = size.height;
      }
      if (!width) {
        width = this.element.width();
      }
      if (!height) {
        height = this.element.height();
      }
      this._map.resize(0, 0, width, height);
    },

    /**
     * Do a full redraw of the map.  In general, users shouldn't need to
     * call this method, but it could be useful when accessing lower
     * level features of the mapping api.
     * @instance
     */
    redraw: function () {
      this._resize();
    },

    /**
     * Set point feature data and styles.  Only the properties provided
     * will be applied to the map.  For example, if options.data is
     * undefined, then the data previously given will be used.
     * @instance
     * @param {object} options Point options (see {@link pointOptions})
     * @example
Initializing point attributes

     * $("#map").geojsMap('points', {
     *     position: function (d) {
     *          return {x: d.geometry.lon, y: d.geometry.lat}
     *     },
     *     radius: function (d) { return d.size; },
     *     fillColor: "red",
     *     strokeColor: "#010a10"
     * });
     * @example
Updating the point data

     * $("#map").geojsMap('points', {
     *     data: data
     * });
     */
    points: function (options) {
      var pt = this._points, key, data, scl, that = this;
      options = options || {};

      if (options.data) {
        pt.data(options.data);
      }
      data = pt.data();

      if (options.position) {
        pt.position(function () {
          // could use some optimization
          var f = geo.util.ensureFunction(options.position);
          var d = f.apply(this, arguments);
          return geo.util.normalizeCoordinates(d);
        });
      }

      if (options.data && options.data.length) {
        // force recompute the color scales with new data
        options.fillColor = options.fillColor || pt.style().fillColor;
        options.strokeColor = options.strokeColor || pt.style().strokeColor;
      }

      if (options.size) {
        // save the size function to update the radius
        // scale when new data is given
        this._size = options.size;
      } else if (options.size === null) {
        delete this._size;
      }

      if (data.length && this._size) {
        scl = d3.scale.linear()
          .domain(
            d3.extent(data, this._size)
          )
          .range([5, 20]);
        options.radius = function () {
          return scl(that._size.apply(this, arguments));
        };
        delete options.size;
      }

      // apply color scales if necessary
      for (key in options) {
        if (options.hasOwnProperty(key) &&
            isColorKey(key)) {
          options[key] = makeColorScale(data, options[key]);
        }
      }
      pt.style(options).draw();

      // handle vglRenderer bug where feature.draw() doesn't cause a redraw
      if (this._renderer === 'vglRenderer') {
        this._map.draw();
      }
    }
  });
  };

  $(load);
})($ || window.$, geo || window.geo, d3 || window.d3);
<|endoftext|>


<commit_before>/**
 * @mixin NestedDirtyModel
 *
 * @description Adds the `$dirty` method to a model`s instances. Acts in the same way as the DirtyModel plugin, but supports nested objects.
 */

'use strict';

angular.module('restmod').factory('NestedDirtyModel', ['restmod', function(restmod) {

  // Helper function to check model for changes properties
  function findChanged(_model, _original, _keys, _comparator) {
    var changes = [], keys = angular.copy(_keys);

    if(_original) {
      for(var key in _original) {
        // isObject returns true if value is an array
        if(angular.isObject(_original[key]) && !angular.isArray(_original[key])) {
          keys.push(key);
          changes = changes.concat(findChanged(_model[key], _original[key], keys, _comparator));
        } else {
          if(isDirtyValue(_model, _original, [key], _comparator)) {
            changes.push(keys.length ? (keys.push(key) && keys.join('.')) : key);
          }
        }

        keys = angular.copy(_keys);
      }
    }

    return changes;
  }

  // Compares original value with current value
  function isDirtyValue(_model, _original, _keys, _comparator) {
    var isDirty = false,
        prop = _keys.pop(),
        propChain = buildPropChain(_model, _original, _keys);

    _model = propChain[0];
    _original = propChain[1];

    if(_original.hasOwnProperty(prop)) {
      if(_comparator && angular.isFunction(_comparator)) {
        isDirty = !!_comparator(_model[prop], _original[prop]);
      } else { // Check via equality
        // Join arrays before comparing them
        if(angular.isArray(_original[prop])) {
          isDirty = _model[prop].join('|') !== _original[prop].join('|');
        } else {
          isDirty = _model[prop] !== _original[prop];
        }
      }
    }

    return isDirty;
  }

  // Helper function to build a property chain from a set of keys
  function buildPropChain(_model, _original, _keys) {
    var key;

    while(_keys.length) {
      key = _keys.shift();
      _model = _model[key];
      _original = _original[key];
    }

    return [_model, _original];
  }

  return restmod.mixin(function() {
    this.on('after-feed', function(_original) {
          // store original information in a model's special property
          this.$cmStatus = angular.copy(_original);
        })
        /**
         * @method $dirty
         * @memberof NestedDirtyModel#
         *
         * @description Retrieves the model changes
         *
         * Property changes are determined using the strict equality operator if no comparator
         * function is provided.
         *
         * If given a property name, this method will return true if property has changed
         * or false if it has not.
         *
         * The comparator function can be passed either as the first or second parameter.
         * If first, this function will compare all properties using the comparator.
         *
         * Called without arguments, this method will return a list of changed property names.
         *
         * @param {string|function} _prop Property to query or function to compare all properties
         * @param {function} _comparator Function to compare property
         * @return {boolean|array} Property state or array of changed properties
         */
        .define('$dirty', function(_prop, _comparator) {
          var original = this.$cmStatus, keys;

          if(_prop && !angular.isFunction(_prop)) {
            keys = _prop.split('.');
            return isDirtyValue(this, original, keys, _comparator);
          } else {
            if(angular.isFunction(_prop)) _comparator = _prop;
            return findChanged(this, original, [], _comparator);
          }
        })
        /**
         * @method $restore
         * @memberof NestedDirtyModel#
         *
         * @description Restores the model's last fetched values.
         *
         * Usage:
         *
         * ```javascript
         * bike = Bike.$create({ brand: 'Trek' });
         * // later on...
         * bike.brand = 'Giant';
         * bike.$restore();
         *
         * console.log(bike.brand); // outputs 'Trek'
         * ```
         *
         * @param {string} _prop If provided, only _prop is restored
         * @return {Model} self
         */
        .define('$restore', function(_prop) {
          return this.$action(function() {
            var original = this.$cmStatus,
                model = this;

            if(_prop) {
              var keys = _prop.split('.'), propChain;

              _prop = keys.pop();
              propChain = buildPropChain(model, original, keys);

              propChain[0][_prop] = angular.copy(propChain[1][_prop]);
            } else {
              for(var key in original) {
                if(original.hasOwnProperty(key)) model[key] = angular.copy(original[key]);
              }
            }
          });
        });
  });
}]);<commit_msg>refactor(plugin.nested_dirty): changes the way original data is generated.<commit_after>/**
 * @mixin NestedDirtyModel
 *
 * @description Adds the `$dirty` method to a model`s instances. Acts in the same way as the DirtyModel plugin, but supports nested objects.
 */

'use strict';

angular.module('restmod').factory('NestedDirtyModel', ['restmod', function(restmod) {

  function copyOriginalData(_from) {
    var Model = _from.$type, result = {};

    _from.$each(function(value, key) {
      var meta = Model.$$getDescription(key);
      if(!meta || !meta.relation) {
        // TODO: skip masked properties too?
        result[key] = angular.copy(value);
      }
    });

    return result;
  }

  function hasValueChanged(_model, _original, _keys, _comparator) {
    var isDirty = false,
        prop = _keys.pop(),
        propChain = buildPropChain(_model, _original, _keys);

    _model = propChain[0];
    _original = propChain[1];

    if(_original.hasOwnProperty(prop)) {
      if(_comparator && angular.isFunction(_comparator)) {
        isDirty = !!_comparator(_model[prop], _original[prop]);
      } else { // Check via equality
        // Join arrays before comparing them
        if(angular.isArray(_original[prop])) {
          isDirty = _model[prop].join('|') !== _original[prop].join('|');
        } else {
          isDirty = _model[prop] !== _original[prop];
        }
      }
    }

    return isDirty;
  }

  function findChangedValues(_model, _original, _keys, _comparator) {
    var changes = [], childChanges;

    if(_original) {
      for(var key in _original) {
        if(_original.hasOwnProperty(key)) {
          // isObject returns true if value is an array
          if(angular.isObject(_original[key]) && !angular.isArray(_original[key])) {
            childChanges = findChangedValues(_model[key], _original[key], _keys.concat([key]), _comparator);
            changes.push.apply(changes, childChanges);
          } else {
            if(hasValueChanged(_model, _original, [key], _comparator)) {
              changes.push(_keys.concat([key]).join('.'));
            }
          }
        }
      }
    }

    return changes;
  }

  // Helper function to build a property chain from a set of keys
  function buildPropChain(_model, _original, _keys) {
    var key;

    while(_keys.length) {
      key = _keys.shift();
      _model = _model[key];
      _original = _original[key];
    }

    return [_model, _original];
  }

  return restmod.mixin(function() {
    this.on('after-feed', function() {
          // store original information in a model's special property
          this.$cmStatus = copyOriginalData(this);
        })
        /**
         * @method $dirty
         * @memberof NestedDirtyModel#
         *
         * @description Retrieves the model changes
         *
         * Property changes are determined using the strict equality operator if no comparator
         * function is provided.
         *
         * If given a property name, this method will return true if property has changed
         * or false if it has not.
         *
         * The comparator function can be passed either as the first or second parameter.
         * If first, this function will compare all properties using the comparator.
         *
         * Called without arguments, this method will return a list of changed property names.
         *
         * @param {string|function} _prop Property to query or function to compare all properties
         * @param {function} _comparator Function to compare property
         * @return {boolean|array} Property state or array of changed properties
         */
        .define('$dirty', function(_prop, _comparator) {
          var original = this.$cmStatus;

          if(_prop && !angular.isFunction(_prop)) {
            return hasValueChanged(this, original, _prop.split('.'), _comparator);
          } else {
            if(angular.isFunction(_prop)) _comparator = _prop;
            return findChangedValues(this, original, [], _comparator);
          }
        })
        /**
         * @method $restore
         * @memberof NestedDirtyModel#
         *
         * @description Restores the model's last fetched values.
         *
         * Usage:
         *
         * ```javascript
         * bike = Bike.$create({ brand: 'Trek' });
         * // later on...
         * bike.brand = 'Giant';
         * bike.$restore();
         *
         * console.log(bike.brand); // outputs 'Trek'
         * ```
         *
         * @param {string} _prop If provided, only _prop is restored
         * @return {Model} self
         */
        .define('$restore', function(_prop) {
          return this.$action(function() {
            var original = this.$cmStatus,
                model = this;

            if(_prop) {
              var keys = _prop.split('.'), propChain;

              _prop = keys.pop();
              propChain = buildPropChain(model, original, keys);

              propChain[0][_prop] = angular.copy(propChain[1][_prop]);
            } else {
              for(var key in original) {
                if(original.hasOwnProperty(key)) model[key] = angular.copy(original[key]);
              }
            }
          });
        });
  });
}]);<|endoftext|>


<commit_before>"use strict";
var mongoose = require("mongoose");

var Album = mongoose.model("Album");

module.exports = (function(){
	return{
		index: function(req,res){
			Album.find({}, function(err, data) {
				if (!err){
					res.setHeader('Content-Type', 'application/json');
					res.json(data);
				} else {
					throw err;
				}
			});
		},
		create: function(req,res){
			var newAlbum = new Album({
				title: "Purple Lamborghini [Explicit]",
				artist: "Skrillex",
				url: "https://www.amazon.com/Purple-Lamborghini-Explicit/dp/B01IQ0H1DY/ref=sr_1_3?ie=UTF8&qid=1476948109&sr=8-3&keywords=skrillex+purple+lamborghini",
				image: "https://images-na.ssl-images-amazon.com/images/I/61QHnD41%2BOL._SS500.jpg",
				thumbnail:  "https://images-na.ssl-images-amazon.com/images/I/61QHnD41%2BOL._SS500.jpg"
			});

			newAlbum.save(function(err,data){
				// if(err){
				// 	console.log("something went wrong",err.message);
				// 	res.json(err);
				// }else{
				// 	console.log('successfully added a hahha!\n',data);
				// 	res.json(data);
				// }
			});
			newAlbum = new Album({
				title: "First Of The Year (Equinox)",
				artist: "Skrillex",
				url: "https://www.amazon.com/First-Of-The-Year-Equinox/dp/B0055M9WDO/ref=sr_1_1?ie=UTF8&qid=1476991125&sr=8-1&keywords=first+of+the+year+equinox",
				image: "https://images-na.ssl-images-amazon.com/images/I/51mHgh%2B7l8L._SS500.jpg",
				thumbnail:  "https://images-na.ssl-images-amazon.com/images/I/51mHgh%2B7l8L._SS500.jpg"
			});

			newAlbum.save(function(err,data){
				// if(err){
				// 	console.log("something went wrong",err.message);
				// 	res.json(err);
				// }else{
				// 	console.log('successfully added a hahha!\n',data);
				// 	res.json(data);
				// }
			});

			newAlbum = new Album({
				title: "Bangarang (Feat. Sirah) [Explicit]",
				artist: "Skrillex",
				url: "https://www.amazon.com/Bangarang-Feat-Sirah-Explicit/dp/B006PAZN56/ref=sr_1_1?ie=UTF8&qid=1476994100&sr=8-1&keywords=bangarang",
				image: "https://images-na.ssl-images-amazon.com/images/I/61G8uLZ-rML._SS500.jpg",
				thumbnail:  "https://images-na.ssl-images-amazon.com/images/I/61G8uLZ-rML._SS500.jpg"
			});

			newAlbum.save(function(err,data){
				if(err){
					console.log("something went wrong",err.message);
					res.json(err);
				}else{
					console.log('successfully added a hahha!\n',data);
					res.json(data);
				}
			});
		}
	};
})();<commit_msg>res.send<commit_after>"use strict";
var mongoose = require("mongoose");

var Album = mongoose.model("Album");

module.exports = (function(){
	return{
		index: function(req,res){
			Album.find({}, function(err, data) {
				if (!err){
					res.setHeader('Content-Type', 'application/json');
					res.send(data);
				} else {
					res.json(err);
				}
			});
		},
		create: function(req,res){
			var newAlbum = new Album({
				title: "Purple Lamborghini [Explicit]",
				artist: "Skrillex",
				url: "https://www.amazon.com/Purple-Lamborghini-Explicit/dp/B01IQ0H1DY/ref=sr_1_3?ie=UTF8&qid=1476948109&sr=8-3&keywords=skrillex+purple+lamborghini",
				image: "https://images-na.ssl-images-amazon.com/images/I/61QHnD41%2BOL._SS500.jpg",
				thumbnail:  "https://images-na.ssl-images-amazon.com/images/I/61QHnD41%2BOL._SS500.jpg"
			});

			newAlbum.save(function(err,data){
				// if(err){
				// 	console.log("something went wrong",err.message);
				// 	res.json(err);
				// }else{
				// 	console.log('successfully added a hahha!\n',data);
				// 	res.json(data);
				// }
			});
			newAlbum = new Album({
				title: "First Of The Year (Equinox)",
				artist: "Skrillex",
				url: "https://www.amazon.com/First-Of-The-Year-Equinox/dp/B0055M9WDO/ref=sr_1_1?ie=UTF8&qid=1476991125&sr=8-1&keywords=first+of+the+year+equinox",
				image: "https://images-na.ssl-images-amazon.com/images/I/51mHgh%2B7l8L._SS500.jpg",
				thumbnail:  "https://images-na.ssl-images-amazon.com/images/I/51mHgh%2B7l8L._SS500.jpg"
			});

			newAlbum.save(function(err,data){
				// if(err){
				// 	console.log("something went wrong",err.message);
				// 	res.json(err);
				// }else{
				// 	console.log('successfully added a hahha!\n',data);
				// 	res.json(data);
				// }
			});

			newAlbum = new Album({
				title: "Bangarang (Feat. Sirah) [Explicit]",
				artist: "Skrillex",
				url: "https://www.amazon.com/Bangarang-Feat-Sirah-Explicit/dp/B006PAZN56/ref=sr_1_1?ie=UTF8&qid=1476994100&sr=8-1&keywords=bangarang",
				image: "https://images-na.ssl-images-amazon.com/images/I/61G8uLZ-rML._SS500.jpg",
				thumbnail:  "https://images-na.ssl-images-amazon.com/images/I/61G8uLZ-rML._SS500.jpg"
			});

			newAlbum.save(function(err,data){
				if(err){
					console.log("something went wrong",err.message);
					res.json(err);
				}else{
					console.log('successfully added a hahha!\n',data);
					res.json(data);
				}
			});
		}
	};
})();<|endoftext|>


<commit_before>var DomainDB = {
	// Given a userId, returns a promise containing the domains that have
	// appeared in messages that user has sent/received
	// If userId does not exist in db or no domains have been found in relation
	// to that user, returns a promise containing null
	getDomains(userId) {
		const query = (
			'SELECT d.domain_name AS domain FROM DOMAIN d ' +
			'JOIN USER_DOMAINS ud ON d.domain_id = ud.domain_id ' +
			'WHERE ud.user_id = :userId'
		)
		return this._connection.queryAsync(query, {userId: 1}, {useArray: true}).then(rows => {
			this._connection.end()
			return rows
		})
		// return this._getObjects(
		// 	(
		// 		'SELECT d.domain_name AS domain FROM DOMAIN d ' +
		// 		'JOIN USER_DOMAINS ud ON d.domain_id = ud.domain_id ' +
		// 		'WHERE ud.user_id = :userId'
		// 	),
		// 	{
		// 		userId: userId
		// 	}
		// )
	},

	// Given connection, query and params, returns a promise containing query contents
	// If query returns no results, returns a promise containing null
	_getSingleObject(query, params) {
		return this._connection
			.queryAsync(query, {id: params.id || '', email: params.email || ''})
			.then(rows => {
				return rows && rows.length > 0 ? rows[0] : null;
			});
	},

	_getObjects(query, params) {
		return this._connection
			.queryAsync(query, {id: params.id})
			.then(rows => {
				return rows && rows.length > 0 ? rows : null;
			});
	}
}

module.exports = function (connection) {
	var domainDB = Object.create(DomainDB);
	domainDB._connection = connection;
	return domainDB;
}<commit_msg>updating enpoints to use database data<commit_after>var DomainDB = {
	// Given a userId, returns a promise containing the domains that have
	// appeared in messages that user has sent/received
	// If userId does not exist in db or no domains have been found in relation
	// to that user, returns a promise containing null
	getDomains(userId) {
		const query = (
			'SELECT d.domain_name AS domain FROM DOMAIN d ' +
			'JOIN USER_DOMAINS ud ON d.domain_id = ud.domain_id ' +
			'WHERE ud.user_id = :userId'
		)
		return this._connection.queryAsync(query, {userId: 1}, {useArray: true}).then(rows => {
			this._connection.end()
			return rows.map(row => row[0])
		})
		// return this._getObjects(
		// 	(
		// 		'SELECT d.domain_name AS domain FROM DOMAIN d ' +
		// 		'JOIN USER_DOMAINS ud ON d.domain_id = ud.domain_id ' +
		// 		'WHERE ud.user_id = :userId'
		// 	),
		// 	{
		// 		userId: userId
		// 	}
		// )
	},

	// Given connection, query and params, returns a promise containing query contents
	// If query returns no results, returns a promise containing null
	_getSingleObject(query, params) {
		return this._connection
			.queryAsync(query, {id: params.id || '', email: params.email || ''})
			.then(rows => {
				return rows && rows.length > 0 ? rows[0] : null;
			});
	},

	_getObjects(query, params) {
		return this._connection
			.queryAsync(query, {id: params.id})
			.then(rows => {
				return rows && rows.length > 0 ? rows : null;
			});
	}
}

module.exports = function (connection) {
	var domainDB = Object.create(DomainDB);
	domainDB._connection = connection;
	return domainDB;
}<|endoftext|>