diff --git a/.editorconfig b/.editorconfig
index 6e87a003d..510fa8f6d 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,4 +1,8 @@
+<<<<<<< HEAD
+# Editor configuration, see https://editorconfig.org
+=======
# Editor configuration, see http://editorconfig.org
+>>>>>>> 931316b1596d118e9d78dcb00fc326c6e4d3166c
root = true
[*]
@@ -8,6 +12,12 @@ indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
+<<<<<<< HEAD
+[*.ts]
+quote_type = single
+
+=======
+>>>>>>> 931316b1596d118e9d78dcb00fc326c6e4d3166c
[*.md]
max_line_length = off
trim_trailing_whitespace = false
diff --git a/.gitignore b/.gitignore
index 207803cb0..9ca5e0b4e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,10 +4,22 @@
/dist
/tmp
/out-tsc
+<<<<<<< HEAD
+# Only exists if Bazel was run
+/bazel-out
+
+# dependencies
+/node_modules
+
+# profiling files
+chrome-profiler-events*.json
+speed-measure-plugin*.json
+=======
# dependencies
/node_modules
yarn.lock
+>>>>>>> 931316b1596d118e9d78dcb00fc326c6e4d3166c
# IDEs and editors
/.idea
@@ -24,11 +36,26 @@ yarn.lock
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
+<<<<<<< HEAD
+.history/*
+=======
+>>>>>>> 931316b1596d118e9d78dcb00fc326c6e4d3166c
# misc
/.sass-cache
/connect.lock
/coverage
+<<<<<<< HEAD
+/libpeerconnection.log
+npm-debug.log
+yarn-error.log
+testem.log
+/typings
+
+# System Files
+.DS_Store
+Thumbs.db
+=======
/typings
.firebase
*.log
@@ -47,3 +74,4 @@ yarn.lock
ehthumbs.db
Thumbs.db
+>>>>>>> 931316b1596d118e9d78dcb00fc326c6e4d3166c
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 000000000..fa1ceff3c
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,914 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1591561543202
+
+
+ 1591561543202
+
+
+
+
+
+
+
+
+
+ 1591562148848
+
+
+
+ 1591562148848
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index b60b76b42..d20667351 100644
--- a/README.md
+++ b/README.md
@@ -1,49 +1,27 @@
-[](https://nycjsorg.now.sh) [](https://codelab.fun)
+# Quiz
-# Angular Codelab - [codelab.fun](https://codelab.fun)
+This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 9.1.7.
-Angular Codelab is a self-paced interactive Angular course:
+## Development server
-
-
-- 🔥 Everything in the browser - **no setup needed**
-- 🔥 **Interactive code samples** - Change the code and see the result immediately!
-- 🔥 Hands-on **Exercises** to solidify your knowledge
-- 🔥 **Free** - Made for Angular enthusiasts by Angular enthusiasts
-- 🔥 Written in Angular and **open source**
+Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
-Try it out yourself at [codelab.fun](https://codelab.fun)
+## Code scaffolding
-## Help us make Codelab.fun better
+Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
-- [Contribute to the codebase](#contribute-to-the-codebase)
-- [Host a live Angular Codelab event in your city](#host-a-live-angular-codelab-event-in-your-city)
-- [Translate Codelab to your language](#translate-codelab-to-your-language)
+## Build
-### Contribute to the codebase
+Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
-Codelab.fun is an Angular app!
+## Running unit tests
-It uses [angular-cli](https://cli.angular.io/) with [nx](https://nx.dev) and all materials are in a form of Angular components.
+Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
-
+## Running end-to-end tests
-See what [Good first issues](https://github.com/codelab-fun/codelab/issues?q=is%3Aissue+is%3Aopen+label%3Agood-first-issue) are available.
+Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
-See [CONTRIBUTING.md](./docs/CONTRIBUTING.md) for detailed instructions.
+## Further help
-### Host a live Angular Codelab event in your city
-
-We have hosted multiple live codelab events in 10+ cities, and you can help us host one in yours!
-
-See how in [HOSTING.md](./docs/HOSTING.md)
-
-
-
-### Translate Codelab to your language
-
-Currently codelab.fun is availble in English and Russian.
-
-See [TRANSLATING.md](./docs/TRANSLATING.md) for how you can help us translate the codelab into your language.
-
-Thanks to amazing [PoEditor](https://poeditor.com) for providing us with an open source licence
+To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
diff --git a/angular.json b/angular.json
index 55c146558..051c50d0a 100644
--- a/angular.json
+++ b/angular.json
@@ -1,778 +1,43 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
- "newProjectRoot": "",
+ "newProjectRoot": "projects",
"projects": {
- "codelab": {
- "root": "apps/codelab",
- "sourceRoot": "apps/codelab/src",
+ "quiz": {
"projectType": "application",
- "architect": {
- "build": {
- "builder": "@angular-builders/custom-webpack:browser",
- "options": {
- "customWebpackConfig": {
- "path": "apps/codelab/extra-webpack.config.js"
- },
- "outputPath": "dist/apps/codelab",
- "index": "apps/codelab/src/index.html",
- "main": "apps/codelab/src/main.ts",
- "tsConfig": "apps/codelab/tsconfig.app.json",
- "polyfills": "apps/codelab/src/polyfills.ts",
- "aot": true,
- "assets": [
- "apps/codelab/src/assets",
- "apps/codelab/src/favicon.ico",
- "apps/codelab/src/manifest.webmanifest",
- {
- "glob": "**/*",
- "input": "node_modules/monaco-editor/",
- "output": "./assets/monaco/"
- },
- {
- "glob": "**/*",
- "input": "libs/intro/assets/",
- "output": "./assets/intro/"
- },
- {
- "glob": "**/*",
- "input": "libs/code-demos/assets/runner/",
- "output": "./assets/runner/"
- }
- ],
- "styles": ["apps/codelab/src/styles.scss"],
- "scripts": []
- },
- "configurations": {
- "ru": {
- "optimization": true,
- "outputHashing": "all",
- "sourceMap": false,
- "extractCss": true,
- "namedChunks": true,
- "aot": true,
- "extractLicenses": true,
- "vendorChunk": false,
- "buildOptimizer": true,
- "baseHref": "/ru/",
- "deployUrl": "/ru/",
- "fileReplacements": [
- {
- "replace": "apps/codelab/src/environments/environment.ts",
- "with": "apps/codelab/src/environments/environment.prod.ts"
- }
- ],
- "outputPath": "dist/apps/codelab/ru",
- "i18nFile": "apps/codelab/src/locale/codelab.ru.xtb",
- "i18nFormat": "xtb",
- "i18nLocale": "ru"
- },
- "production": {
- "optimization": true,
- "outputHashing": "all",
- "sourceMap": false,
- "extractCss": true,
- "namedChunks": false,
- "aot": true,
- "extractLicenses": true,
- "vendorChunk": false,
- "buildOptimizer": true,
- "fileReplacements": [
- {
- "replace": "apps/codelab/src/environments/environment.ts",
- "with": "apps/codelab/src/environments/environment.prod.ts"
- }
- ],
- "serviceWorker": false
- }
- }
- },
- "serve": {
- "builder": "@angular-builders/custom-webpack:dev-server",
- "options": {
- "browserTarget": "codelab:build"
- },
- "configurations": {
- "production": {
- "browserTarget": "codelab:build:production"
- },
- "ru": {
- "browserTarget": "codelab:build:ru"
- }
- }
- },
- "extract-i18n": {
- "builder": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "browserTarget": "codelab:build"
- }
- },
- "test": {
- "builder": "@angular-devkit/build-angular:karma",
- "options": {
- "main": "apps/codelab/src/test.ts",
- "karmaConfig": "apps/codelab/karma.conf.js",
- "polyfills": "apps/codelab/src/polyfills.ts",
- "tsConfig": "apps/codelab/tsconfig.spec.json",
- "scripts": [],
- "styles": ["apps/codelab/src/styles.scss"],
- "assets": [
- "apps/codelab/src/assets",
- "apps/codelab/src/favicon.ico",
- "apps/codelab/src/manifest.webmanifest"
- ]
- }
- },
- "lint": {
- "builder": "@angular-devkit/build-angular:tslint",
- "options": {
- "tsConfig": [
- "apps/codelab/tsconfig.app.json",
- "apps/codelab/tsconfig.spec.json"
- ],
- "exclude": []
- }
- }
- }
- },
- "browser": {
- "root": "libs/browser",
- "sourceRoot": "libs/browser/src",
- "projectType": "library",
- "prefix": "codelab",
- "architect": {
- "lint": {
- "builder": "@angular-devkit/build-angular:tslint",
- "options": {
- "tsConfig": [
- "libs/browser/tsconfig.lib.json",
- "libs/browser/tsconfig.spec.json"
- ],
- "exclude": ["**/node_modules/**"]
- }
- }
- }
- },
- "console": {
- "root": "libs/console",
- "sourceRoot": "libs/console/src",
- "projectType": "library",
- "prefix": "codelab",
- "architect": {
- "test": {
- "builder": "@angular-devkit/build-angular:karma",
- "options": {
- "main": "libs/console/src/test.ts",
- "tsConfig": "libs/console/tsconfig.spec.json",
- "karmaConfig": "libs/console/karma.conf.js"
- }
- },
- "lint": {
- "builder": "@angular-devkit/build-angular:tslint",
- "options": {
- "tsConfig": [
- "libs/console/tsconfig.lib.json",
- "libs/console/tsconfig.spec.json"
- ],
- "exclude": ["**/node_modules/**"]
- }
- }
- }
- },
- "utils": {
- "root": "libs/utils",
- "sourceRoot": "libs/utils/src",
- "projectType": "library",
- "prefix": "codelab",
- "architect": {
- "test": {
- "builder": "@angular-devkit/build-angular:karma",
- "options": {
- "main": "libs/utils/src/test.ts",
- "tsConfig": "libs/utils/tsconfig.spec.json",
- "karmaConfig": "libs/utils/karma.conf.js"
- }
- },
- "lint": {
- "builder": "@angular-devkit/build-angular:tslint",
- "options": {
- "tsConfig": [
- "libs/utils/tsconfig.lib.json",
- "libs/utils/tsconfig.spec.json"
- ],
- "exclude": ["**/node_modules/**"]
- }
- }
- }
- },
- "kirjs": {
- "root": "apps/kirjs/",
- "sourceRoot": "apps/kirjs/src",
- "projectType": "application",
- "prefix": "kirjs",
- "schematics": {},
- "architect": {
- "build": {
- "builder": "@angular-devkit/build-angular:browser",
- "options": {
- "aot": true,
- "outputPath": "dist/apps/kirjs",
- "index": "apps/kirjs/src/index.html",
- "main": "apps/kirjs/src/main.ts",
- "polyfills": "apps/kirjs/src/polyfills.ts",
- "tsConfig": "apps/kirjs/tsconfig.app.json",
- "assets": [
- {
- "glob": "**/*",
- "input": "node_modules/monaco-editor/",
- "output": "./assets/monaco/"
- },
- "apps/kirjs/src/favicon.ico",
- "apps/kirjs/src/assets",
- {
- "glob": "**/*",
- "input": "libs/code-demos/assets/runner/",
- "output": "./assets/runner/"
- }
- ],
- "styles": ["apps/kirjs/src/styles.css"],
- "scripts": []
- },
- "configurations": {
- "ru": {
- "outputPath": "dist/apps/kirjs/ru",
- "aot": true,
- "i18nFile": "apps/kirjs/src/locale/kirjs.ru.xtb",
- "i18nFormat": "xtb",
- "i18nLocale": "ru"
- },
- "production": {
- "fileReplacements": [
- {
- "replace": "apps/kirjs/src/environments/environment.ts",
- "with": "apps/kirjs/src/environments/environment.prod.ts"
- }
- ],
- "optimization": true,
- "outputHashing": "all",
- "sourceMap": false,
- "extractCss": true,
- "namedChunks": false,
- "aot": true,
- "extractLicenses": true,
- "vendorChunk": false,
- "buildOptimizer": true
- }
- }
- },
- "serve": {
- "builder": "@angular-devkit/build-angular:dev-server",
- "options": {
- "browserTarget": "kirjs:build"
- },
- "configurations": {
- "production": {
- "browserTarget": "kirjs:build:production"
- },
- "ru": {
- "browserTarget": "kirjs:build:ru"
- }
- }
- },
- "extract-i18n": {
- "builder": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "browserTarget": "kirjs:build"
- },
- "configurations": {
- "ru": {
- "outputPath": "locale/",
- "outFile": "messages.ru.untranslated.xlf",
- "i18nFormat": "xlf",
- "i18nLocale": "ru"
- }
- }
- },
- "test": {
- "builder": "@angular-devkit/build-angular:karma",
- "options": {
- "main": "apps/kirjs/src/test.ts",
- "polyfills": "apps/kirjs/src/polyfills.ts",
- "tsConfig": "apps/kirjs/tsconfig.spec.json",
- "karmaConfig": "apps/kirjs/karma.conf.js",
- "styles": ["apps/kirjs/src/styles.css"],
- "scripts": [],
- "assets": ["apps/kirjs/src/favicon.ico", "apps/kirjs/src/assets"]
- }
- },
- "lint": {
- "builder": "@angular-devkit/build-angular:tslint",
- "options": {
- "tsConfig": [
- "apps/kirjs/tsconfig.app.json",
- "apps/kirjs/tsconfig.spec.json"
- ],
- "exclude": ["**/node_modules/**"]
- }
- }
- }
- },
- "angular-ast-viz": {
- "root": "libs/angular-ast-viz",
- "sourceRoot": "libs/angular-ast-viz/src",
- "projectType": "library",
- "prefix": "codelab",
- "architect": {
- "build": {
- "builder": "@nrwl/angular:package",
- "options": {
- "tsConfig": "libs/angular-ast-viz/tsconfig.lib.json",
- "project": "libs/angular-ast-viz/ng-package.json"
- },
- "configurations": {
- "production": {
- "project": "libs/angular-ast-viz/ng-package.prod.json"
- }
- }
- },
- "test": {
- "builder": "@angular-devkit/build-angular:karma",
- "options": {
- "main": "libs/angular-ast-viz/src/test.ts",
- "tsConfig": "libs/angular-ast-viz/tsconfig.spec.json",
- "karmaConfig": "libs/angular-ast-viz/karma.conf.js"
- }
- },
- "lint": {
- "builder": "@angular-devkit/build-angular:tslint",
- "options": {
- "tsConfig": [
- "libs/angular-ast-viz/tsconfig.lib.json",
- "libs/angular-ast-viz/tsconfig.spec.json"
- ],
- "exclude": ["**/node_modules/**"]
- }
- }
- }
- },
- "angular-slides-to-pdf": {
- "root": "libs/angular-slides-to-pdf",
- "sourceRoot": "libs/angular-slides-to-pdf/src",
- "projectType": "library",
- "prefix": "codelab",
- "architect": {
- "build": {
- "builder": "@nrwl/angular:package",
- "options": {
- "tsConfig": "libs/angular-slides-to-pdf/tsconfig.lib.json",
- "project": "libs/angular-slides-to-pdf/ng-package.json"
- },
- "configurations": {
- "production": {
- "project": "libs/angular-slides-to-pdf/ng-package.prod.json"
- }
- }
- },
- "test": {
- "builder": "@angular-devkit/build-angular:karma",
- "options": {
- "main": "libs/angular-slides-to-pdf/src/test.ts",
- "tsConfig": "libs/angular-slides-to-pdf/tsconfig.spec.json",
- "karmaConfig": "libs/angular-slides-to-pdf/karma.conf.js"
- }
- },
- "lint": {
- "builder": "@angular-devkit/build-angular:tslint",
- "options": {
- "tsConfig": [
- "libs/angular-slides-to-pdf/tsconfig.lib.json",
- "libs/angular-slides-to-pdf/tsconfig.spec.json"
- ],
- "exclude": ["**/node_modules/**"]
- }
- }
- }
- },
- "feedback": {
- "root": "libs/feedback",
- "sourceRoot": "libs/feedback/src",
- "projectType": "library",
- "prefix": "codelab",
- "architect": {
- "build": {
- "builder": "@nrwl/angular:package",
- "options": {
- "tsConfig": "libs/feedback/tsconfig.lib.json",
- "project": "libs/feedback/ng-package.json"
- }
- },
- "test": {
- "builder": "@angular-devkit/build-angular:karma",
- "options": {
- "main": "libs/feedback/src/test.ts",
- "tsConfig": "libs/feedback/tsconfig.spec.json",
- "karmaConfig": "libs/feedback/karma.conf.js"
- }
- },
- "lint": {
- "builder": "@angular-devkit/build-angular:tslint",
- "options": {
- "tsConfig": [
- "libs/feedback/tsconfig.lib.json",
- "libs/feedback/tsconfig.spec.json"
- ],
- "exclude": ["**/node_modules/**"]
- }
- }
- }
- },
- "code-demos": {
- "root": "libs/code-demos",
- "sourceRoot": "libs/code-demos/src",
- "projectType": "library",
- "prefix": "codelab",
- "architect": {
- "build": {
- "builder": "@nrwl/angular:package",
- "options": {
- "tsConfig": "libs/code-demos/tsconfig.lib.json",
- "project": "libs/code-demos/ng-package.json"
- },
- "configurations": {
- "production": {
- "project": "libs/code-demos/ng-package.prod.json"
- }
- }
- },
- "lint": {
- "builder": "@angular-devkit/build-angular:tslint",
- "options": {
- "tsConfig": [
- "libs/code-demos/tsconfig.lib.json",
- "libs/code-demos/tsconfig.spec.json"
- ],
- "exclude": ["**/node_modules/**"]
- }
- },
- "test": {
- "builder": "@nrwl/jest:jest",
- "options": {
- "jestConfig": "libs/code-demos/jest.config.js",
- "tsConfig": "libs/code-demos/tsconfig.spec.json",
- "setupFile": "libs/code-demos/src/test-setup.ts"
- }
- }
- }
- },
- "live": {
- "root": "libs/live",
- "sourceRoot": "libs/live/src",
- "projectType": "library",
- "prefix": "live",
- "architect": {
- "build": {
- "builder": "@nrwl/angular:package",
- "options": {
- "tsConfig": "libs/live/tsconfig.lib.json",
- "project": "libs/live/ng-package.json"
- }
- },
- "lint": {
- "builder": "@angular-devkit/build-angular:tslint",
- "options": {
- "tsConfig": [
- "libs/live/tsconfig.lib.json",
- "libs/live/tsconfig.spec.json"
- ],
- "exclude": ["**/node_modules/**"]
- }
- },
- "test": {
- "builder": "@nrwl/jest:jest",
- "options": {
- "jestConfig": "libs/live/jest.config.js",
- "tsConfig": "libs/live/tsconfig.spec.json"
- }
- }
- },
- "schematics": {}
- },
- "firebase-login": {
- "root": "libs/firebase-login",
- "sourceRoot": "libs/firebase-login/src",
- "projectType": "library",
- "prefix": "angular-presentation",
- "architect": {
- "build": {
- "builder": "@nrwl/angular:package",
- "options": {
- "tsConfig": "libs/firebase-login/tsconfig.lib.json",
- "project": "libs/firebase-login/ng-package.json"
- }
- },
- "test": {
- "builder": "@angular-devkit/build-angular:karma",
- "options": {
- "main": "libs/firebase-login/src/test.ts",
- "tsConfig": "libs/firebase-login/tsconfig.spec.json",
- "karmaConfig": "libs/firebase-login/karma.conf.js"
- }
- },
- "lint": {
- "builder": "@angular-devkit/build-angular:tslint",
- "options": {
- "tsConfig": [
- "libs/firebase-login/tsconfig.lib.json",
- "libs/firebase-login/tsconfig.spec.json"
- ],
- "exclude": ["**/node_modules/**"]
- }
- }
- }
- },
- "blog": {
- "root": "apps/blog/",
- "sourceRoot": "apps/blog/src",
- "projectType": "application",
- "prefix": "codelab",
"schematics": {
- "@nrwl/schematics:component": {
+ "@schematics/angular:component": {
"style": "scss"
}
},
+ "root": "",
+ "sourceRoot": "src",
+ "prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
- "outputPath": "dist/apps/blog",
- "index": "apps/blog/src/index.html",
- "main": "apps/blog/src/main.ts",
- "polyfills": "apps/blog/src/polyfills.ts",
- "tsConfig": "apps/blog/tsconfig.app.json",
- "assets": ["apps/blog/src/favicon.ico", "apps/blog/src/assets"],
- "styles": ["apps/blog/src/styles.scss"],
- "scripts": []
- },
- "configurations": {
- "production": {
- "fileReplacements": [
- {
- "replace": "apps/blog/src/environments/environment.ts",
- "with": "apps/blog/src/environments/environment.prod.ts"
- }
- ],
- "optimization": true,
- "outputHashing": "all",
- "sourceMap": false,
- "extractCss": true,
- "namedChunks": false,
- "aot": true,
- "extractLicenses": true,
- "vendorChunk": false,
- "buildOptimizer": true,
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "2mb",
- "maximumError": "20mb"
- }
- ]
- }
- }
- },
- "serve": {
- "builder": "@angular-devkit/build-angular:dev-server",
- "options": {
- "browserTarget": "blog:build"
- },
- "configurations": {
- "production": {
- "browserTarget": "blog:build:production"
- }
- }
- },
- "extract-i18n": {
- "builder": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "browserTarget": "blog:build"
- }
- },
- "lint": {
- "builder": "@angular-devkit/build-angular:tslint",
- "options": {
- "tsConfig": [
- "apps/blog/tsconfig.app.json",
- "apps/blog/tsconfig.spec.json"
- ],
- "exclude": ["**/node_modules/**"]
- }
- },
- "test": {
- "builder": "@nrwl/jest:jest",
- "options": {
- "jestConfig": "apps/blog/jest.config.js",
- "tsConfig": "apps/blog/tsconfig.spec.json",
- "setupFile": "apps/blog/src/test-setup.ts"
- }
- }
- }
- },
- "angular-thirty-seconds": {
- "root": "apps/angular-thirty-seconds/",
- "sourceRoot": "apps/angular-thirty-seconds/src",
- "projectType": "application",
- "prefix": "codelab",
- "schematics": {
- "@nrwl/schematics:component": {
- "style": "scss"
- }
- },
- "architect": {
- "build": {
- "builder": "@angular-devkit/build-angular:browser",
- "options": {
- "outputPath": "dist/apps/codelab/30",
- "index": "apps/angular-thirty-seconds/src/index.html",
- "main": "apps/angular-thirty-seconds/src/main.ts",
- "polyfills": "apps/angular-thirty-seconds/src/polyfills.ts",
- "tsConfig": "apps/angular-thirty-seconds/tsconfig.app.json",
+ "outputPath": "dist/quiz",
+ "index": "src/index.html",
+ "main": "src/main.ts",
+ "polyfills": "src/polyfills.ts",
+ "tsConfig": "tsconfig.app.json",
+ "aot": true,
"assets": [
- {
- "glob": "**/*",
- "input": "node_modules/monaco-editor/",
- "output": "./assets/monaco/"
- },
- "apps/angular-thirty-seconds/src/favicon.ico",
- "apps/angular-thirty-seconds/src/assets",
- {
- "glob": "**/*",
- "input": "libs/code-demos/assets/runner/",
- "output": "./assets/runner/"
- }
+ "src/favicon.ico",
+ "src/assets"
],
"styles": [
- "apps/angular-thirty-seconds/src/styles.scss",
- "node_modules/prismjs/themes/prism-okaidia.css",
- "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.css"
+ "src/styles.scss"
],
- "scripts": [
- "node_modules/prismjs/prism.js",
- "node_modules/prismjs/components/prism-typescript.min.js",
- "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.js"
- ]
- },
- "configurations": {
- "production": {
- "fileReplacements": [
- {
- "replace": "apps/angular-thirty-seconds/src/environments/environment.ts",
- "with": "apps/angular-thirty-seconds/src/environments/environment.prod.ts"
- }
- ],
- "baseHref": "/30/",
- "deployUrl": "/30/",
- "optimization": true,
- "outputHashing": "all",
- "sourceMap": false,
- "extractCss": true,
- "namedChunks": false,
- "aot": true,
- "extractLicenses": true,
- "vendorChunk": false,
- "buildOptimizer": true,
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "60mb",
- "maximumError": "70mb"
- }
- ]
- }
- }
- },
- "serve": {
- "builder": "@angular-devkit/build-angular:dev-server",
- "options": {
- "browserTarget": "angular-thirty-seconds:build"
- },
- "configurations": {
- "production": {
- "browserTarget": "angular-thirty-seconds:build:production"
- }
- }
- },
- "extract-i18n": {
- "builder": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "browserTarget": "angular-thirty-seconds:build"
- }
- },
- "test": {
- "builder": "@angular-devkit/build-angular:karma",
- "options": {
- "main": "apps/angular-thirty-seconds/src/test.ts",
- "polyfills": "apps/angular-thirty-seconds/src/polyfills.ts",
- "tsConfig": "apps/angular-thirty-seconds/tsconfig.spec.json",
- "karmaConfig": "apps/angular-thirty-seconds/karma.conf.js",
- "styles": ["apps/angular-thirty-seconds/src/styles.scss"],
- "scripts": [],
- "assets": [
- "apps/angular-thirty-seconds/src/favicon.ico",
- "apps/angular-thirty-seconds/src/assets"
- ]
- }
- },
- "lint": {
- "builder": "@angular-devkit/build-angular:tslint",
- "options": {
- "tsConfig": [
- "apps/angular-thirty-seconds/tsconfig.app.json",
- "apps/angular-thirty-seconds/tsconfig.spec.json"
- ],
- "exclude": ["**/node_modules/**"]
- }
- }
- }
- },
- "lis": {
- "projectType": "application",
- "schematics": {},
- "root": "apps/lis",
- "sourceRoot": "apps/lis/src",
- "prefix": "codelab",
- "architect": {
- "build": {
- "builder": "@angular-devkit/build-angular:browser",
- "options": {
- "outputPath": "dist/apps/lis",
- "index": "apps/lis/src/index.html",
- "main": "apps/lis/src/main.ts",
- "polyfills": "apps/lis/src/polyfills.ts",
- "tsConfig": "apps/lis/tsconfig.app.json",
- "aot": false,
- "assets": [
- "apps/lis/src/favicon.ico",
- "apps/lis/src/assets",
- {
- "glob": "**/*",
- "input": "node_modules/monaco-editor/",
- "output": "./assets/monaco/"
- },
- {
- "glob": "**/*",
- "input": "libs/code-demos/assets/runner/",
- "output": "./assets/runner/"
- }
- ],
- "styles": ["apps/lis/src/styles.css"],
"scripts": []
},
"configurations": {
"production": {
"fileReplacements": [
{
- "replace": "apps/lis/src/environments/environment.ts",
- "with": "apps/lis/src/environments/environment.prod.ts"
+ "replace": "src/environments/environment.ts",
+ "with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
@@ -780,7 +45,6 @@
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
- "aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
@@ -802,265 +66,63 @@
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
- "browserTarget": "lis:build"
+ "browserTarget": "quiz:build"
},
"configurations": {
"production": {
- "browserTarget": "lis:build:production"
+ "browserTarget": "quiz:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
- "browserTarget": "lis:build"
- }
- },
- "lint": {
- "builder": "@angular-devkit/build-angular:tslint",
- "options": {
- "tsConfig": [
- "apps/lis/tsconfig.app.json",
- "apps/lis/tsconfig.spec.json"
- ],
- "exclude": ["**/node_modules/**", "!apps/lis/**"]
+ "browserTarget": "quiz:build"
}
},
"test": {
- "builder": "@nrwl/jest:jest",
- "options": {
- "jestConfig": "apps/lis/jest.config.js",
- "tsConfig": "apps/lis/tsconfig.spec.json",
- "setupFile": "apps/lis/src/test-setup.ts"
- }
- }
- }
- },
- "playground": {
- "projectType": "application",
- "schematics": {
- "@nrwl/angular:component": {
- "style": "scss"
- }
- },
- "root": "apps/playground",
- "sourceRoot": "apps/playground/src",
- "prefix": "codelab",
- "architect": {
- "build": {
- "builder": "@angular-devkit/build-angular:browser",
+ "builder": "@angular-devkit/build-angular:karma",
"options": {
- "outputPath": "dist/apps/playground",
- "index": "apps/playground/src/index.html",
- "main": "apps/playground/src/main.ts",
- "polyfills": "apps/playground/src/polyfills.ts",
- "tsConfig": "apps/playground/tsconfig.app.json",
- "aot": true,
+ "main": "src/test.ts",
+ "polyfills": "src/polyfills.ts",
+ "tsConfig": "tsconfig.spec.json",
+ "karmaConfig": "karma.conf.js",
"assets": [
- "apps/playground/src/favicon.ico",
- "apps/playground/src/assets",
- {
- "glob": "**/*",
- "input": "node_modules/monaco-editor/",
- "output": "./assets/monaco/"
- }
- ],
- "styles": ["apps/playground/src/styles.scss"],
- "scripts": []
- },
- "configurations": {
- "production": {
- "fileReplacements": [
- {
- "replace": "apps/playground/src/environments/environment.ts",
- "with": "apps/playground/src/environments/environment.prod.ts"
- }
- ],
- "optimization": true,
- "outputHashing": "all",
- "sourceMap": false,
- "extractCss": true,
- "namedChunks": false,
- "aot": true,
- "extractLicenses": true,
- "vendorChunk": false,
- "buildOptimizer": true,
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "20mb",
- "maximumError": "25mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "6kb",
- "maximumError": "10kb"
- }
- ]
- }
- }
- },
- "serve": {
- "builder": "@angular-devkit/build-angular:dev-server",
- "options": {
- "browserTarget": "playground:build"
- },
- "configurations": {
- "production": {
- "browserTarget": "playground:build:production"
- }
- }
- },
- "extract-i18n": {
- "builder": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "browserTarget": "playground:build"
- }
- },
- "lint": {
- "builder": "@angular-devkit/build-angular:tslint",
- "options": {
- "tsConfig": [
- "apps/playground/tsconfig.app.json",
- "apps/playground/tsconfig.spec.json"
+ "src/favicon.ico",
+ "src/assets"
],
- "exclude": ["**/node_modules/**", "!apps/playground/**"]
- }
- },
- "test": {
- "builder": "@nrwl/jest:jest",
- "options": {
- "jestConfig": "apps/playground/jest.config.js",
- "tsConfig": "apps/playground/tsconfig.spec.json",
- "setupFile": "apps/playground/src/test-setup.ts"
- }
- }
- }
- },
- "firebase": {
- "projectType": "library",
- "root": "libs/firebase",
- "sourceRoot": "libs/firebase/src",
- "prefix": "codelab",
- "architect": {
- "lint": {
- "builder": "@angular-devkit/build-angular:tslint",
- "options": {
- "tsConfig": [
- "libs/firebase/tsconfig.lib.json",
- "libs/firebase/tsconfig.spec.json"
+ "styles": [
+ "src/styles.scss"
],
- "exclude": ["**/node_modules/**", "!libs/firebase/**"]
+ "scripts": []
}
},
- "test": {
- "builder": "@nrwl/jest:jest",
- "options": {
- "jestConfig": "libs/firebase/jest.config.js",
- "tsConfig": "libs/firebase/tsconfig.spec.json",
- "setupFile": "libs/firebase/src/test-setup.ts"
- }
- }
- },
- "schematics": {}
- },
- "intro": {
- "projectType": "library",
- "root": "libs/intro",
- "sourceRoot": "libs/intro/src",
- "prefix": "codelab",
- "architect": {
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
- "libs/intro/tsconfig.lib.json",
- "libs/intro/tsconfig.spec.json"
+ "tsconfig.app.json",
+ "tsconfig.spec.json",
+ "e2e/tsconfig.json"
],
- "exclude": ["**/node_modules/**", "!libs/intro/**"]
+ "exclude": [
+ "**/node_modules/**"
+ ]
}
},
- "test": {
- "builder": "@nrwl/jest:jest",
+ "e2e": {
+ "builder": "@angular-devkit/build-angular:protractor",
"options": {
- "jestConfig": "libs/intro/jest.config.js",
- "tsConfig": "libs/intro/tsconfig.spec.json",
- "setupFile": "libs/intro/src/test-setup.ts"
- }
- }
- },
- "schematics": {}
- },
- "slides": {
- "projectType": "library",
- "root": "libs/slides",
- "sourceRoot": "libs/slides/src",
- "prefix": "codelab",
- "architect": {
- "build": {
- "builder": "@nrwl/angular:package",
- "options": {
- "tsConfig": "libs/slides/tsconfig.lib.json",
- "project": "libs/slides/ng-package.json"
+ "protractorConfig": "e2e/protractor.conf.js",
+ "devServerTarget": "quiz:serve"
},
"configurations": {
"production": {
- "tsConfig": "libs/slides/tsconfig.lib.prod.json"
+ "devServerTarget": "quiz:serve:production"
}
}
- },
- "lint": {
- "builder": "@angular-devkit/build-angular:tslint",
- "options": {
- "tsConfig": [
- "libs/slides/tsconfig.lib.json",
- "libs/slides/tsconfig.spec.json"
- ],
- "exclude": ["**/node_modules/**", "!libs/slides/**"]
- }
- },
- "test": {
- "builder": "@nrwl/jest:jest",
- "options": {
- "jestConfig": "libs/slides/jest.config.js",
- "tsConfig": "libs/slides/tsconfig.spec.json",
- "setupFile": "libs/slides/src/test-setup.ts"
- }
}
- },
- "schematics": {}
- }
- },
- "defaultProject": "codelab",
- "schematics": {
- "@schematics/angular:component": {
- "prefix": "slides",
- "style": "css"
- },
- "@schematics/angular:directive": {
- "prefix": "slides"
- },
- "@nrwl/schematics:library": {
- "unitTestRunner": "karma",
- "framework": "angular"
- },
- "@nrwl/schematics:application": {
- "unitTestRunner": "karma",
- "e2eTestRunner": "protractor"
- },
- "@nrwl/schematics:node-application": {
- "framework": "express"
- },
- "@nrwl/angular:application": {
- "unitTestRunner": "jest",
- "e2eTestRunner": "cypress"
- },
- "@nrwl/angular:library": {
- "unitTestRunner": "jest"
- }
- },
- "cli": {
- "defaultCollection": "@nrwl/angular",
- "analytics": "2d33a6dc-15e8-4227-b14e-dedd96805cec"
- }
+ }
+ }},
+ "defaultProject": "quiz"
}
diff --git a/animations/animations.ts b/animations/animations.ts
new file mode 100644
index 000000000..4e1d74915
--- /dev/null
+++ b/animations/animations.ts
@@ -0,0 +1,24 @@
+import { animate, keyframes, style, transition, trigger } from '@angular/animations';
+
+/************** animation utilized in QuizSelectionComponent *********************/
+export const SlideLeftToRightAnimation = {
+ slideLeftToRight: trigger('slideLeftToRight', [
+ transition(':enter', [
+ style({transform: 'translateX(-100%)'}),
+ animate('500ms ease-in', style({transform: 'translateX(0%)'}))
+ ])
+ ])
+};
+
+/************** animation utilized in QuizComponent *********************/
+export const ChangeRouteAnimation = {
+ changeRoute: trigger('changeRoute', [
+ transition('* => animationStarted', [
+ animate('1s', keyframes([
+ style({transform: 'scale(1.0)'}),
+ style({transform: 'scale(1.3)'}),
+ style({transform: 'scale(1.0)'})
+ ]))
+ ]),
+ ])
+};
diff --git a/animations/index.ts b/animations/index.ts
new file mode 100644
index 000000000..5fbd24ec7
--- /dev/null
+++ b/animations/index.ts
@@ -0,0 +1,2 @@
+export * from './animations';
+
diff --git a/apps/kirjs/src/app/modules/gomoku/renlib/I7.lib b/apps/kirjs/src/app/modules/gomoku/renlib/I7.lib
old mode 100755
new mode 100644
diff --git a/apps/playground/src/app/app.module.ts b/apps/playground/src/app/app.module.ts
index ab8fda53c..6fb2f9130 100644
--- a/apps/playground/src/app/app.module.ts
+++ b/apps/playground/src/app/app.module.ts
@@ -5,10 +5,17 @@ import { AppComponent } from './app.component';
import { RouterModule } from '@angular/router';
import { monacoReady } from '@codelab/code-demos';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { HttpClientModule } from '@angular/common/http';
import { environment } from '../environments/environment';
import { AngularFireModule } from '@angular/fire';
import { AngularFireDatabaseModule } from '@angular/fire/database';
import { AngularFireAuthModule } from '@angular/fire/auth';
+import { MatGridListModule } from '@angular/material/grid-list';
+import { MatMenuModule } from '@angular/material/menu';
+import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
+import { MatToolbarModule } from '@angular/material/toolbar';
+import { MatTooltipModule } from '@angular/material/tooltip';
+
const routes = [
{
@@ -25,6 +32,11 @@ const routes = [
path: 'code-sync',
loadChildren: () =>
import('./code-sync/code-sync.module').then(m => m.CodeSyncModule)
+ },
+ {
+ path: 'quiz',
+ loadChildren: () =>
+ import('./quiz/routing/quiz-routing.module').then(m => m.QuizRoutingModule)
}
];
@@ -38,9 +50,15 @@ export const AngularFireApp = AngularFireModule.initializeApp(
BrowserModule,
BrowserAnimationsModule,
RouterModule.forRoot(routes, { initialNavigation: 'enabled' }),
+ HttpClientModule,
AngularFireApp,
AngularFireDatabaseModule,
- AngularFireAuthModule
+ AngularFireAuthModule,
+ MatGridListModule,
+ MatMenuModule,
+ MatProgressSpinnerModule,
+ MatToolbarModule,
+ MatTooltipModule
],
providers: [
{
diff --git a/apps/playground/src/app/quiz b/apps/playground/src/app/quiz
new file mode 160000
index 000000000..84aaf6b30
--- /dev/null
+++ b/apps/playground/src/app/quiz
@@ -0,0 +1 @@
+Subproject commit 84aaf6b3020aeac43c9db40f2bebfb757308ed55
diff --git a/apps/playground/src/assets/audio/sound-correct.mp3 b/apps/playground/src/assets/audio/sound-correct.mp3
new file mode 100644
index 000000000..074d27a0b
Binary files /dev/null and b/apps/playground/src/assets/audio/sound-correct.mp3 differ
diff --git a/apps/playground/src/assets/audio/sound-incorrect.mp3 b/apps/playground/src/assets/audio/sound-incorrect.mp3
new file mode 100644
index 000000000..3d9a1e866
Binary files /dev/null and b/apps/playground/src/assets/audio/sound-incorrect.mp3 differ
diff --git a/apps/playground/src/assets/fonts/DjbUpOnTheScoreboard.ttf b/apps/playground/src/assets/fonts/DjbUpOnTheScoreboard.ttf
new file mode 100644
index 000000000..ded21514c
Binary files /dev/null and b/apps/playground/src/assets/fonts/DjbUpOnTheScoreboard.ttf differ
diff --git a/apps/playground/src/assets/fonts/LucidaUnicodeCalligraphy.ttf b/apps/playground/src/assets/fonts/LucidaUnicodeCalligraphy.ttf
new file mode 100644
index 000000000..c716b2b15
Binary files /dev/null and b/apps/playground/src/assets/fonts/LucidaUnicodeCalligraphy.ttf differ
diff --git a/apps/playground/src/assets/images/DIDiagram.png b/apps/playground/src/assets/images/DIDiagram.png
new file mode 100644
index 000000000..8aab83cbc
Binary files /dev/null and b/apps/playground/src/assets/images/DIDiagram.png differ
diff --git a/apps/playground/src/assets/images/angular-cli.png b/apps/playground/src/assets/images/angular-cli.png
new file mode 100644
index 000000000..93e20291d
Binary files /dev/null and b/apps/playground/src/assets/images/angular-cli.png differ
diff --git a/apps/playground/src/assets/images/angular.png b/apps/playground/src/assets/images/angular.png
new file mode 100644
index 000000000..6c115fba8
Binary files /dev/null and b/apps/playground/src/assets/images/angular.png differ
diff --git a/apps/playground/src/assets/images/angular.svg b/apps/playground/src/assets/images/angular.svg
new file mode 100644
index 000000000..bf081acb1
--- /dev/null
+++ b/apps/playground/src/assets/images/angular.svg
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/playground/src/assets/images/backpack.svg b/apps/playground/src/assets/images/backpack.svg
new file mode 100644
index 000000000..b5c458ae9
--- /dev/null
+++ b/apps/playground/src/assets/images/backpack.svg
@@ -0,0 +1,133 @@
+<<<<<<< HEAD
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+=======
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+>>>>>>> a5fd134b84149c490bf14430ee27d0cab79a5ec7
diff --git a/apps/playground/src/assets/images/codelab_logo.jpeg b/apps/playground/src/assets/images/codelab_logo.jpeg
new file mode 100644
index 000000000..5e955a845
Binary files /dev/null and b/apps/playground/src/assets/images/codelab_logo.jpeg differ
diff --git a/apps/playground/src/assets/images/congrats.gif b/apps/playground/src/assets/images/congrats.gif
new file mode 100644
index 000000000..be7cc32a5
Binary files /dev/null and b/apps/playground/src/assets/images/congrats.gif differ
diff --git a/apps/playground/src/assets/images/congratulations.jpg b/apps/playground/src/assets/images/congratulations.jpg
new file mode 100644
index 000000000..06bcb7b38
Binary files /dev/null and b/apps/playground/src/assets/images/congratulations.jpg differ
diff --git a/apps/playground/src/assets/images/email.svg b/apps/playground/src/assets/images/email.svg
new file mode 100644
index 000000000..77c5db3ca
--- /dev/null
+++ b/apps/playground/src/assets/images/email.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/apps/playground/src/assets/images/facebook.gif b/apps/playground/src/assets/images/facebook.gif
new file mode 100644
index 000000000..cb02b6d11
Binary files /dev/null and b/apps/playground/src/assets/images/facebook.gif differ
diff --git a/apps/playground/src/assets/images/first_app.png b/apps/playground/src/assets/images/first_app.png
new file mode 100644
index 000000000..c1da063f7
Binary files /dev/null and b/apps/playground/src/assets/images/first_app.png differ
diff --git a/apps/playground/src/assets/images/forms.png b/apps/playground/src/assets/images/forms.png
new file mode 100644
index 000000000..ea45c97d1
Binary files /dev/null and b/apps/playground/src/assets/images/forms.png differ
diff --git a/apps/playground/src/assets/images/headgears.png b/apps/playground/src/assets/images/headgears.png
new file mode 100644
index 000000000..a0b92b19d
Binary files /dev/null and b/apps/playground/src/assets/images/headgears.png differ
diff --git a/apps/playground/src/assets/images/helloworldapp.png b/apps/playground/src/assets/images/helloworldapp.png
new file mode 100644
index 000000000..93c99071f
Binary files /dev/null and b/apps/playground/src/assets/images/helloworldapp.png differ
diff --git a/apps/playground/src/assets/images/material.png b/apps/playground/src/assets/images/material.png
new file mode 100644
index 000000000..5adb294e1
Binary files /dev/null and b/apps/playground/src/assets/images/material.png differ
diff --git a/apps/playground/src/assets/images/ng-trophy.jpg b/apps/playground/src/assets/images/ng-trophy.jpg
new file mode 100644
index 000000000..a223523ca
Binary files /dev/null and b/apps/playground/src/assets/images/ng-trophy.jpg differ
diff --git a/apps/playground/src/assets/images/ngtrophy.jpg b/apps/playground/src/assets/images/ngtrophy.jpg
new file mode 100644
index 000000000..a223523ca
Binary files /dev/null and b/apps/playground/src/assets/images/ngtrophy.jpg differ
diff --git a/apps/playground/src/assets/images/not-bad.jpg b/apps/playground/src/assets/images/not-bad.jpg
new file mode 100644
index 000000000..e8a2f9f31
Binary files /dev/null and b/apps/playground/src/assets/images/not-bad.jpg differ
diff --git a/apps/playground/src/assets/images/notbad.jpg b/apps/playground/src/assets/images/notbad.jpg
new file mode 100644
index 000000000..e8a2f9f31
Binary files /dev/null and b/apps/playground/src/assets/images/notbad.jpg differ
diff --git a/apps/playground/src/assets/images/router.png b/apps/playground/src/assets/images/router.png
new file mode 100644
index 000000000..6fb15f154
Binary files /dev/null and b/apps/playground/src/assets/images/router.png differ
diff --git a/apps/playground/src/assets/images/template.png b/apps/playground/src/assets/images/template.png
new file mode 100644
index 000000000..793d2e673
Binary files /dev/null and b/apps/playground/src/assets/images/template.png differ
diff --git a/apps/playground/src/assets/images/tree.png b/apps/playground/src/assets/images/tree.png
new file mode 100644
index 000000000..86cd829a2
Binary files /dev/null and b/apps/playground/src/assets/images/tree.png differ
diff --git a/apps/playground/src/assets/images/try-again.jpeg b/apps/playground/src/assets/images/try-again.jpeg
new file mode 100644
index 000000000..9b6fdaa1e
Binary files /dev/null and b/apps/playground/src/assets/images/try-again.jpeg differ
diff --git a/apps/playground/src/assets/images/tryagain.jpeg b/apps/playground/src/assets/images/tryagain.jpeg
new file mode 100644
index 000000000..9b6fdaa1e
Binary files /dev/null and b/apps/playground/src/assets/images/tryagain.jpeg differ
diff --git a/apps/playground/src/assets/images/ts.png b/apps/playground/src/assets/images/ts.png
new file mode 100644
index 000000000..98e94cd8b
Binary files /dev/null and b/apps/playground/src/assets/images/ts.png differ
diff --git a/apps/playground/src/assets/images/twitter.svg b/apps/playground/src/assets/images/twitter.svg
new file mode 100644
index 000000000..a4ed81154
--- /dev/null
+++ b/apps/playground/src/assets/images/twitter.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/apps/playground/src/index.html b/apps/playground/src/index.html
index 4039ce552..d7d735cdc 100644
--- a/apps/playground/src/index.html
+++ b/apps/playground/src/index.html
@@ -2,16 +2,29 @@
- Playground
+ Angular Codelab Quiz App
-
+
+
-
+
+
+
+ Please enable JavaScript to continue using this application.
diff --git a/apps/playground/tsconfig.app.json b/apps/playground/tsconfig.app.json
index ddd50436d..cd6236720 100644
--- a/apps/playground/tsconfig.app.json
+++ b/apps/playground/tsconfig.app.json
@@ -5,7 +5,7 @@
"types": []
},
"angularCompilerOptions": {
- "enableIvy": true
+ "enableIvy": false
},
"files": ["src/main.ts", "src/polyfills.ts"],
"include": ["**/*.ts"],
diff --git a/apps/playground/tsconfig.json b/apps/playground/tsconfig.json
index 7ceb7d74d..db4f20839 100644
--- a/apps/playground/tsconfig.json
+++ b/apps/playground/tsconfig.json
@@ -1,10 +1,44 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
- "types": ["node", "jest"]
+ "baseUrl": ".",
+ "types": ["node", "jest"],
+ "paths": {
+ "@codelab/*": ["../../../codelab-master/libs/*"],
+ "@ng360/slides": ["../../../codelab-master/libs/slides/src/index.ts"],
+ "@codelab/utils": ["../../../codelab-master/libs/utils/src/index.ts"],
+ "@codelab/code-demos": ["../../../codelab-master/libs/code-demos/src/index.ts"],
+ "@codelab/firebase": ["../../../codelab-master/libs/firebase/src/index.ts"],
+ "@codelab/intro": ["../../../codelab-master/libs/intro/src/index.ts"],
+ "@codelab/browser": ["../../../codelab-master/libs/browser/src/index.ts"],
+ "@codelab-quiz/animations/*": [
+ "src/app/quiz/animations/index.ts"
+ ],
+ "@codelab-quiz/components/*": [
+ "src/app/quiz/components/index.ts"
+ ],
+ "@codelab-quiz/containers/*": [
+ "src/app/quiz/containers/index.ts"
+ ],
+ "@codelab-quiz/pipes/*": [
+ "src/app/quiz/pipes/index.ts"
+ ],
+ "@codelab-quiz/shared/*": [
+ "src/app/quiz/shared/index.ts"
+ ],
+ "@codelab-quiz/shared/models/*": [
+ "src/app/quiz/shared/models/index.ts"
+ ],
+ "@codelab-quiz/shared/quiz-data": [
+ "src/app/quiz/shared/quiz.ts"
+ ],
+ "@codelab-quiz/shared/services/*": [
+ "src/app/quiz/shared/services/index.ts"
+ ]
+ }
},
"angularCompilerOptions": {
- "enableIvy": true
+ "enableIvy": false
},
"include": ["**/*.ts"]
}
diff --git a/assets/audio/sound-correct.mp3 b/assets/audio/sound-correct.mp3
new file mode 100644
index 000000000..074d27a0b
Binary files /dev/null and b/assets/audio/sound-correct.mp3 differ
diff --git a/assets/audio/sound-incorrect.mp3 b/assets/audio/sound-incorrect.mp3
new file mode 100644
index 000000000..3d9a1e866
Binary files /dev/null and b/assets/audio/sound-incorrect.mp3 differ
diff --git a/assets/fonts/DjbUpOnTheScoreboard.ttf b/assets/fonts/DjbUpOnTheScoreboard.ttf
new file mode 100644
index 000000000..ded21514c
Binary files /dev/null and b/assets/fonts/DjbUpOnTheScoreboard.ttf differ
diff --git a/assets/fonts/LucidaUnicodeCalligraphy.ttf b/assets/fonts/LucidaUnicodeCalligraphy.ttf
new file mode 100644
index 000000000..c716b2b15
Binary files /dev/null and b/assets/fonts/LucidaUnicodeCalligraphy.ttf differ
diff --git a/assets/images/DIDiagram.png b/assets/images/DIDiagram.png
new file mode 100644
index 000000000..8aab83cbc
Binary files /dev/null and b/assets/images/DIDiagram.png differ
diff --git a/assets/images/angular-cli.png b/assets/images/angular-cli.png
new file mode 100644
index 000000000..93e20291d
Binary files /dev/null and b/assets/images/angular-cli.png differ
diff --git a/assets/images/angular.png b/assets/images/angular.png
new file mode 100644
index 000000000..6c115fba8
Binary files /dev/null and b/assets/images/angular.png differ
diff --git a/assets/images/angular.svg b/assets/images/angular.svg
new file mode 100644
index 000000000..bf081acb1
--- /dev/null
+++ b/assets/images/angular.svg
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/images/backpack.svg b/assets/images/backpack.svg
new file mode 100644
index 000000000..7c4e4e329
--- /dev/null
+++ b/assets/images/backpack.svg
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/images/codelab_logo.jpeg b/assets/images/codelab_logo.jpeg
new file mode 100644
index 000000000..5e955a845
Binary files /dev/null and b/assets/images/codelab_logo.jpeg differ
diff --git a/assets/images/congrats.gif b/assets/images/congrats.gif
new file mode 100644
index 000000000..be7cc32a5
Binary files /dev/null and b/assets/images/congrats.gif differ
diff --git a/assets/images/congratulations.jpg b/assets/images/congratulations.jpg
new file mode 100644
index 000000000..06bcb7b38
Binary files /dev/null and b/assets/images/congratulations.jpg differ
diff --git a/assets/images/email.svg b/assets/images/email.svg
new file mode 100644
index 000000000..77c5db3ca
--- /dev/null
+++ b/assets/images/email.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/assets/images/facebook.gif b/assets/images/facebook.gif
new file mode 100644
index 000000000..cb02b6d11
Binary files /dev/null and b/assets/images/facebook.gif differ
diff --git a/assets/images/first_app.png b/assets/images/first_app.png
new file mode 100644
index 000000000..c1da063f7
Binary files /dev/null and b/assets/images/first_app.png differ
diff --git a/assets/images/forms.png b/assets/images/forms.png
new file mode 100644
index 000000000..ea45c97d1
Binary files /dev/null and b/assets/images/forms.png differ
diff --git a/assets/images/headgears.png b/assets/images/headgears.png
new file mode 100644
index 000000000..a0b92b19d
Binary files /dev/null and b/assets/images/headgears.png differ
diff --git a/assets/images/helloworldapp.png b/assets/images/helloworldapp.png
new file mode 100644
index 000000000..93c99071f
Binary files /dev/null and b/assets/images/helloworldapp.png differ
diff --git a/assets/images/material.png b/assets/images/material.png
new file mode 100644
index 000000000..5adb294e1
Binary files /dev/null and b/assets/images/material.png differ
diff --git a/assets/images/ng-trophy.jpg b/assets/images/ng-trophy.jpg
new file mode 100644
index 000000000..a223523ca
Binary files /dev/null and b/assets/images/ng-trophy.jpg differ
diff --git a/assets/images/ngtrophy.jpg b/assets/images/ngtrophy.jpg
new file mode 100644
index 000000000..a223523ca
Binary files /dev/null and b/assets/images/ngtrophy.jpg differ
diff --git a/assets/images/not-bad.jpg b/assets/images/not-bad.jpg
new file mode 100644
index 000000000..e8a2f9f31
Binary files /dev/null and b/assets/images/not-bad.jpg differ
diff --git a/assets/images/router.png b/assets/images/router.png
new file mode 100644
index 000000000..6fb15f154
Binary files /dev/null and b/assets/images/router.png differ
diff --git a/assets/images/template.png b/assets/images/template.png
new file mode 100644
index 000000000..793d2e673
Binary files /dev/null and b/assets/images/template.png differ
diff --git a/assets/images/tree.png b/assets/images/tree.png
new file mode 100644
index 000000000..86cd829a2
Binary files /dev/null and b/assets/images/tree.png differ
diff --git a/assets/images/try-again.jpeg b/assets/images/try-again.jpeg
new file mode 100644
index 000000000..9b6fdaa1e
Binary files /dev/null and b/assets/images/try-again.jpeg differ
diff --git a/assets/images/ts.png b/assets/images/ts.png
new file mode 100644
index 000000000..98e94cd8b
Binary files /dev/null and b/assets/images/ts.png differ
diff --git a/assets/images/twitter.svg b/assets/images/twitter.svg
new file mode 100644
index 000000000..a4ed81154
--- /dev/null
+++ b/assets/images/twitter.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/browserslist b/browserslist
new file mode 100644
index 000000000..80848532e
--- /dev/null
+++ b/browserslist
@@ -0,0 +1,12 @@
+# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
+# For additional information regarding the format and rule options, please see:
+# https://github.com/browserslist/browserslist#queries
+
+# You can see what browsers were selected by your queries by running:
+# npx browserslist
+
+> 0.5%
+last 2 versions
+Firefox ESR
+not dead
+not IE 9-11 # For IE 9-11 support, remove 'not'.
\ No newline at end of file
diff --git a/codelab-master/.editorconfig b/codelab-master/.editorconfig
new file mode 100644
index 000000000..6e87a003d
--- /dev/null
+++ b/codelab-master/.editorconfig
@@ -0,0 +1,13 @@
+# Editor configuration, see http://editorconfig.org
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.md]
+max_line_length = off
+trim_trailing_whitespace = false
diff --git a/codelab-master/.firebaserc b/codelab-master/.firebaserc
new file mode 100644
index 000000000..5aef36aa3
--- /dev/null
+++ b/codelab-master/.firebaserc
@@ -0,0 +1,27 @@
+{
+ "projects": {
+ "default": "angular-presentation",
+ "kirjs": "kirjs-kirjs"
+ },
+ "targets": {
+ "angular-presentation": {
+ "hosting": {
+ "codelab": [
+ "angular-presentation"
+ ],
+ "kirjs": [
+ "kirjs-home"
+ ],
+ "codelab-next": [
+ "codelab-next"
+ ],
+ "lis": [
+ "lis-lis"
+ ],
+ "angular-ivy": [
+ "angular-ivy"
+ ]
+ }
+ }
+ }
+}
diff --git a/codelab-master/.flooignore b/codelab-master/.flooignore
new file mode 100644
index 000000000..ed824d39a
--- /dev/null
+++ b/codelab-master/.flooignore
@@ -0,0 +1,6 @@
+extern
+node_modules
+tmp
+vendor
+.idea/workspace.xml
+.idea/misc.xml
diff --git a/codelab-master/.gitattributes b/codelab-master/.gitattributes
new file mode 100644
index 000000000..940a34485
--- /dev/null
+++ b/codelab-master/.gitattributes
@@ -0,0 +1 @@
+src/assets/monaco linguist-vendored
diff --git a/codelab-master/.gitignore b/codelab-master/.gitignore
new file mode 100644
index 000000000..207803cb0
--- /dev/null
+++ b/codelab-master/.gitignore
@@ -0,0 +1,49 @@
+# See http://help.github.com/ignore-files/ for more about ignoring files.
+
+# compiled output
+/dist
+/tmp
+/out-tsc
+
+# dependencies
+/node_modules
+yarn.lock
+
+# IDEs and editors
+/.idea
+.project
+.classpath
+.c9/
+*.launch
+.settings/
+*.sublime-workspace
+
+# IDE - VSCode
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+
+# misc
+/.sass-cache
+/connect.lock
+/coverage
+/typings
+.firebase
+*.log
+.floo
+
+# e2e
+/e2e/*.js
+/e2e/*.map
+
+# OS generated files
+.DS_Store
+.DS_Store?
+._*
+.Spotlight-V100
+.Trashes
+ehthumbs.db
+Thumbs.db
+
diff --git a/codelab-master/.nvmrc b/codelab-master/.nvmrc
new file mode 100644
index 000000000..73bffb039
--- /dev/null
+++ b/codelab-master/.nvmrc
@@ -0,0 +1 @@
+10.17.0
diff --git a/codelab-master/.prettierignore b/codelab-master/.prettierignore
new file mode 100644
index 000000000..85c3af54c
--- /dev/null
+++ b/codelab-master/.prettierignore
@@ -0,0 +1,5 @@
+ng2ts
+dist
+coverage
+libs/code-demos/assets/runner/ng2/ng-bundle.js
+libs/code-demos/assets/runner/ng-dts/files.txt
diff --git a/codelab-master/.prettierrc b/codelab-master/.prettierrc
new file mode 100644
index 000000000..544138be4
--- /dev/null
+++ b/codelab-master/.prettierrc
@@ -0,0 +1,3 @@
+{
+ "singleQuote": true
+}
diff --git a/codelab-master/.travis.yml b/codelab-master/.travis.yml
new file mode 100644
index 000000000..54b5c3ee5
--- /dev/null
+++ b/codelab-master/.travis.yml
@@ -0,0 +1,31 @@
+dist: trusty
+language: node_js
+node_js:
+ - "10"
+
+env:
+ matrix:
+ - TRIGGER="format:check"
+ - TRIGGER="lint"
+ - TRIGGER="ng build -- --prod --source-map=false --build-optimizer=false"
+
+script:
+ - npm run $TRIGGER
+
+notifications:
+ email: false
+
+cache:
+ npm: true
+ directories:
+ - node_modules
+
+deploy:
+ provider: firebase
+ project: "angular-presentation"
+ token:
+ secure: "ed9U/81s4sR9ihLEogOdbXlKin0/vhJdk9XaLLTv6jVxGG/n40tcwwsCze6F3sBTibjq90OJHZn1ip+4uDdF+BzdzJ+hjU0SCR4B/Fi3OtxW73vz//ou1BktVrkHh+kzyS+3AvLQ9xvkz1h57vfzgfW8V/Jhy3PviZXvoPO4ttOQs2HwbO3C0BvwIaneRlNDudRz/rIQDHxHPaR6Hh3gG69vBc6D0eWhbMbFcWr6kHN3t2ki3APFR3omtNhZIdrFF9icSkeQ1fwiMKKfQaxmHXT1HZhxSCfvcqYwIqqidcFWTpABlt+2MNpWjnPLJV0l4D2HGSVF4RWtLFqfHhm/cyJTB/1ejDB92U4bA5W/tSGGgry5mgvD2pGrRHqHt+awtP9G4hgrZB3oADj3Q0nbj4VRDMgAYbAvrRYSFzxeXg50j7NwogGh02osAGpBhZzJA1I93c2yEPmcu+ysG1FkCnggh65LYX3Zjyu2eRyuPj0kaT+5OhFUanpCYO2cM/pGFMnG8+InvwLKUKfAtgUrP6yefd5CGJZaWbLGemNue6teAyMVWye4Ep2swY3DW0di5Ikn5lrV2V33yzeNd2OoSQbCaBbFLEYrlHw1+/7yNf928jj4vG0TYJwdUhlZDWdkogFIGx5cyu7dNEa5UnlzhJFkqIoo77kQrD0PKCyoAVg="
+ before_deploy:
+ - npm run pre-deploy
+ on:
+ branch: release
diff --git a/codelab-master/.vscode/extensions.json b/codelab-master/.vscode/extensions.json
new file mode 100644
index 000000000..f04b90129
--- /dev/null
+++ b/codelab-master/.vscode/extensions.json
@@ -0,0 +1,7 @@
+{
+ "recommendations": [
+ "nrwl.angular-console",
+ "angular.ng-template",
+ "esbenp.prettier-vscode"
+ ]
+}
diff --git a/LICENSE b/codelab-master/LICENSE
similarity index 100%
rename from LICENSE
rename to codelab-master/LICENSE
diff --git a/codelab-master/README.md b/codelab-master/README.md
new file mode 100644
index 000000000..b60b76b42
--- /dev/null
+++ b/codelab-master/README.md
@@ -0,0 +1,49 @@
+[](https://nycjsorg.now.sh) [](https://codelab.fun)
+
+# Angular Codelab - [codelab.fun](https://codelab.fun)
+
+Angular Codelab is a self-paced interactive Angular course:
+
+
+
+- 🔥 Everything in the browser - **no setup needed**
+- 🔥 **Interactive code samples** - Change the code and see the result immediately!
+- 🔥 Hands-on **Exercises** to solidify your knowledge
+- 🔥 **Free** - Made for Angular enthusiasts by Angular enthusiasts
+- 🔥 Written in Angular and **open source**
+
+Try it out yourself at [codelab.fun](https://codelab.fun)
+
+## Help us make Codelab.fun better
+
+- [Contribute to the codebase](#contribute-to-the-codebase)
+- [Host a live Angular Codelab event in your city](#host-a-live-angular-codelab-event-in-your-city)
+- [Translate Codelab to your language](#translate-codelab-to-your-language)
+
+### Contribute to the codebase
+
+Codelab.fun is an Angular app!
+
+It uses [angular-cli](https://cli.angular.io/) with [nx](https://nx.dev) and all materials are in a form of Angular components.
+
+
+
+See what [Good first issues](https://github.com/codelab-fun/codelab/issues?q=is%3Aissue+is%3Aopen+label%3Agood-first-issue) are available.
+
+See [CONTRIBUTING.md](./docs/CONTRIBUTING.md) for detailed instructions.
+
+### Host a live Angular Codelab event in your city
+
+We have hosted multiple live codelab events in 10+ cities, and you can help us host one in yours!
+
+See how in [HOSTING.md](./docs/HOSTING.md)
+
+
+
+### Translate Codelab to your language
+
+Currently codelab.fun is availble in English and Russian.
+
+See [TRANSLATING.md](./docs/TRANSLATING.md) for how you can help us translate the codelab into your language.
+
+Thanks to amazing [PoEditor](https://poeditor.com) for providing us with an open source licence
diff --git a/codelab-master/angular.json b/codelab-master/angular.json
new file mode 100644
index 000000000..3f00ceada
--- /dev/null
+++ b/codelab-master/angular.json
@@ -0,0 +1,1079 @@
+{
+ "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
+ "version": 1,
+ "newProjectRoot": "",
+ "projects": {
+ "codelab": {
+ "root": "apps/codelab",
+ "sourceRoot": "apps/codelab/src",
+ "projectType": "application",
+ "architect": {
+ "build": {
+ "builder": "@angular-builders/custom-webpack:browser",
+ "options": {
+ "customWebpackConfig": {
+ "path": "apps/codelab/extra-webpack.config.js"
+ },
+ "outputPath": "dist/apps/codelab",
+ "index": "apps/codelab/src/index.html",
+ "main": "apps/codelab/src/main.ts",
+ "tsConfig": "apps/codelab/tsconfig.app.json",
+ "polyfills": "apps/codelab/src/polyfills.ts",
+ "aot": true,
+ "assets": [
+ "apps/codelab/src/assets",
+ "apps/codelab/src/favicon.ico",
+ "apps/codelab/src/manifest.webmanifest",
+ {
+ "glob": "**/*",
+ "input": "node_modules/monaco-editor/",
+ "output": "./assets/monaco/"
+ },
+ {
+ "glob": "**/*",
+ "input": "libs/intro/assets/",
+ "output": "./assets/intro/"
+ },
+ {
+ "glob": "**/*",
+ "input": "libs/code-demos/assets/runner/",
+ "output": "./assets/runner/"
+ }
+ ],
+ "styles": ["apps/codelab/src/styles.scss"],
+ "scripts": []
+ },
+ "configurations": {
+ "ru": {
+ "optimization": true,
+ "outputHashing": "all",
+ "sourceMap": false,
+ "extractCss": true,
+ "namedChunks": true,
+ "aot": true,
+ "extractLicenses": true,
+ "vendorChunk": false,
+ "buildOptimizer": true,
+ "baseHref": "/ru/",
+ "deployUrl": "/ru/",
+ "fileReplacements": [
+ {
+ "replace": "apps/codelab/src/environments/environment.ts",
+ "with": "apps/codelab/src/environments/environment.prod.ts"
+ }
+ ],
+ "outputPath": "dist/apps/codelab/ru",
+ "i18nFile": "apps/codelab/src/locale/codelab.ru.xtb",
+ "i18nFormat": "xtb",
+ "i18nLocale": "ru"
+ },
+ "production": {
+ "optimization": true,
+ "outputHashing": "all",
+ "sourceMap": false,
+ "extractCss": true,
+ "namedChunks": false,
+ "aot": true,
+ "extractLicenses": true,
+ "vendorChunk": false,
+ "buildOptimizer": true,
+ "fileReplacements": [
+ {
+ "replace": "apps/codelab/src/environments/environment.ts",
+ "with": "apps/codelab/src/environments/environment.prod.ts"
+ }
+ ],
+ "serviceWorker": false
+ }
+ }
+ },
+ "serve": {
+ "builder": "@angular-builders/custom-webpack:dev-server",
+ "options": {
+ "browserTarget": "codelab:build"
+ },
+ "configurations": {
+ "production": {
+ "browserTarget": "codelab:build:production"
+ },
+ "ru": {
+ "browserTarget": "codelab:build:ru"
+ }
+ }
+ },
+ "extract-i18n": {
+ "builder": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "browserTarget": "codelab:build"
+ }
+ },
+ "test": {
+ "builder": "@angular-devkit/build-angular:karma",
+ "options": {
+ "main": "apps/codelab/src/test.ts",
+ "karmaConfig": "apps/codelab/karma.conf.js",
+ "polyfills": "apps/codelab/src/polyfills.ts",
+ "tsConfig": "apps/codelab/tsconfig.spec.json",
+ "scripts": [],
+ "styles": ["apps/codelab/src/styles.scss"],
+ "assets": [
+ "apps/codelab/src/assets",
+ "apps/codelab/src/favicon.ico",
+ "apps/codelab/src/manifest.webmanifest"
+ ]
+ }
+ },
+ "lint": {
+ "builder": "@angular-devkit/build-angular:tslint",
+ "options": {
+ "tsConfig": [
+ "apps/codelab/tsconfig.app.json",
+ "apps/codelab/tsconfig.spec.json"
+ ],
+ "exclude": []
+ }
+ }
+ }
+ },
+ "browser": {
+ "root": "libs/browser",
+ "sourceRoot": "libs/browser/src",
+ "projectType": "library",
+ "prefix": "codelab",
+ "architect": {
+ "lint": {
+ "builder": "@angular-devkit/build-angular:tslint",
+ "options": {
+ "tsConfig": [
+ "libs/browser/tsconfig.lib.json",
+ "libs/browser/tsconfig.spec.json"
+ ],
+ "exclude": ["**/node_modules/**"]
+ }
+ }
+ }
+ },
+ "console": {
+ "root": "libs/console",
+ "sourceRoot": "libs/console/src",
+ "projectType": "library",
+ "prefix": "codelab",
+ "architect": {
+ "test": {
+ "builder": "@angular-devkit/build-angular:karma",
+ "options": {
+ "main": "libs/console/src/test.ts",
+ "tsConfig": "libs/console/tsconfig.spec.json",
+ "karmaConfig": "libs/console/karma.conf.js"
+ }
+ },
+ "lint": {
+ "builder": "@angular-devkit/build-angular:tslint",
+ "options": {
+ "tsConfig": [
+ "libs/console/tsconfig.lib.json",
+ "libs/console/tsconfig.spec.json"
+ ],
+ "exclude": ["**/node_modules/**"]
+ }
+ }
+ }
+ },
+ "utils": {
+ "root": "libs/utils",
+ "sourceRoot": "libs/utils/src",
+ "projectType": "library",
+ "prefix": "codelab",
+ "architect": {
+ "test": {
+ "builder": "@angular-devkit/build-angular:karma",
+ "options": {
+ "main": "libs/utils/src/test.ts",
+ "tsConfig": "libs/utils/tsconfig.spec.json",
+ "karmaConfig": "libs/utils/karma.conf.js"
+ }
+ },
+ "lint": {
+ "builder": "@angular-devkit/build-angular:tslint",
+ "options": {
+ "tsConfig": [
+ "libs/utils/tsconfig.lib.json",
+ "libs/utils/tsconfig.spec.json"
+ ],
+ "exclude": ["**/node_modules/**"]
+ }
+ }
+ }
+ },
+ "kirjs": {
+ "root": "apps/kirjs/",
+ "sourceRoot": "apps/kirjs/src",
+ "projectType": "application",
+ "prefix": "kirjs",
+ "schematics": {},
+ "architect": {
+ "build": {
+ "builder": "@angular-devkit/build-angular:browser",
+ "options": {
+ "aot": true,
+ "outputPath": "dist/apps/kirjs",
+ "index": "apps/kirjs/src/index.html",
+ "main": "apps/kirjs/src/main.ts",
+ "polyfills": "apps/kirjs/src/polyfills.ts",
+ "tsConfig": "apps/kirjs/tsconfig.app.json",
+ "assets": [
+ {
+ "glob": "**/*",
+ "input": "node_modules/monaco-editor/",
+ "output": "./assets/monaco/"
+ },
+ "apps/kirjs/src/favicon.ico",
+ "apps/kirjs/src/assets",
+ {
+ "glob": "**/*",
+ "input": "libs/code-demos/assets/runner/",
+ "output": "./assets/runner/"
+ }
+ ],
+ "styles": ["apps/kirjs/src/styles.css"],
+ "scripts": []
+ },
+ "configurations": {
+ "ru": {
+ "outputPath": "dist/apps/kirjs/ru",
+ "aot": true,
+ "i18nFile": "apps/kirjs/src/locale/kirjs.ru.xtb",
+ "i18nFormat": "xtb",
+ "i18nLocale": "ru"
+ },
+ "production": {
+ "fileReplacements": [
+ {
+ "replace": "apps/kirjs/src/environments/environment.ts",
+ "with": "apps/kirjs/src/environments/environment.prod.ts"
+ }
+ ],
+ "optimization": true,
+ "outputHashing": "all",
+ "sourceMap": false,
+ "extractCss": true,
+ "namedChunks": false,
+ "aot": true,
+ "extractLicenses": true,
+ "vendorChunk": false,
+ "buildOptimizer": true
+ }
+ }
+ },
+ "serve": {
+ "builder": "@angular-devkit/build-angular:dev-server",
+ "options": {
+ "browserTarget": "kirjs:build"
+ },
+ "configurations": {
+ "production": {
+ "browserTarget": "kirjs:build:production"
+ },
+ "ru": {
+ "browserTarget": "kirjs:build:ru"
+ }
+ }
+ },
+ "extract-i18n": {
+ "builder": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "browserTarget": "kirjs:build"
+ },
+ "configurations": {
+ "ru": {
+ "outputPath": "locale/",
+ "outFile": "messages.ru.untranslated.xlf",
+ "i18nFormat": "xlf",
+ "i18nLocale": "ru"
+ }
+ }
+ },
+ "test": {
+ "builder": "@angular-devkit/build-angular:karma",
+ "options": {
+ "main": "apps/kirjs/src/test.ts",
+ "polyfills": "apps/kirjs/src/polyfills.ts",
+ "tsConfig": "apps/kirjs/tsconfig.spec.json",
+ "karmaConfig": "apps/kirjs/karma.conf.js",
+ "styles": ["apps/kirjs/src/styles.css"],
+ "scripts": [],
+ "assets": ["apps/kirjs/src/favicon.ico", "apps/kirjs/src/assets"]
+ }
+ },
+ "lint": {
+ "builder": "@angular-devkit/build-angular:tslint",
+ "options": {
+ "tsConfig": [
+ "apps/kirjs/tsconfig.app.json",
+ "apps/kirjs/tsconfig.spec.json"
+ ],
+ "exclude": ["**/node_modules/**"]
+ }
+ }
+ }
+ },
+ "angular-ast-viz": {
+ "root": "libs/angular-ast-viz",
+ "sourceRoot": "libs/angular-ast-viz/src",
+ "projectType": "library",
+ "prefix": "codelab",
+ "architect": {
+ "build": {
+ "builder": "@nrwl/angular:package",
+ "options": {
+ "tsConfig": "libs/angular-ast-viz/tsconfig.lib.json",
+ "project": "libs/angular-ast-viz/ng-package.json"
+ },
+ "configurations": {
+ "production": {
+ "project": "libs/angular-ast-viz/ng-package.prod.json"
+ }
+ }
+ },
+ "test": {
+ "builder": "@angular-devkit/build-angular:karma",
+ "options": {
+ "main": "libs/angular-ast-viz/src/test.ts",
+ "tsConfig": "libs/angular-ast-viz/tsconfig.spec.json",
+ "karmaConfig": "libs/angular-ast-viz/karma.conf.js"
+ }
+ },
+ "lint": {
+ "builder": "@angular-devkit/build-angular:tslint",
+ "options": {
+ "tsConfig": [
+ "libs/angular-ast-viz/tsconfig.lib.json",
+ "libs/angular-ast-viz/tsconfig.spec.json"
+ ],
+ "exclude": ["**/node_modules/**"]
+ }
+ }
+ }
+ },
+ "angular-slides-to-pdf": {
+ "root": "libs/angular-slides-to-pdf",
+ "sourceRoot": "libs/angular-slides-to-pdf/src",
+ "projectType": "library",
+ "prefix": "codelab",
+ "architect": {
+ "build": {
+ "builder": "@nrwl/angular:package",
+ "options": {
+ "tsConfig": "libs/angular-slides-to-pdf/tsconfig.lib.json",
+ "project": "libs/angular-slides-to-pdf/ng-package.json"
+ },
+ "configurations": {
+ "production": {
+ "project": "libs/angular-slides-to-pdf/ng-package.prod.json"
+ }
+ }
+ },
+ "test": {
+ "builder": "@angular-devkit/build-angular:karma",
+ "options": {
+ "main": "libs/angular-slides-to-pdf/src/test.ts",
+ "tsConfig": "libs/angular-slides-to-pdf/tsconfig.spec.json",
+ "karmaConfig": "libs/angular-slides-to-pdf/karma.conf.js"
+ }
+ },
+ "lint": {
+ "builder": "@angular-devkit/build-angular:tslint",
+ "options": {
+ "tsConfig": [
+ "libs/angular-slides-to-pdf/tsconfig.lib.json",
+ "libs/angular-slides-to-pdf/tsconfig.spec.json"
+ ],
+ "exclude": ["**/node_modules/**"]
+ }
+ }
+ }
+ },
+ "feedback": {
+ "root": "libs/feedback",
+ "sourceRoot": "libs/feedback/src",
+ "projectType": "library",
+ "prefix": "codelab",
+ "architect": {
+ "build": {
+ "builder": "@nrwl/angular:package",
+ "options": {
+ "tsConfig": "libs/feedback/tsconfig.lib.json",
+ "project": "libs/feedback/ng-package.json"
+ }
+ },
+ "test": {
+ "builder": "@angular-devkit/build-angular:karma",
+ "options": {
+ "main": "libs/feedback/src/test.ts",
+ "tsConfig": "libs/feedback/tsconfig.spec.json",
+ "karmaConfig": "libs/feedback/karma.conf.js"
+ }
+ },
+ "lint": {
+ "builder": "@angular-devkit/build-angular:tslint",
+ "options": {
+ "tsConfig": [
+ "libs/feedback/tsconfig.lib.json",
+ "libs/feedback/tsconfig.spec.json"
+ ],
+ "exclude": ["**/node_modules/**"]
+ }
+ }
+ }
+ },
+ "code-demos": {
+ "root": "libs/code-demos",
+ "sourceRoot": "libs/code-demos/src",
+ "projectType": "library",
+ "prefix": "codelab",
+ "architect": {
+ "build": {
+ "builder": "@nrwl/angular:package",
+ "options": {
+ "tsConfig": "libs/code-demos/tsconfig.lib.json",
+ "project": "libs/code-demos/ng-package.json"
+ },
+ "configurations": {
+ "production": {
+ "project": "libs/code-demos/ng-package.prod.json"
+ }
+ }
+ },
+ "lint": {
+ "builder": "@angular-devkit/build-angular:tslint",
+ "options": {
+ "tsConfig": [
+ "libs/code-demos/tsconfig.lib.json",
+ "libs/code-demos/tsconfig.spec.json"
+ ],
+ "exclude": ["**/node_modules/**"]
+ }
+ },
+ "test": {
+ "builder": "@nrwl/jest:jest",
+ "options": {
+ "jestConfig": "libs/code-demos/jest.config.js",
+ "tsConfig": "libs/code-demos/tsconfig.spec.json",
+ "setupFile": "libs/code-demos/src/test-setup.ts"
+ }
+ }
+ }
+ },
+ "live": {
+ "root": "libs/live",
+ "sourceRoot": "libs/live/src",
+ "projectType": "library",
+ "prefix": "live",
+ "architect": {
+ "build": {
+ "builder": "@nrwl/angular:package",
+ "options": {
+ "tsConfig": "libs/live/tsconfig.lib.json",
+ "project": "libs/live/ng-package.json"
+ }
+ },
+ "lint": {
+ "builder": "@angular-devkit/build-angular:tslint",
+ "options": {
+ "tsConfig": [
+ "libs/live/tsconfig.lib.json",
+ "libs/live/tsconfig.spec.json"
+ ],
+ "exclude": ["**/node_modules/**"]
+ }
+ },
+ "test": {
+ "builder": "@nrwl/jest:jest",
+ "options": {
+ "jestConfig": "libs/live/jest.config.js",
+ "tsConfig": "libs/live/tsconfig.spec.json"
+ }
+ }
+ },
+ "schematics": {}
+ },
+ "firebase-login": {
+ "root": "libs/firebase-login",
+ "sourceRoot": "libs/firebase-login/src",
+ "projectType": "library",
+ "prefix": "angular-presentation",
+ "architect": {
+ "build": {
+ "builder": "@nrwl/angular:package",
+ "options": {
+ "tsConfig": "libs/firebase-login/tsconfig.lib.json",
+ "project": "libs/firebase-login/ng-package.json"
+ }
+ },
+ "test": {
+ "builder": "@angular-devkit/build-angular:karma",
+ "options": {
+ "main": "libs/firebase-login/src/test.ts",
+ "tsConfig": "libs/firebase-login/tsconfig.spec.json",
+ "karmaConfig": "libs/firebase-login/karma.conf.js"
+ }
+ },
+ "lint": {
+ "builder": "@angular-devkit/build-angular:tslint",
+ "options": {
+ "tsConfig": [
+ "libs/firebase-login/tsconfig.lib.json",
+ "libs/firebase-login/tsconfig.spec.json"
+ ],
+ "exclude": ["**/node_modules/**"]
+ }
+ }
+ }
+ },
+ "blog": {
+ "root": "apps/blog/",
+ "sourceRoot": "apps/blog/src",
+ "projectType": "application",
+ "prefix": "codelab",
+ "schematics": {
+ "@nrwl/schematics:component": {
+ "style": "scss"
+ }
+ },
+ "architect": {
+ "build": {
+ "builder": "@angular-devkit/build-angular:browser",
+ "options": {
+ "outputPath": "dist/apps/blog",
+ "index": "apps/blog/src/index.html",
+ "main": "apps/blog/src/main.ts",
+ "polyfills": "apps/blog/src/polyfills.ts",
+ "tsConfig": "apps/blog/tsconfig.app.json",
+ "assets": ["apps/blog/src/favicon.ico", "apps/blog/src/assets"],
+ "styles": ["apps/blog/src/styles.scss"],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "fileReplacements": [
+ {
+ "replace": "apps/blog/src/environments/environment.ts",
+ "with": "apps/blog/src/environments/environment.prod.ts"
+ }
+ ],
+ "optimization": true,
+ "outputHashing": "all",
+ "sourceMap": false,
+ "extractCss": true,
+ "namedChunks": false,
+ "aot": true,
+ "extractLicenses": true,
+ "vendorChunk": false,
+ "buildOptimizer": true,
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "2mb",
+ "maximumError": "20mb"
+ }
+ ]
+ }
+ }
+ },
+ "serve": {
+ "builder": "@angular-devkit/build-angular:dev-server",
+ "options": {
+ "browserTarget": "blog:build"
+ },
+ "configurations": {
+ "production": {
+ "browserTarget": "blog:build:production"
+ }
+ }
+ },
+ "extract-i18n": {
+ "builder": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "browserTarget": "blog:build"
+ }
+ },
+ "lint": {
+ "builder": "@angular-devkit/build-angular:tslint",
+ "options": {
+ "tsConfig": [
+ "apps/blog/tsconfig.app.json",
+ "apps/blog/tsconfig.spec.json"
+ ],
+ "exclude": ["**/node_modules/**"]
+ }
+ },
+ "test": {
+ "builder": "@nrwl/jest:jest",
+ "options": {
+ "jestConfig": "apps/blog/jest.config.js",
+ "tsConfig": "apps/blog/tsconfig.spec.json",
+ "setupFile": "apps/blog/src/test-setup.ts"
+ }
+ }
+ }
+ },
+ "angular-thirty-seconds": {
+ "root": "apps/angular-thirty-seconds/",
+ "sourceRoot": "apps/angular-thirty-seconds/src",
+ "projectType": "application",
+ "prefix": "codelab",
+ "schematics": {
+ "@nrwl/schematics:component": {
+ "style": "scss"
+ }
+ },
+ "architect": {
+ "build": {
+ "builder": "@angular-devkit/build-angular:browser",
+ "options": {
+ "outputPath": "dist/apps/codelab/30",
+ "index": "apps/angular-thirty-seconds/src/index.html",
+ "main": "apps/angular-thirty-seconds/src/main.ts",
+ "polyfills": "apps/angular-thirty-seconds/src/polyfills.ts",
+ "tsConfig": "apps/angular-thirty-seconds/tsconfig.app.json",
+ "assets": [
+ {
+ "glob": "**/*",
+ "input": "node_modules/monaco-editor/",
+ "output": "./assets/monaco/"
+ },
+ "apps/angular-thirty-seconds/src/favicon.ico",
+ "apps/angular-thirty-seconds/src/assets",
+ {
+ "glob": "**/*",
+ "input": "libs/code-demos/assets/runner/",
+ "output": "./assets/runner/"
+ }
+ ],
+ "styles": [
+ "apps/angular-thirty-seconds/src/styles.scss",
+ "node_modules/prismjs/themes/prism-okaidia.css",
+ "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.css"
+ ],
+ "scripts": [
+ "node_modules/prismjs/prism.js",
+ "node_modules/prismjs/components/prism-typescript.min.js",
+ "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.js"
+ ]
+ },
+ "configurations": {
+ "production": {
+ "fileReplacements": [
+ {
+ "replace": "apps/angular-thirty-seconds/src/environments/environment.ts",
+ "with": "apps/angular-thirty-seconds/src/environments/environment.prod.ts"
+ }
+ ],
+ "baseHref": "/30/",
+ "deployUrl": "/30/",
+ "optimization": true,
+ "outputHashing": "all",
+ "sourceMap": false,
+ "extractCss": true,
+ "namedChunks": false,
+ "aot": true,
+ "extractLicenses": true,
+ "vendorChunk": false,
+ "buildOptimizer": true,
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "60mb",
+ "maximumError": "70mb"
+ }
+ ]
+ }
+ }
+ },
+ "serve": {
+ "builder": "@angular-devkit/build-angular:dev-server",
+ "options": {
+ "browserTarget": "angular-thirty-seconds:build"
+ },
+ "configurations": {
+ "production": {
+ "browserTarget": "angular-thirty-seconds:build:production"
+ }
+ }
+ },
+ "extract-i18n": {
+ "builder": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "browserTarget": "angular-thirty-seconds:build"
+ }
+ },
+ "test": {
+ "builder": "@angular-devkit/build-angular:karma",
+ "options": {
+ "main": "apps/angular-thirty-seconds/src/test.ts",
+ "polyfills": "apps/angular-thirty-seconds/src/polyfills.ts",
+ "tsConfig": "apps/angular-thirty-seconds/tsconfig.spec.json",
+ "karmaConfig": "apps/angular-thirty-seconds/karma.conf.js",
+ "styles": ["apps/angular-thirty-seconds/src/styles.scss"],
+ "scripts": [],
+ "assets": [
+ "apps/angular-thirty-seconds/src/favicon.ico",
+ "apps/angular-thirty-seconds/src/assets"
+ ]
+ }
+ },
+ "lint": {
+ "builder": "@angular-devkit/build-angular:tslint",
+ "options": {
+ "tsConfig": [
+ "apps/angular-thirty-seconds/tsconfig.app.json",
+ "apps/angular-thirty-seconds/tsconfig.spec.json"
+ ],
+ "exclude": ["**/node_modules/**"]
+ }
+ }
+ }
+ },
+ "lis": {
+ "projectType": "application",
+ "schematics": {},
+ "root": "apps/lis",
+ "sourceRoot": "apps/lis/src",
+ "prefix": "codelab",
+ "architect": {
+ "build": {
+ "builder": "@angular-devkit/build-angular:browser",
+ "options": {
+ "outputPath": "dist/apps/lis",
+ "index": "apps/lis/src/index.html",
+ "main": "apps/lis/src/main.ts",
+ "polyfills": "apps/lis/src/polyfills.ts",
+ "tsConfig": "apps/lis/tsconfig.app.json",
+ "aot": false,
+ "assets": [
+ "apps/lis/src/favicon.ico",
+ "apps/lis/src/assets",
+ {
+ "glob": "**/*",
+ "input": "node_modules/monaco-editor/",
+ "output": "./assets/monaco/"
+ },
+ {
+ "glob": "**/*",
+ "input": "libs/code-demos/assets/runner/",
+ "output": "./assets/runner/"
+ }
+ ],
+ "styles": ["apps/lis/src/styles.css"],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "fileReplacements": [
+ {
+ "replace": "apps/lis/src/environments/environment.ts",
+ "with": "apps/lis/src/environments/environment.prod.ts"
+ }
+ ],
+ "optimization": true,
+ "outputHashing": "all",
+ "sourceMap": false,
+ "extractCss": true,
+ "namedChunks": false,
+ "aot": true,
+ "extractLicenses": true,
+ "vendorChunk": false,
+ "buildOptimizer": true,
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "2mb",
+ "maximumError": "5mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "6kb",
+ "maximumError": "10kb"
+ }
+ ]
+ }
+ }
+ },
+ "serve": {
+ "builder": "@angular-devkit/build-angular:dev-server",
+ "options": {
+ "browserTarget": "lis:build"
+ },
+ "configurations": {
+ "production": {
+ "browserTarget": "lis:build:production"
+ }
+ }
+ },
+ "extract-i18n": {
+ "builder": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "browserTarget": "lis:build"
+ }
+ },
+ "lint": {
+ "builder": "@angular-devkit/build-angular:tslint",
+ "options": {
+ "tsConfig": [
+ "apps/lis/tsconfig.app.json",
+ "apps/lis/tsconfig.spec.json"
+ ],
+ "exclude": ["**/node_modules/**", "!apps/lis/**"]
+ }
+ },
+ "test": {
+ "builder": "@nrwl/jest:jest",
+ "options": {
+ "jestConfig": "apps/lis/jest.config.js",
+ "tsConfig": "apps/lis/tsconfig.spec.json",
+ "setupFile": "apps/lis/src/test-setup.ts"
+ }
+ }
+ }
+ },
+ "playground": {
+ "projectType": "application",
+ "schematics": {
+ "@nrwl/angular:component": {
+ "style": "scss"
+ }
+ },
+ "root": "apps/playground",
+ "sourceRoot": "apps/playground/src",
+ "prefix": "codelab",
+ "architect": {
+ "build": {
+ "builder": "@angular-devkit/build-angular:browser",
+ "options": {
+ "outputPath": "dist/apps/playground",
+ "index": "apps/playground/src/index.html",
+ "main": "apps/playground/src/main.ts",
+ "polyfills": "apps/playground/src/polyfills.ts",
+ "tsConfig": "apps/playground/tsconfig.app.json",
+ "aot": true,
+ "assets": [
+ "apps/playground/src/favicon.ico",
+ "apps/playground/src/assets",
+ {
+ "glob": "**/*",
+ "input": "node_modules/monaco-editor/",
+ "output": "./assets/monaco/"
+ }
+ ],
+ "styles": [
+ "node_modules/bootstrap/dist/css/bootstrap.css",
+ "node_modules/@fortawesome/fontawesome-free/css/all.min.css",
+ "node_modules/hover.css/css/hover-min.css",
+ "apps/playground/src/app/quiz/styles/styles.scss"
+ ],
+ "stylePreprocessorOptions": {
+ "includePaths": [
+ "apps/playground/src/app/quiz/styles/"
+ ]
+ },
+ "scripts": [
+ "node_modules/jquery/dist/jquery.min.js",
+ "node_modules/bootstrap/dist/js/bootstrap.min.js"
+ ]
+ },
+ "configurations": {
+ "production": {
+ "fileReplacements": [
+ {
+ "replace": "apps/playground/src/environments/environment.ts",
+ "with": "apps/playground/src/environments/environment.prod.ts"
+ }
+ ],
+ "optimization": true,
+ "outputHashing": "all",
+ "sourceMap": false,
+ "extractCss": true,
+ "namedChunks": false,
+ "aot": true,
+ "extractLicenses": true,
+ "vendorChunk": false,
+ "buildOptimizer": true,
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "20mb",
+ "maximumError": "25mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "6kb",
+ "maximumError": "10kb"
+ }
+ ]
+ }
+ }
+ },
+ "serve": {
+ "builder": "@angular-devkit/build-angular:dev-server",
+ "options": {
+ "browserTarget": "playground:build"
+ },
+ "configurations": {
+ "production": {
+ "browserTarget": "playground:build:production"
+ }
+ }
+ },
+ "extract-i18n": {
+ "builder": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "browserTarget": "playground:build"
+ }
+ },
+ "lint": {
+ "builder": "@angular-devkit/build-angular:tslint",
+ "options": {
+ "tsConfig": [
+ "apps/playground/tsconfig.app.json",
+ "apps/playground/tsconfig.spec.json"
+ ],
+ "exclude": ["**/node_modules/**", "!apps/playground/**"]
+ }
+ },
+ "test": {
+ "builder": "@nrwl/jest:jest",
+ "options": {
+ "jestConfig": "apps/playground/jest.config.js",
+ "tsConfig": "apps/playground/tsconfig.spec.json",
+ "setupFile": "apps/playground/src/test-setup.ts"
+ }
+ }
+ }
+ },
+ "firebase": {
+ "projectType": "library",
+ "root": "libs/firebase",
+ "sourceRoot": "libs/firebase/src",
+ "prefix": "codelab",
+ "architect": {
+ "lint": {
+ "builder": "@angular-devkit/build-angular:tslint",
+ "options": {
+ "tsConfig": [
+ "libs/firebase/tsconfig.lib.json",
+ "libs/firebase/tsconfig.spec.json"
+ ],
+ "exclude": ["**/node_modules/**", "!libs/firebase/**"]
+ }
+ },
+ "test": {
+ "builder": "@nrwl/jest:jest",
+ "options": {
+ "jestConfig": "libs/firebase/jest.config.js",
+ "tsConfig": "libs/firebase/tsconfig.spec.json",
+ "setupFile": "libs/firebase/src/test-setup.ts"
+ }
+ }
+ },
+ "schematics": {}
+ },
+ "intro": {
+ "projectType": "library",
+ "root": "libs/intro",
+ "sourceRoot": "libs/intro/src",
+ "prefix": "codelab",
+ "architect": {
+ "lint": {
+ "builder": "@angular-devkit/build-angular:tslint",
+ "options": {
+ "tsConfig": [
+ "libs/intro/tsconfig.lib.json",
+ "libs/intro/tsconfig.spec.json"
+ ],
+ "exclude": ["**/node_modules/**", "!libs/intro/**"]
+ }
+ },
+ "test": {
+ "builder": "@nrwl/jest:jest",
+ "options": {
+ "jestConfig": "libs/intro/jest.config.js",
+ "tsConfig": "libs/intro/tsconfig.spec.json",
+ "setupFile": "libs/intro/src/test-setup.ts"
+ }
+ }
+ },
+ "schematics": {}
+ },
+ "slides": {
+ "projectType": "library",
+ "root": "libs/slides",
+ "sourceRoot": "libs/slides/src",
+ "prefix": "codelab",
+ "architect": {
+ "build": {
+ "builder": "@nrwl/angular:package",
+ "options": {
+ "tsConfig": "libs/slides/tsconfig.lib.json",
+ "project": "libs/slides/ng-package.json"
+ },
+ "configurations": {
+ "production": {
+ "tsConfig": "libs/slides/tsconfig.lib.prod.json"
+ }
+ }
+ },
+ "lint": {
+ "builder": "@angular-devkit/build-angular:tslint",
+ "options": {
+ "tsConfig": [
+ "libs/slides/tsconfig.lib.json",
+ "libs/slides/tsconfig.spec.json"
+ ],
+ "exclude": ["**/node_modules/**", "!libs/slides/**"]
+ }
+ },
+ "test": {
+ "builder": "@nrwl/jest:jest",
+ "options": {
+ "jestConfig": "libs/slides/jest.config.js",
+ "tsConfig": "libs/slides/tsconfig.spec.json",
+ "setupFile": "libs/slides/src/test-setup.ts"
+ }
+ }
+ },
+ "schematics": {}
+ }
+ },
+ "defaultProject": "codelab",
+ "schematics": {
+ "@schematics/angular:component": {
+ "prefix": "slides",
+ "style": "css"
+ },
+ "@schematics/angular:directive": {
+ "prefix": "slides"
+ },
+ "@nrwl/schematics:library": {
+ "unitTestRunner": "karma",
+ "framework": "angular"
+ },
+ "@nrwl/schematics:application": {
+ "unitTestRunner": "karma",
+ "e2eTestRunner": "protractor"
+ },
+ "@nrwl/schematics:node-application": {
+ "framework": "express"
+ },
+ "@nrwl/angular:application": {
+ "unitTestRunner": "jest",
+ "e2eTestRunner": "cypress"
+ },
+ "@nrwl/angular:library": {
+ "unitTestRunner": "jest"
+ }
+ },
+ "cli": {
+ "defaultCollection": "@nrwl/angular",
+ "analytics": "2d33a6dc-15e8-4227-b14e-dedd96805cec"
+ }
+}
diff --git a/codelab-master/apps/angular-thirty-seconds/browserslist b/codelab-master/apps/angular-thirty-seconds/browserslist
new file mode 100644
index 000000000..37371cb04
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/browserslist
@@ -0,0 +1,11 @@
+# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers
+# For additional information regarding the format and rule options, please see:
+# https://github.com/browserslist/browserslist#queries
+#
+# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed
+
+> 0.5%
+last 2 versions
+Firefox ESR
+not dead
+not IE 9-11
\ No newline at end of file
diff --git a/codelab-master/apps/angular-thirty-seconds/karma.conf.js b/codelab-master/apps/angular-thirty-seconds/karma.conf.js
new file mode 100644
index 000000000..97cb50940
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/karma.conf.js
@@ -0,0 +1,31 @@
+// Karma configuration file, see link for more information
+// https://karma-runner.github.io/1.0/config/configuration-file.html
+
+module.exports = function(config) {
+ config.set({
+ basePath: '../',
+ frameworks: ['jasmine', '@angular-devkit/build-angular'],
+ plugins: [
+ require('karma-jasmine'),
+ require('karma-chrome-launcher'),
+ require('karma-jasmine-html-reporter'),
+ require('karma-coverage-istanbul-reporter'),
+ require('@angular-devkit/build-angular/plugins/karma')
+ ],
+ client: {
+ clearContext: false // leave Jasmine Spec Runner output visible in browser
+ },
+ coverageIstanbulReporter: {
+ dir: require('path').join(__dirname, '../coverage'),
+ reports: ['html', 'lcovonly'],
+ fixWebpackSourcePaths: true
+ },
+ reporters: ['progress', 'kjhtml'],
+ port: 9876,
+ colors: true,
+ logLevel: config.LOG_INFO,
+ autoWatch: true,
+ browsers: ['Chrome'],
+ singleRun: false
+ });
+};
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/app.component.ts b/codelab-master/apps/angular-thirty-seconds/src/app/app.component.ts
new file mode 100644
index 000000000..9713b60a8
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/app.component.ts
@@ -0,0 +1,27 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'codelab-root',
+ template: `
+
+
+
+ `,
+
+ styles: [
+ `
+ .wrapper {
+ margin: 0 60px;
+ padding: 0 20px;
+ }
+
+ :host ::ng-deep {
+ font-family: 'Helvetica Neue', sans-serif;
+ font-weight: 300;
+ padding: 0 20px;
+ display: block;
+ }
+ `
+ ]
+})
+export class AppComponent {}
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/app.module.ts b/codelab-master/apps/angular-thirty-seconds/src/app/app.module.ts
new file mode 100644
index 000000000..750a872c4
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/app.module.ts
@@ -0,0 +1,51 @@
+import { MatButtonModule } from '@angular/material/button';
+import { MatTableModule } from '@angular/material/table';
+import { BrowserModule } from '@angular/platform-browser';
+import { APP_INITIALIZER, NgModule } from '@angular/core';
+import { AppComponent } from './app.component';
+import { RouterModule, Routes } from '@angular/router';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { monacoReady } from '@codelab/code-demos';
+import { HttpClientModule } from '@angular/common/http';
+import { CreateSnippetComponent } from './create-snippet/create-snippet.component';
+import { CreateSnippetModule } from './create-snippet/create-snippet.module';
+import { environment } from '../../../codelab/src/environments/environment';
+import { AngularFireModule } from '@angular/fire';
+import { PullRequestsListComponent } from './pull-requests-list/pull-requests-list.component';
+
+export const angularFire = AngularFireModule.initializeApp(
+ environment.firebaseConfig
+);
+
+const routes: Routes = [
+ { path: '', redirectTo: 'list', pathMatch: 'full' },
+ { path: 'list', component: PullRequestsListComponent },
+ { path: 'new/:repoName/:repoOwner', component: CreateSnippetComponent },
+ {
+ path: 'new/:repoName/:repoOwner/:pullNumber',
+ component: CreateSnippetComponent
+ }
+];
+
+@NgModule({
+ imports: [
+ angularFire,
+ BrowserModule,
+ BrowserAnimationsModule,
+ RouterModule.forRoot(routes),
+ MatButtonModule,
+ MatTableModule,
+ HttpClientModule,
+ CreateSnippetModule
+ ],
+ declarations: [AppComponent, PullRequestsListComponent],
+ providers: [
+ {
+ provide: APP_INITIALIZER,
+ useValue: monacoReady,
+ multi: true
+ }
+ ],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/create-snippet.component.html b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/create-snippet.component.html
new file mode 100644
index 000000000..f3119620c
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/create-snippet.component.html
@@ -0,0 +1,222 @@
+
+
+ {{ isEditing ? '' : 'New' }} Snippet
+
+ {{ isEditing ? 'Edit' : 'Create' }} Snippet
+
+
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/create-snippet.component.scss b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/create-snippet.component.scss
new file mode 100644
index 000000000..3b752d38e
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/create-snippet.component.scss
@@ -0,0 +1,112 @@
+:host {
+ label {
+ color: #3e515b;
+ }
+
+ textarea {
+ width: 100%;
+ height: 280px;
+ }
+
+ mat-form-field {
+ width: 100%;
+ }
+
+ section {
+ display: flex;
+ margin: 30px 0;
+ }
+
+ .icon {
+ justify-content: center;
+ align-items: center;
+ font-size: 15px;
+
+ &-plus:before {
+ content: '\FF0B';
+ border: 1px solid #444;
+ border-radius: 50%;
+ color: #444;
+ }
+
+ &-minus:before {
+ content: '\FF0D';
+ border: 1px solid #444;
+ border-radius: 50%;
+ color: #444;
+ }
+ }
+
+ .btn-submit {
+ float: right;
+ font-weight: 400;
+ text-align: center;
+ vertical-align: middle;
+ border: 1px solid #213451;
+ font-size: 14px;
+ color: #fff;
+ background-color: #213451;
+ cursor: pointer;
+ }
+
+ .container {
+ max-width: 850px;
+ padding: 0 15px 30px 15px;
+ margin: 0 auto;
+ font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
+ }
+
+ .input-info {
+ display: block;
+ height: 10px;
+ line-height: 10px;
+ font-size: 0.625em;
+ margin-top: -15px;
+ color: #8b8b8b;
+ }
+
+ .markdown-info {
+ width: 50%;
+ padding: 15px 35px;
+ border: 1px solid #a4b7c1;
+ margin-left: 30px;
+ }
+
+ .input-block {
+ width: 300px;
+
+ div {
+ margin-bottom: 25px;
+ width: 100%;
+ }
+ }
+
+ .required {
+ color: red;
+ }
+
+ .cursor-pointer {
+ cursor: pointer;
+ }
+
+ .w {
+ &-100 {
+ width: 100%;
+ }
+
+ &-50 {
+ width: 50%;
+ }
+ }
+
+ .validation-message {
+ color: red;
+ position: absolute;
+ width: 100%;
+ height: 1em;
+ margin-top: 5px;
+ line-height: 1em;
+ font-size: 0.75em;
+ text-align: left;
+ }
+}
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/create-snippet.component.spec.ts b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/create-snippet.component.spec.ts
new file mode 100644
index 000000000..3d138aff1
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/create-snippet.component.spec.ts
@@ -0,0 +1,70 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { CreateSnippetComponent } from './create-snippet.component';
+import { CreateSnippetModule } from './create-snippet.module';
+import { ActivatedRoute } from '@angular/router';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { SnippetService } from '../shared/services/snippet.service';
+import SpyObj = jasmine.SpyObj;
+import { of } from 'rxjs';
+
+describe('CreateSnippetComponent', () => {
+ let component: CreateSnippetComponent;
+ let fixture: ComponentFixture;
+ let snippetService: SpyObj;
+ let activatedRoute: Partial;
+
+ beforeEach(async(() => {
+ activatedRoute = {
+ snapshot: {
+ params: {}
+ }
+ } as any;
+
+ snippetService = jasmine.createSpyObj('snippetService', ['fetchPR']);
+
+ TestBed.configureTestingModule({
+ imports: [CreateSnippetModule, NoopAnimationsModule],
+ providers: [
+ {
+ provide: ActivatedRoute,
+ useFactory: () => activatedRoute
+ },
+ {
+ provide: SnippetService,
+ useValue: snippetService
+ }
+ ]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {});
+
+ xit('should create', () => {
+ const repoName = 'name';
+ const repoOwner = 'PIKACHU';
+ const pullNumber = 689;
+
+ activatedRoute = {
+ snapshot: {
+ params: {
+ pullNumber,
+ repoName,
+ repoOwner
+ }
+ }
+ } as any;
+
+ snippetService.fetchPR.and.returnValue(of({}));
+
+ fixture = TestBed.createComponent(CreateSnippetComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+
+ expect(snippetService.fetchPR).toHaveBeenCalledWith(
+ repoName,
+ repoOwner,
+ pullNumber
+ );
+ });
+});
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/create-snippet.component.ts b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/create-snippet.component.ts
new file mode 100644
index 000000000..9935a4f78
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/create-snippet.component.ts
@@ -0,0 +1,219 @@
+import {
+ ChangeDetectionStrategy,
+ ChangeDetectorRef,
+ Component,
+ ElementRef,
+ OnDestroy,
+ ViewChild
+} from '@angular/core';
+import { FormBuilder, Validators } from '@angular/forms';
+import { ActivatedRoute } from '@angular/router';
+import {
+ MatAutocomplete,
+ MatAutocompleteSelectedEvent
+} from '@angular/material/autocomplete';
+import { MatChipInputEvent } from '@angular/material/chips';
+import { MatDialog } from '@angular/material/dialog';
+import { COMMA, ENTER } from '@angular/cdk/keycodes';
+import { Observable } from 'rxjs/internal/Observable';
+import { finalize, map } from 'rxjs/operators';
+import { ReplaySubject } from 'rxjs/internal/ReplaySubject';
+import { SnippetOverviewComponent } from './snippet-modal/snippet-overview.component';
+import {
+ angularSampleCode,
+ LINKS_PLACEHOLDER,
+ MARKDOWN_PLACEHOLDER,
+ TAGS_LIST
+} from '../shared';
+import { SnippetService } from '../shared/services/snippet.service';
+import {
+ markFormControlsAsTouched,
+ validatorMaxLines,
+ validatorMaxTags
+} from '../shared/functions/validation';
+import { parseSnippet } from '../shared/functions/parse-snippet';
+import { SEPARATOR } from '../shared/consts';
+
+interface SnippetFileInfo {
+ sha: string;
+ fileName: string;
+ snippet: string;
+ branchName: string;
+}
+
+function importSnippet(snippet) {
+ const result = { ...snippet };
+ result.links = (result.links || []).join(SEPARATOR);
+ return result;
+}
+
+@Component({
+ selector: 'codelab-create-snippet',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ templateUrl: './create-snippet.component.html',
+ styleUrls: ['./create-snippet.component.scss']
+})
+export class CreateSnippetComponent implements OnDestroy {
+ @ViewChild('tagInput', { static: false }) tagInput: ElementRef<
+ HTMLInputElement
+ >;
+ @ViewChild('auto', { static: false }) matAutocomplete: MatAutocomplete;
+
+ repoName: string;
+ repoOwner: string;
+
+ destroy = new ReplaySubject(1);
+
+ isLoading = false;
+ isEditing = false;
+ snippetFileInfo: SnippetFileInfo;
+
+ TAGS_LIST = TAGS_LIST;
+ tags: string[] = ['tip'];
+ filteredTags: Observable;
+
+ snippetForm = this.fb.group({
+ title: ['', Validators.required],
+ twitter: [''],
+ level: ['beginner', Validators.required],
+ tags: [this.tags, [Validators.required, validatorMaxTags(5)]],
+ content: [
+ MARKDOWN_PLACEHOLDER,
+ [Validators.required, validatorMaxLines(25)]
+ ],
+ bonus: [''],
+ links: [LINKS_PLACEHOLDER],
+ demo: [angularSampleCode]
+ });
+
+ hasBonus = false;
+ hasLinks = false;
+ hasDemo = false;
+
+ separatorKeysCodes: number[] = [ENTER, COMMA];
+
+ constructor(
+ private fb: FormBuilder,
+ private cd: ChangeDetectorRef,
+ private activatedRoute: ActivatedRoute,
+ private snippetService: SnippetService,
+ public dialog: MatDialog
+ ) {
+ const pullNumber = this.activatedRoute.snapshot.params['pullNumber'];
+ this.repoName = this.activatedRoute.snapshot.params['repoName'];
+ this.repoOwner = this.activatedRoute.snapshot.params['repoOwner'];
+
+ if (pullNumber) {
+ this.isEditing = true;
+ this.fetchPR(pullNumber);
+ }
+
+ this.filteredTags = this.snippetForm
+ .get('tags')
+ .valueChanges.pipe(
+ map((tags: string) =>
+ tags ? this._filterTags(tags.slice(-1)[0]) : this.TAGS_LIST.slice()
+ )
+ );
+ }
+
+ fetchPR(pullNumber: number) {
+ this.isLoading = true;
+ this.snippetService
+ .fetchPR(this.repoName, this.repoOwner, pullNumber)
+ .pipe(
+ finalize(() => {
+ this.isLoading = false;
+ this.cd.markForCheck();
+ })
+ )
+ .subscribe((snippetFileInfo: SnippetFileInfo) => {
+ this.snippetFileInfo = snippetFileInfo;
+
+ const snippet = importSnippet(parseSnippet(snippetFileInfo.snippet));
+ if (snippet.demo) {
+ this.hasDemo = true;
+ }
+ if (snippet.bonus) {
+ this.hasBonus = true;
+ }
+ if (snippet.links) {
+ this.hasLinks = true;
+ }
+ this.snippetForm.patchValue(snippet);
+ });
+ }
+
+ ngOnDestroy() {
+ this.destroy.next(null);
+ this.destroy.complete();
+ }
+
+ openPreview() {
+ if (this.snippetForm.valid) {
+ this.dialog.open(SnippetOverviewComponent, {
+ data: {
+ formValue: this.getPreparedFormValue(this.snippetForm.value),
+ isEditing: this.isEditing,
+ fileInfo: this.snippetFileInfo
+ ? {
+ sha: this.snippetFileInfo['sha'],
+ fileName: this.snippetFileInfo['fileName'],
+ branchName: this.snippetFileInfo['branchName']
+ }
+ : null,
+ repoName: this.repoName,
+ repoOwner: this.repoOwner
+ }
+ });
+ } else {
+ markFormControlsAsTouched(this.snippetForm);
+ }
+ }
+
+ getPreparedFormValue(value) {
+ Object.keys(value['demo']).forEach(x => {
+ const isChangedAndNotEmpty =
+ this.hasDemo && value.demo[x] && value.demo[x] !== angularSampleCode[x];
+ value['demo'][x] = isChangedAndNotEmpty ? value.demo[x] : null;
+ });
+ value['bonus'] = this.hasBonus ? value['bonus'] : null;
+ value['links'] = this.hasLinks ? value['links'] : null;
+ return value;
+ }
+
+ addTag(event: MatChipInputEvent): void {
+ if (!this.matAutocomplete.isOpen) {
+ const input = event.input;
+ const value = event.value;
+ if ((value || '').trim()) {
+ this.tags.push(value.trim());
+ }
+ if (input) {
+ input.value = '';
+ }
+ this.snippetForm.get('tags').patchValue(this.tags);
+ }
+ }
+
+ removeTag(tag: string): void {
+ const index = this.tags.indexOf(tag);
+ if (index >= 0) {
+ this.tags.splice(index, 1);
+ }
+ this.snippetForm.get('tags').patchValue(this.tags);
+ }
+
+ selectedTags(event: MatAutocompleteSelectedEvent): void {
+ this.tags.push(event.option.viewValue);
+ this.tagInput.nativeElement.value = '';
+ this.snippetForm.get('tags').patchValue(this.tags);
+ }
+
+ private _filterTags(value: string): string[] {
+ const filterValue = value ? value.toLowerCase() : null;
+ return this.TAGS_LIST.filter(
+ tag => tag.toLowerCase().indexOf(filterValue) === 0
+ );
+ }
+}
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/create-snippet.module.ts b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/create-snippet.module.ts
new file mode 100644
index 000000000..6cbab2a18
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/create-snippet.module.ts
@@ -0,0 +1,50 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { CreateSnippetComponent } from './create-snippet.component';
+import { SnippetInfoComponent } from './snippet-info/snippet-info.component';
+import { ReactiveFormsModule } from '@angular/forms';
+import { MatAutocompleteModule } from '@angular/material/autocomplete';
+import { MatButtonModule } from '@angular/material/button';
+import { MatChipsModule } from '@angular/material/chips';
+import { MatDialogModule } from '@angular/material/dialog';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { MatInputModule } from '@angular/material/input';
+import { MatSelectModule } from '@angular/material/select';
+import { MatSnackBarModule } from '@angular/material/snack-bar';
+import { MarkdownModule } from 'ngx-markdown';
+import { CodeDemoModule } from '@codelab/code-demos';
+import { SnippetOverviewComponent } from './snippet-modal/snippet-overview.component';
+import { SnippetSpinnerComponent } from './snippet-spinner/snippet-spinner.component';
+import { AngularFireAuthModule } from '@angular/fire/auth';
+import { RouterModule } from '@angular/router';
+
+const MAT_MODULES = [
+ MatButtonModule,
+ MatFormFieldModule,
+ MatChipsModule,
+ MatAutocompleteModule,
+ MatSelectModule,
+ MatInputModule,
+ MatDialogModule,
+ MatSnackBarModule
+];
+
+@NgModule({
+ declarations: [
+ CreateSnippetComponent,
+ SnippetInfoComponent,
+ SnippetOverviewComponent,
+ SnippetSpinnerComponent
+ ],
+ entryComponents: [SnippetOverviewComponent],
+ imports: [
+ ...MAT_MODULES,
+ CommonModule,
+ ReactiveFormsModule,
+ AngularFireAuthModule,
+ MarkdownModule.forRoot(),
+ CodeDemoModule,
+ RouterModule
+ ]
+})
+export class CreateSnippetModule {}
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-info/snippet-info.component.html b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-info/snippet-info.component.html
new file mode 100644
index 000000000..54ffa270f
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-info/snippet-info.component.html
@@ -0,0 +1,3 @@
+
+ This form will generate a snippet request for you.
+
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-info/snippet-info.component.scss b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-info/snippet-info.component.scss
new file mode 100644
index 000000000..0115567e8
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-info/snippet-info.component.scss
@@ -0,0 +1,58 @@
+:host {
+ .snippets-info {
+ float: right;
+ top: 40px;
+ max-width: 50%;
+ padding: 35px 35px 15px 35px;
+ margin-left: 30px;
+ }
+
+ .nav {
+ &-fixed-wrapper {
+ position: fixed;
+ right: 30px;
+ bottom: 30px;
+ z-index: 2000;
+ }
+
+ &-btn {
+ border-radius: 50%;
+ width: 45px;
+ height: 45px;
+ font-weight: bold;
+ display: table;
+ text-align: center;
+
+ box-shadow: 0 3px 7px rgba(0, 0, 0, 0.9);
+
+ &-go-up {
+ background: #213451;
+ color: white;
+ cursor: pointer;
+ }
+
+ p {
+ vertical-align: middle;
+ display: table-cell;
+ }
+ }
+ }
+
+ .animated {
+ animation-duration: 1s;
+ }
+
+ @keyframes fadeIn {
+ from {
+ opacity: 0;
+ }
+
+ to {
+ opacity: 1;
+ }
+ }
+
+ .fadeIn {
+ animation-name: fadeIn;
+ }
+}
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-info/snippet-info.component.ts b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-info/snippet-info.component.ts
new file mode 100644
index 000000000..2d9116c31
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-info/snippet-info.component.ts
@@ -0,0 +1,8 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'codelab-snippet-info',
+ templateUrl: './snippet-info.component.html',
+ styleUrls: ['./snippet-info.component.scss']
+})
+export class SnippetInfoComponent {}
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-modal/snippet-overview.component.html b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-modal/snippet-overview.component.html
new file mode 100644
index 000000000..766eef5d8
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-modal/snippet-overview.component.html
@@ -0,0 +1,20 @@
+
+ Snippet Markdown
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-modal/snippet-overview.component.scss b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-modal/snippet-overview.component.scss
new file mode 100644
index 000000000..f6cd210b7
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-modal/snippet-overview.component.scss
@@ -0,0 +1,23 @@
+:host {
+ h1 {
+ color: #444;
+ }
+
+ .snippet-modal {
+ &-footer {
+ float: right;
+ }
+ }
+
+ .btn-submit {
+ float: right;
+ font-weight: 400;
+ text-align: center;
+ vertical-align: middle;
+ border: 1px solid #213451;
+ font-size: 14px;
+ color: #fff;
+ background-color: #213451;
+ cursor: pointer;
+ }
+}
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-modal/snippet-overview.component.ts b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-modal/snippet-overview.component.ts
new file mode 100644
index 000000000..f10ff685d
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-modal/snippet-overview.component.ts
@@ -0,0 +1,157 @@
+import { Component, Inject, OnDestroy, OnInit } from '@angular/core';
+import { Router } from '@angular/router';
+import { AngularFireAuth } from '@angular/fire/auth';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
+import { MatSnackBar } from '@angular/material/snack-bar';
+import { auth } from 'firebase/app';
+import { finalize, switchMap, take, takeUntil } from 'rxjs/operators';
+import { ReplaySubject } from 'rxjs/internal/ReplaySubject';
+import { SnippetService } from '../../shared/services/snippet.service';
+import { GitHubService } from '../../shared/services/github.service';
+import { generateSnippet } from '../../shared/functions/generate-snippet';
+import { SEPARATOR } from '../../shared/consts';
+
+interface SnippetOverviewData {
+ formValue: object;
+ isEditing: boolean;
+ fileInfo: {
+ sha: string;
+ fileName: string;
+ branchName: string;
+ };
+ repoName: string;
+ repoOwner: string;
+}
+
+function exportSnippet(snippet) {
+ const result = { ...snippet };
+ result.links = result.links ? result.links.split(SEPARATOR) : undefined;
+ result.author = result.author || '** Your github username will be here **';
+ result.bonus = result.bonus || undefined;
+ return result;
+}
+
+@Component({
+ selector: 'codelab-snippet-overview',
+ templateUrl: './snippet-overview.component.html',
+ styleUrls: ['./snippet-overview.component.scss']
+})
+export class SnippetOverviewComponent implements OnInit, OnDestroy {
+ destroy = new ReplaySubject(1);
+
+ githubAuth;
+ isPRCreating = false;
+
+ isEditing: boolean;
+ snippet: string;
+ snippetWithFormat: string;
+
+ constructor(
+ public dialogRef: MatDialogRef,
+ private afAuth: AngularFireAuth,
+ private snippetService: SnippetService,
+ private githubService: GitHubService,
+ private _snackBar: MatSnackBar,
+ private router: Router,
+ @Inject(MAT_DIALOG_DATA) public data: SnippetOverviewData
+ ) {}
+
+ ngOnInit() {
+ this.isEditing = this.data.isEditing;
+ this.snippet = generateSnippet(exportSnippet(this.data.formValue));
+ // This is a temporary hack.
+ // The version of markdown requires new lines between meta values, but github does not.
+ this.snippetWithFormat = this.snippet.replace(
+ /\n(title|author|twitter|level|tags|links):/g,
+ '\n\n$1:'
+ );
+ }
+
+ ngOnDestroy() {
+ this.destroy.next(null);
+ this.destroy.complete();
+ }
+
+ async onSubmit() {
+ console.log('You can copy the snippet here:\n', this.snippet);
+ this.isPRCreating = true;
+
+ if (!(this.githubAuth && this.githubAuth.credential)) {
+ await this.login();
+ }
+
+ if (this.isEditing) {
+ this.snippetService
+ .updatePR(
+ this.githubAuth,
+ this.snippet,
+ this.data.fileInfo,
+ this.data.repoName
+ )
+ .pipe(
+ finalize(() => (this.isPRCreating = false)),
+ takeUntil(this.destroy)
+ )
+ .subscribe(res =>
+ this.navigateAndShowSnackBar(
+ 'Success',
+ 'Snippet updated',
+ res['commit']['html_url']
+ )
+ );
+ } else {
+ this.snippetService
+ .createPR(
+ this.githubAuth,
+ this.snippet,
+ this.data.formValue['title'],
+ this.data.repoName,
+ this.data.repoOwner
+ )
+ .pipe(
+ switchMap(res =>
+ this.githubService.addLinkToEditForm(
+ this.data.repoOwner,
+ this.data.repoName,
+ res['number']
+ )
+ ),
+ switchMap(res =>
+ this.githubService.addSnippetLabel(
+ this.data.repoOwner,
+ this.data.repoName,
+ res['number']
+ )
+ ),
+ finalize(() => (this.isPRCreating = false)),
+ takeUntil(this.destroy)
+ )
+ .subscribe(res =>
+ this.navigateAndShowSnackBar(
+ 'Pull request created',
+ res['title'].replace('Add - new snippet: ', ''),
+ res['html_url']
+ )
+ );
+ }
+ }
+
+ navigateAndShowSnackBar(text: string, linkLabel: string, linkUrl: string) {
+ this.dialogRef.close();
+ this.router.navigate(['list']);
+ const snakeBarRef = this._snackBar.open(text, linkLabel, {
+ duration: 20000
+ });
+ snakeBarRef
+ .onAction()
+ .pipe(take(1))
+ .subscribe(() => window.open(linkUrl));
+ }
+
+ async login() {
+ const provider = new auth.GithubAuthProvider().addScope('repo');
+ this.githubAuth = await this.afAuth.auth.signInWithPopup(provider);
+ this.data.formValue['author'] = this.githubAuth.additionalUserInfo.username;
+ this.snippet = generateSnippet(exportSnippet(this.data.formValue));
+ }
+}
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-spinner/snippet-spinner.component.html b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-spinner/snippet-spinner.component.html
new file mode 100644
index 000000000..b12fe4427
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-spinner/snippet-spinner.component.html
@@ -0,0 +1,10 @@
+
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-spinner/snippet-spinner.component.scss b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-spinner/snippet-spinner.component.scss
new file mode 100644
index 000000000..ab4423af9
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-spinner/snippet-spinner.component.scss
@@ -0,0 +1,73 @@
+.spinner-back-ground {
+ position: fixed;
+ width: 100%;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ background-color: rgba(0, 0, 0, 0.2);
+ z-index: 9999;
+}
+
+.centered-spinner {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100vw;
+ height: 100vh;
+}
+
+.preload {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ /*change these sizes to fit into your project*/
+ width: 100px;
+ height: 100px;
+}
+
+.preload div {
+ border: 0;
+ margin: 0;
+ width: 40%;
+ height: 40%;
+ position: absolute;
+ border-radius: 50%;
+ animation: spin 2s ease infinite;
+}
+
+.preload :first-child {
+ background: #19a68c;
+ animation-delay: -1.5s;
+}
+
+.preload :nth-child(2) {
+ background: #f63d3a;
+ animation-delay: -1s;
+}
+
+.preload :nth-child(3) {
+ background: #fda543;
+ animation-delay: -0.5s;
+}
+
+.preload :last-child {
+ background: #193b48;
+}
+
+@keyframes spin {
+ 0%,
+ 100% {
+ transform: translate(0);
+ }
+ 25% {
+ transform: translate(160%);
+ }
+ 50% {
+ transform: translate(160%, 160%);
+ }
+ 75% {
+ transform: translate(0, 160%);
+ }
+}
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-spinner/snippet-spinner.component.ts b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-spinner/snippet-spinner.component.ts
new file mode 100644
index 000000000..d66eb393b
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/create-snippet/snippet-spinner/snippet-spinner.component.ts
@@ -0,0 +1,8 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'codelab-snippet-spinner',
+ templateUrl: './snippet-spinner.component.html',
+ styleUrls: ['./snippet-spinner.component.scss']
+})
+export class SnippetSpinnerComponent {}
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/pull-requests-list/pull-requests-list.component.html b/codelab-master/apps/angular-thirty-seconds/src/app/pull-requests-list/pull-requests-list.component.html
new file mode 100644
index 000000000..a47a9a204
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/pull-requests-list/pull-requests-list.component.html
@@ -0,0 +1,68 @@
+
+
+
+
+
+ #
+
+ {{ item.number }}
+
+
+
+ Title
+
+ {{ item.title }}
+
+
+
+ Author
+
+ {{ item.user.login }}
+
+
+
+ Creation Date
+
+ {{ item.created_at | date: 'MM/dd/yyyy' }}
+
+
+
+ Action
+
+
+ Edit
+
+
+
+
+
+
+
+
+
+ loading ...
+
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/pull-requests-list/pull-requests-list.component.scss b/codelab-master/apps/angular-thirty-seconds/src/app/pull-requests-list/pull-requests-list.component.scss
new file mode 100644
index 000000000..f6d1ff26c
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/pull-requests-list/pull-requests-list.component.scss
@@ -0,0 +1,27 @@
+h1 {
+ color: #444;
+}
+
+.container {
+ max-width: 850px;
+ padding: 0 15px 30px 15px;
+ margin: 0 auto;
+ font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
+}
+
+table {
+ width: 100%;
+}
+
+.mat-cell-padding {
+ padding: 0 5px;
+}
+
+.flex-header {
+ display: flex;
+ justify-content: space-between;
+}
+
+.align-center {
+ align-self: center;
+}
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/pull-requests-list/pull-requests-list.component.ts b/codelab-master/apps/angular-thirty-seconds/src/app/pull-requests-list/pull-requests-list.component.ts
new file mode 100644
index 000000000..54ccb339b
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/pull-requests-list/pull-requests-list.component.ts
@@ -0,0 +1,22 @@
+import { Component } from '@angular/core';
+import { Router } from '@angular/router';
+import { GitHubService } from '../shared/services/github.service';
+
+const REPO_OWNER = 'nycJSorg';
+const REPO_NAME = '30-seconds-of-angular';
+
+@Component({
+ selector: 'codelab-pull-requests-list',
+ templateUrl: './pull-requests-list.component.html',
+ styleUrls: ['./pull-requests-list.component.scss']
+})
+export class PullRequestsListComponent {
+ repoOwner = REPO_OWNER;
+ repoName = REPO_NAME;
+
+ pullsList$ = this.githubService.getPullsList(this.repoOwner, this.repoName);
+
+ displayedColumns = ['number', 'title', 'login', 'created_at', 'action'];
+
+ constructor(private router: Router, private githubService: GitHubService) {}
+}
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/shared/angular-sample.ts b/codelab-master/apps/angular-thirty-seconds/src/app/shared/angular-sample.ts
new file mode 100644
index 000000000..fa1e5e82b
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/shared/angular-sample.ts
@@ -0,0 +1,26 @@
+export const angularSampleCode = {
+ 'app.component.ts': `import { Component } from '@angular/core';
+
+@Component({
+ selector: 'my-app',
+ template: \`Edit me \`
+})
+export class AppComponent {}`,
+ 'app.module.ts': `import { BrowserModule } from '@angular/platform-browser';
+import { NgModule } from '@angular/core';
+import { AppComponent } from './app.component';
+
+@NgModule({
+ imports: [BrowserModule],
+ declarations: [AppComponent],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}`,
+
+ 'main.ts': `import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+import { AppModule } from './app.module';
+
+platformBrowserDynamic().bootstrapModule(AppModule);
+`,
+ 'index.html': ' '
+};
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/shared/constants.ts b/codelab-master/apps/angular-thirty-seconds/src/app/shared/constants.ts
new file mode 100644
index 000000000..a0e564c1d
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/shared/constants.ts
@@ -0,0 +1,24 @@
+export const MARKDOWN_PLACEHOLDER = `
+You can use markdown here.\n
+Highlight \`important terms\` with backticks.\n
+For examples use:
+\`\`\`typescript
+const language = 'English';
+function theLanguageISpeak(language) {
+ // English? No, only typescript!
+ return 'typescript'
+}
+\`\`\``;
+
+export const TAGS_LIST = [
+ 'components',
+ 'tip',
+ 'forms',
+ 'templates',
+ 'styling',
+ 'routing',
+ 'performance'
+];
+
+export const LINKS_PLACEHOLDER = `https://angular.io/
+https://www.typescriptlang.org/`;
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/shared/consts.ts b/codelab-master/apps/angular-thirty-seconds/src/app/shared/consts.ts
new file mode 100644
index 000000000..beddfd27e
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/shared/consts.ts
@@ -0,0 +1 @@
+export const SEPARATOR = '\n';
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/shared/functions/generate-snippet.spec.ts b/codelab-master/apps/angular-thirty-seconds/src/app/shared/functions/generate-snippet.spec.ts
new file mode 100644
index 000000000..3e9828c6a
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/shared/functions/generate-snippet.spec.ts
@@ -0,0 +1,30 @@
+import { testSnippetMd, testSnippetParsed } from './test-data/snippet';
+import { generateSnippet } from './generate-snippet';
+
+describe('GenerateSnippet', () => {
+ it('generates a simple snippet', () => {
+ const actual = generateSnippet(testSnippetParsed);
+ expect(actual).toEqual(testSnippetMd);
+ });
+
+ it('generates a snippet without demo', () => {
+ const testSnippet = { ...testSnippetParsed };
+ delete testSnippet.demo;
+ const actual = generateSnippet(testSnippet);
+ expect(actual).not.toContain('file:');
+ });
+
+ it('generates a snippet without bonus', () => {
+ const testSnippet = { ...testSnippetParsed };
+ delete testSnippet.bonus;
+ const actual = generateSnippet(testSnippet);
+ expect(actual).not.toContain('bonus');
+ });
+
+ it('generates a snippet without links', () => {
+ const testSnippet = { ...testSnippetParsed };
+ delete testSnippet.links;
+ const actual = generateSnippet(testSnippet);
+ expect(actual).not.toContain('links');
+ });
+});
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/shared/functions/generate-snippet.ts b/codelab-master/apps/angular-thirty-seconds/src/app/shared/functions/generate-snippet.ts
new file mode 100644
index 000000000..cd93efef5
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/shared/functions/generate-snippet.ts
@@ -0,0 +1,105 @@
+import { Snippet } from '../interfaces/snippet';
+import { angularSampleCode } from '../angular-sample';
+import { SEPARATOR } from '../consts';
+
+const config = {
+ header: ['title', 'author', 'twitter', 'level', 'links', 'tags'],
+ body: ['content', 'bonus']
+};
+
+function arrayToMarkdownList(tagsArray: Array): string {
+ return tagsArray
+ .filter(a => a)
+ .map(x => `- ${x}`)
+ .join(`\n`);
+}
+
+function generateMdHeader(keys: string[], snippet: Snippet) {
+ return keys
+ .map(key => ({
+ key,
+ value: snippet[key]
+ }))
+ .filter(({ value }) => !!value)
+ .map(({ value, key }) => {
+ if (typeof value === 'string') {
+ return `${key}: ${value}`;
+ }
+ if (Array.isArray(value)) {
+ return `${key}:
+${arrayToMarkdownList(value)}`;
+ }
+ throw new Error(key + 'is not a real key');
+ })
+ .join(SEPARATOR);
+}
+
+const ucFirst = s => {
+ if (typeof s !== 'string') {
+ return '';
+ }
+ return s.charAt(0).toUpperCase() + s.slice(1);
+};
+
+const extensionTolanguage = {
+ ts: 'typescript',
+ js: 'javascript'
+};
+
+function getFileLanguage(fileName) {
+ const fileExtension =
+ fileName.substring(fileName.lastIndexOf('.') + 1, fileName.length) ||
+ fileName;
+ return extensionTolanguage[fileExtension] || fileExtension;
+}
+
+/**
+ * Drop markdown "```language```" from the code
+ */
+function addMarkdownLanguageMark(code: string, filename: string) {
+ return `\`\`\`${getFileLanguage(filename)}
+${code}
+\`\`\``;
+}
+
+function generateMdBody(keys: string[], snippet: Snippet) {
+ return keys
+ .map(key => ({
+ key,
+ value: snippet[key]
+ }))
+ .filter(({ value, key }) => !!value)
+ .map(({ value, key }) => {
+ return `# ${ucFirst(key)}
+${value}
+`;
+ })
+ .join(SEPARATOR);
+}
+
+function generateDemo(snippet) {
+ if (!snippet.demo) {
+ return '';
+ }
+
+ return (
+ Object.entries(snippet.demo)
+ .filter(([key, value]) => value && value !== angularSampleCode[key])
+ .map(([key, value]) => {
+ return `# file:${key}
+${addMarkdownLanguageMark(value.toString(), key)}`;
+ })
+ .join(SEPARATOR) + SEPARATOR
+ );
+}
+
+export function generateSnippet(snippet: Snippet) {
+ const header = generateMdHeader(config.header, snippet);
+ const body = generateMdBody(config.body, snippet);
+ const demo = generateDemo(snippet);
+ return `---
+${header}
+---
+${body}
+${demo}`;
+}
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/shared/functions/parse-snippet.spec.ts b/codelab-master/apps/angular-thirty-seconds/src/app/shared/functions/parse-snippet.spec.ts
new file mode 100644
index 000000000..ac4dd9889
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/shared/functions/parse-snippet.spec.ts
@@ -0,0 +1,40 @@
+import { parseSnippet } from './parse-snippet';
+import {
+ testSnippetEdgeCases,
+ testSnippetMd,
+ testSnippetMinimal,
+ testSnippetParsed
+} from './test-data/snippet';
+
+describe('ParseSnippet', () => {
+ it('parses a simple snippet', () => {
+ const actual = parseSnippet(testSnippetMd);
+ expect(actual).toEqual(testSnippetParsed);
+ });
+
+ it('testSnippetMinimal', () => {
+ const actual = parseSnippet(testSnippetMinimal);
+ expect(actual.bonus).toBe('');
+ expect(actual.links).toEqual(undefined);
+ expect(actual.demo).toEqual(undefined);
+ expect(actual.content).toEqual('Content');
+ });
+
+ it('works when file names have spaces', () => {
+ const actual = parseSnippet(testSnippetEdgeCases);
+
+ expect(actual.demo).toEqual({
+ 'app.component.ts':
+ "import { Component } from '@angular/core';\n\n@Component({\n selector: 'my-app',\n template: `Edit me `\n})\nexport class AppComponent {}",
+ 'app.module.ts':
+ "import { BrowserModule } from '@angular/platform-browser';\nimport { NgModule } from '@angular/core';\nimport { AppComponent } from './app.component';\n" +
+ '\n@NgModule({\n imports: [BrowserModule],\n declarations: [AppComponent],\n' +
+ ' bootstrap: [AppComponent]\n})\nexport class AppModule {}',
+ 'main.ts':
+ "import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';\nimport { AppModule } from './app.module';" +
+ '\n\nplatformBrowserDynamic().bootstrapModule(AppModule);\n',
+ 'index.html': ' ',
+ 'app.svg': ' '
+ });
+ });
+});
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/shared/functions/parse-snippet.ts b/codelab-master/apps/angular-thirty-seconds/src/app/shared/functions/parse-snippet.ts
new file mode 100644
index 000000000..14a75dbb4
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/shared/functions/parse-snippet.ts
@@ -0,0 +1,98 @@
+import { angularSampleCode } from '../angular-sample';
+
+// @ts-ignore
+// If you delete this you get a run time error.
+// This is needed for gray-matter
+window.Buffer = {
+ from() {}
+};
+
+// @ts-ignore
+const matter = require('gray-matter');
+
+/**
+ *
+ * Takes markdown and returns content.
+ * e.g. input:
+ *
+ * # LOL
+ * 1
+ * # HI
+ * 2
+ *
+ * result:
+ *
+ * {LOL: "1", HI: "2"}
+ */
+function extractHeaders(str) {
+ const match = ('\n' + str + '\n#').match(/\n#+.*\n[\s\S]*?(?=\n#)/g);
+ return !match
+ ? { content: str }
+ : match.reduce((result, a) => {
+ const [, header, content] = a.match(/^\n#+(.*)\n([\s\S]*)$/);
+ result[header.trim().toLocaleLowerCase()] = content.trim();
+ return result;
+ }, {});
+}
+
+/**
+ *
+ * Takes markdown and returns content.
+ * e.g. input:
+ *
+ * ---
+ * title: Hello
+ * tags:
+ * - tips
+ * - good-to-know
+ * ---
+ *
+ * # LOL
+ * 1
+ * # HI
+ * 2
+ *
+ * result:
+ *
+ * {title: "Hello", tags: ["tips", "good-to-know"], LOL: "1", HI: "2"}
+ *
+ */
+function mdTextToJson(snippet: string) {
+ const metaData = matter(snippet);
+ return { ...extractHeaders(metaData.content), ...metaData.data };
+}
+
+/**
+ * Drop markdown "```language```" from the code
+ */
+function stripMarkdownLanguageMark(code = '') {
+ return code.replace(/```\w+\n/, '').replace(/\n```/, '');
+}
+
+function normalize(text) {
+ return text ? text.replace(/↵/g, '\n') : '';
+}
+
+export function parseSnippet(snippetBody: string) {
+ const snippet = mdTextToJson(snippetBody);
+ snippet.content = normalize(snippet.content);
+ snippet.bonus = normalize(snippet.bonus);
+
+ const demoFiles = Object.entries(snippet)
+ .filter(([key]) => key.startsWith('file:'))
+ .reduce((files, [key, value]) => {
+ files[key.replace(/^file:/, '').trim()] = stripMarkdownLanguageMark(
+ value.toString()
+ );
+ return files;
+ }, {});
+
+ if (Object.keys(demoFiles).length) {
+ snippet.demo = {
+ ...angularSampleCode,
+ ...demoFiles
+ };
+ }
+
+ return snippet;
+}
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/shared/functions/test-data/snippet.ts b/codelab-master/apps/angular-thirty-seconds/src/app/shared/functions/test-data/snippet.ts
new file mode 100644
index 000000000..6194ec450
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/shared/functions/test-data/snippet.ts
@@ -0,0 +1,84 @@
+export const testSnippetMd = `---
+title: title
+author: author
+twitter: kirjs
+level: intermediate
+links:
+- gogel.com
+- 123.com
+tags:
+- tip
+---
+# Content
+Content
+
+# Bonus
+Wow bonus
+
+# file:app.component.ts
+\`\`\`typescript
+import { Component } from '@angular/core';
+ @Component({
+ selector: 'my-app',
+ templateUrl: './app.svg'
+})
+export class AppComponent {}
+\`\`\`
+# file:app.svg
+\`\`\`svg
+
+\`\`\`
+`;
+
+export const testSnippetParsed = {
+ content: 'Content',
+ bonus: 'Wow bonus',
+ 'file:app.component.ts':
+ "```typescript\nimport { Component } from '@angular/core';\n @Component({\n selector: 'my-app',\n templateUrl: './app.svg'\n})\nexport class AppComponent {}\n```",
+ 'file:app.svg': '```svg\n \n```',
+ title: 'title',
+ author: 'author',
+ twitter: 'kirjs',
+ level: 'intermediate',
+ links: ['gogel.com', '123.com'],
+ tags: ['tip'],
+ demo: {
+ 'app.component.ts':
+ "import { Component } from '@angular/core';\n @Component({\n selector: 'my-app',\n templateUrl: './app.svg'\n})\nexport class AppComponent {}",
+ 'app.module.ts':
+ "import { BrowserModule } from '@angular/platform-browser';\nimport { NgModule } from '@angular/core';\nimport { AppComponent } from './app.component';\n" +
+ '\n@NgModule({\n imports: [BrowserModule],\n declarations: [AppComponent],\n bootstrap: [AppComponent]\n})\nexport class AppModule {}',
+ 'main.ts':
+ "import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';\nimport { AppModule } from './app.module';\n\nplatformBrowserDynamic().bootstrapModule(AppModule);\n",
+ 'index.html': ' ',
+ 'app.svg': ' '
+ }
+};
+
+export const testSnippetMinimal = `---
+title: title
+author: author
+twitter: kirjs
+level: intermediate
+tags:
+- tip
+---
+# Content
+Content`;
+
+export const testSnippetEdgeCases = `---
+title: title
+author: author
+twitter: kirjs
+level: intermediate
+tags:
+- tip
+---
+# Content
+Content
+
+# file: app.svg
+\`\`\`svg
+
+\`\`\`
+`;
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/shared/functions/validation/index.ts b/codelab-master/apps/angular-thirty-seconds/src/app/shared/functions/validation/index.ts
new file mode 100644
index 000000000..4d5ffa36a
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/shared/functions/validation/index.ts
@@ -0,0 +1 @@
+export * from './validation';
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/shared/functions/validation/validation.ts b/codelab-master/apps/angular-thirty-seconds/src/app/shared/functions/validation/validation.ts
new file mode 100644
index 000000000..62d73bd26
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/shared/functions/validation/validation.ts
@@ -0,0 +1,30 @@
+import { FormArray, FormControl, FormGroup } from '@angular/forms';
+import { AbstractControl } from '@angular/forms';
+
+export function markFormControlsAsTouched(
+ formGroup: FormGroup | FormArray
+): void {
+ Object.values(formGroup.controls).forEach(control => {
+ if (control instanceof FormControl) {
+ control.markAsTouched({ onlySelf: true });
+ } else if (control instanceof FormGroup || control instanceof FormArray) {
+ markFormControlsAsTouched(control);
+ }
+ });
+}
+
+export function validatorMaxTags(maximumTags: number) {
+ return (control: AbstractControl) => {
+ return Array.isArray(control.value) && control.value.length > maximumTags
+ ? { tagsError: `Number of tags should be below ${maximumTags + 1}` }
+ : null;
+ };
+}
+
+export function validatorMaxLines(lines: number) {
+ return (control: AbstractControl) => {
+ return control.value.split('\n').length > lines
+ ? { linesError: `This field shouldn't have more than ${lines} lines` }
+ : null;
+ };
+}
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/shared/index.ts b/codelab-master/apps/angular-thirty-seconds/src/app/shared/index.ts
new file mode 100644
index 000000000..47429c854
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/shared/index.ts
@@ -0,0 +1,2 @@
+export * from './angular-sample';
+export * from './constants';
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/shared/interfaces/branch.interface.ts b/codelab-master/apps/angular-thirty-seconds/src/app/shared/interfaces/branch.interface.ts
new file mode 100644
index 000000000..b549864e4
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/shared/interfaces/branch.interface.ts
@@ -0,0 +1,10 @@
+export interface Branch {
+ ref: string;
+ node_id: string;
+ url: string;
+ object: {
+ type: string;
+ sha: string;
+ url: string;
+ };
+}
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/shared/interfaces/commit-info.interface.ts b/codelab-master/apps/angular-thirty-seconds/src/app/shared/interfaces/commit-info.interface.ts
new file mode 100644
index 000000000..0078d4807
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/shared/interfaces/commit-info.interface.ts
@@ -0,0 +1,6 @@
+export interface CommitInfo {
+ message: string;
+ content: string;
+ branchName: string;
+ filePath: string;
+}
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/shared/interfaces/github-auth.interface.ts b/codelab-master/apps/angular-thirty-seconds/src/app/shared/interfaces/github-auth.interface.ts
new file mode 100644
index 000000000..20999beaf
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/shared/interfaces/github-auth.interface.ts
@@ -0,0 +1,10 @@
+import { User } from './user.interface';
+
+export interface GithubAuth {
+ additionalUserInfo: {
+ profile: User;
+ };
+ credential: {
+ accessToken: string;
+ };
+}
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/shared/interfaces/index.ts b/codelab-master/apps/angular-thirty-seconds/src/app/shared/interfaces/index.ts
new file mode 100644
index 000000000..2a353af9c
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/shared/interfaces/index.ts
@@ -0,0 +1,6 @@
+export * from './branch.interface';
+export * from './github-auth.interface';
+export * from './repo.interface';
+export * from './user.interface';
+export * from './pull-request.intreface';
+export * from './commit-info.interface';
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/shared/interfaces/pull-request.intreface.ts b/codelab-master/apps/angular-thirty-seconds/src/app/shared/interfaces/pull-request.intreface.ts
new file mode 100644
index 000000000..78246e8ce
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/shared/interfaces/pull-request.intreface.ts
@@ -0,0 +1,11 @@
+export interface CreatePullRequest {
+ title: string;
+ body: string;
+ branchName: string;
+ labels?: Array;
+}
+
+export interface PullRequest {
+ title: string;
+ html_url: string;
+}
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/shared/interfaces/repo.interface.ts b/codelab-master/apps/angular-thirty-seconds/src/app/shared/interfaces/repo.interface.ts
new file mode 100644
index 000000000..e64c77626
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/shared/interfaces/repo.interface.ts
@@ -0,0 +1,7 @@
+export interface Repo {
+ name: string;
+ full_name: string;
+ sha: string;
+ url: string;
+ git_refs_url: string;
+}
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/shared/interfaces/snippet.ts b/codelab-master/apps/angular-thirty-seconds/src/app/shared/interfaces/snippet.ts
new file mode 100644
index 000000000..05b294c8c
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/shared/interfaces/snippet.ts
@@ -0,0 +1 @@
+export type Snippet = Record;
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/shared/interfaces/user.interface.ts b/codelab-master/apps/angular-thirty-seconds/src/app/shared/interfaces/user.interface.ts
new file mode 100644
index 000000000..c8c6cf937
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/shared/interfaces/user.interface.ts
@@ -0,0 +1,4 @@
+export interface User {
+ login: string;
+ repos_url: string;
+}
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/shared/services/github.service.ts b/codelab-master/apps/angular-thirty-seconds/src/app/shared/services/github.service.ts
new file mode 100644
index 000000000..3bf2616bb
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/shared/services/github.service.ts
@@ -0,0 +1,237 @@
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { MatSnackBar } from '@angular/material/snack-bar';
+import { Observable } from 'rxjs/internal/Observable';
+import { catchError, map } from 'rxjs/operators';
+import { throwError } from 'rxjs/internal/observable/throwError';
+import { MonoTypeOperatorFunction } from 'rxjs/internal/types';
+import {
+ Branch,
+ CommitInfo,
+ CreatePullRequest,
+ Repo,
+ User
+} from '../interfaces';
+
+// TODO work on github api names
+// Here is an example link: https://github.com/github-tools/github
+
+@Injectable({
+ providedIn: 'root'
+})
+export class GitHubService {
+ private apiGithubUrl = 'https://api.github.com';
+ private options: object;
+
+ constructor(private http: HttpClient, private _snackBar: MatSnackBar) {}
+
+ showSnackbarOnError(message: string): MonoTypeOperatorFunction {
+ return catchError(() => {
+ this._snackBar.open(message, '', { duration: 10000 });
+ return throwError(new Error(message));
+ });
+ }
+
+ setToken(token: string) {
+ this.options = { headers: { Authorization: `token ${token}` } };
+ }
+
+ getRepo(owner: string, repoName: string): Observable {
+ requires(owner, 'Owner is required');
+ requires(repoName, 'Repo name is required');
+
+ const requestUrl = `${this.apiGithubUrl}/repos/${owner}/${repoName}`;
+ return this.http
+ .get(requestUrl, this.options)
+ .pipe(this.showSnackbarOnError("Can't get repo"));
+ }
+
+ getMyRepos(user: User): Observable {
+ requires(user, 'User is required');
+
+ return this.http
+ .get(user.repos_url, this.options)
+ .pipe(this.showSnackbarOnError("Can't fetch user repos"));
+ }
+
+ forkRepo(repo: Repo): Observable {
+ requires(repo, 'Repository is required');
+
+ const requestUrl = `${this.apiGithubUrl}/repos/${repo.full_name}/forks`;
+ return this.http
+ .post(requestUrl, {}, this.options)
+ .pipe(this.showSnackbarOnError("Can't fork 30 secs repo"));
+ }
+
+ getMasterBranch(repo: Repo): Observable {
+ requires(repo, 'Repository is required');
+
+ const requestUrl = `${this.apiGithubUrl}/repos/${repo.full_name}/git/refs/heads/master`;
+ return this.http
+ .get(requestUrl, this.options)
+ .pipe(
+ this.showSnackbarOnError(
+ `Can't fetch master branch of ${repo.full_name}`
+ )
+ );
+ }
+
+ createBranch(
+ repo: Repo,
+ baseBranch: Branch,
+ branchName: string
+ ): Observable {
+ requires(repo, 'Repository is required');
+ requires(baseBranch, 'Base branch is required');
+ requires(branchName, 'Branch name is required');
+
+ const requestUrl = `${this.apiGithubUrl}/repos/${repo.full_name}/git/refs`;
+ const branchRef = `refs/heads/${branchName}`;
+ const requestData = {
+ ref: branchRef,
+ sha: baseBranch.object.sha
+ };
+
+ return this.http
+ .post(requestUrl, requestData, this.options)
+ .pipe(
+ this.showSnackbarOnError(
+ `Can't create branch ${branchName} of base branch ${baseBranch.object.url}`
+ )
+ );
+ }
+
+ createCommit(repo: Repo, commitInfo: CommitInfo): Observable {
+ requires(repo, 'Repository is required');
+ requires(commitInfo, 'Commit is required');
+
+ const requestUrl = `${this.apiGithubUrl}/repos/${repo.full_name}/${commitInfo.filePath}`;
+ const requestData = {
+ message: commitInfo.message,
+ branch: commitInfo.branchName,
+ content: commitInfo.content
+ };
+
+ return this.http
+ .put(requestUrl, requestData, this.options)
+ .pipe(this.showSnackbarOnError("Can't create commit"));
+ }
+
+ createPullRequest(
+ repo: Repo,
+ user: User,
+ pullRequest: CreatePullRequest
+ ): Observable {
+ requires(repo, 'Repository is required');
+ requires(user, 'User is required');
+ requires(pullRequest, 'Pull request is required');
+
+ const requestUrl = `${this.apiGithubUrl}/repos/${repo.full_name}/pulls`;
+ const requestData = {
+ title: pullRequest.title,
+ head: `${user.login}:${pullRequest.branchName}`,
+ base: 'master',
+ body: pullRequest.body,
+ labels: pullRequest.labels
+ };
+
+ return this.http
+ .post(requestUrl, requestData, this.options)
+ .pipe(this.showSnackbarOnError("Can't create pull request"));
+ }
+
+ getPullsList(owner: string, repoName: string): Observable {
+ return this.http
+ .get(
+ `${this.apiGithubUrl}/repos/${owner}/${repoName}/pulls`,
+ this.options
+ )
+ .pipe(
+ map(res =>
+ res.filter(
+ x =>
+ x['labels'].length &&
+ x['labels'].map(y => y['name']).indexOf('snippet') > -1
+ )
+ ),
+ this.showSnackbarOnError("Can't fetch user repos")
+ );
+ }
+
+ getPullByPullNumber(
+ owner: string,
+ repoName: string,
+ pullNumber: number
+ ): Observable {
+ return this.http
+ .get(
+ `${this.apiGithubUrl}/repos/${owner}/${repoName}/pulls/${pullNumber}`,
+ this.options
+ )
+ .pipe(this.showSnackbarOnError("Can't get pull request"));
+ }
+
+ addLinkToEditForm(
+ owner: string,
+ repoName: string,
+ pullNumber: number
+ ): Observable {
+ return this.http
+ .patch(
+ `${this.apiGithubUrl}/repos/${owner}/${repoName}/pulls/${pullNumber}`,
+ {
+ body: `Here you can edit snippet content: https://30.codelab.fun/new/${pullNumber}`
+ },
+ this.options
+ )
+ .pipe(this.showSnackbarOnError("Can't update pull request"));
+ }
+
+ addSnippetLabel(owner: string, repoName: string, issueNumber: number) {
+ return this.http
+ .patch(
+ `${this.apiGithubUrl}/repos/${owner}/${repoName}/issues/${issueNumber}`,
+ { labels: ['snippet'] },
+ this.options
+ )
+ .pipe(this.showSnackbarOnError("Can't get issues list"));
+ }
+
+ getPullFileByPullNumber(
+ owner: string,
+ repoName: string,
+ pullNumber: number
+ ): Observable {
+ return this.http
+ .get(
+ `${this.apiGithubUrl}/repos/${owner}/${repoName}/pulls/${pullNumber}/files`,
+ this.options
+ )
+ .pipe(this.showSnackbarOnError("Can't get pull request file"));
+ }
+
+ getSnippetBody(url) {
+ return this.http
+ .get(url, this.options)
+ .pipe(this.showSnackbarOnError("Can't get snippet body"));
+ }
+
+ updateFile(repoFullName, snippetData, fileInfo): Observable {
+ const requestUrl = `${this.apiGithubUrl}/repos/${repoFullName}/contents/${fileInfo['fileName']}`;
+ const requestPayload = {
+ message: `Snippet Update`,
+ content: btoa(snippetData),
+ sha: fileInfo['sha'],
+ branch: fileInfo['branchName']
+ };
+ return this.http
+ .put(requestUrl, requestPayload, this.options)
+ .pipe(this.showSnackbarOnError('Cannot update file'));
+ }
+}
+
+function requires(expression: any, message: string) {
+ if (!expression) {
+ throw new Error(message);
+ }
+}
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/shared/services/snippet.service.spec.ts b/codelab-master/apps/angular-thirty-seconds/src/app/shared/services/snippet.service.spec.ts
new file mode 100644
index 000000000..cb314792f
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/shared/services/snippet.service.spec.ts
@@ -0,0 +1,70 @@
+import { TestBed } from '@angular/core/testing';
+import { SnippetService } from './snippet.service';
+import { GitHubService } from './github.service';
+import { of } from 'rxjs';
+import SpyObj = jasmine.SpyObj;
+
+describe('SnippetService', () => {
+ let gitHubService: SpyObj;
+ const repoName = '30seconds';
+ const repoOwner = 'PIKACHU';
+ const pullNumber = 689;
+
+ beforeEach(() => {
+ gitHubService = jasmine.createSpyObj('gitHubService', [
+ 'getPullByPullNumber',
+ 'getPullFileByPullNumber',
+ 'getSnippetBody'
+ ]);
+
+ TestBed.configureTestingModule({
+ providers: [
+ {
+ provide: GitHubService,
+ useValue: gitHubService
+ }
+ ]
+ });
+ });
+
+ it('should be created', () => {
+ const snippet = 'pirojok';
+ const fileName = 'john';
+ const contents_url = 'LOL';
+ const branchName = 'branch';
+
+ const service: SnippetService = TestBed.inject(SnippetService);
+
+ gitHubService.getPullByPullNumber.and.returnValue(
+ of({
+ head: { ref: branchName }
+ })
+ );
+ const sha = 'sa sha';
+
+ gitHubService.getPullFileByPullNumber.and.returnValue(
+ of([
+ {
+ contents_url,
+ sha,
+ filename: fileName
+ }
+ ])
+ );
+
+ gitHubService.getSnippetBody.and.returnValue(
+ of({
+ content: btoa(snippet)
+ })
+ );
+
+ service.fetchPR(repoName, repoOwner, pullNumber).subscribe(result => {
+ expect(result).toEqual({
+ branchName,
+ fileName,
+ sha,
+ snippet
+ });
+ });
+ });
+});
diff --git a/codelab-master/apps/angular-thirty-seconds/src/app/shared/services/snippet.service.ts b/codelab-master/apps/angular-thirty-seconds/src/app/shared/services/snippet.service.ts
new file mode 100644
index 000000000..3ea6e055b
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/app/shared/services/snippet.service.ts
@@ -0,0 +1,156 @@
+import { Injectable } from '@angular/core';
+import { combineLatest, Observable, of } from 'rxjs';
+import { debounceTime, map, switchMap } from 'rxjs/operators';
+import slugify from 'slugify';
+import { GitHubService } from './github.service';
+import {
+ Branch,
+ CommitInfo,
+ CreatePullRequest,
+ GithubAuth,
+ PullRequest,
+ Repo,
+ User
+} from '../interfaces';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class SnippetService {
+ constructor(private githubService: GitHubService) {}
+
+ fetchPR(repoName: string, repoOwner: string, pullNumber: number) {
+ // todo move it to service later
+ const pr$ = this.githubService.getPullByPullNumber(
+ repoOwner,
+ repoName,
+ pullNumber
+ );
+ const file$ = this.githubService
+ .getPullFileByPullNumber(repoOwner, repoName, pullNumber)
+ .pipe(
+ switchMap(([file]) => {
+ return this.githubService.getSnippetBody(file['contents_url']).pipe(
+ map(res => {
+ const body = atob(res.content);
+ return {
+ ...res[0],
+ body,
+ sha: file['sha'],
+ fileName: file['filename']
+ };
+ })
+ );
+ })
+ );
+
+ return combineLatest([file$, pr$]).pipe(
+ map(([file, pr]) => {
+ return {
+ sha: file['sha'],
+ fileName: file['fileName'],
+ snippet: file['body'] as string,
+ branchName: pr['head']['ref']
+ };
+ })
+ );
+ }
+
+ updatePR(
+ githubAuth: GithubAuth,
+ snippetData: string,
+ fileInfo: object,
+ repoName: string
+ ): Observable {
+ this.githubService.setToken(githubAuth.credential.accessToken);
+ const user: User = githubAuth.additionalUserInfo.profile;
+
+ return this.githubService.getMyRepos(user).pipe(
+ switchMap((repos: Repo[]) => {
+ const repo = repos.find(r => r.name === repoName);
+ return this.githubService.updateFile(
+ repo.full_name,
+ snippetData,
+ fileInfo
+ );
+ })
+ );
+ }
+
+ createPR(
+ githubAuth: GithubAuth,
+ snippetData: string,
+ title: string,
+ repoName: string,
+ repoOwner: string
+ ): Observable {
+ requires(githubAuth, 'Github auth is required');
+ requires(snippetData, 'Snippet is required');
+ requires(title, 'Snippet title is required');
+
+ this.githubService.setToken(githubAuth.credential.accessToken);
+
+ const branchName = `new_snippet_${this.toLowerCaseAndSlugify(title)}`;
+ const filePath = `contents/snippets/${this.toLowerCaseAndSlugify(
+ title
+ )}.md`;
+
+ const user: User = githubAuth.additionalUserInfo.profile;
+ return this.githubService.getRepo(repoOwner, repoName).pipe(
+ switchMap((baseRepo: Repo) => {
+ return this.githubService.getMyRepos(user).pipe(
+ switchMap((repos: Repo[]) => {
+ const repo = repos.find(r => r.name === repoName);
+ return repo
+ ? of(repo)
+ : this.githubService.forkRepo(baseRepo).pipe(debounceTime(5000));
+ }),
+ switchMap((userRepo: Repo) => {
+ return this.githubService.getMasterBranch(userRepo).pipe(
+ switchMap((masterBranch: Branch) => {
+ return this.githubService.createBranch(
+ userRepo,
+ masterBranch,
+ branchName
+ );
+ }),
+ switchMap(() => {
+ const commit: CommitInfo = {
+ message:
+ 'I have added awesome snippet. Look at my awesome snippet!',
+ content: btoa(snippetData),
+ branchName: branchName,
+ filePath: filePath
+ };
+ return this.githubService.createCommit(userRepo, commit);
+ }),
+ switchMap(() => {
+ const pullRequest: CreatePullRequest = {
+ title: `Add - new snippet: ${title}`,
+ body: 'Here is a new snippet. Hope you like it :)',
+ labels: ['snippet'],
+ branchName: branchName
+ };
+ return this.githubService.createPullRequest(
+ baseRepo,
+ user,
+ pullRequest
+ );
+ })
+ );
+ })
+ );
+ })
+ );
+ }
+
+ private toLowerCaseAndSlugify(str: string) {
+ return slugify(str.toLowerCase());
+ }
+}
+
+function requires(expression: any, message: string) {
+ if (!expression) {
+ throw new Error(message);
+ }
+}
diff --git a/libs/angular-ast-viz/src/lib/app.component.css b/codelab-master/apps/angular-thirty-seconds/src/assets/.gitkeep
similarity index 100%
rename from libs/angular-ast-viz/src/lib/app.component.css
rename to codelab-master/apps/angular-thirty-seconds/src/assets/.gitkeep
diff --git a/codelab-master/apps/angular-thirty-seconds/src/environments/environment.prod.ts b/codelab-master/apps/angular-thirty-seconds/src/environments/environment.prod.ts
new file mode 100644
index 000000000..3612073bc
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/environments/environment.prod.ts
@@ -0,0 +1,3 @@
+export const environment = {
+ production: true
+};
diff --git a/codelab-master/apps/angular-thirty-seconds/src/environments/environment.ts b/codelab-master/apps/angular-thirty-seconds/src/environments/environment.ts
new file mode 100644
index 000000000..7b4f817ad
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/environments/environment.ts
@@ -0,0 +1,16 @@
+// This file can be replaced during build by using the `fileReplacements` array.
+// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
+// The list of file replacements can be found in `angular.json`.
+
+export const environment = {
+ production: false
+};
+
+/*
+ * For easier debugging in development mode, you can import the following file
+ * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
+ *
+ * This import should be commented out in production mode because it will have a negative impact
+ * on performance if an error is thrown.
+ */
+// import 'zone.js/dist/zone-error'; // Included with Angular CLI.
diff --git a/codelab-master/apps/angular-thirty-seconds/src/favicon.ico b/codelab-master/apps/angular-thirty-seconds/src/favicon.ico
new file mode 100644
index 000000000..8081c7cea
Binary files /dev/null and b/codelab-master/apps/angular-thirty-seconds/src/favicon.ico differ
diff --git a/codelab-master/apps/angular-thirty-seconds/src/index.html b/codelab-master/apps/angular-thirty-seconds/src/index.html
new file mode 100644
index 000000000..dccd1fe1f
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/index.html
@@ -0,0 +1,18 @@
+
+
+
+
+ AngularThirtySeconds
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/angular-thirty-seconds/src/main.ts b/codelab-master/apps/angular-thirty-seconds/src/main.ts
new file mode 100644
index 000000000..fa4e0aef3
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/main.ts
@@ -0,0 +1,13 @@
+import { enableProdMode } from '@angular/core';
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+
+import { AppModule } from './app/app.module';
+import { environment } from './environments/environment';
+
+if (environment.production) {
+ enableProdMode();
+}
+
+platformBrowserDynamic()
+ .bootstrapModule(AppModule)
+ .catch(err => console.error(err));
diff --git a/codelab-master/apps/angular-thirty-seconds/src/polyfills.ts b/codelab-master/apps/angular-thirty-seconds/src/polyfills.ts
new file mode 100644
index 000000000..d15a1152a
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/polyfills.ts
@@ -0,0 +1,62 @@
+/**
+ * This file includes polyfills needed by Angular and is loaded before the app.
+ * You can add your own extra polyfills to this file.
+ *
+ * This file is divided into 2 sections:
+ * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
+ * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
+ * file.
+ *
+ * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
+ * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
+ * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
+ *
+ * Learn more in https://angular.io/guide/browser-support
+ */
+
+/***************************************************************************************************
+ * BROWSER POLYFILLS
+ */
+
+/** IE10 and IE11 requires the following for NgClass support on SVG elements */
+// import 'classlist.js'; // Run `npm install --save classlist.js`.
+
+/**
+ * Web Animations `@angular/platform-browser/animations`
+ * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
+ * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
+ */
+// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
+
+/**
+ * By default, zone.js will patch all possible macroTask and DomEvents
+ * user can disable parts of macroTask/DomEvents patch by setting following flags
+ * because those flags need to be set before `zone.js` being loaded, and webpack
+ * will put import in the top of bundle, so user need to create a separate file
+ * in this directory (for example: zone-flags.ts), and put the following flags
+ * into that file, and then add the following code before importing zone.js.
+ * import './zone-flags.ts';
+ *
+ * The flags allowed in zone-flags.ts are listed here.
+ *
+ * The following flags will work for all browsers.
+ *
+ * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
+ * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
+ * (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
+ *
+ * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
+ * with the following flag, it will bypass `zone.js` patch for IE/Edge
+ *
+ * (window as any).__Zone_enable_cross_context_check = true;
+ *
+ */
+
+/***************************************************************************************************
+ * Zone JS is required by default for Angular itself.
+ */
+import 'zone.js/dist/zone'; // Included with Angular CLI.
+
+/***************************************************************************************************
+ * APPLICATION IMPORTS
+ */
diff --git a/codelab-master/apps/angular-thirty-seconds/src/styles.scss b/codelab-master/apps/angular-thirty-seconds/src/styles.scss
new file mode 100644
index 000000000..d6562785a
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/styles.scss
@@ -0,0 +1,7 @@
+@import '~@angular/material/prebuilt-themes/indigo-pink.css';
+
+html,
+body {
+ margin: 0;
+ padding: 0;
+}
diff --git a/codelab-master/apps/angular-thirty-seconds/src/test.ts b/codelab-master/apps/angular-thirty-seconds/src/test.ts
new file mode 100644
index 000000000..16317897b
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/src/test.ts
@@ -0,0 +1,20 @@
+// This file is required by karma.conf.js and loads recursively all the .spec and framework files
+
+import 'zone.js/dist/zone-testing';
+import { getTestBed } from '@angular/core/testing';
+import {
+ BrowserDynamicTestingModule,
+ platformBrowserDynamicTesting
+} from '@angular/platform-browser-dynamic/testing';
+
+declare const require: any;
+
+// First, initialize the Angular testing environment.
+getTestBed().initTestEnvironment(
+ BrowserDynamicTestingModule,
+ platformBrowserDynamicTesting()
+);
+// Then we find all the tests.
+const context = require.context('./', true, /\.spec\.ts$/);
+// And load the modules.
+context.keys().map(context);
diff --git a/codelab-master/apps/angular-thirty-seconds/tsconfig.app.json b/codelab-master/apps/angular-thirty-seconds/tsconfig.app.json
new file mode 100644
index 000000000..f68ed007e
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/tsconfig.app.json
@@ -0,0 +1,9 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../../dist/out-tsc",
+ "types": []
+ },
+ "exclude": ["test.ts", "**/*.spec.ts"],
+ "include": ["**/*.ts"]
+}
diff --git a/codelab-master/apps/angular-thirty-seconds/tsconfig.json b/codelab-master/apps/angular-thirty-seconds/tsconfig.json
new file mode 100644
index 000000000..38260e195
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/tsconfig.json
@@ -0,0 +1,6 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "types": ["jasmine"]
+ }
+}
diff --git a/codelab-master/apps/angular-thirty-seconds/tsconfig.spec.json b/codelab-master/apps/angular-thirty-seconds/tsconfig.spec.json
new file mode 100644
index 000000000..e729d1001
--- /dev/null
+++ b/codelab-master/apps/angular-thirty-seconds/tsconfig.spec.json
@@ -0,0 +1,9 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../../dist/out-tsc",
+ "types": ["jasmine", "node"]
+ },
+ "files": ["src/test.ts", "src/polyfills.ts"],
+ "include": ["**/*.spec.ts", "**/*.d.ts"]
+}
diff --git a/libs/firebase-login/tslint.json b/codelab-master/apps/angular-thirty-seconds/tslint.json
similarity index 100%
rename from libs/firebase-login/tslint.json
rename to codelab-master/apps/angular-thirty-seconds/tslint.json
diff --git a/codelab-master/apps/blog/browserslist b/codelab-master/apps/blog/browserslist
new file mode 100644
index 000000000..37371cb04
--- /dev/null
+++ b/codelab-master/apps/blog/browserslist
@@ -0,0 +1,11 @@
+# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers
+# For additional information regarding the format and rule options, please see:
+# https://github.com/browserslist/browserslist#queries
+#
+# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed
+
+> 0.5%
+last 2 versions
+Firefox ESR
+not dead
+not IE 9-11
\ No newline at end of file
diff --git a/codelab-master/apps/blog/jest.config.js b/codelab-master/apps/blog/jest.config.js
new file mode 100644
index 000000000..0e1024e8d
--- /dev/null
+++ b/codelab-master/apps/blog/jest.config.js
@@ -0,0 +1,5 @@
+module.exports = {
+ name: 'blog',
+ preset: '../../jest.config.js',
+ coverageDirectory: '../../coverage/apps/blog/'
+};
diff --git a/codelab-master/apps/blog/src/app/app.component.html b/codelab-master/apps/blog/src/app/app.component.html
new file mode 100644
index 000000000..c1fd98af5
--- /dev/null
+++ b/codelab-master/apps/blog/src/app/app.component.html
@@ -0,0 +1,6 @@
+
+
Angular Codelab Newsletter
+
+
+
+
diff --git a/codelab-master/apps/blog/src/app/app.component.scss b/codelab-master/apps/blog/src/app/app.component.scss
new file mode 100644
index 000000000..9761a7948
--- /dev/null
+++ b/codelab-master/apps/blog/src/app/app.component.scss
@@ -0,0 +1,24 @@
+h2 {
+ color: white;
+ text-align: center;
+ height: 70px;
+ background-image: linear-gradient(to right, red, white);
+ width: 90%;
+}
+div {
+ width: 100%;
+ display: flex;
+}
+
+span {
+ margin: auto;
+ display: inline-block;
+ vertical-align: middle;
+ line-height: normal;
+ margin-top: 20px;
+}
+
+img {
+ height: 100px;
+ margin-left: auto;
+}
diff --git a/codelab-master/apps/blog/src/app/app.component.spec.ts b/codelab-master/apps/blog/src/app/app.component.spec.ts
new file mode 100644
index 000000000..83efa430f
--- /dev/null
+++ b/codelab-master/apps/blog/src/app/app.component.spec.ts
@@ -0,0 +1,33 @@
+import { TestBed, async } from '@angular/core/testing';
+import { AppComponent } from './app.component';
+import { RouterTestingModule } from '@angular/router/testing';
+
+describe('AppComponent', () => {
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [RouterTestingModule],
+ declarations: [AppComponent]
+ }).compileComponents();
+ }));
+
+ it('should create the app', () => {
+ const fixture = TestBed.createComponent(AppComponent);
+ const app = fixture.debugElement.componentInstance;
+ expect(app).toBeTruthy();
+ });
+
+ it(`should have as title 'blog'`, () => {
+ const fixture = TestBed.createComponent(AppComponent);
+ const app = fixture.debugElement.componentInstance;
+ expect(app.title).toEqual('blog');
+ });
+
+ it('should render title in a h1 tag', () => {
+ const fixture = TestBed.createComponent(AppComponent);
+ fixture.detectChanges();
+ const compiled = fixture.debugElement.nativeElement;
+ expect(compiled.querySelector('h1').textContent).toContain(
+ 'Welcome to blog!'
+ );
+ });
+});
diff --git a/codelab-master/apps/blog/src/app/app.component.ts b/codelab-master/apps/blog/src/app/app.component.ts
new file mode 100644
index 000000000..014583e16
--- /dev/null
+++ b/codelab-master/apps/blog/src/app/app.component.ts
@@ -0,0 +1,10 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'codelab-root',
+ templateUrl: './app.component.html',
+ styleUrls: ['./app.component.scss']
+})
+export class AppComponent {
+ title = 'blog';
+}
diff --git a/codelab-master/apps/blog/src/app/app.module.ts b/codelab-master/apps/blog/src/app/app.module.ts
new file mode 100644
index 000000000..2a243e61a
--- /dev/null
+++ b/codelab-master/apps/blog/src/app/app.module.ts
@@ -0,0 +1,60 @@
+import { HttpClientModule } from '@angular/common/http';
+import { NgModule } from '@angular/core';
+import { AngularFireModule } from '@angular/fire';
+import { AngularFireAuthModule } from '@angular/fire/auth';
+import { AngularFireDatabaseModule } from '@angular/fire/database';
+import { ReactiveFormsModule } from '@angular/forms';
+import { MatCardModule } from '@angular/material/card';
+import { MatSnackBarModule } from '@angular/material/snack-bar';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { MatSelectModule } from '@angular/material/select';
+import { BrowserModule } from '@angular/platform-browser';
+import { RouterModule, Routes } from '@angular/router';
+import { MarkdownModule } from 'ngx-markdown';
+
+import { environment } from '../../../../apps/codelab/src/environments/environment';
+import { AppComponent } from './app.component';
+import { FeedComponent } from './feed/feed.component';
+import { FormComponent } from './form/form.component';
+import { PostService } from './post.service';
+import { PostComponent } from './post/post.component';
+import { SinglePostComponent } from './single-post/single-post.component';
+
+export const angularFire = AngularFireModule.initializeApp(
+ environment.firebaseConfig
+);
+
+const appRoutes: Routes = [
+ { path: 'post/:id', component: PostComponent },
+ { path: '', component: FeedComponent },
+ { path: 'form', component: FormComponent }
+];
+
+@NgModule({
+ declarations: [
+ AppComponent,
+ FormComponent,
+ FeedComponent,
+ PostComponent,
+ SinglePostComponent
+ ],
+ imports: [
+ BrowserModule,
+ MarkdownModule.forRoot(),
+ MatFormFieldModule,
+ MatSelectModule,
+ ReactiveFormsModule,
+ HttpClientModule,
+ AngularFireDatabaseModule,
+ angularFire,
+ MatCardModule,
+ AngularFireAuthModule,
+ MatSnackBarModule,
+
+ RouterModule.forRoot(appRoutes, { initialNavigation: 'enabled' })
+ ],
+ providers: [PostService],
+ bootstrap: [AppComponent],
+ exports: [FormComponent]
+})
+export class AppModule {}
diff --git a/codelab-master/apps/blog/src/app/common.ts b/codelab-master/apps/blog/src/app/common.ts
new file mode 100644
index 000000000..9b67162c2
--- /dev/null
+++ b/codelab-master/apps/blog/src/app/common.ts
@@ -0,0 +1,8 @@
+export interface Post {
+ key?: string;
+ title: string;
+ author: string;
+ text: string;
+ date: string;
+ hidden: boolean;
+}
diff --git a/codelab-master/apps/blog/src/app/feed/feed.component.html b/codelab-master/apps/blog/src/app/feed/feed.component.html
new file mode 100644
index 000000000..4ad805a88
--- /dev/null
+++ b/codelab-master/apps/blog/src/app/feed/feed.component.html
@@ -0,0 +1,6 @@
+Tell us what you have done!
+
+
diff --git a/libs/angular-ast-viz/src/lib/ast-tree/ast-tree.module.ts b/codelab-master/apps/blog/src/app/feed/feed.component.scss
similarity index 100%
rename from libs/angular-ast-viz/src/lib/ast-tree/ast-tree.module.ts
rename to codelab-master/apps/blog/src/app/feed/feed.component.scss
diff --git a/codelab-master/apps/blog/src/app/feed/feed.component.spec.ts b/codelab-master/apps/blog/src/app/feed/feed.component.spec.ts
new file mode 100644
index 000000000..b854547c9
--- /dev/null
+++ b/codelab-master/apps/blog/src/app/feed/feed.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { FeedComponent } from './feed.component';
+
+describe('FeedComponent', () => {
+ let component: FeedComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [FeedComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(FeedComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/blog/src/app/feed/feed.component.ts b/codelab-master/apps/blog/src/app/feed/feed.component.ts
new file mode 100644
index 000000000..92f61da95
--- /dev/null
+++ b/codelab-master/apps/blog/src/app/feed/feed.component.ts
@@ -0,0 +1,30 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { PostService } from '../post.service';
+import { Observable } from 'rxjs';
+import { Post } from '../common';
+import { map } from 'rxjs/operators';
+
+@Component({
+ selector: 'codelab-feed',
+ templateUrl: './feed.component.html',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ styleUrls: ['./feed.component.scss']
+})
+export class FeedComponent {
+ posts$: Observable;
+
+ constructor(private postService: PostService) {
+ this.posts$ = this.postService.repo$.snapshotChanges().pipe(
+ map(items => {
+ return items
+ .map(a => {
+ return {
+ ...a.payload.val(),
+ key: a.payload.key
+ };
+ })
+ .reverse();
+ })
+ );
+ }
+}
diff --git a/codelab-master/apps/blog/src/app/form/form.component.html b/codelab-master/apps/blog/src/app/form/form.component.html
new file mode 100644
index 000000000..dabb82aa4
--- /dev/null
+++ b/codelab-master/apps/blog/src/app/form/form.component.html
@@ -0,0 +1,38 @@
+Tell us what's new
+
+
+
+
+
+
+
+
+
+ Submit
+
+
+
+Back
diff --git a/codelab-master/apps/blog/src/app/form/form.component.scss b/codelab-master/apps/blog/src/app/form/form.component.scss
new file mode 100644
index 000000000..991f2c273
--- /dev/null
+++ b/codelab-master/apps/blog/src/app/form/form.component.scss
@@ -0,0 +1,19 @@
+.container {
+ display: flex;
+ flex-direction: column;
+ width: 40%;
+}
+
+input,
+textarea {
+ width: 600px;
+}
+
+.form-control {
+ margin: 2px;
+}
+
+textarea {
+ overflow: auto;
+ resize: vertical;
+}
diff --git a/codelab-master/apps/blog/src/app/form/form.component.spec.ts b/codelab-master/apps/blog/src/app/form/form.component.spec.ts
new file mode 100644
index 000000000..0d2585861
--- /dev/null
+++ b/codelab-master/apps/blog/src/app/form/form.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { FormComponent } from './form.component';
+
+describe('FormComponent', () => {
+ let component: FormComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [FormComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(FormComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/blog/src/app/form/form.component.ts b/codelab-master/apps/blog/src/app/form/form.component.ts
new file mode 100644
index 000000000..067721b50
--- /dev/null
+++ b/codelab-master/apps/blog/src/app/form/form.component.ts
@@ -0,0 +1,48 @@
+import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { Observable } from 'rxjs';
+import { FormControl, FormGroup, Validators } from '@angular/forms';
+import { PostService } from '../post.service';
+import { Router } from '@angular/router';
+import { Post } from '../common';
+
+@Component({
+ selector: 'codelab-form',
+ templateUrl: './form.component.html',
+ styleUrls: ['./form.component.scss'],
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class FormComponent {
+ title = new FormControl('', Validators.required);
+ author = new FormControl('', Validators.required);
+ text = new FormControl('', Validators.required);
+ date: Date;
+ post: Observable;
+ myform = new FormGroup({
+ title: this.title,
+ author: this.author,
+ text: this.text
+ });
+ statusMessage = '';
+ error = false;
+
+ constructor(
+ private http: HttpClient,
+ private postService: PostService,
+ private router: Router
+ ) {}
+
+ onSubmit() {
+ const formValues: any = this.myform.getRawValue();
+ this.postService
+ .addPost(formValues)
+ .then(({ key }) => {
+ this.myform.reset();
+ this.router.navigateByUrl(`post/${key}`);
+ })
+ .catch(() => {
+ this.statusMessage = 'Error';
+ this.error = true;
+ });
+ }
+}
diff --git a/codelab-master/apps/blog/src/app/post.service.ts b/codelab-master/apps/blog/src/app/post.service.ts
new file mode 100644
index 000000000..31cafe4dc
--- /dev/null
+++ b/codelab-master/apps/blog/src/app/post.service.ts
@@ -0,0 +1,39 @@
+import { Injectable } from '@angular/core';
+import { AngularFireDatabase, AngularFireList } from '@angular/fire/database';
+import { Observable } from 'rxjs';
+import { Post } from './common';
+import { database } from 'firebase/app';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class PostService {
+ repo$: AngularFireList = this.database.list('/posts', ref => {
+ return ref.orderByChild('hidden').equalTo(null);
+ });
+
+ constructor(private database: AngularFireDatabase) {}
+
+ getPostById(id: string) {
+ return this.database.object(`posts/${id}`);
+ }
+
+ removePost(id: string) {
+ return this.getPostById(id).remove();
+ }
+
+ updatePost(id: string, post: Partial) {
+ return this.getPostById(id).update(post);
+ }
+
+ addPost(post: Post): any {
+ return this.repo$.push({
+ ...post,
+ date: database.ServerValue.TIMESTAMP as string
+ });
+ }
+
+ getPost(id: string): Observable {
+ return this.getPostById(id).valueChanges();
+ }
+}
diff --git a/codelab-master/apps/blog/src/app/post/post.component.html b/codelab-master/apps/blog/src/app/post/post.component.html
new file mode 100644
index 000000000..49632850a
--- /dev/null
+++ b/codelab-master/apps/blog/src/app/post/post.component.html
@@ -0,0 +1,8 @@
+
+
+ Back
+
diff --git a/codelab-master/apps/blog/src/app/post/post.component.scss b/codelab-master/apps/blog/src/app/post/post.component.scss
new file mode 100644
index 000000000..bdeae1ef1
--- /dev/null
+++ b/codelab-master/apps/blog/src/app/post/post.component.scss
@@ -0,0 +1,4 @@
+.text {
+ overflow: hidden;
+ max-height: 100px;
+}
diff --git a/codelab-master/apps/blog/src/app/post/post.component.spec.ts b/codelab-master/apps/blog/src/app/post/post.component.spec.ts
new file mode 100644
index 000000000..14de6c8b0
--- /dev/null
+++ b/codelab-master/apps/blog/src/app/post/post.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { PostComponent } from './post.component';
+
+describe('PostComponent', () => {
+ let component: PostComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [PostComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(PostComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/blog/src/app/post/post.component.ts b/codelab-master/apps/blog/src/app/post/post.component.ts
new file mode 100644
index 000000000..3bb4dd9f6
--- /dev/null
+++ b/codelab-master/apps/blog/src/app/post/post.component.ts
@@ -0,0 +1,27 @@
+import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
+import { Observable } from 'rxjs';
+import { Post } from '../common';
+import { PostService } from '../post.service';
+import { ActivatedRoute } from '@angular/router';
+import { MarkdownModule } from 'ngx-markdown';
+
+@Component({
+ selector: 'codelab-post',
+ templateUrl: './post.component.html',
+ styleUrls: ['./post.component.scss'],
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class PostComponent implements OnInit {
+ post$: Observable;
+ key: string;
+
+ constructor(
+ private postService: PostService,
+ private route: ActivatedRoute
+ ) {}
+
+ ngOnInit() {
+ this.key = this.route.snapshot.params['id'];
+ this.post$ = this.postService.getPost(this.key);
+ }
+}
diff --git a/codelab-master/apps/blog/src/app/single-post/single-post.component.html b/codelab-master/apps/blog/src/app/single-post/single-post.component.html
new file mode 100644
index 000000000..f7fd7f0b4
--- /dev/null
+++ b/codelab-master/apps/blog/src/app/single-post/single-post.component.html
@@ -0,0 +1,23 @@
+
+
+
+ {{ post.title }}
+ by {{ post.author }} on
+ {{ post.date | date: 'short' }}
+
+
+
+
+
+
+
+
More
+
+ Edit
+ Delete
+
+
+
+
diff --git a/codelab-master/apps/blog/src/app/single-post/single-post.component.scss b/codelab-master/apps/blog/src/app/single-post/single-post.component.scss
new file mode 100644
index 000000000..ce8ecbc07
--- /dev/null
+++ b/codelab-master/apps/blog/src/app/single-post/single-post.component.scss
@@ -0,0 +1,30 @@
+.date {
+ float: right;
+ margin-right: 5px;
+}
+
+.title {
+ margin-top: 0px;
+ margin-top: 0px;
+ padding-left: 5px;
+}
+
+mat-card {
+ margin-bottom: 10px;
+ padding-bottom: 10px;
+}
+.text {
+ overflow: hidden;
+ max-height: 100px;
+}
+
+.gradient {
+ position: absolute;
+ height: 130px;
+ bottom: 0;
+ width: 100%;
+}
+
+.container {
+ position: relative;
+}
diff --git a/codelab-master/apps/blog/src/app/single-post/single-post.component.ts b/codelab-master/apps/blog/src/app/single-post/single-post.component.ts
new file mode 100644
index 000000000..fe4991e38
--- /dev/null
+++ b/codelab-master/apps/blog/src/app/single-post/single-post.component.ts
@@ -0,0 +1,38 @@
+import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
+import { AccessService } from '../../../../codelab/src/app/shared/services/access.service';
+import { Post } from '../common';
+import { PostService } from '../post.service';
+import { Router } from '@angular/router';
+import { MatSnackBar } from '@angular/material/snack-bar';
+
+@Component({
+ selector: 'codelab-single-post',
+ templateUrl: './single-post.component.html',
+ styleUrls: ['./single-post.component.scss'],
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class SinglePostComponent {
+ @Input() post: Post;
+ @Input() full: boolean;
+ @Input() key = '';
+
+ constructor(
+ private postService: PostService,
+ private accessService: AccessService,
+ private router: Router,
+ private snackBar: MatSnackBar
+ ) {}
+
+ delete() {
+ this.accessService.oldIsAdmin$.subscribe();
+ this.post.hidden = true;
+ this.postService
+ .updatePost(this.key, this.post)
+ .then(() => {
+ this.router.navigateByUrl(``);
+ })
+ .catch(err => {
+ this.snackBar.open(`ERR: ${err}`);
+ });
+ }
+}
diff --git a/libs/code-demos/src/lib/code-demo-runner/code-demo-runner.component.css b/codelab-master/apps/blog/src/assets/.gitkeep
similarity index 100%
rename from libs/code-demos/src/lib/code-demo-runner/code-demo-runner.component.css
rename to codelab-master/apps/blog/src/assets/.gitkeep
diff --git a/codelab-master/apps/blog/src/assets/fonts/droid-sans/Apache License.txt b/codelab-master/apps/blog/src/assets/fonts/droid-sans/Apache License.txt
new file mode 100644
index 000000000..989e2c59e
--- /dev/null
+++ b/codelab-master/apps/blog/src/assets/fonts/droid-sans/Apache License.txt
@@ -0,0 +1,201 @@
+Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
\ No newline at end of file
diff --git a/codelab-master/apps/blog/src/assets/fonts/droid-sans/DroidSans-Bold.ttf b/codelab-master/apps/blog/src/assets/fonts/droid-sans/DroidSans-Bold.ttf
new file mode 100644
index 000000000..d065b64eb
Binary files /dev/null and b/codelab-master/apps/blog/src/assets/fonts/droid-sans/DroidSans-Bold.ttf differ
diff --git a/codelab-master/apps/blog/src/assets/fonts/droid-sans/DroidSans.ttf b/codelab-master/apps/blog/src/assets/fonts/droid-sans/DroidSans.ttf
new file mode 100644
index 000000000..ad1efca88
Binary files /dev/null and b/codelab-master/apps/blog/src/assets/fonts/droid-sans/DroidSans.ttf differ
diff --git a/codelab-master/apps/blog/src/assets/images/logo.png b/codelab-master/apps/blog/src/assets/images/logo.png
new file mode 100644
index 000000000..82b24332f
Binary files /dev/null and b/codelab-master/apps/blog/src/assets/images/logo.png differ
diff --git a/codelab-master/apps/blog/src/assets/images/logo.svg b/codelab-master/apps/blog/src/assets/images/logo.svg
new file mode 100644
index 000000000..8f47be04c
--- /dev/null
+++ b/codelab-master/apps/blog/src/assets/images/logo.svg
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/blog/src/environments/environment.prod.ts b/codelab-master/apps/blog/src/environments/environment.prod.ts
new file mode 100644
index 000000000..3612073bc
--- /dev/null
+++ b/codelab-master/apps/blog/src/environments/environment.prod.ts
@@ -0,0 +1,3 @@
+export const environment = {
+ production: true
+};
diff --git a/codelab-master/apps/blog/src/environments/environment.ts b/codelab-master/apps/blog/src/environments/environment.ts
new file mode 100644
index 000000000..7b4f817ad
--- /dev/null
+++ b/codelab-master/apps/blog/src/environments/environment.ts
@@ -0,0 +1,16 @@
+// This file can be replaced during build by using the `fileReplacements` array.
+// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
+// The list of file replacements can be found in `angular.json`.
+
+export const environment = {
+ production: false
+};
+
+/*
+ * For easier debugging in development mode, you can import the following file
+ * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
+ *
+ * This import should be commented out in production mode because it will have a negative impact
+ * on performance if an error is thrown.
+ */
+// import 'zone.js/dist/zone-error'; // Included with Angular CLI.
diff --git a/codelab-master/apps/blog/src/favicon.ico b/codelab-master/apps/blog/src/favicon.ico
new file mode 100644
index 000000000..8081c7cea
Binary files /dev/null and b/codelab-master/apps/blog/src/favicon.ico differ
diff --git a/codelab-master/apps/blog/src/index.html b/codelab-master/apps/blog/src/index.html
new file mode 100644
index 000000000..90c8ac10f
--- /dev/null
+++ b/codelab-master/apps/blog/src/index.html
@@ -0,0 +1,14 @@
+
+
+
+
+ Blog
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/blog/src/main.ts b/codelab-master/apps/blog/src/main.ts
new file mode 100644
index 000000000..fa4e0aef3
--- /dev/null
+++ b/codelab-master/apps/blog/src/main.ts
@@ -0,0 +1,13 @@
+import { enableProdMode } from '@angular/core';
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+
+import { AppModule } from './app/app.module';
+import { environment } from './environments/environment';
+
+if (environment.production) {
+ enableProdMode();
+}
+
+platformBrowserDynamic()
+ .bootstrapModule(AppModule)
+ .catch(err => console.error(err));
diff --git a/codelab-master/apps/blog/src/polyfills.ts b/codelab-master/apps/blog/src/polyfills.ts
new file mode 100644
index 000000000..d15a1152a
--- /dev/null
+++ b/codelab-master/apps/blog/src/polyfills.ts
@@ -0,0 +1,62 @@
+/**
+ * This file includes polyfills needed by Angular and is loaded before the app.
+ * You can add your own extra polyfills to this file.
+ *
+ * This file is divided into 2 sections:
+ * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
+ * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
+ * file.
+ *
+ * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
+ * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
+ * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
+ *
+ * Learn more in https://angular.io/guide/browser-support
+ */
+
+/***************************************************************************************************
+ * BROWSER POLYFILLS
+ */
+
+/** IE10 and IE11 requires the following for NgClass support on SVG elements */
+// import 'classlist.js'; // Run `npm install --save classlist.js`.
+
+/**
+ * Web Animations `@angular/platform-browser/animations`
+ * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
+ * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
+ */
+// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
+
+/**
+ * By default, zone.js will patch all possible macroTask and DomEvents
+ * user can disable parts of macroTask/DomEvents patch by setting following flags
+ * because those flags need to be set before `zone.js` being loaded, and webpack
+ * will put import in the top of bundle, so user need to create a separate file
+ * in this directory (for example: zone-flags.ts), and put the following flags
+ * into that file, and then add the following code before importing zone.js.
+ * import './zone-flags.ts';
+ *
+ * The flags allowed in zone-flags.ts are listed here.
+ *
+ * The following flags will work for all browsers.
+ *
+ * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
+ * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
+ * (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
+ *
+ * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
+ * with the following flag, it will bypass `zone.js` patch for IE/Edge
+ *
+ * (window as any).__Zone_enable_cross_context_check = true;
+ *
+ */
+
+/***************************************************************************************************
+ * Zone JS is required by default for Angular itself.
+ */
+import 'zone.js/dist/zone'; // Included with Angular CLI.
+
+/***************************************************************************************************
+ * APPLICATION IMPORTS
+ */
diff --git a/codelab-master/apps/blog/src/styles.scss b/codelab-master/apps/blog/src/styles.scss
new file mode 100644
index 000000000..be998b46d
--- /dev/null
+++ b/codelab-master/apps/blog/src/styles.scss
@@ -0,0 +1,15 @@
+/* You can add global styles to this file, and also import other style files */
+@import '~@angular/material/prebuilt-themes/indigo-pink.css';
+@font-face {
+ font-family: 'Droid Sans';
+ src: url('/assets/fonts/droid-sans/DroidSans.ttf') format('opentype');
+}
+
+@font-face {
+ font-family: 'Droid Sans Bold';
+ src: url('/assets/fonts/droid-sans/DroidSans-Bold.ttf') format('opentype');
+}
+
+body {
+ font-family: 'Droid Sans', 'Droid Sans Bold';
+}
diff --git a/libs/code-demos/src/test-setup.ts b/codelab-master/apps/blog/src/test-setup.ts
similarity index 100%
rename from libs/code-demos/src/test-setup.ts
rename to codelab-master/apps/blog/src/test-setup.ts
diff --git a/codelab-master/apps/blog/tsconfig.app.json b/codelab-master/apps/blog/tsconfig.app.json
new file mode 100644
index 000000000..7f64c89c1
--- /dev/null
+++ b/codelab-master/apps/blog/tsconfig.app.json
@@ -0,0 +1,8 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../dist/out-tsc",
+ "types": []
+ },
+ "exclude": ["src/test-setup.ts", "**/*.spec.ts"]
+}
diff --git a/codelab-master/apps/blog/tsconfig.json b/codelab-master/apps/blog/tsconfig.json
new file mode 100644
index 000000000..929357216
--- /dev/null
+++ b/codelab-master/apps/blog/tsconfig.json
@@ -0,0 +1,10 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "types": ["node", "jest"]
+ },
+ "include": ["**/*.ts"],
+ "angularCompilerOptions": {
+ "enableIvy": true
+ }
+}
diff --git a/codelab-master/apps/blog/tsconfig.spec.json b/codelab-master/apps/blog/tsconfig.spec.json
new file mode 100644
index 000000000..61c376d57
--- /dev/null
+++ b/codelab-master/apps/blog/tsconfig.spec.json
@@ -0,0 +1,9 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../dist/out-tsc",
+ "types": ["jest", "node"]
+ },
+ "files": ["src/test-setup.ts"],
+ "include": ["**/*.spec.ts", "**/*.d.ts"]
+}
diff --git a/libs/firebase/tslint.json b/codelab-master/apps/blog/tslint.json
similarity index 100%
rename from libs/firebase/tslint.json
rename to codelab-master/apps/blog/tslint.json
diff --git a/codelab-master/apps/codelab/browserslist b/codelab-master/apps/codelab/browserslist
new file mode 100644
index 000000000..b15c7fae5
--- /dev/null
+++ b/codelab-master/apps/codelab/browserslist
@@ -0,0 +1,12 @@
+# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
+# For additional information regarding the format and rule options, please see:
+# https://github.com/browserslist/browserslist#queries
+
+# You can see what browsers were selected by your queries by running:
+# npx browserslist
+
+> 0.5%
+last 2 versions
+Firefox ESR
+not dead
+not IE 9-11 # For IE 9-11 support, remove 'not'.
diff --git a/codelab-master/apps/codelab/extra-webpack.config.js b/codelab-master/apps/codelab/extra-webpack.config.js
new file mode 100644
index 000000000..69558fa55
--- /dev/null
+++ b/codelab-master/apps/codelab/extra-webpack.config.js
@@ -0,0 +1,27 @@
+const webpack = require('webpack');
+const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
+
+const findLoader = (webpackConfig, regex) => {
+ return webpackConfig.module.rules
+ .filter(rule => !!rule.use)
+ .find(rule => rule.use.find(it => !!it.loader && regex.test(it.loader)));
+};
+
+module.exports = (webpackConfig, cliConfig) => {
+ if (cliConfig.buildOptimizer) {
+ const loader = findLoader(
+ webpackConfig,
+ /@angular-devkit\/build-optimizer.*\/webpack-loader/
+ );
+
+ const originalTest = loader.test;
+ loader.test = file => {
+ const isMonaco = !!file.match('node_modules/monaco-editor');
+ return !isMonaco && !!file.match(originalTest);
+ };
+ }
+
+ webpackConfig.plugins.push(new MonacoWebpackPlugin());
+
+ return webpackConfig;
+};
diff --git a/codelab-master/apps/codelab/karma.conf.js b/codelab-master/apps/codelab/karma.conf.js
new file mode 100644
index 000000000..97cb50940
--- /dev/null
+++ b/codelab-master/apps/codelab/karma.conf.js
@@ -0,0 +1,31 @@
+// Karma configuration file, see link for more information
+// https://karma-runner.github.io/1.0/config/configuration-file.html
+
+module.exports = function(config) {
+ config.set({
+ basePath: '../',
+ frameworks: ['jasmine', '@angular-devkit/build-angular'],
+ plugins: [
+ require('karma-jasmine'),
+ require('karma-chrome-launcher'),
+ require('karma-jasmine-html-reporter'),
+ require('karma-coverage-istanbul-reporter'),
+ require('@angular-devkit/build-angular/plugins/karma')
+ ],
+ client: {
+ clearContext: false // leave Jasmine Spec Runner output visible in browser
+ },
+ coverageIstanbulReporter: {
+ dir: require('path').join(__dirname, '../coverage'),
+ reports: ['html', 'lcovonly'],
+ fixWebpackSourcePaths: true
+ },
+ reporters: ['progress', 'kjhtml'],
+ port: 9876,
+ colors: true,
+ logLevel: config.LOG_INFO,
+ autoWatch: true,
+ browsers: ['Chrome'],
+ singleRun: false
+ });
+};
diff --git a/codelab-master/apps/codelab/src/app/admin/admin-routing.module.ts b/codelab-master/apps/codelab/src/app/admin/admin-routing.module.ts
new file mode 100644
index 000000000..55944685e
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/admin/admin-routing.module.ts
@@ -0,0 +1,22 @@
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { AdminComponent } from './admin.component';
+import { UsersComponent } from './users/users.component';
+import { FeedbackComponent } from './feedback/feedback.component';
+
+const routes = [
+ {
+ path: '',
+ component: AdminComponent,
+ children: [
+ { path: 'users', component: UsersComponent },
+ { path: 'feedback', component: FeedbackComponent }
+ ]
+ }
+];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule]
+})
+export class AdminRoutingModule {}
diff --git a/codelab-master/apps/codelab/src/app/admin/admin.component.css b/codelab-master/apps/codelab/src/app/admin/admin.component.css
new file mode 100644
index 000000000..aac68fdee
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/admin/admin.component.css
@@ -0,0 +1,9 @@
+:host {
+ display: block;
+ max-width: 1000px;
+ margin: 0 auto;
+}
+
+.wrapper {
+ margin-top: 20px;
+}
diff --git a/codelab-master/apps/codelab/src/app/admin/admin.component.html b/codelab-master/apps/codelab/src/app/admin/admin.component.html
new file mode 100644
index 000000000..beff4dca8
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/admin/admin.component.html
@@ -0,0 +1,20 @@
+
+ Angular Codelab 🔥 Admin
+
+
+
+ {{ link.name }}
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/admin/admin.component.spec.ts b/codelab-master/apps/codelab/src/app/admin/admin.component.spec.ts
new file mode 100644
index 000000000..60b8ca95a
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/admin/admin.component.spec.ts
@@ -0,0 +1,28 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { AdminComponent } from './admin.component';
+import { AdminModule } from './admin.module';
+import { getMockAngularFireProviders } from '@codelab/utils/src/lib/testing/mocks/angular-fire';
+import { RouterModule } from '@angular/router';
+
+describe('AdminComponent', () => {
+ let component: AdminComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [AdminModule, RouterModule.forRoot([])],
+ providers: [...getMockAngularFireProviders()]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(AdminComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/codelab/src/app/admin/admin.component.ts b/codelab-master/apps/codelab/src/app/admin/admin.component.ts
new file mode 100644
index 000000000..1105c7a59
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/admin/admin.component.ts
@@ -0,0 +1,13 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'codelab-admin',
+ templateUrl: './admin.component.html',
+ styleUrls: ['./admin.component.css']
+})
+export class AdminComponent {
+ readonly links = [
+ { link: 'users', name: 'Users' },
+ { link: 'feedback', name: 'Feedback' }
+ ];
+}
diff --git a/codelab-master/apps/codelab/src/app/admin/admin.module.ts b/codelab-master/apps/codelab/src/app/admin/admin.module.ts
new file mode 100644
index 000000000..cc58d961e
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/admin/admin.module.ts
@@ -0,0 +1,21 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { MatCardModule } from '@angular/material/card';
+import { MatTabsModule } from '@angular/material/tabs';
+import { AdminComponent } from './admin.component';
+import { AdminRoutingModule } from './admin-routing.module';
+import { FeedbackModule } from './feedback/feedback.module';
+import { UsersModule } from './users/users.module';
+
+@NgModule({
+ imports: [
+ AdminRoutingModule,
+ CommonModule,
+ FeedbackModule,
+ UsersModule,
+ MatCardModule,
+ MatTabsModule
+ ],
+ declarations: [AdminComponent]
+})
+export class AdminModule {}
diff --git a/codelab-master/apps/codelab/src/app/admin/feedback/feedback-message-table/feedback-message-table.component.ts b/codelab-master/apps/codelab/src/app/admin/feedback/feedback-message-table/feedback-message-table.component.ts
new file mode 100644
index 000000000..ec02731e2
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/admin/feedback/feedback-message-table/feedback-message-table.component.ts
@@ -0,0 +1,56 @@
+import {
+ Component,
+ Input,
+ ViewChild,
+ Output,
+ EventEmitter,
+ ChangeDetectionStrategy
+} from '@angular/core';
+import { MatMenuTrigger } from '@angular/material/menu';
+import { MatTableDataSource } from '@angular/material/table';
+import { MatSort } from '@angular/material/sort';
+import { Message } from '@codelab/feedback/src/lib/message';
+
+const clearTags = (value: string) =>
+ value.replace(/<[^>]+>/g, '').replace(/Angular Codelab \/ /, '');
+const clearAllTags = (values: Message[]): Message[] =>
+ values.map((m: Message) => ({
+ ...m,
+ header: clearTags(m.header || 'No header')
+ }));
+const sortingDataAccessor = (item, property) => {
+ switch (property) {
+ case 'timestamp':
+ return new Date(item.timestamp).toISOString();
+ default:
+ return item[property];
+ }
+};
+
+@Component({
+ selector: 'codelab-feedback-message-table',
+ templateUrl: './feedback-message-table.html',
+ styleUrls: ['./feedback-message-table.css'],
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class FeedbackMessageTableComponent {
+ @ViewChild(MatSort, { static: true }) sort: MatSort;
+
+ @Input('dataSource')
+ set dataSourceSetter(values: Message[]) {
+ this.dataSource.data = clearAllTags(values);
+ this.dataSource.sortingDataAccessor = sortingDataAccessor;
+ this.dataSource.sort = this.sort;
+ }
+ dataSource = new MatTableDataSource([]);
+
+ closeReasons = [
+ { name: '[Duplicate]', reason: '[Duplicate]' },
+ { name: '[No fix]', reason: '[No fix]' },
+ { name: '[Done]', reason: '[Done]' },
+ { name: '[Nice message]', reason: '[Nice message, though not a real bug]' },
+ { name: "[Can't reproduce]", reason: "[Can't reproduce]" }
+ ];
+
+ tableColumns = ['comment', 'name', 'header', 'timestamp', 'actions'];
+}
diff --git a/codelab-master/apps/codelab/src/app/admin/feedback/feedback-message-table/feedback-message-table.css b/codelab-master/apps/codelab/src/app/admin/feedback/feedback-message-table/feedback-message-table.css
new file mode 100644
index 000000000..7868785b8
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/admin/feedback/feedback-message-table/feedback-message-table.css
@@ -0,0 +1,35 @@
+.done-row {
+ background: #fcfcfc;
+ color: #666;
+}
+
+.mat-column-comment {
+ width: 55%;
+ padding-right: 5px;
+}
+
+.mat-column-name {
+ width: 10%;
+ padding-right: 5px;
+}
+
+.mat-column-header {
+ width: 20%;
+ padding-right: 5px;
+}
+
+.mat-column-timestamp {
+ width: 10%;
+ max-width: 120px;
+ padding-right: 5px;
+}
+
+.mat-column-actions {
+ width: 5%;
+ max-width: 20px;
+}
+
+table {
+ width: 100%;
+ overflow: hidden;
+}
diff --git a/codelab-master/apps/codelab/src/app/admin/feedback/feedback-message-table/feedback-message-table.html b/codelab-master/apps/codelab/src/app/admin/feedback/feedback-message-table/feedback-message-table.html
new file mode 100644
index 000000000..450dd7ccb
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/admin/feedback/feedback-message-table/feedback-message-table.html
@@ -0,0 +1,48 @@
+
+
+ comment
+
+ {{element.comment}}
+
+
+
+
+
+ name
+
+ {{element.name}}
+
+
+
+ header
+
+ {{ element.header}}
+
+
+
+
+ href
+ {{element.href}}
+
+
+
+ timestamp
+
+ {{element.timestamp|date}}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/admin/feedback/feedback.component.css b/codelab-master/apps/codelab/src/app/admin/feedback/feedback.component.css
new file mode 100644
index 000000000..988742743
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/admin/feedback/feedback.component.css
@@ -0,0 +1,9 @@
+.panel {
+ margin-bottom: 10px;
+}
+
+mat-form-field {
+ margin-left: 15px;
+ margin-top: 5px;
+ width: 120px;
+}
diff --git a/codelab-master/apps/codelab/src/app/admin/feedback/feedback.component.html b/codelab-master/apps/codelab/src/app/admin/feedback/feedback.component.html
new file mode 100644
index 000000000..b2e31eae0
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/admin/feedback/feedback.component.html
@@ -0,0 +1,67 @@
+
+
+
+ Feedback
+
+ All
+ Done
+ Undone
+
+
+
+
+ Group by
+
+ Do not group
+ Slide URL
+ Name
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Clear
+
+
+
+
+
+
+
+ {{ item.key }}
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/admin/feedback/feedback.component.spec.ts b/codelab-master/apps/codelab/src/app/admin/feedback/feedback.component.spec.ts
new file mode 100644
index 000000000..5ea7ff3b1
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/admin/feedback/feedback.component.spec.ts
@@ -0,0 +1,31 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { FeedbackComponent } from './feedback.component';
+import { FeedbackModule } from './feedback.module';
+import { getMockAngularFireProviders } from '@codelab/utils/src/lib/testing/mocks/angular-fire';
+import { GithubService } from './github.service';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+
+describe('FeedbackComponent', () => {
+ let component: FeedbackComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [FeedbackModule, NoopAnimationsModule],
+ providers: [
+ ...getMockAngularFireProviders(),
+ { provide: GithubService, useValue: {} }
+ ]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(FeedbackComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/codelab/src/app/admin/feedback/feedback.component.ts b/codelab-master/apps/codelab/src/app/admin/feedback/feedback.component.ts
new file mode 100644
index 000000000..a0d750b4f
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/admin/feedback/feedback.component.ts
@@ -0,0 +1,113 @@
+import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
+import { AngularFireDatabase, AngularFireList } from '@angular/fire/database';
+import { Message } from '@codelab/feedback/src/lib/message';
+import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
+import { map } from 'rxjs/operators';
+
+type Filter = 'all' | 'done' | 'notDone';
+type Grouping = 'nothing' | 'href' | 'name';
+
+function groupBy(feedback: Array, grouping: Grouping) {
+ const result = feedback.reduce((comment, item) => {
+ const groupName = item[grouping];
+ comment[groupName] = comment[groupName] || [];
+ comment[groupName].push(item);
+ return comment;
+ }, {});
+
+ return Object.keys(result).map(key => ({ key, value: result[key] }));
+}
+
+function normalize(feedback: Array) {
+ return feedback.map(item => ({
+ ...(item.payload && item.payload.val()),
+ key: item.key
+ }));
+}
+
+function group([feedback, grouping]) {
+ if (grouping === 'nothing') {
+ return [
+ {
+ key: 'Messages',
+ value: feedback
+ }
+ ];
+ }
+ if (grouping === 'name' || grouping === 'href') {
+ return groupBy(feedback, grouping);
+ }
+ throw new Error('Unknown grouping: ' + grouping);
+}
+
+function filter([feedback, filterName, [fromDate, toDate]]) {
+ let result;
+ if (filterName === 'all') {
+ result = feedback;
+ }
+
+ if (filterName === 'done') {
+ result = feedback.filter(message => message.isDone);
+ }
+
+ if (filterName === 'notDone') {
+ result = feedback.filter(message => !message.isDone);
+ }
+
+ const fromMs = fromDate ? new Date(fromDate).getTime() : null;
+ const toMs = toDate ? new Date(toDate).getTime() + 86400000 : null; // add 24hrs to include the day of upper bound
+
+ result = result.filter(msg => {
+ const timestampMs = new Date(msg.timestamp).getTime();
+ return (
+ (fromMs ? timestampMs >= fromMs : true) &&
+ (toMs ? timestampMs <= toMs : true)
+ );
+ });
+ return result;
+}
+
+@Component({
+ selector: 'codelab-feedback',
+ templateUrl: './feedback.component.html',
+ styleUrls: ['./feedback.component.css'],
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class FeedbackComponent implements OnInit {
+ messages$: Observable<{ key: string; value: Message }[]>;
+ filter$ = new BehaviorSubject('notDone');
+ dateFilter$ = new BehaviorSubject<[string, string]>(['', '']);
+ group$ = new BehaviorSubject('nothing');
+
+ datesForFilter = { dateFrom: '', dateTo: '' };
+
+ constructor(private database: AngularFireDatabase) {}
+
+ ngOnInit() {
+ const feedback$: AngularFireList = this.database.list('/feedback');
+
+ const filteredMessages$ = combineLatest([
+ feedback$.snapshotChanges().pipe(map(normalize)),
+ this.filter$,
+ this.dateFilter$
+ ]).pipe(map(filter));
+
+ this.messages$ = combineLatest([filteredMessages$, this.group$]).pipe(
+ map(group)
+ );
+ }
+
+ changeDate(clearDates = false) {
+ if (clearDates) {
+ this.datesForFilter = { dateFrom: '', dateTo: '' };
+ }
+ this.dateFilter$.next([
+ this.datesForFilter.dateFrom || '',
+ this.datesForFilter.dateTo || ''
+ ]);
+ }
+
+ clearDate() {
+ this.changeDate(true);
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/admin/feedback/feedback.module.ts b/codelab-master/apps/codelab/src/app/admin/feedback/feedback.module.ts
new file mode 100644
index 000000000..0013325ea
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/admin/feedback/feedback.module.ts
@@ -0,0 +1,53 @@
+import { AngularFireDatabaseModule } from '@angular/fire/database';
+import { AngularFireAuthModule } from '@angular/fire/auth';
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { CommonModule } from '@angular/common';
+import { MatCardModule } from '@angular/material/card';
+import { MatMenuModule } from '@angular/material/menu';
+import { MatButtonModule } from '@angular/material/button';
+import { MatSelectModule } from '@angular/material/select';
+import { MatTableModule } from '@angular/material/table';
+import { MatIconModule } from '@angular/material/icon';
+import { MatDatepickerModule } from '@angular/material/datepicker';
+import { MatInputModule } from '@angular/material/input';
+import { MatExpansionModule } from '@angular/material/expansion';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { MatSortModule } from '@angular/material/sort';
+import { MatNativeDateModule } from '@angular/material/core';
+import { SlidesModule } from '@ng360/slides';
+import { BrowserWindowModule } from '@codelab/browser';
+import { FeedbackMessageTableComponent } from './feedback-message-table/feedback-message-table.component';
+import { FeedbackComponent } from './feedback.component';
+import { FeedbackModule as FeedbackLibModule } from '@codelab/feedback';
+
+@NgModule({
+ imports: [
+ RouterModule,
+ AngularFireDatabaseModule,
+ AngularFireAuthModule,
+ BrowserWindowModule,
+ FormsModule,
+ ReactiveFormsModule,
+ CommonModule,
+ SlidesModule,
+ MatButtonModule,
+ MatCardModule,
+ MatMenuModule,
+ MatSelectModule,
+ MatTableModule,
+ MatIconModule,
+ MatDatepickerModule,
+ MatNativeDateModule,
+ MatFormFieldModule,
+ MatInputModule,
+ MatExpansionModule,
+ MatSortModule,
+ FeedbackLibModule
+ ],
+ declarations: [FeedbackComponent, FeedbackMessageTableComponent],
+ exports: [FeedbackComponent],
+ entryComponents: [FeedbackComponent]
+})
+export class FeedbackModule {}
diff --git a/codelab-master/apps/codelab/src/app/admin/feedback/github.service.ts b/codelab-master/apps/codelab/src/app/admin/feedback/github.service.ts
new file mode 100644
index 000000000..50664cd0a
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/admin/feedback/github.service.ts
@@ -0,0 +1,31 @@
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class GithubService {
+ repo = 'codelab-fun/codelab';
+
+ constructor(private http: HttpClient) {}
+
+ createIssue(issueData, accessToken) {
+ const headers = { Authorization: 'token ' + accessToken };
+ const options = { headers };
+ return this.http.post(
+ `https://api.github.com/repos/${this.repo}/issues`,
+ issueData,
+ options
+ );
+ }
+
+ closeIssue(changes, issueId, accessToken) {
+ const headers = { Authorization: 'token ' + accessToken };
+ const options = { headers };
+ return this.http.patch(
+ `https://api.github.com/repos/${this.repo}/issues/${issueId}`,
+ changes,
+ options
+ );
+ }
+}
diff --git a/libs/utils/src/lib/sync/components/sync-sessions/sync-sessions.component.css b/codelab-master/apps/codelab/src/app/admin/users/users.component.css
similarity index 100%
rename from libs/utils/src/lib/sync/components/sync-sessions/sync-sessions.component.css
rename to codelab-master/apps/codelab/src/app/admin/users/users.component.css
diff --git a/codelab-master/apps/codelab/src/app/admin/users/users.component.html b/codelab-master/apps/codelab/src/app/admin/users/users.component.html
new file mode 100644
index 000000000..aa4f76676
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/admin/users/users.component.html
@@ -0,0 +1,16 @@
+
+
+ Key
+ {{ admin.key }}
+
+
+
+ You
+
+ {{ admin.isCurrentUser ? '⛱' : '' }}
+
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/admin/users/users.component.spec.ts b/codelab-master/apps/codelab/src/app/admin/users/users.component.spec.ts
new file mode 100644
index 000000000..fb26617da
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/admin/users/users.component.spec.ts
@@ -0,0 +1,38 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { UsersComponent } from './users.component';
+import { UsersModule } from './users.module';
+import { SyncDbService } from '@codelab/utils/src/lib/sync/services/sync-db.service';
+import { of } from 'rxjs';
+import { LoginService } from '@codelab/firebase-login';
+
+describe('UsersComponent', () => {
+ let component: UsersComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [UsersModule],
+ providers: [
+ {
+ provide: SyncDbService,
+ useValue: { list: () => ({ snapshots$: of([]) }) }
+ },
+ {
+ provide: LoginService,
+ useValue: {}
+ }
+ ]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(UsersComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/codelab/src/app/admin/users/users.component.ts b/codelab-master/apps/codelab/src/app/admin/users/users.component.ts
new file mode 100644
index 000000000..762a6f902
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/admin/users/users.component.ts
@@ -0,0 +1,51 @@
+import { Component, OnInit } from '@angular/core';
+import { LoginService } from '@codelab/firebase-login';
+import { SyncDbService } from '@codelab/utils/src/lib/sync/services/sync-db.service';
+import { map } from 'rxjs/operators';
+import { firebaseToValuesWithKey } from '@codelab/utils/src/lib/sync/common';
+import { combineLatest, Observable } from 'rxjs';
+import { Permissions } from '../../shared/services/access.service';
+
+export interface AdminDb {
+ key: string;
+ permissions: Record;
+}
+
+export interface Admin extends AdminDb {
+ isCurrentUser: boolean;
+}
+
+export interface UserDb {
+ admin: AdminDb[];
+}
+
+@Component({
+ selector: 'codelab-users',
+ templateUrl: './users.component.html',
+ styleUrls: ['./users.component.css']
+})
+export class UsersComponent {
+ readonly displayedColumns = ['isCurrentUser', 'key'];
+
+ readonly admins = this.dbService.list('admin');
+ private readonly allAdmins$ = this.admins.snapshots$.pipe(
+ map(firebaseToValuesWithKey)
+ );
+
+ readonly admins$: Observable = combineLatest([
+ this.allAdmins$,
+ this.loginService.uid$
+ ]).pipe(
+ map(([admins, currentUserUid]) => {
+ return admins.map(admin => ({
+ ...admin,
+ isCurrentUser: admin.key === currentUserUid
+ }));
+ })
+ );
+
+ constructor(
+ private readonly loginService: LoginService,
+ private readonly dbService: SyncDbService
+ ) {}
+}
diff --git a/codelab-master/apps/codelab/src/app/admin/users/users.module.ts b/codelab-master/apps/codelab/src/app/admin/users/users.module.ts
new file mode 100644
index 000000000..9456579a6
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/admin/users/users.module.ts
@@ -0,0 +1,12 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { UsersComponent } from './users.component';
+import { MatCardModule } from '@angular/material/card';
+import { MatTableModule } from '@angular/material/table';
+
+@NgModule({
+ declarations: [UsersComponent],
+ entryComponents: [UsersComponent],
+ imports: [CommonModule, MatTableModule, MatCardModule]
+})
+export class UsersModule {}
diff --git a/codelab-master/apps/codelab/src/app/app-routing.module.ts b/codelab-master/apps/codelab/src/app/app-routing.module.ts
new file mode 100644
index 000000000..51db37503
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/app-routing.module.ts
@@ -0,0 +1,36 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+import { LoginComponent } from './components/login/login.component';
+import { NotFoundComponent } from './components/not-found/not-found.component';
+import { AdminGuard } from './shared/services/guards/admin-guard';
+import { LoginGuard } from './shared/services/guards/login-guard';
+
+const routes: Routes = [
+ {
+ path: '',
+ loadChildren: () =>
+ import('./codelabs/codelabs.module').then(m => m.CodelabsModule)
+ },
+ {
+ path: 'login',
+ component: LoginComponent,
+ canActivate: [LoginGuard]
+ },
+ {
+ path: 'admin',
+ loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule),
+ canActivate: [AdminGuard]
+ },
+ {
+ path: 'sync',
+ loadChildren: () =>
+ import('./sync/sync.module').then(m => m.SyncAdminModule)
+ },
+ { path: '**', component: NotFoundComponent }
+];
+
+@NgModule({
+ imports: [RouterModule.forRoot(routes)],
+ exports: [RouterModule]
+})
+export class AppRoutingModule {}
diff --git a/codelab-master/apps/codelab/src/app/app.component.ts b/codelab-master/apps/codelab/src/app/app.component.ts
new file mode 100644
index 000000000..552b511d6
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/app.component.ts
@@ -0,0 +1,7 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'codelab-root',
+ template: ' '
+})
+export class AppComponent {}
diff --git a/codelab-master/apps/codelab/src/app/app.module.ts b/codelab-master/apps/codelab/src/app/app.module.ts
new file mode 100644
index 000000000..60dcb8a02
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/app.module.ts
@@ -0,0 +1,40 @@
+import { APP_INITIALIZER, NgModule } from '@angular/core';
+import { BrowserModule } from '@angular/platform-browser';
+import { monacoReady } from '@codelab/code-demos';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { AngularFireDatabaseModule } from '@angular/fire/database';
+import { AngularFireModule } from '@angular/fire';
+import { AngularFireAuthModule } from '@angular/fire/auth';
+import { AppComponent } from './app.component';
+import { AppRoutingModule } from './app-routing.module';
+import { LoginModule } from './components/login/login.module';
+import { menuRoutes } from './codelabs/angular/angular-routing.module';
+import { MENU_ROUTES } from './common';
+import { environment } from '../environments/environment';
+import { NotFoundModule } from './components/not-found/not-found.module';
+import { MatButtonModule } from '@angular/material/button';
+import { DirectivesModule } from './directives/directives.module';
+import { HttpClientModule } from '@angular/common/http';
+
+@NgModule({
+ imports: [
+ AppRoutingModule,
+ LoginModule,
+ BrowserModule,
+ BrowserAnimationsModule,
+ HttpClientModule,
+ AngularFireModule.initializeApp(environment.firebaseConfig),
+ AngularFireAuthModule,
+ AngularFireDatabaseModule,
+ NotFoundModule,
+ MatButtonModule,
+ DirectivesModule
+ ],
+ declarations: [AppComponent],
+ providers: [
+ { provide: MENU_ROUTES, useValue: menuRoutes },
+ { provide: APP_INITIALIZER, useValue: monacoReady, multi: true }
+ ],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/about/about.component.html b/codelab-master/apps/codelab/src/app/codelabs/about/about.component.html
new file mode 100644
index 000000000..92a1d5081
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/about/about.component.html
@@ -0,0 +1,403 @@
+
+
+ codelab.fun
+
+
+
+ What is codelab.fun
+
+ Online interactive angular tutorial no setup
+
+
+
+ Interactive code samples
+
+
+
+
+ All open source/Angular Ivy/on Github
+
+
+
+
+
+ Regular offline contributors meetings
+
+
+
+
20+ Live-events in 10+ countries
+
+
+
+
~1000 users a month
+
+
+
+
Almost 50 contributors
+
+
+
+
+
Live-Stream "Звуки программистов"
+
+ @kirjs and @thekiba_io meet on weekends and do long technical streams in
+ russian, https://www.twitch.tv/kirjs
+
+
+
+
+
+ Nov 11, 2016
+ Angular 2.1
+ Kirjs did not know Angular
+ Move exercises to the browser
+
+
+
+ Running tests (mocha / babel + traversing AST)
+
+ - The goal is to quickly assess whether user's code does what we want.
+
+
+ - Initially the plan was to run unit tests in an iframe with TestBed, mocha
+ + chai (code TBD)
+
+
+
+ Types
+ There's no types (TODO: Explain)
+
+
+ Next level
+
+
+ Creating slides library with Angular
+
+
+
What's an ideal API for a presentation?
+
+
+
+
+
Can we use ng-template?
+
+
+
+
+
Can we use ng-template?
+
+
+
+
+
+ Highlights
+
+
+
+
How to implement this?
+
+
+
+
+
We need a popup which
+
+ plays well with Monaco
+ Updates when the code is updated
+ Not obstructive
+
+
+
+
+
We don't. We use highlight instead
+
+
+
+
We don't. We use highlight instead
+
+
+
+
+
Find position by regex or string
+
+
+
+
+
Add classes using Monaco's deltaDecorations
+
+
+
+
+ Storing code samples
+
+
This can't be hard!
+
+
+
+
Can we use multiline strings?
+
+
+
+
Custom interpolation to the rescue?
+
+
+
+
+
Can we use ng-template?
+
+
+
+
Can we use ngNonBindable?
+
+
+
+
Can we use Script tag?
+
+
+
+
Can we use Textarea?
+
+
+
+
Textarea + ngNonBindable
+
+
+
+
+
Code in the component
+
+
+
+
+
raw-loader - code in files
+
+
+
+
+
+
+ Can we use figure out the types now?
+
+
+
+
Let's fake it!
+
+
+
+
+
+
Then webstorm started shouting at me.
+
+
+
+
Let's fake it!
+
+
+
+
+
+
+
+
So we kinda ready for prime time, except nothing really works
+
+
+
+
+
People will probably get really mad?
+
+
+
+
+
Let's add feedback feature
+
+
+
+
We use firebase
+
+
+
+
+
+ We want the feedback to be as specific as possible, so we need to identify
+ the slide
+
+
+
+
+
+
We Already use routing, and each slide has a #
+
+
+
+
+
We can't generate and ID
+
+
+
+
We have to give an ID manually
+
+
+
+
+
TADA
+
+
+
+
+
+
+ i18n
+
+
+
We use standard Angular i18n
+
+
+
+
But how can we translate code samples?
+
+
+
+
+ Have strings in template with ids
+ Then query it in the Component
+
+ {{ "@ViewChild('translations', { static: true }) translation;" }}
+
+
+
+
+ How to we translate it in a way that scales?
+
+
+
+
Codelab uses PoEditor
+
+
+
+
+
Thanks PoEditor for providing us with an Open Source license!
+
+
+
+ Anybody can help with translation
+ - Already translated into Russian
+
+
+
+ Let's make it faster
+
+ - изначальные проблемы:
+ очень долго пересобиралось, потому что пересоздавался iframe
+
+ типы задавались вручную, поэтому было проблемно подключать дополнительные
+ библиотеки
+
+ - что сделано:
+ iframe стал переиспользоваться
+ инстанс ts compiler был переведен на watch режим
+ реализован bundler, который собирает типы в один файл
+ оптимизация бандла с пакетами, чтобы все сжималось
+ - что получили:
+
+ перезапуск вместо 0.5-1 сек стало почти мгновенно (показать демонстрацию)
+
+ размер бандла уменьшился в 2 раза (todo: посмотреть размер)
+
+ появилась возможность подключать любые библиотеки на этапе компиляции
+
+ Running tests (mocha / babel + traversing AST)
+
+ - The goal is to quickly assess whether user's code does what we want.
+
+
+ - Initially the plan was to run unit tests in an iframe with TestBed, mocha
+ + chai (code TBD)
+
+ - Phase 2 - We started reusing iframe (code TBD)
+ - Special case testing bootstrapping the app (code TBD)
+
+ - We also added babel tests (babel can parse TypeScript) (code TBD)
+
+ - This works, we look at the code, not at the result.
+ Monaco
+
+ - The goal is to give users a type aware editor with SyntaxHighlighting
+ quick, extensible
+
+ - We chose monaco
+
+ - Bundle size/It's own AMD loader/Have to be included in the assets
+
+ - Adding types to monaco
+ - Highlighting
+ - Autofolding
+ - Init on app load
+ Experiments/What's next?
+ Sync lib
+ - Codelab is not just an angular course it is a platform
+ - Demo
+ New runner
+ - What we want:
+ - Generic runner (not just angular)
+
+ - Does not need types/libraries bundled (fetched them asynchronously from
+ cdn)
+
+ - Where we are?
+ - We don't know how to
+ How/Why to contribute?
+ Is is hard?
+ How to start
+ Why to contribute?
+ What's next?
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/about/about.component.scss b/codelab-master/apps/codelab/src/app/codelabs/about/about.component.scss
new file mode 100644
index 000000000..5b77e2453
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/about/about.component.scss
@@ -0,0 +1,101 @@
+.screenshot {
+ /*background: url("images/sss");*/
+}
+
+[cover] ::ng-deep {
+ line-height: 100vh;
+ text-align: center;
+ background: #6cae00;
+ color: white;
+ font-size: 100px;
+ font-weight: 300;
+}
+
+[text] ::ng-deep {
+ line-height: 100vh;
+ text-align: center;
+ background: #6cae00;
+ color: white;
+ font-size: 100px;
+ font-weight: 300;
+}
+
+[pic] {
+ background-size: contain;
+ background-repeat: no-repeat;
+ width: 100%;
+ height: 100%;
+}
+
+[pic-label] ::ng-deep {
+ line-height: 20vh;
+ text-align: center;
+ color: black;
+ font-size: 100px;
+ font-weight: 280;
+}
+
+.types-error {
+ background-image: url('./images/types-error.png');
+}
+
+.types-missing {
+ background-image: url('./images/types-missing.png');
+}
+
+.types-work {
+ background-image: url('./images/types-work.png');
+}
+
+.i18n-poeditor {
+ background-image: url('./images/i18n-poeditor.png');
+}
+
+.highlight-slides {
+ background-image: url('./images/highlight-slides.png');
+}
+
+.img-todo {
+ content: 'lol';
+ border: 50px white dotted;
+ margin-top: 20px;
+ background: #d68200;
+ box-sizing: border-box;
+
+ &:before {
+ line-height: 100%;
+ font-size: 200px;
+ content: 'IMAGE-TBD';
+ padding: 100px 0;
+ text-align: center;
+ display: block;
+ color: white;
+ }
+}
+h2 {
+ padding: 20px;
+}
+
+.no-setup {
+ background-image: url('./images/no-setup.png');
+}
+
+.examples {
+ background-image: url('./images/examples.gif');
+}
+
+.exercises {
+ background-image: url('./images/exercises.gif');
+}
+
+.github {
+ background-image: url('./images/github.png');
+}
+
+.issues {
+ background-image: url('./images/issues.gif');
+}
+
+.community {
+ background-image: url('./images/codelab.jpeg');
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/about/about.component.spec.ts b/codelab-master/apps/codelab/src/app/codelabs/about/about.component.spec.ts
new file mode 100644
index 000000000..063616a61
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/about/about.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { AboutComponent } from './about.component';
+
+describe('AboutComponent', () => {
+ let component: AboutComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [AboutComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(AboutComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/codelab/src/app/codelabs/about/about.component.ts b/codelab-master/apps/codelab/src/app/codelabs/about/about.component.ts
new file mode 100644
index 000000000..f4731b7d4
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/about/about.component.ts
@@ -0,0 +1,34 @@
+import { Component, OnInit } from '@angular/core';
+
+declare const require;
+
+@Component({
+ selector: 'about',
+ templateUrl: './about.component.html',
+ styleUrls: ['./about.component.scss']
+})
+export class AboutComponent implements OnInit {
+ code = {
+ fakeTypes: require('!!raw-loader!./samples/fake-types.d.ts.not-really'),
+ slides: {
+ template: require('!!raw-loader!./samples/slides/ng-template.html'),
+ component: require('!!raw-loader!./samples/slides/slide-component.html'),
+ directive: require('!!raw-loader!./samples/slides/structural-directive.html')
+ },
+ storingCode: {
+ plain: require('!!raw-loader!./samples/storing-code/plain.html'),
+ backticks: require('!!raw-loader!./samples/storing-code/backticks.html'),
+ backticksMatch: [/{{`/, /`}}/],
+ interpolation: {
+ 'bootstrap.ts': require('!!raw-loader!./samples/storing-code/interpolations.ts')
+ }
+ },
+ highlights: {
+ find: require('!!raw-loader!@codelab/code-demos/src/lib/code-demo-editor/utils/utils')
+ }
+ };
+
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/about/about.module.ts b/codelab-master/apps/codelab/src/app/codelabs/about/about.module.ts
new file mode 100644
index 000000000..9982deb89
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/about/about.module.ts
@@ -0,0 +1,15 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { RouterModule } from '@angular/router';
+import { FormsModule } from '@angular/forms';
+import { CodeDemoModule } from '@codelab/code-demos';
+import { SlidesModule, SlidesRoutes } from '@ng360/slides';
+import { AboutComponent } from './about.component';
+
+const routes = RouterModule.forChild(SlidesRoutes.get(AboutComponent));
+
+@NgModule({
+ declarations: [AboutComponent],
+ imports: [CommonModule, SlidesModule, routes, CodeDemoModule, FormsModule]
+})
+export class AboutModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/about/images/codelab.jpeg b/codelab-master/apps/codelab/src/app/codelabs/about/images/codelab.jpeg
new file mode 100644
index 000000000..11f4356db
Binary files /dev/null and b/codelab-master/apps/codelab/src/app/codelabs/about/images/codelab.jpeg differ
diff --git a/codelab-master/apps/codelab/src/app/codelabs/about/images/comments.gif b/codelab-master/apps/codelab/src/app/codelabs/about/images/comments.gif
new file mode 100644
index 000000000..da9c3e229
Binary files /dev/null and b/codelab-master/apps/codelab/src/app/codelabs/about/images/comments.gif differ
diff --git a/codelab-master/apps/codelab/src/app/codelabs/about/images/examples.gif b/codelab-master/apps/codelab/src/app/codelabs/about/images/examples.gif
new file mode 100644
index 000000000..47fe6ac18
Binary files /dev/null and b/codelab-master/apps/codelab/src/app/codelabs/about/images/examples.gif differ
diff --git a/codelab-master/apps/codelab/src/app/codelabs/about/images/exercises.gif b/codelab-master/apps/codelab/src/app/codelabs/about/images/exercises.gif
new file mode 100644
index 000000000..7ed2e52ba
Binary files /dev/null and b/codelab-master/apps/codelab/src/app/codelabs/about/images/exercises.gif differ
diff --git a/codelab-master/apps/codelab/src/app/codelabs/about/images/github.png b/codelab-master/apps/codelab/src/app/codelabs/about/images/github.png
new file mode 100644
index 000000000..38892f591
Binary files /dev/null and b/codelab-master/apps/codelab/src/app/codelabs/about/images/github.png differ
diff --git a/codelab-master/apps/codelab/src/app/codelabs/about/images/highlight-slides.png b/codelab-master/apps/codelab/src/app/codelabs/about/images/highlight-slides.png
new file mode 100644
index 000000000..864531a67
Binary files /dev/null and b/codelab-master/apps/codelab/src/app/codelabs/about/images/highlight-slides.png differ
diff --git a/codelab-master/apps/codelab/src/app/codelabs/about/images/i18n-poeditor.png b/codelab-master/apps/codelab/src/app/codelabs/about/images/i18n-poeditor.png
new file mode 100644
index 000000000..3aa421bac
Binary files /dev/null and b/codelab-master/apps/codelab/src/app/codelabs/about/images/i18n-poeditor.png differ
diff --git a/codelab-master/apps/codelab/src/app/codelabs/about/images/issues.gif b/codelab-master/apps/codelab/src/app/codelabs/about/images/issues.gif
new file mode 100644
index 000000000..18b88cc32
Binary files /dev/null and b/codelab-master/apps/codelab/src/app/codelabs/about/images/issues.gif differ
diff --git a/codelab-master/apps/codelab/src/app/codelabs/about/images/no-setup.png b/codelab-master/apps/codelab/src/app/codelabs/about/images/no-setup.png
new file mode 100644
index 000000000..319cf6411
Binary files /dev/null and b/codelab-master/apps/codelab/src/app/codelabs/about/images/no-setup.png differ
diff --git a/codelab-master/apps/codelab/src/app/codelabs/about/images/types-error.png b/codelab-master/apps/codelab/src/app/codelabs/about/images/types-error.png
new file mode 100644
index 000000000..9c8077b88
Binary files /dev/null and b/codelab-master/apps/codelab/src/app/codelabs/about/images/types-error.png differ
diff --git a/codelab-master/apps/codelab/src/app/codelabs/about/images/types-missing.png b/codelab-master/apps/codelab/src/app/codelabs/about/images/types-missing.png
new file mode 100644
index 000000000..4f5a6242b
Binary files /dev/null and b/codelab-master/apps/codelab/src/app/codelabs/about/images/types-missing.png differ
diff --git a/codelab-master/apps/codelab/src/app/codelabs/about/images/types-work.png b/codelab-master/apps/codelab/src/app/codelabs/about/images/types-work.png
new file mode 100644
index 000000000..379109b9c
Binary files /dev/null and b/codelab-master/apps/codelab/src/app/codelabs/about/images/types-work.png differ
diff --git a/codelab-master/apps/codelab/src/app/codelabs/about/samples/fake-types.d.ts.not-really b/codelab-master/apps/codelab/src/app/codelabs/about/samples/fake-types.d.ts.not-really
new file mode 100644
index 000000000..bd829ea92
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/about/samples/fake-types.d.ts.not-really
@@ -0,0 +1,146 @@
+interface RouteConfig {
+ path: string;
+ component: any;
+}
+
+declare module '@angular/core' {
+ export class EventEmitter {
+ emit: (param: T) => void;
+ }
+
+ export interface DirectiveConfig {
+ selector: string;
+ }
+
+ export interface ComponentConfig {
+ selector: string;
+ template?: string;
+ templateUrl?: string;
+ }
+
+ export interface PipeConfig {
+ name: string;
+ }
+
+ export function enableProdMode();
+
+ export function Component(config: ComponentConfig);
+
+ export function Directive(config: DirectiveConfig);
+
+ export class TemplateRef {
+ }
+
+ export class ViewContainerRef {
+ clear: () => void;
+ createEmbeddedView: (ref: TemplateRef, context: any) => void;
+ }
+
+ export interface AfterViewInit {
+ ngAfterViewInit: () => void;
+ }
+
+ export interface OnInit {
+ ngOnInit: () => void;
+ }
+
+ export interface NgModuleConfig {
+ imports?: any[];
+ declarations?: any[];
+ providers?: any[];
+ bootstrap?: any[];
+ exports?: any[];
+ }
+
+ export function NgModule(config: NgModuleConfig);
+
+ export function Injectable();
+
+ export function Output();
+
+ export function Input();
+
+ export interface OnChanges {
+ ngOnChanges: (simpleChanges: SimpleChange[]) => void;
+ }
+
+ export interface SimpleChange {
+ [key: string]: any;
+ }
+
+ export function Pipe(config: PipeConfig);
+
+ export interface PipeTransform {
+ transform(value: string);
+ }
+}
+
+declare module '@angular/forms' {
+ export class FormsModule {
+ }
+}
+declare module '@angular/platform-browser' {
+ export class BrowserModule {
+ }
+}
+
+declare module '@angular/platform-browser/animations' {
+ export class NoopAnimationsModule {
+ }
+}
+declare module '@angular/platform-browser-dynamic' {
+ export class Platform {
+ bootstrapModule: (module: any, config?: any) => void;
+ }
+
+ export function platformBrowserDynamic(): Platform;
+}
+
+declare module '@angular/compiler' {
+ export class ResourceLoader {
+ }
+}
+
+declare class Observable {
+ subscribe: (T) => void;
+}
+
+declare module '@angular/router' {
+ export type Routes = Array;
+
+ export class RouterModule {
+ static forRoot: (routes: Routes) => any;
+ }
+}
+
+declare module '@angular/common' {
+ export class NgIf {
+ constructor(v: any, t: any);
+ }
+}
+
+declare module '@angular/material' {
+ export class MatTab {
+ position: number;
+ }
+
+ export class MatTabGroup {
+ selectedIndex: number;
+ selectChange: Observable;
+ }
+
+ export class MatInputModule {
+ }
+
+ export class MatTabsModule {
+ }
+
+ export class MatToolbarModule {
+ }
+
+ export class MatCardModule {
+ }
+
+ export class MatButtonModule {
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/about/samples/slides/ng-template.html b/codelab-master/apps/codelab/src/app/codelabs/about/samples/slides/ng-template.html
new file mode 100644
index 000000000..ac97206a2
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/about/samples/slides/ng-template.html
@@ -0,0 +1,11 @@
+
+
+ Awesome slide
+
+
+ Code sample
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/about/samples/slides/slide-component.html b/codelab-master/apps/codelab/src/app/codelabs/about/samples/slides/slide-component.html
new file mode 100644
index 000000000..a3ef823ca
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/about/samples/slides/slide-component.html
@@ -0,0 +1,11 @@
+
+
+ Awesome slide
+
+
+ Code sample
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/about/samples/slides/structural-directive.html b/codelab-master/apps/codelab/src/app/codelabs/about/samples/slides/structural-directive.html
new file mode 100644
index 000000000..1cfbd9f6f
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/about/samples/slides/structural-directive.html
@@ -0,0 +1,11 @@
+
+
+
Awesome slide
+
+
+
Code sample
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/about/samples/storing-code/backticks.html b/codelab-master/apps/codelab/src/app/codelabs/about/samples/storing-code/backticks.html
new file mode 100644
index 000000000..cc57e7b58
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/about/samples/storing-code/backticks.html
@@ -0,0 +1,9 @@
+
+
+ {{` import { Component } from '@angular/core'; @Component({ selector:
+ 'hello-world', template: `
+ Hello I'm an Angular app!
+ Very soon you will learn how to create and bootstrap me!
+ ` }) export class AppComponent {} `}}
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/about/samples/storing-code/interpolations.ts b/codelab-master/apps/codelab/src/app/codelabs/about/samples/storing-code/interpolations.ts
new file mode 100644
index 000000000..819ef6357
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/about/samples/storing-code/interpolations.ts
@@ -0,0 +1,23 @@
+import { Component, NgModule } from '@angular/core';
+import { BrowserModule } from '@angular/platform-browser';
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+
+@Component({
+ selector: 'app-root',
+ template: `
+ 🐶 1 + 2 🦊
+ `,
+ interpolation: ['🐶', '🦊']
+})
+export class AppComponent {}
+
+@NgModule({
+ imports: [BrowserModule],
+ declarations: [AppComponent],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}
+
+platformBrowserDynamic()
+ .bootstrapModule(AppModule)
+ .catch(err => console.error(err));
diff --git a/codelab-master/apps/codelab/src/app/codelabs/about/samples/storing-code/plain.html b/codelab-master/apps/codelab/src/app/codelabs/about/samples/storing-code/plain.html
new file mode 100644
index 000000000..56f62aa14
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/about/samples/storing-code/plain.html
@@ -0,0 +1,9 @@
+
+
+ import { Component } from '@angular/core'; @Component({ selector:
+ 'hello-world', template: `
+ Hello I'm an Angular app!
+ Very soon you will learn how to create and bootstrap me!
+ ` }) export class AppComponent {}
+
+
diff --git a/libs/console/src/lib/display-dynamic.component/display-dynamic-component.component.css b/codelab-master/apps/codelab/src/app/codelabs/angular/angular-cli/angular-cli.component.css
similarity index 100%
rename from libs/console/src/lib/display-dynamic.component/display-dynamic-component.component.css
rename to codelab-master/apps/codelab/src/app/codelabs/angular/angular-cli/angular-cli.component.css
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/angular-cli/angular-cli.component.html b/codelab-master/apps/codelab/src/app/codelabs/angular/angular-cli/angular-cli.component.html
new file mode 100644
index 000000000..e2e15d39e
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/angular-cli/angular-cli.component.html
@@ -0,0 +1,197 @@
+
+
+
+
+
+
+
+
+
+
+
Intro
+
+ Angular CLI is a command line tool that can be used to quickly get up to
+ speed with running your Angular app.
+
+
+
+ $ ng hello
+
+ Hi, I'm angular-cli , I'm a command line tool!
+
+ It may sound scary, but I'm really easy to use!
+
+
+
+
+
+
node
+
Before you start, make sure you have node.js on your machine.
+
Open terminal and type in: node -v
+
+
+ If there is an error, follow the
+ NodeJS setup instructions
+
+
+ If the output is a number, you're good, move to the next slide.
+
+
+
+ $ node -v v6.11.3
+
+
+
+
+
installing
+
+ Run npm install -g @angular/cli
to install
+ Angular cli on your machine
+
+
+
+ $ sudo npm install -g @angular/cli
+ … A bunch of output omitted for brevety …
+ │ ├─┬ strip-ansi@3.0.1
+ │ │ └── ansi-regex@2.1.1
+ │ ├─┬ supports-color@3.2.3
+ │ │ └── has-flag@1.0.0
+ │ └─┬ yargs@6.6.0
+ │ ├── camelcase@3.0.0
+ │ ├── os-locale@1.4.0
+ │ ├─┬ string-width@1.0.2
+ │ │ ├── code-point-at@1.1.0
+ │ │ └─┬ is-fullwidth-code-point@1.0.0
+ │ │ └── number-is-nan@1.0.1
+ │ ├── which-module@1.0.0
+ │ └── yargs-parser@4.2.1
+ ├── webpack-merge@4.1.0
+ ├── webpack-sources@1.0.1
+ └── zone.js@0.8.18
+
+
+
+
+
+
Creating new Angular app
+
+ To create a new Angular app run:
+ ng new awesome-app
, then cd awesome-app
+
+
+
+ $ ng new awesome-app
+
+ create awesome-app/README.md (1026 bytes)
+ create awesome-app/.angular-cli.json (1288 bytes)
+ create awesome-app/.editorconfig (245 bytes)
+ … A bunch of output omitted for brevety …
+ create awesome-app/src/app/app.component.spec.ts (986 bytes)
+ create awesome-app/src/app/app.component.ts (207 bytes)
+
+ Installing packages for tooling via npm.
+ Installed packages for tooling via npm.
+ Successfully initialized git.
+ Project 'awesome-app' successfully created.
+
+
+
+
+
+
+
Starting the app
+
+ Once you're in the app folder, start the app with ng serve
+
+
>
+
+ $ ng serve
+ ** NG Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ **
+ Date: 2017-10-22T03:25:09.430Z - Hash: 6af162d0da3cc77873d4
+ Time: 6417ms
+ chunk {{'{'}}inline{{'}'}} inline.bundle.js, inline.bundle.js.map (inline) 5.83 kB [entry] [rendered]
+ chunk {{'{'}}main{{'}'}} main.bundle.js, main.bundle.js.map (main) 8.63 kB {{'{'}}vendor{{'}'}} [initial]
+ [rendered]
+ chunk {{'{'}}polyfills{{'}'}} polyfills.bundle.js, polyfills.bundle.js.map (polyfills) 199 kB {{'{'}}inline{{'}'}}
+ [initial] [rendered]
+ chunk {{'{'}}styles{{'}'}} styles.bundle.js, styles.bundle.js.map (styles) 11.3 kB {{'{'}}inline{{'}'}} [initial]
+ [rendered]
+ chunk {{'{'}}vendor{{'}'}} vendor.bundle.js, vendor.bundle.js.map (vendor) 2.32 MB [initial] [rendered]
+
+ webpack: Compiled successfully.
+
+
+
+
+
+ Once the app is started just open
+ http://localhost:4200/ in your
+ browser
+
+
+
+
+
Generating components
+
+ You can easily generate new components
+ ng generate component my-component
+
+
+ $ ng generate component my-component
+ create src/app/my-component/my-component.component.css (0 bytes)
+ create src/app/my-component/my-component.component.html (31 bytes)
+ create src/app/my-component/my-component.component.spec.ts (664 bytes)
+ create src/app/my-component/my-component.component.ts (292 bytes)
+ update src/app/app.module.ts (418 bytes)
+
+
+
+
You can also generate modules, services and pipes
+
+ You can use a shorter version: ng g c my-component
+
+
+
+
+
+
+
+
+ This is the end of the codelab, but it's just the beginning of
+ your Angular journey. Below are some links that can help you continue
+ learning.
+
+
+
+ Angular.io —
+ Find features, docs and events listed here
+
+
+ Angular CLI
+
+ makes it easy to create an application that already works, right
+ out of the box and generate new components! It also takes care of
+ the build system for you
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/angular-cli/angular-cli.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/angular-cli/angular-cli.component.ts
new file mode 100644
index 000000000..ac3904811
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/angular-cli/angular-cli.component.ts
@@ -0,0 +1,11 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'codelab-slides-angular-cli',
+ templateUrl: './angular-cli.component.html',
+ styleUrls: [
+ '../../../components/css/codelab-styles.scss',
+ './angular-cli.component.css'
+ ]
+})
+export class AngularCliComponent {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/angular-cli/angular-cli.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/angular-cli/angular-cli.module.ts
new file mode 100644
index 000000000..b5b0ab118
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/angular-cli/angular-cli.module.ts
@@ -0,0 +1,29 @@
+import { AngularCliComponent } from './angular-cli.component';
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { FeedbackModule } from '@codelab/feedback';
+import { CommonModule } from '@angular/common';
+import { BrowserWindowModule } from '@codelab/browser';
+import { CodelabComponentsModule } from '../../../components/codelab-components.module';
+import { FormsModule } from '@angular/forms';
+import { ExternalLinkDirectiveDirective } from '../../../components/external-link-directive/external-link-directive.directive';
+import { SlidesModule, SlidesRoutes } from '@ng360/slides';
+
+const routes = RouterModule.forChild([
+ ...SlidesRoutes.get(AngularCliComponent)
+]);
+
+@NgModule({
+ imports: [
+ routes,
+ FeedbackModule,
+ CommonModule,
+ BrowserWindowModule,
+ CodelabComponentsModule,
+ SlidesModule,
+ FormsModule
+ ],
+ declarations: [AngularCliComponent, ExternalLinkDirectiveDirective],
+ exports: [AngularCliComponent]
+})
+export class AngularCliModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/angular-routing.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/angular-routing.module.ts
new file mode 100644
index 000000000..abf90017f
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/angular-routing.module.ts
@@ -0,0 +1,181 @@
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { AngularRoutesComponent } from '../../components/angular-routes/angular-routes.component';
+import { FullLayoutComponent } from '../../containers/full-layout';
+import { environment } from '../../../environments/environment';
+import { MENU_ROUTES, MenuRoutes } from '../../common';
+
+const routes: MenuRoutes = [
+ {
+ path: '',
+ component: FullLayoutComponent,
+ children: [
+ {
+ path: '',
+ component: AngularRoutesComponent
+ },
+ {
+ path: 'intro',
+ loadChildren: () => import('@codelab/intro').then(m => m.IntroModule),
+ name: 'Introduction',
+ description: `Learn more about Angular`,
+ page: 'main',
+ prod: true
+ },
+ {
+ path: 'typescript',
+ loadChildren: () =>
+ import('./typescript/typescript.module').then(
+ m => m.TypeScriptModule
+ ),
+ name: 'TypeScript',
+ description:
+ 'Angular is written in TypeScript, a superset of JavaScript. Learn TypeScript',
+ page: 'typescript',
+ prod: true
+ },
+ {
+ path: 'create-first-app',
+ loadChildren: () =>
+ import('./create-first-app/create-first-app.module').then(
+ m => m.CreateFirstAppModule
+ ),
+ name: 'Create your first Angular app',
+ description:
+ 'Learn how to create and bootstrap your first Angular application',
+ page: 'main',
+ prod: true,
+ translationIds: ['createFirstNgApp', 'learnHowToBootstrapApp']
+ },
+ {
+ path: 'templates',
+ loadChildren: () =>
+ import('./templates/templates.module').then(m => m.TemplatesModule),
+ name: 'Templates',
+ description: 'Learn how to use Angular templates',
+ page: 'main',
+ prod: true,
+ translationIds: ['templates', 'learnUsingTemplates']
+ },
+ {
+ path: 'dependency-injection',
+ loadChildren: () =>
+ import('./dependency-injection/dependency-injection.module').then(
+ m => m.DependencyInjectionModule
+ ),
+ name: 'Dependency-Injection',
+ description:
+ 'Learn how to provide dependencies to your code instead of hard-coding them',
+ page: 'main',
+ prod: true,
+ translationIds: ['dependencyInjection', 'learnToProvideDependencies']
+ },
+ {
+ path: 'component-tree',
+ loadChildren: () =>
+ import('./component-tree/component-tree.module').then(
+ m => m.ComponentTreeModule
+ ),
+ name: 'Component-Tree',
+ description: 'Learn how to structure your app with reusable components',
+ page: 'main',
+ prod: true,
+ translationIds: [
+ 'componentTree',
+ 'learnToStructureAppWithReusableComponents'
+ ]
+ },
+ // {
+ // path: 'custom-events',
+ // loadChildren: './custom-events/custom-events.module#CustomEventsModule',
+ // name: 'Custom-Events (work in progress)',
+ // description: 'Learn to bind to events.',
+ // page: 'bonus',
+ // translationIds: ['customEvents', 'learnToBindToEvents']
+ // },
+ {
+ path: 'router',
+ loadChildren: () =>
+ import('./router/router.module').then(m => m.RouterCodelabModule),
+ name: 'Angular Router',
+ description: 'Learn how to add routes to your Angular application',
+ page: 'main',
+ prod: true
+ },
+ {
+ path: 'material',
+ loadChildren: () =>
+ import('./material/material.module').then(
+ m => m.MaterialCodelabModule
+ ),
+ name: 'Angular Material',
+ description: 'Learn how to use Angular Material',
+ page: 'main',
+ prod: true
+ },
+ {
+ path: 'forms',
+ loadChildren: () =>
+ import('./forms/forms.module').then(m => m.FormsCodelabModule),
+ name: 'Forms',
+ description: 'Learn how to add Forms to your app',
+ page: 'main',
+ prod: true
+ },
+ {
+ path: 'angular-cli',
+ loadChildren: () =>
+ import('./angular-cli/angular-cli.module').then(
+ m => m.AngularCliModule
+ ),
+ name: 'Angular-cli',
+ description: 'Learn how to quickly start working with angular',
+ page: 'main',
+ prod: true
+ },
+ {
+ path: 'pipes',
+ loadChildren: () =>
+ import('./pipes/pipes.module').then(m => m.PipesModule),
+ name: 'Pipes',
+ description:
+ 'Learn how pipes transform input values to output values for display in a view',
+ page: 'bonus',
+ prod: false
+ },
+ {
+ path: 'structural-directives',
+ loadChildren: () =>
+ import('./structural-directives/structural-directives.module').then(
+ m => m.StructuralDirectivesModule
+ ),
+ name: 'Structural Directives',
+ description: 'Learn about structural directives in angular',
+ page: 'bonus',
+ prod: true
+ },
+ {
+ path: 'playground',
+ loadChildren: () =>
+ import('./playground/playground.module').then(
+ m => m.PlaygroundModule
+ ),
+ page: 'bonus',
+ prod: true
+ }
+ ]
+ }
+];
+
+const isProd = environment.production;
+export const menuRoutes = routes[0].children
+ .filter(x => x.page === 'main')
+ // Hide non-prod routes in prod
+ .filter(x => !isProd || x.prod);
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule],
+ providers: [{ provide: MENU_ROUTES, useValue: menuRoutes }]
+})
+export class AngularRoutingModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/angular.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/angular.module.ts
new file mode 100644
index 000000000..2a1403745
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/angular.module.ts
@@ -0,0 +1,9 @@
+import { NgModule } from '@angular/core';
+import { AngularRoutingModule } from './angular-routing.module';
+import { FullLayoutModule } from '../../containers/full-layout/full-layout.module';
+import { AngularRoutesModule } from '../../components/angular-routes/angular-routes.module';
+
+@NgModule({
+ imports: [AngularRoutingModule, FullLayoutModule, AngularRoutesModule]
+})
+export class AngularModule {}
diff --git a/libs/console/src/lib/display-dynamic.component/display-dynamic-component.component.html b/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/component-tree.component.css
similarity index 100%
rename from libs/console/src/lib/display-dynamic.component/display-dynamic-component.component.html
rename to codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/component-tree.component.css
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/component-tree.component.html b/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/component-tree.component.html
new file mode 100644
index 000000000..899cba331
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/component-tree.component.html
@@ -0,0 +1,282 @@
+
+
+ video/video.component.ts: Add the '@Component' decorator and set its
+ selector property to 'my-video'.
+
+
+ app.module.ts: Add VideoComponent to the AppModule 'declarations'.
+
+
+
+ video/video.component.ts: Set the templateUrl to load the appropriate html
+ file
+
+
+ video/video.component.ts: Add a video property and decorate it with @Input()
+
+
+ video/video.component.html: Display the video title
+
+
+ video/video.component.html: Display the video thumbnail (src)
+
+
+ video/video.component.html: Display the video description
+
+
+ video/video.component.html: Display the video date
+
+
+ video/video.component.html: Display the number of video views
+
+
+ video/video.component.html: Display the number video likes
+
+
+ app.html: Replace existing title and thumbnail with our shiny new my-video
+ component
+
+
+ app.html: Use the data binding to pass the video object to the component
+ (don't forget the square brackets)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Component Tree
+
+ So far we have only one component, but as your app grows it will form a
+ tree of components
+
+
+
+
+
+
+
Parent and Child
+
+ Any component can render another one by using an HTML element that matches
+ the selector of the other component
+
+
+
+
+
+
+
+
+
+
Passing Data from Parent to Child
+
+ Parent component passes its data to the child component via properties
+
+
+ Change the size to 100 and color to red to
+ recreate the Japanese flag.
+
+
+
+
+
+
+
Passing Data from Parent to Child
+
+ The child class must decorate its properties with a special
+ @Input() decorator
+
+
+
+ This is the first time we're applying decorators to properties (as opposed
+ to classes).
+
+
+
+
+
Exercise 1
+
+ We already know how to create a component. Let's move all the
+ video-related information into a new component called VideoComponent.
+
+
+ We will bootstrap the component for you; the result will be as follows:
+
+
+
+
Cute kitten
+
+
Date 2016-11-25
+
Views 100
+
Likes 49329
+
Description todo
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parent and Child component
+
+ Components won't know about each other unless they're declared in the same
+ module
+
+
+
+
+
+
+
+ Exercise 2
+
In the next exercise you will use the newly created component
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Milestone Completed
+
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/component-tree.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/component-tree.component.ts
new file mode 100644
index 000000000..edd8eca2e
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/component-tree.component.ts
@@ -0,0 +1,115 @@
+import { AfterViewInit, Component, ViewChild } from '@angular/core';
+import {
+ ExerciseConfigTemplate,
+ Ng2TsExercises,
+ SlideTemplate
+} from '../../../../../../../ng2ts/ng2ts';
+
+import { extractMessages } from '@codelab/utils/src/lib/i18n/i18n-tools';
+import { boxAndCircle, circleAndBox } from '../../../shared/helpers/helpers';
+
+const circleAndBoxCode = circleAndBox();
+declare const require;
+
+@Component({
+ selector: 'codelab-slides-component-tree',
+ templateUrl: './component-tree.component.html',
+ styleUrls: [
+ '../../../components/css/codelab-styles.scss',
+ './component-tree.component.css'
+ ]
+})
+export class ComponentTreeComponent implements AfterViewInit {
+ t: { [key: string]: string };
+
+ @ViewChild('translations', { static: false }) translation;
+
+ exercise: ExerciseConfigTemplate | SlideTemplate;
+ exercise2: ExerciseConfigTemplate | SlideTemplate;
+ title = 'Component Tree';
+ description = '';
+ prereqs = '';
+
+ code = {
+ parentComponentSkeleton: {
+ match: /slides-circle/,
+ code: `import { Component } from '@angular/core';
+
+@Component({
+ selector: 'slides-hello',
+ template: \`Hello \`
+})
+export class HelloComponent {}
+`,
+ path: 'parent.component.ts',
+ type: 'typescript'
+ },
+ childComponentSkeleton: {
+ code: `import { Component } from '@angular/core';
+
+@Component({
+ selector: 'slides-world',
+ template: 'World '
+})
+export class WorldComponent {}
+`,
+ path: 'child.component.ts',
+ type: 'typescript'
+ },
+ appModule: {
+ code: {
+ 'app.module.ts': require('!!raw-loader!./samples/module/app.module.ts'),
+ 'circle.component.ts': require('!!raw-loader!./samples/module/circle.component.ts'),
+ 'box.component.ts': require('!!raw-loader!./samples/module/box.component.ts'),
+ 'bootstrap.ts': require('!!raw-loader!./../../../shared/angular-code/bootstrap.ts'),
+ 'index.html': require('!!raw-loader!./samples/module/index.html')
+ },
+ files: ['app.module.ts'],
+ highlights: { 'app.module.ts': /declarations.*/ }
+ },
+ parentComponent: {
+ code: `import { Component } from '@angular/core';
+import { Result } from './result.model';
+
+@Component({
+ selector: 'parent',
+ template: '
+ '
+})
+export class Parent {
+ results(): Result[] {...}
+}`,
+ path: 'parent.component.ts',
+ type: 'typescript'
+ },
+ childComponent: {
+ code: `import { Component, Input } from '@angular/core';
+import { Result } from './result.model';
+
+@Component({
+ selector: 'child',
+ template: '{{result}}
'
+})
+export class Child {
+ @Input() data: Result[];
+}`,
+ path: 'child.component.ts',
+ type: 'typescript'
+ },
+
+ boxAndCircle: boxAndCircle(),
+ circleAndBox: circleAndBoxCode,
+ passingDataToChildHighlights: {
+ 'circle.component.ts': [/@Input\(\) size/, /@Input\(\) color/]
+ }
+ };
+
+ constructor(private exercises: Ng2TsExercises) {
+ this.exercise = exercises.getExercises(4, 1);
+ this.exercise2 = exercises.getExercises(4, 2);
+ }
+
+ ngAfterViewInit() {
+ this.t = extractMessages(this.translation);
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/component-tree.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/component-tree.module.ts
new file mode 100644
index 000000000..fd9876520
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/component-tree.module.ts
@@ -0,0 +1,31 @@
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { FormsModule } from '@angular/forms';
+import { SlidesModule, SlidesRoutes } from '@ng360/slides';
+import { CodeDemoModule } from '@codelab/code-demos';
+import { FeedbackModule } from '@codelab/feedback';
+import { BrowserWindowModule } from '@codelab/browser';
+import { ComponentTreeComponent } from './component-tree.component';
+import { ComponentsHierarchySvgComponent } from './components-hierarchy-svg';
+import { Ng2TsExercises } from '../../../../../../../ng2ts/ng2ts';
+import { CodelabComponentsModule } from '../../../components/codelab-components.module';
+
+const routes = RouterModule.forChild([
+ ...SlidesRoutes.get(ComponentTreeComponent)
+]);
+
+@NgModule({
+ imports: [
+ routes,
+ BrowserWindowModule,
+ CodeDemoModule,
+ FeedbackModule,
+ CodelabComponentsModule,
+ SlidesModule,
+ FormsModule
+ ],
+ providers: [Ng2TsExercises],
+ declarations: [ComponentTreeComponent, ComponentsHierarchySvgComponent],
+ exports: [ComponentTreeComponent]
+})
+export class ComponentTreeModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/components-hierarchy-svg/components-hierarchy-svg.component.html b/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/components-hierarchy-svg/components-hierarchy-svg.component.html
new file mode 100644
index 000000000..809f5908c
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/components-hierarchy-svg/components-hierarchy-svg.component.html
@@ -0,0 +1,134 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Child
+ Child
+ Child
+
+ Parent
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/components-hierarchy-svg/components-hierarchy-svg.component.spec.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/components-hierarchy-svg/components-hierarchy-svg.component.spec.ts
new file mode 100644
index 000000000..01b078bc1
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/components-hierarchy-svg/components-hierarchy-svg.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ComponentsHierarchySvgComponent } from './components-hierarchy-svg.component';
+
+describe('ComponentsHierarchySvgComponent', () => {
+ let component: ComponentsHierarchySvgComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ComponentsHierarchySvgComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ComponentsHierarchySvgComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/components-hierarchy-svg/components-hierarchy-svg.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/components-hierarchy-svg/components-hierarchy-svg.component.ts
new file mode 100644
index 000000000..c35125568
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/components-hierarchy-svg/components-hierarchy-svg.component.ts
@@ -0,0 +1,8 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+
+@Component({
+ selector: 'codelab-components-hierarchy-svg',
+ templateUrl: './components-hierarchy-svg.component.html',
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class ComponentsHierarchySvgComponent {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/components-hierarchy-svg/index.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/components-hierarchy-svg/index.ts
new file mode 100644
index 000000000..b96f5ef4b
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/components-hierarchy-svg/index.ts
@@ -0,0 +1 @@
+export * from './components-hierarchy-svg.component';
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/samples/module/app.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/samples/module/app.module.ts
new file mode 100644
index 000000000..ec9353cb0
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/samples/module/app.module.ts
@@ -0,0 +1,11 @@
+import { NgModule } from '@angular/core';
+import { BrowserModule } from '@angular/platform-browser';
+import { BoxComponent } from './box.component';
+import { CircleComponent } from './circle.component';
+
+@NgModule({
+ imports: [BrowserModule],
+ declarations: [BoxComponent, CircleComponent],
+ bootstrap: [BoxComponent]
+})
+export class AppModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/samples/module/box.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/samples/module/box.component.ts
new file mode 100644
index 000000000..35d3c8310
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/samples/module/box.component.ts
@@ -0,0 +1,13 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'my-app',
+ template: `
+
+
+
+ `
+})
+export class BoxComponent {
+ circleColor = 'green';
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/samples/module/circle.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/samples/module/circle.component.ts
new file mode 100644
index 000000000..c670862b2
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/samples/module/circle.component.ts
@@ -0,0 +1,11 @@
+import { Component, Input } from '@angular/core';
+
+@Component({
+ selector: 'slides-circle',
+ template:
+ '
'
+})
+export class CircleComponent {
+ @Input() size: number;
+ @Input() color: string;
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/samples/module/index.html b/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/samples/module/index.html
new file mode 100644
index 000000000..1ca8c6f04
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/component-tree/samples/module/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Loading...
+
+
diff --git a/libs/utils/src/lib/sandbox-runner/typescript-checker-runner/typescript-checker-runner.component.css b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/create-first-app.component.css
similarity index 100%
rename from libs/utils/src/lib/sandbox-runner/typescript-checker-runner/typescript-checker-runner.component.css
rename to codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/create-first-app.component.css
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/create-first-app.component.html b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/create-first-app.component.html
new file mode 100644
index 000000000..f436bb307
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/create-first-app.component.html
@@ -0,0 +1,512 @@
+
+
+ @Component is an Angular decorator
+
+
+ No semicolon here (as it attaches itself to the class below
+
+
+ The Decorator goes directly above the decorated entity (class in this case)
+
+
+ Component name is the class name (AppComponent).
+
+
+ Create a class called 'AppComponent'
+
+
+ Create a class called 'AppModule'
+
+
+ All set! Bootstrap your application
+
+
+
Export the class
+
+ Add a Component decorator for the class
+
+
+ Add a selector to the component decorator and set it to 'my-app'
+
+
+ Add a template that contains: h1 with a text "Hello MewTube!"
+
+
+ Add a NgModule decorator for the class
+
+
+ Add 'BrowserModule' to the NgModule decorator imports
+
+
+ Add 'AppComponent' to the 'declarations' property of the decorator
+
+
+ Add 'AppComponent' to the 'bootstrap' property of the decorator
+
+
+
+
+
+
+
+
+
+
+
+
+
What is Angular?
+
+
+ Angular is a development platform for building mobile and desktop
+ applications. Angular lets you extend HTML's syntax to express
+ your application's components clearly and succinctly. Angular's binding
+ and Dependency Injection eliminate much of the code you would
+ otherwise have to write.
+
+
+
+
+
+
+ Intro
+
Given an HTML file:
+
+
+ Let's create an Angular app which replaces the hello-world HTML
+ element with the app's contents.
+
+ This can be done with 3 simple steps.
+
+
+
+
+
Intro
+
The 3 steps are:
+
+ Create an Angular component
+ Create an Angular module
+ Bootstrap the module
+
+
+
+
+
+ Step 1
+
+ Start by creating an Angular Component . Components in Angular are
+ responsible for the visual part of the app
+
+
+
+ An Angular component is just a class. Properties and behavior can be added
+ inside.
+
+
+
+
+
+
Decorators
+
+
+
+
The class is adorned with a @Component decorator
+
+ Decorators attach Angular specific information to the class.
+
+
+
+
+
+
Decorators
+
+ Decorators are a new feature of TypeScript. They attach metadata to a
+ class, function, property or variable
+
+
+
+
+ TypeScript decorators are inspired by a similar feature in the Python
+ language.
+
+
+
+
+
+ Selector
+
+ Selectors define the location of the component. When Angular renders this
+ component, it'll find a hello-world HTML element in the document
+ and render the component inside of it
+
+
+
+
+
+
+
+
Inline Template
+
Template defines the HTML code that the component generates
+
+
+
+ If the amount of HTML grows out of hand, it's possible (and recommended)
+ to use a templateUrl instead and provide a path to the HTML file.
+
+
+
+
+
+ Exercise
+
+ In the next slide you'll create your first Angular component! We'll
+ do all the wiring for you. The result will look like this:
+
+
+
+
+
+
+
+
+ Create first Angular component!
+
+
+
+
+
+
Step 2
+
Next step is to declare the component in an NgModule .
+
+ NgModule does not have any visual representation and is used
+ exclusively for grouping Angular building blocks together
+
+
+ We will learn more about NgModules in the future milestones
+
+
+
+
+
+ Module Class
+
Like a component, Angular module is just a class
+
+
+
+
+
+
+ NgModule Decorator
+
+ Like a component, Angular module is adorned with a decorator
+ providing metadata
+
+
+
+
+
+
+
+ Browser Module
+
+
+
+
+
+ Declarations
+
+ The declarations array specifies components belonging to the
+ AppModule
+
+
+
+
+
+
+ Bootstrap
+
+ The component passed into the bootstrap array will be created and
+ displayed in your index.html file
+
+
+
+
+
+
+ Exercise
+
+ In the next slide you'll create your first Angular module! We'll
+ use the component from the previous exercises and do all the wiring for
+ you. The result will look like this:
+
+
+
+
+
+
+
+
+
+
Bootstrapping
+
+ We have everything ready, so now it's time to start (bootstrap) the app!
+
+
+ Passing your AppModule to the bootstrapModule method will
+ start up all the components from that module's bootstrap section
+
+
+
+ For most simple apps, you can just copy/paste the code above "as is"
+
+
+
+
+
Bootstrapping 1
+
How does bootstrapping work in Angular?
+
+
+ 1. Kicks off execution environment. platformBrowserDynamic() tells
+ Angular that we are operating in the browser
+
+
+
+
+
+
+
+
Bootstrapping 2
+
+ 2. Angular initializes the component from the bootstrap array in
+ app.module.ts (HelloWorldComponent in this case)
+
+
+
+
+
+
+
+
Bootstrapping 3
+
+ 3. Angular looks in the document for an element matching the selector
+ defined in HelloWorldComponent ('hello-world' in our case)
+ and inserts the component inside that element
+
+
+
+
+
+
+
+ Exercise
+
+ All set! In the next page you'll bootstrap your first Angular app!
+
+
+
+
+
+
+
+
+
+ Now that we've got both NgModule and the component ready, let's
+ bootstrap the app!
+
+
+
+
+
+
+
+
+
Review
+
Loading order: index -> main -> app.module -> app.component
+
+
+
+
+
+ While Angular is loading, the contents of the element will stay the same
+ (Loading... ) in this case
+
+
+
+
+
+
+
+
Well done! This is the end of the milestone!
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/create-first-app.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/create-first-app.component.ts
new file mode 100644
index 000000000..9ec58100f
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/create-first-app.component.ts
@@ -0,0 +1,128 @@
+import { Component, OnInit, ViewChild } from '@angular/core';
+
+import { ng2tsConfig } from '../../../../../../../ng2ts/ng2ts';
+import { extractMessages } from '@codelab/utils/src/lib/i18n/i18n-tools';
+
+declare const require;
+
+@Component({
+ selector: 'codelab-slides-create-first-app',
+ templateUrl: './create-first-app.component.html',
+ styleUrls: [
+ '../../../components/css/codelab-styles.scss',
+ './create-first-app.component.css'
+ ]
+})
+export class CreateFirstAppComponent implements OnInit {
+ t: { [key: string]: string };
+
+ // TODO(kirjs): we can't access tanslation in OnInit hook iwht static set to false
+ // need to consider changing how we set code
+ @ViewChild('translations', { static: true }) translation;
+ // Exercises
+ exercises = [
+ ng2tsConfig.milestones[1].exercises[1],
+ ng2tsConfig.milestones[1].exercises[2],
+ ng2tsConfig.milestones[1].exercises[3],
+ {
+ name: 'Create a component',
+ description: 'Create first Angular component!
',
+ files: [
+ {
+ bootstrap: false,
+ excludeFromTesting: false,
+ type: 'typescript',
+ path: 'app.component.ts',
+ template: `import {Component} from '@angular/core';\n\n`,
+ moduleName: 'app.component',
+ code: `import { Component } from '@angular/core';
+
+@Component({
+ selector: 'my-app',
+ template: 'Hello MewTube! ',
+})
+export class AppComponent {
+}
+`,
+ solution: `import { Component } from '@angular/core';\n\n@Component({\n selector: 'my-app',\n
+ template: 'Hello MewTube! ',\n})\nexport class AppComponent {\n}\n`,
+ after: 'export function evalJs( js ){ return eval(js);}'
+ },
+ {
+ bootstrap: false,
+ excludeFromTesting: false,
+ type: 'typescript',
+ path: 'app.module.ts',
+ template: `import { BrowserWindowModule } from '@angular/platform-browser';\nimport { NgModule } from '@angular/core';\n
+ import { AppComponent } from './app.component';\n\n@NgModule({\n imports: [BrowserWindowModule],\n declarations: [AppComponent],
+ \n bootstrap: [AppComponent]\n})\nexport class AppModule {\n}\n`,
+ moduleName: 'app.module',
+ code: `import { BrowserWindowModule } from '@angular/platform-browser';\nimport {NgModule} from '@angular/core';\n
+ import { AppComponent } from './app.component';\n\n@NgModule({\n imports: [BrowserWindowModule],\n declarations: [AppComponent],
+ \n bootstrap: [AppComponent]\n})\nexport class AppModule {\n}\n`,
+ readonly: true,
+ collapsed: true
+ },
+ {
+ bootstrap: true,
+ excludeFromTesting: true,
+ type: 'typescript',
+ path: 'main.ts',
+ template: `import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';\nimport {AppModule} from './app.module';\n\n
+ const platform = platformBrowserDynamic();\nplatform.bootstrapModule(AppModule);\n`,
+ moduleName: 'main',
+ code: `import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';\nimport {AppModule} from './app.module';\n\n
+ const platform = platformBrowserDynamic();\nplatform.bootstrapModule(AppModule);\n`,
+ readonly: true,
+ collapsed: true
+ }
+ ]
+ }
+ ];
+
+ // tslint:disable:max-line-length TODO: Clean up exercises and remove this comment.
+ private code: any = {};
+
+ // tslint:enable:max-line-length
+
+ ngOnInit() {
+ this.t = extractMessages(this.translation);
+
+ this.code = {
+ indexHtml: {
+ 'index.html': require('!!raw-loader!./samples/index-html/index.html'),
+ 'bootstrap.ts': require('!!raw-loader!./samples/index-html/bootstrap.ts')
+ },
+ angularApp: {
+ 'index.html': require('!!raw-loader!./samples/app-component/index.html'),
+ 'bootstrap.ts': require('!!raw-loader!./samples/app-component/bootstrap.ts'),
+ 'app.component.ts': require('!!raw-loader!./samples/app-component/app.component.ts'),
+ 'app.module.ts': require('!!raw-loader!./samples/app-component/app.module.ts')
+ },
+ indexHtmlMatches: { 'index.html': // },
+ helloMatches: { 'app.component.ts': /hello-world/ },
+ componentMatches: { 'app.component.ts': /export.*/ },
+ decoratorsMatches: { 'app.component.ts': /@C[^]*?\)[^]/ },
+ selectorMatches: { 'app.component.ts': /selector.*'.*'/ },
+ templateMatches: { 'app.component.ts': /template: `[^]*?`[^]/ },
+ exportMatches: { 'app.module.ts': /export.*/ },
+ ngModuleMatches: { 'app.module.ts': /@N[^]*?\)[^]/ },
+ declarationsMatches: { 'app.module.ts': /declarations.*/ },
+ bootstrapMatches: { 'app.module.ts': /bootstrap.*/ },
+ bootstrapPlatformMatches: {
+ 'bootstrap.ts': /platformBrowserDynamic\(\).*/
+ },
+ decorators: {
+ code: `import {Component} from '@angular/core';
+// ${this.t.componentIsDecorator}
+@Component({
+ // metadata
+}) // ${this.t.noSemicolon}
+export class AppComponent {
+ // ${this.t.decoratorGoesAboveEntity}
+ // ${this.t.componentNameIsClassName}
+}`
+ }
+ };
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/create-first-app.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/create-first-app.module.ts
new file mode 100644
index 000000000..9833b1325
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/create-first-app.module.ts
@@ -0,0 +1,32 @@
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { FeedbackModule } from '@codelab/feedback';
+import { CommonModule } from '@angular/common';
+import { BrowserWindowModule } from '@codelab/browser';
+import { CodeDemoModule } from '@codelab/code-demos';
+import { FormsModule } from '@angular/forms';
+import { SlidesModule, SlidesRoutes } from '@ng360/slides';
+import { CodelabComponentsModule } from '../../../components/codelab-components.module';
+import { ModeComponent } from './mode/mode.component';
+import { CreateFirstAppComponent } from './create-first-app.component';
+
+const routes = RouterModule.forChild([
+ ...SlidesRoutes.get(CreateFirstAppComponent)
+]);
+
+@NgModule({
+ imports: [
+ routes,
+ FeedbackModule,
+ CommonModule,
+ CodeDemoModule,
+ BrowserWindowModule,
+ CodelabComponentsModule,
+ CodeDemoModule,
+ SlidesModule,
+ FormsModule
+ ],
+ declarations: [CreateFirstAppComponent, ModeComponent],
+ exports: [CreateFirstAppComponent]
+})
+export class CreateFirstAppModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/mode/mode.component.css b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/mode/mode.component.css
new file mode 100644
index 000000000..41bfec4ae
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/mode/mode.component.css
@@ -0,0 +1,46 @@
+.mode {
+ background-size: cover;
+ cursor: pointer;
+ background-repeat: no-repeat;
+ width: 60px;
+ height: 40px;
+ padding: 5px;
+ margin-right: 10px;
+ filter: grayscale(100%);
+}
+
+.mode.mode-current {
+ filter: none;
+}
+
+.mode:hover {
+ border-bottom: 5px solid gray;
+}
+
+.mode-web {
+ background-image: url(./pics/browsericon.png);
+}
+
+.mode-mobile {
+ background-image: url(./pics/phoneicon.png);
+}
+
+.mode-vr {
+ background-image: url(./pics/vricon.png);
+}
+
+.angular {
+ width: 100px;
+}
+
+.module-options {
+ display: flex;
+}
+
+.box-row {
+ display: flex;
+}
+
+.box-row-fill {
+ width: 50vw;
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/mode/mode.component.html b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/mode/mode.component.html
new file mode 100644
index 000000000..648df0149
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/mode/mode.component.html
@@ -0,0 +1,70 @@
+
+
+ Because we're building a browser web app, we need to pass
+ BrowserModule to the imports array
+
+
+
+
+
+
+
+
+ Hello World
+
+
+
+
+
+
+
+
With Angular we build mobile apps using NativeScript or Ionic.
+
+
+
+
+
+
+
+
+
With Angular you can build VR apps with A-FRAME or WEBGL.
+
+
+
+
+
+
+
+
+
+
+ Angular is not just for web apps anymore; you can also use it to create
+ native phone apps and even VR scenes.
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/mode/mode.component.spec.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/mode/mode.component.spec.ts
new file mode 100644
index 000000000..b4a31eca0
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/mode/mode.component.spec.ts
@@ -0,0 +1,22 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { NO_ERRORS_SCHEMA } from '@angular/core';
+import { ModeComponent } from './mode.component';
+
+describe('ModeComponent', () => {
+ let component: ModeComponent;
+ let fixture: ComponentFixture;
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ schemas: [NO_ERRORS_SCHEMA],
+ declarations: [ModeComponent]
+ });
+ fixture = TestBed.createComponent(ModeComponent);
+ component = fixture.componentInstance;
+ });
+ it('can load instance', () => {
+ expect(component).toBeTruthy();
+ });
+ it(`modes defaults to: ['web', 'mobile', 'vr']`, () => {
+ expect(component.modes).toEqual(['web', 'mobile', 'vr']);
+ });
+});
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/mode/mode.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/mode/mode.component.ts
new file mode 100644
index 000000000..d2389b298
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/mode/mode.component.ts
@@ -0,0 +1,52 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'codelab-slides-ng-module-mode',
+ templateUrl: './mode.component.html',
+ styleUrls: ['./mode.component.css']
+})
+export class ModeComponent implements OnInit {
+ modes = ['web', 'mobile', 'vr'];
+ mode = this.modes[0];
+ code = {
+ moduleAnatomy: {
+ // Module Anatomy - Milestone #1
+ code: `/* Imports */
+
+@NgModule({
+ imports: [ BrowserModule ],
+ declarations: [ HelloWorldComponent ],
+ bootstrap: [ HelloWorldComponent ],
+})
+export class AppModule {}`,
+ codeMobile: `/* Imports */
+
+@NgModule({
+ imports: [ NativeScriptModule ],
+ declarations: [ HelloWorldComponent ],
+ bootstrap: [ HelloWorldComponent ],
+})
+export class AppModule {}`,
+ codeVR: `/* Imports */
+
+@NgModule({
+ imports: [ SomeMagicVRModule ],
+ declarations: [ HelloWorldComponent ],
+ bootstrap: [ HelloWorldComponent ],
+})
+export class AppModule {}`,
+ matches: {
+ exportClass: /export.*/,
+ ngModule: /@N[^]*?\)[^]/,
+ importsArr: /imports.*/
+ },
+ readonly: true,
+ path: 'module.anatomy.ts',
+ type: 'typescript'
+ }
+ };
+
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/mode/pics/browsericon.png b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/mode/pics/browsericon.png
new file mode 100644
index 000000000..26d3ff2ae
Binary files /dev/null and b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/mode/pics/browsericon.png differ
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/mode/pics/phoneicon.png b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/mode/pics/phoneicon.png
new file mode 100644
index 000000000..b5b6350f1
Binary files /dev/null and b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/mode/pics/phoneicon.png differ
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/mode/pics/vricon.png b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/mode/pics/vricon.png
new file mode 100644
index 000000000..45453645e
Binary files /dev/null and b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/mode/pics/vricon.png differ
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/samples/app-component/app.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/samples/app-component/app.component.ts
new file mode 100644
index 000000000..fab01d4c7
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/samples/app-component/app.component.ts
@@ -0,0 +1,10 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'hello-world',
+ template: `
+ Hello I'm an Angular app!
+ Very soon you will learn how to create and bootstrap me!
+ `
+})
+export class AppComponent {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/samples/app-component/app.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/samples/app-component/app.module.ts
new file mode 100644
index 000000000..02260c17c
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/samples/app-component/app.module.ts
@@ -0,0 +1,10 @@
+import { NgModule } from '@angular/core';
+import { BrowserModule } from '@angular/platform-browser';
+import { AppComponent } from './app.component';
+
+@NgModule({
+ imports: [BrowserModule],
+ declarations: [AppComponent],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/samples/app-component/bootstrap.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/samples/app-component/bootstrap.ts
new file mode 100644
index 000000000..2470c9595
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/samples/app-component/bootstrap.ts
@@ -0,0 +1,4 @@
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+import { AppModule } from './app.module';
+
+platformBrowserDynamic().bootstrapModule(AppModule);
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/samples/app-component/index.html b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/samples/app-component/index.html
new file mode 100644
index 000000000..c9d305ae1
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/samples/app-component/index.html
@@ -0,0 +1,10 @@
+
+
+
+ Loading...
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/samples/index-html/bootstrap.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/samples/index-html/bootstrap.ts
new file mode 100644
index 000000000..aa06ef41d
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/samples/index-html/bootstrap.ts
@@ -0,0 +1,22 @@
+import { Component, NgModule } from '@angular/core';
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+import { BrowserModule } from '@angular/platform-browser';
+
+@Component({
+ // tslint:disable-next-line:component-selector
+ selector: 'hello-world',
+ template: `
+ Hello I'm an Angular app!
+ Very soon you will learn how to create and bootstrap me!
+ `
+})
+export class AppComponent {}
+
+@NgModule({
+ imports: [BrowserModule],
+ declarations: [AppComponent],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}
+
+platformBrowserDynamic().bootstrapModule(AppModule);
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/samples/index-html/index.html b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/samples/index-html/index.html
new file mode 100644
index 000000000..c9d305ae1
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/create-first-app/samples/index-html/index.html
@@ -0,0 +1,10 @@
+
+
+
+ Loading...
+
+
+
+
+
diff --git a/libs/utils/src/lib/sandbox-runner/typescript-test-runner/typescript-test-runner.component.css b/codelab-master/apps/codelab/src/app/codelabs/angular/custom-events/custom-events.component.css
similarity index 100%
rename from libs/utils/src/lib/sandbox-runner/typescript-test-runner/typescript-test-runner.component.css
rename to codelab-master/apps/codelab/src/app/codelabs/angular/custom-events/custom-events.component.css
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/custom-events/custom-events.component.html b/codelab-master/apps/codelab/src/app/codelabs/angular/custom-events/custom-events.component.html
new file mode 100644
index 000000000..a3e3f1994
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/custom-events/custom-events.component.html
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
Custom Events / Intro
+
+ In this milestone, you will learn to use @Output() to communicate from
+ child to parent component and handle custom events.
+
+
+
+
+
+
Custom Events / Passing data from child to parent
+
+
+
+
+
+
+ To 'listen' to a child's event, we bind to the child's event
+ childDidSomething.
+
+
+
+
+
+
+ To let the parent know that there is an event. We emit an event from
+ the child.
+
+
+
+
+
+
+
+
Custom Events / Exercise - Intro
+
+ Let's implement a ThumbsUp and ThumbsDown button for the VideoComponent
+ you worked on before.
+
+
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/custom-events/custom-events.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/custom-events/custom-events.component.ts
new file mode 100644
index 000000000..843fc65cc
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/custom-events/custom-events.component.ts
@@ -0,0 +1,63 @@
+import { Component } from '@angular/core';
+import { ng2tsConfig } from '../../../../../../../ng2ts/ng2ts';
+
+@Component({
+ selector: 'codelab-slides-custom-events',
+ templateUrl: './custom-events.component.html',
+ styleUrls: ['./custom-events.component.css']
+})
+export class CustomEventsComponent {
+ code = {
+ exercise1a: {
+ // parent
+ code: `
+ import { Component } from '@angular/core';
+
+ @Component({
+ selector: 'parent',
+ template: \`
+
+ \`
+ })
+ export class ParentComponent {
+ parentDoSomething() {
+ console.log('child did something');
+ }
+ }
+ `,
+ path: 'test.ts',
+ type: 'typescript',
+ match: /childDidSomething/
+ },
+ exercise1b: {
+ // child
+ code: `
+ import { Component } from '@angular/core';
+
+ @Component({
+ selector: 'child',
+ template: \`
+
+ \`
+ })
+ export class ChildComponent {
+ @Output() childDidSomething = new EventEmitter();
+
+ buttonClicked() {
+ this.childDidSomething.emit();
+ }
+ }
+ `,
+ path: 'test.ts',
+ type: 'typescript',
+ match: ``
+ }
+ };
+
+ exercises = [ng2tsConfig.milestones[5].exercises[1]];
+
+ // constructor(private exercises: Ng2TsExercises) {
+ // // this.exercise = exercises.getExercises(4, 1);
+ // // this.exercise2 = exercises.getExercises(4, 2);
+ // }
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/custom-events/custom-events.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/custom-events/custom-events.module.ts
new file mode 100644
index 000000000..50c785e67
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/custom-events/custom-events.module.ts
@@ -0,0 +1,30 @@
+import { CustomEventsComponent } from './custom-events.component';
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { FeedbackModule } from '@codelab/feedback';
+import { CommonModule } from '@angular/common';
+import { BrowserWindowModule } from '@codelab/browser';
+import { CodelabComponentsModule } from '../../../components/codelab-components.module';
+import { FormsModule } from '@angular/forms';
+import { CodeDemoModule } from '@codelab/code-demos';
+import { SlidesModule, SlidesRoutes } from '@ng360/slides';
+
+const routes = RouterModule.forChild([
+ ...SlidesRoutes.get(CustomEventsComponent)
+]);
+
+@NgModule({
+ imports: [
+ routes,
+ FeedbackModule,
+ CommonModule,
+ BrowserWindowModule,
+ CodeDemoModule,
+ CodelabComponentsModule,
+ SlidesModule,
+ FormsModule
+ ],
+ declarations: [CustomEventsComponent],
+ exports: [CustomEventsComponent]
+})
+export class CustomEventsModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/dependency-injection/dependency-injection.component.css b/codelab-master/apps/codelab/src/app/codelabs/angular/dependency-injection/dependency-injection.component.css
new file mode 100644
index 000000000..2ad211544
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/dependency-injection/dependency-injection.component.css
@@ -0,0 +1,33 @@
+.content-container {
+ display: flex;
+ flex-direction: row;
+ width: 100%;
+ margin-top: 20px;
+}
+
+.center-preview {
+ margin: 0 auto;
+}
+
+.mewtube-preview {
+ height: 100%;
+ padding: 2vw;
+ overflow: auto;
+}
+
+.comparision {
+ padding: 0.5em;
+}
+
+.diagram-container {
+ height: 500px;
+ width: 100%;
+ max-width: 800px;
+ margin: 2rem auto 0;
+}
+.di-diagram {
+ height: 100%;
+ width: 100%;
+ background: url(./pics/deps.svg) no-repeat;
+ background-size: contain;
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/dependency-injection/dependency-injection.component.html b/codelab-master/apps/codelab/src/app/codelabs/angular/dependency-injection/dependency-injection.component.html
new file mode 100644
index 000000000..af9ddc5e5
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/dependency-injection/dependency-injection.component.html
@@ -0,0 +1,320 @@
+
+
+ * TypeScript shorthand makes 'profession' * available to component instance.
+
+
+ assuming Job has property '.title'
+
+
+ video.service.ts: Add @Injectable() decorator to the class
+
+
+
+ app.module.ts: Add VideoService to the NgModule providers property
+
+
+ app.component.ts: Get rid of FAKE_VIDEOS
+
+
+ app.component.ts: Inject 'VideoService' in the component constructor as
+ 'videoService'
+
+
+ app.component.ts: Update the app component's search method to use
+ videoService's search method
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Example of a dependency
+
+ We display a list of hard-coded videos in our component, but in the real
+ world we'd load them from the server.
+
+
+ The code for fetching the data would live in a separate class (service)
+ called VideoService
+
+
Therefore our component will depend on the VideoService:
+
+
+
+ AppComponent
+
+
+
+ VideoService
+
+
+
+
+
+
+
+
Intro
+
+
+ As our app grows, number of dependencies will increase. Dependencies, in
+ order, will have their own dependencies. Managing all of them manually
+ becomes increasingly harder.
+
+
+ To simplify that Angular provides a mechanism called
+ Dependency injection
+
+
+
+
+
+
+
Comparison
+
+
+
+
+
+ Without Dependency Injection, Profession has to be instantiated
+ in the Person class
+
+
+
+
+
+
+ With Dependency Injection, Person class just "requires" an
+ instance of Job in the constructor, and Angular takes care of
+ instantiating it
+
+
+
+
+
+
+
Parameters
+
+
+
+
+
+ Without Dependency Injection, you have to figure out all the
+ parameters yourself
+
+
+
+
+
+
+ With Dependency Injection, Angular takes care of it
+
+
+
+
+
+
+
Testing
+
+ Also Dependency Injection simplifies testing a lot, because you can just
+ pass mock dependencies as constructor parameters
+
+
+
+
+
+
+
Example
+
+ Let's say we have an existing UnitConverterService and we want to
+ start using it in UnitConversionComponent . It will take 3 simple
+ steps:
+
+
+ Mark dependency as @Injectable()
+ Provide in the module
+ Require in the component
+
+
+
+
+
+
Step 1
+
+ Mark the class as @Injectable() . This lets Angular know that this
+ class is part of Angular Dependency Injection system
+
+
+
+
+ If a service class is marked as injectable, it can require other services
+ in its constructor.
+
+
+
+
+
+
Step 2
+
+ Provide the injectable to the providers section of NgModule
+
+
+
+
+ Now, this service becomes available for every Component and other
+ service in this NgModule .
+
+
+
+
+
+
Step 3
+
Consume the Injectable in the component
+
+
+
+ Because of the private access modifier the service becomes
+ accessible across the class as this.converter .
+
+
+
+
+ Exercise
+
+ In the next slide you'll use videoService which has even more cats!!! The
+ result will look like this:
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/dependency-injection/dependency-injection.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/dependency-injection/dependency-injection.component.ts
new file mode 100644
index 000000000..9255bc8d6
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/dependency-injection/dependency-injection.component.ts
@@ -0,0 +1,129 @@
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { Ng2TsExercises } from '../../../../../../../ng2ts/ng2ts';
+import { extractMessages } from '@codelab/utils/src/lib/i18n/i18n-tools';
+
+@Component({
+ selector: 'codelab-slides-dependency-injection',
+ templateUrl: './dependency-injection.component.html',
+ styleUrls: ['./dependency-injection.component.css']
+})
+export class DependencyInjectionComponent implements OnInit {
+ t: { [key: string]: string };
+ exercise;
+
+ // TODO(kirjs): we can't access tanslation in OnInit hook iwht static set to false
+ // need to consider changing how we set code
+ @ViewChild('translations', { static: true }) translation;
+ code = {};
+
+ constructor(private exercises: Ng2TsExercises) {
+ this.exercise = exercises.getExercises(3, 1);
+ }
+
+ ngOnInit() {
+ this.t = extractMessages(this.translation);
+
+ this.code = {
+ withOutDI: {
+ code: `export class Person {
+ profession: Job;
+
+ constructor() {
+ this.profession = new Job();
+ }
+}`,
+ code2: `import {ProfessionsEnum} from './professions';
+
+export class Person {
+ profession: Job;
+
+ constructor() {
+ const Schedule = new Schedule(ProfessionsEnum.ENGINEER);
+ this.profession = new Job(ProfessionsEnum.ENGINEER, Schedule, /* TODO: Find how to inject salary*/);
+ }
+}`,
+
+ matches: {
+ noDI: /this.*/
+ },
+ readonly: true,
+ path: 'person-noDI.ts',
+ type: 'typescript'
+ },
+
+ withDI: {
+ code: `export class Person {
+ /**
+ ${this.t.shorthandMakesProfessionAvailable}
+ */
+ constructor(public profession: Job) {}
+}`,
+ matches: {
+ constructor: /constructor.*/
+ },
+ readonly: true,
+ path: 'personDI.ts',
+ type: 'typescript'
+ },
+ withDITesting: {
+ code: `const mockProfession = new Job('lawyer');
+it('should create a Person with the right profession', () => {
+ const person = new Person(mockProfession);
+ // ${this.t.assumingJobHasPropTitle}
+ expect(person.profession.title).toEqual('lawyer');
+});
+`,
+ matches: {
+ constructor: /constructor.*/
+ },
+ readonly: true,
+ path: 'personDI.spec.ts',
+ type: 'typescript'
+ },
+
+ classAsInjectable: {
+ code: `import { Injectable } from '@angular/core';
+
+@Injectable()
+export class UnitConverterService {
+ // ...
+}`,
+ matches: {
+ injectable: /@I[^]*?\)[^]/
+ },
+ readonly: true,
+ type: 'typescript'
+ },
+
+ provideInjectable: {
+ code: `import { NgModule } from '@angular/core';
+import { UnitConverterService } from '../services/unit-converter.service';
+import { UnitConversionComponent } from './unit-conversion.component';
+
+@NgModule({
+ declarations: [ UnitConversionComponent ],
+ providers: [ UnitConverterService ]
+})
+export class AppModule {}`,
+ matches: {
+ providers: /providers.*/
+ },
+ readonly: true,
+ type: 'typescript'
+ },
+
+ consumeInjectable: {
+ code: `import { Component } from '@angular/core';
+import { UnitConverterService } from '../services/unit-converter.service';
+
+@Component({...})
+export class UnitConversionComponent {
+ constructor(private converter: UnitConverterService) {}
+}`,
+ matches: {
+ constructor: /constructor.*/
+ }
+ }
+ };
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/dependency-injection/dependency-injection.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/dependency-injection/dependency-injection.module.ts
new file mode 100644
index 000000000..753eb529c
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/dependency-injection/dependency-injection.module.ts
@@ -0,0 +1,30 @@
+import { NgModule } from '@angular/core';
+import { DependencyInjectionComponent } from './dependency-injection.component';
+import { RouterModule } from '@angular/router';
+import { FormsModule } from '@angular/forms';
+import { SlidesModule, SlidesRoutes } from '@ng360/slides';
+import { FeedbackModule } from '@codelab/feedback';
+import { BrowserWindowModule } from '@codelab/browser';
+import { CodeDemoModule } from '@codelab/code-demos';
+import { CodelabComponentsModule } from '../../../components/codelab-components.module';
+import { Ng2TsExercises } from '../../../../../../../ng2ts/ng2ts';
+
+const routes = RouterModule.forChild([
+ ...SlidesRoutes.get(DependencyInjectionComponent)
+]);
+
+@NgModule({
+ imports: [
+ routes,
+ FeedbackModule,
+ BrowserWindowModule,
+ CodeDemoModule,
+ CodelabComponentsModule,
+ SlidesModule,
+ FormsModule
+ ],
+ providers: [Ng2TsExercises],
+ declarations: [DependencyInjectionComponent],
+ exports: [DependencyInjectionComponent]
+})
+export class DependencyInjectionModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/dependency-injection/pics/deps.svg b/codelab-master/apps/codelab/src/app/codelabs/angular/dependency-injection/pics/deps.svg
new file mode 100644
index 000000000..51f7a5ab9
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/dependency-injection/pics/deps.svg
@@ -0,0 +1,132 @@
+
+
+
+
+
+
+
+
+
+
+
+ GreatComponent
+
+
+
+
+
+
+
+
+
+
+
+
+ DifferentService
+
+
+
+
+
+
+
+
+
+
+
+
+ CoolService
+
+
+
+
+
+
+
+
+
+
+
+
+ AmazingService
+
+
+
+
+
+
+
+
+
+
+
+
+ AwesomeService
+
+
+
+
+
+
+
+
+
+
+
+
+ AnotherDependency
+
+
+
+
+
diff --git a/libs/utils/src/lib/sync/components/configure-sync/configure-sync.component.css b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/forms.component.css
similarity index 100%
rename from libs/utils/src/lib/sync/components/configure-sync/configure-sync.component.css
rename to codelab-master/apps/codelab/src/app/codelabs/angular/forms/forms.component.css
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/forms/forms.component.html b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/forms.component.html
new file mode 100644
index 000000000..b9183b7d7
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/forms.component.html
@@ -0,0 +1,236 @@
+
+ ¬
+
+ app.module.ts: Add FormsModule and MatInputModule, to the imports.
+
+
+ upload/upload.component.html: Add "title" input bound to the title property
+ of the component
+
+
+ upload/upload.component.html: Add "description" textarea bound to the
+ description property of the component
+
+
+
+
+
+
+
+
+
+
+
+
+ Simple Form
+
+ We have this simple form, let's find out how to map input values with the
+ ones from our Angular component!
+
+
+
+
+
+ Simple Form
+
First we have to add FormsModule to our NgModule.
+
+
+
+
+
+
NgModel
+
+ Now let's use ngModel to bind the inputs to the appropriate fields on the
+ component.
+
+
Try changing the inputs and see the values updated.
+
+
+ [(NgModel)] - Banana in the box is a simple mnemonic for the braces
+ order.
+
+
+
+
+
+
+
+
Validators
+
+ Here's the list of
+ built-in validators
+ that Angular provides out of the box
+
+
+ min
+ max
+ required
+ requiredTrue
+ email
+ minLength
+ maxLength
+ pattern
+
+
+ It's also possible to create custom validators, but it's out of scope for
+ this milestone, you can read more:
+
here
+
+
+
+
+ Error Always Displayed
+
+ There's one small issue though, if we don't have initial values, the error
+ is displayed right away.
+
+
+
+
+
+
+
+
+
+
+
Exercise
+
+ In the next slide there is an exercise. We're going to add a form to the
+ upload page.
+
+
+
+
+ Note: you'd have to manually click on the "upload link" to see the result,
+ we're working on the fix.
+
+
+
+
+
+
+
+
+
+
+
+
+
Well done! This is the end of the milestone!
+
+ There are more than one way to handle forms in Angular. While
+ Advanced forms milestone is in works, check out
+ Angular docs
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/forms/forms.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/forms.component.ts
new file mode 100644
index 000000000..db58b0fc0
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/forms.component.ts
@@ -0,0 +1,132 @@
+import { CodelabFile } from '../../../shared/helpers/codelabFile';
+import { AfterViewInit, Component, ViewChild } from '@angular/core';
+import {
+ ExerciseConfigTemplate,
+ Ng2TsExercises
+} from '../../../../../../../ng2ts/ng2ts';
+import { extractMessages } from '@codelab/utils/src/lib/i18n/i18n-tools';
+
+declare const require;
+
+interface FileHighlights {
+ appModule?: RegExp | RegExp[];
+ appHtml?: RegExp | RegExp[];
+ appComponent?: RegExp | RegExp[];
+}
+
+function formsConfig(code, highlights: FileHighlights = {}) {
+ const files = {
+ appHtml: require('!!raw-loader!./samples/basic/app.1.html'),
+ appModule: require('!!raw-loader!./samples/basic/app.module.ts'),
+ appComponent: require('!!raw-loader!./samples/basic/app.component.ts'),
+ ...code
+ };
+
+ return {
+ files: [
+ CodelabFile.Html('app')
+ .setCode(files.appHtml)
+ .withHighlight(highlights.appHtml),
+
+ CodelabFile.TypeScriptFile('app.module')
+ .setCode(files.appModule)
+ .withHighlight(highlights.appModule),
+
+ CodelabFile.TypeScriptFile('app.component')
+ .setCode(files.appComponent)
+ .withHighlight(highlights.appComponent),
+
+ CodelabFile.TypeScriptFile('bootstrap')
+ .setCode(require('!!raw-loader!./samples/basic/main.ts'))
+ .makeBootstrappable(),
+
+ CodelabFile.Css('styles').setCode(
+ require('!!raw-loader!@angular/material/prebuilt-themes/indigo-pink.css')
+ ),
+
+ CodelabFile.Css('extra').setCode(
+ require('!!raw-loader!./samples/basic/styles.css')
+ )
+ ]
+ };
+}
+
+@Component({
+ selector: 'codelab-slides-forms',
+ templateUrl: './forms.component.html',
+ styleUrls: ['./forms.component.css']
+})
+export class FormsComponent implements AfterViewInit {
+ @ViewChild('translations', { static: false }) translations;
+ exercise: ExerciseConfigTemplate;
+ samples = {
+ basicForm: formsConfig(
+ { appHtml: require('!!raw-loader!./samples/basic/app.1.html') },
+ {
+ appModule: /FormsModule]/
+ }
+ ),
+ ngModel: formsConfig(
+ { appHtml: require('!!raw-loader!./samples/basic/app.2.html') },
+ {
+ appHtml: [/ngModel/g]
+ }
+ ),
+ ngValidation1: formsConfig(
+ { appHtml: require('!!raw-loader!./samples/basic/app.3.html') },
+ {
+ appHtml: [/required/]
+ }
+ ),
+ ngValidation2: formsConfig(
+ { appHtml: require('!!raw-loader!./samples/basic/app.4.html') },
+ {
+ appHtml: [/#usernameModel="ngModel"/, //]
+ }
+ ),
+ touched: formsConfig(
+ {
+ appHtml: require('!!raw-loader!./samples/basic/app.4.html'),
+ appComponent: require('!!raw-loader!./samples/basic/app.component.5.ts')
+ },
+ {
+ appComponent: /username = ''/
+ }
+ ),
+ touched2: formsConfig(
+ {
+ appHtml: require('!!raw-loader!./samples/basic/app.5.html'),
+ appComponent: require('!!raw-loader!./samples/basic/app.component.5.ts')
+ },
+ {
+ appHtml: /(usernameModel.touched \|\| usernameModel.dirty)/
+ }
+ ),
+ ngMaterial: formsConfig(
+ {
+ appHtml: require('!!raw-loader!./samples/basic/app.6.html'),
+ appModule: require('!!raw-loader!./samples/basic/app.module.6.ts').replace(
+ 'component.5',
+ 'component' /*Stupid hack*/
+ )
+ },
+ {
+ appHtml: [
+ /
/,
+ /<\/mat-form-field>/,
+ /matInput/,
+ /.*<\/mat-error>/
+ ]
+ }
+ )
+ };
+ private t: Record;
+
+ constructor(private exercises: Ng2TsExercises) {
+ this.exercise = exercises.getExercises(7, 0);
+ }
+
+ ngAfterViewInit() {
+ this.t = extractMessages(this.translations);
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/forms/forms.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/forms.module.ts
new file mode 100644
index 000000000..cb592eee9
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/forms.module.ts
@@ -0,0 +1,28 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { RouterModule } from '@angular/router';
+import { FormsModule } from '@angular/forms';
+import { SlidesModule, SlidesRoutes } from '@ng360/slides';
+import { FeedbackModule } from '@codelab/feedback';
+import { BrowserWindowModule } from '@codelab/browser';
+import { FormsComponent } from './forms.component';
+import { Ng2TsExercises } from '../../../../../../../ng2ts/ng2ts';
+import { CodelabComponentsModule } from '../../../components/codelab-components.module';
+
+const routes = RouterModule.forChild([...SlidesRoutes.get(FormsComponent)]);
+
+@NgModule({
+ imports: [
+ routes,
+ FeedbackModule,
+ CommonModule,
+ BrowserWindowModule,
+ CodelabComponentsModule,
+ SlidesModule,
+ FormsModule
+ ],
+ declarations: [FormsComponent],
+ exports: [FormsComponent],
+ providers: [Ng2TsExercises]
+})
+export class FormsCodelabModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.1.html b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.1.html
new file mode 100644
index 000000000..d94fa6148
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.1.html
@@ -0,0 +1,8 @@
+
+ *name:
+
+
+
+ email:
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.2.html b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.2.html
new file mode 100644
index 000000000..7b12640bd
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.2.html
@@ -0,0 +1,13 @@
+
+ *name:
+
+
+
+ email:
+
+
+
+
+ Username: {{username}}
+ email: {{email}}
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.3.html b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.3.html
new file mode 100644
index 000000000..04f63fa37
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.3.html
@@ -0,0 +1,13 @@
+
+ *name:
+
+
+
+ email:
+
+
+
+
+ Username: {{username}}
+ email: {{email}}
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.4.html b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.4.html
new file mode 100644
index 000000000..11721cb93
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.4.html
@@ -0,0 +1,16 @@
+
+ *name:
+
+
+ Username is required
+
+
+
+ email:
+
+
+
+
+ Username: {{username}}
+ email: {{email}}
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.5.html b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.5.html
new file mode 100644
index 000000000..ba9f55205
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.5.html
@@ -0,0 +1,17 @@
+
+ *name:
+
+
+ Username is required
+
+
+email:
+
+
+ Username: {{username}}
+ email: {{email}}
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.6.html b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.6.html
new file mode 100644
index 000000000..b288340f2
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.6.html
@@ -0,0 +1,21 @@
+
+
+
+ Username is required
+
+
+
+
+
+
+
+
+ Username: {{username}}
+ email: {{email}}
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.component.5.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.component.5.ts
new file mode 100644
index 000000000..f2e51686d
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.component.5.ts
@@ -0,0 +1,11 @@
+import { Component } from '@angular/core';
+
+/* tslint:disable */
+@Component({
+ selector: 'my-app',
+ templateUrl: './app.html'
+})
+export class AppComponent {
+ username = '';
+ email = 'pirojok@angular.io';
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.component.ts
new file mode 100644
index 000000000..225736b26
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.component.ts
@@ -0,0 +1,11 @@
+import { Component } from '@angular/core';
+
+/* tslint:disable */
+@Component({
+ selector: 'my-app',
+ templateUrl: 'app.html'
+})
+export class AppComponent {
+ username = 'Pirojok';
+ email = 'pirojok@angular.io';
+}
diff --git a/libs/utils/src/lib/sync/components/poll/sync-poll-admin/sync-poll-admin.component.css b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.html
similarity index 100%
rename from libs/utils/src/lib/sync/components/poll/sync-poll-admin/sync-poll-admin.component.css
rename to codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.html
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.module.6.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.module.6.ts
new file mode 100644
index 000000000..42e4dd52c
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.module.6.ts
@@ -0,0 +1,13 @@
+import { BrowserModule } from '@angular/platform-browser';
+import { NgModule } from '@angular/core';
+import { AppComponent } from './app.component.5';
+import { FormsModule } from '@angular/forms';
+import { MatInputModule } from '@angular/material/input';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+
+@NgModule({
+ imports: [BrowserModule, NoopAnimationsModule, MatInputModule, FormsModule],
+ declarations: [AppComponent],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.module.ts
new file mode 100644
index 000000000..d1b8795f3
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/app.module.ts
@@ -0,0 +1,11 @@
+import { BrowserModule } from '@angular/platform-browser';
+import { NgModule } from '@angular/core';
+import { AppComponent } from './app.component';
+import { FormsModule } from '@angular/forms';
+
+@NgModule({
+ imports: [BrowserModule, FormsModule],
+ declarations: [AppComponent],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/code.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/code.ts
new file mode 100644
index 000000000..63c681e0b
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/code.ts
@@ -0,0 +1,2 @@
+// I'm ignored
+export const hi = 'hi';
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/main.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/main.ts
new file mode 100644
index 000000000..fb38f68fb
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/main.ts
@@ -0,0 +1,23 @@
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+import { AppModule } from './app.module';
+import { ResourceLoader } from '@angular/compiler';
+import * as code from './code';
+
+class MyResourceLoader extends ResourceLoader {
+ get(url: string): Promise {
+ const templateId = Object.keys(code).find(key =>
+ key.includes(url.replace(/[\/\.-]/gi, '_'))
+ );
+ const template = code[templateId];
+ if (!template) {
+ console.log(template);
+ // tslint:disable-next-line:no-debugger
+ debugger;
+ }
+ return Promise.resolve(template);
+ }
+}
+
+platformBrowserDynamic().bootstrapModule(AppModule, {
+ providers: [{ provide: ResourceLoader, useClass: MyResourceLoader, deps: [] }]
+} as any);
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/styles.css b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/styles.css
new file mode 100644
index 000000000..f2a00b407
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/forms/samples/basic/styles.css
@@ -0,0 +1,24 @@
+body {
+ padding: 0;
+ margin: 0;
+}
+
+.error {
+ color: red;
+ font-size: 12px;
+ margin-top: 6px;
+}
+
+.field {
+ padding: 10px;
+ border-bottom: 1px #ddd solid;
+ width: 200px;
+}
+
+.field input {
+ float: right;
+}
+
+.values {
+ margin-top: 20px;
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/material/material.component.css b/codelab-master/apps/codelab/src/app/codelabs/angular/material/material.component.css
new file mode 100644
index 000000000..d3db77975
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/material/material.component.css
@@ -0,0 +1,3 @@
+.examples {
+ width: 100%;
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/material/material.component.html b/codelab-master/apps/codelab/src/app/codelabs/angular/material/material.component.html
new file mode 100644
index 000000000..d700acd8d
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/material/material.component.html
@@ -0,0 +1,243 @@
+
+ ¬
+
+ app.module.ts: Add MatCardModule and MatToolbarModule, to the imports.
+
+
+ app.html: Add material toolbar containing the title
+
+
+ video/video.component.html: Use material card to display the data
+
+
+ video/video.component.html: Add mat-card-title (inside of the mat-card) to
+ display video title
+
+
+ video/video.component.html: Add mat-card-subtitle (inside of the mat-card)
+ to display video description
+
+
+ video/video.component.html: Mark img with mat-card-image attribute (inside
+ of the mat-card) so that it takes full card size
+
+
+ video/video.component.html: move date/views/likes info inside of
+ mat-card-content (inside of the mat-card)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Now let's use
+ Angular Material
+ to make our app look beautiful ✨✨
+
+
+ Angular Material provides you with a set of
+ Material Design
+ components for Angular:
+
+
+
+
+ Fast and Consistent
+ Versatile
+ Accessible
+ Optimized for Angular
+ Look great on mobile
+
+
+
+ See the list of components
+ here
+
+
+
+
+
+
+ Card
+
Now let's add material card.
+
+
+
+
+
+
+
+
+
Themes
+
+ All Angular Material components allow to apply themes. Try different
+ themes by clicking the buttons below:
+
+
+
+ Indigo
+
+
+ Deep purple
+
+
+ Pink
+
+
+ Purple
+
+
+
+
+
+
+
+
Exercise
+
+ In the next slide there is an exercise. We're going to materialize our
+ application
+
+
+
+ Note: the final app won't be super beautiful, we're still working on that.
+
+
+
+
+
+
+
+
+
+
+
+
+
Well done! This is the end of the milestone!
+
+ Check out Angular Material
+ "Getting Started"
+ Guide
+
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/material/material.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/material/material.component.ts
new file mode 100644
index 000000000..9141260ba
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/material/material.component.ts
@@ -0,0 +1,162 @@
+import {
+ AfterViewInit,
+ Component,
+ ViewChild,
+ ViewEncapsulation
+} from '@angular/core';
+
+import {
+ ExerciseConfigTemplate,
+ Ng2TsExercises
+} from '../../../../../../../ng2ts/ng2ts';
+import { extractMessages } from '@codelab/utils/src/lib/i18n/i18n-tools';
+import { CodelabFile } from '../../../shared/helpers/codelabFile';
+
+declare const require;
+
+interface FileHighlights {
+ appModule?: RegExp;
+ appHtml?: RegExp;
+}
+
+function matExercise(
+ modules,
+ html,
+ highlights: FileHighlights = {},
+ theme = 'purple'
+) {
+ const moduleCode = require('!!raw-loader!./samples/basic/app.module.ts').replace(
+ /MatCardModule, MatToolbarModule/g,
+ modules
+ );
+
+ return {
+ files: [
+ CodelabFile.TypeScriptFile('app.module')
+ .setCode(moduleCode)
+ .withHighlight(highlights.appModule),
+ CodelabFile.Html('app')
+ .setCode(html)
+ .withHighlight(highlights.appHtml),
+ CodelabFile.TypeScriptFile('app.component').setCode(
+ require('!!raw-loader!./samples/basic/app.component.ts')
+ ),
+ CodelabFile.TypeScriptFile('bootstrap')
+ .setCode(require('!!raw-loader!./samples/basic/main.ts'))
+ .makeBootstrappable(),
+ CodelabFile.Css('styles').setCode(
+ require('!!raw-loader!@angular/material/prebuilt-themes/indigo-pink.css')
+ ),
+ CodelabFile.Css('extra').setCode('body {padding: 0; margin: 0;}')
+ ]
+ };
+}
+
+@Component({
+ selector: 'codelab-slides-material',
+ templateUrl: './material.component.html',
+ styleUrls: ['./material.component.css'],
+ encapsulation: ViewEncapsulation.None
+})
+export class MaterialComponent implements AfterViewInit {
+ exercise: ExerciseConfigTemplate;
+ @ViewChild('themePlayground', { static: false }) themePlayground;
+ @ViewChild('translations', { static: false }) translations;
+
+ themes = {
+ indigo: require('!!raw-loader!@angular/material/prebuilt-themes/indigo-pink.css'),
+ deeppurple: require('!!raw-loader!@angular/material/prebuilt-themes/deeppurple-amber.css'),
+ pink: require('!!raw-loader!@angular/material/prebuilt-themes/pink-bluegrey.css'),
+ purple: require('!!raw-loader!@angular/material/prebuilt-themes/purple-green.css')
+ };
+
+ code = {
+ material: {
+ step1: {
+ code: {
+ 'app.component.ts': require('!!raw-loader!./samples/basic/app.component.ts'),
+ 'app.module.ts': require('!!raw-loader!./samples/step1/app.module.ts'),
+ 'app.html': require('!!raw-loader!./samples/step1/app.html'),
+ 'bootstrap.ts': require('!!raw-loader!./samples/basic/main.ts'),
+ 'styles.css': this.themes.indigo
+ },
+ files: ['app.module.ts', 'app.html'],
+ highlights: {
+ 'app.module.ts': 'MatToolbarModule,',
+ 'app.html': //
+ }
+ },
+ step2: {
+ code: {
+ 'app.component.ts': require('!!raw-loader!./samples/basic/app.component.ts'),
+ 'app.module.ts': require('!!raw-loader!./samples/step2/app.module.ts'),
+ 'app.html': require('!!raw-loader!./samples/step2/app.html'),
+ 'bootstrap.ts': require('!!raw-loader!./samples/basic/main.ts'),
+ 'styles.css': this.themes.indigo
+ },
+ files: ['app.module.ts', 'app.html'],
+ highlights: {
+ 'app.module.ts': /MatCardModule,/,
+ 'app.html': //
+ }
+ },
+ step3: {
+ code: {
+ 'app.component.ts': require('!!raw-loader!./samples/basic/app.component.ts'),
+ 'app.module.ts': require('!!raw-loader!./samples/step2/app.module.ts'),
+ 'app.html': require('!!raw-loader!./samples/step3/app.html'),
+ 'bootstrap.ts': require('!!raw-loader!./samples/basic/main.ts'),
+ 'styles.css': this.themes.indigo
+ },
+ files: ['app.html'],
+ highlights: {
+ 'app.html': //
+ }
+ },
+ step4: {
+ code: {
+ 'app.component.ts': require('!!raw-loader!./samples/basic/app.component.ts'),
+ 'app.module.ts': require('!!raw-loader!./samples/step4/app.module.ts'),
+ 'app.html': require('!!raw-loader!./samples/step4/app.html'),
+ 'bootstrap.ts': require('!!raw-loader!./samples/basic/main.ts'),
+ 'styles.css': this.themes.indigo
+ },
+ files: ['app.module.ts', 'app.html'],
+ highlights: {
+ 'app.module.ts': /MatButtonModule\n/,
+ 'app.html': //
+ }
+ },
+ themes: {
+ code: {
+ 'app.component.ts': require('!!raw-loader!./samples/basic/app.component.ts'),
+ 'app.module.ts': require('!!raw-loader!./samples/step4/app.module.ts'),
+ 'app.html': require('!!raw-loader!./samples/step4/app.html'),
+ 'bootstrap.ts': require('!!raw-loader!./samples/basic/main.ts'),
+ 'styles.css': this.themes.indigo
+ },
+ files: ['app.html', 'styles.css']
+ },
+ theme: matExercise(
+ `MatToolbarModule,\n MatCardModule,\n MatButtonModule`,
+ require('!!raw-loader!./samples/basic/app.4.html')
+ )
+ }
+ };
+ private theme = 'indigo';
+ private t: Record;
+
+ constructor(private exercises: Ng2TsExercises) {
+ this.exercise = exercises.getExercises(6, 0);
+ }
+
+ ngAfterViewInit() {
+ this.t = extractMessages(this.translations);
+ }
+
+ setTheme(theme) {
+ this.theme = theme;
+ this.code.material.themes.code['styles.css'] = this.themes[theme];
+ this.code.material.themes.code = { ...this.code.material.themes.code };
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/material/material.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/material/material.module.ts
new file mode 100644
index 000000000..fb550d4ca
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/material/material.module.ts
@@ -0,0 +1,36 @@
+import { MaterialComponent } from './material.component';
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { RouterModule } from '@angular/router';
+import { MatButtonModule } from '@angular/material/button';
+import { MatCardModule } from '@angular/material/card';
+import { MatInputModule } from '@angular/material/input';
+import { FormsModule } from '@angular/forms';
+import { SlidesModule, SlidesRoutes } from '@ng360/slides';
+import { FeedbackModule } from '@codelab/feedback';
+import { BrowserWindowModule } from '@codelab/browser';
+import { CodeDemoModule } from '@codelab/code-demos';
+import { Ng2TsExercises } from '../../../../../../../ng2ts/ng2ts';
+import { CodelabComponentsModule } from '../../../components/codelab-components.module';
+
+const routes = RouterModule.forChild([...SlidesRoutes.get(MaterialComponent)]);
+
+@NgModule({
+ imports: [
+ routes,
+ FeedbackModule,
+ CommonModule,
+ BrowserWindowModule,
+ MatButtonModule,
+ MatCardModule,
+ MatInputModule,
+ CodelabComponentsModule,
+ SlidesModule,
+ FormsModule,
+ CodeDemoModule
+ ],
+ declarations: [MaterialComponent],
+ exports: [MaterialComponent],
+ providers: [Ng2TsExercises]
+})
+export class MaterialCodelabModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/app.1.html b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/app.1.html
new file mode 100644
index 000000000..b40c58a4a
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/app.1.html
@@ -0,0 +1,3 @@
+
+ Hi, I'm material toolbar
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/app.2.html b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/app.2.html
new file mode 100644
index 000000000..133bb147b
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/app.2.html
@@ -0,0 +1,13 @@
+
+ Hi, I'm material toolbar
+
+
+
+
+
+ The Shiba Inu is the smallest of the six original and distinct spitz
+ breeds of dog from Japan. A small, agile dog that copes very well with
+ mountainous terrain, the Shiba Inu was originally bred for hunting.
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/app.3.html b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/app.3.html
new file mode 100644
index 000000000..af6af7195
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/app.3.html
@@ -0,0 +1,23 @@
+
+ Hi, I'm material toolbar
+
+
+
+
+
+ Shiba Inu
+ Dog Breed
+
+
+
+
+ The Shiba Inu is the smallest of the six original and distinct spitz
+ breeds of dog from Japan. A small, agile dog that copes very well with
+ mountainous terrain, the Shiba Inu was originally bred for hunting.
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/app.4.html b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/app.4.html
new file mode 100644
index 000000000..4f1bb7f34
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/app.4.html
@@ -0,0 +1,25 @@
+ Header
+
+
+
+
+ Shiba Inu
+ Dog Breed
+
+
+
+
+ The Shiba Inu is the smallest of the six original and distinct spitz
+ breeds of dog from Japan. A small, agile dog that copes very well with
+ mountainous terrain, the Shiba Inu was originally bred for hunting.
+
+
+
+ LIKE
+ SHARE
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/app.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/app.component.ts
new file mode 100644
index 000000000..decef5238
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/app.component.ts
@@ -0,0 +1,8 @@
+import { Component } from '@angular/core';
+
+/* tslint:disable */
+@Component({
+ selector: 'my-app',
+ templateUrl: './app.html'
+})
+export class AppComponent {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/app.html b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/app.html
new file mode 100644
index 000000000..4ba73475d
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/app.html
@@ -0,0 +1,24 @@
+ Header
+
+
+
+
+ Shiba Inu
+ Dog Breed
+
+
+
+
+ The Shiba Inu is the smallest of the six original and distinct spitz
+ breeds of dog from Japan. A small, agile dog that copes very well with
+ mountainous terrain, the Shiba Inu was originally bred for hunting.
+
+
+
+ LIKE SHARE
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/app.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/app.module.ts
new file mode 100644
index 000000000..d3ad83983
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/app.module.ts
@@ -0,0 +1,20 @@
+import { BrowserModule } from '@angular/platform-browser';
+import { NgModule } from '@angular/core';
+import { MatButtonModule } from '@angular/material/button';
+import { MatCardModule } from '@angular/material/card';
+import { MatToolbarModule } from '@angular/material/toolbar';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { AppComponent } from './app.component';
+
+@NgModule({
+ imports: [
+ BrowserModule,
+ NoopAnimationsModule,
+ MatToolbarModule,
+ MatCardModule,
+ MatButtonModule
+ ],
+ declarations: [AppComponent],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/code.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/code.ts
new file mode 100644
index 000000000..63c681e0b
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/code.ts
@@ -0,0 +1,2 @@
+// I'm ignored
+export const hi = 'hi';
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/main.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/main.ts
new file mode 100644
index 000000000..f8b9878bf
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/basic/main.ts
@@ -0,0 +1,31 @@
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+import { AppModule } from './app.module';
+import { ResourceLoader } from '@angular/compiler';
+import * as code from './code';
+
+class MyResourceLoader extends ResourceLoader {
+ get(url: string): Promise {
+ const templateId = Object.keys(code).find(key =>
+ key.includes(url.replace(/[\/\.-]/gi, '_'))
+ );
+ const template = code[templateId];
+ if (!template) {
+ console.log(template);
+ // tslint:disable-next-line:no-debugger
+ debugger;
+ }
+ return Promise.resolve(template);
+ }
+}
+
+platformBrowserDynamic().bootstrapModule(AppModule, [
+ {
+ providers: [
+ {
+ provide: ResourceLoader,
+ useFactory: () => new MyResourceLoader(),
+ deps: []
+ }
+ ]
+ }
+]);
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/step1/app.html b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/step1/app.html
new file mode 100644
index 000000000..b40c58a4a
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/step1/app.html
@@ -0,0 +1,3 @@
+
+ Hi, I'm material toolbar
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/step1/app.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/step1/app.module.ts
new file mode 100644
index 000000000..d3ad83983
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/step1/app.module.ts
@@ -0,0 +1,20 @@
+import { BrowserModule } from '@angular/platform-browser';
+import { NgModule } from '@angular/core';
+import { MatButtonModule } from '@angular/material/button';
+import { MatCardModule } from '@angular/material/card';
+import { MatToolbarModule } from '@angular/material/toolbar';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { AppComponent } from './app.component';
+
+@NgModule({
+ imports: [
+ BrowserModule,
+ NoopAnimationsModule,
+ MatToolbarModule,
+ MatCardModule,
+ MatButtonModule
+ ],
+ declarations: [AppComponent],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/step2/app.html b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/step2/app.html
new file mode 100644
index 000000000..133bb147b
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/step2/app.html
@@ -0,0 +1,13 @@
+
+ Hi, I'm material toolbar
+
+
+
+
+
+ The Shiba Inu is the smallest of the six original and distinct spitz
+ breeds of dog from Japan. A small, agile dog that copes very well with
+ mountainous terrain, the Shiba Inu was originally bred for hunting.
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/step2/app.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/step2/app.module.ts
new file mode 100644
index 000000000..d3ad83983
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/step2/app.module.ts
@@ -0,0 +1,20 @@
+import { BrowserModule } from '@angular/platform-browser';
+import { NgModule } from '@angular/core';
+import { MatButtonModule } from '@angular/material/button';
+import { MatCardModule } from '@angular/material/card';
+import { MatToolbarModule } from '@angular/material/toolbar';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { AppComponent } from './app.component';
+
+@NgModule({
+ imports: [
+ BrowserModule,
+ NoopAnimationsModule,
+ MatToolbarModule,
+ MatCardModule,
+ MatButtonModule
+ ],
+ declarations: [AppComponent],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/step3/app.html b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/step3/app.html
new file mode 100644
index 000000000..af6af7195
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/step3/app.html
@@ -0,0 +1,23 @@
+
+ Hi, I'm material toolbar
+
+
+
+
+
+ Shiba Inu
+ Dog Breed
+
+
+
+
+ The Shiba Inu is the smallest of the six original and distinct spitz
+ breeds of dog from Japan. A small, agile dog that copes very well with
+ mountainous terrain, the Shiba Inu was originally bred for hunting.
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/step4/app.html b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/step4/app.html
new file mode 100644
index 000000000..4f1bb7f34
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/step4/app.html
@@ -0,0 +1,25 @@
+ Header
+
+
+
+
+ Shiba Inu
+ Dog Breed
+
+
+
+
+ The Shiba Inu is the smallest of the six original and distinct spitz
+ breeds of dog from Japan. A small, agile dog that copes very well with
+ mountainous terrain, the Shiba Inu was originally bred for hunting.
+
+
+
+ LIKE
+ SHARE
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/step4/app.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/step4/app.module.ts
new file mode 100644
index 000000000..d3ad83983
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/material/samples/step4/app.module.ts
@@ -0,0 +1,20 @@
+import { BrowserModule } from '@angular/platform-browser';
+import { NgModule } from '@angular/core';
+import { MatButtonModule } from '@angular/material/button';
+import { MatCardModule } from '@angular/material/card';
+import { MatToolbarModule } from '@angular/material/toolbar';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { AppComponent } from './app.component';
+
+@NgModule({
+ imports: [
+ BrowserModule,
+ NoopAnimationsModule,
+ MatToolbarModule,
+ MatCardModule,
+ MatButtonModule
+ ],
+ declarations: [AppComponent],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}
diff --git a/libs/utils/src/lib/sync/components/poll/sync-poll-presenter/leaderboard/leaderboard-presenter/leaderboard-presenter.component.css b/codelab-master/apps/codelab/src/app/codelabs/angular/pipes/pipes.component.css
similarity index 100%
rename from libs/utils/src/lib/sync/components/poll/sync-poll-presenter/leaderboard/leaderboard-presenter/leaderboard-presenter.component.css
rename to codelab-master/apps/codelab/src/app/codelabs/angular/pipes/pipes.component.css
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/pipes/pipes.component.html b/codelab-master/apps/codelab/src/app/codelabs/angular/pipes/pipes.component.html
new file mode 100644
index 000000000..233c6bc27
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/pipes/pipes.component.html
@@ -0,0 +1,174 @@
+
+
+
+
+
+
+
+
+
+
+
Introduction
+
+
+ Every application starts out with what seems like a simple task: get
+ data, transform it, and show it to users. Getting data could be as
+ simple as creating a local variable or as complex as streaming data over
+ a WebSocket.
+ An Angular pipe is a function that transforms input values to
+ output values for display in a view. Let's see how it works.
+
+
+
+
+
+
+
How do pipes work?
+
+ A pipe takes in data as input and transforms it to a desired output.
+
+
+ Inside the interpolation expression, we use the pipe
+ ( | ) operator to pass the App Component's 'dob' through the
+ the 'date' pipe on the right, transforming a long timestamp into a more
+ human-readable output. All pipes follow this signature.
+
+
+
+
+
+
+
Built-in Pipes
+
+
+ Angular comes with a variety of built-in pipes that can be used in any
+ template or binding expression. Some of these pipes are:
+
+
+ DatePipe
+ UpperCasePipe
+ LowerCasePipe
+ CurrencyPipe
+ PercentPipe
+
+
+ You can check out all the pipes
+ in the docs.
+
+
+
+
+
+
+
Chained Pipes
+
+ Translate Dali's birthday to a more human-friendly format. While you're at
+ it, make his birthday uppercase, too.
+
+
+
Hint: dob ... date ... uppercase
+
+
+
+
+
Pipes with arguments:
+
+
+
+ To add parameters to a pipe, append a colon ( : ) followed by the
+ parameters' values e.g. currency:'AUD'
+
+
+
+
+
+
Using custom pipes to filter data
+
+
+
+
+
+
+
Creating a pipe
+
+
+ A pipe is a class decorated with pipe metadata.
+
+
+
+
+
Creating a pipe
+
+
+ The pipe class implements the PipeTransform interface.
+
+
+
+
+
Creating a pipe
+
+
+
+ The transform method accepts an input value followed by optional
+ parameters and returns the transformed value.
+
+
+
+
+
+
Creating a pipe
+
+
+
+ The @Pipe decorator allows you to define the pipe name that you'll use
+ within template expressions.
+
+
+ Don't forget to import the @Pipe decorator from the core Angular library.
+
+
+
+
+
+
+
+
+
Well done! This is the end of the milestone!
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/pipes/pipes.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/pipes/pipes.component.ts
new file mode 100644
index 000000000..c1e619a8e
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/pipes/pipes.component.ts
@@ -0,0 +1,80 @@
+import { Component } from '@angular/core';
+import { displayAngularComponent } from '../../../shared/helpers/helpers';
+
+@Component({
+ selector: 'codelab-slides-pipes',
+ templateUrl: './pipes.component.html',
+ styleUrls: ['./pipes.component.css']
+})
+export class PipesComponent {
+ code = {
+ chainedPipesExample: {
+ template: displayAngularComponent(`import {Component} from '@angular/core';
+
+@Component({
+ selector: 'my-app',
+ template: \`Salvador's Dali DOB
+ {{ dob }}
\`
+})
+export class AppComponent {
+ dob = new Date(1904, 4, 11);
+}`)
+ },
+ workingPipes: {
+ template: displayAngularComponent(`import {Component} from '@angular/core';
+
+@Component({
+ selector: 'my-app',
+ template: \`Salvador's Dali DOB
+ {{dob}}
+ {{ dob | date }}
\`
+})
+export class AppComponent {
+ dob = new Date(1904, 4, 11);
+}`),
+ matches: {
+ pipeOperator: '|'
+ }
+ },
+ argumentPipes: {
+ template: `Your budget is {{budget | currency:'AUD'}}
+Your truncated name is {{name | substring:1:4}}
+`,
+ readonly: true,
+ path: 'argument.pipe.html'
+ },
+ filterPipes: {
+ template: `
+`,
+ readonly: true,
+ path: 'filter.pipe.html'
+ },
+ creatingAPipe: {
+ template: `import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({name: 'substring'})
+export class SubstringPipe implements PipeTransform {
+ transform(value: string, start: number, end: number): string {
+ return (value || '').slice(start, end);
+ }
+}`,
+ matches: {
+ exportClass: /export.*/,
+ decorator: /@Pipe/,
+ pipeTransform: /PipeTransform/,
+ method: /transform[^]*?\)[^]/
+ },
+ readonly: true,
+ path: 'substring.pipe.ts',
+ type: 'typescript'
+ }
+ };
+
+ constructor() {}
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/pipes/pipes.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/pipes/pipes.module.ts
new file mode 100644
index 000000000..4ce63b1a1
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/pipes/pipes.module.ts
@@ -0,0 +1,26 @@
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { FormsModule } from '@angular/forms';
+import { SlidesModule, SlidesRoutes } from '@ng360/slides';
+import { FeedbackModule } from '@codelab/feedback';
+import { BrowserWindowModule } from '@codelab/browser';
+import { CodeDemoModule } from '@codelab/code-demos';
+import { PipesComponent } from './pipes.component';
+import { CodelabComponentsModule } from '../../../components/codelab-components.module';
+
+const routes = RouterModule.forChild(SlidesRoutes.get(PipesComponent));
+
+@NgModule({
+ imports: [
+ routes,
+ CodeDemoModule,
+ BrowserWindowModule,
+ FeedbackModule,
+ CodelabComponentsModule,
+ SlidesModule,
+ FormsModule
+ ],
+ declarations: [PipesComponent],
+ exports: [PipesComponent]
+})
+export class PipesModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/pipes/samples/pipes/app.component.html b/codelab-master/apps/codelab/src/app/codelabs/angular/pipes/samples/pipes/app.component.html
new file mode 100644
index 000000000..3ede6aafc
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/pipes/samples/pipes/app.component.html
@@ -0,0 +1,2 @@
+Wow, check out this terribly formatted date:
+{{ birthday }}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/pipes/samples/pipes/app.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/pipes/samples/pipes/app.component.ts
new file mode 100644
index 000000000..49d54ae8d
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/pipes/samples/pipes/app.component.ts
@@ -0,0 +1,9 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'my-app',
+ templateUrl: './app.component.html'
+})
+export class AppComponent {
+ birthday = new Date('2012-01-19');
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/pipes/samples/pipes/app.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/pipes/samples/pipes/app.module.ts
new file mode 100644
index 000000000..60e193df9
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/pipes/samples/pipes/app.module.ts
@@ -0,0 +1,11 @@
+import { NgModule } from '@angular/core';
+import { BrowserModule } from '@angular/platform-browser';
+import { AppComponent } from './app.component';
+
+// Useless app module to prevent angular from complaining
+@NgModule({
+ imports: [BrowserModule],
+ declarations: [AppComponent],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/playground/angular-sample.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/playground/angular-sample.ts
new file mode 100644
index 000000000..fa1e5e82b
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/playground/angular-sample.ts
@@ -0,0 +1,26 @@
+export const angularSampleCode = {
+ 'app.component.ts': `import { Component } from '@angular/core';
+
+@Component({
+ selector: 'my-app',
+ template: \`Edit me \`
+})
+export class AppComponent {}`,
+ 'app.module.ts': `import { BrowserModule } from '@angular/platform-browser';
+import { NgModule } from '@angular/core';
+import { AppComponent } from './app.component';
+
+@NgModule({
+ imports: [BrowserModule],
+ declarations: [AppComponent],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}`,
+
+ 'main.ts': `import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+import { AppModule } from './app.module';
+
+platformBrowserDynamic().bootstrapModule(AppModule);
+`,
+ 'index.html': ' '
+};
diff --git a/libs/utils/src/lib/sync/components/poll/sync-poll-presenter/leaderboard/leaderboard-viewer/leaderboard-viewer.component.css b/codelab-master/apps/codelab/src/app/codelabs/angular/playground/playground.component.css
similarity index 100%
rename from libs/utils/src/lib/sync/components/poll/sync-poll-presenter/leaderboard/leaderboard-viewer/leaderboard-viewer.component.css
rename to codelab-master/apps/codelab/src/app/codelabs/angular/playground/playground.component.css
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/playground/playground.component.html b/codelab-master/apps/codelab/src/app/codelabs/angular/playground/playground.component.html
new file mode 100644
index 000000000..ea1a4a542
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/playground/playground.component.html
@@ -0,0 +1,5 @@
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/playground/playground.component.spec.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/playground/playground.component.spec.ts
new file mode 100644
index 000000000..a426454eb
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/playground/playground.component.spec.ts
@@ -0,0 +1,38 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { PlaygroundComponent } from './playground.component';
+import { PlaygroundModule } from './playground.module';
+import { ActivatedRoute, Router } from '@angular/router';
+
+describe('PlaygroundComponent', () => {
+ let component: PlaygroundComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [PlaygroundModule],
+ providers: [
+ {
+ provide: ActivatedRoute,
+ useValue: { snapshot: { queryParams: { code: '' } } }
+ },
+ {
+ provide: Router,
+ useValue: {
+ navigate: jasmine.createSpy('navigate')
+ }
+ }
+ ]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(PlaygroundComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create!', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/playground/playground.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/playground/playground.component.ts
new file mode 100644
index 000000000..6e82f60bc
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/playground/playground.component.ts
@@ -0,0 +1,34 @@
+import { Component } from '@angular/core';
+import { angularSampleCode } from './angular-sample';
+import { ActivatedRoute, Router } from '@angular/router';
+
+@Component({
+ selector: 'codelab-playground',
+ templateUrl: './playground.component.html',
+ styleUrls: ['./playground.component.css']
+})
+export class PlaygroundComponent {
+ code = angularSampleCode;
+
+ constructor(
+ private readonly activatedRoute: ActivatedRoute,
+ private readonly router: Router
+ ) {
+ const code = activatedRoute.snapshot.queryParams.code;
+ if (code) {
+ try {
+ this.code = { ...angularSampleCode, ...JSON.parse(atob(code)) };
+ } catch (e) {
+ console.log('can not parse code', code);
+ }
+ }
+ }
+
+ handleUpdate(code: any) {
+ const encoded = btoa(JSON.stringify(code));
+ this.router.navigate([], {
+ relativeTo: this.activatedRoute,
+ queryParams: { code: encoded }
+ });
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/playground/playground.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/playground/playground.module.ts
new file mode 100644
index 000000000..ec4585dbc
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/playground/playground.module.ts
@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { PlaygroundComponent } from './playground.component';
+import { RouterModule } from '@angular/router';
+import { CodeDemoModule } from '@codelab/code-demos';
+import { FormsModule } from '@angular/forms';
+
+@NgModule({
+ declarations: [PlaygroundComponent],
+ imports: [
+ RouterModule.forChild([{ path: '', component: PlaygroundComponent }]),
+ CodeDemoModule,
+ CommonModule,
+ FormsModule
+ ]
+})
+export class PlaygroundModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/router/router.component.css b/codelab-master/apps/codelab/src/app/codelabs/angular/router/router.component.css
new file mode 100644
index 000000000..103b62fb9
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/router/router.component.css
@@ -0,0 +1,12 @@
+.router-preview {
+ display: flex;
+}
+
+.router-preview codelab-exercise-preview {
+ margin: 10px;
+}
+
+.router-preview ::ng-deep .url {
+ color: black !important;
+ background: #f8ff15 !important;
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/router/router.component.html b/codelab-master/apps/codelab/src/app/codelabs/angular/router/router.component.html
new file mode 100644
index 000000000..05d7661b8
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/router/router.component.html
@@ -0,0 +1,184 @@
+
+
+ app.module.ts: Using RouterModule.forRoot provide an empty array to the
+ module
+
+
+ app.module.ts: Add a route with an empty ('') path to display
+ SearchComponent
+
+
+ app.module.ts: Add a route with path of "upload" to display UploadComponent
+
+
+ app.html: Add router-outlet
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Intro
+
+ Router is used to give URLs to different parts of your app.
+
+
+
+ Kittens
+
+
+ Puppies
+
+
+
+
+
Intro
+
It takes 3 steps to set up routing in Angular:
+
+
+ Configure the mapping and specify which component to display for which
+ URL
+
+ Create the menu with navigation links
+ Find a place to display selected component
+
+
+
+
+ Configuration
+
+ Routes are configured by defining an array of mapping between URL path and
+ a component
+
+
+
+
+
+
Configuration
+
Then we have to pass the config to our module.
+
+
+ Note that we're using RouterModule.forRoot which creates an Angular
+ Module out of our configuration.
+
+
+
+
+ router-outlet
+
+ Now we have to find a place where the router would display selected
+ component.
+
+ It can be marked by placing router-outlet tag
+
+
+
+
+
+
+
+
Exercise
+
+ In the next slide there is an exercise. We're going to add 2 routes:
+ Search and Upload , and a menu for switching between them.
+
+
+
+ Note: We have already created empty Upload component and SearchComponent
+ containing search logic.
+
+
+
+
+
+
+
+
+
+
+
+
+
Well done! This is the end of the milestone!
+
+ Check out
+ Angular Router Guide for
+ more fun and advanced techniques.
+
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/router/router.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/router/router.component.ts
new file mode 100644
index 000000000..9029146b6
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/router/router.component.ts
@@ -0,0 +1,62 @@
+import { CodelabFile } from '../../../shared/helpers/codelabFile';
+import { AfterViewInit, Component, ViewChild } from '@angular/core';
+import {
+ ExerciseConfigTemplate,
+ Ng2TsExercises
+} from '../../../../../../../ng2ts/ng2ts';
+import { extractMessages } from '@codelab/utils/src/lib/i18n/i18n-tools';
+
+declare const require;
+
+interface FileHighlights {
+ appModule?: RegExp | RegExp[];
+ appHtml?: RegExp | RegExp[];
+}
+
+@Component({
+ selector: 'codelab-slides-router',
+ templateUrl: './router.component.html',
+ styleUrls: ['./router.component.css']
+})
+export class RouterComponent implements AfterViewInit {
+ @ViewChild('translations', { static: false }) translations;
+ private t: Record;
+ exercise: ExerciseConfigTemplate;
+
+ code = {
+ files: {
+ 'app.module.ts': require('!!raw-loader!./samples/simple-router/app.module.ts'),
+ 'app.component.html': require('!!raw-loader!./samples/simple-router/app.component.html'),
+ 'app.component.ts': require('!!raw-loader!./samples/simple-router/app.component.ts'),
+ 'components/kitten.ts': require('!!raw-loader!./samples/simple-router/components/kitten.ts'),
+ 'components/puppy.ts': require('!!raw-loader!./samples/simple-router/components/puppy.ts'),
+ 'bootstrap.ts': require('!!raw-loader!./samples/simple-router/main.ts'),
+ 'index.html': require('!!raw-loader!./samples/simple-router/index.html'),
+ 'components/.html': require('!!raw-loader!./samples/simple-router/index.html')
+ },
+ config: {
+ files: ['app.module.ts'],
+ highlights: { 'app.module.ts': /const routes[\s\S]*?];[\s\S]/ }
+ },
+ configPass: {
+ files: ['app.module.ts'],
+ highlights: { 'app.module.ts': /RouterModule.forRoot\(routes\)/ }
+ },
+ routerOutlet: {
+ files: ['app.component.html'],
+ highlights: { 'app.component.html': /<\/router-outlet>/ }
+ },
+ menu: {
+ files: ['app.component.html'],
+ highlights: { 'app.component.html': // }
+ }
+ };
+
+ constructor(private exercises: Ng2TsExercises) {
+ this.exercise = exercises.getExercises(5, 0);
+ }
+
+ ngAfterViewInit() {
+ this.t = extractMessages(this.translations);
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/router/router.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/router/router.module.ts
new file mode 100644
index 000000000..4e85ff5ef
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/router/router.module.ts
@@ -0,0 +1,30 @@
+import { RouterComponent } from './router.component';
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { FormsModule } from '@angular/forms';
+import { CommonModule } from '@angular/common';
+import { SlidesModule, SlidesRoutes } from '@ng360/slides';
+import { FeedbackModule } from '@codelab/feedback';
+import { BrowserWindowModule } from '@codelab/browser';
+import { CodeDemoModule } from '@codelab/code-demos';
+import { Ng2TsExercises } from '../../../../../../../ng2ts/ng2ts';
+import { CodelabComponentsModule } from '../../../components/codelab-components.module';
+
+const routes = RouterModule.forChild([...SlidesRoutes.get(RouterComponent)]);
+
+@NgModule({
+ imports: [
+ routes,
+ FeedbackModule,
+ CommonModule,
+ BrowserWindowModule,
+ CodelabComponentsModule,
+ SlidesModule,
+ FormsModule,
+ CodeDemoModule
+ ],
+ declarations: [RouterComponent],
+ providers: [Ng2TsExercises],
+ exports: [RouterComponent]
+})
+export class RouterCodelabModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/router/samples/simple-router/app.component.html b/codelab-master/apps/codelab/src/app/codelabs/angular/router/samples/simple-router/app.component.html
new file mode 100644
index 000000000..af550fe5f
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/router/samples/simple-router/app.component.html
@@ -0,0 +1,3 @@
+Puppies And Kittens
+ Puppies | Kittens
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/router/samples/simple-router/app.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/router/samples/simple-router/app.component.ts
new file mode 100644
index 000000000..5f2d7aaf6
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/router/samples/simple-router/app.component.ts
@@ -0,0 +1,8 @@
+import { Component } from '@angular/core';
+
+@Component({
+ // tslint:disable-next-line
+ selector: 'my-app',
+ templateUrl: './app.component.html'
+})
+export class AppComponent {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/router/samples/simple-router/app.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/router/samples/simple-router/app.module.ts
new file mode 100644
index 000000000..0ccb9f5b6
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/router/samples/simple-router/app.module.ts
@@ -0,0 +1,18 @@
+import { NgModule } from '@angular/core';
+import { AppComponent } from './app.component';
+import { RouterModule, Routes } from '@angular/router';
+import { PuppyComponent } from './components/puppy';
+import { KittenComponent } from './components/kitten';
+import { BrowserModule } from '@angular/platform-browser';
+
+const routes: Routes = [
+ { path: '', component: PuppyComponent },
+ { path: 'kittens', component: KittenComponent }
+];
+
+@NgModule({
+ declarations: [AppComponent, PuppyComponent, KittenComponent],
+ imports: [BrowserModule, RouterModule.forRoot(routes)],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/router/samples/simple-router/code.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/router/samples/simple-router/code.ts
new file mode 100644
index 000000000..63c681e0b
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/router/samples/simple-router/code.ts
@@ -0,0 +1,2 @@
+// I'm ignored
+export const hi = 'hi';
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/router/samples/simple-router/components/kitten.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/router/samples/simple-router/components/kitten.ts
new file mode 100644
index 000000000..6ab730331
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/router/samples/simple-router/components/kitten.ts
@@ -0,0 +1,7 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'codelab-i-am-not-very-important',
+ template: 'Kittens '
+})
+export class KittenComponent {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/router/samples/simple-router/components/puppy.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/router/samples/simple-router/components/puppy.ts
new file mode 100644
index 000000000..c26309025
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/router/samples/simple-router/components/puppy.ts
@@ -0,0 +1,7 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'codelab-i-will-be-ignored',
+ template: 'Puppies! '
+})
+export class PuppyComponent {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/router/samples/simple-router/index.html b/codelab-master/apps/codelab/src/app/codelabs/angular/router/samples/simple-router/index.html
new file mode 100644
index 000000000..1fab8b6da
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/router/samples/simple-router/index.html
@@ -0,0 +1,3 @@
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/router/samples/simple-router/main.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/router/samples/simple-router/main.ts
new file mode 100644
index 000000000..d55fc449c
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/router/samples/simple-router/main.ts
@@ -0,0 +1,29 @@
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+import { AppModule } from './app.module';
+import { ResourceLoader } from '@angular/compiler';
+import * as code from './code';
+
+class MyResourceLoader extends ResourceLoader {
+ get(url: string): Promise {
+ const templateId = Object.keys(code).find(key =>
+ key.includes(url.replace(/[\/\.-]/gi, '_'))
+ );
+ const template = code[templateId];
+ if (!template) {
+ console.log(template);
+ // tslint:disable-next-line:no-debugger
+ debugger;
+ }
+ return Promise.resolve(template);
+ }
+}
+
+platformBrowserDynamic().bootstrapModule(AppModule, {
+ providers: [
+ {
+ provide: ResourceLoader,
+ useFactory: () => new MyResourceLoader(),
+ deps: []
+ }
+ ]
+});
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/bsod.css b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/bsod.css
new file mode 100644
index 000000000..f0145b2b8
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/bsod.css
@@ -0,0 +1,65 @@
+@import url(https://fonts.googleapis.com/css?family=Press+Start+2p);
+
+.container {
+ display: flex;
+ font-family: 'Press Start 2P', cursive;
+ align-items: center;
+ width: 100%;
+ height: 100%;
+}
+
+.msg {
+ padding-left: 100px;
+ padding-right: 100px;
+}
+
+p {
+ text-align: left;
+}
+
+.continue {
+ text-align: center;
+}
+
+.highlight {
+ color: rgb(1, 2, 172);
+ background-color: rgb(172, 173, 168);
+ padding: 3px;
+ text-align: center;
+ width: 150px;
+}
+
+.blink {
+ animation: blink 1s steps(2, start) infinite;
+}
+
+@keyframes blink {
+ to {
+ visibility: hidden;
+ }
+}
+
+#bsod,
+#bsod-2,
+#bsod-beautiful {
+ color: white;
+ background: #084fdd;
+ display: inline-block;
+ height: 100vh;
+}
+
+#bsod-2 .alfred-upset {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 263px;
+ height: 420px;
+ background: url(./pics/Alfred_Sisley_photo_full.jpg);
+}
+
+#bsod-beautiful {
+ background: url(./pics/bebbf81f5402fbbec1cff6eb687aa90a.jpg) no-repeat center
+ center fixed;
+ background-size: 100%;
+ color: black;
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/pics/Alfred_Sisley_photo_full.jpg b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/pics/Alfred_Sisley_photo_full.jpg
new file mode 100644
index 000000000..05bf3c270
Binary files /dev/null and b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/pics/Alfred_Sisley_photo_full.jpg differ
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/pics/alfred-sisley-9485226-1-402.jpg b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/pics/alfred-sisley-9485226-1-402.jpg
new file mode 100644
index 000000000..655404a19
Binary files /dev/null and b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/pics/alfred-sisley-9485226-1-402.jpg differ
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/pics/bebbf81f5402fbbec1cff6eb687aa90a.jpg b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/pics/bebbf81f5402fbbec1cff6eb687aa90a.jpg
new file mode 100644
index 000000000..cda16c1b3
Binary files /dev/null and b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/pics/bebbf81f5402fbbec1cff6eb687aa90a.jpg differ
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/pics/bridge-at-villeneuve-la-garenne-1872.jpg b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/pics/bridge-at-villeneuve-la-garenne-1872.jpg
new file mode 100644
index 000000000..7717e006c
Binary files /dev/null and b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/pics/bridge-at-villeneuve-la-garenne-1872.jpg differ
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/mat-tab-nav-bar/alert.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/mat-tab-nav-bar/alert.component.ts
new file mode 100644
index 000000000..519a316e6
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/mat-tab-nav-bar/alert.component.ts
@@ -0,0 +1,13 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: '' + 'app-alert',
+ template: `
+ Hi ALert
+ `
+})
+export class AlertComponent {
+ constructor() {
+ alert('Hello');
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/mat-tab-nav-bar/app.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/mat-tab-nav-bar/app.component.ts
new file mode 100644
index 000000000..609e0e332
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/mat-tab-nav-bar/app.component.ts
@@ -0,0 +1,27 @@
+import { Component } from '@angular/core';
+
+/* tslint:disable */
+@Component({
+ selector: 'my-app',
+ template: `
+
+
+ {{ tab.label }}
+
+
+
+
+ `
+})
+export class AppComponent {
+ tabs = [
+ {
+ link: '',
+ label: 'Tab 1'
+ },
+ {
+ link: 'danger',
+ label: 'Danger'
+ }
+ ];
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/mat-tab-nav-bar/app.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/mat-tab-nav-bar/app.module.ts
new file mode 100644
index 000000000..708bc7a7f
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/mat-tab-nav-bar/app.module.ts
@@ -0,0 +1,21 @@
+import { BrowserModule } from '@angular/platform-browser';
+import { NgModule } from '@angular/core';
+import { AppComponent } from './app.component';
+import { AlertComponent } from './alert.component';
+import { TabComponent } from './tab.component';
+import { RouterModule } from '@angular/router';
+import { APP_BASE_HREF } from '@angular/common';
+import { MatTabsModule } from '@angular/material/tabs';
+
+const routes = [
+ { path: '', component: TabComponent },
+ { path: 'danger', component: AlertComponent }
+];
+
+@NgModule({
+ imports: [BrowserModule, MatTabsModule, RouterModule.forRoot(routes)],
+ declarations: [AppComponent, AlertComponent, TabComponent],
+ bootstrap: [AppComponent],
+ providers: [{ provide: APP_BASE_HREF, useValue: '/assets/runner/' }]
+})
+export class AppModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/mat-tab-nav-bar/tab.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/mat-tab-nav-bar/tab.component.ts
new file mode 100644
index 000000000..710c317ae
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/mat-tab-nav-bar/tab.component.ts
@@ -0,0 +1,10 @@
+import { Component } from '@angular/core';
+
+/* tslint:disable */
+@Component({
+ selector: 'my-app',
+ template: `
+
+ `
+})
+export class TabComponent {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs-structural-directive/alert.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs-structural-directive/alert.component.ts
new file mode 100644
index 000000000..519a316e6
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs-structural-directive/alert.component.ts
@@ -0,0 +1,13 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: '' + 'app-alert',
+ template: `
+ Hi ALert
+ `
+})
+export class AlertComponent {
+ constructor() {
+ alert('Hello');
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs-structural-directive/app.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs-structural-directive/app.component.ts
new file mode 100644
index 000000000..decef5238
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs-structural-directive/app.component.ts
@@ -0,0 +1,8 @@
+import { Component } from '@angular/core';
+
+/* tslint:disable */
+@Component({
+ selector: 'my-app',
+ templateUrl: './app.html'
+})
+export class AppComponent {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs-structural-directive/app.html b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs-structural-directive/app.html
new file mode 100644
index 000000000..2e9431a80
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs-structural-directive/app.html
@@ -0,0 +1,8 @@
+Alfred Sisley
+
+
+
+
+
+ Content 2
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs-structural-directive/app.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs-structural-directive/app.module.ts
new file mode 100644
index 000000000..18b4c2a7e
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs-structural-directive/app.module.ts
@@ -0,0 +1,14 @@
+import { BrowserModule } from '@angular/platform-browser';
+import { NgModule } from '@angular/core';
+import { AppComponent } from './app.component';
+import { MatTabsModule } from '@angular/material/tabs';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { AlertComponent } from './alert.component';
+import { HideMeDirective } from './hideme.directive';
+
+@NgModule({
+ imports: [BrowserModule, MatTabsModule, NoopAnimationsModule],
+ declarations: [AppComponent, AlertComponent, HideMeDirective],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs-structural-directive/app.solved.html b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs-structural-directive/app.solved.html
new file mode 100644
index 000000000..894ae68c0
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs-structural-directive/app.solved.html
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs-structural-directive/hideme.directive.solved.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs-structural-directive/hideme.directive.solved.ts
new file mode 100644
index 000000000..0f396def1
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs-structural-directive/hideme.directive.solved.ts
@@ -0,0 +1,36 @@
+import {
+ AfterViewInit,
+ Directive,
+ TemplateRef,
+ ViewContainerRef
+} from '@angular/core';
+import { MatTabGroup, MatTab } from '@angular/material/tabs';
+
+/* tslint:disable */
+@Directive({ selector: '[matHideMe]' })
+export class HideMeDirective implements AfterViewInit {
+ constructor(
+ private parentTab: MatTab,
+ private tabs: MatTabGroup,
+ private viewContainer: ViewContainerRef,
+ private templateRef: TemplateRef
+ ) {
+ (tabs as any).selectChange.subscribe(({ tab }: { tab: MatTab }) => {
+ this.toggleContentDisplay(tab === parentTab);
+ });
+ }
+
+ toggleContentDisplay(isDisplayed: boolean) {
+ if (isDisplayed) {
+ this.viewContainer.createEmbeddedView(this.templateRef);
+ } else {
+ this.viewContainer.clear();
+ }
+ }
+
+ ngAfterViewInit() {
+ this.toggleContentDisplay(
+ this.parentTab.position === this.tabs.selectedIndex
+ );
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs-structural-directive/hideme.directive.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs-structural-directive/hideme.directive.ts
new file mode 100644
index 000000000..0f5016ab4
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs-structural-directive/hideme.directive.ts
@@ -0,0 +1,7 @@
+import { Directive } from '@angular/core';
+
+/* tslint:disable */
+@Directive({ selector: '[matHideMe]' })
+export class HideMeDirective {
+ constructor() {}
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs-structural-directive/ignored.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs-structural-directive/ignored.module.ts
new file mode 100644
index 000000000..b1eaddb1a
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs-structural-directive/ignored.module.ts
@@ -0,0 +1,9 @@
+import { NgModule } from '@angular/core';
+import { HideMeDirective } from './hideme.directive.solved';
+
+// This is needed because angular cli wants the directive to be in a module
+// https://github.com/angular/angular/issues/13590
+@NgModule({
+ declarations: [HideMeDirective]
+})
+export class IgnoredModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs/alert.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs/alert.component.ts
new file mode 100644
index 000000000..c3e92ee6a
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs/alert.component.ts
@@ -0,0 +1,13 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: '' + 'app-alert',
+ template: `
+ This is AlertComponent!
+ `
+})
+export class AlertComponent {
+ constructor() {
+ alert('Hello');
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs/app.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs/app.component.ts
new file mode 100644
index 000000000..decef5238
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs/app.component.ts
@@ -0,0 +1,8 @@
+import { Component } from '@angular/core';
+
+/* tslint:disable */
+@Component({
+ selector: 'my-app',
+ templateUrl: './app.html'
+})
+export class AppComponent {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs/app.html b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs/app.html
new file mode 100644
index 000000000..ba69a4f64
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs/app.html
@@ -0,0 +1,8 @@
+Alfred Sisley
+
+
+
+
+
+ TBD
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs/app.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs/app.module.ts
new file mode 100644
index 000000000..b0cf13a17
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs/app.module.ts
@@ -0,0 +1,21 @@
+import { BrowserModule } from '@angular/platform-browser';
+import { NgModule } from '@angular/core';
+import { AppComponent } from './app.component';
+import { MatTabsModule } from '@angular/material/tabs';
+
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { AlertComponent } from './alert.component';
+import { BreakMyComputerComponent } from './break-my-computer.component';
+import { TaetLedComponent } from './taet-led.component';
+
+@NgModule({
+ imports: [BrowserModule, MatTabsModule, NoopAnimationsModule],
+ declarations: [
+ AppComponent,
+ AlertComponent,
+ BreakMyComputerComponent,
+ TaetLedComponent
+ ],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs/app.solved.html b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs/app.solved.html
new file mode 100644
index 000000000..903291b51
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs/app.solved.html
@@ -0,0 +1,12 @@
+Alfred Sisley
+
+
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs/break-my-computer.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs/break-my-computer.component.ts
new file mode 100644
index 000000000..884e37f1f
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs/break-my-computer.component.ts
@@ -0,0 +1,14 @@
+import { Component } from '@angular/core';
+
+/* tslint:disable */
+@Component({
+ selector: 'break-my-computer',
+ template: `
+ I'll break your computer
+ `
+})
+export class BreakMyComputerComponent {
+ constructor() {
+ alert('Congratulations! Your computer has been broken successfully!');
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs/style.css b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs/style.css
new file mode 100644
index 000000000..963ef3a70
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs/style.css
@@ -0,0 +1,13 @@
+body,
+html {
+ width: 100%;
+ height: 100%;
+}
+
+body,
+h1,
+p,
+div {
+ font-family: 'Helvetica Neue', sans-serif;
+ font-weight: 300;
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs/taet-led.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs/taet-led.component.ts
new file mode 100644
index 000000000..50d942040
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/material-tabs/taet-led.component.ts
@@ -0,0 +1,18 @@
+import { Component } from '@angular/core';
+
+/* tslint:disable */
+@Component({
+ selector: 'play-terrible-russian-pop-music',
+ template: `
+ VIDEO
+ `
+})
+export class TaetLedComponent {
+ constructor() {}
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/micro-syntax/code.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/micro-syntax/code.ts
new file mode 100644
index 000000000..210a310a4
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/micro-syntax/code.ts
@@ -0,0 +1,2 @@
+// Needed for type checking,
+export const app_html = '';
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/micro-syntax/ms.spec.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/micro-syntax/ms.spec.ts
new file mode 100644
index 000000000..479b71229
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/micro-syntax/ms.spec.ts
@@ -0,0 +1,34 @@
+import { parseTemplate } from './ms';
+
+describe('micro-syntax', () => {
+ it('parses ngIF', () => {
+ expect(parseTemplate('{{hero.name}}
'))
+ .toBe(`
+ {{hero.name}}
+ `);
+ });
+
+ it('parses ngIf multi line', () => {
+ expect(
+ parseTemplate(`
+ {{hero.name}}
+
`)
+ ).toBe(`
+
+ {{hero.name}}
+
+ `);
+ });
+
+ xit('parses ngFor', () => {
+ expect(
+ parseTemplate(`
+ {{hero.name}}
+
`)
+ ).toBe(`
+
+ {{hero.name}}
+
+ `);
+ });
+});
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/micro-syntax/ms.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/micro-syntax/ms.ts
new file mode 100644
index 000000000..13f7485b9
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/micro-syntax/ms.ts
@@ -0,0 +1,17 @@
+import * as code from './code';
+
+export function parseTemplate(template: string) {
+ const x = template.match(
+ /<([^ ]+)\s+\*(\w+)\s*="([^"]+)"\s*>([\s\S]*)<\/\w+>/
+ );
+ if (x) {
+ const [_, tag, directive, value, contents] = x;
+ return `
+ <${tag}>${contents}${tag}>
+ `;
+ }
+}
+
+const pre = document.createElement('pre');
+document.body.appendChild(pre);
+pre.innerText = parseTemplate(code.app_html);
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/structural-directives/microsyntax.html b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/structural-directives/microsyntax.html
new file mode 100644
index 000000000..7a3164bf9
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/structural-directives/microsyntax.html
@@ -0,0 +1,6 @@
+*:prefix="( :let | :expression ) (';' | ',')? ( :let | :as | :keyExp )*"
+:prefix: HTML attribute key. :key: HTML attribute key. :local: local variable
+name used in the template. :export: value exported by the directive under a
+given name. :experession: standard Angular expression :keyExp = :key ":"?
+:expression ("as" :local)? ";"? :let = "let" :local "=" :export ";"? :as =
+:export "as" :local ";"?
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/structural-directives/ng-for-after.html b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/structural-directives/ng-for-after.html
new file mode 100644
index 000000000..3a44e0ce6
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/structural-directives/ng-for-after.html
@@ -0,0 +1,10 @@
+
+ ({{i}}) {{hero.name}}
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/structural-directives/ng-for-before.html b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/structural-directives/ng-for-before.html
new file mode 100644
index 000000000..09ca363a8
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/structural-directives/ng-for-before.html
@@ -0,0 +1,6 @@
+
+ ({{i}}) {{hero.name}}
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/structural-directives/ng-if-after.html b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/structural-directives/ng-if-after.html
new file mode 100644
index 000000000..041b7277b
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/structural-directives/ng-if-after.html
@@ -0,0 +1 @@
+ {{hero.name}}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/structural-directives/ng-if-before.html b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/structural-directives/ng-if-before.html
new file mode 100644
index 000000000..2c86f4c01
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/samples/structural-directives/ng-if-before.html
@@ -0,0 +1 @@
+{{hero.name}}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/structural-directives.component.css b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/structural-directives.component.css
new file mode 100644
index 000000000..6ca715334
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/structural-directives.component.css
@@ -0,0 +1,78 @@
+#intro .bg {
+ background: #fff;
+ opacity: 0.5;
+ padding: 2vw 5vw;
+ margin: 5vw 0;
+}
+
+#intro h1 {
+ font-size: 10vw;
+}
+
+#intro h2 {
+ font-size: 6vw;
+}
+
+:host /deep/ .slide {
+ background: transparent;
+}
+
+#intro {
+ background: url(./pics/bridge-at-villeneuve-la-garenne-1872.jpg) no-repeat;
+ display: inline-block;
+ height: 100vh;
+}
+
+#we-need-tabs {
+ background: url(./pics/alfred-sisley-9485226-1-402.jpg) no-repeat black;
+ display: inline-block;
+ height: 100vh;
+}
+
+#we-need-tabs h1 {
+ color: #ffffee;
+ font-size: 8vw;
+ background: #000;
+ opacity: 0.5;
+}
+
+:host /deep/ .runner,
+:host /deep/ .runner iframe {
+ display: block;
+ width: 100%;
+ height: 100%;
+}
+
+/* Specificity */
+:host /deep/ .side.side.side {
+ display: block;
+}
+
+.font-size:hover {
+ opacity: 1;
+}
+
+.font-size {
+ display: block;
+ opacity: 0.1;
+ background-color: #eeeeee;
+ border-radius: 50%;
+ font-size: 30px;
+ width: 30px;
+ height: 30px;
+ cursor: pointer;
+ text-align: center;
+}
+
+.twitter {
+ position: absolute;
+ left: 20px;
+ bottom: 20px;
+ color: #400;
+ height: 50px;
+ z-index: 100;
+ font-size: 50px;
+ font-family: Monaco, 'Lucida Console', monospace;
+ opacity: 1;
+ width: auto;
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/structural-directives.component.html b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/structural-directives.component.html
new file mode 100644
index 000000000..adc98650a
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/structural-directives.component.html
@@ -0,0 +1,214 @@
+
+
+
+
+
+
+
+
+
+
+
Structural directives
+ By @kirjs
+
+
+
We need tabs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Windows
+
+ A fatal exception 0E has occured at 028:C00068F8 in VxD VMM(01)
+ 000059F8. The current application will be terminated.
+
+
* Press any key to terminate the application.
+
+ * Press CTRL+ALT+DEL to restart your computer. You will lose any
+ unsaved information in all aplications.
+
+
+
+ Press any key to continue _
+
+
+
+
+
+
+
+
+
Windows
+
+ A fatal exception 0E has occured at 028:C00068F8 in VxD VMM(01)
+ 000059F8. The current application will be terminated.
+
+
* Press any key to terminate the application.
+
+ * Press CTRL+ALT+DEL to restart your computer. You will lose any
+ unsaved information in all aplications.
+
+
+
+ Press any key to continue _
+
+
+
+
+
+
+
+
Windows
+
+ A fatal exception 0E has occured at 028:C00068F8 in VxD VMM(01)
+ 000059F8. The current application will be terminated.
+
+
* Press any key to terminate the application.
+
+ * Press CTRL+ALT+DEL to restart your computer. You will lose any
+ unsaved information in all aplications.
+
+
+
+ Press any key to continue _
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Structural directives ngIf
+
+
+
+
+
Desugars into
+
+
+
+
+
+
+
+
Structural directives ngFor
+
+
+
+
+
Desugars into
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Russian pop music
+ @kirjs
+ VIDEO
+ VIDEO
+ VIDEO
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/structural-directives.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/structural-directives.component.ts
new file mode 100644
index 000000000..1d479edd2
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/structural-directives.component.ts
@@ -0,0 +1,119 @@
+import { Component } from '@angular/core';
+
+import {
+ bootstrap,
+ builder,
+ exercise,
+ html,
+ stylesheet
+} from '../../../shared/helpers/helpers';
+
+declare const require;
+
+@Component({
+ selector: 'codelab-slides-structural-directives',
+ templateUrl: './structural-directives.component.html',
+ styleUrls: ['./structural-directives.component.css', './bsod.css']
+})
+export class StructuralDirectivesComponent {
+ fontSize = 18;
+
+ code = {
+ materialTabs: {
+ files: [
+ html(
+ 'app',
+ require('!!raw-loader!./samples/material-tabs/app.html'),
+ require('!!raw-loader!./samples/material-tabs/app.solved.html')
+ ),
+ exercise(
+ 'app.component',
+ require('!!raw-loader!./samples/material-tabs/app.component.ts')
+ ),
+ exercise(
+ 'alert.component',
+ require('!!raw-loader!./samples/material-tabs/alert.component.ts')
+ ),
+ exercise(
+ 'taet-led.component',
+ require('!!raw-loader!./samples/material-tabs/taet-led.component.ts')
+ ),
+ exercise(
+ 'app.module',
+ require('!!raw-loader!./samples/material-tabs/app.module.ts')
+ ),
+ exercise(
+ 'break-my-computer.component',
+ require('!!raw-loader!./samples/material-tabs/break-my-computer.component.ts')
+ ),
+ stylesheet(require('!!raw-loader!./samples/material-tabs/style.css')),
+ bootstrap('main', builder.bootstrap())
+ ]
+ },
+ materialTabsStructuralDirective: [
+ html(
+ 'app',
+ require('!!raw-loader!./samples/material-tabs-structural-directive/app.html'),
+ require('!!raw-loader!./samples/material-tabs-structural-directive/app.solved.html')
+ ),
+ exercise(
+ 'app.component',
+ require('!!raw-loader!./samples/material-tabs-structural-directive/app.component.ts')
+ ),
+ exercise(
+ 'hideme.directive',
+ require('!!raw-loader!./samples/material-tabs-structural-directive/hideme.directive.ts'),
+ require('!!raw-loader!./samples/material-tabs-structural-directive/hideme.directive.solved.ts')
+ ),
+ exercise(
+ 'alert.component',
+ require('!!raw-loader!./samples/material-tabs-structural-directive/alert.component.ts')
+ ),
+ exercise(
+ 'app.module',
+ require('!!raw-loader!./samples/material-tabs-structural-directive/app.module.ts')
+ ),
+ stylesheet(require('!!raw-loader!./samples/material-tabs/style.css')),
+ bootstrap('main', builder.bootstrap())
+ ],
+ microSyntax: [
+ html('app', `
`),
+ bootstrap('main', require('!!raw-loader!./samples/micro-syntax/ms.ts'))
+ ],
+
+ mdTabNavBar: [
+ exercise(
+ 'app.component',
+ require('!!raw-loader!./samples/mat-tab-nav-bar/app.component.ts')
+ ),
+ exercise(
+ 'alert.component',
+ require('!!raw-loader!./samples/mat-tab-nav-bar/alert.component.ts')
+ ),
+ exercise(
+ 'tab.component',
+ require('!!raw-loader!./samples/mat-tab-nav-bar/tab.component.ts')
+ ),
+ stylesheet(require('!!raw-loader!./samples/material-tabs/style.css')),
+ exercise(
+ 'app.module',
+ require('!!raw-loader!./samples/mat-tab-nav-bar/app.module.ts')
+ ),
+ bootstrap('main', builder.bootstrap())
+ ],
+
+ structuralDirectives: {
+ ngIfBefore: require('!!raw-loader!./samples/structural-directives/ng-if-before.html'),
+ ngIfAfter: require('!!raw-loader!./samples/structural-directives/ng-if-after.html'),
+ ngForBefore: require('!!raw-loader!./samples/structural-directives/ng-for-before.html'),
+ ngForAfter: require('!!raw-loader!./samples/structural-directives/ng-for-after.html'),
+ microSyntax: require('!!raw-loader!./samples/structural-directives/microsyntax.html')
+ }
+ };
+
+ constructor() {}
+
+ updateFontSize(diff) {
+ this.fontSize += diff;
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/structural-directives.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/structural-directives.module.ts
new file mode 100644
index 000000000..55c91d5a1
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/structural-directives/structural-directives.module.ts
@@ -0,0 +1,28 @@
+import { NgModule } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { RouterModule } from '@angular/router';
+import { SlidesModule, SlidesRoutes } from '@ng360/slides';
+import { FeedbackModule } from '@codelab/feedback';
+import { CodeDemoModule } from '@codelab/code-demos';
+import { BrowserWindowModule } from '@codelab/browser';
+import { StructuralDirectivesComponent } from './structural-directives.component';
+import { CodelabComponentsModule } from '../../../components/codelab-components.module';
+
+const routes = RouterModule.forChild(
+ SlidesRoutes.get(StructuralDirectivesComponent)
+);
+
+@NgModule({
+ imports: [
+ routes,
+ CodeDemoModule,
+ BrowserWindowModule,
+ FeedbackModule,
+ CodelabComponentsModule,
+ SlidesModule,
+ FormsModule
+ ],
+ declarations: [StructuralDirectivesComponent],
+ exports: [StructuralDirectivesComponent]
+})
+export class StructuralDirectivesModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/data-binding-extra/app.component.html b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/data-binding-extra/app.component.html
new file mode 100644
index 000000000..1da59a747
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/data-binding-extra/app.component.html
@@ -0,0 +1,15 @@
+Here we bind value of the input to the name property
+
+
+A shortcut applying (or not) class name based on the value of isSpecial
+
+ Wow, I'm special!
+
+
+Shortcut for binding styles
+
+ special button
+
+
+It also works with custom components
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/data-binding-extra/app.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/data-binding-extra/app.component.ts
new file mode 100644
index 000000000..6f0c94b18
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/data-binding-extra/app.component.ts
@@ -0,0 +1,10 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'my-app',
+ templateUrl: './app.component.html'
+})
+export class AppComponent {
+ readonly name = 'Camille Pissarro';
+ isSpecial = true;
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/data-binding-extra/app.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/data-binding-extra/app.module.ts
new file mode 100644
index 000000000..b28bfb723
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/data-binding-extra/app.module.ts
@@ -0,0 +1,11 @@
+import { NgModule } from '@angular/core';
+import { BrowserModule } from '@angular/platform-browser';
+import { BirthdayCardComponent } from './number-praiser';
+import { AppComponent } from './app.component';
+
+@NgModule({
+ imports: [BrowserModule],
+ declarations: [AppComponent, BirthdayCardComponent],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/data-binding-extra/index.html b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/data-binding-extra/index.html
new file mode 100644
index 000000000..22bea202e
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/data-binding-extra/index.html
@@ -0,0 +1,39 @@
+
+
+
+
+
+ Loading...
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/data-binding-extra/number-praiser.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/data-binding-extra/number-praiser.ts
new file mode 100644
index 000000000..87ca40560
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/data-binding-extra/number-praiser.ts
@@ -0,0 +1,14 @@
+import { Component, Input } from '@angular/core';
+
+@Component({
+ // tslint:disable-next-line:component-selector
+ selector: 'number-praiser',
+ template: `
+
+ 🎈 {{ number }} 🎈 What an amazing number!!! 🎖
+
+ `
+})
+export class BirthdayCardComponent {
+ @Input() number = 0;
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/event-binding-shortcuts/app.component.html b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/event-binding-shortcuts/app.component.html
new file mode 100644
index 000000000..98cf49139
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/event-binding-shortcuts/app.component.html
@@ -0,0 +1,10 @@
+Message: {{ message }}
+
+
+
+
+ Update message
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/event-binding/app.component.html b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/event-binding/app.component.html
new file mode 100644
index 000000000..8b246f8d3
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/event-binding/app.component.html
@@ -0,0 +1,3 @@
+Message: {{ message }}
+
+Update version
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/event-binding/app.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/event-binding/app.component.ts
new file mode 100644
index 000000000..86499ce4d
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/event-binding/app.component.ts
@@ -0,0 +1,9 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'my-app',
+ templateUrl: './app.component.html'
+})
+export class AppComponent {
+ message = 'no message';
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/event-binding/app.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/event-binding/app.module.ts
new file mode 100644
index 000000000..60e193df9
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/event-binding/app.module.ts
@@ -0,0 +1,11 @@
+import { NgModule } from '@angular/core';
+import { BrowserModule } from '@angular/platform-browser';
+import { AppComponent } from './app.component';
+
+// Useless app module to prevent angular from complaining
+@NgModule({
+ imports: [BrowserModule],
+ declarations: [AppComponent],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/reference-binding/app.component.html b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/reference-binding/app.component.html
new file mode 100644
index 000000000..e6f391dd4
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/reference-binding/app.component.html
@@ -0,0 +1,7 @@
+Message: {{ message }}
+
+
+
+
+ Update message
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/reference-binding/app.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/reference-binding/app.component.ts
new file mode 100644
index 000000000..eeefa2679
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/reference-binding/app.component.ts
@@ -0,0 +1,9 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'my-app',
+ templateUrl: './app.component.html'
+})
+export class AppComponent {
+ message = 'No message';
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/reference-binding/app.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/reference-binding/app.module.ts
new file mode 100644
index 000000000..60e193df9
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/samples/reference-binding/app.module.ts
@@ -0,0 +1,11 @@
+import { NgModule } from '@angular/core';
+import { BrowserModule } from '@angular/platform-browser';
+import { AppComponent } from './app.component';
+
+// Useless app module to prevent angular from complaining
+@NgModule({
+ imports: [BrowserModule],
+ declarations: [AppComponent],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}
diff --git a/libs/utils/src/lib/sync/components/poll/sync-poll-presenter/leaderboard/leaderboard.component.css b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/templates.component.css
similarity index 100%
rename from libs/utils/src/lib/sync/components/poll/sync-poll-presenter/leaderboard/leaderboard.component.css
rename to codelab-master/apps/codelab/src/app/codelabs/angular/templates/templates.component.css
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/templates/templates.component.html b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/templates.component.html
new file mode 100644
index 000000000..d23046841
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/templates.component.html
@@ -0,0 +1,391 @@
+
+
+ This is valid HTML syntax.
+
+
+ It works on attribute syntax.
+
+
+ It allows to conditionally bind a class
+
+
Or style properties
+
+ And works with custom components!
+
+
+ When user clicks the button, it calls the "saveUser" function on the
+ component instance and passes the underlying event.
+
+
+ You can also create events for custom components. Here we have a depleted
+ event, and it's going to call the "soundAlarm" function on the component
+ instance when it fires.
+
+
+ There are also shortcut event bindings! The submit function on the component
+ instance will be called when the user presses control and enter (this is an
+ Angular feature).
+
+
+ userName has a reference to the input element
+
+
+ Try changing to true!
+
+
+ Need to repeat puppies here
+
+
+ app.component.ts: Add a 'videos' property, set the value as empty array.
+
+
+ app.component.ts: Inside of the 'search' method assign FAKE_VIDEOS, to the
+ component 'videos' property.
+
+
+
+
+ app.component.ts: Add a 'search' method on the component, that takes a
+ 'searchString' parameter.
+
+
+ app.html: Add a click handler to the button, call 'search' method and pass
+ the input value (Actual search functionality will be implemented in the next
+ exercise)
+
+
+ app.html: Add a message saying 'no videos' which is displayed only when the
+ videos array is empty
+
+
+
+ #Bonus app.component.ts: Right now it takes pressing a search button to
+ display the videos. Instead display all videos by default.
+
+
+ app.component.ts: Inside of the 'search' method filter FAKE_VIDEOS and only
+ return videos with the title containing searchString. (hint: use .includes
+ or .indexOf string methods)
+
+
+ app.html: Also display a thumbnail
+
+
+ app.html: Iterate over the videos using '*ngFor', and display a title for
+ each
+
+
+
+ app.html: Add a button tag with a text 'search'
+
+
+ app.html: Add an input tag with a 'placeholder' attribute set to 'video'
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Intro
+
+ Angular has a very expressive template system, which takes HTML as a base,
+ and extends it with custom elements
+
+
+
+
+
+
+
Interpolation
+
+ Double curlies include the appropriate component property value
+
+
+
+ Backticks ` ` , are magic quotes that allow multi-line strings and
+ text interpolation.
+
+
+
+
+
+ Interpolation
+
+ Simple expressions are also allowed, you can run a component method (like
+ fullName() below), or calculate 323213+34234
+
+
+
+
+
+ Exercise
+
+ In the next slide you'll edit a component template to create a simple
+ header and search form. The result will look like this:
+
+
+
+
+
+
+
+
+
+
+
+
+ Properties
+
+ String interpolation {{ curlies }} can also be used to pass a value
+ to a child element's attribute
+
+
+
+
+
+
+
Property Binding
+
+ Better option is to use property binding [attribute] = property
+
+
+
+ You can use arbitrary expressions in the binding.
+
+
+
+
+
+
+
+
Event binding: (event)
+
+ For handling user actions we can use event bindings. To do that we wrap
+ the event name in parentheses, and pass an expression performing required
+ action:
+
+
+
+ While parentheses are used for event binding: (event) , "on-" can
+ also be used, e.g. on-click is the same as (click) .
+
+
+
+
+
Event binding shortcuts
+
+ When we need to access an HTML element or an Angular component from the
+ template, we can mark it with #name , and it becomes available as
+ name everywhere in the template:
+
+
+
+ We'll learn a better way to work with inputs in Forms milestone.
+
+
+
+
+ Event binding shortcuts
+
+ Angular also provides a shortcut for handling keyboard shortcuts. Try
+ updating the message by pressing Control + Enter in the input.
+
+
+
+
+
+
+ Conditional Display (*ngIf)
+
+ This conditional expression will add or remove an element from the DOM if
+ it evaluates as a truthy
+
+
+
+
+
+ Exercise 2
+
+ In the next slide you'll add a click handler to the search button, and
+ display a message for the case where no videos were found. The result will
+ look like this:
+
+
+
+
+
+
+
+
+
+
+
+ Repeating elements
+
+ Let's say you have an array of puppies, and want to display all of them on
+ the page. Angular has a special syntax for that called *ngFor ,
+ let's see how it works on the next slide
+
+
+
+
+
+
Repeating elements (*ngFor)
+
+ Here *ngFor repeats HTML element it's attached to (li in this case)
+ for every single puppy in the puppies array
+
+
+
+ HTML attributes in Angular are case sensitive:
+ *ngfor won't work, *ngFor will
+
+
+
+
+
Exercise 3
+
+
+
+ In the next slide you'll finally display the videos! The result will
+ look like this:
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/templates/templates.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/templates.component.ts
new file mode 100644
index 000000000..dcaf69710
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/templates.component.ts
@@ -0,0 +1,270 @@
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { ng2tsConfig } from '../../../../../../../ng2ts/ng2ts';
+import {
+ displayAngularComponent,
+ displayAngularComponentWithHtml
+} from '../../../shared/helpers/helpers';
+import { extractMessages } from '@codelab/utils/src/lib/i18n/i18n-tools';
+
+declare const require;
+
+const baseCode = 'TODO';
+
+@Component({
+ selector: 'codelab-slides-templates',
+ templateUrl: './templates.component.html',
+ styleUrls: ['./templates.component.css']
+})
+export class TemplatesComponent implements OnInit {
+ t: { [key: string]: string };
+ exercises = [
+ ng2tsConfig.milestones[2].exercises[1],
+ ng2tsConfig.milestones[2].exercises[2],
+ ng2tsConfig.milestones[2].exercises[3]
+ ];
+ curlies = '{{ property }}';
+
+ // TODO(kirjs): we can't access tanslation in OnInit hook iwht static set to false
+ // need to consider changing how we set code
+ @ViewChild('translations', { static: true }) translation;
+ code: any = {};
+
+ constructor() {}
+
+ ngOnInit() {
+ this.t = extractMessages(this.translation);
+
+ this.code = {
+ template: {
+ intro: displayAngularComponent(`import {Component} from '@angular/core';
+
+@Component({
+ selector: 'my-app',
+ template: 'Hello World! '
+})
+export class AppComponent {
+}`),
+
+ matches: {
+ curlies: { 'app.component.ts': [/{{.*}}/, /firstName = .*/] },
+ curliesFullName: { 'app.component.ts': [/{{.*}}/, /fullName\(\){/] },
+ curliesAttribute: { 'app.component.ts': [/"{{.*}}"/, /avatar = .*/] },
+ template: { 'app.component.ts': /.*<\/h1>/ },
+ squares: { 'app.component.ts': /\[.*]/ }
+ },
+ interpolation: displayAngularComponent(
+ `import {Component} from '@angular/core';
+
+@Component({
+ selector: 'my-app',
+ template: \`
+ Hello {{firstName}}!
+ \`
+})
+export class AppComponent {
+ firstName = 'Pierre-Auguste';
+ lastName = 'Renoir';
+}`,
+ ''
+ ),
+ interpolationMethod: displayAngularComponent(`import {Component} from '@angular/core';
+
+@Component({
+ selector: 'my-app',
+ template: \`Hello {{fullName()}}! \`
+})
+export class AppComponent {
+ firstName = 'Pierre-Auguste';
+ lastName = 'Renoir';
+ fullName(){
+ return this.firstName + " " + this.lastName
+ }
+}`),
+ dataBindingPre: displayAngularComponent(`import {Component} from '@angular/core';
+
+@Component({
+ selector: 'my-app',
+ template: \`Hello {{fullName()}}!
+
+ \`
+})
+export class AppComponent {
+ firstName = 'Pierre-Auguste';
+ lastName = 'Renoir';
+ avatar = 'assets/images/renoir.jpg';
+ fullName(){ return this.firstName + " " + this.lastName }
+}`),
+ dataBinding: displayAngularComponent(`import {Component} from '@angular/core';
+
+@Component({
+ selector: 'my-app',
+ template: \`Hello {{fullName()}}!
+
+ \`
+})
+export class AppComponent {
+ firstName = 'Pierre-Auguste';
+ lastName = 'Renoir';
+ avatar = 'assets/images/renoir.jpg';
+ fullName(){ return this.firstName + " " + this.lastName }
+}`),
+ dataBindingExtra: {
+ code: {
+ 'app.component.html': require('!!raw-loader!./samples/data-binding-extra/app.component.html'),
+ 'app.component.ts': require('!!raw-loader!./samples/data-binding-extra/app.component.ts'),
+ 'bootstrap.ts': require('!!raw-loader!./../../../shared/angular-code/bootstrap.ts'),
+ 'app.module.ts': require('!!raw-loader!./samples/data-binding-extra/app.module.ts'),
+ 'number-praiser.ts': require('!!raw-loader!./samples/data-binding-extra/number-praiser.ts'),
+ 'index.html': require('!!raw-loader!./samples/data-binding-extra/index.html')
+ },
+ files: ['app.component.html', 'app.component.ts']
+ }
+ },
+ ngIfDirective: {
+ template: displayAngularComponent(`import {Component} from '@angular/core';
+@Component({
+ selector: 'my-app',
+ template: \`Hello {{firstName}}!
+
+ \`
+})
+export class AppComponent {
+ firstName = 'Pierre-Auguste';
+ avatar = 'assets/images/renoir.jpg';
+ onDisplay(){ return false } // ${this.t.tryChangingToTrue}
+}`),
+ matches: {
+ ngIf: { 'app.component.ts': /\*ngIf/ }
+ }
+ },
+ ngForDirectivePre: {
+ template: displayAngularComponent(`import {Component} from '@angular/core';
+
+@Component({
+ selector: 'my-app',
+ template: \`Puppies names:
+ ???
+ \`
+})
+export class AppComponent {
+ puppies = ['Schumann', 'Mendelssohn', 'Bach'];
+}`),
+ matches: { 'app.component.ts': ['???', /puppies.*;/] }
+ },
+ ngForDirective: {
+ template: displayAngularComponent(
+ `import {Component} from '@angular/core';
+
+@Component({
+ selector: 'my-app',
+ template: \`Puppies names:
+
+ \`
+})
+export class AppComponent {
+ puppies = ['Schumann', 'Mendelssohn', 'Bach'];
+}`,
+ `
+import {AppComponent} from './app.component';
+
+describe('AppComponent', ()=>{
+ it('Add one more puppy to the list', ()=>{
+ const app = new AppComponent();
+ chai.expect(app.puppies.length).equals(4);
+ })
+})
+
+`
+ ),
+ matches: {
+ ngFor: { 'app.component.ts': '*ngFor' }
+ }
+ },
+
+ templateInterpolation: `
+
+ Profile for {{person.name}}
+
+
+ Profile for {{person.getBiography()}}
+
+
+
+ `,
+ templateInterpolationMatch: /{{person.name}}/,
+ templateInterpolationExercise: displayAngularComponentWithHtml(
+ baseCode,
+ `Hello, {{user.firstName}} `
+ ),
+ templateInterpolationExerciseMatch: /user.firstName/,
+ bindingPropMatch: /person.photoUrl/,
+ bindingPropExercise: displayAngularComponentWithHtml(
+ baseCode,
+ ` `
+ ),
+ bindingPropExerciseMatch: /user.pic/,
+ eventBinding: {
+ code: {
+ 'app.component.html': require('!!raw-loader!./samples/event-binding/app.component.html'),
+ 'app.component.ts': require('!!raw-loader!./samples/event-binding/app.component.ts'),
+ 'bootstrap.ts': require('!!raw-loader!./../../../shared/angular-code/bootstrap.ts'),
+ 'app.module.ts': require('!!raw-loader!./../../../shared/angular-code/app.module.ts'),
+ 'index.html': require('!!raw-loader!./../../../shared/angular-code/index.html')
+ },
+ files: ['app.component.html'],
+ highlights: { 'app.component.html': '(click)' }
+ },
+ referenceBinding: {
+ code: {
+ 'app.component.html': require('!!raw-loader!./samples/reference-binding/app.component.html'),
+ 'app.component.ts': require('!!raw-loader!./samples/reference-binding/app.component.ts'),
+ 'bootstrap.ts': require('!!raw-loader!./../../../shared/angular-code/bootstrap.ts'),
+ 'app.module.ts': require('!!raw-loader!./../../../shared/angular-code/app.module.ts'),
+ 'index.html': require('!!raw-loader!./../../../shared/angular-code/index.html')
+ },
+ files: ['app.component.html'],
+ highlights: { 'app.component.html': ['#input', 'input.value'] }
+ },
+ eventBindingShortcuts: {
+ code: {
+ 'app.component.html': require('!!raw-loader!./samples/event-binding-shortcuts/app.component.html'),
+ 'app.component.ts': require('!!raw-loader!./samples/reference-binding/app.component.ts'),
+ 'bootstrap.ts': require('!!raw-loader!./../../../shared/angular-code/bootstrap.ts'),
+ 'app.module.ts': require('!!raw-loader!./../../../shared/angular-code/app.module.ts'),
+ 'index.html': require('!!raw-loader!./../../../shared/angular-code/index.html')
+ },
+ files: ['app.component.html'],
+ highlights: { 'app.component.html': '(keydown.control.enter)' }
+ },
+
+ eventBindingExercise: displayAngularComponentWithHtml(
+ baseCode,
+ ``
+ ),
+ conditionalDisplay: `
+
+
+
+`,
+ conditionalDisplayMatch: /ngIf/,
+ conditionalDisplayExercise: displayAngularComponentWithHtml(
+ baseCode,
+ ``
+ ),
+ conditionalDisplayFor: ``,
+ conditionalDisplayForMatch: /ngFor/,
+ conditionalDisplayForExercise: displayAngularComponentWithHtml(
+ baseCode,
+ ``
+ )
+ };
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/templates/templates.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/templates.module.ts
new file mode 100644
index 000000000..d7152ccef
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/templates/templates.module.ts
@@ -0,0 +1,24 @@
+import { NgModule } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { RouterModule } from '@angular/router';
+import { SlidesModule, SlidesRoutes } from '@ng360/slides';
+import { FeedbackModule } from '@codelab/feedback';
+import { CodeDemoModule } from '@codelab/code-demos';
+import { TemplatesComponent } from './templates.component';
+import { CodelabComponentsModule } from '../../../components/codelab-components.module';
+
+const routes = RouterModule.forChild([...SlidesRoutes.get(TemplatesComponent)]);
+
+@NgModule({
+ imports: [
+ routes,
+ CodeDemoModule,
+ FeedbackModule,
+ CodelabComponentsModule,
+ SlidesModule,
+ FormsModule
+ ],
+ declarations: [TemplatesComponent],
+ exports: [TemplatesComponent]
+})
+export class TemplatesModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript-routing.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript-routing.module.ts
new file mode 100644
index 000000000..c24c37711
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript-routing.module.ts
@@ -0,0 +1,27 @@
+import { Component, NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { SlidesRoutes } from '@ng360/slides';
+import { TypeScriptComponent } from './typescript/typescript.component';
+
+@Component({
+ // tslint:disable-next-line:component-selector
+ selector: 'ignored',
+ template: ' '
+})
+export class EmptyTypeScriptComponent {}
+
+const routes = [
+ {
+ path: '',
+ component: EmptyTypeScriptComponent,
+ children: [...SlidesRoutes.get(TypeScriptComponent)]
+ }
+];
+
+@NgModule({
+ declarations: [EmptyTypeScriptComponent],
+ entryComponents: [EmptyTypeScriptComponent],
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule]
+})
+export class TypeScriptRoutingModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript.module.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript.module.ts
new file mode 100644
index 000000000..4a5b5c5bc
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript.module.ts
@@ -0,0 +1,11 @@
+import { NgModule } from '@angular/core';
+import { TypeScriptComponent } from './typescript/typescript.component';
+import { TypeScriptRoutingModule } from './typescript-routing.module';
+import { TypeScriptSvgComponent } from './typescript/typescript-svg/typescript-svg.component';
+import { SharedModule } from '../../../shared/shared.module';
+
+@NgModule({
+ declarations: [TypeScriptComponent, TypeScriptSvgComponent],
+ imports: [SharedModule, TypeScriptRoutingModule]
+})
+export class TypeScriptModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript/code/app.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript/code/app.ts
new file mode 100644
index 000000000..777c5d604
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript/code/app.ts
@@ -0,0 +1 @@
+export const value = { value: 4 };
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript/code/code.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript/code/code.ts
new file mode 100644
index 000000000..99e2b9d86
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript/code/code.ts
@@ -0,0 +1,3 @@
+export { ts } from '../../../../../../../../../ng2ts/code';
+
+export const app_ts_AST = {};
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript/code/mini-exercise-test.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript/code/mini-exercise-test.ts
new file mode 100644
index 000000000..ddcf0f9cb
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript/code/mini-exercise-test.ts
@@ -0,0 +1,39 @@
+import { value } from './app';
+import { app_ts_AST, ts } from './code';
+
+declare const it, describe;
+
+function getFunctionNode(code) {
+ let functionNode;
+
+ /**
+ * Fancy: Require the actual source code, and search in it.
+ */
+ function findFunctionNode(node) {
+ if (
+ node.kind === ts.SyntaxKind.FunctionDeclaration &&
+ node.name.text === 'add'
+ ) {
+ functionNode = node;
+ }
+ ts.forEachChild(node, findFunctionNode);
+ }
+
+ findFunctionNode(code);
+ return functionNode;
+}
+
+describe('value', () => {
+ it(`@@specifyTheTypeForB`, () => {
+ const func = getFunctionNode(app_ts_AST);
+ chai.assert(
+ func.parameters[1].type &&
+ func.parameters[1].type.kind === ts.SyntaxKind.NumberKeyword,
+ 'Test failed: b is not a number'
+ );
+ });
+
+ it(`@@typescriptHighlightsErrorFix224`, () => {
+ chai.expect(value.value).equals(4);
+ });
+});
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript/typescript-svg/typescript-svg.component.html b/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript/typescript-svg/typescript-svg.component.html
new file mode 100644
index 000000000..38e8fbd02
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript/typescript-svg/typescript-svg.component.html
@@ -0,0 +1,164 @@
+
+
+
+
+
+
+
+
+ ES7
+
+
+ Decorators
+
+
+ Types
+
+
+ TypeScript
+
+
+ Classes
+
+
+ Modules
+
+
+ More...
+
+
+ ES6
+
+
+ ES5
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript/typescript-svg/typescript-svg.component.spec.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript/typescript-svg/typescript-svg.component.spec.ts
new file mode 100644
index 000000000..22e425248
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript/typescript-svg/typescript-svg.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { TypeScriptSvgComponent } from './typescript-svg.component';
+
+describe('TypeScriptSvgComponent', () => {
+ let component: TypeScriptSvgComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [TypeScriptSvgComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(TypeScriptSvgComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript/typescript-svg/typescript-svg.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript/typescript-svg/typescript-svg.component.ts
new file mode 100644
index 000000000..44cecc704
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript/typescript-svg/typescript-svg.component.ts
@@ -0,0 +1,11 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'codelab-typescript-svg',
+ templateUrl: './typescript-svg.component.html'
+})
+export class TypeScriptSvgComponent implements OnInit {
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/libs/utils/src/lib/sync/components/questions/common/question-list/question-list.component.css b/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript/typescript.component.css
similarity index 100%
rename from libs/utils/src/lib/sync/components/questions/common/question-list/question-list.component.css
rename to codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript/typescript.component.css
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript/typescript.component.html b/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript/typescript.component.html
new file mode 100644
index 000000000..52dc91ec7
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript/typescript.component.html
@@ -0,0 +1,471 @@
+
+
+ Or use shorthand function notation.
+
+
+ Error: this is clearly not a puppy
+
+
This is a number
+
+ Or use shorthand function notation.
+
+
+ (Also called arrow function)
+
+
+ Actually TypeScript can infer number here;
+
+
+ TypeScript can infer it's a string.
+
+
+ Can't add number and boolean
+
+
Can't slice a number
+
But can slice a string!
+
Works!
+
+ Type[] does the same thing.
+
+
This is a method.
+
+ This a common russian dog name.
+
+
+ That's how russian dogs talk.
+
+
+ Now we can instantiate (create) it
+
+
And use its methods
+
+ Later we'll have code here
+
+
+ Let's create more puppies
+
+
+ Var is still allowed but not recommended.
+
+
+ Let should be used instead of var.
+
+
+ Unlike var let is unavailable outside of this if.
+
+
+ Const is like let, but if you try to change it, TS will give you an error.
+
+
+ okay, definitely a boolean
+
+
+ Create a class called 'Codelab'
+
+
Export the class
+
Add a constructor
+
+ Make constructor take a parameter 'guests'
+
+
+ Specify the type for the guests parameter (hint: it's an array of a type
+ Guest)
+
+
+ Make the parameter public (note that now you can access it anywhere in the
+ class using this.guests)
+
+
+ Create new method 'getGuestsComing'
+
+
+
+ "b" in the code below is highlighted, because TypeScript is missing the
+ type. Specify the type for b.
+
+
+ With this information TypeScript can highlight the error. Fix it, make 2 + 2
+ = 4 again!
+
+
+
+ Modify getGuestsComing to filter the guests array return an array of guests
+ with the 'coming' property set to true.
+
+
+
+
+
+
+
+
+
+
+
+
+
Why TypeScript
+
+ JavaScript is a great language, but there's space for improvement:
+
+
+
+ JS is not type safe which makes it harder to develop large scale
+ applications
+
+
+ New features of the latest versions of JS standards (ES2018, ES2019) are
+ not supported well across all the browsers
+
+
+
+
ES stands for
+
ECMAScript , which is the name of the JavaScript language specification (standard)
+
+
+
+
+
TypeScript
+
+ This is why TypeScript has been created. Since TypeScript can be
+ compiled to JavaScript, it can be used in any modern browser.
+
+
+
+
+ TypeScript extends the latest version of JavaScript
+
+ TypeScript adds new features from the next version of JavaScript
+
+
+ On top of it, TypeScript adds an optional type system and decorators
+
+
+
+
+
+
+
+
+ Decorator looks like @twitter_handles, we'll learn more about them later
+
+
+
+
+
+ Type System
+
+ Below we have an add function, and we're adding 2 and 2. What could
+ go wrong?
+
+
+
+ Turns out it's possible to pass a string to this function and we get
+ 22 instead of 4 . Let's see how TypeScript can help address
+ this issue on the next slide
+
+
+
+
+
+
Type System
+
+ TypeScript uses ": " to specify the type information (e.g.
+ n: number ). Both a and b should be numbers. We
+ specified the type for a , now it's your turn!
+
+
+
The code above is editable!
+
+
+
+ Primitives (strings, numbers, etc...)
+
+
Below are more types we can use
+
+
+
+
+
+
+
+
Interfaces
+
+ TypeScript Interfaces allow to specify properties and methods for an
+ object.
+
+
+
+
+
+ Here, realPuppy is an implementation of the Puppy Interface.
+
+
+
+
+
Arrays
+
+ Array types are defined as Array{{ '<' }}Type{{ '>' }} or
+ Type[]
+
+
+
+ Here, each element in the betterCats array is an instance of the
+ Cat Interface.
+
+
+
+
+
+ Classes
+
TypeScript has classes , and Angular uses them heavily.
+
+ They are similar to classes in other languages, and are used to group
+ methods and properties together
+
+
+
+
+
+ Constructor
+
+ There's a special method on the class called constructor . It's run
+ when the class is instantiated and allows the class to take parameters
+
+
+
+
+
+
Access Modifiers
+
+ Constructor parameters marked as public (or private, or protected),
+ become class properties accessible as this.ParameterName within the
+ class
+
+
+
+ private or protected properties are not visible outside of the class.
+
+
+
+
+ Export
+
+ By the way, did you notice the export keyword before class? It is
+ used to share information between files. In the next slide, we'll show you
+ how to import and use this class in a different file
+
+
+
+
+
+
+
+
+
Import
+
Now we can use the Puppy class in the other file
+
+
+ import and export keywords are not just for classes. They
+ work with variables, functions and other things!
+
+
+
+
+ Filter (One last thing)
+
+ "filter " is an Array method that allows you to generate a new array
+ keeping only values that satisfy the condition
+
+
+
+
+
+
More
+
TypeScript supports lots of other cool features such as:
+
+
+ We won't cover them in detail, check out the
+ TypeScript
+ website!
+
+
+
+
+ Exercise
+
In the next slide we have a TypeScript exercise
+
+ Your task is to build a TypeScript class called Codelab which will take a
+ list of guests, and will have a method to output only the ones who are
+ coming.
+
+ The result will be as follows:
+
+
+
+
+
+
+
+
+
+
+
+ Milestone Completed
+
+
+
+ Now you should know enough TypeScript to start learning
+ Angular ! Read more about TypeScript on
+ TypeScript web site
+
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript/typescript.component.ts b/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript/typescript.component.ts
new file mode 100644
index 000000000..4a05c5d44
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/angular/typescript/typescript/typescript.component.ts
@@ -0,0 +1,212 @@
+import { Component, OnInit, ViewChild } from '@angular/core';
+
+import { extractMessages } from '@codelab/utils/src/lib/i18n/i18n-tools';
+import { ng2tsConfig } from '../../../../../../../../ng2ts/ng2ts';
+import {
+ javaScriptWithConsoleLog,
+ typeScriptWithConsoleLog
+} from '../../../../shared/helpers/helpers';
+
+declare const require;
+
+@Component({
+ selector: 'codelab-slides-typescript',
+ templateUrl: './typescript.component.html',
+ styleUrls: ['./typescript.component.css']
+})
+export class TypeScriptComponent implements OnInit {
+ t: { [key: string]: string };
+ // need to consider changing how we set code
+ @ViewChild('translations', { static: true }) translation;
+
+ // TODO(kirjs): we can't access tanslation in OnInit hook iwht static set to false
+ private exercises = [ng2tsConfig.milestones[0].exercises[1]];
+ private code: any = {};
+
+ ngOnInit(): void {
+ this.t = extractMessages(this.translation);
+
+ this.code = {
+ filter: typeScriptWithConsoleLog(`const numbers = [12,23,62,34,19,40,4,9];
+
+console.log(numbers.filter(function(n: number){
+ return n > 30;
+}));
+
+// ${this.t.useShorthandNotation}
+// ${this.t.calledArrowFunction}
+console.log(
+ numbers.filter(n => n > 30)
+);`),
+ moreTypes: {
+ codeInterfaces: `interface Puppy {
+ name: string;
+ age: number;
+};
+
+const realPuppy: Puppy = {
+ name: 'Pikachu',
+ age: 1
+};
+
+const notRealPuppy: Puppy = {
+ says: 'meow' // ${this.t.errorNotAPuppy}
+}`,
+ codeArraysMatch: /Array/,
+ codeArrays: typeScriptWithConsoleLog(`// Array
+const cats: Array = ['Simba', 'Aslan'];
+// ${this.t.typeDoesSameThing}
+const cats2: string[] = ['Simba', 'Aslan'];
+
+interface Cat {
+ name: string,
+ age: number
+}
+
+const betterCats: Cat[] = [
+ {name: 'Simba', age: 22},
+ {name: 'Aslan', age: 9999}
+];
+
+console.log(betterCats);`),
+ code: `const price: number = 100; // ${this.t.thisIsNumber}
+const tax = 20; // ${this.t.typescriptCanInferNumber}
+const productName = 'pikachu'; // ${this.t.typescriptCanInferString}
+const isHungry = true; // Boolean
+
+const weird = tax + isHungry; // ${this.t.cantAddNumAndBool}
+tax.slice(1,5); // ${this.t.cantSliceNum}
+productName.slice(1,5); // ${this.t.canSliceString}
+const total = price + tax; // ${this.t.works}`
+ },
+ varDeclaration: {
+ code: `// ${this.t.varAllowedNotRecommended}
+var v = 1;
+
+// ${this.t.letInsteadOfVar}
+let l = 1;
+
+if(true){
+ let ll = 1; // ${this.t.letUnavailableOutsideIfUnlikeIf}
+}
+console.log(ll); // undefined
+
+
+// ${this.t.constLikeLet}
+const x = 1;
+x = 2;`
+ },
+ stringType: {
+ code: `let fullName: string = 'Bob Bobbington';
+let sentence: string = \`Hello, my name is \${ fullName }.\`;`
+ },
+ stringType2: {
+ code: `let sentence: string = "Hello, my name is " + fullName + "."`
+ },
+ anyType: {
+ code: `let notSure: any = 4;
+notSure = "maybe a string instead";
+notSure = false; // ${this.t.definitelyBoolean}`
+ },
+ classDescription: {
+ code: typeScriptWithConsoleLog(`export class Puppy {
+ // ${this.t.commonDogName}
+ name = 'Bar Boss';
+
+ // ${this.t.thisIsMethod}
+ bark(){
+ // ${this.t.thatsHowRussianDogsTalk}
+ return this.name + ': Gav gav!!';
+ }
+}
+
+// ${this.t.nowWeCanInstantiate}
+var hotdog = new Puppy();
+// ${this.t.andUseItsMethods}
+console.log(hotdog.bark());
+`),
+ codeConstructor: typeScriptWithConsoleLog(`export class Puppy {
+ constructor(public name: string){
+ // ${this.t.laterWeWillHaveCode}
+ }
+ bark(){
+ return 'Gav! my name is ' + this.name;
+ }
+}
+
+var hotdog = new Puppy('Édouard');
+console.log(hotdog.bark());
+// ${this.t.letsCreateMorePuppies}
+var oscar = new Puppy('Oscar-Claude');
+console.log(oscar.bark());`),
+ codeExport: typeScriptWithConsoleLog(`export class Puppy {
+ constructor(public name: string){}
+ bark(){
+ return 'Gav! my name is ' + this.name;
+ }
+}`),
+ codeImport: typeScriptWithConsoleLog(
+ `import {Puppy} from './puppy';
+
+var hotdog = new Puppy('Édouard');
+console.log(hotdog.bark());
+// ${this.t.letsCreateMorePuppies}
+var oscar = new Puppy('Oscar-Claude');
+console.log(oscar.bark());`,
+ 'import "./app";',
+ undefined,
+ `export class Puppy {
+ constructor(public name: string){}
+ bark(){
+ return 'Gav! my name is ' + this.name;
+ }
+}`
+ ),
+ matches: {
+ classPuppyMatch: { 'app.ts': /class Puppy/ },
+ classMatch: /class/,
+ exportMatch: /export/,
+ importMatch: {
+ 'puppy.ts': /export/,
+ 'app.ts': /import/
+ },
+ arrayMatch: {
+ 'app.ts': [/Array/, /string\[]/]
+ },
+ constants: /const /,
+
+ constructorMatch: { 'app.ts': [/(public name: string)/, /Édouard/] },
+ modifierMatch: { 'app.ts': [/public name/, /this.name/] },
+ oscarMatch: /Oscar-Claude/
+ }
+ },
+ tsExercise: typeScriptWithConsoleLog(
+ `function add(a: number, b){
+ return a+b;
+};
+
+console.log(add(2, '2'));`,
+ undefined,
+ require(`!raw-loader!./code/mini-exercise-test.ts`)
+ .replace('@@specifyTheTypeForB', this.t.specifyTheTypeForB)
+ .replace(
+ '@@typescriptHighlightsErrorFix224',
+ this.t.typescriptHighlightsErrorFix224
+ )
+ ),
+
+ js2And2: (() => {
+ const code = javaScriptWithConsoleLog(
+ `function add(a, b){
+ return a+b;
+};
+
+console.log(add(2, '2'));`
+ );
+ (code.files[2] as any).bootstrap = false;
+ return code;
+ })(),
+ tsExerciseMatch: { 'app.ts': /'.*'/ }
+ };
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/codelabs-routing.module.ts b/codelab-master/apps/codelab/src/app/codelabs/codelabs-routing.module.ts
new file mode 100644
index 000000000..bdfbda2d3
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/codelabs-routing.module.ts
@@ -0,0 +1,26 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+import { IndexComponent } from '../components/index/index.component';
+
+const routes: Routes = [
+ { path: '', component: IndexComponent },
+ {
+ path: 'angular',
+ loadChildren: () =>
+ import('./angular/angular.module').then(m => m.AngularModule)
+ },
+ {
+ path: 'extra',
+ loadChildren: () => import('./extra/extra.module').then(m => m.ExtraModule)
+ },
+ {
+ path: 'about',
+ loadChildren: () => import('./about/about.module').then(m => m.AboutModule)
+ }
+];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule]
+})
+export class CodelabsRoutingModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/codelabs.module.ts b/codelab-master/apps/codelab/src/app/codelabs/codelabs.module.ts
new file mode 100644
index 000000000..f3a48169b
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/codelabs.module.ts
@@ -0,0 +1,8 @@
+import { NgModule } from '@angular/core';
+import { CodelabsRoutingModule } from './codelabs-routing.module';
+import { IndexModule } from '../components/index/index.module';
+
+@NgModule({
+ imports: [CodelabsRoutingModule, IndexModule]
+})
+export class CodelabsModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/extra/code-playground/code-playground.component.css b/codelab-master/apps/codelab/src/app/codelabs/extra/code-playground/code-playground.component.css
new file mode 100644
index 000000000..f91184da9
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/extra/code-playground/code-playground.component.css
@@ -0,0 +1,16 @@
+.vscode-gifs img {
+ width: 100%;
+ height: auto;
+ max-height: 100%;
+}
+
+.feature-title {
+ text-align: center;
+ font-style: italic;
+ margin: 20px 1px 1px 1px;
+}
+
+.vscode-gifs {
+ display: inline-block;
+ padding: 5px;
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/extra/code-playground/code-playground.component.html b/codelab-master/apps/codelab/src/app/codelabs/extra/code-playground/code-playground.component.html
new file mode 100644
index 000000000..ebe8b3059
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/extra/code-playground/code-playground.component.html
@@ -0,0 +1,145 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/extra/code-playground/code-playground.component.ts b/codelab-master/apps/codelab/src/app/codelabs/extra/code-playground/code-playground.component.ts
new file mode 100644
index 000000000..3b87d6b05
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/extra/code-playground/code-playground.component.ts
@@ -0,0 +1,90 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'codelab-code-playground',
+ templateUrl: './code-playground.component.html',
+ styleUrls: ['./code-playground.component.css']
+})
+export class CodePlaygroundComponent {}
+
+//
+//
+// // 1. code- components
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+//
+//
+// /// TypeScript
+// /// Javasdcript
+//
+// @Component({
+// selector: 'codelab-exercise',
+// template: ' ',
+// providers: [CodeSource]
+// })
+// class CodelabExercise {
+// constructor(cs: CodeSource) {
+// cs.addBeforeStep((cide) => {
+// code.before = 1
+// })
+// }
+//
+// getRoot(){
+// return this.parent || this;
+// }
+//
+// addCode(code: Record) {
+// this.code = code;
+// }
+//
+// getCode() {
+// if (this.code) {
+// return this.code;
+// }
+// return this.parent.getCode();
+// }
+//
+// getDeps() {
+// return this.parent && this.parent.getDeps() + this.deps;
+// }
+//
+// }
+//
+//
+// @Component({
+// selector: 'code-group',
+// template: ' ',
+// providers: [CodeSource]
+// })
+// class CodeGroup {
+// // { "main.ts": "console.log('')" }
+// @Input() code: Record;
+// // { "main.ts": "console.log('Hello')" }
+// @Input() solution: Record;
+// // // "main.ts"
+// // @Input() bootstrap: string;
+// // "angular, react"
+// @Input() deps: string;
+// @Input() compile: (code: Record) => Record;
+// // "browser, tests"
+// @Input() ui: string;
+// }
+//
+// @Component({
+// selector: 'code-preview',
+// template: '',
+// providers: [CodeSource]
+// })
+// class CodePreview {
+// constructor(private source: CodeSource) {
+// }
+// }
diff --git a/codelab-master/apps/codelab/src/app/codelabs/extra/code-playground/code-playground.module.ts b/codelab-master/apps/codelab/src/app/codelabs/extra/code-playground/code-playground.module.ts
new file mode 100644
index 000000000..0aacf6bea
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/extra/code-playground/code-playground.module.ts
@@ -0,0 +1,15 @@
+import { RouterModule } from '@angular/router';
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { SlidesModule, SlidesRoutes } from '@ng360/slides';
+import { FeedbackModule } from '@codelab/feedback';
+import { CodePlaygroundComponent } from './code-playground.component';
+
+const routes = RouterModule.forChild(SlidesRoutes.get(CodePlaygroundComponent));
+
+@NgModule({
+ imports: [routes, SlidesModule, FeedbackModule, CommonModule],
+ declarations: [CodePlaygroundComponent],
+ exports: [CodePlaygroundComponent]
+})
+export class CodePlaygroundModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/extra/extra-routing.module.ts b/codelab-master/apps/codelab/src/app/codelabs/extra/extra-routing.module.ts
new file mode 100644
index 000000000..9250d0180
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/extra/extra-routing.module.ts
@@ -0,0 +1,45 @@
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { environment } from '../../../environments/environment';
+import { FullLayoutComponent } from '../../containers/full-layout';
+
+let routes = [
+ {
+ path: '',
+ component: FullLayoutComponent,
+ children: [
+ {
+ path: 'code-playground',
+ loadChildren: () =>
+ import('./code-playground/code-playground.module').then(
+ m => m.CodePlaygroundModule
+ ),
+ name: 'code-playground',
+ description:
+ 'Learn how pipes transform input values to output values for display in a view',
+ page: 'extra'
+ },
+ {
+ path: 'rating-summary',
+ loadChildren: () =>
+ import('./rating-summary/rating-summary.module').then(
+ m => m.RatingSummaryModule
+ ),
+ name: 'rating-summary',
+ description:
+ 'Learn how pipes transform input values to output values for display in a view',
+ page: 'extra'
+ }
+ ]
+ }
+];
+
+if (environment.production) {
+ routes = routes.filter(r => r['prod']);
+}
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule]
+})
+export class ExtraRoutingModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/extra/extra.module.ts b/codelab-master/apps/codelab/src/app/codelabs/extra/extra.module.ts
new file mode 100644
index 000000000..9affcc7a2
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/extra/extra.module.ts
@@ -0,0 +1,19 @@
+import { NgModule } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { HttpClientModule } from '@angular/common/http';
+import { CommonModule } from '@angular/common';
+import { SharedModule } from '../../shared/shared.module';
+import { ExtraRoutingModule } from './extra-routing.module';
+import { FullLayoutModule } from '../../containers/full-layout/full-layout.module';
+
+@NgModule({
+ imports: [
+ SharedModule,
+ ExtraRoutingModule,
+ CommonModule,
+ HttpClientModule,
+ FormsModule,
+ FullLayoutModule
+ ]
+})
+export class ExtraModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/extra/rating-summary/rating-summary.component.css b/codelab-master/apps/codelab/src/app/codelabs/extra/rating-summary/rating-summary.component.css
new file mode 100644
index 000000000..dc8759818
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/extra/rating-summary/rating-summary.component.css
@@ -0,0 +1,8 @@
+.ratingsummary {
+ text-align: center;
+ margin-left: auto;
+ margin-right: auto;
+ margin-top: 60px;
+ border: 1px solid slategray;
+ padding: 20px;
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/extra/rating-summary/rating-summary.component.html b/codelab-master/apps/codelab/src/app/codelabs/extra/rating-summary/rating-summary.component.html
new file mode 100644
index 000000000..9aa2aa0cc
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/extra/rating-summary/rating-summary.component.html
@@ -0,0 +1,7 @@
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/extra/rating-summary/rating-summary.component.ts b/codelab-master/apps/codelab/src/app/codelabs/extra/rating-summary/rating-summary.component.ts
new file mode 100644
index 000000000..41fd538df
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/extra/rating-summary/rating-summary.component.ts
@@ -0,0 +1,10 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'codelab-slides-rating-summary',
+ templateUrl: './rating-summary.component.html',
+ styleUrls: ['./rating-summary.component.css']
+})
+export class RatingSummaryComponent implements OnInit {
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/extra/rating-summary/rating-summary.module.ts b/codelab-master/apps/codelab/src/app/codelabs/extra/rating-summary/rating-summary.module.ts
new file mode 100644
index 000000000..041c591df
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/extra/rating-summary/rating-summary.module.ts
@@ -0,0 +1,37 @@
+import { AngularFireModule } from '@angular/fire';
+import { AngularFireDatabaseModule } from '@angular/fire/database';
+import { AngularFireAuthModule } from '@angular/fire/auth';
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { CommonModule } from '@angular/common';
+import { HttpClientModule } from '@angular/common/http';
+import { SlidesModule, SlidesRoutes } from '@ng360/slides';
+import { FeedbackModule } from '@codelab/feedback';
+import { BrowserWindowModule } from '@codelab/browser';
+import { RatingSummaryComponent } from './rating-summary.component';
+import { environment } from '../../../../environments/environment';
+
+const routes = RouterModule.forChild(SlidesRoutes.get(RatingSummaryComponent));
+
+export const angularFire = AngularFireModule.initializeApp(
+ environment.firebaseConfig
+);
+
+@NgModule({
+ imports: [
+ routes,
+ BrowserWindowModule,
+
+ angularFire,
+ CommonModule,
+ HttpClientModule,
+ FeedbackModule,
+ SlidesModule,
+ AngularFireDatabaseModule,
+ AngularFireAuthModule
+ ],
+ declarations: [RatingSummaryComponent],
+ providers: [],
+ exports: [RatingSummaryComponent]
+})
+export class RatingSummaryModule {}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/extra/visual-studio-code/visual-studio-code.component.css b/codelab-master/apps/codelab/src/app/codelabs/extra/visual-studio-code/visual-studio-code.component.css
new file mode 100644
index 000000000..f91184da9
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/extra/visual-studio-code/visual-studio-code.component.css
@@ -0,0 +1,16 @@
+.vscode-gifs img {
+ width: 100%;
+ height: auto;
+ max-height: 100%;
+}
+
+.feature-title {
+ text-align: center;
+ font-style: italic;
+ margin: 20px 1px 1px 1px;
+}
+
+.vscode-gifs {
+ display: inline-block;
+ padding: 5px;
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/extra/visual-studio-code/visual-studio-code.component.html b/codelab-master/apps/codelab/src/app/codelabs/extra/visual-studio-code/visual-studio-code.component.html
new file mode 100644
index 000000000..208417db3
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/extra/visual-studio-code/visual-studio-code.component.html
@@ -0,0 +1,254 @@
+
+
+
+
+
+
+
+
+
What is Visual Studio Code?
+
+
+
+ Visual Studio Code is a free, open-source code editor developed by
+ Microsoft
+
+
+
+ built with Github Electron, and written in HTML, CSS,and Javascript
+
+
+ offers a robust extensible architecture and is highly customizable
+
+
+ built-in perks include:
+
+ Source Control
+ Extensions Marketplace
+ Debugger
+ Built-in Terminal
+
+
+
+
+
+
+
+
+
Why Use Visual Studio Code?
+
+ It has awesome tooling support and works especially well with TypeScript.
+
+
+ It comes with Intellisense , which provides code completion and
+ code info.
+
+
+
+
+
+
+
+
+
+
+
+
+
No Really, Why Use Visual Studio Code?
+
Missing Reference? Syntax Error? No problem!
+
+ Look for the lightbulb to shed some light on the issue and maybe even
+ automatically fix it for you.
+
+
+
+
+
+
+
+
+
+
OK, How Do I Get VSCode?
+
+
+
Interested? Curious?
+
Ready to join the cult?
+
+
+ Click
+ here to
+ download.
+
+ Run the installer
+ Enjoy!
+ Profit???
+
+
+
+
+
+
+
+
Popular extensions
+
+
+
+ are many extensions available for VSCode. Some good ones
+ include:
+
+
+ vscode-icons
+ - Adds icons to your file tree (ohhhh shiny)
+
+
+ Editor Config
+ - Editor Config Plugin for vs code
+
+
+ ESLint
+ - JS linter plugin
+
+
+ TSLint
+ - TypeScript linter plugin (Moarrrrr linter)
+
+
+ Beautify
+ - Beautify code, if you don't like JS-beautify
+
+
+ And many many more! check out the
+ offical site
+ and
+ Awesome VS Code
+ for more!
+
+
+
+
+
+
+
+
+
+
Common Keyboard Shortcuts
+
+ Formats your code (Shift+Alt+F)
+ Open New Window (Ctrl+Shift+N)
+ Open Project Folder (Ctrl+K,Ctrl+O)
+ Go to File (Ctrl+P)
+ Expand Selection (Shift+Alt+Right)
+ Search multiple File (Ctrl+Shift+F)
+ Go to Definition (F12)
+ Rename (F2)
+ Multiple Cursor(Alt+Mouse)
+
+ See more
+ here
+
+
+
+ Miss your old editor keymap? Try out of one of these extensions:
+ Vim ,
+ Atom ,
+ Sublime
+
+
+
+
+
+
What!? you forgot all the shortcuts already?
+
+ No problem, VSCode has your back. Hit (F1) or (ctrl+shift+p) and type the
+ command you want to perform
+
+
+
+
+
+
+
+
+
+
+
Well done! This is the end of the milestone!
+
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/codelabs/extra/visual-studio-code/visual-studio-code.component.ts b/codelab-master/apps/codelab/src/app/codelabs/extra/visual-studio-code/visual-studio-code.component.ts
new file mode 100644
index 000000000..529134734
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/extra/visual-studio-code/visual-studio-code.component.ts
@@ -0,0 +1,12 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'codelab-slides-visual-studio-code',
+ templateUrl: './visual-studio-code.component.html',
+ styleUrls: ['./visual-studio-code.component.css']
+})
+export class VisualStudioCodeComponent implements OnInit {
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/codelab/src/app/codelabs/extra/visual-studio-code/visual-studio-code.module.ts b/codelab-master/apps/codelab/src/app/codelabs/extra/visual-studio-code/visual-studio-code.module.ts
new file mode 100644
index 000000000..e1e6279be
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/codelabs/extra/visual-studio-code/visual-studio-code.module.ts
@@ -0,0 +1,26 @@
+import { RouterModule } from '@angular/router';
+import { FeedbackModule } from '@codelab/feedback';
+
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { SlidesModule, SlidesRoutes } from '@ng360/slides';
+import { VisualStudioCodeComponent } from './visual-studio-code.component';
+import { CodelabComponentsModule } from '../../../components/codelab-components.module';
+
+const routes = RouterModule.forChild(
+ SlidesRoutes.get(VisualStudioCodeComponent)
+);
+
+@NgModule({
+ imports: [
+ SlidesModule,
+ CodelabComponentsModule,
+ routes,
+
+ FeedbackModule,
+ CommonModule
+ ],
+ declarations: [VisualStudioCodeComponent],
+ exports: [VisualStudioCodeComponent]
+})
+export class VisualStudioCodeModule {}
diff --git a/codelab-master/apps/codelab/src/app/common.ts b/codelab-master/apps/codelab/src/app/common.ts
new file mode 100644
index 000000000..fe2d8a183
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/common.ts
@@ -0,0 +1,15 @@
+import { InjectionToken } from '@angular/core';
+import { Route } from '@angular/router';
+
+export type MenuRoutes = MenuRoute[];
+
+interface MenuRoute extends Route {
+ name?: string;
+ description?: string;
+ page?: string;
+ prod?: boolean;
+ translationIds?: string[];
+ children?: MenuRoutes;
+}
+
+export const MENU_ROUTES = new InjectionToken('menuRoutes');
diff --git a/codelab-master/apps/codelab/src/app/components/angular-routes/angular-routes.component.html b/codelab-master/apps/codelab/src/app/components/angular-routes/angular-routes.component.html
new file mode 100644
index 000000000..e4f98983f
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/angular-routes/angular-routes.component.html
@@ -0,0 +1,9 @@
+Lessons
+
+
+
+ {{ route.description }}
+
+
diff --git a/codelab-master/apps/codelab/src/app/components/angular-routes/angular-routes.component.scss b/codelab-master/apps/codelab/src/app/components/angular-routes/angular-routes.component.scss
new file mode 100644
index 000000000..f8e081dc5
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/angular-routes/angular-routes.component.scss
@@ -0,0 +1,23 @@
+:host {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ margin: 2rem;
+ font-family: 'Helvetica Neue', sans-serif;
+ font-size: 30px;
+
+ ol {
+ margin-block-start: 0;
+
+ h2 {
+ font-size: 1.2em;
+ margin-block-end: 0.5em;
+ }
+ }
+}
+
+@media screen and (max-width: 500px) {
+ :host {
+ font-size: 20px;
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/components/angular-routes/angular-routes.component.ts b/codelab-master/apps/codelab/src/app/components/angular-routes/angular-routes.component.ts
new file mode 100644
index 000000000..5a73fbb48
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/angular-routes/angular-routes.component.ts
@@ -0,0 +1,12 @@
+import { ChangeDetectionStrategy, Component, Inject } from '@angular/core';
+import { MENU_ROUTES } from '../../common';
+
+@Component({
+ selector: 'codelab-angular-routes',
+ templateUrl: 'angular-routes.component.html',
+ styleUrls: ['angular-routes.component.scss'],
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class AngularRoutesComponent {
+ constructor(@Inject(MENU_ROUTES) readonly menuRoutes) {}
+}
diff --git a/codelab-master/apps/codelab/src/app/components/angular-routes/angular-routes.module.ts b/codelab-master/apps/codelab/src/app/components/angular-routes/angular-routes.module.ts
new file mode 100644
index 000000000..73a955855
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/angular-routes/angular-routes.module.ts
@@ -0,0 +1,11 @@
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { CommonModule } from '@angular/common';
+import { AngularRoutesComponent } from './angular-routes.component';
+
+@NgModule({
+ imports: [CommonModule, RouterModule],
+ declarations: [AngularRoutesComponent],
+ exports: [AngularRoutesComponent]
+})
+export class AngularRoutesModule {}
diff --git a/codelab-master/apps/codelab/src/app/components/angular-test-runner/angular-test-runner.component.css b/codelab-master/apps/codelab/src/app/components/angular-test-runner/angular-test-runner.component.css
new file mode 100644
index 000000000..9c7849792
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/angular-test-runner/angular-test-runner.component.css
@@ -0,0 +1,3 @@
+.runner {
+ display: none;
+}
diff --git a/codelab-master/apps/codelab/src/app/components/angular-test-runner/angular-test-runner.component.html b/codelab-master/apps/codelab/src/app/components/angular-test-runner/angular-test-runner.component.html
new file mode 100644
index 000000000..4c70cb613
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/angular-test-runner/angular-test-runner.component.html
@@ -0,0 +1,5 @@
+
+
diff --git a/codelab-master/apps/codelab/src/app/components/angular-test-runner/angular-test-runner.component.ts b/codelab-master/apps/codelab/src/app/components/angular-test-runner/angular-test-runner.component.ts
new file mode 100644
index 000000000..2ab42e29a
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/angular-test-runner/angular-test-runner.component.ts
@@ -0,0 +1,175 @@
+import {
+ AfterViewInit,
+ ChangeDetectorRef,
+ Component,
+ ElementRef,
+ EventEmitter,
+ Input,
+ OnChanges,
+ OnDestroy,
+ OnInit,
+ Output,
+ SimpleChanges,
+ ViewChild
+} from '@angular/core';
+import { createSystemJsSandbox } from '@codelab/code-demos/src/lib/shared/sandbox';
+import { ScriptLoaderService } from '@codelab/code-demos/src/lib/shared/script-loader.service';
+import babel_traverse from '@babel/traverse';
+import * as babylon from 'babylon';
+import * as babel_types from 'babel-types';
+import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
+import { Subscription } from 'rxjs/internal/Subscription';
+import { getTypeScript } from '@codelab/utils/src/lib/loaders/loaders';
+import { TestRunResult } from '@codelab/utils/src/lib/test-results/common';
+import { handleTestMessage } from './tests';
+
+const ts = getTypeScript();
+
+// TODO(kirjs): This is a duplicate
+export function addMetaInformation(sandbox, files: { [key: string]: string }) {
+ sandbox.evalJs(`System.registry.delete(System.normalizeSync('./code'));`);
+ (sandbox.iframe.contentWindow as any).System.register('code', [], function(
+ exports
+ ) {
+ return {
+ setters: [],
+ execute: function() {
+ exports('ts', ts);
+ exports('babylon', babylon);
+ exports('babel_traverse', babel_traverse);
+ exports('babel_types', babel_types);
+ Object.entries(files)
+ .filter(([moduleName]) => moduleName.match(/\.ts$/))
+ .forEach(([path, code]) => {
+ exports(path.replace(/[\/.-]/gi, '_'), code);
+ exports(
+ path.replace(/[\/.-]/gi, '_') + '_AST',
+ ts.createSourceFile(path, code, ts.ScriptTarget.ES5)
+ );
+ });
+ Object.entries(files)
+ .filter(([moduleName]) => moduleName.match(/\.html/))
+ .forEach(([path, code]) => {
+ const templatePath = path.replace(/[\/.-]/gi, '_');
+ exports(templatePath, code);
+ });
+ }
+ };
+ });
+}
+
+@Component({
+ selector: 'codelab-simple-angular-test-runner',
+ templateUrl: './angular-test-runner.component.html',
+ styleUrls: ['./angular-test-runner.component.css']
+})
+export class SimpleAngularTestRunnerComponent
+ implements OnInit, OnChanges, AfterViewInit, OnDestroy {
+ handleMessageBound: any;
+ @Output() solved: EventEmitter = new EventEmitter();
+ @Output() public selectFile: EventEmitter = new EventEmitter<
+ string
+ >();
+ @Input() translations: { [key: string]: string } = {};
+ @Input() code: any;
+ @Input() bootstrap: string;
+
+ @ViewChild('runner', { static: false }) runnerElement: ElementRef;
+
+ changedFilesSubject = new BehaviorSubject>({});
+ tests: any;
+ private subscription: Subscription;
+ result: TestRunResult = { tests: [] };
+
+ constructor(
+ private scriptLoaderService: ScriptLoaderService,
+ private cd: ChangeDetectorRef
+ ) {}
+
+ ngOnInit() {
+ this.handleMessageBound = message => {
+ this.tests = handleTestMessage(message, this.tests || []);
+
+ this.result = {
+ tests: this.tests.map(test => {
+ const name =
+ this.translations[test.title.replace('@@', '')] || test.title;
+ return { ...test, name, error: test.result };
+ })
+ };
+
+ if (message.data.type === 'testEnd') {
+ this.solved.emit(
+ this.tests.length > 0 && this.tests.every(test => test.pass)
+ );
+ }
+
+ this.cd.markForCheck();
+ };
+ window.addEventListener('message', this.handleMessageBound, false);
+ }
+
+ ngOnChanges(changes: SimpleChanges) {
+ if (changes.code) {
+ this.changedFilesSubject.next(changes.code.currentValue);
+ }
+ }
+
+ async ngAfterViewInit() {
+ const sandbox = await createSystemJsSandbox(
+ this.runnerElement.nativeElement,
+ {
+ id: 'testing',
+ url: '/assets/runner'
+ }
+ );
+
+ sandbox.setHtml(
+ this.code['index.html'] ||
+ '
'
+ );
+
+ sandbox.evalJs(this.scriptLoaderService.getScript('chai'));
+ sandbox.evalJs(this.scriptLoaderService.getScript('mocha'));
+ sandbox.evalJs(this.scriptLoaderService.getScript('test-bootstrap'));
+ sandbox.evalJs(this.scriptLoaderService.getScript('shim'));
+ sandbox.evalJs(this.scriptLoaderService.getScript('zone'));
+ sandbox.evalJs(this.scriptLoaderService.getScript('system-config'));
+ sandbox.evalJs(this.scriptLoaderService.getScript('ng-bundle'));
+
+ this.subscription = this.changedFilesSubject.subscribe(files => {
+ const hasErrors = Object.entries(files)
+ .filter(([path]) => path.match(/\.js$/))
+ .map(([path, code]) => {
+ try {
+ sandbox.evalJs(
+ `System.registry.delete(System.normalizeSync('./${path.replace(
+ '.js',
+ ''
+ )}'));`
+ );
+ addMetaInformation(sandbox, this.code);
+ sandbox.evalJs(code);
+ } catch (e) {
+ console.groupCollapsed(e.message);
+ console.log(e);
+ console.groupEnd();
+ return true;
+ }
+ return false;
+ })
+ .some(a => a);
+
+ if (!hasErrors) {
+ sandbox.evalJs(`System.import('${this.bootstrap}')`);
+ }
+ });
+ }
+
+ ngOnDestroy() {
+ if (this.subscription) {
+ this.subscription.unsubscribe();
+ this.subscription = null;
+ }
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/components/angular-test-runner/tests.ts b/codelab-master/apps/codelab/src/app/components/angular-test-runner/tests.ts
new file mode 100644
index 000000000..391046d1c
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/angular-test-runner/tests.ts
@@ -0,0 +1,27 @@
+export function handleTestMessage(message, tests) {
+ if (!message.data || !message.data.type) {
+ return tests;
+ }
+
+ if (message.data.type === 'testList') {
+ return message.data.tests.map(test => ({
+ title: test
+ }));
+ }
+
+ if (message.data.type === 'testEnd') {
+ return tests;
+ }
+
+ if (message.data.type === 'testResult') {
+ return tests.map(test => {
+ if (test.title === message.data.test.title) {
+ test.pass = message.data.pass;
+ test.result = message.data.result;
+ }
+ return test;
+ });
+ }
+
+ return tests;
+}
diff --git a/codelab-master/apps/codelab/src/app/components/babel-test-runner/babel-helpers.ts b/codelab-master/apps/codelab/src/app/components/babel-test-runner/babel-helpers.ts
new file mode 100644
index 000000000..cee8238e5
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/babel-test-runner/babel-helpers.ts
@@ -0,0 +1,215 @@
+import * as T from 'babel-types';
+import * as babylon from 'babylon';
+import babel_traverse from '@babel/traverse';
+import { getTypeScript } from '@codelab/utils/src/lib/loaders/loaders';
+import * as TsTypes from 'typescript';
+
+const ts = getTypeScript();
+
+function matchesValue(actual, expected) {
+ if (!actual) {
+ return false;
+ }
+ if (expected instanceof RegExp) {
+ return expected.test(actual);
+ }
+
+ return actual.trim() === expected.trim();
+}
+
+export const expectClass = name => ({ node, parent }) =>
+ T.isIdentifier(node, { name }) &&
+ T.isClassDeclaration(parent, { superClass: null });
+
+export const expectExportedClass = name => ({ node, parent, parentPath }) =>
+ expectClass(name)({ node, parent }) &&
+ T.isExportNamedDeclaration(parentPath.parent);
+
+export const expectDecorator = name => ({ node }) =>
+ T.isDecorator(node) && node.expression.callee.name === name;
+
+export const expectDecoratorPropertyStringValue = (
+ decoratorName,
+ keyName,
+ value
+) => path => {
+ function matchesTemplateLiteral() {
+ return (
+ T.isTemplateLiteral(path.node) &&
+ matchesValue(path.node.quasis[0].value.raw, value)
+ );
+ }
+
+ function matchesStringLiteral() {
+ return T.isStringLiteral(path.node) && matchesValue(path.node.value, value);
+ }
+
+ return (
+ (matchesTemplateLiteral() || matchesStringLiteral()) &&
+ T.isObjectProperty(path.parent) &&
+ path.parent.key.name === keyName &&
+ path.findParent(T.isDecorator).node.expression.callee.name === decoratorName
+ );
+};
+
+export function babelTestSuite(filePath, tests) {
+ return function test(files) {
+ const results = tests.map(({ title }) => ({ title, pass: false }));
+ const code = files[filePath];
+
+ const ast = babylon.parse(code, {
+ sourceType: 'module',
+ plugins: ['decorators']
+ });
+
+ babel_traverse(ast, {
+ enter(path) {
+ tests.forEach((testConfig, index) => {
+ try {
+ results[index].pass =
+ results[index].pass || testConfig.condition(path);
+ } catch (e) {
+ console.log(e);
+ }
+ });
+ }
+ });
+
+ return results;
+ };
+}
+
+export type Predicate = (node: TsTypes.Node) => boolean;
+
+export class MiniTsQuery {
+ constructor(private readonly ast: TsTypes.Node) {}
+
+ some(predicate: Predicate) {
+ let result = false;
+
+ this.traverse(this.ast, node => {
+ if (predicate(node)) {
+ result = true;
+ }
+ });
+
+ return result;
+ }
+
+ findOne(predicate) {
+ let result;
+
+ this.traverse(this.ast, node => {
+ if (!result && predicate(node)) {
+ result = node;
+ }
+ });
+
+ return result;
+ }
+
+ hasOne(predicate) {
+ return !!this.findOne(predicate);
+ }
+
+ hasIdentifier(identifier: string) {
+ return !!this.getIdentifier(identifier);
+ }
+
+ getIdentifier(identifier: string) {
+ return this.findOne(
+ node => ts.isIdentifier(node) && node.text === identifier
+ );
+ }
+
+ hasConstructorParam(identifier: string, type: string) {
+ const node = this.findOne(
+ node => ts.isIdentifier(node) && node.text === identifier
+ );
+
+ return node ? node.parent.type.typeName.text === type : undefined;
+ }
+
+ hasVariableDeclaration(identifier: string) {
+ const node = this.getIdentifier(identifier);
+ return node && ts.isVariableDeclaration(node.parent) ? node : undefined;
+ }
+
+ hasDecorator(type: string) {
+ return !!this.getDecorator(type);
+ }
+
+ hasDecoratorValue(decoratorType: string, property: string, type: string) {
+ const decorator = this.getDecorator(decoratorType);
+ if (
+ decorator.expression &&
+ ts.isCallExpression(decorator.expression) &&
+ decorator.expression.arguments &&
+ decorator.expression.arguments[0] &&
+ ts.isObjectLiteralExpression(decorator.expression.arguments[0])
+ ) {
+ return (decorator.expression.arguments[0] as any).properties
+ .filter(prop => prop && prop.name && prop.name.text === property)
+ .some(arrayValue =>
+ arrayValue.initializer.elements.some(a => a.text === type)
+ );
+ }
+ return false;
+ }
+
+ hasProvider(type: string) {
+ return this.hasDecoratorValue('NgModule', 'providers', 'VideoService');
+ }
+
+ getDecorator(type: string): TsTypes.Decorator {
+ return this.findOne(node => {
+ return (
+ ts.isDecorator(node) &&
+ node.expression &&
+ ts.isCallExpression(node.expression) &&
+ node.expression.expression &&
+ ts.isIdentifier(node.expression.expression) &&
+ node.expression.expression.text === type
+ );
+ });
+ }
+
+ private traverse(node, callback) {
+ callback(node);
+ ts.forEachChild(node, node => this.traverse(node, callback));
+ }
+}
+
+export function tsAstTestSuite(tests) {
+ return function test(files) {
+ const results = tests.map(({ title }) => ({ title, pass: false }));
+ const astCache = {};
+
+ function getAst(filePath) {
+ if (!astCache[filePath]) {
+ astCache[filePath] = new MiniTsQuery(
+ ts.createSourceFile(
+ filePath,
+ files[filePath],
+ ts.ScriptTarget.ES2015,
+ /*setParentNodes */ true
+ )
+ );
+ }
+ return astCache[filePath];
+ }
+
+ tests.forEach((testConfig, index) => {
+ try {
+ if (!testConfig.file) {
+ throw new Error('test must specify a file');
+ }
+ results[index].pass =
+ results[index].pass || testConfig.condition(getAst(testConfig.file));
+ } catch (e) {
+ console.log(e);
+ }
+ });
+ return results;
+ };
+}
diff --git a/codelab-master/apps/codelab/src/app/components/babel-test-runner/babel-test-runner.component.css b/codelab-master/apps/codelab/src/app/components/babel-test-runner/babel-test-runner.component.css
new file mode 100644
index 000000000..9c7849792
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/babel-test-runner/babel-test-runner.component.css
@@ -0,0 +1,3 @@
+.runner {
+ display: none;
+}
diff --git a/codelab-master/apps/codelab/src/app/components/babel-test-runner/babel-test-runner.component.html b/codelab-master/apps/codelab/src/app/components/babel-test-runner/babel-test-runner.component.html
new file mode 100644
index 000000000..4630a70e1
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/babel-test-runner/babel-test-runner.component.html
@@ -0,0 +1 @@
+
diff --git a/codelab-master/apps/codelab/src/app/components/babel-test-runner/babel-test-runner.component.ts b/codelab-master/apps/codelab/src/app/components/babel-test-runner/babel-test-runner.component.ts
new file mode 100644
index 000000000..e14de24b3
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/babel-test-runner/babel-test-runner.component.ts
@@ -0,0 +1,70 @@
+import {
+ AfterViewInit,
+ Component,
+ EventEmitter,
+ Input,
+ OnChanges,
+ Output,
+ SimpleChanges
+} from '@angular/core';
+import { TestInfo } from '../../shared/interfaces/test-info';
+import { FileConfig } from '../../shared/interfaces/file-config';
+import { TestRunResult } from '@codelab/utils/src/lib/test-results/common';
+
+declare const require;
+
+@Component({
+ selector: 'codelab-babel-test-runner',
+ templateUrl: './babel-test-runner.component.html',
+ styleUrls: ['./babel-test-runner.component.css']
+})
+export class BabelTestRunnerComponent implements AfterViewInit, OnChanges {
+ @Input() bootstrap: string;
+ tests: Array = [];
+ @Input() translations: { [key: string]: string } = {};
+ @Input() code: any;
+ @Output() solved: EventEmitter = new EventEmitter();
+
+ constructor() {}
+
+ result: TestRunResult = { tests: [] };
+
+ ngOnChanges(changes: SimpleChanges) {
+ if (changes.code) {
+ this.run(this.code);
+ }
+ }
+
+ run(files: any) {
+ const test = files[this.bootstrap + '.ts.execute'];
+ try {
+ this.tests = test(files);
+ this.result = {
+ tests: this.tests.map(test => {
+ const name =
+ this.translations[test.title.replace('@@', '')] || test.title;
+
+ return {
+ ...test,
+ name,
+ error: test.result,
+ pass: !!test.pass
+ };
+ })
+ };
+
+ const isSolved = this.result.tests.every(a => a.pass);
+ this.solved.emit(isSolved);
+ } catch (e) {
+ this.tests.find(t => !t.pass).result = '[Parsing error]' + e;
+ }
+ }
+
+ selectFile(file: FileConfig) {
+ // this.parent.currentFile = file;
+ }
+
+ ngAfterViewInit(): void {
+ // this.parent.files$.subscribe(files => requestAnimationFrame(() => this.run(files)));
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/components/breadcrumb/breadcrumb.component.css b/codelab-master/apps/codelab/src/app/components/breadcrumb/breadcrumb.component.css
new file mode 100644
index 000000000..93fd784f6
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/breadcrumb/breadcrumb.component.css
@@ -0,0 +1,13 @@
+a {
+ text-decoration: none;
+ font-weight: 300;
+}
+
+span {
+ cursor: pointer;
+}
+
+span.arrow {
+ font-size: 0.5em;
+ vertical-align: middle;
+}
diff --git a/codelab-master/apps/codelab/src/app/components/breadcrumb/breadcrumb.component.html b/codelab-master/apps/codelab/src/app/components/breadcrumb/breadcrumb.component.html
new file mode 100644
index 000000000..9fe1e6beb
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/breadcrumb/breadcrumb.component.html
@@ -0,0 +1,20 @@
+
+ Angular Codelab {{ separator }}
+
+ {{ active }} ▼
+
+ {{ separator }}
+
+
+
+
+ {{ milestone.name }}
+
+
diff --git a/codelab-master/apps/codelab/src/app/components/breadcrumb/breadcrumb.component.spec.ts b/codelab-master/apps/codelab/src/app/components/breadcrumb/breadcrumb.component.spec.ts
new file mode 100644
index 000000000..e9e2511a6
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/breadcrumb/breadcrumb.component.spec.ts
@@ -0,0 +1,40 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { BreadcrumbComponent } from './breadcrumb.component';
+import { ActivatedRoute } from '@angular/router';
+import { MENU_ROUTES } from '../../common';
+import { CodelabComponentsModule } from '../codelab-components.module';
+import { RouterTestingModule } from '@angular/router/testing';
+
+describe('BreadcrumbComponent', () => {
+ let component: BreadcrumbComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [CodelabComponentsModule, RouterTestingModule],
+ providers: [
+ {
+ provide: ActivatedRoute,
+ useValue: {
+ pathFromRoot: [{ routeConfig: { name: 'lol' } }]
+ }
+ },
+ {
+ provide: MENU_ROUTES,
+ useValue: []
+ }
+ ]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(BreadcrumbComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/codelab/src/app/components/breadcrumb/breadcrumb.component.ts b/codelab-master/apps/codelab/src/app/components/breadcrumb/breadcrumb.component.ts
new file mode 100644
index 000000000..5932fb1ae
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/breadcrumb/breadcrumb.component.ts
@@ -0,0 +1,22 @@
+import { Component, Inject } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+import { MENU_ROUTES } from '../../common';
+
+@Component({
+ selector: 'codelab-breadcrumb',
+ templateUrl: './breadcrumb.component.html',
+ styleUrls: ['./breadcrumb.component.css']
+})
+export class BreadcrumbComponent {
+ active: string;
+ readonly separator = '/';
+
+ constructor(
+ private activatedRoute: ActivatedRoute,
+ @Inject(MENU_ROUTES) readonly menuRoutes
+ ) {
+ this.active = this.activatedRoute.pathFromRoot.find(
+ route => route.routeConfig && route.routeConfig['name']
+ ).routeConfig['name'];
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/buttons-nav-bar.component.html b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/buttons-nav-bar.component.html
new file mode 100644
index 000000000..cf0620136
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/buttons-nav-bar.component.html
@@ -0,0 +1,7 @@
+
diff --git a/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/buttons-nav-bar.component.scss b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/buttons-nav-bar.component.scss
new file mode 100644
index 000000000..4a8fc6119
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/buttons-nav-bar.component.scss
@@ -0,0 +1,42 @@
+:host ::ng-deep {
+ .btn-bar {
+ z-index: 110;
+ }
+
+ button:focus {
+ outline: 0;
+ }
+
+ .menu-bar-btn {
+ width: 45px;
+ height: 45px;
+ border-radius: 50%;
+ background: no-repeat center white;
+ box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
+ margin-left: 10px;
+ cursor: pointer;
+ border: none;
+ padding: 0;
+ }
+}
+
+::ng-deep {
+ .modal-title {
+ margin: 0 0 10px 0;
+ }
+
+ .buttons-nav-bar-modal-content-wrapper {
+ padding: 8px;
+ font-weight: 300;
+ font-family: 'Helvetica Neue', sans-serif;
+ }
+
+ @media screen and (max-width: 350px) {
+ .cdk-overlay-pane {
+ width: 100%;
+ }
+ .buttons-nav-bar-modal-content-wrapper {
+ width: 100%;
+ }
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/buttons-nav-bar.component.ts b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/buttons-nav-bar.component.ts
new file mode 100644
index 000000000..e2252579d
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/buttons-nav-bar.component.ts
@@ -0,0 +1,8 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'codelab-buttons-nav-bar',
+ templateUrl: './buttons-nav-bar.component.html',
+ styleUrls: ['./buttons-nav-bar.component.scss']
+})
+export class ButtonsNavBarComponent {}
diff --git a/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/buttons-nav-bar.module.ts b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/buttons-nav-bar.module.ts
new file mode 100644
index 000000000..6686c061c
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/buttons-nav-bar.module.ts
@@ -0,0 +1,29 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { ButtonsNavBarComponent } from './buttons-nav-bar.component';
+import { FeedbackModule } from '@codelab/feedback';
+import { FirebaseLoginModule } from '@codelab/firebase-login';
+import { MenuGithubWidgetModule } from './menu-github-widget/menu-github-widget.module';
+import { MenuShortcutWidgetModule } from './menu-shortcut-widget/menu-shortcut-widget.module';
+import { MenuFullscreenWidgetComponent } from './menu-fullscreen-widget/menu-fullscreen-widget.component';
+import { DirectivesModule } from '../../directives/directives.module';
+
+@NgModule({
+ imports: [
+ CommonModule,
+ FeedbackModule,
+ FirebaseLoginModule,
+ MenuGithubWidgetModule,
+ MenuShortcutWidgetModule,
+ DirectivesModule
+ ],
+ declarations: [ButtonsNavBarComponent, MenuFullscreenWidgetComponent],
+ exports: [
+ ButtonsNavBarComponent,
+ FeedbackModule,
+ FirebaseLoginModule,
+ MenuGithubWidgetModule,
+ MenuShortcutWidgetModule
+ ]
+})
+export class ButtonsNavBarModule {}
diff --git a/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-fullscreen-widget/menu-fullscreen-widget.component.html b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-fullscreen-widget/menu-fullscreen-widget.component.html
new file mode 100644
index 000000000..a5f77cf56
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-fullscreen-widget/menu-fullscreen-widget.component.html
@@ -0,0 +1,3 @@
+
diff --git a/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-fullscreen-widget/menu-fullscreen-widget.component.scss b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-fullscreen-widget/menu-fullscreen-widget.component.scss
new file mode 100644
index 000000000..a6c31c91f
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-fullscreen-widget/menu-fullscreen-widget.component.scss
@@ -0,0 +1,15 @@
+.menu-bar-btn {
+ width: 45px;
+ height: 45px;
+ border-radius: 50%;
+ background: no-repeat center #ecf0f1;
+ box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
+ margin-left: 10px;
+ cursor: pointer;
+ border: none;
+ padding: 0;
+
+ img {
+ width: 60%;
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-fullscreen-widget/menu-fullscreen-widget.component.spec.ts b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-fullscreen-widget/menu-fullscreen-widget.component.spec.ts
new file mode 100644
index 000000000..d33c10775
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-fullscreen-widget/menu-fullscreen-widget.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { MenuFullscreenWidgetComponent } from './menu-fullscreen-widget.component';
+
+describe('MenuFullscreenWidgetComponent', () => {
+ let component: MenuFullscreenWidgetComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [MenuFullscreenWidgetComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(MenuFullscreenWidgetComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-fullscreen-widget/menu-fullscreen-widget.component.ts b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-fullscreen-widget/menu-fullscreen-widget.component.ts
new file mode 100644
index 000000000..54304ea3c
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-fullscreen-widget/menu-fullscreen-widget.component.ts
@@ -0,0 +1,15 @@
+import { Component } from '@angular/core';
+import { FullScreenModeService } from '@ng360/slides';
+
+@Component({
+ selector: 'codelab-menu-fullscreen-widget',
+ templateUrl: './menu-fullscreen-widget.component.html',
+ styleUrls: ['./menu-fullscreen-widget.component.scss']
+})
+export class MenuFullscreenWidgetComponent {
+ constructor(private fullScreenService: FullScreenModeService) {}
+
+ openFullScreen() {
+ this.fullScreenService.toggleFullScreen();
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-github-widget/images/octocat.png b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-github-widget/images/octocat.png
new file mode 100644
index 000000000..edbc6f359
Binary files /dev/null and b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-github-widget/images/octocat.png differ
diff --git a/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-github-widget/menu-github-widget.component.css b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-github-widget/menu-github-widget.component.css
new file mode 100644
index 000000000..e18fab01c
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-github-widget/menu-github-widget.component.css
@@ -0,0 +1,39 @@
+.menu-bar-btn.github-widget {
+ background-color: white;
+}
+
+img {
+ width: 100%;
+}
+
+.octocat {
+ float: left;
+ width: 224px;
+ margin: 0 auto;
+ height: 224px;
+ background: url(images/octocat.png) no-repeat;
+ margin-right: 16px;
+}
+
+.content {
+ float: right;
+ width: 250px;
+}
+
+@media screen and (max-width: 350px) {
+ .octocat {
+ float: none;
+ margin: 5px auto;
+ display: block;
+ }
+
+ .content {
+ margin: 0 auto;
+ float: none;
+ text-align: center;
+ }
+}
+
+h3 {
+ font-weight: 300;
+}
diff --git a/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-github-widget/menu-github-widget.component.html b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-github-widget/menu-github-widget.component.html
new file mode 100644
index 000000000..dbac1cb56
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-github-widget/menu-github-widget.component.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
This Codelab is written in Angular!
+
+ It's 100% open-source and is available on
+
+ Github
+
+
+
Please ⭐ the repo if you find it useful.
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-github-widget/menu-github-widget.component.ts b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-github-widget/menu-github-widget.component.ts
new file mode 100644
index 000000000..4d5d2bc1a
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-github-widget/menu-github-widget.component.ts
@@ -0,0 +1,8 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'codelab-menu-github-widget',
+ templateUrl: './menu-github-widget.component.html',
+ styleUrls: ['./menu-github-widget.component.css']
+})
+export class MenuGithubWidgetComponent {}
diff --git a/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-github-widget/menu-github-widget.module.ts b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-github-widget/menu-github-widget.module.ts
new file mode 100644
index 000000000..6151822bf
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-github-widget/menu-github-widget.module.ts
@@ -0,0 +1,11 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { MatMenuModule } from '@angular/material/menu';
+import { MenuGithubWidgetComponent } from './menu-github-widget.component';
+
+@NgModule({
+ imports: [CommonModule, MatMenuModule],
+ declarations: [MenuGithubWidgetComponent],
+ exports: [MenuGithubWidgetComponent]
+})
+export class MenuGithubWidgetModule {}
diff --git a/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-shortcut-widget/menu-shortcut-widget.component.css b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-shortcut-widget/menu-shortcut-widget.component.css
new file mode 100644
index 000000000..163b29dab
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-shortcut-widget/menu-shortcut-widget.component.css
@@ -0,0 +1,22 @@
+.menu-bar-btn.index-menu {
+ background-color: #ff594b;
+}
+
+ul,
+li {
+ margin: 0;
+ padding: 0;
+ list-style-type: none;
+}
+
+a {
+ text-decoration: none;
+ cursor: pointer;
+ display: block;
+ padding: 6px 10px;
+}
+
+a:hover {
+ background-color: #982a2a;
+ color: white;
+}
diff --git a/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-shortcut-widget/menu-shortcut-widget.component.html b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-shortcut-widget/menu-shortcut-widget.component.html
new file mode 100644
index 000000000..8895bb0e8
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-shortcut-widget/menu-shortcut-widget.component.html
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-shortcut-widget/menu-shortcut-widget.component.ts b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-shortcut-widget/menu-shortcut-widget.component.ts
new file mode 100644
index 000000000..fd7bcdcee
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-shortcut-widget/menu-shortcut-widget.component.ts
@@ -0,0 +1,11 @@
+import { Component, Inject } from '@angular/core';
+import { MENU_ROUTES } from '../../../common';
+
+@Component({
+ selector: 'codelab-menu-shortcut-widget',
+ templateUrl: './menu-shortcut-widget.component.html',
+ styleUrls: ['./menu-shortcut-widget.component.css']
+})
+export class MenuShortcutWidgetComponent {
+ constructor(@Inject(MENU_ROUTES) readonly menuRoutes) {}
+}
diff --git a/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-shortcut-widget/menu-shortcut-widget.module.ts b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-shortcut-widget/menu-shortcut-widget.module.ts
new file mode 100644
index 000000000..205a2436a
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/buttons-nav-bar/menu-shortcut-widget/menu-shortcut-widget.module.ts
@@ -0,0 +1,12 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { RouterModule } from '@angular/router';
+import { MatMenuModule } from '@angular/material/menu';
+import { MenuShortcutWidgetComponent } from './menu-shortcut-widget.component';
+
+@NgModule({
+ imports: [CommonModule, RouterModule, MatMenuModule],
+ declarations: [MenuShortcutWidgetComponent],
+ exports: [MenuShortcutWidgetComponent]
+})
+export class MenuShortcutWidgetModule {}
diff --git a/codelab-master/apps/codelab/src/app/components/codelab-components.module.ts b/codelab-master/apps/codelab/src/app/components/codelab-components.module.ts
new file mode 100644
index 000000000..5923330f2
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/codelab-components.module.ts
@@ -0,0 +1,62 @@
+import { NgModule } from '@angular/core';
+import { CodelabExerciseComponent } from './exercise/exercise.component';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+import { MatButtonModule } from '@angular/material/button';
+import { MatMenuModule } from '@angular/material/menu';
+import { MatSelectModule } from '@angular/material/select';
+import { RouterModule } from '@angular/router';
+import { DirectivesModule } from '../directives/directives.module';
+import { TitleSlideComponent } from './slides/title-slide/title-slide.component';
+import { CodelabClosingSlideComponent } from './slides/closing-slide/codelab-closing-slide.component';
+import { CodelabExercisePreviewComponent } from './exercise-preview/exercise-preview.component';
+import { CodelabExercisePlaygroundComponent } from './exercise-playground/codelab-exercise-playground.component';
+import { CodelabProgressBarComponent } from './codelab-progress-bar/codelab-progress-bar.component';
+import { BabelTestRunnerComponent } from './babel-test-runner/babel-test-runner.component';
+import { CodelabRippleAnimationComponent } from './slides/title-slide/ripple-animation/codelab-ripple-animation.component';
+import { SimpleAngularTestRunnerComponent } from './angular-test-runner/angular-test-runner.component';
+import { CodeDemoModule } from '@codelab/code-demos';
+import { CodelabPreviewComponent } from './slides-preview/codelab-preview.component';
+import { BreadcrumbComponent } from './breadcrumb/breadcrumb.component';
+import { TestResultsModule } from '@codelab/utils/src/lib/test-results/test-results.module';
+
+@NgModule({
+ imports: [
+ CommonModule,
+ FormsModule,
+ RouterModule,
+ CodeDemoModule,
+ MatButtonModule,
+ MatMenuModule,
+ MatSelectModule,
+ TestResultsModule,
+ DirectivesModule
+ ],
+ declarations: [
+ SimpleAngularTestRunnerComponent,
+ TitleSlideComponent,
+ BabelTestRunnerComponent,
+ BreadcrumbComponent,
+ CodelabExerciseComponent,
+ CodelabPreviewComponent,
+ CodelabClosingSlideComponent,
+ CodelabExercisePreviewComponent,
+ CodelabExercisePlaygroundComponent,
+ CodelabProgressBarComponent,
+ CodelabRippleAnimationComponent
+ ],
+ exports: [
+ SimpleAngularTestRunnerComponent,
+ TitleSlideComponent,
+ BabelTestRunnerComponent,
+ BreadcrumbComponent,
+ CodelabExerciseComponent,
+ CodelabPreviewComponent,
+ CodelabClosingSlideComponent,
+ CodelabExercisePreviewComponent,
+ CodelabExercisePlaygroundComponent,
+ CodelabProgressBarComponent,
+ CodelabRippleAnimationComponent
+ ]
+})
+export class CodelabComponentsModule {}
diff --git a/codelab-master/apps/codelab/src/app/components/codelab-progress-bar/codelab-progress-bar.component.css b/codelab-master/apps/codelab/src/app/components/codelab-progress-bar/codelab-progress-bar.component.css
new file mode 100644
index 000000000..eab6a02ec
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/codelab-progress-bar/codelab-progress-bar.component.css
@@ -0,0 +1,48 @@
+.progress-bar {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ z-index: 1;
+}
+
+.points-container {
+ display: flex;
+ height: 25px;
+}
+
+.points-container:hover .slide-block {
+ transition-duration: 0.5s;
+ height: 15px;
+}
+
+.slide-block {
+ flex-grow: 1;
+ height: 3px;
+ transition-duration: 0.5s;
+ background: #abb7b7;
+}
+
+.slide-block:hover {
+ background: #dadfe1;
+}
+
+.exercise-block {
+ background: #d35400;
+}
+
+.exercise-block:hover {
+ background: #f9690e;
+}
+
+.completed-slide {
+ background: #f89406;
+}
+
+.completed-slide:hover {
+ background: #e9d460;
+}
+
+.completed-slide.exercise-block {
+ background: #e67e22;
+}
diff --git a/codelab-master/apps/codelab/src/app/components/codelab-progress-bar/codelab-progress-bar.component.html b/codelab-master/apps/codelab/src/app/components/codelab-progress-bar/codelab-progress-bar.component.html
new file mode 100644
index 000000000..ef3ecf24d
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/codelab-progress-bar/codelab-progress-bar.component.html
@@ -0,0 +1,11 @@
+
diff --git a/codelab-master/apps/codelab/src/app/components/codelab-progress-bar/codelab-progress-bar.component.ts b/codelab-master/apps/codelab/src/app/components/codelab-progress-bar/codelab-progress-bar.component.ts
new file mode 100644
index 000000000..7b3ab8ef2
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/codelab-progress-bar/codelab-progress-bar.component.ts
@@ -0,0 +1,37 @@
+import { AfterViewInit, Component } from '@angular/core';
+import { SlidesDeckComponent } from '@ng360/slides';
+
+@Component({
+ selector: 'codelab-progress-bar',
+ templateUrl: './codelab-progress-bar.component.html',
+ styleUrls: ['./codelab-progress-bar.component.css']
+})
+export class CodelabProgressBarComponent implements AfterViewInit {
+ slides = [];
+ activeSlideIndex = 0;
+ tempSlideId = 0;
+
+ constructor(public deck: SlidesDeckComponent) {}
+
+ ngAfterViewInit() {
+ // Change detection complains if updating it right away.
+ requestAnimationFrame(() => {
+ this.slides = this.deck.slides;
+ this.activeSlideIndex = this.deck.activeSlideIndex;
+ });
+
+ this.deck.slideChange.subscribe(index => {
+ this.activeSlideIndex = index;
+ });
+ }
+
+ previewSlide(index) {
+ this.tempSlideId = this.activeSlideIndex;
+ this.deck.goToSlide(index);
+ }
+
+ goToSlide(index) {
+ this.deck.goToSlide(index);
+ this.tempSlideId = this.activeSlideIndex;
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/components/css/codelab-styles.scss b/codelab-master/apps/codelab/src/app/components/css/codelab-styles.scss
new file mode 100644
index 000000000..df5494111
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/css/codelab-styles.scss
@@ -0,0 +1,4 @@
+code-demo-file-path {
+ display: block;
+ margin: 1px 0;
+}
diff --git a/codelab-master/apps/codelab/src/app/components/exercise-playground/codelab-exercise-playground.component.css b/codelab-master/apps/codelab/src/app/components/exercise-playground/codelab-exercise-playground.component.css
new file mode 100644
index 000000000..4cef8a0ce
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/exercise-playground/codelab-exercise-playground.component.css
@@ -0,0 +1,4 @@
+:host {
+ display: flex;
+ flex-direction: column;
+}
diff --git a/codelab-master/apps/codelab/src/app/components/exercise-playground/codelab-exercise-playground.component.html b/codelab-master/apps/codelab/src/app/components/exercise-playground/codelab-exercise-playground.component.html
new file mode 100644
index 000000000..c443a9f6d
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/exercise-playground/codelab-exercise-playground.component.html
@@ -0,0 +1,32 @@
+
+
diff --git a/codelab-master/apps/codelab/src/app/components/exercise-playground/codelab-exercise-playground.component.ts b/codelab-master/apps/codelab/src/app/components/exercise-playground/codelab-exercise-playground.component.ts
new file mode 100644
index 000000000..e594dee53
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/exercise-playground/codelab-exercise-playground.component.ts
@@ -0,0 +1,14 @@
+import { Component, Input } from '@angular/core';
+import { CodelabExerciseComponent } from '../exercise/exercise.component';
+import { PreviewWindowType } from '@codelab/browser/src/lib/preview-window/preview-window.component';
+
+@Component({
+ selector: 'codelab-exercise-playground',
+ templateUrl: 'codelab-exercise-playground.component.html',
+ styleUrls: ['codelab-exercise-playground.component.css']
+})
+export class CodelabExercisePlaygroundComponent extends CodelabExerciseComponent {
+ @Input() allowSwitchingFiles = false;
+ @Input() path = '';
+ @Input() ui: PreviewWindowType = 'browser';
+}
diff --git a/codelab-master/apps/codelab/src/app/components/exercise-preview/exercise-preview.component.html b/codelab-master/apps/codelab/src/app/components/exercise-preview/exercise-preview.component.html
new file mode 100644
index 000000000..f847459cd
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/exercise-preview/exercise-preview.component.html
@@ -0,0 +1,8 @@
+
diff --git a/codelab-master/apps/codelab/src/app/components/exercise-preview/exercise-preview.component.ts b/codelab-master/apps/codelab/src/app/components/exercise-preview/exercise-preview.component.ts
new file mode 100644
index 000000000..f8b1d490e
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/exercise-preview/exercise-preview.component.ts
@@ -0,0 +1,21 @@
+import { Component, Input } from '@angular/core';
+import {
+ CodelabExerciseComponent,
+ extractSolutions
+} from '../exercise/exercise.component';
+import { convertExerciseToMap } from '../../../../../../ng2ts/ng2ts';
+
+@Component({
+ selector: 'codelab-exercise-preview',
+ templateUrl: 'exercise-preview.component.html'
+ // styleUrls: ['../exercise/code-demo-code-demo.component.css'],
+})
+export class CodelabExercisePreviewComponent extends CodelabExerciseComponent {
+ @Input() set exercise(exercise) {
+ const map = convertExerciseToMap(exercise);
+ this.filesConfig = exercise;
+ this.bootstrap = map.bootstrap;
+ this.code = extractSolutions(exercise.files);
+ this.update(this.code);
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/components/exercise/exercise.component.css b/codelab-master/apps/codelab/src/app/components/exercise/exercise.component.css
new file mode 100644
index 000000000..a0079869d
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/exercise/exercise.component.css
@@ -0,0 +1,24 @@
+.quarter {
+ width: 50vw;
+ height: 50vh;
+}
+
+.row {
+ display: flex;
+}
+
+.tests {
+ padding: 0.5vw;
+ box-sizing: border-box;
+ overflow-y: auto;
+}
+
+.solved-message {
+ margin-top: 16px;
+}
+
+.solved-message img {
+ display: block;
+ height: 280px;
+ margin-top: 16px;
+}
diff --git a/codelab-master/apps/codelab/src/app/components/exercise/exercise.component.html b/codelab-master/apps/codelab/src/app/components/exercise/exercise.component.html
new file mode 100644
index 000000000..6a53f3106
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/exercise/exercise.component.html
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+ Well done! Now you can go to the next slide
+
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/components/exercise/exercise.component.ts b/codelab-master/apps/codelab/src/app/components/exercise/exercise.component.ts
new file mode 100644
index 000000000..acc0331a2
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/exercise/exercise.component.ts
@@ -0,0 +1,70 @@
+import { ChangeDetectorRef, Component, Input } from '@angular/core';
+import { convertExerciseToMap } from '../../../../../../ng2ts/ng2ts';
+import { CodeDemoComponent } from '@codelab/code-demos/src/lib/code-demo/code-demo.component';
+
+function filterByFileType(type: string, files: Record) {
+ return Object.entries(files).reduce((changedFiles, [path, code]) => {
+ if (path.match(new RegExp(`\\\.${type}$`))) {
+ changedFiles[path] = code;
+ }
+ return changedFiles;
+ }, {});
+}
+
+export function extractSolutions(files: any[]) {
+ return files.reduce((result, file) => {
+ if (file.solution) {
+ result[file.path] = file.solution || file.template;
+ }
+
+ return result;
+ }, {});
+}
+
+export function getChanges(current, previous) {
+ return Object.keys(current).reduce((changedFiles, path) => {
+ if (current[path] !== previous[path]) {
+ changedFiles[path] = current[path];
+ }
+ return changedFiles;
+ }, {});
+}
+
+@Component({
+ selector: 'codelab-exercise',
+ templateUrl: 'exercise.component.html',
+ styleUrls: ['./exercise.component.css']
+})
+export class CodelabExerciseComponent extends CodeDemoComponent {
+ isSolved = false;
+
+ constructor(private readonly cdr: ChangeDetectorRef) {
+ super();
+ }
+
+ showDogs() {
+ this.cdr.markForCheck();
+ }
+
+ @Input() set exercise(exercise) {
+ const map = convertExerciseToMap(exercise);
+
+ if (!this.highlights) {
+ this.highlights = map.highlights;
+ }
+ this.bootstrap = map.bootstrap;
+ this.bootstrapTest = map.bootstrapTest;
+ if (!this.files) {
+ this.files = [exercise.files[this.openFileIndex].path];
+ }
+ this.filesConfig = exercise;
+ this.solutions = extractSolutions(this.filesConfig.files);
+ this.code = map.code;
+ this.update(map.code);
+ }
+
+ retrieveFile(file, code) {
+ const f = this.filesConfig.files.find(f => f.path === file);
+ return (f.before || '') + code + (f.after || '');
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/components/external-link-directive/external-link-directive.directive.spec.ts b/codelab-master/apps/codelab/src/app/components/external-link-directive/external-link-directive.directive.spec.ts
new file mode 100644
index 000000000..8c3e29e95
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/external-link-directive/external-link-directive.directive.spec.ts
@@ -0,0 +1,10 @@
+import { ExternalLinkDirectiveDirective } from './external-link-directive.directive';
+
+describe('ExternalLinkDirectiveDirective', () => {
+ it('should create an instance', () => {
+ const directive = new ExternalLinkDirectiveDirective({
+ nativeElement: document.createElement('a')
+ });
+ expect(directive).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/codelab/src/app/components/external-link-directive/external-link-directive.directive.ts b/codelab-master/apps/codelab/src/app/components/external-link-directive/external-link-directive.directive.ts
new file mode 100644
index 000000000..4cdb070da
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/external-link-directive/external-link-directive.directive.ts
@@ -0,0 +1,12 @@
+import { Directive, Input, ElementRef } from '@angular/core';
+
+@Directive({
+ // tslint:disable-next-line
+ selector: '[href]'
+})
+// TODO(meinou): Remove the second postfix
+export class ExternalLinkDirectiveDirective {
+ constructor({ nativeElement }: ElementRef) {
+ nativeElement.target = '_blank';
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/components/index/index.component.html b/codelab-master/apps/codelab/src/app/components/index/index.component.html
new file mode 100644
index 000000000..9caadc087
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/index/index.component.html
@@ -0,0 +1,75 @@
+
+
+ Create your first Angular app
+
+
Templates
+
+ Dependency-Injection
+
+
Component-Tree
+
Custom-Events
+
+ Angular is written in TypeScript, a superset of JavaScript. Learn
+ TypeScript.
+
+
+ Learn how to create and bootstrap your first Angular application
+
+
+ Learn how to use Angular templates
+
+
+ Learn how to provide dependencies to your code instead of hard-coding them
+
+
+ Learn how to structure your app with reusable components
+
+
+ Learn to bind to events.
+
+
+
+
+
+
+
+
+
Angular Codelab
+
+ Welcome to the interactive Angular Codelab. Here you can learn the basics
+ of Angular !
+
+
+
+ ▶
+
+
Learn TypeScript
+
Skip if you're familiar with TypeScript
+
+
+
+
+ ▶
+ Learn Angular
+
+
+
+
+
+ Or click here to see full contents...
+
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/components/index/index.component.scss b/codelab-master/apps/codelab/src/app/components/index/index.component.scss
new file mode 100644
index 000000000..844fb6086
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/index/index.component.scss
@@ -0,0 +1,104 @@
+.intro li a:hover {
+ text-decoration: underline;
+}
+
+.intro li a {
+ text-decoration: none;
+ color: #888;
+}
+
+.intro ul {
+ margin: 0;
+ padding: 0;
+}
+
+.intro li {
+ margin: 0;
+ padding: 0;
+ padding-left: 21px;
+ font-size: 1.3vw;
+ margin-bottom: 16px;
+}
+
+.intro li h2 {
+ font-size: 2vw;
+}
+
+.feedback-shift {
+ position: fixed;
+ right: 107px;
+ bottom: 1vh;
+}
+
+img .angular {
+ width: 30vw;
+}
+
+.learn-box:hover {
+ background: #eee;
+}
+
+.title {
+ color: #444;
+}
+
+.hint {
+ color: #666;
+ font-size: 3vw;
+}
+
+.learn-box.typescript {
+ opacity: 0.8;
+}
+
+.learn-box {
+ display: flex;
+ width: 100%;
+ font-size: 7vw;
+ justify-content: space-between;
+ background: #fafafa;
+ padding: 2vw;
+ margin-bottom: 2vw;
+ cursor: pointer;
+ border: 1px #999 solid;
+ border-radius: 10px;
+}
+
+.learn-box img {
+ width: 10vw;
+ height: 10vw;
+ font-size: 10px;
+}
+
+::ng-deep .slide {
+ display: block;
+}
+
+.play {
+ margin: 4vw 0;
+}
+
+.contents {
+ border-bottom: 1px #999 dashed;
+ display: inline-block;
+ cursor: pointer;
+ min-height: 20px;
+}
+
+::ng-deep {
+ .btn-bar {
+ z-index: 110;
+ }
+
+ .menu-bar-btn {
+ width: 45px;
+ height: 45px;
+ border-radius: 50%;
+ background: no-repeat center #3498db;
+ box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
+ margin-left: 10px;
+ cursor: pointer;
+ border: none;
+ padding: 0;
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/components/index/index.component.ts b/codelab-master/apps/codelab/src/app/components/index/index.component.ts
new file mode 100644
index 000000000..3e428730b
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/index/index.component.ts
@@ -0,0 +1,12 @@
+import { Component, ViewChild } from '@angular/core';
+
+@Component({
+ selector: 'codelab-slides-index',
+ templateUrl: './index.component.html',
+ styleUrls: ['./index.component.scss']
+})
+export class IndexComponent {
+ @ViewChild('translations', { static: false }) translations;
+
+ showContents: boolean;
+}
diff --git a/codelab-master/apps/codelab/src/app/components/index/index.module.ts b/codelab-master/apps/codelab/src/app/components/index/index.module.ts
new file mode 100644
index 000000000..4ef7ff965
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/index/index.module.ts
@@ -0,0 +1,26 @@
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { CommonModule } from '@angular/common';
+import { MatCardModule } from '@angular/material/card';
+import { SlidesModule } from '@ng360/slides';
+import { IndexComponent } from './index.component';
+import { ButtonsNavBarModule } from '../buttons-nav-bar/buttons-nav-bar.module';
+import { CodelabComponentsModule } from '../codelab-components.module';
+import { SyncModule } from '../../sync/sync.module';
+import { AngularRoutesModule } from '../angular-routes/angular-routes.module';
+
+@NgModule({
+ imports: [
+ CommonModule,
+ RouterModule,
+ ButtonsNavBarModule,
+ CodelabComponentsModule,
+ SlidesModule,
+ MatCardModule,
+ SyncModule,
+ AngularRoutesModule
+ ],
+ declarations: [IndexComponent],
+ exports: [IndexComponent]
+})
+export class IndexModule {}
diff --git a/libs/utils/src/lib/sync/components/questions/questions-admin/questions-admin.component.css b/codelab-master/apps/codelab/src/app/components/login/login.component.css
similarity index 100%
rename from libs/utils/src/lib/sync/components/questions/questions-admin/questions-admin.component.css
rename to codelab-master/apps/codelab/src/app/components/login/login.component.css
diff --git a/codelab-master/apps/codelab/src/app/components/login/login.component.html b/codelab-master/apps/codelab/src/app/components/login/login.component.html
new file mode 100644
index 000000000..414967fd6
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/login/login.component.html
@@ -0,0 +1,11 @@
+
+
+ user: {{ user.displayName || user.email }}
+ uid: {{ loginService.uid$ | async }}
+
+
+
+
+ Login with Github
+
+
diff --git a/codelab-master/apps/codelab/src/app/components/login/login.component.spec.ts b/codelab-master/apps/codelab/src/app/components/login/login.component.spec.ts
new file mode 100644
index 000000000..f7f8302c1
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/login/login.component.spec.ts
@@ -0,0 +1,26 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { getMockAngularFireProviders } from '@codelab/utils/src/lib/testing/mocks/angular-fire';
+import { LoginComponent } from './login.component';
+import { LoginModule } from './login.module';
+
+describe('LoginComponent', () => {
+ let component: LoginComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [LoginModule],
+ providers: [...getMockAngularFireProviders()]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(LoginComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/codelab/src/app/components/login/login.component.ts b/codelab-master/apps/codelab/src/app/components/login/login.component.ts
new file mode 100644
index 000000000..e3131dc29
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/login/login.component.ts
@@ -0,0 +1,20 @@
+import { Component } from '@angular/core';
+import { AngularFireAuth } from '@angular/fire/auth';
+import { LoginService } from '@codelab/firebase-login';
+import { auth } from 'firebase/app';
+
+@Component({
+ selector: 'codelab-login',
+ templateUrl: './login.component.html',
+ styleUrls: ['./login.component.css']
+})
+export class LoginComponent {
+ constructor(
+ private auth: AngularFireAuth,
+ readonly loginService: LoginService
+ ) {}
+
+ login() {
+ this.auth.auth.signInWithPopup(new auth.GoogleAuthProvider());
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/components/login/login.module.ts b/codelab-master/apps/codelab/src/app/components/login/login.module.ts
new file mode 100644
index 000000000..d028e3db7
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/login/login.module.ts
@@ -0,0 +1,12 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { MatButtonModule } from '@angular/material/button';
+import { MatCardModule } from '@angular/material/card';
+import { RouterModule } from '@angular/router';
+import { LoginComponent } from './login.component';
+
+@NgModule({
+ imports: [CommonModule, MatCardModule, RouterModule, MatButtonModule],
+ declarations: [LoginComponent]
+})
+export class LoginModule {}
diff --git a/codelab-master/apps/codelab/src/app/components/not-found/not-found.component.html b/codelab-master/apps/codelab/src/app/components/not-found/not-found.component.html
new file mode 100644
index 000000000..381e2dcdd
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/not-found/not-found.component.html
@@ -0,0 +1,15 @@
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/components/not-found/not-found.component.scss b/codelab-master/apps/codelab/src/app/components/not-found/not-found.component.scss
new file mode 100644
index 000000000..7158d4eb8
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/not-found/not-found.component.scss
@@ -0,0 +1,53 @@
+:host {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ height: 100%;
+ font-family: 'Helvetica Neue', sans-serif;
+
+ .message {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ .error-code {
+ font-size: 70px;
+ margin-right: 20px;
+ }
+
+ .error-message {
+ .header {
+ font-size: 20px;
+ font-weight: 600;
+ }
+
+ .subheader {
+ font-size: 14px;
+ }
+ }
+ }
+
+ nav {
+ max-width: 100%;
+ width: 400px;
+
+ ul {
+ display: flex;
+ justify-content: space-around;
+ width: 100%;
+ padding-inline-start: 0;
+
+ li {
+ list-style-type: none;
+ }
+ }
+ }
+}
+
+@media screen and (max-width: 500px) {
+ .container .message {
+ flex-direction: column;
+ text-align: center;
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/components/not-found/not-found.component.ts b/codelab-master/apps/codelab/src/app/components/not-found/not-found.component.ts
new file mode 100644
index 000000000..aa08d0927
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/not-found/not-found.component.ts
@@ -0,0 +1,24 @@
+import { Component, ChangeDetectionStrategy } from '@angular/core';
+
+@Component({
+ selector: 'codelab-not-found',
+ templateUrl: './not-found.component.html',
+ styleUrls: ['./not-found.component.scss'],
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class NotFoundComponent {
+ public routes = [
+ {
+ path: '',
+ name: 'Home'
+ },
+ {
+ path: '/angular/typescript',
+ name: 'Typescript'
+ },
+ {
+ path: '/angular',
+ name: 'Angular'
+ }
+ ];
+}
diff --git a/codelab-master/apps/codelab/src/app/components/not-found/not-found.module.ts b/codelab-master/apps/codelab/src/app/components/not-found/not-found.module.ts
new file mode 100644
index 000000000..ee30c845e
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/not-found/not-found.module.ts
@@ -0,0 +1,11 @@
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { CommonModule } from '@angular/common';
+import { ButtonsNavBarModule } from '../buttons-nav-bar/buttons-nav-bar.module';
+import { NotFoundComponent } from './not-found.component';
+
+@NgModule({
+ imports: [CommonModule, RouterModule, ButtonsNavBarModule],
+ declarations: [NotFoundComponent]
+})
+export class NotFoundModule {}
diff --git a/codelab-master/apps/codelab/src/app/components/slides-preview/codelab-preview.component.html b/codelab-master/apps/codelab/src/app/components/slides-preview/codelab-preview.component.html
new file mode 100644
index 000000000..513889466
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/slides-preview/codelab-preview.component.html
@@ -0,0 +1,14 @@
+
diff --git a/codelab-master/apps/codelab/src/app/components/slides-preview/codelab-preview.component.scss b/codelab-master/apps/codelab/src/app/components/slides-preview/codelab-preview.component.scss
new file mode 100644
index 000000000..06ed498e1
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/slides-preview/codelab-preview.component.scss
@@ -0,0 +1,48 @@
+.codelab-preview {
+ position: relative;
+ width: 100%;
+ height: 100%;
+}
+
+.codelab-preview.expanded {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 100;
+ background-color: #fff;
+}
+
+.preview-header {
+ position: absolute;
+ right: 1px;
+ top: 1px;
+}
+
+.button-expand {
+ outline: none;
+ width: 35px;
+ height: 35px;
+ padding: 0;
+ border: 0;
+ background-image: url('/assets/images/expand.png');
+ background-color: #fff;
+ background-size: 100% 100%;
+ cursor: pointer;
+
+ &:hover {
+ background-color: #eee;
+ }
+}
+
+iframe {
+ box-shadow: 0 0 1px #dddddd;
+ border: 0 solid;
+}
+
+.body,
+iframe {
+ width: 100%;
+ height: 100%;
+}
diff --git a/codelab-master/apps/codelab/src/app/components/slides-preview/codelab-preview.component.ts b/codelab-master/apps/codelab/src/app/components/slides-preview/codelab-preview.component.ts
new file mode 100644
index 000000000..f72483510
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/slides-preview/codelab-preview.component.ts
@@ -0,0 +1,44 @@
+import { Component, Input, OnInit } from '@angular/core';
+import { DomSanitizer } from '@angular/platform-browser';
+import { ActivatedRoute, Router } from '@angular/router';
+import { Location } from '@angular/common';
+
+@Component({
+ selector: 'codelab-preview',
+ templateUrl: './codelab-preview.component.html',
+ styleUrls: ['./codelab-preview.component.scss']
+})
+export class CodelabPreviewComponent implements OnInit {
+ @Input() milestone;
+ public isExpanded: boolean;
+ private iframeSource;
+
+ constructor(
+ private sanitizer: DomSanitizer,
+ private router: Router,
+ private activatedRoute: ActivatedRoute,
+ private location: Location
+ ) {}
+
+ ngOnInit() {
+ const url = this.location.prepareExternalUrl(
+ this.router
+ .createUrlTree(['.'], {
+ relativeTo: this.activatedRoute,
+ queryParams: {
+ milestone: this.milestone,
+ hideControls: true,
+ resize: true
+ },
+ queryParamsHandling: 'merge'
+ })
+ .toString()
+ );
+
+ this.iframeSource = this.sanitizer.bypassSecurityTrustResourceUrl(url);
+ }
+
+ expandToggle() {
+ return (this.isExpanded = !this.isExpanded);
+ }
+}
diff --git a/libs/utils/src/lib/sync/components/questions/questions-presenter/questions-presenter.component.css b/codelab-master/apps/codelab/src/app/components/slides/closing-slide/codelab-closing-slide.component.css
similarity index 100%
rename from libs/utils/src/lib/sync/components/questions/questions-presenter/questions-presenter.component.css
rename to codelab-master/apps/codelab/src/app/components/slides/closing-slide/codelab-closing-slide.component.css
diff --git a/codelab-master/apps/codelab/src/app/components/slides/closing-slide/codelab-closing-slide.component.html b/codelab-master/apps/codelab/src/app/components/slides/closing-slide/codelab-closing-slide.component.html
new file mode 100644
index 000000000..216d4d169
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/slides/closing-slide/codelab-closing-slide.component.html
@@ -0,0 +1,13 @@
+
diff --git a/codelab-master/apps/codelab/src/app/components/slides/closing-slide/codelab-closing-slide.component.spec.ts b/codelab-master/apps/codelab/src/app/components/slides/closing-slide/codelab-closing-slide.component.spec.ts
new file mode 100644
index 000000000..9cbbd0035
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/slides/closing-slide/codelab-closing-slide.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { CodelabClosingSlideComponent } from './codelab-closing-slide.component';
+
+describe('CodelabClosingSlideComponent', () => {
+ let component: CodelabClosingSlideComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [CodelabClosingSlideComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(CodelabClosingSlideComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/codelab/src/app/components/slides/closing-slide/codelab-closing-slide.component.ts b/codelab-master/apps/codelab/src/app/components/slides/closing-slide/codelab-closing-slide.component.ts
new file mode 100644
index 000000000..064a1c8b8
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/slides/closing-slide/codelab-closing-slide.component.ts
@@ -0,0 +1,16 @@
+import { Component, Input, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'codelab-closing-slide',
+ templateUrl: './codelab-closing-slide.component.html',
+ styleUrls: ['./codelab-closing-slide.component.css']
+})
+export class CodelabClosingSlideComponent implements OnInit {
+ @Input() header: String;
+ @Input() body: String;
+ @Input() footer: String;
+
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/codelab/src/app/components/slides/title-slide/ripple-animation/codelab-ripple-animation.component.css b/codelab-master/apps/codelab/src/app/components/slides/title-slide/ripple-animation/codelab-ripple-animation.component.css
new file mode 100644
index 000000000..6c50de87b
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/slides/title-slide/ripple-animation/codelab-ripple-animation.component.css
@@ -0,0 +1,31 @@
+@keyframes circle {
+ from {
+ transform: scale(0);
+ }
+ to {
+ transform: scale(0.5);
+ }
+}
+
+.circle {
+ margin: 0 auto;
+ width: 25vw;
+ height: 25vw;
+ border: 1vw solid rgba(255, 89, 75, 0.1);
+ border-radius: 50%;
+ position: absolute;
+ left: 0;
+ top: 0;
+}
+
+.one {
+ animation: circle 4s infinite linear;
+}
+
+.two {
+ animation: circle 3s infinite linear;
+}
+
+.three {
+ animation: circle 2s infinite linear;
+}
diff --git a/codelab-master/apps/codelab/src/app/components/slides/title-slide/ripple-animation/codelab-ripple-animation.component.html b/codelab-master/apps/codelab/src/app/components/slides/title-slide/ripple-animation/codelab-ripple-animation.component.html
new file mode 100644
index 000000000..b1265eeff
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/slides/title-slide/ripple-animation/codelab-ripple-animation.component.html
@@ -0,0 +1,3 @@
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/components/slides/title-slide/ripple-animation/codelab-ripple-animation.component.spec.ts b/codelab-master/apps/codelab/src/app/components/slides/title-slide/ripple-animation/codelab-ripple-animation.component.spec.ts
new file mode 100644
index 000000000..d9d5c32e8
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/slides/title-slide/ripple-animation/codelab-ripple-animation.component.spec.ts
@@ -0,0 +1,23 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { CodelabRippleAnimationComponent } from './codelab-ripple-animation.component';
+
+describe('CodelabRippleAnimationComponent', () => {
+ let component: CodelabRippleAnimationComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [CodelabRippleAnimationComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(CodelabRippleAnimationComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/codelab/src/app/components/slides/title-slide/ripple-animation/codelab-ripple-animation.component.ts b/codelab-master/apps/codelab/src/app/components/slides/title-slide/ripple-animation/codelab-ripple-animation.component.ts
new file mode 100644
index 000000000..dd61c8314
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/slides/title-slide/ripple-animation/codelab-ripple-animation.component.ts
@@ -0,0 +1,12 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'codelab-ripple-animation',
+ templateUrl: './codelab-ripple-animation.component.html',
+ styleUrls: ['./codelab-ripple-animation.component.css']
+})
+export class CodelabRippleAnimationComponent implements OnInit {
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/codelab/src/app/components/slides/title-slide/title-slide.component.css b/codelab-master/apps/codelab/src/app/components/slides/title-slide/title-slide.component.css
new file mode 100644
index 000000000..c634769e3
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/slides/title-slide/title-slide.component.css
@@ -0,0 +1,48 @@
+:host {
+ height: 100%;
+}
+
+.title-slide {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+}
+
+.header {
+ flex: 0.5;
+ display: flex;
+ justify-content: flex-end;
+ flex-direction: column;
+ background: #982a2a;
+ color: white;
+ font-size: 10vw;
+ padding: 2vw;
+}
+
+.contents {
+ padding: 2vw;
+ display: flex;
+ flex-direction: column;
+ flex: 0.5;
+}
+
+.description {
+ font-size: 5vw;
+}
+
+.instructions {
+ flex-grow: 1;
+ font-size: 4vw;
+ color: #666;
+ margin-top: 20px;
+}
+
+.left-half-ripple {
+ overflow: hidden;
+ margin: 0;
+ height: 25vw;
+ width: calc(25vw / 2 + 2vw);
+ position: absolute;
+ top: calc(50% - 25vw / 2);
+ right: 0;
+}
diff --git a/codelab-master/apps/codelab/src/app/components/slides/title-slide/title-slide.component.html b/codelab-master/apps/codelab/src/app/components/slides/title-slide/title-slide.component.html
new file mode 100644
index 000000000..cc7384490
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/slides/title-slide/title-slide.component.html
@@ -0,0 +1,15 @@
+
+
+
+
{{ description }}
+
+
+ Use ← and → on your keyboard to navigate the slides.
+
+
+
+ Prerequisites: {{ prereqs }}
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/app/components/slides/title-slide/title-slide.component.spec.ts b/codelab-master/apps/codelab/src/app/components/slides/title-slide/title-slide.component.spec.ts
new file mode 100644
index 000000000..26f3c42f2
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/slides/title-slide/title-slide.component.spec.ts
@@ -0,0 +1,55 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { By } from '@angular/platform-browser';
+
+import { TitleSlideComponent } from './title-slide.component';
+import { CodelabRippleAnimationComponent } from './ripple-animation/codelab-ripple-animation.component';
+
+describe('TitleSlideComponent', () => {
+ let component: TitleSlideComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [CodelabRippleAnimationComponent, TitleSlideComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(TitleSlideComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it('should render a title', () => {
+ component.title = 'awesome title';
+ fixture.detectChanges();
+ const el = fixture.debugElement.query(By.css('.header'));
+ expect(el.nativeElement.textContent).toContain('awesome title');
+ });
+
+ it('should render a description', () => {
+ component.description = 'hello world!';
+ fixture.detectChanges();
+ const el = fixture.debugElement.query(By.css('.description'));
+ expect(el.nativeElement.textContent).toContain('hello world!');
+ });
+
+ it('should render prerequisites', () => {
+ component.prereqs = 'do this first';
+ fixture.detectChanges();
+ const el = fixture.debugElement.query(By.css('.prereqs'));
+ expect(el.nativeElement.textContent).toContain('do this first');
+ expect(el.nativeElement.textContent).toContain('Prerequisites');
+ });
+
+ it('should not show "Prerequisites" if undefined', () => {
+ component.prereqs = undefined;
+ fixture.detectChanges();
+ const el = fixture.debugElement.query(By.css('.prereqs'));
+ expect(el.nativeElement.textContent).not.toContain('Prerequisites');
+ });
+});
diff --git a/codelab-master/apps/codelab/src/app/components/slides/title-slide/title-slide.component.ts b/codelab-master/apps/codelab/src/app/components/slides/title-slide/title-slide.component.ts
new file mode 100644
index 000000000..aa76cc2b4
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/components/slides/title-slide/title-slide.component.ts
@@ -0,0 +1,12 @@
+import { Component, Input } from '@angular/core';
+
+@Component({
+ selector: 'codelab-title-slide',
+ templateUrl: './title-slide.component.html',
+ styleUrls: ['./title-slide.component.css']
+})
+export class TitleSlideComponent {
+ @Input() title: string;
+ @Input() description: string;
+ @Input() prereqs: string;
+}
diff --git a/codelab-master/apps/codelab/src/app/containers/full-layout/full-layout.component.html b/codelab-master/apps/codelab/src/app/containers/full-layout/full-layout.component.html
new file mode 100644
index 000000000..515dd78d6
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/containers/full-layout/full-layout.component.html
@@ -0,0 +1,5 @@
+
+
+
diff --git a/libs/utils/src/lib/sync/components/registration/registration-admin/registration-admin.component.css b/codelab-master/apps/codelab/src/app/containers/full-layout/full-layout.component.scss
similarity index 100%
rename from libs/utils/src/lib/sync/components/registration/registration-admin/registration-admin.component.css
rename to codelab-master/apps/codelab/src/app/containers/full-layout/full-layout.component.scss
diff --git a/codelab-master/apps/codelab/src/app/containers/full-layout/full-layout.component.ts b/codelab-master/apps/codelab/src/app/containers/full-layout/full-layout.component.ts
new file mode 100644
index 000000000..36df1e64f
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/containers/full-layout/full-layout.component.ts
@@ -0,0 +1,15 @@
+import { ChangeDetectionStrategy, Component, Optional } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+
+@Component({
+ selector: 'codelab-full-layout',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ templateUrl: './full-layout.component.html',
+ styleUrls: ['./full-layout.component.scss']
+})
+export class FullLayoutComponent {
+ displayButtons: boolean;
+ constructor(@Optional() route: ActivatedRoute) {
+ this.displayButtons = !route.snapshot.queryParams.milestone;
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/containers/full-layout/full-layout.module.ts b/codelab-master/apps/codelab/src/app/containers/full-layout/full-layout.module.ts
new file mode 100644
index 000000000..db027701c
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/containers/full-layout/full-layout.module.ts
@@ -0,0 +1,11 @@
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { FullLayoutComponent } from './full-layout.component';
+import { SyncModule } from '../../sync/sync.module';
+import { ButtonsNavBarModule } from '../../components/buttons-nav-bar/buttons-nav-bar.module';
+
+@NgModule({
+ imports: [RouterModule, SyncModule, ButtonsNavBarModule],
+ declarations: [FullLayoutComponent]
+})
+export class FullLayoutModule {}
diff --git a/codelab-master/apps/codelab/src/app/containers/full-layout/index.ts b/codelab-master/apps/codelab/src/app/containers/full-layout/index.ts
new file mode 100644
index 000000000..315223dd1
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/containers/full-layout/index.ts
@@ -0,0 +1 @@
+export * from './full-layout.component';
diff --git a/codelab-master/apps/codelab/src/app/containers/index.ts b/codelab-master/apps/codelab/src/app/containers/index.ts
new file mode 100644
index 000000000..11f57518e
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/containers/index.ts
@@ -0,0 +1 @@
+export * from './full-layout';
diff --git a/codelab-master/apps/codelab/src/app/directives/directives.module.ts b/codelab-master/apps/codelab/src/app/directives/directives.module.ts
new file mode 100644
index 000000000..326e39b0a
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/directives/directives.module.ts
@@ -0,0 +1,21 @@
+import { NgModule } from '@angular/core';
+import { IsLoggedInDirective } from './permissions/is-logged-in/is-loggef-in.directive';
+import { CanLoadAdminDirective } from './permissions/can-load-admin/can-load-admin.directive';
+import { NextSlideDirective } from './nextSlide.directive';
+import { PreviousSlideDirective } from './previousSlide.directive';
+
+@NgModule({
+ declarations: [
+ IsLoggedInDirective,
+ CanLoadAdminDirective,
+ NextSlideDirective,
+ PreviousSlideDirective
+ ],
+ exports: [
+ IsLoggedInDirective,
+ CanLoadAdminDirective,
+ NextSlideDirective,
+ PreviousSlideDirective
+ ]
+})
+export class DirectivesModule {}
diff --git a/codelab-master/apps/codelab/src/app/directives/nextSlide.directive.ts b/codelab-master/apps/codelab/src/app/directives/nextSlide.directive.ts
new file mode 100644
index 000000000..94f629fb5
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/directives/nextSlide.directive.ts
@@ -0,0 +1,14 @@
+import { Directive, HostListener } from '@angular/core';
+import { SlidesDeckComponent } from '@ng360/slides';
+
+@Directive({
+ selector: '[nextSlide]'
+})
+export class NextSlideDirective {
+ constructor(public deck: SlidesDeckComponent) {}
+
+ @HostListener('click')
+ onClick() {
+ this.deck.nextSlide();
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/directives/permissions/abstract-permission.ts b/codelab-master/apps/codelab/src/app/directives/permissions/abstract-permission.ts
new file mode 100644
index 000000000..9d7dee7ae
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/directives/permissions/abstract-permission.ts
@@ -0,0 +1,34 @@
+import {
+ TemplateRef,
+ ViewContainerRef,
+ OnDestroy,
+ Injectable
+} from '@angular/core';
+import { AccessService } from '../../shared/services/access.service';
+import { ReplaySubject, Observable } from 'rxjs';
+import { takeUntil } from 'rxjs/operators';
+@Injectable()
+export class AbstractPermission implements OnDestroy {
+ public destroy = new ReplaySubject(1);
+
+ constructor(
+ public templateRef: TemplateRef,
+ public viewContainer: ViewContainerRef,
+ public accessService: AccessService
+ ) {}
+
+ ngOnDestroy() {
+ this.destroy.next(null);
+ this.destroy.complete();
+ }
+
+ public render(observable: Observable): void {
+ observable.pipe(takeUntil(this.destroy)).subscribe(hasPermission => {
+ if (hasPermission) {
+ this.viewContainer.createEmbeddedView(this.templateRef);
+ } else {
+ this.viewContainer.clear();
+ }
+ });
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/directives/permissions/can-load-admin/can-load-admin.directive.ts b/codelab-master/apps/codelab/src/app/directives/permissions/can-load-admin/can-load-admin.directive.ts
new file mode 100644
index 000000000..3c81cde4c
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/directives/permissions/can-load-admin/can-load-admin.directive.ts
@@ -0,0 +1,29 @@
+import {
+ Directive,
+ OnInit,
+ TemplateRef,
+ ViewContainerRef
+} from '@angular/core';
+import {
+ AccessService,
+ Permissions
+} from '../../../shared/services/access.service';
+import { AbstractPermission } from '../abstract-permission';
+
+@Directive({
+ selector: '[canLoadAdmin]'
+})
+export class CanLoadAdminDirective extends AbstractPermission
+ implements OnInit {
+ constructor(
+ templateRef: TemplateRef,
+ viewContainer: ViewContainerRef,
+ accessService: AccessService
+ ) {
+ super(templateRef, viewContainer, accessService);
+ }
+
+ ngOnInit() {
+ this.render(this.accessService.can(Permissions.CAN_LOAD_ADMIN));
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/directives/permissions/is-logged-in/is-loggef-in.directive.ts b/codelab-master/apps/codelab/src/app/directives/permissions/is-logged-in/is-loggef-in.directive.ts
new file mode 100644
index 000000000..0cf87a58d
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/directives/permissions/is-logged-in/is-loggef-in.directive.ts
@@ -0,0 +1,25 @@
+import {
+ Directive,
+ OnInit,
+ TemplateRef,
+ ViewContainerRef
+} from '@angular/core';
+import { AccessService } from '../../../shared/services/access.service';
+import { AbstractPermission } from '../abstract-permission';
+
+@Directive({
+ selector: '[isLoggedIn]'
+})
+export class IsLoggedInDirective extends AbstractPermission implements OnInit {
+ constructor(
+ templateRef: TemplateRef,
+ viewContainer: ViewContainerRef,
+ accessService: AccessService
+ ) {
+ super(templateRef, viewContainer, accessService);
+ }
+
+ ngOnInit() {
+ this.render(this.accessService.oldIsAdmin$);
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/directives/previousSlide.directive.ts b/codelab-master/apps/codelab/src/app/directives/previousSlide.directive.ts
new file mode 100644
index 000000000..39e27f92f
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/directives/previousSlide.directive.ts
@@ -0,0 +1,14 @@
+import { Directive, HostListener } from '@angular/core';
+import { SlidesDeckComponent } from '@ng360/slides';
+
+@Directive({
+ selector: '[previousSlide]'
+})
+export class PreviousSlideDirective {
+ constructor(public deck: SlidesDeckComponent) {}
+
+ @HostListener('click')
+ onClick() {
+ this.deck.previousSlide();
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/shared/angular-code/app.component.ts b/codelab-master/apps/codelab/src/app/shared/angular-code/app.component.ts
new file mode 100644
index 000000000..7e347818f
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/shared/angular-code/app.component.ts
@@ -0,0 +1,7 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'my-app',
+ template: 'Hi!'
+})
+export class AppComponent {}
diff --git a/codelab-master/apps/codelab/src/app/shared/angular-code/app.module.ts b/codelab-master/apps/codelab/src/app/shared/angular-code/app.module.ts
new file mode 100644
index 000000000..02260c17c
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/shared/angular-code/app.module.ts
@@ -0,0 +1,10 @@
+import { NgModule } from '@angular/core';
+import { BrowserModule } from '@angular/platform-browser';
+import { AppComponent } from './app.component';
+
+@NgModule({
+ imports: [BrowserModule],
+ declarations: [AppComponent],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}
diff --git a/codelab-master/apps/codelab/src/app/shared/angular-code/bootstrap.ts b/codelab-master/apps/codelab/src/app/shared/angular-code/bootstrap.ts
new file mode 100644
index 000000000..96788cb59
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/shared/angular-code/bootstrap.ts
@@ -0,0 +1,31 @@
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+import { ResourceLoader } from '@angular/compiler';
+import * as code from './code';
+import { AppModule } from './app.module';
+
+class MyResourceLoader extends ResourceLoader {
+ get(url: string): Promise {
+ const templateId = Object.keys(code).find(key =>
+ key.includes(url.replace(/[\/\.-]/gi, '_'))
+ );
+ const template = code[templateId];
+ if (!template) {
+ console.log(template);
+ // tslint:disable-next-line:no-debugger
+ debugger;
+ }
+ return Promise.resolve(template);
+ }
+}
+
+platformBrowserDynamic().bootstrapModule(AppModule, [
+ {
+ providers: [
+ {
+ provide: ResourceLoader,
+ useFactory: () => new MyResourceLoader(),
+ deps: []
+ }
+ ]
+ }
+]);
diff --git a/codelab-master/apps/codelab/src/app/shared/angular-code/code.ts b/codelab-master/apps/codelab/src/app/shared/angular-code/code.ts
new file mode 100644
index 000000000..2e9e9ab92
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/shared/angular-code/code.ts
@@ -0,0 +1 @@
+export const code = '';
diff --git a/codelab-master/apps/codelab/src/app/shared/angular-code/index.html b/codelab-master/apps/codelab/src/app/shared/angular-code/index.html
new file mode 100644
index 000000000..fcc059559
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/shared/angular-code/index.html
@@ -0,0 +1,33 @@
+
+
+
+
+
+ Loading...
+
+
diff --git a/codelab-master/apps/codelab/src/app/shared/helpers/codelabFile.ts b/codelab-master/apps/codelab/src/app/shared/helpers/codelabFile.ts
new file mode 100644
index 000000000..8e54a7f77
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/shared/helpers/codelabFile.ts
@@ -0,0 +1,108 @@
+import { FileConfig } from '../interfaces/file-config';
+
+export enum FileType {
+ TypeScript = 'typescript',
+ Html = 'html',
+ Css = 'css'
+}
+
+const fileConfig = {
+ [FileType.TypeScript]: {
+ extension: '.ts'
+ },
+ [FileType.Html]: {
+ extension: '.html'
+ },
+ [FileType.Css]: {
+ extension: '.css'
+ }
+};
+
+export class CodelabFile implements FileConfig {
+ highlight?: RegExp | RegExp[];
+ after: string;
+ public code: string;
+ public template: string;
+ public solution: string;
+ public bootstrap = false;
+ public path: string;
+ public excludeFromTesting = false;
+ public test = false;
+ public before: string;
+ public hidden = false;
+
+ static TypeScriptFile(name: string): CodelabFile {
+ return new CodelabFile(FileType.TypeScript, name).setAfter(
+ 'export function evalJs( js ){ return eval(js);}'
+ );
+ }
+
+ static TypeScriptTest(name: string): CodelabFile {
+ return new CodelabFile(FileType.TypeScript, name + 'Test').makeTest();
+ }
+
+ static Html(name: string): CodelabFile {
+ return new CodelabFile(FileType.Html, name);
+ }
+
+ static Css(name: string): CodelabFile {
+ return new CodelabFile(FileType.Css, name);
+ }
+
+ constructor(
+ public readonly type: FileType,
+ public readonly moduleName: string
+ ) {
+ this.path = moduleName + fileConfig[type].extension;
+ }
+
+ public setAfter(after: string): CodelabFile {
+ this.after = after;
+ return this;
+ }
+
+ public clone(): CodelabFile {
+ return Object.assign(Object.create(CodelabFile), this);
+ }
+
+ public makeBootstrappable(): CodelabFile {
+ this.bootstrap = true;
+ this.excludeFromTesting = true;
+ return this;
+ }
+
+ public makeHidden(): CodelabFile {
+ this.hidden = true;
+ return this;
+ }
+
+ public makeTest(): CodelabFile {
+ this.test = true;
+ this.before = 'mochaBefore();';
+ this.after = 'mochaAfter();';
+ this.excludeFromTesting = false;
+ this.makeHidden();
+ this.makeBootstrappable();
+ return this;
+ }
+
+ public setSolution(solution: string): CodelabFile {
+ this.solution = solution;
+ return this;
+ }
+
+ public withHighlight(highlight: RegExp | RegExp[]) {
+ this.highlight = highlight;
+ return this;
+ }
+
+ public setCode(code: string): CodelabFile {
+ this.code = code;
+ this.template = code;
+ if (!this.solution) {
+ this.solution = code;
+ }
+
+ return this;
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/shared/helpers/helpers.ts b/codelab-master/apps/codelab/src/app/shared/helpers/helpers.ts
new file mode 100644
index 000000000..44589428d
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/shared/helpers/helpers.ts
@@ -0,0 +1,368 @@
+import { FileConfig } from '../interfaces/file-config';
+
+function exerciseWithConsoleLog(moduleName: string, code: any, code2: any) {
+ return {
+ ...exercise(moduleName, code, code2),
+ before: `
+
+ export const value = window.value = window.value || {};
+
+ function wrap(context, prop, callback){
+ if(!context[prop].patched){
+ const originalMethod = context[prop];
+
+ context[prop] = function(...args){
+ callback(...args);
+ return originalMethod.apply(context, args);
+ }
+
+ context[prop].patched = true;
+ }
+ }
+
+ /* TODO: Get rid of the CSS hack */
+
+ wrap(console, 'log', (v)=>{
+ value.value = v;
+ document.body.innerHTML += '' +
+ '< ' + JSON.stringify(v, null, ' ') + ' ' +
+ ' '
+ document.body.scrollTop = document.body.scrollHeight;
+ })
+ `
+ };
+}
+
+export function exercise(
+ moduleName: string,
+ template: string,
+ solution?: string
+): FileConfig {
+ solution = solution || template;
+
+ return {
+ bootstrap: false,
+ excludeFromTesting: false,
+ type: 'typescript',
+ path: moduleName + '.ts',
+ template,
+ code: template,
+ moduleName: moduleName,
+ solution,
+ after: `export function evalJs( js ){ return eval(js);}`
+ };
+}
+
+export function test(moduleName: string, template: string): FileConfig {
+ return {
+ path: moduleName + 'Test.ts',
+ type: 'typescript',
+ template,
+ code: template,
+ moduleName: moduleName + 'Test',
+ excludeFromTesting: false,
+ test: true,
+ bootstrap: true,
+ before: 'mochaBefore();',
+ after: 'mochaAfter();',
+ hidden: true
+ };
+}
+
+interface SimpleImport {
+ name: string;
+ path: string;
+}
+
+export const builder = {
+ imports(imports: Array) {
+ return imports.map(i => `import {${i.name}} from '${i.path}';`).join('\n');
+ },
+ listOfComponents: (components: Array) => {
+ return `[${components.map(c => c.name).join(',')}]`;
+ },
+
+ ngModule(
+ declarations: Array = [
+ {
+ name: 'AppComponent',
+ path: './app.component'
+ }
+ ],
+ bootstrapComponent?: Array
+ ) {
+ bootstrapComponent = bootstrapComponent || declarations;
+
+ return `import {BrowserModule} from \'@angular/platform-browser\';
+import {NgModule} from \'@angular/core\';
+${this.imports(declarations)}
+
+@NgModule({
+ imports: [BrowserModule],
+ declarations: ${this.listOfComponents(declarations)},
+ bootstrap: ${this.listOfComponents(bootstrapComponent)}
+})
+export class AppModule {}`;
+ },
+
+ bootstrap(
+ module: SimpleImport = { name: 'AppModule', path: './app.module' }
+ ): string {
+ return `import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
+${this.imports([module])}
+
+import {ResourceLoader} from '@angular/compiler';
+class MyResourceLoader extends ResourceLoader {
+ get(url: string): Promise {
+ const templateId = Object.keys(code).find(key => key.includes(url.replace(/[\\/\\.-]/gi, '_')));
+ const template = code[templateId];
+ if (!template) {
+ console.log(template);
+ // tslint:disable-next-line:no-debugger
+ debugger;
+ }
+ return Promise.resolve(template);
+ };
+}
+
+
+
+
+const platform = platformBrowserDynamic();
+platform.bootstrapModule(${module.name}, [
+ {
+ providers: [
+ {provide: ResourceLoader, useFactory: () => new MyResourceLoader(), deps: []}
+ ]
+ }
+]);
+
+`;
+ }
+};
+
+export function html(path = 'app', code, solution = '') {
+ return {
+ code,
+ path: path + '.html',
+ solution: solution,
+ type: 'html'
+ };
+}
+
+export function stylesheet(code, solution = '') {
+ return {
+ code,
+ path: 'style.css',
+ solution: solution || code,
+ type: 'css'
+ };
+}
+
+export function bootstrap(
+ moduleName: string,
+ template: string,
+ solution?: string
+) {
+ solution = solution || template;
+ return {
+ bootstrap: true,
+ excludeFromTesting: true,
+ type: 'typescript',
+ path: moduleName + '.ts',
+ template,
+ code: template,
+ moduleName: moduleName,
+ solution
+ };
+}
+
+export function circleAndBox() {
+ const result = boxAndCircle();
+ const temp = result.files[0];
+ result.files[0] = result.files[1];
+ result.files[1] = temp;
+ return result;
+}
+
+// That's me being plain lazy, we need
+export function boxAndCircle() {
+ const moduleCode = `import {BrowserModule} from \'@angular/platform-browser\';
+ import {NgModule} from '@angular/core';
+ import {BoxComponent} from './box.component';
+ import {CircleComponent} from './circle.component';
+
+ @NgModule({
+ imports: [BrowserModule],
+ declarations: [CircleComponent, BoxComponent],
+ bootstrap: [BoxComponent]
+ })
+ export class AppModule {}`;
+ const circleCode = `import { Component, Input } from '@angular/core';
+
+ @Component({
+ selector: 'slides-circle',
+ template: '
'
+ })
+ export class CircleComponent {
+ @Input() size: number;
+ @Input() color: string;
+ }`;
+
+ const boxCode = `import { Component } from '@angular/core';
+
+ @Component({
+ selector: 'my-app',
+ template: \`
\`
+ })
+ export class BoxComponent {
+ circleColor="green"
+ }`;
+
+ const bootstrapCode = `import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
+import {AppModule} from './app.module';
+platformBrowserDynamic().bootstrapModule(AppModule)
+`;
+
+ return {
+ other: {
+ boxNoParams: `import { Component } from '@angular/core';
+
+ @Component({
+ selector: 'slides-box',
+ template: \`
\`
+ })
+ export class BoxComponent {
+ circleColor="green"
+ }`
+ },
+ files: [
+ exercise('box.component', boxCode),
+ exercise('circle.component', circleCode),
+ exercise('app.module', moduleCode),
+ bootstrap('main', bootstrapCode, bootstrapCode),
+ {
+ type: 'css',
+ path: 'styles.css',
+ template: `
+ my-app > div {
+ width: 300px;
+ height: 200px;
+ border: 1px #ddd solid;
+ }
+ .circle {
+ margin-left: 100px;
+ margin-top: 50px;
+ border-radius: 50%;
+ }
+ `
+ }
+ ]
+ };
+}
+
+export function displayAngularComponent(
+ componentCode: string,
+ testCode?: string
+) {
+ // tslint:disable-next-line:max-line-length TODO: Clean up next line and remove this comment.
+ const moduleCode = builder.ngModule();
+ const bootstrapCode = builder.bootstrap();
+
+ return {
+ files: [
+ exercise('app.component', componentCode),
+ exercise('app.module', moduleCode),
+ bootstrap('main', bootstrapCode, bootstrapCode),
+ {
+ type: 'css',
+ path: 'styles.css',
+ code: `
+ body, html {
+ margin: 0;
+ padding: 2vw;
+ font-family: sans-serif;
+ }
+
+ h1, h2 {
+ margin: 0;
+ padding: 0;
+ }
+
+ h1 {font-size: 6vw;}
+ h2 {font-size: 4vw;}
+ `
+ },
+ ...(testCode ? [test('test', testCode)] : [])
+ ]
+ };
+}
+
+export function typeScriptWithConsoleLog(
+ code: string,
+ bootstrapCode = 'import "./app";',
+ testCode = '',
+ otherCode = ''
+) {
+ const files = [
+ exerciseWithConsoleLog('app', code, code),
+ bootstrap('main', bootstrapCode, bootstrapCode),
+ test('test', testCode),
+ {
+ path: 'main.css',
+ type: 'css',
+ code: ``
+ }
+ ];
+ if (otherCode !== '') {
+ files.push(exercise('puppy', otherCode));
+ }
+ return {
+ files
+ };
+}
+
+export function javaScriptWithConsoleLog(
+ code: string,
+ bootstrapCode = 'import "./app";',
+ testCode = '',
+ otherCode = ''
+) {
+ const result = typeScriptWithConsoleLog(
+ code,
+ bootstrapCode,
+ testCode,
+ otherCode
+ );
+ (result.files[0] as FileConfig).editorType = 'javascript';
+ return result;
+}
+
+export function displayAngularComponentWithHtml(
+ componentCode: string,
+ code: string
+) {
+ return {
+ files: [
+ {
+ code,
+ path: 'app/app.html',
+ solution: '',
+ type: 'html'
+ },
+ ...displayAngularComponent(componentCode).files
+ ]
+ };
+}
+
+export function solve(exerciseConfig) {
+ return {
+ ...exerciseConfig,
+ files: exerciseConfig.files.map(file => ({
+ ...file,
+ code: file.solution || file.code
+ }))
+ };
+}
diff --git a/codelab-master/apps/codelab/src/app/shared/interfaces/exercise-config.ts b/codelab-master/apps/codelab/src/app/shared/interfaces/exercise-config.ts
new file mode 100644
index 000000000..396a66bf3
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/shared/interfaces/exercise-config.ts
@@ -0,0 +1,11 @@
+import { FileConfig } from './file-config';
+import { TestInfo } from './test-info';
+
+export interface ExerciseConfig {
+ name: string;
+ description: string;
+ runner?: string;
+ files: Array;
+ skipTests?: boolean;
+ tests?: Array;
+}
diff --git a/codelab-master/apps/codelab/src/app/shared/interfaces/file-config.ts b/codelab-master/apps/codelab/src/app/shared/interfaces/file-config.ts
new file mode 100644
index 000000000..5d158b98e
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/shared/interfaces/file-config.ts
@@ -0,0 +1,76 @@
+export interface FileConfig {
+ opened?: boolean;
+ /**
+ * typescript or html.
+ */
+ type?: string;
+
+ /**
+ * Source code of the file.
+ */
+ code?: string;
+
+ template: string;
+ /**
+ * Source code of the file.
+ */
+ solution?: string;
+
+ /**
+ * TS code to run before running the file.
+ */
+ before?: string;
+
+ /**
+ * TS code to run after running the file.
+ */
+ after?: string;
+
+ /**
+ * Usually the same as fileName without .ts postfix.
+ * Currently gets inferred from filename.
+ */
+ moduleName?: string;
+
+ /**
+ * Actual filename.
+ */
+ path: string;
+
+ /**
+ * If this is true; the file will be included in the preview iframe.
+ */
+ ui?: boolean;
+
+ /**
+ * If this is true
+ */
+ bootstrap?: boolean;
+
+ excludeFromTesting?: boolean;
+
+ /**
+ * if this is true; the file will be displayed in read only mode.
+ */
+ readonly?: boolean;
+
+ /**
+ * If this is true the file will be included in the test iframe.
+ */
+ test?: boolean;
+
+ /**
+ * If this is true; the file will be hidden.
+ */
+ hidden?: boolean;
+
+ /**
+ * File dependencies, need for proper highlighting in monaco.
+ */
+
+ editorType?: string;
+
+ // If this is set, this will be executed as a test.
+ // This is a hack and will be removed.
+ execute?: any;
+}
diff --git a/codelab-master/apps/codelab/src/app/shared/interfaces/test-info.ts b/codelab-master/apps/codelab/src/app/shared/interfaces/test-info.ts
new file mode 100644
index 000000000..406b19458
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/shared/interfaces/test-info.ts
@@ -0,0 +1,9 @@
+import { FileConfig } from './file-config';
+
+export interface TestInfo {
+ title: string;
+ file: FileConfig;
+ pass?: boolean;
+ result?: string;
+ filename?: string;
+}
diff --git a/codelab-master/apps/codelab/src/app/shared/services/access.service.ts b/codelab-master/apps/codelab/src/app/shared/services/access.service.ts
new file mode 100644
index 000000000..bde8bde36
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/shared/services/access.service.ts
@@ -0,0 +1,44 @@
+import { Injectable } from '@angular/core';
+import { LoginService } from '@codelab/firebase-login';
+import { SyncDbService } from '@codelab/utils/src/lib/sync/services/sync-db.service';
+import { filter, switchMap } from 'rxjs/operators';
+import { Observable } from 'rxjs';
+import { SyncDb } from '@codelab/utils/src/lib/sync/services/sync-data.service';
+
+export enum Permissions {
+ MANAGE_USERS = 'manage_users',
+ CAN_LOAD_ADMIN = 'can_load_admin'
+}
+
+@Injectable({ providedIn: 'root' })
+export class AccessService {
+ readonly oldIsAdmin$ = this.loginService.uid$.pipe(
+ switchMap(uid => {
+ return this.dbService
+ .object('authorized_users')
+ .object(uid)
+ .withDefault(false)
+ .valueChanges();
+ })
+ );
+
+ private readonly adminPermissions = this.dbService
+ .object('admin')
+ .object(this.loginService.uid$)
+ .object('permissions');
+
+ constructor(
+ private readonly loginService: LoginService,
+ private readonly dbService: SyncDbService
+ ) {}
+
+ can(p: Permissions): Observable {
+ return (
+ this.adminPermissions
+ // TODO(kirjs): default: false
+ .object(p)
+ .valueChanges()
+ .pipe(filter(a => a !== null))
+ );
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/shared/services/guards/admin-guard.ts b/codelab-master/apps/codelab/src/app/shared/services/guards/admin-guard.ts
new file mode 100644
index 000000000..264dd891e
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/shared/services/guards/admin-guard.ts
@@ -0,0 +1,32 @@
+import { Injectable } from '@angular/core';
+import {
+ Router,
+ RouterStateSnapshot,
+ ActivatedRouteSnapshot,
+ CanActivate
+} from '@angular/router';
+import { Observable } from 'rxjs';
+import { map } from 'rxjs/operators';
+import { AccessService, Permissions } from '../access.service';
+
+@Injectable({ providedIn: 'root' })
+export class AdminGuard implements CanActivate {
+ constructor(private _route: Router, private accessService: AccessService) {}
+
+ canActivate(
+ route: ActivatedRouteSnapshot,
+ state: RouterStateSnapshot
+ ): Observable | boolean {
+ return true;
+ return this.accessService.can(Permissions.CAN_LOAD_ADMIN).pipe(
+ map(hasAccess => {
+ if (!hasAccess) {
+ this._route.navigate(['login']);
+ return false;
+ }
+
+ return true;
+ })
+ );
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/shared/services/guards/login-guard.ts b/codelab-master/apps/codelab/src/app/shared/services/guards/login-guard.ts
new file mode 100644
index 000000000..00529d006
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/shared/services/guards/login-guard.ts
@@ -0,0 +1,29 @@
+import { Injectable } from '@angular/core';
+import { Router, RouterStateSnapshot, CanActivate } from '@angular/router';
+import { LoginService } from '@codelab/firebase-login';
+import { Observable } from 'rxjs';
+import { map } from 'rxjs/operators';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class LoginGuard implements CanActivate {
+ constructor(private _route: Router, private loginService: LoginService) {}
+
+ canActivate(
+ ActivatedRouteSnapshot,
+ state: RouterStateSnapshot
+ ): Observable | boolean {
+ return this.loginService.isAnonymous$.pipe(
+ map(res => {
+ if (res) {
+ // user is anonymous
+ return true;
+ }
+ // user is logged in, navigate to home
+ this._route.navigate(['/']);
+ return false;
+ })
+ );
+ }
+}
diff --git a/codelab-master/apps/codelab/src/app/shared/shared.module.ts b/codelab-master/apps/codelab/src/app/shared/shared.module.ts
new file mode 100644
index 000000000..1d5787450
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/shared/shared.module.ts
@@ -0,0 +1,31 @@
+import { NgModule } from '@angular/core';
+import { HttpClientModule } from '@angular/common/http';
+import { FormsModule } from '@angular/forms';
+import { RouterModule } from '@angular/router';
+import { SlidesModule } from '@ng360/slides';
+import { CodeDemoModule } from '@codelab/code-demos';
+import { CodelabComponentsModule } from '../components/codelab-components.module';
+import { ButtonsNavBarModule } from '../components/buttons-nav-bar/buttons-nav-bar.module';
+import { SyncModule } from '../sync/sync.module';
+
+@NgModule({
+ imports: [
+ HttpClientModule,
+ FormsModule,
+ RouterModule,
+ CodeDemoModule,
+ CodelabComponentsModule,
+ SlidesModule,
+ ButtonsNavBarModule,
+ SyncModule
+ ],
+ exports: [
+ HttpClientModule,
+ FormsModule,
+ CodeDemoModule,
+ CodelabComponentsModule,
+ SlidesModule,
+ ButtonsNavBarModule
+ ]
+})
+export class SharedModule {}
diff --git a/codelab-master/apps/codelab/src/app/sync/sync.component.css b/codelab-master/apps/codelab/src/app/sync/sync.component.css
new file mode 100644
index 000000000..17edfbc67
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/sync/sync.component.css
@@ -0,0 +1,17 @@
+.survey {
+ opacity: 0.98;
+ position: absolute;
+ top: 20px;
+ left: 20px;
+ bottom: 20px;
+ right: 20px;
+ border: 1px solid #000;
+ background-color: #fff;
+ padding: 20px;
+ z-index: 1000;
+ font-family: sans-serif;
+}
+
+h1 {
+ text-align: center;
+}
diff --git a/codelab-master/apps/codelab/src/app/sync/sync.component.html b/codelab-master/apps/codelab/src/app/sync/sync.component.html
new file mode 100644
index 000000000..e9d742025
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/sync/sync.component.html
@@ -0,0 +1,38 @@
+
+
Quick Survey
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ userId$ | async }}
+
+
diff --git a/codelab-master/apps/codelab/src/app/sync/sync.component.spec.ts b/codelab-master/apps/codelab/src/app/sync/sync.component.spec.ts
new file mode 100644
index 000000000..00db356e2
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/sync/sync.component.spec.ts
@@ -0,0 +1,33 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SyncComponent } from './sync.component';
+import { SyncModule } from './sync.module';
+import { AngularFireDatabase } from '@angular/fire/database';
+import { AngularFireAuth } from '@angular/fire/auth';
+import {
+ getMockAngularFireProviders,
+ MockAngularFireAuth,
+ MockAngularFireDatabase
+} from '@codelab/utils/src/lib/testing/mocks/angular-fire';
+
+describe('SyncComponent', () => {
+ let component: SyncComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [SyncModule],
+ providers: [getMockAngularFireProviders()]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(SyncComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/codelab/src/app/sync/sync.component.ts b/codelab-master/apps/codelab/src/app/sync/sync.component.ts
new file mode 100644
index 000000000..25e0e9510
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/sync/sync.component.ts
@@ -0,0 +1,70 @@
+import { Component, Input } from '@angular/core';
+import { SyncPollConfig } from '@codelab/utils/src/lib/sync/components/poll/common/common';
+import { SyncDataService } from '@codelab/utils/src/lib/sync/services/sync-data.service';
+import { SyncSessionService } from '@codelab/utils/src/lib/sync/services/sync-session.service';
+import { switchMap } from 'rxjs/operators';
+import {
+ canWritePresenterData,
+ SyncStatus
+} from '@codelab/utils/src/lib/sync/common';
+import { of } from 'rxjs';
+
+@Component({
+ selector: 'codelab-sync-survey',
+ templateUrl: './sync.component.html',
+ styleUrls: ['./sync.component.css']
+})
+export class SyncComponent {
+ @Input() admin = false;
+ readonly userId$ = this.syncSessionService.viewerId$;
+
+ readonly isPresentationEnabled$ = this.syncDataService
+ .getPresenterObject('enabled')
+ .withDefault(false)
+ .valueChanges();
+
+ readonly shouldShowPresentation$ = this.syncSessionService.status$.pipe(
+ switchMap(s => {
+ if (canWritePresenterData(s)) {
+ return of(true);
+ }
+
+ if (s === SyncStatus.OFF) {
+ return this.admin
+ ? this.syncSessionService.canStartSession$
+ : of(false);
+ }
+
+ return this.isPresentationEnabled$;
+ })
+ );
+
+ polls: SyncPollConfig[] = [
+ {
+ key: 'js',
+ type: 'stars',
+ question: 'How well do you know JavaScript'
+ },
+ {
+ key: 'ts',
+ type: 'stars',
+ question: 'How well do you know TypeScript'
+ },
+ {
+ key: 'angularjs',
+ type: 'stars',
+ question: 'How well do you know AngularJS (Old version)'
+ },
+ {
+ key: 'angular',
+ type: 'stars',
+ question:
+ 'How well do you know Angular (The new version we are learning today)'
+ }
+ ];
+
+ constructor(
+ private readonly syncDataService: SyncDataService,
+ private readonly syncSessionService: SyncSessionService
+ ) {}
+}
diff --git a/codelab-master/apps/codelab/src/app/sync/sync.module.ts b/codelab-master/apps/codelab/src/app/sync/sync.module.ts
new file mode 100644
index 000000000..9d7aa9fb7
--- /dev/null
+++ b/codelab-master/apps/codelab/src/app/sync/sync.module.ts
@@ -0,0 +1,39 @@
+import { Component, NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { CommonModule } from '@angular/common';
+import { SlidesModule, SlidesRoutes } from '@ng360/slides';
+import { SyncPollModule } from '@codelab/utils/src/lib/sync/components/poll/sync-poll.module';
+import { SyncButtonModule } from '@codelab/utils/src/lib/sync/sync-button/sync-button.module';
+import { SyncDirectivesModule } from '@codelab/utils/src/lib/sync/directives/sync-directives.module';
+import { ConfigureSyncModule } from '@codelab/utils/src/lib/sync/components/configure-sync/configure-sync.module';
+import { SyncComponent } from './sync.component';
+
+@NgModule({
+ declarations: [SyncComponent],
+ exports: [SyncComponent],
+ imports: [
+ CommonModule,
+ SlidesModule,
+ SyncPollModule,
+ SyncButtonModule,
+ SyncDirectivesModule,
+ ConfigureSyncModule
+ ]
+})
+export class SyncModule {}
+
+@Component({
+ selector: 'codelab-sync-admin-wrapper',
+ template: ' '
+})
+export class SyncAdminWrapperComponent {}
+
+const routes = RouterModule.forChild(
+ SlidesRoutes.get(SyncAdminWrapperComponent)
+);
+
+@NgModule({
+ declarations: [SyncAdminWrapperComponent],
+ imports: [SyncModule, routes]
+})
+export class SyncAdminModule {}
diff --git a/libs/utils/src/lib/sync/components/registration/registration-viewer/registration-viewer.component.css b/codelab-master/apps/codelab/src/assets/.gitkeep
similarity index 100%
rename from libs/utils/src/lib/sync/components/registration/registration-viewer/registration-viewer.component.css
rename to codelab-master/apps/codelab/src/assets/.gitkeep
diff --git a/codelab-master/apps/codelab/src/assets/icons/icon-128x128.png b/codelab-master/apps/codelab/src/assets/icons/icon-128x128.png
new file mode 100644
index 000000000..9f9241f0b
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/icons/icon-128x128.png differ
diff --git a/codelab-master/apps/codelab/src/assets/icons/icon-144x144.png b/codelab-master/apps/codelab/src/assets/icons/icon-144x144.png
new file mode 100644
index 000000000..4a5f8c163
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/icons/icon-144x144.png differ
diff --git a/codelab-master/apps/codelab/src/assets/icons/icon-152x152.png b/codelab-master/apps/codelab/src/assets/icons/icon-152x152.png
new file mode 100644
index 000000000..34a1a8d64
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/icons/icon-152x152.png differ
diff --git a/codelab-master/apps/codelab/src/assets/icons/icon-192x192.png b/codelab-master/apps/codelab/src/assets/icons/icon-192x192.png
new file mode 100644
index 000000000..9172e5dd2
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/icons/icon-192x192.png differ
diff --git a/codelab-master/apps/codelab/src/assets/icons/icon-384x384.png b/codelab-master/apps/codelab/src/assets/icons/icon-384x384.png
new file mode 100644
index 000000000..e54e8d3ea
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/icons/icon-384x384.png differ
diff --git a/codelab-master/apps/codelab/src/assets/icons/icon-512x512.png b/codelab-master/apps/codelab/src/assets/icons/icon-512x512.png
new file mode 100644
index 000000000..51ee297df
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/icons/icon-512x512.png differ
diff --git a/codelab-master/apps/codelab/src/assets/icons/icon-72x72.png b/codelab-master/apps/codelab/src/assets/icons/icon-72x72.png
new file mode 100644
index 000000000..2814a3f30
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/icons/icon-72x72.png differ
diff --git a/codelab-master/apps/codelab/src/assets/icons/icon-96x96.png b/codelab-master/apps/codelab/src/assets/icons/icon-96x96.png
new file mode 100644
index 000000000..d271025c4
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/icons/icon-96x96.png differ
diff --git a/codelab-master/apps/codelab/src/assets/icons/touch-icon-ios.png b/codelab-master/apps/codelab/src/assets/icons/touch-icon-ios.png
new file mode 100644
index 000000000..08e51b799
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/icons/touch-icon-ios.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/angular-notice.png b/codelab-master/apps/codelab/src/assets/images/angular-notice.png
new file mode 100644
index 000000000..2b5d1f979
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/angular-notice.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/angular.png b/codelab-master/apps/codelab/src/assets/images/angular.png
new file mode 100644
index 000000000..1977b0733
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/angular.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/angular.svg b/codelab-master/apps/codelab/src/assets/images/angular.svg
new file mode 100644
index 000000000..bf081acb1
--- /dev/null
+++ b/codelab-master/apps/codelab/src/assets/images/angular.svg
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/assets/images/block.png b/codelab-master/apps/codelab/src/assets/images/block.png
new file mode 100644
index 000000000..b6dc6df70
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/block.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/bridge-at-villeneuve-la-garenne-1872.jpg b/codelab-master/apps/codelab/src/assets/images/bridge-at-villeneuve-la-garenne-1872.jpg
new file mode 100644
index 000000000..7717e006c
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/bridge-at-villeneuve-la-garenne-1872.jpg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/bzU-gXSyAcs.jpg b/codelab-master/apps/codelab/src/assets/images/bzU-gXSyAcs.jpg
new file mode 100644
index 000000000..72be56919
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/bzU-gXSyAcs.jpg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/cat-00.png b/codelab-master/apps/codelab/src/assets/images/cat-00.png
new file mode 100644
index 000000000..c795f7d67
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/cat-00.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/cat-01.jpg b/codelab-master/apps/codelab/src/assets/images/cat-01.jpg
new file mode 100644
index 000000000..f47a82ce7
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/cat-01.jpg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/cat-02.jpg b/codelab-master/apps/codelab/src/assets/images/cat-02.jpg
new file mode 100644
index 000000000..13104f78b
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/cat-02.jpg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/cat-03.jpg b/codelab-master/apps/codelab/src/assets/images/cat-03.jpg
new file mode 100644
index 000000000..daeb04494
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/cat-03.jpg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/cat-04.jpg b/codelab-master/apps/codelab/src/assets/images/cat-04.jpg
new file mode 100644
index 000000000..cd4a49b88
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/cat-04.jpg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/cat-05.png b/codelab-master/apps/codelab/src/assets/images/cat-05.png
new file mode 100644
index 000000000..7322f463f
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/cat-05.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/cat-06.jpg b/codelab-master/apps/codelab/src/assets/images/cat-06.jpg
new file mode 100644
index 000000000..a81ad36cf
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/cat-06.jpg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/cat-07.jpg b/codelab-master/apps/codelab/src/assets/images/cat-07.jpg
new file mode 100644
index 000000000..5319794ae
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/cat-07.jpg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/cat-08.jpg b/codelab-master/apps/codelab/src/assets/images/cat-08.jpg
new file mode 100644
index 000000000..8634bdf69
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/cat-08.jpg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/cat-09.jpg b/codelab-master/apps/codelab/src/assets/images/cat-09.jpg
new file mode 100644
index 000000000..f201ff344
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/cat-09.jpg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/cat-10.jpg b/codelab-master/apps/codelab/src/assets/images/cat-10.jpg
new file mode 100644
index 000000000..8af83dde5
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/cat-10.jpg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/cat-11.jpg b/codelab-master/apps/codelab/src/assets/images/cat-11.jpg
new file mode 100644
index 000000000..6a3ef53ab
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/cat-11.jpg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/cat-12.jpg b/codelab-master/apps/codelab/src/assets/images/cat-12.jpg
new file mode 100644
index 000000000..fe80d92d7
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/cat-12.jpg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/cat-13.jpg b/codelab-master/apps/codelab/src/assets/images/cat-13.jpg
new file mode 100644
index 000000000..46e7d9cfc
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/cat-13.jpg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/cat-14.jpg b/codelab-master/apps/codelab/src/assets/images/cat-14.jpg
new file mode 100644
index 000000000..a81ad36cf
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/cat-14.jpg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/cat-15.jpg b/codelab-master/apps/codelab/src/assets/images/cat-15.jpg
new file mode 100644
index 000000000..607fe3b73
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/cat-15.jpg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/cat-16.jpg b/codelab-master/apps/codelab/src/assets/images/cat-16.jpg
new file mode 100644
index 000000000..68f21814d
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/cat-16.jpg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/cat-17.jpg b/codelab-master/apps/codelab/src/assets/images/cat-17.jpg
new file mode 100644
index 000000000..7bc9dbc5a
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/cat-17.jpg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/cat-18.jpg b/codelab-master/apps/codelab/src/assets/images/cat-18.jpg
new file mode 100644
index 000000000..e5619cc1e
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/cat-18.jpg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/chat.png b/codelab-master/apps/codelab/src/assets/images/chat.png
new file mode 100644
index 000000000..dcd35b91b
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/chat.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/code.svg b/codelab-master/apps/codelab/src/assets/images/code.svg
new file mode 100644
index 000000000..2d836d044
--- /dev/null
+++ b/codelab-master/apps/codelab/src/assets/images/code.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/codelab-master/apps/codelab/src/assets/images/consoletop-left.png b/codelab-master/apps/codelab/src/assets/images/consoletop-left.png
new file mode 100644
index 000000000..9ce87cf6f
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/consoletop-left.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/consoletop-middle.png b/codelab-master/apps/codelab/src/assets/images/consoletop-middle.png
new file mode 100644
index 000000000..20362325d
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/consoletop-middle.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/consoletop-right.png b/codelab-master/apps/codelab/src/assets/images/consoletop-right.png
new file mode 100644
index 000000000..085db4034
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/consoletop-right.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/consoletop.png b/codelab-master/apps/codelab/src/assets/images/consoletop.png
new file mode 100644
index 000000000..4b281636a
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/consoletop.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/document_view.png b/codelab-master/apps/codelab/src/assets/images/document_view.png
new file mode 100644
index 000000000..e79954470
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/document_view.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/dog.jpg b/codelab-master/apps/codelab/src/assets/images/dog.jpg
new file mode 100644
index 000000000..170491cbe
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/dog.jpg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/expand.png b/codelab-master/apps/codelab/src/assets/images/expand.png
new file mode 100644
index 000000000..f1ce28602
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/expand.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/file-html.png b/codelab-master/apps/codelab/src/assets/images/file-html.png
new file mode 100644
index 000000000..edd6f48ef
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/file-html.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/file-ts.png b/codelab-master/apps/codelab/src/assets/images/file-ts.png
new file mode 100644
index 000000000..74e9340a7
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/file-ts.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/file.png b/codelab-master/apps/codelab/src/assets/images/file.png
new file mode 100644
index 000000000..4fc40cddb
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/file.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/folder.png b/codelab-master/apps/codelab/src/assets/images/folder.png
new file mode 100644
index 000000000..bd058e4d0
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/folder.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/hb.jpg b/codelab-master/apps/codelab/src/assets/images/hb.jpg
new file mode 100644
index 000000000..b51cae72b
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/hb.jpg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/helloworldapp.png b/codelab-master/apps/codelab/src/assets/images/helloworldapp.png
new file mode 100644
index 000000000..93c99071f
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/helloworldapp.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/home.png b/codelab-master/apps/codelab/src/assets/images/home.png
new file mode 100644
index 000000000..ea14c6602
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/home.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/icon.png b/codelab-master/apps/codelab/src/assets/images/icon.png
new file mode 100644
index 000000000..77905c150
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/icon.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/icons/fullscreen.png b/codelab-master/apps/codelab/src/assets/images/icons/fullscreen.png
new file mode 100644
index 000000000..f6dbadddc
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/icons/fullscreen.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/icons/github-icon.png b/codelab-master/apps/codelab/src/assets/images/icons/github-icon.png
new file mode 100644
index 000000000..405b4ebee
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/icons/github-icon.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/icons/icon-tools.png b/codelab-master/apps/codelab/src/assets/images/icons/icon-tools.png
new file mode 100644
index 000000000..cf327aa41
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/icons/icon-tools.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/icons/logout.svg b/codelab-master/apps/codelab/src/assets/images/icons/logout.svg
new file mode 100644
index 000000000..a5dce8820
--- /dev/null
+++ b/codelab-master/apps/codelab/src/assets/images/icons/logout.svg
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/assets/images/lock.png b/codelab-master/apps/codelab/src/assets/images/lock.png
new file mode 100644
index 000000000..40eaf98b6
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/lock.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/ng-angry.svg b/codelab-master/apps/codelab/src/assets/images/ng-angry.svg
new file mode 100644
index 000000000..8b807b60b
--- /dev/null
+++ b/codelab-master/apps/codelab/src/assets/images/ng-angry.svg
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/assets/images/ng-ok.svg b/codelab-master/apps/codelab/src/assets/images/ng-ok.svg
new file mode 100644
index 000000000..f547602cf
--- /dev/null
+++ b/codelab-master/apps/codelab/src/assets/images/ng-ok.svg
@@ -0,0 +1,71 @@
+
+
+
+image/svg+xml
\ No newline at end of file
diff --git a/codelab-master/apps/codelab/src/assets/images/ng-sad.svg b/codelab-master/apps/codelab/src/assets/images/ng-sad.svg
new file mode 100644
index 000000000..6e528eb58
--- /dev/null
+++ b/codelab-master/apps/codelab/src/assets/images/ng-sad.svg
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/assets/images/ng-sleepy.svg b/codelab-master/apps/codelab/src/assets/images/ng-sleepy.svg
new file mode 100644
index 000000000..4926f5313
--- /dev/null
+++ b/codelab-master/apps/codelab/src/assets/images/ng-sleepy.svg
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/assets/images/ng-smile.svg b/codelab-master/apps/codelab/src/assets/images/ng-smile.svg
new file mode 100644
index 000000000..9da6ef0b6
--- /dev/null
+++ b/codelab-master/apps/codelab/src/assets/images/ng-smile.svg
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/codelab/src/assets/images/ng-soso.svg b/codelab-master/apps/codelab/src/assets/images/ng-soso.svg
new file mode 100644
index 000000000..dae0df5a4
--- /dev/null
+++ b/codelab-master/apps/codelab/src/assets/images/ng-soso.svg
@@ -0,0 +1,71 @@
+
+
+
+image/svg+xml
\ No newline at end of file
diff --git a/codelab-master/apps/codelab/src/assets/images/park.jpg b/codelab-master/apps/codelab/src/assets/images/park.jpg
new file mode 100644
index 000000000..3daea2047
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/park.jpg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/renoir.jpg b/codelab-master/apps/codelab/src/assets/images/renoir.jpg
new file mode 100644
index 000000000..959bf9bd0
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/renoir.jpg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/responsive-framework.svg b/codelab-master/apps/codelab/src/assets/images/responsive-framework.svg
new file mode 100644
index 000000000..0ff2b594f
--- /dev/null
+++ b/codelab-master/apps/codelab/src/assets/images/responsive-framework.svg
@@ -0,0 +1,169 @@
+
+
+
+ Responsive Framework
+ Created with Sketch.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/codelab-master/apps/codelab/src/assets/images/sisley/img0.jpeg b/codelab-master/apps/codelab/src/assets/images/sisley/img0.jpeg
new file mode 100644
index 000000000..e51a7813a
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/sisley/img0.jpeg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/sisley/img1.jpeg b/codelab-master/apps/codelab/src/assets/images/sisley/img1.jpeg
new file mode 100644
index 000000000..6ab62ce26
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/sisley/img1.jpeg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/sisley/img2.jpeg b/codelab-master/apps/codelab/src/assets/images/sisley/img2.jpeg
new file mode 100644
index 000000000..42e771de8
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/sisley/img2.jpeg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/sisley/img3.jpeg b/codelab-master/apps/codelab/src/assets/images/sisley/img3.jpeg
new file mode 100644
index 000000000..8b360bf28
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/sisley/img3.jpeg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/sisley/img4.jpeg b/codelab-master/apps/codelab/src/assets/images/sisley/img4.jpeg
new file mode 100644
index 000000000..51db06aec
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/sisley/img4.jpeg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/sisley/img5.jpeg b/codelab-master/apps/codelab/src/assets/images/sisley/img5.jpeg
new file mode 100644
index 000000000..6fd3633e4
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/sisley/img5.jpeg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/sisley/img6.jpeg b/codelab-master/apps/codelab/src/assets/images/sisley/img6.jpeg
new file mode 100644
index 000000000..97e74c17c
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/sisley/img6.jpeg differ
diff --git a/codelab-master/apps/codelab/src/assets/images/speed-performance.svg b/codelab-master/apps/codelab/src/assets/images/speed-performance.svg
new file mode 100644
index 000000000..0331dbdec
--- /dev/null
+++ b/codelab-master/apps/codelab/src/assets/images/speed-performance.svg
@@ -0,0 +1,279 @@
+
+
+
+ Speed & Performance
+ Created with Sketch.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/codelab-master/apps/codelab/src/assets/images/tree.png b/codelab-master/apps/codelab/src/assets/images/tree.png
new file mode 100644
index 000000000..86cd829a2
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/tree.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/ts.png b/codelab-master/apps/codelab/src/assets/images/ts.png
new file mode 100644
index 000000000..f72e727d4
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/ts.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/vrhelloworld.png b/codelab-master/apps/codelab/src/assets/images/vrhelloworld.png
new file mode 100644
index 000000000..0ca92d098
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/vrhelloworld.png differ
diff --git a/codelab-master/apps/codelab/src/assets/images/well_done.gif b/codelab-master/apps/codelab/src/assets/images/well_done.gif
new file mode 100644
index 000000000..38c7b5dba
Binary files /dev/null and b/codelab-master/apps/codelab/src/assets/images/well_done.gif differ
diff --git a/codelab-master/apps/codelab/src/environments/environment.prod.ts b/codelab-master/apps/codelab/src/environments/environment.prod.ts
new file mode 100644
index 000000000..340c086d6
--- /dev/null
+++ b/codelab-master/apps/codelab/src/environments/environment.prod.ts
@@ -0,0 +1,15 @@
+export const environment = {
+ production: true,
+
+ // Firebase
+ // TODO: Create a new firebase app/config for prod deploy.
+ firebaseConfig: {
+ apiKey: 'AIzaSyBiY1Lg2RIcKtbgqzfE6Vrg28Zjal6ZWHs',
+ authDomain: 'angular-presentation.firebaseapp.com',
+ databaseURL: 'https://angular-presentation.firebaseio.com',
+ projectId: 'angular-presentation',
+ storageBucket: 'angular-presentation.appspot.com',
+ messagingSenderId: '1087862173437',
+ appId: '1:1087862173437:web:0bb7fe324b62580bb31894'
+ }
+};
diff --git a/codelab-master/apps/codelab/src/environments/environment.ts b/codelab-master/apps/codelab/src/environments/environment.ts
new file mode 100644
index 000000000..16e2f17eb
--- /dev/null
+++ b/codelab-master/apps/codelab/src/environments/environment.ts
@@ -0,0 +1,19 @@
+// The file contents for the current environment will overwrite these during build.
+// The build system defaults to the dev environment which uses `environment.ts`, but if you do
+// `ng build --env=prod` then `environment.prod.ts` will be used instead.
+// The list of which env maps to which file can be found in `.angular-cli.json`.
+
+export const environment = {
+ production: false,
+
+ // Firebase
+ firebaseConfig: {
+ apiKey: 'AIzaSyBiY1Lg2RIcKtbgqzfE6Vrg28Zjal6ZWHs',
+ authDomain: 'angular-presentation.firebaseapp.com',
+ databaseURL: 'https://angular-presentation.firebaseio.com',
+ projectId: 'angular-presentation',
+ storageBucket: 'angular-presentation.appspot.com',
+ messagingSenderId: '1087862173437',
+ appId: '1:1087862173437:web:0bb7fe324b62580bb31894'
+ }
+};
diff --git a/codelab-master/apps/codelab/src/index.html b/codelab-master/apps/codelab/src/index.html
new file mode 100644
index 000000000..1c5b5e7d6
--- /dev/null
+++ b/codelab-master/apps/codelab/src/index.html
@@ -0,0 +1,54 @@
+
+
+
+
+ Angular Codelab
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Please enable JavaScript to continue using this application.
+
+
diff --git a/codelab-master/apps/codelab/src/locale/codelab.ru.xtb b/codelab-master/apps/codelab/src/locale/codelab.ru.xtb
new file mode 100644
index 000000000..369860262
--- /dev/null
+++ b/codelab-master/apps/codelab/src/locale/codelab.ru.xtb
@@ -0,0 +1,555 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+]>
+
+ Angular Codelab
+ Милый котенок
+ В следующем упражнении вы будете использовать созданный ранее компонент
+ Здесь перечислены документация, описание функций и событий
+ Предположим, имеется HTML файл:
+ Это может быть сделано в три этапа.
+ Три этапа для создания приложения:
+ Создание Angular компонента
+ Создание Angular модуля
+ Запуск (Bootstrap) модуля
+ Компонент определяется декоратором <b> @Component</b> у класса
+ Создайте первый Angular компонент!
+ порядок загрузки: index -> main -> app.module -> app.component
+ Конец раздела загрузки (Bootstrap)
+ Отлично сработано! Упражнение выполнено!
+
+ Внедрение зависимостей
+ Узнайте про систему внедрения зависимости в Angular
+
+ Отметить зависимость декоратором @Injectable()
+ Передать модулю
+ Запросить в компоненте
+ Запрашиваем внедряемый сервис в компоненте
+ При привязке можно использовать произвольные выражения
+ Почему TypeScript?
+ TypeScript
+ В TypeScript есть<b> классы</b> , и Angular часто их использует.
+ Теперь мы можем использовать класс <b> Puppy</b> в другом файле.
+ Интерфейсы
+ Перечисляемые типы (enums)
+ Асинхронность / Ожидания
+ Деструктурирование
+ И много чего еще!
+ На следующем слайде будет упражнение по TypeScript
+ Выглядеть будет вот так:
+ Или пользуйтесь сокращенной натацией
+ Ошибка: очевидно, что это не собачка
+ Это число (number)
+ Дерево компонентов
+ Родительские и дочерние компоненты
+ Родительские и дочерние компоненты
+ Обзор
+ Упражнение 2
+ @Component это декоратор Angular
+ Декоратор указывается над сущностью (классом)
+ Имя компонента это имя класса (AppComponent)
+ Что такое Angular
+ Селектор
+ Встроенный шаблон
+ Модуль
+ Декоратор NgModule
+ BrowserModule
+ Declarations
+ Bootstrap
+ Создание первого Ng модуля
+ Bootstrapping
+ Bootstrapping 1
+ Bootstrapping 2
+ Bootstrapping 3
+ *Сокращения в Typescript делают 'profession' доступным в объекте компонента
+ предполагая, что Job имеет свойство '.title'
+ Параметры
+ Тестирование
+ Пример
+ Это рабочий HTML синтаксис.
+ Так можно привязать значение аттрибутов
+ Это позволяет условно сделать привязку к классу
+ Или CSS
+ Все работает с пользовательскими компонентами
+ При нажатии на кнопку, вызовется метод компонента "saveUser" и передаст соответствующий event.
+ Вы также можете создавать события для собственных компонентов.
+Здесь у нас есть событие "depleted", которое вызовет "soundAlarm" когда сработает
+ Еще есть упрощенный способ привязки событий!
+Если пользователь нажмет CTRL+ENTER, запустится метод submit (это возможность Angular)
+ в userName есть ссылка на input
+ Попробуйте изменить на true!
+ Необходимо повторить собачку тут
+ Интерполирование
+ Cвойства
+ Привязка свойства
+ Продвинутая привязка данных
+ Привязка событий
+ Повторяющиеся элементы
+ Повторение элементов (*ngFor)
+ Упражнение 3
+ Или используйте сокращенную нотацию для функций
+ (стрелочные функции)
+ TypeScript догадается, что это число
+ TypeScript догадается, что это строка (string)
+ Невозможно сложить число с логическим значением
+ У прототипа Number нет метода slice
+ Но можно для строки
+ Работает!
+ Type[] делает тоже самое.
+ Это метод
+ Гав гав
+ Теперь мы можем создать экземпляр класса Puppy
+ И вызвать его методы
+ Потом добавим здесь код
+ Создадим еще собачек
+ Var по-прежнему разрешен, но не рекомендуется.
+ Let рекомендуется для использования взамен var.
+ В отличие от var let недоступен вне this.
+ Const похож на let, но если вы попробуете изменить его, то TS выдаст ошибку.
+ хорошо, определенно boolean
+ TypeScript
+ Массивы
+ Конструктор
+ Модификатор доступа
+ Экспорт
+ Импорт
+ Фильтр (последнее)
+ Еще...
+ Раздел завершен
+ Тут не должно быть точки с запятой. Декоратор привязывается к классу.
+ Первое приложение на Angular
+ Вы узнаете как создать Angular компонент, добавить его в модуль и запустить приложение.
+ Знание основ TypeScript
+ Шаблоны
+ Узнайте больше о шаблонах в Angular!
+ Создайте класс с именем 'Codelab'
+ Основы JavaScript.
+ video/video.component.ts: Отметьте компонент декоратором '@Component' и добавьте в него селектор 'my-video'.
+ app.module.ts: Объявите компонент VideoComponent в свойстве 'declarations' модуля AppModule.
+ video.component.ts Добавьте ссылку на соответствующий HTML файл с шаблоном в свойство templateUrl , чтобы загрузить шаблон в компонент
+ video/video.component.ts: Добавьте свойство video и отметьте его декоратором @Input()
+ video/video.component.html: Отобразите название (title) видео
+ video/video.component.html: Отобразите превью (src) видео
+ video/video.component.html: Отобразите описание(description) видео
+ video/video.component.html: Выведите дату видео
+ video/video.component.html: Отобразите количество просмотров видео(views)
+ video/video.component.html: Отобразите количество отметок "нравится"(likes)
+ app.html: Замените текущие название и превью видео на наш чудесный компонент <my-video>
+ app.html: С помощью биндинга передайте объект "video" в компонент my-video (не забудьте про квадратные скобки)
+ Создайте класс 'AppComponent'
+ Создайте класс 'AppModule'
+ Всё готово! Загружайте приложение
+ Экспортируйте класс
+ Добавьте классу декоратор @Component
+ Добавьте селектор 'my-app' в @Component декоратор компонента
+ Добавьте шаблон, содержащий тег h1 с текстом "Hello MewTube!"
+ Добавьте классу декоратор NgModule
+ Добавьте 'BrowserModule' в свойство 'imports' декоратора NgModule
+ Добавьте компонент 'AppComponent' к свойству 'declarations' у декоратора
+ Добавьте компонент 'AppComponent' в свойство 'bootstrap' декоратора
+ video.service.ts: Добавьте классу декоратор @Injectable()
+ app.module.ts: Добавьте VideoService в свойство providers вашего NgModule
+ app.component.ts: Избавьтесь от константы FAKE_VIDEOS
+ app.component.ts: Внедрите 'VideoService' в конструктор компонента как
+ 'videoService'
+
+ app.component.ts: Сделайте так, чтобы метод 'search' компонента использовал метод 'search' сервиса 'videoService'
+ app.component.ts: Добавьте свойство 'videos', и установите пустой массив в качестве значения.
+ app.component.ts: Внутри метода 'search' установите переменную FAKE_VIDEOS в качестве значения свойства 'videos'.
+
+ app.component.ts: Добавьте в компонент метод 'search', который принимает параметр 'searchString'
+ app.html: Добавьте обработчик нажатия мышки на кнопку, вызовите метод 'search' и передайте значение поля ввода (Сам поиск мы сделаем позже)
+ app.html: Добавьте сообщение 'no videos', которое появляется только когда массив videos пуст
+ #Bonus app.component.ts: Сейчас вам придется нажать кнопку поиска, чтобы отобразились видео. Поправьте код так, чтобы видео отображались по умолчанию, без нажатия кнопки.
+ app.component.ts: Внутри метода 'search' отфильтруйте FAKE_VIDEOS так, чтобы возвращались только видео, название которых содержит искомую строку searchString. (подсказка: используйте .includes или .indexOf строковый метод)
+ app.html: Отобразите превью
+ app.html: Пройдитесь по массиву videos с помощью '*ngFor' и выведите название каждого видео
+ app.html: Добавьте кнопку (<button>) с текстом 'search' (Поиск)
+ app.html: Добавьте тег input с атрибутом 'placeholder' = 'video'
+ Добавьте конструктор
+ Примите значение 'guests' в качестве параметра конструктора
+ Укажите тип параметра guests (подсказка: массив типа Guest)
+ Отметьте параметр ключевым словом public (обратите внимание, что теперь вы можете получить к нему доступ в классе, обратившись к this.guests)
+ Создайте метод 'getGuestsComing'
+ Измените метод getGuestsComing так, чтобы он возвращал массив из элементов 'guests', у которых свойство 'coming' равно true.
+ Создайте ваше первое Angular приложение
+ Пользовательские события
+ Узнайте как создать и запустить ваше первое Angular приложение
+ Узнайте как пользоваться шаблонами в Angular
+ Узнайте как использовать систему внедрения звисимостей вместо того, чтобы хардкодить их
+ Узнайте как лучше всего организовать ваше приложение с помощью пользовательских компонентов.
+ Узнайте как привязывать события
+ Следующий шаг - определить компонент в <b> <b> NgModule</b> </b> .
+ С Angular мы создаем мобильные приложения, используя NativeScript или Ionic
+ С Angular мы можем создать VR приложения с помощью A-FRAME или WEDGL
+ Конец раздела Формы
+ Переменная 'b' в коде ниже отмечена как ошибка, так как тип отсутствует. Укажите тип переменной 'b'.
+ Благодаря этой информации, TypeScript может указать нам на ошибку. Исправьте eё, чтобы 2 + 2 снова стало равно 4!
+ Другие типы, которые можно использовать
+ TypeScript
+ Пропустите, если вы уже знакомы с TypeScript
+ Angular
+ Или нажмите сюда чтобы показать все разделы
+ Это конец курса от Codelab, но только начало вашего путешествия в Angular. Ниже приведены некоторые ссылки, которые могут помочь вам продолжить изучение.
+ Пока в нашем приложении только один компонент, но по мере роста приложения и добавления новых компонентов, у нас получится дерево компонентов
+ Внутри компонент может отобразить любой другой с помощью HTML тега, который соответствует селектору выбранного компонента
+ Родительский компонент передает свои данные дочернему через свойства
+ Измените <b> <b> размер</b> </b>
+ на <b> <b> 100 </b> </b> и <b> <b> цвет </b> </b> на <b> <b> красный </b> </b> , чтобы получить японский флаг
+ Свойства дочернего класса должны быть декорированы специальным <b> <b> @Input() </b> </b> декоратором
+ В этом случае мы впервые применяем декораторы к свойствам, а не к классам
+ В первом разделе мы изучили как создавать компоненты. Давайте создадим новый компонент VideoComponent и опишем там информацию, связанную с видео.
+ Результат будет отображаться автоматически. В итоге должно получиться следующее:
+ Компоненты не будут знать друг о друге, если они не задекларированы в общем модуле
+ Angular - это <b> платформа разработки</b> для создания приложений под мобильные телефоны и компьютеры. Angular позволяет <b> расширить HTML синтаксис</b> , чтобы кратко и удобно разрабатывать компоненты приложения. Привязка данных (Data Binding) и внедрение зависимостей (Dependency Injection) позволяют использовать код в существенно меньшем объеме.
+ Давайте создадим Angular приложение, которое заменит <b> <b> hello-world</b> </b> HTML элемент некоторым наполнением.
+
+ Компонент в Angular - это просто класс. Свойства и поведение описываются внутри этого класса.
+ Декораторы - новая функциональность TypeScript. Они описывают мета-данные к классу, функции, свойству класса или переменной.
+ 'Selector' привязывает компонент к соответствующему элементу в HTML структуре документа. Когда Angular находит <b> <b> hello-world</b> </b> HTML тег в документе, он отрисовывает шаблон HelloWorldComponent'а внутри этого тега
+ Шаблон (template) определяется HTML кодом, который генерируется компонентом.
+ Если количество тегов в HTML растет, можно (и рекомендуется) использовать <b> <b> templateUrl</b> </b> вместо этого, указав путь к файлу HTML с шаблоном.
+ На следующем слайде вы создадите свой первый <b> <b> Angular</b> </b> -компонент!
+Подготовьте компонент и опишите его поведение по предложенным инструкциям, результат будет отображен автоматически. В итоге должно получиться следующее:
+ <b> <b> NgModule</b> </b> не имеет визуального представления и используется исключительно для группировки функциональных элементов Angular
+
+ Мы узнаем больше о NgModule в следующих секциях
+
+ В списке <b> <b> declarations</b> </b> определяются компоненты, принадлежащие AppModule
+ Компонент, указываемый в списке <b> <b> bootstrap</b> </b> будет создан и показан в файле <b> <b> index.html</b> </b>
+ На следующем слайде вы создадите свой первый <b> <b> Angular</b> </b> -модуль.
+Подготовьте модуль и опишите его поведение по предложенным инструкциям, результат будет отображен автоматически. В итоге получится следующее:
+ У нас всё готово, самое время начать (загрузить) приложение
+ Передайте <b> <b> AppModule</b> </b> в метод <b> <b> bootstrapModule</b> </b> , и он запустит все компоненты из раздела bootstrap этого модуля
+ Для большинства простых приложений вы можете просто скопировать и вставить код выше «как есть»
+ Как работает начальная загрузка в Angular?
+ 1. Добавим среду исполнения. <b> <b> platformBrowserDynamic()</b> </b> указывает Angular, что мы работаем в браузере
+ Узнайте больше о корневом модуле и начальной загрузке в Angular
+ 2. Angular инициализирует компонент из списка <b> <b> bootstrap</b> </b> , указанного в <b> <b> app.module.ts</b> </b> (в нашем случае это <b> <b> HelloWorldComponent</b> </b> )
+ 3. Angular ищет в документе элемент, соответствующий селектору, определенному в <b> <b> HelloWorldComponent</b> </b> (в нашем случае это <b> <b> 'hello-world'</b> </b> ) и вставляет компонент внутрь этого элемента
+ Готово! На следующей странице вы запустите свое первое <b> <b> Angular</b> </b> -приложение
+ Теперь, когда у нас есть и NgModule, и готовый компонент, давайте загрузим приложение!
+ Пока Angular загружается, содержимое элемента остается неизменным: в нашем случае, "<b> <b> Loading...</b> </b> "
+ Мы пишем браузерное веб-приложение, поэтому в списке <b> <b> imports</b> </b> необходимо указать <b> <b> BrowserModule</b> </b>
+ <div> <div>
+ Angular применяется не только для веб-приложений. Вы также можете создавать мобильные приложения и даже VR-зарисовки.
+ </div> </div>
+ <div> <div>
+ <a> <a></a> </a>
+ </div> </div>
+
+ Без системы внедрения зависимостей (Dependency Injection), свойство <b> <b> profession</b> </b> должно быть инициализировано внутри класса <b> <b> Person</b> </b>
+ При использовании системы внедрения зависимостей (Dependency Injection), класс <b> <b> Person</b> </b> просто запрашивает объект <b> <b> Job</b> </b> в конструкторе. Angular инстанциирует зависимость и передает результат классу.
+ При использовании системы внедрения зависимостей Angular сделает это за вас.
+ Также внедрение зависимостей (Dependency Injection) значительно упрощает тестирование, так как для этого необходимо просто подать "ложные" зависимости (Mock Dependecies) в параметры конструктора
+ Предположим, что у нас есть существующий <b> <b> UnitConverterService</b> </b> и мы хотели бы использовать его в <b> <b> UnitConversionComponent</b> </b> . Для этого необходимо проделать 3 простых шага:
+ Мы помечаем класс декоратором <b> <b> @Injectable()</b> </b> , что позволяет Angular понять, что этот класс будет использован в системе внедрения зависимостей.
+ Если сервисный класс отмечен декоратором @Injectable(), он может запрашивать другие сервисы в конструкторе
+ Передайте все экспортируемые (injectable) зависимости в секцию <b> providers</b> вашего <b> NgModule</b>
+ Теперь этот сервис становится доступным для всех <b> компонентов</b> и других сервисов в <b> NgModule</b> .
+ Благодаря <b> <b> private</b> </b> модификатору доступа, сервис становится доступным через класс как <b> <b> this.converter</b> </b>
+ На следующем слайде вы используете (и внедрите) videoService, в котором будет еще больше котиков!!! Результат будет выглядеть вот так:
+ [(ngModel)] - <b> <b> Banana in the box</b> </b> — мнемоника для такого порядка скобок
+ У Angular очень выразительная система шаблонов, основанная на HTML, которую можно расширить новыми элементами
+ В двойные фигурные скобки записывается нужное свойство компонента
+ Обратные кавычки <b> <b> ` `</b> </b> — волшебные кавычки, позволяющие делать переносы строк и использовать строковую интерполяцию
+ Также можно использовать простые выражения: вы можете вызвать метод компонента (как fullName() ниже) или вычислить <code> <code> 323213+34234</code> </code>
+ На следующем слайде отредактируйте шаблон компонента, чтобы создать простой заголовок и форму поиска. Результат должен выглядеть следующим образом:
+ Строковая интерполяция <b> <b>{{ curlies }} {{ curlies }}</b> </b> также позволяет передавать значения в атрибуты дочерних элементов
+ Но лучше использовать property binding (привязку свойств) <b> <b> [attribute]="property"</b> </b>
+
+ Angular поддерживает более продвинутые привязки свойств, чем просто имя атрибута
+ Это условное выражение добавляет или удаляет DOM элемент по условию
+ На следующем слайде добавьте обработчик нажатий кнопки поиска и отображение сообщения для случая, когда ни одно видео не было найдено. Результат должен выглядеть следующим образом:
+ Допустим, у нас есть список щенков, и мы хотим отобразить их на странице. Для этого в Angular есть специальный синтаксис — <b> <b> *ngFor</b> </b>
+Давайте посмотрим, как это работает на следующем слайде
+ Для каждого щенка в массиве всех щенков<b> <b> *ngFor</b> </b> повторяет тот HTML-элемент, в котором и указан (в этом случае li)
+ HTML-атрибуты в <b> <b> Angular</b> </b> регистрозависимы:
+ <b> <b><s> <s> *ngfor</s> </s></b> </b> не сработает, а <b> <b> *ngFor</b> </b> сработает
+ На следующем слайде вы, наконец, покажете видео! Результат будет выглядеть следующим образом:
+ <b> <b> JavaScript</b> </b> – отличный язык, однако, при его использовании есть некоторая специфика:
+ <b> <b> ES</b> </b> расшифровывается как
+ <a> <a><b> <b> ECMAScript</b> </b></a> </a> - стандарт языка JavaScript.
+ Кроме этого, TypeScript расширяет систему типов и декораторов
+ Декораторы выглядят как @twitter_handles, мы изучим их позже
+ Ниже приведена функция <b> <b> add</b> </b> , где мы складываем 2 + 2. Что может пойти не так?
+ Оказывается, можно передать строку в качестве параметра и получить
+ <b> <b> 22</b> </b> вместо <b> <b> 4</b> </b> . Давайте посмотрим, как TypeScript поможет нам это предотвратить.
+ В TypeScript для указания типа используется "<b> <b> :</b> </b> " (например,
+ <b> <b> n: number</b> </b> ). Как <b> <b> a</b> </b> , так и <b> <b> b</b> </b> должны быть числами. Мы указали тип <b> <b> a</b> </b> , теперь ваша очередь!
+ Код выше можно редактировать
+ Здесь каждый элемент в массиве <b> <b> betterCats</b> </b> — экземпляр интерфейса <b> <b> Cat</b> </b> .
+ Они похожи на классы в других языках программирования и используются для группировки методов и свойств
+ В классе есть специальный метод: <b> <b> constructor</b> </b> , который вызывается при создании класса и позволяет записать полученные параметры в свойства класса.
+ Параметры конструктора, отмеченные как <b> <b> public </b> </b> (или private, или protected), записываются в свойства класса. Они будут доступны как <b> <b> this.ParameterName </b> </b> внутри класса.
+ Свойства 'private' или 'protected' не могут быть использованы вне класса.
+ Возможно, вы заметили оператор <b> <b> export </b> </b> перед классом.
+Он используется для того, чтобы сделать класс доступным в других файлах. На следующем слайде мы покажем вам, как импортировать и использовать тот класс в другом файле.
+ "<b> <b> filter</b> </b> " - метод массива, который позволяет генерировать новый массив, выбрав только значения, удовлетворяющие условию
+ TypeScript поддерживает множество других интересных и полезных штук, например:
+ Стрелочные функции
+ Мы не будем рассматривать их подробно, вы можете ознакомиться с ними на сайте <a> <a> TypeScript </a> </a>
+ Ваша задача - создать TypeScript класс и назвать его CodeLab. При создании он получит список гостей. Также мы создадим метод, который выведет список тех, кто придет.
+ ES7
+ Декораторы
+ Типы
+ TypeScript
+ Классы
+ Модули
+ Далее...
+ Используйте клавиши <b> <b> ←</b> </b> и <b> <b> →</b> </b> на клавиатурe для навигации по слайдам.
+ Необходимые знания
+ Опишите ошибку, или поделитесь идеями
+ Отлично
+ Хорошо
+ Норм
+ Не очень
+ Оцените этот урок ...
+ Узнайте как быстро начать работу над вашим Angular приложением
+ Дерево компонентов
+ Научитесь выстраивать взаимосвязь между компонентами
+ Формы
+ Добавьте несложные формы в ваше приложение
+ Material Design
+ Узнайте как использовать библиотеку Angular Material
+ Маршрутизация
+ Узнайте как добавить маршрутизацию в ваше приложение
+ Этот курс написан на Angular и <a> <a> доступен на Github</a> </a> . Пожалуйста, поставьте ⭐, если вам понравилось! :)
+ Привет, я - <b> <b> angular-cli</b> </b> , я инструмент для командой строки!
+ Прежде всего убедитесь, что на вашем компьютере есть node.js.
+ Откройте командную строку и введите: <code> <code> node -v</code> </code>
+ Если увидите ошибку, следуйте <a> <a> инструкциям по настройке Node.js</a> </a>
+ Перейдите в папку с только что созданным приложением и запустите его командой <code> <code> ng serve</code> </code>
+ Когда приложение запустится, откройте
+ <a> <a> http://localhost:4200/</a> </a> в вашем браузере
+ Вы можете сгенерировать новые компоненты командой
+ <code> <code> ng generate component my-component</code> </code>
+ Вы также можете генерировать модули, сервисы и пайпы
+ Можно использовать упрощенную версию: <code> <code> ng g c my-component</code> </code>
+ У нас есть несложная форма, давайте разберемся как привязать ее значения к параметрам компонента
+ Сначала необходимо добавить <b> <b> FormsModule</b> </b> в наш NgModule
+ Далее мы можем использовать ngModel, чтобы привязать поля ввода к соответствующим параметрам компонента.
+ Пропробуйте поменять значение полей ввода, чтобы обновить значения
+ Давайте сделаем поле "username" обязательным (<b> <b> required</b> </b> )
+ Теперь отобразим валидационную ошибку. Для этого нужно проделать следующее:
+ Получить доступ к модели (ngModel) поля ввода с помощью <b> <b> #name="ngModel"</b> </b>
+ Использовать свойство <b> <b> errors </b> </b> у свойства <b> <b> usernameModel</b> </b>
+ Попробуйте очистить поле username, чтобы увидеть ошибку
+ Ниже представлен список <a> <a> встроеных валидаторов</a> </a> , которые используются в Angular
+ min - Минимальное значение (для чисел)
+ max - Максимальное значение (для чисел)
+ required - Обязательное значение
+ requiredTrue - Обязательное правдивое значение для флага
+ email - Соответствие регулярному выражению email'а
+ minLength - Минимальная длина текстового поля
+ maxLength - Максимальная длина текстового поля
+ pattern - Регулярное выражение для текстового поля
+ Можно также создавать собственные валидаторы, узнайте больше: <a> <a> здесь</a> </a>
+ Осталось решить небольшую проблему: если не указывать изначальные значение полей ввода, ошибка будет отображена сразу
+ Мы можем проверить, взаимодействовал ли пользователь с полем ввода с помощью свойства <b> <b> touched</b> </b> .
+ Значение <b> <b> touched</b> </b> положительно, если юзер сфокусировался на поле ввода и после убрал фокус, не меняя значение.
+ Попробуйте добавить/убрать фокус с поля ввода, или добавить/удалить значение, чтобы увидеть ошибку.
+ Теперь давайте сделаем нашу форму красивой с помощью Material Design.
+Основные строительные блоки:
+ <b> <b> mat-form-field</b> </b> - Обертка вокруг поля ввода
+ <b> <b> matInput</b> </b> - Аттрибут должен быть добавлен на поле ввода
+
+ <b> <b> mat-error</b> </b> - Умная обертка для ошибок
+ Обратите внимание, что нам больше не нужно добавлять <b> <b> #name</b> </b> на поле ввода.
+ На следующем слайде будет упражнение, в котором мы добавим форму на страницу загрузки.
+ Обратите внимание: вам нужно будет вручную нажать на кнопку upload, чтобы увидеть результат
+ Есть два основных способа работы с формами в Angular. Пока раздел <b> <b> Продвинутых форм</b> </b> в разработке, прочитайте <a> <a> документацию Angular </a> </a>
+ Быстрые
+ Гибкие в использовании
+ Поддерживают Accessibility(доступность в использовании)
+ Оптимизированы для Angular
+ Отлично выглядят на мобильных устройствах
+ Вы можете посмотреть список компонентов
+ <a> <a> здесь</a> </a>
+ Добавьте <b> <b> MatToolbarModule</b> </b> в импорты
+ Используйте компонент в шаблоне
+ Обратите внимание, что анимации в Angular вынесены в отдельный модуль. Мы добавляем
+ <b> <b> NoopAnimationsModule</b> </b> здесь, но могли бы использовать
+ <b> <b> BrowserAnimationsModule</b> </b> вместо того, чтобы получить полноценные анимации.
+ Теперь давайте добавим material card
+ Заголовок и картинка
+ Добавим пару кнопок
+ Обратите внимание, что мы используем аттрибут <b> <b> mat-button</b> </b> вместо отдельного тега.
+ Indigo
+ Deep purple
+ Pink
+ Purple
+ На следующем слайде будет упражнение. Мы применим Angular Material к нашему приложению.
+ Примечание: В результате наше приложение не будет выглядеть так прекрасно как могло бы, но мы работаем над этим.
+ Котятки
+ Щеночки
+ Настройте машрутизацию, привязав компоненты к соответствующим URL
+
+ Создайте меню
+ Выберите место, где отобразить выбранный компонент
+ Потом передадим конфигурацию в наш модуль
+ Обратите внимание, что мы используем <b> <b> RouterModule.forRoot</b> </b> , который превращает нашу конфигурацию в Модуль Angular.
+ Теперь выберем место, где роутер отобразит выбранный компонент.
+ Мы можем сделать это положив тег <b> <b> router-outlet</b> </b> в нужное место в нужном компоненте
+ Осталось создать меню
+ Используйте директиву <b> <b> routerLink</b> </b> чтобы передать ссылку
+ На следующем слайде будет упражнение, в котором мы добавим два роута:
+ <b> <b> Search</b> </b> и <b> <b> Upload</b> </b> и меню для переключения между ними
+ Мы уже создали пустой компонент Upload и SearchComponent, содержащий логику для поиска.
+ Изучите <a> <a> Angular Router Guide</a> </a> чтобы подняться на более продвинутый уровень.
+ Без системы внедрения зависимостей, вам придется разбираться со всеми параметрами самостоятельно.
+ Добро пожаловать в интерактивный курс по Angular. Здесь вы сможете выучить основы <a> <a> Angular</a> </a> !
+ app.module.ts: Добавьте MatCardModule и MatToolbarModule в свойство "imports".
+ app.html: Добавьте material toolbar, содержащий значение свойства title
+ video/video.component.html: Используйте material card, чтобы отобразить дату
+ video/video.component.html: Добавьте mat-card-title (внутри of the mat-card), чтобы отобразить заголовок видео (title)
+ video/video.component.html: Добавьте mat-card-subtitle (внутри mat-card), чтобы отобразить описание (description)
+ video/video.component.html: Добавьте к картинке (img) аттрибут mat-card-image и ее ширина увеличится до ширины mat-card
+ video/video.component.html: Перенесите дату/информацию о просмотрах/лайках в mat-card-content (внутри mat-card)
+ app.module.ts: Используя RouterModule.forRoot, передайте пустой массив в модуль
+ app.module.ts: Добавьте роут с пустым ('') путем, отображающий SearchComponent
+ app.module.ts: Добавьте роут с путем ('upload'), отображающий UploadComponent
+ app.html: Добавьте router-outlet
+
+
+ Следующий слайд
+ Показать только следующий шаг
+ Введение
+ Установка
+ Создание нового приложение на Angular
+ Запускаем приложение
+ Генерируем компоненты
+ Упражнение 1
+ Узнайте, как настроить роутинг в вашем Angular приложении
+ Шаг 1
+ Декораторы
+ Упражнение
+ Шаг 2
+ К разделу "Шаблоны"
+ Пример зависимости
+ Сравнение
+ Шаг 3
+ Узнайте, как комбинировать компоненты
+ Простая форма
+ NgModel
+ Валидация
+ Отображение ошибки валидации
+ Валидаторы
+ Свойства Touched & Dirty
+ Material инпуты (бонус!)
+ Теперь сделаем наше приложение более привлекательным при помощи
+ <a> <a> Angular Material</a> </a> ✨✨
+ MatCard
+ Заголовок MatCard
+ MatButton
+ Темы оформления
+ Узнайте, как создавать простые формы в Angular
+ Конфигурация
+ Меню
+ Узнайте, как создавать красивые интерфейсы с помощью Angular Material
+ Узнайте, как использовать Angular Dependency Injection
+ Система типов
+ Классы
+ Узнайте, как создать ваше первое Angular приложение!
+ Angular CLI — инструмент для командной строки, который можно использовать для ускорения работы с вашим Angular приложением
+ Передача данных от родительского компонента к дочернему
+
+ Начнем с создания Angular <b> <b> Component </b> </b> 'а. Компоненты в Angular отвечают за визуальную часть приложения.
+
+ Как и компонент, модуль в <b> <b> Angular</b> </b> - это просто класс 👍(JavaScript class)
+ Как и компонент, модуль в <b> <b> Angular</b> </b> оборачивается в декоратор, в котором задается конфигурация модуля
+ При помощи готовых директив, включенных в Angular, можно легко добавить валидацию инпутов
+ Если вы очистите инпут, он будет помечен ошибкой, однако при этом никакой ошибки показано не будет. На следующем слайде мы узнаем, как их отображать.
+ Прочитайте больше о темах Angular Material
+ <a> <a> в этом руководстве</a> </a>
+ Роуты настраиваются с помощью создания списка, привязывающего URL-адресами к соответствующим компонентам
+ router-outlet
+ В этом примере, <b> <b> realPuppy</b> </b> — экземпляр интерфейса <b> <b> Puppy</b> </b> .
+
+ Angular-cli
+ Ошибка всегда показана
+ Angular написан на TypeScript, который, в свою очередь, является расширением JavaScript. Узнайте больше о TypeScript.
+ Angular написан на TypeScript. Узнайте больше про основы языка.
+
+ JavaScript не поддерживает строгую типизацию, что затрудняет разработку крупных приложений
+ TypeScript добавляет новую функциональность из следующей версии JavaScript
+ node
+ позволяет легко создавать работающее приложение прямо из коробки и генерировать новые компоненты! Он также настраивает конфигурацию сборки.
+ Далее:
+ Angular Material предоставляет набор Angular компонентов в стиле
+ <a> <a> Material Design</a> </a> , которые имеют ряд преимуществ:
+ MatToolBar
+ Смотрите также <a> <a> руководство для начала работы с Angular Material</a> </a>
+ Таким образом, наш компонент будет зависеть от VideoService
+ Далее...
+ Показать все шаги
+ Декораторы в <b> <b> Angular </b> </b> добавляют специальную информацию к классу.
+ Условное отображение (*ngIf)
+ Этот курс написан на Angular
+ Поставьте нам ⭐ если вы выучили что-то полезное
+ Не надо меня бояться, меня легко использовать
+ Если в результате увидите число(номер версии), то все в порядке, переходите на следующий слайд.
+ Декораторы в TypeScript были созданы по образу и подобию аналогичной функциональности в языке Python.
+ Мы показываем захардкоженый список видеозаписей в нашем компоненте, но в реальном приложении мы бы загрузили их с сервера
+ Код для получения данных был бы выделен в отдельный класс (сервис) с именем VideoService
+ С ростом нашего приложения, увеличивается и число зависимостей. В свою очередь, зависимости будут обрастать собственными зависимостями. Держать это все под контролем вручную становится все сложнее и сложнее
+ Чтобы упростить это, у <b> <b> Angular</b> </b> есть механизм, который называется <b> <b> Dependency injection</b> </b>
+ app.module.ts: Добавьте FormsModule и MatInputModule в свойство "imports".
+ upload/upload.component.html: Добавьте поле ввода "title" и привяжите его к свойству title компонента
+ upload/upload.component.html: Добавьте текстовое поле (textarea) "description" и привяжите к свойству description компонента
+ Значение <b> <b> dirty</b> </b> положительно, если пользователь изменил значение текстового поля.
+ Узнайте, как начать работу с Angular приложением в разделе "Angular-cli"
+ Все компоненты Angular Material позволяют применять темы. Попробуйте различные темы, нажимая на кнопки ниже:
+ Router is used to give <b> <b> URLs</b> </b> to different parts of your app.
+ Новая функциональность последних версий стандарта JavaScript часто может не поддерживаться в некоторых браузерах
+ Поэтому был создан <b> <b> TypeScript</b> </b> . Так как TypeScript может быть скомпилирован в JavaScript, он поддерживает все версии современных браузеров.
+ TypeScript расширяет последнюю версию JavaScript
+ Интерфейсы в Typescript позволяют указывать, какие свойства и методы должны быть у объекта
+ Типы массивов указываются с помощью <b> <b> Array{{ '<' }} {{ '<' }} тип {{ '>' }} {{ '>' }}</b> </b> или <b> <b> Type[]</b> </b>
+ <b> <b> import</b> </b> и <b> <b> export</b> </b> предназначены не только для классов. Они работают и с переменными, функциями и другими конструкциями!
+ Accessors (Getters / Setters)
+ Имя
+ Email (не обязателен и будет спрятан)
+ Отправить
+ Исходный код открыт на 100% и доступен на
+ <a> <a>
+ Github
+ </a> </a>
+ Примитивные типы (string, number, и прочие...)
+
+ Теперь вы знаете достаточно <b> <b> TypeScript</b> </b> чтобы начать изучение
+ <b> <b> Angular</b> </b> ! Узнайте больше о TypeScript на
+ <a> <a> TypeScript веб-сайт</a> </a>
+ Дополнительные возможности привязки событий
+ Мы познакомимся с более удобным способом работы с текстовыми полями в разделе "Формы"
+ Настроить маршрутизацию в Angular можно в 3 шага:
+ Конец раздела "Маршрутизация"
+ Вы можете добавить material toolbar в два шага:
+ Конец раздела "angular-cli"
+ Выполните <code> <code> npm install -g @angular/cli</code> </code> , чтобы
+ установить
+ <b> <b> Angular cli</b> </b> на ваш компьютер
+ Чтобы создать новое Angular приложение, выполните:
+ <code> <code> ng new awesome-app</code> </code> , затем <code> <code> cd awesome-app</code> </code>
+ Конец раздела "angular-cli"
+ Для обработки действий пользователя можно использовать привязку событий (event-binding). Для этого мы оборачиваем имя события в скобки и передаем выражение-обработчик:
+ В качестве альтернативы использования скобок для обозначения привязки событий (<b> <b> (event)</b> </b> ), может быть использован префикс "on-", например <b> <b> on-click</b> </b> это то же самое что и <b> <b> (click)</b> </b> .
+ Angular также предоставляет удобный способ обработки горячих клавиш.
+Попробуйте обновить сообщение, нажав Control + Enter в текстовом поле.
+ Чтобы получить доступ к HTML элементу или Angular компоненту из шаблона, можно пометить этот элемент как <b> <b> #name</b> </b> , и он станет доступным как <b> <b> name</b> </b> во всём шаблоне:
+
diff --git a/codelab-master/apps/codelab/src/locale/messages.xmb b/codelab-master/apps/codelab/src/locale/messages.xmb
new file mode 100644
index 000000000..8dda6fbd1
--- /dev/null
+++ b/codelab-master/apps/codelab/src/locale/messages.xmb
@@ -0,0 +1,1256 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+]>
+
+ src/app/components/index/index.component.html:2,4
+ Create your first Angular app
+
+ src/app/components/index/index.component.html:5 src/app/codelabs/angular/templates/templates.component.html:119 Templates
+ src/app/components/index/index.component.html:6,8 src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:40
+ Dependency-Injection
+
+ src/app/components/index/index.component.html:9 Component-Tree
+ src/app/components/index/index.component.html:10 Custom-Events
+ src/app/components/index/index.component.html:11,14
+ Angular is written in TypeScript, a superset of JavaScript. Learn
+ TypeScript.
+
+ src/app/components/index/index.component.html:15,17
+ Learn how to create and bootstrap your first Angular application
+
+ src/app/components/index/index.component.html:18,20
+ Learn how to use Angular templates
+
+ src/app/components/index/index.component.html:21,23
+ Learn how to provide dependencies to your code instead of hard-coding them
+
+ src/app/components/index/index.component.html:27,29
+ Learn how to structure your app with reusable components
+
+ src/app/components/index/index.component.html:30,32
+ Learn to bind to events.
+
+ src/app/components/index/index.component.html:40 Angular Codelab
+ src/app/components/index/index.component.html:41,44
+ Welcome to the interactive Angular Codelab. Here you can learn the basics
+ of <a> <a> Angular</a> </a> !
+
+ src/app/components/index/index.component.html:52 Learn TypeScript
+ src/app/components/index/index.component.html:53 Skip if you're familiar with TypeScript
+ src/app/components/index/index.component.html:59 Learn Angular
+ src/app/components/index/index.component.html:68,70
+ Or click here to see full contents...
+
+ src/app/components/slides/title-slide/title-slide.component.html:6,8
+ Use <b> <b> ←</b> </b> and <b> <b> →</b> </b> on your keyboard to navigate the slides.
+
+ src/app/components/slides/title-slide/title-slide.component.html:11 Prerequisites:
+ src/app/components/slides/closing-slide/codelab-closing-slide.component.html:5,10
+ This codelab is written in Angular and
+ <a> <a> available on Github</a> </a> . Please ⭐ if you enjoyed it.
+
+ ../../libs/slides/src/lib/arrows/slides-arrows.component.html:12 Next slide
+ ../../libs/feedback/src/lib/feedback-widget/feedback-widget.component.html:41 Enter your name
+ ../../libs/feedback/src/lib/feedback-widget/feedback-widget.component.html:52,53 Email is optional and, will not displayed
+
+ ../../libs/feedback/src/lib/feedback-widget/feedback-widget.component.html:57 Describe your issue or share your ideas
+ ../../libs/feedback/src/lib/feedback-widget/feedback-widget.component.html:70,72
+ Send
+
+ ../../libs/feedback/src/lib/feedback-rating/feedback-rating.component.html:2 Perfect
+ ../../libs/feedback/src/lib/feedback-rating/feedback-rating.component.html:3 good
+ ../../libs/feedback/src/lib/feedback-rating/feedback-rating.component.html:4 ok
+ ../../libs/feedback/src/lib/feedback-rating/feedback-rating.component.html:5 Hoped for more
+ ../../libs/feedback/src/lib/feedback-rating/feedback-rating.component.html:12 Rate this lesson ...
+ src/app/components/buttons-nav-bar/menu-github-widget/menu-github-widget.component.html:9 This Codelab is written in Angular!
+ src/app/components/buttons-nav-bar/menu-github-widget/menu-github-widget.component.html:10,15
+ It's 100% open-source and is available on
+ <a> <a>
+ Github
+ </a> </a>
+
+ src/app/components/buttons-nav-bar/menu-github-widget/menu-github-widget.component.html:16 Please ⭐ the repo if you find it useful.
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:2,4
+ Or use shorthand function notation.
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:5,7
+ Error: this is clearly not a puppy
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:8 This is a number
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:9,11
+ Or use shorthand function notation.
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:12,14
+ (Also called arrow function)
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:15,17
+ Actually TypeScript can infer number here;
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:18,20
+ TypeScript can infer it's a string.
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:21,23
+ Can't add number and boolean
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:24 Can't slice a number
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:25 But can slice a string!
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:26 Works!
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:27,29
+ Type[] does the same thing.
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:30 This is a method.
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:31,33
+ That's how russian dogs talk.
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:34,36
+ Now we can instantiate (create) it
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:37 And use its methods
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:38,40
+ Later we'll have code here
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:41,43
+ Let's create more puppies
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:44,46
+ Var is still allowed but not recommended.
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:47,49
+ Let should be used instead of var.
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:53,55
+ Unlike var let is unavailable outside of this if.
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:56,58
+ Const is like let, but if you try to change it, TS will give you an error.
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:59,61
+ okay, definitely a boolean
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:62,64
+ Create a class called 'Codelab'
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:65 src/app/codelabs/angular/create-first-app/create-first-app.component.html:24 Export the class
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:66 Add a constructor
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:70,72
+ Make constructor take a parameter 'guests'
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:73,76
+ Specify the type for the guests parameter (hint: it's an array of a type
+ Guest)
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:77,80
+ Make the parameter public (note that now you can access it anywhere in the
+ class using this.guests)
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:84,86
+ Create new method 'getGuestsComing'
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:88,91
+ "b" in the code below is highlighted, because TypeScript is missing the
+ type. Specify the type for b.
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:95,98
+ With this information TypeScript can highlight the error. Fix it, make 2 + 2
+ = 4 again!
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:103,106
+ Modify getGuestsComing to filter the guests array return an array of guests
+ with the 'coming' property set to true.
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:115 TypeScript
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:117 Angular is written in TypeScript. Learn more about the language basics.
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:119 Basic understanding of JavaScript is required.
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:125 Why TypeScript
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:126,128
+ <b> <b> JavaScript</b> </b> is a great language, but there's space for improvement:
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:130,133
+ JS is not type safe which makes it harder to develop large scale
+ applications
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:134,137
+ New features of the latest versions of JS standards (ES2018, ES2019) are
+ not supported well across all the browsers
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:139,143
+ <b> <b> ES</b> </b> stands for
+ <a> <a><b> <b> ECMAScript</b> </b></a> </a> , which is the name of the JavaScript language specification (standard)
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:147 TypeScript
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:148,151
+ This is why <b> <b> TypeScript</b> </b> has been created. Since TypeScript can be
+ compiled to JavaScript, it can be used in any modern browser.
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:155 TypeScript extends the latest version of JavaScript
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:156,158
+ TypeScript adds new features from the next version of JavaScript
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:159,161
+ On top of it, TypeScript adds an optional type system and decorators
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:168,170
+ Decorator looks like @twitter_handles, we'll learn more about them later
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:180 src/app/codelabs/angular/typescript/typescript/typescript.component.html:200 Type System
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:181,184
+ Below we have an <b> <b> add</b> </b> function, and we're adding 2 and 2. What could
+ go wrong?
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:191,195
+ Turns out it's possible to pass a string to this function and we get
+ <b> <b> 22</b> </b> instead of <b> <b> 4</b> </b> . Let's see how TypeScript can help address
+ this issue on the next slide
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:201,205
+ TypeScript uses "<b> <b> :</b> </b> " to specify the type information (e.g.
+ <b> <b> n: number</b> </b> ). Both <b> <b> a</b> </b> and <b> <b> b</b> </b> should be numbers. We
+ specified the type for <b> <b> a</b> </b> , now it's your turn!
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:211 The code above is editable!
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:216,217 Primitives (strings, numbers, etc...)
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:218 Below are more types we can use
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:232 Interfaces
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:233,236
+ TypeScript Interfaces allow to specify properties and methods for an
+ object.
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:246,248
+ Here, <b> <b> realPuppy</b> </b> is an implementation of the <b> <b> Puppy</b> </b> Interface.
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:252 Arrays
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:253,256
+ Array types are defined as <b> <b> Array{{ '<' }} {{ '<' }} Type{{ '>' }} {{ '>' }}</b> </b> or
+ <b> <b> Type[]</b> </b>
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:263,266
+ Here, each element in the <b> <b> betterCats</b> </b> array is an instance of the
+ <b> <b> Cat</b> </b> Interface.
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:271 Classes
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:272 TypeScript has <b> <b> classes</b> </b> , and Angular uses them heavily.
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:273,276
+ They are similar to classes in other languages, and are used to group
+ methods and properties together
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:286 Constructor
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:287,290
+ There's a special method on the class called <b> <b> constructor</b> </b> . It's run
+ when the class is instantiated and allows the class to take parameters
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:300 Access Modifiers
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:301,305
+ Constructor parameters marked as <b> <b> public</b> </b> (or private, or protected),
+ become class properties accessible as <b> <b> this.ParameterName</b> </b> within the
+ class
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:312,314
+ private or protected properties are not visible outside of the class.
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:318 Export
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:319,323
+ By the way, did you notice the <b> <b> export</b> </b> keyword before class? It is
+ used to share information between files. In the next slide, we'll show you
+ how to import and use this class in a different file
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:338 Import
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:339 Now we can use the <b> <b> Puppy</b> </b> class in the other file
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:347,350
+ <b> <b> import</b> </b> and <b> <b> export</b> </b> keywords are not just for classes. They
+ work with variables, functions and other things!
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:354 Filter (One last thing)
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:355,358
+ "<b> <b> filter</b> </b> " is an Array method that allows you to generate a new array
+ keeping only values that satisfy the condition
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:366 More
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:367 TypeScript supports lots of other cool features such as:
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:374 Enums
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:382 Async / Await
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:390 Accessors (Getters / Setters)
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:398 Destructuring
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:406 Arrow functions
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:409 And more!
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:411,415
+ We won't cover them in detail, check out the
+ <a> <a> TypeScript</a> </a>
+ website!
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:419 src/app/codelabs/angular/create-first-app/create-first-app.component.html:196 src/app/codelabs/angular/create-first-app/create-first-app.component.html:304 src/app/codelabs/angular/create-first-app/create-first-app.component.html:417 src/app/codelabs/angular/templates/templates.component.html:170 src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:278 src/app/codelabs/angular/router/router.component.html:125 src/app/codelabs/angular/material/material.component.html:181 src/app/codelabs/angular/forms/forms.component.html:183 Exercise
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:420 In the next slide we have a TypeScript exercise
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:421,425
+ Your task is to build a TypeScript class called Codelab which will take a
+ list of guests, and will have a method to output only the ones who are
+ coming.
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:426 The result will be as follows:
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:446 src/app/codelabs/angular/templates/templates.component.html:377 src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:303 src/app/codelabs/angular/component-tree/component-tree.component.html:266 Milestone Completed
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:449,453
+ Now you should know enough <b> <b> TypeScript</b> </b> to start learning
+ <b> <b> Angular</b> </b> ! Read more about TypeScript on
+ <a> <a> TypeScript web site</a> </a>
+
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:459 src/app/codelabs/angular/create-first-app/create-first-app.component.html:510 src/app/codelabs/angular/templates/templates.component.html:382 src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:308 src/app/codelabs/angular/router/router.component.html:168 src/app/codelabs/angular/material/material.component.html:227 src/app/codelabs/angular/forms/forms.component.html:224 Next:
+ src/app/codelabs/angular/typescript/typescript/typescript.component.html:460,462
+ Learn how to create your first Angular app!
+
+ src/app/codelabs/angular/typescript/typescript/typescript-svg/typescript-svg.component.html:66,68
+ ES7
+
+ src/app/codelabs/angular/typescript/typescript/typescript-svg/typescript-svg.component.html:78,80
+ Decorators
+
+ src/app/codelabs/angular/typescript/typescript/typescript-svg/typescript-svg.component.html:90,92
+ Types
+
+ src/app/codelabs/angular/typescript/typescript/typescript-svg/typescript-svg.component.html:102,104
+ TypeScript
+
+ src/app/codelabs/angular/typescript/typescript/typescript-svg/typescript-svg.component.html:114,116
+ Classes
+
+ src/app/codelabs/angular/typescript/typescript/typescript-svg/typescript-svg.component.html:126,128
+ Modules
+
+ src/app/codelabs/angular/typescript/typescript/typescript-svg/typescript-svg.component.html:138,140
+ More...
+
+ src/app/components/tests/simple-tests.component.html:27 see only next step
+ src/app/components/tests/simple-tests.component.html:28 see all steps
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:2,4
+ @Component is an Angular decorator
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:5,7
+ No semicolon here (as it attaches itself to the class below
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:8,10
+ The Decorator goes directly above the decorated entity (class in this case)
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:11,13
+ Component name is the class name (AppComponent).
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:14,16
+ Create a class called 'AppComponent'
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:17,19
+ Create a class called 'AppModule'
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:20,22
+ All set! Bootstrap your application
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:25,27
+ Add a Component decorator for the class
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:28,30
+ Add a selector to the component decorator and set it to 'my-app'
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:31,33
+ Add a template that contains: h1 with a text "Hello MewTube!"
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:34,36
+ Add a NgModule decorator for the class
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:37,39
+ Add 'BrowserModule' to the NgModule decorator imports
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:43,45
+ Add 'AppComponent' to the 'declarations' property of the decorator
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:46,48
+ Add 'AppComponent' to the 'bootstrap' property of the decorator
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:56 Create your first Angular app
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:58 You will learn how to create your first Angular component, put it in a module, and bootstrap the app.
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:60 Knowing TypeScript basics would help a lot
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:67 What is Angular?
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:69,75
+ Angular is a <b> <b> development platform</b> </b> for building mobile and desktop
+ applications. Angular lets you <b> <b> extend HTML's syntax</b> </b> to express
+ your application's components clearly and succinctly. Angular's binding
+ and Dependency Injection <b> <b> eliminate much of the code</b> </b> you would
+ otherwise have to write.
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:81 src/app/codelabs/angular/create-first-app/create-first-app.component.html:97 src/app/codelabs/angular/templates/templates.component.html:129 src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:107 src/app/codelabs/angular/router/router.component.html:39 src/app/codelabs/angular/router/router.component.html:61 src/app/codelabs/angular/angular-cli/angular-cli.component.html:16 Intro
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:82 Given an HTML file:
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:88,91
+ Let's create an Angular app which replaces the <b> <b> hello-world</b> </b> HTML
+ element with the app's contents.
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:92 This can be done with 3 simple steps.
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:98 The 3 steps are:
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:100 Create an Angular component
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:101 Create an Angular module
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:102 Bootstrap the module
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:108 src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:224 Step 1
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:109,112
+ Start by creating an Angular <b> <b> Component</b> </b> . Components in Angular are
+ responsible for the visual part of the app
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:118,121
+ An Angular component is just a class. Properties and behavior can be added
+ inside.
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:126 src/app/codelabs/angular/create-first-app/create-first-app.component.html:142 Decorators
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:134 The class is adorned with a <b> <b> @Component</b> </b> decorator
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:135,137
+ Decorators attach <b> <b> Angular</b> </b> specific information to the class.
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:143,146
+ Decorators are a new feature of TypeScript. They attach metadata to a
+ class, function, property or variable
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:153,156
+ TypeScript decorators are inspired by a similar feature in the Python
+ language.
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:161 Selector
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:162,166
+ Selectors define the location of the component. When Angular renders this
+ component, it'll find a <b> <b> hello-world</b> </b> HTML element in the document
+ and render the component inside of it
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:179 Inline Template
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:180 Template defines the HTML code that the component generates
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:188,191
+ If the amount of HTML grows out of hand, it's possible (and recommended)
+ to use a <b> <b> templateUrl</b> </b> instead and provide a path to the HTML file.
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:197,200
+ In the next slide you'll create your first <b> <b> Angular</b> </b> component! We'll
+ do all the wiring for you. The result will look like this:
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:216 Create first Angular component!
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:222 src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:242 Step 2
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:223 Next step is to declare the component in an <b> <b> NgModule</b> </b> .
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:224,227
+ <b> <b> NgModule</b> </b> does not have any visual representation and is used
+ exclusively for grouping Angular building blocks together
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:228,230
+ We will learn more about NgModules in the future milestones
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:235 Module Class
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:236 Like a component, <b> <b> Angular</b> </b> module is just a class
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:249 NgModule Decorator
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:250,253
+ Like a component, <b> <b> Angular</b> </b> module is adorned with a decorator
+ providing metadata
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:266 Browser Module
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:272 Declarations
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:273,276
+ The <b> <b> Declarations array</b> </b> specifies components belonging to the
+ AppModule
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:288 Bootstrap
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:289,292
+ The component passed into the <b> <b> bootstrap</b> </b> array will be created and
+ displayed in your <b> <b> index.html</b> </b> file
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:305,309
+ In the next slide you'll create your first <b> <b> Angular</b> </b> module! We'll
+ use the component from the previous exercises and do all the wiring for
+ you. The result will look like this:
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:324 Create first NgModule.
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:330 Bootstrapping
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:331,333
+ We have everything ready, so now it's time to start (bootstrap) the app!
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:334,337
+ Passing your <b> <b> AppModule</b> </b> to the <b> <b> bootstrapModule</b> </b> method will
+ start up all the components from that module's bootstrap section
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:344,346
+ For most simple apps, you can just copy/paste the code above "as is"
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:350 Bootstrapping 1
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:351 How does bootstrapping work in Angular?
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:353,356
+ 1. Kicks off execution environment. <b> <b> platformBrowserDynamic()</b> </b> tells
+ Angular that we are operating in the browser
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:367,368 src/app/codelabs/angular/create-first-app/create-first-app.component.html:388,389 src/app/codelabs/angular/create-first-app/create-first-app.component.html:411,412 Read more about root module and bootstrapping in Angular
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:373 Bootstrapping 2
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:374,377
+ 2. Angular initializes the component from the <b> <b> bootstrap</b> </b> array in
+ <b> <b> app.module.ts</b> </b> (<b> <b> HelloWorldComponent</b> </b> in this case)
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:394 Bootstrapping 3
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:395,399
+ 3. Angular looks in the document for an element matching the selector
+ defined in <b> <b> HelloWorldComponent</b> </b> (<b> <b> 'hello-world'</b> </b> in our case)
+ and inserts the component inside that element
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:418,420
+ All set! In the next page you'll bootstrap your first <b> <b> Angular</b> </b> app!
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:436,439
+ Now that we've got both NgModule and the component ready, let's
+ bootstrap the app!
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:447 src/app/codelabs/angular/component-tree/component-tree.component.html:201 Review
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:448 Loading order: index -> main -> app.module -> app.component
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:494,497
+ While Angular is loading, the contents of the element will stay the same
+ (<b> <b> Loading...</b> </b> ) in this case
+
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:503 End of Bootstrap Section
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:506 src/app/codelabs/angular/router/router.component.html:159 src/app/codelabs/angular/material/material.component.html:214 src/app/codelabs/angular/forms/forms.component.html:217 Well done! This is the end of the milestone!
+ src/app/codelabs/angular/create-first-app/create-first-app.component.html:511,513
+ Go to the templates Milestone
+
+ src/app/codelabs/angular/create-first-app/mode/mode.component.html:2,5
+ Because we're building a browser web app, we need to pass
+ <b> <b> BrowserModule</b> </b> to the <b> <b> imports</b> </b> array
+
+ src/app/codelabs/angular/create-first-app/mode/mode.component.html:26 With Angular we build mobile apps using NativeScript or Ionic.
+ src/app/codelabs/angular/create-first-app/mode/mode.component.html:42 With Angular you can build VR apps with A-FRAME or WEBGL.
+ src/app/codelabs/angular/create-first-app/mode/mode.component.html:57,70
+ <div> <div>
+ Angular is not just for web apps anymore; you can also use it to create
+ native phone apps and even VR scenes.
+ </div> </div>
+ <div> <div>
+ <a> <a></a> </a>
+ </div> </div>
+
+ src/app/codelabs/angular/templates/templates.component.html:2,4
+ This is valid HTML syntax.
+
+ src/app/codelabs/angular/templates/templates.component.html:5,7
+ It works on attribute syntax.
+
+ src/app/codelabs/angular/templates/templates.component.html:11,13
+ It allows to conditionally bind a class
+
+ src/app/codelabs/angular/templates/templates.component.html:14 Or style properties
+ src/app/codelabs/angular/templates/templates.component.html:15,17
+ And works with custom components!
+
+ src/app/codelabs/angular/templates/templates.component.html:21,24
+ When user clicks the button, it calls the "saveUser" function on the
+ component instance and passes the underlying event.
+
+ src/app/codelabs/angular/templates/templates.component.html:28,32
+ You can also create events for custom components. Here we have a depleted
+ event, and it's going to call the "soundAlarm" function on the component
+ instance when it fires.
+
+ src/app/codelabs/angular/templates/templates.component.html:36,40
+ There are also shortcut event bindings! The submit function on the component
+ instance will be called when the user presses control and enter (this is an
+ Angular feature).
+
+ src/app/codelabs/angular/templates/templates.component.html:41,43
+ userName has a reference to the input element
+
+ src/app/codelabs/angular/templates/templates.component.html:44,46
+ Try changing to true!
+
+ src/app/codelabs/angular/templates/templates.component.html:47,49
+ Need to repeat puppies here
+
+ src/app/codelabs/angular/templates/templates.component.html:50,52
+ app.component.ts: Add a 'videos' property, set the value as empty array.
+
+ src/app/codelabs/angular/templates/templates.component.html:53,56
+ app.component.ts: Inside of the 'search' method assign FAKE_VIDEOS, to the
+ component 'videos' property.
+
+
+ src/app/codelabs/angular/templates/templates.component.html:62,65
+ app.component.ts: Add a 'search' method on the component, that takes a
+ 'searchString' parameter.
+
+ src/app/codelabs/angular/templates/templates.component.html:69,73
+ app.html: Add a click handler to the button, call 'search' method and pass
+ the input value (Actual search functionality will be implemented in the next
+ exercise)
+
+ src/app/codelabs/angular/templates/templates.component.html:74,77
+ app.html: Add a message saying 'no videos' which is displayed only when the
+ videos array is empty
+
+ src/app/codelabs/angular/templates/templates.component.html:82,85
+ #Bonus app.component.ts: Right now it takes pressing a search button to
+ display the videos. Instead display all videos by default.
+
+ src/app/codelabs/angular/templates/templates.component.html:89,93
+ app.component.ts: Inside of the 'search' method filter FAKE_VIDEOS and only
+ return videos with the title containing searchString. (hint: use .includes
+ or .indexOf string methods)
+
+ src/app/codelabs/angular/templates/templates.component.html:94,96
+ app.html: Also display a thumbnail
+
+ src/app/codelabs/angular/templates/templates.component.html:100,103
+ app.html: Iterate over the videos using '*ngFor', and display a title for
+ each
+
+ src/app/codelabs/angular/templates/templates.component.html:105,107
+ app.html: Add a button tag with a text 'search'
+
+ src/app/codelabs/angular/templates/templates.component.html:108,110
+ app.html: Add an input tag with a 'placeholder' attribute set to 'video'
+
+ src/app/codelabs/angular/templates/templates.component.html:121 Learn more about Angular templates!
+ src/app/codelabs/angular/templates/templates.component.html:130,133
+ Angular has a very expressive template system, which takes HTML as a base,
+ and extends it with custom elements
+
+ src/app/codelabs/angular/templates/templates.component.html:142 src/app/codelabs/angular/templates/templates.component.html:158 Interpolation
+ src/app/codelabs/angular/templates/templates.component.html:143,145
+ Double curlies include the appropriate component property value
+
+ src/app/codelabs/angular/templates/templates.component.html:150,153
+ Backticks <b> <b> ` `</b> </b> , are magic quotes that allow multi-line strings and
+ text interpolation.
+
+ src/app/codelabs/angular/templates/templates.component.html:159,162
+ Simple expressions are also allowed, you can run a component method (like
+ fullName() below), or calculate <code> <code> 323213+34234</code> </code>
+
+ src/app/codelabs/angular/templates/templates.component.html:171,174
+ In the next slide you'll edit a component template to create a simple
+ header and search form. The result will look like this:
+
+ src/app/codelabs/angular/templates/templates.component.html:193 Properties
+ src/app/codelabs/angular/templates/templates.component.html:194,197
+ String interpolation <b> <b>{{ curlies }} {{ curlies }}</b> </b> can also be used to pass a value
+ to a child element's attribute
+
+ src/app/codelabs/angular/templates/templates.component.html:206 Property Binding
+ src/app/codelabs/angular/templates/templates.component.html:207,209
+ Better option is to use property binding <b> <b> [attribute] = property</b> </b>
+
+ src/app/codelabs/angular/templates/templates.component.html:214,216
+ You can use arbitrary expressions in the binding.
+
+ src/app/codelabs/angular/templates/templates.component.html:221 Data binding extras
+ src/app/codelabs/angular/templates/templates.component.html:222,224
+ Angular supports more advanced property bindings than just attribute name
+
+ src/app/codelabs/angular/templates/templates.component.html:233 Event binding: (event)
+ src/app/codelabs/angular/templates/templates.component.html:234,238
+ For handling user actions we can use event bindings. To do that we wrap
+ the event name in parentheses, and pass an expression performing required
+ action:
+
+ src/app/codelabs/angular/templates/templates.component.html:245,248
+ While parentheses are used for event binding: <b> <b> (event)</b> </b> , "on-" can
+ also be used, e.g. <b> <b> on-click</b> </b> is the same as <b> <b> (click)</b> </b> .
+
+ src/app/codelabs/angular/templates/templates.component.html:252 src/app/codelabs/angular/templates/templates.component.html:270 Event binding shortcuts
+ src/app/codelabs/angular/templates/templates.component.html:253,257
+ When we need to access an HTML element or an Angular component
+ from the template, we can mark it with <b> <b> #name</b> </b> , and it becomes
+ available as <b> <b> name</b> </b> everywhere in the template:
+
+ src/app/codelabs/angular/templates/templates.component.html:264,266
+ We'll learn a better way to work with inputs in Forms milestone.
+
+ src/app/codelabs/angular/templates/templates.component.html:271,274
+ Angular also provides a shortcut for handling keyboard shortcuts. Try
+ updating the message by pressing Control + Enter in the input.
+
+ src/app/codelabs/angular/templates/templates.component.html:285 Conditional Display (*ngIf)
+ src/app/codelabs/angular/templates/templates.component.html:286,289
+ This conditional expression will add or remove an element from the DOM if
+ it evaluates as a truthy
+
+ src/app/codelabs/angular/templates/templates.component.html:297 src/app/codelabs/angular/component-tree/component-tree.component.html:244 Exercise 2
+ src/app/codelabs/angular/templates/templates.component.html:298,302
+ In the next slide you'll add a click handler to the search button, and
+ display a message for the case where no videos were found. The result will
+ look like this:
+
+ src/app/codelabs/angular/templates/templates.component.html:320 Repeating elements
+ src/app/codelabs/angular/templates/templates.component.html:321,325
+ Let's say you have an array of puppies, and want to display all of them on
+ the page. Angular has a special syntax for that called <b> <b> *ngFor</b> </b> ,
+ let's see how it works on the next slide
+
+ src/app/codelabs/angular/templates/templates.component.html:333 Repeating elements (*ngFor)
+ src/app/codelabs/angular/templates/templates.component.html:334,337
+ Here <b> <b> *ngFor</b> </b> repeats HTML element it's attached to (li in this case)
+ for every single puppy in the puppies array
+
+ src/app/codelabs/angular/templates/templates.component.html:343,346
+ HTML attributes in <b> <b> Angular</b> </b> are case sensitive:
+ <b> <b><s> <s> *ngfor</s> </s></b> </b> won't work, <b> <b> *ngFor</b> </b> will
+
+ src/app/codelabs/angular/templates/templates.component.html:350 Exercise 3
+ src/app/codelabs/angular/templates/templates.component.html:353,356
+ In the next slide you'll finally display the videos! The result will
+ look like this:
+
+ src/app/codelabs/angular/templates/templates.component.html:383,385
+ Learn how to use Angular Dependency Injection
+
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:5,7
+ * TypeScript shorthand makes 'profession' * available to component instance.
+
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:8,10
+ assuming Job has property '.title'
+
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:11,13
+ video.service.ts: Add @Injectable() decorator to the class
+
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:15,17
+ app.module.ts: Add VideoService to the NgModule providers property
+
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:18,20
+ app.component.ts: Get rid of FAKE_VIDEOS
+
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:21,24
+ app.component.ts: Inject 'VideoService' in the component constructor as
+ 'videoService'
+
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:28,31
+ app.component.ts: Update the app component's search method to use
+ videoService's search method
+
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:42 Learn more about Angular's powerful Dependency Injection system
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:50 Example of a dependency
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:51,54
+ We display a list of hard-coded videos in our component, but in the real
+ world we'd load them from the server.
+
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:55,58
+ The code for fetching the data would live in a separate class (service)
+ called VideoService
+
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:59 Therefore our component will depend on the VideoService:
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:109,113
+ As our app grows, number of dependencies will increase. Dependencies, in
+ order, will have their own dependencies. Managing all of them manually
+ becomes increasingly harder.
+
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:114,117
+ To simplify that <b> <b> Angular</b> </b> provides a mechanism called
+ <b> <b> Dependency injection</b> </b>
+
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:124 Comparison
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:133,136
+ Without Dependency Injection, <b> <b> Profession</b> </b> has to be instantiated
+ in the <b> <b> Person</b> </b> class
+
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:145,149
+ With Dependency Injection, <b> <b> Person</b> </b> class just "requires" an
+ instance of <b> <b> Job</b> </b> in the constructor, and Angular takes care of
+ instantiating it
+
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:155 Parameters
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:164,167
+ Without Dependency Injection, you have to figure out all the
+ parameters yourself
+
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:176,178
+ With Dependency Injection, Angular takes care of it
+
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:184 Testing
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:185,188
+ Also Dependency Injection simplifies testing a lot, because you can just
+ pass mock dependencies as constructor parameters
+
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:209 Example
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:210,214
+ Let's say we have an existing <b> <b> UnitConverterService</b> </b> and we want to
+ start using it in <b> <b> UnitConversionComponent</b> </b> . It will take 3 simple
+ steps:
+
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:216 Mark dependency as @Injectable()
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:217 Provide in the module
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:218 Require in the component
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:225,228
+ Mark the class as <b> <b> @Injectable()</b> </b> . This lets Angular know that this
+ class is part of Angular Dependency Injection system
+
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:234,237
+ If a service class is marked as injectable, it can require other services
+ in its constructor.
+
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:243,245
+ Provide the injectable to the <b> <b> providers</b> </b> section of <b> <b> NgModule</b> </b>
+
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:254,257
+ Now, this service becomes available for every <b> <b> Component</b> </b> and other
+ service in this <b> <b> NgModule</b> </b> .
+
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:262 Step 3
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:263 Consume the Injectable in the component
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:271,274
+ Because of the <b> <b> private</b> </b> access modifier the service becomes
+ accessible across the class as <b> <b> this.converter</b> </b> .
+
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:279,282
+ In the next slide you'll use videoService which has even more cats!!! The
+ result will look like this:
+
+ src/app/codelabs/angular/dependency-injection/dependency-injection.component.html:309,311
+ Learn how to combine components together
+
+ src/app/codelabs/angular/component-tree/component-tree.component.html:5,8
+ video/video.component.ts: Add the '@Component' decorator and set its selector
+ property to 'my-video'.
+
+ src/app/codelabs/angular/component-tree/component-tree.component.html:9,11
+ app.module.ts: Add VideoComponent to the AppModule 'declarations'.
+
+ src/app/codelabs/angular/component-tree/component-tree.component.html:16,18
+ video/video.component.ts: Set the templateUrl to load the appropriate html file
+
+ src/app/codelabs/angular/component-tree/component-tree.component.html:22,24
+ video/video.component.ts: Add a video property and decorate it with @Input()
+
+ src/app/codelabs/angular/component-tree/component-tree.component.html:25,27
+ video/video.component.html: Display the video title
+
+ src/app/codelabs/angular/component-tree/component-tree.component.html:28,30
+ video/video.component.html: Display the video thumbnail (src)
+
+ src/app/codelabs/angular/component-tree/component-tree.component.html:31,33
+ video/video.component.html: Display the video description
+
+ src/app/codelabs/angular/component-tree/component-tree.component.html:34,36
+ video/video.component.html: Display the video date
+
+ src/app/codelabs/angular/component-tree/component-tree.component.html:37,39
+ video/video.component.html: Display the number of video views
+
+ src/app/codelabs/angular/component-tree/component-tree.component.html:40,42
+ video/video.component.html: Display the number video likes
+
+ src/app/codelabs/angular/component-tree/component-tree.component.html:43,46
+ app.html: Replace existing title and thumbnail with our shiny new my-video
+ component
+
+ src/app/codelabs/angular/component-tree/component-tree.component.html:50,53
+ app.html: Use the data binding to pass the video object to the component
+ (don't forget the square brackets)
+
+ src/app/codelabs/angular/component-tree/component-tree.component.html:67 src/app/codelabs/angular/component-tree/component-tree.component.html:76 Component Tree
+ src/app/codelabs/angular/component-tree/component-tree.component.html:69 Combine components together
+ src/app/codelabs/angular/component-tree/component-tree.component.html:77,80
+ So far we have only one component, but as your app grows it will form a
+ tree of components
+
+ src/app/codelabs/angular/component-tree/component-tree.component.html:86 Parent and Child
+ src/app/codelabs/angular/component-tree/component-tree.component.html:87,90
+ Any component can render another one by using an HTML element that matches
+ the selector of the other component
+
+ src/app/codelabs/angular/component-tree/component-tree.component.html:121 src/app/codelabs/angular/component-tree/component-tree.component.html:138 Passing Data from Parent to Child
+ src/app/codelabs/angular/component-tree/component-tree.component.html:123,125
+ Parent component passes its data to the child component via properties
+
+ src/app/codelabs/angular/component-tree/component-tree.component.html:126,129
+ Change the <b> <b> size</b> </b> to <b> <b> 100</b> </b> and <b> <b> color</b> </b> to <b> <b> red</b> </b> to
+ recreate the Japanese flag.
+
+ src/app/codelabs/angular/component-tree/component-tree.component.html:140,143
+ The child class must decorate its properties with a special
+ <b> <b> @Input()</b> </b> decorator
+
+ src/app/codelabs/angular/component-tree/component-tree.component.html:148,151
+ This is the first time we're applying decorators to properties (as opposed
+ to classes).
+
+ src/app/codelabs/angular/component-tree/component-tree.component.html:155 Exercise 1
+ src/app/codelabs/angular/component-tree/component-tree.component.html:156,159
+ We already know how to create a component. Let's move all the
+ video-related information into a new component called VideoComponent.
+
+ src/app/codelabs/angular/component-tree/component-tree.component.html:160,162
+ We will bootstrap the component for you; the result will be as follows:
+
+ src/app/codelabs/angular/component-tree/component-tree.component.html:165 Cute kitten
+ src/app/codelabs/angular/component-tree/component-tree.component.html:188 Parent and Child component
+ src/app/codelabs/angular/component-tree/component-tree.component.html:189,192
+ Components won't know about each other unless they're declared in the same
+ module
+
+ src/app/codelabs/angular/component-tree/component-tree.component.html:245 In the next exercise you will use the newly created component
+ src/app/codelabs/angular/component-tree/component-tree.component.html:271 Next:
+ src/app/codelabs/angular/component-tree/component-tree.component.html:272,274
+ Learn how to set up routing in your Angular app
+
+ src/app/codelabs/angular/router/router.component.html:2,5
+ app.module.ts: Using RouterModule.forRoot provide an empty array to the
+ module
+
+ src/app/codelabs/angular/router/router.component.html:6,9
+ app.module.ts: Add a route with an empty (\'\') path to display
+ SearchComponent
+
+ src/app/codelabs/angular/router/router.component.html:10,12
+ app.module.ts: Add a route with path of "upload" to display UploadComponent
+
+ src/app/codelabs/angular/router/router.component.html:13,15
+ app.html: Add router-outlet
+
+
+
+ src/app/codelabs/angular/router/router.component.html:32 Routing
+ src/app/codelabs/angular/router/router.component.html:33 Learn how to add routing to your app
+ src/app/codelabs/angular/router/router.component.html:40,42
+ Router is used to give <b> <b> URLs</b> </b> to different parts of your app.
+
+ src/app/codelabs/angular/router/router.component.html:49 Kittens
+ src/app/codelabs/angular/router/router.component.html:56 Puppies
+ src/app/codelabs/angular/router/router.component.html:62 It takes 3 steps to set up routing in Angular:
+ src/app/codelabs/angular/router/router.component.html:64,67
+ Configure the mapping and specify which component to display for which
+ URL
+
+ src/app/codelabs/angular/router/router.component.html:68 Create the menu
+ src/app/codelabs/angular/router/router.component.html:69 Find a place to display selected component
+ src/app/codelabs/angular/router/router.component.html:74 src/app/codelabs/angular/router/router.component.html:86 Configuration
+ src/app/codelabs/angular/router/router.component.html:75,78
+ Routes are configured by defining an array of mapping between URL path and
+ a component
+
+ src/app/codelabs/angular/router/router.component.html:87 Then we have to pass the config to our module.
+ src/app/codelabs/angular/router/router.component.html:92,95
+ Note that we're using <b> <b> RouterModule.forRoot</b> </b> which creates an Angular
+ Module out of our configuration.
+
+ src/app/codelabs/angular/router/router.component.html:99 router-outlet
+ src/app/codelabs/angular/router/router.component.html:100,103
+ Now we have to find a place where the router would display selected
+ component.
+
+ src/app/codelabs/angular/router/router.component.html:104 It can be marked by placing <b> <b> router-outlet tag</b> </b>
+ src/app/codelabs/angular/router/router.component.html:114 Menu
+ src/app/codelabs/angular/router/router.component.html:115 The last part is creating the menu.
+ src/app/codelabs/angular/router/router.component.html:116 Use <b> <b> routerLink</b> </b> directive to provide the URL
+ src/app/codelabs/angular/router/router.component.html:126,129
+ In the next slide there is an exercise. We're going to add 2 routes:
+ <b> <b> Search</b> </b> and <b> <b> Upload</b> </b> , and a menu for switching between them.
+
+ src/app/codelabs/angular/router/router.component.html:135,138
+ Note: We have already created empty Upload component and SearchComponent
+ containing search logic.
+
+ src/app/codelabs/angular/router/router.component.html:155,156 End of The Routing Milestone
+
+ src/app/codelabs/angular/router/router.component.html:160,164
+ Check out
+ <a> <a> Angular Router Guide</a> </a> for
+ more fun and advanced techniques.
+
+ src/app/codelabs/angular/router/router.component.html:169,171
+ Learn how to create beautiful UIs with Angular Material
+
+ src/app/codelabs/angular/material/material.component.html:3,5
+ app.module.ts: Add MatCardModule and MatToolbarModule, to the imports.
+
+ src/app/codelabs/angular/material/material.component.html:6,8
+ app.html: Add material toolbar containing the title
+
+ src/app/codelabs/angular/material/material.component.html:9,11
+ video/video.component.html: Use material card to display the data
+
+ src/app/codelabs/angular/material/material.component.html:12,15
+ video/video.component.html: Add mat-card-title (inside of the mat-card) to display
+ video title
+
+ src/app/codelabs/angular/material/material.component.html:16,19
+ video/video.component.html: Add mat-card-subtitle (inside of the mat-card) to
+ display video description
+
+ src/app/codelabs/angular/material/material.component.html:20,23
+ video/video.component.html: Mark img with mat-card-image attribute (inside of the
+ mat-card) so that it takes full card size
+
+ src/app/codelabs/angular/material/material.component.html:24,27
+ video/video.component.html: move date/views/likes info inside of mat-card-content
+ (inside of the mat-card)
+
+ src/app/codelabs/angular/material/material.component.html:39 Material design
+ src/app/codelabs/angular/material/material.component.html:40 Learn how to use Angular Material
+ src/app/codelabs/angular/material/material.component.html:45,49
+ Now let's use
+ <a> <a> Angular Material</a> </a>
+ to make our app look beautiful ✨✨
+
+ src/app/codelabs/angular/material/material.component.html:50,54
+ Angular Material provides you with a set of
+ <a> <a> Material Design</a> </a>
+ components for Angular:
+
+ src/app/codelabs/angular/material/material.component.html:58 Fast and Consistent
+ src/app/codelabs/angular/material/material.component.html:59 Versatile
+ src/app/codelabs/angular/material/material.component.html:60 Accessible
+ src/app/codelabs/angular/material/material.component.html:61 Optimized for Angular
+ src/app/codelabs/angular/material/material.component.html:62 Look great on mobile
+ src/app/codelabs/angular/material/material.component.html:65,72
+ See the list of components
+ <a> <a> here</a> </a>
+
+ src/app/codelabs/angular/material/material.component.html:76 MatToolBar
+ src/app/codelabs/angular/material/material.component.html:77 Adding a toolbar takes 2 steps:
+ src/app/codelabs/angular/material/material.component.html:79 Add <b> <b> MatToolbarModule</b> </b> to the imports
+ src/app/codelabs/angular/material/material.component.html:80 Use the component in the template
+ src/app/codelabs/angular/material/material.component.html:87,91
+ Note that Angular animations come in a separate module. We're including
+ <b> <b> NoopAnimationsModule</b> </b> here, but could have used
+ <b> <b> BrowserAnimationsModule</b> </b> instead, to have full-fledged animations.
+
+ src/app/codelabs/angular/material/material.component.html:95 Card
+ src/app/codelabs/angular/material/material.component.html:96 Now let's add material card.
+ src/app/codelabs/angular/material/material.component.html:104 Card Header
+ src/app/codelabs/angular/material/material.component.html:105 Header and an image.
+ src/app/codelabs/angular/material/material.component.html:113 Buttons
+ src/app/codelabs/angular/material/material.component.html:114 Adding some actions....
+ src/app/codelabs/angular/material/material.component.html:119,122
+ Note that for the button we're using <b> <b> mat-button</b> </b> attribute instead
+ of a separate tag.
+
+ src/app/codelabs/angular/material/material.component.html:126 Themes
+ src/app/codelabs/angular/material/material.component.html:127,130
+ All Angular Material components allow to apply themes. Try different
+ themes by clicking the buttons below:
+
+ src/app/codelabs/angular/material/material.component.html:138,140
+ Indigo
+
+ src/app/codelabs/angular/material/material.component.html:147,149
+ Deep purple
+
+ src/app/codelabs/angular/material/material.component.html:156,158
+ Pink
+
+ src/app/codelabs/angular/material/material.component.html:165,167
+ Purple
+
+ src/app/codelabs/angular/material/material.component.html:174,177
+ Read more on theming Angular Material
+ <a> <a> in this guide</a> </a>
+
+ src/app/codelabs/angular/material/material.component.html:182,185
+ In the next slide there is an exercise. We're going to materialize our
+ application
+
+ src/app/codelabs/angular/material/material.component.html:191,193
+ Note: the final app won't be super beautiful, we're still working on that.
+
+ src/app/codelabs/angular/material/material.component.html:210,211 End of The Material Milestone
+
+ src/app/codelabs/angular/material/material.component.html:215,223
+ Check out Angular Material
+ <a> <a> "Getting Started"</a> </a>
+ Guide
+
+ src/app/codelabs/angular/material/material.component.html:228,230
+ Learn how to create simple forms with Angular
+
+ src/app/codelabs/angular/forms/forms.component.html:3,5
+ app.module.ts: Add FormsModule and MatInputModule, to the imports.
+
+ src/app/codelabs/angular/forms/forms.component.html:6,9
+ upload/upload.component.html: Add "title" input bound to the title property of the
+ component
+
+ src/app/codelabs/angular/forms/forms.component.html:10,13
+ upload/upload.component.html: Add "description" textarea bound to the description
+ property of the component
+
+ src/app/codelabs/angular/forms/forms.component.html:24 Forms
+ src/app/codelabs/angular/forms/forms.component.html:25 Adding basic forms into your app
+ src/app/codelabs/angular/forms/forms.component.html:30 src/app/codelabs/angular/forms/forms.component.html:41 Simple Form
+ src/app/codelabs/angular/forms/forms.component.html:31,34
+ We have this simple form, let's find out how to map input values with the
+ ones from our Angular component!
+
+ src/app/codelabs/angular/forms/forms.component.html:42 First we have to add <b> <b> FormsModule</b> </b> to our NgModule.
+ src/app/codelabs/angular/forms/forms.component.html:51 NgModel
+ src/app/codelabs/angular/forms/forms.component.html:52,55
+ Now let's use ngModel to bind the inputs to the appropriate fields on the
+ component.
+
+ src/app/codelabs/angular/forms/forms.component.html:56 Try changing the inputs and see the values updated.
+ src/app/codelabs/angular/forms/forms.component.html:60,63
+ [(NgModel)] - <b> <b> Banana in the box</b> </b> is a simple mnemonic for the braces
+ order.
+
+ src/app/codelabs/angular/forms/forms.component.html:67 Validation
+ src/app/codelabs/angular/forms/forms.component.html:68,71
+ It's really easy to add validation for your inputs using predefined
+ Angular directives.
+
+ src/app/codelabs/angular/forms/forms.component.html:72 Let's make username <b> <b> required</b> </b>
+ src/app/codelabs/angular/forms/forms.component.html:76,79
+ If you clear the input it'll be marked with an error, however no error
+ will be displayed. We'll learn how to display it in the next slide
+
+ src/app/codelabs/angular/forms/forms.component.html:83 Displaying Validation Errors
+ src/app/codelabs/angular/forms/forms.component.html:84 Now we let's display validation error. It takes 2 steps:
+ src/app/codelabs/angular/forms/forms.component.html:86,88
+ Get ahold of the input ngModel using <b> <b> #name="ngModel"</b> </b> binding
+
+ src/app/codelabs/angular/forms/forms.component.html:89 Use <b> <b> usernameModel</b> </b> 's <b> <b> errors</b> </b> property.
+ src/app/codelabs/angular/forms/forms.component.html:94,96
+ Try clearing the username input and see the error displayed.
+
+ src/app/codelabs/angular/forms/forms.component.html:99 Validators
+ src/app/codelabs/angular/forms/forms.component.html:100,106
+ Here's the list of
+ <a> <a> built-in validators</a> </a>
+ that Angular provides out of the box
+
+ src/app/codelabs/angular/forms/forms.component.html:108 min
+ src/app/codelabs/angular/forms/forms.component.html:109 max
+ src/app/codelabs/angular/forms/forms.component.html:110 required
+ src/app/codelabs/angular/forms/forms.component.html:111 requiredTrue
+ src/app/codelabs/angular/forms/forms.component.html:112 email
+ src/app/codelabs/angular/forms/forms.component.html:113 minLength
+ src/app/codelabs/angular/forms/forms.component.html:114 maxLength
+ src/app/codelabs/angular/forms/forms.component.html:115 pattern
+ src/app/codelabs/angular/forms/forms.component.html:117,123
+ It's also possible to create custom validators, but it's out of scope for
+ this milestone, you can read more:
+ <a> <a> here</a> </a>
+
+ src/app/codelabs/angular/forms/forms.component.html:127 Error Always Displayed
+ src/app/codelabs/angular/forms/forms.component.html:128,131
+ There's one small issue though, if we don't have initial values, the error
+ is displayed right away.
+
+ src/app/codelabs/angular/forms/forms.component.html:139 Touched & Dirty
+ src/app/codelabs/angular/forms/forms.component.html:140,143
+ Luckily we can check if the user interacted with an input using
+ <b> <b> touched</b> </b> property.
+
+ src/app/codelabs/angular/forms/forms.component.html:145,147
+ <b> <b> dirty</b> </b> is true if the user changed the value of the input.
+
+ src/app/codelabs/angular/forms/forms.component.html:148,151
+ <b> <b> touched</b> </b> is true if the user focused on the input, and then blured
+ without changing the value.
+
+ src/app/codelabs/angular/forms/forms.component.html:156,159
+ Try focusing/bluring the <b> <b> username</b> </b> field, or adding some value and
+ then removing to see the error.
+
+ src/app/codelabs/angular/forms/forms.component.html:163 Material Inputs (Bonus!)
+ src/app/codelabs/angular/forms/forms.component.html:164,167
+ Now let's make our forms beautiful using Material Design inputs! Main
+ building blocks are:
+
+ src/app/codelabs/angular/forms/forms.component.html:169 <b> <b> mat-form-field</b> </b> - Wraps the input
+ src/app/codelabs/angular/forms/forms.component.html:170 <b> <b> matInput</b> </b> - has to be put on the input
+ src/app/codelabs/angular/forms/forms.component.html:171 <b> <b> mat-error</b> </b> - Smarter error wrapper
+ src/app/codelabs/angular/forms/forms.component.html:177,179
+ Note that we don't need to <b> <b> #name</b> </b> the input anymore.
+
+ src/app/codelabs/angular/forms/forms.component.html:184,187
+ In the next slide there is an exercise. We're going to add a form to the
+ upload page.
+
+ src/app/codelabs/angular/forms/forms.component.html:195,198
+ Note: you'd have to manually click on the "upload link" to see the result,
+ we're working on the fix.
+
+ src/app/codelabs/angular/forms/forms.component.html:214 End of The Forms Milestone
+ src/app/codelabs/angular/forms/forms.component.html:218,222
+ There are more than one way to handle forms in Angular. While
+ <b> <b> Advanced forms</b> </b> milestone is in works, check out
+ <a> <a> Angular docs</a> </a>
+
+ src/app/codelabs/angular/forms/forms.component.html:225,228
+ Learn how to start working on your angular app in the Angular-cli
+ Milestone
+
+ src/app/codelabs/angular/angular-cli/angular-cli.component.html:9 Angular-cli
+ src/app/codelabs/angular/angular-cli/angular-cli.component.html:11 Learn how to quickly start working on your Angular app
+ src/app/codelabs/angular/angular-cli/angular-cli.component.html:17,20
+ Angular CLI is a command line tool that can be used to quickly get up to
+ speed with running your Angular app.
+
+ src/app/codelabs/angular/angular-cli/angular-cli.component.html:24,26
+ Hi, I'm <b> <b> angular-cli</b> </b> , I'm a command line tool!
+
+ src/app/codelabs/angular/angular-cli/angular-cli.component.html:27 It may sound scary, but I'm really easy to use!
+ src/app/codelabs/angular/angular-cli/angular-cli.component.html:33 node
+ src/app/codelabs/angular/angular-cli/angular-cli.component.html:34 Before you start, make sure you have node.js on your machine.
+ src/app/codelabs/angular/angular-cli/angular-cli.component.html:35 Open terminal and type in: <code> <code> node -v</code> </code>
+ src/app/codelabs/angular/angular-cli/angular-cli.component.html:37,40
+ If there is an error, follow the
+ <a> <a> NodeJS setup instructions</a> </a>
+
+ src/app/codelabs/angular/angular-cli/angular-cli.component.html:41,43
+ If the output is a number, you're good, move to the next slide.
+
+ src/app/codelabs/angular/angular-cli/angular-cli.component.html:51 installing
+ src/app/codelabs/angular/angular-cli/angular-cli.component.html:52,55
+ Run <code> <code> npm install -g @angular/cli</code> </code> to install
+ <b> <b> Angular cli</b> </b> on your machine
+
+ src/app/codelabs/angular/angular-cli/angular-cli.component.html:81 Creating new Angular app
+ src/app/codelabs/angular/angular-cli/angular-cli.component.html:82,85
+ To create a new Angular app run:
+ <code> <code> ng new awesome-app</code> </code> , then <code> <code> cd awesome-app</code> </code>
+
+ src/app/codelabs/angular/angular-cli/angular-cli.component.html:107 Starting the app
+ src/app/codelabs/angular/angular-cli/angular-cli.component.html:108,110
+ Once you're in the app folder, start the app with <code> <code> ng serve</code> </code>
+
+ src/app/codelabs/angular/angular-cli/angular-cli.component.html:132,136
+ Once the app is started just open
+ <a> <a> http://localhost:4200/</a> </a> in your
+ browser
+
+ src/app/codelabs/angular/angular-cli/angular-cli.component.html:140 Generating components
+ src/app/codelabs/angular/angular-cli/angular-cli.component.html:141,144
+ You can easily generate new components
+ <code> <code> ng generate component my-component</code> </code>
+
+ src/app/codelabs/angular/angular-cli/angular-cli.component.html:157 You can also generate modules, services and pipes
+ src/app/codelabs/angular/angular-cli/angular-cli.component.html:158,160
+ You can use a shorter version: <code> <code> ng g c my-component</code> </code>
+
+ src/app/codelabs/angular/angular-cli/angular-cli.component.html:167,168 End of The Angular-cli Milestone
+
+ src/app/codelabs/angular/angular-cli/angular-cli.component.html:171,175
+ This is <b> <b> the end</b> </b> of the codelab, but it's just the beginning of
+ your Angular journey. Below are some links that can help you continue
+ learning.
+
+ src/app/codelabs/angular/angular-cli/angular-cli.component.html:179 Find features, docs and events listed here
+ src/app/codelabs/angular/angular-cli/angular-cli.component.html:183,187
+ makes it easy to create an application that already works, right
+ out of the box and generate new components! It also takes care of
+ the build system for you
+
+
diff --git a/codelab-master/apps/codelab/src/main.ts b/codelab-master/apps/codelab/src/main.ts
new file mode 100644
index 000000000..18cbbe5b4
--- /dev/null
+++ b/codelab-master/apps/codelab/src/main.ts
@@ -0,0 +1,10 @@
+import { enableProdMode } from '@angular/core';
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+import { environment } from './environments/environment';
+import { AppModule } from './app/app.module';
+
+if (environment.production) {
+ enableProdMode();
+}
+
+platformBrowserDynamic().bootstrapModule(AppModule);
diff --git a/codelab-master/apps/codelab/src/manifest.webmanifest b/codelab-master/apps/codelab/src/manifest.webmanifest
new file mode 100644
index 000000000..6c62bb9de
--- /dev/null
+++ b/codelab-master/apps/codelab/src/manifest.webmanifest
@@ -0,0 +1,51 @@
+{
+ "name": "Codelab",
+ "short_name": "Codelab",
+ "theme_color": "#1976d2",
+ "background_color": "#fafafa",
+ "display": "standalone",
+ "scope": "/",
+ "start_url": "/",
+ "icons": [
+ {
+ "src": "assets/icons/icon-72x72.png",
+ "sizes": "72x72",
+ "type": "image/png"
+ },
+ {
+ "src": "assets/icons/icon-96x96.png",
+ "sizes": "96x96",
+ "type": "image/png"
+ },
+ {
+ "src": "assets/icons/icon-128x128.png",
+ "sizes": "128x128",
+ "type": "image/png"
+ },
+ {
+ "src": "assets/icons/icon-144x144.png",
+ "sizes": "144x144",
+ "type": "image/png"
+ },
+ {
+ "src": "assets/icons/icon-152x152.png",
+ "sizes": "152x152",
+ "type": "image/png"
+ },
+ {
+ "src": "assets/icons/icon-192x192.png",
+ "sizes": "192x192",
+ "type": "image/png"
+ },
+ {
+ "src": "assets/icons/icon-384x384.png",
+ "sizes": "384x384",
+ "type": "image/png"
+ },
+ {
+ "src": "assets/icons/icon-512x512.png",
+ "sizes": "512x512",
+ "type": "image/png"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/codelab-master/apps/codelab/src/polyfills.ts b/codelab-master/apps/codelab/src/polyfills.ts
new file mode 100644
index 000000000..dc29929a4
--- /dev/null
+++ b/codelab-master/apps/codelab/src/polyfills.ts
@@ -0,0 +1,18 @@
+import 'fullscreen-api-polyfill';
+import 'zone.js/dist/zone'; // Included with Angular CLI.
+import '@angular/localize/init';
+
+// Needed for babel :(
+(window as any).Buffer = {};
+
+(window as any).process = {
+ env: { DEBUG: undefined },
+ argv: {
+ indexOf() {
+ return 0;
+ }
+ },
+ getuid() {
+ return 0;
+ }
+};
diff --git a/libs/utils/src/lib/sync/components/registration/registration.component.css b/codelab-master/apps/codelab/src/service-worker.js
similarity index 100%
rename from libs/utils/src/lib/sync/components/registration/registration.component.css
rename to codelab-master/apps/codelab/src/service-worker.js
diff --git a/codelab-master/apps/codelab/src/styles.scss b/codelab-master/apps/codelab/src/styles.scss
new file mode 100644
index 000000000..e5588700a
--- /dev/null
+++ b/codelab-master/apps/codelab/src/styles.scss
@@ -0,0 +1,291 @@
+@import '~@angular/material/prebuilt-themes/indigo-pink.css';
+
+body,
+html {
+ margin: 0;
+ padding: 0;
+ height: 100%;
+}
+
+.presentation.size-600 li {
+ font-size: 12px;
+ margin-bottom: 5px;
+}
+
+.space-left {
+ margin-left: 20px;
+}
+
+[row] {
+ flex-direction: row;
+ display: flex;
+}
+
+/* GRID TO USE */
+.col-1 {
+ width: 8.33%;
+}
+
+.col-2 {
+ width: 16.66%;
+}
+
+.col-3 {
+ width: 25%;
+}
+
+.col-4 {
+ width: 33.33%;
+}
+
+.col-5 {
+ width: 41.66%;
+}
+
+.col-6 {
+ width: 50%;
+}
+
+.col-7 {
+ width: 58.33%;
+}
+
+.col-8 {
+ width: 66.66%;
+}
+
+.col-9 {
+ width: 75%;
+}
+
+.col-10 {
+ width: 83.33%;
+}
+
+.col-11 {
+ width: 91.66%;
+}
+
+.col-12 {
+ width: 100%;
+}
+
+.presentation.presentation.presentation [no-padding] .slide {
+ padding: 0;
+}
+
+.browser-frame,
+.runner,
+.browser-frame,
+.frame {
+}
+
+.slide [large-font] {
+ font-size: 30px;
+}
+
+.slide [p20] {
+ padding-top: 20px;
+}
+
+.slide [m20] {
+ margin-top: 20px;
+}
+
+.slide [m40] {
+ margin-top: 40px;
+}
+
+.slide [column-5] {
+ width: 50%;
+ padding: 0 1vw;
+}
+
+.slide [column-4] {
+ width: 40%;
+}
+
+.slide [column-2] {
+ width: 20%;
+}
+
+.slide [column-1] {
+ width: 10%;
+}
+
+.slide [flex] {
+ display: flex;
+}
+
+.slide .browser-frame h1 {
+ font-size: 60px;
+}
+
+.slide .browser-frame h2 {
+ font-size: 20px;
+}
+
+/* TODO(kirjs): Support themes */
+.slide h1 {
+ font-size: 20px;
+}
+
+.centered-vertically {
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+ justify-content: center;
+}
+
+.popup-message {
+ padding: 5px 5px 0 5px;
+ background: black;
+ color: white;
+ font-size: 20px;
+}
+
+.popup-arrow {
+ width: 0;
+ height: 0;
+ border-left: 0 solid transparent;
+ border-right: 20px solid transparent;
+ border-top: 8px solid black;
+}
+
+.monaco-editor.vs
+ .grayed-out-code.grayed-out-code.grayed-out-code.grayed-out-code {
+}
+
+.monaco-editor.vs .loc.loc.loc.loc {
+ background: yellow;
+}
+
+.monaco-editor.vs
+ .highlighted-code.highlighted-code.highlighted-code.highlighted-code {
+ background: yellow;
+}
+
+p {
+ margin: 0;
+ margin-bottom: 10px;
+ padding: 0;
+}
+
+.info:before {
+ content: 'ⓘ';
+ margin-right: 10px;
+}
+
+a {
+ color: #a03800;
+ font-weight: 400;
+}
+
+.info {
+ font-weight: 300;
+ margin-top: 20px;
+ background: #d3fffd;
+ padding: 12px;
+ font-size: 30px;
+}
+
+/* BUTTONS BAR CONTAINER */
+.btn-bar {
+ z-index: 2;
+ position: fixed;
+ bottom: 1%;
+ right: 4%;
+ display: flex;
+ flex-direction: row;
+}
+
+.exercise {
+ font-size: 30px;
+ padding: 10px;
+ margin-top: 20px;
+ font-weight: 300;
+ border: 1px #ddd solid;
+}
+
+.exercise:before {
+ content: '💡';
+ display: inline-block;
+ width: 20px;
+ height: 20px;
+ margin-right: 10px;
+}
+
+.exercise.solved {
+ color: #90dd59;
+}
+
+.exercise.solved:before {
+ content: '✔';
+ background: none;
+}
+
+/* context: https://github.com/Microsoft/monaco-editor/issues/113 */
+.monaco-editor .inputarea {
+ position: fixed !important;
+ top: 0 !important;
+ left: 0 !important;
+}
+
+.preload {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ /*change these sizes to fit into your project*/
+ width: 100px;
+ height: 100px;
+}
+
+.preload div {
+ border: 0;
+ margin: 0;
+ width: 40%;
+ height: 40%;
+ position: absolute;
+ border-radius: 50%;
+ animation: spin 2s ease infinite;
+}
+
+.preload :first-child {
+ background: #19a68c;
+ animation-delay: -1.5s;
+}
+
+.preload :nth-child(2) {
+ background: #f63d3a;
+ animation-delay: -1s;
+}
+
+.preload :nth-child(3) {
+ background: #fda543;
+ animation-delay: -0.5s;
+}
+
+.preload :last-child {
+ background: #193b48;
+}
+
+@keyframes spin {
+ 0%,
+ 100% {
+ transform: translate(0);
+ }
+ 25% {
+ transform: translate(160%);
+ }
+ 50% {
+ transform: translate(160%, 160%);
+ }
+ 75% {
+ transform: translate(0, 160%);
+ }
+}
+
+.mt-60 {
+ margin-top: 60px;
+}
diff --git a/codelab-master/apps/codelab/src/test.ts b/codelab-master/apps/codelab/src/test.ts
new file mode 100644
index 000000000..48bde5fa7
--- /dev/null
+++ b/codelab-master/apps/codelab/src/test.ts
@@ -0,0 +1,32 @@
+// This file is required by karma.conf.js and loads recursively all the .spec and framework files
+
+import 'zone.js/dist/long-stack-trace-zone';
+import 'zone.js/dist/proxy.js';
+import 'zone.js/dist/sync-test';
+import 'zone.js/dist/jasmine-patch';
+import 'zone.js/dist/async-test';
+import 'zone.js/dist/fake-async-test';
+import { getTestBed } from '@angular/core/testing';
+import {
+ BrowserDynamicTestingModule,
+ platformBrowserDynamicTesting
+} from '@angular/platform-browser-dynamic/testing';
+
+// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
+declare var __karma__: any;
+declare var require: any;
+
+// Prevent Karma from running prematurely.
+__karma__.loaded = function() {};
+
+// First, initialize the Angular testing environment.
+getTestBed().initTestEnvironment(
+ BrowserDynamicTestingModule,
+ platformBrowserDynamicTesting()
+);
+// Then we find all the tests.
+const context = require.context('./', true, /\.spec\.ts$/);
+// And load the modules.
+context.keys().map(context);
+// Finally, start Karma to run the tests.
+__karma__.start();
diff --git a/codelab-master/apps/codelab/src/typings.d.ts b/codelab-master/apps/codelab/src/typings.d.ts
new file mode 100644
index 000000000..dfad1e84b
--- /dev/null
+++ b/codelab-master/apps/codelab/src/typings.d.ts
@@ -0,0 +1,6 @@
+/* SystemJS module definition */
+declare var module: NodeModule;
+declare const chai;
+interface NodeModule {
+ id: string;
+}
diff --git a/codelab-master/apps/codelab/tsconfig.app.json b/codelab-master/apps/codelab/tsconfig.app.json
new file mode 100644
index 000000000..65ae73b58
--- /dev/null
+++ b/codelab-master/apps/codelab/tsconfig.app.json
@@ -0,0 +1,9 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../dist/out-tsc",
+ "types": []
+ },
+ "files": ["./src/main.ts", "./src/polyfills.ts"],
+ "exclude": ["test.ts", "**/*.spec.ts"]
+}
diff --git a/codelab-master/apps/codelab/tsconfig.json b/codelab-master/apps/codelab/tsconfig.json
new file mode 100644
index 000000000..480acf7bd
--- /dev/null
+++ b/codelab-master/apps/codelab/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "types": ["jasmine", "node"]
+ },
+ "angularCompilerOptions": {
+ "enableIvy": true
+ }
+}
diff --git a/codelab-master/apps/codelab/tsconfig.spec.json b/codelab-master/apps/codelab/tsconfig.spec.json
new file mode 100644
index 000000000..43c4640b7
--- /dev/null
+++ b/codelab-master/apps/codelab/tsconfig.spec.json
@@ -0,0 +1,9 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../dist/out-tsc",
+ "types": ["jasmine", "node"]
+ },
+ "files": ["src/test.ts", "src/polyfills.ts"],
+ "include": ["**/*.spec.ts", "**/*.d.ts"]
+}
diff --git a/codelab-master/apps/codelab/tslint.json b/codelab-master/apps/codelab/tslint.json
new file mode 100644
index 000000000..8f03598c8
--- /dev/null
+++ b/codelab-master/apps/codelab/tslint.json
@@ -0,0 +1,7 @@
+{
+ "extends": "../../tslint.json",
+ "linterOptions": {
+ "exclude": ["src/**/*.json"]
+ },
+ "rules": {}
+}
diff --git a/codelab-master/apps/kirjs/browserslist b/codelab-master/apps/kirjs/browserslist
new file mode 100644
index 000000000..37371cb04
--- /dev/null
+++ b/codelab-master/apps/kirjs/browserslist
@@ -0,0 +1,11 @@
+# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers
+# For additional information regarding the format and rule options, please see:
+# https://github.com/browserslist/browserslist#queries
+#
+# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed
+
+> 0.5%
+last 2 versions
+Firefox ESR
+not dead
+not IE 9-11
\ No newline at end of file
diff --git a/codelab-master/apps/kirjs/karma.conf.js b/codelab-master/apps/kirjs/karma.conf.js
new file mode 100644
index 000000000..5e0547450
--- /dev/null
+++ b/codelab-master/apps/kirjs/karma.conf.js
@@ -0,0 +1,16 @@
+// Karma configuration file, see link for more information
+// https://karma-runner.github.io/1.0/config/configuration-file.html
+
+const { join } = require('path');
+const getBaseKarmaConfig = require('../../karma.conf');
+
+module.exports = function(config) {
+ const baseConfig = getBaseKarmaConfig();
+ config.set({
+ ...baseConfig,
+ coverageIstanbulReporter: {
+ ...baseConfig.coverageIstanbulReporter,
+ dir: join(__dirname, '../../coverage/apps/kirjs')
+ }
+ });
+};
diff --git a/codelab-master/apps/kirjs/src/app/app.component.css b/codelab-master/apps/kirjs/src/app/app.component.css
new file mode 100644
index 000000000..59d511d8f
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/app.component.css
@@ -0,0 +1,22 @@
+.fire:hover {
+ opacity: 1;
+ cursor: pointer;
+ background: #fff;
+ box-shadow: 0 0 2px #333333;
+}
+
+.fire {
+ opacity: 0.8;
+ position: fixed;
+ right: 10px;
+ top: 10px;
+ background: #ddd;
+ border-radius: 50%;
+ width: 20px;
+ height: 20px;
+ font-size: 12px;
+ text-decoration: none;
+ text-align: center;
+ text-indent: 3px;
+ z-index: 100;
+}
diff --git a/codelab-master/apps/kirjs/src/app/app.component.html b/codelab-master/apps/kirjs/src/app/app.component.html
new file mode 100644
index 000000000..78e4b8e99
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/app.component.html
@@ -0,0 +1,2 @@
+
+
diff --git a/codelab-master/apps/kirjs/src/app/app.component.spec.ts b/codelab-master/apps/kirjs/src/app/app.component.spec.ts
new file mode 100644
index 000000000..ab7de707b
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/app.component.spec.ts
@@ -0,0 +1,27 @@
+import { TestBed, async } from '@angular/core/testing';
+import { AppComponent } from './app.component';
+describe('AppComponent', () => {
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [AppComponent]
+ }).compileComponents();
+ }));
+ it('should create the app', async(() => {
+ const fixture = TestBed.createComponent(AppComponent);
+ const app = fixture.debugElement.componentInstance;
+ expect(app).toBeTruthy();
+ }));
+ it(`should have as title 'kirjs'`, async(() => {
+ const fixture = TestBed.createComponent(AppComponent);
+ const app = fixture.debugElement.componentInstance;
+ expect(app.title).toEqual('kirjs');
+ }));
+ it('should render title in a h1 tag', async(() => {
+ const fixture = TestBed.createComponent(AppComponent);
+ fixture.detectChanges();
+ const compiled = fixture.debugElement.nativeElement;
+ expect(compiled.querySelector('h1').textContent).toContain(
+ 'Welcome to kirjs!'
+ );
+ }));
+});
diff --git a/codelab-master/apps/kirjs/src/app/app.component.ts b/codelab-master/apps/kirjs/src/app/app.component.ts
new file mode 100644
index 000000000..1f6ee4783
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/app.component.ts
@@ -0,0 +1,31 @@
+import { Component, HostListener } from '@angular/core';
+import { Router } from '@angular/router';
+
+@Component({
+ selector: 'kirjs-main',
+ templateUrl: './app.component.html',
+ styleUrls: ['./app.component.css']
+})
+export class AppComponent {
+ title = 'kirjs';
+
+ @HostListener(`window:keydown.meta.'`)
+ HandleLinker() {
+ const key = 'linker';
+ if (localStorage.getItem(key)) {
+ localStorage.removeItem(key);
+ alert(`Linker removed!`);
+ } else {
+ const path = window.location.pathname;
+ localStorage.setItem(key, path);
+ alert(`Linker stored ${path}!`);
+ }
+ }
+
+ constructor(private router: Router) {
+ const path: string = localStorage.getItem('linker');
+ if (path && path !== window.location.pathname) {
+ router.navigate([path]);
+ }
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/cv/resume.css b/codelab-master/apps/kirjs/src/app/cv/resume.css
new file mode 100644
index 000000000..f7e26a996
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/cv/resume.css
@@ -0,0 +1,115 @@
+ul {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+ul li {
+ margin: 0;
+ padding: 0;
+}
+
+/*.......| Resume |.......................*/
+#resume {
+ max-width: 800px;
+ margin: 0 auto;
+ font-family: verdana, sans-serif;
+}
+#resume #header {
+ width: 250px;
+ float: left;
+}
+#resume #header .title {
+ width: 90px;
+}
+#resume #info {
+ margin-left: 300px;
+}
+#resume h1 {
+ font-size: 1.4em;
+ text-transform: uppercase;
+ margin-top: 30px;
+ margin-bottom: 20px;
+}
+#resume h2 {
+ color: #900;
+ font-size: 1.4em;
+ font-weight: 400;
+ padding-top: 0px;
+ padding-bottom: 10px;
+ margin-bottom: 0;
+}
+#resume h3 {
+ margin: 0;
+ font-size: 0.8em;
+ font-weight: 600;
+}
+#resume h4 {
+ font-size: 0.8em;
+ color: #444;
+ font-weight: 400;
+ padding: 0;
+ margin: 0;
+}
+#resume a {
+ color: #990000;
+}
+#resume .line {
+ font-size: 0.8em;
+ overflow: hidden;
+ padding-top: 12px;
+}
+#resume .title {
+ color: #444;
+ width: 130px;
+ display: block;
+ float: left;
+}
+#resume dl {
+ line-height: 30px;
+}
+#resume dt {
+ width: 190px;
+ float: left;
+}
+#resume .spanstart:after {
+ content: ' - ';
+}
+#resume .date_duration {
+ font-weight: 400;
+}
+#resume .vcard > h1 {
+ font-size: 1.6em;
+ padding: 0;
+ margin: 0;
+ font-weight: 400;
+ padding-bottom: 10px;
+}
+#resume .experience {
+ padding-bottom: 20px;
+}
+#resume .experience:last-child {
+ padding-bottom: 0;
+}
+#resume .experience-header {
+ overflow: hidden;
+}
+#resume .experience-hgroup {
+ float: left;
+}
+#resume .vcalendar li {
+ font-size: 0.8em;
+}
+#resume .description {
+ list-style: circle;
+ color: #666;
+ margin-left: 20px;
+ padding-left: 20px;
+ line-height: 25px;
+}
+#resume .skills {
+ overflow: hidden;
+ margin: 0;
+}
+#resume .skills li {
+ float: left;
+}
diff --git a/codelab-master/apps/kirjs/src/app/cv/resume.html b/codelab-master/apps/kirjs/src/app/cv/resume.html
new file mode 100644
index 000000000..2ad78393d
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/cv/resume.html
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Designed and contributed to the development of an Angular single
+ page app for generating reports
+
+
+ Developed Backbone-based form handling framework, for a CRUD
+ Single Page application
+
+
+ Organized and led internal hackathons, debates and presentations
+
+
+
+
+
+
+
+
+ Provided IT support for 50 users
+ Created a single page Backbone app, utilizing YouTube API
+ Developed Active Directory management system with C#
+
+
+
+
+
+
+
+ Developed WordPress web sites for CIPE, ALA group, Taxpayers for
+ Common Sense, Rosebar Lounge.
+
+
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/cv/resume.scss b/codelab-master/apps/kirjs/src/app/cv/resume.scss
new file mode 100644
index 000000000..319de81c2
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/cv/resume.scss
@@ -0,0 +1,122 @@
+ul {
+ li {
+ margin: 0;
+ padding: 0;
+ }
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+/*.......| Resume |.......................*/
+
+#resume {
+ #header {
+ width: 250px;
+ float: left;
+ .title {
+ width: 90px;
+ }
+ }
+
+ #info {
+ margin-left: 300px;
+ }
+ h1 {
+ font-size: 1.4em;
+ text-transform: uppercase;
+ margin-top: 30px;
+ margin-bottom: 20px;
+ }
+ h2 {
+ color: #900;
+ font-size: 1.4em;
+ font-weight: 400;
+ padding-top: 0px;
+ padding-bottom: 10px;
+ margin-bottom: 0;
+ }
+ h3 {
+ margin: 0;
+ font-size: 0.8em;
+ font-weight: 600;
+ }
+ h4 {
+ font-size: 0.8em;
+ color: #444;
+ font-weight: 400;
+ padding: 0;
+ margin: 0;
+ }
+ a {
+ color: #990000;
+ }
+
+ .line {
+ font-size: 0.8em;
+ overflow: hidden;
+ padding-top: 12px;
+ }
+ .title {
+ color: #444;
+ width: 130px;
+ display: block;
+ float: left;
+ }
+ max-width: 800px;
+ margin: 0 auto;
+ font-family: verdana, sans-serif;
+ dl {
+ line-height: 30px;
+ }
+ dt {
+ width: 190px;
+ float: left;
+ }
+ .spanstart:after {
+ content: ' - ';
+ }
+ .date_duration {
+ font-weight: 400;
+ }
+ .vcard > h1 {
+ font-size: 1.6em;
+ padding: 0;
+ margin: 0;
+ font-weight: 400;
+ padding-bottom: 10px;
+ }
+
+ .experience {
+ &:last-child {
+ padding-bottom: 0;
+ }
+ padding-bottom: 20px;
+ }
+ .experience-header {
+ overflow: hidden;
+ }
+ .experience-hgroup {
+ float: left;
+ }
+
+ .vcalendar li {
+ font-size: 0.8em;
+ }
+
+ .description {
+ list-style: circle;
+ color: #666;
+ margin-left: 20px;
+ padding-left: 20px;
+ line-height: 25px;
+ }
+
+ .skills {
+ overflow: hidden;
+ margin: 0;
+ li {
+ float: left;
+ }
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/kirjs.module.ts b/codelab-master/apps/kirjs/src/app/kirjs.module.ts
new file mode 100644
index 000000000..967374264
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/kirjs.module.ts
@@ -0,0 +1,189 @@
+import { BrowserModule } from '@angular/platform-browser';
+import { APP_INITIALIZER, NgModule } from '@angular/core';
+import { monacoReady } from '@codelab/code-demos';
+
+import { AppComponent } from './app.component';
+import { RouterModule } from '@angular/router';
+import { environment } from '../../../codelab/src/environments/environment';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { AngularFireModule } from '@angular/fire';
+import { AngularFireAuthModule } from '@angular/fire/auth';
+import { AngularFireDatabaseModule } from '@angular/fire/database';
+import { OverlayComponent } from './modules/streaming/overlay/overlay.component';
+import { MatCardModule } from '@angular/material/card';
+import { MarkdownModule } from 'ngx-markdown';
+
+export const angularFire = AngularFireModule.initializeApp(
+ environment.firebaseConfig
+);
+
+const routes = [
+ {
+ path: 'binary',
+ loadChildren: () =>
+ import('./modules/binary/binary.module').then(m => m.BinaryModule),
+ name: 'Binary',
+ description: 'Learn about Binary in JS',
+ page: 'bonus',
+ prod: true
+ },
+ {
+ path: 'gomoku',
+ loadChildren: () =>
+ import('./modules/gomoku/gomoku.module').then(m => m.GomokuModule),
+ name: 'Gomoku',
+ description: 'Gomoku',
+ page: 'bonus',
+ prod: true
+ },
+ {
+ path: 'cellular-automation',
+ loadChildren: () =>
+ import(
+ './modules/cellular-automation/cellular-automation-routing.module'
+ ).then(m => m.CellularAutomationRoutingModule),
+ name: 'Image inclusion',
+ description: 'Image inclusion'
+ },
+ {
+ path: 'music',
+ loadChildren: () =>
+ import('./modules/music/music.module').then(m => m.MusicModule),
+ name: 'Music',
+ description: 'Music'
+ },
+ {
+ path: 'webassembly',
+ loadChildren: () =>
+ import('./modules/webassembly/webassembly.module').then(
+ m => m.WebassemblyModule
+ ),
+ name: 'webassembly',
+ description: 'webassembly'
+ },
+ {
+ path: 'svg',
+ loadChildren: () =>
+ import('./modules/svg/svg.module').then(m => m.SvgModule),
+ name: 'Svg + Angular',
+ description: 'SVG '
+ },
+ {
+ path: 'regex',
+ loadChildren: () =>
+ import('./modules/regex/regex.module').then(m => m.RegexModule),
+ name: 'Regex',
+ description: 'Regex '
+ },
+ {
+ path: 'ast',
+ loadChildren: () =>
+ import('./modules/ast/ast.module').then(m => m.AstModule),
+ name: 'Ast + Angular',
+ description: 'SVG '
+ },
+ {
+ path: 'svg-race',
+ loadChildren: () =>
+ import('./modules/svg-race/svg-race.module').then(m => m.SvgRaceModule),
+ name: 'SVG Race',
+ description: 'SVG '
+ },
+ {
+ path: '',
+ loadChildren: () =>
+ import('./modules/home/home.module').then(m => m.HomeModule),
+ name: 'Home',
+ description: 'Home'
+ },
+ {
+ path: 'streaming',
+ loadChildren: () =>
+ import('./modules/streaming/streaming.module').then(
+ m => m.StreamingModule
+ ),
+ name: 'Home',
+ description: 'Home'
+ },
+ {
+ path: 'sync',
+ loadChildren: () =>
+ import('./modules/sync/sync.module').then(m => m.SyncModule),
+ name: 'Sync',
+ description: 'Sync Session'
+ },
+ {
+ path: 'stack',
+ loadChildren: () =>
+ import('./modules/stack/stack.module').then(m => m.StackModule),
+ name: 'Stack Module',
+ description: 'stack'
+ },
+ {
+ path: 'sync',
+ loadChildren: () =>
+ import('./modules/sync/sync.module').then(m => m.SyncModule),
+ name: 'Sync',
+ description: 'Sync Session'
+ },
+ {
+ path: 'test',
+ loadChildren: () =>
+ import('./modules/test/test.module').then(m => m.TestModule),
+ name: 'Home',
+ description: 'Home'
+ },
+ {
+ path: 'qna',
+ loadChildren: () =>
+ import('./modules/qna/qna.module').then(m => m.QnaModule),
+ name: 'Q&A'
+ },
+ {
+ path: 'msk',
+ loadChildren: () =>
+ import('./modules/msk/msk.module').then(m => m.MskModule),
+ name: 'Angular Moscow Meetup'
+ },
+ {
+ path: 'stack',
+ loadChildren: () =>
+ import('./modules/stack/stack-routing.module').then(
+ m => m.StackRoutingModule
+ ),
+ name: 'Stack Module',
+ description: 'stack'
+ }
+];
+
+@NgModule({
+ declarations: [AppComponent, OverlayComponent],
+ imports: [
+ BrowserModule,
+ BrowserAnimationsModule,
+ RouterModule.forRoot(routes),
+ AngularFireAuthModule,
+ AngularFireDatabaseModule,
+ angularFire,
+ MatCardModule,
+ MarkdownModule
+ ],
+ providers: [
+ {
+ provide: APP_INITIALIZER,
+ useValue: monacoReady,
+ multi: true
+ },
+ {
+ provide: 'ROUTES',
+ useValue: []
+ },
+ {
+ provide: APP_INITIALIZER,
+ useValue: monacoReady,
+ multi: true
+ }
+ ],
+ bootstrap: [AppComponent]
+})
+export class KirjsModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/ast-preview-runner/ast-preview-runner.component.css b/codelab-master/apps/kirjs/src/app/modules/ast/ast-preview-runner/ast-preview-runner.component.css
new file mode 100644
index 000000000..4f72b9c82
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/ast-preview-runner/ast-preview-runner.component.css
@@ -0,0 +1,8 @@
+.error {
+ color: red;
+ font-size: 50px;
+}
+
+:host ::ng-deep .header.header.header.header {
+ font-size: inherit;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/ast-preview-runner/ast-preview-runner.component.html b/codelab-master/apps/kirjs/src/app/modules/ast/ast-preview-runner/ast-preview-runner.component.html
new file mode 100644
index 000000000..d18a49f40
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/ast-preview-runner/ast-preview-runner.component.html
@@ -0,0 +1,4 @@
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/ast-preview-runner/ast-preview-runner.component.ts b/codelab-master/apps/kirjs/src/app/modules/ast/ast-preview-runner/ast-preview-runner.component.ts
new file mode 100644
index 000000000..d641ed5c8
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/ast-preview-runner/ast-preview-runner.component.ts
@@ -0,0 +1,55 @@
+import {
+ Component,
+ EventEmitter,
+ Input,
+ OnChanges,
+ Output,
+ SimpleChanges
+} from '@angular/core';
+import { parse } from 'babylon';
+
+declare const require;
+
+@Component({
+ selector: 'kirjs-ast-preview-runner',
+ templateUrl: './ast-preview-runner.component.html',
+ styleUrls: ['./ast-preview-runner.component.css']
+})
+export class AstPreviewRunnerComponent implements OnChanges {
+ ast: any;
+ hasError = false;
+ @Input() program = true;
+ @Input() code = '';
+ @Output() highlight = new EventEmitter();
+
+ update() {
+ this.run();
+ }
+
+ selectNode({ loc }) {
+ this.highlight.emit([
+ loc.start.line,
+ loc.start.column + 1,
+ loc.end.line,
+ loc.end.column + 1
+ ]);
+ }
+
+ run() {
+ this.hasError = false;
+ try {
+ this.ast = parse(this.code);
+ if (this.program) {
+ this.ast = this.ast.program.body;
+ }
+ } catch (e) {
+ this.hasError = true;
+ }
+ }
+
+ ngOnChanges(changes: SimpleChanges) {
+ this.run();
+ }
+
+ constructor() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/ast-preview-runner/ast-preview-runner.module.ts b/codelab-master/apps/kirjs/src/app/modules/ast/ast-preview-runner/ast-preview-runner.module.ts
new file mode 100644
index 000000000..c0609505d
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/ast-preview-runner/ast-preview-runner.module.ts
@@ -0,0 +1,12 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { AstPreviewRunnerComponent } from './ast-preview-runner.component';
+import { FormsModule } from '@angular/forms';
+import { AngularAstVizModule } from '@codelab/angular-ast-viz';
+
+@NgModule({
+ imports: [CommonModule, FormsModule, AngularAstVizModule],
+ declarations: [AstPreviewRunnerComponent],
+ exports: [AstPreviewRunnerComponent]
+})
+export class AstPreviewRunnerModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/ast.component.css b/codelab-master/apps/kirjs/src/app/modules/ast/ast.component.css
new file mode 100644
index 000000000..30a6c2b44
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/ast.component.css
@@ -0,0 +1,359 @@
+.bg {
+ background: #fff;
+ opacity: 0.7;
+ padding: 2vw 5vw;
+ margin: 5vw 0;
+ border: 1px solid #000;
+}
+
+#intro h1 {
+ font-size: 9vw;
+ font-weight: 100;
+ font-family: 'Helvetica Neue', sans-serif;
+}
+
+a {
+ color: #9c2600;
+}
+
+#intro h2,
+#outro h2 {
+ font-size: 12vw;
+}
+
+#intro h2,
+#outro h1 {
+ font-size: 6vw;
+}
+
+:host /deep/ .slide > div {
+ width: 100%;
+}
+
+:host /deep/ .slide {
+ background: transparent;
+}
+
+#sausage-pre {
+ background: url(pics/sausage-pre.jpg) no-repeat;
+ background-size: 100% auto;
+ display: inline-block;
+ height: 100vh;
+ font-size: 5vw;
+}
+
+#not-like-sausage {
+ background: url(pics/sausage2.jpg) no-repeat;
+ background-size: 100% auto;
+ display: inline-block;
+ height: 100vh;
+ font-size: 5vw;
+}
+
+#babel-types {
+ background: url(pics/park.jpg) no-repeat;
+ background-size: 100% auto;
+ display: inline-block;
+ height: 100vh;
+ font-size: 5vw;
+}
+
+#babel-traverse .bg,
+#babel-transform .bg,
+#renoir .bg {
+ margin: 30vw 0;
+}
+
+#babel-traverse {
+ background: url(pics/girl-reading-1890.jpg) no-repeat;
+ background-size: 100% auto;
+ display: inline-block;
+ height: 100vh;
+ font-size: 5vw;
+}
+
+#babel-transform {
+ background: url(pics/doggie.jpg) no-repeat;
+ background-size: 100% auto;
+ display: inline-block;
+ height: 100vh;
+ font-size: 5vw;
+}
+
+#debugger-pre {
+ background: url(pics/debugger.jpg) no-repeat;
+ background-size: 100% auto;
+ display: inline-block;
+ height: 100vh;
+ font-size: 5vw;
+}
+
+#renoir {
+ background: url(pics/renoir.png) no-repeat;
+ background-size: 100% auto;
+ display: inline-block;
+ height: 100vh;
+ font-size: 5vw;
+}
+
+#babel-remove-debugger {
+ background: url(pics/cat.jpg) no-repeat;
+ background-size: 100% auto;
+ display: inline-block;
+ height: 100vh;
+ font-size: 5vw;
+}
+
+#babel-fit {
+ background: url(pics/the-garden.jpg) no-repeat;
+ background-size: 100% auto;
+ display: inline-block;
+ height: 100vh;
+ font-size: 5vw;
+}
+
+#parser {
+ background: url(pics/parser.png) no-repeat;
+ background-size: 100% auto;
+ display: inline-block;
+ height: 100vh;
+ font-size: 5vw;
+}
+
+#links-5-cool-things {
+ background: url(pics/bg-links.jpg) no-repeat;
+ background-size: 100% auto;
+ display: inline-block;
+ height: 100vh;
+ font-size: 5vw;
+}
+
+#panda {
+ background: url(pics/panda.webp) no-repeat;
+ background-size: 100% auto;
+ display: inline-block;
+ height: 100vh;
+ font-size: 5vw;
+}
+
+.henry-zhu {
+ background: url(pics/patreon.png) no-repeat;
+ background-size: 100% auto;
+ display: inline-block;
+ height: 100vh;
+ font-size: 5vw;
+ width: 70vw;
+}
+
+.babylon {
+ background: url(pics/babylon.png) no-repeat;
+ background-size: 100% auto;
+ display: inline-block;
+ height: 100vh;
+ font-size: 5vw;
+ width: 70vw;
+}
+
+.babylon {
+ background: url(pics/babylon.png) no-repeat;
+ background-size: 100% auto;
+ display: inline-block;
+ height: 100vh;
+ font-size: 5vw;
+ width: 70vw;
+}
+
+.success-complete-disco {
+ margin-top: 20px;
+ width: 500px;
+ height: 300px;
+ background: url(pics/success/disco.webp);
+ background-repeat: no-repeat;
+ background-size: cover;
+}
+
+.success-complete-husky {
+ margin-top: 20px;
+ width: 500px;
+ height: 300px;
+ background: url(pics/success/happy.webp);
+ background-repeat: no-repeat;
+ background-size: cover;
+}
+
+.success-complete-dancing {
+ margin-top: 20px;
+ width: 500px;
+ height: 300px;
+ background: url(pics/success/dancing-dog.webp);
+ background-repeat: no-repeat;
+ background-size: cover;
+}
+
+.github {
+ background: url(pics/github.png) no-repeat;
+ background-size: 100% auto;
+ display: inline-block;
+ height: 100vh;
+ font-size: 5vw;
+ width: 70vw;
+}
+
+.opencollective {
+ background: url(pics/opencollective.png) no-repeat;
+ background-size: 100% auto;
+ display: inline-block;
+ height: 100vh;
+ font-size: 5vw;
+ width: 70vw;
+}
+
+#eslint {
+ background: url(pics/debugger.jpg) no-repeat;
+ background-size: 100% auto;
+ display: inline-block;
+ height: 100vh;
+ font-size: 5vw;
+}
+
+#kirjs {
+ background: url(pics/kirjs.jpg) no-repeat;
+ background-size: 100% auto;
+ display: inline-block;
+ height: 100vh;
+}
+
+#intro,
+#outro {
+ background: url(pics/landscape-with-trees-1.jpg) no-repeat;
+ background-size: 100% auto;
+ display: inline-block;
+ height: 100vh;
+}
+
+.bad-tree {
+ background: url(pics/tree.gif) no-repeat;
+ background-size: 100% auto;
+ display: inline-block;
+ height: 100vh;
+}
+
+#venok img {
+ width: 384px;
+ height: 288px;
+ margin: 0 auto;
+}
+
+.ast-explorer-link:hover {
+ font-size: 5vw;
+}
+
+.ast-explorer-link {
+ padding-top: 25px;
+ font-size: 10px;
+}
+
+.description.description.description {
+ margin: 0;
+ margin-top: 20px;
+ padding: 0;
+ font-size: 0;
+}
+
+#debugger-regex /deep/ .solution:hover:before {
+ color: red;
+ font-size: 3vw;
+}
+
+:host /deep/ #debugger-regex .solution {
+}
+
+.ast-preview-helper-list li:hover {
+ color: #444;
+}
+
+.ast-preview-helper-list li {
+ font-size: 20px;
+ text-decoration: dashed;
+ cursor: pointer;
+ color: #999;
+ border-bottom: 1px #ddd dashed;
+}
+
+.ast-preview {
+ font-size: 30px;
+}
+
+.two-button {
+ background: url(pics/button-1.png) no-repeat;
+ background-size: 50% auto;
+ display: inline-block;
+ height: 50vh;
+ font-size: 5vw;
+ border: 0 solid;
+ padding: 0;
+ margin: 0;
+}
+
+.two-button2 {
+ background: url(pics/two-button2.gif) no-repeat;
+ background-size: 50% auto;
+ display: inline-block;
+ height: 50vh;
+ font-size: 5vw;
+ border: 0 solid;
+ padding: 0;
+ margin: 0;
+}
+
+.two-button3 {
+ background: url(pics/two-button3.gif) no-repeat;
+ background-size: 100% auto;
+ display: inline-block;
+ height: 100vh;
+ font-size: 5vw;
+ border: 0 solid;
+ padding: 0;
+ margin: 0;
+}
+
+.link-number {
+ display: inline-block;
+ font-size: 8vw;
+ border-radius: 50%;
+ width: 10vw;
+ height: 10vw;
+ text-align: center;
+ margin-bottom: 10vh;
+}
+
+.collie.display {
+ background: url(pics/collie.webp) no-repeat;
+}
+
+.collie {
+ background-size: 100% auto;
+ display: inline-block;
+ height: 40vh;
+ font-size: 5vw;
+ width: 50vw;
+}
+
+.btn-bar {
+ line-height: 3vw;
+}
+
+.btn-bar:hover .font-size {
+ display: block;
+ font-size: 4vw;
+}
+
+.btn-bar .font-size {
+ display: none;
+}
+
+.twitter {
+ color: #444;
+ font-size: 3vw;
+ margin: 2vw;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/ast.component.html b/codelab-master/apps/kirjs/src/app/modules/ast/ast.component.html
new file mode 100644
index 000000000..8c332657e
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/ast.component.html
@@ -0,0 +1,429 @@
+
+
+
+
+
+
+
Абстрактные Синтаксические Деревья в JavaScript
+ @kirjs
+
+
+
+
+
+
+
Абстрактные синтаксические деревья (АСД)
+
+ Это выступление о том как научить код понимать и
+ трансформировать другой код.
+
+
+
+
+
+
Начнем сразу с примера
+ Как определить что из файла забыли вырезать console.log
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Парсим с помощью babylon:
+
+
+
+
+
19 Мая babylon был переименован в @babel/parser
+
+
+
+
+
+
+
Пример Абстрактного Синтаксического Дерева:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ log
+ console.log
+ log()
+ console.log()
+ console.log(1)
+
+ console.log(1, a.b)
+
+
+ All literals
+
+
+
+
+
+
+
+
+
+
+
+
Обход AST с помощью babel-traverse
+
+
+
+
+
+
Упрощаем работу с AST с помощью babel-types
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Давайте найдем в коде debugger
+
+
+
+
+
+
+ Давайте напишем плагин для
ESLint (на
+
AstExplorer )
+
+
+
+
+
Где еще полезны АСД?
+
+ Больше контроля надо кодом, проще рефакторинг, codemods
+ Меньше споров про оформление кода
+ Создание игровых проэктов
+ Лучшее понимание JavaScript
+
+
+
+
+
+
+ Когда вы увидите эти 5 ссылок про Babel вы не поверите своим
+ глаза...
+
+
+
+
+
+
+
2
+
+ Часть процесса добавления новой функциональности в EcmaScript - создание
+ плагина для Babel.
+
+
+
+
+
+
3
+
Babel Generator теряет форматирование при гегенерации кода.
+
+
+
+
+
4
+
+ Оргомная подборка информации про Babel в репозитории
+ Awesome Babel
+
+
+
+
+ 5
+
+ Babel - проект с открытыми исходниками, над ним трудится команда
+ волонтеров и им не помешала бы помощь :)
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/ast.component.ts b/codelab-master/apps/kirjs/src/app/modules/ast/ast.component.ts
new file mode 100644
index 000000000..afd57a239
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/ast.component.ts
@@ -0,0 +1,222 @@
+import { Component } from '@angular/core';
+
+import { parse } from 'babylon';
+import {
+ findHighlightsObjectProp,
+ isBody,
+ isLoc,
+ isType,
+ processCode,
+ removeDoubleWhiteLines,
+ removeLoc
+} from './parse-hello-world-ast';
+import { exercise } from '../../../../../codelab/src/app/shared/helpers/helpers';
+
+declare const require;
+
+const helloWorld = require('./samples/hello-world.json');
+
+function jsify(program) {
+ return 'const ast = ' + JSON.stringify(program, null, ' ');
+}
+
+const helloWorldCodePre = jsify(helloWorld);
+
+const angularCodeBefore = `import {
+ Component
+} from '@angular/core';
+
+@Component({
+ selector: 'amazing-component',
+ template: './app.html',
+})
+export class SimpleEditorComponent implements ControlValueAccessor {
+}`;
+const angularCodeAfter = `import {
+ Component,
+ forwardRef,
+} from '@angular/core';
+import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
+
+@Component({
+ selector: 'amazing-component',
+ template: './app.html',
+ providers: [
+ {
+ provide: NG_VALUE_ACCESSOR,
+ useExisting: forwardRef(() => SimpleEditorComponent),
+ multi: true
+ }
+ ],
+})
+export class SimpleEditorComponent implements ControlValueAccessor {
+ registerOnTouched(fn: any): void {
+ }
+
+ registerOnChange(onChange: (code: string) => void): void {
+ this.change.subscribe(onChange)
+ }
+
+ writeValue(value: string): void {
+ console.log(value)
+ }
+}`;
+
+const consoleLog = `console.log('hello')`;
+const consoleLogAst = parse(consoleLog);
+const consoleLogCode = JSON.stringify(consoleLogAst, null, ' ');
+const consoleLogBodyAst = consoleLogAst.program.body;
+const consoleLogBodyAstCode = JSON.stringify(consoleLogBodyAst, null, ' ');
+const consoleLogNoLocCode = removeDoubleWhiteLines(
+ processCode(consoleLogBodyAstCode, { remove: [removeLoc] })
+);
+
+@Component({
+ selector: 'kirjs-ast',
+ templateUrl: './ast.component.html',
+ styleUrls: ['./ast.component.css']
+})
+export class AstComponent {
+ fontSize = 28;
+
+ displayCallee = false;
+ code = {
+ parser: `import { parse } from 'babylon';
+parse("console.log('🐶🐶🐶')");`,
+ astPreview: 'log',
+ astPreviewDebugger: 'console.log();\ndebugger\n123',
+ types: {
+ identifier: `
+// Before
+path.node.property.type === 'Identifier'
+
+// with babel types
+import {isIdentifier} from 'babel-types';
+isIdentifier(path.node.property)`,
+ name: `
+// Before
+path.node.property.type === 'Identifier'
+path.node.property.name === 'log'
+
+// with babel types
+import {isIdentifier} from 'babel-types';
+isIdentifier(path.node.property, {name: log})`
+ },
+ astHello: 'hello(console.log)',
+ matches: {
+ loc: /"loc": \{[\s\S]*?\{[\s\S]*?\}[\s\S]*?\{[\s\S]*?\}[\s\S]*?\},/
+ },
+ astExampleFull: processCode(helloWorldCodePre, { remove: [] }),
+ astExample: removeDoubleWhiteLines(
+ processCode(helloWorldCodePre, { remove: [removeLoc] })
+ ),
+ astExampleNoBody: removeDoubleWhiteLines(
+ processCode(jsify(helloWorld.program.body), { remove: [removeLoc] })
+ ),
+ consoleLog: consoleLog,
+ consoleLogAst: consoleLogCode,
+ consoleLogAstJs: 'const ast = ' + consoleLogCode,
+ consoleLogBodyAstCode,
+ consoleLogNoLocCode,
+ angularCodeBefore,
+ angularCodeAfter,
+ angularMatchesAfter: [/a/],
+ findConsoleLog: [
+ exercise(
+ 'find-console-log',
+ require('!!raw-loader!./samples/find-console-log/find-console-log.js'),
+ require('!!raw-loader!./samples/find-console-log/find-console-log-regex.solved.js')
+ ),
+ exercise(
+ 'find-console-log.test',
+ require('!!raw-loader!./samples/find-console-log/find-console-log.test.js')
+ )
+ ],
+ findDebuggerBabel: [
+ exercise(
+ 'find-debugger-babel',
+ require('!!raw-loader!./samples/find-debugger/find-debugger-babel.ts'),
+ require('!!raw-loader!./samples/find-debugger/find-debugger-babel.solved.ts')
+ ),
+ exercise(
+ 'find-debugger.test',
+ require('!!raw-loader!./samples/find-debugger/find-debugger.test.js')
+ )
+ ],
+ traverseConsoleLogBabel: [
+ exercise(
+ 'traverse-console-log-babel',
+ require('!!raw-loader!./samples/find-console-log/traverse-console-log-babel.ts'),
+ require('!!raw-loader!./samples/find-console-log/traverse-console-log-babel.solved.ts')
+ ),
+ exercise(
+ 'find-console-log.test',
+ require('!!raw-loader!./samples/find-console-log/find-console-log.test.js')
+ )
+ ],
+ traverseConsoleLogBabel2: [
+ exercise(
+ 'traverse-console-log-babel',
+ require('!!raw-loader!./samples/find-console-log/traverse-console-log-babel.solved.ts'),
+ require('!!raw-loader!./samples/find-console-log/traverse-console-log-babel.solved2.ts')
+ ),
+ exercise(
+ 'find-console-log.test',
+ require('!!raw-loader!./samples/find-console-log/find-console-log.test.js')
+ )
+ ],
+ removeConsoleLogBabel: [
+ exercise(
+ 'remove-console-log',
+ require('!!raw-loader!./samples/find-console-log/remove-console-log.ts'),
+ require('!!raw-loader!./samples/find-console-log/remove-console-log.solved.ts')
+ ),
+ exercise(
+ 'remove-console-log.test',
+ require('!!raw-loader!./samples/find-console-log/remove-console-log.test.js')
+ )
+ ],
+ findfIt: [
+ exercise(
+ 'find-fit',
+ require('!!raw-loader!./samples/find-fit/find-fit.js'),
+ require('!!raw-loader!./samples/find-fit/find-fit.solved.js')
+ ),
+ exercise(
+ 'find-fit.test',
+ require('!!raw-loader!./samples/find-fit/find-fit.test.js')
+ )
+ ],
+ itLines: [
+ exercise(
+ 'it-lines',
+ require('!!raw-loader!./samples/it-lines/it-lines.js'),
+ require('!!raw-loader!./samples/it-lines/it-lines.solved.js')
+ ),
+ exercise(
+ 'it-lines.test',
+ require('!!raw-loader!./samples/it-lines/it-lines.test.js')
+ )
+ ],
+ decToBin: require('!!raw-loader!./samples/dec-to-bin.js'),
+ decToBinFixed: require('!!raw-loader!./samples/dec-to-bin-with-semicolons.js')
+ };
+
+ constructor() {}
+
+ matchTreePartsLoc(code) {
+ return findHighlightsObjectProp(code, [isLoc]);
+ }
+
+ matchTreePartsBody(code) {
+ return findHighlightsObjectProp(code, [isBody]);
+ }
+
+ matchTreePartsType(code) {
+ return findHighlightsObjectProp(code, [isType]);
+ }
+
+ updateFontSize(diff) {
+ this.fontSize += diff;
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/ast.module.ts b/codelab-master/apps/kirjs/src/app/modules/ast/ast.module.ts
new file mode 100644
index 000000000..b200b64ad
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/ast.module.ts
@@ -0,0 +1,45 @@
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { FormsModule } from '@angular/forms';
+import { MatCardModule } from '@angular/material/card';
+import { CommonModule } from '@angular/common';
+import { SlidesModule, SlidesRoutes } from '@ng360/slides';
+import { AngularSlidesToPdfModule } from '@codelab/angular-slides-to-pdf';
+import { BrowserWindowModule } from '@codelab/browser';
+import { FeedbackModule } from '@codelab/feedback';
+import { CodeDemoModule } from '@codelab/code-demos';
+import { AstPreviewRunnerModule } from './ast-preview-runner/ast-preview-runner.module';
+import { NewProgressBarModule } from './new-progress-bar/new-progress-bar.module';
+import { AstComponent } from './ast.component';
+import { DebuggerComponent } from './debugger/debugger.component';
+import { TestSetComponent } from './test-set/test-set.component';
+import { SizePickerModule } from './size-picker/size-picker.module';
+import { BabelTestRunnerComponent } from './test-set/babel-test-runner/babel-test-runner.component';
+
+const routes = RouterModule.forChild(SlidesRoutes.get(AstComponent));
+
+@NgModule({
+ imports: [
+ routes,
+ CommonModule,
+ AstPreviewRunnerModule,
+
+ SlidesModule,
+ BrowserWindowModule,
+ FeedbackModule,
+ CodeDemoModule,
+ FormsModule,
+ SizePickerModule,
+ MatCardModule,
+ NewProgressBarModule,
+ AngularSlidesToPdfModule
+ ],
+ declarations: [
+ AstComponent,
+ BabelTestRunnerComponent,
+ DebuggerComponent,
+ TestSetComponent
+ ],
+ exports: [AstComponent]
+})
+export class AstModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/babel-highlight/babel-highlight-match.directive.ts b/codelab-master/apps/kirjs/src/app/modules/ast/babel-highlight/babel-highlight-match.directive.ts
new file mode 100644
index 000000000..0d489f3ae
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/babel-highlight/babel-highlight-match.directive.ts
@@ -0,0 +1,36 @@
+import { AfterViewInit, Directive, Input, NgModule } from '@angular/core';
+import { CodeDemoEditorComponent } from '@codelab/code-demos/src/lib/code-demo-editor/code-demo-editor.component';
+
+// TODO(kirjs): Uncommit
+@Directive({
+ // tslint:disable-next-line:all TODO: Fix linter warnings on the selector and delete this comment.
+ selector: '[slidesBabelHighlightMatch]'
+})
+export class BabelHighlightDirective implements AfterViewInit {
+ // tslint:disable-next-line:all TODO: Fix linter warnings on the next line and delete this comment.
+ @Input('slidesBabelHighlightMatch') callback;
+
+ constructor(private editorComponent: CodeDemoEditorComponent) {}
+
+ ngAfterViewInit(): void {
+ if (this.callback) {
+ const matches = this.callback(this.editorComponent.code) || [];
+
+ const decorations = matches.map(match => {
+ return {
+ range: new this.editorComponent.monacoConfigService.monaco.Range(
+ ...match.loc
+ ),
+ options: { inlineClassName: match.className }
+ };
+ });
+
+ this.editorComponent.editor.deltaDecorations([], decorations);
+ }
+ }
+}
+
+@NgModule({
+ declarations: [BabelHighlightDirective]
+})
+export class MockaADASDASDASDASDASDModule {}
diff --git a/libs/utils/src/lib/sync/components/sync-code-game/sync-code-game-admin/sync-code-game-admin.component.css b/codelab-master/apps/kirjs/src/app/modules/ast/debugger/debugger.component.css
similarity index 100%
rename from libs/utils/src/lib/sync/components/sync-code-game/sync-code-game-admin/sync-code-game-admin.component.css
rename to codelab-master/apps/kirjs/src/app/modules/ast/debugger/debugger.component.css
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/debugger/debugger.component.html b/codelab-master/apps/kirjs/src/app/modules/ast/debugger/debugger.component.html
new file mode 100644
index 000000000..96240b0d6
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/debugger/debugger.component.html
@@ -0,0 +1,13 @@
+
+
+
+ RUN!
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/debugger/debugger.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/ast/debugger/debugger.component.spec.ts
new file mode 100644
index 000000000..6d7038ca6
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/debugger/debugger.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { DebuggerComponent } from './debugger.component';
+
+describe('DebuggerComponent', () => {
+ let component: DebuggerComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [DebuggerComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(DebuggerComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/debugger/debugger.component.ts b/codelab-master/apps/kirjs/src/app/modules/ast/debugger/debugger.component.ts
new file mode 100644
index 000000000..92e6af5d8
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/debugger/debugger.component.ts
@@ -0,0 +1,22 @@
+import { Component, Input, OnInit } from '@angular/core';
+
+declare const require;
+const code = require('!!raw-loader!./debugger.ts');
+
+@Component({
+ selector: 'kirjs-debugger-sample',
+ templateUrl: './debugger.component.html',
+ styleUrls: ['./debugger.component.css']
+})
+export class DebuggerComponent implements OnInit {
+ @Input() fontSize = 20;
+ code = code;
+
+ constructor() {}
+
+ run() {
+ eval(this.code + ';weird()');
+ }
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/debugger/debugger.ts b/codelab-master/apps/kirjs/src/app/modules/ast/debugger/debugger.ts
new file mode 100644
index 000000000..44388eeec
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/debugger/debugger.ts
@@ -0,0 +1,13 @@
+function weird() {
+ parseInt('Infinity', 10);
+ parseInt('Infinity', 18);
+ parseInt('Infinity', 19);
+ parseInt('Infinity', 23);
+ parseInt('Infinity', 24);
+ parseInt('Infinity', 29);
+ parseInt('Infinity', 30);
+ parseInt('Infinity', 34);
+ parseInt('Infinity', 35);
+ parseInt('Infinity', 36);
+ parseInt('Infinity', 37);
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/new-progress-bar/new-progress-bar.component.css b/codelab-master/apps/kirjs/src/app/modules/ast/new-progress-bar/new-progress-bar.component.css
new file mode 100644
index 000000000..26fffe6bf
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/new-progress-bar/new-progress-bar.component.css
@@ -0,0 +1,69 @@
+.progress-bar {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ width: 100vw;
+ z-index: 100;
+ background-color: #fff;
+ border-top: 1px solid #000;
+ padding: 0.5vw;
+ opacity: 0.3;
+}
+
+.progress-bar:hover .font-size {
+ visibility: visible;
+}
+
+.progress-bar:hover {
+ opacity: 1;
+}
+
+.font-size {
+ visibility: hidden;
+}
+
+.slide-block.completed-slide {
+ background: #ddd;
+}
+
+.slide-block.completed-slide {
+ background: #000;
+}
+
+.slide-block:hover {
+ opacity: 1;
+ cursor: pointer;
+}
+
+.slide-block.current-slide {
+ background: lime;
+}
+
+.slide-block {
+ margin-top: 0.1vw;
+ opacity: 0.7;
+ width: 0.5vw;
+ height: 0.5vw;
+ border: 1px solid #000;
+ border-radius: 50%;
+ margin-right: 0.3vw;
+}
+
+.handle {
+ font-family: 'Helvetica Neue', sans-serif;
+ position: fixed;
+ right: 0;
+ bottom: 0;
+ color: #444444;
+ font-size: 3vw;
+ z-index: 101;
+ padding: 0.5vw;
+ padding-right: 2vw;
+ text-shadow: 0px 3px 20px #fff, 0px -3px 20px #fff, -3px 0px 20px #fff,
+ 3px 0px 20px #fff;
+ text-decoration: none;
+}
+
+kirjs-size-picker {
+ margin-right: 200px;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/new-progress-bar/new-progress-bar.component.html b/codelab-master/apps/kirjs/src/app/modules/ast/new-progress-bar/new-progress-bar.component.html
new file mode 100644
index 000000000..a67d63567
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/new-progress-bar/new-progress-bar.component.html
@@ -0,0 +1,25 @@
+
+
{{ title }}
+
+
+
+
+
+
+
+sli.do/armadajs | @kirjs
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/new-progress-bar/new-progress-bar.component.ts b/codelab-master/apps/kirjs/src/app/modules/ast/new-progress-bar/new-progress-bar.component.ts
new file mode 100644
index 000000000..6639b5205
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/new-progress-bar/new-progress-bar.component.ts
@@ -0,0 +1,46 @@
+import {
+ AfterViewInit,
+ Component,
+ EventEmitter,
+ Input,
+ Output
+} from '@angular/core';
+import { SlidesDeckComponent } from '@ng360/slides';
+
+@Component({
+ selector: 'kirjs-new-progress-bar',
+ templateUrl: './new-progress-bar.component.html',
+ styleUrls: ['./new-progress-bar.component.css']
+})
+export class NewProgressBarComponent implements AfterViewInit {
+ @Input() fontSize = 28;
+ @Input() title = 'JavaScript AST';
+ @Output() fontSizeChange = new EventEmitter();
+ slides = [];
+ activeSlideIndex = 0;
+ tempSlideId = 0;
+
+ constructor(public deck: SlidesDeckComponent) {}
+
+ ngAfterViewInit() {
+ // Change detection complains if updating it right away.
+ requestAnimationFrame(() => {
+ this.slides = this.deck.slides;
+ this.activeSlideIndex = this.deck.activeSlideIndex;
+ });
+
+ this.deck.slideChange.subscribe(index => {
+ this.activeSlideIndex = index;
+ });
+ }
+
+ previewSlide(index) {
+ this.tempSlideId = this.activeSlideIndex;
+ this.deck.goToSlide(index);
+ }
+
+ goToSlide(index) {
+ this.deck.goToSlide(index);
+ this.tempSlideId = this.activeSlideIndex;
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/new-progress-bar/new-progress-bar.module.ts b/codelab-master/apps/kirjs/src/app/modules/ast/new-progress-bar/new-progress-bar.module.ts
new file mode 100644
index 000000000..854c0bdec
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/new-progress-bar/new-progress-bar.module.ts
@@ -0,0 +1,11 @@
+import { NgModule } from '@angular/core';
+import { NewProgressBarComponent } from './new-progress-bar.component';
+import { CommonModule } from '@angular/common';
+import { SizePickerModule } from '../size-picker/size-picker.module';
+
+@NgModule({
+ imports: [CommonModule, SizePickerModule],
+ declarations: [NewProgressBarComponent],
+ exports: [NewProgressBarComponent]
+})
+export class NewProgressBarModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/parse-hello-world-ast.ts b/codelab-master/apps/kirjs/src/app/modules/ast/parse-hello-world-ast.ts
new file mode 100644
index 000000000..f811896d8
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/parse-hello-world-ast.ts
@@ -0,0 +1,103 @@
+import { parse } from 'babylon';
+import generate from '@babel/generator';
+import babel_traverse from '@babel/traverse';
+
+export function isLoc(node) {
+ return (
+ node.key.value === 'loc' ||
+ node.key.value === 'start' ||
+ node.key.value === 'end' ||
+ node.key.value === 'extra'
+ );
+}
+
+export function isType(node) {
+ return node.key.value === 'type';
+}
+
+export function isBody(node) {
+ return node.key.value === 'body';
+}
+
+export function removeLoc(path) {
+ if (isLoc(path.node)) {
+ path.remove();
+ }
+}
+
+export function removeExtra(path) {
+ if (isLoc(path.node)) {
+ path.remove();
+ }
+}
+
+export function locToMonacoLoc(loc, className) {
+ return {
+ loc: [
+ loc.start.line,
+ loc.start.column + 1,
+ loc.end.line,
+ loc.end.column + 1
+ ],
+ className
+ };
+}
+export function parseCode(code) {
+ return parse(code);
+}
+
+export function processCode(code, { remove = [] }: any) {
+ const ast = parse(code, {
+ sourceType: 'module',
+ plugins: ['decorators']
+ });
+
+ babel_traverse(ast, {
+ ObjectProperty(path) {
+ remove.forEach(callback => callback(path));
+ }
+ });
+
+ return generate(ast, {}).code;
+}
+
+export function findHighlightsObjectProp(code: string, matchers: Array) {
+ const ast = parse(code, {
+ sourceType: 'module',
+ plugins: ['decorators']
+ });
+
+ const highlights = [];
+
+ babel_traverse(ast, {
+ ObjectProperty({ node }) {
+ if (matchers.some(matcher => matcher(node))) {
+ highlights.push(locToMonacoLoc(node.loc, 'loc'));
+ }
+ }
+ });
+ return highlights;
+}
+
+export function findHighlightsAll(code: string, matcher) {
+ const ast = parse(code, {
+ sourceType: 'module',
+ plugins: ['decorators']
+ });
+
+ const highlights = [];
+
+ babel_traverse(ast, {
+ enter({ node }) {
+ const className = matcher(node);
+ if (className) {
+ highlights.push(locToMonacoLoc(node.loc, className));
+ }
+ }
+ });
+ return highlights;
+}
+
+export function removeDoubleWhiteLines(code) {
+ return code.replace(/\n\n/gi, '\n');
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/babylon.png b/codelab-master/apps/kirjs/src/app/modules/ast/pics/babylon.png
new file mode 100644
index 000000000..636e1c0a1
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/babylon.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/bg-links.jpg b/codelab-master/apps/kirjs/src/app/modules/ast/pics/bg-links.jpg
new file mode 100644
index 000000000..81c876606
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/bg-links.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/button-1.png b/codelab-master/apps/kirjs/src/app/modules/ast/pics/button-1.png
new file mode 100644
index 000000000..e640b8e46
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/button-1.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/cat.jpg b/codelab-master/apps/kirjs/src/app/modules/ast/pics/cat.jpg
new file mode 100644
index 000000000..888e8bb0d
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/cat.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/collie.webp b/codelab-master/apps/kirjs/src/app/modules/ast/pics/collie.webp
new file mode 100644
index 000000000..c71549823
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/collie.webp differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/console.png b/codelab-master/apps/kirjs/src/app/modules/ast/pics/console.png
new file mode 100644
index 000000000..c8e7eb26a
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/console.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/debugger.jpg b/codelab-master/apps/kirjs/src/app/modules/ast/pics/debugger.jpg
new file mode 100644
index 000000000..42beb2c06
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/debugger.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/doggie.jpg b/codelab-master/apps/kirjs/src/app/modules/ast/pics/doggie.jpg
new file mode 100644
index 000000000..2088f4b09
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/doggie.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/girl-reading-1890.jpg b/codelab-master/apps/kirjs/src/app/modules/ast/pics/girl-reading-1890.jpg
new file mode 100644
index 000000000..023ba94d0
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/girl-reading-1890.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/github.png b/codelab-master/apps/kirjs/src/app/modules/ast/pics/github.png
new file mode 100644
index 000000000..e522423eb
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/github.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/kirjs.jpg b/codelab-master/apps/kirjs/src/app/modules/ast/pics/kirjs.jpg
new file mode 100644
index 000000000..daad7ca92
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/kirjs.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/landscape-with-trees-1.jpg b/codelab-master/apps/kirjs/src/app/modules/ast/pics/landscape-with-trees-1.jpg
new file mode 100644
index 000000000..73ced1d29
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/landscape-with-trees-1.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/lotus.jpg b/codelab-master/apps/kirjs/src/app/modules/ast/pics/lotus.jpg
new file mode 100644
index 000000000..3aaca818a
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/lotus.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/magicshialabeouf-650x400.jpg b/codelab-master/apps/kirjs/src/app/modules/ast/pics/magicshialabeouf-650x400.jpg
new file mode 100644
index 000000000..34b678c79
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/magicshialabeouf-650x400.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/opencollective.png b/codelab-master/apps/kirjs/src/app/modules/ast/pics/opencollective.png
new file mode 100644
index 000000000..d7b8fe7ba
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/opencollective.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/panda.webp b/codelab-master/apps/kirjs/src/app/modules/ast/pics/panda.webp
new file mode 100644
index 000000000..5183ab9fa
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/panda.webp differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/park.jpg b/codelab-master/apps/kirjs/src/app/modules/ast/pics/park.jpg
new file mode 100644
index 000000000..3daea2047
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/park.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/parser.png b/codelab-master/apps/kirjs/src/app/modules/ast/pics/parser.png
new file mode 100644
index 000000000..023f1c695
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/parser.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/patreon.png b/codelab-master/apps/kirjs/src/app/modules/ast/pics/patreon.png
new file mode 100644
index 000000000..af39dd647
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/patreon.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/renoir.png b/codelab-master/apps/kirjs/src/app/modules/ast/pics/renoir.png
new file mode 100644
index 000000000..a6161b2f9
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/renoir.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/roses-garden.jpg b/codelab-master/apps/kirjs/src/app/modules/ast/pics/roses-garden.jpg
new file mode 100644
index 000000000..a86e5db63
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/roses-garden.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/sausage-pre.jpg b/codelab-master/apps/kirjs/src/app/modules/ast/pics/sausage-pre.jpg
new file mode 100644
index 000000000..e914e8613
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/sausage-pre.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/sausage.jpg b/codelab-master/apps/kirjs/src/app/modules/ast/pics/sausage.jpg
new file mode 100644
index 000000000..0b7a56e82
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/sausage.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/sausage2.jpg b/codelab-master/apps/kirjs/src/app/modules/ast/pics/sausage2.jpg
new file mode 100644
index 000000000..1edd5bb6e
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/sausage2.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/semicolon-missing.png b/codelab-master/apps/kirjs/src/app/modules/ast/pics/semicolon-missing.png
new file mode 100644
index 000000000..90c043199
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/semicolon-missing.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/shocked.gif b/codelab-master/apps/kirjs/src/app/modules/ast/pics/shocked.gif
new file mode 100644
index 000000000..09e5876b2
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/shocked.gif differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/success/dancing-dog.webp b/codelab-master/apps/kirjs/src/app/modules/ast/pics/success/dancing-dog.webp
new file mode 100644
index 000000000..cd6a8a986
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/success/dancing-dog.webp differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/success/disco.webp b/codelab-master/apps/kirjs/src/app/modules/ast/pics/success/disco.webp
new file mode 100644
index 000000000..5e63f7b21
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/success/disco.webp differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/success/happy.webp b/codelab-master/apps/kirjs/src/app/modules/ast/pics/success/happy.webp
new file mode 100644
index 000000000..52303bc75
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/success/happy.webp differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/the-garden.jpg b/codelab-master/apps/kirjs/src/app/modules/ast/pics/the-garden.jpg
new file mode 100644
index 000000000..0d31516af
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/the-garden.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/tree.gif b/codelab-master/apps/kirjs/src/app/modules/ast/pics/tree.gif
new file mode 100644
index 000000000..c4a39927e
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/tree.gif differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/tree_yanik.gif b/codelab-master/apps/kirjs/src/app/modules/ast/pics/tree_yanik.gif
new file mode 100644
index 000000000..82d13ec92
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/tree_yanik.gif differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/two-button2.gif b/codelab-master/apps/kirjs/src/app/modules/ast/pics/two-button2.gif
new file mode 100644
index 000000000..280662231
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/two-button2.gif differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/two-button3.gif b/codelab-master/apps/kirjs/src/app/modules/ast/pics/two-button3.gif
new file mode 100644
index 000000000..9e1ad8fc5
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/two-button3.gif differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/woman-in-a-landscape (1).jpg b/codelab-master/apps/kirjs/src/app/modules/ast/pics/woman-in-a-landscape (1).jpg
new file mode 100644
index 000000000..26240f812
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/woman-in-a-landscape (1).jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/pics/woman-in-a-landscape.jpg b/codelab-master/apps/kirjs/src/app/modules/ast/pics/woman-in-a-landscape.jpg
new file mode 100644
index 000000000..26240f812
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/ast/pics/woman-in-a-landscape.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/dec-to-bin-with-semicolons.js b/codelab-master/apps/kirjs/src/app/modules/ast/samples/dec-to-bin-with-semicolons.js
new file mode 100644
index 000000000..4b00d54cc
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/dec-to-bin-with-semicolons.js
@@ -0,0 +1,132 @@
+function bin6BitsToDec(bin) {
+ switch (bin) {
+ case '000000':
+ return 0;
+ case '000001':
+ return 1;
+ case '000010':
+ return 2;
+ case '000011':
+ return 3;
+ case '000100':
+ return 4;
+ case '000101':
+ return 5;
+ case '000110':
+ return 6;
+ case '000111':
+ return 7;
+ case '001000':
+ return 8;
+ case '001001':
+ return 9;
+ case '001010':
+ return 10;
+ case '001011':
+ return 11;
+ case '001100':
+ return 12;
+ case '001101':
+ return 13;
+ case '001110':
+ return 14;
+ case '001111':
+ return 15;
+ case '010000':
+ return 16;
+ case '010001':
+ return 17;
+ case '010010':
+ return 18;
+ case '010011':
+ return 19;
+ case '010100':
+ return 20;
+ case '010101':
+ return 21;
+ case '010110':
+ return 22;
+ case '010111':
+ return 23;
+ case '011000':
+ return 24;
+ case '011001':
+ return 25;
+ case '011010':
+ return 26;
+ case '011011':
+ return 27;
+ case '011100':
+ return 28;
+ case '011101':
+ return 29;
+ case '011110':
+ return 30;
+ case '011111':
+ return 31;
+ case '100000':
+ return 32;
+ case '100001':
+ return 33;
+ case '100010':
+ return 34;
+ case '100011':
+ return 35;
+ case '100100':
+ return 36;
+ case '100101':
+ return 37;
+ case '100110':
+ return 38;
+ case '100111':
+ return 39;
+ case '101000':
+ return 40;
+ case '101001':
+ return 41;
+ case '101010':
+ return 42;
+ case '101011':
+ return 43;
+ case '101100':
+ return 44;
+ case '101101':
+ return 45;
+ case '101110':
+ return 46;
+ case '101111':
+ return 47;
+ case '110000':
+ return 48;
+ case '110001':
+ return 49;
+ case '110010':
+ return 50;
+ case '110011':
+ return 51;
+ case '110100':
+ return 52;
+ case '110101':
+ return 53;
+ case '110110':
+ return 54;
+ case '110111':
+ return 55;
+ case '111000':
+ return 56;
+ case '111001':
+ return 57;
+ case '111010':
+ return 58;
+ case '111011':
+ return 59;
+ case '111100':
+ return 60;
+ case '111101':
+ return 61;
+ case '111110':
+ return 62;
+ case '111111':
+ return 63;
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/dec-to-bin.js b/codelab-master/apps/kirjs/src/app/modules/ast/samples/dec-to-bin.js
new file mode 100644
index 000000000..4b00d54cc
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/dec-to-bin.js
@@ -0,0 +1,132 @@
+function bin6BitsToDec(bin) {
+ switch (bin) {
+ case '000000':
+ return 0;
+ case '000001':
+ return 1;
+ case '000010':
+ return 2;
+ case '000011':
+ return 3;
+ case '000100':
+ return 4;
+ case '000101':
+ return 5;
+ case '000110':
+ return 6;
+ case '000111':
+ return 7;
+ case '001000':
+ return 8;
+ case '001001':
+ return 9;
+ case '001010':
+ return 10;
+ case '001011':
+ return 11;
+ case '001100':
+ return 12;
+ case '001101':
+ return 13;
+ case '001110':
+ return 14;
+ case '001111':
+ return 15;
+ case '010000':
+ return 16;
+ case '010001':
+ return 17;
+ case '010010':
+ return 18;
+ case '010011':
+ return 19;
+ case '010100':
+ return 20;
+ case '010101':
+ return 21;
+ case '010110':
+ return 22;
+ case '010111':
+ return 23;
+ case '011000':
+ return 24;
+ case '011001':
+ return 25;
+ case '011010':
+ return 26;
+ case '011011':
+ return 27;
+ case '011100':
+ return 28;
+ case '011101':
+ return 29;
+ case '011110':
+ return 30;
+ case '011111':
+ return 31;
+ case '100000':
+ return 32;
+ case '100001':
+ return 33;
+ case '100010':
+ return 34;
+ case '100011':
+ return 35;
+ case '100100':
+ return 36;
+ case '100101':
+ return 37;
+ case '100110':
+ return 38;
+ case '100111':
+ return 39;
+ case '101000':
+ return 40;
+ case '101001':
+ return 41;
+ case '101010':
+ return 42;
+ case '101011':
+ return 43;
+ case '101100':
+ return 44;
+ case '101101':
+ return 45;
+ case '101110':
+ return 46;
+ case '101111':
+ return 47;
+ case '110000':
+ return 48;
+ case '110001':
+ return 49;
+ case '110010':
+ return 50;
+ case '110011':
+ return 51;
+ case '110100':
+ return 52;
+ case '110101':
+ return 53;
+ case '110110':
+ return 54;
+ case '110111':
+ return 55;
+ case '111000':
+ return 56;
+ case '111001':
+ return 57;
+ case '111010':
+ return 58;
+ case '111011':
+ return 59;
+ case '111100':
+ return 60;
+ case '111101':
+ return 61;
+ case '111110':
+ return 62;
+ case '111111':
+ return 63;
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/eslint/eslint.js b/codelab-master/apps/kirjs/src/app/modules/ast/samples/eslint/eslint.js
new file mode 100644
index 000000000..f5cca0b55
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/eslint/eslint.js
@@ -0,0 +1,8 @@
+function findFit(code, { babylon, babelTraverse, babelGenerator, log }) {
+ const ast = babylon.parse(code);
+
+ babelTraverse(ast);
+
+ log(babelGenerator(ast).code);
+ return babelGenerator(ast).code;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/eslint/eslint.test.js b/codelab-master/apps/kirjs/src/app/modules/ast/samples/eslint/eslint.test.js
new file mode 100644
index 000000000..fba045364
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/eslint/eslint.test.js
@@ -0,0 +1,63 @@
+function testThings(findDebugger, callback, args) {
+ const log = args.log;
+ const tests = [
+ {
+ title: `describe('test', ()=>{
+ fit('test', ()=>{
+ expect(true).toBe(true);
+ })
+})`,
+ test(func, args) {
+ let result = func(this.title, args);
+ return result && result.includes && !result.includes('fit');
+ }
+ },
+ {
+ title: `describe('test', ()=>{
+ fit('fits?', ()=>{
+ let fit = true;
+ expect(fit).toBe(true);
+ })
+})`,
+ test(func, args) {
+ let result = func(this.title, args);
+ return (
+ result &&
+ result.includes &&
+ !result.includes('fit(') &&
+ result.includes('let fit')
+ );
+ }
+ }
+ ];
+
+ let results = [];
+ let failed = false;
+ for (let i in tests) {
+ if (tests.hasOwnProperty(i)) {
+ let test = tests[i];
+ if (!failed) {
+ const logs = [];
+ args.log = value => {
+ logs.push(value);
+ };
+ let pass = test.test(findDebugger, args);
+ results.push({ title: test.title, pass: pass });
+ if (!pass) {
+ failed = true;
+ logs.map(log);
+ }
+ } else {
+ results.push({ title: test.title, pass: false });
+ }
+ }
+ }
+
+ callback(results);
+}
+/**
+
+ return code
+ .replace(/\/\/.*|'.*?[^\\]'|".*"|`[\s\S]+`/)
+ .match(/\bdebugger\b/)
+ */
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/find-console-log-babel.solved.ts b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/find-console-log-babel.solved.ts
new file mode 100644
index 000000000..76084cb29
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/find-console-log-babel.solved.ts
@@ -0,0 +1,6 @@
+// tslint:ignore
+function findConsoleLogSolved(code, { babylon, babelTraverse, log }) {
+ return babylon
+ .parse(code)
+ .program.body.some(node => node.type === 'ConsoleLogStatement');
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/find-console-log-babel.ts b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/find-console-log-babel.ts
new file mode 100644
index 000000000..143ddb436
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/find-console-log-babel.ts
@@ -0,0 +1,3 @@
+function findConsoleLogBabel(code, { babylon, babelTraverse, log }) {
+ // Find debugger!!
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/find-console-log-regex.solved.js b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/find-console-log-regex.solved.js
new file mode 100644
index 000000000..83d7830aa
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/find-console-log-regex.solved.js
@@ -0,0 +1,5 @@
+function findConsoleLog(code) {
+ return code
+ .replace(/\/\/.*|'.*?[^\\]'|".*?"|`[\s\S]*`|\/\*[\s\S]*\*\//)
+ .match(/\bconsole\s*.log\(/);
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/find-console-log.js b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/find-console-log.js
new file mode 100644
index 000000000..fd2105101
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/find-console-log.js
@@ -0,0 +1 @@
+function findConsoleLog(code) {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/find-console-log.test.js b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/find-console-log.test.js
new file mode 100644
index 000000000..b205c5809
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/find-console-log.test.js
@@ -0,0 +1,120 @@
+function testThings(findConsoleLog, callback, args) {
+ const log = args.log;
+ const tests = [
+ {
+ code: `console.log('🐶🐶🐶')`,
+ expected: true
+ },
+ {
+ code: `lolconsole.log()`,
+ expected: false
+ },
+ {
+ code: `// don't use console.log();`,
+ expected: false
+ },
+ {
+ code: `'console.log()'`,
+ expected: false
+ },
+ {
+ code: `'hi'; console.log(123); 'bye'`,
+ expected: true
+ },
+ {
+ code: `console
+ .log()`,
+ expected: true
+ },
+ {
+ code: `'Fake //'; console.log(123); `,
+ expected: true
+ },
+ {
+ code: `"console.log(123)"`,
+ expected: false
+ },
+ {
+ code: `\`
+ console.log(123)\``,
+ expected: false
+ },
+ {
+ code: `' \\' console.log(123)'`,
+ expected: false
+ },
+ {
+ code: `console.lol()`,
+ expected: false
+ },
+ {
+ code: `"hello".log()`,
+ expected: false
+ },
+ {
+ code: `/* \`
+ */ console.log(123); \`
+ \` + ''`,
+ expected: true
+ },
+ {
+ code: `function hello() {
+ console.log(123);
+ }`,
+ expected: true
+ },
+ {
+ code: `console.log({
+ hello: 123
+ })`,
+ expected: true
+ },
+ {
+ code: `console.log`,
+ expected: false
+ },
+ {
+ code: `hello(console.log)`,
+ expected: false
+ }
+ ];
+
+ let results = [];
+ let failed = false;
+ for (let i in tests) {
+ if (tests.hasOwnProperty(i)) {
+ let test = tests[i];
+ if (!failed) {
+ const logs = [];
+ args.log = value => {
+ logs.push(value);
+ };
+
+ const result = !!findConsoleLog(test.code, args);
+ const pass = result === test.expected;
+
+ results.push({
+ code: test.code,
+ expected: test.expected,
+ result,
+ pass
+ });
+ if (!pass) {
+ failed = true;
+ logs.map(log);
+ }
+ } else {
+ results.push({ code: test.code, pass: false });
+ }
+ }
+ }
+
+ callback(results);
+}
+
+/**
+
+ return code
+ .replace(/\/\/.*|'.*?[^\\]'|".*"|`[\s\S]+`/)
+ .match(/\bdebugger\b/)
+ */
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/remove-console-log.solved.ts b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/remove-console-log.solved.ts
new file mode 100644
index 000000000..8fdcb6cff
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/remove-console-log.solved.ts
@@ -0,0 +1,21 @@
+function removeConsoleLogSolved(
+ code,
+ { babelGenerator, babylon, babelTraverse, types }
+) {
+ const ast = babylon.parse(code);
+
+ babelTraverse(ast, {
+ MemberExpression(path) {
+ if (
+ types.isIdentifier(path.node.object, { name: 'console' }) &&
+ types.isIdentifier(path.node.property, { name: 'log' }) &&
+ types.isCallExpression(path.parent) &&
+ path.parentKey === 'callee'
+ ) {
+ path.parentPath.remove();
+ }
+ }
+ });
+
+ return babelGenerator(ast).code;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/remove-console-log.test.js b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/remove-console-log.test.js
new file mode 100644
index 000000000..4d9028eb1
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/remove-console-log.test.js
@@ -0,0 +1,108 @@
+function testThings(findConsoleLog, callback, args) {
+ const log = args.log;
+ const tests = [
+ {
+ code: `console.log('🐶🐶🐶')`,
+ expected: ''
+ },
+ {
+ code: `lolconsole.log();`,
+ expected: 'lolconsole.log();'
+ },
+ {
+ code: `console.lol();`,
+ expected: `console.lol();`
+ },
+ {
+ code: `// don't use console.log();`,
+ expected: `// don't use console.log();`
+ },
+ {
+ code: `'console.log()';`,
+ expected: `'console.log()';`
+ },
+ {
+ code: `'hi'; console.log(123); 'bye';`,
+ expected: `'hi';\n'bye';`
+ },
+ {
+ code: `console
+ .log()`,
+ expected: ``
+ },
+ {
+ code: `"console.log(123)";`,
+ expected: `"console.log(123)";`
+ },
+ {
+ code: `\`
+ console.log(1234)\`;`,
+ expected: `\`
+ console.log(1234)\`;`
+ },
+ {
+ code: `' \\' console.log(123)';`,
+ expected: `' \\' console.log(123)';`
+ },
+ {
+ code: `/* \`
+ */ console.log(123); \`
+ \` + '';`,
+ expected: `\`
+ \` + ''; /* \`
+ */`
+ },
+ {
+ code: `hello(console.log);`,
+ expected: `hello(console.log);`
+ }
+ ];
+
+ let results = [];
+ let failed = false;
+ for (let i in tests) {
+ if (tests.hasOwnProperty(i)) {
+ let test = tests[i];
+ if (!failed) {
+ const logs = [];
+ args.log = value => {
+ logs.push(value);
+ };
+
+ let result = false;
+
+ let error;
+ try {
+ result = findConsoleLog(test.code, args);
+ } catch (e) {
+ error = e;
+ }
+
+ const pass = result === test.expected;
+
+ results.push({
+ code: test.code,
+ expected: test.expected,
+ result,
+ pass,
+ error
+ });
+ if (!pass) {
+ failed = true;
+ logs.map(log);
+ }
+ } else {
+ results.push({ code: test.code, pass: false });
+ }
+ }
+ }
+
+ callback(results);
+}
+
+/**
+
+ return code
+ .replace(/\/\/.*|'.*?[^\\]'|".*"|`[\s\S]+`/)
+ .match(/\bdebugger\b/)
+ */
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/remove-console-log.ts b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/remove-console-log.ts
new file mode 100644
index 000000000..c6a6018c3
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/remove-console-log.ts
@@ -0,0 +1,21 @@
+function removeConsoleLog(
+ code,
+ { babelGenerator, babylon, babelTraverse, types }
+) {
+ const ast = babylon.parse(code);
+ let hasConsoleLog = false;
+ babelTraverse(ast, {
+ MemberExpression(path) {
+ if (
+ types.isIdentifier(path.node.object, { name: 'console' }) &&
+ types.isIdentifier(path.node.property, { name: 'log' }) &&
+ types.isCallExpression(path.parent) &&
+ path.parentKey === 'callee'
+ ) {
+ hasConsoleLog = true;
+ }
+ }
+ });
+
+ return hasConsoleLog;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/traverse-console-log-babel.solved.ts b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/traverse-console-log-babel.solved.ts
new file mode 100644
index 000000000..d05fc7a5e
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/traverse-console-log-babel.solved.ts
@@ -0,0 +1,23 @@
+function traverseConsoleLogSolved(
+ code,
+ { babylon, babelTraverse, types, log }
+) {
+ const ast = babylon.parse(code);
+ let hasConsoleLog = false;
+ babelTraverse(ast, {
+ MemberExpression(path) {
+ if (
+ path.node.property.type === 'Identifier' &&
+ path.node.property.name === 'log' &&
+ path.node.object.type === 'Identifier' &&
+ path.node.object.name === 'console' &&
+ path.parent.type === 'CallExpression' &&
+ path.key === 'callee'
+ ) {
+ hasConsoleLog = true;
+ }
+ }
+ });
+
+ return hasConsoleLog;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/traverse-console-log-babel.solved2.ts b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/traverse-console-log-babel.solved2.ts
new file mode 100644
index 000000000..24fabf671
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/traverse-console-log-babel.solved2.ts
@@ -0,0 +1,18 @@
+function traverseConsoleLogSolved2(code, { babylon, babelTraverse, types }) {
+ const ast = babylon.parse(code);
+ let hasConsoleLog = false;
+ babelTraverse(ast, {
+ MemberExpression(path) {
+ if (
+ types.isIdentifier(path.node.object, { name: 'console' }) &&
+ types.isIdentifier(path.node.property, { name: 'log' }) &&
+ types.isCallExpression(path.parent) &&
+ path.parentKey === 'callee'
+ ) {
+ hasConsoleLog = true;
+ }
+ }
+ });
+
+ return hasConsoleLog;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/traverse-console-log-babel.ts b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/traverse-console-log-babel.ts
new file mode 100644
index 000000000..049c11d70
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-console-log/traverse-console-log-babel.ts
@@ -0,0 +1,3 @@
+function traverseConsoleLog(code, { babylon, babelTraverse, log }) {
+ const ast = babylon.parse(code);
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/find-debugger-babel.solved.ts b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/find-debugger-babel.solved.ts
new file mode 100644
index 000000000..9ef796c9c
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/find-debugger-babel.solved.ts
@@ -0,0 +1,6 @@
+// tslint:ignore
+function findDebuggerSolved(code, { babylon, babelTraverse, log }) {
+ return babylon
+ .parse(code)
+ .program.body.some(node => node.type === 'DebuggerStatement');
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/find-debugger-babel.ts b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/find-debugger-babel.ts
new file mode 100644
index 000000000..24cc013fa
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/find-debugger-babel.ts
@@ -0,0 +1,3 @@
+function findDebuggerBabel(code, { babylon, babelTraverse, log }) {
+ // Find debugger!!
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/find-debugger-regex.solved.js b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/find-debugger-regex.solved.js
new file mode 100644
index 000000000..5f6601cab
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/find-debugger-regex.solved.js
@@ -0,0 +1,5 @@
+function findDebugger(code) {
+ return code
+ .replace(/\/\/.*|'.*?[^\\]'|".*?"|`[\s\S]*`|\/\*[\s\S]*\*\//)
+ .match(/\bdebugger\b/);
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/find-debugger.js b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/find-debugger.js
new file mode 100644
index 000000000..4bb1f9905
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/find-debugger.js
@@ -0,0 +1 @@
+function findDebugger(code) {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/find-debugger.test.js b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/find-debugger.test.js
new file mode 100644
index 000000000..3a2aa0cb8
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/find-debugger.test.js
@@ -0,0 +1,132 @@
+function testThings(findDebugger, callback, args) {
+ const log = args.log;
+ const tests = [
+ {
+ title: `debugger`,
+ shouldPass: true,
+ test(func, args) {
+ return !!func(this.title, args);
+ }
+ },
+ {
+ title: `debuggerStart()`,
+ shouldPass: false,
+ test(func, args) {
+ return !func(this.title, args);
+ }
+ },
+ {
+ title: `//debugger
+console.log('hi');`,
+ shouldPass: false,
+ test(func, args) {
+ return !func(this.title, args);
+ }
+ },
+ {
+ title: `'debugger'`,
+ shouldPass: false,
+ test(func, args) {
+ return !func(this.title, args);
+ }
+ },
+ {
+ title: `'hi'; debugger; 'bye'`,
+ shouldPass: true,
+ test(func, args) {
+ return func(this.title, args);
+ }
+ },
+ {
+ title: `'Fake //'; debugger; `,
+ shouldPass: true,
+ test(func, args) {
+ return func(this.title, args);
+ }
+ },
+ {
+ title: `"debugger"`,
+ shouldPass: false,
+ test(func, args) {
+ return !func(this.title, args);
+ }
+ },
+ {
+ title: `\`
+ debugger\``,
+ shouldPass: false,
+ test(func, args) {
+ return !func(this.title, args);
+ }
+ },
+ {
+ title: `' \\' debugger'`,
+ test(func, args) {
+ return !func(this.title, args);
+ },
+ shouldPass: false
+ },
+ {
+ title: `/* \`
+ */ debugger; \`
+ \` + ''`,
+ test(func, args) {
+ return func(this.title, args);
+ }
+ },
+ {
+ title: `function hello(){ debugger; }
+
+
+ class Rectangle {
+ constructor(height, width) {
+ this.height = height;
+ this.width = width;
+ }
+}
+`,
+ test(func, args) {
+ return func(this.title, args);
+ }
+ }
+ ];
+
+ let results = [];
+ let failed = false;
+ for (let i in tests) {
+ if (tests.hasOwnProperty(i)) {
+ let test = tests[i];
+ if (!failed) {
+ const logs = [];
+ args.log = value => {
+ logs.push(value);
+ };
+ let pass = test.test(findDebugger, args);
+ results.push({
+ shouldPass: test.shouldPass,
+ title: test.title,
+ pass: pass
+ });
+ if (!pass) {
+ failed = true;
+ logs.map(log);
+ }
+ } else {
+ results.push({
+ shouldPass: test.shouldPass,
+ title: test.title,
+ pass: false
+ });
+ }
+ }
+ }
+
+ callback(results);
+}
+
+/**
+
+ return code
+ .replace(/\/\/.*|'.*?[^\\]'|".*"|`[\s\S]+`/)
+ .match(/\bdebugger\b/)
+ */
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/hint.js b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/hint.js
new file mode 100644
index 000000000..229c8472a
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/hint.js
@@ -0,0 +1,16 @@
+debugger;
+
+function hello() {
+ debugger;
+}
+
+// There
+function hello3() {
+ return 'debugger in a string';
+}
+
+// There is no debugger
+function hello2() {}
+
+// there's no debugger
+function hello3() {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/remove-debugger.solved.ts b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/remove-debugger.solved.ts
new file mode 100644
index 000000000..93a7ae76c
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/remove-debugger.solved.ts
@@ -0,0 +1,14 @@
+function removeDebuggerSolved(
+ code,
+ { babylon, babelTraverse, babelGenerator, log }
+) {
+ const ast = babylon.parse(code);
+
+ babelTraverse(ast, {
+ DebuggerStatement: node => {
+ node.remove();
+ }
+ });
+
+ return babelGenerator(ast).code;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/remove-debugger.test.js b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/remove-debugger.test.js
new file mode 100644
index 000000000..7efd5f044
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/remove-debugger.test.js
@@ -0,0 +1,108 @@
+function testThings(findDebugger, callback, args) {
+ const log = args.log;
+ const tests = [
+ {
+ title: `debugger`,
+ test(func, args) {
+ return '' === func(this.title, args);
+ }
+ },
+ {
+ title: `debuggerStart();`,
+ test(func, args) {
+ return this.title === func(this.title, args);
+ }
+ },
+ {
+ title: `//debugger
+console.log('hi');`,
+ test(func, args) {
+ return this.title === func(this.title, args);
+ }
+ },
+ {
+ title: `'debugger';`,
+ test(func, args) {
+ return this.title === func(this.title, args);
+ }
+ },
+ {
+ title: `'hi'; debugger; 'bye';`,
+ test(func, args) {
+ return (
+ `'hi';
+'bye';` === func(this.title, args)
+ );
+ }
+ },
+ {
+ title: `'Fake //'; debugger; `,
+ test(func, args) {
+ return `'Fake //';` === func(this.title, args);
+ }
+ },
+ {
+ title: `"debugger";`,
+ test(func, args) {
+ return this.title === func(this.title, args);
+ }
+ },
+ {
+ title: `\`
+ debugger\`;`,
+ test(func, args) {
+ return this.title === func(this.title, args);
+ }
+ },
+ {
+ title: `' \\' debugger';`,
+ test(func, args) {
+ return this.title === func(this.title, args);
+ }
+ },
+ {
+ title: `/* \`
+ */ debugger; \`
+ \` + '';`,
+ test(func, args) {
+ return !func(this.title, args).includes('debugger');
+ }
+ },
+ {
+ title: `function hello(){ debugger; }`,
+ test(func, args) {
+ return `function hello() {}` === func(this.title, args);
+ }
+ }
+ ];
+
+ let results = [];
+ let failed = false;
+ for (let i in tests) {
+ if (tests.hasOwnProperty(i)) {
+ let test = tests[i];
+ if (!failed) {
+ const logs = [];
+ args.log = value => {
+ logs.push(value);
+ };
+ let pass = test.test(findDebugger, args);
+ results.push({ title: test.title, pass: pass });
+ if (!pass) {
+ failed = true;
+ logs.map(log);
+ }
+ } else {
+ results.push({ title: test.title, pass: false });
+ }
+ }
+ }
+
+ callback(results);
+}
+/**
+
+ return code
+ .replace(/\/\/.*|'.*?[^\\]'|".*"|`[\s\S]+`/)
+ .match(/\bdebugger\b/)
+ */
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/remove-debugger.ts b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/remove-debugger.ts
new file mode 100644
index 000000000..0fc4a1c22
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/remove-debugger.ts
@@ -0,0 +1,12 @@
+function removeDebugger(code, { babylon, babelTraverse, babelGenerator, log }) {
+ const ast = babylon.parse(code);
+
+ let hasDebugger = false;
+ babelTraverse(ast, {
+ DebuggerStatement: node => {
+ hasDebugger = true;
+ }
+ });
+
+ return hasDebugger;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/traverse-debugger-babel.solved.ts b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/traverse-debugger-babel.solved.ts
new file mode 100644
index 000000000..78202c878
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/traverse-debugger-babel.solved.ts
@@ -0,0 +1,11 @@
+function traverseDebuggerSolved(code, { babylon, babelTraverse, log }) {
+ const ast = babylon.parse(code);
+
+ let hasCode = false;
+ babelTraverse(ast, {
+ DebuggerStatement: () => {
+ hasCode = true;
+ }
+ });
+ return hasCode;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/traverse-debugger-babel.ts b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/traverse-debugger-babel.ts
new file mode 100644
index 000000000..4155142f2
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-debugger/traverse-debugger-babel.ts
@@ -0,0 +1,3 @@
+function traverseDebugger(code, { babylon, babelTraverse, log }) {
+ const ast = babylon.parse(code);
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-fit/find-fit.js b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-fit/find-fit.js
new file mode 100644
index 000000000..78ec47ec0
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-fit/find-fit.js
@@ -0,0 +1,7 @@
+function findFit(code, { babylon, babelTraverse, babelGenerator, log }) {
+ const ast = babylon.parse(code);
+
+ babelTraverse(ast);
+
+ return babelGenerator(ast).code;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-fit/find-fit.solved.js b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-fit/find-fit.solved.js
new file mode 100644
index 000000000..d05dab356
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-fit/find-fit.solved.js
@@ -0,0 +1,13 @@
+function findFit(code, { babylon, babelTraverse, babelGenerator, log }) {
+ const ast = babylon.parse(code);
+
+ babelTraverse(ast, {
+ Identifier: ({ node, parentPath }) => {
+ if (node.name === 'fit' && parentPath.isCallExpression()) {
+ node.name = 'it';
+ }
+ }
+ });
+
+ return babelGenerator(ast).code;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-fit/find-fit.test.js b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-fit/find-fit.test.js
new file mode 100644
index 000000000..fba045364
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/find-fit/find-fit.test.js
@@ -0,0 +1,63 @@
+function testThings(findDebugger, callback, args) {
+ const log = args.log;
+ const tests = [
+ {
+ title: `describe('test', ()=>{
+ fit('test', ()=>{
+ expect(true).toBe(true);
+ })
+})`,
+ test(func, args) {
+ let result = func(this.title, args);
+ return result && result.includes && !result.includes('fit');
+ }
+ },
+ {
+ title: `describe('test', ()=>{
+ fit('fits?', ()=>{
+ let fit = true;
+ expect(fit).toBe(true);
+ })
+})`,
+ test(func, args) {
+ let result = func(this.title, args);
+ return (
+ result &&
+ result.includes &&
+ !result.includes('fit(') &&
+ result.includes('let fit')
+ );
+ }
+ }
+ ];
+
+ let results = [];
+ let failed = false;
+ for (let i in tests) {
+ if (tests.hasOwnProperty(i)) {
+ let test = tests[i];
+ if (!failed) {
+ const logs = [];
+ args.log = value => {
+ logs.push(value);
+ };
+ let pass = test.test(findDebugger, args);
+ results.push({ title: test.title, pass: pass });
+ if (!pass) {
+ failed = true;
+ logs.map(log);
+ }
+ } else {
+ results.push({ title: test.title, pass: false });
+ }
+ }
+ }
+
+ callback(results);
+}
+/**
+
+ return code
+ .replace(/\/\/.*|'.*?[^\\]'|".*"|`[\s\S]+`/)
+ .match(/\bdebugger\b/)
+ */
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/hello-world.json b/codelab-master/apps/kirjs/src/app/modules/ast/samples/hello-world.json
new file mode 100644
index 000000000..65f9ffaae
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/hello-world.json
@@ -0,0 +1,106 @@
+{
+ "type": "File",
+ "start": 0,
+ "end": 8,
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 0
+ },
+ "end": {
+ "line": 1,
+ "column": 8
+ }
+ },
+ "program": {
+ "type": "Program",
+ "start": 0,
+ "end": 8,
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 0
+ },
+ "end": {
+ "line": 1,
+ "column": 8
+ }
+ },
+ "sourceType": "script",
+ "body": [
+ {
+ "type": "DebuggerStatement",
+ "start": 0,
+ "end": 8,
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 0
+ },
+ "end": {
+ "line": 1,
+ "column": 8
+ }
+ }
+ }
+ ],
+ "directives": []
+ },
+ "comments": [],
+ "tokens": [
+ {
+ "type": {
+ "label": "debugger",
+ "keyword": "debugger",
+ "beforeExpr": false,
+ "startsExpr": false,
+ "rightAssociative": false,
+ "isLoop": false,
+ "isAssign": false,
+ "prefix": false,
+ "postfix": false,
+ "binop": null,
+ "updateContext": null
+ },
+ "value": "debugger",
+ "start": 0,
+ "end": 8,
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 0
+ },
+ "end": {
+ "line": 1,
+ "column": 8
+ }
+ }
+ },
+ {
+ "type": {
+ "label": "eof",
+ "beforeExpr": false,
+ "startsExpr": false,
+ "rightAssociative": false,
+ "isLoop": false,
+ "isAssign": false,
+ "prefix": false,
+ "postfix": false,
+ "binop": null,
+ "updateContext": null
+ },
+ "start": 8,
+ "end": 8,
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 8
+ },
+ "end": {
+ "line": 1,
+ "column": 8
+ }
+ }
+ }
+ ]
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/it-lines/it-lines.js b/codelab-master/apps/kirjs/src/app/modules/ast/samples/it-lines/it-lines.js
new file mode 100644
index 000000000..462a19ff0
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/it-lines/it-lines.js
@@ -0,0 +1,17 @@
+function addItByLine(
+ code,
+ line,
+ { babylon, babelTraverse, babelGenerator, log }
+) {
+ const ast = babylon.parse(code);
+
+ babelTraverse(ast, {
+ Identifier: ({ node, parentPath }) => {
+ if (node.name === 'fit' && parentPath.isCallExpression()) {
+ node.name = 'it';
+ }
+ }
+ });
+
+ return babelGenerator(ast).code;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/it-lines/it-lines.solved.js b/codelab-master/apps/kirjs/src/app/modules/ast/samples/it-lines/it-lines.solved.js
new file mode 100644
index 000000000..6b439bce0
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/it-lines/it-lines.solved.js
@@ -0,0 +1,19 @@
+function addItByLine(
+ code,
+ line,
+ { babylon, babelTraverse, babelGenerator, log }
+) {
+ const ast = babylon.parse(code);
+
+ babelTraverse(ast, {
+ Identifier: ({ node, parentPath }) => {
+ if (node.name === 'it' && parentPath.isCallExpression()) {
+ if (node.loc.start.line === line) {
+ node.name = 'fit';
+ }
+ }
+ }
+ });
+
+ return babelGenerator(ast).code;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/it-lines/it-lines.test.js b/codelab-master/apps/kirjs/src/app/modules/ast/samples/it-lines/it-lines.test.js
new file mode 100644
index 000000000..b33c37dd4
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/it-lines/it-lines.test.js
@@ -0,0 +1,60 @@
+function testThings(findDebugger, callback, args) {
+ const log = args.log;
+ const tests = [
+ {
+ title: `// Line 3
+describe('test', ()=>{
+it('test', ()=>{
+ expect(true).toBe(true);
+ })
+})`,
+ test(func, args) {
+ let result = func(this.title, 3, args);
+ return result && result.includes && result.includes('fit');
+ }
+ },
+
+ {
+ title: `// Line 22
+describe('test', ()=>{
+ it('test', ()=>{
+ expect(true).toBe(true);
+ })
+})`,
+ test(func, args) {
+ let result = func(this.title, 1, args);
+ return result && result.includes && !result.includes('fit');
+ }
+ }
+ ];
+
+ let results = [];
+ let failed = false;
+ for (let i in tests) {
+ if (tests.hasOwnProperty(i)) {
+ let test = tests[i];
+ if (!failed) {
+ const logs = [];
+ args.log = value => {
+ logs.push(value);
+ };
+ let pass = test.test(findDebugger, args);
+ results.push({ title: test.title, pass: pass });
+ if (!pass) {
+ failed = true;
+ logs.map(log);
+ }
+ } else {
+ results.push({ title: test.title, pass: false });
+ }
+ }
+ }
+
+ callback(results);
+}
+/**
+
+ return code
+ .replace(/\/\/.*|'.*?[^\\]'|".*"|`[\s\S]+`/)
+ .match(/\bdebugger\b/)
+ */
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/samples/tricky.js b/codelab-master/apps/kirjs/src/app/modules/ast/samples/tricky.js
new file mode 100644
index 000000000..74fead46e
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/samples/tricky.js
@@ -0,0 +1,47 @@
+debugger;
+debuggerStart();
+//debugger
+console.log('hi');
+console.log('debugger');
+`'hi'; debugger; 'bye'`;
+let x = 'Fake //';
+('debugger');
+`
+ debugger\`
+ ' \\' debugger'
+ `;
+/* \`
+ */
+debugger;
+`
+ \` + ''`;
+function hello() {
+ debugger;
+}
+
+console.log(
+ 1,
+ function hello() {
+ console.log(function hi() {
+ console.log(123);
+ });
+ },
+ 3,
+ 4,
+ 5,
+ 6
+);
+
+call(1, 2, 3, 4, 5, 5);
+describe('test', () => {
+ fit('test', () => {
+ expect(true).toBe(true);
+ });
+});
+
+describe('test', () => {
+ fit('fits?', () => {
+ let fit = true;
+ expect(fit).toBe(true);
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/size-picker/size-picker.component.css b/codelab-master/apps/kirjs/src/app/modules/ast/size-picker/size-picker.component.css
new file mode 100644
index 000000000..7fa2398f1
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/size-picker/size-picker.component.css
@@ -0,0 +1,15 @@
+.button:hover {
+ background: #444444;
+ color: white;
+}
+
+.button {
+ border: 1px solid #000;
+ border-radius: 50%;
+ height: 1vw;
+ width: 1vw;
+ cursor: pointer;
+ display: inline-block;
+ text-align: center;
+ line-height: 1vw;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/size-picker/size-picker.component.html b/codelab-master/apps/kirjs/src/app/modules/ast/size-picker/size-picker.component.html
new file mode 100644
index 000000000..7062f7f02
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/size-picker/size-picker.component.html
@@ -0,0 +1,2 @@
+- {{ size }}
++
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/size-picker/size-picker.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/ast/size-picker/size-picker.component.spec.ts
new file mode 100644
index 000000000..ddcd865bd
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/size-picker/size-picker.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SizePickerComponent } from './size-picker.component';
+
+describe('SizePickerComponent', () => {
+ let component: SizePickerComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [SizePickerComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(SizePickerComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/size-picker/size-picker.component.ts b/codelab-master/apps/kirjs/src/app/modules/ast/size-picker/size-picker.component.ts
new file mode 100644
index 000000000..98dc3d672
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/size-picker/size-picker.component.ts
@@ -0,0 +1,12 @@
+import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-size-picker',
+ templateUrl: './size-picker.component.html',
+ styleUrls: ['./size-picker.component.css']
+})
+export class SizePickerComponent {
+ @Input() size = 28;
+ @Input() step = 2;
+ @Output() sizeChange = new EventEmitter();
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/size-picker/size-picker.module.ts b/codelab-master/apps/kirjs/src/app/modules/ast/size-picker/size-picker.module.ts
new file mode 100644
index 000000000..837e9bf6d
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/size-picker/size-picker.module.ts
@@ -0,0 +1,8 @@
+import { NgModule } from '@angular/core';
+import { SizePickerComponent } from './size-picker.component';
+
+@NgModule({
+ declarations: [SizePickerComponent],
+ exports: [SizePickerComponent]
+})
+export class SizePickerModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/test-set/babel-test-runner/babel-test-runner.component.css b/codelab-master/apps/kirjs/src/app/modules/ast/test-set/babel-test-runner/babel-test-runner.component.css
new file mode 100644
index 000000000..e93fc9dab
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/test-set/babel-test-runner/babel-test-runner.component.css
@@ -0,0 +1,108 @@
+:host {
+ height: 100%;
+ display: flex;
+}
+
+.runner {
+ display: none;
+}
+
+.test {
+ margin-bottom: 5px;
+ background: #ff9a86;
+ padding: 5px 10px;
+ font-size: 3vw;
+}
+
+.test.pass {
+ background: #b2ff37;
+}
+
+.mini {
+ font-size: 30%;
+ display: block;
+}
+
+pre {
+ margin: 0;
+}
+
+.test.future.future {
+ background: #e8e8e8;
+ color: #ddd;
+}
+
+.wrapper {
+ display: flex;
+ height: 100%;
+}
+
+.test-point:hover {
+ border: 3px black solid;
+}
+
+.test-point {
+ width: 32px;
+ height: 32px;
+ border-radius: 50%;
+ display: inline-block;
+ margin-left: 5px;
+ background: #999999;
+}
+
+.test-point.pass {
+ background: #b2ff37;
+ border: 1px solid #444444;
+}
+
+.test-point.current {
+ background: #ff9a86;
+ border: 1px solid #444444;
+}
+
+code.failing {
+ color: #ff4e3d;
+}
+
+code {
+ font-size: 3vw;
+ margin-top: 4px;
+ display: block;
+ margin-bottom: 24px;
+}
+
+mat-card {
+ width: 100%;
+ height: 100%;
+}
+
+.label {
+ color: #444;
+ font-size: 1.5vw;
+}
+
+.summary .label {
+ margin-bottom: 12px;
+}
+
+.summary {
+ padding-bottom: 24px;
+}
+
+.results {
+ padding-top: 24px;
+}
+
+.ast-full {
+ background: #ffffff;
+ position: fixed;
+ left: 0;
+ top: 0;
+ width: 100vw;
+ height: 100vh;
+ padding: 20px;
+}
+
+kirjs-size-picker {
+ margin-left: 20px;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/test-set/babel-test-runner/babel-test-runner.component.html b/codelab-master/apps/kirjs/src/app/modules/ast/test-set/babel-test-runner/babel-test-runner.component.html
new file mode 100644
index 000000000..fc14e462e
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/test-set/babel-test-runner/babel-test-runner.component.html
@@ -0,0 +1,63 @@
+
+
+
+
+
Running {{ tests.length }} tests.
+
+
firstFailingIndex()"
+ (mouseenter)="displayedTest = test"
+ (mouseout)="displayedTest = null"
+ >
+
+
+
+
+
+ For the code:
+ {{ test.error }}
+
+
+ For the code:
+ {{test.code.trim()}}
+ Expected:
+ {{ test.expected | json }}
+ Actual:
+ {{ test.result | json }}
+
+
+ AST:
+
+
+
+
+
+
╳
+
{{test.code.trim()}}
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/test-set/babel-test-runner/babel-test-runner.component.ts b/codelab-master/apps/kirjs/src/app/modules/ast/test-set/babel-test-runner/babel-test-runner.component.ts
new file mode 100644
index 000000000..20ebbcbdb
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/test-set/babel-test-runner/babel-test-runner.component.ts
@@ -0,0 +1,65 @@
+import { Component, Input } from '@angular/core';
+
+import * as babylon from 'babylon';
+import * as types from 'babel-types';
+import babelTraverse from '@babel/traverse';
+import babelGenerator from '@babel/generator';
+import { TestInfo } from '../../../../../../../codelab/src/app/shared/interfaces/test-info';
+
+declare const require;
+
+@Component({
+ selector: 'kirjs-babel-test-runner',
+ templateUrl: './babel-test-runner.component.html',
+ styleUrls: ['./babel-test-runner.component.css']
+})
+export class BabelTestRunnerComponent {
+ tests: Array = [];
+ logs = [];
+ @Input() files: any[];
+ @Input() showAst = false;
+ scale = 10;
+ showFull = false;
+ firstFailing: TestInfo;
+ displayedTest: TestInfo;
+
+ run(files: Array) {
+ this.logs = [];
+ const args = {
+ babylon,
+ babelTraverse,
+ babelGenerator,
+ types,
+ log: value => {
+ this.logs.push(value);
+ }
+ };
+ const callback = result => {
+ if (result) {
+ this.tests = result;
+ this.firstFailing = this.tests.find(test => !test.pass);
+ }
+ };
+
+ try {
+ // tslint:disable
+ const func = eval('(' + files[0].code + ')');
+ eval('(' + files[1].code + ')')(func, callback, args);
+ } catch (e) {
+ console.log(e);
+ }
+ }
+
+ firstFailingIndex() {
+ const firstFailing = this.tests.findIndex(i => !i.pass);
+ return firstFailing === -1 ? this.tests.length : firstFailing;
+ }
+
+ runTests() {
+ this.run(this.files);
+ }
+
+ ngOnInit() {
+ this.runTests();
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/test-set/test-set.component.css b/codelab-master/apps/kirjs/src/app/modules/ast/test-set/test-set.component.css
new file mode 100644
index 000000000..d95409b52
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/test-set/test-set.component.css
@@ -0,0 +1,7 @@
+.show-solution .icon {
+ visibility: hidden;
+}
+
+.show-solution:hover .icon {
+ visibility: visible;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/test-set/test-set.component.html b/codelab-master/apps/kirjs/src/app/modules/ast/test-set/test-set.component.html
new file mode 100644
index 000000000..c32d4850f
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/test-set/test-set.component.html
@@ -0,0 +1,24 @@
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/test-set/test-set.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/ast/test-set/test-set.component.spec.ts
new file mode 100644
index 000000000..351a64f31
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/test-set/test-set.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { TestSetComponent } from './test-set.component';
+
+describe('TestSetComponent', () => {
+ let component: TestSetComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [TestSetComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(TestSetComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/ast/test-set/test-set.component.ts b/codelab-master/apps/kirjs/src/app/modules/ast/test-set/test-set.component.ts
new file mode 100644
index 000000000..925521f0f
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/ast/test-set/test-set.component.ts
@@ -0,0 +1,12 @@
+import { Component, Input } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-test-set',
+ templateUrl: './test-set.component.html',
+ styleUrls: ['./test-set.component.css']
+})
+export class TestSetComponent {
+ @Input() files = [];
+ @Input() fontSize = 30;
+ @Input() showAst = false;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/angular-flags/angular-flags.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/angular-flags/angular-flags.component.css
new file mode 100644
index 000000000..e677e7f37
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/angular-flags/angular-flags.component.css
@@ -0,0 +1,4 @@
+.flags {
+ font-size: 2vw;
+ white-space: pre-wrap;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/angular-flags/angular-flags.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/angular-flags/angular-flags.component.html
new file mode 100644
index 000000000..e2969f501
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/angular-flags/angular-flags.component.html
@@ -0,0 +1,16 @@
+
+
+
+
+ {{ flag.name }} = {{ flag.value }}
+
+
+
+
{{ number }}
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/angular-flags/angular-flags.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/angular-flags/angular-flags.component.spec.ts
new file mode 100644
index 000000000..734e2aa64
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/angular-flags/angular-flags.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { AngularFlagsComponent } from './angular-flags.component';
+
+describe('AngularFlagsComponent', () => {
+ let component: AngularFlagsComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [AngularFlagsComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(AngularFlagsComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/angular-flags/angular-flags.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/angular-flags/angular-flags.component.ts
new file mode 100644
index 000000000..0d5b564c3
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/angular-flags/angular-flags.component.ts
@@ -0,0 +1,67 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-angular-flags',
+ templateUrl: './angular-flags.component.html',
+ styleUrls: ['./angular-flags.component.css']
+})
+export class AngularFlagsComponent implements OnInit {
+ number = 124;
+ flags = [
+ { checked: false, name: 'None', value: 0 },
+ { checked: false, name: 'TypeElement', value: 1 },
+ { checked: false, name: 'TypeText', value: 2 },
+ { checked: false, name: 'ProjectedTemplate', value: 4 },
+ { checked: false, name: 'CatRenderNode', value: 3 },
+ { checked: false, name: 'TypeNgContent', value: 8 },
+ { checked: false, name: 'TypePipe', value: 16 },
+ { checked: false, name: 'TypePureArray', value: 32 },
+ { checked: false, name: 'TypePureObject', value: 64 },
+ { checked: false, name: 'TypePurePipe', value: 128 },
+ { checked: false, name: 'CatPureExpression', value: 224 },
+ { checked: false, name: 'TypeValueProvider', value: 256 },
+ { checked: false, name: 'TypeClassProvider', value: 512 },
+ { checked: false, name: 'TypeFactoryProvider', value: 1024 },
+ { checked: false, name: 'TypeUseExistingProvider', value: 2048 },
+ { checked: false, name: 'LazyProvider', value: 4096 },
+ { checked: false, name: 'PrivateProvider', value: 8192 },
+ { checked: false, name: 'TypeDirective', value: 16384 },
+ { checked: false, name: 'Component', value: 32768 },
+ { checked: false, name: 'CatProviderNoDirective', value: 3840 },
+ { checked: false, name: 'CatProvider', value: 20224 },
+ { checked: false, name: 'OnInit', value: 65536 },
+ { checked: false, name: 'OnDestroy', value: 131072 },
+ { checked: false, name: 'DoCheck', value: 262144 },
+ { checked: false, name: 'OnChanges', value: 524288 },
+ { checked: false, name: 'AfterContentInit', value: 1048576 },
+ { checked: false, name: 'AfterContentChecked', value: 2097152 },
+ { checked: false, name: 'AfterViewInit', value: 4194304 },
+ { checked: false, name: 'AfterViewChecked', value: 8388608 },
+ { checked: false, name: 'EmbeddedViews', value: 16777216 },
+ { checked: false, name: 'ComponentView', value: 33554432 },
+ { checked: false, name: 'TypeContentQuery', value: 67108864 },
+ { checked: false, name: 'TypeViewQuery', value: 134217728 },
+ { checked: false, name: 'StaticQuery', value: 268435456 },
+ { checked: false, name: 'DynamicQuery', value: 536870912 },
+ { checked: false, name: 'TypeModuleProvider', value: 1073741824 },
+ { checked: false, name: 'CatQuery', value: 201326592 },
+ { checked: false, name: 'Types', value: 201347067 }
+ ];
+
+ checked: string[];
+
+ constructor() {
+ this.syncCheckBoxes();
+ }
+
+ syncCheckBoxes() {
+ this.flags.forEach(f => (f.checked = !!(this.number & f.value)));
+ }
+
+ ngOnInit() {}
+
+ handleClick(checked: boolean, value: number) {
+ this.number = this.number | value;
+ this.syncCheckBoxes();
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/ascii/ascii.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/ascii/ascii.component.css
new file mode 100644
index 000000000..64b4f3740
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/ascii/ascii.component.css
@@ -0,0 +1,29 @@
+.parent {
+ display: grid;
+ grid-template-columns: repeat(12, 1fr);
+}
+
+.item {
+ background: #fff;
+ border-right: 1px #444 dotted;
+ border-bottom: 1px #444 dotted;
+ padding: 0.5vw;
+ display: flex;
+ justify-content: space-between;
+}
+
+.key {
+ vertical-align: top;
+ font-size: 2vw;
+ color: #666;
+}
+
+.value {
+ font-size: 3.5vw;
+}
+
+select {
+ border: 1px #444 solid;
+ background: #ffffff;
+ font-size: 3vw;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/ascii/ascii.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/ascii/ascii.component.html
new file mode 100644
index 000000000..d750df2aa
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/ascii/ascii.component.html
@@ -0,0 +1,15 @@
+
+ Display character table for:
+
+ {{ e.key }}
+
+
+
+
+
+
+ {{ item.key }}
+ {{ item.value }}
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/ascii/ascii.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/ascii/ascii.component.spec.ts
new file mode 100644
index 000000000..183cb2bbb
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/ascii/ascii.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { AsciiComponent } from './ascii.component';
+
+describe('AsciiComponent', () => {
+ let component: AsciiComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [AsciiComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(AsciiComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/ascii/ascii.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/ascii/ascii.component.ts
new file mode 100644
index 000000000..6071cc4e6
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/ascii/ascii.component.ts
@@ -0,0 +1,63 @@
+import {
+ Component,
+ Input,
+ OnChanges,
+ OnInit,
+ SimpleChanges
+} from '@angular/core';
+
+function encode(from: number, to: number, encoding: string) {
+ return new TextDecoder(encoding)
+ .decode(new Uint8Array(to - from).map((a, i) => i + from).buffer as any)
+ .split('')
+ .map((value, i) => ({
+ key: i + from,
+ value
+ }));
+}
+
+const layouts = {};
+
+@Component({
+ selector: 'kirjs-ascii',
+ templateUrl: './ascii.component.html',
+ styleUrls: ['./ascii.component.css']
+})
+export class AsciiComponent implements OnChanges {
+ @Input() param: string;
+
+ encodings = [
+ {
+ key: 'ascii',
+ value: encode(33, 128, 'ascii')
+ },
+ {
+ key: 'ascii - Page 2',
+ value: encode(128, 255, 'ascii')
+ },
+ {
+ key: 'windows-1251',
+ value: encode(128, 255, 'windows-1251')
+ },
+ {
+ key: 'KOI8-R',
+ value: encode(128, 255, 'KOI8-R')
+ },
+ {
+ key: 'utf-8',
+ value: encode(1000, 1255, 'utf-16')
+ }
+ ];
+
+ encoding = this.encodings[0];
+
+ constructor() {
+ // d = new TextDecoder('windows-125').decode(new Uint8Array(255).map((a,i)=>i).buffer)
+ }
+
+ ngOnChanges(changes: SimpleChanges): void {
+ if ('param' in changes) {
+ this.encoding = this.encodings.find(a => a.key === this.param);
+ }
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-flat/binary-flat.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/binary-flat/binary-flat.component.css
new file mode 100644
index 000000000..d62357f3f
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-flat/binary-flat.component.css
@@ -0,0 +1,52 @@
+.wrapper {
+ word-break: break-all;
+ padding: 40px;
+}
+
+.binary {
+ letter-spacing: 2vw;
+}
+
+.item,
+.detail-item {
+ font-size: 3vw;
+}
+
+.item-1 {
+ background: #eee;
+}
+
+.detail-item {
+ padding: 20px;
+}
+
+.detail {
+ width: 60%;
+ word-break: break-all;
+}
+
+.field-header {
+ font-size: 2vw;
+}
+
+.raw-value {
+ width: 40%;
+ font-size: 2vw;
+ word-break: break-all;
+ padding-right: 1vw;
+ margin-right: 1vw;
+ border-right: 1px #444 solid;
+}
+
+button {
+ display: block;
+ width: 100%;
+ background: #e51400;
+ color: #fff;
+ padding: 1vw;
+ font-size: 4vw;
+}
+
+h3 {
+ font-size: 2vw;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-flat/binary-flat.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/binary-flat/binary-flat.component.html
new file mode 100644
index 000000000..a2b2b3530
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-flat/binary-flat.component.html
@@ -0,0 +1,34 @@
+
+
+ {{
+ item.rawValue
+ }}
+ i"
+ class="detail-item item-{{ i % 2 }}"
+ style="display: flex"
+ >
+
+ {{ item.rawValue }}
+
+
+
+
{{ item.value }}
+
+
+
+ Next
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-flat/binary-flat.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-flat/binary-flat.component.spec.ts
new file mode 100644
index 000000000..ae4a24d1a
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-flat/binary-flat.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { BinaryFlatComponent } from './binary-flat.component';
+
+describe('BinaryFlatComponent', () => {
+ let component: BinaryFlatComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [BinaryFlatComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(BinaryFlatComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-flat/binary-flat.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-flat/binary-flat.component.ts
new file mode 100644
index 000000000..08683e974
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-flat/binary-flat.component.ts
@@ -0,0 +1,74 @@
+import {
+ Component,
+ EventEmitter,
+ Input,
+ OnChanges,
+ OnInit,
+ Output,
+ SimpleChanges
+} from '@angular/core';
+import { BinaryParser } from '../parser/binary-parser';
+import { StringBinaryReader } from '../parser/readers/string-reader';
+import { BinaryParentComponent } from '../binary-view/binary-parent/binary-parent.component';
+
+export function flatten(
+ structure: any[],
+ nesting = 0,
+ parent = null,
+ path = []
+) {
+ return structure.reduce((result, item) => {
+ if (item.type === 'object' || item.type === 'array') {
+ item.data = false;
+ item.nesting = nesting;
+ item.className = 'tbd';
+ result = result
+ .concat(item)
+ .concat(
+ flatten(
+ item.value,
+ nesting + 1,
+ item,
+ item.name ? [...path, item.name] : [...path]
+ )
+ );
+ } else {
+ item.data = true;
+ item.nesting = nesting;
+ item.parent = parent || item;
+ item.root = item.parent.root || item.parent;
+ item.path = path;
+ item.className = path.map(p => 'parent-' + p).join(' ');
+ result.push(item);
+ }
+ return result;
+ }, []);
+}
+
+@Component({
+ selector: 'kirjs-binary-flat',
+ templateUrl: './binary-flat.component.html',
+ styleUrls: ['./binary-flat.component.css']
+})
+export class BinaryFlatComponent implements OnChanges {
+ @Input() parser: BinaryParser;
+ @Input() binary: string;
+ @Output() updateBinary = new EventEmitter();
+
+ detailIndex = 30;
+ structure: { start: number };
+
+ constructor(private readonly root: BinaryParentComponent) {}
+
+ update(event, item) {
+ this.root.update(item, event.target.textContent);
+ }
+
+ ngOnChanges(changes: SimpleChanges): void {
+ if ('binary' in changes) {
+ this.structure = flatten(
+ this.parser.readOrdered(new StringBinaryReader(this.binary)).value
+ );
+ }
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-gif/binary-gif.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/binary-gif/binary-gif.component.css
new file mode 100644
index 000000000..43c1e1ee8
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-gif/binary-gif.component.css
@@ -0,0 +1,3 @@
+img {
+ image-rendering: pixelated !important;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-gif/binary-gif.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/binary-gif/binary-gif.component.html
new file mode 100644
index 000000000..92cca6b6e
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-gif/binary-gif.component.html
@@ -0,0 +1 @@
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-gif/binary-gif.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-gif/binary-gif.component.spec.ts
new file mode 100644
index 000000000..c76676306
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-gif/binary-gif.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { BinaryGifComponent } from './binary-gif.component';
+
+describe('BinaryGifComponent', () => {
+ let component: BinaryGifComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [BinaryGifComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(BinaryGifComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-gif/binary-gif.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-gif/binary-gif.component.ts
new file mode 100644
index 000000000..f5b069f02
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-gif/binary-gif.component.ts
@@ -0,0 +1,22 @@
+import { Component, Input } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-binary-gif',
+ templateUrl: './binary-gif.component.html',
+ styleUrls: ['./binary-gif.component.css']
+})
+export class BinaryGifComponent {
+ gif: string;
+
+ @Input()
+ set binary(binary: string) {
+ const binaries = binary.match(/.{8}/g);
+ const recombined = new Uint8Array(binaries.map(a => parseInt(a, 2)));
+ const b64encoded = btoa(
+ Array.from(recombined)
+ .map(a => String.fromCharCode(a))
+ .join('')
+ );
+ this.gif = 'data:image/gif;base64,' + b64encoded;
+ }
+}
diff --git a/libs/utils/src/lib/sync/components/sync-code-game/sync-code-game-viewer/sync-code-game-viewer.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/binary-inline/binary-display/binary-display.component.css
similarity index 100%
rename from libs/utils/src/lib/sync/components/sync-code-game/sync-code-game-viewer/sync-code-game-viewer.component.css
rename to codelab-master/apps/kirjs/src/app/modules/binary/binary-inline/binary-display/binary-display.component.css
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-inline/binary-display/binary-display.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/binary-inline/binary-display/binary-display.component.html
new file mode 100644
index 000000000..35a42b4c3
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-inline/binary-display/binary-display.component.html
@@ -0,0 +1 @@
+{{ bin }}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-inline/binary-display/binary-display.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-inline/binary-display/binary-display.component.spec.ts
new file mode 100644
index 000000000..f72403664
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-inline/binary-display/binary-display.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { BinaryDisplayComponent } from './binary-display.component';
+
+describe('BinaryDisplayComponent', () => {
+ let component: BinaryDisplayComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [BinaryDisplayComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(BinaryDisplayComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-inline/binary-display/binary-display.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-inline/binary-display/binary-display.component.ts
new file mode 100644
index 000000000..6751c487a
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-inline/binary-display/binary-display.component.ts
@@ -0,0 +1,14 @@
+import { Component, Input } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-binary-display',
+ templateUrl: './binary-display.component.html',
+ styleUrls: ['./binary-display.component.css']
+})
+export class BinaryDisplayComponent {
+ binaries = [];
+
+ @Input() set binary(binary: string) {
+ this.binaries = binary.match(/.{8}/g);
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-inline/binary-inline.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/binary-inline/binary-inline.component.css
new file mode 100644
index 000000000..2d546be1c
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-inline/binary-inline.component.css
@@ -0,0 +1,18 @@
+.wrapper {
+ display: grid;
+ grid-template-columns: 200px 100px 100%;
+ font-size: 20px;
+}
+
+.bin-block {
+ word-break: break-all;
+}
+
+[name='section-type'] {
+ font-size: 30px;
+ font-weight: 300;
+}
+
+.cell {
+ padding: 10px;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-inline/binary-inline.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/binary-inline/binary-inline.component.html
new file mode 100644
index 000000000..e6ae2574e
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-inline/binary-inline.component.html
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+ {{ item.displayValue || item.value }}
+
+
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-inline/binary-inline.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-inline/binary-inline.component.spec.ts
new file mode 100644
index 000000000..223e5f760
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-inline/binary-inline.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { BinaryInlineComponent } from './binary-inline.component';
+
+describe('BinaryInlineComponent', () => {
+ let component: BinaryInlineComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [BinaryInlineComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(BinaryInlineComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-inline/binary-inline.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-inline/binary-inline.component.ts
new file mode 100644
index 000000000..677a861c2
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-inline/binary-inline.component.ts
@@ -0,0 +1,29 @@
+import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
+import { flatten } from '../binary-flat/binary-flat.component';
+import { StringBinaryReader } from '../parser/readers/string-reader';
+import { BinaryParser } from '../parser/binary-parser';
+
+@Component({
+ selector: 'kirjs-binary-inline',
+ templateUrl: './binary-inline.component.html',
+ styleUrls: ['./binary-inline.component.css']
+})
+export class BinaryInlineComponent implements OnChanges {
+ @Input() filterClassName = /./;
+ @Input() parser: BinaryParser;
+ @Input() binary: string;
+
+ structure: any[];
+
+ ngOnChanges(changes: SimpleChanges): void {
+ if ('binary' in changes) {
+ try {
+ this.structure = flatten(
+ this.parser.readOrdered(new StringBinaryReader(this.binary)).value
+ ).filter(a => a.className.match(this.filterClassName));
+ } catch (e) {
+ console.log(e);
+ }
+ }
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-inline/binary-inline.module.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-inline/binary-inline.module.ts
new file mode 100644
index 000000000..2a25b56da
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-inline/binary-inline.module.ts
@@ -0,0 +1,11 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { BinaryInlineComponent } from './binary-inline.component';
+import { BinaryDisplayComponent } from './binary-display/binary-display.component';
+
+@NgModule({
+ declarations: [BinaryInlineComponent, BinaryDisplayComponent],
+ exports: [BinaryInlineComponent],
+ imports: [CommonModule]
+})
+export class BinaryInlineModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-parser-demo/binary-parser-demo.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/binary-parser-demo/binary-parser-demo.component.css
new file mode 100644
index 000000000..e5aad3dd0
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-parser-demo/binary-parser-demo.component.css
@@ -0,0 +1,13 @@
+.error::before {
+ color: #e51400;
+ content: '🙀';
+}
+
+.error {
+ color: #e51400;
+ border: 1px #e51400 solid;
+ border-radius: 12px;
+ font-size: 3vw;
+ padding: 2vw;
+ display: block;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-parser-demo/binary-parser-demo.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/binary-parser-demo/binary-parser-demo.component.html
new file mode 100644
index 000000000..e0bba82fb
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-parser-demo/binary-parser-demo.component.html
@@ -0,0 +1,47 @@
+
+
+
+
+ {{ error }}
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-parser-demo/binary-parser-demo.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-parser-demo/binary-parser-demo.component.spec.ts
new file mode 100644
index 000000000..7b81e1888
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-parser-demo/binary-parser-demo.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { BinaryParserDemoComponent } from './binary-parser-demo.component';
+
+describe('BinaryParserDemoComponent', () => {
+ let component: BinaryParserDemoComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [BinaryParserDemoComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(BinaryParserDemoComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-parser-demo/binary-parser-demo.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-parser-demo/binary-parser-demo.component.ts
new file mode 100644
index 000000000..76b3b3204
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-parser-demo/binary-parser-demo.component.ts
@@ -0,0 +1,47 @@
+import { Component, EventEmitter, Input, OnInit } from '@angular/core';
+import { Parser } from 'binary-parser';
+import { Buffer } from 'buffer';
+import { bin2hex } from '../shared';
+
+(window as any).Buffer = Buffer;
+
+@Component({
+ selector: 'kirjs-binary-parser-demo',
+ templateUrl: './binary-parser-demo.component.html',
+ styleUrls: ['./binary-parser-demo.component.css']
+})
+export class BinaryParserDemoComponent implements OnInit {
+ @Input() helpers;
+ code = '';
+
+ @Input() filterClassName = /./;
+ result = '';
+ @Input() binary = '';
+ error = '';
+ onCodeChange = new EventEmitter();
+
+ constructor() {}
+
+ ngOnInit() {
+ this.code = this.helpers[0];
+ this.generateCode();
+ }
+
+ generateCode() {
+ this.onCodeChange.emit(this.code);
+ this.error = '';
+ try {
+ const parser = new Function(
+ 'Parser',
+ 'const parser = ' + this.code + '; return parser;'
+ )(Parser);
+ this.result = JSON.stringify(
+ parser.parse(Buffer.from(bin2hex(this.binary), 'hex')),
+ null,
+ ' '
+ );
+ } catch (e) {
+ this.error = e.message;
+ }
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-plain/binary-plain.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/binary-plain/binary-plain.component.css
new file mode 100644
index 000000000..fb81b4b57
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-plain/binary-plain.component.css
@@ -0,0 +1,137 @@
+.wrapper {
+ display: flex;
+ flex-direction: column;
+}
+
+button {
+ font-size: inherit;
+}
+
+.legend {
+ width: 200px;
+ font-size: 2vw;
+ padding: 3vw 0;
+ display: flex;
+}
+
+.legend .item {
+ margin-right: 10px;
+ background: #dddddd;
+ border-radius: 4px;
+ padding: 0.5vw 1vw;
+}
+
+.enums .enums {
+ background: #ff3302;
+ color: black;
+}
+
+.string .string {
+ background: #ffaf00;
+ color: black;
+}
+
+.const .const {
+ background: #aaaaaa;
+ color: black;
+}
+
+.number .number {
+ background: #00ff51;
+ color: black;
+}
+
+.hex .color,
+.hex .hex {
+ background: #00a4ff;
+ color: black;
+}
+
+.boolean .boolean {
+ background: #f600ff;
+ color: black;
+}
+
+.binary {
+ white-space: normal;
+ font-size: 3vw;
+ word-break: break-all;
+ padding-right: 3vw;
+}
+
+.spacing .binary {
+ display: flex;
+ flex-wrap: wrap;
+}
+
+.spacing .bin-block {
+ margin-right: 4vw;
+ white-space: nowrap;
+}
+
+.groups .parent-palette {
+ background: #00ff51;
+}
+
+.groups .parent-header {
+ background: #ffaf00;
+}
+
+.groups .parent-extensions {
+ background: #00a4ff;
+}
+
+.spacing {
+ line-height: 50px;
+}
+
+.mini .legend {
+ font-size: 1.2vw;
+ padding: 0;
+}
+
+.mini .legend .item {
+ padding: 0.2vw;
+ height: 2vw;
+}
+
+.mini input[type='checkbox'] {
+ zoom: 2 !important;
+}
+
+.mini .spacing {
+ line-height: 2vw;
+}
+
+.item-header:first-child {
+ margin-top: 0;
+}
+
+.item-header {
+ width: 100%;
+ font-size: 5vw;
+ display: block;
+ margin-bottom: 2vw;
+ margin-top: 4vw;
+}
+
+.selected {
+ width: 100%;
+ border: 1px #ddd solid;
+ padding: 1vw;
+}
+
+.label {
+ display: inline-block;
+ width: 24vw;
+ flex-shrink: 0;
+}
+
+.meta {
+ margin-top: 2vw;
+ margin-bottom: 1vw;
+}
+
+.selected .bin-block {
+ font-size: 4vw;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-plain/binary-plain.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/binary-plain/binary-plain.component.html
new file mode 100644
index 000000000..a4d77bf68
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-plain/binary-plain.component.html
@@ -0,0 +1,85 @@
+
+
+
+
+ {{ type }}
+
+
+ Spacing
+
+
+
+
+
+
+
+ {{ item.rawValue }}
+
+
+ - {{ hackHack[item.value] }}
+
+
+
+
+
+ {{ item.rawValue }}
+
+
+ ×
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-plain/binary-plain.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-plain/binary-plain.component.spec.ts
new file mode 100644
index 000000000..4d6adf4bd
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-plain/binary-plain.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { BinaryPlainComponent } from './binary-plain.component';
+
+describe('BinaryPlainComponent', () => {
+ let component: BinaryPlainComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [BinaryPlainComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(BinaryPlainComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-plain/binary-plain.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-plain/binary-plain.component.ts
new file mode 100644
index 000000000..2c5ae0f6a
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-plain/binary-plain.component.ts
@@ -0,0 +1,66 @@
+import {
+ Component,
+ EventEmitter,
+ Input,
+ OnChanges,
+ Output
+} from '@angular/core';
+import { BinaryParser } from '../parser/binary-parser';
+import { StringBinaryReader } from '../parser/readers/string-reader';
+import { flatten } from '../binary-flat/binary-flat.component';
+
+@Component({
+ selector: 'kirjs-binary-plain',
+ templateUrl: './binary-plain.component.html',
+ styleUrls: ['./binary-plain.component.css']
+})
+export class BinaryPlainComponent implements OnChanges {
+ @Output() updateChunk = new EventEmitter();
+ @Input() parser: BinaryParser;
+ @Input() highlightGroups = false;
+ @Input() filterClassName = /./;
+ @Input() mini = false;
+ @Input() showPopups = false;
+ hackHack = {
+ 0x01: 'Types',
+ 0x02: 'Import',
+ 0x03: 'Function',
+ 0x05: 'Table',
+ 0x07: 'Export',
+ 0x08: 'Start',
+ 0x0a: 'Code'
+ };
+ show = [];
+ types = ['boolean', 'number', 'hex', 'string', 'const', 'enums'];
+ @Input()
+ spacing = false;
+ @Input()
+ highlightedMap = this.types.reduce((r, v) => {
+ r[v] = false;
+ return r;
+ }, {});
+ structure: any[];
+ @Input() binary: string;
+
+ get highlighted() {
+ return Object.keys(this.highlightedMap)
+ .filter(key => this.highlightedMap[key])
+ .join(' ');
+ }
+
+ ngOnChanges() {
+ if (this.binary && this.parser) {
+ try {
+ this.structure = flatten(
+ this.parser.readOrdered(new StringBinaryReader(this.binary)).value
+ ).filter(a => a.className.match(this.filterClassName));
+ } catch (e) {
+ console.log(e);
+ }
+ }
+ }
+
+ update(chunk: any, value: any) {
+ this.updateChunk.emit({ chunk, value });
+ }
+}
diff --git a/libs/utils/src/lib/sync/components/sync-join-instructions/sync-join-instructions.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/array/array.component.css
similarity index 100%
rename from libs/utils/src/lib/sync/components/sync-join-instructions/sync-join-instructions.component.css
rename to codelab-master/apps/kirjs/src/app/modules/binary/binary-view/array/array.component.css
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/array/array.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/array/array.component.html
new file mode 100644
index 000000000..b316b2874
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/array/array.component.html
@@ -0,0 +1,12 @@
+
+ {{ item.name }}
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/array/array.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/array/array.component.spec.ts
new file mode 100644
index 000000000..561912d8c
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/array/array.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ArrayComponent } from './array.component';
+
+describe('ArrayComponent', () => {
+ let component: ArrayComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ArrayComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ArrayComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/array/array.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/array/array.component.ts
new file mode 100644
index 000000000..e1cc8cf03
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/array/array.component.ts
@@ -0,0 +1,19 @@
+import { Component, Input, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-array',
+ templateUrl: './array.component.html',
+ styleUrls: ['./array.component.css']
+})
+export class ArrayComponent implements OnInit {
+ @Input() data;
+ @Input() showMeta: boolean;
+
+ constructor() {}
+
+ trackBy(i, data) {
+ return data.index;
+ }
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/binary-parent/binary-parent.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/binary-parent/binary-parent.component.html
new file mode 100644
index 000000000..cba26fba1
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/binary-parent/binary-parent.component.html
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/binary-parent/binary-parent.component.scss b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/binary-parent/binary-parent.component.scss
new file mode 100644
index 000000000..54c57c268
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/binary-parent/binary-parent.component.scss
@@ -0,0 +1,29 @@
+:host ::ng-deep {
+ .block {
+ display: block;
+ font-size: 30px;
+ margin-left: 40px;
+ }
+
+ .name {
+ width: 200px;
+ }
+
+ kirjs-object .block > .name {
+ display: block;
+ }
+}
+
+.block {
+ margin-left: 0;
+ font-size: 40px;
+}
+
+:host ::ng-deep {
+ input {
+ background: transparent;
+ font-size: inherit;
+ border: 0 solid;
+ font-family: Monaco, 'Lucida Console', monospace;
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/binary-parent/binary-parent.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/binary-parent/binary-parent.component.spec.ts
new file mode 100644
index 000000000..e6fb903df
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/binary-parent/binary-parent.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { BinaryParentComponent } from './binary-parent.component';
+
+describe('BinaryParentComponent', () => {
+ let component: BinaryParentComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [BinaryParentComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(BinaryParentComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/binary-parent/binary-parent.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/binary-parent/binary-parent.component.ts
new file mode 100644
index 000000000..1d103dfc6
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/binary-parent/binary-parent.component.ts
@@ -0,0 +1,60 @@
+import {
+ Component,
+ EventEmitter,
+ Input,
+ OnChanges,
+ OnInit,
+ Output
+} from '@angular/core';
+import { BinaryParser } from '../../parser/binary-parser';
+import { StringBinaryReader } from '../../parser/readers/string-reader';
+
+@Component({
+ selector: 'kirjs-binary-parent',
+ templateUrl: './binary-parent.component.html',
+ styleUrls: ['./binary-parent.component.scss']
+})
+export class BinaryParentComponent implements OnInit, OnChanges {
+ @Input() showMeta = true;
+ @Input() parser: BinaryParser;
+ @Input() binary: string;
+ @Input() type = 'structure';
+ @Input() spacing = false;
+
+ @Output() updateBinary = new EventEmitter();
+ structure: any;
+
+ constructor() {}
+
+ ngOnInit() {
+ this.regenerate();
+ }
+
+ ngOnChanges() {
+ this.regenerate();
+ }
+
+ regenerate() {
+ this.structure = this.parser.readOrdered(
+ new StringBinaryReader(this.binary)
+ );
+ }
+
+ update(chunk, value) {
+ const len = chunk.end - chunk.start;
+ value = value.padEnd(len, 0).slice(0, len);
+ this.binary =
+ this.binary.slice(0, chunk.start) + value + this.binary.substr(chunk.end);
+ this.updateBinary.emit(this.binary);
+ this.regenerate();
+ }
+
+ updatePart(chunk, value) {
+ const len = chunk.end - chunk.start;
+ value = value.padEnd(len, 0).slice(0, len);
+
+ this.binary =
+ this.binary.slice(0, chunk.start) + value + this.binary.substr(chunk.end);
+ //
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/binary-view.module.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/binary-view.module.ts
new file mode 100644
index 000000000..3b01b25f0
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/binary-view.module.ts
@@ -0,0 +1,61 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { BlockComponent } from './block/block.component';
+import { ObjectComponent } from './object/object.component';
+import { BitsComponent } from './bits/bits.component';
+import { StringComponent } from './string/string.component';
+import { NumberComponent } from './number/number.component';
+import { ArrayComponent } from './array/array.component';
+import { ColorComponent } from './color/color.component';
+import { BinaryParentComponent } from './binary-parent/binary-parent.component';
+import { HexComponent } from './hex/hex.component';
+import { InlineComponent } from './inline/inline.component';
+import { InlineRootComponent } from './inline-root/inline-root.component';
+import { BinaryFlatComponent } from '../binary-flat/binary-flat.component';
+import { BinaryPlainComponent } from '../binary-plain/binary-plain.component';
+import { FormsModule } from '@angular/forms';
+
+@NgModule({
+ imports: [CommonModule, FormsModule],
+ declarations: [
+ BlockComponent,
+ ObjectComponent,
+ BitsComponent,
+ StringComponent,
+ NumberComponent,
+ ArrayComponent,
+ ColorComponent,
+ BinaryParentComponent,
+ BinaryFlatComponent,
+ HexComponent,
+ InlineComponent,
+ InlineRootComponent,
+ BinaryPlainComponent
+ ],
+ exports: [
+ BinaryFlatComponent,
+ BinaryPlainComponent,
+ BlockComponent,
+ ObjectComponent,
+ BitsComponent,
+ StringComponent,
+ NumberComponent,
+ ArrayComponent,
+ ColorComponent,
+ BinaryParentComponent,
+ HexComponent
+ ],
+ entryComponents: [
+ BinaryFlatComponent,
+ BlockComponent,
+ ObjectComponent,
+ BitsComponent,
+ StringComponent,
+ NumberComponent,
+ ArrayComponent,
+ ColorComponent,
+ HexComponent,
+ BinaryPlainComponent
+ ]
+})
+export class BinaryViewModule {}
diff --git a/libs/utils/src/lib/sync/sync-playground/sync-playground-presenter/sync-playground-presenter.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/bits/bits.component.css
similarity index 100%
rename from libs/utils/src/lib/sync/sync-playground/sync-playground-presenter/sync-playground-presenter.component.css
rename to codelab-master/apps/kirjs/src/app/modules/binary/binary-view/bits/bits.component.css
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/bits/bits.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/bits/bits.component.html
new file mode 100644
index 000000000..b464a513d
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/bits/bits.component.html
@@ -0,0 +1,10 @@
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/bits/bits.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/bits/bits.component.spec.ts
new file mode 100644
index 000000000..c3a3c4d0e
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/bits/bits.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { BitsComponent } from './bits.component';
+
+describe('BitsComponent', () => {
+ let component: BitsComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [BitsComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(BitsComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/bits/bits.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/bits/bits.component.ts
new file mode 100644
index 000000000..2362484ec
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/bits/bits.component.ts
@@ -0,0 +1,18 @@
+import { Component, Input } from '@angular/core';
+import { BinaryParentComponent } from '../binary-parent/binary-parent.component';
+
+@Component({
+ selector: 'kirjs-bits',
+ templateUrl: './bits.component.html',
+ styleUrls: ['./bits.component.css']
+})
+export class BitsComponent {
+ @Input() data;
+ @Input() showMeta = false;
+
+ constructor(private readonly root: BinaryParentComponent) {}
+
+ update(value) {
+ this.root.update(this.data, Number(value).toString());
+ }
+}
diff --git a/libs/utils/src/lib/sync/sync-playground/sync-playground-test/sync-playground-test.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/block/block.component.css
similarity index 100%
rename from libs/utils/src/lib/sync/sync-playground/sync-playground-test/sync-playground-test.component.css
rename to codelab-master/apps/kirjs/src/app/modules/binary/binary-view/block/block.component.css
diff --git a/ng2ts/tests/test.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/block/block.component.html
similarity index 100%
rename from ng2ts/tests/test.ts
rename to codelab-master/apps/kirjs/src/app/modules/binary/binary-view/block/block.component.html
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/block/block.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/block/block.component.spec.ts
new file mode 100644
index 000000000..b94785b8c
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/block/block.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { BlockComponent } from './block.component';
+
+describe('BlockComponent', () => {
+ let component: BlockComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [BlockComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(BlockComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/block/block.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/block/block.component.ts
new file mode 100644
index 000000000..4ac10fb1f
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/block/block.component.ts
@@ -0,0 +1,69 @@
+import {
+ ChangeDetectorRef,
+ Component,
+ ComponentFactoryResolver,
+ Input,
+ OnChanges,
+ OnInit,
+ ViewContainerRef
+} from '@angular/core';
+import { ObjectComponent } from '../object/object.component';
+import { BitsComponent } from '../bits/bits.component';
+import { StringComponent } from '../string/string.component';
+import { NumberComponent } from '../number/number.component';
+import { ArrayComponent } from '../array/array.component';
+import { ColorComponent } from '../color/color.component';
+import { HexComponent } from '../hex/hex.component';
+
+const componentMap = {
+ object: ObjectComponent,
+ bits: BitsComponent,
+ string: StringComponent,
+ number: NumberComponent,
+ array: ArrayComponent,
+ color: ColorComponent,
+ hex: HexComponent
+};
+
+@Component({
+ selector: 'kirjs-block',
+ templateUrl: './block.component.html',
+ styleUrls: ['./block.component.css']
+})
+export class BlockComponent implements OnInit, OnChanges {
+ @Input() data: any;
+ @Input() showMeta: boolean;
+ private componentRef: any;
+
+ constructor(
+ private vcr: ViewContainerRef,
+ private readonly cdr: ChangeDetectorRef,
+ private componentFactoryResolver: ComponentFactoryResolver
+ ) {}
+
+ ngOnChanges(changes) {
+ if (this.componentRef && changes.showMeta) {
+ this.componentRef.instance.showMeta = changes.showMeta.currentValue;
+ }
+
+ if (this.componentRef && changes.data) {
+ this.componentRef.instance.data = changes.data.currentValue;
+ }
+ this.cdr.detectChanges();
+ }
+
+ ngOnInit() {
+ if (!componentMap[this.data.type]) {
+ // tslint:disable-next-line:no-debugger
+ debugger;
+ }
+
+ const cf = this.componentFactoryResolver.resolveComponentFactory(
+ componentMap[this.data.type]
+ );
+ this.vcr.clear();
+ this.componentRef = this.vcr.createComponent(cf) as any;
+ this.componentRef.instance.data = this.data;
+ this.componentRef.instance.showMeta = this.showMeta;
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/color/color.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/color/color.component.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/color/color.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/color/color.component.html
new file mode 100644
index 000000000..32f496a40
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/color/color.component.html
@@ -0,0 +1,7 @@
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/color/color.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/color/color.component.spec.ts
new file mode 100644
index 000000000..2c30608d6
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/color/color.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ColorComponent } from './color.component';
+
+describe('ColorComponent', () => {
+ let component: ColorComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ColorComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ColorComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/color/color.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/color/color.component.ts
new file mode 100644
index 000000000..d863cd809
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/color/color.component.ts
@@ -0,0 +1,39 @@
+import { Component, Input, OnInit } from '@angular/core';
+import { BinaryParentComponent } from '../binary-parent/binary-parent.component';
+
+@Component({
+ selector: 'kirjs-color',
+ templateUrl: './color.component.html',
+ styleUrls: ['./color.component.css']
+})
+export class ColorComponent implements OnInit {
+ color: string;
+
+ constructor(private readonly root: BinaryParentComponent) {}
+
+ private _data: any;
+
+ get data() {
+ return this._data;
+ }
+
+ @Input()
+ set data(data) {
+ this._data = data;
+ this.color = data.value.toString(16).padStart(6, 0);
+ }
+
+ update(value) {
+ const val = (parseInt(value.slice(1), 16).toString(2) as any).padStart(
+ 24,
+ 0
+ );
+ this.root.update(this._data, val);
+ }
+
+ updateBinary(binary) {
+ this.root.update(this.data, binary);
+ }
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/hex/hex.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/hex/hex.component.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/hex/hex.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/hex/hex.component.html
new file mode 100644
index 000000000..ea1587484
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/hex/hex.component.html
@@ -0,0 +1 @@
+{{ data.rawValue }}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/hex/hex.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/hex/hex.component.spec.ts
new file mode 100644
index 000000000..d58de6b7d
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/hex/hex.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { HexComponent } from './hex.component';
+
+describe('HexComponent', () => {
+ let component: HexComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [HexComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(HexComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/hex/hex.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/hex/hex.component.ts
new file mode 100644
index 000000000..4d95c2fb3
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/hex/hex.component.ts
@@ -0,0 +1,14 @@
+import { Component, Input, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-hex',
+ templateUrl: './hex.component.html',
+ styleUrls: ['./hex.component.css']
+})
+export class HexComponent implements OnInit {
+ @Input() data;
+
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/inline-root/inline-root.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/inline-root/inline-root.component.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/inline-root/inline-root.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/inline-root/inline-root.component.html
new file mode 100644
index 000000000..e531bc894
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/inline-root/inline-root.component.html
@@ -0,0 +1,9 @@
+
+ {{ displayData | json }}
+
+ {{ displayData.name }}
+
+
+ {{ displayData.value }}
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/inline-root/inline-root.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/inline-root/inline-root.component.spec.ts
new file mode 100644
index 000000000..c4db75a51
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/inline-root/inline-root.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { InlineRootComponent } from './inline-root.component';
+
+describe('InlineRootComponent', () => {
+ let component: InlineRootComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [InlineRootComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(InlineRootComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/inline-root/inline-root.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/inline-root/inline-root.component.ts
new file mode 100644
index 000000000..f5cae0cdf
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/inline-root/inline-root.component.ts
@@ -0,0 +1,20 @@
+import { Component, Input, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-inline-root',
+ templateUrl: './inline-root.component.html',
+ styleUrls: ['./inline-root.component.css']
+})
+export class InlineRootComponent implements OnInit {
+ @Input() data: any;
+
+ displayData: any;
+
+ constructor() {}
+
+ ngOnInit() {}
+
+ display(displayData: any) {
+ this.displayData = displayData;
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/inline/inline.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/inline/inline.component.css
new file mode 100644
index 000000000..3e8f31f2e
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/inline/inline.component.css
@@ -0,0 +1,27 @@
+span {
+ font-size: 50px;
+ word-wrap: break-word;
+}
+
+.header {
+ background: #52ff93;
+}
+
+.palette {
+ background: #ffb71a;
+}
+
+.extensions {
+ background: #61e9ff;
+}
+
+.item:hover {
+ box-shadow: 0px 0px 4px 4px #444;
+ cursor: pointer;
+}
+
+input {
+ background: transparent;
+ border: 0 solid;
+ font-size: inherit;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/inline/inline.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/inline/inline.component.html
new file mode 100644
index 000000000..873d9196f
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/inline/inline.component.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/inline/inline.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/inline/inline.component.spec.ts
new file mode 100644
index 000000000..041a2678a
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/inline/inline.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { InlineComponent } from './inline.component';
+
+describe('InlineComponent', () => {
+ let component: InlineComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [InlineComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(InlineComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/inline/inline.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/inline/inline.component.ts
new file mode 100644
index 000000000..67bf93e20
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/inline/inline.component.ts
@@ -0,0 +1,41 @@
+import { Component, Input, OnInit } from '@angular/core';
+import { InlineRootComponent } from '../inline-root/inline-root.component';
+import { BinaryParentComponent } from '../binary-parent/binary-parent.component';
+
+@Component({
+ selector: 'kirjs-inline',
+ templateUrl: './inline.component.html',
+ styleUrls: ['./inline.component.css']
+})
+export class InlineComponent implements OnInit {
+ isArray: boolean;
+ private value: any;
+
+ constructor(
+ private readonly root: InlineRootComponent,
+ private readonly binaryRoot: BinaryParentComponent
+ ) {}
+
+ private _data: any;
+
+ get data() {
+ return this._data;
+ }
+
+ @Input()
+ set data(data) {
+ this._data = data;
+ this.value = data.value;
+ this.isArray = Array.isArray(data.value);
+ }
+
+ updateValue(value) {
+ this.binaryRoot.update(this.data, value);
+ }
+
+ ngOnInit() {}
+
+ display() {
+ this.root.display(this.data);
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/number/number.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/number/number.component.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/number/number.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/number/number.component.html
new file mode 100644
index 000000000..8a64a1fa5
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/number/number.component.html
@@ -0,0 +1,13 @@
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/number/number.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/number/number.component.spec.ts
new file mode 100644
index 000000000..60f299243
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/number/number.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { NumberComponent } from './number.component';
+
+describe('NumberComponent', () => {
+ let component: NumberComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [NumberComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(NumberComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/number/number.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/number/number.component.ts
new file mode 100644
index 000000000..047a41e63
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/number/number.component.ts
@@ -0,0 +1,28 @@
+import { Component, Input, OnInit } from '@angular/core';
+import { BinaryParentComponent } from '../binary-parent/binary-parent.component';
+
+@Component({
+ selector: 'kirjs-number',
+ templateUrl: './number.component.html',
+ styleUrls: ['./number.component.css']
+})
+export class NumberComponent implements OnInit {
+ @Input() data: any;
+ @Input() showMeta = false;
+
+ constructor(private readonly root: BinaryParentComponent) {}
+
+ update(value) {
+ const val = (Number(value).toString(2) as any).padStart(
+ this.data.length,
+ 0
+ );
+ this.root.update(this.data, val.slice(8) + val.slice(0, 8));
+ }
+
+ updateBinary(binary) {
+ this.root.update(this.data, binary);
+ }
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/object/object.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/object/object.component.css
new file mode 100644
index 000000000..e7c5b7a55
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/object/object.component.css
@@ -0,0 +1,16 @@
+.show-meta {
+ padding: 4px;
+ margin-right: 4px;
+ margin-top: 4px;
+ border: 1px #ddd solid;
+ border-radius: 10px;
+ font-size: 2vw;
+}
+
+.name {
+ display: none;
+}
+
+.show-meta .name {
+ display: inline-block;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/object/object.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/object/object.component.html
new file mode 100644
index 000000000..b316b2874
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/object/object.component.html
@@ -0,0 +1,12 @@
+
+ {{ item.name }}
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/object/object.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/object/object.component.spec.ts
new file mode 100644
index 000000000..13162071d
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/object/object.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ObjectComponent } from './object.component';
+
+describe('ObjectComponent', () => {
+ let component: ObjectComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ObjectComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ObjectComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/object/object.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/object/object.component.ts
new file mode 100644
index 000000000..5999d491a
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/object/object.component.ts
@@ -0,0 +1,23 @@
+import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-object',
+ templateUrl: './object.component.html',
+ styleUrls: ['./object.component.css']
+})
+export class ObjectComponent implements OnInit {
+ @Input() data: any;
+ @Input() showMeta = true;
+
+ constructor(private cdr: ChangeDetectorRef) {}
+
+ ngOnInit() {}
+
+ trackBy(i, data) {
+ return data.name;
+ }
+
+ init() {
+ this.cdr.detectChanges();
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/string/string.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/string/string.component.css
new file mode 100644
index 000000000..107a9a02a
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/string/string.component.css
@@ -0,0 +1,3 @@
+:host {
+ word-break: break-all;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/string/string.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/string/string.component.html
new file mode 100644
index 000000000..8a64a1fa5
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/string/string.component.html
@@ -0,0 +1,13 @@
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/string/string.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/string/string.component.spec.ts
new file mode 100644
index 000000000..ba502c559
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/string/string.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { StringComponent } from './string.component';
+
+describe('StringComponent', () => {
+ let component: StringComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [StringComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(StringComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/string/string.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/string/string.component.ts
new file mode 100644
index 000000000..843cbc494
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary-view/string/string.component.ts
@@ -0,0 +1,41 @@
+import { Component, Input, OnInit } from '@angular/core';
+import { BinaryParentComponent } from '../binary-parent/binary-parent.component';
+
+@Component({
+ selector: 'kirjs-string',
+ templateUrl: './string.component.html',
+ styleUrls: ['./string.component.css']
+})
+export class StringComponent implements OnInit {
+ get data() {
+ return this._data;
+ }
+
+ @Input()
+ set data(data) {
+ this._data = data;
+ }
+
+ @Input() showMeta = false;
+
+ _data: any;
+
+ constructor(private readonly root: BinaryParentComponent) {}
+
+ updateBinary(binary) {
+ this.root.update(this.data, binary);
+ }
+
+ update(value) {
+ const val = value
+ .split('')
+ .map(a => a.charCodeAt(0))
+ .map(a => a.toString(2))
+ .map(a => (a as any).padStart(8, 0))
+ .join('');
+
+ this.root.update(this.data, val);
+ }
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/binary.component.html
new file mode 100644
index 000000000..0e6204f90
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary.component.html
@@ -0,0 +1,712 @@
+
+
+
+
+
+
+
+
+
@kirjs
+ ️JavaScript ❤️ Binary
+ kirjs.com/binary/0
+
+
+
+
+ If you can't read the numbers below, move closer or go to
+ kirjs.com/binary/0
+
+
+ {{ binaryLittleGif.substr(0, 200) }}
+
+
+
+
+
Binary is hidden behind many layers of abstraction
+
+
+
+
In this talk:
+
+ Binary in files (images, video, other media, zip)
+ Binary for data transfer (instead of JSON)
+ Javascript using binary in memory
+
+
+
+
+
+
+
+
Let's see what's inside of gif
+
+
+
+
+
+
+
+
+
+
+ {{ chikinGif }}
+
+
+
+
+
+
+ {{ littleGif }}
+
+
+
+
+
+
+
+
+
+
+ {{ binaryLittleGif }}
+
+
+
+
+
+
Binary data makes no sense without a schema
+
+
+ Binary data
+
+ 01001110 01101111 01110110 01101001 00100000 01110011 01100001
+ 01100100
+
+
+
+ +
+
+
+ Schema
+ Lol, what's this?
+
+
+ =
+
+
+
+ Numbers? Picture? Archive? Text?
+
+
+
+
+
+
+
Binary data makes no sense without a schema
+
+
+ Binary data
+
+ 01001110 01101111 01110110 01101001 00100000 01110011 01100001
+ 01100100
+
+
+
+ +
+
+
+ Schema
+ This is UTF-8 string!
+
+
+ =
+
+
+ Novi Sad
+
+
+
+
+
+
+GRAPHICS INTERCHANGE FORMAT(sm)
+
+Version 89a
+
+(c)1987,1988,1989,1990
+
+Copyright
+CompuServe Incorporated
+Columbus, Ohio
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Header
+
+
Palette (Optional, size defined )
+
+ Contains indexed colors
+
+
Extensions (Optional)
+
+
+ Actual image data
+ Image Control
+ Animation Control
+ Comments
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Convert binary to decimal with JavaScript
+
+
+
+
+
Convert decimal to binary
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Convert binary to hexadecimal with JavaScript
+
+
+
+
+
Convert hexadecimal to binary with JavaScript
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
ПЕЛЬМЕНЬ
+
+
+
ПЕЛЬМЕНЬ
+ ПЕЉМЕЊ
+
+
+
+
+
+┌─┬┐ ╔═╦╗ ╓─╥╖ ╒═╤╕
+│ ││ ║ ║║ ║ ║║ │ ││
+├─┼┤ ╠═╬╣ ╟─╫╢ ╞═╪╡
+└─┴┘ ╚═╩╝ ╙─╨╜ ╘═╧╛
+┌───────────────────┐
+│ ╔═══╗ │
+│ ╚═╦═╝ │
+╞═╤══╩══╤═══════════╡
+│ ├──┬──┤ │
+│ └──┴──┘ │
+└───────────────────┘
+
+
+
+
+
+
+
+
+
Get charcode from string
+
+
+
+
+
Get letter from charcode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Parsing binary(with binary-parser )
+
+
+
+
+
+
+
+
+
+
+
Gif facts
+
+ Image size: 1х1 to 65535х65535
+ Colors: 2 - 256
+ True color gifs are possible
+ Max number of animation frames - unlimited
+ Animation delay 1/100 - 655 seconds
+ There's a plain text extension
+ 24 pages + 12 pages appendix in gif89 standard
+
+
+
+
+
File header constants
+
+ Gif - GIF87a (or GIF89a)
+ Jpeg - begin with ‘FF D8‘ and end with ‘FF D9'
+ Java class - CAFEBABE
+ ZIP files begin with ‘PK‘ (50 4B)
+ PDF files start with ‘%PDF‘ (25 50 44 46)
+
+ PNG image files begin with “\211 P N G \r \n 32 \n” (89 50 4E 47 0D 0A
+ 1A 0A)
+
+ HTTP2 - PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n
+
+
+
+
+
Big library of binary formats
+ https://formats.kaitai.io/
+
+
+
+
Can we use binary instead of JSON ?
+
+
+
+
+
+
+
+
+
+
Serialization speed
+
+
+
+
+
Debugging
+
+
+
JSON
+
+
+ Easy to understand
+ Human readable
+
+
+
+
+
Binary
+
+ Requires special tooling
+
+
+
+
+
+
+
+
+
Schema
+
+
+
+
+
Binary
+
+ Needs a schema
+ Comes with type checking
+ Comes with validation
+
+
+
+
+
+
+
+
+
Thought experiment
+ Memory management in JavaScript
+
+
+
+
Let's see how memory works in typed arrays
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Angular Component Flags (bitmask)
+
+
+
+
+
ReactDOM Flags (bitmask)
+
+
+
+
+
+
+
+
The end:
+
+ Binary in files (images, video, other media, zip)
+ Binary for data transfer (instead of JSON)
+ Javascript using binary in memory
+
+
+
+
+
@kirjs
+ Binary ❤️ JavaScript
+ kirjs.com/binary/0
+ Thanks @andrey_sitnik, @_bmsdave, @NisamProgramer for review
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary.component.scss b/codelab-master/apps/kirjs/src/app/modules/binary/binary.component.scss
new file mode 100644
index 000000000..de3f5c54a
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary.component.scss
@@ -0,0 +1,201 @@
+h1 {
+ font-size: 5vw;
+}
+
+::ng-deep feedback-widget {
+ position: absolute;
+ right: 0;
+ bottom: 140px;
+ display: block;
+ width: 32px;
+ height: 32px;
+ z-index: 100;
+
+ .feedback-button {
+ width: 24px;
+ height: 24px;
+ }
+}
+
+#font-size b {
+ font-size: 10vw;
+ margin-bottom: 6vw;
+ display: block;
+}
+
+:host {
+ .binary-presentation ::ng-deep {
+ .slide [intro] {
+ background: url(pics/kirjs.webp);
+ background-size: 100vh !important;
+ padding-left: 3vw;
+ h2 {
+ font-size: 3vw;
+ }
+ h1,
+ h2,
+ h3 {
+ text-align: left;
+ margin-left: 100vh;
+ margin-bottom: 2vw;
+ }
+
+ h3 {
+ font-size: 3vw;
+ }
+ }
+
+ .slide [json] {
+ background: url(pics/p2.jpg);
+ }
+
+ .slide [krakoziabry] {
+ background: url(pics/krakoziabry.jpg);
+ background-size: cover;
+ }
+
+ .slide [endianness] {
+ background: url(pics/endianness.png);
+ background-size: 80vw !important;
+ }
+
+ .slide [pelmen] {
+ background: url(pics/pelmeni.jpg);
+ background-size: cover;
+
+ h1 {
+ font-size: 10vw;
+ text-shadow: 0 0 1vw #ffffff;
+ }
+ }
+
+ .slide [kaitai] {
+ background: url(pics/kaitai.png);
+ background-size: 400px 400px !important;
+ background-color: #fff;
+
+ h1 {
+ font-size: 3vw;
+ }
+ h2 {
+ text-align: center;
+ font-size: 2vw;
+ }
+ }
+
+ .slide [gif] {
+ background: url(pics/zoom.gif);
+ }
+
+ .slide #binary-abstraction {
+ background: url(pics/binary-abstraction.jpg);
+ }
+
+ .slide [message],
+ [gif] .slide {
+ background: url(pics/gdg-binary.jpg);
+ }
+
+ .slide [gif-bg],
+ [gif-bg] .slide {
+ background: url(pics/little.gif);
+ }
+ .slide [bg],
+ [bg] .slide {
+ background-repeat: no-repeat;
+ background-size: cover;
+ }
+
+ .slide [vs] {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .slide h1 {
+ font-size: 5vw;
+ color: #444;
+ text-align: center;
+ }
+
+ h2 {
+ font-size: 4vw;
+ margin-bottom: 2vw;
+ }
+
+ [bg] h1 {
+ margin-top: 40px;
+ font-size: 10vw;
+ text-shadow: 0 3px 20px #fff, 0 -3px 20px #fff, -3px 0 20px #fff,
+ 3px 0 20px #fff;
+ }
+
+ [bg] h2 {
+ font-size: 6vw;
+ text-shadow: 0 3px 20px #fff, 0 -3px 20px #fff, -3px 0 20px #fff,
+ 3px 0 20px #fff;
+ }
+
+ td {
+ font-size: 2vw;
+ font-weight: 300;
+ padding: 1vw;
+ }
+ }
+
+ [bg] h1 b,
+ [bg] h2 b {
+ background: transparent;
+ font-weight: bold;
+ }
+}
+
+.compare-json {
+ width: 50%;
+}
+
+.compare-serialization {
+ padding: 0 20vw;
+}
+
+#gif-structure {
+ .text,
+ li {
+ font-size: 3vw;
+ }
+ h2 {
+ margin-bottom: 1vw;
+ }
+
+ .text {
+ margin-bottom: 2vw;
+ }
+}
+
+[binary-schema] {
+ table {
+ width: 100%;
+ }
+ td {
+ font-size: 4vw;
+ font-weight: 400;
+ }
+}
+
+#gif-structure {
+ .parent-palette {
+ background: #00ff51;
+ }
+
+ .parent-header {
+ background: #ffaf00;
+ }
+
+ .parent-extensions {
+ background: #00a4ff;
+ }
+}
+
+#bitwise-to-read .book {
+ background-image: url(./pics/hackers-delight.jpeg);
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary.component.ts
new file mode 100644
index 000000000..4d6acb79f
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary.component.ts
@@ -0,0 +1,385 @@
+import { Component } from '@angular/core';
+import { strToBin } from './parser/utils';
+
+declare const require;
+
+const littleGif = require('!binary-loader!./pics/little.gif');
+const chikinGif = require('!binary-loader!./pics/chikin.gif');
+
+@Component({
+ selector: 'kirjs-binary',
+ templateUrl: './binary.component.html',
+ styleUrls: ['./binary.component.scss']
+})
+export class BinaryComponent {
+ fontSize = 30;
+
+ binaryLittleGif = strToBin(littleGif);
+ binaryChikinGif = strToBin(chikinGif);
+
+ code = {
+ message: `['01001011', '01001111',
+ '01010100', '01001100',
+ '01001001', '01001110',
+ '00100000', '00111110',
+ '00100000', '01001010',
+ '01000001', '01010110',
+ '01000001'
+]
+
+
+
+
+
+
+// .map(
+// a => String.fromCharCode(
+// parseInt(a, 2)))
+// .join('');
+`,
+ simpleBinaryOperations: `let i = 7; // 7 = 1 + 2 + 4
+!!(i & 1) // true
+!!(i & 2) // true
+!!(i & 4) // true
+
+i = i & ~2; // 5 = 1 + 4 (Not 2)
+
+!!(i & 1) // true
+!!(i & 2) // false
+!!(i & 4) // true
+
+i = i | 2 // 7 = 1 + 2 + 4
+
+!!(i & 1) // true
+!!(i & 2) // true
+!!(i & 4) // true
+
+
+`,
+ jsonBasic: `{
+ "name": "Sarah",
+ "test": true,
+ "something": 1212
+}`,
+ jsonOne: `{
+ "str": "1",
+ "number": 1,
+ "bool": true
+}`,
+ inputFile: ' ',
+ fileHandlerHighlight: { match: /read/, className: 'highlighted-code' },
+ fileHandler: `const input = document.getElementById('file');
+input.addEventListener('change', (e) => {
+ const reader = new FileReader();
+
+ reader.onloadend = (e) => {
+ console.log(e.target.result);
+ };
+
+ reader.readAsString(input.files[0]);
+});
+`,
+ fileHandlerBinary: `const input = document.getElementById('file');
+input.addEventListener('change', (e) => {
+ const reader = new FileReader();
+
+ reader.onloadend = (e) => {
+ console.log(e.target.result);
+ };
+
+ reader.readAsArrayBuffer(input.files[0]);
+});`
+ };
+
+ littleGif = littleGif;
+ chikinGif = chikinGif;
+
+ binaryParserHeaderMatch = /parent-header/;
+ binaryParserHeaderHelpers = [
+ `new Parser();`,
+ `new Parser()
+ .string('gif', {length: 3})
+ `,
+ `new Parser()
+ .string('gif', {length: 3})
+ .string('version', {length: 3})
+ `,
+ `new Parser()
+ .string('gif', {length: 3})
+ .string('version', {length: 3})
+ .uint16('width')
+ `,
+ `new Parser()
+ .string('gif', {length: 3})
+ .string('version', {length: 3})
+ .uint16le('width')
+ `,
+ `new Parser()
+ .string('gif', {length: 3})
+ .string('version', {length: 3})
+ .uint16le('width')
+ .uint16le('height')
+ `,
+ `new Parser()
+ .string('gif', {length: 3})
+ .string('version', {length: 3})
+ .uint16le('width')
+ .uint16le('height')
+ .bit1('globalPalette')
+ `,
+ `new Parser()
+ .string('gif', {length: 3})
+ .string('version', {length: 3})
+ .uint16le('width')
+ .uint16le('height')
+ .bit1('globalPalette')
+ .bit3('resolution')
+ .bit1('paletteSorted')
+ .bit3('paletteSize')
+ .uint8('background')
+ .uint8('ratio')
+ `
+ ];
+
+ reactBitmask = `// Don't change these two values. They're used by React Dev Tools.
+var NoEffect = /* */0;
+var PerformedWork = /* */1;
+
+// You can change the rest (and add more).
+var Placement = /* */2;
+var Update = /* */4;
+var PlacementAndUpdate = /* */6;
+var Deletion = /* */8;
+var ContentReset = /* */16;
+var Callback = /* */32;
+var DidCapture = /* */64;
+var Ref = /* */128;
+var Snapshot = /* */256;
+var Passive = /* */512;
+
+// Passive & Update & Callback & Ref & Snapshot
+var LifecycleEffectMask = /* */932;
+
+// Union of all host effects
+var HostEffectMask = /* */1023;
+
+var Incomplete = /* */1024;
+var ShouldCapture = /* */2048;`;
+
+ binaryParserPaletteMatch = /parent-palette/;
+ binaryParserPaletteHelpers = [
+ `new Parser()
+ .string('gif', {length: 3})
+ .string('version', {length: 3})
+ .uint16le('width')
+ .uint16le('height')
+ .bit1('globalPalette')
+ .bit3('resolution')
+ .bit1('paletteSorted')
+ .bit3('paletteSize')
+ .uint8('background')
+ .uint8('ratio')`,
+
+ `new Parser()
+ .string('gif', {length: 3})
+ .string('version', {length: 3})
+ .uint16le('width')
+ .uint16le('height')
+ .bit1('globalPalette')
+ .bit3('resolution')
+ .bit1('paletteSorted')
+ .bit3('paletteSize')
+ .uint8('background')
+ .uint8('ratio')
+ .array('palette', {
+ type: new Parser().bit24('color'),
+ length: 4
+ }
+ )`,
+ `new Parser()
+ .string('gif', {length: 3})
+ .string('version', {length: 3})
+ .uint16le('width')
+ .uint16le('height')
+ .bit1('globalPalette')
+ .bit3('resolution')
+ .bit1('paletteSorted')
+ .bit3('paletteSize')
+ .uint8('background')
+ .uint8('ratio')
+ .array('palette', {
+ type: new Parser().bit24('color'),
+ length: (result) =>
+ 2 ** (result.paletteSize + 1)
+ }
+ )`,
+ `new Parser()
+ .string('gif', {length: 3})
+ .string('version', {length: 3})
+ .uint16le('width')
+ .uint16le('height')
+ .bit1('globalPalette')
+ .bit3('resolution')
+ .bit1('paletteSorted')
+ .bit3('paletteSize')
+ .uint8('background')
+ .uint8('ratio')
+ .array('palette', {
+ type: new Parser()
+ .uint8('r')
+ .uint8('g')
+ .uint8('b'),
+ length: (result) =>
+ 2 ** (result.paletteSize + 1)
+ }
+ )`
+ ];
+
+ //
+ // `file.byteLength`,
+ // `String.fromCharCode(...new Uint8Array(file))`,
+ // // `// Let's test how many arguments we can apply
+ // // String.fromCharCode(...Array.from(new Array(100)))`,
+ // // `String.fromCharCode(...Array.from(new Array(10000)))`,
+ // // `String.fromCharCode(...Array.from(new Array(100000)))`,
+ // // `String.fromCharCode(...Array.from(new Array(1000000)))`,
+ // // `String.fromCharCode(...Array.from(new Array(125307)))`,
+ // // `
+ // // // read more:
+ // https://stackoverflow.com/questions/22747068/is-there-a-max-number-of-arguments-javascript-functions-can-accept
+ // // String.fromCharCode(...Array.from(new Array(125306)))`,
+ // `String.fromCharCode(...new Uint8Array(file))`,
+ // `Array.from(new Uint8Array(file)).map(a=>a.toString(2).padStart(8, 0)).join('')`,
+
+ //
+ // document.getElementById('file').addEventListener('change', (e)=>{
+ // const reader = new FileReader();
+ //
+ // reader.onloadend = (e) => {
+ // file = e.target.result;
+ // console.log(file);
+ // };
+ //
+ // reader.readAsArrayBuffer(e.target.files[0]);
+ // })
+
+ // gif = {
+ // width: "4",
+ // height: "4",
+ // image: [
+ // '#f00', '#f00', '#f00', '#f00',
+ // '#f90', '#f0f', '#f00', '#f00',
+ // '#f90', '#f0f', '#f00', '#f00',
+ // '#f90', '#f0f', '#f00', '#f00',
+ // ]
+ // }
+
+ commands = [
+ `\`
+
+
+
+
+
+ @kirjs
+ Binary ❤️ JavaScript
+
+
+
+
+ \``,
+ ` `,
+ `
+ document.getElementById('file').addEventListener('change', (e)=>{
+ const reader = new FileReader();
+
+ reader.onloadend = (e) => {
+ file = e.target.result;
+ console.log(file);
+ };
+
+ reader.readAsArrayBuffer(e.target.files[0]);
+ })`,
+
+ `file.byteLength`,
+ `String.fromCharCode(...new Uint8Array(file))`,
+ // `// Let's test how many arguments we can apply
+ // String.fromCharCode(...Array.from(new Array(100)))`,
+ // `String.fromCharCode(...Array.from(new Array(10000)))`,
+ // `String.fromCharCode(...Array.from(new Array(100000)))`,
+ // `String.fromCharCode(...Array.from(new Array(1000000)))`,
+ // `String.fromCharCode(...Array.from(new Array(125307)))`,
+ // `
+ // // read more: https://stackoverflow.com/questions/22747068/is-there-a-max-number-of-arguments-javascript-functions-can-accept
+ // String.fromCharCode(...Array.from(new Array(125306)))`,
+ `String.fromCharCode(...new Uint8Array(file))`,
+ `Array.from(new Uint8Array(file)).map(a=>a.toString(2).padStart(8, 0)).join('')`,
+
+ `explain('message', 'basic')`,
+ `explain('message', 'bytes')`,
+ `explain('bindec', 'uint8')`,
+ `parseInt('01010101', 2)`,
+ `explain('bindec', 'int8')`,
+ `explain('message', 'uint8')`,
+ `explain('ascii')`,
+ `explain('message', 'string')`,
+
+ `explain('compare')`,
+ `explain('json')`,
+ `explain('gif')`,
+ `
+ // Let's reinvent gif with JSON:
+
+
+ gif = {
+ width: "4",
+ height: "4",
+ image: [
+ '#f00', '#f00', '#f00', '#f00',
+ '#f90', '#f0f', '#f00', '#f00',
+ '#f90', '#f0f', '#f00', '#f00',
+ '#f90', '#f0f', '#f00', '#f00',
+ ]
+ }
+
+ `,
+ `
+ // Let's index the colors
+
+
+ gif = {
+ width: "4",
+ height: "4",
+ colors: ['#f00', '#f90', '#f0f'],
+ image: [
+ 0, 0, 0, 0,
+ 1, 2, 0, 0,
+ 1, 2, 0, 0,
+ 1, 0 ,2 , 0
+ ]
+ }
+
+ `,
+ `JSON.stringify(gif)`,
+ `JSON.stringify(gif).length`,
+
+ `"010010010111010000100000011010010111001100100000011000110110111101101101011011010110111101101110001"
+
+
+ `,
+
+ `explain('gif')`,
+
+ `// How to read binary data?`
+ ];
+ private evaledMessage: string;
+
+ evalMessage() {
+ this.evaledMessage = eval(this.code.message);
+ }
+
+ setLittleGifBinary(value: string) {
+ this.littleGif = value;
+ this.binaryLittleGif = strToBin(value);
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/binary.module.ts b/codelab-master/apps/kirjs/src/app/modules/binary/binary.module.ts
new file mode 100644
index 000000000..7967d0986
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/binary.module.ts
@@ -0,0 +1,85 @@
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+import { MatSelectModule } from '@angular/material/select';
+import { MatAutocompleteModule } from '@angular/material/autocomplete';
+import { SlidesModule, SlidesRoutes } from '@ng360/slides';
+import { FeedbackModule } from '@codelab/feedback';
+import { ConsoleModule } from '@codelab/console';
+import { CodeDemoModule } from '@codelab/code-demos';
+import { SharedPipeModule } from '@codelab/utils/src/lib/pipes/pipes.module';
+import { BinaryComponent } from './binary.component';
+import { FakeGifComponent } from './fake-gif/fake-gif.component';
+import { GifPaletteComponent } from './gif-palette/gif-palette.component';
+import { BinaryViewModule } from './binary-view/binary-view.module';
+import { MidiComponent } from './midi/midi.component';
+import { AsciiComponent } from './ascii/ascii.component';
+import { BindecComponent } from './bindec/bindec.component';
+import { MessageComponent } from './message/message.component';
+import { JsonComponent } from './json/json.component';
+import { CompareComponent } from './compare/compare.component';
+import { HtmlPostComponent } from './html-post/html-post.component';
+import { NewProgressBarModule } from '../ast/new-progress-bar/new-progress-bar.module';
+import { BinaryGifComponent } from './binary-gif/binary-gif.component';
+import { BitComponent } from './bit/bit.component';
+import { MemoryComponent } from './memory/memory.component';
+import { BinaryParserDemoComponent } from './binary-parser-demo/binary-parser-demo.component';
+import { HexdecComponent } from './hexdec/hexdec.component';
+import { AngularFlagsComponent } from './angular-flags/angular-flags.component';
+import { ColorIndexingComponent } from './color-indexing/color-indexing.component';
+import { BitwiseComponent } from './bitwise/bitwise.component';
+import { ToReadComponent } from './to-read/to-read.component';
+
+const routes = RouterModule.forChild(SlidesRoutes.get(BinaryComponent));
+
+@NgModule({
+ imports: [
+ routes,
+ FormsModule,
+ CommonModule,
+ BinaryViewModule,
+ CodeDemoModule,
+ MatAutocompleteModule,
+ SharedPipeModule,
+ ConsoleModule,
+
+ NewProgressBarModule,
+ MatSelectModule,
+ SlidesModule,
+ FeedbackModule
+ ],
+ declarations: [
+ BinaryComponent,
+ FakeGifComponent,
+ GifPaletteComponent,
+ MidiComponent,
+ AsciiComponent,
+ BindecComponent,
+ MessageComponent,
+ JsonComponent,
+ CompareComponent,
+ HtmlPostComponent,
+ BinaryGifComponent,
+ BitComponent,
+ MemoryComponent,
+ BinaryParserDemoComponent,
+ HexdecComponent,
+ AngularFlagsComponent,
+ ColorIndexingComponent,
+ BitwiseComponent,
+ ToReadComponent
+ ],
+ entryComponents: [
+ FakeGifComponent,
+ MidiComponent,
+ AsciiComponent,
+ BindecComponent,
+ MessageComponent,
+ JsonComponent,
+ HtmlPostComponent,
+ CompareComponent
+ ],
+ exports: [BinaryComponent]
+})
+export class BinaryModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/bindec/bindec.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/bindec/bindec.component.css
new file mode 100644
index 000000000..bfa609a2c
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/bindec/bindec.component.css
@@ -0,0 +1,44 @@
+.powers {
+ display: flex;
+ font-size: 5vw;
+ justify-content: center;
+}
+
+.power {
+ width: 12.5%;
+ border: 1px #ddd dotted;
+ text-align: center;
+ cursor: pointer;
+}
+
+.power:hover {
+ box-shadow: 0 0 12px 6px #999;
+ background: #eeeeee;
+}
+
+.power input {
+ zoom: 4;
+}
+
+.dec {
+ font-size: 3vw;
+ color: #444;
+}
+.bin {
+ font-size: 10vw;
+}
+.number {
+ width: 100%;
+ text-align: center;
+ font-size: 16vw;
+ padding: 2vw;
+}
+
+.link:hover {
+ color: #90cd79;
+}
+.link {
+ border-bottom: 1px #999 dotted;
+ margin-right: 20px;
+ cursor: pointer;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/bindec/bindec.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/bindec/bindec.component.html
new file mode 100644
index 000000000..b86fe719e
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/bindec/bindec.component.html
@@ -0,0 +1,27 @@
+
+
+ {{ sign ? '-' : '+' }}
+
+ {{ sign ? '1' : '0' }}
+
+
+ {{ getBaseValue(i) }}
+
+
+
+ {{ v ? '1' : '0' }}
+
+
+
+
+
1
+
2
+
4
+
8
+
Add one
+
Remove one
+
Add sign
+
+ Remove sign
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/bindec/bindec.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/bindec/bindec.component.spec.ts
new file mode 100644
index 000000000..2c1d2dc70
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/bindec/bindec.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { BindecComponent } from './bindec.component';
+
+describe('BindecComponent', () => {
+ let component: BindecComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [BindecComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(BindecComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/bindec/bindec.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/bindec/bindec.component.ts
new file mode 100644
index 000000000..2a197d26c
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/bindec/bindec.component.ts
@@ -0,0 +1,37 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-bindec',
+ templateUrl: './bindec.component.html',
+ styleUrls: ['./bindec.component.css']
+})
+export class BindecComponent implements OnInit {
+ digits = [0];
+ result = [0];
+ displaySign = false;
+ sign = false;
+
+ constructor() {}
+
+ get size() {
+ return this.digits.length;
+ }
+
+ get convertedValue() {
+ return (
+ (this.sign ? -1 : 1) *
+ this.result.reduce(
+ (result, value, index) => result + value * this.getBaseValue(index),
+ 0
+ )
+ );
+ }
+
+ getBaseValue(i: number) {
+ return 2 ** (this.size - i - 1);
+ }
+
+ update(value) {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/bit/bit.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/bit/bit.component.css
new file mode 100644
index 000000000..01f7d18e6
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/bit/bit.component.css
@@ -0,0 +1,32 @@
+.bits {
+ display: flex;
+ margin-bottom: 4vw;
+}
+
+.size-16 .bit {
+ font-size: 5vw;
+}
+
+.size-24 .bit {
+ font-size: 4vw;
+}
+.size-32 .bit {
+ font-size: 2.5vw;
+}
+
+.bit {
+ font-size: 10vw;
+ margin-left: 1vw;
+ color: #444;
+ border-bottom: 0.2vw #888 solid;
+}
+
+.label {
+ color: #999;
+ border: none;
+ margin-right: 2vw;
+}
+
+:host ::ng-deep .content.content.content table td {
+ font-size: 4vw;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/bit/bit.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/bit/bit.component.html
new file mode 100644
index 000000000..1f04d8c18
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/bit/bit.component.html
@@ -0,0 +1,6 @@
+
+
{{ bitValue.length }} bits:
+
{{ value }}
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/bit/bit.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/bit/bit.component.spec.ts
new file mode 100644
index 000000000..395404a6e
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/bit/bit.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { BitComponent } from './bit.component';
+
+describe('BitComponent', () => {
+ let component: BitComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [BitComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(BitComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/bit/bit.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/bit/bit.component.ts
new file mode 100644
index 000000000..768f69d38
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/bit/bit.component.ts
@@ -0,0 +1,31 @@
+import { Component, Input, OnDestroy, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-bit',
+ templateUrl: './bit.component.html',
+ styleUrls: ['./bit.component.css']
+})
+export class BitComponent implements OnInit, OnDestroy {
+ bits = 7;
+ @Input() param = 1;
+
+ bitValue: number[] = [];
+
+ private interval = setInterval(() => {
+ this.generate();
+ }, 500);
+
+ generate() {
+ this.bitValue = Array.from({ length: this.param }).map(a =>
+ Math.round(Math.random())
+ );
+ }
+
+ ngOnDestroy() {
+ clearInterval(this.interval);
+ }
+
+ ngOnInit() {
+ this.generate();
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/bitwise/bitwise.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/bitwise/bitwise.component.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/bitwise/bitwise.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/bitwise/bitwise.component.html
new file mode 100644
index 000000000..5406b703a
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/bitwise/bitwise.component.html
@@ -0,0 +1 @@
+bitwise works!
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/bitwise/bitwise.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/bitwise/bitwise.component.spec.ts
new file mode 100644
index 000000000..fe090db39
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/bitwise/bitwise.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { BitwiseComponent } from './bitwise.component';
+
+describe('BitwiseComponent', () => {
+ let component: BitwiseComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [BitwiseComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(BitwiseComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/bitwise/bitwise.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/bitwise/bitwise.component.ts
new file mode 100644
index 000000000..3a3786cb1
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/bitwise/bitwise.component.ts
@@ -0,0 +1,12 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-bitwise',
+ templateUrl: './bitwise.component.html',
+ styleUrls: ['./bitwise.component.css']
+})
+export class BitwiseComponent implements OnInit {
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/color-indexing/color-indexing.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/color-indexing/color-indexing.component.css
new file mode 100644
index 000000000..1305661e0
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/color-indexing/color-indexing.component.css
@@ -0,0 +1,8 @@
+.cell {
+ width: 8vw;
+ height: 8vw;
+ text-align: center;
+ font-size: 3vw !important;
+ vertical-align: middle;
+ line-height: 8vw;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/color-indexing/color-indexing.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/color-indexing/color-indexing.component.html
new file mode 100644
index 000000000..3ece96397
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/color-indexing/color-indexing.component.html
@@ -0,0 +1,40 @@
+
+
+
+
Color table (Palette)
+
+
+ {{ color.index }}
+
+
+
Indexed image
+
+
+
+ {{ hash[cell] }}
+
+
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/color-indexing/color-indexing.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/color-indexing/color-indexing.component.spec.ts
new file mode 100644
index 000000000..64ab0cfb3
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/color-indexing/color-indexing.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ColorIndexingComponent } from './color-indexing.component';
+
+describe('ColorIndexingComponent', () => {
+ let component: ColorIndexingComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ColorIndexingComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ColorIndexingComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/color-indexing/color-indexing.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/color-indexing/color-indexing.component.ts
new file mode 100644
index 000000000..b57c460cb
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/color-indexing/color-indexing.component.ts
@@ -0,0 +1,53 @@
+import { Component, OnInit } from '@angular/core';
+
+interface TableItem {
+ color: string;
+ index: number;
+}
+
+interface ColorTableHash {
+ [key: string]: number;
+}
+
+@Component({
+ selector: 'kirjs-color-indexing',
+ templateUrl: './color-indexing.component.html',
+ styleUrls: ['./color-indexing.component.css']
+})
+export class ColorIndexingComponent implements OnInit {
+ noIndexing = [
+ ['#ff0000', '#ff0000', '#ff0000'],
+ ['#fff000', '#ff0000', '#fff000'],
+ ['#ff0000', '#ff0000', '#ff0000']
+ ];
+
+ colorTable: TableItem[];
+ hash: ColorTableHash;
+
+ constructor() {
+ this.generate();
+ }
+
+ index() {
+ const index = this.noIndexing.reduce((colors, row) => {
+ return row.reduce((colors, cell) => {
+ colors[cell] = true;
+ return colors;
+ }, colors);
+ }, {});
+ return Object.keys(index).map((color, index) => ({ color, index }));
+ }
+
+ generate() {
+ this.colorTable = this.index();
+ this.hash = this.colorTable.reduce(
+ (hash: ColorTableHash, value: TableItem): ColorTableHash => {
+ hash[value.color] = value.index;
+ return hash;
+ },
+ {}
+ );
+ }
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/compare/compare.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/compare/compare.component.css
new file mode 100644
index 000000000..c2ccebcb0
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/compare/compare.component.css
@@ -0,0 +1,3 @@
+.slide {
+ flex: 0 0 100vw;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/compare/compare.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/compare/compare.component.html
new file mode 100644
index 000000000..e69de29bb
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/compare/compare.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/compare/compare.component.spec.ts
new file mode 100644
index 000000000..b83c4b54a
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/compare/compare.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { CompareComponent } from './compare.component';
+
+describe('CompareComponent', () => {
+ let component: CompareComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [CompareComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(CompareComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/compare/compare.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/compare/compare.component.ts
new file mode 100644
index 000000000..bd2997c14
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/compare/compare.component.ts
@@ -0,0 +1,12 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-compare',
+ templateUrl: './compare.component.html',
+ styleUrls: ['./compare.component.css']
+})
+export class CompareComponent implements OnInit {
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/fake-gif/fake-gif.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/fake-gif/fake-gif.component.css
new file mode 100644
index 000000000..0696bbc01
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/fake-gif/fake-gif.component.css
@@ -0,0 +1,3 @@
+* {
+ font-family: Monaco, 'Lucida Console', monospace;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/fake-gif/fake-gif.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/fake-gif/fake-gif.component.html
new file mode 100644
index 000000000..84f9f6d83
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/fake-gif/fake-gif.component.html
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
This is always "87a" or "89a"
+
Width of the image
+
Height of the image
+
+
Whether global palette is present
+
Number of bits per primary color available
+
Whether the palette is sorted
+
+ Specifies number of colors in the palette proportional a power of two. e.g.
+
+
+ If present specifies index of a color in the global color table that would
+ be transparent
+
+
Ratio of the pixel
+
+
Reserved bits
+
+ Disposal Method - Indicates the way in which the graphic is to be treated
+ after being displayed. Values : 0 - No disposal specified. The decoder is
+ not required to take any action. 1 - Do not dispose. The graphic is to be
+ left in place. 2 - Restore to background color. The area used by the graphic
+ must be restored to the background color. 3 - Restore to previous. The
+ decoder is required to restore the area overwritten by the graphic with what
+ was there prior to rendering the graphic. 4-7 - To be defined.
+
+
+ Not used, the initial intention was to allow user interactions
+
+
+ Whether the frame should have a transparent color
+
+
Animation delay for next image
+
Optional transparent color index
+
Horizontal shift in pixels
+
Vertical shift in pixels
+
Width of the image
+
Height of the image
+
Whether the image has local palette
+
+ Indicates if the image is interlaced.
+
+
Whether local palette is sorted
+
Bucket of sizes of local palette.
+
+
+ Identifies the Netscape Looping Extension. This field contains the fixed
+ value 0x01
+
+
Size of the extension block in bytes
+
Number of animation loops
+
This is the actual image encoded with LZW
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/fake-gif/fake-gif.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/fake-gif/fake-gif.component.spec.ts
new file mode 100644
index 000000000..a3da8fa5a
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/fake-gif/fake-gif.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { FakeGifComponent } from './fake-gif.component';
+
+describe('FakeGifComponent', () => {
+ let component: FakeGifComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [FakeGifComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(FakeGifComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/fake-gif/fake-gif.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/fake-gif/fake-gif.component.ts
new file mode 100644
index 000000000..7ae853bcd
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/fake-gif/fake-gif.component.ts
@@ -0,0 +1,77 @@
+import {
+ AfterViewInit,
+ Component,
+ EventEmitter,
+ Input,
+ Output,
+ ViewChild
+} from '@angular/core';
+import { BinaryParser } from '../parser/binary-parser';
+import { gifParser } from './gif-parser';
+import { extractMessages } from '@codelab/utils/src/lib/i18n/i18n-tools';
+
+interface Chunk {
+ name: string;
+ size: number;
+ value: string;
+ start?: number;
+}
+
+@Component({
+ selector: 'kirjs-fake-gif',
+ templateUrl: './fake-gif.component.html',
+ styleUrls: ['./fake-gif.component.css']
+})
+export class FakeGifComponent implements AfterViewInit {
+ t: { [key: string]: string };
+ @Input()
+ spacing = false;
+ showMeta = true;
+ @Input() binary: string;
+ @Input() highlightedMap: Record = {};
+ @Input() highlightGroups = false;
+ @Input() preview = true;
+ @Input() filterClassName = /./;
+ @Input() mini = false;
+ @Input() showPopups = false;
+ @Output() binaryUpdate = new EventEmitter();
+ gif: string;
+ parser: BinaryParser;
+
+ @ViewChild('translations', { static: false }) translation;
+
+ constructor() {}
+
+ upload(file) {
+ const reader = new FileReader();
+
+ reader.onloadend = (e: any) => {
+ const result = new Uint8Array(e.target.result);
+ const binaries = Array.from(result)
+ .map(a => a.toString(2))
+ .map(a => (a as any).padStart(8, 0));
+ this.binary = binaries.join('');
+ };
+
+ reader.readAsArrayBuffer(file.files[0]);
+ }
+
+ update(chunk, value) {
+ const len = chunk.end - chunk.start;
+ value = value.padEnd(len, 0).slice(0, len);
+ this.binary =
+ this.binary.slice(0, chunk.start) + value + this.binary.substr(chunk.end);
+ this.binaryUpdate.emit(this.binary);
+ }
+
+ ngAfterViewInit() {
+ requestAnimationFrame(() => {
+ this.t = extractMessages(this.translation);
+ this.parser = new BinaryParser().block('gif', gifParser(this.t));
+ });
+ }
+
+ updateChunk({ chunk, value }) {
+ this.update(chunk, value);
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/fake-gif/gif-parser.ts b/codelab-master/apps/kirjs/src/app/modules/binary/fake-gif/gif-parser.ts
new file mode 100644
index 000000000..efde1c0b2
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/fake-gif/gif-parser.ts
@@ -0,0 +1,131 @@
+import { BinaryParser } from '../parser/binary-parser';
+import { lzw } from './gif';
+
+export function gifParser(t: { [key: string]: string }) {
+ const header = new BinaryParser()
+ .string('headerConst', { length: 3, description: t.headerConst })
+ .string('version', { length: 3, description: t.version })
+ .uInt16('width', { description: t.width })
+ .uInt16('height', { description: t.height })
+ .boolean('globalPalette', { description: t.globalPalette })
+ .bit3('resolution', { type: 'number', description: t.resolution })
+ .boolean('isPaletteSorted', { description: t.isPaletteSorted })
+ .bit3('paletteSize', { type: 'number', description: t.paletteSize })
+ .uInt8('background', { description: t.background })
+ .uInt8('Ratio', { description: t.ratio });
+
+ const commentParser = new BinaryParser()
+ .string('comment', { readUntil: '00000000' })
+ .hex('end', { length: 2 });
+
+ const palette = new BinaryParser().array('palette', {
+ parser: new BinaryParser().hex('color', {
+ length: 6,
+ type: 'color'
+ }),
+ length(data) {
+ const paletteSize = data
+ .find(d => d.name === '_parent')
+ .value.find(d => d.name === 'header')
+ .value.find(d => d.name === 'paletteSize').value;
+ const size = parseInt(paletteSize, 2);
+ return 2 ** (size + 1);
+ }
+ });
+
+ const netscapeParser = new BinaryParser()
+ .uInt8('extensionSize', { description: t.extensionSize })
+ .constBits('00000001', { description: t.netscapeLoopingExtensionId })
+ .uInt16('loops', { description: t.loops })
+ .constBits('00000000', { description: '' });
+
+ const xmpParser = new BinaryParser()
+ .string('data', {
+ readUntil: '00000000'
+ })
+ .hex('end', { length: 4 });
+
+ const extensionParser = new BinaryParser()
+ .hex('0b', { length: 2 })
+ .string('type', { length: 8 })
+ .string('code', { length: 3 })
+ .choice('data', {
+ key: 'type',
+ values: {
+ NETSCAPE: netscapeParser,
+ 'XMP Data': xmpParser
+ }
+ });
+
+ const graphicControlParser = new BinaryParser()
+ .hex('const', { length: 2 })
+ .constBits('000', { description: t.reservedBits })
+ .bit3('disposalMethod', { type: 'enums', description: t.disposalMethod })
+ .boolean('UI', { description: t.UI })
+ .boolean('isTransparent', { description: t.isTransparent })
+ .uInt16('delay', { description: t.delay })
+ .uInt8('transparentColor', { description: t.transparentColor })
+ .constBits('00000000');
+
+ const exclamationMarkParser = new BinaryParser()
+ .hex('subtype', { length: 2 })
+ .choice('extension', {
+ key: 'subtype',
+ values: {
+ f9: graphicControlParser,
+ ff: extensionParser,
+ fe: commentParser
+ }
+ });
+
+ const imageDescriptorParser = new BinaryParser()
+ .uInt16('left', { description: t.left })
+ .uInt16('top', { description: t.top })
+ .uInt16('imageWidth', { description: t.imageWidth })
+ .uInt16('imageHeight', { description: t.imageHeight })
+ .boolean('localPalette', { description: t.localPalette })
+ .boolean('isImageInterlacingEnabld', {
+ description: t.isImageInterlacingEnabld
+ })
+ .boolean('isLocalPaletteSorted', { description: t.isLocalPaletteSorted })
+ .constBits('00', { description: t.reservedBits })
+ .bit3('localPaletteSize', {
+ type: 'enums',
+ description: t.localPaletteSize
+ })
+ .uInt8('colorDepth')
+ .uInt8('blockSize')
+ .bit('graphicBlock', {
+ description: t.graphicBlock,
+ length: fields => {
+ return (
+ (Object as any).values(fields).find(a => a.name === 'blockSize')
+ .value * 8
+ );
+ },
+ converter(bits) {
+ return lzw(
+ 2,
+ bits.match(/.{8}/g).map(a => parseInt(a, 2)),
+ 4
+ );
+ }
+ })
+ .constBits('00000000');
+
+ const body = new BinaryParser()
+ .string('marker', { length: 1 })
+ .choice('extension', {
+ key: 'marker',
+ values: {
+ '!': exclamationMarkParser,
+ ';': new BinaryParser(),
+ ',': imageDescriptorParser
+ }
+ });
+
+ return new BinaryParser()
+ .block('header', header)
+ .block('palette', palette)
+ .array('extensions', { parser: body, length: 200 });
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/fake-gif/gif.ts b/codelab-master/apps/kirjs/src/app/modules/binary/fake-gif/gif.ts
new file mode 100644
index 000000000..ef2f3c1e2
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/fake-gif/gif.ts
@@ -0,0 +1,115 @@
+export function lzw(minCodeSize, data, pixelCount) {
+ const MAX_STACK_SIZE = 4096;
+ const nullCode = -1;
+
+ const npix = pixelCount;
+ let available,
+ clear,
+ code_mask,
+ code_size,
+ end_of_information,
+ in_code,
+ old_code,
+ bits,
+ code,
+ i,
+ datum,
+ data_size,
+ first,
+ top,
+ bi,
+ pi;
+
+ const dstPixels = new Array(pixelCount);
+ const prefix = new Array(MAX_STACK_SIZE);
+ const suffix = new Array(MAX_STACK_SIZE);
+ const pixelStack = new Array(MAX_STACK_SIZE + 1);
+
+ // Initialize GIF data stream decoder.
+ data_size = minCodeSize;
+ clear = 1 << data_size;
+ end_of_information = clear + 1;
+ available = clear + 2;
+ old_code = nullCode;
+ code_size = data_size + 1;
+ code_mask = (1 << code_size) - 1;
+ for (code = 0; code < clear; code++) {
+ prefix[code] = 0;
+ suffix[code] = code;
+ }
+
+ // Decode GIF pixel stream.
+ datum = bits = first = top = pi = bi = 0;
+
+ for (i = 0; i < npix; ) {
+ if (top === 0) {
+ if (bits < code_size) {
+ // get the next byte
+ datum += data[bi] << bits;
+
+ bits += 8;
+ bi++;
+ continue;
+ }
+ // Get the next code.
+ code = datum & code_mask;
+ datum >>= code_size;
+ bits -= code_size;
+ // Interpret the code
+ if (code > available || code === end_of_information) {
+ break;
+ }
+
+ if (code === clear) {
+ // Reset decoder.
+ code_size = data_size + 1;
+ code_mask = (1 << code_size) - 1;
+ available = clear + 2;
+ old_code = nullCode;
+ continue;
+ }
+ if (old_code === nullCode) {
+ pixelStack[top++] = suffix[code];
+ old_code = code;
+ first = code;
+ continue;
+ }
+ in_code = code;
+ if (code === available) {
+ pixelStack[top++] = first;
+ code = old_code;
+ }
+ while (code > clear) {
+ pixelStack[top++] = suffix[code];
+ code = prefix[code];
+ }
+
+ first = suffix[code] & 0xff;
+ pixelStack[top++] = first;
+
+ // add a new string to the table, but only if space is available
+ // if not, just continue with current table until a clear code is found
+ // (deferred clear code implementation as per GIF spec)
+ if (available < MAX_STACK_SIZE) {
+ prefix[available] = old_code;
+ suffix[available] = first;
+ available++;
+ if ((available & code_mask) === 0 && available < MAX_STACK_SIZE) {
+ code_size++;
+ code_mask += available;
+ }
+ }
+ old_code = in_code;
+ }
+ // Pop a pixel off the pixel stack.
+ top--;
+ dstPixels[pi++] = pixelStack[top];
+ i++;
+ }
+
+ for (i = pi; i < npix; i++) {
+ dstPixels[i] = 0; // clear missing pixels
+ }
+
+ return dstPixels;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/gif-palette/gif-palette.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/gif-palette/gif-palette.component.css
new file mode 100644
index 000000000..0696bbc01
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/gif-palette/gif-palette.component.css
@@ -0,0 +1,3 @@
+* {
+ font-family: Monaco, 'Lucida Console', monospace;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/gif-palette/gif-palette.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/gif-palette/gif-palette.component.html
new file mode 100644
index 000000000..38d23e791
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/gif-palette/gif-palette.component.html
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/gif-palette/gif-palette.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/gif-palette/gif-palette.component.spec.ts
new file mode 100644
index 000000000..ffc888a25
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/gif-palette/gif-palette.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { GifPaletteComponent } from './gif-palette.component';
+
+describe('GifPaletteComponent', () => {
+ let component: GifPaletteComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [GifPaletteComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(GifPaletteComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/gif-palette/gif-palette.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/gif-palette/gif-palette.component.ts
new file mode 100644
index 000000000..7e35fad90
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/gif-palette/gif-palette.component.ts
@@ -0,0 +1,45 @@
+import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+
+interface Chunk {
+ name: string;
+ size: number;
+ value: string;
+ start?: number;
+}
+
+@Component({
+ selector: 'kirjs-gif-palette',
+ templateUrl: './gif-palette.component.html',
+ styleUrls: ['./gif-palette.component.css']
+})
+export class GifPaletteComponent implements OnInit {
+ @Output() change = new EventEmitter();
+
+ colors: number[][];
+
+ private _value = '';
+
+ get value() {
+ return this._value;
+ }
+
+ @Input()
+ set value(val: string) {
+ this._value = val;
+ this.colors = Array.from(val.match(/.{24}/g)).map(a =>
+ Array.from(a.match(/.{8}/g)).map(str => parseInt(str, 2))
+ );
+ }
+
+ serialize() {
+ this._value = this.colors
+ .map(c =>
+ c
+ .map(p => ((+p).toString(2) as any).padStart(8, 0).slice(0, 8))
+ .join('')
+ )
+ .join('');
+ }
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/hexdec/hexdec.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/hexdec/hexdec.component.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/hexdec/hexdec.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/hexdec/hexdec.component.html
new file mode 100644
index 000000000..848591c57
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/hexdec/hexdec.component.html
@@ -0,0 +1,7 @@
+Converting bin to hex
+
+
+
{{ n.hex }}
+
{{ n.bin }}
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/hexdec/hexdec.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/hexdec/hexdec.component.spec.ts
new file mode 100644
index 000000000..d821855aa
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/hexdec/hexdec.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { HexdecComponent } from './hexdec.component';
+
+describe('HexdecComponent', () => {
+ let component: HexdecComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [HexdecComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(HexdecComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/hexdec/hexdec.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/hexdec/hexdec.component.ts
new file mode 100644
index 000000000..3824c6c6c
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/hexdec/hexdec.component.ts
@@ -0,0 +1,17 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-hexdec',
+ templateUrl: './hexdec.component.html',
+ styleUrls: ['./hexdec.component.css']
+})
+export class HexdecComponent implements OnInit {
+ numbers = new Array(16).fill(0).map((a, i) => ({
+ bin: i.toString(2).padStart(4, '0'),
+ hex: i.toString(16)
+ }));
+
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/html-post/html-post.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/html-post/html-post.component.css
new file mode 100644
index 000000000..5c39ddde2
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/html-post/html-post.component.css
@@ -0,0 +1,5 @@
+:host {
+ padding: 2vw;
+ display: block;
+ zoom: 3;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/html-post/html-post.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/html-post/html-post.component.html
new file mode 100644
index 000000000..a3642dee7
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/html-post/html-post.component.html
@@ -0,0 +1 @@
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/html-post/html-post.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/html-post/html-post.component.spec.ts
new file mode 100644
index 000000000..8864c6ffb
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/html-post/html-post.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { HtmlPostComponent } from './html-post.component';
+
+describe('HtmlPostComponent', () => {
+ let component: HtmlPostComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [HtmlPostComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(HtmlPostComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/html-post/html-post.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/html-post/html-post.component.ts
new file mode 100644
index 000000000..10e09699b
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/html-post/html-post.component.ts
@@ -0,0 +1,20 @@
+import { Component, Input } from '@angular/core';
+import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
+
+@Component({
+ selector: 'kirjs-html-post',
+ templateUrl: './html-post.component.html',
+ styleUrls: ['./html-post.component.css']
+})
+export class HtmlPostComponent {
+ html: SafeHtml;
+
+ constructor(private sanitizer: DomSanitizer) {
+ this.html = sanitizer.bypassSecurityTrustHtml('');
+ }
+
+ @Input()
+ set param(html: string) {
+ this.html = this.sanitizer.bypassSecurityTrustHtml(html);
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/json/json.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/json/json.component.html
new file mode 100644
index 000000000..49a5db746
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/json/json.component.html
@@ -0,0 +1,85 @@
+
+
+
+ Data as JSON ({{ codeLength }} bytes )
+
+
+
+
+
+ Binary data ({{ binariesLength }} bytes )
+
+
{{ error }}
+
+
+ {{ item.binary }}
+
+ {{ item.type }}
+
+
+ {{ l.value }}
+ {{ l.bin }}
+
+
+
+ {{
+ item.value
+ }}
+ {{ item.binary }}
+
+
+ {{
+ item.value
+ }}
+ {{ item.binary }}
+
+
+
+
+
+ Schema ({{ schemaLength }} bytes )
+
+
+
+ {{ item.value }}
+
+
+
+
+Next
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/json/json.component.scss b/codelab-master/apps/kirjs/src/app/modules/binary/json/json.component.scss
new file mode 100644
index 000000000..f4972b80b
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/json/json.component.scss
@@ -0,0 +1,89 @@
+.wrapper {
+ font-size: 3vw;
+ word-break: break-all;
+}
+
+.code {
+ white-space: pre-wrap;
+ font-size: 2vw;
+ margin-right: 2vw;
+ margin-left: 1vw;
+}
+
+.binary .selected {
+ display: block;
+ box-shadow: 0 0 4px 1px #444;
+ background: #eee;
+ font-size: 3vw;
+}
+
+.code .selected {
+ color: #444;
+ font-size: 3vw;
+ box-shadow: 0 0 4px 1px #444;
+ background: #eee;
+}
+
+.detail {
+ display: none;
+}
+
+.selected .detail {
+ display: block;
+}
+
+.selected .value {
+ display: none;
+}
+
+:host ::ng-deep {
+ .highlight-0 {
+ background: rgba(255, 124, 0, 0.47);
+ }
+
+ .highlight-1 {
+ background: rgba(255, 239, 0, 0.47);
+ }
+
+ .highlight-2 {
+ background: #00ff29;
+ }
+
+ .highlight-3 {
+ background: #00ffe7;
+ }
+
+ .highlight-4 {
+ background: rgba(0, 177, 255, 0.46);
+ }
+
+ .highlight-5 {
+ background: rgba(185, 0, 255, 0.29);
+ }
+
+ .highlight-6 {
+ background: rgba(255, 0, 89, 0.47);
+ }
+
+ .highlight-7 {
+ background: rgba(255, 115, 0, 0.4);
+ }
+}
+
+h2 {
+ font-size: 3vw !important;
+}
+
+.error::before {
+ color: #e51400;
+ content: '🙀';
+}
+
+.error {
+ color: #e51400;
+ border: 1px #e51400 solid;
+ border-radius: 12px;
+ font-size: 3vw;
+ padding: 2vw;
+ display: block;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/json/json.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/json/json.component.spec.ts
new file mode 100644
index 000000000..910c7b653
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/json/json.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { JsonComponent } from './json.component';
+
+describe('JsonComponent', () => {
+ let component: JsonComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [JsonComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(JsonComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/json/json.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/json/json.component.ts
new file mode 100644
index 000000000..1a99e25e3
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/json/json.component.ts
@@ -0,0 +1,116 @@
+import { Component, Input, OnInit } from '@angular/core';
+
+function strToBin(s: string) {
+ return Array.from(new TextEncoder().encode(s))
+ .map(a => a.toString(2).padStart(8, '0'))
+ .join('');
+}
+
+@Component({
+ selector: 'kirjs-json',
+ templateUrl: './json.component.html',
+ styleUrls: ['./json.component.scss']
+})
+export class JsonComponent implements OnInit {
+ @Input() code = `{
+ "name": "Sarah",
+ "test": true,
+ "something": 1212
+}`;
+
+ match = [];
+
+ index = 0;
+ binaries: any[];
+ binariesLength: number;
+ codeLength: number;
+ schema: { value: string }[] = [];
+ schemaLength: number;
+ error: string;
+
+ constructor() {}
+
+ handleLineChange({ value: code, lineNumber }) {
+ this.binaries = [
+ {
+ binary: '',
+ comment: `we don't need to encode curly braces :)`
+ }
+ ];
+
+ let val;
+ try {
+ val = JSON.parse(code);
+ this.error = '';
+ } catch (e) {
+ this.error = e.message;
+ return;
+ }
+
+ this.binaries = this.binaries.concat(
+ Object.keys(val).map(key => {
+ const value = val[key];
+ const data: any = {};
+
+ data.key = key;
+ data.key = key;
+ if (typeof value === 'boolean') {
+ data.binary = Number(value);
+ data.type = 'boolean';
+ data.comment = 'just one bit!';
+ } else if (typeof value === 'number') {
+ data.binary = value
+ .toString(2)
+ .padStart(Math.ceil(Math.log2(value + 1) / 8) * 8, '0');
+ data.type = 'number';
+ data.comment = 'Number';
+ } else if (typeof value === 'string') {
+ data.binary = strToBin(value) + '0000000000000000';
+ data.display = value
+ .split('')
+ .map(value => ({
+ value,
+ bin: (value.charCodeAt(0).toString(2) as any).padStart(8, 0)
+ }))
+ .concat({ value: 'Separator', bin: '000000000000000000' });
+ data.type = 'string';
+ data.comment = 'String!';
+ }
+ data.value = value;
+
+ return data;
+ })
+ );
+
+ this.schema = [
+ {
+ value: 'message {',
+ className: ''
+ }
+ ]
+ .concat(
+ this.binaries.slice(1).map((b, i) => ({
+ value: ` ${b.type} ${b.key} = ${i};`,
+ className: 'highlight-' + i
+ }))
+ )
+ .concat({
+ value: '}',
+ className: ''
+ });
+
+ this.schemaLength = this.schema.map(s => s.value).join('').length;
+ this.match = code
+ .split('\n')
+ .map((a, i) => ({ match: a.trim(), className: `highlight-${i}` }));
+ this.index = lineNumber - 1;
+ this.codeLength = code.replace(/\s/g, '').length;
+ this.binariesLength = Math.ceil(
+ this.binaries
+ .map(a => a.binary.toString().length)
+ .reduce((a, b) => a + b, 0) / 8
+ );
+ }
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/memory/memory.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/memory/memory.component.css
new file mode 100644
index 000000000..cf66893d1
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/memory/memory.component.css
@@ -0,0 +1,95 @@
+.memory {
+ display: flex;
+ flex-wrap: wrap;
+ width: 100%;
+ flex-shrink: 0;
+}
+
+.cell {
+ font-size: 1vw;
+ color: #999;
+ width: 5.7vw;
+ box-sizing: border-box;
+
+ margin-right: 0.3vw;
+ height: 6vw;
+ background: #ddd;
+ margin-bottom: 0.5vw;
+ padding: 0.5vw;
+ border: 1px #999 solid;
+}
+
+.value {
+ font-size: 3vw;
+}
+
+.index {
+ font-size: 1.5vw;
+ vertical-align: top;
+ padding: 0.2vw;
+ color: #444;
+ width: 2vw;
+ display: inline-block;
+}
+
+.cell.cell-empty {
+ background: #ffffff;
+}
+
+.cell.cell-boolean {
+ background: #444444;
+ color: #bbb;
+}
+
+.cell.selected2.selected2.selected2,
+.cell.cell-selected2 {
+ background: #ff9900;
+ color: #444;
+}
+
+.cell.cell-number.selected,
+.cell.cell-selected.cell-selected.cell-selected {
+ background: #ffff00;
+ color: #444;
+}
+
+.cell.cell-number-end-highlight,
+.cell.cell-number-highlight {
+ background: #ff0;
+ color: #444;
+}
+
+.cell.cell-cell-number-end,
+.cell.cell-number {
+ background: #444444;
+ color: #bbb;
+}
+
+.cell.cell-cell-number-end .index,
+.cell.cell-number .index {
+ color: #999;
+}
+
+.cell.cell-number.cell-selected,
+.cell.cell-number-highlight,
+.cell.cell-number {
+ width: 6vw;
+ margin-right: 0;
+ border-right: 0;
+ border-left-style: dotted;
+}
+
+.number.number {
+ background: #9f0;
+ color: black;
+}
+
+.bool.bool {
+ background: #f90;
+ color: black;
+}
+
+.link.link {
+ background: #00c8ff;
+ color: black;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/memory/memory.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/memory/memory.component.html
new file mode 100644
index 000000000..a130045e2
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/memory/memory.component.html
@@ -0,0 +1,19 @@
+
+
+
+
+ {{ i }}
+ {{ cell.value }}
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/memory/memory.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/memory/memory.component.spec.ts
new file mode 100644
index 000000000..babb4e4d2
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/memory/memory.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { MemoryComponent } from './memory.component';
+
+describe('MemoryComponent', () => {
+ let component: MemoryComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [MemoryComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(MemoryComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/memory/memory.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/memory/memory.component.ts
new file mode 100644
index 000000000..bb051f4df
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/memory/memory.component.ts
@@ -0,0 +1,194 @@
+import { Component, Input, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-memory',
+ templateUrl: './memory.component.html',
+ styleUrls: ['./memory.component.css']
+})
+export class MemoryComponent implements OnInit {
+ @Input() param = 0;
+ @Input() code = '';
+ start = 0;
+
+ memory = Array.from({ length: 64 }).fill({
+ value: 0,
+ type: 'empty'
+ }) as any;
+
+ constructor() {}
+
+ allocValues(values, classes = []) {
+ let i = 0;
+ for (let x = 0; x < values.length; x++) {
+ const v = values[x];
+ for (let y = 0; y < v.length; y++) {
+ this.memory[i] = {
+ value: v[y],
+ type:
+ (y === v.length - 1 ? 'cell-number-end' : 'number') +
+ ' ' +
+ (classes[x] || '')
+ };
+
+ i++;
+ }
+ }
+ }
+
+ highlightBoolean(i: number) {
+ this.memory[i].type =
+ (this.memory[i].type || '') + ' selected cell-selected';
+ }
+
+ highlightShouldBe(i: number) {
+ this.memory[i].type = (this.memory[i].type || '') + ' selected2';
+ }
+
+ highlightNumber(i: number) {
+ for (let y = 0; y < 8; y++) {
+ this.memory[i * 8 + y] = {
+ value: Math.round(Math.random()),
+ type: y === 7 ? 'number-end-highlight' : 'number-highlight'
+ };
+ }
+ }
+
+ ngOnInit() {
+ if (this.param === 0) {
+ return;
+ }
+
+ if (this.param === 1) {
+ this.allocValues('00000'.split(''));
+ }
+
+ if (this.param === 2) {
+ this.allocValues('00000'.split(''));
+ this.highlightBoolean(3);
+ }
+
+ if (this.param === 3) {
+ this.allocValues([
+ '00000000',
+ '00000000',
+ '00000000',
+ '00000000',
+ '00000000'
+ ]);
+ }
+
+ if (this.param === 4) {
+ this.allocValues([
+ '00000000',
+ '00000000',
+ '00000000',
+ '00000000',
+ '00000000'
+ ]);
+ this.highlightNumber(3);
+ }
+
+ if (this.param === 5) {
+ this.allocValues('10101'.split(''));
+ this.highlightBoolean(3);
+ }
+
+ const bools = '10101'.split('');
+ const num = '00000011';
+ bools[1] = num;
+
+ if (this.param === 6) {
+ this.allocValues(bools);
+ this.highlightBoolean(3);
+ this.highlightShouldBe(10);
+ }
+
+ if (this.param === 7) {
+ const typedArray = [
+ '001',
+ '1',
+ '010',
+ num,
+ '001',
+ '0',
+ '001',
+ '0',
+ '001',
+ '1',
+ '000'
+ ];
+ this.allocValues(typedArray, [
+ ' bool',
+ '',
+ ' number',
+ '',
+ ' bool',
+ '',
+ ' bool',
+ ' cell-selected ',
+ ' bool'
+ ]);
+ }
+
+ const typedArray = [
+ '011110',
+ '010010',
+ '101101',
+ '110001',
+ '110101',
+ '001',
+ '1',
+ '010',
+ num,
+ '001',
+ '0',
+ '001',
+ '0',
+ '001',
+ '1'
+ ];
+ if (this.param === 8) {
+ this.allocValues(typedArray, [
+ ' link',
+ ' link',
+ ' link',
+ ' link',
+ ' link',
+ ' bool',
+ '',
+ ' number',
+ '',
+ ' bool',
+ '',
+ ' bool',
+ '',
+ ' bool'
+ ]);
+ }
+
+ if (this.param === 9) {
+ const typedArrayWidhBool = [...typedArray, '001', '0'];
+
+ typedArrayWidhBool[1] = '111001';
+
+ this.allocValues(typedArrayWidhBool, [
+ ' link',
+ ' link',
+ ' link',
+ ' link highlight',
+ ' link',
+ ' bool',
+ '',
+ ' bool',
+ '',
+ ' bool',
+ '',
+ ' bool',
+ '',
+ ' bool',
+ '',
+ ' bool'
+ ]);
+ }
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/message/message.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/message/message.component.css
new file mode 100644
index 000000000..6cefa6eb5
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/message/message.component.css
@@ -0,0 +1,27 @@
+.blocks {
+ display: flex;
+ flex-wrap: wrap;
+}
+
+.block {
+ font-size: 1.5vw;
+ color: #444;
+}
+
+.basic .block {
+ padding: 0;
+ font-size: 3vw;
+}
+
+.bytes .block {
+ font-size: 3vw;
+}
+
+.human {
+ font-size: 4vw;
+}
+
+.block {
+ padding: 1vw;
+ text-align: center;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/message/message.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/message/message.component.html
new file mode 100644
index 000000000..97dcade91
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/message/message.component.html
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ block.bin }}
+
{{ block.human }}
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/message/message.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/message/message.component.spec.ts
new file mode 100644
index 000000000..697ba47fb
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/message/message.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { MessageComponent } from './message.component';
+
+describe('MessageComponent', () => {
+ let component: MessageComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [MessageComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(MessageComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/message/message.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/message/message.component.ts
new file mode 100644
index 000000000..8d9ab6846
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/message/message.component.ts
@@ -0,0 +1,106 @@
+import { Component, Input, OnInit } from '@angular/core';
+
+function toByte(message) {
+ return Array.from(message.match(/.{8}/gi)).map(bin => ({
+ className: 'basic',
+ bin
+ }));
+}
+
+const transforms = {
+ basic: toByte,
+ bytes: toByte,
+ boolean(message) {
+ return message.split('').map(bin => {
+ return {
+ className: 'basic',
+ bin,
+ human: (!!Number(bin)).toString()
+ };
+ });
+ },
+ uint16(message) {
+ return Array.from(message.match(/.{16}/gi)).map(bin => ({
+ className: 'basic',
+ bin,
+ human: parseInt(bin as string, 2)
+ }));
+ },
+ uint17(message) {
+ return Array.from(message.match(/.{17}/gi)).map(bin => ({
+ className: 'basic',
+ bin,
+ human: parseInt(bin as string, 2)
+ }));
+ },
+ uint32(message) {
+ return Array.from(message.match(/.{32}/gi)).map(bin => ({
+ className: 'basic',
+ bin,
+ human: parseInt(bin as string, 2)
+ }));
+ },
+ hex(message) {
+ return Array.from(message.match(/.{8}/gi)).map((bin: string) => ({
+ className: 'basic',
+ bin,
+ human: parseInt(bin, 2).toString(16)
+ }));
+ },
+ uint8(message) {
+ return Array.from(message.match(/.{8}/gi)).map(bin => ({
+ className: 'basic',
+ bin,
+ human: parseInt(bin as string, 2)
+ }));
+ },
+ int8(message) {
+ return Array.from(message.match(/.{8}/gi)).map(bin => {
+ const sign = !!(Number(bin) & 128) ? 1 : -1;
+ return {
+ className: 'basic',
+ bin,
+ human: sign * (Number(bin) & 127)
+ };
+ });
+ },
+ string(message) {
+ return Array.from(message.match(/.{8}/gi)).map((bin: string) => ({
+ className: 'basic',
+ bin,
+ human: String.fromCharCode(parseInt(bin, 2))
+ }));
+ }
+};
+
+@Component({
+ selector: 'kirjs-message',
+ templateUrl: './message.component.html',
+ styleUrls: ['./message.component.css']
+})
+export class MessageComponent implements OnInit {
+ message =
+ '0100111001100101011101100110010101110010001000000110011101101111011011100110111001100001001000000110011' +
+ '101101001011101100110010100100000011110010110111101110101001000000111010101110000001000000100111001100101011101' +
+ '100110010101110010001000000110011101101111011011100110111001100001001000000110110001100101011101000010000001111' +
+ '00101101111011101010010000001100100011011110111011101101110';
+
+ mode = 1;
+ display = 'boolean';
+
+ blocks = transforms[this.display](this.message);
+
+ constructor() {}
+
+ @Input()
+ set param(value: string) {
+ this.setDisplay(value);
+ }
+
+ setDisplay(value: string) {
+ this.display = value;
+ this.blocks = transforms[this.display](this.message);
+ }
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/midi/midi.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/midi/midi.component.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/midi/midi.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/midi/midi.component.html
new file mode 100644
index 000000000..410958cad
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/midi/midi.component.html
@@ -0,0 +1,8 @@
+
+ meta
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/midi/midi.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/midi/midi.component.spec.ts
new file mode 100644
index 000000000..4d9326d49
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/midi/midi.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { MidiComponent } from './midi.component';
+
+describe('MidiComponent', () => {
+ let component: MidiComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [MidiComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(MidiComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/midi/midi.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/midi/midi.component.ts
new file mode 100644
index 000000000..eb4e5f58d
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/midi/midi.component.ts
@@ -0,0 +1,122 @@
+import { Component, OnInit } from '@angular/core';
+import { BinaryParser } from '../parser/binary-parser';
+import { BinaryReaderResult } from '../parser/readers/abstract-reader';
+import { StringBinaryReader } from '../parser/readers/string-reader';
+import { StringParser } from '../parser/parsers/string-parser';
+
+@Component({
+ selector: 'kirjs-midi',
+ templateUrl: './midi.component.html',
+ styleUrls: ['./midi.component.css']
+})
+export class MidiComponent implements OnInit {
+ showMeta = true;
+ binary: string;
+ parser: BinaryParser;
+ s: BinaryReaderResult;
+
+ constructor() {}
+
+ updateBinary(e: Event) {}
+
+ ngOnInit() {
+ this.binary = localStorage.getItem('midi');
+
+ const header = new BinaryParser()
+ .string('headerConst', { length: 4 })
+ .uInt32('6')
+ .uInt16('Single multi-channel track')
+ .uInt16('Number of tracs')
+ .uInt16('Time-code-based time');
+
+ const timeSignatureParser = new BinaryParser()
+ .uInt8('upper')
+ .uInt8('lower')
+ .uInt8('clocks')
+ .uInt8('something');
+
+ const theEnd = new BinaryParser().uInt8('00');
+
+ const metaParser = new BinaryParser()
+ .uInt8('subtype')
+ .uInt8('length')
+ .choice('value', {
+ parser(data) {
+ const type = (Object as any)
+ .values(data)
+ .find(l => l.name === 'subtype').rawValue;
+ const length = (Object as any)
+ .values(data)
+ .find(l => l.name === 'length').value;
+ const parsers = {
+ '00000011': new StringParser({ length }),
+ '00000010': new StringParser({ length }),
+ '01011000': timeSignatureParser,
+ // tempo
+ '01010001': new BinaryParser().uInt24('value'),
+ '00101111': theEnd
+ };
+
+ if (parsers[type]) {
+ return parsers[type];
+ }
+
+ // tslint:disable-next-line:no-debugger
+ debugger;
+ }
+ });
+
+ const noteSwitch = new BinaryParser()
+ .uInt8('note number')
+ .uInt8('velocity');
+
+ const instrumentChannel = new BinaryParser().uInt8('instrument');
+ const track = new BinaryParser()
+ .varuint7('delta')
+ .uInt8('type')
+ .choice('typeData', {
+ parser: data => {
+ const type = (Object as any).values(data).find(l => l.name === 'type')
+ .rawValue;
+ const parsers = {
+ '11111111': metaParser,
+ '11000000': instrumentChannel,
+ '10010000': noteSwitch,
+ '10000000': noteSwitch
+ };
+
+ if (parsers[type]) {
+ return parsers[type];
+ }
+
+ // tslint:disable-next-line:no-debugger
+ debugger;
+ }
+ });
+
+ const tracks = new BinaryParser()
+ .string('headerConst', { length: 4 })
+ .uInt32('tracklen')
+ .array('tracks', { parser: track, length: 12 });
+
+ this.parser = new BinaryParser()
+ .block('header', header)
+ .block('block', tracks);
+ this.s = this.parser.readOrdered(new StringBinaryReader(this.binary));
+ }
+
+ upload(file) {
+ const reader = new FileReader();
+
+ reader.onloadend = (e: ProgressEvent) => {
+ const result = new Uint8Array((e.target as any).result);
+ const binaries = Array.from(result)
+ .map(a => a.toString(2))
+ .map(a => (a as any).padStart(8, 0));
+ this.binary = binaries.join('');
+ localStorage.setItem('midi', this.binary);
+ };
+
+ reader.readAsArrayBuffer(file.files[0]);
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/parser/binary-parser.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/parser/binary-parser.spec.ts
new file mode 100644
index 000000000..056fb8d8a
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/parser/binary-parser.spec.ts
@@ -0,0 +1,109 @@
+import { StringBinaryReader } from './readers/string-reader';
+import { BinaryParser } from './binary-parser';
+
+describe('BinaryParser', () => {
+ beforeEach(() => {
+ const s = 'Universal Serial Bus'
+ .split('')
+ .map(a => a.charCodeAt(0))
+ .map(a => a.toString(2))
+ .map(a => (a as any).padStart(8, 0))
+ .join('');
+ this.reader = new StringBinaryReader(s);
+ });
+
+ describe('BinaryParser', () => {
+ it('allows shortcuts', () => {
+ const parser = new BinaryParser()
+ .string('u', { length: 3 })
+ .bit1('a')
+ .bit1('b');
+
+ expect(parser.read(this.reader, {}).value).toEqual({
+ a: '0',
+ b: '1',
+ u: 'Uni'
+ });
+ });
+
+ it('allows nesting', () => {
+ const header = new BinaryParser().bit1('a').bit1('b');
+
+ const parser = new BinaryParser()
+ .block('header', header)
+ .bit1('c')
+ .bit1('d');
+
+ expect(parser.read(this.reader).value).toEqual({
+ header: { a: '0', b: '1' },
+ c: '0',
+ d: '1'
+ });
+ });
+
+ it('tracks position', () => {
+ const header = new BinaryParser().bit1('a').bit1('b');
+
+ const parser = new BinaryParser()
+ .block('header', header)
+ .bit1('c')
+ .bit1('d');
+
+ const result = parser.readOrdered(this.reader).value;
+
+ expect(result).toEqual([
+ {
+ start: 0,
+ end: 2,
+ length: 2,
+ name: 'header',
+ value: [
+ {
+ start: 0,
+ end: 1,
+ length: 1,
+ name: 'a',
+ value: '0',
+ rawValue: '0',
+ type: 'bits'
+ },
+ {
+ start: 1,
+ end: 2,
+ length: 1,
+ name: 'b',
+ value: '1',
+ rawValue: '1',
+ type: 'bits'
+ }
+ ],
+ rawValue: '01',
+ type: 'object'
+ },
+ {
+ start: 2,
+ end: 3,
+ length: 1,
+ name: 'c',
+ value: '0',
+ rawValue: '0',
+ type: 'bits'
+ },
+ {
+ start: 3,
+ end: 4,
+ length: 1,
+ name: 'd',
+ value: '1',
+ rawValue: '1',
+ type: 'bits'
+ }
+ ]);
+ });
+
+ it('allows uint16', () => {
+ const parser = new BinaryParser().uInt16('u');
+ expect(parser.read(this.reader).value).toEqual({ u: 28245 });
+ });
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/parser/binary-parser.ts b/codelab-master/apps/kirjs/src/app/modules/binary/parser/binary-parser.ts
new file mode 100644
index 000000000..0ad924c23
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/parser/binary-parser.ts
@@ -0,0 +1,192 @@
+import { BinaryObjectParser } from './parsers/object-parser';
+import { StringParser, StringParserConfig } from './parsers/string-parser';
+import { BinaryChoiceParser } from './parsers/choice-parser';
+import { BinaryArrayParser } from './parsers/array-parser';
+import { BitParser } from './parsers/bit-parser';
+import { VarUintParser, VarUintParserConfig } from './parsers/var-uint-parser';
+import { BinaryReader } from './readers/abstract-reader';
+import { beToLe32 } from './parsers/common';
+
+export interface BaseConfig {
+ description?: string;
+ length?: number;
+ type?: string;
+ converter?: (a: string) => number;
+ enum?: { [key: string]: string };
+}
+
+export class BinaryParser {
+ type = 'object';
+ private parser: BinaryObjectParser;
+
+ constructor() {
+ this.parser = new BinaryObjectParser();
+ }
+
+ string(name: string, config: StringParserConfig) {
+ this.parser.addStep(name, new StringParser(config));
+ return this;
+ }
+
+ varuint7(name: string, config: Partial = {}) {
+ this.parser.addStep(name, new VarUintParser(config));
+ return this;
+ }
+
+ varuint31(name: string, config: Partial = {}) {
+ this.parser.addStep(
+ name,
+ new VarUintParser({
+ ...config,
+ size: 31
+ })
+ );
+ return this;
+ }
+
+ choice(name: string, config: any) {
+ this.parser.addStep(name, new BinaryChoiceParser({ ...config }));
+ return this;
+ }
+
+ array(name: string, config: any) {
+ this.parser.addStep(name, new BinaryArrayParser({ ...config }));
+ return this;
+ }
+
+ bit(name: string, config: any) {
+ this.parser.addStep(name, new BitParser({ ...config }));
+ return this;
+ }
+
+ block(name: string, parser) {
+ this.parser.addStep(name, parser);
+ return this;
+ }
+
+ constBits(value, config?: Partial) {
+ return this.bit('const', {
+ length: value.length,
+ type: 'const',
+ ...config
+ });
+ }
+
+ boolean(name: string, config?: Partial) {
+ return this.bit(name, { length: 1, type: 'boolean', ...config });
+ }
+
+ bit1(name: string, config?: Partial) {
+ return this.bit(name, { length: 1, ...config });
+ }
+
+ bit2(name: string, config?: Partial) {
+ return this.bit(name, { length: 2, ...config });
+ }
+
+ bit3(name: string, config?: Partial) {
+ return this.bit(name, { length: 3, ...config });
+ }
+
+ bit8(name: string, config?: Partial) {
+ return this.bit(name, { length: 8, ...config });
+ }
+
+ bit32(name: string, config?: Partial) {
+ return this.bit(name, { length: 32, ...config });
+ }
+ bit24(name: string, config?: Partial) {
+ return this.bit(name, { length: 24, ...config });
+ }
+
+ object(name: string, config?: Partial) {
+ return this.bit(name, { length: 1, ...config });
+ }
+
+ uInt16(name: string, config?: Partial) {
+ return this.bit(name, {
+ type: 'number',
+ length: 16,
+ converter: a => {
+ return parseInt(a.slice(8) + a.slice(0, 8), 2);
+ },
+ ...config
+ });
+ }
+
+ uInt24(name: string, config: any = {}) {
+ return this.bit(name, {
+ type: 'number',
+ length: 24,
+ converter: a => {
+ return parseInt(a, 2);
+ },
+ ...config
+ });
+ }
+
+ uInt32(name: string, config?: Partial) {
+ return this.bit(name, {
+ type: 'number',
+ length: 32,
+ converter: a => {
+ return parseInt(a, 2);
+ },
+ ...config
+ });
+ }
+
+ uInt32le(name: string, config?: Partial) {
+ return this.uInt32(name, {
+ converter: a => {
+ return beToLe32(parseInt(a, 2));
+ },
+ ...config
+ });
+ }
+
+ uInt8(name: string, config?: Partial) {
+ return this.bit(name, {
+ type: 'number',
+ subtype: 'uint8',
+ length: 8,
+ converter: a => {
+ return parseInt(a, 2);
+ },
+ ...config
+ });
+ }
+
+ hex(name: string, config?: Partial) {
+ if (typeof config.length === 'function') {
+ // tslint:disable-next-line:no-debugger
+ debugger;
+ // TODO
+ }
+
+ return this.bit(name, {
+ type: 'hex',
+ converter: data => {
+ return Array.from(data.match(/.{4}/g))
+ .map(a => parseInt(a.toString(), 2))
+ .map(a => a.toString(16))
+ .join('');
+ },
+ ...config,
+ length: config.length * 4
+ });
+ }
+
+ read(reader, data: any = {}) {
+ return this.parser.read(reader, data);
+ }
+
+ readOrdered(reader: BinaryReader, data: any = [], start = 0) {
+ const v = this.parser.readOrdered(reader, data, start);
+
+ return {
+ start: start,
+ ...v
+ };
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/abstract-parser.ts b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/abstract-parser.ts
new file mode 100644
index 000000000..5e95e6da3
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/abstract-parser.ts
@@ -0,0 +1,16 @@
+import { BinaryReader, BinaryReaderResult } from '../readers/abstract-reader';
+
+export abstract class AbstractBinaryParser {
+ type: string;
+
+ abstract read(
+ reader: BinaryReader,
+ data: BinaryReaderResult
+ ): BinaryReaderResult;
+
+ abstract readOrdered(
+ reader: BinaryReader,
+ data: any[],
+ start: number
+ ): BinaryReaderResult;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/array-parser.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/array-parser.spec.ts
new file mode 100644
index 000000000..a0caf196d
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/array-parser.spec.ts
@@ -0,0 +1,41 @@
+import { StringParser } from './string-parser';
+import { BinaryArrayParser } from './array-parser';
+import { StringBinaryReader } from '../readers/string-reader';
+
+describe('array parser', () => {
+ beforeEach(() => {
+ const s = 'Universal Serial Bus'
+ .split('')
+ .map(a => a.charCodeAt(0))
+ .map(a => a.toString(2))
+ .map(a => (a as any).padStart(8, 0))
+ .join('');
+ this.reader = new StringBinaryReader(s);
+ });
+
+ it('can read one letter', () => {
+ const parser = new BinaryArrayParser({
+ length: 2,
+ parser: new StringParser({ length: 2 })
+ });
+ expect(parser.read(this.reader).value).toEqual(['Un', 'iv']);
+ });
+
+ it('can read one letter', () => {
+ const parser = new BinaryArrayParser({
+ parser: new StringParser({ length: 2 })
+ });
+ expect(parser.read(this.reader).value).toEqual([
+ 'Un',
+ 'iv',
+ 'er',
+ 'sa',
+ 'l ',
+ 'Se',
+ 'ri',
+ 'al',
+ ' B',
+ 'us'
+ ]);
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/array-parser.ts b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/array-parser.ts
new file mode 100644
index 000000000..c9d55360b
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/array-parser.ts
@@ -0,0 +1,75 @@
+import { AbstractBinaryParser } from './abstract-parser';
+import { BinaryReader, BinaryReaderResult } from '../readers/abstract-reader';
+import { resolveFunctionOrvalue, resolveLengthOrdered } from '../utils';
+
+export class BinaryArrayParser extends AbstractBinaryParser {
+ type = 'array';
+
+ constructor(private config) {
+ super();
+ }
+
+ read(
+ reader: BinaryReader,
+ data: BinaryReaderResult = {}
+ ): BinaryReaderResult {
+ let len = resolveFunctionOrvalue(this.config.length, data) || Infinity;
+ let raw = '';
+ const value = [];
+
+ while (len > 0 && reader.hasMore()) {
+ const result = this.config.parser.read(reader, data);
+ raw += result.raw;
+ value.push(result.value);
+ len--;
+ }
+
+ return { value, raw };
+ }
+
+ readOrdered(
+ reader: BinaryReader,
+ data: BinaryReaderResult = [],
+ start = 0
+ ): BinaryReaderResult {
+ let numberOfElements = resolveLengthOrdered(this.config.length, data);
+ if (numberOfElements === undefined) {
+ numberOfElements = Infinity;
+ }
+
+ let rawValue = '';
+ const value = [];
+
+ let len = 0;
+ let index = 0;
+
+ while (numberOfElements > 0 && reader.hasMore()) {
+ index++;
+ const result = this.config.parser.readOrdered(reader, data, start + len);
+ rawValue += result.rawValue;
+
+ const length = result.rawValue.length;
+ value.push({
+ start: start + len,
+ end: start + len + length,
+ length,
+ index,
+ type: this.config.parser.type,
+ value: result.value,
+ rawValue: result.rawValue
+ });
+ len += length;
+ numberOfElements--;
+ }
+
+ return {
+ name: this.config.name,
+ start,
+ length: len,
+ end: start + len,
+ value,
+ rawValue,
+ type: this.type
+ };
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/bit-parser.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/bit-parser.spec.ts
new file mode 100644
index 000000000..a77c59fcf
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/bit-parser.spec.ts
@@ -0,0 +1,38 @@
+import { StringBinaryReader } from '../readers/string-reader';
+import { BitParser } from './bit-parser';
+
+describe('BinaryParser', () => {
+ beforeEach(() => {
+ const s = 'Universal Serial Bus'
+ .split('')
+ .map(a => a.charCodeAt(0))
+ .map(a => a.toString(2))
+ .map(a => (a as any).padStart(8, 0))
+ .join('');
+ this.reader = new StringBinaryReader(s);
+ });
+
+ describe('bit parser', () => {
+ it('can read 3 bit bit', () => {
+ const parser = new BitParser({ length: 3 });
+ const results = parser.read(this.reader);
+ expect(results.value).toBe('010');
+ expect(results.rawValue).toBe('010');
+ });
+
+ it('takes a length function', () => {
+ const parser = new BitParser({ length: () => 3 });
+
+ const result = parser.read(this.reader);
+ expect(result.value).toBe('010');
+ expect(result.rawValue).toBe('010');
+ });
+
+ it('takes a length function which can use existing data', () => {
+ const parser = new BitParser({ length: data => data.len });
+ const result = parser.read(this.reader, { len: 3 });
+ expect(result.value).toBe('010');
+ expect(result.rawValue).toBe('010');
+ });
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/bit-parser.ts b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/bit-parser.ts
new file mode 100644
index 000000000..af42e657a
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/bit-parser.ts
@@ -0,0 +1,71 @@
+import { AbstractBinaryParser } from './abstract-parser';
+import { BinaryReader, BinaryReaderResult } from '../readers/abstract-reader';
+import {
+ resolveByKey,
+ resolveFunctionKeyOrValue,
+ resolveOrderedByKey
+} from '../utils';
+
+export class BitParser extends AbstractBinaryParser {
+ type = 'bits';
+
+ constructor(private config) {
+ super();
+ this.type = config.type || this.type;
+ }
+
+ readWithLength(
+ reader: BinaryReader,
+ data: BinaryReaderResult = [],
+ len: number
+ ) {
+ const rawValue = reader.read(len);
+ const converter = this.config.converter || (a => a);
+ return { value: converter(rawValue), rawValue };
+ }
+
+ read(
+ reader: BinaryReader,
+ data: BinaryReaderResult = {}
+ ): BinaryReaderResult {
+ const len = resolveFunctionKeyOrValue(
+ this.config.length,
+ data,
+ resolveByKey
+ );
+ return this.readWithLength(reader, data, len);
+ }
+
+ readOrdered(
+ reader: BinaryReader,
+ data: BinaryReaderResult = [],
+ start = 0
+ ): BinaryReaderResult {
+ if (start === 0) {
+ // tslint:disable-next-line:no-debugger
+ debugger;
+ }
+
+ const len = resolveFunctionKeyOrValue(
+ this.config.length,
+ data,
+ resolveOrderedByKey
+ );
+ const result = this.readWithLength(reader, data, len);
+ const length = result.rawValue.length;
+ const end = start + length;
+
+ return {
+ displayValue:
+ (this.config && this.config.enum && this.config.enum[result.value]) ||
+ result.value,
+ start,
+ length,
+ end,
+ ...result,
+ type: this.type,
+ description: this.config && this.config.description,
+ unconverter: this.config.unconverter
+ };
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/choice-parser.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/choice-parser.spec.ts
new file mode 100644
index 000000000..5433a1aca
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/choice-parser.spec.ts
@@ -0,0 +1,44 @@
+import { StringBinaryReader } from '../readers/string-reader';
+import { BitParser } from './bit-parser';
+import { BinaryChoiceParser } from './choice-parser';
+import { StringParser } from './string-parser';
+
+describe('BinaryParser', () => {
+ beforeEach(() => {
+ const s = 'Universal Serial Bus'
+ .split('')
+ .map(a => a.charCodeAt(0))
+ .map(a => a.toString(2))
+ .map(a => (a as any).padStart(8, 0))
+ .join('');
+ this.reader = new StringBinaryReader(s);
+ });
+
+ describe('choice parser', () => {
+ it('can read one letter', () => {
+ const parser = new BinaryChoiceParser({
+ key: ({ p }) => p,
+ values: {
+ '1': new BitParser({ length: 8 }),
+ '2': new StringParser({ length: 2 })
+ }
+ });
+ expect(parser.read(this.reader, { p: '1' }).value).toEqual('01010101');
+ expect(parser.read(this.reader, { p: '2' }).value).toEqual('ni');
+ });
+
+ it('can read one letter', () => {
+ const parser = new BinaryChoiceParser({
+ key: ({ p }) => p,
+ values: {
+ '1': new BitParser({ length: 8 }),
+ '2': new StringParser({ length: 2 })
+ }
+ });
+ expect(parser.readOrdered(this.reader, { p: '1' }).value).toEqual(
+ '01010101'
+ );
+ expect(parser.readOrdered(this.reader, { p: '2' }).value).toEqual('ni');
+ });
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/choice-parser.ts b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/choice-parser.ts
new file mode 100644
index 000000000..0fc48acb8
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/choice-parser.ts
@@ -0,0 +1,54 @@
+import { AbstractBinaryParser } from './abstract-parser';
+import { BinaryReader, BinaryReaderResult } from '../readers/abstract-reader';
+import { resolveByKey, resolveOrderedByKey } from '../utils';
+
+export class BinaryChoiceParser extends AbstractBinaryParser {
+ constructor(private config) {
+ super();
+ }
+
+ get type() {
+ return 'bich';
+ }
+
+ read(
+ reader: BinaryReader,
+ data: BinaryReaderResult = []
+ ): BinaryReaderResult {
+ return this.getParser(data, resolveByKey).read(reader, data);
+ }
+
+ getParser(data, resolver) {
+ let parser: AbstractBinaryParser;
+
+ if (this.config.key) {
+ const keyValue = resolver(this.config.key, data);
+ parser = this.config.values[keyValue];
+ }
+
+ if (this.config.parser) {
+ parser = this.config.parser(data);
+ }
+
+ if (!parser) {
+ // tslint:disable-next-line:no-debugger
+ debugger;
+ }
+
+ return parser;
+ }
+
+ readOrdered(
+ reader: BinaryReader,
+ data: BinaryReaderResult = [],
+ start = 0
+ ): BinaryReaderResult {
+ const parser = this.getParser(data, resolveOrderedByKey);
+ const { value, rawValue, description } = parser.readOrdered(
+ reader,
+ data,
+ start
+ );
+ return { start, value, rawValue, type: parser.type, description };
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/common.ts b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/common.ts
new file mode 100644
index 000000000..3e8e2c313
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/common.ts
@@ -0,0 +1,30 @@
+export interface ParserConfig {
+ description?: string;
+}
+
+export enum Endianness {
+ BIG = 1,
+ LITTLE
+}
+
+export interface BinaryParserConfig {
+ endianness: Endianness.BIG;
+}
+
+export const defaultConfig: BinaryParserConfig = {
+ endianness: Endianness.BIG
+};
+
+export function beToLe32(val) {
+ return (
+ ((val & 0xff) << 24) |
+ ((val & 0xff00) << 8) |
+ ((val >> 8) & 0xff00) |
+ ((val >> 24) & 0xff)
+ );
+}
+
+export interface ReadResult {
+ parent: ReadResult | null;
+ results: ReadResult[];
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/debugger-parser.ts b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/debugger-parser.ts
new file mode 100644
index 000000000..6c450819e
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/debugger-parser.ts
@@ -0,0 +1,15 @@
+import { BinaryReader, BinaryReaderResult } from '../readers/abstract-reader';
+
+export abstract class DebuggerParser {
+ type = 'debugger';
+
+ read(reader: BinaryReader, data: BinaryReaderResult) {
+ // tslint:disable-next-line:no-debugger
+ debugger;
+ }
+
+ readOrdered(reader: BinaryReader, data: BinaryReaderResult) {
+ // tslint:disable-next-line:no-debugger
+ debugger;
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/first-bit-parser.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/first-bit-parser.spec.ts
new file mode 100644
index 000000000..002adbda2
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/first-bit-parser.spec.ts
@@ -0,0 +1,27 @@
+import { StringBinaryReader } from '../readers/string-reader';
+import { VarUintParser } from './var-uint-parser';
+
+fdescribe('FirstBitParse', () => {
+ it('can read 1 byte', () => {
+ const reader = new StringBinaryReader('0111111111111111');
+ const result = new VarUintParser().read(reader);
+ expect(result.rawValue).toEqual('01111111');
+ });
+ it('can read 1 byte', () => {
+ const reader = new StringBinaryReader('11111111');
+ const result = new VarUintParser().read(reader);
+ expect(result.rawValue).toEqual('11111111');
+ });
+
+ it('can read 2 bytes', () => {
+ const reader = new StringBinaryReader('1111111101111111111');
+ const result = new VarUintParser().read(reader);
+ expect(result.rawValue).toEqual('1111111101111111');
+ });
+
+ it('can read 3 bytes', () => {
+ const reader = new StringBinaryReader('111111111111111101111111111');
+ const result = new VarUintParser().read(reader);
+ expect(result.rawValue).toEqual('111111111111111101111111');
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/object-parser.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/object-parser.spec.ts
new file mode 100644
index 000000000..5d30efb7c
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/object-parser.spec.ts
@@ -0,0 +1,97 @@
+import { StringBinaryReader } from '../readers/string-reader';
+import { BinaryObjectParser } from './object-parser';
+import { BitParser } from './bit-parser';
+
+describe('BinaryParser', () => {
+ beforeEach(() => {
+ const s = 'Universal Serial Bus'
+ .split('')
+ .map(a => a.charCodeAt(0))
+ .map(a => a.toString(2))
+ .map(a => (a as any).padStart(8, 0))
+ .join('');
+ this.reader = new StringBinaryReader(s);
+ });
+
+ describe('BinaryObjectParser', () => {
+ it('can read simple bits', () => {
+ const parser = new BinaryObjectParser();
+ parser.addStep('a', new BitParser({ length: 1 }));
+ parser.addStep('b', new BitParser({ length: 2 }));
+ parser.addStep('c', new BitParser({ length: 1 }));
+
+ const result = parser.read(this.reader);
+ expect(result.value).toEqual({
+ a: '0',
+ b: '10',
+ c: '1'
+ });
+ });
+
+ it('can read nested objects', () => {
+ const parser = new BinaryObjectParser();
+ parser.addStep('a', new BitParser({ length: 1 }));
+
+ const innerParser = new BinaryObjectParser();
+ innerParser.addStep('a', new BitParser({ length: 1 }));
+ innerParser.addStep('b', new BitParser({ length: 1 }));
+ parser.addStep('inner', innerParser);
+ parser.addStep('b', new BitParser({ length: 1 }));
+ const result = parser.read(this.reader);
+ expect(result.value).toEqual({
+ a: '0',
+ inner: {
+ a: '1',
+ b: '0'
+ },
+ b: '1'
+ });
+ });
+
+ it('can read nested objects', () => {
+ const parser = new BinaryObjectParser();
+ parser.addStep('a', new BitParser({ length: 1 }));
+
+ const innerParser = new BinaryObjectParser();
+ innerParser.addStep('a', new BitParser({ length: 1 }));
+ innerParser.addStep('b', new BitParser({ length: 1 }));
+ parser.addStep('inner', innerParser);
+ parser.addStep('b', new BitParser({ length: 1 }));
+ const result = parser.readOrdered(this.reader);
+
+ expect(result.value).toEqual([
+ {
+ name: 'a',
+ value: '0',
+ rawValue: '0',
+ type: 'bits'
+ },
+ {
+ name: 'inner',
+ value: [
+ {
+ name: 'a',
+ value: '1',
+ rawValue: '1',
+ type: 'bits'
+ },
+ {
+ name: 'b',
+ value: '0',
+ rawValue: '0',
+ type: 'bits'
+ }
+ ],
+ rawValue: '10',
+ type: 'object'
+ },
+ {
+ name: 'b',
+ value: '1',
+ rawValue: '1',
+ type: 'bits'
+ }
+ ]);
+ });
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/object-parser.ts b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/object-parser.ts
new file mode 100644
index 000000000..466e2ec75
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/object-parser.ts
@@ -0,0 +1,83 @@
+import { AbstractBinaryParser } from './abstract-parser';
+import { BinaryReader, BinaryReaderResult } from '../readers/abstract-reader';
+
+export class BinaryObjectParser extends AbstractBinaryParser {
+ type = 'object';
+
+ steps: {
+ name: string;
+ description?: string;
+ parser: AbstractBinaryParser;
+ }[] = [];
+
+ addStep(name: string, parser: AbstractBinaryParser) {
+ this.steps.push({ name, parser });
+ }
+
+ read(
+ reader: BinaryReader,
+ data: BinaryReaderResult = {}
+ ): BinaryReaderResult {
+ let raw = '';
+ const val = this.steps.reduce((result, step) => {
+ const { value, rawValue } = step.parser.read(reader, result);
+ result[step.name] = value;
+ raw += rawValue;
+ return result;
+ }, {});
+
+ return { value: val, rawValue: raw };
+ }
+
+ readOrdered(
+ reader: BinaryReader,
+ data: BinaryReaderResult = [],
+ start = 0
+ ): BinaryReaderResult {
+ let raw = '';
+ let len = 0;
+
+ const value = this.steps.reduce((result, step) => {
+ const {
+ value,
+ rawValue,
+ type,
+ description,
+ displayValue
+ } = step.parser.readOrdered(
+ reader,
+ [...result, { name: '_parent', value: data }],
+ start + len
+ );
+ raw += rawValue;
+ if (!type) {
+ // tslint:disable-next-line:no-debugger
+ debugger;
+ }
+
+ len += rawValue.length;
+ result.push({
+ start: start + len - rawValue.length,
+ end: start + len,
+ length: rawValue.length,
+ name: step.name,
+ description,
+ value,
+ displayValue,
+ rawValue,
+ type
+ });
+
+ return result;
+ }, []);
+
+ return {
+ start,
+ length: len,
+ end: start + len,
+ value,
+ rawValue: raw,
+ type: 'object'
+ };
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/string-parser.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/string-parser.spec.ts
new file mode 100644
index 000000000..294fd68b7
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/string-parser.spec.ts
@@ -0,0 +1,66 @@
+import { BinaryParser } from '../binary-parser';
+import { StringParser } from './string-parser';
+import { StringBinaryReader } from '../readers/string-reader';
+
+describe('BinaryParser', () => {
+ beforeEach(() => {
+ const s = 'Universal Serial Bus'
+ .split('')
+ .map(a => a.charCodeAt(0))
+ .map(a => a.toString(2))
+ .map(a => (a as any).padStart(8, 0))
+ .join('');
+ this.reader = new StringBinaryReader(s);
+ });
+
+ fdescribe('string parser', () => {
+ it('can read one letter', () => {
+ const parser = new StringParser({ length: 1 });
+ expect(parser.read(this.reader).value).toBe('U');
+ });
+
+ it('can read 3 letttes', () => {
+ const parser = new StringParser({ length: 3 });
+ expect(parser.read(this.reader).value).toBe('Uni');
+ });
+
+ describe('readuntil', () => {
+ const s = 'lollol'
+ .split('')
+ .map(a => a.charCodeAt(0))
+ .map(a => a.toString(2))
+ .map(a => (a as any).padStart(8, 0))
+ .join('');
+
+ const s2 = 'ogogog'
+ .split('')
+ .map(a => a.charCodeAt(0))
+ .map(a => a.toString(2))
+ .map(a => (a as any).padStart(8, 0))
+ .join('');
+
+ it('can read until 00', () => {
+ this.reader = new StringBinaryReader(s + '00000000' + s2);
+ const parser = new StringParser({ readUntil: '00000000' });
+ const binaryReaderResult = parser.readOrdered(this.reader);
+ expect(binaryReaderResult.value).toBe('lollol');
+ });
+
+ it('Reads the whole thing if no 00', () => {
+ this.reader = new StringBinaryReader(s + '01010101' + s2);
+ const parser = new StringParser({ readUntil: '00000000' });
+ const binaryReaderResult = parser.readOrdered(this.reader);
+ expect(binaryReaderResult.value).toBe('lollolUogogog');
+ });
+ });
+
+ it('can read ordered 3 letttes', () => {
+ const parser = new StringParser({ length: 3 });
+ const binaryReaderResult = parser.readOrdered(this.reader);
+ expect(binaryReaderResult.value).toBe('Uni');
+ expect(binaryReaderResult.start).toBe(0);
+ expect(binaryReaderResult.end).toBe(24);
+ expect(binaryReaderResult.length).toBe(24);
+ });
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/string-parser.ts b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/string-parser.ts
new file mode 100644
index 000000000..59c121851
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/string-parser.ts
@@ -0,0 +1,73 @@
+import { AbstractBinaryParser } from './abstract-parser';
+import { BinaryReader, BinaryReaderResult } from '../readers/abstract-reader';
+import {
+ resolveFunctionKeyOrValue,
+ resolveFunctionOrvalue,
+ resolveLengthOrdered
+} from '../utils';
+import { ParserConfig } from './common';
+
+function bytesToChar(a) {
+ return String.fromCharCode(parseInt(a, 2));
+}
+
+export interface StringParserConfig extends ParserConfig {
+ length?: number | Function | string;
+ readUntil?: string;
+}
+
+export class StringParser extends AbstractBinaryParser {
+ type = 'string';
+
+ constructor(private config: StringParserConfig) {
+ super();
+ }
+
+ read(
+ reader: BinaryReader,
+ data: BinaryReaderResult = {},
+ start = 0
+ ): BinaryReaderResult {
+ if (this.config.readUntil) {
+ let value = '';
+ let rawValue = '';
+
+ while (
+ reader.peak(this.config.readUntil.length) !== this.config.readUntil &&
+ reader.peak(this.config.readUntil.length) > 0
+ ) {
+ const letter = reader.read(8);
+ value += bytesToChar(letter);
+ rawValue += letter;
+ }
+
+ return { value, rawValue };
+ } else {
+ const len = resolveLengthOrdered(this.config.length, data) * 8;
+ const rawValue = reader.read(len);
+ const value = rawValue
+ .match(/.{8}/g)
+ .map(bytesToChar)
+ .join('');
+ return { value, rawValue };
+ }
+ }
+
+ readOrdered(
+ reader: BinaryReader,
+ data: BinaryReaderResult = [],
+ start = 0
+ ): BinaryReaderResult {
+ const result = this.read(reader, data);
+ const length = start + result.rawValue.length;
+ const end = start + length;
+ return {
+ ...result,
+ type: this.type,
+ description: this.config.description,
+ start,
+ end,
+ length
+ };
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/var-uint-parser.ts b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/var-uint-parser.ts
new file mode 100644
index 000000000..d02203a2e
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/parser/parsers/var-uint-parser.ts
@@ -0,0 +1,61 @@
+import { AbstractBinaryParser } from './abstract-parser';
+import { BinaryReader, BinaryReaderResult } from '../readers/abstract-reader';
+import { BaseConfig } from '../binary-parser';
+
+export interface VarUintParserConfig extends BaseConfig {
+ size?: number;
+}
+
+export const defaultVarUintParserConfig = {
+ size: 7
+};
+
+export class VarUintParser extends AbstractBinaryParser {
+ type = 'bits';
+
+ constructor(
+ private config: VarUintParserConfig = defaultVarUintParserConfig
+ ) {
+ super();
+ this.type = config.type || this.type;
+ }
+
+ static converter(n: string) {
+ return parseInt(n, 2);
+ }
+
+ read(
+ reader: BinaryReader,
+ data: BinaryReaderResult = {}
+ ): BinaryReaderResult {
+ let hasNext = true;
+ let value = '';
+ let rawValue = '';
+ const size = this.config.size || 7;
+
+ let i = 100;
+ while (hasNext) {
+ const firstBit = reader.read(1);
+ hasNext = !!+firstBit;
+ rawValue += firstBit;
+ const result = reader.read(size);
+ value += result;
+ rawValue += result;
+ if (i-- < 1) {
+ // tslint:disable-next-line:no-debugger
+ debugger;
+ }
+ }
+
+ const converter = this.config.converter || VarUintParser.converter;
+ return { value: converter(rawValue), rawValue };
+ }
+
+ readOrdered(
+ reader: BinaryReader,
+ data: BinaryReaderResult = [],
+ start = 0
+ ): BinaryReaderResult {
+ return { ...this.read(reader, data), type: this.type };
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/parser/readers/abstract-reader.ts b/codelab-master/apps/kirjs/src/app/modules/binary/parser/readers/abstract-reader.ts
new file mode 100644
index 000000000..c8cba8e92
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/parser/readers/abstract-reader.ts
@@ -0,0 +1,8 @@
+export type BinaryReaderResult = any;
+
+export abstract class BinaryReader {
+ abstract read(bits: number);
+ abstract peak(bits: number);
+
+ abstract hasMore(): boolean;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/parser/readers/string-reader.ts b/codelab-master/apps/kirjs/src/app/modules/binary/parser/readers/string-reader.ts
new file mode 100644
index 000000000..0eca46185
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/parser/readers/string-reader.ts
@@ -0,0 +1,21 @@
+import { BinaryReader, BinaryReaderResult } from './abstract-reader';
+
+export class StringBinaryReader implements BinaryReader {
+ private index = 0;
+
+ constructor(private s: string) {}
+
+ hasMore() {
+ return this.index < this.s.length;
+ }
+
+ peak(bits: number): BinaryReaderResult {
+ return this.s.slice(this.index, this.index + bits);
+ }
+
+ read(bits: number): BinaryReaderResult {
+ this.index += bits;
+ const result = this.s.slice(this.index - bits, this.index);
+ return result;
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/parser/utils.ts b/codelab-master/apps/kirjs/src/app/modules/binary/parser/utils.ts
new file mode 100644
index 000000000..4891b0696
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/parser/utils.ts
@@ -0,0 +1,42 @@
+export function resolveLengthOrdered(functionOrValue, data) {
+ if (typeof functionOrValue === 'string') {
+ return resolveOrderedByKey(functionOrValue, data);
+ }
+ return typeof functionOrValue === 'function'
+ ? functionOrValue(data)
+ : functionOrValue;
+}
+
+export function resolveFunctionOrvalue(functionOrValue, arg) {
+ return typeof functionOrValue === 'function'
+ ? functionOrValue(arg)
+ : functionOrValue;
+}
+
+export function resolveFunctionKeyOrValue(val, data, resolve) {
+ if (typeof val === 'string') {
+ return resolve(val, data);
+ }
+
+ if (typeof val === 'function') {
+ return val(data, resolve);
+ }
+
+ return val;
+}
+
+export function resolveOrderedByKey(key: string, data: any[]) {
+ return Object.values(data).find(a => a.name === key).value;
+}
+
+export function resolveByKey(key: string, data: any) {
+ return data[key];
+}
+
+export function strToBin(str) {
+ return str
+ .split('')
+ .map(a => a.charCodeAt(0))
+ .map(a => a.toString(2).padStart(8, 0))
+ .join('');
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/pics/MVIMG_20181224_181143.jpg b/codelab-master/apps/kirjs/src/app/modules/binary/pics/MVIMG_20181224_181143.jpg
new file mode 100644
index 000000000..10e2c6766
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/binary/pics/MVIMG_20181224_181143.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/pics/T02092_10.jpg b/codelab-master/apps/kirjs/src/app/modules/binary/pics/T02092_10.jpg
new file mode 100644
index 000000000..3105b5fef
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/binary/pics/T02092_10.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/pics/binary-abstraction.jpg b/codelab-master/apps/kirjs/src/app/modules/binary/pics/binary-abstraction.jpg
new file mode 100644
index 000000000..f135a955f
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/binary/pics/binary-abstraction.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/pics/chikin.gif b/codelab-master/apps/kirjs/src/app/modules/binary/pics/chikin.gif
new file mode 100644
index 000000000..3eed0be10
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/binary/pics/chikin.gif differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/pics/endianness.png b/codelab-master/apps/kirjs/src/app/modules/binary/pics/endianness.png
new file mode 100644
index 000000000..d47eaf691
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/binary/pics/endianness.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/pics/gdg-binary.jpg b/codelab-master/apps/kirjs/src/app/modules/binary/pics/gdg-binary.jpg
new file mode 100644
index 000000000..e34e429fc
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/binary/pics/gdg-binary.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/pics/hackers-delight.jpeg b/codelab-master/apps/kirjs/src/app/modules/binary/pics/hackers-delight.jpeg
new file mode 100644
index 000000000..5778a8fd0
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/binary/pics/hackers-delight.jpeg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/pics/jqbSOmRU_400x400.jpg b/codelab-master/apps/kirjs/src/app/modules/binary/pics/jqbSOmRU_400x400.jpg
new file mode 100644
index 000000000..c008d66d5
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/binary/pics/jqbSOmRU_400x400.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/pics/kaitai.png b/codelab-master/apps/kirjs/src/app/modules/binary/pics/kaitai.png
new file mode 100644
index 000000000..2fae1f6ff
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/binary/pics/kaitai.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/pics/kirjs.gif b/codelab-master/apps/kirjs/src/app/modules/binary/pics/kirjs.gif
new file mode 100644
index 000000000..4ef9143b8
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/binary/pics/kirjs.gif differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/pics/kirjs.jpg b/codelab-master/apps/kirjs/src/app/modules/binary/pics/kirjs.jpg
new file mode 100644
index 000000000..4ef9143b8
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/binary/pics/kirjs.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/pics/kirjs.webp b/codelab-master/apps/kirjs/src/app/modules/binary/pics/kirjs.webp
new file mode 100644
index 000000000..188a9298a
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/binary/pics/kirjs.webp differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/pics/krakoziabry.jpg b/codelab-master/apps/kirjs/src/app/modules/binary/pics/krakoziabry.jpg
new file mode 100644
index 000000000..0133f0bdd
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/binary/pics/krakoziabry.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/pics/little.gif b/codelab-master/apps/kirjs/src/app/modules/binary/pics/little.gif
new file mode 100644
index 000000000..cc1000fd0
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/binary/pics/little.gif differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/pics/p1.jpg b/codelab-master/apps/kirjs/src/app/modules/binary/pics/p1.jpg
new file mode 100644
index 000000000..6588660b9
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/binary/pics/p1.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/pics/p2.jpg b/codelab-master/apps/kirjs/src/app/modules/binary/pics/p2.jpg
new file mode 100644
index 000000000..d35d7a6cf
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/binary/pics/p2.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/pics/p3.jpg b/codelab-master/apps/kirjs/src/app/modules/binary/pics/p3.jpg
new file mode 100644
index 000000000..31d6a5737
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/binary/pics/p3.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/pics/pelmeni.jpg b/codelab-master/apps/kirjs/src/app/modules/binary/pics/pelmeni.jpg
new file mode 100644
index 000000000..a98a4961d
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/binary/pics/pelmeni.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/pics/photo.jpg b/codelab-master/apps/kirjs/src/app/modules/binary/pics/photo.jpg
new file mode 100644
index 000000000..4ef9143b8
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/binary/pics/photo.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/pics/zoom.gif b/codelab-master/apps/kirjs/src/app/modules/binary/pics/zoom.gif
new file mode 100644
index 000000000..edce46f3f
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/binary/pics/zoom.gif differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/shared.ts b/codelab-master/apps/kirjs/src/app/modules/binary/shared.ts
new file mode 100644
index 000000000..7cf3100ee
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/shared.ts
@@ -0,0 +1,6 @@
+export function bin2hex(bin: string) {
+ return bin
+ .match(/.{8}/gi)
+ .map(a => (parseInt(a, 2).toString(16) as any).padStart(2, 0))
+ .join('');
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/to-read/to-read.component.css b/codelab-master/apps/kirjs/src/app/modules/binary/to-read/to-read.component.css
new file mode 100644
index 000000000..3f196fa8b
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/to-read/to-read.component.css
@@ -0,0 +1,16 @@
+h2 {
+ font-size: 5vw !important;
+ line-height: 5vw !important;
+}
+
+h3 {
+ font-size: 3vw;
+ color: #444;
+}
+
+:host ::ng-deep .book {
+ width: 40vw;
+ height: 100vw;
+ background-repeat: no-repeat;
+ background-size: 40vw;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/to-read/to-read.component.html b/codelab-master/apps/kirjs/src/app/modules/binary/to-read/to-read.component.html
new file mode 100644
index 000000000..41a7a9663
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/to-read/to-read.component.html
@@ -0,0 +1,7 @@
+
+
+
+
{{ title }}
+ {{ author }}
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/to-read/to-read.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/binary/to-read/to-read.component.spec.ts
new file mode 100644
index 000000000..ac13a3149
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/to-read/to-read.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ToReadComponent } from './to-read.component';
+
+describe('ToReadComponent', () => {
+ let component: ToReadComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ToReadComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ToReadComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/binary/to-read/to-read.component.ts b/codelab-master/apps/kirjs/src/app/modules/binary/to-read/to-read.component.ts
new file mode 100644
index 000000000..cb522e58e
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/binary/to-read/to-read.component.ts
@@ -0,0 +1,14 @@
+import { Component, Input, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-to-read',
+ templateUrl: './to-read.component.html',
+ styleUrls: ['./to-read.component.css']
+})
+export class ToReadComponent implements OnInit {
+ @Input() author: string;
+ @Input() title: string;
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/board/board.component.css b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/board/board.component.css
new file mode 100644
index 000000000..8830b0e3d
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/board/board.component.css
@@ -0,0 +1,20 @@
+.cell {
+ border: 1px #888 solid;
+ margin-left: -1px;
+ margin-top: -5px;
+}
+
+.cell.cell-x {
+ border: none;
+}
+.cell-1 {
+ background: black;
+}
+
+.board,
+.cell {
+ display: inline-block;
+}
+
+.line {
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/board/board.component.html b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/board/board.component.html
new file mode 100644
index 000000000..3f810d91e
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/board/board.component.html
@@ -0,0 +1,10 @@
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/board/board.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/board/board.component.spec.ts
new file mode 100644
index 000000000..64e8a847d
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/board/board.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { BoardComponent } from './board.component';
+
+describe('BoardComponent', () => {
+ let component: BoardComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [BoardComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(BoardComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should be created', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/board/board.component.ts b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/board/board.component.ts
new file mode 100644
index 000000000..c71fcaa5f
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/board/board.component.ts
@@ -0,0 +1,36 @@
+import { Component, Input, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-board',
+ templateUrl: './board.component.html',
+ styleUrls: ['./board.component.css']
+})
+export class BoardComponent implements OnInit {
+ @Input() pattern;
+ @Input() cellHeight = 50;
+ @Input() cellWidth = 50;
+ @Input() transform;
+ @Input() playing = false;
+ @Input() delay = 500;
+
+ constructor() {}
+
+ public play() {
+ this.playing = true;
+ }
+
+ runTransform() {
+ if (this.playing) {
+ this.pattern = this.transform(this.pattern);
+ }
+ setTimeout(() => {
+ this.runTransform();
+ }, this.delay);
+ }
+
+ ngOnInit() {
+ if (this.transform) {
+ this.runTransform();
+ }
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/cellular-automation-routing.module.ts b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/cellular-automation-routing.module.ts
new file mode 100644
index 000000000..9ee8b6eb0
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/cellular-automation-routing.module.ts
@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { SlidesRoutes } from '@ng360/slides';
+
+import { CellularAutomationComponent } from './cellular-automation.component';
+import { CellularAutomationModule } from './cellular-automation.module';
+
+const routes = RouterModule.forChild(
+ SlidesRoutes.get(CellularAutomationComponent)
+);
+
+@NgModule({
+ imports: [routes, CellularAutomationModule],
+ declarations: [],
+ exports: []
+})
+export class CellularAutomationRoutingModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/cellular-automation.component.css b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/cellular-automation.component.css
new file mode 100644
index 000000000..c3df37951
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/cellular-automation.component.css
@@ -0,0 +1,161 @@
+h2 {
+ font-weight: 800;
+}
+
+pre {
+ font-size: 24px;
+}
+
+.empty-slide {
+ width: 400px;
+ height: 250px;
+ border: 1px solid #000;
+ margin-left: 300px;
+ margin-top: 10px;
+ -webkit-box-shadow: 10px 10px 5px 0px rgba(181, 172, 181, 1);
+ -moz-box-shadow: 10px 10px 5px 0px rgba(181, 172, 181, 1);
+ box-shadow: 10px 10px 5px 0px rgba(181, 172, 181, 1);
+}
+
+.html-elements {
+ font-size: 28px;
+ margin-top: 20px;
+ margin-left: 24px;
+}
+
+.kirjs {
+ width: 800px;
+ height: 300px;
+
+ background: url(intro/kirjs.png) no-repeat;
+ background-size: 100%;
+ margin: 0 auto;
+}
+
+.rules {
+ display: flex;
+}
+
+.play:hover {
+ background-color: #d6510f;
+}
+
+.play {
+ font-size: 14px;
+ padding: 5px;
+ text-align: center;
+ cursor: pointer;
+ margin-left: 20px;
+ margin-top: 10px;
+ background-color: #000000;
+ color: #ffffee;
+ height: 30px;
+ width: 30px;
+}
+
+.grid-header {
+ margin-top: 20px;
+ display: flex;
+}
+
+.img-wolfram {
+ width: 400px;
+ height: 400px;
+ background: url('intro/wolfram.jpg');
+}
+
+.img-moore {
+ width: 400px;
+ height: 400px;
+ background: url('intro/moore.jpg') no-repeat;
+ background-size: 100%;
+ margin-right: 50px;
+}
+
+.img-neuman {
+ width: 400px;
+ height: 400px;
+ background: url('intro/JohnvonNeumann.gif') no-repeat;
+ background-size: 100%;
+ margin-right: 50px;
+}
+
+.img-conway {
+ width: 600px;
+ height: 400px;
+ background: url('intro/Conway_.jpg') no-repeat;
+ background-size: 100%;
+ margin-right: 50px;
+}
+
+.neighborhood {
+ display: flex;
+}
+
+.img-gun {
+ width: 800px;
+ height: 600px;
+ background: url('intro/Gosperglidergun.gif') no-repeat;
+ background-size: 100%;
+ margin-right: 50px;
+}
+
+.img-turing {
+ width: 800px;
+ height: 800px;
+ background: url('intro/turing.gif') no-repeat;
+ background-size: 100%;
+ margin-right: 50px;
+}
+
+.img-mp {
+ width: 800px;
+ height: 800px;
+ background: url('intro/metapixel.png') no-repeat;
+ background-size: 100%;
+ margin-right: 50px;
+}
+
+.img-30 {
+ width: 800px;
+ height: 800px;
+ background: url('intro/30.png') no-repeat;
+ background-size: 100%;
+ margin-right: 50px;
+}
+
+.img-30-2 {
+ width: 800px;
+ height: 800px;
+ background: url('intro/30-2.png') no-repeat;
+ background-size: 100%;
+ margin-right: 50px;
+}
+
+.img-gosper {
+ width: 800px;
+ height: 800px;
+ background: url('intro/Bill_Gosper_2006.jpg') no-repeat;
+ background-size: 100%;
+ margin-right: 50px;
+}
+
+.img-cave {
+ width: 800px;
+ height: 800px;
+ background: url('intro/maze.png') no-repeat;
+ background-size: 100%;
+ margin-right: 50px;
+}
+
+.img-nks {
+ width: 800px;
+ height: 800px;
+ background: url('intro/nks.jpg') no-repeat;
+ background-size: 100%;
+ margin-right: 50px;
+}
+
+:host /deep/ .slide {
+ display: block;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/cellular-automation.component.html b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/cellular-automation.component.html
new file mode 100644
index 000000000..9280bac7b
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/cellular-automation.component.html
@@ -0,0 +1,918 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Grid
+
+
+
+
+
+
+
+
+
+
+
Rule 90
+
+
+
+
+
+
+
+
+
+
+
Stephen Wolfram (Rule 30)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
New kind of science
+
+
+
+
+
+
Cellular Automata 2D!
+
+
+
+
+
Neighborhoods
+
+
+
+
+
Edward F. Moore
+
+
+
+
+
+
+
John von Neumann
+
+
+
+
Extended
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Bunch of demos
+
+
+
3d
+ VIDEO
+
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/cellular-automation.component.ts b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/cellular-automation.component.ts
new file mode 100644
index 000000000..c68be56f2
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/cellular-automation.component.ts
@@ -0,0 +1,757 @@
+import { Component } from '@angular/core';
+
+function inPlace(rule) {
+ const map = (256 + rule)
+ .toString(2)
+ .substr(1)
+ .split('')
+ .map(Number)
+ .reduce((a, v, i) => {
+ a[(15 - i).toString(2).substr(1)] = v;
+ return a;
+ }, {});
+
+ function transformRow(row) {
+ const result = [];
+ for (let i = 0; i < row.length; i++) {
+ const a1 = row[(row.length + i - 1) % row.length].toString();
+ const a2 = row[i].toString();
+ const a3 = row[(i + 1) % row.length].toString();
+ result[i] = [map[a1 + a2 + a3]];
+ }
+ return result;
+ }
+
+ return function(grid) {
+ return grid.map(transformRow);
+ };
+}
+
+function transform2d(rule) {
+ const survive = rule.survive.reduce((a, v) => {
+ a[v] = true;
+ return a;
+ }, {});
+ const born = rule.born.reduce((a, v) => {
+ a[v] = true;
+ return a;
+ }, {});
+
+ return function(grid) {
+ return grid.map((row, y) => {
+ return row.map((cell, x) => {
+ const px = (row.length + x - 1) % row.length;
+ const nx = (x + 1) % row.length;
+ const py = (grid.length + y - 1) % grid.length;
+ const ny = (y + 1) % grid.length;
+
+ const score =
+ grid[py][px] +
+ grid[py][x] +
+ grid[py][nx] +
+ grid[y][px] +
+ grid[y][nx] +
+ grid[ny][px] +
+ grid[ny][x] +
+ grid[ny][nx];
+
+ if ((cell === 0 && born[score]) || (cell === 1 && survive[score])) {
+ return 1;
+ }
+
+ return 0;
+ });
+ });
+ };
+}
+
+function appendTransform(rule) {
+ const transform = inPlace(rule);
+ return function(grid) {
+ const lastRow = grid[grid.length - 1];
+ grid.push(transform([lastRow])[0]);
+ return grid;
+ };
+}
+
+const rand = Math.floor(Math.random() * 255);
+
+const randomRules = new Array(8).fill(0).reduce(
+ (a, v, i) => {
+ if (Math.random() < 0.3) {
+ a.survive.push(i);
+ }
+ if (Math.random() < 0.3) {
+ a.born.push(i);
+ }
+ return a;
+ },
+ { survive: [], born: [] }
+);
+
+const gameOfLifeRules = { survive: [2, 3], born: [3] };
+const gameOfLife = transform2d(gameOfLifeRules);
+const randomPattern = new Array(30)
+ .fill(0)
+ .map(() => new Array(60).fill(0).map(() => (Math.random() < 0.3 ? 1 : 0)));
+const randomPatternSparce = new Array(30)
+ .fill(0)
+ .map(() => new Array(60).fill(0).map(() => (Math.random() < 0.04 ? 1 : 0)));
+
+const labyrynthRules = { survive: [0, 1, 2, 3], born: [1] };
+
+const labRules4 = { survive: [0, 1, 2, 3, 4], born: [1] };
+const labRules5 = { survive: [0, 1, 2, 3, 4, 5], born: [1] };
+const labRules6 = { survive: [0, 1, 2, 3, 4, 5, 6], born: [1] };
+
+@Component({
+ selector: 'kirjs-cellular-automation',
+ templateUrl: './cellular-automation.component.html',
+ styleUrls: ['./cellular-automation.component.css']
+})
+export class CellularAutomationComponent {
+ examples = {
+ intro: {
+ inverse(pattern) {
+ return pattern.map(line => line.map(cell => (cell + 1) % 2));
+ },
+ rand,
+ inPlace16: inPlace(16),
+ inPlace90: inPlace(90),
+ twoD18: appendTransform(18),
+ twoD30: appendTransform(30),
+ twoD90: appendTransform(90),
+ twoD110: appendTransform(110),
+ twoDRand: appendTransform(rand),
+
+ pattern: [
+ [0, 0, 0, 1, 0, 0, 0, 0],
+ [0, 0, 0, 1, 0, 0, 0, 0],
+ [0, 0, 0, 1, 0, 0, 0, 0],
+ [0, 0, 0, 1, 0, 0, 0, 0]
+ ]
+ },
+ life: {
+ randomRules,
+ random: transform2d(randomRules),
+ gameOfLifeRules,
+ gameOfLife,
+ labyrynthRules: labyrynthRules,
+ labyrynth: transform2d(labyrynthRules),
+ labRules4,
+ labyrynth4: transform2d(labRules4),
+ labRules5,
+ labyrynth5: transform2d(labRules5),
+ labRules6,
+ labyrynth6: transform2d(labRules6),
+ pattern: {
+ randomPattern,
+ randomPatternSparce,
+ stillLife: [
+ [0, 0, 0, 0],
+ [0, 1, 1, 0],
+ [0, 1, 1, 0],
+ [0, 0, 0, 0]
+ ],
+ oscilator: [
+ [0, 0, 0, 0, 0],
+ [0, 0, 1, 0, 0],
+ [0, 0, 1, 0, 0],
+ [0, 0, 1, 0, 0],
+ [0, 0, 0, 0, 0]
+ ],
+ oscilatorClock: [
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0],
+ [0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0],
+ [0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0],
+ [0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0],
+ [0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0],
+ [0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+ ],
+
+ glider: [
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+ ],
+
+ copperhead: [
+ [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 0,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 0,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ]
+ ]
+ }
+ }
+ };
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/cellular-automation.module.ts b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/cellular-automation.module.ts
new file mode 100644
index 000000000..7b1109038
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/cellular-automation.module.ts
@@ -0,0 +1,37 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { SlidesModule } from '@ng360/slides';
+import { FeedbackModule } from '@codelab/feedback';
+
+import { CellularAutomationComponent } from './cellular-automation.component';
+import { BoardComponent } from './board/board.component';
+import { Rule3Component } from './rule3/rule3.component';
+import { RuleComponent } from './rule/rule.component';
+import { Rule8Component } from './rule8/rule8.component';
+import { OscilatorsComponent } from './oscilators/oscilators.component';
+import { Rule4Component } from './rule3/rule4/rule4.component';
+
+@NgModule({
+ imports: [SlidesModule, FeedbackModule, CommonModule],
+ declarations: [
+ CellularAutomationComponent,
+ BoardComponent,
+ Rule3Component,
+ RuleComponent,
+ Rule8Component,
+ OscilatorsComponent,
+ Rule4Component
+ ],
+ exports: [
+ CellularAutomationComponent,
+ CellularAutomationComponent,
+ BoardComponent,
+ Rule3Component,
+ RuleComponent,
+ Rule8Component,
+ OscilatorsComponent,
+ BoardComponent,
+ Rule4Component
+ ]
+})
+export class CellularAutomationModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/30-2.png b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/30-2.png
new file mode 100644
index 000000000..d554e82a2
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/30-2.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/30.png b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/30.png
new file mode 100644
index 000000000..0765ebd75
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/30.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/3181356.jpg b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/3181356.jpg
new file mode 100644
index 000000000..5e324d4f1
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/3181356.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/Bill_Gosper_2006.jpg b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/Bill_Gosper_2006.jpg
new file mode 100644
index 000000000..7c11e5344
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/Bill_Gosper_2006.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/Conway_.jpg b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/Conway_.jpg
new file mode 100644
index 000000000..eb0552d5b
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/Conway_.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/Copperhead.gif b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/Copperhead.gif
new file mode 100644
index 000000000..20419fde6
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/Copperhead.gif differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/Gosperglidergun.gif b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/Gosperglidergun.gif
new file mode 100644
index 000000000..7895ff520
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/Gosperglidergun.gif differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/JohnvonNeumann.gif b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/JohnvonNeumann.gif
new file mode 100644
index 000000000..9c0f1cfd8
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/JohnvonNeumann.gif differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/kirjs.png b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/kirjs.png
new file mode 100644
index 000000000..4e623fbc3
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/kirjs.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/maze.png b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/maze.png
new file mode 100644
index 000000000..ae2054ac6
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/maze.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/metapixel.png b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/metapixel.png
new file mode 100644
index 000000000..b5fef43bb
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/metapixel.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/moore.jpg b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/moore.jpg
new file mode 100644
index 000000000..434a2af25
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/moore.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/nks.jpg b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/nks.jpg
new file mode 100644
index 000000000..69be07738
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/nks.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/turing.gif b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/turing.gif
new file mode 100644
index 000000000..f7a10795e
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/turing.gif differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/turing_js_r.gif b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/turing_js_r.gif
new file mode 100644
index 000000000..f7a10795e
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/turing_js_r.gif differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/wolfram.jpg b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/wolfram.jpg
new file mode 100644
index 000000000..f6e5de42f
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/intro/wolfram.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/oscilators/oscilators.component.css b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/oscilators/oscilators.component.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/oscilators/oscilators.component.html b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/oscilators/oscilators.component.html
new file mode 100644
index 000000000..4aeb856ac
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/oscilators/oscilators.component.html
@@ -0,0 +1,2327 @@
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/oscilators/oscilators.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/oscilators/oscilators.component.spec.ts
new file mode 100644
index 000000000..37c1353c2
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/oscilators/oscilators.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { OscilatorsComponent } from './oscilators.component';
+
+describe('OscilatorsComponent', () => {
+ let component: OscilatorsComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [OscilatorsComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(OscilatorsComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should be created', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/oscilators/oscilators.component.ts b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/oscilators/oscilators.component.ts
new file mode 100644
index 000000000..f586bfda8
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/oscilators/oscilators.component.ts
@@ -0,0 +1,12 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-oscilators',
+ templateUrl: './oscilators.component.html',
+ styleUrls: ['./oscilators.component.css']
+})
+export class OscilatorsComponent implements OnInit {
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule/rule.component.css b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule/rule.component.css
new file mode 100644
index 000000000..b30813d77
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule/rule.component.css
@@ -0,0 +1,13 @@
+:host {
+ margin: 10px 0;
+}
+
+.rule {
+ margin-left: 10px;
+}
+
+.arrow {
+ font-size: 18px;
+ text-align: center;
+ padding: 5px;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule/rule.component.html b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule/rule.component.html
new file mode 100644
index 000000000..0544ee352
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule/rule.component.html
@@ -0,0 +1,3 @@
+
+⇩
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule/rule.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule/rule.component.spec.ts
new file mode 100644
index 000000000..a30e9e078
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule/rule.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { RuleComponent } from './rule.component';
+import { BoardComponent } from '../board/board.component';
+
+describe('RuleComponent', () => {
+ let component: RuleComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [RuleComponent, BoardComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(RuleComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should be created', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule/rule.component.ts b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule/rule.component.ts
new file mode 100644
index 000000000..f9dcb0908
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule/rule.component.ts
@@ -0,0 +1,16 @@
+import { Component, Input, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-rule',
+ templateUrl: './rule.component.html',
+ styleUrls: ['./rule.component.css']
+})
+export class RuleComponent implements OnInit {
+ @Input() before = [];
+ @Input() after = [];
+ @Input() arrow = false;
+
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule3/rule3.component.css b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule3/rule3.component.css
new file mode 100644
index 000000000..5efa370ca
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule3/rule3.component.css
@@ -0,0 +1,16 @@
+.rule {
+ display: flex;
+ width: 100%;
+ justify-content: space-between;
+}
+
+.index {
+ text-align: center;
+ font-size: 50px;
+ flex: 1;
+ margin-left: -20px;
+}
+
+kirjs-rule {
+ margin-right: 20px;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule3/rule3.component.html b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule3/rule3.component.html
new file mode 100644
index 000000000..1980c65ec
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule3/rule3.component.html
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule3/rule3.component.ts b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule3/rule3.component.ts
new file mode 100644
index 000000000..ead55f0a7
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule3/rule3.component.ts
@@ -0,0 +1,37 @@
+import { Component, Input, OnChanges, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-rule3',
+ templateUrl: './rule3.component.html',
+ styleUrls: ['./rule3.component.css']
+})
+export class Rule3Component implements OnInit, OnChanges {
+ after: Array>;
+ before: Array>;
+
+ @Input() rule = 0;
+ @Input() indexes = false;
+ @Input() arrow = false;
+
+ constructor() {}
+
+ ngOnChanges() {
+ this.after = (256 + this.rule)
+ .toString(2)
+ .substr(1)
+ .split('')
+ .map(Number)
+ .map(a => ['x', a, 'x']);
+ // tslint:disable
+ this.before = this.after
+ .map((v, i) =>
+ (8 + i)
+ .toString(2)
+ .substr(1)
+ .split('')
+ )
+ .reverse();
+ }
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule3/rule4/rule4.component.css b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule3/rule4/rule4.component.css
new file mode 100644
index 000000000..6a416af23
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule3/rule4/rule4.component.css
@@ -0,0 +1,23 @@
+.wrapper {
+ display: flex;
+ flex-wrap: wrap;
+}
+
+.rule {
+ margin-left: 10px;
+ margin-top: 10px;
+}
+
+.cell {
+ width: 20px;
+ height: 20px;
+ border: 1px #ddd solid;
+}
+
+.after {
+ margin-left: 20px;
+}
+
+.active {
+ background: lime;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule3/rule4/rule4.component.html b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule3/rule4/rule4.component.html
new file mode 100644
index 000000000..d40edfea0
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule3/rule4/rule4.component.html
@@ -0,0 +1,8 @@
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule3/rule4/rule4.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule3/rule4/rule4.component.spec.ts
new file mode 100644
index 000000000..e67aa1ec4
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule3/rule4/rule4.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { Rule4Component } from './rule4.component';
+
+describe('Rule4Component', () => {
+ let component: Rule4Component;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [Rule4Component]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(Rule4Component);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule3/rule4/rule4.component.ts b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule3/rule4/rule4.component.ts
new file mode 100644
index 000000000..7137a7bb9
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule3/rule4/rule4.component.ts
@@ -0,0 +1,26 @@
+import { Component, Input, OnChanges } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-rule4',
+ templateUrl: './rule4.component.html',
+ styleUrls: ['./rule4.component.css']
+})
+export class Rule4Component implements OnChanges {
+ @Input() test;
+ before: string[][];
+ after: number[];
+
+ ngOnChanges() {
+ this.after = this.test.table.map(a => (a === 'enable' ? 1 : 0));
+
+ this.before = new Array(8)
+ .fill(0)
+ .map((v, i) =>
+ (8 + i)
+ .toString(2)
+ .substr(1)
+ .split('')
+ )
+ .reverse();
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule8/rule8.component.css b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule8/rule8.component.css
new file mode 100644
index 000000000..b8748c993
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule8/rule8.component.css
@@ -0,0 +1,12 @@
+:host {
+ width: 100%;
+}
+
+kirjs-rule {
+ margin-right: 20px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ float: left;
+ margin-bottom: 20px;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule8/rule8.component.html b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule8/rule8.component.html
new file mode 100644
index 000000000..4df6b49c6
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule8/rule8.component.html
@@ -0,0 +1,6 @@
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule8/rule8.component.ts b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule8/rule8.component.ts
new file mode 100644
index 000000000..c2b20172a
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/cellular-automation/rule8/rule8.component.ts
@@ -0,0 +1,29 @@
+import { Component, Input, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-rule8',
+ templateUrl: './rule8.component.html',
+ styleUrls: ['./rule8.component.css']
+})
+export class Rule8Component implements OnInit {
+ after: Array>>;
+ before: Array>>;
+
+ @Input() rule = 0;
+ @Input() arrow = false;
+
+ constructor() {}
+
+ ngOnInit() {
+ const numbers = new Array(1024).fill(0, 0, 1024);
+ this.after = numbers.map(a => [[Math.round(Math.random())]]);
+ this.before = numbers.map((v, i) => {
+ const arr = (1024 + i).toString(2).substr(1);
+ return [
+ arr.substr(0, 3).split(''),
+ arr.substr(3, 3).split(''),
+ arr.substr(6, 3).split('')
+ ];
+ });
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku-print/gomoku-print.component.css b/codelab-master/apps/kirjs/src/app/modules/gomoku-print/gomoku-print.component.css
new file mode 100644
index 000000000..24fcf1016
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku-print/gomoku-print.component.css
@@ -0,0 +1,101 @@
+#intro,
+#outro {
+ /* background: url(./browser/landscape-with-trees-1.jpg) no-repeat; */
+ background-size: 100% auto;
+ display: inline-block;
+}
+
+h1 {
+ font-size: 20px;
+}
+h2 {
+ font-size: 20px;
+}
+
+.hb {
+ width: 200px;
+ height: 200px;
+ background: url('hb.jpg');
+ background-size: 200px;
+ background-repeat: no-repeat;
+}
+
+.header p {
+ font-size: 14px;
+}
+
+b {
+ background: #fff;
+ color: #000;
+ font-size: 14px;
+ font-weight: bold;
+}
+
+li {
+ font-size: 12px;
+}
+
+@media print {
+ @page {
+ size: A4 landscape;
+ }
+}
+
+.front {
+ display: flex;
+ width: 1024px;
+ height: 768px;
+}
+
+.main-board {
+ width: 360px;
+ height: 360px;
+ display: block;
+ margin: 0 auto;
+}
+
+.left,
+.right {
+ width: 512px;
+ box-sizing: border-box;
+ padding: 20px;
+}
+
+.board84 {
+ display: block;
+ width: 120px;
+ height: 60px;
+}
+
+.explanation {
+ display: flex;
+ margin-bottom: 20px;
+}
+
+.explanation .text p {
+ text-align: right;
+ padding-right: 20px;
+ font-size: 12px;
+ margin-bottom: 2px;
+}
+
+.explanation .text {
+ flex: 1;
+ font-size: 12px;
+}
+
+.back {
+ margin: 0 auto;
+ width: 1024px;
+ padding: 0 60px;
+ display: flex;
+ flex-wrap: wrap;
+}
+
+.mini-board {
+ display: block;
+ width: 400px;
+ height: 400px;
+ margin-right: 30px;
+ margin-bottom: 20px;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku-print/gomoku-print.component.html b/codelab-master/apps/kirjs/src/app/modules/gomoku-print/gomoku-print.component.html
new file mode 100644
index 000000000..5d4989e02
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku-print/gomoku-print.component.html
@@ -0,0 +1,98 @@
+
+
+
Hi, I'm Gomoku!
+
+
+
+
+
+
Some gomoku hints:
+
When playing try to create one of the patterns below:
+
+
+
+
’s have an “Open 3” attack.
+
if ’s don’t block it from either side, they lose.
+
+
+
+
+
+
+
This is also an “Open 3” .
+
Now there are 3 places where it can (and should) be blocked.
+
+
+
+
+
+
+
Here ’s have “Open 3”, but X’s went with “Open 4” attack
+
It’s even stronger and must be blocked asap!
+
+
+
+
+
+
+
And here has a “3 by 4 fork”. They will win this game!!
+
’s can’t block both attacks, and will lose.
+
(despite having an “Open 3” attack)
+
+
+
+
+ Enjoy!
+
+
+
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku-print/gomoku-print.component.ts b/codelab-master/apps/kirjs/src/app/modules/gomoku-print/gomoku-print.component.ts
new file mode 100644
index 000000000..e4b698675
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku-print/gomoku-print.component.ts
@@ -0,0 +1,55 @@
+import { Component } from '@angular/core';
+import { parse } from 'babylon';
+import { TicTacToe, Gomoku } from 'gomoku-tools';
+
+declare const require;
+
+@Component({
+ selector: 'kirjs-gomoku',
+ templateUrl: './gomoku-print.component.html',
+ styleUrls: ['./gomoku-print.component.css']
+})
+export class GomokuPrintComponent {
+ fontSize = 18;
+
+ game = new Gomoku().moveTo();
+ examples = {
+ open3: new Gomoku({ cellsX: 8, cellsY: 4 }).moveTo(
+ 'C3',
+ 'C2',
+ 'D3',
+ 'D2',
+ 'E3'
+ ),
+ open32: new Gomoku({ cellsX: 8, cellsY: 4 }).moveTo(
+ 'C3',
+ 'C2',
+ 'D3',
+ 'D2',
+ 'F3'
+ ),
+ close4: new Gomoku({ cellsX: 8, cellsY: 4 }).moveTo(
+ 'C3',
+ 'C2',
+ 'D3',
+ 'D2',
+ 'F3',
+ 'E2',
+ 'E3',
+ 'B3'
+ ),
+ fork: new Gomoku({ cellsX: 8, cellsY: 5 }).moveTo(
+ 'C3',
+ 'C2',
+ 'D3',
+ 'D2',
+ 'F3',
+ 'E2',
+ 'E3',
+ 'B3',
+ 'F4',
+ 'E4',
+ 'F2'
+ )
+ };
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku-print/gomoku-print.module.ts b/codelab-master/apps/kirjs/src/app/modules/gomoku-print/gomoku-print.module.ts
new file mode 100644
index 000000000..3767711a2
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku-print/gomoku-print.module.ts
@@ -0,0 +1,16 @@
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { GomokuPrintComponent } from './gomoku-print.component';
+import { GomokuBoardModule } from '../gomoku/board/board.module';
+import { XComponent } from './x/x.component';
+import { OComponent } from './o/o.component';
+
+@NgModule({
+ imports: [
+ RouterModule.forChild([{ path: `**`, component: GomokuPrintComponent }]),
+ GomokuBoardModule
+ ],
+ declarations: [GomokuPrintComponent, XComponent, OComponent],
+ exports: [GomokuPrintComponent]
+})
+export class GomokuPrintModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku-print/hb.jpg b/codelab-master/apps/kirjs/src/app/modules/gomoku-print/hb.jpg
new file mode 100644
index 000000000..b51cae72b
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/gomoku-print/hb.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku-print/o/o.component.css b/codelab-master/apps/kirjs/src/app/modules/gomoku-print/o/o.component.css
new file mode 100644
index 000000000..fb8455735
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku-print/o/o.component.css
@@ -0,0 +1,6 @@
+:host {
+ color: #444;
+ font-size: 18px;
+ font-weight: bold;
+ line-height: 14px;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku-print/o/o.component.html b/codelab-master/apps/kirjs/src/app/modules/gomoku-print/o/o.component.html
new file mode 100644
index 000000000..13e7564ea
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku-print/o/o.component.html
@@ -0,0 +1 @@
+o
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku-print/o/o.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/gomoku-print/o/o.component.spec.ts
new file mode 100644
index 000000000..98cdd6cfc
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku-print/o/o.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { OComponent } from './o.component';
+
+describe('OComponent', () => {
+ let component: OComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [OComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(OComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku-print/o/o.component.ts b/codelab-master/apps/kirjs/src/app/modules/gomoku-print/o/o.component.ts
new file mode 100644
index 000000000..2a34eba1e
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku-print/o/o.component.ts
@@ -0,0 +1,9 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ // tslint:disable-next-line
+ selector: 'o',
+ templateUrl: './o.component.html',
+ styleUrls: ['./o.component.css']
+})
+export class OComponent {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku-print/x/x.component.css b/codelab-master/apps/kirjs/src/app/modules/gomoku-print/x/x.component.css
new file mode 100644
index 000000000..74f08e54d
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku-print/x/x.component.css
@@ -0,0 +1,7 @@
+:host {
+ color: #c53a00;
+ font-size: 18px;
+ font-weight: bold;
+ line-height: 14px;
+ vertical-align: middle;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku-print/x/x.component.html b/codelab-master/apps/kirjs/src/app/modules/gomoku-print/x/x.component.html
new file mode 100644
index 000000000..024c853b3
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku-print/x/x.component.html
@@ -0,0 +1 @@
+×
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku-print/x/x.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/gomoku-print/x/x.component.spec.ts
new file mode 100644
index 000000000..b818773c4
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku-print/x/x.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { XComponent } from './x.component';
+
+describe('XComponent', () => {
+ let component: XComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [XComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(XComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku-print/x/x.component.ts b/codelab-master/apps/kirjs/src/app/modules/gomoku-print/x/x.component.ts
new file mode 100644
index 000000000..bcc74cd04
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku-print/x/x.component.ts
@@ -0,0 +1,9 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ // tslint:disable-next-line
+ selector: 'x',
+ templateUrl: './x.component.html',
+ styleUrls: ['./x.component.css']
+})
+export class XComponent {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku/board/board.component.html b/codelab-master/apps/kirjs/src/app/modules/gomoku/board/board.component.html
new file mode 100644
index 000000000..6d99643a2
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku/board/board.component.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku/board/board.component.scss b/codelab-master/apps/kirjs/src/app/modules/gomoku/board/board.component.scss
new file mode 100644
index 000000000..f53bbd437
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku/board/board.component.scss
@@ -0,0 +1,96 @@
+.column {
+ display: flex;
+ flex-grow: 1;
+ flex-basis: 0;
+}
+
+kirjs-tools {
+ display: none;
+}
+
+.board {
+ width: 100%;
+ height: 100%;
+ border-left: 1px #999 solid;
+ border-top: 1px #999 solid;
+ display: flex;
+ flex-direction: column;
+}
+
+.cell {
+ &.highlight-yellow {
+ background: #ff0;
+ }
+ &.highlight-orange {
+ background: #ffb900;
+ }
+
+ &.highlight-transparent {
+ opacity: 0.4;
+ }
+
+ flex-grow: 1;
+ flex-basis: 0;
+ border-right: 1px #999 solid;
+ border-bottom: 1px #999 solid;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: relative;
+}
+
+.theme-print {
+ .cell-1:before {
+ content: 'x';
+ color: #c53a00;
+ }
+
+ .cell-2:before {
+ content: 'o';
+ color: #666;
+ }
+ .cell-1:before,
+ .cell-2:before {
+ font-size: 12px;
+ }
+}
+
+.theme-gomoku {
+ .cell-1:before {
+ content: '⚫';
+ }
+
+ .cell-2:before {
+ content: '🔴';
+ }
+ .cell-3:before {
+ content: '⚫';
+ opacity: 0.5;
+ }
+
+ .cell-4:before {
+ content: '🔴';
+ opacity: 0.5;
+ }
+ .cell-1:before,
+ .cell-2:before {
+ font-size: 28px;
+ }
+}
+
+.theme-xo {
+ .cell-1:before {
+ content: '×';
+ color: red;
+ }
+
+ .cell-2:before {
+ content: '⚬';
+ color: blue;
+ }
+
+ .cell-1:before,
+ .cell-2:before {
+ font-size: 200px;
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku/board/board.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/gomoku/board/board.component.spec.ts
new file mode 100644
index 000000000..5c8d230f4
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku/board/board.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { BoardComponent } from './board.component';
+import { ToolsComponent } from '../tools/tools.component';
+
+describe('BoardComponent', () => {
+ let component: BoardComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [BoardComponent, ToolsComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(BoardComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku/board/board.component.ts b/codelab-master/apps/kirjs/src/app/modules/gomoku/board/board.component.ts
new file mode 100644
index 000000000..7fcaaf55f
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku/board/board.component.ts
@@ -0,0 +1,57 @@
+import { Component, HostListener, Input } from '@angular/core';
+import { Gomoku } from 'gomoku-tools';
+import { Highlights } from '../highlights';
+
+@Component({
+ selector: 'kirjs-board',
+ templateUrl: './board.component.html',
+ styleUrls: ['./board.component.scss']
+})
+export class BoardComponent {
+ @Input() theme = 'gomoku';
+ @Input() game = new Gomoku().moveTo(
+ 'H8',
+ 'I8',
+ 'H9',
+ 'H7',
+ 'J9',
+ 'I9',
+ 'I10',
+ 'H11',
+ 'J11',
+ 'K12',
+ 'J10',
+ 'J12',
+ 'G10',
+ 'H10',
+ 'G8',
+ 'F7',
+ 'G9',
+ 'G7',
+ 'I7',
+ 'J6',
+ 'H12'
+ );
+ @Input() highlights = new Highlights();
+ @Input() showTools = true;
+
+ @HostListener('window:keydown.H', ['$event.target'])
+ @HostListener('window:keydown.J', ['$event.target'])
+ back() {
+ this.game.back();
+ }
+
+ @HostListener('window:keydown.T', ['$event.target'])
+ @HostListener('window:keydown.K', ['$event.target'])
+ forward() {
+ this.game.forward();
+ }
+
+ constructor() {}
+
+ log() {
+ console.log(this.game.getHistory());
+ console.log(this.game.getHistory().length);
+ console.log(this.highlights.highlights);
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku/board/board.module.ts b/codelab-master/apps/kirjs/src/app/modules/gomoku/board/board.module.ts
new file mode 100644
index 000000000..8d044d686
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku/board/board.module.ts
@@ -0,0 +1,11 @@
+import { NgModule } from '@angular/core';
+import { BoardComponent } from './board.component';
+import { CommonModule } from '@angular/common';
+import { ToolsComponent } from '../tools/tools.component';
+
+@NgModule({
+ imports: [CommonModule],
+ declarations: [BoardComponent, ToolsComponent],
+ exports: [BoardComponent]
+})
+export class GomokuBoardModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku/gomoku.component.css b/codelab-master/apps/kirjs/src/app/modules/gomoku/gomoku.component.css
new file mode 100644
index 000000000..bdefc00d1
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku/gomoku.component.css
@@ -0,0 +1,65 @@
+#intro,
+#outro {
+ /* background: url(./browser/landscape-with-trees-1.jpg) no-repeat; */
+ background-size: 100% auto;
+ display: inline-block;
+ height: 100vh;
+}
+
+input[type='checkbox'] {
+ transform: scale(2);
+}
+
+.hb,
+cake {
+ width: 100vw;
+ height: 200px;
+ background-position: center center;
+ background-color: white;
+ background-image: url('print/hb.jpg');
+ background-size: 300px;
+ background-repeat: no-repeat;
+}
+kirjs-board {
+ width: 500px;
+ height: 500px;
+}
+
+:host ::ng-deep [title][blue] .slide {
+ background: #0079ff;
+}
+
+:host ::ng-deep [title] .slide {
+ align-items: center;
+ background: #ff6e00;
+ color: white;
+ display: flex;
+ height: 100vh;
+ justify-content: center;
+ text-align: center;
+ width: 100%;
+}
+
+h1 {
+ font-size: 100px;
+}
+
+tr:first-child td {
+ background: #ff6e00;
+}
+
+td,
+th {
+ font-size: 40px;
+ padding: 20px;
+}
+
+b {
+ background: transparent;
+ color: black;
+ text-decoration: underline dotted;
+}
+
+a {
+ color: #444;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku/gomoku.component.html b/codelab-master/apps/kirjs/src/app/modules/gomoku/gomoku.component.html
new file mode 100644
index 000000000..7b51c2961
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku/gomoku.component.html
@@ -0,0 +1,282 @@
+
+
+
+
+
+
+
+
+
+
Plan
+
+ What's gomoku?
+ Rules
+ Why Gomoku?
+ Gomoku and Computers
+ Sample game
+
+
+
+
+
+
+
Gomoku
+ Abstract strategy board game
+ coming from ancient asia (China & Japan)
+
+
+
+
tic-tac-toe
+
+
+
+
+
Gomoku
+
+
+
+
Rules
+
+
+
Rule 1: Black puts a stone first
+
+
+
+
+
+ Rule 2: Players alternate, putting a stone of their color on an empty cell
+
+
+
+
+
+
Rule 3: The first player to get 5 in a row wins
+
+
+
+
+
+
+
+
+
8 Reasons to play Gomoku
+
+
+
+
1. Brain massage
+
+ Lots of memorization
+ Patterns recognition
+ Problem solving
+ A lot of gomoku playes became successful at poker
+
+
+
+
+
2. Transferable life skills
+
+ Learn to win/lose
+ Opportunities to learn from mistakes
+ The skill is directly proportional to the amount of work put in
+ Strategical/Tacting thinking
+ Understanding consequences / thinking ahead
+
+
+
+
+
3. Social Aspect
+
+ Cross cultures/ages/accessible to everyone
+ Play people from different countries
+ Play in Tournaments or online
+ Play solo or in a team.
+ Hopefully soon play in real life :)
+
+
+
+
+
4. Quantifiable
+
+ All stats are out there
+ Learning curve - plateaus and accelerations.
+
+
+
+
+
5. Easy to start
+
+ Can play with pen and paper
+ Play online
+ A bunch of android apps
+ Very simple rules
+
+
+
+
+
6.Not very popular in the US
+
+ Very few people are playing
+ Not much has been done
+ Not much learning materials/tutorials/videos in english
+
+
+
+
+
7. Lots of space for technical solutions
+
+ No good database of games
+ Existing online playing platforms not perfect
+
+
+
8. It's Fun!
+
+
Gomoku and Computers 🤖
+
+
+
Complexity
+
+
+ Game
+ Space/State as log to base 10
+ Game Tree as log to base 10
+ Branching Factor
+
+
+ Gomoku
+ 105
+ 70
+ 210
+
+
+ Chess
+ 47
+ 123
+ 35
+
+
+ Go
+ 170
+ 360
+ 250
+
+
+ Draughts (8x8)
+ 20
+ 20
+ 2.8
+
+
+ Tic-Tac-Toe
+ 3
+ 5
+ 4
+
+
+
+
More on wikipedia
+
+
+
+
In the initial rules ⚫️ always started in the center
+
+
+
+
+ In 1994 Victor Ellis proved that this way ⚫️ always win.
+
+ 📄
+
+
+
+
+
+
+ Since then more advanced opening rules have been used, which haven't yet
+ been solved.
+
+
+
+
+
One of them is swap2
+
+
(Using divide and choose)
+
+
+
+
Black is stronger
+
+
+
+
+
A draw?
+
+
+
+
+
White surewin
+
+
+
+
+
Swap2 opening hasn't been solved by a computer
+
+
+
+
+ Gomocup is a yearly gomoku AI
+ tournament.
+
+
+
+
Now let's look at a real game
+
+
+
Very Advanced - Defend from 4s
+
+
+
+
How to start playing
+
+
How to start playing
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku/gomoku.component.ts b/codelab-master/apps/kirjs/src/app/modules/gomoku/gomoku.component.ts
new file mode 100644
index 000000000..b3255a745
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku/gomoku.component.ts
@@ -0,0 +1,473 @@
+import { Component } from '@angular/core';
+import { parse } from 'babylon';
+import { TicTacToe, Gomoku } from 'gomoku-tools';
+import utils from 'gomoku-tools/src/tools/utils';
+
+declare const require;
+
+const json = require('./renlib/moves.json');
+
+class Node {
+ p: string;
+ down: boolean;
+ depth = 0;
+ parent: Node;
+ children: Node[] = [];
+
+ constructor(public position: [number, number]) {
+ this.p = position.join(',');
+ }
+
+ addChild(node: Node) {
+ this.children.push(node);
+ node.parent = this;
+ node.depth = this.depth + 1;
+ }
+}
+
+let i = 0;
+
+function buildTree(moves, index, parentNode) {
+ i++;
+ const move = moves[index];
+ let node = new Node(move.move);
+ node.down = !!move.down;
+
+ parentNode.addChild(node);
+
+ if (index + 1 < moves.length) {
+ if (move.down) {
+ node.down = true;
+ }
+
+ if (move.right) {
+ while (node && !node.down) {
+ if (!node) {
+ throw new Error('Weird');
+ }
+
+ node = node.parent;
+ }
+ node = node.parent;
+ }
+ return buildTree(moves, index + 1, node);
+ }
+}
+
+const parent = new Node([2, 2]);
+
+buildTree(json.moves, 0, parent);
+console.log(i);
+
+class RenlibGame {
+ private current: Node;
+ parent;
+
+ constructor(private start) {
+ this.current = start;
+ }
+
+ back() {
+ if (this.current.parent) {
+ this.current = this.current.parent;
+ }
+ }
+
+ moveTo(point) {
+ let child = this.current.children.find(
+ ({ position }) => position[0] === point[0] && position[1] === point[1]
+ );
+
+ if (!child) {
+ child = new Node(point);
+ this.current.children.push(child);
+ }
+ this.current = child;
+ }
+
+ forward() {}
+
+ getPosition() {
+ let node = this.current;
+
+ const game = [node.position];
+ while ((node = node.parent)) {
+ game.push(node.position);
+ }
+
+ const putStones = (stones, move, index) => {
+ stones[move[0]][move[1]] = (index % 2) + 1;
+ return stones;
+ };
+ const position = game
+ .reverse()
+ .reduce(putStones, utils.generateEmptyPosition(15, 15));
+
+ this.current.children
+ .map(n => n.position)
+ .reduce((stones, move) => {
+ stones[move[0]][move[1]] = (game.length % 2) + 1 + 2;
+ return stones;
+ }, position);
+
+ console.log(position);
+ return position;
+ }
+}
+
+@Component({
+ selector: 'kirjs-gomoku',
+ templateUrl: './gomoku.component.html',
+ styleUrls: ['./gomoku.component.css']
+})
+export class GomokuComponent {
+ fontSize = 18;
+
+ games = {
+ renlib: new RenlibGame(parent),
+ ticTacToe: new TicTacToe().moveTo('B2', 'A2', 'A1', 'C3', 'B1', 'B3', 'C1'),
+ empty: new Gomoku().moveTo(),
+ start: new Gomoku().moveTo('H8'),
+ start2: new Gomoku().moveTo('H8', 'H7'),
+ swap2: new Gomoku().moveTo('H8', 'E7', 'G8'), // Sure win
+ swap23: new Gomoku().moveTo('H8', 'E7', 'F10'), // Draw
+ swap24: new Gomoku().moveTo('H8', 'H13', 'M10'), // White surewin H11, 10 horizontal
+ swap25: new Gomoku().moveTo('C3', 'L7', 'F8'), // White surewin
+ swap26: new Gomoku().moveTo('H8', 'J8', 'M8'), // Central Draw
+ start5: new Gomoku()
+ .moveTo('H8', 'H7', 'I8', 'I7', 'J8', 'J7', 'K8', 'K7', 'L8')
+ .jumpToMove(2),
+ sample: new Gomoku()
+ .moveTo('H8', 'I7', 'H7', 'H6', 'G8', 'I8', 'H9', 'I6')
+ .jumpToMove(2),
+ start52: new Gomoku().moveTo(
+ 'H8',
+ 'H7',
+ 'I8',
+ 'I7',
+ 'J8',
+ 'K8',
+ 'J9',
+ 'J7',
+ 'G8',
+ 'F8',
+ 'G7',
+ 'K7',
+ 'L7',
+ 'I6',
+ 'L9',
+ 'K5',
+ 'K9',
+ 'H5',
+ 'G4',
+ 'K4',
+ 'K6',
+ 'J5',
+ 'L3',
+ 'I5',
+ 'L5',
+ 'G5'
+ ),
+ fork33: new Gomoku().moveTo('H8', 'H7', 'I8', 'I7', 'J7', 'I6', 'J6', 'H6'),
+ fork43: new Gomoku().moveTo(
+ 'H8',
+ 'H7',
+ 'I8',
+ 'I7',
+ 'J7',
+ 'I6',
+ 'J6',
+ 'H6',
+ 'G8',
+ 'F8'
+ ),
+ fork44: new Gomoku().moveTo(
+ 'H8',
+ 'H7',
+ 'I8',
+ 'I7',
+ 'J7',
+ 'I6',
+ 'J6',
+ 'H6',
+ 'G8',
+ 'F8',
+ 'J5',
+ 'J4'
+ ),
+ wonGame: new Gomoku().moveTo(
+ 'H8',
+ 'I10',
+ 'I11',
+ 'H10',
+ 'J10',
+ 'I9',
+ 'J8',
+ 'J9',
+ 'K9',
+ 'L8',
+ 'G9',
+ 'I7',
+ 'I6',
+ 'I8',
+ 'G8',
+ 'L7',
+ 'K8',
+ 'L9',
+ 'L10',
+ 'J7',
+ 'K7',
+ 'L5',
+ 'L6',
+ 'K6',
+ 'M4',
+ 'H9'
+ ),
+ openThree: new Gomoku().moveTo('H8', 'H7', 'I8', 'I7', 'J8'),
+ old: new Gomoku().moveTo(
+ 'h8',
+ 'i8',
+ 'h7',
+ 'h9',
+ 'j7',
+ 'i7',
+ 'i6',
+ 'j5',
+ 'h5',
+ 'g4',
+ 'h6',
+ 'h4',
+ 'f6',
+ 'g6',
+ 'g7',
+ 'e5',
+ 'f8',
+ 'e9',
+ 'f9',
+ 'f7',
+ 'g8',
+ 'e10',
+ 'j10',
+ 'i9',
+ 'j9',
+ 'i10',
+ 'i11',
+ 'j8',
+ 'e8',
+ 'd8',
+ 'h11',
+ 'g10',
+ 'h10',
+ 'j12',
+ 'k9',
+ 'f11',
+ 'e12',
+ 'l8',
+ 'k11',
+ 'k8',
+ 'm8',
+ 'g11',
+ 'h12',
+ 'g13',
+ 'g12',
+ 'f12',
+ 'e11',
+ 'f4',
+ 'i4',
+ 'c7',
+ 'f10',
+ 'd6',
+ 'g9',
+ 'g3'
+ ),
+ moreFours: new Gomoku().moveTo(
+ 'C14',
+ 'C12',
+ 'D14',
+ 'D12',
+ 'E14',
+ 'F12',
+ 'G14',
+ 'G12',
+ 'C10',
+ 'B10',
+ 'E10',
+ 'O1',
+ 'F10',
+ 'N1',
+ 'G10',
+ 'H10'
+ ),
+ openThreeSpaced: new Gomoku().moveTo('H8', 'H7', 'I8', 'I7', 'K8'),
+ closedFour: new Gomoku().moveTo(
+ 'H8',
+ 'H7',
+ 'I8',
+ 'I7',
+ 'J8',
+ 'K8',
+ 'J9',
+ 'J7',
+ 'G8'
+ ),
+ closedBrokenFour: new Gomoku().moveTo(
+ 'H8',
+ 'H7',
+ 'I8',
+ 'I7',
+ 'J8',
+ 'K8',
+ 'J9',
+ 'J7',
+ 'F8'
+ ),
+ findWin: new Gomoku().moveTo(
+ 'H8',
+ 'H7',
+ 'I8',
+ 'I7',
+ 'J8',
+ 'K8',
+ 'J9',
+ 'J7',
+ 'G8',
+ 'F8',
+ 'G7',
+ 'K7',
+ 'L7',
+ 'I6',
+ 'L9'
+ ),
+ defendFrom4s: new Gomoku().moveTo(
+ 'H8',
+ 'H7',
+ 'I8',
+ 'I7',
+ 'J8',
+ 'K8',
+ 'J9',
+ 'J7',
+ 'G8',
+ 'F8',
+ 'G7',
+ 'K7',
+ 'L7',
+ 'I6',
+ 'L9',
+ 'K5',
+ 'K6',
+ 'H5',
+ 'G4',
+ 'I5',
+ 'J5',
+ 'I4',
+ 'I3'
+ ),
+ defendFrom4sSolved: new Gomoku().moveTo(
+ 'H8',
+ 'H7',
+ 'I8',
+ 'I7',
+ 'J8',
+ 'K8',
+ 'J9',
+ 'J7',
+ 'G8',
+ 'F8',
+ 'G7',
+ 'K7',
+ 'L7',
+ 'I6',
+ 'L9',
+ 'K5',
+ 'K6',
+ 'H5',
+ 'G4',
+ 'I5',
+ 'J5',
+ 'I4',
+ 'I3',
+ 'J6',
+ 'N9',
+ 'M8',
+ 'K9',
+ 'M9',
+ 'L8',
+ 'H4',
+ 'G3',
+ 'H6',
+ 'H3',
+ 'G6',
+ 'F6'
+ ),
+ many4s: new Gomoku()
+ .moveTo(
+ 'h8',
+ 'i9',
+ 'j9',
+ 'j8',
+ 'h11',
+ 'h10',
+ 'g11',
+ 'i11',
+ 'i10',
+ 'g12',
+ 'g9',
+ 'f10',
+ 'g8',
+ 'g10',
+ 'e10',
+ 'f9',
+ 'f7',
+ 'h9',
+ 'f11',
+ 'e8',
+ 'd7',
+ 'e6',
+ 'g5',
+ 'g7',
+ 'e5',
+ 'f4',
+ 'd8',
+ 'd9',
+ 'd5',
+ 'c5',
+ 'h5',
+ 'f5',
+ 'f3',
+ 'g4',
+ 'h4',
+ 'h3',
+ 'i2',
+ 'i3',
+ 'j3',
+ 'j5',
+ 'k4',
+ 'l5',
+ 'e7',
+ 'f6',
+ 'b7',
+ 'c7',
+ 'e4',
+ 'c6',
+ 'g2',
+ 'h1',
+ 'i4',
+ 'g6',
+ 'd6',
+ 'd4',
+ 'h6',
+ 'h7',
+ 'k2',
+ 'l1',
+ 'j2',
+ 'h2',
+ 'l2',
+ 'm2',
+ 'j4',
+ 'l4',
+ 'k3'
+ )
+ .jumpToMove(39)
+ };
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku/gomoku.module.ts b/codelab-master/apps/kirjs/src/app/modules/gomoku/gomoku.module.ts
new file mode 100644
index 000000000..796989e51
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku/gomoku.module.ts
@@ -0,0 +1,25 @@
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { CommonModule } from '@angular/common';
+import { SlidesModule, SlidesRoutes } from '@ng360/slides';
+import { FeedbackModule } from '@codelab/feedback';
+import { BrowserWindowModule } from '@codelab/browser';
+import { GomokuComponent } from './gomoku.component';
+import { GomokuBoardModule } from './board/board.module';
+
+const routes = RouterModule.forChild(SlidesRoutes.get(GomokuComponent));
+
+@NgModule({
+ imports: [
+ routes,
+
+ BrowserWindowModule,
+ FeedbackModule,
+ CommonModule,
+ GomokuBoardModule,
+ SlidesModule
+ ],
+ declarations: [GomokuComponent],
+ exports: [GomokuComponent]
+})
+export class GomokuModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku/highlights.spec.ts b/codelab-master/apps/kirjs/src/app/modules/gomoku/highlights.spec.ts
new file mode 100644
index 000000000..e92274b22
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku/highlights.spec.ts
@@ -0,0 +1,33 @@
+import { Highlights } from './highlights';
+
+describe('highlights', () => {
+ beforeEach(() => {
+ this.highlights = new Highlights();
+ });
+
+ it('gets empty value if there are no highlightss set', () => {
+ expect(this.highlights.get([0, 0])).toBe('');
+ });
+
+ it('Toggles single value', () => {
+ this.highlights.toggle([1, 2], 'pirojok');
+ expect(this.highlights.get([1, 2])).toBe('pirojok');
+ expect(this.highlights.get([5, 5])).toBe('');
+ this.highlights.toggle([1, 2], 'pirojok');
+ expect(this.highlights.get([1, 2])).toBe('');
+ });
+
+ it('Toggles multiple values', () => {
+ this.highlights.toggle([1, 2], 'a');
+ this.highlights.toggle([1, 2], 'b');
+ expect(this.highlights.get([1, 2])).toBe('a b');
+ this.highlights.toggle([1, 2], 'c');
+ expect(this.highlights.get([1, 2])).toBe('a b c');
+ this.highlights.toggle([1, 2], 'b');
+ expect(this.highlights.get([1, 2])).toBe('a c');
+ });
+
+ it('Allows chaning', () => {
+ expect(this.highlights.toggle([1, 2], 'a').get([1, 2])).toBe('a');
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku/highlights.ts b/codelab-master/apps/kirjs/src/app/modules/gomoku/highlights.ts
new file mode 100644
index 000000000..b062c4f53
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku/highlights.ts
@@ -0,0 +1,67 @@
+export class Highlights {
+ history = [];
+ historyIndex = 0;
+
+ constructor(public highlights = []) {}
+
+ redo() {
+ if (this.historyIndex < this.history.length) {
+ this.historyIndex++;
+ const change = this.history[this.historyIndex];
+ this.highlights[change.point[0]][change.point[1]] = change.newValue;
+ }
+ }
+
+ undo() {
+ if (this.historyIndex > 0) {
+ this.historyIndex--;
+ const change = this.history[this.historyIndex];
+ this.highlights[change.point[0]][change.point[1]] = change.oldValue;
+ }
+ }
+
+ toggle([x, y], type) {
+ this.highlights[x] = this.highlights[x] || [];
+ this.highlights[x][y] = this.highlights[x][y] || [];
+ const oldValue = [...this.highlights[x][y]];
+ let newValue;
+ if (this.highlights[x][y].includes(type)) {
+ newValue = this.highlights[x][y] = this.highlights[x][y].filter(
+ a => a !== type
+ );
+ } else {
+ this.highlights[x][y].push(type);
+ newValue = this.highlights[x][y];
+ }
+
+ this.history = this.history.slice(0, this.historyIndex);
+ this.history.push({
+ point: [x, y],
+ oldValue,
+ newValue
+ });
+
+ this.historyIndex++;
+
+ return this;
+ }
+
+ get([x, y]) {
+ return (
+ (this.highlights[x] &&
+ this.highlights[x][y] &&
+ this.highlights[x][y].join(' ')) ||
+ ''
+ );
+ }
+
+ clear(point?) {
+ const [x, y] = point;
+ if (point) {
+ this.highlights[x] = this.highlights[x] || [];
+ this.highlights[x][y] = [];
+ } else {
+ this.highlights = [];
+ }
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku/print/hb.jpg b/codelab-master/apps/kirjs/src/app/modules/gomoku/print/hb.jpg
new file mode 100644
index 000000000..b51cae72b
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/gomoku/print/hb.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku/renlib/I7.lib b/codelab-master/apps/kirjs/src/app/modules/gomoku/renlib/I7.lib
new file mode 100644
index 000000000..7152b8100
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/gomoku/renlib/I7.lib differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku/renlib/lines.lib b/codelab-master/apps/kirjs/src/app/modules/gomoku/renlib/lines.lib
new file mode 100644
index 000000000..21912ff95
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/gomoku/renlib/lines.lib differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku/renlib/moves.json b/codelab-master/apps/kirjs/src/app/modules/gomoku/renlib/moves.json
new file mode 100644
index 000000000..14cdd9177
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku/renlib/moves.json
@@ -0,0 +1,173 @@
+{
+ "header": { "open": 255, "type": "RenLib", "major": 3, "minor": 0 },
+ "moves": [
+ {
+ "move": [7, 7],
+ "down": 0,
+ "right": 0,
+ "hz4": 0,
+ "mark": 0,
+ "hasComment": 0,
+ "hz2": 0,
+ "hz1": 0,
+ "extension": 0,
+ "comment": {}
+ },
+ {
+ "move": [6, 7],
+ "down": 1,
+ "right": 0,
+ "hz4": 0,
+ "mark": 0,
+ "hasComment": 0,
+ "hz2": 0,
+ "hz1": 0,
+ "extension": 0,
+ "comment": {}
+ },
+ {
+ "move": [5, 7],
+ "down": 0,
+ "right": 0,
+ "hz4": 0,
+ "mark": 0,
+ "hasComment": 0,
+ "hz2": 0,
+ "hz1": 0,
+ "extension": 0,
+ "comment": {}
+ },
+ {
+ "move": [4, 7],
+ "down": 0,
+ "right": 0,
+ "hz4": 0,
+ "mark": 0,
+ "hasComment": 0,
+ "hz2": 0,
+ "hz1": 0,
+ "extension": 0,
+ "comment": {}
+ },
+ {
+ "move": [3, 7],
+ "down": 0,
+ "right": 0,
+ "hz4": 0,
+ "mark": 0,
+ "hasComment": 0,
+ "hz2": 0,
+ "hz1": 0,
+ "extension": 0,
+ "comment": {}
+ },
+ {
+ "move": [2, 7],
+ "down": 0,
+ "right": 0,
+ "hz4": 0,
+ "mark": 0,
+ "hasComment": 0,
+ "hz2": 0,
+ "hz1": 0,
+ "extension": 0,
+ "comment": {}
+ },
+ {
+ "move": [1, 7],
+ "down": 0,
+ "right": 0,
+ "hz4": 0,
+ "mark": 0,
+ "hasComment": 0,
+ "hz2": 0,
+ "hz1": 0,
+ "extension": 0,
+ "comment": {}
+ },
+ {
+ "move": [0, 7],
+ "down": 0,
+ "right": 1,
+ "hz4": 0,
+ "mark": 0,
+ "hasComment": 0,
+ "hz2": 0,
+ "hz1": 0,
+ "extension": 0,
+ "comment": {}
+ },
+ {
+ "move": [6, 8],
+ "down": 1,
+ "right": 0,
+ "hz4": 0,
+ "mark": 0,
+ "hasComment": 0,
+ "hz2": 0,
+ "hz1": 0,
+ "extension": 0,
+ "comment": {}
+ },
+ {
+ "move": [5, 9],
+ "down": 0,
+ "right": 0,
+ "hz4": 0,
+ "mark": 0,
+ "hasComment": 0,
+ "hz2": 0,
+ "hz1": 0,
+ "extension": 0,
+ "comment": {}
+ },
+ {
+ "move": [4, 8],
+ "down": 1,
+ "right": 1,
+ "hz4": 0,
+ "mark": 0,
+ "hasComment": 0,
+ "hz2": 0,
+ "hz1": 0,
+ "extension": 0,
+ "comment": {}
+ },
+ {
+ "move": [4, 10],
+ "down": 0,
+ "right": 0,
+ "hz4": 0,
+ "mark": 0,
+ "hasComment": 0,
+ "hz2": 0,
+ "hz1": 0,
+ "extension": 0,
+ "comment": {}
+ },
+ {
+ "move": [3, 11],
+ "down": 0,
+ "right": 1,
+ "hz4": 0,
+ "mark": 0,
+ "hasComment": 0,
+ "hz2": 0,
+ "hz1": 0,
+ "extension": 0,
+ "comment": {}
+ },
+ {
+ "move": [7, 8],
+ "down": 0,
+ "right": 1,
+ "hz4": 0,
+ "mark": 0,
+ "hasComment": 0,
+ "hz2": 0,
+ "hz1": 0,
+ "extension": 0,
+ "comment": {}
+ }
+ ]
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku/renlib/parse.js b/codelab-master/apps/kirjs/src/app/modules/gomoku/renlib/parse.js
new file mode 100644
index 000000000..7ebf010c2
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku/renlib/parse.js
@@ -0,0 +1,64 @@
+// Module import
+const fs = require('fs');
+const Parser = require('binary-parser').Parser;
+
+const readComment = Parser.start()
+ .array('comment', {
+ type: 'uint8',
+ readUntil: function(a, b) {
+ return b.readUInt16LE() === 0 || b.length < 3;
+ },
+ formatter: function(a) {
+ return a
+ .map(v => String.fromCharCode(parseInt(v, 10).toString(10)))
+ .join('');
+ }
+ })
+ .skip(2);
+
+const readMove = Parser.start()
+ .uint8('move', {
+ formatter: flag => [(flag % 16) - 1, Math.ceil(flag / 16) - 1]
+ })
+ .bit1('down') // 128 Has Siblings
+ .bit1('right') // 64 Has a child node, into the subtree
+ .bit1('hz4')
+ .bit1('mark')
+ .bit1('hasComment')
+ .bit1('hz2')
+ .bit1('hz1')
+ .bit1('extension')
+ .choice('comment', {
+ tag: 'hasComment',
+ choices: {
+ 0: Parser.start(),
+ 1: readComment
+ }
+ });
+
+const header = Parser.start()
+ .endianess('little')
+ .uint8('open', { assert: 255 })
+ .string('type', {
+ length: 6,
+ assert: 'RenLib'
+ })
+ .uint8('open', { assert: 255 })
+ .int8('major', { assert: 3 })
+ .int8('minor')
+ .skip(10);
+
+p = new Parser()
+ .nest('header', {
+ type: header
+ })
+ .array('moves', {
+ type: readMove,
+ readUntil: 'eof'
+ });
+
+require('fs').readFile('ss.lib', function(err, data) {
+ const v = p.parse(data);
+ console.log(JSON.stringify(v));
+ fs.writeFileSync('moves.json', JSON.stringify(v), 'UTF-8');
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku/renlib/ss.lib b/codelab-master/apps/kirjs/src/app/modules/gomoku/renlib/ss.lib
new file mode 100644
index 000000000..d7affbd91
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/gomoku/renlib/ss.lib differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku/renlib/test.lib b/codelab-master/apps/kirjs/src/app/modules/gomoku/renlib/test.lib
new file mode 100644
index 000000000..600e04664
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/gomoku/renlib/test.lib differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku/tools/tools.component.css b/codelab-master/apps/kirjs/src/app/modules/gomoku/tools/tools.component.css
new file mode 100644
index 000000000..8a67333b1
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku/tools/tools.component.css
@@ -0,0 +1,48 @@
+.tools {
+ display: flex;
+}
+
+.tool.selected {
+ outline: 1px #888 solid;
+ background: #eeeeee;
+}
+
+.tool {
+ outline: 1px #ddd solid;
+ width: 30px;
+ height: 30px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.tool-next:before {
+ content: '?';
+}
+
+.tool-clear:before {
+ content: 'X';
+}
+
+.tool-undo:before {
+ content: '⎌';
+}
+
+.tool-redo {
+ content: '⎌';
+ transform: scale(-1, 1);
+}
+
+.tool-red-maybe:before {
+ content: '🔴';
+ opacity: 0.5;
+}
+
+.tool-highlight:before {
+ content: '▩';
+}
+
+.tool-black-maybe:before {
+ content: '⚫';
+ opacity: 0.5;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku/tools/tools.component.html b/codelab-master/apps/kirjs/src/app/modules/gomoku/tools/tools.component.html
new file mode 100644
index 000000000..58089fe00
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku/tools/tools.component.html
@@ -0,0 +1,9 @@
+
+{{ selectedTool | json }}?
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku/tools/tools.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/gomoku/tools/tools.component.spec.ts
new file mode 100644
index 000000000..19c3fc584
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku/tools/tools.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ToolsComponent } from './tools.component';
+
+describe('ToolsComponent', () => {
+ let component: ToolsComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ToolsComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ToolsComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/gomoku/tools/tools.component.ts b/codelab-master/apps/kirjs/src/app/modules/gomoku/tools/tools.component.ts
new file mode 100644
index 000000000..97d47d07f
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/gomoku/tools/tools.component.ts
@@ -0,0 +1,109 @@
+import { Component, HostListener, Input, OnInit } from '@angular/core';
+import { Highlights } from '../highlights';
+
+@Component({
+ selector: 'kirjs-tools',
+ templateUrl: './tools.component.html',
+ styleUrls: ['./tools.component.css']
+})
+export class ToolsComponent implements OnInit {
+ @Input() game;
+ @Input() highlights;
+
+ tools = [
+ {
+ name: 'next',
+ action: function(point, game) {
+ game.moveTo(point);
+ },
+ init: function() {
+ return this;
+ }
+ },
+ {
+ name: 'red-maybe',
+ action: function(point, game, highlights) {
+ highlights.toggle(point, 'highlight-transparent cell-2');
+ },
+ init: function() {
+ return this;
+ }
+ },
+ {
+ name: 'black-maybe',
+ action: function(point, game, highlights) {
+ highlights.toggle(point, 'highlight-transparent cell-1');
+ },
+ init: function() {
+ return this;
+ }
+ },
+ {
+ name: 'highlight',
+ action: function(point, game, highlights) {
+ highlights.toggle(point, 'highlight-yellow');
+ },
+ init: function() {
+ return this;
+ }
+ },
+ {
+ name: 'highlight2',
+ action: function(point, game, highlights: Highlights) {
+ highlights.toggle(point, 'highlight-orange');
+ },
+ init: function() {
+ return this;
+ }
+ },
+ {
+ name: 'clear',
+ action: function(point, game, highlights) {
+ highlights.clear(point);
+ },
+ init: function() {
+ return this;
+ }
+ },
+ {
+ name: 'clear-all',
+ init: function(game, highlights: Highlights) {
+ highlights.clear();
+ }
+ },
+ {
+ name: 'undo',
+ init: function(game, highlights: Highlights) {
+ highlights.undo();
+ }
+ },
+ {
+ name: 'redo',
+ init: function(game, highlights: Highlights) {
+ highlights.redo();
+ }
+ }
+ ];
+ selectedTool: any;
+
+ @HostListener('window:keydown', ['$event.keyCode'])
+ shortcut(a: number) {
+ if (a >= 48 && a <= 57) {
+ this.handle(this.tools[a - 49]);
+ }
+ }
+
+ handle(tool) {
+ const selected = tool.init(this.game, this.highlights);
+
+ if (selected) {
+ this.selectedTool = tool;
+ }
+ }
+
+ constructor() {
+ this.selectedTool = this.tools[0];
+ }
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/home/home.component.css b/codelab-master/apps/kirjs/src/app/modules/home/home.component.css
new file mode 100644
index 000000000..80f2b1526
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/home/home.component.css
@@ -0,0 +1,37 @@
+.wrapper {
+ font-family: 'Helvetica Neue', sans-serif;
+ font-weight: 300;
+ border-top: 10vw black solid;
+ border-bottom: 10vw black solid;
+ box-sizing: border-box;
+}
+
+kirjs-polaroid {
+ display: block;
+ margin-left: 30px;
+}
+
+.picture.fb {
+ background: url(pics/fb.png);
+ background-size: cover;
+}
+
+.picture.lastfm {
+ background: url(pics/lastfm.png);
+ background-size: cover;
+}
+
+.picture.binary {
+ background: url(pics/binary.png);
+ background-size: cover;
+}
+
+.picture.kirjs {
+ background: url(pics/kirjs.jpg);
+ background-size: cover;
+}
+
+a {
+ text-decoration: none;
+ color: #444;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/home/home.component.html b/codelab-master/apps/kirjs/src/app/modules/home/home.component.html
new file mode 100644
index 000000000..997aa7454
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/home/home.component.html
@@ -0,0 +1,57 @@
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/home/home.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/home/home.component.spec.ts
new file mode 100644
index 000000000..7e1d513de
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/home/home.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { HomeComponent } from './home.component';
+
+describe('HomeComponent', () => {
+ let component: HomeComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [HomeComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(HomeComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/home/home.component.ts b/codelab-master/apps/kirjs/src/app/modules/home/home.component.ts
new file mode 100644
index 000000000..45ec85e99
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/home/home.component.ts
@@ -0,0 +1,12 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-home',
+ templateUrl: './home.component.html',
+ styleUrls: ['./home.component.css']
+})
+export class HomeComponent implements OnInit {
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/home/home.module.spec.ts b/codelab-master/apps/kirjs/src/app/modules/home/home.module.spec.ts
new file mode 100644
index 000000000..0f1337bab
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/home/home.module.spec.ts
@@ -0,0 +1,13 @@
+import { HomeModule } from './home.module';
+
+describe('HomeModule', () => {
+ let homeModule: HomeModule;
+
+ beforeEach(() => {
+ homeModule = new HomeModule();
+ });
+
+ it('should create an instance', () => {
+ expect(homeModule).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/home/home.module.ts b/codelab-master/apps/kirjs/src/app/modules/home/home.module.ts
new file mode 100644
index 000000000..aac3251ec
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/home/home.module.ts
@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { HomeComponent } from './home.component';
+import { RouterModule } from '@angular/router';
+import { PolaroidComponent } from './polaroid/polaroid.component';
+
+@NgModule({
+ imports: [
+ CommonModule,
+ RouterModule.forChild([
+ {
+ path: '',
+ component: HomeComponent
+ }
+ ])
+ ],
+ declarations: [HomeComponent, PolaroidComponent],
+ entryComponents: [HomeComponent]
+})
+export class HomeModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/home/pics/binary.png b/codelab-master/apps/kirjs/src/app/modules/home/pics/binary.png
new file mode 100644
index 000000000..7954c9a42
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/home/pics/binary.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/home/pics/fb.png b/codelab-master/apps/kirjs/src/app/modules/home/pics/fb.png
new file mode 100644
index 000000000..37b64aa0b
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/home/pics/fb.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/home/pics/kirjs.jpg b/codelab-master/apps/kirjs/src/app/modules/home/pics/kirjs.jpg
new file mode 100644
index 000000000..c008d66d5
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/home/pics/kirjs.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/home/pics/lastfm.png b/codelab-master/apps/kirjs/src/app/modules/home/pics/lastfm.png
new file mode 100644
index 000000000..8f7285ced
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/home/pics/lastfm.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/home/polaroid/polaroid.component.css b/codelab-master/apps/kirjs/src/app/modules/home/polaroid/polaroid.component.css
new file mode 100644
index 000000000..371678bae
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/home/polaroid/polaroid.component.css
@@ -0,0 +1,22 @@
+::ng-deep .picture {
+ width: 200px;
+ height: 200px;
+ background-size: cover;
+ box-shadow: 0 0 10px #444 inset;
+ border-radius: 50%;
+}
+
+.frame-outer {
+ width: 240px;
+ height: 400px;
+ background: #fff;
+ padding: 20px;
+ box-sizing: border-box;
+}
+
+.text {
+ margin-top: 20px;
+ background: white;
+ padding: 20px;
+ font-size: 1.3vw;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/home/polaroid/polaroid.component.html b/codelab-master/apps/kirjs/src/app/modules/home/polaroid/polaroid.component.html
new file mode 100644
index 000000000..5a09b2335
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/home/polaroid/polaroid.component.html
@@ -0,0 +1,4 @@
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/home/polaroid/polaroid.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/home/polaroid/polaroid.component.spec.ts
new file mode 100644
index 000000000..217720ecc
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/home/polaroid/polaroid.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { PolaroidComponent } from './polaroid.component';
+
+describe('PolaroidComponent', () => {
+ let component: PolaroidComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [PolaroidComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(PolaroidComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/home/polaroid/polaroid.component.ts b/codelab-master/apps/kirjs/src/app/modules/home/polaroid/polaroid.component.ts
new file mode 100644
index 000000000..d9bea0d24
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/home/polaroid/polaroid.component.ts
@@ -0,0 +1,12 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-polaroid',
+ templateUrl: './polaroid.component.html',
+ styleUrls: ['./polaroid.component.css']
+})
+export class PolaroidComponent implements OnInit {
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/msk/msk.component.css b/codelab-master/apps/kirjs/src/app/modules/msk/msk.component.css
new file mode 100644
index 000000000..7583334b0
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/msk/msk.component.css
@@ -0,0 +1,23 @@
+.pic {
+ width: 100%;
+ height: 100%;
+
+ background-repeat: no-repeat;
+ background-size: contain;
+}
+
+.awesome {
+ background-image: url(./pics/awesome.png);
+}
+
+.default {
+ background-image: url(./pics/default.png);
+}
+
+.ivy {
+ background-image: url(./pics/ivy.png);
+}
+
+.differential-loading {
+ background-image: url(./pics/differential-loading.png);
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/msk/msk.component.html b/codelab-master/apps/kirjs/src/app/modules/msk/msk.component.html
new file mode 100644
index 000000000..ec5975c2f
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/msk/msk.component.html
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+
What's new in the Angular World
+ by @kirjs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
ng make-this-awesome
+
+
+
+
+
ng deploy
+
+ Now you can deploy your angular-cli app to multiple cloud providers using
+ ng deploy command
+
+
+
+ng add @angular/fire@next
+ng deploy
+
+
+
Now you can deploy
+
+ Firebase
+ Netlify
+ Azure
+ Github
+ And more...
+
+
+
+
Differential loading
+
+
+
✨ Juan's tip ✨
+ https://browserl.ist/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
cdk-experimental clipboard service + directive
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/msk/msk.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/msk/msk.component.spec.ts
new file mode 100644
index 000000000..ff1d7c939
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/msk/msk.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { MskComponent } from './msk.component';
+
+describe('MskComponent', () => {
+ let component: MskComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [MskComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(MskComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/msk/msk.component.ts b/codelab-master/apps/kirjs/src/app/modules/msk/msk.component.ts
new file mode 100644
index 000000000..ab9970171
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/msk/msk.component.ts
@@ -0,0 +1,109 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-msk',
+ templateUrl: './msk.component.html',
+ styleUrls: ['./msk.component.css']
+})
+export class MskComponent implements OnInit {
+ polls = [
+ {
+ key: 'favorite',
+ type: 'choice',
+ question: 'Which framework do you use most at work?',
+ options: [
+ 'Angular',
+ 'AngularJS',
+ 'React',
+ 'Vue',
+ 'Svelte',
+ 'jQuery',
+ 'Something else'
+ ]
+ },
+ {
+ key: 'skill',
+ type: 'choice',
+ question: 'How well do you know angular?',
+ options: [
+ 'Not at all',
+ 'Somewhat',
+ 'I can use it',
+ 'Good',
+ 'Really good',
+ "I'm Minko Fluin"
+ ]
+ },
+ {
+ key: 'build-dev',
+ type: 'choice',
+ question:
+ 'how long does it take to rebuild your app in dev mode (and see the result via local dev server) - the total turnaround time',
+ options: [
+ '< 1 second',
+ '1 - 5 seconds',
+ '5 - 10 seconds',
+ '10 - 30 seconds',
+ '30 - 60 seconds',
+ '1-10 minutes',
+ 'More than 10 minutes'
+ ]
+ },
+ {
+ key: 'build-prod',
+ type: 'choice',
+ question:
+ 'how long does it take to create a production build of your app',
+ options: [
+ '< 1 second',
+ '1 - 5 seconds',
+ '5 - 10 seconds',
+ '10 - 30 seconds',
+ '30 - 60 seconds',
+ '1-10 minutes',
+ 'More than 10 minutes'
+ ]
+ },
+ {
+ key: 'cli',
+ type: 'choice',
+ question: 'Which feature is NOT in CLI 8.3.0-next.2 ',
+ answer: 'New command ng make-this-awesome',
+ options: [
+ 'Redesigned default app',
+ 'New command ng make-this-awesome',
+ 'Faster builds with enabled differential loading',
+ 'New command ng deploy'
+ ]
+ },
+ {
+ key: 'tomorrow',
+ type: 'choice',
+ question: 'What is being released today?',
+ answer: 'CLI 9.0.0-next.0 with Ivy by default',
+ options: [
+ 'CLI 9.0.0-next.0 with Ivy by default',
+ 'RxJS 8',
+ 'React 16.12',
+ 'Angular XS'
+ ]
+ },
+ {
+ key: 'material',
+ type: 'choice',
+ question:
+ 'Which feature was added to Angular CDK library 8.1.3 "gelatin-key" (2019-08-14)?',
+ answer: '',
+ options: [
+ 'Windows 95 theme support',
+ 'Drag and drop',
+ 'New material-fox component',
+ 'New Clipboard service + directive'
+ ]
+ }
+ ];
+
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/msk/msk.module.ts b/codelab-master/apps/kirjs/src/app/modules/msk/msk.module.ts
new file mode 100644
index 000000000..8af8593c6
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/msk/msk.module.ts
@@ -0,0 +1,45 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { AngularFireDatabaseModule } from '@angular/fire/database';
+import { RouterModule } from '@angular/router';
+import { SlidesModule, SlidesRoutes } from '@ng360/slides';
+import { SyncDataService } from '@codelab/utils/src/lib/sync/services/sync-data.service';
+import { SyncSessionService } from '@codelab/utils/src/lib/sync/services/sync-session.service';
+import { SyncDbService } from '@codelab/utils/src/lib/sync/services/sync-db.service';
+import { SyncPollService } from '@codelab/utils/src/lib/sync/components/poll/common/sync-poll.service';
+import { SyncRegistrationService } from '@codelab/utils/src/lib/sync/components/registration/sync-registration.service';
+import { SyncButtonModule } from '@codelab/utils/src/lib/sync/sync-button/sync-button.module';
+import { QuestionsModule } from '@codelab/utils/src/lib/sync/components/questions/questions.module';
+import { SyncModule } from '@codelab/utils/src/lib/sync/sync.module';
+import { AngularFireAuthModule } from '@angular/fire/auth';
+import { SyncDirectivesModule } from '@codelab/utils/src/lib/sync/directives/sync-directives.module';
+import { SyncRegistrationModule } from '@codelab/utils/src/lib/sync/components/registration/sync-registration.module';
+import { SyncPollModule } from '@codelab/utils/src/lib/sync/components/poll/sync-poll.module';
+import { MskComponent } from './msk.component';
+
+const routes = RouterModule.forChild(SlidesRoutes.get(MskComponent));
+
+@NgModule({
+ providers: [
+ SyncDataService,
+ SyncSessionService,
+ SyncDbService,
+ SyncPollService,
+ SyncRegistrationService
+ ],
+ declarations: [MskComponent],
+ imports: [
+ CommonModule,
+ SlidesModule,
+ routes,
+ QuestionsModule,
+ SyncModule,
+ AngularFireAuthModule,
+ AngularFireDatabaseModule,
+ SyncButtonModule,
+ SyncDirectivesModule,
+ SyncRegistrationModule,
+ SyncPollModule
+ ]
+})
+export class MskModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/msk/pics/awesome.png b/codelab-master/apps/kirjs/src/app/modules/msk/pics/awesome.png
new file mode 100644
index 000000000..6b99a428e
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/msk/pics/awesome.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/msk/pics/default.png b/codelab-master/apps/kirjs/src/app/modules/msk/pics/default.png
new file mode 100644
index 000000000..879d33286
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/msk/pics/default.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/msk/pics/differential-loading.png b/codelab-master/apps/kirjs/src/app/modules/msk/pics/differential-loading.png
new file mode 100644
index 000000000..897816f6b
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/msk/pics/differential-loading.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/msk/pics/ivy-router-component.jpeg b/codelab-master/apps/kirjs/src/app/modules/msk/pics/ivy-router-component.jpeg
new file mode 100644
index 000000000..9307cb737
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/msk/pics/ivy-router-component.jpeg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/msk/pics/ivy.png b/codelab-master/apps/kirjs/src/app/modules/msk/pics/ivy.png
new file mode 100644
index 000000000..58be22891
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/msk/pics/ivy.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/music/music.component.css b/codelab-master/apps/kirjs/src/app/modules/music/music.component.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/codelab-master/apps/kirjs/src/app/modules/music/music.component.html b/codelab-master/apps/kirjs/src/app/modules/music/music.component.html
new file mode 100644
index 000000000..67fc81f04
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/music/music.component.html
@@ -0,0 +1 @@
+music works!
diff --git a/codelab-master/apps/kirjs/src/app/modules/music/music.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/music/music.component.spec.ts
new file mode 100644
index 000000000..e458615d1
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/music/music.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { MusicComponent } from './music.component';
+
+describe('MusicComponent', () => {
+ let component: MusicComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [MusicComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(MusicComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/music/music.component.ts b/codelab-master/apps/kirjs/src/app/modules/music/music.component.ts
new file mode 100644
index 000000000..25ce8cc4e
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/music/music.component.ts
@@ -0,0 +1,12 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-music',
+ templateUrl: './music.component.html',
+ styleUrls: ['./music.component.css']
+})
+export class MusicComponent implements OnInit {
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/music/music.module.ts b/codelab-master/apps/kirjs/src/app/modules/music/music.module.ts
new file mode 100644
index 000000000..ce773594e
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/music/music.module.ts
@@ -0,0 +1,9 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { MusicComponent } from './music.component';
+
+@NgModule({
+ imports: [CommonModule],
+ declarations: [MusicComponent]
+})
+export class MusicModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/qna/qna.component.css b/codelab-master/apps/kirjs/src/app/modules/qna/qna.component.css
new file mode 100644
index 000000000..27e2cc5f7
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/qna/qna.component.css
@@ -0,0 +1,5 @@
+:host ::ng-deep {
+ display: block;
+ padding: 40px;
+ position: relative;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/qna/qna.component.html b/codelab-master/apps/kirjs/src/app/modules/qna/qna.component.html
new file mode 100644
index 000000000..a4cdbfa0b
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/qna/qna.component.html
@@ -0,0 +1,3 @@
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/qna/qna.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/qna/qna.component.spec.ts
new file mode 100644
index 000000000..3b7569c9b
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/qna/qna.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { QnaComponent } from './qna.component';
+
+describe('QnaComponent', () => {
+ let component: QnaComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [QnaComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(QnaComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/qna/qna.component.ts b/codelab-master/apps/kirjs/src/app/modules/qna/qna.component.ts
new file mode 100644
index 000000000..39f66b315
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/qna/qna.component.ts
@@ -0,0 +1,12 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-qna',
+ templateUrl: './qna.component.html',
+ styleUrls: ['./qna.component.css']
+})
+export class QnaComponent implements OnInit {
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/qna/qna.module.ts b/codelab-master/apps/kirjs/src/app/modules/qna/qna.module.ts
new file mode 100644
index 000000000..1010a5183
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/qna/qna.module.ts
@@ -0,0 +1,43 @@
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { CommonModule } from '@angular/common';
+import { AngularFireAuthModule } from '@angular/fire/auth';
+import { AngularFireDatabaseModule } from '@angular/fire/database';
+import { SlidesModule } from '@ng360/slides';
+import { QuestionsModule } from '@codelab/utils/src/lib/sync/components/questions/questions.module';
+import { SyncModule } from '@codelab/utils/src/lib/sync/sync.module';
+import { SyncDataService } from '@codelab/utils/src/lib/sync/services/sync-data.service';
+import { SyncRegistrationService } from '@codelab/utils/src/lib/sync/components/registration/sync-registration.service';
+import { SyncSessionService } from '@codelab/utils/src/lib/sync/services/sync-session.service';
+import { SyncDbService } from '@codelab/utils/src/lib/sync/services/sync-db.service';
+import { SyncPollService } from '@codelab/utils/src/lib/sync/components/poll/common/sync-poll.service';
+import { SyncButtonModule } from '@codelab/utils/src/lib/sync/sync-button/sync-button.module';
+import { SyncDirectivesModule } from '@codelab/utils/src/lib/sync/directives/sync-directives.module';
+import { SyncRegistrationModule } from '@codelab/utils/src/lib/sync/components/registration/sync-registration.module';
+import { QnaComponent } from './qna.component';
+
+const routes = RouterModule.forChild([{ path: '', component: QnaComponent }]);
+
+@NgModule({
+ declarations: [QnaComponent],
+ providers: [
+ SyncDataService,
+ SyncSessionService,
+ SyncDbService,
+ SyncPollService,
+ SyncRegistrationService
+ ],
+ imports: [
+ CommonModule,
+ SlidesModule,
+ routes,
+ QuestionsModule,
+ SyncModule,
+ AngularFireAuthModule,
+ AngularFireDatabaseModule,
+ SyncButtonModule,
+ SyncDirectivesModule,
+ SyncRegistrationModule
+ ]
+})
+export class QnaModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/regex/live/index.ts b/codelab-master/apps/kirjs/src/app/modules/regex/live/index.ts
new file mode 100644
index 000000000..28971d890
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/regex/live/index.ts
@@ -0,0 +1 @@
+export * from './live.module';
diff --git a/codelab-master/apps/kirjs/src/app/modules/regex/live/live-mock/index.ts b/codelab-master/apps/kirjs/src/app/modules/regex/live/live-mock/index.ts
new file mode 100644
index 000000000..61fa8274b
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/regex/live/live-mock/index.ts
@@ -0,0 +1 @@
+export * from './live-mock.module';
diff --git a/codelab-master/apps/kirjs/src/app/modules/regex/live/live-mock/live-mock.component.css b/codelab-master/apps/kirjs/src/app/modules/regex/live/live-mock/live-mock.component.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/codelab-master/apps/kirjs/src/app/modules/regex/live/live-mock/live-mock.component.html b/codelab-master/apps/kirjs/src/app/modules/regex/live/live-mock/live-mock.component.html
new file mode 100644
index 000000000..4b0be7ab7
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/regex/live/live-mock/live-mock.component.html
@@ -0,0 +1,10 @@
+
+
+ Presenter
+ Viewer
+
+
+
+
+ {{ data | json }}
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/regex/live/live-mock/live-mock.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/regex/live/live-mock/live-mock.component.spec.ts
new file mode 100644
index 000000000..a509a94f1
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/regex/live/live-mock/live-mock.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { LiveMockComponent } from './live-mock.component';
+
+describe('LiveMockComponent', () => {
+ let component: LiveMockComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [LiveMockComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(LiveMockComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/regex/live/live-mock/live-mock.component.ts b/codelab-master/apps/kirjs/src/app/modules/regex/live/live-mock/live-mock.component.ts
new file mode 100644
index 000000000..10c89ee47
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/regex/live/live-mock/live-mock.component.ts
@@ -0,0 +1,39 @@
+import { Component, OnDestroy, OnInit } from '@angular/core';
+import { LiveService, LiveInfo } from '../live.service';
+import { Subject } from 'rxjs';
+import { takeUntil } from 'rxjs/operators';
+import { FormBuilder, FormGroup } from '@angular/forms';
+
+@Component({
+ selector: 'kirjs-live-mock-component',
+ templateUrl: './live-mock.component.html',
+ styleUrls: ['./live-mock.component.css']
+})
+export class LiveMockComponent implements OnInit, OnDestroy {
+ data: LiveInfo;
+
+ form: FormGroup = this.fb.group({
+ user: this.fb.control(''),
+ status: this.fb.control('')
+ });
+
+ private onDestroy: Subject = new Subject();
+
+ constructor(private service: LiveService, private fb: FormBuilder) {}
+
+ ngOnInit() {
+ this.form.valueChanges.subscribe(data => {
+ this.service.storeLiveInfo(data);
+ });
+
+ this.service.liveInfo.pipe(takeUntil(this.onDestroy)).subscribe(data => {
+ this.data = data;
+ this.form.patchValue(data, { emitEvent: false });
+ });
+ }
+
+ ngOnDestroy(): void {
+ this.onDestroy.next(null);
+ this.onDestroy.complete();
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/regex/live/live-mock/live-mock.module.ts b/codelab-master/apps/kirjs/src/app/modules/regex/live/live-mock/live-mock.module.ts
new file mode 100644
index 000000000..37a0399f6
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/regex/live/live-mock/live-mock.module.ts
@@ -0,0 +1,11 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { LiveMockComponent } from './live-mock.component';
+
+@NgModule({
+ imports: [CommonModule, ReactiveFormsModule],
+ declarations: [LiveMockComponent],
+ exports: [LiveMockComponent]
+})
+export class LiveMockModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/regex/live/live.module.ts b/codelab-master/apps/kirjs/src/app/modules/regex/live/live.module.ts
new file mode 100644
index 000000000..982a4abf0
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/regex/live/live.module.ts
@@ -0,0 +1,9 @@
+import { NgModule } from '@angular/core';
+
+import { LiveMockModule } from './live-mock';
+import { PollModule } from './poll';
+
+@NgModule({
+ exports: [LiveMockModule, PollModule]
+})
+export class LiveModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/regex/live/live.service.spec.ts b/codelab-master/apps/kirjs/src/app/modules/regex/live/live.service.spec.ts
new file mode 100644
index 000000000..2f952aeca
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/regex/live/live.service.spec.ts
@@ -0,0 +1,12 @@
+import { TestBed } from '@angular/core/testing';
+
+import { LiveService } from './live.service';
+
+describe('LiveService', () => {
+ beforeEach(() => TestBed.configureTestingModule({}));
+
+ it('should be created', () => {
+ const service: LiveService = TestBed.inject(LiveService);
+ expect(service).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/regex/live/live.service.ts b/codelab-master/apps/kirjs/src/app/modules/regex/live/live.service.ts
new file mode 100644
index 000000000..6666b023c
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/regex/live/live.service.ts
@@ -0,0 +1,72 @@
+import { Injectable, OnDestroy } from '@angular/core';
+import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
+import { map } from 'rxjs/operators';
+
+export interface LiveInfo {
+ // Login service
+ user: string;
+ // Global
+ sessionId: string;
+
+ //
+ status: 'presenter' | 'viewer'; // in the future 'admin';
+ // e.g. regex
+ presentationId: string;
+ // slide id
+ slide: string;
+}
+
+type AllData = Record;
+
+@Injectable({
+ providedIn: 'root'
+})
+export class LiveService implements OnDestroy {
+ private liveInfoSubject: BehaviorSubject = new BehaviorSubject<
+ LiveInfo
+ >({
+ user: 'code',
+ sessionId: 'test',
+ status: 'presenter', // 'viewer'
+ presentationId: 'regex',
+ slide: 'config'
+ } as LiveInfo);
+ liveInfo: Observable = this.liveInfoSubject.asObservable();
+ private allDataSubject: BehaviorSubject> = new BehaviorSubject<
+ AllData
+ >({} as AllData);
+ allData = this.allDataSubject.asObservable();
+ myData = combineLatest([this.allData, this.liveInfo]).pipe(
+ map(([allData, { user }]) => {
+ return allData[user];
+ })
+ );
+
+ constructor() {}
+
+ storeLiveInfo(data: LiveInfo): void {
+ const liveInfo = this.liveInfoSubject.getValue();
+ this.liveInfoSubject.next({ ...liveInfo, ...data });
+ }
+
+ // Viewer
+ storeMyData(data: T): void {
+ // firebase.store
+ const liveInfo = this.liveInfoSubject.getValue();
+ const allData = this.allDataSubject.getValue();
+ const value = { ...allData, [liveInfo.user]: data };
+
+ this.allDataSubject.next(value);
+ }
+
+ ngOnDestroy() {
+ if (this.allDataSubject) {
+ this.allDataSubject.complete();
+ this.allDataSubject = null;
+ }
+ if (this.liveInfoSubject) {
+ this.liveInfoSubject.complete();
+ this.liveInfoSubject = null;
+ }
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/regex/live/poll/index.ts b/codelab-master/apps/kirjs/src/app/modules/regex/live/poll/index.ts
new file mode 100644
index 000000000..b4d735a13
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/regex/live/poll/index.ts
@@ -0,0 +1 @@
+export * from './poll.module';
diff --git a/codelab-master/apps/kirjs/src/app/modules/regex/live/poll/poll.component.css b/codelab-master/apps/kirjs/src/app/modules/regex/live/poll/poll.component.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/codelab-master/apps/kirjs/src/app/modules/regex/live/poll/poll.component.html b/codelab-master/apps/kirjs/src/app/modules/regex/live/poll/poll.component.html
new file mode 100644
index 000000000..917934dc3
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/regex/live/poll/poll.component.html
@@ -0,0 +1,56 @@
+
+
+
+ 2
+
+
+
+
+ {{ service.allData | async | json }} 3
+
+
+
+
+ Results are here!!!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ // results myDAta
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/regex/live/poll/poll.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/regex/live/poll/poll.component.spec.ts
new file mode 100644
index 000000000..4d69b65fe
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/regex/live/poll/poll.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { PollComponent } from './poll.component';
+
+describe('SyncPollComponent', () => {
+ let component: PollComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [PollComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(PollComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/regex/live/poll/poll.component.ts b/codelab-master/apps/kirjs/src/app/modules/regex/live/poll/poll.component.ts
new file mode 100644
index 000000000..3d89d1b8d
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/regex/live/poll/poll.component.ts
@@ -0,0 +1,26 @@
+import { Component, Injectable, Input, OnInit } from '@angular/core';
+import { LiveService } from '../live.service';
+
+@Component({
+ selector: 'kirjs-poll',
+ templateUrl: './poll.component.html',
+ styleUrls: ['./poll.component.css']
+})
+export class PollComponent {
+ @Input() question: string;
+ constructor(readonly service: LiveService) {}
+}
+
+@Component({
+ selector: 'kirjs-poll-answer',
+ template: `
+
+ `,
+ styleUrls: ['./poll.component.css']
+})
+export class SlidesAnswerComponent implements OnInit {
+ @Input() value: string;
+ constructor(readonly service: LiveService) {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/regex/live/poll/poll.module.ts b/codelab-master/apps/kirjs/src/app/modules/regex/live/poll/poll.module.ts
new file mode 100644
index 000000000..236aa7acd
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/regex/live/poll/poll.module.ts
@@ -0,0 +1,10 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { PollComponent, SlidesAnswerComponent } from './poll.component';
+
+@NgModule({
+ declarations: [PollComponent, SlidesAnswerComponent],
+ exports: [PollComponent, SlidesAnswerComponent],
+ imports: [CommonModule]
+})
+export class PollModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/regex/regex.component.css b/codelab-master/apps/kirjs/src/app/modules/regex/regex.component.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/codelab-master/apps/kirjs/src/app/modules/regex/regex.component.html b/codelab-master/apps/kirjs/src/app/modules/regex/regex.component.html
new file mode 100644
index 000000000..fd7ac3e3d
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/regex/regex.component.html
@@ -0,0 +1,19 @@
+
+
Hello
+
+
+
+
+
+
+
+ Yes
+ No
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/regex/regex.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/regex/regex.component.spec.ts
new file mode 100644
index 000000000..2ab4b8607
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/regex/regex.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { RegexComponent } from './regex.component';
+
+describe('RegexComponent', () => {
+ let component: RegexComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [RegexComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(RegexComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/regex/regex.component.ts b/codelab-master/apps/kirjs/src/app/modules/regex/regex.component.ts
new file mode 100644
index 000000000..67ad46e82
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/regex/regex.component.ts
@@ -0,0 +1,12 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-regex',
+ templateUrl: './regex.component.html',
+ styleUrls: ['./regex.component.css']
+})
+export class RegexComponent implements OnInit {
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/regex/regex.module.ts b/codelab-master/apps/kirjs/src/app/modules/regex/regex.module.ts
new file mode 100644
index 000000000..191a3f441
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/regex/regex.module.ts
@@ -0,0 +1,14 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { RouterModule } from '@angular/router';
+import { SlidesModule, SlidesRoutes } from '@ng360/slides';
+import { RegexComponent } from './regex.component';
+import { LiveModule } from './live';
+
+const routes = RouterModule.forChild(SlidesRoutes.get(RegexComponent));
+
+@NgModule({
+ declarations: [RegexComponent],
+ imports: [routes, CommonModule, SlidesModule, LiveModule]
+})
+export class RegexModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/simple-stack/simple-stack.component.css b/codelab-master/apps/kirjs/src/app/modules/stack/simple-stack/simple-stack.component.css
new file mode 100644
index 000000000..6990c5cdd
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/simple-stack/simple-stack.component.css
@@ -0,0 +1,22 @@
+:host {
+ white-space: nowrap;
+ border: 3px #666 dotted;
+ border-top-left-radius: 5px;
+ border-bottom-left-radius: 5px;
+ border-right: 0;
+ padding-left: 10px;
+ padding-right: 40px;
+ height: 46px;
+ position: relative;
+}
+
+:host:after {
+ content: '';
+ position: absolute;
+ left: 0;
+ top: 0;
+ height: 46px;
+ right: 80px;
+ background: white;
+ opacity: 0.7;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/simple-stack/simple-stack.component.html b/codelab-master/apps/kirjs/src/app/modules/stack/simple-stack/simple-stack.component.html
new file mode 100644
index 000000000..40cf72a23
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/simple-stack/simple-stack.component.html
@@ -0,0 +1 @@
+{{ value }}
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/simple-stack/simple-stack.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/stack/simple-stack/simple-stack.component.spec.ts
new file mode 100644
index 000000000..25f1f5cc0
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/simple-stack/simple-stack.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SimpleStackComponent } from './simple-stack.component';
+
+describe('SimpleStackComponent', () => {
+ let component: SimpleStackComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [SimpleStackComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(SimpleStackComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/simple-stack/simple-stack.component.ts b/codelab-master/apps/kirjs/src/app/modules/stack/simple-stack/simple-stack.component.ts
new file mode 100644
index 000000000..ff3e30b9f
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/simple-stack/simple-stack.component.ts
@@ -0,0 +1,14 @@
+import { Component, Input, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'slides-simple-stack',
+ templateUrl: './simple-stack.component.html',
+ styleUrls: ['./simple-stack.component.css']
+})
+export class SimpleStackComponent implements OnInit {
+ @Input() value: string;
+
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-function-button/stack-function-button.component.css b/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-function-button/stack-function-button.component.css
new file mode 100644
index 000000000..7b85afe42
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-function-button/stack-function-button.component.css
@@ -0,0 +1,13 @@
+button {
+ font-size: inherit;
+ cursor: pointer;
+ background: #ffffff;
+ border: 1px #ddd solid;
+ border-radius: 10px;
+ padding: 10px;
+ margin: 0 10px;
+}
+
+button:hover {
+ background: #eee;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-function-button/stack-function-button.component.html b/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-function-button/stack-function-button.component.html
new file mode 100644
index 000000000..00fb66d2c
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-function-button/stack-function-button.component.html
@@ -0,0 +1,6 @@
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-function-button/stack-function-button.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-function-button/stack-function-button.component.spec.ts
new file mode 100644
index 000000000..a36c11bd3
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-function-button/stack-function-button.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { StackFunctionButtonComponent } from './stack-function-button.component';
+
+describe('StackFunctionButtonComponent', () => {
+ let component: StackFunctionButtonComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [StackFunctionButtonComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(StackFunctionButtonComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-function-button/stack-function-button.component.ts b/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-function-button/stack-function-button.component.ts
new file mode 100644
index 000000000..9b1c953a7
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-function-button/stack-function-button.component.ts
@@ -0,0 +1,13 @@
+import { Component, HostBinding, Input, OnInit } from '@angular/core';
+import { StackFunction } from '../stack-game.component';
+
+@Component({
+ // tslint:disable-next-line:component-selector
+ selector: 'slides-stack-function-button',
+ templateUrl: './stack-function-button.component.html',
+ styleUrls: ['./stack-function-button.component.css']
+})
+export class StackFunctionButtonComponent {
+ @Input() func: StackFunction;
+ @Input() disabled = false;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-function/stack-function.component.css b/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-function/stack-function.component.css
new file mode 100644
index 000000000..679e795a8
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-function/stack-function.component.css
@@ -0,0 +1,21 @@
+:host {
+ white-space: nowrap;
+}
+.grid {
+ display: grid;
+ grid-template-columns: 1fr 80px 1fr;
+}
+
+.arrow {
+ text-align: center;
+}
+
+:host.disabled {
+ opacity: 0.4;
+ background: #eee;
+}
+
+.inputs {
+ justify-self: end;
+ white-space: nowrap;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-function/stack-function.component.html b/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-function/stack-function.component.html
new file mode 100644
index 000000000..d3b742b36
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-function/stack-function.component.html
@@ -0,0 +1,8 @@
+
+ {{ func.name }}
+
+
+ ({{ func.inputs }})
+ =>
+ {{ func.outputs }}
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-function/stack-function.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-function/stack-function.component.spec.ts
new file mode 100644
index 000000000..2f72415e9
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-function/stack-function.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { StackFunctionComponent } from './stack-function.component';
+
+describe('StackFunctionComponent', () => {
+ let component: StackFunctionComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [StackFunctionComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(StackFunctionComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-function/stack-function.component.ts b/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-function/stack-function.component.ts
new file mode 100644
index 000000000..cd07210f2
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-function/stack-function.component.ts
@@ -0,0 +1,18 @@
+import { Component, HostBinding, Input, OnInit } from '@angular/core';
+import { StackFunction } from '../stack-game.component';
+
+@Component({
+ selector: 'slides-stack-function',
+ templateUrl: './stack-function.component.html',
+ styleUrls: ['./stack-function.component.css']
+})
+export class StackFunctionComponent implements OnInit {
+ @Input() func: StackFunction;
+
+ @HostBinding('class.disabled')
+ @Input()
+ disabled = false;
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-game.component.css b/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-game.component.css
new file mode 100644
index 000000000..f57703502
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-game.component.css
@@ -0,0 +1,44 @@
+.buttons {
+ margin: 20px 0 40px;
+ text-align: center;
+}
+
+.complete {
+ text-align: center;
+}
+
+.stack {
+ margin-left: 30px;
+}
+
+.item {
+ white-space: nowrap;
+ margin-bottom: 10px;
+ height: 55px;
+ display: block;
+ line-height: 55px;
+}
+
+.initial {
+ color: #666;
+ text-align: right;
+}
+
+.function-usage {
+ text-align: right;
+}
+
+.history {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+}
+
+.next {
+ background: #dddddd;
+ text-align: center;
+ border-radius: 5px;
+}
+
+.remove-button {
+ margin-right: 10px;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-game.component.html b/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-game.component.html
new file mode 100644
index 000000000..b48471183
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-game.component.html
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+ ✨💖 Success! ✨💖
+
+
+
+
+
Initial stack:
+
+ ⓧ
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-game.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-game.component.spec.ts
new file mode 100644
index 000000000..a571cdb08
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-game.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { StackGameComponent } from './stack-game.component';
+
+describe('StackGameComponent', () => {
+ let component: StackGameComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [StackGameComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(StackGameComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-game.component.ts b/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-game.component.ts
new file mode 100644
index 000000000..8c402968f
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/stack-game/stack-game.component.ts
@@ -0,0 +1,89 @@
+import { Component, Input, OnInit } from '@angular/core';
+
+export interface StackFunction {
+ inputs: string;
+ outputs: string;
+ name?: string;
+}
+
+export interface Level {
+ functions: StackFunction[];
+ inputs: string;
+ outputs: string;
+}
+
+const ANY_CHAR = '*';
+
+@Component({
+ selector: 'slides-stack-game',
+ templateUrl: './stack-game.component.html',
+ styleUrls: ['./stack-game.component.css']
+})
+export class StackGameComponent implements OnInit {
+ isComplete = false;
+
+ @Input() level: Level = {
+ functions: [
+ {
+ inputs: '',
+ outputs: '🍏',
+ name: 'push 🍏'
+ },
+ {
+ inputs: '🍏🍏',
+ outputs: '🍋'
+ },
+ {
+ inputs: '🍋🍋',
+ outputs: '🍒'
+ },
+ {
+ inputs: '*',
+ outputs: '',
+ name: 'pop'
+ }
+ ],
+ inputs: '🍏',
+ outputs: '🍒'
+ };
+
+ functions = [];
+ stack = '';
+ history: string[];
+
+ canAddFunction(stack: string, func) {
+ return stack.match(new RegExp(func.inputs.replace(ANY_CHAR, '.') + '$'));
+ }
+
+ calcStack() {
+ let stack = this.level.inputs.replace(ANY_CHAR, '🍏');
+ const history = [];
+ for (const func of this.functions) {
+ stack =
+ stack.slice(
+ 0,
+ stack.length - func.inputs.replace(ANY_CHAR, '🍏').length
+ ) + func.outputs;
+ history.push(stack);
+ }
+ this.history = history;
+ this.stack = stack;
+ if (this.stack === this.level.outputs) {
+ this.isComplete = true;
+ }
+ }
+
+ addFunction(func: StackFunction) {
+ this.functions.push(func);
+ this.calcStack();
+ }
+
+ removeFunction() {
+ this.functions.pop();
+ this.calcStack();
+ }
+
+ ngOnInit() {
+ this.stack = this.level.inputs;
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/stack-routing.module.ts b/codelab-master/apps/kirjs/src/app/modules/stack/stack-routing.module.ts
new file mode 100644
index 000000000..6b14807f4
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/stack-routing.module.ts
@@ -0,0 +1,12 @@
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { SlidesRoutes } from '@ng360/slides';
+import { StackComponent } from './stack.component';
+import { StackModule } from './stack.module';
+
+const routes = RouterModule.forChild(SlidesRoutes.get(StackComponent));
+
+@NgModule({
+ imports: [StackModule, routes]
+})
+export class StackRoutingModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/stack-test/assets/sb-icon.svg b/codelab-master/apps/kirjs/src/app/modules/stack/stack-test/assets/sb-icon.svg
new file mode 100644
index 000000000..8e5ab049f
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/stack-test/assets/sb-icon.svg
@@ -0,0 +1 @@
+ Path Created with Sketch.
\ No newline at end of file
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/stack-test/assets/so-icon.svg b/codelab-master/apps/kirjs/src/app/modules/stack/stack-test/assets/so-icon.svg
new file mode 100644
index 000000000..5298d4c2c
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/stack-test/assets/so-icon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/stack-test/stack-test.component.html b/codelab-master/apps/kirjs/src/app/modules/stack/stack-test/stack-test.component.html
new file mode 100644
index 000000000..8bdd4f124
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/stack-test/stack-test.component.html
@@ -0,0 +1,20 @@
+
+ Test time! those two companies have "stack" in their name, but only one of
+ them actually has stack as their logo. which one?
+
+
+
+
+ StackOverflow.com
+
+
+
+
+ StackBlitz.com
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/stack-test/stack-test.component.scss b/codelab-master/apps/kirjs/src/app/modules/stack/stack-test/stack-test.component.scss
new file mode 100644
index 000000000..2992f78d4
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/stack-test/stack-test.component.scss
@@ -0,0 +1,38 @@
+.wrapper {
+ display: flex;
+
+ .company {
+ text-align: center;
+ flex: 1;
+
+ .name {
+ font-size: 40px;
+ font-weight: 300;
+ margin: 20px 0;
+ }
+
+ .logo {
+ height: 150px;
+
+ > div {
+ background-size: cover;
+ margin: 20px auto;
+ }
+ .sb {
+ width: 80px;
+ height: 120px;
+ background-image: url('./assets/sb-icon.svg');
+ }
+
+ .so {
+ width: 150px;
+ height: 150px;
+ background-image: url('./assets/so-icon.svg');
+ }
+ }
+ }
+
+ .gap {
+ flex: 0.2;
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/stack-test/stack-test.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/stack/stack-test/stack-test.component.spec.ts
new file mode 100644
index 000000000..3a351a98f
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/stack-test/stack-test.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { StackTestComponent } from './stack-test.component';
+
+describe('StackTestComponent', () => {
+ let component: StackTestComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [StackTestComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(StackTestComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/stack-test/stack-test.component.ts b/codelab-master/apps/kirjs/src/app/modules/stack/stack-test/stack-test.component.ts
new file mode 100644
index 000000000..d63f53ae8
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/stack-test/stack-test.component.ts
@@ -0,0 +1,13 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ // tslint:disable-next-line:component-selector
+ selector: 'slides-stack-test',
+ templateUrl: './stack-test.component.html',
+ styleUrls: ['./stack-test.component.scss']
+})
+export class StackTestComponent implements OnInit {
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/stack.component.css b/codelab-master/apps/kirjs/src/app/modules/stack/stack.component.css
new file mode 100644
index 000000000..911cf9f45
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/stack.component.css
@@ -0,0 +1,15 @@
+:host ::ng-deep .slide.slide > div {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 40px;
+ padding: 0 20vw;
+}
+
+::ng-deep {
+ font-weight: 300;
+}
+
+.button-wrapper {
+ margin: 20px 0;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/stack.component.html b/codelab-master/apps/kirjs/src/app/modules/stack/stack.component.html
new file mode 100644
index 000000000..31b02723c
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/stack.component.html
@@ -0,0 +1,94 @@
+
+
+
+ Stack is a data structure, serving as a collection. Here's a stack
+ of fruit:
+
+
+
+
+
All operations are possible only with the last element of the stack.
+
+
+
+
First operation is called pop , it removes the last element.
+
+
+
+
+
+ The other operation is push . It adds an element on top of the
+ stack.
+
+
+
+
+
+
+ Some implementations also have a peek operation. It tells you what
+ top element on the stack is. You can try it below:
+
+
+
+
+
+
Congrats! It is a 🍋
+
+
+
+
Let's practice!
+
+ Use the commands you know already to get a stack of:
+
+
+
+
+
+
+
+
+
+
+
Congrats! Now you are a stack expert!
+
+ But why are stacks important? And how can I use them in a language like
+ asm
+
+
+
+
+
Let's learn stack machine.
+
+ This is one of the fundamental principles used in JVM Java Byte Code,
+ WebAssembly byte code
+
+
+
+
+
+ Stack machine offers various intructions that can pop and then push
+ multiple element on the stack
+
+
+ For example (🌲🍏)=>🍍 takes two elements from the stack (Pine and Apple)
+ and pushes a 🍍 back
+
+
+
+
+
Now use the instructions below to prepare a lemonade drink:
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/stack.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/stack/stack.component.spec.ts
new file mode 100644
index 000000000..b250ad7f9
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/stack.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { StackComponent } from './stack.component';
+
+describe('StackComponent', () => {
+ let component: StackComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [StackComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(StackComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/stack.component.ts b/codelab-master/apps/kirjs/src/app/modules/stack/stack.component.ts
new file mode 100644
index 000000000..be96a0412
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/stack.component.ts
@@ -0,0 +1,138 @@
+import { Component, OnInit } from '@angular/core';
+import { Level } from './stack-game/stack-game.component';
+
+@Component({
+ selector: 'kirjs-stack',
+ templateUrl: './stack.component.html',
+ styleUrls: ['./stack.component.css']
+})
+export class StackComponent implements OnInit {
+ itIsALemon = false;
+
+ levels: Record = {
+ push: {
+ functions: [
+ {
+ inputs: '',
+ outputs: '🍏',
+ name: 'push 🍏'
+ },
+ {
+ inputs: '',
+ outputs: '🍋',
+ name: 'push 🍋'
+ }
+ ],
+ inputs: '',
+ outputs: '🍏🍋🍏'
+ },
+
+ pop: {
+ functions: [
+ {
+ inputs: '*',
+ outputs: '',
+ name: 'pop'
+ }
+ ],
+ inputs: '🍏🍏🍏🍏🍏',
+ outputs: '🍏'
+ },
+
+ together: {
+ functions: [
+ {
+ inputs: '*',
+ outputs: '',
+ name: 'pop'
+ },
+ {
+ inputs: '',
+ outputs: '🍓',
+ name: 'push 🍓'
+ },
+ {
+ inputs: '',
+ outputs: '🍋',
+ name: 'push 🍋'
+ }
+ ],
+ inputs: '🍏🍏',
+ outputs: '🍓🍋'
+ },
+
+ lemonade: {
+ functions: [
+ {
+ inputs: '',
+ outputs: '💦'
+ },
+ {
+ inputs: '',
+ outputs: '🍋'
+ },
+ {
+ inputs: '',
+ outputs: '🍒'
+ },
+ {
+ inputs: '🍒💦🍋',
+ outputs: '🍹'
+ }
+ ],
+ inputs: '',
+ outputs: '🍹'
+ },
+ level1: {
+ functions: [
+ {
+ inputs: '',
+ outputs: '🍏🍏'
+ },
+ {
+ inputs: '',
+ outputs: '🍋'
+ },
+ {
+ inputs: '🍋🍋',
+ outputs: '🍒'
+ },
+ {
+ inputs: '*',
+ outputs: '',
+ name: 'pop'
+ }
+ ],
+ inputs: '🍏',
+ outputs: '🍒'
+ },
+ level2: {
+ functions: [
+ {
+ inputs: '',
+ outputs: '🍏',
+ name: 'push 🍏'
+ },
+ {
+ inputs: '🍏🍏',
+ outputs: '🍋'
+ },
+ {
+ inputs: '🍋🍋',
+ outputs: '🍒'
+ },
+ {
+ inputs: '*',
+ outputs: '',
+ name: 'pop'
+ }
+ ],
+ inputs: '🍏',
+ outputs: '🍒'
+ }
+ };
+
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/stack/stack.module.ts b/codelab-master/apps/kirjs/src/app/modules/stack/stack.module.ts
new file mode 100644
index 000000000..3a50c7bd0
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/stack/stack.module.ts
@@ -0,0 +1,31 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { SlidesModule } from '@ng360/slides';
+import { StackComponent } from './stack.component';
+import { StackGameComponent } from './stack-game/stack-game.component';
+import { SimpleStackComponent } from './simple-stack/simple-stack.component';
+import { StackTestComponent } from './stack-test/stack-test.component';
+import { StackFunctionComponent } from './stack-game/stack-function/stack-function.component';
+import { StackFunctionButtonComponent } from './stack-game/stack-function-button/stack-function-button.component';
+import { MatButtonModule } from '@angular/material/button';
+
+@NgModule({
+ declarations: [
+ StackComponent,
+ StackGameComponent,
+ SimpleStackComponent,
+ StackTestComponent,
+ StackFunctionComponent,
+ StackFunctionButtonComponent
+ ],
+ exports: [
+ StackComponent,
+ StackGameComponent,
+ SimpleStackComponent,
+ StackTestComponent,
+ StackFunctionComponent,
+ StackFunctionButtonComponent
+ ],
+ imports: [CommonModule, SlidesModule, MatButtonModule]
+})
+export class StackModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/streaming/common.ts b/codelab-master/apps/kirjs/src/app/modules/streaming/common.ts
new file mode 100644
index 000000000..2a611fa6f
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/streaming/common.ts
@@ -0,0 +1,13 @@
+import { InjectionToken } from '@angular/core';
+
+export const FLAME_LINK = new InjectionToken('FLAME_LINK');
+
+interface Guest {
+ name: string;
+ twitter: string;
+ avatar: string;
+}
+export interface StreamSession {
+ name: string;
+ guests: Guest[];
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/streaming/overlay/overlay.component.html b/codelab-master/apps/kirjs/src/app/modules/streaming/overlay/overlay.component.html
new file mode 100644
index 000000000..1dd5d9ad1
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/streaming/overlay/overlay.component.html
@@ -0,0 +1,45 @@
+
+
+ {{ config.header }}
+ {{ config.subHeader }}
+
+
+
+
+
+ {{ guest.name }}
+
+
@{{ guest.twitter }}
+
+
+ Chat
+
+
+
+
+ @kirjs
+
+
+
+
+ @{{ guest.twitter }}
+
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/streaming/overlay/overlay.component.scss b/codelab-master/apps/kirjs/src/app/modules/streaming/overlay/overlay.component.scss
new file mode 100644
index 000000000..fde8e5680
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/streaming/overlay/overlay.component.scss
@@ -0,0 +1,29 @@
+:host {
+ border: 1px #ddd solid;
+ width: 1650px;
+ height: 1050px;
+ display: block;
+ font-family: 'Helvetica Neue', sans-serif;
+ position: relative;
+}
+
+.circle {
+ position: absolute;
+ right: 20px;
+ bottom: 20px;
+ height: 240px;
+ width: 240px;
+ border-radius: 50%;
+}
+
+:host ::ng-deep {
+ h2 {
+ margin-bottom: 0;
+ font-family: 'Helvetica Neue', sans-serif;
+ font-weight: 300;
+ }
+
+ p {
+ margin-top: 8px;
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/streaming/overlay/overlay.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/streaming/overlay/overlay.component.spec.ts
new file mode 100644
index 000000000..7256ba08e
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/streaming/overlay/overlay.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { OverlayComponent } from './overlay.component';
+
+describe('OverlayComponent', () => {
+ let component: OverlayComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [OverlayComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(OverlayComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/streaming/overlay/overlay.component.ts b/codelab-master/apps/kirjs/src/app/modules/streaming/overlay/overlay.component.ts
new file mode 100644
index 000000000..8e28ca29b
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/streaming/overlay/overlay.component.ts
@@ -0,0 +1,27 @@
+import { Component, Inject, OnInit } from '@angular/core';
+import { FLAME_LINK, StreamSession } from '../common';
+import { interval, Observable } from 'rxjs';
+import { map, startWith, switchMap } from 'rxjs/operators';
+
+@Component({
+ selector: 'slides-overlay',
+ templateUrl: './overlay.component.html',
+ styleUrls: ['./overlay.component.scss']
+})
+export class OverlayComponent implements OnInit {
+ readonly layout = 'horizontal';
+ data$: Observable = interval(5000).pipe(
+ startWith(0),
+ switchMap(() => {
+ return this.flameLink.content.get({
+ schemaKey: 'currentSession',
+ populate: true
+ });
+ }),
+ map((a: any) => a.session)
+ );
+
+ constructor(@Inject(FLAME_LINK) private flameLink: any) {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/streaming/streaming.module.ts b/codelab-master/apps/kirjs/src/app/modules/streaming/streaming.module.ts
new file mode 100644
index 000000000..c2da528d3
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/streaming/streaming.module.ts
@@ -0,0 +1,56 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { RouterModule } from '@angular/router';
+import { OverlayComponent } from './overlay/overlay.component';
+
+import firebase from 'firebase/app';
+// Add additional services that you want to use
+import 'firebase/auth';
+import 'firebase/firestore';
+import flamelink from 'flamelink/app';
+// Add additional modules that you want to use
+import 'flamelink/content';
+import 'flamelink/storage';
+import { FLAME_LINK } from './common';
+import { MarkdownModule } from 'ngx-markdown';
+
+const firebaseConfig = {
+ apiKey: 'AIzaSyC_Zyq9Ve1SrbenuN0iDlDd4hQvTIlruP8',
+ authDomain: 'kirjs-c884f.firebaseapp.com',
+ databaseURL: 'https://kirjs-c884f.firebaseio.com',
+ projectId: 'kirjs-c884f',
+ storageBucket: 'kirjs-c884f.appspot.com',
+ messagingSenderId: '651206687896',
+ appId: '1:651206687896:web:3df45fa9e636bb5882a4ed',
+ measurementId: 'G-3B7YEC4QG7'
+};
+
+const firebaseApp = firebase.initializeApp(firebaseConfig);
+
+const app = flamelink({
+ firebaseApp,
+ env: 'production', // optional, defaults to `production`
+ locale: 'en-US', // optional, defaults to `en-US`
+ dbType: 'cf' // optional, defaults to `rtdb` - can be 'rtdb' or 'cf' (Realtime DB vs Cloud Firestore)
+});
+
+@NgModule({
+ declarations: [],
+ providers: [
+ {
+ provide: FLAME_LINK,
+ useValue: app
+ }
+ ],
+ imports: [
+ RouterModule.forChild([
+ {
+ path: '',
+ component: OverlayComponent
+ }
+ ]),
+ CommonModule,
+ MarkdownModule
+ ]
+})
+export class StreamingModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg-race/finish/finish.component.css b/codelab-master/apps/kirjs/src/app/modules/svg-race/finish/finish.component.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg-race/finish/finish.component.html b/codelab-master/apps/kirjs/src/app/modules/svg-race/finish/finish.component.html
new file mode 100644
index 000000000..1d48ad167
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg-race/finish/finish.component.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg-race/finish/finish.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/svg-race/finish/finish.component.spec.ts
new file mode 100644
index 000000000..45cdb1b4b
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg-race/finish/finish.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { FinishComponent } from './finish.component';
+
+describe('FinishComponent', () => {
+ let component: FinishComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [FinishComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(FinishComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg-race/finish/finish.component.ts b/codelab-master/apps/kirjs/src/app/modules/svg-race/finish/finish.component.ts
new file mode 100644
index 000000000..3301a247e
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg-race/finish/finish.component.ts
@@ -0,0 +1,15 @@
+import { Component, Input, OnInit } from '@angular/core';
+
+@Component({
+ // tslint:disable-next-line:component-selector
+ selector: '[kirjs-finish]',
+ templateUrl: './finish.component.html',
+ styleUrls: ['./finish.component.css']
+})
+export class FinishComponent implements OnInit {
+ @Input() position = { x: 0, y: 0 };
+
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg-race/little-car/little-car.component.css b/codelab-master/apps/kirjs/src/app/modules/svg-race/little-car/little-car.component.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg-race/little-car/little-car.component.html b/codelab-master/apps/kirjs/src/app/modules/svg-race/little-car/little-car.component.html
new file mode 100644
index 000000000..6686b8860
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg-race/little-car/little-car.component.html
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg-race/little-car/little-car.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/svg-race/little-car/little-car.component.spec.ts
new file mode 100644
index 000000000..543e4192f
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg-race/little-car/little-car.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { LittleCarComponent } from './little-car.component';
+
+describe('LittleCarComponent', () => {
+ let component: LittleCarComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [LittleCarComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(LittleCarComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg-race/little-car/little-car.component.ts b/codelab-master/apps/kirjs/src/app/modules/svg-race/little-car/little-car.component.ts
new file mode 100644
index 000000000..b8c45929a
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg-race/little-car/little-car.component.ts
@@ -0,0 +1,19 @@
+import { Component, Input } from '@angular/core';
+
+@Component({
+ // tslint:disable-next-line:component-selector
+ selector: '[kirjs-little-car]',
+ templateUrl: './little-car.component.html',
+ styleUrls: ['./little-car.component.css']
+})
+export class LittleCarComponent {
+ @Input() position = { x: 0, y: 0, angle: 0 };
+ lightColor = '#ffbc05';
+ darkColor = '#e38100';
+
+ @Input()
+ set color(color: string) {
+ this.lightColor = color;
+ this.darkColor = '#444';
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg-race/player/player.component.css b/codelab-master/apps/kirjs/src/app/modules/svg-race/player/player.component.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg-race/player/player.component.html b/codelab-master/apps/kirjs/src/app/modules/svg-race/player/player.component.html
new file mode 100644
index 000000000..f1438537b
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg-race/player/player.component.html
@@ -0,0 +1,7 @@
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg-race/player/player.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/svg-race/player/player.component.spec.ts
new file mode 100644
index 000000000..3138c1cc8
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg-race/player/player.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { PlayerComponent } from './player.component';
+
+describe('PlayerComponent', () => {
+ let component: PlayerComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [PlayerComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(PlayerComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg-race/player/player.component.ts b/codelab-master/apps/kirjs/src/app/modules/svg-race/player/player.component.ts
new file mode 100644
index 000000000..86eeab60e
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg-race/player/player.component.ts
@@ -0,0 +1,148 @@
+import {
+ AfterViewInit,
+ Component,
+ ElementRef,
+ EventEmitter,
+ Input,
+ OnChanges,
+ OnInit,
+ Output,
+ SimpleChanges,
+ ViewChild
+} from '@angular/core';
+
+@Component({
+ // tslint:disable-next-line:component-selector
+ selector: '[kirjs-player]',
+ templateUrl: './player.component.html',
+ styleUrls: ['./player.component.css']
+})
+export class PlayerComponent implements OnInit, AfterViewInit, OnChanges {
+ @ViewChild('guess', { static: true }) guess: ElementRef;
+ @Input() path;
+ @Input() d = '';
+ @Input() color = '#ffffff';
+ @Output() scoreChanged = new EventEmitter();
+ points = [];
+ carPosition = { x: 50, y: 50, angle: 0 };
+ pathLength = 0;
+ startPosition = { x: 0, y: 0 };
+ trackWidth = 20;
+ score = 0;
+
+ ngOnChanges(changes: SimpleChanges) {
+ if (changes.d) {
+ this.calculateScore();
+ }
+ }
+
+ calculateScore() {
+ requestAnimationFrame(() => {
+ this.calculateCarPosition();
+ this.score = 0;
+ const guess = this.guess.nativeElement;
+
+ for (let i = 0; i < this.points.length; i++) {
+ const point = this.points[i];
+
+ const { distance } = closestPoint(guess, point);
+
+ if (distance < this.trackWidth) {
+ this.score++;
+ } else {
+ this.pathLength = ((i - 3) / 100) * this.path.getTotalLength();
+ this.scoreChanged.emit(this.score);
+ return;
+ }
+ }
+ this.scoreChanged.emit(this.score);
+ });
+ }
+
+ ngAfterViewInit() {
+ requestAnimationFrame(() => {
+ const path = this.path;
+ const l = path.getTotalLength();
+
+ for (let i = 0; i < l; i += l / 100) {
+ this.points.push(path.getPointAtLength(i));
+ }
+
+ this.startPosition = path.getPointAtLength(0);
+ });
+ }
+
+ calculateCarPosition() {
+ const guess = this.guess.nativeElement;
+ const totalLength = guess.getTotalLength();
+ this.carPosition = guess.getPointAtLength(totalLength);
+ if (totalLength > 1) {
+ const carPosition = guess.getPointAtLength(totalLength - 1);
+ const dx = this.carPosition.x - carPosition.x;
+ const dy = this.carPosition.y - carPosition.y;
+ this.carPosition.angle = (Math.atan2(-dx, dy) * 180) / Math.PI;
+ }
+ }
+
+ ngOnInit() {}
+}
+
+function closestPoint(pathNode, point) {
+ const pathLength = pathNode.getTotalLength();
+ let precision = 8,
+ best,
+ bestLength,
+ bestDistance = Infinity;
+
+ // linear scan for coarse approximation
+ for (
+ let scan, scanLength = 0, scanDistance;
+ scanLength <= pathLength;
+ scanLength += precision
+ ) {
+ if (
+ (scanDistance = distance2(
+ (scan = pathNode.getPointAtLength(scanLength))
+ )) < bestDistance
+ ) {
+ (best = scan), (bestLength = scanLength), (bestDistance = scanDistance);
+ }
+ }
+
+ // binary search for precise estimate
+ precision /= 2;
+ while (precision > 0.5) {
+ let before, after, beforeLength, afterLength, beforeDistance, afterDistance;
+ if (
+ (beforeLength = bestLength - precision) >= 0 &&
+ (beforeDistance = distance2(
+ (before = pathNode.getPointAtLength(beforeLength))
+ )) < bestDistance
+ ) {
+ (best = before),
+ (bestLength = beforeLength),
+ (bestDistance = beforeDistance);
+ } else if (
+ (afterLength = bestLength + precision) <= pathLength &&
+ (afterDistance = distance2(
+ (after = pathNode.getPointAtLength(afterLength))
+ )) < bestDistance
+ ) {
+ (best = after),
+ (bestLength = afterLength),
+ (bestDistance = afterDistance);
+ } else {
+ precision /= 2;
+ }
+ }
+
+ best = [best.x, best.y];
+ best.distance = Math.sqrt(bestDistance);
+ return best;
+
+ function distance2(p) {
+ const dx = p.x - point.x,
+ dy = p.y - point.y;
+ return dx * dx + dy * dy;
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg-race/race/race.component.css b/codelab-master/apps/kirjs/src/app/modules/svg-race/race/race.component.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg-race/race/race.component.html b/codelab-master/apps/kirjs/src/app/modules/svg-race/race/race.component.html
new file mode 100644
index 000000000..adcc23cd2
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg-race/race/race.component.html
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg-race/race/race.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/svg-race/race/race.component.spec.ts
new file mode 100644
index 000000000..495bb85ef
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg-race/race/race.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { RaceComponent } from './race.component';
+
+describe('RaceComponent', () => {
+ let component: RaceComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [RaceComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(RaceComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg-race/race/race.component.ts b/codelab-master/apps/kirjs/src/app/modules/svg-race/race/race.component.ts
new file mode 100644
index 000000000..9139d8ed9
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg-race/race/race.component.ts
@@ -0,0 +1,62 @@
+import {
+ AfterViewInit,
+ Component,
+ ElementRef,
+ Input,
+ ViewChild
+} from '@angular/core';
+
+@Component({
+ selector: 'kirjs-race',
+ templateUrl: './race.component.html',
+ styleUrls: ['./race.component.css']
+})
+export class RaceComponent implements AfterViewInit {
+ @Input() code: string;
+ d = 'M50 450 v -5';
+ cars = [
+ {
+ name: 'cheburek',
+ color: '#fd6b00',
+ d: this.d,
+ score: 0
+ },
+ {
+ name: 'banana',
+ color: '#fde200',
+ d: 'M50 450 v 5 l -10 -300',
+ score: 0
+ },
+ {
+ name: 'ololo',
+ color: '#bdfd00',
+ d: 'M50 450 v -5 h 10v-300',
+ score: 0
+ }
+ ];
+ @Input() track: string;
+ @ViewChild('path', { static: false }) path: ElementRef;
+ name = 'cheburek';
+ scores = {};
+ trackWidth = 20;
+ finishPosition = { x: 0, y: 0 };
+
+ updateCurrentPlayer() {
+ const c = this.cars.find(car => car.name === this.name);
+ if (c) {
+ c.d = this.d;
+ }
+ }
+
+ ngAfterViewInit() {
+ const path = this.path.nativeElement;
+ this.finishPosition = path.getPointAtLength(path.getTotalLength());
+ }
+
+ setScore(name: string, score: number) {
+ const c = this.cars.find(car => name === car.name);
+ if (c) {
+ c.score = score;
+ }
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg-race/svg-race.component.css b/codelab-master/apps/kirjs/src/app/modules/svg-race/svg-race.component.css
new file mode 100644
index 000000000..ae9ea3870
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg-race/svg-race.component.css
@@ -0,0 +1,36 @@
+:host ::ng-deep .monaco-editor .view-overlays .current-line {
+ display: none;
+}
+
+:host ::ng-deep .decorationsOverviewRuler {
+ display: none;
+}
+
+:host ::ng-deep .scrollbar.vertical {
+ display: none;
+}
+
+.timer {
+ position: fixed;
+ left: 20px;
+ bottom: 20px;
+}
+
+.btn-bar {
+ line-height: 3vw;
+}
+
+.btn-bar:hover .font-size {
+ display: block;
+ font-size: 4vw;
+}
+
+.btn-bar .font-size {
+ display: none;
+}
+
+.twitter {
+ color: #444;
+ font-size: 3vw;
+ margin: 2vw;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg-race/svg-race.component.html b/codelab-master/apps/kirjs/src/app/modules/svg-race/svg-race.component.html
new file mode 100644
index 000000000..44ebc5f9a
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg-race/svg-race.component.html
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+ Angular ❤️ SVG
+
+ @kirjs
+
+
+
+
+
+
+
+
+
+
Anybody will see this info!
+ Only presenter sees this
+ Only viewer sees this
+
+
+
+
We can take user input
+
+
+
+
+
+
+
+
+
+
You are a presenter
+
+
+
You are a viewer
+
+
+
What is SVG?
+
+ Scalable Vector Graphic Format
+ Every object is just an XML tag
+ Also works with CSS
+
+
+
+
+
LOL
+
+
+
+
+
Race
+
+
+
+
+
Race
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg-race/svg-race.component.ts b/codelab-master/apps/kirjs/src/app/modules/svg-race/svg-race.component.ts
new file mode 100644
index 000000000..eb8406841
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg-race/svg-race.component.ts
@@ -0,0 +1,33 @@
+import { Component } from '@angular/core';
+import {
+ bootstrap,
+ builder,
+ exercise,
+ stylesheet
+} from '../../../../../codelab/src/app/shared/helpers/helpers';
+
+declare const require;
+
+@Component({
+ selector: 'kirjs-svg-race',
+ templateUrl: './svg-race.component.html',
+ styleUrls: ['./svg-race.component.css']
+})
+export class SvgRaceComponent {
+ fontSize = 20;
+
+ tracks = {
+ advanced: `M50 450 Q -50 -60 300 50
+Q 380 75 400 150
+Q 450 350 300 150
+Q 250 50 150 120
+Q 50 250 150 320
+Q 250 420 450 320
+
+`
+ };
+ input = 'hi';
+ input2: any;
+
+ constructor() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg-race/svg-race.module.ts b/codelab-master/apps/kirjs/src/app/modules/svg-race/svg-race.module.ts
new file mode 100644
index 000000000..db0fa3901
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg-race/svg-race.module.ts
@@ -0,0 +1,55 @@
+import { NgModule, Pipe, PipeTransform } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { DomSanitizer } from '@angular/platform-browser';
+import { CommonModule } from '@angular/common';
+import { MatButtonModule } from '@angular/material/button';
+import { SlidesModule, SlidesRoutes } from '@ng360/slides';
+
+import { FeedbackModule } from '@codelab/feedback';
+import { SyncModule } from '@codelab/utils/src/lib/sync/sync.module';
+import { CodeDemoModule } from '@codelab/code-demos';
+import { TimerComponent } from './timer/timer.component';
+import { RaceComponent } from './race/race.component';
+import { LittleCarComponent } from './little-car/little-car.component';
+import { FinishComponent } from './finish/finish.component';
+import { PlayerComponent } from './player/player.component';
+import { SvgRaceComponent } from './svg-race.component';
+import { ButtonsNavBarModule } from '../../../../../codelab/src/app/components/buttons-nav-bar/buttons-nav-bar.module';
+
+const routes = RouterModule.forChild(SlidesRoutes.get(SvgRaceComponent));
+
+@Pipe({ name: 'safeHtml' })
+export class SafeHtml implements PipeTransform {
+ constructor(private readonly sanitizer: DomSanitizer) {}
+
+ transform(html) {
+ return this.sanitizer.bypassSecurityTrustHtml(html);
+ }
+}
+
+@NgModule({
+ imports: [
+ routes,
+ CommonModule,
+ SlidesModule,
+ ButtonsNavBarModule,
+ FeedbackModule,
+ CodeDemoModule,
+ FormsModule,
+ MatButtonModule,
+ SyncModule,
+ ReactiveFormsModule
+ ],
+ declarations: [
+ RaceComponent,
+ SafeHtml,
+ SvgRaceComponent,
+ TimerComponent,
+ LittleCarComponent,
+ FinishComponent,
+ PlayerComponent
+ ],
+ exports: [SvgRaceComponent]
+})
+export class SvgRaceModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg-race/timer/timer.component.css b/codelab-master/apps/kirjs/src/app/modules/svg-race/timer/timer.component.css
new file mode 100644
index 000000000..1ee7514d1
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg-race/timer/timer.component.css
@@ -0,0 +1,4 @@
+.timer-running {
+ color: #444;
+ font-size: 3vw;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg-race/timer/timer.component.html b/codelab-master/apps/kirjs/src/app/modules/svg-race/timer/timer.component.html
new file mode 100644
index 000000000..6b16b6af5
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg-race/timer/timer.component.html
@@ -0,0 +1,2 @@
+▶️
+ 0" class="timer-running">{{ time }}️
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg-race/timer/timer.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/svg-race/timer/timer.component.spec.ts
new file mode 100644
index 000000000..b393c12a9
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg-race/timer/timer.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { TimerComponent } from './timer.component';
+
+describe('TimerComponent', () => {
+ let component: TimerComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [TimerComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(TimerComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg-race/timer/timer.component.ts b/codelab-master/apps/kirjs/src/app/modules/svg-race/timer/timer.component.ts
new file mode 100644
index 000000000..1cb7ecfe6
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg-race/timer/timer.component.ts
@@ -0,0 +1,24 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-timer',
+ templateUrl: './timer.component.html',
+ styleUrls: ['./timer.component.css']
+})
+export class TimerComponent implements OnInit {
+ time = 0;
+
+ reset() {
+ this.time = 180;
+ }
+
+ constructor() {
+ window.setInterval(() => {
+ if (this.time > 0) {
+ this.time--;
+ }
+ }, 1000);
+ }
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/pics/1.jpg b/codelab-master/apps/kirjs/src/app/modules/svg/pics/1.jpg
new file mode 100644
index 000000000..7d9e301fd
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/svg/pics/1.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/pics/2.jpg b/codelab-master/apps/kirjs/src/app/modules/svg/pics/2.jpg
new file mode 100644
index 000000000..b61f46e7d
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/svg/pics/2.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/pics/3.jpg b/codelab-master/apps/kirjs/src/app/modules/svg/pics/3.jpg
new file mode 100644
index 000000000..a4804c6d0
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/svg/pics/3.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/pics/4.jpg b/codelab-master/apps/kirjs/src/app/modules/svg/pics/4.jpg
new file mode 100644
index 000000000..ed0fe1d86
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/svg/pics/4.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/pics/5.gif b/codelab-master/apps/kirjs/src/app/modules/svg/pics/5.gif
new file mode 100644
index 000000000..753dc9f07
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/svg/pics/5.gif differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/pics/ava.gif b/codelab-master/apps/kirjs/src/app/modules/svg/pics/ava.gif
new file mode 100644
index 000000000..4ef9143b8
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/svg/pics/ava.gif differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/samples/app.component.ts b/codelab-master/apps/kirjs/src/app/modules/svg/samples/app.component.ts
new file mode 100644
index 000000000..b534cdae3
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/samples/app.component.ts
@@ -0,0 +1,8 @@
+import { Component } from '@angular/core';
+
+// Just an empty component to make everything compile
+@Component({
+ selector: 'kirjs-app',
+ template: ''
+})
+export class AppComponent {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/samples/app.module.ts b/codelab-master/apps/kirjs/src/app/modules/svg/samples/app.module.ts
new file mode 100644
index 000000000..faea495af
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/samples/app.module.ts
@@ -0,0 +1,10 @@
+import { BrowserModule } from '@angular/platform-browser';
+import { NgModule } from '@angular/core';
+import { AppComponent } from './app.component';
+
+@NgModule({
+ imports: [BrowserModule],
+ declarations: [AppComponent],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/samples/attr/app.component.ts b/codelab-master/apps/kirjs/src/app/modules/svg/samples/attr/app.component.ts
new file mode 100644
index 000000000..f2fd98a55
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/samples/attr/app.component.ts
@@ -0,0 +1,27 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-app',
+ template: `
+
+
+
+ `
+})
+export class AppComponent {
+ y = 200;
+
+ constructor() {
+ window.setInterval(() => {
+ this.y = Math.random() * 300;
+ }, 200);
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/samples/bs.module.ts b/codelab-master/apps/kirjs/src/app/modules/svg/samples/bs.module.ts
new file mode 100644
index 000000000..9f8fb09e5
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/samples/bs.module.ts
@@ -0,0 +1,22 @@
+import { AppComponent as A1 } from './sub.component';
+import { AppComponent as A2 } from './attr/app.component';
+import { AppComponent as A3 } from './chart/app.component';
+import { AppComponent as A4 } from './svg/app.component';
+import { AppComponent as A5 } from './chart4/app.component.solved';
+import { AppComponent as A6 } from './chart2/app.component.solved';
+import { Component, Input, NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+
+@Component({
+ selector: 'kirjs-ticks',
+ template: ''
+})
+export class FakeTicksComponent {
+ @Input() data: any;
+}
+
+@NgModule({
+ imports: [CommonModule],
+ declarations: [A1, A2, A3, A4, A5, A6, FakeTicksComponent]
+})
+export class AppModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart/app.component.ts b/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart/app.component.ts
new file mode 100644
index 000000000..c2193ab27
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart/app.component.ts
@@ -0,0 +1,48 @@
+import { Component } from '@angular/core';
+
+function generateData() {
+ return Array.from(new Array(10)).map(index =>
+ Math.round(Math.random() * 300)
+ );
+}
+
+@Component({
+ selector: 'kirjs-app',
+ template: `
+
+
+
+
+ {{ item }}
+
+
+ `
+})
+export class AppComponent {
+ barWidth = 30;
+ padding = 10;
+ barSpace = this.padding + this.barWidth;
+
+ data = generateData();
+
+ constructor() {
+ window.setInterval(() => {
+ this.data = generateData();
+ }, 1000);
+ }
+
+ getIndex(a, b) {
+ return a;
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart2/app.component.solved.ts b/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart2/app.component.solved.ts
new file mode 100644
index 000000000..1edd47f20
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart2/app.component.solved.ts
@@ -0,0 +1,49 @@
+import { Component } from '@angular/core';
+
+function generateData() {
+ return Array.from(new Array(10)).map(index => ({
+ index,
+ value: Math.round(Math.random() * 300)
+ }));
+}
+
+@Component({
+ selector: 'kirjs-app',
+ template: `
+
+
+
+
+ {{ item.value }}
+
+
+
+ `
+})
+export class AppComponent {
+ barWidth = 30;
+ padding = 10;
+ barSpace = this.padding + this.barWidth;
+ data = generateData();
+
+ constructor() {
+ window.setInterval(() => {
+ this.data = generateData();
+ }, 1000);
+ }
+
+ getIndex(a, b) {
+ return a;
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart2/app.component.ts b/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart2/app.component.ts
new file mode 100644
index 000000000..a4d6d5cbb
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart2/app.component.ts
@@ -0,0 +1,48 @@
+import { Component } from '@angular/core';
+
+function generateData() {
+ return Array.from(new Array(10)).map(index => ({
+ index,
+ value: Math.round(Math.random() * 300)
+ }));
+}
+
+@Component({
+ selector: 'kirjs-app',
+ template: `
+
+
+
+
+ {{ item.value }}
+
+
+ `
+})
+export class AppComponent {
+ barWidth = 30;
+ padding = 10;
+ barSpace = this.padding + this.barWidth;
+ data = generateData();
+
+ constructor() {
+ window.setInterval(() => {
+ this.data = generateData();
+ }, 1000);
+ }
+
+ getIndex(a, b) {
+ return a;
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart2/app.module.ts b/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart2/app.module.ts
new file mode 100644
index 000000000..5075dc62b
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart2/app.module.ts
@@ -0,0 +1,11 @@
+import { BrowserModule } from '@angular/platform-browser';
+import { NgModule } from '@angular/core';
+import { AppComponent } from './app.component';
+import { TicksComponent } from './ticks.component';
+
+@NgModule({
+ imports: [BrowserModule],
+ declarations: [AppComponent, TicksComponent],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart2/ticks.component.ts b/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart2/ticks.component.ts
new file mode 100644
index 000000000..dc7aded0d
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart2/ticks.component.ts
@@ -0,0 +1,25 @@
+import { Component, Input } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-ticks',
+ template: `
+
+ {{ i }}
+
+ `
+})
+export class TicksComponent {
+ @Input() data;
+ @Input() barWidth = 30;
+ padding = 10;
+ barSpace = this.padding + this.barWidth;
+
+ getIndex(i: number) {
+ return i;
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart3/app.component.ts b/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart3/app.component.ts
new file mode 100644
index 000000000..a4d6d5cbb
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart3/app.component.ts
@@ -0,0 +1,48 @@
+import { Component } from '@angular/core';
+
+function generateData() {
+ return Array.from(new Array(10)).map(index => ({
+ index,
+ value: Math.round(Math.random() * 300)
+ }));
+}
+
+@Component({
+ selector: 'kirjs-app',
+ template: `
+
+
+
+
+ {{ item.value }}
+
+
+ `
+})
+export class AppComponent {
+ barWidth = 30;
+ padding = 10;
+ barSpace = this.padding + this.barWidth;
+ data = generateData();
+
+ constructor() {
+ window.setInterval(() => {
+ this.data = generateData();
+ }, 1000);
+ }
+
+ getIndex(a, b) {
+ return a;
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart3/app.module.ts b/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart3/app.module.ts
new file mode 100644
index 000000000..5075dc62b
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart3/app.module.ts
@@ -0,0 +1,11 @@
+import { BrowserModule } from '@angular/platform-browser';
+import { NgModule } from '@angular/core';
+import { AppComponent } from './app.component';
+import { TicksComponent } from './ticks.component';
+
+@NgModule({
+ imports: [BrowserModule],
+ declarations: [AppComponent, TicksComponent],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart3/ticks.component.ts b/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart3/ticks.component.ts
new file mode 100644
index 000000000..dc7aded0d
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart3/ticks.component.ts
@@ -0,0 +1,25 @@
+import { Component, Input } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-ticks',
+ template: `
+
+ {{ i }}
+
+ `
+})
+export class TicksComponent {
+ @Input() data;
+ @Input() barWidth = 30;
+ padding = 10;
+ barSpace = this.padding + this.barWidth;
+
+ getIndex(i: number) {
+ return i;
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart4/app.component.solved.ts b/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart4/app.component.solved.ts
new file mode 100644
index 000000000..e02ad6528
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart4/app.component.solved.ts
@@ -0,0 +1,49 @@
+import { Component } from '@angular/core';
+
+function generateData() {
+ return Array.from(new Array(10)).map(index => ({
+ index,
+ value: Math.round(Math.random() * 300)
+ }));
+}
+
+@Component({
+ selector: 'kirjs-app',
+ template: `
+
+
+
+
+ {{ item.value }}
+
+
+
+ `
+})
+export class AppComponent {
+ barWidth = 30;
+ padding = 10;
+ barSpace = this.padding + this.barWidth;
+ data = generateData();
+
+ constructor() {
+ window.setInterval(() => {
+ this.data = generateData();
+ }, 1000);
+ }
+
+ getIndex(a, b) {
+ return a;
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart4/app.component.ts b/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart4/app.component.ts
new file mode 100644
index 000000000..709eb3894
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart4/app.component.ts
@@ -0,0 +1,49 @@
+import { Component } from '@angular/core';
+
+function generateData() {
+ return Array.from(new Array(10)).map(index => ({
+ index,
+ value: Math.round(Math.random() * 300)
+ }));
+}
+
+@Component({
+ selector: 'kirjs-app',
+ template: `
+
+
+
+
+ {{ item.value }}
+
+
+
+ `
+})
+export class AppComponent {
+ barWidth = 30;
+ padding = 10;
+ barSpace = this.padding + this.barWidth;
+ data = generateData();
+
+ constructor() {
+ window.setInterval(() => {
+ this.data = generateData();
+ }, 1000);
+ }
+
+ getIndex(a, b) {
+ return a;
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart4/app.module.ts b/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart4/app.module.ts
new file mode 100644
index 000000000..5075dc62b
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart4/app.module.ts
@@ -0,0 +1,11 @@
+import { BrowserModule } from '@angular/platform-browser';
+import { NgModule } from '@angular/core';
+import { AppComponent } from './app.component';
+import { TicksComponent } from './ticks.component';
+
+@NgModule({
+ imports: [BrowserModule],
+ declarations: [AppComponent, TicksComponent],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart4/ticks.component.ts b/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart4/ticks.component.ts
new file mode 100644
index 000000000..dc7aded0d
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/samples/chart4/ticks.component.ts
@@ -0,0 +1,25 @@
+import { Component, Input } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-ticks',
+ template: `
+
+ {{ i }}
+
+ `
+})
+export class TicksComponent {
+ @Input() data;
+ @Input() barWidth = 30;
+ padding = 10;
+ barSpace = this.padding + this.barWidth;
+
+ getIndex(i: number) {
+ return i;
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/samples/index.html b/codelab-master/apps/kirjs/src/app/modules/svg/samples/index.html
new file mode 100644
index 000000000..3eb5376ac
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/samples/index.html
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/samples/style.css b/codelab-master/apps/kirjs/src/app/modules/svg/samples/style.css
new file mode 100644
index 000000000..26c577754
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/samples/style.css
@@ -0,0 +1,17 @@
+svg,
+body,
+html {
+ width: 100%;
+ height: 100%;
+}
+
+text {
+ font-family: sans-serif;
+ text-anchor: middle;
+}
+
+rect,
+text,
+g {
+ transition: 1s;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/samples/sub.component.ts b/codelab-master/apps/kirjs/src/app/modules/svg/samples/sub.component.ts
new file mode 100644
index 000000000..f2fd98a55
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/samples/sub.component.ts
@@ -0,0 +1,27 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-app',
+ template: `
+
+
+
+ `
+})
+export class AppComponent {
+ y = 200;
+
+ constructor() {
+ window.setInterval(() => {
+ this.y = Math.random() * 300;
+ }, 200);
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/samples/svg/app.component.ts b/codelab-master/apps/kirjs/src/app/modules/svg/samples/svg/app.component.ts
new file mode 100644
index 000000000..20b60f4e9
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/samples/svg/app.component.ts
@@ -0,0 +1,17 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-app',
+ template: `
+
+ `
+})
+export class AppComponent {
+ y = 200;
+
+ constructor() {
+ window.setInterval(() => {
+ this.y = Math.random() * 300;
+ }, 200);
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/svg-demo/svg-demo.component.css b/codelab-master/apps/kirjs/src/app/modules/svg/svg-demo/svg-demo.component.css
new file mode 100644
index 000000000..157c3b2dd
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/svg-demo/svg-demo.component.css
@@ -0,0 +1,9 @@
+:host {
+ height: 100%;
+ display: block;
+}
+
+:host ::ng-deep svg {
+ width: 100%;
+ height: 100%;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/svg-demo/svg-demo.component.html b/codelab-master/apps/kirjs/src/app/modules/svg/svg-demo/svg-demo.component.html
new file mode 100644
index 000000000..1f6ea3220
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/svg-demo/svg-demo.component.html
@@ -0,0 +1,12 @@
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/svg-demo/svg-demo.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/svg/svg-demo/svg-demo.component.spec.ts
new file mode 100644
index 000000000..45375a870
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/svg-demo/svg-demo.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SvgDemoComponent } from './svg-demo.component';
+
+describe('SvgDemoComponent', () => {
+ let component: SvgDemoComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [SvgDemoComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(SvgDemoComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/svg-demo/svg-demo.component.ts b/codelab-master/apps/kirjs/src/app/modules/svg/svg-demo/svg-demo.component.ts
new file mode 100644
index 000000000..65e2307c2
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/svg-demo/svg-demo.component.ts
@@ -0,0 +1,18 @@
+import { Component, Input, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-svg-demo',
+ templateUrl: './svg-demo.component.html',
+ styleUrls: ['./svg-demo.component.css']
+})
+export class SvgDemoComponent implements OnInit {
+ code: string;
+
+ @Input() fontSize;
+ @Input('code')
+ set codeInput(value) {
+ this.code = '\n' + value + '\n ';
+ }
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/svg-playground/svg-playground.component.css b/codelab-master/apps/kirjs/src/app/modules/svg/svg-playground/svg-playground.component.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/svg-playground/svg-playground.component.html b/codelab-master/apps/kirjs/src/app/modules/svg/svg-playground/svg-playground.component.html
new file mode 100644
index 000000000..c4dc8d31e
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/svg-playground/svg-playground.component.html
@@ -0,0 +1 @@
+svg-playground works!
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/svg-playground/svg-playground.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/svg/svg-playground/svg-playground.component.spec.ts
new file mode 100644
index 000000000..1c10b4ab9
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/svg-playground/svg-playground.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SvgPlaygroundComponent } from './svg-playground.component';
+
+describe('RaceComponent', () => {
+ let component: SvgPlaygroundComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [SvgPlaygroundComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(SvgPlaygroundComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/svg-playground/svg-playground.component.ts b/codelab-master/apps/kirjs/src/app/modules/svg/svg-playground/svg-playground.component.ts
new file mode 100644
index 000000000..17add7ab6
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/svg-playground/svg-playground.component.ts
@@ -0,0 +1,14 @@
+import { Component, Input, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-svg-playground',
+ templateUrl: './svg-playground.component.html',
+ styleUrls: ['./svg-playground.component.css']
+})
+export class SvgPlaygroundComponent implements OnInit {
+ @Input() code: string;
+
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/svg-together-result/svg-together-result.component.css b/codelab-master/apps/kirjs/src/app/modules/svg/svg-together-result/svg-together-result.component.css
new file mode 100644
index 000000000..6053e8ea1
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/svg-together-result/svg-together-result.component.css
@@ -0,0 +1,23 @@
+:host {
+ height: 100%;
+ display: block;
+}
+
+:host ::ng-deep svg {
+ width: 100%;
+ height: 100%;
+}
+
+code-demo-editor {
+ height: 500px;
+ width: 100%;
+ display: inline-block;
+ border: 1px solid #000;
+}
+
+::ng-deep svg {
+ width: 500px;
+ height: 500px;
+ border: 1px solid #999999;
+ min-height: 500px;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/svg-together-result/svg-together-result.component.html b/codelab-master/apps/kirjs/src/app/modules/svg/svg-together-result/svg-together-result.component.html
new file mode 100644
index 000000000..7532d3122
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/svg-together-result/svg-together-result.component.html
@@ -0,0 +1,15 @@
+
+
+ https://codelab.fun/svg/draw
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/svg-together-result/svg-together-result.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/svg/svg-together-result/svg-together-result.component.spec.ts
new file mode 100644
index 000000000..44ac9a3bb
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/svg-together-result/svg-together-result.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SvgTogetherResultComponent } from './svg-together-result.component';
+
+describe('SvgTogetherResultComponent', () => {
+ let component: SvgTogetherResultComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [SvgTogetherResultComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(SvgTogetherResultComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/svg-together-result/svg-together-result.component.ts b/codelab-master/apps/kirjs/src/app/modules/svg/svg-together-result/svg-together-result.component.ts
new file mode 100644
index 000000000..f9d8e5ebb
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/svg-together-result/svg-together-result.component.ts
@@ -0,0 +1,31 @@
+import { Component, Input, OnInit } from '@angular/core';
+import { AngularFireDatabase, AngularFireList } from '@angular/fire/database';
+
+@Component({
+ selector: 'kirjs-svg-together-result',
+ templateUrl: './svg-together-result.component.html',
+ styleUrls: ['./svg-together-result.component.css']
+})
+export class SvgTogetherResultComponent implements OnInit {
+ code = '';
+ angularFireList: AngularFireList;
+ @Input() fontSize;
+ allCode = 'TBD';
+
+ constructor(af: AngularFireDatabase) {
+ this.angularFireList = af.list('/svg-together');
+ this.angularFireList.snapshotChanges().subscribe(a => {
+ this.allCode =
+ '' +
+ a.map(a => a.payload.val()).join('\n') +
+ ' ';
+ });
+ }
+
+ @Input('code')
+ set codeInput(value) {
+ this.code = '\n' + value + '\n ';
+ }
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/svg-together/svg-together.component.css b/codelab-master/apps/kirjs/src/app/modules/svg/svg-together/svg-together.component.css
new file mode 100644
index 000000000..6053e8ea1
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/svg-together/svg-together.component.css
@@ -0,0 +1,23 @@
+:host {
+ height: 100%;
+ display: block;
+}
+
+:host ::ng-deep svg {
+ width: 100%;
+ height: 100%;
+}
+
+code-demo-editor {
+ height: 500px;
+ width: 100%;
+ display: inline-block;
+ border: 1px solid #000;
+}
+
+::ng-deep svg {
+ width: 500px;
+ height: 500px;
+ border: 1px solid #999999;
+ min-height: 500px;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/svg-together/svg-together.component.html b/codelab-master/apps/kirjs/src/app/modules/svg/svg-together/svg-together.component.html
new file mode 100644
index 000000000..9d7d2db56
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/svg-together/svg-together.component.html
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/svg-together/svg-together.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/svg/svg-together/svg-together.component.spec.ts
new file mode 100644
index 000000000..ee07989cc
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/svg-together/svg-together.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SvgTogetherComponent } from './svg-together.component';
+
+describe('SvgTogetherComponent', () => {
+ let component: SvgTogetherComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [SvgTogetherComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(SvgTogetherComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/svg-together/svg-together.component.ts b/codelab-master/apps/kirjs/src/app/modules/svg/svg-together/svg-together.component.ts
new file mode 100644
index 000000000..55fc5248a
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/svg-together/svg-together.component.ts
@@ -0,0 +1,132 @@
+import { Component, Input, OnInit } from '@angular/core';
+import { AngularFireDatabase, AngularFireList } from '@angular/fire/database';
+
+@Component({
+ selector: 'kirjs-svg-together',
+ templateUrl: './svg-together.component.html',
+ styleUrls: ['./svg-together.component.css']
+})
+export class SvgTogetherComponent implements OnInit {
+ code = '';
+ angularFireList: AngularFireList;
+ @Input() fontSize;
+ allCode = 'TBD';
+ helpers = [
+ {
+ label: '⭕️',
+ code: `
+
+
+ `
+ },
+ {
+ label: '⬭',
+ code: `
+
+ `
+ },
+ {
+ label: '▭',
+ code: `
+
+
+ `
+ },
+ {
+ label: '_',
+ code: `
+
+
+ `
+ },
+ {
+ label: 't',
+ code: `
+
+LOL❤
+
+ `
+ },
+ {
+ label: '☆',
+ code: `
+
+ `
+ },
+ {
+ label: '⌇',
+ code: `
+
+ `
+ }
+ ];
+
+ constructor(af: AngularFireDatabase) {
+ this.angularFireList = af.list('/svg-together');
+ this.angularFireList.snapshotChanges().subscribe(a => {
+ this.allCode =
+ '' + a.map(a => a.payload.val()).join('\n') + ' ';
+ });
+ this.reset();
+ }
+
+ @Input('code')
+ set codeInput(value) {
+ this.code = '\n' + value + '\n ';
+ }
+
+ submit() {
+ const code = this.code.replace(/\s+/, '').replace(' ', '');
+ this.angularFireList.push(code);
+ this.reset();
+ }
+
+ reset() {
+ this.code = `
+
+ `;
+ }
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/svg.component.css b/codelab-master/apps/kirjs/src/app/modules/svg/svg.component.css
new file mode 100644
index 000000000..863048277
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/svg.component.css
@@ -0,0 +1,94 @@
+:host ::ng-deep .monaco-editor .view-overlays .current-line {
+ display: none;
+}
+
+:host ::ng-deep .decorationsOverviewRuler {
+ display: none;
+}
+
+:host ::ng-deep .scrollbar.vertical {
+ display: none;
+}
+
+.timer {
+ position: fixed;
+ left: 20px;
+ bottom: 20px;
+}
+
+.bg {
+ width: 100%;
+ height: 100%;
+ background-repeat: no-repeat;
+ background-size: cover;
+}
+
+.intro {
+ background-image: url(pics/1.jpg);
+}
+
+.kirjs {
+ background-image: url(pics/ava.gif);
+}
+
+.svg-60 {
+ background-image: url(pics/2.jpg);
+}
+
+.example {
+ background-image: url(pics/3.jpg);
+}
+
+.the-end {
+ background-image: url(pics/4.jpg);
+}
+
+.dog {
+ background-image: url(pics/5.gif);
+}
+
+.bg.intro h2 {
+ background: #000;
+ color: white;
+ margin-top: 50vh;
+ padding: 50px;
+ font-size: 10vh;
+ opacity: 0.7;
+}
+
+.bg.kirjs h2 {
+ background: #000;
+ color: white;
+ margin-top: 50vh;
+ padding: 10px;
+ font-size: 10vh;
+ opacity: 0.7;
+}
+
+.bg h2 {
+ background: #fff;
+ color: black;
+ margin-top: 50vh;
+ padding: 50px;
+ font-size: 10vh;
+ opacity: 0.7;
+}
+
+.btn-bar {
+ line-height: 3vw;
+}
+
+.btn-bar:hover .font-size {
+ display: block;
+ font-size: 4vw;
+}
+
+.btn-bar .font-size {
+ display: none;
+}
+
+.twitter {
+ color: #444;
+ font-size: 3vw;
+ margin: 2vw;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/svg.component.html b/codelab-master/apps/kirjs/src/app/modules/svg/svg.component.html
new file mode 100644
index 000000000..2b862216d
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/svg.component.html
@@ -0,0 +1,241 @@
+
+
+
+
+
+
+
+
+
+
+ Angular ❤️ SVG
+ @kirjs
+
+
+
+
+
+
+
+
What is SVG?
+
+ Scalable Vector Graphic Format
+ Can be edited with a text editor!
+ Every object is just an XML tag
+ Works with CSS
+ Plays well with angular templates!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Some cool stuff
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Now you're an SVG expert!
+ However SVG has a couple of edge cases
+
+
+
+
+
Sign up for my 80 hour workshop "Wait, SVG, LOL, Really?"
+
+
+
+
+
Let's check out some examples:
+
+
+
+
+
+
+
+
+
+
SVG attributes binding
+
+
+
+
+
+
+
Let's create a simple barchart
+
+
+
+
+
Custom SVG Elements
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/svg.component.ts b/codelab-master/apps/kirjs/src/app/modules/svg/svg.component.ts
new file mode 100644
index 000000000..c1c60e926
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/svg/svg.component.ts differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/svg.module.ts b/codelab-master/apps/kirjs/src/app/modules/svg/svg.module.ts
new file mode 100644
index 000000000..a916ff1af
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/svg.module.ts
@@ -0,0 +1,46 @@
+import { NgModule } from '@angular/core';
+
+import { RouterModule } from '@angular/router';
+import { SlidesRoutes } from '@ng360/slides';
+import { FeedbackModule } from '@codelab/feedback';
+import { SvgComponent } from './svg.component';
+
+import { FormsModule } from '@angular/forms';
+import { SvgDemoComponent } from './svg-demo/svg-demo.component';
+import { SvgPlaygroundComponent } from './svg-playground/svg-playground.component';
+
+import { TimerComponent } from './timer/timer.component';
+import { CommonModule } from '@angular/common';
+import { SvgTogetherComponent } from './svg-together/svg-together.component';
+import { MatButtonModule } from '@angular/material/button';
+import { SharedPipeModule } from '@codelab/utils/src/lib/pipes/pipes.module';
+import { SlidesModule } from '@ng360/slides';
+import { CodeDemoModule } from '@codelab/code-demos';
+import { SvgTogetherResultComponent } from './svg-together-result/svg-together-result.component';
+import { NewProgressBarModule } from '../ast/new-progress-bar/new-progress-bar.module';
+
+const routes = RouterModule.forChild(SlidesRoutes.get(SvgComponent));
+
+@NgModule({
+ imports: [
+ routes,
+ CommonModule,
+ FeedbackModule,
+ FormsModule,
+ MatButtonModule,
+ NewProgressBarModule,
+ SharedPipeModule,
+ SlidesModule,
+ CodeDemoModule
+ ],
+ declarations: [
+ SvgComponent,
+ SvgTogetherComponent,
+ SvgTogetherResultComponent,
+ SvgDemoComponent,
+ SvgPlaygroundComponent,
+ TimerComponent
+ ],
+ exports: [SvgComponent]
+})
+export class SvgModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/timer/timer.component.css b/codelab-master/apps/kirjs/src/app/modules/svg/timer/timer.component.css
new file mode 100644
index 000000000..1ee7514d1
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/timer/timer.component.css
@@ -0,0 +1,4 @@
+.timer-running {
+ color: #444;
+ font-size: 3vw;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/timer/timer.component.html b/codelab-master/apps/kirjs/src/app/modules/svg/timer/timer.component.html
new file mode 100644
index 000000000..6b16b6af5
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/timer/timer.component.html
@@ -0,0 +1,2 @@
+▶️
+ 0" class="timer-running">{{ time }}️
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/timer/timer.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/svg/timer/timer.component.spec.ts
new file mode 100644
index 000000000..b393c12a9
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/timer/timer.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { TimerComponent } from './timer.component';
+
+describe('TimerComponent', () => {
+ let component: TimerComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [TimerComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(TimerComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/svg/timer/timer.component.ts b/codelab-master/apps/kirjs/src/app/modules/svg/timer/timer.component.ts
new file mode 100644
index 000000000..1cb7ecfe6
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/svg/timer/timer.component.ts
@@ -0,0 +1,24 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-timer',
+ templateUrl: './timer.component.html',
+ styleUrls: ['./timer.component.css']
+})
+export class TimerComponent implements OnInit {
+ time = 0;
+
+ reset() {
+ this.time = 180;
+ }
+
+ constructor() {
+ window.setInterval(() => {
+ if (this.time > 0) {
+ this.time--;
+ }
+ }, 1000);
+ }
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/sync/sync.component.css b/codelab-master/apps/kirjs/src/app/modules/sync/sync.component.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/codelab-master/apps/kirjs/src/app/modules/sync/sync.component.html b/codelab-master/apps/kirjs/src/app/modules/sync/sync.component.html
new file mode 100644
index 000000000..704a8d028
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/sync/sync.component.html
@@ -0,0 +1 @@
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/sync/sync.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/sync/sync.component.spec.ts
new file mode 100644
index 000000000..78bc9b619
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/sync/sync.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SyncComponent } from './sync.component';
+
+describe('SyncComponent', () => {
+ let component: SyncComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [SyncComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(SyncComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/sync/sync.component.ts b/codelab-master/apps/kirjs/src/app/modules/sync/sync.component.ts
new file mode 100644
index 000000000..7bdefba51
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/sync/sync.component.ts
@@ -0,0 +1,12 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-sync',
+ templateUrl: './sync.component.html',
+ styleUrls: ['./sync.component.css']
+})
+export class SyncComponent implements OnInit {
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/sync/sync.module.ts b/codelab-master/apps/kirjs/src/app/modules/sync/sync.module.ts
new file mode 100644
index 000000000..baeb59888
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/sync/sync.module.ts
@@ -0,0 +1,25 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { SlidesModule, SlidesRoutes } from '@ng360/slides';
+import { RouterModule } from '@angular/router';
+import { SyncModule as SyncLibModule } from '@codelab/utils/src/lib/sync/sync.module';
+import { AngularFireAuthModule } from '@angular/fire/auth';
+import { SyncSessionsComponent } from '@codelab/utils/src/lib/sync/components/sync-sessions/sync-sessions.component';
+import { SyncComponent } from './sync.component';
+
+const routes = RouterModule.forChild([
+ { path: 'sessions', component: SyncSessionsComponent },
+ ...SlidesRoutes.get(SyncComponent)
+]);
+
+@NgModule({
+ declarations: [SyncComponent],
+ imports: [
+ CommonModule,
+ SlidesModule,
+ routes,
+ SyncLibModule,
+ AngularFireAuthModule
+ ]
+})
+export class SyncModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/test/test.component.css b/codelab-master/apps/kirjs/src/app/modules/test/test.component.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/codelab-master/apps/kirjs/src/app/modules/test/test.component.html b/codelab-master/apps/kirjs/src/app/modules/test/test.component.html
new file mode 100644
index 000000000..941f267e6
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/test/test.component.html
@@ -0,0 +1 @@
+test works!
diff --git a/codelab-master/apps/kirjs/src/app/modules/test/test.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/test/test.component.spec.ts
new file mode 100644
index 000000000..3ce2f9bb2
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/test/test.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { TestComponent } from './test.component';
+
+describe('TestComponent', () => {
+ let component: TestComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [TestComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(TestComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/test/test.component.ts b/codelab-master/apps/kirjs/src/app/modules/test/test.component.ts
new file mode 100644
index 000000000..2a28d9ff7
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/test/test.component.ts
@@ -0,0 +1,12 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'kirjs-test',
+ templateUrl: './test.component.html',
+ styleUrls: ['./test.component.css']
+})
+export class TestComponent implements OnInit {
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/test/test.module.ts b/codelab-master/apps/kirjs/src/app/modules/test/test.module.ts
new file mode 100644
index 000000000..73286878d
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/test/test.module.ts
@@ -0,0 +1,14 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { RouterModule } from '@angular/router';
+import { SlidesRoutes } from '@ng360/slides';
+import { TestComponent } from './test.component';
+
+const routes = RouterModule.forChild(SlidesRoutes.get(TestComponent));
+
+@NgModule({
+ imports: [CommonModule, routes],
+ declarations: [TestComponent],
+ entryComponents: [TestComponent]
+})
+export class TestModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/ca.module.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/ca.module.ts
new file mode 100644
index 000000000..21b603af8
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/ca.module.ts
@@ -0,0 +1,11 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { SingleCellComponent } from './single-cell/single-cell.component';
+import { SingleGridComponent } from './single-grid/single-grid.component';
+
+@NgModule({
+ declarations: [SingleCellComponent, SingleGridComponent],
+ exports: [SingleCellComponent, SingleGridComponent],
+ imports: [CommonModule]
+})
+export class CaModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/single-cell/single-cell.component.css b/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/single-cell/single-cell.component.css
new file mode 100644
index 000000000..c8b46c5ce
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/single-cell/single-cell.component.css
@@ -0,0 +1,43 @@
+:host {
+ display: flex;
+ height: 100%;
+ width: 100%;
+ align-items: center;
+ justify-content: space-around;
+}
+
+.cell {
+ width: 10vh;
+ height: 10vh;
+ border: 4px #444 solid;
+ animation: toColor 5s infinite linear, size 5s linear;
+}
+
+@keyframes size {
+ 0% {
+ width: 60vh;
+ height: 60vh;
+ }
+ 100% {
+ width: 10vh;
+ height: 10vh;
+ }
+}
+
+@keyframes toColor {
+ 0% {
+ background: #000;
+ }
+ 45% {
+ background: #000;
+ }
+ 50% {
+ background: #fff;
+ }
+ 95% {
+ background: #fff;
+ }
+ 100% {
+ background: #000;
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/single-cell/single-cell.component.html b/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/single-cell/single-cell.component.html
new file mode 100644
index 000000000..9c5b1d34a
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/single-cell/single-cell.component.html
@@ -0,0 +1 @@
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/single-cell/single-cell.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/single-cell/single-cell.component.spec.ts
new file mode 100644
index 000000000..847a44020
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/single-cell/single-cell.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SingleCellComponent } from './single-cell.component';
+
+describe('SingleCellComponent', () => {
+ let component: SingleCellComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [SingleCellComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(SingleCellComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/single-cell/single-cell.component.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/single-cell/single-cell.component.ts
new file mode 100644
index 000000000..882dbfb6b
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/single-cell/single-cell.component.ts
@@ -0,0 +1,14 @@
+import { Component, Input, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'slides-single-cell',
+ templateUrl: './single-cell.component.html',
+ styleUrls: ['./single-cell.component.css']
+})
+export class SingleCellComponent implements OnInit {
+ @Input() single = true;
+
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/single-grid/single-grid.component.css b/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/single-grid/single-grid.component.css
new file mode 100644
index 000000000..f369bb3c6
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/single-grid/single-grid.component.css
@@ -0,0 +1,52 @@
+:host {
+ display: flex;
+ height: 100%;
+ width: 100%;
+ align-items: center;
+ justify-content: center;
+}
+
+.cell {
+ width: 10vh;
+ height: 10vh;
+ animation: toColor 4s linear infinite;
+ /*animation: size 15s linear;*/
+}
+
+.row {
+ display: flex;
+}
+
+.central {
+ animation: none;
+ background: #000;
+}
+
+@keyframes size {
+ 0% {
+ width: 60vh;
+ height: 60vh;
+ }
+ 100% {
+ width: 10vh;
+ height: 10vh;
+ }
+}
+
+@keyframes toColor {
+ 0% {
+ background: #000;
+ }
+ 45% {
+ background: #000;
+ }
+ 50% {
+ background: #fff;
+ }
+ 95% {
+ background: #fff;
+ }
+ 100% {
+ background: #000;
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/single-grid/single-grid.component.html b/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/single-grid/single-grid.component.html
new file mode 100644
index 000000000..a3ecb19a5
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/single-grid/single-grid.component.html
@@ -0,0 +1,10 @@
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/single-grid/single-grid.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/single-grid/single-grid.component.spec.ts
new file mode 100644
index 000000000..b946dd61d
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/single-grid/single-grid.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SingleGridComponent } from './single-grid.component';
+
+describe('SingleGridComponent', () => {
+ let component: SingleGridComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [SingleGridComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(SingleGridComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/single-grid/single-grid.component.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/single-grid/single-grid.component.ts
new file mode 100644
index 000000000..d4283e428
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/ca/single-grid/single-grid.component.ts
@@ -0,0 +1,15 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'slides-single-grid',
+ templateUrl: './single-grid.component.html',
+ styleUrls: ['./single-grid.component.css']
+})
+export class SingleGridComponent implements OnInit {
+ readonly f = [...new Array(9)].map((a, i) => i);
+ readonly randomDelays = this.f.map(a => this.f.map(b => Math.random() * 5));
+
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/full-screen-runner/full-screen-runner.component.css b/codelab-master/apps/kirjs/src/app/modules/webassembly/full-screen-runner/full-screen-runner.component.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/full-screen-runner/full-screen-runner.component.html b/codelab-master/apps/kirjs/src/app/modules/webassembly/full-screen-runner/full-screen-runner.component.html
new file mode 100644
index 000000000..9b58302d5
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/full-screen-runner/full-screen-runner.component.html
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 90, 110, 184, 30
+
+
+
+
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/full-screen-runner/full-screen-runner.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/full-screen-runner/full-screen-runner.component.spec.ts
new file mode 100644
index 000000000..b54608e62
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/full-screen-runner/full-screen-runner.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { FullScreenRunnerComponent } from './full-screen-runner.component';
+
+describe('FullScreenRunnerComponent', () => {
+ let component: FullScreenRunnerComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [FullScreenRunnerComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(FullScreenRunnerComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/full-screen-runner/full-screen-runner.component.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/full-screen-runner/full-screen-runner.component.ts
new file mode 100644
index 000000000..765e5cea2
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/full-screen-runner/full-screen-runner.component.ts
@@ -0,0 +1,50 @@
+import { Component, Input, OnChanges, OnInit } from '@angular/core';
+import { extractExpressionByMatch } from '../utils';
+
+@Component({
+ selector: 'slides-full-screen-runner',
+ templateUrl: './full-screen-runner.component.html',
+ styleUrls: ['./full-screen-runner.component.css']
+})
+export class FullScreenRunnerComponent implements OnInit, OnChanges {
+ @Input() code: any;
+ cellSize = 10;
+ wat: string;
+ js: string;
+ width = 2000;
+ height = 1800;
+ rowSize = 100;
+ rule = 1;
+ steps = 100;
+
+ constructor() {}
+
+ ngOnInit() {}
+
+ ngOnChanges() {
+ this.prepare();
+ }
+
+ prepare() {
+ const expected = (256 + this.rule)
+ .toString(2)
+ .substr(1)
+ .split('')
+ .map(Number)
+ .reverse()
+ .map(n => (n ? ' $enable' : ' $disable'))
+ .join('\n');
+
+ this.wat = this.code.wat;
+ this.js = this.code.js;
+ this.js = this.js.replace(/size = \d+/, 'size = ' + this.cellSize);
+ this.js = this.js.replace(/steps: \d+/, 'steps: ' + this.steps);
+ this.js = this.js.replace(/rowSize: \d+/, 'rowSize: ' + this.rowSize);
+ const elem = extractExpressionByMatch(/\(elem/, this.wat);
+ const newElem = `(elem (i32.const 0)
+ ${expected}
+ )`;
+
+ this.wat = this.wat.replace(elem, newElem);
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/full-screen-runner/full-screen-runner.module.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/full-screen-runner/full-screen-runner.module.ts
new file mode 100644
index 000000000..24a2cdb64
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/full-screen-runner/full-screen-runner.module.ts
@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FullScreenRunnerComponent } from './full-screen-runner.component';
+import { WebassemblyRunnerModule } from '../webassembly-playground/webassembly-runner/webassembly-runner.module';
+import { MatInputModule } from '@angular/material/input';
+import { FormsModule } from '@angular/forms';
+import { CellularAutomationModule } from '../../cellular-automation/cellular-automation.module';
+
+@NgModule({
+ declarations: [FullScreenRunnerComponent],
+ exports: [FullScreenRunnerComponent],
+ imports: [
+ CommonModule,
+ WebassemblyRunnerModule,
+ MatInputModule,
+ FormsModule,
+ CellularAutomationModule
+ ]
+})
+export class FullScreenRunnerModule {}
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/monaco-wat.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/monaco-wat.ts
new file mode 100644
index 000000000..9db36b005
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/monaco-wat.ts
@@ -0,0 +1,1334 @@
+/* Copyright 2018 Mozilla Foundation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the 'Software'), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+declare const monaco;
+
+const languages = monaco.languages;
+
+const CompletionItemKind = languages.CompletionItemKind;
+const CompletionItemInsertTextRule = languages.CompletionItemInsertTextRule;
+type CompletionItem = typeof languages.CompletionItem;
+
+type IModel = any;
+type IPosition = any;
+type IRichLanguageConfiguration = any;
+
+let completionItems: CompletionItem[] = null;
+
+export function getWatCompletionItems() {
+ const keyword = CompletionItemKind.Keyword;
+ if (completionItems) {
+ return completionItems;
+ }
+ return (completionItems = [
+ { label: 'module', documentation: '', kind: keyword, insertText: 'module' },
+
+ {
+ label: 'func',
+ documentation: 'function declaration',
+ kind: keyword,
+ insertText: 'func'
+ },
+ {
+ label: 'param',
+ documentation: 'parameter',
+ kind: keyword,
+ insertText: { value: 'param ${1:identifier} ${2:type}' } as any
+ },
+
+ {
+ label: 'i32',
+ documentation: '32-bit integer',
+ kind: keyword,
+ insertText: 'i32'
+ },
+ {
+ label: 'i64',
+ documentation: '64-bit integer',
+ kind: keyword,
+ insertText: 'i64'
+ },
+ {
+ label: 'f32',
+ documentation: '32-bit floating point',
+ kind: keyword,
+ insertText: 'f32'
+ },
+ {
+ label: 'f64',
+ documentation: '64-bit floating point',
+ kind: keyword,
+ insertText: 'f64'
+ },
+ {
+ label: 'anyfunc',
+ documentation: 'function reference',
+ kind: keyword,
+ insertText: 'anyfunc'
+ },
+
+ {
+ label: 'i32.load8_s',
+ documentation: 'load 1 byte and sign-extend i8 to i32',
+ kind: keyword,
+ insertText: 'i32.load8_s'
+ },
+ {
+ label: 'i32.load8_u',
+ documentation: 'load 1 byte and zero-extend i8 to i32',
+ kind: keyword,
+ insertText: 'i32.load8_u'
+ },
+ {
+ label: 'i32.load16_s',
+ documentation: 'load 2 bytes and sign-extend i16 to i32',
+ kind: keyword,
+ insertText: 'i32.load16_s'
+ },
+ {
+ label: 'i32.load16_u',
+ documentation: 'load 2 bytes and zero-extend i16 to i32',
+ kind: keyword,
+ insertText: 'i32.load16_u'
+ },
+ {
+ label: 'i32.load',
+ documentation: 'load 4 bytes as i32',
+ kind: keyword,
+ insertText: 'i32.load'
+ },
+ {
+ label: 'i64.load8_s',
+ documentation: 'load 1 byte and sign-extend i8 to i64',
+ kind: keyword,
+ insertText: 'i64.load8_s'
+ },
+ {
+ label: 'i64.load8_u',
+ documentation: 'load 1 byte and zero-extend i8 to i64',
+ kind: keyword,
+ insertText: 'i64.load8_u'
+ },
+ {
+ label: 'i64.load16_s',
+ documentation: 'load 2 bytes and sign-extend i16 to i64',
+ kind: keyword,
+ insertText: 'i64.load16_s'
+ },
+ {
+ label: 'i64.load16_u',
+ documentation: 'load 2 bytes and zero-extend i16 to i64',
+ kind: keyword,
+ insertText: 'i64.load16_u'
+ },
+ {
+ label: 'i64.load32_s',
+ documentation: 'load 4 bytes and sign-extend i32 to i64',
+ kind: keyword,
+ insertText: 'i64.load32_s'
+ },
+ {
+ label: 'i64.load32_u',
+ documentation: 'load 4 bytes and zero-extend i32 to i64',
+ kind: keyword,
+ insertText: 'i64.load32_u'
+ },
+ {
+ label: 'i64.load',
+ documentation: 'load 8 bytes as i64',
+ kind: keyword,
+ insertText: 'i64.load'
+ },
+ {
+ label: 'f32.load',
+ documentation: 'load 4 bytes as f32',
+ kind: keyword,
+ insertText: 'f32.load'
+ },
+ {
+ label: 'f64.load',
+ documentation: 'load 8 bytes as f64',
+ kind: keyword,
+ insertText: 'f64.load'
+ },
+
+ {
+ label: 'i32.store8',
+ documentation: 'wrap i32 to i8 and store 1 byte',
+ kind: keyword,
+ insertText: 'i32.store8'
+ },
+ {
+ label: 'i32.store16',
+ documentation: 'wrap i32 to i16 and store 2 bytes',
+ kind: keyword,
+ insertText: 'i32.store16'
+ },
+ {
+ label: 'i32.store',
+ documentation: '(no conversion) store 4 bytes',
+ kind: keyword,
+ insertText: 'i32.store'
+ },
+ {
+ label: 'i64.store8',
+ documentation: 'wrap i64 to i8 and store 1 byte',
+ kind: keyword,
+ insertText: 'i64.store8'
+ },
+ {
+ label: 'i64.store16',
+ documentation: 'wrap i64 to i16 and store 2 bytes',
+ kind: keyword,
+ insertText: 'i64.store16'
+ },
+ {
+ label: 'i64.store32',
+ documentation: 'wrap i64 to i32 and store 4 bytes',
+ kind: keyword,
+ insertText: 'i64.store32'
+ },
+ {
+ label: 'i64.store',
+ documentation: '(no conversion) store 8 bytes',
+ kind: keyword,
+ insertText: 'i64.store'
+ },
+ {
+ label: 'f32.store',
+ documentation: '(no conversion) store 4 bytes',
+ kind: keyword,
+ insertText: 'f32.store'
+ },
+ {
+ label: 'f64.store',
+ documentation: '(no conversion) store 8 bytes',
+ kind: keyword,
+ insertText: 'f64.store'
+ },
+
+ {
+ label: 'get_local',
+ documentation: 'read the current value of a local variable',
+ kind: keyword,
+ insertText: 'get_local'
+ },
+ {
+ label: 'set_local',
+ documentation: 'set the current value of a local variable',
+ kind: keyword,
+ insertText: 'set_local'
+ },
+ {
+ label: 'tee_local',
+ documentation: 'like `set_local`, but also returns the set value',
+ kind: keyword,
+ insertText: 'tee_local'
+ },
+
+ {
+ label: 'get_global',
+ documentation: 'get the current value of a global variable',
+ kind: keyword,
+ insertText: 'get_global'
+ },
+ {
+ label: 'set_global',
+ documentation: 'set the current value of a global variable',
+ kind: keyword,
+ insertText: 'set_global'
+ },
+
+ {
+ label: 'nop',
+ documentation: 'no operation, no effect',
+ kind: keyword,
+ insertText: 'nop'
+ },
+ {
+ label: 'block',
+ documentation:
+ 'the beginning of a block construct, a sequence of instructions with a label at the end',
+ kind: keyword,
+ insertText: 'block'
+ },
+ {
+ label: 'loop',
+ documentation:
+ 'a block with a label at the beginning which may be used to form loops',
+ kind: keyword,
+ insertText: 'loop'
+ },
+ {
+ label: 'if',
+ documentation:
+ 'the beginning of an if construct with an implicit *then* block',
+ kind: keyword,
+ insertText: 'if'
+ },
+ {
+ label: 'else',
+ documentation: 'marks the else block of an if',
+ kind: keyword,
+ insertText: 'else'
+ },
+ {
+ label: 'br',
+ documentation: 'branch to a given label in an enclosing construct',
+ kind: keyword,
+ insertText: 'br'
+ },
+ {
+ label: 'br_if',
+ documentation:
+ 'conditionally branch to a given label in an enclosing construct',
+ kind: keyword,
+ insertText: 'br_if'
+ },
+ {
+ label: 'br_table',
+ documentation:
+ 'a jump table which jumps to a label in an enclosing construct',
+ kind: keyword,
+ insertText: 'br_table'
+ },
+ {
+ label: 'return',
+ documentation: 'return zero or more values from this function',
+ kind: keyword,
+ insertText: 'return'
+ },
+ {
+ label: 'end',
+ documentation:
+ 'an instruction that marks the end of a block, loop, if, or function',
+ kind: keyword,
+ insertText: 'end'
+ },
+
+ {
+ label: 'call',
+ documentation: 'call function directly',
+ kind: keyword,
+ insertText: 'call'
+ },
+ {
+ label: 'call_indirect',
+ documentation: 'call function indirectly',
+ kind: keyword,
+ insertText: 'call_indirect'
+ },
+
+ {
+ label: 'i64.const',
+ documentation: 'produce the value of an i64 immediate',
+ kind: keyword,
+ insertText: { value: 'i64.const ${1:constant}' }
+ },
+ {
+ label: 'i32.const',
+ documentation: 'produce the value of an i32 immediate',
+ kind: keyword,
+ insertText: { value: 'i32.const ${1:constant}' }
+ },
+ {
+ label: 'f32.const',
+ documentation: 'produce the value of an f32 immediate',
+ kind: keyword,
+ insertText: { value: 'f32.const ${1:constant}' }
+ },
+ {
+ label: 'f64.const',
+ documentation: 'produce the value of an f64 immediate',
+ kind: keyword,
+ insertText: { value: 'f64.const ${1:constant}' }
+ },
+
+ {
+ label: 'i32.add',
+ documentation: 'sign-agnostic addition',
+ kind: keyword,
+ insertText: 'i32.add'
+ },
+ {
+ label: 'i32.sub',
+ documentation: 'sign-agnostic subtraction',
+ kind: keyword,
+ insertText: 'i32.sub'
+ },
+ {
+ label: 'i32.mul',
+ documentation: 'sign-agnostic multiplication (lower 32-bits)',
+ kind: keyword,
+ insertText: 'i32.mul'
+ },
+ {
+ label: 'i32.div_s',
+ documentation: 'signed division (result is truncated toward zero)',
+ kind: keyword,
+ insertText: 'i32.div_s'
+ },
+ {
+ label: 'i32.div_u',
+ documentation:
+ 'unsigned division (result is [floored](https://en.wikipedia.org/wiki/Floor_and_ceiling_functions))',
+ kind: keyword,
+ insertText: 'i32.div_u'
+ },
+ {
+ label: 'i32.rem_s',
+ documentation: 'signed remainder (result has the sign of the dividend)',
+ kind: keyword,
+ insertText: 'i32.rem_s'
+ },
+ {
+ label: 'i32.rem_u',
+ documentation: 'unsigned remainder',
+ kind: keyword,
+ insertText: 'i32.rem_u'
+ },
+ {
+ label: 'i32.and',
+ documentation: 'sign-agnostic bitwise and',
+ kind: keyword,
+ insertText: 'i32.and'
+ },
+ {
+ label: 'i32.or',
+ documentation: 'sign-agnostic bitwise inclusive or',
+ kind: keyword,
+ insertText: 'i32.or'
+ },
+ {
+ label: 'i32.xor',
+ documentation: 'sign-agnostic bitwise exclusive or',
+ kind: keyword,
+ insertText: 'i32.xor'
+ },
+ {
+ label: 'i32.shl',
+ documentation: 'sign-agnostic shift left',
+ kind: keyword,
+ insertText: 'i32.shl'
+ },
+ {
+ label: 'i32.shr_u',
+ documentation: 'zero-replicating (logical) shift right',
+ kind: keyword,
+ insertText: 'i32.shr_u'
+ },
+ {
+ label: 'i32.shr_s',
+ documentation: 'sign-replicating (arithmetic) shift right',
+ kind: keyword,
+ insertText: 'i32.shr_s'
+ },
+ {
+ label: 'i32.rotl',
+ documentation: 'sign-agnostic rotate left',
+ kind: keyword,
+ insertText: 'i32.rotl'
+ },
+ {
+ label: 'i32.rotr',
+ documentation: 'sign-agnostic rotate right',
+ kind: keyword,
+ insertText: 'i32.rotr'
+ },
+ {
+ label: 'i32.eq',
+ documentation: 'sign-agnostic compare equal',
+ kind: keyword,
+ insertText: 'i32.eq'
+ },
+ {
+ label: 'i32.ne',
+ documentation: 'sign-agnostic compare unequal',
+ kind: keyword,
+ insertText: 'i32.ne'
+ },
+ {
+ label: 'i32.lt_s',
+ documentation: 'signed less than',
+ kind: keyword,
+ insertText: 'i32.lt_s'
+ },
+ {
+ label: 'i32.le_s',
+ documentation: 'signed less than or equal',
+ kind: keyword,
+ insertText: 'i32.le_s'
+ },
+ {
+ label: 'i32.lt_u',
+ documentation: 'unsigned less than',
+ kind: keyword,
+ insertText: 'i32.lt_u'
+ },
+ {
+ label: 'i32.le_u',
+ documentation: 'unsigned less than or equal',
+ kind: keyword,
+ insertText: 'i32.le_u'
+ },
+ {
+ label: 'i32.gt_s',
+ documentation: 'signed greater than',
+ kind: keyword,
+ insertText: 'i32.gt_s'
+ },
+ {
+ label: 'i32.ge_s',
+ documentation: 'signed greater than or equal',
+ kind: keyword,
+ insertText: 'i32.ge_s'
+ },
+ {
+ label: 'i32.gt_u',
+ documentation: 'unsigned greater than',
+ kind: keyword,
+ insertText: 'i32.gt_u'
+ },
+ {
+ label: 'i32.ge_u',
+ documentation: 'unsigned greater than or equal',
+ kind: keyword,
+ insertText: 'i32.ge_u'
+ },
+ {
+ label: 'i32.clz',
+ documentation:
+ 'sign-agnostic count leading zero bits (All zero bits are considered leading if the value is zero)',
+ kind: keyword,
+ insertText: 'i32.clz'
+ },
+ {
+ label: 'i32.ctz',
+ documentation:
+ 'sign-agnostic count trailing zero bits (All zero bits are considered trailing if the value is zero)',
+ kind: keyword,
+ insertText: 'i32.ctz'
+ },
+ {
+ label: 'i32.popcnt',
+ documentation: 'sign-agnostic count number of one bits',
+ kind: keyword,
+ insertText: 'i32.popcnt'
+ },
+ {
+ label: 'i32.eqz',
+ documentation:
+ 'compare equal to zero (return 1 if operand is zero, 0 otherwise)',
+ kind: keyword,
+ insertText: 'i32.eqz'
+ },
+
+ {
+ label: 'f32.add',
+ documentation: 'addition',
+ kind: keyword,
+ insertText: 'f32.add'
+ },
+ {
+ label: 'f32.sub',
+ documentation: 'subtraction',
+ kind: keyword,
+ insertText: 'f32.sub'
+ },
+ {
+ label: 'f32.mul',
+ documentation: 'multiplication',
+ kind: keyword,
+ insertText: 'f32.mul'
+ },
+ {
+ label: 'f32.div',
+ documentation: 'division',
+ kind: keyword,
+ insertText: 'f32.div'
+ },
+ {
+ label: 'f32.abs',
+ documentation: 'absolute value',
+ kind: keyword,
+ insertText: 'f32.abs'
+ },
+ {
+ label: 'f32.neg',
+ documentation: 'negation',
+ kind: keyword,
+ insertText: 'f32.neg'
+ },
+ {
+ label: 'f32.copysign',
+ documentation: 'copysign',
+ kind: keyword,
+ insertText: 'f32.copysign'
+ },
+ {
+ label: 'f32.ceil',
+ documentation: 'ceiling operator',
+ kind: keyword,
+ insertText: 'f32.ceil'
+ },
+ {
+ label: 'f32.floor',
+ documentation: 'floor operator',
+ kind: keyword,
+ insertText: 'f32.floor'
+ },
+ {
+ label: 'f32.trunc',
+ documentation: 'round to nearest integer towards zero',
+ kind: keyword,
+ insertText: 'f32.trunc'
+ },
+ {
+ label: 'f32.nearest',
+ documentation: 'round to nearest integer, ties to even',
+ kind: keyword,
+ insertText: 'f32.nearest'
+ },
+ {
+ label: 'f32.eq',
+ documentation: 'compare ordered and equal',
+ kind: keyword,
+ insertText: 'f32.eq'
+ },
+ {
+ label: 'f32.ne',
+ documentation: 'compare unordered or unequal',
+ kind: keyword,
+ insertText: 'f32.ne'
+ },
+ {
+ label: 'f32.lt',
+ documentation: 'compare ordered and less than',
+ kind: keyword,
+ insertText: 'f32.lt'
+ },
+ {
+ label: 'f32.le',
+ documentation: 'compare ordered and less than or equal',
+ kind: keyword,
+ insertText: 'f32.le'
+ },
+ {
+ label: 'f32.gt',
+ documentation: 'compare ordered and greater than',
+ kind: keyword,
+ insertText: 'f32.gt'
+ },
+ {
+ label: 'f32.ge',
+ documentation: 'compare ordered and greater than or equal',
+ kind: keyword,
+ insertText: 'f32.ge'
+ },
+ {
+ label: 'f32.sqrt',
+ documentation: 'square root',
+ kind: keyword,
+ insertText: 'f32.sqrt'
+ },
+ {
+ label: 'f32.min',
+ documentation:
+ 'minimum (binary operator); if either operand is NaN, returns NaN',
+ kind: keyword,
+ insertText: 'f32.min'
+ },
+ {
+ label: 'f32.max',
+ documentation:
+ 'maximum (binary operator); if either operand is NaN, returns NaN',
+ kind: keyword,
+ insertText: 'f32.max'
+ },
+
+ {
+ label: 'f64.add',
+ documentation: 'addition',
+ kind: keyword,
+ insertText: 'f64.add'
+ },
+ {
+ label: 'f64.sub',
+ documentation: 'subtraction',
+ kind: keyword,
+ insertText: 'f64.sub'
+ },
+ {
+ label: 'f64.mul',
+ documentation: 'multiplication',
+ kind: keyword,
+ insertText: 'f64.mul'
+ },
+ {
+ label: 'f64.div',
+ documentation: 'division',
+ kind: keyword,
+ insertText: 'f64.div'
+ },
+ {
+ label: 'f64.abs',
+ documentation: 'absolute value',
+ kind: keyword,
+ insertText: 'f64.abs'
+ },
+ {
+ label: 'f64.neg',
+ documentation: 'negation',
+ kind: keyword,
+ insertText: 'f64.neg'
+ },
+ {
+ label: 'f64.copysign',
+ documentation: 'copysign',
+ kind: keyword,
+ insertText: 'f64.copysign'
+ },
+ {
+ label: 'f64.ceil',
+ documentation: 'ceiling operator',
+ kind: keyword,
+ insertText: 'f64.ceil'
+ },
+ {
+ label: 'f64.floor',
+ documentation: 'floor operator',
+ kind: keyword,
+ insertText: 'f64.floor'
+ },
+ {
+ label: 'f64.trunc',
+ documentation: 'round to nearest integer towards zero',
+ kind: keyword,
+ insertText: 'f64.trunc'
+ },
+ {
+ label: 'f64.nearest',
+ documentation: 'round to nearest integer, ties to even',
+ kind: keyword,
+ insertText: 'f64.nearest'
+ },
+ {
+ label: 'f64.eq',
+ documentation: 'compare ordered and equal',
+ kind: keyword,
+ insertText: 'f64.eq'
+ },
+ {
+ label: 'f64.ne',
+ documentation: 'compare unordered or unequal',
+ kind: keyword,
+ insertText: 'f64.ne'
+ },
+ {
+ label: 'f64.lt',
+ documentation: 'compare ordered and less than',
+ kind: keyword,
+ insertText: 'f64.lt'
+ },
+ {
+ label: 'f64.le',
+ documentation: 'compare ordered and less than or equal',
+ kind: keyword,
+ insertText: 'f64.le'
+ },
+ {
+ label: 'f64.gt',
+ documentation: 'compare ordered and greater than',
+ kind: keyword,
+ insertText: 'f64.gt'
+ },
+ {
+ label: 'f64.ge',
+ documentation: 'compare ordered and greater than or equal',
+ kind: keyword,
+ insertText: 'f64.ge'
+ },
+ {
+ label: 'f64.sqrt',
+ documentation: 'square root',
+ kind: keyword,
+ insertText: 'f64.sqrt'
+ },
+ {
+ label: 'f64.min',
+ documentation:
+ 'minimum (binary operator); if either operand is NaN, returns NaN',
+ kind: keyword,
+ insertText: 'f64.min'
+ },
+ {
+ label: 'f64.max',
+ documentation:
+ 'maximum (binary operator); if either operand is NaN, returns NaN',
+ kind: keyword,
+ insertText: 'f64.max'
+ },
+
+ {
+ label: 'i32.wrap/i64',
+ documentation: 'wrap a 64-bit integer to a 32-bit integer',
+ kind: keyword,
+ insertText: 'i32.wrap/i64'
+ },
+ {
+ label: 'i32.trunc_s/f32',
+ documentation: 'truncate a 32-bit float to a signed 32-bit integer',
+ kind: keyword,
+ insertText: 'i32.trunc_s/f32'
+ },
+ {
+ label: 'i32.trunc_s/f64',
+ documentation: 'truncate a 64-bit float to a signed 32-bit integer',
+ kind: keyword,
+ insertText: 'i32.trunc_s/f64'
+ },
+ {
+ label: 'i32.trunc_u/f32',
+ documentation: 'truncate a 32-bit float to an unsigned 32-bit integer',
+ kind: keyword,
+ insertText: 'i32.trunc_u/f32'
+ },
+ {
+ label: 'i32.trunc_u/f64',
+ documentation: 'truncate a 64-bit float to an unsigned 32-bit integer',
+ kind: keyword,
+ insertText: 'i32.trunc_u/f64'
+ },
+ {
+ label: 'i32.reinterpret/f32',
+ documentation:
+ 'reinterpret the bits of a 32-bit float as a 32-bit integer',
+ kind: keyword,
+ insertText: 'i32.reinterpret/f32'
+ },
+ {
+ label: 'i64.extend_s/i32',
+ documentation: 'extend a signed 32-bit integer to a 64-bit integer',
+ kind: keyword,
+ insertText: 'i64.extend_s/i32'
+ },
+ {
+ label: 'i64.extend_u/i32',
+ documentation: 'extend an unsigned 32-bit integer to a 64-bit integer',
+ kind: keyword,
+ insertText: 'i64.extend_u/i32'
+ },
+ {
+ label: 'i64.trunc_s/f32',
+ documentation: 'truncate a 32-bit float to a signed 64-bit integer',
+ kind: keyword,
+ insertText: 'i64.trunc_s/f32'
+ },
+ {
+ label: 'i64.trunc_s/f64',
+ documentation: 'truncate a 64-bit float to a signed 64-bit integer',
+ kind: keyword,
+ insertText: 'i64.trunc_s/f64'
+ },
+ {
+ label: 'i64.trunc_u/f32',
+ documentation: 'truncate a 32-bit float to an unsigned 64-bit integer',
+ kind: keyword,
+ insertText: 'i64.trunc_u/f32'
+ },
+ {
+ label: 'i64.trunc_u/f64',
+ documentation: 'truncate a 64-bit float to an unsigned 64-bit integer',
+ kind: keyword,
+ insertText: 'i64.trunc_u/f64'
+ },
+ {
+ label: 'i64.reinterpret/f64',
+ documentation:
+ 'reinterpret the bits of a 64-bit float as a 64-bit integer',
+ kind: keyword,
+ insertText: 'i64.reinterpret/f64'
+ },
+ {
+ label: 'f32.demote/f64',
+ documentation: 'demote a 64-bit float to a 32-bit float',
+ kind: keyword,
+ insertText: 'f32.demote/f64'
+ },
+ {
+ label: 'f32.convert_s/i32',
+ documentation: 'convert a signed 32-bit integer to a 32-bit float',
+ kind: keyword,
+ insertText: 'f32.convert_s/i32'
+ },
+ {
+ label: 'f32.convert_s/i64',
+ documentation: 'convert a signed 64-bit integer to a 32-bit float',
+ kind: keyword,
+ insertText: 'f32.convert_s/i64'
+ },
+ {
+ label: 'f32.convert_u/i32',
+ documentation: 'convert an unsigned 32-bit integer to a 32-bit float',
+ kind: keyword,
+ insertText: 'f32.convert_u/i32'
+ },
+ {
+ label: 'f32.convert_u/i64',
+ documentation: 'convert an unsigned 64-bit integer to a 32-bit float',
+ kind: keyword,
+ insertText: 'f32.convert_u/i64'
+ },
+ {
+ label: 'f32.reinterpret/i32',
+ documentation:
+ 'reinterpret the bits of a 32-bit integer as a 32-bit float',
+ kind: keyword,
+ insertText: 'f32.reinterpret/i32'
+ },
+ {
+ label: 'f64.promote/f32',
+ documentation: 'promote a 32-bit float to a 64-bit float',
+ kind: keyword,
+ insertText: 'f64.promote/f32'
+ },
+ {
+ label: 'f64.convert_s/i32',
+ documentation: 'convert a signed 32-bit integer to a 64-bit float',
+ kind: keyword,
+ insertText: 'f64.convert_s/i32'
+ },
+ {
+ label: 'f64.convert_s/i64',
+ documentation: 'convert a signed 64-bit integer to a 64-bit float',
+ kind: keyword,
+ insertText: 'f64.convert_s/i64'
+ },
+ {
+ label: 'f64.convert_u/i32',
+ documentation: 'convert an unsigned 32-bit integer to a 64-bit float',
+ kind: keyword,
+ insertText: 'f64.convert_u/i32'
+ },
+ {
+ label: 'f64.convert_u/i64',
+ documentation: 'convert an unsigned 64-bit integer to a 64-bit float',
+ kind: keyword,
+ insertText: 'f64.convert_u/i64'
+ },
+ {
+ label: 'f64.reinterpret/i64',
+ documentation:
+ 'reinterpret the bits of a 64-bit integer as a 64-bit float',
+ kind: keyword,
+ insertText: 'f64.reinterpret/i64'
+ },
+
+ {
+ label: 'current_memory',
+ documentation: 'current memory size in 64k pages',
+ kind: keyword,
+ insertText: 'current_memory'
+ },
+ {
+ label: 'grow_memory',
+ documentation: 'grow memory size by the specified amount of 64k pages',
+ kind: keyword,
+ insertText: 'grow_memory'
+ }
+ ]);
+}
+
+const LanguageConfiguration: IRichLanguageConfiguration = {
+ // the default separators except `@$`
+ wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\'\,\.\<\>\/\?\s]+)/g,
+ comments: {
+ lineComment: ';;'
+ },
+ brackets: [
+ ['{', '}'],
+ ['[', ']'],
+ ['(', ')']
+ ],
+ autoClosingPairs: [
+ { open: '{', close: '}' },
+ { open: '[', close: ']' },
+ { open: '(', close: ')' },
+ { open: "'", close: "'" },
+ { open: "'", close: "'" }
+ ],
+ surroundingPairs: [
+ { open: '{', close: '}' },
+ { open: '[', close: ']' },
+ { open: '(', close: ')' },
+ { open: "'", close: "'" },
+ { open: "'", close: "'" },
+ { open: '<', close: '>' }
+ ]
+};
+
+const MonarchDefinitions = {
+ // Set defaultToken to invalid to see what you do not tokenize yet
+ // defaultToken: 'invalid',
+
+ keywords: [
+ 'module',
+ 'table',
+ 'memory',
+ 'export',
+ 'import',
+ 'func',
+ 'result',
+ 'offset',
+ 'anyfunc',
+ 'type',
+ 'data',
+ 'start',
+ 'element',
+ 'global',
+ 'local',
+ 'mut',
+ 'param',
+ 'result',
+
+ 'i32.load8_s',
+ 'i32.load8_u',
+ 'i32.load16_s',
+ 'i32.load16_u',
+ 'i32.load',
+ 'i64.load8_s',
+ 'i64.load8_u',
+ 'i64.load16_s',
+ 'i64.load16_u',
+ 'i64.load32_s',
+ 'i64.load32_u',
+ 'i64.load',
+ 'f32.load',
+ 'f64.load',
+
+ 'i32.store8',
+ 'i32.store16',
+ 'i32.store',
+ 'i64.store8',
+ 'i64.store16',
+ 'i64.store32',
+ 'i64.store',
+ 'f32.store',
+ 'f64.store',
+
+ 'i32.const',
+ 'i64.const',
+ 'f32.const',
+ 'f64.const',
+
+ 'i32.add',
+ 'i32.sub',
+ 'i32.mul',
+ 'i32.div_s',
+ 'i32.div_u',
+ 'i32.rem_s',
+ 'i32.rem_u',
+ 'i32.and',
+ 'i32.or',
+ 'i32.xor',
+ 'i32.shl',
+ 'i32.shr_u',
+ 'i32.shr_s',
+ 'i32.rotl',
+ 'i32.rotr',
+ 'i32.eq',
+ 'i32.ne',
+ 'i32.lt_s',
+ 'i32.le_s',
+ 'i32.lt_u',
+ 'i32.le_u',
+ 'i32.gt_s',
+ 'i32.ge_s',
+ 'i32.gt_u',
+ 'i32.ge_u',
+ 'i32.clz',
+ 'i32.ctz',
+ 'i32.popcnt',
+ 'i32.eqz',
+
+ 'f32.add',
+ 'f32.sub',
+ 'f32.mul',
+ 'f32.div',
+ 'f32.abs',
+ 'f32.neg',
+ 'f32.copysign',
+ 'f32.ceil',
+ 'f32.floor',
+ 'f32.trunc',
+ 'f32.nearest',
+ 'f32.eq',
+ 'f32.ne',
+ 'f32.lt',
+ 'f32.le',
+ 'f32.gt',
+ 'f32.ge',
+ 'f32.sqrt',
+ 'f32.min',
+ 'f32.max',
+
+ 'f64.add',
+ 'f64.sub',
+ 'f64.mul',
+ 'f64.div',
+ 'f64.abs',
+ 'f64.neg',
+ 'f64.copysign',
+ 'f64.ceil',
+ 'f64.floor',
+ 'f64.trunc',
+ 'f64.nearest',
+ 'f64.eq',
+ 'f64.ne',
+ 'f64.lt',
+ 'f64.le',
+ 'f64.gt',
+ 'f64.ge',
+ 'f64.sqrt',
+ 'f64.min',
+ 'f64.max',
+
+ 'i32.wrap/i64',
+ 'i32.trunc_s/f32',
+ 'i32.trunc_s/f64',
+ 'i32.trunc_u/f32',
+ 'i32.trunc_u/f64',
+ 'i32.reinterpret/f32',
+ 'i64.extend_s/i32',
+ 'i64.extend_u/i32',
+ 'i64.trunc_s/f32',
+ 'i64.trunc_s/f64',
+ 'i64.trunc_u/f32',
+ 'i64.trunc_u/f64',
+ 'i64.reinterpret/f64',
+ 'f32.demote/f64',
+ 'f32.convert_s/i32',
+ 'f32.convert_s/i64',
+ 'f32.convert_u/i32',
+ 'f32.convert_u/i64',
+ 'f32.reinterpret/i32',
+ 'f64.promote/f32',
+ 'f64.convert_s/i32',
+ 'f64.convert_s/i64',
+ 'f64.convert_u/i32',
+ 'f64.convert_u/i64',
+ 'f64.reinterpret/i64',
+
+ 'local.get',
+ 'local.set',
+ 'local.tee',
+ 'global.get',
+ 'global.set',
+ 'global.tee',
+ 'get_local',
+ 'set_local',
+ 'tee_local',
+ 'get_global',
+ 'set_global',
+
+ 'current_memory',
+ 'grow_memory'
+ ],
+
+ typeKeywords: ['i32', 'i64', 'f32', 'f64', 'anyfunc'],
+
+ operators: [] as any,
+
+ brackets: [
+ ['(', ')', 'bracket.parenthesis'],
+ ['{', '}', 'bracket.curly'],
+ ['[', ']', 'bracket.square']
+ ],
+
+ // we include these common regular expressions
+ symbols: /[=> x.label === word;
+ const item = watCompletionItems.find(predicate);
+ if (!item) {
+ return;
+ }
+ return {
+ range: new monaco.Range(
+ position.lineNumber,
+ index + 1,
+ position.lineNumber,
+ index + 1 + word.length
+ ),
+ contents: [
+ '**DETAILS**',
+ { language: 'html', value: item.documentation }
+ ]
+ };
+ }
+ }
+};
+
+monaco.languages.onLanguage('wat', () => {
+ monaco.languages.setMonarchTokensProvider(
+ 'wat',
+ Wat.MonarchDefinitions as any
+ );
+ monaco.languages.setLanguageConfiguration('wat', Wat.LanguageConfiguration);
+ monaco.languages.registerCompletionItemProvider(
+ 'wat',
+ Wat.CompletionItemProvider
+ );
+ monaco.languages.registerHoverProvider('wat', Wat.HoverProvider as any);
+});
+monaco.languages.register({
+ id: 'wat'
+});
+
+monaco.languages.registerCompletionItemProvider(
+ 'wat',
+ {
+ provideCompletionItems: function() {
+ return {
+ suggestions: [
+ {
+ label: 'const',
+ kind: monaco.languages.CompletionItemKind.Function,
+ documentation: 'i32',
+ insertText: 'i32.const ${1:value}',
+ insertTextRules: CompletionItemInsertTextRule.InsertAsSnippet
+ },
+ {
+ label: 'function',
+ kind: monaco.languages.CompletionItemKind.Keyword,
+ documentation: 'i32',
+ insertText: '(func $${1:name} ${2:params} (result i32)\n ${3}\n)',
+ insertTextRules: CompletionItemInsertTextRule.InsertAsSnippet
+ },
+ {
+ label: 'add',
+ kind: monaco.languages.CompletionItemKind.Keyword,
+ documentation: 'i32',
+ insertText: 'i32.add',
+ insertTextRules: CompletionItemInsertTextRule.InsertAsSnippet
+ },
+ {
+ label: 'param',
+ kind: monaco.languages.CompletionItemKind.Keyword,
+ documentation: 'i32',
+ insertText: '(param $${1:name} i32) ',
+ insertTextRules: CompletionItemInsertTextRule.InsertAsSnippet
+ },
+ {
+ label: 'local.get',
+ kind: monaco.languages.CompletionItemKind.Keyword,
+ documentation: 'i32',
+ insertText: 'local.get $${1:name}',
+ insertTextRules: CompletionItemInsertTextRule.InsertAsSnippet
+ },
+ {
+ label: 'global.get',
+ kind: monaco.languages.CompletionItemKind.Keyword,
+ documentation: 'i32',
+ insertText: 'global.get $${1:name}',
+ insertTextRules: CompletionItemInsertTextRule.InsertAsSnippet
+ }
+ ]
+ };
+ }
+ },
+ '('
+);
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/30-2.png b/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/30-2.png
new file mode 100644
index 000000000..d554e82a2
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/30-2.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/30.png b/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/30.png
new file mode 100644
index 000000000..0765ebd75
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/30.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/JohnvonNeumann.gif b/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/JohnvonNeumann.gif
new file mode 100644
index 000000000..9c0f1cfd8
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/JohnvonNeumann.gif differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/feynman.png b/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/feynman.png
new file mode 100644
index 000000000..6d5269085
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/feynman.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/joking.jpg b/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/joking.jpg
new file mode 100644
index 000000000..e99c3ee8c
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/joking.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/kirjs.png b/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/kirjs.png
new file mode 100644
index 000000000..4e623fbc3
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/kirjs.png differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/milica.jpg b/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/milica.jpg
new file mode 100644
index 000000000..ab180a8e6
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/milica.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/nks.jpg b/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/nks.jpg
new file mode 100644
index 000000000..e7c9bf837
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/nks.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/wolfram.jpg b/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/wolfram.jpg
new file mode 100644
index 000000000..f6e5de42f
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/webassembly/pics/wolfram.jpg differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/samples/answer.wat b/codelab-master/apps/kirjs/src/app/modules/webassembly/samples/answer.wat
new file mode 100644
index 000000000..b05bab8a6
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/samples/answer.wat
@@ -0,0 +1,190 @@
+(module
+ (import "config" "rowSize" (global $rowSize i32))
+ (memory 1)
+ (export "memory" (memory 0))
+
+ (table 8 anyfunc)
+
+ (func $enable (result i32)
+ (i32.const 1)
+ )
+
+ (func $disable (result i32)
+ (i32.const 0)
+ )
+
+ (elem (i32.const 0)
+ $enable ;; 000
+ $enable ;; 001
+ $enable ;; 010
+ $enable ;; 011
+ $enable ;; 100
+ $enable ;; 101
+ $enable ;; 110
+ $enable ;; 111
+ )
+
+ (type $return_i32 (func (result i32)))
+
+
+ (global $step (export "step") (mut i32) (i32.const 1))
+
+
+
+
+ (func $rotate (param $x i32) (result i32)
+ local.get $x
+ global.get $rowSize
+ i32.add
+
+ global.get $rowSize
+
+ i32.rem_s
+ )
+
+ (func $getIndex (param $x i32) (param $y i32) (result i32)
+ local.get $x
+
+ local.get $y
+ global.get $rowSize
+ i32.mul
+
+ i32.add
+ )
+
+ (func $loadCell (param $x i32) (param $y i32) (result i32)
+ (local.get $x)
+ call $rotate
+
+ (local.get $y)
+
+ call $getIndex
+ i32.const 4
+ i32.mul
+
+ i32.load
+ )
+
+ (func $storeCell (param $x i32) (param $value i32)
+ local.get $x
+ global.get $step
+ call $getIndex
+
+ i32.const 4
+ i32.mul
+
+ local.get $value
+
+ i32.store
+ )
+
+
+
+ (func $shift (param $a i32) (param $b i32) (param $c i32) (result i32)
+ local.get $a
+ (i32.const 4)
+ i32.mul
+
+ local.get $b
+ (i32.const 2)
+ i32.mul
+
+ local.get $c
+
+ i32.add
+ i32.add
+ )
+
+
+
+ (func $loadPreviousCell (param $x i32) (result i32)
+ local.get $x
+
+ global.get $step
+ (i32.const 1)
+ i32.sub
+
+ call $loadCell
+ )
+
+
+
+ (func $getCellScore (param $x i32) (result i32)
+ local.get $x
+ i32.const 1
+ i32.sub
+ call $loadPreviousCell
+
+ local.get $x
+ call $loadPreviousCell
+
+ local.get $x
+ i32.const 1
+ i32.add
+ call $loadPreviousCell
+
+ call $shift
+ )
+
+
+
+ (func $evolveCell (param $x i32)
+ local.get $x
+
+
+ local.get $x
+ call $getCellScore
+ call_indirect (type $return_i32)
+
+ call $storeCell
+ )
+
+
+
+ (func $evolveRow (local $i i32)
+ block
+ loop
+ local.get $i
+ call $evolveCell
+
+ local.get $i
+ (i32.const 1)
+ i32.add
+ local.tee $i
+
+ global.get $rowSize
+ i32.eq
+
+ br_if 1
+ br 0
+ end
+ end
+ )
+
+
+
+ (func $evolve (export "evolve") (param $steps i32) (local $i i32)
+ block
+ loop
+ call $evolveRow
+ global.get $step
+ i32.const 1
+ i32.add
+ global.set $step
+
+ local.get $i
+ (i32.const 1)
+ i32.add
+ tee_local $i
+
+
+ local.get $steps
+ i32.eq
+
+ br_if 1
+ br 0
+ end
+ end
+
+ )
+)
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/samples/base.js b/codelab-master/apps/kirjs/src/app/modules/webassembly/samples/base.js
new file mode 100644
index 000000000..18d2f0d45
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/samples/base.js
@@ -0,0 +1,31 @@
+const size = 80;
+
+const config = {
+ rowSize: 5,
+ steps: 100,
+ log: console.log
+};
+
+function drawOnCanvas(canvas, arr) {
+ const context = canvas.getContext('2d');
+
+ for (let i = 0; i < arr.length; i++) {
+ const x = i % config.rowSize;
+ const y = Math.floor(i / config.rowSize);
+
+ context.fillStyle = arr[i] ? 'lime' : '#444';
+
+ context.fillRect(x * size, y * size, size - 1, size - 1);
+ }
+}
+
+async function run(code, canvas) {
+ const result = await WebAssembly.instantiate(code, { config });
+
+ let memory = new Uint32Array(result.instance.exports.memory.buffer);
+ memory[Math.round(config.rowSize / 2)] = 1;
+
+ const r = result.instance.exports.evolve(config.steps);
+ drawOnCanvas(canvas, memory);
+ return r;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/samples/base.wat b/codelab-master/apps/kirjs/src/app/modules/webassembly/samples/base.wat
new file mode 100644
index 000000000..7cc2e296c
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/samples/base.wat
@@ -0,0 +1,3 @@
+(module
+
+)
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/samples/old.wat b/codelab-master/apps/kirjs/src/app/modules/webassembly/samples/old.wat
new file mode 100644
index 000000000..90da30a3f
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/samples/old.wat
@@ -0,0 +1,153 @@
+ (module
+ (import "config" "rowSize" (global $rowSize i32))
+ (import "config" "log" (func $log (param i32)))
+ (type $return_i32 (func (result i32)))
+ (memory 1)
+ (export "memory" (memory 0))
+
+ (table 8 funcref)
+ (elem (i32.const 0)
+ $remove ;; 000
+ $remove ;; 001
+ $create ;; 010
+ $create ;; 011
+ $create ;; 100
+ $create ;; 101
+ $remove ;; 110
+ $remove ;; 111
+ )
+
+ (func $create (result i32)
+ i32.const 1)
+ (func $remove (result i32)
+ i32.const 0)
+
+ (global $step (export "step") (mut i32) (i32.const 1))
+
+ (func $getIndex (param $x i32) (param $y i32) (result i32)
+ (i32.mul
+ (i32.const 4)
+ (i32.add
+ (local.get $x)
+ (i32.mul
+ (local.get $y)
+ (global.get $rowSize))))
+ )
+
+ (func $getCurrentIndex (param $x i32) (result i32)
+ (call $getIndex (local.get $x) (global.get $step))
+ )
+
+ (func $getPreviousIndex (param $x i32) (result i32)
+ (call $getIndex
+ (local.get $x)
+ (i32.sub
+ (global.get $step)
+ (i32.const 1)))
+ )
+
+ (func $rotate (param $x i32) (result i32)
+ (i32.rem_s
+ (i32.add
+ (global.get $rowSize)
+ (local.get $x))
+ (global.get $rowSize)
+ )
+ )
+
+ (func $shift (param $a i32) (param $b i32) (param $c i32) (result i32)
+ (local.get $c)
+
+ (local.get $b)
+ (i32.const 1)
+ i32.shl
+ i32.add
+
+ (local.get $a)
+ (i32.const 2)
+ i32.shl
+ i32.add
+ )
+
+ (func $calcNextState (param $x i32) (result i32)
+ local.get $x
+ call $getCellScore
+ call_indirect (type $return_i32)
+ )
+
+ (func $getCellScore (param $x i32) (result i32) (local $a i32)
+ local.get $x
+ i32.const 1
+ i32.sub
+ call $rotate
+ call $getPreviousIndex
+ i32.load
+
+
+ local.get $x
+ call $rotate
+ call $getPreviousIndex
+ i32.load
+
+ local.get $x
+ i32.const 1
+ i32.add
+ call $rotate
+ call $getPreviousIndex
+ i32.load
+
+ call $shift
+ )
+
+
+
+ (func $evolve (param $steps i32) (local $index i32)
+ block
+ loop
+ (call $evolveSingle)
+
+ ;; $index++
+ local.get $index
+ i32.const 1
+ i32.add
+ local.tee $index
+
+ (br_if 1 (i32.eq (local.get $steps) (local.get $index)))
+ drop
+ br 0
+ end
+ end
+ )
+
+ (func $evolveSingle (result i32) (local $index i32)
+ block
+ loop
+ ;; color up the cell
+ local.get $index
+ call $getCurrentIndex
+ local.get $index
+ call $calcNextState
+
+ i32.store
+
+ ;; $index++
+ local.get $index
+ i32.const 1
+ i32.add
+ local.tee $index
+
+ (br_if 1 (i32.eq (global.get $rowSize) (local.get $index)))
+ drop
+ br 0
+ end
+ end
+
+ global.get $step
+ i32.const 1
+ i32.add
+ global.set $step
+
+ local.get $index
+ )
+ (export "evolve" (func $evolve))
+)
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/add-tests.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/add-tests.ts
new file mode 100644
index 000000000..697025f7a
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/add-tests.ts
@@ -0,0 +1,18 @@
+export const addTests = [
+ {
+ args: [0, 0],
+ output: 0
+ },
+ {
+ args: [1, 0],
+ output: 1
+ },
+ {
+ args: [1, 1],
+ output: 2
+ },
+ {
+ args: [17, 25],
+ output: 42
+ }
+];
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/common.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/common.ts
new file mode 100644
index 000000000..77cb562ec
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/common.ts
@@ -0,0 +1,31 @@
+export const red = '#ff3f00';
+export const defaultRowSize = 5;
+
+export function colorMatchesExpected(a, i, c, test) {
+ return test.actualMemory[i] === test.expectedMemory[i] ? '#ddd' : red;
+}
+
+export function outputCoordinates(config) {
+ return [
+ {
+ y: -1,
+ x: config.args[0],
+ color: 'yellow',
+ text: config.args[0]
+ },
+
+ {
+ x: -1,
+ y: config.args[1],
+ color: 'yellow',
+ text: config.args[1]
+ },
+
+ {
+ x: config.args[0],
+ y: config.args[1],
+ color: 'lime',
+ text: config.output
+ }
+ ];
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/disable-tests.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/disable-tests.ts
new file mode 100644
index 000000000..d697e895e
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/disable-tests.ts
@@ -0,0 +1,6 @@
+export const disableTests = [
+ {
+ args: [],
+ output: 0
+ }
+];
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/enable-tests.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/enable-tests.ts
new file mode 100644
index 000000000..6e5c29189
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/enable-tests.ts
@@ -0,0 +1,6 @@
+export const enableTests = [
+ {
+ args: [],
+ output: 1
+ }
+];
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/evolve-cell.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/evolve-cell.ts
new file mode 100644
index 000000000..b570243ed
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/evolve-cell.ts
@@ -0,0 +1,68 @@
+import { colorMatchesExpected } from './common';
+
+const rowSize = 3;
+
+const viz = {
+ type: 'evolve',
+ rowSize,
+ text: a => a,
+ memory: test => test.actualMemory,
+ color: colorMatchesExpected
+};
+
+export const evolveCellTests = [
+ {
+ args: [0],
+ memory: [0, 0, 0, 0, 0, 0],
+ table: [
+ 'enable',
+ 'enable',
+ 'enable',
+ 'enable',
+ 'enable',
+ 'enable',
+ 'enable',
+ 'enable'
+ ],
+ expectedMemory: [0, 0, 0, 1, 0, 0],
+ imports: { config: { step: 1, rowSize: 3 } },
+ viz: {
+ ...viz,
+ rule: 0
+ }
+ },
+ {
+ args: [2],
+ memory: [0, 0, 0, 0, 0, 0],
+ table: [
+ 'enable',
+ 'enable',
+ 'enable',
+ 'enable',
+ 'enable',
+ 'enable',
+ 'enable',
+ 'enable'
+ ],
+ expectedMemory: [0, 0, 0, 0, 0, 1],
+ imports: { config: { step: 1, rowSize: 3 } },
+ viz
+ },
+ {
+ args: [2],
+ memory: [1, 1, 1, 1, 1, 1],
+ table: [
+ 'disable',
+ 'disable',
+ 'disable',
+ 'disable',
+ 'disable',
+ 'disable',
+ 'disable',
+ 'disable'
+ ],
+ expectedMemory: [1, 1, 1, 1, 1, 0],
+ imports: { config: { step: 1, rowSize: 3 } },
+ viz
+ }
+];
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/evolve-row.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/evolve-row.ts
new file mode 100644
index 000000000..48ad5850f
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/evolve-row.ts
@@ -0,0 +1,48 @@
+import { colorMatchesExpected } from './common';
+
+const rowSize = 3;
+
+const viz = {
+ type: 'evolve',
+ rowSize,
+ text: a => a,
+ memory: test => test.actualMemory,
+ color: colorMatchesExpected
+};
+
+export const evolveRowTests = [
+ {
+ args: [],
+ memory: [0, 0, 0, 0, 0, 0],
+ table: [
+ 'enable',
+ 'enable',
+ 'enable',
+ 'enable',
+ 'enable',
+ 'enable',
+ 'enable',
+ 'enable'
+ ],
+ expectedMemory: [0, 0, 0, 1, 1, 1],
+ imports: { config: { step: 1, rowSize: 3 } },
+ viz
+ },
+ {
+ args: [2],
+ memory: [1, 1, 1, 1, 1, 1],
+ table: [
+ 'disable',
+ 'disable',
+ 'disable',
+ 'disable',
+ 'disable',
+ 'disable',
+ 'disable',
+ 'disable'
+ ],
+ expectedMemory: [1, 1, 1, 0, 0, 0],
+ imports: { config: { step: 1, rowSize: 3 } },
+ viz
+ }
+];
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/evolve.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/evolve.ts
new file mode 100644
index 000000000..dfccb109d
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/evolve.ts
@@ -0,0 +1,29 @@
+import { colorMatchesExpected, defaultRowSize } from './common';
+
+const viz = {
+ type: 'evolve',
+ rowSize: defaultRowSize,
+ text: a => a,
+ memory: test => test.actualMemory,
+ color: colorMatchesExpected
+};
+
+export const evolveTests = [
+ {
+ args: [1],
+ memory: [0, 0, 0, 1, 0],
+ table: [
+ 'enable',
+ 'enable',
+ 'enable',
+ 'enable',
+ 'enable',
+ 'enable',
+ 'enable',
+ 'enable'
+ ],
+ expectedMemory: [0, 0, 0, 1, 0, 1, 1, 1, 1, 1],
+ imports: { config: { step: 1, rowSize: defaultRowSize } },
+ viz
+ }
+];
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/get-cell-score.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/get-cell-score.ts
new file mode 100644
index 000000000..a5f536ecf
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/get-cell-score.ts
@@ -0,0 +1,20 @@
+export const getCellScoreTests = [
+ {
+ args: [1],
+ memory: [0, 0, 1],
+ output: 0b001,
+ imports: { config: { rowSize: 3, step: 1 } }
+ },
+ {
+ args: [2],
+ memory: [1, 0, 0],
+ output: 0b001,
+ imports: { config: { rowSize: 3, step: 1 } }
+ },
+ {
+ args: [1],
+ memory: [1, 1, 0],
+ output: 0b110,
+ imports: { config: { rowSize: 3, step: 1 } }
+ }
+];
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/get-index.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/get-index.ts
new file mode 100644
index 000000000..16317f1fe
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/get-index.ts
@@ -0,0 +1,41 @@
+import { outputCoordinates } from './common';
+
+const rowSize = 5;
+
+const viz = {
+ rowSize,
+ text: (a, i) => i,
+ extras: outputCoordinates
+};
+export const getIndex = [
+ {
+ args: [0, 0],
+ imports: { config: { rowSize: rowSize } },
+ output: 0,
+ viz
+ },
+ {
+ args: [1, 0],
+ imports: { config: { rowSize: rowSize } },
+ output: 1,
+ viz
+ },
+ {
+ args: [0, 1],
+ imports: { config: { rowSize: rowSize } },
+ output: rowSize,
+ viz
+ },
+ {
+ args: [0, 1],
+ imports: { config: { rowSize: 4 } },
+ output: 4,
+ viz
+ },
+ {
+ args: [3, 3],
+ imports: { config: { rowSize: 4 } },
+ output: 15,
+ viz
+ }
+];
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/load-cell.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/load-cell.ts
new file mode 100644
index 000000000..175049f06
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/load-cell.ts
@@ -0,0 +1,53 @@
+const rowSize = 2;
+
+export const memoryRepViz = {
+ rowSize: rowSize * 4,
+ text: (a, i, c, test) => {
+ return i % 4 === 0 ? test.memory[i / 4] : '';
+ },
+ color: (a, i, o, test) => {
+ const c = (test.args[1] * rowSize + test.args[0]) * 4;
+ if (i >= c && i < c + 4) {
+ return 'lime';
+ }
+ return Math.floor((i / 4) % 2) === 0 ? '#ddd' : '#999';
+ }
+};
+
+export const loadCellTests = [
+ {
+ args: [0, 0],
+ memory: [0, 0, 0],
+ output: 0,
+ imports: { config: { rowSize } },
+ viz: memoryRepViz
+ },
+ {
+ args: [0, 0],
+ memory: [1, 0, 0],
+ output: 1,
+ imports: { config: { rowSize } },
+ viz: memoryRepViz
+ },
+ {
+ args: [1, 0],
+ memory: [1, 1, 0, 0],
+ output: 1,
+ imports: { config: { rowSize } },
+ viz: memoryRepViz
+ },
+ {
+ args: [0, 1],
+ memory: [1, 0, 1, 0],
+ viz: memoryRepViz,
+ output: 1,
+ imports: { config: { rowSize } }
+ },
+ {
+ args: [1, 1],
+ memory: [1, 0, 0, 0],
+ output: 0,
+ viz: memoryRepViz,
+ imports: { config: { rowSize } }
+ }
+];
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/load-previous-cell.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/load-previous-cell.ts
new file mode 100644
index 000000000..5944bc37c
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/load-previous-cell.ts
@@ -0,0 +1,32 @@
+export const loadPreviousCellTests = [
+ {
+ args: [0],
+ memory: [0, 0, 0],
+ output: 0,
+ imports: { config: { step: 1, rowSize: 3 } }
+ },
+ {
+ args: [0],
+ memory: [1, 0, 0],
+ output: 1,
+ imports: { config: { step: 1, rowSize: 3 } }
+ },
+ {
+ args: [2],
+ memory: [1, 0, 1],
+ output: 1,
+ imports: { config: { step: 1, rowSize: 3 } }
+ },
+ {
+ args: [2],
+ memory: [1, 0, 1, 1, 0, 1],
+ output: 1,
+ imports: { config: { step: 2, rowSize: 3 } }
+ },
+ {
+ args: [2],
+ memory: [1, 0, 1, 1, 0, 0],
+ output: 0,
+ imports: { config: { step: 2, rowSize: 3 } }
+ }
+];
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/rotate.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/rotate.ts
new file mode 100644
index 000000000..57ad50f7f
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/rotate.ts
@@ -0,0 +1,145 @@
+const rowSize = 5;
+const longFowSize = 4;
+const yellow = {
+ color: 'yellow',
+ text: 'Y'
+};
+
+const lime = {
+ color: 'lime',
+ text: 'G'
+};
+
+const red = {
+ color: 'red',
+ text: 'R'
+};
+
+export const rotate = [
+ {
+ args: [0, rowSize],
+ imports: { config: { rowSize } },
+ output: 0,
+ viz: {
+ rowSize,
+ extras: [
+ {
+ ...lime,
+ x: 0,
+ y: 0
+ },
+ {
+ ...yellow,
+ x: 0,
+ y: 1
+ }
+ ]
+ }
+ },
+ {
+ args: [rowSize, rowSize],
+ imports: { config: { rowSize } },
+ output: 0,
+ viz: {
+ rowSize,
+ extras: [
+ {
+ ...red,
+ x: rowSize,
+ y: 0
+ },
+ {
+ ...lime,
+ x: 0,
+ y: 0
+ },
+ {
+ ...lime,
+ x: rowSize - 2,
+ y: 0
+ },
+ {
+ ...lime,
+ x: rowSize - 1,
+ y: 0
+ },
+ {
+ ...yellow,
+ x: rowSize - 1,
+ y: 1
+ }
+ ]
+ }
+ },
+ {
+ args: [-1, rowSize],
+ imports: { config: { rowSize } },
+ output: 4,
+ viz: {
+ rowSize,
+ extras: [
+ {
+ ...red,
+ x: -1,
+ y: 0
+ },
+ {
+ ...lime,
+ x: 0,
+ y: 0
+ },
+ {
+ ...lime,
+ x: 1,
+ y: 0
+ },
+ {
+ ...lime,
+ x: rowSize - 1,
+ y: 0
+ },
+ {
+ ...yellow,
+ x: 0,
+ y: 1
+ }
+ ]
+ }
+ },
+
+ {
+ args: [longFowSize, longFowSize],
+ imports: { config: { rowSize: longFowSize } },
+ output: 0,
+ viz: {
+ rowSize: longFowSize,
+ extras: [
+ {
+ ...red,
+ x: longFowSize,
+ y: 0
+ },
+ {
+ ...lime,
+ x: 0,
+ y: 0
+ },
+ {
+ ...lime,
+ x: longFowSize - 2,
+ y: 0
+ },
+ {
+ ...lime,
+ x: longFowSize - 1,
+ y: 0
+ },
+ {
+ ...yellow,
+ x: longFowSize - 1,
+ y: 1
+ }
+ ]
+ }
+ }
+];
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/shift-tests.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/shift-tests.ts
new file mode 100644
index 000000000..dab6017aa
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/shift-tests.ts
@@ -0,0 +1,31 @@
+const viz = {
+ type: 'shift'
+};
+
+export const shiftTests = [
+ {
+ args: [0, 0, 0],
+ output: 0,
+ viz
+ },
+ {
+ args: [0, 0, 1],
+ output: 0b1,
+ viz
+ },
+ {
+ args: [0, 1, 0],
+ output: 0b10,
+ viz
+ },
+ {
+ args: [1, 0, 0],
+ output: 0b100,
+ viz
+ },
+ {
+ args: [1, 1, 1],
+ output: 0b111,
+ viz
+ }
+];
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/store-cell-tests.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/store-cell-tests.ts
new file mode 100644
index 000000000..86aff1155
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/tests/store-cell-tests.ts
@@ -0,0 +1,18 @@
+import { memoryRepViz } from './load-cell';
+
+export const storeCellTests = [
+ {
+ args: [1, 1],
+ imports: { config: { rowSize: 3, step: 0 } },
+ memory: [0, 1, 0],
+ expectedMemory: [0, 1, 0],
+ viz: memoryRepViz
+ },
+ {
+ args: [1, 0],
+ imports: { config: { rowSize: 3, step: 0 } },
+ memory: [0, 1, 0],
+ expectedMemory: [0, 0, 0],
+ viz: memoryRepViz
+ }
+];
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/utils.spec.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/utils.spec.ts
new file mode 100644
index 000000000..f41cdddb9
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/utils.spec.ts
@@ -0,0 +1,24 @@
+import { extractFunction } from './utils';
+
+describe('SyncComponent', () => {
+ it('should create', () => {
+ expect(
+ extractFunction(
+ 'getIndex',
+ ` (export "memory" (memory 0))
+ (global $step (export "step") (mut i32) (i32.const 1))
+
+ (func $getIndex (param $x i32) (param $y i32) (result i32)
+ (i32.mul
+ (i32.const 4)
+ (i32.add
+ (local.get $x)
+ (i32.mul
+ (local.get $y)
+ (global.get $rowSize))))
+ )
+`
+ )
+ ).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/utils.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/utils.ts
new file mode 100644
index 000000000..9f20a1432
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/utils.ts
@@ -0,0 +1,309 @@
+import {
+ BaseBlock,
+ CodeHelperBlock
+} from './webassembly-playground/monaco-directives/common';
+
+export function extractFunction(name, code) {
+ return extractExpressionByMatch(
+ new RegExp('\\(func \\$' + name + '\\b'),
+ code
+ );
+}
+
+export function prepareTableCode(code) {
+ const elements = extractExpressionByMatch(/\(elem/, code);
+ if (!elements) {
+ // tslint:disable-next-line:no-debugger
+ debugger;
+ }
+ const functions = [
+ ...new Set([...elements.matchAll(/\$(\w+)\b/g)].map(a => a[1]))
+ ]
+ .map(name => extractFunction(name, code))
+ .join('\n');
+
+ const tableDef = extractExpressionByMatch(/\(table/, code);
+ return `
+ ;; table
+ ${tableDef}
+
+ ;; elem
+ ${elements}
+
+ ;; table functions
+ ${functions}
+`;
+}
+
+export function extractTypeCode(code) {
+ // TODO(kirjs): This would only extract one type, at some point there can be more
+ const type = extractExpressionByMatch(/\(type/, code);
+
+ return `
+ ;; types (we only extract one ATM)
+ ${type}
+`;
+}
+
+const matchTypeRegex = /^\(\s*([\w.]+)\b/;
+const funcNameRegex = /func\s*\$(\w+)/;
+
+function getName(code) {
+ if (getType(code) === 'func') {
+ const match = code.match(funcNameRegex);
+ return match ? match[1] : undefined;
+ }
+
+ return undefined;
+}
+
+function getType(code) {
+ const t = code.match(matchTypeRegex);
+ return t && t[1];
+}
+
+export function serializeBlocks(blocks: CodeHelperBlock[]) {
+ return blocks.map(b => b.type + (b.name ? `(${b.name})` : '')).join('/');
+}
+
+export function populateBlocks(blocks: BaseBlock[]): CodeHelperBlock[] {
+ return blocks.map((b: any) => {
+ const type = getType(b.code) || 'module';
+
+ return {
+ name: getName(b.code),
+ type,
+ ...b
+ };
+ });
+}
+
+export function extractBlocks(
+ textBefore,
+ textAfter,
+ prependLeft = '',
+ prependRight = ''
+) {
+ const before = findPrevNonMatchingClosingBrace(textBefore);
+ const after = findNextNonMatchingClosingBrace(textAfter);
+
+ if (before && after) {
+ const next = extractBlocks(
+ textBefore.slice(0, -before.length - 1),
+ textAfter.slice(after.length),
+ before + prependLeft,
+ prependRight + after
+ );
+
+ return [
+ {
+ before,
+ after,
+ code: before + prependLeft + prependRight + after
+ },
+ ...next
+ ];
+ }
+
+ return [];
+}
+
+export function findNextNonMatchingClosingBrace(code: string) {
+ return findMatchingBrace(code, 0, 1, 1);
+}
+
+export function findPrevNonMatchingClosingBrace(code: string) {
+ return findMatchingBrace(code, code.length - 1, -1, -1, -1);
+}
+
+function findMatchingBrace(
+ code: string,
+ startIndex = 0,
+ shift = 1,
+ braces = 0,
+ /*This is a hack, need proper fix*/ resultShift = 0
+) {
+ let i = startIndex;
+ while (code[i]) {
+ const c = code[i];
+
+ if (c === '(') {
+ braces++;
+ }
+ if (c === ')') {
+ braces--;
+ }
+
+ i += shift;
+
+ if (braces === 0) {
+ return code.substring(startIndex, i - resultShift);
+ }
+ }
+}
+
+export function extractExpressionByMatch(regex, code) {
+ const match = regex.exec(code);
+ if (match) {
+ let i = match.index;
+ let braces = 0;
+ while (true) {
+ const c = code[i];
+
+ if (!c) {
+ return null;
+ }
+
+ if (c === '(') {
+ braces++;
+ }
+ if (c === ')') {
+ braces--;
+ }
+
+ i++;
+
+ if (braces === 0) {
+ return code.substring(match.index, i);
+ }
+ }
+ }
+}
+
+export function extractGlobalAccess(code) {
+ const match = /(?:get_global|global\.get)\s+\$(\w+)*/g;
+ return [...new Set([...code.matchAll(match)].map(a => a[1]))];
+}
+
+export function extractGlobals(code, allCode) {
+ return extractGlobalAccess(code);
+}
+
+export function hasMemoryCalls(code) {
+ return /i32\.(store|load)\s+/g.test(code);
+}
+
+export function hasTypeCalls(code) {
+ return /type \$/g.test(code);
+}
+
+export function hasTableCalls(code, config) {
+ return /(call_indirect)\s+/g.test(code);
+}
+
+function unique(arr) {
+ return [...new Set(arr)];
+}
+
+export function populateTestCode(
+ code: string,
+ test,
+ allCode: string,
+ table: string
+) {
+ if (test.table) {
+ const funcs = unique(test.table)
+ .map(name => extractFunction(name, allCode))
+ .join('\n\n');
+ const elements = test.table.map(e => ' $' + e).join('\n');
+ table = `
+(table ${test.table.length} funcref)
+(elem (i32.const 0)
+${elements}
+)
+
+${funcs}
+
+`;
+ }
+
+ const regExp = /;;{table}/;
+ if (table) {
+ code = code.replace(regExp, table);
+ }
+ return code;
+}
+
+export function extractFunctionWithDependencies(
+ name,
+ code: string,
+ dependencies: string[]
+) {
+ return extractFunctionDependencyNames(name, code, dependencies)
+ .map(name => extractFunction(name, code))
+ .join('\n\n');
+}
+
+export function hasGlobal(name, code) {
+ return /global\s+/g.test(code);
+}
+
+export function extractFunctionDependencyNames(
+ name,
+ code: string,
+ dependencies: string[]
+) {
+ const funcCode = extractFunction(name, code);
+ const match = /(?:\bcall)\s+\$(\w+)*/g;
+ if (!funcCode) {
+ return [];
+ }
+ const functions = [
+ ...new Set([...funcCode.matchAll(match)].map(a => a[1]))
+ ].filter(d => !dependencies.includes(d));
+ const nestedDeps = functions.flatMap(f =>
+ extractFunctionDependencyNames(f, code, [...dependencies, ...functions])
+ );
+ return [...new Set([...dependencies, ...nestedDeps, ...functions])];
+}
+
+function getMemoryCode(hasMemory: boolean) {
+ return hasMemory
+ ? `
+ (memory 1)
+ (export "memory" (memory 0))
+ `
+ : '';
+}
+
+export function generateWatTestCode({
+ code,
+ globals,
+ name,
+ hasMemory,
+ types
+}: any) {
+ const globalsCode = globals
+ .map(
+ global =>
+ `(global \$${global} (export "${global}") (mut i32) (i32.const 0))`
+ )
+ .join('\n');
+ const memoryCode = getMemoryCode(hasMemory);
+
+ const funcExport = code.match(`export "${name}"`)
+ ? ''
+ : `(export "${name}" (func $${name}))`;
+
+ return `(module
+ ${funcExport}
+ ${types}
+ ${globalsCode}
+ ;;{table}
+ ${memoryCode}
+ ${code}
+)`;
+}
+
+export function extractAllFunctions(code) {
+ const match = /func\s+\$(\w+)*/g;
+ return [...new Set([...code.matchAll(match)].map(a => a[1]))];
+}
+
+export function extractAnswers(code) {
+ const functions = extractAllFunctions(code).map(name => [
+ name,
+ extractFunction(name, code)
+ ]);
+ return new Map(functions as any);
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/wasm-binary/test._wasm b/codelab-master/apps/kirjs/src/app/modules/webassembly/wasm-binary/test._wasm
new file mode 100644
index 000000000..46ebb50dc
Binary files /dev/null and b/codelab-master/apps/kirjs/src/app/modules/webassembly/wasm-binary/test._wasm differ
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/wasm-binary/wasm-binary.component.css b/codelab-master/apps/kirjs/src/app/modules/webassembly/wasm-binary/wasm-binary.component.css
new file mode 100644
index 000000000..3162d444d
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/wasm-binary/wasm-binary.component.css
@@ -0,0 +1,10 @@
+::ng-deep [name='section-type'] {
+ display: block;
+ flex-basis: 100%;
+ background: #444 !important;
+ border-radius: 4px;
+ margin-top: 8px;
+ margin-bottom: 4px;
+ padding: 8px 16px;
+ color: white !important;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/wasm-binary/wasm-binary.component.html b/codelab-master/apps/kirjs/src/app/modules/webassembly/wasm-binary/wasm-binary.component.html
new file mode 100644
index 000000000..569cab08d
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/wasm-binary/wasm-binary.component.html
@@ -0,0 +1,6 @@
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/wasm-binary/wasm-binary.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/wasm-binary/wasm-binary.component.spec.ts
new file mode 100644
index 000000000..12d9b818b
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/wasm-binary/wasm-binary.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { WasmBinaryComponent } from './wasm-binary.component';
+
+describe('WasmBinaryComponent', () => {
+ let component: WasmBinaryComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [WasmBinaryComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(WasmBinaryComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/wasm-binary/wasm-binary.component.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/wasm-binary/wasm-binary.component.ts
new file mode 100644
index 000000000..a092052e1
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/wasm-binary/wasm-binary.component.ts
@@ -0,0 +1,17 @@
+import { Component } from '@angular/core';
+import { wasmParser } from './wasm-parser';
+import { strToBin } from '../../binary/parser/utils';
+
+declare const require;
+// if the extention is .wasm, webpack is being stupid.
+const wasm = require('!binary-loader!./test._wasm');
+
+@Component({
+ selector: 'kirjs-wasm-binary',
+ templateUrl: './wasm-binary.component.html',
+ styleUrls: ['./wasm-binary.component.css']
+})
+export class WasmBinaryComponent {
+ readonly binary = strToBin(wasm);
+ readonly parser = wasmParser();
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/wasm-binary/wasm-parser.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/wasm-binary/wasm-parser.ts
new file mode 100644
index 000000000..d30b02a61
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/wasm-binary/wasm-parser.ts
@@ -0,0 +1,129 @@
+import { BinaryParser } from '../../binary/parser/binary-parser';
+
+const funcTypes = {
+ 0x7f: 'i32',
+ 0x7e: 'i64',
+ 0x7d: 'f32',
+ 0x7c: 'f64',
+ 0x70: 'anyfunc',
+ 0x60: 'func',
+ 0x40: 'empty_block'
+};
+
+const valueTypes = {
+ 0x7f: 'i32',
+ 0x7e: 'i64',
+ 0x7d: 'f32',
+ 0x7c: 'f64'
+};
+
+export function wasmParser() {
+ const funcParamTypeParser = new BinaryParser().uInt8('type', {
+ enum: valueTypes
+ });
+
+ const funcTypeParser = new BinaryParser()
+ .uInt8('type', { enum: funcTypes })
+ .uInt8('paramCount')
+ .array('params', {
+ parser: funcParamTypeParser,
+ length: 'paramCount'
+ })
+ .uInt8('returnCount')
+ .array('returns', {
+ parser: funcParamTypeParser,
+ length: 'returnCount'
+ });
+
+ const fieldParser = new BinaryParser()
+ .varuint7('len')
+ .string('name', { length: 'len' });
+
+ const kindParser = new BinaryParser().uInt8('kind').choice('declaration', {
+ key: 'kind',
+ values: {
+ 0: new BinaryParser().varuint7('function'),
+ 2: new BinaryParser().varuint7('memory-tbd')
+ }
+ });
+
+ const exportItemParser = new BinaryParser()
+ .block('field', fieldParser)
+ .block('kind', kindParser);
+
+ const localEntryParser = new BinaryParser()
+ .varuint7('local_count')
+ .uInt8('value_type');
+
+ const codeBodyParser = new BinaryParser()
+ .varuint7('function_body_type_body_size')
+ .block('local', localEntryParser)
+ .block('local', localEntryParser)
+ .block('local', localEntryParser)
+ .block('local', localEntryParser);
+
+ const sectionParsers = {
+ type: new BinaryParser().uInt8('count').array('params', {
+ length: 'count',
+ parser: funcTypeParser
+ }),
+
+ import: new BinaryParser()
+ .uInt8('count')
+ .varuint7('moduleLen')
+ .string('module', { length: 'moduleLen' })
+ .block('field', fieldParser)
+ .block('kind', kindParser),
+
+ function: new BinaryParser().bit32('TBD'),
+
+ table: new BinaryParser().bit24('TBD'),
+
+ export: new BinaryParser().varuint7('count').array('items', {
+ length: 'count',
+ parser: exportItemParser
+ }),
+
+ start: new BinaryParser().varuint7('index'),
+
+ code: new BinaryParser()
+ .varuint7('number_of_functions')
+ .block('lol', codeBodyParser)
+ };
+
+ const sectionParser = new BinaryParser()
+ .uInt8('section-type', {
+ enum: {
+ 0x01: 'Types',
+ 0x02: 'Import',
+ 0x03: 'Function',
+ 0x05: 'Table',
+ 0x07: 'Export',
+ 0x08: 'Start',
+ 0x0a: 'Code'
+ }
+ })
+ .varuint7('size')
+ .choice('section', {
+ key: 'section-type',
+ values: {
+ 0x01: sectionParsers.type,
+ 0x02: sectionParsers.import,
+ 0x03: sectionParsers.function,
+ 0x05: sectionParsers.table,
+ 0x07: sectionParsers.export,
+ 0x08: sectionParsers.start,
+ 0x0a: sectionParsers.code
+ }
+ });
+
+ const header = new BinaryParser()
+ .string('headerConst', {
+ length: 4,
+ description: `header const`
+ })
+ .uInt32le('version')
+ .array('sections', { length: 7, parser: sectionParser });
+
+ return new BinaryParser().block('header', header);
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/error-message/error-message.component.css b/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/error-message/error-message.component.css
new file mode 100644
index 000000000..bba56b702
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/error-message/error-message.component.css
@@ -0,0 +1,10 @@
+.error {
+ font-size: 20px;
+ padding: 20px;
+ text-align: center;
+ background: #ff4e3d;
+ color: #fff;
+ opacity: 0.9;
+ width: 100%;
+ margin-left: -20px;
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/error-message/error-message.component.html b/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/error-message/error-message.component.html
new file mode 100644
index 000000000..2c36aded4
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/error-message/error-message.component.html
@@ -0,0 +1,3 @@
+
+ {{ result.value }}
+
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/error-message/error-message.component.spec.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/error-message/error-message.component.spec.ts
new file mode 100644
index 000000000..b8beb4a9d
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/error-message/error-message.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ErrorMessageComponent } from './error-message.component';
+
+describe('ErrorMessageComponent', () => {
+ let component: ErrorMessageComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ErrorMessageComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ErrorMessageComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/error-message/error-message.component.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/error-message/error-message.component.ts
new file mode 100644
index 000000000..405d69c55
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/error-message/error-message.component.ts
@@ -0,0 +1,15 @@
+import { Component, Input, OnInit } from '@angular/core';
+import { Result } from '../web-assembly.service';
+
+@Component({
+ selector: 'slides-error-message',
+ templateUrl: './error-message.component.html',
+ styleUrls: ['./error-message.component.css']
+})
+export class ErrorMessageComponent implements OnInit {
+ @Input() result: Result;
+
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/monaco-directives/common.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/monaco-directives/common.ts
new file mode 100644
index 000000000..4d6ac663a
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/monaco-directives/common.ts
@@ -0,0 +1,43 @@
+import {
+ webAssemblyModuleContentHandler,
+ webAssemblyTestHandler
+} from '../runners/wasm-test-runner/wasm-test-runner.component';
+
+export interface BaseBlock {
+ code: string;
+ before?: string;
+ after?: string;
+}
+
+export interface CodeHelperBlock extends BaseBlock {
+ type: string;
+ name?: string;
+ meta: any;
+}
+
+export interface CodePath {
+ type: 'ts' | 'wat';
+ blocks: CodeHelperBlock[];
+}
+
+export function getCodeBlockHandler(lang, type) {
+ if (!codeBlockHandlers[lang] || !codeBlockHandlers[lang][type]) {
+ return;
+ }
+ return codeBlockHandlers[lang][type];
+}
+
+const displayPreview = () => {
+ return { mode: 'default' };
+};
+export const codeBlockHandlers = {
+ ts: {
+ FunctionDeclaration: displayPreview,
+ SourceFile: displayPreview
+ },
+ wat: {
+ elem: displayPreview,
+ func: webAssemblyTestHandler,
+ module: webAssemblyModuleContentHandler
+ }
+};
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/monaco-directives/monaco-js-position.directive.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/monaco-directives/monaco-js-position.directive.ts
new file mode 100644
index 000000000..4caebca6c
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/monaco-directives/monaco-js-position.directive.ts
@@ -0,0 +1,96 @@
+import {
+ AfterViewInit,
+ Directive,
+ EventEmitter,
+ Optional,
+ Output,
+ Self
+} from '@angular/core';
+import { CodeDemoEditorInjector } from '@codelab/code-demos/src/lib/code-demo-editor/code-demo-editor.injector';
+import { getTypeScript } from '@codelab/utils/src/lib/loaders/loaders';
+import { serializeBlocks } from '../../utils';
+import { CodePath } from './common';
+
+const ts = getTypeScript();
+
+const printer = ts.createPrinter({
+ newLine: ts.NewLineKind.LineFeed
+});
+
+const usefulTypes = new Set([
+ ts.SyntaxKind.SourceFile,
+ ts.SyntaxKind.FunctionDeclaration
+]);
+
+function getName(token) {
+ if (token.kind === ts.SyntaxKind.FunctionDeclaration) {
+ return token.name.text;
+ }
+}
+
+function resolveToken(token, sourceFile) {
+ const code = printer.printNode(ts.EmitHint.Unspecified, token, sourceFile);
+
+ const name = getName(token);
+ return {
+ code,
+ type: ts.SyntaxKind[token.kind],
+ ...token,
+ name
+ };
+}
+
+function processBlocks(blocks: any[], sourceFile) {
+ return blocks
+ .map(b => resolveToken(b, sourceFile))
+ .filter(b => {
+ return usefulTypes.has(b.kind);
+ });
+}
+
+@Directive({
+ selector: '[slidesMonacoJsPosition]'
+})
+export class MonacoJsPositionDirective implements AfterViewInit {
+ @Output() slidesMonacoJsPosition = new EventEmitter();
+ lastResult: string;
+
+ constructor(
+ @Self() @Optional() private editorInjector: CodeDemoEditorInjector
+ ) {}
+
+ ngAfterViewInit() {
+ const editor = this.editorInjector.editor;
+ editor.onDidChangeCursorPosition(({ position }) => {
+ const model = editor.getModel();
+ const value = model.getValue();
+ const sourceFile = ts.createSourceFile(
+ 'file.ts',
+ value,
+ ts.ScriptTarget.ES2015,
+ /*setParentNodes */ true
+ );
+
+ const offset = model.getOffsetAt(position);
+ let token = (ts as any).getTokenAtPosition(sourceFile, offset);
+ const blocks = [token];
+ while (token.parent && token.kind) {
+ token = token.parent;
+ blocks.push(token);
+ }
+
+ const processedBlocks = processBlocks(blocks, sourceFile);
+
+ const result = serializeBlocks(processedBlocks);
+ // If we're in the same path and value is the same, let's not update
+ const key = result + value;
+ if (this.lastResult !== key) {
+ this.lastResult = key;
+ this.slidesMonacoJsPosition.emit({
+ type: 'ts',
+ blocks: processedBlocks
+ });
+ }
+ });
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/monaco-directives/monaco-load-answer.directive.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/monaco-directives/monaco-load-answer.directive.ts
new file mode 100644
index 000000000..c2fea48b9
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/monaco-directives/monaco-load-answer.directive.ts
@@ -0,0 +1,25 @@
+import { Directive, EventEmitter, Optional, Output, Self } from '@angular/core';
+import { CodeDemoEditorInjector } from '@codelab/code-demos/src/lib/code-demo-editor/code-demo-editor.injector';
+
+@Directive({
+ selector: '[slidesMonacoLoadAnswer]',
+ exportAs: 'MonacoWatLoadAnswer'
+})
+export class MonacoWatLoadAnswerDirective {
+ @Output() slidesMonacoLoadAnswer = new EventEmitter();
+
+ constructor(
+ @Self() @Optional() private editorInjector: CodeDemoEditorInjector
+ ) {}
+
+ loadAnswer(config: any) {
+ const model = this.editorInjector.editor.getModel();
+ const value = model.getValue();
+ const newValue = value.replace(config.originalCode, config.answer);
+ model.setValue(newValue);
+ this.slidesMonacoLoadAnswer.emit();
+ const pos = model.getPositionAt(newValue.indexOf(config.answer) + 20);
+ this.editorInjector.editor.setPosition(pos);
+ this.editorInjector.editor.focus();
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/monaco-directives/monaco-scrolling.directive.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/monaco-directives/monaco-scrolling.directive.ts
new file mode 100644
index 000000000..c4b45313e
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/monaco-directives/monaco-scrolling.directive.ts
@@ -0,0 +1,41 @@
+import { Directive, Input, OnChanges, Optional, Self } from '@angular/core';
+import { CodeDemoEditorInjector } from '@codelab/code-demos/src/lib/code-demo-editor/code-demo-editor.injector';
+import { findPosition } from '@codelab/code-demos/src/lib/code-demo-editor/utils/utils';
+
+@Directive({
+ selector: '[slidesMonacoScrolling]'
+})
+export class MonacoScrollingDirective implements OnChanges {
+ @Input() slidesMonacoScrolling = '';
+ lastValue: string;
+
+ constructor(
+ @Self() @Optional() private editorInjector: CodeDemoEditorInjector
+ ) {}
+
+ ngOnChanges(changes) {
+ const editor = this.editorInjector.editor;
+ if (
+ editor &&
+ changes.slidesMonacoScrolling &&
+ changes.slidesMonacoScrolling.currentValue !== this.lastValue
+ ) {
+ this.lastValue = this.slidesMonacoScrolling;
+
+ if (this.slidesMonacoScrolling) {
+ const range = findPosition(
+ editor.getModel().getValue(),
+ this.slidesMonacoScrolling
+ );
+
+ // This does not really work
+ editor.revealRangeInCenter({
+ startColumn: range.indexStart,
+ endColumn: range.indexEnd,
+ startLineNumber: range.lineStart,
+ endLineNumber: range.lineEnd
+ });
+ }
+ }
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/monaco-directives/monaco-wat-position.directive.spec.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/monaco-directives/monaco-wat-position.directive.spec.ts
new file mode 100644
index 000000000..af98704c6
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/monaco-directives/monaco-wat-position.directive.spec.ts
@@ -0,0 +1,8 @@
+import { MonacoWatPositionDirective } from './monaco-cursor-position.directive';
+
+describe('MonacoCursorPositionDirective', () => {
+ it('should create an instance', () => {
+ const directive = new MonacoWatPositionDirective();
+ expect(directive).toBeTruthy();
+ });
+});
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/monaco-directives/monaco-wat-position.directive.ts b/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/monaco-directives/monaco-wat-position.directive.ts
new file mode 100644
index 000000000..0ddfea5fa
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/monaco-directives/monaco-wat-position.directive.ts
@@ -0,0 +1,47 @@
+import {
+ AfterViewInit,
+ Directive,
+ EventEmitter,
+ Optional,
+ Output,
+ Self
+} from '@angular/core';
+import { CodeDemoEditorInjector } from '@codelab/code-demos/src/lib/code-demo-editor/code-demo-editor.injector';
+import { extractBlocks, populateBlocks, serializeBlocks } from '../../utils';
+import { CodePath } from './common';
+
+@Directive({
+ selector: '[slidesMonacoWatPosition]'
+})
+export class MonacoWatPositionDirective implements AfterViewInit {
+ @Output() slidesMonacoWatPosition = new EventEmitter();
+ lastResult: string;
+
+ constructor(
+ @Self() @Optional() private editorInjector: CodeDemoEditorInjector
+ ) {}
+
+ ngAfterViewInit() {
+ const editor = this.editorInjector.editor;
+ editor.onDidChangeCursorPosition(x => {
+ const position = x.position;
+ const model = editor.getModel();
+ const offset = model.getOffsetAt(position);
+ const value = model.getValue();
+
+ const textBefore = value.slice(0, offset + 1);
+ const textAfter = value.slice(offset);
+
+ const blocks = populateBlocks(extractBlocks(textBefore, textAfter));
+
+ const result = serializeBlocks(blocks);
+ // If we're in the same path and value is the same, let's not update
+
+ const key = result + value;
+ if (this.lastResult !== key) {
+ this.lastResult = key;
+ this.slidesMonacoWatPosition.emit({ type: 'wat', blocks });
+ }
+ });
+ }
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/runners/wasm-test-runner/runner.js b/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/runners/wasm-test-runner/runner.js
new file mode 100644
index 000000000..5ef3c627d
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/runners/wasm-test-runner/runner.js
@@ -0,0 +1,31 @@
+async function run(code, { args, imports, name, memory }) {
+ // imports.config.log = console.log;
+
+ const program = await WebAssembly.instantiate(code, imports);
+
+ if (memory) {
+ if (!program.instance.exports.memory) {
+ throw new Error(
+ 'This test expects memory to be exported from WebAssembly, but none was exported.'
+ );
+ }
+ const mem = new Uint32Array(program.instance.exports.memory.buffer);
+ for (let m = 0; m < memory.length; m++) {
+ mem[m] = memory[m];
+ }
+ }
+
+ if (imports) {
+ Object.entries(imports.config).map(([key, value]) => {
+ if (program.instance.exports[key]) {
+ program.instance.exports[key].value = value;
+ }
+ });
+ }
+
+ const result = program.instance.exports[name](...args);
+ return {
+ result,
+ exports: program.instance.exports
+ };
+}
diff --git a/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/runners/wasm-test-runner/wasm-test-runner.component.html b/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/runners/wasm-test-runner/wasm-test-runner.component.html
new file mode 100644
index 000000000..bb21e974f
--- /dev/null
+++ b/codelab-master/apps/kirjs/src/app/modules/webassembly/webassembly-playground/runners/wasm-test-runner/wasm-test-runner.component.html
@@ -0,0 +1,39 @@
+