/**
 * Declares XNamespace and XName fields for the `xmlns:p15="http://schemas.microsoft.com/office/powerpoint/2012/main"` namespace.
 */
export class P15 {
  /** @internal */
  private constructor() {
    // Ignore
  }

  /**
   * Defines the XML namespace associated with the `p15` prefix.
   */
  public static readonly p15: XNamespace = XNamespace.get(
    'http://schemas.microsoft.com/office/powerpoint/2012/main'
  );

  /**
   * Returns the namespace declaration `XAttribute` for this namespace.
   */
  public static get namespaceDeclaration(): XAttribute {
    return new XAttribute(XNamespace.xmlns.getName('p15'), P15.p15.namespaceName);
  }

  /**
   * Represents the `p15:chartTrackingRefBased` XML element.
   *
   * @remarks
   * As an XML element, it has the following:
   * - parent XML elements: {@linkcode A.graphicData a:graphicData}, {@linkcode P.ext p:ext}
   */
  public static readonly chartTrackingRefBased: XName = P15.p15.getName('chartTrackingRefBased');

  /**
   * Represents the `p15:clr` XML element.
   *
   * @remarks
   * As an XML element, it has the following:
   * - parent XML elements: {@linkcode guide p15:guide}
   * - child XML elements: {@linkcode A.hslClr a:hslClr}, {@linkcode A.prstClr a:prstClr}, {@linkcode A.schemeClr a:schemeClr}, {@linkcode A.scrgbClr a:scrgbClr}, {@linkcode A.srgbClr a:srgbClr}, {@linkcode A.sysClr a:sysClr}
   */
  public static readonly clr: XName = P15.p15.getName('clr');

  /**
   * Represents the `p15:extLst` XML element.
   *
   * @remarks
   * As an XML element, it has the following:
   * - parent XML elements: {@linkcode guide p15:guide}, {@linkcode notesGuideLst p15:notesGuideLst}, {@linkcode sldGuideLst p15:sldGuideLst}
   * - child XML elements: {@linkcode P.ext p:ext}
   */
  public static readonly extLst: XName = P15.p15.getName('extLst');

  /**
   * Represents the `p15:guide` XML element.
   *
   * @remarks
   * As an XML element, it has the following:
   * - parent XML elements: {@linkcode notesGuideLst p15:notesGuideLst}, {@linkcode sldGuideLst p15:sldGuideLst}
   * - child XML elements: {@linkcode clr p15:clr}, {@linkcode extLst p15:extLst}
   */
  public static readonly guide: XName = P15.p15.getName('guide');

  /**
   * Represents the `p15:notesGuideLst` XML element.
   *
   * @remarks
   * As an XML element, it has the following:
   * - parent XML elements: {@linkcode A.graphicData a:graphicData}, {@linkcode P.ext p:ext}
   * - child XML elements: {@linkcode extLst p15:extLst}, {@linkcode guide p15:guide}
   */
  public static readonly notesGuideLst: XName = P15.p15.getName('notesGuideLst');

  /**
   * Represents the `p15:parentCm` XML element.
   *
   * @remarks
   * As an XML element, it has the following:
   * - parent XML elements: {@linkcode threadingInfo p15:threadingInfo}
   */
  public static readonly parentCm: XName = P15.p15.getName('parentCm');

  /**
   * Represents the `p15:presenceInfo` XML element.
   *
   * @remarks
   * As an XML element, it has the following:
   * - parent XML elements: {@linkcode A.graphicData a:graphicData}, {@linkcode P.ext p:ext}
   */
  public static readonly presenceInfo: XName = P15.p15.getName('presenceInfo');

  /**
   * Represents the `p15:prstTrans` XML element.
   *
   * @remarks
   * As an XML element, it has the following:
   * - parent XML elements: {@linkcode A.graphicData a:graphicData}, {@linkcode P.transition p:transition}
   */
  public static readonly prstTrans: XName = P15.p15.getName('prstTrans');

  /**
   * Represents the `p15:sldGuideLst` XML element.
   *
   * @remarks
   * As an XML element, it has the following:
   * - parent XML elements: {@linkcode A.graphicData a:graphicData}, {@linkcode P.ext p:ext}
   * - child XML elements: {@linkcode extLst p15:extLst}, {@linkcode guide p15:guide}
   */
  public static readonly sldGuideLst: XName = P15.p15.getName('sldGuideLst');

  /**
   * Represents the `p15:threadingInfo` XML element.
   *
   * @remarks
   * As an XML element, it has the following:
   * - parent XML elements: {@linkcode A.graphicData a:graphicData}, {@linkcode P.ext p:ext}
   * - child XML elements: {@linkcode parentCm p15:parentCm}
   */
  public static readonly threadingInfo: XName = P15.p15.getName('threadingInfo');
}


/**
 * JoinTable decorator is used in many-to-many relationship to specify owner side of relationship.
 * Its also used to set a custom junction table's name, column names and referenced columns.
 */
export function JoinTable(options?: JoinTableOptions): Function {
    return function (object: Object, propertyName: string) {
        options = options || {} as JoinTableOptions;
        const args: JoinTableMetadataArgs = {
            target: object.constructor,
            propertyName: propertyName,
            name: options.name,
            joinColumn: options.joinColumn,
            inverseJoinColumn: options.inverseJoinColumn
        };
        getMetadataArgsStorage().joinTables.add(args);
    };
}


(eventListSnapshot) => {
      this.eventList = [];
      eventListSnapshot.forEach((snap) => {
        this.eventList.push({
          id: snap.id,
          name: snap.data().name,
          price: snap.data().price,
          date: snap.data().date,
        });
        return false;
      });
    }


(snap) => {
        this.eventList.push({
          id: snap.id,
          name: snap.data().name,
          price: snap.data().price,
          date: snap.data().date,
        });
        return false;
      }


@Component({
  selector: 'app-events',
  templateUrl: './events.page.html',
  styleUrls: ['./events.page.scss'],
})
export class EventsPage implements OnInit {
  public eventList: Array<any>;
  constructor(private eventService: EventService, private routerOutlet: IonRouterOutlet, private modalController: ModalController) {}

  ngOnInit() {
    this.eventService.getEventList().then((eventListSnapshot) => {
      this.eventList = [];
      eventListSnapshot.forEach((snap) => {
        this.eventList.push({
          id: snap.id,
          name: snap.data().name,
          price: snap.data().price,
          date: snap.data().date,
        });
        return false;
      });
    });
  }

  async openCreate() {
    console.log('clicked');
    const modal = await this.modalController.create({
      component: EventCreatePage,

      swipeToClose: true,
      presentingElement: this.routerOutlet.nativeEl,
    });
    await modal.present();
    const {data} = await modal.onWillDismiss();
    console.log(data);
  }
  async openDetail(id) {
    console.log('clicked');
    const modal = await this.modalController.create({
      component: EventDetailPage,
      componentProps: {
        eventId: id,
      },
      swipeToClose: true,
      presentingElement: this.routerOutlet.nativeEl,
    });
    await modal.present();
    const {data} = await modal.onWillDismiss();
    console.log(data);
  }
}


ngOnInit() {
    this.eventService.getEventList().then((eventListSnapshot) => {
      this.eventList = [];
      eventListSnapshot.forEach((snap) => {
        this.eventList.push({
          id: snap.id,
          name: snap.data().name,
          price: snap.data().price,
          date: snap.data().date,
        });
        return false;
      });
    });
  }


async openCreate() {
    console.log('clicked');
    const modal = await this.modalController.create({
      component: EventCreatePage,

      swipeToClose: true,
      presentingElement: this.routerOutlet.nativeEl,
    });
    await modal.present();
    const {data} = await modal.onWillDismiss();
    console.log(data);
  }


async openDetail(id) {
    console.log('clicked');
    const modal = await this.modalController.create({
      component: EventDetailPage,
      componentProps: {
        eventId: id,
      },
      swipeToClose: true,
      presentingElement: this.routerOutlet.nativeEl,
    });
    await modal.present();
    const {data} = await modal.onWillDismiss();
    console.log(data);
  }


/**
 * Search for all applicable test cases
 * @param title
 * @returns {any}
 */
export function titleToCaseIds(title: string): number[] {
  let caseIds: number[] = [];

  let testCaseIdRegExp: RegExp = /\bT?C(\d+)\b/g;
  let m;
  while ((m = testCaseIdRegExp.exec(title)) !== null) {
    let caseId = parseInt(m[1]);
    caseIds.push(caseId);
  }
  return caseIds;
}


/**
 * Get Testrail elapsed string from duration
 * @param duration
 * @returns {any}
 */
export function durationToElapsed(duration: number): string {
  let elapsed = '';

  const millis = 1000;
  const minMillis = 60 * millis;
  const hrsMillis = 60 * minMillis;

  let hrs = Math.floor(duration / hrsMillis);
  if (hrs > 0) {
    elapsed += `${hrs}h `;
    duration -= hrs * hrsMillis;
  }

  let mins = Math.floor(duration / minMillis);
  if (mins > 0) {
    elapsed += `${mins}m `;
    duration -= mins * minMillis;
  }

  let sec = Math.round(duration / millis);
  if (sec > 0) {
    elapsed += `${sec}s `;
  }
  return elapsed.trim();
}


declare interface IntlTelInputCountryData {
  name: string;
  iso2: IntlTelInputAlpha2;
  dialCode: string;
}


declare interface IntlTelInputInstance {
  getExtension(): string | undefined | null;
  getNumber(): string | undefined | null;
  getNumberType(): number | undefined | null;
  getSelectedCountryData(): IntlTelInputCountryData;
  getValidationError(): number | undefined | null;
  isValidNumber(): boolean;

  destroy();
  setCountry(alpha2: IntlTelInputAlpha2);
  setNumber(e164: string);
  setPlaceholderNumberType(typ: IntlTelInputPlaceholderNumberType);
}


declare interface IntlTelInputInitOptions {
  // UI
  autoPlaceholder?: "polite" | "aggressive" | "off";
  placeholderNumberType?: IntlTelInputPlaceholderNumberType;
  customContainer?: string;
  customPlaceholder?: (selectedCountryPlaceholder: string, selectedCountryData: IntlTelInputCountryData) => string;
  dropdownContainer?: HTMLElement;

  // Functionality
  utilsScript?: string;
  nationalMode?: boolean;
  autoHideDialCode?: boolean;
  separateDialCode?: boolean;
  allowDropdown?: boolean;
  formatOnDisplay?: boolean;
  geoIpLookup?: (success: (alpha2: IntlTelInputAlpha2) => void, failure: (err: unknown) => void) => void;
  initialCountry?: "auto" | IntlTelInputAlpha2;
  excludeCountries?: IntlTelInputAlpha2[];
  onlyCountries?: IntlTelInputAlpha2[];
  preferredCountries?: IntlTelInputAlpha2[];

  // Localization
  localizedCountries?: Record<IntlTelInputAlpha2, string>;

  // Form integration
  hiddenInput?: string;
}


declare interface IntlTelInputInitFunction {
  (element: HTMLElement, options?: IntlTelInputInitOptions): IntlTelInputInstance;
}


declare interface IntlTelInputGlobals {
  getCountryData(): IntlTelInputCountryData[];
  getInstance(element: HTMLElement): IntlTelInputInstance | null | undefined;
  loadUtils(s: string): Promise<void>;
}


// Inject things into window.
declare interface Window {
  intlTelInputGlobals: IntlTelInputGlobals;
  intlTelInput: IntlTelInputInitFunction;
}


// Type definition for intl-tel-input v17.0.13
declare type IntlTelInputAlpha2 = string;


declare type IntlTelInputPlaceholderNumberType = "MOBILE" | "FIXED_LINE";


(accessToken, refreshToken, profile, done) => {
    const profile_json = profile._json;
    console.log('josn데이터 확인: ',profile_json);
    done(null, profile_json);
  }


interface GenericMap<K, V> extends Array<V> {
    has(key: K): boolean
    get(key: K): V
    set(key: K, value: V): boolean
    add(value: V, key: K): boolean
    delete(key: K): boolean
    clear()
  }


() => {
  const currentUser = useSelector(selectCurrentMemberData)
  const loading = useSelector(selectCurrentMemberIsLoading)
  if (loading) {
    return <Loader />
  }
  if (currentUser?.role === 'admin') {
    return (
      <>
        <Section>
          <Tabs role={currentUser?.role} />
        </Section>
        <AccountsInformationForm />
        <Subcriptions />
      </>


() => {
  test('Menu', async ({ page }) => {
    await page.goto();

    await page.click('text=Settings');
    await page.click('ul[role="menu"] >> text=Language');

    // Inject capture zone
    await page.evaluate(
      ([zone]) => {
        document.body.insertAdjacentHTML('beforeend', zone);
      },
      [generateCaptureArea({ top: 5, left: 250, width: 800, height: 600 })]
    );

    await page.waitForFrames(5);
    expect(
      await (await page.$('#capture-screenshot')).screenshot()
    ).toMatchSnapshot('language_settings.png');
  });

  test('Confirm language', async ({ page }) => {
    await page.goto();

    await page.click('text=Settings');
    await page.click('ul[role="menu"] >> text=Language');
    await page.click('#jp-mainmenu-settings-language >> text=Chinese');

    // Inject capture zone
    await page.evaluate(
      ([zone]) => {
        document.body.insertAdjacentHTML('beforeend', zone);
      },
      [generateCaptureArea({ top: 200, left: 350, width: 600, height: 300 })]
    );

    await page.waitForFrames(3);
    expect(
      await (await page.$('#capture-screenshot')).screenshot()
    ).toMatchSnapshot('language_change.png');
  });

  test('UI in Chinese', async ({ page }) => {
    await galata.Mock.freezeContentLastModified(page);
    await page.goto();

    await page.click('text=Settings');
    await page.click('ul[role="menu"] >> text=Language');
    await page.click('#jp-mainmenu-settings-language >> text=Chinese');

    await Promise.all([
      page.waitForNavigation(),
      page.waitForSelector('#jupyterlab-splash'),
      page.click('button:has-text("Change and reload")')
    ]);

    await page.waitForSelector('#jupyterlab-splash', {
      state: 'detached'
    });

    await page.addStyleTag({
      content: `.jp-LabShell.jp-mod-devMode {
        border-top: none;
      }`
    });

    // Wait for the launcher to be loaded
    await page.waitForSelector('text=README.md');

    await page.waitForFrames(3);
    expect(await page.screenshot()).toMatchSnapshot('language_chinese.png');
  });
}


async ({ page }) => {
    await page.goto();

    await page.click('text=Settings');
    await page.click('ul[role="menu"] >> text=Language');

    // Inject capture zone
    await page.evaluate(
      ([zone]) => {
        document.body.insertAdjacentHTML('beforeend', zone);
      },
      [generateCaptureArea({ top: 5, left: 250, width: 800, height: 600 })]
    );

    await page.waitForFrames(5);
    expect(
      await (await page.$('#capture-screenshot')).screenshot()
    ).toMatchSnapshot('language_settings.png');
  }


([zone]) => {
        document.body.insertAdjacentHTML('beforeend', zone);
      }


async ({ page }) => {
    await page.goto();

    await page.click('text=Settings');
    await page.click('ul[role="menu"] >> text=Language');
    await page.click('#jp-mainmenu-settings-language >> text=Chinese');

    // Inject capture zone
    await page.evaluate(
      ([zone]) => {
        document.body.insertAdjacentHTML('beforeend', zone);
      },
      [generateCaptureArea({ top: 200, left: 350, width: 600, height: 300 })]
    );

    await page.waitForFrames(3);
    expect(
      await (await page.$('#capture-screenshot')).screenshot()
    ).toMatchSnapshot('language_change.png');
  }


async ({ page }) => {
    await galata.Mock.freezeContentLastModified(page);
    await page.goto();

    await page.click('text=Settings');
    await page.click('ul[role="menu"] >> text=Language');
    await page.click('#jp-mainmenu-settings-language >> text=Chinese');

    await Promise.all([
      page.waitForNavigation(),
      page.waitForSelector('#jupyterlab-splash'),
      page.click('button:has-text("Change and reload")')
    ]);

    await page.waitForSelector('#jupyterlab-splash', {
      state: 'detached'
    });

    await page.addStyleTag({
      content: `.jp-LabShell.jp-mod-devMode {
        border-top: none;
      }`
    });

    // Wait for the launcher to be loaded
    await page.waitForSelector('text=README.md');

    await page.waitForFrames(3);
    expect(await page.screenshot()).toMatchSnapshot('language_chinese.png');
  }


() => {
  let component: AppCountdownComponent;
  let fixture: ComponentFixture<AppCountdownComponent>;

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

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

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


() => {
    TestBed.configureTestingModule({
      declarations: [ AppCountdownComponent ]
    })
    .compileComponents();
  }


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


({
  label,
  labelColor,
  labelStyle: _labelStyle,
  containerColor,
  style,
  onPress,
}: ButtonProps) => {
  // hooks
  const { appearance } = useAppearance();

  // styles
  const containerStyle = useMemo(
    () => [
      styles.container,
      style,
      containerColor && {
        backgroundColor:
          appearance === 'light' ? containerColor[0] : containerColor[1],
      },
    ],
    [style, containerColor, appearance]
  );
  const labelStyle = useMemo(
    () => [
      styles.label,
      _labelStyle,
      labelColor && {
        color: appearance === 'light' ? labelColor[0] : labelColor[1],
      },
    ],
    [_labelStyle, labelColor, appearance]
  );

  // render

  return Platform.OS === 'ios' ? (
    // @ts-ignore
    <TouchableOpacity style={containerStyle} onPress={onPress}>
      <Text style={labelStyle}>{label}</Text>
    </TouchableOpacity>


() => [
      styles.container,
      style,
      containerColor && {
        backgroundColor:
          appearance === 'light' ? containerColor[0] : containerColor[1],
      },
    ]


() => [
      styles.label,
      _labelStyle,
      labelColor && {
        color: appearance === 'light' ? labelColor[0] : labelColor[1],
      },
    ]


interface ButtonProps {
  label: string;
  labelColor?: string[];
  labelStyle?: TextStyle;
  containerColor?: string[];
  style?: ViewStyle;
  onPress?: () => void;
}


({ tx, t, symbol, }) => (
  <React.Fragment>
    <div>TX


({ tx, t, symbol, }) => (
  <span className={styles.txInfo}>
    <div className


({ tx, t, symbol, }) => (
  <ListItem key={tx.hash}


({
    transactions,
    t,
    symbol,
  }: {
  transactions: TransactionFromServer[]
  t: (key: string) => string
  symbol?: string
  }) => (
    <List
      classes={


tx => (
        <TransactionCell {...{ tx, t, symbol, }} />
      )


formatedAgeString(tx


t('value')


valueFormatter(


() => {
  let readStub;
  const correctCgroupData =
    'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklm';

  afterEach(() => {
    sinon.restore();
  });

  describe('Supported docker - Container ID ', () => {
    it('should return a resource attributes without container id - docker cgroup v1 detector', async () => {
      readStub = sinon
        .stub(DockerCGroupV1Detector, 'readFileAsync' as any)
        .resolves(undefined);

      const resource: Resource = await dockerCGroupV1Detector.detect();

      assert.deepStrictEqual(resource.attributes, {});
      assert.ok(resource);
    });

    it('should return a resource with container ID with a valid container ID present', async () => {
      readStub = sinon
        .stub(DockerCGroupV1Detector, 'readFileAsync' as any)
        .resolves(correctCgroupData);

      const resource: Resource = await dockerCGroupV1Detector.detect();

      sinon.assert.calledOnce(readStub);

      assert.ok(resource);
      assertContainerResource(resource, {
        id: 'bcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklm',
      });
    });

    it('should return a resource without attribute container.id when cgroup file does not contain valid Container ID', async () => {
      readStub = sinon
        .stub(DockerCGroupV1Detector, 'readFileAsync' as any)
        .resolves('');

      const resource: Resource = await dockerCGroupV1Detector.detect();
      assert.deepStrictEqual(resource.attributes, {});

      sinon.assert.calledOnce(readStub);
      assert.ok(resource);
    });

    it('should return an empty resource when containerId is not valid', async () => {
      const errorMsg = {
        fileNotFoundError: new Error('cannot find file in path'),
      };

      readStub = sinon
        .stub(DockerCGroupV1Detector, 'readFileAsync' as any)
        .rejects(errorMsg.fileNotFoundError);

      const resource: Resource = await dockerCGroupV1Detector.detect();

      sinon.assert.calledOnce(readStub);
      assertEmptyResource(resource);
    });
  });
}


() => {
    it('should return a resource attributes without container id - docker cgroup v1 detector', async () => {
      readStub = sinon
        .stub(DockerCGroupV1Detector, 'readFileAsync' as any)
        .resolves(undefined);

      const resource: Resource = await dockerCGroupV1Detector.detect();

      assert.deepStrictEqual(resource.attributes, {});
      assert.ok(resource);
    });

    it('should return a resource with container ID with a valid container ID present', async () => {
      readStub = sinon
        .stub(DockerCGroupV1Detector, 'readFileAsync' as any)
        .resolves(correctCgroupData);

      const resource: Resource = await dockerCGroupV1Detector.detect();

      sinon.assert.calledOnce(readStub);

      assert.ok(resource);
      assertContainerResource(resource, {
        id: 'bcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklm',
      });
    });

    it('should return a resource without attribute container.id when cgroup file does not contain valid Container ID', async () => {
      readStub = sinon
        .stub(DockerCGroupV1Detector, 'readFileAsync' as any)
        .resolves('');

      const resource: Resource = await dockerCGroupV1Detector.detect();
      assert.deepStrictEqual(resource.attributes, {});

      sinon.assert.calledOnce(readStub);
      assert.ok(resource);
    });

    it('should return an empty resource when containerId is not valid', async () => {
      const errorMsg = {
        fileNotFoundError: new Error('cannot find file in path'),
      };

      readStub = sinon
        .stub(DockerCGroupV1Detector, 'readFileAsync' as any)
        .rejects(errorMsg.fileNotFoundError);

      const resource: Resource = await dockerCGroupV1Detector.detect();

      sinon.assert.calledOnce(readStub);
      assertEmptyResource(resource);
    });
  }


async () => {
      readStub = sinon
        .stub(DockerCGroupV1Detector, 'readFileAsync' as any)
        .resolves(undefined);

      const resource: Resource = await dockerCGroupV1Detector.detect();

      assert.deepStrictEqual(resource.attributes, {});
      assert.ok(resource);
    }


async () => {
      readStub = sinon
        .stub(DockerCGroupV1Detector, 'readFileAsync' as any)
        .resolves(correctCgroupData);

      const resource: Resource = await dockerCGroupV1Detector.detect();

      sinon.assert.calledOnce(readStub);

      assert.ok(resource);
      assertContainerResource(resource, {
        id: 'bcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklm',
      });
    }


async () => {
      readStub = sinon
        .stub(DockerCGroupV1Detector, 'readFileAsync' as any)
        .resolves('');

      const resource: Resource = await dockerCGroupV1Detector.detect();
      assert.deepStrictEqual(resource.attributes, {});

      sinon.assert.calledOnce(readStub);
      assert.ok(resource);
    }


async () => {
      const errorMsg = {
        fileNotFoundError: new Error('cannot find file in path'),
      };

      readStub = sinon
        .stub(DockerCGroupV1Detector, 'readFileAsync' as any)
        .rejects(errorMsg.fileNotFoundError);

      const resource: Resource = await dockerCGroupV1Detector.detect();

      sinon.assert.calledOnce(readStub);
      assertEmptyResource(resource);
    }


/**
 * Generate a random lion.
 *
 * @category animals
 *
 * @example
 *
 * randLion()
 *
 * @example
 *
 * randLion({ length: 10 })
 *
 */
export function randLion<Options extends FakeOptions = never>(
  options?: Options
) {
  return fake(data, options);
}


/**
 * Activate the notebook tools extension.
 */
function activateNotebookTools(
  app: JupyterFrontEnd,
  tracker: INotebookTracker,
  editorServices: IEditorServices,
  state: IStateDB,
  translator: ITranslator,
  inspectorProvider: IPropertyInspectorProvider | null
): INotebookTools {
  const trans = translator.load('jupyterlab');
  const id = 'notebook-tools';
  const notebookTools = new NotebookTools({ tracker, translator });
  const activeCellTool = new NotebookTools.ActiveCellTool();
  const editable = NotebookTools.createEditableToggle(translator);
  const slideShow = NotebookTools.createSlideShowSelector(translator);
  const editorFactory = editorServices.factoryService.newInlineEditor;
  const cellMetadataEditor = new NotebookTools.CellMetadataEditorTool({
    editorFactory,
    collapsed: false,
    translator
  });
  const notebookMetadataEditor = new NotebookTools.NotebookMetadataEditorTool({
    editorFactory,
    translator
  });

  const services = app.serviceManager;

  // Create message hook for triggers to save to the database.
  const hook = (sender: any, message: Message): boolean => {
    switch (message.type) {
      case 'activate-request':
        void state.save(id, { open: true });
        break;
      case 'after-hide':
      case 'close-request':
        void state.remove(id);
        break;
      default:
        break;
    }
    return true;
  };
  const optionsMap: { [key: string]: JSONValue } = {};
  optionsMap.None = null;
  void services.nbconvert.getExportFormats().then(response => {
    if (response) {
      /**
       * The excluded Cell Inspector Raw NbConvert Formats
       * (returned from nbconvert's export list)
       */
      const rawFormatExclude = [
        'pdf',
        'slides',
        'script',
        'notebook',
        'custom'
      ];
      let optionValueArray: any = [
        [trans.__('PDF'), 'pdf'],
        [trans.__('Slides'), 'slides'],
        [trans.__('Script'), 'script'],
        [trans.__('Notebook'), 'notebook'],
        [trans.__('Custom'), 'custom']
      ];

      // convert exportList to palette and menu items
      const formatList = Object.keys(response);
      const formatLabels = Private.getFormatLabels(translator);
      formatList.forEach(function (key) {
        if (rawFormatExclude.indexOf(key) === -1) {
          const altOption = trans.__(key[0].toUpperCase() + key.substr(1));
          const option = formatLabels[key] ? formatLabels[key] : altOption;
          const mimeTypeValue = response[key].output_mimetype;
          optionValueArray.push([option, mimeTypeValue]);
        }
      });
      const nbConvert = NotebookTools.createNBConvertSelector(
        optionValueArray,
        translator
      );
      notebookTools.addItem({ tool: nbConvert, section: 'common', rank: 3 });
    }
  });
  notebookTools.title.icon = buildIcon;
  notebookTools.title.caption = trans.__('Notebook Tools');
  notebookTools.id = id;

  notebookTools.addItem({ tool: activeCellTool, section: 'common', rank: 1 });
  notebookTools.addItem({ tool: editable, section: 'common', rank: 2 });
  notebookTools.addItem({ tool: slideShow, section: 'common', rank: 3 });

  notebookTools.addItem({
    tool: cellMetadataEditor,
    section: 'advanced',
    rank: 1
  });
  notebookTools.addItem({
    tool: notebookMetadataEditor,
    section: 'advanced',
    rank: 2
  });

  MessageLoop.installMessageHook(notebookTools, hook);

  if (inspectorProvider) {
    tracker.widgetAdded.connect((sender, panel) => {
      const inspector = inspectorProvider.register(panel);
      inspector.render(notebookTools);
    });
  }

  return notebookTools;
}


/**
 * Activate the notebook widget factory.
 */
function activateWidgetFactory(
  app: JupyterFrontEnd,
  contentFactory: NotebookPanel.IContentFactory,
  editorServices: IEditorServices,
  rendermime: IRenderMimeRegistry,
  sessionContextDialogs: ISessionContextDialogs,
  toolbarRegistry: IToolbarWidgetRegistry,
  translator: ITranslator,
  settingRegistry: ISettingRegistry | null
): NotebookWidgetFactory.IFactory {
  const { commands } = app;
  let toolbarFactory:
    | ((widget: NotebookPanel) => DocumentRegistry.IToolbarItem[])
    | undefined;

  // Register notebook toolbar widgets
  toolbarRegistry.registerFactory<NotebookPanel>(FACTORY, 'save', panel =>
    DocToolbarItems.createSaveButton(commands, panel.context.fileChanged)
  );
  toolbarRegistry.registerFactory<NotebookPanel>(FACTORY, 'cellType', panel =>
    ToolbarItems.createCellTypeItem(panel, translator)
  );
  toolbarRegistry.registerFactory<NotebookPanel>(FACTORY, 'kernelName', panel =>
    Toolbar.createKernelNameItem(
      panel.sessionContext,
      sessionContextDialogs,
      translator
    )
  );

  toolbarRegistry.registerFactory<NotebookPanel>(
    FACTORY,
    'executionProgress',
    panel => {
      return ExecutionIndicator.createExecutionIndicatorItem(
        panel,
        translator,
        settingRegistry?.load(trackerPlugin.id)
      );
    }
  );

  if (settingRegistry) {
    // Create the factory
    toolbarFactory = createToolbarFactory(
      toolbarRegistry,
      settingRegistry,
      FACTORY,
      PANEL_SETTINGS,
      translator
    );
  }

  const trans = translator.load('jupyterlab');

  const factory = new NotebookWidgetFactory({
    name: FACTORY,
    label: trans.__('Notebook'),
    fileTypes: ['notebook'],
    modelName: 'notebook',
    defaultFor: ['notebook'],
    preferKernel: true,
    canStartKernel: true,
    rendermime,
    contentFactory,
    editorConfig: StaticNotebook.defaultEditorConfig,
    notebookConfig: StaticNotebook.defaultNotebookConfig,
    mimeTypeService: editorServices.mimeTypeService,
    sessionDialogs: sessionContextDialogs,
    toolbarFactory,
    translator: translator
  });
  app.docRegistry.addWidgetFactory(factory);
  return factory;
}


/**
 * Activate the plugin to create and track cloned outputs.
 */
function activateClonedOutputs(
  app: JupyterFrontEnd,
  docManager: IDocumentManager,
  notebookTracker: INotebookTracker,
  translator: ITranslator,
  restorer: ILayoutRestorer | null
): void {
  const trans = translator.load('jupyterlab');
  const clonedOutputs = new WidgetTracker<
    MainAreaWidget<Private.ClonedOutputArea>
  >({
    namespace: 'cloned-outputs'
  });

  if (restorer) {
    void restorer.restore(clonedOutputs, {
      command: CommandIDs.createOutputView,
      args: widget => ({
        path: widget.content.path,
        index: widget.content.index
      }),
      name: widget => `${widget.content.path}:${widget.content.index}`,
      when: notebookTracker.restored // After the notebook widgets (but not contents).
    });
  }

  const { commands, shell } = app;

  const isEnabledAndSingleSelected = (): boolean => {
    return Private.isEnabledAndSingleSelected(shell, notebookTracker);
  };

  commands.addCommand(CommandIDs.createOutputView, {
    label: trans.__('Create New View for Output'),
    execute: async args => {
      let cell: CodeCell | undefined;
      let current: NotebookPanel | undefined | null;
      // If we are given a notebook path and cell index, then
      // use that, otherwise use the current active cell.
      const path = args.path as string | undefined | null;
      let index = args.index as number | undefined | null;
      if (path && index !== undefined && index !== null) {
        current = docManager.findWidget(path, FACTORY) as NotebookPanel;
        if (!current) {
          return;
        }
      } else {
        current = notebookTracker.currentWidget;
        if (!current) {
          return;
        }
        cell = current.content.activeCell as CodeCell;
        index = current.content.activeCellIndex;
      }
      // Create a MainAreaWidget
      const content = new Private.ClonedOutputArea({
        notebook: current,
        cell,
        index,
        translator
      });
      const widget = new MainAreaWidget({ content });
      current.context.addSibling(widget, {
        ref: current.id,
        mode: 'split-bottom'
      });

      const updateCloned = () => {
        void clonedOutputs.save(widget);
      };

      current.context.pathChanged.connect(updateCloned);
      current.context.model?.cells.changed.connect(updateCloned);

      // Add the cloned output to the output widget tracker.
      void clonedOutputs.add(widget);

      // Remove the output view if the parent notebook is closed.
      current.content.disposed.connect(() => {
        current!.context.pathChanged.disconnect(updateCloned);
        current!.context.model?.cells.changed.disconnect(updateCloned);
        widget.dispose();
      });
    },
    isEnabled: isEnabledAndSingleSelected
  });
}


/**
 * Activate the plugin to add code console functionalities
 */
function activateCodeConsole(
  app: JupyterFrontEnd,
  tracker: INotebookTracker,
  translator: ITranslator
): void {
  const trans = translator.load('jupyterlab');
  const { commands, shell } = app;

  const isEnabled = (): boolean => Private.isEnabled(shell, tracker);

  commands.addCommand(CommandIDs.createConsole, {
    label: trans.__('New Console for Notebook'),
    execute: args => {
      const current = tracker.currentWidget;

      if (!current) {
        return;
      }

      return Private.createConsole(
        commands,
        current,
        args['activate'] as boolean
      );
    },
    isEnabled
  });

  commands.addCommand(CommandIDs.runInConsole, {
    label: trans.__('Run Selected Text or Current Line in Console'),
    execute: async args => {
      // Default to not activating the notebook (thereby putting the notebook
      // into command mode)
      const current = tracker.currentWidget;

      if (!current) {
        return;
      }

      const { context, content } = current;

      const cell = content.activeCell;
      const metadata = cell?.model.metadata.toJSON();
      const path = context.path;
      // ignore action in non-code cell
      if (!cell || cell.model.type !== 'code') {
        return;
      }

      let code: string;
      const editor = cell.editor;
      const selection = editor.getSelection();
      const { start, end } = selection;
      const selected = start.column !== end.column || start.line !== end.line;

      if (selected) {
        // Get the selected code from the editor.
        const start = editor.getOffsetAt(selection.start);
        const end = editor.getOffsetAt(selection.end);
        code = editor.model.value.text.substring(start, end);
      } else {
        // no selection, find the complete statement around the current line
        const cursor = editor.getCursorPosition();
        const srcLines = editor.model.value.text.split('\n');
        let curLine = selection.start.line;
        while (
          curLine < editor.lineCount &&
          !srcLines[curLine].replace(/\s/g, '').length
        ) {
          curLine += 1;
        }
        // if curLine > 0, we first do a search from beginning
        let fromFirst = curLine > 0;
        let firstLine = 0;
        let lastLine = firstLine + 1;
        // eslint-disable-next-line
        while (true) {
          code = srcLines.slice(firstLine, lastLine).join('\n');
          const reply = await current.context.sessionContext.session?.kernel?.requestIsComplete(
            {
              // ipython needs an empty line at the end to correctly identify completeness of indented code
              code: code + '\n\n'
            }
          );
          if (reply?.content.status === 'complete') {
            if (curLine < lastLine) {
              // we find a block of complete statement containing the current line, great!
              while (
                lastLine < editor.lineCount &&
                !srcLines[lastLine].replace(/\s/g, '').length
              ) {
                lastLine += 1;
              }
              editor.setCursorPosition({
                line: lastLine,
                column: cursor.column
              });
              break;
            } else {
              // discard the complete statement before the current line and continue
              firstLine = lastLine;
              lastLine = firstLine + 1;
            }
          } else if (lastLine < editor.lineCount) {
            // if incomplete and there are more lines, add the line and check again
            lastLine += 1;
          } else if (fromFirst) {
            // we search from the first line and failed, we search again from current line
            firstLine = curLine;
            lastLine = curLine + 1;
            fromFirst = false;
          } else {
            // if we have searched both from first line and from current line and we
            // cannot find anything, we submit the current line.
            code = srcLines[curLine];
            while (
              curLine + 1 < editor.lineCount &&
              !srcLines[curLine + 1].replace(/\s/g, '').length
            ) {
              curLine += 1;
            }
            editor.setCursorPosition({
              line: curLine + 1,
              column: cursor.column
            });
            break;
          }
        }
      }

      if (!code) {
        return;
      }

      await commands.execute('console:open', {
        activate: false,
        insertMode: 'split-bottom',
        path
      });
      await commands.execute('console:inject', {
        activate: false,
        code,
        path,
        metadata
      });
    },
    isEnabled
  });
}


/**
 * Activate the output copying extension
 */
function activateCopyOutput(
  app: JupyterFrontEnd,
  translator: ITranslator,
  tracker: INotebookTracker
): void {
  const trans = translator.load('jupyterlab');

  /**
   * Copy the contents of an HTMLElement to the system clipboard
   */
  function copyElement(e: HTMLElement): void {
    const sel = window.getSelection();

    if (sel == null) {
      return;
    }

    // Save the current selection.
    const savedRanges: Range[] = [];
    for (let i = 0; i < sel.rangeCount; ++i) {
      savedRanges[i] = sel.getRangeAt(i).cloneRange();
    }

    const range = document.createRange();
    range.selectNodeContents(e);
    sel.removeAllRanges();
    sel.addRange(range);

    document.execCommand('copy');

    // Restore the saved selection.
    sel.removeAllRanges();
    savedRanges.forEach(r => sel.addRange(r));
  }

  app.commands.addCommand(CommandIDs.copyToClipboard, {
    label: trans.__('Copy Output to Clipboard'),
    execute: args => {
      const cell = tracker.currentWidget?.content.activeCell as CodeCell;

      if (cell == null) {
        return;
      }

      const output = cell.outputArea.outputTracker.currentWidget;

      if (output == null) {
        return;
      }

      const outputAreaAreas = output.node.getElementsByClassName(
        'jp-OutputArea-output'
      );
      if (outputAreaAreas.length > 0) {
        const area = outputAreaAreas[0];
        copyElement(area as HTMLElement);
      }
    }
  });

  app.contextMenu.addItem({
    command: CommandIDs.copyToClipboard,
    selector: '.jp-OutputArea-child',
    rank: 0
  });
}


/**
   * Copy the contents of an HTMLElement to the system clipboard
   */
function copyElement(e: HTMLElement): void {
    const sel = window.getSelection();

    if (sel == null) {
      return;
    }

    // Save the current selection.
    const savedRanges: Range[] = [];
    for (let i = 0; i < sel.rangeCount; ++i) {
      savedRanges[i] = sel.getRangeAt(i).cloneRange();
    }

    const range = document.createRange();
    range.selectNodeContents(e);
    sel.removeAllRanges();
    sel.addRange(range);

    document.execCommand('copy');

    // Restore the saved selection.
    sel.removeAllRanges();
    savedRanges.forEach(r => sel.addRange(r));
  }


/**
   * Update the settings of the current tracker.
   */
function updateTracker(options: NotebookPanel.IConfig): void {
    tracker.forEach(widget => {
      widget.setConfig(options);
    });
  }


/**
   * Update the setting values.
   */
function updateConfig(settings: ISettingRegistry.ISettings): void {
    const code = {
      ...StaticNotebook.defaultEditorConfig.code,
      ...(settings.get('codeCellConfig').composite as JSONObject)
    };

    const markdown = {
      ...StaticNotebook.defaultEditorConfig.markdown,
      ...(settings.get('markdownCellConfig').composite as JSONObject)
    };

    const raw = {
      ...StaticNotebook.defaultEditorConfig.raw,
      ...(settings.get('rawCellConfig').composite as JSONObject)
    };

    factory.editorConfig = { code, markdown, raw };
    factory.notebookConfig = {
      showHiddenCellsButton: settings.get('showHiddenCellsButton')
        .composite as boolean,
      scrollPastEnd: settings.get('scrollPastEnd').composite as boolean,
      defaultCell: settings.get('defaultCell').composite as nbformat.CellType,
      recordTiming: settings.get('recordTiming').composite as boolean,
      numberCellsToRenderDirectly: settings.get('numberCellsToRenderDirectly')
        .composite as number,
      renderCellOnIdle: settings.get('renderCellOnIdle').composite as boolean,
      observedTopMargin: settings.get('observedTopMargin').composite as string,
      observedBottomMargin: settings.get('observedBottomMargin')
        .composite as string,
      maxNumberOutputs: settings.get('maxNumberOutputs').composite as number,
      disableDocumentWideUndoRedo: settings.get(
        'experimentalDisableDocumentWideUndoRedo'
      ).composite as boolean
    };
    factory.shutdownOnClose = settings.get('kernelShutdown')
      .composite as boolean;

    modelFactory.disableDocumentWideUndoRedo = settings.get(
      'experimentalDisableDocumentWideUndoRedo'
    ).composite as boolean;

    Private.renderSideBySide = !settings.get('sideBySideRendering')
      .composite as boolean;
    commands.execute(CommandIDs.toggleRenderSideBySide);

    updateTracker({
      editorConfig: factory.editorConfig,
      notebookConfig: factory.notebookConfig,
      kernelShutdown: factory.shutdownOnClose
    });
  }


// Get the current widget and activate unless the args specify otherwise.
function getCurrent(
  tracker: INotebookTracker,
  shell: JupyterFrontEnd.IShell,
  args: ReadonlyPartialJSONObject
): NotebookPanel | null {
  const widget = tracker.currentWidget;
  const activate = args['activate'] !== false;

  if (activate && widget) {
    shell.activateById(widget.id);
  }

  return widget;
}


/**
 * Populate the application's command palette with notebook commands.
 */
function populatePalette(
  palette: ICommandPalette,
  translator: ITranslator
): void {
  const trans = translator.load('jupyterlab');
  let category = trans.__('Notebook Operations');

  [
    CommandIDs.interrupt,
    CommandIDs.restart,
    CommandIDs.restartClear,
    CommandIDs.restartRunAll,
    CommandIDs.runAll,
    CommandIDs.renderAllMarkdown,
    CommandIDs.runAllAbove,
    CommandIDs.runAllBelow,
    CommandIDs.restartAndRunToSelected,
    CommandIDs.selectAll,
    CommandIDs.deselectAll,
    CommandIDs.clearAllOutputs,
    CommandIDs.toggleAllLines,
    CommandIDs.editMode,
    CommandIDs.commandMode,
    CommandIDs.changeKernel,
    CommandIDs.reconnectToKernel,
    CommandIDs.createConsole,
    CommandIDs.closeAndShutdown,
    CommandIDs.trust,
    CommandIDs.toggleCollapseCmd,
    CommandIDs.collapseAllCmd,
    CommandIDs.expandAllCmd
  ].forEach(command => {
    palette.addItem({ command, category });
  });

  palette.addItem({
    command: CommandIDs.createNew,
    category,
    args: { isPalette: true }
  });

  category = trans.__('Notebook Cell Operations');
  [
    CommandIDs.run,
    CommandIDs.runAndAdvance,
    CommandIDs.runAndInsert,
    CommandIDs.runInConsole,
    CommandIDs.clearOutputs,
    CommandIDs.toCode,
    CommandIDs.toMarkdown,
    CommandIDs.toRaw,
    CommandIDs.cut,
    CommandIDs.copy,
    CommandIDs.pasteBelow,
    CommandIDs.pasteAbove,
    CommandIDs.pasteAndReplace,
    CommandIDs.deleteCell,
    CommandIDs.split,
    CommandIDs.merge,
    CommandIDs.mergeAbove,
    CommandIDs.mergeBelow,
    CommandIDs.insertAbove,
    CommandIDs.insertBelow,
    CommandIDs.selectAbove,
    CommandIDs.selectBelow,
    CommandIDs.extendAbove,
    CommandIDs.extendTop,
    CommandIDs.extendBelow,
    CommandIDs.extendBottom,
    CommandIDs.moveDown,
    CommandIDs.moveUp,
    CommandIDs.undoCellAction,
    CommandIDs.redoCellAction,
    CommandIDs.markdown1,
    CommandIDs.markdown2,
    CommandIDs.markdown3,
    CommandIDs.markdown4,
    CommandIDs.markdown5,
    CommandIDs.markdown6,
    CommandIDs.hideCode,
    CommandIDs.showCode,
    CommandIDs.hideAllCode,
    CommandIDs.showAllCode,
    CommandIDs.hideOutput,
    CommandIDs.showOutput,
    CommandIDs.hideAllOutputs,
    CommandIDs.showAllOutputs,
    CommandIDs.toggleRenderSideBySide,
    CommandIDs.setSideBySideRatio,
    CommandIDs.enableOutputScrolling,
    CommandIDs.disableOutputScrolling
  ].forEach(command => {
    palette.addItem({ command, category });
  });
}


/**
 * Populates the application menus for the notebook.
 */
function populateMenus(
  app: JupyterFrontEnd,
  mainMenu: IMainMenu,
  tracker: INotebookTracker,
  translator: ITranslator,
  sessionDialogs: ISessionContextDialogs | null
): void {
  const trans = translator.load('jupyterlab');
  const { commands } = app;
  sessionDialogs = sessionDialogs || sessionContextDialogs;

  // Add undo/redo hooks to the edit menu.
  mainMenu.editMenu.undoers.add({
    tracker,
    undo: widget => {
      widget.content.activeCell?.editor.undo();
    },
    redo: widget => {
      widget.content.activeCell?.editor.redo();
    }
  } as IEditMenu.IUndoer<NotebookPanel>);

  // Add a clearer to the edit menu
  mainMenu.editMenu.clearers.add({
    tracker,
    clearCurrentLabel: (n: number) => trans.__('Clear Output'),
    clearAllLabel: (n: number) => {
      return trans.__('Clear All Outputs');
    },
    clearCurrent: (current: NotebookPanel) => {
      return NotebookActions.clearOutputs(current.content);
    },
    clearAll: (current: NotebookPanel) => {
      return NotebookActions.clearAllOutputs(current.content);
    }
  } as IEditMenu.IClearer<NotebookPanel>);

  // Add a close and shutdown command to the file menu.
  mainMenu.fileMenu.closeAndCleaners.add({
    tracker,
    closeAndCleanupLabel: (n: number) =>
      trans.__('Close and Shutdown Notebook'),
    closeAndCleanup: (current: NotebookPanel) => {
      const fileName = current.title.label;
      return showDialog({
        title: trans.__('Shut down the Notebook?'),
        body: trans.__('Are you sure you want to close "%1"?', fileName),
        buttons: [Dialog.cancelButton(), Dialog.warnButton()]
      }).then(result => {
        if (result.button.accept) {
          return current.context.sessionContext.shutdown().then(() => {
            current.dispose();
          });
        }
      });
    }
  } as IFileMenu.ICloseAndCleaner<NotebookPanel>);

  // Add a kernel user to the Kernel menu
  mainMenu.kernelMenu.kernelUsers.add({
    tracker,
    interruptKernel: current => {
      const kernel = current.sessionContext.session?.kernel;
      if (kernel) {
        return kernel.interrupt();
      }
      return Promise.resolve(void 0);
    },
    reconnectToKernel: current => {
      const kernel = current.sessionContext.session?.kernel;
      if (kernel) {
        return kernel.reconnect();
      }
      return Promise.resolve(void 0);
    },
    restartKernelAndClearLabel: (n: number) =>
      trans.__('Restart Kernel and Clear All Outputs…'),
    restartKernel: current =>
      sessionDialogs!.restart(current.sessionContext, translator),
    restartKernelAndClear: current => {
      return sessionDialogs!
        .restart(current.sessionContext, translator)
        .then(restarted => {
          if (restarted) {
            NotebookActions.clearAllOutputs(current.content);
          }
          return restarted;
        });
    },
    changeKernel: current =>
      sessionDialogs!.selectKernel(current.sessionContext, translator),
    shutdownKernel: current => current.sessionContext.shutdown()
  } as IKernelMenu.IKernelUser<NotebookPanel>);

  // Add a console creator the the Kernel menu
  mainMenu.fileMenu.consoleCreators.add({
    tracker,
    createConsoleLabel: (n: number) => trans.__('New Console for Notebook'),
    createConsole: current => Private.createConsole(commands, current, true)
  } as IFileMenu.IConsoleCreator<NotebookPanel>);

  // Add an IEditorViewer to the application view menu
  mainMenu.viewMenu.editorViewers.add({
    tracker,
    toggleLineNumbers: widget => {
      NotebookActions.toggleAllLineNumbers(widget.content);
    },
    lineNumbersToggled: widget => {
      const config = widget.content.editorConfig;
      return !!(
        config.code.lineNumbers &&
        config.markdown.lineNumbers &&
        config.raw.lineNumbers
      );
    }
  } as IViewMenu.IEditorViewer<NotebookPanel>);

  // Add an ICodeRunner to the application run menu
  mainMenu.runMenu.codeRunners.add({
    tracker,
    runLabel: (n: number) => trans.__('Run Selected Cells'),
    runCaption: (n: number) => trans.__('Run the selected cells and advance'),
    runAllLabel: (n: number) => trans.__('Run All Cells'),
    runAllCaption: (n: number) => trans.__('Run the all notebook cells'),
    restartAndRunAllLabel: (n: number) =>
      trans.__('Restart Kernel and Run All Cells…'),
    restartAndRunAllCaption: (n: number) =>
      trans.__('Restart the kernel, then re-run the whole notebook'),
    run: current => {
      const { context, content } = current;
      return NotebookActions.runAndAdvance(
        content,
        context.sessionContext
      ).then(() => void 0);
    },
    runAll: current => {
      const { context, content } = current;
      return NotebookActions.runAll(content, context.sessionContext).then(
        () => void 0
      );
    },
    restartAndRunAll: current => {
      const { context, content } = current;
      return sessionDialogs!
        .restart(context.sessionContext, translator)
        .then(restarted => {
          if (restarted) {
            void NotebookActions.runAll(content, context.sessionContext);
          }
          return restarted;
        });
    }
  } as IRunMenu.ICodeRunner<NotebookPanel>);

  // Add kernel information to the application help menu.
  mainMenu.helpMenu.kernelUsers.add({
    tracker,
    getKernel: current => current.sessionContext.session?.kernel
  } as IHelpMenu.IKernelUser<NotebookPanel>);
}


/**
   * Create a console connected with a notebook kernel
   *
   * @param commands Commands registry
   * @param widget Notebook panel
   * @param activate Should the console be activated
   */
export function createConsole(
    commands: CommandRegistry,
    widget: NotebookPanel,
    activate?: boolean
  ): Promise<void> {
    const options = {
      path: widget.context.path,
      preferredLanguage: widget.context.model.defaultKernelLanguage,
      activate: activate,
      ref: widget.id,
      insertMode: 'split-bottom'
    };

    return commands.execute('console:create', options);
  }


/**
   * Whether there is an active notebook.
   */
export function isEnabled(
    shell: JupyterFrontEnd.IShell,
    tracker: INotebookTracker
  ): boolean {
    return (
      tracker.currentWidget !== null &&
      tracker.currentWidget === shell.currentWidget
    );
  }


/**
   * Whether there is an notebook active, with a single selected cell.
   */
export function isEnabledAndSingleSelected(
    shell: JupyterFrontEnd.IShell,
    tracker: INotebookTracker
  ): boolean {
    if (!Private.isEnabled(shell, tracker)) {
      return false;
    }
    const { content } = tracker.currentWidget!;
    const index = content.activeCellIndex;
    // If there are selections that are not the active cell,
    // this command is confusing, so disable it.
    for (let i = 0; i < content.widgets.length; ++i) {
      if (content.isSelected(content.widgets[i]) && i !== index) {
        return false;
      }
    }
    return true;
  }


/**
   * Whether there is an notebook active, with a single selected cell.
   */
export function isEnabledAndHeadingSelected(
    shell: JupyterFrontEnd.IShell,
    tracker: INotebookTracker
  ): boolean {
    if (!Private.isEnabled(shell, tracker)) {
      return false;
    }
    const { content } = tracker.currentWidget!;
    const index = content.activeCellIndex;
    if (!(content.activeCell instanceof MarkdownCell)) {
      return false;
    }
    // If there are selections that are not the active cell,
    // this command is confusing, so disable it.
    for (let i = 0; i < content.widgets.length; ++i) {
      if (content.isSelected(content.widgets[i]) && i !== index) {
        return false;
      }
    }
    return true;
  }


/**
   * The default Export To ... formats and their human readable labels.
   */
export function getFormatLabels(
    translator: ITranslator
  ): { [k: string]: string } {
    translator = translator || nullTranslator;
    const trans = translator.load('jupyterlab');
    return {
      html: trans.__('HTML'),
      latex: trans.__('LaTeX'),
      markdown: trans.__('Markdown'),
      pdf: trans.__('PDF'),
      rst: trans.__('ReStructured Text'),
      script: trans.__('Executable Script'),
      slides: trans.__('Reveal.js Slides')
    };
  }


(app: JupyterFrontEnd, editorServices: IEditorServices) => {
    const editorFactory = editorServices.factoryService.newInlineEditor;
    return new NotebookPanel.ContentFactory({ editorFactory });
  }


(
    app: JupyterFrontEnd,
    tracker: INotebookTracker,
    translator: ITranslator,
    statusBar: IStatusBar | null
  ) => {
    if (!statusBar) {
      // Automatically disable if statusbar missing
      return;
    }
    const { shell } = app;
    const item = new CommandEditStatus(translator);

    // Keep the status item up-to-date with the current notebook.
    tracker.currentChanged.connect(() => {
      const current = tracker.currentWidget;
      item.model.notebook = current && current.content;
    });

    statusBar.registerStatusItem('@jupyterlab/notebook-extension:mode-status', {
      item,
      align: 'right',
      rank: 4,
      isActive: () =>
        !!shell.currentWidget &&
        !!tracker.currentWidget &&
        shell.currentWidget === tracker.currentWidget
    });
  }


() => {
      const current = tracker.currentWidget;
      item.model.notebook = current && current.content;
    }


() =>
        !!shell.currentWidget &&
        !!tracker.currentWidget &&
        shell.currentWidget === tracker.currentWidget


(
    app: JupyterFrontEnd,
    notebookTracker: INotebookTracker,
    labShell: ILabShell,
    translator: ITranslator,
    statusBar: IStatusBar | null,
    settingRegistry: ISettingRegistry | null
  ) => {
    let statusbarItem: ExecutionIndicator;
    let labShellCurrentChanged: (
      _: ILabShell,
      change: ILabShell.IChangedArgs
    ) => void;

    let statusBarDisposable: IDisposable;

    const updateSettings = (settings: {
      showOnToolBar: boolean;
      showProgress: boolean;
    }): void => {
      let { showOnToolBar, showProgress } = settings;

      if (!showOnToolBar) {
        // Status bar mode, only one `ExecutionIndicator` is needed.
        if (!statusBar) {
          // Automatically disable if statusbar missing
          return;
        }

        if (!statusbarItem?.model) {
          statusbarItem = new ExecutionIndicator(translator);
          labShellCurrentChanged = (
            _: ILabShell,
            change: ILabShell.IChangedArgs
          ) => {
            const { newValue } = change;
            if (newValue && notebookTracker.has(newValue)) {
              const panel = newValue as NotebookPanel;
              statusbarItem.model!.attachNotebook({
                content: panel.content,
                context: panel.sessionContext
              });
            }
          };
          statusBarDisposable = statusBar.registerStatusItem(
            '@jupyterlab/notebook-extension:execution-indicator',
            {
              item: statusbarItem,
              align: 'left',
              rank: 3,
              isActive: () => {
                const current = labShell.currentWidget;
                return !!current && notebookTracker.has(current);
              }
            }
          );

          statusbarItem.model.attachNotebook({
            content: notebookTracker.currentWidget?.content,
            context: notebookTracker.currentWidget?.sessionContext
          });

          labShell.currentChanged.connect(labShellCurrentChanged);
          statusbarItem.disposed.connect(() => {
            labShell.currentChanged.disconnect(labShellCurrentChanged);
          });
        }

        statusbarItem.model.displayOption = {
          showOnToolBar,
          showProgress
        };
      } else {
        //Remove old indicator widget on status bar
        if (statusBarDisposable) {
          labShell.currentChanged.disconnect(labShellCurrentChanged);
          statusBarDisposable.dispose();
        }
      }
    };

    if (settingRegistry) {
      // Indicator is default in tool bar, user needs to specify its
      // position in settings in order to have indicator on status bar.
      const loadSettings = settingRegistry.load(trackerPlugin.id);
      Promise.all([loadSettings, app.restored])
        .then(([settings]) => {
          updateSettings(ExecutionIndicator.getSettingValue(settings));
          settings.changed.connect(sender =>
            updateSettings(ExecutionIndicator.getSettingValue(sender))
          );
        })
        .catch((reason: Error) => {
          console.error(reason.message);
        });
    }
  }


(settings: {
      showOnToolBar: boolean;
      showProgress: boolean;
    }): void => {
      let { showOnToolBar, showProgress } = settings;

      if (!showOnToolBar) {
        // Status bar mode, only one `ExecutionIndicator` is needed.
        if (!statusBar) {
          // Automatically disable if statusbar missing
          return;
        }

        if (!statusbarItem?.model) {
          statusbarItem = new ExecutionIndicator(translator);
          labShellCurrentChanged = (
            _: ILabShell,
            change: ILabShell.IChangedArgs
          ) => {
            const { newValue } = change;
            if (newValue && notebookTracker.has(newValue)) {
              const panel = newValue as NotebookPanel;
              statusbarItem.model!.attachNotebook({
                content: panel.content,
                context: panel.sessionContext
              });
            }
          };
          statusBarDisposable = statusBar.registerStatusItem(
            '@jupyterlab/notebook-extension:execution-indicator',
            {
              item: statusbarItem,
              align: 'left',
              rank: 3,
              isActive: () => {
                const current = labShell.currentWidget;
                return !!current && notebookTracker.has(current);
              }
            }
          );

          statusbarItem.model.attachNotebook({
            content: notebookTracker.currentWidget?.content,
            context: notebookTracker.currentWidget?.sessionContext
          });

          labShell.currentChanged.connect(labShellCurrentChanged);
          statusbarItem.disposed.connect(() => {
            labShell.currentChanged.disconnect(labShellCurrentChanged);
          });
        }

        statusbarItem.model.displayOption = {
          showOnToolBar,
          showProgress
        };
      } else {
        //Remove old indicator widget on status bar
        if (statusBarDisposable) {
          labShell.currentChanged.disconnect(labShellCurrentChanged);
          statusBarDisposable.dispose();
        }
      }
    }


(
            _: ILabShell,
            change: ILabShell.IChangedArgs
          ) => {
            const { newValue } = change;
            if (newValue && notebookTracker.has(newValue)) {
              const panel = newValue as NotebookPanel;
              statusbarItem.model!.attachNotebook({
                content: panel.content,
                context: panel.sessionContext
              });
            }
          }


() => {
                const current = labShell.currentWidget;
                return !!current && notebookTracker.has(current);
              }


() => {
            labShell.currentChanged.disconnect(labShellCurrentChanged);
          }


([settings]) => {
          updateSettings(ExecutionIndicator.getSettingValue(settings));
          settings.changed.connect(sender =>
            updateSettings(ExecutionIndicator.getSettingValue(sender))
          );
        }


sender =>
            updateSettings(ExecutionIndicator.getSettingValue(sender))


(reason: Error) => {
          console.error(reason.message);
        }


(
    app: JupyterFrontEnd,
    translator: ITranslator,
    tracker: INotebookTracker,
    mainMenu: IMainMenu | null,
    palette: ICommandPalette | null
  ) => {
    const trans = translator.load('jupyterlab');
    const { commands, shell } = app;
    const services = app.serviceManager;

    const isEnabled = (): boolean => {
      return Private.isEnabled(shell, tracker);
    };

    commands.addCommand(CommandIDs.exportToFormat, {
      label: args => {
        const formatLabel = args['label'] as string;
        return args['isPalette']
          ? trans.__('Save and Export Notebook: %1', formatLabel)
          : formatLabel;
      },
      execute: args => {
        const current = getCurrent(tracker, shell, args);

        if (!current) {
          return;
        }

        const url = PageConfig.getNBConvertURL({
          format: args['format'] as string,
          download: true,
          path: current.context.path
        });
        const { context } = current;

        if (context.model.dirty && !context.model.readOnly) {
          return context.save().then(() => {
            window.open(url, '_blank', 'noopener');
          });
        }

        return new Promise<void>(resolve => {
          window.open(url, '_blank', 'noopener');
          resolve(undefined);
        });
      },
      isEnabled
    });

    // Add a notebook group to the File menu.
    let exportTo: Menu | null | undefined;
    if (mainMenu) {
      exportTo = mainMenu.fileMenu.items.find(
        item =>
          item.type === 'submenu' &&
          item.submenu?.id === 'jp-mainmenu-file-notebookexport'
      )?.submenu;
    }

    void services.nbconvert.getExportFormats().then(response => {
      if (response) {
        const formatLabels: any = Private.getFormatLabels(translator);

        // Convert export list to palette and menu items.
        const formatList = Object.keys(response);
        formatList.forEach(function (key) {
          const capCaseKey = trans.__(key[0].toUpperCase() + key.substr(1));
          const labelStr = formatLabels[key] ? formatLabels[key] : capCaseKey;
          let args = {
            format: key,
            label: labelStr,
            isPalette: false
          };
          if (FORMAT_EXCLUDE.indexOf(key) === -1) {
            if (exportTo) {
              exportTo.addItem({
                command: CommandIDs.exportToFormat,
                args: args
              });
            }
            if (palette) {
              args = {
                format: key,
                label: labelStr,
                isPalette: true
              };
              const category = trans.__('Notebook Operations');
              palette.addItem({
                command: CommandIDs.exportToFormat,
                category,
                args
              });
            }
          }
        });
      }
    });
  }


(): boolean => {
      return Private.isEnabled(shell, tracker);
    }


args => {
        const formatLabel = args['label'] as string;
        return args['isPalette']
          ? trans.__('Save and Export Notebook: %1', formatLabel)
          : formatLabel;
      }


args => {
        const current = getCurrent(tracker, shell, args);

        if (!current) {
          return;
        }

        const url = PageConfig.getNBConvertURL({
          format: args['format'] as string,
          download: true,
          path: current.context.path
        });
        const { context } = current;

        if (context.model.dirty && !context.model.readOnly) {
          return context.save().then(() => {
            window.open(url, '_blank', 'noopener');
          });
        }

        return new Promise<void>(resolve => {
          window.open(url, '_blank', 'noopener');
          resolve(undefined);
        });
      }


() => {
            window.open(url, '_blank', 'noopener');
          }


resolve => {
          window.open(url, '_blank', 'noopener');
          resolve(undefined);
        }


item =>
          item.type === 'submenu' &&
          item.submenu?.id === 'jp-mainmenu-file-notebookexport'


response => {
      if (response) {
        const formatLabels: any = Private.getFormatLabels(translator);

        // Convert export list to palette and menu items.
        const formatList = Object.keys(response);
        formatList.forEach(function (key) {
          const capCaseKey = trans.__(key[0].toUpperCase() + key.substr(1));
          const labelStr = formatLabels[key] ? formatLabels[key] : capCaseKey;
          let args = {
            format: key,
            label: labelStr,
            isPalette: false
          };
          if (FORMAT_EXCLUDE.indexOf(key) === -1) {
            if (exportTo) {
              exportTo.addItem({
                command: CommandIDs.exportToFormat,
                args: args
              });
            }
            if (palette) {
              args = {
                format: key,
                label: labelStr,
                isPalette: true
              };
              const category = trans.__('Notebook Operations');
              palette.addItem({
                command: CommandIDs.exportToFormat,
                category,
                args
              });
            }
          }
        });
      }
    }


(
    app: JupyterFrontEnd,
    tracker: INotebookTracker,
    tranlator: ITranslator,
    statusBar: IStatusBar | null
  ) => {
    if (!statusBar) {
      // Automatically disable if statusbar missing
      return;
    }
    const { shell } = app;
    const item = new NotebookTrustStatus(tranlator);

    // Keep the status item up-to-date with the current notebook.
    tracker.currentChanged.connect(() => {
      const current = tracker.currentWidget;
      item.model.notebook = current && current.content;
    });

    statusBar.registerStatusItem(
      '@jupyterlab/notebook-extension:trust-status',
      {
        item,
        align: 'right',
        rank: 3,
        isActive: () =>
          !!shell.currentWidget &&
          !!tracker.currentWidget &&
          shell.currentWidget === tracker.currentWidget
      }
    );
  }


() =>
          !!shell.currentWidget &&
          !!tracker.currentWidget &&
          shell.currentWidget === tracker.currentWidget


(sender: any, message: Message): boolean => {
    switch (message.type) {
      case 'activate-request':
        void state.save(id, { open: true });
        break;
      case 'after-hide':
      case 'close-request':
        void state.remove(id);
        break;
      default:
        break;
    }
    return true;
  }


response => {
    if (response) {
      /**
       * The excluded Cell Inspector Raw NbConvert Formats
       * (returned from nbconvert's export list)
       */
      const rawFormatExclude = [
        'pdf',
        'slides',
        'script',
        'notebook',
        'custom'
      ];
      let optionValueArray: any = [
        [trans.__('PDF'), 'pdf'],
        [trans.__('Slides'), 'slides'],
        [trans.__('Script'), 'script'],
        [trans.__('Notebook'), 'notebook'],
        [trans.__('Custom'), 'custom']
      ];

      // convert exportList to palette and menu items
      const formatList = Object.keys(response);
      const formatLabels = Private.getFormatLabels(translator);
      formatList.forEach(function (key) {
        if (rawFormatExclude.indexOf(key) === -1) {
          const altOption = trans.__(key[0].toUpperCase() + key.substr(1));
          const option = formatLabels[key] ? formatLabels[key] : altOption;
          const mimeTypeValue = response[key].output_mimetype;
          optionValueArray.push([option, mimeTypeValue]);
        }
      });
      const nbConvert = NotebookTools.createNBConvertSelector(
        optionValueArray,
        translator
      );
      notebookTools.addItem({ tool: nbConvert, section: 'common', rank: 3 });
    }
  }


(sender, panel) => {
      const inspector = inspectorProvider.register(panel);
      inspector.render(notebookTools);
    }


panel =>
    DocToolbarItems.createSaveButton(commands, panel.context.fileChanged)


panel =>
    ToolbarItems.createCellTypeItem(panel, translator)


panel =>
    Toolbar.createKernelNameItem(
      panel.sessionContext,
      sessionContextDialogs,
      translator
    )


panel => {
      return ExecutionIndicator.createExecutionIndicatorItem(
        panel,
        translator,
        settingRegistry?.load(trackerPlugin.id)
      );
    }


widget => ({
        path: widget.content.path,
        index: widget.content.index
      })


widget => `${widget.content.path}:${widget.content.index}`


(): boolean => {
    return Private.isEnabledAndSingleSelected(shell, notebookTracker);
  }


async args => {
      let cell: CodeCell | undefined;
      let current: NotebookPanel | undefined | null;
      // If we are given a notebook path and cell index, then
      // use that, otherwise use the current active cell.
      const path = args.path as string | undefined | null;
      let index = args.index as number | undefined | null;
      if (path && index !== undefined && index !== null) {
        current = docManager.findWidget(path, FACTORY) as NotebookPanel;
        if (!current) {
          return;
        }
      } else {
        current = notebookTracker.currentWidget;
        if (!current) {
          return;
        }
        cell = current.content.activeCell as CodeCell;
        index = current.content.activeCellIndex;
      }
      // Create a MainAreaWidget
      const content = new Private.ClonedOutputArea({
        notebook: current,
        cell,
        index,
        translator
      });
      const widget = new MainAreaWidget({ content });
      current.context.addSibling(widget, {
        ref: current.id,
        mode: 'split-bottom'
      });

      const updateCloned = () => {
        void clonedOutputs.save(widget);
      };

      current.context.pathChanged.connect(updateCloned);
      current.context.model?.cells.changed.connect(updateCloned);

      // Add the cloned output to the output widget tracker.
      void clonedOutputs.add(widget);

      // Remove the output view if the parent notebook is closed.
      current.content.disposed.connect(() => {
        current!.context.pathChanged.disconnect(updateCloned);
        current!.context.model?.cells.changed.disconnect(updateCloned);
        widget.dispose();
      });
    }


() => {
        void clonedOutputs.save(widget);
      }


() => {
        current!.context.pathChanged.disconnect(updateCloned);
        current!.context.model?.cells.changed.disconnect(updateCloned);
        widget.dispose();
      }


(): boolean => Private.isEnabled(shell, tracker)


args => {
      const current = tracker.currentWidget;

      if (!current) {
        return;
      }

      return Private.createConsole(
        commands,
        current,
        args['activate'] as boolean
      );
    }


async args => {
      // Default to not activating the notebook (thereby putting the notebook
      // into command mode)
      const current = tracker.currentWidget;

      if (!current) {
        return;
      }

      const { context, content } = current;

      const cell = content.activeCell;
      const metadata = cell?.model.metadata.toJSON();
      const path = context.path;
      // ignore action in non-code cell
      if (!cell || cell.model.type !== 'code') {
        return;
      }

      let code: string;
      const editor = cell.editor;
      const selection = editor.getSelection();
      const { start, end } = selection;
      const selected = start.column !== end.column || start.line !== end.line;

      if (selected) {
        // Get the selected code from the editor.
        const start = editor.getOffsetAt(selection.start);
        const end = editor.getOffsetAt(selection.end);
        code = editor.model.value.text.substring(start, end);
      } else {
        // no selection, find the complete statement around the current line
        const cursor = editor.getCursorPosition();
        const srcLines = editor.model.value.text.split('\n');
        let curLine = selection.start.line;
        while (
          curLine < editor.lineCount &&
          !srcLines[curLine].replace(/\s/g, '').length
        ) {
          curLine += 1;
        }
        // if curLine > 0, we first do a search from beginning
        let fromFirst = curLine > 0;
        let firstLine = 0;
        let lastLine = firstLine + 1;
        // eslint-disable-next-line
        while (true) {
          code = srcLines.slice(firstLine, lastLine).join('\n');
          const reply = await current.context.sessionContext.session?.kernel?.requestIsComplete(
            {
              // ipython needs an empty line at the end to correctly identify completeness of indented code
              code: code + '\n\n'
            }
          );
          if (reply?.content.status === 'complete') {
            if (curLine < lastLine) {
              // we find a block of complete statement containing the current line, great!
              while (
                lastLine < editor.lineCount &&
                !srcLines[lastLine].replace(/\s/g, '').length
              ) {
                lastLine += 1;
              }
              editor.setCursorPosition({
                line: lastLine,
                column: cursor.column
              });
              break;
            } else {
              // discard the complete statement before the current line and continue
              firstLine = lastLine;
              lastLine = firstLine + 1;
            }
          } else if (lastLine < editor.lineCount) {
            // if incomplete and there are more lines, add the line and check again
            lastLine += 1;
          } else if (fromFirst) {
            // we search from the first line and failed, we search again from current line
            firstLine = curLine;
            lastLine = curLine + 1;
            fromFirst = false;
          } else {
            // if we have searched both from first line and from current line and we
            // cannot find anything, we submit the current line.
            code = srcLines[curLine];
            while (
              curLine + 1 < editor.lineCount &&
              !srcLines[curLine + 1].replace(/\s/g, '').length
            ) {
              curLine += 1;
            }
            editor.setCursorPosition({
              line: curLine + 1,
              column: cursor.column
            });
            break;
          }
        }
      }

      if (!code) {
        return;
      }

      await commands.execute('console:open', {
        activate: false,
        insertMode: 'split-bottom',
        path
      });
      await commands.execute('console:inject', {
        activate: false,
        code,
        path,
        metadata
      });
    }


r => sel.addRange(r)


args => {
      const cell = tracker.currentWidget?.content.activeCell as CodeCell;

      if (cell == null) {
        return;
      }

      const output = cell.outputArea.outputTracker.currentWidget;

      if (output == null) {
        return;
      }

      const outputAreaAreas = output.node.getElementsByClassName(
        'jp-OutputArea-output'
      );
      if (outputAreaAreas.length > 0) {
        const area = outputAreaAreas[0];
        copyElement(area as HTMLElement);
      }
    }


settings => {
        updateConfig(settings);
        settings.changed.connect(() => {
          updateConfig(settings);
        });
        commands.addCommand(CommandIDs.autoClosingBrackets, {
          execute: args => {
            const codeConfig = settings.get('codeCellConfig')
              .composite as JSONObject;
            const markdownConfig = settings.get('markdownCellConfig')
              .composite as JSONObject;
            const rawConfig = settings.get('rawCellConfig')
              .composite as JSONObject;

            const anyToggled =
              codeConfig.autoClosingBrackets ||
              markdownConfig.autoClosingBrackets ||
              rawConfig.autoClosingBrackets;
            const toggled = !!(args['force'] ?? !anyToggled);
            [
              codeConfig.autoClosingBrackets,
              markdownConfig.autoClosingBrackets,
              rawConfig.autoClosingBrackets
            ] = [toggled, toggled, toggled];

            void settings.set('codeCellConfig', codeConfig);
            void settings.set('markdownCellConfig', markdownConfig);
            void settings.set('rawCellConfig', rawConfig);
          },
          label: trans.__('Auto Close Brackets for All Notebook Cell Types'),
          isToggled: () =>
            ['codeCellConfig', 'markdownCellConfig', 'rawCellConfig'].some(
              x => (settings.get(x).composite as JSONObject).autoClosingBrackets
            )
        });
      }


() => {
          updateConfig(settings);
        }


args => {
            const codeConfig = settings.get('codeCellConfig')
              .composite as JSONObject;
            const markdownConfig = settings.get('markdownCellConfig')
              .composite as JSONObject;
            const rawConfig = settings.get('rawCellConfig')
              .composite as JSONObject;

            const anyToggled =
              codeConfig.autoClosingBrackets ||
              markdownConfig.autoClosingBrackets ||
              rawConfig.autoClosingBrackets;
            const toggled = !!(args['force'] ?? !anyToggled);
            [
              codeConfig.autoClosingBrackets,
              markdownConfig.autoClosingBrackets,
              rawConfig.autoClosingBrackets
            ] = [toggled, toggled, toggled];

            void settings.set('codeCellConfig', codeConfig);
            void settings.set('markdownCellConfig', markdownConfig);
            void settings.set('rawCellConfig', rawConfig);
          }


() =>
            ['codeCellConfig', 'markdownCellConfig', 'rawCellConfig'].some(
              x => (settings.get(x).composite as JSONObject).autoClosingBrackets
            )


x => (settings.get(x).composite as JSONObject).autoClosingBrackets


(reason: Error) => {
        console.warn(reason.message);
        updateTracker({
          editorConfig: factory.editorConfig,
          notebookConfig: factory.notebookConfig,
          kernelShutdown: factory.shutdownOnClose
        });
      }


panel => ({ path: panel.context.path, factory: FACTORY })


panel => panel.context.path


(sender, widget) => {
    // If the notebook panel does not have an ID, assign it one.
    widget.id = widget.id || `notebook-${++id}`;

    // Set up the title icon
    widget.title.icon = ft?.icon;
    widget.title.iconClass = ft?.iconClass ?? '';
    widget.title.iconLabel = ft?.iconLabel ?? '';

    // Notify the widget tracker if restore data needs to update.
    widget.context.pathChanged.connect(() => {
      void tracker.save(widget);
    });
    // Add the notebook panel to the tracker.
    void tracker.add(widget);
  }


() => {
      void tracker.save(widget);
    }


widget => {
      widget.setConfig(options);
    }


(cwd: string, kernelName?: string) => {
    return commands
      .execute('docmanager:new-untitled', { path: cwd, type: 'notebook' })
      .then(model => {
        if (model != undefined) {
          return commands.execute('docmanager:open', {
            path: model.path,
            factory: FACTORY,
            kernel: { name: kernelName }
          });
        }
      });
  }


model => {
        if (model != undefined) {
          return commands.execute('docmanager:open', {
            path: model.path,
            factory: FACTORY,
            kernel: { name: kernelName }
          });
        }
      }


args => {
      const kernelName = (args['kernelName'] as string) || '';
      if (args['isLauncher'] && args['kernelName'] && services.kernelspecs) {
        return (
          services.kernelspecs.specs?.kernelspecs[kernelName]?.display_name ??
          ''
        );
      }
      if (args['isPalette'] || args['isContextMenu']) {
        return trans.__('New Notebook');
      }
      return trans.__('Notebook');
    }


args => (args['isPalette'] ? undefined : notebookIcon)


args => {
      const cwd =
        (args['cwd'] as string) ||
        (browserFactory ? browserFactory.defaultBrowser.model.path : '');
      const kernelName = (args['kernelName'] as string) || '';
      return createNew(cwd, kernelName);
    }


() => {
      let disposables: DisposableSet | null = null;
      const onSpecsChanged = () => {
        if (disposables) {
          disposables.dispose();
          disposables = null;
        }
        const specs = services.kernelspecs.specs;
        if (!specs) {
          return;
        }
        disposables = new DisposableSet();

        for (const name in specs.kernelspecs) {
          const rank = name === specs.default ? 0 : Infinity;
          const spec = specs.kernelspecs[name]!;
          let kernelIconUrl = spec.resources['logo-64x64'];
          disposables.add(
            launcher.add({
              command: CommandIDs.createNew,
              args: { isLauncher: true, kernelName: name },
              category: trans.__('Notebook'),
              rank,
              kernelIconUrl,
              metadata: {
                kernel: JSONExt.deepCopy(
                  spec.metadata || {}
                ) as ReadonlyJSONValue
              }
            })
          );
        }
      };
      onSpecsChanged();
      services.kernelspecs.specsChanged.connect(onSpecsChanged);
    }


() => {
        if (disposables) {
          disposables.dispose();
          disposables = null;
        }
        const specs = services.kernelspecs.specs;
        if (!specs) {
          return;
        }
        disposables = new DisposableSet();

        for (const name in specs.kernelspecs) {
          const rank = name === specs.default ? 0 : Infinity;
          const spec = specs.kernelspecs[name]!;
          let kernelIconUrl = spec.resources['logo-64x64'];
          disposables.add(
            launcher.add({
              command: CommandIDs.createNew,
              args: { isLauncher: true, kernelName: name },
              category: trans.__('Notebook'),
              rank,
              kernelIconUrl,
              metadata: {
                kernel: JSONExt.deepCopy(
                  spec.metadata || {}
                ) as ReadonlyJSONValue
              }
            })
          );
        }
      }


(): boolean => {
    return Private.isEnabled(shell, tracker);
  }


(): boolean => {
    return Private.isEnabledAndSingleSelected(shell, tracker);
  }


(notebook: Notebook): void => {
    for (const cell of notebook.widgets) {
      if (cell instanceof MarkdownCell && cell.headingCollapsed) {
        NotebookActions.setHeadingCollapse(cell, true, notebook);
      }
      if (cell.model.id === notebook.activeCell?.model?.id) {
        NotebookActions.expandParent(cell, notebook);
      }
    }
  }


(): boolean => {
    return Private.isEnabledAndHeadingSelected(shell, tracker);
  }


(sender: INotebookTracker, panel: NotebookPanel) => {
      if (!panel?.content?.model?.cells) {
        return;
      }
      panel.content.model.cells.changed.connect(
        (
          list: IObservableUndoableList<ICellModel>,
          args: IObservableList.IChangedArgs<ICellModel>
        ) => {
          // Might be overkill to refresh this every time, but
          // it helps to keep the collapse state consistent.
          refreshCellCollapsed(panel.content);
        }
      );
      panel.content.activeCellChanged.connect(
        (notebook: Notebook, cell: Cell) => {
          NotebookActions.expandParent(cell, notebook);
        }
      );
    }


(
          list: IObservableUndoableList<ICellModel>,
          args: IObservableList.IChangedArgs<ICellModel>
        ) => {
          // Might be overkill to refresh this every time, but
          // it helps to keep the collapse state consistent.
          refreshCellCollapsed(panel.content);
        }


(notebook: Notebook, cell: Cell) => {
          NotebookActions.expandParent(cell, notebook);
        }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        const { context, content } = current;

        return NotebookActions.runAndAdvance(content, context.sessionContext);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        const { context, content } = current;

        return NotebookActions.run(content, context.sessionContext);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        const { context, content } = current;

        return NotebookActions.runAndInsert(content, context.sessionContext);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        const { context, content } = current;

        return NotebookActions.runAll(content, context.sessionContext);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        const { context, content } = current;

        return NotebookActions.runAllAbove(content, context.sessionContext);
      }
    }


() => {
      // Can't run above if there are multiple cells selected,
      // or if we are at the top of the notebook.
      return (
        isEnabledAndSingleSelected() &&
        tracker.currentWidget!.content.activeCellIndex !== 0
      );
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        const { context, content } = current;

        return NotebookActions.runAllBelow(content, context.sessionContext);
      }
    }


() => {
      // Can't run below if there are multiple cells selected,
      // or if we are at the bottom of the notebook.
      return (
        isEnabledAndSingleSelected() &&
        tracker.currentWidget!.content.activeCellIndex !==
          tracker.currentWidget!.content.widgets.length - 1
      );
    }


args => {
      const current = getCurrent(tracker, shell, args);
      if (current) {
        const { context, content } = current;
        return NotebookActions.renderAllMarkdown(
          content,
          context.sessionContext
        );
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return sessionDialogs!.restart(current.sessionContext, translator);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (!current) {
        return;
      }

      const fileName = current.title.label;

      return showDialog({
        title: trans.__('Shut down the notebook?'),
        body: trans.__('Are you sure you want to close "%1"?', fileName),
        buttons: [Dialog.cancelButton(), Dialog.warnButton()]
      }).then(result => {
        if (result.button.accept) {
          return current.context.sessionContext.shutdown().then(() => {
            current.dispose();
          });
        }
      });
    }


result => {
        if (result.button.accept) {
          return current.context.sessionContext.shutdown().then(() => {
            current.dispose();
          });
        }
      }


() => {
            current.dispose();
          }


() => trans.__('Trust Notebook')


args => {
      const current = getCurrent(tracker, shell, args);
      if (current) {
        const { context, content } = current;
        return NotebookActions.trust(content).then(() => context.save());
      }
    }


() => context.save()


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        const { content, sessionContext } = current;

        return sessionDialogs!.restart(sessionContext, translator).then(() => {
          NotebookActions.clearAllOutputs(content);
        });
      }
    }


() => {
          NotebookActions.clearAllOutputs(content);
        }


args => {
      const current = getCurrent(tracker, shell, args);
      if (current) {
        const { context, content } = current;
        return sessionDialogs!
          .restart(current.sessionContext, translator)
          .then(restarted => {
            if (restarted) {
              void NotebookActions.runAllAbove(
                content,
                context.sessionContext
              ).then(executed => {
                if (executed || content.activeCellIndex === 0) {
                  void NotebookActions.run(content, context.sessionContext);
                }
              });
            }
          });
      }
    }


restarted => {
            if (restarted) {
              void NotebookActions.runAllAbove(
                content,
                context.sessionContext
              ).then(executed => {
                if (executed || content.activeCellIndex === 0) {
                  void NotebookActions.run(content, context.sessionContext);
                }
              });
            }
          }


executed => {
                if (executed || content.activeCellIndex === 0) {
                  void NotebookActions.run(content, context.sessionContext);
                }
              }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        const { context, content, sessionContext } = current;

        return sessionDialogs!
          .restart(sessionContext, translator)
          .then(restarted => {
            if (restarted) {
              void NotebookActions.runAll(content, context.sessionContext);
            }
            return restarted;
          });
      }
    }


restarted => {
            if (restarted) {
              void NotebookActions.runAll(content, context.sessionContext);
            }
            return restarted;
          }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.clearAllOutputs(current.content);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.clearOutputs(current.content);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (!current) {
        return;
      }

      const kernel = current.context.sessionContext.session?.kernel;

      if (kernel) {
        return kernel.interrupt();
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.changeCellType(current.content, 'code');
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.changeCellType(current.content, 'markdown');
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.changeCellType(current.content, 'raw');
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.cut(current.content);
      }
    }


args => (args.toolbar ? cutIcon : undefined)


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.copy(current.content);
      }
    }


args => (args.toolbar ? copyIcon : '')


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.paste(current.content, 'below');
      }
    }


args => (args.toolbar ? pasteIcon : undefined)


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.paste(current.content, 'above');
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.paste(current.content, 'replace');
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.deleteCells(current.content);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.splitCell(current.content);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.mergeCells(current.content);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.mergeCells(current.content, true);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.mergeCells(current.content, false);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.insertAbove(current.content);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.insertBelow(current.content);
      }
    }


args => (args.toolbar ? addIcon : undefined)


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.selectAbove(current.content);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.selectBelow(current.content);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.extendSelectionAbove(current.content);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.extendSelectionAbove(current.content, true);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.extendSelectionBelow(current.content);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.extendSelectionBelow(current.content, true);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.selectAll(current.content);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.deselectAll(current.content);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.moveUp(current.content);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.moveDown(current.content);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.toggleAllLineNumbers(current.content);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        current.content.mode = 'command';
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        current.content.mode = 'edit';
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.undo(current.content);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.redo(current.content);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return sessionDialogs!.selectKernel(
          current.context.sessionContext,
          translator
        );
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (!current) {
        return;
      }

      const kernel = current.context.sessionContext.session?.kernel;

      if (kernel) {
        return kernel.reconnect();
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.setMarkdownHeader(current.content, 1);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.setMarkdownHeader(current.content, 2);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.setMarkdownHeader(current.content, 3);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.setMarkdownHeader(current.content, 4);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.setMarkdownHeader(current.content, 5);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.setMarkdownHeader(current.content, 6);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.hideCode(current.content);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.showCode(current.content);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.hideAllCode(current.content);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.showAllCode(current.content);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.hideOutput(current.content);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.showOutput(current.content);
      }
    }


args => {
      const current = getCurrent(tracker, shell, args);

      if (current) {
        return NotebookActions.hideAllOutputs(current.content);
      }
    }