function handleDOMRelated(
  doc: Document
): LongmanSearchResultRelated | Promise<LongmanSearchResultRelated> {
  const $didyoumean = doc.querySelector('.didyoumean')
  if ($didyoumean) {
    return {
      result: {
        type: 'related',
        list: getInnerHTML(HOST, $didyoumean)
      }
    }
  }
  return handleNoResult()
}


text => {
  return `https://www.ldoceonline.com/dictionary/${text
    .trim()
    .split(/\s+/)
    .join('-')}`
}


(
  text,
  config,
  profile,
  payload
) => {
  const options = profile.dicts.all.longman.options
  return fetchDirtyDOM(
    'http://www.ldoceonline.com/dictionary/' +
      text.toLocaleLowerCase().replace(/[^A-Za-z0-9]+/g, '-')
  )
    .catch(handleNetWorkError)
    .then(doc => handleDOM(doc, options))
}


doc => handleDOM(doc, options)


$speaker => {
      const mp3 = $speaker.dataset.srcMp3
      if (mp3) {
        const parent = $speaker.parentElement
        $speaker.replaceWith(getStaticSpeaker(mp3))
        if (parent && parent.classList.contains('EXAMPLE')) {
          parent.classList.add('withSpeaker')
        }
      }
    }


$el => ({
      title: $el.title,
      rank: $el.textContent || ''
    })


$pron => {
      let lang = 'us'
      const title = $pron.title
      if (title.includes('British')) {
        lang = 'uk'
      }
      const pron = $pron.getAttribute('data-src-mp3') || ''

      audio[lang] = pron
      entry.prons.push({ lang, pron })
    }


$sen =>
      getInnerHTML(HOST, $sen)


$exa => getInnerHTML(HOST, $exa)


export interface LongmanResultEntry {
  title: {
    HWD: string
    HYPHENATION: string
    HOMNUM: string
  }
  senses: HTMLString[]
  prons: Array<{
    lang: string
    pron: string
  }>
  topic?: {
    title: string
    href: string
  }
  phsym?: string
  level?: {
    rate: number
    title: string
  }
  freq?: Array<{
    title: string
    rank: string
  }>
  pos?: string
  collocations?: HTMLString
  grammar?: HTMLString
  thesaurus?: HTMLString
  examples?: HTMLString[]
}


export interface LongmanResultLex {
  type: 'lex'
  bussinessFirst: boolean
  contemporary: LongmanResultEntry[]
  bussiness: LongmanResultEntry[]
  wordfams?: HTMLString
}


export interface LongmanResultRelated {
  type: 'related'
  list: HTMLString
}


export type LongmanResult = LongmanResultLex | LongmanResultRelated


type LongmanSearchResult = DictSearchResult<LongmanResult>


type LongmanSearchResultLex = DictSearchResult<LongmanResultLex>


type LongmanSearchResultRelated = DictSearchResult<LongmanResultRelated>


(url: any) => axios.get(url)


() => {
  const card: CSSProperties = {
    backgroundColor: '#FCFCFC',
    borderRadius: '18px',
    padding: '21px 20px 27px',
  };

  const txtPrice: CSSProperties = {
    color: '#FF6F61',
    fontSize: '28px',
    lineHeight: '36px',
    fontFamily: 'Boon-500',
  };

  const btnCheckout: CSSProperties = {
    backgroundColor: '#FF6F61',
    borderRadius: '10px',
    width: 295,
    height: 48,
    fontSize: '14px',
    lineHeight: '18px',
    fontFamily: 'Boon-600',
  };

  const txtTotal: CSSProperties = {
    fontFamily: 'Boon-500',
    fontSize: '20px',
    lineHeight: '26px',
    color: '#484848',
    marginBottom: '24px',
    marginRight: '10px',
  };

  const cart = useSelector((state: RootState) => state.rootReducer.cart);

  let sumItem = [];
  let totalItem = [];
  cart.forEach((e, index) => {
    let aPrice = +e.price * e.quantity;
    sumItem.push(aPrice);
    totalItem.push(e.quantity);
  });
  // console.log('sumItem', sumItem);

  let sumPrice: number = sumItem.reduce((a, b) => a + b, 0);
  let sumQuantity: number = totalItem.reduce((a, b) => a + b, 0);
  // console.log('sumPrice', sumPrice, 'sumItem', sumItem)

  const { data, error } = useSWR(
    `https://cc-mock-api.herokuapp.com/product`,
    fetcher
  );

  if (error) return
failed to load
;
  if (!data)
    return (
      <div style={{ padding: '50px 0 100px', color: '#484848' }}


(state: RootState) => state.rootReducer.cart


(e, index) => {
    let aPrice = +e.price * e.quantity;
    sumItem.push(aPrice);
    totalItem.push(e.quantity);
  }


(item) => (
                <div key={item._id}


<T extends Props>(props: T) => {
    // @dts-jest:pass:snap -> Pick<T, { [Key in keyof T]: T[Key] extends number ? Key : never; }[keyof T]>
    testType<PickByValue<T, number>>();
  }


<T extends Props>(props: T) => {
    // @dts-jest:pass:snap -> Pick<T, { [Key in keyof T]: [number] extends [T[Key]] ? [T[Key]] extends [T[Key] & number] ? Key : never : never; }[keyof T]>
    testType<PickByValueExact<T, number>>();
  }


<T extends Props>(props: T) => {
    // @dts-jest:pass:snap -> Pick<T, SetDifference<keyof T, "age">>
    testType<Omit<T, 'age'>>();

    const { age, ...rest } = props;
    // @dts-jest:pass:snap -> any
    const result: Omit<T, 'age'> = rest;
  }


<T extends Props>(props: T) => {
    // @dts-jest:pass:snap -> Pick<T, { [Key in keyof T]: T[Key] extends string | boolean ? never : Key; }[keyof T]>
    testType<OmitByValue<T, string | boolean>>();
  }


<T extends Props>(props: T) => {
    // @dts-jest:pass:snap -> Pick<T, { [Key in keyof T]: [number] extends [T[Key]] ? [T[Key]] extends [T[Key] & number] ? never : Key : Key; }[keyof T]>
    testType<OmitByValueExact<T, number>>();
  }


<T extends Props>(props: T) => {
    const { age, ...rest } = props;
    // @dts-jest:pass:snap -> any
    const result: Intersection<T, Omit<T, 'age'>> = rest;
  }


<T extends Props>(props: T) => {
    const { age, ...rest } = props;
    // @dts-jest:pass:snap -> any
    const result: Diff<T, Pick<T, 'age'>> = rest;
  }


<T extends Props>(props: T) => {
    const { age, ...rest } = props;
    // @dts-jest:pass:snap -> any
    const result: Subtract<T, Pick<T, 'age'>> = rest;
  }


<T extends Props>(props: T) => {
    const { age, ...rest } = props;
    // @dts-jest:pass:snap -> any
    const result: Overwrite<Omit<T, 'age'>, T> = rest;
  }


<T extends Props>(props: T) => {
    const { age, ...rest } = props;
    // @dts-jest:pass:snap -> any
    const result: Assign<{}, Omit<T, 'age'>> = rest;
  }


/**
 * Fixtures
 */
type Props = { name: string; age: number; visible: boolean };


type DefaultProps = { age: number };


type NewProps = { age: string; other: string };


type MixedProps = {
  name: string;
  setName: (name: string) => void;
  someKeys?: string;
  someFn?: (...args: any) => any;
};


type ReadWriteProps = { readonly a: number; b: string };


type RequiredOptionalProps = {
  req: number;
  reqUndef: number | undefined;
  opt?: string;
  optUndef?: string | undefined;
};


type NestedProps = {
    first: {
      second: {
        name: string;
      };
    };
  };


type NestedArrayProps = {
    first: {
      second: Array<{ name: string }>;
    };
  };


type NestedFunctionProps = {
    first: {
      second: (value: number) => string;
    };
  };


type NestedProps = {
    first?: {
      second?: {
        name?: string | null;
      };
    };
  };


type NestedArrayProps = {
    first?: {
      second?: Array<{ name?: string | null } | undefined>;
    };
  };


type NestedFunctionProps = {
    first?: {
      second?: (value: number) => string;
    };
  };


type NestedProps = {
    first?: null | {
      second?: null | {
        name?: null | string;
      };
    };
  };


type NestedArrayProps = {
    first?: null | {
      second?: Array<{ name?: string | null } | undefined | null>;
    };
  };


type NestedFunctionProps = {
    first?: null | {
      second?: (value: number) => string;
    };
  };


@Module({
  imports: [],
  controllers: [AppController, BookController],
  providers: [AppService, BookService],
})
export class AppModule {}


export function isModClassName(className: string) {
  const isMod =
    (className.startsWith('/Game/') &&
      !className.startsWith('/Game/FactoryGame/')) ||
    (!className.startsWith('/Game/') && !className.startsWith('/Script/')) ||
    modClassNamePrefixes.some((prefix) => className.startsWith(prefix));
  if (isMod) {
    console.log(`Mod: ${className}`);
  }
  return isMod;
}


(prefix) => className.startsWith(prefix)


export interface ModelConfig {
  model: string;
  color: number;
  // true if this actor can be painted with the color gun
  paintable: Paintable;
  powerLineOffset?: { x: number; y: number; z: number };
}


export enum Paintable {
  FALSE,
  TRUE,
  NOT_SLOT0, // Slot 0 is not used to paint, but default color is used instead
}


export function TaskList() {
  const [tasks, setTasks] = useState<Task[]>([]);
  const [newTaskTitle, setNewTaskTitle] = useState('');

  function handleCreateNewTask() {
    // Crie uma nova task com um id random, não permita criar caso o título seja vazio.
    if(!newTaskTitle) return;

    const newTask = {
      id: Math.random(),
      title: newTaskTitle,
      isCOmplete: false
    }

    setTasks([...tasks, newTask]);
    setNewTaskTitle('');
  }

  function handleToggleTaskCompletion(id: number) {
    // Altere entre `true` ou `false` o campo `isComplete` de uma task com dado ID
    const completedTask = tasks.map(task => task.id === id ? {
      ...task,
      isComplete: !task.isComplete
    } : task);

    setTasks(completedTask)
  }

  function handleRemoveTask(id: number) {
    // Remova uma task da listagem pelo ID
    const taskFilter = tasks.filter(task => task.id !== id);

    setTasks(taskFilter)
  }

  return (

Minhas tasks

          <input
            type="text"
            placeholder="Adicionar novo todo"
            onChange={(e) => setNewTaskTitle(e.target.value)}


function handleCreateNewTask() {
    // Crie uma nova task com um id random, não permita criar caso o título seja vazio.
    if(!newTaskTitle) return;

    const newTask = {
      id: Math.random(),
      title: newTaskTitle,
      isCOmplete: false
    }

    setTasks([...tasks, newTask]);
    setNewTaskTitle('');
  }


function handleToggleTaskCompletion(id: number) {
    // Altere entre `true` ou `false` o campo `isComplete` de uma task com dado ID
    const completedTask = tasks.map(task => task.id === id ? {
      ...task,
      isComplete: !task.isComplete
    } : task);

    setTasks(completedTask)
  }


function handleRemoveTask(id: number) {
    // Remova uma task da listagem pelo ID
    const taskFilter = tasks.filter(task => task.id !== id);

    setTasks(taskFilter)
  }


task => task.id === id ? {
      ...task,
      isComplete: !task.isComplete
    } : task


export default class Table<T> extends React.Component<TableProps<T>, TableState<T>> {
    static Column: typeof Column;
    static ColumnGroup: typeof ColumnGroup;
    static propTypes: {
        dataSource: PropTypes.Requireable<any[]>;
        columns: PropTypes.Requireable<any[]>;
        prefixCls: PropTypes.Requireable<string>;
        useFixedHeader: PropTypes.Requireable<boolean>;
        rowSelection: PropTypes.Requireable<object>;
        className: PropTypes.Requireable<string>;
        size: PropTypes.Requireable<"small" | "default" | "middle">;
        loading: PropTypes.Requireable<boolean | object>;
        bordered: PropTypes.Requireable<boolean>;
        onChange: PropTypes.Requireable<(...args: any[]) => any>;
        locale: PropTypes.Requireable<object>;
        dropdownPrefixCls: PropTypes.Requireable<string>;
        sortDirections: PropTypes.Requireable<any[]>;
        getPopupContainer: PropTypes.Requireable<(...args: any[]) => any>;
    };
    static defaultProps: {
        dataSource: never[];
        useFixedHeader: boolean;
        className: string;
        size: "small" | "default" | "middle";
        loading: boolean;
        bordered: boolean;
        indentSize: number;
        locale: {};
        rowKey: string;
        showHeader: boolean;
        sortDirections: string[];
        childrenColumnName: string;
    };
    CheckboxPropsCache: {
        [key: string]: any;
    };
    store: Store;
    columns: ColumnProps<T>[];
    components: TableComponents;
    row: React.ComponentType<any>;
    constructor(props: TableProps<T>);
    componentWillReceiveProps(nextProps: TableProps<T>): void;
    getCheckboxPropsByItem: (item: T, index: number) => any;
    getDefaultSelection(): any[];
    getDefaultPagination(props: TableProps<T>): {};
    getSortOrderColumns(columns?: ColumnProps<T>[]): any;
    getFilteredValueColumns(columns?: ColumnProps<T>[]): any;
    getFiltersFromColumns(columns?: ColumnProps<T>[]): any;
    getDefaultSortOrder(columns?: ColumnProps<T>[]): {
        sortColumn: any;
        sortOrder: any;
    };
    getSortStateFromColumns(columns?: ColumnProps<T>[]): {
        sortColumn: any;
        sortOrder: any;
    };
    getMaxCurrent(total: number): number | undefined;
    getRecordKey: (record: T, index: number) => any;
    getSorterFn(state: TableState<T>): ((a: T, b: T) => number) | undefined;
    getCurrentPageData(): T[];
    getFlatData(): any[];
    getFlatCurrentPageData(): any[];
    getLocalData(state?: TableState<T> | null, filter?: boolean): Array<T>;
    onRow: (prefixCls: string, record: T, index: number) => {
        prefixCls: string;
        store: Store;
        rowKey: any;
        onClick?: ((arg: React.MouseEvent<Element, MouseEvent>) => void) | undefined;
        onDoubleClick?: ((arg: React.MouseEvent<Element, MouseEvent>) => void) | undefined;
        onContextMenu?: ((arg: React.MouseEvent<Element, MouseEvent>) => void) | undefined;
        onMouseEnter?: ((arg: React.MouseEvent<Element, MouseEvent>) => void) | undefined;
        onMouseLeave?: ((arg: React.MouseEvent<Element, MouseEvent>) => void) | undefined;
    };
    setSelectedRowKeys(selectedRowKeys: string[], selectionInfo: SelectionInfo<T>): void;
    generatePopupContainerFunc: (getPopupContainer: ((triggerNode: HTMLElement) => HTMLElement) | undefined) => ((triggerNode: HTMLElement) => HTMLElement) | undefined;
    handleFilter: (column: ColumnProps<T>, nextFilters: string[]) => void;
    handleSelect: (record: T, rowIndex: number, e: CheckboxChangeEvent) => void;
    handleRadioSelect: (record: T, rowIndex: number, e: RadioChangeEvent) => void;
    handleSelectRow: (selectionKey: string, index: number, onSelectFunc: SelectionItemSelectFn) => void;
    handlePageChange: (current: number, ...otherArguments: any[]) => void;
    handleShowSizeChange: (current: number, pageSize: number) => void;
    toggleSortOrder(column: ColumnProps<T>): void;
    hasPagination(props?: any): boolean;
    isFiltersChanged(filters: TableStateFilters): boolean;
    isSortColumn(column: ColumnProps<T>): boolean;
    prepareParamsArguments(state: any): PrepareParamsArgumentsReturn<T>;
    findColumn(myKey: string | number): undefined;
    createComponents(components?: TableComponents, prevComponents?: TableComponents): void;
    recursiveSort(data: T[], sorterFn: (a: any, b: any) => number): T[];
    renderExpandIcon: (prefixCls: string) => ({ expandable, expanded, needIndentSpaced, record, onExpand, }: ExpandIconProps<T>) => JSX.Element | null;
    renderPagination(prefixCls: string, paginationPosition: string): JSX.Element | null;
    renderSelectionBox: (type: "checkbox" | "radio" | undefined) => (_: any, record: T, index: number) => JSX.Element;
    renderRowSelection({ prefixCls, locale, getPopupContainer, }: {
        prefixCls: string;
        locale: TableLocale;
        getPopupContainer: TableProps<T>['getPopupContainer'];
    }): ColumnProps<T>[];
    renderColumnsDropdown({ prefixCls, dropdownPrefixCls, columns, locale, getPopupContainer, }: {
        prefixCls: string;
        dropdownPrefixCls: string;
        columns: ColumnProps<T>[];
        locale: TableLocale;
        getPopupContainer: TableProps<T>['getPopupContainer'];
    }): any[];
    renderColumnTitle(title: ColumnProps<T>['title']): React.ReactNode;
    renderTable: ({ prefixCls, renderEmpty, dropdownPrefixCls, contextLocale, getPopupContainer: contextGetPopupContainer, }: {
        prefixCls: string;
        renderEmpty: (componentName?: string | undefined) => React.ReactNode;
        dropdownPrefixCls: string;
        contextLocale: TableLocale;
        getPopupContainer: ((triggerNode: HTMLElement) => HTMLElement) | undefined;
    }) => JSX.Element;
    renderComponent: ({ getPrefixCls, renderEmpty, getPopupContainer }: ConfigConsumerProps) => JSX.Element;
    render(): JSX.Element;
}


componentWillReceiveProps(nextProps: TableProps<T>): void;


getDefaultSelection(): any[];


getDefaultPagination(props: TableProps<T>): {};


getSortOrderColumns(columns?: ColumnProps<T>[]): any;


getFilteredValueColumns(columns?: ColumnProps<T>[]): any;


getFiltersFromColumns(columns?: ColumnProps<T>[]): any;


getDefaultSortOrder(columns?: ColumnProps<T>[]): {
        sortColumn: any;
        sortOrder: any;
    };


getSortStateFromColumns(columns?: ColumnProps<T>[]): {
        sortColumn: any;
        sortOrder: any;
    };


getMaxCurrent(total: number): number | undefined;


getSorterFn(state: TableState<T>): ((a: T, b: T) => number) | undefined;


getCurrentPageData(): T[];


getFlatData(): any[];


getFlatCurrentPageData(): any[];


getLocalData(state?: TableState<T> | null, filter?: boolean): Array<T>;


setSelectedRowKeys(selectedRowKeys: string[], selectionInfo: SelectionInfo<T>): void;


toggleSortOrder(column: ColumnProps<T>): void;


hasPagination(props?: any): boolean;


isFiltersChanged(filters: TableStateFilters): boolean;


isSortColumn(column: ColumnProps<T>): boolean;


prepareParamsArguments(state: any): PrepareParamsArgumentsReturn<T>;


findColumn(myKey: string | number): undefined;


createComponents(components?: TableComponents, prevComponents?: TableComponents): void;


recursiveSort(data: T[], sorterFn: (a: any, b: any) => number): T[];


renderPagination(prefixCls: string, paginationPosition: string): JSX.Element | null;


renderRowSelection({ prefixCls, locale, getPopupContainer, }: {
        prefixCls: string;
        locale: TableLocale;
        getPopupContainer: TableProps<T>['getPopupContainer'];
    }): ColumnProps<T>[];


renderColumnsDropdown({ prefixCls, dropdownPrefixCls, columns, locale, getPopupContainer, }: {
        prefixCls: string;
        dropdownPrefixCls: string;
        columns: ColumnProps<T>[];
        locale: TableLocale;
        getPopupContainer: TableProps<T>['getPopupContainer'];
    }): any[];


renderColumnTitle(title: ColumnProps<T>['title']): React.ReactNode;


//% block="move $leftrightupdown by $steps"
//% group="Moving"
/**
 * moves what blocks you see in the direction you pick
*/
export function move (leftrightupdown: LeftRightUpDown, steps: number) {
    for(let i = 0; i < steps; i++) {
        move_(leftrightupdown, 1)
    }
    if (not(disabled_portal == "")) {
        portals_two_way.push(disabled_portal)
        disabled_portal = ""
    }
    show()
}


function move_ (leftrightupdown: LeftRightUpDown, steps: number) {
    if (leftrightupdown == LeftRightUpDown.Left) {
        if (not(xy_pos(XY.X) - steps < edge_o_world[0])) {
            leftright_difference += steps
        }
    } else if (leftrightupdown == LeftRightUpDown.Right) {
        if (not(xy_pos(XY.X) + steps > edge_o_world[1])) {
            leftright_difference += 0 - steps
        }
    } else if (leftrightupdown == LeftRightUpDown.Up) {
        if (not(xy_pos(XY.Y) - steps < edge_o_world[2])) {
            updown_difference += steps
        }
    } else if (leftrightupdown == LeftRightUpDown.Down) {
        if (not(xy_pos(XY.Y) + steps > edge_o_world[3])) {
            updown_difference += 0 - steps
        }
    }
}


function not (bool: boolean) {
    return (!(bool))
}


//% block="move %leftright and %updown by $steps"
//% group="Moving"
/**
 * self-explanatory
*/
export function move_diagonally (leftright: LeftRight, updown: UpDown, steps: number) {
    for(let i = 0; i < steps; i++) {
        move__diagonally(leftright, updown, 1)
    }
    if (not(disabled_portal == "")) {
        portals_two_way.push(disabled_portal)
        disabled_portal = ""
    }
    show()
}


function move__diagonally (leftright: LeftRight, updown: UpDown, steps: number) {
    if (leftright == LeftRight.Left) {
        if (not(xy_pos(XY.X) - steps < edge_o_world[0])) {
            leftright_difference += steps
        }
    } else if (leftright == LeftRight.Right) {
        if (not(xy_pos(XY.X) + steps > edge_o_world[1])) {
            leftright_difference += 0 - steps
        }
    }
    if (updown == UpDown.Up) {
        if (not(xy_pos(XY.Y) + steps > edge_o_world[3])) {
            updown_difference += steps
        }
    } else if (updown == UpDown.Down) {
        if (not(xy_pos(XY.Y) - steps < edge_o_world[2])) {
            updown_difference += 0 - steps
        }
    }
}


//% block="draw the world"
//% group="Diplaying"
/**
 * updates the display of the world so that it moves appropriately
*/
export function show () {
    basic.clearScreen()
    for (let index = 0; index < world.length; index++) {
        led.plot(world_blocks(XY.X, index) + leftright_difference, world_blocks(XY.Y, index) + updown_difference)
    }
}


//% block="add a circle at x: $x y: $y with a radius of $radius $filled"
//% group="Creating & Destroying"
//% radius.fieldOptions.precision=1
//% inlineInputMode=inline
/**
 * adds a circle
*/
export function add_circle (x: number, y: number, radius: number, filled: FilledUn) {
    if (filled == FilledUn.Filled) {
        diam = (radius * 2) + 1
        for(let i = 0; i < diam; i++) {
            add_by(ColumnRow.Row, y + radius - i, 0 - radius + x, radius + x)
        }
        return
    }
    if (filled == FilledUn.Unfilled) {
        add_stuff(x, y, radius)
    }
}


function add_stuff (x: number, y: number, radius: number) {
    let diam_stuff = (radius * 2) + 1
    let simple = diam_stuff - 2
    for(let i = 0; i < diam_stuff; i++) {
        add(radius + x - i, y + radius)
    }
    for(let i = 0; i < diam_stuff; i++) {
        add(radius + x - i, y - radius)
    }
    for(let i = 0; i < simple; i++) {
        add(x - radius, (y + i - simple) + radius)
    }
    for(let i = 0; i < simple; i++) {
        add(x + radius, (y + i - simple) + radius)
    }
}


function destroy_stuff (x: number, y: number, radius: number) {
    let diam_stuff = (radius * 2) + 1
    let simple = diam_stuff - 2
    for(let i = 0; i < diam_stuff; i++) {
        destroy(radius + x - i, y + radius)
    }
    for(let i = 0; i < diam_stuff; i++) {
        destroy(radius + x - i, y - radius)
    }
    for(let i = 0; i < simple; i++) {
        destroy(x - radius, (y + i - simple) + radius)
    }
    for(let i = 0; i < simple; i++) {
        destroy(x + radius, (y + i - simple) + radius)
    }
}


//% block="add a portal at x: $x y: $y that goes to x: $tox y: $toy and is $_type"
//% group="Creating & Destroying"
//% inlineInputMode=inline
/**
 * adds a portal
*/
export function add_portal (x: number, y: number, tox: number, toy: number, _type: OneTwo) {
    if (_type == OneTwo.OneWay) {
        portals_one_way.push("" + encode(x) + encode(y) + encode(tox) + encode(toy))
    } else if (_type == OneTwo.TwoWay) {
        portals_two_way.push("" + encode(x) + encode(y) + encode(tox) + encode(toy))
    }
}


//% block="set the world to $arr"
//% group="Dangerous things that can mess up your world"
//% inlineInputMode=inline
/**
 * sets the world to this array
*/
export function set_world (arr: string[]) {
    world = arr
}


//% block="destroy the portal at x: $x y: $y that goes to x: $tox y: $toy and is $_type"
//% group="Creating & Destroying"
//% inlineInputMode=inline
/**
 * adds a portal
*/
export function destroy_portal (x: number, y: number, tox: number, toy: number, _type: OneTwo) {
    if (_type == OneTwo.OneWay) {
        portals_one_way.removeAt(portals_one_way.indexOf("" + encode(x) + encode(y) + encode(tox) + encode(toy)))
    } else if (_type == OneTwo.TwoWay) {
        portals_two_way.removeAt(portals_two_way.indexOf("" + encode(x) + encode(y) + encode(tox) + encode(toy)))
    }
}


//% block="destroy a circle at x: $x y: $y with a radius of $radius $filled"
//% group="Creating & Destroying"
//% radius.fieldOptions.precision=1
//% inlineInputMode=inline
/**
 * destroys a circle
*/
export function destroy_circle (x: number, y: number, radius: number, filled: FilledUn) {
    if (filled == FilledUn.Filled) {
        diam = (radius * 2) + 1
        for(let i = 0; i < diam; i++) {
            destroy_by(ColumnRow.Row, y + radius - i, 0 - radius + x, radius + x)
        }
        return
    }
    if (filled == FilledUn.Unfilled) {
        destroy_stuff(x, y, radius)
    }
}


//% block="$xy position"
//% group="Position"
/**
 * gives you the x or y position you are at according to what you see
*/
export function xy_pos (xy: XY) {
    if (xy == XY.X) {
        return 2 - leftright_difference
    } else if (xy == XY.Y) {
        return 2 - updown_difference
    }
    return 0
}


//% block="spawnpoint myself at the current position"
//% group="Spawnpoint"
/**
 * sets your spawn point to the position you are at
*/
export function spawnpoint () {
    spawn_x = xy_pos(XY.X)
    spawn_y = xy_pos(XY.Y)
}


//% block="set spawnpoint to x: $x y: $y"
//% group="Spawnpoint"
//% x.min=-9 x.max=99
//% y.min=-9 y.max=99
/**
 * sets your spawn point to x and y
*/
export function spawnpoint_at_pos (x: number, y: number) {
    spawn_x = x
    spawn_y = y
}


//% block="Destroy all blocks"
//% group="Creating & Destroying"
/**
 * removes all blocks from the world
*/
export function destroy_all() {
    for(let i = 0; i < world.length; i++) {
        world.pop()
    }
}


//% block="add $details via $xy, at $at_xy"
//% group="Creating & Destroying"
//% details.defl="0000000000"
//% inlineInputMode=inline
/**
 * adds stuff led display style (post in issues on github if you do not understand)
*/
export function add_advanced (xy: XY, at_xy: number, details: string) {
    for(let i = 0; i < 109 - details.length; i++) {
        details = details + "0"
    }
    for(let i2 = 0; i2 < world.length; i2++) {
        if (world_blocks(xy, i2) == at_xy) {
            world.removeAt(i2)
            i2--
        }
    }
    for(let i3 = -9; i3 < 100; i3++) {
        if (parseFloat(details.charAt(i3 + 9)) == 1) {
            if (xy == XY.X) {
                add(i3, at_xy)
            } else if (xy == XY.Y)  {
                add(at_xy, i3)
            }
        }
    }
}


//% block="destroy block at x: $x y: $y"
//% group="Creating & Destroying"
//% x.min=-9 x.max=99
//% y.min=-9 y.max=99
/**
 * destroys the blocks at x and y
*/
export function destroy (x: number, y: number) {
    if (block_detect(parseFloat(encode(x)), parseFloat(encode(y)))) {
        world.removeAt(find(x, y))
    }
}


//% block="which block is at x: $x y: $y"
//% group="Position"
//% x.min=-9 x.max=99
//% y.min=-9 y.max=99
/**
 * finds where the block is in the array
*/
export function find (x: number, y: number) {
    return world.indexOf("" + encode(x) + encode(y))
}


//% block="go to spawnpoint"
//% group="Position"
/**
 * goes to your spawn point
*/
export function spawn () {
    goto(spawn_x, spawn_y)
    if (not(disabled_portal == "")) {
        portals_two_way.push(disabled_portal)
        disabled_portal = ""
    }
}


//% block="go to x: $x y: $y"
//% group="Position"
//% x.min=-9 x.max=99
//% y.min=-9 y.max=99
/**
 * goes to x and y
*/
export function goto (x: number, y: number) {
    updown_difference = 2 - y
    leftright_difference = 2 - x
    if (not(disabled_portal == "")) {
        portals_two_way.push(disabled_portal)
        disabled_portal = ""
    }
    show()
}


//% block="number of blocks in the world"
//% group="Position"
/**
 * gives you the length of the array
*/
export function world_blocks_detect () {
    return world.length
}


//% block="is there a block at x: $x_pos y: $y_pos"
//% group="Detect"
//% x_pos.min=-9 x_pos.max=99
//% y_pos.min=-9 y_pos.max=99
/**
 * checks whether or not there is a block at x and y
*/
export function block_detect (x_pos: number, y_pos: number) {
    return find(x_pos, y_pos) != -1
}


//% block="world $xy coordinate at item $place"
//% group="Position"
//% place.min=1 place.max=11881
/**
 * gives you the x or y of an item in the array
*/
export function world_blocks (xy: XY, place: number) {
    if (xy == XY.X) {
        return parseFloat(world[place].substr(0, 2))
    } else if (xy = XY.Y) {
        return parseFloat(world[place].substr(2, 2))
    }
    return -13
}


//% block="set edge of the world to minimum x: $min_x maximum x: $max_x minimum y: $min_y maximum y: $max_y"
//% group="Position"
//% inlineInputMode=inline
/**
 * sets the edge of the world to points
*/
export function edge (min_x: number, max_x: number, min_y: number, max_y: number) {
    edge_o_world = [min_x, max_x, min_y, max_y]
}


//% block="world (array)"
//% group="Position"
/**
 * gives you do the array that you can do whatever you want with
*/
export function all_world_blocks () {
    return world
}


//% block="destroy by $columnrow at $xy from $from_xy to $to_xy "
//% group="Creating & Destroying"
//% xy.min=-9 xy.max=99
//% from_xy.min=-9 from_xy.max=99
//% to_xy.min=-9 to_xy.max=99
//% inlineInputMode=inline
/**
 * self-explanatory
*/
export function destroy_by (columnrow: ColumnRow, xy: number, from_xy: number, to_xy: number) {
    if (columnrow == ColumnRow.Column) {
        for (let index2 = from_xy; index2 <= to_xy; index2++) {
            destroy(xy, index2)
        }
    } else if (columnrow == ColumnRow.Row) {
        for (let index3 = from_xy; index3 <= to_xy; index3++) {
            destroy(index3, xy)
        }
    }
}


//% block="add by $columnrow at $xy from $from_xy to $to_xy "
//% group="Creating & Destroying"
//% xy.min=-9 xy.max=99
//% from_xy.min=-9 from_xy.max=99
//% to_xy.min=-9 to_xy.max=99
//% inlineInputMode=inline
/**
 * self-explanatory
*/
export function add_by (columnrow: ColumnRow, xy: number, from_xy: number, to_xy: number) {
    if (columnrow == ColumnRow.Column) {
        for (let index2 = from_xy; index2 <= to_xy; index2++) {
            add(xy, index2)
        }
    } else if (columnrow == ColumnRow.Row) {
        for (let index3 = from_xy; index3 <= to_xy; index3++) {
            add(index3, xy)
        }
    }
}


//% block="add x $x and y $y to the world"
//% group="Creating & Destroying"
//% x.min=-9 x.max=99
//% y.min=-9 y.max=99
/**
 * self-explanatory
*/
export function add (x: number, y: number) {
    if (not(block_detect(parseFloat(encode(x)), parseFloat(encode(y))))) {
        world.push("" + encode(x) + encode(y))
    }
}


function decode (txt: string) {
    return parseFloat(txt)
}


function c1 (txt: string) {
    return decode(txt.substr(0, 2)) == xy_pos(XY.X) && decode(txt.substr(2, 2)) == xy_pos(XY.Y)
}


function c21 (txt: string) {
    return decode(txt.substr(0, 2)) == xy_pos(XY.X) && decode(txt.substr(2, 2)) == xy_pos(XY.Y)
}


function c22 (txt: string) {
    return decode(txt.substr(4, 2)) == xy_pos(XY.X) && decode(txt.substr(6, 2)) == xy_pos(XY.Y)
}


function do_ur_magic1 (txt: string) {
    if (c1(txt)) {
        goto(decode(txt.substr(4, 2)), decode(txt.substr(6, 2)))
    }
}


function do_ur_magic2 (txt: string) {
    if (c21(txt)) {
        goto(decode(txt.substr(4, 2)), decode(txt.substr(6, 2)))
    } else if (c22(txt)) {
        goto(decode(txt.substr(0, 2)), decode(txt.substr(2, 2)))
    } else {
        return
    }
    disabled_portal = txt
    portals_two_way.removeAt(portals_two_way.indexOf(txt))
}


function encode (oof: number) {
    temp_txt = convertToText(oof)
    for (let index4 = 0; index4 < 2 - temp_txt.length; index4++) {
        temp_txt = "0" + temp_txt
    }
    return temp_txt
}


enum LeftRightUpDown {
    //% block="Left"
    Left,

    //% block="Right"
    Right,

    //% block="Up"
    Up,

    //% block="Down"
    Down,
}


enum UpDown {
    //% block="Up"
    Up,

    //% block="Down"
    Down,
}


enum LeftRight {
    //% block="Left"
    Left,

    //% block="Right"
    Right,
}


enum ColumnRow {
    //% block="Column"
    Column,

    //% block="Row"
    Row,
}


enum XY {
    //% block="X"
    X,

    //% block="Y"
    Y,
}


enum FilledUn {
    //% block="Filled"
    Filled,

    //% block="Unfilled"
    Unfilled,
}


enum OneTwo {
    //% block="one way"
    OneWay,

    //% block="two way"
    TwoWay,
}


(router: Router): ((name: string) => string[]) => (
  name: string,
): string[] => {
  const { routes } = router.getDependencies();
  const segments = name.split('.');
  const path = [];

  return segments.reduce((acc, segment): string[] => {
    path.push(segment);
    const route = getRoute(path.join('.'), routes);

    return [...acc, ...(route.chunks || [])];
  }, []);
}


(
  name: string,
): string[] => {
  const { routes } = router.getDependencies();
  const segments = name.split('.');
  const path = [];

  return segments.reduce((acc, segment): string[] => {
    path.push(segment);
    const route = getRoute(path.join('.'), routes);

    return [...acc, ...(route.chunks || [])];
  }, []);
}


(acc, segment): string[] => {
    path.push(segment);
    const route = getRoute(path.join('.'), routes);

    return [...acc, ...(route.chunks || [])];
  }


(hre) => {
  if (!hre.deployments) {
    hre.deployments = new DeploymentsExtensionMock()
  }
}


interface MainSectionProps {
    todos: Seq.Set<TodoItem>;
    areAllComplete: boolean;
    setState: StateSetter<TodoAppState>;
}


export function withSDK<T extends Bridge = Bridge>(Base: IConstructor<T>) {
  const BaseClass = Base as typeof Bridge

  // 如果不是手机端, 就直接使用 `浏览器` API
  if (window.isPC) {
    return BaseClass
  }

  class HybridSDK extends BaseClass implements IBridge {
    hybridSDK: any = {}

    async initializeSDK(): Promise<void> {
      const { sdkName } = qs.parse(window.location.search.slice(1))
      if (sdkName === 'kk') {
        const { sdk } = await import('./withKKSDK')
        this.hybridSDK = sdk
        this.showTitleBar()
      }
    }

    async close(): Promise<void> {
      this.hybridSDK.close()
    }

    scan(props: IScanProps = {}): Promise<string> {
      if (this.hybridSDK.scan) {
        return this.hybridSDK.scan(props)
      }
      return super.scan(props)
    }

    setTitle(title: string): Promise<void> {
      if (this.hybridSDK.setTilte) {
        return this.hybridSDK.setTilte(title)
      }
      return super.setTitle(title)
    }

    async openLink(link: string, props: ILinkProps = {}): Promise<void> {
      if (props.iframe) {
        return super.openURLInIframe(link, props)
      }
      if (this.hybridSDK.openLink) {
        return this.hybridSDK.openLink(link, props)
      }
      return super.openLink(link, props)
    }

    async share(props: IShareProps): Promise<void> {
      if (this.hybridSDK.share) {
        return this.hybridSDK.share(props)
      }
      return super.share(props)
    }

    async preview(url: string, fileName: string = ''): Promise<any> {
      if (this.hybridSDK.preview) {
        return this.hybridSDK.preview(url, fileName)
      }
      return super.preview(url, fileName)
    }

    async showTitleBar() {
      if (this.hybridSDK.showTitleBar) {
        this.hybridSDK.showTitleBar()
      }
    }
  }

  return (HybridSDK as unknown) as IConstructor<T>
}


class HybridSDK extends BaseClass implements IBridge {
    hybridSDK: any = {}

    async initializeSDK(): Promise<void> {
      const { sdkName } = qs.parse(window.location.search.slice(1))
      if (sdkName === 'kk') {
        const { sdk } = await import('./withKKSDK')
        this.hybridSDK = sdk
        this.showTitleBar()
      }
    }

    async close(): Promise<void> {
      this.hybridSDK.close()
    }

    scan(props: IScanProps = {}): Promise<string> {
      if (this.hybridSDK.scan) {
        return this.hybridSDK.scan(props)
      }
      return super.scan(props)
    }

    setTitle(title: string): Promise<void> {
      if (this.hybridSDK.setTilte) {
        return this.hybridSDK.setTilte(title)
      }
      return super.setTitle(title)
    }

    async openLink(link: string, props: ILinkProps = {}): Promise<void> {
      if (props.iframe) {
        return super.openURLInIframe(link, props)
      }
      if (this.hybridSDK.openLink) {
        return this.hybridSDK.openLink(link, props)
      }
      return super.openLink(link, props)
    }

    async share(props: IShareProps): Promise<void> {
      if (this.hybridSDK.share) {
        return this.hybridSDK.share(props)
      }
      return super.share(props)
    }

    async preview(url: string, fileName: string = ''): Promise<any> {
      if (this.hybridSDK.preview) {
        return this.hybridSDK.preview(url, fileName)
      }
      return super.preview(url, fileName)
    }

    async showTitleBar() {
      if (this.hybridSDK.showTitleBar) {
        this.hybridSDK.showTitleBar()
      }
    }
  }


async initializeSDK(): Promise<void> {
      const { sdkName } = qs.parse(window.location.search.slice(1))
      if (sdkName === 'kk') {
        const { sdk } = await import('./withKKSDK')
        this.hybridSDK = sdk
        this.showTitleBar()
      }
    }


async close(): Promise<void> {
      this.hybridSDK.close()
    }


scan(props: IScanProps = {}): Promise<string> {
      if (this.hybridSDK.scan) {
        return this.hybridSDK.scan(props)
      }
      return super.scan(props)
    }


setTitle(title: string): Promise<void> {
      if (this.hybridSDK.setTilte) {
        return this.hybridSDK.setTilte(title)
      }
      return super.setTitle(title)
    }


async openLink(link: string, props: ILinkProps = {}): Promise<void> {
      if (props.iframe) {
        return super.openURLInIframe(link, props)
      }
      if (this.hybridSDK.openLink) {
        return this.hybridSDK.openLink(link, props)
      }
      return super.openLink(link, props)
    }


async share(props: IShareProps): Promise<void> {
      if (this.hybridSDK.share) {
        return this.hybridSDK.share(props)
      }
      return super.share(props)
    }


async preview(url: string, fileName: string = ''): Promise<any> {
      if (this.hybridSDK.preview) {
        return this.hybridSDK.preview(url, fileName)
      }
      return super.preview(url, fileName)
    }


async showTitleBar() {
      if (this.hybridSDK.showTitleBar) {
        this.hybridSDK.showTitleBar()
      }
    }


@NgModule({
    declarations: [
        HomepageComponent,
        SupportBotComponent,
        DynamicComponent,
        TextMessageComponent,
        LoadingMessageComponent,
        MainMenuComponent,
        ButtonMessageComponent,
        HealthCheckComponent,
        TalkToAgentMessageComponent,
        FeedbackComponent,
        SolutionsMessageComponent,
        GraphMessageComponent,
        ProblemStatementMessageComponent,
        CategoryMenuComponent,
        DetectorSummaryComponent,
        DocumentSearchComponent,
        DocumentSearchResultsComponent,
        HealthCheckV3Component
    ],
    imports: [
        SharedModule,
        AvailabilityModule,
        SolutionsModule,
        SharedV2Module,
        DiagnosticDataModule
    ],
    exports: [
        HomepageComponent,
        SupportBotComponent,
        CategoryMenuComponent,
        DetectorSummaryComponent
    ],
    providers: [
        StartupMessages,
        MainMenuMessageFlow,
        HealthCheckMessageFlow,
        FeedbackMessageFlow,
        CpuAnalysisChatFlow,
        MessageProcessor,
        AvailabilityPerformanceFlow,
        LinuxAvailabilityPerformanceFlow,
        GenericCategoryFlow
    ]
})
export class SupportBotModule {
}


x => x === waypoint.name


(unboughtArticle) => {
                console.log(`${unboughtArticle} couldn't be accquired`)
                npc.scene.gameLoop.customerHappiness--
            }


(unpayedArticle) => {
                    console.log(`${unpayedArticle} was returned`)
                    npc.scene.gameLoop.money--
                    if (npc.scene.gameLoop.customerHappiness > 0) {
                        npc.scene.gameLoop.customerHappiness--
                    }
                    npc.scene.shelves[unpayedArticle].quantity++
                }


(pointer: Phaser.Input.Pointer) => {
                const pointerLocation = npc.scene.input.activePointer.positionToCamera(npc.scene.cameras.main) as Phaser.Math.Vector2;
                if (pointer.leftButtonDown()) {
                    if (npc.scene.player.interactionRadius.circle.contains(pointerLocation.x, pointerLocation.y)) {
                        switch (npc.scene.currentTool) {
                            case Tools.STOP:
                                npc.npc_state.stopped = !npc.npc_state.stopped
                                break;
                            case Tools.CASH:
                                delete npc.npc_state.meta.waitForCashierUntil
                                if (!npc.npc_state.hasPayed && npc.npc_state.waitingInLine) {
                                    npc.npc_state.shoppingBasket.forEach((boughtArticle) => {
                                        console.log(`${boughtArticle} has been sold`)
                                        npc.scene.gameLoop.money += 10
                                        if (npc.scene.gameLoop.customerHappiness < 100) {
                                            npc.scene.gameLoop.customerHappiness++
                                        }
                                    })
                                    npc.npc_state.hasPayed = true
                                    npc.npc_state.waitingInLine = false
                                }
                                break;
                            case Tools.FORCEOUT:
                                if (npc.scene.store.rectangle.contains((npc.sprite.body as Phaser.Physics.Arcade.Body).x, (npc.sprite.body as Phaser.Physics.Arcade.Body).y)) {
                                    npc.npc_state.forcedOut = true
                                    npc.npc_state.waypoints = [
                                        npc.scene.checkPoints.FarmUpstate,
                                        npc.scene.checkPoints.Entrance
                                    ]
                                    npc.npc_state.currentWaypoint = npc.scene.checkPoints.Hallway
                                } else {
                                    console.log(`You can't force out customers that are not on the store`)
                                }
                                break;
                            case Tools.MASK:
                                npc.npc_state.wearingMask = true
                                npc.sprite.play("idle_npc_mask")
                                break;
                            default:
                                console.log(`This tool can't be used here!`)
                                break;
                        }
                    } else {
                        console.log("You left-clicked me, but I am out of your range!")
                    }
                }
                if (pointer.rightButtonDown()) {
                    if (npc.scene.player.interactionRadius.circle.contains(pointerLocation.x, pointerLocation.y)) {
                        switch (npc.scene.currentTool) {
                            default:
                                console.log(`This tool can't be used here!`)
                                break;
                        }
                    } else {
                        console.log("You righ-clicked me, but I am out of your range!")
                    }
                }
            }


(boughtArticle) => {
                                        console.log(`${boughtArticle} has been sold`)
                                        npc.scene.gameLoop.money += 10
                                        if (npc.scene.gameLoop.customerHappiness < 100) {
                                            npc.scene.gameLoop.customerHappiness++
                                        }
                                    }


item => {
            this.waypoints.push(scene.checkPoints[item])
            if (['Bread', 'Dairy', 'Sweets', 'Cereal', 'Hygiene'].find(x => x === item)) {
                this.waypoints.push(scene.checkPoints.Hallway2)
            } else {
                this.waypoints.push(scene.checkPoints.Hallway)
            }
        }


x => x === item


class NPCState {
    declare wearingMask: boolean

    declare patienceScore: number
    declare understandingScore: number

    declare shoppingList: Articles[]
    declare shoppingBasket: Articles[]

    declare waypoints: Phaser.GameObjects.GameObject[]
    declare currentWaypoint: Phaser.GameObjects.GameObject

    declare waitingInLine: boolean
    declare hasPayed: boolean
    declare forcedOut: boolean

    declare stopped: boolean

    declare meta: { [key: string]: any }

    constructor(scene: CoronaShopSimScene) {
        this.wearingMask = Boolean(randomIntFromInterval(0, 1))

        this.patienceScore = randomIntFromInterval(1, 10) / 10
        this.understandingScore = randomIntFromInterval(1, 10) / 10

        this.shoppingList = this.generateShoppingList()
        this.shoppingBasket = []

        this.waypoints = [
            scene.checkPoints.FarmUpstate,
            scene.checkPoints.Entrance,
            scene.checkPoints.Hallway,
            scene.checkPoints.Register,
            scene.checkPoints.Hallway
        ]
        this.currentWaypoint = scene.checkPoints.Entrance

        this.populateWaypointsFromShoppingList(scene)

        this.waitingInLine = false
        this.hasPayed = false
        this.forcedOut = false

        this.stopped = false

        this.meta = {}
    }

    private generateShoppingList(): Articles[] {
        let amountOfArticles = randomIntFromInterval(1, 10)
        let shoppingList: Articles[] = []

        for (let article = 0; article < amountOfArticles; article++) {
            shoppingList.push(randomEnum(Articles))
        }
        return shoppingList
    }

    private populateWaypointsFromShoppingList(scene: CoronaShopSimScene) {
        this.shoppingList.forEach(item => {
            this.waypoints.push(scene.checkPoints[item])
            if (['Bread', 'Dairy', 'Sweets', 'Cereal', 'Hygiene'].find(x => x === item)) {
                this.waypoints.push(scene.checkPoints.Hallway2)
            } else {
                this.waypoints.push(scene.checkPoints.Hallway)
            }
        })
        this.waypoints.push(scene.checkPoints.Hallway)
    }
}


update() {
        const npc = this

        let body = npc.sprite.body as Phaser.Physics.Arcade.Body

        if (
            npc.npc_state.stopped ||
            (npc.npc_state.meta.waitUntil && npc.npc_state.meta.waitUntil > npc.scene.gameLoop.totalPlayTime) ||
            (npc.npc_state.meta.waitForCashierUntil && npc.npc_state.meta.waitForCashierUntil > npc.scene.gameLoop.totalPlayTime) ||
            (npc.npc_state.meta.waitForRefillUntil && npc.npc_state.meta.waitForRefillUntil > npc.scene.gameLoop.totalPlayTime)
        ) {
            body.setVelocity(0); return
        }

        const speed = 40;

        let waypoint = (npc.npc_state.currentWaypoint as any) as { x: number, y: number, name: string }

        // Stop any previous movement from the last frame
        body.setVelocity(0);

        if (waypoint && (npc.sprite.x !== waypoint.x || npc.sprite.y !== waypoint.y)) {
            if (waypoint.y <= npc.sprite.y) {
                body.setVelocityY(-speed)
            } else {
                body.setVelocityY(speed)
            }

            if (waypoint.x <= npc.sprite.x) {
                body.setVelocityX(-speed)
            } else {
                body.setVelocityX(speed)
            }

        }

        if (waypoint && Math.abs(npc.sprite.x - waypoint.x) < 8 && Math.abs(npc.sprite.y - waypoint.y) < 8) {
            if (Object.keys(Articles).some(x => x === waypoint.name)) {
                if (npc.scene.shelves[waypoint.name].quantity > 0) {
                    npc.npc_state.shoppingList.splice(npc.npc_state.shoppingList.indexOf(Articles[waypoint.name]))
                    npc.scene.shelves[waypoint.name].quantity--
                    if (npc.scene.shelves[waypoint.name].dirtyness <= 80) {
                        npc.scene.shelves[waypoint.name].dirtyness = npc.scene.shelves[waypoint.name].dirtyness + 20
                    }
                    npc.npc_state.shoppingBasket.push(Articles[waypoint.name])
                    npc.npc_state.currentWaypoint = npc.npc_state.waypoints.pop()
                    if (npc.npc_state.meta.waitForRefillUntil) {
                        delete npc.npc_state.meta.waitForRefillUntil
                    } else {
                        npc.npc_state.meta.waitUntil = npc.scene.gameLoop.totalPlayTime + 2_500
                    }
                } else if (!npc.npc_state.meta.waitForRefillUntil) {
                    // TODO: Show needed article
                    npc.npc_state.meta.waitForRefillUntil = npc.scene.gameLoop.totalPlayTime + 7_500
                } else if (npc.npc_state.meta.waitForRefillUntil < npc.scene.gameLoop.totalPlayTime) {
                    npc.npc_state.currentWaypoint = npc.npc_state.waypoints.pop()
                }
            } else if (waypoint.name === 'Register' && npc.npc_state.shoppingBasket.length > 0) {
                npc.npc_state.currentWaypoint = npc.npc_state.waypoints.pop()
                npc.npc_state.waitingInLine = true
                npc.npc_state.meta.waitForCashierUntil = npc.scene.gameLoop.totalPlayTime + 25_000
            } else {
                npc.npc_state.currentWaypoint = npc.npc_state.waypoints.pop()
            }
        }

        if (npc.npc_state.currentWaypoint === undefined) {
            npc.npc_state.shoppingList.forEach((unboughtArticle) => {
                console.log(`${unboughtArticle} couldn't be accquired`)
                npc.scene.gameLoop.customerHappiness--
            })
            if (!npc.npc_state.hasPayed) {
                npc.npc_state.shoppingBasket.forEach((unpayedArticle) => {
                    console.log(`${unpayedArticle} was returned`)
                    npc.scene.gameLoop.money--
                    if (npc.scene.gameLoop.customerHappiness > 0) {
                        npc.scene.gameLoop.customerHappiness--
                    }
                    npc.scene.shelves[unpayedArticle].quantity++
                })
                if (npc.npc_state.forcedOut) {
                    if (npc.scene.gameLoop.customerHappiness >= 10) {
                        npc.scene.gameLoop.customerHappiness -= 10
                    } else {
                        npc.scene.gameLoop.customerHappiness = 0
                    }
                }
            }
            npc.destroy()
        }

        body.velocity.normalize().scale(speed);
    }


destroy() {
        let npc = this
        npc.destroyed = true
        npc.sprite.destroy()
    }


private initializeSprite(x: number, y: number, npc: NPC): Phaser.GameObjects.Sprite {
        let sprite = npc.scene.physics.add.sprite(x, y, "npc_sprite")
            .setInteractive()
            .on(Phaser.Input.Events.POINTER_DOWN, (pointer: Phaser.Input.Pointer) => {
                const pointerLocation = npc.scene.input.activePointer.positionToCamera(npc.scene.cameras.main) as Phaser.Math.Vector2;
                if (pointer.leftButtonDown()) {
                    if (npc.scene.player.interactionRadius.circle.contains(pointerLocation.x, pointerLocation.y)) {
                        switch (npc.scene.currentTool) {
                            case Tools.STOP:
                                npc.npc_state.stopped = !npc.npc_state.stopped
                                break;
                            case Tools.CASH:
                                delete npc.npc_state.meta.waitForCashierUntil
                                if (!npc.npc_state.hasPayed && npc.npc_state.waitingInLine) {
                                    npc.npc_state.shoppingBasket.forEach((boughtArticle) => {
                                        console.log(`${boughtArticle} has been sold`)
                                        npc.scene.gameLoop.money += 10
                                        if (npc.scene.gameLoop.customerHappiness < 100) {
                                            npc.scene.gameLoop.customerHappiness++
                                        }
                                    })
                                    npc.npc_state.hasPayed = true
                                    npc.npc_state.waitingInLine = false
                                }
                                break;
                            case Tools.FORCEOUT:
                                if (npc.scene.store.rectangle.contains((npc.sprite.body as Phaser.Physics.Arcade.Body).x, (npc.sprite.body as Phaser.Physics.Arcade.Body).y)) {
                                    npc.npc_state.forcedOut = true
                                    npc.npc_state.waypoints = [
                                        npc.scene.checkPoints.FarmUpstate,
                                        npc.scene.checkPoints.Entrance
                                    ]
                                    npc.npc_state.currentWaypoint = npc.scene.checkPoints.Hallway
                                } else {
                                    console.log(`You can't force out customers that are not on the store`)
                                }
                                break;
                            case Tools.MASK:
                                npc.npc_state.wearingMask = true
                                npc.sprite.play("idle_npc_mask")
                                break;
                            default:
                                console.log(`This tool can't be used here!`)
                                break;
                        }
                    } else {
                        console.log("You left-clicked me, but I am out of your range!")
                    }
                }
                if (pointer.rightButtonDown()) {
                    if (npc.scene.player.interactionRadius.circle.contains(pointerLocation.x, pointerLocation.y)) {
                        switch (npc.scene.currentTool) {
                            default:
                                console.log(`This tool can't be used here!`)
                                break;
                        }
                    } else {
                        console.log("You righ-clicked me, but I am out of your range!")
                    }
                }
            })
            .on(Phaser.Input.Events.POINTER_OVER, () => {

            })
            .on(Phaser.Input.Events.POINTER_OUT, () => {

            })
            .setDepth(2)

        return sprite
    }


private generateShoppingList(): Articles[] {
        let amountOfArticles = randomIntFromInterval(1, 10)
        let shoppingList: Articles[] = []

        for (let article = 0; article < amountOfArticles; article++) {
            shoppingList.push(randomEnum(Articles))
        }
        return shoppingList
    }


private populateWaypointsFromShoppingList(scene: CoronaShopSimScene) {
        this.shoppingList.forEach(item => {
            this.waypoints.push(scene.checkPoints[item])
            if (['Bread', 'Dairy', 'Sweets', 'Cereal', 'Hygiene'].find(x => x === item)) {
                this.waypoints.push(scene.checkPoints.Hallway2)
            } else {
                this.waypoints.push(scene.checkPoints.Hallway)
            }
        })
        this.waypoints.push(scene.checkPoints.Hallway)
    }


async () => connections = await createTestingConnections({
        entities: [__dirname + "/entity/*{.js,.ts}"],
        schemaCreate: true,
        dropSchemaOnConnection: true,
    })


() => Promise.all(connections.map(async connection => {

            const category1 = new Category();
            category1.name = "cars";
            category1.type = "common-category";
            category1.code = 1;
            category1.version = 1;
            await connection.manager.save(category1);

            const category2 = new Category();
            category2.name = "airplanes";
            category2.type = "common-category";
            category2.code = 2;
            category2.version = 1;
            await connection.manager.save(category2);

            const post1 = new Post();
            post1.title = "About BMW";
            post1.category = category1;
            await connection.manager.save(post1);

            const post2 = new Post();
            post2.title = "About Boeing";
            post2.category = category2;
            await connection.manager.save(post2);

            const loadedPosts = await connection.manager
                .createQueryBuilder(Post, "post")
                .leftJoinAndSelect("post.category", "category")
                .orderBy("post.id")
                .getMany();

            expect(loadedPosts[0].category).to.not.be.empty;
            expect(loadedPosts[0].category.name).to.be.equal("cars");
            expect(loadedPosts[0].category.type).to.be.equal("common-category");
            expect(loadedPosts[1].category).to.not.be.empty;
            expect(loadedPosts[1].category.name).to.be.equal("airplanes");
            expect(loadedPosts[1].category.type).to.be.equal("common-category");

            const loadedPost = await connection.manager
                .createQueryBuilder(Post, "post")
                .leftJoinAndSelect("post.category", "category")
                .where("post.id = :id", {id: 1})
                .getOne();

            expect(loadedPost!.category).to.not.be.empty;
            expect(loadedPost!.category.name).to.be.equal("cars");
            expect(loadedPost!.category.type).to.be.equal("common-category");

        }))


async connection => {

            const category1 = new Category();
            category1.name = "cars";
            category1.type = "common-category";
            category1.code = 1;
            category1.version = 1;
            await connection.manager.save(category1);

            const category2 = new Category();
            category2.name = "airplanes";
            category2.type = "common-category";
            category2.code = 2;
            category2.version = 1;
            await connection.manager.save(category2);

            const post1 = new Post();
            post1.title = "About BMW";
            post1.category = category1;
            await connection.manager.save(post1);

            const post2 = new Post();
            post2.title = "About Boeing";
            post2.category = category2;
            await connection.manager.save(post2);

            const loadedPosts = await connection.manager
                .createQueryBuilder(Post, "post")
                .leftJoinAndSelect("post.category", "category")
                .orderBy("post.id")
                .getMany();

            expect(loadedPosts[0].category).to.not.be.empty;
            expect(loadedPosts[0].category.name).to.be.equal("cars");
            expect(loadedPosts[0].category.type).to.be.equal("common-category");
            expect(loadedPosts[1].category).to.not.be.empty;
            expect(loadedPosts[1].category.name).to.be.equal("airplanes");
            expect(loadedPosts[1].category.type).to.be.equal("common-category");

            const loadedPost = await connection.manager
                .createQueryBuilder(Post, "post")
                .leftJoinAndSelect("post.category", "category")
                .where("post.id = :id", {id: 1})
                .getOne();

            expect(loadedPost!.category).to.not.be.empty;
            expect(loadedPost!.category.name).to.be.equal("cars");
            expect(loadedPost!.category.type).to.be.equal("common-category");

        }


() => Promise.all(connections.map(async connection => {

            const category1 = new Category();
            category1.name = "cars";
            category1.type = "common-category";
            category1.code = 1;
            category1.version = 1;
            await connection.manager.save(category1);

            const category2 = new Category();
            category2.name = "airplanes";
            category2.type = "common-category";
            category2.code = 2;
            category2.version = 1;
            await connection.manager.save(category2);

            const post1 = new Post();
            post1.title = "About BMW";
            post1.categoryWithEmptyJoinColumn = category1;
            await connection.manager.save(post1);

            const post2 = new Post();
            post2.title = "About Boeing";
            post2.categoryWithEmptyJoinColumn = category2;
            await connection.manager.save(post2);

            const loadedPosts = await connection.manager
                .createQueryBuilder(Post, "post")
                .leftJoinAndSelect("post.categoryWithEmptyJoinColumn", "category")
                .orderBy("post.id")
                .getMany();

            expect(loadedPosts[0].categoryWithEmptyJoinColumn).to.not.be.empty;
            expect(loadedPosts[0].categoryWithEmptyJoinColumn.name).to.be.equal("cars");
            expect(loadedPosts[0].categoryWithEmptyJoinColumn.type).to.be.equal("common-category");
            expect(loadedPosts[1].categoryWithEmptyJoinColumn).to.not.be.empty;
            expect(loadedPosts[1].categoryWithEmptyJoinColumn.name).to.be.equal("airplanes");
            expect(loadedPosts[1].categoryWithEmptyJoinColumn.type).to.be.equal("common-category");

            const loadedPost = await connection.manager
                .createQueryBuilder(Post, "post")
                .leftJoinAndSelect("post.categoryWithEmptyJoinColumn", "category")
                .where("post.id = :id", {id: 1})
                .getOne();

            expect(loadedPost!.categoryWithEmptyJoinColumn).to.not.be.empty;
            expect(loadedPost!.categoryWithEmptyJoinColumn.name).to.be.equal("cars");
            expect(loadedPost!.categoryWithEmptyJoinColumn.type).to.be.equal("common-category");

        }))


async connection => {

            const category1 = new Category();
            category1.name = "cars";
            category1.type = "common-category";
            category1.code = 1;
            category1.version = 1;
            await connection.manager.save(category1);

            const category2 = new Category();
            category2.name = "airplanes";
            category2.type = "common-category";
            category2.code = 2;
            category2.version = 1;
            await connection.manager.save(category2);

            const post1 = new Post();
            post1.title = "About BMW";
            post1.categoryWithEmptyJoinColumn = category1;
            await connection.manager.save(post1);

            const post2 = new Post();
            post2.title = "About Boeing";
            post2.categoryWithEmptyJoinColumn = category2;
            await connection.manager.save(post2);

            const loadedPosts = await connection.manager
                .createQueryBuilder(Post, "post")
                .leftJoinAndSelect("post.categoryWithEmptyJoinColumn", "category")
                .orderBy("post.id")
                .getMany();

            expect(loadedPosts[0].categoryWithEmptyJoinColumn).to.not.be.empty;
            expect(loadedPosts[0].categoryWithEmptyJoinColumn.name).to.be.equal("cars");
            expect(loadedPosts[0].categoryWithEmptyJoinColumn.type).to.be.equal("common-category");
            expect(loadedPosts[1].categoryWithEmptyJoinColumn).to.not.be.empty;
            expect(loadedPosts[1].categoryWithEmptyJoinColumn.name).to.be.equal("airplanes");
            expect(loadedPosts[1].categoryWithEmptyJoinColumn.type).to.be.equal("common-category");

            const loadedPost = await connection.manager
                .createQueryBuilder(Post, "post")
                .leftJoinAndSelect("post.categoryWithEmptyJoinColumn", "category")
                .where("post.id = :id", {id: 1})
                .getOne();

            expect(loadedPost!.categoryWithEmptyJoinColumn).to.not.be.empty;
            expect(loadedPost!.categoryWithEmptyJoinColumn.name).to.be.equal("cars");
            expect(loadedPost!.categoryWithEmptyJoinColumn.type).to.be.equal("common-category");

        }


() => Promise.all(connections.map(async connection => {

            const category1 = new Category();
            category1.name = "cars";
            category1.type = "common-category";
            category1.code = 1;
            category1.version = 1;
            await connection.manager.save(category1);

            const category2 = new Category();
            category2.name = "airplanes";
            category2.type = "common-category";
            category2.code = 2;
            category2.version = 1;
            await connection.manager.save(category2);

            const post1 = new Post();
            post1.title = "About BMW";
            post1.categoryWithOptions = category1;
            await connection.manager.save(post1);

            const post2 = new Post();
            post2.title = "About Boeing";
            post2.categoryWithOptions = category2;
            await connection.manager.save(post2);

            const loadedPosts = await connection.manager
                .createQueryBuilder(Post, "post")
                .leftJoinAndSelect("post.categoryWithOptions", "category")
                .orderBy("post.id")
                .getMany();

            expect(loadedPosts[0].categoryWithOptions).to.not.be.empty;
            expect(loadedPosts[0].categoryWithOptions.name).to.be.equal("cars");
            expect(loadedPosts[0].categoryWithOptions.type).to.be.equal("common-category");
            expect(loadedPosts[1].categoryWithOptions).to.not.be.empty;
            expect(loadedPosts[1].categoryWithOptions.name).to.be.equal("airplanes");
            expect(loadedPosts[1].categoryWithOptions.type).to.be.equal("common-category");

            const loadedPost = await connection.manager
                .createQueryBuilder(Post, "post")
                .leftJoinAndSelect("post.categoryWithOptions", "category")
                .where("post.id = :id", {id: 1})
                .getOne();

            expect(loadedPost!.categoryWithOptions).to.not.be.empty;
            expect(loadedPost!.categoryWithOptions.name).to.be.equal("cars");
            expect(loadedPost!.categoryWithOptions.type).to.be.equal("common-category");

        }))


async connection => {

            const category1 = new Category();
            category1.name = "cars";
            category1.type = "common-category";
            category1.code = 1;
            category1.version = 1;
            await connection.manager.save(category1);

            const category2 = new Category();
            category2.name = "airplanes";
            category2.type = "common-category";
            category2.code = 2;
            category2.version = 1;
            await connection.manager.save(category2);

            const post1 = new Post();
            post1.title = "About BMW";
            post1.categoryWithOptions = category1;
            await connection.manager.save(post1);

            const post2 = new Post();
            post2.title = "About Boeing";
            post2.categoryWithOptions = category2;
            await connection.manager.save(post2);

            const loadedPosts = await connection.manager
                .createQueryBuilder(Post, "post")
                .leftJoinAndSelect("post.categoryWithOptions", "category")
                .orderBy("post.id")
                .getMany();

            expect(loadedPosts[0].categoryWithOptions).to.not.be.empty;
            expect(loadedPosts[0].categoryWithOptions.name).to.be.equal("cars");
            expect(loadedPosts[0].categoryWithOptions.type).to.be.equal("common-category");
            expect(loadedPosts[1].categoryWithOptions).to.not.be.empty;
            expect(loadedPosts[1].categoryWithOptions.name).to.be.equal("airplanes");
            expect(loadedPosts[1].categoryWithOptions.type).to.be.equal("common-category");

            const loadedPost = await connection.manager
                .createQueryBuilder(Post, "post")
                .leftJoinAndSelect("post.categoryWithOptions", "category")
                .where("post.id = :id", {id: 1})
                .getOne();

            expect(loadedPost!.categoryWithOptions).to.not.be.empty;
            expect(loadedPost!.categoryWithOptions.name).to.be.equal("cars");
            expect(loadedPost!.categoryWithOptions.type).to.be.equal("common-category");

        }


() => Promise.all(connections.map(async connection => {

            const category1 = new Category();
            category1.name = "cars";
            category1.type = "common-category";
            category1.code = 1;
            category1.version = 1;
            category1.description = "category about cars";
            await connection.manager.save(category1);

            const category2 = new Category();
            category2.name = "airplanes";
            category2.type = "common-category";
            category2.code = 2;
            category2.version = 1;
            category2.description = "category about airplanes";
            await connection.manager.save(category2);

            const post1 = new Post();
            post1.title = "About BMW";
            post1.categoryWithNonPrimaryColumns = category1;
            await connection.manager.save(post1);

            const post2 = new Post();
            post2.title = "About Boeing";
            post2.categoryWithNonPrimaryColumns = category2;
            await connection.manager.save(post2);

            const loadedPosts = await connection.manager
                .createQueryBuilder(Post, "post")
                .leftJoinAndSelect("post.categoryWithNonPrimaryColumns", "category")
                .orderBy("post.id")
                .getMany();

            expect(loadedPosts[0].categoryWithNonPrimaryColumns).to.not.be.empty;
            expect(loadedPosts[0].categoryWithNonPrimaryColumns.code).to.be.equal(1);
            expect(loadedPosts[0].categoryWithNonPrimaryColumns.version).to.be.equal(1);
            expect(loadedPosts[0].categoryWithNonPrimaryColumns.description).to.be.equal("category about cars");
            expect(loadedPosts[1].categoryWithNonPrimaryColumns).to.not.be.empty;
            expect(loadedPosts[1].categoryWithNonPrimaryColumns.code).to.be.equal(2);
            expect(loadedPosts[1].categoryWithNonPrimaryColumns.version).to.be.equal(1);

            const loadedPost = await connection.manager
                .createQueryBuilder(Post, "post")
                .leftJoinAndSelect("post.categoryWithNonPrimaryColumns", "category")
                .where("post.id = :id", {id: 1})
                .getOne();

            expect(loadedPost!.categoryWithNonPrimaryColumns).to.not.be.empty;
            expect(loadedPost!.categoryWithNonPrimaryColumns.code).to.be.equal(1);
            expect(loadedPost!.categoryWithNonPrimaryColumns.version).to.be.equal(1);
            expect(loadedPost!.categoryWithNonPrimaryColumns.description).to.be.equal("category about cars");

        }))


async connection => {

            const category1 = new Category();
            category1.name = "cars";
            category1.type = "common-category";
            category1.code = 1;
            category1.version = 1;
            category1.description = "category about cars";
            await connection.manager.save(category1);

            const category2 = new Category();
            category2.name = "airplanes";
            category2.type = "common-category";
            category2.code = 2;
            category2.version = 1;
            category2.description = "category about airplanes";
            await connection.manager.save(category2);

            const post1 = new Post();
            post1.title = "About BMW";
            post1.categoryWithNonPrimaryColumns = category1;
            await connection.manager.save(post1);

            const post2 = new Post();
            post2.title = "About Boeing";
            post2.categoryWithNonPrimaryColumns = category2;
            await connection.manager.save(post2);

            const loadedPosts = await connection.manager
                .createQueryBuilder(Post, "post")
                .leftJoinAndSelect("post.categoryWithNonPrimaryColumns", "category")
                .orderBy("post.id")
                .getMany();

            expect(loadedPosts[0].categoryWithNonPrimaryColumns).to.not.be.empty;
            expect(loadedPosts[0].categoryWithNonPrimaryColumns.code).to.be.equal(1);
            expect(loadedPosts[0].categoryWithNonPrimaryColumns.version).to.be.equal(1);
            expect(loadedPosts[0].categoryWithNonPrimaryColumns.description).to.be.equal("category about cars");
            expect(loadedPosts[1].categoryWithNonPrimaryColumns).to.not.be.empty;
            expect(loadedPosts[1].categoryWithNonPrimaryColumns.code).to.be.equal(2);
            expect(loadedPosts[1].categoryWithNonPrimaryColumns.version).to.be.equal(1);

            const loadedPost = await connection.manager
                .createQueryBuilder(Post, "post")
                .leftJoinAndSelect("post.categoryWithNonPrimaryColumns", "category")
                .where("post.id = :id", {id: 1})
                .getOne();

            expect(loadedPost!.categoryWithNonPrimaryColumns).to.not.be.empty;
            expect(loadedPost!.categoryWithNonPrimaryColumns.code).to.be.equal(1);
            expect(loadedPost!.categoryWithNonPrimaryColumns.version).to.be.equal(1);
            expect(loadedPost!.categoryWithNonPrimaryColumns.description).to.be.equal("category about cars");

        }


() => Promise.all(connections.map(async connection => {

            const post1 = new Post();
            post1.title = "About BMW";
            await connection.manager.save(post1);

            const post2 = new Post();
            post2.title = "About Audi";
            await connection.manager.save(post2);

            const post3 = new Post();
            post3.title = "About Boeing";
            await connection.manager.save(post3);

            const category1 = new Category();
            category1.name = "cars";
            category1.type = "common-category";
            category1.code = 1;
            category1.version = 1;
            category1.posts = [post1, post2];
            await connection.manager.save(category1);

            const category2 = new Category();
            category2.name = "airplanes";
            category2.type = "common-category";
            category2.code = 2;
            category2.version = 1;
            category2.posts = [post3];
            await connection.manager.save(category2);

            const loadedCategories = await connection.manager
                .createQueryBuilder(Category, "category")
                .leftJoinAndSelect("category.posts", "posts")
                .orderBy("category.code, posts.id")
                .getMany();

            expect(loadedCategories[0].posts).to.not.be.empty;
            expect(loadedCategories[0].posts[0].id).to.be.equal(1);
            expect(loadedCategories[0].posts[0].title).to.be.equal("About BMW");
            expect(loadedCategories[0].posts[1].id).to.be.equal(2);
            expect(loadedCategories[0].posts[1].title).to.be.equal("About Audi");
            expect(loadedCategories[1].posts).to.not.be.empty;
            expect(loadedCategories[1].posts[0].id).to.be.equal(3);
            expect(loadedCategories[1].posts[0].title).to.be.equal("About Boeing");

            const loadedCategory = await connection.manager
                .createQueryBuilder(Category, "category")
                .leftJoinAndSelect("category.posts", "posts")
                .orderBy("posts.id")
                .where("category.code = :code", {code: 1})
                .getOne();

            expect(loadedCategory!.posts).to.not.be.empty;
            expect(loadedCategory!.posts[0].id).to.be.equal(1);
            expect(loadedCategory!.posts[0].title).to.be.equal("About BMW");
            expect(loadedCategory!.posts[1].id).to.be.equal(2);
            expect(loadedCategory!.posts[1].title).to.be.equal("About Audi");

        }))


async connection => {

            const post1 = new Post();
            post1.title = "About BMW";
            await connection.manager.save(post1);

            const post2 = new Post();
            post2.title = "About Audi";
            await connection.manager.save(post2);

            const post3 = new Post();
            post3.title = "About Boeing";
            await connection.manager.save(post3);

            const category1 = new Category();
            category1.name = "cars";
            category1.type = "common-category";
            category1.code = 1;
            category1.version = 1;
            category1.posts = [post1, post2];
            await connection.manager.save(category1);

            const category2 = new Category();
            category2.name = "airplanes";
            category2.type = "common-category";
            category2.code = 2;
            category2.version = 1;
            category2.posts = [post3];
            await connection.manager.save(category2);

            const loadedCategories = await connection.manager
                .createQueryBuilder(Category, "category")
                .leftJoinAndSelect("category.posts", "posts")
                .orderBy("category.code, posts.id")
                .getMany();

            expect(loadedCategories[0].posts).to.not.be.empty;
            expect(loadedCategories[0].posts[0].id).to.be.equal(1);
            expect(loadedCategories[0].posts[0].title).to.be.equal("About BMW");
            expect(loadedCategories[0].posts[1].id).to.be.equal(2);
            expect(loadedCategories[0].posts[1].title).to.be.equal("About Audi");
            expect(loadedCategories[1].posts).to.not.be.empty;
            expect(loadedCategories[1].posts[0].id).to.be.equal(3);
            expect(loadedCategories[1].posts[0].title).to.be.equal("About Boeing");

            const loadedCategory = await connection.manager
                .createQueryBuilder(Category, "category")
                .leftJoinAndSelect("category.posts", "posts")
                .orderBy("posts.id")
                .where("category.code = :code", {code: 1})
                .getOne();

            expect(loadedCategory!.posts).to.not.be.empty;
            expect(loadedCategory!.posts[0].id).to.be.equal(1);
            expect(loadedCategory!.posts[0].title).to.be.equal("About BMW");
            expect(loadedCategory!.posts[1].id).to.be.equal(2);
            expect(loadedCategory!.posts[1].title).to.be.equal("About Audi");

        }


() => Promise.all(connections.map(async connection => {

            const post1 = new Post();
            post1.title = "About BMW";
            await connection.manager.save(post1);

            const post2 = new Post();
            post2.title = "About Audi";
            await connection.manager.save(post2);

            const post3 = new Post();
            post3.title = "About Boeing";
            await connection.manager.save(post3);

            const category1 = new Category();
            category1.name = "cars";
            category1.type = "common-category";
            category1.code = 1;
            category1.version = 1;
            category1.postsWithEmptyJoinColumn = [post1, post2];
            await connection.manager.save(category1);

            const category2 = new Category();
            category2.name = "airplanes";
            category2.type = "common-category";
            category2.code = 2;
            category2.version = 1;
            category2.postsWithEmptyJoinColumn = [post3];
            await connection.manager.save(category2);

            const loadedCategories = await connection.manager
                .createQueryBuilder(Category, "category")
                .leftJoinAndSelect("category.postsWithEmptyJoinColumn", "posts")
                .orderBy("category.code, posts.id")
                .getMany();

            expect(loadedCategories[0].postsWithEmptyJoinColumn).to.not.be.empty;
            expect(loadedCategories[0].postsWithEmptyJoinColumn[0].id).to.be.equal(1);
            expect(loadedCategories[0].postsWithEmptyJoinColumn[0].title).to.be.equal("About BMW");
            expect(loadedCategories[0].postsWithEmptyJoinColumn[1].id).to.be.equal(2);
            expect(loadedCategories[0].postsWithEmptyJoinColumn[1].title).to.be.equal("About Audi");
            expect(loadedCategories[1].postsWithEmptyJoinColumn).to.not.be.empty;
            expect(loadedCategories[1].postsWithEmptyJoinColumn[0].id).to.be.equal(3);
            expect(loadedCategories[1].postsWithEmptyJoinColumn[0].title).to.be.equal("About Boeing");

            const loadedCategory = await connection.manager
                .createQueryBuilder(Category, "category")
                .leftJoinAndSelect("category.postsWithEmptyJoinColumn", "posts")
                .orderBy("posts.id")
                .where("category.code = :code", {code: 1})
                .getOne();

            expect(loadedCategory!.postsWithEmptyJoinColumn).to.not.be.empty;
            expect(loadedCategory!.postsWithEmptyJoinColumn[0].id).to.be.equal(1);
            expect(loadedCategory!.postsWithEmptyJoinColumn[0].title).to.be.equal("About BMW");
            expect(loadedCategory!.postsWithEmptyJoinColumn[1].id).to.be.equal(2);
            expect(loadedCategory!.postsWithEmptyJoinColumn[1].title).to.be.equal("About Audi");

        }))


async connection => {

            const post1 = new Post();
            post1.title = "About BMW";
            await connection.manager.save(post1);

            const post2 = new Post();
            post2.title = "About Audi";
            await connection.manager.save(post2);

            const post3 = new Post();
            post3.title = "About Boeing";
            await connection.manager.save(post3);

            const category1 = new Category();
            category1.name = "cars";
            category1.type = "common-category";
            category1.code = 1;
            category1.version = 1;
            category1.postsWithEmptyJoinColumn = [post1, post2];
            await connection.manager.save(category1);

            const category2 = new Category();
            category2.name = "airplanes";
            category2.type = "common-category";
            category2.code = 2;
            category2.version = 1;
            category2.postsWithEmptyJoinColumn = [post3];
            await connection.manager.save(category2);

            const loadedCategories = await connection.manager
                .createQueryBuilder(Category, "category")
                .leftJoinAndSelect("category.postsWithEmptyJoinColumn", "posts")
                .orderBy("category.code, posts.id")
                .getMany();

            expect(loadedCategories[0].postsWithEmptyJoinColumn).to.not.be.empty;
            expect(loadedCategories[0].postsWithEmptyJoinColumn[0].id).to.be.equal(1);
            expect(loadedCategories[0].postsWithEmptyJoinColumn[0].title).to.be.equal("About BMW");
            expect(loadedCategories[0].postsWithEmptyJoinColumn[1].id).to.be.equal(2);
            expect(loadedCategories[0].postsWithEmptyJoinColumn[1].title).to.be.equal("About Audi");
            expect(loadedCategories[1].postsWithEmptyJoinColumn).to.not.be.empty;
            expect(loadedCategories[1].postsWithEmptyJoinColumn[0].id).to.be.equal(3);
            expect(loadedCategories[1].postsWithEmptyJoinColumn[0].title).to.be.equal("About Boeing");

            const loadedCategory = await connection.manager
                .createQueryBuilder(Category, "category")
                .leftJoinAndSelect("category.postsWithEmptyJoinColumn", "posts")
                .orderBy("posts.id")
                .where("category.code = :code", {code: 1})
                .getOne();

            expect(loadedCategory!.postsWithEmptyJoinColumn).to.not.be.empty;
            expect(loadedCategory!.postsWithEmptyJoinColumn[0].id).to.be.equal(1);
            expect(loadedCategory!.postsWithEmptyJoinColumn[0].title).to.be.equal("About BMW");
            expect(loadedCategory!.postsWithEmptyJoinColumn[1].id).to.be.equal(2);
            expect(loadedCategory!.postsWithEmptyJoinColumn[1].title).to.be.equal("About Audi");

        }


() => Promise.all(connections.map(async connection => {

            const post1 = new Post();
            post1.title = "About BMW";
            await connection.manager.save(post1);

            const post2 = new Post();
            post2.title = "About Audi";
            await connection.manager.save(post2);

            const post3 = new Post();
            post3.title = "About Boeing";
            await connection.manager.save(post3);

            const category1 = new Category();
            category1.name = "cars";
            category1.type = "common-category";
            category1.code = 1;
            category1.version = 1;
            category1.postsWithOptions = [post1, post2];
            await connection.manager.save(category1);

            const category2 = new Category();
            category2.name = "airplanes";
            category2.type = "common-category";
            category2.code = 2;
            category2.version = 1;
            category2.postsWithOptions = [post3];
            await connection.manager.save(category2);

            const loadedCategories = await connection.manager
                .createQueryBuilder(Category, "category")
                .leftJoinAndSelect("category.postsWithOptions", "posts")
                .orderBy("category.code, posts.id")
                .getMany();

            expect(loadedCategories[0].postsWithOptions).to.not.be.empty;
            expect(loadedCategories[0].postsWithOptions[0].id).to.be.equal(1);
            expect(loadedCategories[0].postsWithOptions[0].title).to.be.equal("About BMW");
            expect(loadedCategories[0].postsWithOptions[1].id).to.be.equal(2);
            expect(loadedCategories[0].postsWithOptions[1].title).to.be.equal("About Audi");
            expect(loadedCategories[1].postsWithOptions).to.not.be.empty;
            expect(loadedCategories[1].postsWithOptions[0].id).to.be.equal(3);
            expect(loadedCategories[1].postsWithOptions[0].title).to.be.equal("About Boeing");

            const loadedCategory = await connection.manager
                .createQueryBuilder(Category, "category")
                .leftJoinAndSelect("category.postsWithOptions", "posts")
                .orderBy("posts.id")
                .where("category.code = :code", {code: 1})
                .getOne();

            expect(loadedCategory!.postsWithOptions).to.not.be.empty;
            expect(loadedCategory!.postsWithOptions[0].id).to.be.equal(1);
            expect(loadedCategory!.postsWithOptions[0].title).to.be.equal("About BMW");
            expect(loadedCategory!.postsWithOptions[1].id).to.be.equal(2);
            expect(loadedCategory!.postsWithOptions[1].title).to.be.equal("About Audi");

        }))


async connection => {

            const post1 = new Post();
            post1.title = "About BMW";
            await connection.manager.save(post1);

            const post2 = new Post();
            post2.title = "About Audi";
            await connection.manager.save(post2);

            const post3 = new Post();
            post3.title = "About Boeing";
            await connection.manager.save(post3);

            const category1 = new Category();
            category1.name = "cars";
            category1.type = "common-category";
            category1.code = 1;
            category1.version = 1;
            category1.postsWithOptions = [post1, post2];
            await connection.manager.save(category1);

            const category2 = new Category();
            category2.name = "airplanes";
            category2.type = "common-category";
            category2.code = 2;
            category2.version = 1;
            category2.postsWithOptions = [post3];
            await connection.manager.save(category2);

            const loadedCategories = await connection.manager
                .createQueryBuilder(Category, "category")
                .leftJoinAndSelect("category.postsWithOptions", "posts")
                .orderBy("category.code, posts.id")
                .getMany();

            expect(loadedCategories[0].postsWithOptions).to.not.be.empty;
            expect(loadedCategories[0].postsWithOptions[0].id).to.be.equal(1);
            expect(loadedCategories[0].postsWithOptions[0].title).to.be.equal("About BMW");
            expect(loadedCategories[0].postsWithOptions[1].id).to.be.equal(2);
            expect(loadedCategories[0].postsWithOptions[1].title).to.be.equal("About Audi");
            expect(loadedCategories[1].postsWithOptions).to.not.be.empty;
            expect(loadedCategories[1].postsWithOptions[0].id).to.be.equal(3);
            expect(loadedCategories[1].postsWithOptions[0].title).to.be.equal("About Boeing");

            const loadedCategory = await connection.manager
                .createQueryBuilder(Category, "category")
                .leftJoinAndSelect("category.postsWithOptions", "posts")
                .orderBy("posts.id")
                .where("category.code = :code", {code: 1})
                .getOne();

            expect(loadedCategory!.postsWithOptions).to.not.be.empty;
            expect(loadedCategory!.postsWithOptions[0].id).to.be.equal(1);
            expect(loadedCategory!.postsWithOptions[0].title).to.be.equal("About BMW");
            expect(loadedCategory!.postsWithOptions[1].id).to.be.equal(2);
            expect(loadedCategory!.postsWithOptions[1].title).to.be.equal("About Audi");

        }


() => Promise.all(connections.map(async connection => {

            const post1 = new Post();
            post1.title = "About BMW";
            await connection.manager.save(post1);

            const post2 = new Post();
            post2.title = "About Audi";
            await connection.manager.save(post2);

            const post3 = new Post();
            post3.title = "About Boeing";
            await connection.manager.save(post3);

            const category1 = new Category();
            category1.name = "cars";
            category1.type = "common-category";
            category1.code = 1;
            category1.version = 1;
            category1.description = "category of cars";
            category1.postsWithNonPrimaryColumns = [post1, post2];
            await connection.manager.save(category1);

            const category2 = new Category();
            category2.name = "airplanes";
            category2.type = "common-category";
            category2.code = 2;
            category2.version = 1;
            category2.description = "category of airplanes";
            category2.postsWithNonPrimaryColumns = [post3];
            await connection.manager.save(category2);

            const loadedCategories = await connection.manager
                .createQueryBuilder(Category, "category")
                .leftJoinAndSelect("category.postsWithNonPrimaryColumns", "posts")
                .orderBy("category.code, posts.id")
                .getMany();

            expect(loadedCategories[0].postsWithNonPrimaryColumns).to.not.be.empty;
            expect(loadedCategories[0].postsWithNonPrimaryColumns[0].id).to.be.equal(1);
            expect(loadedCategories[0].postsWithNonPrimaryColumns[0].title).to.be.equal("About BMW");
            expect(loadedCategories[0].postsWithNonPrimaryColumns[1].id).to.be.equal(2);
            expect(loadedCategories[0].postsWithNonPrimaryColumns[1].title).to.be.equal("About Audi");
            expect(loadedCategories[1].postsWithNonPrimaryColumns).to.not.be.empty;
            expect(loadedCategories[1].postsWithNonPrimaryColumns[0].id).to.be.equal(3);
            expect(loadedCategories[1].postsWithNonPrimaryColumns[0].title).to.be.equal("About Boeing");

            const loadedCategory = await connection.manager
                .createQueryBuilder(Category, "category")
                .leftJoinAndSelect("category.postsWithNonPrimaryColumns", "posts")
                .orderBy("posts.id")
                .where("category.code = :code", {code: 1})
                .getOne();

            expect(loadedCategory!.postsWithNonPrimaryColumns).to.not.be.empty;
            expect(loadedCategory!.postsWithNonPrimaryColumns[0].id).to.be.equal(1);
            expect(loadedCategory!.postsWithNonPrimaryColumns[0].title).to.be.equal("About BMW");
            expect(loadedCategory!.postsWithNonPrimaryColumns[1].id).to.be.equal(2);
            expect(loadedCategory!.postsWithNonPrimaryColumns[1].title).to.be.equal("About Audi");

        }))


async connection => {

            const post1 = new Post();
            post1.title = "About BMW";
            await connection.manager.save(post1);

            const post2 = new Post();
            post2.title = "About Audi";
            await connection.manager.save(post2);

            const post3 = new Post();
            post3.title = "About Boeing";
            await connection.manager.save(post3);

            const category1 = new Category();
            category1.name = "cars";
            category1.type = "common-category";
            category1.code = 1;
            category1.version = 1;
            category1.description = "category of cars";
            category1.postsWithNonPrimaryColumns = [post1, post2];
            await connection.manager.save(category1);

            const category2 = new Category();
            category2.name = "airplanes";
            category2.type = "common-category";
            category2.code = 2;
            category2.version = 1;
            category2.description = "category of airplanes";
            category2.postsWithNonPrimaryColumns = [post3];
            await connection.manager.save(category2);

            const loadedCategories = await connection.manager
                .createQueryBuilder(Category, "category")
                .leftJoinAndSelect("category.postsWithNonPrimaryColumns", "posts")
                .orderBy("category.code, posts.id")
                .getMany();

            expect(loadedCategories[0].postsWithNonPrimaryColumns).to.not.be.empty;
            expect(loadedCategories[0].postsWithNonPrimaryColumns[0].id).to.be.equal(1);
            expect(loadedCategories[0].postsWithNonPrimaryColumns[0].title).to.be.equal("About BMW");
            expect(loadedCategories[0].postsWithNonPrimaryColumns[1].id).to.be.equal(2);
            expect(loadedCategories[0].postsWithNonPrimaryColumns[1].title).to.be.equal("About Audi");
            expect(loadedCategories[1].postsWithNonPrimaryColumns).to.not.be.empty;
            expect(loadedCategories[1].postsWithNonPrimaryColumns[0].id).to.be.equal(3);
            expect(loadedCategories[1].postsWithNonPrimaryColumns[0].title).to.be.equal("About Boeing");

            const loadedCategory = await connection.manager
                .createQueryBuilder(Category, "category")
                .leftJoinAndSelect("category.postsWithNonPrimaryColumns", "posts")
                .orderBy("posts.id")
                .where("category.code = :code", {code: 1})
                .getOne();

            expect(loadedCategory!.postsWithNonPrimaryColumns).to.not.be.empty;
            expect(loadedCategory!.postsWithNonPrimaryColumns[0].id).to.be.equal(1);
            expect(loadedCategory!.postsWithNonPrimaryColumns[0].title).to.be.equal("About BMW");
            expect(loadedCategory!.postsWithNonPrimaryColumns[1].id).to.be.equal(2);
            expect(loadedCategory!.postsWithNonPrimaryColumns[1].title).to.be.equal("About Audi");

        }


export default class Utils {
	static api = axios;
	private static props: UtilsProps;

	constructor(props: UtilsProps) {

	}

	static setNotice(options:NoticeOptions, onCloseCallback: ToastCallback) {
		toast.custom("
Hello World
");
	}

	static clearNotice() {
		toast.dismiss();
	}

	static sprintFormat(arrayArguments:Array<string>)
	{
		let baseUrl = this.props.smfVars.scriptUrl +
			'?action={0};' + this.props.smfVars.session.var +'='+ this.props.smfVars.session.id + ';sa={1}';
		let i = arrayArguments.length

		while (i--) {
			baseUrl = baseUrl.replace(new RegExp('\\{' + i + '\\}', 'gm'), arrayArguments[i]);
		}

		return baseUrl;
	}

    private static canUseLocalStorage()
	{
        let storage = window['localStorage']

		try {
			let	x = 'breeze_storage_test';
			storage.setItem(x, x);
			storage.removeItem(x);

			return true;
		}
		catch(e) {
			return e instanceof DOMException && (
					e.code === 22 ||
					e.code === 1014 ||
					e.name === 'QuotaExceededError' ||
					e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
				storage && storage.length !== 0;
		}
	}

    setLocalObject(keyName:string, objectToStore:object)
	{
		if (!Utils.canUseLocalStorage()) {
		return false;
		}

		localStorage.setItem(keyName, JSON.stringify(objectToStore));

		return true;
	}

	getLocalObject(keyName:string)
	{
		if (!Utils.canUseLocalStorage()) {
			return false;
		}

    	let objectStored = JSON.parse(<string>localStorage.getItem(keyName));

		if (objectStored !== null){
			return objectStored;
		} else {
			return false;
		}
	}

    decode(html:string)
	{
		let decoder = document.createElement('div');
		decoder.innerHTML = html;
		return decoder.textContent;
	}
}


static setNotice(options:NoticeOptions, onCloseCallback: ToastCallback) {
		toast.custom("
Hello World
");
	}


static clearNotice() {
		toast.dismiss();
	}


static sprintFormat(arrayArguments:Array<string>)
	{
		let baseUrl = this.props.smfVars.scriptUrl +
			'?action={0};' + this.props.smfVars.session.var +'='+ this.props.smfVars.session.id + ';sa={1}';
		let i = arrayArguments.length

		while (i--) {
			baseUrl = baseUrl.replace(new RegExp('\\{' + i + '\\}', 'gm'), arrayArguments[i]);
		}

		return baseUrl;
	}


private static canUseLocalStorage()
	{
        let storage = window['localStorage']

		try {
			let	x = 'breeze_storage_test';
			storage.setItem(x, x);
			storage.removeItem(x);

			return true;
		}
		catch(e) {
			return e instanceof DOMException && (
					e.code === 22 ||
					e.code === 1014 ||
					e.name === 'QuotaExceededError' ||
					e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
				storage && storage.length !== 0;
		}
	}


setLocalObject(keyName:string, objectToStore:object)
	{
		if (!Utils.canUseLocalStorage()) {
		return false;
		}

		localStorage.setItem(keyName, JSON.stringify(objectToStore));

		return true;
	}


getLocalObject(keyName:string)
	{
		if (!Utils.canUseLocalStorage()) {
			return false;
		}

    	let objectStored = JSON.parse(<string>localStorage.getItem(keyName));

		if (objectStored !== null){
			return objectStored;
		} else {
			return false;
		}
	}


decode(html:string)
	{
		let decoder = document.createElement('div');
		decoder.innerHTML = html;
		return decoder.textContent;
	}