async (resolve, reject) => {
    const aVar = makeVar(123);
    const bVar = makeVar("asdf");
    const aSpy = jest.spyOn(aVar, "forgetCache");
    const bSpy = jest.spyOn(bVar, "forgetCache");
    const cache: InMemoryCache = new InMemoryCache({
      typePolicies: {
        Query: {
          fields: {
            a() {
              return aVar();
            },
            b() {
              return bVar();
            },
          },
        },
      },
    });

    const client = new ApolloClient({ cache });

    const obsQueries = new Set<ObservableQuery<any>>();
    const subs = new Set<ObservableSubscription>();
    function watch(
      query: DocumentNode,
      fetchPolicy: WatchQueryFetchPolicy = "cache-first",
    ): any[] {
      const results: any[] = [];
      const obsQuery = client.watchQuery({
        query,
        fetchPolicy,
      });
      obsQueries.add(obsQuery);
      subs.add(obsQuery.subscribe({
        next(result) {
          results.push(result.data);
        },
      }));
      return results;
    }

    const aQuery = gql`{ a }`;
    const bQuery = gql`{ b }`;
    const abQuery = gql`{ a b }`;

    const aResults = watch(aQuery);
    const bResults = watch(bQuery);

    expect(cache["watches"].size).toBe(2);

    expect(aResults).toEqual([]);
    expect(bResults).toEqual([]);

    expect(aSpy).not.toBeCalled();
    expect(bSpy).not.toBeCalled();

    subs.forEach(sub => sub.unsubscribe());

    expect(aSpy).toBeCalledTimes(1);
    expect(aSpy).toBeCalledWith(cache);
    expect(bSpy).toBeCalledTimes(1);
    expect(bSpy).toBeCalledWith(cache);

    expect(aResults).toEqual([]);
    expect(bResults).toEqual([]);

    expect(cache["watches"].size).toBe(0);
    const abResults = watch(abQuery);
    expect(abResults).toEqual([]);
    expect(cache["watches"].size).toBe(1);

    await wait();

    expect(aResults).toEqual([]);
    expect(bResults).toEqual([]);
    expect(abResults).toEqual([
      { a: 123, b: "asdf" }
    ]);

    client.stop();

    await wait();

    expect(aSpy).toBeCalledTimes(2);
    expect(aSpy).toBeCalledWith(cache);
    expect(bSpy).toBeCalledTimes(2);
    expect(bSpy).toBeCalledWith(cache);

    resolve();
  }


() => {
    const query = gql`
      query number {
        myNumber {
          n
        }
      }
    `;

    const initialData = {
      myNumber: {
        n: 1,
      },
    };
    const networkFetch = {
      myNumber: {
        n: 2,
      },
    };

    itAsync('allows setting default options for watchQuery', (resolve, reject) => {
      const link = mockSingleLink({
        request: { query },
        result: { data: networkFetch },
      }).setOnError(reject);
      const client = new ApolloClient({
        link,
        cache: new InMemoryCache({ addTypename: false }),
        defaultOptions: {
          watchQuery: {
            fetchPolicy: 'cache-and-network',
          },
        },
      });

      client.writeQuery({
        query,
        data: initialData,
      });

      const obs = client.watchQuery({
        query,
        // This undefined value should be ignored in favor of
        // defaultOptions.watchQuery.fetchPolicy.
        fetchPolicy: void 0,
      });

      subscribeAndCount(reject, obs, (handleCount, result) => {
        const resultData = result.data;
        if (handleCount === 1) {
          expect(resultData).toEqual(initialData);
        } else if (handleCount === 2) {
          expect(resultData).toEqual(networkFetch);
          resolve();
        }
      });
    });

    itAsync('allows setting nextFetchPolicy in defaultOptions', (resolve, reject) => {
      let networkCounter = 0;
      let nextFetchPolicyCallCount = 0;

      const client = new ApolloClient({
        link: new ApolloLink(operation => new Observable(observer => {
          observer.next({
            data: {
              count: networkCounter++,
            },
          });
          observer.complete();
        })),

        cache: new InMemoryCache,

        defaultOptions: {
          watchQuery: {
            nextFetchPolicy(fetchPolicy) {
              expect(++nextFetchPolicyCallCount).toBe(1);
              expect(this.query).toBe(query);
              expect(fetchPolicy).toBe("cache-first");
              // Usually options.nextFetchPolicy applies only once, but a
              // nextFetchPolicy function can set this.nextFetchPolicy
              // again to perform an additional transition.
              this.nextFetchPolicy = fetchPolicy => {
                ++nextFetchPolicyCallCount;
                return "cache-first";
              };
              return "cache-and-network";
            },
          },
        },
      });

      const query = gql`
        query {
          count
        }
      `;

      client.writeQuery({
        query,
        data: {
          count: "initial",
        },
      });

      const obs = client.watchQuery({ query });

      subscribeAndCount(reject, obs, (handleCount, result) => {
        if (handleCount === 1) {
          expect(nextFetchPolicyCallCount).toBe(1);
          expect(result.data).toEqual({ count: "initial" });
          // Refetching makes a copy of the current options, which
          // includes options.nextFetchPolicy, so the inner
          // nextFetchPolicy function ends up getting called twice.
          obs.refetch();
        } else if (handleCount === 2) {
          expect(result.data).toEqual({ count: "initial" });
          expect(nextFetchPolicyCallCount).toBe(2);
        } else if (handleCount === 3) {
          expect(result.data).toEqual({ count: 0 });
          expect(nextFetchPolicyCallCount).toBe(2);
          client.writeQuery({
            query,
            data: {
              count: "secondary",
            },
          });
        } else if (handleCount === 4) {
          expect(result.data).toEqual({ count: "secondary" });
          expect(nextFetchPolicyCallCount).toBe(3);
        } else if (handleCount === 5) {
          expect(result.data).toEqual({ count: 1 });
          expect(nextFetchPolicyCallCount).toBe(3);
          client.cache.evict({ fieldName: "count" });
        } else if (handleCount === 6) {
          expect(result.data).toEqual({ count: 2 });
          expect(nextFetchPolicyCallCount).toBe(4);
          expect(obs.options.fetchPolicy).toBe("cache-first");
          setTimeout(resolve, 50);
        } else {
          reject("too many results");
        }
      });
    });

    itAsync('allows setting default options for query', (resolve, reject) => {
      const errors = [{ message: 'failure', name: 'failure' }];
      const link = mockSingleLink({
        request: { query },
        result: { errors },
      }).setOnError(reject);
      const client = new ApolloClient({
        link,
        cache: new InMemoryCache({ addTypename: false }),
        defaultOptions: {
          query: { errorPolicy: 'all' },
        },
      });

      return client.query({ query }).then(result => {
        expect(result.errors).toEqual(errors);
      }).then(resolve, reject);
    });

    itAsync('allows setting default options for mutation', (resolve, reject) => {
      const mutation = gql`
        mutation upVote($id: ID!) {
          upvote(id: $id) {
            success
          }
        }
      `;

      const data = {
        upvote: { success: true },
      };

      const link = mockSingleLink({
        request: { query: mutation, variables: { id: 1 } },
        result: { data },
      }).setOnError(reject);

      const client = new ApolloClient({
        link,
        cache: new InMemoryCache({ addTypename: false }),
        defaultOptions: {
          mutate: { variables: { id: 1 } },
        },
      });

      return client.mutate({
        mutation,
        // This undefined value should be ignored in favor of
        // defaultOptions.mutate.variables.
        variables: void 0,
      }).then(result => {
        expect(result.data).toEqual(data);
      }).then(resolve, reject);
    });
  }


(resolve, reject) => {
      const link = mockSingleLink({
        request: { query },
        result: { data: networkFetch },
      }).setOnError(reject);
      const client = new ApolloClient({
        link,
        cache: new InMemoryCache({ addTypename: false }),
        defaultOptions: {
          watchQuery: {
            fetchPolicy: 'cache-and-network',
          },
        },
      });

      client.writeQuery({
        query,
        data: initialData,
      });

      const obs = client.watchQuery({
        query,
        // This undefined value should be ignored in favor of
        // defaultOptions.watchQuery.fetchPolicy.
        fetchPolicy: void 0,
      });

      subscribeAndCount(reject, obs, (handleCount, result) => {
        const resultData = result.data;
        if (handleCount === 1) {
          expect(resultData).toEqual(initialData);
        } else if (handleCount === 2) {
          expect(resultData).toEqual(networkFetch);
          resolve();
        }
      });
    }


(handleCount, result) => {
        const resultData = result.data;
        if (handleCount === 1) {
          expect(resultData).toEqual(initialData);
        } else if (handleCount === 2) {
          expect(resultData).toEqual(networkFetch);
          resolve();
        }
      }


(resolve, reject) => {
      let networkCounter = 0;
      let nextFetchPolicyCallCount = 0;

      const client = new ApolloClient({
        link: new ApolloLink(operation => new Observable(observer => {
          observer.next({
            data: {
              count: networkCounter++,
            },
          });
          observer.complete();
        })),

        cache: new InMemoryCache,

        defaultOptions: {
          watchQuery: {
            nextFetchPolicy(fetchPolicy) {
              expect(++nextFetchPolicyCallCount).toBe(1);
              expect(this.query).toBe(query);
              expect(fetchPolicy).toBe("cache-first");
              // Usually options.nextFetchPolicy applies only once, but a
              // nextFetchPolicy function can set this.nextFetchPolicy
              // again to perform an additional transition.
              this.nextFetchPolicy = fetchPolicy => {
                ++nextFetchPolicyCallCount;
                return "cache-first";
              };
              return "cache-and-network";
            },
          },
        },
      });

      const query = gql`
        query {
          count
        }
      `;

      client.writeQuery({
        query,
        data: {
          count: "initial",
        },
      });

      const obs = client.watchQuery({ query });

      subscribeAndCount(reject, obs, (handleCount, result) => {
        if (handleCount === 1) {
          expect(nextFetchPolicyCallCount).toBe(1);
          expect(result.data).toEqual({ count: "initial" });
          // Refetching makes a copy of the current options, which
          // includes options.nextFetchPolicy, so the inner
          // nextFetchPolicy function ends up getting called twice.
          obs.refetch();
        } else if (handleCount === 2) {
          expect(result.data).toEqual({ count: "initial" });
          expect(nextFetchPolicyCallCount).toBe(2);
        } else if (handleCount === 3) {
          expect(result.data).toEqual({ count: 0 });
          expect(nextFetchPolicyCallCount).toBe(2);
          client.writeQuery({
            query,
            data: {
              count: "secondary",
            },
          });
        } else if (handleCount === 4) {
          expect(result.data).toEqual({ count: "secondary" });
          expect(nextFetchPolicyCallCount).toBe(3);
        } else if (handleCount === 5) {
          expect(result.data).toEqual({ count: 1 });
          expect(nextFetchPolicyCallCount).toBe(3);
          client.cache.evict({ fieldName: "count" });
        } else if (handleCount === 6) {
          expect(result.data).toEqual({ count: 2 });
          expect(nextFetchPolicyCallCount).toBe(4);
          expect(obs.options.fetchPolicy).toBe("cache-first");
          setTimeout(resolve, 50);
        } else {
          reject("too many results");
        }
      });
    }


operation => new Observable(observer => {
          observer.next({
            data: {
              count: networkCounter++,
            },
          });
          observer.complete();
        })


observer => {
          observer.next({
            data: {
              count: networkCounter++,
            },
          });
          observer.complete();
        }


fetchPolicy => {
                ++nextFetchPolicyCallCount;
                return "cache-first";
              }


(handleCount, result) => {
        if (handleCount === 1) {
          expect(nextFetchPolicyCallCount).toBe(1);
          expect(result.data).toEqual({ count: "initial" });
          // Refetching makes a copy of the current options, which
          // includes options.nextFetchPolicy, so the inner
          // nextFetchPolicy function ends up getting called twice.
          obs.refetch();
        } else if (handleCount === 2) {
          expect(result.data).toEqual({ count: "initial" });
          expect(nextFetchPolicyCallCount).toBe(2);
        } else if (handleCount === 3) {
          expect(result.data).toEqual({ count: 0 });
          expect(nextFetchPolicyCallCount).toBe(2);
          client.writeQuery({
            query,
            data: {
              count: "secondary",
            },
          });
        } else if (handleCount === 4) {
          expect(result.data).toEqual({ count: "secondary" });
          expect(nextFetchPolicyCallCount).toBe(3);
        } else if (handleCount === 5) {
          expect(result.data).toEqual({ count: 1 });
          expect(nextFetchPolicyCallCount).toBe(3);
          client.cache.evict({ fieldName: "count" });
        } else if (handleCount === 6) {
          expect(result.data).toEqual({ count: 2 });
          expect(nextFetchPolicyCallCount).toBe(4);
          expect(obs.options.fetchPolicy).toBe("cache-first");
          setTimeout(resolve, 50);
        } else {
          reject("too many results");
        }
      }


(resolve, reject) => {
      const errors = [{ message: 'failure', name: 'failure' }];
      const link = mockSingleLink({
        request: { query },
        result: { errors },
      }).setOnError(reject);
      const client = new ApolloClient({
        link,
        cache: new InMemoryCache({ addTypename: false }),
        defaultOptions: {
          query: { errorPolicy: 'all' },
        },
      });

      return client.query({ query }).then(result => {
        expect(result.errors).toEqual(errors);
      }).then(resolve, reject);
    }


result => {
        expect(result.errors).toEqual(errors);
      }


(resolve, reject) => {
      const mutation = gql`
        mutation upVote($id: ID!) {
          upvote(id: $id) {
            success
          }
        }
      `;

      const data = {
        upvote: { success: true },
      };

      const link = mockSingleLink({
        request: { query: mutation, variables: { id: 1 } },
        result: { data },
      }).setOnError(reject);

      const client = new ApolloClient({
        link,
        cache: new InMemoryCache({ addTypename: false }),
        defaultOptions: {
          mutate: { variables: { id: 1 } },
        },
      });

      return client.mutate({
        mutation,
        // This undefined value should be ignored in favor of
        // defaultOptions.mutate.variables.
        variables: void 0,
      }).then(result => {
        expect(result.data).toEqual(data);
      }).then(resolve, reject);
    }


result => {
        expect(result.data).toEqual(data);
      }


result => {
    expect(result.data).toEqual(data.data);
  }


next() {
        throw expectedError;
      }


next() {
        reject(new Error('did not expect next to be called'));
      }


error() {
        throw expectedError;
      }


next(result) {
        expect(result.data).toEqual(data);
        resolve();
      }


next() {
        client
          .mutate({ mutation, updateQueries, update: updateSpy })
          .then(() => {
            expect(queryUpdaterSpy).toBeCalled();
            expect(updateSpy).toBeCalled();
            sub.unsubscribe();
            resolve();
          })
          .catch(err => {
            reject(err);
          });
      }


error(err) {
        reject(err);
      }


error(error) {
        expect(error.message).toBe('Uh oh!');
        resolve();
      }


next(result: any) {
        try {
          switch (count++) {
            case 0:
              if (!result.data!.allPeople) {
                reject('Should have data by this point');
                break;
              }
              // First result is loaded, run a refetch to get the second result
              // which is an error.
              expect(result.loading).toBeFalsy();
              expect(result.networkStatus).toBe(7);
              expect(result.data!.allPeople).toEqual(
                data.allPeople,
              );
              setTimeout(() => {
                observable.refetch().then(() => {
                  reject('Expected error value on first refetch.');
                }, noop);
              }, 0);
              break;
            case 1:
              // Waiting for the second result to load
              expect(result.loading).toBeTruthy();
              expect(result.networkStatus).toBe(4);
              break;
            // case 2 is handled by the error callback
            case 3:
              expect(result.loading).toBeTruthy();
              expect(result.networkStatus).toBe(4);
              expect(result.errors).toBeFalsy();
              break;
            case 4:
              // Third result's data is loaded
              expect(result.loading).toBeFalsy();
              expect(result.networkStatus).toBe(7);
              expect(result.errors).toBeFalsy();
              if (!result.data) {
                reject('Should have data by this point');
                break;
              }
              expect(result.data.allPeople).toEqual(
                dataTwo.allPeople,
              );
              resolve();
              break;
            default:
              throw new Error('Unexpected fall through');
          }
        } catch (e) {
          reject(e);
        }
      }


error(error: Error) {
        expect(count++).toBe(2);
        expect(error.message).toBe('This is an error!');

        subscription.unsubscribe();

        const lastError = observable.getLastError();
        expect(lastError).toBeInstanceOf(ApolloError);
        expect(lastError!.networkError).toEqual(error);

        const lastResult = observable.getLastResult();
        expect(lastResult).toBeTruthy();
        expect(lastResult!.loading).toBe(false);
        expect(lastResult!.networkStatus).toBe(8);

        observable.resetLastResults();
        subscription = observable.subscribe(observerOptions);

        // The error arrived, run a refetch to get the third result
        // which should now contain valid data.
        setTimeout(() => {
          observable.refetch().catch(() => {
            reject('Expected good data on second refetch.');
          });
        }, 0);
      }


a() {
              return aVar();
            }


b() {
              return bVar();
            }


next(result) {
          results.push(result.data);
        }


c(value) {
          expect(value).toBe("see");
          return "saw";
        }


nextFetchPolicy(fetchPolicy) {
              expect(++nextFetchPolicyCallCount).toBe(1);
              expect(this.query).toBe(query);
              expect(fetchPolicy).toBe("cache-first");
              // Usually options.nextFetchPolicy applies only once, but a
              // nextFetchPolicy function can set this.nextFetchPolicy
              // again to perform an additional transition.
              this.nextFetchPolicy = fetchPolicy => {
                ++nextFetchPolicyCallCount;
                return "cache-first";
              };
              return "cache-and-network";
            }


() => {
											this.props.removeToast({ id: toast.id });
										}


finished => {
				this.shouldUpdate = true;
				this.setState({
					controls: nextProps.dynamic.controls,
				});
			}


class DynamicControl extends React.Component<Prop, State> {
	_defaultOptions = {};
	shouldUpdate = true;
	state = {
		controls: {},
		toasts: [],
	};
	constructor(props: any) {
		super(props);
		this.state.toasts = this.props.dynamic.toasts || [];
	}
	_getControls(controlsState: any) {
		var arr = [];
		for (var key in controlsState) {
			if (!Object.prototype.hasOwnProperty.call(controlsState, key)) continue;
			var cs = controlsState[key];
			if (cs.options.animationX || cs.options.animationY) {
				arr.push(
					<SlideUpDownViewControl ref={key} key={key} style={{ position: 'absolute', left: 0, right: 0, top: 0, bottom: 0 }} options={cs.options}>
						{cs.comp}
					</SlideUpDownViewControl>,
				);
			} else {
				arr.push(
					<View ref={key} key={key} style={{ position: 'absolute', left: 0, right: 0, top: 0, bottom: 0 }}>
						{cs.comp}
					</View>,
				);
			}
		}


interface Prop {
	dynamic: any;
	removeToast: any;
}


interface State {
	controls: any;
	toasts: any;
}


_getControls(controlsState: any) {
		var arr = [];
		for (var key in controlsState) {
			if (!Object.prototype.hasOwnProperty.call(controlsState, key)) continue;
			var cs = controlsState[key];
			if (cs.options.animationX || cs.options.animationY) {
				arr.push(
					<SlideUpDownViewControl ref={key} key={key} style={{ position: 'absolute', left: 0, right: 0, top: 0, bottom: 0 }} options={cs.options}>
						{cs.comp}
					</SlideUpDownViewControl>,
				);
			} else {
				arr.push(
					<View ref={key} key={key} style={{ position: 'absolute', left: 0, right: 0, top: 0, bottom: 0 }}>
						{cs.comp}
					</View>,
				);
			}


export default class CompleteActivityRequestRepository
  implements ICompleteActivityRequestRepository {
  public async findAllFromGame(
    gameId: string,
  ): Promise<ICompleteActivityRequest[]> {
    return CompleteActivityRequest.find({ game: gameId })
      .populate('activity')
      .populate({
        path: 'requester',
        populate: {
          path: 'user',
        },
      })
      .sort({ requestDate: -1 });
  }

  public async findOne(
    id: string,
  ): Promise<ICompleteActivityRequest | undefined> {
    if (!isValidObjectId(id))
      throw new RequestError('Id is invalid!', errorCodes.INVALID_ID);

    const request = await CompleteActivityRequest.findById(id)
      .populate('activity')
      .populate({
        path: 'requester',
        populate: {
          path: 'user',
        },
      });

    return request || undefined;
  }

  public async create(
    {
      requester,
      activity,
      requestDate,
      completionDate,
      information,
      game,
    }: CreateCompleteActivityRequestAdapter,
    session?: ClientSession,
  ): Promise<ICompleteActivityRequest> {
    const [result] = await CompleteActivityRequest.create(
      [
        {
          requester,
          activity,
          requestDate,
          completionDate,
          information,
          game,
        },
      ],
      { session },
    );

    return result;
  }

  public async delete(
    id: string,
    gameId: string,
    session?: ClientSession,
  ): Promise<void> {
    if (!isValidObjectId(id))
      throw new RequestError('Id is invalid!', errorCodes.INVALID_ID);

    await CompleteActivityRequest.deleteOne(
      { _id: id, game: gameId },
      { session },
    );
  }
}


public async findAllFromGame(
    gameId: string,
  ): Promise<ICompleteActivityRequest[]> {
    return CompleteActivityRequest.find({ game: gameId })
      .populate('activity')
      .populate({
        path: 'requester',
        populate: {
          path: 'user',
        },
      })
      .sort({ requestDate: -1 });
  }


public async findOne(
    id: string,
  ): Promise<ICompleteActivityRequest | undefined> {
    if (!isValidObjectId(id))
      throw new RequestError('Id is invalid!', errorCodes.INVALID_ID);

    const request = await CompleteActivityRequest.findById(id)
      .populate('activity')
      .populate({
        path: 'requester',
        populate: {
          path: 'user',
        },
      });

    return request || undefined;
  }


public async create(
    {
      requester,
      activity,
      requestDate,
      completionDate,
      information,
      game,
    }: CreateCompleteActivityRequestAdapter,
    session?: ClientSession,
  ): Promise<ICompleteActivityRequest> {
    const [result] = await CompleteActivityRequest.create(
      [
        {
          requester,
          activity,
          requestDate,
          completionDate,
          information,
          game,
        },
      ],
      { session },
    );

    return result;
  }


public async delete(
    id: string,
    gameId: string,
    session?: ClientSession,
  ): Promise<void> {
    if (!isValidObjectId(id))
      throw new RequestError('Id is invalid!', errorCodes.INVALID_ID);

    await CompleteActivityRequest.deleteOne(
      { _id: id, game: gameId },
      { session },
    );
  }


/**
 * Install all exarcheia-element components into Vue.
 * Please do not invoke this method directly.
 * Call `Vue.use(ElementUI)` to install.
 */
export function install (vue: typeof Vue, options: InstallationOptions): void


// TS cannot merge imported class with namespace, so declare subclasses instead
/** Alert Component */
export class Alert extends ElAlert {}


/** Aside Component */
export class Aside extends ElAside {}


/** Autocomplete Component */
export class Autocomplete extends ElAutocomplete {}


/** Bagde Component */
export class Badge extends ElBadge {}


/** Breadcrumb Component */
export class Breadcrumb extends ElBreadcrumb {}


/** Breadcrumb Item Component */
export class BreadcrumbItem extends ElBreadcrumbItem {}


/** Button Component */
export class Button extends ElButton {}


/** Button Group Component */
export class ButtonGroup extends ElButtonGroup {}


/** Card Component */
export class Card extends ElCard {}


/** Cascader Component */
export class Cascader extends ElCascader {}


/** Carousel Component */
export class Carousel extends ElCarousel {}


/** Carousel Item Component */
export class CarouselItem extends ElCarouselItem {}


/** Checkbox Component */
export class Checkbox extends ElCheckbox {}


/** Checkbox Button Component */
export class CheckboxButton extends ElCheckboxButton {}


/** Checkbox Group Component */
export class CheckboxGroup extends ElCheckboxGroup {}


/** Colunm Layout Component */
export class Col extends ElCol {}


/** Collapse Component */
export class Collapse extends ElCollapse {}


/** Collapse Item Component */
export class CollapseItem extends ElCollapseItem {}


/** Color Picker Component */
export class ColorPicker extends ElColorPicker {}


/** Container Component */
export class Container extends ElContainer {}


/** Date Picker Component */
export class DatePicker extends ElDatePicker {}


/** Dialog Component */
export class Dialog extends ElDialog {}


/** Dropdown Component */
export class Dropdown extends ElDropdown {}


/** Dropdown Item Component */
export class DropdownItem extends ElDropdownItem {}


/** Dropdown Menu Component */
export class DropdownMenu extends ElDropdownMenu {}


/** Footer Component */
export class Footer extends ElFooter {}


/** Form Component */
export class Form extends ElForm {}


/** Form Item Component */
export class FormItem extends ElFormItem {}


/** Header Component */
export class Header extends ElHeader {}


/** Input Component */
export class Input extends ElInput {}


/** Input Number Component */
export class InputNumber extends ElInputNumber {}


/** Main Component */
export class Main extends ElMain {}


/** Menu that provides navigation for your website */
export class Menu extends ElMenu {}


/** Menu Item Component */
export class MenuItem extends ElMenuItem {}


/** Menu Item Group Component */
export class MenuItemGroup extends ElMenuItemGroup {}


/** Dropdown Select Option Component */
export class Option extends ElOption {}


/** Dropdown Select Option Group Component */
export class OptionGroup extends ElOptionGroup {}


/** Pagination Component */
export class Pagination extends ElPagination {}


/** Popover Component */
export class Popover extends ElPopover {}


/** Progress Component */
export class Progress extends ElProgress {}


/** Rate Component */
export class Rate extends ElRate {}


/** Radio Component */
export class Radio extends ElRadio {}


/** Radio Button Component */
export class RadioButton extends ElRadioButton {}


/** Radio Group Component */
export class RadioGroup extends ElRadioGroup {}


/** Row Layout Component */
export class Row extends ElRow {}


/** Dropdown Select Component */
export class Select extends ElSelect {}


/** Slider Component */
export class Slider extends ElSlider {}


/** Step Component */
export class Step extends ElStep {}


/** Steps Component */
export class Steps extends ElSteps {}


/** Submenu Component */
export class Submenu extends ElSubmenu {}


/** Switch Component */
export class Switch extends ElSwitch {}


/** Table Component */
export class Table extends ElTable {}


/** Table Column Component */
export class TableColumn extends ElTableColumn {}


/** Tabs Component */
export class Tabs extends ElTabs {}


/** Tab Pane Component */
export class TabPane extends ElTabPane {}


/** Tag Component */
export class Tag extends ElTag {}


/** Timeline Component */
export class Timeline extends ElTimeline {}


/** Timeline Item Component */
export class TimelineItem extends ElTimelineItem {}


/** TimePicker Component */
export class TimePicker extends ElTimePicker {}


/** TimeSelect Component */
export class TimeSelect extends ElTimeSelect {}


/** Tooltip Component */
export class Tooltip extends ElTooltip {}


/** Transfer Component */
export class Transfer extends ElTransfer {}


/** Tree Component */
export class Tree<K = any, D = TreeData> extends ElTree<K, D> {}


/** Upload Component */
export class Upload extends ElUpload {}


/** Divider Component */
export class Divider extends ElDivider {}


/** Link Component */
export class Link extends ElLink {}


/** Image Component */
export class Image extends ElImage {}


/** Icon Component */
export class Icon extends ElIcon {}


/** Calendar Component */
export class Calendar extends ElCalendar {}


/** Backtop Component */
export class Backtop extends ElBacktop {}


/** PageHeader Component */
export class PageHeader extends ElPageHeader {}


/** Avatar Component */
export class Avatar extends ElAvatar {}


/** Drawer Component */
export class Drawer extends ElDrawer {}


/** Popconfirm Component */
export class Popconfirm extends ElPopconfirm {}


export interface InstallationOptions {
  locale: any,
  i18n: any,
  size: string
}


/** ElementUI component common definition */
export type Component = ElementUIComponent


/** Component size definition for button, input, etc */
export type ComponentSize = ElementUIComponentSize


/** Horizontal alignment */
export type HorizontalAlignment = ElementUIHorizontalAlignment


position => {
            this.singleProductsCache.set(url, position);
        }


position => {
            cache.set(url, position);
        }


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

    catalogProductsCache = new Map();
    filteredProductsCache = new Map();
    singleProductsCache = new Map();

    constructor(private http: HttpClient) {

    }

    create(form: Product, images?: File[]): Observable<Product> {
        const fd = new FormData();

        if (images) {
            for (let image of images) {
                fd.append('images', image, image.name);
            }
        }
        fd.append('price', form.price);
        fd.append('name', form.name);
        fd.append('weight', String(form.weight));
        fd.append('currency', form.currency);
        fd.append('description', form.description);
        fd.append('bonuses', JSON.stringify(form.bonuses));
        fd.append('category', JSON.stringify(form.category));
        fd.append('chartDays', JSON.stringify(form.chartDays));
        fd.append('customFields', JSON.stringify(form.customFields));

        return this.http.post<Product>('/api/product/uploadMultipleFiles', fd);
    }

    getByFilters(category: string = '%', day: string = '%'): Observable<Product[]> {
        const url = `/api/product/getByFilters?category=${category}&day=${day}`;
        return this.toCache(url, this.filteredProductsCache);
    }

    getById(id: string): Observable<Product> {
        const url = `/api/product/getById/${id}`;
        const productsFromCache = this.singleProductsCache.get(url);
        if (productsFromCache) {
            return of(productsFromCache)
        }
        const response = this.http.get<Product>(url);
        response.subscribe(position => {
            this.singleProductsCache.set(url, position);
        });
        return response;
    }

    getProducts(limit: number = 8): Observable<Product[]> {
        return this.http.get<Product[]>(`/api/product/getProducts?limit=${limit}`);
    }

    getAll(): Observable<Product[]> {
        const url = '/api/product/getAll';
        return this.toCache(url, this.catalogProductsCache);
    }

    toCache(url: string, cache: any): Observable<Product[]> {
        const productsFromCache = cache.get(url);
        if (productsFromCache) {
            return of(productsFromCache)
        }
        const response = this.http.get<Product[]>(url);
        response.subscribe(position => {
            cache.set(url, position);
        });
        return response;
    }

}


create(form: Product, images?: File[]): Observable<Product> {
        const fd = new FormData();

        if (images) {
            for (let image of images) {
                fd.append('images', image, image.name);
            }
        }
        fd.append('price', form.price);
        fd.append('name', form.name);
        fd.append('weight', String(form.weight));
        fd.append('currency', form.currency);
        fd.append('description', form.description);
        fd.append('bonuses', JSON.stringify(form.bonuses));
        fd.append('category', JSON.stringify(form.category));
        fd.append('chartDays', JSON.stringify(form.chartDays));
        fd.append('customFields', JSON.stringify(form.customFields));

        return this.http.post<Product>('/api/product/uploadMultipleFiles', fd);
    }


getByFilters(category: string = '%', day: string = '%'): Observable<Product[]> {
        const url = `/api/product/getByFilters?category=${category}&day=${day}`;
        return this.toCache(url, this.filteredProductsCache);
    }


getById(id: string): Observable<Product> {
        const url = `/api/product/getById/${id}`;
        const productsFromCache = this.singleProductsCache.get(url);
        if (productsFromCache) {
            return of(productsFromCache)
        }
        const response = this.http.get<Product>(url);
        response.subscribe(position => {
            this.singleProductsCache.set(url, position);
        });
        return response;
    }


getProducts(limit: number = 8): Observable<Product[]> {
        return this.http.get<Product[]>(`/api/product/getProducts?limit=${limit}`);
    }


getAll(): Observable<Product[]> {
        const url = '/api/product/getAll';
        return this.toCache(url, this.catalogProductsCache);
    }


toCache(url: string, cache: any): Observable<Product[]> {
        const productsFromCache = cache.get(url);
        if (productsFromCache) {
            return of(productsFromCache)
        }
        const response = this.http.get<Product[]>(url);
        response.subscribe(position => {
            cache.set(url, position);
        });
        return response;
    }


@Module({
  imports: [TypeOrmModule.forRoot(), UserModule, AnimalModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}


export function getInitiativeIdentifiers(teamId: string): string {
  return `${TEAM}:${teamId}|${INITIATIVE_TYPE}`;
}


export function getStatusDisplay(status: Status): string {
  const display = status.toLowerCase().replace('_', ' ');
  return display.charAt(0).toUpperCase() + display.slice(1);
}


function getShortDescription(description: string, length: number = 160): string {
  return description && description.length > length ? `${description.substring(0, length)}...` : description;
}


export class CreateInitiativeRequest {
  initiativeId: string;
  identifiers: string;
  type: string;
  team: {
    id: string;
    domain: string;
  };
  name: string;
  description: string;
  office: string;
  channel: {
    id: string;
    name: string;
    parsed: string;
  };
  status: Status;
  createdBy: {
    slackUserId: string;
    name: string;
    icon: string;
    office?: string;
  };
  createdBySlackUserId: string;
  createdAt: string;

  constructor({ name, team, description, channel, createdBy }: CreateInitiativeRequestProperties) {
    this.initiativeId = id();
    this.identifiers = getInitiativeIdentifiers(team.id);
    this.type = INITIATIVE_TYPE;
    this.team = team;
    this.name = name;
    this.description = description ? description : null;
    this.channel = channel ? channel : null;
    this.office = createdBy.office ? createdBy.office : null;
    this.status = Status.ACTIVE;
    this.createdBy = createdBy;
    this.createdAt = new Date().toDateString();
  }
}


export class Initiative {
  initiativeId: string;
  name: string;
  description: string;
  shortDescription: string;
  channel: {
    id: string;
    name: string;
    parsed: string;
  };
  status: Status;
  statusDisplay: string;
  team: {
    id: string;
    domain: string;
  };
  office?: string;
  members?: Member[];
  createdBy: {
    slackUserId: string;
    name: string;
    icon: string;
    office?: string;
  };
  createdAt: number;

  constructor(record: InitiativeRecord) {
    this.initiativeId = record.initiativeId;
    this.name = record.name;
    this.description = record.description;
    this.channel = record.channel;
    this.status = record.status;
    this.office = record.office;
    this.statusDisplay = getStatusDisplay(record.status);
    this.shortDescription = getShortDescription(record.description);
    this.team = record.team;
    this.createdAt = record.createdAt;
    this.createdBy = record.createdBy;
  }
}


export interface InitiativeRecord {
  initiativeId: string;
  identifiers: string;
  [key: string]: any;
}


interface CreateInitiativeRequestProperties {
  name: string;
  team: {
    id: string;
    domain: string;
  };
  description?: string;
  channel?: {
    id: string;
    name: string;
    parsed: string;
  };
  createdBy: {
    slackUserId: string;
    name: string;
    icon: string;
    office?: string;
  };
}


export enum Status {
  ACTIVE = 'ACTIVE',
  COMPLETE = 'COMPLETE',
  ABANDONED = 'ABANDONED',
  ON_HOLD = 'ON_HOLD'
}


function returnThisMember(this: NoImplicitThisContainer, this: NoImplicitThisContainer) {
    return this.member;
}


// These would normally be wrapped in an IIFE, but:
// https://github.com/microsoft/TypeScript/issues/36309
export interface NoImplicitThisContainer {
    member: string;
    returnThisMember: () => string;
}


@Module({
  providers: [
    CollectionsResolver,
    CollectionsService,
    CollectiblesService,
    UsersService,
    PrismaService,
  ],
})
export class CollectionsModule {}


({
  options = [],
  idToSelectedMap = {},
  onChange,
  className,
  disabled,
  compressed,
  legend,
  ...rest
}) => {
  const checkboxes = options.map((option, index) => {
    const {
      disabled: isOptionDisabled,
      className: optionClass,
      ...optionRest
    } = option;
    return (
      <EuiCheckbox
        className={classNames('euiCheckboxGroup__item', optionClass)}
        key={index}
        checked={idToSelectedMap[option.id]}
        disabled={disabled || isOptionDisabled}
        onChange={onChange.bind(null, option.id)}
        compressed={compressed}
        {...optionRest}
      />
    );
  }


(option, index) => {
    const {
      disabled: isOptionDisabled,
      className: optionClass,
      ...optionRest
    } = option;
    return (
      <EuiCheckbox
        className={classNames('euiCheckboxGroup__item', optionClass)}
        key={index}
        checked={idToSelectedMap[option.id]}
        disabled={disabled || isOptionDisabled}


export interface EuiCheckboxGroupOption
  extends Omit<EuiCheckboxProps, 'checked' | 'onChange'> {
  id: string;
}


export interface EuiCheckboxGroupIdToSelectedMap {
  [id: string]: boolean;
}


// Must omit inherit `onChange` properties or else TS complaines when applying to the EuiRadio
type AsDivProps = Omit<HTMLAttributes<HTMLDivElement>, 'onChange'>;


type WithLegendProps = Omit<EuiFormFieldsetProps, 'onChange'> & {
  /**
   * If the individual labels for each radio do not provide a sufficient description, add a legend.
   * Wraps the group in a `EuiFormFieldset` which adds an `EuiLegend` for titling the whole group.
   * Accepts an `EuiFormLegendProps` shape.
   */
  legend?: EuiFormLegendProps;
};


export type EuiCheckboxGroupProps = CommonProps & {
  options: EuiCheckboxGroupOption[];
  idToSelectedMap: EuiCheckboxGroupIdToSelectedMap;
  onChange: (optionId: string) => void;
  /**
   * Tightens up the spacing between checkbox rows and sends down the
   * compressed prop to the checkbox itself
   */
  compressed?: boolean;
  disabled?: boolean;
} & ExclusiveUnion<AsDivProps, WithLegendProps>;


classNames('euiCheckboxGroup__item', optionClass)


export class SubDataCodeDTO {
  subDataCode: string;
  subDataCodeDescription: string;
}


() => {
  let component: BtnAppsComponent
  let fixture: ComponentFixture<BtnAppsComponent>

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [BtnAppsComponent],
    })
    .compileComponents()
  }))

  beforeEach(() => {
    fixture = TestBed.createComponent(BtnAppsComponent)
    component = fixture.componentInstance
    fixture.detectChanges()
  })

  it('should create', () => {
    expect(component).toBeTruthy()
  })
}


() => {
    TestBed.configureTestingModule({
      declarations: [BtnAppsComponent],
    })
    .compileComponents()
  }


() => {
    fixture = TestBed.createComponent(BtnAppsComponent)
    component = fixture.componentInstance
    fixture.detectChanges()
  }


export default function main(params: any) {
  return {
    module: {
      "xsd": "https://ibm.com/daas/module/1.0/module.xsd",
      "source": {
        "id": "CSV_File",
        "srcUrl": {
          "sourceUrl": "https://developer.ibm.com/static/site-id/141/bikeShareRidesDemographics.csv",
          "mimeType": "text/csv",
          "property": [
            {
              "name": "separator",
              "value": ","
            },
            {
              "name": "ColumnNamesLine",
              "value": "true"
            }
          ]
        }
      },
      "table": {
        "name": "Bike Share Rides Demographics CSV",
        "description": "description of the table for visual hints",
        "column": [
          {
            "name": "Date",
            "datatype": "DATE",
            "nullable": true,
            "description": "Date",
            "label": "Date",
            "usage": "attribute",
            "regularAggregate": "countDistinct",
            "taxonomyFamily": "cDate"
          },
          {
            "name": "From_Community",
            "datatype": "NVARCHAR(256)",
            "nullable": true,
            "description": "From_Community",
            "label": "From_Community",
            "usage": "attribute",
            "regularAggregate": "countDistinct"
          },
          {
            "name": "Latitude",
            "datatype": "DOUBLE",
            "nullable": true,
            "description": "Latitude",
            "label": "Latitude",
            "usage": "attribute",
            "regularAggregate": "countDistinct",
            "taxonomyFamily": "cLatitude"
          },
          {
            "name": "Longitude",
            "datatype": "DOUBLE",
            "nullable": true,
            "description": "Longitude",
            "label": "Longitude",
            "usage": "attribute",
            "regularAggregate": "countDistinct",
            "taxonomyFamily": "cLongitude"
          },
          {
            "name": "Year",
            "datatype": "BIGINT",
            "description": "Year",
            "label": "Year",
            "usage": "attribute",
            "regularAggregate": "countDistinct",
            "taxonomyFamily": "cYear"
          },
          {
            "name": "YearMonth",
            "datatype": "NVARCHAR(256)",
            "nullable": true,
            "description": "YearMonth",
            "label": "YearMonth",
            "usage": "attribute",
            "regularAggregate": "countDistinct",
            "taxonomyFamily": "cMonth"
          },
          {
            "name": "Month",
            "datatype": "BIGINT",
            "nullable": true,
            "description": "Month",
            "label": "Month",
            "usage": "attribute",
            "regularAggregate": "countDistinct",
            "taxonomyFamily": "cMonth"
          },
          {
            "name": "MonthNameShort",
            "datatype": "NVARCHAR(256)",
            "nullable": true,
            "description": "MonthNameShort",
            "label": "MonthNameShort",
            "usage": "attribute",
            "regularAggregate": "countDistinct",
            "taxonomyFamily": "cMonth"
          },
          {
            "name": "MonthNameLong",
            "datatype": "NVARCHAR(256)",
            "nullable": true,
            "description": "MonthNameLong",
            "label": "MonthNameLong",
            "usage": "attribute",
            "regularAggregate": "countDistinct",
            "taxonomyFamily": "cMonth"
          },
          {
            "name": "Weekend",
            "datatype": "NVARCHAR(256)",
            "nullable": true,
            "description": "Weekend",
            "label": "Weekend",
            "usage": "attribute",
            "regularAggregate": "countDistinct"
          },
          {
            "name": "Day_of_Week",
            "datatype": "NVARCHAR(256)",
            "nullable": true,
            "description": "Day_of_Week",
            "label": "Day_of_Week",
            "usage": "attribute",
            "regularAggregate": "countDistinct",
            "taxonomyFamily": "cDay"
          },
          {
            "name": "Number_of_Rides",
            "datatype": "BIGINT",
            "nullable": true,
            "description": "Number_of_Rides",
            "label": "Number_of_Rides",
            "usage": "fact",
            "regularAggregate": "total"
          },
          {
            "name": "Percent_Customers",
            "datatype": "BIGINT",
            "nullable": true,
            "description": "Percent_Customers",
            "label": "Percent_Customers",
            "usage": "fact",
            "regularAggregate": "average"
          },
          {
            "name": "Percent_Subscribers",
            "datatype": "BIGINT",
            "nullable": true,
            "description": "Percent_Subscribers",
            "label": "Percent_Subscribers",
            "usage": "fact",
            "regularAggregate": "average"
          },
          {
            "name": "Percent_Dependents",
            "datatype": "BIGINT",
            "nullable": true,
            "description": "Percent_Dependents",
            "label": "Percent_Dependents",
            "usage": "fact",
            "regularAggregate": "average"
          },
          {
            "name": "Percent_Males",
            "datatype": "BIGINT",
            "nullable": true,
            "description": "Percent_Males",
            "label": "Percent_Males",
            "usage": "fact",
            "regularAggregate": "average"
          },
          {
            "name": "Percent_Females",
            "datatype": "BIGINT",
            "nullable": true,
            "description": "Percent_Females",
            "label": "Percent_Females",
            "usage": "fact",
            "regularAggregate": "average"
          },
          {
            "name": "Average_Age",
            "datatype": "BIGINT",
            "nullable": true,
            "description": "Average_Age",
            "label": "Average_Age",
            "usage": "fact",
            "regularAggregate": "average"
          }
        ]
      },
      "label": "Module Name",
      "identifier": "moduleId"
    }
  };
}


/** Provides operations to call the forward method. */
export class ForwardPostRequestBody implements AdditionalDataHolder, Parsable {
    /** Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. */
    private _additionalData: Record<string, unknown>;
    /** The Comment property */
    private _comment?: string | undefined;
    /** The ToRecipients property */
    private _toRecipients?: Recipient[] | undefined;
    /**
     * Gets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well.
     * @returns a Record<string, unknown>
     */
    public get additionalData() {
        return this._additionalData;
    };
    /**
     * Sets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well.
     * @param value Value to set for the AdditionalData property.
     */
    public set additionalData(value: Record<string, unknown>) {
        this._additionalData = value;
    };
    /**
     * Gets the comment property value. The Comment property
     * @returns a string
     */
    public get comment() {
        return this._comment;
    };
    /**
     * Sets the comment property value. The Comment property
     * @param value Value to set for the Comment property.
     */
    public set comment(value: string | undefined) {
        this._comment = value;
    };
    /**
     * Instantiates a new forwardPostRequestBody and sets the default values.
     */
    public constructor() {
        this._additionalData = {};
    };
    /**
     * The deserialization information for the current model
     * @returns a Record<string, (node: ParseNode) => void>
     */
    public getFieldDeserializers() : Record<string, (node: ParseNode) => void> {
        return {
            "comment": n => { this.comment = n.getStringValue(); },
            "toRecipients": n => { this.toRecipients = n.getCollectionOfObjectValues<Recipient>(createRecipientFromDiscriminatorValue); },
        };
    };
    /**
     * Serializes information the current object
     * @param writer Serialization writer to use to serialize this model
     */
    public serialize(writer: SerializationWriter) : void {
        if(!writer) throw new Error("writer cannot be undefined");
        writer.writeStringValue("comment", this.comment);
        writer.writeCollectionOfObjectValues<Recipient>("toRecipients", this.toRecipients);
        writer.writeAdditionalData(this.additionalData);
    };
    /**
     * Gets the toRecipients property value. The ToRecipients property
     * @returns a recipient
     */
    public get toRecipients() {
        return this._toRecipients;
    };
    /**
     * Sets the toRecipients property value. The ToRecipients property
     * @param value Value to set for the ToRecipients property.
     */
    public set toRecipients(value: Recipient[] | undefined) {
        this._toRecipients = value;
    };
}


/**
     * The deserialization information for the current model
     * @returns a Record<string, (node: ParseNode) => void>
     */
public getFieldDeserializers() : Record<string, (node: ParseNode) => void> {
        return {
            "comment": n => { this.comment = n.getStringValue(); },
            "toRecipients": n => { this.toRecipients = n.getCollectionOfObjectValues<Recipient>(createRecipientFromDiscriminatorValue); },
        };
    }


/**
     * Serializes information the current object
     * @param writer Serialization writer to use to serialize this model
     */
public serialize(writer: SerializationWriter) : void {
        if(!writer) throw new Error("writer cannot be undefined");
        writer.writeStringValue("comment", this.comment);
        writer.writeCollectionOfObjectValues<Recipient>("toRecipients", this.toRecipients);
        writer.writeAdditionalData(this.additionalData);
    }


export default class Relaxiprange extends SfdxCommand {
  public connectedapp_consumerKey: string;
  public static description = messages.getMessage("commandDescription");

  public static examples = [
    `sfdx sfpowerkit:org:relaxiprange -u sandbox -r "122.0.0.0-122.255.255.255,49.0.0.0-49.255.255.255"`
  ];

  protected static flagsConfig = {
    range: flags.array({
      required: true,
      char: "r",
      description: messages.getMessage("rangeFlagDescription")
    }),
    loglevel: flags.enum({
      description: "logging level for this command invocation",
      default: "info",
      required: false,
      options: [
        "trace",
        "debug",
        "info",
        "warn",
        "error",
        "fatal",
        "TRACE",
        "DEBUG",
        "INFO",
        "WARN",
        "ERROR",
        "FATAL"
      ]
    })
  };

  // Comment this out if your command does not require an org username
  protected static requiresUsername = true;

  public async run(): Promise<AnyJson> {
    SFPowerkit.setLogLevel(this.flags.loglevel, this.flags.json);

    let ipRangeToSet = this.flags.range.map(function(element: string) {
      let range = element.split("-");
      return { start: range[0], end: range[1] };
    });

    return await RelaxIPRangeImpl.setIp(
      this.org.getConnection(),
      this.org.getUsername(),
      ipRangeToSet
    );
  }
}


public async run(): Promise<AnyJson> {
    SFPowerkit.setLogLevel(this.flags.loglevel, this.flags.json);

    let ipRangeToSet = this.flags.range.map(function(element: string) {
      let range = element.split("-");
      return { start: range[0], end: range[1] };
    });

    return await RelaxIPRangeImpl.setIp(
      this.org.getConnection(),
      this.org.getUsername(),
      ipRangeToSet
    );
  }


export default abstract class WSCommand {
    static get schema(): WSSchema.TV4;
    static get CommandClasses(): {
        [key: string]: WSCommandConstructor;
    };
    get WSCommandNotFoundError(): typeof WSCommandNotFoundError;
    static addCommandClass(name: string, classObj: WSCommandConstructor): void;
    static framed(module: any, func: any, payload: any): Uint8Array;
    static dequeueOne(buf: any): {
        module: any;
        func: any;
        payload: any;
        next: any;
    } | null;
    static compress(wscommands: any, json: any): Uint8Array | null;
    _hw: any;
    ioNotUsed: number;
    COMMAND_FUNC_ID_ERROR: number;
    abstract module: number;
    private parsed?;
    constructor();
    setHw(obj: any): void;
    sendCommand(func: any, payload: any): void;
    parseFromJson(json: any): void;
    notifyFromBinary(objToSend: any, func: any, payload: any): void;
    envelopWarning(objToSend: any, module_key: any, obj: any): void;
    envelopError(objToSend: any, module_key: any, obj: any): void;
    isValidIO(io: any): boolean;
    getSchema(uri: any): WSSchema.JsonSchema;
    validateCommandSchema(uriList: any, json: any, rootPath: any, customArg: any): any;
    validate(commandUri: any, json: any): WSSchema.MultiResult;
    fastValidate(commandUri: any, json: any): boolean;
    onlyTypeErrorMessage(validateError: any, rootPath: any): any;
    filter(commandUri: any, json: any): any;
    _filterSchema(schema: any, json: any): any;
}


declare class WSCommandNotFoundError extends Error {
}


declare type WSCommandConstructor = new () => WSCommand;


static addCommandClass(name: string, classObj: WSCommandConstructor): void;


static framed(module: any, func: any, payload: any): Uint8Array;


static dequeueOne(buf: any): {
        module: any;
        func: any;
        payload: any;
        next: any;
    } | null;


static compress(wscommands: any, json: any): Uint8Array | null;


setHw(obj: any): void;


sendCommand(func: any, payload: any): void;


parseFromJson(json: any): void;


notifyFromBinary(objToSend: any, func: any, payload: any): void;


envelopWarning(objToSend: any, module_key: any, obj: any): void;


envelopError(objToSend: any, module_key: any, obj: any): void;


isValidIO(io: any): boolean;


getSchema(uri: any): WSSchema.JsonSchema;


validateCommandSchema(uriList: any, json: any, rootPath: any, customArg: any): any;


validate(commandUri: any, json: any): WSSchema.MultiResult;


fastValidate(commandUri: any, json: any): boolean;


onlyTypeErrorMessage(validateError: any, rootPath: any): any;


filter(commandUri: any, json: any): any;


_filterSchema(schema: any, json: any): any;


async () => {
    // Airdropping tokens to a payer.
    await provider.connection.confirmTransaction(
      await provider.connection.requestAirdrop(payer.publicKey, 10000000000),
      "confirmed"
    );

    mintA = await Token.createMint(
      provider.connection,
      payer,
      mintAuthority.publicKey,
      null,
      0,
      TOKEN_PROGRAM_ID
    );

    mintB = await Token.createMint(
      provider.connection,
      payer,
      mintAuthority.publicKey,
      null,
      0,
      TOKEN_PROGRAM_ID
    );

    initializerTokenAccountA = await mintA.createAccount(
      provider.wallet.publicKey
    );
    takerTokenAccountA = await mintA.createAccount(provider.wallet.publicKey);

    initializerTokenAccountB = await mintB.createAccount(
      provider.wallet.publicKey
    );
    takerTokenAccountB = await mintB.createAccount(provider.wallet.publicKey);

    await mintA.mintTo(
      initializerTokenAccountA,
      mintAuthority.publicKey,
      [mintAuthority],
      initializerABalance
    );

    await mintB.mintTo(
      takerTokenAccountB,
      mintAuthority.publicKey,
      [mintAuthority],
      takerBBalance
    );

    let _initializerTokenAccountA = await mintA.getAccountInfo(
      initializerTokenAccountA
    );
    let _takerTokenAccountB = await mintB.getAccountInfo(takerTokenAccountB);

    assert.ok(_initializerTokenAccountA.amount.toNumber() == initializerABalance);
    assert.ok(_takerTokenAccountB.amount.toNumber() == takerBBalance);
    const [_pda, _bumpSeed] = await PublicKey.findProgramAddress(
      [Buffer.from(anchor.utils.bytes.utf8.encode("escrow"))],
      program.programId
    );

    pda = _pda;
  }


async () => {
    await program.rpc.initializeEscrow(
      new BN(initializerAmount),
      new BN(takerAmount),
      {
        accounts: {
          initializer: provider.wallet.publicKey,
          initializerDepositTokenAccount: initializerTokenAccountA,
          initializerReceiveTokenAccount: initializerTokenAccountB,
          escrowAccount: escrowAccount.publicKey,
          systemProgram: SystemProgram.programId,
          tokenProgram: TOKEN_PROGRAM_ID,
        },
        signers: [escrowAccount],
      }
    );

    let _initializerTokenAccountA = await mintA.getAccountInfo(
      initializerTokenAccountA
    );

    let _escrowAccount: EscrowAccount =
      await program.account.escrowAccount.fetch(escrowAccount.publicKey);

    // Check that the new owner is the PDA.
    assert.ok(_initializerTokenAccountA.owner.equals(pda));

    // Check that the values in the escrow account match what we expect.
    assert.ok(_escrowAccount.initializerKey.equals(provider.wallet.publicKey));
    assert.ok(_escrowAccount.initializerAmount.toNumber() == initializerAmount);
    assert.ok(_escrowAccount.takerAmount.toNumber() == takerAmount);
    assert.ok(
      _escrowAccount.initializerDepositTokenAccount.equals(
        initializerTokenAccountA
      )
    );
    assert.ok(
      _escrowAccount.initializerReceiveTokenAccount.equals(
        initializerTokenAccountB
      )
    );
  }


async () => {
    await program.rpc.exchange({
      accounts: {
        taker: provider.wallet.publicKey,
        takerDepositTokenAccount: takerTokenAccountB,
        takerReceiveTokenAccount: takerTokenAccountA,
        pdaDepositTokenAccount: initializerTokenAccountA,
        initializerReceiveTokenAccount: initializerTokenAccountB,
        initializerMainAccount: provider.wallet.publicKey,
        escrowAccount: escrowAccount.publicKey,
        pdaAccount: pda,
        tokenProgram: TOKEN_PROGRAM_ID,
      },
    });

    let _takerTokenAccountA = await mintA.getAccountInfo(takerTokenAccountA);
    let _takerTokenAccountB = await mintB.getAccountInfo(takerTokenAccountB);
    let _initializerTokenAccountA = await mintA.getAccountInfo(
      initializerTokenAccountA
    );
    let _initializerTokenAccountB = await mintB.getAccountInfo(
      initializerTokenAccountB
    );

    // Check that the initializer gets back ownership of their token account.
    assert.ok(_takerTokenAccountA.owner.equals(provider.wallet.publicKey));

    assert.ok(_takerTokenAccountA.amount.toNumber() == initializerAmount);
    assert.ok(_initializerTokenAccountA.amount.toNumber() == initializerABalance - initializerAmount);
    assert.ok(_initializerTokenAccountB.amount.toNumber() == takerAmount);
    assert.ok(_takerTokenAccountB.amount.toNumber() == takerBBalance - takerAmount);
  }


async () => {
    let newEscrow = Keypair.generate();

    // Put back tokens into initializer token A account.
    await mintA.mintTo(
      initializerTokenAccountA,
      mintAuthority.publicKey,
      [mintAuthority],
      initializerAmount
    );

    await program.rpc.initializeEscrow(
      new BN(initializerAmount),
      new BN(takerAmount),
      {
        accounts: {
          initializer: provider.wallet.publicKey,
          initializerDepositTokenAccount: initializerTokenAccountA,
          initializerReceiveTokenAccount: initializerTokenAccountB,
          escrowAccount: newEscrow.publicKey,
          systemProgram: SystemProgram.programId,
          tokenProgram: TOKEN_PROGRAM_ID,
        },
        signers: [newEscrow],
      }
    );

    let _initializerTokenAccountA = await mintA.getAccountInfo(
      initializerTokenAccountA
    );

    // Check that the new owner is the PDA.
    assert.ok(_initializerTokenAccountA.owner.equals(pda));

    // Cancel the escrow.
    await program.rpc.cancelEscrow({
      accounts: {
        initializer: provider.wallet.publicKey,
        pdaDepositTokenAccount: initializerTokenAccountA,
        pdaAccount: pda,
        escrowAccount: newEscrow.publicKey,
        tokenProgram: TOKEN_PROGRAM_ID,
      },
    });

    // Check the final owner should be the provider public key.
    _initializerTokenAccountA = await mintA.getAccountInfo(
      initializerTokenAccountA
    );
    assert.ok(
      _initializerTokenAccountA.owner.equals(provider.wallet.publicKey)
    );

    // Check all the funds are still there.
    assert.ok(_initializerTokenAccountA.amount.toNumber() == initializerABalance);
  }


type EscrowAccount = IdlAccounts<Escrow>["escrowAccount"];


export class ReportsBalancesFetchAllFailed extends BaseError {
  public name = 'ReportsBalancesFetchAllFailed'
  constructor (
    public message: string = 'Could not fetch all the balances',
    properties?: Record<string, unknown>
  ) {
    super(message, properties)
    Object.setPrototypeOf(this, ReportsBalancesFetchAllFailed.prototype)
  }
}


export class ReportsBalancesFetchOneFailed extends BaseError {
  public name = 'ReportsBalancesFetchOneFailed'
  constructor (
    public message: string = 'Could not fetch one balance',
    properties?: Record<string, unknown>
  ) {
    super(message, properties)
    Object.setPrototypeOf(this, ReportsBalancesFetchOneFailed.prototype)
  }
}


export class ReportsBalancesMetaFailed extends BaseError {
  public name = 'ReportsBalancesMetaFailed'
  constructor (
    public message: string = 'Could not fetch meta data for balances',
    properties?: Record<string, unknown>
  ) {
    super(message, properties)
    Object.setPrototypeOf(this, ReportsBalancesMetaFailed.prototype)
  }
}


export class ReportsPaymentOptionsFetchAllFailed extends BaseError {
  public name = 'ReportsPaymentOptionsFetchAllFailed'
  constructor (
    public message: string = 'Could not fetch all the payment options',
    properties?: Record<string, unknown>
  ) {
    super(message, properties)
    Object.setPrototypeOf(this, ReportsPaymentOptionsFetchAllFailed.prototype)
  }
}


export class ReportsPaymentOptionsMetaFailed extends BaseError {
  public name = 'ReportsPaymentOptionsMetaFailed'
  constructor (
    public message: string = 'Could not fetch meta the payment options',
    properties?: Record<string, unknown>
  ) {
    super(message, properties)
    Object.setPrototypeOf(this, ReportsPaymentOptionsMetaFailed.prototype)
  }
}


export class ReportsPaymentsFetchAllFailed extends BaseError {
  public name = 'ReportsPaymentsFetchAllFailed'
  constructor (
    public message: string = 'Could not fetch all the payments',
    properties?: Record<string, unknown>
  ) {
    super(message, properties)
    Object.setPrototypeOf(this, ReportsPaymentsFetchAllFailed.prototype)
  }
}


export class ReportsPaymentsMetaFailed extends BaseError {
  public name = 'ReportsPaymentsMetaFailed'
  constructor (
    public message: string = 'Could not fetch meta data for payments',
    properties?: Record<string, unknown>
  ) {
    super(message, properties)
    Object.setPrototypeOf(this, ReportsPaymentsMetaFailed.prototype)
  }
}


export class VatReportFetchFailed extends BaseError {
  public name = 'VatReportFetchFailed'
  constructor (
    public message: string = 'Could not fetch the vat report',
    properties?: Record<string, unknown>
  ) {
    super(message, properties)
    Object.setPrototypeOf(this, VatReportFetchFailed.prototype)
  }
}


export class VatReportFetchMetaFailed extends BaseError {
  public name = 'VatReportFetchMetaFailed'
  constructor (
    public message: string = 'Could not fetch meta data for vat report',
    properties?: Record<string, unknown>
  ) {
    super(message, properties)
    Object.setPrototypeOf(this, VatReportFetchMetaFailed.prototype)
  }
}


export class CustomerFetchFailed extends BaseError {
  public name = 'CustomerFetchFailed'
  constructor (
    public message: string = 'Could not fetch customer report',
    properties?: Record<string, unknown>
  ) {
    super(message, properties)
    Object.setPrototypeOf(this, CustomerFetchFailed.prototype)
  }
}


export class CustomerFilterFetchFailed extends BaseError {
  public name = 'CustomerFilterFetchFailed'
  constructor (
    public message: string = 'Could not fetch customer filters',
    properties?: Record<string, unknown>
  ) {
    super(message, properties)
    Object.setPrototypeOf(this, CustomerFilterFetchFailed.prototype)
  }
}


export class CustomerTransactionFetchFailed extends BaseError {
  public name = 'CustomerTransactionFetchFailed'
  constructor (
    public message: string = 'Could not fetch customer report transactions',
    properties?: Record<string, unknown>
  ) {
    super(message, properties)
    Object.setPrototypeOf(this, CustomerTransactionFetchFailed.prototype)
  }
}


export class CustomerOverviewFetchFailed extends BaseError {
  public name = 'CustomerOverviewFetchFailed'
  constructor (
    public message: string = 'Could not fetch customer report overview',
    properties?: Record<string, unknown>
  ) {
    super(message, properties)
    Object.setPrototypeOf(this, CustomerOverviewFetchFailed.prototype)
  }
}


export class CustomersMetaFailed extends BaseError {
  public name = 'CustomersMetaFailed'
  constructor (
    public message: string = 'Could not fetch customer report metadata',
    properties?: Record<string, unknown>
  ) {
    super(message, properties)
    Object.setPrototypeOf(this, CustomersMetaFailed.prototype)
  }
}


export enum TextureKeys {
  Drol = "drol",
}


export async function updated({
  paths,
  contractsBuildDirectory,
}: UpdatedOptions): Promise<string[]> {
  const sourceFilesArtifacts = readAndParseArtifactFiles(
    paths,
    contractsBuildDirectory
  );
  const sourceFilesArtifactsUpdatedTimes = minimumUpdatedTimePerSource(
    sourceFilesArtifacts
  );
  return findUpdatedFiles(
    sourceFilesArtifacts,
    sourceFilesArtifactsUpdatedTimes
  );
}


function readAndParseArtifactFiles(
  paths: string[],
  contracts_build_directory: string
): SourceFilesArtifacts {
  const sourceFilesArtifacts: SourceFilesArtifacts = {};
  // Get all the source files and create an object out of them.
  paths.forEach((sourceFile) => {
    sourceFilesArtifacts[sourceFile] = [];
  });
  // Get all the artifact files, and read them, parsing them as JSON
  let buildFiles: string[];
  try {
    buildFiles = fs.readdirSync(contracts_build_directory);
  } catch (error) {
    // The build directory may not always exist.
    if (error.message.includes("ENOENT: no such file or directory")) {
      // Ignore it.
      buildFiles = [];
    } else {
      throw error;
    }
  }

  buildFiles = buildFiles.filter((file) => path.extname(file) === ".json");
  const jsonData = buildFiles.map((file) => {
    const body = fs.readFileSync(
      path.join(contracts_build_directory, file),
      "utf8"
    );
    return { file, body };
  });

  for (let i = 0; i < jsonData.length; i++) {
    try {
      const data: ContractObject = JSON.parse(jsonData[i].body);

      // In case there are artifacts from other source locations.
      if (sourceFilesArtifacts[data.sourcePath] == null) {
        sourceFilesArtifacts[data.sourcePath] = [];
      }

      sourceFilesArtifacts[data.sourcePath].push(data);
    } catch (error) {
      // JSON.parse throws SyntaxError objects
      if (error instanceof SyntaxError) {
        throw new Error("Problem parsing artifact: " + jsonData[i].file);
      } else {
        throw error;
      }
    }
  }
  return sourceFilesArtifacts;
}


function findUpdatedFiles(
  sourceFilesArtifacts: SourceFilesArtifacts,
  sourceFilesArtifactsUpdatedTimes: SourceFilesArtifactsUpdatedTimes
): string[] {
  // Stat all the source files, getting there updated times, and comparing them to
  // the artifact updated times.
  const sourceFiles = Object.keys(sourceFilesArtifacts);

  let sourceFileStats: (fs.Stats | null)[];
  sourceFileStats = sourceFiles.map((file) => {
    try {
      return fs.statSync(file);
    } catch (error) {
      // Ignore it. This means the source file was removed
      // but the artifact file possibly exists. Return null
      // to signfy that we should ignore it.
      return null;
    }
  });

  return sourceFiles
    .map((sourceFile, index) => {
      const sourceFileStat = sourceFileStats[index];

      // Ignore updating artifacts if source file has been removed.
      if (sourceFileStat == null) return;

      const artifactsUpdatedTime =
        sourceFilesArtifactsUpdatedTimes[sourceFile] || 0;
      const sourceFileUpdatedTime = (
        sourceFileStat.mtime || sourceFileStat.ctime
      ).getTime();

      if (sourceFileUpdatedTime > artifactsUpdatedTime) return sourceFile;
    })
    .filter((file) => file);
}


function minimumUpdatedTimePerSource(
  sourceFilesArtifacts: SourceFilesArtifacts
) {
  let sourceFilesArtifactsUpdatedTimes: SourceFilesArtifactsUpdatedTimes = {};
  // Get the minimum updated time for all of a source file's artifacts
  // (note: one source file might have multiple artifacts).
  for (const sourceFile of Object.keys(sourceFilesArtifacts)) {
    const artifacts = sourceFilesArtifacts[sourceFile];

    sourceFilesArtifactsUpdatedTimes[sourceFile] = artifacts.reduce(
      (minimum, current) => {
        const updatedAt = new Date(current.updatedAt).getTime();

        if (updatedAt < minimum) {
          return updatedAt;
        }
        return minimum;
      },
      Number.MAX_SAFE_INTEGER
    );

    // Empty array?
    if (
      sourceFilesArtifactsUpdatedTimes[sourceFile] === Number.MAX_SAFE_INTEGER
    ) {
      sourceFilesArtifactsUpdatedTimes[sourceFile] = 0;
    }
  }
  return sourceFilesArtifactsUpdatedTimes;
}


(sourceFile) => {
    sourceFilesArtifacts[sourceFile] = [];
  }


(file) => path.extname(file) === ".json"


(file) => {
    const body = fs.readFileSync(
      path.join(contracts_build_directory, file),
      "utf8"
    );
    return { file, body };
  }


(file) => {
    try {
      return fs.statSync(file);
    } catch (error) {
      // Ignore it. This means the source file was removed
      // but the artifact file possibly exists. Return null
      // to signfy that we should ignore it.
      return null;
    }
  }


(sourceFile, index) => {
      const sourceFileStat = sourceFileStats[index];

      // Ignore updating artifacts if source file has been removed.
      if (sourceFileStat == null) return;

      const artifactsUpdatedTime =
        sourceFilesArtifactsUpdatedTimes[sourceFile] || 0;
      const sourceFileUpdatedTime = (
        sourceFileStat.mtime || sourceFileStat.ctime
      ).getTime();

      if (sourceFileUpdatedTime > artifactsUpdatedTime) return sourceFile;
    }


(file) => file


(minimum, current) => {
        const updatedAt = new Date(current.updatedAt).getTime();

        if (updatedAt < minimum) {
          return updatedAt;
        }
        return minimum;
      }


export interface UpdatedOptions {
  paths: string[];
  contractsBuildDirectory: string;
}


interface SourceFilesArtifacts {
  [filePath: string]: ContractObject[];
}


interface SourceFilesArtifactsUpdatedTimes {
  [filePath: string]: number; // ms since epoch
}


@Component({
  selector: 'dt-example-tabs-dynamic',
  templateUrl: './tabs-dynamic-example.html',
})
export class DtExampleTabsDynamic {
  hasProblems = false;
}


export default function requireSession(
  cb: (session: Session) => AsyncNextApiHandler
): AsyncNextApiHandler {
  return async (req, res) => {
    const session = getSessionCookie(req, res)

    if (!session) {
      res.status(401).end('Unauthorized')
    } else {
      return cb(session)(req, res)
    }
  }
}


async (req, res) => {
    const session = getSessionCookie(req, res)

    if (!session) {
      res.status(401).end('Unauthorized')
    } else {
      return cb(session)(req, res)
    }
  }


() => Yup.object().shape({
    otp: Yup.string().required("OTP is required")
        .matches(/^[0-9]+$/, "OTP must contain only digits."),
})


function main([tsconfigPath, output, target, attrsStr]: string[]): 0|1 {
  // The Bazel ts_project attributes were json-encoded
  // (on Windows the quotes seem to be quoted wrong, so replace backslash with quotes :shrug:)
  const attrs = JSON.parse(attrsStr.replace(/\\/g, '"'));

  // Parse your typescript settings from the tsconfig
  // This will understand the "extends" semantics.
  const {config, error} = ts.readConfigFile(tsconfigPath, ts.sys.readFile);
  if (error) throw new Error(tsconfigPath + ':' + ts.formatDiagnostic(error, diagnosticsHost));
  const {errors, options} =
      ts.parseJsonConfigFileContent(config, ts.sys, dirname(tsconfigPath));
  // We don't pass the srcs to this action, so it can't know if the program has the right sources.
  // Diagnostics look like
  // error TS18002: The 'files' list in config file 'tsconfig.json' is empty.
  // error TS18003: No inputs were found in config file 'tsconfig.json'. Specified 'include'...
  const fatalErrors = errors.filter(e => e.code !== 18002 && e.code !== 18003);
  if (fatalErrors.length > 0)
    throw new Error(tsconfigPath + ':' + ts.formatDiagnostics(fatalErrors, diagnosticsHost));

  const failures: string[] = [];
  const buildozerCmds: string[] = [];

  function getTsOption(option) {
    if (typeof (options[option]) === 'string') {
      // Currently the only string-typed options are filepaths.
      // TypeScript will resolve these to a project path
      // so when echoing that back to the user, we need to reverse that resolution.
      // First turn //path/to/pkg:tsconfig into path/to/pkg
      const packageDir = target.substr(2, target.indexOf(':') - 2);
      return relative(packageDir, options[option] as string);
    }
    return options[option];
  }

  function check(option: string, attr?: string) {
    attr = attr || option;
    // treat compilerOptions undefined as false
    const optionVal = getTsOption(option);
    const match = optionVal === attrs[attr] ||
        (optionVal === undefined && (attrs[attr] === false || attrs[attr] === ''));
    if (!match) {
      failures.push(
          `attribute ${attr}=${attrs[attr]} does not match compilerOptions.${option}=${optionVal}`);
      if (typeof (optionVal) === 'boolean') {
        buildozerCmds.push(`set ${attr} ${optionVal ? 'True' : 'False'}`);
      } else if (typeof (optionVal) === 'string') {
        buildozerCmds.push(`set ${attr} \"${optionVal}\"`);
      } else if (optionVal === undefined) {
        // nothing to sync
      } else {
        throw new Error(`cannot check option ${option} of type ${typeof (option)}`);
      }
    }
  }

  const jsxEmit: Record<ts.JsxEmit, string|undefined> =
      {
        [ts.JsxEmit.None]: 'none',
        [ts.JsxEmit.Preserve]: 'preserve',
        [ts.JsxEmit.React]: 'react',
        [ts.JsxEmit.ReactNative]: 'react-native',
        [ts.JsxEmit.ReactJSX]: 'react-jsx',
        [ts.JsxEmit.ReactJSXDev]: 'react-jsx-dev',
      }

  function check_preserve_jsx() {
    const attr = 'preserve_jsx'
    const jsxVal = options['jsx'] as ts.JsxEmit
    if ((jsxVal === ts.JsxEmit.Preserve) !== Boolean(attrs[attr])) {
      failures.push(
          `attribute ${attr}=${attrs[attr]} does not match compilerOptions.jsx=${jsxEmit[jsxVal]}`);
      buildozerCmds.push(`set ${attr} ${jsxVal === ts.JsxEmit.Preserve ? 'True' : 'False'}`);
    }
  }

  if (options.noEmit) {
    console.error(`ERROR: ts_project rule ${
      target} cannot be built because the 'noEmit' option is specified in the tsconfig.`);
    console.error('This is not compatible with ts_project, which always produces outputs.');
    console.error('- If you mean to only typecheck the code, use the tsc_test rule instead.');
    console.error('  (See the Alternatives section in the documentation.)');
    console.error('- Otherwise, remove the noEmit option from tsconfig and try again.');
    return 1;
  }

  // When there are dependencies on other ts_project targets, the tsconfig must be configured
  // to help TypeScript resolve them.
  if (attrs.has_local_deps) {
    let rootDirsValid = true
    if (!options.rootDirs) {
      console.error(`ERROR: ts_project rule ${target} is configured without rootDirs.`);
      rootDirsValid = false;
    }
    else if (!options.rootDirs.some(d => d.startsWith(process.env['BINDIR']))) {
      console.error(`ERROR: ts_project rule ${target} is missing a needed rootDir under ${process.env['BINDIR']}.`);
      console.error('Found only: ', options.rootDirs);
      rootDirsValid = false;
    }
    if (!rootDirsValid) {
      console.error('This makes it likely that TypeScript will be unable to resolve dependencies using relative import paths');
      console.error(`For example, if you 'import {} from ./foo', this expects to resolve foo.d.ts from Bazel's output tree`);
      console.error('and TypeScript only knows how to locate this when the rootDirs attribute includes that path.');
      console.error('See the ts_project documentation: https://bazelbuild.github.io/rules_nodejs/TypeScript.html#ts_project');
      return 1;
    }
  }

  check('allowJs', 'allow_js');
  check('declarationMap', 'declaration_map');
  check('emitDeclarationOnly', 'emit_declaration_only');
  check('resolveJsonModule', 'resolve_json_module');
  check('sourceMap', 'source_map');
  check('composite');
  check('declaration');
  check('incremental');
  check('tsBuildInfoFile', 'ts_build_info_file');
  check_preserve_jsx();

  if (failures.length > 0) {
    console.error(`ERROR: ts_project rule ${
        target} was configured with attributes that don't match the tsconfig`);
    failures.forEach(f => console.error(' - ' + f));
    console.error('You can automatically fix this by running:');
    console.error(
        `    npx @bazel/buildozer ${buildozerCmds.map(c => `'${c}'`).join(' ')} ${target}`);
    return 1;
  }

  // We have to write an output so that Bazel needs to execute this action.
  // Make the output change whenever the attributes changed.
  require('fs').writeFileSync(
      output, `
// ${process.argv[1]} checked attributes for ${target}
// allow_js:              ${attrs.allow_js}
// composite:             ${attrs.composite}
// declaration:           ${attrs.declaration}
// declaration_map:       ${attrs.declaration_map}
// incremental:           ${attrs.incremental}
// source_map:            ${attrs.source_map}
// emit_declaration_only: ${attrs.emit_declaration_only}
// ts_build_info_file:    ${attrs.ts_build_info_file}
// preserve_jsx:          ${attrs.preserve_jsx}
`,
      'utf-8');
  return 0;
}


function getTsOption(option) {
    if (typeof (options[option]) === 'string') {
      // Currently the only string-typed options are filepaths.
      // TypeScript will resolve these to a project path
      // so when echoing that back to the user, we need to reverse that resolution.
      // First turn //path/to/pkg:tsconfig into path/to/pkg
      const packageDir = target.substr(2, target.indexOf(':') - 2);
      return relative(packageDir, options[option] as string);
    }
    return options[option];
  }


function check(option: string, attr?: string) {
    attr = attr || option;
    // treat compilerOptions undefined as false
    const optionVal = getTsOption(option);
    const match = optionVal === attrs[attr] ||
        (optionVal === undefined && (attrs[attr] === false || attrs[attr] === ''));
    if (!match) {
      failures.push(
          `attribute ${attr}=${attrs[attr]} does not match compilerOptions.${option}=${optionVal}`);
      if (typeof (optionVal) === 'boolean') {
        buildozerCmds.push(`set ${attr} ${optionVal ? 'True' : 'False'}`);
      } else if (typeof (optionVal) === 'string') {
        buildozerCmds.push(`set ${attr} \"${optionVal}\"`);
      } else if (optionVal === undefined) {
        // nothing to sync
      } else {
        throw new Error(`cannot check option ${option} of type ${typeof (option)}`);
      }
    }
  }


function check_preserve_jsx() {
    const attr = 'preserve_jsx'
    const jsxVal = options['jsx'] as ts.JsxEmit
    if ((jsxVal === ts.JsxEmit.Preserve) !== Boolean(attrs[attr])) {
      failures.push(
          `attribute ${attr}=${attrs[attr]} does not match compilerOptions.jsx=${jsxEmit[jsxVal]}`);
      buildozerCmds.push(`set ${attr} ${jsxVal === ts.JsxEmit.Preserve ? 'True' : 'False'}`);
    }
  }


() => ts.sys.getCurrentDirectory()


(f: string) => f


e => e.code !== 18002 && e.code !== 18003


d => d.startsWith(process.env['BINDIR'])


f => console.error(' - ' + f)


c => `'${c}'`


interface JQuery {
    dxAccordion(): JQuery;
    dxAccordion(options: "instance"): DevExpress.ui.dxAccordion;
    dxAccordion(options: string): any;
    dxAccordion(options: string, ...params: any[]): any;
    dxAccordion(options: DevExpress.ui.dxAccordionOptions): JQuery;
}


function is_math_like(text: string): boolean {
        for (const c of new Set(text)) {
          if ("0" <= c && c <= "9")
            continue
          switch (c) {
            case ",":
            case ".":
            case "+":
            case "-":
            case "\u2212":
            case "e":
              continue
            default:
              return false
          }
        }
        return true
      }


() => {
  const canvas = document.createElement("canvas")
  const ctx = canvas.getContext("2d")!
  let current_font = ""

  return (text: string, font: string): number => {
    if (font != current_font) {
      current_font = font
      ctx.font = font
    }
    return ctx.measureText(text).width
  }
}


(text: string, font: string): number => {
    if (font != current_font) {
      current_font = font
      ctx.font = font
    }
    return ctx.measureText(text).width
  }


() => {
      switch (baseline) {
        case "top": return "top"
        case "middle": return "center"
        case "bottom": return "bottom"
        default: return "baseline"
      }
    }


() => {
      switch (metric) {
        case "x":
        case "x_descent":
          return fmetrics.x_height
        case "cap":
        case "cap_descent":
          return fmetrics.cap_height
        case "ascent":
        case "ascent_descent":
          return fmetrics.ascent
      }
    }


() => {
      switch (metric) {
        case "x":
        case "cap":
        case "ascent":
          return 0
        case "x_descent":
        case "cap_descent":
        case "ascent_descent":
          return fmetrics.descent
      }
    }


(line) => text_width(line, font)


() => {
      if (isNumber(x_anchor))
        return x_anchor*width
      else {
        switch (x_anchor) {
          case "left": return 0
          case "center": return 0.5*width
          case "right": return width
        }
      }
    }


() => {
      if (isNumber(y_anchor))
        return y_anchor*height
      else {
        switch (y_anchor) {
          case "top": return 0
          case "center": return 0.5*height
          case "bottom": return height
          case "baseline": {
            if (nlines == 1) {
              const metric = this.text_height_metric ?? this.infer_text_height()
              switch (metric) {
                case "x":
                case "x_descent":
                  return metrics.x_height
                case "cap":
                case "cap_descent":
                  return metrics.cap_height
                case "ascent":
                case "ascent_descent":
                  return metrics.ascent
              }
            } else
              return 0.5*height
          }
        }
      }
    }


(word) => text_width(word, font)


() => {
          switch (align == "auto" ? this._visual_align : align) {
            case "left": return 0
            case "center": return 0.5*(width - widths[i])
            case "right": return width - widths[i]
          }
        }


() => {
      if (isNumber(y_anchor))
        return y_anchor*height
      else {
        switch (y_anchor) {
          case "top": return 0
          case "center": return 0.5*height
          case "bottom": return height
          case "baseline": return 0.5*height /* TODO */
        }
      }
    }


(item) => item.infer_text_height()


(metric) => metric_map[metric]


export abstract class GraphicsBox {
  _position: Position = {sx: 0, sy: 0}
  angle?: number
  width?: {value: number, unit: "%"}
  height?: {value: number, unit: "%"}
  padding?: Padding
  font_size_scale: number = 1.0
  text_height_metric?: TextHeightMetric
  align: "auto" | "left" | "center" | "right" | "justify" = "left"

  _base_font_size: number = 13 // the same as .bk-root's font-size (13px)

  _x_anchor: "left" | "center" | "right" = "left"
  _y_anchor: "top"  | "center" | "baseline" | "bottom" = "center"

  set base_font_size(v: number | null | undefined) {
    if (v != null)
      this._base_font_size = v
  }

  get base_font_size(): number {
    return this._base_font_size
  }

  set position(p: Position) {
    this._position = p
  }

  get position(): Position {
    return this._position
  }

  abstract set visuals(v: visuals.Text["Values"] | visuals.Line["Values"] | visuals.Fill["Values"])

  abstract _rect(): Rect
  abstract _size(): Size
  abstract paint(ctx: Context2d): void

  infer_text_height(): TextHeightMetric {
    return "ascent_descent"
  }

  bbox(): BBox {
    const {p0, p1, p2, p3} = this.rect()

    const left = Math.min(p0.x, p1.x, p2.x, p3.x)
    const top = Math.min(p0.y, p1.y, p2.y, p3.y)
    const right = Math.max(p0.x, p1.x, p2.x, p3.x)
    const bottom = Math.max(p0.y, p1.y, p2.y, p3.y)

    return new BBox({left, right, top, bottom})
  }

  size(): Size {
    const {width, height} = this._size()
    const {angle} = this
    if (!angle)
      return {width, height}
    else {
      const c = Math.cos(Math.abs(angle))
      const s = Math.sin(Math.abs(angle))

      return {
        width: Math.abs(width*c + height*s),
        height: Math.abs(width*s + height*c),
      }
    }
  }

  rect(): Rect {
    const rect = this._rect()
    const {angle} = this
    if (!angle)
      return rect
    else {
      const {sx, sy} = this.position
      const tr = new AffineTransform()
      tr.translate(sx, sy)
      tr.rotate(angle)
      tr.translate(-sx, -sy)
      return tr.apply_rect(rect)
    }
  }

  paint_rect(ctx: Context2d): void {
    const {p0, p1, p2, p3} = this.rect()
    ctx.save()
    ctx.strokeStyle = "red"
    ctx.lineWidth = 1
    ctx.beginPath()
    const {round} = Math
    ctx.moveTo(round(p0.x), round(p0.y))
    ctx.lineTo(round(p1.x), round(p1.y))
    ctx.lineTo(round(p2.x), round(p2.y))
    ctx.lineTo(round(p3.x), round(p3.y))
    ctx.closePath()
    ctx.stroke()
    ctx.restore()
  }

  paint_bbox(ctx: Context2d): void {
    const {x, y, width, height} = this.bbox()
    ctx.save()
    ctx.strokeStyle = "blue"
    ctx.lineWidth = 1
    ctx.beginPath()
    const {round} = Math
    ctx.moveTo(round(x), round(y))
    ctx.lineTo(round(x), round(y + height))
    ctx.lineTo(round(x + width), round(y + height))
    ctx.lineTo(round(x + width), round(y))
    ctx.closePath()
    ctx.stroke()
    ctx.restore()
  }
}


export class BaseExpo extends GraphicsBox {
  constructor(readonly base: GraphicsBox, readonly expo: GraphicsBox) {
    super()
  }

  get children(): GraphicsBox[] {
    return [this.base, this.expo]
  }

  override set base_font_size(v: number) {
    super.base_font_size = v
    this.base.base_font_size = v
    this.expo.base_font_size = v
  }

  override set position(p: Position) {
    this._position = p

    const bs = this.base.size()
    const es = this.expo.size()

    const shift = this._shift_scale()*bs.height
    const height = Math.max(bs.height, shift + es.height)

    this.base.position = {
      sx: 0, x_anchor: "left",
      sy: height, y_anchor: "bottom",
    }

    this.expo.position = {
      sx: bs.width, x_anchor: "left",
      sy: shift, y_anchor: "bottom",
    }
  }

  override get position(): Position {
    return this._position
  }

  set visuals(v: visuals.Text["Values"] | visuals.Line["Values"] | visuals.Fill["Values"]) {
    this.expo.font_size_scale = 0.7
    this.base.visuals = v
    this.expo.visuals = v
  }

  _shift_scale(): number {
    if (this.base instanceof TextBox && this.base.nlines == 1) {
      const {x_height, cap_height} = font_metrics(this.base.font)
      return x_height/cap_height
    } else {
      return 2/3
    }
  }

  override infer_text_height() {
    return this.base.infer_text_height()
  }

  _rect(): Rect {
    const bb = this.base.bbox()
    const eb = this.expo.bbox()

    const bbox = bb.union(eb)
    const {x, y} = this._computed_position()
    return bbox.translate(x, y).rect
  }

  _size(): Size {
    const bs = this.base.size()
    const es = this.expo.size()

    return {
      width: bs.width + es.width,
      height: Math.max(bs.height, this._shift_scale()*bs.height + es.height),
    }
  }

  paint(ctx: Context2d): void {
    ctx.save()
    const {angle} = this
    if (angle) {
      const {sx, sy} = this.position
      ctx.translate(sx, sy)
      ctx.rotate(angle)
      ctx.translate(-sx, -sy)
    }
    const {x, y} = this._computed_position()
    ctx.translate(x, y)
    this.base.paint(ctx)
    this.expo.paint(ctx)
    ctx.restore()
  }

  // paint_rect ...

  override paint_bbox(ctx: Context2d): void {
    super.paint_bbox(ctx)
    const {x, y} = this._computed_position()
    ctx.save()
    ctx.translate(x, y)
    for (const child of this.children) {
      child.paint_bbox(ctx)
    }
    ctx.restore()
  }

  _computed_position(): {x: number, y: number} {
    const {width, height} = this._size()
    const {sx, sy, x_anchor=this._x_anchor, y_anchor=this._y_anchor} = this.position

    const x = sx - (() => {
      if (isNumber(x_anchor))
        return x_anchor*width
      else {
        switch (x_anchor) {
          case "left": return 0
          case "center": return 0.5*width
          case "right": return width
        }
      }
    })()

    const y = sy - (() => {
      if (isNumber(y_anchor))
        return y_anchor*height
      else {
        switch (y_anchor) {
          case "top": return 0
          case "center": return 0.5*height
          case "bottom": return height
          case "baseline": return 0.5*height /* TODO */
        }
      }
    })()

    return {x, y}
  }
}


export class GraphicsBoxes {
  constructor(readonly items: GraphicsBox[]) {}

  set base_font_size(v: number | null | undefined) {
    for (const item of this.items) {
      item.base_font_size = v
    }
  }

  get length(): number {
    return this.items.length
  }

  set visuals(v: visuals.Text["Values"] | visuals.Line["Values"] | visuals.Fill["Values"]) {
    for (const item of this.items) {
      item.visuals = v
    }

    const metric_map = {x: 0, cap: 1, ascent: 2, x_descent: 3, cap_descent: 4, ascent_descent: 5}
    const common = max_by(this.items.map((item) => item.infer_text_height()), (metric) => metric_map[metric])

    for (const item of this.items) {
      item.text_height_metric = common
    }
  }

  set angle(a: number) {
    for (const item of this.items) {
      item.angle = a
    }
  }

  max_size(): Size {
    let width = 0
    let height = 0
    for (const item of this.items) {
      const size = item.size()
      width = Math.max(width, size.width)
      height = Math.max(height, size.height)
    }
    return {width, height}
  }
}


export type Position = {
  sx: number
  sy: number
  x_anchor?: number | "left" | "center" | "right"
  y_anchor?: number | "top"  | "center" | "baseline" | "bottom"
}


type Val = number | {value: number, unit: "px" | "%"}


type Extents = {left: Val, right: Val, top: Val, bottom: Val}


type Padding = Val | [v: Val, h: Val] | [top: Val, right: Val, bottom: Val, left: Val] | Extents


export type TextHeightMetric = "x" | "cap" | "ascent" | "x_descent" | "cap_descent" | "ascent_descent"


abstract _rect(): Rect


abstract _size(): Size


abstract paint(ctx: Context2d): void


infer_text_height(): TextHeightMetric {
    return "ascent_descent"
  }


bbox(): BBox {
    const {p0, p1, p2, p3} = this.rect()

    const left = Math.min(p0.x, p1.x, p2.x, p3.x)
    const top = Math.min(p0.y, p1.y, p2.y, p3.y)
    const right = Math.max(p0.x, p1.x, p2.x, p3.x)
    const bottom = Math.max(p0.y, p1.y, p2.y, p3.y)

    return new BBox({left, right, top, bottom})
  }


size(): Size {
    const {width, height} = this._size()
    const {angle} = this
    if (!angle)
      return {width, height}
    else {
      const c = Math.cos(Math.abs(angle))
      const s = Math.sin(Math.abs(angle))

      return {
        width: Math.abs(width*c + height*s),
        height: Math.abs(width*s + height*c),
      }
    }
  }


rect(): Rect {
    const rect = this._rect()
    const {angle} = this
    if (!angle)
      return rect
    else {
      const {sx, sy} = this.position
      const tr = new AffineTransform()
      tr.translate(sx, sy)
      tr.rotate(angle)
      tr.translate(-sx, -sy)
      return tr.apply_rect(rect)
    }
  }


paint_rect(ctx: Context2d): void {
    const {p0, p1, p2, p3} = this.rect()
    ctx.save()
    ctx.strokeStyle = "red"
    ctx.lineWidth = 1
    ctx.beginPath()
    const {round} = Math
    ctx.moveTo(round(p0.x), round(p0.y))
    ctx.lineTo(round(p1.x), round(p1.y))
    ctx.lineTo(round(p2.x), round(p2.y))
    ctx.lineTo(round(p3.x), round(p3.y))
    ctx.closePath()
    ctx.stroke()
    ctx.restore()
  }


paint_bbox(ctx: Context2d): void {
    const {x, y, width, height} = this.bbox()
    ctx.save()
    ctx.strokeStyle = "blue"
    ctx.lineWidth = 1
    ctx.beginPath()
    const {round} = Math
    ctx.moveTo(round(x), round(y))
    ctx.lineTo(round(x), round(y + height))
    ctx.lineTo(round(x + width), round(y + height))
    ctx.lineTo(round(x + width), round(y))
    ctx.closePath()
    ctx.stroke()
    ctx.restore()
  }


override infer_text_height() {
    if (this.text.includes("\n"))
      return "ascent_descent"
    else {
      function is_math_like(text: string): boolean {
        for (const c of new Set(text)) {
          if ("0" <= c && c <= "9")
            continue
          switch (c) {
            case ",":
            case ".":
            case "+":
            case "-":
            case "\u2212":
            case "e":
              continue
            default:
              return false
          }
        }
        return true
      }

      if (is_math_like(this.text))
        return "cap"
      else
        return "ascent_descent"

      /*
      const {font} = this
      const fmetrics = font_metrics(font)

      let max_ascent = 0
      let max_descent = 0
      for (const c of this.text) {
        const metrics = glyph_metrics(c, font)
        max_ascent = Math.max(metrics.ascent)
        max_descent = Math.max(metrics.descent)
      }

      const ascent = (() => {
        if (max_ascent > fmetrics.cap_height)
          return "ascent"
        else if (max_ascent > fmetrics.x_height)
          return "cap"
        else
          return "x"
      })()

      return max_descent > 0 ? `${ascent}_descent` as const : ascent
      */
    }
  }


_text_line(fmetrics: FontMetrics): {height: number, ascent: number, descent: number} {
    const metric = this.text_height_metric ?? this.infer_text_height()

    const ascent = (() => {
      switch (metric) {
        case "x":
        case "x_descent":
          return fmetrics.x_height
        case "cap":
        case "cap_descent":
          return fmetrics.cap_height
        case "ascent":
        case "ascent_descent":
          return fmetrics.ascent
      }
    })()

    const descent = (() => {
      switch (metric) {
        case "x":
        case "cap":
        case "ascent":
          return 0
        case "x_descent":
        case "cap_descent":
        case "ascent_descent":
          return fmetrics.descent
      }
    })()

    return {height: ascent + descent, ascent, descent}
  }