├── src ├── assets │ └── .gitkeep ├── app │ ├── app.component.html │ ├── app.component.ts │ ├── app.routes.ts │ ├── revealer │ │ ├── revealer.module.ts │ │ ├── revealer.component.css │ │ ├── revealer.component.html │ │ └── revealer.component.ts │ └── app.module.ts ├── styles.css ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── typings.d.ts ├── tsconfig.app.json ├── main.ts ├── index.html └── polyfills.ts ├── dist ├── styles.34c57ab7888ec1573f9c.css ├── runtime.a66f828dca56eeb90e02.js ├── index.html ├── scripts.3bb0e4e9ce73a32a2222.js ├── 3rdpartylicenses.txt └── polyfills.700e3909f17f72cff20f.js ├── .gitignore ├── index.html ├── tsconfig.json ├── package.json ├── angular.json └── README /src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dist/styles.34c57ab7888ec1573f9c.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | *~ 4 | -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | directory: '/preference-revealer/dist' 4 | }; 5 | -------------------------------------------------------------------------------- /src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | 4 | @Component({ 5 | selector: 'app-root', 6 | templateUrl: './app.component.html', 7 | styleUrls: [] 8 | }) 9 | export class AppComponent { 10 | } 11 | -------------------------------------------------------------------------------- /src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "baseUrl": "./", 6 | "module": "es2015", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "test.ts", 11 | "**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/app/app.routes.ts: -------------------------------------------------------------------------------- 1 | import { Routes, RouterModule } from '@angular/router'; 2 | import { RevealerComponent } from './revealer/revealer.component'; 3 | 4 | 5 | export const routes: Routes = [ 6 | { path: '', component: RevealerComponent } 7 | ]; 8 | 9 | export const appRoutingProviders: any[] = [ 10 | 11 | ]; 12 | 13 | export const routing = RouterModule.forRoot(routes); 14 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule); 12 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "target": "es5", 11 | "typeRoots": [ 12 | "node_modules/@types" 13 | ], 14 | "lib": [ 15 | "es2017", 16 | "dom" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false, 8 | directory: '' 9 | }; 10 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Preference Revealer 6 | 7 | 8 | 9 | 10 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/app/revealer/revealer.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { RouterModule } from '@angular/router'; 5 | 6 | import { RevealerComponent } from './revealer.component'; 7 | 8 | @NgModule({ 9 | imports: [ 10 | CommonModule, 11 | FormsModule, 12 | RouterModule 13 | ], 14 | declarations: [ 15 | RevealerComponent 16 | ], 17 | providers: [ 18 | ], 19 | exports: [ 20 | RevealerComponent 21 | ] 22 | }) 23 | export class RevealerModule { } 24 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { FormsModule } from '@angular/forms'; 3 | import { NgModule } from '@angular/core'; 4 | 5 | import { routing, appRoutingProviders } from './app.routes'; 6 | 7 | import { AppComponent } from './app.component'; 8 | import { RevealerModule } from './revealer/revealer.module'; 9 | 10 | @NgModule({ 11 | declarations: [ 12 | AppComponent 13 | ], 14 | imports: [ 15 | BrowserModule, 16 | FormsModule, 17 | routing, 18 | RevealerModule 19 | ], 20 | providers: [ 21 | appRoutingProviders 22 | ], 23 | bootstrap: [ AppComponent ] 24 | }) 25 | export class AppModule { } 26 | -------------------------------------------------------------------------------- /dist/runtime.a66f828dca56eeb90e02.js: -------------------------------------------------------------------------------- 1 | !function(r){function e(e){for(var t,p,c=e[0],a=e[1],f=e[2],l=0,s=[];l 2 | 3 | 4 | 5 | Preference Revealer 6 | 7 | 8 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/app/revealer/revealer.component.css: -------------------------------------------------------------------------------- 1 | nav { 2 | background: black; 3 | min-height: 36px; 4 | color: #9d9d9d; 5 | margin-bottom: 16px; 6 | } 7 | 8 | .nav-box { 9 | justify-content: space-between; 10 | padding: 10px; 11 | user-select: none; 12 | } 13 | .logo { 14 | flex-grow: 2; 15 | margin: 0; 16 | } 17 | 18 | .logo a { 19 | text-decoration: none; 20 | color: inherit; 21 | } 22 | 23 | .about { 24 | position: relative; 25 | top: 6px; 26 | cursor: pointer; 27 | } 28 | 29 | div.full { 30 | display: flex; 31 | } 32 | 33 | div.btn-bar { 34 | justify-content: center; 35 | margin-bottom: 16px; 36 | } 37 | 38 | div.btn-bar button { 39 | margin-bottom: 8px; 40 | } 41 | 42 | textarea { 43 | flex-grow: 2; 44 | height: 24em; 45 | padding: 5px; 46 | margin-bottom: 16px; 47 | } 48 | 49 | div.choice span { 50 | margin: 10px; 51 | user-select: none; 52 | } 53 | 54 | div.choice button { 55 | min-width: 100px; 56 | white-space: normal; /* !important;*/ 57 | word-wrap: break-word; 58 | } 59 | 60 | a { 61 | user-select: none; 62 | cursor: pointer; 63 | word-wrap: break-word; 64 | } 65 | 66 | div.modal { 67 | display: block; 68 | } 69 | 70 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "preference-revealer", 3 | "description": "Sorts a list of items by asking you to make pairwise comparisons.", 4 | "version": "2.0.0", 5 | "license": "CC-BY-3.0-SA", 6 | "scripts": { 7 | "ng": "ng", 8 | "start": "ng serve", 9 | "build": "ng build --prod --base-href /preference-revealer/dist/" 10 | }, 11 | "private": true, 12 | "dependencies": { 13 | "@angular/animations": "^6.1.4", 14 | "@angular/common": "^6.1.4", 15 | "@angular/compiler": "^6.1.4", 16 | "@angular/core": "^6.1.4", 17 | "@angular/forms": "^6.1.4", 18 | "@angular/http": "^6.1.4", 19 | "@angular/platform-browser": "^6.1.4", 20 | "@angular/platform-browser-dynamic": "^6.1.4", 21 | "@angular/router": "^6.1.4", 22 | "@types/js-base64": "^2.1.5", 23 | "core-js": "^2.5.1", 24 | "js-base64": "^2.3.2", 25 | "lzwcompress": "^0.2.4", 26 | "rxjs": "^6.2.2", 27 | "zone.js": "^0.8.26" 28 | }, 29 | "devDependencies": { 30 | "@angular/cli": "^6.1.5", 31 | "@angular/compiler-cli": "^6.1.4", 32 | "@angular/language-service": "^6.1.4", 33 | "typescript": "~2.9.2", 34 | "@angular-devkit/build-angular": "~0.6.8" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /dist/scripts.3bb0e4e9ce73a32a2222.js: -------------------------------------------------------------------------------- 1 | "use strict";(function(){var r=function(r,e,n){var t={},o=!1,i=function(r){try{console.log("lzwCompress: "+(new Date).toISOString()+" : "+("object"==typeof r?e.stringify(r):r))}catch(r){}};return function(r,e,n){var u=[],f=function(r){return function(e){return e===r}},c=function(r,e,n){(function(r,e){for(var n=0;n= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/ 22 | // import 'core-js/es6/symbol'; 23 | // import 'core-js/es6/object'; 24 | // import 'core-js/es6/function'; 25 | // import 'core-js/es6/parse-int'; 26 | // import 'core-js/es6/parse-float'; 27 | // import 'core-js/es6/number'; 28 | // import 'core-js/es6/math'; 29 | // import 'core-js/es6/string'; 30 | // import 'core-js/es6/date'; 31 | // import 'core-js/es6/array'; 32 | // import 'core-js/es6/regexp'; 33 | // import 'core-js/es6/map'; 34 | // import 'core-js/es6/weak-map'; 35 | // import 'core-js/es6/set'; 36 | 37 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 38 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 39 | 40 | /** Evergreen browsers require these. **/ 41 | import 'core-js/es6/reflect'; 42 | import 'core-js/es7/reflect'; 43 | 44 | 45 | /** 46 | * Required to support Web Animations `@angular/animation`. 47 | * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation 48 | **/ 49 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 50 | 51 | 52 | 53 | /*************************************************************************************************** 54 | * Zone JS is required by Angular itself. 55 | */ 56 | import 'zone.js/dist/zone'; // Included with Angular CLI. 57 | 58 | 59 | 60 | /*************************************************************************************************** 61 | * APPLICATION IMPORTS 62 | */ 63 | 64 | /** 65 | * Date, currency, decimal and percent pipes. 66 | * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10 67 | */ 68 | // import 'intl'; // Run `npm install --save intl`. 69 | /** 70 | * Need to import at least one locale-data with intl. 71 | */ 72 | // import 'intl/locale-data/jsonp/en'; 73 | -------------------------------------------------------------------------------- /src/app/revealer/revealer.component.html: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 |
10 |

The preference revealer sorts a list of items by asking you to make comparisons between pairs.

11 |

Enter your items in the area below with each entry on a separate line.

12 | 13 | 14 |
15 |
16 | 17 |
18 | 19 |
20 | 21 | or 22 | 23 |
24 | 25 |
26 | {{baseUrl}}/... 27 |
28 | 29 |
30 |
31 | 32 |
33 |
34 |
{{getProgress()}}
35 |
36 | 37 |
38 | 39 | or 40 | 41 |
42 |
43 | 44 |
45 |

{{name}}’s results:

46 |

Your results:

47 |
48 |
    49 |
  1. {{i}}
  2. 50 |
51 |
52 | 53 |

Share and enjoy!

54 |

Options to share your results or list:

55 | 56 |
57 |
58 | 59 | 60 |
61 |
62 | 63 | or 64 | 65 |
66 | 67 |
68 | {{encoded}} 69 |
70 | 71 |
72 |
73 | 74 | 96 | 97 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "prefs": { 7 | "root": "", 8 | "sourceRoot": "src", 9 | "projectType": "application", 10 | "architect": { 11 | "build": { 12 | "builder": "@angular-devkit/build-angular:browser", 13 | "options": { 14 | "outputPath": "dist", 15 | "index": "src/index.html", 16 | "main": "src/main.ts", 17 | "tsConfig": "src/tsconfig.app.json", 18 | "polyfills": "src/polyfills.ts", 19 | "assets": [ 20 | "src/assets", 21 | "src/favicon.ico" 22 | ], 23 | "styles": [ 24 | "src/styles.css" 25 | ], 26 | "scripts": [ 27 | "node_modules/lzwcompress/lzwCompress.js" 28 | ] 29 | }, 30 | "configurations": { 31 | "production": { 32 | "optimization": true, 33 | "outputHashing": "all", 34 | "sourceMap": false, 35 | "extractCss": true, 36 | "namedChunks": false, 37 | "aot": true, 38 | "extractLicenses": true, 39 | "vendorChunk": false, 40 | "buildOptimizer": true, 41 | "fileReplacements": [ 42 | { 43 | "replace": "src/environments/environment.ts", 44 | "with": "src/environments/environment.prod.ts" 45 | } 46 | ] 47 | } 48 | } 49 | }, 50 | "serve": { 51 | "builder": "@angular-devkit/build-angular:dev-server", 52 | "options": { 53 | "browserTarget": "prefs:build" 54 | }, 55 | "configurations": { 56 | "production": { 57 | "browserTarget": "prefs:build:production" 58 | } 59 | } 60 | }, 61 | "extract-i18n": { 62 | "builder": "@angular-devkit/build-angular:extract-i18n", 63 | "options": { 64 | "browserTarget": "prefs:build" 65 | } 66 | }, 67 | "test": { 68 | "builder": "@angular-devkit/build-angular:karma", 69 | "options": { 70 | "main": "src/test.ts", 71 | "karmaConfig": "./karma.conf.js", 72 | "polyfills": "src/polyfills.ts", 73 | "tsConfig": "src/tsconfig.spec.json", 74 | "scripts": [ 75 | "node_modules/lzwcompress/lzwCompress.js" 76 | ], 77 | "styles": [ 78 | "src/styles.css" 79 | ], 80 | "assets": [ 81 | "src/assets", 82 | "src/favicon.ico" 83 | ] 84 | } 85 | }, 86 | "lint": { 87 | "builder": "@angular-devkit/build-angular:tslint", 88 | "options": { 89 | "tsConfig": [ 90 | "src/tsconfig.app.json", 91 | "src/tsconfig.spec.json" 92 | ], 93 | "exclude": [ 94 | "**/node_modules/**" 95 | ] 96 | } 97 | } 98 | } 99 | }, 100 | "prefs-e2e": { 101 | "root": "", 102 | "sourceRoot": "e2e", 103 | "projectType": "application", 104 | "architect": { 105 | "e2e": { 106 | "builder": "@angular-devkit/build-angular:protractor", 107 | "options": { 108 | "protractorConfig": "./protractor.conf.js", 109 | "devServerTarget": "prefs:serve" 110 | } 111 | }, 112 | "lint": { 113 | "builder": "@angular-devkit/build-angular:tslint", 114 | "options": { 115 | "tsConfig": [ 116 | "e2e/tsconfig.e2e.json" 117 | ], 118 | "exclude": [ 119 | "**/node_modules/**" 120 | ] 121 | } 122 | } 123 | } 124 | } 125 | }, 126 | "defaultProject": "prefs", 127 | "schematics": { 128 | "@schematics/angular:class": { 129 | "spec": false 130 | }, 131 | "@schematics/angular:component": { 132 | "spec": false, 133 | "inlineStyle": false, 134 | "inlineTemplate": false, 135 | "prefix": "app", 136 | "styleext": "css" 137 | }, 138 | "@schematics/angular:directive": { 139 | "spec": false, 140 | "prefix": "app" 141 | }, 142 | "@schematics/angular:guard": { 143 | "spec": false 144 | }, 145 | "@schematics/angular:module": { 146 | "spec": false 147 | }, 148 | "@schematics/angular:pipe": { 149 | "spec": false 150 | }, 151 | "@schematics/angular:service": { 152 | "spec": false 153 | } 154 | } 155 | } -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Preference Revealer v1.1 2 | 3 | https://github.com/Xomnom/Preference-Revealer 4 | 5 | v0.0, 2012-2-17: Original version. 6 | v0.1, 2012-7-31: Now strips non-whitelisted HTML tags when processing input; 7 | also minor performance tweak (original version had worse 8 | worst-case performance than is correct (by 1% or so)). 9 | v1.0, 2012-9-18: Custom links (using query string); progress bar; 10 | updated explanatory text (most of which is also in here). 11 | v1.1, 2012-9-27: When results are reached, update location bar using 12 | window.history.pushState (which only works in some modern 13 | browsers), in case user expects it to contain permalink; 14 | TODO: warn user when this fails. 15 | 16 | Preference Revealer sorts a list of items by asking you to make pairwise comparisons. 17 | (This level of decomposition isn't always appropriate, but sometimes it's invaluable.) 18 | 19 | Click [_example_] twice to see an additional example. 20 | After inputting a list, click the "Generate custom link for sharing..." button for 21 | a link to a version of the page already filled out with your list. 22 | The results page has a similar button for sharing your results. 23 | 24 | Inspired by Tōhō Sort[0][1]. 25 | Hat tip to pluffei for suggesting a general-purpose version. 26 | Many thanks to Knuth for his in-depth discussion of minimal-comparison sorting. 27 | 28 | [0] http://mainyan.sakura.ne.jp/thsort.html 29 | [1] http://freewebs.com/tohosort 30 | 31 | Unlike Tōhō Sort, which uses merge sort, Preference Revealer uses the 32 | Ford-Johnson algorithm, a.k.a. merge insertion, as described in Knuth's 33 | The Art of Computer Programming, vol. 3: Sorting and Searching. 34 | Its worst-case makes fewer comparisons than merge sort's. According to my rather 35 | hasty calculations, its average-case also tends to make one or two percent fewer. 36 | Naturally, it probably can't beat most merge sort implementations' best-case 37 | (i.e. minimum) comparisons. Its overhead makes it unsuitable for most practical 38 | applications. Here I'll describe enough of the algorithm to determine it, 39 | but see Knuth for more details. 40 | 41 | First, we group all the items into pairs, and compare each pair to find 42 | the higher item; there may be an odd one out, which we'll get back to. 43 | 44 | Then, we recur the algorithm to sort the pairs by their higher items. 45 | After that finishes, call the sequence of higher items the main chain; 46 | its elements are initially a_1 through a_k, where a_k is the highest of 47 | the higher items. 48 | 49 | It remains to insert the lower items into the main chain using binary insertion. 50 | 51 | We'll continue to call the higher items as a_1 through a_n regardless of 52 | shifts in position. We'll call the corresponding lower items b_1 through b_n. 53 | For each b_i, the lowest possible insertion position is at the bottom, and 54 | the highest is right under a_i, wherever that happens to be. So if we had 55 | an odd item, it makes sense now to call it b_n+1, befitting where it could 56 | possibly be inserted. 57 | 58 | It turns out that a very efficient ordering is to insert b_1 for free, 59 | then insert as many items as possible for at most two comparisons each 60 | (b_3 then b_2, because after b_2 it might cost three for b_3), then as 61 | many as possible for at most three each (b_5 then b_4), then for four 62 | (b_11 down to b_6), and so on, skipping nonexisting b_i, until done. 63 | 64 | To check your understanding of the algorithm, try following along on pencil 65 | and paper. Optionally, you can save the files locally and comment out 66 | the one-liner that shuffles the initial input. 67 | 68 | One other tricky portion is the code that keeps track of where the a_i get shifted. 69 | A conservative estimate would preserve the worst-case performance, but by updating 70 | the highest possible insertion position based on where the previous insertions 71 | actually go, a few comparisons can be spared here and there, which presumably 72 | also is presumed by Knuth when he calculates the average-case. 73 | 74 | This implementation started out using a stack of tokens to track state across 75 | user inputs (inspired by Wiz Zumwalt[2]), but then I started shoving data into 76 | auxiliary variables, because I couldn't figure out how to make everything work 77 | cleanly with just Forth-isms. The resulting mess, of course, is worse than 78 | having a panoply of variables to hold the state in the first place. Regardless, 79 | I currently have no plans to rewrite the guts, since everything already works. 80 | 81 | [2] http://baen.com/library/0671878468/0671878468.htm 82 | 83 | Preference Revealer by Xomnom is licensed under the Creative Commons 84 | Attribution 3.0 Unported License. To view a copy of this license, visit 85 | http://creativecommons.org/licenses/by/3.0/ or send a letter to Creative 86 | Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA. 87 | -------------------------------------------------------------------------------- /dist/3rdpartylicenses.txt: -------------------------------------------------------------------------------- 1 | core-js@2.5.1 2 | MIT 3 | Copyright (c) 2014-2017 Denis Pushkarev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | zone.js@0.8.26 24 | MIT 25 | The MIT License 26 | 27 | Copyright (c) 2016-2018 Google, Inc. 28 | 29 | Permission is hereby granted, free of charge, to any person obtaining a copy 30 | of this software and associated documentation files (the "Software"), to deal 31 | in the Software without restriction, including without limitation the rights 32 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 33 | copies of the Software, and to permit persons to whom the Software is 34 | furnished to do so, subject to the following conditions: 35 | 36 | The above copyright notice and this permission notice shall be included in 37 | all copies or substantial portions of the Software. 38 | 39 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 40 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 41 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 42 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 43 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 44 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 45 | THE SOFTWARE. 46 | 47 | isarray@1.0.0 48 | MIT 49 | MIT 50 | 51 | base64-js@1.3.0 52 | MIT 53 | The MIT License (MIT) 54 | 55 | Copyright (c) 2014 56 | 57 | Permission is hereby granted, free of charge, to any person obtaining a copy 58 | of this software and associated documentation files (the "Software"), to deal 59 | in the Software without restriction, including without limitation the rights 60 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 61 | copies of the Software, and to permit persons to whom the Software is 62 | furnished to do so, subject to the following conditions: 63 | 64 | The above copyright notice and this permission notice shall be included in 65 | all copies or substantial portions of the Software. 66 | 67 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 68 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 69 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 70 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 71 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 72 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 73 | THE SOFTWARE. 74 | 75 | js-base64@2.3.2 76 | BSD-3-Clause 77 | Copyright (c) 2014, Dan Kogai 78 | All rights reserved. 79 | 80 | Redistribution and use in source and binary forms, with or without 81 | modification, are permitted provided that the following conditions are met: 82 | 83 | * Redistributions of source code must retain the above copyright notice, this 84 | list of conditions and the following disclaimer. 85 | 86 | * Redistributions in binary form must reproduce the above copyright notice, 87 | this list of conditions and the following disclaimer in the documentation 88 | and/or other materials provided with the distribution. 89 | 90 | * Neither the name of {{{project}}} nor the names of its 91 | contributors may be used to endorse or promote products derived from 92 | this software without specific prior written permission. 93 | 94 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 95 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 96 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 97 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 98 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 99 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 100 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 101 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 102 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 103 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 104 | 105 | ieee754@1.1.12 106 | BSD-3-Clause 107 | Copyright (c) 2008, Fair Oaks Labs, Inc. 108 | All rights reserved. 109 | 110 | Redistribution and use in source and binary forms, with or without 111 | modification, are permitted provided that the following conditions are met: 112 | 113 | * Redistributions of source code must retain the above copyright notice, 114 | this list of conditions and the following disclaimer. 115 | 116 | * Redistributions in binary form must reproduce the above copyright notice, 117 | this list of conditions and the following disclaimer in the documentation 118 | and/or other materials provided with the distribution. 119 | 120 | * Neither the name of Fair Oaks Labs, Inc. nor the names of its contributors 121 | may be used to endorse or promote products derived from this software 122 | without specific prior written permission. 123 | 124 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 125 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 126 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 127 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 128 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 129 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 130 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 131 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 132 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 133 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 134 | POSSIBILITY OF SUCH DAMAGE. 135 | 136 | buffer@4.9.1 137 | MIT 138 | The MIT License (MIT) 139 | 140 | Copyright (c) Feross Aboukhadijeh, and other contributors. 141 | 142 | Permission is hereby granted, free of charge, to any person obtaining a copy 143 | of this software and associated documentation files (the "Software"), to deal 144 | in the Software without restriction, including without limitation the rights 145 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 146 | copies of the Software, and to permit persons to whom the Software is 147 | furnished to do so, subject to the following conditions: 148 | 149 | The above copyright notice and this permission notice shall be included in 150 | all copies or substantial portions of the Software. 151 | 152 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 153 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 154 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 155 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 156 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 157 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 158 | THE SOFTWARE. -------------------------------------------------------------------------------- /src/app/revealer/revealer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, ViewContainerRef } from '@angular/core'; 2 | import { Location } from '@angular/common'; 3 | import { ActivatedRoute, Router } from '@angular/router'; 4 | 5 | import { Base64 } from 'js-base64'; 6 | 7 | import { environment } from '../../environments/environment'; 8 | 9 | declare var lzwCompress:any; 10 | 11 | 12 | // see Knuth vol.3 SORTING AND SEARCHING for description of Ford-Johnson algorithm (AKA merge insertion) 13 | // negatives for distinguishing from item indices 14 | // first step is PairSORT, which invokes KEYALIGN, which invokes MERGE 15 | enum Sort { PSORT = -1, KEYSORTODD = -2, KEYSORTEVEN = -3, KEYALIGN = -4, MERGE = -5, BINSERT = -6 } 16 | 17 | @Component({ 18 | selector: 'app-revealer', 19 | templateUrl: './revealer.component.html', 20 | styleUrls: ['./revealer.component.css'] 21 | }) 22 | export class RevealerComponent implements OnInit { 23 | 24 | collapse = true; 25 | showAbout = false; 26 | baseUrl:string; 27 | list = ''; 28 | 29 | stack:Array; 30 | 31 | action:Sort; 32 | aux; 33 | 34 | items = []; 35 | itemsLen:number = -1; 36 | results = []; 37 | comps = 0; 38 | worst:number; 39 | 40 | btnOne: string; 41 | btnTwo: string; 42 | btnOneFunc; 43 | btnTwoFunc; 44 | name = ''; 45 | encoded: string; 46 | done = false; 47 | 48 | constructor(vcr:ViewContainerRef, private location:Location, private route:ActivatedRoute, private router:Router) { 49 | } 50 | 51 | ngOnInit() { 52 | this.restart(); 53 | this.baseUrl = location.origin; 54 | 55 | this.route.queryParams.subscribe( params => { 56 | 57 | const list = params['data']; 58 | if (list) { 59 | let data = lzwCompress.unpack(Base64.decode(list).split(',')); 60 | if (data.items) { 61 | this.items = data.items; 62 | this.list = data.items.join('\n'); 63 | } 64 | 65 | this.name = data.name; 66 | this.itemsLen = (data.results ? data.results.length : -1); 67 | if (this.itemsLen !== -1) { 68 | this.showResults(data.results, true); 69 | } 70 | } 71 | }); 72 | 73 | } 74 | 75 | restart() { 76 | this.comps = 0; 77 | this.stack = [ Sort.PSORT ]; 78 | this.done = false; 79 | } 80 | 81 | private log2(x:number) : number { 82 | return Math.log(x) / Math.LN2; 83 | } 84 | 85 | submitList() { 86 | this.stack = [ Sort.PSORT ]; 87 | this.done = false; 88 | 89 | this.items = this.list.split('\n'); 90 | this.itemsLen = this.items.length; 91 | 92 | for (let a = 0; a < this.itemsLen; a += 1) { 93 | // Remove whitespace-only lines. 94 | while (!(/\S/.test(this.items[a]))) { 95 | this.items.splice(a, 1); 96 | this.itemsLen -= 1; 97 | } 98 | } 99 | 100 | if (this.itemsLen > 1) { 101 | this.worst = this.itemsLen * Math.ceil(this.log2(this.itemsLen * 3 / 4)) - Math.floor((1 << Math.floor(this.log2(this.itemsLen * 6))) / 3) + Math.floor(this.log2(this.itemsLen * 6) / 2); 102 | 103 | // TODO: Use lodash shuffle 104 | 105 | // array-shuffling one-liner by Jonas Raoni Soares Silva: http://jsfromhell.com/array/shuffle 106 | for (let j, x, i = this.itemsLen; i; j = Math.floor(Math.random() * i), x = this.items[--i], this.items[i] = this.items[j], this.items[j] = x); 107 | 108 | this.aux = new Array(this.itemsLen); 109 | for (let k = 0; k < this.itemsLen; k += 1) { 110 | this.aux[k] = k; 111 | } 112 | this.beginStep(); 113 | } 114 | } 115 | 116 | beginStep() { 117 | this.action = this.stack.pop(); 118 | 119 | switch (this.action) { 120 | case Sort.PSORT: 121 | // expect this.aux to be array of indices of this.items to sort 122 | // outer layer still references this.aux, so don't destroy 123 | if (this.aux.length > 1) { 124 | if (this.aux.length % 2 == 1) { 125 | this.stack.push(this.aux[0]); 126 | this.stack.push(Sort.KEYSORTODD); 127 | this.stack = this.stack.concat(this.aux.slice(1)); 128 | } else { 129 | this.stack.push(Sort.KEYSORTEVEN); 130 | this.stack = this.stack.concat(this.aux); 131 | } 132 | this.aux = [[],[]]; 133 | this.showChoices(this.stack.pop(), this.stack.pop()); 134 | } else { 135 | this.beginStep(); 136 | } 137 | break; 138 | case Sort.KEYALIGN: // reorder losers to match sorted winners 139 | // expect this.stack[-1][0] to be array of winners of pairwise comparisons 140 | // expect this.stack[-1][1] to be array of losers of pairwise comparisons, plus odd element if exists 141 | // expect aux to be sorted array of winners 142 | let w = this.aux.length; 143 | this.aux = [this.aux, new Array(w), new Array(w), [0, 1, 0, 0]]; // first insertion 144 | // this.aux[0] is now the main chain 145 | let oldaux = this.stack.pop(); 146 | let keydict = new Array(this.itemsLen); 147 | 148 | for (let i = 0; i < w; i += 1) { 149 | keydict[oldaux[0][i]] = oldaux[1][i]; 150 | } 151 | 152 | for (let j = 0; j < w; j+= 1) { 153 | this.aux[1][j] = keydict[this.aux[0][j]]; 154 | this.aux[2][j] = 0; 155 | } 156 | if (w < oldaux[1].length) // check for odd element 157 | { 158 | this.aux[1][w] = oldaux[1][w]; 159 | } 160 | // fall through 161 | case Sort.MERGE: 162 | // expect this.aux[0] to be the main chain 163 | // expect this.aux[1] to be post-KEYALIGN array of losers, plus odd element if exists 164 | // expect this.aux[2] to be array of offsets from old indices to projected indices as main chain grows 165 | // expect this.aux[3][0] to be k 166 | // expect this.aux[3][1] to be t_k 167 | // expect this.aux[3][2] to be loser index of loser to insert 168 | // expect this.aux[3][3] to be insertion position in main chain 169 | this.aux[0].splice(this.aux[3][3], 0, this.aux[1][this.aux[3][2]]); 170 | if ((this.aux[3][2] == 0) || (this.aux[3][2] == this.aux[3][1])) { 171 | this.aux[3][0] += 1; 172 | this.aux[3][1] = (1 << this.aux[3][0]) - this.aux[3][1]; 173 | let l = this.aux[1].length; 174 | if (this.aux[3][1] < l) { 175 | this.aux[3][2] = Math.min(l - 1, (2 << this.aux[3][0]) - this.aux[3][1] - 1); 176 | this.aux[3][3] = 0; 177 | this.aux[3][4] = this.aux[3][1] + this.aux[3][2]; 178 | this.stack.push(Sort.BINSERT); 179 | } else { 180 | this.stack.push(this.aux[0]); 181 | } 182 | } else { 183 | this.aux[3][2] -= 1; 184 | let k = this.aux[3][2]; 185 | while (this.aux[3][1] + k + this.aux[2][k] >= this.aux[3][3]) // while previous insertion affects max position 186 | { 187 | this.aux[2][k] += 1; 188 | k--; // test conveniently fails when we reach old this.items we don't care about 189 | } 190 | this.aux[3][3] = 0; 191 | this.aux[3][4] = this.aux[3][1] + this.aux[3][2] + this.aux[2][this.aux[3][2]]; 192 | this.stack.push(Sort.BINSERT); 193 | } 194 | 195 | this.beginStep(); 196 | break; 197 | 198 | case Sort.BINSERT: 199 | // expect this.aux[3][0] to be k 200 | // expect this.aux[3][1] to be t_k 201 | // expect this.aux[3][2] to be loser index of loser to insert 202 | // expect this.aux[3][3] to be min position in main chain 203 | // expect this.aux[3][4] to be max position in main chain 204 | this.aux[3][5] = Math.ceil((this.aux[3][3] + this.aux[3][4]) / 2) - 1; 205 | this.showChoices(this.aux[1][this.aux[3][2]], this.aux[0][this.aux[3][5]]); 206 | break; 207 | 208 | default: 209 | // expect to have encountered sorted array 210 | if (this.stack.length > 0) { 211 | this.aux = this.action; 212 | this.beginStep(); 213 | } else { 214 | this.showResults(this.action, true); 215 | } 216 | break; 217 | } 218 | } 219 | 220 | 221 | endStep(x:Sort, y:Sort) { 222 | this.comps++; 223 | 224 | switch (this.action) { 225 | case Sort.PSORT: 226 | // expect this.aux[0] to be array of winners of pairwise comparisons 227 | // expect this.aux[1] to be array of losers of pairwise comparisons 228 | this.aux[0].push(x); 229 | this.aux[1].push(y); 230 | let popped = this.stack.pop(); 231 | if (popped < 0) { 232 | if (popped == Sort.KEYSORTODD) // other possible value is KEYSORTEVEN 233 | { 234 | this.aux[1].push(this.stack.pop()); 235 | } 236 | this.stack.push(this.aux); 237 | this.stack.push(Sort.KEYALIGN); 238 | this.stack.push(Sort.PSORT); // recur to sort winners 239 | this.aux = this.aux[0]; 240 | this.beginStep(); 241 | } else { 242 | this.showChoices(popped, this.stack.pop()); 243 | } 244 | break; 245 | case Sort.BINSERT: 246 | // expect this.aux[3][0] to be k 247 | // expect this.aux[3][1] to be t_k 248 | // expect this.aux[3][2] to be loser index of loser to insert 249 | // expect this.aux[3][3] to be min position in main chain 250 | // expect this.aux[3][4] to be max position in main chain 251 | // expect this.aux[3][5] to be main chain index of comparand 252 | if (x == this.aux[1][this.aux[3][2]]) { 253 | this.aux[3][3] = this.aux[3][5] + 1; 254 | } else { 255 | this.aux[3][4] = this.aux[3][5]; 256 | } 257 | if (this.aux[3][3] == this.aux[3][4]) { 258 | this.stack.push(Sort.MERGE); 259 | } else { 260 | this.stack.push(Sort.BINSERT); 261 | } 262 | 263 | this.beginStep(); 264 | break; 265 | } 266 | } 267 | 268 | showChoices(x:Sort, y:Sort) { 269 | this.btnOne = this.items[x]; 270 | this.btnTwo = this.items[y]; 271 | this.btnOneFunc = function(e: MouseEvent) { 272 | this.endStep(x, y); 273 | const elem = e.target as HTMLElement; 274 | elem.blur(); 275 | } 276 | this.btnTwoFunc = function(e: any) { 277 | this.endStep(y, x); 278 | const elem = e.target as HTMLElement; 279 | elem.blur(); 280 | } 281 | } 282 | 283 | getProgress() : string { 284 | if (this.worst) { 285 | return Math.floor(100 * this.comps / this.worst ) + '%'; 286 | } 287 | return '0%'; 288 | } 289 | 290 | showResults(ids:any, myResults:boolean) { 291 | this.btnOne = undefined; 292 | this.btnTwo = undefined; 293 | this.btnOneFunc = undefined; 294 | this.btnTwoFunc = undefined; 295 | this.done = true; 296 | this.encoded = undefined; 297 | 298 | if (myResults) { 299 | this.results = new Array(this.itemsLen); 300 | 301 | for (let i = 0; i < this.itemsLen; i += 1) { 302 | this.results[i] = this.items[ids[this.itemsLen - i - 1]]; 303 | } 304 | } 305 | } 306 | 307 | makeUrl(isResults:boolean) { 308 | this.items = this.list.split('\n'); 309 | let results = undefined; 310 | const nm = (isResults ? this.name : undefined); 311 | 312 | if (isResults) { 313 | results = []; 314 | for (let i = 0; i < this.itemsLen; i += 1) { 315 | results.unshift(this.items.indexOf(this.results[i])); 316 | } 317 | } 318 | 319 | try { 320 | const data = lzwCompress.pack({ items: this.items, results: results, name: nm }); 321 | this.encoded = this.baseUrl + environment.directory + '?data=' + Base64.encode(data).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '%3D'); 322 | } 323 | catch (e) { 324 | console.error(e); 325 | } 326 | } 327 | 328 | } 329 | -------------------------------------------------------------------------------- /dist/polyfills.700e3909f17f72cff20f.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[2],{"+rLv":function(t,e,n){var r=n("dyZX").document;t.exports=r&&r.documentElement},"0/R4":function(t,e){t.exports=function(t){return"object"==typeof t?null!==t:"function"==typeof t}},"0TWp":function(t,e,n){!function(){"use strict";!function(t){var e=t.performance;function n(t){e&&e.mark&&e.mark(t)}function r(t,n){e&&e.measure&&e.measure(t,n)}if(n("Zone"),t.Zone)throw new Error("Zone already loaded.");var o,i=function(){function e(t,e){this._properties=null,this._parent=t,this._name=e?e.name||"unnamed":"",this._properties=e&&e.properties||{},this._zoneDelegate=new c(this,this._parent&&this._parent._zoneDelegate,e)}return e.assertZonePatched=function(){if(t.Promise!==O.ZoneAwarePromise)throw new Error("Zone.js has detected that ZoneAwarePromise `(window|global).Promise` has been overwritten.\nMost likely cause is that a Promise polyfill has been loaded after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. If you must load one, do so before loading zone.js.)")},Object.defineProperty(e,"root",{get:function(){for(var t=e.current;t.parent;)t=t.parent;return t},enumerable:!0,configurable:!0}),Object.defineProperty(e,"current",{get:function(){return D.zone},enumerable:!0,configurable:!0}),Object.defineProperty(e,"currentTask",{get:function(){return P},enumerable:!0,configurable:!0}),e.__load_patch=function(o,i){if(O.hasOwnProperty(o))throw Error("Already loaded patch: "+o);if(!t["__Zone_disable_"+o]){var a="Zone:"+o;n(a),O[o]=i(t,e,S),r(a,a)}},Object.defineProperty(e.prototype,"parent",{get:function(){return this._parent},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"name",{get:function(){return this._name},enumerable:!0,configurable:!0}),e.prototype.get=function(t){var e=this.getZoneWith(t);if(e)return e._properties[t]},e.prototype.getZoneWith=function(t){for(var e=this;e;){if(e._properties.hasOwnProperty(t))return e;e=e._parent}return null},e.prototype.fork=function(t){if(!t)throw new Error("ZoneSpec required!");return this._zoneDelegate.fork(this,t)},e.prototype.wrap=function(t,e){if("function"!=typeof t)throw new Error("Expecting function got: "+t);var n=this._zoneDelegate.intercept(this,t,e),r=this;return function(){return r.runGuarded(n,this,arguments,e)}},e.prototype.run=function(t,e,n,r){void 0===e&&(e=void 0),void 0===n&&(n=null),void 0===r&&(r=null),D={parent:D,zone:this};try{return this._zoneDelegate.invoke(this,t,e,n,r)}finally{D=D.parent}},e.prototype.runGuarded=function(t,e,n,r){void 0===e&&(e=null),void 0===n&&(n=null),void 0===r&&(r=null),D={parent:D,zone:this};try{try{return this._zoneDelegate.invoke(this,t,e,n,r)}catch(t){if(this._zoneDelegate.handleError(this,t))throw t}}finally{D=D.parent}},e.prototype.runTask=function(t,e,n){if(t.zone!=this)throw new Error("A task can only be run in the zone of creation! (Creation: "+(t.zone||y).name+"; Execution: "+this.name+")");if(t.state!==g||t.type!==x){var r=t.state!=_;r&&t._transitionTo(_,m),t.runCount++;var o=P;P=t,D={parent:D,zone:this};try{t.type==E&&t.data&&!t.data.isPeriodic&&(t.cancelFn=null);try{return this._zoneDelegate.invokeTask(this,t,e,n)}catch(t){if(this._zoneDelegate.handleError(this,t))throw t}}finally{t.state!==g&&t.state!==w&&(t.type==x||t.data&&t.data.isPeriodic?r&&t._transitionTo(m,_):(t.runCount=0,this._updateTaskCount(t,-1),r&&t._transitionTo(g,_,g))),D=D.parent,P=o}}},e.prototype.scheduleTask=function(t){if(t.zone&&t.zone!==this)for(var e=this;e;){if(e===t.zone)throw Error("can not reschedule task to "+this.name+" which is descendants of the original zone "+t.zone.name);e=e.parent}t._transitionTo(k,g);var n=[];t._zoneDelegates=n,t._zone=this;try{t=this._zoneDelegate.scheduleTask(this,t)}catch(e){throw t._transitionTo(w,k,g),this._zoneDelegate.handleError(this,e),e}return t._zoneDelegates===n&&this._updateTaskCount(t,1),t.state==k&&t._transitionTo(m,k),t},e.prototype.scheduleMicroTask=function(t,e,n,r){return this.scheduleTask(new u(T,t,e,n,r,null))},e.prototype.scheduleMacroTask=function(t,e,n,r,o){return this.scheduleTask(new u(E,t,e,n,r,o))},e.prototype.scheduleEventTask=function(t,e,n,r,o){return this.scheduleTask(new u(x,t,e,n,r,o))},e.prototype.cancelTask=function(t){if(t.zone!=this)throw new Error("A task can only be cancelled in the zone of creation! (Creation: "+(t.zone||y).name+"; Execution: "+this.name+")");t._transitionTo(b,m,_);try{this._zoneDelegate.cancelTask(this,t)}catch(e){throw t._transitionTo(w,b),this._zoneDelegate.handleError(this,e),e}return this._updateTaskCount(t,-1),t._transitionTo(g,b),t.runCount=0,t},e.prototype._updateTaskCount=function(t,e){var n=t._zoneDelegates;-1==e&&(t._zoneDelegates=null);for(var r=0;r0,macroTask:n.macroTask>0,eventTask:n.eventTask>0,change:t})},t}(),u=function(){function e(n,r,o,i,a,c){this._zone=null,this.runCount=0,this._zoneDelegates=null,this._state="notScheduled",this.type=n,this.source=r,this.data=i,this.scheduleFn=a,this.cancelFn=c,this.callback=o;var u=this;this.invoke=n===x&&i&&i.useG?e.invokeTask:function(){return e.invokeTask.call(t,u,this,arguments)}}return e.invokeTask=function(t,e,n){t||(t=this),j++;try{return t.runCount++,t.zone.runTask(t,e,n)}finally{1==j&&d(),j--}},Object.defineProperty(e.prototype,"zone",{get:function(){return this._zone},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"state",{get:function(){return this._state},enumerable:!0,configurable:!0}),e.prototype.cancelScheduleRequest=function(){this._transitionTo(g,k)},e.prototype._transitionTo=function(t,e,n){if(this._state!==e&&this._state!==n)throw new Error(this.type+" '"+this.source+"': can not transition to '"+t+"', expecting state '"+e+"'"+(n?" or '"+n+"'":"")+", was '"+this._state+"'.");this._state=t,t==g&&(this._zoneDelegates=null)},e.prototype.toString=function(){return this.data&&void 0!==this.data.handleId?this.data.handleId:Object.prototype.toString.call(this)},e.prototype.toJSON=function(){return{type:this.type,state:this.state,source:this.source,zone:this.zone.name,runCount:this.runCount}},e}(),s=z("setTimeout"),f=z("Promise"),l=z("then"),p=[],h=!1;function v(e){0===j&&0===p.length&&(o||t[f]&&(o=t[f].resolve(0)),o?o[l](d):t[s](d,0)),e&&p.push(e)}function d(){if(!h){for(h=!0;p.length;){var t=p;p=[];for(var e=0;e=0;n--)"function"==typeof t[n]&&(t[n]=p(t[n],e+"_"+n));return t}function b(t){return!t||!1!==t.writable&&!("function"==typeof t.get&&void 0===t.set)}var w="undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope,T=!("nw"in g)&&void 0!==g.process&&"[object process]"==={}.toString.call(g.process),E=!T&&!w&&!(!d||!y.HTMLElement),x=void 0!==g.process&&"[object process]"==={}.toString.call(g.process)&&!w&&!(!d||!y.HTMLElement),O={},S=function(t){if(t=t||g.event){var e=O[t.type];e||(e=O[t.type]=v("ON_PROPERTY"+t.type));var n=(this||t.target||g)[e],r=n&&n.apply(this,arguments);return void 0==r||r||t.preventDefault(),r}};function D(n,r,o){var i=t(n,r);if(!i&&o&&t(o,r)&&(i={enumerable:!0,configurable:!0}),i&&i.configurable){delete i.writable,delete i.value;var a=i.get,c=i.set,u=r.substr(2),s=O[u];s||(s=O[u]=v("ON_PROPERTY"+u)),i.set=function(t){var e=this;e||n!==g||(e=g),e&&(e[s]&&e.removeEventListener(u,S),c&&c.apply(e,m),"function"==typeof t?(e[s]=t,e.addEventListener(u,S,!1)):e[s]=null)},i.get=function(){var t=this;if(t||n!==g||(t=g),!t)return null;var e=t[s];if(e)return e;if(a){var o=a&&a.call(this);if(o)return i.set.call(this,o),"function"==typeof t[k]&&t.removeAttribute(r),o}return null},e(n,r,i)}}function P(t,e,n){if(e)for(var r=0;r1?new c(e,n):new c(e),l=t(f,"onmessage");return l&&!1===l.configurable?(u=r(f),s=f,[i,a,"send","close"].forEach(function(t){u[t]=function(){var e=o.call(arguments);if(t===i||t===a){var n=e.length>0?e[0]:void 0;if(n){var r=Zone.__symbol__("ON_PROPERTY"+n);f[r]=u[r]}}return f[t].apply(f,e)}})):u=f,P(u,["close","error","message","open"],s),u};var u=n.WebSocket;for(var s in c)u[s]=c[s]}(0,u)}}var lt=v("unbound");Zone.__load_patch("util",function(t,e,n){n.patchOnProperties=P,n.patchMethod=z,n.bindArguments=_}),Zone.__load_patch("timers",function(t){U(t,"set","clear","Timeout"),U(t,"set","clear","Interval"),U(t,"set","clear","Immediate")}),Zone.__load_patch("requestAnimationFrame",function(t){U(t,"request","cancel","AnimationFrame"),U(t,"mozRequest","mozCancel","AnimationFrame"),U(t,"webkitRequest","webkitCancel","AnimationFrame")}),Zone.__load_patch("blocking",function(t,e){for(var n=["alert","prompt","confirm"],r=0;r=0&&"function"==typeof n[r.cbIdx]?h(r.name,n[r.cbIdx],r,i,null):t.apply(e,n)}})}()}),Zone.__load_patch("XHR",function(t,e){!function(e){var s=XMLHttpRequest.prototype,f=s[c],l=s[u];if(!f){var p=t.XMLHttpRequestEventTarget;if(p){var v=p.prototype;f=v[c],l=v[u]}}var d="readystatechange",y="scheduled";function g(t){XMLHttpRequest[i]=!1;var e=t.data,r=e.target,a=r[o];f||(f=r[c],l=r[u]),a&&l.call(r,d,a);var s=r[o]=function(){r.readyState===r.DONE&&!e.aborted&&XMLHttpRequest[i]&&t.state===y&&t.invoke()};return f.call(r,d,s),r[n]||(r[n]=t),b.apply(r,e.args),XMLHttpRequest[i]=!0,t}function k(){}function m(t){var e=t.data;return e.aborted=!0,w.apply(e.target,e.args)}var _=z(s,"open",function(){return function(t,e){return t[r]=0==e[2],t[a]=e[1],_.apply(t,e)}}),b=z(s,"send",function(){return function(t,e){return t[r]?b.apply(t,e):h("XMLHttpRequest.send",k,{target:t,url:t[a],isPeriodic:!1,delay:null,args:e,aborted:!1},g,m)}}),w=z(s,"abort",function(){return function(t){var e=t[n];if(e&&"string"==typeof e.type){if(null==e.cancelFn||e.data&&e.data.aborted)return;e.zone.cancelTask(e)}}})}();var n=v("xhrTask"),r=v("xhrSync"),o=v("xhrListener"),i=v("xhrScheduled"),a=v("xhrURL")}),Zone.__load_patch("geolocation",function(e){e.navigator&&e.navigator.geolocation&&function(e,n){for(var r=e.constructor.name,o=function(o){var i=n[o],a=e[i];if(a){if(!b(t(e,i)))return"continue";e[i]=function(t){var e=function(){return t.apply(this,_(arguments,r+"."+i))};return F(e,t),e}(a)}},i=0;i0?arguments[0]:void 0)}},{get:function(t){var e=r.getEntry(o(this,"Map"),t);return e&&e.v},set:function(t,e){return r.def(o(this,"Map"),0===t?0:t,e)}},r,!0)},"9gX7":function(t,e){t.exports=function(t,e,n,r){if(!(t instanceof e)||void 0!==r&&r in t)throw TypeError(n+": incorrect invocation!");return t}},"9rMk":function(t,e,n){var r=n("XKFU");r(r.S,"Reflect",{has:function(t,e){return e in t}})},Afnz:function(t,e,n){"use strict";var r=n("LQAc"),o=n("XKFU"),i=n("KroJ"),a=n("Mukb"),c=n("aagx"),u=n("hPIQ"),s=n("QaDb"),f=n("fyDq"),l=n("OP3Y"),p=n("K0xU")("iterator"),h=!([].keys&&"next"in[].keys()),v=function(){return this};t.exports=function(t,e,n,d,y,g,k){s(n,e,d);var m,_,b,w=function(t){if(!h&&t in O)return O[t];switch(t){case"keys":case"values":return function(){return new n(this,t)}}return function(){return new n(this,t)}},T=e+" Iterator",E="values"==y,x=!1,O=t.prototype,S=O[p]||O["@@iterator"]||y&&O[y],D=S||w(y),P=y?E?w("entries"):D:void 0,j="Array"==e&&O.entries||S;if(j&&(b=l(j.call(new t)))!==Object.prototype&&b.next&&(f(b,T,!0),r||c(b,p)||a(b,p,v)),E&&S&&"values"!==S.name&&(x=!0,D=function(){return S.call(this)}),r&&!k||!h&&!x&&O[p]||a(O,p,D),u[e]=D,u[T]=v,y)if(m={values:E?D:w("values"),keys:g?D:w("keys"),entries:P},k)for(_ in m)_ in O||i(O,_,m[_]);else o(o.P+o.F*(h||x),e,m);return m}},BqfV:function(t,e,n){var r=n("N6cJ"),o=n("y3w9"),i=r.get,a=r.key;r.exp({getOwnMetadata:function(t,e){return i(t,o(e),arguments.length<3?void 0:a(arguments[2]))}})},CkkT:function(t,e,n){var r=n("m0Pp"),o=n("Ymqv"),i=n("S/j/"),a=n("ne8i"),c=n("zRwo");t.exports=function(t,e){var n=1==t,u=2==t,s=3==t,f=4==t,l=6==t,p=5==t||l,h=e||c;return function(e,c,v){for(var d,y,g=i(e),k=o(g),m=r(c,v,3),_=a(k.length),b=0,w=n?h(e,_):u?h(e,0):void 0;_>b;b++)if((p||b in k)&&(y=m(d=k[b],b,g),t))if(n)w[b]=y;else if(y)switch(t){case 3:return!0;case 5:return d;case 6:return b;case 2:w.push(d)}else if(f)return!1;return l?-1:s||f?f:w}}},DVgA:function(t,e,n){var r=n("zhAb"),o=n("4R4u");t.exports=Object.keys||function(t){return r(t,o)}},EK0E:function(t,e,n){"use strict";var r,o=n("CkkT")(0),i=n("KroJ"),a=n("Z6vF"),c=n("czNK"),u=n("ZD67"),s=n("0/R4"),f=n("eeVq"),l=n("s5qY"),p=a.getWeak,h=Object.isExtensible,v=u.ufstore,d={},y=function(t){return function(){return t(this,arguments.length>0?arguments[0]:void 0)}},g={get:function(t){if(s(t)){var e=p(t);return!0===e?v(l(this,"WeakMap")).get(t):e?e[this._i]:void 0}},set:function(t,e){return u.def(l(this,"WeakMap"),t,e)}},k=t.exports=n("4LiD")("WeakMap",y,g,u,!0,!0);f(function(){return 7!=(new k).set((Object.freeze||Object)(d),7).get(d)})&&(c((r=u.getConstructor(y,"WeakMap")).prototype,g),a.NEED=!0,o(["delete","has","get","set"],function(t){var e=k.prototype,n=e[t];i(e,t,function(e,o){if(s(e)&&!h(e)){this._f||(this._f=new r);var i=this._f[t](e,o);return"set"==t?this:i}return n.call(this,e,o)})}))},EWmC:function(t,e,n){var r=n("LZWt");t.exports=Array.isArray||function(t){return"Array"==r(t)}},EemH:function(t,e,n){var r=n("UqcF"),o=n("RjD/"),i=n("aCFj"),a=n("apmT"),c=n("aagx"),u=n("xpql"),s=Object.getOwnPropertyDescriptor;e.f=n("nh4g")?s:function(t,e){if(t=i(t),e=a(e,!0),u)try{return s(t,e)}catch(t){}if(c(t,e))return o(!r.f.call(t,e),t[e])}},FJW5:function(t,e,n){var r=n("hswa"),o=n("y3w9"),i=n("DVgA");t.exports=n("nh4g")?Object.defineProperties:function(t,e){o(t);for(var n,a=i(e),c=a.length,u=0;c>u;)r.f(t,n=a[u++],e[n]);return t}},FZcq:function(t,e,n){n("49D4"),n("zq+C"),n("45Tv"),n("uAtd"),n("BqfV"),n("fN/3"),n("iW+S"),n("7Dlh"),n("Opxb"),t.exports=n("g3g5").Reflect},H6hf:function(t,e,n){var r=n("y3w9");t.exports=function(t,e,n,o){try{return o?e(r(n)[0],n[1]):e(n)}catch(e){var i=t.return;throw void 0!==i&&r(i.call(t)),e}}},I5cv:function(t,e,n){var r=n("XKFU"),o=n("Kuth"),i=n("2OiF"),a=n("y3w9"),c=n("0/R4"),u=n("eeVq"),s=n("8MEG"),f=(n("dyZX").Reflect||{}).construct,l=u(function(){function t(){}return!(f(function(){},[],t)instanceof t)}),p=!u(function(){f(function(){})});r(r.S+r.F*(l||p),"Reflect",{construct:function(t,e){i(t),a(e);var n=arguments.length<3?t:i(arguments[2]);if(p&&!l)return f(t,e,n);if(t==n){switch(e.length){case 0:return new t;case 1:return new t(e[0]);case 2:return new t(e[0],e[1]);case 3:return new t(e[0],e[1],e[2]);case 4:return new t(e[0],e[1],e[2],e[3])}var r=[null];return r.push.apply(r,e),new(s.apply(t,r))}var u=n.prototype,h=o(c(u)?u:Object.prototype),v=Function.apply.call(t,h,e);return c(v)?v:h}})},"I8a+":function(t,e,n){var r=n("LZWt"),o=n("K0xU")("toStringTag"),i="Arguments"==r(function(){return arguments}());t.exports=function(t){var e,n,a;return void 0===t?"Undefined":null===t?"Null":"string"==typeof(n=function(t,e){try{return t[e]}catch(t){}}(e=Object(t),o))?n:i?r(e):"Object"==(a=r(e))&&"function"==typeof e.callee?"Arguments":a}},IlFx:function(t,e,n){var r=n("XKFU"),o=n("y3w9"),i=Object.isExtensible;r(r.S,"Reflect",{isExtensible:function(t){return o(t),!i||i(t)}})},Iw71:function(t,e,n){var r=n("0/R4"),o=n("dyZX").document,i=r(o)&&r(o.createElement);t.exports=function(t){return i?o.createElement(t):{}}},"J+6e":function(t,e,n){var r=n("I8a+"),o=n("K0xU")("iterator"),i=n("hPIQ");t.exports=n("g3g5").getIteratorMethod=function(t){if(void 0!=t)return t[o]||t["@@iterator"]||i[r(t)]}},JiEa:function(t,e){e.f=Object.getOwnPropertySymbols},K0xU:function(t,e,n){var r=n("VTer")("wks"),o=n("ylqs"),i=n("dyZX").Symbol,a="function"==typeof i;(t.exports=function(t){return r[t]||(r[t]=a&&i[t]||(a?i:o)("Symbol."+t))}).store=r},KroJ:function(t,e,n){var r=n("dyZX"),o=n("Mukb"),i=n("aagx"),a=n("ylqs")("src"),c=Function.toString,u=(""+c).split("toString");n("g3g5").inspectSource=function(t){return c.call(t)},(t.exports=function(t,e,n,c){var s="function"==typeof n;s&&(i(n,"name")||o(n,"name",e)),t[e]!==n&&(s&&(i(n,a)||o(n,a,t[e]?""+t[e]:u.join(String(e)))),t===r?t[e]=n:c?t[e]?t[e]=n:o(t,e,n):(delete t[e],o(t,e,n)))})(Function.prototype,"toString",function(){return"function"==typeof this&&this[a]||c.call(this)})},Kuth:function(t,e,n){var r=n("y3w9"),o=n("FJW5"),i=n("4R4u"),a=n("YTvA")("IE_PROTO"),c=function(){},u=function(){var t,e=n("Iw71")("iframe"),r=i.length;for(e.style.display="none",n("+rLv").appendChild(e),e.src="javascript:",(t=e.contentWindow.document).open(),t.write("