<commit_before>import Ember from 'ember';
import {request as ajax} from 'ic-ajax';
/* global key */

export default Ember.Component.extend({

    selection: null,
    content: [],
    isLoading: false,
    contentExpiry: 60 * 1000,
    contentExpiresAt: false,

    posts: Ember.computed.filterBy('content', 'category', 'Posts'),
    pages: Ember.computed.filterBy('content', 'category', 'Pages'),
    users: Ember.computed.filterBy('content', 'category', 'Users'),

    _store: Ember.inject.service('store'),
    _routing: Ember.inject.service('-routing'),
    _selectize: Ember.computed(function () {
        return this.$('select')[0].selectize;
    }),

    refreshContent: function () {
        var promises = [],
            now = new Date(),
            contentExpiry = this.get('contentExpiry'),
            contentExpiresAt = this.get('contentExpiresAt'),
            self = this;

        if (self.get('isLoading') || contentExpiresAt > now) { return; }

        self.set('isLoading', true);
        promises.pushObject(this._loadPosts());
        promises.pushObject(this._loadUsers());

        Ember.RSVP.all(promises).then(function () { }).finally(function () {
            self.set('isLoading', false);
            self.set('contentExpiresAt', new Date(now.getTime() + contentExpiry));
        });
    },

    _loadPosts: function () {
        var store = this.get('_store'),
            postsUrl = store.adapterFor('post').urlForFindQuery({}, 'post') + '/',
            postsQuery = {fields: 'id,title,page', limit: 'all', status: 'all', staticPages: 'all'},
            content = this.get('content'),
            self = this;

        return ajax(postsUrl, {data: postsQuery}).then(function (posts) {
            content.removeObjects(self.get('posts'));
            content.removeObjects(self.get('pages'));
            content.pushObjects(posts.posts.map(function (post) {
                return {
                    id: post.id,
                    title: post.title,
                    category: post.page ? 'Pages' : 'Posts'
                };
            }));
        });
    },

    _loadUsers: function () {
        var store = this.get('_store'),
            usersUrl = store.adapterFor('user').urlForFindQuery({}, 'user') + '/',
            usersQuery = {fields: 'name,slug', limit: 'all'},
            content = this.get('content'),
            self = this;

        return ajax(usersUrl, {data: usersQuery}).then(function (users) {
            content.removeObjects(self.get('users'));
            content.pushObjects(users.users.map(function (user) {
                return {
                    id: user.slug,
                    title: user.name,
                    category: 'Users'
                };
            }));
        });
    },

    _setKeymasterScope: function () {
        key.setScope('search-input');
    },

    _resetKeymasterScope: function () {
        key.setScope('default');
    },

    willDestroy: function () {
        this._resetKeymasterScope();
    },

    actions: {
        openSelected: function (selected) {
            var transition = null,
                self = this;

            if (!selected) { return; }

            if (selected.category === 'Posts' || selected.category === 'Pages') {
                transition = self.get('_routing.router').transitionTo('editor.edit', selected.id);
            }

            if (selected.category === 'Users') {
                transition = self.get('_routing.router').transitionTo('team.user', selected.id);
            }

            self.set('selection', '');
            transition.then(function () {
                if (self.get('_selectize').$control_input.is(':focus')) {
                    self._setKeymasterScope();
                }
            });
        },

        focusInput: function () {
            this.get('_selectize').focus();
        },

        onInit: function () {
            var selectize = this.get('_selectize'),
                html = '
Nothing found…
';

            selectize.$empty_results_container = $(html);
            selectize.$empty_results_container.hide();
            selectize.$dropdown.append(selectize.$empty_results_container);
        },

        onFocus: function () {
            this._setKeymasterScope();
            this.refreshContent();
        },

        onBlur: function () {
            var selectize = this.get('_selectize');

            this._resetKeymasterScope();
            selectize.$empty_results_container.hide();
        },

        onType: function () {
            var selectize = this.get('_selectize');

            if (!selectize.hasOptions) {
                selectize.open();
                selectize.$empty_results_container.show();
            } else {
                selectize.$empty_results_container.hide();
            }
        }
    }

});
<commit_msg>Fix selected search item appearing as multi-select item in search input<commit_after>import Ember from 'ember';
import {request as ajax} from 'ic-ajax';
/* global key */

export default Ember.Component.extend({

    selection: null,
    content: [],
    isLoading: false,
    contentExpiry: 60 * 1000,
    contentExpiresAt: false,

    posts: Ember.computed.filterBy('content', 'category', 'Posts'),
    pages: Ember.computed.filterBy('content', 'category', 'Pages'),
    users: Ember.computed.filterBy('content', 'category', 'Users'),

    _store: Ember.inject.service('store'),
    _routing: Ember.inject.service('-routing'),
    _selectize: Ember.computed(function () {
        return this.$('select')[0].selectize;
    }),

    refreshContent: function () {
        var promises = [],
            now = new Date(),
            contentExpiry = this.get('contentExpiry'),
            contentExpiresAt = this.get('contentExpiresAt'),
            self = this;

        if (self.get('isLoading') || contentExpiresAt > now) { return; }

        self.set('isLoading', true);
        promises.pushObject(this._loadPosts());
        promises.pushObject(this._loadUsers());

        Ember.RSVP.all(promises).then(function () { }).finally(function () {
            self.set('isLoading', false);
            self.set('contentExpiresAt', new Date(now.getTime() + contentExpiry));
        });
    },

    _loadPosts: function () {
        var store = this.get('_store'),
            postsUrl = store.adapterFor('post').urlForFindQuery({}, 'post') + '/',
            postsQuery = {fields: 'id,title,page', limit: 'all', status: 'all', staticPages: 'all'},
            content = this.get('content'),
            self = this;

        return ajax(postsUrl, {data: postsQuery}).then(function (posts) {
            content.removeObjects(self.get('posts'));
            content.removeObjects(self.get('pages'));
            content.pushObjects(posts.posts.map(function (post) {
                return {
                    id: post.id,
                    title: post.title,
                    category: post.page ? 'Pages' : 'Posts'
                };
            }));
        });
    },

    _loadUsers: function () {
        var store = this.get('_store'),
            usersUrl = store.adapterFor('user').urlForFindQuery({}, 'user') + '/',
            usersQuery = {fields: 'name,slug', limit: 'all'},
            content = this.get('content'),
            self = this;

        return ajax(usersUrl, {data: usersQuery}).then(function (users) {
            content.removeObjects(self.get('users'));
            content.pushObjects(users.users.map(function (user) {
                return {
                    id: user.slug,
                    title: user.name,
                    category: 'Users'
                };
            }));
        });
    },

    _keepSelectionClear: Ember.observer('selection', function () {
        if (this.get('selection') !== null) {
            this.set('selection', null);
        }
    }),

    _setKeymasterScope: function () {
        key.setScope('search-input');
    },

    _resetKeymasterScope: function () {
        key.setScope('default');
    },

    willDestroy: function () {
        this._resetKeymasterScope();
    },

    actions: {
        openSelected: function (selected) {
            var transition = null,
                self = this;

            if (!selected) { return; }

            if (selected.category === 'Posts' || selected.category === 'Pages') {
                transition = self.get('_routing.router').transitionTo('editor.edit', selected.id);
            }

            if (selected.category === 'Users') {
                transition = self.get('_routing.router').transitionTo('team.user', selected.id);
            }

            transition.then(function () {
                if (self.get('_selectize').$control_input.is(':focus')) {
                    self._setKeymasterScope();
                }
            });
        },

        focusInput: function () {
            this.get('_selectize').focus();
        },

        onInit: function () {
            var selectize = this.get('_selectize'),
                html = '
Nothing found…
';

            selectize.$empty_results_container = $(html);
            selectize.$empty_results_container.hide();
            selectize.$dropdown.append(selectize.$empty_results_container);
        },

        onFocus: function () {
            this._setKeymasterScope();
            this.refreshContent();
        },

        onBlur: function () {
            var selectize = this.get('_selectize');

            this._resetKeymasterScope();
            selectize.$empty_results_container.hide();
        },

        onType: function () {
            var selectize = this.get('_selectize');

            if (!selectize.hasOptions) {
                selectize.open();
                selectize.$empty_results_container.show();
            } else {
                selectize.$empty_results_container.hide();
            }
        }
    }

});
<|endoftext|>


<commit_before>import React, {
  forwardRef,
  useContext,
  useEffect,
  useRef,
  useState,
} from 'react';
import styled, { ThemeContext } from 'styled-components';
import { defaultProps } from '../../default-props';

import { FocusedContainer } from '../FocusedContainer';
import { Keyboard } from '../Keyboard';
import { backgroundIsDark, findVisibleParent } from '../../utils';

import { StyledLayer, StyledContainer, StyledOverlay } from './StyledLayer';

const HiddenAnchor = styled.a`
  width: 0;
  height: 0;
  overflow: hidden;
  position: absolute;
`;

const fullBounds = { left: 0, right: 0, top: 0, bottom: 0 };

const LayerContainer = forwardRef(
  (
    {
      children,
      full = false,
      id,
      margin = 'none',
      modal = true,
      onClickOutside,
      onEsc,
      plain,
      position = 'center',
      responsive = true,
      target: layerTarget,
      ...rest
    },
    ref,
  ) => {
    const theme = useContext(ThemeContext) || defaultProps.theme;
    const [targetBounds, setTargetBounds] = useState(fullBounds);
    const anchorRef = useRef();
    const containerRef = useRef();
    const layerRef = useRef();

    useEffect(() => {
      if (position !== 'hidden') {
        const node = layerRef.current || containerRef.current || ref.current;
        if (node && node.scrollIntoView) node.scrollIntoView();
        // Once layer is open we make sure it has focus so that you
        // can start tabbing inside the layer. If the caller put focus
        // on an element already, we honor that. Otherwise, we put
        // the focus in the hidden anchor.
        let element = document.activeElement;
        while (element) {
          if (element === containerRef.current) {
            // already have focus inside the container
            break;
          }
          element = element.parentElement;
        }
        if (modal && !element && anchorRef.current) {
          anchorRef.current.focus();
        }
      }
    }, [modal, position, ref]);

    useEffect(() => {
      if (position !== 'hidden') {
        const node = layerRef.current || containerRef.current || ref.current;
        if (node && node.scrollIntoView) node.scrollIntoView();
      }
    }, [position, ref]);

    useEffect(() => {
      if (layerTarget) {
        const updateBounds = () => {
          const rect = findVisibleParent(layerTarget).getBoundingClientRect();
          setTargetBounds({
            left: rect.left,
            right: window.innerWidth - rect.right,
            top: rect.top,
            bottom: window.innerHeight - rect.bottom,
          });
        };

        updateBounds();
        window.addEventListener('resize', updateBounds);
        return () => window.removeEventListener('resize', updateBounds);
      }
      setTargetBounds(fullBounds);
      return undefined;
    }, [layerTarget]);

    let content = (
      <StyledContainer
        ref={ref || containerRef}
        id={id}
        full={full}
        margin={margin}
        modal={modal}
        targetBounds={!modal ? targetBounds : fullBounds}
        {...rest}
        position={position}
        plain={plain}
        responsive={responsive}
        dir={theme.dir}
      >
        {/* eslint-disable max-len */}
        {/* eslint-disable jsx-a11y/anchor-is-valid, jsx-a11y/anchor-has-content */}
        <HiddenAnchor ref={anchorRef} tabIndex="-1" aria-hidden="true" />
        {/* eslint-enable jsx-a11y/anchor-is-valid, jsx-a11y/anchor-has-content */}
        {/* eslint-enable max-len */}
        {children}
      </StyledContainer>
    );
    if (modal) {
      content = (
        <StyledLayer
          ref={layerRef}
          id={id}
          targetBounds={targetBounds}
          plain={plain}
          position={position}
          responsive={responsive}
          tabIndex="-1"
          dir={theme.dir}
        >
          <StyledOverlay
            plain={plain}
            onMouseDown={onClickOutside}
            responsive={responsive}
          />
          {content}
        </StyledLayer>
      );
    }

    if (onEsc) {
      content = <Keyboard onEsc={onEsc}>{content}</Keyboard>;
    }

    if (theme.layer.background) {
      const dark = backgroundIsDark(theme.layer.background, theme);
      if (dark !== undefined && dark !== theme.dark) {
        content = (
          <ThemeContext.Provider value={{ ...theme, dark }}>
            {content}
          </ThemeContext.Provider>
        );
      }
    }
    if (modal) {
      content = (
        <FocusedContainer hidden={position === 'hidden'} restrictScroll>
          {content}
        </FocusedContainer>
      );
    }

    return content;
  },
);

export { LayerContainer };
<commit_msg>Changed LayerContainer to use trapFocus (#4735)<commit_after>import React, {
  forwardRef,
  useContext,
  useEffect,
  useRef,
  useState,
} from 'react';
import styled, { ThemeContext } from 'styled-components';
import { defaultProps } from '../../default-props';

import { FocusedContainer } from '../FocusedContainer';
import { Keyboard } from '../Keyboard';
import { backgroundIsDark, findVisibleParent } from '../../utils';

import { StyledLayer, StyledContainer, StyledOverlay } from './StyledLayer';

const HiddenAnchor = styled.a`
  width: 0;
  height: 0;
  overflow: hidden;
  position: absolute;
`;

const fullBounds = { left: 0, right: 0, top: 0, bottom: 0 };

const LayerContainer = forwardRef(
  (
    {
      children,
      full = false,
      id,
      margin = 'none',
      modal = true,
      onClickOutside,
      onEsc,
      plain,
      position = 'center',
      responsive = true,
      target: layerTarget,
      ...rest
    },
    ref,
  ) => {
    const theme = useContext(ThemeContext) || defaultProps.theme;
    const [targetBounds, setTargetBounds] = useState(fullBounds);
    const anchorRef = useRef();
    const containerRef = useRef();
    const layerRef = useRef();

    useEffect(() => {
      if (position !== 'hidden') {
        const node = layerRef.current || containerRef.current || ref.current;
        if (node && node.scrollIntoView) node.scrollIntoView();
        // Once layer is open we make sure it has focus so that you
        // can start tabbing inside the layer. If the caller put focus
        // on an element already, we honor that. Otherwise, we put
        // the focus in the hidden anchor.
        let element = document.activeElement;
        while (element) {
          if (element === containerRef.current) {
            // already have focus inside the container
            break;
          }
          element = element.parentElement;
        }
        if (modal && !element && anchorRef.current) {
          anchorRef.current.focus();
        }
      }
    }, [modal, position, ref]);

    useEffect(() => {
      if (position !== 'hidden') {
        const node = layerRef.current || containerRef.current || ref.current;
        if (node && node.scrollIntoView) node.scrollIntoView();
      }
    }, [position, ref]);

    useEffect(() => {
      if (layerTarget) {
        const updateBounds = () => {
          const rect = findVisibleParent(layerTarget).getBoundingClientRect();
          setTargetBounds({
            left: rect.left,
            right: window.innerWidth - rect.right,
            top: rect.top,
            bottom: window.innerHeight - rect.bottom,
          });
        };

        updateBounds();
        window.addEventListener('resize', updateBounds);
        return () => window.removeEventListener('resize', updateBounds);
      }
      setTargetBounds(fullBounds);
      return undefined;
    }, [layerTarget]);

    let content = (
      <StyledContainer
        ref={ref || containerRef}
        id={id}
        full={full}
        margin={margin}
        modal={modal}
        targetBounds={!modal ? targetBounds : fullBounds}
        {...rest}
        position={position}
        plain={plain}
        responsive={responsive}
        dir={theme.dir}
      >
        {/* eslint-disable max-len */}
        {/* eslint-disable jsx-a11y/anchor-is-valid, jsx-a11y/anchor-has-content */}
        <HiddenAnchor ref={anchorRef} tabIndex="-1" aria-hidden="true" />
        {/* eslint-enable jsx-a11y/anchor-is-valid, jsx-a11y/anchor-has-content */}
        {/* eslint-enable max-len */}
        {children}
      </StyledContainer>
    );
    if (modal) {
      content = (
        <StyledLayer
          ref={layerRef}
          id={id}
          targetBounds={targetBounds}
          plain={plain}
          position={position}
          responsive={responsive}
          tabIndex="-1"
          dir={theme.dir}
        >
          <StyledOverlay
            plain={plain}
            onMouseDown={onClickOutside}
            responsive={responsive}
          />
          {content}
        </StyledLayer>
      );
    }

    if (onEsc) {
      content = <Keyboard onEsc={onEsc}>{content}</Keyboard>;
    }

    if (theme.layer.background) {
      const dark = backgroundIsDark(theme.layer.background, theme);
      if (dark !== undefined && dark !== theme.dark) {
        content = (
          <ThemeContext.Provider value={{ ...theme, dark }}>
            {content}
          </ThemeContext.Provider>
        );
      }
    }
    if (modal) {
      content = (
        <FocusedContainer
          hidden={position === 'hidden'}
          restrictScroll
          trapFocus
        >
          {content}
        </FocusedContainer>
      );
    }

    return content;
  },
);

export { LayerContainer };
<|endoftext|>


<commit_before>// import Divmod.UnitTest
// import Methanal.Preds
// import Methanal.Validators
// import Methanal.Util
// import Methanal.Tests.Util

Methanal.Tests.Util.TestCase.subclass(
    Methanal.Tests.TestValidators, 'ValidatorsTestCase').methods(
    /**
     * Assert that C{value} is a valid input for C{validator}.
     */
    function assertValid(self, validator /*...*/) {
        var args = Array.prototype.slice.call(arguments, 2);
        var msg = validator.apply(null, args);
        self.assertIdentical(msg, undefined,
            'Expected valid input for ' + Methanal.Util.repr(validator) +
            ' (' + Methanal.Util.repr(args) + '), got: ' +
            Methanal.Util.repr(msg));
    },

    /**
     * Assert that C{value} is NOT a valid input for C{validator}.
     */
    function assertInvalid(self, validator /*...*/) {
        var args = Array.prototype.slice.call(arguments, 2);
        self.assertNotIdentical(validator.apply(null, args), undefined,
            'Expected invalid input for ' + Methanal.Util.repr(validator) +
            ', got: ' + Methanal.Util.repr(args));
    });

Methanal.Tests.TestValidators.ValidatorsTestCase.subclass(
    Methanal.Tests.TestValidators, 'TestValidators').methods(
    /**
     * Validator with an inverted predicate.
     */
    function test_invert(self) {
        var x = Methanal.Validators.pred(
            Methanal.Preds.invert(Methanal.Preds.lengthOf(3)),
            'Length cannot be 3');
        self.assertValid(x, 'a');
        self.assertValid(x, 'ab');
        self.assertInvalid(x, 'abc');
        self.assertValid(x, 'abcd');
    },

    /**
     * Logical intersection of combined validator results.
     */
    function test_intersection(self) {
        var even = Methanal.Validators.pred(function (n) {
            return n % 2 === 0;
        }, 'Must be even');
        var x = Methanal.Validators.intersection([
            Methanal.Validators.notNull, Methanal.Validators.numeric, even]);
        self.assertValid(x, '2');
        self.assertValid(x, '42');
        self.assertInvalid(x, '3');
        self.assertInvalid(x, 'a');
        self.assertInvalid(x, null);
    },

    /**
     * Any input, but at least one, value must pass the predicate C{func}.
     */
    function test_any(self) {
        var x = Methanal.Validators.any(Methanal.Preds.hasLength);
        self.assertValid(x, '1');
        self.assertValid(x, '1', '2');
        self.assertValid(x, null, '2');
        self.assertValid(x, '1', null);
        self.assertValid(x, '1', '', '3');
        self.assertInvalid(x, '', null);
        self.assertInvalid(x, '', null, '');
    },

    /**
     * All input values must pass the predicate C{func}.
     */
    function test_all(self) {
        var x = Methanal.Validators.all(Methanal.Preds.hasLength);
        self.assertValid(x, '1');
        self.assertValid(x, '1', '2');
        self.assertInvalid(x, null, '2');
        self.assertInvalid(x, '1', null);
        self.assertInvalid(x, '1', null, '3');
    },

    /**
     * Create a validator that is only executed if C{pred} is C{true}.
     */
    function test_ifThen(self) {
        var x = Methanal.Validators.ifThen(
            Methanal.Preds.notNull,
            Methanal.Validators.alpha);
        self.assertValid(x, null);
        self.assertValid(x, 'a');
        self.assertValid(x, 'abc');
        self.assertInvalid(x, 'abc1');
        self.assertInvalid(x, 'abc_');
    },

    /**
     * Value is defined and has non-zero, positive length.
     */
    function test_hasLength(self) {
        var hasLength = Methanal.Validators.hasLength;
        self.assertValid(hasLength, 'foo');
        self.assertInvalid(hasLength, '');
        self.assertInvalid(hasLength, null);
    },

    /**
     * Value has a length of exactly C{n}.
     */
    function test_lengthOf(self) {
        var lengthOf = Methanal.Validators.lengthOf;
        self.assertValid(lengthOf(0), '');
        self.assertValid(lengthOf(3), 'foo');
        self.assertInvalid(lengthOf(3), '');
        self.assertInvalid(lengthOf(3), null);
        self.assertInvalid(lengthOf(3), undefined);
    },

    /**
     * Value has a length of at least C{n}.
     */
    function test_lengthAtLeast(self) {
        var lengthAtLeast = Methanal.Validators.lengthAtLeast;
        self.assertValid(lengthAtLeast(2), 'quux');
        self.assertValid(lengthAtLeast(2), 'foo');
        self.assertValid(lengthAtLeast(2), 'hi');
        self.assertInvalid(lengthAtLeast(2), 'a');
        self.assertInvalid(lengthAtLeast(2), '');
        self.assertInvalid(lengthAtLeast(2), null);
        self.assertInvalid(lengthAtLeast(2), undefined);
    },

    /**
     * Value has a length of at most C{n}.
     */
    function test_lengthAtMost(self) {
        var lengthAtMost = Methanal.Validators.lengthAtMost;
        self.assertInvalid(lengthAtMost(2), 'quux');
        self.assertInvalid(lengthAtMost(2), 'foo');
        self.assertValid(lengthAtMost(2), 'hi');
        self.assertValid(lengthAtMost(2), 'a');
        self.assertValid(lengthAtMost(2), '');
        self.assertInvalid(lengthAtMost(2), null);
        self.assertInvalid(lengthAtMost(2), undefined);
    },

    /**
     * Value is not null.
     */
    function test_notNull(self) {
        var notNull = Methanal.Validators.notNull;
        self.assertValid(notNull, 2);
        self.assertValid(notNull, '');
        self.assertValid(notNull, []);
        self.assertInvalid(notNull, null);
    },

    /**
     * Value is within a given range.
     */
    function test_between(self) {
        var between = Methanal.Validators.between;
        self.assertValid(between(0, 3), 1);
        self.assertValid(between(0, 3), 3);
        self.assertValid(between(-3, 3), 0);
        self.assertInvalid(between(-3, 3), 4);
        self.assertInvalid(between(-3, 3), -4);
    },

    /**
     * Value is less than C{n}.
     */
    function test_lessThan(self) {
        var lessThan = Methanal.Validators.lessThan;
        self.assertValid(lessThan(3), 2);
        self.assertValid(lessThan(0), -1);
        self.assertValid(lessThan(-1), -2);
        self.assertInvalid(lessThan(3), 3);
        self.assertInvalid(lessThan(0), 3);
    },

    /**
     * Value is at most (or, not greater than; or less than or equal to) C{n}.
     */
    function test_atMost(self) {
        var atMost = Methanal.Validators.atMost;
        self.assertValid(atMost(3), 2);
        self.assertValid(atMost(0), -1);
        self.assertValid(atMost(-1), -2);
        self.assertValid(atMost(3), 3);
        self.assertInvalid(atMost(0), 3);
    },

    /**
     * Value is greater than C{n}.
     */
    function test_greaterThan(self) {
        var greaterThan = Methanal.Validators.greaterThan;
        self.assertValid(greaterThan(2), 3);
        self.assertValid(greaterThan(-1), 0);
        self.assertValid(greaterThan(-2), -1);
        self.assertInvalid(greaterThan(3), 3);
        self.assertInvalid(greaterThan(0), -1);
        self.assertInvalid(greaterThan(3), 1);
    },

    /**
     * Value is at least (or, not less than; or greater than or equal to) C{n}.
     */
    function test_atLeast(self) {
        var atLeast = Methanal.Validators.atLeast;
        self.assertValid(atLeast(2), 3);
        self.assertValid(atLeast(-1), 0);
        self.assertValid(atLeast(-2), -1);
        self.assertValid(atLeast(3), 3);
        self.assertInvalid(atLeast(0), -1);
        self.assertInvalid(atLeast(3), 1);
    },

    /**
     * Value is a multiple of C{n}.
     */
    function test_multipleOf(self) {
        var multipleOf = Methanal.Validators.multipleOf;
        self.assertValid(multipleOf(3), 3);
        self.assertValid(multipleOf(3), 6);
        self.assertValid(multipleOf(2), -8);
        self.assertInvalid(multipleOf(2), 1);
        self.assertInvalid(multipleOf(2), 0);
    },

    /**
     * Value is one of a given set.
     */
    function test_oneOf(self) {
        var oneOf = Methanal.Validators.oneOf;
        self.assertValid(oneOf(['foo', 'bar']), 'foo');
        self.assertInvalid(oneOf(['foo', 'bar']), 'baz');
        self.assertInvalid(oneOf(['foo', 'bar']), '');
        self.assertInvalid(oneOf([]), 'foo');
        self.assertInvalid(oneOf([]), '');
    },

    /**
     * Value contains a subset (in no particular order) of an C{Array}.
     */
    function test_arraySubset(self) {
        var arraySubset = Methanal.Validators.arraySubset;
        var x = ['a', 'b'];
        self.assertValid(arraySubset([]), x);
        self.assertValid(arraySubset(['a']), x);
        self.assertValid(arraySubset(['b']), x);
        self.assertValid(arraySubset(['a', 'b']), x);
        self.assertInvalid(arraySubset(['c']), x);
        self.assertInvalid(arraySubset(['a', 'c']), x);
    },

    /**
     * Value contains only characters matching a regular expression character
     * class.
     */
    function test_isChars(self) {
        var isChars = Methanal.Validators.isChars;
        self.assertValid(isChars('[0-9]'), '0123456789')
        self.assertValid(isChars('[A-Z]'), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')
        self.assertValid(isChars('[a-z]'), 'abcdefghijklmnopqrstuvwxyz')
        self.assertValid(isChars("[a-z_']"), "hello_world's")
        self.assertInvalid(isChars('[0-9]'), 'hello')
    },

    /**
     * Value consists of only digits.
     */
    function test_numeric(self) {
        var numeric = Methanal.Validators.numeric;
        self.assertValid(numeric, '0123456789');
        self.assertInvalid(numeric, '0a');
        self.assertInvalid(numeric, '0._');
    },

    /**
     * Value consists of only letters.
     */
    function test_alpha(self) {
        var alpha = Methanal.Validators.alpha;
        self.assertValid(alpha, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')
        self.assertValid(alpha, 'abcdefghijklmnopqrstuvwxyz')
        self.assertInvalid(alpha, '0a');
        self.assertInvalid(alpha, '0._');
    },

    /**
     * Value consists of only letters and digits.
     */
    function test_alphaNumeric(self) {
        var alphaNumeric = Methanal.Validators.alphaNumeric;
        self.assertValid(alphaNumeric, '0123456789');
        self.assertValid(alphaNumeric, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')
        self.assertValid(alphaNumeric, 'abcdefghijklmnopqrstuvwxyz')
        self.assertValid(alphaNumeric, '0a');
        self.assertInvalid(alphaNumeric, '0._');
    },

    /**
     * Value is a valid, or blank, e-mail address.
     */
    function test_email(self) {
        var email = Methanal.Validators.email;
        self.assertValid(email, null);
        self.assertValid(email, '');
        self.assertValid(email, 'foo@bar.com');
        self.assertValid(email, 'f0o.baz-qu_ux@b4r.com');
        self.assertValid(email, 'f0o.baz-qu_ux@b4r.co.za');
        self.assertValid(email, 'foo+baz@bar.com');
        self.assertInvalid(email, 'hello');
        self.assertInvalid(email, 'hello@');
        self.assertInvalid(email, 'hello@world');
        self.assertInvalid(email, '@bar.com');
        self.assertInvalid(email, '@bar.comhaha');
    },

    /**
     * Value is within a timedelta and a start date.
     */
    function test_dateSince(self) {
        var now = Methanal.Util.Time().oneDay();
        var tomorrow = now.offset(
            Methanal.Util.TimeDelta({'days': 1}));
        var nextDay = now.offset(
            Methanal.Util.TimeDelta({'days': 2}));

        var dateSince = Methanal.Validators.dateSince;
        self.assertValid(
            dateSince(Methanal.Util.TimeDelta({'days': 2}), tomorrow),
            nextDay.asDate());
        self.assertValid(
            dateSince(Methanal.Util.TimeDelta({'days': 2}), tomorrow),
            nextDay.asTimestamp());
        self.assertInvalid(
            dateSince(Methanal.Util.TimeDelta({'hours': 1}), tomorrow),
            nextDay.asDate());
        self.assertInvalid(
            dateSince(Methanal.Util.TimeDelta({'days': 1}), tomorrow),
            nextDay.asTimestamp());
    },

    /**
     * Value is within a timedelta and the current time.
     */
    function test_dateWithin(self) {
        var now = Methanal.Util.Time();
        var tomorrow = now.offset(
            Methanal.Util.TimeDelta({'days': 1, 'minutes': 10}));

        var dateWithin = Methanal.Validators.dateWithin;
        self.assertValid(
            dateWithin(Methanal.Util.TimeDelta({'hours': 1})),
            now.offset(Methanal.Util.TimeDelta({'minutes': 30})).asDate());
        self.assertValid(
            dateWithin(Methanal.Util.TimeDelta({'days': 1,
                                                'minutes': 30})),
            tomorrow.asTimestamp());
        self.assertInvalid(
            dateWithin(Methanal.Util.TimeDelta({'days': 1})),
            tomorrow.asDate());

        var yesterday = now.offset(
            Methanal.Util.TimeDelta({'days': -1, 'minutes': -10}));
        self.assertValid(
            dateWithin(Methanal.Util.TimeDelta({'hours': -1})),
            now.offset(Methanal.Util.TimeDelta({'minutes': -30})).asDate());
        self.assertValid(
            dateWithin(Methanal.Util.TimeDelta({'days': -1,
                                                'minutes': -30})),
            yesterday.asDate());
        // XXX: Fudge it slightly since dateWithin uses the current time and
        // sometimes things take some time.
        self.assertInvalid(
            dateWithin(Methanal.Util.TimeDelta({'days': -1})),
            yesterday.asDate());
        self.assertInvalid(
            dateWithin(Methanal.Util.TimeDelta({'days': -1})),
            yesterday.asTimestamp());
    },

    /**
     * Value is a future date.
     */
    function test_futureDate(self) {
        var now = Methanal.Util.Time();
        var yesterday = now.offset(
            Methanal.Util.TimeDelta({'days': -1})).asDate();
        var tomorrow = now.offset(
            Methanal.Util.TimeDelta({'days': 1})).asDate();
        var futureDate = Methanal.Validators.futureDate;
        self.assertValid(futureDate, tomorrow);
        self.assertInvalid(futureDate, yesterday);
    },

    /**
     * Value is a past date.
     */
    function test_pastDate(self) {
        var now = Methanal.Util.Time();
        var yesterday = now.offset(
            Methanal.Util.TimeDelta({'days': -1})).asDate();
        var tomorrow = now.offset(
            Methanal.Util.TimeDelta({'days': 1})).asDate();
        var pastDate = Methanal.Validators.pastDate;
        self.assertInvalid(pastDate, tomorrow);
        self.assertValid(pastDate, yesterday);
    });
<commit_msg>Make test_any and test_all easier to follow.<commit_after>// import Divmod.UnitTest
// import Methanal.Preds
// import Methanal.Validators
// import Methanal.Util
// import Methanal.Tests.Util

Methanal.Tests.Util.TestCase.subclass(
    Methanal.Tests.TestValidators, 'ValidatorsTestCase').methods(
    /**
     * Assert that C{value} is a valid input for C{validator}.
     */
    function assertValid(self, validator /*...*/) {
        var args = Array.prototype.slice.call(arguments, 2);
        var msg = validator.apply(null, args);
        self.assertIdentical(msg, undefined,
            'Expected valid input for ' + Methanal.Util.repr(validator) +
            ' (' + Methanal.Util.repr(args) + '), got: ' +
            Methanal.Util.repr(msg));
    },

    /**
     * Assert that C{value} is NOT a valid input for C{validator}.
     */
    function assertInvalid(self, validator /*...*/) {
        var args = Array.prototype.slice.call(arguments, 2);
        self.assertNotIdentical(validator.apply(null, args), undefined,
            'Expected invalid input for ' + Methanal.Util.repr(validator) +
            ', got: ' + Methanal.Util.repr(args));
    });

Methanal.Tests.TestValidators.ValidatorsTestCase.subclass(
    Methanal.Tests.TestValidators, 'TestValidators').methods(
    /**
     * Validator with an inverted predicate.
     */
    function test_invert(self) {
        var x = Methanal.Validators.pred(
            Methanal.Preds.invert(Methanal.Preds.lengthOf(3)),
            'Length cannot be 3');
        self.assertValid(x, 'a');
        self.assertValid(x, 'ab');
        self.assertInvalid(x, 'abc');
        self.assertValid(x, 'abcd');
    },

    /**
     * Logical intersection of combined validator results.
     */
    function test_intersection(self) {
        var even = Methanal.Validators.pred(function (n) {
            return n % 2 === 0;
        }, 'Must be even');
        var x = Methanal.Validators.intersection([
            Methanal.Validators.notNull, Methanal.Validators.numeric, even]);
        self.assertValid(x, '2');
        self.assertValid(x, '42');
        self.assertInvalid(x, '3');
        self.assertInvalid(x, 'a');
        self.assertInvalid(x, null);
    },

    /**
     * Any input, but at least one, value must pass the predicate C{func}.
     */
    function test_any(self) {
        var any = Methanal.Validators.any(
            function identity(x) { return x });
        self.assertValid(any, true);
        self.assertValid(any, true, true);
        self.assertValid(any, false, true);
        self.assertValid(any, true, false);
        self.assertValid(any, true, false, true);
        self.assertInvalid(any, false);
        self.assertInvalid(any, false, false);
    },

    /**
     * All input values must pass the predicate C{func}.
     */
    function test_all(self) {
        var all = Methanal.Validators.all(
            function identity(x) { return x });
        self.assertValid(all, true);
        self.assertValid(all, true, true);
        self.assertInvalid(all, false, true);
        self.assertInvalid(all, false, true);
        self.assertInvalid(all, false, true, false);
    },

    /**
     * Create a validator that is only executed if C{pred} is C{true}.
     */
    function test_ifThen(self) {
        var x = Methanal.Validators.ifThen(
            Methanal.Preds.notNull,
            Methanal.Validators.alpha);
        self.assertValid(x, null);
        self.assertValid(x, 'a');
        self.assertValid(x, 'abc');
        self.assertInvalid(x, 'abc1');
        self.assertInvalid(x, 'abc_');
    },

    /**
     * Value is defined and has non-zero, positive length.
     */
    function test_hasLength(self) {
        var hasLength = Methanal.Validators.hasLength;
        self.assertValid(hasLength, 'foo');
        self.assertInvalid(hasLength, '');
        self.assertInvalid(hasLength, null);
    },

    /**
     * Value has a length of exactly C{n}.
     */
    function test_lengthOf(self) {
        var lengthOf = Methanal.Validators.lengthOf;
        self.assertValid(lengthOf(0), '');
        self.assertValid(lengthOf(3), 'foo');
        self.assertInvalid(lengthOf(3), '');
        self.assertInvalid(lengthOf(3), null);
        self.assertInvalid(lengthOf(3), undefined);
    },

    /**
     * Value has a length of at least C{n}.
     */
    function test_lengthAtLeast(self) {
        var lengthAtLeast = Methanal.Validators.lengthAtLeast;
        self.assertValid(lengthAtLeast(2), 'quux');
        self.assertValid(lengthAtLeast(2), 'foo');
        self.assertValid(lengthAtLeast(2), 'hi');
        self.assertInvalid(lengthAtLeast(2), 'a');
        self.assertInvalid(lengthAtLeast(2), '');
        self.assertInvalid(lengthAtLeast(2), null);
        self.assertInvalid(lengthAtLeast(2), undefined);
    },

    /**
     * Value has a length of at most C{n}.
     */
    function test_lengthAtMost(self) {
        var lengthAtMost = Methanal.Validators.lengthAtMost;
        self.assertInvalid(lengthAtMost(2), 'quux');
        self.assertInvalid(lengthAtMost(2), 'foo');
        self.assertValid(lengthAtMost(2), 'hi');
        self.assertValid(lengthAtMost(2), 'a');
        self.assertValid(lengthAtMost(2), '');
        self.assertInvalid(lengthAtMost(2), null);
        self.assertInvalid(lengthAtMost(2), undefined);
    },

    /**
     * Value is not null.
     */
    function test_notNull(self) {
        var notNull = Methanal.Validators.notNull;
        self.assertValid(notNull, 2);
        self.assertValid(notNull, '');
        self.assertValid(notNull, []);
        self.assertInvalid(notNull, null);
    },

    /**
     * Value is within a given range.
     */
    function test_between(self) {
        var between = Methanal.Validators.between;
        self.assertValid(between(0, 3), 1);
        self.assertValid(between(0, 3), 3);
        self.assertValid(between(-3, 3), 0);
        self.assertInvalid(between(-3, 3), 4);
        self.assertInvalid(between(-3, 3), -4);
    },

    /**
     * Value is less than C{n}.
     */
    function test_lessThan(self) {
        var lessThan = Methanal.Validators.lessThan;
        self.assertValid(lessThan(3), 2);
        self.assertValid(lessThan(0), -1);
        self.assertValid(lessThan(-1), -2);
        self.assertInvalid(lessThan(3), 3);
        self.assertInvalid(lessThan(0), 3);
    },

    /**
     * Value is at most (or, not greater than; or less than or equal to) C{n}.
     */
    function test_atMost(self) {
        var atMost = Methanal.Validators.atMost;
        self.assertValid(atMost(3), 2);
        self.assertValid(atMost(0), -1);
        self.assertValid(atMost(-1), -2);
        self.assertValid(atMost(3), 3);
        self.assertInvalid(atMost(0), 3);
    },

    /**
     * Value is greater than C{n}.
     */
    function test_greaterThan(self) {
        var greaterThan = Methanal.Validators.greaterThan;
        self.assertValid(greaterThan(2), 3);
        self.assertValid(greaterThan(-1), 0);
        self.assertValid(greaterThan(-2), -1);
        self.assertInvalid(greaterThan(3), 3);
        self.assertInvalid(greaterThan(0), -1);
        self.assertInvalid(greaterThan(3), 1);
    },

    /**
     * Value is at least (or, not less than; or greater than or equal to) C{n}.
     */
    function test_atLeast(self) {
        var atLeast = Methanal.Validators.atLeast;
        self.assertValid(atLeast(2), 3);
        self.assertValid(atLeast(-1), 0);
        self.assertValid(atLeast(-2), -1);
        self.assertValid(atLeast(3), 3);
        self.assertInvalid(atLeast(0), -1);
        self.assertInvalid(atLeast(3), 1);
    },

    /**
     * Value is a multiple of C{n}.
     */
    function test_multipleOf(self) {
        var multipleOf = Methanal.Validators.multipleOf;
        self.assertValid(multipleOf(3), 3);
        self.assertValid(multipleOf(3), 6);
        self.assertValid(multipleOf(2), -8);
        self.assertInvalid(multipleOf(2), 1);
        self.assertInvalid(multipleOf(2), 0);
    },

    /**
     * Value is one of a given set.
     */
    function test_oneOf(self) {
        var oneOf = Methanal.Validators.oneOf;
        self.assertValid(oneOf(['foo', 'bar']), 'foo');
        self.assertInvalid(oneOf(['foo', 'bar']), 'baz');
        self.assertInvalid(oneOf(['foo', 'bar']), '');
        self.assertInvalid(oneOf([]), 'foo');
        self.assertInvalid(oneOf([]), '');
    },

    /**
     * Value contains a subset (in no particular order) of an C{Array}.
     */
    function test_arraySubset(self) {
        var arraySubset = Methanal.Validators.arraySubset;
        var x = ['a', 'b'];
        self.assertValid(arraySubset([]), x);
        self.assertValid(arraySubset(['a']), x);
        self.assertValid(arraySubset(['b']), x);
        self.assertValid(arraySubset(['a', 'b']), x);
        self.assertInvalid(arraySubset(['c']), x);
        self.assertInvalid(arraySubset(['a', 'c']), x);
    },

    /**
     * Value contains only characters matching a regular expression character
     * class.
     */
    function test_isChars(self) {
        var isChars = Methanal.Validators.isChars;
        self.assertValid(isChars('[0-9]'), '0123456789')
        self.assertValid(isChars('[A-Z]'), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')
        self.assertValid(isChars('[a-z]'), 'abcdefghijklmnopqrstuvwxyz')
        self.assertValid(isChars("[a-z_']"), "hello_world's")
        self.assertInvalid(isChars('[0-9]'), 'hello')
    },

    /**
     * Value consists of only digits.
     */
    function test_numeric(self) {
        var numeric = Methanal.Validators.numeric;
        self.assertValid(numeric, '0123456789');
        self.assertInvalid(numeric, '0a');
        self.assertInvalid(numeric, '0._');
    },

    /**
     * Value consists of only letters.
     */
    function test_alpha(self) {
        var alpha = Methanal.Validators.alpha;
        self.assertValid(alpha, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')
        self.assertValid(alpha, 'abcdefghijklmnopqrstuvwxyz')
        self.assertInvalid(alpha, '0a');
        self.assertInvalid(alpha, '0._');
    },

    /**
     * Value consists of only letters and digits.
     */
    function test_alphaNumeric(self) {
        var alphaNumeric = Methanal.Validators.alphaNumeric;
        self.assertValid(alphaNumeric, '0123456789');
        self.assertValid(alphaNumeric, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')
        self.assertValid(alphaNumeric, 'abcdefghijklmnopqrstuvwxyz')
        self.assertValid(alphaNumeric, '0a');
        self.assertInvalid(alphaNumeric, '0._');
    },

    /**
     * Value is a valid, or blank, e-mail address.
     */
    function test_email(self) {
        var email = Methanal.Validators.email;
        self.assertValid(email, null);
        self.assertValid(email, '');
        self.assertValid(email, 'foo@bar.com');
        self.assertValid(email, 'f0o.baz-qu_ux@b4r.com');
        self.assertValid(email, 'f0o.baz-qu_ux@b4r.co.za');
        self.assertValid(email, 'foo+baz@bar.com');
        self.assertInvalid(email, 'hello');
        self.assertInvalid(email, 'hello@');
        self.assertInvalid(email, 'hello@world');
        self.assertInvalid(email, '@bar.com');
        self.assertInvalid(email, '@bar.comhaha');
    },

    /**
     * Value is within a timedelta and a start date.
     */
    function test_dateSince(self) {
        var now = Methanal.Util.Time().oneDay();
        var tomorrow = now.offset(
            Methanal.Util.TimeDelta({'days': 1}));
        var nextDay = now.offset(
            Methanal.Util.TimeDelta({'days': 2}));

        var dateSince = Methanal.Validators.dateSince;
        self.assertValid(
            dateSince(Methanal.Util.TimeDelta({'days': 2}), tomorrow),
            nextDay.asDate());
        self.assertValid(
            dateSince(Methanal.Util.TimeDelta({'days': 2}), tomorrow),
            nextDay.asTimestamp());
        self.assertInvalid(
            dateSince(Methanal.Util.TimeDelta({'hours': 1}), tomorrow),
            nextDay.asDate());
        self.assertInvalid(
            dateSince(Methanal.Util.TimeDelta({'days': 1}), tomorrow),
            nextDay.asTimestamp());
    },

    /**
     * Value is within a timedelta and the current time.
     */
    function test_dateWithin(self) {
        var now = Methanal.Util.Time();
        var tomorrow = now.offset(
            Methanal.Util.TimeDelta({'days': 1, 'minutes': 10}));

        var dateWithin = Methanal.Validators.dateWithin;
        self.assertValid(
            dateWithin(Methanal.Util.TimeDelta({'hours': 1})),
            now.offset(Methanal.Util.TimeDelta({'minutes': 30})).asDate());
        self.assertValid(
            dateWithin(Methanal.Util.TimeDelta({'days': 1,
                                                'minutes': 30})),
            tomorrow.asTimestamp());
        self.assertInvalid(
            dateWithin(Methanal.Util.TimeDelta({'days': 1})),
            tomorrow.asDate());

        var yesterday = now.offset(
            Methanal.Util.TimeDelta({'days': -1, 'minutes': -10}));
        self.assertValid(
            dateWithin(Methanal.Util.TimeDelta({'hours': -1})),
            now.offset(Methanal.Util.TimeDelta({'minutes': -30})).asDate());
        self.assertValid(
            dateWithin(Methanal.Util.TimeDelta({'days': -1,
                                                'minutes': -30})),
            yesterday.asDate());
        // XXX: Fudge it slightly since dateWithin uses the current time and
        // sometimes things take some time.
        self.assertInvalid(
            dateWithin(Methanal.Util.TimeDelta({'days': -1})),
            yesterday.asDate());
        self.assertInvalid(
            dateWithin(Methanal.Util.TimeDelta({'days': -1})),
            yesterday.asTimestamp());
    },

    /**
     * Value is a future date.
     */
    function test_futureDate(self) {
        var now = Methanal.Util.Time();
        var yesterday = now.offset(
            Methanal.Util.TimeDelta({'days': -1})).asDate();
        var tomorrow = now.offset(
            Methanal.Util.TimeDelta({'days': 1})).asDate();
        var futureDate = Methanal.Validators.futureDate;
        self.assertValid(futureDate, tomorrow);
        self.assertInvalid(futureDate, yesterday);
    },

    /**
     * Value is a past date.
     */
    function test_pastDate(self) {
        var now = Methanal.Util.Time();
        var yesterday = now.offset(
            Methanal.Util.TimeDelta({'days': -1})).asDate();
        var tomorrow = now.offset(
            Methanal.Util.TimeDelta({'days': 1})).asDate();
        var pastDate = Methanal.Validators.pastDate;
        self.assertInvalid(pastDate, tomorrow);
        self.assertValid(pastDate, yesterday);
    });
<|endoftext|>


<commit_before>"use strict";

importScripts("thirdparty/typescript/bin/typescriptServices.js");

var kLiveSourceFileName = "live.ts";
var kLiveCompiledFileNmae = "live.js";

function createCompilerHost(source, libSource, options) {
  var output;
  var host = {
    getSourceFile: function(filename, languageVersion) {
      var source = this.__fileContents[filename];
      if (source) {
        return ts.createSourceFile(filename, source, options, "0");
      }
    },
    writeFile: function(name, text, writeByteOrderMark) {
      if (name === kLiveCompiledFileNmae) {
        output = text;
      }
    },
    getDefaultLibFilename: function() {
      return "lib.d.ts";
    },
    useCaseSensitiveFileNames: function() { return false; },
    getCanonicalFileName: function(filename) { return filename; },
    getCurrentDirectory: function() { return ""; },
    getNewLine: function() { return "\n"; },
    getOutput: function() { return output; },

    __options: options,
    __fileContents: {},
  };

  host.__fileContents[kLiveSourceFileName] = source;
  host.__fileContents["lib.d.ts"] = libSource;
  return host;
}

var libSource = void 0;

function compile(source) {
  var host = createCompilerHost(source, libSource, {});
  var program = ts.createProgram([kLiveSourceFileName], {}, host);
  var errors = program.getDiagnostics();

  if (errors.length) {
    postMessage({
      type: "error",
      errors: errorText(errors)
    });
    return;
  }

  var checker = program.getTypeChecker(true);
  errors = checker.getDiagnostics();
  checker.emitFiles(program.getSourceFile(kLiveSourceFileName));

  postMessage({
    type: "compiled",
    compiled: host.getOutput(),
    errors: errorText(errors)
  });

  function errorText(errors) {
    return errors.map(function(e) {
      if (e.file) {
        var start = e.file.getLineAndCharacterFromPosition(e.start);
        return start.line + ": " + e.messageText;
      }
      return "Error: " + e.messageText;
    }).join("\n");
  }
}

onmessage = function(e) {
  var source = e.data || "";
  if (!source.trim()) {
    postMessage({
      type: "compiled",
      compiled: "",
      errors: ""
    })
    return;
  }
  if (libSource === void 0) {
    var xhr = new XMLHttpRequest();
    xhr.open("get", "thirdparty/typescript/bin/lib.d.ts");
    xhr.onload = function(e) {
      libSource = e.target.response;
      compile(source);
    }
    xhr.onerror = function(err) {
      postMessage({
        type: "error",
        errors: ["" + err].join("\n")
      });
    }
    xhr.send();
  } else {
    compile(source);
  }
}
<commit_msg>fix(worker): oops typo<commit_after>"use strict";

importScripts("thirdparty/typescript/bin/typescriptServices.js");

var kLiveSourceFileName = "live.ts";
var kLiveCompiledFileName = "live.js";

function createCompilerHost(source, libSource, options) {
  var output;
  var host = {
    getSourceFile: function(filename, languageVersion) {
      var source = this.__fileContents[filename];
      if (source) {
        return ts.createSourceFile(filename, source, options, "0");
      }
    },
    writeFile: function(name, text, writeByteOrderMark) {
      if (name === kLiveCompiledFileName) {
        output = text;
      }
    },
    getDefaultLibFilename: function() {
      return "lib.d.ts";
    },
    useCaseSensitiveFileNames: function() { return false; },
    getCanonicalFileName: function(filename) { return filename; },
    getCurrentDirectory: function() { return ""; },
    getNewLine: function() { return "\n"; },
    getOutput: function() { return output; },

    __options: options,
    __fileContents: {},
  };

  host.__fileContents[kLiveSourceFileName] = source;
  host.__fileContents["lib.d.ts"] = libSource;
  return host;
}

var libSource = void 0;

function compile(source) {
  var host = createCompilerHost(source, libSource, {});
  var program = ts.createProgram([kLiveSourceFileName], {}, host);
  var errors = program.getDiagnostics();

  if (errors.length) {
    postMessage({
      type: "error",
      errors: errorText(errors)
    });
    return;
  }

  var checker = program.getTypeChecker(true);
  errors = checker.getDiagnostics();
  checker.emitFiles(program.getSourceFile(kLiveSourceFileName));

  postMessage({
    type: "compiled",
    compiled: host.getOutput(),
    errors: errorText(errors)
  });

  function errorText(errors) {
    return errors.map(function(e) {
      if (e.file) {
        var start = e.file.getLineAndCharacterFromPosition(e.start);
        return start.line + ": " + e.messageText;
      }
      return "Error: " + e.messageText;
    }).join("\n");
  }
}

onmessage = function(e) {
  var source = e.data || "";
  if (!source.trim()) {
    postMessage({
      type: "compiled",
      compiled: "",
      errors: ""
    })
    return;
  }
  if (libSource === void 0) {
    var xhr = new XMLHttpRequest();
    xhr.open("get", "thirdparty/typescript/bin/lib.d.ts");
    xhr.onload = function(e) {
      libSource = e.target.response;
      compile(source);
    }
    xhr.onerror = function(err) {
      postMessage({
        type: "error",
        errors: ["" + err].join("\n")
      });
    }
    xhr.send();
  } else {
    compile(source);
  }
}
<|endoftext|>


<commit_before>define(["bpmn/Transformer", "bpmn/Renderer", "dojo/request", "dojo/Deferred", "dojo/query", "dojo/_base/array", "dojo/dom-class", "dojo/dom-construct"], function (Transformer, Renderer, request, Deferred, query, array, domClass, domConstruct) {
  function Bpmn() {
  };

  Bpmn.prototype.renderUrl  = function (url, options) {
    var deferred = new Deferred();
    var promise = request(url);
    var self = this;

    promise.then(
      function (bpmnXml) {
        var renderer = self.render(bpmnXml, options);
        self.bpmnXml = bpmnXml;
        deferred.resolve(self);
      },
      function (error) {
        throw error;
      }
    );

    return deferred;
  };

  Bpmn.prototype.render = function(bpmnXml, options) {
    var processDefinition = new Transformer().transform(bpmnXml);

    var definitionRenderer = new Renderer(processDefinition);
    definitionRenderer.render(options);

    this.definitionRenderer = definitionRenderer;
    this.bpmnXml = bpmnXml;
    this.options = options;

    // zoom the diagram to suite the bounds specified on options if any;
    var bounds = definitionRenderer.getBounds(), bwidth = 1, bheight = 1;

    if (bounds) {
      bwidth = parseFloat(bounds.width),
      bheight = parseFloat(bounds.height);
    }

    var scale = Math.min(
          (options.width || bwidth) / bwidth,
          (options.height || bheight) / bheight);

    this.zoom(scale);

    return this;
  },

  Bpmn.prototype.zoom = function (factor) {
      var transform = this.definitionRenderer.gfxGroup.getTransform();

      var xx = 1;
      var yy = 1;

      if (!!transform) {
        xx = transform.xx;
        yy = transform.yy;
      }

      this.definitionRenderer.gfxGroup.setTransform({xx:factor, yy:factor});
      var currentDimension = this.definitionRenderer.getSurface().getDimensions();
      this.definitionRenderer.getSurface().setDimensions(+currentDimension.width/xx * factor, +currentDimension.height/xx * factor);

      array.forEach(query(".bpmnElement"), function(element) {
        element.style.left = element.style.left.split("px")[0]/xx * factor + "px";
        element.style.top = element.style.top.split("px")[0]/yy * factor + "px";
        element.style.width = element.style.width.split("px")[0]/xx * factor + "px";
        element.style.height = element.style.height.split("px")[0]/yy * factor + "px";
      });

      return this;
    };

  Bpmn.prototype.annotate = function (id, innerHTML, classesArray) {
    var element = query(".bpmnElement" + "#"+id)[0];
    if (!element) {
      return;
    }

    element.innerHTML = innerHTML;

    domClass.add(element, classesArray.join(" "));
  };

  Bpmn.prototype.clear = function (id, innerHTML, classesArray) {
    this.definitionRenderer.gfxGroup.destroy();
    domConstruct.empty(query("#"+this.options.diagramElement)[0]);
  };

  return Bpmn;
});<commit_msg>fix(bpmn renderer): backport zoom fix<commit_after>define(["bpmn/Transformer", "bpmn/Renderer", "dojo/request", "dojo/Deferred", "dojo/query", "dojo/_base/array", "dojo/dom-class", "dojo/dom-construct"], function (Transformer, Renderer, request, Deferred, query, array, domClass, domConstruct) {
  function Bpmn() {
  };

  Bpmn.prototype.renderUrl  = function (url, options) {
    var deferred = new Deferred();
    var promise = request(url);
    var self = this;

    promise.then(
      function (bpmnXml) {
        var renderer = self.render(bpmnXml, options);
        self.bpmnXml = bpmnXml;
        deferred.resolve(self);
      },
      function (error) {
        throw error;
      }
    );

    return deferred;
  };

  Bpmn.prototype.render = function(bpmnXml, options) {
    var processDefinition = new Transformer().transform(bpmnXml);

    var definitionRenderer = new Renderer(processDefinition);
    definitionRenderer.render(options);

    this.definitionRenderer = definitionRenderer;
    this.bpmnXml = bpmnXml;
    this.options = options;

    // zoom the diagram to suite the bounds specified on options if any;
    var bounds = definitionRenderer.getSurface().getDimensions(), bwidth = 1, bheight = 1;

    if (bounds) {
      bwidth = parseFloat(bounds.width),
      bheight = parseFloat(bounds.height);
    }

    var scale = Math.min(
          (options.width || bwidth) / bwidth,
          (options.height || bheight) / bheight);

    this.zoom(scale);

    return this;
  },

  Bpmn.prototype.zoom = function (factor) {
      var transform = this.definitionRenderer.gfxGroup.getTransform();

      var xx = 1;
      var yy = 1;

      if (!!transform) {
        xx = transform.xx;
        yy = transform.yy;
      }

      this.definitionRenderer.gfxGroup.setTransform({xx:factor, yy:factor});
      var currentDimension = this.definitionRenderer.getSurface().getDimensions();
      this.definitionRenderer.getSurface().setDimensions(+currentDimension.width/xx * factor, +currentDimension.height/xx * factor);

      array.forEach(query(".bpmnElement"), function(element) {
        element.style.left = element.style.left.split("px")[0]/xx * factor + "px";
        element.style.top = element.style.top.split("px")[0]/yy * factor + "px";
        element.style.width = element.style.width.split("px")[0]/xx * factor + "px";
        element.style.height = element.style.height.split("px")[0]/yy * factor + "px";
      });

      return this;
    };

  Bpmn.prototype.annotate = function (id, innerHTML, classesArray) {
    var element = query(".bpmnElement" + "#"+id)[0];
    if (!element) {
      return;
    }

    element.innerHTML = innerHTML;

    domClass.add(element, classesArray.join(" "));
  };

  Bpmn.prototype.clear = function (id, innerHTML, classesArray) {
    this.definitionRenderer.gfxGroup.destroy();
    domConstruct.empty(query("#"+this.options.diagramElement)[0]);
  };

  return Bpmn;
});
<|endoftext|>


<commit_before>'use strict'

const Slapp = require('slapp')
const Context = require('slapp-context-beepboop')
const ConvoStore = require('slapp-convo-beepboop')

module.exports = (server, db) => {
  let app = Slapp({
    verify_token: process.env.SLACK_VERIFY_TOKEN,
    context: Context(),
    convo_store: ConvoStore()
  })

  // Middleware
  app.use((msg, next) => {
    if (msg.body.event.user)
    {
      db.saveConvo(msg.body.event.user, msg.body, (err, convo) => {
        console.log(err)
      })
    }
    next()
  })

  var HELP_TEXT = `
  I will respond to the following messages:
  \`help\` - to see this message
  \`hi\` - to demonstrate a conversation that tracks state.
  \`thanks\` - to demonstrate a simple response.
  \`<type-any-other-text>\` - to demonstrate a random emoticon response, some of the time :wink:.
  \`attachment\` - to see a Slack attachment message.
  `

//*********************************************
// Setup different handlers for messages
//*********************************************

  app.message('store', ['mention', 'direct_message'], (msg, text, greeting) => {
    db.increaseExperience(msg.body.event.user, (err) => {
      if (err) {
        console.log(err)
      }
    })
    msg
      .say(`Conversation model stored!`)
      .route('store_step_2')
  })

  app.route('store_step_2', (msg, state) => {
    var text = (msg.body.event && msg.body.event.text) || ''
    msg.say({
      text: '',
      "attachments": [
        {
            "fallback": "Required plain-text summary of the attachment.",
            "color": "#36a64f",
            "pretext": "Optional text that appears above the attachment block",
            "author_name": "Bobby Tables",
            "author_link": "http://flickr.com/bobby/",
            "author_icon": "http://flickr.com/icons/bobby.jpg",
            "title": "Slack API Documentation",
            "title_link": "https://api.slack.com/",
            "text": "Optional text that appears within the attachment",
            "fields": [
                {
                    "title": "Priority",
                    "value": "High",
                    "short": false
                }
            ],
            "image_url": "https://media.stsci.edu/uploads/story/thumbnail/1178/low_STSCI-H-p1715a-t-400x400.png",
            "thumb_url": "https://media.stsci.edu/uploads/story/thumbnail/1178/low_STSCI-H-p1715a-t-400x400.png",
            "footer": "Slack API",
            "footer_icon": "https://platform.slack-edge.com/img/default_application_icon.png",
            "ts": 123456789
        }
      ]
    })
  })

  app.message('space', ['direct_mention', 'direct_message'], (msg, text, greeting) => {
    // Pull from database space images and captions
    db.getSpaceImages((err, spaceImages) => {
        if (err) {
          console.error(err)
        }

    })
    // Setup the attachment for the response

  })

  app.message('spaceAdd', ['direct_mention', 'direct_message'], (msg, text, greeting) => {
    // Pull from database space images and captions
    db.saveSpaceImages( {
      'title': "NASA's Hubble Takes Close-up Portrait of Jupiter",
      'text': 'The planet Jupiter is the fifth planet out from the Sun, and is two and a half times more massive than all the other planets in the solar system combined.',
      'image': 'https://media.stsci.edu/uploads/story/thumbnail/1178/low_STSCI-H-p1715a-t-400x400.png',
    },(err, spaceImages) => {
        if (err) {
          console.error(err)
          msg.say(err)
        }

    })
    // Setup the attachment for the response
    msg.say({
      text: '',
      "attachments": [
        {
            "fallback": "Required plain-text summary of the attachment.",
            "color": "#36a64f",
            "pretext": "Optional text that appears above the attachment block",
            "author_name": "Bobby Tables",
            "author_link": "http://flickr.com/bobby/",
            "author_icon": "http://flickr.com/icons/bobby.jpg",
            "title": "Slack API Documentation",
            "title_link": "https://api.slack.com/",
            "text": "Optional text that appears within the attachment",
            "fields": [
                {
                    "title": "Priority",
                    "value": "High",
                    "short": false
                }
            ],
            "image_url": "https://media.stsci.edu/uploads/story/thumbnail/1178/low_STSCI-H-p1715a-t-400x400.png",
            "thumb_url": "https://media.stsci.edu/uploads/story/thumbnail/1178/low_STSCI-H-p1715a-t-400x400.png",
            "footer": "Slack API",
            "footer_icon": "https://platform.slack-edge.com/img/default_application_icon.png",
            "ts": 123456789
        }
      ]
    })
  })

  app.message('test', ['direct_mention', 'direct_message'], (msg, text, greeting) => {
    msg
      .say(`How are you?`)
      .route('handleHowAreYou')  // where to route the next msg in the conversation
  })

  // register a route handler
  app.route('handleHowAreYou', (msg) => {
    // respond with a random entry from array
    msg.say(['Me too', 'Noted', 'That is interesting'])
  })

  app
    .message('motivators', ['direct_mention', 'direct_message'], (msg, text) => {

      var motivators

      db.getMotivations(msg.body.event.user, (err, motivations) => {
        if (err) {
          console.error(err)
        }

        motivators = motivations
        if (motivators instanceof Object)
        {
          msg
            .say('You have motivations set.')
            .say(`Do more of this: `+motivators.motivates+'. Do less of this: '+motivators.discourages)
        }
        else
        {
          msg
            .say(`What is something that motivates you to create?`)
            // sends next event from user to this route, passing along state
            .route('motivates')
        }
      })
    })
  app.route('motivates', (msg, state) => {
      var text = (msg.body.event && msg.body.event.text) || ''

      // user may not have typed text as their next action, ask again and re-route
      if (!text) {
        return msg
          .say("Whoops, I'm still waiting to hear a response.")
          .say('What is something that motivates you to create?')
          .route('motivates', state)
      }

      // add their response to state
      state.motivates = text

      msg
        .say(`Ok. And what's something that discourages you from creating?`)
        .route('discourages', state)
    })
  app.route('discourages', (msg, state) => {
      var text = (msg.body.event && msg.body.event.text) || ''

      // user may not have typed text as their next action, ask again and re-route
      if (!text) {
        return msg
          .say("I'm eagerly awaiting to hear something that discourages you from creating.")
          .route('discourages', state)
      }

      // add their response to state
      state.discourages = text

      // Store the responses
      db.saveMotivations(msg.body.event.user, { 'motivates' : state.motivates , 'discourages' : state.discourages }, (err, convo) => {
        console.log(err)
      })

      msg
        .say('Thanks for sharing.')
        .say(`Do more of this: `+state.motivates+'. Do less of this: '+state.discourages)
      // At this point, since we don't route anywhere, the "conversation" is over
    })

  // response to the user typing "help"
  app.message('help', ['mention', 'direct_message'], (msg) => {
    msg.say(HELP_TEXT)
  })

  // Test response for boxes
  app.message('yesno', (msg) => {
    msg.say({
      text: '',
      attachments: [
        {
          text: '',
          fallback: 'Yes or No?',
          callback_id: 'yesno_callback',
          actions: [
            { name: 'answer', text: 'Yes', type: 'button', value: 'yes' },
            { name: 'answer', text: 'No',  type: 'button',  value: 'no' }
          ]
        }]
      })
  })

  app.action('yesno_callback', 'answer', (msg, value) => {
    msg.respond(msg.body.response_url, `${value} is a good choice!`)
  })

  // "Conversation" flow that tracks state - kicks off when user says hi, hello or hey
  app
    .message('^(hi|hello|hey)$', ['direct_mention', 'direct_message'], (msg, text) => {
      msg
        .say(`${text}, how are you?`)
        // sends next event from user to this route, passing along state
        .route('how-are-you', { greeting: text })
    })
    .route('how-are-you', (msg, state) => {
      var text = (msg.body.event && msg.body.event.text) || ''

      // user may not have typed text as their next action, ask again and re-route
      if (!text) {
        return msg
          .say("Whoops, I'm still waiting to hear how you're doing.")
          .say('How are you?')
          .route('how-are-you', state)
      }

      // add their response to state
      state.status = text

      msg
        .say(`Ok then. What's your favorite color?`)
        .route('color', state)
    })
    .route('color', (msg, state) => {
      var text = (msg.body.event && msg.body.event.text) || ''

      // user may not have typed text as their next action, ask again and re-route
      if (!text) {
        return msg
          .say("I'm eagerly awaiting to hear your favorite color.")
          .route('color', state)
      }

      // add their response to state
      state.color = text

      msg
        .say('Thanks for sharing.')
        .say(`Here's what you've told me so far: \`\`\`${JSON.stringify(state)}\`\`\``)
      // At this point, since we don't route anywhere, the "conversation" is over
    })

  // Can use a regex as well
  app.message(/^(thanks|thank you)/i, ['mention', 'direct_message'], (msg) => {
    // You can provide a list of responses, and a random one will be chosen
    // You can also include slack emoji in your responses
    msg.say([
      "You're welcome :smile:",
      'You bet',
      ':+1: Of course',
      'Anytime :sun_with_face: :full_moon_with_face:'
    ])
  })

  // demonstrate returning an attachment...
  app.message('attachment', ['mention', 'direct_message'], (msg) => {
    msg.say({
      text: 'Check out this amazing attachment! :confetti_ball: ',
      attachments: [{
        text: 'Slapp is a robust open source library that sits on top of the Slack APIs',
        title: 'Slapp Library - Open Source',
        image_url: 'https://storage.googleapis.com/beepboophq/_assets/bot-1.22f6fb.png',
        title_link: 'https://beepboophq.com/',
        color: '#7CD197'
      }]
    })
  })

  // response to the user asking "how did you get here?"
  app.message('how did you get here?', ['mention', 'direct_message'], (msg) => {
    msg.say('Team Rocket! :rocket:')
  })

  // "Creative motivators" flow

  app
    .message('^(hi|hello|hey)$', ['direct_mention', 'direct_message'], (msg, text) => {
      msg
        .say(text + ', how are you?')
        .route('how-are-you', { text }, 60)
    })
    .route('how-are-you', (msg, state) => {
      var resp = msg.body.event && msg.body.event.text

      if (/good/i.test(resp)) {
        msg
          .say(['Great! Ready?', ':smile: Are you sure?'])
          .route('how-are-you', state, 60)
      } else {
        msg
          .say('Me too', () => msg.say(`Thanks for saying ${state.text}`))
      }
    })
    .message('^(thanks|thank you)', ['mention', 'direct_message'], (msg) => {
      msg.say(["You're welcome", 'Of course'])
    })
    .message('help', ['direct_message', 'direct_mention'], (msg) => {
      let help = `I will respond to the following messages:
\`@slapp hi||hello\` for a greeting.
\`mention me by name in a message\` to demonstrate detecting a mention.
\`@slapp help\` to see this again.`

      msg.say(help)
    })
    .message('fix it', 'ambient', (msg) => {
      msg.say('https://www.youtube.com/watch?v=yo3uxqwTxk0')
    })
    .message(/.*/, 'mention', (msg) => {
      msg.say('You really do care about me. :heart:')
    })

    app.attachToExpress(server)

  return app
}
<commit_msg>Object to array.<commit_after>'use strict'

const Slapp = require('slapp')
const Context = require('slapp-context-beepboop')
const ConvoStore = require('slapp-convo-beepboop')

module.exports = (server, db) => {
  let app = Slapp({
    verify_token: process.env.SLACK_VERIFY_TOKEN,
    context: Context(),
    convo_store: ConvoStore()
  })

  // Middleware
  app.use((msg, next) => {
    if (msg.body.event.user)
    {
      db.saveConvo(msg.body.event.user, msg.body, (err, convo) => {
        console.log(err)
      })
    }
    next()
  })

  var HELP_TEXT = `
  I will respond to the following messages:
  \`help\` - to see this message
  \`hi\` - to demonstrate a conversation that tracks state.
  \`thanks\` - to demonstrate a simple response.
  \`<type-any-other-text>\` - to demonstrate a random emoticon response, some of the time :wink:.
  \`attachment\` - to see a Slack attachment message.
  `

//*********************************************
// Setup different handlers for messages
//*********************************************

  app.message('store', ['mention', 'direct_message'], (msg, text, greeting) => {
    db.increaseExperience(msg.body.event.user, (err) => {
      if (err) {
        console.log(err)
      }
    })
    msg
      .say(`Conversation model stored!`)
      .route('store_step_2')
  })

  app.route('store_step_2', (msg, state) => {
    var text = (msg.body.event && msg.body.event.text) || ''
    msg.say({
      text: '',
      "attachments": [
        {
            "fallback": "Required plain-text summary of the attachment.",
            "color": "#36a64f",
            "pretext": "Optional text that appears above the attachment block",
            "author_name": "Bobby Tables",
            "author_link": "http://flickr.com/bobby/",
            "author_icon": "http://flickr.com/icons/bobby.jpg",
            "title": "Slack API Documentation",
            "title_link": "https://api.slack.com/",
            "text": "Optional text that appears within the attachment",
            "fields": [
                {
                    "title": "Priority",
                    "value": "High",
                    "short": false
                }
            ],
            "image_url": "https://media.stsci.edu/uploads/story/thumbnail/1178/low_STSCI-H-p1715a-t-400x400.png",
            "thumb_url": "https://media.stsci.edu/uploads/story/thumbnail/1178/low_STSCI-H-p1715a-t-400x400.png",
            "footer": "Slack API",
            "footer_icon": "https://platform.slack-edge.com/img/default_application_icon.png",
            "ts": 123456789
        }
      ]
    })
  })

  app.message('space', ['direct_mention', 'direct_message'], (msg, text, greeting) => {
    // Pull from database space images and captions
    db.getSpaceImages((err, spaceImages) => {
        if (err) {
          console.error(err)
        }

    })
    // Setup the attachment for the response

  })

  app.message('spaceAdd', ['direct_mention', 'direct_message'], (msg, text, greeting) => {
    // Pull from database space images and captions
    db.saveSpaceImages( [
      'title': "NASA's Hubble Takes Close-up Portrait of Jupiter",
      'text': 'The planet Jupiter is the fifth planet out from the Sun, and is two and a half times more massive than all the other planets in the solar system combined.',
      'image': 'https://media.stsci.edu/uploads/story/thumbnail/1178/low_STSCI-H-p1715a-t-400x400.png',
    ],(err, spaceImages) => {
        if (err) {
          console.error(err)
          msg.say(err)
        }

    })
    // Setup the attachment for the response
    msg.say({
      text: '',
      "attachments": [
        {
            "fallback": "Required plain-text summary of the attachment.",
            "color": "#36a64f",
            "pretext": "Optional text that appears above the attachment block",
            "author_name": "Bobby Tables",
            "author_link": "http://flickr.com/bobby/",
            "author_icon": "http://flickr.com/icons/bobby.jpg",
            "title": "Slack API Documentation",
            "title_link": "https://api.slack.com/",
            "text": "Optional text that appears within the attachment",
            "fields": [
                {
                    "title": "Priority",
                    "value": "High",
                    "short": false
                }
            ],
            "image_url": "https://media.stsci.edu/uploads/story/thumbnail/1178/low_STSCI-H-p1715a-t-400x400.png",
            "thumb_url": "https://media.stsci.edu/uploads/story/thumbnail/1178/low_STSCI-H-p1715a-t-400x400.png",
            "footer": "Slack API",
            "footer_icon": "https://platform.slack-edge.com/img/default_application_icon.png",
            "ts": 123456789
        }
      ]
    })
  })

  app.message('test', ['direct_mention', 'direct_message'], (msg, text, greeting) => {
    msg
      .say(`How are you?`)
      .route('handleHowAreYou')  // where to route the next msg in the conversation
  })

  // register a route handler
  app.route('handleHowAreYou', (msg) => {
    // respond with a random entry from array
    msg.say(['Me too', 'Noted', 'That is interesting'])
  })

  app
    .message('motivators', ['direct_mention', 'direct_message'], (msg, text) => {

      var motivators

      db.getMotivations(msg.body.event.user, (err, motivations) => {
        if (err) {
          console.error(err)
        }

        motivators = motivations
        if (motivators instanceof Object)
        {
          msg
            .say('You have motivations set.')
            .say(`Do more of this: `+motivators.motivates+'. Do less of this: '+motivators.discourages)
        }
        else
        {
          msg
            .say(`What is something that motivates you to create?`)
            // sends next event from user to this route, passing along state
            .route('motivates')
        }
      })
    })
  app.route('motivates', (msg, state) => {
      var text = (msg.body.event && msg.body.event.text) || ''

      // user may not have typed text as their next action, ask again and re-route
      if (!text) {
        return msg
          .say("Whoops, I'm still waiting to hear a response.")
          .say('What is something that motivates you to create?')
          .route('motivates', state)
      }

      // add their response to state
      state.motivates = text

      msg
        .say(`Ok. And what's something that discourages you from creating?`)
        .route('discourages', state)
    })
  app.route('discourages', (msg, state) => {
      var text = (msg.body.event && msg.body.event.text) || ''

      // user may not have typed text as their next action, ask again and re-route
      if (!text) {
        return msg
          .say("I'm eagerly awaiting to hear something that discourages you from creating.")
          .route('discourages', state)
      }

      // add their response to state
      state.discourages = text

      // Store the responses
      db.saveMotivations(msg.body.event.user, { 'motivates' : state.motivates , 'discourages' : state.discourages }, (err, convo) => {
        console.log(err)
      })

      msg
        .say('Thanks for sharing.')
        .say(`Do more of this: `+state.motivates+'. Do less of this: '+state.discourages)
      // At this point, since we don't route anywhere, the "conversation" is over
    })

  // response to the user typing "help"
  app.message('help', ['mention', 'direct_message'], (msg) => {
    msg.say(HELP_TEXT)
  })

  // Test response for boxes
  app.message('yesno', (msg) => {
    msg.say({
      text: '',
      attachments: [
        {
          text: '',
          fallback: 'Yes or No?',
          callback_id: 'yesno_callback',
          actions: [
            { name: 'answer', text: 'Yes', type: 'button', value: 'yes' },
            { name: 'answer', text: 'No',  type: 'button',  value: 'no' }
          ]
        }]
      })
  })

  app.action('yesno_callback', 'answer', (msg, value) => {
    msg.respond(msg.body.response_url, `${value} is a good choice!`)
  })

  // "Conversation" flow that tracks state - kicks off when user says hi, hello or hey
  app
    .message('^(hi|hello|hey)$', ['direct_mention', 'direct_message'], (msg, text) => {
      msg
        .say(`${text}, how are you?`)
        // sends next event from user to this route, passing along state
        .route('how-are-you', { greeting: text })
    })
    .route('how-are-you', (msg, state) => {
      var text = (msg.body.event && msg.body.event.text) || ''

      // user may not have typed text as their next action, ask again and re-route
      if (!text) {
        return msg
          .say("Whoops, I'm still waiting to hear how you're doing.")
          .say('How are you?')
          .route('how-are-you', state)
      }

      // add their response to state
      state.status = text

      msg
        .say(`Ok then. What's your favorite color?`)
        .route('color', state)
    })
    .route('color', (msg, state) => {
      var text = (msg.body.event && msg.body.event.text) || ''

      // user may not have typed text as their next action, ask again and re-route
      if (!text) {
        return msg
          .say("I'm eagerly awaiting to hear your favorite color.")
          .route('color', state)
      }

      // add their response to state
      state.color = text

      msg
        .say('Thanks for sharing.')
        .say(`Here's what you've told me so far: \`\`\`${JSON.stringify(state)}\`\`\``)
      // At this point, since we don't route anywhere, the "conversation" is over
    })

  // Can use a regex as well
  app.message(/^(thanks|thank you)/i, ['mention', 'direct_message'], (msg) => {
    // You can provide a list of responses, and a random one will be chosen
    // You can also include slack emoji in your responses
    msg.say([
      "You're welcome :smile:",
      'You bet',
      ':+1: Of course',
      'Anytime :sun_with_face: :full_moon_with_face:'
    ])
  })

  // demonstrate returning an attachment...
  app.message('attachment', ['mention', 'direct_message'], (msg) => {
    msg.say({
      text: 'Check out this amazing attachment! :confetti_ball: ',
      attachments: [{
        text: 'Slapp is a robust open source library that sits on top of the Slack APIs',
        title: 'Slapp Library - Open Source',
        image_url: 'https://storage.googleapis.com/beepboophq/_assets/bot-1.22f6fb.png',
        title_link: 'https://beepboophq.com/',
        color: '#7CD197'
      }]
    })
  })

  // response to the user asking "how did you get here?"
  app.message('how did you get here?', ['mention', 'direct_message'], (msg) => {
    msg.say('Team Rocket! :rocket:')
  })

  // "Creative motivators" flow

  app
    .message('^(hi|hello|hey)$', ['direct_mention', 'direct_message'], (msg, text) => {
      msg
        .say(text + ', how are you?')
        .route('how-are-you', { text }, 60)
    })
    .route('how-are-you', (msg, state) => {
      var resp = msg.body.event && msg.body.event.text

      if (/good/i.test(resp)) {
        msg
          .say(['Great! Ready?', ':smile: Are you sure?'])
          .route('how-are-you', state, 60)
      } else {
        msg
          .say('Me too', () => msg.say(`Thanks for saying ${state.text}`))
      }
    })
    .message('^(thanks|thank you)', ['mention', 'direct_message'], (msg) => {
      msg.say(["You're welcome", 'Of course'])
    })
    .message('help', ['direct_message', 'direct_mention'], (msg) => {
      let help = `I will respond to the following messages:
\`@slapp hi||hello\` for a greeting.
\`mention me by name in a message\` to demonstrate detecting a mention.
\`@slapp help\` to see this again.`

      msg.say(help)
    })
    .message('fix it', 'ambient', (msg) => {
      msg.say('https://www.youtube.com/watch?v=yo3uxqwTxk0')
    })
    .message(/.*/, 'mention', (msg) => {
      msg.say('You really do care about me. :heart:')
    })

    app.attachToExpress(server)

  return app
}
<|endoftext|>


<commit_before>var React = require('react');
var Filter = require('./Filter.react');
var $ = require('jquery');

const defaultProps = {
  inventory: [],
  makes: [
    { makeId: 0, make: 'All'},
    { makeId: 1, make: 'Toyota'},
    { makeId: 2, make: 'Lexus'},
    { makeId: 3, make: 'Honda'},
    { makeId: 4, make: 'Acura'}
  ],
  models: [
    { modelId: 0, model: 'All'},
    { modelId: 1, model: 'Prius'},
    { modelId: 2, model: 'Camry'},
    { modelId: 3, model: 'Sienna'},
    { modelId: 11, model: 'GS'},
    { modelId: 12, model: 'IS'},
    { modelId: 21, model: 'Accord'},
    { modelId: 22, model: 'Civic'},
    { modelId: 31, model: 'TLX'},
    { modelId: 32, model: 'ILX'}
  ],
  endYear: 2015
};

class Inventory extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      inventory: this.props.inventory,
      makeId: 0,
      modelId: 0,
      year: 0
    };

    this._handleChange = this._handleChange.bind(this);
    this._updateInventory = this._updateInventory.bind(this);
  }

  _handleChange(e) {
    var key = e.target.name;
    var val = e.target.value;
    this.setState({
      [key]: val
    }, () => {
      this._updateInventory();
    });
  }

  _generateURL() {
    var { makeId, modelId, year } = this.state;
    return '/api/inventory/?makeId=' + makeId + '&modelId=' + modelId + '&year=' + year;
  }

  _updateInventory() {
    var url = this._generateURL();
    $.ajax({
      url: url,
      type: 'GET',
      success: (res) => {
        this.setState({
          inventory: res
        });
      }
    });
  }

  render() {
    var {
      inventory,
      makeId,
      modelId,
      year
    } = this.state;

    var {
      makes,
      models
    } = this.props;

    var yearOptions = (x, y) => {
      var options = [];
      options.push(<option value={0}>All</option>);
      for (x; x <= y; x++) {
        options.push(<option value={x}>{x}</option>);
      }
      return options;
    };

    return (

Inventory

          <Filter name="makeId"
            value={makeId}
            options={makes}
            optionName="make"
            optionValue="makeId"
            handleChange={this._handleChange}
          />
          <Filter name="modelId"
            value={modelId}
            options={models}
            optionName="model"
            optionValue="modelId"
            handleChange={this._handleChange}
          />
          <select name="year" value={year} onChange={this._handleChange}>
            {yearOptions(2011,2015)}
          </select>

          {
            inventory.map((item, index) => {
              var { vin, make, model, year, price } = item;
              return (

                  {vin}, {make}, {model}, {year}, {price}

              );
            })
          }

    );
  }
};

Inventory.defaultProps = defaultProps;

module.exports = Inventory;<commit_msg>changed year logic to a filter component<commit_after>var React = require('react');
var Filter = require('./Filter.react');
var $ = require('jquery');

const defaultProps = {
  inventory: [],
  makes: [
    { makeId: 0, make: 'All'},
    { makeId: 1, make: 'Toyota'},
    { makeId: 2, make: 'Lexus'},
    { makeId: 3, make: 'Honda'},
    { makeId: 4, make: 'Acura'}
  ],
  models: [
    { modelId: 0, model: 'All'},
    { modelId: 1, model: 'Prius'},
    { modelId: 2, model: 'Camry'},
    { modelId: 3, model: 'Sienna'},
    { modelId: 11, model: 'GS'},
    { modelId: 12, model: 'IS'},
    { modelId: 21, model: 'Accord'},
    { modelId: 22, model: 'Civic'},
    { modelId: 31, model: 'TLX'},
    { modelId: 32, model: 'ILX'}
  ],
  years: (start, end) => {
    var options = [];
    options.push({
      year: 'All',
      yearId: 0
    });
    for(var y = start; y <= end; y++) {
      options.push({
        year: y,
        yearId: y
      });
    }
    return options;
  }
};

class Inventory extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      inventory: this.props.inventory,
      makeId: 0,
      modelId: 0,
      year: 0
    };

    this._handleChange = this._handleChange.bind(this);
    this._updateInventory = this._updateInventory.bind(this);
  }

  _handleChange(e) {
    var key = e.target.name;
    var val = e.target.value;
    this.setState({
      [key]: val
    }, () => {
      this._updateInventory();
    });
  }

  _generateURL() {
    var { makeId, modelId, year } = this.state;
    return '/api/inventory/?makeId=' + makeId + '&modelId=' + modelId + '&year=' + year;
  }

  _updateInventory() {
    var url = this._generateURL();
    $.ajax({
      url: url,
      type: 'GET',
      success: (res) => {
        this.setState({
          inventory: res
        });
      }
    });
  }

  render() {
    var {
      inventory,
      makeId,
      modelId,
      year
    } = this.state;

    var {
      makes,
      models,
      years
    } = this.props;

    return (

Inventory

          <Filter name="makeId"
            value={makeId}
            options={makes}
            optionName="make"
            optionValue="makeId"
            handleChange={this._handleChange}
          />
          <Filter name="modelId"
            value={modelId}
            options={models}
            optionName="model"
            optionValue="modelId"
            handleChange={this._handleChange}
          />
          <Filter name="year"
            value={year}
            options={years(2011,2015)}
            optionName="year"
            optionValue="yearId"
            handleChange={this._handleChange}
          />

          {
            inventory.map((item, index) => {
              var { vin, make, model, year, price } = item;
              return (

                  {vin}, {make}, {model}, {year}, {price}

              );
            })
          }

    );
  }
};

Inventory.defaultProps = defaultProps;

module.exports = Inventory;<|endoftext|>


<commit_before>import Ember from "ember";

export default Ember.Component.extend({
  parentDialects: function() {
    // console.log(this.get("labels"))
    return this.get("labels").filterBy("isDialect", true).filterBy("parent", null);
  }.property("labels"),
  parentLabels: function() {
    return this.get("labels").filterBy("isDialect", false).filterBy("parent", null);
  }.property("labels"),
});
<commit_msg>Remove log line<commit_after>import Ember from "ember";

export default Ember.Component.extend({
  parentDialects: function() {
    return this.get("labels").filterBy("isDialect", true).filterBy("parent", null);
  }.property("labels"),
  parentLabels: function() {
    return this.get("labels").filterBy("isDialect", false).filterBy("parent", null);
  }.property("labels"),
});
<|endoftext|>


<commit_before>// Obtain a list of meetings attended by a given individual or a given
// organisation / department, and then visualise who they met with as
// bubbles, where the size of the bubble is how often they met with
// them.

// FIXME: make this constant configurable
let RADIUS_SCALE = 10;

let d3 = require('d3');
let meetingData = require('./meetingData');

let d3Chart = {
  initChart: function(topdiv, svg, meetingCounts) {
    d3Chart.getSvgDimensions(svg);
    d3Chart.initBubbleCoordsRadius(svg, meetingCounts);

    d3Chart.force = d3Chart.initForceSimulation(svg, meetingCounts);

    d3Chart.update(topdiv, svg, meetingCounts);
  },

  getSvgDimensions: function(svg) {
    let sel = d3.select(svg);
    svg.pixelWidth = sel.style("width").replace("px", "");
    svg.pixelHeight = sel.style("height").replace("px", "");
    svg.centreX = svg.pixelWidth / 2;
    svg.centreY = svg.pixelHeight / 2;
  },

  initBubbleCoordsRadius: function(svg, data) {
    for (let i = 0; i < data.length; i++) {
      data[i].radius = data[i].meetingCount * RADIUS_SCALE;
      data[i].x = Math.random() * svg.pixelWidth;
      data[i].y = Math.random() * svg.pixelHeight;
    }
  },

  translate: function(x, y) {
    return "translate(" + x + "," + y + ")";
  },

  positionBubble: function(d, i) {
    return d3Chart.translate(d.x, d.y);
  },

  bubbleRadius: function(d, i) {
    return d.radius + 2;
  },

  initForceSimulation: function(svg, meetingCounts) {
    return d3.forceSimulation(meetingCounts)
      //.force("charge", d3.forceManyBody().strength(-1000))
      .force("centerX", d3.forceX(svg.centreX))
      .force("centerY", d3.forceY(svg.centreY))
      .force("collide", d3.forceCollide()
                          .radius(d3Chart.bubbleRadius)
                          .iterations(3))
      .force("center", d3.forceCenter(svg.centreX, svg.centreY))
      .on("tick", this.tickHandler);
  },

  tickHandler: function() {
    d3Chart.updateBubblePositions();
  },

  updateBubblePositions: function() {
      this.bubbles.attr("transform", this.positionBubble);
  },

  update: function(topdiv, svg, data) {
    let g = d3.select(svg).select('.d3-points');

    let tooltip = d3.select(topdiv).append("div")
                .attr("class", "tooltip")
                .style("opacity", 0);

    this.bubbles = g.selectAll('g.bubble')
        .data(data)
      .enter().append("g")
        .attr("class", "bubble")
        .on("mouseover", function(d) {
           tooltip.transition()
             .duration(200)
             .style("opacity", 1);
           tooltip.html("" + d.targetName + ""+ "
 " + "Meetings: " + d.meetingCount)
             .style("left", (d3.event.pageX) + "px")
             .style("top", (d3.event.pageY) + "px");
           })
        .on("mousemove", function() {
          tooltip.style("left", (d3.event.pageX ) + "px")
            .style("top", (d3.event.pageY) + "px");
        })
        .on("mouseout", function(d) {
           tooltip.transition()
             .duration(200)
             .style("opacity", 0);
           });

    this.updateBubblePositions();

    this.bubbles.append("circle")
      .attr("r", function(d) {return d.radius;});

    this.bubbles.append("text")
      .text(function(d) {return d.targetName;})
      .style("font-size", this.bubbleTextFontSize)
  },

  bubbleTextFontSize: function(d) {
    return Math.min(
      2 * d.radius,
      (2 * d.radius - 8) / this.getComputedTextLength() * 10
    ) + "px";
  },

  destroy: function() {
  },
};

module.exports = d3Chart;
<commit_msg>ui: make bubble area proportional to meeting count<commit_after>// Obtain a list of meetings attended by a given individual or a given
// organisation / department, and then visualise who they met with as
// bubbles, where the size of the bubble is how often they met with
// them.

// FIXME: make this constant configurable
let RADIUS_SCALE = 25;

let d3 = require('d3');
let meetingData = require('./meetingData');

let d3Chart = {
  initChart: function(topdiv, svg, meetingCounts) {
    d3Chart.getSvgDimensions(svg);
    d3Chart.initBubbleCoordsRadius(svg, meetingCounts);

    d3Chart.force = d3Chart.initForceSimulation(svg, meetingCounts);

    d3Chart.update(topdiv, svg, meetingCounts);
  },

  getSvgDimensions: function(svg) {
    let sel = d3.select(svg);
    svg.pixelWidth = sel.style("width").replace("px", "");
    svg.pixelHeight = sel.style("height").replace("px", "");
    svg.centreX = svg.pixelWidth / 2;
    svg.centreY = svg.pixelHeight / 2;
  },

  initBubbleCoordsRadius: function(svg, data) {
    for (let i = 0; i < data.length; i++) {
      data[i].radius = Math.sqrt(data[i].meetingCount) * RADIUS_SCALE;
      data[i].x = Math.random() * svg.pixelWidth;
      data[i].y = Math.random() * svg.pixelHeight;
    }
  },

  translate: function(x, y) {
    return "translate(" + x + "," + y + ")";
  },

  positionBubble: function(d, i) {
    return d3Chart.translate(d.x, d.y);
  },

  bubbleRadius: function(d, i) {
    return d.radius + 2;
  },

  initForceSimulation: function(svg, meetingCounts) {
    return d3.forceSimulation(meetingCounts)
      //.force("charge", d3.forceManyBody().strength(-1000))
      .force("centerX", d3.forceX(svg.centreX))
      .force("centerY", d3.forceY(svg.centreY))
      .force("collide", d3.forceCollide()
                          .radius(d3Chart.bubbleRadius)
                          .iterations(3))
      .force("center", d3.forceCenter(svg.centreX, svg.centreY))
      .on("tick", this.tickHandler);
  },

  tickHandler: function() {
    d3Chart.updateBubblePositions();
  },

  updateBubblePositions: function() {
      this.bubbles.attr("transform", this.positionBubble);
  },

  update: function(topdiv, svg, data) {
    let g = d3.select(svg).select('.d3-points');

    let tooltip = d3.select(topdiv).append("div")
                .attr("class", "tooltip")
                .style("opacity", 0);

    this.bubbles = g.selectAll('g.bubble')
        .data(data)
      .enter().append("g")
        .attr("class", "bubble")
        .on("mouseover", function(d) {
           tooltip.transition()
             .duration(200)
             .style("opacity", 1);
           tooltip.html("" + d.targetName + ""+ "
 " + "Meetings: " + d.meetingCount)
             .style("left", (d3.event.pageX) + "px")
             .style("top", (d3.event.pageY) + "px");
           })
        .on("mousemove", function() {
          tooltip.style("left", (d3.event.pageX ) + "px")
            .style("top", (d3.event.pageY) + "px");
        })
        .on("mouseout", function(d) {
           tooltip.transition()
             .duration(200)
             .style("opacity", 0);
           });

    this.updateBubblePositions();

    this.bubbles.append("circle")
      .attr("r", function(d) {return d.radius;});

    this.bubbles.append("text")
      .text(function(d) {return d.targetName;})
      .style("font-size", this.bubbleTextFontSize)
  },

  bubbleTextFontSize: function(d) {
    return Math.min(
      2 * d.radius,
      (2 * d.radius - 8) / this.getComputedTextLength() * 10
    ) + "px";
  },

  destroy: function() {
  },
};

module.exports = d3Chart;
<|endoftext|>