/**
 * Helper to assert the React.CSSProperties type for all properties in a tuple,
 * while maintaining property names. This will fail compilation if input CSS
 * properties are invalid and will avoid the need for a type assertion on the
 * output. Also makes the properties readonly.
 *
 * This is a workaround to an issue in the Typescript compiler which should
 * eventually be fixed: https://github.com/Microsoft/TypeScript/issues/11152.
 *
 * This approach works only with a single-level nested tuples currently:
 * const styles = reactStyles({
 *   style1: {color: 'red'},
 *   style2: {color: 'blue', position: 'relative'}
 * });
 *
 * Alternatively, style tuples can be cast individually (with arbitrary nesting):
 * const styles = {
 *   style1: {color: 'red'} as React.CssProperties,
 *   style2: {color: 'blue', position: 'relative'} as React.CssProperties
 * };
 */
export function reactStyles<T extends { [key: string]: React.CSSProperties }>(
  t: T
): ReactStyles<T> {
  return t;
}


export function decamelize(str: string, separator: string) {
  separator = typeof separator === 'undefined' ? '_' : separator;

  return str
    .replace(/([a-z\d])([A-Z])/g, '$1' + separator + '$2')
    .replace(/([A-Z]+)([A-Z][a-z\d]+)/g, '$1' + separator + '$2')
    .toLowerCase();
}


export function formatDomainString(domainString: string): string {
  return domainString === Domain.PHYSICALMEASUREMENTCSS.toString()
    ? fp.capitalize(Domain.PHYSICALMEASUREMENT.toString())
    : domainString === Domain.WHOLEGENOMEVARIANT.toString()
    ? 'VCF Files'
    : fp.capitalize(domainString);
}


export function formatDomain(domain: Domain): string {
  return formatDomainString(domain.toString());
}


export function sliceByHalfLength(obj) {
  return Math.ceil(obj.length / 2);
}


export function hasNewValidProps(currProps, prevProps, fieldsToCompare) {
  for (const fieldGetter of fieldsToCompare) {
    if (!fieldGetter(currProps)) {
      return false;
    }

    if (fieldGetter(currProps) !== fieldGetter(prevProps)) {
      return true;
    }
  }

  return false;
}


// Returns a function which will execute `action` at most once every `sensitivityMs` milliseconds
// if the returned function has been invoked within the last `sensitivityMs` milliseconds
// Example : debouncing user activity events to change rate of invocation from 1000/s to 1/s
export function debouncer(action, sensitivityMs) {
  let t = Date.now();

  const timer = global.setInterval(() => {
    if (Date.now() - t < sensitivityMs) {
      action();
    }
  }, sensitivityMs);

  return {
    invoke: () => {
      t = Date.now();
    },
    getTimer: () => timer,
  };
}


// Starts a timer which will invoke `f` after `timeoutInSeconds` has passed
// Calling the returned function will reset the timer to zero
// Example : Call a logout function after 30 seconds of the returned function not being invoked
export function resettableTimeout(f, timeoutInSeconds) {
  let timeout;
  return {
    reset: () => {
      clearTimeout(timeout);
      timeout = setTimeout(f, timeoutInSeconds);
    },
    getTimer: () => timeout,
  };
}


export function highlightSearchTerm(
  searchTerm: string,
  stringToHighlight: string,
  highlightColor: string
) {
  if (searchTerm.length < 3) {
    return stringToHighlight;
  }
  try {
    const words: string[] = [];
    const matchString = new RegExp(
      searchTerm.replace(/([^a-zA-z0-9 \-<>=\/]+)/g, () => '').trim(),
      'i'
    );
    const matches = stringToHighlight.match(new RegExp(matchString, 'gi'));
    const splits = stringToHighlight.split(new RegExp(matchString, 'gi'));
    if (matches) {
      for (let i = 0; i < matches.length; i++) {
        words.push(splits[i], matches[i]);
      }
      words.push(splits[splits.length - 1]);
    } else {
      words.push(splits[0]);
    }
    return words.map((word, w) => (
      <span
        key={w}
        style={
          matchString.test(word.toLowerCase())
            ? {
                color: colorWithWhiteness(highlightColor, -0.4),
                backgroundColor: colorWithWhiteness(highlightColor, 0.7),
                display: 'inline-block',
              }
            : {}
        }
      >
        {word}
      </span>
    ));
  } catch (e) {
    return stringToHighlight;
  }
}


// render a float value as US currency, rounded to cents: 255.372793 -> $255.37
// negative values are rendered as $0
export function formatInitialCreditsUSD(value?: number): string {
  if (!value || value <= 0.0) {
    return '$0';
  } else {
    return '$' + value.toFixed(2).toString();
  }
}


// Takes a search string and validates for the most common MySQL use cases.
// Checks for unclosed "", trailing + or -, and breaking special characters.
export function validateInputForMySQL(searchString: string): Array<string> {
  const inputErrors = new Set<string>(); // use Set to prevent duplicate messages
  let unclosedQuotes = false;
  for (let i = 0; i < searchString.length; i++) {
    const character = searchString[i];
    if (character === '"') {
      unclosedQuotes = !unclosedQuotes;
      continue;
    }
    if (unclosedQuotes) {
      // inside a quote, no need to validate further
      continue;
    }
    // Check for characters that break search
    if ('~@[]|<>()'.indexOf(character) > -1) {
      inputErrors.add(
        'The following characters are not allowed in the search string: ~ @ [ ] | < > ( )'
      );
      continue;
    }
    // Check for trailing + or -
    if (
      '+-'.indexOf(character) > -1 &&
      (searchString[i + 1] === ' ' || searchString[i + 1] === undefined)
    ) {
      inputErrors.add(
        `Trailing ${character} characters are not allowed in the search string`
      );
      continue;
    }
  }
  if (unclosedQuotes) {
    // unclosed quote
    inputErrors.add('There is an unclosed " in the search string');
  }
  return Array.from(inputErrors);
}


(value, ...pairs) => {
  const match = fp.find(
    ([v]) => fp.isEqual(v, value) || fp.isEqual(v, DEFAULT),
    pairs
  );
  return match?.[1]();
}


([v]) => fp.isEqual(v, value) || fp.isEqual(v, DEFAULT)


(fn) => {
  let running = false;
  return (...args) => {
    if (!running) {
      running = true;
      window.requestAnimationFrame(() => {
        running = false;
        fn(...args);
      });
    }
  };
}


(...args) => {
    if (!running) {
      running = true;
      window.requestAnimationFrame(() => {
        running = false;
        fn(...args);
      });
    }
  }


() => {
        running = false;
        fn(...args);
      }


() => {
    window.dispatchEvent(new CustomEvent('resizeAnimation'));
  }


(): WindowSize => {
  return { height: window.innerHeight, width: window.innerWidth };
}


() => (WrappedComponent) => {
  class Wrapper extends React.Component<any, { windowSize: WindowSize }> {
    constructor(props) {
      super(props);
      this.state = { windowSize: getWindowSize() };
    }

    static displayName = 'withWindowSize()';

    resize = () => {
      const { windowSize } = this.state;
      const newSize = getWindowSize();
      if (!fp.isEqual(windowSize, newSize)) {
        this.setState({ windowSize: newSize });
      }
    };

    componentDidMount() {
      window.addEventListener('resizeAnimation', this.resize);
    }

    componentWillUnmount() {
      window.removeEventListener('resizeAnimation', this.resize);
    }

    render() {
      const { windowSize } = this.state;
      return <WrappedComponent windowSize={windowSize} {...this.props} />;
    }
  }

  return Wrapper;
}


(WrappedComponent) => {
  class Wrapper extends React.Component<any, { windowSize: WindowSize }> {
    constructor(props) {
      super(props);
      this.state = { windowSize: getWindowSize() };
    }

    static displayName = 'withWindowSize()';

    resize = () => {
      const { windowSize } = this.state;
      const newSize = getWindowSize();
      if (!fp.isEqual(windowSize, newSize)) {
        this.setState({ windowSize: newSize });
      }
    };

    componentDidMount() {
      window.addEventListener('resizeAnimation', this.resize);
    }

    componentWillUnmount() {
      window.removeEventListener('resizeAnimation', this.resize);
    }

    render() {
      const { windowSize } = this.state;
      return <WrappedComponent windowSize={windowSize} {...this.props} />;
    }
  }

  return Wrapper;
}


() => {
      const { windowSize } = this.state;
      const newSize = getWindowSize();
      if (!fp.isEqual(windowSize, newSize)) {
        this.setState({ windowSize: newSize });
      }
    }


({ field, direction }, newField) => {
  return newField === field
    ? { field, direction: direction === 'asc' ? 'desc' : 'asc' }
    : { field: newField, direction: 'asc' };
}


(styleObj) => (WrappedComponent) => {
  const Wrapper = React.forwardRef(({ style = {}, ...props }: any, ref) => {
    return (
      <WrappedComponent
        ref={ref}
        style={{ ...styleObj, ...style }


(WrappedComponent) => {
  const Wrapper = React.forwardRef(({ style = {}, ...props }: any, ref) => {
    return (
      <WrappedComponent
        ref={ref}
        style={{ ...styleObj, ...style }


({ style = {}, ...props }: any, ref) => {
    return (
      <WrappedComponent
        ref={ref}
        style={{


(errors) => {
  const errorList = fp.cond([
    [fp.isPlainObject, fp.flatMap(fp.values)],
    [fp.isArray, fp.identity],
    [() => true, () => []],
  ])(errors);
  if (errorList.length) {
    return errorList.map((v, i) => {
      return (
        <div key={i} style={{ marginTop: i !== 0 ? '0.25rem' : undefined }}>
          {v}
        </div>
      );
    });
  }


(v, i) => {
      return (
        <div key={i} style={{ marginTop: i !== 0 ? '0.25rem' : undefined }}


<T extends {}>(
  subject: BehaviorSubject<T>,
  name: string,
  preventRenderUntilDataIsPresent: boolean = false
) => {
  return (WrappedComponent) => {
    class Wrapper extends React.Component<any, { value: T }> {
      static displayName = 'connectBehaviorSubject()';
      private subscription;

      constructor(props) {
        super(props);
        this.state = { value: subject.getValue() };
      }

      componentDidMount() {
        this.subscription = subject.subscribe((v) => {
          this.setState({ value: v });
        });
      }

      componentWillUnmount() {
        this.subscription.unsubscribe();
      }

      render() {
        const { value } = this.state;
        // We allow overriding of the currentValue, for reuse of the same
        // logic outside of the scope of a current workspace.
        if (preventRenderUntilDataIsPresent && value == null) {
          return null;
        }
        return <WrappedComponent {...{ [name]: value }} {...this.props} />;
      }
    }

    return Wrapper;
  };
}


(WrappedComponent) => {
    class Wrapper extends React.Component<any, { value: T }> {
      static displayName = 'connectBehaviorSubject()';
      private subscription;

      constructor(props) {
        super(props);
        this.state = { value: subject.getValue() };
      }

      componentDidMount() {
        this.subscription = subject.subscribe((v) => {
          this.setState({ value: v });
        });
      }

      componentWillUnmount() {
        this.subscription.unsubscribe();
      }

      render() {
        const { value } = this.state;
        // We allow overriding of the currentValue, for reuse of the same
        // logic outside of the scope of a current workspace.
        if (preventRenderUntilDataIsPresent && value == null) {
          return null;
        }
        return <WrappedComponent {...{ [name]: value }} {...this.props} />;
      }
    }

    return Wrapper;
  }


(v) => {
          this.setState({ value: v });
        }


<T extends {}>(
  subject: ReplaySubject<T>,
  name: string
) => {
  return (WrappedComponent) => {
    class Wrapper extends React.Component<any, { value: T }> {
      static displayName = 'connectReplaySubject()';
      private subscription;

      constructor(props) {
        super(props);
        this.state = { value: null };
      }

      componentDidMount() {
        this.subscription = subject.subscribe((v) =>
          this.setState({ value: v })
        );
      }

      componentWillUnmount() {
        this.subscription.unsubscribe();
      }

      render() {
        const { value } = this.state;
        // Since ReplaySubject may not have an initial value, only render the
        // connected value once the value is available.
        return (
          value && <WrappedComponent {...{ [name]: value }} {...this.props} />


(WrappedComponent) => {
    class Wrapper extends React.Component<any, { value: T }> {
      static displayName = 'connectReplaySubject()';
      private subscription;

      constructor(props) {
        super(props);
        this.state = { value: null };
      }

      componentDidMount() {
        this.subscription = subject.subscribe((v) =>
          this.setState({ value: v })
        );
      }

      componentWillUnmount() {
        this.subscription.unsubscribe();
      }

      render() {
        const { value } = this.state;
        // Since ReplaySubject may not have an initial value, only render the
        // connected value once the value is available.
        return (
          value && <WrappedComponent {...{ [name]: value }} {...this.props} />


(v) =>
          this.setState({ value: v })


() => {
  return connectBehaviorSubject(currentWorkspaceStore, 'workspace');
}


() => {
  return connectBehaviorSubject(currentCohortStore, 'cohort');
}


() => {
  return connectBehaviorSubject(currentCohortReviewStore, 'cohortReview');
}


() => {
  return connectBehaviorSubject(currentCohortCriteriaStore, 'criteria');
}


() => {
  return connectBehaviorSubject(currentConceptStore, 'concept');
}


() => {
  return connectBehaviorSubject(
    currentCohortSearchContextStore,
    'cohortContext'
  );
}


() => {
  return connectBehaviorSubject(currentConceptSetStore, 'conceptSet');
}


() => {
  return connectBehaviorSubject(globalErrorStore, 'globalError');
}


() => {
  return withStore(profileStore, 'profileState');
}


() => {
  return withStore(cdrVersionStore, 'cdrVersionTiersResponse');
}


(value, arr) => fp.concat(arr, [value])


<T extends {}>(value: T, arr: Array<T>) => {
    return fp.includes(value, arr) ? fp.pull(value, arr) : append(value, arr);
  }


() => {
    if (Date.now() - t < sensitivityMs) {
      action();
    }
  }


() => {
      t = Date.now();
    }


() => timer


() => {
      clearTimeout(timeout);
      timeout = setTimeout(f, timeoutInSeconds);
    }


() => timeout


(word, w) => (
      <span
        key={w}


(fn: Function, updateList = [], ms = 250) => {
  useEffect(() => {
    const timeoutId = setTimeout(fn, ms);
    return () => clearTimeout(timeoutId);
  }, updateList);
}


() => {
    const timeoutId = setTimeout(fn, ms);
    return () => clearTimeout(timeoutId);
  }


() => clearTimeout(timeoutId)


(): [boolean, Function] => {
  const [state, setState] = useState(false);

  useEffect(() => {
    if (state) {
      setState(false);
    }
  }, [state]);

  return [state, setState];
}


() => {
    if (state) {
      setState(false);
    }
  }


(
      handler: (error: Error) => void,
      fnToTry: (...args: any[]) => Promise<any>
    ) =>
    async (...args) => {
      try {
        return await fnToTry(...args);
      } catch (error) {
        handler(error);
      }
    }


async (...args) => {
      try {
        return await fnToTry(...args);
      } catch (error) {
        handler(error);
      }
    }


(setters: string[], getters: string[], obj: object): object => {
    return fp.flow(
      fp.zip(getters),
      fp.map<[string, string], [string, object]>(([fromProp, toProp]) => [
        toProp,
        obj[fromProp],
      ]),
      fp.fromPairs
    )(setters);
  }


([fromProp, toProp]) => [
        toProp,
        obj[fromProp],
      ]


() => {
  const [id] = useState(() => fp.uniqueId('element-'));
  return id;
}


() => fp.uniqueId('element-')


(fn, value) =>
  value !== nothing && value ? fn(value) : nothing


<T extends unknown>(
  ...args: ([boolean, () => T] | (() => T))[]
) => {
  for (const arg of args) {
    // If the arg is an array, conditionally execute (maybe). If not an array, then this is the default case.
    const result = Array.isArray(arg) ? maybe(...fp.reverse(arg)) : arg();
    if (result !== nothing) {
      return result;
    }
  }
}


(username: string) => {
  if (!username) {
    return '';
  }
  const atIdx = username.indexOf('@');
  return atIdx === -1 ? username : username.substring(0, atIdx);
}


(value: string, maxLength: number) =>
  value?.length > maxLength ? value.slice(0, maxLength) + '...' : value


class Wrapper extends React.Component<any, { windowSize: WindowSize }> {
    constructor(props) {
      super(props);
      this.state = { windowSize: getWindowSize() };
    }

    static displayName = 'withWindowSize()';

    resize = () => {
      const { windowSize } = this.state;
      const newSize = getWindowSize();
      if (!fp.isEqual(windowSize, newSize)) {
        this.setState({ windowSize: newSize });
      }
    };

    componentDidMount() {
      window.addEventListener('resizeAnimation', this.resize);
    }

    componentWillUnmount() {
      window.removeEventListener('resizeAnimation', this.resize);
    }

    render() {
      const { windowSize } = this.state;
      return <WrappedComponent windowSize={windowSize} {...this.props} />;
    }
  }


class Wrapper extends React.Component<any, { value: T }> {
      static displayName = 'connectBehaviorSubject()';
      private subscription;

      constructor(props) {
        super(props);
        this.state = { value: subject.getValue() };
      }

      componentDidMount() {
        this.subscription = subject.subscribe((v) => {
          this.setState({ value: v });
        });
      }

      componentWillUnmount() {
        this.subscription.unsubscribe();
      }

      render() {
        const { value } = this.state;
        // We allow overriding of the currentValue, for reuse of the same
        // logic outside of the scope of a current workspace.
        if (preventRenderUntilDataIsPresent && value == null) {
          return null;
        }
        return <WrappedComponent {...{ [name]: value }} {...this.props} />;
      }
    }


class Wrapper extends React.Component<any, { value: T }> {
      static displayName = 'connectReplaySubject()';
      private subscription;

      constructor(props) {
        super(props);
        this.state = { value: null };
      }

      componentDidMount() {
        this.subscription = subject.subscribe((v) =>
          this.setState({ value: v })
        );
      }

      componentWillUnmount() {
        this.subscription.unsubscribe();
      }

      render() {
        const { value } = this.state;
        // Since ReplaySubject may not have an initial value, only render the
        // connected value once the value is available.
        return (
          value && <WrappedComponent {...{ [name]: value }} {...this.props} />


export interface WindowSize {
  height: number;
  width: number;
}


// Components using withWindowSize can use this props interface to ensure they are including the
// correctly-named props, e.g. "interface MyClassProps extends WindowSizeProps".
export interface WindowSizeProps {
  windowSize: WindowSize;
}


type ReactStyles<T> = {
  readonly [P in keyof T]: React.CSSProperties;
};


componentDidMount() {
      window.addEventListener('resizeAnimation', this.resize);
    }


componentWillUnmount() {
      window.removeEventListener('resizeAnimation', this.resize);
    }


render() {
      const { windowSize } = this.state;
      return <WrappedComponent windowSize={windowSize} {...this.props} />;
    }


componentDidMount() {
        this.subscription = subject.subscribe((v) => {
          this.setState({ value: v });
        });
      }


componentWillUnmount() {
        this.subscription.unsubscribe();
      }


render() {
        const { value } = this.state;
        // We allow overriding of the currentValue, for reuse of the same
        // logic outside of the scope of a current workspace.
        if (preventRenderUntilDataIsPresent && value == null) {
          return null;
        }
        return <WrappedComponent {...{ [name]: value }} {...this.props} />;
      }


componentDidMount() {
        this.subscription = subject.subscribe((v) =>
          this.setState({ value: v })
        );
      }


render() {
        const { value } = this.state;
        // Since ReplaySubject may not have an initial value, only render the
        // connected value once the value is available.
        return (
          value && <WrappedComponent {...{ [name]: value }} {...this.props} />


function ignore(): ignore.Ignore;


interface Ignore {
            add(patterns: string | Array<string> | Ignore): Ignore;
            filter(paths: Array<string>): Array<string>;
        }


export type SimpleBinaryKernelImplCPU = SimpleBinaryKernelImpl;


export type SimpleUnaryKernelImplCPU = SimpleUnaryImpl;


/**
 * Provides all nessesary aria-* attributes to create valid disabled state for interactive components.
 */
export function ariaDisabled<T extends AriaDisabled>(): ClassDecorator {
  return (target: any) => target.addInitializer((instance: T) => new AriaDisabledController(instance));
}


(target: any) => target.addInitializer((instance: T) => new AriaDisabledController(instance))


(instance: T) => new AriaDisabledController(instance)


export class AriaDisabledController<T extends AriaDisabled> implements ReactiveController {
  constructor(private host: T) {
    this.host.addController(this);
  }

  hostUpdated() {
    if (this.host.disabled !== null) {
      this.host.ariaDisabled = this.host.disabled;
    }

    if (this.host.readonly) {
      this.host.ariaDisabled = null;
    }
  }
}


export type AriaDisabled = ReactiveElement & { disabled: boolean; readonly?: boolean };


hostUpdated() {
    if (this.host.disabled !== null) {
      this.host.ariaDisabled = this.host.disabled;
    }

    if (this.host.readonly) {
      this.host.ariaDisabled = null;
    }
  }


async function initPluginWithHandlers(handlers: Array<EmailEventHandler<string, any>>, options?: Partial<EmailPluginOptions>) {
        eventBus = new EventBus();
        onSend = jest.fn();
        plugin = new EmailPlugin({
            templatePath: path.join(__dirname, '../test-templates'),
            transport: {
                type: 'testing',
                onSend,
            },
            handlers,
            ...options,
        });

        const inject = (token: any): any => {
            if (token === EventBus) {
                return eventBus;
            } else {
                throw new Error(`Was not expecting to inject the token ${token}`);
            }
        };

        await plugin.onBootstrap(inject);
    }


(token: any): any => {
            if (token === EventBus) {
                return eventBus;
            } else {
                throw new Error(`Was not expecting to inject the token ${token}`);
            }
        }


() => {

        const ctx = {
            channel: { code: DEFAULT_CHANNEL_CODE },
            languageCode: LanguageCode.en,
        } as any;

        it('single filter', async () => {
            const handler = new EmailEventListener('test')
                .on(MockEvent)
                .filter(event => event.shouldSend === true)
                .setRecipient(() => 'test@test.com')
                .setSubject('test subject');

            await initPluginWithHandlers([handler]);

            eventBus.publish(new MockEvent(ctx, false));
            await pause();
            expect(onSend).not.toHaveBeenCalled();

            eventBus.publish(new MockEvent(ctx, true));
            await pause();
            expect(onSend).toHaveBeenCalledTimes(1);
        });

        it('multiple filters', async () => {
            const handler = new EmailEventListener('test')
                .on(MockEvent)
                .filter(event => event.shouldSend === true)
                .filter(event => !!event.ctx.user)
                .setRecipient(() => 'test@test.com')
                .setSubject('test subject');

            await initPluginWithHandlers([handler]);

            eventBus.publish(new MockEvent(ctx, true));
            await pause();
            expect(onSend).not.toHaveBeenCalled();

            eventBus.publish(new MockEvent({ ...ctx, user: 'joe' }, true));
            await pause();
            expect(onSend).toHaveBeenCalledTimes(1);
        });
    }


async () => {
            const handler = new EmailEventListener('test')
                .on(MockEvent)
                .filter(event => event.shouldSend === true)
                .setRecipient(() => 'test@test.com')
                .setSubject('test subject');

            await initPluginWithHandlers([handler]);

            eventBus.publish(new MockEvent(ctx, false));
            await pause();
            expect(onSend).not.toHaveBeenCalled();

            eventBus.publish(new MockEvent(ctx, true));
            await pause();
            expect(onSend).toHaveBeenCalledTimes(1);
        }


event => event.shouldSend === true


() => 'test@test.com'


async () => {
            const handler = new EmailEventListener('test')
                .on(MockEvent)
                .filter(event => event.shouldSend === true)
                .filter(event => !!event.ctx.user)
                .setRecipient(() => 'test@test.com')
                .setSubject('test subject');

            await initPluginWithHandlers([handler]);

            eventBus.publish(new MockEvent(ctx, true));
            await pause();
            expect(onSend).not.toHaveBeenCalled();

            eventBus.publish(new MockEvent({ ...ctx, user: 'joe' }, true));
            await pause();
            expect(onSend).toHaveBeenCalledTimes(1);
        }


event => !!event.ctx.user


() => {
        const ctx = {
            channel: { code: DEFAULT_CHANNEL_CODE },
            languageCode: LanguageCode.en,
        } as any;

        it('interpolates subject', async () => {
            const handler = new EmailEventListener('test')
                .on(MockEvent)
                .setRecipient(() => 'test@test.com')
                .setSubject('Hello {{ subjectVar }}')
                .setTemplateVars(event => ({ subjectVar: 'foo' }));

            await initPluginWithHandlers([handler]);

            eventBus.publish(new MockEvent(ctx, true));
            await pause();
            expect(onSend.mock.calls[0][0].subject).toBe('Hello foo');
        });

        it('interpolates body', async () => {
            const handler = new EmailEventListener('test')
                .on(MockEvent)
                .setRecipient(() => 'test@test.com')
                .setSubject('Hello')
                .setTemplateVars(event => ({ testVar: 'this is the test var' }));

            await initPluginWithHandlers([handler]);

            eventBus.publish(new MockEvent(ctx, true));
            await pause();
            expect(onSend.mock.calls[0][0].body).toContain('this is the test var');
        });

        it('interpolates globalTemplateVars', async () => {
            const handler = new EmailEventListener('test')
                .on(MockEvent)
                .setRecipient(() => 'test@test.com')
                .setSubject('Hello {{ globalVar }}');

            await initPluginWithHandlers([handler], { globalTemplateVars: { globalVar: 'baz' } });

            eventBus.publish(new MockEvent(ctx, true));
            await pause();
            expect(onSend.mock.calls[0][0].subject).toBe('Hello baz');
        });

        it('globalTemplateVars available in setTemplateVars method', async () => {
            const handler = new EmailEventListener('test')
                .on(MockEvent)
                .setRecipient(() => 'test@test.com')
                .setSubject('Hello {{ testVar }}')
                .setTemplateVars((event, globals) => ({ testVar: globals.globalVar + ' quux' }));

            await initPluginWithHandlers([handler], { globalTemplateVars: { globalVar: 'baz' } });

            eventBus.publish(new MockEvent(ctx, true));
            await pause();
            expect(onSend.mock.calls[0][0].subject).toBe('Hello baz quux');
        });

        it('setTemplateVars overrides globals', async () => {
            const handler = new EmailEventListener('test')
                .on(MockEvent)
                .setRecipient(() => 'test@test.com')
                .setSubject('Hello {{ name }}')
                .setTemplateVars((event, globals) => ({ name: 'quux' }));

            await initPluginWithHandlers([handler], { globalTemplateVars: { name: 'baz' } });

            eventBus.publish(new MockEvent(ctx, true));
            await pause();
            expect(onSend.mock.calls[0][0].subject).toBe('Hello quux');
        });
    }


async () => {
            const handler = new EmailEventListener('test')
                .on(MockEvent)
                .setRecipient(() => 'test@test.com')
                .setSubject('Hello {{ subjectVar }}')
                .setTemplateVars(event => ({ subjectVar: 'foo' }));

            await initPluginWithHandlers([handler]);

            eventBus.publish(new MockEvent(ctx, true));
            await pause();
            expect(onSend.mock.calls[0][0].subject).toBe('Hello foo');
        }


event => ({ subjectVar: 'foo' })


async () => {
            const handler = new EmailEventListener('test')
                .on(MockEvent)
                .setRecipient(() => 'test@test.com')
                .setSubject('Hello')
                .setTemplateVars(event => ({ testVar: 'this is the test var' }));

            await initPluginWithHandlers([handler]);

            eventBus.publish(new MockEvent(ctx, true));
            await pause();
            expect(onSend.mock.calls[0][0].body).toContain('this is the test var');
        }


event => ({ testVar: 'this is the test var' })


async () => {
            const handler = new EmailEventListener('test')
                .on(MockEvent)
                .setRecipient(() => 'test@test.com')
                .setSubject('Hello {{ globalVar }}');

            await initPluginWithHandlers([handler], { globalTemplateVars: { globalVar: 'baz' } });

            eventBus.publish(new MockEvent(ctx, true));
            await pause();
            expect(onSend.mock.calls[0][0].subject).toBe('Hello baz');
        }


async () => {
            const handler = new EmailEventListener('test')
                .on(MockEvent)
                .setRecipient(() => 'test@test.com')
                .setSubject('Hello {{ testVar }}')
                .setTemplateVars((event, globals) => ({ testVar: globals.globalVar + ' quux' }));

            await initPluginWithHandlers([handler], { globalTemplateVars: { globalVar: 'baz' } });

            eventBus.publish(new MockEvent(ctx, true));
            await pause();
            expect(onSend.mock.calls[0][0].subject).toBe('Hello baz quux');
        }


(event, globals) => ({ testVar: globals.globalVar + ' quux' })


async () => {
            const handler = new EmailEventListener('test')
                .on(MockEvent)
                .setRecipient(() => 'test@test.com')
                .setSubject('Hello {{ name }}')
                .setTemplateVars((event, globals) => ({ name: 'quux' }));

            await initPluginWithHandlers([handler], { globalTemplateVars: { name: 'baz' } });

            eventBus.publish(new MockEvent(ctx, true));
            await pause();
            expect(onSend.mock.calls[0][0].subject).toBe('Hello quux');
        }


(event, globals) => ({ name: 'quux' })


() => {
        const ctx = {
            channel: { code: DEFAULT_CHANNEL_CODE },
            languageCode: LanguageCode.en,
        } as any;

        it('additional LanguageCode', async () => {
            const handler = new EmailEventListener('test')
                .on(MockEvent)
                .setSubject('Hello, {{ name }}!')
                .setRecipient(() => 'test@test.com')
                .setTemplateVars(() => ({ name: 'Test' }))
                .addTemplate({
                    channelCode: 'default',
                    languageCode: LanguageCode.de,
                    templateFile: 'body.de.hbs',
                    subject: 'Servus, {{ name }}!',
                });

            await initPluginWithHandlers([handler]);

            eventBus.publish(new MockEvent({ ...ctx, languageCode: LanguageCode.ta }, true));
            await pause();
            expect(onSend.mock.calls[0][0].subject).toBe('Hello, Test!');
            expect(onSend.mock.calls[0][0].body).toContain('Default body.');

            eventBus.publish(new MockEvent({ ...ctx, languageCode: LanguageCode.de }, true));
            await pause();
            expect(onSend.mock.calls[1][0].subject).toBe('Servus, Test!');
            expect(onSend.mock.calls[1][0].body).toContain('German body.');
        });
    }


async () => {
            const handler = new EmailEventListener('test')
                .on(MockEvent)
                .setSubject('Hello, {{ name }}!')
                .setRecipient(() => 'test@test.com')
                .setTemplateVars(() => ({ name: 'Test' }))
                .addTemplate({
                    channelCode: 'default',
                    languageCode: LanguageCode.de,
                    templateFile: 'body.de.hbs',
                    subject: 'Servus, {{ name }}!',
                });

            await initPluginWithHandlers([handler]);

            eventBus.publish(new MockEvent({ ...ctx, languageCode: LanguageCode.ta }, true));
            await pause();
            expect(onSend.mock.calls[0][0].subject).toBe('Hello, Test!');
            expect(onSend.mock.calls[0][0].body).toContain('Default body.');

            eventBus.publish(new MockEvent({ ...ctx, languageCode: LanguageCode.de }, true));
            await pause();
            expect(onSend.mock.calls[1][0].subject).toBe('Servus, Test!');
            expect(onSend.mock.calls[1][0].body).toContain('German body.');
        }


() => ({ name: 'Test' })


() => {

        beforeEach(async () => {
            await initPluginWithHandlers([orderConfirmationHandler], { templatePath: path.join(__dirname, '../templates') });
        });

        const ctx = {
            channel: { code: DEFAULT_CHANNEL_CODE },
            languageCode: LanguageCode.en,
        } as any;

        const order = {
            code: 'ABCDE',
            customer: {
                emailAddress: 'test@test.com',
            },
        } as Partial<Order> as any;

        it('filters events with wrong order state', async () => {
            eventBus.publish(new OrderStateTransitionEvent('AddingItems', 'ArrangingPayment', ctx, order));
            await pause();
            expect(onSend).not.toHaveBeenCalled();

            eventBus.publish(new OrderStateTransitionEvent('AddingItems', 'Cancelled', ctx, order));
            await pause();
            expect(onSend).not.toHaveBeenCalled();

            eventBus.publish(new OrderStateTransitionEvent('AddingItems', 'OrderComplete', ctx, order));
            await pause();
            expect(onSend).not.toHaveBeenCalled();

            eventBus.publish(new OrderStateTransitionEvent('ArrangingPayment', 'PaymentSettled', ctx, order));
            await pause();
            expect(onSend).toHaveBeenCalledTimes(1);
        });

        it('sets the Order Customer emailAddress as recipient', async () => {
            eventBus.publish(new OrderStateTransitionEvent('ArrangingPayment', 'PaymentSettled', ctx, order));
            await pause();

            expect(onSend.mock.calls[0][0].recipient).toBe(order.customer!.emailAddress);
        });

        it('sets the subject', async () => {
            eventBus.publish(new OrderStateTransitionEvent('ArrangingPayment', 'PaymentSettled', ctx, order));
            await pause();

            expect(onSend.mock.calls[0][0].subject).toBe(`Order confirmation for #${order.code}`);
        });
    }


async () => {
            await initPluginWithHandlers([orderConfirmationHandler], { templatePath: path.join(__dirname, '../templates') });
        }


async () => {
            eventBus.publish(new OrderStateTransitionEvent('AddingItems', 'ArrangingPayment', ctx, order));
            await pause();
            expect(onSend).not.toHaveBeenCalled();

            eventBus.publish(new OrderStateTransitionEvent('AddingItems', 'Cancelled', ctx, order));
            await pause();
            expect(onSend).not.toHaveBeenCalled();

            eventBus.publish(new OrderStateTransitionEvent('AddingItems', 'OrderComplete', ctx, order));
            await pause();
            expect(onSend).not.toHaveBeenCalled();

            eventBus.publish(new OrderStateTransitionEvent('ArrangingPayment', 'PaymentSettled', ctx, order));
            await pause();
            expect(onSend).toHaveBeenCalledTimes(1);
        }


async () => {
            eventBus.publish(new OrderStateTransitionEvent('ArrangingPayment', 'PaymentSettled', ctx, order));
            await pause();

            expect(onSend.mock.calls[0][0].recipient).toBe(order.customer!.emailAddress);
        }


async () => {
            eventBus.publish(new OrderStateTransitionEvent('ArrangingPayment', 'PaymentSettled', ctx, order));
            await pause();

            expect(onSend.mock.calls[0][0].subject).toBe(`Order confirmation for #${order.code}`);
        }


() => new Promise(resolve => setTimeout(resolve, 50))


resolve => setTimeout(resolve, 50)


class MockEvent extends VendureEvent {
    constructor(public ctx: any, public shouldSend: boolean) {
        super();
    }
}


(state: IState) => ({
  hp: state.player.hp,
  mp: state.player.mp,
  percentage: state.player.hp,
  inventorySlots: state.player.inventorySlots,
})


({ hp, mp, inventorySlots, percentage }: any) => {
  const [inventoryOpen, setInventoryOpen] = useState(false);
  const showInventory = () => {
    setInventoryOpen(!inventoryOpen);
  };

  return (
    <div id='hud-items'>
      <HealthBar hp={hp} percentage={percentage} />
      <MagicBar mp={mp} percentage={percentage} />
      {inventoryOpen ? (
        <Inventory hp={hp} mp={mp} inventorySlots={inventorySlots} />
      ) : null}
      <button id='inventory-button' onClick={showInventory}>
        Show Inventory
      </button>
    </div>


() => {
    setInventoryOpen(!inventoryOpen);
  }


inventoryOpen ? (
        <Inventory hp={hp} mp={mp} inventorySlots={inventorySlots} />
      ) : null


<T>(name: string, initialState: T, storageCondition = true): [T, React.Dispatch<React.SetStateAction<T>>] => {
  const [state, setState] = useState(() => {
    const item = localStorage.getItem(name);
    if(item !== null && storageCondition) {
      return JSON.parse(item) as T;
    } else {
      return initialState;
    }
  });

  useEffect(() => {
    localStorage.setItem(name, JSON.stringify(state));
  }, [name, state]);

  return [state, setState];
}


() => {
    const item = localStorage.getItem(name);
    if(item !== null && storageCondition) {
      return JSON.parse(item) as T;
    } else {
      return initialState;
    }
  }


() => {
    localStorage.setItem(name, JSON.stringify(state));
  }


() => (
  <div className={styles.skillContainer}>
    <div className


/**
 * @docid
 * @inherits CollectionWidget
 * @module ui/validation_summary
 * @export default
 * @prevFileNamespace DevExpress.ui
 * @public
 */
export default class dxValidationSummary extends CollectionWidget {
    constructor(element: TElement, options?: dxValidationSummaryOptions)
}


export interface dxValidationSummaryOptions extends CollectionWidgetOptions<dxValidationSummary> {
    /**
     * @docid
     * @ref
     * @prevFileNamespace DevExpress.ui
     * @public
     */
    validationGroup?: string;
}


/** @public */
export type ContentReadyEvent = ComponentEvent<dxValidationSummary>;


/** @public */
export type DisposingEvent = ComponentEvent<dxValidationSummary>;


/** @public */
export type InitializedEvent = ComponentInitializedEvent<dxValidationSummary>;


/** @public */
export type ItemClickEvent = ComponentNativeEvent<dxValidationSummary> & ItemInfo;


/** @public */
export type OptionChangedEvent = ComponentEvent<dxValidationSummary> & ChangedOptionInfo;


export type Options = dxValidationSummaryOptions;


/** @deprecated use Options instead */
export type IOptions = dxValidationSummaryOptions;


({ children, style }: Props) => {
  return (
    <View style={styles.container}>
      <View style={[styles.subContainer, style]}>
        {children}
      </View>
    </View>


interface Props {
  children?: ReactNode,
  style?: ViewStyle
}


enum projectRoles {
  // This Enum provides the list of Project Roles.
  developer = 1,
  manager = 2,
  cto = 3,
}


enum algorithmBase {
  // This Enum provides the list of algorithams.
  SignedJWT = 1,
  SecureJWT = 2,
}


enum projectStatus {
  draft = 1,
  dev = 2,
  devComplete = 3,
  complianceChecks = 4,
  complianceReview = 5,
  complianceChecksComplete = 6,
  awaitingProdKeys = 7,
  inProd = 8,
}


/**
 * The grid extent is computed from the points. If the cell number for the right edge of the grid
 * is rounded down, some points could fall outside the grid. `lonlat.toPixel` and `lonlat.toPixel`
 * naturally truncate down, which is the correct behavior for binning points into cells but means
 * the grid is (almost) always 1 row too narrow/short, so we add 1 to the height and width when a
 * grid is created in this manner.
 */
export default function calculateGridPoints(
  bounds: CL.Bounds,
  zoom = PROJECTION_ZOOM_LEVEL
): number {
  const topLeft = toPixel([bounds.west, bounds.north], zoom)
  const bottomRight = toPixel([bounds.east, bounds.south], zoom)
  const width = Math.abs(topLeft.x - bottomRight.x) + 1
  const height = Math.abs(topLeft.y - bottomRight.y) + 1
  return width * height
}


@Injectable({
  providedIn: 'root'
})
export class DashboardService {
  constructor(private http:HttpClient,private ipService:StoreIpService) { }
  getTransactionDetails(customerId:number):Observable<Selltransaction[]>{
    return this.http.post<Selltransaction[]>("http://"+this.ipService.ipAddress+":"+this.ipService.port+"/getSellTransactionDetails",customerId)
  }
  getBuyTransactions(consumerId:number):Observable<Buytransaction[]>{
    return this.http.post<Buytransaction[]>("http://"+this.ipService.ipAddress+":"+this.ipService.port+"/getBuyTransactionDetails",consumerId)
  }
}


getTransactionDetails(customerId:number):Observable<Selltransaction[]>{
    return this.http.post<Selltransaction[]>("http://"+this.ipService.ipAddress+":"+this.ipService.port+"/getSellTransactionDetails",customerId)
  }


getBuyTransactions(consumerId:number):Observable<Buytransaction[]>{
    return this.http.post<Buytransaction[]>("http://"+this.ipService.ipAddress+":"+this.ipService.port+"/getBuyTransactionDetails",consumerId)
  }


(data: any) => {
            self.data = data.data;
            self.render(self.data, (data: News[]) => {
                // End loading
                self.templateHelper.loading(false);
                self.initializeSlider();
            });
        }


(data: News[]) => {
                // End loading
                self.templateHelper.loading(false);
                self.initializeSlider();
            }


() => {
            if (typeof callback === 'function')
                callback(data);
        }


() => {
            // Next News
            $carousel.slick('slickPrev');
        }


() => {
            // Prev News
            $carousel.slick('slickNext');
        }


() => {
            self.loadDetails($carousel);
        }


(e) => {
            self.loadDetails($carousel, $(this));
        }


news => news.id === id


() => {
            self.showDetails(!!item.media);
        }


() => {
                // play video
                self.playVideo();
            }


() => {
            const scrollValue = parseInt($newsDetails.css('top').replace('px', '')) - 100;
            $newsDetails.css('top', scrollValue.toString() + 'px');
        }


() => {
            const scrollValue = parseInt($newsDetails.css('top').replace('px', '')) + 100;
            if (scrollValue <= 0)
                $newsDetails.css('top', scrollValue.toString() + 'px');
        }


() => {
            // Return to news list
            self.hideDetails();
        }


() => {
            $('#news-details').empty();
        }


() => {
            self.layoutInstance.prepareUnloadModule();
        }


() => {
                self.playerInstance.unload();
            }


export default class NewsModule extends Module {

    private data;
    private pageTitle = 'آخرین اخبار';
    protected playerInstance;
    protected events = {
        'news.next': { control: 'right', title: 'خبر بعدی', icon: 'right' },
        'news.prev': { control: 'left', title: 'خبر قبلی', icon: 'left' },
        'news.enter': { control: 'enter', title: 'نمایش خبر', icon: 'enter' },
        'news.back': { control: 'back,backspace', title: 'بازگشت به اخبار', icon: 'refresh' },
        'news.play': { control: 'blue,b', title: 'نمایش ویدیو', button: true },
        'news.scroll-up': { control: 'up', title: 'اسکرول بالا' },
        'news.scroll-down': { control: 'down', title: 'اسکرول پایین' },
    };

    constructor(config?, layoutInstance?, moduleType?: string) {
        super(config, layoutInstance, moduleType);
        this.service = NewsService.instance;
        this.load();
        return this;
    }

    public load(callback?: any) {
        const self = this;
        let id: string = null;
        let service = 'getByCategory';

        this.templateHelper.loading();

        if (typeof this.moduleType !== 'undefined' && this.moduleType) {
            switch (this.moduleType) {
                case 'uhd-programs':
                    service = 'getItemsByCategory';
                    this.pageTitle = 'برنامه‌ها';
                    id = '4';
                    break;
                case 'news-teaching':
                    this.pageTitle = 'آموزش کسب و کار';
                    id = '85';
                    break;
                case 'tourism':
                    this.pageTitle = 'ایران گردی';
                    id = '115,116,117,118,126';
                    break;
                case 'multimedia':
                    this.pageTitle = 'چندرسانه‌ای';
                    id = '17,23,100';
                    break;
            }
        }
        this.service[service](id).done((data: any) => {
            self.data = data.data;
            self.render(self.data, (data: News[]) => {
                // End loading
                self.templateHelper.loading(false);
                self.initializeSlider();
            });
        });
    }

    public render(data: News[], callback): void {
        const template = this.layoutInstance.layout === 'uhd' ? uhdNewsTemplate : newsTemplate;
        this.templateHelper.render(template, { items: data, pageTitle: this.pageTitle }, this.$el, 'html', () => {
            if (typeof callback === 'function')
                callback(data);
        });
    }

    private initializeSlider(): void {
        const self = this;
        const $el = $("ul.news-items");
        const slidesToShow = 3;
        if (!$el.is(':visible'))
            $el.show(1);
        $el.slick({
            rtl: $("body").hasClass('rtl'),
            accessibility: false,
            slidesToShow: slidesToShow,
            slidesToScroll: 1,
            centerMode: true,
            focusOnSelect: true,
            infinite: true,
            speed: self.config.transitionSpeed,
            useCSS: false,
            useTransform: false
        });
        this.registerKeyboardInputs($el);
    }

    private registerKeyboardInputs($carousel): void {
        const self = this;

        this.input.addEvent('right', false, this.events['news.next'], () => {
            // Next News
            $carousel.slick('slickPrev');
        });

        this.input.addEvent('left', false, this.events['news.prev'], () => {
            // Prev News
            $carousel.slick('slickNext');
        });

        this.input.addEvent('enter', false, this.events['news.enter'], () => {
            self.loadDetails($carousel);
        });
        $(document).on('click', "ul.news-items li", (e) => {
            self.loadDetails($carousel, $(this));
        });
    }

    private loadDetails($carousel, $item?): void {
        const self = this;
        const id = (typeof $item !== 'undefined'
            && typeof $item.attr('data-id') !== 'undefined'
            && $item.attr('data-id'))
            ? ~~$item.attr('data-id')
            : ~~$carousel.find('.slick-current.slick-center li').attr('data-id');
        const item = this.data.find(news => news.id === id);
        // Load item details
        const template = this.layoutInstance.layout === 'uhd' ? uhdDetailsTemplate : detailsTemplate;
        this.templateHelper.render(template, { data: item }, $('#news-details'), 'html', () => {
            self.showDetails(!!item.media);
        });
    }

    private showDetails(hasVideo: boolean = false): void {
        $('#news-details').fadeIn();
        const self = this;
        const $newsDetails = $('#news-details .inner .news-body');
        $newsDetails.css('top', '0');
        if (hasVideo) {
            this.input.addEvent('blue,b', false, this.events['news.play'], () => {
                // play video
                self.playVideo();
            });
        }
        this.input.addEvent('down', false, this.events['news.scroll-down'], () => {
            const scrollValue = parseInt($newsDetails.css('top').replace('px', '')) - 100;
            $newsDetails.css('top', scrollValue.toString() + 'px');
        });
        this.input.addEvent('up', false, this.events['news.scroll-up'], () => {
            const scrollValue = parseInt($newsDetails.css('top').replace('px', '')) + 100;
            if (scrollValue <= 0)
                $newsDetails.css('top', scrollValue.toString() + 'px');
        });
        this.input.removeEvent('back,backspace', { key: 'module.exit' });
        this.input.addEvent('back,backspace', false, this.events['news.back'], () => {
            // Return to news list
            self.hideDetails();
        });
    }

    private hideDetails(): void {
        const self = this;
        $('#news-details').fadeOut(() => {
            $('#news-details').empty();
        });
        this.input.removeEvent('blue,b', { key: 'news.play' });
        this.input.removeEvent('back,backspace', { key: 'news.back' });
        setTimeout(() => {
            self.layoutInstance.prepareUnloadModule();
        }, 500);
    }

    private playVideo(): void {
        const self = this;
        if (this.templateHelper.hasClass('player-mode'))
            return;
        const $newsDetails = $('.news-details');
        const playerParams = {
            unloadMethod: () => {
                self.playerInstance.unload();
            },
            sources: [{
                src: $newsDetails.attr('data-media'),
                poster: $newsDetails.find('img').attr('src'),
                type: 'video/mp4'
            }]
        };
        this.playerInstance = new this.playerService('mediaplayer', playerParams);
    }

}


public load(callback?: any) {
        const self = this;
        let id: string = null;
        let service = 'getByCategory';

        this.templateHelper.loading();

        if (typeof this.moduleType !== 'undefined' && this.moduleType) {
            switch (this.moduleType) {
                case 'uhd-programs':
                    service = 'getItemsByCategory';
                    this.pageTitle = 'برنامه‌ها';
                    id = '4';
                    break;
                case 'news-teaching':
                    this.pageTitle = 'آموزش کسب و کار';
                    id = '85';
                    break;
                case 'tourism':
                    this.pageTitle = 'ایران گردی';
                    id = '115,116,117,118,126';
                    break;
                case 'multimedia':
                    this.pageTitle = 'چندرسانه‌ای';
                    id = '17,23,100';
                    break;
            }
        }
        this.service[service](id).done((data: any) => {
            self.data = data.data;
            self.render(self.data, (data: News[]) => {
                // End loading
                self.templateHelper.loading(false);
                self.initializeSlider();
            });
        });
    }


public render(data: News[], callback): void {
        const template = this.layoutInstance.layout === 'uhd' ? uhdNewsTemplate : newsTemplate;
        this.templateHelper.render(template, { items: data, pageTitle: this.pageTitle }, this.$el, 'html', () => {
            if (typeof callback === 'function')
                callback(data);
        });
    }


private initializeSlider(): void {
        const self = this;
        const $el = $("ul.news-items");
        const slidesToShow = 3;
        if (!$el.is(':visible'))
            $el.show(1);
        $el.slick({
            rtl: $("body").hasClass('rtl'),
            accessibility: false,
            slidesToShow: slidesToShow,
            slidesToScroll: 1,
            centerMode: true,
            focusOnSelect: true,
            infinite: true,
            speed: self.config.transitionSpeed,
            useCSS: false,
            useTransform: false
        });
        this.registerKeyboardInputs($el);
    }


private registerKeyboardInputs($carousel): void {
        const self = this;

        this.input.addEvent('right', false, this.events['news.next'], () => {
            // Next News
            $carousel.slick('slickPrev');
        });

        this.input.addEvent('left', false, this.events['news.prev'], () => {
            // Prev News
            $carousel.slick('slickNext');
        });

        this.input.addEvent('enter', false, this.events['news.enter'], () => {
            self.loadDetails($carousel);
        });
        $(document).on('click', "ul.news-items li", (e) => {
            self.loadDetails($carousel, $(this));
        });
    }


private loadDetails($carousel, $item?): void {
        const self = this;
        const id = (typeof $item !== 'undefined'
            && typeof $item.attr('data-id') !== 'undefined'
            && $item.attr('data-id'))
            ? ~~$item.attr('data-id')
            : ~~$carousel.find('.slick-current.slick-center li').attr('data-id');
        const item = this.data.find(news => news.id === id);
        // Load item details
        const template = this.layoutInstance.layout === 'uhd' ? uhdDetailsTemplate : detailsTemplate;
        this.templateHelper.render(template, { data: item }, $('#news-details'), 'html', () => {
            self.showDetails(!!item.media);
        });
    }


private showDetails(hasVideo: boolean = false): void {
        $('#news-details').fadeIn();
        const self = this;
        const $newsDetails = $('#news-details .inner .news-body');
        $newsDetails.css('top', '0');
        if (hasVideo) {
            this.input.addEvent('blue,b', false, this.events['news.play'], () => {
                // play video
                self.playVideo();
            });
        }
        this.input.addEvent('down', false, this.events['news.scroll-down'], () => {
            const scrollValue = parseInt($newsDetails.css('top').replace('px', '')) - 100;
            $newsDetails.css('top', scrollValue.toString() + 'px');
        });
        this.input.addEvent('up', false, this.events['news.scroll-up'], () => {
            const scrollValue = parseInt($newsDetails.css('top').replace('px', '')) + 100;
            if (scrollValue <= 0)
                $newsDetails.css('top', scrollValue.toString() + 'px');
        });
        this.input.removeEvent('back,backspace', { key: 'module.exit' });
        this.input.addEvent('back,backspace', false, this.events['news.back'], () => {
            // Return to news list
            self.hideDetails();
        });
    }


private hideDetails(): void {
        const self = this;
        $('#news-details').fadeOut(() => {
            $('#news-details').empty();
        });
        this.input.removeEvent('blue,b', { key: 'news.play' });
        this.input.removeEvent('back,backspace', { key: 'news.back' });
        setTimeout(() => {
            self.layoutInstance.prepareUnloadModule();
        }, 500);
    }


private playVideo(): void {
        const self = this;
        if (this.templateHelper.hasClass('player-mode'))
            return;
        const $newsDetails = $('.news-details');
        const playerParams = {
            unloadMethod: () => {
                self.playerInstance.unload();
            },
            sources: [{
                src: $newsDetails.attr('data-media'),
                poster: $newsDetails.find('img').attr('src'),
                type: 'video/mp4'
            }]
        };
        this.playerInstance = new this.playerService('mediaplayer', playerParams);
    }


export default function useDeferredEvents(
  initialState: DeferredEvent[] = [],
  { onDone, onAdd, onReset }: DeferredEventsHookOptions = {}
): DeferredEventsHook {
  const [events, setEvents] = useState<Set<DeferredEvent>>(
    new Set(initialState)
  );

  const add = useCallback<DeferredEventAddFn>(
    event =>
      setEvents(prevEvents => {
        if (onAdd) {
          onAdd(event);
        }

        const newEvents = new Set(prevEvents);
        newEvents.add(event);
        return newEvents;
      }),
    [onAdd]
  );

  const done = useCallback<DeferredEventDoneFn>(
    (event, args) =>
      setEvents(prevEvents => {
        if (onDone) {
          onDone(event, args);
        }

        const newEvents = new Set(prevEvents);
        newEvents.delete(event);
        return newEvents;
      }),
    [onDone]
  );

  const reset = useCallback<DeferredEventsResetFn>(() => {
    if (onReset) {
      onReset();
    }

    setEvents(new Set([]));
  }, [onReset]);

  return { add, done, reset, hasEvents: events.size > 0 };
}


event =>
      setEvents(prevEvents => {
        if (onAdd) {
          onAdd(event);
        }

        const newEvents = new Set(prevEvents);
        newEvents.add(event);
        return newEvents;
      })


prevEvents => {
        if (onAdd) {
          onAdd(event);
        }

        const newEvents = new Set(prevEvents);
        newEvents.add(event);
        return newEvents;
      }


(event, args) =>
      setEvents(prevEvents => {
        if (onDone) {
          onDone(event, args);
        }

        const newEvents = new Set(prevEvents);
        newEvents.delete(event);
        return newEvents;
      })


prevEvents => {
        if (onDone) {
          onDone(event, args);
        }

        const newEvents = new Set(prevEvents);
        newEvents.delete(event);
        return newEvents;
      }


() => {
    if (onReset) {
      onReset();
    }

    setEvents(new Set([]));
  }


async function fetchDashboards(options: DashListOptions) {
  let starredDashboards: Promise<Dashboard[]> = Promise.resolve([]);
  if (options.showStarred) {
    const params = { limit: options.maxItems, starred: 'true' };
    starredDashboards = getBackendSrv().search(params);
  }

  let recentDashboards: Promise<Dashboard[]> = Promise.resolve([]);
  let dashIds: number[] = [];
  if (options.showRecentlyViewed) {
    dashIds = take<number>(impressionSrv.getDashboardOpened(), options.maxItems);
    recentDashboards = getBackendSrv().search({ dashboardIds: dashIds, limit: options.maxItems });
  }

  let searchedDashboards: Promise<Dashboard[]> = Promise.resolve([]);
  if (options.showSearch) {
    const params = {
      limit: options.maxItems,
      query: options.query,
      folderIds: options.folderId,
      tag: options.tags,
      type: 'dash-db',
    };

    searchedDashboards = getBackendSrv().search(params);
  }

  const [starred, searched, recent] = await Promise.all([starredDashboards, searchedDashboards, recentDashboards]);

  // We deliberately deal with recent dashboards first so that the order of dash IDs is preserved
  let dashMap = new Map<number, Dashboard>();
  for (const dashId of dashIds) {
    const dash = recent.find(d => d.id === dashId);
    if (dash) {
      dashMap.set(dashId, { ...dash, isRecent: true });
    }
  }

  searched.forEach(dash => {
    if (dashMap.has(dash.id)) {
      dashMap.get(dash.id)!.isSearchResult = true;
    } else {
      dashMap.set(dash.id, { ...dash, isSearchResult: true });
    }
  });

  starred.forEach(dash => {
    if (dashMap.has(dash.id)) {
      dashMap.get(dash.id)!.isStarred = true;
    } else {
      dashMap.set(dash.id, { ...dash, isStarred: true });
    }
  });

  return dashMap;
}


export function DashList(props: PanelProps<DashListOptions>) {
  const [dashboards, setDashboards] = useState(new Map<number, Dashboard>());
  useEffect(() => {
    fetchDashboards(props.options).then(dashes => {
      setDashboards(dashes);
    });
  }, [
    props.options.showSearch,
    props.options.showStarred,
    props.options.showRecentlyViewed,
    props.options.maxItems,
    props.options.query,
    props.options.tags,
    props.options.folderId,
  ]);

  const toggleDashboardStar = async (e: React.SyntheticEvent, dash: Dashboard) => {
    e.preventDefault();
    e.stopPropagation();

    const isStarred = await getDashboardSrv().starDashboard(dash.id.toString(), dash.isStarred);
    const updatedDashboards = new Map(dashboards);
    updatedDashboards.set(dash.id, { ...dash, isStarred });
    setDashboards(updatedDashboards);
  };

  const [starredDashboards, recentDashboards, searchedDashboards] = useMemo(() => {
    const dashboardList = [...dashboards.values()];
    return [
      dashboardList.filter(dash => dash.isStarred),
      dashboardList.filter(dash => dash.isRecent),
      dashboardList.filter(dash => dash.isSearchResult),
    ];
  }, [dashboards]);

  const { showStarred, showRecentlyViewed, showHeadings, showSearch } = props.options;

  const dashboardGroups: DashboardGroup[] = [
    {
      header: 'Starred dashboards',
      dashboards: starredDashboards,
      show: showStarred,
    },
    {
      header: 'Recently viewed dashboards',
      dashboards: recentDashboards,
      show: showRecentlyViewed,
    },
    {
      header: 'Search',
      dashboards: searchedDashboards,
      show: showSearch,
    },
  ];

  const css = useStyles(getStyles);
  return (
    <CustomScrollbar autoHeightMin="100%" autoHeightMax="100%">
      {dashboardGroups.map(
        ({ show, header, dashboards }, i) =>
          show && (
            <div className={css.dashlistSection} key={`dash-group-${i}`}>
              {showHeadings &&
{header}
}

                {dashboards.map(dash => (
                  <li className={css.dashlistItem} key={`dash-${dash.id}`}>

                          {dash.title}

                        {dash.folderTitle &&
{dash.folderTitle}
}

                       toggleDashboardStar(e, dash)}>
                        <Icon name={dash.isStarred ? 'favorite' : 'star'} type={dash.isStarred ? 'mono' : 'default'} />

                ))}

          )
      )}


d => d.id === dashId


dash => {
    if (dashMap.has(dash.id)) {
      dashMap.get(dash.id)!.isSearchResult = true;
    } else {
      dashMap.set(dash.id, { ...dash, isSearchResult: true });
    }
  }


dash => {
    if (dashMap.has(dash.id)) {
      dashMap.get(dash.id)!.isStarred = true;
    } else {
      dashMap.set(dash.id, { ...dash, isStarred: true });
    }
  }


() => {
    fetchDashboards(props.options).then(dashes => {
      setDashboards(dashes);
    });
  }


dashes => {
      setDashboards(dashes);
    }


async (e: React.SyntheticEvent, dash: Dashboard) => {
    e.preventDefault();
    e.stopPropagation();

    const isStarred = await getDashboardSrv().starDashboard(dash.id.toString(), dash.isStarred);
    const updatedDashboards = new Map(dashboards);
    updatedDashboards.set(dash.id, { ...dash, isStarred });
    setDashboards(updatedDashboards);
  }


() => {
    const dashboardList = [...dashboards.values()];
    return [
      dashboardList.filter(dash => dash.isStarred),
      dashboardList.filter(dash => dash.isRecent),
      dashboardList.filter(dash => dash.isSearchResult),
    ];
  }


dash => dash.isStarred


dash => dash.isRecent


dash => dash.isSearchResult


({ show, header, dashboards }, i) =>
          show && (
            <div className


dash => (
                  <li className={css.dashlistItem}


interface DashboardGroup {
  show: boolean;
  header: string;
  dashboards: Dashboard[];
}


type Dashboard = DashboardSearchHit & { isSearchResult?: boolean; isRecent?: boolean };


toggleDashboardStar(e, dash)


export interface ISequelizeUriConfig extends Options {

  /**
   * Uri connection string to database
   */
  url: string;

  /**
   * Path to models, which should be loaded
   */
  modelPaths?: string[];

  /**
   * Makes it possible to use sequelize for validation only
   * if set to true. For this configuration it is always false.
   * See ISequelizeValidationOnlyConfig interface
   */
  validateOnly?: false;
}


() => {
  describe('createClient', () => {
    const originalFetch = global.fetch

    let clientOptions: BeagleGrpcClientOptions
    let fetchGrpcViewSpy: JestMock.SpyInstance<Promise<Response>, [name: string, client: ScreenServiceClient, fetchReq: FetchRequest]>
    let getRequestSpy: JestMock.SpyInstance<FetchRequest | null, [requestInfo: RequestInfo]>

    beforeAll(() => {
      fetchGrpcViewSpy = jest.spyOn(view, 'fetchGrpcView').mockImplementation(() => Promise.resolve(new Response()))
      getRequestSpy = jest.spyOn(request, 'getRequest')
      global.fetch = (jest.fn().mockImplementation(() => Promise.resolve(new Response())) as any)
    })

    beforeEach(() => {
      (global.fetch as jest.Mock<any, any[]>).mockClear()
      fetchGrpcViewSpy.mockClear()
      getRequestSpy.mockClear()

      clientOptions = {
        proxyAddress: 'http://localhost:6692/',
        redirectGrpcFrom: _MOCK_GRPC_URL_,
        customHttpClient: (jest.fn().mockImplementation(() => new Response()) as any)
      }
    })

    test('it should create the client (function) using the "ScreenServiceClient" generated by the protocol buffer', () => {
      expect(typeof createClient(clientOptions)).toBe('function')
    })

    describe('fetchGrpcView', () => {
      test('it should use the "fetchGrpcView" when the url matches the grpc origin, using the client generated by the protobuf', () => {
        const url = `${_MOCK_GRPC_URL_}/my-grpc/endpoint`
        createClient(clientOptions)(url)

        expect(fetchGrpcViewSpy).toHaveBeenCalledTimes(1)
        expect(getRequestSpy).toHaveReturnedWith({ url })

        const screenServiceClient = new ScreenServiceClient(clientOptions.proxyAddress)
        expect(fetchGrpcViewSpy).toHaveBeenCalledWith('/my-grpc/endpoint', screenServiceClient, { url })
      })

      test('it should not call "fetchGrpcView" when the url does not match the grpc origin', () => {
        const url = `${_MOCK_GRPC_URL_.replace('/grpc', '')}/endpoint`
        createClient(clientOptions)(url)

        expect(getRequestSpy).toHaveBeenCalledTimes(1)
        expect(getRequestSpy).toHaveReturnedWith({ url })
        expect(fetchGrpcViewSpy).not.toHaveBeenCalled()
      })

      test('it should not call "fetchGrpcView" when "getRequest" does not return a valid object', () => {
        const url = `${_MOCK_GRPC_URL_.replace('/grpc', '')}/endpoint`
        getRequestSpy = jest.spyOn(request, 'getRequest').mockImplementation(() => null)
        createClient(clientOptions)(url)

        expect(getRequestSpy).toHaveBeenCalledTimes(1)
        expect(getRequestSpy).toHaveReturnedWith(null)
        expect(fetchGrpcViewSpy).not.toHaveBeenCalled()

        getRequestSpy.mockRestore()
        getRequestSpy = jest.spyOn(request, 'getRequest')
      })

      test('it should not call "fetchGrpcView" when the "redirectGrpcFrom" is not defined', () => {
        const url = `${_MOCK_GRPC_URL_.replace('/grpc', '')}/endpoint`
        createClient({ ...clientOptions, redirectGrpcFrom: undefined })(url)

        expect(getRequestSpy).toHaveReturnedWith({ url })
        expect(fetchGrpcViewSpy).not.toHaveBeenCalled()
      })
    })

    describe('customHttpClient', () => {
      test('it should use the custom http client when one is provided and the url does not match the grpc origin', () => {
        createClient(clientOptions)(_MOCK_URL_)

        expect(clientOptions.customHttpClient).toHaveBeenCalledTimes(1)
        expect(clientOptions.customHttpClient).toHaveBeenCalledWith(_MOCK_URL_)
      })

      test('it should use the custom http client when the "redirectGrpcFrom" is not defined and is provided an url that does not match the grpc origin', () => {
        createClient({ ...clientOptions, redirectGrpcFrom: undefined })(_MOCK_URL_)

        expect(clientOptions.customHttpClient).toHaveBeenCalledTimes(1)
        expect(global.fetch).not.toHaveBeenCalled()
      })
    })

    describe('fetch', () => {
      test('it should use fetch when the custom http client is not defined and is provided an url that does not match the grpc origin', () => {
        createClient({ ...clientOptions, customHttpClient: undefined })(_MOCK_URL_)

        expect(clientOptions.customHttpClient).not.toHaveBeenCalled()
        expect(global.fetch).toHaveBeenCalledTimes(1)
        expect(global.fetch).toHaveBeenCalledWith(_MOCK_URL_)
      })

      test('it should use fetch when the "redirectGrpcFrom" and the custom http client are not defined and is provided an url that does not match the grpc origin', () => {
        createClient({ ...clientOptions, redirectGrpcFrom: undefined, customHttpClient: undefined })(_MOCK_URL_)

        expect(clientOptions.customHttpClient).not.toHaveBeenCalled()
        expect(global.fetch).toHaveBeenCalledTimes(1)
        expect(global.fetch).toHaveBeenCalledWith(_MOCK_URL_)
      })

      test('it should use fetch when the args does not match the requirements', () => {
        createClient(clientOptions)(null as any)

        expect(clientOptions.customHttpClient).not.toHaveBeenCalled()
        expect(global.fetch).toHaveBeenCalledTimes(1)
        expect(global.fetch).toHaveBeenCalledWith(null)
      })
    })

    afterAll(() => {
      (global.fetch as jest.Mock<any, any[]>).mockRestore()
      global.fetch = originalFetch

      fetchGrpcViewSpy.mockRestore()
    })
  })
}


() => {
    const originalFetch = global.fetch

    let clientOptions: BeagleGrpcClientOptions
    let fetchGrpcViewSpy: JestMock.SpyInstance<Promise<Response>, [name: string, client: ScreenServiceClient, fetchReq: FetchRequest]>
    let getRequestSpy: JestMock.SpyInstance<FetchRequest | null, [requestInfo: RequestInfo]>

    beforeAll(() => {
      fetchGrpcViewSpy = jest.spyOn(view, 'fetchGrpcView').mockImplementation(() => Promise.resolve(new Response()))
      getRequestSpy = jest.spyOn(request, 'getRequest')
      global.fetch = (jest.fn().mockImplementation(() => Promise.resolve(new Response())) as any)
    })

    beforeEach(() => {
      (global.fetch as jest.Mock<any, any[]>).mockClear()
      fetchGrpcViewSpy.mockClear()
      getRequestSpy.mockClear()

      clientOptions = {
        proxyAddress: 'http://localhost:6692/',
        redirectGrpcFrom: _MOCK_GRPC_URL_,
        customHttpClient: (jest.fn().mockImplementation(() => new Response()) as any)
      }
    })

    test('it should create the client (function) using the "ScreenServiceClient" generated by the protocol buffer', () => {
      expect(typeof createClient(clientOptions)).toBe('function')
    })

    describe('fetchGrpcView', () => {
      test('it should use the "fetchGrpcView" when the url matches the grpc origin, using the client generated by the protobuf', () => {
        const url = `${_MOCK_GRPC_URL_}/my-grpc/endpoint`
        createClient(clientOptions)(url)

        expect(fetchGrpcViewSpy).toHaveBeenCalledTimes(1)
        expect(getRequestSpy).toHaveReturnedWith({ url })

        const screenServiceClient = new ScreenServiceClient(clientOptions.proxyAddress)
        expect(fetchGrpcViewSpy).toHaveBeenCalledWith('/my-grpc/endpoint', screenServiceClient, { url })
      })

      test('it should not call "fetchGrpcView" when the url does not match the grpc origin', () => {
        const url = `${_MOCK_GRPC_URL_.replace('/grpc', '')}/endpoint`
        createClient(clientOptions)(url)

        expect(getRequestSpy).toHaveBeenCalledTimes(1)
        expect(getRequestSpy).toHaveReturnedWith({ url })
        expect(fetchGrpcViewSpy).not.toHaveBeenCalled()
      })

      test('it should not call "fetchGrpcView" when "getRequest" does not return a valid object', () => {
        const url = `${_MOCK_GRPC_URL_.replace('/grpc', '')}/endpoint`
        getRequestSpy = jest.spyOn(request, 'getRequest').mockImplementation(() => null)
        createClient(clientOptions)(url)

        expect(getRequestSpy).toHaveBeenCalledTimes(1)
        expect(getRequestSpy).toHaveReturnedWith(null)
        expect(fetchGrpcViewSpy).not.toHaveBeenCalled()

        getRequestSpy.mockRestore()
        getRequestSpy = jest.spyOn(request, 'getRequest')
      })

      test('it should not call "fetchGrpcView" when the "redirectGrpcFrom" is not defined', () => {
        const url = `${_MOCK_GRPC_URL_.replace('/grpc', '')}/endpoint`
        createClient({ ...clientOptions, redirectGrpcFrom: undefined })(url)

        expect(getRequestSpy).toHaveReturnedWith({ url })
        expect(fetchGrpcViewSpy).not.toHaveBeenCalled()
      })
    })

    describe('customHttpClient', () => {
      test('it should use the custom http client when one is provided and the url does not match the grpc origin', () => {
        createClient(clientOptions)(_MOCK_URL_)

        expect(clientOptions.customHttpClient).toHaveBeenCalledTimes(1)
        expect(clientOptions.customHttpClient).toHaveBeenCalledWith(_MOCK_URL_)
      })

      test('it should use the custom http client when the "redirectGrpcFrom" is not defined and is provided an url that does not match the grpc origin', () => {
        createClient({ ...clientOptions, redirectGrpcFrom: undefined })(_MOCK_URL_)

        expect(clientOptions.customHttpClient).toHaveBeenCalledTimes(1)
        expect(global.fetch).not.toHaveBeenCalled()
      })
    })

    describe('fetch', () => {
      test('it should use fetch when the custom http client is not defined and is provided an url that does not match the grpc origin', () => {
        createClient({ ...clientOptions, customHttpClient: undefined })(_MOCK_URL_)

        expect(clientOptions.customHttpClient).not.toHaveBeenCalled()
        expect(global.fetch).toHaveBeenCalledTimes(1)
        expect(global.fetch).toHaveBeenCalledWith(_MOCK_URL_)
      })

      test('it should use fetch when the "redirectGrpcFrom" and the custom http client are not defined and is provided an url that does not match the grpc origin', () => {
        createClient({ ...clientOptions, redirectGrpcFrom: undefined, customHttpClient: undefined })(_MOCK_URL_)

        expect(clientOptions.customHttpClient).not.toHaveBeenCalled()
        expect(global.fetch).toHaveBeenCalledTimes(1)
        expect(global.fetch).toHaveBeenCalledWith(_MOCK_URL_)
      })

      test('it should use fetch when the args does not match the requirements', () => {
        createClient(clientOptions)(null as any)

        expect(clientOptions.customHttpClient).not.toHaveBeenCalled()
        expect(global.fetch).toHaveBeenCalledTimes(1)
        expect(global.fetch).toHaveBeenCalledWith(null)
      })
    })

    afterAll(() => {
      (global.fetch as jest.Mock<any, any[]>).mockRestore()
      global.fetch = originalFetch

      fetchGrpcViewSpy.mockRestore()
    })
  }


() => {
      fetchGrpcViewSpy = jest.spyOn(view, 'fetchGrpcView').mockImplementation(() => Promise.resolve(new Response()))
      getRequestSpy = jest.spyOn(request, 'getRequest')
      global.fetch = (jest.fn().mockImplementation(() => Promise.resolve(new Response())) as any)
    }


() => Promise.resolve(new Response())


() => {
      (global.fetch as jest.Mock<any, any[]>).mockClear()
      fetchGrpcViewSpy.mockClear()
      getRequestSpy.mockClear()

      clientOptions = {
        proxyAddress: 'http://localhost:6692/',
        redirectGrpcFrom: _MOCK_GRPC_URL_,
        customHttpClient: (jest.fn().mockImplementation(() => new Response()) as any)
      }
    }


() => new Response()


() => {
      expect(typeof createClient(clientOptions)).toBe('function')
    }


() => {
      test('it should use the "fetchGrpcView" when the url matches the grpc origin, using the client generated by the protobuf', () => {
        const url = `${_MOCK_GRPC_URL_}/my-grpc/endpoint`
        createClient(clientOptions)(url)

        expect(fetchGrpcViewSpy).toHaveBeenCalledTimes(1)
        expect(getRequestSpy).toHaveReturnedWith({ url })

        const screenServiceClient = new ScreenServiceClient(clientOptions.proxyAddress)
        expect(fetchGrpcViewSpy).toHaveBeenCalledWith('/my-grpc/endpoint', screenServiceClient, { url })
      })

      test('it should not call "fetchGrpcView" when the url does not match the grpc origin', () => {
        const url = `${_MOCK_GRPC_URL_.replace('/grpc', '')}/endpoint`
        createClient(clientOptions)(url)

        expect(getRequestSpy).toHaveBeenCalledTimes(1)
        expect(getRequestSpy).toHaveReturnedWith({ url })
        expect(fetchGrpcViewSpy).not.toHaveBeenCalled()
      })

      test('it should not call "fetchGrpcView" when "getRequest" does not return a valid object', () => {
        const url = `${_MOCK_GRPC_URL_.replace('/grpc', '')}/endpoint`
        getRequestSpy = jest.spyOn(request, 'getRequest').mockImplementation(() => null)
        createClient(clientOptions)(url)

        expect(getRequestSpy).toHaveBeenCalledTimes(1)
        expect(getRequestSpy).toHaveReturnedWith(null)
        expect(fetchGrpcViewSpy).not.toHaveBeenCalled()

        getRequestSpy.mockRestore()
        getRequestSpy = jest.spyOn(request, 'getRequest')
      })

      test('it should not call "fetchGrpcView" when the "redirectGrpcFrom" is not defined', () => {
        const url = `${_MOCK_GRPC_URL_.replace('/grpc', '')}/endpoint`
        createClient({ ...clientOptions, redirectGrpcFrom: undefined })(url)

        expect(getRequestSpy).toHaveReturnedWith({ url })
        expect(fetchGrpcViewSpy).not.toHaveBeenCalled()
      })
    }


() => {
        const url = `${_MOCK_GRPC_URL_}/my-grpc/endpoint`
        createClient(clientOptions)(url)

        expect(fetchGrpcViewSpy).toHaveBeenCalledTimes(1)
        expect(getRequestSpy).toHaveReturnedWith({ url })

        const screenServiceClient = new ScreenServiceClient(clientOptions.proxyAddress)
        expect(fetchGrpcViewSpy).toHaveBeenCalledWith('/my-grpc/endpoint', screenServiceClient, { url })
      }


() => {
        const url = `${_MOCK_GRPC_URL_.replace('/grpc', '')}/endpoint`
        createClient(clientOptions)(url)

        expect(getRequestSpy).toHaveBeenCalledTimes(1)
        expect(getRequestSpy).toHaveReturnedWith({ url })
        expect(fetchGrpcViewSpy).not.toHaveBeenCalled()
      }


() => {
        const url = `${_MOCK_GRPC_URL_.replace('/grpc', '')}/endpoint`
        getRequestSpy = jest.spyOn(request, 'getRequest').mockImplementation(() => null)
        createClient(clientOptions)(url)

        expect(getRequestSpy).toHaveBeenCalledTimes(1)
        expect(getRequestSpy).toHaveReturnedWith(null)
        expect(fetchGrpcViewSpy).not.toHaveBeenCalled()

        getRequestSpy.mockRestore()
        getRequestSpy = jest.spyOn(request, 'getRequest')
      }


() => {
        const url = `${_MOCK_GRPC_URL_.replace('/grpc', '')}/endpoint`
        createClient({ ...clientOptions, redirectGrpcFrom: undefined })(url)

        expect(getRequestSpy).toHaveReturnedWith({ url })
        expect(fetchGrpcViewSpy).not.toHaveBeenCalled()
      }


() => {
      test('it should use the custom http client when one is provided and the url does not match the grpc origin', () => {
        createClient(clientOptions)(_MOCK_URL_)

        expect(clientOptions.customHttpClient).toHaveBeenCalledTimes(1)
        expect(clientOptions.customHttpClient).toHaveBeenCalledWith(_MOCK_URL_)
      })

      test('it should use the custom http client when the "redirectGrpcFrom" is not defined and is provided an url that does not match the grpc origin', () => {
        createClient({ ...clientOptions, redirectGrpcFrom: undefined })(_MOCK_URL_)

        expect(clientOptions.customHttpClient).toHaveBeenCalledTimes(1)
        expect(global.fetch).not.toHaveBeenCalled()
      })
    }


() => {
        createClient(clientOptions)(_MOCK_URL_)

        expect(clientOptions.customHttpClient).toHaveBeenCalledTimes(1)
        expect(clientOptions.customHttpClient).toHaveBeenCalledWith(_MOCK_URL_)
      }


() => {
        createClient({ ...clientOptions, redirectGrpcFrom: undefined })(_MOCK_URL_)

        expect(clientOptions.customHttpClient).toHaveBeenCalledTimes(1)
        expect(global.fetch).not.toHaveBeenCalled()
      }


() => {
      test('it should use fetch when the custom http client is not defined and is provided an url that does not match the grpc origin', () => {
        createClient({ ...clientOptions, customHttpClient: undefined })(_MOCK_URL_)

        expect(clientOptions.customHttpClient).not.toHaveBeenCalled()
        expect(global.fetch).toHaveBeenCalledTimes(1)
        expect(global.fetch).toHaveBeenCalledWith(_MOCK_URL_)
      })

      test('it should use fetch when the "redirectGrpcFrom" and the custom http client are not defined and is provided an url that does not match the grpc origin', () => {
        createClient({ ...clientOptions, redirectGrpcFrom: undefined, customHttpClient: undefined })(_MOCK_URL_)

        expect(clientOptions.customHttpClient).not.toHaveBeenCalled()
        expect(global.fetch).toHaveBeenCalledTimes(1)
        expect(global.fetch).toHaveBeenCalledWith(_MOCK_URL_)
      })

      test('it should use fetch when the args does not match the requirements', () => {
        createClient(clientOptions)(null as any)

        expect(clientOptions.customHttpClient).not.toHaveBeenCalled()
        expect(global.fetch).toHaveBeenCalledTimes(1)
        expect(global.fetch).toHaveBeenCalledWith(null)
      })
    }


() => {
        createClient({ ...clientOptions, customHttpClient: undefined })(_MOCK_URL_)

        expect(clientOptions.customHttpClient).not.toHaveBeenCalled()
        expect(global.fetch).toHaveBeenCalledTimes(1)
        expect(global.fetch).toHaveBeenCalledWith(_MOCK_URL_)
      }


() => {
        createClient({ ...clientOptions, redirectGrpcFrom: undefined, customHttpClient: undefined })(_MOCK_URL_)

        expect(clientOptions.customHttpClient).not.toHaveBeenCalled()
        expect(global.fetch).toHaveBeenCalledTimes(1)
        expect(global.fetch).toHaveBeenCalledWith(_MOCK_URL_)
      }


() => {
        createClient(clientOptions)(null as any)

        expect(clientOptions.customHttpClient).not.toHaveBeenCalled()
        expect(global.fetch).toHaveBeenCalledTimes(1)
        expect(global.fetch).toHaveBeenCalledWith(null)
      }


() => {
      (global.fetch as jest.Mock<any, any[]>).mockRestore()
      global.fetch = originalFetch

      fetchGrpcViewSpy.mockRestore()
    }


({ children }) => {
  return <SectionTitle>{children}</SectionTitle>;
}


/* eslint-disable no-unused-vars */
export const enum Endpoints {
	devUrl = "https://jsonplaceholder.typicode.com/todos",
	prodUrl = "https://api.mocki.io/v1/b043df5a"
}


export const enum Env {
	dev = "development",
	prod = "production"
}


export const enum Domain {
	lcoal = "127.0.0.1"
}


@Module({
    providers: [StudentsService],
    controllers: [StudentsController],
})
export class StudentsModule {}


declare function notLoopable<T>(value: T | Loopable<any>): value is T;


export default class SidebarHeader extends React.Component<Props> {
    public render() {
        const me = this.props.currentUser;
        let profilePicture = null;

        if (!me) {
            return null;
        }

        if (me.last_picture_update) {
            profilePicture = (
                <Avatar
                    username={me.username}
                    url={Client4.getProfilePictureUrl(me.id, me.last_picture_update)}
                    size='lg'
                />
            );
        }

        return (
            <MenuWrapper className='AdminSidebarHeader'>

                    {profilePicture}

                            <FormattedMessage
                                id='admin.sidebarHeader.systemConsole'
                                defaultMessage='System Console'
                            />

{'@' + me.username}

                    <button className='style--none'>
                        <MenuIcon className='menu-icon'/>
                    </button>

                <AdminNavbarDropdown/>
            </MenuWrapper>
        );
    }
}


type Props = {
    currentUser: UserProfile& {last_picture_update?: number};
}


public render() {
        const me = this.props.currentUser;
        let profilePicture = null;

        if (!me) {
            return null;
        }

        if (me.last_picture_update) {
            profilePicture = (
                <Avatar
                    username={me.username}
                    url={Client4.getProfilePictureUrl(me.id, me.last_picture_update)}
                    size='lg'
                />
            );
        }

        return (
            <MenuWrapper className='AdminSidebarHeader'>

                    {profilePicture}

                            <FormattedMessage
                                id='admin.sidebarHeader.systemConsole'
                                defaultMessage='System Console'
                            />

{'@' + me.username}

                    <button className='style--none'>
                        <MenuIcon className='menu-icon'/>
                    </button>

                <AdminNavbarDropdown/>
            </MenuWrapper>
        );
    }


@Injectable()
export class ProfileService {

    constructor(
        private http: HttpClient,
        private _handleErrorService: HandleErrorService
    ) { }

    GetCurrent(): Observable<{}> {
        return this.http.get(environment.appBaseUrl + environment.apiBaseUrl + '/users/profile/current')
            .pipe(
                catchError(this._handleErrorService.handleError<any>('GetCurrentProfile'))
            );
    }

    Update(profile: any): Observable<{}> {
        return this.http.put(environment.appBaseUrl + environment.apiBaseUrl + '/users/profile/' + profile._id, profile)
            .pipe(
                catchError(this._handleErrorService.handleError<any>('UpdateProfile'))
            );
    }

}


GetCurrent(): Observable<{}> {
        return this.http.get(environment.appBaseUrl + environment.apiBaseUrl + '/users/profile/current')
            .pipe(
                catchError(this._handleErrorService.handleError<any>('GetCurrentProfile'))
            );
    }


Update(profile: any): Observable<{}> {
        return this.http.put(environment.appBaseUrl + environment.apiBaseUrl + '/users/profile/' + profile._id, profile)
            .pipe(
                catchError(this._handleErrorService.handleError<any>('UpdateProfile'))
            );
    }


export default function Category() {
  const { pathname } = useLocation()
  const { datoQuerySubscription } = useLoaderData()
  const { title, desc, sidebar }: Route = useNav(pathname)
  const prevRoute = usePrevRoute(pathname)

  const {
    data: { post, morePosts },
  } = useQuerySubscription(datoQuerySubscription)

  const paths = pathname ? pathname.split('/') : [null]
  const tabId = paths[paths.length - 1]
  const context: TabContextType = { post, tabId }
  const outlet = <Outlet context={context} />
  const props = {
    title: post?.title || title,
    Icon: post?.author ? <Avatar name={post.author.name} picture={post.author.picture} /> : <></>,
    desc: post?.excerpt || desc,
    prevRoute,
    cover: post?.coverImage ? <Image data={post.coverImage.responsiveImage} /> : <></>,
    date: post?.date ? <Date dateString={post.date} /> : <></>,
    categoryId: post?.category?.id,
    sidebar,
  }


async ({ request, params }: any) => {
  invariant(params.slug, 'expected params.slug')

  return datoQuerySubscription({
    request,
    query,
    variables: {
      slug: params.slug,
    },
  })
}


({
  data: {
    datoQuerySubscription: {
      initialData: { post },
    },
  },
}: any) => {
  return post?.seo ? toRemixMeta(post.seo) : []
}


post ? (
        <Post {...{ post, outlet, tabId, pathname, morePosts }}


export declare function fromAstNodes(astRules: cssParser.Node[]): RuleSet[];


export declare function createSelector(sel: string): SimpleSelector | SimpleSelectorSequence | Selector;


export declare abstract class SelectorCore {
    pos: number;
    specificity: number;
    rarity: Rarity;
    combinator: Combinator;
    ruleset: RuleSet;
    /**
     * Dynamic selectors depend on attributes and pseudo classes.
     */
    dynamic: boolean;
    abstract match(node: Node): boolean;
    /**
     * If the selector is static returns if it matches the node.
     * If the selector is dynamic returns if it may match the node, and accumulates any changes that may affect its state.
     */
    abstract accumulateChanges(node: Node, map: ChangeAccumulator): boolean;
    lookupSort(sorter: LookupSorter, base?: SelectorCore): void;
}


export declare abstract class SimpleSelector extends SelectorCore {
    accumulateChanges(node: Node, map?: ChangeAccumulator): boolean;
    mayMatch(node: Node): boolean;
    trackChanges(node: Node, map: ChangeAccumulator): void;
}


export declare class InvalidSelector extends SimpleSelector {
    e: Error;
    constructor(e: Error);
    toString(): string;
    match(node: Node): boolean;
    lookupSort(sorter: LookupSorter, base?: SelectorCore): void;
}


export declare class UniversalSelector extends SimpleSelector {
    toString(): string;
    match(node: Node): boolean;
}


export declare class IdSelector extends SimpleSelector {
    id: string;
    constructor(id: string);
    toString(): string;
    match(node: Node): boolean;
    lookupSort(sorter: LookupSorter, base?: SelectorCore): void;
}


export declare class TypeSelector extends SimpleSelector {
    cssType: string;
    constructor(cssType: string);
    toString(): string;
    match(node: Node): boolean;
    lookupSort(sorter: LookupSorter, base?: SelectorCore): void;
}


export declare class ClassSelector extends SimpleSelector {
    cssClass: string;
    constructor(cssClass: string);
    toString(): string;
    match(node: Node): boolean;
    lookupSort(sorter: LookupSorter, base?: SelectorCore): void;
}


export declare class AttributeSelector extends SimpleSelector {
    attribute: string;
    test?: AttributeTest;
    value?: string;
    constructor(attribute: string, test?: AttributeTest, value?: string);
    toString(): string;
    match(node: Node): boolean;
    mayMatch(node: Node): boolean;
    trackChanges(node: Node, map: ChangeAccumulator): void;
}


export declare class PseudoClassSelector extends SimpleSelector {
    cssPseudoClass: string;
    constructor(cssPseudoClass: string);
    toString(): string;
    match(node: Node): boolean;
    mayMatch(node: Node): boolean;
    trackChanges(node: Node, map: ChangeAccumulator): void;
}


export declare class SimpleSelectorSequence extends SimpleSelector {
    selectors: SimpleSelector[];
    private head;
    constructor(selectors: SimpleSelector[]);
    toString(): string;
    match(node: Node): boolean;
    mayMatch(node: Node): boolean;
    trackChanges(node: any, map: any): void;
    lookupSort(sorter: LookupSorter, base?: SelectorCore): void;
}


export declare class Selector extends SelectorCore {
    selectors: SimpleSelector[];
    private groups;
    private last;
    constructor(selectors: SimpleSelector[]);
    toString(): string;
    match(node: Node): boolean;
    lookupSort(sorter: LookupSorter, base?: SelectorCore): void;
    accumulateChanges(node: Node, map?: ChangeAccumulator): boolean;
}


class ChildGroup {
        private selectors;
        dynamic: boolean;
        constructor(selectors: SiblingGroup[]);
        match(node: Node): Node;
        mayMatch(node: Node): Node;
        trackChanges(node: Node, map: ChangeAccumulator): void;
    }


class SiblingGroup {
        private selectors;
        dynamic: boolean;
        constructor(selectors: SimpleSelector[]);
        match(node: Node): Node;
        mayMatch(node: Node): Node;
        trackChanges(node: Node, map: ChangeAccumulator): void;
    }


export declare class RuleSet {
    selectors: SelectorCore[];
    declarations: Declaration[];
    tag: string | number;
    scopedTag: string;
    constructor(selectors: SelectorCore[], declarations: Declaration[]);
    toString(): string;
    lookupSort(sorter: LookupSorter): void;
}


export declare class SelectorsMap<T extends Node> implements LookupSorter {
    private id;
    private class;
    private type;
    private universal;
    private position;
    constructor(rulesets: RuleSet[]);
    query(node: T): SelectorsMatch<T>;
    sortById(id: string, sel: SelectorCore): void;
    sortByClass(cssClass: string, sel: SelectorCore): void;
    sortByType(cssType: string, sel: SelectorCore): void;
    sortAsUniversal(sel: SelectorCore): void;
    private addToMap;
    private makeDocSelector;
}


export declare class SelectorsMatch<T extends Node> implements ChangeAccumulator {
    changeMap: ChangeMap<T>;
    selectors: any;
    addAttribute(node: T, attribute: string): void;
    addPseudoClass(node: T, pseudoClass: string): void;
    properties(node: T): Changes;
}


/**
 * An interface describing the shape of a type on which the selectors may apply.
 * Note, the ui/core/view.View implements Node.
 */
export interface Node {
    parent?: Node;
    id?: string;
    nodeName?: string;
    cssType?: string;
    cssClasses?: Set<string>;
    cssPseudoClasses?: Set<string>;
    getChildIndex?(node: Node): number;
    getChildAt?(index: number): Node;
}


export interface Declaration {
    property: string;
    value: string;
}


export interface Changes {
    attributes?: Set<string>;
    pseudoClasses?: Set<string>;
}


interface LookupSorter {
    sortById(id: string, sel: SelectorCore): any;
    sortByClass(cssClass: string, sel: SelectorCore): any;
    sortByType(cssType: string, sel: SelectorCore): any;
    sortAsUniversal(sel: SelectorCore): any;
}


interface Bound {
        left: Node;
        right: Node;
    }


interface ChangeAccumulator {
    addAttribute(node: Node, attribute: string): void;
    addPseudoClass(node: Node, pseudoClass: string): void;
}


declare const enum Rarity {
    Invalid = 4,
    Id = 3,
    Class = 2,
    Type = 1,
    PseudoClass = 0,
    Attribute = 0,
    Universal = 0,
    Inline = 0
}


export declare type ChangeMap<T extends Node> = Map<T, Changes>;


declare type Combinator = '+' | '>' | '~' | ' ';


declare type AttributeTest = '=' | '^=' | '$=' | '*=' | '=' | '~=' | '|=';


abstract match(node: Node): boolean;


/**
     * If the selector is static returns if it matches the node.
     * If the selector is dynamic returns if it may match the node, and accumulates any changes that may affect its state.
     */
abstract accumulateChanges(node: Node, map: ChangeAccumulator): boolean;


lookupSort(sorter: LookupSorter, base?: SelectorCore): void;


accumulateChanges(node: Node, map?: ChangeAccumulator): boolean;


mayMatch(node: Node): boolean;


trackChanges(node: Node, map: ChangeAccumulator): void;


match(node: Node): boolean;


trackChanges(node: any, map: any): void;


match(node: Node): Node;


mayMatch(node: Node): Node;


lookupSort(sorter: LookupSorter): void;


query(node: T): SelectorsMatch<T>;


sortById(id: string, sel: SelectorCore): void;


sortByClass(cssClass: string, sel: SelectorCore): void;


sortByType(cssType: string, sel: SelectorCore): void;


sortAsUniversal(sel: SelectorCore): void;


addAttribute(node: T, attribute: string): void;


addPseudoClass(node: T, pseudoClass: string): void;


properties(node: T): Changes;


export class ListUserProfilesCommand extends $Command<
  ListUserProfilesCommandInput,
  ListUserProfilesCommandOutput,
  SageMakerClientResolvedConfig
> {
  // Start section: command_properties
  // End section: command_properties

  constructor(readonly input: ListUserProfilesCommandInput) {
    // Start section: command_constructor
    super();
    // End section: command_constructor
  }

  resolveMiddleware(
    clientStack: MiddlewareStack<ServiceInputTypes, ServiceOutputTypes>,
    configuration: SageMakerClientResolvedConfig,
    options?: __HttpHandlerOptions
  ): Handler<ListUserProfilesCommandInput, ListUserProfilesCommandOutput> {
    this.middlewareStack.use(
      getSerdePlugin(configuration, this.serialize, this.deserialize)
    );

    const stack = clientStack.concat(this.middlewareStack);

    const handlerExecutionContext: HandlerExecutionContext = {
      logger: {} as any
    };
    const { requestHandler } = configuration;
    return stack.resolve(
      (request: FinalizeHandlerArguments<any>) =>
        requestHandler.handle(request.request as __HttpRequest, options || {}),
      handlerExecutionContext
    );
  }

  private serialize(
    input: ListUserProfilesCommandInput,
    context: __SerdeContext
  ): Promise<__HttpRequest> {
    return serializeAws_json1_1ListUserProfilesCommand(input, context);
  }

  private deserialize(
    output: __HttpResponse,
    context: __SerdeContext
  ): Promise<ListUserProfilesCommandOutput> {
    return deserializeAws_json1_1ListUserProfilesCommand(output, context);
  }

  // Start section: command_body_extra
  // End section: command_body_extra
}


export type ListUserProfilesCommandInput = ListUserProfilesRequest;


export type ListUserProfilesCommandOutput = ListUserProfilesResponse &
  __MetadataBearer;


resolveMiddleware(
    clientStack: MiddlewareStack<ServiceInputTypes, ServiceOutputTypes>,
    configuration: SageMakerClientResolvedConfig,
    options?: __HttpHandlerOptions
  ): Handler<ListUserProfilesCommandInput, ListUserProfilesCommandOutput> {
    this.middlewareStack.use(
      getSerdePlugin(configuration, this.serialize, this.deserialize)
    );

    const stack = clientStack.concat(this.middlewareStack);

    const handlerExecutionContext: HandlerExecutionContext = {
      logger: {} as any
    };
    const { requestHandler } = configuration;
    return stack.resolve(
      (request: FinalizeHandlerArguments<any>) =>
        requestHandler.handle(request.request as __HttpRequest, options || {}),
      handlerExecutionContext
    );
  }


private serialize(
    input: ListUserProfilesCommandInput,
    context: __SerdeContext
  ): Promise<__HttpRequest> {
    return serializeAws_json1_1ListUserProfilesCommand(input, context);
  }


private deserialize(
    output: __HttpResponse,
    context: __SerdeContext
  ): Promise<ListUserProfilesCommandOutput> {
    return deserializeAws_json1_1ListUserProfilesCommand(output, context);
  }