[
  {
    "path": "README.md",
    "content": "# javascript-professional\nLas mejores prácticas de Javascript para ser un profesional, es necesario tener buenos fundamentos del lenguaje\n"
  },
  {
    "path": "decorator/index.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n  <meta charset=\"UTF-8\">\r\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n  <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\r\n  <title>Decorator Patterns</title>\r\n</head>\r\n<body>\r\n  <div>\r\n    <h1>Decorator Desgin Patterns</h1>\r\n    <label for=\"email\">Email</label>\r\n    <input type=\"text\" id=\"email\">\r\n  </div>\r\n</body>\r\n</html>"
  },
  {
    "path": "decorator/index.ts",
    "content": "class Field {\r\n  errors: string[];\r\n  input: HTMLInputElement;\r\n\r\n  constructor(input: HTMLInputElement) {\r\n    this.input = input;\r\n    this.errors = [];\r\n\r\n    let errorMessage = document.createElement('p');\r\n    errorMessage.className = 'text-danger';\r\n    this.input.parentNode.insertBefore(errorMessage, this.input.nextSibling);\r\n\r\n    this.input.addEventListener('input', () => {\r\n      this.errors = [];\r\n      this.validate();\r\n      errorMessage.innerText = this.errors[0] || ' ';\r\n    })\r\n  }\r\n  validate() {}\r\n}\r\n\r\nfunction RequireFieldDecorator(field: Field): Field {\r\n  let validate = field.validate;\r\n\r\n  field.validate = function () {\r\n    validate()\r\n    let value = field.input.value;\r\n    if (!value) {\r\n      field.errors.push(\"Requisito\");\r\n    }\r\n  };\r\n\r\n  return field;\r\n}\r\n\r\nfunction EmailFieldDecorator(field: Field): Field {\r\n  let validate = field.validate;\r\n\r\n  field.validate = function () {\r\n    validate()\r\n    let value = field.input.value;\r\n\r\n    if (value.indexOf(\"@\") === -1) {\r\n      field.errors.push(\"Debe ser un email\");\r\n    }\r\n\r\n  };\r\n  \r\n  return field;\r\n}\r\n\r\nlet field = new Field(document.querySelector(\"#email\"));\r\nRequireFieldDecorator(field);\r\nEmailFieldDecorator(RequireFieldDecorator(field));"
  },
  {
    "path": "ejercicios/abort-fetch.html",
    "content": "<html>\n  <head>\n    <title>Abort Fetch</title>\n  </head>\n\n  <body>\n    <a href=\"/ejercicios/\">Go back</a>\n    <p><em>Abre la consola</em></p>\n\n    <img id=\"huge-image\" height=\"400\" />\n\n    <button id=\"load\">Load HUGE Image</button>\n    <button id=\"stop\" disabled>Stop Fetching</button>\n\n    <script src=\"abort-fetch.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "ejercicios/abort-fetch.js",
    "content": "const url =\r\n  'https://images.pexels.com/photos/974470/nature-stars-milky-way-galaxy-974470.jpeg?q=100';\r\n      // Elementos del DOM imagen y 2 botones\r\n      const img = document.getElementById('huge-image');\r\n      const loadButton = document.getElementById('load');\r\n      const stopButton = document.getElementById('stop');\r\n      let controller;\r\n\r\n      // Función que habilita o desabilita un boton\r\n      function startLoading() {\r\n        loadButton.disabled = true;\r\n        // Camnbia el texto de su contenido\r\n        loadButton.innerText = 'Loading...';\r\n        stopButton.disabled = false;\r\n      }\r\n      // Funcíon que desabilita el boton de carga\r\n      function stopLoading() {\r\n        loadButton.disabled = false;\r\n        loadButton.innerText = 'Load HUGE Image';\r\n        stopButton.disabled = true;\r\n      }\r\n\r\n      loadButton.onclick = async function() {\r\n        // Se ejecuta startLoading que lo unico que hace es cambiar la apariencia del boton\r\n        // Para que se vea que esta cargando\r\n        startLoading();\r\n\r\n        // Declaramos la variable antes para despues tener acceso a ella\r\n        // en el boton de cancelar petición fetch\r\n        controller = new AbortController();\r\n        try {\r\n          // Hacemos la petición asincrona a la URL usando Async await\r\n          // Vamos a añadirle un objeto de configuración al fetch\r\n          // Esté objeto de configuración le vamos a pasar un objeto que se llama la señal\r\n          // La señal va a venir del abort controller\r\n          const response = await fetch(url, { signal: controller.signal });\r\n          // Vamos a obtener el binario de la imagen con blob img en forma binaria\r\n          const blob = await response.blob();\r\n          // Convertimos el blob binario a una URL, el navegador se encarga de asignar el blob una url\r\n          const imgUrl = URL.createObjectURL(blob);\r\n          // Ahora el src se lo asignamos a la url de la imagen\r\n          img.src = imgUrl;\r\n        } catch (error) {\r\n          console.log(error.message);\r\n        }\r\n\r\n        // Cuando la función asincrona se falle vamos a cambiar el boton a stop\r\n        stopLoading();\r\n      };\r\n\r\n      stopButton.onclick = function() {\r\n        // Si deseamos detener tenemos que llamar al abort controller.container\r\n        // El abort envia una señal al fetch y hace que la petición se cancele\r\n        controller.abort();\r\n\r\n        stopLoading();\r\n      };\r\n      \r\n"
  },
  {
    "path": "ejercicios/call-apply-bind.js",
    "content": "// Establece this usando 'call'\r\nfunction saludar() {\r\n  console.log(`Hola soy ${this.name} ${this.lastname}`)\r\n}\r\n\r\nconst richard = {\r\n  name: 'Richard',\r\n  lastname: 'Lopez'\r\n}\r\n\r\nsaludar.call(richard)\r\n\r\n// Establece this usando 'call' y pasar argumentos a la función.\r\nfunction caminar(metros, direccion) {\r\n  console.log(`${this.name} camina ${metros} metros hacia ${direccion}`);\r\n}\r\n\r\ncaminar.call(richard, 500, 'norte');\r\n\r\n// Establece this usando 'apply' y pasar argumentos a la función\r\n\r\ncaminar.apply(richard, [900, 'noreste']);\r\n\r\n// Establecer una nueva función usando bind()\r\nconst daniel = {\r\n  name: \"Daniel\",\r\n  lastname: \"Sanchez\"\r\n}\r\nconst danielSaluda = saludar.bind(daniel);\r\ndanielSaluda();\r\n\r\nconst danielCamina = caminar.bind(daniel, 1000);\r\ndanielCamina('oeste');\r\n\r\n// Cuando es útil uno de estós métodos \r\nconst buttons = document.getElementsByClassName(\"call-to-action\");\r\n// buttons.forEach(button => {\r\n//   button.onclick = () => alert('Nunca pares de aprender');\r\n// });\r\n\r\n// No es una funcion forEach porque button es NodeList\r\nArray.prototype.forEach.call(buttons, button => {\r\n  button.onclick = () => alert('Nunca pares de aprender');\r\n})"
  },
  {
    "path": "ejercicios/clousers.js",
    "content": "// Clousers\r\n// printColor\r\n// let color = 'green';\r\n// function printColor() {\r\n//   console.log(color);\r\n// }\r\n// IIFE: immediately invoked function expression\r\n(function () {\r\n  let color = 'green';\r\n\r\n  function printColor() {\r\n    console.log(color);\r\n  }\r\n\r\n  printColor();\r\n})();\r\nfunction makeColorPrinter(color) {\r\n  let colorMessage = `The color is: ${color}`;\r\n  return function () {\r\n    console.log(colorMessage);\r\n  }\r\n}\r\nlet greenColorPrinter = makeColorPrinter(\"green\");\r\nconsole.log(greenColorPrinter());\r\n\r\n// Clousers Jasan Hernández.\r\n// ¿Variables privadas?\r\nconst counter1 = {\r\n  count: 3\r\n}\r\n// count esta en el scope Global Window\r\nconsole.log(counter1.count);\r\n// Podemos modificar su valor si quisieramos\r\ncounter1.count = 99;\r\nconsole.log(counter1.count);\r\n\r\n// Clouseres - creamos un function scope\r\nfunction makeCounter(n) {\r\n  // count ya no existe en window, ahora\r\n  // solo pertenece a la función\r\n  let count = n;\r\n  return {\r\n    increase: function () { count += 1; },\r\n    decrease: function () { count -= 1},\r\n    getCount: function () { return count; },\r\n  }\r\n}\r\nlet counter = makeCounter(7);\r\nconsole.log('This count is:', counter.getCount());\r\nconsole.log('This count is:', counter.increase());\r\nconsole.log('This count is:', counter.decrease());\r\n// No podemos cambiar el valor de count porque no \r\n// está en nuestro alcance.\r\n// ERROR FATAL\r\n// counter.count = 99;"
  },
  {
    "path": "ejercicios/generators.js",
    "content": "function* simpleGenerator() {\r\n  console.log(\"GENERATOR START\");\r\n  yield 1; // {value: 1, done: false}\r\n  yield 2; // {value: 2, done: false}\r\n  yield 3; // {value: 3, done: false}\r\n  console.log(\"GENERATOR END\");\r\n}\r\n\r\n// const gen = simpleGenerator();\r\n// gen.next()\r\n// GENERATOR START\r\n// gen.next();\r\n// GENERATOR END\r\n\r\n// Podemos hacer generadores infinitos\r\nfunction* idMaker() {\r\n  let id = 1;\r\n  while (true) {\r\n    yield id;\r\n    id += 1;\r\n  }\r\n}\r\n\r\n// Cuando llamamos a next también podemos pasar valores que la función recibe.\r\nfunction* idMakerWithReset() {\r\n  let id = 1;\r\n  let reset;\r\n  while (true) {\r\n    reset = yield id;\r\n    if (reset) {\r\n      id = 1;\r\n    } else {\r\n      id += 1;\r\n    }\r\n  }\r\n}\r\n\r\n// Ahora hagamos un ejemplo un poco más complejo: la secuencia fibonacci\r\nfunction* fibonacci() {\r\n  let a = 1, b = 1;\r\n  while (true) {\r\n    const nextNumber = a + b;\r\n    a = b;\r\n    b = nextNumber;\r\n    yield nextNumber;\r\n  }\r\n}"
  },
  {
    "path": "ejercicios/index.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n\r\n<head>\r\n  <meta charset=\"UTF-8\">\r\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n  <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\r\n  <title>Scope</title>\r\n</head>\r\n<body>\r\n  <ul>\r\n    <button class=\"call-to-action\">Aprender</button>\r\n    <button class=\"call-to-action\">Aprender Más</button>\r\n    <button class=\"call-to-action\">¡Nunca pares de aprender!</button>\r\n  </ul>\r\n  <!-- <script\r\n  src=\"https://code.jquery.com/jquery-3.4.1.min.js\"\r\n  integrity=\"sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=\"\r\n  crossorigin=\"anonymous\"></script> -->\r\n  <!-- <script src=\"call-apply-bind.js\"></script> -->\r\n  <!-- <script src=\"https://cdn.jsdelivr.net/npm/fast-levenshtein@2.0.6/levenshtein.min.js\"></script> -->\r\n  <!-- <script src=\"proxy.js\"></script> -->\r\n  <script src=\"generators.js\"></script>\r\n  <!-- <script src=\"prototype-inheritance.js\"></script> -->\r\n</body>\r\n\r\n</html>"
  },
  {
    "path": "ejercicios/promise.js",
    "content": "// Ejemplo: renderMovies([{ title: \"Spider-Man\", release_date: \"2019-06-30\", poster_path: \"/rjbNpRMoVvqHmhmksbokcyCr7wn.jpg\" }])\r\n      // Traducir las funciones de usar thens a usar async/await\r\n      // Crear función para que no nos gastemos la cantidad de requests demasiado rapido\r\n      // Crear función donde hacemos requests secuenciales\r\n      // Crear función donde hacemos requests en paralelo\r\n      // Crear función donde obtenemos el primer request que llegue\r\n\r\n      // The Movie Database API: https://developers.themoviedb.org/3/getting-started/introduction\r\n      const apiKey = 'b89fc45c2067cbd33560270639722eae';\r\n\r\n      // function getMovie(id) {\r\n      //   const url = `https://api.themoviedb.org/3/movie/${id}?api_key=${apiKey}`;\r\n      //   return fetch(url).then(response => response.json());\r\n      // }\r\n\r\n      async function getMovie(id) {\r\n        const url = `https://api.themoviedb.org/3/movie/${id}?api_key=${apiKey}`;\r\n        const response = await fetch(url)\r\n        const data = await response.json();\r\n        return data;\r\n      }\r\n\r\n      async function getPopularMovies() {\r\n        const url = `https://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=${apiKey}`;\r\n        const response = await fetch(url);\r\n        const data = await response.json();\r\n        return data.results;\r\n      }\r\n\r\n      async function getTopMoviesIds(n = 3) {\r\n        // try {\r\n        //   const popularMovies = await getPopularMovies();\r\n        // } catch(error) {\r\n        //   console.log(error);\r\n        // }\r\n        const popularMovies = await getPopularMovies();\r\n        const ids = popularMovies.slice(0, n).map(movie => movie.id);\r\n        return ids;\r\n      }\r\n\r\n      function renderMovies(movies) {\r\n        const movieList = document.getElementById('movies');\r\n        movieList.innerHTML = '';\r\n\r\n        movies.forEach(movie => {\r\n          const listItem = document.createElement('li');\r\n          listItem.innerHTML = `\r\n            <img src=\"https://image.tmdb.org/t/p/w342${movie.poster_path}\" />\r\n            <h5>${movie.title}</h5>\r\n            <p>Released on <em>${movie.release_date}</em></p>\r\n            `;\r\n\r\n          movieList.appendChild(listItem);\r\n        });\r\n      }\r\n\r\n      // Peliculas en secuencia\r\n\r\n      async function getTopMoviesInSequence() {\r\n        const ids = await getTopMoviesIds();\r\n        const movies = [];\r\n\r\n        for (const id of ids) {\r\n          const movie = await getMovie(id);\r\n          movies.push(movie);\r\n        }\r\n\r\n        return movies;\r\n      }\r\n\r\n      async function getTopMoviesInParallel() {\r\n        const ids = await getTopMoviesIds();\r\n        const moviePromises = ids.map(id => getMovie(id));\r\n\r\n        const movies = await Promise.all(moviePromises);\r\n\r\n        return movies;\r\n      }\r\n\r\n      async function getFastestTopMovie() {\r\n        const ids = await getTopMoviesIds();\r\n        const moviePromises = ids.map(id => getMovie(id));\r\n\r\n        const movie = await Promise.race(moviePromises);\r\n        return movie;\r\n      }\r\n\r\n      document.getElementById('sequence').onclick = async function() {\r\n        const movies = await getTopMoviesInSequence();\r\n        renderMovies(movies);\r\n      };\r\n\r\n      document.getElementById('parallel').onclick = async function() {\r\n        const movies = await getTopMoviesInParallel();\r\n        renderMovies(movies);\r\n      };\r\n\r\n      document.getElementById('fastest').onclick = async function() {\r\n        const movie = await getFastestTopMovie();\r\n        renderMovies([movie]);\r\n      };"
  },
  {
    "path": "ejercicios/promises.html",
    "content": "<html>\n  <head>\n    <title>Promesas</title>\n  </head>\n\n  <body>\n    <a href=\"/ejercicios/\">Go back</a>\n\n    <ul>\n      <li><button id=\"sequence\">Get Top Movies in Sequence</button></li>\n      <li><button id=\"parallel\">Get Top Movies in Parallel</button></li>\n      <li><button id=\"fastest\">Get Fastest Top Movie</button></li>\n    </ul>\n\n    <ul id=\"movies\"></ul>\n\n    <script src=\"promise.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "ejercicios/prototype-inheritance.js",
    "content": "function Hero(name) {\r\n  this.name = name;\r\n}\r\n\r\nHero.prototype.saludar = function () {\r\n  console.log(`Hola, soy ${this.name}`);\r\n}\r\n\r\nconst zelda = new Hero('Zelda');\r\n\r\n// Propiedades de la instancia\r\nconsole.log(`New: ${zelda.name} `);\r\n// Propiedades de la \"clase\".\r\nconsole.log(`saludar: ${zelda.saludar} `);\r\n\r\n// Propiedades heredadas de ej: toString\r\nconsole.log('toString: ', zelda.toString);\r\n\r\n// hasOwnProperty (de dónde sale toString o esto?)\r\nconsole.log('zelda.hasOwnProperty(\"name\"): ', zelda.hasOwnProperty('name'));\r\nconsole.log('zelda.hasOwnProperty(\"saludar\"): ', zelda.hasOwnProperty('saludar'));\r\n"
  },
  {
    "path": "ejercicios/prototype.js",
    "content": "// Un objeto común y corriente\r\n// const zelda = {\r\n//   name: \"Zelda\"\r\n// }\r\n// zelda.saludar = function () {\r\n//   console.log(`Hola soy ${this.name}`);\r\n// }\r\n// zelda.saludar();\r\n\r\n// const link = {\r\n//   name: \"Link\"\r\n// }\r\n// link.saludar = function () {\r\n//   console.log(`Hola soy ${this.name}`);\r\n// }\r\n// link.saludar();\r\n\r\n// Seamos un poco más eficientes\r\n// function Hero(name) {\r\n//   const hero = {\r\n//     name: name,\r\n//   }\r\n//   hero.saludar = function () {\r\n//     console.log(`Hola soy ${this.name}`);\r\n//   }\r\n\r\n//   return hero;\r\n// }\r\n// const zelda = Hero('Zelda');\r\n// zelda.saludar();\r\n\r\n// const link = Hero(\"Link\");\r\n// link.saludar();\r\n\r\n// Aun podemos mejorar más y evitar tener que crear la misma función cada vez\r\n// const heroMethods = {\r\n//   saludar: function () {\r\n//     console.log(`Me llamó ${this.name}`);\r\n//   }\r\n// }\r\n// function Hero(name) {\r\n//   const hero = {\r\n//     name: name,\r\n//   }\r\n//   hero.saludar = heroMethods.saludar;\r\n\r\n//   return hero;\r\n// }\r\n// const zelda = Hero('Zelda');\r\n// zelda.saludar();\r\n\r\n// const link = Hero(\"Link\");\r\n// link.saludar();\r\n\r\n// Object create\r\n// const heroMethods = {\r\n//   saludar: function () {\r\n//     console.log(`Soy un super heroe ${this.name}`);\r\n//   }\r\n// }\r\n// function Hero(name) {\r\n//   const hero = Object.create(heroMethods);\r\n//   hero.name = name;\r\n\r\n//   return hero;\r\n// }\r\n// const zelda = Hero('Zelda');\r\n// zelda.saludar();\r\n\r\n// const link = Hero(\"Link\");\r\n// link.saludar();\r\n\r\n// Métodos de Hero dentro de Hero\r\n// function Hero(name) {\r\n//   const hero = Object.create(Hero.prototype);\r\n//   hero.name = name;\r\n//   return hero;\r\n// }\r\n\r\n// Hero.prototype.saludar = function () {\r\n//   console.log(`Soy una super heroina ${this.name}`);\r\n// }\r\n\r\n// const zelda = Hero('Zelda');\r\n// zelda.saludar();\r\n\r\n// const link = Hero(\"Link\");\r\n// link.saludar();\r\n\r\n// new es un atajo (azucar sintactica) para llevar Hero.prototype al objeto\r\n\r\nfunction Hero(name) {\r\n  // const hero = Object.create(Hero.prototype);\r\n  this.name = name;\r\n  // return this impliciamente\r\n}\r\n\r\nHero.prototype.saludar = function () {\r\n  console.log(`New: ${this.name}`);\r\n}\r\n\r\nconst zelda = new Hero('Zelda');\r\nzelda.saludar();\r\n\r\nconst link = new Hero(\"Link\");\r\nlink.saludar();"
  },
  {
    "path": "ejercicios/proxy.js",
    "content": "// target es mi objeto a supervisar (sus propiedades pueden ser objetos, array, funciones, u otro proxy)\r\nconst target = {\r\n  red: 'Rojo',\r\n  green: 'Verde',\r\n  blue: 'Azul'\r\n}\r\n// handler es un objeto con funciones (trampa) que definen las acciones a seguir cuando se accede al objeto supervisado\r\nconst handler = {\r\n  get(obj, prop) {\r\n    if (prop in obj) {\r\n      // si la propiedad existe, pues retornamos su valor\r\n      return obj[prop]\r\n    }\r\n\r\n    // Si llega hasta aqui, vamos a ver si podemos retornar una sugerencia\r\n    const suggetion = Object.keys(obj).find(key => {\r\n      // creo un objeto con todas mis claves del objeto supervisado, y retorno aquella (nombre) \r\n      // que su distancia sea <= 3 tomando como base la propiedad invocada\r\n      return Levenshtein.get(key, prop) <= 3 \r\n    })\r\n\r\n    \r\n    if (suggetion) {\r\n      console.log(`${prop} no se encontró. ¿Quisiste decir ${suggetion}?`);\r\n    }\r\n\r\n    return obj[prop];\r\n  }\r\n}\r\nconst p = new Proxy(target, handler);\r\n\r\np.red; // \"Rojo\"\r\np.green; // \"Verder\"\r\np.reed //reee no se encontró. ¿Quisiste decir red?\r\np.geen //reee no se encontró. ¿Quisiste decir green?"
  },
  {
    "path": "ejercicios/scope.js",
    "content": "// Global scope\r\nvar message = 'Hola, Senior';\r\nvar $ = function (message) {\r\n  console.log(`Say: ${message}`)\r\n}\r\n\r\n// Funcion Scope \r\nfunction printNumbers() {\r\n  var i; // No importa si declaramos i adentro javascript lo ejecutará siempre así cuando se trata de var.\r\n  for (i = 0; i < 10; i++) {\r\n    setTimeout(() => { \r\n      console.log(i);\r\n    }, 100);\r\n  }\r\n}\r\n\r\nfunction printNumbers2() {\r\n  var i\r\n  for (i = 0; i < 10; i++) {\r\n    function eventuallyPrintNumber(n) {\r\n      setTimeout(() => { \r\n        console.log(n);\r\n      }, 100);\r\n    }\r\n\r\n    eventuallyPrintNumber(i)\r\n  }\r\n}\r\n\r\n// Block Scope\r\nfunction printNumbers3() {\r\n  for (let i = 0; i < 10; i++) {\r\n      setTimeout(() => { \r\n        console.log(i);\r\n      }, 100);\r\n  }\r\n}"
  },
  {
    "path": "ejercicios/this.js",
    "content": "// this en el scope global\r\nconsole.log(`this: ${this}`);\r\n\r\n// this en el scope de una función\r\n// function whoIsThis() {\r\n//   return this;\r\n// }\r\n// console.log(whoIsThis());\r\n\r\n// this en el scope de una función strict mode \r\nfunction whoIsThisStrictMode() {\r\n  \"use strict\";\r\n  return this;\r\n}\r\n// undefine\r\nconsole.log(`whoIsThisStrictMode: ${whoIsThisStrictMode()}`);\r\n\r\n// this en el constexto de un objeto \r\nconst person = {\r\n  name: \"Gabriel\",\r\n  saludar: function () {\r\n    console.log(`hola soy ${this.name}`);\r\n  }\r\n}\r\nconsole.log(person.saludar());\r\n\r\n// this cuando sacamos una función de un objeto \r\nconst accion = person.saludar;\r\naccion();\r\n\r\n// This en el contexto de una Clase(Prototype);\r\nfunction Person(name, lastName) {\r\n  this.name = name;\r\n  this.lastName = lastName;\r\n}\r\n\r\nPerson.prototype.saludar = function () {\r\n  console.log(`Me llamó ${this.name} ${this.lastName}`);\r\n}\r\n\r\nconst jasan = new Person('Jasan', 'Hernández');\r\njasan.saludar();"
  },
  {
    "path": "mediaplayer/.gitignore",
    "content": "node_modules\r\nlib"
  },
  {
    "path": "mediaplayer/package.json",
    "content": "{\n  \"name\": \"@jasanhdz/mediaplayer\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"build\": \"tsc src/**/*.ts --outDir lib\",\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"author\": \"Jasan Hernández <jasan814@gmail.com>\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"typescript\": \"^3.6.3\"\n  }\n}\n"
  },
  {
    "path": "mediaplayer/src/MediaPlayer.ts",
    "content": "class MediaPlayer {\r\n  media: HTMLMediaElement;\r\n  plugins: Array<any>;\r\n  container: HTMLElement;\r\n\r\n  constructor(config: any) {\r\n    this.media = config.el;\r\n    this.plugins = config.plugins || [];\r\n    this.initPlayer();\r\n    this.initPlugins();\r\n  }\r\n\r\n  initPlayer() {\r\n    this.container = document.createElement('div');\r\n\r\n    this.media.parentNode.insertBefore(this.container, this.media);\r\n    this.container.appendChild(this.media);\r\n    this.container.style.position = 'relative';\r\n  }\r\n\r\n  private initPlugins() {\r\n    this.plugins.forEach(plugin => {\r\n      plugin.run(this);\r\n    });\r\n  }\r\n\r\n  pause() {\r\n    this.media.pause();\r\n  }\r\n\r\n  play() {\r\n    if (this.media.paused)\r\n      this.media.play();\r\n    else\r\n      this.media.pause();\r\n  }\r\n\r\n  muted() {\r\n    this.media.muted ?\r\n      this.unmuted() :\r\n      this.media.muted = true;\r\n  }\r\n\r\n  unmuted() {\r\n    this.media.muted = false;\r\n  }\r\n}\r\n\r\n \r\n\r\n\r\n\r\n\r\n\r\nexport default MediaPlayer;"
  },
  {
    "path": "mediaplayer/src/plugins/Ads/Ads.ts",
    "content": "import { ALL_ADS } from './ads_list.js';\r\n\r\nexport interface Ad {\r\n  imageUrl: string,\r\n  title: string,\r\n  body: string,\r\n  url: string\r\n}\r\n\r\nclass Ads {\r\n  private static instance: Ads;\r\n  private ads: Ad[];\r\n\r\n  private constructor() { \r\n    this.initAds();\r\n  }\r\n\r\n  static getInstance() {\r\n    if (!Ads.instance) {\r\n      Ads.instance = new Ads();\r\n    }\r\n\r\n    return Ads.instance;\r\n  }\r\n\r\n  private initAds() {\r\n    this.ads = [...ALL_ADS];\r\n  }\r\n\r\n  getAd() {\r\n    if (this.ads.length === 0) {\r\n      this.initAds();\r\n    }\r\n    return this.ads.pop();\r\n\r\n  }\r\n}\r\n\r\nexport default Ads;"
  },
  {
    "path": "mediaplayer/src/plugins/Ads/ads_list.js",
    "content": "export const ALL_ADS = [\r\n  {\r\n    imageUrl:\r\n      'https://static.platzi.com/media/achievements/badge-profesional-javascript-13538df2-24ce-433f-9aa6-e34eed608e70.png',\r\n    title: 'Curso Profesional de JavaScript',\r\n    body:\r\n      'Mejora tus habilidades en Javascript. Conoce Typescript y cómo puedes ocuparlo para mejorar el control de tus variables.',\r\n    url: 'https://platzi.com/cursos/javascript-profesional/',\r\n  },\r\n\r\n  {\r\n    imageUrl:\r\n      'https://static.platzi.com/media/achievements/badge-frontend-developer-8a49e681-3e22-408d-b886-2f47dfc9953a.png',\r\n    title: 'Curso de Frontend Developer',\r\n    body:\r\n      'Domina las bases de HTML y CSS. Define la arquitectura de tu código y construye un sitio web usando componentes estáticos. ',\r\n    url: 'https://platzi.com/cursos/frontend-developer/',\r\n  },\r\n\r\n  {\r\n    imageUrl:\r\n      'https://static.platzi.com/media/achievements/badge-backend-node-8e6aa8a9-f7cd-42b7-bf4a-e1ee916a942b.png',\r\n    title: 'Curso de Backend con Node.js',\r\n    body:\r\n      'Crea aplicaciones backend utilizando Node.js, Express y Mongo. Entiende cómo funciona Javascript en un servidor y escribe aplicaciones con Node.js.',\r\n    url: 'https://platzi.com/cursos/backend-nodejs/',\r\n  },\r\n\r\n  {\r\n    imageUrl:\r\n      'https://static.platzi.com/media/achievements/badge-prework-da6b0493-9908-40f3-ad53-f5d330b995b8.png',\r\n    title:\r\n      'Comienza tus proyectos de desarrollo para JavaScript configurando un entorno de desarrollo cómodo y adaptado a tus necesidades.',\r\n    body:\r\n      'Mejora tus habilidades en Javascript. Conoce Typescript y cómo puedes ocuparlo para mejorar el control de tus variables.',\r\n    url: 'https://platzi.com/cursos/prework/',\r\n  },\r\n\r\n  {\r\n    imageUrl:\r\n      'https://static.platzi.com/media/achievements/badge-autenticacion-passport-6d45426a-2b24-4757-8927-7bfaf54529dd.png',\r\n    title: 'Curso de Autenticación con Passport.js',\r\n    body:\r\n      'Genera estrategias de autenticación Sign-In y Sign-Out usando Passport.js. Agrega autenticación con Facebook, Twitter y Google a tus desarrollos.',\r\n    url: 'https://platzi.com/cursos/passport/',\r\n  },\r\n\r\n  {\r\n    imageUrl:\r\n      'https://static.platzi.com/media/achievements/badge-backend-frontend-02b2ac18-331a-4959-85bf-0bd3c2aa009c.png',\r\n    title: 'Curso de Backend for Frontend',\r\n    body:\r\n      'La ingeniería de software evoluciona día a día, no te quedes atrás. Ahora que eres un Desarrollador FullStack JavaScript necesitas evolucionar con el software, construye arquitecturas de software modernas.',\r\n    url: 'https://platzi.com/cursos/bff/',\r\n  },\r\n\r\n  {\r\n    imageUrl:\r\n      'https://static.platzi.com/media/achievements/badge-react-adec89d0-1c35-4c9c-847e-18c284dc79dd.png',\r\n    title: 'Curso Práctico de React JS',\r\n    body:\r\n      'React es una de las librerías más utilizadas hoy para crear aplicaciones web. Aprende a través de la creación de la interfaz de PlatziVideo todo lo que necesitas para crear increíbles componentes con React.      ',\r\n    url: 'https://platzi.com/cursos/react-ejs/',\r\n  },\r\n\r\n  {\r\n    imageUrl:\r\n      'https://static.platzi.com/media/achievements/badge-react-redux-2ca3c0a5-fc53-437f-bfba-69e9ddd5a803.png',\r\n    title: 'Curso de React Router y Redux',\r\n    body:\r\n      'Aprende de forma práctica a implementar React Router para manejar rutas en tus proyectos de frontend como un profesional.',\r\n    url: 'https://platzi.com/cursos/react-router-redux/',\r\n  },\r\n];"
  },
  {
    "path": "mediaplayer/src/plugins/Ads/index.ts",
    "content": "import MediaPlayer from '../../MediaPlayer';\r\nimport Ads, {Ad} from './Ads';\r\n\r\nclass AdsPlugin {\r\n  private player: MediaPlayer;\r\n  private media: HTMLMediaElement;\r\n  private ads: Ads;\r\n  private currentAd: Ad;\r\n  private adsContainer: HTMLElement;\r\n\r\n  constructor() {\r\n    this.ads = Ads.getInstance()\r\n    this.adsContainer = document.createElement('div');\r\n  }\r\n\r\n  run(player: MediaPlayer) {\r\n    this.player = player;\r\n    this.player.container.appendChild(this.adsContainer);\r\n    this.media = this.player.media;\r\n    this.media.addEventListener('timeupdate', this.handleTimeUpdate.bind(this));\r\n  }\r\n\r\n  private handleTimeUpdate() {\r\n    const currentTime = Math.floor(this.media.currentTime);\r\n    if (currentTime % 30 === 0) {\r\n      this.renderAd();\r\n    }\r\n  }\r\n\r\n  private renderAd() {\r\n    if (this.currentAd) {\r\n      return;\r\n    }\r\n    const ad = this.ads.getAd();\r\n    this.currentAd = ad;\r\n    console.log(this.currentAd);\r\n    // this.adsContainer.style.position = 'absolute';\r\n    // <a class=\"ads__link\"href=\"${this.currentAd.url}\"target=\"_blank\">\r\n    this.adsContainer.innerHTML = `\r\n      <div class=\"ads\">\r\n          <img class=\"ads__img\"src=\"${this.currentAd.imageUrl}\" />\r\n          <div class=\"ads__info\">\r\n            <h5 class=\"ads__title\">${this.currentAd.title}</h5>\r\n            <p class=\"ads__body\">${this.currentAd.body}</p>\r\n          </div>\r\n          </div>\r\n          `;\r\n          \r\n          // </a>\r\n    setTimeout(() => {\r\n      this.currentAd = null;\r\n      this.adsContainer.innerHTML = \"\";\r\n    }, 10000);\r\n\r\n  }\r\n}\r\n\r\nexport default AdsPlugin;"
  },
  {
    "path": "mediaplayer/src/plugins/AutoPause.ts",
    "content": "import MediaPlayer from '../MediaPlayer'\r\nclass AutoPause {\r\n  private threshold: number;\r\n  player: MediaPlayer;\r\n  constructor() {\r\n    this.threshold = 0.25;\r\n    this.handlerIntersection = this.handlerIntersection.bind(this)\r\n    this.handleVisibilityChange = this.handleVisibilityChange.bind(this);\r\n  }\r\n  run(player) {\r\n    this.player = player;\r\n    // const observer = new IntersectionObserver(handler, config)\r\n    const observer = new IntersectionObserver(this.handlerIntersection, {\r\n      // threshold: umbral define que porciento del elemento tiene que tener interseccion\r\n      threshold: this.threshold\r\n    })\r\n\r\n    observer.observe(this.player.media) \r\n\r\n    document.addEventListener('visibilitychange', this.handleVisibilityChange)\r\n  }\r\n  private handleVisibilityChange() {\r\n    const isVisible = document.visibilityState === \"visible\";\r\n    if (isVisible) {\r\n      this.player.play();\r\n    } else {\r\n      this.player.pause();\r\n    }\r\n  }\r\n  // Cuando intersectionObserver llame a handlerIntersection le va a pasar una lista de entries\r\n  // los entries son todos los objetos que estamos observando \r\n  private handlerIntersection(entries: IntersectionObserverEntry[]) {\r\n    const entry = entries[0];\r\n    // console.log(entry);\r\n\r\n    const isVisible = entry.intersectionRatio >= this.threshold\r\n\r\n    if (isVisible) {\r\n      this.player.play();\r\n    } else {\r\n      this.player.pause();\r\n    }\r\n  }\r\n}\r\nexport default AutoPause;"
  },
  {
    "path": "mediaplayer/src/plugins/AutoPlay.ts",
    "content": "import MediaPlayer from '../MediaPlayer'\r\n\r\nclass AutoPlay {\r\n  constructor() { }\r\n  run(player: MediaPlayer) {\r\n    if (!player.media.muted) {\r\n      player.media.muted = true;\r\n    }\r\n    player.play();\r\n  }\r\n}\r\n\r\n\r\nexport default AutoPlay;"
  },
  {
    "path": "notes/readme.md",
    "content": "<div align=\"center\">\r\n  <h1>JavaScript Profesional</h1>\r\n</div>\r\n\r\n## Tabla de Contenido\r\n- [¿Cómo llega un script al navegador?](#como-llegá-un-script-al-navegador)\r\n- [Scope](#scope)\r\n- [Clouseres](#clouseres)\r\n- [¿Quién es This?](#quién-es-this)\r\n- [Métodos Call y Apply](#métodos-call-y-apply)\r\n  - [Evitar confundir Apply y Call](#evitar-confundir-apply-y-call)\r\n- [Bind](#bind)\r\n- [Diferencias Apply, Call y Bind](#diferencias-apply-call-y-bind)\r\n- [Prototype](#prototype)\r\n- [Object create](#object-create)\r\n- [Herencia Prototipal](#herencia-prototipal)\r\n- [¿Cómo funciona Javascript?](#como-funciona-javascript)\r\n  - [Analizador y Abstract Syntax Tree](#analizador-y-abstract-syntax-tree)\r\n  - [Fallo en el Parset](#fallo-en-el-parset)\r\n  - [Eager Parsing (Parser de V8)](#eager-parsing-parser-de-v8))\r\n  - [Lazy Parsing](#lazy-parsing)\r\n  - [Tokens](#tokens)\r\n  - [Abstract Syntax Tree](#abstract-syntax-tree)\r\n- [Abstract Syntax Tree en Práctica](#abstract-syntax-tree-en-práctica)\r\n- [Cómo funciona el Javascript Engine](#como-funciona-el-javascript-engine)\r\n  - [Bytecode vs Machine Code](#bytecode-vs-machine-code)\r\n  - [SpiderMonkey vs V8](#spidermonkey-vs-v8)\r\n- [Event Loop](#event-loop)\r\n  - [EventLoop con Asincronía](#eventloop-con-asincronia)\r\n  - [Task Queue](#task-queue)\r\n  - [Event Loop con Promesas](#event-loop-con-promesas)\r\n- [Promesas](#promesas)\r\n- [Getters y Setters](#getters-y-setters)\r\n- [Proxy](#proxy)\r\n- [Generadores](#generadores)\r\n- [Cómo cancelar peticiones Fetch](#como-cancelar-peticiones-fetch)\r\n- [Intersection Observer API](#intersection-observer-api)\r\n  - [Creando un Intersection Observer](#creando-un-intersection-observer)\r\n  - [Opciones de Intersection observer](#opciones-de-intersection-observer)\r\n  - [Determinando un elemento para ser observado](#determinando-un-elemento-para-ser-observado)\r\n- [Creación de Plugin para IntersectionObserver de nuestro videoplayer](#creación-de-plugin-para-intersectionobserver-de-nuestro-videoplayer)\r\n- [Visibility Change](#visibility-change)\r\n- [Service worker](#service-worker)\r\n- [Typescript](#typescript)\r\n  - [Tipos básicos en Typescript](#tipos-básicos-en-typescript)\r\n  - [Funciones en Typescript](#funciones-en-typescript)\r\n  - [Interfaces en Typescript](#interfaces-en-typescript)\r\n  - [Clases en Typescript](#clases-en-typescript)\r\n  - [Herencia Typescript](#herencia-typescript)\r\n- [Modificadores de Acceso en Typescript](#modificadores-de-acceso-en-typescript)\r\n  - [Público por defecto](#público-por-defecto)\r\n  - [Private](#private)\r\n  - [Protected](#protected)\r\n- [Convertir Proyecto a Typescript](#convertir-proyecto-a-typescript)\r\n  - [Refactorización](#refactorización)\r\n- [Patrones de diseño](#patrones-de-diseño)\r\n- [Objetivos de los patrones de diseño](#objetivos-de-los-patrones-de-diseño)\r\n  - [Historia sobre Patrones de diseño](#historia-sobre-patrones-de-diseño)\r\n  - [Beneficios de utilizar patrones de diseño](#beneficios-de-utilizar-patrones-de-diseño)\r\n  - [Desventajas de utilizar patrones de diseño](#desventajas-de-utilizar-patrones-de-diseño)\r\n- [Categorías de patrones de diseño](#categorias-de-patrones-de-diseño)\r\n  - [Patrones Creacionales](#patrones-creacionales)\r\n  - [Patrones estructurales](#patrones-estructurales)\r\n  - [ Patrones de comportamiento](#patrones-de-comportamiento)\r\n- [Patrón Singleton y casos de uso](#patrón-singleton-y-casos-de-uso)\r\n- [Implementación del patrón Singleton con Typescript](#implementación-del-patrón-singleton-con-typescript)\r\n  - [Es genial con Typescript](#es-genial-con-typescript)\r\n  - [Observer (patrón de diseño)](#observer-patrón-de-diseño)\r\n  - [Objetivo](#objetivo)\r\n  - [Motivación](#motivación)\r\n  - [Participantes](#participantes)\r\n- [Implicaciones sobre Observer](#implicaciones-sobre-observer)\r\n- [Implementación del patrón Observer con Typescript](#implementación-del-patrón-observer-con-typescript)\r\n- [Casos de uso del patrón Observer: Redux](#casos-de-uso-del-patrón-observer-redux)\r\n  - [Conceptos básicos](#conceptos-básicos)\r\n- [Patrón Decoratory casos de uso](#patrón-decoratory-casos-de-uso)\r\n  - [Motivation](#decorator-motivation)\r\n  - [Aplicabilidad](#decorator-aplicabilidad)\r\n  - [Estructura](#decorator-estructura)\r\n  - [Participantes](#decorator-participantes)\r\n  - [Colaboraciones](#decorator-colaboraciones)\r\n  - [Consecuencias](#decorator-consecuencias)\r\n  - [Implementación](#decorator-implementación)\r\n\r\n## ¿Cómo llega un script al navegador?\r\n\r\nEl **DOM** es la representación que hace el navegador de un documento HTML.\r\n\r\nEl navegador interpreta el archivo HTML y cuando termina de transformarlo al DOM se dispara el evento DOMContentLoaded lo que significa que todo el documento está disponible para ser manipulado.\r\n\r\nTodo script que carguemos en nuestra página tiene un llamado y una ejecución.\r\n\r\nTanto con **async** como **defer** podemos hacer llamados asíncronos, pero tiene sus diferencias:\r\n\r\n- **async**. Con async podemos hacer la petición de forma asíncrona y no vamos a detener la carga del DOM hasta que se haga la ejecución del código.\r\n- **defer**. La petición es igual, asíncrona como en el async pero va a deferir la ejecución del Javascript hasta el final de que se cargue todo el documento.\r\n- **scripts embebidos**: el navegador carga línea a línea el HTML y cuando se encuentra un código entre scripts va a detener su ejecución hasta que haya procesado todo el script.\r\n\r\nHay que tener en cuenta que, cuando carga una página y se encuentra un script a ejecutar, toda la carga se detiene. Por eso se recomienda agregar tus scripts justo antes de cerrar el body para que todo el documento este disponible.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Scope\r\n\r\nEl Scope o ámbito es lo que define el tiempo de vida de una variable, en qué partes de nuestro código pueden ser usadas.\r\n\r\n**Global Scope**\r\nVariables disponibles de forma global se usa la palabra ```var```, son accesibles por todos los scripts que se cargan en la página. Aquí hay mucho riesgo de sobreescritura.\r\n\r\n**Function Scope**\r\nVariables declaradas dentro de una función sólo visibles dentro de ella misma (incluyendo los argumentos que se pasan a la función).\r\n\r\n**Block Scope**\r\nVariables definidas dentro de un bloque, por ejemplo variables declaradas dentro un loop while o for. Se usa **let** y **const** para declarar este tipo de variables.\r\n\r\n**Module Scope**\r\nCuando se denota un script de tipo module con el atributo ```type=\"module``` las variables son limitadas al archivo en el que están declaradas.\r\n\r\nEsto va a declarar que este archivo es un módulo. Esto no está en todos los navegadores pero sí en los más modernos. Los valores que teníamos escritos ahora no los vamos a poder leer en consola porque el module scope está limitando el alcance\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Clouseres\r\n\r\nEl scope cuando lo juntamos con funciones podemos lograr algo que se llama clouseres o clausuras, para entender bien vemos un ejemplo:\r\n\r\n```js\r\n// Clouseres\r\n// printColor\r\nlet color = 'green';\r\nfunction printColor() {\r\n  console.log(color);\r\n}\r\n```\r\n\r\nPodemos observar que la variable ```color``` está en el scope global, para evitar eso lo que vamos a hacer es crear una función que se va a llamár autómaticamente\r\n\r\n```js\r\n// IIFE: immediately invoked function expression\r\n(function () {\r\n  let color = 'green';\r\n\r\n  function printColor() {\r\n    console.log(color);\r\n  }\r\n\r\n  printColor();\r\n})();\r\n\r\n```\r\nSacamos este codigó del entorno global, lo pasamos a uno de una función y entonces color no cruza al scope global. Cuando tenemos esta declaración y esta ejecución que se declara afuera de la función interna, **estó es un Closures**. Es la combinación del scope de una función y el scope donde fue definida, donde el scope de la función es la función *IIFE* la función principal, y adentro la función que fue definida dentro de ese scope que tiene acceso a lo que estaba afuera.\r\n\r\nClouseres nos va a permitir tener una funcionalidad o feature que el lenguaje no trae: variables privadas\r\n\r\n```js\r\n// Clousers Jasan Hernández.\r\n// ¿Variables privadas?\r\nconst counter1 = {\r\n  count: 3\r\n}\r\n// count está en el scope Global Window\r\nconsole.log(counter1.count);\r\n// Podemos modificar su valor si quisiéramos\r\ncounter1.count = 99;\r\nconsole.log(counter1.count);\r\n\r\n// Clouseres - creamos un function scope\r\nfunction makeCounter(n) {\r\n  // count ya no existe en window, ahora\r\n  // solo pertenece a la función\r\n  let count = n;\r\n  return {\r\n    increase: function () { count += 1; },\r\n    decrease: function () { count -= 1},\r\n    getCount: function () { return count; },\r\n  }\r\n}\r\nlet counter = makeCounter(7);\r\nconsole.log('This count is:', counter.getCount());\r\nconsole.log('This count is:', counter.increase());\r\nconsole.log('This count is:', counter.decrease());\r\n// No podemos cambiar el valor de count porque no \r\n// está en nuestro alcance.\r\n// ERROR FATAL\r\ncounter.count = 99;\r\n```\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## ¿Quién es This?\r\n\r\nThis se refiere a un objeto. Ese objeto es el que actualmente está ejecutando un pedazo de código.\r\n\r\nthis es un concepto que tienen muchos lenguajes de programación, sobre todo aquellos que son orientados a objetos, quizás si conoces un poco de Java sabes que cuando escribes *this* en una clase, this se va a referir a la instancia de esa clase cuando creas ese objeto. En JavaScript esto también es cierto, pero también hay otros contextos de los cuales hay que conocer para saber en qué momentos this se comporta así y en qué otros momentos this tiene valores diferentes.\r\n\r\n- Global Scope, como se comporta this con el global-scope.\r\n\r\n```js\r\n// this en el scope global\r\nconsole.log(`this: ${this}`);\r\n\r\n// this en el scope de una función\r\nfunction whoIsThis() {\r\n  return this;\r\n}\r\nconsole.log(whoIsThis());\r\n```\r\nCuando llamamos a la función whoIsThis() directamente el motor de javascript le va asignar que this va a ser ```window```, ya que es un valor que se tiene que asignar por default, excepto si estamos usando javascript en un modo estricto. El **'strict mode'**, este _strict mode_ que puedes encender manualmente solo escribiendo una cadena que diga \"use strict\", con estó comienza el modo estricto.\r\n\r\n- This en el Scope de una Función strict mode \r\n\r\nAhora usando el modo **strict mode** dentro de la siguiente función que también retorna **this** nos imprime que ahora es **undefined**, y este es justo el comportamiento que sucede cuando usamos strict mode, _strict mode_ nos ayuda a evitar algunos errores que le pueden pasar a cualquier otro programador, pero el motor de javascript va a tratar de ayudarnos y estos errores nos van a salir temprano durante la fase de desarrollo y no en producción, y un error es mejor tenerlo en desarrollo que en producción. \r\n\r\n```js\r\n// this en el scope de una función strict mode \r\nfunction whoIsThisStrictMode() {\r\n  \"use strict\";\r\n  return this;\r\n}\r\n// undefined\r\nconsole.log(`whoIsThisStrictMode: ${whoIsThisStrictMode()}`);\r\n```\r\n\r\n- This en el contexto de un objeto\r\n\r\nthis se refiere al objeto que actualmente está ejecutando un pedazo de código, por lo tanto this va a ser todo este objeto. ejemplo:\r\n\r\n```js\r\n// this en el constexto de un objeto \r\nconst person = {\r\n  name: \"Gabriel\",\r\n  saludar: function () {\r\n    console.log(`hola soy ${this.name}`);\r\n  }\r\n}\r\nconsole.log(person.saludar());\r\n```\r\n\r\n- This cuando sacamos una función de un objeto.\r\n\r\n```js\r\nconst person = {\r\n  name: \"Gabriel\",\r\n  saludar: function () {\r\n    console.log(`hola soy ${this.name}`);\r\n  }\r\n}\r\n// this cuando sacamos una función de un objeto \r\nconst accion = person.saludar;\r\naccion();\r\n```\r\nAhora nos aparece undefined porque ```accion``` no se está llamando dentro del contexto de un objeto, simplemente se está llamado directamente similar como lo hicimos arriba en las funciones directas, por lo tanto el mensaje se mostrará incompleto cuando se intenta usar this.\r\n\r\n- This en el contexto de una clase\r\n\r\nLas clases como tál no existen en javascript, al menos no son como las clases de java o de c++, pero resulta útil llamarles clases a estas funciones especiales que llamamos con new.\r\n\r\nTodas las funciones tienen un valor de this, lo que sucede es que ese valor de this es un objeto vacío, en otras palabras, this comienza siendo estó ```this = {}```.\r\nNo puedes asignar this directamente, pero si puedes asignar una propiedad de this.\r\n\r\n```js\r\n// This en el contexto de una Clase(Prototype);\r\nfunction Person(name, lastName) {\r\n  this.name = name;\r\n  this.lastName = lastName;\r\n}\r\n\r\nPerson.prototype.saludar = function () {\r\n  console.log(`Me llamo ${this.name} ${this.lastName}`);\r\n}\r\n\r\nconst Jasan = new Person('Jasan', 'Hernández');\r\nJasan.saludar();\r\n```\r\nEn el contexto de objetos que fueron instanciados de una clase, **this** se va a referir a la instancia de ese objeto, no se va ha referir a ```Person``` ni a ```Person.prototype.saludar```, sino que se va a referir a ```Jasan```, que es el objeto que está ejecutando a ```saludar```. \r\n\r\nY cuando asignamos los valores de ``this.name = name`` lo estamos haciendo sobre la instancia, no sobre el objeto prototipal.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Métodos Call y Apply.\r\n\r\nThis no es un valor que podemos asignar directamente, no podemos escribir this = 'valor', pero sí existen unos métodos que son parte del prototipo de function *call, apply, bind*. Estos 3 métodos nos van a ayudar a establecer cuál es el this que va a ser el contexto de la llamada a una función .\r\n\r\n- Establece this usando 'call'\r\n\r\n```js\r\n// Establece this usando 'call'\r\nfunction saludar() {\r\n  console.log(`Hola soy ${this.name} ${this.lastname}`)\r\n}\r\n```\r\nTenemos una función que no está en el contexto de un objeto ni de niguna clase, con la ayuda de call vamos a establecer cuál va a ser el this.\r\n\r\n```js\r\nfunction saludar() {\r\n  console.log(`Hola soy ${this.name} ${this.lastname}`)\r\n}\r\nconst richard = {\r\n  name: 'Richard',\r\n  lastname: 'Lopez'\r\n}\r\nsaludar.call(richard)\r\n```\r\nAquí lo que hicimos fue establecer el valor de this para la función saludar, pero a veces las funciones sí reciben argumentos.\r\n\r\n- Establece this usando 'call' y pasar argumentos a la función.\r\n\r\n```js\r\nconst richard = {\r\n  name: 'Richard',\r\n  lastname: 'Lopez'\r\n}\r\nfunction caminar(metros, direccion) {\r\n  console.log(`${this.name} camina ${metos} metros hacia ${direccion}`);\r\n}\r\ncaminar.call(richard, 400, 'norte');\r\n```\r\nLo primero es establecer el contexto del this para ```caminar``` usando call(richard) pero además tenemos algunos argumentos. Cuando esto no sucede tenemos que pasar los argumentos además de pasar el contexto.\r\n\r\n- Establece this usando 'apply' y pasar argumentos a la función.\r\n\r\n**apply** hace la misma funcionalidad que *call* pero sus argumentos los pasamos de una forma ligeramente diferente, así que vamos a seguir usando el ejemplo de caminar y vamos usar apply que usa el mismo argumento que tiene call, que en este caso el this será richard. Pero, en lugar de pasar los argumentos separados por comas,  vamos a pasarlos como **parte de un arreglo** y en ese arreglo van todos los argumentos que queramos.\r\n\r\n```js\r\nconst richard = {\r\n  name: 'Richard',\r\n  lastname: 'Lopez'\r\n}\r\nfunction caminar(metros, direccion) {\r\n  console.log(`${this.name} camina ${metos} metros hacia ${direccion}`);\r\n}\r\ncaminar.apply(richard, [400, 'norte']);\r\n// también podemos pasarle un arreglo\r\nconst valores = [200, 'sur'];\r\ncaminar.apply(richard, valores)\r\n```\r\nEs lo mismo, pero nos podemos enfrentar donde hay situaciones donde es más fácil usar el call y hay lugares donde es más fácil usar el apply. Sobre todo si son valores que son una lista de valores.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Evitar confundir Apply y Call\r\n\r\nCall = Commas\r\nApply = Areglo\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Bind\r\n\r\nbind() es parte de este conjunto de: call, apply, bind. Sin embargo, bind no va a llamar la función automáticamente, sino que va a construir una nueva función, esta nueva función va a tener el this que le pasamos ya integrado y cuando llamemos a está nueva función se va a ejecutar.\r\n\r\n```js\r\n// Establecer una nueva función usando bind()\r\nfunction saludar() {\r\n  console.log(`Hola soy ${this.name} ${this.lastname}`)\r\n}\r\nconst daniel = {\r\n  name: \"Daniel\",\r\n  lastname: \"Sanchez\"\r\n}\r\nconst danielSaluda = saludar.bind(daniel);\r\ndanielSaluda();\r\n```\r\n\r\n- ¿Cómo le haríamos si necesitáramos pasar argumentos a esta función a la que estamos bindeando?\r\n\r\n```js\r\nfunction saludar() {\r\n  console.log(`Hola soy ${this.name} ${this.lastname}`)\r\n}\r\nfunction caminar(metros, direccion) {\r\n  console.log(`${this.name} camina ${metos} metros hacia ${direccion}`);\r\n}\r\nconst daniel = {\r\n  name: \"Daniel\",\r\n  lastname: \"Sanchez\"\r\n}\r\nconst danielSaluda = saludar.bind(daniel);\r\ndanielSaluda();\r\n\r\nconst danielCamina = caminar.bind(daniel);\r\ndanielCamina(1000, 'SurOeste');\r\n```\r\nExiste otra forma de pasar estos argumentos, y es muy interesante porque permite harcodear estos argumentos, y en lugar de escribirlos dentro de la nueva función los escribimos despues del **this**.\r\n\r\n```js\r\nconst danielCamina = caminar.bind(daniel, 1000, 'SurOeste');\r\ndanielCamina();\r\n```\r\n\r\nEsto se vuelve más interesante porque podemos guardar argumentos parciales, es decir, poner argumentos en ambas funciones, tanto el funció que genera como a la llamada a la nueva función:\r\n\r\n```js\r\nconst danielCamina = caminar.bind(daniel, 1000);\r\ndanielCamina('SurOeste');\r\n```\r\n\r\nEsta técnica se llama kurin, donde guardamos parcialmente algunos argumentos y luego llenamos los demás, es una ténica funcional que es muy poderosa y que te va a permitir hacer funciones reutilizables para contextos donde solo parcialmente está establecido un valor.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Diferencias Apply, Call y Bind\r\n\r\nCall y Apply van a establecer el this y va a llamar la función inmediatamente, bind va a crear una nueva función donde this estará guardado y luego tocará guardar y ejecutar esa nueva función.\r\n\r\nExisten veces que tenemos objetos que se parecen a otros, por ejemplo: *cuando usamos un getElementByClassName* del *DOM* lo que nos regresa es un tipo de de objeto **nodeList**, **no es un array**, por lo tanto **no tienen** todos lo **métodos** que tiene el array como el **forEach**\r\n\r\nDOM:\r\n```html\r\n<body>\r\n  <ul>\r\n    <button class=\"call-to-action\">Aprender</button>\r\n    <button class=\"call-to-action\">Aprender Más</button>\r\n    <button class=\"call-to-action\">¡Nunca pares de aprender!</button>\r\n  </ul>\r\n  <script src=\"call-apply-bind.js\"></script>\r\n</body>\r\n```\r\nObteniendo los botones del Dom:\r\n```js\r\n// Cuando es útil uno de estós métodos \r\nconst buttons = document.getElementsByClassName(\"call-to-action\");\r\nbuttons.forEach(button => {\r\n  button.onclick = () => alert('Nunca pares de aprender');\r\n});\r\n\r\n// No es una funcion forEach porque button es NodeList\r\n```\r\nNo es una funcion forEach porque button es NodeList, es por eso que el código de arriba nos marcará un error.\r\n\r\nLos nodeList se parecen a los arreglos, pero no del todo, lo que sí sabemos es que tienen una propiedad que se llama length y esta es suficiente para hacer alguna de las operaciones de arreglos.\r\n\r\nAhora lo que podemos hacer es lo siguiente:\r\n\r\nVamos a llamar al forEach a través del array, porque foreach es una propiedad del prototype que entonces le podemos cambiar el this usando call(), donde le pasamos el nuevo this y ejecutamos la función por cada elemento como si usaramos un forEach de un arreglo.\r\n\r\n```js\r\n// Cuándo es útil uno de estós métodos \r\nconst buttons = document.getElementsByClassName(\"call-to-action\");\r\n\r\n// Obtenemos la función foreach de Un arreglo y le cambiamos this. para que haga referencia a buttons y de este modo recorrer el arreglo.\r\nArray.prototype.forEach.call(buttons, button => {\r\n  button.onclick = () => alert('Nunca pares de aprender');\r\n})\r\n```\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Prototype\r\n\r\nSi hay un tema que hace que a todos los desarrolladores de javascript nos explote la cabeza de lo difícil que es, es este: **Prototype** es un concepto casi único de javascript que es parte de como normalmente manejamos lenguajes y objetos en lenguajes de programación, las clases son como un plano en Java, lo escribimos y luego instanciamos objetos, si queremos crear una clase que hereda de otra clase y volvemos a instanciar otros objetos, pero en javascript todos son objetos.\r\n\r\n- Ejemplo de objeto comú y corriente:\r\n\r\n```js\r\n// Un objeto común y corriente\r\nconst zelda = {\r\n  name: \"Zelda\"\r\n}\r\nzelda.saludar = function () {\r\n  console.log(`Hola soy ${this.name}`);\r\n}\r\nzelda.saludar();\r\n\r\nconst link = {\r\n  name: \"Link\"\r\n}\r\nlink.saludar = function () {\r\n  console.log(`Hola soy ${this.name}`);\r\n}\r\nlink.saludar();\r\n```\r\nEsto es algo ineficiente, estamos creando una función por cada uno de los 2 objetos y además los objetos son similares y los tenemos que escribir a mano.\r\n\r\n- Escribiendo una función que haga más eficiente a nuestro objeto.\r\n\r\n```js\r\n// Seamos un poco más eficientes\r\nfunction Hero(name) {\r\n  const hero = {\r\n    name: name,\r\n  }\r\n  hero.saludar = function () {\r\n    console.log(`Hola soy ${this.name}`);\r\n  }\r\n\r\n  return hero;\r\n}\r\nconst zelda = Hero('Zelda');\r\nzelda.saludar();\r\n\r\nconst link = Hero(\"Link\");\r\nlink.saludar();\r\n```\r\nAquí hay un poco de ineficiencia, ya que esta función saludar la estamos definiendo cada vez llamamos a Hero.\r\n\r\nPodemos ser un poco más eficientes y tener un método que tenga la colección de métodos para los Heros \r\n\r\n- Aun podemos mejorar más y evitar tener que crear la misma función cada vez\r\n\r\nLo logramos creando un objeto externo llamado **heroMethods**, el cual tiene una función saludar como propiedad, la cual solo se está definiedo una sola vez. Y a nuestro objeto hero en su método saludar solo le pasamos la referencia de el objeto externo *heroMethods.saludar*\r\n\r\n```js\r\n// Aun podemos mejorar más y evitar tener que crear la misma función cada vez\r\nconst heroMethods = {\r\n  saludar: function () {\r\n    console.log(`Me llamó ${this.name}`);\r\n  }\r\n}\r\nfunction Hero(name) {\r\n  const hero = {\r\n    name: name,\r\n  }\r\n  hero.saludar = heroMethods.saludar;\r\n\r\n  return hero;\r\n}\r\nconst zelda = Hero('Zelda');\r\nzelda.saludar();\r\n\r\nconst link = Hero(\"Link\");\r\nlink.saludar();\r\n```\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Object create\r\n\r\nRecibe un objeto y lo que hace es crear un nuevo objeto, como lo dice su nombre\r\n```js\r\nconst nuevoObjeto = Object.create({});\r\n```\r\nEste nuevo objeto va a contener todas las propiedades que este objeto tiene definido, esto la da algo parecido a 'super poderes'. Usando el ejemplo de prototypes quedaría de la siguiente manera:\r\n\r\n```js\r\n// Object create\r\nconst heroMethods = {\r\n  saludar: function () {\r\n    console.log(`Soy un super heroe ${this.name}`);\r\n  }\r\n}\r\nfunction Hero(name) {\r\n  const hero = Object.create(heroMethods);\r\n  hero.name = name;\r\n\r\n  return hero;\r\n}\r\nconst zelda = Hero('Zelda');\r\nzelda.saludar();\r\n\r\nconst link = Hero(\"Link\");\r\nlink.saludar();\r\n```\r\n\r\nAnalícemos lo que esta haciendo object create, porque va más allá de copiar propiedades de un objeto a uno nuevo. Si nostros ejecutamos al objeto zelda y a heroMethods, nos aparecerán 2 objetos tal cual como los habíamos definido. \r\n\r\nSi intentamos crear un nuevo objeto directo desde la consola del navegador pasará algo interesante.\r\n\r\n```js\r\nzelda\r\nheroMethods\r\nconst newHero = Object.create(heroMethods);\r\n```\r\nCuando nosotros creamos un nuevo objeto con ```Object.create``` nuestro objeto aparentemente se mostrará vacío, pero si nosotros intentamos ingresar a una propiedad del objeto sí aparecerá definido. Esto es gracias a un objeto que sí se nos imprimió, el cual aparece dentro del nuevo objeto con un color azul desvanecido el cual se llama **_proto_**.\r\n\r\nNostros accedemos a newHero.saludar sin estar definido dentro del objeto mismo, esto sucede gracias a la **herencia prototipal**. Por ahora basta con que entendamos que **todo lo que estaba en heroMethods** pasó al **_proto_** de **newHero** \r\n\r\nModificaremos el object Hero agregando la función saludar de heroMethods porque la propiedad saludar le debería pertenecer a Hero, ya que es una función que esta ocupando el objeto. El lugar para hacer esto que se nos recomienda es hacerlo dentro de su método prototype, inicialmente prototype es un objeto vacío. Pero como es un objeto le podemos añadir nuevas propiedades\r\n\r\n```js\r\n// Métodos de Hero dentro de Hero\r\nfunction Hero(name) {\r\n  const hero = Object.create(Hero.prototype);\r\n  hero.name = name;\r\n  return hero;\r\n}\r\n\r\nHero.prototype.saludar = function () {\r\n  console.log(`Soy una super heroina ${this.name}`);\r\n}\r\n\r\nconst zelda = Hero('Zelda');\r\nzelda.saludar();\r\n\r\nconst link = Hero(\"Link\");\r\nlink.saludar();\r\n```\r\n\r\n- new es un atajo (azúcar sintáctica) para llevar Hero.prototype al objeto \r\n\r\nSeguro has usado un keyword que se llamá **new**. Desde ahora te advierto que new es un atajo lo que le llamamos azúcar sintáctica, es decir, es algo que le añadimos al lenguaje para facilitar algunos procesos, pero son cosas que ya podemos hacer y justo tiene que ver con Object.create.\r\n\r\nPrimero comenzamos añadiendo new cada vez que queremos instanciar un nuevo objeto.\r\n\r\n```js\r\nconst zelda = new Hero('Zelda');\r\nzelda.saludar();\r\n```\r\nnew es lo mismo que hacer esto:\r\n\r\n```js\r\nfunction Hero(name) {\r\n  const hero = Object.create(Hero.prototype);\r\n  hero.name = name;\r\n  return hero;\r\n}\r\nconst zelda = new Hero('Zelda');\r\nzelda.saludar();\r\n```\r\n\r\nCada vez que usamos **new** este atajo de Object.create ocurre autómaticamente:\r\n\r\n```js\r\nfunction Hero(name) {\r\n  // Object.create Ocurre automáticamente cada vez que utilizamos new y no necesitamos ponerlo\r\n  // const hero = Object.create(Hero.prototype);\r\n  this = Object.create(Hero.prototype);\r\n  hero.name = name;\r\n  return this;\r\n}\r\nconst zelda = new Hero('Zelda');\r\nzelda.saludar();\r\n```\r\nLa regla que usa new cuando hace el Object.create es que siempre va a sacar el prototype de lo que sea el constructor, si después de new dice hero ``new Hero``\r\n\r\nLo que hará será un ``Hero.prototype``, no existe otro. Y en lugar de guardarlo en hero sirve imaginarnos que lo va a guardar en *this*. Este this se va a inicializar, no lo haremos nosotros directamente, lo está haciendo el lenguaje, entonces sí se vale y en lugar de decir ``hero.name`` hacemos: ``this.name``. Siempre la clase o función clase lo que hará siempre será retornarnos this implícitamente.\r\n\r\nLo que acabamos de hacer es: tienes un objeto simple, donde nos las inventamos para crear nuevos objetos, y fuimos arreglando algunas ineficiencias hasta llegar a Object.create y new, que solo es sugar-sintaxs para Object.create. Esto es lo que ocurre cada vez que construimos un constructor en una función o cuando escribimos Hero.prototype.\r\n\r\nHoy en día hay nuevas formas de hacerlo, usando el keyword ``class`` internamente, definimos los métodos, definimos un constructor, todo esto es también sugar-syntax que vale la pena y es muy importante entender cómo funciona nativamente para ver cómo es que nuestro lenguaje se está comportando.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Herencia Prototipal\r\n\r\nPor default los objetos en JavaScript tienen como prototipo a Object, que es el punto de partida de todos los objetos, es el prototipo padre. Object es la raíz de todo, por lo tanto tiene un prototipo padre undefined.\r\n\r\nCuando se llama a una función o variable que no se encuentra en el mismo objeto que la llamó, se busca en toda la **prototype chain** hasta encontrarla o regresar undefined.\r\n\r\nLa función ```hasOwnProperty``` sirve para verificar si una propiedad es parte del objeto o si viene heredada desde su prototype chain.\r\n\r\n```js\r\nfunction Hero(name) {\r\n  this.name = name;\r\n}\r\n\r\nHero.prototype.saludar = function () {\r\n  console.log(`Hola, soy ${this.name}`);\r\n}\r\n\r\nconst zelda = new Hero('Zelda');\r\n\r\n// Propiedades de la instancia\r\nconsole.log(`New: ${zelda.name} `);\r\n// Propiedades de la \"clase\".\r\nconsole.log(`saludar: ${zelda.saludar} `);\r\n\r\n// Propiedades heredadas de ej: toString\r\nconsole.log('toString: ', zelda.toString);\r\n\r\n// hasOwnProperty (de dónde sale toString o esto?)\r\nconsole.log('zelda.hasOwnProperty(\"name\"): ', zelda.hasOwnProperty('name'));\r\nconsole.log('zelda.hasOwnProperty(\"saludar\"): ', zelda.hasOwnProperty('saludar'));\r\n```\r\n\r\nProto __proto__ es el lugar donde cayeron todas las propiedades que estaban en Hero.prototype, si seguimos por ahí, hay otro __proto__ que viene desde Object y aquí está hasOwnProperty y toString.\r\n\r\nNosotros podemos escribrir ``zelda._proto_`` y va funcionar, pero esa propiedad __proto__ es algo que puede variar, no es algo que está especificado en el lenguaje. Es un detalle de implementación que ponen los browsers o node o cualquier otro entorno. La forma correcta o sugerida es utilizando **Object.getPrototypeOf(zelda)**, el cual nos va a regresar ese prototipo.\r\n\r\nsi comparamos:\r\n```js\r\nconst prototypeOfZelda = Object.getPrototypeOf(zelda);\r\nprototypeOfZelda === Hero.prototype;\r\n// true\r\n```\r\nEste objeto es idéntico al que está a prototypeOfZelda, no solo porque tiene el mismo contenido sino porque es el mismo objeto. Cuando utilizamos ``===``es porque estamos comparando la referencia en memoria es decir: el mismo lugar en memoria. Si esto es cierto nosotros podemos hacer lo siguiente:\r\n\r\n```js\r\nconst prototypeOfZelda = Object.getPrototypeOf(zelda);\r\nprototypeOfZelda === Hero.prototype;\r\n// true\r\nHero.prototype.fight = function () {console.log(\"FIGHT\")}\r\nzelda.fight();\r\n// Ejecuta el menssage\r\n```\r\nEs una referencia desde zelda hasta prototype, el lenguaje lo está encadenando, porque si vamos a ``zelda.hasOwnProperty(\"fight\");`` es false porque no le pertenece, le pertence al prototype.\r\n\r\nLo que hace el lenguaje para encontrarlo es preguntar: \r\n-- ¿zelda.fight existe? \r\n-- No existe\r\n-- Okay, vamos a buscarlo en su proto\r\n-- ¿zelda.__proto__.fight existe? \r\n-- Sí\r\n-- Ejecutamos!!\r\n\r\n**Object** es el punto de partida de todos los objetos en javascript, esto incluye las funciones que también son objetos en javascript\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## ¿Cómo funciona Javascript?\r\n\r\n¿Qué pasa cuando llega un script al navegador?\r\n\r\nComienza un proceso ejecutado por el motor de javascript que va a tomar ese código y lo va analizar  y lo va a deconstruir y reconstruir, despues ejecuta y luego lo optimiza.\r\n\r\nAcerca de la web...\r\n\r\nLa web no siempre ha sido igual y cuando llegó javascript llegó con **Netscape**. En ese entonces lo que hacíaamos eran cosas muy simples donde abriamos un cajon donde el usuario ingresaba información y luego el programa lo leía y lo seguíaa ejecutando, pero eran cosas muy simples, en javascript lo que hacíamos es que íbamos leyendo línea por línea y lo íbamos interpretando un paso a la vez, y eso sigue siendo cierto pero de una manera totalmente nueva, y esta nueva manera llegó con Google Chrome. \r\n\r\nGoogle, una compañía con productos sumamente complejos como Google Maps, necesitaba un navegador que pudiera ejecutar las cosas más eficientemente y por eso reinventó cómo funcionaban los Motores de Javascript. En resumen, esto es lo que hacen:\r\n\r\n- Reciben un código fuente, lo analizan y lo deconstruyen en el AST(Abstract Syntax Tree). Este AST lo toma un interpretador y lo convierte en bytecode, que es lo que se va a ejecutar, el programa va a empezar ejecutando bytecode y eventualmente va a tener suficiente información para ejecutar machine code que es el mismo código pero automizado.\r\n\r\n1. Recibe código fuente,\r\n2. Parsea código y produce Abstract Syntax Tree(AST)\r\n3. Se compila a bytecode y se ejecuta.\r\n4. Se optimiza a machine code y se remplaza el código base.\r\n\r\nMirando un grafo con este orden usando V8.\r\n\r\n<div align=\"center\">\r\n  <img src=\"../assets/v8.jpg\"> \r\n</div>\r\n\r\n**Javascript source code** pasa por el **parser** donde obtenemos el AST, después el **AST** se lo damos al **interpretador** que va a producir **bytecode**, ahí es donde comienza a ejecutarse nuestro programa. Bytecode es un lenguaje de menor nivel pero va a permitir que se ejecute más rápido, **mientras se va ejecutando** hay un proceso que se llama el **profiling data** que va a estar analizando la ejecución, va a encontrar los puntos donde el programa se puede optimizar y eventualemente va a producir el machine code, esto hace el **optimizing compiler** el **compilador de optimizaciones** y despues tenemos el **Optimized code**.\r\n\r\nHay veces en que estas asunciones fallan, ahí deoptimize(deoptimizamos) el código.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Analizador y Abstract Syntax Tree\r\n\r\n**Parser:** un parser va a tomar tu código fuente y lo va a leer, pero lo que tú estás escribiendo no es la que la computadora entiende así tal cual como lo escribiste. Primero lo tiene que descomponer y esa descomposición o esos pedazos que van a salir se llamán **tokens**. Tokens identifican que let es una palabra clave o new es una palabra clave, que el símbolo de + es un operador y que lo que está a un lado y al otro o quizás son número u otro tipo de variable; y una vez que tenemos esos tokens es cuando vamos a hacer el AST(Abstract Syntax Tree).\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Fallo en el Parset\r\n\r\nQué pasa si el parser está analizando tu programa y de momento hay algo que no hace sentido, justo es cuando ocurre un **syntax error**\r\n\r\nUn **SyntaxError** es lanzado cuando el motor de javascript se encuentra con parte de código que no forma parte de la sintaxis del lenguaje al momento de analizar código.\r\n\r\nEl proceso de parsing es muy importante que se haga bien.\r\n\r\n**Google dice:** \r\n\r\n- Parsing es 15% - 20% del proceso de ejecución.\r\n- La mayoría del Javascript en una página nunca se ejecuta.\r\n- Esto hace que **bundling y code splitting** sea muy importante!\r\n\r\nLa tercer parte significa que el código lo tenemos que empaquetar de una forma eficiente donde hay unos archivos de código separados lógicamente y que solamente vamos a cargar cuando sea necesario, esta es una modalidad que se está volviendo muy frecuentemente en aplicaciones de una sola página **Single Pages Apps**.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Eager Parsing (Parser de V8):\r\n\r\nCuando sea hace este parsing vamos a encontrar todos los errores de sintaxis en el código que se está analizando y vamos a crear el AST. Que siemplemente es un árbol o arquitectura en forma de árbol que representa tu programa, y además va ha construir los scopes. En este momento vamos a saber qué variables se pueden leer en qué partes del código \r\n\r\n- Encuentrar errores de sintaxis\r\n- Crea el AST\r\n- Construye Scopes\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n#### Lazy Parsing\r\n\r\nCuando hacemos esto (parsing) estamos retrazando alguna parte del código, porque no hace falta analizarla y puede esperar. Esto tiene una ventaja y es que es el doble de rápido, por lo tanto, si las cosas tardaban 20%, si logramos que ocurra mucho lazy parsing podemos retrazar ese análisis, una consecuencia es que el AST no se construye  y los Scopes se construyen parcialmente.\r\n\r\n- Doble de rápido que el eager parser\r\n- No crea el AST\r\n- Construye los scopes parcialmente.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n#### Tokens\r\n\r\nAccediendo al siguiente enlce podemos ver con ejemplos la manera en cómo una sentencia de javascript se transpila a un token. [url](https://esprima.org/demo/parse.html#) o ingresando a [esprima](https://esprima.org/) \r\n\r\nParser produces the (beautiful) syntax tree\r\n\r\n```js\r\n// Life, Universe, and Everything\r\nvar answer = \"hola\";\r\n```\r\n\r\n```json\r\n[\r\n    {\r\n        \"type\": \"Keyword\",\r\n        \"value\": \"var\"\r\n    },\r\n    {\r\n        \"type\": \"Identifier\",\r\n        \"value\": \"answer\"\r\n    },\r\n    {\r\n        \"type\": \"Punctuator\",\r\n        \"value\": \"=\"\r\n    },\r\n    {\r\n        \"type\": \"String\",\r\n        \"value\": \"\\\"hola\\\"\"\r\n    },\r\n    {\r\n        \"type\": \"Punctuator\",\r\n        \"value\": \";\"\r\n    }\r\n]\r\n```\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n#### Abstract Syntax Tree\r\n\r\nEl AST es un gráfo (estructura en forma de árbol) donde vamos a tener una raíz que será nuestro programa y lo vamos a ir descomponiendo en partes, todo esto lo vamos a poder hacer siguiendo los tokens que produce el parser. Esto se usa en muchísimos sitios, no solo para ejecutar un programa javascript, también lo usamos para transformar código de una forma a otra, que es como lo que hace **babel** o **priged** \r\n\r\nSe usa en:\r\n- Javascript Engine\r\n- Bundlers: Webpack, Rollup, Parcel\r\n- Transpilers: Babel\r\n- Linters: ESLint, Prettify\r\n- Type Checkers: TypeScript, Flow\r\n- Syntax Highlighters\r\n\r\nDemo de AST\r\n\r\n```js\r\nlet foo = \"bar\";\r\n```\r\n\r\n<div align=\"center\">\r\n  <img src=\"../assets/demoast.jpg\" alt=\"demo AST\">\r\n</div>\r\n\r\nTambién puede construir tu propio ejemplo en [AST Explorer](https://astexplorer.net/)\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Abstract Syntax Tree en Práctica\r\n\r\nUsemos el AST para crear una regla para ESLint, que analiza estéticamente nuestro código para ver si encuentra errores, o si hay que leventar warnings porque estamos violando alguna regla de estilo, o simplemente nuestro código está violando la sintaxis del lenguaje. Muchas de estas reglas ya vienen con ESLint pero también podemos desarrollar nuevas, para hacer eso vamos a utilizar una herramienta que se llama [AST Explorer](https://astexplorer.net). En este explorer tenemos que asegurarnos que la configuración es la correcta, si aquí no dice babel-eslint vamos a seleccionarla y vamos a ver cómo vamos a transformar el código. En este caso lo vamos a procesar y vamos usar la última versión de ESLint.\r\n\r\nEn la parte de abajo del lado izquierdo vamos a escribir esa regla, y en la parte de abajo del lado derecho vamos a ver cómo esa regla está funcionando.\r\n\r\nLa regla la vamos a definir dentro de una función y el nombre de esa función va a ser el nombre del nodo que queremos corregir. Si vamos al AST vemos que esta parte del código trabaja con declaraciones de variables. Cuando hay una declaración la queremos entender y si encontramos que el nombre está en lowerCase, que lo que hace es guardar un número, lo queremos corregir, así que vamos a corregir esto y copiaremos en este caso el nombre del nodo \"VariableDeclaration\", esta función es la que va a recibir un nodo.\r\n\r\nCódigo al que queremos establecer reglas:\r\n```js\r\nconst pi = 3.1415;\r\nconst halft_pi = 1.356;\r\n\r\n// Variables constantes\r\n// Variables que guarden un número \r\n\r\n// El nombre de la variable tiene que estar en UPPER CASE\r\n```\r\n\r\nReglas que establecemos para el código usando ESLint\r\n```js\r\nexport default function(context) {\r\n  return {\r\n  \tVariableDeclaration(node) {\r\n    \t// Tipo de variable const\r\n      if(node.kind === \"const\") {\r\n      \tconst declaration = node.declarations[0];\r\n        // asegurarnos que el valor es un número  \r\n        if(typeof declaration.init.value === \"number\") {\r\n        \tif(declaration.id.name !== declaration.id.name.toUpperCase()) {\r\n            \tcontext.report({\r\n                \tnode: declaration.id,\r\n                  \tmessage: \"El nombre de la constante debe estar en Mayúsculas\",\r\n                  \tfix: function(fixer) {\r\n                    \treturn fixer.replaceText(declaration.id, declaration.id.name.toUpperCase());\r\n                    }\r\n                })\r\n            }\r\n        }\r\n      }\r\n    }\r\n  };\r\n};\r\n```\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Como funciona el Javascript Engine\r\n\r\nDespues de que el parser hizo su trabajo y nos dio el AST continúa el interpretador, el compilador para obtener código optimizado.\r\n\r\n- Recibe código fuente\r\n- Parsea el código y produce un Abstract Syntax Tree(AST)\r\n- Se compila a bytecode\r\n- Se optimiza a machine code y se remplaza el código base.\r\n\r\nCuando el bytecode se está ejecutando hay un observador, un programa que observa el bytecode y va a estar tomando notas, cuando tiene suficientes notas es capaz de tomar decisiones para optimizar tu código y así obtener código optimizado, si alguna de estas observaciones en el futuro resulta ser falsa y que todavía no se cumple, no pasa nada, tu código va a regresar a una versión ya optmizada donde va a seguir corriendo, aunque no tan rápido.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Bytecode vs Machine Code\r\n\r\nEl bytecode es algo parecido a assembly y assembly es un lenguaje de muy bajo nivel pero que aún se puede escribir, son palabras clave que le dicen al procesador que hacer. Es similar a Assembly, excepto que en lugar de operar sobre un procesador va a operar sobre algo que se llama la virtual machine, que es un programa que ejecuta bytecode.\r\n\r\nEl Machine Code es lo más bajo nivel, ni tú ni yo queremos escribir machine code a mano porque se trata básicamente de ceros y de unos, es código binario, pero los procesadores si lo necesitan así, es el código que les va a llegar a ellos y va a volar y es muy rápido porque el machine code no hay que traducirlo, ya está traducido.\r\n\r\nCuando el motor de Javascript V8, que es el que ocupa chrome y node, produce este código va a crearlo a machine code. Ya el bytecode que corre la máquina virtual no se va a ocupar.\r\n\r\nEl profiler es un programa que está en medio del bytecode y el optimizador, este programa lo que hace es que toma una observación de la ejecución del bytecode y, cuando ve que las funciones se están llamando igual una vez tras otra y todas la llamadas son iguales, puede hacer unas optimizaciones, ejemplo:\r\n\r\n```js\r\nfunction add(a, b) {\r\n  return a + b;\r\n}\r\n\r\nfor (let i = 0; i < 1000; i++) {\r\n  add(i, i);\r\n}\r\n```\r\nCuando el código se haya ejecutado (ejemplo, 50 veces), el código va a empezar a ponerse caliente, luego 100 iteraciones más y sera más caliente y así sucesivamente hasta que está súper caliente y está listo para ser optimizado. En términos del V8 le llamos hot function(función caliente). Esto significa que el optimizador de código ya está listo para optimizar esa parte, está seguro que la ejecución siempre es similar, recibe numeros, regresa numeros, entonces podemos optimizarla a machine code.\r\n\r\nQue pasa si, por la razón que sea, ya no estamos pasando 2 números como argumento, ahora estamos pasando 2 números y 1 cadena, el resultado sería el número 1 más el string todo pegado. Pero esto va a confundir al optimizador y lo regresará a bytecode, y lo que pasa es que se va a desoptimizar el código. Tú puedes seguir programando, no pasará nada, pero esto demuestra un poco de ineficiencia. Por esto es bueno que las funciones se llamen igual, si le pasamos objetos que tengan una forma diferente o argumentos de tipos diferentes, o no se va a poder optimizar tu función, o se va a desoptimizar, pero esto es así.\r\n\r\nLos motores de Javascript funcionan ligeramente diferente, cada browser tiene su propia implementación aunque todos siguen una estructura parecida, el que acabamos de analizar fue V8.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### SpiderMonkey vs V8\r\n\r\nSpiderMonkey tiene 2 capas de optimización, Chakra también y recibe información de profiler y de varios lugares. **JavascriptCore tiene 3 capas de optimización**. \r\n¿Esto significa que Safari es más rápido que Chrome? No necesariamente, en el desarrollo de programas o de ingeniería siempre se trata trades, intercambio de costo-beneficio. Esto quizás no sea perfecto, pero luego saldra mejor, y en javascriptCore puede ser que nuestro programa tarde un poquito más en comenzar, pero una vez que se inicialice, el profiler comienza a actuar, optimiza poco y luego otro poco, así sucesivamente.\r\n\r\nMientras que en Chrome nuestro programa empieza a ejecutarse rápido y quizás toma un poco más de tiempo en que se optmize pero así es como funcionan los motores de javascript.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Event Loop\r\n\r\nSi lo tuviéramos que describir en una oración: El eventLoop es lo que hace que javascript parezca ser multihilo cuando realmente es un solo hilo. Entonces ¿cómo rayos es que podemos hacer scroll, click, cargar un imagen, hacer una petición, miles de cosas haciendo eso una sola vez?\r\n\r\nTenemos que saber que Javascript se organiza usando 2 estructuras de datos, es el Stack y el Heap.\r\n\r\n<div align=\"center\">\r\n<img src=\"../assets/stackheap.png\" alt=\"memorystructuresjs\">\r\n</div>\r\n\r\nEl stack es una estructura de datos que lleva rastro de dónde está el programa, si un programa comienza con una función ``main()``, a su vez llama a ``renderList()`` y ``renderList()`` llama a ``getMovies()``, es Stack se vería algo así.\r\n\r\nTambién tenemos el memory heap, el memory heap es una estructura desorganizada, en el stack hay un orden, una función dentro de una función, una dentro de otra, el memory Heap es completamente aleatoria y ahí es donde se guarda la información de las variables, el scope, etc.\r\n\r\nEl stack comenzará vacío, pero vamos a hacer una operación que se llama un push y vamos a poner como si ponemos un plato. Entonces en ese contenedor que solo está abierto para arriba hay un plato, si vovemos a hacer un push pusimos otro plato encima, hacemos push, otro plato encima; ahora, ¿qué pasa si tú quisieras quitar el plato que estaba hasta abajo? No puedes, porque no hay forma de sacarlo por enfrente, ni por debajo, solamente por arriba; por lo tanto tienes que sacar el plato que está hasta arriba, para sacar otro plato, otro y otro y por fin sacar el plato de hasta abajo.\r\n\r\nEsa operación de sacar se llama pop, si hacemos pop sale getMovies, si volvemos a hacer pop sale renderList, y si volvemos a hacer pop sale main y el obtenemos el stack vacío.\r\n\r\n<div align=\"center\">\r\n  <img src=\"../assets/stack.png\" alt=\"stack\">\r\n</div>\r\n\r\nEl stack es donde están nuestras funciones, es el registro de cómo está operando nuestro programa, apunta a variables como el scope.\r\n\r\n<div align=\"center\">\r\n  <img src=\"../assets/scope.png\" alt=\"stack\">\r\n</div>\r\n\r\nEs donde dice: Estas cosas en esta función tienen acceso al entorno global, esto tiene acceso al scope de la función, esto tiene acceso al scope de un bloque y nos guarda esa información.\r\n\r\nEntonces si tenemos un programa como este:\r\n\r\n<div align=\"center\">\r\n  <img src=\"../assets/stackstart.png\" alt=\"stackstart\">\r\n  <img src=\"../assets/stackmain.png\" alt=\"stackmain\">\r\n  <img src=\"../assets/stackhello.png\" alt=\"stackhello\">\r\n  <img src=\"../assets/stackconsole.png\" alt=\"stackconsole\">\r\n</div>\r\n\r\nY así sucesivamente van agregando y quitando ejecuciones en el orden correspondiete.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### EventLoop con Asincronía\r\n\r\nCuando se ejecuta una función asíncrona, como por ejemplo un ``setTimeout()``, lo reconoce pero no lo ejecuta, sigue con su proceso normal y luego aparece otra vez para ejecutar la función que ejecutaría un setTimeout().\r\n\r\nParece raro, pero esta es la asincronía, cosas que van a pasar eventualmente, pues eventualmente pasarán, pero aún no les toca.\r\n\r\n<div align=\"center\">\r\n  <img src=\"../assets/stackasyncrono.png\" alt=\"stackasync\">\r\n  <img src=\"../assets/stackasyncronosettimeout.png\" alt=\"stackasynctimeout\">\r\n  <img src=\"../assets/stackasyncronoconsole.png\" alt=\"stackasyncconsole\">\r\n  <img src=\"../assets/stackasyncronofin.png\" alt=\"stackasyncfin\">\r\n  <img src=\"../assets/stackasyncronoclean.png\" alt=\"stackasyncclean\">\r\n  <img src=\"../assets/stacksettimeout.png\" alt=\"stacksettimeout\">\r\n  <img src=\"../assets/stackasyncronoclean.png\" alt=\"stackasyncclean\">\r\n</div>\r\n<br>\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Task Queue\r\n\r\n**¿Cómo funciona esto?**\r\n\r\nPara poder entenderlo tenemos que hablar sobre **Queue**: es una estructura de datos igual que el stack, donde lo primero que entra es lo último que sale. En el **Queue lo primero que entra es lo primero que sale**, es como ir al banco y hacemos una fila, el que llegó primero es al que van a atender primero \r\n\r\nTeniendo en cuenta esto vamos a hablar sobre la cola de tareas.\r\n\r\nCuando teníamos el setTimeout() encolamos una tarea que ibamos a hacer en 1000 milisegundos.\r\n\r\n<div align=\"center\">\r\n  <img src=\"../assets/eventloop.png\" alt=\"eventloop\">\r\n  <img src=\"../assets/eventloopstack.png\" alt=\"eventloopstack\">\r\n</div>\r\n\r\n¿Qué pasa si el stack no está vacío?\r\n\r\n<div align=\"center\">\r\n  <img src=\"../assets/eventloopstackloadtwo.png\" alt=\"eventloopstackloadtwo\">\r\n  <img src=\"../assets/eventloopstackloadtwotask.png\" alt=\"eventloopstackloadtwotask\">\r\n  <img src=\"../assets/eventloopstackloadtwotaskall.png\" alt=\"eventloopstackloadtwotaskall\">\r\n  <img src=\"../assets/eventloopstackiii.png\" alt=\"eventloopstackiii\">\r\n  <img src=\"../assets/eventloopstackfintwo.png\" alt=\"eventloopstackfintwo\">\r\n</div>\r\n<br>\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Event Loop con Promesas\r\n\r\nLas promesas son algo que eventualmente va a pasar, se puede resolver una promesa o se puede rechazar pero lo importante es que eventualmente van a retornar algo, esto es asíncrono, entonces llevamos este programa de nombre moreAsync.\r\n\r\n<div align=\"center\">\r\n  <img src=\"../assets/promiseeventloop.png\" alt=\"promiseeventloop\">\r\n</div>\r\n\r\nResulta que las promesas van en otra cola, la cola de microtareas **Microtask Queue**. Las microtareas son de mayor proridad y simpre van primero sobre el scheduled task.\r\n\r\n<div align=\"center\">\r\n  <img src=\"../assets/microtask.png\" alt=\"microtask\">\r\n  <img src=\"../assets/microtaskespera.png\" alt=\"microtaskespera\">\r\n  <img src=\"../assets/microtaskpromise.png\" alt=\"microtaskpromise\">\r\n  <img src=\"../assets/microtaskpromise2.png\" alt=\"microtaskpromise2\">\r\n  <img src=\"../assets/microtaskpromisefin.png\" alt=\"microtaskpromisefin\">\r\n</div>\r\n<br>\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Promesas\r\n\r\nYa vimos cómo el eventLoop procesa las promesas, ahora vamos a volver a las promesas, pero esta vez vamos a ver cómo funciona el patrón de **.then** .Lo vamos a convertir a **async await** y también vamos a aprender diferentes patrones cuando escribimos funciones que nos regresan una promesa, todo esto para facilitar el desarrollo de nuestras apps. Todo esto lo vamos a hacer con una API que es libre, se llamá [themoviedb](https://www.themoviedb.org/?language=es-ES).\r\n\r\n```js\r\n// The Movie Database API: https://developers.themoviedb.org/3/getting-started/introduction\r\n      const apiKey = 'b89fc45c2067cbd33560270639722eae';\r\n\r\n      function getMovie(id) {\r\n        const url = `https://api.themoviedb.org/3/movie/${id}?api_key=${apiKey}`;\r\n        return fetch(url).then(response => response.json());\r\n      }\r\n\r\n      async function getPopularMovies() {\r\n        const url = `https://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=${apiKey}`;\r\n        const response = await fetch(url);\r\n        const data = await response.json();\r\n        return fetch(url)\r\n          .then(response => response.json())\r\n          .then(data => data.results);\r\n      }\r\n\r\n      async function getTopMoviesIds(n = 3) {\r\n        return getPopularMovies().then(popularMovies => {\r\n          popularMovies.slice(0, n).map(movie => movie.id);\r\n        })\r\n      }\r\n```\r\n<br>\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Getters y Setters\r\n\r\nUno de los features modernos que trae javascript son getters y setters, son funciones que podemos utilizar dentro de objetos que nos permiten tener propiedades virtuales, es decir, no es una propiedad que existe directamente en el objeto, pero a través de un getter o setter podemos correr una fución que va a calcular estos valores o va a mostrar una valor para establecer este nuevo valor.\r\n\r\nLos getters los vamos a escribir usando el keyword ``get`` seguido de la propiedad virtual \r\n\r\n```js\r\nlet persona = {\r\n  nombre: 'Yeison',\r\n  apellido: 'Daza',\r\n  get nombreCompleto() {\r\n    return`${nombre}${apellido}`\r\n  },\r\n  set nombreCompleto(nom) {\r\n    const palabras = nom.split(' ');\r\n    this.nombre = palabras[0] || '';\r\n    this.apellido = palabras[1] || '';\r\n  }\r\n}\r\npersona.nombreCompleto = 'Camilo Sanchez'\r\n\r\nconsole.log(persona.nombre); //camilo\r\nconsole.log(persona.apellido); //sanchez\r\n```\r\n<br>\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Proxy\r\n\r\nIgual que los getters y setters, el proxy es uno de los features más recientes del lenguaje. También igual que los getters y setters, podemos intersectar algunas llamadas a un objeto. Sin embargo, más alla de get y set, podemos intersectar muchísimas otras cosas. Si vamos a la documentación de Proxy en [MDN]() vamos a encontrar una sección que dice *Methods of the handler object* (métodos del objeto manejador). Aquí vamos a encontrar a get y set, decimos que son trampas. Cuando hay una llamada, la llamada va a caer en estas trampas si las tenemos definidas. En la trampa de get y de set también hay trampas para ver el getPrototypeOf, handler.apply, handler.constructor, etc. \r\n\r\nEsto nos va a permitir que antes de que la llamada llegue al objeto al que tiene que llegar podemos manipularla. Hay una idea que se me hace muy interesante y muy divertida, es un feature que tienen algunos programas como por ejemplo git. Si vamos a la consola y escribimos mal el comando, no se ejecutara la instrucción, pero nos devolverá una sugerencia a lo que escribimos, o en dado caso de no tener una sugerencia, nos dará una lista de posibles comandos.\r\n\r\nVamos a hacer esto mismo, pero en Javascript, que será interceptar las llamadas si la propiedad que está buscando el usuario no existe en un objeto. Vamos a ver cuáles son las que sí existen para sugerir una.\r\n\r\nPara este ejemplo nos vamos a apoyar de una librería que se llama [fast-levenshtein](https://www.jsdelivr.com/package/npm/fast-levenshtein). Leveshtein es un algoritmo que va a encontrar la distancia entre 2 cadenas. Es decir, si tenemos 2 cadenas y se diferencian por 1 sola letra la distancia sería de 1; si se diferencian por 2 campos, sería una distancia de 2.\r\n\r\n```js\r\n// target es mi objeto a supervisar (sus propiedades pueden ser objetos, array, funciones, u otro proxy)\r\nconst target = {\r\n  red: 'Rojo',\r\n  green: 'Verde',\r\n  blue: 'Azul'\r\n}\r\n// handler es un objeto con funciones (trampa) que definen las acciones a seguir cuando se accede al objeto supervisado\r\nconst handler = {\r\n  get(obj, prop) {\r\n    if (prop in obj) {\r\n      // si la propiedad existe, pues retornamos su valor\r\n      return obj[prop]\r\n    }\r\n\r\n    // Si llega hasta aqui, vamos a ver si podemos retornar una sugerencia\r\n    const suggetion = Object.keys(obj).find(key => {\r\n      // creo un objeto con todas mis claves del objeto supervisado, y retorno aquella (nombre) \r\n      // que su distancia sea <= 3 tomando como base la propiedad invocada\r\n      return Levenshtein.get(key, prop) <= 3 \r\n    })\r\n\r\n    \r\n    if (suggetion) {\r\n      console.log(`${prop} no se encontró. ¿Quisiste decir ${suggetion}?`);\r\n    }\r\n\r\n    return obj[prop];\r\n  }\r\n}\r\nconst p = new Proxy(target, handler);\r\n\r\np.red; // \"Rojo\"\r\np.green; // \"Verder\"\r\np.reed //reee no se encontró. ¿Quisiste decir red?\r\np.geen //geen no se encontró. ¿Quisiste decir green?\r\n```\r\n<br>\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Generadores\r\n\r\nLos generadores sons funciones especiales, podemos iniciar su ejecución y detenerla a mitad, nuestro programa continúa por otro sitio y luego podemos regresar a esta función generador y continuar su ejecución donde la dejamos. Lo que está muy interesante es que los generadores, cuando los detenemos, se recuerdan de su contexto, de cuáles eran las variables que tenían en su scope. Veámos un ejemplo de cómo son las funciones.\r\n\r\n```js\r\nfunction* simpleGenerator() {\r\n  console.log(\"GENERATOR START\");\r\n  console.log(\"GENERATOR END\");\r\n}\r\n\r\nconst gen = simpleGenerator();\r\n```\r\n\r\nLos generadores que se crean traen una función que se llama ``next()``, es una forma de decirle al generador \"continúa tu ejecucíon\", porque ahora esta suspendido. Si hacemos next(), escribirá el generador en consola. Pero también regresa un objeto con los valores [value: undefine, y done: true], este es el valor de retorno del generador. Cuando ``done`` es ``true`` quiere decir que el generador terminó su ejecución.\r\n\r\nPara obtener value definido podemos utilizar un keyword que se llama ``yield`` y si ejecutamos next() el yield cortará la ejecución y ahi terminará la ejecución, y si queremos volver a ejecutar las instrucciones pendientes tenemos que volver a lanzar a next().\r\n\r\n```js\r\nfunction* simpleGenerator() {\r\n  console.log(\"GENERATOR START\");\r\n  yield;\r\n  console.log(\"GENERATOR END\");\r\n}\r\n\r\nconst gen = simpleGenerator();\r\ngen.next()\r\n// GENERATOR START\r\ngen.next();\r\n// GENERATOR END\r\n```\r\n\r\nAlgó muy interesantes es que cuando hacemos **yield** podemos regresar un valor \r\n\r\n```js\r\nfunction* simpleGenerator() {\r\n  console.log(\"GENERATOR START\");\r\n  yield 1; // {value: 1, done: false}\r\n  yield 2; // {value: 2, done: false}\r\n  yield 3; // {value: 3, done: false}\r\n  console.log(\"GENERATOR END\");\r\n}\r\n\r\nconst gen = simpleGenerator();\r\ngen.next()\r\n// GENERATOR START\r\ngen.next();\r\n// GENERATOR END\r\n```\r\nGeneradores inifitos\r\n```js\r\n// Podemos hacer generadores infinitos\r\nfunction* idMaker() {\r\n  let id = 1;\r\n  while (true) {\r\n    yield id;\r\n    id += 1;\r\n  }\r\n}\r\n```\r\nCuando llamamos a next() también podemos pasar valores que la función recibe.\r\n\r\n```js\r\nfunction* idMakerWithReset() {\r\n  let id = 1;\r\n  let reset;\r\n  while (true) {\r\n    reset = yield id;\r\n    if (reset) {\r\n      id = 1;\r\n    } else {\r\n      id += 1;\r\n    }\r\n  }\r\n}\r\n```\r\n\r\nLos generadores se prestan para crear funciones eficientes en memoria. Vamos a escribir la secuencia fibonacci, una función que imprima la secuencia, que lo que hace es sumar los dos números anteriores para generar uno nuevo.\r\n\r\n```js\r\n// Ahora hagamos un ejemplo un poco más complejo: la secuencia fibonacci\r\nfunction* fibonacci() {\r\n  let a = 1, b = 1;\r\n  while (true) {\r\n    const nextNumber = a + b;\r\n    a = b;\r\n    b = nextNumber;\r\n    yield nextNumber;\r\n  }\r\n}\r\n```\r\n\r\nLos generadores son funciones especiales cuya ejecución podemos comenzar y detener a mitad de vuelo, y cuando queramos continuarla podemos llamar a next(). Podemos pasarle un valor al generador si hace falta y su ejecución va a continuar siempre recordándose del scope en el que estaba.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Cómo cancelar peticiones Fetch\r\n\r\nLa peticiones [AJAX]() permitieron en su tiempo hacer peticiones asíncronas al servidor sin tener que detener la carga de la página. Hoy en día se utiliza la función ``fetc()`` para esto.\r\n\r\nCon fetch() tenemos algo llamado ``AbortController()`` que nos permite enviar una señal a una petición en plena ejecución para detenerla.\r\n\r\nAbortController() nos va a dar 2 controllers para poder detener una ejecución, en este caso va a ser la del fetch(), la cual es una clase que trae el Motor de javascript, la cual tenemos que instanciarla.\r\n\r\n```html\r\n<html>\r\n  <head>\r\n    <title>Abort Fetch</title>\r\n  </head>\r\n  <body>\r\n    <a href=\"/ejercicios/\">Go back</a>\r\n    <p><em>Abre la consola</em></p>\r\n    <img id=\"huge-image\" height=\"400\" />\r\n    <button id=\"load\">Load HUGE Image</button>\r\n    <button id=\"stop\" disabled>Stop Fetching</button>\r\n    <script src=\"abort-fetch.js\"></script>\r\n  </body>\r\n</html>\r\n```\r\n\r\n```js\r\nconst url =\r\n  'https://images.pexels.com/photos/974470/nature-stars-milky-way-galaxy-974470.jpeg?q=100';\r\n      // Elementos del DOM imagen y 2 botones\r\n      const img = document.getElementById('huge-image');\r\n      const loadButton = document.getElementById('load');\r\n      const stopButton = document.getElementById('stop');\r\n      let controller;\r\n\r\n      // Función que habilita o desabilita un boton\r\n      function startLoading() {\r\n        loadButton.disabled = true;\r\n        // Camnbia el texto de su contenido\r\n        loadButton.innerText = 'Loading...';\r\n        stopButton.disabled = false;\r\n      }\r\n      // Funcíon que desabilita el botón de carga\r\n      function stopLoading() {\r\n        loadButton.disabled = false;\r\n        loadButton.innerText = 'Load HUGE Image';\r\n        stopButton.disabled = true;\r\n      }\r\n\r\n      loadButton.onclick = async function() {\r\n        // Se ejecuta startLoading que lo único que hace es cambiar la apariencia del botón\r\n        // Para que se vea que está cargando\r\n        startLoading();\r\n\r\n        // Declaramos la variable antes para después tener acceso a ella\r\n        // en el botón de cancelar petición fetch\r\n        controller = new AbortController();\r\n        try {\r\n          // Hacemos la petición asíncrona a la URL usando Async await\r\n          // Vamos a añadirle un objeto de configuración al fetch\r\n          // Este objeto de configuración le vamos a pasar un objeto que se llama la señal\r\n          // La señal va a venir del abort controller\r\n          const response = await fetch(url, { signal: controller.signal });\r\n          // Vamos a obtener el binario de la imagen con blob img en forma binaria\r\n          const blob = await response.blob();\r\n          // Convertimos el blob binario a una URL, el navegador se encarga de asignar el blob una url\r\n          const imgUrl = URL.createObjectURL(blob);\r\n          // Ahora el src se lo asignamos a la url de la imagen\r\n          img.src = imgUrl;\r\n        } catch (error) {\r\n          console.log(error.message);\r\n        }\r\n\r\n        // Cuando la función asíncrona falle vamos a cambiar el boton a stop\r\n        stopLoading();\r\n      };\r\n\r\n      stopButton.onclick = function() {\r\n        // Si deseamos detener tenemos que llamar al abort controller.container\r\n        // El abort envía una señal al fetch y hace que la petición se cancele\r\n        controller.abort();\r\n\r\n        stopLoading();\r\n      };\r\n      \r\n```\r\n<br>\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Intersection Observer API\r\n\r\nLa API Observador de Intersección provee una vía para, de forma asíncrona, observar cambios en la intersección de un elemento con un elemento ancestro o con el viewport del documento de nivel superior.\r\n\r\nLa información sobre intersección es necesaria por muchas razones, tales como:\r\n\r\nLazy-loading de imágenes u otro contenido a medida que la página se desplaza.\r\nImplementación de “scroll infinito” de sitios web, donde más y más contenido se carga y muestra a medida que usted hace scroll, de forma que el usuario no tiene que pasar páginas.\r\nInformes de visualizaciones de anuncios para calcular ingresos por publicidad.\r\nDecidir si deben realizarse tareas o procesos de animación basados en si el usuario verá o no el resultado.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Creando un Intersection Observer\r\n\r\nCrear el Intersection Observer llamando a su constructor y pasándole una función callback() para que se ejecute cuando un nivel (threshold) sea cruzado en una u otra dirección:\r\n\r\n```js\r\nvar options = {\r\n  root: document.querySelector('#scrollArea'),\r\n  rootMargin: '0px',\r\n  threshold: 1.0\r\n}\r\n\r\nvar observer = new IntersectionObserver(callback, options);\r\n```\r\n\r\nUn threshold de 1.0 significa que cuando el 100% del elemento target está visible dentro del elemento especificado por la opción root, la función callback es invocada.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Opciones de Intersection observer\r\n\r\nEl objeto options pasado al constructor [IntersectionObserver()](https://developer.mozilla.org/es/docs/Web/API/IntersectionObserver/IntersectionObserver) le deja controlar las circunstancias bajo las cuales la función callback del observer es invocada. Tiene los siguientes campos:\r\n\r\n**root**\r\n\r\nEl elemento que es usado como viewport para comprobar la visibilidad de elemento target debe ser un elemento ascendiente del target. Por defecto se toma el viewport del navegador si no se especifica o si se especifica como ``null``.\r\n\r\n**rootMargin**\r\n\r\nMargen alrededor del elemeto root. Puede tener valores similares a los de CSS [margin](https://developer.mozilla.org/es/docs/Web/CSS/margin) property, e.g. \"10px 20px 30px 40px\" (top, right, bottom, left). Los valores pueden ser porcentajes. Este conjunto de valores sirve para aumentar o encoger cada lado del cuadro delimitador del elemento root antes de calcular las intersecciones. Por defecto son todos cero.\r\n\r\n**threshold**\r\n\r\nEs un número o un array de números que indican a que porcentaje de visibilidad del elemento target, la función callback del observer debería ser ejecutada. Si usted quiere que se detecte cuando la visibilidad pasa la marca del 50%, debería usar un valor de 0.5. Si quiere ejecutar la función callback cada vez que la visibilidad pase otro 25%, usted debería especificar el array [0, 0.25, 0.5, 0.75, 1]. El valor por defecto es 0 (lo que significa que tan pronto como un píxel sea visible, la función callback será ejecutada). Un valor de 1.0 significa que el umbral no se considera pasado hasta que todos los pixels son visibles.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Determinando un elemento para ser observado\r\n\r\nUna vez usted ha creado el observer, necesita darle un elemento target para observar:\r\n\r\n```js\r\nvar target = document.querySelector('#listItem');\r\nobserver.observe(target);\r\n```\r\n\r\nCuando el elemento target encuentra un threshold especificado por el IntersectionObserver, la función callback es invocada. La función callback recibe una lista de objetos [IntersectionObserverEntry](https://developer.mozilla.org/es/docs/Web/API/IntersectionObserverEntry) y el observer:\r\n\r\n```js\r\nvar callback = function(entries, observer) { \r\n  entries.forEach(entry => {\r\n    // Cada entry describe un cambio en la intersección para\r\n    // un elemento observado\r\n    //   entry.boundingClientRect\r\n    //   entry.intersectionRatio\r\n    //   entry.intersectionRect\r\n    //   entry.isIntersecting\r\n    //   entry.rootBounds\r\n    //   entry.target\r\n    //   entry.time\r\n  });\r\n};\r\n```\r\n\r\nAsegúrese de que su función callback se ejecute sobre el hilo principal. Debería operar tan rápidamente como sea posible; si alguna cosa necesita tiempo extra para ser realizada, use [Window.requestIdleCallback()](https://developer.mozilla.org/es/docs/Web/API/Window/requestIdleCallback).\r\n\r\nTambién, note que si especifica la opción root, el elemento target debe ser un descendiente del elemento root.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Creación de Plugin para IntersectionObserver de nuestro videoplayer\r\n\r\n```js\r\nclass AutoPause {\r\n  constructor() {\r\n    this.threshold = 0.25;\r\n    this.handlerIntersection = this.handlerIntersection.bind(this)\r\n  }\r\n  run(player) {\r\n    this.player = player;\r\n    // const observer = new IntersectionObserver(handler, config)\r\n    const observer = new IntersectionObserver(this.handlerIntersection, {\r\n      // threshold: umbral define que porciento del elemento tiene que tener interseccion\r\n      threshold: this.threshold\r\n    })\r\n\r\n    observer.observe(this.player.media) \r\n  }\r\n  // Cuando intersectionObserver llame a handlerIntersection le va a pasar una lista de entries\r\n  // los entries son todos los objetos que estamos observando \r\n  handlerIntersection(entries) {\r\n    const entry = entries[0];\r\n    console.log(entry);\r\n\r\n    const isVisible = entry.intersectionRatio >= this.threshold\r\n\r\n    if (isVisible) {\r\n      this.player.play();\r\n    } else {\r\n      this.player.pause();\r\n    }\r\n  }\r\n}\r\nexport default AutoPause;\r\n```\r\n<br>\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Visibility Change\r\n\r\nEl visibilityChange forma parte del API del DOM llamado Page Visibility y nos deja saber si el elemento es visible, pude ser usado para ejecutar una acción cuando cambiamos de pestaña. Así podemos ahorrar batería y mejorar la UX.\r\n\r\nEl documento DOM ahora tiene un elemento que podemos escuchar.\r\n```js\r\ndocument.addEventListener('visibilitychange', () => {\r\n  console.log(document.visibilityState);\r\n})\r\n```\r\n\r\nUsando este evento nosotros podemos salirnos del navegador, también podemos cambiar de pestaña y el DOM lo sabrá. Usemos esto en nuestro plugin para que cuando cambiemos de tab el video se detenga. En el método run() es cuando los plugins se echan a correr, aquí es un buen momento para conectarnos a este evento y que cuando suceda tomar acción.\r\n\r\n```js\r\nrun(player) {\r\n    this.player = player;\r\n    // const observer = new IntersectionObserver(handler, config)\r\n    const observer = new IntersectionObserver(this.handlerIntersection, {\r\n      // threshold: umbral define que porciento del elemento tiene que tener interseccion\r\n      threshold: this.threshold\r\n    })\r\n\r\n    observer.observe(this.player.media) \r\n    // Ejecutamos el evento VisiblityChange y ejecutamos una función\r\n    document.addEventListener('visibilitychange', this.handleVisibilityChange)\r\n  }\r\n  handleVisibilityChange() {\r\n    const isVisible = document.visibilityState === \"visible\";\r\n    if (isVisible) {\r\n      this.player.play();\r\n    } else {\r\n      this.player.pause();\r\n    }\r\n  }\r\n```\r\n\r\nEl evento visibilityChange es un evento muy simple pero muy útil, nos deja saber si el tab es el que está hasta el frente, el tab que el usuario está viendo. Si cambiamos de tab nos permite cambiar acción, no solo nos permite ver un video, también pudiera ser cambiar el título de la pestaña, y así decirle al DOM que haga otras acciones que pueden ahorrar batería o mejorar el rendimiento de nuestras aplicaciones.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Service worker\r\n\r\nUna de las nuevas tendencias en el desarrollo web, son las PWA o _progressive web apps_, dentro de las varias cosas que ofrecen está que **tu app funcione offline**, esto lo hacemos posible usando los services workers, **services workers es una capa que va a vivir entre el navegador y el internet**. Lo que van a hacer es algo parecido a los Proxys. Van a interceptar peticiones, en este caso las peticiones vamos a tener la oportunidad de agarrar la petición, buscar la respuesta, pero antes de regresarla al browser, la vamos a guardar en caché \r\n\r\n**¿Qué pasa una vez que lo tenemos en caché?**\r\n\r\nLa proxima vez que ocurra una petición, en lugar de tener que ir a internet, ya tenemos la respuesta; así que nadamás la regresamos. Imagínate un usuario que va dentro del metro, se mete en un túnel y pierde conectividad, va a seguir utilizando tu aplicación porque usando service workers va a funcionar offline.\r\n\r\nVamos a añadírselo a nuestro VideoPlayer.\r\n\r\n1. Primero vamos a crear una condición. Esta condición nos va a servir si el navegador del usuario le da apoyo a los services workers. Como es un feature reciente, no todos los navegadores tienen service workers.\r\n```js\r\nif ('serviceworkers' in navigator) \r\n```\r\n2. Después, dentro del service workets vamos a registrar un archivo, este archivo va a ser el service worker tal cual, pero es posible que dentro del registro ocurra un error, asi que es importante ver ese error.\r\n```js\r\n  navigator.serviceWorker.register('/sw.js')\r\n    .catch(error => {\r\n      console.log(error.message);\r\n  })\r\n```\r\n3. En el nivel más alto del proyecto vamos a escribir el archivo del services worker. Aquí es donde vamos a escribir el código.\r\n\r\nLos services workers se instalan, el navegador lo va a instalar en la computadora del usuario, no es lo mismo que una aplicación, pero sí va a vivir dentro del navegador. Entonces cada vez que nostros hagamos cambios hay que volver a instalarlos, esto va suceder cuando el usuario esté usando la aplicación en producción. Pero cuando estamos en desarrollo queremos que esto suceda rápido, no con la lentitud que pueda suceder en producción. Para hacerlo hay que activar *updated on reload* en las devtools\r\n\r\n4. Vamos a escribir el código del service worker\r\n\r\n```js\r\n// Self hace refencia al service worker es como this a los objetos\r\nself.addEventListener('install', event => {\r\n  // Creamos un precache con una lista de recursos que queremos que mantenga en cache\r\n  event.waitUntil(precache());\r\n})\r\n\r\n// Cuando ocurra una petición queremos a ir al cache para ver si encontramos la respuesta\r\nself.addEventListener('fetch', event => {\r\n  // Extraemos la petición\r\n  const request = event.request;\r\n  // Solo queremos hacer algo con las peticiones que son GET\r\n  if (request.method !== \"GET\")\r\n    return;\r\n  \r\n  // actualizar el cache\r\n  event.waitUntil(updateCache(cache))\r\n\r\n  \r\n  // Buscamos en el cache\r\n  // event tiene otra función que se llamá responder con responseWith\r\n  // vamos a responder con una respuesta cacheada\r\n  event.respondWith(cachedResponse(request))\r\n})\r\n\r\n// Escribimos la función del precache\r\nasync function precache() {\r\n  // Para trabajar con cache tenemos que trabajar con una parte\r\n  // de la api del dom que se llamá caches, y lo que hay que hacer es abrir un cache en especifico\r\n  // Creamos una instancia de cache que le va a pertenecer o se va a llamar v1,\r\n  // podemos ponerle como queramos porque apenas estamos haciendo una instancia,\r\n  // este cache regresa una promesa, por lo cual hay que esperarla\r\n  const cache = await caches.open(\"v1\");\r\n\r\n  // Una vez tenemos la instancia de cache queremos añadir varios recursos\r\n  // añadirmos todos nuestro recursos, los cuales son todos lo archivos que hemos escrito\r\n  // Tenemos que regresarlo porque devuelve una promesa\r\n  return cache.addAll([\r\n    // Es muy importante asignarne este request\r\n    '/',\r\n    'index.html',\r\n    'styles.css',\r\n    'MediaPlayer.js',\r\n    'index.js',\r\n    'plugins/AutoPause.js',\r\n    'plugins/AutoPlay.js',\r\n    'buckbunny.mp4'\r\n  ]);\r\n\r\n\r\n}\r\n\r\n// vamos a pasarle el request\r\nasync function cachedResponse(request) {\r\n// Comenzamos abriendo el cache \r\n  const cache = await caches.open(\"v1\");\r\n  // debemos checar si en el cache tenemos la contestanción al request\r\n  // Para hacer eso vamos a guardalo en el response\r\n  // Estamos preguntando al cache\r\n  // ¿Ya tienes una copia que le corresponse al request?\r\n  const response = await cache.match(request)\r\n  // Como es posible que este response sea undefine, tenemos que contestar con lo que nos de la red\r\n  return response || fetch(request);\r\n\r\n}\r\n\r\nasync function updateCache(request) {\r\n  const cache = await caches.open(\"v1\");\r\n  const response = await fetch(request);\r\n  return cache.put(request, response)\r\n}\r\n```\r\n<br>\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Typescript\r\n\r\nTypeScript es un superset de JavaScript que añade tipos a nuestras variables ayudando así a la detección de errores de forma temprana y mejorando el autocompletado.\r\n\r\nLos navegadores no entienden TypeScript así que lo vamos a transpilar a JavaScript usando **Parcel**.\r\n\r\n``yarn add parcel-bundler --dev``\r\n\r\nAgregamos un par de configuraciones a nuestro packages.json\r\n\r\n```json\r\n\"scripts\": {\r\n    \"start\": \"parcel index.html player-video/index.html player-video/**/*.html\"\r\n  },\r\n  \"browserslist\": [\r\n    \"last 1 Chrome version\"\r\n  ]\r\n```\r\n\r\nTypeScript es un lenguaje de programación libre y de **código abierto** desarrollado y mantenido por **Microsoft**. Es un superconjunto de JavaScript, que esencialmente añade tipos estáticos y objetos basados en clases. [Anders Hejlsberg](https://es.wikipedia.org/wiki/Anders_Hejlsberg), diseñador de C# y creador de Delphi y Turbo Pascal, ha trabajado en el desarrollo de TypeScript.1​ TypeScript puede ser usado para desarrollar aplicaciones JavaScript que se ejecutarán en el lado del cliente o del servidor (**Node.js**).\r\n\r\nTypeScript extiende la sintaxis de JavaScript, por tanto cualquier código JavaScript existente debería funcionar sin problemas. Está pensado para grandes proyectos, los cuales a través de un compilador de TypeScript se traducen a código JavaScript original.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Tipos básicos en Typescript\r\n\r\n- boolean. Valor verdadero o falso.\r\n- number. Números.\r\n- string. Cadenas de texto.\r\n- string[]. Arreglo del tipo cadena de texto.\r\n- Array. Arreglo multi-tipo, acepta cadenas de texto o números.\r\n- enum. Es un tipo especial llamado enumeración.\r\n- any. Cualquier tipo.\r\n- object. Del tipo objeto.\r\n\r\n```ts\r\n// TypeScript por Jasan Hernández\r\n// Boolean\r\nlet muted: boolean = true;\r\nmuted = false;\r\n\r\n// Numbers\r\nlet numerador: number = 42;\r\nlet denomindador: number = 6;\r\nlet resultado = numerador / denomindador;\r\n\r\n// String\r\nlet nombre: string = \"Jasan\";\r\nlet saludo: string = `Me llamo ${nombre}`;\r\n\r\n// Arreglos\r\nlet people: string[] = [];\r\npeople = [\"Isabel\", \"Nicole\", \"Raúl\"];\r\n// people.push(34);\r\n\r\n// Arreglos de Strings and numbers:\r\nlet peopleAndNumbers: Array<string | number> = [];\r\npeopleAndNumbers.push(\"Ricardo\");\r\npeopleAndNumbers.push(345);\r\n\r\n// Enum\r\nenum Color {\r\n  Rojo = \"Rojo\",\r\n  Verde = \"Verde\",\r\n  Azul = \"Amarillo\",\r\n}\r\nlet colorFavorito: Color = Color.Azul;\r\nconsole.log(`Mi color favorito es: ${colorFavorito}`);\r\n\r\n// Any\r\nlet comodin: any  = \"Joker\";\r\ncomodin = { type: \"WildCard\" }\r\n\r\n// Object \r\nlet someObject: object = { type: \"WildCard\" };\r\n```\r\n<br>\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Funciones en Typescript\r\n\r\nEn Javascript las funciones toman argumentos y pudieran regresar algun valor. **En Typescript** podemos ser explícitos de cómo deben ser esos argumentos y también podemos proveer información de cuál es valor que debe regresar la función.\r\n\r\nTypescript va a evitar que cometamos errores que le puedan pasar a cualquiera, typescript es programación pareja, escribes y tu pareja te va diciendo: \"ahí tienes un error\".\r\n\r\n```ts\r\n// Funciones\r\nfunction add(a: number, b: number): number {\r\n  return a + b;\r\n}\r\nconst sum = add(4, 25)\r\n\r\nfunction createAdder(a: number): (number) => number {\r\n  return function (b: number) {\r\n    return a + b;\r\n  }\r\n}\r\n\r\nconst addFour = createAdder(4);\r\nconst fourPlus6 = addFour(6);\r\n\r\nfunction fullName(firtsName: string, lastName?: string): string {\r\n  return `${firtsName} ${lastName}`;\r\n}\r\nconst jasan = fullName('Jasan');\r\n\r\nfunction fullValue(firtsName: string = \"Pepe\", lastName: string = \"Smith\"): string {\r\n  return `${firtsName} ${lastName}`;\r\n}\r\nconst person = fullValue();\r\n```\r\n<br>\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Interfaces en Typescript\r\n\r\nLas interfaces nos permiten declarar la forma que tiene un objeto, esto puede ser útil porque nos ayuda en autocompletado y evitar cometer algunos errores.\r\n\r\n```ts\r\nenum Color {\r\n  Rojo = \"Rojo\",\r\n  Verde = \"Verde\"\r\n};\r\n\r\ninterface Rectangulo {\r\n  height: number,\r\n  width: number\r\n  color?: Color\r\n}\r\n\r\nlet rect: Rectangulo = {\r\n  height: 4,\r\n  width: 3,\r\n  // color: Color.Verde\r\n}\r\n\r\nfunction area(r: Rectangulo) {\r\n  return r.height * r.width;\r\n}\r\n\r\nconst areaReact = area(rect);\r\nrect.toString = function () {\r\n  return this.color ? `Un rectangulo ${this.color}` : `Un rectangulo`;\r\n}\r\n\r\nconsole.log(rect.toString());\r\n```\r\n\r\nLas interfaces definen la forma exacta que debe tener un objeto, no podemos añadir propiedades de más ni de menos. En caso de que una propiedad sea opcional la tenemos que marcar como opcional\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Clases en Typescript\r\n\r\nJavaScript tradicional utiliza funciones y herencia basada en prototipos para construir componentes reutilizables, pero esto puede resultar un poco incómodo para los programadores más cómodos con un enfoque orientado a objetos, donde las clases heredan la funcionalidad y los objetos se crean a partir de estas clases. A partir de ECMAScript 2015, también conocido como ECMAScript 6, los programadores de JavaScript podrán construir sus aplicaciones utilizando este enfoque basado en clases orientado a objetos. En TypeScript, permitimos que los desarrolladores usen estas técnicas ahora y las compilen en JavaScript que funcione en todos los principales navegadores y plataformas, sin tener que esperar a la próxima versión de JavaScript.\r\n\r\nEchemos un vistazo a un ejemplo simple basado en clases:\r\n\r\n```ts\r\nclass Greeter {\r\n    greeting: string;\r\n    constructor(message: string) {\r\n        this.greeting = message;\r\n    }\r\n    greet() {\r\n        return\"Hello, \" + this.greeting;\r\n    }\r\n}\r\n\r\nlet greeter = new Greeter(\"world\");\r\n```\r\n\r\nLa sintaxis debería resultarle familiar si ha usado C # o Java anteriormente. Declaramos una nueva clase Greeter. Esta clase tiene tres miembros: una propiedad llamada greeting, un constructor y un método greet.\r\n\r\nNotarás que en la clase cuando nos referimos a uno de los miembros de la clase que anteponemos this.. Esto denota que es un acceso de miembro.\r\n\r\nEn la última línea construimos una instancia de la Greeterclase usando new. Esto llama al constructor que definimos anteriormente, creando un nuevo objeto con la Greeterforma y ejecutando el constructor para inicializarlo.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Herencia Typescript\r\n\r\nEn TypeScript podemos usar patrones comunes orientados a objetos. Uno de los patrones más fundamentales en la programación basada en clases es poder extender las clases existentes para crear otras nuevas usando la herencia.\r\n\r\nEchemos un vistazo a un ejemplo:\r\n```ts\r\nclass Animal {\r\n    move(distanceInMeters: number = 0) {\r\n        console.log(`Animal moved ${distanceInMeters}m.`);\r\n    }\r\n}\r\n\r\nclass Dog extends Animal {\r\n    bark() {\r\n        console.log('Woof! Woof!');\r\n    }\r\n}\r\n\r\nconst dog = new Dog();\r\ndog.bark();\r\ndog.move(10);\r\ndog.bark();\r\n```\r\nEste ejemplo muestra la característica de herencia más básica: las clases heredan propiedades y métodos de las clases base. Aquí, Doghay una clase derivada que deriva de la clase Animalbase usando la extendspalabra clave. Las clases derivadas a menudo se denominan subclases , y las clases base a menudo se denominan superclases .\r\n\r\nDebido a que Dogextiende la funcionalidad desde Animal, pudimos crear una instancia de Dogque podría ambos bark()y move().\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Modificadores de Acceso en Typescript\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Público por defecto\r\n\r\nEn nuestros ejemplos, hemos podido acceder libremente a los miembros que declaramos en todos nuestros programas. Si está familiarizado con las clases en otros idiomas, puede haber notado en los ejemplos anteriores que no hemos tenido que usar la palabrapublic para lograr esto; por ejemplo, C # requiere que cada miembro este explícitamente etiquetado publiccomo visible. En TypeScript, cada miembro es publicpor defecto.\r\n\r\nAún puede marcar un miembro publicexplícitamente. Podríamos haber escrito la Animalclase de la sección anterior de la siguiente manera:\r\n\r\n```ts\r\nclass Animal {\r\n    public name: string;\r\n    publicconstructor(theName: string) { this.name = theName; }\r\n    public move(distanceInMeters: number) {\r\n        console.log(`${this.name} moved ${distanceInMeters}m.`);\r\n    }\r\n}\r\n```\r\n<br>\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Private\r\nCuando se marca un miembro private, no se puede acceder desde fuera de su clase que lo contiene. Por ejemplo:\r\n\r\n```ts\r\nclass Animal {\r\n    private name: string;\r\n    constructor(theName: string) { this.name = theName; }\r\n}\r\n\r\nnew Animal(\"Cat\").name; // Error: 'name' is private;\r\n```\r\nTypeScript es un sistema de tipo estructural. Cuando comparamos dos tipos diferentes, independientemente de su procedencia, si los tipos de todos los miembros son compatibles, entonces decimos que los tipos mismos son compatibles.\r\n\r\nSin embargo, al comparar tipos que tienen private y protectedmiembros, tratamos estos tipos de manera diferente. Para que dos tipos se consideren compatibles, si uno de ellos tiene un privatemiembro, el otro debe tener un privatemiembro que se originó en la misma declaración. Lo mismo se aplica a los protectedmiembros.\r\n\r\nVeamos un ejemplo para ver mejor cómo se desarrolla esto en la práctica:\r\n\r\n```ts\r\nclass Animal {\r\n    private name: string;\r\n    constructor(theName: string) { this.name = theName; }\r\n}\r\n\r\nclass Rhino extends Animal {\r\n    constructor() { super(\"Rhino\"); }\r\n}\r\n\r\nclass Employee {\r\n    private name: string;\r\n    constructor(theName: string) { this.name = theName; }\r\n}\r\n\r\nlet animal = new Animal(\"Goat\");\r\nlet rhino = new Rhino();\r\nlet employee = new Employee(\"Bob\");\r\n\r\nanimal = rhino;\r\nanimal = employee; // Error: 'Animal' and 'Employee' are not compatible\r\n```\r\n\r\nEn este ejemplo, tenemos una Animaly una Rhino, con Rhinoser una subclase de Animal. También tenemos una nueva clase Employee que se ve idéntica Animalen términos de forma. Creamos algunas instancias de estas clases y luego tratamos de asignarlas entre sí para ver qué sucederá. Porque Animal y Rhino comparten el private lado de su forma desde la misma declaración de private name: string in Animal, son compatibles. Sin embargo, este no es el caso Employee. Cuando intentamos asignar de a Employee a Animal, obtenemos un error de que estos tipos no son compatibles. Aunque Employee también tiene un private miembro llamado name, no es el que declaramos en Animal .\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Protected\r\n\r\nEl protected modificador actúa de manera muy similar al private modificador con la excepción de que los miembros declarados protected también pueden accederse dentro de las clases derivadas. Por ejemplo:\r\n\r\n```ts\r\nclass Person {\r\n    protected name: string;\r\n    constructor(name: string) { this.name = name; }\r\n}\r\n\r\nclass Employee extends Person {\r\n    private department: string;\r\n\r\n    constructor(name: string, department: string) {\r\n        super(name);\r\n        this.department = department;\r\n    }\r\n\r\n    public getElevatorPitch() {\r\n        return`Hello, my name is ${this.name} and I work in ${this.department}.`;\r\n    }\r\n}\r\n\r\nlet howard = new Employee(\"Howard\", \"Sales\");\r\nconsole.log(howard.getElevatorPitch());\r\nconsole.log(howard.name); // error\r\n```\r\n\r\nTenga en cuenta que si bien no podemos usarlo nam edesde fuera Person, aún podemos usarlo desde un método de instancia de Employee porque Employee deriva de Person .\r\n\r\nUn constructor también puede estar marcado protected. Esto significa que la clase no se puede instanciar fuera de su clase que contiene, sino que se puede extender. Por ejemplo:\r\n\r\n```ts\r\nclass Person {\r\n    protected name: string;\r\n    protected constructor(theName: string) { this.name = theName; }\r\n}\r\n\r\n// Employee can extend Person\r\nclass Employee extends Person {\r\n    private department: string;\r\n\r\n    constructor(name: string, department: string) {\r\n        super(name);\r\n        this.department = department;\r\n    }\r\n\r\n    public getElevatorPitch() {\r\n        return`Hello, my name is ${this.name} and I work in ${this.department}.`;\r\n    }\r\n}\r\n\r\nlet howard = new Employee(\"Howard\", \"Sales\");\r\nlet john = new Person(\"John\"); // Error: The 'Person' constructor is protected\r\n```\r\n<br>\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Convertir Proyecto a Typescript\r\n\r\nQuick fix es algo que vas a poder usar si usas typescript y Visual Studio Code. VSC ya trae un plugin que habilita todas estas funcionalidades de a gratis, esa es una buenas convinaciones en el desarrollo de js. vscode y typescript.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Refactorización\r\n\r\nLa [refactorización del código fuente](https://en.wikipedia.org/wiki/Code_refactoring) puede mejorar la calidad y la facilidad de mantenimiento de su proyecto al reestructurar su código sin modificar el comportamiento del tiempo de ejecución. Visual Studio Code admite operaciones de refactorización (refactorizaciones) como el Método deextracción y la [Variable de extracción](https://refactoring.com/catalog/extractVariable.html) para mejorar su base de código desde su editor.\r\n\r\n**La refactorización de código** es el proceso de reestructurar el código de computadora existente, cambiar la [factorización](https://en.wikipedia.org/wiki/Decomposition_(computer_science)), sin cambiar su comportamiento externo. La refactorización está destinada a mejorar los atributos [no funcionales](https://en.wikipedia.org/wiki/Non-functional_requirement) del [software](https://en.wikipedia.org/wiki/Software) . Las ventajas incluyen [legibilidad](https://en.wikipedia.org/wiki/Readability) mejorada del código y [complejidad] reducida ; Estos pueden mejorar el [mantenimiento del código fuente](https://en.wikipedia.org/wiki/Maintainability) y crear una [arquitectura] interna más expresiva o [un modelo de objeto] para mejorar la [extensibilidad](https://en.wikipedia.org/wiki/Extensibility).\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Patrones de diseño\r\n\r\nLos patrones de diseño son unas técnicas para resolver problemas comunes en el [desarrollo de software](https://es.wikipedia.org/wiki/Ingenier%C3%ADa_de_software) y otros ámbitos referentes al diseño de interacción o interfaces.\r\n\r\nUn patrón de diseño resulta ser una solución a un problema de diseño. Para que una solución sea considerada un patrón debe poseer ciertas características. Una de ellas es que debe haber comprobado su efectividad resolviendo problemas similares en ocasiones anteriores. Otra es que debe ser reutilizable, lo que significa que es aplicable a diferentes problemas de diseño en distintas circunstancias.\r\n\r\n**Sumary**:\r\nLos patrones de diseño son como recetas que resuelven problemas que nos enfrentamos frecuentemente en el diseño de software, en especifico, son una solución de un problema dentro de un contexto, y este contexto no se vale que ocurra una sola vez, tiene que pasar muchas veces. Porque si ocurriera una sola vez, fuera una solución pero no lo podemos categorizar como un patrón de diseño, los patrones de diseño van a resolver problemas dentro de un contexto recurrente.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Objetivos de los patrones de diseño\r\n\r\nLos patrones de diseño pretenden:\r\n\r\n- Proporcionar catálogos de elementos reusables en el diseño de sistemas software.\r\n- Evitar la reiteración en la búsqueda de soluciones a problemas ya conocidos y solucionados anteriormente.\r\n- Formalizar un vocabulario común entre diseñadores.\r\n- Estandarizar el modo en que se realiza el diseño.\r\n- Facilitar el aprendizaje de las nuevas generaciones de diseñadores condensando conocimiento ya existente.\r\n\r\nAsimismo, no pretenden:\r\n\r\n- Imponer ciertas alternativas de diseño frente a otras.\r\n- Eliminar la creatividad inherente al proceso de diseño.\r\n\r\nNo es obligatorio utilizar los patrones, solo es aconsejable en el caso de tener el mismo problema o similar que soluciona el patrón, siempre teniendo en cuenta que en un caso particular puede no ser aplicable. \"Abusar o forzar el uso de los patrones puede ser un error\".\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Historia sobre Patrones de diseño\r\n\r\nNo los inventaron los ingenieros de software, programadores o desarrolladores, los patrones de diseño vienen de la arquitectura de estos 2 libros: [The timeless way of building](https://en.wikipedia.org/wiki/The_Timeless_Way_of_Building) y [A Pattern Language](https://en.wikipedia.org/wiki/A_Pattern_Language) escritos por [Christopher Alexander](https://en.wikipedia.org/wiki/Christopher_Alexander). \r\n\r\nLo que buscaba este author era reconocer ciertos patrones que el veía en la arquitectura, no solo en la moderna, sino en la arquitectura de toda la historia y así poder construir un lenguaje. Cuando tienes un lenguaje sobre todos estos conceptos y entre arquitectos se hablan estas palabras, saben que se están referiendo a algo exactamente, algo muy particular, una idea exacta. Y cuando los recopilas estás creando un recetario para futuras generaciones de arquitectos que vayan a hacer nuevos edificios, nadie quiere reinventar la rueda cuando ya la inventamos y además funciona bien.\r\n\r\nDe aquí 4 personas que conocemos como el  Gang of Four (GoF) o Ganga de cuatro, compuesto por **Erich Gamma**, **Richard Helm**, **Ralph Johnson** y **John Vlissides**, en el que se recogían 23 patrones de diseño comunes. Son 4 authores que escribieron un libro famosísimo que se llama [Design Patterns](https://en.wikipedia.org/wiki/Design_Patterns). \r\n\r\n\r\nDesde aquí que el sofware comienza a tomar estás ideas, es un libro de los 90s pero su importancia y validez aún se mantiene. \r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Beneficios de utilizar patrones de diseño\r\n\r\n- Son una caja bien probadas a problemas comunes en diseño de software.\r\n- Te proveen un lenguaje común que te permiten comunicarte de una forma específica y eficiente.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Desventajas de utilizar patrones de diseño\r\n\r\n- Introducen un nivel de complejidad\r\n- Son soluciones a las limitaciones de un lenguaje de programación. ejemplo: Java o C# no tienen funciones de alto nivel.\r\n- \"Cuando lo que tienes es un martillo, todo te parece un clavo\".\r\n\r\nNo es algo que constamente vamos a estar buscando usar, siempre debemos tratar de resolver los problemas de una forma simple natural. Pero cuando ya vemos que no hay una forma fácil, podemos ir a los patrones de diseño y decir, vemos si ya una solución detallada que podamos aplicar.\r\n\r\nLos patrones, como todas las formas de complejidad, deben evitarse hasta que sean absolutamente necesarios.\r\n\r\nRecuerda no siempre estar pensando en patrones de diseño, deja que naturalmente surjan las necesidades para usarlos, porque siempre preferimos tener programas que sean simples. Y recuerda que los patrones de diseño van a incluir un nivel de complejidad.\r\n\r\nsaber más [codigohorror](https://blog.codinghorror.com/head-first-design-patterns/)\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Categorias de patrones de diseño\r\n\r\nEl libro Design Patterns de GoF definió la lita inicial de patrones de diseño de software, los dividió en 3 categorías:\r\n\r\n- Patrones creacionales\r\n- Patrones estructurales\r\n- Patrones de comportamiento\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Patrones Creacionales\r\n\r\nProveen diferentes mecanismos para crear objetos. Nos ayudan a encapsular y abstraer dicha creación:\r\n\r\n[Object Pool](https://es.wikipedia.org/wiki/Object_pool_(patr%C3%B3n_de_dise%C3%B1o)) (Pisicina de objetos): no pertenece a los patrones especificados por GoF): se obtienen objetos nuevos a través de la clonación. Utilizado cuando el costo de crear una clase es mayor que el de clonarla. Especialmente con objetos muy complejos. Se especifica un tipo de objeto a crear y se utiliza una interfaz del prototipo para crear un nuevo objeto por clonación. El proceso de clonación se inicia instanciando un tipo de objeto de la clase que queremos clonar.\r\n\r\n[Abstract Factory](https://es.wikipedia.org/wiki/Abstract_Factory) (fábrica abstracta): permite trabajar con objetos de distintas familias de manera que las familias no se mezclen entre sí y haciendo transparente el tipo de familia concreta que se este usando. El problema a solucionar por este patrón es el de crear diferentes familias de objetos, como por ejemplo, la creación de interfaces gráficas de distintos tipos (ventana, menú, botón, etc.).\r\n\r\n[Builder](https://es.wikipedia.org/wiki/Builder_(patr%C3%B3n_de_dise%C3%B1o)) (constructor virtual): abstrae el proceso de creación de un objeto complejo, centralizando dicho proceso en un único punto.\r\n\r\nEs usado para permitir la creación de una variedad de objetos complejos desde un objeto fuente. Es como si tenemos un punto de partida que es este objeto y vamos a poder tomar varios caminos dependiendo de cuales funciones o métodos llamemos.\r\n\r\nSepara la creación de objeto complejo de su estructura, de tal forma que el mismo proceso de construcción puede servir para crear representaciones diferentes.\r\n\r\n[Factory Method](https://es.wikipedia.org/wiki/Factory_Method_(patrón_de_diseño)) (método de fabricación): centraliza en una clase constructora la creación de objetos de un subtipo de un tipo determinado, ocultando al usuario la casuística, es decir, la diversidad de casos particulares que se pueden prever, para elegir el subtipo que crear. Parte del principio de que las subclases determinan la clase a implementar. A continuación se muestra un ejemplo de este patrón:\r\n\r\n```java\r\nclass ConcreteCreator extends Creator{\r\n    protected Product factoryMethod(){\r\n        return new ConcreteProduct();\r\n    }\r\n}\r\n\r\ninterface Product{...}\r\n\r\nclass ConcreteProduct implements Product{...}\r\n\r\npublic class Client{\r\n    public static void main(String args[])\r\n    {\r\n        Creator unCreator = new ConcreteCreator();\r\n        unCreator.factoryMethod();\r\n    }\r\n}\r\n```\r\n\r\n[Prototype](https://es.wikipedia.org/wiki/Prototipo_(patr%C3%B3n_de_dise%C3%B1o)) (prototipo): crea nuevos objetos clonándolos de una instancia ya existente.\r\n\r\n[Singleton](https://es.wikipedia.org/wiki/Singleton) (instancia única): garantiza la existencia de una única instancia para una clase y la creación de un mecanismo de acceso global a dicha instancia. Restringe la instanciación de una clase o valor de un tipo a un solo objeto. A continuación se muestra un ejemplo de este patrón:\r\n\r\nejemplo en Java:\r\n\r\n```java\r\npublic sealed class Singleton\r\n{\r\n    private static volatile Singleton instance;\r\n    private static object syncRoot = new Object();\r\n    private Singleton()\r\n    {\r\n        System.Windows.Forms.MessageBox.Show(\"Nuevo Singleton\");\r\n    }\r\n    public static Singleton GetInstance\r\n    {\r\n        get\r\n        {\r\n            if (instance == null)\r\n            {\r\n                lock(syncRoot)\r\n                {\r\n                    if (instance == null)\r\n                    instance = new Singleton();\r\n                }\r\n            }\r\n            return instance;\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n[Model View Controller](https://es.wikipedia.org/wiki/Modelo%E2%80%93vista%E2%80%93controlador) (MVC) ♙En español: Modelo Vista Controlador. Es un patrón de arquitectura de software que separa los datos y la lógica de negocio de una aplicación de la interfaz de usuario y el módulo encargado de gestionar los eventos y las comunicaciones. Este patrón plantea la separación del problema en tres capas: la capa model, que representa la realidad; la capa controller , que conoce los métodos y atributos del modelo, recibe y realiza lo que el usuario quiere hacer; y la capa vista, que muestra un aspecto del modelo y es utilizada por la capa anterior para interactuar con el usuario.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Patrones estructurales\r\n\r\nDescriben formas de componer  objetos para formar nuevas estructuras flexibles y eficientes.\r\n\r\n- [Adapter o Wrapper](https://es.wikipedia.org/wiki/Adaptador_(patr%C3%B3n_de_dise%C3%B1o)) (Adaptador o Envoltorio): Adapta una interfaz para que pueda ser utilizada por una clase que de otro modo no podría utilizarla.\r\n- [Bridge](https://es.wikipedia.org/wiki/Bridge_(patrón_de_diseño)) (Puente): Desacopla una abstracción de su implementación.\r\n- [Composite](https://es.wikipedia.org/wiki/Composite_(patr%C3%B3n_de_dise%C3%B1o)) (Objeto compuesto): Permite tratar objetos compuestos como si de uno simple se tratase.\r\n- [Decorator](https://es.wikipedia.org/wiki/Decorator_(patr%C3%B3n_de_dise%C3%B1o)) (Decorador): Añade funcionalidad a una clase dinámicamente.\r\n- [Facade](https://es.wikipedia.org/wiki/Facade_(patr%C3%B3n_de_dise%C3%B1o)) (Fachada): Provee de una interfaz unificada simple para acceder a una interfaz o grupo de interfaces de un subsistema.\r\n- [Flyweight](https://es.wikipedia.org/wiki/Flyweight_(patr%C3%B3n_de_dise%C3%B1o)) (Peso ligero): Reduce la redundancia cuando gran cantidad de objetos poseen idéntica información.\r\n- [Proxy](https://es.wikipedia.org/wiki/Proxy_(patr%C3%B3n_de_dise%C3%B1o)): Proporciona un intermediario de un objeto para controlar su acceso.\r\n- [Module](https://es.wikipedia.org/wiki/M%C3%B3dulo_(patr%C3%B3n_de_dise%C3%B1o)): Agrupa varios elementos relacionados, como clases, singletons, y métodos, utilizados globalmente, en una entidad única.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Patrones de comportamiento\r\n\r\nGestionan algoritmos y responsabilidades. Estos patrones lo que ofrecen son formas de poder manejar diferentes algoritmos, funcionalidades que pueden llegar a tener tus objetos o las relaciones entre ellos.\r\n\r\nSe definen como patrones de diseño software que ofrecen soluciones respecto a la interacción y responsabilidades entre clases y objetos, así como los algoritmos que encapsulan:\r\n\r\n[Chain of Responsibility](https://es.wikipedia.org/wiki/Cadena_de_responsabilidad) (Cadena de responsabilidad): Permite establecer la línea que deben llevar los mensajes para que los objetos realicen la tarea indicada.\r\n[Command](https://es.wikipedia.org/wiki/Command_(patr%C3%B3n_de_dise%C3%B1o)) (Orden): Encapsula una operación en un objeto, permitiendo ejecutar dicha operación sin necesidad de conocer el contenido de la misma.\r\n[Interpreter](https://es.wikipedia.org/wiki/Interpreter_(patr%C3%B3n_de_dise%C3%B1o)) (Intérprete): Dado un lenguaje, define una gramática para dicho lenguaje, así como las herramientas necesarias para interpretarlo.\r\n[Iterator](https://es.wikipedia.org/wiki/Iterador_(patr%C3%B3n_de_dise%C3%B1o)) (Iterador): Permite realizar recorridos sobre objetos compuestos independientemente de la implementación de estos.\r\n[Mediator](https://es.wikipedia.org/wiki/Mediator_(patr%C3%B3n_de_dise%C3%B1o)) (Mediador): Define un objeto que coordine la comunicación entre objetos de distintas clases, pero que funcionan como un conjunto.\r\n[Memento](https://es.wikipedia.org/wiki/Memento_(patr%C3%B3n_de_dise%C3%B1o)) (Recuerdo): Permite volver a estados anteriores del sistema.\r\n[Observer](https://es.wikipedia.org/wiki/Observer_(patr%C3%B3n_de_dise%C3%B1o)) (Observador): Define una dependencia de uno-a-muchos entre objetos, de forma que cuando un objeto cambie de estado se notifique y actualicen automáticamente todos los objetos que dependen de él.\r\n[State](https://es.wikipedia.org/wiki/State_(patr%C3%B3n_de_dise%C3%B1o)) (Estado): Permite que un objeto modifique su comportamiento cada vez que cambie su estado interno.\r\n[Strategy](https://es.wikipedia.org/wiki/Strategy_(patr%C3%B3n_de_dise%C3%B1o)) (Estrategia): Permite disponer de varios métodos para resolver un problema y elegir cuál utilizar en tiempo de ejecución.\r\n[Template Method](https://es.wikipedia.org/wiki/Patr%C3%B3n_de_m%C3%A9todo_de_la_plantilla) (Método plantilla): Define en una operación el esqueleto de un algoritmo, delegando en las subclases algunos de sus pasos, esto permite que las subclases redefinan ciertos pasos de un algoritmo sin cambiar su estructura.\r\n[Visitor](https://es.wikipedia.org/wiki/Visitor_(patr%C3%B3n_de_dise%C3%B1o)) (Visitante): Permite definir nuevas operaciones sobre una jerarquía de clases sin modificar las clases sobre las que opera.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Patrón Singleton y casos de uso\r\n\r\nSingleton es un patron creacional. El Singleton te va ayudar a que una clase solo sea capaz de crear una sola instancia de sí misma, esa instancia siempre va a ser la misma. Para describir patrones de diseño siempre usamos una notación que se llama UML.\r\n\r\nDiagrama UML de una clase que implementa el patrón Singleton.\r\n\r\n<div align=\"center\">\r\n  <img src=\"../assets/umlsingleton.png\" alt=\"singleton uml\">\r\n</div>\r\n\r\nEn ingeniería de software, Singleton o instancia única es un patrón de diseño que permite restringir la creación de objetos pertenecientes a una clase o el valor de un tipo a un único objeto.\r\n\r\nSu intención consiste en garantizar que una clase solo tenga una instancia y proporcionar un punto de acceso global a ella.\r\n\r\nEl patrón singleton se implementa creando en nuestra clase un método que crea una instancia del objeto solo si todavía no existe alguna. Para asegurar que la clase no puede ser instanciada nuevamente se regula el alcance del constructor (con modificadores de acceso como protegido o privado).\r\n\r\nEl patrón singleton se implementa creando en nuestra clase un método que crea una instancia del objeto solo si todavía no existe alguna. Para asegurar que la clase no puede ser instanciada nuevamente se regula el alcance del constructor (con modificadores de acceso como protegido o privado).\r\n\r\nLa instrumentación del patrón puede ser delicada en programas con múltiples hilos de ejecución. Si dos hilos de ejecución intentan crear la instancia al mismo tiempo y esta no existe todavía, solo uno de ellos debe lograr crear el objeto. La solución clásica para este problema es utilizar exclusión mutua en el método de creación de la clase que implementa el patrón.\r\n\r\nLas situaciones más habituales de aplicación de este patrón son aquellas en las que dicha clase controla el acceso a un recurso físico único (como puede ser el ratón o un archivo abierto en modo exclusivo) o cuando cierto tipo de datos debe estar disponible para todos los demás objetos de la aplicación.\r\n\r\nEl patrón singleton provee una única instancia global gracias a que:\r\n\r\nLa propia clase es responsable de crear la única instancia.\r\nPermite el acceso global a dicha instancia mediante un método de clase.\r\nDeclara el constructor de clase como privado para que no sea instanciable directamente.\r\nAl estar internamente autoreferenciada, en lenguajes como Java, el recolector de basura no actúa.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Implementación del patrón Singleton con Typescript\r\n\r\nUno de los patrones de diseño de creación más populares es el patrón Singleton que restringe la creación de instancias de una clase a un objeto.\r\n\r\nEn esta publicación, le mostraré cómo usar el patrón junto con TypeScript.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Es genial con Typescript\r\n\r\nLa biblia de los patrones de diseño, a saber, el libro de Gang of Four (GoF), presenta la aplicación de patrones utilizando el lenguaje C ++, un lenguaje estáticamente tipado.\r\n\r\nTypeScript permite implementar el patrón Singleton gracias a las siguientes características:\r\n\r\n- soporte para modificadores de acceso (privado, protegido, público),\r\n- soporte para métodos estáticos,\r\n- siendo un lenguaje estáticamente escrito.\r\n\r\n```ts\r\nclass Singleton {\r\n  private static instance: Singleton;\r\n  private constructor() {\r\n    // initialition\r\n  }\r\n\r\n  static getInstance() {\r\n    if (!Singleton.instance) {\r\n      Singleton.instance = new Singleton();\r\n    }\r\n\r\n    return Singleton.instance;\r\n  }\r\n}\r\n\r\nexport default Singleton;\r\n```\r\nLuego podemos crear instancias de Singleton que harán referencia al mismo objeto en memoria.\r\n\r\n```ts\r\nimport Singleton from './Singleton';\r\n\r\nconst a = Singleton.getInstance();\r\nconst b = Singleton.getInstance();\r\n\r\nconsole.log(\"¿A es igual a B?\", a === b);\r\n```\r\n<br>\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Observer (patrón de diseño)\r\n\r\nObservador (en inglés:[ Observer](https://en.wikipedia.org/wiki/Observer_pattern)) es un [patrón de diseño](https://es.wikipedia.org/wiki/Patr%C3%B3n_de_dise%C3%B1o) de software que define una dependencia del tipo uno a muchos entre objetos, de manera que cuando uno de los objetos cambia su estado, notifica este cambio a todos los dependientes. Se trata de un patrón de comportamiento (existen de tres tipos: creación, estructurales y de comportamiento), por lo que está relacionado con algoritmos de funcionamiento y asignación de responsabilidades a [clases](https://es.wikipedia.org/wiki/Clase_(inform%C3%A1tica)) y [objetos](https://es.wikipedia.org/wiki/Objeto_(programaci%C3%B3n)).\r\n\r\nLos patrones de comportamiento describen no solamente estructuras de relación entre objetos o clases sino también esquemas de comunicación entre ellos y se pueden clasificar en función de que trabajen con clases (método plantilla) u objetos (cadena de responsabilidad, comando, iterador, recuerdo, observador, estado, estrategia, visitante).\r\n\r\nLa variación de la encapsulación es la base de muchos patrones de comportamiento, por lo que cuando un aspecto de un programa cambia frecuentemente, estos patrones definen un objeto que encapsula dicho aspecto. Los patrones definen una clase abstracta que describe la encapsulación del objeto.\r\n\r\nEste patrón también se conoce como el patrón de publicación-inscripción o modelo-patrón. Estos nombres sugieren las ideas básicas del patrón, que son: el objeto de datos, que se le puede llamar Sujeto a partir de ahora, contiene atributos mediante los cuales cualquier objeto observador o vista se puede suscribir a él pasándole una referencia a sí mismo. El Sujeto mantiene así una lista de las referencias a sus observadores. Los observadores a su vez están obligados a implementar unos métodos determinados mediante los cuales el Sujeto es capaz de notificar a sus observadores suscritos los cambios que sufre para que todos ellos tengan la oportunidad de refrescar el contenido representado. De manera que cuando se produce un cambio en el Sujeto, ejecutado, por ejemplo, por alguno de los observadores, el objeto de datos puede recorrer la lista de observadores avisando a cada uno. Este patrón suele utilizarse en los [entornos de trabajo](https://es.wikipedia.org/wiki/Framework) de interfaces gráficas orientados a objetos, en los que la forma de capturar los eventos es suscribir listeners a los objetos que pueden disparar eventos.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Objetivo\r\n\r\nDefinir una dependencia uno a muchos entre objetos, de tal forma que cuando el objeto cambie de estado, todos sus objetos dependientes sean notificados automáticamente. Se trata de desacoplar la clase de los objetos clientes del objeto, aumentando la modularidad del lenguaje, creando las mínimas dependencias y evitando bucles de actualización (espera activa o sondeo). En definitiva, normalmente, se usará el patrón observador cuando un elemento quiere estar pendiente de otro, sin tener que estar comprobando de forma continua si ha cambiado o no.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Motivación\r\n\r\nSi se necesita consistencia entre clases relacionadas, pero con independencia, es decir, con un bajo [acoplamiento](https://es.wikipedia.org/wiki/Acoplamiento_(inform%C3%A1tica)).\r\n\r\n<div align=\"center\">\r\n  <img src=\"../assets/observer.png\" alt=\"observer uml\">\r\n</div>\r\nEl patrón observador es la clave del patrón de arquitectura Modelo Vista Controlador (MVC).1​ De hecho el patrón fue implementado por primera vez en el MVC de Smalltalk basado en un entorno de trabajo de interfaz.2​ Este patrón está implementado en numerosos bibliotecas y sistemas, incluyendo todos los toolkits de GUI.\r\n\r\nPatrones relacionados: publicador-subscriptor, mediador, singleton.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Participantes\r\n\r\nHabrá sujetos concretos cuyos cambios pueden resultar interesantes a otros y observadores a los que al menos les interesa estar pendientes de un elemento y en un momento dado, reaccionar ante sus notificaciones de cambio. Todos los sujetos tienen en común que un conjunto de objetos quieren estar pendientes de ellos. Cualquier elemento que quiera ser observado tiene que permitir indicar:\r\n\r\n1. \"Estoy interesado en tus cambios\".\r\n1. \"Ya no estoy interesado en tus cambios\".\r\n\r\nEl observable tiene que tener, además, un mecanismo de aviso a los interesados. A continuación se detallan a los participantes de forma desglosada:\r\n\r\n**Sujeto (subject):**\r\nEl sujeto proporciona una interfaz para agregar (attach) y eliminar (detach) observadores. El Sujeto conoce a todos sus observadores.\r\n\r\n**Observador (observer):**\r\nDefine el método que usa el sujeto para notificar cambios en su estado (update/notify).\r\n**Sujeto concreto (concrete subject):**\r\nMantiene el estado de interés para los observadores concretos y los notifica cuando cambia su estado. No tienen porque ser elementos de la misma jerarquía.\r\n\r\n**Observador concreto (concrete observer):**\r\nMantiene una referencia al sujeto concreto e implementa la interfaz de actualización, es decir, guardan la referencia del objeto que observan, así en caso de ser notificados de algún cambio, pueden preguntar sobre este cambio.\r\n\r\nEs uno de los patrones más utilizados, algunos ejemplos típicos son\r\n\r\n- Newsletter\r\n- Sockets\r\n- Listeners en páginas web\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Implicaciones sobre Observer\r\n\r\n**Problema 1:**\r\n\r\nPara evitar que el observador concreto tenga una asociación con el sujeto concreto, se podría hacer que la relación entre sujeto y observador fuese bidireccional, evitando así asociaciones concretas, el problema es que dejaría de ser una interfaz. El que deje de ser una interfaz puede producir problemas si el lenguaje de programación no soporta la [herencia múltiple](https://es.wikipedia.org/wiki/Herencia_m%C3%BAltiple).\r\n\r\nSe podría eliminar la bidireccionalidad de la asociación pasando el sujeto como parámetro al método actualizar y ya no se tendría que referenciar el objeto observado. Esto podría causar problemas si se observan varios objetos, tanto de la misma clase como de distintas, ya que no elimina dependencias, y para hacer operaciones específicas sobre el objeto actualizado obliga a hacer en la implementación.\r\n\r\n**Problema 2:**\r\nSi hay muchos sujetos sin observador, la estructura de los observadores está desaprovechada, para solucionarlo se puede tener un intermediario que centralice el almacenamiento de la asociación de cada sujeto con sus observadores. Para esta solución se crea ese gestor de observadores usando el patrón [singleton](https://es.wikipedia.org/wiki/Singleton) (instancia única), ya que proporciona una única referencia y no una por cada sujeto. El gestor aunque mejora el aprovechamiento del espacio, hace que se reduzca el rendimiento y se pierde eficiencia en el método notificar.\r\n\r\n**Problema 3:**\r\nEl responsable de iniciar la comunicación es el sujeto concreto, pero se puede dar un problema cuando el objeto concreto está siendo actualizado de forma continua ya que debido a esto se tendría que realizar muchas actualizaciones en muy poco tiempo. La solución sería suspender temporalmente las llamadas al método de actualización/notificación; por ejemplo, haciendo que el cliente pueda activar o desactivar las notificaciones y notificar todos los cambios cuando las vuelva a habilitar. El patrón Estado sería una posible solución para diseñar esta variante de no notificar si no se han dado cambios o hacerlo en caso de que si.\r\n\r\n**Problema 4 (referencias inválidas):**\r\nA la hora de implementar este patrón se debe tener cuidado cuando un elemento observable desaparece. En ciertos lenguajes será el gestor de memoria el que cada cierto tiempo debe de limpiar las referencias liberadas, pero si un observable que sigue siendo observado puede no liberarse nunca. Para solucionar este problema puede crearse una función destruir que notifique al gestor que el elemento observable va a desaparecer y si no se está usando la variante del gestor el observable directamente desregistrará a sus observadores. Antes de esto hay que eliminar las referencias a este elemento, por tanto, hay que eliminar a los observadores antes de eliminar al observable, ya que así se evitará tanto que aparezcan referencias inválidas al objeto una vez este haya sido eliminado, como que se produzcan operaciones inválidas intentando invocarlo.\r\n\r\nSe puede avisar a los observadores creando un método actualizar especial, en el que se tendrían dos opciones:\r\n\r\n1. El observador también muere.\r\n2. El observador sigue vivo, pero apunta a nulo.\r\n\r\n**Problema 5:**\r\nYa que se debe asegurar la consistencia del estado del sujeto antes de iniciar una notificación, siempre se notificará al final, ya que aunque en entorno multihilo se notifica antes de hacer los cambios, puede que los observadores soliciten información al observable cuando aún se van a hacer más cambios y se darían problemas de consistencia si se accede a un estado que aún no es el definitivo. De esta forma, los observadores ya no accederán a sujetos en estado inconsistente.\r\n\r\nPor ejemplo:\r\n\r\nSecuencia incorrecta:\r\na\r\nb\r\nc\r\nnotificar()\r\nd\r\ne\r\nf\r\nSecuencia correcta:\r\na\r\nb\r\nc\r\nd\r\ne\r\nf\r\nnotificar()\r\n\r\nJerarquía con varios tipos des observadores: en este caso el hilo redefine cambios, no los notifica.\r\n\r\n<div align=\"center\">\r\n  <img src=\"../assets/JerarquiasObservador.png\" alt=\"jerarquias observador\">\r\n</div>\r\n\r\nJerarquía de varios observadores\r\n\r\n**Problema 6:**\r\nEn mecanismos de notificación tradicionalmente hay dos opciones: pull que es la que propone el patrón observador; y push que es la que se tendría si se incluye información como parámetros en el mecanismo de actualización. El problema de hacer esto es que la interfaz del observador se vuelve más específica y por tanto menos genérica y reutilizable.\r\n\r\nPULL: los objetos avisan de que han cambiado y el observador pregunta cuál ha sido el cambio.\r\n\r\nPUSH: minimiza (eficiencia) que cuando algo cambia y se informará a todos los interesados, se realicen el menor número de llamadas posibles.\r\n\r\nDependiendo del problema que haya que resolver, se habrá de valorar que implementación se ajusta mejor para resolverlo de la forma más eficiente y efectiva o si las variantes anteriores pueden combinarse entre sí dependiendo de las características de escenario concreto. Por ejemplo, la opción 2 podría aplicarse cuando interese aplicar en un sujeto concreto n métodos seguidos y no se quiere notificar hasta que todos finalicen su ejecución.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Implementación del patrón Observer con Typescript\r\n\r\nDocuento HTML:\r\n```html\r\n<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n  <meta charset=\"UTF-8\">\r\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n  <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\r\n  <title>Observer</title>\r\n</head>\r\n<body>\r\n  <h1>Precio del Bitcoin</h1>\r\n  <p><em id=\"price\">$0.00</em></p>\r\n\r\n  <input type=\"text\" id=\"value\">\r\n\r\n  <script src=\"index.ts\"></script>\r\n</body>\r\n</html>\r\n```\r\n\r\nLógica de Typescript\r\n```ts\r\n// Definiendo algunas interfaces\r\n\r\ninterface Observer {\r\n  updated: (data: any) => void;\r\n\r\n}\r\n\r\ninterface Subject {\r\n  subscribe: (observer: Observer) => void;\r\n  unsubscribe: (observer: Observer) => void;\r\n}\r\n\r\nclass BitcoinPrice implements Subject {\r\n  observers: Observer[] = [];\r\n\r\n  constructor() {\r\n    const el: HTMLInputElement = document.querySelector(\"#value\");\r\n    el.addEventListener('input', () => {\r\n      this.notify(el.value);\r\n    })\r\n  }\r\n\r\n  subscribe(observer: Observer) {\r\n    this.observers.push(observer)\r\n  }\r\n\r\n  unsubscribe(observer: Observer) {\r\n    const index = this.observers.findIndex(obs => {\r\n      return obs === observer;\r\n    })\r\n\r\n    this.observers.splice(index, 1);\r\n  }\r\n\r\n  notify(data: any) {\r\n    this.observers.forEach(observer => observer.updated(data))\r\n  }\r\n}\r\n\r\nclass PriceDisplay implements Observer {\r\n  private el: HTMLElement;\r\n\r\n  constructor() {\r\n    this.el = document.querySelector(\"#price\");\r\n  }\r\n  updated(data: any) { \r\n    this.el.innerText = data;\r\n  }\r\n}\r\n\r\nconst value = new BitcoinPrice();\r\nconst display = new PriceDisplay();\r\n\r\n// Subscribimos el Display al Value\r\nvalue.subscribe(display);\r\n\r\n// Simulamos unsubscribe usando un setTimeout de 5 segundos\r\nsetTimeout(\r\n  () => value.unsubscribe(display),\r\n  5000\r\n)\r\n```\r\n<br>\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Casos de uso del patrón Observer: Redux\r\n\r\n<div align=\"center\">\r\n  <img src=\"../assets/redux.png\" alt=\"redux header\">\r\n</div>\r\n\r\nTe ayuda a escribir aplicaciones que se comportan de manera consistente, corren en distintos ambientes (cliente, servidor y nativo), y son fáciles de probar. Además de eso, provee una gran experiencia de desarrollo, gracias a [edición en vivo combinado con un depurador sobre una línea de tiempo](https://github.com/reduxjs/redux-devtools).\r\n\r\nPuedes usar Redux combinado con React, o cual cualquier otra librería de vistas. Es muy pequeño (2kB) y no tiene dependencias.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Conceptos básicos\r\n\r\nRedux de por si es muy simple.\r\n\r\nImagine que el estado de su aplicación se describe como un simble objeto. Por ejemplo, el estado de una aplicación de tareas (TODO List) puede tener el siguiente aspecto:\r\n\r\n```js\r\n{\r\n  todos: [{\r\n    text: 'Comer',\r\n    completed: true\r\n  }, {\r\n    text: 'Hacer ejercicio',\r\n    completed: false\r\n  }],\r\n  visibilityFilter: 'SHOW_COMPLETED'\r\n}\r\n```\r\n\r\nEste objeto es como un “modelo” excepto que no hay setters. Esto es así para que diferentes partes del código no puedan cambiar el estado arbitrariamente, causando errores difíciles de reproducir.\r\n\r\nPara cambiar algo en el estado, es necesario enviar una acción. Una acción es un simple objeto en JavaScript (observe cómo no introducimos ninguna magia) que describe lo que sucedió. A continuación mostramos algunos ejemplos de acciones:\r\n\r\n```js\r\n{ type: 'ADD_TODO', text: 'Ir a nadar a la piscina' }\r\n{ type: 'TOGGLE_TODO', index: 1 }\r\n{ type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_ALL' }\r\n```\r\n\r\nHacer valer que cada cambio sea descrito como una acción nos permite tener una claro entendimiento de lo que está pasando en la aplicación. Si algo cambió, sabemos por qué cambió. Las acciones son como migas de pan (el rastro) de lo que ha sucedido. Finalmente, para juntar el estado y las acciones entre si, escribimos una función llamada reductor (reducer). Una vez más, nada de magia sobre él asunto, es sólo una función que toma el estado y la acción como argumentos y devuelve el siguiente estado de la aplicación. Sería difícil escribir tal función para una aplicación grande, por lo que escribimos funciones más pequeñas que gestionan partes del estado:\r\n\r\n```js\r\nfunction visibilityFilter(state = 'SHOW_ALL', action) {\r\n  if (action.type === 'SET_VISIBILITY_FILTER') {\r\n    return action.filter;\r\n  } else {\r\n    return state;\r\n  }\r\n}\r\n\r\nfunction todos(state = [], action) {\r\n  switch (action.type) {\r\n  case 'ADD_TODO':\r\n    return state.concat([{ text: action.text, completed: false }]);\r\n  case 'TOGGLE_TODO':\r\n    return state.map((todo, index) =>\r\n      action.index === index ?\r\n        { text: todo.text, completed: !todo.completed } :\r\n        todo\r\n   )\r\n  default:\r\n    return state;\r\n  }\r\n}\r\n```\r\n\r\nY escribimos otro reductor que gestiona el estado completo de nuestra aplicación llamando a esos dos reductores por sus respectivas state keys:\r\n\r\n```js\r\nfunction todoApp(state = {}, action) {\r\n  return {\r\n    todos: todos(state.todos, action),\r\n    visibilityFilter: visibilityFilter(state.visibilityFilter, action)\r\n  };\r\n}\r\n```\r\n\r\nEsto es básicamente toda la idea de Redux. Tenga en cuenta que no hemos utilizado ninguna API de Redux. Ya se incluyen algunas utilidades para facilitar este patrón, pero la idea principal es que usted describe cómo su estado se actualiza con el tiempo en respuesta a los objetos de acción, y el 90% del código que se escribe es simplemente JavaScript, sin uso de Redux en si mismo, sus APIs, o cualquier magia.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n<br>\r\n\r\n## Patrón Decorator y casos de uso\r\n\r\nDecorator (patrón de diseño)\r\n\r\nEl patrón [Decorator](https://es.wikipedia.org/wiki/Decorator_(patr%C3%B3n_de_dise%C3%B1o)) responde a la necesidad de añadir dinámicamente funcionalidad a un Objeto. Esto nos permite no tener que crear sucesivas clases que hereden de la primera incorporando la nueva funcionalidad, sino otras que la implementan y se asocian a la primera.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Decorator motivation\r\n\r\nUn ejemplo para poder ver la aplicabilidad del patrón decorador podría ser el siguiente:\r\n\r\nDisponemos de una herramienta para crear interfaces gráﬁcas, que permite añadir funcionalidades como bordes o barras de desplazamiento a cualquier componente de la interfaz.\r\nUna posible solución sería utilizar la herencia para extender las responsabilidades de la clase. Si optamos por esta solución, estaríamos haciendo un diseño inflexible (estático), ya que el cliente no puede controlar cuándo y cómo decorar el componente con esa propiedad.\r\nLa solución está en encapsular dentro de otro objeto, llamado Decorador, las nuevas responsabilidades. El decorador redirige las peticiones al componente y, además, puede realizar acciones adicionales antes y después de la redirección. De este modo, se pueden añadir decoradores con cualidades añadidas recursivamente.\r\n\r\n<div align=\"center\">\r\n<img src=\"../assets/decorator.png\" alt=\"Decorator patterns\">\r\n</div>\r\n\r\nEn este diagrama de clases, podemos ver que la interfaz decorador implementa la interfaz del componente, redirigiendo todos los métodos al componente visual que encapsula.\r\nLas subclases decoradoras refinan los métodos del componente, añadiendo responsabilidades.\r\nTambién se puede ver que el cliente no necesita hacer distinción entre los componentes visuales decorados y los sin decorar.\r\n\r\n<div align=\"center\">\r\n<img src=\"../assets/secuencia.png\" alt=\"Decorator patterns\">\r\n</div>\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n<br>\r\n\r\n### Decorator Aplicabilidad\r\n\r\nAñadir responsabilidades a objetos individuales de forma dinámica y transparente\r\nResponsabilidades de un objeto pueden ser retiradas\r\nCuando la extensión mediante la herencia no es viable\r\nHay una necesidad de extender la funcionalidad de una clase, pero no hay razones para extenderlo a través de la herencia.\r\nExiste la necesidad de extender dinámicamente la funcionalidad de un objeto y quizás quitar la funcionalidad extendida.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Decorator: Estructura\r\n\r\n<div align=\"center\">\r\n<img src=\"../assets/decoratorgenerico.png\" alt=\"Decorator patterns\">\r\n</div>\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Decorator: Participantes\r\n\r\n- Componente\r\nDeﬁne la interfaz para los objetos que pueden tener responsabilidades añadidas.\r\n\r\n- Componente Concreto\r\nDeﬁne un objeto al cual se le pueden agregar responsabilidades adicionales.\r\n\r\n- Decorador\r\nMantiene una referencia al componente asociado. Implementa la interfaz de la superclase Componente delegando en el componente asociado.\r\n\r\n- Decorador Concreto\r\nAñade responsabilidades al componente.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Decorator Colaboraciones:\r\n\r\nEl decorador redirige las peticiones al componente asociado.\r\nOpcionalmente puede realizar tareas adicionales antes y después de redirigir la petición\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Decorator Consecuencias\r\n\r\nMás flexible que la herencia. Al utilizar este patrón, se pueden añadir y eliminar responsabilidades en tiempo de ejecución. Además, evita la utilización de la herencia con muchas clases y también, en algunos casos, la herencia múltiple.\r\nEvita la aparición de clases con muchas responsabilidades en las clases superiores de la jerarquía. Este patrón nos permite ir incorporando de manera incremental responsabilidades.\r\nGenera gran cantidad de objetos pequeños. El uso de decoradores da como resultado sistemas formados por muchos objetos pequeños y parecidos.\r\nPuede haber problemas con la identidad de los objetos. Un decorador se comporta como un envoltorio transparente. Pero desde el punto de vista de la identidad de objetos, estos no son idénticos, por lo tanto no deberíamos apoyarnos en la identidad cuando estamos usando decoradores.\r\n\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n### Decorator Implementación\r\n\r\nEl patrón Decorator soluciona este problema de una manera mucho más sencilla y extensible.\r\n\r\nSe crea a partir de Ventana la subclase abstracta VentanaDecorator y, heredando de ella, BordeDecorator y BotonDeAyudaDecorator. VentanaDecorator encapsula el comportamiento de Ventana y utiliza composición recursiva para que sea posible añadir tantas “capas” de Decorators como se desee. Podemos crear tantos Decorators como queramos heredando de VentanaDecorator.\r\n\r\n<div align=\"center\">\r\n<img src=\"../assets/openclosed.png\" alt=\"open closed software\">\r\n</div>\r\n<br>\r\n\r\n<div align=\"center\">\r\n<img src=\"../assets/monkeypatching.png\" alt=\"monkeypatching\">\r\n</div>\r\n<br>\r\n\r\n<div align=\"center\">\r\n<img src=\"../assets/timeexecute.png\" alt=\"timeexecute\">\r\n</div>\r\n\r\n<br>\r\n<div align=\"right\">\r\n  <small><a href=\"#tabla-de-contenido\">🡡 volver al inicio</a></small>\r\n</div>\r\n\r\n## Implementación del patrón Decorator\r\n\r\nDocumento HTML:\r\n\r\n```html\r\n<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n  <meta charset=\"UTF-8\">\r\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n  <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\r\n  <title>Decorator Patterns</title>\r\n</head>\r\n<body>\r\n  <div>\r\n    <h1>Decorator Desgin Patterns</h1>\r\n    <label for=\"email\">Email</label>\r\n    <input type=\"text\" id=\"email\">\r\n  </div>\r\n</body>\r\n</html>\r\n```\r\n\r\n```ts\r\nclass Field {\r\n  errors: string[];\r\n  input: HTMLInputElement;\r\n\r\n  constructor(input: HTMLInputElement) {\r\n    this.input = input;\r\n    this.errors = [];\r\n\r\n    let errorMessage = document.createElement('p');\r\n    errorMessage.className = 'text-danger';\r\n    this.input.parentNode.insertBefore(errorMessage, this.input.nextSibling);\r\n\r\n    this.input.addEventListener('input', () => {\r\n      this.errors = [];\r\n      this.validate();\r\n      errorMessage.innerText = this.errors[0] || ' ';\r\n    })\r\n  }\r\n  validate() {}\r\n}\r\n\r\nfunction RequireFieldDecorator(field: Field): Field {\r\n  let validate = field.validate;\r\n\r\n  field.validate = function () {\r\n    validate()\r\n    let value = field.input.value;\r\n    if (!value) {\r\n      field.errors.push(\"Requisito\");\r\n    }\r\n  };\r\n\r\n  return field;\r\n}\r\n\r\nfunction EmailFieldDecorator(field: Field): Field {\r\n  let validate = field.validate;\r\n\r\n  field.validate = function () {\r\n    validate()\r\n    let value = field.input.value;\r\n\r\n    if (value.indexOf(\"@\") === -1) {\r\n      field.errors.push(\"Debe ser un email\");\r\n    }\r\n\r\n  };\r\n  \r\n  return field;\r\n}\r\n\r\nlet field = new Field(document.querySelector(\"#email\"));\r\nRequireFieldDecorator(field);\r\nEmailFieldDecorator(RequireFieldDecorator(field));\r\n```\r\n\r\n## Publicar en NPM\r\n\r\nPara publicar en npm hay un requisito: necesitas una cuenta en npm, es gratis no cuesta nada, es muy fácil de hacer y esto es todo lo que vas a necesitar "
  },
  {
    "path": "observer/index.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n  <meta charset=\"UTF-8\">\r\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n  <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\r\n  <title>Observer</title>\r\n</head>\r\n<body>\r\n  <h1>Precio del Bitcoin</h1>\r\n  <p><em id=\"price\">$0.00</em></p>\r\n\r\n  <input type=\"text\" id=\"value\">\r\n\r\n  <script src=\"index.ts\"></script>\r\n</body>\r\n</html>"
  },
  {
    "path": "observer/index.ts",
    "content": "// Definiendo algunas interfaces\r\n\r\ninterface Observer {\r\n  updated: (data: any) => void;\r\n\r\n}\r\n\r\ninterface Subject {\r\n  subscribe: (observer: Observer) => void;\r\n  unsubscribe: (observer: Observer) => void;\r\n}\r\n\r\nclass BitcoinPrice implements Subject {\r\n  observers: Observer[] = [];\r\n\r\n  constructor() {\r\n    const el: HTMLInputElement = document.querySelector(\"#value\");\r\n    el.addEventListener('input', () => {\r\n      this.notify(el.value);\r\n    })\r\n  }\r\n\r\n  subscribe(observer: Observer) {\r\n    this.observers.push(observer)\r\n  }\r\n\r\n  unsubscribe(observer: Observer) {\r\n    const index = this.observers.findIndex(obs => {\r\n      return obs === observer;\r\n    })\r\n\r\n    this.observers.splice(index, 1);\r\n  }\r\n\r\n  notify(data: any) {\r\n    this.observers.forEach(observer => observer.updated(data))\r\n  }\r\n}\r\n\r\nclass PriceDisplay implements Observer {\r\n  private el: HTMLElement;\r\n\r\n  constructor() {\r\n    this.el = document.querySelector(\"#price\");\r\n  }\r\n  updated(data: any) { \r\n    this.el.innerText = data;\r\n  }\r\n}\r\n\r\nconst value = new BitcoinPrice();\r\nconst display = new PriceDisplay();\r\n\r\nvalue.subscribe(display);\r\n\r\nsetTimeout(\r\n  () => value.unsubscribe(display),\r\n  5000\r\n)\r\n"
  },
  {
    "path": "player-video/MediaPlayer.ts",
    "content": "class MediaPlayer {\r\n  media: HTMLMediaElement;\r\n  plugins: Array<any>;\r\n  container: HTMLElement;\r\n\r\n  constructor(config: any) {\r\n    this.media = config.el;\r\n    this.plugins = config.plugins || [];\r\n    this.initPlayer();\r\n    this.initPlugins();\r\n  }\r\n\r\n  initPlayer() {\r\n    this.container = document.createElement('div');\r\n\r\n    this.media.parentNode.insertBefore(this.container, this.media);\r\n    this.container.appendChild(this.media);\r\n    this.container.style.position = 'relative';\r\n  }\r\n\r\n  private initPlugins() {\r\n    this.plugins.forEach(plugin => {\r\n      plugin.run(this);\r\n    });\r\n  }\r\n\r\n  pause() {\r\n    this.media.pause();\r\n  }\r\n\r\n  play() {\r\n    if (this.media.paused)\r\n      this.media.play();\r\n    else\r\n      this.media.pause();\r\n  }\r\n\r\n  muted() {\r\n    this.media.muted ?\r\n      this.unmuted() :\r\n      this.media.muted = true;\r\n  }\r\n\r\n  unmuted() {\r\n    this.media.muted = false;\r\n  }\r\n}\r\n\r\n \r\n\r\n\r\n\r\n\r\n\r\nexport default MediaPlayer;"
  },
  {
    "path": "player-video/index.html",
    "content": "<html>\r\n  <head>\r\n    <title>PlatziMediaPlayer.js</title>\r\n    <link\r\n      rel=\"stylesheet\"\r\n      href=\"https://necolas.github.io/normalize.css/8.0.1/normalize.css\"\r\n    />\r\n    <link rel=\"stylesheet\" href=\"./styles.css\" />\r\n  </head>\r\n\r\n  <body>\r\n    <header>\r\n      <h1>PlatziMediaPlayer.js</h1>\r\n      <p>An extensible media player.</p>\r\n    </header>\r\n\r\n    <main class=\"container\">\r\n      <video class=\"movie\">\r\n        <source src=\"buckbunny.mp4\" />\r\n      </video>\r\n\r\n      <button id=\"play\">Play/Pause</button>       \r\n      <button id=\"muted\">Muted/UnMuted</button>       \r\n    </main>\r\n    \r\n    <div>\r\n      <ul>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n      </ul>\r\n    </div>\r\n    <script type=\"module\" src=\"index.ts\"></script>\r\n  </body>\r\n</html>"
  },
  {
    "path": "player-video/index.ts",
    "content": "import MediaPlayer from './MediaPlayer';\r\nimport AutoPlay from './plugins/AutoPlay'; \r\nimport AutoPause from './plugins/AutoPause'; \r\nimport Ads from './plugins/Ads/';\r\n\r\nconst video: HTMLElement = document.querySelector('video');\r\nconst btnplay: HTMLElement = document.getElementById('play');\r\nconst btnmuted: HTMLElement = document.getElementById('muted');\r\n\r\nconst player = new MediaPlayer({\r\n  el: video, plugins: [\r\n    new AutoPlay(),\r\n    new AutoPause(),\r\n    new Ads()\r\n] });\r\nbtnplay.onclick = () => player.play();\r\nbtnmuted.onclick = () => player.muted();\r\n\r\nif ('serviceWorker' in navigator) {\r\n  navigator.serviceWorker.register('sw.js')\r\n    .catch(error => {\r\n      console.log(error.message);\r\n  })\r\n}"
  },
  {
    "path": "player-video/plugins/Ads/Ads.ts",
    "content": "import { ALL_ADS } from './ads_list.js';\r\n\r\nexport interface Ad {\r\n  imageUrl: string,\r\n  title: string,\r\n  body: string,\r\n  url: string\r\n}\r\n\r\nclass Ads {\r\n  private static instance: Ads;\r\n  private ads: Ad[];\r\n\r\n  private constructor() { \r\n    this.initAds();\r\n  }\r\n\r\n  static getInstance() {\r\n    if (!Ads.instance) {\r\n      Ads.instance = new Ads();\r\n    }\r\n\r\n    return Ads.instance;\r\n  }\r\n\r\n  private initAds() {\r\n    this.ads = [...ALL_ADS];\r\n  }\r\n\r\n  getAd() {\r\n    if (this.ads.length === 0) {\r\n      this.initAds();\r\n    }\r\n    return this.ads.pop();\r\n\r\n  }\r\n}\r\n\r\nexport default Ads;"
  },
  {
    "path": "player-video/plugins/Ads/ads_list.js",
    "content": "export const ALL_ADS = [\r\n  {\r\n    imageUrl:\r\n      'https://static.platzi.com/media/achievements/badge-profesional-javascript-13538df2-24ce-433f-9aa6-e34eed608e70.png',\r\n    title: 'Curso Profesional de JavaScript',\r\n    body:\r\n      'Mejora tus habilidades en Javascript. Conoce Typescript y cómo puedes ocuparlo para mejorar el control de tus variables.',\r\n    url: 'https://platzi.com/cursos/javascript-profesional/',\r\n  },\r\n\r\n  {\r\n    imageUrl:\r\n      'https://static.platzi.com/media/achievements/badge-frontend-developer-8a49e681-3e22-408d-b886-2f47dfc9953a.png',\r\n    title: 'Curso de Frontend Developer',\r\n    body:\r\n      'Domina las bases de HTML y CSS. Define la arquitectura de tu código y construye un sitio web usando componentes estáticos. ',\r\n    url: 'https://platzi.com/cursos/frontend-developer/',\r\n  },\r\n\r\n  {\r\n    imageUrl:\r\n      'https://static.platzi.com/media/achievements/badge-backend-node-8e6aa8a9-f7cd-42b7-bf4a-e1ee916a942b.png',\r\n    title: 'Curso de Backend con Node.js',\r\n    body:\r\n      'Crea aplicaciones backend utilizando Node.js, Express y Mongo. Entiende cómo funciona Javascript en un servidor y escribe aplicaciones con Node.js.',\r\n    url: 'https://platzi.com/cursos/backend-nodejs/',\r\n  },\r\n\r\n  {\r\n    imageUrl:\r\n      'https://static.platzi.com/media/achievements/badge-prework-da6b0493-9908-40f3-ad53-f5d330b995b8.png',\r\n    title:\r\n      'Comienza tus proyectos de desarrollo para JavaScript configurando un entorno de desarrollo cómodo y adaptado a tus necesidades.',\r\n    body:\r\n      'Mejora tus habilidades en Javascript. Conoce Typescript y cómo puedes ocuparlo para mejorar el control de tus variables.',\r\n    url: 'https://platzi.com/cursos/prework/',\r\n  },\r\n\r\n  {\r\n    imageUrl:\r\n      'https://static.platzi.com/media/achievements/badge-autenticacion-passport-6d45426a-2b24-4757-8927-7bfaf54529dd.png',\r\n    title: 'Curso de Autenticación con Passport.js',\r\n    body:\r\n      'Genera estrategias de autenticación Sign-In y Sign-Out usando Passport.js. Agrega autenticación con Facebook, Twitter y Google a tus desarrollos.',\r\n    url: 'https://platzi.com/cursos/passport/',\r\n  },\r\n\r\n  {\r\n    imageUrl:\r\n      'https://static.platzi.com/media/achievements/badge-backend-frontend-02b2ac18-331a-4959-85bf-0bd3c2aa009c.png',\r\n    title: 'Curso de Backend for Frontend',\r\n    body:\r\n      'La ingeniería de software evoluciona día a día, no te quedes atrás. Ahora que eres un Desarrollador FullStack JavaScript necesitas evolucionar con el software, construye arquitecturas de software modernas.',\r\n    url: 'https://platzi.com/cursos/bff/',\r\n  },\r\n\r\n  {\r\n    imageUrl:\r\n      'https://static.platzi.com/media/achievements/badge-react-adec89d0-1c35-4c9c-847e-18c284dc79dd.png',\r\n    title: 'Curso Práctico de React JS',\r\n    body:\r\n      'React es una de las librerías más utilizadas hoy para crear aplicaciones web. Aprende a través de la creación de la interfaz de PlatziVideo todo lo que necesitas para crear increíbles componentes con React.      ',\r\n    url: 'https://platzi.com/cursos/react-ejs/',\r\n  },\r\n\r\n  {\r\n    imageUrl:\r\n      'https://static.platzi.com/media/achievements/badge-react-redux-2ca3c0a5-fc53-437f-bfba-69e9ddd5a803.png',\r\n    title: 'Curso de React Router y Redux',\r\n    body:\r\n      'Aprende de forma práctica a implementar React Router para manejar rutas en tus proyectos de frontend como un profesional.',\r\n    url: 'https://platzi.com/cursos/react-router-redux/',\r\n  },\r\n];"
  },
  {
    "path": "player-video/plugins/Ads/index.ts",
    "content": "import MediaPlayer from '../../MediaPlayer';\r\nimport Ads, {Ad} from './Ads';\r\n\r\nclass AdsPlugin {\r\n  private player: MediaPlayer;\r\n  private media: HTMLMediaElement;\r\n  private ads: Ads;\r\n  private currentAd: Ad;\r\n  private adsContainer: HTMLElement;\r\n\r\n  constructor() {\r\n    this.ads = Ads.getInstance()\r\n    this.adsContainer = document.createElement('div');\r\n  }\r\n\r\n  run(player: MediaPlayer) {\r\n    this.player = player;\r\n    this.player.container.appendChild(this.adsContainer);\r\n    this.media = this.player.media;\r\n    this.media.addEventListener('timeupdate', this.handleTimeUpdate.bind(this));\r\n  }\r\n\r\n  private handleTimeUpdate() {\r\n    const currentTime = Math.floor(this.media.currentTime);\r\n    if (currentTime % 30 === 0) {\r\n      this.renderAd();\r\n    }\r\n  }\r\n\r\n  private renderAd() {\r\n    if (this.currentAd) {\r\n      return;\r\n    }\r\n    const ad = this.ads.getAd();\r\n    this.currentAd = ad;\r\n    console.log(this.currentAd);\r\n    // this.adsContainer.style.position = 'absolute';\r\n    // <a class=\"ads__link\"href=\"${this.currentAd.url}\"target=\"_blank\">\r\n    this.adsContainer.innerHTML = `\r\n      <div class=\"ads\">\r\n          <img class=\"ads__img\"src=\"${this.currentAd.imageUrl}\" />\r\n          <div class=\"ads__info\">\r\n            <h5 class=\"ads__title\">${this.currentAd.title}</h5>\r\n            <p class=\"ads__body\">${this.currentAd.body}</p>\r\n          </div>\r\n          </div>\r\n          `;\r\n          \r\n          // </a>\r\n    setTimeout(() => {\r\n      this.currentAd = null;\r\n      this.adsContainer.innerHTML = \"\";\r\n    }, 10000);\r\n\r\n  }\r\n}\r\n\r\nexport default AdsPlugin;"
  },
  {
    "path": "player-video/plugins/AutoPause.ts",
    "content": "import MediaPlayer from '../MediaPlayer'\r\nclass AutoPause {\r\n  private threshold: number;\r\n  player: MediaPlayer;\r\n  constructor() {\r\n    this.threshold = 0.25;\r\n    this.handlerIntersection = this.handlerIntersection.bind(this)\r\n    this.handleVisibilityChange = this.handleVisibilityChange.bind(this);\r\n  }\r\n  run(player) {\r\n    this.player = player;\r\n    // const observer = new IntersectionObserver(handler, config)\r\n    const observer = new IntersectionObserver(this.handlerIntersection, {\r\n      // threshold: umbral define que porciento del elemento tiene que tener interseccion\r\n      threshold: this.threshold\r\n    })\r\n\r\n    observer.observe(this.player.media) \r\n\r\n    document.addEventListener('visibilitychange', this.handleVisibilityChange)\r\n  }\r\n  private handleVisibilityChange() {\r\n    const isVisible = document.visibilityState === \"visible\";\r\n    if (isVisible) {\r\n      this.player.play();\r\n    } else {\r\n      this.player.pause();\r\n    }\r\n  }\r\n  // Cuando intersectionObserver llame a handlerIntersection le va a pasar una lista de entries\r\n  // los entries son todos los objetos que estamos observando \r\n  private handlerIntersection(entries: IntersectionObserverEntry[]) {\r\n    const entry = entries[0];\r\n    // console.log(entry);\r\n\r\n    const isVisible = entry.intersectionRatio >= this.threshold\r\n\r\n    if (isVisible) {\r\n      this.player.play();\r\n    } else {\r\n      this.player.pause();\r\n    }\r\n  }\r\n}\r\nexport default AutoPause;"
  },
  {
    "path": "player-video/plugins/AutoPlay.ts",
    "content": "import MediaPlayer from '../MediaPlayer'\r\n\r\nclass AutoPlay {\r\n  constructor() { }\r\n  run(player: MediaPlayer) {\r\n    if (!player.media.muted) {\r\n      player.media.muted = true;\r\n    }\r\n    player.play();\r\n  }\r\n}\r\n\r\n\r\nexport default AutoPlay;"
  },
  {
    "path": "player-video/styles.css",
    "content": "* {\r\n  -webkit-font-smoothing: antialiased;\r\n  -moz-osx-font-smoothing: grayscale;\r\n  box-sizing: border-box;\r\n}\r\n\r\nbody {\r\n  background: #eeeeee;\r\n  color: #030303;\r\n  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,\r\n    Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;\r\n}\r\n\r\nheader {\r\n  text-align: center;\r\n  padding: 3rem 0;\r\n  background-image: linear-gradient(120deg, #f093fb 0%, #f5576c 100%);\r\n  color: white;\r\n}\r\n\r\nheader > h1 {\r\n  font-weight: normal;\r\n  font-style: italic;\r\n}\r\n\r\nmain {\r\n  padding: 1rem 0;\r\n}\r\n\r\n.container {\r\n  max-width: 960px;\r\n  width: 100%;\r\n  margin: 0 auto;\r\n}\r\n\r\n.movie {\r\n  width: 100%;\r\n}\r\n\r\n.ads {\r\n  padding: 4px;\r\n  padding-right: 8px;\r\n  background: white;\r\n  width: 80%;\r\n\r\n  position: absolute;\r\n  bottom: 20px;\r\n  left: 50%;\r\n  transform: translateX(-50%);\r\n}\r\n\r\n.ads__link {\r\n  display: flex;\r\n  color: inherit;\r\n  text-decoration: inherit;\r\n}\r\n\r\n.ads__img {\r\n  width: 80px;\r\n  min-width: 80px;\r\n  height: 80px;\r\n  margin-right: 16px;\r\n}\r\n\r\n.ads__info {\r\n  display: flex;\r\n  flex-direction: column;\r\n  justify-content: center;\r\n}\r\n\r\n.ads__title {\r\n  margin: 0;\r\n}\r\n.ads__body {\r\n  margin: 0;\r\n}"
  },
  {
    "path": "player-video/sw.js",
    "content": "// Self hace refencia al service worker es como this a los objetos\r\nself.addEventListener('install', event => {\r\n  // Creamos un precache con una lista de recursos que queremos que mantenga en cache\r\n  event.waitUntil(precache());\r\n})\r\n\r\n// Cuando ocurra una petición queremos a ir al cache para ver si encontramos la respuesta\r\nself.addEventListener('fetch', event => {\r\n  // Extraemos la petición\r\n  const request = event.request;\r\n  // Solo queremos hacer algo con las peticiones que son GET\r\n  if (request.method !== \"GET\")\r\n    return;\r\n  \r\n  // actualizar el cache\r\n  event.waitUntil(updateCache(cache))\r\n\r\n  \r\n  // Buscamos en el cache\r\n  // event tiene otra función que se llamá responder con responseWith\r\n  // vamos a responder con una respuesta cacheada\r\n  event.respondWith(cachedResponse(request))\r\n})\r\n\r\n// Escribimos la función del precache\r\nasync function precache() {\r\n  // Para trabajar con cache tenemos que trabajar con una parte\r\n  // de la api del dom que se llamá caches, y lo que hay que hacer es abrir un cache en especifico\r\n  // Creamos una instancia de cache que le va a pertenecer o se va a llamar v1,\r\n  // podemos ponerle como queramos porque apenas estamos haciendo una instancia,\r\n  // este cache regresa una promesa, por lo cual hay que esperarla\r\n  const cache = await caches.open(\"v1\");\r\n\r\n  // Una vez tenemos la instancia de cache queremos añadir varios recursos\r\n  // añadirmos todos nuestro recursos, los cuales son todos lo archivos que hemos escrito\r\n  // Tenemos que regresarlo porque devuelve una promesa\r\n  return cache.addAll([\r\n    // Es muy importante asignarne este request\r\n    '/',\r\n    'index.html',\r\n    'styles.css',\r\n    'MediaPlayer.js',\r\n    'index.js',\r\n    'plugins/AutoPause.js',\r\n    'plugins/AutoPlay.js',\r\n    'buckbunny.mp4'\r\n  ]);\r\n\r\n\r\n}\r\n\r\n// vamos a pasarle el request\r\nasync function cachedResponse(request) {\r\n// Comenzamos abriendo el cache \r\n  const cache = await caches.open(\"v1\");\r\n  // debemos checar si en el cache tenemos la contestanción al request\r\n  // Para hacer eso vamos a guardalo en el response\r\n  // Estamos preguntando al cache\r\n  // ¿Ya tienes una copia que le corresponse al request?\r\n  const response = await cache.match(request)\r\n  // Como es posible que este response sea undefine, tenemos que contestar con lo que nos de la red\r\n  return response || fetch(request);\r\n\r\n}\r\n\r\nasync function updateCache(request) {\r\n  const cache = await caches.open(\"v1\");\r\n  const response = await fetch(request);\r\n  return cache.put(request, response)\r\n}"
  },
  {
    "path": "singleton/Singleton.ts",
    "content": "class Singleton {\r\n  private static instance: Singleton;\r\n  private constructor() {\r\n    // initialition\r\n  }\r\n\r\n  static getInstance() {\r\n    if (!Singleton.instance) {\r\n      Singleton.instance = new Singleton();\r\n    }\r\n\r\n    return Singleton.instance;\r\n  }\r\n}\r\n\r\nexport default Singleton;"
  },
  {
    "path": "singleton/index.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n  <meta charset=\"UTF-8\">\r\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n  <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\r\n  <title>Singleton</title>\r\n</head>\r\n<body>\r\n  <p>Abre la terminal....</p>\r\n</body>\r\n</html>"
  },
  {
    "path": "singleton/index.ts",
    "content": "import Singleton from './Singleton';\r\n\r\nconst a = Singleton.getInstance();\r\nconst b = Singleton.getInstance();\r\n\r\nconsole.log(\"¿A es igual a B?\", a === b);"
  },
  {
    "path": "typescript/functions.ts",
    "content": "// Funciones\r\nfunction add(a: number, b: number): number {\r\n  return a + b;\r\n}\r\nconst sum = add(4, 25)\r\n\r\nfunction createAdder(a: number): (number) => number {\r\n  return function (b: number) {\r\n    return a + b;\r\n  }\r\n}\r\n\r\nconst addFour = createAdder(4);\r\nconst fourPlus6 = addFour(6);\r\n\r\nfunction fullName(firtsName: string, lastName?: string): string {\r\n  return `${firtsName} ${lastName}`;\r\n}\r\nconst jasan = fullName('Jasan');\r\n\r\nfunction fullValue(firtsName: string = \"Pepe\", lastName: string = \"Smith\"): string {\r\n  return `${firtsName} ${lastName}`;\r\n}\r\nconst person = fullValue();"
  },
  {
    "path": "typescript/index.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n  <meta charset=\"UTF-8\">\r\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n  <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\r\n  <title>Typescript</title>\r\n</head>\r\n<body>\r\n  <script src=\"index.ts\"></script>\r\n</body>\r\n</html>"
  },
  {
    "path": "typescript/index.ts",
    "content": "// TypeScript por Jasan Hernández\r\n// Boolean\r\nlet muted: boolean = true;\r\nmuted = false;\r\n\r\n// Numbers\r\nlet numerador: number = 42;\r\nlet denomindador: number = 6;\r\nlet resultado = numerador / denomindador;\r\n\r\n// String\r\nlet nombre: string = \"Jasan\";\r\nlet saludo: string = `Me llamo ${nombre}`;\r\n\r\n// Arreglos\r\nlet people: string[] = [];\r\npeople = [\"Isabel\", \"Nicole\", \"Raúl\"];\r\n// people.push(34);\r\n\r\n// Arreglos de Strings and numbers:\r\nlet peopleAndNumbers: Array<string | number> = [];\r\npeopleAndNumbers.push(\"Ricardo\");\r\npeopleAndNumbers.push(345);\r\n\r\n// Enum\r\nenum Color {\r\n  Rojo = \"Rojo\",\r\n  Verde = \"Verde\",\r\n  Azul = \"Amarillo\",\r\n}\r\nlet colorFavorito: Color = Color.Azul;\r\nconsole.log(`Mi color favorito es: ${colorFavorito}`);\r\n\r\n// Any\r\nlet comodin: any  = \"Joker\";\r\ncomodin = { type: \"WildCard\" }\r\n\r\n// Object \r\nlet someObject: object = { type: \"WildCard\" };\r\n"
  },
  {
    "path": "typescript/interface.ts",
    "content": "enum Color {\r\n  Rojo = \"Rojo\",\r\n  Verde = \"Verde\"\r\n};\r\n\r\ninterface Rectangulo {\r\n  height: number,\r\n  width: number\r\n  color?: Color\r\n}\r\n\r\nlet rect: Rectangulo = {\r\n  height: 4,\r\n  width: 3,\r\n  // color: Color.Verde\r\n}\r\n\r\nfunction area(r: Rectangulo) {\r\n  return r.height * r.width;\r\n}\r\n\r\nconst areaReact = area(rect);\r\nrect.toString = function () {\r\n  return this.color ? `Un rectangulo ${this.color}` : `Un rectangulo`;\r\n}\r\n\r\nconsole.log(rect.toString());\r\n\r\n"
  },
  {
    "path": "website/.gitignore",
    "content": "buckbunny.mp4\r\n\r\n# Carpetas bundle Typescript \r\n.cache\r\ndist\r\n\r\n\r\n# Logs\r\nlogs\r\n*.log\r\nnpm-debug.log*\r\nyarn-debug.log*\r\nyarn-error.log*\r\nlerna-debug.log*\r\n\r\n# Diagnostic reports (https://nodejs.org/api/report.html)\r\nreport.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json\r\n\r\n# Runtime data\r\npids\r\n*.pid\r\n*.seed\r\n*.pid.lock\r\n\r\n# Directory for instrumented libs generated by jscoverage/JSCover\r\nlib-cov\r\n\r\n# Coverage directory used by tools like istanbul\r\ncoverage\r\n*.lcov\r\n\r\n# nyc test coverage\r\n.nyc_output\r\n\r\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\r\n.grunt\r\n\r\n# Bower dependency directory (https://bower.io/)\r\nbower_components\r\n\r\n# node-waf configuration\r\n.lock-wscript\r\n\r\n# Compiled binary addons (https://nodejs.org/api/addons.html)\r\nbuild/Release\r\n\r\n# Dependency directories\r\nnode_modules/\r\njspm_packages/\r\n\r\n# TypeScript v1 declaration files\r\ntypings/\r\n\r\n# TypeScript cache\r\n*.tsbuildinfo\r\n\r\n# Optional npm cache directory\r\n.npm\r\n\r\n# Optional eslint cache\r\n.eslintcache\r\n\r\n# Optional REPL history\r\n.node_repl_history\r\n\r\n# Output of 'npm pack'\r\n*.tgz\r\n\r\n# Yarn Integrity file\r\n.yarn-integrity\r\n\r\n# dotenv environment variables file\r\n.env\r\n.env.test\r\n\r\n# parcel-bundler cache (https://parceljs.org/)\r\n.cache\r\n\r\n# next.js build output\r\n.next\r\n\r\n# nuxt.js build output\r\n.nuxt\r\n\r\n# vuepress build output\r\n.vuepress/dist\r\n\r\n# Serverless directories\r\n.serverless/\r\n\r\n# FuseBox cache\r\n.fusebox/\r\n\r\n# DynamoDB Local files\r\n.dynamodb/"
  },
  {
    "path": "website/index.html",
    "content": "<html>\r\n  <head>\r\n    <title>PlatziMediaPlayer.js</title>\r\n    <link\r\n      rel=\"stylesheet\"\r\n      href=\"https://necolas.github.io/normalize.css/8.0.1/normalize.css\"\r\n    />\r\n    <link rel=\"stylesheet\" href=\"./styles.css\" />\r\n  </head>\r\n\r\n  <body>\r\n    <header>\r\n      <h1>PlatziMediaPlayer.js</h1>\r\n      <p>An extensible media player.</p>\r\n    </header>\r\n\r\n    <main class=\"container\">\r\n      <video class=\"movie\">\r\n        <source src=\"buckbunny.mp4\" />\r\n      </video>\r\n\r\n      <button id=\"play\">Play/Pause</button>       \r\n      <button id=\"muted\">Muted/UnMuted</button>       \r\n    </main>\r\n    \r\n    <div>\r\n      <ul>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n        <li>\r\n          \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\r\n        </li>\r\n      </ul>\r\n    </div>\r\n    <script type=\"module\" src=\"index.ts\"></script>\r\n  </body>\r\n</html>"
  },
  {
    "path": "website/index.ts",
    "content": "import MediaPlayer from '@jasanhdz/mediaplayer/src/MediaPlayer';\r\nimport AutoPlay from '@jasanhdz/mediaplayer/src/plugins/AutoPlay'; \r\nimport AutoPause from '@jasanhdz/mediaplayer/src/plugins/AutoPause'; \r\nimport Ads from '@jasanhdz/mediaplayer/src/plugins/Ads/';\r\n\r\nconst video: HTMLElement = document.querySelector('video');\r\nconst btnplay: HTMLElement = document.getElementById('play');\r\nconst btnmuted: HTMLElement = document.getElementById('muted');\r\n\r\nconst player = new MediaPlayer({\r\n  el: video, plugins: [\r\n    new AutoPlay(),\r\n    new AutoPause(),\r\n    new Ads()\r\n] });\r\nbtnplay.onclick = () => player.play();\r\nbtnmuted.onclick = () => player.muted();\r\n\r\nif ('serviceWorker' in navigator) {\r\n  navigator.serviceWorker.register('sw.js')\r\n    .catch(error => {\r\n      console.log(error.message);\r\n  })\r\n}"
  },
  {
    "path": "website/package.json",
    "content": "{\n  \"name\": \"jsprofessional\",\n  \"version\": \"1.0.0\",\n  \"description\": \"prácticas avanzadas de javascript\",\n  \"scripts\": {\n    \"start\": \"parcel index.html player-video/index.html typescript/**/*.html singleton/**/*.html observer/index.html\"\n  },\n  \"keywords\": [\n    \"javascript\",\n    \"professional\"\n  ],\n  \"author\": \"Jasan A. Hérnandez Bautista <jasan814@gmail.com>\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"parcel-bundler\": \"1.12.3\",\n    \"typescript\": \"^3.6.3\"\n  },\n  \"browserslist\": [\n    \"last 1 Chrome version\"\n  ],\n  \"dependencies\": {\n    \"@jasanhdz/mediaplayer\": \"^1.0.0\"\n  }\n}\n"
  },
  {
    "path": "website/styles.css",
    "content": "* {\r\n  -webkit-font-smoothing: antialiased;\r\n  -moz-osx-font-smoothing: grayscale;\r\n  box-sizing: border-box;\r\n}\r\n\r\nbody {\r\n  background: #eeeeee;\r\n  color: #030303;\r\n  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,\r\n    Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;\r\n}\r\n\r\nheader {\r\n  text-align: center;\r\n  padding: 3rem 0;\r\n  background-image: linear-gradient(120deg, #f093fb 0%, #f5576c 100%);\r\n  color: white;\r\n}\r\n\r\nheader > h1 {\r\n  font-weight: normal;\r\n  font-style: italic;\r\n}\r\n\r\nmain {\r\n  padding: 1rem 0;\r\n}\r\n\r\n.container {\r\n  max-width: 960px;\r\n  width: 100%;\r\n  margin: 0 auto;\r\n}\r\n\r\n.movie {\r\n  width: 100%;\r\n}\r\n\r\n.ads {\r\n  padding: 4px;\r\n  padding-right: 8px;\r\n  background: white;\r\n  width: 80%;\r\n\r\n  position: absolute;\r\n  bottom: 20px;\r\n  left: 50%;\r\n  transform: translateX(-50%);\r\n}\r\n\r\n.ads__link {\r\n  display: flex;\r\n  color: inherit;\r\n  text-decoration: inherit;\r\n}\r\n\r\n.ads__img {\r\n  width: 80px;\r\n  min-width: 80px;\r\n  height: 80px;\r\n  margin-right: 16px;\r\n}\r\n\r\n.ads__info {\r\n  display: flex;\r\n  flex-direction: column;\r\n  justify-content: center;\r\n}\r\n\r\n.ads__title {\r\n  margin: 0;\r\n}\r\n.ads__body {\r\n  margin: 0;\r\n}"
  },
  {
    "path": "website/sw.js",
    "content": "// Self hace refencia al service worker es como this a los objetos\r\nself.addEventListener('install', event => {\r\n  // Creamos un precache con una lista de recursos que queremos que mantenga en cache\r\n  event.waitUntil(precache());\r\n})\r\n\r\n// Cuando ocurra una petición queremos a ir al cache para ver si encontramos la respuesta\r\nself.addEventListener('fetch', event => {\r\n  // Extraemos la petición\r\n  const request = event.request;\r\n  // Solo queremos hacer algo con las peticiones que son GET\r\n  if (request.method !== \"GET\")\r\n    return;\r\n  \r\n  // actualizar el cache\r\n  event.waitUntil(updateCache(cache))\r\n\r\n  \r\n  // Buscamos en el cache\r\n  // event tiene otra función que se llamá responder con responseWith\r\n  // vamos a responder con una respuesta cacheada\r\n  event.respondWith(cachedResponse(request))\r\n})\r\n\r\n// Escribimos la función del precache\r\nasync function precache() {\r\n  // Para trabajar con cache tenemos que trabajar con una parte\r\n  // de la api del dom que se llamá caches, y lo que hay que hacer es abrir un cache en especifico\r\n  // Creamos una instancia de cache que le va a pertenecer o se va a llamar v1,\r\n  // podemos ponerle como queramos porque apenas estamos haciendo una instancia,\r\n  // este cache regresa una promesa, por lo cual hay que esperarla\r\n  const cache = await caches.open(\"v1\");\r\n\r\n  // Una vez tenemos la instancia de cache queremos añadir varios recursos\r\n  // añadirmos todos nuestro recursos, los cuales son todos lo archivos que hemos escrito\r\n  // Tenemos que regresarlo porque devuelve una promesa\r\n  return cache.addAll([\r\n    // Es muy importante asignarne este request\r\n    '/',\r\n    'index.html',\r\n    'styles.css',\r\n    'MediaPlayer.js',\r\n    'index.js',\r\n    'plugins/AutoPause.js',\r\n    'plugins/AutoPlay.js',\r\n    'buckbunny.mp4'\r\n  ]);\r\n\r\n\r\n}\r\n\r\n// vamos a pasarle el request\r\nasync function cachedResponse(request) {\r\n// Comenzamos abriendo el cache \r\n  const cache = await caches.open(\"v1\");\r\n  // debemos checar si en el cache tenemos la contestanción al request\r\n  // Para hacer eso vamos a guardalo en el response\r\n  // Estamos preguntando al cache\r\n  // ¿Ya tienes una copia que le corresponse al request?\r\n  const response = await cache.match(request)\r\n  // Como es posible que este response sea undefine, tenemos que contestar con lo que nos de la red\r\n  return response || fetch(request);\r\n\r\n}\r\n\r\nasync function updateCache(request) {\r\n  const cache = await caches.open(\"v1\");\r\n  const response = await fetch(request);\r\n  return cache.put(request, response)\r\n}"
  }
]