|  | @@ -15,42 +15,41 @@ namespace editor {
 | 
	
		
			
				|  |  |      jsonElement: HTMLInputElement;
 | 
	
		
			
				|  |  |      track: audio.Track | null = null;
 | 
	
		
			
				|  |  |      markers: Marker[] = [];
 | 
	
		
			
				|  |  | -    rafId: number;
 | 
	
		
			
				|  |  |      waveForm: WaveForm;
 | 
	
		
			
				|  |  | -    currentMarker: Marker;
 | 
	
		
			
				|  |  | +    currentMarker: Marker | null = null;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      constructor() {
 | 
	
		
			
				|  |  |        this.audioManager = new audio.AudioManager();
 | 
	
		
			
				|  |  | -      this.audioElement = document.querySelector('#audio');
 | 
	
		
			
				|  |  | +      this.audioElement = util.getElement(document, '#audio');
 | 
	
		
			
				|  |  |        this.audioElement.addEventListener('change', event => {
 | 
	
		
			
				|  |  |          this.loadAudio();
 | 
	
		
			
				|  |  |        });
 | 
	
		
			
				|  |  | -      this.barElement = document.querySelector('.bar-overlay');
 | 
	
		
			
				|  |  | -      this.markerListElement = document.querySelector('.markers');
 | 
	
		
			
				|  |  | -      this.intervalListElement = document.querySelector('#intervals');
 | 
	
		
			
				|  |  | -      this.kanaElement = document.querySelector('#kana');
 | 
	
		
			
				|  |  | -      this.kanjiElement = document.querySelector('#kanji');
 | 
	
		
			
				|  |  | -      this.displayElement = document.querySelector('#display');
 | 
	
		
			
				|  |  | -      this.jsonElement = document.querySelector('#json');
 | 
	
		
			
				|  |  | +      this.barElement = util.getElement(document, '.bar-overlay');
 | 
	
		
			
				|  |  | +      this.markerListElement = util.getElement(document, '.markers');
 | 
	
		
			
				|  |  | +      this.intervalListElement = util.getElement(document, '#intervals');
 | 
	
		
			
				|  |  | +      this.kanaElement = util.getElement(document, '#kana');
 | 
	
		
			
				|  |  | +      this.kanjiElement = util.getElement(document, '#kanji');
 | 
	
		
			
				|  |  | +      this.displayElement = util.getElement(document, '#display');
 | 
	
		
			
				|  |  | +      this.jsonElement = util.getElement(document, '#json');
 | 
	
		
			
				|  |  |        this.waveForm = new WaveForm(
 | 
	
		
			
				|  |  | -        document.querySelector('#waveform'),
 | 
	
		
			
				|  |  | -        document.querySelector('#waveform-overlay'),
 | 
	
		
			
				|  |  | +        util.getElement(document, '#waveform'),
 | 
	
		
			
				|  |  | +        util.getElement(document, '#waveform-overlay'),
 | 
	
		
			
				|  |  |          (time: number) => this.play(time)
 | 
	
		
			
				|  |  |        );
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |        this.markerListElement.addEventListener('click', (event: MouseEvent) => this.markersClick(event));
 | 
	
		
			
				|  |  | -      document.querySelector('#play').addEventListener('click', () => this.play());
 | 
	
		
			
				|  |  | -      document.querySelector('#pause').addEventListener('click', () => this.pause());
 | 
	
		
			
				|  |  | -      document.querySelector('#insert-marker').addEventListener('click', () => this.insertMarker());
 | 
	
		
			
				|  |  | -      document.querySelector('.bar').addEventListener('click', (event: MouseEvent) => this.scrubberClick(event));
 | 
	
		
			
				|  |  | -      document.querySelector('#import').addEventListener('click', () => this.import());
 | 
	
		
			
				|  |  | -      document.querySelector('#export').addEventListener('click', () => this.export());
 | 
	
		
			
				|  |  | +      document.querySelector('#play')!.addEventListener('click', () => this.play());
 | 
	
		
			
				|  |  | +      document.querySelector('#pause')!.addEventListener('click', () => this.pause());
 | 
	
		
			
				|  |  | +      document.querySelector('#insert-marker')!.addEventListener('click', () => this.insertMarker());
 | 
	
		
			
				|  |  | +      document.querySelector<HTMLElement>('.bar')!.addEventListener('click', (event: MouseEvent) => this.scrubberClick(event));
 | 
	
		
			
				|  |  | +      document.querySelector('#import')!.addEventListener('click', () => this.import());
 | 
	
		
			
				|  |  | +      document.querySelector('#export')!.addEventListener('click', () => this.export());
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |        this.update();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      loadAudio(): void {
 | 
	
		
			
				|  |  | -      let file = this.audioElement.files[0];
 | 
	
		
			
				|  |  | +      let file = this.audioElement.files![0];
 | 
	
		
			
				|  |  |        if (file != null) {
 | 
	
		
			
				|  |  |          if (this.track != null) {
 | 
	
		
			
				|  |  |            this.track.stop();
 | 
	
	
		
			
				|  | @@ -71,7 +70,7 @@ namespace editor {
 | 
	
		
			
				|  |  |          if (this.currentMarker) {
 | 
	
		
			
				|  |  |            this.currentMarker.liElement.className = '';
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        let index = this.markers.findIndex(m => m.time > this.track.getTime());
 | 
	
		
			
				|  |  | +        let index = this.markers.findIndex(m => m.time > this.track!.getTime());
 | 
	
		
			
				|  |  |          if (index < 0) index = 0;
 | 
	
		
			
				|  |  |          this.currentMarker = this.markers[index - 1];
 | 
	
		
			
				|  |  |          if (this.currentMarker) {
 | 
	
	
		
			
				|  | @@ -87,27 +86,27 @@ namespace editor {
 | 
	
		
			
				|  |  |        let pos = event.clientX - 10;
 | 
	
		
			
				|  |  |        console.log(pos);
 | 
	
		
			
				|  |  |        let percentage = pos / this.markerListElement.clientWidth;
 | 
	
		
			
				|  |  | -      let targetTime = percentage * this.track.getDuration();
 | 
	
		
			
				|  |  | +      let targetTime = percentage * this.track!.getDuration();
 | 
	
		
			
				|  |  |        this.play(targetTime);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      markersClick(event: MouseEvent): void {
 | 
	
		
			
				|  |  |        let pos = event.clientX - 10;
 | 
	
		
			
				|  |  |        let percentage = pos / this.markerListElement.clientWidth;
 | 
	
		
			
				|  |  | -      let targetTime = percentage * this.track.getDuration();
 | 
	
		
			
				|  |  | +      let targetTime = percentage * this.track!.getDuration();
 | 
	
		
			
				|  |  |        this.insertMarker(targetTime);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    insertMarker(time: number = undefined): void {
 | 
	
		
			
				|  |  | +    insertMarker(time?: number): void {
 | 
	
		
			
				|  |  |        let marker = new Marker(
 | 
	
		
			
				|  |  | -        this.track.getDuration(),
 | 
	
		
			
				|  |  | +        this.track!.getDuration(),
 | 
	
		
			
				|  |  |          (marker: Marker) => this.removeMarker(marker),
 | 
	
		
			
				|  |  |          (marker: Marker) => this.playMarker(marker)
 | 
	
		
			
				|  |  |        );
 | 
	
		
			
				|  |  |        if (time !== undefined) {
 | 
	
		
			
				|  |  |          marker.time = time;
 | 
	
		
			
				|  |  |        } else {
 | 
	
		
			
				|  |  | -        marker.time = this.track.getTime();
 | 
	
		
			
				|  |  | +        marker.time = this.track!.getTime();
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |        let insertIndex = this.markers.findIndex(m => m.time > marker.time);
 | 
	
		
			
				|  |  |        if (insertIndex >= 0) {
 | 
	
	
		
			
				|  | @@ -123,21 +122,21 @@ namespace editor {
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    play(start: number = undefined, duration: number = undefined): void {
 | 
	
		
			
				|  |  | -      this.track.pause();
 | 
	
		
			
				|  |  | +    play(start?: number, duration?: number): void {
 | 
	
		
			
				|  |  | +      this.track!.pause();
 | 
	
		
			
				|  |  |        if (start != undefined) {
 | 
	
		
			
				|  |  | -        this.track.resumeTime = start;
 | 
	
		
			
				|  |  | +        this.track!.resumeTime = start;
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  | -      this.track.start(duration);
 | 
	
		
			
				|  |  | +      this.track!.start(duration);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      pause(): void {
 | 
	
		
			
				|  |  | -      this.track.pause();
 | 
	
		
			
				|  |  | +      this.track!.pause();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      playMarker(marker: Marker): void {
 | 
	
		
			
				|  |  |        let start = marker.time;
 | 
	
		
			
				|  |  | -      let end = this.track.getDuration();
 | 
	
		
			
				|  |  | +      let end = this.track!.getDuration();
 | 
	
		
			
				|  |  |        let index = this.markers.findIndex(m => m == marker);
 | 
	
		
			
				|  |  |        if (index < this.markers.length - 1) {
 | 
	
		
			
				|  |  |          end = this.markers[index + 1].time;
 | 
	
	
		
			
				|  | @@ -234,14 +233,14 @@ namespace editor {
 | 
	
		
			
				|  |  |        this.markerElement.className = 'marker';
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |        let fragment = util.loadTemplate('interval');
 | 
	
		
			
				|  |  | -      this.liElement = fragment.querySelector('*');
 | 
	
		
			
				|  |  | -      this.inputElement = fragment.querySelector('.interval');
 | 
	
		
			
				|  |  | +      this.liElement = util.getElement(fragment, '*');
 | 
	
		
			
				|  |  | +      this.inputElement = util.getElement(fragment, '.interval');
 | 
	
		
			
				|  |  |        this.inputElement.addEventListener('change', () => {
 | 
	
		
			
				|  |  |          this.time = parseFloat(this.inputElement.value);
 | 
	
		
			
				|  |  |        });
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      fragment.querySelector('.play-section').addEventListener('click', () => play(this));
 | 
	
		
			
				|  |  | -      fragment.querySelector('.remove-section').addEventListener('click', () => remove(this));
 | 
	
		
			
				|  |  | +      fragment.querySelector('.play-section')!.addEventListener('click', () => play(this));
 | 
	
		
			
				|  |  | +      fragment.querySelector('.remove-section')!.addEventListener('click', () => remove(this));
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      get time(): number {
 | 
	
	
		
			
				|  | @@ -258,10 +257,10 @@ namespace editor {
 | 
	
		
			
				|  |  |    class WaveForm {
 | 
	
		
			
				|  |  |      ctx: CanvasRenderingContext2D;
 | 
	
		
			
				|  |  |      overlayCtx: CanvasRenderingContext2D;
 | 
	
		
			
				|  |  | -    track: audio.Track | null;
 | 
	
		
			
				|  |  | -    data: Float32Array | null;
 | 
	
		
			
				|  |  | -    stride: number;
 | 
	
		
			
				|  |  | -    currentSection: number;
 | 
	
		
			
				|  |  | +    track: audio.Track | null = null;
 | 
	
		
			
				|  |  | +    data: Float32Array | null = null;
 | 
	
		
			
				|  |  | +    stride: number = 0;
 | 
	
		
			
				|  |  | +    currentSection: number = -1;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      constructor(
 | 
	
		
			
				|  |  |        readonly canvas: HTMLCanvasElement,
 | 
	
	
		
			
				|  | @@ -272,8 +271,8 @@ namespace editor {
 | 
	
		
			
				|  |  |        canvas.width = canvas.clientWidth;
 | 
	
		
			
				|  |  |        overlay.height = overlay.clientHeight;
 | 
	
		
			
				|  |  |        overlay.width = overlay.clientWidth;
 | 
	
		
			
				|  |  | -      this.ctx = canvas.getContext('2d');
 | 
	
		
			
				|  |  | -      this.overlayCtx = overlay.getContext('2d');
 | 
	
		
			
				|  |  | +      this.ctx = canvas.getContext('2d')!;
 | 
	
		
			
				|  |  | +      this.overlayCtx = overlay.getContext('2d')!;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |        this.overlayCtx.fillStyle = 'rgba(255, 0, 0, 0.5)';
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -296,11 +295,11 @@ namespace editor {
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      update(markers: Marker[]): void {
 | 
	
		
			
				|  |  | -      let section = Math.floor(this.track.getTime() / 5);
 | 
	
		
			
				|  |  | +      let section = Math.floor(this.track!.getTime() / 5);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |        let height = this.canvas.height;
 | 
	
		
			
				|  |  |        if (this.currentSection != section) {
 | 
	
		
			
				|  |  | -        this.data = this.track.buffer.getChannelData(0);
 | 
	
		
			
				|  |  | +        this.data = this.track!.buffer.getChannelData(0);
 | 
	
		
			
				|  |  |          this.ctx.clearRect(0, 0, this.canvas.width, height);
 | 
	
		
			
				|  |  |          this.ctx.beginPath();
 | 
	
		
			
				|  |  |          this.ctx.moveTo(0, height / 2);
 | 
	
	
		
			
				|  | @@ -314,7 +313,7 @@ namespace editor {
 | 
	
		
			
				|  |  |          this.currentSection = section;
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      let marker = this.timeToX(this.track.getTime());
 | 
	
		
			
				|  |  | +      let marker = this.timeToX(this.track!.getTime());
 | 
	
		
			
				|  |  |        this.overlayCtx.clearRect(0, 0, this.canvas.width, height);
 | 
	
		
			
				|  |  |        this.overlayCtx.fillRect(0, 0, marker, height);
 | 
	
		
			
				|  |  |        markers.forEach(m => {
 |