text: // @flow
  import typeof {
    MAGDECK,
    TEMPDECK,
    THERMOCYCLER,
    MAGNETIC_MODULE_V1,
    MAGNETIC_MODULE_V2,
    TEMPERATURE_MODULE_V1,
    TEMPERATURE_MODULE_V2,
    THERMOCYCLER_MODULE_V1,
    MAGNETIC_MODULE_TYPE,
    TEMPERATURE_MODULE_TYPE,
    THERMOCYCLER_MODULE_TYPE,
    GEN1,
    GEN2,
  } from './constants'
  // TODO Ian 2019-06-04 split this out into eg ../labware/flowTypes/labwareV1.js
  export type WellDefinition = {
    diameter?: number, // NOTE: presence of diameter indicates a circular well
    depth?: number, // TODO Ian 2018-03-12: depth should be required, but is missing in MALDI-plate
    height: number,
    length: number,
    width: number,
    x: number,
    y: number,
    z: number,
    'total-liquid-volume': number,
  }
  
  // typedef for labware definitions under v1 labware schema
  export type LabwareDefinition1 = {
    metadata: {
      name: string,
      format: string,
      deprecated?: boolean,
      displayName?: string,
      displayCategory?: string,
      isValidSource?: boolean,
      isTiprack?: boolean,
      tipVolume?: number,
    },
    ordering: Array<Array<string>>,
    wells: {
      [well: string]: WellDefinition,
    },
  }
  
  // TODO(mc, 2019-05-29): Remove this enum in favor of string + exported
  // constants + unit tests to catch typos in our definitions. Make changes
  // here and in shared-data/labware/schemas/2.json
  export type LabwareDisplayCategory =
    | 'wellPlate'
    | 'tipRack'
    | 'tubeRack'
    | 'reservoir'
    | 'aluminumBlock'
    | 'trash'
    | 'other'
  
  export type LabwareVolumeUnits = 'µL' | 'mL' | 'L'
  
  // TODO(mc, 2019-05-29): Remove this enum in favor of string + exported
  // constants + unit tests to catch typos in our definitions. Make changes
  // here and in shared-data/labware/schemas/2.json
  export type WellBottomShape = 'flat' | 'u' | 'v'
  
  export type LabwareMetadata = {|
    displayName: string,
    displayCategory: LabwareDisplayCategory,
    displayVolumeUnits: LabwareVolumeUnits,
    tags?: Array<string>,
  |}
  
  export type LabwareDimensions = {|
    xDimension: number,
    yDimension: number,
    zDimension: number,
  |}
  
  export type LabwareOffset = {|
    x: number,
    y: number,
    z: number,
  |}
  
  // 1. Valid pipette type for a container (i.e. is there multi channel access?)
  // 2. Is the container a tiprack?
  export type LabwareParameters = {|
    loadName: string,
    format: string,
    isTiprack: boolean,
    tipLength?: number,
    isMagneticModuleCompatible: boolean,
    magneticModuleEngageHeight?: number,
    quirks?: Array<string>,
  |}
  
  export type LabwareBrand = {|
    brand: string,
    brandId?: Array<string>,
    links?: Array<string>,
  |}
  
  export type LabwareWellShapeProperties =
    | {|
        shape: 'circular',
        diameter: number,
      |}
    | {|
        shape: 'rectangular',
        xDimension: number,
        yDimension: number,
      |}
  
  // well without x,y,z
  export type LabwareWellProperties = {|
    ...LabwareWellShapeProperties,
    depth: number,
    totalLiquidVolume: number,
  |}
  
  export type LabwareWell = {|
    ...LabwareWellProperties,
    x: number,
    y: number,
    z: number,
  |}
  
  // TODO(mc, 2019-03-21): exact object is tough to use with the initial value in
  // reduce, so leaving this inexact (e.g. `const a: {||} = {}` errors)
  export type LabwareWellMap = {
    [wellName: string]: LabwareWell,
  }
  
  export type LabwareWellGroupMetadata = {|
    displayName?: string,
    displayCategory?: LabwareDisplayCategory,
    wellBottomShape?: WellBottomShape,
  |}
  
  export type LabwareWellGroup = {|
    wells: Array<string>,
    metadata: LabwareWellGroupMetadata,
    brand?: LabwareBrand,
  |}
  
  // NOTE: must be synced with shared-data/labware/schemas/2.json
  export type LabwareDefinition2 = {|
    version: number,
    schemaVersion: 2,
    namespace: string,
    metadata: LabwareMetadata,
    dimensions: LabwareDimensions,
    cornerOffsetFromSlot: LabwareOffset,
    parameters: LabwareParameters,
    brand: LabwareBrand,
    ordering: Array<Array<string>>,
    wells: LabwareWellMap,
    groups: Array<LabwareWellGroup>,
  |}
  
  // Module Type corresponds to `moduleType` key in a module definition. Is NOT model.
  // TODO: IL 2020-02-20 ModuleType is DEPRECATED. Replace all instances with ModuleRealType
  // (then finally rename ModuleRealType -> ModuleType)
  export type ModuleType = MAGDECK | TEMPDECK | THERMOCYCLER
  export type ModuleRealType =
    | MAGNETIC_MODULE_TYPE
    | TEMPERATURE_MODULE_TYPE
    | THERMOCYCLER_MODULE_TYPE
  
  // ModuleModel corresponds to top-level keys in shared-data/module/definitions/2
  
  export type MagneticModuleModel = MAGNETIC_MODULE_V1 | MAGNETIC_MODULE_V2
  export type TemperatureModuleModel =
    | TEMPERATURE_MODULE_V1
    | TEMPERATURE_MODULE_V2
  export type ThermocyclerModuleModel = THERMOCYCLER_MODULE_V1
  
  export type ModuleModel =
    | MagneticModuleModel
    | TemperatureModuleModel
    | ThermocyclerModuleModel
  
  export type ModuleModelWithLegacy =
    | ModuleModel
    | THERMOCYCLER
    | MAGDECK
    | TEMPDECK
  
  export type DeckOffset = {|
    x: number,
    y: number,
    z: number,
  |}
  
  export type Dimensions = {|
    xDimension: number,
    yDimension: number,
    zDimension: number,
  |}
  
  export type DeckRobot = {|
    model: string,
  |}
  
  export type DeckFixture = {|
    id: string,
    slot: string,
    labware: string,
    displayName: string,
  |}
  
  export type CoordinateTuple = [number, number, number]
  
  export type UnitDirection = 1 | -1
  export type UnitVectorTuple = [UnitDirection, UnitDirection, UnitDirection]
  
  export type DeckSlotId = string
  
  export type DeckSlot = {|
    id: DeckSlotId,
    position: CoordinateTuple,
    matingSurfaceUnitVector?: UnitVectorTuple,
    boundingBox: Dimensions,
    displayName: string,
    compatibleModules: Array<ModuleType>,
  |}
  export type DeckCalibrationPoint = {|
    id: string,
    position: CoordinateTuple,
    displayName: string,
  |}
  export type DeckLocations = {|
    orderedSlots: Array<DeckSlot>,
    calibrationPoints: Array<DeckCalibrationPoint>,
    fixtures: Array<DeckFixture>,
  |}
  
  export type DeckMetadata = {|
    displayName: string,
    tags: Array<string>,
  |}
  
  export type DeckLayerFeature = {|
    footprint: string,
  |}
  
  export type DeckLayer = Array<DeckLayerFeature>
  
  export type DeckDefinition = {|
    otId: string,
    cornerOffsetFromOrigin: CoordinateTuple,
    dimensions: CoordinateTuple,
    robot: DeckRobot,
    locations: DeckLocations,
    metadata: DeckMetadata,
    layers: { [string]: DeckLayer },
  |}
  
  export type ModuleDimensions = {|
    bareOverallHeight: number,
    overLabwareHeight: number,
    lidHeight: number,
  |}
  
  export type ModuleCalibrationPoint = {|
    x: number,
    y: number,
    z?: number,
  |}
  
  export type ModuleDefinition = {|
    labwareOffset: LabwareOffset,
    dimensions: ModuleDimensions,
    calibrationPoint: ModuleCalibrationPoint,
    displayName: string,
    loadName: string,
    quirks: Array<string>,
  |}
  
  export type PipetteChannels = 1 | 8
  
  export type PipetteDisplayCategory = GEN1 | GEN2
  
  export type FlowRateSpec = {|
    value: number,
    min: number,
    max: number,
  |}
  
  export type PipetteNameSpecs = {|
    name: string,
    displayName: string,
    displayCategory: PipetteDisplayCategory,
    minVolume: number,
    maxVolume: number,
    channels: PipetteChannels,
    defaultAspirateFlowRate: FlowRateSpec,
    defaultDispenseFlowRate: FlowRateSpec,
    defaultBlowOutFlowRate: FlowRateSpec,
    defaultTipracks: Array<string>,
    smoothieConfigs?: {|
      stepsPerMM: number,
      homePosition: number,
      travelDistance: number,
    |},
  |}
  
  // TODO(mc, 2019-10-14): update this type according to the schema
  export type PipetteModelSpecs = {
    ...PipetteNameSpecs,
    model: string,
    backCompatNames?: Array<string>,
    tipLength: { value: number },
    ...
  }
  