export class OptionalTypeC<T extends TypeC<any>> extends TypeC<
  TypeOf<T> | undefined,
  DtoTypeOf<T> | undefined
> {
  public readonly _tag: 'Optional' = 'Optional'
  public readonly base: T

  public constructor(base: T, name: string = getOptionalName(base)) {
    super(name)
    this.base = base
  }

  public validate(value: TypeOf<T> | undefined, path: Path = []): Result<boolean> {
    if (typeof value === 'undefined') {
      return success(true)
    } else {
      return this.base.validate(value)
    }
  }

  fromDTOCyclic(value: any, path: Path, context: ToDtoContext): TypeOf<T> | undefined {
    if (typeof value === 'undefined') {
      return undefined
    } else {
      return this.base.fromDTOCyclic(value, path, context)
    }
  }

  toDTOCyclic(
    input: TypeOf<T> | undefined,
    path: Path,
    context: ToDtoContext
  ): DtoTypeOf<T> | undefined {
    if (typeof input === 'undefined') {
      return undefined
    } else {
      return this.base.toDTOCyclic(input, path, context)
    }
  }

  traverseCyclic<R>(
    instance: TypeOf<T> | undefined,
    f: TraversalFunc<R>,
    currentResult: R,
    role: RoleType,
    extra: ExtraInfo,
    context: TraversalContext<R>
  ): R {
    return this.base.traverseCyclic(
      instance,
      f,
      currentResult,
      role,
      { ...extra, ...{ optional: true } },
      context
    )
  }

  validateLinks(traversed: Map<Any, Any>): Result<boolean> {
    traversed.set(this, this)
    if (traversed.has(this.base)) return success(true)
    else return this.base.validateLinks(traversed)
  }

  defaultValue(): any {
    return undefined
  }
}


public validate(value: TypeOf<T> | undefined, path: Path = []): Result<boolean> {
    if (typeof value === 'undefined') {
      return success(true)
    } else {
      return this.base.validate(value)
    }
  }


fromDTOCyclic(value: any, path: Path, context: ToDtoContext): TypeOf<T> | undefined {
    if (typeof value === 'undefined') {
      return undefined
    } else {
      return this.base.fromDTOCyclic(value, path, context)
    }
  }


toDTOCyclic(
    input: TypeOf<T> | undefined,
    path: Path,
    context: ToDtoContext
  ): DtoTypeOf<T> | undefined {
    if (typeof input === 'undefined') {
      return undefined
    } else {
      return this.base.toDTOCyclic(input, path, context)
    }
  }


traverseCyclic<R>(
    instance: TypeOf<T> | undefined,
    f: TraversalFunc<R>,
    currentResult: R,
    role: RoleType,
    extra: ExtraInfo,
    context: TraversalContext<R>
  ): R {
    return this.base.traverseCyclic(
      instance,
      f,
      currentResult,
      role,
      { ...extra, ...{ optional: true } },
      context
    )
  }


validateLinks(traversed: Map<Any, Any>): Result<boolean> {
    traversed.set(this, this)
    if (traversed.has(this.base)) return success(true)
    else return this.base.validateLinks(traversed)
  }


defaultValue(): any {
    return undefined
  }


export function generateUniformsSync(group: UniformGroup, uniformData: Dict<any>): UniformsSyncCallback
{
    const funcFragments = [`
        var v = null;
        var cv = null
        var t = 0;
        var gl = renderer.gl
    `];

    for (const i in group.uniforms)
    {
        const data = uniformData[i];

        if (!data)
        {
            if (group.uniforms[i].group)
            {
                funcFragments.push(`
                    renderer.shader.syncUniformGroup(uv["${i}"], syncData);
                `);
            }

            continue;
        }

        const uniform = group.uniforms[i];

        let parsed = false;

        for (let j = 0; j < uniformParsers.length; j++)
        {
            if (uniformParsers[j].test(data, uniform))
            {
                funcFragments.push(uniformParsers[j].code(i, uniform));
                parsed = true;

                break;
            }
        }

        if (!parsed)
        {
            const templateType = (data.size === 1) ? GLSL_TO_SINGLE_SETTERS_CACHED : GLSL_TO_ARRAY_SETTERS;

            const template =  templateType[data.type].replace('location', `ud["${i}"].location`);

            funcFragments.push(`
            cv = ud["${i}"].value;
            v = uv["${i}"];
            ${template};`);
        }
    }

    /*
     * the introduction of syncData is to solve an issue where textures in uniform groups are not set correctly
     * the texture count was always starting from 0 in each group. This needs to increment each time a texture is used
     * no matter which group is being used
     *
     */
    // eslint-disable-next-line no-new-func
    return new Function('ud', 'uv', 'renderer', 'syncData', funcFragments.join('\n')) as UniformsSyncCallback;
}


export type UniformsSyncCallback = (...args: any[]) => void;


() => {
  return (
    <Wrapper as="main">

        <Title>Editable Input</Title>
        <Paragraph>Renders text that can be edited in place by clicking on it.</Paragraph>

        <SubTitle>Usage</SubTitle>
        <Usage>{"import { EditableInput } from '@binarycapsule/ui-capsules';"}</Usage>

      <Demo />

      <PropsTable props={PROPS} />
    </Wrapper>


/**
 * This Error is thrown when there's an error that happens when the networking is being initialized.
 * It is thrown when an error occurs when trying to instantiate a PathRouterNode.
 */
export class PathRouterInstantiationError extends LoggableError {

    public constructor(message: string, path: string, parent?: PathRouterNode) {
        super(message, {
            path,
            parent,
        });

        // Set the prototype explicitly.
        // As specified in the documentation in TypeScript
        // https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work
        Object.setPrototypeOf(this, PathRouterInstantiationError.prototype);    }
}


() => <Home />


() => <About />


() => <Contact />


() => <Login />


() => <Register />


() => <Folder />,


() => <User />,


() => <Cart />,


() => <NotFound />


@Component({
  selector: 'app-sidebar',
  templateUrl: './sidebar.component.html',
  styleUrls: ['./sidebar.component.scss']
})
export class SidebarComponent implements OnInit {
  menuItems: any[];

  constructor() { }

  ngOnInit() {
    this.menuItems = ROUTES.filter(menuItem => menuItem);
  }
  isMobileMenu() {
      if ($(window).width() > 991) {
          return false;
      }
      return true;
  };
}


/**
 * Merge two buildspecs into a new BuildSpec
 *
 * NOTE: will currently only merge commands, not artifact
 * declarations, environment variables, secrets, or any
 * other configuration elements.
 *
 * Internal for now because it's not complete/good enough
 * to expose on the objects directly, but we need to it to
 * keep feature-parity for Project.
 *
 * @internal
 */
export function mergeBuildSpecs(lhs: BuildSpec, rhs: BuildSpec): BuildSpec {
  if (!(lhs instanceof ObjectBuildSpec) || !(rhs instanceof ObjectBuildSpec)) {
    throw new Error('Can only merge buildspecs created using BuildSpec.fromObject()');
  }

  return new ObjectBuildSpec(copyCommands(lhs.spec, rhs.spec));
}


/**
 * Extend buildSpec phases with the contents of another one
 */
function copyCommands(buildSpec: any, extend: any): any {
  if (buildSpec.version === '0.1') {
    throw new Error('Cannot extend buildspec at version "0.1". Set the version to "0.2" or higher instead.');
  }

  const ret = Object.assign({}, buildSpec); // Return a copy
  ret.phases = Object.assign({}, ret.phases);

  for (const phaseName of Object.keys(extend.phases)) {
    const phase = ret.phases[phaseName] = Object.assign({}, ret.phases[phaseName]);
    phase.commands = [...phase.commands || [], ...extend.phases[phaseName].commands];
  }

  return ret;
}


(ctx: IResolveContext) =>
      Stack.of(ctx.scope).toJsonString(this.spec, 2)


/**
 * BuildSpec for CodeBuild projects
 */
export abstract class BuildSpec {
  public static fromObject(value: {[key: string]: any}): BuildSpec {
    return new ObjectBuildSpec(value);
  }

  /**
   * Use a file from the source as buildspec
   *
   * Use this if you want to use a file different from 'buildspec.yml'`
   */
  public static fromSourceFilename(filename: string): BuildSpec {
    return new FilenameBuildSpec(filename);
  }

  /**
   * Whether the buildspec is directly available or deferred until build-time
   */
  public abstract readonly isImmediate: boolean;

  protected constructor() {
  }

  /**
   * Render the represented BuildSpec
   */
  public abstract toBuildSpec(): string;
}


/**
 * BuildSpec that just returns the input unchanged
 */
class FilenameBuildSpec extends BuildSpec {
  public readonly isImmediate: boolean = false;

  constructor(private readonly filename: string) {
    super();
  }

  public toBuildSpec(): string {
    return this.filename;
  }

  public toString() {
    return `<buildspec file: ${this.filename}>`;
  }
}


/**
 * BuildSpec that understands about structure
 */
class ObjectBuildSpec extends BuildSpec {
  public readonly isImmediate: boolean = true;

  constructor(public readonly spec: {[key: string]: any}) {
    super();
  }

  public toBuildSpec(): string {
    // We have to pretty-print the buildspec, otherwise
    // CodeBuild will not recognize it as an inline buildspec.
    return Lazy.stringValue({ produce: (ctx: IResolveContext) =>
      Stack.of(ctx.scope).toJsonString(this.spec, 2),
    });
  }
}


public static fromObject(value: {[key: string]: any}): BuildSpec {
    return new ObjectBuildSpec(value);
  }


/**
   * Use a file from the source as buildspec
   *
   * Use this if you want to use a file different from 'buildspec.yml'`
   */
public static fromSourceFilename(filename: string): BuildSpec {
    return new FilenameBuildSpec(filename);
  }


/**
   * Render the represented BuildSpec
   */
public abstract toBuildSpec(): string;


public toBuildSpec(): string {
    return this.filename;
  }


public toString() {
    return `<buildspec file: ${this.filename}>`;
  }


public toBuildSpec(): string {
    // We have to pretty-print the buildspec, otherwise
    // CodeBuild will not recognize it as an inline buildspec.
    return Lazy.stringValue({ produce: (ctx: IResolveContext) =>
      Stack.of(ctx.scope).toJsonString(this.spec, 2),
    });
  }


() => srcCheckedValuesRef.value.includes(props.value)


() => tgtCheckedValuesRef.value.includes(props.value)


() => {
          if (!props.disabled) {
            handleSrcCheckboxClick(!checkedRef.value, props.value)
          }
        }


() => {
          if (!props.disabled) {
            handleTgtCheckboxClick(!checkedRef.value, props.value)
          }
        }


setup (props) {
    const { source } = props
    const {
      mergedClsPrefixRef,
      mergedThemeRef,
      srcCheckedValuesRef,
      tgtCheckedValuesRef,
      handleSrcCheckboxClick,
      handleTgtCheckboxClick
      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    } = inject(transferInjectionKey)!
    const checkedRef = source
      ? useMemo(() => srcCheckedValuesRef.value.includes(props.value))
      : useMemo(() => tgtCheckedValuesRef.value.includes(props.value))
    const handleClick = source
      ? () => {
          if (!props.disabled) {
            handleSrcCheckboxClick(!checkedRef.value, props.value)
          }
        }
      : () => {
          if (!props.disabled) {
            handleTgtCheckboxClick(!checkedRef.value, props.value)
          }
        }
    return {
      mergedClsPrefix: mergedClsPrefixRef,
      mergedTheme: mergedThemeRef,
      checked: checkedRef,
      handleClick
    }
  }


render () {
    const { disabled, mergedTheme, mergedClsPrefix, label, checked, source } =
      this
    return (
      <div
        class={[
          `${mergedClsPrefix}-transfer-list-item`,
          disabled && `${mergedClsPrefix}-transfer-list-item--disabled`,
          source
            ? `${mergedClsPrefix}-transfer-list-item--source`
            : `${mergedClsPrefix}-transfer-list-item--target`
        ]}
        onClick={this.handleClick}
      >
        <div class={`${mergedClsPrefix}-transfer-list-item__checkbox`}>
          <NCheckbox
            theme={mergedTheme.peers.Checkbox}
            themeOverrides={mergedTheme.peerOverrides.Checkbox}
            disabled={disabled}
            checked={checked}
          />
        </div>
        <div
          class={`${mergedClsPrefix}-transfer-list-item__label`}
          title={getTitleAttribute(label)}
        >
          {label}
        </div>
      </div>


getTitleAttribute(label)


export class FileSaver {
  public saveJSON(json: string, fileName = 'file.json'): void {
    const jsonEncoded = window.encodeURIComponent(json);

    const dataStr = `data:text/json;charset=utf-8,${jsonEncoded}`;

    const linkElement = document.createElement('a');
    linkElement.setAttribute('href', dataStr);
    linkElement.setAttribute('download', fileName);
    linkElement.click();
  }
}


public saveJSON(json: string, fileName = 'file.json'): void {
    const jsonEncoded = window.encodeURIComponent(json);

    const dataStr = `data:text/json;charset=utf-8,${jsonEncoded}`;

    const linkElement = document.createElement('a');
    linkElement.setAttribute('href', dataStr);
    linkElement.setAttribute('download', fileName);
    linkElement.click();
  }


@Module({
  imports: [DatabaseModule],
  providers: [...AccountProvider, AccountService],
  exports: [AccountService],
})
export class AccountModule {}


@Component({
  template: `

{{renderValue['pharmacyType']['name']}}

Not Assigned

  `,
})
export class PharmacyTypeRenderComponent implements ViewCell, OnInit {

  renderValue: any;

  @Input() value: number;
  @Input() rowData: any;

  ngOnInit() {
    this.renderValue = this.rowData;
  }

}


ngOnInit() {
    this.renderValue = this.rowData;
  }


() =>
		this.actions$.pipe(
			ofType(dummyActions.Load),
			switchMap(() => {
				return this.dummyService.getDummyData().pipe(
					map((entity: DummyInterface) =>
						dummyActions.LoadSuccess({ entity }),
					),
					catchError(() => {
						return of(
							dummyActions.LoadFail({
								errorMessage: 'global.something-went-wrong',
							}),
						);
					}),
				);
			}),
		)


() => {
				return this.dummyService.getDummyData().pipe(
					map((entity: DummyInterface) =>
						dummyActions.LoadSuccess({ entity }),
					),
					catchError(() => {
						return of(
							dummyActions.LoadFail({
								errorMessage: 'global.something-went-wrong',
							}),
						);
					}),
				);
			}


(entity: DummyInterface) =>
						dummyActions.LoadSuccess({ entity })


() => {
						return of(
							dummyActions.LoadFail({
								errorMessage: 'global.something-went-wrong',
							}),
						);
					}


/**
 * DummyEffects represents the class being used to trigger all effects used for the NGRX dummy store
 */
@Injectable()
export class DummyEffects {
	constructor(
		private readonly actions$: Actions,
		private readonly dummyService: DummyService,
	) {}

	/**
	 * loadDummy$ Effect will be triggered when action LOAD is called from dummyActions
	 * @return Observable of LoadSuccess or LoadFail
	 */
	loadDummy$: Observable<any> = createEffect(() =>
		this.actions$.pipe(
			ofType(dummyActions.Load),
			switchMap(() => {
				return this.dummyService.getDummyData().pipe(
					map((entity: DummyInterface) =>
						dummyActions.LoadSuccess({ entity }),
					),
					catchError(() => {
						return of(
							dummyActions.LoadFail({
								errorMessage: 'global.something-went-wrong',
							}),
						);
					}),
				);
			}),
		),
	);
}


(ids: Key[], context: SchemaTypes["Context"]) => getDataloader(context).loadMany(ids)


(nodeConfig) => {
        this.objectField(ref, "id", (t) => (t as unknown as {
            globalID: (options: Record<string, unknown>) => FieldRef<unknown>;
        }).globalID({
            ...options.id,
            nullable: false,
            args: {},
            resolve: async (parent: Shape, args: object, context: object, info: GraphQLResolveInfo) => ({
                type: nodeConfig.name,
                id: await options.id.resolve(parent, args, context, info),
            }),
        }));
    }


(t) => (t as unknown as {
            globalID: (options: Record<string, unknown>) => FieldRef<unknown>;
        }).globalID({
            ...options.id,
            nullable: false,
            args: {},
            resolve: async (parent: Shape, args: object, context: object, info: GraphQLResolveInfo) => ({
                type: nodeConfig.name,
                id: await options.id.resolve(parent, args, context, info),
            }),
        })


async (parent: Shape, args: object, context: object, info: GraphQLResolveInfo) => ({
                type: nodeConfig.name,
                id: await options.id.resolve(parent, args, context, info),
            })


/**
 * This sample demonstrates how to Retrieves information about a gallery image definition.
 *
 * @summary Retrieves information about a gallery image definition.
 * x-ms-original-file: specification/compute/resource-manager/Microsoft.Compute/stable/2021-07-01/examples/gallery/GetAGalleryImage.json
 */
async function getAGalleryImage() {
  const subscriptionId = "{subscription-id}";
  const resourceGroupName = "myResourceGroup";
  const galleryName = "myGalleryName";
  const galleryImageName = "myGalleryImageName";
  const credential = new DefaultAzureCredential();
  const client = new ComputeManagementClient(credential, subscriptionId);
  const result = await client.galleryImages.get(
    resourceGroupName,
    galleryName,
    galleryImageName
  );
  console.log(result);
}


function getVersionViewUnavailableMessage(
  deployment: ApplicationDeployment
): IUnavailableServiceMessage | undefined {
  const serviceUnavailableBecause = unavailableServiceMessageCreator(
    'Det er ikke mulig å endre versjonen på denne applikasjonen'
  );

  if (deployment.details.deploymentSpec?.type === 'development') {
    return serviceUnavailableBecause(
      'Applikasjonen er av type development, og kan kun oppgraderes med binary builds',
      'info'
    );
  }
  if (!deployment.imageRepository?.isFullyQualified) {
    return serviceUnavailableBecause(
      'Applikasjonen har en Docker Image referanse som ikke går mot det interne Docker Registry, og versjoner kan dermed ikke hentes',
      'warning'
    );
  }

  return undefined;
}


function versionStatusMessage(
  deployment: ApplicationDeployment
): VersionStatus {
  const { pods, deploymentSpec } = deployment.details;
  const { deployTag, releaseTo } = deployment.version;

  const deploymentInProgress = !!deployment.status.reasons.find(
    (status) => status.name === 'DeploymentInProgressCheck'
  );

  return getVersionStatus(
    pods,
    deployTag.name,
    deploymentSpec && deploymentSpec.version,
    releaseTo,
    deploymentInProgress
  );
}


(status) => status.name === 'DeploymentInProgressCheck'


({
  filterPathUrl,
  affiliation,
  deployment,
  isRefreshing,
  deleteAndRefreshApplications,
  refreshApplicationDeployment,
}) => {
  const match = useRouteMatch<ApplicationDeploymentMatchParams>();
  const history = useHistory();

  if (!match) {
    return null;
  }

  const unavailableMessage = getVersionViewUnavailableMessage(deployment);
  const versionStatus = versionStatusMessage(deployment);

  const goToDeploymentsPage = () => {
    history.push(`/a/${affiliation}/deployments${filterPathUrl}`);
  };

  return (
    <DetailsViewGrid>
      <InitVersionsContainer
        hasPermission={deployment.permission.paas.admin}
        imageRepository={deployment.imageRepository}
      />
      <DetailsActionBar
        title={`${deployment.environment}/${deployment.name}`}
        isRefreshing={isRefreshing}
        updatedTime={deployment.time}
        goToDeploymentsPage={goToDeploymentsPage}
        refreshApplicationDeployment={()


() => {
    history.push(`/a/${affiliation}/deployments${filterPathUrl}`);
  }


interface IDetailsViewProps {
  deployment: ApplicationDeployment;
  filterPathUrl: string;
  refreshApplicationDeployment: (
    applicationDeploymentId: string,
    affiliation: string
  ) => Promise<void>;
  deleteAndRefreshApplications: (
    affiliation: string,
    namespace: string,
    name: string
  ) => Promise<void>;
  isRefreshing: boolean;
  affiliation: string;
}


unavailableMessage ? (
              <UnavailableServiceMessage
                message={unavailableMessage}
                type={unavailableMessage.type}
              />
            ) : (
              <VersionViewContainer
                versionStatus={versionStatus}
                deploymentSpecVersion={
                  deployment.details.deploymentSpec


({ stream }: any) =>
				this.props.children ? (this.props.children as any)(stream) : stream


export class MapElement<T> extends React.PureComponent<{
	stream: Observable<T>
	children?: (stream: T) => React.ReactNode
}> {
	render() {
		return React.createElement(LiftWrapper, {
			component: ({ stream }: any) =>
				this.props.children ? (this.props.children as any)(stream) : stream,
			props: { stream: this.props.stream },
		})
	}
}


render() {
		return React.createElement(LiftWrapper, {
			component: ({ stream }: any) =>
				this.props.children ? (this.props.children as any)(stream) : stream,
			props: { stream: this.props.stream },
		})
	}


export function HexTile(props: HexTileProps) {
    return (

 props.tileOnClick(props.letter)}


export interface HexTileProps {
    letter: String,
    tileOnClick: any
}


() => {
  const renderer = createRenderer();
  renderer.render(<Empty />);
  expect(renderer.getRenderOutput()).toMatchSnapshot();
}


(
    {
      alt,
      aspectRatio,
      containerProps,
      imgProps,
      height,
      src,
      width,
      ...restProps
    }: ImageProps,
    ref: Ref<any>,
  ) => {
    return (
      <ImageContainer
        {...restProps}
        {


interface ImageProps {
  alt?: string;
  aspectRatio?: number;
  containerProps?: ExtractVisageComponentProps<typeof ImageContainer>;
  imgProps?: ExtractVisageComponentProps<typeof Img>;
  height?: number;
  src?: string;
  width?: number;
}


(theme: Theme) => ({
  projectNav: {
    minWidth: '15rem',
    '& a': {
      color: theme.palette.text.secondary,
      '&:hover': {
        background: 'rgba(0, 51, 102, 0.05)'
      }
    },
    '& a.active': {
      color: theme.palette.primary.main,
      background: 'rgba(0, 51, 102, 0.05)',
      '& svg': {
        color: theme.palette.primary.main
      }
    }
  },
  chip: {
    padding: '0px 8px',
    borderRadius: '4px',
    color: 'white'
  },
  chipActive: {
    backgroundColor: theme.palette.warning.main
  },
  chipCompleted: {
    backgroundColor: theme.palette.success.main
  },
  spacingRight: {
    paddingRight: '1rem'
  },
  actionButton: {
    minWidth: '6rem',
    '& + button': {
      marginLeft: '0.5rem'
    }
  }
})


() => {
  const urlParams = useParams();
  const location = useLocation();
  const biohubApi = useBiohubApi();
  const history = useHistory();

  const dialogContext = useContext(DialogContext);

  const classes = useStyles();

  const [isLoadingProject, setIsLoadingProject] = useState(false);
  const [projectWithDetails, setProjectWithDetails] = useState<IGetProjectForViewResponse | null>(null);

  const [isLoadingCodes, setIsLoadingCodes] = useState(false);
  const [codes, setCodes] = useState<IGetAllCodeSetsResponse>();

  const { keycloakWrapper } = useContext(AuthStateContext);

  useEffect(() => {
    const getCodes = async () => {
      const codesResponse = await biohubApi.codes.getAllCodeSets();

      if (!codesResponse) {
        // TODO error handling/messaging
        return;
      }

      setCodes(codesResponse);
    };

    if (!isLoadingCodes && !codes) {
      getCodes();
      setIsLoadingCodes(true);
    }
  }, [urlParams, biohubApi.codes, isLoadingCodes, codes]);

  const getProject = useCallback(async () => {
    const projectWithDetailsResponse = await biohubApi.project.getProjectForView(urlParams['id']);

    if (!projectWithDetailsResponse) {
      // TODO error handling/messaging
      return;
    }

    setProjectWithDetails(projectWithDetailsResponse);
  }, [biohubApi.project, urlParams]);

  useEffect(() => {
    if (!isLoadingProject && !projectWithDetails) {
      getProject();
      setIsLoadingProject(true);
    }
  }, [isLoadingProject, projectWithDetails, getProject]);

  const defaultYesNoDialogProps = {
    dialogTitle: DeleteProjectI18N.deleteTitle,
    dialogText: DeleteProjectI18N.deleteText,
    open: false,
    onClose: () => dialogContext.setYesNoDialog({ open: false }),
    onNo: () => dialogContext.setYesNoDialog({ open: false }),
    onYes: () => dialogContext.setYesNoDialog({ open: false })
  };

  const deleteErrorDialogProps = {
    dialogTitle: DeleteProjectI18N.deleteErrorTitle,
    dialogText: DeleteProjectI18N.deleteErrorText,
    open: false,
    onClose: () => {
      dialogContext.setErrorDialog({ open: false });
    },
    onOk: () => {
      dialogContext.setErrorDialog({ open: false });
    }
  };

  const publishErrorDialogProps = {
    ...deleteErrorDialogProps,
    dialogTitle: PublishProjectI18N.publishErrorTitle,
    dialogText: PublishProjectI18N.publishErrorText
  };

  const publishProject = async (publish: boolean) => {
    if (!projectWithDetails) {
      return;
    }

    try {
      const response = await biohubApi.project.publishProject(projectWithDetails.id, publish);

      if (!response) {
        showPublishErrorDialog({ open: true });
        return;
      }

      await getProject();
    } catch (error) {
      const apiError = error as APIError;
      showPublishErrorDialog({ dialogText: apiError.message, open: true });
      return error;
    }
  };

  const showDeleteProjectDialog = () => {
    dialogContext.setYesNoDialog({
      ...defaultYesNoDialogProps,
      open: true,
      onYes: () => {
        deleteProject();
        dialogContext.setYesNoDialog({ open: false });
      }
    });
  };

  const showDeleteErrorDialog = (textDialogProps?: Partial<IErrorDialogProps>) => {
    dialogContext.setErrorDialog({ ...deleteErrorDialogProps, ...textDialogProps, open: true });
  };

  const showPublishErrorDialog = (textDialogProps?: Partial<IErrorDialogProps>) => {
    dialogContext.setErrorDialog({ ...publishErrorDialogProps, ...textDialogProps, open: true });
  };

  const deleteProject = async () => {
    if (!projectWithDetails) {
      return;
    }

    try {
      const response = await biohubApi.project.deleteProject(projectWithDetails.id);

      if (!response) {
        showDeleteErrorDialog({ open: true });
        return;
      }

      history.push(`/admin/projects`);
    } catch (error) {
      const apiError = error as APIError;
      showDeleteErrorDialog({ dialogText: apiError.message, open: true });
      return error;
    }
  };

  const getChipIcon = (status_name: string) => {
    let chipLabel;
    let chipStatusClass;

    if (ProjectStatusType.ACTIVE === status_name) {
      chipLabel = 'ACTIVE';
      chipStatusClass = classes.chipActive;
    } else if (ProjectStatusType.COMPLETED === status_name) {
      chipLabel = 'COMPLETED';
      chipStatusClass = classes.chipCompleted;
    }

    return <Chip size="small" className={clsx(classes.chip, chipStatusClass)} label={chipLabel} />;
  };

  if (!codes || !projectWithDetails) {
    return <CircularProgress className="pageProgress" size={40} />;
  }

  // Show delete button if you are a system admin or a project admin
  const showDeleteProjectButton = keycloakWrapper?.hasSystemRole([SYSTEM_ROLE.SYSTEM_ADMIN, SYSTEM_ROLE.PROJECT_ADMIN]);
  // Enable delete button if you a system admin OR a project admin and the project is not published
  const enableDeleteProjectButton =
    keycloakWrapper?.hasSystemRole([SYSTEM_ROLE.SYSTEM_ADMIN]) ||
    (keycloakWrapper?.hasSystemRole([SYSTEM_ROLE.PROJECT_ADMIN]) && !projectWithDetails.project.publish_date);

  return (
    <>
      <Paper elevation={2} square={true}>
        <Container maxWidth="xl">
          <Box display="flex" justifyContent="space-between">
            <Box py={4}>
              <Box mb={1} display="flex">
                <Typography className={classes.spacingRight} variant="h1">
                  {projectWithDetails.project.project_name}
                </Typography>
                {getChipIcon(projectWithDetails.project.completion_status)}
              </Box>
              <Box>
                <Typography variant="subtitle1" color="textSecondary">
                  <span>
                    {projectWithDetails.project.end_date ? (
                      <>
                        {getFormattedDateRangeString(
                          DATE_FORMAT.ShortMediumDateFormat,
                          projectWithDetails.project.start_date,
                          projectWithDetails.project.end_date
                        )}
                      </>


() => {
    const getCodes = async () => {
      const codesResponse = await biohubApi.codes.getAllCodeSets();

      if (!codesResponse) {
        // TODO error handling/messaging
        return;
      }

      setCodes(codesResponse);
    };

    if (!isLoadingCodes && !codes) {
      getCodes();
      setIsLoadingCodes(true);
    }
  }


async () => {
      const codesResponse = await biohubApi.codes.getAllCodeSets();

      if (!codesResponse) {
        // TODO error handling/messaging
        return;
      }

      setCodes(codesResponse);
    }


async () => {
    const projectWithDetailsResponse = await biohubApi.project.getProjectForView(urlParams['id']);

    if (!projectWithDetailsResponse) {
      // TODO error handling/messaging
      return;
    }

    setProjectWithDetails(projectWithDetailsResponse);
  }


() => {
    if (!isLoadingProject && !projectWithDetails) {
      getProject();
      setIsLoadingProject(true);
    }
  }


() => dialogContext.setYesNoDialog({ open: false })


() => {
      dialogContext.setErrorDialog({ open: false });
    }


async (publish: boolean) => {
    if (!projectWithDetails) {
      return;
    }

    try {
      const response = await biohubApi.project.publishProject(projectWithDetails.id, publish);

      if (!response) {
        showPublishErrorDialog({ open: true });
        return;
      }

      await getProject();
    } catch (error) {
      const apiError = error as APIError;
      showPublishErrorDialog({ dialogText: apiError.message, open: true });
      return error;
    }
  }


() => {
    dialogContext.setYesNoDialog({
      ...defaultYesNoDialogProps,
      open: true,
      onYes: () => {
        deleteProject();
        dialogContext.setYesNoDialog({ open: false });
      }
    });
  }


() => {
        deleteProject();
        dialogContext.setYesNoDialog({ open: false });
      }


(textDialogProps?: Partial<IErrorDialogProps>) => {
    dialogContext.setErrorDialog({ ...deleteErrorDialogProps, ...textDialogProps, open: true });
  }


(textDialogProps?: Partial<IErrorDialogProps>) => {
    dialogContext.setErrorDialog({ ...publishErrorDialogProps, ...textDialogProps, open: true });
  }


async () => {
    if (!projectWithDetails) {
      return;
    }

    try {
      const response = await biohubApi.project.deleteProject(projectWithDetails.id);

      if (!response) {
        showDeleteErrorDialog({ open: true });
        return;
      }

      history.push(`/admin/projects`);
    } catch (error) {
      const apiError = error as APIError;
      showDeleteErrorDialog({ dialogText: apiError.message, open: true });
      return error;
    }
  }


(status_name: string) => {
    let chipLabel;
    let chipStatusClass;

    if (ProjectStatusType.ACTIVE === status_name) {
      chipLabel = 'ACTIVE';
      chipStatusClass = classes.chipActive;
    } else if (ProjectStatusType.COMPLETED === status_name) {
      chipLabel = 'COMPLETED';
      chipStatusClass = classes.chipCompleted;
    }

    return <Chip size="small" className={clsx(classes.chip, chipStatusClass)} label={chipLabel} />;
  }


getFormattedDateRangeString(
                          DATE_FORMAT


publishProject(!projectWithDetails


async ctx => {
  ctx.end('Hello world!');
}


value => this._filter(value)


option => {
      if (option.hasOwnProperty('name')) {
        return option.name.toLowerCase().includes(filterValue)
          || option.author.toLowerCase().includes(filterValue)
          || new Date(option.timestamp).toUTCString().toLowerCase().includes(filterValue) ||
          filterValue.includes(this.formatValue(option).toLowerCase());
      } else {
        return option.toLowerCase().includes(filterValue);
      }
    }


@Component({
  selector: 'app-autosuggest-wrapper',
  encapsulation: ViewEncapsulation.None,
  templateUrl: './autosuggest-wrapper.component.html',
  styleUrls: ['./autosuggest-wrapper.component.scss']
})
export class AutosuggestWrapperComponent implements OnChanges, OnInit {

  @ViewChild('inputElement') inputElement;

  @Input() model: any;
  @Input() source: any;
  @Input() isDisabled: boolean;
  @Input() alignRight = false;
  @Input() label: string;
  @Output() valueChanged = new EventEmitter();

  filteredOptions: Observable<any[]>;
  formControl = new FormControl();

  handleValueChanged(chosenModel: any) {
    this.valueChanged.emit(chosenModel);
  }

  formatValue(value: any) {
    if (value === null || value === undefined) {
      return '';
    }
    if (value.hasOwnProperty('name')) {
      return new Date(value.timestamp).toUTCString() + ',  ' + value.name.substring(0, 7) + ', ' + value.author;
    } else {
      return value;
    }
  }

  ngOnChanges(changes: SimpleChanges) {
    if (this.model !== null && this.model !== undefined) {
      this.formControl.setValue(this.model);
    }
    this.filteredOptions = this.formControl.valueChanges
      .pipe(
        startWith(''),
        map(value => this._filter(value))
      );
  }

  private _filter(value: any): string[] {
    if (this.source === undefined) {
      return [];
    } else if (value === undefined) {
      return this.source;
    }

    let filterValue = '';
    if (value.hasOwnProperty('name')) {
      filterValue = value.name.toLowerCase();
    } else {
      filterValue = value.toLowerCase();
    }

    return this.source.filter(option => {
      if (option.hasOwnProperty('name')) {
        return option.name.toLowerCase().includes(filterValue)
          || option.author.toLowerCase().includes(filterValue)
          || new Date(option.timestamp).toUTCString().toLowerCase().includes(filterValue) ||
          filterValue.includes(this.formatValue(option).toLowerCase());
      } else {
        return option.toLowerCase().includes(filterValue);
      }
    });
  }

  ngOnInit(): void {
    if (this.model !== null && this.model !== undefined) {
      this.formControl.setValue(this.model);
    }
    this.filteredOptions = this.formControl.valueChanges
      .pipe(
        startWith(''),
        map(value => this._filter(value))
      );
  }
}


handleValueChanged(chosenModel: any) {
    this.valueChanged.emit(chosenModel);
  }


formatValue(value: any) {
    if (value === null || value === undefined) {
      return '';
    }
    if (value.hasOwnProperty('name')) {
      return new Date(value.timestamp).toUTCString() + ',  ' + value.name.substring(0, 7) + ', ' + value.author;
    } else {
      return value;
    }
  }


ngOnChanges(changes: SimpleChanges) {
    if (this.model !== null && this.model !== undefined) {
      this.formControl.setValue(this.model);
    }
    this.filteredOptions = this.formControl.valueChanges
      .pipe(
        startWith(''),
        map(value => this._filter(value))
      );
  }


private _filter(value: any): string[] {
    if (this.source === undefined) {
      return [];
    } else if (value === undefined) {
      return this.source;
    }

    let filterValue = '';
    if (value.hasOwnProperty('name')) {
      filterValue = value.name.toLowerCase();
    } else {
      filterValue = value.toLowerCase();
    }

    return this.source.filter(option => {
      if (option.hasOwnProperty('name')) {
        return option.name.toLowerCase().includes(filterValue)
          || option.author.toLowerCase().includes(filterValue)
          || new Date(option.timestamp).toUTCString().toLowerCase().includes(filterValue) ||
          filterValue.includes(this.formatValue(option).toLowerCase());
      } else {
        return option.toLowerCase().includes(filterValue);
      }
    });
  }


ngOnInit(): void {
    if (this.model !== null && this.model !== undefined) {
      this.formControl.setValue(this.model);
    }
    this.filteredOptions = this.formControl.valueChanges
      .pipe(
        startWith(''),
        map(value => this._filter(value))
      );
  }


// Jobs with IDs JOB0 -> JOB4.
function testJobs(count: number): QueryJobsResult[] {
    const base = {
      status: JobStatus.Running,
      submission: new Date('2015-04-20T20:00:00'),
      start: new Date('2015-04-20T20:00:01'),
      end: new Date('2015-04-20T20:01:00'),
      extensions: {userId: 'test-user-id'}
    };
    return (new Array(count)).fill(null).map((_, i) => {
      return {
        ...base,
        id: `JOB${i}`,
        name: `JOB ${i}`
      };
    });
  }


function expectJobsRendered(jobs: QueryJobsResult[]) {
    const de: DebugElement = fixture.debugElement;
    const rows = de.queryAll(By.css('.mat-row'));
    expect(rows.length).toEqual(jobs.length);
    rows.forEach((row, i) => {
      expect(row.nativeElement.textContent).toContain(jobs[i].name);
    });
  }


(_, i) => {
      return {
        ...base,
        id: `JOB${i}`,
        name: `JOB ${i}`
      };
    }


() => {
    fakeJobService = new FakeJobManagerService(testJobs(5));
    capabilities = {
      displayFields: [
        {field: 'name', display: 'Name', primary: true},
        {field: 'status', display: 'Status', primary: true},
        {field: 'submission', display: 'Submitted', primary: true},
        {field: 'extensions.userId', display: 'User ID', primary: true}
      ]
    };
    fakeCapabilitiesService = new FakeCapabilitiesService(capabilities);
    authService = new AuthService(null, fakeCapabilitiesService, null, snackBar);
    settingsService = new SettingsService(authService, fakeCapabilitiesService, localStorage);
    TestBed.configureTestingModule({
      declarations: [
        AppComponent,
        FakeProjectsComponent,
        JobsBulkEditComponent,
        JobListComponent,
        TestJobListComponent,
        JobsTableComponent
      ],
      imports: [
        BrowserAnimationsModule,
        ClrIconModule,
        ClrTooltipModule,
        CommonModule,
        MatButtonModule,
        MatCardModule,
        MatCheckboxModule,
        MatDialogModule,
        MatDividerModule,
        MatListModule,
        MatSlideToggleModule,
        MatMenuModule,
        MatPaginatorModule,
        MatProgressSpinnerModule,
        MatSnackBarModule,
        MatSelectModule,
        MatSortModule,
        MatTableModule,
        MatTooltipModule,
        RouterTestingModule.withRoutes([
          {path: 'jobs', component: TestJobListComponent, resolve: {stream: JobListResolver}},
          {path: 'projects', component: FakeProjectsComponent}
        ]),
        SharedModule
      ],
      providers: [
        {provide: JobManagerService, useValue: fakeJobService},
        {provide: SettingsService, useValue: settingsService},
        {provide: CapabilitiesService, useValue: fakeCapabilitiesService},
        {provide: AuthService, useValue: authService},
        JobListResolver,
        RouteReuse
      ],
    }).compileComponents();
  }


() => {
    fixture = TestBed.createComponent(AppComponent);

    const router: Router = TestBed.get(Router);
    router.initialNavigation();
    router.navigate(['jobs']);
    tick();

    fixture.detectChanges();
    tick();

    testComponent = fixture.debugElement.query(By.css('jm-job-list')).componentInstance;
  }


(row, i) => {
      expect(row.nativeElement.textContent).toContain(jobs[i].name);
    }


() => {
    let error = {
      status: 400,
      title: 'Bad Request',
      message: 'Missing required field `parentId`'
    };
    testComponent.handleError(error);
    fixture.detectChanges();

    let de: DebugElement = fixture.debugElement;
    expect(de.query(By.css('.mat-simple-snackbar')).nativeElement.textContent)
      .toEqual("Bad Request (400): Missing required field `parentId` Dismiss");
  }


() => {
    fixture.detectChanges();
    tick();
    expectJobsRendered(fakeJobService.jobs.slice(0, 3));
  }


() => {
    let de: DebugElement = fixture.debugElement;
    expect(de.queryAll(By.css('.spinner-container')).length).toEqual(0);

    // Ideally we'd click a nav element here instead, but unfortunately the
    // navigate and job load would be evaluated within a single tick(), so we'd
    // never see the loading spinner.
    testComponent.reloadJobs('');
    fixture.detectChanges();
    expect(de.queryAll(By.css('.spinner-container')).length).toEqual(1);
    tick();

    // We don't finish loading until we complete a query that matches the
    // the ActiveRoute; so trigger a real navigate to clear the loading state.
    de.query(By.css('.running-button')).nativeElement.click();
    tick();
    fixture.detectChanges();
    expect(de.queryAll(By.css('.spinner-container')).length).toEqual(0);
  }


() => {
    fakeJobService.jobs = testJobs(5);
    tick();
    fixture.detectChanges();
    tick();
    const de: DebugElement = fixture.debugElement;
    de.query(By.css('.mat-paginator-increment')).nativeElement.click();
    fixture.detectChanges();
    tick();

    // Page 2.
    expectJobsRendered(fakeJobService.jobs.slice(3, 5));

    // the prev page button should be enabled and the next page button should be disabled
    expect(de.query(By.css('.mat-paginator-navigation-previous')).attributes['ng-reflect-disabled']).toEqual('false');
    expect(de.query(By.css('.mat-paginator-navigation-next')).attributes['ng-reflect-disabled']).toEqual('true');
  }


() => {
    fakeJobService.jobs = testJobs(5);
    tick();
    fixture.detectChanges();
    const de: DebugElement = fixture.debugElement;
    de.query(By.css('.mat-paginator-increment')).nativeElement.click();
    fixture.detectChanges();

    // Back to page 1, which should have the first 3 jobs.
    de.query(By.css('.mat-paginator-decrement')).nativeElement.click();
    fixture.detectChanges();
    tick();
    expectJobsRendered(fakeJobService.jobs.slice(0, 3));

    // the prev page button should be disabled and the next page button should be enabled
    expect(de.query(By.css('.mat-paginator-navigation-previous')).attributes['ng-reflect-disabled']).toEqual('true');
    expect(de.query(By.css('.mat-paginator-navigation-next')).attributes['ng-reflect-disabled']).toEqual('false');
  }


() => {
    fakeJobService.jobs = testJobs(6);
    testComponent.jobStream.setStale();
    fixture.detectChanges();
    tick(100);

    const de: DebugElement = fixture.debugElement;
    de.query(By.css('.mat-paginator-increment')).nativeElement.click();
    fixture.detectChanges();

    // the last three jobs should be displayed and next page button should be disabled
    expectJobsRendered(fakeJobService.jobs.slice(3, 6));
    expect(de.query(By.css('.mat-paginator-navigation-next')).attributes['ng-reflect-disabled']).toEqual('true');
  }


() => {
    const jobs: QueryJobsResult[] = testJobs(5);
    jobs[1].status = JobStatus.Succeeded;
    jobs[3].status = JobStatus.Aborted;
    fakeJobService.jobs = jobs;
    tick();
    fixture.detectChanges();

    let de: DebugElement = fixture.debugElement;
    de.query(By.css('.succeeded-button')).nativeElement.click();
    tick();
    fixture.detectChanges();
    tick();
    expectJobsRendered([jobs[1]]);
  }


() => {
    const jobs = testJobs(5);
    fakeJobService.jobs = jobs;
    fixture.detectChanges();

    // Filter by active to filter out jobs after they've been aborted.
    let de: DebugElement = fixture.debugElement;
    de.query(By.css('.running-button')).nativeElement.click();
    fixture.detectChanges();

    // We select the first page (3 jobs) and abort. Jobs 3 and 4 are unaffected.
    let component = de.query(By.css('jm-job-list-table')).componentInstance;
    component.toggleSelectAll();
    fixture.detectChanges();

    // fakeAsync() doesn't play well with the Promises used on abort.
    de.query(By.css('.group-abort')).nativeElement.click();
    fixture.whenStable().then(() => {
      fixture.detectChanges();

      // Jobs 3 and 4 should be the only jobs displayed, as they are the only
      // remaining active jobs.
      expectJobsRendered(jobs.slice(3, 5));
    });
  }


() => {
      fixture.detectChanges();

      // Jobs 3 and 4 should be the only jobs displayed, as they are the only
      // remaining active jobs.
      expectJobsRendered(jobs.slice(3, 5));
    }


() => {
    tick();
    fixture.detectChanges();

    const freshJobs = testJobs(10);
    freshJobs[0].name = "updated";
    freshJobs[1].name = "new";
    fakeJobService.jobs = freshJobs;
    testComponent.jobStream.setStale();

    fixture.detectChanges();
    tick(1000);

    fixture.whenStable().then(() => {
      fixture.detectChanges();
      expectJobsRendered(freshJobs.slice(0, 3));
    });
  }


() => {
      fixture.detectChanges();
      expectJobsRendered(freshJobs.slice(0, 3));
    }


() => {
    const jobs = testJobs(5);
    jobs[3].status = JobStatus.Failed;
    fakeJobService.jobs = jobs;
    tick();
    fixture.detectChanges();

    const de: DebugElement = fixture.debugElement;
    de.query(By.css('.mat-paginator-increment')).nativeElement.click();
    fixture.detectChanges();

    de.query(By.css('.failed-button')).nativeElement.click();
    tick();
    fixture.detectChanges();
    tick();
    expectJobsRendered([jobs[3]]);
  }


() => {
    capabilities.queryExtensions = ['projectId'];
    testComponent.reloadJobs('');

    fixture.detectChanges();
    tick();

    const de: DebugElement = fixture.debugElement;
    expect(de.queryAll(By.css('.fake-projects')).length).toEqual(1);
  }


() => {
    testComponent.settingsService.setSavedSettingValue('hideArchived', null, testComponent.projectId);
    fixture.detectChanges();
    const de: DebugElement = fixture.debugElement;

    de.query(By.css('button.settings-icon')).nativeElement.click();
    fixture.detectChanges();

    expect(de.queryAll(By.css('.settings-menu .mat-slide-toggle.hide-archived')).length).toEqual(0);
  }


() => {
    testComponent.settingsService.setSavedSettingValue('hideArchived', true, testComponent.projectId);
    fixture.detectChanges();
    const de: DebugElement = fixture.debugElement;

    de.query(By.css('button.settings-icon')).nativeElement.click();
    fixture.detectChanges();

    expect(de.queryAll(By.css('.settings-menu .mat-slide-toggle.hide-archived')).length).toEqual(1);
  }


@Component({
    selector: 'jm-test-app',
    template: '<router-outlet></router-outlet>'
  })
  class AppComponent {}


@Component({
    selector: 'jm-test-job-list-component',
    template: '<jm-job-list [pageSize]="3"></jm-job-list>'
  })
  class TestJobListComponent {}


@Component({
    selector: 'jm-fake-projects-component',
    template: '

'
  })
  class FakeProjectsComponent {}


/**
     * Numeric rounding
     *
     * Example: round to 3 decimal places
     * ```
     * makerjs.round(3.14159, .001); //returns 3.142
     * ```
     *
     * @param n The number to round off.
     * @param accuracy Optional exemplar of number of decimal places.
     */
function round(n: number, accuracy?: number): number;


/**
     * Create a string representation of a route array.
     *
     * @param route Array of strings which are segments of a route.
     * @returns String of the flattened array.
     */
function createRouteKey(route: string[]): string;


/**
     * Clone an object.
     *
     * @param objectToClone The object to clone.
     * @returns A new clone of the original object.
     */
function cloneObject<T>(objectToClone: T): T;


/**
     * Copy the properties from one object to another object.
     *
     * Example:
     * ```
     * makerjs.extendObject({ abc: 123 }, { xyz: 789 }); //returns { abc: 123, xyz: 789 }
     * ```
     *
     * @param target The object to extend. It will receive the new properties.
     * @param other An object containing properties to merge in.
     * @returns The original object after merging.
     */
function extendObject(target: Object, other: Object): Object;


/**
     * Test to see if a variable is a function.
     *
     * @param value The object to test.
     * @returns True if the object is a function type.
     */
function isFunction(value: any): boolean;


/**
     * Test to see if a variable is a number.
     *
     * @param value The object to test.
     * @returns True if the object is a number type.
     */
function isNumber(value: any): boolean;


/**
     * Test to see if a variable is an object.
     *
     * @param value The object to test.
     * @returns True if the object is an object type.
     */
function isObject(value: any): boolean;


/**
     * Test to see if an object implements the required properties of a point.
     *
     * @param item The item to test.
     */
function isPoint(item: any): boolean;


/**
     * Test to see if an object implements the required properties of a path.
     *
     * @param item The item to test.
     */
function isPath(item: any): boolean;


/**
     * Test to see if an object implements the required properties of a line.
     *
     * @param item The item to test.
     */
function isPathLine(item: any): boolean;


/**
     * Test to see if an object implements the required properties of a circle.
     *
     * @param item The item to test.
     */
function isPathCircle(item: any): boolean;


/**
     * Test to see if an object implements the required properties of an arc.
     *
     * @param item The item to test.
     */
function isPathArc(item: any): boolean;


/**
     * Test to see if an object implements the required properties of an arc in a bezier curve.
     *
     * @param item The item to test.
     */
function isPathArcInBezierCurve(item: any): boolean;


/**
     * Test to see if an object implements the required properties of a model.
     */
function isModel(item: any): boolean;


/**
     * Ensures an angle is not greater than 360
     *
     * @param angleInDegrees Angle in degrees.
     * @retiurns Same polar angle but not greater than 360 degrees.
     */
function noRevolutions(angleInDegrees: number): number;


/**
     * Convert an angle from degrees to radians.
     *
     * @param angleInDegrees Angle in degrees.
     * @returns Angle in radians.
     */
function toRadians(angleInDegrees: number): number;


/**
     * Convert an angle from radians to degrees.
     *
     * @param angleInRadians Angle in radians.
     * @returns Angle in degrees.
     */
function toDegrees(angleInRadians: number): number;


/**
     * Get an arc's end angle, ensured to be greater than its start angle.
     *
     * @param arc An arc path object.
     * @returns End angle of arc.
     */
function ofArcEnd(arc: IPathArc): number;


/**
     * Get the angle in the middle of an arc's start and end angles.
     *
     * @param arc An arc path object.
     * @param ratio Optional number between 0 and 1 specifying percentage between start and end angles. Default is .5
     * @returns Middle angle of arc.
     */
function ofArcMiddle(arc: IPathArc, ratio?: number): number;


/**
     * Total angle of an arc between its start and end angles.
     *
     * @param arc The arc to measure.
     * @returns Angle of arc.
     */
function ofArcSpan(arc: IPathArc): number;


/**
     * Angle of a line path.
     *
     * @param line The line path to find the angle of.
     * @returns Angle of the line path, in degrees.
     */
function ofLineInDegrees(line: IPathLine): number;


/**
     * Angle of a line through a point, in degrees.
     *
     * @param pointToFindAngle The point to find the angle.
     * @param origin Point of origin of the angle.
     * @returns Angle of the line throught the point, in degrees.
     */
function ofPointInDegrees(origin: IPoint, pointToFindAngle: IPoint): number;


/**
     * Angle of a line through a point, in radians.
     *
     * @param pointToFindAngle The point to find the angle.
     * @param origin Point of origin of the angle.
     * @returns Angle of the line throught the point, in radians.
     */
function ofPointInRadians(origin: IPoint, pointToFindAngle: IPoint): number;


/**
     * Mirror an angle on either or both x and y axes.
     *
     * @param angleInDegrees The angle to mirror.
     * @param mirrorX Boolean to mirror on the x axis.
     * @param mirrorY Boolean to mirror on the y axis.
     * @returns Mirrored angle.
     */
function mirror(angleInDegrees: number, mirrorX: boolean, mirrorY: boolean): number;


/**
     * Add two points together and return the result as a new point object.
     *
     * @param a First point.
     * @param b Second point.
     * @param subtract Optional boolean to subtract instead of add.
     * @returns A new point object.
     */
function add(a: IPoint, b: IPoint, subtract?: boolean): IPoint;


/**
     * Get the average of two points.
     *
     * @param a First point.
     * @param b Second point.
     * @returns New point object which is the average of a and b.
     */
function average(a: IPoint, b: IPoint): IPoint;


/**
     * Clone a point into a new point.
     *
     * @param pointToClone The point to clone.
     * @returns A new point with same values as the original.
     */
function clone(pointToClone: IPoint): IPoint;


/**
     * From an array of points, find the closest point to a given reference point.
     *
     * @param referencePoint The reference point.
     * @param pointOptions Array of points to choose from.
     * @returns The first closest point from the pointOptions.
     */
function closest(referencePoint: IPoint, pointOptions: IPoint[]): IPoint;


/**
     * Get a point from its polar coordinates.
     *
     * @param angleInRadians The angle of the polar coordinate, in radians.
     * @param radius The radius of the polar coordinate.
     * @returns A new point object.
     */
function fromPolar(angleInRadians: number, radius: number): IPoint;


/**
     * Get a point on a circle or arc path, at a given angle.
     * @param angleInDegrees The angle at which you want to find the point, in degrees.
     * @param circle A circle or arc.
     * @returns A new point object.
     */
function fromAngleOnCircle(angleInDegrees: number, circle: IPathCircle): IPoint;


/**
     * Get the two end points of an arc path.
     *
     * @param arc The arc path object.
     * @returns Array with 2 elements: [0] is the point object corresponding to the start angle, [1] is the point object corresponding to the end angle.
     */
function fromArc(arc: IPathArc): IPoint[];


/**
     * Get the two end points of a path.
     *
     * @param pathContext The path object.
     * @returns Array with 2 elements: [0] is the point object corresponding to the origin, [1] is the point object corresponding to the end.
     */
function fromPathEnds(pathContext: IPath, pathOffset?: IPoint): IPoint[];


/**
     * Calculates the intersection of slopes of two lines.
     *
     * @param lineA First line to use for slope.
     * @param lineB Second line to use for slope.
     * @param options Optional IPathIntersectionOptions.
     * @returns point of intersection of the two slopes, or null if the slopes did not intersect.
     */
function fromSlopeIntersection(lineA: IPathLine, lineB: IPathLine, options?: IPathIntersectionBaseOptions): IPoint;


/**
     * Get the middle point of a path.
     *
     * @param pathContext The path object.
     * @param ratio Optional ratio (between 0 and 1) of point along the path. Default is .5 for middle.
     * @returns Point on the path, in the middle of the path.
     */
function middle(pathContext: IPath, ratio?: number): IPoint;


/**
     * Create a clone of a point, mirrored on either or both x and y axes.
     *
     * @param pointToMirror The point to mirror.
     * @param mirrorX Boolean to mirror on the x axis.
     * @param mirrorY Boolean to mirror on the y axis.
     * @returns Mirrored point.
     */
function mirror(pointToMirror: IPoint, mirrorX: boolean, mirrorY: boolean): IPoint;


/**
     * Round the values of a point.
     *
     * @param pointContext The point to serialize.
     * @param accuracy Optional exemplar number of decimal places.
     * @returns A new point with the values rounded.
     */
function rounded(pointContext: IPoint, accuracy?: number): IPoint;


/**
     * Rotate a point.
     *
     * @param pointToRotate The point to rotate.
     * @param angleInDegrees The amount of rotation, in degrees.
     * @param rotationOrigin The center point of rotation.
     * @returns A new point.
     */
function rotate(pointToRotate: IPoint, angleInDegrees: number, rotationOrigin: IPoint): IPoint;


/**
     * Scale a point's coordinates.
     *
     * @param pointToScale The point to scale.
     * @param scaleValue The amount of scaling.
     * @returns A new point.
     */
function scale(pointToScale: IPoint, scaleValue: number): IPoint;


/**
     * Distort a point's coordinates.
     *
     * @param pointToDistort The point to distort.
     * @param scaleX The amount of x scaling.
     * @param scaleY The amount of y scaling.
     * @returns A new point.
     */
function distort(pointToDistort: IPoint, scaleX: number, scaleY: number): IPoint;


/**
     * Subtract a point from another point, and return the result as a new point. Shortcut to Add(a, b, subtract = true).
     *
     * @param a First point.
     * @param b Second point.
     * @returns A new point object.
     */
function subtract(a: IPoint, b: IPoint): IPoint;


/**
     * A point at 0,0 coordinates.
     * NOTE: It is important to call this as a method, with the empty parentheses.
     *
     * @returns A new point.
     */
function zero(): IPoint;


/**
     * Create a clone of a path. This is faster than cloneObject.
     *
     * @param pathToClone The path to clone.
     * @returns Cloned path.
     */
function clone(pathToClone: IPath): IPath;


/**
     * Create a clone of a path, mirrored on either or both x and y axes.
     *
     * @param pathToMirror The path to mirror.
     * @param mirrorX Boolean to mirror on the x axis.
     * @param mirrorY Boolean to mirror on the y axis.
     * @returns Mirrored path.
     */
function mirror(pathToMirror: IPath, mirrorX: boolean, mirrorY: boolean): IPath;


/**
     * Move a path to an absolute point.
     *
     * @param pathToMove The path to move.
     * @param origin The new origin for the path.
     * @returns The original path (for chaining).
     */
function move(pathToMove: IPath, origin: IPoint): IPath;


/**
     * Move a path's origin by a relative amount.
     *
     * @param pathToMove The path to move.
     * @param delta The x & y adjustments as a point object.
     * @param subtract Optional boolean to subtract instead of add.
     * @returns The original path (for chaining).
     */
function moveRelative(pathToMove: IPath, delta: IPoint, subtract?: boolean): IPath;


/**
     * Move some paths relatively during a task execution, then unmove them.
     *
     * @param pathsToMove The paths to move.
     * @param deltas The x & y adjustments as a point object array.
     * @param task The function to call while the paths are temporarily moved.
     */
function moveTemporary(pathsToMove: IPath[], deltas: IPoint[], task: Function): void;


/**
     * Rotate a path.
     *
     * @param pathToRotate The path to rotate.
     * @param angleInDegrees The amount of rotation, in degrees.
     * @param rotationOrigin The center point of rotation.
     * @returns The original path (for chaining).
     */
function rotate(pathToRotate: IPath, angleInDegrees: number, rotationOrigin: IPoint): IPath;


/**
     * Scale a path.
     *
     * @param pathToScale The path to scale.
     * @param scaleValue The amount of scaling.
     * @returns The original path (for chaining).
     */
function scale(pathToScale: IPath, scaleValue: number): IPath;


/**
     * Distort a path - scale x and y individually.
     *
     * @param pathToDistort The path to distort.
     * @param scaleX The amount of x scaling.
     * @param scaleY The amount of y scaling.
     * @returns A new IModel (for circles and arcs) or IPath (for lines and bezier seeds).
     */
function distort(pathToDistort: IPath, scaleX: number, scaleY: number): IModel | IPath;


/**
     * Connect 2 lines at their slope intersection point.
     *
     * @param lineA First line to converge.
     * @param lineB Second line to converge.
     * @param useOriginA Optional flag to converge the origin point of lineA instead of the end point.
     * @param useOriginB Optional flag to converge the origin point of lineB instead of the end point.
     */
function converge(lineA: IPathLine, lineB: IPathLine, useOriginA?: boolean, useOriginB?: boolean): IPoint;


/**
     * Breaks a path in two. The supplied path will end at the supplied pointOfBreak,
     * a new path is returned which begins at the pointOfBreak and ends at the supplied path's initial end point.
     * For Circle, the original path will be converted in place to an Arc, and null is returned.
     *
     * @param pathToBreak The path to break.
     * @param pointOfBreak The point at which to break the path.
     * @returns A new path of the same type, when path type is line or arc. Returns null for circle.
     */
function breakAtPoint(pathToBreak: IPath, pointOfBreak: IPoint): IPath;


/**
     * Count the number of child models within a given model.
     *
     * @param modelContext The model containing other models.
     * @returns Number of child models.
     */
function countChildModels(modelContext: IModel): number;


/**
     * Get an unused id in the models map with the same prefix.
     *
     * @param modelContext The model containing the models map.
     * @param modelId The id to use directly (if unused), or as a prefix.
     */
function getSimilarModelId(modelContext: IModel, modelId: string): string;


/**
     * Get an unused id in the paths map with the same prefix.
     *
     * @param modelContext The model containing the paths map.
     * @param pathId The id to use directly (if unused), or as a prefix.
     */
function getSimilarPathId(modelContext: IModel, pathId: string): string;


/**
     * Moves all of a model's children (models and paths, recursively) in reference to a single common origin. Useful when points between children need to connect to each other.
     *
     * @param modelToOriginate The model to originate.
     * @param origin Optional offset reference point.
     */
function originate(modelToOriginate: IModel, origin?: IPoint): IModel;


/**
     * Create a clone of a model, mirrored on either or both x and y axes.
     *
     * @param modelToMirror The model to mirror.
     * @param mirrorX Boolean to mirror on the x axis.
     * @param mirrorY Boolean to mirror on the y axis.
     * @returns Mirrored model.
     */
function mirror(modelToMirror: IModel, mirrorX: boolean, mirrorY: boolean): IModel;


/**
     * Move a model to an absolute point. Note that this is also accomplished by directly setting the origin property. This function exists for chaining.
     *
     * @param modelToMove The model to move.
     * @param origin The new position of the model.
     * @returns The original model (for chaining).
     */
function move(modelToMove: IModel, origin: IPoint): IModel;


/**
     * Move a model's origin by a relative amount.
     *
     * @param modelToMove The model to move.
     * @param delta The x & y adjustments as a point object.
     * @returns The original model (for chaining).
     */
function moveRelative(modelToMove: IModel, delta: IPoint): IModel;


/**
     * Prefix the ids of paths in a model.
     *
     * @param modelToPrefix The model to prefix.
     * @param prefix The prefix to prepend on paths ids.
     * @returns The original model (for chaining).
     */
function prefixPathIds(modelToPrefix: IModel, prefix: string): IModel;


/**
     * Rotate a model.
     *
     * @param modelToRotate The model to rotate.
     * @param angleInDegrees The amount of rotation, in degrees.
     * @param rotationOrigin The center point of rotation.
     * @returns The original model (for chaining).
     */
function rotate(modelToRotate: IModel, angleInDegrees: number, rotationOrigin: IPoint): IModel;


/**
     * Scale a model.
     *
     * @param modelToScale The model to scale.
     * @param scaleValue The amount of scaling.
     * @param scaleOrigin Optional boolean to scale the origin point. Typically false for the root model.
     * @returns The original model (for chaining).
     */
function scale(modelToScale: IModel, scaleValue: number, scaleOrigin?: boolean): IModel;


/**
     * Convert a model to match a different unit system.
     *
     * @param modeltoConvert The model to convert.
     * @param destUnitType The unit system.
     * @returns The scaled model (for chaining).
     */
function convertUnits(modeltoConvert: IModel, destUnitType: string): IModel;


/**
     * Recursively walk through all paths for a given model.
     *
     * @param modelContext The model to walk.
     * @param callback Callback for each path.
     */
function walkPaths(modelContext: IModel, callback: IModelPathCallback): void;


/**
     * Recursively walk through all paths for a given model.
     *
     * @param modelContext The model to walk.
     * @param pathCallback Callback for each path.
     * @param modelCallbackBeforeWalk Callback for each model prior to recursion, which can cancel the recursion if it returns false.
     * @param modelCallbackAfterWalk Callback for each model after recursion.
     */
function walk(modelContext: IModel, options: IWalkOptions): void;


/**
     * Check to see if a path is inside of a model.
     *
     * @param pathContext The path to check.
     * @param modelContext The model to check against.
     * @param farPoint Optional point of reference which is outside the bounds of the modelContext.
     * @returns Boolean true if the path is inside of the modelContext.
     */
function isPathInsideModel(pathContext: IPath, modelContext: IModel, pathOffset?: IPoint, farPoint?: IPoint, measureAtlas?: measure.Atlas): boolean;


/**
     * Break a model's paths everywhere they intersect with another path.
     *
     * @param modelToBreak The model containing paths to be broken.
     * @param modelToIntersect Optional model containing paths to look for intersection, or else the modelToBreak will be used.
     */
function breakPathsAtIntersections(modelToBreak: IModel, modelToIntersect?: IModel): void;


/**
     * Combine 2 models.
     *
     * @param modelA First model to combine.
     * @param modelB Second model to combine.
     * @param includeAInsideB Flag to include paths from modelA which are inside of modelB.
     * @param includeAOutsideB Flag to include paths from modelA which are outside of modelB.
     * @param includeBInsideA Flag to include paths from modelB which are inside of modelA.
     * @param includeBOutsideA Flag to include paths from modelB which are outside of modelA.
     * @param keepDuplicates Flag to include paths which are duplicate in both models.
     * @param farPoint Optional point of reference which is outside the bounds of both models.
     */
function combine(modelA: IModel, modelB: IModel, includeAInsideB?: boolean, includeAOutsideB?: boolean, includeBInsideA?: boolean, includeBOutsideA?: boolean, options?: ICombineOptions): void;


/**
     * Combine 2 models, resulting in a intersection.
     *
     * @param modelA First model to combine.
     * @param modelB Second model to combine.
     */
function combineIntersection(modelA: IModel, modelB: IModel): void;


/**
     * Combine 2 models, resulting in a subtraction of B from A.
     *
     * @param modelA First model to combine.
     * @param modelB Second model to combine.
     */
function combineSubtraction(modelA: IModel, modelB: IModel): void;


/**
     * Combine 2 models, resulting in a union.
     *
     * @param modelA First model to combine.
     * @param modelB Second model to combine.
     */
function combineUnion(modelA: IModel, modelB: IModel): void;


/**
     * Simplify a model's paths by reducing redundancy: combine multiple overlapping paths into a single path. The model must be originated.
     *
     * @param modelContext The originated model to search for similar paths.
     * @param options Optional options object.
     * @returns The simplified model (for chaining).
     */
function simplify(modelToSimplify: IModel, options?: ISimplifyOptions): IModel;


/**
     * Expand path by creating a model which surrounds it.
     *
     * @param pathToExpand Path to expand.
     * @param expansion Distance to expand.
     * @param isolateCaps Optional flag to put the end caps into a separate model named "caps".
     * @returns Model which surrounds the path.
     */
function expand(pathToExpand: IPath, expansion: number, isolateCaps?: boolean): IModel;


/**
     * Represent an arc using straight lines.
     *
     * @param arc Arc to straighten.
     * @param bevel Optional flag to bevel the angle to prevent it from being too sharp.
     * @param prefix Optional prefix to apply to path ids.
     * @returns Model of straight lines with same endpoints as the arc.
     */
function straighten(arc: IPathArc, bevel?: boolean, prefix?: string): IModel;


/**
     * Expand all paths in a model, then combine the resulting expansions.
     *
     * @param modelToExpand Model to expand.
     * @param distance Distance to expand.
     * @param joints Number of points at a joint between paths. Use 0 for round joints, 1 for pointed joints, 2 for beveled joints.
     * @returns Model which surrounds the paths of the original model.
     */
function expandPaths(modelToExpand: IModel, distance: number, joints?: number, combineOptions?: ICombineOptions): IModel;


/**
     * Outline a model by a specified distance. Useful for accommodating for kerf.
     *
     * @param modelToOutline Model to outline.
     * @param distance Distance to outline.
     * @param joints Number of points at a joint between paths. Use 0 for round joints, 1 for pointed joints, 2 for beveled joints.
     * @param inside Optional boolean to draw lines inside the model instead of outside.
     * @returns Model which surrounds the paths outside of the original model.
     */
function outline(modelToOutline: IModel, distance: number, joints?: number, inside?: boolean): IModel;


/**
     * Get a conversion ratio between a source unit and a destination unit.
     *
     * @param srcUnitType unitType converting from.
     * @param destUnitType unitType converting to.
     * @returns Numeric ratio of the conversion.
     */
function conversionScale(srcUnitType: string, destUnitType: string): number;


/**
     * Find out if two angles are equal.
     *
     * @param angleA First angle.
     * @param angleB Second angle.
     * @returns true if angles are the same, false if they are not
     */
function isAngleEqual(angleA: number, angleB: number, accuracy?: number): boolean;


/**
     * Find out if two paths are equal.
     *
     * @param pathA First path.
     * @param pathB Second path.
     * @returns true if paths are the same, false if they are not
     */
function isPathEqual(pathA: IPath, pathB: IPath, withinPointDistance?: number, pathAOffset?: IPoint, pathBOffset?: IPoint): boolean;


/**
     * Find out if two points are equal.
     *
     * @param a First point.
     * @param b Second point.
     * @returns true if points are the same, false if they are not
     */
function isPointEqual(a: IPoint, b: IPoint, withinDistance?: number): boolean;


/**
     * Find out if point is on a slope.
     *
     * @param p Point to check.
     * @param b Slope.
     * @returns true if point is on the slope
     */
function isPointOnSlope(p: IPoint, slope: ISlope, withinDistance?: number): boolean;


/**
     * Check for slope equality.
     *
     * @param slopeA The ISlope to test.
     * @param slopeB The ISlope to check for equality.
     * @returns Boolean true if slopes are equal.
     */
function isSlopeEqual(slopeA: ISlope, slopeB: ISlope): boolean;


/**
     * Increase a measurement by an additional measurement.
     *
     * @param baseMeasure The measurement to increase.
     * @param addMeasure The additional measurement.
     * @param addOffset Optional offset point of the additional measurement.
     * @returns The increased original measurement (for chaining).
     */
function increase(baseMeasure: IMeasure, addMeasure: IMeasure): IMeasure;


/**
     * Check for arc being concave or convex towards a given point.
     *
     * @param arc The arc to test.
     * @param towardsPoint The point to test.
     * @returns Boolean true if arc is concave towards point.
     */
function isArcConcaveTowardsPoint(arc: IPathArc, towardsPoint: IPoint): boolean;


/**
     * Check for arc overlapping another arc.
     *
     * @param arcA The arc to test.
     * @param arcB The arc to check for overlap.
     * @param excludeTangents Boolean to exclude exact endpoints and only look for deep overlaps.
     * @returns Boolean true if arc1 is overlapped with arcB.
     */
function isArcOverlapping(arcA: IPathArc, arcB: IPathArc, excludeTangents: boolean): boolean;


/**
     * Check if a given number is between two given limits.
     *
     * @param valueInQuestion The number to test.
     * @param limitA First limit.
     * @param limitB Second limit.
     * @param exclusive Flag to exclude equaling the limits.
     * @returns Boolean true if value is between (or equal to) the limits.
     */
function isBetween(valueInQuestion: number, limitA: number, limitB: number, exclusive: boolean): boolean;


/**
     * Check if a given angle is between an arc's start and end angles.
     *
     * @param angleInQuestion The angle to test.
     * @param arc Arc to test against.
     * @param exclusive Flag to exclude equaling the start or end angles.
     * @returns Boolean true if angle is between (or equal to) the arc's start and end angles.
     */
function isBetweenArcAngles(angleInQuestion: number, arc: IPathArc, exclusive: boolean): boolean;


/**
     * Check if a given point is between a line's end points.
     *
     * @param pointInQuestion The point to test.
     * @param line Line to test against.
     * @param exclusive Flag to exclude equaling the origin or end points.
     * @returns Boolean true if point is between (or equal to) the line's origin and end points.
     */
function isBetweenPoints(pointInQuestion: IPoint, line: IPathLine, exclusive: boolean): boolean;


/**
     * Check if a given bezier seed is simply a line.
     *
     * @param seed The bezier seed to test.
     * @returns Boolean true if bezier seed has control points on the line slope and between the line endpoints.
     */
function isBezierSeedLinear(seed: IPathBezierSeed): boolean;


/**
     * Check for line overlapping another line.
     *
     * @param lineA The line to test.
     * @param lineB The line to check for overlap.
     * @param excludeTangents Boolean to exclude exact endpoints and only look for deep overlaps.
     * @returns Boolean true if line1 is overlapped with lineB.
     */
function isLineOverlapping(lineA: IPathLine, lineB: IPathLine, excludeTangents: boolean): boolean;


/**
     * Check for measurement overlapping another measurement.
     *
     * @param measureA The measurement to test.
     * @param measureB The measurement to check for overlap.
     * @returns Boolean true if measure1 is overlapped with measureB.
     */
function isMeasurementOverlapping(measureA: IMeasure, measureB: IMeasure): boolean;


/**
     * Gets the slope of a line.
     */
function lineSlope(line: IPathLine): ISlope;


/**
     * Calculates the distance between two points.
     *
     * @param a First point.
     * @param b Second point.
     * @returns Distance between points.
     */
function pointDistance(a: IPoint, b: IPoint): number;


/**
     * Calculates the smallest rectangle which contains a path.
     *
     * @param pathToMeasure The path to measure.
     * @returns object with low and high points.
     */
function pathExtents(pathToMeasure: IPath, addOffset?: IPoint): IMeasure;


/**
     * Measures the length of a path.
     *
     * @param pathToMeasure The path to measure.
     * @returns Length of the path.
     */
function pathLength(pathToMeasure: IPath): number;


/**
     * Measures the smallest rectangle which contains a model.
     *
     * @param modelToMeasure The model to measure.
     * @param atlas Optional atlas to save measurements.
     * @returns object with low and high points.
     */
function modelExtents(modelToMeasure: IModel, atlas?: measure.Atlas): IMeasure;


/**
     * Try to get the unit system from a model
     * @private
     */
function tryGetModelUnits(itemToExport: any): string;


/**
     * Create a numeric array from a string of numbers. The numbers may be delimited by anything non-numeric.
     *
     * Example:
     * ```
     * var n = makerjs.importer.parseNumericList('5, 10, 15.20 25-30-35 4e1 .5');
     * ```
     *
     * @param s The string of numbers.
     * @returns Array of numbers.
     */
function parseNumericList(s: string): number[];


function toDXF(modelToExport: IModel, options?: IDXFRenderOptions): string;


function toDXF(pathsToExport: IPath[], options?: IDXFRenderOptions): string;


function toDXF(pathToExport: IPath, options?: IDXFRenderOptions): string;


/**
     * Solves for the angle of a triangle when you know lengths of 3 sides.
     *
     * @param lengthA Length of side of triangle, opposite of the angle you are trying to find.
     * @param lengthB Length of any other side of the triangle.
     * @param lengthC Length of the remaining side of the triangle.
     * @returns Angle opposite of the side represented by the first parameter.
     */
function solveTriangleSSS(lengthA: number, lengthB: number, lengthC: number): number;


/**
     * Solves for the length of a side of a triangle when you know length of one side and 2 angles.
     *
     * @param oppositeAngleInDegrees Angle which is opposite of the side you are trying to find.
     * @param lengthOfSideBetweenAngles Length of one side of the triangle which is between the provided angles.
     * @param otherAngleInDegrees An other angle of the triangle.
     * @returns Length of the side of the triangle which is opposite of the first angle parameter.
     */
function solveTriangleASA(oppositeAngleInDegrees: number, lengthOfSideBetweenAngles: number, otherAngleInDegrees: number): number;


/**
     * Find the point(s) where 2 paths intersect.
     *
     * @param path1 First path to find intersection.
     * @param path2 Second path to find intersection.
     * @param options Optional IPathIntersectionOptions.
     * @returns IPathIntersection object, with points(s) of intersection (and angles, when a path is an arc or circle); or null if the paths did not intersect.
     */
function intersection(path1: IPath, path2: IPath, options?: IPathIntersectionOptions): IPathIntersection;


/**
     * Adds a round corner to the outside angle between 2 lines. The lines must meet at one point.
     *
     * @param lineA First line to fillet, which will be modified to fit the fillet.
     * @param lineB Second line to fillet, which will be modified to fit the fillet.
     * @returns Arc path object of the new fillet.
     */
function dogbone(lineA: IPathLine, lineB: IPathLine, filletRadius: number, options?: IPointMatchOptions): IPathArc;


/**
     * Adds a round corner to the inside angle between 2 paths. The paths must meet at one point.
     *
     * @param pathA First path to fillet, which will be modified to fit the fillet.
     * @param pathB Second path to fillet, which will be modified to fit the fillet.
     * @returns Arc path object of the new fillet.
     */
function fillet(pathA: IPath, pathB: IPath, filletRadius: number, options?: IPointMatchOptions): IPathArc;


/**
     * Helper function to use the JavaScript "apply" function in conjunction with the "new" keyword.
     *
     * @param ctor The constructor for the class which is an IKit.
     * @param args The array of parameters passed to the constructor.
     * @returns A new instance of the class, which implements the IModel interface.
     */
function construct(ctor: IKit, args: any): IModel;


/**
     * Extract just the initial sample values from a kit.
     *
     * @param ctor The constructor for the class which is an IKit.
     * @returns Array of the inital sample values provided in the metaParameters array.
     */
function getParameterValues(ctor: IKit): any[];


/**
     * Find paths that have common endpoints and form chains.
     *
     * @param modelContext The model to search for chains.
     * @param options Optional options object.
     */
function findChains(modelContext: IModel, callback: IChainCallback, options?: IFindChainsOptions): void;


/**
     * Find paths that have common endpoints and form loops.
     *
     * @param modelContext The model to search for loops.
     * @param options Optional options object.
     * @returns A new model with child models ranked according to their containment within other found loops. The paths of models will be IPathDirectionalWithPrimeContext.
     */
function findLoops(modelContext: IModel, options?: IFindLoopsOptions): IModel;


/**
     * Remove all paths in a loop model from the model(s) which contained them.
     *
     * @param loopToDetach The model to search for loops.
     */
function detachLoop(loopToDetach: IModel): void;


/**
     * Remove paths from a model which have endpoints that do not connect to other paths.
     *
     * @param modelContext The model to search for dead ends.
     * @param options Optional options object.
     * @returns The input model (for chaining).
     */
function removeDeadEnds(modelContext: IModel, pointMatchingDistance?: any, keep?: IWalkPathBooleanCallback): IModel;


function toOpenJsCad(modelToExport: IModel, options?: IOpenJsCadOptions): string;


function toOpenJsCad(pathsToExport: IPath[], options?: IOpenJsCadOptions): string;


function toOpenJsCad(pathToExport: IPath, options?: IOpenJsCadOptions): string;


/**
     * Executes a JavaScript string with the OpenJsCad engine - converts 2D to 3D.
     *
     * @param modelToExport Model object to export.
     * @param options Export options object.
     * @param options.extrusion Height of 3D extrusion.
     * @param options.resolution Size of facets.
     * @returns String of STL format of 3D object.
     */
function toSTL(modelToExport: IModel, options?: IOpenJsCadOptions): string;


/**
     * Injects drawing into a PDFKit document.
     *
     * @param modelToExport Model object to export.
     * @param options Export options object.
     * @returns String of PDF file contents.
     */
function toPDF(doc: PDFKit.PDFDocument, modelToExport: IModel, options?: IPDFRenderOptions): void;


/**
     * Convert a chain to SVG path data.
     */
function chainToSVGPathData(chain: IChain, offset: IPoint, scale: number): string;


/**
     * Convert a path to SVG path data.
     */
function pathToSVGPathData(pathToExport: IPath, offset: IPoint, offset2: IPoint, scale: number): string;


function toSVG(modelToExport: IModel, options?: ISVGRenderOptions): string;


function toSVG(pathsToExport: IPath[], options?: ISVGRenderOptions): string;


function toSVG(pathToExport: IPath, options?: ISVGRenderOptions): string;


function fromSVGPathData(pathData: string): IModel;


/**
     * Class for arc path.
     */
class Arc implements IPathArc {
        origin: IPoint;
        radius: number;
        startAngle: number;
        endAngle: number;
        type: string;
        /**
         * Class for arc path, created from origin point, radius, start angle, and end angle.
         *
         * @param origin The center point of the arc.
         * @param radius The radius of the arc.
         * @param startAngle The start angle of the arc.
         * @param endAngle The end angle of the arc.
         */
        constructor(origin: IPoint, radius: number, startAngle: number, endAngle: number);
        /**
         * Class for arc path, created from 2 points, radius, large Arc flag, and clockwise flag.
         *
         * @param pointA First end point of the arc.
         * @param pointB Second end point of the arc.
         * @param radius The radius of the arc.
         * @param largeArc Boolean flag to indicate clockwise direction.
         * @param clockwise Boolean flag to indicate clockwise direction.
         */
        constructor(pointA: IPoint, pointB: IPoint, radius: number, largeArc: boolean, clockwise: boolean);
        /**
         * Class for arc path, created from 2 points and optional boolean flag indicating clockwise.
         *
         * @param pointA First end point of the arc.
         * @param pointB Second end point of the arc.
         * @param clockwise Boolean flag to indicate clockwise direction.
         */
        constructor(pointA: IPoint, pointB: IPoint, clockwise?: boolean);
        /**
         * Class for arc path, created from 3 points.
         *
         * @param pointA First end point of the arc.
         * @param pointB Middle point on the arc.
         * @param pointC Second end point of the arc.
         */
        constructor(pointA: IPoint, pointB: IPoint, pointC: IPoint);
    }


/**
     * Class for circle path.
     */
class Circle implements IPathCircle {
        type: string;
        origin: IPoint;
        radius: number;
        /**
         * Class for circle path, created from radius. Origin will be [0, 0].
         *
         * Example:
         * ```
         * var c = new makerjs.paths.Circle(7);
         * ```
         *
         * @param radius The radius of the circle.
         */
        constructor(radius: number);
        /**
         * Class for circle path, created from origin point and radius.
         *
         * Example:
         * ```
         * var c = new makerjs.paths.Circle([10, 10], 7);
         * ```
         *
         * @param origin The center point of the circle.
         * @param radius The radius of the circle.
         */
        constructor(origin: IPoint, radius: number);
        /**
         * Class for circle path, created from 2 points.
         *
         * Example:
         * ```
         * var c = new makerjs.paths.Circle([5, 15], [25, 15]);
         * ```
         *
         * @param pointA First point on the circle.
         * @param pointB Second point on the circle.
         */
        constructor(pointA: IPoint, pointB: IPoint);
        /**
         * Class for circle path, created from 3 points.
         *
         * Example:
         * ```
         * var c = new makerjs.paths.Circle([0, 0], [0, 10], [20, 0]);
         * ```
         *
         * @param pointA First point on the circle.
         * @param pointB Second point on the circle.
         * @param pointC Third point on the circle.
         */
        constructor(pointA: IPoint, pointB: IPoint, pointC: IPoint);
    }


/**
     * Class for line path.
     */
class Line implements IPathLine {
        type: string;
        origin: IPoint;
        end: IPoint;
        /**
         * Class for line path, constructed from array of 2 points.
         *
         * @param points Array of 2 points.
         */
        constructor(points: IPoint[]);
        /**
         * Class for line path, constructed from 2 points.
         *
         * @param origin The origin point of the line.
         * @param end The end point of the line.
         */
        constructor(origin: IPoint, end: IPoint);
    }


/**
     * Class for chord, which is simply a line path that connects the endpoints of an arc.
     *
     * @param arc Arc to use as the basic for the chord.
     */
class Chord implements IPathLine {
        type: string;
        origin: IPoint;
        end: IPoint;
        constructor(arc: IPathArc);
    }


/**
     * Class for a parallel line path.
     *
     * @param toLine A line to be parallel to.
     * @param distance Distance between parallel and original line.
     * @param nearPoint Any point to determine which side of the line to place the parallel.
     */
class Parallel implements IPathLine {
        type: string;
        origin: IPoint;
        end: IPoint;
        constructor(toLine: IPathLine, distance: number, nearPoint: IPoint);
    }


/**
     * Collects items that share a common key.
     */
class Collector<K, T> {
        private comparer;
        collections: ICollection<K, T>[];
        constructor(comparer?: ICollectionKeyComparer<K>);
        addItemToCollection(key: K, item: T): void;
        findCollection(key: K, action?: (index: number) => void): T[];
        removeCollection(key: K): boolean;
        removeItemFromCollection(key: K, item: T): boolean;
        getCollectionsOfMultiple(cb: (key: K, items: T[]) => void): void;
    }


/**
     * A list of maps of measurements.
     *
     * @param modelToMeasure The model to measure.
     * @param atlas Optional atlas to save measurements.
     * @returns object with low and high points.
     */
class Atlas {
        modelContext: IModel;
        /**
         * Flag that models have been measured.
         */
        modelsMeasured: boolean;
        /**
         * Map of model measurements, mapped by routeKey.
         */
        modelMap: IMeasureMap;
        /**
         * Map of path measurements, mapped by routeKey.
         */
        pathMap: IMeasureMap;
        /**
         * Constructor.
         * @param modelContext The model to measure.
         */
        constructor(modelContext: IModel);
        measureModels(): void;
    }


/**
     * Class to traverse an item 's models or paths and ultimately render each path.
     * @private
     */
class Exporter {
        private map;
        private fixPoint;
        private fixPath;
        private beginModel;
        private endModel;
        /**
         * @param map Object containing properties: property name is the type of path, e.g. "line", "circle"; property value
         * is a function to render a path. Function parameters are path and point.
         * @param fixPoint Optional function to modify a point prior to export. Function parameter is a point; function must return a point.
         * @param fixPath Optional function to modify a path prior to output. Function parameters are path and offset point; function must return a path.
         */
        constructor(map: IPathOriginFunctionMap, fixPoint?: (pointToFix: IPoint) => IPoint, fixPath?: (pathToFix: IPath, origin: IPoint) => IPath, beginModel?: (id: string, modelContext: IModel) => void, endModel?: (modelContext: IModel) => void);
        /**
         * Export a path.
         *
         * @param pathToExport The path to export.
         * @param offset The offset position of the path.
         */
        exportPath(id: string, pathToExport: IPath, offset: IPoint, layer: string): void;
        /**
         * Export a model.
         *
         * @param modelToExport The model to export.
         * @param offset The offset position of the model.
         */
        exportModel(modelId: string, modelToExport: IModel, offset: IPoint): void;
        /**
         * Export an object.
         *
         * @param item The object to export. May be a path, an array of paths, a model, or an array of models.
         * @param offset The offset position of the object.
         */
        exportItem(itemId: string, itemToExport: any, origin: IPoint): void;
    }


/**
     * Class for an XML tag.
     * @private
     */
class XmlTag {
        name: string;
        attrs: IXmlTagAttrs;
        /**
         * Text between the opening and closing tags.
         */
        innerText: string;
        /**
         * Boolean to indicate that the innerText has been escaped.
         */
        innerTextEscaped: boolean;
        /**
         * Escapes certain characters within a string so that it can appear in a tag or its attribute.
         *
         * @returns Escaped string.
         */
        static escapeString(value: string): string;
        /**
         * @param name Name of the XML tag.
         * @param attrs Optional attributes for the tag.
         */
        constructor(name: string, attrs?: IXmlTagAttrs);
        /**
         * Get the opening tag.
         *
         * @param selfClose Flag to determine if opening tag should be self closing.
         */
        getOpeningTag(selfClose: boolean): string;
        /**
         * Get the inner text.
         */
        getInnerText(): string;
        /**
         * Get the closing tag.
         */
        getClosingTag(): string;
        /**
         * Output the entire tag as a string.
         */
        toString(): string;
    }


class BezierCurve implements IModel {
        models: IModelMap;
        paths: IPathMap;
        origin: IPoint;
        type: string;
        seed: IPathBezierSeed;
        accuracy: number;
        constructor(points: IPoint[], accuracy?: number);
        constructor(seed: IPathBezierSeed, accuracy?: number);
        constructor(seed: IPathBezierSeed, isChild: boolean, accuracy?: number);
        constructor(origin: IPoint, control: IPoint, end: IPoint, accuracy?: number);
        constructor(origin: IPoint, controls: IPoint[], end: IPoint, accuracy?: number);
        constructor(origin: IPoint, control1: IPoint, control2: IPoint, end: IPoint, accuracy?: number);
        static typeName: string;
        static getBezierSeeds(curve: BezierCurve, options?: IFindChainsOptions): IPathBezierSeed[];
        static computePoint(seed: IPathBezierSeed, t: number): IPoint;
    }


class Ellipse implements IModel {
        models: IModelMap;
        origin: IPoint;
        /**
         * Class for Ellipse created with 2 radii.
         *
         * @param radiusX The x radius of the ellipse.
         * @param radiusY The y radius of the ellipse.
         * @param accuracy Optional accuracy of the underlying BezierCurve.
         */
        constructor(radiusX: number, radiusY: number, accuracy?: number);
        /**
         * Class for Ellipse created at a specific origin and 2 radii.
         *
         * @param origin The center of the ellipse.
         * @param radiusX The x radius of the ellipse.
         * @param radiusY The y radius of the ellipse.
         * @param accuracy Optional accuracy of the underlying BezierCurve.
         */
        constructor(origin: IPoint, radiusX: number, radiusY: number, accuracy?: number);
        /**
         * Class for Ellipse created at a specific x, y and 2 radii.
         *
         * @param cx The x coordinate of the center of the ellipse.
         * @param cy The y coordinate of the center of the ellipse.
         * @param rX The x radius of the ellipse.
         * @param rY The y radius of the ellipse.
         * @param accuracy Optional accuracy of the underlying BezierCurve.
         */
        constructor(cx: number, cy: number, rx: number, ry: number, accuracy?: number);
    }


class EllipticArc implements IModel {
        models: IModelMap;
        /**
         * Class for Elliptic Arc created by distorting a circular arc.
         *
         * @param arc The circular arc to use as the basis of the elliptic arc.
         * @param radiusX The x radius of the ellipse.
         * @param radiusY The y radius of the ellipse.
         * @param accuracy Optional accuracy of the underlying BezierCurve.
         */
        constructor(startAngle: number, endAngle: number, radiusX: number, radiusY: number, accuracy?: number);
        /**
         * Class for Elliptic Arc created by distorting a circular arc.
         *
         * @param arc The circular arc to use as the basis of the elliptic arc.
         * @param distortX The x scale of the ellipse.
         * @param distortY The y scale of the ellipse.
         * @param accuracy Optional accuracy of the underlying BezierCurve.
         */
        constructor(arc: IPathArc, distortX: number, distortY: number, accuracy?: number);
    }


class ConnectTheDots implements IModel {
        paths: IPathMap;
        /**
         * Create a model by connecting points designated in a string. The model will be 'closed' - i.e. the last point will connect to the first point.
         *
         * Example:
         * ```
         * var c = new makerjs.models.ConnectTheDots('-10 0 10 0 0 20'); // 3 coordinates to form a triangle
         * ```
         *
         * @param numericList String containing a list of numbers which can be delimited by spaces, commas, or anything non-numeric (Note: [exponential notation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toExponential) is allowed).
         */
        constructor(numericList: string);
        /**
         * Create a model by connecting points designated in a numeric array. The model will be 'closed' - i.e. the last point will connect to the first point.
         *
         * Example:
         * ```
         * var c = new makerjs.models.ConnectTheDots([-10, 0, 10, 0, 0, 20]); // 3 coordinates to form a triangle
         * ```
         *
         * @param coords Array of coordinates.
         */
        constructor(coords: number[]);
        /**
         * Create a model by connecting points designated in an array of points. The model may be closed, or left open.
         *
         * Example:
         * ```
         * var c = new makerjs.models.ConnectTheDots(false, [[-10, 0], [10, 0], [0, 20]]); // 3 coordinates left open
         * ```
         *
         * @param isClosed Flag to specify if last point should connect to the first point.
         * @param points Array of IPoints.
         */
        constructor(isClosed: boolean, points: IPoint[]);
    }


class Polygon implements IModel {
        paths: IPathMap;
        constructor(numberOfSides: number, radius: number, firstCornerAngleInDegrees?: number, circumscribed?: boolean);
        static circumscribedRadius(radius: number, angleInRadians: number): number;
        static getPoints(numberOfSides: number, radius: number, firstCornerAngleInDegrees?: number, circumscribed?: boolean): IPoint[];
    }


class BoltCircle implements IModel {
        paths: IPathMap;
        constructor(boltRadius: number, holeRadius: number, boltCount: number, firstBoltAngleInDegrees?: number);
    }


class BoltRectangle implements IModel {
        paths: IPathMap;
        constructor(width: number, height: number, holeRadius: number);
    }


class Dome implements IModel {
        paths: IPathMap;
        constructor(width: number, height: number, radius?: number);
    }