diff --git a/bits/18_cfb.js b/bits/18_cfb.js
index 58dbe25..8ac3c6e 100644
--- a/bits/18_cfb.js
+++ b/bits/18_cfb.js
@@ -211,8 +211,15 @@ function parse_extra_field(blob/*:CFBlob*/)/*:any*/ {
 					if(flags & 4) p.ctime = blob.read_shift(4);
 				}
 				if(p.mtime) p.mt = new Date(p.mtime*1000);
-			}
-			break;
+			} break;
+			/* ZIP64 Extended Information Field */
+			case 0x0001: {
+				var sz1 = blob.read_shift(4), sz2 = blob.read_shift(4);
+				p.usz = (sz2 * Math.pow(2,32) + sz1);
+				sz1 = blob.read_shift(4); sz2 = blob.read_shift(4);
+				p.csz = (sz2 * Math.pow(2,32) + sz1);
+				// NOTE: volume fields are skipped
+			} break;
 		}
 		blob.l = tgt;
 		o[type] = p;
@@ -1401,6 +1408,11 @@ function parse_zip(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/
 
 		var L = blob.l;
 		blob.l = offset + 4;
+		/* ZIP64 lengths */
+		if(EF && EF[0x0001]) {
+			if((EF[0x0001]||{}).usz) usz = EF[0x0001].usz;
+			if((EF[0x0001]||{}).csz) csz = EF[0x0001].csz;
+		}
 		parse_local_file(blob, csz, usz, o, EF);
 		blob.l = L;
 	}
@@ -1430,7 +1442,13 @@ function parse_local_file(blob/*:CFBlob*/, csz/*:number*/, usz/*:number*/, o/*:C
 	if(efsz) {
 		var ef = parse_extra_field(/*::(*/blob.slice(blob.l, blob.l + efsz)/*:: :any)*/);
 		if((ef[0x5455]||{}).mt) date = ef[0x5455].mt;
-		if(((EF||{})[0x5455]||{}).mt) date = EF[0x5455].mt;
+		if((ef[0x0001]||{}).usz) _usz = ef[0x0001].usz;
+		if((ef[0x0001]||{}).csz) _csz = ef[0x0001].csz;
+		if(EF) {
+			if((EF[0x5455]||{}).mt) date = EF[0x5455].mt;
+			if((EF[0x0001]||{}).usz) _usz = ef[0x0001].usz;
+			if((EF[0x0001]||{}).csz) _csz = ef[0x0001].csz;
+		}
 	}
 	blob.l += efsz;
 
diff --git a/demos/README.md b/demos/README.md
index 98db244..e7df176 100644
--- a/demos/README.md
+++ b/demos/README.md
@@ -26,23 +26,23 @@ can be installed with Bash on Windows or with `cygwin`.
 - [`IndexedDB`](https://docs.sheetjs.com/docs/demos/database#indexeddb)
 
 **Frameworks**
+- [`Angular 2+ and Ionic`](https://docs.sheetjs.com/docs/demos/angular)
+- [`React`](https://docs.sheetjs.com/docs/demos/react)
+- [`VueJS`](https://docs.sheetjs.com/docs/demos/vue)
 - [`Angular.JS`](https://docs.sheetjs.com/docs/demos/legacy#angularjs)
-- [`Angular 2+ and Ionic`](angular2/)
 - [`Knockout`](https://docs.sheetjs.com/docs/demos/legacy#knockoutjs)
-- [`React and NextJS`](react/)
-- [`VueJS`](vue/)
 
 **Front-End UI Components**
 - [`canvas-datagrid`](https://docs.sheetjs.com/docs/demos/grid#canvas-datagrid)
-- [`x-spreadsheet`](xspreadsheet/)
-- [`react-data-grid`](react/modify/)
-- [`vue3-table-light`](vue/modify/)
+- [`x-spreadsheet`](https://docs.sheetjs.com/docs/demos/grid#x-spreadsheet)
+- [`react-data-grid`](https://docs.sheetjs.com/docs/demos/grid#react-data-grid)
+- [`vue3-table-lite`](https://docs.sheetjs.com/docs/demos/grid#vue3-table-lite)
 - [`angular-ui-grid`](https://docs.sheetjs.com/docs/demos/grid#angular-ui-grid)
 
 **Platforms and Integrations**
 - [`Command-Line Tools`](https://docs.sheetjs.com/docs/demos/cli)
 - [`iOS and Android Mobile Applications`](https://docs.sheetjs.com/docs/demos/mobile)
-- [`NodeJS Server-Side Processing`](server/)
+- [`NodeJS Server-Side Processing`](https://docs.sheetjs.com/docs/demos/server#nodejs)
 - [`Content Management and Static Sites`](https://docs.sheetjs.com/docs/demos/content)
 - [`Electron`](https://docs.sheetjs.com/docs/demos/desktop#electron)
 - [`NW.js`](https://docs.sheetjs.com/docs/demos/desktop#nwjs)
@@ -54,8 +54,9 @@ can be installed with Bash on Windows or with `cygwin`.
 - [`SalesForce Lightning Web Components`](https://docs.sheetjs.com/docs/demos/salesforce)
 - [`Excel JavaScript API`](https://docs.sheetjs.com/docs/demos/excel)
 - [`Headless Automation`](https://docs.sheetjs.com/docs/demos/headless)
-- [`Swift JSC and Other JavaScript Engines`](https://docs.sheetjs.com/docs/demos/engines)
-- [`"serverless" functions`](function/)
+- [`Other JavaScript Engines`](https://docs.sheetjs.com/docs/demos/engines)
+- [`Azure Functions and Storage`](https://docs.sheetjs.com/docs/demos/azure)
+- [`Amazon Web Services`](https://docs.sheetjs.com/docs/demos/aws)
 - [`Databases and Structured Data Stores`](https://docs.sheetjs.com/docs/demos/database)
 - [`NoSQL and Unstructured Data Stores`](https://docs.sheetjs.com/docs/demos/nosql)
 - [`Legacy Internet Explorer`](https://docs.sheetjs.com/docs/demos/legacy#internet-explorer)
diff --git a/demos/angular2/.angular-cli.json b/demos/angular2/.angular-cli.json
deleted file mode 100644
index 35d76d7..0000000
--- a/demos/angular2/.angular-cli.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
-  "project": {
-    "name": "angular2"
-  },
-  "apps": [
-    {
-      "root": "src",
-      "outDir": "dist",
-      "index": "index.html",
-      "main": "main.ts",
-      "polyfills": "polyfills.ts",
-      "test": "test.ts",
-      "tsconfig": "tsconfig.app.json",
-      "prefix": "app",
-      "scripts": []
-    }
-  ],
-  "defaults": {
-    "styleExt": "css",
-    "component": {}
-  }
-}
diff --git a/demos/angular2/.eslintrc b/demos/angular2/.eslintrc
deleted file mode 100644
index 31ada8c..0000000
--- a/demos/angular2/.eslintrc
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-	"parser": "@typescript-eslint/parser",
-	"extends": [
-		"eslint:recommended"
-	]
-}
diff --git a/demos/angular2/.gitattributes b/demos/angular2/.gitattributes
deleted file mode 100644
index 80fa1f4..0000000
--- a/demos/angular2/.gitattributes
+++ /dev/null
@@ -1 +0,0 @@
-*.*-ng*           linguist-generated=true binary
diff --git a/demos/angular2/.gitignore b/demos/angular2/.gitignore
deleted file mode 100644
index f1fd2db..0000000
--- a/demos/angular2/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-dist
-hooks
-SheetJSIonic
-SheetJSNS
-angular.json
-tsconfig.app.json
-src/polyfills.ts
-.angular
diff --git a/demos/angular2/Makefile b/demos/angular2/Makefile
deleted file mode 100644
index b37e495..0000000
--- a/demos/angular2/Makefile
+++ /dev/null
@@ -1,34 +0,0 @@
-.PHONY: ng2 ng4 ng5 ng6 ng7 ng8 ng9 ng10 ng11 ng12 ng13
-ng2 ng4 ng5 ng6 ng7 ng8 ng9 ng10 ng11 ng12 ng13:
-	rm -f angular.json tsconfig.app.json src/polyfills.ts
-	cp versions/package.json-$@ package.json
-	if [ -e versions/angular.json-$@ ]; then cp versions/angular.json-$@ angular.json; fi
-	if [ -e versions/tsconfig.app.json-$@ ]; then cp versions/tsconfig.app.json-$@ tsconfig.app.json; fi
-	if [ -e versions/polyfills.ts-$@ ]; then cp versions/polyfills.ts-$@ src/polyfills.ts; fi
-	rm -rf node_modules
-	if [ ! -e node_modules ]; then mkdir node_modules; fi
-	npm install
-	if [ ! -e node_modules/xlsx ]; then cd node_modules; ln -s ../../../ xlsx; cd -; fi
-	npm run build
-
-.PHONY: refresh
-refresh: ## refresh the `xlsx` symlink to force angular to rebuild
-	rm -rf .angular/
-	rm -f node_modules/xlsx
-	cd node_modules; ln -s ../../../ xlsx; cd -
-	touch node_modules/xlsx
-
-.PHONY: all
-all:
-	for i in 2 4 5 6 7 8 9 10 11 12 13; do make ng$$i; done
-
-.PHONY: ionic
-ionic:
-	bash ./ionic.sh
-
-.PHONY: ios android browser
-ios browser: ionic
-	cd SheetJSIonic; ionic cordova emulate $@ </dev/null; cd -
-android: ionic
-	cd SheetJSIonic; ionic cordova prepare $@ </dev/null; ionic cordova emulate $@ </dev/null; cd -
-
diff --git a/demos/angular2/README.md b/demos/angular2/README.md
index 746d448..68bd4b8 100644
--- a/demos/angular2/README.md
+++ b/demos/angular2/README.md
@@ -1,148 +1,11 @@
 # Angular 2+
 
-The ESM build can be imported directly from TS code with:
+[The new demo](https://docs.sheetjs.com/docs/demos/angular) has an updated
+exposition for legacy and modern deployments alike.
 
-```typescript
-import { read, utils, writeFileXLSX } from 'xlsx';
-```
+The ecosystem demos were grouped by type in the new demo site:
 
-This demo uses an array of arrays (type `Array<Array<any>>`) as the core state.
-The component template includes a file input element, a table that updates with
-the data, and a button to export the data.
-
-Other scripts in this demo show:
-- `ionic` deployment for iOS, android, and browser
-- `nativescript` deployment for iOS and android
-
-## Array of Arrays
-
-`Array<Array<any>>` neatly maps to a table with `ngFor`:
-
-```html
-<table class="sjs-table">
-  <tr *ngFor="let row of data">
-    <td *ngFor="let val of row">
-      {{val}}
-    </td>
-  </tr>
-</table>
-```
-
-The `aoa_to_sheet` utility function returns a worksheet.  Exporting is simple:
-
-```typescript
-/* generate worksheet */
-const ws: XLSX.WorkSheet = XLSX.utils.aoa_to_sheet(this.data);
-
-/* generate workbook and add the worksheet */
-const wb: XLSX.WorkBook = XLSX.utils.book_new();
-XLSX.utils.book_append_sheet(wb, ws, 'Sheet1');
-
-/* save to file */
-XLSX.writeFile(wb, 'SheetJS.xlsx');
-```
-
-`sheet_to_json` with the option `header:1` makes importing simple:
-
-```typescript
-/* <input type="file" (change)="onFileChange($event)" multiple="false" /> */
-/* ... (within the component class definition) ... */
-  onFileChange(evt: any) {
-    /* wire up file reader */
-    const target: DataTransfer = <DataTransfer>(evt.target);
-    if (target.files.length !== 1) throw new Error('Cannot use multiple files');
-    const reader: FileReader = new FileReader();
-    reader.onload = (e: any) => {
-      /* read workbook */
-      const ab: ArrayBuffer = e.target.result;
-      const wb: XLSX.WorkBook = XLSX.read(ab);
-
-      /* grab first sheet */
-      const wsname: string = wb.SheetNames[0];
-      const ws: XLSX.WorkSheet = wb.Sheets[wsname];
-
-      /* save data */
-      this.data = <AOA>(XLSX.utils.sheet_to_json(ws, {header: 1}));
-    };
-    reader.readAsArrayBuffer(target.files[0]);
-  }
-```
-
-## Switching between Angular versions
-
-Modules that work with Angular 2 largely work as-is with Angular 4+.  Switching
-between versions is mostly a matter of installing the correct version of the
-core and associated modules.  This demo includes `package.json-angular#` files
-for every major version of Angular up to 12.
-
-To test a particular Angular version, overwrite `package.json`:
-
-```bash
-# switch to Angular 2
-$ cp package.json-ng2 package.json
-$ npm install
-$ ng serve
-```
-
-Note: when running the demos, Angular 2 requires Node <= 14.  This is due to a
-tooling issue with `ng` and does not affect browser use.
-
-## XLSX Symbolic Link
-
-In this tree, `node_modules/xlsx` is a link pointing back to the root.  This
-enables testing the development version of the library.  In order to use this
-demo in other applications, add the `xlsx` dependency:
-
-```bash
-$ npm install --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz
-```
-
-## SystemJS Configuration
-
-The default angular-cli configuration requires no additional configuration.
-
-Some deployments use the SystemJS loader, which does require configuration.
-[SystemJS](https://docs.sheetjs.com/docs/demos/bundler#systemjs)
-demo in the SheetJS CE docs describe the required settings.
-
-## Ionic
-
-<img src="screen.png" width="400px"/>
-
-Reproducing the full project is a little bit tricky.  The included `ionic.sh`
-script performs the necessary installation steps.
-
-`Array<Array<any>>` neatly maps to a table with `ngFor`:
-
-```html
-<ion-grid>
-  <ion-row *ngFor="let row of data">
-    <ion-col *ngFor="let val of row">
-      {{val}}
-    </ion-col>
-  </ion-row>
-</ion-grid>
-```
-
-
-`@ionic-native/file` reads and writes files on devices. `readAsArrayBuffer`
-returns `ArrayBuffer` objects suitable for `array` type, and `array` type can
-be converted to blobs that can be exported with `writeFile`:
-
-```typescript
-/* read a workbook */
-const ab: ArrayBuffer = await this.file.readAsArrayBuffer(url, filename);
-const wb: XLSX.WorkBook = XLSX.read(bstr, {type: 'array'});
-
-/* write a workbook */
-const wbout: ArrayBuffer = XLSX.write(wb, { bookType: 'xlsx', type: 'array' });
-let blob = new Blob([wbout], {type: 'application/octet-stream'});
-this.file.writeFile(url, filename, blob, {replace: true});
-```
-
-## NativeScript
-
-[The new demo](https://docs.sheetjs.com/docs/demos/mobile#nativescript)
-is updated for NativeScript 8 and uses more idiomatic data patterns.
+- [NativeScript](https://docs.sheetjs.com/docs/demos/mobile#nativescript) is now part of "iOS and Android Apps"
+- [Ionic](https://docs.sheetjs.com/docs/demos/mobile#ionic) is now part of "iOS and Android Apps"
 
 [![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)
diff --git a/demos/angular2/ionic-app.module.ts b/demos/angular2/ionic-app.module.ts
deleted file mode 100644
index 5d92df0..0000000
--- a/demos/angular2/ionic-app.module.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
-/* vim: set ts=2: */
-/* NOTE: this file exists because `File` must be added as a provider */
-import { NgModule } from '@angular/core';
-import { BrowserModule } from '@angular/platform-browser';
-import { RouteReuseStrategy } from '@angular/router';
-
-import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
-
-import { AppComponent } from './app.component';
-import { AppRoutingModule } from './app-routing.module';
-
-import { File } from '@ionic-native/file/ngx';
-
-@NgModule({
-  declarations: [AppComponent],
-  entryComponents: [],
-  imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule],
-  providers: [File, { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }],
-  bootstrap: [AppComponent],
-})
-export class AppModule {}
diff --git a/demos/angular2/ionic.sh b/demos/angular2/ionic.sh
deleted file mode 100755
index c12a32e..0000000
--- a/demos/angular2/ionic.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/bash
-if [ ! -e SheetJSIonic ]; then
-	ionic start SheetJSIonic blank --type angular --cordova --quiet --no-git --no-link --confirm </dev/null
-	cd SheetJSIonic
-	ionic cordova platform add browser --confirm </dev/null
-	ionic cordova platform add ios --confirm </dev/null
-	ionic cordova platform add android --confirm </dev/null
-	ionic cordova plugin add cordova-plugin-file </dev/null
-	npm install --save @ionic-native/core
-	npm install --save @ionic-native/file
-	npm install --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz
-	cp ../ionic-app.module.ts src/app/app.module.ts
-	cd -
-fi
-
-cp ionic.ts SheetJSIonic/src/app/home/home.page.ts
diff --git a/demos/angular2/ionic.ts b/demos/angular2/ionic.ts
deleted file mode 100644
index fedc321..0000000
--- a/demos/angular2/ionic.ts
+++ /dev/null
@@ -1,126 +0,0 @@
-/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
-/* vim: set ts=2: */
-import { Component } from '@angular/core';
-import { File } from '@ionic-native/file/ngx';
-import * as XLSX from 'xlsx';
-
-
-type AOA = any[][];
-
-@Component({
-  selector: 'app-home',
-  //templateUrl: 'home.page.html',
-  styleUrls: ['home.page.scss'],
-  template: `
-<ion-header>
-  <ion-toolbar>
-    <ion-title>SheetJS Ionic Demo</ion-title>
-  </ion-toolbar>
-</ion-header>
-
-<ion-content [fullscreen]="true">
-  <ion-header collapse="condense">
-    <ion-toolbar>
-      <ion-title>SheetJS Demo</ion-title>
-    </ion-toolbar>
-  </ion-header>
-
-  <ion-grid>
-    <ion-row *ngFor="let row of data">
-      <ion-col *ngFor="let val of row">
-        {{val}}
-      </ion-col>
-    </ion-row>
-  </ion-grid>
-</ion-content>
-
-<ion-footer padding>
-  <input type="file" (change)="onFileChange($event)" multiple="false" />
-  <button ion-button color="secondary" (click)="import()">Import Data</button>
-  <button ion-button color="secondary" (click)="export()">Export Data</button>
-</ion-footer>
-`
-})
-
-export class HomePage {
-  data: any[][] = [[1,2,3],[4,5,6]];
-  constructor(public file: File) {}
-
-  read(ab: ArrayBuffer) {
-    /* read workbook */
-    const wb: XLSX.WorkBook = XLSX.read(new Uint8Array(ab), {type: 'array'});
-
-    /* grab first sheet */
-    const wsname: string = wb.SheetNames[0];
-    const ws: XLSX.WorkSheet = wb.Sheets[wsname];
-
-    /* save data */
-    this.data = (XLSX.utils.sheet_to_json(ws, {header: 1}) as AOA);
-  };
-
-  write(): XLSX.WorkBook {
-    /* generate worksheet */
-    const ws: XLSX.WorkSheet = XLSX.utils.aoa_to_sheet(this.data);
-
-    /* generate workbook and add the worksheet */
-    const wb: XLSX.WorkBook = XLSX.utils.book_new();
-    XLSX.utils.book_append_sheet(wb, ws, 'SheetJS');
-
-    return wb;
-  };
-
-  /* File Input element for browser */
-  onFileChange(evt: any) {
-    /* wire up file reader */
-    const target: DataTransfer = (evt.target as DataTransfer);
-    if (target.files.length !== 1) { throw new Error('Cannot use multiple files'); }
-    const reader: FileReader = new FileReader();
-    reader.onload = (e: any) => {
-      const ab: ArrayBuffer = e.target.result;
-      this.read(ab);
-    };
-    reader.readAsArrayBuffer(target.files[0]);
-  };
-
-  /* Import button for mobile */
-  async import() {
-    try {
-      const target: string = this.file.documentsDirectory || this.file.externalDataDirectory || this.file.dataDirectory || '';
-      const dentry = await this.file.resolveDirectoryUrl(target);
-      const url: string = dentry.nativeURL || '';
-      alert(`Attempting to read SheetJSIonic.xlsx from ${url}`);
-      const ab: ArrayBuffer = await this.file.readAsArrayBuffer(url, 'SheetJSIonic.xlsx');
-      this.read(ab);
-    } catch(e) {
-      const m: string = e.message;
-      alert(m.match(/It was determined/) ? 'Use File Input control' : `Error: ${m}`);
-    }
-  };
-
-  /* Export button */
-  async export() {
-    const wb: XLSX.WorkBook = this.write();
-    const filename = 'SheetJSIonic.xlsx';
-    try {
-      /* generate Blob */
-      const wbout: ArrayBuffer = XLSX.write(wb, { bookType: 'xlsx', type: 'array' });
-
-      /* find appropriate path for mobile */
-      const target: string = this.file.documentsDirectory || this.file.externalDataDirectory || this.file.dataDirectory || '';
-      const dentry = await this.file.resolveDirectoryUrl(target);
-      const url: string = dentry.nativeURL || '';
-
-      /* attempt to save blob to file */
-      await this.file.writeFile(url, filename, wbout, {replace: true});
-      alert(`Wrote to SheetJSIonic.xlsx in ${url}`);
-    } catch(e) {
-      if(e.message.match(/It was determined/)) {
-        /* in the browser, use writeFile */
-        XLSX.writeFile(wb, filename);
-      } else {
-        alert(`Error: ${e.message}`);
-      }
-    }
-  };
-}
-
diff --git a/demos/angular2/package.json b/demos/angular2/package.json
deleted file mode 100644
index a214cef..0000000
--- a/demos/angular2/package.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
-  "name": "angular13",
-  "version": "0.0.0",
-  "license": "MIT",
-  "scripts": {
-    "ng": "ng",
-    "start": "ng serve",
-    "build": "ng build"
-  },
-  "private": true,
-  "dependencies": {
-    "@angular/animations": "~13.2.0",
-    "@angular/common": "~13.2.0",
-    "@angular/compiler": "~13.2.0",
-
-    "@angular/core": "~13.2.0",
-    "@angular/forms": "~13.2.0",
-
-    "@angular/platform-browser": "~13.2.0",
-    "@angular/platform-browser-dynamic": "~13.2.0",
-
-    "@angular/router": "~13.2.0",
-
-
-    "rxjs": "~7.5.0",
-    "tslib": "^2.3.0",
-    "zone.js": "~0.11.4"
-  },
-  "devDependencies": {
-    "@angular-devkit/build-angular": "~13.2.1",
-    "@angular/cli": "~13.2.1",
-    "@angular/compiler-cli": "~13.2.0",
-
-    "@types/node": "^12.11.1",
-
-
-    "typescript": "~4.5.2"
-  }
-}
diff --git a/demos/angular2/screen.png b/demos/angular2/screen.png
deleted file mode 100644
index 1896373..0000000
Binary files a/demos/angular2/screen.png and /dev/null differ
diff --git a/demos/angular2/src/app/app.module.ts b/demos/angular2/src/app/app.module.ts
deleted file mode 100644
index d7bb39a..0000000
--- a/demos/angular2/src/app/app.module.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import { BrowserModule } from '@angular/platform-browser';
-import { NgModule } from '@angular/core';
-
-import { SheetJSComponent } from './sheetjs.component';
-
-
-import { Component } from '@angular/core';
-
-@Component({
-	selector: 'app-root',
-	template: `<sheetjs></sheetjs>`
-})
-export class AppComponent {
-	title = 'test';
-}
-
-@NgModule({
-	declarations: [
-		SheetJSComponent,
-		AppComponent
-	],
-	imports: [
-		BrowserModule
-	],
-	providers: [],
-	bootstrap: [AppComponent]
-})
-export class AppModule { }
diff --git a/demos/angular2/src/app/sheetjs.component.ts b/demos/angular2/src/app/sheetjs.component.ts
deleted file mode 100644
index 0015d61..0000000
--- a/demos/angular2/src/app/sheetjs.component.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
-/* vim: set ts=2: */
-import { Component } from '@angular/core';
-
-import { WorkBook, WorkSheet, WritingOptions, read, writeFileXLSX as writeFile, utils, version, set_cptable } from 'xlsx';
-//import * as cpexcel from 'xlsx/dist/cpexcel.full.mjs';
-//set_cptable(cpexcel);
-
-type AOA = any[][];
-
-@Component({
-	selector: 'sheetjs',
-	template: `
-	<pre><b>Version: {{ver}}</b></pre>
-	<input type="file" (change)="onFileChange($event)" multiple="false" />
-	<table class="sjs-table">
-		<tr *ngFor="let row of data">
-			<td *ngFor="let val of row">
-				{{val}}
-			</td>
-		</tr>
-	</table>
-	<button (click)="export()">Export!</button>
-	`
-})
-
-export class SheetJSComponent {
-	data: AOA = [ [1, 2], [3, 4] ];
-	wopts: WritingOptions = { bookType: 'xlsx', type: 'array' };
-	fileName: string = 'SheetJS.xlsx';
-	ver: string = version;
-
-	onFileChange(evt: any) {
-		/* wire up file reader */
-		const target: DataTransfer = <DataTransfer>(evt.target);
-		if (target.files.length !== 1) throw new Error('Cannot use multiple files');
-		const reader: FileReader = new FileReader();
-		reader.onload = (e: any) => {
-			/* read workbook */
-			const ab: ArrayBuffer = e.target.result;
-			const wb: WorkBook = read(ab);
-
-			/* grab first sheet */
-			const wsname: string = wb.SheetNames[0];
-			const ws: WorkSheet = wb.Sheets[wsname];
-
-			/* save data */
-			this.data = <AOA>(utils.sheet_to_json(ws, {header: 1}));
-		};
-		reader.readAsArrayBuffer(target.files[0]);
-	}
-
-	export(): void {
-		/* generate worksheet */
-		const ws: WorkSheet = utils.aoa_to_sheet(this.data);
-
-		/* generate workbook and add the worksheet */
-		const wb: WorkBook = utils.book_new();
-		utils.book_append_sheet(wb, ws, 'Sheet1');
-
-		/* save to file */
-		writeFile(wb, this.fileName);
-	}
-}
diff --git a/demos/angular2/src/environments/environment.prod.ts b/demos/angular2/src/environments/environment.prod.ts
deleted file mode 100644
index 3612073..0000000
--- a/demos/angular2/src/environments/environment.prod.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export const environment = {
-  production: true
-};
diff --git a/demos/angular2/src/environments/environment.ts b/demos/angular2/src/environments/environment.ts
deleted file mode 100644
index ffe8aed..0000000
--- a/demos/angular2/src/environments/environment.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export const environment = {
-  production: false
-};
diff --git a/demos/angular2/src/index.html b/demos/angular2/src/index.html
deleted file mode 100644
index bc806fb..0000000
--- a/demos/angular2/src/index.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html>
-<!-- xlsx.js (C) 2013-present  SheetJS http://sheetjs.com -->
-<!-- vim: set ts=2: -->
-<html lang="en">
-<head>
-	<title>SheetJS + Angular 2+</title>
-  <base href="/">
-
-  <meta name="viewport" content="width=device-width, initial-scale=1">
-</head>
-<body>
-<pre>
-<b><a href="http://sheetjs.com">SheetJS + Angular 2+ demo</a></b>
-
-The core library can be used as-is in angular applications.
-The <a href="https://github.com/sheetjs/js-xlsx">Community Edition README</a> details some common use cases.
-We also have some <a href="http://sheetjs.com/demos/">more public demos</a>
-
-This demo shows `SheetJSComponent` which provides:
-- File input button with an event handler to parse the workbook
-- `data` property: array of arrays
-- Simple angular table which binds to the `data` property
-- `export` function that exports the `data` property to a new file.
-
-<a href="https://obamawhitehouse.archives.gov/sites/default/files/omb/budget/fy2014/assets/receipts.xls">Sample Spreadsheet</a>
-</pre>
-
-<app-root></app-root>
-</body>
-</html>
diff --git a/demos/angular2/src/main.ts b/demos/angular2/src/main.ts
deleted file mode 100644
index d3da1bb..0000000
--- a/demos/angular2/src/main.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
-import { AppModule } from './app/app.module';
-platformBrowserDynamic().bootstrapModule(AppModule);
diff --git a/demos/angular2/src/styles.css b/demos/angular2/src/styles.css
deleted file mode 100644
index 90d4ee0..0000000
--- a/demos/angular2/src/styles.css
+++ /dev/null
@@ -1 +0,0 @@
-/* You can add global styles to this file, and also import other style files */
diff --git a/demos/angular2/src/tsconfig.app.json b/demos/angular2/src/tsconfig.app.json
deleted file mode 100644
index 321e0d7..0000000
--- a/demos/angular2/src/tsconfig.app.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-  "extends": "../tsconfig.json",
-  "compilerOptions": {
-    "outDir": "../out-tsc/app",
-    "module": "es2015",
-    "baseUrl": "",
-    "types": []
-  }
-}
diff --git a/demos/angular2/tsconfig.json b/demos/angular2/tsconfig.json
deleted file mode 100644
index a35a8ee..0000000
--- a/demos/angular2/tsconfig.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
-  "compileOnSave": false,
-  "compilerOptions": {
-    "outDir": "./dist/out-tsc",
-    "baseUrl": "src",
-    "sourceMap": true,
-    "declaration": false,
-    "moduleResolution": "node",
-    "emitDecoratorMetadata": true,
-    "experimentalDecorators": true,
-    "target": "es5",
-    "typeRoots": [
-      "node_modules/@types"
-    ],
-    "lib": [
-      "es2016",
-      "dom"
-    ]
-  }
-}
diff --git a/demos/angular2/versions/angular.json-ng10 b/demos/angular2/versions/angular.json-ng10
deleted file mode 100644
index 9e7228c..0000000
--- a/demos/angular2/versions/angular.json-ng10
+++ /dev/null
@@ -1,125 +0,0 @@
-{
-  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
-  "version": 1,
-  "newProjectRoot": "projects",
-  "projects": {
-    "sheetjs": {
-      "root": "",
-      "sourceRoot": "src",
-      "projectType": "application",
-      "prefix": "app",
-      "schematics": {},
-      "architect": {
-        "build": {
-          "builder": "@angular-devkit/build-angular:browser",
-          "options": {
-            "outputPath": "dist/sheetjs",
-            "index": "src/index.html",
-            "main": "src/main.ts",
-            "polyfills": "src/polyfills.ts",
-            "tsConfig": "tsconfig.app.json",
-            "aot": true,
-            "assets": [
-              "src/favicon.ico",
-              "src/assets"
-            ],
-            "styles": [
-              "src/styles.css"
-            ],
-            "scripts": []
-          },
-          "configurations": {
-            "production": {
-              "fileReplacements": [
-                {
-                  "replace": "src/environments/environment.ts",
-                  "with": "src/environments/environment.prod.ts"
-                }
-              ],
-              "optimization": true,
-              "outputHashing": "all",
-              "sourceMap": false,
-              "extractCss": true,
-              "namedChunks": false,
-              "extractLicenses": true,
-              "vendorChunk": false,
-              "buildOptimizer": true,
-              "budgets": [
-                {
-                  "type": "initial",
-                  "maximumWarning": "2mb",
-                  "maximumError": "5mb"
-                },
-                {
-                  "type": "anyComponentStyle",
-                  "maximumWarning": "6kb",
-                  "maximumError": "10kb"
-                }
-              ]
-            }
-          }
-        },
-        "serve": {
-          "builder": "@angular-devkit/build-angular:dev-server",
-          "options": {
-            "browserTarget": "sheetjs:build"
-          },
-          "configurations": {
-            "production": {
-              "browserTarget": "sheetjs:build:production"
-            }
-          }
-        },
-        "extract-i18n": {
-          "builder": "@angular-devkit/build-angular:extract-i18n",
-          "options": {
-            "browserTarget": "sheetjs:build"
-          }
-        },
-        "test": {
-          "builder": "@angular-devkit/build-angular:karma",
-          "options": {
-            "main": "src/test.ts",
-            "polyfills": "src/polyfills.ts",
-            "tsConfig": "tsconfig.spec.json",
-            "karmaConfig": "karma.conf.js",
-            "assets": [
-              "src/favicon.ico",
-              "src/assets"
-            ],
-            "styles": [
-              "src/styles.css"
-            ],
-            "scripts": []
-          }
-        },
-        "lint": {
-          "builder": "@angular-devkit/build-angular:tslint",
-          "options": {
-            "tsConfig": [
-              "tsconfig.app.json",
-              "tsconfig.spec.json",
-              "e2e/tsconfig.json"
-            ],
-            "exclude": [
-              "**/node_modules/**"
-            ]
-          }
-        },
-        "e2e": {
-          "builder": "@angular-devkit/build-angular:protractor",
-          "options": {
-            "protractorConfig": "e2e/protractor.conf.js",
-            "devServerTarget": "sheetjs:serve"
-          },
-          "configurations": {
-            "production": {
-              "devServerTarget": "sheetjs:serve:production"
-            }
-          }
-        }
-      }
-    }
-  },
-  "defaultProject": "sheetjs"
-}
diff --git a/demos/angular2/versions/angular.json-ng11 b/demos/angular2/versions/angular.json-ng11
deleted file mode 100644
index a1563c1..0000000
--- a/demos/angular2/versions/angular.json-ng11
+++ /dev/null
@@ -1,124 +0,0 @@
-{
-  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
-  "version": 1,
-  "newProjectRoot": "projects",
-  "projects": {
-    "sheetjs": {
-      "root": "",
-      "sourceRoot": "src",
-      "projectType": "application",
-      "prefix": "app",
-      "schematics": {},
-      "architect": {
-        "build": {
-          "builder": "@angular-devkit/build-angular:browser",
-          "options": {
-            "outputPath": "dist/sheetjs",
-            "index": "src/index.html",
-            "main": "src/main.ts",
-            "polyfills": "src/polyfills.ts",
-            "tsConfig": "tsconfig.app.json",
-            "aot": true,
-            "assets": [
-              "src/favicon.ico",
-              "src/assets"
-            ],
-            "styles": [
-              "src/styles.css"
-            ],
-            "scripts": []
-          },
-          "configurations": {
-            "production": {
-              "fileReplacements": [
-                {
-                  "replace": "src/environments/environment.ts",
-                  "with": "src/environments/environment.prod.ts"
-                }
-              ],
-              "optimization": true,
-              "outputHashing": "all",
-              "sourceMap": false,
-              "namedChunks": false,
-              "extractLicenses": true,
-              "vendorChunk": false,
-              "buildOptimizer": true,
-              "budgets": [
-                {
-                  "type": "initial",
-                  "maximumWarning": "2mb",
-                  "maximumError": "5mb"
-                },
-                {
-                  "type": "anyComponentStyle",
-                  "maximumWarning": "6kb",
-                  "maximumError": "10kb"
-                }
-              ]
-            }
-          }
-        },
-        "serve": {
-          "builder": "@angular-devkit/build-angular:dev-server",
-          "options": {
-            "browserTarget": "sheetjs:build"
-          },
-          "configurations": {
-            "production": {
-              "browserTarget": "sheetjs:build:production"
-            }
-          }
-        },
-        "extract-i18n": {
-          "builder": "@angular-devkit/build-angular:extract-i18n",
-          "options": {
-            "browserTarget": "sheetjs:build"
-          }
-        },
-        "test": {
-          "builder": "@angular-devkit/build-angular:karma",
-          "options": {
-            "main": "src/test.ts",
-            "polyfills": "src/polyfills.ts",
-            "tsConfig": "tsconfig.spec.json",
-            "karmaConfig": "karma.conf.js",
-            "assets": [
-              "src/favicon.ico",
-              "src/assets"
-            ],
-            "styles": [
-              "src/styles.css"
-            ],
-            "scripts": []
-          }
-        },
-        "lint": {
-          "builder": "@angular-devkit/build-angular:tslint",
-          "options": {
-            "tsConfig": [
-              "tsconfig.app.json",
-              "tsconfig.spec.json",
-              "e2e/tsconfig.json"
-            ],
-            "exclude": [
-              "**/node_modules/**"
-            ]
-          }
-        },
-        "e2e": {
-          "builder": "@angular-devkit/build-angular:protractor",
-          "options": {
-            "protractorConfig": "e2e/protractor.conf.js",
-            "devServerTarget": "sheetjs:serve"
-          },
-          "configurations": {
-            "production": {
-              "devServerTarget": "sheetjs:serve:production"
-            }
-          }
-        }
-      }
-    }
-  },
-  "defaultProject": "sheetjs"
-}
diff --git a/demos/angular2/versions/angular.json-ng12 b/demos/angular2/versions/angular.json-ng12
deleted file mode 100644
index 69d02ea..0000000
--- a/demos/angular2/versions/angular.json-ng12
+++ /dev/null
@@ -1,106 +0,0 @@
-{
-  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
-  "version": 1,
-  "newProjectRoot": "projects",
-  "projects": {
-    "sheetjs": {
-      "root": "",
-      "sourceRoot": "src",
-      "projectType": "application",
-      "prefix": "app",
-      "schematics": {
-        "@schematics/angular:application": {
-          "strict": true
-        }
-      },
-      "architect": {
-        "build": {
-          "builder": "@angular-devkit/build-angular:browser",
-          "options": {
-            "outputPath": "dist/sheetjs",
-            "index": "src/index.html",
-            "main": "src/main.ts",
-            "polyfills": "src/polyfills.ts",
-            "tsConfig": "tsconfig.app.json",
-            "assets": [
-              "src/favicon.ico",
-              "src/assets"
-            ],
-            "styles": [
-              "src/styles.css"
-            ],
-            "scripts": []
-          },
-          "configurations": {
-            "production": {
-              "budgets": [
-                {
-                  "type": "initial",
-                  "maximumWarning": "500kb",
-                  "maximumError": "2mb"
-                },
-                {
-                  "type": "anyComponentStyle",
-                  "maximumWarning": "2kb",
-                  "maximumError": "4kb"
-                }
-              ],
-              "fileReplacements": [
-                {
-                  "replace": "src/environments/environment.ts",
-                  "with": "src/environments/environment.prod.ts"
-                }
-              ],
-              "outputHashing": "all"
-            },
-            "development": {
-              "buildOptimizer": false,
-              "optimization": false,
-              "vendorChunk": true,
-              "extractLicenses": false,
-              "sourceMap": true,
-              "namedChunks": true
-            }
-          },
-          "defaultConfiguration": "production"
-        },
-        "serve": {
-          "builder": "@angular-devkit/build-angular:dev-server",
-          "configurations": {
-            "production": {
-              "browserTarget": "sheetjs:build:production"
-            },
-            "development": {
-              "browserTarget": "sheetjs:build:development"
-            }
-          },
-          "defaultConfiguration": "development"
-        },
-        "extract-i18n": {
-          "builder": "@angular-devkit/build-angular:extract-i18n",
-          "options": {
-            "browserTarget": "sheetjs:build"
-          }
-        },
-        "test": {
-          "builder": "@angular-devkit/build-angular:karma",
-          "options": {
-            "main": "src/test.ts",
-            "polyfills": "src/polyfills.ts",
-            "tsConfig": "tsconfig.spec.json",
-            "karmaConfig": "karma.conf.js",
-            "assets": [
-              "src/favicon.ico",
-              "src/assets"
-            ],
-            "styles": [
-              "src/styles.css"
-            ],
-            "scripts": []
-          }
-        }
-      }
-    }
-  },
-  "defaultProject": "sheetjs"
-}
diff --git a/demos/angular2/versions/angular.json-ng13 b/demos/angular2/versions/angular.json-ng13
deleted file mode 100644
index 69d02ea..0000000
--- a/demos/angular2/versions/angular.json-ng13
+++ /dev/null
@@ -1,106 +0,0 @@
-{
-  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
-  "version": 1,
-  "newProjectRoot": "projects",
-  "projects": {
-    "sheetjs": {
-      "root": "",
-      "sourceRoot": "src",
-      "projectType": "application",
-      "prefix": "app",
-      "schematics": {
-        "@schematics/angular:application": {
-          "strict": true
-        }
-      },
-      "architect": {
-        "build": {
-          "builder": "@angular-devkit/build-angular:browser",
-          "options": {
-            "outputPath": "dist/sheetjs",
-            "index": "src/index.html",
-            "main": "src/main.ts",
-            "polyfills": "src/polyfills.ts",
-            "tsConfig": "tsconfig.app.json",
-            "assets": [
-              "src/favicon.ico",
-              "src/assets"
-            ],
-            "styles": [
-              "src/styles.css"
-            ],
-            "scripts": []
-          },
-          "configurations": {
-            "production": {
-              "budgets": [
-                {
-                  "type": "initial",
-                  "maximumWarning": "500kb",
-                  "maximumError": "2mb"
-                },
-                {
-                  "type": "anyComponentStyle",
-                  "maximumWarning": "2kb",
-                  "maximumError": "4kb"
-                }
-              ],
-              "fileReplacements": [
-                {
-                  "replace": "src/environments/environment.ts",
-                  "with": "src/environments/environment.prod.ts"
-                }
-              ],
-              "outputHashing": "all"
-            },
-            "development": {
-              "buildOptimizer": false,
-              "optimization": false,
-              "vendorChunk": true,
-              "extractLicenses": false,
-              "sourceMap": true,
-              "namedChunks": true
-            }
-          },
-          "defaultConfiguration": "production"
-        },
-        "serve": {
-          "builder": "@angular-devkit/build-angular:dev-server",
-          "configurations": {
-            "production": {
-              "browserTarget": "sheetjs:build:production"
-            },
-            "development": {
-              "browserTarget": "sheetjs:build:development"
-            }
-          },
-          "defaultConfiguration": "development"
-        },
-        "extract-i18n": {
-          "builder": "@angular-devkit/build-angular:extract-i18n",
-          "options": {
-            "browserTarget": "sheetjs:build"
-          }
-        },
-        "test": {
-          "builder": "@angular-devkit/build-angular:karma",
-          "options": {
-            "main": "src/test.ts",
-            "polyfills": "src/polyfills.ts",
-            "tsConfig": "tsconfig.spec.json",
-            "karmaConfig": "karma.conf.js",
-            "assets": [
-              "src/favicon.ico",
-              "src/assets"
-            ],
-            "styles": [
-              "src/styles.css"
-            ],
-            "scripts": []
-          }
-        }
-      }
-    }
-  },
-  "defaultProject": "sheetjs"
-}
diff --git a/demos/angular2/versions/angular.json-ng6 b/demos/angular2/versions/angular.json-ng6
deleted file mode 100644
index 30e40df..0000000
--- a/demos/angular2/versions/angular.json-ng6
+++ /dev/null
@@ -1,127 +0,0 @@
-{
-  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
-  "version": 1,
-  "newProjectRoot": "projects",
-  "projects": {
-    "sheetjs": {
-      "root": "",
-      "sourceRoot": "src",
-      "projectType": "application",
-      "prefix": "app",
-      "schematics": {},
-      "architect": {
-        "build": {
-          "builder": "@angular-devkit/build-angular:browser",
-          "options": {
-            "outputPath": "dist/sheetjs",
-            "index": "src/index.html",
-            "main": "src/main.ts",
-            "polyfills": "src/polyfills.ts",
-            "tsConfig": "src/tsconfig.app.json",
-            "assets": [
-              "src/favicon.ico",
-              "src/assets"
-            ],
-            "styles": [
-              "src/styles.css"
-            ],
-            "scripts": []
-          },
-          "configurations": {
-            "production": {
-              "fileReplacements": [
-                {
-                  "replace": "src/environments/environment.ts",
-                  "with": "src/environments/environment.prod.ts"
-                }
-              ],
-              "optimization": true,
-              "outputHashing": "all",
-              "sourceMap": false,
-              "extractCss": true,
-              "namedChunks": false,
-              "aot": true,
-              "extractLicenses": true,
-              "vendorChunk": false,
-              "buildOptimizer": true
-            }
-          }
-        },
-        "serve": {
-          "builder": "@angular-devkit/build-angular:dev-server",
-          "options": {
-            "browserTarget": "sheetjs:build"
-          },
-          "configurations": {
-            "production": {
-              "browserTarget": "sheetjs:build:production"
-            }
-          }
-        },
-        "extract-i18n": {
-          "builder": "@angular-devkit/build-angular:extract-i18n",
-          "options": {
-            "browserTarget": "sheetjs:build"
-          }
-        },
-        "test": {
-          "builder": "@angular-devkit/build-angular:karma",
-          "options": {
-            "main": "src/test.ts",
-            "polyfills": "src/polyfills.ts",
-            "tsConfig": "src/tsconfig.spec.json",
-            "karmaConfig": "src/karma.conf.js",
-            "styles": [
-              "src/styles.css"
-            ],
-            "scripts": [],
-            "assets": [
-              "src/favicon.ico",
-              "src/assets"
-            ]
-          }
-        },
-        "lint": {
-          "builder": "@angular-devkit/build-angular:tslint",
-          "options": {
-            "tsConfig": [
-              "src/tsconfig.app.json",
-              "src/tsconfig.spec.json"
-            ],
-            "exclude": [
-              "**/node_modules/**"
-            ]
-          }
-        }
-      }
-    },
-    "sheetjs-e2e": {
-      "root": "e2e/",
-      "projectType": "application",
-      "architect": {
-        "e2e": {
-          "builder": "@angular-devkit/build-angular:protractor",
-          "options": {
-            "protractorConfig": "e2e/protractor.conf.js",
-            "devServerTarget": "sheetjs:serve"
-          },
-          "configurations": {
-            "production": {
-              "devServerTarget": "sheetjs:serve:production"
-            }
-          }
-        },
-        "lint": {
-          "builder": "@angular-devkit/build-angular:tslint",
-          "options": {
-            "tsConfig": "e2e/tsconfig.e2e.json",
-            "exclude": [
-              "**/node_modules/**"
-            ]
-          }
-        }
-      }
-    }
-  },
-  "defaultProject": "sheetjs"
-}
diff --git a/demos/angular2/versions/angular.json-ng7 b/demos/angular2/versions/angular.json-ng7
deleted file mode 100644
index be12951..0000000
--- a/demos/angular2/versions/angular.json-ng7
+++ /dev/null
@@ -1,136 +0,0 @@
-{
-  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
-  "version": 1,
-  "newProjectRoot": "projects",
-  "projects": {
-    "sheetjs": {
-      "root": "",
-      "sourceRoot": "src",
-      "projectType": "application",
-      "prefix": "app",
-      "schematics": {},
-      "architect": {
-        "build": {
-          "builder": "@angular-devkit/build-angular:browser",
-          "options": {
-            "outputPath": "dist/sheetjs",
-            "index": "src/index.html",
-            "main": "src/main.ts",
-            "polyfills": "src/polyfills.ts",
-            "tsConfig": "src/tsconfig.app.json",
-            "assets": [
-              "src/favicon.ico",
-              "src/assets"
-            ],
-            "styles": [
-              "src/styles.css"
-            ],
-            "scripts": [],
-            "es5BrowserSupport": true
-          },
-          "configurations": {
-            "production": {
-              "fileReplacements": [
-                {
-                  "replace": "src/environments/environment.ts",
-                  "with": "src/environments/environment.prod.ts"
-                }
-              ],
-              "optimization": true,
-              "outputHashing": "all",
-              "sourceMap": false,
-              "extractCss": true,
-              "namedChunks": false,
-              "aot": true,
-              "extractLicenses": true,
-              "vendorChunk": false,
-              "buildOptimizer": true,
-              "budgets": [
-                {
-                  "type": "initial",
-                  "maximumWarning": "2mb",
-                  "maximumError": "5mb"
-                }
-              ]
-            }
-          }
-        },
-        "serve": {
-          "builder": "@angular-devkit/build-angular:dev-server",
-          "options": {
-            "browserTarget": "sheetjs:build"
-          },
-          "configurations": {
-            "production": {
-              "browserTarget": "sheetjs:build:production"
-            }
-          }
-        },
-        "extract-i18n": {
-          "builder": "@angular-devkit/build-angular:extract-i18n",
-          "options": {
-            "browserTarget": "sheetjs:build"
-          }
-        },
-        "test": {
-          "builder": "@angular-devkit/build-angular:karma",
-          "options": {
-            "main": "src/test.ts",
-            "polyfills": "src/polyfills.ts",
-            "tsConfig": "src/tsconfig.spec.json",
-            "karmaConfig": "src/karma.conf.js",
-            "styles": [
-              "src/styles.css"
-            ],
-            "scripts": [],
-            "assets": [
-              "src/favicon.ico",
-              "src/assets"
-            ]
-          }
-        },
-        "lint": {
-          "builder": "@angular-devkit/build-angular:tslint",
-          "options": {
-            "tsConfig": [
-              "src/tsconfig.app.json",
-              "src/tsconfig.spec.json"
-            ],
-            "exclude": [
-              "**/node_modules/**"
-            ]
-          }
-        }
-      }
-    },
-    "sheetjs-e2e": {
-      "root": "e2e/",
-      "projectType": "application",
-      "prefix": "",
-      "architect": {
-        "e2e": {
-          "builder": "@angular-devkit/build-angular:protractor",
-          "options": {
-            "protractorConfig": "e2e/protractor.conf.js",
-            "devServerTarget": "sheetjs:serve"
-          },
-          "configurations": {
-            "production": {
-              "devServerTarget": "sheetjs:serve:production"
-            }
-          }
-        },
-        "lint": {
-          "builder": "@angular-devkit/build-angular:tslint",
-          "options": {
-            "tsConfig": "e2e/tsconfig.e2e.json",
-            "exclude": [
-              "**/node_modules/**"
-            ]
-          }
-        }
-      }
-    }
-  },
-  "defaultProject": "sheetjs"
-}
diff --git a/demos/angular2/versions/angular.json-ng8 b/demos/angular2/versions/angular.json-ng8
deleted file mode 100644
index de608c0..0000000
--- a/demos/angular2/versions/angular.json-ng8
+++ /dev/null
@@ -1,126 +0,0 @@
-{
-  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
-  "version": 1,
-  "newProjectRoot": "projects",
-  "projects": {
-    "sheetjs": {
-      "root": "",
-      "sourceRoot": "src",
-      "projectType": "application",
-      "prefix": "app",
-      "schematics": {},
-      "architect": {
-        "build": {
-          "builder": "@angular-devkit/build-angular:browser",
-          "options": {
-            "outputPath": "dist/sheetjs",
-            "index": "src/index.html",
-            "main": "src/main.ts",
-            "polyfills": "src/polyfills.ts",
-            "tsConfig": "tsconfig.app.json",
-            "aot": false,
-            "assets": [
-              "src/favicon.ico",
-              "src/assets"
-            ],
-            "styles": [
-              "src/styles.css"
-            ],
-            "scripts": []
-          },
-          "configurations": {
-            "production": {
-              "fileReplacements": [
-                {
-                  "replace": "src/environments/environment.ts",
-                  "with": "src/environments/environment.prod.ts"
-                }
-              ],
-              "optimization": true,
-              "outputHashing": "all",
-              "sourceMap": false,
-              "extractCss": true,
-              "namedChunks": false,
-              "aot": true,
-              "extractLicenses": true,
-              "vendorChunk": false,
-              "buildOptimizer": true,
-              "budgets": [
-                {
-                  "type": "initial",
-                  "maximumWarning": "2mb",
-                  "maximumError": "5mb"
-                },
-                {
-                  "type": "anyComponentStyle",
-                  "maximumWarning": "6kb",
-                  "maximumError": "10kb"
-                }
-              ]
-            }
-          }
-        },
-        "serve": {
-          "builder": "@angular-devkit/build-angular:dev-server",
-          "options": {
-            "browserTarget": "sheetjs:build"
-          },
-          "configurations": {
-            "production": {
-              "browserTarget": "sheetjs:build:production"
-            }
-          }
-        },
-        "extract-i18n": {
-          "builder": "@angular-devkit/build-angular:extract-i18n",
-          "options": {
-            "browserTarget": "sheetjs:build"
-          }
-        },
-        "test": {
-          "builder": "@angular-devkit/build-angular:karma",
-          "options": {
-            "main": "src/test.ts",
-            "polyfills": "src/polyfills.ts",
-            "tsConfig": "tsconfig.spec.json",
-            "karmaConfig": "karma.conf.js",
-            "assets": [
-              "src/favicon.ico",
-              "src/assets"
-            ],
-            "styles": [
-              "src/styles.css"
-            ],
-            "scripts": []
-          }
-        },
-        "lint": {
-          "builder": "@angular-devkit/build-angular:tslint",
-          "options": {
-            "tsConfig": [
-              "tsconfig.app.json",
-              "tsconfig.spec.json",
-              "e2e/tsconfig.json"
-            ],
-            "exclude": [
-              "**/node_modules/**"
-            ]
-          }
-        },
-        "e2e": {
-          "builder": "@angular-devkit/build-angular:protractor",
-          "options": {
-            "protractorConfig": "e2e/protractor.conf.js",
-            "devServerTarget": "sheetjs:serve"
-          },
-          "configurations": {
-            "production": {
-              "devServerTarget": "sheetjs:serve:production"
-            }
-          }
-        }
-      }
-    }
-  },
-  "defaultProject": "sheetjs"
-}
diff --git a/demos/angular2/versions/angular.json-ng9 b/demos/angular2/versions/angular.json-ng9
deleted file mode 100644
index 9e7228c..0000000
--- a/demos/angular2/versions/angular.json-ng9
+++ /dev/null
@@ -1,125 +0,0 @@
-{
-  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
-  "version": 1,
-  "newProjectRoot": "projects",
-  "projects": {
-    "sheetjs": {
-      "root": "",
-      "sourceRoot": "src",
-      "projectType": "application",
-      "prefix": "app",
-      "schematics": {},
-      "architect": {
-        "build": {
-          "builder": "@angular-devkit/build-angular:browser",
-          "options": {
-            "outputPath": "dist/sheetjs",
-            "index": "src/index.html",
-            "main": "src/main.ts",
-            "polyfills": "src/polyfills.ts",
-            "tsConfig": "tsconfig.app.json",
-            "aot": true,
-            "assets": [
-              "src/favicon.ico",
-              "src/assets"
-            ],
-            "styles": [
-              "src/styles.css"
-            ],
-            "scripts": []
-          },
-          "configurations": {
-            "production": {
-              "fileReplacements": [
-                {
-                  "replace": "src/environments/environment.ts",
-                  "with": "src/environments/environment.prod.ts"
-                }
-              ],
-              "optimization": true,
-              "outputHashing": "all",
-              "sourceMap": false,
-              "extractCss": true,
-              "namedChunks": false,
-              "extractLicenses": true,
-              "vendorChunk": false,
-              "buildOptimizer": true,
-              "budgets": [
-                {
-                  "type": "initial",
-                  "maximumWarning": "2mb",
-                  "maximumError": "5mb"
-                },
-                {
-                  "type": "anyComponentStyle",
-                  "maximumWarning": "6kb",
-                  "maximumError": "10kb"
-                }
-              ]
-            }
-          }
-        },
-        "serve": {
-          "builder": "@angular-devkit/build-angular:dev-server",
-          "options": {
-            "browserTarget": "sheetjs:build"
-          },
-          "configurations": {
-            "production": {
-              "browserTarget": "sheetjs:build:production"
-            }
-          }
-        },
-        "extract-i18n": {
-          "builder": "@angular-devkit/build-angular:extract-i18n",
-          "options": {
-            "browserTarget": "sheetjs:build"
-          }
-        },
-        "test": {
-          "builder": "@angular-devkit/build-angular:karma",
-          "options": {
-            "main": "src/test.ts",
-            "polyfills": "src/polyfills.ts",
-            "tsConfig": "tsconfig.spec.json",
-            "karmaConfig": "karma.conf.js",
-            "assets": [
-              "src/favicon.ico",
-              "src/assets"
-            ],
-            "styles": [
-              "src/styles.css"
-            ],
-            "scripts": []
-          }
-        },
-        "lint": {
-          "builder": "@angular-devkit/build-angular:tslint",
-          "options": {
-            "tsConfig": [
-              "tsconfig.app.json",
-              "tsconfig.spec.json",
-              "e2e/tsconfig.json"
-            ],
-            "exclude": [
-              "**/node_modules/**"
-            ]
-          }
-        },
-        "e2e": {
-          "builder": "@angular-devkit/build-angular:protractor",
-          "options": {
-            "protractorConfig": "e2e/protractor.conf.js",
-            "devServerTarget": "sheetjs:serve"
-          },
-          "configurations": {
-            "production": {
-              "devServerTarget": "sheetjs:serve:production"
-            }
-          }
-        }
-      }
-    }
-  },
-  "defaultProject": "sheetjs"
-}
diff --git a/demos/angular2/versions/package.json-ng10 b/demos/angular2/versions/package.json-ng10
deleted file mode 100644
index fff68df..0000000
--- a/demos/angular2/versions/package.json-ng10
+++ /dev/null
@@ -1,39 +0,0 @@
-{
-  "name": "angular10",
-  "version": "0.0.0",
-  "license": "MIT",
-  "scripts": {
-    "ng": "ng",
-    "start": "ng serve",
-    "build": "ng build"
-  },
-  "private": true,
-  "dependencies": {
-    "@angular/animations": "~10.2.4",
-    "@angular/common": "~10.2.4",
-    "@angular/compiler": "~10.2.4",
-
-    "@angular/core": "~10.2.4",
-    "@angular/forms": "~10.2.4",
-
-    "@angular/platform-browser": "~10.2.4",
-    "@angular/platform-browser-dynamic": "~10.2.4",
-
-    "@angular/router": "~10.2.4",
-
-
-    "rxjs": "~6.6.0",
-    "tslib": "^2.0.0",
-    "zone.js": "~0.10.2"
-  },
-  "devDependencies": {
-    "@angular-devkit/build-angular": "~0.1002.3",
-    "@angular/cli": "~10.2.3",
-    "@angular/compiler-cli": "~10.2.4",
-
-    "@types/node": "^12.11.1",
-    "ts-node": "~8.3.0",
-    "tslint": "~6.1.0",
-    "typescript": "~4.0.2"
-  }
-}
diff --git a/demos/angular2/versions/package.json-ng11 b/demos/angular2/versions/package.json-ng11
deleted file mode 100644
index 9bb80a8..0000000
--- a/demos/angular2/versions/package.json-ng11
+++ /dev/null
@@ -1,39 +0,0 @@
-{
-  "name": "angular11",
-  "version": "0.0.0",
-  "license": "MIT",
-  "scripts": {
-    "ng": "ng",
-    "start": "ng serve",
-    "build": "ng build"
-  },
-  "private": true,
-  "dependencies": {
-    "@angular/animations": "~11.2.14",
-    "@angular/common": "~11.2.14",
-    "@angular/compiler": "~11.2.14",
-
-    "@angular/core": "~11.2.14",
-    "@angular/forms": "~11.2.14",
-
-    "@angular/platform-browser": "~11.2.14",
-    "@angular/platform-browser-dynamic": "~11.2.14",
-
-    "@angular/router": "~11.2.14",
-
-
-    "rxjs": "~6.6.0",
-    "tslib": "^2.0.0",
-    "zone.js": "~0.11.3"
-  },
-  "devDependencies": {
-    "@angular-devkit/build-angular": "~0.1102.13",
-    "@angular/cli": "~11.2.14",
-    "@angular/compiler-cli": "~11.2.14",
-
-    "@types/node": "^12.11.1",
-    "ts-node": "~8.3.0",
-    "tslint": "~6.1.0",
-    "typescript": "~4.1.5"
-  }
-}
diff --git a/demos/angular2/versions/package.json-ng12 b/demos/angular2/versions/package.json-ng12
deleted file mode 100644
index 74df6c5..0000000
--- a/demos/angular2/versions/package.json-ng12
+++ /dev/null
@@ -1,39 +0,0 @@
-{
-  "name": "angular12",
-  "version": "0.0.0",
-  "license": "MIT",
-  "scripts": {
-    "ng": "ng",
-    "start": "ng serve",
-    "build": "ng build"
-  },
-  "private": true,
-  "dependencies": {
-    "@angular/animations": "~12.2.0",
-    "@angular/common": "~12.2.0",
-    "@angular/compiler": "~12.2.0",
-
-    "@angular/core": "~12.2.0",
-    "@angular/forms": "~12.2.0",
-
-    "@angular/platform-browser": "~12.2.0",
-    "@angular/platform-browser-dynamic": "~12.2.0",
-
-    "@angular/router": "~12.2.0",
-
-
-    "rxjs": "~6.6.0",
-    "tslib": "^2.3.0",
-    "zone.js": "~0.11.4"
-  },
-  "devDependencies": {
-    "@angular-devkit/build-angular": "~12.2.7",
-    "@angular/cli": "~12.2.7",
-    "@angular/compiler-cli": "~12.2.0",
-
-    "@types/node": "^12.11.1",
-
-
-    "typescript": "~4.3.5"
-  }
-}
diff --git a/demos/angular2/versions/package.json-ng13 b/demos/angular2/versions/package.json-ng13
deleted file mode 100644
index a214cef..0000000
--- a/demos/angular2/versions/package.json-ng13
+++ /dev/null
@@ -1,39 +0,0 @@
-{
-  "name": "angular13",
-  "version": "0.0.0",
-  "license": "MIT",
-  "scripts": {
-    "ng": "ng",
-    "start": "ng serve",
-    "build": "ng build"
-  },
-  "private": true,
-  "dependencies": {
-    "@angular/animations": "~13.2.0",
-    "@angular/common": "~13.2.0",
-    "@angular/compiler": "~13.2.0",
-
-    "@angular/core": "~13.2.0",
-    "@angular/forms": "~13.2.0",
-
-    "@angular/platform-browser": "~13.2.0",
-    "@angular/platform-browser-dynamic": "~13.2.0",
-
-    "@angular/router": "~13.2.0",
-
-
-    "rxjs": "~7.5.0",
-    "tslib": "^2.3.0",
-    "zone.js": "~0.11.4"
-  },
-  "devDependencies": {
-    "@angular-devkit/build-angular": "~13.2.1",
-    "@angular/cli": "~13.2.1",
-    "@angular/compiler-cli": "~13.2.0",
-
-    "@types/node": "^12.11.1",
-
-
-    "typescript": "~4.5.2"
-  }
-}
diff --git a/demos/angular2/versions/package.json-ng2 b/demos/angular2/versions/package.json-ng2
deleted file mode 100644
index c6cdfe9..0000000
--- a/demos/angular2/versions/package.json-ng2
+++ /dev/null
@@ -1,37 +0,0 @@
-{
-  "name": "angular2",
-  "version": "0.0.0",
-  "license": "MIT",
-  "scripts": {
-    "ng": "ng",
-    "start": "ng serve",
-    "build": "ng build"
-  },
-  "private": true,
-  "dependencies": {
-    "@angular/common": "~2.4.1",
-    "@angular/compiler": "~2.4.1",
-    "@angular/compiler-cli": "^2.4.1",
-    "@angular/core": "~2.4.1",
-    "@angular/forms": "~2.4.1",
-    "@angular/http": "~2.4.1",
-    "@angular/platform-browser": "~2.4.1",
-    "@angular/platform-browser-dynamic": "~2.4.1",
-    "@angular/platform-server": "^2.4.1",
-    "@angular/router": "~3.4.0",
-    "core-js": "^2.4.1",
-    "reflect-metadata": "^0.1.8",
-    "rxjs": "^5.0.2",
-    "systemjs": "0.19.40",
-    "zone.js": "^0.7.4"
-  },
-  "devDependencies": {
-    "@angular/cli": "1.1.2",
-    "@angular/compiler-cli": "^2.0.0",
-    "@angular/language-service": "^2.0.0",
-    "@types/node": "~6.0.60",
-    "ts-node": "~3.0.4",
-    "tslint": "~5.3.2",
-    "typescript": "~2.3.3"
-  }
-}
diff --git a/demos/angular2/versions/package.json-ng4 b/demos/angular2/versions/package.json-ng4
deleted file mode 100644
index 2891383..0000000
--- a/demos/angular2/versions/package.json-ng4
+++ /dev/null
@@ -1,38 +0,0 @@
-{
-  "name": "angular4",
-  "version": "0.0.0",
-  "license": "MIT",
-  "scripts": {
-    "ng": "ng",
-    "start": "ng serve",
-    "build": "ng build"
-  },
-  "private": true,
-  "dependencies": {
-    "@angular/animations": "^4.0.0",
-    "@angular/common": "^4.0.0",
-    "@angular/compiler": "^4.0.0",
-
-    "@angular/core": "^4.0.0",
-    "@angular/forms": "^4.0.0",
-    "@angular/http": "^4.0.0",
-    "@angular/platform-browser": "^4.0.0",
-    "@angular/platform-browser-dynamic": "^4.0.0",
-
-    "@angular/router": "^4.0.0",
-    "core-js": "^2.4.1",
-
-    "rxjs": "^5.1.0",
-
-    "zone.js": "^0.8.4"
-  },
-  "devDependencies": {
-    "@angular/cli": "1.1.2",
-    "@angular/compiler-cli": "^4.0.0",
-    "@angular/language-service": "^4.0.0",
-    "@types/node": "~6.0.60",
-    "ts-node": "~3.0.4",
-    "tslint": "~5.3.2",
-    "typescript": "~2.3.3"
-  }
-}
diff --git a/demos/angular2/versions/package.json-ng5 b/demos/angular2/versions/package.json-ng5
deleted file mode 100644
index 1f62707..0000000
--- a/demos/angular2/versions/package.json-ng5
+++ /dev/null
@@ -1,38 +0,0 @@
-{
-  "name": "angular5",
-  "version": "0.0.0",
-  "license": "MIT",
-  "scripts": {
-    "ng": "ng",
-    "start": "ng serve",
-    "build": "ng build"
-  },
-  "private": true,
-  "dependencies": {
-    "@angular/animations": "^5.0.0",
-    "@angular/common": "^5.0.0",
-    "@angular/compiler": "^5.0.0",
-
-    "@angular/core": "^5.0.0",
-    "@angular/forms": "^5.0.0",
-    "@angular/http": "^5.0.0",
-    "@angular/platform-browser": "^5.0.0",
-    "@angular/platform-browser-dynamic": "^5.0.0",
-
-    "@angular/router": "^5.0.0",
-    "core-js": "^2.4.1",
-
-    "rxjs": "^5.5.2",
-
-    "zone.js": "^0.8.14"
-  },
-  "devDependencies": {
-    "@angular/cli": "^1.5.3",
-    "@angular/compiler-cli": "^5.0.0",
-    "@angular/language-service": "^5.0.0",
-    "@types/node": "~6.0.60",
-    "ts-node": "~3.2.0",
-    "tslint": "~5.7.0",
-    "typescript": "~2.4.2"
-  }
-}
diff --git a/demos/angular2/versions/package.json-ng6 b/demos/angular2/versions/package.json-ng6
deleted file mode 100644
index a6df172..0000000
--- a/demos/angular2/versions/package.json-ng6
+++ /dev/null
@@ -1,39 +0,0 @@
-{
-  "name": "angular6",
-  "version": "0.0.0",
-  "license": "MIT",
-  "scripts": {
-    "ng": "ng",
-    "start": "ng serve",
-    "build": "ng build"
-  },
-  "private": true,
-  "dependencies": {
-    "@angular/animations": "^6.1.0",
-    "@angular/common": "^6.1.0",
-    "@angular/compiler": "^6.1.0",
-
-    "@angular/core": "^6.1.0",
-    "@angular/forms": "^6.1.0",
-    "@angular/http": "^6.1.0",
-    "@angular/platform-browser": "^6.1.0",
-    "@angular/platform-browser-dynamic": "^6.1.0",
-
-    "@angular/router": "^6.1.0",
-    "core-js": "^2.5.4",
-
-    "rxjs": "~6.2.0",
-
-    "zone.js": "~0.8.26"
-  },
-  "devDependencies": {
-    "@angular-devkit/build-angular": "~0.8.0",
-    "@angular/cli": "~6.2.9",
-    "@angular/compiler-cli": "^6.1.0",
-    "@angular/language-service": "^6.1.0",
-    "@types/node": "~8.9.4",
-    "ts-node": "~7.0.0",
-    "tslint": "~5.11.0",
-    "typescript": "~2.9.2"
-  }
-}
diff --git a/demos/angular2/versions/package.json-ng7 b/demos/angular2/versions/package.json-ng7
deleted file mode 100644
index 841dab7..0000000
--- a/demos/angular2/versions/package.json-ng7
+++ /dev/null
@@ -1,39 +0,0 @@
-{
-  "name": "angular7",
-  "version": "0.0.0",
-  "license": "MIT",
-  "scripts": {
-    "ng": "ng",
-    "start": "ng serve",
-    "build": "ng build"
-  },
-  "private": true,
-  "dependencies": {
-    "@angular/animations": "~7.2.0",
-    "@angular/common": "~7.2.0",
-    "@angular/compiler": "~7.2.0",
-
-    "@angular/core": "~7.2.0",
-    "@angular/forms": "~7.2.0",
-
-    "@angular/platform-browser": "~7.2.0",
-    "@angular/platform-browser-dynamic": "~7.2.0",
-
-    "@angular/router": "~7.2.0",
-    "core-js": "^2.5.4",
-
-    "rxjs": "~6.3.3",
-    "tslib": "^1.9.0",
-    "zone.js": "~0.8.26"
-  },
-  "devDependencies": {
-    "@angular-devkit/build-angular": "~0.13.0",
-    "@angular/cli": "~7.3.10",
-    "@angular/compiler-cli": "~7.2.0",
-    "@angular/language-service": "~7.2.0",
-    "@types/node": "~8.9.4",
-    "ts-node": "~7.0.0",
-    "tslint": "~5.11.0",
-    "typescript": "~3.2.2"
-  }
-}
diff --git a/demos/angular2/versions/package.json-ng8 b/demos/angular2/versions/package.json-ng8
deleted file mode 100644
index 5643841..0000000
--- a/demos/angular2/versions/package.json-ng8
+++ /dev/null
@@ -1,39 +0,0 @@
-{
-  "name": "angular8",
-  "version": "0.0.0",
-  "license": "MIT",
-  "scripts": {
-    "ng": "ng",
-    "start": "ng serve",
-    "build": "ng build"
-  },
-  "private": true,
-  "dependencies": {
-    "@angular/animations": "~8.2.14",
-    "@angular/common": "~8.2.14",
-    "@angular/compiler": "~8.2.14",
-
-    "@angular/core": "~8.2.14",
-    "@angular/forms": "~8.2.14",
-
-    "@angular/platform-browser": "~8.2.14",
-    "@angular/platform-browser-dynamic": "~8.2.14",
-
-    "@angular/router": "~8.2.14",
-
-
-    "rxjs": "~6.4.0",
-    "tslib": "^1.10.0",
-    "zone.js": "~0.9.1"
-  },
-  "devDependencies": {
-    "@angular-devkit/build-angular": "~0.803.29",
-    "@angular/cli": "~8.3.29",
-    "@angular/compiler-cli": "~8.2.14",
-    "@angular/language-service": "~8.2.14",
-    "@types/node": "~8.9.4",
-    "ts-node": "~7.0.0",
-    "tslint": "~5.15.0",
-    "typescript": "~3.5.3"
-  }
-}
diff --git a/demos/angular2/versions/package.json-ng9 b/demos/angular2/versions/package.json-ng9
deleted file mode 100644
index fe6c382..0000000
--- a/demos/angular2/versions/package.json-ng9
+++ /dev/null
@@ -1,39 +0,0 @@
-{
-  "name": "angular9",
-  "version": "0.0.0",
-  "license": "MIT",
-  "scripts": {
-    "ng": "ng",
-    "start": "ng serve",
-    "build": "ng build"
-  },
-  "private": true,
-  "dependencies": {
-    "@angular/animations": "~9.1.13",
-    "@angular/common": "~9.1.13",
-    "@angular/compiler": "~9.1.13",
-
-    "@angular/core": "~9.1.13",
-    "@angular/forms": "~9.1.13",
-
-    "@angular/platform-browser": "~9.1.13",
-    "@angular/platform-browser-dynamic": "~9.1.13",
-
-    "@angular/router": "~9.1.13",
-
-
-    "rxjs": "~6.5.4",
-    "tslib": "^1.10.0",
-    "zone.js": "~0.10.2"
-  },
-  "devDependencies": {
-    "@angular-devkit/build-angular": "~0.901.15",
-    "@angular/cli": "~9.1.15",
-    "@angular/compiler-cli": "~9.1.13",
-
-    "@types/node": "^12.11.1",
-    "ts-node": "~8.3.0",
-    "tslint": "~6.1.0",
-    "typescript": "~3.8.3"
-  }
-}
diff --git a/demos/angular2/versions/polyfills.ts-ng10 b/demos/angular2/versions/polyfills.ts-ng10
deleted file mode 100644
index 741c886..0000000
--- a/demos/angular2/versions/polyfills.ts-ng10
+++ /dev/null
@@ -1 +0,0 @@
-import 'zone.js/dist/zone';
diff --git a/demos/angular2/versions/polyfills.ts-ng11 b/demos/angular2/versions/polyfills.ts-ng11
deleted file mode 100644
index 741c886..0000000
--- a/demos/angular2/versions/polyfills.ts-ng11
+++ /dev/null
@@ -1 +0,0 @@
-import 'zone.js/dist/zone';
diff --git a/demos/angular2/versions/polyfills.ts-ng12 b/demos/angular2/versions/polyfills.ts-ng12
deleted file mode 100644
index aa09a9f..0000000
--- a/demos/angular2/versions/polyfills.ts-ng12
+++ /dev/null
@@ -1 +0,0 @@
-import 'zone.js';
diff --git a/demos/angular2/versions/polyfills.ts-ng13 b/demos/angular2/versions/polyfills.ts-ng13
deleted file mode 100644
index aa09a9f..0000000
--- a/demos/angular2/versions/polyfills.ts-ng13
+++ /dev/null
@@ -1 +0,0 @@
-import 'zone.js';
diff --git a/demos/angular2/versions/polyfills.ts-ng2 b/demos/angular2/versions/polyfills.ts-ng2
deleted file mode 100644
index 2143ebf..0000000
--- a/demos/angular2/versions/polyfills.ts-ng2
+++ /dev/null
@@ -1,3 +0,0 @@
-import 'core-js/es6/reflect';
-import 'core-js/es7/reflect';
-import 'zone.js/dist/zone';
diff --git a/demos/angular2/versions/polyfills.ts-ng4 b/demos/angular2/versions/polyfills.ts-ng4
deleted file mode 100644
index 2143ebf..0000000
--- a/demos/angular2/versions/polyfills.ts-ng4
+++ /dev/null
@@ -1,3 +0,0 @@
-import 'core-js/es6/reflect';
-import 'core-js/es7/reflect';
-import 'zone.js/dist/zone';
diff --git a/demos/angular2/versions/polyfills.ts-ng5 b/demos/angular2/versions/polyfills.ts-ng5
deleted file mode 100644
index 2143ebf..0000000
--- a/demos/angular2/versions/polyfills.ts-ng5
+++ /dev/null
@@ -1,3 +0,0 @@
-import 'core-js/es6/reflect';
-import 'core-js/es7/reflect';
-import 'zone.js/dist/zone';
diff --git a/demos/angular2/versions/polyfills.ts-ng6 b/demos/angular2/versions/polyfills.ts-ng6
deleted file mode 100644
index 2143ebf..0000000
--- a/demos/angular2/versions/polyfills.ts-ng6
+++ /dev/null
@@ -1,3 +0,0 @@
-import 'core-js/es6/reflect';
-import 'core-js/es7/reflect';
-import 'zone.js/dist/zone';
diff --git a/demos/angular2/versions/polyfills.ts-ng7 b/demos/angular2/versions/polyfills.ts-ng7
deleted file mode 100644
index 2143ebf..0000000
--- a/demos/angular2/versions/polyfills.ts-ng7
+++ /dev/null
@@ -1,3 +0,0 @@
-import 'core-js/es6/reflect';
-import 'core-js/es7/reflect';
-import 'zone.js/dist/zone';
diff --git a/demos/angular2/versions/polyfills.ts-ng8 b/demos/angular2/versions/polyfills.ts-ng8
deleted file mode 100644
index 741c886..0000000
--- a/demos/angular2/versions/polyfills.ts-ng8
+++ /dev/null
@@ -1 +0,0 @@
-import 'zone.js/dist/zone';
diff --git a/demos/angular2/versions/polyfills.ts-ng9 b/demos/angular2/versions/polyfills.ts-ng9
deleted file mode 100644
index 741c886..0000000
--- a/demos/angular2/versions/polyfills.ts-ng9
+++ /dev/null
@@ -1 +0,0 @@
-import 'zone.js/dist/zone';
diff --git a/demos/angular2/versions/tsconfig.app.json-ng10 b/demos/angular2/versions/tsconfig.app.json-ng10
deleted file mode 100644
index f758d98..0000000
--- a/demos/angular2/versions/tsconfig.app.json-ng10
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-  "extends": "./tsconfig.json",
-  "compilerOptions": {
-    "outDir": "./out-tsc/app",
-    "types": []
-  },
-  "files": [
-    "src/main.ts",
-    "src/polyfills.ts"
-  ],
-  "include": [
-    "src/**/*.d.ts"
-  ]
-}
diff --git a/demos/angular2/versions/tsconfig.app.json-ng11 b/demos/angular2/versions/tsconfig.app.json-ng11
deleted file mode 100644
index f758d98..0000000
--- a/demos/angular2/versions/tsconfig.app.json-ng11
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-  "extends": "./tsconfig.json",
-  "compilerOptions": {
-    "outDir": "./out-tsc/app",
-    "types": []
-  },
-  "files": [
-    "src/main.ts",
-    "src/polyfills.ts"
-  ],
-  "include": [
-    "src/**/*.d.ts"
-  ]
-}
diff --git a/demos/angular2/versions/tsconfig.app.json-ng12 b/demos/angular2/versions/tsconfig.app.json-ng12
deleted file mode 100644
index f758d98..0000000
--- a/demos/angular2/versions/tsconfig.app.json-ng12
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-  "extends": "./tsconfig.json",
-  "compilerOptions": {
-    "outDir": "./out-tsc/app",
-    "types": []
-  },
-  "files": [
-    "src/main.ts",
-    "src/polyfills.ts"
-  ],
-  "include": [
-    "src/**/*.d.ts"
-  ]
-}
diff --git a/demos/angular2/versions/tsconfig.app.json-ng13 b/demos/angular2/versions/tsconfig.app.json-ng13
deleted file mode 100644
index f758d98..0000000
--- a/demos/angular2/versions/tsconfig.app.json-ng13
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-  "extends": "./tsconfig.json",
-  "compilerOptions": {
-    "outDir": "./out-tsc/app",
-    "types": []
-  },
-  "files": [
-    "src/main.ts",
-    "src/polyfills.ts"
-  ],
-  "include": [
-    "src/**/*.d.ts"
-  ]
-}
diff --git a/demos/angular2/versions/tsconfig.app.json-ng8 b/demos/angular2/versions/tsconfig.app.json-ng8
deleted file mode 100644
index 565a11a..0000000
--- a/demos/angular2/versions/tsconfig.app.json-ng8
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-  "extends": "./tsconfig.json",
-  "compilerOptions": {
-    "outDir": "./out-tsc/app",
-    "types": []
-  },
-  "files": [
-    "src/main.ts",
-    "src/polyfills.ts"
-  ],
-  "include": [
-    "src/**/*.ts"
-  ],
-  "exclude": [
-    "src/test.ts",
-    "src/**/*.spec.ts"
-  ]
-}
diff --git a/demos/angular2/versions/tsconfig.app.json-ng9 b/demos/angular2/versions/tsconfig.app.json-ng9
deleted file mode 100644
index f758d98..0000000
--- a/demos/angular2/versions/tsconfig.app.json-ng9
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-  "extends": "./tsconfig.json",
-  "compilerOptions": {
-    "outDir": "./out-tsc/app",
-    "types": []
-  },
-  "files": [
-    "src/main.ts",
-    "src/polyfills.ts"
-  ],
-  "include": [
-    "src/**/*.d.ts"
-  ]
-}
diff --git a/demos/function/.eslintrc b/demos/function/.eslintrc
deleted file mode 100644
index dbf6551..0000000
--- a/demos/function/.eslintrc
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-	"env": { "shared-node-browser":true },
-	"parserOptions": {
-		"ecmaVersion": 8
-	},
-	"plugins": [ "html", "json" ]
-}
diff --git a/demos/function/AzureHTTPTrigger/function.json b/demos/function/AzureHTTPTrigger/function.json
deleted file mode 100644
index 7c64ea6..0000000
--- a/demos/function/AzureHTTPTrigger/function.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-  "disabled": false,
-  "bindings": [
-    {
-      "authLevel": "function",
-      "type": "httpTrigger",
-      "direction": "in",
-      "dataType": "binary",
-      "name": "req"
-    },
-    {
-      "type": "http",
-      "direction": "out",
-      "name": "res"
-    }
-  ]
-}
diff --git a/demos/function/AzureHTTPTrigger/index.js b/demos/function/AzureHTTPTrigger/index.js
deleted file mode 100644
index c39d77c..0000000
--- a/demos/function/AzureHTTPTrigger/index.js
+++ /dev/null
@@ -1,44 +0,0 @@
-/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
-/* eslint-env node */
-// base64 sheetjs.xlsb | curl -F "data=@-;filename=test.xlsb" http://localhost:7262/api/AzureHTTPTrigger
-
-const XLSX = require('xlsx');
-const formidable = require('formidable');
-const Readable = require('stream').Readable;
-var fs = require('fs');
-
-/* formidable expects the request object to be a stream */
-const streamify = (req) => {
-	if(typeof req.on !== 'undefined') return req;
-	const s = new Readable();
-	s._read = ()=>{};
-	s.push(new Buffer(req.body));
-	s.push(null);
-	Object.assign(s, req);
-	return s;
-};
-
-module.exports = (context, req) => {
-	const form = new formidable.IncomingForm();
-	form.parse(streamify(req), (err, fields, files) => {
-		/* grab the first file */
-		var f = Object.values(files)[0];
-		if(!f) {
-			context.res = { status: 400, body: "Must submit a file for processing!" };
-		} else {
-			/* file is stored in a temp directory, so we can point to that and read it */
-			const wb = XLSX.read(f.path, {type:"file"});
-
-			/* convert to specified output type -- default CSV */
-			const ext = (fields.bookType || "csv").toLowerCase();
-			const out = XLSX.write(wb, {type:"string", bookType:ext});
-
-			context.res = {
-				status: 200,
-				headers: { "Content-Disposition": `attachment; filename="download.${ext}";` },
-				body: out
-			};
-		}
-		context.done();
-	});
-};
diff --git a/demos/function/Firebase/.gitignore b/demos/function/Firebase/.gitignore
deleted file mode 100644
index f9ed3da..0000000
--- a/demos/function/Firebase/.gitignore
+++ /dev/null
@@ -1,65 +0,0 @@
-# Logs
-logs
-*.log
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-firebase-debug.log*
-
-# Firebase cache
-.firebase/
-
-# Firebase config
-
-# Uncomment this if you'd like others to create their own Firebase project.
-# For a team working on the same Firebase project(s), it is recommended to leave
-# it commented so all members can deploy to the same project(s) in .firebaserc.
-.firebaserc
-
-# Runtime data
-pids
-*.pid
-*.seed
-*.pid.lock
-
-# Directory for instrumented libs generated by jscoverage/JSCover
-lib-cov
-
-# Coverage directory used by tools like istanbul
-coverage
-
-# nyc test coverage
-.nyc_output
-
-# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
-.grunt
-
-# Bower dependency directory (https://bower.io/)
-bower_components
-
-# node-waf configuration
-.lock-wscript
-
-# Compiled binary addons (http://nodejs.org/api/addons.html)
-build/Release
-
-# Dependency directories
-node_modules/
-
-# Optional npm cache directory
-.npm
-
-# Optional eslint cache
-.eslintcache
-
-# Optional REPL history
-.node_repl_history
-
-# Output of 'npm pack'
-*.tgz
-
-# Yarn Integrity file
-.yarn-integrity
-
-# dotenv environment variables file
-.env
diff --git a/demos/function/Firebase/firebase.json b/demos/function/Firebase/firebase.json
deleted file mode 100644
index 0967ef4..0000000
--- a/demos/function/Firebase/firebase.json
+++ /dev/null
@@ -1 +0,0 @@
-{}
diff --git a/demos/function/Firebase/functions/.gitignore b/demos/function/Firebase/functions/.gitignore
deleted file mode 100644
index 40b878d..0000000
--- a/demos/function/Firebase/functions/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-node_modules/
\ No newline at end of file
diff --git a/demos/function/Firebase/functions/index.js b/demos/function/Firebase/functions/index.js
deleted file mode 100644
index d14b499..0000000
--- a/demos/function/Firebase/functions/index.js
+++ /dev/null
@@ -1,39 +0,0 @@
-const functions = require('firebase-functions');
-const Busboy = require('busboy');
-const XLSX = require('xlsx');
-
-// // Create and Deploy Your First Cloud Functions
-// // https://firebase.google.com/docs/functions/write-firebase-functions
-//
-exports.helloWorld = functions.https.onRequest((request, response) => {
- response.send("Hello from Firebase!");
-});
-
-exports.main = functions.https.onRequest((req, res) => {
-  var bb = new Busboy({
-    headers: {
-      'content-type': req.headers['content-type']
-    }
-  });
-  let fields = {};
-  let files = {};
-  bb.on('field', (fieldname, val) => {
-    fields[fieldname] = val;
-  });
-  bb.on('file', (fieldname, file, filename) => {
-    var buffers = [];
-    file.on('data', (data) => {
-      buffers.push(data);
-    });
-    file.on('end', () => {
-      files[fieldname] = [Buffer.concat(buffers), filename];
-    });
-  });
-  bb.on('finish', () => {
-    let f = files[Object.keys(files)[0]];
-    const wb = XLSX.read(f[0], { type: "buffer" });
-    // Convert to CSV
-    res.send(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]));
-  });
-  bb.end(req.body)
-});
diff --git a/demos/function/Firebase/functions/package.json b/demos/function/Firebase/functions/package.json
deleted file mode 100644
index 53238b4..0000000
--- a/demos/function/Firebase/functions/package.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
-  "name": "functions",
-  "description": "Cloud Functions for Firebase",
-  "scripts": {
-    "serve": "firebase emulators:start --only functions",
-    "shell": "firebase functions:shell",
-    "start": "npm run shell",
-    "deploy": "firebase deploy --only functions",
-    "logs": "firebase functions:log"
-  },
-  "engines": {
-    "node": "8"
-  },
-  "dependencies": {
-    "busboy": "^0.3.1",
-    "firebase-admin": "^8.6.0",
-    "firebase-functions": "^3.3.0",
-    "xlsx": "^0.16.2"
-  },
-  "devDependencies": {
-    "firebase-functions-test": "^0.1.6"
-  },
-  "private": true
-}
diff --git a/demos/function/LambdaProxy/index.js b/demos/function/LambdaProxy/index.js
deleted file mode 100644
index 5d82404..0000000
--- a/demos/function/LambdaProxy/index.js
+++ /dev/null
@@ -1,40 +0,0 @@
-/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
-/* eslint-env node */
-// base64 sheetjs.xlsb | curl -F "data=@-;filename=test.xlsb" http://localhost:3000/LambdaProxy
-
-'use strict';
-var XLSX = require('xlsx');
-var Busboy = require('busboy');
-
-exports.handler = function(event, context, callback) {
-	/* set up busboy */
-	var ctype = event.headers['Content-Type']||event.headers['content-type'];
-	var bb = new Busboy({headers:{'content-type':ctype}});
-
-	/* busboy is evented; accumulate the fields and files manually */
-	var fields = {}, files = {};
-	bb.on('error', function(err) { console.log('err', err); callback(err); });
-	bb.on('field', function(fieldname, val) {fields[fieldname] = val });
-	bb.on('file', function(fieldname, file, filename) {
-		/* concatenate the individual data buffers */
-		var buffers = [];
-		file.on('data', function(data) { buffers.push(data); });
-		file.on('end', function() { files[fieldname] = [Buffer.concat(buffers), filename]; });
-	});
-
-	/* on the finish event, all of the fields and files are ready */
-	bb.on('finish', function() {
-		/* grab the first file */
-		var f = files[Object.keys(files)[0]];
-		if(!f) callback(new Error("Must submit a file for processing!"));
-
-		/* f[0] is a buffer, convert to string and interpret as Base64 */
-		var wb = XLSX.read(f[0].toString(), {type:"base64"});
-
-		/* grab first worksheet and convert to CSV */
-		var ws = wb.Sheets[wb.SheetNames[0]];
-		callback(null, { body: XLSX.utils.sheet_to_csv(ws) });
-	});
-
-	bb.end(event.body);
-};
diff --git a/demos/function/LambdaProxy/template.yaml b/demos/function/LambdaProxy/template.yaml
deleted file mode 100644
index 43ef45a..0000000
--- a/demos/function/LambdaProxy/template.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-AWSTemplateFormatVersion : '2010-09-09'
-Transform: AWS::Serverless-2016-10-31
-
-Description: Sample Lambda API Gateway Normalizer
-Resources:
-  LambdaProxy:
-    Type: AWS::Serverless::Function
-    Properties:
-      Runtime: nodejs6.10
-      Handler: index.handler
-      BinaryMediaTypes: '*/*'
-      Events:
-        Api:
-          Type: Api
-          Properties:
-            Path: /LambdaProxy
-            Method: any
-            BinaryMediaTypes: '*/*'
diff --git a/demos/function/Makefile b/demos/function/Makefile
deleted file mode 100644
index 1588319..0000000
--- a/demos/function/Makefile
+++ /dev/null
@@ -1,28 +0,0 @@
-.PHONY: aws
-aws: lambda-proxy
-
-.PHONY: lambda-proxy
-lambda-proxy:
-	cd LambdaProxy; mkdir -p node_modules; npm install https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz busboy; sam local start-api; cd -
-
-.PHONY: init-azure
-init-azure:
-	cd AzureHTTPTrigger; mkdir -p node_modules; npm install https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz formidable fs
-
-.PHONY: azure
-azure: init-azure
-	func start
-
-.PHONY: azure-server
-azure-server:
-	mkdir -p /tmp/azurite
-	azurite -l /tmp/azurite
-
-FILES=$(filter-out xlsx.full.min.js,$(wildcard *.js)) $(wildcard *.html)
-.PHONY: lint
-lint: $(FILES)
-	eslint $(FILES)
-
-.PHONY: clean
-clean:
-	rm -f *.db *.xlsx *.csv
diff --git a/demos/function/README.md b/demos/function/README.md
index c5cd76a..238afbc 100644
--- a/demos/function/README.md
+++ b/demos/function/README.md
@@ -1,113 +1,9 @@
 # "Serverless" Functions
 
-Because the library is pure JS, the hard work of reading and writing files can
-be performed in the client browser or on the server side.  On the server side,
-the mechanical process is essentially independent from the data parsing or
-generation.  As a result, it is sometimes sensible to organize applications so
-that the "last mile" conversion between JSON data and spreadsheet files is
-independent from the main application.
+Cloud services are covered in separate demos:
 
-The straightforward architecture would split off the JSON data conversion as a
-separate microservice or application.  Since it is only needed when an import or
-export is requested, and since the process itself is relatively independent from
-the rest of a typical service, a "Serverless" architecture makes a great fit.
-Since the "function" is separate from the rest of the application, it can be
-integrated into a platform built in Java or Go or Python or another language!
+- [AWS](https://docs.sheetjs.com/docs/demos/aws)
+- [Azure](https://docs.sheetjs.com/docs/demos/azure)
 
-This demo discusses general architectures and provides examples for popular
-commercial systems and self-hosted alternatives.  The examples are merely
-intended to demonstrate very basic functionality.
+[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)
 
-
-## Simple Strategies
-
-#### Data Normalization
-
-Most programming languages and platforms can process CSV or JSON but can't use
-XLS or XLSX or XLSB directly.  Form data from an HTTP POST request can be parsed
-and contained files can be converted to CSV or JSON.  The `XLSX.stream.to_csv`
-utility can stream rows to a standard HTTP response.  `XLSX.utils.sheet_to_json`
-can generate an array of objects that can be fed to another service.
-
-At the simplest level, a file on the filesystem can be converted using the bin
-script that ships with the NodeJS package:
-
-```bash
-$ xlsx /path/to/uploads/file > /tmp/new_csv_file
-```
-
-From a utility script, workbooks can be converted in two lines:
-
-```js
-var workbook = XLSX.readFile("path/to/file.xlsb");
-XLSX.writeFile(workbook, "output/path/file.csv");
-```
-
-#### Report Generation
-
-For an existing platform that already generates JSON or CSV or HTML output, the
-library can process the data and generate a new file with embellishments. The
-`XLSX.utils.sheet_add_json` and `XLSX.utils.sheet_add_aoa` functions can add
-data rows to an existing worksheet:
-
-```js
-var ws = XLSX.utils.aoa_to_sheet([
-	["Company Report"],
-	[],
-	["Item", "Cost"]
-]);
-XLSX.utils.sheet_add_json(ws, [
-	{ item: "Coffee", cost: 5 },
-	{ item: "Cake", cost: 20 }
-], { skipHeader: true, origin: -1, header: ["item", "cost"] });
-```
-
-
-## Deployment Targets
-
-The library is supported in Node versions starting from `0.8` as well as a
-myriad of ES3 and ES5 compatible JS engines.  All major services use Node
-versions beyond major release 4, so there should be no problem directly using
-the library in those environments.
-
-Note that most cloud providers proactively convert form data to UTF8 strings.
-This is especially problematic when dealing with XLSX and XLSB files, as they
-naturally contain codes that are not valid UTF8 characters.  As a result, these
-demos specifically handle Base64-encoded files only.  To test on the command
-line, use the `base64` tool to encode data before piping to `curl`:
-
-```
-base64 test.xlsb | curl -F "data=@-;filename=test.xlsb" http://localhost/
-```
-
-#### AWS Lambda
-
-Through the AWS Gateway API, Lambda functions can be triggered on HTTP requests.
-The `LambdaProxy` example reads files from form data and converts to CSV.
-
-When deploying on AWS, be sure to `npm install` locally and include the modules
-in the ZIP file.
-
-When reading form data, be sure to include the necessary binary types on the AWS API Gateway console.
-To do this, navigate to the "Binary Media Types" section in the settings tab of the console.
-For reading a file, you may need to add `"multipart/form-data"`.
-For downloading a file, you may need to add `"application/vnd.ms-excel"`.
-
-#### Azure Functions
-
-Azure supports many types of triggers.  The `AzureHTTPTrigger` shows an example
-HTTP trigger that converts the submitted file to CSV.
-
-When deploying on Azure, be sure to install the module from the remote console,
-as described in the "Azure Functions JavaScript developer guide".
-
-#### Firebase Functions
-
-Firebase functions can be triggered via HTTP requests, similar to a REST API.
-In the `Firebase` directory, the example function reads files sent through
-HTTP and converts it to a CSV and sends the response in the form of a string.
-
-To run this demo locally, run `npm i -g firebase-tools` to install the
-Firebase CLI and `npm i` to install the dependencies, then `firebase use --add`
-to connect to an existing Firebase project. Run `firebase emulators:start` to
-start the local server.
diff --git a/demos/function/host.json b/demos/function/host.json
deleted file mode 100644
index 81e35b7..0000000
--- a/demos/function/host.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  "version": "2.0"
-}
\ No newline at end of file
diff --git a/demos/function/local.settings.json b/demos/function/local.settings.json
deleted file mode 100644
index 755966e..0000000
--- a/demos/function/local.settings.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-  "IsEncrypted": false,
-  "Values": {
-    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
-    "AzureWebJobsDashboard": "UseDevelopmentStorage=true"
-  },
-  "Host": {
-    "LocalHttpPort": 7262,
-    "CORS": "*"
-  }
-}
diff --git a/demos/react/.gitignore b/demos/react/.gitignore
deleted file mode 100644
index 228ee28..0000000
--- a/demos/react/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-SheetJS
-.next
-static/shim.js
-public/shim.js
diff --git a/demos/react/Makefile b/demos/react/Makefile
deleted file mode 100644
index da556c3..0000000
--- a/demos/react/Makefile
+++ /dev/null
@@ -1,24 +0,0 @@
-.PHONY: react
-react: init ## Simple server for react and clones
-	python -mSimpleHTTPServer
-
-.PHONY: next
-next: init ## next.js demo
-	next
-
-.PHONY: native
-native: ## Build react-native project
-	bash ./native.sh
-
-.PHONY: ios
-ios: native ## react-native ios sim
-	cd SheetJS; cd ios; pod install; cd -; react-native run-ios --simulator="iPhone X"; cd -
-
-.PHONY: android
-android: native ## react-native android sim
-	cd SheetJS; react-native run-android; cd -
-
-.PHONY: init
-init: ## set up node_modules and symlink
-	mkdir -p node_modules
-	cd node_modules; if [ ! -e xlsx ]; then ln -s ../../../ xlsx; fi; cd -
diff --git a/demos/react/NOTES.md b/demos/react/NOTES.md
deleted file mode 100644
index ca6238e..0000000
--- a/demos/react/NOTES.md
+++ /dev/null
@@ -1,22 +0,0 @@
-# Additional Notes
-
-## Java, React Native, Gradle versions
-
-This demo was tested and runs with React Native 0.62.2, Java 11, and Gradle
-3.5.2. Running `make native` will invoke `native.sh`, which uses a fixed version
-of React Native 0.62.2 to build and run the demo.
-
-Make sure you have the correct version of Java (11) installed, since 0.62.2 might
-not work with newer versions of Java.
-
-## Common Issues
-
-```
-ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-```
-
-Add `export JAVA_HOME=<directory>`, replacing `<directory>` with the location of
-your Java install, to your `.bashrc` or any other shell that you are using.
-
-
-
diff --git a/demos/react/README.md b/demos/react/README.md
index ffee578..428f391 100644
--- a/demos/react/README.md
+++ b/demos/react/README.md
@@ -1,154 +1,12 @@
 # React
 
-The `xlsx.core.min.js` and `xlsx.full.min.js` scripts are designed to be dropped
-into web pages with script tags:
+[The new demo](https://docs.sheetjs.com/docs/demos/react) has an updated
+exposition for legacy and modern deployments alike.
 
-```html
-<script src="xlsx.full.min.js"></script>
-```
+The ecosystem demos were grouped by type in the new demo site:
 
-The library can also be imported directly from JSX code with:
-
-```js
-import { read, utils, writeFileXLSX } from 'xlsx';
-```
-
-This demo shows a simple React component transpiled in the browser using Babel
-standalone library.  Since there is no standard React table model, this demo
-settles on the array of arrays approach.
-
-
-Other scripts in this demo show:
-- server-rendered React component (with `next.js`)
-- `react-native` deployment for iOS and android
-- [`react-data-grid` reading, modifying, and writing files](modify/)
-
-## How to run
-
-Run `make react` to run the browser demo for React, or run `make next` to run
-the server-rendered demo using `next.js`.
-
-## Internal State
-
-The simplest state representation is an array of arrays.  To avoid having the
-table component depend on the library, the column labels are precomputed.  The
-state in this demo is shaped like the following object:
-
-```js
-{
-  cols: [{ name: "A", key: 0 }, { name: "B", key: 1 }, { name: "C", key: 2 }],
-  data: [
-    [ "id",    "name", "value" ],
-    [    1, "sheetjs",    7262 ],
-    [    2, "js-xlsx",    6969 ]
-  ]
-}
-```
-
-`sheet_to_json` and `aoa_to_sheet` utility functions can convert between arrays
-of arrays and worksheets:
-
-```js
-/* convert from workbook to array of arrays */
-var first_worksheet = workbook.Sheets[workbook.SheetNames[0]];
-var data = XLSX.utils.sheet_to_json(first_worksheet, {header:1});
-
-/* convert from array of arrays to workbook */
-var worksheet = XLSX.utils.aoa_to_sheet(data);
-var new_workbook = XLSX.utils.book_new();
-XLSX.utils.book_append_sheet(new_workbook, worksheet, "SheetJS");
-```
-
-The column objects can be generated with the `encode_col` utility function:
-
-```js
-function make_cols(refstr/*:string*/) {
-  var o = [];
-  var range = XLSX.utils.decode_range(refstr);
-  for(var i = 0; i <= range.e.c; ++i) {
-    o.push({name: XLSX.utils.encode_col(i), key:i});
-  }
-  return o;
-}
-```
-
-## React Native
-
-[The new demo](https://docs.sheetjs.com/docs/demos/mobile#react-native) uses
-up-to-date file I/O and file picker libraries.
-
-## Server-Rendered React Components with Next.js
-
-The demo reads from `public/sheetjs.xlsx`.  HTML output is generated using
-`XLSX.utils.sheet_to_html` and inserted with `dangerouslySetInnerHTML`:
-
-```jsx
-export default function Index({html, type}) { return (
-  // ...
-  <div dangerouslySetInnerHTML={{ __html: html }} />
-  // ...
-); }
-```
-
-Next currently offers 3 general strategies for server-side data fetching:
-
-#### "Server-Side Rendering" using `getServerSideProps`
-
-`/getServerSideProps` reads the file on each request.  The first worksheet is
-converted to HTML:
-
-```js
-export async function getServerSideProps() {
-  const wb = XLSX.readFile(path);
-  return { props: {
-    html: utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]])
-  }};
-}
-```
-
-#### "Static Site Generation" using `getStaticProps`
-
-`/getServerSideProps` reads the file at build time.  The first worksheet is
-converted to HTML:
-
-```js
-export async function getStaticProps() {
-  const wb = XLSX.readFile(path);
-  return { props: {
-    html: utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]])
-  }};
-}
-```
-
-#### "Static Site Generation with Dynamic Routes" using `getStaticPaths`
-
-`/getStaticPaths` reads the file at build time and generates a list of sheets.
-
-`/sheets/[id]` uses `getStaticPaths` to generate a path per sheet index:
-
-```js
-export async function getStaticPaths() {
-  const wb = XLSX.readFile(path);
-  return {
-    paths: wb.SheetNames.map((name, idx) => ({ params: { id: idx.toString()  } })),
-    fallback: false
-  };
-}
-```
-
-It also uses `getStaticProps` for the actual HTML generation:
-
-```js
-export async function getStaticProps(ctx) {
-  const wb = XLSX.readFile(path);
-  return { props: {
-    html: utils.sheet_to_html(wb.Sheets[wb.SheetNames[ctx.params.id]]),
-  }};
-}
-```
-
-## Additional Notes
-
-Some additional notes can be found in [`NOTES.md`](NOTES.md).
+- [server-rendered React components with `next.js`](https://docs.sheetjs.com/docs/demos/content#nextjs) is now part of "Content and Site Generation"
+- [`react-native` deployment for iOS and android](https://docs.sheetjs.com/docs/demos/mobile#react-native) is now part of "iOS and Android Apps"
+- [`react-data-grid` reading, modifying, and writing files](https://docs.sheetjs.com/docs/demo/grid#react-data-grid) is now part of "Data Grids and UI"
 
 [![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)
diff --git a/demos/react/index.html b/demos/react/index.html
deleted file mode 100644
index 8487db4..0000000
--- a/demos/react/index.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE html>
-<!-- xlsx.js (C) 2013-present  SheetJS http://sheetjs.com -->
-<!-- vim: set ts=2: -->
-<html lang="en" style="height: 100%">
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<title>SheetJS React Demo</title>
-<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
-<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
-<script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
-<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
-<script src="node_modules/xlsx/dist/shim.min.js"></script>
-<script src="node_modules/xlsx/dist/xlsx.full.min.js"></script>
-<style>body, #app { height: 100%; };</style>
-</head>
-<body>
-<div class="container-fluid">
-<h1><a href="http://sheetjs.com">SheetJS React Demo</a></h1>
-<br />
-<a href="https://github.com/SheetJS/js-xlsx">Source Code Repo</a><br />
-<a href="https://github.com/SheetJS/js-xlsx/issues">Issues?  Something look weird?  Click here and report an issue</a><br /><br />
-</div>
-<div id="app" class="container-fluid"></div>
-<script type="text/babel" src="sheetjs.js"></script>
-<script type="text/babel">
-	ReactDOM.render( <SheetJSApp />, document.getElementById('app') );
-</script>
-</body>
-</html>
diff --git a/demos/react/modify/.gitignore b/demos/react/modify/.gitignore
deleted file mode 100644
index 4d29575..0000000
--- a/demos/react/modify/.gitignore
+++ /dev/null
@@ -1,23 +0,0 @@
-# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
-
-# dependencies
-/node_modules
-/.pnp
-.pnp.js
-
-# testing
-/coverage
-
-# production
-/build
-
-# misc
-.DS_Store
-.env.local
-.env.development.local
-.env.test.local
-.env.production.local
-
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
diff --git a/demos/react/modify/README.md b/demos/react/modify/README.md
deleted file mode 100644
index 97180e0..0000000
--- a/demos/react/modify/README.md
+++ /dev/null
@@ -1,10 +0,0 @@
-# react-modify
-
-This demo shows import and export with the `react-data-grid` table component.
-
-In the project directory, you can run:
-
-```bash
-$ npm install
-$ npm start
-```
diff --git a/demos/react/modify/package.json b/demos/react/modify/package.json
deleted file mode 100644
index dde42e3..0000000
--- a/demos/react/modify/package.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
-  "name": "react-modify-demo",
-  "dependencies": {
-    "@types/react": "^17.0.0",
-    "@types/react-dom": "^17.0.0",
-    "react": "^17.0.2",
-    "react-data-grid": "^7.0.0-beta.11",
-    "react-dom": "^17.0.2",
-    "react-scripts": "4.0.3",
-    "typescript": "^4.1.2",
-    "xlsx": "https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz"
-  },
-  "scripts": {
-    "start": "react-scripts start",
-    "build": "react-scripts build",
-    "eject": "react-scripts eject"
-  },
-  "eslintConfig": {
-    "extends": [
-      "react-app",
-      "react-app/jest"
-    ]
-  },
-  "browserslist": {
-    "production": [
-      ">0.2%",
-      "not dead",
-      "not op_mini all"
-    ],
-    "development": [
-      "last 1 chrome version",
-      "last 1 firefox version",
-      "last 1 safari version"
-    ]
-  }
-}
diff --git a/demos/react/modify/public/index.html b/demos/react/modify/public/index.html
deleted file mode 100644
index aa069f2..0000000
--- a/demos/react/modify/public/index.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-  <head>
-    <meta charset="utf-8" />
-    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
-    <meta name="viewport" content="width=device-width, initial-scale=1" />
-    <meta name="theme-color" content="#000000" />
-    <meta
-      name="description"
-      content="Web site created using create-react-app"
-    />
-    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
-    <!--
-      manifest.json provides metadata used when your web app is installed on a
-      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-    -->
-    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
-    <!--
-      Notice the use of %PUBLIC_URL% in the tags above.
-      It will be replaced with the URL of the `public` folder during the build.
-      Only files inside the `public` folder can be referenced from the HTML.
-
-      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
-      work correctly both with client-side routing and a non-root public URL.
-      Learn how to configure a non-root public URL by running `npm run build`.
-    -->
-    <title>React App</title>
-  </head>
-  <body>
-    <noscript>You need to enable JavaScript to run this app.</noscript>
-    <div id="root"></div>
-    <!--
-      This HTML file is a template.
-      If you open it directly in the browser, you will see an empty page.
-
-      You can add webfonts, meta tags, or analytics to this file.
-      The build step will place the bundled scripts into the <body> tag.
-
-      To begin the development, run `npm start` or `yarn start`.
-      To create a production bundle, use `npm run build` or `yarn build`.
-    -->
-  </body>
-</html>
diff --git a/demos/react/modify/src/components/App.tsx b/demos/react/modify/src/components/App.tsx
deleted file mode 100644
index 7e979d5..0000000
--- a/demos/react/modify/src/components/App.tsx
+++ /dev/null
@@ -1,107 +0,0 @@
-import React, { useState, ChangeEvent } from "react";
-import DataGrid, { TextEditor } from "react-data-grid";
-import { read, utils, WorkSheet, writeFile } from "xlsx";
-
-import "../styles/App.css";
-
-type Row = any[]; /*{
-  [index: string]: string | number;
-};*/
-
-type Column = {
-  key: string;
-  name: string;
-  editor: typeof TextEditor;
-};
-
-type DataSet = {
-  [index: string]: WorkSheet;
-};
-
-function getRowsCols(
-  data: DataSet,
-  sheetName: string
-): {
-  rows: Row[];
-  columns: Column[];
-} {
-  const rows: Row[] = utils.sheet_to_json(data[sheetName], {header:1});
-  let columns: Column[] = [];
-
-  for (let row of rows) {
-    const keys: string[] = Object.keys(row);
-
-    if (keys.length > columns.length) {
-      columns = keys.map((key) => {
-        return { key, name: utils.encode_col(+key), editor: TextEditor };
-      });
-    }
-  }
-
-  return { rows, columns };
-}
-
-export default function App() {
-  const [rows, setRows] = useState<Row[]>([]);
-  const [columns, setColumns] = useState<Column[]>([]);
-  const [workBook, setWorkBook] = useState<DataSet>({} as DataSet);
-  const [sheets, setSheets] = useState<string[]>([]);
-  const [current, setCurrent] = useState<string>("");
-
-  const exportTypes = ["xlsx", "xlsb", "csv", "html"];
-
-  function selectSheet(name: string, reset = true) {
-    if(reset) workBook[current] = utils.json_to_sheet(rows, {
-      header: columns.map((col: Column) => col.key),
-      skipHeader: true
-    });
-
-    const { rows: new_rows, columns: new_columns } = getRowsCols(workBook, name);
-
-    setRows(new_rows);
-    setColumns(new_columns);
-    setCurrent(name);
-  }
-
-  async function handleFile(ev: ChangeEvent<HTMLInputElement>): Promise<void> {
-    const file = await ev.target.files?.[0]?.arrayBuffer();
-    const data = read(file);
-
-    setWorkBook(data.Sheets);
-    setSheets(data.SheetNames);
-  }
-
-  function saveFile(ext: string): void {
-    const wb = utils.book_new();
-
-    sheets.forEach((n) => {
-      utils.book_append_sheet(wb, workBook[n], n);
-    });
-
-    writeFile(wb, "sheet." + ext);
-  }
-
-  return (
-    <>
-      <input type="file" onChange={handleFile} />
-      <div className="flex-cont">
-        {sheets.map((sheet) => (
-          <button key={sheet} onClick={(e) => selectSheet(sheet)}>
-            {sheet}
-          </button>
-        ))}
-      </div>
-      <div className="flex-cont">
-        <b>Current Sheet: {current}</b>
-      </div>
-      <DataGrid columns={columns} rows={rows} onRowsChange={setRows} />
-      <div className="flex-cont">
-        {exportTypes.map((ext) => (
-          <button key={ext} onClick={() => saveFile(ext)}>
-            export [.{ext}]
-          </button>
-        ))}
-      </div>
-    </>
-  );
-}
diff --git a/demos/react/modify/src/index.tsx b/demos/react/modify/src/index.tsx
deleted file mode 100644
index 270ed1a..0000000
--- a/demos/react/modify/src/index.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
-import App from './components/App';
-
-import './styles/index.css';
-
-ReactDOM.render(
-  <React.StrictMode>
-    <App/>
-  </React.StrictMode>,
-  document.getElementById('root')
-);
diff --git a/demos/react/modify/src/react-app-env.d.ts b/demos/react/modify/src/react-app-env.d.ts
deleted file mode 100644
index 6431bc5..0000000
--- a/demos/react/modify/src/react-app-env.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-/// <reference types="react-scripts" />
diff --git a/demos/react/modify/src/styles/App.css b/demos/react/modify/src/styles/App.css
deleted file mode 100644
index 28b9df9..0000000
--- a/demos/react/modify/src/styles/App.css
+++ /dev/null
@@ -1,14 +0,0 @@
-input {
-  margin: 0.5rem;
-}
-
-.flex-cont {
-  display: flex;
-  margin: 0.5rem;
-  justify-content: center;
-}
-
-.flex-cont button {
-    margin: 0.3rem;
-    padding: 0.2rem;
-}
diff --git a/demos/react/modify/src/styles/index.css b/demos/react/modify/src/styles/index.css
deleted file mode 100644
index 1532074..0000000
--- a/demos/react/modify/src/styles/index.css
+++ /dev/null
@@ -1,8 +0,0 @@
-body {
-  margin: 0;
-  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
-    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
-    sans-serif;
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-}
diff --git a/demos/react/modify/tsconfig.json b/demos/react/modify/tsconfig.json
deleted file mode 100644
index 5136b52..0000000
--- a/demos/react/modify/tsconfig.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
-  "compilerOptions": {
-    "target": "es5",
-    "lib": [
-      "dom",
-      "dom.iterable",
-      "esnext"
-    ],
-    "allowJs": true,
-    "skipLibCheck": true,
-    "esModuleInterop": true,
-    "allowSyntheticDefaultImports": true,
-    "forceConsistentCasingInFileNames": true,
-    "strict": true,
-    "noFallthroughCasesInSwitch": true,
-    "module": "esnext",
-    "moduleResolution": "node",
-    "resolveJsonModule": true,
-    "isolatedModules": true,
-    "noEmit": true,
-    "jsx": "react-jsx"
-  },
-  "include": [
-    "src"
-  ]
-}
diff --git a/demos/react/nexthdr.js b/demos/react/nexthdr.js
deleted file mode 100644
index 1ba3dc6..0000000
--- a/demos/react/nexthdr.js
+++ /dev/null
@@ -1,3 +0,0 @@
-/* xlsx.js (C) 2013-present  SheetJS -- http://sheetjs.com */
-import * as XLSX from 'xlsx';
-import React from 'react';
diff --git a/demos/react/pages/getServerSideProps.js b/demos/react/pages/getServerSideProps.js
deleted file mode 100644
index 55cd11f..0000000
--- a/demos/react/pages/getServerSideProps.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import Head from 'next/head';
-import { readFile, utils } from 'xlsx';
-import { join } from 'path';
-import { cwd } from 'process';
-
-export default function Index({html, type}) { return (
-<div>
-  <Head>
-    <meta httpEquiv="Content-Type" content="text/html; charset=UTF-8" />
-    <title>SheetJS Next.JS {type} Demo</title>
-    <script src="/shim.js"></script>
-    <style jsx>{`
-      body, #app { height: 100%; };
-    `}</style>
-  </Head>
-  <pre>
-<h3>SheetJS Next.JS {type} Demo</h3>
-This demo reads from /public/sheetjs.xlsx and generates HTML from the first sheet.
-  </pre>
-  <div dangerouslySetInnerHTML={{ __html: html }} />
-</div>
-); }
-
-export async function getServerSideProps() {
-  const wb = readFile(join(cwd(), "public", "sheetjs.xlsx"))
-  return {
-    props: {
-      type: "getStaticProps",
-      html: utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]),
-    },
-  }
-}
\ No newline at end of file
diff --git a/demos/react/pages/getStaticPaths.js b/demos/react/pages/getStaticPaths.js
deleted file mode 100644
index 3852295..0000000
--- a/demos/react/pages/getStaticPaths.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import Head from 'next/head';
-import Link from "next/link";
-import { readFile, utils } from 'xlsx';
-import { join } from 'path';
-import { cwd } from 'process';
-
-export default function Index({snames, type}) { return (
-<div>
-  <Head>
-    <meta httpEquiv="Content-Type" content="text/html; charset=UTF-8" />
-    <title>SheetJS Next.JS {type} Demo</title>
-    <script src="/shim.js"></script>
-    <style jsx>{`
-      body, #app { height: 100%; };
-    `}</style>
-  </Head>
-  <pre>
-<h3>SheetJS Next.JS {type} Demo</h3>
-This demo reads from /public/sheetjs.xlsx.  Each worksheet maps to a path:<br/><br/>
-{snames.map((sname, idx) => (<>
-  <Link key={idx} href="/sheets/[id]" as={`/sheets/${idx}`}><a>{`Sheet index=${idx} name="${sname}"`}</a></Link>
-  <br/>
-  <br/>
-</>))}
-
-  </pre>
-</div>
-); }
-
-export async function getStaticProps() {
-  const wb = readFile(join(cwd(), "public", "sheetjs.xlsx"))
-  return {
-    props: {
-      type: "getStaticPaths",
-      snames: wb.SheetNames,
-    },
-  }
-}
\ No newline at end of file
diff --git a/demos/react/pages/getStaticProps.js b/demos/react/pages/getStaticProps.js
deleted file mode 100644
index ca2e304..0000000
--- a/demos/react/pages/getStaticProps.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import Head from 'next/head';
-import { readFile, utils } from 'xlsx';
-import { join } from 'path';
-import { cwd } from 'process';
-
-export default function Index({html, type}) { return (
-<div>
-  <Head>
-    <meta httpEquiv="Content-Type" content="text/html; charset=UTF-8" />
-    <title>SheetJS Next.JS {type} Demo</title>
-    <script src="/shim.js"></script>
-    <style jsx>{`
-      body, #app { height: 100%; };
-    `}</style>
-  </Head>
-  <pre>
-<h3>SheetJS Next.JS {type} Demo</h3>
-This demo reads from /public/sheetjs.xlsx and generates HTML from the first sheet.
-  </pre>
-  <div dangerouslySetInnerHTML={{ __html: html }} />
-</div>
-); }
-
-export async function getStaticProps() {
-  const wb = readFile(join(cwd(), "public", "sheetjs.xlsx"))
-  return {
-    props: {
-      type: "getStaticProps",
-      html: utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]),
-    },
-  }
-}
\ No newline at end of file
diff --git a/demos/react/pages/index.js b/demos/react/pages/index.js
deleted file mode 100644
index c93bccd..0000000
--- a/demos/react/pages/index.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import Head from 'next/head';
-
-export default function Index() { return (
-<div>
-  <Head>
-    <meta httpEquiv="Content-Type" content="text/html; charset=UTF-8" />
-    <title>SheetJS Next.JS Demo</title>
-    <script src="/shim.js"></script>
-    <style jsx>{`
-      body, #app { height: 100%; };
-    `}</style>
-  </Head>
-  <pre>
-<h3>SheetJS Next.JS Demos</h3>
-All demos read from /public/sheetjs.xlsx.<br/>
-<br/>
-- <a href="/getStaticProps">getStaticProps</a><br/>
-<br/>
-- <a href="/getServerSideProps">getServerSideProps</a><br/>
-<br/>
-- <a href="/getStaticPaths">getStaticPaths</a><br/>
-  </pre>
-</div>
-); }
\ No newline at end of file
diff --git a/demos/react/pages/sheets/[id].js b/demos/react/pages/sheets/[id].js
deleted file mode 100644
index 530b675..0000000
--- a/demos/react/pages/sheets/[id].js
+++ /dev/null
@@ -1,51 +0,0 @@
-import Head from 'next/head';
-import { readFile, utils } from 'xlsx';
-import { join } from 'path';
-import { cwd } from 'process';
-
-export default function Index({html, type, name}) { return (
-<div>
-  <Head>
-    <meta httpEquiv="Content-Type" content="text/html; charset=UTF-8" />
-    <title>SheetJS Next.JS {type} Demo</title>
-    <script src="/shim.js"></script>
-    <style jsx>{`
-      body, #app { height: 100%; };
-    `}</style>
-  </Head>
-  <pre>
-<h3>SheetJS Next.JS {type} Demo</h3>
-This demo reads from /public/sheetjs.xlsx.<br/>
-<br/>
-<b>{name}</b>
-  </pre>
-  <div dangerouslySetInnerHTML={{ __html: html }} />
-</div>
-); }
-
-let cache = [];
-
-export async function getStaticProps(ctx) {
-  if(!cache || !cache.length) {
-    const wb = readFile(join(cwd(), "public", "sheetjs.xlsx"));
-    cache = wb.SheetNames.map((name) => ({ name, sheet: wb.Sheets[name] }));
-  }
-  const entry = cache[ctx.params.id];
-  return {
-    props: {
-      type: "getStaticPaths",
-      name: entry.name,
-      id: ctx.params.id.toString(),
-      html: entry.sheet ? utils.sheet_to_html(entry.sheet) : "",
-    },
-  }
-}
-
-export async function getStaticPaths() {
-  const wb = readFile(join(cwd(), "public", "sheetjs.xlsx"));
-  cache = wb.SheetNames.map((name) => ({ name, sheet: wb.Sheets[name] }));
-  return {
-    paths: wb.SheetNames.map((name, idx) => ({ params: { id: idx.toString()  } })),
-    fallback: false,
-  };
-}
diff --git a/demos/react/public/sheetjs.xlsx b/demos/react/public/sheetjs.xlsx
deleted file mode 100644
index 25496b9..0000000
Binary files a/demos/react/public/sheetjs.xlsx and /dev/null differ
diff --git a/demos/react/sheetjs.js b/demos/react/sheetjs.js
deleted file mode 100644
index cdb0237..0000000
--- a/demos/react/sheetjs.js
+++ /dev/null
@@ -1,144 +0,0 @@
-/* xlsx.js (C) 2013-present  SheetJS -- http://sheetjs.com */
-/* Notes:
-   - usage: `ReactDOM.render( <SheetJSApp />, document.getElementById('app') );`
-   - xlsx.full.min.js is loaded in the head of the HTML page
-   - this script should be referenced with type="text/babel"
-   - babel.js in-browser transpiler should be loaded before this script
-*/
-function SheetJSApp() {
-	const [data, setData] = React.useState([]);
-	const [cols, setCols] = React.useState([]);
-
-	const handleFile = (file) => {
-		const reader = new FileReader();
-		reader.onload = (e) => {
-			/* Parse data */
-			const ab = e.target.result;
-			const wb = XLSX.read(ab, {type:'array'});
-			/* Get first worksheet */
-			const wsname = wb.SheetNames[0];
-			const ws = wb.Sheets[wsname];
-			/* Convert array of arrays */
-			const data = XLSX.utils.sheet_to_json(ws, {header:1});
-			/* Update state */
-			setData(data);
-			setCols(make_cols(ws['!ref']))
-		};
-		reader.readAsArrayBuffer(file);
-	}
-
-	const exportFile = () => {
-		/* convert state to workbook */
-		const ws = XLSX.utils.aoa_to_sheet(data);
-		const wb = XLSX.utils.book_new();
-		XLSX.utils.book_append_sheet(wb, ws, "SheetJS");
-		/* generate XLSX file and send to client */
-		XLSX.writeFile(wb, "sheetjs.xlsx")
-	};
-
-	return (
-	<DragDropFile handleFile={handleFile}>
-		<div className="row"><div className="col-xs-12">
-			<DataInput handleFile={handleFile} />
-		</div></div>
-		<div className="row"><div className="col-xs-12">
-			<button disabled={!data.length} className="btn btn-success" onClick={exportFile}>Export</button>
-		</div></div>
-		<div className="row"><div className="col-xs-12">
-			<OutTable data={data} cols={cols} />
-		</div></div>
-	</DragDropFile>
-	);
-}
-
-if(typeof module !== 'undefined') module.exports = SheetJSApp
-
-/* -------------------------------------------------------------------------- */
-
-/*
-  Simple HTML5 file drag-and-drop wrapper
-  usage: <DragDropFile handleFile={handleFile}>...</DragDropFile>
-    handleFile(file:File):void;
-*/
-
-function DragDropFile({ handleFile, children }) {
-	const suppress = (e) => { e.stopPropagation(); e.preventDefault(); };
-	const handleDrop = (e) => { e.stopPropagation(); e.preventDefault();
-		const files = e.dataTransfer.files;
-		if(files && files[0]) handleFile(files[0]);
-	};
-
-	return (
-		<div
-			onDrop={handleDrop}
-			onDragEnter={suppress}
-			onDragOver={suppress}
-		>
-		{children}
-		</div>
-	);
-}
-
-/*
-  Simple HTML5 file input wrapper
-  usage: <DataInput handleFile={callback} />
-    handleFile(file:File):void;
-*/
-
-function DataInput({ handleFile }) {
-	const handleChange = (e) => {
-		const files = e.target.files;
-		if(files && files[0]) handleFile(files[0]);
-	};
-
-	return (
-		<form className="form-inline">
-			<div className="form-group">
-				<label htmlFor="file">Drag or choose a spreadsheet file</label>
-				<br />
-				<input
-					type="file"
-					className="form-control"
-					id="file"
-					accept={SheetJSFT}
-					onChange={handleChange}
-				/>
-			</div>
-		</form>
-	)
-}
-
-/*
-  Simple HTML Table
-  usage: <OutTable data={data} cols={cols} />
-    data:Array<Array<any> >;
-    cols:Array<{name:string, key:number|string}>;
-*/
-function OutTable({ data, cols }) {
-	return (
-		<div className="table-responsive">
-			<table className="table table-striped">
-				<thead>
-					<tr>{cols.map((c) => <th key={c.key}>{c.name}</th>)}</tr>
-				</thead>
-				<tbody>
-					{data.map((r,i) => <tr key={i}>
-						{cols.map(c => <td key={c.key}>{ r[c.key] }</td>)}
-					</tr>)}
-				</tbody>
-			</table>
-		</div>
-	);
-}
-
-/* list of supported file types */
-const SheetJSFT = [
-	"xlsx", "xlsb", "xlsm", "xls", "xml", "csv", "txt", "ods", "fods", "uos", "sylk", "dif", "dbf", "prn", "qpw", "123", "wb*", "wq*", "html", "htm"
-].map(x => `.${x}`).join(",");
-
-/* generate an array of column objects */
-const make_cols = refstr => {
-	let o = [], C = XLSX.utils.decode_range(refstr).e.c + 1;
-	for(var i = 0; i < C; ++i) o[i] = {name:XLSX.utils.encode_col(i), key:i}
-	return o;
-};
diff --git a/demos/server/.gitignore b/demos/server/.gitignore
deleted file mode 100644
index 0bb4e01..0000000
--- a/demos/server/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-xlsx.full.min.js
-xlsx-demo
diff --git a/demos/server/Makefile b/demos/server/Makefile
deleted file mode 100644
index 9a340b6..0000000
--- a/demos/server/Makefile
+++ /dev/null
@@ -1,29 +0,0 @@
-.PHONY: init
-init:
-	mkdir -p node_modules
-	cd node_modules; if [ ! -e xlsx ]; then ln -s ../../../ xlsx; fi; cd -
-
-.PHONY: request
-request: init ## request demo
-	node _request.js
-
-.PHONY: express
-express: init ## express demo
-	node express.js
-
-.PHONY: koa
-koa: init ## koa demo
-	node koa.js
-
-.PHONY: hapi
-hapi: init ## hapi demo
-	cp ../../dist/xlsx.full.min.js .
-	node hapi.js
-
-.PHONY: nest
-nest: init ## nest demo
-	bash -c ./nest.sh
-
-.PHONY: drash
-drash: ## drash demo
-	deno run --allow-net drash.ts
diff --git a/demos/server/README.md b/demos/server/README.md
index 41df3fd..4f03372 100644
--- a/demos/server/README.md
+++ b/demos/server/README.md
@@ -1,208 +1,11 @@
 # NodeJS Server Deployments
 
-This library is 100% pure JS.  This is great for compatibility but tends to lock
-up long-running processes.  In the web browser, Web Workers are used to offload
-work from the main browser thread.  In NodeJS, there are other strategies.  This
-demo shows a few different strategies applied to different server frameworks.
+[The new demo](https://docs.sheetjs.com/docs/demos/server) has a more focused
+discussion with examples for popular JS server-side frameworks.
 
-NOTE: these examples merely demonstrate the core concepts and do not include
-appropriate error checking or other production-level features.
-
-
-### Express Setup
-
-The following commands are required in order to test the [Express](https://github.com/expressjs/express) demo:
-
-```bash
-npm install express printj express-formidable https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz
-node express.js
-```
-
-### Koa Setup
-
-The following commands are required in order to test the [Koa](https://github.com/koajs/koa) demo:
-
-```bash
-npm install koa printj formidable https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz
-node koa.js
-```
-
-### Hapi Setup
-
-**Note: Hapi demo as written only works with Hapi version 16 and below.**
-
-The following commands are required in order to test the [Hapi](https://github.com/hapijs/hapi) demo:
-
-```bash
-npm install hapi@16.x printj tiny-worker https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz
-node hapi.js
-```
-
-
-
-### Node Buffer
-
-The `read` and `write` functions can handle `Buffer` data with `type:"buffer"`.
-For example, the `request` library returns data in a buffer:
-
-```js
-var XLSX = require('xlsx'), request = require('request');
-request(url, {encoding: null}, function(err, res, data) {
-	if(err || res.statusCode !== 200) return;
-
-	/* data is a node Buffer that can be passed to XLSX.read */
-	var workbook = XLSX.read(data, {type:'buffer'});
-
-	/* DO SOMETHING WITH workbook HERE */
-});
-```
-
-The `readFile` / `writeFile` functions wrap `fs.{read,write}FileSync`:
-
-```js
-/* equivalent to `var wb = XLSX.readFile("sheetjs.xlsx");` */
-var buf = fs.readFileSync("sheetjs.xlsx");
-var wb = XLSX.read(buf, {type:'buffer'});
-```
-
-### Responding to Form Uploads
-
-Using `formidable`, files uploaded to forms are stored to temporary files that
-can be read with `readFile`:
-
-```js
-/* within the server callback function(request, response) { */
-var form = new formidable.IncomingForm();
-form.parse(req, function(err, fields, files) {
-	var f = files[Object.keys(files)[0]];
-	var workbook = XLSX.readFile(f.path);
-	/* DO SOMETHING WITH workbook HERE */
-});
-```
-
-The `node.js` demo shows a plain HTTP server that accepts file uploads and
-converts data to requested output format.
-
-### Example servers
-
-Each example server is expected to hold an array-of-arrays in memory.  They are
-expected to handle:
-
-- `POST /         ` accepts an encoded `file` and updates the internal storage
-- `GET  /?t=<type>` returns the internal storage in the specified type
-- `POST /?f=<name>` reads the local file and updates the internal storage
-- `GET  /?f=<name>` writes the file to the specified name
-
-Testing with cURL is straightforward:
-
-```bash
-# upload sheetjs.csv and update data
-curl -X POST -F "data=@sheetjs.csv" http://localhost:7262/
-# download data in SYLK format
-curl -X GET http://localhost:7262/?t=slk
-# read sheetjs.csv from the server directory
-curl -X POST http://localhost:7262/?f=sheetjs.csv
-# write sheetjs.xlsb in the XLSB format
-curl -X GET http://localhost:7262/?f=sheetjs.xlsb
-```
-
-
-## Main-process logic with express
-
-The most straightforward approach is to handle the data directly in HTTP event
-handlers.  The `buffer` type for `XLSX.read` and `XLSX.write` work with `http`
-module and with express directly.  The following snippet generates a workbook
-based on an array of arrays and sends it to the client:
-
-```js
-function send_aoa_to_client(req, res, data, bookType) {
-	/* generate workbook */
-	var ws = XLSX.utils.aoa_to_sheet(data);
-	var wb = XLSX.utils.book_new();
-	XLSX.utils.book_append_sheet(wb, ws, "SheetJS");
-
-	/* generate buffer */
-	var buf = XLSX.write(wb, {type:'buffer', bookType:bookType || "xlsx"});
-
-	/* send to client */
-	res.status(200).send(buf);
-}
-```
-
-
-## fork with koa
-
-`child_process.fork` provides a light-weight and customizable way to offload
-work from the main server process.  This demo passes commands to a custom child
-process and the child passes back buffers of data.
-
-The main server script is `koa.js` and the worker script is `koasub.js`.  State
-is maintained in the worker script.
-
-
-
-## tiny-worker with hapi
-
-`tiny-worker` provides a Web Worker-like interface.  Binary strings and simple
-objects are readily passed across the Worker divide.
-
-The main server script is `hapi.js` and the worker script is `worker.js`.  State
-is maintained in the server script.
-
-Note: due to an issue with hapi payload parsing, the route `POST /file` is used
-to handle the case of reading from file, so the cURL test is:
-
-```bash
-# upload sheetjs.csv and update data
-curl -X POST -F "data=@sheetjs.csv" http://localhost:7262/
-# download data in SYLK format
-curl -X GET http://localhost:7262/?t=slk
-# read sheetjs.csv from the server directory
-curl -X POST http://localhost:7262/file?f=sheetjs.csv
-# write sheetjs.xlsb in the XLSB format
-curl -X GET http://localhost:7262/?f=sheetjs.xlsb
-```
-
-
-
-## NestJS
-
-[NestJS](https://nestjs.com/) is a Node.js framework for server-side web applications.
-
-This demo uses SheetJS to parse a spreadsheet via a POST API endpoint. The file
-arrives to the endpoint as body `form-data`, accessible using the `file` key.
-After parsing the file, CSV contents of the first worksheet will be returned.
-[Body parsing uses `multer`](https://docs.nestjs.com/techniques/file-upload).
-
-Before running the demo, the NestJS CLI tool must be installed.  The instruction
-is described in the NestJS ["First Steps"](https://docs.nestjs.com/first-steps):
-
-```bash
-npm i -g @nestjs/cli
-make nest
-```
-
-The demo can be tested using the `/sheetjs/upload-xlsx-file` endpoint:
-
-```bash
-curl -X POST -F "file=@test.xlsx" http://localhost:3000/sheetjs/upload-xlsx-file
-```
-
-The included [`nest.sh`](./nest.sh) script creates and configures the project.
-
-
-This demo creates a module and a controller.  The controller handles the actual
-requests (creating the endpoint) while the module is used to configure `multer`.
-
-
-
-## Deno
-
-[`Drash`](https://drash.land/drash/) is a Deno framework for Deno's HTTP server.
-
-The `drash.ts` demo responds to POST requests and responds with HTML previews.
-
-<https://s2c.deno.dev> is a live deployment of the service.
+Cloud services are covered in separate demos:
 
+- [AWS](https://docs.sheetjs.com/docs/demos/aws)
+- [Azure](https://docs.sheetjs.com/docs/demos/azure)
 
 [![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)
diff --git a/demos/server/_cors.js b/demos/server/_cors.js
deleted file mode 100644
index 22b04c2..0000000
--- a/demos/server/_cors.js
+++ /dev/null
@@ -1,4 +0,0 @@
-/* xlsx.js (C) 2013-present  SheetJS -- http://sheetjs.com */
-var cors = function(req, res) { res.header('Access-Control-Allow-Origin', '*'); };
-cors.mw = function(req, res, next) { cors(req, res); next(); };
-module.exports = cors;
diff --git a/demos/server/_logit.js b/demos/server/_logit.js
deleted file mode 100644
index 94f1a44..0000000
--- a/demos/server/_logit.js
+++ /dev/null
@@ -1,7 +0,0 @@
-/* xlsx.js (C) 2013-present  SheetJS -- http://sheetjs.com */
-var sprintf = require('printj').sprintf;
-var logit = function(req, res) {
-	console.log(sprintf("%s %s %d", req.method, req.url, res.statusCode));
-};
-logit.mw = function(req, res, next) { logit(req, res); next(); }
-module.exports = logit;
diff --git a/demos/server/_request.js b/demos/server/_request.js
deleted file mode 100644
index 1e3aee0..0000000
--- a/demos/server/_request.js
+++ /dev/null
@@ -1,9 +0,0 @@
-/* xlsx.js (C) 2013-present  SheetJS -- http://sheetjs.com */
-var XLSX = require('xlsx'), request = require('request');
-var url = 'http://www.freddiemac.com/pmms/2017/historicalweeklydata.xls'
-request(url, {encoding: null}, function(err, res, data) {
-	if(err || res.statusCode !== 200) return;
-	var wb = XLSX.read(data, {type:'buffer'});
-	var ws = wb.Sheets[wb.SheetNames[0]];
-	console.log(XLSX.utils.sheet_to_csv(ws, {blankrows:false}));
-});
diff --git a/demos/server/drash.ts b/demos/server/drash.ts
deleted file mode 100644
index 5446b66..0000000
--- a/demos/server/drash.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-/*! sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */
-// @deno-types="https://cdn.sheetjs.com/xlsx-latest/package/types/index.d.ts"
-import { read, utils, set_cptable } from 'https://cdn.sheetjs.com/xlsx-latest/package/xlsx.mjs';
-import * as cptable from 'https://cdn.sheetjs.com/xlsx-latest/package/dist/cpexcel.full.mjs';
-set_cptable(cptable);
-
-import * as Drash from "https://deno.land/x/drash@v2.5.4/mod.ts";
-
-
-// Create your resource
-
-class HomeResource extends Drash.Resource {
-  public paths = ["/"];
-
-  public POST(request: Drash.Request, response: Drash.Response) {
-    const file = request.bodyParam<Drash.Types.BodyFile>("file");
-    if (!file) throw new Error("File is required!");
-    var wb = read(file.content, {type: "buffer"});
-    return response.html( utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]));
-  }
-
-  public GET(request: Drash.Request, response: Drash.Response): void {
-    return response.html(`\
-<!DOCTYPE html>
-<html>
-  <head>
-    <title>SheetJS Spreadsheet to HTML Conversion Service</title>
-    <meta charset="utf-8" />
-  </head>
-  <body>
-<pre><h3><a href="//sheetjs.com/">SheetJS</a> Spreadsheet Conversion Service</h3>
-<b>API</b>
-
-Send a POST request to https://s2c.deno.dev/ with the file in the "file" body parameter:
-
-$ curl -X POST -F"file=@test.xlsx" https://s2c.deno.dev/
-
-The response will be an HTML TABLE generated from the first worksheet.
-
-<b>Try it out!</b><form action="/" method="post" enctype="multipart/form-data">
-
-<input type="file" name="file" />
-
-Use the file input element to select a file, then click "Submit"
-
-<button type="submit">Submit</button>
-</form>
-</pre>
-  </body>
-</html>`,
-    );
-  }
-}
-
-// Create and run your server
-const server = new Drash.Server({
-  hostname: "",
-  port: 3000,
-  protocol: "http",
-  resources: [
-    HomeResource,
-  ],
-});
-
-server.run();
-
-console.log(`Server running at ${server.address}.`);
-
diff --git a/demos/server/express.js b/demos/server/express.js
deleted file mode 100644
index 2b50552..0000000
--- a/demos/server/express.js
+++ /dev/null
@@ -1,65 +0,0 @@
-/* xlsx.js (C) 2013-present  SheetJS -- http://sheetjs.com */
-
-var fs = require('fs'), path = require('path'), URL = require('url');
-var express = require('express'), app = express();
-var sprintf = require('printj').sprintf;
-var logit = require('./_logit');
-var cors = require('./_cors');
-var data = "a,b,c\n1,2,3".split("\n").map(function(x) { return x.split(","); });
-var XLSX = require('xlsx');
-
-/* helper to generate the workbook object */
-function make_book() {
-	var ws = XLSX.utils.aoa_to_sheet(data);
-	var wb = XLSX.utils.book_new();
-	XLSX.utils.book_append_sheet(wb, ws, "SheetJS");
-	return wb;
-}
-
-function get_data(req, res, type) {
-	var wb = make_book();
-	/* send buffer back */
-	res.status(200).send(XLSX.write(wb, {type:'buffer', bookType:type}));
-}
-
-function get_file(req, res, file) {
-	var wb = make_book();
-	/* write using XLSX.writeFile */
-	XLSX.writeFile(wb, file);
-	res.status(200).send("wrote to " + file + "\n");
-}
-
-function load_data(file) {
-	var wb = XLSX.readFile(file);
-	/* generate array of arrays */
-	data = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]], {header:1});
-	console.log(data);
-}
-
-function post_data(req, res) {
-	var keys = Object.keys(req.files), k = keys[0];
-	load_data(req.files[k].path);
-	res.status(200).send("ok\n");
-}
-
-function post_file(req, res, file) {
-	load_data(file);
-	res.status(200).send("ok\n");
-}
-app.use(logit.mw);
-app.use(cors.mw);
-app.use(require('express-formidable')());
-app.get('/', function(req, res, next) {
-	var url = URL.parse(req.url, true);
-	if(url.query.t) return get_data(req, res, url.query.t);
-	else if(url.query.f) return get_file(req, res, url.query.f);
-	res.status(403).end("Forbidden");
-});
-app.post('/', function(req, res, next) {
-	var url = URL.parse(req.url, true);
-	if(url.query.f) return post_file(req, res, url.query.f);
-	return post_data(req, res);
-});
-
-var port = +process.argv[2] || +process.env.PORT || 7262;
-app.listen(port, function() { console.log('Serving HTTP on port ' + port); });
diff --git a/demos/server/hapi.js b/demos/server/hapi.js
deleted file mode 100644
index a9db56b..0000000
--- a/demos/server/hapi.js
+++ /dev/null
@@ -1,67 +0,0 @@
-/* xlsx.js (C) 2013-present  SheetJS -- http://sheetjs.com */
-var Hapi = require('hapi'), server = new Hapi.Server();
-var logit = require('./_logit');
-var Worker = require('tiny-worker');
-var fs = require('fs');
-var data = "a,b,c\n1,2,3".split("\n").map(x => x.split(","));
-
-function get_data(req, res, type) {
-	var work = new Worker('worker.js');
-	work.onmessage = function(e) {
-		if(e.data.err) console.log(e.data.err);
-		var buf = new Buffer(e.data.data, "binary");
-		return res(buf);
-	};
-	work.postMessage({action:"write", type:type, data:data});
-}
-
-function get_file(req, res, file) {
-	var work = new Worker('worker.js');
-	work.onmessage = function(e) {
-		fs.writeFileSync(file, e.data.data, 'binary');
-		return res("wrote to " + file + "\n");
-	};
-	work.postMessage({action:"write", file:file, data:data});
-}
-
-function post_file(req, res, file) {
-	var work = new Worker('worker.js');
-	work.onmessage = function(e) {
-		data = e.data.data;
-		return res("read from " + file + "\n");
-	};
-	work.postMessage({action:"read", file:file});
-}
-
-function post_data(req, res, type) {
-	var keys = Object.keys(req.payload), k = keys[0];
-	post_file(req, res, req.payload[k].path);
-}
-
-var port = 7262;
-server.connection({ host:'localhost', port: port});
-
-server.route({ method: 'GET', path: '/',
-handler: function(req, res) {
-	logit(req.raw.req, req.raw.res);
-	if(req.query.t) get_data(req, res, req.query.t);
-	else if(req.query.f) get_file(req, res, req.query.f);
-	else res('Forbidden').code(403);
-}});
-server.route({ method: 'POST', path: '/',
-config:{payload:{ output: 'file', parse: true, allow: 'multipart/form-data'}},
-handler: function(req, res) {
-	logit(req.raw.req, req.raw.res);
-	if(req.query.f) return post_file(req, res, req.query.f);
-	return post_data(req, res);
-}});
-server.route({ method: 'POST', path: '/file',
-handler: function(req, res) {
-	logit(req.raw.req, req.raw.res);
-	if(req.query.f) return post_file(req, res, req.query.f);
-	return post_data(req, res);
-}});
-server.start(function(err) {
-	if(err) throw err;
-	console.log('Serving HTTP on port ' + port);
-});
diff --git a/demos/server/koa.js b/demos/server/koa.js
deleted file mode 100644
index 1f1176d..0000000
--- a/demos/server/koa.js
+++ /dev/null
@@ -1,79 +0,0 @@
-/* xlsx.js (C) 2013-present  SheetJS -- http://sheetjs.com */
-
-const Koa = require('koa'), app = new Koa();
-const { sprintf } = require('printj');
-const { IncomingForm } = require('formidable');
-const { fork } = require('child_process');
-const logit = require('./_logit');
-const subprocess = fork('koasub.js');
-
-const get_data = async (ctx, type) => {
-	await new Promise((resolve, reject) => {
-		const cb = (data) => {
-			ctx.response.body = Buffer(data);
-			subprocess.removeListener('message', cb);
-			resolve();
-		};
-		subprocess.on('message', cb);
-		subprocess.send(['get data', type]);
-	});
-};
-
-const get_file = async (ctx, file) => {
-	await new Promise((resolve, reject) => {
-		const cb = (data) => {
-			ctx.response.body = Buffer(data);
-			subprocess.removeListener('message', cb);
-			resolve();
-		};
-		subprocess.on('message', cb);
-		subprocess.send(['get file', file]);
-	});
-};
-
-const load_data = async (ctx, file) => {
-	await new Promise((resolve, reject) => {
-		const cb = (data) => {
-			ctx.response.body = "ok\n";
-			subprocess.removeListener('message', cb);
-			resolve();
-		};
-		subprocess.on('message', cb);
-		subprocess.send(['load data', file]);
-	});
-};
-
-const post_data = async (ctx) => {
-	const keys = Object.keys(ctx.request._files), k = keys[0];
-	await load_data(ctx, ctx.request._files[k].path);
-};
-
-app.use(async (ctx, next) => { logit(ctx.req, ctx.res); await next(); });
-app.use(async (ctx, next) => {
-	const form = new IncomingForm();
-	await new Promise((resolve, reject) => {
-		form.parse(ctx.req, (err, fields, files) => {
-			if(err) return reject(err);
-			ctx.request._fields = fields;
-			ctx.request._files = files;
-			resolve();
-		});
-	});
-	await next();
-});
-app.use(async (ctx, next) => {
-	if(ctx.request.method !== 'GET') await next();
-	else if(ctx.request.path !== '/') await next();
-	else if(ctx.request.query.t) await get_data(ctx, ctx.request.query.t);
-	else if(ctx.request.query.f) await get_file(ctx, ctx.request.query.f);
-	else ctx.throw(403, "Forbidden");
-});
-app.use(async (ctx, next) => {
-	if(ctx.request.method !== 'POST') await next();
-	else if(ctx.request.path !== '/') await next();
-	else if(ctx.request.query.f) await load_data(ctx, ctx.request.query.f);
-	else await post_data(ctx);
-});
-
-const port = +process.argv[2] || +process.env.PORT || 7262;
-app.listen(port, () => { console.log('Serving HTTP on port ' + port); });
diff --git a/demos/server/koasub.js b/demos/server/koasub.js
deleted file mode 100644
index 1eeb989..0000000
--- a/demos/server/koasub.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/* xlsx.js (C) 2013-present  SheetJS -- http://sheetjs.com */
-const XLSX = require('xlsx');
-let data = "a,b,c\n1,2,3".split("\n").map(x => x.split(","));
-process.on('message', ([m, data] = _) => {
-	switch(m) {
-		case 'load data': load_data(data); break;
-		case 'get data': get_data(data); break;
-		case 'get file': get_file(data); break;
-	}
-});
-
-function load_data(file) {
-	var wb = XLSX.readFile(file);
-	/* generate array of arrays */
-	data = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]], {header:1});
-	console.log(data);
-	process.send("done");
-}
-
-/* helper to generate the workbook object */
-function make_book() {
-	var ws = XLSX.utils.aoa_to_sheet(data);
-	var wb = XLSX.utils.book_new();
-	XLSX.utils.book_append_sheet(wb, ws, "SheetJS");
-	return wb;
-}
-
-function get_data(type) {
-	var wb = make_book();
-	/* send buffer back */
-	process.send(XLSX.write(wb, {type:'buffer', bookType:type}));
-}
-
-function get_file(file) {
-	var wb = make_book();
-	/* write using XLSX.writeFile */
-	XLSX.writeFile(wb, file);
-	process.send("wrote to " + file + "\n");
-}
diff --git a/demos/server/nest.sh b/demos/server/nest.sh
deleted file mode 100755
index ce3f07d..0000000
--- a/demos/server/nest.sh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/bash
-
-# it is assumed that @nestjs/cli is installed globally
-
-if [ ! -e xlsx-demo ]; then
-	nest new -p npm xlsx-demo
-fi
-
-cd xlsx-demo
-npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz
-npm i --save-dev @types/multer
-
-if [ ! -e src/sheetjs/sheetjs.module.ts ]; then
-	nest generate module sheetjs
-fi
-
-if [ ! -e src/sheetjs/sheetjs.controller.ts ]; then
-	nest generate controller sheetjs
-fi
-
-cp ../sheetjs.module.ts src/sheetjs/
-cp ../sheetjs.controller.ts src/sheetjs/
-mkdir -p upload
-npm run start
diff --git a/demos/server/nodejs.js b/demos/server/nodejs.js
deleted file mode 100644
index 7b54d37..0000000
--- a/demos/server/nodejs.js
+++ /dev/null
@@ -1,84 +0,0 @@
-/* xlsx.js (C) 2013-present  SheetJS -- http://sheetjs.com */
-
-var http = require('http');
-var XLSX = require('xlsx');
-var formidable = require('formidable');
-var html = "";
-var PORT = 3000;
-
-var extmap = {};
-
-var server = http.createServer(function(req, res) {
-	if(req.method !== 'POST') return res.end(html);
-	var form = new formidable.IncomingForm();
-	form.parse(req, function(err, fields, files) {
-		var f = files[Object.keys(files)[0]];
-		var wb = XLSX.readFile(f.path);
-		var ext = (fields.bookType || "xlsx").toLowerCase();
-		res.setHeader('Content-Disposition', 'attachment; filename="download.' + (extmap[ext] || ext) + '";');
-		res.end(XLSX.write(wb, {type:"buffer", bookType:ext}));
-	});
-}).listen(PORT);
-
-html = [
-'<pre>',
-'<h3><a href="http://sheetjs.com/">SheetJS File Converter</a></h3>',
-'Upload a file to convert the contents to another format.',
-'',
-'<b>Form Fields</b>:',
-'- bookType: output format type (defaults to "XLSX")',
-'- basename: basename for output file (defaults to "download")',
-'',
-'<form method="POST" enctype="multipart/form-data" action="/">',
-'<input type="file" id="file" name="file"/>',
-'<select name="bookType">',
-[
-	["xlsb",  "XLSB"],
-	["xlsx",  "XLSX"],
-	["xlsm",  "XLSM"],
-	["biff8", "BIFF8 XLS"],
-	["biff5", "BIFF5 XLS"],
-	["biff2", "BIFF2 XLS"],
-	["xlml",  "SSML 2003"],
-	["ods",   "ODS"],
-	["fods",  "Flat ODS"],
-	["csv",   "CSV"],
-	["txt",   "Unicode Text"],
-	["sylk",  "Symbolic Link"],
-	["html",  "HTML"],
-	["dif",   "DIF"],
-	["dbf",   "DBF"],
-	["rtf",   "RTF"],
-	["prn",   "Lotus PRN"],
-	["eth",   "Ethercalc"],
-].map(function(x) { return '  <option value="' + x[0] + '">' + x[1] + '</option>'; }).join("\n"),
-'</select>',
-'<input type="submit" value="Submit Form">',
-'</form>',
-'',
-'<b>Form code:</b>',
-'&lt;form method="POST" enctype="multipart/form-data" action="/"&gt;',
-'&lt;input type="file" id="file" name="file"/&gt;',
-'&lt;select name="bookType"&gt',
-'&lt;!-- options here --&gt;',
-'&lt;/select&gt',
-'&lt;input type="submit" value="Submit Form"&gt;',
-'&lt;/form&gt;',
-'',
-'<b>fetch Code:</b>',
-'var blob = new Blob("1,2,3\\n4,5,6".split("")); // original file',
-'var fd = new FormData();',
-'fd.set("data", blob, "foo.bar");',
-'fd.set("bookType", "xlsb");',
-'var res = await fetch("/", {method:"POST", body:fd});',
-'var data = await res.arrayBuffer();',
-'</pre>'
-].join("\n");
-
-extmap = {
-	"biff2" : "xls",
-	"biff5" : "xls",
-	"biff8" : "xls",
-	"xlml"  : "xls"
-};
-console.log('listening on port ' + PORT);
diff --git a/demos/server/sheetjs.controller.ts b/demos/server/sheetjs.controller.ts
deleted file mode 100644
index bad90eb..0000000
--- a/demos/server/sheetjs.controller.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { Controller, Logger, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
-import { FileInterceptor } from '@nestjs/platform-express';
-import { readFile, utils } from 'xlsx';
-
-@Controller('sheetjs')
-export class SheetjsController {
-  private readonly logger = new Logger(SheetjsController.name);
-
-  @Post('upload-xlsx-file')
-  @UseInterceptors(FileInterceptor('file'))
-  async uploadXlsxFile(@UploadedFile() file: Express.Multer.File) {
-    // Open the uploaded XLSX file and perform SheetJS operations
-    const workbook = readFile(file.path);
-    const firstSheet = workbook.Sheets[workbook.SheetNames[0]];
-    const output = utils.sheet_to_csv(firstSheet);
-    this.logger.log(output);
-    return output;
-  }
-}
diff --git a/demos/server/sheetjs.csv b/demos/server/sheetjs.csv
deleted file mode 100644
index eddbf8a..0000000
--- a/demos/server/sheetjs.csv
+++ /dev/null
@@ -1,19 +0,0 @@
-Text,Number,Rich,Span
-This is Bold,123,This is Bold,This is Bold
-This is Italic,234,This is Italic,This is Italic
-This is Underline,345,This is Underline,This is Underline
-This is Stricken,456,This is Stricken,This is Stricken
-This is 18 px,567,This is 18 px,This is 18 px
-This is superscript,678,This is superscript,This is superscript
-This is subscript,789,This is subscript,This is subscript
-This is red,135,This is red,This is red
-This is green,246,This is green,This is green
-This is Times,357,This is Times,This is Times
-This is BIU,159,This is 01324576 yes,This is BIU
-BG Green,255,White on Blue,Green on Black
-Standard Newline,W S,"BR
-New  line","Pre
-New line"
-Height,100,px (not pt),yeah
-Top Left,80,Middle Center,Bottom Right
-Top Right,60,Bottom Center,Bottom Left
diff --git a/demos/server/sheetjs.module.ts b/demos/server/sheetjs.module.ts
deleted file mode 100644
index 4dd9a53..0000000
--- a/demos/server/sheetjs.module.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { Module } from '@nestjs/common';
-import { SheetjsController } from './sheetjs.controller';
-import { MulterModule } from '@nestjs/platform-express';
-
-@Module({
-  controllers: [SheetjsController],
-  imports: [
-    MulterModule.register({
-      dest: './upload',
-    }),
-  ],
-})
-export class SheetjsModule {}
diff --git a/demos/server/worker.js b/demos/server/worker.js
deleted file mode 100644
index c8e1a63..0000000
--- a/demos/server/worker.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
-var XLSX = require('xlsx');
-var fs = require('fs');
-
-onmessage = function(e) {
-	try { switch(e.data.action) {
-		case 'write':
-			var ws = XLSX.utils.aoa_to_sheet(e.data.data);
-			var wb = XLSX.utils.book_new();
-			XLSX.utils.book_append_sheet(wb, ws, "SheetJS");
-			postMessage({data: XLSX.write(wb, {type:'binary', bookType:e.data.type || e.data.file.match(/\.([^\.]*)$/)[1]})});
-			break;
-		case 'read':
-			var wb;
-			if(e.data.file) wb = XLSX.readFile(e.data.file);
-			else wb = XLSX.read(e.data.data);
-			var ws = wb.Sheets[wb.SheetNames[0]];
-			postMessage({data: XLSX.utils.sheet_to_json(ws, {header:1})});
-			break;
-		default: throw "unknown action";
-	}} catch(e) { postMessage({err:e.message || e}); }
-};
diff --git a/demos/vue/Makefile b/demos/vue/Makefile
deleted file mode 100644
index 0adece9..0000000
--- a/demos/vue/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-.PHONY: vue
-vue: ## Simple server for vue
-	python -mSimpleHTTPServer || python3 -mhttp.server
diff --git a/demos/vue/README.md b/demos/vue/README.md
index c364a8a..6229e41 100644
--- a/demos/vue/README.md
+++ b/demos/vue/README.md
@@ -1,83 +1,12 @@
 # VueJS
 
-The `xlsx.core.min.js` and `xlsx.full.min.js` scripts are designed to be dropped
-into web pages with script tags:
+[The new demo](https://docs.sheetjs.com/docs/demos/vue) has an updated
+exposition for legacy and modern deployments alike.
 
-```html
-<script src="xlsx.full.min.js"></script>
-```
+The ecosystem demos were grouped by type in the new demo site:
 
-The library can also be imported directly from single-file components with:
-
-```js
-// full import
-import * as XLSX from 'xlsx';
-
-// named imports
-import { read, utils, writeFileXLSX } from 'xlsx';
-```
-
-This demo directly generates HTML using `sheet_to_html` and adds an element to
-a pre-generated template.  It also has a button for exporting as XLSX.
-
-Other scripts in this demo show:
-- server-rendered VueJS component (with `nuxt.js`)
-- `weex` deployment for iOS
-
-## Internal State
-
-The plain JS demo embeds state in the DOM.  Other demos use proper state.
-
-The simplest state representation is an array of arrays.  To avoid having the
-table component depend on the library, the column labels are precomputed.  The
-state in this demo is shaped like the following object:
-
-```js
-{
-  cols: [{ name: "A", key: 0 }, { name: "B", key: 1 }, { name: "C", key: 2 }],
-  data: [
-    [ "id",    "name", "value" ],
-    [    1, "sheetjs",    7262 ],
-    [    2, "js-xlsx",    6969 ]
-  ]
-}
-```
-
-`sheet_to_json` and `aoa_to_sheet` utility functions can convert between arrays
-of arrays and worksheets:
-
-```js
-/* convert from workbook to array of arrays */
-var first_worksheet = workbook.Sheets[workbook.SheetNames[0]];
-var data = XLSX.utils.sheet_to_json(first_worksheet, {header:1});
-
-/* convert from array of arrays to workbook */
-var worksheet = XLSX.utils.aoa_to_sheet(data);
-var new_workbook = XLSX.utils.book_new();
-XLSX.utils.book_append_sheet(new_workbook, worksheet, "SheetJS");
-```
-
-The column objects can be generated with the `encode_col` utility function:
-
-```js
-function make_cols(refstr/*:string*/) {
-  var o = [];
-  var range = XLSX.utils.decode_range(refstr);
-  for(var i = 0; i <= range.e.c; ++i) {
-    o.push({name: XLSX.utils.encode_col(i), key:i});
-  }
-  return o;
-}
-```
-
-## Mobile Apps
-
-[The new demo](https://docs.sheetjs.com/docs/demos/mobile#quasar) uses the
-Quasar Framework in a VueJS + Vite project to generate a native iOS app.
-
-## Nuxt Content
-
-[The new demo](https://docs.sheetjs.com/docs/demos/content#nuxtjs) includes a
-complete example starting from `create-nuxt-app`.
+- [Nuxt Content](https://docs.sheetjs.com/docs/demos/content#nuxtjs) is now part of "Content and Site Generation"
+- [The new iOS app demo](https://docs.sheetjs.com/docs/demos/mobile#quasar) uses the Quasar Framework in a VueJS + Vite project to generate a native iOS app.
+- [`vue3-table-lite` reading, modifying, and writing files](https://docs.sheetjs.com/docs/demo/grid#vue3-table-lite) is now part of "Data Grids and UI"
 
 [![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)
diff --git a/demos/vue/SheetJS-vue.js b/demos/vue/SheetJS-vue.js
deleted file mode 100644
index a21d563..0000000
--- a/demos/vue/SheetJS-vue.js
+++ /dev/null
@@ -1,68 +0,0 @@
-/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
-var SheetJSFT = [
-	"xlsx", "xlsb", "xlsm", "xls", "xml", "csv", "txt", "ods", "fods", "uos", "sylk", "dif", "dbf", "prn", "qpw", "123", "wb*", "wq*", "html", "htm", "numbers"
-].map(function(x) { return "." + x; }).join(",");
-
-var SJSTemplate = [
-	'<div>',
-		'<input type="file" multiple="false" id="sheetjs-input" accept="' + SheetJSFT + '" @change="onchange" />',
-		'<br/>',
-		'<button type="button" id="export-table" style="visibility:hidden" @click="onexport">Export to XLSX</button>',
-		'<br/>',
-		'<div id="out-table"></div>',
-	'</div>'
-].join("");
-var component_struct = {
-	template: SJSTemplate,
-	methods: {
-		onchange: function(evt) {
-			var file;
-			var files = evt.target.files;
-
-			if (!files || files.length == 0) return;
-
-			file = files[0];
-
-			var reader = new FileReader();
-			reader.onload = function (e) {
-				// pre-process data
-				var binary = "";
-				var bytes = new Uint8Array(e.target.result);
-				var length = bytes.byteLength;
-				for (var i = 0; i < length; i++) {
-					binary += String.fromCharCode(bytes[i]);
-				}
-
-				/* read workbook */
-				var wb = XLSX.read(binary, {type: 'binary'});
-
-				/* grab first sheet */
-				var wsname = wb.SheetNames[0];
-				var ws = wb.Sheets[wsname];
-
-				/* generate HTML */
-				var HTML = XLSX.utils.sheet_to_html(ws);
-
-				/* update table */
-				document.getElementById('out-table').innerHTML = HTML;
-				/* show export button */
-				document.getElementById('export-table').style.visibility = "visible";
-			};
-
-			reader.readAsArrayBuffer(file);
-		},
-		onexport: function(evt) {
-			/* generate workbook object from table */
-			var wb = XLSX.utils.table_to_book(document.getElementById('out-table'));
-			/* generate file and force a download*/
-			XLSX.writeFile(wb, "sheetjs.xlsx");
-		}
-	}
-};
-var app;
-if(Vue.component) {
-	Vue.component('html-preview', component_struct);
-} else {
-	app = Vue.createApp({});
-	app.component('html-preview', component_struct);
-}
diff --git a/demos/vue/index2.html b/demos/vue/index2.html
deleted file mode 100644
index 1870671..0000000
--- a/demos/vue/index2.html
+++ /dev/null
@@ -1,63 +0,0 @@
-<!DOCTYPE html>
-<!-- xlsx.js (C) 2013-present  SheetJS http://sheetjs.com -->
-<!-- vim: set ts=2: -->
-<html>
-<head>
-	<title>SheetJS + VueJS2</title>
-	<!-- Vue 2 -->
-	<script src="https://unpkg.com/vue@2.x"></script>
-
-	<!-- Various shims -->
-	<script src="shim.js"></script>
-
-	<!-- SheetJS js-xlsx library -->
-	<script src="xlsx.full.min.js"></script>
-
-	<!-- SheetJS Vue components -->
-	<script src="SheetJS-vue.js"></script>
-
-<style>
-.grid1 {
-	width: 500px;
-	height: 400px;
-};
-</style>
-</head>
-<body>
-<pre>
-<b><a href="http://sheetjs.com">SheetJS + VueJS2 demo</a></b>
-
-The core library can be used as-is in Vue applications.
-The <a href="https://github.com/sheetjs/js-xlsx">Community Edition README</a> details some common use cases.
-We also have some <a href="http://sheetjs.com/demos/">more public demos</a>
-
-This demo shows a sample Vue component "html-preview" that:
-- displays a file input that accepts a spreadsheet file
-- draws the first worksheet of a submitted file as HTML
-- presents an export button to generate XLSX files
-
-<a href="https://obamawhitehouse.archives.gov/sites/default/files/omb/budget/fy2014/assets/receipts.xls">Sample Spreadsheet</a>
-</pre>
-<script type="text/javascript">
-	var _gaq = _gaq || [];
-	_gaq.push(['_setAccount', 'UA-36810333-1']);
-	_gaq.push(['_trackPageview']);
-
-	(function() {
-		var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
-		ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
-		var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
-	})();
-</script>
-
-<div id="app">
-	<html-preview></html-preview>
-</div>
-
-<script lang="javascript">
-if(Vue.component) var app = new Vue({ el: '#app' });
-else app.mount('#app');
-</script>
-</body>
-</html>
-
diff --git a/demos/vue/index3.html b/demos/vue/index3.html
deleted file mode 100644
index c095d70..0000000
--- a/demos/vue/index3.html
+++ /dev/null
@@ -1,63 +0,0 @@
-<!DOCTYPE html>
-<!-- xlsx.js (C) 2013-present  SheetJS http://sheetjs.com -->
-<!-- vim: set ts=2: -->
-<html>
-<head>
-	<title>SheetJS + VueJS3</title>
-	<!-- Vue 2 -->
-	<script src="https://unpkg.com/vue@3.x"></script>
-
-	<!-- Various shims -->
-	<script src="shim.js"></script>
-
-	<!-- SheetJS js-xlsx library -->
-	<script src="xlsx.full.min.js"></script>
-
-	<!-- SheetJS Vue components -->
-	<script src="SheetJS-vue.js"></script>
-
-<style>
-.grid1 {
-	width: 500px;
-	height: 400px;
-};
-</style>
-</head>
-<body>
-<pre>
-<b><a href="http://sheetjs.com">SheetJS + VueJS3 demo</a></b>
-
-The core library can be used as-is in Vue applications.
-The <a href="https://github.com/sheetjs/js-xlsx">Community Edition README</a> details some common use cases.
-We also have some <a href="http://sheetjs.com/demos/">more public demos</a>
-
-This demo shows a sample Vue component "html-preview" that:
-- displays a file input that accepts a spreadsheet file
-- draws the first worksheet of a submitted file as HTML
-- presents an export button to generate XLSX files
-
-<a href="https://obamawhitehouse.archives.gov/sites/default/files/omb/budget/fy2014/assets/receipts.xls">Sample Spreadsheet</a>
-</pre>
-<script type="text/javascript">
-	var _gaq = _gaq || [];
-	_gaq.push(['_setAccount', 'UA-36810333-1']);
-	_gaq.push(['_trackPageview']);
-
-	(function() {
-		var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
-		ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
-		var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
-	})();
-</script>
-
-<div id="app">
-	<html-preview></html-preview>
-</div>
-
-<script lang="javascript">
-if(Vue.component) var app = new Vue({ el: '#app' });
-else app.mount('#app');
-</script>
-</body>
-</html>
-
diff --git a/demos/vue/modify/.gitignore b/demos/vue/modify/.gitignore
deleted file mode 100644
index a547bf3..0000000
--- a/demos/vue/modify/.gitignore
+++ /dev/null
@@ -1,24 +0,0 @@
-# Logs
-logs
-*.log
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-pnpm-debug.log*
-lerna-debug.log*
-
-node_modules
-dist
-dist-ssr
-*.local
-
-# Editor directories and files
-.vscode/*
-!.vscode/extensions.json
-.idea
-.DS_Store
-*.suo
-*.ntvs*
-*.njsproj
-*.sln
-*.sw?
diff --git a/demos/vue/modify/README.md b/demos/vue/modify/README.md
deleted file mode 100644
index 4d76306..0000000
--- a/demos/vue/modify/README.md
+++ /dev/null
@@ -1,10 +0,0 @@
-# vue-modify
-
-This demo shows import an export with `vue3-table-light` table component.
-
-In this directory, run
-
-```bash
-npm i
-npm run dev
-```
diff --git a/demos/vue/modify/index.html b/demos/vue/modify/index.html
deleted file mode 100644
index 867581c..0000000
--- a/demos/vue/modify/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-  <head>
-    <meta charset="UTF-8" />
-    <link rel="icon" type="image/svg+xml" href="favicon.svg" />
-    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <title>Vite App</title>
-  </head>
-  <body>
-    <div id="app"></div>
-    <script type="module" src="/src/main.ts"></script>
-  </body>
-</html>
diff --git a/demos/vue/modify/package.json b/demos/vue/modify/package.json
deleted file mode 100644
index e39cc11..0000000
--- a/demos/vue/modify/package.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-  "name": "vue-modify",
-  "private": true,
-  "version": "0.0.0",
-  "scripts": {
-    "dev": "vite --host",
-    "build": "vue-tsc --noEmit && vite build",
-    "preview": "vite preview"
-  },
-  "dependencies": {
-    "vue": "^3.2.25",
-    "vue3-table-lite": "^1.1.7-1",
-    "xlsx": "https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz"
-  },
-  "devDependencies": {
-    "@vitejs/plugin-vue": "^2.2.0",
-    "typescript": "^4.5.4",
-    "vite": "^2.8.0",
-    "vue-tsc": "^0.29.8"
-  }
-}
diff --git a/demos/vue/modify/src/App.vue b/demos/vue/modify/src/App.vue
deleted file mode 100644
index 2b1f5ec..0000000
--- a/demos/vue/modify/src/App.vue
+++ /dev/null
@@ -1,241 +0,0 @@
-<script setup lang="ts">
-import { ref } from "vue";
-import { read, utils, writeFile, WorkBook } from "xlsx";
-
-import VueTableLite from "vue3-table-lite/ts";
-
-type DataSet = {
-  [index: string]: WorkBook;
-};
-
-type Row = any[];
-
-type Column = {
-  field: string;
-  label: string;
-  display: (row: Row) => string;
-};
-
-const currFileName = ref<string>("");
-const currSheet = ref<string>("");
-const sheets = ref<string[]>([]);
-const workBook = ref<DataSet>({} as DataSet);
-const rows = ref<Row[]>([]);
-const columns = ref<Column[]>([]);
-
-const exportTypes: string[] = ["xlsx", "xlsb", "csv", "html"];
-
-let cell = 0;
-
-function resetCell() {
-  cell = 0;
-}
-
-function display(col: number): (row: Row) => string {
-  return function (row: Row) {
-    return `<span
-               style="user-select: none; display: block"
-               position="${Math.floor(cell++ / columns.value.length)}.${col}"
-               onblur="endEdit(event)"
-               ondblclick="startEdit(event)"
-               onkeydown="endEdit(event)">${row[col] ?? "&nbsp;"}</span>`;
-  };
-}
-
-window.startEdit = function (ev) {
-  ev.target.contentEditable = true;
-  ev.target.focus();
-};
-
-window.endEdit = function (ev) {
-  if (ev.key === undefined || ev.key === "Enter") {
-    const pos = ev.target.getAttribute("position").split(".");
-
-    ev.target.contentEditable = false;
-
-    rows.value[pos[0]][pos[1]] = ev.target.innerText;
-
-    workBook.value[currSheet.value] = utils.json_to_sheet(rows.value, {
-      header: columns.value.map((col: Column) => col.field),
-      skipHeader: true,
-    });
-  }
-};
-
-function getRowsCols(
-  data: DataSet,
-  sheetName: string
-): {
-  rows: Row[];
-  cols: Column[];
-} {
-  const rows: Row[] = utils.sheet_to_json(data[sheetName], { header: 1 });
-  let cols: Column[] = [];
-
-  for (let row of rows) {
-    const keys: string[] = Object.keys(row);
-
-    if (keys.length > cols.length) {
-      cols = keys.map((key) => {
-        return {
-          field: key,
-          label: utils.encode_col(+key),
-          display: display(key),
-        };
-      });
-    }
-  }
-
-  return { rows, cols };
-}
-
-async function importFile(ev: ChangeEvent<HTMLInputElement>): Promise<void> {
-  const file = ev.target.files[0];
-  const data = read(await file.arrayBuffer());
-
-  currFileName.value = file.name;
-  currSheet.value = data.SheetNames?.[0];
-  sheets.value = data.SheetNames;
-  workBook.value = data.Sheets;
-
-  selectSheet(currSheet.value);
-}
-
-function exportFile(type: string): void {
-  const wb = utils.book_new();
-
-  sheets.value.forEach((sheet) => {
-    utils.book_append_sheet(wb, workBook.value[sheet], sheet);
-  });
-
-  writeFile(wb, `sheet.${type}`);
-}
-
-function selectSheet(sheet: string): void {
-  const { rows: newRows, cols: newCols } = getRowsCols(workBook.value, sheet);
-
-  resetCell();
-
-  rows.value = newRows;
-  columns.value = newCols;
-  currSheet.value = sheet;
-}
-</script>
-
-<template>
-  <header class="imp-exp">
-    <div class="import">
-      <input type="file" id="import" @change="importFile" />
-      <label for="import">import</label>
-    </div>
-    <span>{{ currFileName || "vue-modify demo" }}</span>
-    <div class="export">
-      <span>export</span>
-      <ul>
-        <li v-for="type in exportTypes" @click="exportFile(type)">
-          {{ `.${type}` }}
-        </li>
-      </ul>
-    </div>
-  </header>
-  <div class="sheets">
-    <span
-      v-for="sheet in sheets"
-      @click="selectSheet(sheet)"
-      :class="[currSheet === sheet ? 'selected' : '']"
-    >
-      {{ sheet }}
-    </span>
-  </div>
-  <vue-table-lite
-    :is-static-mode="true"
-    :page-size="50"
-    :columns="columns"
-    :rows="rows"
-  ></vue-table-lite>
-</template>
-
-<style>
-.imp-exp {
-  display: flex;
-  justify-content: space-between;
-  padding: 0.5rem;
-  font-family: mono;
-  color: #212529;
-}
-
-.import {
-  font-size: medium;
-}
-
-.import input {
-  position: absolute;
-  opacity: 0;
-  cursor: pointer;
-}
-
-.import label {
-  background-color: white;
-  border: 1px solid;
-  padding: 0.3rem;
-}
-
-.export: hover {
-  border-bottom: none;
-}
-
-.export:hover ul {
-  display: block;
-}
-
-.export span {
-  padding: 0.3rem;
-  border: 1px solid;
-  cursor: pointer;
-}
-
-.export ul {
-  display: none;
-  position: absolute;
-  z-index: 5;
-  background-color: white;
-  list-style: none;
-  padding: 0.3rem;
-  border: 1px solid;
-  margin-top: 0.3rem;
-  border-top: none;
-}
-
-.export ul li {
-  padding: 0.3rem;
-  text-align: center;
-}
-
-.export ul li:hover {
-  background-color: lightgray;
-  cursor: pointer;
-}
-
-.sheets {
-  display: flex;
-  justify-content: center;
-  margin: 0.3rem;
-  color: #212529;
-}
-
-.sheets span {
-  border: 1px solid;
-  padding: 0.5rem;
-  margin: 0.3rem;
-}
-
-.sheets span:hover:not(.selected) {
-  background-color: lightgray;
-  cursor: pointer;
-}
-
-.selected {
-  background-color: #343a40;
-  color: white;
-}
-</style>
diff --git a/demos/vue/modify/src/env.d.ts b/demos/vue/modify/src/env.d.ts
deleted file mode 100644
index aafef95..0000000
--- a/demos/vue/modify/src/env.d.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-/// <reference types="vite/client" />
-
-declare module '*.vue' {
-  import type { DefineComponent } from 'vue'
-  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
-  const component: DefineComponent<{}, {}, any>
-  export default component
-}
diff --git a/demos/vue/modify/src/main.ts b/demos/vue/modify/src/main.ts
deleted file mode 100644
index 684d042..0000000
--- a/demos/vue/modify/src/main.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import { createApp } from 'vue';
-import App from './App.vue';
-
-createApp(App).mount('#app');
diff --git a/demos/vue/modify/tsconfig.json b/demos/vue/modify/tsconfig.json
deleted file mode 100644
index af31eb8..0000000
--- a/demos/vue/modify/tsconfig.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
-  "compilerOptions": {
-    "target": "esnext",
-    "useDefineForClassFields": true,
-    "module": "esnext",
-    "moduleResolution": "node",
-    "strict": true,
-    "jsx": "preserve",
-    "sourceMap": true,
-    "resolveJsonModule": true,
-    "esModuleInterop": true,
-    "lib": ["esnext", "dom"]
-  },
-  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
-  "references": [{ "path": "./tsconfig.node.json" }]
-}
diff --git a/demos/vue/modify/tsconfig.node.json b/demos/vue/modify/tsconfig.node.json
deleted file mode 100644
index e993792..0000000
--- a/demos/vue/modify/tsconfig.node.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "compilerOptions": {
-    "composite": true,
-    "module": "esnext",
-    "moduleResolution": "node"
-  },
-  "include": ["vite.config.ts"]
-}
diff --git a/demos/vue/modify/vite.config.ts b/demos/vue/modify/vite.config.ts
deleted file mode 100644
index 315212d..0000000
--- a/demos/vue/modify/vite.config.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { defineConfig } from 'vite'
-import vue from '@vitejs/plugin-vue'
-
-// https://vitejs.dev/config/
-export default defineConfig({
-  plugins: [vue()]
-})
diff --git a/demos/vue/shim.js b/demos/vue/shim.js
deleted file mode 120000
index 7ec5819..0000000
--- a/demos/vue/shim.js
+++ /dev/null
@@ -1 +0,0 @@
-../../shim.js
\ No newline at end of file
diff --git a/demos/vue/xlsx.full.min.js b/demos/vue/xlsx.full.min.js
deleted file mode 120000
index dbca48d..0000000
--- a/demos/vue/xlsx.full.min.js
+++ /dev/null
@@ -1 +0,0 @@
-../../dist/xlsx.full.min.js
\ No newline at end of file
diff --git a/demos/xspreadsheet/README.md b/demos/xspreadsheet/README.md
index 2321769..5d21b9e 100644
--- a/demos/xspreadsheet/README.md
+++ b/demos/xspreadsheet/README.md
@@ -5,62 +5,14 @@ with other JS libraries such as data grids for previewing data.  With a familiar
 UI, [`x-spreadsheet`](https://myliang.github.io/x-spreadsheet/) is an excellent
 choice for developers looking for a modern editor.
 
-This demo is available at <https://oss.sheetjs.com/sheetjs/x-spreadsheet.html>
+[The new docs](https://docs.sheetjs.com/docs/demos/grid/#x-spreadsheet)
+include more detail and examples.
 
-## Obtaining the Library
+The original demo is available at <https://docs.sheetjs.com/xspreadsheet/>
 
-The `x-data-spreadsheet` NodeJS packages include a minified script that can be
-directly inserted as a script tag.  The unpkg CDN also serves this script:
+A hosted version of the `xlsxspread.js` script is available on the SheetJS CDN:
 
-```html
-<script src="https://unpkg.com/x-data-spreadsheet/dist/xspreadsheet.js"></script>
-```
-
-## Previewing Data
-
-The HTML document needs a container element:
-
-```html
-<div id="gridctr"></div>
-```
-
-Grid initialization is a one-liner:
-
-```js
-/* note that the browser build exposes the variable `x` */
-var grid = x_spreadsheet(document.getElementById("gridctr"));
-```
-
-The following function converts data from SheetJS to x-spreadsheet:
-
-```js
-/* load data */
-grid.loadData(stox(workbook_object));
-```
-
-`stox` is defined in [`xlsxspread.js`](./xlsxspread.js)
-
-## Editing
-
-`x-spreadsheet` handles the entire edit cycle. No intervention is necessary.
-
-## Saving Data
-
-`grid.getData()` returns an object that can be converted back to a worksheet:
-
-```js
-/* build workbook from the grid data */
-var new_wb = xtos(xspr.getData());
-
-/* generate download */
-XLSX.writeFile(new_wb, "SheetJS.xlsx");
-```
-
-`stox` is defined in [`xlsxspread.js`](./xlsxspread.js)
-
-## Additional Features
-
-This demo barely scratches the surface.  The underlying grid component includes
-many additional features that work with [SheetJS Pro](https://sheetjs.com/pro).
+- <https://cdn.sheetjs.com/xspreadsheet/xlsxspread.js> original script
+- <https://cdn.sheetjs.com/xspreadsheet/xlsxspread.min.js> minified
 
 [![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)
diff --git a/demos/xspreadsheet/index.html b/demos/xspreadsheet/index.html
deleted file mode 100644
index dd80a43..0000000
--- a/demos/xspreadsheet/index.html
+++ /dev/null
@@ -1,135 +0,0 @@
-<!DOCTYPE html>
-<!-- xlsx.js (C) 2013-present  SheetJS http://sheetjs.com -->
-<!-- vim: set ts=2: -->
-<html>
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<title>SheetJS + x-spreadsheet Live Demo</title>
-<style>
-#drop{
-	border:2px dashed #bbb;
-	-moz-border-radius:5px;
-	-webkit-border-radius:5px;
-	border-radius:5px;
-	padding:25px;
-	text-align:center;
-	font:20pt bold,"Vollkorn";color:#bbb
-}
-#b64data{
-	width:100%;
-}
-a { text-decoration: none }
-</style>
-<!-- x-spreadsheet stylesheet -->
-<link rel="stylesheet" href="https://unpkg.com/x-data-spreadsheet/dist/xspreadsheet.css"/>
-</head>
-<body>
-<pre>
-<b><a href="http://sheetjs.com">SheetJS Data Preview Live Demo</a></b>
-
-<a href="https://github.com/myliang/x-spreadsheet">x-spreadsheet component library</a>
-
-<a href="https://github.com/SheetJS/sheetjs">Source Code Repo</a>
-<a href="https://github.com/SheetJS/sheetjs/issues">Issues?  Something look weird?  Click here and report an issue</a>
-
-<div id="drop">Drop a spreadsheet file here to see sheet data</div>
-<input type="file" name="xlfile" id="xlf" /> ... or click here to select a file
-<textarea id="b64data">... or paste a base64-encoding here</textarea>
-</pre>
-<p><input type="submit" value="Export to XLSX!" id="xport" onclick="export_xlsx();"></p>
-<div id="htmlout"></div>
-<br />
-<script src="https://unpkg.com/x-data-spreadsheet/dist/xspreadsheet.js"></script>
-<script src="shim.js"></script>
-<script src="xlsx.full.min.js"></script>
-<script src="xlsxspread.js"></script>
-<script>
-/*jshint browser:true */
-/* eslint-env browser */
-/* eslint no-use-before-define:0 */
-/*global Uint8Array, Uint16Array, ArrayBuffer */
-/*global XLSX */
-
-var HTMLOUT = document.getElementById('htmlout');
-var xspr = x_spreadsheet(HTMLOUT);
-HTMLOUT.style.height = (window.innerHeight - 400) + "px";
-HTMLOUT.style.width = (window.innerWidth - 50) + "px";
-
-var process_wb = (function() {
-	var XPORT = document.getElementById('xport');
-
-	return function process_wb(wb) {
-		/* convert to x-spreadsheet form */
-		var data = stox(wb);
-
-		/* update x-spreadsheet */
-		xspr.loadData(data);
-		XPORT.disabled = false;
-
-		if(typeof console !== 'undefined') console.log("output", new Date());
-	};
-})();
-
-var do_file = (function() {
-	return function do_file(files) {
-		var f = files[0];
-		var reader = new FileReader();
-		reader.onload = function(e) {
-			if(typeof console !== 'undefined') console.log("onload", new Date());
-			var data = e.target.result;
-			data = new Uint8Array(data);
-			process_wb(XLSX.read(data, {type: 'array'}));
-		};
-		reader.readAsArrayBuffer(f);
-	};
-})();
-
-(function() {
-	var drop = document.getElementById('drop');
-	if(!drop.addEventListener) return;
-
-	function handleDrop(e) {
-		e.stopPropagation();
-		e.preventDefault();
-		do_file(e.dataTransfer.files);
-	}
-
-	function handleDragover(e) {
-		e.stopPropagation();
-		e.preventDefault();
-		e.dataTransfer.dropEffect = 'copy';
-	}
-
-	drop.addEventListener('dragenter', handleDragover, false);
-	drop.addEventListener('dragover', handleDragover, false);
-	drop.addEventListener('drop', handleDrop, false);
-})();
-
-(function() {
-	var xlf = document.getElementById('xlf');
-	if(!xlf.addEventListener) return;
-	function handleFile(e) { do_file(e.target.files); }
-	xlf.addEventListener('change', handleFile, false);
-})();
-
-function export_xlsx() {
-	var new_wb = xtos(xspr.getData());
-
-	/* write file and trigger a download */
-	XLSX.writeFile(new_wb, 'sheetjs.xlsx', {});
-}
-</script>
-<script type="text/javascript">
-/* eslint no-use-before-define:0 */
-	var _gaq = _gaq || [];
-	_gaq.push(['_setAccount', 'UA-36810333-1']);
-	_gaq.push(['_trackPageview']);
-
-	(function() {
-		var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
-		ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
-		var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
-	})();
-</script>
-</body>
-</html>
diff --git a/demos/xspreadsheet/shim.js b/demos/xspreadsheet/shim.js
deleted file mode 120000
index 7ec5819..0000000
--- a/demos/xspreadsheet/shim.js
+++ /dev/null
@@ -1 +0,0 @@
-../../shim.js
\ No newline at end of file
diff --git a/demos/xspreadsheet/xlsx.full.min.js b/demos/xspreadsheet/xlsx.full.min.js
deleted file mode 120000
index dbca48d..0000000
--- a/demos/xspreadsheet/xlsx.full.min.js
+++ /dev/null
@@ -1 +0,0 @@
-../../dist/xlsx.full.min.js
\ No newline at end of file
diff --git a/demos/xspreadsheet/xlsxspread.js b/demos/xspreadsheet/xlsxspread.js
index d4b88f9..cced956 100644
--- a/demos/xspreadsheet/xlsxspread.js
+++ b/demos/xspreadsheet/xlsxspread.js
@@ -2,6 +2,7 @@
 /* eslint-env browser */
 /*global XLSX */
 /*exported stox, xtos */
+console.log("The latest version of the xlsxspread.js script is at https://cdn.sheetjs.com/xspreadsheet/xlsxspread.js !")
 
 /**
  * Converts data from SheetJS to x-spreadsheet
@@ -129,3 +130,4 @@ function xtos(sdata) {
 
   return out;
 }
+