() => {
            return request(testServer)
                .post('/api/classes/' + TESTCLASS + '/students/studentid/projects/' + projectid + '/images')
                .attach('image', './src/tests/utils/resources/test-02.jpg')
                .expect(httpStatus.BAD_REQUEST)
                .then((res) => {
                    assert.deepStrictEqual(res.body, { error : 'Image label not provided' });
                });
        }


(res) => {
                    assert.deepStrictEqual(res.body, { error : 'Image label not provided' });
                }


async () => {
            const project = await store.storeProject('studentid', TESTCLASS, 'text', 'invalid', 'en', [], false);
            return request(testServer)
                .post('/api/classes/' + TESTCLASS + '/students/studentid/projects/' + project.id + '/images')
                .attach('image', './src/tests/utils/resources/test-04.jpg')
                .expect(httpStatus.BAD_REQUEST)
                .then((res) => {
                    assert.deepStrictEqual(res.body, { error : 'Only images projects allow image uploads' });
                });
        }


(res) => {
                    assert.deepStrictEqual(res.body, { error : 'Only images projects allow image uploads' });
                }


() => {
            return request(testServer)
                .post('/api/classes/' + TESTCLASS + '/students/studentid/projects/' + projectid + '/images')
                .attach('image', './src/tests/utils/resources/test-02.jpg')
                .field('label', 'MYSTERY')
                .expect(httpStatus.BAD_REQUEST)
                .then((res) => {
                    assert.deepStrictEqual(res.body, { error : 'Unrecognised label' });
                });
        }


(res) => {
                    assert.deepStrictEqual(res.body, { error : 'Unrecognised label' });
                }


() => {
        it('should upload a file', async () => {
            const USER = 'TESTSTUDENT';
            const LABEL = 'testlabel';
            const project = await store.storeProject(USER, TESTCLASS, 'images', 'test uploads', 'en', [], false);
            await store.addLabelToProject(USER, TESTCLASS, project.id, LABEL);

            const IMAGESURL = '/api/classes/' + TESTCLASS +
                                '/students/' + USER +
                                '/projects/' + project.id +
                                '/images';

            NEXT_USERID = USER;

            return request(testServer)
                .post(IMAGESURL)
                .attach('image', './src/tests/utils/resources/test-01.jpg')
                .field('label', LABEL)
                .expect(httpStatus.CREATED)
                .then((res) => {
                    assert(res.body.id);

                    assert.strictEqual(res.body.isstored, true);
                    assert.strictEqual(res.body.label, LABEL);
                    assert.strictEqual(res.body.projectid, project.id);

                    assert(res.body.imageurl.startsWith(IMAGESURL));

                    assert.strictEqual(res.body.imageurl, IMAGESURL + '/' + res.body.id);

                    assert(res.header.etag);

                    return store.deleteTraining('images', 'TESTPROJECT', res.body.id);
                });
        });

    }


async () => {
            const USER = 'TESTSTUDENT';
            const LABEL = 'testlabel';
            const project = await store.storeProject(USER, TESTCLASS, 'images', 'test uploads', 'en', [], false);
            await store.addLabelToProject(USER, TESTCLASS, project.id, LABEL);

            const IMAGESURL = '/api/classes/' + TESTCLASS +
                                '/students/' + USER +
                                '/projects/' + project.id +
                                '/images';

            NEXT_USERID = USER;

            return request(testServer)
                .post(IMAGESURL)
                .attach('image', './src/tests/utils/resources/test-01.jpg')
                .field('label', LABEL)
                .expect(httpStatus.CREATED)
                .then((res) => {
                    assert(res.body.id);

                    assert.strictEqual(res.body.isstored, true);
                    assert.strictEqual(res.body.label, LABEL);
                    assert.strictEqual(res.body.projectid, project.id);

                    assert(res.body.imageurl.startsWith(IMAGESURL));

                    assert.strictEqual(res.body.imageurl, IMAGESURL + '/' + res.body.id);

                    assert(res.header.etag);

                    return store.deleteTraining('images', 'TESTPROJECT', res.body.id);
                });
        }


(res) => {
                    assert(res.body.id);

                    assert.strictEqual(res.body.isstored, true);
                    assert.strictEqual(res.body.label, LABEL);
                    assert.strictEqual(res.body.projectid, project.id);

                    assert(res.body.imageurl.startsWith(IMAGESURL));

                    assert.strictEqual(res.body.imageurl, IMAGESURL + '/' + res.body.id);

                    assert(res.header.etag);

                    return store.deleteTraining('images', 'TESTPROJECT', res.body.id);
                }


() => {

        let projectid = '';

        before(() => {
            return store.storeProject('studentid', TESTCLASS, 'images', 'invalids', 'en', [], false)
                .then((proj) => {
                    projectid = proj.id;
                });
        });

        it('should handle non-existent images', () => {
            return request(testServer)
                .get('/api/classes/' + TESTCLASS + '/students/studentid/projects/' + projectid + '/images/someimageid')
                .expect(httpStatus.NOT_FOUND)
                .then((res) => {
                    assert.deepStrictEqual(res.body, { error : 'File not found' });
                });
        });
    }


() => {
            return store.storeProject('studentid', TESTCLASS, 'images', 'invalids', 'en', [], false)
                .then((proj) => {
                    projectid = proj.id;
                });
        }


(proj) => {
                    projectid = proj.id;
                }


() => {
            return request(testServer)
                .get('/api/classes/' + TESTCLASS + '/students/studentid/projects/' + projectid + '/images/someimageid')
                .expect(httpStatus.NOT_FOUND)
                .then((res) => {
                    assert.deepStrictEqual(res.body, { error : 'File not found' });
                });
        }


(res) => {
                    assert.deepStrictEqual(res.body, { error : 'File not found' });
                }


() => {

        function readFileToBuffer(path: string) {
            return new Promise((resolve, reject) => {
                fs.readFile(path, (err, data) => {
                    if (err) {
                        return reject(err);
                    }
                    return resolve(data);
                });
            });
        }

        it('should download a file', async () => {
            let id;
            const filepath = './src/tests/utils/resources/test-01.jpg';
            const contents = await readFileToBuffer(filepath);

            const userid = uuid();

            const project = await store.storeProject(userid, TESTCLASS, 'images', 'valid', 'en', [], false);
            const projectid = project.id;

            const label = 'testlabel';
            await store.addLabelToProject(userid, TESTCLASS, projectid, label);

            NEXT_USERID = userid;

            const imagesurl = '/api/classes/' + TESTCLASS +
                                '/students/' + userid +
                                '/projects/' + projectid +
                                '/images';

            await request(testServer)
                .post(imagesurl)
                .attach('image', filepath)
                .field('label', label)
                .expect(httpStatus.CREATED)
                .then((res) => {
                    assert(res.body.id);
                    id = res.body.id;

                    assert.strictEqual(res.body.projectid, projectid);
                });

            await request(testServer)
                .get(imagesurl + '/' + id)
                .expect(httpStatus.OK)
                .then((res) => {
                    assert.deepStrictEqual(res.body, contents);
                    assert.strictEqual(res.header['content-type'], 'image/jpeg');
                    assert.strictEqual(res.header['cache-control'], 'max-age=31536000');
                });

            if (id) {
                return store.deleteTraining('images', projectid, id);
            }
        });

    }


(resolve, reject) => {
                fs.readFile(path, (err, data) => {
                    if (err) {
                        return reject(err);
                    }
                    return resolve(data);
                });
            }


(err, data) => {
                    if (err) {
                        return reject(err);
                    }
                    return resolve(data);
                }


async () => {
            let id;
            const filepath = './src/tests/utils/resources/test-01.jpg';
            const contents = await readFileToBuffer(filepath);

            const userid = uuid();

            const project = await store.storeProject(userid, TESTCLASS, 'images', 'valid', 'en', [], false);
            const projectid = project.id;

            const label = 'testlabel';
            await store.addLabelToProject(userid, TESTCLASS, projectid, label);

            NEXT_USERID = userid;

            const imagesurl = '/api/classes/' + TESTCLASS +
                                '/students/' + userid +
                                '/projects/' + projectid +
                                '/images';

            await request(testServer)
                .post(imagesurl)
                .attach('image', filepath)
                .field('label', label)
                .expect(httpStatus.CREATED)
                .then((res) => {
                    assert(res.body.id);
                    id = res.body.id;

                    assert.strictEqual(res.body.projectid, projectid);
                });

            await request(testServer)
                .get(imagesurl + '/' + id)
                .expect(httpStatus.OK)
                .then((res) => {
                    assert.deepStrictEqual(res.body, contents);
                    assert.strictEqual(res.header['content-type'], 'image/jpeg');
                    assert.strictEqual(res.header['cache-control'], 'max-age=31536000');
                });

            if (id) {
                return store.deleteTraining('images', projectid, id);
            }
        }


(res) => {
                    assert(res.body.id);
                    id = res.body.id;

                    assert.strictEqual(res.body.projectid, projectid);
                }


(res) => {
                    assert.deepStrictEqual(res.body, contents);
                    assert.strictEqual(res.header['content-type'], 'image/jpeg');
                    assert.strictEqual(res.header['cache-control'], 'max-age=31536000');
                }


() => UserService


@Controller('user')
export class UserController {
  constructor(
    @Inject(forwardRef(() => UserService))
    private readonly userService: UserService,
  ) {}

  @Post()
  create(@Body() createUserDto: CreateUserDto) {
    return this.userService.create(createUserDto);
  }

  @Get('getByEmail')
  getUserByEmail(@Param('email') email: string) {
    return this.userService.getUserByEmail(email);
  }

  @Get()
  findAll() {
    return this.userService.findAll();
  }

  @Get('/:id')
  findById(@Param('id') id: string) {
    return this.userService.getById(id);
  }

  @Patch(':id')
  update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
    return this.userService.update(id, updateUserDto);
  }

  @Delete(':id')
  remove(@Param('id') id: string) {
    return this.userService.remove(id);
  }
  @Post('/join-to-room')
  async joinToRoom(
    @Body('userId') userId: string,
    @Body('roomId') roomId: string,
  ) {
    return this.userService.joinToRoom(userId, roomId);
  }

  @Post('/leave-from-room')
  async leaveFromRoom(@Body('userId') userId: string): Promise<IUser> {
    return this.userService.leaveFromRoom(userId);
  }

  @Get('/room/:roomId')
  getAllUsersFromRoom(@Param('roomId') roomId: string): Promise<IUser[]> {
    return this.userService.getAllUsersFromRoom(roomId);
  }
}


@Post()
  create(@Body() createUserDto: CreateUserDto) {
    return this.userService.create(createUserDto);
  }


@Get('getByEmail')
  getUserByEmail(@Param('email') email: string) {
    return this.userService.getUserByEmail(email);
  }


@Get()
  findAll() {
    return this.userService.findAll();
  }


@Get('/:id')
  findById(@Param('id') id: string) {
    return this.userService.getById(id);
  }


@Patch(':id')
  update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
    return this.userService.update(id, updateUserDto);
  }


@Delete(':id')
  remove(@Param('id') id: string) {
    return this.userService.remove(id);
  }


@Post('/join-to-room')
  async joinToRoom(
    @Body('userId') userId: string,
    @Body('roomId') roomId: string,
  ) {
    return this.userService.joinToRoom(userId, roomId);
  }


@Post('/leave-from-room')
  async leaveFromRoom(@Body('userId') userId: string): Promise<IUser> {
    return this.userService.leaveFromRoom(userId);
  }


@Get('/room/:roomId')
  getAllUsersFromRoom(@Param('roomId') roomId: string): Promise<IUser[]> {
    return this.userService.getAllUsersFromRoom(roomId);
  }


props => {
  const {
    defaultVisibled = true,
    className,
    forwardedRef,
    wrapperClassName,
    innerClassName
  } = props;

  const [visibled, setVisibled] = useState(defaultVisibled);

  return (
    <Input
      {...props}
      ref={forwardedRef}
      className={classNames(baseCls, className)}
      wrapperClassName={classNames(
        getPrefixCls('wrapper', baseCls),
        wrapperClassName


(props, ref) => {
  return <Password {...props} forwardedRef={ref} />;
}


export interface IPasswordProps extends IInputProps {
  /** 默认可见 */
  defaultVisibled?: boolean;
}


interface IForwardRefProps extends IPasswordProps {
  forwardedRef?: React.Ref<any>;
}


classNames(baseCls, className)


classNames(
        getPrefixCls


getPrefixCls('toggle', baseCls)


function Image(props: ImageProps) {
  const { src, ratio, ...other } = props;
  return (
    <Box
      {...other}
      sx={{
        position: 'relative',
        '& div': {
          paddingTop: `${Math.round(ratio * 100)}%`,
        },
        '& img': {
          position: 'absolute',
          top: 0,
          left: 0,
          width: '100%',
          height: '100%',
          objectFit: 'cover',
        },
        ...other.sx,
      }}


function BrandingHero() {
  return (
    <Container>
      <Typography variant="h1" align="center" sx={{ mt: 9, mx: 'auto' }}


function BrandingKPI() {
  return (
    <Grid container spacing={1} sx={{ mb: { md: 15 } }}


function BrandingMission() {
  return (
    <Box sx={{ position: 'relative' }}


function BrandingVision() {
  return (
    <Container sx={{ my: 15 }}


function BrandingTeam() {
  return (
    <Box sx={{ bgcolor: 'greyF3', pt: 15, pb: 10 }}


function BrandingCompany() {
  return (
    <Box sx={{ bgcolor: 'greyEA', pt: 12, pb: 11 }}


function BrandingContributors() {
  return (
    <Box sx={{ bgcolor: 'greyF3', pt: 10, pb: 9 }}


function BrandingEmeriti() {
  return (
    <Box sx={{ bgcolor: 'greyEA', pt: 10, pb: 9 }}


function BrandingJoinUs() {
  return (
    <Box
      sx={{
        bgcolor: 'secondary.main',
        color: 'secondary.contrastText',
        overflow: 'hidden',
      }}


function BrandingSupportUs() {
  return (
    <Container sx={{ mt: [10, 18], mb: [12, 20] }}


export default function Page() {
  return (
    <BrandingRoot>
      <Head
        title="About Us - Material-UI"
        description="Material-UI started back in 2014 to unify React and Material Design. Today, Material-UI has grown to become one of the world's most popular React libraries – used by a vibrant community of more than 2M developers in over 180 countries."
      />
      <BrandingHeader />
      <BrandingHero />
      <BrandingKPI />
      <BrandingMission />
      <BrandingVision />
      <BrandingTeam />
      <BrandingCompany />
      <BrandingContributors />
      <BrandingEmeriti />
      <BrandingJoinUs />
      <BrandingSupportUs />
      <BrandingDiscoverMore />
      <BrandingBeginToday />
    </BrandingRoot>
  );
}


(member) => (
            <Grid item


interface ImageProps {
  src: string;
  ratio: number;
  sx?: BoxProps['sx'];
}


() => `

                  Can't find your data?

                    You may be looking for the
                    GDC Legacy Archive.

                  Data in the GDC Data Portal
                  has been harmonized using GDC Bioinformatics Pipelines whereas data in the
                  GDC Legacy Archive is an unmodified copy of data that was previously stored
                  in CGHub and in the TCGA Data Portal hosted by the TCGA Data Coordinating Center (DCC).
                  Certain previously available data types and formats are not currently supported by
                  the GDC Data Portal and are only distributed via the GDC Legacy Archive.

                  Check the Data Release Notes for additional details.

            `


class HeaderController implements IHeaderController {
    bannerDismissed: boolean;
    isCollapsed: boolean = true;
    currentLang: string = "en";
    addedLanguages: boolean = false;
    languages: any = {
      "en": "English",
      "fr": "French",
      "es": "Spanish"
    };
    cookieEnabled: any;

    /* @ngInject */
    constructor(
      private gettextCatalog,
      private CartService: ICartService,
      private $state: ng.ui.IStateService,
      private UserService: IUserService,
      private $uibModal: any,
      private $window: ng.IWindowService,
      private $rootScope: ngApp.IRootScope,
      private $uibModalStack,
      private config: any,
      private CoreService: ngApp.core.services.ICoreService
    ) {
      // this.config = this.CoreService.getComponentFromConfig('navbar');
      this.config = $rootScope.config;

      this.addedLanguages = !!_.keys(gettextCatalog.strings).length;
      this.cookieEnabled = navigator.cookieEnabled;
      this.bannerDismissed = true;
    }

    getToken(): void {
      this.UserService.getToken();
    }

    collapse(event: any): void {
      if (event.which === 1 || event.which === 13) {
        this.isCollapsed = true;
      }
    }

    toggleCollapsed(): void {
      this.isCollapsed = !this.isCollapsed;
    }

    setLanguage(): void {
      this.gettextCatalog.setCurrentLanguage(this.currentLang);
    }

    shouldShowOption(option: string): boolean {
      var showOption = true,
          currentState = (<any>_).get(this.$state, 'current.name', '').toLowerCase();

      switch(option.toLowerCase()) {
        case 'quick-search':
          if (currentState === 'home') {
            showOption = false;
          }
          break;
        case 'my-projects':
          if (currentState === 'home') {
            showOption = false;
          }
          break;
        default:
          break;
      }

      return showOption;
    }

    dismissBanner(): void {
      this.bannerDismissed = true;
      this.$rootScope.$emit('hideBanner');
    }

    showBannerModal(): void {
      if (!this.$uibModalStack.getTop()) {
        this.$uibModal.open({
          templateUrl: "core/templates/modal.html",
          controller: "WarningController",
          controllerAs: "wc",
          backdrop: "static",
          keyboard: false,
          backdropClass: "warning-backdrop",
          animation: false,
          size: "lg",
          windowClass: "banner-modal",
          resolve: {
            warning: () => `

                  Can't find your data?

                    You may be looking for the
                    GDC Legacy Archive.

                  Data in the GDC Data Portal
                  has been harmonized using GDC Bioinformatics Pipelines whereas data in the
                  GDC Legacy Archive is an unmodified copy of data that was previously stored
                  in CGHub and in the TCGA Data Portal hosted by the TCGA Data Coordinating Center (DCC).
                  Certain previously available data types and formats are not currently supported by
                  the GDC Data Portal and are only distributed via the GDC Legacy Archive.

                  Check the Data Release Notes for additional details.

            `,
            header: null
          }
        });
      }
    }

  }


export interface IHeaderController {
    bannerDismissed: boolean;
    isCollapsed: boolean;
    currentLang: string;
    addedLanguages: boolean;
    languages: any;
    cookieEnabled: any;

    getToken(): void;
    collapse(event: any): void;
    toggleCollapsed(): void;
    setLanguage(): void;
    shouldShowOption(option: string): boolean;
    dismissBanner(): void;
    showBannerModal(): void;
    // getNumCartItems(): number;
  }


getToken(): void {
      this.UserService.getToken();
    }


collapse(event: any): void {
      if (event.which === 1 || event.which === 13) {
        this.isCollapsed = true;
      }
    }


toggleCollapsed(): void {
      this.isCollapsed = !this.isCollapsed;
    }


setLanguage(): void {
      this.gettextCatalog.setCurrentLanguage(this.currentLang);
    }


shouldShowOption(option: string): boolean {
      var showOption = true,
          currentState = (<any>_).get(this.$state, 'current.name', '').toLowerCase();

      switch(option.toLowerCase()) {
        case 'quick-search':
          if (currentState === 'home') {
            showOption = false;
          }
          break;
        case 'my-projects':
          if (currentState === 'home') {
            showOption = false;
          }
          break;
        default:
          break;
      }

      return showOption;
    }


dismissBanner(): void {
      this.bannerDismissed = true;
      this.$rootScope.$emit('hideBanner');
    }


showBannerModal(): void {
      if (!this.$uibModalStack.getTop()) {
        this.$uibModal.open({
          templateUrl: "core/templates/modal.html",
          controller: "WarningController",
          controllerAs: "wc",
          backdrop: "static",
          keyboard: false,
          backdropClass: "warning-backdrop",
          animation: false,
          size: "lg",
          windowClass: "banner-modal",
          resolve: {
            warning: () => `

                  Can't find your data?

                    You may be looking for the
                    GDC Legacy Archive.

                  Data in the GDC Data Portal
                  has been harmonized using GDC Bioinformatics Pipelines whereas data in the
                  GDC Legacy Archive is an unmodified copy of data that was previously stored
                  in CGHub and in the TCGA Data Portal hosted by the TCGA Data Coordinating Center (DCC).
                  Certain previously available data types and formats are not currently supported by
                  the GDC Data Portal and are only distributed via the GDC Legacy Archive.

                  Check the Data Release Notes for additional details.

            `,
            header: null
          }
        });
      }
    }


({ iconUrl, onOpen, name, onDragStart }: Props) => {
  const ref = useRef<HTMLDivElement>(null);
  const [selected, setSelected] = useState(false);

  useEffect(() => {
    if (!selected) {
      return;
    }
    const handleClick = (e: MouseEvent) => {
      if (ref.current != null && ref.current.contains(e.target as Element)) {
        return;
      }
      setSelected(false);
    };
    document.addEventListener("click", handleClick);
    return () => document.removeEventListener("click", handleClick);
  }, [selected]);

  return (
    <div
      ref={ref}
      onDoubleClick={()


() => {
    if (!selected) {
      return;
    }
    const handleClick = (e: MouseEvent) => {
      if (ref.current != null && ref.current.contains(e.target as Element)) {
        return;
      }
      setSelected(false);
    };
    document.addEventListener("click", handleClick);
    return () => document.removeEventListener("click", handleClick);
  }


(e: MouseEvent) => {
      if (ref.current != null && ref.current.contains(e.target as Element)) {
        return;
      }
      setSelected(false);
    }


() => document.removeEventListener("click", handleClick)


interface Props {
  iconUrl: string;
  name: string;
  onOpen: () => void;
  onDragStart?: (e: React.DragEvent<HTMLDivElement>) => void;
}


classnames("desktop-icon", { selected })


(_, {defaultRender}) => {
      return defaultRender(_);
    }


(_, record) => (
      <Space>
        {record.labels.map(({name, color}) => (
          <Tag color={color} key={name}>
            {name}
          </Tag>
        ))}
      </Space>
    )


({name, color}) => (
          <Tag color={color}


(value) => {
        return {
          startTime: value[0],
          endTime: value[1],
        };
      }


(text, record, _, action) => [
      <a
        key="editable"
        onClick={()


() => {
  const actionRef = useRef<ActionType>();
  return (
    <PageContainer title={false}>
      <ProTable<GithubIssueItem, API.PageParams>
        columns={columns}
        actionRef={actionRef}
        cardBordered
        request={async (params = {}, sort, filter)


(values, type) => {
            if (type === 'get') {
              return {
                ...values,
                created_at: [values.startTime, values.endTime],
              };
            }
            return values;
          }


(page) => console.log(page)


type GithubIssueItem = {
  url: string;
  id: number;
  number: number;
  title: string;
  labels: {
    name: string;
    color: string;
  }[];
  state: string;
  comments: number;
  created_at: string;
  updated_at: string;
  closed_at?: string;
};


async (params = {}, sort, filter)


function requireHID(install?: boolean): any {
    if (HID) return HID;
    return HID = nodeutil.lazyRequire("node-hid", install);
}


export function isInstalled(info?: boolean): boolean {
    return !!requireHID(!!info);
}


export function listAsync() {
    if (!requireHID(true))
        return Promise.resolve();
    return getHF2DevicesAsync()
        .then(devices => {
            pxt.log(`found ${devices.length} HID devices`);
            devices.forEach(device => pxt.log(device));
        })
}


export function serialAsync() {
    if (!requireHID(true))
        return Promise.resolve();
    return initAsync()
        .then(d => {
            d.autoReconnect = true
            connectSerial(d)
        })
}


export function dmesgAsync() {
    return initAsync()
        .then(d => d.talkAsync(pxt.HF2.HF2_CMD_DMESG)
            .then(resp => {
                console.log(U.fromUTF8(U.uint8ArrayToString(resp)))
                return d.disconnectAsync()
            }))
}


function hex(n: number) {
    return ("000" + n.toString(16)).slice(-4)
}


export function deviceInfo(h: HidDevice) {
    return `${h.product} (by ${h.manufacturer} at USB ${hex(h.vendorId)}:${hex(h.productId)})`
}


function getHF2Devices(): HidDevice[] {
    const hid = requireHID(false);
    if (!hid) return [];
    let devices = hid.devices() as HidDevice[]
    for (let d of devices) {
        pxt.debug(JSON.stringify(d))
    }
    let serial = pxt.appTarget.serial
    return devices.filter(d =>
        (serial && parseInt(serial.productId) == d.productId && parseInt(serial.vendorId) == d.vendorId) ||
        (d.release & 0xff00) == 0x4200)
}


export function getHF2DevicesAsync(): Promise<HidDevice[]> {
    return Promise.resolve(getHF2Devices());
}


export function hf2ConnectAsync(path: string, raw = false) {
    if (!requireHID(true)) return Promise.resolve(undefined);
    // in .then() to make sure we catch errors
    let h = new HF2.Wrapper(new HidIO(path))
    h.rawMode = raw
    return h.reconnectAsync(true).then(() => h)
}


export function mkPacketIOAsync() {
    return Promise.resolve()
        .then(() => {
            // in .then() to make sure we catch errors
            return new HidIO(null)
        })
}


export function initAsync(path: string = null): Promise<HF2.Wrapper> {
    if (!hf2Dev) {
        hf2Dev = hf2ConnectAsync(path)
    }
    return hf2Dev
}


export function connectSerial(w: HF2.Wrapper) {
    process.stdin.on("data", (buf: Buffer) => {
        w.sendSerialAsync(new Uint8Array(buf)).done()
    })
    w.onSerial = (arr, iserr) => {
        let buf = new Buffer(arr)
        if (iserr) process.stderr.write(buf)
        else process.stdout.write(buf)
    }
}


devices => {
            pxt.log(`found ${devices.length} HID devices`);
            devices.forEach(device => pxt.log(device));
        }


device => pxt.log(device)


d => {
            d.autoReconnect = true
            connectSerial(d)
        }


d => d.talkAsync(pxt.HF2.HF2_CMD_DMESG)
            .then(resp => {
                console.log(U.fromUTF8(U.uint8ArrayToString(resp)))
                return d.disconnectAsync()
            })


resp => {
                console.log(U.fromUTF8(U.uint8ArrayToString(resp)))
                return d.disconnectAsync()
            }


d =>
        (serial && parseInt(serial.productId) == d.productId && parseInt(serial.vendorId) == d.vendorId) ||
        (d.release & 0xff00) == 0x4200


() => h


() => {
            // in .then() to make sure we catch errors
            return new HidIO(null)
        }


(buf: Buffer) => {
        w.sendSerialAsync(new Uint8Array(buf)).done()
    }


(arr, iserr) => {
        let buf = new Buffer(arr)
        if (iserr) process.stderr.write(buf)
        else process.stdout.write(buf)
    }


(v: Uint8Array) => { }


(e: Error) => { }


(v: Buffer) => {
            //console.log("got", v.toString("hex"))
            this.onData(new Uint8Array(v))
        }


(v: Error) => this.onError(v)


() => {
                let lst = [0]
                for (let i = 0; i < Math.max(64, pkt.length); ++i)
                    lst.push(pkt[i] || 0)
                this.dev.write(lst)
            }


e => { }


() => {
                if (this.dev) {
                    this.dev.close()
                    this.dev = null
                }
            }


() => {
                this.connect()
            }


export class HIDError extends Error {
    constructor(m: string) {
        super(m)
        this.message = m
    }
}


export class HidIO implements HF2.PacketIO {
    dev: any;
    private path: string;

    onData = (v: Uint8Array) => { };
    onEvent = (v: Uint8Array) => { };
    onError = (e: Error) => { };

    constructor(private requestedPath: string) {
        this.connect()
    }

    private connect() {
        U.assert(requireHID(false))
        if (this.requestedPath == null) {
            let devs = getHF2Devices()
            if (devs.length == 0)
                throw new HIDError("no devices found")
            this.path = devs[0].path
        } else {
            this.path = this.requestedPath
        }

        this.dev = new HID.HID(this.path)
        this.dev.on("data", (v: Buffer) => {
            //console.log("got", v.toString("hex"))
            this.onData(new Uint8Array(v))
        })
        this.dev.on("error", (v: Error) => this.onError(v))
    }

    sendPacketAsync(pkt: Uint8Array): Promise<void> {
        //console.log("SEND: " + new Buffer(pkt).toString("hex"))
        return Promise.resolve()
            .then(() => {
                let lst = [0]
                for (let i = 0; i < Math.max(64, pkt.length); ++i)
                    lst.push(pkt[i] || 0)
                this.dev.write(lst)
            })
    }

    error(msg: string): any {
        let fullmsg = "HID error on " + this.path + ": " + msg
        console.error(fullmsg)
        throw new HIDError(fullmsg)
    }

    disconnectAsync(): Promise<void> {
        if (!this.dev) return Promise.resolve()

        // see https://github.com/node-hid/node-hid/issues/61
        this.dev.removeAllListeners("data");
        this.dev.removeAllListeners("error");
        let pkt = new Uint8Array([0x48])
        this.sendPacketAsync(pkt).catch(e => { })
        return Promise.delay(100)
            .then(() => {
                if (this.dev) {
                    this.dev.close()
                    this.dev = null
                }
            })
    }

    reconnectAsync(): Promise<void> {
        return this.disconnectAsync()
            .then(() => {
                this.connect()
            })
    }
}


export interface HidDevice {
    vendorId: number; // 9025,
    productId: number; // 589,
    path: string; //.../UF2-HID@...
    serialNumber: string; // '',
    manufacturer: string; // 'Arduino',
    product: string; // 'Zero',
    release: number; // 0x4201
}


private connect() {
        U.assert(requireHID(false))
        if (this.requestedPath == null) {
            let devs = getHF2Devices()
            if (devs.length == 0)
                throw new HIDError("no devices found")
            this.path = devs[0].path
        } else {
            this.path = this.requestedPath
        }

        this.dev = new HID.HID(this.path)
        this.dev.on("data", (v: Buffer) => {
            //console.log("got", v.toString("hex"))
            this.onData(new Uint8Array(v))
        })
        this.dev.on("error", (v: Error) => this.onError(v))
    }


sendPacketAsync(pkt: Uint8Array): Promise<void> {
        //console.log("SEND: " + new Buffer(pkt).toString("hex"))
        return Promise.resolve()
            .then(() => {
                let lst = [0]
                for (let i = 0; i < Math.max(64, pkt.length); ++i)
                    lst.push(pkt[i] || 0)
                this.dev.write(lst)
            })
    }


error(msg: string): any {
        let fullmsg = "HID error on " + this.path + ": " + msg
        console.error(fullmsg)
        throw new HIDError(fullmsg)
    }


disconnectAsync(): Promise<void> {
        if (!this.dev) return Promise.resolve()

        // see https://github.com/node-hid/node-hid/issues/61
        this.dev.removeAllListeners("data");
        this.dev.removeAllListeners("error");
        let pkt = new Uint8Array([0x48])
        this.sendPacketAsync(pkt).catch(e => { })
        return Promise.delay(100)
            .then(() => {
                if (this.dev) {
                    this.dev.close()
                    this.dev = null
                }
            })
    }


reconnectAsync(): Promise<void> {
        return this.disconnectAsync()
            .then(() => {
                this.connect()
            })
    }


async (resolve, reject) => {
            try {
                const mocha = this._createMocha()
                this._setupFiles(mocha)
                mocha.run((failures: any) => {
                    resolve(failures ? 1 : 0)
                })
            } catch(e) {
                console.error(e)
                resolve(1)
            }
        }


(failures: any) => {
                    resolve(failures ? 1 : 0)
                }


path => {
                return path.endsWith("test.js")
            }


path => {
                mocha.addFile(path)
            }


export class Testing {

    static _instance: Testing

    _target: string
    _conversation: Conversation
    _report: string

    constructor(conversation: Conversation, target: string, report: string) {
        this._conversation = conversation
        this._target = target
        this._report = report
    }

    static createInstance(conversation: Conversation, target: string, report: string): Testing {
        if (!Testing._instance) {
            Testing._instance = new Testing(conversation, target, report)
        }
        return Testing._instance
    }

    static getInstance(): Testing {
        return Testing._instance
    }

    async start(): Promise<number> {
        return new Promise<number>(async (resolve, reject) => {
            try {
                const mocha = this._createMocha()
                this._setupFiles(mocha)
                mocha.run((failures: any) => {
                    resolve(failures ? 1 : 0)
                })
            } catch(e) {
                console.error(e)
                resolve(1)
            }
        })
    }

    _createMocha(): any {
        return new Mocha({
            timeout: 10000,
            reporter: this._report,
        })
    }

    _setupFiles(mocha: any): void {
        const resolvedPath = path.resolve(this._target)
        if (fs.statSync(resolvedPath).isDirectory()) {
            fs.readdirSync(resolvedPath).filter(path => {
                return path.endsWith("test.js")
            }).forEach(path => {
                mocha.addFile(path)
            })
        } else {
            mocha.addFile(resolvedPath)
        }
    }

    static getConversation(): Conversation {
        return Testing.getInstance()._conversation
    }

}


static createInstance(conversation: Conversation, target: string, report: string): Testing {
        if (!Testing._instance) {
            Testing._instance = new Testing(conversation, target, report)
        }
        return Testing._instance
    }


static getInstance(): Testing {
        return Testing._instance
    }


async start(): Promise<number> {
        return new Promise<number>(async (resolve, reject) => {
            try {
                const mocha = this._createMocha()
                this._setupFiles(mocha)
                mocha.run((failures: any) => {
                    resolve(failures ? 1 : 0)
                })
            } catch(e) {
                console.error(e)
                resolve(1)
            }
        })
    }


_createMocha(): any {
        return new Mocha({
            timeout: 10000,
            reporter: this._report,
        })
    }


_setupFiles(mocha: any): void {
        const resolvedPath = path.resolve(this._target)
        if (fs.statSync(resolvedPath).isDirectory()) {
            fs.readdirSync(resolvedPath).filter(path => {
                return path.endsWith("test.js")
            }).forEach(path => {
                mocha.addFile(path)
            })
        } else {
            mocha.addFile(resolvedPath)
        }
    }


static getConversation(): Conversation {
        return Testing.getInstance()._conversation
    }


export interface SlickstreamRecommendationsService extends SosService {
    getRecommendations(options?: GetRecommendationOptions): Promise<PageRecommendations>;
}


export interface PageRecommendations {
    pages: PageListing;
    nextPage?(): Promise<PageListing>;
}


export interface GetRecommendationOptions {
    countPerPage?: number;
    type?: PageRecommendationsType;
    categoryMatchPreferred?: boolean;
    pageDescriptors?: PageDescriptorOptions;
    usePinnedItem?: boolean;
}


export declare type PageRecommendationsType = 'auto' | 'related' | 'popular' | 'recent';


/**
 * 剪裁图片
 */
export declare function clipImage(sourceImg: ImageInfo, props: RoundRectIncome): (ctx: Context) => void;


/**
 * The TreeWalker object represents the nodes of a document subtree and a position within them.
 */
export default class TreeWalker {
	public root: INode = null;
	public whatToShow = -1;
	public filter: INodeFilter = null;
	public currentNode: INode = null;

	/**
	 * Constructor.
	 *
	 * @param root Root.
	 * @param [whatToShow] What to show.
	 * @param [filter] Filter.
	 */
	constructor(root: INode, whatToShow = -1, filter: INodeFilter = null) {
		if (!(root instanceof Node)) {
			throw new DOMException('Parameter 1 was not of type Node.');
		}

		this.root = root;
		this.whatToShow = whatToShow;
		this.filter = filter;
		this.currentNode = root;
	}

	/**
	 * Moves the current Node to the next visible node in the document order.
	 *
	 * @return Current node.
	 */
	public nextNode(): INode {
		if (!this.firstChild()) {
			while (!this.nextSibling() && this.parentNode()) {}
			this.currentNode = this.currentNode === this.root ? null : this.currentNode || null;
		}
		return this.currentNode;
	}

	/**
	 * Moves the current Node to the previous visible node in the document order, and returns the found node. It also moves the current node to this one. If no such node exists, or if it is before that the root node defined at the object construction, returns null and the current node is not changed.
	 *
	 * @return Current node.
	 */
	public previousNode(): INode {
		while (!this.previousSibling() && this.parentNode()) {}
		this.currentNode = this.currentNode === this.root ? null : this.currentNode || null;
		return this.currentNode;
	}

	/**
	 * Moves the current Node to the first visible ancestor node in the document order, and returns the found node. It also moves the current node to this one. If no such node exists, or if it is before that the root node defined at the object construction, returns null and the current node is not changed.
	 *
	 * @return Current node.
	 */
	public parentNode(): INode {
		if (this.currentNode !== this.root && this.currentNode && this.currentNode.parentNode) {
			this.currentNode = this.currentNode.parentNode;

			if (this.filterNode(this.currentNode) === NodeFilter.FILTER_ACCEPT) {
				return this.currentNode;
			}

			this.parentNode();
		}

		return null;
	}

	/**
	 * Moves the current Node to the first visible child of the current node, and returns the found child. It also moves the current node to this child. If no such child exists, returns null and the current node is not changed.
	 *
	 * @return Current node.
	 */
	public firstChild(): INode {
		const childNodes = this.currentNode ? this.currentNode.childNodes : [];

		if (childNodes.length > 0) {
			this.currentNode = childNodes[0];

			if (this.filterNode(this.currentNode) === NodeFilter.FILTER_ACCEPT) {
				return this.currentNode;
			}

			return this.nextSibling();
		}

		return null;
	}

	/**
	 * Moves the current Node to the last visible child of the current node, and returns the found child. It also moves the current node to this child. If no such child exists, null is returned and the current node is not changed.
	 *
	 * @return Current node.
	 */
	public lastChild(): INode {
		const childNodes = this.currentNode ? this.currentNode.childNodes : [];

		if (childNodes.length > 0) {
			this.currentNode = childNodes[childNodes.length - 1];

			if (this.filterNode(this.currentNode) === NodeFilter.FILTER_ACCEPT) {
				return this.currentNode;
			}

			return this.previousSibling();
		}

		return null;
	}

	/**
	 * Moves the current Node to its previous sibling, if any, and returns the found sibling. If there is no such node, return null and the current node is not changed.
	 *
	 * @return Current node.
	 */
	public previousSibling(): INode {
		if (this.currentNode !== this.root && this.currentNode) {
			const siblings = this.currentNode.parentNode.childNodes;
			const index = siblings.indexOf(this.currentNode);

			if (index > 0) {
				this.currentNode = siblings[index - 1];

				if (this.filterNode(this.currentNode) === NodeFilter.FILTER_ACCEPT) {
					return this.currentNode;
				}

				return this.previousSibling();
			}
		}

		return null;
	}

	/**
	 * Moves the current Node to its next sibling, if any, and returns the found sibling. If there is no such node, null is returned and the current node is not changed.
	 *
	 * @return Current node.
	 */
	public nextSibling(): INode {
		if (this.currentNode !== this.root && this.currentNode) {
			const siblings = this.currentNode.parentNode.childNodes;
			const index = siblings.indexOf(this.currentNode);

			if (index + 1 < siblings.length) {
				this.currentNode = siblings[index + 1];

				if (this.filterNode(this.currentNode) === NodeFilter.FILTER_ACCEPT) {
					return this.currentNode;
				}

				return this.nextSibling();
			}
		}

		return null;
	}

	/**
	 * Filters a node.
	 *
	 * Based on solution:
	 * https://gist.github.com/shawndumas/1132009
	 *
	 * @param node Node.
	 * @return Child nodes.
	 */
	private filterNode(node: INode): number {
		const mask = NodeFilterMask[node.nodeType];

		if (mask && (this.whatToShow & mask) == 0) {
			return NodeFilter.FILTER_SKIP;
		} else if (this.filter) {
			return this.filter.acceptNode(node);
		}

		return NodeFilter.FILTER_ACCEPT;
	}
}


/**
	 * Moves the current Node to the next visible node in the document order.
	 *
	 * @return Current node.
	 */
public nextNode(): INode {
		if (!this.firstChild()) {
			while (!this.nextSibling() && this.parentNode()) {}
			this.currentNode = this.currentNode === this.root ? null : this.currentNode || null;
		}
		return this.currentNode;
	}


/**
	 * Moves the current Node to the previous visible node in the document order, and returns the found node. It also moves the current node to this one. If no such node exists, or if it is before that the root node defined at the object construction, returns null and the current node is not changed.
	 *
	 * @return Current node.
	 */
public previousNode(): INode {
		while (!this.previousSibling() && this.parentNode()) {}
		this.currentNode = this.currentNode === this.root ? null : this.currentNode || null;
		return this.currentNode;
	}


/**
	 * Moves the current Node to the first visible ancestor node in the document order, and returns the found node. It also moves the current node to this one. If no such node exists, or if it is before that the root node defined at the object construction, returns null and the current node is not changed.
	 *
	 * @return Current node.
	 */
public parentNode(): INode {
		if (this.currentNode !== this.root && this.currentNode && this.currentNode.parentNode) {
			this.currentNode = this.currentNode.parentNode;

			if (this.filterNode(this.currentNode) === NodeFilter.FILTER_ACCEPT) {
				return this.currentNode;
			}

			this.parentNode();
		}

		return null;
	}


/**
	 * Moves the current Node to the first visible child of the current node, and returns the found child. It also moves the current node to this child. If no such child exists, returns null and the current node is not changed.
	 *
	 * @return Current node.
	 */
public firstChild(): INode {
		const childNodes = this.currentNode ? this.currentNode.childNodes : [];

		if (childNodes.length > 0) {
			this.currentNode = childNodes[0];

			if (this.filterNode(this.currentNode) === NodeFilter.FILTER_ACCEPT) {
				return this.currentNode;
			}

			return this.nextSibling();
		}

		return null;
	}


/**
	 * Moves the current Node to the last visible child of the current node, and returns the found child. It also moves the current node to this child. If no such child exists, null is returned and the current node is not changed.
	 *
	 * @return Current node.
	 */
public lastChild(): INode {
		const childNodes = this.currentNode ? this.currentNode.childNodes : [];

		if (childNodes.length > 0) {
			this.currentNode = childNodes[childNodes.length - 1];

			if (this.filterNode(this.currentNode) === NodeFilter.FILTER_ACCEPT) {
				return this.currentNode;
			}

			return this.previousSibling();
		}

		return null;
	}


/**
	 * Moves the current Node to its previous sibling, if any, and returns the found sibling. If there is no such node, return null and the current node is not changed.
	 *
	 * @return Current node.
	 */
public previousSibling(): INode {
		if (this.currentNode !== this.root && this.currentNode) {
			const siblings = this.currentNode.parentNode.childNodes;
			const index = siblings.indexOf(this.currentNode);

			if (index > 0) {
				this.currentNode = siblings[index - 1];

				if (this.filterNode(this.currentNode) === NodeFilter.FILTER_ACCEPT) {
					return this.currentNode;
				}

				return this.previousSibling();
			}
		}

		return null;
	}


/**
	 * Moves the current Node to its next sibling, if any, and returns the found sibling. If there is no such node, null is returned and the current node is not changed.
	 *
	 * @return Current node.
	 */
public nextSibling(): INode {
		if (this.currentNode !== this.root && this.currentNode) {
			const siblings = this.currentNode.parentNode.childNodes;
			const index = siblings.indexOf(this.currentNode);

			if (index + 1 < siblings.length) {
				this.currentNode = siblings[index + 1];

				if (this.filterNode(this.currentNode) === NodeFilter.FILTER_ACCEPT) {
					return this.currentNode;
				}

				return this.nextSibling();
			}
		}

		return null;
	}


/**
	 * Filters a node.
	 *
	 * Based on solution:
	 * https://gist.github.com/shawndumas/1132009
	 *
	 * @param node Node.
	 * @return Child nodes.
	 */
private filterNode(node: INode): number {
		const mask = NodeFilterMask[node.nodeType];

		if (mask && (this.whatToShow & mask) == 0) {
			return NodeFilter.FILTER_SKIP;
		} else if (this.filter) {
			return this.filter.acceptNode(node);
		}

		return NodeFilter.FILTER_ACCEPT;
	}


(context) => {
    const storeName = findNgRxStoreName(context)
    if (!storeName) return {}

    return {
      [`${pipeableSelect(storeName)}, ${storeSelect(storeName)}`]({
        arguments: args,
      }: TSESTree.CallExpression) {
        args
          .filter(
            (node) =>
              isLiteral(node) ||
              isArrowFunctionExpression(node) ||
              isFunctionExpression(node),
          )
          .forEach((node) =>
            context.report({
              node,
              messageId,
            }),
          )
      },
    }
  }


(node) =>
              isLiteral(node) ||
              isArrowFunctionExpression(node) ||
              isFunctionExpression(node)


(node) =>
            context.report({
              node,
              messageId,
            })


export type MessageIds = typeof messageId


type Options = []


[`${pipeableSelect(storeName)}, ${storeSelect(storeName)}`]({
        arguments: args,
      }: TSESTree.CallExpression) {
        args
          .filter(
            (node) =>
              isLiteral(node) ||
              isArrowFunctionExpression(node) ||
              isFunctionExpression(node),
          )
          .forEach((node) =>
            context.report({
              node,
              messageId,
            }),
          )
      }


() => {
    let fixture: ComponentFixture<FileUploadingListRowComponent>;
    let component: FileUploadingListRowComponent;
    let file = new FileModel(<File> { name: 'fake-name' });

    beforeEach(() => {
        TestBed.configureTestingModule({
            imports: [
                UploadModule
            ]
        }).compileComponents();
    });

    beforeEach(() => {
        fixture = TestBed.createComponent(FileUploadingListRowComponent);
        component = fixture.componentInstance;
        component.file = file;
    });

    it('emits cancel event', () => {
        spyOn(component.cancel, 'emit');
        component.onCancel(component.file);

        expect(component.cancel.emit).toHaveBeenCalledWith(file);
    });

    it('emits remove event', () => {
        spyOn(component.remove, 'emit');
        component.onRemove(component.file);

        expect(component.remove.emit).toHaveBeenCalledWith(file);
    });
}


() => {
        TestBed.configureTestingModule({
            imports: [
                UploadModule
            ]
        }).compileComponents();
    }


() => {
        fixture = TestBed.createComponent(FileUploadingListRowComponent);
        component = fixture.componentInstance;
        component.file = file;
    }


() => {
        spyOn(component.cancel, 'emit');
        component.onCancel(component.file);

        expect(component.cancel.emit).toHaveBeenCalledWith(file);
    }


() => {
        spyOn(component.remove, 'emit');
        component.onRemove(component.file);

        expect(component.remove.emit).toHaveBeenCalledWith(file);
    }


/**
 * Compile a directive for the render3 runtime as defined by the `R3DirectiveMetadata`.
 */
export function compileDirectiveFromMetadata(
    meta: R3DirectiveMetadata, constantPool: ConstantPool,
    bindingParser: BindingParser): R3CompiledExpression {
  const definitionMap = baseDirectiveFields(meta, constantPool, bindingParser);
  addFeatures(definitionMap, meta);
  const expression =
      o.importExpr(R3.defineDirective).callFn([definitionMap.toLiteralMap()], undefined, true);
  const type = createDirectiveType(meta);

  return {expression, type, statements: []};
}


/**
 * Compile a component for the render3 runtime as defined by the `R3ComponentMetadata`.
 */
export function compileComponentFromMetadata(
    meta: R3ComponentMetadata, constantPool: ConstantPool,
    bindingParser: BindingParser): R3CompiledExpression {
  const definitionMap = baseDirectiveFields(meta, constantPool, bindingParser);
  addFeatures(definitionMap, meta);

  const selector = meta.selector && CssSelector.parse(meta.selector);
  const firstSelector = selector && selector[0];

  // e.g. `attr: ["class", ".my.app"]`
  // This is optional an only included if the first selector of a component specifies attributes.
  if (firstSelector) {
    const selectorAttributes = firstSelector.getAttrs();
    if (selectorAttributes.length) {
      definitionMap.set(
          'attrs',
          constantPool.getConstLiteral(
              o.literalArr(selectorAttributes.map(
                  value => value != null ? o.literal(value) : o.literal(undefined))),
              /* forceShared */ true));
    }
  }

  // e.g. `template: function MyComponent_Template(_ctx, _cm) {...}`
  const templateTypeName = meta.name;
  const templateName = templateTypeName ? `${templateTypeName}_Template` : null;

  const changeDetection = meta.changeDetection;

  const template = meta.template;
  const templateBuilder = new TemplateDefinitionBuilder(
      constantPool, BindingScope.createRootScope(), 0, templateTypeName, null, null, templateName,
      R3.namespaceHTML, meta.relativeContextFilePath, meta.i18nUseExternalIds);

  const templateFunctionExpression = templateBuilder.buildTemplateFunction(template.nodes, []);

  // We need to provide this so that dynamically generated components know what
  // projected content blocks to pass through to the component when it is instantiated.
  const ngContentSelectors = templateBuilder.getNgContentSelectors();
  if (ngContentSelectors) {
    definitionMap.set('ngContentSelectors', ngContentSelectors);
  }

  // e.g. `decls: 2`
  definitionMap.set('decls', o.literal(templateBuilder.getConstCount()));

  // e.g. `vars: 2`
  definitionMap.set('vars', o.literal(templateBuilder.getVarCount()));

  // Generate `consts` section of ComponentDef:
  // - either as an array:
  //   `consts: [['one', 'two'], ['three', 'four']]`
  // - or as a factory function in case additional statements are present (to support i18n):
  //   `consts: function() { var i18n_0; if (ngI18nClosureMode) {...} else {...} return [i18n_0]; }`
  const {constExpressions, prepareStatements} = templateBuilder.getConsts();
  if (constExpressions.length > 0) {
    let constsExpr: o.LiteralArrayExpr|o.FunctionExpr = o.literalArr(constExpressions);
    // Prepare statements are present - turn `consts` into a function.
    if (prepareStatements.length > 0) {
      constsExpr = o.fn([], [...prepareStatements, new o.ReturnStatement(constsExpr)]);
    }
    definitionMap.set('consts', constsExpr);
  }

  definitionMap.set('template', templateFunctionExpression);

  // e.g. `directives: [MyDirective]`
  if (meta.directives.length > 0) {
    const directivesList = o.literalArr(meta.directives.map(dir => dir.type));
    const directivesExpr = compileDeclarationList(directivesList, meta.declarationListEmitMode);
    definitionMap.set('directives', directivesExpr);
  }

  // e.g. `pipes: [MyPipe]`
  if (meta.pipes.size > 0) {
    const pipesList = o.literalArr(Array.from(meta.pipes.values()));
    const pipesExpr = compileDeclarationList(pipesList, meta.declarationListEmitMode);
    definitionMap.set('pipes', pipesExpr);
  }

  if (meta.encapsulation === null) {
    meta.encapsulation = core.ViewEncapsulation.Emulated;
  }

  // e.g. `styles: [str1, str2]`
  if (meta.styles && meta.styles.length) {
    const styleValues = meta.encapsulation == core.ViewEncapsulation.Emulated ?
        compileStyles(meta.styles, CONTENT_ATTR, HOST_ATTR) :
        meta.styles;
    const strings = styleValues.map(str => constantPool.getConstLiteral(o.literal(str)));
    definitionMap.set('styles', o.literalArr(strings));
  } else if (meta.encapsulation === core.ViewEncapsulation.Emulated) {
    // If there is no style, don't generate css selectors on elements
    meta.encapsulation = core.ViewEncapsulation.None;
  }

  // Only set view encapsulation if it's not the default value
  if (meta.encapsulation !== core.ViewEncapsulation.Emulated) {
    definitionMap.set('encapsulation', o.literal(meta.encapsulation));
  }

  // e.g. `animation: [trigger('123', [])]`
  if (meta.animations !== null) {
    definitionMap.set(
        'data', o.literalMap([{key: 'animation', value: meta.animations, quoted: false}]));
  }

  // Only set the change detection flag if it's defined and it's not the default.
  if (changeDetection != null && changeDetection !== core.ChangeDetectionStrategy.Default) {
    definitionMap.set('changeDetection', o.literal(changeDetection));
  }

  const expression =
      o.importExpr(R3.defineComponent).callFn([definitionMap.toLiteralMap()], undefined, true);
  const type = createComponentType(meta);

  return {expression, type, statements: []};
}


/**
 * Creates the type specification from the component meta. This type is inserted into .d.ts files
 * to be consumed by upstream compilations.
 */
export function createComponentType(meta: R3ComponentMetadata): o.Type {
  const typeParams = createDirectiveTypeParams(meta);
  typeParams.push(stringArrayAsType(meta.template.ngContentSelectors));
  return o.expressionType(o.importExpr(R3.ComponentDeclaration, typeParams));
}


/**
 * Compiles the array literal of declarations into an expression according to the provided emit
 * mode.
 */
function compileDeclarationList(
    list: o.LiteralArrayExpr, mode: DeclarationListEmitMode): o.Expression {
  switch (mode) {
    case DeclarationListEmitMode.Direct:
      // directives: [MyDir],
      return list;
    case DeclarationListEmitMode.Closure:
      // directives: function () { return [MyDir]; }
      return o.fn([], [new o.ReturnStatement(list)]);
    case DeclarationListEmitMode.ClosureResolved:
      // directives: function () { return [MyDir].map(ng.resolveForwardRef); }
      const resolvedList = list.prop('map').callFn([o.importExpr(R3.resolveForwardRef)]);
      return o.fn([], [new o.ReturnStatement(resolvedList)]);
  }
}


function prepareQueryParams(query: R3QueryMetadata, constantPool: ConstantPool): o.Expression[] {
  const parameters = [getQueryPredicate(query, constantPool), o.literal(toQueryFlags(query))];
  if (query.read) {
    parameters.push(query.read);
  }
  return parameters;
}


/**
 * Translates query flags into `TQueryFlags` type in packages/core/src/render3/interfaces/query.ts
 * @param query
 */
function toQueryFlags(query: R3QueryMetadata): number {
  return (query.descendants ? QueryFlags.descendants : QueryFlags.none) |
      (query.static ? QueryFlags.isStatic : QueryFlags.none) |
      (query.emitDistinctChangesOnly ? QueryFlags.emitDistinctChangesOnly : QueryFlags.none);
}


// Define and update any content queries
function createContentQueriesFunction(
    queries: R3QueryMetadata[], constantPool: ConstantPool, name?: string): o.Expression {
  const createStatements: o.Statement[] = [];
  const updateStatements: o.Statement[] = [];
  const tempAllocator = temporaryAllocator(updateStatements, TEMPORARY_NAME);

  for (const query of queries) {
    // creation, e.g. r3.contentQuery(dirIndex, somePredicate, true, null);
    createStatements.push(
        o.importExpr(R3.contentQuery)
            .callFn([o.variable('dirIndex'), ...prepareQueryParams(query, constantPool) as any])
            .toStmt());

    // update, e.g. (r3.queryRefresh(tmp = r3.loadQuery()) && (ctx.someDir = tmp));
    const temporary = tempAllocator();
    const getQueryList = o.importExpr(R3.loadQuery).callFn([]);
    const refresh = o.importExpr(R3.queryRefresh).callFn([temporary.set(getQueryList)]);
    const updateDirective = o.variable(CONTEXT_NAME)
                                .prop(query.propertyName)
                                .set(query.first ? temporary.prop('first') : temporary);
    updateStatements.push(refresh.and(updateDirective).toStmt());
  }

  const contentQueriesFnName = name ? `${name}_ContentQueries` : null;
  return o.fn(
      [
        new o.FnParam(RENDER_FLAGS, o.NUMBER_TYPE), new o.FnParam(CONTEXT_NAME, null),
        new o.FnParam('dirIndex', null)
      ],
      [
        renderFlagCheckIfStmt(core.RenderFlags.Create, createStatements),
        renderFlagCheckIfStmt(core.RenderFlags.Update, updateStatements)
      ],
      o.INFERRED_TYPE, null, contentQueriesFnName);
}


export function createDirectiveTypeParams(meta: R3DirectiveMetadata): o.Type[] {
  // On the type side, remove newlines from the selector as it will need to fit into a TypeScript
  // string literal, which must be on one line.
  const selectorForType = meta.selector !== null ? meta.selector.replace(/\n/g, '') : null;

  return [
    typeWithParameters(meta.type.type, meta.typeArgumentCount),
    selectorForType !== null ? stringAsType(selectorForType) : o.NONE_TYPE,
    meta.exportAs !== null ? stringArrayAsType(meta.exportAs) : o.NONE_TYPE,
    stringMapAsType(meta.inputs),
    stringMapAsType(meta.outputs),
    stringArrayAsType(meta.queries.map(q => q.propertyName)),
  ];
}


/**
 * Creates the type specification from the directive meta. This type is inserted into .d.ts files
 * to be consumed by upstream compilations.
 */
export function createDirectiveType(meta: R3DirectiveMetadata): o.Type {
  const typeParams = createDirectiveTypeParams(meta);
  return o.expressionType(o.importExpr(R3.DirectiveDeclaration, typeParams));
}


// Define and update any view queries
function createViewQueriesFunction(
    viewQueries: R3QueryMetadata[], constantPool: ConstantPool, name?: string): o.Expression {
  const createStatements: o.Statement[] = [];
  const updateStatements: o.Statement[] = [];
  const tempAllocator = temporaryAllocator(updateStatements, TEMPORARY_NAME);

  viewQueries.forEach((query: R3QueryMetadata) => {
    // creation, e.g. r3.viewQuery(somePredicate, true);
    const queryDefinition =
        o.importExpr(R3.viewQuery).callFn(prepareQueryParams(query, constantPool));
    createStatements.push(queryDefinition.toStmt());

    // update, e.g. (r3.queryRefresh(tmp = r3.loadQuery()) && (ctx.someDir = tmp));
    const temporary = tempAllocator();
    const getQueryList = o.importExpr(R3.loadQuery).callFn([]);
    const refresh = o.importExpr(R3.queryRefresh).callFn([temporary.set(getQueryList)]);
    const updateDirective = o.variable(CONTEXT_NAME)
                                .prop(query.propertyName)
                                .set(query.first ? temporary.prop('first') : temporary);
    updateStatements.push(refresh.and(updateDirective).toStmt());
  });

  const viewQueryFnName = name ? `${name}_Query` : null;
  return o.fn(
      [new o.FnParam(RENDER_FLAGS, o.NUMBER_TYPE), new o.FnParam(CONTEXT_NAME, null)],
      [
        renderFlagCheckIfStmt(core.RenderFlags.Create, createStatements),
        renderFlagCheckIfStmt(core.RenderFlags.Update, updateStatements)
      ],
      o.INFERRED_TYPE, null, viewQueryFnName);
}


// Return a host binding function or null if one is not necessary.
function createHostBindingsFunction(
    hostBindingsMetadata: R3HostMetadata, typeSourceSpan: ParseSourceSpan,
    bindingParser: BindingParser, constantPool: ConstantPool, selector: string, name: string,
    definitionMap: DefinitionMap): o.Expression|null {
  const bindingContext = o.variable(CONTEXT_NAME);
  const styleBuilder = new StylingBuilder(bindingContext);

  const {styleAttr, classAttr} = hostBindingsMetadata.specialAttributes;
  if (styleAttr !== undefined) {
    styleBuilder.registerStyleAttr(styleAttr);
  }
  if (classAttr !== undefined) {
    styleBuilder.registerClassAttr(classAttr);
  }

  const createStatements: o.Statement[] = [];
  const updateStatements: o.Statement[] = [];

  const hostBindingSourceSpan = typeSourceSpan;

  // Calculate host event bindings
  const eventBindings = bindingParser.createDirectiveHostEventAsts(
      hostBindingsMetadata.listeners, hostBindingSourceSpan);
  if (eventBindings && eventBindings.length) {
    const listeners = createHostListeners(eventBindings, name);
    createStatements.push(...listeners);
  }

  // Calculate the host property bindings
  const bindings = bindingParser.createBoundHostProperties(
      hostBindingsMetadata.properties, hostBindingSourceSpan);
  const allOtherBindings: ParsedProperty[] = [];

  // We need to calculate the total amount of binding slots required by
  // all the instructions together before any value conversions happen.
  // Value conversions may require additional slots for interpolation and
  // bindings with pipes. These calculates happen after this block.
  let totalHostVarsCount = 0;
  bindings && bindings.forEach((binding: ParsedProperty) => {
    const stylingInputWasSet = styleBuilder.registerInputBasedOnName(
        binding.name, binding.expression, hostBindingSourceSpan);
    if (stylingInputWasSet) {
      totalHostVarsCount += MIN_STYLING_BINDING_SLOTS_REQUIRED;
    } else {
      allOtherBindings.push(binding);
      totalHostVarsCount++;
    }
  });

  let valueConverter: ValueConverter;
  const getValueConverter = () => {
    if (!valueConverter) {
      const hostVarsCountFn = (numSlots: number): number => {
        const originalVarsCount = totalHostVarsCount;
        totalHostVarsCount += numSlots;
        return originalVarsCount;
      };
      valueConverter = new ValueConverter(
          constantPool,
          () => error('Unexpected node'),  // new nodes are illegal here
          hostVarsCountFn,
          () => error('Unexpected pipe'));  // pipes are illegal here
    }
    return valueConverter;
  };

  const propertyBindings: o.Expression[][] = [];
  const attributeBindings: o.Expression[][] = [];
  const syntheticHostBindings: o.Expression[][] = [];
  allOtherBindings.forEach((binding: ParsedProperty) => {
    // resolve literal arrays and literal objects
    const value = binding.expression.visit(getValueConverter());
    const bindingExpr = bindingFn(bindingContext, value);

    const {bindingName, instruction, isAttribute} = getBindingNameAndInstruction(binding);

    const securityContexts =
        bindingParser.calcPossibleSecurityContexts(selector, bindingName, isAttribute)
            .filter(context => context !== core.SecurityContext.NONE);

    let sanitizerFn: o.ExternalExpr|null = null;
    if (securityContexts.length) {
      if (securityContexts.length === 2 &&
          securityContexts.indexOf(core.SecurityContext.URL) > -1 &&
          securityContexts.indexOf(core.SecurityContext.RESOURCE_URL) > -1) {
        // Special case for some URL attributes (such as "src" and "href") that may be a part
        // of different security contexts. In this case we use special sanitization function and
        // select the actual sanitizer at runtime based on a tag name that is provided while
        // invoking sanitization function.
        sanitizerFn = o.importExpr(R3.sanitizeUrlOrResourceUrl);
      } else {
        sanitizerFn = resolveSanitizationFn(securityContexts[0], isAttribute);
      }
    }
    const instructionParams = [o.literal(bindingName), bindingExpr.currValExpr];
    if (sanitizerFn) {
      instructionParams.push(sanitizerFn);
    }

    updateStatements.push(...bindingExpr.stmts);

    if (instruction === R3.hostProperty) {
      propertyBindings.push(instructionParams);
    } else if (instruction === R3.attribute) {
      attributeBindings.push(instructionParams);
    } else if (instruction === R3.syntheticHostProperty) {
      syntheticHostBindings.push(instructionParams);
    } else {
      updateStatements.push(o.importExpr(instruction).callFn(instructionParams).toStmt());
    }
  });

  if (propertyBindings.length > 0) {
    updateStatements.push(chainedInstruction(R3.hostProperty, propertyBindings).toStmt());
  }

  if (attributeBindings.length > 0) {
    updateStatements.push(chainedInstruction(R3.attribute, attributeBindings).toStmt());
  }

  if (syntheticHostBindings.length > 0) {
    updateStatements.push(
        chainedInstruction(R3.syntheticHostProperty, syntheticHostBindings).toStmt());
  }

  // since we're dealing with directives/components and both have hostBinding
  // functions, we need to generate a special hostAttrs instruction that deals
  // with both the assignment of styling as well as static attributes to the host
  // element. The instruction below will instruct all initial styling (styling
  // that is inside of a host binding within a directive/component) to be attached
  // to the host element alongside any of the provided host attributes that were
  // collected earlier.
  const hostAttrs = convertAttributesToExpressions(hostBindingsMetadata.attributes);
  styleBuilder.assignHostAttrs(hostAttrs, definitionMap);

  if (styleBuilder.hasBindings) {
    // finally each binding that was registered in the statement above will need to be added to
    // the update block of a component/directive templateFn/hostBindingsFn so that the bindings
    // are evaluated and updated for the element.
    styleBuilder.buildUpdateLevelInstructions(getValueConverter()).forEach(instruction => {
      if (instruction.calls.length > 0) {
        const calls: o.Expression[][] = [];

        instruction.calls.forEach(call => {
          // we subtract a value of `1` here because the binding slot was already allocated
          // at the top of this method when all the input bindings were counted.
          totalHostVarsCount +=
              Math.max(call.allocateBindingSlots - MIN_STYLING_BINDING_SLOTS_REQUIRED, 0);
          calls.push(convertStylingCall(call, bindingContext, bindingFn));
        });

        updateStatements.push(chainedInstruction(instruction.reference, calls).toStmt());
      }
    });
  }

  if (totalHostVarsCount) {
    definitionMap.set('hostVars', o.literal(totalHostVarsCount));
  }

  if (createStatements.length > 0 || updateStatements.length > 0) {
    const hostBindingsFnName = name ? `${name}_HostBindings` : null;
    const statements: o.Statement[] = [];
    if (createStatements.length > 0) {
      statements.push(renderFlagCheckIfStmt(core.RenderFlags.Create, createStatements));
    }
    if (updateStatements.length > 0) {
      statements.push(renderFlagCheckIfStmt(core.RenderFlags.Update, updateStatements));
    }
    return o.fn(
        [new o.FnParam(RENDER_FLAGS, o.NUMBER_TYPE), new o.FnParam(CONTEXT_NAME, null)], statements,
        o.INFERRED_TYPE, null, hostBindingsFnName);
  }

  return null;
}


function bindingFn(implicit: any, value: AST) {
  return convertPropertyBinding(
      null, implicit, value, 'b', () => error('Unexpected interpolation'));
}


/**
 * Verifies host bindings and returns the list of errors (if any). Empty array indicates that a
 * given set of host bindings has no errors.
 *
 * @param bindings set of host bindings to verify.
 * @param sourceSpan source span where host bindings were defined.
 * @returns array of errors associated with a given set of host bindings.
 */
export function verifyHostBindings(
    bindings: ParsedHostBindings, sourceSpan: ParseSourceSpan): ParseError[] {
  // TODO: abstract out host bindings verification logic and use it instead of
  // creating events and properties ASTs to detect errors (FW-996)
  const bindingParser = makeBindingParser();
  bindingParser.createDirectiveHostEventAsts(bindings.listeners, sourceSpan);
  bindingParser.createBoundHostProperties(bindings.properties, sourceSpan);
  return bindingParser.errors;
}


dir => dir.type


(query: R3QueryMetadata) => {
    // creation, e.g. r3.viewQuery(somePredicate, true);
    const queryDefinition =
        o.importExpr(R3.viewQuery).callFn(prepareQueryParams(query, constantPool));
    createStatements.push(queryDefinition.toStmt());

    // update, e.g. (r3.queryRefresh(tmp = r3.loadQuery()) && (ctx.someDir = tmp));
    const temporary = tempAllocator();
    const getQueryList = o.importExpr(R3.loadQuery).callFn([]);
    const refresh = o.importExpr(R3.queryRefresh).callFn([temporary.set(getQueryList)]);
    const updateDirective = o.variable(CONTEXT_NAME)
                                .prop(query.propertyName)
                                .set(query.first ? temporary.prop('first') : temporary);
    updateStatements.push(refresh.and(updateDirective).toStmt());
  }


(binding: ParsedProperty) => {
    // resolve literal arrays and literal objects
    const value = binding.expression.visit(getValueConverter());
    const bindingExpr = bindingFn(bindingContext, value);

    const {bindingName, instruction, isAttribute} = getBindingNameAndInstruction(binding);

    const securityContexts =
        bindingParser.calcPossibleSecurityContexts(selector, bindingName, isAttribute)
            .filter(context => context !== core.SecurityContext.NONE);

    let sanitizerFn: o.ExternalExpr|null = null;
    if (securityContexts.length) {
      if (securityContexts.length === 2 &&
          securityContexts.indexOf(core.SecurityContext.URL) > -1 &&
          securityContexts.indexOf(core.SecurityContext.RESOURCE_URL) > -1) {
        // Special case for some URL attributes (such as "src" and "href") that may be a part
        // of different security contexts. In this case we use special sanitization function and
        // select the actual sanitizer at runtime based on a tag name that is provided while
        // invoking sanitization function.
        sanitizerFn = o.importExpr(R3.sanitizeUrlOrResourceUrl);
      } else {
        sanitizerFn = resolveSanitizationFn(securityContexts[0], isAttribute);
      }
    }
    const instructionParams = [o.literal(bindingName), bindingExpr.currValExpr];
    if (sanitizerFn) {
      instructionParams.push(sanitizerFn);
    }

    updateStatements.push(...bindingExpr.stmts);

    if (instruction === R3.hostProperty) {
      propertyBindings.push(instructionParams);
    } else if (instruction === R3.attribute) {
      attributeBindings.push(instructionParams);
    } else if (instruction === R3.syntheticHostProperty) {
      syntheticHostBindings.push(instructionParams);
    } else {
      updateStatements.push(o.importExpr(instruction).callFn(instructionParams).toStmt());
    }
  }


/**
 * A set of flags to be used with Queries.
 *
 * NOTE: Ensure changes here are in sync with `packages/core/src/render3/interfaces/query.ts`
 */
export const enum QueryFlags {
  /**
   * No flags
   */
  none = 0b0000,

  /**
   * Whether or not the query should descend into children.
   */
  descendants = 0b0001,

  /**
   * The query can be computed statically and hence can be assigned eagerly.
   *
   * NOTE: Backwards compatibility with ViewEngine.
   */
  isStatic = 0b0010,

  /**
   * If the `QueryList` should fire change event only if actual change to query was computed (vs old
   * behavior where the change was fired whenever the query was recomputed, even if the recomputed
   * query resulted in the same list.)
   */
  emitDistinctChangesOnly = 0b0100,
}


(order) => this._orderFactory(order)


@Injectable()
export class OrderRouter implements IOrderRouter {
	private readonly router: Router;

	constructor(routerFactory: RouterFactory) {
		this.router = routerFactory.create('order');
	}

	get(id: string, options?: IOrderRouterGetOptions): Observable<Order> {
		return this.router
			.runAndObserve<IOrder>('get', id, options)
			.pipe(map((order) => this._orderFactory(order)));
	}

	async confirm(orderId: string): Promise<Order> {
		const order = await this.router.run<IOrder>('confirm', orderId);
		return this._orderFactory(order);
	}

	async complete(orderId: string): Promise<Order> {
		const order = await this.router.run<IOrder>('complete', orderId);
		return this._orderFactory(order);
	}

	async updateCarrierStatus(
		orderId: string,
		status: OrderCarrierStatus
	): Promise<Order> {
		const order = await this.router.run<IOrder>(
			'updateCarrierStatus',
			orderId,
			status
		);
		return this._orderFactory(order);
	}

	async updateWarehouseStatus(
		orderId: string,
		status: OrderWarehouseStatus
	): Promise<Order> {
		const order = await this.router.run<IOrder>(
			'updateWarehouseStatus',
			orderId,
			status
		);
		return this._orderFactory(order);
	}

	async payWithStripe(orderId: string, cardId: string): Promise<Order> {
		const order = await this.router.run<IOrder>(
			'payWithStripe',
			orderId,
			cardId
		);
		return this._orderFactory(order);
	}

	async refundWithStripe(orderId: string): Promise<Order> {
		const order = await this.router.run<IOrder>(
			'refundWithStripe',
			orderId
		);
		return this._orderFactory(order);
	}

	async addProducts(
		orderId: Order['id'],
		products,
		warehouseId: Warehouse['id']
	): Promise<Order> {
		const order = await this.router.run<IOrder>(
			'addProducts',
			orderId,
			products,
			warehouseId
		);
		return this._orderFactory(order);
	}

	async decreaseOrderProducts(
		orderId: Order['id'],
		products,
		warehouseId: Warehouse['id']
	): Promise<Order> {
		const order = await this.router.run<IOrder>(
			'decreaseOrderProducts',
			orderId,
			products,
			warehouseId
		);
		return this._orderFactory(order);
	}

	async removeProducts(
		orderId: Order['id'],
		productsIds: string[]
	): Promise<Order> {
		const order = await this.router.run<IOrder>(
			'removeProducts',
			orderId,
			productsIds
		);
		return this._orderFactory(order);
	}

	async addProductComment(
		orderId: Order['id'],
		productId: string,
		comment: string
	): Promise<Order> {
		const order = await this.router.run<IOrder>(
			'addProductComment',
			orderId,
			productId,
			comment
		);
		return this._orderFactory(order);
	}

	protected _orderFactory(order: IOrder) {
		return order == null ? null : new Order(order);
	}
}


get(id: string, options?: IOrderRouterGetOptions): Observable<Order> {
		return this.router
			.runAndObserve<IOrder>('get', id, options)
			.pipe(map((order) => this._orderFactory(order)));
	}


async confirm(orderId: string): Promise<Order> {
		const order = await this.router.run<IOrder>('confirm', orderId);
		return this._orderFactory(order);
	}


async complete(orderId: string): Promise<Order> {
		const order = await this.router.run<IOrder>('complete', orderId);
		return this._orderFactory(order);
	}


async updateCarrierStatus(
		orderId: string,
		status: OrderCarrierStatus
	): Promise<Order> {
		const order = await this.router.run<IOrder>(
			'updateCarrierStatus',
			orderId,
			status
		);
		return this._orderFactory(order);
	}


async updateWarehouseStatus(
		orderId: string,
		status: OrderWarehouseStatus
	): Promise<Order> {
		const order = await this.router.run<IOrder>(
			'updateWarehouseStatus',
			orderId,
			status
		);
		return this._orderFactory(order);
	}


async payWithStripe(orderId: string, cardId: string): Promise<Order> {
		const order = await this.router.run<IOrder>(
			'payWithStripe',
			orderId,
			cardId
		);
		return this._orderFactory(order);
	}


async refundWithStripe(orderId: string): Promise<Order> {
		const order = await this.router.run<IOrder>(
			'refundWithStripe',
			orderId
		);
		return this._orderFactory(order);
	}


async addProducts(
		orderId: Order['id'],
		products,
		warehouseId: Warehouse['id']
	): Promise<Order> {
		const order = await this.router.run<IOrder>(
			'addProducts',
			orderId,
			products,
			warehouseId
		);
		return this._orderFactory(order);
	}


async decreaseOrderProducts(
		orderId: Order['id'],
		products,
		warehouseId: Warehouse['id']
	): Promise<Order> {
		const order = await this.router.run<IOrder>(
			'decreaseOrderProducts',
			orderId,
			products,
			warehouseId
		);
		return this._orderFactory(order);
	}


async removeProducts(
		orderId: Order['id'],
		productsIds: string[]
	): Promise<Order> {
		const order = await this.router.run<IOrder>(
			'removeProducts',
			orderId,
			productsIds
		);
		return this._orderFactory(order);
	}


async addProductComment(
		orderId: Order['id'],
		productId: string,
		comment: string
	): Promise<Order> {
		const order = await this.router.run<IOrder>(
			'addProductComment',
			orderId,
			productId,
			comment
		);
		return this._orderFactory(order);
	}


protected _orderFactory(order: IOrder) {
		return order == null ? null : new Order(order);
	}


export type ServiceProviderImageCategory = 'Logo' | 'Face' | 'Exterior' | 'Interior' | 'Satellite';


() => {
    const WIKI_NOTATION = `\\* aaa
\\# bbb
\\- ccc`;

    checkParseEncodeRoundTrips(
      WIKI_NOTATION,
      defaultSchema,
      WIKI_NOTATION,
      doc(
        p(
          '* aaa',
          hardBreak(),
          '# bbb',
          hardBreak(),
          '- ccc',
          hardBreak(),
        ),
      ),
    );
  }


() => {
    const WIKI_NOTATION = `* aaa
* bbb
* ccc
* ddd
* eee`;

    checkParseEncodeRoundTrips(
      WIKI_NOTATION,
      defaultSchema,
      WIKI_NOTATION,
      doc(
        ul(
          li(p('aaa')),
          li(p('bbb')),
          li(p('ccc')),
          li(p('ddd')),
          li(p('eee')),
        ),
      ),
    );
  }


() => {
    const WIKI_NOTATION = `- aaa
- bbb
- ccc
- ddd
- eee`;

    checkParseEncodeRoundTrips(
      WIKI_NOTATION,
      defaultSchema,
      WIKI_NOTATION,
      doc(
        ul(
          li(p('aaa')),
          li(p('bbb')),
          li(p('ccc')),
          li(p('ddd')),
          li(p('eee')),
        ),
      ),
    );
  }


() => {
    const WIKI_NOTATION = `* aaa
* bbb
* ccc

* ddd
* eee
* fff`;

    checkParseEncodeRoundTrips(
      WIKI_NOTATION,
      defaultSchema,
      WIKI_NOTATION,
      doc(
        ul(li(p('aaa')), li(p('bbb')), li(p('ccc'))),
        ul(li(p('ddd')), li(p('eee')), li(p('fff'))),
      ),
    );
  }


() => {
    const WIKI_NOTATION = `# one
# two
## two-one
## two-two
# three
# four
## four-one`;

    checkParseEncodeRoundTrips(
      WIKI_NOTATION,
      defaultSchema,
      WIKI_NOTATION,
      doc(
        ol(
          li(p('two'), ol(li(p('two-one')), li(p('two-two')))),
          li(p('three')),
          li(p('four'), ol(li(p('four-one')))),
        ),
      ),
    );
  }


() => {
    const WIKI_NOTATION = `* aaa
* bbb
 * ccc
  * ddd
* eee`;

    checkParseEncodeRoundTrips(
      WIKI_NOTATION,
      defaultSchema,
      WIKI_NOTATION,
      doc(
        ul(
          li(p('aaa')),
          li(p('bbb')),
          li(p('ccc')),
          li(p('ddd')),
          li(p('eee')),
        ),
      ),
    );
  }


() => {
    const WIKI_NOTATION = `* aaa
* bbb
* ccc
*ddd
*eee
* ffff
** ggggg`;

    checkParseEncodeRoundTrips(
      WIKI_NOTATION,
      defaultSchema,
      WIKI_NOTATION,
      doc(
        ul(
          li(p('aaa')),
          li(p('bbb')),
          li(p('ccc', hardBreak(), 'ddd', hardBreak(), 'eee')),
        ),
        ul(li(p('ffff'), ul(li(p('ggggg'))))),
      ),
    );
  }


() => {
    const WIKI_NOTATION = `- aaa
- bbb \\\\| another bbb
- ccc
- ddd`;

    checkParseEncodeRoundTrips(
      WIKI_NOTATION,
      defaultSchema,
      WIKI_NOTATION,
      doc(
        ul(
          li(p('aaa')),
          li(p('bbb | another bbb')),
          li(p('ccc')),
          li(p('ddd')),
        ),
      ),
    );
  }


() => {
    const WIKI_NOTATION = `some texts here
- jobs to do
* more jobs to do`;

    checkParseEncodeRoundTrips(
      WIKI_NOTATION,
      defaultSchema,
      WIKI_NOTATION,
      doc(
        p('some texts here'),
        ul(li(p('jobs to do'))),
        ul(li(p('more jobs to do'))),
      ),
    );
  }


() => {
    const WIKI_NOTATION = `Just a list:
# first item
# second item
** another1 item
** another2 item
# unknown item`;

    checkParseEncodeRoundTrips(
      WIKI_NOTATION,
      defaultSchema,
      WIKI_NOTATION,
      doc(
        p('Just a list:'),
        ol(
          li(p('first item')),
          li(
            p('second item'),
            ul(li(p('another1 item')), li(p('another2 item'))),
          ),
          li(p('unknown item')),
        ),
      ),
    );
  }


() => {
    const WIKI_NOTATION = `** An item`;

    checkParseEncodeRoundTrips(
      WIKI_NOTATION,
      defaultSchema,
      WIKI_NOTATION,
      doc(ul(li(ul(li(p('An item')))))),
    );
  }


() => {
    const WIKI_NOTATION = `Just a list:
# one
## two
## three
** four
# five`;

    checkParseEncodeRoundTrips(
      WIKI_NOTATION,
      defaultSchema,
      WIKI_NOTATION,
      doc(
        p('Just a list:'),
        ol(
          li(p('one'), ol(li(p('two')), li(p('three'))), ul(li(p('four')))),
          li(p('five')),
        ),
      ),
    );
  }


() => {
    const WIKI_NOTATION = `# foo
**** bar
# baz`;

    checkParseEncodeRoundTrips(
      WIKI_NOTATION,
      defaultSchema,
      WIKI_NOTATION,
      doc(ol(li(p('foo'), ul(li(ul(li(ul(li(p('bar')))))))), li(p('baz')))),
    );
  }


() => {
    const WIKI_NOTATION = `* *bold test*
** *deeper test*
* normal test`;

    checkParseEncodeRoundTrips(
      WIKI_NOTATION,
      defaultSchema,
      WIKI_NOTATION,
      doc(
        ul(
          li(p(strong('bold test')), ul(li(p(strong('deeper test'))))),
          li(p('normal test')),
        ),
      ),
    );
  }


() => {
    const WIKI_NOTATION = `* Middleware Configuration
* Core Collection Drivers
** JDBC Driver
*** JDBC Collection Driver
*** JDBC Metadata Driver
**** JDBC Template Report Configuration
**** JDBC URL Report Configuration
***** Generating Reports from JSP and other sources
*** JDBC Query Driver`;

    checkParseEncodeRoundTrips(
      WIKI_NOTATION,
      defaultSchema,
      WIKI_NOTATION,
      doc(
        ul(
          li(p('Middleware Configuration')),
          li(
            p('Core Collection Drivers'),
            ul(
              li(
                p('JDBC Driver'),
                ul(
                  li(p('JDBC Collection Driver')),
                  li(
                    p('JDBC Metadata Driver'),
                    ul(
                      li(p('JDBC Template Report Configuration')),
                      li(
                        p('JDBC URL Report Configuration'),
                        ul(
                          li(
                            p('Generating Reports from JSP and other sources'),
                          ),
                        ),
                      ),
                    ),
                  ),
                  li(p('JDBC Query Driver')),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }


() => {
    const WIKI_NOTATION = ` first item
* second item
second item, second part
and the third section
* third item
** third.one item`;

    checkParseEncodeRoundTrips(
      WIKI_NOTATION,
      defaultSchema,
      WIKI_NOTATION,
      doc(
        p(' first item'),
        ul(
          li(
            p(
              'second item',
              hardBreak(),
              'second item, second part',
              hardBreak(),
              'and the third section',
            ),
          ),
          li(p('third item'), ul(li(p('third.one item')))),
        ),
      ),
    );
  }


() => {
    const WIKI_NOTATION = `h2.Just a list here
# item one {noformat}a preformatted *block* and more{noformat}
# second item
# then {noformat}another _preformatted_ block{noformat}
#- as mentioned, the above is a preformatted block
# third item {noformat}and the last/preformatted/block{noformat}`;

    checkParseEncodeRoundTrips(
      WIKI_NOTATION,
      defaultSchema,
      WIKI_NOTATION,
      doc(
        h2('Just a list here'),
        ol(
          li(p('item one ', code('a preformatted *block* and more'))),
          li(p('second item')),
          li(
            p('then ', code('another _preformatted_ block')),
            ul(li(p('as mentioned, the above is a preformatted block'))),
          ),
          li(p('third item ', code('and the last/preformatted/block'))),
        ),
      ),
    );
  }


() => {
    const WIKI_NOTATION = `# Just
# Some
# [link to yahoo|http://www.yahoo.com]
# and
# [link to atlassian|http://www.atlassian.com]
# here`;

    checkParseEncodeRoundTrips(
      WIKI_NOTATION,
      defaultSchema,
      WIKI_NOTATION,
      doc(
        ol(
          li(p('Just')),
          li(p('Some')),
          li(p(link({ href: 'http://www.yahoo.com' })('link to yahoo'))),
          li(p('and')),
          li(
            p(link({ href: 'http://www.atlassian.com' })('link to atlassian')),
          ),
          li(p('here')),
        ),
      ),
    );
  }


() => {
    const WIKI_NOTATION = `* List item one
* List item two
* List item three
## List item two
## List item three
## List item four
## List item five
* List item six`;

    checkParseEncodeRoundTrips(
      WIKI_NOTATION,
      defaultSchema,
      WIKI_NOTATION,
      doc(
        ol(
          li(p('List item one')),
          li(p('List item two')),
          li(
            p('List item three'),
            ol(
              li(p('List item two')),
              li(p('List item three')),
              li(p('List item four')),
              li(p('List item five')),
            ),
          ),
          li(p('List item six')),
        ),
      ),
    );
  }


() => {
    const WIKI_NOTATION = `* Follow these instructions and then click *Next*.\\\\\\\\{color:red}*Tip:*{color} You can copy and paste the required information.\\\\\\\\ \\\\\\\\ !Helpful Image.jpg! \\\\\\\\ \\\\\\\\\\n\\
* Another bulleted item.`;

    checkParseEncodeRoundTrips(
      WIKI_NOTATION,
      defaultSchema,
      WIKI_NOTATION,
      doc(
        ol(
          li(
            p(
              'Follow these instructions and then click ',
              strong('Next'),
              '.',
              hardBreak(),
              textColor({ color: '#F00' })(strong('Tip:')),
              ' You can copy and paste the required information.',
              hardBreak(),
              img({ src: 'Helpful Image.jpg' })(), // @TODO media?
            ),
          ),
          li(p('Another bulleted item.')),
        ),
      ),
    );
  }


() => {
    const WIKI_NOTATION = `* item1
* item2
  still item2
  * item3

h2. header`;

    checkParseEncodeRoundTrips(
      WIKI_NOTATION,
      defaultSchema,
      WIKI_NOTATION,
      doc(
        ul(
          li(p('item1')),
          li(p('item2', hardBreak(), 'still item2')),
          li(p('item3')),
        ),
        h2('header'),
      ),
    );
  }


export interface AchievementTranslation {
	moduleName: string
	details: string
	done: string
	rewards: string
	experience: string
	coins: string
}


() => {
    console.info('The application was started! Kill it using Ctrl + C')
}


@Module({
  controllers: [BotsController],
  providers: [BotsService]
})
export class BotsModule {}


p => p.name === 'medianBlur'


p => p.name === 'canny'


/**
 * This is a high level API for flood fill given color or image starting from given [seed] coords and involves several opencv operations.
 */
export class FloodFill extends AbstractOperation<FloodFillOptions> {
  name = "FloodFill"
  description = 'This is a high level API for flood fill given color or image starting from given [seed] coords and involves several opencv operations. '
  sameSizeAndType = true

  protected _exec(o: FloodFillOptions) {
    const preprocess = o.preprocess || [{ name: 'medianBlur' }, { name: 'canny' }]
    const dst = o.dst = o.dst || new cv.Mat()
    o.src.copyTo(dst)
    const blur = preprocess.find(p => p.name === 'medianBlur') as any as MedianBlurConcreteOptions
    if (blur) {
      cv.medianBlur(o.src, dst, toNumber(blur.ksize || 3))
    }
    cv.cvtColor(dst, dst, cv.CV_8UC1, 3)
    const mask = cv.Mat.zeros(dst.rows + 2, dst.cols + 2, cv.CV_8UC1)
    const canny = preprocess.find(p => p.name === 'canny') as CannyConcreteOptions
    if (canny) {
      cv.Canny(dst, mask, canny.threshold1 || 0, canny.threshold2 || 255) // heads up ! dst needs to be bigger!
      cv.copyMakeBorder(mask, mask, 1, 1, 1, 1, cv.BORDER_REPLICATE) // that's why we need to copy again
    } else {
      cv.copyMakeBorder(dst, mask, 1, 1, 1, 1, cv.BORDER_REPLICATE)
    }
    const fillValue = 128
    cv.floodFill(dst, mask, o.seed, new cv.Scalar(255, 255, 255, 255), 0, o.lowDiff || new cv.Scalar(255, 255, 255, 255),
      o.upDiff || new cv.Scalar(255, 255, 255, 255), (o.connectivity || 4) | cv.FLOODFILL_MASK_ONLY | (fillValue << 8))
    // mask has canny edges in 255 and fill in 128 - we keep with just 128:
    cv.inRange(mask, new cv.Mat(mask.rows, mask.cols, mask.type(), new cv.Scalar(128, 128, 128)),
      new cv.Mat(mask.rows, mask.cols, mask.type(), new cv.Scalar(128, 128, 128)), mask)
    const dst2 = cv.Mat.zeros(o.src.rows + 2, o.src.cols + 2, o.src.type())
    cv.copyMakeBorder(o.src, dst2, 1, 1, 1, 1, cv.BORDER_REPLICATE)
    //copy b= o.newColorOrImage mask(dst2)
    const b = isMat(o.newColorOrImage) ? o.newColorOrImage : new cv.Mat(dst2.rows, dst2.cols, dst2.type(), o.newColorOrImage)
    b.copyTo(dst2, mask)
    // idea : o.src.copyTo(dst2, maskNegated)
    const r = dst2.roi({ x: 1, y: 1, width: mask.cols - 2, height: mask.rows - 2 })
    r.copyTo(dst)
    del(mask, dst2, r, ...isMat(o.newColorOrImage) ? [] : [b])
  }
}


export interface FloodFillOptions extends OperationExecBaseOptions {
  seed: Point;
  preprocess?: FloodFillPreprocess[]
  newColorOrImage?: Scalar | number[] | Mat;
  connectivity?: 4 | 8;
  lowDiff?: Scalar | number[]
  upDiff?: Scalar | number[]
}


export type FloodFillPreprocess = ({ name: 'canny' } & CannyConcreteOptions) | ({ name: 'medianBlur' } & MedianBlurConcreteOptions)


protected _exec(o: FloodFillOptions) {
    const preprocess = o.preprocess || [{ name: 'medianBlur' }, { name: 'canny' }]
    const dst = o.dst = o.dst || new cv.Mat()
    o.src.copyTo(dst)
    const blur = preprocess.find(p => p.name === 'medianBlur') as any as MedianBlurConcreteOptions
    if (blur) {
      cv.medianBlur(o.src, dst, toNumber(blur.ksize || 3))
    }
    cv.cvtColor(dst, dst, cv.CV_8UC1, 3)
    const mask = cv.Mat.zeros(dst.rows + 2, dst.cols + 2, cv.CV_8UC1)
    const canny = preprocess.find(p => p.name === 'canny') as CannyConcreteOptions
    if (canny) {
      cv.Canny(dst, mask, canny.threshold1 || 0, canny.threshold2 || 255) // heads up ! dst needs to be bigger!
      cv.copyMakeBorder(mask, mask, 1, 1, 1, 1, cv.BORDER_REPLICATE) // that's why we need to copy again
    } else {
      cv.copyMakeBorder(dst, mask, 1, 1, 1, 1, cv.BORDER_REPLICATE)
    }
    const fillValue = 128
    cv.floodFill(dst, mask, o.seed, new cv.Scalar(255, 255, 255, 255), 0, o.lowDiff || new cv.Scalar(255, 255, 255, 255),
      o.upDiff || new cv.Scalar(255, 255, 255, 255), (o.connectivity || 4) | cv.FLOODFILL_MASK_ONLY | (fillValue << 8))
    // mask has canny edges in 255 and fill in 128 - we keep with just 128:
    cv.inRange(mask, new cv.Mat(mask.rows, mask.cols, mask.type(), new cv.Scalar(128, 128, 128)),
      new cv.Mat(mask.rows, mask.cols, mask.type(), new cv.Scalar(128, 128, 128)), mask)
    const dst2 = cv.Mat.zeros(o.src.rows + 2, o.src.cols + 2, o.src.type())
    cv.copyMakeBorder(o.src, dst2, 1, 1, 1, 1, cv.BORDER_REPLICATE)
    //copy b= o.newColorOrImage mask(dst2)
    const b = isMat(o.newColorOrImage) ? o.newColorOrImage : new cv.Mat(dst2.rows, dst2.cols, dst2.type(), o.newColorOrImage)
    b.copyTo(dst2, mask)
    // idea : o.src.copyTo(dst2, maskNegated)
    const r = dst2.roi({ x: 1, y: 1, width: mask.cols - 2, height: mask.rows - 2 })
    r.copyTo(dst)
    del(mask, dst2, r, ...isMat(o.newColorOrImage) ? [] : [b])
  }


() => parseMessageDescription(tokenAccessor, entityLookup)


lookupEntity (id: string): Entity | undefined {
        return id === foo.id ? foo : (id === bar.id ? bar : undefined)
      }


export function AlertingSettings<T extends AlertingConfig>({
  alertmanagerDataSources,
  options,
  onOptionsChange,
}: Props<T>): JSX.Element {
  const alertmanagerOptions = useMemo(
    () =>
      alertmanagerDataSources.map((ds) => ({
        label: ds.name,
        value: ds.uid,
        imgUrl: ds.meta.info.logos.small,
        meta: ds.meta,
      })),
    [alertmanagerDataSources]
  );

  return (
    <>

Alerting

            <Switch
              label="Manage alerts via Alerting UI"
              labelClass="width-13"
              checked={options.jsonData.manageAlerts !== false}
              onChange={(event) =>
                onOptionsChange({
                  ...options,
                  jsonData: { ...options.jsonData, manageAlerts: event!.currentTarget.checked },
                })
              }


() =>
      alertmanagerDataSources.map((ds) => ({
        label: ds.name,
        value: ds.uid,
        imgUrl: ds.meta.info.logos.small,
        meta: ds.meta,
      }))


(ds) => ({
        label: ds.name,
        value: ds.uid,
        imgUrl: ds.meta.info.logos.small,
        meta: ds.meta,
      })


interface Props<T> extends Pick<DataSourcePluginOptionsEditorProps<T>, 'options' | 'onOptionsChange'> {
  alertmanagerDataSources: Array<DataSourceInstanceSettings<DataSourceJsonData>>;
}


interface AlertingConfig extends DataSourceJsonData {
  manageAlerts?: boolean;
}