From 622608d0d9bfa890eb53720f2d16d296b708d86d Mon Sep 17 00:00:00 2001 From: Sander Elias Date: Mon, 16 Dec 2019 12:27:36 +0100 Subject: [PATCH 1/7] Fix organge color for chalk --- projects/scullyio/ng-lib/package.json | 2 +- scully/package.json | 6 +++--- scully/utils/log.ts | 5 ++++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/projects/scullyio/ng-lib/package.json b/projects/scullyio/ng-lib/package.json index 749191999..c29beff60 100644 --- a/projects/scullyio/ng-lib/package.json +++ b/projects/scullyio/ng-lib/package.json @@ -1,6 +1,6 @@ { "name": "@scullyio/ng-lib", - "version": "0.0.4", + "version": "0.0.5", "repository": { "type": "GIT", "url": "https://github.com/scullyio/scully/tree/master/projects/scullyio/ng-lib" diff --git a/scully/package.json b/scully/package.json index 10d7528c1..27b7d666f 100644 --- a/scully/package.json +++ b/scully/package.json @@ -15,9 +15,9 @@ "start": "tsc -p ./tsconfig.scully.json -w", "commit": "git add . && git commit -m \"add new version build\"", "push": "git push origin master", - "publish:patch": "tsc -p ./tsconfig.scully.json && npm version patch && npm run commit && npm publish && npm run push", - "publish:minor": "tsc -p ./tsconfig.scully.json && npm version minor && npm run commit && npm publish && npm run push", - "publish:major": "tsc -p ./tsconfig.scully.json && npm version major && npm run commit && npm publish && npm run push" + "publish:patch": "tsc -p ./tsconfig.scully.json && npm version patch + "publish:minor": "tsc -p ./tsconfig.scully.json && npm version minor", + "publish:major": "tsc -p ./tsconfig.scully.json && npm version major" }, "dependencies": { "@types/express": "^4.17.0", diff --git a/scully/utils/log.ts b/scully/utils/log.ts index ec1444381..515cef758 100644 --- a/scully/utils/log.ts +++ b/scully/utils/log.ts @@ -1,6 +1,9 @@ import chalk from 'chalk'; -export const {white, red, yellow, green, orange}: {[x: string]: any} = chalk; + +const orange = chalk.hex('#FFA500') +export const {white, red, yellow, green, organge}: {[x: string]: any} = chalk; + export const log = (...a) => console.log(white(...a)); export const logError = (...a) => console.log(red(...a)); From 62d1febe420c50b81348aaed94abe79e5902c172 Mon Sep 17 00:00:00 2001 From: Sander Elias Date: Mon, 16 Dec 2019 12:32:43 +0100 Subject: [PATCH 2/7] published update --- scully/package-lock.json | 2 +- scully/package.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scully/package-lock.json b/scully/package-lock.json index 83da1d2ea..bf2b8cea9 100644 --- a/scully/package-lock.json +++ b/scully/package-lock.json @@ -1,6 +1,6 @@ { "name": "@scullyio/scully", - "version": "0.0.43", + "version": "0.0.44", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/scully/package.json b/scully/package.json index 27b7d666f..2deb4bdef 100644 --- a/scully/package.json +++ b/scully/package.json @@ -1,6 +1,6 @@ { "name": "@scullyio/scully", - "version": "0.0.43", + "version": "0.0.44", "description": "Scully CLI", "repository": { "type": "GIT", @@ -15,7 +15,7 @@ "start": "tsc -p ./tsconfig.scully.json -w", "commit": "git add . && git commit -m \"add new version build\"", "push": "git push origin master", - "publish:patch": "tsc -p ./tsconfig.scully.json && npm version patch + "publish:patch": "tsc -p ./tsconfig.scully.json && npm version patch", "publish:minor": "tsc -p ./tsconfig.scully.json && npm version minor", "publish:major": "tsc -p ./tsconfig.scully.json && npm version major" }, From b99609e29bc428e16b7b640ca6197ee50b763fa7 Mon Sep 17 00:00:00 2001 From: Sander Elias Date: Mon, 16 Dec 2019 12:49:52 +0100 Subject: [PATCH 3/7] fix for orange color --- scully/utils/log.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/scully/utils/log.ts b/scully/utils/log.ts index 515cef758..7ac00291f 100644 --- a/scully/utils/log.ts +++ b/scully/utils/log.ts @@ -1,9 +1,7 @@ import chalk from 'chalk'; - -const orange = chalk.hex('#FFA500') -export const {white, red, yellow, green, organge}: {[x: string]: any} = chalk; - +export const orange = chalk.hex('#FFA500'); +export const {white, red, yellow, green}: {[x: string]: any} = chalk; export const log = (...a) => console.log(white(...a)); export const logError = (...a) => console.log(red(...a)); From 2661e64d9b0e6309d165d108b28b4d10ebb091b5 Mon Sep 17 00:00:00 2001 From: Sander Elias Date: Wed, 18 Dec 2019 11:48:22 +0100 Subject: [PATCH 4/7] Added scully mode detaction. (in scully/from generated) --- blog/jorge.md | 42 +++++++++++++++++++ .../sampleBlog/src/app/app.component.html | 2 +- projects/sampleBlog/src/app/app.component.ts | 8 +++- projects/scullyio/ng-lib/package.json | 2 +- .../scullyio/ng-lib/src/lib/utils/isScully.ts | 3 ++ projects/scullyio/ng-lib/src/public-api.ts | 3 +- scully/renderPlugins/puppeteerRenderPlugin.ts | 10 ++++- scully/utils/validateConfig.ts | 4 +- 8 files changed, 65 insertions(+), 9 deletions(-) create mode 100644 blog/jorge.md create mode 100644 projects/scullyio/ng-lib/src/lib/utils/isScully.ts diff --git a/blog/jorge.md b/blog/jorge.md new file mode 100644 index 000000000..6123d6d4f --- /dev/null +++ b/blog/jorge.md @@ -0,0 +1,42 @@ +--- +title: Deberías colaborar en proyectos open source +published: true +tags: community,developer,open-source +description: ¿Qué Some spanish blog post? +publish date: 2019-12-16 +--- +Hace algunas semanas en las oficinas de google de sunnyvale se hosteo el "Google Developer Expert Summit" y tuve la "gran idea" de hablar sobre porque deberíamos trabajar en proyectos open source en nuestro tiempo libre. +Y toque varios puntos que me gustaría compartir con ustedes: +### - Yo haciendo OSS? +Claro, basicamente si sabes programar podes colaborar en OSS +> ¿Qué te diferencia de la gente que lo hace? Que ellos simplemente lo hacen! +Seguramente una persona que esta haciendo hace tiempo OSS sabra algunos trucos mas que vos a la hora de crear un PR o de entender y dialogar en los tickets abiertos… Pero no se nace sabiendo, se va aprendiendo todo… +Así que a la primera pregunta es un SI, tu código en proyectos open source es posible, solo tenés que tener ganas, tiempo y hacerlo. +### No es tan fácil! +Bueno, claro que no, pero nunca te topaste con uno de esos issues bien difíciles hasta que lo sacaste? +Bueno, es lo mismo, la diferencia es que posiblemente tenga el "síndrome del impostor" +![](https://cdn-images-1.medium.com/max/926/0*yKQQUkVVSfR4H6rW) +Claro que existe, lo dice wikipedia. +La verdad que a veces uno piensa que no esta "al nivel" de los que hacen "open source" pero la verdad es que si no empezás a hacer aunque sea cambios SUPER chiquitos, no vas a empezar nunca. +### ¿Por qué necesito contribuir en open source? +![](https://cdn-images-1.medium.com/max/498/0*ssFA3EJN4f0ZyXRn) +Esta es una de las preguntas que me hicieron varias veces… Y creo que es la más fácil de responder de todas. +- Vas a entender mejor la libreria/framework +- Vas a ayudar a otros desarrolladores +- Vas a tener una mejor vision del potencial de utilizar ese proyecto +- Vas a ayudar a las personas que te ayudan a vos (los mantainers) +> ¡Aprendes una nueva forma de ayudar y mejorar tus habilidades! +¿Cómo empiezo a colaborar? +Esta es una pregunta tal vez un poco mas trabajosa (?) , bueno en realidad no, una vez que arrancas te vas a dar cuenta que es más fácil de lo que parece… pero para mí, las mejores formas de arrancar son: +- Buscando en el proyecto los issues con label "good for first PR" / "community help" +- Busca algún mentor que haga OSS +- Busca la forma de comunicarte con el team que mantiene el proyecto +- No te avergüences por preguntar o por lo que estas haciendo +> Agradecer, no cuesta nada y alegra a muchos +![](https://cdn-images-1.medium.com/max/480/0*5uhbsJVA1k2iKWg1) +Cuando alguien te ayude o te de una mano, siempre tenes que ser agradecido, no te cuesta realmente nada… Y eso va a hablar bien de vos! +#### Espero que estos pequeños tips te sirvan para arrancar a colaborar con proyecto open source y lleves tus skills a otro nivel !! +Como siempre, espero que les guste lo compartido y cualquier duda dejo mis canales: +- [Jorge Cano (@jorgeucano) | Twitter](https://twitter.com/@jorgeucano) +- [Jorge Cano](https://www.youtube.com/channel/UCdp9sM22GW5uIOaU9eZ7n6w) +Saludos diff --git a/projects/sampleBlog/src/app/app.component.html b/projects/sampleBlog/src/app/app.component.html index a1a440888..5aa52aae3 100644 --- a/projects/sampleBlog/src/app/app.component.html +++ b/projects/sampleBlog/src/app/app.component.html @@ -1,5 +1,5 @@
-

Scully demo blog app!

+

Scully demo blog app! {{currentState}}

🏠
diff --git a/projects/sampleBlog/src/app/app.component.ts b/projects/sampleBlog/src/app/app.component.ts index 8932f84c8..af8ea21a4 100644 --- a/projects/sampleBlog/src/app/app.component.ts +++ b/projects/sampleBlog/src/app/app.component.ts @@ -1,5 +1,5 @@ import {Component} from '@angular/core'; -import { IdleMonitorService } from '@scullyio/ng-lib'; +import {IdleMonitorService, isScullyGenerated, isScullyRunning} from '@scullyio/ng-lib'; @Component({ selector: 'app-root', @@ -7,6 +7,10 @@ import { IdleMonitorService } from '@scullyio/ng-lib'; styleUrls: ['./app.component.css'], }) export class AppComponent { - title = 'sampleBlog'; + currentState = isScullyRunning() + ? 'rendering inside scully' + : isScullyGenerated() + ? 'Loaded from static HTML' + : 'SPA mode'; constructor(private idle: IdleMonitorService) {} } diff --git a/projects/scullyio/ng-lib/package.json b/projects/scullyio/ng-lib/package.json index c29beff60..7b9cc203e 100644 --- a/projects/scullyio/ng-lib/package.json +++ b/projects/scullyio/ng-lib/package.json @@ -1,6 +1,6 @@ { "name": "@scullyio/ng-lib", - "version": "0.0.5", + "version": "0.0.6", "repository": { "type": "GIT", "url": "https://github.com/scullyio/scully/tree/master/projects/scullyio/ng-lib" diff --git a/projects/scullyio/ng-lib/src/lib/utils/isScully.ts b/projects/scullyio/ng-lib/src/lib/utils/isScully.ts new file mode 100644 index 000000000..5140aff6a --- /dev/null +++ b/projects/scullyio/ng-lib/src/lib/utils/isScully.ts @@ -0,0 +1,3 @@ +// tslint:disable: no-string-literal +export const isScullyRunning = () => window && window['ScullyIO'] === 'running'; +export const isScullyGenerated = () => window && window['ScullyIO'] === 'generated'; diff --git a/projects/scullyio/ng-lib/src/public-api.ts b/projects/scullyio/ng-lib/src/public-api.ts index cd7638cfb..645f07518 100644 --- a/projects/scullyio/ng-lib/src/public-api.ts +++ b/projects/scullyio/ng-lib/src/public-api.ts @@ -5,5 +5,6 @@ export * from './lib/components.module'; export * from './lib/idleMonitor/idle-monitor.service'; export * from './lib/route-service/scully-routes.service'; -export * from './lib/scully-content/scully-content.component' +export * from './lib/scully-content/scully-content.component'; +export * from './lib/utils/isScully' diff --git a/scully/renderPlugins/puppeteerRenderPlugin.ts b/scully/renderPlugins/puppeteerRenderPlugin.ts index 06e50ec94..adf2aa668 100644 --- a/scully/renderPlugins/puppeteerRenderPlugin.ts +++ b/scully/renderPlugins/puppeteerRenderPlugin.ts @@ -1,3 +1,4 @@ +// tslint:disable: no-string-literal // const puppeteer = require('puppeteer'); import {Browser, Page} from 'puppeteer'; import {HandledRoute} from '../routerPlugins/addOptionalRoutesPlugin'; @@ -26,8 +27,13 @@ export const puppeteerRender = async (route: HandledRoute): Promise => { /** Inject this into the running page, runs in browser*/ await page.evaluateOnNewDocument(() => { + /** set "running" mode */ + window['ScullyIO'] = 'running'; window.addEventListener('AngularReady', () => { - // setTimeout(() => window['onCustomEvent'](),10000); + /** add a small script tag to set "generated" mode */ + const d = document.createElement('script'); + d.innerHTML = `window['ScullyIO']='generated';`; + document.head.appendChild(d); window['onCustomEvent'](); }); }); @@ -35,7 +41,7 @@ export const puppeteerRender = async (route: HandledRoute): Promise => { // enter url in page await page.goto(path); - await Promise.race([pageReady, waitForIt(25 * 1000)] ); + await Promise.race([pageReady, waitForIt(25 * 1000)]); /** * The stange notation is needed bcs typescript messes diff --git a/scully/utils/validateConfig.ts b/scully/utils/validateConfig.ts index 56f0da9fa..4f0385b07 100644 --- a/scully/utils/validateConfig.ts +++ b/scully/utils/validateConfig.ts @@ -23,7 +23,7 @@ export async function validateConfig(config: ScullyConfig) { } result.projectRoot = config.projectRoot; } else { - error(`projectRoot missing in "${yellow('scully.json')}"`); + error(`projectRoot missing in "${yellow('scully.config.js')}"`); } if (config.routes) { await Promise.all( @@ -50,7 +50,7 @@ export async function validateConfig(config: ScullyConfig) { }) ); } else { - logWarn('No routes defined in "scully.config"'); + logWarn('No routes defined in "scully.config.js "'); } if (hasErrors) { /** stop everthing if there are errors in the config. */ From 4b6a202357f8076b8c3e96d29803e49bb8c907c2 Mon Sep 17 00:00:00 2001 From: Sander Elias Date: Wed, 18 Dec 2019 16:20:34 +0100 Subject: [PATCH 5/7] wip setting up contxt --- scully/utils/compileConfig.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/scully/utils/compileConfig.ts b/scully/utils/compileConfig.ts index 8a15feae8..254e865a0 100644 --- a/scully/utils/compileConfig.ts +++ b/scully/utils/compileConfig.ts @@ -5,7 +5,7 @@ import {join} from 'path'; import {createContext, runInContext} from 'vm'; import {ScullyConfig} from '..'; import {configValidator, registerPlugin} from '../pluginManagement/pluginRepository'; -import {angularRoot} from './config'; +import {angularRoot, scullyConfig} from './config'; import {routeSplit} from './routeSplit'; export const compileConfig = async (): Promise => { @@ -39,10 +39,14 @@ export const compileConfig = async (): Promise => { const tsCode = readFileSync(path).toString(); // const jsCode = ts.compile(tsCode, filename, 0); const jsCode = tsCode; - runInContext(jsCode, runtimeEnvironment, {filename, displayErrors: true}); + runInContext(jsCode, runtimeEnvironment, {filename, displayErrors: true, importModuleDynamically: myReq}); return runtimeEnvironment.exports.config; } catch (e) { console.error(e); return ({} as unknown) as ScullyConfig; } }; + +function myReq(path: string): Promise { + return import(join(scullyConfig.homeFolder, path)); +} From 2236e5542cac73f00f73095b2aa7b47c874d0900 Mon Sep 17 00:00:00 2001 From: Sander Elias Date: Wed, 18 Dec 2019 17:53:12 +0100 Subject: [PATCH 6/7] replaces require with custom one, and added node's global to context --- extraPlugin/extra-plugin.js | 24 +++++++++++++++++++++ scully.config.js | 24 ++++----------------- scully/package-lock.json | 2 +- scully/package.json | 2 +- scully/pluginManagement/pluginRepository.ts | 3 ++- scully/utils/compileConfig.ts | 5 +++-- 6 files changed, 35 insertions(+), 25 deletions(-) create mode 100644 extraPlugin/extra-plugin.js diff --git a/extraPlugin/extra-plugin.js b/extraPlugin/extra-plugin.js new file mode 100644 index 000000000..bb7e0e227 --- /dev/null +++ b/extraPlugin/extra-plugin.js @@ -0,0 +1,24 @@ + +const {configValidator} = require('../scully/bin'); + +console.log(__dirname) + +exports.extraRoutesPlugin = (route, options) => { + const {createPath} = routeSplit(route); + if (options.numberOfPages) { + return Array.from({length: options.numberOfPages}, (_v, k) => k).map(n => ({ + route: `${createPath(`${n}`)}`, + title: `page number ${n}`, + })); + } + if (options.data) { + return options.data.map(item => ({ + route: createPath(item.data), + title: item.title || '', + })); + } + return []; +}; +/** the validator is mandatory */ +exports.extraRoutesPlugin[configValidator] = async options => []; + diff --git a/scully.config.js b/scully.config.js index 296a9476a..b6eb03a1d 100644 --- a/scully.config.js +++ b/scully.config.js @@ -1,25 +1,9 @@ -const extraRoutesPlugin = (route, options) => { - const {createPath} = routeSplit(route); - if (options.numberOfPages) { - return Array.from({length: options.numberOfPages}, (_v, k) => k).map(n => ({ - route: `${createPath(`${n}`)}`, - title: `page number ${n}`, - })); - } - if (options.data) { - return options.data.map(item => ({ - route: createPath(item.data), - title: item.title || '', - })); - } - return []; -}; -extraRoutesPlugin[configValidator] = async config => { - return []; -}; - +/** load the plugin */ +const {extraRoutesPlugin} = require('./extraPlugin/extra-plugin.js') +/** register the plugin */ registerPlugin('router', 'extra', extraRoutesPlugin); + exports.config = { /** projectRoot is mandatory! */ projectRoot: './projects/sampleBlog/src/app', diff --git a/scully/package-lock.json b/scully/package-lock.json index bf2b8cea9..7a3e37a4a 100644 --- a/scully/package-lock.json +++ b/scully/package-lock.json @@ -1,6 +1,6 @@ { "name": "@scullyio/scully", - "version": "0.0.44", + "version": "0.0.45", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/scully/package.json b/scully/package.json index 9b6366030..8d27d48d9 100644 --- a/scully/package.json +++ b/scully/package.json @@ -1,6 +1,6 @@ { "name": "@scullyio/scully", - "version": "0.0.44", + "version": "0.0.45", "description": "Scully CLI", "repository": { "type": "GIT", diff --git a/scully/pluginManagement/pluginRepository.ts b/scully/pluginManagement/pluginRepository.ts index 626516423..56fdab248 100644 --- a/scully/pluginManagement/pluginRepository.ts +++ b/scully/pluginManagement/pluginRepository.ts @@ -1,7 +1,8 @@ import {HandledRoute} from '../routerPlugins/addOptionalRoutesPlugin'; import {logError, yellow} from '../utils/log'; -export const configValidator = Symbol('configValidator'); +// export const configValidator = Symbol('configValidator'); +export const configValidator = `___Scully_Validate_config_plugin___`; export type PluginHandler = (...args: any) => Promise; export interface Plugin { diff --git a/scully/utils/compileConfig.ts b/scully/utils/compileConfig.ts index 254e865a0..3042c6add 100644 --- a/scully/utils/compileConfig.ts +++ b/scully/utils/compileConfig.ts @@ -22,7 +22,8 @@ export const compileConfig = async (): Promise => { registerPlugin, configValidator, routeSplit, - require, + global, + require: (path: string) => (path.startsWith('@') ? require(path) : require(join(angularRoot, path))), }); // const tsCompilerConfig: CreateOptions = { // logError: true, @@ -39,7 +40,7 @@ export const compileConfig = async (): Promise => { const tsCode = readFileSync(path).toString(); // const jsCode = ts.compile(tsCode, filename, 0); const jsCode = tsCode; - runInContext(jsCode, runtimeEnvironment, {filename, displayErrors: true, importModuleDynamically: myReq}); + runInContext(jsCode, runtimeEnvironment, {filename, displayErrors: true}); return runtimeEnvironment.exports.config; } catch (e) { console.error(e); From 499655ad3e3ba83e266112a7dc74f632e9ac91c4 Mon Sep 17 00:00:00 2001 From: Sander Elias Date: Wed, 18 Dec 2019 18:11:40 +0100 Subject: [PATCH 7/7] remove stray blog sample --- blog/jorge.md | 42 ------------------------------------------ 1 file changed, 42 deletions(-) delete mode 100644 blog/jorge.md diff --git a/blog/jorge.md b/blog/jorge.md deleted file mode 100644 index 6123d6d4f..000000000 --- a/blog/jorge.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -title: Deberías colaborar en proyectos open source -published: true -tags: community,developer,open-source -description: ¿Qué Some spanish blog post? -publish date: 2019-12-16 ---- -Hace algunas semanas en las oficinas de google de sunnyvale se hosteo el "Google Developer Expert Summit" y tuve la "gran idea" de hablar sobre porque deberíamos trabajar en proyectos open source en nuestro tiempo libre. -Y toque varios puntos que me gustaría compartir con ustedes: -### - Yo haciendo OSS? -Claro, basicamente si sabes programar podes colaborar en OSS -> ¿Qué te diferencia de la gente que lo hace? Que ellos simplemente lo hacen! -Seguramente una persona que esta haciendo hace tiempo OSS sabra algunos trucos mas que vos a la hora de crear un PR o de entender y dialogar en los tickets abiertos… Pero no se nace sabiendo, se va aprendiendo todo… -Así que a la primera pregunta es un SI, tu código en proyectos open source es posible, solo tenés que tener ganas, tiempo y hacerlo. -### No es tan fácil! -Bueno, claro que no, pero nunca te topaste con uno de esos issues bien difíciles hasta que lo sacaste? -Bueno, es lo mismo, la diferencia es que posiblemente tenga el "síndrome del impostor" -![](https://cdn-images-1.medium.com/max/926/0*yKQQUkVVSfR4H6rW) -Claro que existe, lo dice wikipedia. -La verdad que a veces uno piensa que no esta "al nivel" de los que hacen "open source" pero la verdad es que si no empezás a hacer aunque sea cambios SUPER chiquitos, no vas a empezar nunca. -### ¿Por qué necesito contribuir en open source? -![](https://cdn-images-1.medium.com/max/498/0*ssFA3EJN4f0ZyXRn) -Esta es una de las preguntas que me hicieron varias veces… Y creo que es la más fácil de responder de todas. -- Vas a entender mejor la libreria/framework -- Vas a ayudar a otros desarrolladores -- Vas a tener una mejor vision del potencial de utilizar ese proyecto -- Vas a ayudar a las personas que te ayudan a vos (los mantainers) -> ¡Aprendes una nueva forma de ayudar y mejorar tus habilidades! -¿Cómo empiezo a colaborar? -Esta es una pregunta tal vez un poco mas trabajosa (?) , bueno en realidad no, una vez que arrancas te vas a dar cuenta que es más fácil de lo que parece… pero para mí, las mejores formas de arrancar son: -- Buscando en el proyecto los issues con label "good for first PR" / "community help" -- Busca algún mentor que haga OSS -- Busca la forma de comunicarte con el team que mantiene el proyecto -- No te avergüences por preguntar o por lo que estas haciendo -> Agradecer, no cuesta nada y alegra a muchos -![](https://cdn-images-1.medium.com/max/480/0*5uhbsJVA1k2iKWg1) -Cuando alguien te ayude o te de una mano, siempre tenes que ser agradecido, no te cuesta realmente nada… Y eso va a hablar bien de vos! -#### Espero que estos pequeños tips te sirvan para arrancar a colaborar con proyecto open source y lleves tus skills a otro nivel !! -Como siempre, espero que les guste lo compartido y cualquier duda dejo mis canales: -- [Jorge Cano (@jorgeucano) | Twitter](https://twitter.com/@jorgeucano) -- [Jorge Cano](https://www.youtube.com/channel/UCdp9sM22GW5uIOaU9eZ7n6w) -Saludos