<commit_before>// @flow
import React, { Fragment } from 'react';
import Helmet from 'react-helmet';
import md from '../../markdown/renderer';
import ExampleWrapper from '../../ExampleWrapper';
import {
  AccessingInternals,
  ControlledMenu,
  OnSelectResetsInput,
  BasicGrouped,
  CreateFilter,
  CustomFilterOptions,
  CustomGetOptionLabel,
  CustomGetOptionValue,
  CustomIsOptionDisabled,
  Experimental,
  Popout,
  MenuBuffer,
  MenuPortal,
} from '../../examples';

export default function Advanced() {
  return (
    <Fragment>
      <Helmet>
        <title>Advanced - React Select</title>
        <meta
          name="description"
          content="The react-select property API documentation."
        />
      </Helmet>
      {md`
      # Advanced

      ## Custom Filter logic
      While React-Select assumes a standard way of filtering the menu on search, our api allows you to customise that filtering logic in various ways.

      ### createFilter function
      React-Select exports a createFilter function that returns a filterOption method. By using this, users can pick and choose bits of the filtration logic to customise,
      without having to rewrite the logic wholesale.

      Below is an example of how you could use the createFilter function to customise filtration logic in react-select.

      ${(
        <ExampleWrapper
          label="Custom filterOption with createFilter"
          urlPath="docs/examples/CreateFilter.js"
          raw={require('!!raw-loader!../../examples/CreateFilter.js')}
        >
          <CreateFilter />
        </ExampleWrapper>
      )}

      ### filterOption
      If you really would like to rewrite the filtration logic from the ground up, simply declare a new filterOption function to be passed in as a prop to react-select.
      For details on the shape of the filterOption prop, please see the proptypes in the api docs [here](/props).

      ${(
        <ExampleWrapper
          label="Custom filterOption with createFilter"
          urlPath="docs/examples/CreateFilter.js"
          raw={require('!!raw-loader!../../examples/CreateFilter.js')}
        >
          <CustomFilterOptions />
        </ExampleWrapper>
      )}

      ## Replacing builtins
      For a list of builtins that we expose, please see the API docs [here](/props#prop-types).

      ${(
        <ExampleWrapper
          label="custom formatGroupLabel function example"
          urlPath="docs/examples/BasicGrouped.js"
          raw={require('!!raw-loader!../../examples/BasicGrouped.js')}
        >
          <BasicGrouped />
        </ExampleWrapper>
      )}

      ${(
        <ExampleWrapper
          label="custom getOptionLabel function example"
          urlPath="docs/examples/CustomSingleValue.js"
          raw={require('!!raw-loader!../../examples/CustomSingleValue.js')}
        >
          <CustomGetOptionLabel />
        </ExampleWrapper>
      )}

      ${(
        <ExampleWrapper
          label="custom getOptionValue function example"
          urlPath="docs/examples/CustomGetOptionValue.js"
          raw={require('!!raw-loader!../../examples/CustomGetOptionValue.js')}
        >
          <CustomGetOptionValue />
        </ExampleWrapper>
      )}

      ${(
        <ExampleWrapper
          label="custom isOptionDisabled function example"
          raw={require('!!raw-loader!../../examples/CustomIsOptionDisabled.js')}
        >
          <CustomIsOptionDisabled />
        </ExampleWrapper>
      )}

      ${(
        <ExampleWrapper
          label="Using the style API to replace `menuBuffer`"
          raw={require('!!raw-loader!../../examples/MenuBuffer.js')}
        >
          <MenuBuffer />
        </ExampleWrapper>
      )}

      ## Methods

      These two methods sit as callable methods on the component. They are designed
      to be accessible to wrapping components.

      ### \`focus()\`

      Focused the internal control input.

      ### \`blur()\`

      Blur the internal control input.

      ## Action Meta
      React Select exposes a variety of eventListeners to you via props.
      The onchange function prop now has the following signature.
      (value: ValueType, action: ActionType) => undefined;

      The action argument is a string with the following possible values

      'select-option'
      'deselect-option'
      'remove-value'
      'pop-value'
      'set-value'
      'clear'
      'create-option'

      By explicitly passing you what type of change event has been fired, we allow you to have more granular control
      over how the select behaves after an onChange even is fired.

      Below is an example of replicating the behaviour supported by the (deprecated) onSelectResetsInput and (deprecated) closeMenuOnSelect props in react-select v1

      ${(
        <ExampleWrapper
          label="onSelectResetsInput = false; closeMenuOnSelect = false"
          urlPath="docs/examples/OnSelectResetsInput.js"
          raw={require('!!raw-loader!../../examples/OnSelectResetsInput.js')}
        >
          <OnSelectResetsInput />
        </ExampleWrapper>
      )}

      ## Portaling
      React-select exposes a menuPortalTarget prop, that lets you portal the select menu to a dom node of your choosing.
      Additionally we expose the menuPortal styles for layering purposes.

      ${(
        <ExampleWrapper
          isEditable={false}
          label="Example of Portaling"
          urlPath="docs/examples/MenuPortal.js"
          raw={require('!!raw-loader!../../examples/MenuPortal.js')}
        >
          <MenuPortal />
        </ExampleWrapper>
      )}

      ## Controlled Props

      ${(
        <ExampleWrapper
          label="Example of controlled MenuIsOpen"
          urlPath="docs/examples/ControlledMenu.js"
          raw={require('!!raw-loader!../../examples/ControlledMenu.js')}
        >
          <ControlledMenu />
        </ExampleWrapper>
      )}

      ## Accessing Internals
      ${(
        <ExampleWrapper
          isEditable={false}
          label="Accessing Internals via ref"
          urlPath="docs/examples/Experimental.js"
          raw={require('!!raw-loader!../../examples/AccessingInternals.js')}
        >
          <AccessingInternals />
        </ExampleWrapper>
      )}

      ## SSR / Universal Rendering

      React-Select uses Emotion for CSS, which make it easy to extract the
      styles when doing server-side rendering. To get started, do the following:

      ~~~bash
      yarn add emotion-server
      ~~~

      Then, in the file where you render your React app to a string of HTML that
      will be sent to the client, wrap React's \`renderToString\` result with
      Emotion's \`renderStylesToString\` method:

      ~~~jsx
      import { renderToString } from 'react-dom/server'
      import { renderStylesToString } from 'emotion-server'
      import App from './App'

      const html = renderStylesToString(renderToString(<App />))
      ~~~

      for more ways you can do this (including critical CSS) see the
      [Emotion SSR Docs](https://github.com/emotion-js/emotion/blob/master/docs/ssr.md)

      ## Experimental

      Experimental recipes of prop combinations with react-select v2.

      ${(
        <ExampleWrapper
          isEditable={false}
          label="Popout"
          urlPath="docs/examples/Popout.js"
          raw={require('!!raw-loader!../../examples/Popout.js')}
        >
          <Popout />
        </ExampleWrapper>
      )}

      A popular recipe for using select when there's limited real estate.

      > When \`controlShouldRenderValue\` is disabled, it's recommended to also disable \`isClearable\` and \`backspaceRemovesValue\`.

      ${(
        <ExampleWrapper
          isEditable={false}
          label="Date Picker"
          urlPath="docs/examples/Experimental.js"
          raw={require('!!raw-loader!../../examples/Experimental.js')}
        >
          <Experimental />
        </ExampleWrapper>
      )}

      This example uses a combination of custom components and functions to make react-select behave like a date picker.

      > Type a date like "25/8/18", "tomorrow", "next monday", or "6 weeks from now" into the field to get date suggestions.

    `}
    </Fragment>
  );
}
<commit_msg>fix custom filter function example<commit_after>// @flow
import React, { Fragment } from 'react';
import Helmet from 'react-helmet';
import md from '../../markdown/renderer';
import ExampleWrapper from '../../ExampleWrapper';
import {
  AccessingInternals,
  ControlledMenu,
  OnSelectResetsInput,
  BasicGrouped,
  CreateFilter,
  CustomFilterOptions,
  CustomGetOptionLabel,
  CustomGetOptionValue,
  CustomIsOptionDisabled,
  Experimental,
  Popout,
  MenuBuffer,
  MenuPortal,
} from '../../examples';

export default function Advanced() {
  return (
    <Fragment>
      <Helmet>
        <title>Advanced - React Select</title>
        <meta
          name="description"
          content="The react-select property API documentation."
        />
      </Helmet>
      {md`
      # Advanced

      ## Custom Filter logic
      While React-Select assumes a standard way of filtering the menu on search, our api allows you to customise that filtering logic in various ways.

      ### createFilter function
      React-Select exports a createFilter function that returns a filterOption method. By using this, users can pick and choose bits of the filtration logic to customise,
      without having to rewrite the logic wholesale.

      Below is an example of how you could use the createFilter function to customise filtration logic in react-select.

      ${(
        <ExampleWrapper
          label="Custom filterOption with createFilter"
          urlPath="docs/examples/CreateFilter.js"
          raw={require('!!raw-loader!../../examples/CreateFilter.js')}
        >
          <CreateFilter />
        </ExampleWrapper>
      )}

      ### filterOption
      If you really would like to rewrite the filtration logic from the ground up, simply declare a new filterOption function to be passed in as a prop to react-select.
      For details on the shape of the filterOption prop, please see the proptypes in the api docs [here](/props).

      ${(
        <ExampleWrapper
          label="Custom filterOption function"
          urlPath="docs/examples/CustomFilterOptions.js"
          raw={require('!!raw-loader!../../examples/CustomFilterOptions.js')}
        >
          <CustomFilterOptions />
        </ExampleWrapper>
      )}

      ## Replacing builtins
      For a list of builtins that we expose, please see the API docs [here](/props#prop-types).

      ${(
        <ExampleWrapper
          label="custom formatGroupLabel function example"
          urlPath="docs/examples/BasicGrouped.js"
          raw={require('!!raw-loader!../../examples/BasicGrouped.js')}
        >
          <BasicGrouped />
        </ExampleWrapper>
      )}

      ${(
        <ExampleWrapper
          label="custom getOptionLabel function example"
          urlPath="docs/examples/CustomSingleValue.js"
          raw={require('!!raw-loader!../../examples/CustomSingleValue.js')}
        >
          <CustomGetOptionLabel />
        </ExampleWrapper>
      )}

      ${(
        <ExampleWrapper
          label="custom getOptionValue function example"
          urlPath="docs/examples/CustomGetOptionValue.js"
          raw={require('!!raw-loader!../../examples/CustomGetOptionValue.js')}
        >
          <CustomGetOptionValue />
        </ExampleWrapper>
      )}

      ${(
        <ExampleWrapper
          label="custom isOptionDisabled function example"
          raw={require('!!raw-loader!../../examples/CustomIsOptionDisabled.js')}
        >
          <CustomIsOptionDisabled />
        </ExampleWrapper>
      )}

      ${(
        <ExampleWrapper
          label="Using the style API to replace `menuBuffer`"
          raw={require('!!raw-loader!../../examples/MenuBuffer.js')}
        >
          <MenuBuffer />
        </ExampleWrapper>
      )}

      ## Methods

      These two methods sit as callable methods on the component. They are designed
      to be accessible to wrapping components.

      ### \`focus()\`

      Focused the internal control input.

      ### \`blur()\`

      Blur the internal control input.

      ## Action Meta
      React Select exposes a variety of eventListeners to you via props.
      The onchange function prop now has the following signature.
      (value: ValueType, action: ActionType) => undefined;

      The action argument is a string with the following possible values

      'select-option'
      'deselect-option'
      'remove-value'
      'pop-value'
      'set-value'
      'clear'
      'create-option'

      By explicitly passing you what type of change event has been fired, we allow you to have more granular control
      over how the select behaves after an onChange even is fired.

      Below is an example of replicating the behaviour supported by the (deprecated) onSelectResetsInput and (deprecated) closeMenuOnSelect props in react-select v1

      ${(
        <ExampleWrapper
          label="onSelectResetsInput = false; closeMenuOnSelect = false"
          urlPath="docs/examples/OnSelectResetsInput.js"
          raw={require('!!raw-loader!../../examples/OnSelectResetsInput.js')}
        >
          <OnSelectResetsInput />
        </ExampleWrapper>
      )}

      ## Portaling
      React-select exposes a menuPortalTarget prop, that lets you portal the select menu to a dom node of your choosing.
      Additionally we expose the menuPortal styles for layering purposes.

      ${(
        <ExampleWrapper
          isEditable={false}
          label="Example of Portaling"
          urlPath="docs/examples/MenuPortal.js"
          raw={require('!!raw-loader!../../examples/MenuPortal.js')}
        >
          <MenuPortal />
        </ExampleWrapper>
      )}

      ## Controlled Props

      ${(
        <ExampleWrapper
          label="Example of controlled MenuIsOpen"
          urlPath="docs/examples/ControlledMenu.js"
          raw={require('!!raw-loader!../../examples/ControlledMenu.js')}
        >
          <ControlledMenu />
        </ExampleWrapper>
      )}

      ## Accessing Internals
      ${(
        <ExampleWrapper
          isEditable={false}
          label="Accessing Internals via ref"
          urlPath="docs/examples/Experimental.js"
          raw={require('!!raw-loader!../../examples/AccessingInternals.js')}
        >
          <AccessingInternals />
        </ExampleWrapper>
      )}

      ## SSR / Universal Rendering

      React-Select uses Emotion for CSS, which make it easy to extract the
      styles when doing server-side rendering. To get started, do the following:

      ~~~bash
      yarn add emotion-server
      ~~~

      Then, in the file where you render your React app to a string of HTML that
      will be sent to the client, wrap React's \`renderToString\` result with
      Emotion's \`renderStylesToString\` method:

      ~~~jsx
      import { renderToString } from 'react-dom/server'
      import { renderStylesToString } from 'emotion-server'
      import App from './App'

      const html = renderStylesToString(renderToString(<App />))
      ~~~

      for more ways you can do this (including critical CSS) see the
      [Emotion SSR Docs](https://github.com/emotion-js/emotion/blob/master/docs/ssr.md)

      ## Experimental

      Experimental recipes of prop combinations with react-select v2.

      ${(
        <ExampleWrapper
          isEditable={false}
          label="Popout"
          urlPath="docs/examples/Popout.js"
          raw={require('!!raw-loader!../../examples/Popout.js')}
        >
          <Popout />
        </ExampleWrapper>
      )}

      A popular recipe for using select when there's limited real estate.

      > When \`controlShouldRenderValue\` is disabled, it's recommended to also disable \`isClearable\` and \`backspaceRemovesValue\`.

      ${(
        <ExampleWrapper
          isEditable={false}
          label="Date Picker"
          urlPath="docs/examples/Experimental.js"
          raw={require('!!raw-loader!../../examples/Experimental.js')}
        >
          <Experimental />
        </ExampleWrapper>
      )}

      This example uses a combination of custom components and functions to make react-select behave like a date picker.

      > Type a date like "25/8/18", "tomorrow", "next monday", or "6 weeks from now" into the field to get date suggestions.

    `}
    </Fragment>
  );
}
<|endoftext|>


<commit_before>/* @flow strict-local */
import deepFreeze from 'deep-freeze';
import { createStore } from 'redux';

import type { CrossRealmBot, Message, PmRecipientUser, Stream, User } from '../api/modelTypes';
import type { GlobalState, RealmState } from '../reduxTypes';
import type { Account } from '../types';
import { ACCOUNT_SWITCH, LOGIN_SUCCESS } from '../actionConstants';
import rootReducer from '../boot/reducers';

// TODO either fix Jest test-discovery patterns, or rename this file,
// so this dummy test isn't required.
describe('nothing', () => {
  test('nothing', () => {});
});

/** Return a string that's almost surely different every time. */
const randString = () =>
  Math.random()
    .toString(36)
    .substring(7);

/** Return an integer 0 <= N < end, roughly uniformly at random. */
const randInt = (end: number) => Math.floor(Math.random() * end);

const userOrBotProperties = ({ name: _name }) => {
  const name = _name !== undefined ? _name : randString();
  const capsName = name.substring(0, 1).toUpperCase() + name.substring(1);
  return {
    avatar_url: `https://zulip.example.org/yo/avatar-${name}.png`,

    date_joined: `2014-04-${randInt(30)
      .toString()
      .padStart(2, '0')}`,

    email: `${name}@example.org`,
    full_name: `${capsName} User`,
    is_admin: false,
    timezone: 'UTC',
    user_id: randInt(10000),
  };
};

/** Caveat emptor!  These values may not be representative. */
const makeUser = (args: { name?: string } = {}): User => ({
  ...userOrBotProperties(args),

  is_bot: false,
  // bot_type omitted
  // bot_owner omitted

  is_guest: false,

  // profile_data omitted
});

/** Caveat emptor!  These values may not be representative. */
const makeCrossRealmBot = (args: { name?: string } = {}): CrossRealmBot => ({
  ...userOrBotProperties(args),
  is_bot: true,
});

const makeAccount = (user: User): Account => ({
  realm: 'https://zulip.example.org',
  email: user.email,
  apiKey: randString() + randString(),
  ackedPushToken: null,
});

const selfUser: User = makeUser({ name: 'self' });
const selfAccount: Account = makeAccount(selfUser);

const otherUser: User = makeUser({ name: 'other' });

const crossRealmBot: CrossRealmBot = makeCrossRealmBot({ name: 'bot' });

const stream: Stream = {
  stream_id: 34,
  description: 'An example stream.',
  name: 'a stream',
  invite_only: false,
  is_announcement_only: false,
  history_public_to_subscribers: true,
};

const displayRecipientFromUser = (user: User): PmRecipientUser => {
  const { email, full_name, user_id: id } = user;
  return {
    email,
    full_name,
    id,
    is_mirror_dummy: false,
    short_name: '', // what is this, anyway?
  };
};

/** Boring properties common to all example Message objects. */
const messagePropertiesBase = {
  isOutbox: false,

  // match_content omitted
  // match_subject omitted

  // flags omitted

  edit_history: [],
  is_me_message: false,
  // last_edit_timestamp omitted
  reactions: [],
  subject_links: [],
  submessages: [],
};

const messagePropertiesFromSender = (user: User) => {
  const {
    avatar_url,
    user_id: sender_id,
    email: sender_email,
    full_name: sender_full_name,
  } = otherUser;

  return {
    sender_domain: '',

    avatar_url,
    client: 'ExampleClient',
    gravatar_hash: 'd3adb33f',
    sender_email,
    sender_full_name,
    sender_id,
    sender_realm_str: 'zulip',
    sender_short_name: '',
  };
};

/** Caveat emptor!  These values may not be representative. */
const pmMessage = (extra?: $Rest<Message, {}>): Message => {
  const baseMessage: Message = {
    ...messagePropertiesBase,
    ...messagePropertiesFromSender(otherUser),

    content: 'This is an example PM message.',
    content_type: 'text/markdown',
    display_recipient: [displayRecipientFromUser(selfUser)],
    id: 1234567,
    recipient_id: 2342,
    stream_id: -1,
    subject: '',
    timestamp: 1556579160,
    type: 'private',
  };

  return { ...baseMessage, ...extra };
};

const messagePropertiesFromStream = (stream1: Stream) => {
  const { stream_id, name: display_recipient } = stream1;
  return {
    recipient_id: 2567,
    display_recipient,
    stream_id,
  };
};

/** Caveat emptor!  These values may not be representative. */
const streamMessage = (extra?: $Rest<Message, {}>): Message => {
  const baseMessage: Message = {
    ...messagePropertiesBase,
    ...messagePropertiesFromSender(otherUser),
    ...messagePropertiesFromStream(stream),

    content: 'This is an example stream message.',
    content_type: 'text/markdown',
    id: 1234789,
    subject: 'example topic',
    timestamp: 1556579727,
    type: 'stream',
  };

  return { ...baseMessage, ...extra };
};

const privateReduxStore = createStore(rootReducer);

const baseReduxState: GlobalState = deepFreeze(privateReduxStore.getState());

const reduxState = (extra?: $Rest<GlobalState, {}>): GlobalState =>
  deepFreeze({
    ...baseReduxState,
    ...extra,
  });

const realmState = (extra?: $Rest<RealmState, {}>): RealmState =>
  deepFreeze({
    ...baseReduxState.realm,
    ...extra,
  });

const action = deepFreeze({
  account_switch: {
    type: ACCOUNT_SWITCH,
    index: 0,
  },
  login_success: {
    type: LOGIN_SUCCESS,
    realm: selfAccount.realm,
    email: selfAccount.email,
    apiKey: selfAccount.apiKey,
  },
});

export const eg = {
  makeUser,
  makeCrossRealmBot,
  selfUser,
  selfAccount,
  otherUser,
  crossRealmBot,
  stream,

  pmMessage,
  streamMessage,

  baseReduxState,
  reduxState,
  realmState,

  action,
};
<commit_msg>exampleData: Make somewhat better random strings.<commit_after>/* @flow strict-local */
import deepFreeze from 'deep-freeze';
import { createStore } from 'redux';

import type { CrossRealmBot, Message, PmRecipientUser, Stream, User } from '../api/modelTypes';
import type { GlobalState, RealmState } from '../reduxTypes';
import type { Account } from '../types';
import { ACCOUNT_SWITCH, LOGIN_SUCCESS } from '../actionConstants';
import rootReducer from '../boot/reducers';

// TODO either fix Jest test-discovery patterns, or rename this file,
// so this dummy test isn't required.
describe('nothing', () => {
  test('nothing', () => {});
});

/** Return an integer 0 <= N < end, roughly uniformly at random. */
const randInt = (end: number) => Math.floor(Math.random() * end);

/** Return a string that's almost surely different every time. */
const randString = () => randInt(2 ** 54).toString(36);

const userOrBotProperties = ({ name: _name }) => {
  const name = _name !== undefined ? _name : randString();
  const capsName = name.substring(0, 1).toUpperCase() + name.substring(1);
  return {
    avatar_url: `https://zulip.example.org/yo/avatar-${name}.png`,

    date_joined: `2014-04-${randInt(30)
      .toString()
      .padStart(2, '0')}`,

    email: `${name}@example.org`,
    full_name: `${capsName} User`,
    is_admin: false,
    timezone: 'UTC',
    user_id: randInt(10000),
  };
};

/** Caveat emptor!  These values may not be representative. */
const makeUser = (args: { name?: string } = {}): User => ({
  ...userOrBotProperties(args),

  is_bot: false,
  // bot_type omitted
  // bot_owner omitted

  is_guest: false,

  // profile_data omitted
});

/** Caveat emptor!  These values may not be representative. */
const makeCrossRealmBot = (args: { name?: string } = {}): CrossRealmBot => ({
  ...userOrBotProperties(args),
  is_bot: true,
});

const makeAccount = (user: User): Account => ({
  realm: 'https://zulip.example.org',
  email: user.email,
  apiKey: randString() + randString(),
  ackedPushToken: null,
});

const selfUser: User = makeUser({ name: 'self' });
const selfAccount: Account = makeAccount(selfUser);

const otherUser: User = makeUser({ name: 'other' });

const crossRealmBot: CrossRealmBot = makeCrossRealmBot({ name: 'bot' });

const stream: Stream = {
  stream_id: 34,
  description: 'An example stream.',
  name: 'a stream',
  invite_only: false,
  is_announcement_only: false,
  history_public_to_subscribers: true,
};

const displayRecipientFromUser = (user: User): PmRecipientUser => {
  const { email, full_name, user_id: id } = user;
  return {
    email,
    full_name,
    id,
    is_mirror_dummy: false,
    short_name: '', // what is this, anyway?
  };
};

/** Boring properties common to all example Message objects. */
const messagePropertiesBase = {
  isOutbox: false,

  // match_content omitted
  // match_subject omitted

  // flags omitted

  edit_history: [],
  is_me_message: false,
  // last_edit_timestamp omitted
  reactions: [],
  subject_links: [],
  submessages: [],
};

const messagePropertiesFromSender = (user: User) => {
  const {
    avatar_url,
    user_id: sender_id,
    email: sender_email,
    full_name: sender_full_name,
  } = otherUser;

  return {
    sender_domain: '',

    avatar_url,
    client: 'ExampleClient',
    gravatar_hash: 'd3adb33f',
    sender_email,
    sender_full_name,
    sender_id,
    sender_realm_str: 'zulip',
    sender_short_name: '',
  };
};

/** Caveat emptor!  These values may not be representative. */
const pmMessage = (extra?: $Rest<Message, {}>): Message => {
  const baseMessage: Message = {
    ...messagePropertiesBase,
    ...messagePropertiesFromSender(otherUser),

    content: 'This is an example PM message.',
    content_type: 'text/markdown',
    display_recipient: [displayRecipientFromUser(selfUser)],
    id: 1234567,
    recipient_id: 2342,
    stream_id: -1,
    subject: '',
    timestamp: 1556579160,
    type: 'private',
  };

  return { ...baseMessage, ...extra };
};

const messagePropertiesFromStream = (stream1: Stream) => {
  const { stream_id, name: display_recipient } = stream1;
  return {
    recipient_id: 2567,
    display_recipient,
    stream_id,
  };
};

/** Caveat emptor!  These values may not be representative. */
const streamMessage = (extra?: $Rest<Message, {}>): Message => {
  const baseMessage: Message = {
    ...messagePropertiesBase,
    ...messagePropertiesFromSender(otherUser),
    ...messagePropertiesFromStream(stream),

    content: 'This is an example stream message.',
    content_type: 'text/markdown',
    id: 1234789,
    subject: 'example topic',
    timestamp: 1556579727,
    type: 'stream',
  };

  return { ...baseMessage, ...extra };
};

const privateReduxStore = createStore(rootReducer);

const baseReduxState: GlobalState = deepFreeze(privateReduxStore.getState());

const reduxState = (extra?: $Rest<GlobalState, {}>): GlobalState =>
  deepFreeze({
    ...baseReduxState,
    ...extra,
  });

const realmState = (extra?: $Rest<RealmState, {}>): RealmState =>
  deepFreeze({
    ...baseReduxState.realm,
    ...extra,
  });

const action = deepFreeze({
  account_switch: {
    type: ACCOUNT_SWITCH,
    index: 0,
  },
  login_success: {
    type: LOGIN_SUCCESS,
    realm: selfAccount.realm,
    email: selfAccount.email,
    apiKey: selfAccount.apiKey,
  },
});

export const eg = {
  makeUser,
  makeCrossRealmBot,
  selfUser,
  selfAccount,
  otherUser,
  crossRealmBot,
  stream,

  pmMessage,
  streamMessage,

  baseReduxState,
  reduxState,
  realmState,

  action,
};
<|endoftext|>


<commit_before>// ==UserScript==
// @name         AgarTool⇒Legend Mod
// @name:ja      AgarTool⇒Legend Mod
// @name:en      AgarTool⇒Legend Mod
// @version      0.12
// @namespace    AgarTool⇒Legend Mod
// @description  Link Agar Tool to Legend Mod
// @description:ja   Legend Mod 上から Agar Tool へ情報連携します
// @description:en   Link to Agar Tool on Legend Mod
// @author       tannichi & Jimboy3100
// @match        http://agar.io/*
// @downloadURL  jimboy3100.github.io/ExampleScripts/LMAgartool.user.js
// @updateURL    jimboy3100.github.io/ExampleScripts/LMAgartool.user.js
// @grant        none
// @run-at document-end
// @grant none
// ==/UserScript==

//v0.12

/*MIT License

Copyright (c) [The Legend Mod]

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
  var tamp = setInterval(function() {
      if (document.getElementsByClassName('circle bordered skinWrapper').length > 0) {
          clearInterval(tamp);
          var elem = document.body;
          var script = document.createElement('script');
          script.src = 'https://jimboy3100.github.io/ExampleScripts/LMAgartool.js';
          document.head.appendChild(script);
          elem.appendChild(script);
      }
  }, 100);
<commit_msg>Update LMAgartool.user.js<commit_after>// ==UserScript==
// @name         Legend Mod⇒AgarTool
// @name:ja      Legend Mod⇒AgarTool
// @name:en      Legend Mod⇒AgarTool
// @version      0.13
// @namespace    Legend Mod⇒AgarTool
// @description  Link Legend Mod to Agar tool
// @description:ja   Legend Mod 上から Agar Tool へ情報連携します
// @description:en   Link to Legend Mod on Agar Tool
// @author       tannichi & Jimboy3100
// @match        http://agar.io/*
// @downloadURL  jimboy3100.github.io/ExampleScripts/LMtoAgartool.user.js
// @updateURL    jimboy3100.github.io/ExampleScripts/LMtoAgartool.user.js
// @grant        none
// @run-at document-end
// ==/UserScript==

//This  Script is the opposite of the script AgarTool⇒Legend Mod.
//It is already installed on LM Main version.
//It can be installed for LM Express, Kitty mod, Ogario v3&v4,
//so people can communicate with Agar Tool mod users.

//v0.12

/*MIT License
Copyright (c) [The Legend Mod]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
  var tamp = setInterval(function() {
          clearInterval(tamp);
          var elem = document.body;
          var script = document.createElement('script');
          script.src = 'https://jimboy3100.github.io/ExampleScripts/LMtoAgartool.js';
          document.head.appendChild(script);
          elem.appendChild(script);
  }, 3000);
<|endoftext|>


<commit_before>'use strict';

var fs = require('fs');
var _ = require('underscore');
var geoJSONSQL = fs.readFileSync(__dirname + '/geojson_template.sql', 'utf8');

function GeoJsonSqlWrapper() {
    this.geoJSONTemplate = _.template(geoJSONSQL);
}

GeoJsonSqlWrapper.prototype.wrap = function (queryContext) {
    return this.geoJSONTemplate(queryContext);
};

module.exports = GeoJsonSqlWrapper;
<commit_msg>Renamed geojson sql wrapper's properties<commit_after>'use strict';

var fs = require('fs');
var _ = require('underscore');
var geojsonSQL = fs.readFileSync(__dirname + '/geojson_template.sql', 'utf8');

function GeojsonSqlWrapper() {
    this.geojsonTemplate = _.template(geojsonSQL);
}

module.exports = GeojsonSqlWrapper;

GeojsonSqlWrapper.prototype.wrap = function (queryContext) {
    return this.geojsonTemplate(queryContext);
};
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2012-2013 B3Partners B.V.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Graph component
 * Creates a Graph component
 * @author Meine Toonen
 */
Ext.define("viewer.components.Graph", {
    extend: "viewer.components.Component",
    panel: null,
    initialized: false,
    toolMapClick:null,
    deActivatedTools:null,
    layers:null,
    config: {
        title: null,
        iconUrl: null,
        tooltip: null,
        graphs: null
    },
    constructor: function(conf) {
        viewer.components.Graph.superclass.constructor.call(this, conf);
        this.initConfig(conf);
        var me = this;
        this.renderButton({
            handler: function() {
                 me.buttonClick();
            },
            text: me.title,
            icon: me.iconUrl,
            tooltip: me.tooltip,
            label: me.label
        });
        this.viewerController.addListener(viewer.viewercontroller.controller.Event.ON_LAYERS_INITIALIZED, this.initialize, this);
        return this;
    },
    initialize: function() {
        this.initialized = true;

        this.toolMapClick =  this.viewerController.mapComponent.createTool({
            type: viewer.viewercontroller.controller.Tool.MAP_CLICK,
            id: this.name + "toolMapClick",
            handler:{
                fn: this.mapClicked,
                scope:this
            },
            viewerController: this.viewerController
        });

        this.layers = [];
        for (var i = 0 ; i < this.graphs.length ;i ++){
            var graph = this.graphs[i];
            this.layers.push(graph.layer);
        }
        this.loadWindow();
    },
     loadWindow : function (){
        var me =this;
        this.maincontainer = Ext.create('Ext.container.Container', {
            id: this.name + 'Container',
            width: '100%',
            height: '100%',
            autoScroll: true,
            layout: {
                type: 'vbox',
                align: 'stretch'
            },
            style: {
                backgroundColor: 'White'
            },
            renderTo: this.getContentDiv(),
            items: [
                {
                    id: this.name + 'LayerSelectorPanel',
                    xtype: "container",
                    padding: 4,
                    height: 36
                },
                {
                    xtype: "container",
                    items: [{
                        xtype: 'button',
                        text: 'Selecteer punt voor grafiek',
                        listeners: {
                            click: {
                                scope: me,
                                fn: me.activateMapClick
                            }
                        }
                    }],
                    height: 25
                },
                 {
                    id: this.name + 'graphPanel',
                    xtype: this.graphs.length > 1 ? "tabpanel" : "container",
                    padding: 4,
                    flex: 1,
                    layout: 'fit'
                }
            ]
        });
        this.createLayerSelector();
    },
    createLayerSelector: function(){
        var config = {
            viewerController : this.viewerController,
            restriction : "attribute",
            id : this.name + "layerSelector",
            layers: this.layers,
            div: this.name + 'LayerSelectorPanel'
        };
        this.layerSelector = Ext.create("viewer.components.LayerSelector",config);
        if(this.layers.length === 1){
            this.layerSelector.setValue(this.layers[0]);
        }
    },
    mapClicked : function(tool, comp){
       this.deactivateMapClick();
        //Ext.get(this.getContentDiv()).mask("Haalt features op...")
        var coords = comp.coord;
        var x = coords.x;
        var y = coords.y;

        var appLayer = this.layerSelector.getValue();
        if(appLayer === null) {
            Ext.Msg.alert('Let op', 'Selecteer eerst een kaartlaag');
            return;
        }
        var graphConfig = this.getConfigByAppLayer(appLayer.id);
        var attributes = [];
        if(!graphConfig){
            return;
        }
        var me = this;
        var graphPanel = Ext.getCmp(this.name + 'graphPanel');
        graphPanel.removeAll();
        // We create placeholders to be able to insert graphs in correct order in the tabpanel
        if(graphConfig.length > 1) {
            for(var i = 0; i < graphConfig.length; i++) {
                graphPanel.add({
                    xtype: 'container',
                    title: graphConfig[i].title,
                    html: 'Bezig met laden...',
                    padding: 10,
                    id: 'placeholderContainer' + i
                });
            }
        }
        for(var i = 0; i < graphConfig.length; i++) {
            (function(config, configId){
                for(var j = 0; j < config.serieAttribute.length; j++) {
                    attributes.push(config.serieAttribute[j]);
                }
                attributes.push(config.categoryAttribute);
                var extraParams = {
                    attributesToInclude : attributes,
                    graph:true
                };
                this.viewerController.mapComponent.getMap().setMarker("edit",x,y);
                var featureInfo = Ext.create("viewer.FeatureInfo", {
                    viewerController: me.viewerController
                });
                featureInfo.editFeatureInfo(x,y,me.viewerController.mapComponent.getMap().getResolution() * 4,appLayer, function (features){
                    me.featuresReceived(features, attributes, configId);
                },function(msg){me.failed(msg);},extraParams);
            })(graphConfig[i], i);
        }
    },
    failed: function(msg) {
        Ext.Msg.alert('Fout', 'Fout bij het ophalen van de grafiek gegevens');
    },
    featuresReceived : function (features,attributes, configId){
        var json = {};
        for (var i = 0 ; i < features.length ;i++){
            var feature = features[i];
            json = feature;
            if(json.related_featuretypes){
                for (var j = 0 ; j < json.related_featuretypes.length ;j++){
                    var linked = this.getLinkedData(json.related_featuretypes[i], attributes, configId);
                    json.linkedData = linked;
                    break;
                }
            }
        }
    },
    getLinkedData : function (related_feature,attributes, configId){
        var appLayer = this.layerSelector.getValue();
        var options = {};

        var filter = "&filter="+encodeURIComponent(related_feature.filter);

        var featureType="&featureType="+related_feature.id;

        options.application = this.appId;
        options.appLayer = appLayer.id;
        options.limit = 1000;
        options.filter = filter;
        options.graph = true;
        options.arrays = false;
        options.attributesToInclude = attributes;
        Ext.Ajax.request({
            url: appLayer.featureService.getStoreUrl() + featureType+filter,
            params: options,
            scope: this,
            success: function(result) {
                var response = Ext.JSON.decode(result.responseText);
                var features = response.features;
                this.createGraph(appLayer, features, configId);
            },
            failure: function(result) {
               this.viewerController.logger.error(result);
            }
        });
    },
    buttonClick: function(){
        this.popup.show();
    },
    createGraph : function (appLayer,  data, configId){
        var gco = this.graphs[configId];
        var me = this;
        var fields = this.getAttributeName(appLayer,gco.serieAttribute);
        fields.push(this.getAttributeName(appLayer,gco.categoryAttribute));
        var store = Ext.create('Ext.data.JsonStore', {
            fields: fields,
            data: data
        });

        var graphType = gco.type.toLowerCase();
        // Line charts need to have multiple series
        // Bar/Column charts need 1 serie with multiple yFields
        // For line charts we can iterate over serieAttribute array,
        // for bar/column we wrap it in an array so 1 serie is added only.
        var series = [], serieAttributes = gco.serieAttribute;
        if(graphType === 'bar' || graphType === 'column') {
            serieAttributes = [ gco.serieAttribute ];
        }
        for(var i = 0; i < serieAttributes.length; i++) {
            (function(serieAttribute) {
                series.push({
                    type: graphType,
                    axis: 'left',
                    xField: me.getAttributeName(appLayer, gco.categoryAttribute),
                    yField: me.getAttributeName(appLayer, serieAttribute),
                    markerConfig: {
                        type: 'circle',
                        size: 4,
                        radius: 4,
                        'stroke-width': 0
                    },
                    tips: {
                        trackMouse: true,
                        minWidth: 140,
                        height: 28,
                        renderer: function(storeItem, item) {
                            if(graphType === 'bar' || graphType === 'column') {
                                this.setTitle(item.value[0] + ': ' + item.value[1]);
                            } else {
                                this.setTitle(storeItem.get(me.getAttributeName(appLayer,gco.categoryAttribute)) + ': ' + storeItem.get(me.getAttributeName(appLayer,serieAttribute)));
                            }
                        }
                    },
                    highlight: {
                        size: 7,
                        radius: 7
                    }
                });
            })(serieAttributes[i]);
        }
        /*
         * The setup for a Theme, we could use this in the future to control the color of the lines/bars
         *
         * Ext.define('Ext.chart.theme.Flamingo', {
            extend: 'Ext.chart.theme.Base',
            constructor: function(config) {
                var themeConfig = [Ext.apply({
                    series: {
                        'stroke-width': 1
                    },
                    colors: ['#FF0000', '#00FF00', '#0000FF', '#4292C6', '#2171B5', '#084594'],
                    seriesThemes: [{
                        fill: "#FF0000"
                        }, {
                        fill: "#00FF00"
                        }, {
                        fill: "#0000FF"
                        }, {
                        fill: '#4292C6'
                        },{
                        fill: '#2171B5'
                        },{
                        fill: '#084594'
                        }
                    ],
                    stacked: false
                }, config)];
                this.callParent(themeConfig);
            }
        }); */
        var axes = [
            {
                type: 'Numeric',
                position: 'left',
                fields: this.getAttributeName(appLayer, gco.serieAttribute),
                label: {
                    renderer: Ext.util.Format.numberRenderer('0,0')
                },
                title: this.isArray(gco.serieAttribute) ? '' : this.getAttributeTitle(appLayer,gco.serieAttribute),
                grid: true,
                minimum: 0
            },{
                type: 'Category',
                position: 'bottom',
                fields: [this.getAttributeName(appLayer,gco.categoryAttribute)],
                title: this.getAttributeTitle(appLayer,gco.categoryAttribute)
            }
        ];
        if(graphType === 'bar') {
            axes[0]['position'] = 'bottom';
            axes[1]['position'] = 'left';
        }
        var chart = Ext.create('Ext.chart.Chart', {
            //theme: 'Flamingo',
            animate: true,
            store: store,
            axes: axes,
            series: series,
            title: gco.title,
            legend: true
        });
        var graphPanel = Ext.getCmp(this.name + 'graphPanel');
        // remove placeholder
        graphPanel.remove('placeholderContainer' + configId, true);
        // add graph in placeholder place
        graphPanel.insert(configId, chart);
        // Always select first tab
        graphPanel.setActiveTab(0);
    },
    activateMapClick: function(){
        this.deActivatedTools = this.viewerController.mapComponent.deactivateTools();
        this.toolMapClick.activateTool();
    },
    deactivateMapClick: function(){
        for (var i=0; i < this.deActivatedTools.length; i++){
            this.deActivatedTools[i].activate();
        }
        this.deActivatedTools = [];
        this.toolMapClick.deactivateTool();
    },
    getConfigByAppLayer : function (appLayerId) {
        var configs = [];
        for (var i = 0 ; i < this.graphs.length ;i++){
            if(this.graphs[i].layer === appLayerId){
                configs.push(this.graphs[i]);
            }
        }
        if(!configs.length) return null;
        return configs;
    },
    getAttribute : function (appLayer, attributeId){
        for(var i = 0 ; i < appLayer.attributes.length;i++){
            if(appLayer.attributes[i].id === attributeId){
                return appLayer.attributes[i];
            }
        }
        return null;
    },
    getAttributeName: function(appLayer, attributeId) {
        return this.getAttributeTitleName(appLayer, attributeId, false);
    },
    getAttributeTitle: function(appLayer, attributeId) {
        return this.getAttributeTitleName(appLayer, attributeId, true);
    },
    getAttributeTitleName: function(appLayer, attributeId, allowAlias) {
        var attributes = this.wrapArray(attributeId),
            attributeTitles = [],
            attribute = null;
        for(var i = 0; i < attributes.length; i++) {
            attribute = this.getAttribute(appLayer, attributes[i]);
            if(attribute === null) {
                attributeTitles.push('');
                continue;
            }
            attributeTitles.push(allowAlias && attribute.alias ? attribute.alias : attribute.name);
        }
        if(attributeTitles.length === 1) return attributeTitles[0];
        return attributeTitles;
    },
    wrapArray: function(item) {
        if(this.isArray(item)) return item;
        return [ item ];
    },
    isArray: function(item) {
        return Object.prototype.toString.call(item) === '[object Array]';
    },
    getExtComponents: function() {
        return [ this.maincontainer.getId() ];
    }
});
<commit_msg>Solved error when trying to setActiveTab when there are none. Fixed problem when using attributes with aliases (they were ignored)<commit_after>/*
 * Copyright (C) 2012-2013 B3Partners B.V.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Graph component
 * Creates a Graph component
 * @author Meine Toonen
 */
Ext.define("viewer.components.Graph", {
    extend: "viewer.components.Component",
    panel: null,
    initialized: false,
    toolMapClick:null,
    deActivatedTools:null,
    layers:null,
    config: {
        title: null,
        iconUrl: null,
        tooltip: null,
        graphs: null
    },
    constructor: function(conf) {
        viewer.components.Graph.superclass.constructor.call(this, conf);
        this.initConfig(conf);
        var me = this;
        this.renderButton({
            handler: function() {
                 me.buttonClick();
            },
            text: me.title,
            icon: me.iconUrl,
            tooltip: me.tooltip,
            label: me.label
        });
        this.viewerController.addListener(viewer.viewercontroller.controller.Event.ON_LAYERS_INITIALIZED, this.initialize, this);
        return this;
    },
    initialize: function() {
        this.initialized = true;

        this.toolMapClick =  this.viewerController.mapComponent.createTool({
            type: viewer.viewercontroller.controller.Tool.MAP_CLICK,
            id: this.name + "toolMapClick",
            handler:{
                fn: this.mapClicked,
                scope:this
            },
            viewerController: this.viewerController
        });

        this.layers = [];
        for (var i = 0 ; i < this.graphs.length ;i ++){
            var graph = this.graphs[i];
            this.layers.push(graph.layer);
        }
        this.loadWindow();
    },
     loadWindow : function (){
        var me =this;
        this.maincontainer = Ext.create('Ext.container.Container', {
            id: this.name + 'Container',
            width: '100%',
            height: '100%',
            autoScroll: true,
            layout: {
                type: 'vbox',
                align: 'stretch'
            },
            style: {
                backgroundColor: 'White'
            },
            renderTo: this.getContentDiv(),
            items: [
                {
                    id: this.name + 'LayerSelectorPanel',
                    xtype: "container",
                    padding: 4,
                    height: 36
                },
                {
                    xtype: "container",
                    items: [{
                        xtype: 'button',
                        text: 'Selecteer punt voor grafiek',
                        listeners: {
                            click: {
                                scope: me,
                                fn: me.activateMapClick
                            }
                        }
                    }],
                    height: 25
                },
                 {
                    id: this.name + 'graphPanel',
                    xtype: this.graphs.length > 1 ? "tabpanel" : "container",
                    padding: 4,
                    flex: 1,
                    layout: 'fit'
                }
            ]
        });
        this.createLayerSelector();
    },
    createLayerSelector: function(){
        var config = {
            viewerController : this.viewerController,
            restriction : "attribute",
            id : this.name + "layerSelector",
            layers: this.layers,
            div: this.name + 'LayerSelectorPanel'
        };
        this.layerSelector = Ext.create("viewer.components.LayerSelector",config);
        if(this.layers.length === 1){
            this.layerSelector.setValue(this.layers[0]);
        }
    },
    mapClicked : function(tool, comp){
       this.deactivateMapClick();
        //Ext.get(this.getContentDiv()).mask("Haalt features op...")
        var coords = comp.coord;
        var x = coords.x;
        var y = coords.y;

        var appLayer = this.layerSelector.getValue();
        if(appLayer === null) {
            Ext.Msg.alert('Let op', 'Selecteer eerst een kaartlaag');
            return;
        }
        var graphConfig = this.getConfigByAppLayer(appLayer.id);
        var attributes = [];
        if(!graphConfig){
            return;
        }
        var me = this;
        var graphPanel = Ext.getCmp(this.name + 'graphPanel');
        graphPanel.removeAll();
        // We create placeholders to be able to insert graphs in correct order in the tabpanel
        if(graphConfig.length > 1) {
            for(var i = 0; i < graphConfig.length; i++) {
                graphPanel.add({
                    xtype: 'container',
                    title: graphConfig[i].title,
                    html: 'Bezig met laden...',
                    padding: 10,
                    id: 'placeholderContainer' + i
                });
            }
        }
        for(var i = 0; i < graphConfig.length; i++) {
            (function(config, configId){
                for(var j = 0; j < config.serieAttribute.length; j++) {
                    attributes.push(config.serieAttribute[j]);
                }
                attributes.push(config.categoryAttribute);
                var extraParams = {
                    attributesToInclude : attributes,
                    graph:true
                };
                this.viewerController.mapComponent.getMap().setMarker("edit",x,y);
                var featureInfo = Ext.create("viewer.FeatureInfo", {
                    viewerController: me.viewerController
                });
                featureInfo.editFeatureInfo(x,y,me.viewerController.mapComponent.getMap().getResolution() * 4,appLayer, function (features){
                    me.featuresReceived(features, attributes, configId);
                },function(msg){me.failed(msg);},extraParams);
            })(graphConfig[i], i);
        }
    },
    failed: function(msg) {
        Ext.Msg.alert('Fout', 'Fout bij het ophalen van de grafiek gegevens');
    },
    featuresReceived : function (features,attributes, configId){
        var json = {};
        for (var i = 0 ; i < features.length ;i++){
            var feature = features[i];
            json = feature;
            if(json.related_featuretypes){
                for (var j = 0 ; j < json.related_featuretypes.length ;j++){
                    var linked = this.getLinkedData(json.related_featuretypes[i], attributes, configId);
                    json.linkedData = linked;
                    break;
                }
            }
        }
    },
    getLinkedData : function (related_feature,attributes, configId){
        var appLayer = this.layerSelector.getValue();
        var options = {};

        var filter = "&filter="+encodeURIComponent(related_feature.filter);

        var featureType="&featureType="+related_feature.id;

        options.application = this.appId;
        options.appLayer = appLayer.id;
        options.limit = 1000;
        options.filter = filter;
        options.graph = true;
        options.arrays = false;
        options.attributesToInclude = attributes;
        Ext.Ajax.request({
            url: appLayer.featureService.getStoreUrl() + featureType+filter,
            params: options,
            scope: this,
            success: function(result) {
                var response = Ext.JSON.decode(result.responseText);
                var features = response.features;
                this.createGraph(appLayer, features, configId);
            },
            failure: function(result) {
               this.viewerController.logger.error(result);
            }
        });
    },
    buttonClick: function(){
        this.popup.show();
    },
    createGraph : function (appLayer,  data, configId){
        var gco = this.graphs[configId];
        var me = this;
        var fields = this.getAttributeTitle(appLayer,gco.serieAttribute);
        if(!(fields instanceof Array)){
            fields = [fields];
        }
        fields.push(this.getAttributeTitle(appLayer,gco.categoryAttribute));
        var store = Ext.create('Ext.data.JsonStore', {
            fields: fields,
            data: data
        });

        var graphType = gco.type.toLowerCase();
        // Line charts need to have multiple series
        // Bar/Column charts need 1 serie with multiple yFields
        // For line charts we can iterate over serieAttribute array,
        // for bar/column we wrap it in an array so 1 serie is added only.
        var series = [], serieAttributes = gco.serieAttribute;
        if(graphType === 'bar' || graphType === 'column') {
            serieAttributes = [ gco.serieAttribute ];
        }
        for(var i = 0; i < serieAttributes.length; i++) {
            (function(serieAttribute) {
                series.push({
                    type: graphType,
                    axis: 'left',
                    xField: me.getAttributeTitle(appLayer, gco.categoryAttribute),
                    yField: me.getAttributeTitle(appLayer, serieAttribute),
                    markerConfig: {
                        type: 'circle',
                        size: 4,
                        radius: 4,
                        'stroke-width': 0
                    },
                    tips: {
                        trackMouse: true,
                        minWidth: 140,
                        height: 28,
                        renderer: function(storeItem, item) {
                            if(graphType === 'bar' || graphType === 'column') {
                                this.setTitle(item.value[0] + ': ' + item.value[1]);
                            } else {
                                this.setTitle(storeItem.get(me.getAttributeName(appLayer,gco.categoryAttribute)) + ': ' + storeItem.get(me.getAttributeName(appLayer,serieAttribute)));
                            }
                        }
                    },
                    highlight: {
                        size: 7,
                        radius: 7
                    }
                });
            })(serieAttributes[i]);
        }
        /*
         * The setup for a Theme, we could use this in the future to control the color of the lines/bars
         *
         * Ext.define('Ext.chart.theme.Flamingo', {
            extend: 'Ext.chart.theme.Base',
            constructor: function(config) {
                var themeConfig = [Ext.apply({
                    series: {
                        'stroke-width': 1
                    },
                    colors: ['#FF0000', '#00FF00', '#0000FF', '#4292C6', '#2171B5', '#084594'],
                    seriesThemes: [{
                        fill: "#FF0000"
                        }, {
                        fill: "#00FF00"
                        }, {
                        fill: "#0000FF"
                        }, {
                        fill: '#4292C6'
                        },{
                        fill: '#2171B5'
                        },{
                        fill: '#084594'
                        }
                    ],
                    stacked: false
                }, config)];
                this.callParent(themeConfig);
            }
        }); */
        var axes = [
            {
                type: 'Numeric',
                position: 'left',
                fields: this.getAttributeName(appLayer, gco.serieAttribute),
                label: {
                    renderer: Ext.util.Format.numberRenderer('0,0')
                },
                title: this.isArray(gco.serieAttribute) ? '' : this.getAttributeTitle(appLayer,gco.serieAttribute),
                grid: true,
                minimum: 0
            },{
                type: 'Category',
                position: 'bottom',
                fields: [this.getAttributeName(appLayer,gco.categoryAttribute)],
                title: this.getAttributeTitle(appLayer,gco.categoryAttribute)
            }
        ];
        if(graphType === 'bar') {
            axes[0]['position'] = 'bottom';
            axes[1]['position'] = 'left';
        }
        var chart = Ext.create('Ext.chart.Chart', {
            //theme: 'Flamingo',
            animate: true,
            store: store,
            axes: axes,
            series: series,
            title: gco.title,
            legend: true
        });
        var graphPanel = Ext.getCmp(this.name + 'graphPanel');
        // remove placeholder
        graphPanel.remove('placeholderContainer' + configId, true);
        // add graph in placeholder place
        graphPanel.insert(configId, chart);
        // Always select first tab
        if(graphPanel.setActiveTab){
            graphPanel.setActiveTab(0);
        }
    },
    activateMapClick: function(){
        this.deActivatedTools = this.viewerController.mapComponent.deactivateTools();
        this.toolMapClick.activateTool();
    },
    deactivateMapClick: function(){
        for (var i=0; i < this.deActivatedTools.length; i++){
            this.deActivatedTools[i].activate();
        }
        this.deActivatedTools = [];
        this.toolMapClick.deactivateTool();
    },
    getConfigByAppLayer : function (appLayerId) {
        var configs = [];
        for (var i = 0 ; i < this.graphs.length ;i++){
            if(this.graphs[i].layer === appLayerId){
                configs.push(this.graphs[i]);
            }
        }
        if(!configs.length) return null;
        return configs;
    },
    getAttribute : function (appLayer, attributeId){
        for(var i = 0 ; i < appLayer.attributes.length;i++){
            if(appLayer.attributes[i].id === attributeId){
                return appLayer.attributes[i];
            }
        }
        return null;
    },
    getAttributeName: function(appLayer, attributeId) {
        return this.getAttributeTitleName(appLayer, attributeId, false);
    },
    getAttributeTitle: function(appLayer, attributeId) {
        return this.getAttributeTitleName(appLayer, attributeId, true);
    },
    getAttributeTitleName: function(appLayer, attributeId, allowAlias) {
        var attributes = this.wrapArray(attributeId),
            attributeTitles = [],
            attribute = null;
        for(var i = 0; i < attributes.length; i++) {
            attribute = this.getAttribute(appLayer, attributes[i]);
            if(attribute === null) {
                attributeTitles.push('');
                continue;
            }
            attributeTitles.push(allowAlias && attribute.alias ? attribute.alias : attribute.name);
        }
        if(attributeTitles.length === 1) return attributeTitles[0];
        return attributeTitles;
    },
    wrapArray: function(item) {
        if(this.isArray(item)) return item;
        return [ item ];
    },
    isArray: function(item) {
        return Object.prototype.toString.call(item) === '[object Array]';
    },
    getExtComponents: function() {
        return [ this.maincontainer.getId() ];
    }
});
<|endoftext|>


<commit_before>import React, { PropTypes, Component } from 'react';
import Box from 'grommet/components/Box';
import Image from 'grommet/components/Image';
import Tiles from 'grommet/components/Tiles';
import Tile from 'grommet/components/Tile';
import styled from 'styled-components';

const Div = styled.div`
  @media all and (-ms-high-contrast:none) {
    height: 100%;
  }
`;

const Img = styled.img`
  height: 100%;
  width: 100%;
  @-moz-document url-prefix() {
    height: auto;
  }
`;

export default class ImageGallery extends Component {
  constructor() {
    super();
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick(i) {
    this.props.onClickItem(i);
  }
  render() {
    const {
      images,
      currentIndex,
    } = this.props;
    return (
      <Box align="center" justify="center" direction="column">

          <Tiles responsive={false} pad="none" flush={false}>
            {images && images.map((image, i) =>
              <Tile
                onClick={() => this.handleClick(i)}
                key={i}
                style={{ outline: i === currentIndex ? '.2em solid #01a982' : '' }}
              >
                <Image size="thumb" src={image.path} />
              </Tile>,
            )}
          </Tiles>

      </Box>
    );
  }
}

ImageGallery.propTypes = {
  images: PropTypes.arrayOf(
    PropTypes.shape({
      path: PropTypes.string,
    }),
  ),
  currentIndex: PropTypes.number.isRequired,
  onClickItem: PropTypes.func.isRequired,
};
<commit_msg>Fix: add height 100 only for ie in image gallery component<commit_after>import React, { PropTypes, Component } from 'react';
import Box from 'grommet/components/Box';
import Image from 'grommet/components/Image';
import Tiles from 'grommet/components/Tiles';
import Tile from 'grommet/components/Tile';
import styled from 'styled-components';

const Div = styled.div`
  @media all and (-ms-high-contrast:none) {
    height: 100%;
  }
`;

const Img = styled.img`
  width: 100%;
  @media all and (-ms-high-contrast:none) {
    height: 100%;
  }
`;

export default class ImageGallery extends Component {
  constructor() {
    super();
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick(i) {
    this.props.onClickItem(i);
  }
  render() {
    const {
      images,
      currentIndex,
    } = this.props;
    return (
      <Box align="center" justify="center" direction="column">

          <Tiles responsive={false} pad="none" flush={false}>
            {images && images.map((image, i) =>
              <Tile
                onClick={() => this.handleClick(i)}
                key={i}
                style={{ outline: i === currentIndex ? '.2em solid #01a982' : '' }}
              >
                <Image size="thumb" src={image.path} />
              </Tile>,
            )}
          </Tiles>

      </Box>
    );
  }
}

ImageGallery.propTypes = {
  images: PropTypes.arrayOf(
    PropTypes.shape({
      path: PropTypes.string,
    }),
  ),
  currentIndex: PropTypes.number.isRequired,
  onClickItem: PropTypes.func.isRequired,
};
<|endoftext|>


<commit_before>import _get from '../utils/get';
import endsWith from 'lodash/endsWith';
import identity from 'lodash/identity';
import icepick from 'icepick';

import getValue from '../utils/get-value';
import isMulti from '../utils/is-multi';
import actionTypes from '../action-types';
import { trackable } from '../utils/track';

const change = trackable((model, value, options = {}) => {
  // option defaults
  const changeOptions = {
    silent: false,
    multi: isMulti(model),
    ...options,
  };

  return {
    type: actionTypes.CHANGE,
    model,
    value: getValue(value),
    ...changeOptions,
  };
});

const xor = trackable((
  model,
  item,
  iteratee = (value) => value === item
) => (dispatch, getState) => {
  const state = _get(getState(), model, []);
  const stateWithoutItem = state.filter(stateItem => !iteratee(stateItem));
  const value = (state.length === stateWithoutItem.length) ? [...state, item] : stateWithoutItem;

  dispatch({
    type: actionTypes.CHANGE,
    model,
    value,
  });
});

const push = trackable((model, item = null) => (dispatch, getState) => {
  const collection = _get(getState(), model);
  const value = [...(collection || []), item];

  dispatch({
    type: actionTypes.CHANGE,
    model,
    value,
  });
});

const toggle = trackable((model) => (dispatch, getState) => {
  const value = !_get(getState(), model);

  dispatch({
    type: actionTypes.CHANGE,
    model,
    value,
  });
});

const filter = trackable((model, iteratee = identity) => (dispatch, getState) => {
  const collection = _get(getState(), model);
  const value = collection.filter(iteratee);

  dispatch({
    type: actionTypes.CHANGE,
    model,
    value,
  });
});

const reset = trackable((model) => ({
  type: actionTypes.RESET,
  model,
}));

const map = trackable((model, iteratee = identity) => (dispatch, getState) => {
  const collection = _get(getState(), model, []);
  const value = collection.map(iteratee);

  dispatch({
    type: actionTypes.CHANGE,
    model,
    value,
  });
});

const remove = trackable((model, index) => (dispatch, getState) => {
  const collection = _get(getState(), model, []);

  dispatch({
    type: actionTypes.CHANGE,
    model,
    value: icepick.splice(collection, index, 1),
    removeKeys: [index],
  });
});

const move = trackable((model, indexFrom, indexTo) => (dispatch, getState) => {
  const collection = _get(getState(), model, []);

  if (indexFrom >= collection.length || indexTo >= collection.length) {
    throw new Error(`Error moving array item: invalid bounds ${indexFrom}, ${indexTo}`);
  }

  const item = collection[indexFrom];
  const removed = icepick.splice(collection, indexFrom, 1);
  const inserted = icepick.splice(removed, indexTo, 0, item);

  dispatch({
    type: actionTypes.CHANGE,
    model,
    value: inserted,
  });
});

const merge = trackable((model, values) => (dispatch, getState) => {
  const value = _get(getState(), model, {});

  dispatch({
    type: actionTypes.CHANGE,
    model,
    value: icepick.merge(value, values),
  });
});

const omit = trackable((model, props = []) => (dispatch, getState) => {
  const value = _get(getState(), model, {});

  const propsArray = typeof props === 'string'
    ? [props]
    : props;

  const newValue = propsArray.reduce(
    (acc, prop) => icepick.dissoc(acc, prop),
    value);

  dispatch({
    type: actionTypes.CHANGE,
    model,
    value: newValue,
    removeKeys: propsArray,
  });
});

const load = trackable((model, values) => change(model, values, {
  silent: true,
}));

export default {
  change,
  filter,
  map,
  merge,
  push,
  remove,
  move,
  reset,
  toggle,
  xor,
  load,
  omit,
};
<commit_msg>Adding "strategy" for model actions<commit_after>import _get from '../utils/get';
import endsWith from 'lodash/endsWith';
import identity from 'lodash/identity';
import icepick from 'icepick';

import getValue from '../utils/get-value';
import isMulti from '../utils/is-multi';
import actionTypes from '../action-types';
import { trackable } from '../utils/track';

const defaultStrategies = {
  get: _get,
  getValue,
  splice: icepick.splice,
  merge: icepick.merge,
  remove: icepick.dissoc,
};

function createModelActions(s = defaultStrategies) {
  const change = trackable((model, value, options = {}) => {
    // option defaults
    const changeOptions = {
      silent: false,
      multi: isMulti(model),
      ...options,
    };

    return {
      type: actionTypes.CHANGE,
      model,
      value: s.getValue(value),
      ...changeOptions,
    };
  });

  const xor = trackable((
    model,
    item,
    iteratee = (value) => value === item
  ) => (dispatch, getState) => {
    const state = s.get(getState(), model, []);
    const stateWithoutItem = state.filter(stateItem => !iteratee(stateItem));
    const value = (state.length === stateWithoutItem.length) ? [...state, item] : stateWithoutItem;

    dispatch({
      type: actionTypes.CHANGE,
      model,
      value,
    });
  });

  const push = trackable((model, item = null) => (dispatch, getState) => {
    const collection = s.get(getState(), model);
    const value = [...(collection || []), item];

    dispatch({
      type: actionTypes.CHANGE,
      model,
      value,
    });
  });

  const toggle = trackable((model) => (dispatch, getState) => {
    const value = !s.get(getState(), model);

    dispatch({
      type: actionTypes.CHANGE,
      model,
      value,
    });
  });

  const filter = trackable((model, iteratee = identity) => (dispatch, getState) => {
    const collection = s.get(getState(), model);
    const value = collection.filter(iteratee);

    dispatch({
      type: actionTypes.CHANGE,
      model,
      value,
    });
  });

  const reset = trackable((model) => ({
    type: actionTypes.RESET,
    model,
  }));

  const map = trackable((model, iteratee = identity) => (dispatch, getState) => {
    const collection = s.get(getState(), model, []);
    const value = collection.map(iteratee);

    dispatch({
      type: actionTypes.CHANGE,
      model,
      value,
    });
  });

  const remove = trackable((model, index) => (dispatch, getState) => {
    const collection = s.get(getState(), model, []);

    dispatch({
      type: actionTypes.CHANGE,
      model,
      value: s.splice(collection, index, 1),
      removeKeys: [index],
    });
  });

  const move = trackable((model, indexFrom, indexTo) => (dispatch, getState) => {
    const collection = s.get(getState(), model, []);

    if (indexFrom >= collection.length || indexTo >= collection.length) {
      throw new Error(`Error moving array item: invalid bounds ${indexFrom}, ${indexTo}`);
    }

    const item = collection[indexFrom];
    const removed = s.splice(collection, indexFrom, 1);
    const inserted = s.splice(removed, indexTo, 0, item);

    dispatch({
      type: actionTypes.CHANGE,
      model,
      value: inserted,
    });
  });

  const merge = trackable((model, values) => (dispatch, getState) => {
    const value = s.get(getState(), model, {});

    dispatch({
      type: actionTypes.CHANGE,
      model,
      value: s.merge(value, values),
    });
  });

  const omit = trackable((model, props = []) => (dispatch, getState) => {
    const value = s.get(getState(), model, {});

    const propsArray = typeof props === 'string'
      ? [props]
      : props;

    const newValue = propsArray.reduce(
      (acc, prop) => s.remove(acc, prop),
      value);

    dispatch({
      type: actionTypes.CHANGE,
      model,
      value: newValue,
      removeKeys: propsArray,
    });
  });

  const load = trackable((model, values) => change(model, values, {
    silent: true,
  }));

  return {
    change,
    filter,
    map,
    merge,
    push,
    remove,
    move,
    reset,
    toggle,
    xor,
    load,
    omit,
  };
}

export default createModelActions();
<|endoftext|>


<commit_before>/* Module: API -- Used by other modules to provide a HTTP+JSON API for other applications, local or remote. */

//Requests to the API use the POST method, have no path and contain the following JSON in the body: {module; ..., method: ..., args: {name: value, ...}}

var Module = require('./Module.js');
var http = require('http');

class ModAPI extends Module {

    get optionalParams() { return [
        'host',                 //Local IP address for the HTTP server to listen on. Use 0.0.0.0 for any.
        'port'                  //Port for the HTTP server to listen on.
    ]; }

    constructor(name) {
        super('API', name);

        this._params['host'] = '127.0.0.1';
        this._params['port'] = 8098;

        this._server = null;
        this._methods = [];  //List of {mod, methodname, args: [...]}
    }

    initialize(opt) {
        if (!super.initialize(opt)) return false;

        this._server = http.createServer((request, response) => {

            if (request.method != 'POST') {
                response.statusCode = 404;
                return response.end();
            }

            let body = '';
            request.on('data', (data) => {
                body += data;
            });

            request.on('end', () => {

                let json = null;
                try {
                    json = JSON.parse(body);
                } catch (err) {
                    response.statusCode = 400;
                    return response.end();
                }

                if (!json || !json.module || !json.method) {
                    response.statusCode = 400;
                    return response.end();
                }

                let info = this._methods.find((item) => item.mod.name == json.module && item.methodname == json.method);
                if (!info) {
                    this.log('warn', '(NOT FOUND) ' + request.headers.host + ' => ' + json.module + '.' + json.method);
                    response.statusCode = 404;
                    return response.end();
                }

                let args = [];
                if (json.args && info.args) {
                    for (let arg of info.args) {
                        args.push(json.args[arg]);
                    }
                }

                this.log(request.headers.host + ' => ' + json.module + '.' + json.method + '(' + args.join(', ') + ')');

                if (!info.mod[info.methodname] || typeof info.mod[info.methodname] != "function") {
                    this.log('error', request.headers.host + ' <= IMPLEMENTATION MISSING?');
                    response.statusCode = 503;
                    return response.end();
                }

                let res = null;
                try {
                    res = info.mod[info.methodname](args);
                } catch (err) {
                    this.log('error', request.headers.host + ' <= Error in implementation: ' + err);
                    response.statusCode = 500;
                    return response.end();
                }

                if (typeof res == "object") res = JSON.stringify(res);

                this.log(request.headers.host + ' <= ' + res);

                response.statusCode = 200;
                response.write(String(res));
                response.end();
            });

        });

        this._server.listen(this.param('port'), this.param('host'), (err) => {
            if (err) this.log('error', err);
            else this.log('Listening on port ' + this.param('port'));
        });

        return true;
    };

    // # Module code below this line #

    //Use this method from dependent modules to expose one of their methods.

    registerMethod(mod, methodname, args) {
        if (!mod || !mod.name || !mod.modName) {
            this.log('warn', 'Failed to register method: The first argument must be the registering module.');
            return false;
        }

        if (!methodname || !mod[methodname] || typeof mod[methodname] != "function") {
            this.log('warn', 'Failed to register method: The method does not exist in the module.');
            return false;
        }

        if (!args) args = [];
        if (!args.length) {
            this.log('warn', 'Failed to register method: The list of arguments should contain argument names in the order that they will be passed to the method.');
            return false;
        }

        this._methods.push({mod: mod, methodname: methodname, args: args});
    }

}

module.exports = ModAPI;
<commit_msg>Probably done<commit_after>/* Module: API -- Used by other modules to provide a HTTP+JSON API for other applications, local or remote. */

//Requests to the API use the POST method, have no path and contain the following JSON in the body: {module; ..., method: ..., args: {name: value, ...}}

var Module = require('./Module.js');
var http = require('http');

class ModAPI extends Module {

    get optionalParams() { return [
        'host',                 //Local IP address for the HTTP server to listen on. Use 0.0.0.0 for any.
        'port'                  //Port for the HTTP server to listen on.
    ]; }

    constructor(name) {
        super('API', name);

        this._params['host'] = '127.0.0.1';
        this._params['port'] = 8098;

        this._server = null;
        this._methods = [];  //List of {mod, methodname, args: [...]}
    }

    initialize(opt) {
        if (!super.initialize(opt)) return false;

        this._server = http.createServer((request, response) => {

            if (request.method != 'POST') {
                response.statusCode = 404;
                return response.end();
            }

            let body = '';
            request.on('data', (data) => {
                body += data;
            });

            request.on('end', () => {

                let json = null;
                try {
                    json = JSON.parse(body);
                } catch (err) {
                    response.statusCode = 400;
                    return response.end();
                }

                if (!json || !json.module || !json.method) {
                    response.statusCode = 400;
                    return response.end();
                }

                let info = this._methods.find((item) => item.mod.name == json.module && item.methodname == json.method);
                if (!info) {
                    this.log('warn', '(NOT FOUND) ' + request.headers.host + ' => ' + json.module + '.' + json.method);
                    response.statusCode = 404;
                    return response.end();
                }

                let args = [];
                if (json.args && info.args) {
                    for (let arg of info.args) {
                        args.push(json.args[arg]);
                    }
                }

                this.log(request.headers.host + ' => ' + json.module + '.' + json.method + '(' + args.join(', ') + ')');

                if (!info.mod[info.methodname] || typeof info.mod[info.methodname] != "function") {
                    this.log('error', request.headers.host + ' <= IMPLEMENTATION MISSING?');
                    response.statusCode = 503;
                    return response.end();
                }

                let res = null;
                try {
                    res = info.mod[info.methodname].apply(this, args);
                } catch (err) {
                    this.log('error', request.headers.host + ' <= Error in implementation: ' + err);
                    response.statusCode = 500;
                    return response.end();
                }

                if (typeof res == "object") res = JSON.stringify(res);

                this.log(request.headers.host + ' <= ' + res);

                response.statusCode = 200;
                response.write(String(res));
                response.end();
            });

        });

        this._server.listen(this.param('port'), this.param('host'), (err) => {
            if (err) this.log('error', err);
            else this.log('Listening on port ' + this.param('port'));
        });

        return true;
    };

    // # Module code below this line #

    //Use this method from dependent modules to expose one of their methods.

    registerMethod(mod, methodname, args) {
        if (!mod || !mod.name || !mod.modName) {
            this.log('warn', 'Failed to register method: The first argument must be the registering module.');
            return false;
        }

        if (!methodname || !mod[methodname] || typeof mod[methodname] != "function") {
            this.log('warn', 'Failed to register method: The method does not exist in the module.');
            return false;
        }

        if (!args) args = [];
        if (!args.length) {
            this.log('warn', 'Failed to register method: The list of arguments should contain argument names in the order that they will be passed to the method.');
            return false;
        }

        this._methods.push({mod: mod, methodname: methodname, args: args});
    }

}

module.exports = ModAPI;
<|endoftext|>


<commit_before><commit_msg>fix roomMap<commit_after><|endoftext|>


<commit_before>/*!

   Flowplayer HTML5 quality selector plugin

   Copyright (c) 2016, Flowplayer Oy

   Released under the MIT License:
   http://www.opensource.org/licenses/mit-license.php

   revision: $GIT_ID$

*/

(function(flowplayer) {
  flowplayer(function(api, root) {
    'use strict';
    var common = flowplayer.common
     ,  explicitSrc = false;

    //only register once
    if (api.pluginQualitySelectorEnabled) return;
    api.pluginQualitySelectorEnabled = true;

    if (!flowplayer.support.inlineVideo) return; // No inline video

    if (api.conf.qualities) {
      api.conf.qualities = typeof api.conf.qualities === 'string' ? api.conf.qualities.split(',') : api.conf.qualities;
    }

    flowplayer.bean.on(root, 'click', '.fp-quality-selector li', function(ev) {
      var elem = ev.currentTarget;
      if (!common.hasClass(elem, 'active')) {
        var currentTime = api.finished ? 0 : api.video.time
         ,  quality = elem.getAttribute('data-quality')
         ,  src;
        src = processClip(api.video, quality);
        api.quality = quality;
        if (!src) return;
        explicitSrc = true;
        api.load(src, function() {
          //Make sure api is not in finished state anymore
          explicitSrc = false;
          api.finished = false;
          if (currentTime && !api.live) {
            api.seek(currentTime, function() {
              api.resume();
            });
          }
        });
      }
    });

    api.on('load', function(ev, api, video) {
      api.qualities = video.qualities || api.conf.qualities || [];
      api.defaultQuality = video.defaultQuality || api.conf.defaultQuality;
      if (typeof api.qualities === 'string') api.qualities = api.qualities.split(',');
      if (!api.quality) return; // Let's go with default quality
      var desiredQuality = findOptimalQuality(api.quality, api.qualities)
       ,  newClip = processClip(video, desiredQuality, !explicitSrc);
      if (!explicitSrc && newClip) {
        ev.preventDefault();
        api.loading = false;
        api.load(newClip);
      }

    }).on('ready', function(ev, api, video) {
      var quality = /mpegurl/i.test(video.type) ? 'abr' :  getQualityFromSrc(video.src, api.qualities) || Math.min(video.height, video.width) + 'p';
      removeAllQualityClasses();
      common.addClass(root, 'quality-' + quality);
      var ui = common.find('.fp-ui', root)[0];
      common.removeNode(common.find('.fp-quality-selector', ui)[0]);
      if (api.qualities.length < 2) return;
      api.quality = quality;
      var selector = common.createElement('ul', {'class': 'fp-quality-selector'});
      ui.appendChild(selector);
      if (hasABRSource(video) && canPlay('application/x-mpegurl') || api.conf.swfHls) {
        selector.appendChild(common.createElement('li', {'data-quality': 'abr', 'class': quality === 'abr' ? 'active' : ''}, 'Auto'));
      }
      api.qualities.forEach(function(q) {
        selector.appendChild(common.createElement('li', {'data-quality': q, 'class': q == quality ? 'active': ''}, q));
      });

    }).on('unload', function() {
      removeAllQualityClasses();
      common.removeNode(common.find('.fp-quality-selector', root)[0]);

    });

    function hasABRSource(video) {
      return video.sources.some(function(src) {
        return /mpegurl/i.test(src.type);
      });
    }

    function canPlay(type) {
      var videoTag = document.createElement('video');
      return !!videoTag.canPlayType(type).replace('no', '');
    }

    function getQualityFromSrc(src, qualities) {
      var m = /-(\d+p)(\.(mp4|webm))?$/.exec(src);
      if (!m) return;
      if (qualities.indexOf(m[1]) === -1) return;
      return m[1];
    }

    function removeAllQualityClasses() {
      if (!api.qualities || !api.qualities.length) return;
      common.removeClass(root, 'quality-abr');
      api.qualities.forEach(function(quality) {
        common.removeClass(root, 'quality-' + quality);
      });
    }

    function findOptimalQuality(previousQuality, newQualities) {
      if (previousQuality === 'abr') return 'abr';
      var a = parseInt(previousQuality, 0), ret;
      newQualities.forEach(function(quality, i) {
        if (i == newQualities.length - 1 && !ret) { // The best we can do
          ret = quality;
        }
        if (parseInt(quality) <= a && parseInt(newQualities[i+1]) > a) { // Is between
          ret = quality;
        }
      });
      return ret;
    }

    function processClip(video, quality, clean) {
      var changed = false, re
       ,  isDefaultQuality = quality === api.defaultQuality
       ,  currentQuality = api.quality || Math.min(api.video.height, api.video.width) + 'p';
      if (currentQuality === api.defaultQuality) {
        re = /(.+?)((\.(mp4|webm)$|$))/;
      }
      else {
        re = /(-\d+p)?((\.(mp4|webm)$|$))/;
      }
      var newSources = video.sources.map(function(src) {
        if (quality === 'abr' || (clean && isDefaultQuality) || /mpegurl/i.test(src.type)) return src;
        var n = {
          type: src.type,
          src: src.src.replace(re, currentQuality === api.defaultQuality ?
                               '$1-' + quality + '$2' :
                                 isDefaultQuality ? '$2' : '-' + quality + '$2')
        };
        if (n.src !== src.src) changed = true;
        return n;
      });
      var newSourcesStr = JSON.stringify(newSources);
      newSources.sort(function(a, b) {
        var re = /mpegurl/i, ret;
        if (quality === 'abr') ret = re.test(b.type) - re.test(a.type);
        else ret = re.test(a.type) - re.test(b.type);
        return ret;
      });
      changed = changed || JSON.stringify(newSources) !== newSourcesStr;
      var clip = flowplayer.extend({}, video, {
        sources: newSources
      });

      return changed ? clip : false;
    }

  });
})(typeof module === 'object' && module.exports ? require('flowplayer') : window.flowplayer);
<commit_msg>Don't require flowplayer directly<commit_after>/*!

   Flowplayer HTML5 quality selector plugin

   Copyright (c) 2016, Flowplayer Oy

   Released under the MIT License:
   http://www.opensource.org/licenses/mit-license.php

   revision: $GIT_ID$

*/

var extension = function(flowplayer) {
  flowplayer(function(api, root) {
    'use strict';
    var common = flowplayer.common
     ,  explicitSrc = false;

    //only register once
    if (api.pluginQualitySelectorEnabled) return;
    api.pluginQualitySelectorEnabled = true;

    if (!flowplayer.support.inlineVideo) return; // No inline video

    if (api.conf.qualities) {
      api.conf.qualities = typeof api.conf.qualities === 'string' ? api.conf.qualities.split(',') : api.conf.qualities;
    }

    flowplayer.bean.on(root, 'click', '.fp-quality-selector li', function(ev) {
      var elem = ev.currentTarget;
      if (!common.hasClass(elem, 'active')) {
        var currentTime = api.finished ? 0 : api.video.time
         ,  quality = elem.getAttribute('data-quality')
         ,  src;
        src = processClip(api.video, quality);
        api.quality = quality;
        if (!src) return;
        explicitSrc = true;
        api.load(src, function() {
          //Make sure api is not in finished state anymore
          explicitSrc = false;
          api.finished = false;
          if (currentTime && !api.live) {
            api.seek(currentTime, function() {
              api.resume();
            });
          }
        });
      }
    });

    api.on('load', function(ev, api, video) {
      api.qualities = video.qualities || api.conf.qualities || [];
      api.defaultQuality = video.defaultQuality || api.conf.defaultQuality;
      if (typeof api.qualities === 'string') api.qualities = api.qualities.split(',');
      if (!api.quality) return; // Let's go with default quality
      var desiredQuality = findOptimalQuality(api.quality, api.qualities)
       ,  newClip = processClip(video, desiredQuality, !explicitSrc);
      if (!explicitSrc && newClip) {
        ev.preventDefault();
        api.loading = false;
        api.load(newClip);
      }

    }).on('ready', function(ev, api, video) {
      var quality = /mpegurl/i.test(video.type) ? 'abr' :  getQualityFromSrc(video.src, api.qualities) || Math.min(video.height, video.width) + 'p';
      removeAllQualityClasses();
      common.addClass(root, 'quality-' + quality);
      var ui = common.find('.fp-ui', root)[0];
      common.removeNode(common.find('.fp-quality-selector', ui)[0]);
      if (api.qualities.length < 2) return;
      api.quality = quality;
      var selector = common.createElement('ul', {'class': 'fp-quality-selector'});
      ui.appendChild(selector);
      if (hasABRSource(video) && canPlay('application/x-mpegurl') || api.conf.swfHls) {
        selector.appendChild(common.createElement('li', {'data-quality': 'abr', 'class': quality === 'abr' ? 'active' : ''}, 'Auto'));
      }
      api.qualities.forEach(function(q) {
        selector.appendChild(common.createElement('li', {'data-quality': q, 'class': q == quality ? 'active': ''}, q));
      });

    }).on('unload', function() {
      removeAllQualityClasses();
      common.removeNode(common.find('.fp-quality-selector', root)[0]);

    });

    function hasABRSource(video) {
      return video.sources.some(function(src) {
        return /mpegurl/i.test(src.type);
      });
    }

    function canPlay(type) {
      var videoTag = document.createElement('video');
      return !!videoTag.canPlayType(type).replace('no', '');
    }

    function getQualityFromSrc(src, qualities) {
      var m = /-(\d+p)(\.(mp4|webm))?$/.exec(src);
      if (!m) return;
      if (qualities.indexOf(m[1]) === -1) return;
      return m[1];
    }

    function removeAllQualityClasses() {
      if (!api.qualities || !api.qualities.length) return;
      common.removeClass(root, 'quality-abr');
      api.qualities.forEach(function(quality) {
        common.removeClass(root, 'quality-' + quality);
      });
    }

    function findOptimalQuality(previousQuality, newQualities) {
      if (previousQuality === 'abr') return 'abr';
      var a = parseInt(previousQuality, 0), ret;
      newQualities.forEach(function(quality, i) {
        if (i == newQualities.length - 1 && !ret) { // The best we can do
          ret = quality;
        }
        if (parseInt(quality) <= a && parseInt(newQualities[i+1]) > a) { // Is between
          ret = quality;
        }
      });
      return ret;
    }

    function processClip(video, quality, clean) {
      var changed = false, re
       ,  isDefaultQuality = quality === api.defaultQuality
       ,  currentQuality = api.quality || Math.min(api.video.height, api.video.width) + 'p';
      if (currentQuality === api.defaultQuality) {
        re = /(.+?)((\.(mp4|webm)$|$))/;
      }
      else {
        re = /(-\d+p)?((\.(mp4|webm)$|$))/;
      }
      var newSources = video.sources.map(function(src) {
        if (quality === 'abr' || (clean && isDefaultQuality) || /mpegurl/i.test(src.type)) return src;
        var n = {
          type: src.type,
          src: src.src.replace(re, currentQuality === api.defaultQuality ?
                               '$1-' + quality + '$2' :
                                 isDefaultQuality ? '$2' : '-' + quality + '$2')
        };
        if (n.src !== src.src) changed = true;
        return n;
      });
      var newSourcesStr = JSON.stringify(newSources);
      newSources.sort(function(a, b) {
        var re = /mpegurl/i, ret;
        if (quality === 'abr') ret = re.test(b.type) - re.test(a.type);
        else ret = re.test(a.type) - re.test(b.type);
        return ret;
      });
      changed = changed || JSON.stringify(newSources) !== newSourcesStr;
      var clip = flowplayer.extend({}, video, {
        sources: newSources
      });

      return changed ? clip : false;
    }

  });
};

if (typeof module === 'object' && module.exports) module.exports = extension;
else if (window.flowplayer) extension(window.flowplayer);
<|endoftext|>


<commit_before>module.exports = {
	context: __dirname + "/app",
	entry: "./app.js",

	output:
	{
		filename: "app.js",
		path: "../laravel/public/js",
	},

	module: {
		loaders:
		[
			{
				test: /\.js$/,
				exclude: /node_modules/,
				loaders: ["babel-loader"],
			}
		],
	},
}
<commit_msg>New webpack config for latest version of webpack + babel<commit_after>module.exports = {
	context: __dirname + "/app",
	entry: "./app.js",

	output:
	{
		filename: "app.js",
		path: "../laravel/public/js",
	},

	module: {
		loaders:
		[
			{
				test: /\.js$/,
				exclude: /node_modules/,
				loader: "babel-loader",
				query: {
					presets: ['es2015', 'react']
				}
			}
		],
	},
}
<|endoftext|>