diff --git a/.circleci/config.yml b/.circleci/config.yml index 4741bd89b..4276921b8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -31,6 +31,12 @@ var_6: &save_cache var_7: &yarn_install run: yarn install --frozen-lockfile --non-interactive +var_8: &attach_release_output + attach_workspace: + at: dist/ + +var_9: &release_path "releases/**/*" + attach_options: &attach_options at: . @@ -59,18 +65,37 @@ jobs: steps: - attach_workspace: *attach_options - run: yarn run build:lib + - persist_to_workspace: + root: dist + paths: + - *release_path build_cdk: <<: *job_defaults steps: - attach_workspace: *attach_options - run: yarn run build:cdk + - persist_to_workspace: + root: dist + paths: + - *release_path build_mosaic-moment-adapter: <<: *job_defaults steps: - attach_workspace: *attach_options - run: yarn run build:mosaic-moment-adapter + - persist_to_workspace: + root: dist + paths: + - *release_path + + build_dev_app_aot: + <<: *job_defaults + steps: + - *attach_release_output + - attach_workspace: *attach_options + - run: yarn run ci:aot test_unit: <<: *job_defaults @@ -133,6 +158,12 @@ workflows: - build_cdk - build_mosaic - build_mosaic-moment-adapter + - build_dev_app_aot: + requires: + - test_unit + - build_cdk + - build_mosaic + - build_mosaic-moment-adapter - snapshot_publish: requires: - test_unit diff --git a/package.json b/package.json index 2b60c4f2d..94d4759ca 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "@ptsecurity/commitlint-config": "^0.2.1", "@ptsecurity/tslint-config": "^0.10.1", "@schematics/angular": "7.1.4", + "@types/browser-sync": "^0.0.42", "@types/chalk": "^2.2.0", "@types/fs-extra": "^5.0.4", "@types/glob": "^5.0.36", @@ -56,6 +57,7 @@ "angular2-template-loader": "^0.6.2", "autoprefixer": "^9.4.2", "awesome-typescript-loader": "^5.2.1", + "browser-sync": "^2.26.3", "chalk": "^2.4.1", "conventional-changelog": "^3.0.5", "dgeni": "^0.4.10", @@ -80,6 +82,7 @@ "gulp-transform": "^2.0.0", "gulp-util": "^3.0.8", "highlight.js": "^9.13.1", + "http-rewrite-middleware": "^0.1.6", "html-webpack-plugin": "^3.2.0", "husky": "^1.3.1", "inquirer": "^6.2.1", @@ -130,6 +133,9 @@ "webpack-dev-server": "^3.1.9" }, "scripts": { + "serve:dev-app": "gulp serve:devapp", + "ci:aot": "gulp ci:aot", + "build-dev-app:aot": "gulp build-aot", "test:unit": "gulp ci:test", "valid:lic": "gulp validate-licenses", "build:cdk": "gulp cdk:build-release", diff --git a/src/dev-app/button/button-demo.html b/src/dev-app/button/button-demo.html new file mode 100644 index 000000000..da98de12e --- /dev/null +++ b/src/dev-app/button/button-demo.html @@ -0,0 +1,115 @@ +
+   + +   + +   + +   + +
+
+ + + +   + + +
+
+ + + + + + + + +
+
+ + + + + + + + +
+
+ + + + + + + + +
+
+ +   +   +   +   +   + +
+
+ +   +   +   +   +   + +
+
+
+ +   +   +   +   +   + +
+
+ +   +   +   +   +   + +
+
+
+ +   +   +   +   +   + +
+
+ +   +   +   +   +   +
diff --git a/src/dev-app/button/button-demo.scss b/src/dev-app/button/button-demo.scss new file mode 100644 index 000000000..e5f2c0f35 --- /dev/null +++ b/src/dev-app/button/button-demo.scss @@ -0,0 +1,3 @@ +.mc-button-group_vertical { + width: 200px; +} diff --git a/src/dev-app/button/button-demo.ts b/src/dev-app/button/button-demo.ts new file mode 100644 index 000000000..eb2d84a10 --- /dev/null +++ b/src/dev-app/button/button-demo.ts @@ -0,0 +1,13 @@ +import { Component } from '@angular/core'; + + +@Component({ + selector: 'button-demo', + templateUrl: 'button-demo.html', + styleUrls: ['button-demo.css'] +}) +export class ButtonDemo { + isDisabled: boolean = false; + clickCounter: number = 0; + toggleDisable: boolean = false; +} diff --git a/src/dev-app/datepicker/datepicker-demo.html b/src/dev-app/datepicker/datepicker-demo.html new file mode 100644 index 000000000..e8d9bfbda --- /dev/null +++ b/src/dev-app/datepicker/datepicker-demo.html @@ -0,0 +1,85 @@ +
+ + + + + + + +
+
+ + + + + + + + + + +
+
+ + + + + + + + + + +
+
+ + + + + + + + + + +
+
+ + + + + + + + + + +
+
+ + + + + + + + + + +
+
+ + + + + + + + + + +
diff --git a/src/dev-app/datepicker/datepicker-demo.scss b/src/dev-app/datepicker/datepicker-demo.scss new file mode 100644 index 000000000..761434e3b --- /dev/null +++ b/src/dev-app/datepicker/datepicker-demo.scss @@ -0,0 +1,3 @@ +.container { + max-width: 200px; +} diff --git a/src/dev-app/datepicker/datepicker-demo.ts b/src/dev-app/datepicker/datepicker-demo.ts new file mode 100644 index 000000000..239456463 --- /dev/null +++ b/src/dev-app/datepicker/datepicker-demo.ts @@ -0,0 +1,32 @@ +// tslint:disable:no-console +// tslint:disable:no-magic-numbers +import { Component } from '@angular/core'; + +// Depending on whether rollup is used, moment needs to be imported differently. +// Since Moment.js doesn't have a default export, we normally need to import using the `* as` +// syntax. However, rollup creates a synthetic default module and we thus need to import it using +// the `default as` syntax. +// tslint:disable-next-line:ordered-imports +import * as _moment from 'moment'; +// tslint:disable-next-line:no-duplicate-imports +import { default as _rollupMoment, Moment } from 'moment'; + + +const moment = _rollupMoment || _moment; + +@Component({ + selector: 'datepicker-demo', + templateUrl: 'datepicker-demo.html', + styleUrls: ['datepicker-demo.css'], +}) +export class DatepickerDemo { + date = moment([2019, 0, 24]); + minDate = moment([2015, 0, 1]); + maxDate = moment([2020, 0, 1]); + + myFilter(date: Moment): boolean { + const day = date.day(); + + return day !== 0 && day !== 6; + } +} diff --git a/src/dev-app/dev-app-module.ts b/src/dev-app/dev-app-module.ts new file mode 100644 index 000000000..1c8b9bc7c --- /dev/null +++ b/src/dev-app/dev-app-module.ts @@ -0,0 +1,45 @@ +import { CommonModule } from '@angular/common'; +import { HttpClientModule } from '@angular/common/http'; +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { BrowserModule } from '@angular/platform-browser'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { RouterModule } from '@angular/router'; +import { LayoutModule } from '@ptsecurity/cdk/layout'; + +import { ButtonDemo } from './button/button-demo'; +import { DatepickerDemo } from './datepicker/datepicker-demo'; +import { DevAppComponent, DevAppHome, DevApp404 } from './dev-app'; +import { InputDemo } from './input/input-demo'; +import { DevAppMosaicModule } from './mosaic-module'; +import { DEV_APP_ROUTES } from './routes'; + + +@NgModule({ + imports: [ + BrowserAnimationsModule, + BrowserModule, + CommonModule, + DevAppMosaicModule, + + FormsModule, + HttpClientModule, + LayoutModule, + ReactiveFormsModule, + RouterModule.forRoot(DEV_APP_ROUTES) + ], + declarations: [ + DevAppComponent, + DevAppHome, + DevApp404, + + ButtonDemo, + InputDemo, + DatepickerDemo + ], + providers: [], + entryComponents: [], + bootstrap: [DevAppComponent] +}) +export class DevAppModule { +} diff --git a/src/dev-app/dev-app.html b/src/dev-app/dev-app.html new file mode 100644 index 000000000..d83061487 --- /dev/null +++ b/src/dev-app/dev-app.html @@ -0,0 +1,55 @@ +
+
+ + + + + + + PT Mosaic + + + + + {{navItem.text}} + + + + {{ item.text }} + + + + + + + + + + + Light theme + + + Dark theme + + + +
+ +
+
+
diff --git a/src/dev-app/dev-app.scss b/src/dev-app/dev-app.scss new file mode 100644 index 000000000..dcfb11be9 --- /dev/null +++ b/src/dev-app/dev-app.scss @@ -0,0 +1,14 @@ +html, body { + width: 100%; + height: 100%; + margin: 0; +} + +.content-container { + padding: 16px; +} + +.navbar-brand { + cursor: pointer; + padding-left: 16px !important; +} diff --git a/src/dev-app/dev-app.ts b/src/dev-app/dev-app.ts new file mode 100644 index 000000000..5e81b7c76 --- /dev/null +++ b/src/dev-app/dev-app.ts @@ -0,0 +1,45 @@ +import { Component, ViewEncapsulation } from '@angular/core'; + + +/** Root component for the dev-app demos. */ +@Component({ + selector: 'dev-app', + templateUrl: 'dev-app.html', + styleUrls: ['dev-app.css'], + encapsulation: ViewEncapsulation.None +}) +export class DevAppComponent { + dark = false; + navItems = [ + { + text: 'Form controls', + children: [ + { text: 'Button', route: '/button' }, + { text: 'Input', route: '/input' }, + { text: 'Datepicker', route: '/datepicker' } + ] + } + ]; +} + +/** Home component which includes a welcome message for the dev-app. */ +@Component({ + selector: 'home', + template: ` +

Welcome to the development demos for Angular Mosaic!

+

Select demo on the navbar.

+ ` +}) +export class DevAppHome { +} + +@Component({ + template: ` +

404

+

This page does not exist

+ Go back to the home page + `, + host: { class: 'mc-typography' } +}) +export class DevApp404 { +} diff --git a/src/dev-app/favico.ico b/src/dev-app/favico.ico new file mode 100644 index 000000000..76ce3f390 Binary files /dev/null and b/src/dev-app/favico.ico differ diff --git a/src/dev-app/index.html b/src/dev-app/index.html new file mode 100644 index 000000000..e4a1edcad --- /dev/null +++ b/src/dev-app/index.html @@ -0,0 +1,37 @@ + + + + + + Angular Mosaic + + + + + + + + + + + + + + + Loading... + + + + + + + + diff --git a/src/dev-app/input/input-demo.html b/src/dev-app/input/input-demo.html new file mode 100644 index 000000000..d91f14253 --- /dev/null +++ b/src/dev-app/input/input-demo.html @@ -0,0 +1,138 @@ +
+ +
Number Value: {{ numberValue }}
+ +
+
+ + + + + + +
+
+ + + + + + + +
+
+ +
Without placeholder:
+ + + + +

+ +
With placeholder:
+ + + + + +

+ +
With placeholder and monospace:
+ + + + + +

+ +
With placeholder and hint:
+ + + + + Hint under field + + +

+ +
With placeholder, hint and disabled:
+ + + + + Hint under field + + +

+ +
With clear-button:
+ + + + + + + +

+ +
With prefix:
+ + + + + + + +

+ +
With suffix:
+ + + + + + + +

+ +
Invalid:
+ + + + + +

+ +
Invalid with clear-button:
+ + + + + + + +

+ +
With placeholder, hint, prefix, cleaner and disabled:
+ + + + + + + + + +

+ +
Without borders:
+ + + + + + + + +
diff --git a/src/dev-app/input/input-demo.scss b/src/dev-app/input/input-demo.scss new file mode 100644 index 000000000..c185f98d4 --- /dev/null +++ b/src/dev-app/input/input-demo.scss @@ -0,0 +1,3 @@ +.container .mc-form-field { + width: 200px; +} diff --git a/src/dev-app/input/input-demo.ts b/src/dev-app/input/input-demo.ts new file mode 100644 index 000000000..3863b4d75 --- /dev/null +++ b/src/dev-app/input/input-demo.ts @@ -0,0 +1,13 @@ +import { Component } from '@angular/core'; + + +@Component({ + selector: 'input-demo', + templateUrl: 'input-demo.html', + styleUrls: ['input-demo.css'] +}) +export class InputDemo { + value: string = ''; + numberValue: number | null = null; + min = -5; +} diff --git a/src/dev-app/main-aot.ts b/src/dev-app/main-aot.ts new file mode 100644 index 000000000..f9e0142ca --- /dev/null +++ b/src/dev-app/main-aot.ts @@ -0,0 +1,6 @@ +import { platformBrowser } from '@angular/platform-browser'; + +import { DevAppModuleNgFactory } from './dev-app-module.ngfactory'; + + +platformBrowser().bootstrapModuleFactory(DevAppModuleNgFactory); diff --git a/src/dev-app/main.ts b/src/dev-app/main.ts new file mode 100644 index 000000000..d490b4e41 --- /dev/null +++ b/src/dev-app/main.ts @@ -0,0 +1,6 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { DevAppModule } from './dev-app-module'; + + +platformBrowserDynamic().bootstrapModule(DevAppModule); diff --git a/src/dev-app/mosaic-module.ts b/src/dev-app/mosaic-module.ts new file mode 100644 index 000000000..5921ce2bc --- /dev/null +++ b/src/dev-app/mosaic-module.ts @@ -0,0 +1,34 @@ +/** + * NgModule that includes all Mosaic modules that are required to serve the dev-app. + */ +import { NgModule } from '@angular/core'; +import { A11yModule } from '@ptsecurity/cdk/a11y'; +import { BidiModule } from '@ptsecurity/cdk/bidi'; +import { + McButtonModule, + McIconModule, + McNavbarModule, + McInputModule, + McFormFieldModule, + McDatepickerModule +} from '@ptsecurity/mosaic'; +import { McMomentDateModule } from '@ptsecurity/mosaic-moment-adapter'; + + +@NgModule({ + exports: [ + McIconModule, + McButtonModule, + McInputModule, + McNavbarModule, + McMomentDateModule, + McDatepickerModule, + + McFormFieldModule, + + A11yModule, + BidiModule + ] +}) +export class DevAppMosaicModule { +} diff --git a/src/dev-app/routes.ts b/src/dev-app/routes.ts new file mode 100644 index 000000000..e671c73ae --- /dev/null +++ b/src/dev-app/routes.ts @@ -0,0 +1,17 @@ +import { Routes } from '@angular/router'; + +import { ButtonDemo } from './button/button-demo'; +import { DatepickerDemo } from './datepicker/datepicker-demo'; +import { DevApp404, DevAppHome } from './dev-app'; +import { InputDemo } from './input/input-demo'; + + +export const DEV_APP_ROUTES: Routes = [ + {path: '', component: DevAppHome}, + + {path: 'button', component: ButtonDemo}, + {path: 'input', component: InputDemo}, + {path: 'datepicker', component: DatepickerDemo}, + + {path: '**', component: DevApp404} +]; diff --git a/src/dev-app/system-config.ts b/src/dev-app/system-config.ts new file mode 100644 index 000000000..eeb5fbbcc --- /dev/null +++ b/src/dev-app/system-config.ts @@ -0,0 +1,100 @@ +/** Type declaration for ambient System. */ +declare const System: any; + +// Configure the base path and map the different node packages. +System.config({ + paths: { + 'node:*': 'node_modules/*' + }, + map: { + 'main': 'main.js', + 'tslib': 'node:tslib/tslib.js', + 'moment': 'node:moment/min/moment-with-locales.min.js', + 'messageformat': 'node:messageformat/messageformat.min.js', + + 'rxjs': 'node_modules/rxjs/bundles/rxjs.umd.min.js', + 'rxjs/operators': 'system-rxjs-operators.js', + + // Angular specific mappings. + '@angular/core': 'node:@angular/core/bundles/core.umd.js', + '@angular/core/testing': 'node:@angular/core/bundles/core-testing.umd.js', + '@angular/common': 'node:@angular/common/bundles/common.umd.js', + '@angular/common/testing': 'node:@angular/common/bundles/common-testing.umd.js', + '@angular/common/http': 'node:@angular/common/bundles/common-http.umd.js', + '@angular/common/http/testing': 'node:@angular/common/bundles/common-http-testing.umd.js', + '@angular/compiler': 'node:@angular/compiler/bundles/compiler.umd.js', + '@angular/compiler/testing': 'node:@angular/compiler/bundles/compiler-testing.umd.js', + '@angular/forms': 'node:@angular/forms/bundles/forms.umd.js', + '@angular/forms/testing': 'node:@angular/forms/bundles/forms-testing.umd.js', + '@angular/animations': 'node:@angular/animations/bundles/animations.umd.js', + '@angular/animations/browser': 'node:@angular/animations/bundles/animations-browser.umd.js', + '@angular/router': 'node:@angular/router/bundles/router.umd.js', + '@angular/platform-browser/animations': + 'node:@angular/platform-browser/bundles/platform-browser-animations.umd', + '@angular/platform-browser': + 'node:@angular/platform-browser/bundles/platform-browser.umd.js', + '@angular/platform-browser/testing': + 'node:@angular/platform-browser/bundles/platform-browser-testing.umd.js', + '@angular/platform-browser-dynamic': + 'node:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', + '@angular/platform-browser-dynamic/testing': + 'node:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js', + + '@ptsecurity/cdk': 'dist/packages/cdk/index.js', + '@ptsecurity/cdk/a11y': 'dist/packages/cdk/a11y/index.js', + '@ptsecurity/cdk/bidi': 'dist/packages/cdk/bidi/index.js', + '@ptsecurity/cdk/datetime': 'dist/packages/cdk/datetime/index.js', + '@ptsecurity/cdk/coercion': 'dist/packages/cdk/coercion/index.js', + '@ptsecurity/cdk/collections': 'dist/packages/cdk/collections/index.js', + '@ptsecurity/cdk/keycodes': 'dist/packages/cdk/keycodes/index.js', + '@ptsecurity/cdk/layout': 'dist/packages/cdk/layout/index.js', + '@ptsecurity/cdk/overlay': 'dist/packages/cdk/overlay/index.js', + '@ptsecurity/cdk/platform': 'dist/packages/cdk/platform/index.js', + '@ptsecurity/cdk/portal': 'dist/packages/cdk/portal/index.js', + '@ptsecurity/cdk/scrolling': 'dist/packages/cdk/scrolling/index.js', + '@ptsecurity/cdk/testing': 'dist/packages/cdk/testing/index.js', + '@ptsecurity/cdk/tree': 'dist/packages/cdk/tree/index.js', + + '@ptsecurity/mosaic-moment-adapter': 'dist/packages/mosaic-moment-adapter/index.js', + '@ptsecurity/mosaic-moment-adapter/adapter': 'dist/packages/mosaic-moment-adapter/adapter/index.js', + + '@ptsecurity/mosaic': 'dist/packages/mosaic/index.js', + + '@ptsecurity/mosaic/button': 'dist/packages/mosaic/button/index.js', + '@ptsecurity/mosaic/core': 'dist/packages/mosaic/core/index.js', + '@ptsecurity/mosaic/card': 'dist/packages/mosaic/card/index.js', + '@ptsecurity/mosaic/datepicker': 'dist/packages/mosaic/datepicker/index.js', + '@ptsecurity/mosaic/divider': 'dist/packages/mosaic/divider/index.js', + '@ptsecurity/mosaic/dropdown': 'dist/packages/mosaic/dropdown/index.js', + '@ptsecurity/mosaic/list': 'dist/packages/mosaic/list/index.js', + '@ptsecurity/mosaic/navbar': 'dist/packages/mosaic/navbar/index.js', + '@ptsecurity/mosaic/progress-bar': 'dist/packages/mosaic/progress-bar/index.js', + '@ptsecurity/mosaic/progress-spinner': 'dist/packages/mosaic/progress-spinner/index.js', + '@ptsecurity/mosaic/icon': 'dist/packages/mosaic/icon/index.js', + '@ptsecurity/mosaic/layout': 'dist/packages/mosaic/layout/index.js', + '@ptsecurity/mosaic/link': 'dist/packages/mosaic/link/index.js', + '@ptsecurity/mosaic/radio': 'dist/packages/mosaic/radio/index.js', + '@ptsecurity/mosaic/checkbox': 'dist/packages/mosaic/checkbox/index.js', + '@ptsecurity/mosaic/input': 'dist/packages/mosaic/input/index.js', + '@ptsecurity/mosaic/form-field': 'dist/packages/mosaic/form-field/index.js', + '@ptsecurity/mosaic/tree': 'dist/packages/mosaic/tree/index.js', + '@ptsecurity/mosaic/modal': 'dist/packages/mosaic/modal/index.js', + '@ptsecurity/mosaic/tag': 'dist/packages/mosaic/tag/index.js', + '@ptsecurity/mosaic/tabs': 'dist/packages/mosaic/tabs/index.js', + '@ptsecurity/mosaic/select': 'dist/packages/mosaic/select/index.js', + '@ptsecurity/mosaic/sidepanel': 'dist/packages/mosaic/sidepanel/index.js', + '@ptsecurity/mosaic/textarea': 'dist/packages/mosaic/textarea/index.js', + '@ptsecurity/mosaic/toggle': 'dist/packages/mosaic/toggle/index.js', + '@ptsecurity/mosaic/tooltip': 'dist/packages/mosaic/tooltip/index.js', + '@ptsecurity/mosaic/timepicker': 'dist/packages/mosaic/timepicker/index.js', + '@ptsecurity/mosaic/tree-select': 'dist/packages/mosaic/tree-select/index.js', + '@ptsecurity/mosaic/splitter': 'dist/packages/mosaic/splitter/index.js' + }, + packages: { + // Set the default extension for the root package, because otherwise the dev-app can't + // be built within the production mode. Due to missing file extensions. + '.': { + defaultExtension: 'js' + } + } +}); diff --git a/src/dev-app/system-rxjs-operators.ts b/src/dev-app/system-rxjs-operators.ts new file mode 100644 index 000000000..807c25b95 --- /dev/null +++ b/src/dev-app/system-rxjs-operators.ts @@ -0,0 +1,17 @@ +// Workaround for an issue where RxJS cannot be used with UMD bundles only. This is because +// rxjs only ships one UMD bundle and expects everyone to only use the named "rxjs" AMD module. +// Since our code internally loads operators from "rxjs/operators/index", we need to make sure +// that we re-export all operators from the UMD module. This is a small trade-off for not loading +// all rxjs files individually. + +declare const define: { + (deps: string[], factory: (...deps: any[]) => void): void; + amd: boolean; +}; + +if (typeof define === 'function' && define.amd) { + define(['exports', 'rxjs'], (exports: any, rxjs: any) => { + // Re-export all operators in this AMD module. + Object.assign(exports, rxjs.operators); + }); +} diff --git a/src/dev-app/theme.scss b/src/dev-app/theme.scss new file mode 100644 index 000000000..9d3ca599e --- /dev/null +++ b/src/dev-app/theme.scss @@ -0,0 +1,7 @@ +@import '../lib/core/theming/all-theme'; + +@import '../lib/core/theming/prebuilt/default-theme'; + +.dark-theme { + @import '../lib/core/theming/prebuilt/dark-theme'; +} diff --git a/src/dev-app/tsconfig-aot.json b/src/dev-app/tsconfig-aot.json new file mode 100644 index 000000000..7305662ae --- /dev/null +++ b/src/dev-app/tsconfig-aot.json @@ -0,0 +1,55 @@ +// TypeScript config that extends the dev-app tsconfig file. This config compiles the +// "main-aot.ts" file and also enables templage code generation / AOT. +{ + "extends": "./tsconfig-build", + "compilerOptions": { + // Needed for Moment.js since it doesn't have a default export. + "allowSyntheticDefaultImports": true, + "experimentalDecorators": true, + "noUnusedParameters": true, + "noUnusedLocals": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "noImplicitAny": true, + "noImplicitThis": true, + "outDir": "../../dist/packages/dev-app", + "rootDirs": [ + ".", + // Include the package output here because otherwise NGC won't be able to load + // the SCSS files. + "../../dist/packages/dev-app" + ], + "paths": { + "@angular/*": ["../../node_modules/@angular/*"], + "@ptsecurity/mosaic/*": [ + "../../dist/releases/mosaic/*" + ], + "@ptsecurity/mosaic": [ + "../../dist/releases/mosaic" + ], + "@ptsecurity/cdk/*": [ + "../../dist/releases/cdk/*" + ], + "@ptsecurity/cdk": [ + "../../dist/releases/cdk" + ], + "@ptsecurity/mosaic-moment-adapter/*": [ + "../../dist/releases/mosaic-moment-adapter/*" + ], + "@ptsecurity/mosaic-moment-adapter": [ + "../../dist/releases/mosaic-moment-adapter" + ], + "@ptsecurity/mosaic-examples": [ + "../../dist/releases/mosaic-examples" + ] + } + }, + "files": [ + "./dev-app-module.ts", + "./main-aot.ts" + ], + "angularCompilerOptions": { + "skipTemplateCodegen": false, + "fullTemplateTypeCheck": true + } +} diff --git a/src/dev-app/tsconfig-build.json b/src/dev-app/tsconfig-build.json new file mode 100644 index 000000000..af0b60e52 --- /dev/null +++ b/src/dev-app/tsconfig-build.json @@ -0,0 +1,63 @@ +// TypeScript config file that is used to compile the dev-app. Target environment will be ES5, +// since the dev-app will be served in the browser. +{ + "compilerOptions": { + // Needed for Moment.js since it doesn't have a default export. + "allowSyntheticDefaultImports": true, + "declaration": false, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "noUnusedParameters": true, + "noUnusedLocals": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "noImplicitThis": true, + "lib": [ + "es6", + "es2015", + "dom" + ], + "skipLibCheck": true, + "module": "es2015", + "moduleResolution": "node", + "noEmitOnError": true, + "noImplicitAny": true, + "outDir": "../../dist/packages/dev-app", + "sourceMap": true, + "target": "es5", + "stripInternal": false, + "typeRoots": [ + "../../node_modules/@types/!(node)" + ], + "baseUrl": ".", + "paths": { + "@ptsecurity/mosaic/*": [ + "../../dist/packages/mosaic/*" + ], + "@ptsecurity/mosaic": [ + "../../dist/packages/mosaic" + ], + "@ptsecurity/cdk/*": [ + "../../dist/packages/cdk/*" + ], + "@ptsecurity/cdk": [ + "../../dist/packages/cdk" + ], + "@ptsecurity/mosaic-moment-adapter": [ + "../../dist/packages/mosaic-moment-adapter" + ], + "@ptsecurity/mosaic-moment-adapter/*": [ + "../../dist/packages/mosaic-moment-adapter/*" + ], + "@ptsecurity/mosaic-examples": [ + "../../dist/packages/mosaic-examples" + ] + } + }, + "files": [ + "./dev-app-module.ts", + "./system-rxjs-operators.ts", + "./system-config.ts", + "./main.ts" + ] +} diff --git a/src/dev-app/tsconfig.json b/src/dev-app/tsconfig.json new file mode 100644 index 000000000..e9f94b21c --- /dev/null +++ b/src/dev-app/tsconfig.json @@ -0,0 +1,33 @@ +// Configuration for IDEs only. +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + // Needed for Moment.js since it doesn't have a default export. + "allowSyntheticDefaultImports": true, + "rootDir": "..", + "baseUrl": ".", + "paths": { + "@ptsecurity/cdk/*": [ + "../cdk/*" + ], + "@ptsecurity/mosaic/*": [ + "../lib/*" + ], + "@ptsecurity/mosaic": [ + "../lib/public-api.ts" + ], + "@ptsecurity/mosaic-moment-adapter": [ + "../mosaic-moment-adapter/public-api.ts" + ], + "@ptsecurity/mosaic-moment-adapter/*": [ + "../mosaic-moment-adapter/*" + ], + "@ptsecurity/mosaic-examples": [ + "../../dist/packages/mosaic-examples" + ] + } + }, + "include": [ + "./**/*.ts" + ] +} diff --git a/tests/karma-system-config.js b/tests/karma-system-config.js index 231a25b9a..3a3175bed 100644 --- a/tests/karma-system-config.js +++ b/tests/karma-system-config.js @@ -75,7 +75,7 @@ System.config({ '@ptsecurity/mosaic/sidepanel': 'dist/packages/mosaic/sidepanel/index.js', '@ptsecurity/mosaic/textarea': 'dist/packages/mosaic/textarea/index.js', '@ptsecurity/mosaic/tooltip': 'dist/packages/mosaic/tooltip/index.js', - '@ptsucurity/mosaic/timepicker': 'dist/packages/mosaic/timepicker/index.js', + '@ptsecurity/mosaic/timepicker': 'dist/packages/mosaic/timepicker/index.js', '@ptsecurity/mosaic/splitter': 'dist/packages/mosaic/splitter/index.js' }, packages: { diff --git a/tools/gulp/gulpfile.ts b/tools/gulp/gulpfile.ts index b0185f584..1c9882fe4 100644 --- a/tools/gulp/gulpfile.ts +++ b/tools/gulp/gulpfile.ts @@ -13,6 +13,8 @@ createPackageBuildTasks(momentAdapterPackage); createPackageBuildTasks(mosaicPackage); createPackageBuildTasks(examplesPackage, ['build-examples-module']); +import './tasks/development'; +import './tasks/aot'; import './tasks/lint'; import './tasks/unit'; import './tasks/ci'; diff --git a/tools/gulp/tasks/aot.ts b/tools/gulp/tasks/aot.ts new file mode 100644 index 000000000..5f48d1db7 --- /dev/null +++ b/tools/gulp/tasks/aot.ts @@ -0,0 +1,50 @@ +import { task, series, parallel } from 'gulp'; +import { join } from 'path'; + +import { buildConfig } from '../../packages'; +import { execNodeTask } from '../utils/helpers'; + + +const { packagesDir } = buildConfig; + +/** Path to the dev-app source directory. */ +const devAppSource = join(packagesDir, 'dev-app'); + +/** Path to the tsconfig file that builds the AOT files. */ +const tsconfigFile = join(devAppSource, 'tsconfig-aot.json'); + + +/** Builds the dev-app assets and builds the required release packages. */ +task('build-aot:release-packages', series( + 'cdk:build-release', + 'mosaic-moment-adapter:build-release', + 'mosaic:build-release', + 'mosaic-examples:build-release' +)); + +/** + * Task that builds the assets which are required for building with AOT. Since the dev-app uses + * Sass files, we need to provide the transpiled CSS sources in the package output. + */ +task('build-aot:assets', parallel(':build:devapp:assets', ':build:devapp:scss')); + +/** Build the dev-app and a release to confirm that the library is AOT-compatible. */ +task('build-aot:compiler-cli', execNodeTask( + '@angular/compiler-cli', 'ngc', ['-p', tsconfigFile] +)); + +/** + * Build the dev-app wit the releabuild-aot:release-packagesse output in order confirm that the library is + * working with AOT compilation enabled. + */ +task('build-aot', series( + 'clean', + parallel('build-aot:release-packages', 'build-aot:assets'), + 'build-aot:compiler-cli' +)); + +/** + * Task that can be used to build the dev-app with AOT without building the + * release output. This can be run if the release output is already built. + */ +task('build-aot:no-release-build', series('build-aot:assets', 'build-aot:compiler-cli')); diff --git a/tools/gulp/tasks/ci.ts b/tools/gulp/tasks/ci.ts index cc0487b8e..80b8a58d8 100644 --- a/tools/gulp/tasks/ci.ts +++ b/tools/gulp/tasks/ci.ts @@ -9,3 +9,4 @@ task('ci:test', series('test:single-run', (done) => { process.exit(0); })); +task('ci:aot', series('build-aot:no-release-build')); diff --git a/tools/gulp/tasks/development.ts b/tools/gulp/tasks/development.ts new file mode 100644 index 000000000..47f66149c --- /dev/null +++ b/tools/gulp/tasks/development.ts @@ -0,0 +1,100 @@ +// tslint:disable:no-var-requires +import { task, dest, series, parallel } from 'gulp'; +import { join } from 'path'; + +import { buildConfig, buildScssPipeline } from '../../packages'; +import { inlineResourcesForDirectory } from '../../packages/inline-resources'; +import { + cdkPackage, + mosaicPackage, + momentAdapterPackage, + examplesPackage +} from '../packages'; +import { tsBuildTask, copyTask, serverTask } from '../utils/helpers'; +import { watchFilesAndReload } from '../utils/watch-files-reload'; + + +const { outputDir, packagesDir } = buildConfig; + +const appDir = join(packagesDir, 'dev-app'); +const outDir = join(outputDir, 'packages', 'dev-app'); + +/** Glob that matches all assets that need to be copied to the output. */ +const assetsGlob = join(appDir, `**/*.+(html|css|svg|ico)`); + +/** Path to the dev-app tsconfig file. */ +const tsconfigPath = join(appDir, 'tsconfig-build.json'); + +task(':build:devapp:ts', tsBuildTask(tsconfigPath)); +task(':build:devapp:assets', copyTask(assetsGlob, outDir)); +task(':build:devapp:scss', () => buildScssPipeline(appDir).pipe(dest(outDir))); +task(':build:devapp:inline-resources', (done) => { inlineResourcesForDirectory(outDir); done(); }); + +task(':serve:devapp', serverTask(outDir)); + +task('build:devapp', series( + 'cdk:build-no-bundles', + 'mosaic-moment-adapter:build-no-bundles', + 'mosaic:build-no-bundles', + 'build-examples-module', + // The examples module needs to be manually built before building examples package because + // when using the `no-bundles` task, the package-specific pre-build tasks won't be executed. + 'mosaic-examples:build-no-bundles', + parallel(':build:devapp:assets', ':build:devapp:scss', ':build:devapp:ts'), + // Inline all component resources because otherwise SystemJS tries to load HTML, CSS and + // JavaScript files which makes loading the dev-app extremely slow. + ':build:devapp:inline-resources' +)); + + +/* + * Development app watch task. This task ensures that only the packages that have been affected + * by a file-change are being rebuilt. This speeds-up development and makes working on Mosaic + * easier. + */ +task(':watch:devapp', () => { + watchFilesAndReload(join(appDir, '**/*.ts'), [':build:devapp:ts', ':build:devapp:inline-resources']); + watchFilesAndReload(join(appDir, '**/*.scss'), [':watch:devapp:rebuild-scss']); + watchFilesAndReload(join(appDir, '**/*.html'), [':watch:devapp:rebuild-html']); + + // Custom watchers for all packages that are used inside of the dev-app. This is necessary + // because we only want to build the changed package (using the build-no-bundles task). + + // CDK package watchers. + watchFilesAndReload(join(cdkPackage.sourceDir, '**/*'), ['cdk:build-no-bundles']); + + const mosaicCoreThemingGlob = join( + mosaicPackage.sourceDir, + '**/core/+(theming|typography)/**/*.scss' + ); + + // Mosaic package watchers. + watchFilesAndReload([ + join(mosaicPackage.sourceDir, '**/(*-theme.scss)'), `${mosaicCoreThemingGlob}` + ], ['mosaic:build-no-bundles']); + watchFilesAndReload([ + join(mosaicPackage.sourceDir, '**/*-theme.scss'), mosaicCoreThemingGlob + ], [':build:devapp:scss']); + + // Moment adapter package watchers + watchFilesAndReload(join(momentAdapterPackage.sourceDir, '**/*'), + ['mosaic-moment-adapter:build-no-bundles']); + + // Example package watchers. + watchFilesAndReload(join(examplesPackage.sourceDir, '**/*'), + ['mosaic-examples:build-no-bundles']); +}); + +task('serve:devapp', series('build:devapp', parallel(':serve:devapp', ':watch:devapp'))); + +// Note that we need to rebuild the TS here, because the resource inlining +// won't work if the file's resources have been inlined already. +task(':watch:devapp:rebuild-scss', series( + parallel(':build:devapp:scss', ':build:devapp:ts'), + ':build:devapp:inline-resources' +)); + +task(':watch:devapp:rebuild-html', series( + parallel(':build:devapp:assets', ':build:devapp:ts'), + ':build:devapp:inline-resources' +)); diff --git a/tools/gulp/utils/helpers.ts b/tools/gulp/utils/helpers.ts index e9bc94441..db6544a82 100644 --- a/tools/gulp/utils/helpers.ts +++ b/tools/gulp/utils/helpers.ts @@ -1,11 +1,53 @@ +// tslint:disable:no-var-requires +import { BrowserSyncInstance, create as createBrowserSyncInstance } from 'browser-sync'; import * as child_process from 'child_process'; +import * as fs from 'fs'; import * as gulp from 'gulp'; +import * as path from 'path'; + +import { buildConfig } from '../../packages'; import { IExecTaskOptions } from './models'; const gulpClean = require('gulp-clean'); const resolveBin = require('resolve-bin'); +const httpRewrite = require('http-rewrite-middleware'); + +const {projectDir} = buildConfig; + +/** Currently active browsersync instance. */ +let activeBrowserSyncInstance: BrowserSyncInstance; + +/** If the string passed in is a glob, returns it, otherwise append '**\/*' to it. */ +function globify(maybeGlob: string, suffix = '**/*') { + if (maybeGlob.indexOf('*') > -1) { + return maybeGlob; + } + try { + if (fs.statSync(maybeGlob).isFile()) { + return maybeGlob; + } + // tslint:disable-next-line:no-empty + } catch {} + + return path.join(maybeGlob, suffix); +} + +/** Creates a task that runs the TypeScript compiler */ +export function tsBuildTask(tsConfigPath: string) { + return execNodeTask('typescript', 'tsc', ['-p', tsConfigPath]); +} + +/** Copy files from a glob to a destination. */ +export function copyTask(srcGlobOrDir: string | string[], outRoot: string) { + if (typeof srcGlobOrDir === 'string') { + return () => gulp.src(globify(srcGlobOrDir)).pipe(gulp.dest(outRoot)); + } else { + // tslint:disable-next-line:no-unnecessary-callback-wrapper + return () => gulp.src(srcGlobOrDir.map((name) => globify(name))).pipe(gulp.dest(outRoot)); + } +} export function cleanTask(glob: string) { return () => gulp.src(glob, { read: false, allowEmpty: true }).pipe(gulpClean(null)); @@ -39,10 +81,12 @@ export function execTask(binPath: string, args: string[], options: IExecTaskOpti export function execNodeTask(packageName: string, executable: string | string[], args?: string[], options: IExecTaskOptions = {}) { + // tslint:disable:no-parameter-reassignment if (!args) { args = executable; executable = ''; } + // tslint:enable:no-parameter-reassignment return (done: (err: any) => void) => { resolveBin(packageName, { executable }, (err: any, binPath: string) => { @@ -57,3 +101,70 @@ export function execNodeTask(packageName: string, executable: string | string[], }); }; } + + +/** + * Create a task that serves a given directory in the project. + * The server rewrites all node_module/ or dist/ requests to the correct directory. + */ +// tslint:disable-next-line:no-reserved-keywords +export function serverTask(packagePath: string, rewrites?: {from: string; to: string}[]) { + // The http-rewrite-middleware only supports relative paths as rewrite destinations. + const relativePath = path.relative(projectDir, packagePath); + const defaultHttpRewrites = [ + // Rewrite the node_modules/ and dist/ folder to the real paths. This is a trick to + // avoid that those folders will be rewritten to the specified package path. + { from: '^/node_modules/(.*)$', to: '/node_modules/$1' }, + { from: '^/dist/(.*)$', to: '/dist/$1' }, + // Rewrite every path that doesn't point to a specific file to the index.html file. + // This is necessary for Angular's routing using the HTML5 History API. + { from: '^/[^.]+$', to: `/${relativePath}/index.html`}, + // Rewrite any path that didn't match a pattern before to the specified package path. + { from: '^(.*)$', to: `/${relativePath}/$1` } + ]; + + return (done: () => void) => { + if (activeBrowserSyncInstance) { + throw new Error('Cannot setup BrowserSync because there is already an instance running.'); + } + + activeBrowserSyncInstance = createBrowserSyncInstance(); + activeBrowserSyncInstance.init({ + server: projectDir, + port: 4200, + middleware: httpRewrite.getMiddleware(rewrites || defaultHttpRewrites), + notify: false, + + // Options which are disabled by default. We don't want to enable ghostMode by default + // because it can throw-off change detection due to the event listeners syncing events + // between browsers. Also opening the browser is not always desired because in some cases + // developers just want to serve the app, and open the browser on a different device. + ghostMode: process.argv.includes('--ghostMode'), + open: process.argv.includes('--open') + }); + + done(); + }; +} + +/** Gets the currently active browsersync instance */ +export function getActiveBrowserSyncInstance(): BrowserSyncInstance { + if (!activeBrowserSyncInstance) { + throw new Error('Cannot return Browsersync instance because there is no instance running.'); + } + + return activeBrowserSyncInstance; +} + +/** Gulp 4 watch function uses unix style paths even on windows and we should keep it unix styled */ +export function replaceSlashes(value: string | string[]): string | string[] { + if (typeof value !== 'string' && !Array.isArray(value)) { + return value; + } + + if (Array.isArray(value)) { + return value.map((item) => replaceSlashes(item) as string); + } + + return value.replace(/\\/g, '/'); +} diff --git a/tools/gulp/utils/watch-files-reload.ts b/tools/gulp/utils/watch-files-reload.ts new file mode 100644 index 000000000..3ba0ef9a0 --- /dev/null +++ b/tools/gulp/utils/watch-files-reload.ts @@ -0,0 +1,12 @@ +import { watchFiles } from '../../packages/gulp/watch-files'; + +import { getActiveBrowserSyncInstance } from './helpers'; + + +/** + * Function that watches a set of file globs and runs the specified tasks if a file + * changed. Additionally BrowserSync will reload all browsers on file change. + */ +export function watchFilesAndReload(fileGlob: string | string[], tasks: string[]) { + watchFiles(fileGlob, [...tasks, (done: () => void) => { getActiveBrowserSyncInstance().reload(); done(); }]); +} diff --git a/tools/packages/gulp/watch-files.ts b/tools/packages/gulp/watch-files.ts new file mode 100644 index 000000000..632266580 --- /dev/null +++ b/tools/packages/gulp/watch-files.ts @@ -0,0 +1,10 @@ +import { watch, series, TaskFunction } from 'gulp'; + +import { replaceSlashes } from '../../gulp/utils/helpers'; + + +/** Function that watches a set of file globs and runs given Gulp tasks if a given file changes. */ +export function watchFiles(fileGlob: string | string[], tasks: (string | TaskFunction)[], + debounceDelay = 700) { + watch(replaceSlashes(fileGlob), { delay: debounceDelay }, series.apply(series, tasks)); +} diff --git a/tsconfig.webpack.json b/tsconfig.webpack.json index ceffe12b0..6791e899b 100644 --- a/tsconfig.webpack.json +++ b/tsconfig.webpack.json @@ -48,7 +48,8 @@ "src/**/*._spec.ts", "src/**/*.e2e.ts", "src/mosaic-examples/**/*.*", - "src/cdk/schematics/**/*.*" + "src/cdk/schematics/**/*.*", + "src/dev-app/**/*.*" ], "angularCompilerOptions": { "skipMetadataEmit": true diff --git a/yarn.lock b/yarn.lock index 87a333793..6fafc59db 100644 --- a/yarn.lock +++ b/yarn.lock @@ -492,6 +492,16 @@ resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.0.tgz#d1d55958d1fccc5527d4aba29fc9c4b942f563ff" integrity sha512-7WcbyctkE8GTzogDb0ulRAEw7v8oIS54ft9mQTU7PfM0hp5e+8kpa+HeQ7IQrFbKtJXBKcZ4bh+Em9dTw5L6AQ== +"@types/browser-sync@^0.0.42": + version "0.0.42" + resolved "https://registry.yarnpkg.com/@types/browser-sync/-/browser-sync-0.0.42.tgz#cb048a6bd444f3c6b4a830f542f5724eeb5123d0" + integrity sha512-/angMGVhVs4CRYKudYlRDQ8VZY/30m8LEWGYCNNRQcTQhxWNXl8aY0XMDDrAnwHiPgTyKH6O49Ls544WRgzIPg== + dependencies: + "@types/chokidar" "*" + "@types/micromatch" "^2" + "@types/node" "*" + "@types/serve-static" "*" + "@types/chalk@^2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@types/chalk/-/chalk-2.2.0.tgz#b7f6e446f4511029ee8e3f43075fb5b73fbaa0ba" @@ -512,6 +522,14 @@ resolved "https://registry.yarnpkg.com/@types/events/-/events-1.2.0.tgz#81a6731ce4df43619e5c8c945383b3e62a89ea86" integrity sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA== +"@types/express-serve-static-core@*": + version "4.16.1" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.16.1.tgz#35df7b302299a4ab138a643617bd44078e74d44e" + integrity sha512-QgbIMRU1EVRry5cIu1ORCQP4flSYqLM1lS5LYyGWfKnFT3E58f0gKto7BR13clBFVrVZ0G0rbLZ1hUpSkgQQOA== + dependencies: + "@types/node" "*" + "@types/range-parser" "*" + "@types/fs-extra@^5.0.4": version "5.0.4" resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-5.0.4.tgz#b971134d162cc0497d221adde3dbb67502225599" @@ -564,6 +582,18 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= +"@types/micromatch@^2": + version "2.3.30" + resolved "https://registry.yarnpkg.com/@types/micromatch/-/micromatch-2.3.30.tgz#c2a143675f200fbcebe57fb0dab0cbf58093d4b0" + integrity sha512-6rW4NsUHaDudxJSuRlm1PdNu61CDXkgix7LBOBg7b3yWQ43XANYSPwkvX1cGiZvBVZW8c5rsCEfrfzbPkch8ag== + dependencies: + "@types/parse-glob" "*" + +"@types/mime@*": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d" + integrity sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw== + "@types/minimatch@*": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" @@ -579,6 +609,24 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-8.9.5.tgz#162b864bc70be077e6db212b322754917929e976" integrity sha512-jRHfWsvyMtXdbhnz5CVHxaBgnV6duZnPlQuRSo/dm/GnmikNcmZhxIES4E9OZjUmQ8C+HCl4KJux+cXN/ErGDQ== +"@types/parse-glob@*": + version "3.0.29" + resolved "https://registry.yarnpkg.com/@types/parse-glob/-/parse-glob-3.0.29.tgz#6a40ec7ebd2418ee69ee397e48e42169268a10bf" + integrity sha1-akDsfr0kGO5p7jl+SOQhaSaKEL8= + +"@types/range-parser@*": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" + integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== + +"@types/serve-static@*": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.2.tgz#f5ac4d7a6420a99a6a45af4719f4dcd8cd907a48" + integrity sha512-/BZ4QRLpH/bNYgZgwhKEh+5AsboDBcUdlBYgzoLX0fpj3Y2gp6EApyOlM3bK53wQS/OE1SrdSYBAbux2D1528Q== + dependencies: + "@types/express-serve-static-core" "*" + "@types/mime" "*" + "@types/source-map@^0.5.7": version "0.5.7" resolved "https://registry.yarnpkg.com/@types/source-map/-/source-map-0.5.7.tgz#165eeb583c1ef00196fe4ef4da5d7832b03b275b" @@ -1340,7 +1388,12 @@ async-done@^1.2.0, async-done@^1.2.2: process-nextick-args "^1.0.7" stream-exhaust "^1.0.1" -async-each@^1.0.0: +async-each-series@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/async-each-series/-/async-each-series-0.1.1.tgz#7617c1917401fd8ca4a28aadce3dbae98afeb432" + integrity sha1-dhfBkXQB/Yykooqtzj266Yr+tDI= + +async-each@^1.0.0, async-each@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" integrity sha1-GdOGodntxufByF04iu28xW0zYC0= @@ -1362,7 +1415,7 @@ async-settle@^1.0.0: dependencies: async-done "^1.2.2" -async@1.x, async@^1.5.2: +async@1.5.2, async@1.x, async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= @@ -1432,6 +1485,14 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== +axios@0.17.1: + version "0.17.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.17.1.tgz#2d8e3e5d0bdbd7327f91bc814f5c57660f81824d" + integrity sha1-LY4+XQvb1zJ/kbyBT1xXZg+Bgk0= + dependencies: + follow-redirects "^1.2.5" + is-buffer "^1.1.5" + babel-code-frame@^6.22.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" @@ -1647,7 +1708,7 @@ braces@^1.8.2: preserve "^0.2.0" repeat-element "^1.1.2" -braces@^2.3.0, braces@^2.3.1: +braces@^2.3.0, braces@^2.3.1, braces@^2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== @@ -1668,6 +1729,64 @@ brorand@^1.0.1: resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= +browser-sync-client@^2.26.2: + version "2.26.2" + resolved "https://registry.yarnpkg.com/browser-sync-client/-/browser-sync-client-2.26.2.tgz#dd0070c80bdc6d9021e89f7837ee70ed0a8acf91" + integrity sha512-FEuVJD41fI24HJ30XOT2RyF5WcnEtdJhhTqeyDlnMk/8Ox9MZw109rvk9pdfRWye4soZLe+xcAo9tHSMxvgAdw== + dependencies: + etag "1.8.1" + fresh "0.5.2" + mitt "^1.1.3" + rxjs "^5.5.6" + +browser-sync-ui@^2.26.2: + version "2.26.2" + resolved "https://registry.yarnpkg.com/browser-sync-ui/-/browser-sync-ui-2.26.2.tgz#a1d8e107cfed5849d77e3bbd84ae5d566beb4ea0" + integrity sha512-LF7GMWo8ELOE0eAlxuRCfnGQT1ZxKP9flCfGgZdXFc6BwmoqaJHlYe7MmVvykKkXjolRXTz8ztXAKGVqNwJ3EQ== + dependencies: + async-each-series "0.1.1" + connect-history-api-fallback "^1" + immutable "^3" + server-destroy "1.0.1" + socket.io-client "^2.0.4" + stream-throttle "^0.1.3" + +browser-sync@^2.26.3: + version "2.26.3" + resolved "https://registry.yarnpkg.com/browser-sync/-/browser-sync-2.26.3.tgz#1b59bd5935938a5b0fa73b3d78ef1050bd2bf912" + integrity sha512-VLzpjCA4uXqfzkwqWtMM6hvPm2PNHp2RcmzBXcbi6C9WpkUhhFb8SVAr4CFrCsFxDg+oY6HalOjn8F+egyvhag== + dependencies: + browser-sync-client "^2.26.2" + browser-sync-ui "^2.26.2" + bs-recipes "1.3.4" + bs-snippet-injector "^2.0.1" + chokidar "^2.0.4" + connect "3.6.6" + connect-history-api-fallback "^1" + dev-ip "^1.0.1" + easy-extender "^2.3.4" + eazy-logger "^3" + etag "^1.8.1" + fresh "^0.5.2" + fs-extra "3.0.1" + http-proxy "1.15.2" + immutable "^3" + localtunnel "1.9.1" + micromatch "2.3.11" + opn "5.3.0" + portscanner "2.1.1" + qs "6.2.3" + raw-body "^2.3.2" + resp-modifier "6.0.2" + rx "4.1.0" + send "0.16.2" + serve-index "1.9.1" + serve-static "1.13.2" + server-destroy "1.0.1" + socket.io "2.1.1" + ua-parser-js "0.7.17" + yargs "6.4.0" + browserify-aes@^1.0.0, browserify-aes@^1.0.4: version "1.2.0" resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" @@ -1736,6 +1855,16 @@ browserslist@^4.3.7: electron-to-chromium "^1.3.96" node-releases "^1.1.3" +bs-recipes@1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/bs-recipes/-/bs-recipes-1.3.4.tgz#0d2d4d48a718c8c044769fdc4f89592dc8b69585" + integrity sha1-DS1NSKcYyMBEdp/cT4lZLci2lYU= + +bs-snippet-injector@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/bs-snippet-injector/-/bs-snippet-injector-2.0.1.tgz#61b5393f11f52559ed120693100343b6edb04dd5" + integrity sha1-YbU5PxH1JVntEgaTEANDtu2wTdU= + btoa-lite@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337" @@ -2112,6 +2241,25 @@ chokidar@^1.4.2: optionalDependencies: fsevents "^1.0.0" +chokidar@^2.0.4: + version "2.1.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.2.tgz#9c23ea40b01638439e0513864d362aeacc5ad058" + integrity sha512-IwXUx0FXc5ibYmPC2XeEj5mpXoV66sR+t3jqu2NS2GYwCktt3KF1/Qqjws/NkegajBA4RbZ5+DDwlOiJsxDHEg== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.1" + braces "^2.3.2" + glob-parent "^3.1.0" + inherits "^2.0.3" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^3.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.2.1" + upath "^1.1.0" + optionalDependencies: + fsevents "^1.2.7" + chownr@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" @@ -2341,7 +2489,7 @@ commander@2.17.x, commander@~2.17.1: resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== -commander@^2.12.1, commander@^2.13.0, commander@^2.14.1, commander@^2.15.1, commander@^2.16.0, commander@^2.19.0, commander@^2.8.1, commander@^2.9.0: +commander@^2.12.1, commander@^2.13.0, commander@^2.14.1, commander@^2.15.1, commander@^2.16.0, commander@^2.19.0, commander@^2.2.0, commander@^2.8.1, commander@^2.9.0: version "2.19.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== @@ -2419,12 +2567,12 @@ concat-stream@^1.5.0, concat-stream@^1.6.0: readable-stream "^2.2.2" typedarray "^0.0.6" -connect-history-api-fallback@^1.3.0: +connect-history-api-fallback@^1, connect-history-api-fallback@^1.3.0: version "1.6.0" resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== -connect@^3.6.0: +connect@3.6.6, connect@^3.6.0: version "3.6.6" resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.6.tgz#09eff6c55af7236e137135a72574858b6786f524" integrity sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ= @@ -2935,7 +3083,7 @@ debug@=3.1.0, debug@~3.1.0: dependencies: ms "2.0.0" -debug@^3.1.0, debug@^3.2.5: +debug@^3.1.0, debug@^3.2.5, debug@^3.2.6: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== @@ -3211,6 +3359,11 @@ detective-typescript@^5.0.0: typescript "3.1.1" typescript-eslint-parser "21.0.2" +dev-ip@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dev-ip/-/dev-ip-1.0.1.tgz#a76a3ed1855be7a012bb8ac16cb80f3c00dc28f0" + integrity sha1-p2o+0YVb56ASu4rBbLgPPADcKPA= + dezalgo@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" @@ -3457,6 +3610,20 @@ each-props@^1.3.0: is-plain-object "^2.0.1" object.defaults "^1.1.0" +easy-extender@^2.3.4: + version "2.3.4" + resolved "https://registry.yarnpkg.com/easy-extender/-/easy-extender-2.3.4.tgz#298789b64f9aaba62169c77a2b3b64b4c9589b8f" + integrity sha512-8cAwm6md1YTiPpOvDULYJL4ZS6WfM5/cTeVVh4JsvyYZAoqlRVUpHL9Gr5Fy7HA6xcSZicUia3DeAgO3Us8E+Q== + dependencies: + lodash "^4.17.10" + +eazy-logger@^3: + version "3.0.2" + resolved "https://registry.yarnpkg.com/eazy-logger/-/eazy-logger-3.0.2.tgz#a325aa5e53d13a2225889b2ac4113b2b9636f4fc" + integrity sha1-oyWqXlPROiIliJsqxBE7K5Y29Pw= + dependencies: + tfunk "^3.0.1" + ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -3527,6 +3694,23 @@ engine.io-client@~3.2.0: xmlhttprequest-ssl "~1.5.4" yeast "0.1.2" +engine.io-client@~3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.3.2.tgz#04e068798d75beda14375a264bb3d742d7bc33aa" + integrity sha512-y0CPINnhMvPuwtqXfsGuWE8BB66+B6wTtCofQDRecMQPYX3MYUZXFNKDhdrSe3EVjgOu4V3rxdeqN/Tr91IgbQ== + dependencies: + component-emitter "1.2.1" + component-inherit "0.0.3" + debug "~3.1.0" + engine.io-parser "~2.1.1" + has-cors "1.1.0" + indexof "0.0.1" + parseqs "0.0.5" + parseuri "0.0.5" + ws "~6.1.0" + xmlhttprequest-ssl "~1.5.4" + yeast "0.1.2" + engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.3.tgz#757ab970fbf2dfb32c7b74b033216d5739ef79a6" @@ -3815,11 +3999,16 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= -etag@~1.8.1: +etag@1.8.1, etag@^1.8.1, etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= +eventemitter3@1.x.x: + version "1.2.0" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" + integrity sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg= + eventemitter3@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" @@ -4321,6 +4510,13 @@ follow-redirects@^1.0.0: dependencies: debug "=3.1.0" +follow-redirects@^1.2.5: + version "1.7.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.7.0.tgz#489ebc198dc0e7f64167bd23b03c4c19b5784c76" + integrity sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ== + dependencies: + debug "^3.2.6" + for-in@^0.1.3: version "0.1.8" resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1" @@ -4376,7 +4572,7 @@ fragment-cache@^0.2.1: dependencies: map-cache "^0.2.2" -fresh@0.5.2: +fresh@0.5.2, fresh@^0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= @@ -4401,6 +4597,15 @@ fs-constants@^1.0.0: resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== +fs-extra@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-3.0.1.tgz#3794f378c58b342ea7dbbb23095109c4b3b62291" + integrity sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE= + dependencies: + graceful-fs "^4.1.2" + jsonfile "^3.0.0" + universalify "^0.1.0" + fs-extra@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd" @@ -4448,6 +4653,14 @@ fsevents@^1.0.0, fsevents@^1.2.2: nan "^2.9.2" node-pre-gyp "^0.10.0" +fsevents@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.7.tgz#4851b664a3783e52003b3c66eb0eee1074933aa4" + integrity sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw== + dependencies: + nan "^2.9.2" + node-pre-gyp "^0.10.0" + fstream@^1.0.0, fstream@^1.0.2: version "1.0.11" resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" @@ -5281,6 +5494,14 @@ http-proxy-middleware@~0.18.0: lodash "^4.17.5" micromatch "^3.1.9" +http-proxy@1.15.2: + version "1.15.2" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.15.2.tgz#642fdcaffe52d3448d2bda3b0079e9409064da31" + integrity sha1-ZC/cr/5S00SNK9o7AHnpQJBk2jE= + dependencies: + eventemitter3 "1.x.x" + requires-port "1.x.x" + http-proxy@^1.13.0, http-proxy@^1.16.2: version "1.17.0" resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a" @@ -5290,6 +5511,11 @@ http-proxy@^1.13.0, http-proxy@^1.16.2: follow-redirects "^1.0.0" requires-port "^1.0.0" +http-rewrite-middleware@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/http-rewrite-middleware/-/http-rewrite-middleware-0.1.6.tgz#cb2965aafa91ebd4c610b99580aa187812da107c" + integrity sha1-yyllqvqR69TGELmVgKoYeBLaEHw= + http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" @@ -5374,6 +5600,11 @@ ignore@^5.0.4: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.0.4.tgz#33168af4a21e99b00c5d41cbadb6a6cb49903a45" integrity sha512-WLsTMEhsQuXpCiG173+f3aymI43SXa+fB1rSfbzyP4GkPP+ZFVuO0/3sFUGNBtifisPeDcl/uD/Y2NxZ7xFq4g== +immutable@^3: + version "3.8.2" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.2.tgz#c2439951455bb39913daf281376f1530e104adf3" + integrity sha1-wkOZUUVbs5kT2vKBN28VMOEErfM= + import-cwd@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" @@ -5753,6 +5984,13 @@ is-negated-glob@^1.0.0: resolved "https://registry.yarnpkg.com/is-negated-glob/-/is-negated-glob-1.0.0.tgz#6910bca5da8c95e784b5751b976cf5a10fee36d2" integrity sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI= +is-number-like@^1.0.3: + version "1.0.8" + resolved "https://registry.yarnpkg.com/is-number-like/-/is-number-like-1.0.8.tgz#2e129620b50891042e44e9bbbb30593e75cfbbe3" + integrity sha512-6rZi3ezCyFcn5L71ywzz2bS5b2Igl1En3eTlZlvKjpz1n3IZLAYMbKYAIQgFmEu0GENg92ziU/faEOA/aixjbA== + dependencies: + lodash.isfinite "^3.3.2" + is-number@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-number/-/is-number-0.1.1.tgz#69a7af116963d47206ec9bd9b48a14216f1e3806" @@ -6134,6 +6372,13 @@ json5@^2.1.0: dependencies: minimist "^1.2.0" +jsonfile@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-3.0.1.tgz#a5ecc6f65f53f662c4415c7675a0331d0992ec66" + integrity sha1-pezG9l9T9mLEQVx2daAzHQmS7GY= + optionalDependencies: + graceful-fs "^4.1.6" + jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" @@ -6388,6 +6633,11 @@ lightercollective@^0.1.0: resolved "https://registry.yarnpkg.com/lightercollective/-/lightercollective-0.1.0.tgz#70df102c530dcb8d0ccabfe6175a8d00d5f61300" integrity sha512-J9tg5uraYoQKaWbmrzDDexbG6hHnMcWS1qLYgJSWE+mpA3U5OCSeMUhb+K55otgZJ34oFdR0ECvdIb3xuO5JOQ== +limiter@^1.0.5: + version "1.1.4" + resolved "https://registry.yarnpkg.com/limiter/-/limiter-1.1.4.tgz#87c9c3972d389fdb0ba67a45aadbc5d2f8413bc1" + integrity sha512-XCpr5bElgDI65vVgstP8TWjv6/QKWm9GU5UG0Pr5sLQ3QLo8NVKsioe+Jed5/3vFOe3IQuqE7DKwTvKQkjTHvg== + lint-staged@^7.3.0: version "7.3.0" resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-7.3.0.tgz#90ff33e5ca61ed3dbac35b6f6502dbefdc0db58d" @@ -6515,6 +6765,16 @@ loader-utils@^1.0.1, loader-utils@^1.1.0: emojis-list "^2.0.0" json5 "^1.0.1" +localtunnel@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/localtunnel/-/localtunnel-1.9.1.tgz#1d1737eab658add5a40266d8e43f389b646ee3b1" + integrity sha512-HWrhOslklDvxgOGFLxi6fQVnvpl6XdX4sPscfqMZkzi3gtt9V7LKBWYvNUcpHSVvjwCQ6xzXacVvICNbNcyPnQ== + dependencies: + axios "0.17.1" + debug "2.6.9" + openurl "1.1.1" + yargs "6.6.0" + locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" @@ -6657,6 +6917,11 @@ lodash.isarray@^3.0.0: resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" integrity sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U= +lodash.isfinite@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz#fb89b65a9a80281833f0b7478b3a5104f898ebb3" + integrity sha1-+4m2WpqAKBgz8LdHizpRBPiY67M= + lodash.keys@^3.0.0: version "3.1.2" resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" @@ -7095,7 +7360,7 @@ methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= -micromatch@^2.1.5: +micromatch@2.3.11, micromatch@^2.1.5: version "2.3.11" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU= @@ -7251,6 +7516,11 @@ mississippi@^3.0.0: stream-each "^1.1.0" through2 "^2.0.0" +mitt@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/mitt/-/mitt-1.1.3.tgz#528c506238a05dce11cd914a741ea2cc332da9b8" + integrity sha512-mUDCnVNsAi+eD6qA0HkRkwYczbLHJ49z17BGe2PYRhZL4wpZUFZGJHU7/5tmvohoma+Hdn0Vh/oJTiPEmgSruA== + mixin-deep@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" @@ -7595,6 +7865,11 @@ normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1: dependencies: remove-trailing-separator "^1.0.1" +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + normalize-range@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" @@ -7731,7 +8006,7 @@ object-keys@^1.0.11, object-keys@^1.0.12: resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2" integrity sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag== -object-path@^0.9.2: +object-path@^0.9.0, object-path@^0.9.2: version "0.9.2" resolved "https://registry.yarnpkg.com/object-path/-/object-path-0.9.2.tgz#0fd9a74fc5fad1ae3968b586bda5c632bd6c05a5" integrity sha1-D9mnT8X60a45aLWGvaXGMr1sBaU= @@ -7843,6 +8118,18 @@ onetime@^2.0.0: dependencies: mimic-fn "^1.0.0" +openurl@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/openurl/-/openurl-1.1.1.tgz#3875b4b0ef7a52c156f0db41d4609dbb0f94b387" + integrity sha1-OHW0sO96UsFW8NtB1GCduw+Us4c= + +opn@5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.3.0.tgz#64871565c863875f052cfdf53d3e3cb5adb53b1c" + integrity sha512-bYJHo/LOmoTd+pfiYhfZDnf9zekVJrY+cnS2a5F2x+w5ppvTqObojTP7WiFG+kVZs9Inw+qQ/lw7TroWwhdd2g== + dependencies: + is-wsl "^1.1.0" + opn@^5.1.0: version "5.4.0" resolved "https://registry.yarnpkg.com/opn/-/opn-5.4.0.tgz#cb545e7aab78562beb11aa3bfabc7042e1761035" @@ -8338,6 +8625,14 @@ portfinder@^1.0.9: debug "^2.2.0" mkdirp "0.5.x" +portscanner@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/portscanner/-/portscanner-2.1.1.tgz#eabb409e4de24950f5a2a516d35ae769343fbb96" + integrity sha1-6rtAnk3iSVD1oqUW01rnaTQ/u5Y= + dependencies: + async "1.5.2" + is-number-like "^1.0.3" + posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" @@ -8674,6 +8969,11 @@ qjobs@^1.1.4: resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071" integrity sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg== +qs@6.2.3: + version "6.2.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.3.tgz#1cfcb25c10a9b2b483053ff39f5dfc9233908cfe" + integrity sha1-HPyyXBCpsrSDBT/zn138kjOQjP4= + qs@6.5.2, qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" @@ -8728,7 +9028,7 @@ range-parser@^1.0.3, range-parser@^1.2.0, range-parser@~1.2.0: resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= -raw-body@2.3.3: +raw-body@2.3.3, raw-body@^2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" integrity sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw== @@ -8903,7 +9203,7 @@ readdir-scoped-modules@^1.0.0: graceful-fs "^4.1.2" once "^1.3.0" -readdirp@^2.0.0: +readdirp@^2.0.0, readdirp@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== @@ -9171,7 +9471,7 @@ requirejs@^2.3.5: resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.3.6.tgz#e5093d9601c2829251258c0b9445d4d19fa9e7c9" integrity sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg== -requires-port@^1.0.0: +requires-port@1.x.x, requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= @@ -9264,6 +9564,14 @@ resolve@^1.1.6, resolve@^1.1.7, resolve@^1.3.2, resolve@^1.4.0, resolve@^1.9.0: dependencies: path-parse "^1.0.6" +resp-modifier@6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/resp-modifier/-/resp-modifier-6.0.2.tgz#b124de5c4fbafcba541f48ffa73970f4aa456b4f" + integrity sha1-sSTeXE+6/LpUH0j/pzlw9KpFa08= + dependencies: + debug "^2.2.0" + minimatch "^3.0.2" + restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" @@ -9357,6 +9665,11 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" +rx@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" + integrity sha1-pfE/957zt0D+MKqAP7CfmIBdR4I= + rxjs-tslint-rules@4.10.0: version "4.10.0" resolved "https://registry.yarnpkg.com/rxjs-tslint-rules/-/rxjs-tslint-rules-4.10.0.tgz#8b5d0b4e6bcb5f4c313d2b104043778e8b8fdaf0" @@ -9375,6 +9688,13 @@ rxjs@6.3.3, rxjs@^6.1.0, rxjs@^6.3.3: dependencies: tslib "^1.9.0" +rxjs@^5.5.6: + version "5.5.12" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.12.tgz#6fa61b8a77c3d793dbaf270bee2f43f652d741cc" + integrity sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw== + dependencies: + symbol-observable "1.0.1" + safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -9570,7 +9890,7 @@ serialize-javascript@^1.4.0: resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.6.1.tgz#4d1f697ec49429a847ca6f442a2a755126c4d879" integrity sha512-A5MOagrPFga4YaKQSWHryl7AXvbQkEqpw4NNYMTNYUNV51bA8ABHgYFpqKx+YFFrw59xMV1qGH1R4AgoNIVgCw== -serve-index@^1.7.2: +serve-index@1.9.1, serve-index@^1.7.2: version "1.9.1" resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" integrity sha1-03aNabHn2C5c4FD/9bRTvqEqkjk= @@ -9593,6 +9913,11 @@ serve-static@1.13.2: parseurl "~1.3.2" send "0.16.2" +server-destroy@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/server-destroy/-/server-destroy-1.0.1.tgz#f13bf928e42b9c3e79383e61cc3998b5d14e6cdd" + integrity sha1-8Tv5KOQrnD55OD5hzDmYtdFObN0= + set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -9771,6 +10096,26 @@ socket.io-client@2.1.1: socket.io-parser "~3.2.0" to-array "0.1.4" +socket.io-client@^2.0.4: + version "2.2.0" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.2.0.tgz#84e73ee3c43d5020ccc1a258faeeb9aec2723af7" + integrity sha512-56ZrkTDbdTLmBIyfFYesgOxsjcLnwAKoN4CiPyTVkMQj3zTUh0QAx3GbvIvLpFEOvQWu92yyWICxB0u7wkVbYA== + dependencies: + backo2 "1.0.2" + base64-arraybuffer "0.1.5" + component-bind "1.0.0" + component-emitter "1.2.1" + debug "~3.1.0" + engine.io-client "~3.3.1" + has-binary2 "~1.0.2" + has-cors "1.1.0" + indexof "0.0.1" + object-component "0.0.3" + parseqs "0.0.5" + parseuri "0.0.5" + socket.io-parser "~3.3.0" + to-array "0.1.4" + socket.io-parser@~3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.2.0.tgz#e7c6228b6aa1f814e6148aea325b51aa9499e077" @@ -9780,6 +10125,15 @@ socket.io-parser@~3.2.0: debug "~3.1.0" isarray "2.0.1" +socket.io-parser@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.0.tgz#2b52a96a509fdf31440ba40fed6094c7d4f1262f" + integrity sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng== + dependencies: + component-emitter "1.2.1" + debug "~3.1.0" + isarray "2.0.1" + socket.io@2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.1.1.tgz#a069c5feabee3e6b214a75b40ce0652e1cfb9980" @@ -10151,6 +10505,14 @@ stream-shift@^1.0.0: resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" integrity sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI= +stream-throttle@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/stream-throttle/-/stream-throttle-0.1.3.tgz#add57c8d7cc73a81630d31cd55d3961cfafba9c3" + integrity sha1-rdV8jXzHOoFjDTHNVdOWHPr7qcM= + dependencies: + commander "^2.2.0" + limiter "^1.0.5" + streamroller@0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-0.7.0.tgz#a1d1b7cf83d39afb0d63049a5acbf93493bdf64b" @@ -10445,6 +10807,11 @@ swap-case@^1.1.0: lower-case "^1.1.1" upper-case "^1.1.1" +symbol-observable@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" + integrity sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ= + symbol-observable@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" @@ -10560,6 +10927,14 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= +tfunk@^3.0.1: + version "3.1.0" + resolved "https://registry.yarnpkg.com/tfunk/-/tfunk-3.1.0.tgz#38e4414fc64977d87afdaa72facb6d29f82f7b5b" + integrity sha1-OORBT8ZJd9h6/apy+sttKfgve1s= + dependencies: + chalk "^1.1.1" + object-path "^0.9.0" + through2-filter@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-3.0.0.tgz#700e786df2367c2c88cd8aa5be4cf9c1e7831254" @@ -10991,6 +11366,11 @@ typescript@~2.7.1: resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.7.2.tgz#2d615a1ef4aee4f574425cdff7026edf81919836" integrity sha512-p5TCYZDAO0m4G344hD+wx/LATebLWZNkkh2asWUFqSsD2OrDNhbAHuSjobrmsUmdzjJjEeZVU9g1h3O6vpstnw== +ua-parser-js@0.7.17: + version "0.7.17" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" + integrity sha512-uRdSdu1oA1rncCQL7sCj8vSyZkgtL7faaw9Tc9rZ3mGgraQ7+Pdx7w5mnOSF3gw9ZNG6oc+KXfkon3bKuROm0g== + uglify-js@3.4.x, uglify-js@^3.1.4: version "3.4.9" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3" @@ -11176,7 +11556,7 @@ unset-value@^1.0.0: has-value "^0.3.1" isobject "^3.0.0" -upath@^1.0.5: +upath@^1.0.5, upath@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" integrity sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw== @@ -11728,6 +12108,11 @@ window-size@^0.1.4: resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" integrity sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY= +window-size@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" + integrity sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU= + windows-release@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.1.0.tgz#8d4a7e266cbf5a233f6c717dac19ce00af36e12e" @@ -11806,6 +12191,13 @@ ws@~3.3.1: safe-buffer "~5.1.0" ultron "~1.1.0" +ws@~6.1.0: + version "6.1.4" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9" + integrity sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA== + dependencies: + async-limiter "~1.0.0" + x-is-string@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/x-is-string/-/x-is-string-0.1.0.tgz#474b50865af3a49a9c4657f05acd145458f77d82" @@ -11878,6 +12270,13 @@ yargs-parser@^11.1.1: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@^4.1.0, yargs-parser@^4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c" + integrity sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw= + dependencies: + camelcase "^3.0.0" + yargs-parser@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" @@ -11917,6 +12316,45 @@ yargs@12.0.2: y18n "^3.2.1 || ^4.0.0" yargs-parser "^10.1.0" +yargs@6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.4.0.tgz#816e1a866d5598ccf34e5596ddce22d92da490d4" + integrity sha1-gW4ahm1VmMzzTlWW3c4i2S2kkNQ= + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + window-size "^0.2.0" + y18n "^3.2.1" + yargs-parser "^4.1.0" + +yargs@6.6.0: + version "6.6.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208" + integrity sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg= + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + y18n "^3.2.1" + yargs-parser "^4.2.0" + yargs@9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-9.0.1.tgz#52acc23feecac34042078ee78c0c007f5085db4c"