Insert(value: number)
    {
        this.inserted = true;
        Logger.Debug("VisualBinarySearchTree.Insert(" + value + ") : Enter");

        this.nodes.push(value);

        if (this.Root == null)
        {
            Logger.Debug("Inserting into Root" + value);
            this.Root = this.treeDesigner.GenerateRootNode(value);
        }
        else
        {
            var temp = this.Root;

            while (temp != null)
            {
                if (value > temp.Value)
                {
                    if (temp.Right == null)
                    {
                        Logger.Debug("Inserting Right" + value);
                        temp.Right = this.treeDesigner.GenerateRightNode(temp, value);
                        break;
                    }
                    else
                    {
                        temp = temp.Right;
                    }
                }
                else
                {
                    if (temp.Left == null)
                    {
                        Logger.Debug("Inserting Left" + value);
                        temp.Left = this.treeDesigner.GenerateLeftNode(temp, value);
                        break;
                    }
                    else
                    {
                        temp = temp.Left;
                    }
                }
            }
        }

        Logger.Debug("VisualBinarySearchTree.Insert() : Exit");
    }


PreOrder(root: VisualTreeNode)
    {
        Logger.Debug("VisualBinarySearchTree.PreOrder() : Enter");

        if (root != null)
        {
            this.PreOrder(root.Left);
            Logger.Debug(root.Value);
            Logger.Output(root.Value);
            this.treeDesigner.HighlightNode(null, root);
            this.PreOrder(root.Right);
        }

        Logger.Debug("VisualBinarySearchTree.PreOrder() : Exit");
    }


Search(value: number): boolean
    {
        this.searched = true;
        this.searchHeight = 0;
        Logger.Debug("VisualBinarySearchTree.Search(" + value + ") : Exit");

        var temp = this.Root;
        var found = false;

        this.treeDesigner.HighlightNode(null, temp);

        while (temp != null)
        {
            this.searchHeight += 1;

            if (value < temp.Value)
            {
                this.treeDesigner.HighlightNode(temp, temp.Left);
                temp = temp.Left;
            }
            else if (value > temp.Value)
            {
                this.treeDesigner.HighlightNode(temp, temp.Right);
                temp = temp.Right;
            }
            else
            {
                found = true;
                this.treeDesigner.HighlightNode(null, temp);
                break;
            }
        }

        Logger.Debug("VisualBinarySearchTree.Search(" + found + ") : Exit");

        return found;
    }


Delete(value: number)
    {
        this.deleted = true;
        Logger.Debug("VisualBinarySearchTree.Delete(" + value + ") : Enter");

        var temp = this.Root;
        var previous = null;
        var found = false;

        while (temp != null)
        {
            if (value < temp.Value)
            {
                previous = temp;
                temp = temp.Left;
            }
            else if (value > temp.Value)
            {
                previous = temp;
                temp = temp.Right;
            }
            else
            {
                found = true;
                break;
            }
        }

        // we don't delete root yet
        if (previous != null)
        {
            // deleting left node
            if (previous.Left != null && previous.Left.Value == temp.Value)
            {
                this.treeDesigner.HighlightOldConnection(previous, previous.Left);

                if (temp.Right != null)
                {
                    this.treeDesigner.HighlightNewConnection(previous, temp.Right);

                    // hold the deleted nodes left value
                    var left = temp.Left;

                    // assign the right node of the deleted node to the parent's left of deleted node.
                    previous.Left = temp.Right;

                    // temp storage for the new connection
                    var run = previous.Left;

                    // interate all the way to left until null
                    while (run.Left != null)
                    {
                        run = run.Left;
                    }

                    // assign the hanging node as the left node at empty spot
                    run.Left = left;

                    this.treeDesigner.HighlightNewConnection(left, run);
                }
                else
                {
                    previous.Left = temp.Left;
                    this.treeDesigner.HighlightNewConnection(previous, temp.Left);
                }
            }
            // deleting right node
            else if (previous.Right != null && previous.Right.Value == temp.Value)
            {
                this.treeDesigner.HighlightOldConnection(previous, previous.Right);

                if (temp.Right != null)
                {
                    this.treeDesigner.HighlightNewConnection(previous, temp.Right);

                    // hold the deleted nodes left value
                    var left = temp.Left;

                    // assign the right node of the deleted node to the parent's right of deleted node.
                    previous.Right = temp.Right;

                    // temp storage for the new connection
                    var run = previous.Right;

                    // interate all the way to left until null
                    while (run.Left != null)
                    {
                        run = run.Left;
                    }

                    // assign the hanging node as the left node at empty spot
                    run.Left = left;

                    this.treeDesigner.HighlightNewConnection(left, run);
                }
                else
                {
                    previous.Right = temp.Left;
                    this.treeDesigner.HighlightNewConnection(previous, temp.Left);
                }
            }
        }
        else
        {
            this.treeDesigner.HighlightOldConnection(null, temp);

            if (temp.Right == null)
            {
                this.Root = this.Root.Left;
            }
            else if (temp.Left == null)
            {
                this.Root = this.Root.Right;
            }
            else
            {
                // hold the deleted nodes left value
                var left = this.Root.Left;
                this.Root = this.Root.Right;

                temp = temp.Right

                // interate all the way to left until null
                while (temp.Left != null)
                {
                    temp = temp.Left;
                }

                // assign the hanging node as the left node at empty spot
                temp.Left = left;

                this.treeDesigner.HighlightNewConnection(temp, left);
            }
        }

        Logger.Debug("VisualBinarySearchTree.Delete() : Exit");
    }


RefreshStats()
    {
        Logger.Debug("VisualBinarySearchTree.RefreshStats() : Enter");

        if (this.inserted || this.deleted)
        {
            this.searchHeight = -1;
            this.inserted = false;
            this.deleted = false;
        }

        this.height = this.GetHeight(this.Root);
        this.diameter = this.GetDiameter(this.Root);

        CurrentStats.Height = this.height;
        CurrentStats.Diameter = this.diameter;
        CurrentStats.SearchHeight = this.searchHeight;

        CurrentStats.Refresh();

        Logger.Debug("VisualBinarySearchTree.RefreshStats() : Exit");
    }


private GetHeight(root: VisualTreeNode): number
    {
        if (root == null)
        {
            return 0;
        }
        else
        {
            return Math.max(this.GetHeight(root.Left), this.GetHeight(root.Right)) + 1;
        }
    }


private GetDiameter(root: VisualTreeNode): number
    {
        if (root == null)
        {
            return 0;
        }
        else
        {
            var leftHeight = this.GetHeight(root.Left);
            var rightHeight = this.GetHeight(root.Right);

            var leftDiameter = this.GetDiameter(root.Left);
            var rightDiameter = this.GetDiameter(root.Right);

            return Math.max(leftHeight + rightHeight + 1, leftDiameter, rightDiameter);
        }
    }


export function isUserNamespaceDefinition(definition: INamedDefinition): definition is UserFunctionNamespaceDefinition {
    return definition.definitionKind === DefinitionKind.Namespace;
}


() => {
            const membersResult: UserFunctionDefinition[] = [];

            const members: Json.ObjectValue | undefined = Json.asObjectValue(this._value.getPropertyValue(templateKeys.userFunctionMembers));
            if (members) {
                for (let member of members.properties) {
                    let name: Json.StringValue = member.nameValue;
                    let value = Json.asObjectValue(member.value);
                    if (value) {
                        let func = new UserFunctionDefinition(this.document, this, name, value, member.span);
                        membersResult.push(func);
                    }
                }
            }

            return membersResult;
        }


fd => fd.nameValue.toString().toLowerCase() === functionNameLC


md => getUserFunctionUsage(md, false)


mu => `* ${mu}`


/**
 * This class represents the definition of a user-defined namespace in a deployment template.
 */
export class UserFunctionNamespaceDefinition implements INamedDefinition {
    /* Example:

            "functions": [
                {  <----  call createIfValid on this object
                    "namespace": "contoso",
                    "members": {
                        "uniqueName": {
                            "parameters": [
                                {
                                    "name": "namePrefix",
                                    "type": "string"
                                }
                            ],
                            "output": {
                            "type": "string",
                            "value": "[concat(toLower(parameters('namePrefix')), uniqueString(resourceGroup().id))]"
                            }
                        }
                    }
                }
            ],
        */

    public readonly definitionKind: DefinitionKind = DefinitionKind.Namespace;

    private _members: CachedValue<UserFunctionDefinition[]> = new CachedValue<UserFunctionDefinition[]>();

    private constructor(
        public readonly document: IJsonDocument,
        public readonly nameValue: Json.StringValue,
        private readonly _value: Json.ObjectValue
    ) {
        assert(_value);
    }

    public static createIfValid(document: IJsonDocument, functionValue: Json.ObjectValue): UserFunctionNamespaceDefinition | undefined {
        let nameValue: Json.StringValue | undefined = Json.asStringValue(functionValue.getPropertyValue("namespace"));
        if (nameValue) {
            return new UserFunctionNamespaceDefinition(document, nameValue, functionValue);
        }

        return undefined;
    }

    /**
     * Convenient way of seeing what this object represents in the debugger, shouldn't be used for production code
     */
    public get __debugDisplay(): string {
        return this.nameValue.unquotedValue;
    }

    public get span(): language.Span {
        return this._value.span;
    }

    public get members(): UserFunctionDefinition[] {
        return this._members.getOrCacheValue(() => {
            const membersResult: UserFunctionDefinition[] = [];

            const members: Json.ObjectValue | undefined = Json.asObjectValue(this._value.getPropertyValue(templateKeys.userFunctionMembers));
            if (members) {
                for (let member of members.properties) {
                    let name: Json.StringValue = member.nameValue;
                    let value = Json.asObjectValue(member.value);
                    if (value) {
                        let func = new UserFunctionDefinition(this.document, this, name, value, member.span);
                        membersResult.push(func);
                    }
                }
            }

            return membersResult;
        });
    }

    public getMemberDefinition(functionName: string): UserFunctionDefinition | undefined {
        if (functionName) {
            let functionNameLC = functionName.toLowerCase();
            return this.members.find(fd => fd.nameValue.toString().toLowerCase() === functionNameLC);
        } else {
            return undefined;
        }
    }

    public get usageInfo(): IUsageInfo {
        const ns = this.nameValue.unquotedValue;
        const methodsUsage: string[] = this.members
            .map(md => getUserFunctionUsage(md, false));
        let description: string | undefined;
        if (methodsUsage.length > 0) {
            description = `Members:${os.EOL}${methodsUsage.map(mu => `* ${mu}`).join(os.EOL)}`;
        } else {
            description = `No members`;
        }

        return {
            usage: ns,
            friendlyType: "user-defined namespace",
            description // CONSIDER: retrieve description from metadata, if supported
        };
    }
}


public static createIfValid(document: IJsonDocument, functionValue: Json.ObjectValue): UserFunctionNamespaceDefinition | undefined {
        let nameValue: Json.StringValue | undefined = Json.asStringValue(functionValue.getPropertyValue("namespace"));
        if (nameValue) {
            return new UserFunctionNamespaceDefinition(document, nameValue, functionValue);
        }

        return undefined;
    }


public getMemberDefinition(functionName: string): UserFunctionDefinition | undefined {
        if (functionName) {
            let functionNameLC = functionName.toLowerCase();
            return this.members.find(fd => fd.nameValue.toString().toLowerCase() === functionNameLC);
        } else {
            return undefined;
        }
    }


() =>
                    $scope.showMarkAllAudioAsNeedingUpdateModalIfRequired


(stateData) => {
                  if (stateData === undefined || $.isEmptyObject(stateData)) {
                    throw new Error(
                      'Expected stateData to be defined but ' +
                      'received ' + stateData);
                  }
                  $scope.hasLoaded = false;
                  InteractionDetailsCacheService.reset();
                  ResponsesService.onInitializeAnswerGroups.emit({
                    interactionId: stateData.interaction.id,
                    answerGroups: stateData.interaction.answerGroups,
                    defaultOutcome: stateData.interaction.defaultOutcome,
                    confirmedUnclassifiedAnswers: (
                      stateData.interaction.confirmedUnclassifiedAnswers)
                  });

                  _updateInteractionPreview();
                  _updateAnswerChoices();
                  $scope.hasLoaded = true;
                }


/*
 * Copyright 2018-2022 adorsys GmbH & Co KG
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or (at
 * your option) any later version. This program is distributed in the hope that
 * it will be useful, but WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see https://www.gnu.org/licenses/.
 *
 * This project is also available under a separate commercial license. You can
 * contact us at psd2@adorsys.com.
 */
/* tslint:disable */
export interface ResetPassword {
  code?: string;
  email?: string;
  login?: string;
  newPassword?: string;
  phone?: string;
}


(val: string): string => {
  switch (val) {
    case '10':
      return '100%';
    case '8':
      return '80%';
    case '6':
      return '60%';
    case '4':
      return '40%';
    case '2':
      return '20%';
    case '0':
      return '0%';
    default:
      return '';
  }
}


() => {
  const [baseInfoData, setBaseInfoData] = useState<any>([]);
  const [memUsage, setMemUsage] = useState<any>([]);
  const [memUsageTitle, setMemUsageTitle] = useState<any>([]);
  const [cmdInfoData, setCmdInfoData] = useState<VisitDataType[]>([]);

  useEffect(() => {
    getCacheInfo().then((res: CacheInfoResponseType) => {
      if (res.code === 200) {
        const baseinfo = [];
        baseinfo.push({
          col1: 'Redis版本',
          col2: res.data.info.redis_version,
          col3: '运行模式',
          col4: res.data.info.redis_mode === 'standalone' ? '单机' : '集群',
          col5: '端口',
          col6: res.data.info.tcp_port,
          col7: '客户端数',
          col8: res.data.info.connected_clients,
        });
        baseinfo.push({
          col1: '运行时间(天)',
          col2: res.data.info.uptime_in_days,
          col3: '使用内存',
          col4: res.data.info.used_memory_human,
          col5: '使用CPU',
          col6: `${res.data.info.used_cpu_user_children}%`,
          col7: '内存配置',
          col8: res.data.info.maxmemory_human,
        });
        baseinfo.push({
          col1: 'AOF是否开启',
          col2: res.data.info.aof_enabled === '0' ? '否' : '是',
          col3: 'RDB是否成功',
          col4: res.data.info.rdb_last_bgsave_status,
          col5: 'Key数量',
          col6: res.data.dbSize,
          col7: '网络入口/出口',
          col8: `${res.data.info.instantaneous_input_kbps}/${res.data.info.instantaneous_output_kbps}kps`,
        });
        setBaseInfoData(baseinfo);

        const data: VisitDataType[] = res.data.commandStats.map((item) => {
          return {
            x: item.name,
            y: Number(item.value),
          };
        });

        setCmdInfoData(data);
        setMemUsageTitle(res.data.info.used_memory_human);
        setMemUsage(res.data.info.used_memory / res.data.info.total_system_memory);
      }
    });
  }, []);

  return (
    <Content>
      <Row gutter={[24, 24]}>
        <Col span={24}>
          <Card title="基本信息" className={styles.card}>
            <Table
              pagination={false}
              showHeader={false}
              dataSource={baseInfoData}
              columns={columns}
            />
          </Card>
        </Col>
      </Row>
      <Row gutter={[24, 24]}>
        <Col span={12}>
          <Card title="命令统计" className={styles.card}>
            <Pie hasLegend data={cmdInfoData} height={320} lineWidth={4} />
          </Card>
        </Col>
        <Col span={12}>
          <Card title="内存信息" className={styles.card}>
            <Gauge
              title={memUsageTitle}
              height={320}
              percent={memUsage}
              formatter={usageFormatter}
            />
          </Card>
        </Col>
      </Row>
    </Content>


() => {
    getCacheInfo().then((res: CacheInfoResponseType) => {
      if (res.code === 200) {
        const baseinfo = [];
        baseinfo.push({
          col1: 'Redis版本',
          col2: res.data.info.redis_version,
          col3: '运行模式',
          col4: res.data.info.redis_mode === 'standalone' ? '单机' : '集群',
          col5: '端口',
          col6: res.data.info.tcp_port,
          col7: '客户端数',
          col8: res.data.info.connected_clients,
        });
        baseinfo.push({
          col1: '运行时间(天)',
          col2: res.data.info.uptime_in_days,
          col3: '使用内存',
          col4: res.data.info.used_memory_human,
          col5: '使用CPU',
          col6: `${res.data.info.used_cpu_user_children}%`,
          col7: '内存配置',
          col8: res.data.info.maxmemory_human,
        });
        baseinfo.push({
          col1: 'AOF是否开启',
          col2: res.data.info.aof_enabled === '0' ? '否' : '是',
          col3: 'RDB是否成功',
          col4: res.data.info.rdb_last_bgsave_status,
          col5: 'Key数量',
          col6: res.data.dbSize,
          col7: '网络入口/出口',
          col8: `${res.data.info.instantaneous_input_kbps}/${res.data.info.instantaneous_output_kbps}kps`,
        });
        setBaseInfoData(baseinfo);

        const data: VisitDataType[] = res.data.commandStats.map((item) => {
          return {
            x: item.name,
            y: Number(item.value),
          };
        });

        setCmdInfoData(data);
        setMemUsageTitle(res.data.info.used_memory_human);
        setMemUsage(res.data.info.used_memory / res.data.info.total_system_memory);
      }
    });
  }


(res: CacheInfoResponseType) => {
      if (res.code === 200) {
        const baseinfo = [];
        baseinfo.push({
          col1: 'Redis版本',
          col2: res.data.info.redis_version,
          col3: '运行模式',
          col4: res.data.info.redis_mode === 'standalone' ? '单机' : '集群',
          col5: '端口',
          col6: res.data.info.tcp_port,
          col7: '客户端数',
          col8: res.data.info.connected_clients,
        });
        baseinfo.push({
          col1: '运行时间(天)',
          col2: res.data.info.uptime_in_days,
          col3: '使用内存',
          col4: res.data.info.used_memory_human,
          col5: '使用CPU',
          col6: `${res.data.info.used_cpu_user_children}%`,
          col7: '内存配置',
          col8: res.data.info.maxmemory_human,
        });
        baseinfo.push({
          col1: 'AOF是否开启',
          col2: res.data.info.aof_enabled === '0' ? '否' : '是',
          col3: 'RDB是否成功',
          col4: res.data.info.rdb_last_bgsave_status,
          col5: 'Key数量',
          col6: res.data.dbSize,
          col7: '网络入口/出口',
          col8: `${res.data.info.instantaneous_input_kbps}/${res.data.info.instantaneous_output_kbps}kps`,
        });
        setBaseInfoData(baseinfo);

        const data: VisitDataType[] = res.data.commandStats.map((item) => {
          return {
            x: item.name,
            y: Number(item.value),
          };
        });

        setCmdInfoData(data);
        setMemUsageTitle(res.data.info.used_memory_human);
        setMemUsage(res.data.info.used_memory / res.data.info.total_system_memory);
      }
    }


(item) => {
          return {
            x: item.name,
            y: Number(item.value),
          };
        }


function clear_display() {
        display_element.innerHTML = "";
      }


// helper function for determining stimulus locations
function cosd(num: number) {
      return Math.cos((num / 180) * Math.PI);
    }


function sind(num: number) {
      return Math.sin((num / 180) * Math.PI);
    }


() => {
      // show fixation
      //var fixation = paper.image(trial.fixation_image, fix_loc[0], fix_loc[1], trial.fixation_size[0], trial.fixation_size[1]);
      paper.innerHTML +=
        "";

      // wait
      this.jsPsych.pluginAPI.setTimeout(() => {
        // after wait is over
        show_search_array();
      }, trial.fixation_duration);
    }


() => {
        // after wait is over
        show_search_array();
      }


(rt: number, correct: boolean, key_press: string) => {
      // data saving
      var trial_data = {
        correct: correct,
        rt: rt,
        response: key_press,
        locations: display_locs,
        target_present: trial.target_present,
        set_size: trial.set_size,
      };

      // go to next trial
      this.jsPsych.finishTrial(trial_data);
    }


() => {
      for (var i = 0; i < display_locs.length; i++) {
        paper.innerHTML +=
          "";
      }

      var trial_over = false;

      const after_response = (info: { key: string; rt: number }) => {
        trial_over = true;

        var correct = false;

        if (
          (this.jsPsych.pluginAPI.compareKeys(info.key, trial.target_present_key) &&
            trial.target_present) ||
          (this.jsPsych.pluginAPI.compareKeys(info.key, trial.target_absent_key) &&
            !trial.target_present)
        ) {
          correct = true;
        }

        clear_display();

        end_trial(info.rt, correct, info.key);
      };

      var valid_keys = [trial.target_present_key, trial.target_absent_key];

      const key_listener = this.jsPsych.pluginAPI.getKeyboardResponse({
        callback_function: after_response,
        valid_responses: valid_keys,
        rt_method: "performance",
        persist: false,
        allow_held_key: false,
      });

      if (trial.trial_duration !== null) {
        this.jsPsych.pluginAPI.setTimeout(() => {
          if (!trial_over) {
            this.jsPsych.pluginAPI.cancelKeyboardResponse(key_listener);

            trial_over = true;

            var rt = null;
            var correct = false;
            var key_press = null;

            clear_display();

            end_trial(rt, correct, key_press);
          }
        }, trial.trial_duration);
      }

      function clear_display() {
        display_element.innerHTML = "";
      }
    }


(info: { key: string; rt: number }) => {
        trial_over = true;

        var correct = false;

        if (
          (this.jsPsych.pluginAPI.compareKeys(info.key, trial.target_present_key) &&
            trial.target_present) ||
          (this.jsPsych.pluginAPI.compareKeys(info.key, trial.target_absent_key) &&
            !trial.target_present)
        ) {
          correct = true;
        }

        clear_display();

        end_trial(info.rt, correct, info.key);
      }


() => {
          if (!trial_over) {
            this.jsPsych.pluginAPI.cancelKeyboardResponse(key_listener);

            trial_over = true;

            var rt = null;
            var correct = false;
            var key_press = null;

            clear_display();

            end_trial(rt, correct, key_press);
          }
        }


/**
 * **visual-search-circle**
 *
 * jsPsych plugin to display a set of objects, with or without a target, equidistant from fixation.
 * Subject responds with key press to whether or not the target is present.
 * Based on code written for psychtoolbox by Ben Motz.
 *
 * @author Josh de Leeuw
 * @see {@link https://www.jspsych.org/plugins/jspsych-visual-search-circle/ visual-search-circle plugin documentation on jspsych.org}
 **/
class VisualSearchCirclePlugin implements JsPsychPlugin<Info> {
  static info = info;

  constructor(private jsPsych: JsPsych) {}

  trial(display_element: HTMLElement, trial: TrialType<Info>) {
    // circle params
    var diam = trial.circle_diameter; // pixels
    var radi = diam / 2;
    var paper_size = diam + trial.target_size[0];

    // stimuli width, height
    var stimh = trial.target_size[0];
    var stimw = trial.target_size[1];
    var hstimh = stimh / 2;
    var hstimw = stimw / 2;

    // fixation location
    var fix_loc = [
      Math.floor(paper_size / 2 - trial.fixation_size[0] / 2),
      Math.floor(paper_size / 2 - trial.fixation_size[1] / 2),
    ];

    // check for correct combination of parameters and create stimuli set
    var possible_display_locs: number;
    var to_present = [];
    if (trial.target !== null && trial.foil !== null && trial.set_size !== null) {
      possible_display_locs = trial.set_size;
      if (trial.target_present) {
        for (var i = 0; i < trial.set_size - 1; i++) {
          to_present.push(trial.foil);
        }
        to_present.push(trial.target);
      } else {
        for (var i = 0; i < trial.set_size; i++) {
          to_present.push(trial.foil);
        }
      }
    } else if (trial.stimuli !== null) {
      possible_display_locs = trial.stimuli.length;
      to_present = trial.stimuli;
    } else {
      console.error(
        "Error in visual-search-circle plugin: you must specify an array of images via the stimuli parameter OR specify the target, foil and set_size parameters."
      );
    }

    // possible stimulus locations on the circle
    var display_locs = [];
    var random_offset = Math.floor(Math.random() * 360);
    for (var i = 0; i < possible_display_locs; i++) {
      display_locs.push([
        Math.floor(
          paper_size / 2 + cosd(random_offset + i * (360 / possible_display_locs)) * radi - hstimw
        ),
        Math.floor(
          paper_size / 2 - sind(random_offset + i * (360 / possible_display_locs)) * radi - hstimh
        ),
      ]);
    }

    // get target to draw on
    display_element.innerHTML +=
      '

';
    var paper = display_element.querySelector("#jspsych-visual-search-circle-container");

    const show_fixation = () => {
      // show fixation
      //var fixation = paper.image(trial.fixation_image, fix_loc[0], fix_loc[1], trial.fixation_size[0], trial.fixation_size[1]);
      paper.innerHTML +=
        "";

      // wait
      this.jsPsych.pluginAPI.setTimeout(() => {
        // after wait is over
        show_search_array();
      }, trial.fixation_duration);
    };

    const end_trial = (rt: number, correct: boolean, key_press: string) => {
      // data saving
      var trial_data = {
        correct: correct,
        rt: rt,
        response: key_press,
        locations: display_locs,
        target_present: trial.target_present,
        set_size: trial.set_size,
      };

      // go to next trial
      this.jsPsych.finishTrial(trial_data);
    };

    show_fixation();

    const show_search_array = () => {
      for (var i = 0; i < display_locs.length; i++) {
        paper.innerHTML +=
          "";
      }

      var trial_over = false;

      const after_response = (info: { key: string; rt: number }) => {
        trial_over = true;

        var correct = false;

        if (
          (this.jsPsych.pluginAPI.compareKeys(info.key, trial.target_present_key) &&
            trial.target_present) ||
          (this.jsPsych.pluginAPI.compareKeys(info.key, trial.target_absent_key) &&
            !trial.target_present)
        ) {
          correct = true;
        }

        clear_display();

        end_trial(info.rt, correct, info.key);
      };

      var valid_keys = [trial.target_present_key, trial.target_absent_key];

      const key_listener = this.jsPsych.pluginAPI.getKeyboardResponse({
        callback_function: after_response,
        valid_responses: valid_keys,
        rt_method: "performance",
        persist: false,
        allow_held_key: false,
      });

      if (trial.trial_duration !== null) {
        this.jsPsych.pluginAPI.setTimeout(() => {
          if (!trial_over) {
            this.jsPsych.pluginAPI.cancelKeyboardResponse(key_listener);

            trial_over = true;

            var rt = null;
            var correct = false;
            var key_press = null;

            clear_display();

            end_trial(rt, correct, key_press);
          }
        }, trial.trial_duration);
      }

      function clear_display() {
        display_element.innerHTML = "";
      }
    };

    // helper function for determining stimulus locations
    function cosd(num: number) {
      return Math.cos((num / 180) * Math.PI);
    }

    function sind(num: number) {
      return Math.sin((num / 180) * Math.PI);
    }
  }
}


type Info = typeof info;


trial(display_element: HTMLElement, trial: TrialType<Info>) {
    // circle params
    var diam = trial.circle_diameter; // pixels
    var radi = diam / 2;
    var paper_size = diam + trial.target_size[0];

    // stimuli width, height
    var stimh = trial.target_size[0];
    var stimw = trial.target_size[1];
    var hstimh = stimh / 2;
    var hstimw = stimw / 2;

    // fixation location
    var fix_loc = [
      Math.floor(paper_size / 2 - trial.fixation_size[0] / 2),
      Math.floor(paper_size / 2 - trial.fixation_size[1] / 2),
    ];

    // check for correct combination of parameters and create stimuli set
    var possible_display_locs: number;
    var to_present = [];
    if (trial.target !== null && trial.foil !== null && trial.set_size !== null) {
      possible_display_locs = trial.set_size;
      if (trial.target_present) {
        for (var i = 0; i < trial.set_size - 1; i++) {
          to_present.push(trial.foil);
        }
        to_present.push(trial.target);
      } else {
        for (var i = 0; i < trial.set_size; i++) {
          to_present.push(trial.foil);
        }
      }
    } else if (trial.stimuli !== null) {
      possible_display_locs = trial.stimuli.length;
      to_present = trial.stimuli;
    } else {
      console.error(
        "Error in visual-search-circle plugin: you must specify an array of images via the stimuli parameter OR specify the target, foil and set_size parameters."
      );
    }

    // possible stimulus locations on the circle
    var display_locs = [];
    var random_offset = Math.floor(Math.random() * 360);
    for (var i = 0; i < possible_display_locs; i++) {
      display_locs.push([
        Math.floor(
          paper_size / 2 + cosd(random_offset + i * (360 / possible_display_locs)) * radi - hstimw
        ),
        Math.floor(
          paper_size / 2 - sind(random_offset + i * (360 / possible_display_locs)) * radi - hstimh
        ),
      ]);
    }

    // get target to draw on
    display_element.innerHTML +=
      '

';
    var paper = display_element.querySelector("#jspsych-visual-search-circle-container");

    const show_fixation = () => {
      // show fixation
      //var fixation = paper.image(trial.fixation_image, fix_loc[0], fix_loc[1], trial.fixation_size[0], trial.fixation_size[1]);
      paper.innerHTML +=
        "";

      // wait
      this.jsPsych.pluginAPI.setTimeout(() => {
        // after wait is over
        show_search_array();
      }, trial.fixation_duration);
    };

    const end_trial = (rt: number, correct: boolean, key_press: string) => {
      // data saving
      var trial_data = {
        correct: correct,
        rt: rt,
        response: key_press,
        locations: display_locs,
        target_present: trial.target_present,
        set_size: trial.set_size,
      };

      // go to next trial
      this.jsPsych.finishTrial(trial_data);
    };

    show_fixation();

    const show_search_array = () => {
      for (var i = 0; i < display_locs.length; i++) {
        paper.innerHTML +=
          "";
      }

      var trial_over = false;

      const after_response = (info: { key: string; rt: number }) => {
        trial_over = true;

        var correct = false;

        if (
          (this.jsPsych.pluginAPI.compareKeys(info.key, trial.target_present_key) &&
            trial.target_present) ||
          (this.jsPsych.pluginAPI.compareKeys(info.key, trial.target_absent_key) &&
            !trial.target_present)
        ) {
          correct = true;
        }

        clear_display();

        end_trial(info.rt, correct, info.key);
      };

      var valid_keys = [trial.target_present_key, trial.target_absent_key];

      const key_listener = this.jsPsych.pluginAPI.getKeyboardResponse({
        callback_function: after_response,
        valid_responses: valid_keys,
        rt_method: "performance",
        persist: false,
        allow_held_key: false,
      });

      if (trial.trial_duration !== null) {
        this.jsPsych.pluginAPI.setTimeout(() => {
          if (!trial_over) {
            this.jsPsych.pluginAPI.cancelKeyboardResponse(key_listener);

            trial_over = true;

            var rt = null;
            var correct = false;
            var key_press = null;

            clear_display();

            end_trial(rt, correct, key_press);
          }
        }, trial.trial_duration);
      }

      function clear_display() {
        display_element.innerHTML = "";
      }
    };

    // helper function for determining stimulus locations
    function cosd(num: number) {
      return Math.cos((num / 180) * Math.PI);
    }

    function sind(num: number) {
      return Math.sin((num / 180) * Math.PI);
    }
  }


async () => {
  return { hello: 'world' }
}


async function sleep(ms: number = 0) {
  return new Promise(resolve => {
    setTimeout(resolve, ms);
  });
}


function waitUntil(predicate: () => boolean) {
  return new Promise<void>(async resolve => {
    let notFound = true;
    let tries = 5;
    while (notFound || tries-- > 0) {
      await sleep(50);
      notFound = !predicate();
    }
    resolve();
  });
}


resolve => {
    setTimeout(resolve, ms);
  }


async resolve => {
    let notFound = true;
    let tries = 5;
    while (notFound || tries-- > 0) {
      await sleep(50);
      notFound = !predicate();
    }
    resolve();
  }


() => {
  let sandbox: sinon.SinonSandbox;
  let workspacePath: string;
  let soqlFileUri: Uri;
  const encoder = new TextEncoder();
  let mockConnection: MockConnection;

  beforeEach(async () => {
    sandbox = sinon.createSandbox();
    mockConnection = stubMockConnection(sandbox);
    workspacePath = workspace.workspaceFolders![0].uri.fsPath;
    soqlFileUri = Uri.file(path.join(workspacePath, 'test.soql'));
    const ext = extensions.getExtension('salesforce.salesforcedx-vscode-soql')!;
    await ext.activate();
    clearDiagnostics();
  });

  afterEach(async () => {
    sandbox.restore();
    await workspace.fs.delete(soqlFileUri);
  });

  it('should show diagnostics for syntax error', async () => {
    await workspace.fs.writeFile(
      soqlFileUri,
      encoder.encode(`
      SELECT Id
      FRM Account
    `)
    );
    await window.showTextDocument(soqlFileUri);

    const diagnostics = languages.getDiagnostics(soqlFileUri);
    expect(diagnostics)
      .to.be.an('array')
      .to.have.lengthOf(1);
    expect(diagnostics[0].message).to.equal(`missing 'from' at 'Account'`);
  });

  it('should create diagnostics based off of limit 0 execute error results', async () => {
    const expectedError = `SELECT Ids FROM ACCOUNT\nERROR at Row:1:Column:8\nSome error at 'Ids'`;
    await workspace.fs.writeFile(
      soqlFileUri,
      encoder.encode(`
      SELECT Ids
      FROM Account
    `)
    );

    sandbox.stub(mockConnection, 'query').throws({
      name: 'INVALID_FIELD',
      errorCode: 'INVALID_FIELD',
      message: expectedError
    });

    await window.showTextDocument(soqlFileUri);

    await waitUntil(() => {
      return languages.getDiagnostics(soqlFileUri).length > 0;
    });
    const diagnostics = languages.getDiagnostics(soqlFileUri);
    expect(diagnostics)
      .to.be.an('array')
      .to.have.lengthOf(1);
    expect(diagnostics[0].message).to.equal(expectedError);
    expect(diagnostics[0].range.start.line).to.equal(0, 'range start line');
    expect(diagnostics[0].range.start.character).to.equal(
      7,
      'range start char'
    );
    expect(diagnostics[0].range.end.line).to.equal(0, 'range end line');
    expect(diagnostics[0].range.end.character).to.equal(10, 'range end char');
  });
}


async () => {
    sandbox = sinon.createSandbox();
    mockConnection = stubMockConnection(sandbox);
    workspacePath = workspace.workspaceFolders![0].uri.fsPath;
    soqlFileUri = Uri.file(path.join(workspacePath, 'test.soql'));
    const ext = extensions.getExtension('salesforce.salesforcedx-vscode-soql')!;
    await ext.activate();
    clearDiagnostics();
  }


async () => {
    sandbox.restore();
    await workspace.fs.delete(soqlFileUri);
  }


async () => {
    await workspace.fs.writeFile(
      soqlFileUri,
      encoder.encode(`
      SELECT Id
      FRM Account
    `)
    );
    await window.showTextDocument(soqlFileUri);

    const diagnostics = languages.getDiagnostics(soqlFileUri);
    expect(diagnostics)
      .to.be.an('array')
      .to.have.lengthOf(1);
    expect(diagnostics[0].message).to.equal(`missing 'from' at 'Account'`);
  }


async () => {
    const expectedError = `SELECT Ids FROM ACCOUNT\nERROR at Row:1:Column:8\nSome error at 'Ids'`;
    await workspace.fs.writeFile(
      soqlFileUri,
      encoder.encode(`
      SELECT Ids
      FROM Account
    `)
    );

    sandbox.stub(mockConnection, 'query').throws({
      name: 'INVALID_FIELD',
      errorCode: 'INVALID_FIELD',
      message: expectedError
    });

    await window.showTextDocument(soqlFileUri);

    await waitUntil(() => {
      return languages.getDiagnostics(soqlFileUri).length > 0;
    });
    const diagnostics = languages.getDiagnostics(soqlFileUri);
    expect(diagnostics)
      .to.be.an('array')
      .to.have.lengthOf(1);
    expect(diagnostics[0].message).to.equal(expectedError);
    expect(diagnostics[0].range.start.line).to.equal(0, 'range start line');
    expect(diagnostics[0].range.start.character).to.equal(
      7,
      'range start char'
    );
    expect(diagnostics[0].range.end.line).to.equal(0, 'range end line');
    expect(diagnostics[0].range.end.character).to.equal(10, 'range end char');
  }


() => {
      return languages.getDiagnostics(soqlFileUri).length > 0;
    }


export declare function outputLayer(boxPredictions: tf.Tensor4D, classPredictions: tf.Tensor4D, params: OutputLayerParams): {
    boxes: tf.Tensor2D[];
    scores: tf.Tensor1D[];
};


() => {
  const mockConventionalRecommendedBump =
    conventionalRecommendedBump as jest.MockedFunction<
      typeof conventionalRecommendedBump
    >;
  const mockGetLastVersion = getLastVersion as jest.MockedFunction<
    typeof getLastVersion
  >;
  const mockGetCommits = getCommits as jest.MockedFunction<typeof getCommits>;
  const mockGetFirstCommitRef = getFirstCommitRef as jest.MockedFunction<
    typeof getFirstCommitRef
  >;

  let loggerSpy: jest.SpyInstance;

  beforeEach(() => {
    mockGetLastVersion.mockReturnValue(of('2.1.0'));
    loggerSpy = jest.spyOn(logger, 'warn');
  });

  afterEach(() => {
    jest.resetAllMocks();
  });

  it('should compute next version based on last version and changes', async () => {
    mockGetCommits.mockReturnValue(of(['feat: A', 'feat: B']));
    /* Mock bump to return "minor". */
    mockConventionalRecommendedBump.mockImplementation(
      callbackify(
        jest.fn().mockResolvedValue({
          releaseType: 'minor',
        })
      ) as () => void
    );

    const newVersion = await lastValueFrom(
      tryBump({
        preset: 'angular',
        projectRoot: '/libs/demo',
        tagPrefix: 'v',
        releaseType: undefined,
        preid: undefined,
      })
    );

    expect(newVersion).toEqual('2.2.0');

    expect(mockGetCommits).toBeCalledTimes(1);
    expect(mockGetCommits).toBeCalledWith({
      projectRoot: '/libs/demo',
      since: 'v2.1.0',
    });

    expect(mockConventionalRecommendedBump).toBeCalledTimes(1);
    expect(mockConventionalRecommendedBump).toBeCalledWith(
      {
        path: '/libs/demo',
        preset: 'angular',
        tagPrefix: 'v',
      },
      expect.any(Function)
    );
  });

  it('should use given type to calculate next version', async () => {
    mockGetCommits.mockReturnValue(of(['feat: A', 'feat: B']));

    const newVersion = await lastValueFrom(tryBump({
      preset: 'angular',
      projectRoot: '/libs/demo',
      tagPrefix: 'v',
      releaseType: 'premajor',
      preid: 'alpha',
    }));

    expect(newVersion).toEqual('3.0.0-alpha.0');

    expect(mockConventionalRecommendedBump).not.toBeCalled();

    expect(mockGetCommits).toBeCalledTimes(1);
    expect(mockGetCommits).toBeCalledWith({
      projectRoot: '/libs/demo',
      since: 'v2.1.0',
    });
  });

  it('should use given type to calculate next version even if there are no changes', async () => {
    mockGetCommits.mockReturnValue(of([]));

    const newVersion = await lastValueFrom(
      tryBump({
        preset: 'angular',
        projectRoot: '/libs/demo',
        tagPrefix: 'v',
        releaseType: 'patch',
      })
    );

    expect(newVersion).toEqual('2.1.1');

    expect(mockConventionalRecommendedBump).not.toBeCalled();
  });

  it('should call getFirstCommitRef if version is 0.0.0', async () => {
    mockGetLastVersion.mockReturnValue(throwError(() => 'No version found'));
    mockGetCommits.mockReturnValue(of([]));
    mockGetFirstCommitRef.mockReturnValue(of('sha1'));

    await lastValueFrom(
      tryBump({
        preset: 'angular',
        projectRoot: '/libs/demo',
        tagPrefix: 'v'
      })
    );

    expect(loggerSpy).toBeCalledWith(
      expect.stringContaining('No previous version tag found')
    );
    expect(mockGetCommits).toBeCalledTimes(1);
    expect(mockGetCommits).toBeCalledWith({
      projectRoot: '/libs/demo',
      since: 'sha1',
    });
  });

  it('should return undefined if there are no changes in current path', async () => {
    mockGetCommits.mockReturnValue(of([]));

    const newVersion = await lastValueFrom(
      tryBump({
        preset: 'angular',
        projectRoot: '/libs/demo',
        tagPrefix: 'v',
      })
    );

    expect(newVersion).toBeUndefined();

    expect(mockGetCommits).toBeCalledWith({
      projectRoot: '/libs/demo',
      since: 'v2.1.0',
    });
  });
}


() => {
    mockGetLastVersion.mockReturnValue(of('2.1.0'));
    loggerSpy = jest.spyOn(logger, 'warn');
  }


async () => {
    mockGetCommits.mockReturnValue(of(['feat: A', 'feat: B']));
    /* Mock bump to return "minor". */
    mockConventionalRecommendedBump.mockImplementation(
      callbackify(
        jest.fn().mockResolvedValue({
          releaseType: 'minor',
        })
      ) as () => void
    );

    const newVersion = await lastValueFrom(
      tryBump({
        preset: 'angular',
        projectRoot: '/libs/demo',
        tagPrefix: 'v',
        releaseType: undefined,
        preid: undefined,
      })
    );

    expect(newVersion).toEqual('2.2.0');

    expect(mockGetCommits).toBeCalledTimes(1);
    expect(mockGetCommits).toBeCalledWith({
      projectRoot: '/libs/demo',
      since: 'v2.1.0',
    });

    expect(mockConventionalRecommendedBump).toBeCalledTimes(1);
    expect(mockConventionalRecommendedBump).toBeCalledWith(
      {
        path: '/libs/demo',
        preset: 'angular',
        tagPrefix: 'v',
      },
      expect.any(Function)
    );
  }


async () => {
    mockGetCommits.mockReturnValue(of(['feat: A', 'feat: B']));

    const newVersion = await lastValueFrom(tryBump({
      preset: 'angular',
      projectRoot: '/libs/demo',
      tagPrefix: 'v',
      releaseType: 'premajor',
      preid: 'alpha',
    }));

    expect(newVersion).toEqual('3.0.0-alpha.0');

    expect(mockConventionalRecommendedBump).not.toBeCalled();

    expect(mockGetCommits).toBeCalledTimes(1);
    expect(mockGetCommits).toBeCalledWith({
      projectRoot: '/libs/demo',
      since: 'v2.1.0',
    });
  }


async () => {
    mockGetCommits.mockReturnValue(of([]));

    const newVersion = await lastValueFrom(
      tryBump({
        preset: 'angular',
        projectRoot: '/libs/demo',
        tagPrefix: 'v',
        releaseType: 'patch',
      })
    );

    expect(newVersion).toEqual('2.1.1');

    expect(mockConventionalRecommendedBump).not.toBeCalled();
  }


async () => {
    mockGetLastVersion.mockReturnValue(throwError(() => 'No version found'));
    mockGetCommits.mockReturnValue(of([]));
    mockGetFirstCommitRef.mockReturnValue(of('sha1'));

    await lastValueFrom(
      tryBump({
        preset: 'angular',
        projectRoot: '/libs/demo',
        tagPrefix: 'v'
      })
    );

    expect(loggerSpy).toBeCalledWith(
      expect.stringContaining('No previous version tag found')
    );
    expect(mockGetCommits).toBeCalledTimes(1);
    expect(mockGetCommits).toBeCalledWith({
      projectRoot: '/libs/demo',
      since: 'sha1',
    });
  }


() => 'No version found'


async () => {
    mockGetCommits.mockReturnValue(of([]));

    const newVersion = await lastValueFrom(
      tryBump({
        preset: 'angular',
        projectRoot: '/libs/demo',
        tagPrefix: 'v',
      })
    );

    expect(newVersion).toBeUndefined();

    expect(mockGetCommits).toBeCalledWith({
      projectRoot: '/libs/demo',
      since: 'v2.1.0',
    });
  }


(blog: HttpResponse<Blog>) => {
          if (blog.body) {
            return of(blog.body);
          } else {
            this.router.navigate(['404']);
            return EMPTY;
          }
        }


@Injectable({ providedIn: 'root' })
export class BlogRoutingResolveService implements Resolve<IBlog> {
  constructor(protected service: BlogService, protected router: Router) {}

  resolve(route: ActivatedRouteSnapshot): Observable<IBlog> | Observable<never> {
    const id = route.params['id'];
    if (id) {
      return this.service.find(id).pipe(
        mergeMap((blog: HttpResponse<Blog>) => {
          if (blog.body) {
            return of(blog.body);
          } else {
            this.router.navigate(['404']);
            return EMPTY;
          }
        })
      );
    }
    return of(new Blog());
  }
}


resolve(route: ActivatedRouteSnapshot): Observable<IBlog> | Observable<never> {
    const id = route.params['id'];
    if (id) {
      return this.service.find(id).pipe(
        mergeMap((blog: HttpResponse<Blog>) => {
          if (blog.body) {
            return of(blog.body);
          } else {
            this.router.navigate(['404']);
            return EMPTY;
          }
        })
      );
    }
    return of(new Blog());
  }


export interface CallOptions {}


export interface CallData {
  callUUID: string;
  method: string;
  params?: any[];
  options?: CallOptions;
}


export interface IUserState {
  email: string;
  admin: boolean;
  token: string;
}


export interface IUserStatePayload {
  email?: string;
  admin?: boolean;
  token?: string;
}


export interface IUserObservableOutput {
  model$: Observable<IUserState>;
  email$: Observable<string>;
  token$: Observable<string>;
  admin$: Observable<boolean>;
  isLoggedInSubscription$: Observable<boolean>;
}


export interface IUserHandlers {
  setState(payload: IUserStatePayload): void;
}


export type TUserPayload = IActionPayload<IUserStatePayload>;


(props) => {
  const q = props.state.auth.questions.find((data) => {
    return data.id === props.id;
  }) || { question: '', answer: '', public: false, createdAt: '' };
  const question = q.question;
  const [answer, setAnswer] = useState(q.answer);
  const [questionPublic, setPublic] = useState(q.public);
  const [submited, setSubmited] = useState(false);
  const createdAt = q.createdAt;

  const updatePublic = (e: { target: { checked: boolean } }) => {
    setPublic(e.target.checked);
  };

  const updateAnswer = (e: { target: { value: string } }) => {
    setAnswer(e.target.value);
  };

  const submitQuestion = () => {
    setSubmited(true);
    props.actions.updateQuestion({
      answer,
      id: props.id,
      public: questionPublic,
    });
    Router.push('/mypage', undefined, { shallow: true });
  };

  return (
    <ScrollX>

                {question}

                <TextareaAutosize
                  id='textarea'
                  className='textarea'
                  onChange={updateAnswer}
                  value={answer}
                />

              {createdAt}

Public

          <input
            id='sample1'
            type='checkbox'
            checked={questionPublic}
            onChange={updatePublic}
          />

      {
        !submited
          ? <button className='input-button' onClick={submitQuestion}>Update</button>


(data) => {
    return data.id === props.id;
  }


(e: { target: { checked: boolean } }) => {
    setPublic(e.target.checked);
  }


(e: { target: { value: string } }) => {
    setAnswer(e.target.value);
  }


() => {
    setSubmited(true);
    props.actions.updateQuestion({
      answer,
      id: props.id,
      public: questionPublic,
    });
    Router.push('/mypage', undefined, { shallow: true });
  }


(state) => {
  return { state };
}


(dispatch) => {
  return {
    actions: bindActionCreators(Actions, dispatch),
  };
}


interface Props {
  id: string | string[];
  actions: any;
  state: any;
}


(): JSX.Element => {
  return (
    <div>
      <Navbar name="Update Password"></Navbar>
      <UpdatePasswordForm></UpdatePasswordForm>
    </div>


export class PropertyComponent extends LitElement {
    render() {
        return html`
            <div>
                Hello, home page
            </div>
        `;
    }
}


render() {
        return html`
            <div>
                Hello, home page
            </div>
        `;
    }


// [§ 4.5.17 The samp element](https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-samp-element)
export class Sample extends InlineAnnotation<GlobalAttributes> {
  static vendorPrefix = "html";
  static type = "samp";
}


function expectConfigurationOption(configurationList: Stanza, configurationKey: string, expected: any) {
    const value = extractConfigurationValue(configurationList, configurationKey);
    expect(value).toEqual(expected);
}


function extractConfigurationValue(configurationList: Stanza, configurationKey: string) {
    const fieldNodes = configurationList.getChildrenByAttr('var', configurationKey);
    expect(fieldNodes.length).toEqual(1);
    const fieldNode = fieldNodes[0];
    const values = fieldNode.getChildren('value').map(node => node.getText());
    return values.length === 1 ? values[0] : values;
}


() => {
        const mockClientFactory = new MockClientFactory();
        xmppClientMock = mockClientFactory.clientInstance;

        TestBed.configureTestingModule({
            providers: [
                XmppChatConnectionService,
                {provide: XmppClientFactoryService, useValue: mockClientFactory},
                XmppChatAdapter,
                {provide: LogService, useValue: testLogService()},
                ContactFactoryService
            ]
        });

        chatConnectionService = TestBed.inject(XmppChatConnectionService);
        chatConnectionService.client = xmppClientMock;
        chatConnectionService.userJid = parseJid('me', 'example.com', 'something');

        chatAdapter = TestBed.inject(XmppChatAdapter);

        const conferenceService = {
            jid: 'conference.jabber.example.com',
        };
        const serviceDiscoveryPluginMock: any = {
            findService: () => conferenceService
        };

        logService = TestBed.inject(LogService);
        chatAdapter.addPlugins([
            new MultiUserChatPlugin(chatAdapter, logService, serviceDiscoveryPluginMock),
            new MessageUuidPlugin()
        ]);

        multiUserChatPlugin = chatAdapter.getPlugin(MultiUserChatPlugin);
    }


() => conferenceService


() => {

        it('should throw if user is not allowed to create rooms', async () => {

            xmppClientMock.send.and.callFake((content: Stanza) => {
                chatConnectionService.onStanzaReceived(
                    xml('presence', {from: content.attrs.to, to: content.attrs.from},
                        xml('x', {xmlns: 'http://jabber.org/protocol/muc#user', type: 'error'}),
                        xml('error', {by: 'me@example.com', type: 'cancel'},
                            xml('not-allowed', {xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas'})
                        )
                    )
                );
            });

            try {
                await multiUserChatPlugin.createRoom(defaultRoomConfiguration);
                fail('should have thrown');
            } catch (e) {
                expect(e.message).toContain('error joining room: ');
            }

        });

        it('should throw if user is not owner', async () => {

            xmppClientMock.send.and.callFake((content: Stanza) => {
                chatConnectionService.onStanzaReceived(
                    xml('presence', {from: content.attrs.to, to: content.attrs.from},
                        xml('x', {xmlns: 'http://jabber.org/protocol/muc#user'},
                            xml('item', {affiliation: 'visitor', role: 'visitor'})
                        )
                    )
                );
            });

            try {
                await multiUserChatPlugin.createRoom(defaultRoomConfiguration);
                fail('should have thrown');
            } catch (e) {
                expect(e.message).toContain('error creating room, user is not owner');
            }

        });

        it('should throw if room is not configurable', async () => {

            xmppClientMock.send.and.callFake((content: Stanza) => {

                if (content.name === 'presence') {
                    chatConnectionService.onStanzaReceived(
                        xml('presence', {from: content.attrs.to, to: content.attrs.from},
                            xml('x', {xmlns: 'http://jabber.org/protocol/muc#user'},
                                xml('item', {affiliation: 'owner', role: 'moderator'}),
                                xml('status', {code: '110'}),
                                xml('status', {code: '201'})
                            )
                        )
                    );
                } else if (content.name === 'iq') {
                    chatConnectionService.onStanzaReceived(
                        xml('iq', {from: content.attrs.to, to: content.attrs.from, type: 'result', id: content.attrs.id},
                            xml('query', {xmlns: 'http://jabber.org/protocol/muc#owner'})
                        )
                    );
                } else {
                    fail('unexpected stanza: ' + content.toString());
                }

            });

            try {
                await multiUserChatPlugin.createRoom(defaultRoomConfiguration);
                fail('should have thrown');
            } catch (e) {
                expect(e.message).toContain('room not configurable');
            }

        });

        it('should handle room configurations correctly', async () => {
            xmppClientMock.send.and.callFake((content: Stanza) => {
                if (content.name === 'presence') {
                    chatConnectionService.onStanzaReceived(
                        xml('presence', {from: content.attrs.to, to: content.attrs.from},
                            xml('x', {xmlns: 'http://jabber.org/protocol/muc#user'},
                                xml('item', {affiliation: 'owner', role: 'moderator'}),
                                xml('status', {code: '110'}),
                                xml('status', {code: '201'})
                            )
                        )
                    );
                } else if (content.name === 'iq' && content.attrs.type === 'get') {
                    chatConnectionService.onStanzaReceived(
                        xml('iq', {from: content.attrs.to, to: content.attrs.from, type: 'result', id: content.attrs.id},
                            xml('query', {xmlns: 'http://jabber.org/protocol/muc#owner'},
                                xml('x', {type: 'form', xmlns: 'jabber:x:data'},
                                    xml('field', {var: 'FORM_TYPE', type: 'hidden'},
                                        xml('value', {}, 'http://jabber.org/protocol/muc#roomconfig')
                                    )
                                )
                            )
                        )
                    );
                } else if (content.name === 'iq' && content.attrs.type === 'set') {
                    chatConnectionService.onStanzaReceived(
                        xml('iq', {from: content.attrs.to, to: content.attrs.from, type: 'error', id: content.attrs.id},
                            xml('error', {type: 'modify'},
                                xml('not-acceptable', {xmlns: 'urn:ietf:params:ml:ns:xmpp-stanzas'})
                            )
                        )
                    );
                } else {
                    fail('unexpected stanza: ' + content.toString());
                }
            });

            try {
                await multiUserChatPlugin.createRoom(defaultRoomConfiguration);
                fail('should be rejected');
            } catch (e) {
                expect(e.message).toContain('room configuration rejected');
            }

        });

        it('should allow users to create and configure rooms', async () => {

            xmppClientMock.send.and.callFake((content: Stanza) => {
                if (content.name === 'presence') {
                    chatConnectionService.onStanzaReceived(
                        xml('presence', {from: content.attrs.to, to: content.attrs.from},
                            xml('x', {xmlns: 'http://jabber.org/protocol/muc#user'},
                                xml('item', {affiliation: 'owner', role: 'moderator'}),
                                xml('status', {code: '110'}),
                                xml('status', {code: '201'})
                            )
                        )
                    );
                } else if (content.name === 'iq' && content.attrs.type === 'get') {
                    chatConnectionService.onStanzaReceived(
                        xml('iq', {from: content.attrs.to, to: content.attrs.from, type: 'result', id: content.attrs.id},
                            xml('query', {xmlns: 'http://jabber.org/protocol/muc#owner'},
                                xml('x', {type: 'form', xmlns: 'jabber:x:data'},
                                    xml('field', {var: 'FORM_TYPE', type: 'hidden'},
                                        xml('value', {}, 'http://jabber.org/protocol/muc#roomconfig')
                                    ),
                                    xml('field', {var: 'multipleValues', type: 'list-multi'},
                                        xml('value', {}, 'value1'),
                                        xml('value', {}, 'value2')
                                    )
                                )
                            )
                        )
                    );
                } else if (content.name === 'iq' && content.attrs.type === 'set') {
                    const configurationList = content.getChild('query').getChild('x');
                    expectConfigurationOption(configurationList, 'muc#roomconfig_publicroom', '0');
                    expectConfigurationOption(configurationList, 'muc#roomconfig_whois', 'anyone');
                    expectConfigurationOption(configurationList, 'muc#roomconfig_membersonly', '1');
                    expectConfigurationOption(configurationList, 'multipleValues', ['value1', 'value2']);
                    chatConnectionService.onStanzaReceived(
                        xml('iq', {from: content.attrs.to, to: content.attrs.from, type: 'result', id: content.attrs.id})
                    );
                } else {
                    fail('unexpected stanza: ' + content.toString());
                }
            });

            await multiUserChatPlugin.createRoom(defaultRoomConfiguration);

        });
    }


async () => {

            xmppClientMock.send.and.callFake((content: Stanza) => {
                chatConnectionService.onStanzaReceived(
                    xml('presence', {from: content.attrs.to, to: content.attrs.from},
                        xml('x', {xmlns: 'http://jabber.org/protocol/muc#user', type: 'error'}),
                        xml('error', {by: 'me@example.com', type: 'cancel'},
                            xml('not-allowed', {xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas'})
                        )
                    )
                );
            });

            try {
                await multiUserChatPlugin.createRoom(defaultRoomConfiguration);
                fail('should have thrown');
            } catch (e) {
                expect(e.message).toContain('error joining room: ');
            }

        }


(content: Stanza) => {
                chatConnectionService.onStanzaReceived(
                    xml('presence', {from: content.attrs.to, to: content.attrs.from},
                        xml('x', {xmlns: 'http://jabber.org/protocol/muc#user', type: 'error'}),
                        xml('error', {by: 'me@example.com', type: 'cancel'},
                            xml('not-allowed', {xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas'})
                        )
                    )
                );
            }


async () => {

            xmppClientMock.send.and.callFake((content: Stanza) => {
                chatConnectionService.onStanzaReceived(
                    xml('presence', {from: content.attrs.to, to: content.attrs.from},
                        xml('x', {xmlns: 'http://jabber.org/protocol/muc#user'},
                            xml('item', {affiliation: 'visitor', role: 'visitor'})
                        )
                    )
                );
            });

            try {
                await multiUserChatPlugin.createRoom(defaultRoomConfiguration);
                fail('should have thrown');
            } catch (e) {
                expect(e.message).toContain('error creating room, user is not owner');
            }

        }


(content: Stanza) => {
                chatConnectionService.onStanzaReceived(
                    xml('presence', {from: content.attrs.to, to: content.attrs.from},
                        xml('x', {xmlns: 'http://jabber.org/protocol/muc#user'},
                            xml('item', {affiliation: 'visitor', role: 'visitor'})
                        )
                    )
                );
            }


async () => {

            xmppClientMock.send.and.callFake((content: Stanza) => {

                if (content.name === 'presence') {
                    chatConnectionService.onStanzaReceived(
                        xml('presence', {from: content.attrs.to, to: content.attrs.from},
                            xml('x', {xmlns: 'http://jabber.org/protocol/muc#user'},
                                xml('item', {affiliation: 'owner', role: 'moderator'}),
                                xml('status', {code: '110'}),
                                xml('status', {code: '201'})
                            )
                        )
                    );
                } else if (content.name === 'iq') {
                    chatConnectionService.onStanzaReceived(
                        xml('iq', {from: content.attrs.to, to: content.attrs.from, type: 'result', id: content.attrs.id},
                            xml('query', {xmlns: 'http://jabber.org/protocol/muc#owner'})
                        )
                    );
                } else {
                    fail('unexpected stanza: ' + content.toString());
                }

            });

            try {
                await multiUserChatPlugin.createRoom(defaultRoomConfiguration);
                fail('should have thrown');
            } catch (e) {
                expect(e.message).toContain('room not configurable');
            }

        }


(content: Stanza) => {

                if (content.name === 'presence') {
                    chatConnectionService.onStanzaReceived(
                        xml('presence', {from: content.attrs.to, to: content.attrs.from},
                            xml('x', {xmlns: 'http://jabber.org/protocol/muc#user'},
                                xml('item', {affiliation: 'owner', role: 'moderator'}),
                                xml('status', {code: '110'}),
                                xml('status', {code: '201'})
                            )
                        )
                    );
                } else if (content.name === 'iq') {
                    chatConnectionService.onStanzaReceived(
                        xml('iq', {from: content.attrs.to, to: content.attrs.from, type: 'result', id: content.attrs.id},
                            xml('query', {xmlns: 'http://jabber.org/protocol/muc#owner'})
                        )
                    );
                } else {
                    fail('unexpected stanza: ' + content.toString());
                }

            }


async () => {
            xmppClientMock.send.and.callFake((content: Stanza) => {
                if (content.name === 'presence') {
                    chatConnectionService.onStanzaReceived(
                        xml('presence', {from: content.attrs.to, to: content.attrs.from},
                            xml('x', {xmlns: 'http://jabber.org/protocol/muc#user'},
                                xml('item', {affiliation: 'owner', role: 'moderator'}),
                                xml('status', {code: '110'}),
                                xml('status', {code: '201'})
                            )
                        )
                    );
                } else if (content.name === 'iq' && content.attrs.type === 'get') {
                    chatConnectionService.onStanzaReceived(
                        xml('iq', {from: content.attrs.to, to: content.attrs.from, type: 'result', id: content.attrs.id},
                            xml('query', {xmlns: 'http://jabber.org/protocol/muc#owner'},
                                xml('x', {type: 'form', xmlns: 'jabber:x:data'},
                                    xml('field', {var: 'FORM_TYPE', type: 'hidden'},
                                        xml('value', {}, 'http://jabber.org/protocol/muc#roomconfig')
                                    )
                                )
                            )
                        )
                    );
                } else if (content.name === 'iq' && content.attrs.type === 'set') {
                    chatConnectionService.onStanzaReceived(
                        xml('iq', {from: content.attrs.to, to: content.attrs.from, type: 'error', id: content.attrs.id},
                            xml('error', {type: 'modify'},
                                xml('not-acceptable', {xmlns: 'urn:ietf:params:ml:ns:xmpp-stanzas'})
                            )
                        )
                    );
                } else {
                    fail('unexpected stanza: ' + content.toString());
                }
            });

            try {
                await multiUserChatPlugin.createRoom(defaultRoomConfiguration);
                fail('should be rejected');
            } catch (e) {
                expect(e.message).toContain('room configuration rejected');
            }

        }


(content: Stanza) => {
                if (content.name === 'presence') {
                    chatConnectionService.onStanzaReceived(
                        xml('presence', {from: content.attrs.to, to: content.attrs.from},
                            xml('x', {xmlns: 'http://jabber.org/protocol/muc#user'},
                                xml('item', {affiliation: 'owner', role: 'moderator'}),
                                xml('status', {code: '110'}),
                                xml('status', {code: '201'})
                            )
                        )
                    );
                } else if (content.name === 'iq' && content.attrs.type === 'get') {
                    chatConnectionService.onStanzaReceived(
                        xml('iq', {from: content.attrs.to, to: content.attrs.from, type: 'result', id: content.attrs.id},
                            xml('query', {xmlns: 'http://jabber.org/protocol/muc#owner'},
                                xml('x', {type: 'form', xmlns: 'jabber:x:data'},
                                    xml('field', {var: 'FORM_TYPE', type: 'hidden'},
                                        xml('value', {}, 'http://jabber.org/protocol/muc#roomconfig')
                                    )
                                )
                            )
                        )
                    );
                } else if (content.name === 'iq' && content.attrs.type === 'set') {
                    chatConnectionService.onStanzaReceived(
                        xml('iq', {from: content.attrs.to, to: content.attrs.from, type: 'error', id: content.attrs.id},
                            xml('error', {type: 'modify'},
                                xml('not-acceptable', {xmlns: 'urn:ietf:params:ml:ns:xmpp-stanzas'})
                            )
                        )
                    );
                } else {
                    fail('unexpected stanza: ' + content.toString());
                }
            }


async () => {

            xmppClientMock.send.and.callFake((content: Stanza) => {
                if (content.name === 'presence') {
                    chatConnectionService.onStanzaReceived(
                        xml('presence', {from: content.attrs.to, to: content.attrs.from},
                            xml('x', {xmlns: 'http://jabber.org/protocol/muc#user'},
                                xml('item', {affiliation: 'owner', role: 'moderator'}),
                                xml('status', {code: '110'}),
                                xml('status', {code: '201'})
                            )
                        )
                    );
                } else if (content.name === 'iq' && content.attrs.type === 'get') {
                    chatConnectionService.onStanzaReceived(
                        xml('iq', {from: content.attrs.to, to: content.attrs.from, type: 'result', id: content.attrs.id},
                            xml('query', {xmlns: 'http://jabber.org/protocol/muc#owner'},
                                xml('x', {type: 'form', xmlns: 'jabber:x:data'},
                                    xml('field', {var: 'FORM_TYPE', type: 'hidden'},
                                        xml('value', {}, 'http://jabber.org/protocol/muc#roomconfig')
                                    ),
                                    xml('field', {var: 'multipleValues', type: 'list-multi'},
                                        xml('value', {}, 'value1'),
                                        xml('value', {}, 'value2')
                                    )
                                )
                            )
                        )
                    );
                } else if (content.name === 'iq' && content.attrs.type === 'set') {
                    const configurationList = content.getChild('query').getChild('x');
                    expectConfigurationOption(configurationList, 'muc#roomconfig_publicroom', '0');
                    expectConfigurationOption(configurationList, 'muc#roomconfig_whois', 'anyone');
                    expectConfigurationOption(configurationList, 'muc#roomconfig_membersonly', '1');
                    expectConfigurationOption(configurationList, 'multipleValues', ['value1', 'value2']);
                    chatConnectionService.onStanzaReceived(
                        xml('iq', {from: content.attrs.to, to: content.attrs.from, type: 'result', id: content.attrs.id})
                    );
                } else {
                    fail('unexpected stanza: ' + content.toString());
                }
            });

            await multiUserChatPlugin.createRoom(defaultRoomConfiguration);

        }


(content: Stanza) => {
                if (content.name === 'presence') {
                    chatConnectionService.onStanzaReceived(
                        xml('presence', {from: content.attrs.to, to: content.attrs.from},
                            xml('x', {xmlns: 'http://jabber.org/protocol/muc#user'},
                                xml('item', {affiliation: 'owner', role: 'moderator'}),
                                xml('status', {code: '110'}),
                                xml('status', {code: '201'})
                            )
                        )
                    );
                } else if (content.name === 'iq' && content.attrs.type === 'get') {
                    chatConnectionService.onStanzaReceived(
                        xml('iq', {from: content.attrs.to, to: content.attrs.from, type: 'result', id: content.attrs.id},
                            xml('query', {xmlns: 'http://jabber.org/protocol/muc#owner'},
                                xml('x', {type: 'form', xmlns: 'jabber:x:data'},
                                    xml('field', {var: 'FORM_TYPE', type: 'hidden'},
                                        xml('value', {}, 'http://jabber.org/protocol/muc#roomconfig')
                                    ),
                                    xml('field', {var: 'multipleValues', type: 'list-multi'},
                                        xml('value', {}, 'value1'),
                                        xml('value', {}, 'value2')
                                    )
                                )
                            )
                        )
                    );
                } else if (content.name === 'iq' && content.attrs.type === 'set') {
                    const configurationList = content.getChild('query').getChild('x');
                    expectConfigurationOption(configurationList, 'muc#roomconfig_publicroom', '0');
                    expectConfigurationOption(configurationList, 'muc#roomconfig_whois', 'anyone');
                    expectConfigurationOption(configurationList, 'muc#roomconfig_membersonly', '1');
                    expectConfigurationOption(configurationList, 'multipleValues', ['value1', 'value2']);
                    chatConnectionService.onStanzaReceived(
                        xml('iq', {from: content.attrs.to, to: content.attrs.from, type: 'result', id: content.attrs.id})
                    );
                } else {
                    fail('unexpected stanza: ' + content.toString());
                }
            }


() => {

        it('should be able to receive messages in rooms', async (resolve) => {

            xmppClientMock.send.and.callFake((content: Stanza) => {
                chatConnectionService.onStanzaReceived(
                    xml('presence', {from: content.attrs.to, to: content.attrs.from},
                        xml('x', {xmlns: 'http://jabber.org/protocol/muc#user', type: 'error'},
                            xml('item', {affiliation: 'member', role: 'participant'}),
                            xml('status', {code: '110'}),
                            xml('status', {code: '210'})
                        ),
                    )
                );
            });

            await multiUserChatPlugin.joinRoom(parseJid('chatroom', 'conference.example.com'));

            const rooms = multiUserChatPlugin.rooms$.getValue();
            expect(rooms.length).toEqual(1);

            rooms[0].messages$
                .pipe(first())
                .subscribe((message) => {
                    expect(message.body).toEqual('message content here');
                    resolve();
                });

            const otherOccupant = 'chatroom@conference.example.com/other-occupant';
            chatConnectionService.onStanzaReceived(
                xml('message', {from: otherOccupant, id: '1', to: chatConnectionService.userJid.toString(), type: 'groupchat'},
                    xml('body', {}, 'message content here')
                )
            );

        });

        it('should be able to send messages', async () => {

            xmppClientMock.send.and.callFake((stanza: Stanza) => {

                if (stanza.name === 'message') {
                    expect(stanza.name).toEqual('message');
                    expect(stanza.attrs.from).toEqual('me@example.com/something');
                    expect(stanza.attrs.to).toEqual('chatroom@conference.example.com');
                    expect(stanza.attrs.type).toEqual('groupchat');
                    expect(stanza.getChildText('body')).toEqual('message body');

                    chatConnectionService.onStanzaReceived(
                        xml('message', {from: 'chatroom@conference.example.com/me', to: 'me@example.com/something', type: 'groupchat'},
                            xml('body', {}, 'message body'),
                            xml('origin-id', {id: stanza.getChild('origin-id').attrs.id})
                        )
                    );
                } else if (stanza.name === 'presence') {
                    chatConnectionService.onStanzaReceived(
                        xml('presence', {from: stanza.attrs.to, to: stanza.attrs.from},
                            xml('x', {xmlns: 'http://jabber.org/protocol/muc#user'},
                                xml('item', {affiliation: 'owner', role: 'moderator'}),
                                xml('status', {code: '110'}),
                                xml('status', {code: '201'})
                            )
                        )
                    );
                } else {
                    throw new Error('unknown stanza: ' + stanza.toString());
                }

            });

            // when
            const myOccupantJid = parseJid('chatroom@conference.example.com/me');
            const room = await multiUserChatPlugin.joinRoom(myOccupantJid);
            await multiUserChatPlugin.sendMessage(room, 'message body');

            // then
            expect(room.messages.length).toEqual(1);
            expect(room.messages[0].body).toEqual('message body');
            expect(room.messages[0].direction).toEqual(Direction.out);
            expect(room.messages[0].id).not.toBeUndefined();
            expect(room.messages[0].from).toEqual(myOccupantJid);

        });

    }


async (resolve) => {

            xmppClientMock.send.and.callFake((content: Stanza) => {
                chatConnectionService.onStanzaReceived(
                    xml('presence', {from: content.attrs.to, to: content.attrs.from},
                        xml('x', {xmlns: 'http://jabber.org/protocol/muc#user', type: 'error'},
                            xml('item', {affiliation: 'member', role: 'participant'}),
                            xml('status', {code: '110'}),
                            xml('status', {code: '210'})
                        ),
                    )
                );
            });

            await multiUserChatPlugin.joinRoom(parseJid('chatroom', 'conference.example.com'));

            const rooms = multiUserChatPlugin.rooms$.getValue();
            expect(rooms.length).toEqual(1);

            rooms[0].messages$
                .pipe(first())
                .subscribe((message) => {
                    expect(message.body).toEqual('message content here');
                    resolve();
                });

            const otherOccupant = 'chatroom@conference.example.com/other-occupant';
            chatConnectionService.onStanzaReceived(
                xml('message', {from: otherOccupant, id: '1', to: chatConnectionService.userJid.toString(), type: 'groupchat'},
                    xml('body', {}, 'message content here')
                )
            );

        }


(content: Stanza) => {
                chatConnectionService.onStanzaReceived(
                    xml('presence', {from: content.attrs.to, to: content.attrs.from},
                        xml('x', {xmlns: 'http://jabber.org/protocol/muc#user', type: 'error'},
                            xml('item', {affiliation: 'member', role: 'participant'}),
                            xml('status', {code: '110'}),
                            xml('status', {code: '210'})
                        ),
                    )
                );
            }


(message) => {
                    expect(message.body).toEqual('message content here');
                    resolve();
                }


async () => {

            xmppClientMock.send.and.callFake((stanza: Stanza) => {

                if (stanza.name === 'message') {
                    expect(stanza.name).toEqual('message');
                    expect(stanza.attrs.from).toEqual('me@example.com/something');
                    expect(stanza.attrs.to).toEqual('chatroom@conference.example.com');
                    expect(stanza.attrs.type).toEqual('groupchat');
                    expect(stanza.getChildText('body')).toEqual('message body');

                    chatConnectionService.onStanzaReceived(
                        xml('message', {from: 'chatroom@conference.example.com/me', to: 'me@example.com/something', type: 'groupchat'},
                            xml('body', {}, 'message body'),
                            xml('origin-id', {id: stanza.getChild('origin-id').attrs.id})
                        )
                    );
                } else if (stanza.name === 'presence') {
                    chatConnectionService.onStanzaReceived(
                        xml('presence', {from: stanza.attrs.to, to: stanza.attrs.from},
                            xml('x', {xmlns: 'http://jabber.org/protocol/muc#user'},
                                xml('item', {affiliation: 'owner', role: 'moderator'}),
                                xml('status', {code: '110'}),
                                xml('status', {code: '201'})
                            )
                        )
                    );
                } else {
                    throw new Error('unknown stanza: ' + stanza.toString());
                }

            });

            // when
            const myOccupantJid = parseJid('chatroom@conference.example.com/me');
            const room = await multiUserChatPlugin.joinRoom(myOccupantJid);
            await multiUserChatPlugin.sendMessage(room, 'message body');

            // then
            expect(room.messages.length).toEqual(1);
            expect(room.messages[0].body).toEqual('message body');
            expect(room.messages[0].direction).toEqual(Direction.out);
            expect(room.messages[0].id).not.toBeUndefined();
            expect(room.messages[0].from).toEqual(myOccupantJid);

        }


(stanza: Stanza) => {

                if (stanza.name === 'message') {
                    expect(stanza.name).toEqual('message');
                    expect(stanza.attrs.from).toEqual('me@example.com/something');
                    expect(stanza.attrs.to).toEqual('chatroom@conference.example.com');
                    expect(stanza.attrs.type).toEqual('groupchat');
                    expect(stanza.getChildText('body')).toEqual('message body');

                    chatConnectionService.onStanzaReceived(
                        xml('message', {from: 'chatroom@conference.example.com/me', to: 'me@example.com/something', type: 'groupchat'},
                            xml('body', {}, 'message body'),
                            xml('origin-id', {id: stanza.getChild('origin-id').attrs.id})
                        )
                    );
                } else if (stanza.name === 'presence') {
                    chatConnectionService.onStanzaReceived(
                        xml('presence', {from: stanza.attrs.to, to: stanza.attrs.from},
                            xml('x', {xmlns: 'http://jabber.org/protocol/muc#user'},
                                xml('item', {affiliation: 'owner', role: 'moderator'}),
                                xml('status', {code: '110'}),
                                xml('status', {code: '201'})
                            )
                        )
                    );
                } else {
                    throw new Error('unknown stanza: ' + stanza.toString());
                }

            }


node => node.getText()


c => ({
    __typename: "CountryDisplay",
    code: c.code,
    country: c.name
  })


() => <WarehouseCreatePage {...props} />


() => <WarehouseCreatePage {...props}


() => (
    <WarehouseCreatePage
      {...props}


field => ({
        __typename: "WarehouseError",
        code: WarehouseErrorCode.INVALID,
        field,
        message: "Warehouse invalid"
      })


@Component({
    styleUrls: ['./careerbook.component.scss'],
    templateUrl: './careerbook.component.html',
})
export class CareerbookComponent {

}


/**
 * @license
 * Copyright Google LLC All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.io/license
 */
export default function () {
  return `export default '';`;
}


() => {
  let component: AspectMetricsComponent;
  let fixture: ComponentFixture<AspectMetricsComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        AspectMetricsComponent
      ],
      imports: [
        SharedMocksModule,
        FormsModule,
        ReactiveFormsModule
      ],
      providers: [
        AspectMetricsComponent
      ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(AspectMetricsComponent);
    component = fixture.componentInstance;
    component.aspects = [];
    component.aspectType = {name: '', icon: ''};
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
  it('should ', inject(
    [AspectMetricsComponent],
    (component: AspectMetricsComponent) => {
      const type1: PerformanceAspectType = {name: 'PAGE_CONSTRUCTION_STARTED', icon: 'hourglass'};
      const type2: PerformanceAspectType = {name: 'PAGE_SHOWS_USEFUL_CONTENT', icon: 'hourglass'};
      const aspectsOfTwoDifferentTypes = [
        {
          id: 1,
          pageId: 1,
          jobGroupId: 1,
          browserId: 1,
          measurand: {id: 'DOC_COMPLETE', name: 'Document complete'},
          performanceAspectType: type1,
          persistent: true,
          browserName: 'browser1',
          operatingSystem: 'Android',
          deviceType: {name: 'Smartphone', icon: 'mobile'}
        },
        {
          id: 1,
          pageId: 4,
          jobGroupId: 1,
          browserId: 1,
          measurand: {id: 'DOC_COMPLETE', name: 'Document complete'},
          performanceAspectType: type2,
          persistent: true,
          browserName: 'browser1',
          operatingSystem: 'Android',
          deviceType: {name: 'Smartphone', icon: 'mobile'}
        }];
      component.aspects = aspectsOfTwoDifferentTypes;
      component.aspectType = type1;
      component.ngOnInit();
      component.aspectsToShow$.subscribe((aspects: ExtendedPerformanceAspect[]) => {
        expect(aspects.length).toBe(1);
        expect(aspects[0].performanceAspectType).toBe(type1);
      })
    }));
}


() => {
    TestBed.configureTestingModule({
      declarations: [
        AspectMetricsComponent
      ],
      imports: [
        SharedMocksModule,
        FormsModule,
        ReactiveFormsModule
      ],
      providers: [
        AspectMetricsComponent
      ]
    })
    .compileComponents();
  }


() => {
    fixture = TestBed.createComponent(AspectMetricsComponent);
    component = fixture.componentInstance;
    component.aspects = [];
    component.aspectType = {name: '', icon: ''};
    fixture.detectChanges();
  }


(component: AspectMetricsComponent) => {
      const type1: PerformanceAspectType = {name: 'PAGE_CONSTRUCTION_STARTED', icon: 'hourglass'};
      const type2: PerformanceAspectType = {name: 'PAGE_SHOWS_USEFUL_CONTENT', icon: 'hourglass'};
      const aspectsOfTwoDifferentTypes = [
        {
          id: 1,
          pageId: 1,
          jobGroupId: 1,
          browserId: 1,
          measurand: {id: 'DOC_COMPLETE', name: 'Document complete'},
          performanceAspectType: type1,
          persistent: true,
          browserName: 'browser1',
          operatingSystem: 'Android',
          deviceType: {name: 'Smartphone', icon: 'mobile'}
        },
        {
          id: 1,
          pageId: 4,
          jobGroupId: 1,
          browserId: 1,
          measurand: {id: 'DOC_COMPLETE', name: 'Document complete'},
          performanceAspectType: type2,
          persistent: true,
          browserName: 'browser1',
          operatingSystem: 'Android',
          deviceType: {name: 'Smartphone', icon: 'mobile'}
        }];
      component.aspects = aspectsOfTwoDifferentTypes;
      component.aspectType = type1;
      component.ngOnInit();
      component.aspectsToShow$.subscribe((aspects: ExtendedPerformanceAspect[]) => {
        expect(aspects.length).toBe(1);
        expect(aspects[0].performanceAspectType).toBe(type1);
      })
    }


(aspects: ExtendedPerformanceAspect[]) => {
        expect(aspects.length).toBe(1);
        expect(aspects[0].performanceAspectType).toBe(type1);
      }


export declare function startServer(commandOptions: CommandOptions, { isDev: _isDev, isWatch: _isWatch, preparePackages: _preparePackages, }?: {
    isDev?: boolean;
    isWatch?: boolean;
    preparePackages?: boolean;
}): Promise<SnowpackDevServer>;


export declare function command(commandOptions: CommandOptions): Promise<unknown>;


export declare class OneToManyMap {
    readonly keyToValue: Map<string, string[]>;
    readonly valueToKey: Map<string, string>;
    add(key: string, _value: string | string[]): void;
    delete(key: string): void;
    key(value: string): string | undefined;
    value(key: string): string[] | undefined;
}


add(key: string, _value: string | string[]): void;


delete(key: string): void;


key(value: string): string | undefined;


value(key: string): string[] | undefined;


async (id: String) => {
	const deleted = await Favorite.deleteOne({ _id: id });

	return deleted;
}


type BaseOptions = {
  key?: string
  uri?: string
}


export type AppsignalOptions = BaseOptions & {
  namespace?: string
  revision?: string
  ignoreErrors?: RegExp[]
}


export type PushApiOptions = BaseOptions & {
  key: string
  version: string
}


(event) => {

        let toast = this.toastCtrl.create({
          message: 'Event created',
          duration: 3000,
          position: 'bottom',
          showCloseButton: true,
          closeButtonText: 'UNDO'
        });

        toast.onDidDismiss((data, role) => {
          if (role == "close") {
            this.eventService.deleteEvent(event.id);
          }
        });

        toast.present();

      }


(data, role) => {
          if (role == "close") {
            this.eventService.deleteEvent(event.id);
          }
        }


() => {

        let toast = this.toastCtrl.create({
          message: 'Event modified',
          duration: 3000,
          position: 'bottom',
          showCloseButton: true,
          closeButtonText: 'UNDO'
        });

        toast.onDidDismiss((data, role) => {
          if (role == "close") {
            this.eventService.updateEvent(this.eventId, this.originalEvent).then( () => {
              Object.assign(this.event, this.originalEvent);
            });
          }
        });

        toast.present();

      }


(data, role) => {
          if (role == "close") {
            this.eventService.updateEvent(this.eventId, this.originalEvent).then( () => {
              Object.assign(this.event, this.originalEvent);
            });
          }
        }


() => {
              Object.assign(this.event, this.originalEvent);
            }


@Component({
  selector: 'page-event-form',
  templateUrl: 'event-form.html',
})
export class EventFormPage {

  event: Event = new Event();
  eventId: string;
  originalEvent: Event = new Event();
  editMode: Boolean = false;
  title: string = "Create event";
  eventModified: boolean = false;
  userId: string;
  disciplines = [
    {value: 'swimming', label: 'Swimming'},
    {value: 'cycling', label: 'Cycling'},
    {value: 'running', label: 'Running'},
    {value: 'other', label: 'Other'}
  ];

  constructor(public navCtrl: NavController,
    public viewCtrl: ViewController,
    public navParams: NavParams,
    private toastCtrl: ToastController,
    private auth: AuthService,
    private eventService: EventService ) {

      this.userId = this.auth.user.uid;
      this.editMode = Boolean(navParams.get('event'));

      if(this.editMode) {
        this.event = navParams.get('event');
        this.eventId = navParams.get('eventId');
        this.originalEvent = JSON.parse(JSON.stringify(this.event));
        this.event.start = new Date(this.event.start).toISOString();
        this.title = "Edit event";
      }

  }

  ionViewWillLeave() {
    if(!this.eventModified && this.editMode) {
      Object.assign(this.event, this.originalEvent);
    }
  }

  saveEvent() {

    if(!this.editMode) {
      this.event.owner = this.userId;
      this.eventService.createEvent(this.event).then( (event) => {

        let toast = this.toastCtrl.create({
          message: 'Event created',
          duration: 3000,
          position: 'bottom',
          showCloseButton: true,
          closeButtonText: 'UNDO'
        });

        toast.onDidDismiss((data, role) => {
          if (role == "close") {
            this.eventService.deleteEvent(event.id);
          }
        });

        toast.present();

      });
    } else {

      this.eventModified = true;

      this.eventService.updateEvent(this.eventId, this.event).then( () => {

        let toast = this.toastCtrl.create({
          message: 'Event modified',
          duration: 3000,
          position: 'bottom',
          showCloseButton: true,
          closeButtonText: 'UNDO'
        });

        toast.onDidDismiss((data, role) => {
          if (role == "close") {
            this.eventService.updateEvent(this.eventId, this.originalEvent).then( () => {
              Object.assign(this.event, this.originalEvent);
            });
          }
        });

        toast.present();

      });
    }

    this.viewCtrl.dismiss();
  }

}


ionViewWillLeave() {
    if(!this.eventModified && this.editMode) {
      Object.assign(this.event, this.originalEvent);
    }
  }


saveEvent() {

    if(!this.editMode) {
      this.event.owner = this.userId;
      this.eventService.createEvent(this.event).then( (event) => {

        let toast = this.toastCtrl.create({
          message: 'Event created',
          duration: 3000,
          position: 'bottom',
          showCloseButton: true,
          closeButtonText: 'UNDO'
        });

        toast.onDidDismiss((data, role) => {
          if (role == "close") {
            this.eventService.deleteEvent(event.id);
          }
        });

        toast.present();

      });
    } else {

      this.eventModified = true;

      this.eventService.updateEvent(this.eventId, this.event).then( () => {

        let toast = this.toastCtrl.create({
          message: 'Event modified',
          duration: 3000,
          position: 'bottom',
          showCloseButton: true,
          closeButtonText: 'UNDO'
        });

        toast.onDidDismiss((data, role) => {
          if (role == "close") {
            this.eventService.updateEvent(this.eventId, this.originalEvent).then( () => {
              Object.assign(this.event, this.originalEvent);
            });
          }
        });

        toast.present();

      });
    }

    this.viewCtrl.dismiss();
  }