export async function resolveOption(root: string, cliOption: CliOption): Promise<ResolvedOption> {
  const viteConfig = await loadConfigFromFile(
    { command: 'build', mode: 'prod' },
    path.join(root, 'vite.config.ts')
  );

  const mergedViteConfig: UserConfig = mergeConfig(viteConfig ? viteConfig.config : {}, {
    root,
    build: {
      write: false,
      assetsInlineLimit: Number.MAX_SAFE_INTEGER,
      chunkSizeWarningLimit: Number.MAX_SAFE_INTEGER,
      cssCodeSplit: false,
      brotliSize: false,
      rollupOptions: {
        inlineDynamicImports: true,
        output: {
          manualChunks: () => 'all-in-one.js'
        },
        onwarn() {}
      }
    },
    logLevel: 'silent',
    plugins: [viteSingleFile()]
  });

  if (!mergedViteConfig.email) {
    mergedViteConfig.email = { enable: false };
  } else if (cliOption.send === false) {
    mergedViteConfig.email.enable = false;
  } else {
    mergedViteConfig.email.enable = true;
  }

  if (!mergedViteConfig.email.auth) {
    mergedViteConfig.email.auth = {};
  }

  const emailConfig = mergedViteConfig.email;
  const receivers: Receiver[] = [];

  // If specify send target, do not read csv
  if (typeof cliOption.send === 'string' && cliOption.send.length > 0) {
    receivers.push({ receiver: cliOption.send, attachments: [], frontmatter: {} });
  } else {
    if (!emailConfig.csv) {
      emailConfig.csv = 'data.csv';
    }
    const csvPath = path.join(root, emailConfig.csv!);
    receivers.push(...(await loadCSV(csvPath, emailConfig.frontmatter)));
  }

  // 1. Cli Option (overwrite vite config)
  if (cliOption.user) {
    emailConfig.auth!.user = cliOption.user;
  }
  if (cliOption.pass) {
    emailConfig.auth!.pass = cliOption.pass;
  }

  // 2. Prompt user / pass
  if (emailConfig.enable) {
    if (!emailConfig.auth!.user) {
      emailConfig.auth!.user = await promptForUser();
      emailConfig.auth!.pass = await promptForPass();
    } else if (!emailConfig?.auth?.pass) {
      emailConfig.auth!.pass = await promptForPass();
    }
  }

  if (!emailConfig.sender) {
    emailConfig.sender = emailConfig.auth!.user!;
  }

  const option: ResolvedOption = {
    vite: mergedViteConfig,
    template: fs.readFileSync(path.join(root, cliOption.md), 'utf8'),
    frontmatter: emailConfig.frontmatter ?? {},
    email: mergedViteConfig.email as Required<ViteEmailConfig>,
    entry: normalizePath(path.resolve(process.cwd(), root, cliOption.md)),
    receivers
  };

  return option;
}


async function promptForUser() {
  const prompts = (await import('prompts')).default;
  const { user } = await prompts({
    type: 'text',
    name: 'user',
    message: ' User'
  });
  return user;
}


async function promptForPass() {
  const prompts = (await import('prompts')).default;
  const { pass } = await prompts({
    type: 'password',
    name: 'pass',
    message: ' Pass'
  });
  return pass;
}


export async function loadCSV(
  filePath: string,
  frontmatter: Record<string, string | FrontmatterFn> = {}
): Promise<Receiver[]> {
  const content = fs.readFileSync(filePath, 'utf-8');
  const { parse } = await import('csv-parse/sync');
  const result = parse(content, {
    encoding: 'utf-8',
    columns: true,
    skip_empty_lines: true,
    trim: true
  });
  return parseCSV(result, frontmatter);
}


function parseCSV(
  rawData: Array<Record<string, string>>,
  frontmatter: Record<string, string | FrontmatterFn> = {}
): Receiver[] {
  const names: string[] = [];
  const receivers: Receiver[] = [];

  const getField = (record: Record<string, string>, field: string) => {
    if (field in record) {
      return record[field];
    } else if (field in frontmatter) {
      const defaultValue = frontmatter[field];
      if (typeof defaultValue === 'string') {
        return defaultValue;
      } else if (typeof defaultValue === 'function') {
        return defaultValue(record);
      } else {
        return undefined;
      }
    }
  };

  const getReceiver = (record: Record<string, string>): string | undefined =>
    getField(record, 'receiver');

  const getAttachment = (record: Record<string, string>): string[] => {
    const rawAttachment =
      (getField(record, 'attachment') ?? '') + ':' + (getField(record, 'attachments') ?? '');

    return rawAttachment
      .split(':')
      .map((t) => t.trim())
      .filter(Boolean);
  };

  const getExtraField = (record: Record<string, string>): Record<string, string> => {
    const extra: Record<string, string> = {};
    for (const key in frontmatter) {
      if (
        key === 'receiver' ||
        key === 'subject' ||
        key === 'attachment' ||
        key === 'attachments'
      ) {
        continue;
      }
      const value = getField(record, key);
      if (value) {
        extra[key] = value;
      }
    }
    return extra;
  };

  for (const receiver of rawData) {
    const name = getReceiver(receiver);
    if (!name || name.length === 0) {
      throw new Error(`Get receiver fail in "${JSON.stringify(receiver)}"`);
    } else {
      names.push(name);
    }

    const attachments: string[] = getAttachment(receiver);

    receivers.push({
      receiver: name,
      subject: getField(receiver, 'subject'),
      attachments,
      frontmatter: {
        ...getExtraField(receiver),
        ...receiver
      }
    });
  }

  if (new Set(names).size !== names.length) {
    throw new Error('Duplicate receivers');
  }

  return receivers;
}


export async function writeCSV(filePath: string, arr: Array<Receiver>) {
  const { stringify } = await import('csv-stringify/sync');
  const content = stringify(arr, { header: true });
  fs.writeFileSync(filePath, content, 'utf-8');
}


() => 'all-in-one.js'


(record: Record<string, string>, field: string) => {
    if (field in record) {
      return record[field];
    } else if (field in frontmatter) {
      const defaultValue = frontmatter[field];
      if (typeof defaultValue === 'string') {
        return defaultValue;
      } else if (typeof defaultValue === 'function') {
        return defaultValue(record);
      } else {
        return undefined;
      }
    }
  }


(record: Record<string, string>): string | undefined =>
    getField(record, 'receiver')


(record: Record<string, string>): string[] => {
    const rawAttachment =
      (getField(record, 'attachment') ?? '') + ':' + (getField(record, 'attachments') ?? '');

    return rawAttachment
      .split(':')
      .map((t) => t.trim())
      .filter(Boolean);
  }


(t) => t.trim()


(record: Record<string, string>): Record<string, string> => {
    const extra: Record<string, string> = {};
    for (const key in frontmatter) {
      if (
        key === 'receiver' ||
        key === 'subject' ||
        key === 'attachment' ||
        key === 'attachments'
      ) {
        continue;
      }
      const value = getField(record, key);
      if (value) {
        extra[key] = value;
      }
    }
    return extra;
  }


async () => {
    expect(await loadCSV(path.join(__dirname, '../example/data.csv'))).toMatchInlineSnapshot(`
      [
        {
          "attachments": [],
          "frontmatter": {
            "name": "XLor",
            "receiver": "yjl9903@vip.qq.com",
          },
          "receiver": "yjl9903@vip.qq.com",
          "subject": undefined,
        },
        {
          "attachments": [],
          "frontmatter": {
            "name": "yjl",
            "receiver": "yan_jl@yeah.net",
          },
          "receiver": "yan_jl@yeah.net",
          "subject": undefined,
        },
      ]
    `);
  }


() => {
    expect(parseCSV([{ name: '123' }], { receiver: 'name' })).toMatchInlineSnapshot(`
      [
        {
          "attachments": [],
          "frontmatter": {
            "name": "123",
          },
          "receiver": "name",
          "subject": undefined,
        },
      ]
    `);

    expect(parseCSV([{ receiver: '123' }], { name: 'abc' })).toMatchInlineSnapshot(`
      [
        {
          "attachments": [],
          "frontmatter": {
            "name": "abc",
            "receiver": "123",
          },
          "receiver": "123",
          "subject": undefined,
        },
      ]
    `);

    expect(parseCSV([{ 姓名: '456' }], { receiver: (r) => r['姓名'] })).toMatchInlineSnapshot(`
      [
        {
          "attachments": [],
          "frontmatter": {
            "姓名": "456",
          },
          "receiver": "456",
          "subject": undefined,
        },
      ]
    `);
  }


(r) => r['姓名']


() => {
    // @ts-ignore
    expect(() => parseCSV([{ name: '123' }])).toThrowErrorMatchingInlineSnapshot(
      '"Get receiver fail in \\"{\\"name\\":\\"123\\"}\\""'
    );
    // @ts-ignore
    expect(() => parseCSV([{ receiver: '' }])).toThrowErrorMatchingInlineSnapshot(
      '"Get receiver fail in \\"{\\"receiver\\":\\"\\"}\\""'
    );
    expect(() =>
      // @ts-ignore
      parseCSV([{ receiver: '1' }, { receiver: '1' }])
    ).toThrowErrorMatchingInlineSnapshot('"Duplicate receivers"');
  }


() => parseCSV([{ name: '123' }])


() => parseCSV([{ receiver: '' }])


() =>
      // @ts-ignore
      parseCSV([{ receiver: '1' }, { receiver: '1' }])


() => {
    expect(parseCSV([{ receiver: '123', attachment: '123', attachments: '456:789' }]))
      .toMatchInlineSnapshot(`
      [
        {
          "attachments": [
            "123",
            "456",
            "789",
          ],
          "frontmatter": {
            "attachment": "123",
            "attachments": "456:789",
            "receiver": "123",
          },
          "receiver": "123",
          "subject": undefined,
        },
      ]
    `);

    expect(parseCSV([{ receiver: '123' }], { attachment: 'pdf' })).toMatchInlineSnapshot(`
      [
        {
          "attachments": [
            "pdf",
          ],
          "frontmatter": {
            "receiver": "123",
          },
          "receiver": "123",
          "subject": undefined,
        },
      ]
    `);

    expect(parseCSV([{ receiver: '123' }], { attachment: (r) => r['receiver'] + '.pdf' }))
      .toMatchInlineSnapshot(`
        [
          {
            "attachments": [
              "123.pdf",
            ],
            "frontmatter": {
              "receiver": "123",
            },
            "receiver": "123",
            "subject": undefined,
          },
        ]
      `);
  }


(r) => r['receiver'] + '.pdf'


export type Receiver = {
  receiver: string;
  subject?: string;
  attachments: string[];
  frontmatter: Record<string, string>;
};


type ResolvedOption = RenderOption & {
  entry: string;
  email: Required<ViteEmailConfig>;
  receivers: Receiver[];
};


onwarn() {}


function mapStateToProps(state: RootState): StoreProps {
  return {
    recentSearches: recentSearchesSelector(state),
    isPhonePortrait: isPhonePortraitSelector(state),
    autocompleter: autoCompleterSelector(state),
  };
}


/**
 * A reusable, autocompleting item search input. This is an uncontrolled input that
 * announces its query has changed only after some delay. This is the new version of the component
 * that offers a browser-style autocompleting search bar with history.
 *
 * TODO: Should this be the main search bar only, or should it also work for item picker, etc?
 */
function SearchBar(
  {
    searchQueryVersion,
    searchQuery,
    placeholder,
    children,
    autoFocus,
    onQueryChanged,
    onClear,
    dispatch,
    autocompleter,
    recentSearches,
    isPhonePortrait,
  }: Props,
  ref: React.Ref<SearchFilterRef>
) {
  const [liveQuery, setLiveQuery] = useState('');
  const [filterHelpOpen, setFilterHelpOpen] = useState(false);
  const inputElement = useRef<HTMLInputElement>(null);
  const [items, setItems] = useState(() => autocompleter(liveQuery, 0, recentSearches));
  // TODO: this isn't great. We need https://github.com/downshift-js/downshift/issues/1144
  useEffect(() => {
    setItems(autocompleter(liveQuery, inputElement.current?.selectionStart || 0, recentSearches));
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [recentSearches]);

  // eslint-disable-next-line react-hooks/exhaustive-deps
  const debouncedUpdateQuery = useCallback(
    _.debounce((query: string) => {
      onQueryChanged(query);
    }, 500),
    [onQueryChanged]
  );

  const lastBlurQuery = useRef<string>();
  const onBlur = () => {
    if (liveQuery && liveQuery !== lastBlurQuery.current) {
      // save this to the recent searches only on blur
      // we use the ref to only fire if the query changed since the last blur
      dispatch(searchUsed(liveQuery));
      lastBlurQuery.current = liveQuery;
    }
  };

  // Is the current search saved?
  const canonical = liveQuery ? canonicalizeQuery(parseQuery(liveQuery)) : '';
  const saved = canonical ? recentSearches.find((s) => s.query === canonical)?.saved : false;

  const toggleSaved = () => {
    // TODO: keep track of the last search, if you search for something more narrow immediately after then replace?
    dispatch(saveSearch({ query: liveQuery, saved: !saved }));
  };

  const setQuery = useCallback(
    (query: string, immediate = false) => {
      setLiveQuery(query);
      debouncedUpdateQuery(query);
      if (immediate) {
        debouncedUpdateQuery.flush();
      }
      setItems(
        autocompleter(query, inputElement.current!.selectionStart || query.length, recentSearches)
      );
    },
    [autocompleter, debouncedUpdateQuery, recentSearches]
  );

  // useCombobox from Downshift manages the state of the dropdown
  const {
    isOpen,
    getToggleButtonProps,
    getMenuProps,
    getInputProps,
    getLabelProps,
    getComboboxProps,
    highlightedIndex,
    getItemProps,
    reset,
    openMenu,
  } = useCombobox<SearchItem>({
    items,
    inputValue: liveQuery,
    defaultIsOpen: isPhonePortrait,
    defaultHighlightedIndex: liveQuery ? 0 : -1,
    itemToString: (i) => i?.query || '',
    onSelectedItemChange: ({ selectedItem }) => {
      if (selectedItem) {
        // Handle selecting the special "help" item
        if (selectedItem.type === SearchItemType.Help) {
          setFilterHelpOpen(true);
        } else {
          setQuery(selectedItem.query, true);
        }
      }
    },
    stateReducer: (state, actionAndChanges) => {
      const { type, changes } = actionAndChanges;
      switch (type) {
        case useCombobox.stateChangeTypes.FunctionReset:
          // Keep the menu open when we clear the input
          return changes.inputValue !== undefined
            ? {
                ...changes, // default Downshift new state changes on item selection.
                isOpen: state.isOpen, // but keep menu open
              }
            : changes;
        case useCombobox.stateChangeTypes.InputKeyDownEscape: {
          // Reimplement clear - we are controlling the input which break this
          // See https://github.com/downshift-js/downshift/issues/1108
          setQuery('', true);
          return changes;
        }
        default:
          return changes; // otherwise business as usual.
      }
    },
  });

  // This is a hack to fix https://github.com/downshift-js/downshift/issues/1108
  const onChange = (e) => {
    const inputValue = e.target.value;
    setQuery(inputValue || '');
  };

  const onFocus = () => {
    if (!liveQuery && !isOpen) {
      openMenu();
    }
  };

  const clearFilter = useCallback(() => {
    setQuery('', true);
    onClear?.();
    reset();
    openMenu();
  }, [setQuery, onClear, reset, openMenu]);

  // Reset live query when search version changes
  useEffect(() => {
    if (searchQuery !== undefined) {
      setLiveQuery(searchQuery);
    }
    // This should only happen when the query version changes
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [searchQueryVersion]);

  const deleteSearch = useCallback(
    (e: React.MouseEvent, item: SearchItem) => {
      e.stopPropagation();
      dispatch(searchDeleted(item.query));
    },
    [dispatch]
  );

  // Add some methods for refs to use
  useImperativeHandle(
    ref,
    () => ({
      focusFilterInput: () => {
        inputElement.current?.focus();
      },
      clearFilter,
    }),
    [clearFilter]
  );

  // Setting this ref's value allows us to set the cursor position to a specific index on the next render
  const selectionRef = useRef<number>();
  useLayoutEffect(() => {
    if (selectionRef.current !== undefined && inputElement.current) {
      inputElement.current.setSelectionRange(selectionRef.current, selectionRef.current);
      selectionRef.current = undefined;
    }
  });

  // Implement tab completion on the tab key. If the highlighted item is an autocomplete suggestion,
  // accept it. Otherwise, we scan from the beginning to find the first autocomplete suggestion and
  // accept that. If there's nothing to accept, the tab key does its normal thing, which is to switch
  // focus. The tabAutocompleteItem is computed as part of render so we can offer keyboard help.
  const tabAutocompleteItem =
    highlightedIndex > 0 && items[highlightedIndex]?.type === SearchItemType.Autocomplete
      ? items[highlightedIndex]
      : items.find((s) => s.type === SearchItemType.Autocomplete && s.query !== liveQuery);
  const onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (e.key === 'Tab' && tabAutocompleteItem) {
      e.preventDefault();
      setQuery(tabAutocompleteItem.query, true);
      if (tabAutocompleteItem.highlightRange) {
        selectionRef.current = tabAutocompleteItem.highlightRange[1];
      }
    }
  };

  return (
    <div
      className={clsx('search-filter', styles.searchBar, { [styles.open]: isOpen })}


() =>
  import(/* webpackChunkName: "filter-help" */ './FilterHelp')


() => autocompleter(liveQuery, 0, recentSearches)


() => {
    setItems(autocompleter(liveQuery, inputElement.current?.selectionStart || 0, recentSearches));
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }


(query: string) => {
      onQueryChanged(query);
    }


() => {
    if (liveQuery && liveQuery !== lastBlurQuery.current) {
      // save this to the recent searches only on blur
      // we use the ref to only fire if the query changed since the last blur
      dispatch(searchUsed(liveQuery));
      lastBlurQuery.current = liveQuery;
    }
  }


(s) => s.query === canonical


() => {
    // TODO: keep track of the last search, if you search for something more narrow immediately after then replace?
    dispatch(saveSearch({ query: liveQuery, saved: !saved }));
  }


(query: string, immediate = false) => {
      setLiveQuery(query);
      debouncedUpdateQuery(query);
      if (immediate) {
        debouncedUpdateQuery.flush();
      }
      setItems(
        autocompleter(query, inputElement.current!.selectionStart || query.length, recentSearches)
      );
    }


(i) => i?.query || ''


({ selectedItem }) => {
      if (selectedItem) {
        // Handle selecting the special "help" item
        if (selectedItem.type === SearchItemType.Help) {
          setFilterHelpOpen(true);
        } else {
          setQuery(selectedItem.query, true);
        }
      }
    }


(state, actionAndChanges) => {
      const { type, changes } = actionAndChanges;
      switch (type) {
        case useCombobox.stateChangeTypes.FunctionReset:
          // Keep the menu open when we clear the input
          return changes.inputValue !== undefined
            ? {
                ...changes, // default Downshift new state changes on item selection.
                isOpen: state.isOpen, // but keep menu open
              }
            : changes;
        case useCombobox.stateChangeTypes.InputKeyDownEscape: {
          // Reimplement clear - we are controlling the input which break this
          // See https://github.com/downshift-js/downshift/issues/1108
          setQuery('', true);
          return changes;
        }
        default:
          return changes; // otherwise business as usual.
      }
    }


(e) => {
    const inputValue = e.target.value;
    setQuery(inputValue || '');
  }


() => {
    if (!liveQuery && !isOpen) {
      openMenu();
    }
  }


() => {
    setQuery('', true);
    onClear?.();
    reset();
    openMenu();
  }


() => {
    if (searchQuery !== undefined) {
      setLiveQuery(searchQuery);
    }
    // This should only happen when the query version changes
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }


(e: React.MouseEvent, item: SearchItem) => {
      e.stopPropagation();
      dispatch(searchDeleted(item.query));
    }


() => ({
      focusFilterInput: () => {
        inputElement.current?.focus();
      },
      clearFilter,
    })


() => {
        inputElement.current?.focus();
      }


() => {
    if (selectionRef.current !== undefined && inputElement.current) {
      inputElement.current.setSelectionRange(selectionRef.current, selectionRef.current);
      selectionRef.current = undefined;
    }
  }


(s) => s.type === SearchItemType.Autocomplete && s.query !== liveQuery


(e: React.KeyboardEvent<HTMLInputElement>) => {
    if (e.key === 'Tab' && tabAutocompleteItem) {
      e.preventDefault();
      setQuery(tabAutocompleteItem.query, true);
      if (tabAutocompleteItem.highlightRange) {
        selectionRef.current = tabAutocompleteItem.highlightRange[1];
      }
    }
  }


(item, index) => (
            <li
              className={clsx(styles.menuItem,


({
    highlighted,
    item,
    isPhonePortrait,
    isTabAutocompleteItem,
    onClick,
  }: {
    highlighted: boolean;
    item: SearchItem;
    isPhonePortrait: boolean;
    isTabAutocompleteItem: boolean;
    onClick(e: React.MouseEvent, item: SearchItem);
  }) => (
    <>
      <AppIcon className={styles.menuItemIcon}


interface ProvidedProps {
  /** Placeholder text when nothing has been typed */
  placeholder: string;
  /** Whether to autofocus this on mount */
  autoFocus?: boolean;
  /** A fake property that can be used to force the "live" query to be replaced with the one from props */
  searchQueryVersion?: number;
  /** The search query to fill in the input. This is used only initially, or when searchQueryVersion changes */
  searchQuery?: string;
  /** Children are used as optional extra action buttons only when there is a query. */
  children?: React.ReactChild;
  /** Fired whenever the query changes (already debounced) */
  onQueryChanged(query: string): void;
  /** Fired whenever the query has been cleared */
  onClear?(): void;
}


interface StoreProps {
  recentSearches: Search[];
  isPhonePortrait: boolean;
  autocompleter: (query: string, caretIndex: number, recentSearches: Search[]) => SearchItem[];
}


// TODO: break filter autocomplete into its own object/helpers... with tests
/** An interface for interacting with the search filter through a ref */
export interface SearchFilterRef {
  /** Switch focus to the filter field */
  focusFilterInput(): void;
  /** Clear the filter field */
  clearFilter(): void;
}


type Props = ProvidedProps & StoreProps & ThunkDispatchProp;


clsx('search-filter', styles


t('Header.SaveSearch')


t('Header.Clear')


clsx('filter-bar-button', styles


t('Header.Filters')


clsx(styles


t('Hotkey.Tab')


t('Hotkey.Enter')


t('Header.DeleteSearch')


@NgModule({
  imports: [
    SharedModule,
    RouterModule.forChild([
      {path: 'login', component: LoginComponent}
    ])
  ],
  declarations: [
    LoginComponent
  ]
})
export class UserModule { }


@Component({
  selector: "app-action-bar",
  templateUrl: "./action-bar.component.html",
  styleUrls: ["./action-bar.component.css"]
})
export class ActionBarComponent {}


fileName(format) {
                switch (format) {
                    case "es":
                        return "index.mjs";
                    case "cjs":
                        return "index.cjs";
                    default:
                        return "index.js";
                }
            }


() => {throw new Error((`Feed ${name} already exists`)); }


(e) => fsPromises.readFile(Feed.TEMPLATE)


(x) => this.itemsFromSnapshot(x)


(item) => {
      item.description = this.sanitizeHtml(item.description, images);
    }


(attr: any) => allowedAttributes[attr.name]


(attr: any) => attr.name === "src"


(src: any) => {
            const image = this.imageFromUrl(src.value);
            images.push(image);
            src.value = image.localUrl;
          }


(node: any) => allowedTags[node.nodeName]


(node: any) => this.sanitizeElement(node, images)


async (tmpPath: string) => {
      const hash = (s: rss.Channel) => this.channelHash(s);
      const oldHashes = (await this.channelSnapshots()).map(hash);
      const newHash = await fsPromises.readFile(tmpPath)
          .then((s) => hash(this.channelFromSnapshot(s.toString())));
      return oldHashes.filter((oldHash) => oldHash === newHash).length === 0;
    }


(s: rss.Channel) => this.channelHash(s)


(s) => hash(this.channelFromSnapshot(s.toString()))


(oldHash) => oldHash === newHash


(a: string, b: string) => {
      // Extract the timestamp from the file names.
      const aValue = parseInt(a.split(".")[0], 10);
      const bValue = parseInt(b.split(".")[0], 10);
      return bValue - aValue;
    }


(name) => this.feedPath(Feed.PATH_SNAPSHOTS, name)


(item) => {
      if (guids[item.guid]) {
        return;
      }

      guids[item.guid] = true;
      filteredItems.push(item);
    }


(a: rss.Item, b: rss.Item) => b.pubDate - a.pubDate


(item) => !guids[this.hash(item.guid)]


(name) => name.split(".")[0]


(hash) => { x[hash] = true; }


(item) => item.guidHash


(date: string) => {
      try {
        return Date.parse(date);
      } catch (e) {
        return 0;
      }
    }


(item: any) => {
      const ext = path.extname(new url.URL(item.enclosure["@_url"]).pathname) ||
                 ".mp3";
      const guid = item.guid["#text"] || item.guid;
      const guidHash = this.hash(guid);
      const localName = `${guidHash}${ext}`;
      return {
        description: item["content:encoded"] || item.description,
        enclosure: {
          length: item.enclosure["@_length"],
          localPath: this.feedPath(Feed.PATH_AUDIO, localName),
          localUrl: `${this.localUrlBase}/${Feed.PATH_AUDIO}/${localName}`,
          remoteUrl: item.enclosure["@_url"],
          type: item.enclosure["@_type"],
        },
        guid,
        guidHash,
        link: item.link,
        pubDate: Date.parse(item.pubDate),
        pubDateAsString:
            new Date(Date.parse(item.pubDate)).toDateString(),
        title: item.title,
      };
    }


(s) => this.channelFromSnapshot(s)


(snapshotPath: string) =>
        fsPromises.readFile(snapshotPath)
            .then((x) => x.toString())


(x) => x.toString()


(paths) => Promise.all(paths.map(readSnapshot))


(d) => d.isFile()


(d) => d.name


(name) => !name.endsWith(".download")


/**
 * An object where the keys are values from some ID space and values (if they
 * exist) are always true.
 */
interface IdSet {
  [id: string]: true;
}


/** The raw string value of a snapshotted RSS feed. */
type RawSnapshot = any;


/** The parsed XML of a snapshotted RSS feed. */
type XmlSnapshot = any;


/** Loads a feed from disk. */
public static async load(db: Archive, name: string): Promise<Feed> {
    const feedUrl = await
        fsPromises.readFile(path.join(db.path, name, Feed.PATH_FEED_URL));
    return new Feed(db, name, feedUrl.toString());
  }


/** Creates a new feed in the archive that tracks a given URL. */
public static async create(
      db: Archive, name: string, feedUrl: string): Promise<Feed> {
    const feedPath = path.join(db.path, name);
    const urlFile = path.join(db.path, name, Feed.PATH_FEED_URL);
    await fsPromises.stat(feedPath)
        .then(
          () => {throw new Error((`Feed ${name} already exists`)); },
          () => null);
    await fsPromises.ensureDir(feedPath);
    await fsPromises.ensureDir(path.join(feedPath, Feed.PATH_CONFIG));
    await fsPromises.writeFile(urlFile, feedUrl);
    return new Feed(db, name, feedUrl);
  }


/**
   * Generate the HTML interface for this feed.
   */
public async updateHtml(channel?: rss.Channel): Promise<void> {
    channel = channel || await this.generatedChannel();
    const template = await fsPromises
        .readFile(this.db.dbPath(Archive.PATH_CONFIG, Feed.TEMPLATE))
        .catch((e) => fsPromises.readFile(Feed.TEMPLATE));
    const view = {
      ...this.baseMustacheView(),
      channel,
    };
    const inflated = Mustache.render(template.toString(), view);
    await fsPromises.writeFile(this.feedPath(Feed.PATH_INDEX_HTML), inflated);
  }


/**
   * Updates the feed by fetching a new snapshot and downloading any new media
   * files.
   */
public async update(justMp3s = false) {
    if (!justMp3s) {
      try {
        await this.fetchSnapshot();
      } catch (e) {
        console.log(`Unable to fetch RSS feed for ${this.name}: ${e}`);
      }
    }
    const images: rss.Image[] = [];
    const channel = await this.generatedChannel(images);
    await this.fetchAudio(channel);
    await this.fetchImages(images);
    await this.saveFeed(channel);
  }


/**
   * Returns the generated channel definition for this feed.
   *
   * The generated channel includes episodes from all of the locally cached feed
   * snapshots.
   *
   * Takes an optional argument which accumulates images referenced in the
   * generated channel.
   */
public async generatedChannel(
      maybeImages?: rss.Image[]): Promise<rss.Channel> {
    const snapshots = await this.xmlSnapshots();
    const channel = this.channelMetaFromSnapshot(snapshots[0]);
    const allItems = ([] as rss.Item[]).concat(
        ...snapshots.map((x) => this.itemsFromSnapshot(x)));
    channel.items = this.uniquifyItems(allItems);
    const images = maybeImages || [];
    if (channel.image) {
      images.push(channel.image);
    }
    channel.items.forEach((item) => {
      item.description = this.sanitizeHtml(item.description, images);
    });
    return channel;
  }


private sanitizeHtml(html: string | string[], images: rss.Image[]): string {
    if (html instanceof Array) {
      html = html[0] || "";
    }
    const doc = parse5.parseFragment(html || "");
    this.sanitizeElement(doc as parse5.DefaultTreeDocumentFragment, images);
    return parse5.serialize(doc);
  }


private sanitizeElement(element: any, images: rss.Image[]) {
    if (element.attrs) {
      const allowedAttributes: {[attr: string]: boolean} = {
        alt: true,
        height: true,
        href: true,
        rel: true,
        src: true,
        target: true,
        title: true,
        width: true,
      };
      element.attrs =
          element.attrs.filter((attr: any) => allowedAttributes[attr.name]);
    }

    if (element.nodeName === "img" && element.attrs) {
      element.attrs
          .filter((attr: any) => attr.name === "src")
          .forEach((src: any) => {
            const image = this.imageFromUrl(src.value);
            images.push(image);
            src.value = image.localUrl;
          });
    }

    if (element.childNodes) {
      const allowedTags: {[tag: string]: boolean} = {
        "#text": true,
        "a": true,
        "div": true,
        "em": true,
        "img": true,
        "p": true,
        "span": true,
        "strong": true,
      };
      element.childNodes =
          element.childNodes.filter((node: any) => allowedTags[node.nodeName]);
      element.childNodes.map((node: any) => this.sanitizeElement(node, images));
    }
  }


/**
   * Return a set of archive-level variables that are exposed to all mustache
   * templates.
   */
private baseMustacheView() {
    return {
      ...this.db.baseMustacheView(),
      feedBaseUrl: this.localUrlBase,
      feedUrl: this.localUrl,
      name: this.name,
    };
  }


private async saveFeed(channel: rss.Channel) {
    await fsPromises.writeFile(
      this.feedPath(Feed.PATH_RSS),
      rss.toXml(channel));
  }


private async fetchSnapshot(): Promise<any> {
    const snapshotPath = await this.nextSnapshotPath();
    // Used as the validator to only save snapshots if the provide new unique
    // content. This prevents the explosion of saved snapshots and allows for
    // snapshots to be fetched at frequent intervals.
    const isNewSnapshot = async (tmpPath: string) => {
      const hash = (s: rss.Channel) => this.channelHash(s);
      const oldHashes = (await this.channelSnapshots()).map(hash);
      const newHash = await fsPromises.readFile(tmpPath)
          .then((s) => hash(this.channelFromSnapshot(s.toString())));
      return oldHashes.filter((oldHash) => oldHash === newHash).length === 0;
    };
    const isNew = await download(
        `${this.name} RSS feed`, this.url, snapshotPath, isNewSnapshot);
    if (isNew) {
      console.log(`Change detected in RSS feed of ${this.name}.`);
    }
  }


private async snapshotPaths(): Promise<string[]> {
    const compareSnapshotFiles = (a: string, b: string) => {
      // Extract the timestamp from the file names.
      const aValue = parseInt(a.split(".")[0], 10);
      const bValue = parseInt(b.split(".")[0], 10);
      return bValue - aValue;
    };
    return (await this.filesUnder(this.feedPath(Feed.PATH_SNAPSHOTS)))
        .sort(compareSnapshotFiles)
        .map((name) => this.feedPath(Feed.PATH_SNAPSHOTS, name));
  }


private async nextSnapshotPath(): Promise<string> {
    await fsPromises.ensureDir(this.feedPath(Feed.PATH_SNAPSHOTS));
    return this.feedPath(Feed.PATH_SNAPSHOTS, `${Date.now()}.xml`);
  }


private uniquifyItems(items: rss.Item[]): rss.Item[] {
    const guids: IdSet = {};
    const filteredItems: rss.Item[] = [];
    items.forEach((item) => {
      if (guids[item.guid]) {
        return;
      }

      guids[item.guid] = true;
      filteredItems.push(item);
    });
    const compareDates = (a: rss.Item, b: rss.Item) => b.pubDate - a.pubDate;
    return filteredItems.sort(compareDates);
  }


private async fetchImages(images: rss.Image[]) {
    await fsPromises.ensureDir(this.feedPath(Feed.PATH_IMAGES));

    for (const image of images) {
      const imageExists = await fsPromises
          .stat(image.localPath)
          .then(() => true, () => false);
      if (imageExists) {
        continue;
      }

      await download(
          `${this.name} artwork`,
          image.remoteUrl,
          image.localPath);
    }
  }


private async fetchAudio(channel: rss.Channel) {
    await fsPromises.ensureDir(this.feedPath(Feed.PATH_AUDIO));
    const guids = await this.existingGuidHashes();
    const items = await channel.items
        .filter((item) => !guids[this.hash(item.guid)]);

    for (const item of items) {
      await download(
        `${this.name} - ${item.title}`,
        item.enclosure.remoteUrl,
        item.enclosure.localPath);
    }
  }


/**
   * Returns list of the hashed GUID values for the already downloaded audio
   * files.
   */
private async existingGuidHashes(): Promise<IdSet> {
    const hashes =
        (await this.filesUnder(this.feedPath(Feed.PATH_AUDIO)))
            .map((name) => name.split(".")[0]);
    const x: IdSet = {};
    hashes.forEach((hash) => { x[hash] = true; });
    return Promise.resolve(x);
  }


private hash(guid: string) {
    try {
      return createHash("sha1").update(guid.toString()).digest("hex");
    } catch (e) {
      console.log(`Unable to hash GUID ${guid}:`, e);
      throw e;
    }
  }


/**
   * Hashes a channel such that two channels have the same hash IFF they provide
   * the exact same set of episodes (as determined by their GUID).
   */
private channelHash(channel: rss.Channel): string {
    return this.hash(channel.items.map((item) => item.guidHash).join(":"));
  }


/**
   * Returns a complete channel definition from a single XML snapshot.
   */
private channelFromSnapshot(snapshot: string): rss.Channel {
    const xml = rss.fromXml(snapshot);
    return {
      ...this.channelMetaFromSnapshot(xml),
      items: this.itemsFromSnapshot(xml),
    };
  }


/**
   * Returns a channel definition from an XML snapshot excluding any episodes.
   */
private channelMetaFromSnapshot(snapshot: XmlSnapshot): rss.Channel {
    const parseDate = (date: string) => {
      try {
        return Date.parse(date);
      } catch (e) {
        return 0;
      }
    };

    const itunesOwner = snapshot.rss.channel["itunes:owner"];
    let owner;
    if (itunesOwner &&
        itunesOwner["itunes:name"] &&
        itunesOwner["itunes:email"]) {
      owner = {
        email: itunesOwner["itunes:email"],
        name: itunesOwner["itunes:name"],
      };
    }

    const imageRemoteUrl =
        (snapshot.rss.channel.image || {}).url ||
        (snapshot.rss.channel["itunes:image"] || {})["@_href"];
    let image;
    if (imageRemoteUrl) {
      image = this.imageFromUrl(imageRemoteUrl);
    }
    return {
      author: snapshot.rss.channel["itunes:author"],
      copyright: snapshot.rss.channel.copyright,
      description: snapshot.rss.channel.description,
      image,
      items: [],
      language: snapshot.rss.channel.language,
      lastBuildDate: parseDate(snapshot.rss.channel.lastBuildDate),
      link: snapshot.rss.channel.link,
      owner,
      pubDate: parseDate(snapshot.rss.channel.pubDate),
      title: snapshot.rss.channel.title,
    };
  }


private imageFromUrl(remoteUrl: string): rss.Image {
    const localName = `${this.hash(remoteUrl)}`;
    return {
      localPath: this.feedPath(Feed.PATH_IMAGES, localName),
      localUrl: `${this.localUrlBase}/${Feed.PATH_IMAGES}/${localName}`,
      remoteUrl,
    };
  }


/**
   * Returns a list of items that are provided by an Xml snapshot.
   */
private itemsFromSnapshot(snapshot: XmlSnapshot): rss.Item[] {
    return (snapshot.rss.channel.item || []).map((item: any) => {
      const ext = path.extname(new url.URL(item.enclosure["@_url"]).pathname) ||
                 ".mp3";
      const guid = item.guid["#text"] || item.guid;
      const guidHash = this.hash(guid);
      const localName = `${guidHash}${ext}`;
      return {
        description: item["content:encoded"] || item.description,
        enclosure: {
          length: item.enclosure["@_length"],
          localPath: this.feedPath(Feed.PATH_AUDIO, localName),
          localUrl: `${this.localUrlBase}/${Feed.PATH_AUDIO}/${localName}`,
          remoteUrl: item.enclosure["@_url"],
          type: item.enclosure["@_type"],
        },
        guid,
        guidHash,
        link: item.link,
        pubDate: Date.parse(item.pubDate),
        pubDateAsString:
            new Date(Date.parse(item.pubDate)).toDateString(),
        title: item.title,
      };
    });
  }


/**
   * Returns a list of channel definitions derived from each snapshot in
   * isolation.
   */
private async channelSnapshots(): Promise<rss.Channel[]> {
    return (await this.rawSnapshots()).map((s) => this.channelFromSnapshot(s));
  }


/**
   * Returns a list of parsed XML documents corresponding to the snapshoted RSS
   * feeds.
   */
private async xmlSnapshots(): Promise<XmlSnapshot[]> {
    return (await this.rawSnapshots()).map(rss.fromXml);
  }


/**
   * Returns a list of the raw snapshoted RSS feeds.
   */
private async rawSnapshots(): Promise<RawSnapshot[]> {
    const readSnapshot = (snapshotPath: string) =>
        fsPromises.readFile(snapshotPath)
            .then((x) => x.toString());
    return this.snapshotPaths()
        .then((paths) => Promise.all(paths.map(readSnapshot)));
  }


/**
   * Returns all the (non pending download) files in a given directory.
   */
private async filesUnder(root: string): Promise<string[]> {
    const dirents = await fsPromises.readdir(
        root, {withFileTypes: true} as any);
    return (dirents as unknown as fs.Dirent[])
        .filter((d) => d.isFile())
        .map((d) => d.name)
        .filter((name) => !name.endsWith(".download"));
  }


private feedPath(...subDirs: string[]) {
    return path.join(this.db.path, this.name, ...subDirs);
  }


@Injectable({
    providedIn: 'root'
})
export class CategoryDeleteService{

    private _categoryListComponent: CategoryListComponent;

    constructor(private notifyMessage: NotifyMessageService){

    }

    set categoryListComponent(value: CategoryListComponent){
        this._categoryListComponent = value;
    }

    onDeleteSuccess(category){
        this.notifyMessage.success('Categoria deletada com sucesso');
        this._categoryListComponent.getCategories();
    }

    onDeleteError(e){
        console.log(e);
        this.notifyMessage.error(`Houve um erro desconhecido ao excluir a categoria
    Certifique-se que não há nenhum produto vinculado a essa categoria`);
    }

    showModalDelete(category){
        this._categoryListComponent.categoryDeleteModal.showModal(category);
    }
}


onDeleteSuccess(category){
        this.notifyMessage.success('Categoria deletada com sucesso');
        this._categoryListComponent.getCategories();
    }


onDeleteError(e){
        console.log(e);
        this.notifyMessage.error(`Houve um erro desconhecido ao excluir a categoria
    Certifique-se que não há nenhum produto vinculado a essa categoria`);
    }


showModalDelete(category){
        this._categoryListComponent.categoryDeleteModal.showModal(category);
    }


export function sqrt(value: BigNumber) {
  let z = value.add(ONE).div(TWO);
  let y = value;
  while (z.sub(y).isNegative()) {
      y = z;
      z = value.div(z).add(z).div(TWO);
  }
  return y;
}


(a: BigNumber, b: BigNumber): BigNumber => {
  return a.mul(b).div(PRECISE_UNIT);
}


(a: BigNumber, b: BigNumber): BigNumber => {
  if (a.eq(0) || b.eq(0)) {
    return ZERO;
  }

  return a.mul(b).sub(1).div(PRECISE_UNIT).add(1);
}


(a: BigNumber, b: BigNumber): BigNumber => {
  if (a.eq(0) || b.eq(0)) {
    return ZERO;
  }

  if (a.gt(0) && b.gt(0) || a.lt(0) && b.lt(0)) {
    return a.mul(b).sub(1).div(PRECISE_UNIT).add(1);
  } else {
    return a.mul(b).add(1).div(PRECISE_UNIT).sub(1);
  }
}


(a: BigNumber, b: BigNumber): BigNumber => {
  return a.mul(PRECISE_UNIT).div(b);
}


(a: BigNumber, b: BigNumber): BigNumber => {
  if (a.eq(0) || b.eq(0)) {
    return ZERO;
  }

  return a.mul(PRECISE_UNIT).sub(1).div(b).add(1);
}


(a: BigNumber, b: BigNumber): BigNumber => {
  if (a.eq(0) || b.eq(0)) {
    return ZERO;
  }

  if (a.gt(0) && b.gt(0) || a.lt(0) && b.lt(0)) {
    return a.mul(PRECISE_UNIT).sub(1).div(b).add(1);
  } else {
    return a.mul(PRECISE_UNIT).add(1).div(b).sub(1);
  }
}


(a: BigNumber, b: BigNumber): BigNumber => {
  let result = a.div(b);
  if (a.mul(b).lt(0) && !a.mod(b).isZero()) {
    result = result.sub(1);
  }
  return result;
}


(
  valueOne: BigNumber,
  valueTwo: BigNumber
): BigNumber => {
  return valueOne.lt(valueTwo) ? valueOne : valueTwo;
}


option => option.setName("user").setDescription("Mentions someone").setRequired(true)


option => option.setName("user2").setDescription("Mentions someone again").setRequired(true)


export default class ShipCommand extends Command {
    constructor(client) {
        super(client, {
            name: "ship",
            description: "Ship someone",
            category: "social",
            dev: false,
            data: new SlashCommandBuilder()
                .setName("ship")
                .setDescription("[Social] Ship someone")
                .addUserOption(option => option.setName("user").setDescription("Mentions someone").setRequired(true))
                .addUserOption(option => option.setName("user2").setDescription("Mentions someone again").setRequired(true))
        });
    }

    async execute(interaction, t): Promise<void> {
        const user = interaction.options.getUser("user");
        const user2 = interaction.options.getUser("user2");
        if (!user || !user2) return interaction.reply(t('commands:global.noUser'));

        const love = Math.floor(Math.random() * 100);

        const loveIndex = Math.floor(love / 10);
        const loveLevel = '█'.repeat(loveIndex) + '.'.repeat(10 - loveIndex);

        const firstName = user.username.length;
        const secondName = user.username;

        const calc1 = firstName - 4;
        const calc2 = secondName - 4;

        let shipName;
        if (love > 60) {
            shipName = user.username.slice(0, 3) + user2.username.slice(0, 3);
        } else if (love >= 40) {
            shipName = user.username.slice(0, calc1) + user2.username.slice(0, calc2);
        } else {
            shipName = user.username.slice(calc1, firstName) + user2.username.slice(calc2, secondName);
        }

        let desc;
        if (love > 90) {
            desc = (`:sparkling_heart: ${t('commands:ship.question')} :sparkling_heart:\n\`${user.username}\`\n\`${user2.username}\`\n:heart: \`${shipName}\` ${t('commands:ship.perfectCouple')} :heart:`);
        } else if (love >= 70) {
            desc = (`:sparkling_heart: ${t('commands:ship.question')} :sparkling_heart:\n\`${user.username}\`\n\`${user2.username}\`\n:neutral_face: \`${shipName}\` ${t('commands:ship.uwu')} :neutral_face:`);
        } else if (love >= 45) {
            desc = (`:sparkling_heart: ${t('commands:ship.question')} :sparkling_heart:\n\`${user.username}\`\n\`${user2.username}\`\n:no_mouth: \`${shipName}\` ${t('commands:ship.probably', { user: user2.username })} :no_mouth:`);
        } else {
            desc = (`:sparkling_heart: ${t('commands:ship.question')} :sparkling_heart:\n\`${user.username}\`\n\`${user2.username}\`\n:cry: \`${shipName}\` ${t('commands:ship.cry')} :cry: `);
        }

        let emoticon;
        if (love > 60) {
            emoticon = ('https://cdn.glitch.com/00963c7e-8e86-4a55-8d85-36add9e330d7%2Femoji_2.png?v=1593651528429');
        } else if (love >= 40) {
            emoticon = ('https://cdn.glitch.com/00963c7e-8e86-4a55-8d85-36add9e330d7%2Femoji_3-1.png?v=1593652255529');
        } else {
            emoticon = ('https://cdn.glitch.com/00963c7e-8e86-4a55-8d85-36add9e330d7%2Femoji_1.png?v=1593651511900');
        }

        const canvas = Canvas.createCanvas(384, 128);
        const ctx = canvas.getContext('2d');
        const emotes = await Canvas.loadImage(emoticon);
        const avatar1 = await Canvas.loadImage(user.displayAvatarURL({ format: "png" }));
        const avatar2 = await Canvas.loadImage(user2.displayAvatarURL({ format: "png" }));

        ctx.drawImage(emotes, 125, 0, 128, 128);
        ctx.drawImage(avatar1, -10, 0, 128, 128);
        ctx.drawImage(avatar2, 260, 0, 128, 128);
        const img = await new MessageAttachment(canvas.toBuffer(), 'ship.png')

        const shipEmbed = new MessageEmbed()
            .setDescription(`**${love}%** [\`${loveLevel}\`]`)
            .setImage("attachment://ship.png")
        interaction.reply({ content: desc, embeds: [shipEmbed], files: [img] });
    }
}


async execute(interaction, t): Promise<void> {
        const user = interaction.options.getUser("user");
        const user2 = interaction.options.getUser("user2");
        if (!user || !user2) return interaction.reply(t('commands:global.noUser'));

        const love = Math.floor(Math.random() * 100);

        const loveIndex = Math.floor(love / 10);
        const loveLevel = '█'.repeat(loveIndex) + '.'.repeat(10 - loveIndex);

        const firstName = user.username.length;
        const secondName = user.username;

        const calc1 = firstName - 4;
        const calc2 = secondName - 4;

        let shipName;
        if (love > 60) {
            shipName = user.username.slice(0, 3) + user2.username.slice(0, 3);
        } else if (love >= 40) {
            shipName = user.username.slice(0, calc1) + user2.username.slice(0, calc2);
        } else {
            shipName = user.username.slice(calc1, firstName) + user2.username.slice(calc2, secondName);
        }

        let desc;
        if (love > 90) {
            desc = (`:sparkling_heart: ${t('commands:ship.question')} :sparkling_heart:\n\`${user.username}\`\n\`${user2.username}\`\n:heart: \`${shipName}\` ${t('commands:ship.perfectCouple')} :heart:`);
        } else if (love >= 70) {
            desc = (`:sparkling_heart: ${t('commands:ship.question')} :sparkling_heart:\n\`${user.username}\`\n\`${user2.username}\`\n:neutral_face: \`${shipName}\` ${t('commands:ship.uwu')} :neutral_face:`);
        } else if (love >= 45) {
            desc = (`:sparkling_heart: ${t('commands:ship.question')} :sparkling_heart:\n\`${user.username}\`\n\`${user2.username}\`\n:no_mouth: \`${shipName}\` ${t('commands:ship.probably', { user: user2.username })} :no_mouth:`);
        } else {
            desc = (`:sparkling_heart: ${t('commands:ship.question')} :sparkling_heart:\n\`${user.username}\`\n\`${user2.username}\`\n:cry: \`${shipName}\` ${t('commands:ship.cry')} :cry: `);
        }

        let emoticon;
        if (love > 60) {
            emoticon = ('https://cdn.glitch.com/00963c7e-8e86-4a55-8d85-36add9e330d7%2Femoji_2.png?v=1593651528429');
        } else if (love >= 40) {
            emoticon = ('https://cdn.glitch.com/00963c7e-8e86-4a55-8d85-36add9e330d7%2Femoji_3-1.png?v=1593652255529');
        } else {
            emoticon = ('https://cdn.glitch.com/00963c7e-8e86-4a55-8d85-36add9e330d7%2Femoji_1.png?v=1593651511900');
        }

        const canvas = Canvas.createCanvas(384, 128);
        const ctx = canvas.getContext('2d');
        const emotes = await Canvas.loadImage(emoticon);
        const avatar1 = await Canvas.loadImage(user.displayAvatarURL({ format: "png" }));
        const avatar2 = await Canvas.loadImage(user2.displayAvatarURL({ format: "png" }));

        ctx.drawImage(emotes, 125, 0, 128, 128);
        ctx.drawImage(avatar1, -10, 0, 128, 128);
        ctx.drawImage(avatar2, 260, 0, 128, 128);
        const img = await new MessageAttachment(canvas.toBuffer(), 'ship.png')

        const shipEmbed = new MessageEmbed()
            .setDescription(`**${love}%** [\`${loveLevel}\`]`)
            .setImage("attachment://ship.png")
        interaction.reply({ content: desc, embeds: [shipEmbed], files: [img] });
    }


() => {
    return (

                <CornerBrackets spacing="lg" />

                    PostHog is what I always wanted a Product Analytics SaaS to be. Private cloud option so GDPR becomes
                    way more manageable, features built based on direct community feedback, focus on simplicity and
                    usefulness over vanity features...Great job people!

                @benjackwhite


@NgModule({
  imports: [
      BrowserModule,
      FormsModule,
      RouterModule.forRoot([
        {
            path: 'heroes',
            component: HeroesComponent
        },
        {
            path: 'dashboard',
            component: DashboardComponent
        },
        {
            path: '',
            redirectTo: '/dashboard',
            pathMatch: 'full'
        },
        {
        path: 'detail/:id',
        component: HeroDetailComponent
        },

       ])
  ],
    declarations: [
    AppComponent,
    DashboardComponent,
    HeroDetailComponent,
    HeroesComponent
    ],
    providers: [
        HeroService
    ],
    bootstrap: [ AppComponent ]
})
export class AppModule {

}


@Module({
  imports: [TypeOrmModule.forFeature([PublicationEntity, MembersEntity])],
  controllers: [PublicationsController],
  providers: [PublicationsService],
})
export class PublicationsModule {}


export function getShimClass(store: CoreStore, modelName: string): ShimModelClass {
  let shims = AvailableShims.lookup(store);
  let shim = shims[modelName];
  if (shim === undefined) {
    shim = shims[modelName] = new ShimModelClass(store, modelName);
  }

  return shim;
}


function mapFromHash<T>(hash: Dict<T>): Map<string, T> {
  let map = new Map();
  for (let i in hash) {
    if (Object.prototype.hasOwnProperty.call(hash, i)) {
      map.set(i, hash[i]);
    }
  }
  return map;
}


() => {
  return Object.create(null) as Dict<ShimModelClass>;
}


(key) => fields.set(key, 'attribute')


(key) => fields.set(key, relationships[key]!.kind)


(key) => {
      callback.call(binding, key, attrDefs[key] as AttributeSchema);
    }


(key) => {
      callback.call(binding, key, relationshipDefs[key] as RelationshipSchema);
    }


(key) => {
      if (relationshipDefs[key]!.type) {
        callback.call(binding, key, relationshipDefs[key] as RelationshipSchema);
      }
    }


// Mimics the static apis of DSModel
export default class ShimModelClass implements ModelSchema {
  // TODO Maybe expose the class here?
  constructor(private __store: CoreStore, public modelName: string) {}

  get fields(): Map<string, 'attribute' | 'belongsTo' | 'hasMany'> {
    let attrs = this.__store._attributesDefinitionFor({ type: this.modelName });
    let relationships = this.__store._relationshipsDefinitionFor({ type: this.modelName });
    let fields = new Map<string, 'attribute' | 'belongsTo' | 'hasMany'>();
    Object.keys(attrs).forEach((key) => fields.set(key, 'attribute'));
    Object.keys(relationships).forEach((key) => fields.set(key, relationships[key]!.kind));
    return fields;
  }

  get attributes(): Map<string, AttributeSchema> {
    let attrs = this.__store._attributesDefinitionFor({ type: this.modelName });
    return mapFromHash(attrs);
  }

  get relationshipsByName(): Map<string, RelationshipSchema> {
    let relationships = this.__store._relationshipsDefinitionFor({ type: this.modelName });
    return mapFromHash(relationships);
  }

  eachAttribute<T>(callback: (this: T | undefined, key: string, attribute: AttributeSchema) => void, binding?: T) {
    let attrDefs = this.__store._attributesDefinitionFor({ type: this.modelName });
    Object.keys(attrDefs).forEach((key) => {
      callback.call(binding, key, attrDefs[key] as AttributeSchema);
    });
  }

  eachRelationship<T>(
    callback: (this: T | undefined, key: string, relationship: RelationshipSchema) => void,
    binding?: T
  ) {
    let relationshipDefs = this.__store._relationshipsDefinitionFor({ type: this.modelName });
    Object.keys(relationshipDefs).forEach((key) => {
      callback.call(binding, key, relationshipDefs[key] as RelationshipSchema);
    });
  }

  eachTransformedAttribute<T>(
    callback: (this: T | undefined, key: string, relationship: RelationshipSchema) => void,
    binding?: T
  ) {
    let relationshipDefs = this.__store._relationshipsDefinitionFor({ type: this.modelName });
    Object.keys(relationshipDefs).forEach((key) => {
      if (relationshipDefs[key]!.type) {
        callback.call(binding, key, relationshipDefs[key] as RelationshipSchema);
      }
    });
  }
}


eachAttribute<T>(callback: (this: T | undefined, key: string, attribute: AttributeSchema) => void, binding?: T) {
    let attrDefs = this.__store._attributesDefinitionFor({ type: this.modelName });
    Object.keys(attrDefs).forEach((key) => {
      callback.call(binding, key, attrDefs[key] as AttributeSchema);
    });
  }


eachRelationship<T>(
    callback: (this: T | undefined, key: string, relationship: RelationshipSchema) => void,
    binding?: T
  ) {
    let relationshipDefs = this.__store._relationshipsDefinitionFor({ type: this.modelName });
    Object.keys(relationshipDefs).forEach((key) => {
      callback.call(binding, key, relationshipDefs[key] as RelationshipSchema);
    });
  }


eachTransformedAttribute<T>(
    callback: (this: T | undefined, key: string, relationship: RelationshipSchema) => void,
    binding?: T
  ) {
    let relationshipDefs = this.__store._relationshipsDefinitionFor({ type: this.modelName });
    Object.keys(relationshipDefs).forEach((key) => {
      if (relationshipDefs[key]!.type) {
        callback.call(binding, key, relationshipDefs[key] as RelationshipSchema);
      }
    });
  }


/* tslint:disable */
// This file was automatically generated and should not be edited.
// ====================================================
// GraphQL fragment: TaskLineFragment
// ====================================================
export interface TaskLineFragment_unitPrice_gross {
  __typename: "Money";
  amount: number;
  currency: string;
}


export interface TaskLineFragment_unitPrice_net {
  __typename: "Money";
  amount: number;
  currency: string;
}


export interface TaskLineFragment_unitPrice {
  __typename: "TaxedMoney";
  gross: TaskLineFragment_unitPrice_gross;
  net: TaskLineFragment_unitPrice_net;
}


export interface TaskLineFragment {
  __typename: "TaskLine";
  id: string;
  isDeliveryRequired: boolean;
  skillName: string;
  skillSku: string;
  quantity: number;
  quantityFulfilled: number;
  unitPrice: TaskLineFragment_unitPrice | null;
  thumbnailUrl: string | null;
}


(app: App, opt: InstallOptions): void => {
  const option = Object.assign(defaultInstallOpt, opt);
  app.config.globalProperties.$whalue = option;
  setConfig(option);

  components.forEach((component) => {
    app.component(component.name, component);
  });
}


(component) => {
    app.component(component.name, component);
  }


async function getViz() {
  return new Viz({ workerURL });
}


() => {
        i++;
        dot += `node${i} -> node${i + 1};`;

        return viz.renderString(dot + "}");
      }


(svg: string) => assertStringIncludes(svg, "</svg>")


() => viz.terminateWorker()


async fn(): Promise<any> {
    const viz = await getViz();
    const svg = await viz.renderString("digraph { a -> b; }");
    assertStringIncludes(svg, "</svg>");
    viz.terminateWorker();
  }


async fn(): Promise<any> {
    const viz = await getViz();

    let dot = "digraph {";
    let i = 0;
    dot += `node${i} -> node${i + 1};`;

    return viz
      .renderString(dot + "}")
      .then(() => {
        i++;
        dot += `node${i} -> node${i + 1};`;

        return viz.renderString(dot + "}");
      })
      .then((svg: string) => assertStringIncludes(svg, "</svg>"))
      .catch(unreachable)
      .finally(() => viz.terminateWorker());
  }


() => {
  return (
    <Switch>
      <AuthenticatedGuard
        exact
        path={PATHS.CART}
        component={CartPage}
      ></AuthenticatedGuard>
      <AuthenticatedGuard
        exact
        path={PATHS.CART_CHECKOUT}
        component={CartCheckoutPage}
      ></AuthenticatedGuard>
    </Switch>


@NgModule({
  imports: [
    CommonModule,
    AuthPageRoutingModule,
    FormsModule,
    ReactiveFormsModule
  ],
  declarations: [
    LoginFormComponent,
    RegisterFromComponent
  ],
  providers: [
    AuthService
  ]
})
export class AuthPageModule { }


async function bootstrap() {
    const app = await NestFactory.create<NestFastifyApplication>(AppModule, new FastifyAdapter());
    app.enableCors();
    await app.listen(process.env.PORT || 3000);
}


(e) => this.on(e, fn)


(payload: T[K]) => {
      this.off(event, wrapped)
      fn.call(null, payload)
    }


(e) => this.off(e, fn)


(cb) => !(cb === fn || (cb as any).fn === fn)


export class EventEmitter<T extends EventMap = EventMap> {
  protected events: EventRegistry<T> = Object.create(null)

  on<K extends keyof T>(event: K | K[], fn: EventFn<T[K]>): void {
    if (isArray(event)) {
      event.forEach((e) => this.on(e, fn))
    } else {
      // @ts-ignore
      ;(this.events[event] || (this.events[event] = [])).push(fn)
    }
  }

  once<K extends keyof T>(event: K, fn: EventFn<T[K]>): void {
    const wrapped: EventFn<T[K]> = (payload: T[K]) => {
      this.off(event, wrapped)
      fn.call(null, payload)
    }
    wrapped.fn = fn
    this.on(event, wrapped)
  }

  off<K extends keyof T>(event?: K | K[], fn?: EventFn<T[K]>) {
    if (!event) {
      this.events = Object.create(null)
      return
    }

    if (isArray(event)) {
      event.forEach((e) => this.off(e, fn))
      return
    }

    const cbs = this.events[event!]
    if (!cbs) {
      return
    }
    if (!fn) {
      this.events[event!] = undefined
      return
    }
    this.events[event!] = cbs.filter(
      (cb) => !(cb === fn || (cb as any).fn === fn),
    )
  }

  emit<K extends keyof T>(event: K, payload?: T) {
    const cbs = this.events[event]
    if (cbs) {
      callWithAsyncErrorHandling(cbs, payload ? [payload] : [])
    }
  }
}


export interface EventMap {
  [event: string]: any
}


interface EventFn<T = any> {
  (payload: T): void
  fn?: (payload: T) => void
}


type EventRegistry<T extends EventMap> = {
  [K in keyof T]: EventFn<T[K]>[] | undefined
}


on<K extends keyof T>(event: K | K[], fn: EventFn<T[K]>): void {
    if (isArray(event)) {
      event.forEach((e) => this.on(e, fn))
    } else {
      // @ts-ignore
      ;(this.events[event] || (this.events[event] = [])).push(fn)
    }
  }


once<K extends keyof T>(event: K, fn: EventFn<T[K]>): void {
    const wrapped: EventFn<T[K]> = (payload: T[K]) => {
      this.off(event, wrapped)
      fn.call(null, payload)
    }
    wrapped.fn = fn
    this.on(event, wrapped)
  }


off<K extends keyof T>(event?: K | K[], fn?: EventFn<T[K]>) {
    if (!event) {
      this.events = Object.create(null)
      return
    }

    if (isArray(event)) {
      event.forEach((e) => this.off(e, fn))
      return
    }

    const cbs = this.events[event!]
    if (!cbs) {
      return
    }
    if (!fn) {
      this.events[event!] = undefined
      return
    }
    this.events[event!] = cbs.filter(
      (cb) => !(cb === fn || (cb as any).fn === fn),
    )
  }


emit<K extends keyof T>(event: K, payload?: T) {
    const cbs = this.events[event]
    if (cbs) {
      callWithAsyncErrorHandling(cbs, payload ? [payload] : [])
    }
  }


(tenant) => (this.tenant = tenant)


(data) => {
                this.challenge = data;
                if (this.challenge.responseErrors) {
                    return false;
                }
                return true;
            }


(e: Error | Response) => {
                this.errorMessage(e);
                return false;
            }


() => {
                this.loading = false;
                return false;
            }


(tenant) => {
            this.flowSlug = tenant.flowUserSettings;
            if (!this.flowSlug) {
                return;
            }
            new FlowsApi(DEFAULT_CONFIG)
                .flowsInstancesExecuteRetrieve({
                    slug: this.flowSlug || "",
                })
                .then(() => {
                    this.nextChallenge();
                });
        }


() => {
                    this.nextChallenge();
                }


() => {
            this.dispatchEvent(
                new CustomEvent(EVENT_REFRESH, {
                    bubbles: true,
                    composed: true,
                }),
            );
            try {
                document.querySelectorAll("ak-interface-user").forEach((int) => {
                    (int as LitElement).requestUpdate();
                });
            } catch {
                console.debug("authentik/user/flows: failed to find interface to refresh");
            }
        }


(int) => {
                    (int as LitElement).requestUpdate();
                }


@customElement("ak-user-settings-flow-executor")
export class UserSettingsFlowExecutor extends LitElement implements StageHost {
    @property()
    flowSlug?: string;

    private _challenge?: ChallengeTypes;

    @property({ attribute: false })
    set challenge(value: ChallengeTypes | undefined) {
        this._challenge = value;
        this.requestUpdate();
    }

    get challenge(): ChallengeTypes | undefined {
        return this._challenge;
    }

    @property({ type: Boolean })
    loading = false;

    @property({ attribute: false })
    tenant!: CurrentTenant;

    static get styles(): CSSResult[] {
        return [PFBase, PFCard, PFPage, PFButton, PFContent, AKGlobal];
    }

    constructor() {
        super();
        tenant().then((tenant) => (this.tenant = tenant));
    }

    submit(payload?: FlowChallengeResponseRequest): Promise<boolean> {
        if (!payload) return Promise.reject();
        if (!this.challenge) return Promise.reject();
        // @ts-ignore
        payload.component = this.challenge.component;
        this.loading = true;
        return new FlowsApi(DEFAULT_CONFIG)
            .flowsExecutorSolve({
                flowSlug: this.flowSlug || "",
                query: window.location.search.substring(1),
                flowChallengeResponseRequest: payload,
            })
            .then((data) => {
                this.challenge = data;
                if (this.challenge.responseErrors) {
                    return false;
                }
                return true;
            })
            .catch((e: Error | Response) => {
                this.errorMessage(e);
                return false;
            })
            .finally(() => {
                this.loading = false;
                return false;
            });
    }

    firstUpdated(): void {
        tenant().then((tenant) => {
            this.flowSlug = tenant.flowUserSettings;
            if (!this.flowSlug) {
                return;
            }
            new FlowsApi(DEFAULT_CONFIG)
                .flowsInstancesExecuteRetrieve({
                    slug: this.flowSlug || "",
                })
                .then(() => {
                    this.nextChallenge();
                });
        });
    }

    async nextChallenge(): Promise<void> {
        this.loading = true;
        try {
            const challenge = await new FlowsApi(DEFAULT_CONFIG).flowsExecutorGet({
                flowSlug: this.flowSlug || "",
                query: window.location.search.substring(1),
            });
            this.challenge = challenge;
        } catch (e: unknown) {
            // Catch JSON or Update errors
            this.errorMessage(e as Error | Response);
        } finally {
            this.loading = false;
        }
    }

    async errorMessage(error: Error | Response): Promise<void> {
        let body = "";
        if (error instanceof Error) {
            body = error.message;
        }
        this.challenge = {
            type: ChallengeChoices.Shell,
            body: `

                    ${t`Whoops!`}

${t`Something went wrong! Please try again later.`}

${body}

                            ${t`Return`}

            `,
        } as ChallengeTypes;
    }

    globalRefresh(): void {
        refreshMe().then(() => {
            this.dispatchEvent(
                new CustomEvent(EVENT_REFRESH, {
                    bubbles: true,
                    composed: true,
                }),
            );
            try {
                document.querySelectorAll("ak-interface-user").forEach((int) => {
                    (int as LitElement).requestUpdate();
                });
            } catch {
                console.debug("authentik/user/flows: failed to find interface to refresh");
            }
        });
    }

    renderChallenge(): TemplateResult {
        if (!this.challenge) {
            return html``;
        }
        switch (this.challenge.type) {
            case ChallengeChoices.Redirect:
                if ((this.challenge as RedirectChallenge).to !== "/") {
                    return html`${"Edit settings"}`;
                }
                // Flow has finished, so let's load while in the background we can restart the flow
                this.loading = true;
                console.debug("authentik/user/flows: redirect to '/', restarting flow.");
                this.firstUpdated();
                this.globalRefresh();
                showMessage({
                    level: MessageLevel.success,
                    message: t`Successfully updated details`,
                });
                return html`<ak-empty-state ?loading=${true} header=${t`Loading`}>
                </ak-empty-state>`;
            case ChallengeChoices.Shell:
                return html`${unsafeHTML((this.challenge as ShellChallenge).body)}`;
            case ChallengeChoices.Native:
                switch (this.challenge.component) {
                    case "ak-stage-prompt":
                        return html`<ak-user-stage-prompt
                            .host=${this as StageHost}
                            .challenge=${this.challenge}
                        ></ak-user-stage-prompt>`;
                    default:
                        console.log(
                            `authentik/user/flows: unsupported stage type ${this.challenge.component}`,
                        );
                        return html`

                                ${t`Open settings`}

                        `;
                }
            default:
                console.debug(`authentik/user/flows: unexpected data type ${this.challenge.type}`);
                break;
        }
        return html``;
    }

    renderChallengeWrapper(): TemplateResult {
        if (!this.flowSlug) {
            return html`<p>${t`No settings flow configured.`}</p> `;
        }
        if (!this.challenge || this.loading) {
            return html`<ak-empty-state ?loading=${true} header=${t`Loading`}> </ak-empty-state>`;
        }
        return html` ${this.renderChallenge()} `;
    }

    render(): TemplateResult {
        return html`

${t`Update details`}

${this.renderChallengeWrapper()}

`;
    }
}


submit(payload?: FlowChallengeResponseRequest): Promise<boolean> {
        if (!payload) return Promise.reject();
        if (!this.challenge) return Promise.reject();
        // @ts-ignore
        payload.component = this.challenge.component;
        this.loading = true;
        return new FlowsApi(DEFAULT_CONFIG)
            .flowsExecutorSolve({
                flowSlug: this.flowSlug || "",
                query: window.location.search.substring(1),
                flowChallengeResponseRequest: payload,
            })
            .then((data) => {
                this.challenge = data;
                if (this.challenge.responseErrors) {
                    return false;
                }
                return true;
            })
            .catch((e: Error | Response) => {
                this.errorMessage(e);
                return false;
            })
            .finally(() => {
                this.loading = false;
                return false;
            });
    }


firstUpdated(): void {
        tenant().then((tenant) => {
            this.flowSlug = tenant.flowUserSettings;
            if (!this.flowSlug) {
                return;
            }
            new FlowsApi(DEFAULT_CONFIG)
                .flowsInstancesExecuteRetrieve({
                    slug: this.flowSlug || "",
                })
                .then(() => {
                    this.nextChallenge();
                });
        });
    }


async nextChallenge(): Promise<void> {
        this.loading = true;
        try {
            const challenge = await new FlowsApi(DEFAULT_CONFIG).flowsExecutorGet({
                flowSlug: this.flowSlug || "",
                query: window.location.search.substring(1),
            });
            this.challenge = challenge;
        } catch (e: unknown) {
            // Catch JSON or Update errors
            this.errorMessage(e as Error | Response);
        } finally {
            this.loading = false;
        }
    }


async errorMessage(error: Error | Response): Promise<void> {
        let body = "";
        if (error instanceof Error) {
            body = error.message;
        }
        this.challenge = {
            type: ChallengeChoices.Shell,
            body: `

                    ${t`Whoops!`}

${t`Something went wrong! Please try again later.`}

${body}

                            ${t`Return`}

            `,
        } as ChallengeTypes;
    }


globalRefresh(): void {
        refreshMe().then(() => {
            this.dispatchEvent(
                new CustomEvent(EVENT_REFRESH, {
                    bubbles: true,
                    composed: true,
                }),
            );
            try {
                document.querySelectorAll("ak-interface-user").forEach((int) => {
                    (int as LitElement).requestUpdate();
                });
            } catch {
                console.debug("authentik/user/flows: failed to find interface to refresh");
            }
        });
    }


renderChallenge(): TemplateResult {
        if (!this.challenge) {
            return html``;
        }
        switch (this.challenge.type) {
            case ChallengeChoices.Redirect:
                if ((this.challenge as RedirectChallenge).to !== "/") {
                    return html`<a
                        href="${(this.challenge as RedirectChallenge).to}"
                        class="pf-c-button pf-m-primary"
                        >${"Edit settings"}</a
                    >`;
                }
                // Flow has finished, so let's load while in the background we can restart the flow
                this.loading = true;
                console.debug("authentik/user/flows: redirect to '/', restarting flow.");
                this.firstUpdated();
                this.globalRefresh();
                showMessage({
                    level: MessageLevel.success,
                    message: t`Successfully updated details`,
                });
                return html`<ak-empty-state ?loading=${true} header=${t`Loading`}>
                </ak-empty-state>`;
            case ChallengeChoices.Shell:
                return html`${unsafeHTML((this.challenge as ShellChallenge).body)}`;
            case ChallengeChoices.Native:
                switch (this.challenge.component) {
                    case "ak-stage-prompt":
                        return html`<ak-user-stage-prompt
                            .host=${this as StageHost}
                            .challenge=${this.challenge}
                        ></ak-user-stage-prompt>`;
                    default:
                        console.log(
                            `authentik/user/flows: unsupported stage type ${this.challenge.component}`,
                        );
                        return html`
                            <a href="/if/flow/${this.flowSlug}" class="pf-c-button pf-m-primary">
                                ${t`Open settings`}
                            </a>
                        `;
                }
            default:
                console.debug(`authentik/user/flows: unexpected data type ${this.challenge.type}`);
                break;
        }
        return html``;
    }


renderChallengeWrapper(): TemplateResult {
        if (!this.flowSlug) {
            return html`<p>${t`No settings flow configured.`}</p> `;
        }
        if (!this.challenge || this.loading) {
            return html`<ak-empty-state ?loading=${true} header=${t`Loading`}> </ak-empty-state>`;
        }
        return html` ${this.renderChallenge()} `;
    }


render(): TemplateResult {
        return html`

${t`Update details`}

${this.renderChallengeWrapper()}

`;
    }


export interface TableRequest {
  results: number | undefined;
  page?: number;
  sortField?: string;
  sortOrder?: string;
  filters?: Record<string, string[]>;
}


function Calculator() {
	const initialCalcState: CalculatorState = {
		numOfVisitorsControl: 0,
		numOfConversionsControl: 0,
		conversionRateControl: 0,
		standardErrorControl: 0,
		numOfVisitorsVariant: 0,
		numOfConversionsVariant: 0,
		conversionRateVariant: 0,
		standardErrorVariant: 0,
		confidence90: 'No',
		confidence95: 'No',
		confidence99: 'No',
		zScore: 0,
		pValue: 0,
	};

	const [
		{
			numOfVisitorsControl,
			numOfConversionsControl,
			conversionRateControl,
			standardErrorControl,
			numOfVisitorsVariant,
			numOfConversionsVariant,
			conversionRateVariant,
			standardErrorVariant,
			confidence90,
			confidence95,
			confidence99,
			zScore,
			pValue,
		},
		setCalcState,
	] = React.useState<CalculatorState>(initialCalcState);

	const clearState = () => {
		setCalcState({ ...initialCalcState });
	};

	const calculateSignificance = () => {
		if (numOfConversionsControl & numOfVisitorsControl) {
			setCalcState((prevState) => ({
				...prevState,
				conversionRateControl: calcConversionRate(
					numOfConversionsControl,
					numOfVisitorsControl
				),
				standardErrorControl: calcStandardError(
					conversionRateControl,
					numOfVisitorsControl
				),
			}));
		}

		if (numOfConversionsVariant & numOfVisitorsVariant) {
			setCalcState((prevState) => ({
				...prevState,
				conversionRateVariant: calcConversionRate(
					numOfConversionsVariant,
					numOfVisitorsVariant
				),
				standardErrorVariant: calcStandardError(
					conversionRateVariant,
					numOfVisitorsVariant
				),
			}));
		}

		if (
			numOfConversionsControl &
			numOfVisitorsControl &
			numOfConversionsVariant &
			numOfVisitorsVariant
		) {
			setCalcState((prevState) => ({
				...prevState,
				zScore: calcZScore(
					conversionRateControl,
					conversionRateVariant,
					standardErrorControl,
					standardErrorVariant
				),
			}));

			setCalcState((prevState) => ({
				...prevState,
				pValue: calcPValue(zScore),
			}));

			setCalcState((prevState) => ({
				...prevState,
				confidence90: calcConfidence(ConfidenceLevels.Ninety, pValue),
				confidence95: calcConfidence(
					ConfidenceLevels.NinetyFive,
					pValue
				),
				confidence99: calcConfidence(
					ConfidenceLevels.NinetyNine,
					pValue
				),
			}));
		}
	};

	return (

Statistical Significance Calculator

					<form noValidate autoComplete="off" onReset={clearState}>

									Visitors
									Conversions
									Conversion Rate
									Standard Error

									Control

										<input
											id="visitorsControl"
											type="number"
											min={numOfConversionsControl}
											value={numOfVisitorsControl}
											onChange={(e) => {
												setCalcState((prevState) => ({
													...prevState,
													numOfVisitorsControl: parseInt(
														e.target.value
													),
												}));
												calculateSignificance();
											}}


() => {
		setCalcState({ ...initialCalcState });
	}


() => {
		if (numOfConversionsControl & numOfVisitorsControl) {
			setCalcState((prevState) => ({
				...prevState,
				conversionRateControl: calcConversionRate(
					numOfConversionsControl,
					numOfVisitorsControl
				),
				standardErrorControl: calcStandardError(
					conversionRateControl,
					numOfVisitorsControl
				),
			}));
		}

		if (numOfConversionsVariant & numOfVisitorsVariant) {
			setCalcState((prevState) => ({
				...prevState,
				conversionRateVariant: calcConversionRate(
					numOfConversionsVariant,
					numOfVisitorsVariant
				),
				standardErrorVariant: calcStandardError(
					conversionRateVariant,
					numOfVisitorsVariant
				),
			}));
		}

		if (
			numOfConversionsControl &
			numOfVisitorsControl &
			numOfConversionsVariant &
			numOfVisitorsVariant
		) {
			setCalcState((prevState) => ({
				...prevState,
				zScore: calcZScore(
					conversionRateControl,
					conversionRateVariant,
					standardErrorControl,
					standardErrorVariant
				),
			}));

			setCalcState((prevState) => ({
				...prevState,
				pValue: calcPValue(zScore),
			}));

			setCalcState((prevState) => ({
				...prevState,
				confidence90: calcConfidence(ConfidenceLevels.Ninety, pValue),
				confidence95: calcConfidence(
					ConfidenceLevels.NinetyFive,
					pValue
				),
				confidence99: calcConfidence(
					ConfidenceLevels.NinetyNine,
					pValue
				),
			}));
		}
	}


(prevState) => ({
				...prevState,
				conversionRateControl: calcConversionRate(
					numOfConversionsControl,
					numOfVisitorsControl
				),
				standardErrorControl: calcStandardError(
					conversionRateControl,
					numOfVisitorsControl
				),
			})


(prevState) => ({
				...prevState,
				conversionRateVariant: calcConversionRate(
					numOfConversionsVariant,
					numOfVisitorsVariant
				),
				standardErrorVariant: calcStandardError(
					conversionRateVariant,
					numOfVisitorsVariant
				),
			})


(prevState) => ({
				...prevState,
				zScore: calcZScore(
					conversionRateControl,
					conversionRateVariant,
					standardErrorControl,
					standardErrorVariant
				),
			})


(prevState) => ({
				...prevState,
				pValue: calcPValue(zScore),
			})


(prevState) => ({
				...prevState,
				confidence90: calcConfidence(ConfidenceLevels.Ninety, pValue),
				confidence95: calcConfidence(
					ConfidenceLevels.NinetyFive,
					pValue
				),
				confidence99: calcConfidence(
					ConfidenceLevels.NinetyNine,
					pValue
				),
			})


(prevState) => ({
													...prevState,
													numOfVisitorsControl: parseInt(
														e.target.value
													),
												})


(prevState) => ({
													...prevState,
													numOfConversionsControl: parseInt(
														e.target.value
													),
												})


(prevState) => ({
													...prevState,
													numOfVisitorsVariant: parseInt(
														e.target.value
													),
												})


(prevState) => ({
													...prevState,
													numOfConversionsVariant: parseInt(
														e.target.value
													),
												})


interface CalculatorState {
	numOfVisitorsControl: number;
	numOfConversionsControl: number;
	conversionRateControl: number;
	standardErrorControl: number;
	numOfVisitorsVariant: number;
	numOfConversionsVariant: number;
	conversionRateVariant: number;
	standardErrorVariant: number;
	confidence90: string;
	confidence95: string;
	confidence99: string;
	zScore: number;
	pValue: number;
}


roundUp(conversionRateControl)


roundUp(standardErrorControl)


roundUp(conversionRateVariant)


roundUp(standardErrorVariant)


roundUp(zScore)


roundUp(pValue)


@Component({
    selector: 'app-child',
    template: `
        <div>
            <button class="btn btn-success" (click)="increase();">Increase</button>
            <button class="btn btn-warning" (click)="decrease();">Decrease</button>
            <button class="btn btn-danger" (click)="reset();">Reset</button>
        </div>
    `
})
export class ChildComponent{
    constructor(private store: Store<any>){

    }

    increase(){
        this.store.dispatch({type: 'INCREASE'});
    }

    decrease(){
        this.store.dispatch({type: 'DECREASE'});
    }

    reset(){
        this.store.dispatch({type: 'RESET'});
    }
}


increase(){
        this.store.dispatch({type: 'INCREASE'});
    }


decrease(){
        this.store.dispatch({type: 'DECREASE'});
    }


reset(){
        this.store.dispatch({type: 'RESET'});
    }


export default class MdControlPoint extends React.Component<IconBaseProps, any> { }


@NgModule({
  imports: [
    BrowserModule,
    ContactModule,
    routing,
    SharedModule.forRoot()
  ],
  declarations: [ AppComponent ],

  bootstrap:    [ AppComponent ]
})
export class AppModule { }


(option: any, textKey: string, valueKey: string) => {
  if (!option) throw new Error('option can not be undifend or null');
  const optionProps: any = {};
  if (typeof option === 'object') {
    optionProps.disabled = option.disabled || false;
    option = {
      [textKey]: option[textKey],
      [valueKey]: option[valueKey]
    };
  } else {
    option = { [textKey]: option, [valueKey]: option };
  }
  return { option, optionProps };
}


export interface IOption {
  text: string;
  value: string;
}


export default function Grille({ nodeValue, explanation, unit }) {
	return (
		<StyledComponent>
			<Mecanism name="grille" value={nodeValue} unit={unit}>
				<ul className="properties">
					<BarèmeAttributes explanation={explanation} />
					<TrancheTable
						tranches={explanation.tranches}
						multiplicateur={explanation.multiplicateur}
					/>
				</ul>
			</Mecanism>
		</StyledComponent>
	)
}


@Controller('estadomovimiento')
export class EstadomovimientoController {}


export class TelemetryService {
    /**
     *  This method calculate the time elapsed between two number representation of dates expressed as
     *  number of milliseconds elapsed since January 1, 1970 00:00:00 UTC.
     * @param startTime numeric representation of a starting time
     * @param endTime numeric representation of a ending time
     */
    public static calculateTimeElapsed(startTime: number, endTime: number): number | undefined {
        return ((startTime && endTime) && (endTime >= startTime)) ? ((endTime - startTime) / 1000) : undefined;
    }

    /**
     * This method collect the data event for telemetry purpose, apply basic validation
     * and delegate the reporter service to sent them to the target telemetry server
     * @param eventName name assigned for the event for the telemetry
     * @param categories optional list of keywords (act as tags)
     * @param notes optional brief description
     * @param telemetryMeasurement optional set of numeric data with a key name
     */
    public static registerEvent(eventName: string, categories?: string[], notes?: string, telemetryMeasurement?: Map<string, number>): void {
        if (this.isValidEventName(eventName)) {
            TelemetryFactory.getReporter().reportEvent(this.createTelemetryEvent(eventName, categories, notes, undefined, telemetryMeasurement));
        }
    }

    /**
     * This method collect the exception data event for telemetry purpose, apply basic validation
     * and delegate the reporter service to sent them to the target telemetry server
     * @param eventName name assigned for the event for the telemetry
     * @param rootCause the stacktrace attached for debugging purpose.
     * @param categories optional list of keywords (act as tags)
     * @param notes optional brief description
     * @param telemetryMeasurement optional set of numeric data with a key name
     */
    public static registerExceptionEvent(eventName = "RuntimeException", rootCause: string, categories?: string[], notes?: string, telemetryMeasurement?: Map<string, number>): void {
        if (this.isValidEventName(eventName) && this.isValidRootCause(rootCause)) {
            TelemetryFactory.getReporter().reportExceptionEvent(this.createTelemetryEvent(eventName, categories, notes, this.anonymizeContent(rootCause), telemetryMeasurement));
        }

    }

    private static isValidEventName(eventName: string): boolean {
        return eventName !== undefined && eventName.trim() !== "";
    }

    private static createTelemetryEvent(eventName: string, categories: string[], notes: string, rootCause?: string, telemetryMeasurement?: Map<string, number>): TelemetryEvent {
        const telemetryEvent = new TelemetryEvent();
        telemetryEvent.eventName = eventName;
        telemetryEvent.categories = this.resolveCategories(categories);
        telemetryEvent.notes = notes;
        telemetryEvent.rootCause = rootCause;
        telemetryEvent.measurements = telemetryMeasurement;

        return telemetryEvent;
    }

    private static resolveCategories(categories: string[]): string[] {
        return (categories) ? categories : ["N.D"];
    }

    private static isValidRootCause(rootCause: string): boolean {
        return !(Utils.isNullOrUndefined(rootCause)) && rootCause.trim() !== "";
    }

    /**
     * This method allows to anonymize the username value present in stack trace
     * @param content stack trace
     */
    private static anonymizeContent(content: string): string {
        return content.replace(new RegExp("\\" + sep + this.getUsername(), "g"), sep + "anonymous");
    }

    private static getUsername(): string {
        return userInfo().username;
    }

}


/**
     *  This method calculate the time elapsed between two number representation of dates expressed as
     *  number of milliseconds elapsed since January 1, 1970 00:00:00 UTC.
     * @param startTime numeric representation of a starting time
     * @param endTime numeric representation of a ending time
     */
public static calculateTimeElapsed(startTime: number, endTime: number): number | undefined {
        return ((startTime && endTime) && (endTime >= startTime)) ? ((endTime - startTime) / 1000) : undefined;
    }


/**
     * This method collect the data event for telemetry purpose, apply basic validation
     * and delegate the reporter service to sent them to the target telemetry server
     * @param eventName name assigned for the event for the telemetry
     * @param categories optional list of keywords (act as tags)
     * @param notes optional brief description
     * @param telemetryMeasurement optional set of numeric data with a key name
     */
public static registerEvent(eventName: string, categories?: string[], notes?: string, telemetryMeasurement?: Map<string, number>): void {
        if (this.isValidEventName(eventName)) {
            TelemetryFactory.getReporter().reportEvent(this.createTelemetryEvent(eventName, categories, notes, undefined, telemetryMeasurement));
        }
    }


/**
     * This method collect the exception data event for telemetry purpose, apply basic validation
     * and delegate the reporter service to sent them to the target telemetry server
     * @param eventName name assigned for the event for the telemetry
     * @param rootCause the stacktrace attached for debugging purpose.
     * @param categories optional list of keywords (act as tags)
     * @param notes optional brief description
     * @param telemetryMeasurement optional set of numeric data with a key name
     */
public static registerExceptionEvent(eventName = "RuntimeException", rootCause: string, categories?: string[], notes?: string, telemetryMeasurement?: Map<string, number>): void {
        if (this.isValidEventName(eventName) && this.isValidRootCause(rootCause)) {
            TelemetryFactory.getReporter().reportExceptionEvent(this.createTelemetryEvent(eventName, categories, notes, this.anonymizeContent(rootCause), telemetryMeasurement));
        }

    }


private static isValidEventName(eventName: string): boolean {
        return eventName !== undefined && eventName.trim() !== "";
    }


private static createTelemetryEvent(eventName: string, categories: string[], notes: string, rootCause?: string, telemetryMeasurement?: Map<string, number>): TelemetryEvent {
        const telemetryEvent = new TelemetryEvent();
        telemetryEvent.eventName = eventName;
        telemetryEvent.categories = this.resolveCategories(categories);
        telemetryEvent.notes = notes;
        telemetryEvent.rootCause = rootCause;
        telemetryEvent.measurements = telemetryMeasurement;

        return telemetryEvent;
    }


private static resolveCategories(categories: string[]): string[] {
        return (categories) ? categories : ["N.D"];
    }


private static isValidRootCause(rootCause: string): boolean {
        return !(Utils.isNullOrUndefined(rootCause)) && rootCause.trim() !== "";
    }


/**
     * This method allows to anonymize the username value present in stack trace
     * @param content stack trace
     */
private static anonymizeContent(content: string): string {
        return content.replace(new RegExp("\\" + sep + this.getUsername(), "g"), sep + "anonymous");
    }


private static getUsername(): string {
        return userInfo().username;
    }


async function addScriptUrl(
      url: string,
      type: string
    ): Promise<HTMLElement> {
      const script = document.createElement('script');
      script.src = url;
      if (type) script.type = type;
      const promise = new Promise((res, rej) => {
        script.onload = res;
        script.onerror = rej;
      });
      document.head.appendChild(script);
      await promise;
      return script;
    }


function addScriptContent(
      content: string,
      type = 'text/javascript'
    ): HTMLElement {
      const script = document.createElement('script');
      script.type = type;
      script.text = content;
      let error = null;
      script.onerror = (e) => (error = e);
      document.head.appendChild(script);
      if (error) throw error;
      return script;
    }


async function addStyleUrl(url: string): Promise<HTMLElement> {
      const link = document.createElement('link');
      link.rel = 'stylesheet';
      link.href = url;
      const promise = new Promise((res, rej) => {
        link.onload = res;
        link.onerror = rej;
      });
      document.head.appendChild(link);
      await promise;
      return link;
    }


async function addStyleContent(content: string): Promise<HTMLElement> {
      const style = document.createElement('style');
      style.type = 'text/css';
      style.appendChild(document.createTextNode(content));
      const promise = new Promise((res, rej) => {
        style.onload = res;
        style.onerror = rej;
      });
      document.head.appendChild(style);
      await promise;
      return style;
    }


function deliverResult(name: string, seq: number, result: unknown): void {
      globalThis[name].callbacks.get(seq).resolve(result);
      globalThis[name].callbacks.delete(seq);
    }


async function predicate(
      selector: string,
      waitForVisible: boolean,
      waitForHidden: boolean
    ): Promise<Node | null | boolean> {
      const node = predicateQueryHandler
        ? ((await predicateQueryHandler(document, selector)) as Element)
        : document.querySelector(selector);
      return checkWaitForOptions(node, waitForVisible, waitForHidden);
    }


function predicate(
      xpath: string,
      waitForVisible: boolean,
      waitForHidden: boolean
    ): Node | null | boolean {
      const node = document.evaluate(
        xpath,
        document,
        null,
        XPathResult.FIRST_ORDERED_NODE_TYPE,
        null
      ).singleNodeValue;
      return checkWaitForOptions(node, waitForVisible, waitForHidden);
    }


function getPredicateBody(predicateBody: Function | string) {
      if (helper.isString(predicateBody)) return `return (${predicateBody});`;
      return `return (${predicateBody})(...args);`;
    }


async function waitForPredicatePageFunction(
  predicateBody: string,
  polling: string,
  timeout: number,
  ...args: unknown[]
): Promise<unknown> {
  const predicate = new Function('...args', predicateBody);
  let timedOut = false;
  if (timeout) setTimeout(() => (timedOut = true), timeout);
  if (polling === 'raf') return await pollRaf();
  if (polling === 'mutation') return await pollMutation();
  if (typeof polling === 'number') return await pollInterval(polling);

  /**
   * @returns {!Promise<*>}
   */
  async function pollMutation(): Promise<unknown> {
    const success = await predicate(...args);
    if (success) return Promise.resolve(success);

    let fulfill;
    const result = new Promise((x) => (fulfill = x));
    const observer = new MutationObserver(async () => {
      if (timedOut) {
        observer.disconnect();
        fulfill();
      }
      const success = await predicate(...args);
      if (success) {
        observer.disconnect();
        fulfill(success);
      }
    });
    observer.observe(document, {
      childList: true,
      subtree: true,
      attributes: true,
    });
    return result;
  }

  async function pollRaf(): Promise<unknown> {
    let fulfill;
    const result = new Promise((x) => (fulfill = x));
    await onRaf();
    return result;

    async function onRaf(): Promise<unknown> {
      if (timedOut) {
        fulfill();
        return;
      }
      const success = await predicate(...args);
      if (success) fulfill(success);
      else requestAnimationFrame(onRaf);
    }
  }

  async function pollInterval(pollInterval: number): Promise<unknown> {
    let fulfill;
    const result = new Promise((x) => (fulfill = x));
    await onTimeout();
    return result;

    async function onTimeout(): Promise<unknown> {
      if (timedOut) {
        fulfill();
        return;
      }
      const success = await predicate(...args);
      if (success) fulfill(success);
      else setTimeout(onTimeout, pollInterval);
    }
  }
}


/**
   * @returns {!Promise<*>}
   */
async function pollMutation(): Promise<unknown> {
    const success = await predicate(...args);
    if (success) return Promise.resolve(success);

    let fulfill;
    const result = new Promise((x) => (fulfill = x));
    const observer = new MutationObserver(async () => {
      if (timedOut) {
        observer.disconnect();
        fulfill();
      }
      const success = await predicate(...args);
      if (success) {
        observer.disconnect();
        fulfill(success);
      }
    });
    observer.observe(document, {
      childList: true,
      subtree: true,
      attributes: true,
    });
    return result;
  }


async function pollRaf(): Promise<unknown> {
    let fulfill;
    const result = new Promise((x) => (fulfill = x));
    await onRaf();
    return result;

    async function onRaf(): Promise<unknown> {
      if (timedOut) {
        fulfill();
        return;
      }
      const success = await predicate(...args);
      if (success) fulfill(success);
      else requestAnimationFrame(onRaf);
    }
  }


async function onRaf(): Promise<unknown> {
      if (timedOut) {
        fulfill();
        return;
      }
      const success = await predicate(...args);
      if (success) fulfill(success);
      else requestAnimationFrame(onRaf);
    }


async function pollInterval(pollInterval: number): Promise<unknown> {
    let fulfill;
    const result = new Promise((x) => (fulfill = x));
    await onTimeout();
    return result;

    async function onTimeout(): Promise<unknown> {
      if (timedOut) {
        fulfill();
        return;
      }
      const success = await predicate(...args);
      if (success) fulfill(success);
      else setTimeout(onTimeout, pollInterval);
    }
  }


async function onTimeout(): Promise<unknown> {
      if (timedOut) {
        fulfill();
        return;
      }
      const success = await predicate(...args);
      if (success) fulfill(success);
      else setTimeout(onTimeout, pollInterval);
    }


(name: string, contextId: number) =>
    `${name}_${contextId}`


(event) =>
      this._onBindingCalled(event)


(fulfill) => {
        this._contextResolveCallback = fulfill;
      }


async (context) => {
      const document = await context.evaluateHandle('document');
      return document.asElement();
    }


() => {
      let retVal = '';
      if (document.doctype)
        retVal = new XMLSerializer().serializeToString(document.doctype);
      if (document.documentElement)
        retVal += document.documentElement.outerHTML;
      return retVal;
    }


(html) => {
      document.open();
      document.write(html);
      document.close();
    }


(res, rej) => {
        script.onload = res;
        script.onerror = rej;
      }


(e) => (error = e)


(res, rej) => {
        link.onload = res;
        link.onerror = rej;
      }


(res, rej) => {
        style.onload = res;
        style.onerror = rej;
      }